Repository: actonlang/acton Branch: main Commit: 8ac1f50c34d2 Files: 1091 Total size: 9.2 MB Directory structure: gitextract_p92zbpa_/ ├── .containerignore ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── blank_issue.md │ │ ├── bug.yaml │ │ ├── config.yml │ │ ├── feature.yaml │ │ └── ice.yaml │ ├── dependabot.yml │ └── workflows/ │ ├── claude.yml │ ├── code-agent.yml │ ├── create-release.yml │ ├── release.yml │ ├── test-app.yml │ ├── test.yml │ ├── trigger-web-update.yml │ ├── update-ask-acton-vector-store.yml │ └── webex-notifications.yml ├── .gitignore ├── .gitmodules ├── AGENTS.md ├── CHANGELOG.md ├── CLAUDE.md ├── CONTRIBUTING.md ├── Containerfile ├── Containerfile.deb ├── LICENSE ├── Makefile ├── README.md ├── backend/ │ ├── .gitignore │ ├── Build.act │ ├── CLAUDE.md │ ├── actondb.c │ ├── client_api.c │ ├── client_api.h │ ├── comm.c │ ├── comm.h │ ├── common.h │ ├── consumer_state.h │ ├── db.c │ ├── db.h │ ├── db_client_api.h │ ├── failure_detector/ │ │ ├── cells.c │ │ ├── cells.h │ │ ├── db_messages.pb-c.c │ │ ├── db_messages.pb-c.h │ │ ├── db_messages.proto │ │ ├── db_messages_test.c │ │ ├── db_queries.c │ │ ├── db_queries.h │ │ ├── fd.c │ │ ├── fd.h │ │ ├── txns.h │ │ ├── vector_clock.c │ │ └── vector_clock.h │ ├── fastrand.h │ ├── hash_ring.c │ ├── hash_ring.h │ ├── hashes.h │ ├── log.c │ ├── log.h │ ├── queue.c │ ├── queue.h │ ├── queue_callback.c │ ├── queue_callback.h │ ├── queue_groups.c │ ├── queue_groups.h │ ├── skiplist.c │ ├── skiplist.h │ ├── test/ │ │ ├── actor_ring_tests_local.c │ │ ├── actor_ring_tests_remote.c │ │ ├── db_unit_tests.c │ │ ├── queue_unit_tests.c │ │ ├── skiplist_test.c │ │ └── test_client.c │ ├── txn_state.c │ ├── txn_state.h │ ├── txns.c │ └── txns.h ├── base/ │ ├── .gitignore │ ├── Build.act │ ├── CLAUDE.md │ ├── __root.zig │ ├── acton.zig │ ├── builtin/ │ │ ├── Iterator.c │ │ ├── Iterator.h │ │ ├── atom.c │ │ ├── atom.h │ │ ├── bigint.c │ │ ├── bigint.h │ │ ├── bool.c │ │ ├── bool.h │ │ ├── box.c │ │ ├── box.h │ │ ├── builtin.c │ │ ├── builtin.h │ │ ├── builtin_functions.c │ │ ├── builtin_functions.h │ │ ├── class_hierarchy.c │ │ ├── class_hierarchy.h │ │ ├── common.c │ │ ├── common.h │ │ ├── complex.c │ │ ├── complx.h │ │ ├── csiphash.c │ │ ├── dict.c │ │ ├── dict.h │ │ ├── env.c │ │ ├── env.h │ │ ├── exceptions.c │ │ ├── exceptions.h │ │ ├── float.c │ │ ├── float.h │ │ ├── function.c │ │ ├── function.h │ │ ├── hasher.c │ │ ├── hasher.h │ │ ├── i16.c │ │ ├── i16.h │ │ ├── i32.c │ │ ├── i32.h │ │ ├── i8.c │ │ ├── i8.h │ │ ├── int.c │ │ ├── int.h │ │ ├── list.c │ │ ├── list.h │ │ ├── none.c │ │ ├── none.h │ │ ├── range.c │ │ ├── range.h │ │ ├── registration.c │ │ ├── registration.h │ │ ├── serialize.c │ │ ├── serialize.h │ │ ├── set.c │ │ ├── set.h │ │ ├── slice.c │ │ ├── slice.h │ │ ├── staticWitnesses.c │ │ ├── staticWitnesses.h │ │ ├── str.c │ │ ├── str.h │ │ ├── timsort.c │ │ ├── tuple.c │ │ ├── tuple.h │ │ ├── u1.c │ │ ├── u1.h │ │ ├── u16.c │ │ ├── u16.h │ │ ├── u32.c │ │ ├── u32.h │ │ ├── u64.c │ │ ├── u64.h │ │ ├── u8.c │ │ ├── u8.h │ │ ├── utils.c │ │ └── utils.h │ ├── rts/ │ │ ├── common.c │ │ ├── common.h │ │ ├── gc.zig │ │ ├── io.c │ │ ├── io.h │ │ ├── log.c │ │ ├── log.h │ │ ├── netstring.c │ │ ├── netstring.h │ │ ├── q.c │ │ ├── q.h │ │ ├── rts.c │ │ └── rts.h │ └── src/ │ ├── __builtin__.act │ ├── __builtin__.ext.c │ ├── acton/ │ │ ├── rts.act │ │ └── rts.ext.c │ ├── argparse.act │ ├── base64.act │ ├── base64.ext.c │ ├── buildy.act │ ├── crypto/ │ │ └── hash/ │ │ ├── md5.act │ │ └── md5.ext.c │ ├── diff.act │ ├── file.act │ ├── file.ext.c │ ├── fs.act │ ├── hash/ │ │ ├── wyhash.act │ │ └── wyhash.ext.c │ ├── http.act │ ├── json.act │ ├── json.ext.c │ ├── logging.act │ ├── logging.ext.c │ ├── math.act │ ├── math.ext.c │ ├── net.act │ ├── net.ext.c │ ├── process.act │ ├── process.ext.c │ ├── qcheck.act │ ├── random.act │ ├── random.ext.c │ ├── re.act │ ├── re.ext.c │ ├── snappy.act │ ├── snappy.ext.c │ ├── term.act │ ├── testing.act │ ├── time.act │ ├── time.ext.c │ ├── uri.act │ ├── xml.act │ └── xml.ext.c ├── bin/ │ └── runacton ├── compiler/ │ ├── .gitignore │ ├── CLAUDE.md │ ├── acton/ │ │ ├── Main.hs │ │ ├── PkgCommands.hs │ │ ├── TerminalProgress.hs │ │ ├── TerminalSize.hs │ │ ├── TestFormat.hs │ │ ├── TestGolden.hs │ │ ├── TestRunner.hs │ │ ├── TestUI.hs │ │ ├── ZigProgress.hs │ │ ├── package.yaml.in │ │ ├── test/ │ │ │ ├── incremental_cases/ │ │ │ │ └── .gitignore │ │ │ ├── parse/ │ │ │ │ ├── simple.act │ │ │ │ ├── simple.all.golden │ │ │ │ ├── simple.box.golden │ │ │ │ ├── simple.cgen.golden │ │ │ │ ├── simple.cps.golden │ │ │ │ ├── simple.deact.golden │ │ │ │ ├── simple.golden │ │ │ │ ├── simple.hgen.golden │ │ │ │ ├── simple.kinds.golden │ │ │ │ ├── simple.llift.golden │ │ │ │ ├── simple.norm.golden │ │ │ │ ├── simple.sigs.golden │ │ │ │ └── simple.types.golden │ │ │ ├── project/ │ │ │ │ ├── auto_root/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Build.act │ │ │ │ │ └── src/ │ │ │ │ │ ├── b.act │ │ │ │ │ └── test.act │ │ │ │ ├── conf_2bin/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Build.act │ │ │ │ │ └── src/ │ │ │ │ │ ├── a.act │ │ │ │ │ └── b.act │ │ │ │ ├── missing_src/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ └── Build.act │ │ │ │ ├── prune_executables/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Build.act │ │ │ │ │ └── src/ │ │ │ │ │ ├── bar.act │ │ │ │ │ ├── foo.act │ │ │ │ │ └── tests/ │ │ │ │ │ └── simple.act │ │ │ │ ├── prune_partials/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Build.act │ │ │ │ │ └── src/ │ │ │ │ │ ├── bar.act │ │ │ │ │ └── foo.act │ │ │ │ ├── prune_roots/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Build.act │ │ │ │ │ └── src/ │ │ │ │ │ └── foo.act │ │ │ │ ├── qualified_root/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Build.act │ │ │ │ │ └── src/ │ │ │ │ │ ├── b.act │ │ │ │ │ └── test.act │ │ │ │ └── simple/ │ │ │ │ ├── .gitignore │ │ │ │ ├── Build.act │ │ │ │ └── src/ │ │ │ │ ├── a.act │ │ │ │ └── b.act │ │ │ ├── rebuild/ │ │ │ │ ├── .gitignore │ │ │ │ ├── Build.act │ │ │ │ └── golden/ │ │ │ │ ├── file_02-initial-build.golden │ │ │ │ ├── file_03-up-to-date.golden │ │ │ │ ├── file_04-touch-no-rebuild.golden │ │ │ │ ├── file_06-change-a-impl.golden │ │ │ │ ├── file_08-change-b-impl.golden │ │ │ │ ├── project_02-initial-build.golden │ │ │ │ ├── project_03-up-to-date.golden │ │ │ │ ├── project_04-touch-no-rebuild.golden │ │ │ │ ├── project_06-change-a-impl.golden │ │ │ │ ├── project_08-change-b-impl.golden │ │ │ │ ├── project_10-change-a-iface.golden │ │ │ │ ├── project_11-change-b-doc.golden │ │ │ │ └── project_12-codegen-stale.golden │ │ │ ├── root/ │ │ │ │ └── test.act │ │ │ ├── syntaxerrors/ │ │ │ │ ├── err1.act │ │ │ │ ├── err1.golden │ │ │ │ ├── err10.act │ │ │ │ ├── err10.golden │ │ │ │ ├── err11.act │ │ │ │ ├── err11.golden │ │ │ │ ├── err12.act │ │ │ │ ├── err12.golden │ │ │ │ ├── err13.act │ │ │ │ ├── err13.golden │ │ │ │ ├── err14.act │ │ │ │ ├── err14.golden │ │ │ │ ├── err15.act │ │ │ │ ├── err15.golden │ │ │ │ ├── err16.act │ │ │ │ ├── err16.golden │ │ │ │ ├── err17.act │ │ │ │ ├── err17.golden │ │ │ │ ├── err18.act │ │ │ │ ├── err18.golden │ │ │ │ ├── err19.act │ │ │ │ ├── err19.golden │ │ │ │ ├── err2.act │ │ │ │ ├── err2.golden │ │ │ │ ├── err20.act │ │ │ │ ├── err20.golden │ │ │ │ ├── err21.act │ │ │ │ ├── err21.golden │ │ │ │ ├── err22.act │ │ │ │ ├── err22.golden │ │ │ │ ├── err23.act │ │ │ │ ├── err23.golden │ │ │ │ ├── err24.act │ │ │ │ ├── err24.golden │ │ │ │ ├── err25.act │ │ │ │ ├── err25.golden │ │ │ │ ├── err26.act │ │ │ │ ├── err26.golden │ │ │ │ ├── err27.act │ │ │ │ ├── err27.golden │ │ │ │ ├── err28.act │ │ │ │ ├── err28.golden │ │ │ │ ├── err29.act │ │ │ │ ├── err29.golden │ │ │ │ ├── err3.act │ │ │ │ ├── err3.golden │ │ │ │ ├── err30.act │ │ │ │ ├── err30.golden │ │ │ │ ├── err31.act │ │ │ │ ├── err31.golden │ │ │ │ ├── err32.act │ │ │ │ ├── err32.golden │ │ │ │ ├── err33.act │ │ │ │ ├── err33.golden │ │ │ │ ├── err34.act │ │ │ │ ├── err34.golden │ │ │ │ ├── err35.act │ │ │ │ ├── err35.golden │ │ │ │ ├── err36.act │ │ │ │ ├── err36.golden │ │ │ │ ├── err37.act │ │ │ │ ├── err37.golden │ │ │ │ ├── err38.act │ │ │ │ ├── err38.golden │ │ │ │ ├── err39.act │ │ │ │ ├── err39.golden │ │ │ │ ├── err4.act │ │ │ │ ├── err4.golden │ │ │ │ ├── err40.act │ │ │ │ ├── err40.golden │ │ │ │ ├── err41.act │ │ │ │ ├── err41.golden │ │ │ │ ├── err42.act │ │ │ │ ├── err42.golden │ │ │ │ ├── err5.act │ │ │ │ ├── err5.golden │ │ │ │ ├── err6.act │ │ │ │ ├── err6.golden │ │ │ │ ├── err7.act │ │ │ │ ├── err7.golden │ │ │ │ ├── err8.act │ │ │ │ ├── err8.golden │ │ │ │ ├── err9.act │ │ │ │ └── err9.golden │ │ │ └── typeerrors/ │ │ │ ├── actor_self_reserved_assignment.act │ │ │ ├── actor_self_reserved_assignment.golden │ │ │ ├── actor_self_reserved_constructor_param.act │ │ │ ├── actor_self_reserved_constructor_param.golden │ │ │ ├── actor_self_reserved_except_as.act │ │ │ ├── actor_self_reserved_except_as.golden │ │ │ ├── actor_self_reserved_loop_var.act │ │ │ ├── actor_self_reserved_loop_var.golden │ │ │ ├── actor_self_reserved_method_name.act │ │ │ ├── actor_self_reserved_method_name.golden │ │ │ ├── actor_self_reserved_method_param.act │ │ │ ├── actor_self_reserved_method_param.golden │ │ │ ├── actor_self_reserved_method_param2.act │ │ │ ├── actor_self_reserved_method_param2.golden │ │ │ ├── actor_self_reserved_variable.act │ │ │ ├── actor_self_reserved_variable.golden │ │ │ ├── ex1.act │ │ │ ├── ex1.golden │ │ │ ├── ex10.act │ │ │ ├── ex10.golden │ │ │ ├── ex11.act │ │ │ ├── ex11.golden │ │ │ ├── ex13.act │ │ │ ├── ex13.golden │ │ │ ├── ex14.act │ │ │ ├── ex14.golden │ │ │ ├── ex15.act │ │ │ ├── ex15.golden │ │ │ ├── ex16.act │ │ │ ├── ex16.golden │ │ │ ├── ex17.act │ │ │ ├── ex17.golden │ │ │ ├── ex18.act │ │ │ ├── ex18.golden │ │ │ ├── ex19.act │ │ │ ├── ex19.golden │ │ │ ├── ex2.act │ │ │ ├── ex2.golden │ │ │ ├── ex20.act │ │ │ ├── ex20.golden │ │ │ ├── ex21.act │ │ │ ├── ex21.golden │ │ │ ├── ex22.act │ │ │ ├── ex22.golden │ │ │ ├── ex23.act │ │ │ ├── ex23.golden │ │ │ ├── ex24.act │ │ │ ├── ex24.golden │ │ │ ├── ex25.act │ │ │ ├── ex25.golden │ │ │ ├── ex26.act │ │ │ ├── ex26.golden │ │ │ ├── ex27.act │ │ │ ├── ex27.golden │ │ │ ├── ex4.act │ │ │ ├── ex4.golden │ │ │ ├── ex5.act │ │ │ ├── ex5.golden │ │ │ ├── ex6.act │ │ │ ├── ex6.golden │ │ │ ├── ex7.act │ │ │ ├── ex7.golden │ │ │ ├── ex8.act │ │ │ ├── ex8.golden │ │ │ ├── ex9.act │ │ │ ├── ex9.golden │ │ │ ├── funargs1.act │ │ │ ├── funargs1.golden │ │ │ ├── funargs2.act │ │ │ ├── funargs2.golden │ │ │ ├── funargs3.act │ │ │ ├── funargs3.golden │ │ │ ├── funargs4.act │ │ │ ├── funargs4.golden │ │ │ ├── funargs5.act │ │ │ ├── funargs5.golden │ │ │ ├── funargs6.act │ │ │ └── funargs6.golden │ │ ├── test.hs │ │ ├── test_incremental.hs │ │ └── test_online.hs │ ├── diagnose/ │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── PATCHES.md │ │ ├── README.md │ │ ├── diagnose.cabal │ │ ├── hie.yaml │ │ ├── nix/ │ │ │ ├── nixpkgs-pinned.nix │ │ │ └── stack.nix │ │ ├── package.yaml │ │ ├── src/ │ │ │ ├── Data/ │ │ │ │ └── List/ │ │ │ │ └── Safe.hs │ │ │ └── Error/ │ │ │ ├── Diagnose/ │ │ │ │ ├── Compat/ │ │ │ │ │ ├── Hints.hs │ │ │ │ │ ├── Megaparsec.hs │ │ │ │ │ └── Parsec.hs │ │ │ │ ├── Diagnostic/ │ │ │ │ │ └── Internal.hs │ │ │ │ ├── Diagnostic.hs │ │ │ │ ├── Position.hs │ │ │ │ ├── Pretty.hs │ │ │ │ ├── Report/ │ │ │ │ │ └── Internal.hs │ │ │ │ ├── Report.hs │ │ │ │ └── Style.hs │ │ │ └── Diagnose.hs │ │ ├── stack.yaml │ │ └── test/ │ │ ├── megaparsec/ │ │ │ ├── Instances.hs │ │ │ ├── Repro6.hs │ │ │ └── Spec.hs │ │ ├── parsec/ │ │ │ ├── Repro2.hs │ │ │ └── Spec.hs │ │ └── rendering/ │ │ └── Spec.hs │ ├── lib/ │ │ ├── bench/ │ │ │ ├── KindsBench.hs │ │ │ └── TypesBench.hs │ │ ├── package.yaml.in │ │ ├── src/ │ │ │ ├── Acton/ │ │ │ │ ├── Boxing.hs │ │ │ │ ├── BuildSpec.hs │ │ │ │ ├── Builtin.hs │ │ │ │ ├── CPS.hs │ │ │ │ ├── CodeGen.hs │ │ │ │ ├── CommandLineParser.hs │ │ │ │ ├── Compile.hs │ │ │ │ ├── Completion.hs │ │ │ │ ├── Converter.hs │ │ │ │ ├── Deactorizer.hs │ │ │ │ ├── Diagnostics.hs │ │ │ │ ├── DocPrinter.hs │ │ │ │ ├── Env.hs │ │ │ │ ├── Fingerprint.hs │ │ │ │ ├── Hashing.hs │ │ │ │ ├── Kinds.hs │ │ │ │ ├── LambdaLifter.hs │ │ │ │ ├── NameInfo.hs │ │ │ │ ├── Names.hs │ │ │ │ ├── Normalizer.hs │ │ │ │ ├── Parser.hs │ │ │ │ ├── Prim.hs │ │ │ │ ├── Printer.hs │ │ │ │ ├── QuickType.hs │ │ │ │ ├── Solver.hs │ │ │ │ ├── SourceProvider.hs │ │ │ │ ├── Subst.hs │ │ │ │ ├── Syntax.hs │ │ │ │ ├── Testing.hs │ │ │ │ ├── Transform.hs │ │ │ │ ├── TypeEnv.hs │ │ │ │ ├── Types.hs │ │ │ │ └── WitKnots.hs │ │ │ ├── InterfaceFiles.hs │ │ │ ├── Pretty.hs │ │ │ ├── SrcLocation.hs │ │ │ ├── Text_Megaparsec_Expr.hs │ │ │ └── Utils.hs │ │ └── test/ │ │ ├── 1-parse/ │ │ │ ├── docstrings.input │ │ │ ├── docstrings.output │ │ │ ├── syntax1.input │ │ │ └── syntax1.output │ │ ├── 2-kinds/ │ │ │ ├── deact.input │ │ │ └── deact.output │ │ ├── 3-types/ │ │ │ ├── class_init_attrs/ │ │ │ │ ├── uninit_assert_uninit_attr.golden │ │ │ │ ├── uninit_augmented_assign.golden │ │ │ │ ├── uninit_basic.golden │ │ │ │ ├── uninit_basic_inferred.golden │ │ │ │ ├── uninit_elif_missing.golden │ │ │ │ ├── uninit_for_loop.golden │ │ │ │ ├── uninit_grandparent.golden │ │ │ │ ├── uninit_grandparent2.golden │ │ │ │ ├── uninit_inherited.golden │ │ │ │ ├── uninit_init_in_method.golden │ │ │ │ ├── uninit_loop_references_self.golden │ │ │ │ ├── uninit_method_call.golden │ │ │ │ ├── uninit_method_call_assign.golden │ │ │ │ ├── uninit_method_reference.golden │ │ │ │ ├── uninit_nested_function_escape.golden │ │ │ │ ├── uninit_nested_function_with_self.golden │ │ │ │ ├── uninit_nested_if.golden │ │ │ │ ├── uninit_no_parent_init.golden │ │ │ │ ├── uninit_notimpl_call_other.golden │ │ │ │ ├── uninit_partial.golden │ │ │ │ ├── uninit_return_early.golden │ │ │ │ ├── uninit_self_attr_access.golden │ │ │ │ ├── uninit_self_in_list.golden │ │ │ │ ├── uninit_self_reference.golden │ │ │ │ └── uninit_try_except.golden │ │ │ ├── deact.input │ │ │ ├── deact.output │ │ │ ├── test_discovery.input │ │ │ └── test_discovery.output │ │ ├── 4-normalizer/ │ │ │ ├── deact.input │ │ │ └── deact.output │ │ ├── 5-deactorizer/ │ │ │ ├── deact.input │ │ │ ├── deact.output │ │ │ ├── deact_from_import.input │ │ │ └── deact_from_import.output │ │ ├── 6-cps/ │ │ │ ├── cps_andor.input │ │ │ ├── cps_andor.output │ │ │ ├── cps_optchain.input │ │ │ ├── cps_optchain.output │ │ │ ├── cps_volatiles.input │ │ │ └── cps_volatiles.output │ │ ├── 7-lambdalifting/ │ │ │ ├── deact.input │ │ │ └── deact.output │ │ ├── 8-boxing/ │ │ │ ├── deact.input │ │ │ └── deact.output │ │ ├── 9-codegen/ │ │ │ ├── deact.c │ │ │ ├── deact.h │ │ │ ├── deact.input │ │ │ ├── ints.c │ │ │ ├── ints.h │ │ │ ├── ints.input │ │ │ ├── lines.c │ │ │ ├── lines.h │ │ │ └── lines.input │ │ ├── ActonSpec.hs │ │ ├── doc-golden/ │ │ │ ├── bar-color.txt │ │ │ ├── bar.html │ │ │ ├── bar.md │ │ │ ├── bar.txt │ │ │ ├── foo-color.txt │ │ │ ├── foo.html │ │ │ ├── foo.md │ │ │ └── foo.txt │ │ ├── parser_golden/ │ │ │ ├── alternating_quotes_error.golden │ │ │ ├── deep_nesting_error.golden │ │ │ ├── error_at_end.golden │ │ │ ├── error_at_start.golden │ │ │ ├── error_in_middle.golden │ │ │ ├── escaped_brace_error.golden │ │ │ ├── fstring_empty_expression.golden │ │ │ ├── fstring_empty_format_specifier.golden │ │ │ ├── fstring_invalid_alignment.golden │ │ │ ├── fstring_invalid_format.golden │ │ │ ├── fstring_missing_expression.golden │ │ │ ├── fstring_missing_precision_digits_error.golden │ │ │ ├── fstring_triple_double_6quotes.golden │ │ │ ├── fstring_triple_single_6quotes.golden │ │ │ ├── fstring_unbalanced_format.golden │ │ │ ├── fstring_unclosed_brace.golden │ │ │ ├── hex_incomplete_in_interpolation.golden │ │ │ ├── hex_incomplete_no_digits.golden │ │ │ ├── hex_incomplete_one_digit.golden │ │ │ ├── hex_invalid_char.golden │ │ │ ├── invalid_after_align.golden │ │ │ ├── invalid_after_precision.golden │ │ │ ├── invalid_after_width.golden │ │ │ ├── invalid_in_type_spec.golden │ │ │ ├── mixed_quotes_unclosed.golden │ │ │ ├── mixed_six_quotes_double.golden │ │ │ ├── module_actor_before_import.golden │ │ │ ├── module_call_before_import.golden │ │ │ ├── module_class_before_import.golden │ │ │ ├── module_dict_before_import.golden │ │ │ ├── module_for_before_import.golden │ │ │ ├── module_func_before_import.golden │ │ │ ├── module_if_before_import.golden │ │ │ ├── module_list_before_import.golden │ │ │ ├── module_number_before_import.golden │ │ │ ├── module_var_before_import.golden │ │ │ ├── multiline_format_error.golden │ │ │ ├── multiline_nested_error.golden │ │ │ ├── multiline_unclosed.golden │ │ │ ├── nested_bad_type_spec.golden │ │ │ ├── nested_empty_format.golden │ │ │ ├── nested_empty_inner.golden │ │ │ ├── nested_invalid_align.golden │ │ │ ├── nested_invalid_format.golden │ │ │ ├── nested_unclosed_inner.golden │ │ │ ├── nested_unclosed_outer.golden │ │ │ ├── newline_in_expr.golden │ │ │ ├── octal_invalid_char.golden │ │ │ ├── octal_invalid_first_digit.golden │ │ │ ├── octal_out_of_range.golden │ │ │ ├── octal_out_of_range_in_fstring.golden │ │ │ ├── raw_six_quotes.golden │ │ │ ├── raw_triple_double_6quotes.golden │ │ │ ├── raw_triple_single_6quotes.golden │ │ │ ├── seven_double_quotes.golden │ │ │ ├── six_double_quotes.golden │ │ │ ├── six_single_quotes.golden │ │ │ ├── slice_format_error.golden │ │ │ ├── slice_invalid_step.golden │ │ │ ├── slice_missing_bracket.golden │ │ │ ├── slice_nested_error.golden │ │ │ ├── slice_unclosed_bracket.golden │ │ │ ├── string_empty_expression.golden │ │ │ ├── string_invalid_format.golden │ │ │ ├── string_missing_expression.golden │ │ │ ├── string_unclosed_brace.golden │ │ │ ├── tab_in_format.golden │ │ │ ├── triple_double_10quotes.golden │ │ │ ├── triple_double_6quotes.golden │ │ │ ├── triple_double_7quotes.golden │ │ │ ├── triple_double_8quotes.golden │ │ │ ├── triple_nested_unclosed.golden │ │ │ ├── triple_single_10quotes.golden │ │ │ ├── triple_single_6quotes.golden │ │ │ ├── triple_single_7quotes.golden │ │ │ ├── triple_single_8quotes.golden │ │ │ ├── tristring_unclosed_brace.golden │ │ │ ├── unclosed_bytes_string.golden │ │ │ ├── unclosed_bytes_string_single.golden │ │ │ ├── unclosed_raw_bytes_string.golden │ │ │ ├── unclosed_raw_bytes_string_single.golden │ │ │ ├── unclosed_raw_string.golden │ │ │ ├── unclosed_raw_string_single.golden │ │ │ ├── unclosed_string.golden │ │ │ ├── unclosed_string_triple.golden │ │ │ ├── unicode_format_error.golden │ │ │ ├── unicode_long_in_fstring.golden │ │ │ ├── unicode_long_incomplete.golden │ │ │ ├── unicode_long_invalid_char.golden │ │ │ ├── unicode_long_no_digits.golden │ │ │ ├── unicode_short_in_fstring.golden │ │ │ ├── unicode_short_incomplete.golden │ │ │ ├── unicode_short_invalid_char.golden │ │ │ ├── unicode_short_no_digits.golden │ │ │ ├── unknown_escape_in_fstring.golden │ │ │ ├── unknown_escape_p.golden │ │ │ ├── unknown_escape_with_interpolation.golden │ │ │ └── unknown_escape_z.golden │ │ └── src/ │ │ ├── bar.act │ │ ├── class_init_attrs/ │ │ │ ├── init_actor.act │ │ │ ├── init_actor_call.act │ │ │ ├── init_after_loop.act │ │ │ ├── init_after_statements.act │ │ │ ├── init_after_while.act │ │ │ ├── init_assert.act │ │ │ ├── init_assert_with_self.act │ │ │ ├── init_basic.act │ │ │ ├── init_both_branches_with_raise.act │ │ │ ├── init_conditional.act │ │ │ ├── init_constant_condition.act │ │ │ ├── init_delete.act │ │ │ ├── init_elif_raise_after_assignment.act │ │ │ ├── init_except_raise_after_assignment.act │ │ │ ├── init_function_call.act │ │ │ ├── init_grandparent_call.act │ │ │ ├── init_inferred_only.act │ │ │ ├── init_inherited.act │ │ │ ├── init_loop_break.act │ │ │ ├── init_loop_continue.act │ │ │ ├── init_mixed_parent_self.act │ │ │ ├── init_multiple.act │ │ │ ├── init_multiple_except_handlers.act │ │ │ ├── init_nested_function.act │ │ │ ├── init_nested_function_call.act │ │ │ ├── init_nested_if.act │ │ │ ├── init_nested_if_raise.act │ │ │ ├── init_no_init_uses_parent.act │ │ │ ├── init_notimpl_call.act │ │ │ ├── init_notimplemented.act │ │ │ ├── init_parent_call.act │ │ │ ├── init_raise_after_assignment.act │ │ │ ├── init_self_attr_access.act │ │ │ ├── init_self_attr_conditional.act │ │ │ ├── init_self_attr_in_expr.act │ │ │ ├── init_self_attr_in_loop.act │ │ │ ├── init_self_attr_reference.act │ │ │ ├── init_try_else_combined.act │ │ │ ├── init_try_except.act │ │ │ ├── init_try_except_finally.act │ │ │ ├── init_try_except_raise.act │ │ │ ├── init_try_finally.act │ │ │ ├── init_try_inside_if.act │ │ │ ├── uninit_assert_uninit_attr.act │ │ │ ├── uninit_augmented_assign.act │ │ │ ├── uninit_basic.act │ │ │ ├── uninit_basic_inferred.act │ │ │ ├── uninit_elif_missing.act │ │ │ ├── uninit_for_loop.act │ │ │ ├── uninit_grandparent.act │ │ │ ├── uninit_grandparent2.act │ │ │ ├── uninit_inherited.act │ │ │ ├── uninit_init_in_method.act │ │ │ ├── uninit_loop_references_self.act │ │ │ ├── uninit_method_call.act │ │ │ ├── uninit_method_call_assign.act │ │ │ ├── uninit_method_reference.act │ │ │ ├── uninit_nested_function_escape.act │ │ │ ├── uninit_nested_function_with_self.act │ │ │ ├── uninit_nested_if.act │ │ │ ├── uninit_no_parent_init.act │ │ │ ├── uninit_notimpl_call_other.act │ │ │ ├── uninit_partial.act │ │ │ ├── uninit_return_early.act │ │ │ ├── uninit_self_attr_access.act │ │ │ ├── uninit_self_in_list.act │ │ │ ├── uninit_self_reference.act │ │ │ └── uninit_try_except.act │ │ ├── cps_andor.act │ │ ├── cps_optchain.act │ │ ├── cps_volatiles.act │ │ ├── deact.act │ │ ├── deact_from_import.act │ │ ├── docstrings.act │ │ ├── foo.act │ │ ├── import_private.act │ │ ├── import_private_a.act │ │ ├── import_private_qualified.act │ │ ├── ints.act │ │ ├── lines.act │ │ ├── syntax1.act │ │ └── test_discovery.act │ ├── lsp-server/ │ │ ├── Main.hs │ │ └── package.yaml.in │ ├── stack.yaml │ ├── test/ │ │ └── .gitignore │ ├── tests/ │ │ ├── Acton.hs │ │ ├── ActonLevels.hs │ │ ├── CPretty.hs │ │ ├── ProtExtElim.hs │ │ ├── TestTransform.hs │ │ ├── actorring.act │ │ ├── controller.act │ │ ├── counter.act │ │ ├── env.act │ │ ├── env.c │ │ ├── netconf.act │ │ ├── newtuple.act │ │ ├── pingpong.act │ │ ├── records.act │ │ ├── test.act │ │ ├── test1.act │ │ ├── test2.act │ │ ├── test3.act │ │ ├── test4.act │ │ ├── test5.act │ │ ├── test6.act │ │ └── tuples.act │ └── tools/ │ ├── ld-wrapper.sh │ ├── zig-cc.sh │ └── zig-cxx.sh ├── completion/ │ └── acton.bash-completion ├── debian/ │ ├── acton.bash-completion │ ├── changelog.in │ ├── control │ ├── copyright │ ├── rules │ └── watch ├── docs/ │ ├── acton-dev-guide/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── book.toml │ │ ├── mdbook-admonish.css │ │ ├── src/ │ │ │ ├── SUMMARY.md │ │ │ ├── builtins/ │ │ │ │ ├── ffi.md │ │ │ │ ├── functions.md │ │ │ │ ├── index.md │ │ │ │ └── types.md │ │ │ ├── compiler/ │ │ │ │ ├── imports_and_envs.md │ │ │ │ ├── incremental_compilation.md │ │ │ │ ├── index.md │ │ │ │ ├── passes/ │ │ │ │ │ ├── boxing.md │ │ │ │ │ ├── codegen.md │ │ │ │ │ ├── cps.md │ │ │ │ │ ├── deactorize.md │ │ │ │ │ ├── index.md │ │ │ │ │ ├── kinds.md │ │ │ │ │ ├── lambda_lift.md │ │ │ │ │ ├── normalize.md │ │ │ │ │ ├── parse.md │ │ │ │ │ └── type_check.md │ │ │ │ ├── project_dependencies.md │ │ │ │ └── test_cache.md │ │ │ ├── design/ │ │ │ │ ├── capabilities.md │ │ │ │ ├── concurrency.md │ │ │ │ └── index.md │ │ │ ├── getting_started/ │ │ │ │ ├── build.md │ │ │ │ ├── debugging.md │ │ │ │ ├── repo_layout.md │ │ │ │ └── tests.md │ │ │ ├── getting_started.md │ │ │ ├── index.md │ │ │ ├── runtime/ │ │ │ │ ├── actors.md │ │ │ │ ├── index.md │ │ │ │ ├── memory.md │ │ │ │ └── scheduler.md │ │ │ └── tooling/ │ │ │ ├── index.md │ │ │ └── testing.md │ │ ├── svgbob.css │ │ └── theme/ │ │ ├── content-width.css │ │ ├── sbscode.css │ │ ├── sbscode_copy.js │ │ ├── skill-slider.css │ │ ├── skill-slider.js │ │ ├── tabs.css │ │ └── tabs.js │ ├── acton-guide/ │ │ ├── .gitignore │ │ ├── LANGUAGE_REVIEW.md │ │ ├── README.md │ │ ├── RUST_BOOK_COMPARISON.md │ │ ├── book.toml │ │ ├── mdbook-admonish.css │ │ ├── src/ │ │ │ ├── SUMMARY.md │ │ │ ├── actors/ │ │ │ │ ├── async_method_call.md │ │ │ │ ├── attributes.md │ │ │ │ ├── cleanup.md │ │ │ │ ├── concurrency.md │ │ │ │ ├── lifetime.md │ │ │ │ ├── root.md │ │ │ │ ├── self.md │ │ │ │ ├── sequential.md │ │ │ │ └── sync_method_call.md │ │ │ ├── actors.md │ │ │ ├── classes/ │ │ │ │ ├── inheritance.md │ │ │ │ ├── initialization.md │ │ │ │ └── intro.md │ │ │ ├── collections/ │ │ │ │ ├── dicts.md │ │ │ │ ├── lists.md │ │ │ │ └── sets.md │ │ │ ├── collections.md │ │ │ ├── compilation/ │ │ │ │ └── incremental.md │ │ │ ├── compilation.md │ │ │ ├── control_flow/ │ │ │ │ ├── actors.md │ │ │ │ ├── after_sleep.md │ │ │ │ ├── for.md │ │ │ │ ├── if_else.md │ │ │ │ └── while.md │ │ │ ├── control_flow.md │ │ │ ├── environment/ │ │ │ │ ├── interactive_stdin.md │ │ │ │ ├── stdin.md │ │ │ │ └── variables.md │ │ │ ├── environment.md │ │ │ ├── ext/ │ │ │ │ └── integrating_c_library.md │ │ │ ├── functions/ │ │ │ │ ├── actor_methods.md │ │ │ │ └── higher_order.md │ │ │ ├── functions.md │ │ │ ├── hello/ │ │ │ │ ├── args.md │ │ │ │ ├── running_tests.md │ │ │ │ └── shebang.md │ │ │ ├── hello.md │ │ │ ├── index.md │ │ │ ├── install.md │ │ │ ├── install_tip.md │ │ │ ├── language/ │ │ │ │ ├── bindings_scope.md │ │ │ │ ├── comments.md │ │ │ │ ├── common_programming_concepts.md │ │ │ │ ├── environment_capabilities.md │ │ │ │ ├── errors_exceptions.md │ │ │ │ ├── expressions_operators.md │ │ │ │ ├── missing_values_failures.md │ │ │ │ ├── modeling_data_interfaces.md │ │ │ │ ├── optionals_none.md │ │ │ │ ├── organizing_code.md │ │ │ │ └── state_concurrency.md │ │ │ ├── language.md │ │ │ ├── modules.md │ │ │ ├── naming.md │ │ │ ├── package_management.md │ │ │ ├── pkg/ │ │ │ │ ├── add_dependency.md │ │ │ │ ├── fetch_dependencies.md │ │ │ │ ├── fingerprint.md │ │ │ │ ├── local_dependencies.md │ │ │ │ ├── override_dependency.md │ │ │ │ ├── package_index.md │ │ │ │ └── remove_dependency.md │ │ │ ├── primitives/ │ │ │ │ ├── complex.md │ │ │ │ ├── float.md │ │ │ │ ├── integers.md │ │ │ │ ├── scalars.md │ │ │ │ └── tuples.md │ │ │ ├── primitives.md │ │ │ ├── projects/ │ │ │ │ └── directory_structure.md │ │ │ ├── projects.md │ │ │ ├── protocols/ │ │ │ │ ├── dispatch.md │ │ │ │ └── intro.md │ │ │ ├── rts.md │ │ │ ├── security/ │ │ │ │ ├── capabilities.md │ │ │ │ └── intro.md │ │ │ ├── security.md │ │ │ ├── stdlib/ │ │ │ │ ├── builtin_protocols/ │ │ │ │ │ ├── collection.md │ │ │ │ │ ├── general.md │ │ │ │ │ ├── hashable.md │ │ │ │ │ └── numeric.md │ │ │ │ ├── builtin_protocols.md │ │ │ │ ├── math.md │ │ │ │ ├── re.md │ │ │ │ └── standard_library.md │ │ │ ├── stdlib.md │ │ │ ├── testing/ │ │ │ │ ├── async_actor_test.md │ │ │ │ ├── env_test.md │ │ │ │ ├── failures_errors.md │ │ │ │ ├── flaky.md │ │ │ │ ├── perf_record.md │ │ │ │ ├── performance.md │ │ │ │ ├── snapshot.md │ │ │ │ ├── stress.md │ │ │ │ ├── sync_actor_test.md │ │ │ │ └── unit_test.md │ │ │ ├── testing.md │ │ │ ├── types/ │ │ │ │ ├── effects.md │ │ │ │ ├── explicit.md │ │ │ │ ├── generics.md │ │ │ │ ├── intro.md │ │ │ │ ├── optionals.md │ │ │ │ └── troubleshooting.md │ │ │ ├── working_with_zig.md │ │ │ └── zig_dependencies.md │ │ ├── svgbob.css │ │ └── theme/ │ │ ├── acton-theme.css │ │ ├── acton-theme.js │ │ ├── content-width.css │ │ ├── detail-toggles.css │ │ ├── detail-toggles.js │ │ ├── guide-links.css │ │ ├── guide-links.js │ │ ├── sbscode.css │ │ ├── sbscode_copy.js │ │ ├── tabs.css │ │ └── tabs.js │ ├── dev.md │ ├── git-develop-workflow.md │ ├── git-feature-workflow.md │ ├── run-example.py │ ├── triage.md │ ├── tutorial/ │ │ ├── README.md │ │ ├── example-0.md │ │ ├── example-1.md │ │ ├── example-2.md │ │ └── example-3.md │ └── wrapping_c_libraries.md ├── ecolift/ │ ├── CLAUDE.md │ ├── repos/ │ │ └── .gitignore │ └── string_interpolation.md ├── examples/ │ ├── .acton │ ├── StringsAndBytes.act │ ├── abs.act │ ├── average.act │ ├── bsplit.act │ ├── client.act │ ├── count.act │ ├── counter.act │ ├── eq_list_dict.act │ ├── files.act │ ├── helloworld.act │ ├── http_server.act │ ├── inter.act │ ├── print_time.act │ ├── reprtest.act │ ├── server.act │ ├── sieve.act │ ├── sumto.act │ └── worker.act ├── homebrew/ │ └── Formula/ │ └── acton.rb ├── slides/ │ └── ActonCompiler.pptx ├── test/ │ ├── .acton │ ├── Makefile │ └── count.act ├── utils/ │ ├── actonmon │ ├── changelog-find-missing-link-defs.py │ ├── lldb/ │ │ ├── README.md │ │ └── acton.py │ └── update-changelog.sh ├── version.mk └── workspace/ ├── MRO.hs ├── Plan-scribble.txt ├── Plan.txt ├── Semantics.txt ├── Type-hierarchy.act ├── Type-hierarchy.txt ├── Typesystem.txt ├── anomaly_detector/ │ ├── acton_anomaly_detector2.py │ ├── acton_anomaly_detector3.py │ ├── acton_anomaly_detector_demo.py │ ├── acton_anomaly_detector_demo2.py │ └── datasets/ │ └── selected/ │ ├── level_change/ │ │ ├── ambient_temperature_system_failure.csv │ │ ├── ec2_cpu_utilization_825cc2.csv │ │ ├── ec2_cpu_utilization_ac20cd.csv │ │ ├── grok_asg_anomaly.csv │ │ ├── rds_cpu_utilization_cc0c53.csv │ │ └── rds_cpu_utilization_e47b3b.csv │ ├── outliers/ │ │ ├── ec2_cpu_utilization_fe7f93.csv │ │ └── rogue_agent_key_hold.csv │ ├── seasonal/ │ │ ├── Twitter_volume_GOOG.csv │ │ ├── art_daily_jumpsdown.csv │ │ ├── art_daily_jumpsup.csv │ │ ├── art_daily_jumpsup_noised.csv │ │ ├── art_daily_jumpsup_noised_trended.csv │ │ ├── art_daily_jumpsup_noised_trended_det.csv │ │ ├── art_daily_jumpsup_noised_trended_det2.csv │ │ ├── art_daily_jumpsup_noised_trended_det2_ts.csv │ │ ├── art_daily_nojump.csv │ │ ├── exchange-2_cpc_results.csv │ │ ├── exchange-2_cpm_results.csv │ │ ├── exchange-3_cpm_results.csv │ │ ├── nyc_taxi.csv │ │ ├── occupancy_6005.csv │ │ └── occupancy_t4013.csv │ ├── trending/ │ │ └── ambient_temperature_system_failure.csv │ └── variance_change/ │ └── exchange-3_cpm_results.csv ├── concurrent_taskpool/ │ ├── Makefile │ ├── src/ │ │ ├── Makefile │ │ ├── concurrent_task_pool.h │ │ ├── concurrent_task_pool_list.c │ │ ├── concurrent_task_pool_tree.c │ │ └── fastrand.h │ └── tests_and_benchmarks/ │ ├── Makefile │ ├── benchmarking_scripts/ │ │ ├── compare_old_new │ │ ├── compare_settings │ │ ├── get_series │ │ ├── get_series_avg │ │ ├── get_series_q │ │ ├── get_series_r │ │ ├── get_series_r_avg │ │ ├── rank_param_settings │ │ ├── rank_param_settings_d_h │ │ ├── rank_param_settings_freqs │ │ └── rank_param_settings_freqs_d_h │ ├── concurrent_task_pool_test_multithreaded.c │ └── concurrent_task_pool_test_multithreaded_mixed.c ├── micke/ │ ├── Makefile │ ├── bytesview.c │ ├── bytesview.h │ ├── bytesview.py │ ├── bytesview_test.c │ ├── flow.txt │ └── processing.txt ├── misc-examples/ │ ├── divtest.act │ ├── loess_smoother.act │ ├── loess_smoother3.act │ ├── loess_smoother4.act │ ├── loess_smoother5.act │ ├── numpyfns.act │ └── timestest.act └── upgrades/ ├── upgrade_v1 ├── upgrade_v1.act ├── upgrade_v2 └── upgrade_v2.act ================================================ FILE CONTENTS ================================================ ================================================ FILE: .containerignore ================================================ * !dist ================================================ FILE: .github/ISSUE_TEMPLATE/blank_issue.md ================================================ --- name: Blank Issue about: Create a blank issue. --- ================================================ FILE: .github/ISSUE_TEMPLATE/bug.yaml ================================================ name: "\U0001F41E Bug Report" description: "Create a bug report for Acton." labels: ["bug"] body: - type: markdown attributes: value: | A bug is when something works differently than it is expected to. ## Remember to search before filing a new report Please search for this bug in the issue tracker, and use a bug report title that would have made your bug report turn up in the search results for your search query. - type: input id: version attributes: label: Acton Version description: "The output of `acton version`" placeholder: "0.16.3" validations: required: true - type: textarea id: repro attributes: label: Steps to Reproduce and Observed Behavior description: What exactly can someone else do, in order to observe the problem that you observed? Include the output and all error messages. validations: required: true - type: textarea id: expected attributes: label: Expected Behavior description: What did you expect to happen instead? validations: required: true ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: true contact_links: - name: 🗣 Ask a Question, Discuss url: https://github.com/actonlang/acton/discussions about: Please ask and answer questions about Acton using GitHub discussions. ================================================ FILE: .github/ISSUE_TEMPLATE/feature.yaml ================================================ name: "\U0001F680 Feature / Enhancement Request" description: "Suggest a new idea / feature enhancement for Acton." labels: ["enhancement"] body: - type: markdown attributes: value: | A feature is when you would like to add new functionality or change current functionality / behavior. ## Remember to search before filing a new report Please search for this feature request in the issue tracker, and use a feature request title that would have made your feature request turn up in the search results for your search query. - type: textarea id: repro attributes: label: Proposal description: Provide a clear and concise description of what you want validations: required: true - type: textarea id: expected attributes: label: Motivation description: Explain the problem that your proposal is attempting to address validations: required: true - type: textarea id: actual attributes: label: Alternatives description: What other solutions have you tried or considered? validations: required: true ================================================ FILE: .github/ISSUE_TEMPLATE/ice.yaml ================================================ name: "\U0001F4A5 Internal Compiler Error" description: "Create a report for an Internal Compiler Error (ICE) in acton." labels: ["bug", "Compiler"] body: - type: markdown attributes: value: | We're sorry to hear you encountered an Internal Compiler Error and thank you for reporting it! If possible, try to provide a minimal reproduction case. - type: input id: version attributes: label: Acton Version description: "The output of `acton version`" placeholder: "0.16.3" validations: required: true - type: textarea id: repro attributes: label: Reproduction code description: What exactly can someone else do, in order to trigger the ICE? placeholder: If possible, try to provide a minimal reproduction case. validations: required: true - type: textarea id: expected attributes: label: Error output description: Include the full output from compiling using `acton` placeholder: | $ ../dist/acton counter_adder.act /home/user/acton/dist/modules/test/counter_adder.c: In function ‘test$counter_adder$$Counter$count$local’: /home/user/acton/dist/modules/test/counter_adder.c:224:9: error: conversion to non-scalar type requested 224 | return (($R)__self__->i); | ^~~~~~ ERROR: internal compiler error: compilation of generated C code failed NOTE: this is likely a bug in acton, please report this at: NOTE: https://github.com/actonlang/acton/issues/new?template=ice.md NOTE: acton 0.5.2.20210904.7.7.37 $ validations: required: true ================================================ FILE: .github/dependabot.yml ================================================ # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "github-actions" directory: "/" # Location of package manifests schedule: interval: "weekly" ================================================ FILE: .github/workflows/claude.yml ================================================ name: Claude Code on: issue_comment: types: [created] pull_request_review_comment: types: [created] issues: types: [opened, assigned] pull_request_review: types: [submitted] jobs: claude: if: | (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) runs-on: ubuntu-latest permissions: contents: read pull-requests: read issues: read id-token: write steps: - name: Checkout repository uses: actions/checkout@v6 with: fetch-depth: 1 - name: Run Claude Code id: claude uses: anthropics/claude-code-action@beta with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} ================================================ FILE: .github/workflows/code-agent.yml ================================================ name: Code Agent permissions: contents: write pull-requests: write issues: write on: issues: types: [opened] issue_comment: types: [created] pull_request_review_comment: types: [created] jobs: code-agent: runs-on: ubuntu-latest if: ${{ github.event.sender.type != 'Bot' }} steps: - uses: potproject/code-agent@main with: github-token: ${{ secrets.GITHUB_TOKEN }} # [Claude Code Settings] anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} # [Optional Claude Code Settings] # anthropic-base-url: "https://api.anthropic.com" # anthropic-model: "claude-3-7-sonnet-20250219" # anthropic-small-fast-model: "claude-3-5-haiku-20241022" # claude-code-use-bedrock: "1" # anthropic-bedrock-base-url: "https://bedrock.us-east-1.amazonaws.com" # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # aws-region: "us-east-1" # disable-prompt-caching: "1" # [Codex Settings] openai-api-key: ${{ secrets.OPENAI_API_KEY }} # [Optional Codex Settings] # openai-base-url: "https://api.openai.com" ================================================ FILE: .github/workflows/create-release.yml ================================================ name: Create Release Branch on: workflow_dispatch: inputs: release_type: description: 'Release Type' required: true type: choice options: - major - minor - patch default: 'patch' jobs: create-release-branch: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v6 with: ssh-key: ${{ secrets.ACTONBOT_DEPLOY_KEY }} fetch-depth: 0 - name: Set up Git user run: | git config user.name "Acton Bot" git config user.email apt@acton-lang.org - name: Get current version id: current_version run: | VERSION=$(grep "^VERSION=" version.mk | cut -d= -f2) echo "Current version: $VERSION" echo "version=$VERSION" >> $GITHUB_OUTPUT # Split version MAJOR=$(echo $VERSION | cut -d. -f1) MINOR=$(echo $VERSION | cut -d. -f2) PATCH=$(echo $VERSION | cut -d. -f3) echo "major=$MAJOR" >> $GITHUB_OUTPUT echo "minor=$MINOR" >> $GITHUB_OUTPUT echo "patch=$PATCH" >> $GITHUB_OUTPUT - name: Calculate new version id: new_version run: | MAJOR=${{ steps.current_version.outputs.major }} MINOR=${{ steps.current_version.outputs.minor }} PATCH=${{ steps.current_version.outputs.patch }} if [[ "${{ github.event.inputs.release_type }}" == "major" ]]; then MAJOR=$((MAJOR + 1)) MINOR=0 PATCH=0 elif [[ "${{ github.event.inputs.release_type }}" == "minor" ]]; then MINOR=$((MINOR + 1)) PATCH=0 else # patch PATCH=$((PATCH + 1)) fi NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" echo "New version: $NEW_VERSION" echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT - name: Update version in version.mk run: | NEW_VERSION=${{ steps.new_version.outputs.version }} sed -i "s/^VERSION=.*/VERSION=${NEW_VERSION}/" version.mk - name: Update CHANGELOG.md run: | NEW_VERSION=${{ steps.new_version.outputs.version }} TODAY=$(date +%Y-%m-%d) # Replace [Unreleased] with the new version sed -i "s/## \[Unreleased\]/## [${NEW_VERSION}] - ${TODAY}/" CHANGELOG.md - name: Create and push release branch run: | NEW_VERSION=${{ steps.new_version.outputs.version }} BRANCH_NAME="release-v${NEW_VERSION}" git checkout -b $BRANCH_NAME git add version.mk CHANGELOG.md git commit -m "Release version ${NEW_VERSION}" git push origin $BRANCH_NAME echo "::notice::Created release branch $BRANCH_NAME with version $NEW_VERSION" - name: Create pull request env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | NEW_VERSION=${{ steps.new_version.outputs.version }} BRANCH_NAME="release-v${NEW_VERSION}" gh pr create \ --title "Release v${NEW_VERSION}" \ --base main \ --head $BRANCH_NAME \ --body "This PR updates the version to ${NEW_VERSION} and prepares the CHANGELOG.md for release." ================================================ FILE: .github/workflows/release.yml ================================================ name: Add git tag for release on: pull_request: types: - closed jobs: if_merged: # name should be e.g. release-v1.2.3 if: ${{ startsWith(github.head_ref, 'release-v') && github.event.pull_request.merged == true }} runs-on: ubuntu-latest steps: - run: | echo The PR was merged - name: "Check out repository code" uses: actions/checkout@v6 with: ssh-key: ${{ secrets.ACTONBOT_DEPLOY_KEY }} - name: "Get the version" id: get_version run: echo "version=$(grep VERSION= version.mk | cut -d = -f 2)" >> $GITHUB_OUTPUT - name: "Add version tag and push" run: | git config user.name "Apt Bot" git config user.email apt@acton-lang.org git tag v${{steps.get_version.outputs.version}} git push origin v${{steps.get_version.outputs.version}} ================================================ FILE: .github/workflows/test-app.yml ================================================ on: workflow_call: inputs: repo_url: required: true type: string arch: required: false type: string default: "amd64" jobs: test-app: runs-on: ubuntu-24.04${{ inputs.arch == 'arm64' && '-arm' || '' }} steps: - name: "Install gdb" run: | sudo apt update sudo apt install -y gdb - name: "Download .deb files" uses: actions/download-artifact@v8 with: name: acton-debs-${{ inputs.arch }} - name: "Install acton from .deb" run: | sudo apt install -y ./deb/acton_*.deb acton version - name: "Clone app repo" uses: actions/checkout@v6 with: repository: ${{ inputs.repo_url }} path: app - name: "Compile acton program" run: | cd app acton build acton test acton test perf ================================================ FILE: .github/workflows/test.yml ================================================ name: Build, Test & Release # Build, Test & Release (BTR) run for: # - pushes to the main branch # - new tags are pushed # - for pull requests # # Releases are tagged with vX.Y.Z. We determine if we are building for a release # or not by looking if the tag name starts with 'v'. # # To release: # - create new branch using name: release-vX.Y.Z # - update version in version.mk # - update CHANGELOG.md, second entry must equal version in version.mk # - first entry is assumed to be "Unreleased" # - push a tag like vX.Y.Z which is equal to version in version.mk # on: pull_request: push: branches: - main tags: - v* schedule: # Schedule to run daily - cron: '4 0 * * *' env: ZIG_DOWNLOAD_BASE_URL: https://github.com/actonlang/zigballs/raw/main # NOTE: Jobs for version tagged releases just pattern match on any tag starting # with 'v'. That's probably a version tag, but could be something else. Is there # a better way to match? jobs: build-version: runs-on: ubuntu-latest outputs: build_time: ${{ steps.setver.outputs.build_time }} steps: - name: "Set consistent build time" id: setver run: echo "build_time=$(date -u '+%Y%m%d.%-H.%-M')" >> "$GITHUB_OUTPUT" matrix_maker_macos: runs-on: ubuntu-latest outputs: matrix: ${{ steps.setmatrix.outputs.matrix }} steps: - name: "Set Matrix for PR or push" # Keep PR matrix minimal; extra entries increase cache pressure and slow PR workflows. if: github.event_name != 'schedule' id: setmatrix_pr run: | MATRIX_JSON='{\"include\":[{\"os\":\"macos\",\"version\":\"15\",\"arch\":\"aarch64\",\"cache\":true},{\"os\":\"macos\",\"version\":\"15\",\"arch\":\"x86_64\",\"cache\":true},{\"os\":\"macos\",\"version\":\"26\",\"arch\":\"aarch64\",\"cache\":true}]}' echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT - name: "Set Matrix for nightly run" if: github.event_name == 'schedule' id: setmatrix_cron run: | MATRIX_JSON='{\"include\":[{\"os\":\"macos\",\"version\":\"15\",\"arch\":\"aarch64\",\"cache\":true},{\"os\":\"macos\",\"version\":\"15\",\"arch\":\"x86_64\",\"cache\":true},{\"os\":\"macos\",\"version\":\"26\",\"arch\":\"aarch64\",\"cache\":true}]}' echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT - name: "Set final matrix output" id: setmatrix run: | if [ "${{ github.event_name }}" == "schedule" ]; then echo "matrix=${{ steps.setmatrix_cron.outputs.matrix }}" >> $GITHUB_OUTPUT else echo "matrix=${{ steps.setmatrix_pr.outputs.matrix }}" >> $GITHUB_OUTPUT fi - name: "Debug: Print matrix JSON" run: | echo "Matrix JSON:" echo '${{ toJson(fromJson(steps.setmatrix.outputs.matrix)) }}' echo "Event name: ${{ github.event_name }}" test-macos: needs: [build-version, matrix_maker_macos] strategy: fail-fast: false matrix: ${{ fromJson(needs.matrix_maker_macos.outputs.matrix) }} runs-on: ${{ (matrix.version == '15' && matrix.arch == 'x86_64') && 'macos-15-intel' || format('{0}-{1}', matrix.os, matrix.version) }} env: BUILD_TIME: ${{ needs.build-version.outputs.build_time }} steps: - name: "Show env" run: env - name: "Set BUILD_RELEASE when we are building for a version tag" run: | echo "BUILD_RELEASE=1" >> $GITHUB_ENV if: startsWith(github.ref, 'refs/tags/v') - name: "Enable dumping core files" run: | sudo sysctl kern.corefile=core.%P ulimit -c unlimited - name: "Check out repository code" uses: actions/checkout@v6 - name: "Cache stuff" if: matrix.cache == true uses: actions/cache@v5 with: path: | ~/.stack key: test-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.arch }}-${{ hashFiles('compiler/stack.yaml', 'compiler/stack.yaml.lock', 'Makefile', 'compiler/tools/*.sh') }} - name: "Cache Acton" if: matrix.cache == true uses: actions/cache@v5 with: path: | ~/.cache/acton/ key: test-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.arch }}-acton - name: "Install build prerequisites" run: brew install haskell-stack - name: "Build Acton" run: | make -j2 -C ${{ github.workspace }} BUILD_RELEASE=${{ env.BUILD_RELEASE }} BUILD_TIME=${BUILD_TIME} - name: "Build a release" run: make -C ${{ github.workspace }} release BUILD_TIME=${BUILD_TIME} - name: "Upload artifact" uses: actions/upload-artifact@v7 with: name: acton-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.arch }} path: ${{ github.workspace }}/acton-* if-no-files-found: error - name: "Run tests" env: # Package manager uses token to make authenticated requests to GitHub REST API, avoiding rate limits GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | ulimit -c unlimited make -C ${{ github.workspace }} test make -C ${{ github.workspace }} online-tests - name: "Upload whole test dir as artifact on test failure" if: failure() uses: actions/upload-artifact@v7 with: name: test-debug-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.arch }}-${{ github.run_id }}.zip path: | ${{ github.workspace }}/test matrix_maker_linux: runs-on: ubuntu-latest outputs: matrix: ${{ steps.setmatrix.outputs.matrix }} steps: - name: "Set Matrix for PR or push" # Keep PR matrix minimal; extra entries increase cache pressure and slow PR workflows. if: github.event_name != 'schedule' id: setmatrix_pr run: | MATRIX_JSON='{\"include\":[{\"os\":\"debian\",\"version\":\"11\",\"arch\":\"x86_64\",\"cache\":true},{\"os\":\"ubuntu\",\"version\":\"24.04\",\"arch\":\"arm64v8\",\"cache\":true}]}' echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT - name: "Set Matrix for nightly run" if: github.event_name == 'schedule' id: setmatrix_cron run: | MATRIX_JSON='{\"include\":[{\"os\":\"debian\",\"version\":\"11\",\"arch\":\"x86_64\",\"cache\":true},{\"os\":\"debian\",\"version\":\"12\",\"arch\":\"x86_64\",\"cache\":false},{\"os\":\"debian\",\"version\":\"13\",\"arch\":\"x86_64\",\"cache\":false},{\"os\":\"ubuntu\",\"version\":\"22.04\",\"arch\":\"x86_64\",\"cache\":false},{\"os\":\"ubuntu\",\"version\":\"24.04\",\"arch\":\"x86_64\",\"cache\":false},{\"os\":\"ubuntu\",\"version\":\"24.04\",\"arch\":\"arm64v8\",\"cache\":true}]}' echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT - name: "Set final matrix output" id: setmatrix run: | if [ "${{ github.event_name }}" == "schedule" ]; then echo "matrix=${{ steps.setmatrix_cron.outputs.matrix }}" >> $GITHUB_OUTPUT else echo "matrix=${{ steps.setmatrix_pr.outputs.matrix }}" >> $GITHUB_OUTPUT fi - name: "Debug: Print matrix JSON" run: | echo "Matrix JSON:" echo '${{ toJson(fromJson(steps.setmatrix.outputs.matrix)) }}' echo "Event name: ${{ github.event_name }}" test-linux: needs: [build-version, matrix_maker_linux] strategy: fail-fast: false matrix: ${{ fromJson(needs.matrix_maker_linux.outputs.matrix) }} runs-on: ubuntu-24.04${{ matrix.arch == 'arm64v8' && '-arm' || '' }} container: image: ${{ matrix.os }}:${{ matrix.version }} env: LANG: en_US.UTF-8 LC_ALL: en_US.UTF-8 BUILD_TIME: ${{ needs.build-version.outputs.build_time }} steps: - name: "Show platform and environment" run: | uname -a env cat /proc/cpuinfo - name: "Set BUILD_RELEASE when we are building for a version tag" if: startsWith(github.ref, 'refs/tags/v') run: | echo "BUILD_RELEASE=1" >> $GITHUB_ENV - name: "Check out repository code" uses: actions/checkout@v6 - name: "Cache stuff" if: matrix.cache == true uses: actions/cache@v5 with: path: | ~/.stack key: test-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.arch }}-${{ hashFiles('compiler/stack.yaml', 'compiler/stack.yaml.lock', 'Makefile', 'compiler/tools/*.sh') }} - name: "chown our home dir to avoid stack complaining" run: chown -R root:root /github/home - name: "Install build prerequisites" run: | export DEBIAN_FRONTEND=noninteractive apt-get update apt-get install -qy bzip2 curl g++ haskell-stack libgmp-dev libncurses-dev make procps zlib1g-dev apt-get install -qy gdb - name: "locale en_US.UTF-8" run: | apt-get install -qy locales locale-gen en_US.UTF-8 echo "locales locales/default_environment_locale select en_US.UTF-8" | debconf-set-selections echo "locales locales/locales_to_be_generated multiselect en_US.UTF-8 UTF-8" | debconf-set-selections rm "/etc/locale.gen" dpkg-reconfigure --frontend noninteractive locales - name: "Install newer stack" run: | STACK_VERSION=3.9.3 ARCH="$(uname -m)" case "${ARCH}" in x86_64) STACK_ARCH="x86_64" ;; aarch64|arm64) STACK_ARCH="aarch64" ;; *) echo "Unsupported arch: ${ARCH}" >&2; exit 1 ;; esac STACK_TAR="stack-${STACK_VERSION}-linux-${STACK_ARCH}.tar.gz" STACK_URL="https://github.com/commercialhaskell/stack/releases/download/v${STACK_VERSION}/${STACK_TAR}" mkdir -p "${HOME}/.local/bin" curl -fsSL "${STACK_URL}" -o /tmp/stack.tgz tar -xzf /tmp/stack.tgz -C /tmp install -m 0755 "/tmp/stack-${STACK_VERSION}-linux-${STACK_ARCH}/stack" "${HOME}/.local/bin/stack" echo "${HOME}/.local/bin" >> "$GITHUB_PATH" "${HOME}/.local/bin/stack" --version - name: "Use container glibc target for source build" run: | GLIBC_VERSION="$(getconf GNU_LIBC_VERSION | awk '{print $2}')" echo "ACTON_ZIG_GLIBC_VERSION=${GLIBC_VERSION}" >> "$GITHUB_ENV" echo "Using Zig glibc target ${GLIBC_VERSION}" - name: "Build Acton" run: | make -j2 -C ${GITHUB_WORKSPACE} BUILD_RELEASE=${{ env.BUILD_RELEASE }} BUILD_TIME=${BUILD_TIME} - name: "Build a release" run: make -C ${GITHUB_WORKSPACE} release BUILD_TIME=${BUILD_TIME} - name: "Upload artifact" uses: actions/upload-artifact@v7 with: name: acton-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.arch }} path: ${{ github.workspace }}/acton-* if-no-files-found: error - name: "Run tests" run: | ulimit -c unlimited make -C ${GITHUB_WORKSPACE} test make -C ${GITHUB_WORKSPACE} online-tests - name: "Upload whole test dir as artifact on test failure" if: failure() uses: actions/upload-artifact@v7 with: name: test-debug-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.arch }}-${{ github.run_id }}.zip path: | ${{ github.workspace }}/test build-debs: needs: build-version strategy: fail-fast: false matrix: arch: [amd64, arm64] runs-on: ${{ matrix.arch == 'amd64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }} container: image: debian:11 env: LANG: en_US.UTF-8 LC_ALL: en_US.UTF-8 BUILD_TIME: ${{ needs.build-version.outputs.build_time }} HOME: /tmp/acton-gh-home STACK_ROOT: /tmp/acton-gh-home/.stack steps: - name: "Show platform and environment" run: | env ldd --version | head -n1 cat /proc/cpuinfo uname -a - name: "Set BUILD_RELEASE when we are building for a version tag" run: | echo "BUILD_RELEASE=1" >> $GITHUB_ENV if: startsWith(github.ref, 'refs/tags/v') - name: "Install build prerequisites" run: | apt-get update apt-get install -qy bzip2 curl g++ haskell-stack libgmp-dev libncurses-dev make procps zlib1g-dev apt-get install -qy bash-completion build-essential debhelper devscripts - name: "Prepare stack directories" run: | mkdir -p "${HOME}/.local/bin" "${STACK_ROOT}" - name: "Check out repository code" uses: actions/checkout@v6 - name: "Cache stuff" uses: actions/cache@v5 with: path: | ${{ env.STACK_ROOT }} key: build-debs-${{ matrix.arch }}-${{ hashFiles('compiler/stack.yaml', 'compiler/stack.yaml.lock', 'Makefile', 'compiler/tools/*.sh', 'debian/control') }} - name: "locale en_US.UTF-8" run: | apt-get install -qy locales locale-gen en_US.UTF-8 echo "locales locales/default_environment_locale select en_US.UTF-8" | debconf-set-selections echo "locales locales/locales_to_be_generated multiselect en_US.UTF-8 UTF-8" | debconf-set-selections rm "/etc/locale.gen" dpkg-reconfigure --frontend noninteractive locales - name: "Install newer stack" run: | STACK_VERSION=3.9.3 ARCH="$(uname -m)" case "${ARCH}" in x86_64) STACK_ARCH="x86_64" ;; aarch64|arm64) STACK_ARCH="aarch64" ;; *) echo "Unsupported arch: ${ARCH}" >&2; exit 1 ;; esac STACK_TAR="stack-${STACK_VERSION}-linux-${STACK_ARCH}.tar.gz" STACK_URL="https://github.com/commercialhaskell/stack/releases/download/v${STACK_VERSION}/${STACK_TAR}" curl -fsSL "${STACK_URL}" -o /tmp/stack.tgz tar -xzf /tmp/stack.tgz -C /tmp install -m 0755 "/tmp/stack-${STACK_VERSION}-linux-${STACK_ARCH}/stack" "${HOME}/.local/bin/stack" echo "${HOME}/.local/bin" >> "$GITHUB_PATH" "${HOME}/.local/bin/stack" --version - name: "Build Debian packages" shell: bash run: | set -euo pipefail make -C "${GITHUB_WORKSPACE}" debs BUILD_RELEASE=${{ env.BUILD_RELEASE }} BUILD_TIME=${BUILD_TIME} - name: "Show packaged Acton linkage" shell: bash run: | set -euo pipefail make -C "${GITHUB_WORKSPACE}" ldd deb="$(ls "${GITHUB_WORKSPACE}"/../acton_*.deb | head -n1)" dpkg-deb -I "$deb" tmp="$(mktemp -d)" dpkg-deb -x "$deb" "$tmp" bins="$tmp/usr/lib/acton/bin/acton" bins="$bins $tmp/usr/lib/acton/bin/lsp-server-acton" bins="$bins $tmp/usr/lib/acton/bin/actondb" make -C "${GITHUB_WORKSPACE}" ldd ACTON_LINKAGE_BINS="$bins" - name: "Compute variables" id: vars run: | echo "debdir=$(realpath ${GITHUB_WORKSPACE}/../deb)" >> $GITHUB_OUTPUT echo "artifact_dir=$(dirname ${{ github.workspace }})" >> $GITHUB_OUTPUT - name: "Move deb files into place for easy artifact extraction" run: | mkdir -p ${{ steps.vars.outputs.debdir }} ls ${{ steps.vars.outputs.debdir }}/../ mv ${{ steps.vars.outputs.debdir }}/../acton_* ${{ steps.vars.outputs.debdir }}/ - name: "Upload artifact" uses: actions/upload-artifact@v7 with: name: acton-debs-${{ matrix.arch }} # Using a wildcard and then deb here to force the entire directory to # be part of resulting artifact. path: ${{ steps.vars.outputs.artifact_dir }}/*deb/ if-no-files-found: error run-macos: needs: test-macos strategy: fail-fast: false matrix: os: [macos-15, macos-15-intel, macos-26] runs-on: ${{ matrix.os }} steps: - name: "Machine info" run: | uname -a system_profiler SPHardwareDataType - name: "Download artifacts for Macos arm64, built on macos-15" if: ${{ matrix.os == 'macos-15' || matrix.os == 'macos-26' }} uses: actions/download-artifact@v8 with: name: acton-macos-15-aarch64 - name: "Download artifacts for Macos x86_64, built on macos-15" if: ${{ matrix.os == 'macos-15-intel' }} uses: actions/download-artifact@v8 with: name: acton-macos-15-x86_64 - name: "Extract acton" run: | tar Jxf $(ls acton-macos-*.tar.xz | tail -n1) - name: "Compile acton program" run: | export PATH=$(pwd)/acton/bin:$PATH acton version echo '#!/usr/bin/env runacton' > acton-test.act echo 'actor main(env):' >> acton-test.act echo ' print("Hello, world")' >> acton-test.act echo ' env.exit(0)' >> acton-test.act chmod a+x acton-test.act ./acton-test.act ./acton-test.act | grep "Hello, world" acton build acton-test.act ./acton-test ./acton-test | grep "Hello, world" run-linux: needs: build-debs strategy: fail-fast: false matrix: include: - os: "debian" version: "11" arch: "amd64" - os: "debian" version: "12" arch: "amd64" - os: "ubuntu" version: "20.04" arch: "amd64" - os: "ubuntu" version: "22.04" arch: "amd64" - os: "ubuntu" version: "24.04" arch: "amd64" - os: "ubuntu" version: "24.04" arch: "arm64" - os: "ubuntu" version: "24.04" arch: "amd64" target: "x86_64-linux-musl" - os: "ubuntu" version: "24.04" arch: "arm64" target: "aarch64-linux-musl" env: # This makes it possible for the GitHub Action itself to run using an # older version of node, which is the only possibility to get it running # on Ubuntu 18.04 (in the matrix above) ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION: node16 ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true runs-on: ${{ matrix.arch == 'amd64' && 'ubuntu-latest' || 'ubuntu-24.04-arm' }} container: image: ${{ matrix.os }}:${{ matrix.version }} options: --privileged --ulimit core=-1 --security-opt seccomp=unconfined steps: - name: "Show platform and environment" run: | env cat /proc/cpuinfo - name: "Download .deb files" uses: actions/download-artifact@v8 with: name: acton-debs-${{ matrix.arch }} - name: "Install acton from .deb" run: | apt update apt install -y ./deb/acton_*.deb acton version - name: "Enable dumping core files to /tmp/core..." run: | apt install -qy procps cat /proc/sys/kernel/core_pattern sysctl kernel.core_pattern='/tmp/core.%h.%e.%t' || true cat /proc/sys/kernel/core_pattern ulimit -c unlimited - name: "Compile acton program" run: | echo '#!/usr/bin/env runacton' > acton-test.act echo 'actor main(env):' >> acton-test.act echo ' print("Hello, world")' >> acton-test.act echo ' env.exit(0)' >> acton-test.act chmod a+x acton-test.act ./acton-test.act ./acton-test.act | grep "Hello, world" acton build ${{ matrix.target && format('--target {0}', matrix.target) || '' }} acton-test.act ./acton-test ./acton-test | grep "Hello, world" - name: "ls core" if: failure() run: | pwd ls find /tmp mv /tmp/core* . - name: "Upload core file & binaries as artifacts on test failure" if: failure() uses: actions/upload-artifact@v7 with: name: coredumps-${{ matrix.os }}-${{ matrix.version }}-${{ github.run_id }}.zip path: | ${{ github.workspace }}/core* perf-vs-main: needs: build-debs # Use our own runner to get more deterministic results runs-on: [self-hosted, linux, X64] steps: - name: "Check out repository code" uses: actions/checkout@v6 - name: "Remove any currently install Acton to ensure clean slate" run: | sudo apt-get purge -qy acton - name: "Install Acton from APT tip repo" run: | wget -q -O - https://apt.acton-lang.io/acton.gpg | sudo apt-key add - echo "deb http://aptip.acton-lang.io/ tip main" | sudo tee /etc/apt/sources.list.d/acton.list sudo apt-get update sudo apt-get install -qy acton acton version - name: "Run perf tests and record" run: | acton version cd test/stdlib_tests acton test perf --record cd ../perf acton test perf --record - name: "Download .deb files" uses: actions/download-artifact@v8 with: name: acton-debs-amd64 - name: "Install acton from .deb" run: | sudo dpkg -i ./deb/acton_*.deb acton version - name: "Run perf tests to compare" run: | cd test/stdlib_tests rm -rf out acton test perf cd ../perf rm -rf out acton test perf test-app-sorespo: strategy: fail-fast: false matrix: arch: [amd64, arm64] needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/sorespo" arch: ${{ matrix.arch }} test-app-orchestron: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/orchestron" test-app-netcli: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/netcli" test-app-netclics: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/netclics" test-app-snappy: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "actonlang/acton-snappy" test-app-yang: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/acton-yang" test-app-actmf: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/actmf" test-app-ncurl: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/ncurl" test-app-gnmi: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/acton-gnmi" test-app-actxcrypt: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/actxcrypt" test-app-orchino: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/orchino" test-app-lmdb: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "orchestron-orchestrator/acton-lmdb" test-app-zlib: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "actonlang/acton-zlib" test-app-http2: needs: build-debs uses: "./.github/workflows/test-app.yml" with: repo_url: "actonlang/acton-http2" build-container-image: needs: [test-macos, test-linux, build-debs] runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: "Check out repository code" uses: actions/checkout@v6 - name: "Download deb artifacts" uses: actions/download-artifact@v8 with: pattern: acton-debs-* merge-multiple: true - name: "Prepare debs for container build" run: | set -euo pipefail deb_amd64=$(ls deb/acton_*amd64.deb | head -n1) deb_arm64=$(ls deb/acton_*arm64.deb | head -n1) echo "Using debs: $deb_amd64 and $deb_arm64" version=$(basename "$deb_amd64") version=${version#acton_} version=${version%_amd64.deb} echo "AMD64_DEB=$deb_amd64" >> "$GITHUB_ENV" echo "ARM64_DEB=$deb_arm64" >> "$GITHUB_ENV" echo "VERSION_FROM_DEB=$version" >> "$GITHUB_ENV" - name: "Determine container tag & push intent" id: container_meta env: GHCR_OWNER: ${{ github.repository_owner }} run: | ref="${GITHUB_REF}" owner="${GHCR_OWNER:-actonlang}" version="${VERSION_FROM_DEB:-unknown}" push=false alias_tag="" if [[ "$ref" == refs/tags/v* ]]; then push=true elif [[ "$ref" == refs/heads/main ]]; then push=true alias_tag="tip" fi echo "version_tag=$version" >> "$GITHUB_OUTPUT" echo "push=$push" >> "$GITHUB_OUTPUT" echo "owner=$owner" >> "$GITHUB_OUTPUT" echo "alias_tag=$alias_tag" >> "$GITHUB_OUTPUT" - name: "Set up QEMU" uses: docker/setup-qemu-action@v4 - name: "Set up Docker Buildx" uses: docker/setup-buildx-action@v4 - name: "Log in to GHCR" if: steps.container_meta.outputs.push == 'true' uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: "Build container image" run: | set -euo pipefail version="${{ steps.container_meta.outputs.version_tag }}" owner="${{ steps.container_meta.outputs.owner }}" alias_tag="${{ steps.container_meta.outputs.alias_tag }}" image_base="ghcr.io/${owner}/acton" image_version="${image_base}:${version}" image_latest="${image_base}:latest" push="${{ steps.container_meta.outputs.push }}" if [[ "$push" == "true" ]]; then platforms="linux/amd64,linux/arm64" else platforms="linux/amd64" fi build_flags=(--file Containerfile.deb --label "org.opencontainers.image.version=${version}" --provenance=false --sbom=false --platform "$platforms") if [[ "$push" == "true" ]]; then docker buildx build "${build_flags[@]}" --tag "$image_version" --push . if [[ -n "$alias_tag" ]]; then docker buildx imagetools create --tag "${image_base}:${alias_tag}" "$image_version" fi if [[ "${{ github.ref }}" == refs/tags/v* ]]; then docker buildx imagetools create --tag "$image_latest" "$image_version" fi else docker buildx build "${build_flags[@]}" --tag "$image_version" --load . fi # If we are on the main branch, we'll create or update a pre-release called # 'tip' which holds the latest build output from the main branch! We upload # artifacts twice, first with the version number held in the filename and a # second time after being renamed to remove the version number in the # filename, thus providing a stable URL for downloading the tip tar balls. pre-release-tip: # Only run on the main branch if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest needs: [test-macos, test-linux, build-debs, build-container-image] steps: - name: "Delete current tip release & tag" uses: dev-drprasad/delete-tag-and-release@v1.1 with: delete_release: true tag_name: tip env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: "Check out repository code" uses: actions/checkout@v6 - name: "Download artifacts for Macos aarch64, built on macos-15" uses: actions/download-artifact@v8 with: name: acton-macos-15-aarch64 - name: "Download artifacts for Macos x86_64, built on macos-15" uses: actions/download-artifact@v8 with: name: acton-macos-15-x86_64 - name: "Download artifacts for Linux x86_64, built on Debian:11" uses: actions/download-artifact@v8 with: name: acton-debian-11-x86_64 - name: "Download artifacts for Linux arm64, built on Ubuntu:24.04" uses: actions/download-artifact@v8 with: name: acton-ubuntu-24.04-arm64v8 - name: "Download artifacts for Debian Linux on amd64 (x86_64) & arm64 (aarch64)" uses: actions/download-artifact@v8 with: pattern: acton-debs-* merge-multiple: true - name: "List downloaded artifacts" run: | ls ls deb - name: "Workaround for changelog extractor that looks for number versions in headlines, which won't work for 'Unreleased'" run: sed -i -e 's/^## Unreleased/## [999.9] Unreleased\nThis is an unreleased snapshot built from the main branch. Like a nightly but more up to date./' CHANGELOG.md - name: "Extract release notes" id: extract-release-notes uses: ffurrer2/extract-release-notes@v3 - name: "(re-)create 'tip' release notes and upload artifacts as assets" uses: ncipollo/release-action@v1 with: allowUpdates: true artifacts: "acton*.tar*,deb/*deb" body: ${{ steps.extract-release-notes.outputs.release_notes }} draft: false prerelease: true name: "tip" tag: "tip" token: ${{ secrets.GITHUB_TOKEN }} replacesArtifacts: true - name: "Remove version number from macos aarch64 tar ball" run: mv $(ls acton-macos-aarch64*.tar.xz | tail -n1) acton-macos-aarch64-tip.tar.xz - name: "Remove version number from macos x86_64 tar ball" run: mv $(ls acton-macos-x86_64*.tar.xz | tail -n1) acton-macos-x86_64-tip.tar.xz - name: "Remove version number from linux x86_64 tar ball" run: mv $(ls acton-linux-x86_64*.tar.xz | tail -n1) acton-linux-x86_64-tip.tar.xz - name: "Remove version number from linux aarch64 tar ball" run: mv $(ls acton-linux-aarch64*.tar.xz | tail -n1) acton-linux-aarch64-tip.tar.xz - name: "Remove version number from debian amd64 package" run: mv $(ls deb/acton_*amd64.deb | tail -n1) deb/acton_tip_amd64.deb - name: "Remove version number from debian arm64 package" run: mv $(ls deb/acton_*arm64.deb | tail -n1) deb/acton_tip_arm64.deb - name: "List files for debug" run: | ls ls deb - name: "Upload artifacts without version number for stable links" uses: ncipollo/release-action@v1 with: allowUpdates: true artifacts: "acton*.tar*,deb/acton_*.deb" body: ${{ steps.extract-release-notes.outputs.release_notes }} draft: false prerelease: true name: "tip" tag: "tip" token: ${{ secrets.GITHUB_TOKEN }} replacesArtifacts: true # Release job, only run for version tagged releases. release: if: startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest needs: [test-macos, test-linux, build-debs, build-container-image] steps: - name: "Check out repository code" uses: actions/checkout@v6 - name: "Download artifacts for Macos aarch64, built on macos-15" uses: actions/download-artifact@v8 with: name: acton-macos-15-aarch64 - name: "Download artifacts for Macos x86_64, built on macos-15" uses: actions/download-artifact@v8 with: name: acton-macos-15-x86_64 - name: "Download artifacts for Linux x86_64, built on Debian:11" uses: actions/download-artifact@v8 with: name: acton-debian-11-x86_64 - name: "Download artifacts for Linux arm64, built on Ubuntu:24.04" uses: actions/download-artifact@v8 with: name: acton-ubuntu-24.04-arm64v8 - name: "Download artifacts for Debian Linux" uses: actions/download-artifact@v8 with: pattern: acton-debs-* merge-multiple: true - name: "List downloaded artifacts" run: ls - name: "Extract release notes" id: extract-release-notes uses: ffurrer2/extract-release-notes@v3 - name: "Create release" uses: ncipollo/release-action@v1 with: allowUpdates: true artifacts: "acton*.tar*,deb/*deb" body: ${{ steps.extract-release-notes.outputs.release_notes }} draft: false token: ${{ secrets.GITHUB_TOKEN }} replacesArtifacts: true # Update apt repo update-apt-repo: if: startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest container: image: debian:experimental needs: [test-macos, test-linux, build-debs] steps: - name: Install build prerequisites run: | apt-get update apt-get install -qy -t experimental reprepro apt-get install -qy git gnupg - name: Import GPG key id: import_gpg uses: crazy-max/ghaction-import-gpg@v7 with: gpg_private_key: ${{ secrets.APT_GPG_PRIVATE_KEY }} - name: Check out code of apt.acton-lang.io repo uses: actions/checkout@v6 with: repository: actonlang/apt.acton-lang.io path: apt ssh-key: ${{ secrets.APT_DEPLOY_KEY }} - name: "Download artifacts for Debian Linux" uses: actions/download-artifact@v8 with: path: . pattern: acton-debs-* merge-multiple: true - name: "Get the version" id: get_version run: | echo "version=$(ls ../deb/*amd64.changes | sed -e 's/.*acton_//' -e 's/_amd64.*//')" >> $GITHUB_OUTPUT - name: "Include new deb in Apt repository" run: | cd apt for changes_file in ../deb/*.changes; do reprepro include stable "$changes_file" done - name: "Push updates to git repository for apt.acton-lang.io" run: | cd apt git config user.name "Apt Bot" git config user.email apt@acton-lang.org git add . git status git diff git commit -a -m "Add Acton v${{steps.get_version.outputs.version}}" git push # Update apt tip repo update-apt-tip-repo: # Only run on the main branch if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest container: image: debian:experimental permissions: contents: write needs: [test-macos, test-linux, build-debs] steps: - name: Install build prerequisites run: | apt-get update apt-get install -qy -t experimental reprepro apt-get install -qy git gnupg - name: Check out code of aptip.acton-lang.io repo uses: actions/checkout@v6 with: repository: actonlang/aptip.acton-lang.io path: apt ssh-key: ${{ secrets.APT_TIP_DEPLOY_KEY }} - name: "Download artifacts for Debian Linux" uses: actions/download-artifact@v8 with: path: . pattern: acton-debs-* merge-multiple: true - name: "Get the version" id: get_version run: | echo "VERSION=$(ls deb/*amd64.changes | sed -e 's/.*acton_//' -e 's/_amd64.*//')" >> $GITHUB_ENV echo "version=$(ls deb/*amd64.changes | sed -e 's/.*acton_//' -e 's/_amd64.*//')" >> $GITHUB_OUTPUT - name: "Move .deb files in place" run: | cd apt mv -v ../deb/* deb/ - name: "Configure git" run: | cd apt git config user.name "Apt Bot" git config user.email apt@acton-lang.org - name: "Push updates to git repository for aptip.acton-lang.io" run: | cd apt git add deb/* git status git commit -a -m "Add Acton tip v${VERSION}" git push # Update our homebrew tap update-homebrew: if: startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest # Depend on all test jobs so we don't update brew repo in case anything fails needs: [test-macos, test-linux, build-debs] steps: - name: "Check out code of main acton repo" uses: actions/checkout@v6 - name: "Get the version from version.mk" id: get_version run: | cat version.mk # Set both as environment variable for current job and as output for other steps VERSION=$(grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' version.mk) echo "Found version: $VERSION" echo "VERSION=$VERSION" >> $GITHUB_ENV echo "version=$VERSION" >> $GITHUB_OUTPUT - name: "Download release tarball" run: wget https://github.com/actonlang/acton/archive/refs/tags/v${VERSION}.tar.gz - name: "Calculate SHA256 checksum" run: sha256sum v${VERSION}.tar.gz - id: shasum run: | CHECKSUM=$(sha256sum v${VERSION}.tar.gz | cut -d' ' -f1) echo "sum=$CHECKSUM" >> $GITHUB_OUTPUT echo "Checksum: $CHECKSUM" - name: "Check out code of our brew repo" uses: actions/checkout@v6 with: repository: actonlang/homebrew-acton path: homebrew-acton - name: "Update formula in homebrew-acton from acton repo" run: | cp homebrew/Formula/acton.rb homebrew-acton/Formula/acton.rb - name: "Update brew formula for acton with new version" run: | sed -i -e 's,^ url.*, url "https://github.com/actonlang/acton/archive/refs/tags/v'${VERSION}'.tar.gz",' -e 's/^ sha256.*/ sha256 "'${{ steps.shasum.outputs.sum }}'"/' homebrew-acton/Formula/acton.rb echo "Updated formula to version ${VERSION} with checksum ${{ steps.shasum.outputs.sum }}" cat homebrew-acton/Formula/acton.rb | grep -A 1 "^ *url" - name: "Create Pull Request" uses: peter-evans/create-pull-request@v8 with: path: homebrew-acton token: ${{ secrets.ACTBOT_PAT }} branch: acton-v${{ env.VERSION }} title: "acton v${{ env.VERSION }}" body: | Automatic update triggered by release on actonlang/acton. committer: Acton Bot commit-message: "acton v${{ env.VERSION }}" signoff: false ================================================ FILE: .github/workflows/trigger-web-update.yml ================================================ name: Trigger rebuild of Acton Web page # When there are changes to files under docs/acton-guide on main branch, # trigger the workflow to rebuild the Acton web page on: push: branches: - main paths: - 'docs/acton-guide/**' jobs: trigger_web_rebuild: runs-on: ubuntu-latest steps: - name: "Trigger build of www.acton-lang.org" uses: benc-uk/workflow-dispatch@v1 with: repo: actonlang/www.acton-lang.org token: ${{ secrets.ACTBOT_PAT }} workflow: main.yml ref: main - name: "Trigger build of acton.guide" uses: benc-uk/workflow-dispatch@v1 with: repo: actonlang/acton.guide token: ${{ secrets.ACTBOT_PAT }} workflow: main.yml ref: main ================================================ FILE: .github/workflows/update-ask-acton-vector-store.yml ================================================ name: Update Ask Acton vector store on: push: branches: - main paths: - 'docs/acton-guide/**' workflow_dispatch: concurrency: group: ask-acton-vector-store cancel-in-progress: true jobs: update_vector_store: runs-on: ubuntu-latest permissions: contents: read steps: - name: Check out Acton uses: actions/checkout@v6 - name: Check out Ask Acton indexer uses: actions/checkout@v6 with: repository: actonlang/ask-acton path: ask-acton token: ${{ secrets.ACTBOT_PAT }} - name: Set up Node.js uses: actions/setup-node@v6 with: node-version: '22' cache: npm cache-dependency-path: ask-acton/package-lock.json - name: Install Ask Acton dependencies working-directory: ask-acton run: npm ci - name: Update vector store working-directory: ask-acton env: OPENAI_API_KEY: ${{ secrets.ASK_ACTON_OPENAI_API_KEY || secrets.OPENAI_API_KEY }} OPENAI_VECTOR_STORE_ID: ${{ secrets.ASK_ACTON_VECTOR_STORE_ID || secrets.OPENAI_VECTOR_STORE_ID }} DOCS_DIR: ${{ github.workspace }}/docs/acton-guide/src DOCS_REVISION: ${{ github.sha }} INDEX_REPLACE_SOURCE: 'true' run: npm run index:docs ================================================ FILE: .github/workflows/webex-notifications.yml ================================================ name: Webex Notifications on: pull_request: types: [closed] branches: [main] jobs: notify-webex: runs-on: ubuntu-latest if: github.event.pull_request.merged == true steps: - name: Prepare notification message id: message env: PR_NUMBER: ${{ github.event.pull_request.number }} PR_URL: ${{ github.event.pull_request.html_url }} PR_TITLE: ${{ github.event.pull_request.title }} PR_BODY: ${{ github.event.pull_request.body }} run: | MESSAGE="### PR [#${PR_NUMBER}](${PR_URL}) merged: ${PR_TITLE}" if [ -n "$PR_BODY" ]; then #MESSAGE="${MESSAGE}"$'\n'$'\n''```' # TODO: does this contain an extra newline? MESSAGE="${MESSAGE}"$'\n'"${PR_BODY}" #MESSAGE="${MESSAGE}"$'\n''```' fi echo "message<> $GITHUB_OUTPUT echo "$MESSAGE" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT - name: Send Webex notification env: WEBEX_TOKEN: ${{ secrets.WEBEX_TOKEN }} WEBEX_ROOM_ID: ${{ secrets.WEBEX_ROOM_ID }} run: | set -euo pipefail # Write the prepared message to a file verbatim to avoid shell quoting issues cat > message.txt <<'__WEBEX_MSG__' ${{ steps.message.outputs.message }} __WEBEX_MSG__ # Build JSON payload safely; jq will handle JSON escaping JSON_PAYLOAD=$(jq -n \ --arg roomId "$WEBEX_ROOM_ID" \ --rawfile markdown message.txt \ '{roomId: $roomId, markdown: $markdown}') # Send message to Webex room using direct API call RESPONSE=$(curl -sS -X POST "https://webexapis.com/v1/messages" \ -H "Authorization: Bearer $WEBEX_TOKEN" \ -H "Content-Type: application/json" \ -d "$JSON_PAYLOAD" \ -w "\n%{http_code}") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) if [ "$HTTP_CODE" -ne 200 ]; then echo "::error::Failed to send Webex notification. HTTP code: $HTTP_CODE" echo "Response: $BODY" exit 1 else echo "✅ Webex notification sent successfully!" fi ================================================ FILE: .gitignore ================================================ **/.ccls-cache/* **/.zig-cache/* *~ *.o *.a **/.DS_Store **/.stack-work **/*.dSYM **/*.hi **/*.o **/a.out **/build.zig* **/core **/build-cache **/zig-cache **/.acton.compile.lock **/.acton.lock **/.build/ **/*.swp **/*.ty backend/actondb backend/failure_detector/db_messages_test backend/test/actor_ring_tests_local backend/test/actor_ring_tests_remote backend/test/db_unit_tests backend/test/queue_unit_tests backend/test/skiplist_test backend/test/test_client base/build-cache base/out builder/builder builder/build_runner.zig builder/zig-cache compiler/package.yaml compiler/acton/acton.cabal compiler/acton/package.yaml compiler/lib/package.yaml compiler/lsp-server/package.yaml compiler/lsp-server/lsp-server-acton.cabal test/package.yaml debian/.debhelper debian/acton/ debian/acton.substvars debian/debhelper-build-stamp debian/changelog debian/files deps/* deps-download dist/* builder/deps/* examples/* !examples/*.* !examples/*/ examples/** !examples/**/*.* !examples/**/*/ test/* !test/*.* test/*.log !test/*/ test/** !test/Makefile !test/**/*.* test/**/*.log !test/**/*/ !test/**/snapshots/ !test/**/snapshots/**/ !test/**/snapshots/**/* test/**/snapshots/output/** snapshots/output/** # tests organized as acton projects; ignore all but source test/*/*/out/** compiler/acton/test/project/*/out ================================================ FILE: .gitmodules ================================================ [submodule "test/Unity"] path = test/Unity url = https://github.com/ThrowTheSwitch/Unity.git ================================================ FILE: AGENTS.md ================================================ Acton compiler notes: - `acton build --no-threads` controls whether the produced Acton binary uses threads in Acton RTS. It does not disable threads in the Acton compiler process itself, so compilation still happens concurrently. This flag is only to be used for compatibility with platforms that do no have thread support, for example cross-compiling for Windows, we build without threads. ================================================ FILE: CHANGELOG.md ================================================ # Changelog ## Unreleased ### Compiler & Build - Add concurrent top-level type checking for total statements, allowing the compiler to check independent top-level definitions in parallel while keeping source-order semantics for non-total statements. [#2773, #2782] - Verbose and timing builds now report inferred signatures for non-total statements, making it easier to add explicit signatures and unlock more concurrent checking. - Type errors from independent total statements are collected into multiple diagnostics instead of stopping at the first failing statement. - Use a fixed worker pool with bounded lookahead, improving memory behavior and performance for modules with many independent top-level definitions. - Parse modules in parallel by splitting top-level statement chunks across parser workers, reducing parser latency for large source files while preserving source-order results. [#2787] - `--parse-serial` keeps the whole-file parser available for debugging and fallback comparisons. - Module-suite validation now uses a set-based duplicate check, avoiding quadratic validation time in large projects. - Report parser progress percentages during builds, giving useful feedback for very large files before type checking starts. [#2784] - Preserve each module's import context in cached module interfaces, so builds, `acton sig`, documentation, and completion can reuse cached interfaces without losing imported class and protocol information. [#2779] - Speed up compiler environment lookups and scans in large modules by indexing active names, separating closed imports and finalized top-level names from live local bindings, and deduplicating reserved names with a hash index while preserving source-order semantics. [#2789, #2796, #2797] ### Packages & Distribution - Change x86_64 Linux builds from statically linked GNU libc to dynamically linked GNU libc while keeping other libraries statically linked. [#2774, #2781] - The x86_64 Linux release job and Debian package builds run on Debian 11 to provide a glibc 2.31 floor. - Nightly CI still covers Debian 11, 12, and 13 on x86_64. - CI now validates the dynamic library set and maximum required GLIBC version for `acton`, `lsp-server-acton`, and `actondb`. - Vendor the `diagnose` compiler diagnostic library from upstream after `diagnose` removed its stale `text <=2.0` dependency, so compiler builds can use the resolver's `text` package instead of pinning `text-2.0` just for diagnostics. [#2783] ### Documentation - Document when and how to use the Acton container image, including copy-pastable Docker commands for checking the compiler version and building the current project. [#2767] ### Testing & CI - Add a dedicated type-checking benchmark driver that reports parse, environment, kind-checking, and type-checking timings, with optional RTS allocation and GC statistics for compiler performance work. [#2794] - Add a generated class-heavy type-checking fixture to exercise concurrent type-checking scheduler performance on large recursive class structures. [#2777] ## [0.27.0] - 2026-05-08 ### Added - Add precise content-hash based build output reuse throughout the compiler pipeline for optimal compilation [#2447, #2497, #2581, #2674] - Acton now decides whether previous typechecking results, generated build outputs, and downstream work are still valid from source and dependency content instead of relying on file modification times - Cached module interfaces record source hashes, module-level public and implementation hashes, and per-name source / public / implementation hashes - Per-name dependency hashes let the compiler track exactly which names a declaration depends on, so unrelated edits do not force whole modules or downstream dependents to be rebuilt - Public type-signature changes rerun front passes for affected downstream modules; implementation-only changes can refresh implementation hashes and rerun back passes / code generation without forcing unrelated typechecking - When hashes match, cached build output is reused directly instead of reparsing, re-typechecking, or regenerating work that is already fresh - Add concurrent module compilation across the build graph. [#2524, #2527] - The compiler schedules modules as soon as their dependencies are ready, allowing independent parts of a project to typecheck in parallel - Front passes and back passes are separated, so dependent modules can start once an interface is available while normalization, C generation, and other back-end work continue in parallel - Ready modules are prioritized by critical path so large dependency branches do not leave available workers idle - This keeps project builds, watch mode, and LSP feedback responsive while still producing the same deterministic build outputs - Add VS Code editor support through the Acton language server. [#2487, #2753] - The VS Code extension can now show Acton syntax and type errors inline, using the same parser and typechecker as `acton build` - Completion suggests attribute names, function and method argument names, and other relevant source-level names - Hover shows Acton information for names under the cursor - Editor state is kept in memory for fast lookups, so completion and diagnostics stay responsive while typechecking continues - Add `acton doc` command for generating documentation [#2274, #2284, #2292, #2293, #2295] - Supports multiple output formats (text, markdown, HTML) - Default is to open browser into HTML docs when window environment is available, in terminal we fall back to colored text output. Use `acton doc -t` to force text / terminal output. - Plain `acton doc` will show module index in browser - for terminal output, a source file must be given, like `acton doc src/foo.act -t` - Text output is colored for output to TTY (terminal), piping output falls back to plain ASCII output. Also honors `NO_COLOR` env var - HTML supports: - colorized output of types etc - inter-module links to type definitions - explanatory tooltips for generic types - Add optional chaining and forced unwrapping for optional values [#2672, #2726] - `person?.residence?.name` returns `None` when any step is `None` - `person!.residence!.name` raises `ValueError` when a required step is unexpectedly `None` - Both forms support attribute access and method calls via `?.` / `!.`, plus indexing and slicing via `?[...]` / `![...]` - Add `acton sig` to inspect inferred type signatures using the same project-aware module and dependency resolution as `acton build`. [#2746] - Useful when an error says `foo.bar` does not have attribute `X`, since `acton sig foo.bar` resolves names like the compiler does: first as `bar` in module `foo`, then as module `foo.bar` - Add docstring support throughout compiler and AST [#2282] - Parse docstrings in AST declarations [#2269, #2270, #2271, #2565, #2736] - Unescape docstrings in NameInfo - Allow module docstrings before imports - Add short options support for argparse module [#2289] - Add global command-line options support to actonc [#2291] - Add new Hashable protocol and hash() builtin function [#2255] - Replace __hash__ method with new composable hashing approach - Types implement `.hash(self, hasher)` method to update a stateful hasher object - The hasher accumulates state from multiple fields: `self.x.hash(h); self.y.hash(h)` - Use the `hash()` function to get hash values: `h = hash(my_object)` - All built-in types implement Hashable protocol - Uses fast wyhash algorithm via Zig implementation - Parser / Syntax errors are now prettier [#2306, #2307, #2309] - Replace basic error rendering with elegant unicode style using Diagnose library - Better structured error reporting using Megaparsec's ADT typed error system - Improve error messages for type variable name violations - Clear hints explaining that single uppercase letters are reserved for type variables - Show cases possibilities of new parser error diagnostics - Plain ASCII example (in terminal is even prettier): ``` [error Parse error]: Invalid name (reserved for type variables) +--> test/syntaxerrors/err41.act@1:7-1:8 | 1 | class Z(value): : ^ : `- invalid name 'Z' : | Hint: Single upper case character (optionally followed by digits) are reserved for type variables. Use a longer name. -----+ ``` - Improve string interpolation parsing [#2321] - String parsing has been rewritten from scratch - String interpolation now works by default in all string literals (no f-prefix required) - Both `"hello {name}"` and `f"hello {name}"` support interpolation - The change to interpolate normal strings is backwards **incompatible**, any strings containing curly braces now need to be escaped or be converted to raw strings, i.e. "{" -> "{{" or r"{" - Backwards compatibility for classic `%` operator style is currently maintained, i.e. NO interpolation is performed for `s = "hello %s, here is {}" % name`, so curly braces are treated literaly - NOTE: %-operator style formatting will be deprecated in the future - Parser support nested interpolation strings (thought the necessary rewrites - Properly handle escape sequences in interpolated strings - Support complex expressions in interpolations including slices (`{arr[1:3]}`) - Better error messages for malformed format specifications and many other cases ``` ERROR: [error Syntax error]: Empty format specifier after ':' ╭──▶ test@1:27-1:27 │ 1 │ f"Unbalanced format {name:}:10}" • • ╰╸ Empty format specifier after ':' ─────╯ ``` - Let `repr()` and `type()` accept optional values [#2373] - `repr(None)` returns `"None"` and `type(None)` returns `"None"` - More convenient than needing wrapper functions for optional values - Add webex PR merge notification [#2372] - Recognize projects by `Build.act` & `build.act.json` [#2358] - Accept `Build.act` (new ideal), `build.act.json` (common), or `Acton.toml` (existing) - Check for `src/` directory presence for robustness - Allow any expression after `after` [#2342] - Previously limited to local functions, now supports method calls, actor methods, etc. - `after 1.5: obj.method()` and `after 0.1: remote_actor.action()` are now valid - Add `utils/update-changelog.sh` script to update this file (`CHANGELOG.md`) using Claude - it's a good prompt! - Allow logging of optional values [#2382] - Change logging data parameter type from `dict[str, value]` to `dict[str, ?value]` - Enables structured logging with None values like `{"user": None, "count": 42}` - Add `acton build FILE` for file-oriented builds through the main CLI. [#2471, #2592] - Add `acton build --watch` for fast edit/build feedback loops. [#2571] - Watch mode performs an initial project build and then keeps running, rebuilding automatically when source files change - Ordinary `.act` file edits use the incremental compiler scheduler, so unchanged modules, dependencies, and back-end work can be reused instead of rebuilding the whole project - Adding or removing source files, or changing `Build.act`, triggers project rediscovery so the build graph stays aligned with the project layout and dependency configuration - New edits supersede older in-flight work, which keeps the compiler responsive while a user is actively typing - Single-file watch is also supported with `acton build FILE --watch` or `acton FILE --watch` - `acton test --watch` uses the same machinery and reruns affected test modules after successful rebuilds - Add `acton spec` commands for inspecting and updating `Build.act` as JSON. [#2534] - Expand `acton pkg` package management [#2534, #2554, #2586, #2596] - `acton pkg update` downloads the package index - `acton pkg search` searches the local package index - `acton pkg add` can add packages by package name, archive URL, or GitHub repository URL - `acton pkg upgrade` updates dependencies with stored repository metadata - `acton zig-pkg add/remove` manages Zig package dependencies in `Build.act` - Add project fingerprints to `Build.act` [#2634, #2681] - Fingerprints identify project lineage and are validated against the project name - This makes accidental project renames and dependency identity conflicts easier to detect - Add local dependency overrides with `--dep NAME=PATH`. [#2555] - Add release mode aliases [#2708, #2761] - `--release` and `--optimize=release` select `ReleaseFast` - `--release=safe`, `--release=small`, and `--release=fast` select `ReleaseSafe`, `ReleaseSmall`, and `ReleaseFast` - Add `--jobs`, `--tty`, `--no-progress`, and `--timing` controls to the main `acton` CLI. [#2478, #2526, #2628] - Add `--parse-ast` for compiler debugging. [#2541] - Add JSON output for `acton test` and `acton test list`. [#2598] - Add a content-hash based result cache for `acton test`. [#2651] - Test results can be reused when the tested module, its dependencies, and expected snapshot data have not changed - This makes repeated test runs much faster while still invalidating cached results when relevant source or dependency content changes - Use `acton test --no-cache` to bypass the cache and force selected tests to rerun - Add `acton test --show-log` to always print captured test logs. [#2408] - Add `acton test --accept` as an alias for accepting snapshot / golden output. [#2584] - Add `acton test stress` mode for repeated concurrent test execution. [#2683, #2691, #2692, #2694] - `--stress-workers` controls the worker count - Stress output shows mixed outcomes and phase coverage while running - Add test capability tags with `testing.require()` and `acton test --tag`. [#2655] - Add `--min-time`, `--max-time`, `--min-iter`, and `--max-iter` controls for test runs. [#2467, #2408] - Add `u1`, `u8`, `i8`, and builtin `i64` support. [#2532, #2519] - Add `list.count()` method. [#2521] - Add JSON encoding / decoding for list values at the document root. [#2508] - Add `xml.Node.encode(pretty=True)` for pretty XML output. [#2512] - Add URI `quote()` and `unquote()` helpers. [#2719] - Add HTTPS server and TLS listener support. [#2576] - Add an Acton LLDB plugin for debugging Acton programs. [#2520] - Adds `acton bt`, `acton locals`, `acton demangle`, and `acton break` commands inside LLDB - Shows filtered, Acton-demangled backtraces with argument values instead of forcing users to read raw generated C symbol names - Prints locals with Acton names and value summaries, including strings, boxed values, objects, actors, classes, and generic value slots - Supports Acton source breakpoints like `acton break src/main.act:42` - Add container image builds for Acton Debian packages. [#1404] - Add `PROFILE` build option to the Makefile. [#2664] - `re.match()` now accepts an optional `start_pos` to begin scanning at an offset. [#2569] ### Changed - Move total build graph construction, dependency builds, and generated build.zig / build.zig.zon dependency wiring into the compiler. [#2550, #2551] - Use f-strings throughout standard library [#2297, #2290] - Improve process environment handling [#2298] - Inherit PATH when custom environment is provided - Enhance ecosystem lift process with additional documentation [#2272, #2288] - Extend QuickType with effect output for better comprehension translation [#2267] - Improve acton.rts.sleep platform coverage [#2303] - Switch to use new hash() function instead of __hash__ [#2255] - Remove __hash__ special method in favor of hash() builtin [#2304] - Rename `docs/acton-by-example` to `docs/acton-guide` [#2313] - Adopt Zig optimization levels in Acton [#2362] - Replace `--dev` flag with `--optimize` accepting: Debug, ReleaseSafe, ReleaseSmall, ReleaseFast - Change default from ReleaseFast to Debug (matching Zig's default) - `--dev` maps to Debug for backward compatibility, new `--release` maps to ReleaseFast - Simplify command-line parser structure [#2367] - Remove deprecated `--dev` option [#2366] - Revamp `actonc` debug / verbose mode [#2354] - Avoid writing `.ty` files in Types.reconstruct [#2357] - Remove unused sysLib & projLib fields from compiler Paths [#2385] - Cleanup remnants from pre-Zig build system migration - Simplify Webex PR merge notification & handle escapes [#2376, #2384, #2507] - Improve message formatting and environment variable handling - Retire the Acton-written CLI and make the Haskell compiler package provide the `acton` executable directly. [#2607] - `acton`, package management, testing, LSP, and compiler scheduling now use shared compiler code - The old `actonc` implementation has been renamed to the `acton` compiler package - Require `Build.act` for projects and require `name` and `fingerprint` in root project build files. [#2643, #2644] - Stabilize public interface hashes, include qualified free names in name hashing, and preserve full source locations in cached interfaces. [#2578, #2747, #2752] - Validate cached `.ty` files with source metadata and treat version, compiler, and dependency mismatches as recoverable stale cache entries. [#2440, #2717, #2718] - Defer full parsing until after project discovery. [#2742] - Pass explicit module selections into generated Zig builds so dependency builds only build the modules selected by the compiler. [#2666] - Use canonical dependency roots in generated `build.zig.zon` files and isolate transitive Zig dependency names. [#2690, #2696] - Upgrade the bundled Zig toolchain to 0.15.2. [#2590, #2594] - Use architecture-based default CPU settings for Zig targets. [#2574] - Rename `--ignore-compiler` to `--ignore-compiler-version` and make compiler version / mtime mismatches explicit stale-cache checks. [#2568, #2573, #2608, #2609] - Move generated C line directives behind `--dbg-no-lines`. [#2518] - Enable larger parallel GHC nurseries for compiler builds. [#2522] - Use HashMaps for imported type environments. [#2517] - Update the `acton new` project template. [#2589] - Track build cache growth with periodic checks. [#2475] - Make snapshot testing use `snapshots/expected` and `snapshots/output` directories instead of the older golden layout. [#2620] - Make `acton test --name` regex based. [#2616] - Store discovered test metadata in `.ty` headers so test discovery can reuse cached interfaces. [#2636] - Show cached test failures by default while keeping cached successes hidden. [#2557] - Align test progress with build progress, use project-qualified module names in progress output, and adapt progress width/timer fields to terminal width. [#2618, #2619, #2628, #2665, #2667, #2682, #2731] - Use the provided `logging.Handler` in HTTP server actors. [#2698] - Set empty XML node `text` and `tail` values to `None`. [#2509] - Make `file.mkdir()` and `file.rmdir()` idempotent. [#2477] - Use `mkdtemp` semantics for temporary directory creation. [#2693] - Prebuild one-byte ASCII strings to reduce allocation churn. [#2705] - Use common dependency builds to avoid redundant rebuilds and guard root-pin warnings behind `--quiet`. [#2649, #2653] ### Removed - Remove numpy support from the compiler, parser, stdlib, and tests. [#2413] - Remove the old explicit stub compilation mode. [#2414] - Remove the old Acton-written `acton.act` CLI implementation after moving CLI functionality into the compiler package. [#2607] ### Fixed - Fix string 'in' operator for substrings found at position 0 [#2280] - Fix unintended dependency on complete scope when scanning __init__ for attributes [#2285] - Ensure lambda-bound variables are in scope when comprehensions are translated [#2267] - Default print diff for testing.assertEqual failure [#2260] - Fix VERSION substitution in Homebrew PR creation [#2266] - Fix escaped braces in strings at position 0 [#2370] - Escaped braces `{{` and `}}` at start of strings were incorrectly parsed as interpolation - Now correctly converts `"{{a}}"` to `"{a}"` and handles mixed cases like `"{{hello}} {world}"` - Fix actor constructor alias resolution [#2365] - Aliased actors from imports (`from worker import Worker`) now correctly generate module-prefixed constructors - Fixes issues with builtin actors like `StringDecoder` and explicit aliased imports - Fix `.endswith()` for strings shorter than needle [#2348] - Prevent out-of-bounds memory access when haystack is shorter than needle - Fix `acton version` command structure [#2363] - Avoid superfluous rebuilds for actonc [#2349] - Replace `$FORMAT` macro with C function [#2327] - Fix "2320" error [#2323] - Fix Hashable protocol implementation [#2255] - Correct zig bytes definition - Fix issues with bytes containing NUL character - Fix solver handling of generic tuples, top-level constraint solving, skolemized type variables, scoped constraints, optional bounds, and coerced index targets. [#2319, #2332, #2339, #2438, #2564, #2570, #2587, #2603, #2624, #2661, #2675] - Accept four or five quotes at the end of triple-quoted strings. [#2388] - Improve `str.__repr__()` to escape braces correctly and handle quoted strings. [#2386] - Fix unclosed string parser diagnostics. [#2486] - Escape generated C identifiers that became keywords in C23. [#2480] - Fix Unicode handling in regular expressions. [#2540, #2553] - Fix parsing, inference, and code generation for negative integer literals, including the most negative `i64` value. [#2492, #2543] - Infer `bigint` for integer literals outside the `i64` range. [#2519] - Fix `argparse` defaults for list arguments and preserve rest arguments after `--`. [#2473, #2580] - Fix boolean singleton use and `None` checks in arbitrary boolean contexts. [#2485, #2491] - Fix `bytes.startswith()` end-bound checks. [#2410] - Fix `bytes.split()` and `bytearray.split()` for empty separator edge cases. [#2453] - Fix tuple printing when tuple values contain `None`. [#2430] - Implement `__repr__()` for exceptions. [#2421] - Fix printing lists that contain optional elements. [#2613] - Fix violations of the UTF-8 invariant when creating strings. [#2455] - Fix UTF-8 character / byte offset handling in string partitioning. [#2676] - Fix `process.pid()` after the process has exited. [#2405] - Fix process and build output handling for paths containing spaces. [#2516] - Fix UTF-8 handling in accepted golden test output. [#2593] - Fix JSON encoding of fixed-size integer values. [#2530] - Fix XML parse errors to use `XmlParseError` instead of generic runtime errors. [#2420] - Fix XML special character escaping, CDATA decoding, UTF-8 handling, and prefixed attribute decoding. [#2422, #2433] - Fix HTTP response callbacks to pass headers and treat header defaults case-insensitively. [#2448] - Validate malformed HTTP requests and responses instead of accepting invalid input or crashing during decode. [#2454, #2457] - Fix `is not None` lowering and optional narrowing through comprehension head expressions. [#2412, #2402, #2720] - Fix sequential flow analysis around `$RAISE`. [#2401] - Fix `while ... else` handling and reevaluate effectful loop conditions each iteration. [#2464, #2466] - Fix `and` / `or` expressions when unboxing is involved. [#2465] - Fix type casts to unboxable values during code generation. [#2479] - Fix conversion of dot selections with partially aliased import chains. [#2700] - Fix term substitution when the substitution range and domain overlap. [#2701] - Fix lambda lifting and CPS edge cases around converted closure types and nested control flow. [#2709, #2735, #2737] - Fix class attribute initialization checks and improve diagnostics for uninitialized attributes. [#2391] - Fix class-level and cyclic protocol witness handling. [#2484, #2488, #2556] - Fix class instance handling of type-parameter witnesses and prevent static methods from being invoked on instances. [#2623] - Fix conversion of `Self` in protocol methods after moving protocol conversion before constraint solving. [#2632] - Fix optional equality and optional-chain type inference edge cases. [#2716, #2672, #2726] - Fix private imported names leaking through interfaces. [#2567, #2752] - Fix actor `self` checks and discovered actor test wrappers. [#2514, #2535] - Fix malformed module top-level statements by restricting modules to declarations, imports, and assignments. [#2728] - Fix generated name collisions by prefixing generated names with the top-level name. [#2729] - Fix stale transitive dependencies after import renames. [#2727] - Fix transitive imports for cached modules. [#2677] - Fix missing dependency name hashes by treating them as stale cache entries. [#2637] - Fix dependency cache invalidation when a path from `--syspath` changes. [#2510] - Fix dependency override handling for declared dependencies. [#2555] - Validate local `--dep` paths as Acton project roots. [#2638] - Rework dependency downloads and honor `http_proxy`. [#2640] - Fetch transitive remote dependencies reachable through path dependencies before project discovery. [#2668] - Fix stale implementation refreshes when an interface hash is missing. [#2674] - Fix orphaned module artifacts after modules are removed. [#2633] - Preserve normal and test root stubs and prune orphaned binary executables. [#2265, #2505, #2538] - Fix relative / absolute path handling for build files and build.zig.zon syspath entries. [#2493, #2495] - Skip Zig builds for dependency projects when only Acton interface artifacts are needed. [#2496] - Fix `Build.act` null handling and unused dependency builds. [#2539, #2557] - Force recompilation when an alternate output directory is selected. [#2513] - Fix `acton --parse` output. [#2536] - Fix `acton build` handling after Zig toolchain upgrades. [#2595] - Improve error handling for compiler back passes. [#2597] - Fix LSP stdout framing corruption. [#2629] - Fix RTS message waiting so actors are not missed between waiting states and message delivery. [#2689] - Clean up libuv file requests to avoid stale request state. [#2695] - Work around macOS 26.4 command-line tools breaking Zig and set `DEVELOPER_DIR=/dev/null` for actondb on macOS. [#2715, #2756] - Restore the Zig dist target. [#2745] - Delete an accidental root-level copy of `Types.hs`. [#2739] ### Documentation - Add ecosystem lift process documentation - Add Hashable protocol documentation to Acton Guide. [#2310] - Add actor `self`, collection comprehension, and guide organization updates. [#2314, #2315, #2316, #2318] - Add Acton developer guide covering repository layout, build flow, compiler passes, runtime, and testing internals. [#2566] - Reshape the Acton Guide around task-oriented language, project, testing, and stdlib documentation. [#2734, #2740, #2750] - Document optional chaining and forced unwrapping. [#2722, #2732] - Document class initialization rules and improved uninitialized attribute diagnostics. [#2391] - Document project fingerprints and the `Build.act` project format. [#2634, #2644] - Document incremental compilation and content hashing. [#2610] - Document RTS backtrace debugging arguments. [#2615] - Explain constraint errors with rendered signatures. [#2751] - Clarify Acton lock ownership responsibilities. [#2678] - Update Ask Acton vector store data when the guide changes. [#2748] ### Testing / CI - Support test discovery of actors [#2337] - Recognize test actors without needing wrapper functions - Compiler generates wrappers automatically for discovered test actors - Remove old test types (sync/async/env test functions) - Update macOS CI to include macos-15 x86_64/aarch64 and macos-26 arm64, and drop macos-14 to keep the PR matrix small. [#2511, #2583] - Test run MUSL executables on Linux [#2355] - Test http2, netclics, zlib, netcli applications [#2338, #2331, #2324] - Add self name check for actors [#2317] - Add more parser / syntax error test cases [#2308] - Stop testing Debian 10 [#2352] - Drop Debian 11 from test-linux CI matrix [#2588] - this means we do not test / support Debian 11 as a OS dist for developing Acton itself - Debian 11 is still a valid run time target for Acton programs - run-linux still covers compiling & running Acton programs on Debian 11 - Support multiple files for compiler testing framework [#2363] - Accumulate environment from modules to support imports - Add compiler pass golden tests for parse, kind, type, normalize, deactorize, CPS, lambda lift, boxing, header generation, C generation, and signatures. [#2548] - Add incremental rebuild regression tests with stable sanitized hash output. [#2503, #2506, #2581, #2631] - Add snapshot testing coverage and cache validation for expected snapshot metadata. [#2639, #2679] - Add stress testing fixtures with racy and crashing FFI examples. [#2683] - Add TLS stdlib tests and an HTTPS server test fixture. [#2572, #2576] - Add ecosystem and ACTMF application tests. [#2641, #2548] - Add more ecosystem applications to CI coverage. [#2641] - Add Linux container image builds from Debian packages. [#1404] - Build Debian packages on Ubuntu 22.04 and fix stack usage in build-debs. [#2647, #2652] - Allow Telemetrify failures while macOS 26 support settles. [#2585] - Drop the shared Acton cache from CI. [#2605] - Drop Telemetrify from CI. [#2749] - Add build.zig generated-file gitignores. [#2656] - Close golden files after reading them during tests. [#2617] - Update GitHub Actions dependencies including checkout, cache, upload/download-artifact, create-pull-request, Docker build actions, and release-note extraction actions. [#2415, #2429, #2498, #2499, #2537, #2544, #2558, #2559, #2560, #2561, #2669, #2670, #2684, #2685, #2686, #2687, #2591, #2754, #2755] ## [0.26.0] - 2025-06-02 ### Added - Add list, set, and dict comprehensions [#2258] - Add CLAUDE.md files for AI assistant guidance [#2262] - Component-specific development guides - Code style guidelines and best practices - Add Claude PR Assistant GitHub Actions workflow [#2261] ### Changed - Expand numpy test suite [#2259] - Update install docs to remove architecture restrictions for APT repository [#2253] ### Fixed - Fix cosmetic race condition in actor waiting queue operations [#2254] - Ensure atomic setting of waitsfor link when entering waiting state - Fix handling of NotImplemented extension annotations [#2256] - Keep annotations until CodeGen for proper constructor generation ### Documentation - Document changelog update process before releases - Remove arch=amd64 restriction from APT repository documentation ## [0.25.0] - 2025-04-23 ### Added - Acton Vim plugin for syntax highlighting & indent, see https://github.com/actonlang/vim-acton - Add `crypto.hash.md5` module for MD5 hashing - supports incremental updates and one-shot - Add `bytes.from_hex()` & `bytes.hex()` for hex encoding/decoding of bytes - Add `.str_ms()` to `time.Duration` - Add `max_def` and `min_def` functions that require a default argument - Unlike max() & min(), these functions require a default value that is returned when the input iterable is empty - `max_def([1, 2, 3], -1)` returns 3 - `max_def([], -1)` returns -1 - Add `re.split()` function to split strings based on regular expressions - `re.split(" +", "a b c")` returns `["a", "b", "c"]` - Add support for golden testing in the `testing` module - Test functions can return a `str` to be compared against stored golden values - `acton test` will show actual vs expected golden value - Golden values are stored in `test/golden/MODULE/TEST_NAME` - Update expected values with `--golden-update` - Unmangle actor class names in logging - Add `--no-threads` option to compile single-threaded applications - Set minimum thread stack size to 8MB to avoid stack overflows - Add better documentation for integer types in the guide - Add `__name__` variable containing current module name - Add `complex.from_real_imag()` function to create complex numbers - Add support for complex numbers as dictionary keys - Add proper implementation of the Logical protocol for integers - Add URI parsing module for handling HTTP URLs and other URIs - Add `--list-imports` option to actonc to show imported modules - Add a ConsoleSink to the logging module - Capture log messages in tests for easier troubleshooting - Add diff module for comparing strings - Support for unified diff format with customizable context headers and colors - Add GitHub Action to create new releases automatically - Add support for ALPN (Application-Layer Protocol Negotiation) in TLS ### Changed - Dict & Mapping methods `get` and `pop` now return `None` when key is not found, instead of throwing KeyError - Use new `get_def` & `pop_def` for explicit default values - Automatic backtrace printing on crashes disabled on non-Linux platforms - LLDB on MacOS often hangs, so automatic backtrace printing is disabled - Make module paths in type error messages clickable for easier navigation - Improve `RunProcess` handling to properly await EOF for stdout/stderr - Disable garbage collection during package upgrade operations to improve performance - Silence build lock messages for dependency builds to reduce output noise - Use development mode (`--dev`) to build dependencies in test command - Don't store protocol witnesses in class attributes, push further into methods instead - Upgrade tlsuv library to v0.33.4 for improved TLS support - Enhance package dependency handling with support for transitive dependencies - Use a global dependencies directory in `~/.cache` for better dependency management - Improve testing output with deduplication of stdout/stderr messages - Colorize error messages for better readability - Reintroduce `--tempdir` option to actonc for manual control of temporary files - Allow integers to overflow for fixed-size integer types (i16, i32, i64, etc.) - Use diff for golden testing when outputs don't match - Rename common.mk to version.mk to better reflect its purpose - Make del operator idempotent for lists and dictionaries ### Fixed - Fix type conversion between `u16` and `int` - Fix XML default namespace parsing - Fix error handling in process actor - Process signals are now ignored if process has exited - Better error handling around stdin/stdout/stderr operations - Fix volatile variables in try-except blocks to avoid compiler optimization issues impacting control flow - Fix string format in `time.DateTime`'s RFC1123 format (month was off by one) - Improve error messages with better source location information - Added location details for "Missing constraint" errors - Added location details for "missing tuple component" errors - Better error reporting when class method's first parameter doesn't match Self type - Fix dictionary iteration in relation context - Fix constructor functions for bounded integer types - Fix CPS transformation for nested lambdas with preprocessing requirements - Fix handling of main project local dependency overrides - Fix `zip()` function implementation - Fix left shift operator (`<<`) for integers - Fix XML encoding to properly handle UTF-8 - Fix TCP connection close to properly mark socket as invalid - Fix hash function to avoid signed overflow undefined behavior - Fix depth subtyping for builtin collections (list, dict, set) - Fix discovery of root actor based on name - Fix `acton test --name` to correctly filter tests by name - Fix string allocation in `B_str` to properly account for byte length - Fix package upgrade correctness - Fix handling of XML comments during parsing - Fix main project dependencies in build.zig.zon - Fix polarity improvement handling in type solver - Fix exception handling in iterate-relation context - Fix `free()` behavior (now a no-op in GC environment) - Fix race condition in actor waiting queue operations - Optimize f-string parsing for better performance ### Testing / CI - Add macos-aarch64 tip release build - Stop testing on Ubuntu 18.04 - Install gdb in test-app environment for better crash analysis - Separate caches for Acton build and Stack/GHC in CI to avoid cache thrashing - Add caching for Linux ARM64 builds to improve CI speed - Ensure uniqueness of test artifact names to prevent collisions - Add support for Linux on ARM64 (aarch64) in CI - Add test of respnet (a real-world Acton application) to CI - Add testing on Ubuntu 24.04 for ARM64 - Use artifact upload/download v4 for better performance - Add tests for all compiler passes - Await cache cleaning to avoid race conditions ## [0.24.1] (2024-11-09) ## Added - It is now possible to compare actors with `if a is b` - This is a stop gap measure. - Equality comparison requires the `Eq` protocol and this awaits the planned actor / class unification work ## Changed - Change `TCPListenConnection` callback `on_error(c, error: str)` to `on_listen(c, error: ?str)`. Previously, the `on_error()` callback was called if there was an error establishing the listening connection. It is now also called in the positive case, when we have successfully established the listening connection. If the `error` argument is `None`, all went well whereas if it is set, there was an error. ## Fixed - Dependencies are now idempotently fetched, i.e. if we first look if we already have the configured hash locally and use that. We only fetch it if we don't have a dependency locally. - Previously, `acton build` would effectively require an Internet connection, which is now fixed. Like now, you can do `acton fetch` in a repo to fetch all dependencies locally and from there on you can work in "airplane mode". - Dependency hash mismatch is now correctly checked and treated as an error. ### Testing / CI / Build - TCP tests have been rewritten to use the new `TCPListenConnection` `on_listen` callback to properly sequence the test so we first establish the server and then start the client. This removes a racy condition which lead to flaky test failures. - Stopped testing on MacOS 12, which is EoL. ## [0.24.0] (2024-11-05) Acton now supports package dependencies and has a package manager to work with these, fetching and building them. There are new docs at https://acton.guide It's now possible to write Acton low level code in Zig, in addition to C. ## Added - New docs: https://acton.guide - Starting point was the Acton-by-Example and it's been improved from there with new content and updates of existing pages - New top level structure making it easier to navigate - Includes a guide on how to integrate a C library - Package management! - Acton now supports adding dependencies on other packages, either in a local path or to be downloaded from the Internet. - New commands, `acton pkg add` etc to manage dependencies, see https://acton.guide for more - This largely relies on the Zig package manager and the Zig build system - It is also possible to add a Zig package dependency in an Acton project in order to enable the integration with Zig / C / C++ libraries - Lots of improvements around the build system - Upgrade to Zig v0.13 - Avoid anonymousDependency which is deprecated in newer Zig versions - Materialize build.zig on disk, to allow customization, like adding dependencies - Send deps as zig CLI arguments instead of hacking builder imports - Remove old extra headers, now included in Zig 0.13 - Add `any()` and `all()` - does what it sounds like - These were previously removed due to a bug but are now brought back - `json.encode()` now has a `pretty` option to enable pretty printing - `file.ReadFile()` & `file.WriteFile()` now support taking an advisory lock on Linux and MacOS - `acton` now takes a project lock before compiling to avoid races - Revamped zig build caching, separating the local and global cache - Only the local one is automatically periodically cleaned - Add support for writing Acton modules in Zig - It is now possible to write functions in Zig, thus making the entire Zig ecosystem potentially reachable with ease - Add new `base64` module to stdlib - It is built on the Zig stdlib `base64` functions - Allow naming overlap in hierarchical modules - It is now possible to have a module `foo` (src/foo.act) and a `foo.bar` (src/foo/bar.act), which would previously conflict and yield a compilation error. - Improved source location error messages - Upgraded to Haskell GHC 9.6.6 ## Changed - Add `remote_close` callback to TCPConnection / TCPListenConnection & TLSconnection - Use `OSError` instead of `RuntimeError` for general exceptions in the `file` module functions and classes - `argparse` `--help` now shows help for the most specific cmd - Remove worked thread CPU affinity to get compile speedup - This is primarily as a workaround for slow Zig builds. For `acton build` we run the acton compiler `actonc` and eventually `zig build`. Zig gets the number of parallel worker threads to run by inspecting its affinity. When started by Acton, it inherits the affinity of the worker thread that started it. - CPU affinity is probably a win for server workloads, so this is a regression, but for desktop apps, it likely workb setter not pinning to CPU cores ## Fixed - Fixed scope extension to handle accessing variables in else defined in try - Fixed CPS'ed __init__ so we can correctly instantiate actors in class init - Fixed passing function with mut effect to actor - The actor seal leak detection would incorrectly trigger. We need a better detector, until then the check is removed. - Fix returning fixed size integer - The recent unboxing code misbehaved in some situations when trying to return a fixed size integer from a function - Fix assert(Not)Equal - Now actually works for None values, would previously only compare the values if they were not-None - Fix qualified name checking, so we can properly detect method invocation via class name even for imported classes - This was an issue when importing a module and trying to call a @staticmethod on a class ## Testing / CI / Build - Stopped building the vendored libraries we ship, they are now shipped as source and compiled on demand - Force hermetic build on MacOS - Avoids pulling in system libraries - Simplify actondb build - Add dependabot config for updating GitHub Actions workflows - Add test on macos-15 - Test other Acton apps in main Acton repo CI ## [0.23.0] (2024-08-13) ## Added - More unboxing of fixed size integers - Function local variables are unboxed - Passing fixed size integers as arguments between functions is also unboxed - This adds an extra pass to the compiler to handle boxing and unboxing - For some programs, the code is now pretty much optimal - For example, the C code generated from `test/perf/src/dct.act` looks pretty much as one would write it by hand and thus runs at about the "speed of C". It does 0 mallocs and runs about 20x faster than before unboxing (depending a bit on computer). - class and actor attributes are still boxed - This is likely the most important future work around unboxing since individual mallocs for class & actor attributes typically account for a the lion's share of GC pressure - It is challenging around generics though - New `Set.update()` method to add items to a set from an iterable, such as a list or another set - Added `--module` argument to `acton test` to select module to test - For example, `acton test --module foo` to only run tests in module foo - Improved printing of test results for test modules that crashed - The error is now printed for each individual test in the test module - Added `list.index(val, start=0, stop: ?int)` to get the first index of an element in a list. It can be constrained through the start and stop parameters. ## Changed - `re.match()` now returns `Match` object where the group is `list[?str]`. It used to be `list[str]` but it is possible to have groups that do not match on anything and so `?str` is the correct type. This applies both for named groups and normal numbered groups. - For example, consider `foo((123)|bar)` which matches either `foo123` or `foobar`. The inner `(123)` group is ORed and so it will have no match for `foobar`, thus we get the result `m.group = ["foobar", "bar", None]` - `set.pop()` now throws `ValueError` for an empty set ## Fixed - Fixed tuple type inference - Tuples with named fields can now be properly type inferred - `acton test perf` now limits concurrency to 1 to get better results - Fix `str.strip()` on empty strings, it would previously return `\n` but now returns an empty string as it should - Fixes crash in `re.match()` for groups with no matches, which previously resulted in `SEGFAULT` - For example, consider `foo((123)|bar)` which matches either `foo123` or `foobar`. The inner `(123)` group is ORed and so it will have no match for `foobar`, thus we get the result `m.group = ["foobar", "bar", None]` - This would previously crash but we now properly check the result values - Fix str slicing when range is 0 length which would previously `SIGILL` - For example, for `a = "foobar"` if we would try to access `a[23:]`, there is no character 23 and so the length of the slice is 0 which would trigger a `SIGILL` when compiled in `--dev` mode (which comes with lots of extra UBsan) - Fix dict corruption issue when deleting items #1805 - `set.pop()` now does not crash for an empty list (it threw NULL before) - Fix decoding of buffered test output ### Testing / CI - Added performance test to CI - This runs on a dedicated computer, a laptop in Kristian's rack at home - Runs `acton test perf` in `test/perf` which currently only includes the `dct` program - Simply add more test programs to the `test/perf` project to have them run - The testing procedure is as follow: - The CI test checks out the tests from the feature branch, so it will always be the latest version of the test itself - The latest tip release from acton main branch is installed and used to compile the `test/perf` project - `acton test perf --record` is used to run the test and record the result, which will act as the baseline - The acton release from the local feature branch is then installed (fetched as artifact from the `build-debs` job) - `acton test perf` is now run, which will run with the latest version and compare the results against the baseline - We do not currently inspect the results to give a pass / fail score, they're just printed in the CI output for a human to look at - Natural variance seems to hover around +-5%, which feels OK - Revamp PR testing to run on small set of platforms and run a nightly scheduled test job that includes all platforms that were previously in the PR jobs - This was triggered by the number of platforms reaching a higher number which in turn has led to more cached data and as the GitHub Actions runner cache is limited to 10GB, we hit the limit and got churn which meant that there were always slow jobs. By reducing the number of PR jobs, they can continue to run cached whereas the nightly jobs can run without a cache. - Stop CI testing on MacOS 11 as it has been deprecated by Github - Start CI testing on Ubuntu 24.04 - Stop CI testing on Ubuntu 23.04 and 23.10 as they are EoL - Temporary fix of building Acton by using our own mirror for the Zig tar ball. We are using a particular nightly v0.12.0 build that is no longer available for download from ziglang.org and so we now mirror it ourselves. This affects both builds in CI and local builds. - Fix GitHub Actions to run on Ubuntu 18.04 - The artifact download action uses Node.JS to run and as GitHub has imposed constraints and new defaults, this has been magically updated to use a newer version of Node.JS than before. The newer Node version is compiled using glibc 2.28 and that's too new for Ubuntu 18.04, so the end result is that you basically can't use the common GitHub Actions with Ubuntu 18.04 or similar older distros. What a weird way to treat your CI users by GitHub!? Anyhow, we work around this by explicitly enabling the use of the old Node again. - Add caching for test-external-projects of C object files & archives ## [0.22.0] (2024-04-14) Support for Windows and continued improvements for `acton test`! Internally the biggest change is the removal of link time redirection of malloc, which opens up for more flexible memory management. ### Added - Acton programs now run on Windows! - It is now possible to compile Acton programs for Windows, both x86_64 and aarch64, although since Acton itself (compiler etc) is not available on Windows, only cross-compilation from MacOS or Linux is possible. - Use `acton --target aarch64-windows-gnu examples/helloworld.act` to produce `examples/helloworld.exe` which can be run on Windows - Acton applications compiled for Windows are single threaded - termios related terminal settings, is not supported on Windows - Acton RTS now supports actor cleanup through GC finalization - Define a `action def __cleanup__():` action on your actor and it will be run when the actor is about to be garbage collected - `acton build` now builds dependencies in `deps/` before building the main project - `acton test` now excludes the time spent in GC from test times - This is probably somewhat approximate and not super accurate, in particular for tests with very short test durations - `acton test perf` is now expanded and support all kinds of tests (previously only unit tests were supported) - some memory usage is printed alongside timing information - GC is run explicitly during perf test to get better memory usage stats but it also slows things down a bit, in particular for very short duration tests - `acton test perf --record` can save a performance snapshot to disk - Subsequent invocations of `acton test perf` will back the data from disk and display a comparison with percentage diff - AbE: testing documentation is much improved! - `acton --only-build` performs only the low level build from .C source, skipping compilation of .act files. This can be used if you want to modify the C source by hand and still leverage the low level builder to perform the build. - `file.FS.cwd()` to get current working directory - `file.join_path()` to join path components - Link time redirection of malloc & friends is now removed. All malloc calls are instead explicit, either directly to `GC_MALLOC` or via `acton_malloc` which is our own malloc function which is runtime reconfigurable. While there is no usage of malloc directly from our code, it is now possible to do manual memory management mixed with GC managed memory. - As before, module constants are placed in the regular heap, so that the GC does not have to scan it. - Many string formatting functions have been reshaped since `asprintf` does an implicit malloc, which we must either free or avoid. As a result, we now copy less data around, which speeds things up. - `process.Process` now takes an optional timeout argument to stop the process - New `process.RunProcess` that waits for a process to exit and then reports to a callback with the buffered output from stdout / stderr - This can provide a simpler interface than `process.Process` if you just want to wait for the process to finish running before starting to parse its output as you'll get a single invokation and the full output rather than receive it piecemeal - Add `.unix_s()` `.unix_ms()` `.unix_us()` `.unix_ns()` to `time.Instant` - To get a Unix timestamp (seconds since 1970-01-01 00:00:00), as seconds, milliseconds, microseconds or nanoseconds respectively - `env.is_tty()` to check if stdout is a TTY - `acton.rts.start_gc_performance_measurement()` to start a GC perf measurement - `acton.rts.get_gc_time()` to get the GC timings - `env.is_tty()` to check if stdout is a TTY - `env.set_stdin(canonical: bool, echo: bool)` to set stdin options - `canonical` is the default mode which is line buffered where the OS / terminal offers line editing capabilities and we only receive the input ones carriage return is hit - setting `env.set_stdin(canonical=False)` turns stdin into non-canonical mode where each character as entered is immediately forwarded to the stdin callback so we can react to it, great for interactive applications! - `echo` enables (the default) or disables echoing of characters - `term` improvements: - More grey shades - `term.clear` && `term.top` to clear and move cursor to top - `http.Client.close()` to explicitly close a connection - Single threaded RTS mode, only used by Windows for now ### Changed - The work dir and environment arguments of `process.Process` have been moved to the end as they are optional, making it possible to invoke with fewer args - Tests run by `acton test` are now compiled with `--dev` and thus have C asserts enabled, similarly the test.hs that drives the test in the Acton repo now compile with `--dev` to get C asserts - `acton test` now runs test for at least 50ms - `acton test perf` now runs test for at least 1s - Rename `--only-act` to `--skip-build` - Acton build cache now uses up to 15GB instead of 5GB ### Removed - `actonc` no longer supports `--no-zigbuild` / `--zigbuild` (it's now the default/only choice). It hasn't been tested in quite some time now and the zig build system works well enough that there is basically no reason to keep the old system around. - `actonc` no longer accepts `--cc` since we now always build using the zig build system which implies the clang version that Zig ships. - `actonc` no longer supports explicit `--stub` compilation, use `--auto-stub` ### Fixed - `key` argument in `KeyError(key)` is now of type `value`, not `list[None]` which it was previously incorrect inferred as - `file.WriteFile.write()` now truncates file to avoid leftover tail of old content - `time.Stopwatch().reset()` now works - Test crashes are now handled - If the test program (e.g. `._test_foo`) crashes from an assert or similar, the top test runner now captures this and reflects it in the output - Correct dependency path computation in builder - Makefile now more idempotent to avoid building when nothing has changed ### Testing / CI - Test on MacOS 14 on Apple M1 / arm64 / aarch64 - Many tests are now repeatedly 100 times to give some idea of stability ## [0.21.0] (2024-03-13) ### Added - `acton test` testing has been revamped, now doing multiple test iterations - each test will be run for at least 1ms, for many smaller unit tests this means the test case run hundreds of times - all the internals have been rewritten to handle multiple tests results from a test - running multiple test iterations gives better performance measurement but can also show flakiness in tests - `acton test list` will list all the test names in a project - `acton test --name foo --name bar` will filter to only run tests named `foo` and `bar` in a project - AbE: explain testing with `acton test` - New methods to interact with environment variables [#1723] - `getenv` & `getenvb` to read an environment variable - `setenv` & `setenvb` to set an environment variable - `unsetenv` & `unsetenvb` to set an environment variable - The first set of functions work with strings and attempt to automatically detect the encoding, although utf-8 is the only supported encoding by Acton right now. - The functions ending with `b` work with bytes data which can be used for explicit control over encoding. - `env.stdin_install` now supports both `str` and `bytes` [#1723] - It was orignally built to work with `str` which meant it decoded data from stdin automatically. This assumed utf-8 encoding. - `env.stdin_install` was then changed so the callback would get `bytes`, which is technically more correct (it could just be bytes!) but leaves it to the application programmer to decode data. - A new interface now offers the best of both worlds: - `env.stdin_install(on_stdin, encoding, on_stdin_bytes)` - by specifying `env.stdin_install(on_stdin=my_cb)`, `my_cb` will be called and get `str` input. The encoding is detected by reading the `LANG` environment variable or defaults to `utf-8`. It is possible to explicitly specify the encoding with the `encoding` argument. - Use `env.stdin_install(on_stdin_bytes=my_cb)` to instead receive bytes - Acton now always compiles everything from source - Previously, pre-compiled binary libraries were shipped for the native target, so on x86_64-linux, there was a libActon.a compiled for x86_64-linux - Now we just ship the source code of Acton base etc and perform the full C compilation when we actually run actonc - The first invokations of `acton build` is slow, taking up to a few minutes, but as all results are cached, subsequent invokations run in fractions of a second. - `~/.cache/acton` is used to store the cache and it is wiped if it reaches 5GB after which it will be automatically re-populated when the next `acton build` is called - Low level compiler support for dependencies - Place Acton project dependencies in the `deps/` folder and the compiler will automatically find them to allow inclusion of Acton modules from other Acton projects - This implements the low level internal support for finding modules in other projects and correctly linking together the final output - There is NO support for managing the dependency download itself or even compiling the dependency - `SIGABRT` is now automatically handled by the crash handler for automatic backtrace printing or interactive debugging, just like we already manage `SIGILL` and `SIGSEGV` - This simplifies debugging of Acton itself after catastrophic crashes - `file` module now has methods to interact with file system, like listing files, making directories, stating files, removing files and walking directory trees. - `file.FS.exepath()` returns the path to the current executable - `acton` now finds `actonc` by looking at its own location rather than assuming `actonc` is on the path - Add `--only-act` to only perform Acton compilation and skip C compilation ### Changed - `acton test` will compile test functions in dev mode to get asserts - The `dev` and `rel` folders have been removed, e.g. `out/rel/bin` -> `out/bin` - Printing of compiler pass debug output from individual files, like `acton src/foo.act --types` will now only print output from the specified name and not dependencies - Previously, dependent modules, like if `src/foo.act` imports `bar`, we would also print the types debug output for the `bar` module - Printing of compiler pass debug output requires recompiling the module and thus shortcutting the up-to-date check. By not printing output for included modules, the included modules do not need to be recompiled thus speeding up the whole compilation. - Always link in libprotobuf-c to allow modules to use protobuf tech - Improved argparse parsing by doing a descent first parsing of options and into sub-commands with positional argument parsing happening as a second pass [#1714] ### Fixed - `acton new foo` now creates a new project `foo` - Fixed handling of failing tests in `acton test` [#1709] - Fixed required since self is now parsed as a kwd param [#1715] - Upgrade GC - Now ignoring `free()`. This was also previously the case but this was lost when we upstreamed the new build.zig for bdwgc. It is now back, which is required for handling the "edge", like where syscall / libc calls do malloc and then free. uv_fs_scandir is an example of such, which was recently added and triggered a bug. - Incremental collection has been fixed on Linux so that it should work, although it is not supported by the Acton RTS. Incremental collection is likely much slower for most programs but with better responsiveness. It could potentially be better for very large heaps as well as overhead of virtual dirty bit now only hits from a very small heap. It remains to be seen. - `testing.test_runner` has been fixed with regards to scheduling, now we actually wait for a test kind to be completed before proceeding to the next. Previously for async tests we would spawn all tests immediately and then proceed to next test category, so we would oversubscribe the tests runners giving worse performance. - Various fixes to test output, like count of tess was wrong - numpy now compiles and runs. There are new tests cases! ### Testing / CI - Tests, like of builtins etc, now run with `--dev` so we get assertions ## [0.20.1] (2024-02-22) ### Fixed - Install `acton` frontend in Debian package ## [0.20.0] (2024-02-22) ### Added - New `acton` CLI which takes over as the main acton program, it should be called instead of `actonc`, for example `acton build` [#1645] - it calls into `actonc` for doing most of the work and is currently mostly just a thin wrapper - over time, more functionality will be placed in the `acton` frontend - New `acton test` command which build and runs all test in a project [#1645] - The compiler now does automatic test discovery - Simply doing `import testing` and functions with a name starting with `_test` will be identified as a test and run by `acton test`. The functions are sorted into categories based on their type signature. - Run-time reconfigurable `malloc` - It is now possible to reconfigure which malloc to use during runtime - All external libraries (libuv for example) are now configured to use a particular malloc - Libraries that did not support a custom alloc have now been extended with support for custom malloc. - Module constants are placed in non-GC heap - Using the reconfigurable malloc, we now make use of the "real" malloc (the one libc provides) during startup of RTS and up past module init. This means all module constants will be placed on the normal heap and not the GC heap. - The GC is mark & sweep which means it slows down considerably when there is a large live heap. - This makes is a viable option to place large amounts of data as module constants instead of run time state to speed up programs. - Fixed size integers arithmetic and comparisons are now unboxed - For math heavy programs, this can produce a 4x improvement - A lot of witnesses are now unnecessary and thus removed, reducing GC pressure - `testing` module has gotten a face lift with much better asserts - The assert exceptions now include and print the values - Formatting happens in `__str__` so performance of exceptions is unchanged - New `snappy` module in stdlib [#1655] - Snappy is a fast compression library - Snappy is written in C++ which implied some changes to build.zig and actonc - It is now possible to print a .ty file by doing: `acton foo.ty` - Improved size & performance of dictionaries - An empty dictionary is now completely empty - For low number of elements, the dictionary is actually a list with linear searching - For 5 elements and up, the dict starts to use a hashtable - `KeyError` & `IndexError` now include key / index so it's easier to understand what went wrong ### Changed - The Debian package of Acton now depends on libc 2.27 [#1645] - Previously depended on the glibc installed on the the build machine (2.36) since it was expanded from `${shlibs:Depends}` - Now using Zig 0.12.0-dev.2236 - the build system has changed somewhat so all build.zig files are updated - DB backend is now optional, include with `acton build --db` - Using newer version of tlsuv library - RTS main thread now runs special actors, currently just `Env` - This enables us to install signal handlers from `Env` since this must be done from a programs main thread. ### Fixed - `dict` changed internally to allow storing of `None` - Support `None` in JSON - Based on the improved support of dicts - `lstrip`, `rstrip` & `setdefault` now work properly - Fix effect of `json.encode()` and `json.decode()` [#1654] - They are pure! - Fix `testing.test_runner` when there are 0 tests to run [#] - Add tests of client & server in `http` module - `argparse` module now supports nested command parsing - `argparse` module now supports `--` for literal interpretation of positional arguments - Fix compilation of projects that used TLS - We had missed linking in all necessary mbedtls libraries ## [0.19.2] (2024-01-15) ### Added - `argparse` now supports optional positional arguments - like so: `p.add_arg("foo", "Foo thing", required=False, nargs="?")` - `print()` now takes multiple new input arguments: - `print(*vals, sep=" ", end="", stderr=False, flush=False)` - `sep` is the separation character between values, default " " - `end` is the line ending character, default "\n" - Output is written to stdout per default, set `stderr=True` to write to stderr instead - set `flush=True` to flush the output - new `--rts-bt-debug` flag that launches interactive debugger (`gdb`) on SIGSEGV / SIGILL ### Changed - `print()` now formats to a temporary buffer before printing to reduce interleaving multiple outputs - `printn()` has been removed in preference of using `print(foo, end="")` ### Fixed - `KeyError` now includes the key as part of the error message - e.g. `KeyError: getitem: key not in dictionary, key: foobar` - The string formatting of the error message including the key only happens when the str representation of the exception is necessary, so it does not incur a performance penalty in normal scenarios - The key for which the lookup was attempted is stored in the `key` attribute - Homebrew Formula now somewhat decoupled from Stack version [#1627] - Idiomatic Homebrew Formulas use system-ghc, i.e. a GHC version installed by Homebrew itself and not from Stack. Since we specify a Stack LTS resolver, which is a coupled to a particular version of GHC, there is room for a version mismatch. - The latest occurrence of which was GHC 9.4.8 in Homebrew vs Stack LTS 21.13 with GHC 9.4.7. A rather silly small mismatch but that nonetheless breaks the Homebrew build. This is particularly annoying because it happens only after we've made a release, so the feedback is too late and thus a correction version must be released to fix the version mismatch (we've upgraded to LTS 21.25 with GHC 9.4.8 to align on Homebrew). - Now `skip-ghc-check` is used to skip the GHC version check to allow some minor mismatch to happen. We must still ensure that at least the major version of GHC is aligned, like GHC 9.4. ## [0.19.1] (2024-01-08) ### Fixed - Upgraded Stack to 21.25 / GHC 9.4.8 - This should hopefully fix the Homebrew build ## [0.19.0] (2024-01-08) ### Added - Much improved argument "rows" support [#1609] [#1617], including: - positional & keywords arguments - default argument values - `up`, `down`, `left` & `right` in `term` module now accept `n` arg [#1619] - can move multiple steps in given direction ### Changed - for `http.Client` the following positional arguments are now keyword args: - `schema`: defaults to `https` - `port`: defaults to `80` for schema `http` and `443` for `https` - `tls_verify`: default `True` - `connect_timeout`: default `10.0` ### Fixed - Remove superfluous explicit arguments, now using default values [#1615] [#1618] - Now possible to print `None` [#1609] ### Testing / CI - Now testing Telemetrify in GitHub Action workflow as part of CI testing - Telemetrify is the largest known application written using Acton, so we add testing of it to the Acton repo to avoid accidental breakage - Telemetrify main branch is already tested with the latest release of Acton - now, new changes in acton are also verified against the telemetrify repo - we test against the `acton-next` branch in the telemetrify repo - this enables us to make breaking changes in the Acton repo, realize the break, then write a fix adapting the telemetrify code to the new Acton change and push this to the `acton-next` branch after which the PR on the Acton repo can be retried ## [0.18.5] (2023-12-12) ### Testing / CI - Fix build of APT repo ## [0.18.4] (2023-12-12) ### Fixed - Add constraint forcing type of self parameter [#1598] - Let solver use upper bound of type variable when reducing protocol constraints - Remove subclass constraint on isinstance parameters - Type error message improvements [#1522] [#1589] [#1596] - Fix `actonc --debug` [#1591] - Now also printing zig output - `--verbose` has been removed ### Testing / CI - Stop testing on MacOS 11 [#1600] - Homebrew has dropped support for MacOS 11 so the CI job had to build stuff from source making it super slow and fragile, thus dropping it. ## [0.18.3] (2023-11-21) ### Added - `type()` function that provides the type of something as a string [#1587] - Can be really useful as development tool to get inferred types or similar - It should not be used for metaprogramming or similar - This will likely be removed in the future when there is a better way of debugging types, like a language server ### Fixed - Only print truly unhandled exception [#1586] - "Unhandled" Exceptions are no longer printed in actor methods called by another actor that awaits the return value - It used to be that when an actor B raised an exception in a method called by actor A, presuming no try/except handling at all, an `Unhandled exception` message would be printed in both actor A and B. - Now we inspect waiting actors and in case there are any, the exception will be considered "handled" in the actor method that raised the exception - Cleanup old cruft from Makefile [#] - Now using zig v0.12.0-dev.1536 - Improved CPU feature detection for Apple silicon - Some smaller zig build system changes, but it seems to be stabilizing as there are now docs! - Acton now builds on Apple Silicon MacOS [#1582] - It used to not understand the CPU features and thus MbedTLS would fail to compile - With zig v0.12.0, the correct CPU features are recognized - Fix int rounding [#1577] - Improve DNS error handling in net.TCPConnection [#1573] - Ignore DNS resolution errors if we're already in connected state - Given happy eyeball support, we could get a A record and establish a working IPv4 connection while IPv6 would give an error and be retried continuously, which is completely pointless when IPv4 is already established. - Type error now separate error from identifier with `:` [#1583] ### Testing / CI - Now also testing build / test and running on Ubuntu 23.10 - There are now golden tests for the compilers type errors [#1571] ## [0.18.2] (2023-10-31) A real fix this time to the Debian APT repo. ## [0.18.1] (2023-10-31) A small fix for Debian builds. ### Fixed - Align Debian package building on bookworm / 12 ## [0.18.0] (2023-10-30) ### Added - Exceptions now have a `__str__()` method used to print the exception - useful for exception types where we want to be able to include dynamic data - string formatting of dynamic log messages is expensive, so we don't want to incur that cost for exceptions that are thrown but never printed - add extra attributes and print them in `__str__()` in your custom exceptions - Add `testing` module [#1524] [#1552] - Supports four categories of tests: - unit tests: `proc() -> None`, think pure functions - synchronous actor tests, involves actors - asynchronous actor tests - env tests - Improvement to type error messages [#1554] [#1556] [#1559] - Add `term` module - a couple of small helpers for doing colored text and similar in terminals - Add `random.choice()` & `random.choice()` [#1541] - Add `printn()` is like print but prints without an ending newline - also flushes output immediately, useful to print progress style output - this is temporary and will be removed once default argument handling is properly implemented - Add `math.pi = 3.141592653589793` [#1539] - `acton.rts.enable_gc()` & `acton.rts.disable_gc()` - there are situations in which it can be useful to turn off the GC, such as during certain test scenarios - `acton.rts.get_mem_usage()` returns memory usage [#] - approximate output due to how the GC works - Add `uri` module [#1560] - Features a `parse_http()` function to parse a HTTP URL into its parts ### Changed - Reverted to global single threaded malloc [#1547] - There have been some reports of errors that could potentially be related to per-thread malloc or DNS lookups. In caution, the per-thread malloc has been disabled and will be brought back in a safe way once we've been able to test it much more thoroughly. - Integer division by zero now results in exception `ZeroDivisionError` - for `float`, `inf` is returned [#1530] - this is aligned with IEEE & languages like C, Zig, Rust, Swift, Julia - Python raises an exception on float divide by zero - Haskell Stack updated to LTS 21.13 using GHC 9.4 [#1517] - Some tests show actonc running ~25% faster - Presumably thanks to more optimizations in ghc - C++ seemingly pulled in as a dependency for building Acton itself :( - Would be nice to use zig c++ but alas, that does not work - `actonc` now always built statically on Linux - Previously it was only built statically in release mode - It does emit some errors / warnings around using dlopen but those are harmless and can be ignored in our case - commands in `argparse` now expect `proc()` rather than `pure()` - JSON encode/decode are now free functions [#1536] - the JSON encode and decode functions were implemented as methods on an actor due to an earlier actonc bug - bug is fixed, so `encode()` and `decode()` are now moved to free functions in the `json` module - the old `Json` actor remains and simply wraps the free functions ### Fixed - Fix error handling in `net.TCPConnection` for single family use [#1546] - original error handling presumed a dual stack socket and so would wait for both IPv4 and IPv6 to report an error before propagating the error to the caller - now if only a single address family is used, errors are immediately sent to the caller - Fix error handling in `net.TCPConnection` for dual stack use [#1527] - while the original design focused on this use case, there was a bug - Honor `--root` - the automatic detection of root actors based on the name `main` would previously override a manually provided one - Fix time difference calculation when underflowing - Fix add / sub duration & comparison for `time.Instant` [#1545] - Fix premature conversion of input to close converter [#1553] ### Testing / CI - Now building .debs on Debian 12 / bookworm - Avoid DNS lookups in test [#1551] - We have a likely bug around DNS lookups that hits on MacOS. Work around by using "127.0.0.1" rather than "localhost" in tests. ## [0.17.0] (2023-09-25) Acton now has exceptions, how exceptional! ### Added - Add support for exceptions! [#1463] - The syntactic support for exceptions has existed for a long time but the underlying run time support was not implemented. It now is! - It used to be that exceptions would exit the whole application without any means of catching an exception. - Unhandled exceptions are now printed to stderr [#1481] - Do note however that unhandled exceptions will not exit the program nor even the actors encountering an exception. It will abort the execution of the current method and nothing else. - New `http` module [#1485] - `http.Client` is a HTTP client that supports unencrypted HTTP on port 80 and HTTPS using TLS on port 443 - `http.Listener` / `http.Server` is a HTTP server component that currently only supports unencrypted HTTP (due to lack of a `net.TLSListener`) - Supports chunked transfer-encoding [#1510] - New `logging` module [#1483] - Provides logging functionality in an actor centric world - New `argparse` module [#1499] - Command line argument parsing! - `net.TCPConnection`: A new TCP client connection actor [#1398] - Support DNS lookups so the input address can be a name rather than an IP address - It is still possible to connect using an IP address - Supports Happy Eyeballs (RFC6555) which uses both IPv4 and IPv6 simultaneously to connect using the fastest transport - Happy Eyeballs is only used for hostnames. If an IP address is provided, we connect directly to it. - `net.TLSConnection`: A new TLS client connection actor [#1470] - A simple TLS client connection actor. It supports disabling TLS certificate verification for testing purposes. - Using the MbedTLS library and tlsuv under the hood. - `net.is_ipv4(address: str) -> bool` tells you if something is an IPv4 address - `net.is_ipv6(address: str) -> bool` tells you if something is an IPv6 address - AbE: Documented capability based security [#1267] - The class name of exception errors is now printed on exception [#1423] - `actonc build --cpedantic` now works, it was previously only supported for single files [#1438] - It is now possible to have mutually recursive definitions between function defs, classes and actors [#1433] [#1435] - RTS now uses a per thread malloc implementation [#1456] - `malloc` is part of libgc which has two flavours, a global malloc with a lock and a per thread allocator - During the restructuring to use Zigs build system, the compilation option to use the per thread allocator was lost. It is now back! - For parallel workloads across multiple RTS worker threads, there is a clear bottleneck around malloc... not very surprisingly ;) - RTS readyQ and per actor message queue has been optimized [#1456] - There is now a tail pointer which significantly speeds up insertions - The fields have been slightly reorganized to allow the most important fields early so it can be fetched in one cacheline - Before, having many concurrent actors with many outstanding messages would scale poorly, on an AMD 5950X running the pairs benchmark: - before: - 1 actor pair & 1 token: ~4M continuations per second - 10 actor pair & 1 token: ~650K continuations per second - 1000 actor pair & 1 token: ~280K continuations per second - 1000 actor pair & 500 token: ~280K continuations per second - after readyQ tail optimization: - 1 actor pair & 1 token: ~3.8M continuations per second - 1000 actor pair & 1 token: ~3.6M continuations per second - 1000 actor pair & 500 token: ~700K continuations per second - after msg queue tail optimization: - 1 actor pair & 1 token: ~3.8M continuations per second - 1000 actor pair & 1 token: ~3.6M continuations per second - 1000 actor pair & 500 token: ~3.6M continuations per second - This is an artificial benchmark where there is extremely little real work done, so continuation switching becomes the dominant load. Thus, the bottleneck becomes the global readyQ. Using more than 1 worker thread only leads to lock contention and so the benchmarks are for 1 worker thread. - Since the actor message queue is per actor, it is possible that multiple worker threads could work faster but in practice they step on each others toes enough around the global readyQ that it is slower overall. ### Changed - `net.TCPIPConnection` is removed and replaced by `net.TCPConnection` - Originally opted to add `net.TCPConnection` now and phase out `net.TCPIPConnection` later but as there is already a breaking change with the change of Auth -> Cap so all user code related to networking (and other things) need to be changed, we might as well change from `net.TCPIPConnection` to `net.TCPConnection` - `DNS` actor is replaced with lookup functions [#1406] - The `DNS` actor is removed, the `lookup_a` & `lookup_aaaa` methods it has are now free functions in the `net` module, i.e. simply call `net.lookup_a` - It was originally an actonc shortcoming that lead to the design with a `DNS` actor - it was intentional, so this is more of a cleanup - Renamed authentication concept to "capabilities" [#1402] [#1407] - In order to better reflect the mental model and intuition we want to instill in users of Acton, Auth objects are renamed to Cap - With a reference to a capability, we can use that capability. This aligns with the existing security model for the internal actor domain where an actor must hold a reference to another actor in order to call its method. - We want to extend that mental model for all external things in the world as well. - All `*Auth` objects now have a `Cap` suffix - All `auth` args are renamed to `cap` - `SysCap` is a new capability for functions related to Acton RTS System internals [#1388] - `SysCap` is available from `env.syscap` - `SysCap` is separate from the normal capability hierarchy where `WorldCap` is the root - This is to promote the aspiration to restrict access to RTS internal - While `WorldCap` shouldn't be passed around frivolously either, capabilities should restricted and delegated, it is still fairly normal to pass `WorldCap` while the vast majority of programs should not even need `SysCap` - The `msg` of exceptions is now optional [#1422] ### Fixed - Fix control flow bug for `continue` in `for` loop [#1265] - Fix control flow bug for `return` in `while loop` [#1194] - Fix comparison of optional types [#1186] [#1506] - Fix necessary casts for bool checks on tuple field [#1500] [#1504] - Throw exceptions for unimplemented builtins [#1010] - Previously printed to stderr and did `exit(1)` - Now throws a `NotImplemetedError` instead! - Failed dict key lookups now throw `KeyError` [#1499] - Previously incorrectly raised `IndexError` - Document use of `--sigs` in Acton-by-Example [#1405] - Fix up-to-date check for stub compilation [#1399] - Improve support for alternate output in actonc [#1395] - When alternate output is enabled, like `actonc --types`, now uses quiet mode, thus suppressing various progress messages which interferred with the alternate output - Avoid errors when compiling files without a root actor - Clean up old generated output files [#1411] - When the source files is moved or removed, also remove the corresponding output files - Fix return value of int hashable [#1415] - Fix module import check [#1420] - Avoid segfault when exception `error_message` is not set [#1422] - Bump Zig version to v0.11.0 [#1421] - Fix `reversed([])` which would `SIGILL` in dev mode [#1455] - Fix `reversed([1,2,3])` which now returns reversed result [#1455] - Previous code did the reversal but returned the original value :P - Fix `i64` comparisons like eq/ne/etc [#1459] - Would just return the wrong results, like `i64(0) == i64(0)` would not return `True`. Now works as they should! - Fix list add with empty list input, like `[1]+[]` [#1461] - Used to segfault, now works as intended ### Testing / CI - Stop testing on Ubuntu 22.10 since it is End of Support ## [0.16.0] (2023-07-03) Primarily addition of simplified TCP reconnection, related fixes and functionality. ### Added - Add `.close()` and `.reconnect()` on TCP client actor [#1383] - It is now possible to explicitly close or reconnect a TCP client - Add RTS Monitor actor in `acton.rts.Monitor()` [#1383] - The RTS Monitor actor starts a worker monitor per worker thread, each pinned to a particular worker thread. By doing so, it can retrieve information from each worker thread in safe manner, honoring the RTS design. - Currently just supporting getting handles from I/O subsystem. - Add `env.nr_threads` [#1383] - Add `set_actor_affinity(wthread_id)` [#1383] ### Changed - Include DNS query hostname in `on_error` cb [#1382] - Simplifies retrying a query since we otherwise do not have a persistent tracking object per query ### Fixed - Fix `--rts-debug` [#1383] - Has been broken since new builder but is now fixed - Fix off-by-one in worker thread wake up [#1383] - Waking all threads would not consider all threads as there was an off-by-one error. - No known problems in the field from this, it was only noticed in development using --rts-wthreads=1 - The RTS uses at least 4 workers per default - Use relative source file path in logs [#1383] [#1391] - `__FILE__`, set by the C compiler, is used to include source file path in log messages - Zig uses absolute paths to all files - now using `-ffile-prefix-map` to make path relative - project dir name also included, for example `base/rts/rts.c`, to make it easier to understand from which project a file comes from - Assignment in multiple branches [#1390] [#1392] - Only assigning in multiple branches (not before branches) would lead to redefining shadowing variable of outer scope in low level generated C code - Info guiding joined assignment has been fixed ### Testing / CI - Verify we cannot instantiate WorldAuth ## [0.15.3] (2023-06-27) ### Added - `actonc --cache CACHEDIR` can be used to specify the build cache directory ### Fixed - static compilation with Musl libc is now possible on Linux [#1372] - adjusted to adjtimex - hashing for `int` now supports values outside of `i64` [#1348] [#1367] - fix `__pow__` to avoid compiler optimization bug [#1371] - bump Zig version [#1374] - avoids "File not Found" error - text color in SVG in docs now follow font color [#1365] - fix hooking of thread creation to inject signal handler wrapper for stop the world [#812] - corrected arguments passed to `on_error` callback of `net.DNS` related lookup functions [#812] - .act file specified 2 arguments to the `on_error` callback while the .ext.c file only sent a single argument ### Testing / CI - cross-compilation is now tested in CI in all jobs for these targets: - `aarch64-macos-none` - `x86_64-macos-none` - `x86_64-linux-gnu.2.27` - `x86_64-linux-musl` - CI uses `--cache` to place build cache in `~/.cache/acton/test-build-cache`, which is in turn cached in CI - the cross-compilation testing meant testing went from ~1 minute to ~3, with caching it remains at around ~1 minute ## [0.15.2] (2023-06-16) Elevate Acton's build capabilities by completing the adoption of the Zig build system. Everything, including external library dependencies, builtins, RTS, stdlib and backend, is now built using build.zig files. A hierarchy of zig modules are formed, which allow building the entirety of the Acton system with a single zig build, which is what actonc calls internally. This enables complete control over all aspects of the low level compilation. The most striking feature unlocked is likely cross-compilation: $ actonc --quiet helloworld.act $ file helloworld helloworld: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.0.0, with debug_info, not stripped $ actonc --quiet helloworld.act --target x86_64-macos-none $ file helloworld helloworld: Mach-O 64-bit x86_64 executable, flags: Libraries for the local platform are still prebuilt and included in the Acton distribution, hich are used when using the default target, i.e. targetting the local machine. For any customization to the target, everything will be built from source. ### Fixed - revamped low level build, now potentially rebuilding entire Acton system from source code - allows cross-compilation and similar advanced features - use `--target` for cross-compilation, e.g. `--target aarch64-macos-none` to target an Apple M1 computer - for Acton projects, there is now a `build-cache` directory that caches all built output and speeds things up tremendously - `json` module now correctly encodes and decodes floats [#1345] [#1349] - zig build of all external library dependencies - gives us much better control over how libraries are compiled - much much faster! autoconfig is really slow! - e.g. building protobuf-c takes a few seconds on a 2015 MBP while with autoconf, it spends > 1 minute trying to figure out capabilities of the C++ compiler, despite the C++ parts of libprotobuf-c not being enabled! - the debian test job now often build Acton in less than 3 minutes, macos-13 often run in ~4 minutes - a real improvement! - libargp [#1336] - libbsdnt [#1337] - libgc [#1344] - libnetstring [#1325] - libpcre2 [#1331] - libprotobuf-c [#1341] - libutf8proc [#1332] - libuuid [#1340] - libuv [#1334] - libxml2 [#1333] - libyyjson [#1323] - remove libbsd & libmd as dependency [#1329] - only use was of arc4random in numpy, which is now rand using() - backend is now built using zig [#1346] - use curl instead of git clone to fetch dependencies [#1343] - much faster and reduced disk usage ### Testing / CI - caching has been vastly improved in CI - based on the new zig build system, we utilize zigs excellent caching capability by using a single zig cache for the entire build of Acton. In CI, we cache the zig-cache directory, so we don't actually have to recompile files at all. Some CI runs now take less than 2 minutes to build Acton! - we should be able to trust Zigs caching to do the right thing, if files are modified it will notice! - testing of the Homebrew Formula has been removed [#1338] - since some time, this test job has been intermittently failing, or rather only intermittently passing as most of the time it fails - to avoid lots of errors in CI, the job has been removed - the failures are likely coming from some change in brew behavior - we use a fairly hacked up and not supported workflow - several attempts to fix it have been unsuccessful and we're unable to spend more time on it right not - removed test of compiling Acton on Ubuntu 20.04 due to problems with stack - note how executables built by actonc are still compatible with Ubuntu 20.04 ## [0.15.1] (2023-06-02) A better strategy for constraint solver results in vastly lower constraint solving times and thus reduced overall compilation times. Large improvements in code generation resulting in less memory allocations and thus a much lower load on the GC, yielding much better runtime performance. The internal compilation of generation C code has been revamped, now more structured and simplified in many ways, internally making use of the Zig build system which in turn unleashes a lot of benefits. ### Changed - release builds now use `-O3` and dev builds use `-Og` [#1270] - Collection overloading has been removed [#1316] - It was previously possible to overload collections like dict / Mapping - {} now always means the builtin dict ### Fixed - Faster constraint solver through new strategy [#1316] - Evaluates vastly fewer possibilities - One application used to take over 10 mins for constraint solving which now runs in roughly 10 seconds - woohoo - New second stage compilation of generated C code [#1249] [#1304] - new `builder` performs "second stage" compilation of the C code that `actonc` generates into object files, archives and executable binaries - Built on Zig's Build System, gaining all that it offers - Very good caching, dependency detection, up-to-date checking and concurrency - Custom compilation to make `builder` itself portable - Compilation can now be more clearly separated in two steps: - step 1: `actonc` compiles `.act` to `.c` & `.h` - step 2: `builder` compiles `.c` & `.h` to `.o` & `.a` & executables - Up-to-date checking in actonc adjusted to only compare `.act` with `.c` & `.h` output - `builder` does a fantastic job of following dependencies (looking at `#include` statements etc) to figure out when things need to be recompiled - All of this is internal, `actonc` calls `builder` under the hood, much like it earlier called `cc` under the hood - `--no-zigbuild` can be used to force old compilation method - `--no-zigbuild` will be removed in the future - Much faster build of Acton itself using prebuilt libActonDeps [#1279] [#1282] - Uses a checksum of git refs of all lib that constitutes libActonDeps - If any dep lib is updated to use new version, libActonDeps will be rebuilt - Uploaded to github.com/actonlang/libactondeps and downloaded on demand from normal Makefile, thus used for local builds and in CI - Falls back to local compilation if prebuilt version is not available - builtins, RTS & stlib now organized as an Acton project called `base` [#1309] - More streamlined towards imagined design of how project dependencies will work in the future, meaning less special kludges - Cleans up include paths and similar, avoiding potential naming conflicts - builtin code is now generated [#1256] [#1260] - `__builtin__.c` and `__builtin__.h` are now generated from `__builtin__.ty` at build time, whereas they were earlier checked in to git, having once been generated but heavily modified by hand - given complexity of these files, it is difficult to keep the files up to date when there are changes to the `CodeGen` pass in `actonc` - `actonc` CodeGen pass is now infused with some of the bespoke customizations done for builtins, other customizations have been removed to streamline the whole thing or inserted into .ext.c file to use the "standard way of customization" (what an oxymoron) - Better performance through code generation improvements [#1263] [#1274] - Code generation has been improved, primarily to avoid unnecessary allocations, thus reducing pressure on GC, leading to improved performance - One application that ran in > 12 minutes now run in < 2 minutes - `xml` module now correctly parses default namespace [#1262] - address `xml` bugs with more null checks [#126] - Switched to a nightly version of zig [#1264] - pre-release version of zig v0.11 - we still pin to this particular zig version which goes through the Acton CI testing so there is relatively low risk of this silently breaking something - Document `after` and encourage not using `sleep` [#1269] - `actonc` now transparently passes through zig output [#1277] - treats subprocess output as bytestring instead of trying to decode it - we only pass it through anyway, there is no analysis done on it - avoids errors seen when not using UTF-8 locale, like when `LANG` is unset (effectively defaulting to `C`) - Remove bunch of old code, irrelevant tests, old gen env scripts ect [#1278] - `math` module switched from stub style to .ext.c style [#1309] - Add missing MacOS headers [#1309] - Remove note on segfault in AbE that's no longer valid [#1303] ### Testing / CI - Added macos-13 as test target in CI [#1258] - New CI job to build libactondeps and upload to "cache" repository [#1283] [#1284] - Also using cached for CI builds (as well as local) - MacOS CI builds 12 -> 6 minutes, Linux ~8 -> 4 minutes - brew-macos is still slow, but we get quicker feedback of failures looking at test-macos & test-linux jobs - Fixed Homebrew build by applying workaround - Broke due to upstream changes and is still broken with default suggested config in `brew new-tap` ## [0.15.0] (2023-04-26) ### Added - `actonc` is now statically linked in the Acton APT repo packages [#1148] - enables development using Acton on Ubuntu 18.04, Debian 10 and distributions of similar age - static linking only works when the build platform is a slightly older Linux, it works on Debian 11 which we are using, while on a newer Debian (testing as of December 2022) the compilation fails - our static compilation is conditioned on `STATIC_ACTONC=true`, which is set in our `build-debs` CI job which builds the .deb packages used in the Acton APT repo - local compilation still defaults to a dynamically linked `actonc` - Parallel GC marking, speeding up mark phase significantly on computers with many cores [#] - Up to 16 parallel threads are used for marking - Add `sorted()` function [#1211] - Uses timsort, which is the same sorting algorithm used by Python and Java's Arrays.sort() - Add `re` module for regular expression matching [#1208] - Offers `match()` function to match on text, - Unanchored pattern matching, unlike the Python equivalent which is anchored at the start per default (seems highly unintuitive) - Completely revamped `time` module [#1188] - The high level interface is now oriented based on the two common usage patterns of measuring elapsed time or telling the current date and time. - `Stopwatch` measure elapsed time - `time.now()` now returns a DateTime object, which is a higher level object - New fixed width integers: i16, i32, i64, u16, u32, u64 [#1202] [#1202] [#1203] - Backend queue subscriptions now done in bulk [#1127] - An actor mailbox is mapped to a queue in the backend - For every actor creation, the RTS would create and subscribe to the corresponding queue. - There's a new interface for queue subscriptions where individual queues are grouped together into queue groups, so the RTS only needs to subscribe to a group once - New acton projects are now git initialized [#1185] - Using `actonc new foo` to create a new Acton project, we now check if git is available and if so, initialize the repository. Also include a `.gitignore` - Allow overriding number of worker threads [#1199] - It's been possible to set but we always used a minimum of 4, so even setting threads to 2 you would end up with 4. It can be really useful for debugging to run on a single WT, so honoring this is useful. - Add list methods `clear`, `extend` & `pop` [#1206] - New `--rts-no-bt` option to disable automatic backtrace printing [#1226] - Automatic backtrace printing is nice for the normal case where one might run a program and do not have core dumps enabled - However, when doing actual debugging, one usually enables core dumps and analysis it using a debugger interactively, in which case it's only annoying to get a couple of screenfuls of backtrace in the terminal on every iteration - Laid foundation for exception handling [#1228] - Handles exceptions for CPS converted code - Proc style functions do not currently handle exceptions properly - Not fully enabled just yet, as it requires some more work - `int` literals between 0 and 256 are now statically allocated [#1235] - Python uses the same trick for -5 to 255 for speedup for commonly used integers - Acton literal negative integers are really not negative integers but an expression of "minus" and the integer 5 so we cannot currently do the same trick for common negative values, like -1 etc - lists can now shrink to reduce memory usage [#1237] - When list length goes below half, the list will be reallocated and copied over to a new memory area ### Changed - bash completion for `actonc` now completes `.act` files [#1246] - `TCPIPListener` interface has changed for callback registration [#1181] - The `on_receive` and `on_error` handler for individual client connections (`TCPListenConnection`) are now registered after instantiation of each `TCPListenConnection` actor by calling `cb_install()`. - This is most appropriately done in the on_accept callback. - Unlike the old pattern, where we provided these callbacks up front to the `TCPIPListener` actor, having them registered per client connection naturally opens up to having different handlers per client. ### Fixed - Fix `@property` handling & inference [#1207] - Fix bug in dict `__eq__`, so equality check now works [#1144] - `min()` & `max()` now work as they should [#1150] - `isinstance` now works correctly [#1124] - Fix compilation with return in nested branches [#1162] - Signal interrupts are now properly handled in acton.rts.sleep() [#1172] - Previously, a signal would interrupt the sleep and it would simply not sleep long enough. Now, if interrupted, the sleep is called with the remaining time until the full duration has passed. - Fix worker thread indexes in WTS rtsmon interface [#1176] - `bool([])` now correctly returns False [#1193] - Correct `hex`, `bin` and `ascii` functions [#1196] - `actonc docs --signs` now works [#1197] - Correct pid is now reported in rtsmon [#1177] - Atomic mallocs are now used where possible to speed up GC [#1225] - The GC does not need to scan the value of a `str` or `bytearray`, so they are now atomically allocated which means the GC will skip scanning them - Document more list operations [#1136] - Explain named tuples [#1192] - Improved some parser errors [#1198] - Now using zig v0.10.1 [#1174] - Update to LTS 18.28 [#1141] - Internal name mangling has been changed [#1160] - builtins has been reorganized [#1169] - New `make clean-all` target to clean move stuff [#1210] ### Testing / CI - Add Ubuntu 18.04 as test platform in CI [#1149] - It's not possible to build Acton on Ubuntu 18.04 - As actonc is now statically built, the version built on Debian now also runs on Ubuntu 18.04! - Test all available operations on lists [#1137] - Test all available operations on dicts [#1140] - Concurrent builds disabled on MacOS due to intermittent failures [#1145] - web page rebuild now triggered on changes to docs/acton-by-example [#1216] - Deb package now also gets a deterministic name [#1217] [#1219] [#1220] - Makes it much easier to install the pre-built tip packages for testing / CI etc on other repos ## [0.14.2] (2022-11-27) ### Fixed - Improve `actonc` performance [#1119] - The constraint solver can have a massive performance impact on the compilation process, in particular if it has a very large amount of solutions to evaluate. - The number of alternative solutions had too little weight during constraint sorting which would result in a very large amount of potential solutions to evaluate. An example program took 31 minutes to compile, which after the fix compiles in milliseconds. - For a 100 constraints, with the wrong strategy we might need to evaluate 5^100 solutions (heat death of universe etc) whereas if we do things correctly we can solve all constraints in perhaps 100*3 tries. Exponential is exponential. - Fixed size `i64` integer type is now instantiable [#1118] - Improved str to int conversion [#1115] - Corrected str `.split` and `.splitlines()` - Correct DB server & client comm loop select handling [#1111] - Ignores EBADF and have ensured this design is correct with regards to timing of invalid fds. - Drop explicit `gcc` dependency for Debian package [#1110] - Haskell GHC still depends on it though, so it still gets installed. - Use slightly newer bsdgc / libgc version [#1112] - Slight build simplification as we've upstreamed some modifications. ## [0.14.1] (2022-11-14) ### Added - `actonc --cc` to specify which C compiler to use to compile a module and binary executables [#1103] - Note that the Acton system is still compiled by `zig cc`. On Linux we are targeting GNU libc 2.28, which might affect compilation of individual modules or executables. ### Fixed - `float.__ge__` is now working correctly [#1105] - Removed incremental operations from integers [#1106] - Improved `int` to `str` conversion [#1107] ## [0.14.0] (2022-11-10) Acton RTS now does garbage collection! ### Added - The Acton RTS now does garbage collection [#1091] - Using libgc a.k.a the Boehm-Demers-Weiser garbage collector - The GC stops the world to perform garbage collection during which all Acton RTS worker threads are paused. It is likely this will be visible as pauses of the whole system. - Performance appears to be largely on par with and without GC but this is based on small artificial programs. - It is possible to disable the GC at run time by setting the environment variable `export GC_DONT_GC=1` before starting the Acton application - This will be removed in the future when the GC has been field proven. - Long term is to implement an Acton specific GC that can, for example, avoid stop the world events by doing collection per actor. This is quite far into the future. Until then, this will have to do! ## [0.13.1] (2022-11-10) ### Changed - Allow `_` as a dummy variable name [#1020] [#1061] - `_` can be used in an assignment to effectively throw away a result - Unlike using a variable like `dummy`, `_` acts as a wildcard from a type perspective, so that we can do `_ = 3` and `_ = "a"`, while if we attempt to use another dummy variable name we will get a type error as we try to assign it values with different types - `__self__` has been renamed to `self` [#1056] - it is a reference to the own actor and holds the "external" view, i.e. it can be passed to another actor as a reference to the local actor ### Fixed - Correct DB client comm thread to avoid potential deadlock [#1088] - Incorrect handling of error return status from select meant we could attempt to read on fds that had no data and thus the comm thread would deadlock. - Now we do proper error handling, always continuing for another spin & attempt at select in case we get an error back. - The (under development) garbage collector (GC) uses signals to instruct threads to pause for stop the world events and thus we end up interrupting the select loop a lot more frequently than before, thus surfacing this bug. - Correct DB client comm thread to avoid busy waiting [#1089] - On Linux, using `select()` with a timeout, if the select is interrupted the timeout value will be modified to reflect the time not slept. Thus the next select in our comm thread loop would sleep for a shorter period of time. Depending on the timing of the interrupt, the sleep might be shortened to effectively form a busy wait. - The (under development) garbage collector (GC) uses signals to instruct threads to pause for stop the world events and thus we end up interrupting the select loop a lot more frequently than before, thus surfacing this bug. - Fixed by always resetting the timeout value in the loop. - Make RTS DB clients stick to one partition [#1087] - Make sure RTS (a DB client) does not hop between different DB server partitions even if they learn about disjoint gossip views. - Prevents incorrect operation when DB servers are not aware of each other but are "joined" by a RTS that see all the servers. - This scenario is most easily reproduced by starting DB servers without specifying a seed, and so the DB servers won't see each other, and then let a RTS connect to the DB servers, which then sees a view of all 3 servers. - This is now rejected as invalid. - Using vector clocks to determine and reject invalid views. Very elegant =) - Correct `time.monotonic()` [#1097] - It returned a wildly incorrect results as the nanoseconds part was not properly added up with seconds. - Include argp-standalone library in libActonDeps [#1058] - No more external dependencies! - argp is available as part of the system on GNU/Linux but on MacOS we have relied on the argp-standalone package installed via brew. We now prefer to use our own on both Linux and MacOS. - Acton system is now compiled with `-Werror` to improve code quality [#1060] - There are some exceptions to this but the overall goal is to be essentially free of compilation warnings - Fix bug in truediv for `int` [#1076] - Fix bad codegen of classname argument to `isinstance()` [#1055] - Correct effect declaration to `mut` for some builtin protocols [#1053] - Method decorators like `@staticmethod` now work [#1054] - Added lost constraints inferred on target expressions [#1050] - Avoid undefined behavior in builtin object hash [#1065] - Clean up library include paths etc [#1068] [#1077] [#1080] [#1092] - Made possible by including all of our external dependencies in libActonDeps ### Testing / CI - Add back testing on Ubuntu 20.04 [#1093] - libxml2 requires a newer automake (1.16.3) than is available on Ubuntu 20.04 - We fix this by hacking the configure.ac file to require the version available on Ubuntu 20.04 (1.16.1) ## [0.13.0] (2022-11-04) New "deactorizer", which unlocks proper async / sync actor method calls. ### Added - Added new "deactorizer" pass in compiler [#374] - No real user visible change, like no change in syntax, but we now properly compile programs with regards to async / sync calling behavior of methods. - Briefly, an actor method called from the local method is called directly. This effect is called "proc". Remote actor methods are normally called asynchronously and these are called "action". If we assign the return value of an action, we are locking for a synchronous behavior which is achieved by an await. These semantics are now correctly implemented. - In particular, passing methods as arguments, a method might not know whether it is passed an action or proc and thus needs to handle this in a generic way. This is particularly tricky as we don't want to to any run time inspection of arguments and thus need to have it all figured out at compile time. - Many many many other things are fixed through the merge of the new deactorizer. There are improvements and fixes to various passes in the compiler. This has been in the works for almost a year. - Added `--auto-stub` to `actonc` [#1047] - Enables automatic detection of stub mode compilation - Extended actor argument pruning analysis to honour `NotImplemented` [#524] - Pruning analysis prunes away arguments that are not used under the lifetime of an actor, e.g. an argument only used for actor body initialization code. Pruned arguments are not persisted. - Pruning analysis does not cover C code, so when one or more methods are implemented in C and defined as `NotImplemented` in the Acton module, we cannot reliably determine what arguments are used or unused. - The safe choice is to assume all arguments are used, which is what we are now doing. - This removes a bunch of `_force_persistance` methods in stdlib. ### Changed - Default is now to not automatically detect stub mode [#1047] - Use `--auto-stub` to enable automatic stub mode detection ### Fixed - Now using zig v0.10.0, which was recently released [#1029] - Previously using a nightly build of v0.10 - Correct arithmetic operations using hexadecimal literals [#1027] - Build actondb using zig with -target [#1003] ## [0.12.0] (2022-10-27) Edvin's second birthday, only 10 minor releases behind Acton ;) ### Added - Zig is now used as the C compiler for Acton [#972] - Many parts of Acton, like the run time system, builtins and parts of the standard library are written in C - actonc compiles Acton programs into C which are then compiled into binary executables using a C compiler - zig is now used for both of these use cases - zig is bundled with Acton so that we know what version of zig we get, which is the same across Linux and MacOS - Acton programs on Linux are now backwards compatible to GNU libc v2.28 - Previously, acton programs would be built for the GNU libc version on the compiling computer, making it impossible to run on older distributions - Now compatible with for example Ubuntu 20.04 LTS & Debian 10 - This is made possible by zigs incredible cross-compilation functionality, which isn't just about targetting other OS, CPUs but also older libc versions - v2.28 appears to be the oldest version we can practically target without code changes, even earlier versions fail compilation - We could reduce backwards compatible, for example by targetting glibc 2.31, if we find things that we would like access to, i.e. don't regard glibc 2.28 compatibility as a hard promise - Added `--always-build` to actonc [#988] - Used in test suite so that we always force compilation in order to ensure valid test results - `actonc` argument parsing now done using sub-parsers, allowing greater freedom in constructing more complex commands [#976] - All external library dependencies are combined in one .a archive [#849] - Decouples library dependency in builtins, RTS & stdlib from actonc compiler arguments - All external library dependencies are now built from source [#984] - Allows us to compile them with zig, thus power to select target libc - Add `xml` module [#835] - Offers simple `encode()` and `decode()` operations - Based on libxml2 - The `int` type now supports arbitrary precision [#146] - Add some big numbers! - The previous implementation of `int` was as a signed 64 bit integer, this is now available as the `i64` type in Acton, although its use is currently quite limited. - Longer term, fixed size integers like `i64` or `u64` (for an unsigned) are available and can be chosen for high performance use cases. Developers familiar with this level of coding are likely able to make an informed choice about what integer type to choose. Using `int` for the arbitrary precision type is the safer choice which will make most users happy. - Using BSDNT library, which is a reasonably fast C implementation of arbitrary precision types and arithmetic operations. It is not as fast as MPL but has a more liberal license. ### Fixed - Fixed seed arg parsing in actondb [#900] - Avoid crash during TCP client resume - DB now using logging rather fprintf(stderr, ...) - Reduce unprovoked CPS & 'rtail' bugs [#949] - Update docs for --root & `runacton` [#950] - `file.ReadFile` can now read arbitrarily large files [#955] - RTS does proper error handling of DB interaction [#957] - This is a huge improvement!!! - The run time system now properly reads the return code from all DB query operations and acts appropriately. For example, lacking a quorum, the RTS will continuously retry an operation until quorum can be reached. - For some failures a larger chunk of operations needs to be retried, i.e. we can't just wrap up a small function in a retry loop but need a larger retry loop around a group of operations. - DB API now returns a minority status which the RTS can and does react on - Typical example is with 3 DB nodes and a commit goes through on 2, i.e. with a quorum and is thus considered a success, however the 3rd node rejected it because of a schema mismatch. The RTS can now be notified through the minority status and attempt to repair the schema. - A typical example of schema repairs necessary are for the queues, which are dynamic. Every actor gets a queue in the database, so when new actors are created, new queues also need to be created and if a particular DB server is not up when the queue is created, it will be missing and needs to be repaired later on. - We should have proper sync up between DB servers, so that they query each other and converge on the latest state. Until then, repair initiated from RTS is our way of fixing it. - Notify gossip view to clients (RTS) from agreement round leader [#951] - For example, in this scenario: - db1 is started - RTS is started & connected to db1 but unable to progress due to no quorum - db2 is connected, gossips with db1 and we now have quorum - RTS continues to be stalled as it is never notified about db2 and thus unable to reach a quorum - Avoid MacOS quarantine shenanigans that kills actonc [#971] - MacOS has some quarantine concept, so like if a file is downloaded from the Internet, it is marked as quarantine and the user is asked "Are you sure you want to run this" after which the quarantine flag, which is stored as a file system extended attribute, is cleared. - Somehow we trigger this quarantine, presumably by that we overwrite, through cp, a binary executable that macos has run and this triggers it to set the quarantine flag. The effect is that whenever we execute actonc, MacOS kills -9 it, which is obviously rather annoying. - By copying to a temporary file and then moving it in place, we avoid MacOS setting the quarantine flag. We already did this, though for other reasons, for actondb, so in a way this is a unification for the files in bin/ ### Testing / CI - Simplify and clean up RTS DB test orchestrator [#941] [#973] - Stop testing on Ubuntu 20.04 - It's not possible to compile libxml2 on a stock Ubuntu 20.04 as a newer version of automake is required than is shipped - We mainly want to uphold run time compatibility with Ubuntu 20.04, like it should be possible to run Acton applications but utilizing Ubuntu 20.04 as a development platform for Acton is not a high priority target, thus dropping it is quite fine. - Revamp Increase timeout - Avoid kill -9 on macos [#969] - MacOS quarantine functionality thinks we are doing something fishy and kill -9 our process - Worked around by doing cp & mv instead of just a cp ## [0.11.7] (2022-10-03) Many important fixes for RTS/DB and the language in general! ### Added - Bash completion is now part of the Debian packages & brew formula ### Changed - actondb now uses a default value for gossip port of RPC port +1 [#913] - The gossip protocol only propagates the RPC port & parts of the implementation has a hard-coded assumption that the gossip port has a +1 offset - In order to avoid configuration errors, the default gossip port is now RPC port + 1 and if another gossip port is explicitly configured, an error log message is emitted on startup. - While this is marked as a change, it could really be considered a fix as any other configuration of the system was invalid anyway. ### Fixed - Fixed include path for M1 - /opt/homebrew/include added to header include path [#892] - Actually fixes builds on M1! - This has "worked" because the only M2 where Acton was tested also had header files in /usr/local/include but on a fresh install it errored out. - Fix up-to-date check in compiler for imported modules from stdlib [#890] - Fix seed arg parsing in actondb that lead to "Illegal instruction" error - Fix nested dicts definitions [#869] - Now possible to directly define nested dicts - Avoid inconsistent view between RTS & DB in certain situations [#788] - If an RTS node was stopped & quickly rejoins or if a transient partition happens and the gossip round does not complete before the partition heals. - We now wait for gossip round to complete. - This ensures that local actor placement doesn't fail during such events. - Fix handling of missed timer events [#907] - Circumstances such as suspending the Acton RTS or resuming a system from the database could lead to negative timeout, i.e. sleep for less than 0 seconds. - The libuv timeout argument is an uint64 and feeding in a negative signed integer results in a value like 18446744073709550271, which roughly meant sleeping for 584 million years, i.e. effectively blocking the RTS timerQ. - It's now fixed by treating negative timeouts as 0, so we immediately wake up to handle the event, however late we might be. - Timer events now wake up WT threads after system resumption [#907] - Worker Threads (WT) are created in `NoExist` state and should transition into `Idle` once initiated, however that was missing leading to a deadlock. - This was masked as in most cases, a WT and will transition into `Working` once they've carried out some work and then back into `Idle` - `wake_wt` function, which is called to wake up a WT after a timer event is triggered, wakes up threads that are currently in `Idle` state, if they are in `NoExist`, it will do nothing. - If there is no work, such as the case after system resumption from the DB, WTs will stay in the `NoExist` state and then `wake_wt` will do nothing, so the system is blocked. - WT now properly transition into `Idle`. - Only communicate with live DB nodes from RTS DB client [#910] [#916] - When the RTS communicates with the DB nodes, we've broadcast messages to all servers we know about. If they are down, they've had their socket fd set to 0 to signal that the server is down. However, fd=0 is not invalid, it is stdin, so we ended up sending data to stdin creating lots of garbage output on the terminal. - fd -1 is used to signal an invalid fd, which prevents similar mistakes. - The DB node status is inspected and messages are only sent to live servers. - Avoid segfault on resuming TCP listener & TCP listener connection [#922] - Invalidate fds on actor resumption [#917] - Remove remaining ending new lines from RTS log messages [#926] - Remove ending new lines from DB log messages [#932] ### Testing / CI - Rewritten RTS / DB tests [#925] [#929] - More robust event handling, directly reacting when something happens, for example if a DB server segfaults or we see unexpected output we can abort the test - Now has much better combined output of DB & app output for simple correlation during failures - Test orchestrator now written in Acton (previously Python), at least async IO callback style is better supported to directly react to events... ## [0.11.6] (2022-09-20) ### Fixed - Homebrew Formula now includes util-linux for Linux - required for ## [0.11.5] (2022-09-20) ### Fixed - Homebrew Formula test [#882] - Homebrew Formula now pins GHC dependency to version 8.10 [#885] - This is aligned with the stack resolver version we're currently using - actondb is now statically linked with protobuf-c [#887] - Found in brew linkage testing, which should now pass ## [0.11.4] (2022-09-19) ### Testing / CI - Minor correction to Homebrew release automation - This is silly... ## [0.11.3] (2022-09-19) ### Testing / CI - Minor correction to Homebrew release automation ## [0.11.2] (2022-09-19) There are additions but they're so minor you get 'em for free in a patch release! ;) ### Added - Add runacton wrapper to run .act files using shebang [#238] - Write an Acton program in a .act file and add shebang line at top: - `#!/usr/bin/env runacton` - ... and then run the .act file. It will be seamlessly compiled and executed! Magic *whosh* ### Testing / CI - Homebrew Formula moved to actonlang/acton repo [#868] - Building a brew bottle is now part of regular CI testing - Ensures that our Homebrew Formula is correct with regards to dependencies etc, which has previously been a long standing issue - mirrored to actonlang/homebrew-acton when we release - Retry DB test jobs [#853] - No longer have to manually re-run CI jobs on failures - Retry just the DB test itself, which takes a few seconds instead of rerunning entire CI job which takes minutes - New automatic release process - Removes adding git tag as manual step - Now push branch `release-vX.Y.Z` updating `common.mk` & version in `CHANGELOG.md`, once this PR is merged, a new workflow adds the git tag which in turn triggers the release build ## [0.11.1] (2022-09-14) ### Testing / CI - Fix APT repo job ## [0.11.0] (2022-09-14) ### Added - Apple M1 / M2 CPUs are now supported [#823] - aarch64 calling conventions are different for variadic vs fixed functions and this is a problem when we alias a fixed function as a variadic function, which is exactly what we did in a number of places in the stdlib where we manually write C code - Now fixed by calling $function2, $function3 etc for 2 vs 3 args - `actonc new foobar` will create a new project called foobar according to the standard project directory layout - Completely rewritten IO system & RTS workers [#698] - libuv is now used for all IO operations instead of our own home grown IO subsystem. - Rather than a single thread dedicated to IO, all RTS worker threads now also perform IO work. IO actors are pinned to a particular worker thread on initialization. - New `net` module [#733] - replaces `env.connect()` & `env.listen()` - adds DNS lookup functions - New `process` module [#752] [#796] [#797] [#798] [#799] [#800] [#801] [#804] [#808] - runs sub-processes - New `file` module which allows reading and writing files [#806] - Replaces `env.openR` & `env.openW` - New `json` module to encode and decode Acton data to JSON document (strings) [#829] - built on yyjson C library, which is a very fast (3.5GB/s) JSON library - Do token based authentication - Capability based authentication has previously been based around access to the env actor, which was initially fed into the system as an argument to the root actor - We wanted to modularize the code of the env actor and so instead we've opted to use a token based authentication scheme - A WorldAuth token is passed to the root actor, accessible as `env.auth` - Tokens are organized in a hierarchy, e.g. - WorldAuth > NetAuth > TCPAuth > TCPConnectAuth - Performing actions always require most specific auth token - This is to encourage users NOT to pass around the WorldAuth token but make it more specific - For example creating `net.TCPIPConnection` requires a `TCPConnectAuth` token - actonc now outputs some information about what it is doing per default [#840] - Previous quieter output can be achieved with `--quiet` - `--timing` includes extra timing information on how long compiler passes and other operations take - all `--verbose` output now under `--debug` - actonc now takes a lock on a project when compiling, which ensures that two invokations of actonc to build the same project do not step on each others toes [#760] - lock is implemented using flock(), so even if actonc dies and lock file stays in place, it is not considered locked (flock only keeps lock while process that acquired lock is running) - Our own stdlib is built concurrently with development and release profile, which can now be run "concurrently", i.e. we do not have to ensure serialization of these two builds from the Makefile and since all other targets are run concurrenctly this simplifies the Makefile quite a bit, however since there is a lock there won't be an actual concurrent build - actonc now automatically sets the root actor to `main`, if a program contains such an actor. This means `--root` argument is mostly superfluous now [#726] - actonc --root argument now takes a qualified name, like . [#628] - this is required to build an executable in a project with: `actonc build --root test.main` - RTS has improved logging, including timestamps, log levels etc. Also supports file output [#584] - Log output is sent to stderr - RTS worker thread id is included so it is now easier to follow what a particular thread is doing. - stderr output has millisecond time resolution - file output (--rts-log-path) has nanosecond precision - Using pretty, short relative paths - ActonDB has improved logging, including timestamps, log levels etc and supports file output [#588] - supports logging to file with --log-file - similar implementation as RTS (based on same log.c library but modified) - actonc automatically detects stub mode compilation based on presence of .c file [#601] [#624] - actonc supports new .ext.c style definition of C functions where individual functions in an .act file can be externally defined in the .ext.c file by using `NotImplemented` as the function body [#706] - actonc is now aware of development / release profile [#599] [#612] - output placed in correct location, i.e. out/rel or out/dev - actonc now supports custom compilation of modules via Makefile [#602] - if a module is to be stub compiled (i.e. there is a .act file with a corresponding .c file) then if there is also a Makefile in the project root, actonc will run make for the corresponding target, e.g. `make out/rel/foo.o` - actonc now has concept of commands [#608] - like `actonc build` which will build an Acton project - stdlib is now compiled from actonc as a Acton project [#599] - `__builtin__.act` has been moved from stdlib to `builtin/ty`, which is also an Acton project [#623] - `__builtin__.act` really is special, like it's an implicit dependency for everything else, and trying to add extra logic to get it to build first when building the stdlib project doesn't make sense; it's now special rules in the Acton Makefile - Improve DB schema creation messages [#586] - Messages contained "test", which is misleading. The DB server creates the schemas, i.e. the schema is hard-coded. This is per design and a simplification (no need for schema management RPCs) as the DB and RTS are tightly coupled anyway. - ActonDB will now gossip RTS node membership, forming the foundation for doing distributed computing - ActonDB monitor membership information now contains all nodes [#645] - RTS mon now has a membership view [#645] - `bytes` type added [#655] - Library dependencies are now included in the Acton distribution [#698] - Added `__repr__` method to class value & subclasses [#685] - Added Ord instances for lists & dicts [#719] ### Changed - `after` now takes a float argument [#846] - Allows sub-second delays - IO subsystem has been replaced with libuv - `env.connect()`, `env.listen()` has been replaced with `net` module, i.e. `net.TCPIPConnection` and `net.TCPListener` - file access via `env` has been replaced with the `file` module - RTS log output is now sent to stderr rather than stdout - `actonc dump foo.ty` now takes the filename of the `.ty` file to dump as a positional argument rather than the old way of using an option (`actonc dump --file foo.ty`) ### Fixed - Avoid segfault in actondb due to uninitialized mon fds [#627] [#633] - Exceptions during build of executables no longer deletes produced .ty files [#629] - Fixed DB server & client issues leading to segfaults [#559] - Pass skiplist keys by reference - Fix duplicate nonces in msg_callbacks skiplist - Extend lock protection over msg_callbacks - DB client no longer asserts & exits on perror [#574] - Now handles more errors rather than bailing out - Properly initialize fd_data entries [#571] - Sometimes a slot wasn't properly initialized, which would lead to incorrect behavior - RTS now cleans up and closes fd on EOF [#570] - RTS fd array is now 1024 slots long [#570] - Used to be 100, which means we can address up to 100 fds. Default fd limit on most Linuxes is 1024, so we align on that. The proper fix is to have a dynamic structure for fd or set it to the same value as the limit (but that's bad for large values). - RTS uses sigaction instead of signal, which should tighten up some edge cases [#587] - Do not print log message on new connection in RTS / env [#607] - Correct Debian package dependencies [#625] - We used the wrong dependencies, shared libraries, when we should have the development libraries available, since we are not a "normal" application but a compiler, so when we in turn build programs we want to link them as statically as possible (sort of, not including libc but most other things) - Now installing the .deb file will pull in all the correct dependencies on Debian 11 / bullseye and Ubuntu 20.04 - Correct handling of plain and raw bytes / string literals [#655] [#657] - UTF-8 encoding is now enforced for source files - All library dependencies are now included in the Acton [#693] - For example libuv, libutf8proc, libbsd (on Linux) - No longer partially linking some modules like math & numpy - We used to partially link in e.g. libbsd into math - numpy imports math so importing both math and numpy means we got duplicate symbols - This was likely a faulty design in the first place as it lead to symbol collisions - Now all library dependencies are part of the Acton distribution and are linked in with the final application at actonc build time - Files are stored as e.g. dist/lib/libuv_a.a. The _a suffix is to ensure we get the statically compiled library and do not link with a shared .so library if one happens to be present on the system. - C lib guide rewritten for new .ext.c style [#766][#766] - Custom make file invocations are now more idempotent [#845] - Avoid copying .h files which forces make to rebuild targets ### Testing / CI - Tasty (Haskell test library & runner) is now used for testing actonc. Most tests have been migrated from test/Makefile to compiler/test.hs [#631] - Tasty offers different style testing; unit, golden, property etc, with flexible runners that can execute tests in paralell. Has nice, compact and colorized output in the terminal and can output to richer formats as well as run benchmarking tests. - There are now timeouts for all tests run by Tasty - TCP servers stress test for opening & closing fds in RTS [#570] - actonc build of projects have some test cases [#623] [#625] - Now testing on MacOS 12 [#527] - Stopped testing on MacOS 10 [] - Now testing on Ubuntu 20.04, 22.04 & 22.10 [#700] - New test jobs for running actonc and its output on a clean machine [#] - This installs acton from a .deb file on Linux and from artifact .zip file on Mac - Ensure that we have all dependencies declared correctly and that we ship all necessary files - Running on same platforms as normal test, i.e.: - MacOS 11 & 12 - Debian 11 - Ubuntu 20.04, 22.04 & 22.10 ## [0.10.0] (2022-02-25) ### Added - actors now have a `__resume__` function that is called by the RTS just after actors have been deserialized from the database [#517] - This is effectively a generic hook point that can be used by certain actor implementations to run code when being resumed from the database - ListenSocket supports resumption [#529] - We cannot restore the previous state of a listening socket since that fd and all its associated resources in the kernel etc are gone. - The next best thing we can do is tell the application, through the error callback, that there is an error with the listen socket and it is then up to the application to retry, effectively attempting to listen again - Connection now supports resumption [#546] - Similar to ListenSocket, so that upon resumption we invoke the registered error handler so that the application can reconnect - Unlike ListenSocket, the error callback must first be registered through `on_receive` on the `Connection` - What's neat is that any application that attempts to handle reconnects will also automatically have code for dealing with Acton based actor migration and recovery!!! - `actonc` now takes `--tempdir` option to write intermediate output (generated C) to instead of randomly generated directory, which also means the specified directory is kept and not deleted on exit [#516] - in the generated directory, there is a `build.sh` file that contains the same commands that `actonc` would use to produce the final binary output from the source files ### Changed - `on_receipt` is now called `on_receive` on `Connection` [#522] - `on_connection` is now called `on_connect` on `env.listen` [#535] - The error callbacks of Connection & ListenSocket now receive the Connection or ListenSocket as an argument so that it is easy to identify which instance the error pertains too [#547] - The main program thread is no longer named `main` [#528] - The thread name is reported in various tools like top and ps or when there is no thread name, the process name is used - The process name is more unique than the main thread name (always "main"), so we prefer to use the process name ### Fixed - Initialize `pthread_getspecific` to `NULL` value [#529] - Avoids segfault, in particular on MacOS - `on_connect` callback is now always handed a connection argument [#538] - Every since we split out the error handler this was really the case but the function signature indicated that it was maybe a Connection and so all application code had to be written defensively, checking if the argument was None - It will never be None and the signature now matches that so application code can be written more cleanly - Fix TCP client connection on Linux with epoll [#542] - Ever since we started supporting epoll natively on Linux, rather than the libkqueue shim layer, we have had this regression where TCP client connections do not work - We registered the same fd with different filters in epoll which resulted in an error. It's now fixed by first clearing older flags before re-registering the fd. - ActonDB and DDB libraries are now compiled with debug flags [#529] - Unlike other parts of RTS that are compiled with debug flags when `actonc --dev` is used, we don't have the same possibility of conditional compilation here, so meanwhile the DDB things will now always include debug flags ### Testing / CI - Correct DB test so that the return value is actually inspected [#518] - Generated files now come with newline [#521] - Work around current issues with serialization of uninitialized values [#518] - Remove old RTS DDB test [#530] ## [0.9.1] (2022-02-17) ### Fixed - Fix ActonDB monitor interface initialization [#514] - God knows how this ever worked, but it mostly did on Linux. Mac OS X really exposed the errors together with the RTS not halting on DDB errors, which we should address through [#431] - Serialize all manually constructed actors [#512] - A new convenience function makes it easier to serialize all manually constructed actors to the DB and it is used in various places so that all currently known actors are serialized - The better fix for most of these actors is probably to have CPS converted init functions instead but that's some more code to write which is cumbersome for manually defined actors ## [0.9.0] (2022-02-15) ### Added - Add DB client library statistics [#473] - We keep count, sum of time and timing buckets per operation type - `actonmon` exposes these metrics over the prometheus HTTP endpoint - RTS mon interface now uses netstrings as line encoding [#494] - Much more robust than the previous implementation which relied on luck - netstrings are very simple and can be implemented in a few lines of C or Python, so we are still considerably simpler than protobuf or similar - Add mon interface to ActonDB [#499] - We only expose membership information - Gives us a nice programmatic interface to query the DB for membership info, so we can determine whether our DB cluster has converged or not - Acton RTS now handles `SIGINT` and `SIGTERM` [#509] - RTS will gracefully shutdown upon receiving either `SIGINT` or `SIGTERM` - If a second `SIGINT` or `SIGTERM` is received while the RTS is gracefully shutting down, it will instead exit immediately - Add `ListenSocket` actor [#506] - `env.listen()` now returns a `ListenSocket`, previously it did not return anything, which meant that we never got a "handle" on the socket itself so we couldn't for example stop listening on a port. - Also means we have a more natural place to add logic for what should happen on actor resumption. ### Changed - `env.listen()` now takes a on_error callback function [#504] - Previously the on_connect callback would be invoked with a `None` argument on error, which meant it wasn't really an "on connect" handler - Now we get separate callbacks so each can be implemented much cleaner - Enough DDB servers must be specified for configured replication factor [#474] - With a replication factor of 3, `--rts-ddb-host` must be specified at least 3 times to point to 3 DB servers - A previous short term fix [#427] assumed all DDB servers were running on the same host, typically localhost for testing - We now let the user figure it out instead, allowing true multi-node operation - Long term fix is still to properly implement gossip protocol ### Fixed - Fix segfault caused by misaligned uuid.h / libuuid on MacOS [#488] - used `uuid.h` from system and uuid lib from util-linux package - Fix actor instantiation in env.c [#481] - We failed to create the DB queue on actor instantiation which would lead to errors on later enqueues [#472] - [#186] changed the way actors are initiated and code generated by actonc uses the new correct way whereas the builtin actors like Env, Connection etc defined in `env.c` are manually implemented and still used to old way - All actors in `env.c` now use the new correct way! - Fix epoll detection of disconnect [#469] - In addition to listening for `EPOLLHUP` we must detect `EPOLLRDHUP` - Do not rewrite argv for `--rts-ddb-host` option arguments [#476] - Fix `--opt=arg` style parsing of argument [#479] - Argument value was `t=arg` rather than `arg` due to misplaced parentheses - Do single line logging [#475] - Previously had tasks where first a partial log line would be printed, to be completed when the task finished. This looks nice in an interactive terminal but if anything else logs meanwhile, the output becomes garbled. - Cleaned up bootstrap removing `ancestor0` [#481] - Speed up RTS startup when using the database [#493] - A `select()` timeout meant we would always pause for 3 seconds - We now avoid the timeout entirely by having a "wakeup pipe" that we can prod to wake up the comms thread in the RTS - For small programs, like most of our tests, we can now startup 3 DB nodes and run the program in 30ms or so whereas previously it would take just over 3 seconds. 100x improvement! ### Testing / CI - CI jobs now depend on all "previous jobs" which prevents inconsistencies [#478] - There are jobs, like the update-apt-repo job, which depend on previously jobs, like test-linux. - While the test job for Linux could succeed and thus allow the update-apt-repo job to proceed, text-macos could fail, meaning the overall pipeline status is failed, yet enough has passed to now run the update-apt-repo job. Uploading a new version there but not a similar one for Mac OS X causes inconsistencies. - DB test script (`test_db.py`) now uses Python unittest style rather than homegrown functions [#501] - Makes it easier and more robust to handle setUp & tearDown - Ensure app is killed during tearDown as to ensure cleanup [#502] - The test for RTS with DB now has a new test where the test app uses TCP for control and exposing information which should make it much faster and more robust than relying on stdout parsing. - However, it does not currently support testing DB resumption / recovery as our TCP listen sockets do not support resumption ## [0.8.0] (2022-01-14) ### Added - New RTS mon logging option [#464] - This new option makes it possible to write the RTS monitor statistics to a log file specified with `--rts-mon-log-path` - The first stats snapshot is taken just at startup of the application after which subsequent stats snapshots are taken at the specified periodicity. A snapshot is always taken just before shutdown. - The periodicity is specified by `--rts-mon-log-period` in units of seconds and the default value is 30 - New RTS mon output option [#464] - It is possible to output the RTS monitor statistics just before the exit of program by specifying `--rts-mon-on-exit` - The RTS monitor statics are printed to stdout. - Threads now have names, making it easier to debug [#457] - "main", "IO", "Mon Socket" and "Worker X" are the currently used names - Show RTS options and arguments with `--rts-help` [#465] ### Changed - stdout is now line buffered [#464] - `--rts-mon` has been renamed to `--rts-mon-socket-path` - Since there are now multiple output options for the RTS monitor statistics we use a more specific name ### Fixed - Avoid slow RTS performance when using DDB & the DDB server is too fast [#453] - If the DB server responded quickly enough, the client library would enter a pthread_cond_timedwait to wait for the response but it had already arrived leading to always hitting the timeout [#449] - The effect was that the Acton program would run very slowly as each continuation would take one DDB communication timeout to process, which is set to 10 seconds - The DDB client library has been improved to check for the response within the mutex lock to avoid this situation - RTS in DDB mode is now fast! - Acton RTS now shuts down "gracefully" [#460] - `env.exit()` previously called `exit()` in C, immediately shutting down the application & RTS - Any currently running continuation (in another worker thread) would be abrubtly killed - This has been improved so that the RTS will let worker threads complete any currently executing continuation and commit that work before exiting the application - Only do CPU affinity when there are as many worker threads as CPU cores [#447] - `--rts-wthreads` can be used to specify the number of worker threads and if that number does not align with the number of CPU cores in the machine, we will not do CPU pinning - Previously, the worker threads that overlapped with available CPU cores would be pinned whereas the rest would go unpinned. - Corrected worker thread count message [#446] - Previously, the log message (when using `--rts-verbose`) that shows the number of worker threads used when there are few available CPU cores would show the incorrect number (`0`) [#445]: - `**RTS** Detected 2 CPUs: Using 0 worker threads, due to low CPU count. No CPU affinity used.` - RTS was actually using more worker threads but the log message was wrong and has now been corrected. - Corrected actual number of worker threads [#457] - While we computed the correct number of worker threads to use, when creating the threads we completely failed to use that computed value and instead unconditionally spawned as many worker threads as there are CPU cores. - There was also an off-by-one error on the number of worker threads. - This has all been corrected so the correct number of worker threads is now created and there is a test case to prove it. ## [0.7.4] (2022-01-06) ### Fixed - env actor is serialized to database backend during bootstrap [#430] - Actor serialization ("snapshotting") to the database usually happens when a continuation (roughly an actor method) has been run - The env actor might never run, which meant it might not have been serialized to the DB, so when resuming an Acton application from the database, the env actor could be missing leading to a segfault [#408] - RTS now connects to all DB nodes to enable replication factor >1 [#427] - This is a short term fix [#409] - Longer term, the client DB gossip protocol will be enhanced to deal with this properly [#432] - Tests now using 3 DB nodes - Fix DB Membership signaling on DB server crash [#429] - The RTS with DDB test is now using 3 DB nodes and replication factor 3 [#434] - Avoid some C errors so we compile on Ubuntu [#428] ## [0.7.3] (2022-01-03) ### Fixed - Fix segfaults in RTS argument parsing [#420] - Missing argument to option would previously lead to segfault, which is now fixed [#419] - Passing option arguments with =, like `--rts-wthreads=8` now works - Various fixes to C lib wrapping document [#418] - Renamed minienv to env [#417] - Only internal change, does not influence what a user of Acton sees - Now testing RTS using DDB in CI [#425] ## [0.7.2] (2021-12-15) ### Added - Homebrew formula revamped to support Apple M1 [homebrew-acton#28] - Formula now uses brew installed ("system") ghc instead of stack installed GHC, which is more idiomatic Homebrew - Mac on M1 users, simply do: `brew install actonlang/acton/acton` - Acton will be automatically built from source! - No pre-built binary packages ("bottles") as our build environment, which is using GitHub Action runners, cannot build those - `actonc` compiler profiles fully implemented [#403] - previously, `--dev` only used to enable RTS debug - now, all libraries are compiled twice, for dev and rel, and packaged up into libActon_dev and libActon_rel archives - dev mode is compiled with debug symbols (`-g`) - release mode is using optimized code (`-O3`) - final program binary is also compiled with the same flags ### Fixed - The RTS mode using the distributed backend for storing program state is now working [#407] ## [0.7.1] (2021-11-23) There are currently known regressions: - using RTS together with the distributed backend database is not working ### Fixed - `actonc` now explicitly using `-no-pie` on Linux [#390] - this aligns with how we already build our object files, shipped in libActon.a etc ## [0.7.0] (2021-11-23) There are currently known regressions: - using RTS together with the distributed backend database is not working ### Added - Basic support for Apple M1 silicon [#383] - Mostly about keeping track of Homebrew paths, since it uses `/opt/homebrew` on Apple silicon vs `/usr/local` on Intel CPUs - Not thoroughly tested, but Acton compiles and `actonc` appears to produce working programs - *Acton by Example* book [#370] [#371] [#375] - https://www.acton-lang.org/learn/acton-by-example/ - far from complete, but a decent start - using mdBook format - using svgbob plugin to draw pretty SVG art using ASCII art - source in `docs/acton-by-example` - source deliberately kept close (same git repo) to Acton itself, so we can easily update docs as we update other things - The number of worker threads is made configurable [#365] - Run an acton program with `--rts-wthreads X` - As before, number of worker threads defaults to number of logical CPU cores (threads) - RTS statistics and monitoring functionality [#353] - Each worker thread keeps some statistics, like: - number of sleeps - number of continuations executed - time spent executing continuation, counted in bucket less than: - 100ns, 1us, 10us, 100us, 1ms, 10ms, 100ms, 1s, 10s, 100s, +Inf - bookkeeping overhead, like taking internal locks, enqueueing messages etc, also counted in buckets - `utils/actonmon` is a simple utility to connect to monitor socket, fetch statistics and display them - can display in fancy table using `--rich` (using Python rich module) - defaults to simple no-frills output that have no extra dependencies - `--prom` will expose a http server exposing metrics to be consumed by Prometheus in the OpenMetrics exposition format - can then be displayed in Grafana or similar - There are now two compilation "profiles"; development & release [#345] - `--dev` implies debug symbols are included and RTS debugging is enabled, which was previously enabled with `--rts-debug` - release mode is the default and does not include debug symbols nor RTS debugging - `actonc --numeric-version` shows a numeric version number [#346] - a stable interface to simply display the actonc version number - unlike `--version` which stretches across multiple lines and includes the versions of cc, the haskell stack used to build actonc etc - Debian packages are now added as assets to GitHub releases [#369] - .deb have always been available as GH Action job artifact - For release versions, the .deb was available via the Acton apt repo - Now easily possible to grab historic versions as well as pre-release .deb, i.e. from main branch by downloading .deb from GitHub release page ### Changed - Acton compiler now built using Haskell LTS 18.12 [#335] - `--rts-debug` option replaced `--dev` [#345] - GitHub Actions now run for PRs and for main branch and tags [#385] - Would previously run both for PRs and for push to a branch, resulting in duplicate runs ### Fixed - Significantly improve performance by reducing RTS worker thread wake ups [#360] - Best case scenarios is on the scale of 10x performance with drastically reduced syscall overhead - Fix lib path on Mac OS X on x86_64 [#384] - Now includes `/usr/local/lib` in library search path - This was previously included through some default mechanism but it is now explicit - Make build more idempotent [#333] - Fix GNU sed check in Makefile [#344] - Add `#pragma once` to `numpy.h` [#331] - Avoid regenerating protobuf generated files [#382] - Since the generated files are checked into git, we really do not want to regenerate them, thus the Make target has been turned into a NOP - Fix GitHub Action caching issue by adding version cache key [#339] - Simplify GitHub issue template for bug report [#367] ## [0.6.4] (2021-09-29) There are currently known regressions: - using RTS together with the distributed backend database is not working ### Fixed - `break` & `continue` now works in `for` loops that are CPS fragmented [#325] - Using `break` would previously not work in a `for` loop if the loop was broken into multiple continuations during the CPS transform. For example, this happens when a call to another actor is made in the `for` loop. - An installed `actonc` can now find `__builtin__.h` [#327] - A previous restructuring of files in order to improve the Makefile and build organization led to us having to use weirdly long and relative include paths. This ultimately led to run time failures of actonc. Since some of these files need to be built both when building actonc itself as well as when using actonc, the paths must remain the same in source and release output. They did not after [#286], which has now been reverted. ## [0.6.3] (2021-09-28) There are currently known regressions: - using RTS together with the distributed backend database is not working ### Added - Acton now has a apt repository - `apt.acton-lang.io` [#320] - Version tagged releases are automatically uploaded. ### Changed - `actonc` now uses `cc` rather than `gcc` [#303] - Acton project makefiles now use `$(CC)` rather than hardcoding `cc` [#303] - Acton is now built and tested on debian:bullseye (11, current stable) [#313] ### Fixed - Debian packages now depend on non-dev libraries for utf8proc & protobuf [#315] - Makefile restructuring [#304] [#307] - backend and compiler Makefiles have now been folded into the top level Makefile. - DAG is more complete and more things can run correctly in parallel. - stack / ghc build now uses 4 parallel threads, for some speedup (55 seconds -> 35 seconds on an AMD 5950X). Higher parallelism did not improve things much further. - Avoid declaring actonc as a PHONY target, which causes constant rebuilds, not it actually has proper dependencies defined so make can understand when there is nothing to do. - Debian packages now reflect tip version number [#307] [#308] - Previously debian packages had the "base version", like 0.6.2, even when built as a pre-release build. `actonc --version` in the package would still correctly identify like e.g. `0.6.2.20210924.16.58.23` - Now the .deb file also contains the complete build info, like `acton_0.6.2.20210924.16.58.23_amd64.deb` ## [0.6.2] (2021-09-23) ### Added - Linuxbrew build [homebrew-acton#7] - Acton can now be installed via Linuxbrew (Homebrew on Linux) ### Fixed - Constraint grouping to also consider free environment types variables [#277] - Previously, this bug in the constraint solver meant that `actonc` could hang when compiling certain programs. - Added missing CPS case to fix return value [#279] - Would previously lead to an internal compiler error where the generated C code would not compile. - Fix RTS bug that could lead to segmentation fault [#285] - The integrity of a linked list was not preserved during a certain operation which would lead to a segmentation fault. - The error typically occurred during high load situations. - Continuation environment now includes all variables [#288] - Previously, after the CPS step, the generated continuation was lacking its environment which meant some variables were inaccessible. - The numpy module is now working again [#293] - It was broken during a code restructuring and has now been restored. - The entire public interface is now contained in numpy.h (not spread over multiple .h files as before). - numpy.o is partially linked to hide any library dependencies. - The same model of not leaking module internals will be used for other modules in the future. ## [0.6.1] (2021-09-19) ### Added - Debian packaging [#60] - There is now a .deb produced and uploaded as part of the artifacts for each release on GitHub. ### Changed - RTS now uses a minimum of 4 worker threads [#263] - The default is to use as many worker threads as there are CPUs and set CPU affinity to map worker threads to CPUs in a 1:1 fashion. - The first core is used to run the eventloop that processes I/O and the rest runs the main loop that executes actors. - On machines with a low CPU count this can be catastrophic. The extreme example being a single CPU machine, which consequently will have 0 worker threads executing actors. It will only run the eventloop that processes I/O and thus is unable to actually run an Acton program. - Even on a 2 CPU machine, which would lead to a single worker thread executing actors, this can be quite bad. - We now run a minimum of 4 worker threads, 1 for the I/O eventloop and 3 actor processing threads, to get around these problems. ## [0.6.0] (2021-09-17) Despite a regression in the RTS's distributed mode of operationa, v0.6.0 is released as improvements in other areas make it the best version of Acton to date. ### Added - Acton project concept [#140] - An Acton project is a standardized structure for how to organize an Acton project: - At the root is an `Acton.toml` file. It is currently empty but its location denotes the project root. - `src/` is the directory in which source files are stored, imports are relative to this directory, i.e. `import foo` will import `src/foo.act` - imports will also search the system path as before for the stdlib modules - `out/` is the output directory in which generated type file (`.ty`) and object / library files are written as well as binaries - `out/bin` is where executables end up (`actonc --root foo bar.act` will produce an executable) - `out/types` is where types files go - `out/lib` is where object / library files go - We used to write compiled output of modules to the system path. To install acton on a system, outside of a users home directory, we can no longer write to the system path since it is owned by root. Further, we don't want to write to a common system path as different users code could collide. - Now only the builtins and stdlib modules are in the system path. Other compiled output, like type files and object files, are written to the project directory. - It is still possible to compile individual `.act` files as executabes (`--root ROOT`), in which case `actonc` will create a temporary directory for intermediate output and write the final file in the same directory as the `.act` file. This is to preserve the current behavior when "using acton as a scripting language". - Overall, the idea is to cater to both: - Acton as a scripting language - Often a single source file - minimal "project overhead" wanted - Acton for large projects - Many modules, perhaps producing multiple executables - Good project structure necessary to manage it all - There is now an RTS debug mode [#189] - With `actonc --rts-debug`, an Acton program can be compiled with debug functionality included. - When a debug enabled Acton program is run with `my-program --rts-debug`, - Argument to configure the replication factor used with the distributed backend database [#204] - Default is 3, as that is the lowest value that makes sense for a quorum. - Read and write quorum is derived from the replication factor / 2 + 1 - Thus, with replication=3, read/write quorum is 2 - Connecting to multiple database backend servers for redundancy [#206] - `--rts-ddb-host` can be specified multiple times to connect to multiple backend servers - Thus, an RTS compute node can survive a database server going down. - The port number can be specified per host by appending it colon separated from the hostname, like `--rts-ddb-host localhost:32001` - Monotonic time function have been added [#152] - `time.monotonic()` returning a float. - `time.monotonic_ns()` returning nanoseconds as an integer. ### Changed - RTS now uses epoll on Linux [#243] - Was previously written for kqueue, which runs natively on MacOS X. - On Linux, a shim, libkqueue, was used to map kqueue calls to epoll. - To reduce risk of error and potentially squeeze out more performance, epoll is a better choice. - Dependency on libkqueue has been removed, which makes it easier to compile Acton on more platforms. - `time` module has been aligned with its Python counterpart [#152] [#197] - `time.time()` function now returns a float. - New function `time.time_ns()` returns time in nanoseconds as an integer. - `RuntimeError` is raised on an error, just like Python - `actonc --version` now includes verbose output [#212] - Previously it was required to run `actonc --version --verbose` to see CC information etc. This is now included in the default output of `actonc --version` and `--verbose` no longer influences the output. ### Fixed - `actonc --version` no longer requires a "dummy" argument [#212] - Fix actor creation and initialization in the RTS [#186] - Previously, actor creation and initialization was indeterministic and given certain conditions, messages or even actors could be lost, leading to system malfunction. One way in which this showed was how certain programs would just hang even when they should exit. - RTS has been entirely reworked in regards to actor creation and now follows the overall language model, which makes things simpler and more robust. ## [0.5.3] (2021-09-13) ### Added - It is now possible to install Acton on Mac OS X via Homebrew - `brew install actonlang/acton/acton` - Warnings are now generally treated as errors when compiling Acton [#153] - Many warnings have been fixed. - There are some exceptions added for some warnings. - With time these should be reduced. - Bug triage and prioritization document [#165] - see `docs/triage.md` ### Fixed - Fix internal instantiations of tuples to use `$NEWTUPLE` [#173] - For example functions like `divmod` that returns a tuple was using an incorrect macro. - `divmod` now returns correct results. (#)) - It would previously return wildly incorrect results (integer wraparound style) and could lead to segfaults due to incorrect tuple creation - Greater than or equal (`>=`) now works for integers [#161] - It was broken and actually did an equal match. - Fix header inclusion for numpy use of arc4random functions [#155] - Situations where `actonc` was unable to unify atoms and ints or infer type conversion have now been fixed. [#183] - Fix variable being out of scope in a function [#174] ## [0.5.2] (2021-08-25) ### Fixed - It is now possible to raise exceptions [#133] [#137] - Previously a naming misalignment between the Acton compiler code generation and the builtins of the RTS led to an Internal Compiler Error. - BaseException is now also used instead of Exception, as it should. - Distributed RTS mode has been fixed with regards to actor bootstrap that previously lead to duplicate actors [#121] - An actor method (callback) can now be passed as an argument to another actor method [#129] - This could previously lead to a segmentation fault during certain situations. - Avoid cleaning away `modules/math.h` [#136] - This was due to an outdated Makefile cleaning target - Type inferencing now works for all dicts [#139] - Previously worked for some, for example a dict of strings but not for a dict of ints. - The modules `acton.rts`, `math` and `random` now work correctly [#127] - The type signature filed was missing but is now correctly built. - There are test cases for these modules but the tests were not run in CI - More tests are now run in CI [#128] - Due to a directory restructuring and assumptions (mother of all evil), some tests were previously not run. While working locally on a developers computer things worked due to manually compiled files. We failed to detect these missing type signature files in CI since the tests were not run automatically. - Type inference is now order independent [#142] - There were previously situations in which the type inferencer was unable to do its job based on the layout / order of the code. - `print(foo())` now correctly prints the return value of foo() rather than a message reference (due to asynchronous evaluation) [#142] ## [0.5.1] (2021-08-24) ### Fixed - v0.5.0 was released with an incorrect version number and would identify itself as version v0.4.2 ## [0.5.0] (2021-08-23) ### Added - The distributed database backend is enabled in the RTS [#45] - this was previously a build time flag - it is now run time configuration via `--rts-ddb-host` and `--rts-ddb-port` - see `examples/count` for a demo and instructions - RTS now has a `--rts-verbose` argument to make it more chatty [#45] - General evaluation of expressions in a boolean context [#107] - explicit boolean expressions were already supported and working - however, in Python any expression can be evaluated in a boolean context which was not properly supported... and it now is! - this could be considered a bug fix, like it should go under "Fixed" but it is big enough of a thing to warrant being here... almost like new functionality, although we probably did intend to support this all along - Description of development workflow, see `docs/development_workflow.md` [#73] - A short guide on how to wrap C libraries for use in Acton, see `docs/wrapping_c_libraries.md` [#84] - `time.time()` function [#83] - returns the current system time in nanoseconds as an integer - `time` is a new module - `random.randint()` function [#113] - `random` is a new module - `acton.rts.sleep()` function [#95] - from a user perspective acts just like Pythons `time.sleep()` - it uses `usleep` in C which means it actually sleeps the RTS thread executing the actor - this is typically a bad thing - we just want to sleep an actor, not the RTS thread - there are however use cases, like when implementing benchmarking or similar. - this is why it is under `acton.rts` and not in `time` - `acton.rts` is a new module ### Changed - Refactored Makefile structure to complete DAG [#77] - use a single top level Makefile rather than recursive Makefiles - only matters if you are doing development on Acton itself - backend, being enough of a standalone piece, still has its own Makefile - `actonc --hgen` and `actonc --cgen` now outputs only code [#82] - easier to pipe directly to a file - compilation command not included, now available with `actonc --ccmd` - `actonc` argument `--path` is now called `--syspath` [#93] - it is the system path and was already referred to as `syspath` internally - The build output, when building Acton itself, is now placed in `dist` [#88] - makes it considerably easier to produce a release by tarring up its content - release size has been reduced to almost half by avoiding unnecessary files - the top level directories, like `modules` is now a source directory and no longer "the working directory of `actonc`" - Source code of several modules have been moved from separate subdirs, like `math` and `time`, into `modules/`. Less top level clutter! [#99] ### Fixed - Improved dependency declaration for backend [#77] - Only matters if you are building Acton yourself and making changes to the backend database ## [0.4.2] (2021-08-05) ### Added - `tip` releases are now available at stable URLs: [#70] - https://github.com/actonlang/acton/releases/download/tip/acton-darwin-x86_64.tar.bz2 - https://github.com/actonlang/acton/releases/download/tip/acton-linux-x86_64.tar.bz2 ### Fixed - Versioned releases now use correct version number, like `0.4.1` rather than the version style used for `tip` releases which include the date & time, like `0.4.1.2021.08.05.12.15.37` [#69] - tip release tar balls now reflect the full tip version in the filename [#71] - like `acton-linux-x86_64-0.4.1.20210805.13.46.55.tar.bz2` - previously, it would just be `acton-linux-x86_64-0.4.1.tar.bz2`, making it difficult to differentiate against the proper 0.4.1 or other nightlies ## [0.4.1] (2021-08-05) ### Added - `--version --verbose` will print verbose version information [#41] - Internal compiler errors include information about the C compiler (cc) [#41] - Acton is now made available as GitHub Releases [#53] - pre-built binary releases! Users no longer need to compile Acton themselves - available from [Releases page](https://github.com/actonlang/acton/releases) - versioned releases, like this v0.4.1, are available - latest build from `main` branch is available as `tip` ### Fixed - Integer subtraction has been fixed [#48] - wrong order of operators would previously return wildly incorrect results ## [0.4.0] (2021-07-23) ### Added - Linux compatibility! [#1] [#14] [#15] - it is now possible to compile the Acton compiler (actonc), the backend and the RTS on Linux - actonc can now compile Acton programs on Linux - Linux on x86_64 is tested, no other architectures - libkqueue is used on Linux as a compatibility shim between kqueue calls and epoll - Acton was initially developed on OS X and the RTS therefore uses kqueue and not epoll / aio(uring) - More test cases, in particular the ones for which we have GitHub issues [#21] - CI runs on Linux too [#15] - acton is built and tested on both Linux and OS X - all tests are the same across both platforms - `actonc` has got a `--version` argument ### Changed - Now uses Haskell lts-17.14 instead of lts-13.0 [#2] ### Removed - The project repository has been cleaned up overall ### Fixed - `actonc` now detects and reports internal compiler errors [#28] - happens when gcc fails to compile the C code that actonc generates - A bunch of compiler surprises have been made less surprising - see git log for details ;) ## [0.3.0] (2021-04-14) ### Added - Acton is now public and published at its new [home on Github](https://github.com/actonlang/acton/) - Added basic (working) build instructions - A basic test suite with a few tests, including some of the examples being reused for testing - GitHub Actions is used as CI to build and test Acton - Mac OS X / Darwin is the only platform used for testing Acton ### Changed - distributed database backend is disabled in builds per default - while working, it is too rough around the edges to be enabled per default - in particular, it needs to be made run time configurable ## 0.2.0 (a long long time ago, like 2019) This is a sort of fictitious release that roughly maps to the prehistoric era before recorded time. There was a git log but no real version keeping. 0.2.0 was the first ever version of the "new compiler". It wasn't 0.1 because in an earlier prehistoric era, another system existed which could be called the first incarnation of Acton. It was more of a proof of concept based on Python as a runtime and with a hacked up Cassandra database as a backend store. Since then, this second incarnation has been in focus and 0.2.0 was its first version. [#1]: https://github.com/actonlang/acton/pull/1 [#2]: https://github.com/actonlang/acton/pull/2 [#7]: https://github.com/actonlang/acton/pull/7 [#14]: https://github.com/actonlang/acton/pull/14 [#15]: https://github.com/actonlang/acton/pull/15 [#21]: https://github.com/actonlang/acton/pull/21 [#28]: https://github.com/actonlang/acton/pull/28 [#14]: https://github.com/actonlang/acton/pull/14 [#15]: https://github.com/actonlang/acton/pull/15 [#21]: https://github.com/actonlang/acton/pull/21 [#28]: https://github.com/actonlang/acton/pull/28 [#41]: https://github.com/actonlang/acton/pull/41 [#45]: https://github.com/actonlang/acton/pull/45 [#48]: https://github.com/actonlang/acton/pull/48 [#53]: https://github.com/actonlang/acton/pull/53 [#60]: https://github.com/actonlang/acton/pull/60 [#69]: https://github.com/actonlang/acton/pull/69 [#70]: https://github.com/actonlang/acton/pull/70 [#71]: https://github.com/actonlang/acton/pull/71 [#73]: https://github.com/actonlang/acton/pull/73 [#77]: https://github.com/actonlang/acton/pull/77 [#82]: https://github.com/actonlang/acton/pull/82 [#83]: https://github.com/actonlang/acton/pull/83 [#84]: https://github.com/actonlang/acton/pull/84 [#88]: https://github.com/actonlang/acton/pull/88 [#93]: https://github.com/actonlang/acton/pull/93 [#95]: https://github.com/actonlang/acton/pull/95 [#99]: https://github.com/actonlang/acton/pull/99 [#107]: https://github.com/actonlang/acton/pull/107 [#113]: https://github.com/actonlang/acton/pull/113 [#121]: https://github.com/actonlang/acton/pull/121 [#127]: https://github.com/actonlang/acton/pull/127 [#128]: https://github.com/actonlang/acton/pull/128 [#129]: https://github.com/actonlang/acton/pull/129 [#133]: https://github.com/actonlang/acton/pull/133 [#136]: https://github.com/actonlang/acton/pull/136 [#137]: https://github.com/actonlang/acton/pull/137 [#139]: https://github.com/actonlang/acton/pull/139 [#140]: https://github.com/actonlang/acton/pull/140 [#142]: https://github.com/actonlang/acton/pull/142 [#146]: https://github.com/actonlang/acton/issues/146 [#152]: https://github.com/actonlang/acton/pull/152 [#153]: https://github.com/actonlang/acton/pull/153 [#155]: https://github.com/actonlang/acton/pull/155 [#161]: https://github.com/actonlang/acton/pull/161 [#165]: https://github.com/actonlang/acton/pull/165 [#173]: https://github.com/actonlang/acton/pull/173 [#174]: https://github.com/actonlang/acton/pull/174 [#183]: https://github.com/actonlang/acton/pull/183 [#186]: https://github.com/actonlang/acton/pull/186 [#189]: https://github.com/actonlang/acton/pull/189 [#197]: https://github.com/actonlang/acton/pull/197 [#204]: https://github.com/actonlang/acton/pull/204 [#206]: https://github.com/actonlang/acton/pull/206 [#212]: https://github.com/actonlang/acton/pull/212 [#238]: https://github.com/actonlang/acton/issues/238 [#243]: https://github.com/actonlang/acton/pull/243 [#263]: https://github.com/actonlang/acton/pull/264 [#277]: https://github.com/actonlang/acton/pull/277 [#279]: https://github.com/actonlang/acton/pull/279 [#285]: https://github.com/actonlang/acton/pull/285 [#286]: https://github.com/actonlang/acton/pull/286 [#288]: https://github.com/actonlang/acton/pull/288 [#293]: https://github.com/actonlang/acton/pull/293 [#303]: https://github.com/actonlang/acton/pull/303 [#304]: https://github.com/actonlang/acton/pull/304 [#307]: https://github.com/actonlang/acton/pull/307 [#308]: https://github.com/actonlang/acton/pull/308 [#313]: https://github.com/actonlang/acton/pull/313 [#315]: https://github.com/actonlang/acton/pull/315 [#320]: https://github.com/actonlang/acton/pull/320 [#325]: https://github.com/actonlang/acton/pull/325 [#327]: https://github.com/actonlang/acton/pull/327 [#331]: https://github.com/actonlang/acton/pull/331 [#333]: https://github.com/actonlang/acton/pull/333 [#335]: https://github.com/actonlang/acton/pull/335 [#339]: https://github.com/actonlang/acton/pull/339 [#344]: https://github.com/actonlang/acton/pull/344 [#345]: https://github.com/actonlang/acton/pull/345 [#346]: https://github.com/actonlang/acton/pull/346 [#353]: https://github.com/actonlang/acton/pull/353 [#360]: https://github.com/actonlang/acton/pull/360 [#365]: https://github.com/actonlang/acton/pull/365 [#367]: https://github.com/actonlang/acton/pull/367 [#369]: https://github.com/actonlang/acton/pull/369 [#370]: https://github.com/actonlang/acton/pull/370 [#371]: https://github.com/actonlang/acton/pull/371 [#374]: https://github.com/actonlang/acton/issues/374 [#375]: https://github.com/actonlang/acton/pull/375 [#382]: https://github.com/actonlang/acton/pull/382 [#383]: https://github.com/actonlang/acton/pull/383 [#384]: https://github.com/actonlang/acton/pull/384 [#385]: https://github.com/actonlang/acton/pull/385 [#390]: https://github.com/actonlang/acton/pull/390 [#403]: https://github.com/actonlang/acton/pull/403 [#407]: https://github.com/actonlang/acton/pull/407 [#408]: https://github.com/actonlang/acton/issues/408 [#409]: https://github.com/actonlang/acton/issues/409 [#417]: https://github.com/actonlang/acton/pull/417 [#418]: https://github.com/actonlang/acton/pull/418 [#419]: https://github.com/actonlang/acton/issues/419 [#420]: https://github.com/actonlang/acton/pull/420 [#425]: https://github.com/actonlang/acton/pull/425 [#427]: https://github.com/actonlang/acton/pull/427 [#428]: https://github.com/actonlang/acton/pull/428 [#429]: https://github.com/actonlang/acton/pull/429 [#430]: https://github.com/actonlang/acton/pull/430 [#431]: https://github.com/actonlang/acton/issues/431 [#432]: https://github.com/actonlang/acton/issues/432 [#434]: https://github.com/actonlang/acton/pull/434 [#445]: https://github.com/actonlang/acton/issues/445 [#446]: https://github.com/actonlang/acton/pull/446 [#447]: https://github.com/actonlang/acton/pull/447 [#449]: https://github.com/actonlang/acton/issues/449 [#453]: https://github.com/actonlang/acton/pull/453 [#457]: https://github.com/actonlang/acton/pull/457 [#460]: https://github.com/actonlang/acton/pull/460 [#464]: https://github.com/actonlang/acton/pull/464 [#465]: https://github.com/actonlang/acton/pull/465 [#469]: https://github.com/actonlang/acton/pull/469 [#472]: https://github.com/actonlang/acton/issues/472 [#473]: https://github.com/actonlang/acton/pull/473 [#474]: https://github.com/actonlang/acton/pull/474 [#475]: https://github.com/actonlang/acton/pull/475 [#476]: https://github.com/actonlang/acton/pull/476 [#478]: https://github.com/actonlang/acton/pull/478 [#479]: https://github.com/actonlang/acton/pull/479 [#481]: https://github.com/actonlang/acton/pull/481 [#488]: https://github.com/actonlang/acton/pull/488 [#493]: https://github.com/actonlang/acton/pull/493 [#494]: https://github.com/actonlang/acton/pull/494 [#499]: https://github.com/actonlang/acton/pull/499 [#501]: https://github.com/actonlang/acton/pull/501 [#502]: https://github.com/actonlang/acton/pull/502 [#504]: https://github.com/actonlang/acton/pull/504 [#506]: https://github.com/actonlang/acton/pull/506 [#509]: https://github.com/actonlang/acton/pull/509 [#512]: https://github.com/actonlang/acton/pull/512 [#514]: https://github.com/actonlang/acton/pull/514 [#516]: https://github.com/actonlang/acton/pull/516 [#517]: https://github.com/actonlang/acton/pull/517 [#518]: https://github.com/actonlang/acton/pull/518 [#521]: https://github.com/actonlang/acton/pull/521 [#522]: https://github.com/actonlang/acton/pull/522 [#524]: https://github.com/actonlang/acton/issues/524 [#527]: https://github.com/actonlang/acton/issues/527 [#528]: https://github.com/actonlang/acton/pull/528 [#529]: https://github.com/actonlang/acton/pull/529 [#530]: https://github.com/actonlang/acton/pull/530 [#535]: https://github.com/actonlang/acton/pull/535 [#538]: https://github.com/actonlang/acton/pull/538 [#542]: https://github.com/actonlang/acton/pull/542 [#546]: https://github.com/actonlang/acton/pull/546 [#547]: https://github.com/actonlang/acton/issues/547 [#559]: https://github.com/actonlang/acton/pull/559 [#570]: https://github.com/actonlang/acton/pull/570 [#571]: https://github.com/actonlang/acton/pull/571 [#574]: https://github.com/actonlang/acton/pull/574 [#584]: https://github.com/actonlang/acton/pull/584 [#586]: https://github.com/actonlang/acton/pull/586 [#587]: https://github.com/actonlang/acton/pull/587 [#588]: https://github.com/actonlang/acton/pull/588 [#599]: https://github.com/actonlang/acton/pull/599 [#601]: https://github.com/actonlang/acton/pull/601 [#602]: https://github.com/actonlang/acton/pull/602 [#607]: https://github.com/actonlang/acton/pull/607 [#608]: https://github.com/actonlang/acton/pull/608 [#612]: https://github.com/actonlang/acton/pull/612 [#623]: https://github.com/actonlang/acton/pull/623 [#624]: https://github.com/actonlang/acton/pull/624 [#625]: https://github.com/actonlang/acton/pull/625 [#627]: https://github.com/actonlang/acton/issues/627 [#628]: https://github.com/actonlang/acton/pull/628 [#629]: https://github.com/actonlang/acton/pull/629 [#631]: https://github.com/actonlang/acton/pull/631 [#633]: https://github.com/actonlang/acton/pull/633 [#645]: https://github.com/actonlang/acton/pull/645 [#655]: https://github.com/actonlang/acton/pull/655 [#685]: https://github.com/actonlang/acton/pull/685 [#693]: https://github.com/actonlang/acton/pull/693 [#698]: https://github.com/actonlang/acton/pull/698 [#700]: https://github.com/actonlang/acton/pull/700 [#706]: https://github.com/actonlang/acton/pull/706 [#719]: https://github.com/actonlang/acton/pull/719 [#726]: https://github.com/actonlang/acton/pull/726 [#733]: https://github.com/actonlang/acton/pull/733 [#752]: https://github.com/actonlang/acton/pull/752 [#760]: https://github.com/actonlang/acton/pull/760 [#788]: https://github.com/actonlang/acton/issues/788 [#806]: https://github.com/actonlang/acton/pull/806 [#808]: https://github.com/actonlang/acton/pull/808 [#823]: https://github.com/actonlang/acton/pull/823 [#829]: https://github.com/actonlang/acton/pull/829 [#835]: https://github.com/actonlang/acton/issues/835 [#840]: https://github.com/actonlang/acton/pull/840 [#845]: https://github.com/actonlang/acton/pull/845 [#846]: https://github.com/actonlang/acton/pull/846 [#849]: https://github.com/actonlang/acton/issues/849 [#853]: https://github.com/actonlang/acton/issues/853 [#868]: https://github.com/actonlang/acton/pull/868 [#869]: https://github.com/actonlang/acton/issues/869 [#882]: https://github.com/actonlang/acton/issues/882 [#885]: https://github.com/actonlang/acton/issues/885 [#887]: https://github.com/actonlang/acton/issues/887 [#890]: https://github.com/actonlang/acton/issues/890 [#892]: https://github.com/actonlang/acton/pull/892 [#900]: https://github.com/actonlang/acton/pull/900 [#907]: https://github.com/actonlang/acton/issues/907 [#910]: https://github.com/actonlang/acton/pull/910 [#913]: https://github.com/actonlang/acton/issues/913 [#916]: https://github.com/actonlang/acton/pull/916 [#917]: https://github.com/actonlang/acton/pull/917 [#922]: https://github.com/actonlang/acton/pull/922 [#926]: https://github.com/actonlang/acton/issues/926 [#925]: https://github.com/actonlang/acton/pull/925 [#929]: https://github.com/actonlang/acton/pull/929 [#932]: https://github.com/actonlang/acton/pull/932 [#941]: https://github.com/actonlang/acton/issues/941 [#949]: https://github.com/actonlang/acton/pull/949 [#950]: https://github.com/actonlang/acton/pull/950 [#951]: https://github.com/actonlang/acton/issues/951 [#955]: https://github.com/actonlang/acton/pull/955 [#957]: https://github.com/actonlang/acton/pull/957 [#969]: https://github.com/actonlang/acton/issues/969 [#971]: https://github.com/actonlang/acton/pull/971 [#972]: https://github.com/actonlang/acton/issues/972 [#976]: https://github.com/actonlang/acton/pull/976 [#984]: https://github.com/actonlang/acton/pull/984 [#988]: https://github.com/actonlang/acton/pull/988 [#1003]: https://github.com/actonlang/acton/issues/1003 [#1020]: https://github.com/actonlang/acton/pull/1020 [#1027]: https://github.com/actonlang/acton/issues/1027 [#1029]: https://github.com/actonlang/acton/issues/1029 [#1047]: https://github.com/actonlang/acton/issues/1047 [#1050]: https://github.com/actonlang/acton/issues/1050 [#1053]: https://github.com/actonlang/acton/pull/1053 [#1054]: https://github.com/actonlang/acton/pull/1054 [#1055]: https://github.com/actonlang/acton/pull/1055 [#1056]: https://github.com/actonlang/acton/pull/1056 [#1058]: https://github.com/actonlang/acton/pull/1058 [#1060]: https://github.com/actonlang/acton/pull/1060 [#1065]: https://github.com/actonlang/acton/pull/1065 [#1068]: https://github.com/actonlang/acton/pull/1068 [#1076]: https://github.com/actonlang/acton/pull/1076 [#1087]: https://github.com/actonlang/acton/pull/1087 [#1088]: https://github.com/actonlang/acton/pull/1088 [#1089]: https://github.com/actonlang/acton/pull/1089 [#1091]: https://github.com/actonlang/acton/issues/1091 [#1093]: https://github.com/actonlang/acton/pull/1093 [#1097]: https://github.com/actonlang/acton/pull/1097 [#2253]: https://github.com/actonlang/acton/pull/2253 [#2254]: https://github.com/actonlang/acton/pull/2254 [#2256]: https://github.com/actonlang/acton/pull/2256 [#2257]: https://github.com/actonlang/acton/pull/2257 [#2258]: https://github.com/actonlang/acton/pull/2258 [#2259]: https://github.com/actonlang/acton/pull/2259 [#2261]: https://github.com/actonlang/acton/pull/2261 [#2262]: https://github.com/actonlang/acton/pull/2262 [#41]: https://github.com/actonlang/acton/pull/41 [#45]: https://github.com/actonlang/acton/pull/45 [#48]: https://github.com/actonlang/acton/pull/48 [#53]: https://github.com/actonlang/acton/pull/53 [#60]: https://github.com/actonlang/acton/pull/60 [#69]: https://github.com/actonlang/acton/pull/69 [#126]: https://github.com/actonlang/acton/pull/126 [#657]: https://github.com/actonlang/acton/pull/657 [#766]: https://github.com/actonlang/acton/pull/766 [#796]: https://github.com/actonlang/acton/pull/796 [#797]: https://github.com/actonlang/acton/pull/797 [#798]: https://github.com/actonlang/acton/pull/798 [#799]: https://github.com/actonlang/acton/pull/799 [#800]: https://github.com/actonlang/acton/pull/800 [#801]: https://github.com/actonlang/acton/pull/801 [#804]: https://github.com/actonlang/acton/pull/804 [#812]: https://github.com/actonlang/acton/pull/812 [#973]: https://github.com/actonlang/acton/pull/973 [#1010]: https://github.com/actonlang/acton/pull/1010 [#1061]: https://github.com/actonlang/acton/pull/1061 [#1077]: https://github.com/actonlang/acton/pull/1077 [#1080]: https://github.com/actonlang/acton/pull/1080 [#1092]: https://github.com/actonlang/acton/pull/1092 [#1103]: https://github.com/actonlang/acton/pull/1103 [#1105]: https://github.com/actonlang/acton/pull/1105 [#1106]: https://github.com/actonlang/acton/pull/1106 [#1107]: https://github.com/actonlang/acton/pull/1107 [#1110]: https://github.com/actonlang/acton/pull/1110 [#1111]: https://github.com/actonlang/acton/pull/1111 [#1112]: https://github.com/actonlang/acton/pull/1112 [#1115]: https://github.com/actonlang/acton/pull/1115 [#1118]: https://github.com/actonlang/acton/pull/1118 [#1119]: https://github.com/actonlang/acton/pull/1119 [#1124]: https://github.com/actonlang/acton/pull/1124 [#1127]: https://github.com/actonlang/acton/pull/1127 [#1136]: https://github.com/actonlang/acton/pull/1136 [#1137]: https://github.com/actonlang/acton/pull/1137 [#1140]: https://github.com/actonlang/acton/pull/1140 [#1141]: https://github.com/actonlang/acton/pull/1141 [#1144]: https://github.com/actonlang/acton/pull/1144 [#1145]: https://github.com/actonlang/acton/pull/1145 [#1148]: https://github.com/actonlang/acton/pull/1148 [#1149]: https://github.com/actonlang/acton/pull/1149 [#1150]: https://github.com/actonlang/acton/pull/1150 [#1160]: https://github.com/actonlang/acton/pull/1160 [#1162]: https://github.com/actonlang/acton/pull/1162 [#1169]: https://github.com/actonlang/acton/pull/1169 [#1172]: https://github.com/actonlang/acton/pull/1172 [#1174]: https://github.com/actonlang/acton/pull/1174 [#1176]: https://github.com/actonlang/acton/pull/1176 [#1177]: https://github.com/actonlang/acton/pull/1177 [#1181]: https://github.com/actonlang/acton/pull/1181 [#1185]: https://github.com/actonlang/acton/pull/1185 [#1186]: https://github.com/actonlang/acton/pull/1186 [#1188]: https://github.com/actonlang/acton/pull/1188 [#1192]: https://github.com/actonlang/acton/pull/1192 [#1193]: https://github.com/actonlang/acton/pull/1193 [#1194]: https://github.com/actonlang/acton/pull/1194 [#1196]: https://github.com/actonlang/acton/pull/1196 [#1197]: https://github.com/actonlang/acton/pull/1197 [#1198]: https://github.com/actonlang/acton/pull/1198 [#1199]: https://github.com/actonlang/acton/pull/1199 [#1202]: https://github.com/actonlang/acton/pull/1202 [#1203]: https://github.com/actonlang/acton/pull/1203 [#1206]: https://github.com/actonlang/acton/pull/1206 [#1207]: https://github.com/actonlang/acton/pull/1207 [#1208]: https://github.com/actonlang/acton/pull/1208 [#1210]: https://github.com/actonlang/acton/pull/1210 [#1211]: https://github.com/actonlang/acton/pull/1211 [#1216]: https://github.com/actonlang/acton/pull/1216 [#1217]: https://github.com/actonlang/acton/pull/1217 [#1219]: https://github.com/actonlang/acton/pull/1219 [#1220]: https://github.com/actonlang/acton/pull/1220 [#1225]: https://github.com/actonlang/acton/pull/1225 [#1226]: https://github.com/actonlang/acton/pull/1226 [#1228]: https://github.com/actonlang/acton/pull/1228 [#1235]: https://github.com/actonlang/acton/pull/1235 [#1237]: https://github.com/actonlang/acton/pull/1237 [#1246]: https://github.com/actonlang/acton/pull/1246 [#1249]: https://github.com/actonlang/acton/pull/1249 [#1256]: https://github.com/actonlang/acton/pull/1256 [#1258]: https://github.com/actonlang/acton/pull/1258 [#1260]: https://github.com/actonlang/acton/pull/1260 [#1262]: https://github.com/actonlang/acton/pull/1262 [#1263]: https://github.com/actonlang/acton/pull/1263 [#1264]: https://github.com/actonlang/acton/pull/1264 [#1265]: https://github.com/actonlang/acton/pull/1265 [#1267]: https://github.com/actonlang/acton/pull/1267 [#1269]: https://github.com/actonlang/acton/pull/1269 [#1270]: https://github.com/actonlang/acton/pull/1270 [#1274]: https://github.com/actonlang/acton/pull/1274 [#1277]: https://github.com/actonlang/acton/pull/1277 [#1278]: https://github.com/actonlang/acton/pull/1278 [#1279]: https://github.com/actonlang/acton/pull/1279 [#1282]: https://github.com/actonlang/acton/pull/1282 [#1283]: https://github.com/actonlang/acton/pull/1283 [#1284]: https://github.com/actonlang/acton/pull/1284 [#1303]: https://github.com/actonlang/acton/pull/1303 [#1304]: https://github.com/actonlang/acton/pull/1304 [#1309]: https://github.com/actonlang/acton/pull/1309 [#1316]: https://github.com/actonlang/acton/pull/1316 [#1323]: https://github.com/actonlang/acton/pull/1323 [#1325]: https://github.com/actonlang/acton/pull/1325 [#1329]: https://github.com/actonlang/acton/pull/1329 [#1331]: https://github.com/actonlang/acton/pull/1331 [#1332]: https://github.com/actonlang/acton/pull/1332 [#1333]: https://github.com/actonlang/acton/pull/1333 [#1334]: https://github.com/actonlang/acton/pull/1334 [#1336]: https://github.com/actonlang/acton/pull/1336 [#1337]: https://github.com/actonlang/acton/pull/1337 [#1338]: https://github.com/actonlang/acton/pull/1338 [#1340]: https://github.com/actonlang/acton/pull/1340 [#1341]: https://github.com/actonlang/acton/pull/1341 [#1343]: https://github.com/actonlang/acton/pull/1343 [#1344]: https://github.com/actonlang/acton/pull/1344 [#1345]: https://github.com/actonlang/acton/pull/1345 [#1346]: https://github.com/actonlang/acton/pull/1346 [#1348]: https://github.com/actonlang/acton/pull/1348 [#1349]: https://github.com/actonlang/acton/pull/1349 [#1365]: https://github.com/actonlang/acton/pull/1365 [#1367]: https://github.com/actonlang/acton/pull/1367 [#1371]: https://github.com/actonlang/acton/pull/1371 [#1372]: https://github.com/actonlang/acton/pull/1372 [#1374]: https://github.com/actonlang/acton/pull/1374 [#1382]: https://github.com/actonlang/acton/pull/1382 [#1383]: https://github.com/actonlang/acton/pull/1383 [#1388]: https://github.com/actonlang/acton/pull/1388 [#1390]: https://github.com/actonlang/acton/pull/1390 [#1391]: https://github.com/actonlang/acton/pull/1391 [#1392]: https://github.com/actonlang/acton/pull/1392 [#1395]: https://github.com/actonlang/acton/pull/1395 [#1398]: https://github.com/actonlang/acton/pull/1398 [#1399]: https://github.com/actonlang/acton/pull/1399 [#1402]: https://github.com/actonlang/acton/pull/1402 [#1404]: https://github.com/actonlang/acton/pull/1404 [#1405]: https://github.com/actonlang/acton/pull/1405 [#1406]: https://github.com/actonlang/acton/pull/1406 [#1407]: https://github.com/actonlang/acton/pull/1407 [#1411]: https://github.com/actonlang/acton/pull/1411 [#1415]: https://github.com/actonlang/acton/pull/1415 [#1420]: https://github.com/actonlang/acton/pull/1420 [#1421]: https://github.com/actonlang/acton/pull/1421 [#1422]: https://github.com/actonlang/acton/pull/1422 [#1423]: https://github.com/actonlang/acton/pull/1423 [#1433]: https://github.com/actonlang/acton/pull/1433 [#1435]: https://github.com/actonlang/acton/pull/1435 [#1438]: https://github.com/actonlang/acton/pull/1438 [#1455]: https://github.com/actonlang/acton/pull/1455 [#1456]: https://github.com/actonlang/acton/pull/1456 [#1459]: https://github.com/actonlang/acton/pull/1459 [#1461]: https://github.com/actonlang/acton/pull/1461 [#1463]: https://github.com/actonlang/acton/pull/1463 [#1470]: https://github.com/actonlang/acton/pull/1470 [#1481]: https://github.com/actonlang/acton/pull/1481 [#1483]: https://github.com/actonlang/acton/pull/1483 [#1485]: https://github.com/actonlang/acton/pull/1485 [#1499]: https://github.com/actonlang/acton/pull/1499 [#1500]: https://github.com/actonlang/acton/pull/1500 [#1504]: https://github.com/actonlang/acton/pull/1504 [#1506]: https://github.com/actonlang/acton/pull/1506 [#1510]: https://github.com/actonlang/acton/pull/1510 [#1517]: https://github.com/actonlang/acton/pull/1517 [#1522]: https://github.com/actonlang/acton/pull/1522 [#1524]: https://github.com/actonlang/acton/pull/1524 [#1527]: https://github.com/actonlang/acton/pull/1527 [#1530]: https://github.com/actonlang/acton/pull/1530 [#1536]: https://github.com/actonlang/acton/pull/1536 [#1539]: https://github.com/actonlang/acton/pull/1539 [#1541]: https://github.com/actonlang/acton/pull/1541 [#1545]: https://github.com/actonlang/acton/pull/1545 [#1546]: https://github.com/actonlang/acton/pull/1546 [#1547]: https://github.com/actonlang/acton/pull/1547 [#1551]: https://github.com/actonlang/acton/pull/1551 [#1552]: https://github.com/actonlang/acton/pull/1552 [#1553]: https://github.com/actonlang/acton/pull/1553 [#1554]: https://github.com/actonlang/acton/pull/1554 [#1556]: https://github.com/actonlang/acton/pull/1556 [#1559]: https://github.com/actonlang/acton/pull/1559 [#1560]: https://github.com/actonlang/acton/pull/1560 [#1571]: https://github.com/actonlang/acton/pull/1571 [#1573]: https://github.com/actonlang/acton/pull/1573 [#1577]: https://github.com/actonlang/acton/pull/1577 [#1582]: https://github.com/actonlang/acton/pull/1582 [#1583]: https://github.com/actonlang/acton/pull/1583 [#1586]: https://github.com/actonlang/acton/pull/1586 [#1587]: https://github.com/actonlang/acton/pull/1587 [#1589]: https://github.com/actonlang/acton/pull/1589 [#1591]: https://github.com/actonlang/acton/pull/1591 [#1596]: https://github.com/actonlang/acton/pull/1596 [#1598]: https://github.com/actonlang/acton/pull/1598 [#1600]: https://github.com/actonlang/acton/pull/1600 [#1609]: https://github.com/actonlang/acton/pull/1609 [#1615]: https://github.com/actonlang/acton/pull/1615 [#1617]: https://github.com/actonlang/acton/pull/1617 [#1618]: https://github.com/actonlang/acton/pull/1618 [#1619]: https://github.com/actonlang/acton/pull/1619 [#1627]: https://github.com/actonlang/acton/pull/1627 [#1645]: https://github.com/actonlang/acton/pull/1645 [#1654]: https://github.com/actonlang/acton/pull/1654 [#1655]: https://github.com/actonlang/acton/pull/1655 [#1709]: https://github.com/actonlang/acton/pull/1709 [#1714]: https://github.com/actonlang/acton/pull/1714 [#1715]: https://github.com/actonlang/acton/pull/1715 [#1723]: https://github.com/actonlang/acton/pull/1723 [#1805]: https://github.com/actonlang/acton/pull/1805 [#2255]: https://github.com/actonlang/acton/pull/2255 [#2260]: https://github.com/actonlang/acton/pull/2260 [#2266]: https://github.com/actonlang/acton/pull/2266 [#2267]: https://github.com/actonlang/acton/pull/2267 [#2280]: https://github.com/actonlang/acton/pull/2280 [#2282]: https://github.com/actonlang/acton/pull/2282 [#2285]: https://github.com/actonlang/acton/pull/2285 [#2289]: https://github.com/actonlang/acton/pull/2289 [#2291]: https://github.com/actonlang/acton/pull/2291 [#2298]: https://github.com/actonlang/acton/pull/2298 [#2303]: https://github.com/actonlang/acton/pull/2303 [#2304]: https://github.com/actonlang/acton/pull/2304 [#2308]: https://github.com/actonlang/acton/pull/2308 [#2310]: https://github.com/actonlang/acton/pull/2310 [#2313]: https://github.com/actonlang/acton/pull/2313 [#2317]: https://github.com/actonlang/acton/pull/2317 [#2321]: https://github.com/actonlang/acton/pull/2321 [#2323]: https://github.com/actonlang/acton/pull/2323 [#2327]: https://github.com/actonlang/acton/pull/2327 [#2337]: https://github.com/actonlang/acton/pull/2337 [#2342]: https://github.com/actonlang/acton/pull/2342 [#2348]: https://github.com/actonlang/acton/pull/2348 [#2349]: https://github.com/actonlang/acton/pull/2349 [#2352]: https://github.com/actonlang/acton/pull/2352 [#2354]: https://github.com/actonlang/acton/pull/2354 [#2355]: https://github.com/actonlang/acton/pull/2355 [#2357]: https://github.com/actonlang/acton/pull/2357 [#2358]: https://github.com/actonlang/acton/pull/2358 [#2362]: https://github.com/actonlang/acton/pull/2362 [#2363]: https://github.com/actonlang/acton/pull/2363 [#2365]: https://github.com/actonlang/acton/pull/2365 [#2366]: https://github.com/actonlang/acton/pull/2366 [#2367]: https://github.com/actonlang/acton/pull/2367 [#2370]: https://github.com/actonlang/acton/pull/2370 [#2372]: https://github.com/actonlang/acton/pull/2372 [#2373]: https://github.com/actonlang/acton/pull/2373 [#2382]: https://github.com/actonlang/acton/pull/2382 [#2385]: https://github.com/actonlang/acton/pull/2385 [#2386]: https://github.com/actonlang/acton/pull/2386 [#2388]: https://github.com/actonlang/acton/pull/2388 [#2391]: https://github.com/actonlang/acton/pull/2391 [#2401]: https://github.com/actonlang/acton/pull/2401 [#2405]: https://github.com/actonlang/acton/pull/2405 [#2408]: https://github.com/actonlang/acton/pull/2408 [#2410]: https://github.com/actonlang/acton/pull/2410 [#2413]: https://github.com/actonlang/acton/pull/2413 [#2414]: https://github.com/actonlang/acton/pull/2414 [#2420]: https://github.com/actonlang/acton/pull/2420 [#2421]: https://github.com/actonlang/acton/pull/2421 [#2430]: https://github.com/actonlang/acton/pull/2430 [#2448]: https://github.com/actonlang/acton/pull/2448 [#2453]: https://github.com/actonlang/acton/pull/2453 [#2455]: https://github.com/actonlang/acton/pull/2455 [#2465]: https://github.com/actonlang/acton/pull/2465 [#2475]: https://github.com/actonlang/acton/pull/2475 [#2477]: https://github.com/actonlang/acton/pull/2477 [#2479]: https://github.com/actonlang/acton/pull/2479 [#2480]: https://github.com/actonlang/acton/pull/2480 [#2486]: https://github.com/actonlang/acton/pull/2486 [#2496]: https://github.com/actonlang/acton/pull/2496 [#2508]: https://github.com/actonlang/acton/pull/2508 [#2509]: https://github.com/actonlang/acton/pull/2509 [#2510]: https://github.com/actonlang/acton/pull/2510 [#2512]: https://github.com/actonlang/acton/pull/2512 [#2513]: https://github.com/actonlang/acton/pull/2513 [#2516]: https://github.com/actonlang/acton/pull/2516 [#2517]: https://github.com/actonlang/acton/pull/2517 [#2518]: https://github.com/actonlang/acton/pull/2518 [#2519]: https://github.com/actonlang/acton/pull/2519 [#2520]: https://github.com/actonlang/acton/pull/2520 [#2521]: https://github.com/actonlang/acton/pull/2521 [#2522]: https://github.com/actonlang/acton/pull/2522 [#2530]: https://github.com/actonlang/acton/pull/2530 [#2534]: https://github.com/actonlang/acton/pull/2534 [#2536]: https://github.com/actonlang/acton/pull/2536 [#2541]: https://github.com/actonlang/acton/pull/2541 [#2548]: https://github.com/actonlang/acton/pull/2548 [#2555]: https://github.com/actonlang/acton/pull/2555 [#2557]: https://github.com/actonlang/acton/pull/2557 [#2566]: https://github.com/actonlang/acton/pull/2566 [#2569]: https://github.com/actonlang/acton/pull/2569 [#2571]: https://github.com/actonlang/acton/pull/2571 [#2574]: https://github.com/actonlang/acton/pull/2574 [#2576]: https://github.com/actonlang/acton/pull/2576 [#2584]: https://github.com/actonlang/acton/pull/2584 [#2585]: https://github.com/actonlang/acton/pull/2585 [#2588]: https://github.com/actonlang/acton/pull/2588 [#2589]: https://github.com/actonlang/acton/pull/2589 [#2593]: https://github.com/actonlang/acton/pull/2593 [#2595]: https://github.com/actonlang/acton/pull/2595 [#2597]: https://github.com/actonlang/acton/pull/2597 [#2598]: https://github.com/actonlang/acton/pull/2598 [#2605]: https://github.com/actonlang/acton/pull/2605 [#2607]: https://github.com/actonlang/acton/pull/2607 [#2610]: https://github.com/actonlang/acton/pull/2610 [#2613]: https://github.com/actonlang/acton/pull/2613 [#2615]: https://github.com/actonlang/acton/pull/2615 [#2616]: https://github.com/actonlang/acton/pull/2616 [#2617]: https://github.com/actonlang/acton/pull/2617 [#2620]: https://github.com/actonlang/acton/pull/2620 [#2623]: https://github.com/actonlang/acton/pull/2623 [#2629]: https://github.com/actonlang/acton/pull/2629 [#2632]: https://github.com/actonlang/acton/pull/2632 [#2633]: https://github.com/actonlang/acton/pull/2633 [#2636]: https://github.com/actonlang/acton/pull/2636 [#2637]: https://github.com/actonlang/acton/pull/2637 [#2638]: https://github.com/actonlang/acton/pull/2638 [#2640]: https://github.com/actonlang/acton/pull/2640 [#2641]: https://github.com/actonlang/acton/pull/2641 [#2651]: https://github.com/actonlang/acton/pull/2651 [#2655]: https://github.com/actonlang/acton/pull/2655 [#2656]: https://github.com/actonlang/acton/pull/2656 [#2664]: https://github.com/actonlang/acton/pull/2664 [#2666]: https://github.com/actonlang/acton/pull/2666 [#2668]: https://github.com/actonlang/acton/pull/2668 [#2674]: https://github.com/actonlang/acton/pull/2674 [#2676]: https://github.com/actonlang/acton/pull/2676 [#2677]: https://github.com/actonlang/acton/pull/2677 [#2678]: https://github.com/actonlang/acton/pull/2678 [#2683]: https://github.com/actonlang/acton/pull/2683 [#2689]: https://github.com/actonlang/acton/pull/2689 [#2693]: https://github.com/actonlang/acton/pull/2693 [#2695]: https://github.com/actonlang/acton/pull/2695 [#2698]: https://github.com/actonlang/acton/pull/2698 [#2700]: https://github.com/actonlang/acton/pull/2700 [#2701]: https://github.com/actonlang/acton/pull/2701 [#2705]: https://github.com/actonlang/acton/pull/2705 [#2719]: https://github.com/actonlang/acton/pull/2719 [#2727]: https://github.com/actonlang/acton/pull/2727 [#2728]: https://github.com/actonlang/acton/pull/2728 [#2729]: https://github.com/actonlang/acton/pull/2729 [#2739]: https://github.com/actonlang/acton/pull/2739 [#2742]: https://github.com/actonlang/acton/pull/2742 [#2745]: https://github.com/actonlang/acton/pull/2745 [#2746]: https://github.com/actonlang/acton/pull/2746 [#2748]: https://github.com/actonlang/acton/pull/2748 [#2749]: https://github.com/actonlang/acton/pull/2749 [#2751]: https://github.com/actonlang/acton/pull/2751 [#2761]: https://github.com/actonlang/acton/pull/2761 [#2767]: https://github.com/actonlang/acton/pull/2767 [#2773]: https://github.com/actonlang/acton/pull/2773 [#2774]: https://github.com/actonlang/acton/pull/2774 [#2777]: https://github.com/actonlang/acton/pull/2777 [#2779]: https://github.com/actonlang/acton/pull/2779 [#2781]: https://github.com/actonlang/acton/pull/2781 [#2782]: https://github.com/actonlang/acton/pull/2782 [#2783]: https://github.com/actonlang/acton/pull/2783 [#2784]: https://github.com/actonlang/acton/pull/2784 [#2787]: https://github.com/actonlang/acton/pull/2787 [#2789]: https://github.com/actonlang/acton/pull/2789 [#2794]: https://github.com/actonlang/acton/pull/2794 [#2796]: https://github.com/actonlang/acton/pull/2796 [#2797]: https://github.com/actonlang/acton/pull/2797 [0.3.0]: https://github.com/actonlang/acton/releases/tag/v0.3.0 [0.4.0]: https://github.com/actonlang/acton/compare/v0.3.0...v0.4.0 [0.4.1]: https://github.com/actonlang/acton/compare/v0.4.0...v0.4.1 [0.4.2]: https://github.com/actonlang/acton/compare/v0.4.1...v0.4.2 [0.5.0]: https://github.com/actonlang/acton/compare/v0.4.2...v0.5.0 [0.5.1]: https://github.com/actonlang/acton/compare/v0.5.0...v0.5.1 [0.5.2]: https://github.com/actonlang/acton/compare/v0.5.1...v0.5.2 [0.5.3]: https://github.com/actonlang/acton/compare/v0.5.2...v0.5.3 [0.6.0]: https://github.com/actonlang/acton/compare/v0.5.3...v0.6.0 [0.6.1]: https://github.com/actonlang/acton/compare/v0.6.0...v0.6.1 [0.6.2]: https://github.com/actonlang/acton/compare/v0.6.1...v0.6.2 [0.6.3]: https://github.com/actonlang/acton/compare/v0.6.2...v0.6.3 [0.6.4]: https://github.com/actonlang/acton/compare/v0.6.3...v0.6.4 [0.7.0]: https://github.com/actonlang/acton/compare/v0.6.4...v0.7.0 [0.7.1]: https://github.com/actonlang/acton/compare/v0.7.0...v0.7.1 [0.7.2]: https://github.com/actonlang/acton/compare/v0.7.1...v0.7.2 [0.7.3]: https://github.com/actonlang/acton/compare/v0.7.2...v0.7.3 [0.7.4]: https://github.com/actonlang/acton/compare/v0.7.3...v0.7.4 [0.8.0]: https://github.com/actonlang/acton/compare/v0.7.4...v0.8.0 [0.9.0]: https://github.com/actonlang/acton/compare/v0.8.0...v0.9.0 [0.9.1]: https://github.com/actonlang/acton/compare/v0.9.0...v0.9.1 [0.10.0]: https://github.com/actonlang/acton/compare/v0.9.1...v0.10.0 [0.11.0]: https://github.com/actonlang/acton/compare/v0.10.0...v0.11.0 [0.11.1]: https://github.com/actonlang/acton/compare/v0.11.0...v0.11.1 [0.11.2]: https://github.com/actonlang/acton/compare/v0.11.1...v0.11.2 [0.11.3]: https://github.com/actonlang/acton/compare/v0.11.2...v0.11.3 [0.11.4]: https://github.com/actonlang/acton/compare/v0.11.3...v0.11.4 [0.11.5]: https://github.com/actonlang/acton/compare/v0.11.4...v0.11.5 [0.11.6]: https://github.com/actonlang/acton/compare/v0.11.5...v0.11.6 [0.11.7]: https://github.com/actonlang/acton/compare/v0.11.6...v0.11.7 [0.12.0]: https://github.com/actonlang/acton/compare/v0.11.7...v0.12.0 [0.13.0]: https://github.com/actonlang/acton/compare/v0.12.0...v0.13.0 [0.13.1]: https://github.com/actonlang/acton/compare/v0.13.0...v0.13.1 [0.14.0]: https://github.com/actonlang/acton/compare/v0.13.1...v0.14.0 [0.15.0]: https://github.com/actonlang/acton/compare/v0.14.0...v0.15.0 [0.16.0]: https://github.com/actonlang/acton/compare/v0.15.0...v0.16.0 [0.16.1]: https://github.com/actonlang/acton/compare/v0.16.0...v0.16.1 [0.16.2]: https://github.com/actonlang/acton/compare/v0.16.1...v0.16.2 [0.16.3]: https://github.com/actonlang/acton/compare/v0.16.2...v0.16.3 [0.16.4]: https://github.com/actonlang/acton/compare/v0.16.3...v0.16.4 [0.16.5]: https://github.com/actonlang/acton/compare/v0.16.4...v0.16.5 [0.16.6]: https://github.com/actonlang/acton/compare/v0.16.5...v0.16.6 [0.16.7]: https://github.com/actonlang/acton/compare/v0.16.6...v0.16.7 [0.16.8]: https://github.com/actonlang/acton/compare/v0.16.7...v0.16.8 [0.16.9]: https://github.com/actonlang/acton/compare/v0.16.8...v0.16.9 [0.16.10]: https://github.com/actonlang/acton/compare/v0.16.9...v0.16.10 [0.16.11]: https://github.com/actonlang/acton/compare/v0.16.10...v0.16.11 [0.16.12]: https://github.com/actonlang/acton/compare/v0.16.11...v0.16.12 [0.16.13]: https://github.com/actonlang/acton/compare/v0.16.12...v0.16.13 [0.17.0]: https://github.com/actonlang/acton/compare/v0.16.13...v0.17.0 [0.17.1]: https://github.com/actonlang/acton/compare/v0.17.0...v0.17.1 [0.17.2]: https://github.com/actonlang/acton/compare/v0.17.1...v0.17.2 [0.17.3]: https://github.com/actonlang/acton/compare/v0.17.2...v0.17.3 [0.17.4]: https://github.com/actonlang/acton/compare/v0.17.3...v0.17.4 [0.17.5]: https://github.com/actonlang/acton/compare/v0.17.4...v0.17.5 [0.17.6]: https://github.com/actonlang/acton/compare/v0.17.5...v0.17.6 [0.17.7]: https://github.com/actonlang/acton/compare/v0.17.6...v0.17.7 [0.17.8]: https://github.com/actonlang/acton/compare/v0.17.7...v0.17.8 [0.17.9]: https://github.com/actonlang/acton/compare/v0.17.8...v0.17.9 [0.17.10]: https://github.com/actonlang/acton/compare/v0.17.9...v0.17.10 [0.17.11]: https://github.com/actonlang/acton/compare/v0.17.10...v0.17.11 [0.17.12]: https://github.com/actonlang/acton/compare/v0.17.11...v0.17.12 [0.18.0]: https://github.com/actonlang/acton/compare/v0.17.12...v0.18.0 [0.18.1]: https://github.com/actonlang/acton/compare/v0.18.0...v0.18.1 [0.18.2]: https://github.com/actonlang/acton/compare/v0.18.1...v0.18.2 [0.19.0]: https://github.com/actonlang/acton/compare/v0.18.2...v0.19.0 [0.19.1]: https://github.com/actonlang/acton/compare/v0.19.0...v0.19.1 [0.19.2]: https://github.com/actonlang/acton/compare/v0.19.1...v0.19.2 [0.19.3]: https://github.com/actonlang/acton/compare/v0.19.2...v0.19.3 [0.19.4]: https://github.com/actonlang/acton/compare/v0.19.3...v0.19.4 [0.19.5]: https://github.com/actonlang/acton/compare/v0.19.4...v0.19.5 [0.20.0]: https://github.com/actonlang/acton/compare/v0.19.5...v0.20.0 [0.20.1]: https://github.com/actonlang/acton/compare/v0.20.0...v0.20.1 [0.20.2]: https://github.com/actonlang/acton/compare/v0.20.1...v0.20.2 [0.20.3]: https://github.com/actonlang/acton/compare/v0.20.2...v0.20.3 [0.20.4]: https://github.com/actonlang/acton/compare/v0.20.3...v0.20.4 [0.20.5]: https://github.com/actonlang/acton/compare/v0.20.4...v0.20.5 [0.20.6]: https://github.com/actonlang/acton/compare/v0.20.5...v0.20.6 [0.20.7]: https://github.com/actonlang/acton/compare/v0.20.6...v0.20.7 [0.20.8]: https://github.com/actonlang/acton/compare/v0.20.7...v0.20.8 [0.20.9]: https://github.com/actonlang/acton/compare/v0.20.8...v0.20.9 [0.20.10]: https://github.com/actonlang/acton/compare/v0.20.9...v0.20.10 [0.20.11]: https://github.com/actonlang/acton/compare/v0.20.10...v0.20.11 [0.20.12]: https://github.com/actonlang/acton/compare/v0.20.11...v0.20.12 [0.20.13]: https://github.com/actonlang/acton/compare/v0.20.12...v0.20.13 [0.20.14]: https://github.com/actonlang/acton/compare/v0.20.13...v0.20.14 [0.20.15]: https://github.com/actonlang/acton/compare/v0.20.14...v0.20.15 [0.20.16]: https://github.com/actonlang/acton/compare/v0.20.15...v0.20.16 [0.20.17]: https://github.com/actonlang/acton/compare/v0.20.16...v0.20.17 [0.20.18]: https://github.com/actonlang/acton/compare/v0.20.17...v0.20.18 [0.20.19]: https://github.com/actonlang/acton/compare/v0.20.18...v0.20.19 [0.20.20]: https://github.com/actonlang/acton/compare/v0.20.19...v0.20.20 [0.20.21]: https://github.com/actonlang/acton/compare/v0.20.20...v0.20.21 [0.20.22]: https://github.com/actonlang/acton/compare/v0.20.21...v0.20.22 [0.20.23]: https://github.com/actonlang/acton/compare/v0.20.22...v0.20.23 [0.20.24]: https://github.com/actonlang/acton/compare/v0.20.23...v0.20.24 [0.20.25]: https://github.com/actonlang/acton/compare/v0.20.24...v0.20.25 [0.20.26]: https://github.com/actonlang/acton/compare/v0.20.25...v0.20.26 [0.20.27]: https://github.com/actonlang/acton/compare/v0.20.26...v0.20.27 [0.20.28]: https://github.com/actonlang/acton/compare/v0.20.27...v0.20.28 [0.20.29]: https://github.com/actonlang/acton/compare/v0.20.28...v0.20.29 [0.20.30]: https://github.com/actonlang/acton/compare/v0.20.29...v0.20.30 [0.20.31]: https://github.com/actonlang/acton/compare/v0.20.30...v0.20.31 [0.20.32]: https://github.com/actonlang/acton/compare/v0.20.31...v0.20.32 [0.20.33]: https://github.com/actonlang/acton/compare/v0.20.32...v0.20.33 [0.20.34]: https://github.com/actonlang/acton/compare/v0.20.33...v0.20.34 [0.21.0]: https://github.com/actonlang/acton/compare/v0.20.34...v0.21.0 [0.21.1]: https://github.com/actonlang/acton/compare/v0.21.0...v0.21.1 [0.21.2]: https://github.com/actonlang/acton/compare/v0.21.1...v0.21.2 [0.21.3]: https://github.com/actonlang/acton/compare/v0.21.2...v0.21.3 [0.22.0]: https://github.com/actonlang/acton/compare/v0.21.3...v0.22.0 [0.23.0]: https://github.com/actonlang/acton/compare/v0.22.0...v0.23.0 [0.23.1]: https://github.com/actonlang/acton/compare/v0.23.0...v0.23.1 [0.23.2]: https://github.com/actonlang/acton/compare/v0.23.1...v0.23.2 [0.23.3]: https://github.com/actonlang/acton/compare/v0.23.2...v0.23.3 [0.23.4]: https://github.com/actonlang/acton/compare/v0.23.3...v0.23.4 [0.23.5]: https://github.com/actonlang/acton/compare/v0.23.4...v0.23.5 [0.23.6]: https://github.com/actonlang/acton/compare/v0.23.5...v0.23.6 [0.23.7]: https://github.com/actonlang/acton/compare/v0.23.6...v0.23.7 [0.23.8]: https://github.com/actonlang/acton/compare/v0.23.7...v0.23.8 [0.23.9]: https://github.com/actonlang/acton/compare/v0.23.8...v0.23.9 [0.23.10]: https://github.com/actonlang/acton/compare/v0.23.9...v0.23.10 [0.23.11]: https://github.com/actonlang/acton/compare/v0.23.10...v0.23.11 [0.23.12]: https://github.com/actonlang/acton/compare/v0.23.11...v0.23.12 [0.23.13]: https://github.com/actonlang/acton/compare/v0.23.12...v0.23.13 [0.23.14]: https://github.com/actonlang/acton/compare/v0.23.13...v0.23.14 [0.23.15]: https://github.com/actonlang/acton/compare/v0.23.14...v0.23.15 [0.23.16]: https://github.com/actonlang/acton/compare/v0.23.15...v0.23.16 [0.23.17]: https://github.com/actonlang/acton/compare/v0.23.16...v0.23.17 [0.23.18]: https://github.com/actonlang/acton/compare/v0.23.17...v0.23.18 [0.23.19]: https://github.com/actonlang/acton/compare/v0.23.18...v0.23.19 [0.23.20]: https://github.com/actonlang/acton/compare/v0.23.19...v0.23.20 [0.23.21]: https://github.com/actonlang/acton/compare/v0.23.20...v0.23.21 [0.24.0]: https://github.com/actonlang/acton/compare/v0.23.21...v0.24.0 [0.24.1]: https://github.com/actonlang/acton/compare/v0.24.0...v0.24.1 [0.25.0]: https://github.com/actonlang/acton/compare/v0.24.1...v0.25.0 [0.26.0]: https://github.com/actonlang/acton/compare/v0.25.0...v0.26.0 [0.27.0]: https://github.com/actonlang/acton/compare/v0.26.0...v0.27.0 [homebrew-acton#7]: https://github.com/actonlang/homebrew-acton/pull/7 [homebrew-acton#28]: https://github.com/actonlang/homebrew-acton/pull/28 ================================================ FILE: CLAUDE.md ================================================ # Acton Programming Language - Development Guide Acton is an actor-based programming language with distributed computing capabilities. This guide helps AI assistants understand the codebase structure and development practices. ## Quick Start ### Essential Build Commands ```bash make # Build everything make dist/bin/acton # Build only the compiler (faster when working on compiler) make test # Run all tests make test-compiler # Run compiler tests only dist/bin/acton build # Build an Acton project dist/bin/acton test # Test an Acton project ``` ### Key Binaries - `dist/bin/acton` - The Acton compiler and CLI (project management, testing) - `dist/bin/actonc` - Compatibility symlink to `acton` ## Repository Overview ``` acton/ ├── compiler/ # Haskell-based compiler → [See compiler/CLAUDE.md] ├── base/ # Standard library & RTS → [See base/CLAUDE.md] ├── backend/ # Distributed runtime → [See backend/CLAUDE.md] ├── ecolift/ # Ecosystem lift process → [See ecolift/CLAUDE.md] ├── test/ # Test suites ├── docs/ # Documentation (mdBook) └── build.zig # Main build configuration ``` ## Component-Specific Guides For detailed information about each component, see: - **[compiler/CLAUDE.md](compiler/CLAUDE.md)** - Haskell compiler architecture, compilation pipeline - **[base/CLAUDE.md](base/CLAUDE.md)** - Standard library modules, RTS, builtins - **[backend/CLAUDE.md](backend/CLAUDE.md)** - Distributed database, actor persistence - **[ecolift/CLAUDE.md](ecolift/CLAUDE.md)** - Ecosystem lift process for external repositories ## Language Concepts ### Actor Model - Actors are concurrent entities with private state - Communication via asynchronous message passing - No shared memory between actors - Actors can be distributed across nodes ### Type System - Static typing with type inference - Python-inspired syntax - Support for generics - Protocol-based polymorphism (similar to interfaces) ## Code Style Guidelines ### Acton Code ```acton # Variables and functions: snake_case def calculate_sum(values: list[int]) -> int: return sum(values) # Classes and types: PascalCase class DataProcessor: def process(self, data: str) -> None: pass # Actors: PascalCase actor WorkerActor: def handle_request(self, req: Request) -> None: pass ``` ### Haskell Code (Compiler) ```haskell -- Functions: camelCase parseExpression :: Parser Expression -- Types: PascalCase data AstNode = Literal Int | Variable String -- Explicit type signatures always -- 2-space indentation for some functions -- "Whiteboard layout" for other functions where very deep indent is used to lay out expressions almost like one would when writing beautiful math expressions on a whiteboard ``` ### C Code (RTS/Backend) ```c // Functions: snake_case with module prefix int rts_actor_create(rts_actor_t *actor); // Macros/Constants: UPPER_CASE #define MAX_ACTORS 1024 // Structs: snake_case with _t suffix typedef struct actor_state_t { // ... } actor_state_t; ``` ## Testing Philosophy 1. **Comprehensive Coverage**: Every feature should have tests 2. **Snapshot Tests**: For compiler error messages and output 3. **Performance Tests**: Track performance regressions 4. **Integration Tests**: Test distributed features ## Common Development Tasks ### Adding a New Builtin Type 1. Implement C code in `base/builtin/` 2. Add Acton interface in `base/src/__builtin__.act` 3. Update compiler type system if needed 4. Add tests in `test/builtins_auto/` ### Adding a Standard Library Module 1. Create `.act` file in `base/src/` 2. Add C extension in `.ext.c` if needed 3. Update `base/Build.act` 4. Add module tests ### Modifying the Compiler 1. Work in `compiler/lib/src/Acton/` 2. Run `make dist/bin/acton` for quick rebuilds 3. Add test cases in `compiler/acton/test/` 4. Update snapshot files if error messages change ## Build System - Uses Zig build system (`build.zig` files) - Integrates Haskell (Stack), C, and Acton compilation - Supports cross-compilation - Package management via `Build.act` files ## Important Files - `Makefile` - Top-level build orchestration - `build.zig` - Main Zig build configuration - `compiler/stack.yaml` - Haskell dependencies - `*/Build.act` - Acton package configurations ## Debugging Tips 1. **Compiler Issues**: Enable verbose output with `--debug` 2. **Runtime Issues**: Use `ACTON_LOG_LEVEL=debug` 3. **Actor Issues**: Monitor with `actonmon` utility 4. **Memory Issues**: Built-in GC statistics available ## Contributing Guidelines 1. Follow existing code style in each language 2. Add tests for new features 3. Update documentation as needed 4. Ensure `make test` passes before submitting changes 5. Keep commits focused and well-described For detailed development workflow and release procedures, see [docs/dev.md](docs/dev.md) ## Git Commit Guidelines When making commits: - Do not include AI assistant attribution (no "Generated with Claude", co-authored-by or similar) - Write commit messages as if you wrote the code yourself - Focus on what the change does, not how it was created - Try hard to use short summary messages (< 50 chars) - **NEVER use `git add -A` or `git add .`** - always add files deliberately - Be careful not to add generated files (like `package.yaml` which are generated from `.in` templates) ## Release Process ### Creating a New Release 1. **Create release branch**: Use format `release-vX.Y.Z` (note the `v` prefix!) ```bash git checkout -b release-v0.26.0 ``` 2. **Update version files**: - `version.mk` - Update VERSION (this controls the version for the entire project) - Note: Do NOT manually edit `package.yaml` files - they are generated from `package.yaml.in` templates 3. **Update CHANGELOG.md**: - Add new version section with **today's date** (format: YYYY-MM-DD) - Organize changes under: Added, Changed, Fixed, Documentation, Testing/CI - Add PR links for all referenced PRs at the bottom - Add version comparison link 4. **Create and merge PR**: ```bash git push -u origin release-vX.Y.Z gh pr create --title "Release vX.Y.Z" ``` 5. **After PR merge**: - Create and push tag: `git tag vX.Y.Z && git push origin vX.Y.Z` - GitHub Actions will automatically create the release - Update Homebrew formula if needed ### Important Release Notes - Always use `release-v` prefix for release branches (not just `release-`) - Always use today's date in the changelog (not a future or past date) - The changelog update process is documented in `docs/dev.md` ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Acton Hi and thanks for your interest in contributing to Acton! It is possible to contribute in many ways and all contributions are appreciated! # Questions Use [GitHub discussions](https://github.com/actonlang/acton/discussions) to ask questions. Search existing questions to avoid duplicates. # Bug reporting and feature requests Found a bug? Have an idea for a possible improvement? Open an [issue on Github](https://github.com/actonlang/acton/issues/new)! Please search existing issues to avoid creating duplicate issues. Try and write a good concise subject. Include all relevant information in the issue description. # Submitting code Code contributions are generally welcome. Submit your code as a pull request (PR) on the [GitHub project](https://github.com/actonlang/acton). Before writing too much code, please open an issue to ensure that your intended changes or fixes are aligned with the overall direction of the project. This can save everyone's time :) ================================================ FILE: Containerfile ================================================ FROM debian:13 MAINTAINER Kristian Larsson COPY dist/ /usr/lib/acton/ RUN cd /usr/bin \ && ln -sf ../lib/acton/bin/acton \ && ln -sf ../lib/acton/bin/actonc \ && ln -sf ../lib/acton/bin/actondb \ && ln -sf ../lib/acton/bin/runacton ENTRYPOINT ["/usr/bin/acton"] ================================================ FILE: Containerfile.deb ================================================ FROM debian:13 MAINTAINER Kristian Larsson ARG TARGETARCH COPY deb/acton_*${TARGETARCH}.deb /tmp/acton.deb RUN apt-get update \ && apt-get install -y --no-install-recommends /tmp/acton.deb \ && rm /tmp/acton.deb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* ENTRYPOINT ["/usr/bin/acton"] ================================================ FILE: LICENSE ================================================ Copyright (C) 2019-2021 Data Ductus AB Copyright (C) 2019-2021 Deutsche Telekom AG Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: Makefile ================================================ include version.mk TD := $(CURDIR) CHANGELOG_VERSION=$(shell grep '^\#\# \[[0-9]' CHANGELOG.md | sed 's/\#\# \[\([^]]\{1,\}\)].*/\1/' | head -n1) GIT_VERSION_TAG=$(shell git tag --points-at HEAD 2>/dev/null | grep "v[0-9]" | sed -e 's/^v//') ifdef HOME ZIG_LOCAL_CACHE_DIR ?= $(HOME)/.cache/acton/zig-local-cache ZIG_GLOBAL_CACHE_DIR ?= $(HOME)/.cache/acton/zig-global-cache else # TODO: Windows? ZIG_LOCAL_CACHE_DIR ?= $(TD)/zig-cache ZIG_GLOBAL_CACHE_DIR ?= $(TD)/zig-global-cache endif export ZIG_LOCAL_CACHE_DIR export ZIG_GLOBAL_CACHE_DIR ACTON=$(TD)/dist/bin/acton ACTONC=dist/bin/actonc ZIG_VERSION:=0.15.2 ZIG=$(TD)/dist/zig/zig CURL:=curl --fail --location --retry 5 --retry-delay 2 --retry-max-time 120 --retry-all-errors --retry-connrefused AR=$(ZIG) ar CC=$(ZIG) cc CXX=$(ZIG) c++ export CC export CXX ACTON_STACK_CC=$(TD)/compiler/tools/zig-cc.sh ACTON_STACK_CXX=$(TD)/compiler/tools/zig-cxx.sh ACTON_STACK_NEEDS_ZIG= ACTON_ZIG_TARGET= STACK=unset CC && unset CXX && unset CFLAGS && unset CPPFLAGS && unset LDFLAGS && unset ACTON_REAL_LD && stack # Determine which xargs we have. BSD xargs does not have --no-run-if-empty, # rather, it is the default behavior so the argument is superfluous. We check if # we are using GNU xargs by trying to run xargs --version and grep for 'GNU', if # that returns 0 we are on GNU and will use 'xargs --no-run-if-empty', otherwise # we are on BSD and will use 'xargs' straight up. XARGS_CHECK := $(shell xargs --version 2>&1 | grep GNU >/dev/null 2>&1; echo $$?) ifeq ($(XARGS_CHECK),0) XARGS := xargs --no-run-if-empty else XARGS := xargs endif # This is the version we will stamp into acton BUILD_TIME=$(shell date "+%Y%m%d.%-H.%-M.%-S") ifdef BUILD_RELEASE export VERSION_INFO?=$(VERSION) export DEB_DIST=stable export CONTAINER_TAG?=$(VERSION) else export VERSION_INFO?=$(VERSION).$(BUILD_TIME) export DEB_DIST=tip export CONTAINER_TAG?=tip endif ifdef CPEDANTIC CPEDANTIC=--cpedantic endif PROFILE ?= 0 ACTON_STACK_BUILD_OPTS := $(STACK_OPTS) ifeq ($(PROFILE),1) ACTON_STACK_BUILD_OPTS += --profile --library-profiling --executable-profiling ACTC_GHC_OPTS += -fprof-auto -fprof-cafs endif # rewrite arm64 to aarch64 ifeq ($(shell uname -m),arm64) ARCH:=aarch64 else ARCH:=$(shell uname -m) endif # -- Apple Mac OS X ------------------------------------------------------------ ifeq ($(shell uname -s),Darwin) OS:=macos endif # -- Linux --------------------------------------------------------------------- ifeq ($(shell uname -s),Linux) OS:=linux ACTON_ZIG_GLIBC_VERSION ?= 2.31 export ACTON_ZIG_GLIBC_VERSION ACTON_STACK_NEEDS_ZIG=1 STACK=CC="$(ACTON_STACK_CC)" CXX="$(ACTON_STACK_CXX)" CFLAGS= CPPFLAGS= LDFLAGS= ACTON_REAL_LD="$(ACTON_STACK_CC)" stack --with-gcc="$(ACTON_STACK_CC)" ifeq ($(shell uname -m),x86_64) ACTON_ZIG_TARGET := x86_64-linux-gnu.$(ACTON_ZIG_GLIBC_VERSION) else ifeq ($(shell uname -m),aarch64) ACTON_ZIG_TARGET := aarch64-linux-gnu.$(ACTON_ZIG_GLIBC_VERSION) else $(error "Unsupported architecture for Linux?" $(shell uname -m)) endif ACTONC_TARGET := --target $(ACTON_ZIG_TARGET) endif # -- END: Linux ---------------------------------------------------------- .PHONY: all all: version-check $(MAKE) $(DIST_ZIG) $(MAKE) distribution .PHONY: help help: @echo "Available make targets:" @echo " all - build everything" @echo " test - run the test suite" @echo " make PROFILE=1 dist/bin/acton - build profiled acton binary" @echo "" @echo " clean - /normal/ clean repo" @echo " clean-all - thorough cleaning" @echo " clean-downloads - remove downloaded deps, normally never needed?" .PHONY: version-check version-check: ifneq ($(VERSION), $(CHANGELOG_VERSION)) $(error Version in version.mk ($(VERSION)) differs from last version in CHANGELOG.md ($(CHANGELOG_VERSION))) endif ifneq ($(GIT_VERSION_TAG),) # if we are on a git tag.. ifneq ($(VERSION),$(GIT_VERSION_TAG)) # ..ensure the git tag is same as version in version.mk $(error Current git tag ($(GIT_VERSION_TAG)) differs from version in version.mk ($(VERSION))) endif endif BUILTIN_HFILES=$(wildcard base/builtin/*.h) DIST_BINS=$(ACTONC) dist/bin/actondb dist/bin/runacton dist/bin/lsp-server-acton DIST_ZIG=dist/zig ifeq ($(ACTON_STACK_NEEDS_ZIG),1) ACTON_STACK_PREREQS=$(DIST_ZIG) else ACTON_STACK_PREREQS= endif .PHONY: test-backend test-backend: $(BACKEND_TESTS) @echo DISABLED TEST: backend/failure_detector/db_messages_test ./backend/test/actor_ring_tests_local ./backend/test/actor_ring_tests_remote ./backend/test/db_unit_tests @echo DISABLED test: ./backend/test/queue_unit_tests ./backend/test/skiplist_test # /compiler ---------------------------------------------- ACTONC_HS=$(wildcard compiler/lib/src/*.hs compiler/lib/src/*/*.hs compiler/acton/*.hs compiler/acton/*/*.hs) ACTONLSP_HS=$(wildcard compiler/lsp-server/*.hs) dist/bin/acton: compiler/lib/package.yaml.in compiler/acton/package.yaml.in compiler/lsp-server/package.yaml.in compiler/stack.yaml $(ACTONC_HS) $(ACTONLSP_HS) version.mk dist/builder $(ACTON_STACK_PREREQS) mkdir -p dist/bin rm -f dist/bin/actonc cd compiler && sed 's,^version: BUILD_VERSION,version: "$(VERSION)",' < lib/package.yaml.in > lib/package.yaml cd compiler && $(STACK) build acton lsp-server-acton $(ACTON_STACK_BUILD_OPTS) --ghc-options='-j4 $(ACTC_GHC_OPTS)' --dry-run 2>&1 | grep "Nothing to build" || \ (sed 's,^version: BUILD_VERSION,version: "$(VERSION_INFO)",' < acton/package.yaml.in > acton/package.yaml \ && sed 's,^version: BUILD_VERSION,version: "$(VERSION_INFO)",' < lsp-server/package.yaml.in > lsp-server/package.yaml \ && unset CC && unset CXX && unset CFLAGS && unset CPPFLAGS && unset LDFLAGS && unset ACTON_REAL_LD && stack setup \ && $(STACK) build acton lsp-server-acton $(ACTON_STACK_BUILD_OPTS) --ghc-options='-j4 $(ACTC_GHC_OPTS)') cd compiler && $(STACK) --local-bin-path=../dist/bin install acton lsp-server-acton $(ACTON_STACK_BUILD_OPTS) --ghc-options='-j4 $(ACTC_GHC_OPTS)' # Keep actonc as a symlink for compatibility ln -sf acton dist/bin/actonc dist/bin/actonc: dist/bin/acton @mkdir -p $(dir $@) ln -sf acton $@ dist/bin/lsp-server-acton: dist/bin/acton @true .PHONY: clean-compiler clean-compiler: cd compiler && stack clean >/dev/null 2>&1 || true rm -f dist/bin/acton dist/bin/actonc compiler/package.yaml compiler/acton.cabal \ compiler/acton/package.yaml compiler/acton/acton.cabal \ compiler/lib/*.cabal compiler/acton/*.cabal compiler/lsp-server/*.cabal ACTON_LINKAGE_BINS ?= dist/bin/acton dist/bin/lsp-server-acton dist/bin/actondb ACTON_ALLOWED_NEEDED_RE ?= ^(libc\.so\.6|libm\.so\.6|libdl\.so\.2|libpthread\.so\.0|librt\.so\.1|libutil\.so\.1|ld-linux-x86-64\.so\.2|ld-linux-aarch64\.so\.1)$$ .PHONY: ldd ldd: $(ACTON_LINKAGE_BINS) ifeq ($(OS),linux) @for bin in $(ACTON_LINKAGE_BINS); do \ echo "== $$bin =="; \ ldd "$$bin"; \ if command -v readelf >/dev/null 2>&1; then \ unexpected_needed=$$(readelf -d "$$bin" | sed -n 's/.*Shared library: \[\(.*\)\].*/\1/p' | grep -Ev '$(ACTON_ALLOWED_NEEDED_RE)' || true); \ if [ -n "$$unexpected_needed" ]; then \ echo "unexpected dynamic libraries:" >&2; \ echo "$$unexpected_needed" >&2; \ exit 1; \ fi; \ max_glibc=$$(readelf --version-info "$$bin" | grep -o 'GLIBC_[0-9][.0-9]*' | sed 's/GLIBC_//' | sort -Vu | tail -n 1); \ if [ -n "$$max_glibc" ]; then \ echo "max GLIBC version required: $$max_glibc"; \ if [ "$$(printf '%s\n%s\n' "$$max_glibc" "$(ACTON_ZIG_GLIBC_VERSION)" | sort -V | tail -n 1)" != "$(ACTON_ZIG_GLIBC_VERSION)" ]; then \ echo "ERROR: $$bin requires GLIBC $$max_glibc, newer than target $(ACTON_ZIG_GLIBC_VERSION)" >&2; \ exit 1; \ fi; \ fi; \ fi; \ done else @echo "ldd target is only meaningful on Linux" endif # /deps -------------------------------------------------- DEPS += dist/deps/mbedtls DEPS += dist/deps/libargp DEPS += dist/deps/libbsdnt DEPS += dist/deps/libgc DEPS += dist/deps/libnetstring DEPS += dist/deps/pcre2 DEPS += dist/deps/libprotobuf_c DEPS += dist/deps/tlsuv DEPS += dist/deps/libutf8proc DEPS += dist/deps/libuuid DEPS += dist/deps/libuv DEPS += dist/deps/libxml2 DEPS += dist/deps/libyyjson DEPS += dist/deps/libsnappy_c .PHONE: clean-downloads clean-downloads: rm -rf deps-download # /deps/libargp -------------------------------------------- LIBARGP_REF=137154fb257055beb11f3283021d8eccc3c4f470 deps-download/$(LIBARGP_REF).tar.gz: mkdir -p deps-download $(CURL) -o $@ https://github.com/actonlang/argp-standalone/archive/$(LIBARGP_REF).tar.gz dist/deps/libargp: deps-download/$(LIBARGP_REF).tar.gz mkdir -p "$@" cd "$@" && tar zx --strip-components=1 -f "$(TD)/$<" rm -rf "$@/testsuite" touch "$(TD)/$@" # /deps/libbsdnt -------------------------------------------- LIBBSDNT_REF=cf7db3414867b8b4a5561bc9aa94a8050d0225c4 deps-download/$(LIBBSDNT_REF).tar.gz: mkdir -p deps-download $(CURL) -o $@ https://github.com/actonlang/bsdnt/archive/$(LIBBSDNT_REF).tar.gz dist/deps/libbsdnt: deps-download/$(LIBBSDNT_REF).tar.gz mkdir -p "$@" cd "$@" && tar zx --strip-components=1 -f "$(TD)/$<" touch "$(TD)/$@" # /deps/libgc -------------------------------------------- LIBGC_REF=5ef334ab8f9ef9e23d6b9c99fbd2b621bd52789b deps-download/$(LIBGC_REF).tar.gz: mkdir -p deps-download $(CURL) -o $@ https://github.com/actonlang/bdwgc/archive/$(LIBGC_REF).tar.gz dist/deps/libgc: deps-download/$(LIBGC_REF).tar.gz mkdir -p "$@" cd "$@" && tar zx --strip-components=1 -f "$(TD)/$<" rm -rf "$@/tests" "$@/tools" touch "$(TD)/$@" # /deps/libmbedtls -------------------------------------------- LIBMBEDTLS_REF=c7d83538d3d359b05a9331bb2c9217977b5856ac deps-download/$(LIBMBEDTLS_REF).tar.gz: mkdir -p deps-download $(CURL) -o $@ https://github.com/actonlang/mbedtls/archive/$(LIBMBEDTLS_REF).tar.gz dist/deps/mbedtls: deps-download/$(LIBMBEDTLS_REF).tar.gz mkdir -p "$@" cd "$@" && tar zx --strip-components=1 -f "$(TD)/$<" touch "$(TD)/$@" # /deps/libprotobuf_c -------------------------------------------- LIBPROTOBUF_C_REF=faa19a6f6ca393fea01077fb37011a949bc6a3ee deps-download/$(LIBPROTOBUF_C_REF).tar.gz: mkdir -p deps-download $(CURL) -o $@ https://github.com/actonlang/protobuf-c/archive/$(LIBPROTOBUF_C_REF).tar.gz dist/deps/libprotobuf_c: deps-download/$(LIBPROTOBUF_C_REF).tar.gz mkdir -p "$@" cd "$@" && tar zx --strip-components=1 -f "$(TD)/$<" touch "$(TD)/$@" # /deps/tlsuv --------------------------------------------- TLSUV_REF=5af699b033776ec6a21b32c90e7aa7bf08c9929f deps-download/$(TLSUV_REF).tar.gz: mkdir -p deps-download $(CURL) -o $@ https://github.com/actonlang/tlsuv/archive/$(TLSUV_REF).tar.gz dist/deps/tlsuv: deps-download/$(TLSUV_REF).tar.gz dist/deps/libuv dist/deps/mbedtls mkdir -p "$@" cd "$@" && tar zx --strip-components=1 -f "$(TD)/$<" touch "$(TD)/$@" # /deps/libutf8proc -------------------------------------- LIBUTF8PROC_REF=a78677e855f0a282e79da6164db4ce1cf0789237 deps-download/$(LIBUTF8PROC_REF).tar.gz: mkdir -p deps-download $(CURL) -o $@ https://github.com/actonlang/utf8proc/archive/$(LIBUTF8PROC_REF).tar.gz dist/deps/libutf8proc: deps-download/$(LIBUTF8PROC_REF).tar.gz mkdir -p "$@" cd "$@" && tar zx --strip-components=1 -f "$(TD)/$<" touch "$(TD)/$@" # /deps/libuuid ------------------------------------------ dist/deps/libuuid: deps/libuuid mkdir -p "$(TD)/$@" cp -a "$&1 | grep GNU >/dev/null 2>&1; echo $$?) ifeq ($(GNU_TAR),0) TAR_TRANSFORM_OPT=--transform 's,^dist,acton,' else TAR_TRANSFORM_OPT=-s ,^dist,acton, endif # Do grep to only get a version number. If there's an error, we get an empty # string which is better than getting the error message itself. ACTONC_VERSION=$(shell $(ACTONC) --numeric-version 2>/dev/null | grep -E "^[0-9.]+$$") .PHONY: acton-$(OS)-$(ARCH)-$(ACTONC_VERSION).tar.xz acton-$(OS)-$(ARCH)-$(ACTONC_VERSION).tar.xz: tar cv $(TAR_TRANSFORM_OPT) --exclude .gitignore dist | xz -z -0 --threads=0 > "$@" .PHONY: release release: distribution $(MAKE) acton-$(OS)-$(ARCH)-$(ACTONC_VERSION).tar.xz # This target is used by the debian packaging .PHONY: install install: mkdir -p "$(DESTDIR)/usr/bin" "$(DESTDIR)/usr/lib/acton" cp -a dist/. "$(DESTDIR)/usr/lib/acton/" cd "$(DESTDIR)/usr/bin" && ln -s ../lib/acton/bin/acton cd "$(DESTDIR)/usr/bin" && ln -s ../lib/acton/bin/acton actonc cd "$(DESTDIR)/usr/bin" && ln -s ../lib/acton/bin/actondb cd "$(DESTDIR)/usr/bin" && ln -s ../lib/acton/bin/runacton cd "$(DESTDIR)/usr/bin" && ln -s ../lib/acton/bin/lsp-server-acton dist/lldb/acton.py: utils/lldb/acton.py @mkdir -p dist/lldb cp -a $< $@ .PHONY: debian/changelog debian/changelog: debian/changelog.in CHANGELOG.md cat $< | sed -e 's/VERSION/$(VERSION_INFO)/' -e 's/DEB_DIST/$(DEB_DIST)/' > $@ .PHONY: debs debs: debian/changelog debuild --preserve-envvar VERSION_INFO --preserve-envvar PATH --preserve-envvar STACK_ROOT --preserve-envvar ZIG_DOWNLOAD_BASE_URL --preserve-envvar ACTON_ZIG_GLIBC_VERSION -i -us -uc -nc -b .PHONY: container-image image image-deb push-image container-image: all podman build -f Containerfile -t acton:$(CONTAINER_TAG) --volume $(TD):/src:ro . image: container-image # Build container from locally built .deb (useful to mirror CI build path) image-deb: debs podman build -f Containerfile.deb -t acton:$(CONTAINER_TAG) --build-arg TARGETARCH=$(ARCH) --volume $(TD):/src:ro . push-image: @echo "Pushing container image to GitHub Container Registry" podman tag acton:$(CONTAINER_TAG) ghcr.io/actonlang/acton:$(CONTAINER_TAG) podman push ghcr.io/actonlang/acton:$(CONTAINER_TAG) ================================================ FILE: README.md ================================================ # The Acton programming language [![Test](https://github.com/actonlang/acton/actions/workflows/test.yml/badge.svg)](https://github.com/actonlang/acton/actions/workflows/test.yml) Acton is a general purpose programming language, designed to be useful for a wide range of applications, from desktop applications to embedded and distributed systems. In a first approximation Acton can be described as a seamless addition of a powerful new construct to an existing language: Acton adds *actors* to *Python*. Acton is a compiled language, offering the speed of C but with a considerably simpler programming model. There is no explicit memory management, instead relying on garbage collection. Acton is statically typed with an expressive type language and type inference. Type inference means you don't have to explicitly declare types of every variable but that the compiler will *infer* the type and performs its checks accordingly. We can have the benefits of type safety without the extra overhead involved in declaring types. The Acton Run Time System (RTS) offers a distributed mode of operation allowing multiple computers to participate in running one logical Acton system. Actors can migrate between compute nodes for load sharing purposes and similar. The RTS offers exactly once delivery guarantees. Through checkpointing of actor states to a distributed database, the failure of individual compute nodes can be recovered by restoring actor state. Your system can run forever! NOTE: Acton is in an experimental phase and although much of the syntax has been worked out, there may be changes. # Getting started with Acton ## Install Acton Check out the [installation guide](https://www.acton-lang.org/install) for more details. ### Debian / Ubuntu ```sh sudo install -m 0755 -d /etc/apt/keyrings sudo wget -q -O /etc/apt/keyrings/acton.asc https://apt.acton-lang.io/acton.gpg sudo chmod a+r /etc/apt/keyrings/acton.asc echo "deb [signed-by=/etc/apt/keyrings/acton.asc arch=amd64] http://apt.acton-lang.io/ stable main" | sudo tee -a /etc/apt/sources.list.d/acton.list sudo apt-get update sudo apt-get install -qy acton ``` ### Mac OS X ```sh brew install actonlang/acton/acton ``` ### Container image Use the container image to try Acton without installing it locally, or to run Acton builds in CI: ```sh docker run --rm ghcr.io/actonlang/acton:latest version docker run --rm -v "$PWD":/work -w /work ghcr.io/actonlang/acton:latest build ``` For day-to-day development, the native APT and Homebrew packages are usually more convenient. For CI, pin a version tag instead of using `latest`. ## Writing and compiling your first Acton program Edit the program source file, let's call it `helloworld.act`, and enter the following code: ``` Acton actor main(env): print("Hello, world!") env.exit(0) ``` Compile the program and run it: ``` $ acton helloworld.act $ ./helloworld Hello, world! ``` ## And then...? Check out our [learning resources](https://www.acton-lang.org/learn). # Building Acton from source See [building Acton from source](https://www.acton-lang.org/install/from-source). # Developing Acton See [dev info](docs/dev.md). # Contributions For information about contributing to Acton, see [CONTRIBUTING.md](CONTRIBUTING.md). ## Thanks to all the people who already contributed! ================================================ FILE: backend/.gitignore ================================================ ================================================ FILE: backend/Build.act ================================================ name = "actondb" fingerprint = 0xb1be0c7ca3b92d45 ================================================ FILE: backend/CLAUDE.md ================================================ # Acton Backend - Distributed Runtime & Database The backend provides distributed computing capabilities, actor persistence, and fault tolerance for Acton applications. ## Quick Reference ### Directory Structure ``` backend/ ├── actondb.c # Main database implementation ├── db.c/h # Core database operations ├── txns.c/h # Transaction management ├── queue.c/h # Message queue implementation ├── hash_ring.c/h # Consistent hashing for distribution ├── comm.c/h # Network communication ├── failure_detector/ # Node failure detection ├── build.zig # Build configuration └── test/ # Backend tests ``` ### Build & Test ```bash # Build backend (part of main build) make # Run backend tests make test-backend # Build standalone cd backend && zig build ``` ## Core Components ### ActonDB (`actondb.c`, `db.c/h`) ActonDB is the distributed database that provides: - Actor state persistence - Transactional updates - Replication across nodes - Automatic failover #### Key Features - Write-ahead logging - Snapshot isolation - Multi-version concurrency control - Consistent hashing for data distribution #### API Overview ```c // Initialize database int actondb_init(const char *data_dir); // Actor state operations int actondb_put(actor_id_t actor, void *state, size_t size); int actondb_get(actor_id_t actor, void **state, size_t *size); int actondb_delete(actor_id_t actor); // Transaction support txn_t *actondb_txn_begin(); int actondb_txn_commit(txn_t *txn); int actondb_txn_abort(txn_t *txn); ``` ### Transaction System (`txns.c/h`, `txn_state.c/h`) #### Transaction Lifecycle ``` BEGIN → ACTIVE → PREPARING → PREPARED → COMMITTING → COMMITTED ↓ ↓ ABORTING ← ← ← ← ← ← ← ABORTED ``` #### Implementation Details - Two-phase commit protocol - Distributed transaction coordination - Conflict detection and resolution - Deadlock prevention ### Message Queue System (`queue.c/h`, `queue_callback.c/h`) #### Queue Types 1. **Actor Queues** - Per-actor message queues 2. **System Queues** - Internal system messages 3. **Remote Queues** - Inter-node communication #### Features - Lock-free implementation where possible - Priority message handling - Flow control - Back-pressure mechanisms ### Distribution (`hash_ring.c/h`) #### Consistent Hashing - Maps actors to nodes - Handles node additions/removals - Minimizes data movement - Virtual nodes for balance #### Ring Operations ```c // Add/remove nodes hash_ring_add_node(ring, node_id, weight); hash_ring_remove_node(ring, node_id); // Find node for actor node_id_t hash_ring_find_node(ring, actor_id); // Get replica nodes hash_ring_get_replicas(ring, actor_id, replicas, count); ``` ### Communication Layer (`comm.c/h`) #### Network Protocol - Custom binary protocol - Message framing - Compression support - Encryption ready #### Message Types ```c typedef enum { MSG_ACTOR_CALL, MSG_ACTOR_CAST, MSG_STATE_SYNC, MSG_HEARTBEAT, MSG_NODE_JOIN, MSG_NODE_LEAVE } message_type_t; ``` ### Failure Detection (`failure_detector/`) #### Components - **fd.c/h** - Main failure detector - **cells.c/h** - Distributed state cells - **vector_clock.c/h** - Logical time tracking #### Detection Algorithm - Adaptive timeout based on network conditions - Gossip protocol for state dissemination - Vector clocks for causality tracking - Split-brain prevention ## Working with the Backend ### Adding New Database Operations 1. **Define Operation** in `db.h`: ```c int actondb_new_operation(/* parameters */); ``` 2. **Implement** in `db.c`: ```c int actondb_new_operation(/* parameters */) { // Validate inputs // Begin transaction if needed // Perform operation // Handle errors // Return result } ``` 3. **Add Tests** in `test/db_unit_tests.c` ### Implementing New Message Types 1. **Define Message** in `comm.h`: ```c typedef struct { message_header_t header; // Custom fields } my_message_t; ``` 2. **Add Handler** in `comm.c`: ```c static void handle_my_message(connection_t *conn, my_message_t *msg) { // Process message // Send response if needed } ``` 3. **Register Handler**: ```c message_handlers[MSG_MY_TYPE] = handle_my_message; ``` ### Transaction Implementation ```c // Example transactional operation int perform_atomic_update(actor_id_t actor1, actor_id_t actor2) { txn_t *txn = actondb_txn_begin(); if (!txn) return -1; // Read states void *state1, *state2; if (txn_get(txn, actor1, &state1) < 0) goto abort; if (txn_get(txn, actor2, &state2) < 0) goto abort; // Modify states modify_state(state1); modify_state(state2); // Write back if (txn_put(txn, actor1, state1) < 0) goto abort; if (txn_put(txn, actor2, state2) < 0) goto abort; // Commit return actondb_txn_commit(txn); abort: actondb_txn_abort(txn); return -1; } ``` ## Performance Optimization ### Database Performance - Use batch operations when possible - Minimize transaction scope - Leverage indexes appropriately - Monitor lock contention ### Network Performance - Batch messages when possible - Use compression for large payloads - Connection pooling - Async I/O throughout ### Memory Management - Pool allocators for hot paths - Minimize allocations in critical sections - Use stack allocation where appropriate - Profile memory usage regularly ## Debugging & Monitoring ### Logging ```c // Log levels LOG_ERROR("Failed to connect: %s", error_msg); LOG_WARN("Retry attempt %d", retry_count); LOG_INFO("Node %s joined", node_id); LOG_DEBUG("Message received: %d bytes", size); ``` ### Metrics - Transaction throughput - Message queue depths - Network latency - Node health status ### Debug Tools ```bash # Enable debug logging export ACTON_LOG_LEVEL=debug # Trace messages export ACTON_TRACE_MESSAGES=1 # Database diagnostics actondb-debug --stats ``` ## Testing Strategy ### Unit Tests - Test individual components - Mock external dependencies - Focus on edge cases ### Integration Tests - Multi-node scenarios - Failure injection - Performance benchmarks ### Stress Tests - High message rates - Large state sizes - Network partitions - Node failures ## Security Considerations 1. **Authentication** - Node-to-node authentication - Message signing - Certificate management 2. **Encryption** - TLS for network communication - At-rest encryption for database 3. **Access Control** - Actor-level permissions - Operation authorization ## Common Issues & Solutions ### Issue: High Message Latency - Check network conditions - Verify queue depths - Look for lock contention - Consider batching ### Issue: Transaction Conflicts - Reduce transaction scope - Add retry logic - Consider optimistic locking - Review access patterns ### Issue: Memory Growth - Check for queue buildup - Verify state cleanup - Look for memory leaks - Monitor GC activity ## Future Considerations The backend is designed to support: - Geographic distribution - Multi-datacenter deployment - Elastic scaling - Advanced replication strategies ================================================ FILE: backend/actondb.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * server.c * * Author: aagapi */ // ActonDB Server: #include "db.h" #include "queue_callback.h" #include "failure_detector/db_queries.h" #include "failure_detector/fd.h" #include "comm.h" #include "fastrand.h" #include "log.h" #include "netstring.h" #include "yyjson.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LOGPFX "#ActDB# " pid_t pid; #define SERVER_BUFSIZE 128 * 1024 // (1024 * 1024) #define PRINT_BUFSIZE 128 * 1024 #define UPDATE_LC_ON_GOSSIP #define DO_HIERARCHICAL_CONNECT 0 char in_buf[SERVER_BUFSIZE]; char out_buf[SERVER_BUFSIZE]; int no_state_cols = 2; // 1; // 4; int no_state_primary_keys = 1; int min_state_clustering_keys = 1; // 0; // 1; int no_state_index_keys = 0; // 1; int no_queue_cols = 1; // 2; #define ACTORS_TABLE (WORD)0 #define MSGS_TABLE (WORD)1 #define MSG_QUEUE (WORD)2 //WORD state_table_key = (WORD) 0; //WORD queue_table_key = (WORD) 1; void error(char *msg) { log_error(msg); } #define SERVER_VERBOSITY 1 #define DEFAULT_DATA_PORT 32000 #define DEFAULT_GOSSIP_PORT 32001 #define RANDOM_NONCES int64_t requests = 0; int64_t _get_nonce(unsigned int * fastrandstate) { #ifdef RANDOM_NONCES unsigned int randno1, randno2; int64_t randlong; FASTRAND(fastrandstate, randno1); FASTRAND(fastrandstate, randno2); return ((int64_t) randno1 << 32) | ((int64_t) randno2 & 0xFFFFFFFFL); #else return ++requests; #endif } #define PROPOSAL_STATUS_NON_EXISTING 0 #define PROPOSAL_STATUS_ACTIVE 1 #define PROPOSAL_STATUS_ACCEPTED 2 #define PROPOSAL_STATUS_AMMENDED 3 #define PROPOSAL_STATUS_REJECTED 4 #define AGREED_PEERS 0 #define LOCAL_PEERS 1 #define CONNECTED_PEERS 2 #define CONNECTED_CLIENTS 3 typedef struct membership { skiplist_t * connected_peers; skiplist_t * local_peers; skiplist_t * agreed_peers; skiplist_t * stable_peers; skiplist_t * connected_clients; skiplist_t * connected_client_sockets; vector_clock * view_id; int my_id; skiplist_t * outstanding_proposal; skiplist_t * outstanding_proposal_clients; int64_t outstanding_proposal_nonce; vector_clock * outstanding_view_id; int outstanding_proposal_acks; short proposal_status; skiplist_t * merged_responses; skiplist_t * merged_client_responses; } membership; int add_remote_server_to_list(remote_server * rs, skiplist_t * peer_list, unsigned int * seedptr); int add_client_to_membership(struct sockaddr_in addr, int sockfd, char *hostname, int portno, skiplist_t * clients, unsigned int * seedptr); int propose_local_membership(membership * m, vector_clock * my_vc, membership_agreement_msg ** amr, int64_t nonce, unsigned int * fastrandstate); membership * get_membership(int my_id) { membership * m = (membership *) malloc(sizeof(membership)); m->connected_peers = create_skiplist(&sockaddr_cmp); m->local_peers = create_skiplist(&sockaddr_cmp); m->agreed_peers = create_skiplist(&sockaddr_cmp); m->stable_peers = create_skiplist(&sockaddr_cmp); m->connected_clients = create_skiplist(&sockaddr_cmp); m->view_id = NULL; m->my_id = my_id; m->outstanding_proposal = create_skiplist(&sockaddr_cmp); m->outstanding_proposal_clients = create_skiplist(&sockaddr_cmp); m->outstanding_view_id = NULL; m->outstanding_proposal_acks = 0; m->outstanding_proposal_nonce = -1; m->proposal_status = PROPOSAL_STATUS_NON_EXISTING; m->merged_responses = create_skiplist(&sockaddr_cmp); m->merged_client_responses = create_skiplist(&sockaddr_cmp); return m; } void free_membership(membership * m) { skiplist_free(m->connected_peers); skiplist_free(m->local_peers); skiplist_free(m->agreed_peers); skiplist_free(m->stable_peers); skiplist_free(m->connected_clients); if(m->view_id != NULL) free_vc(m->view_id); if(m->outstanding_proposal != NULL) skiplist_free(m->outstanding_proposal); if(m->outstanding_proposal_clients != NULL) skiplist_free(m->outstanding_proposal_clients); if(m->outstanding_view_id != NULL) free_vc(m->outstanding_view_id); if(m->merged_responses != NULL) skiplist_free(m->merged_responses); if(m->merged_client_responses != NULL) skiplist_free(m->merged_client_responses); free(m); } typedef struct client_descriptor { struct sockaddr_in addr; int sockfd; char id[256]; } client_descriptor; client_descriptor * get_client_descriptor(struct sockaddr_in addr, int sockfd, char *hostname, int portno) { client_descriptor * cd = (client_descriptor *) malloc(sizeof(struct client_descriptor)); memcpy(&(cd->addr), &addr, sizeof(struct sockaddr_in)); cd->sockfd = sockfd; snprintf((char *) &cd->id, 256, "%s:%d", hostname, portno); return cd; } void free_client_descriptor(client_descriptor * cd) { free(cd); } int add_client_to_membership(struct sockaddr_in addr, int sockfd, char *hostname, int portno, skiplist_t * clients, unsigned int * seedptr) { client_descriptor * cd = get_client_descriptor(addr, sockfd, hostname, portno); if(skiplist_search(clients, &(cd->addr)) != NULL) { log_info("Client address %s:%d was already added to membership!", hostname, portno); free_client_descriptor(cd); return -1; } int status = skiplist_insert(clients, &(cd->addr), cd, seedptr); if(status != 0) { log_error("Error adding client address %s:%d to membership!", hostname, portno); free_client_descriptor(cd); return -2; } return 0; } client_descriptor * lookup_client_by_fd(int fd, skiplist_t * clients) { for(snode_t * crt = HEAD(clients); crt!=NULL; crt = NEXT(crt)) { client_descriptor * crt_cd = (client_descriptor *) crt->value; if(crt_cd->sockfd == fd) return crt_cd; } return NULL; } int create_state_schema(db_t * db, unsigned int * fastrandstate) { int primary_key_idx = 0; int clustering_key_idxs[2]; clustering_key_idxs[0]=1; clustering_key_idxs[1]=2; int index_key_idx=3; int * col_types = NULL; db_schema_t* db_schema = db_create_schema(col_types, no_state_cols + 1, &primary_key_idx, no_state_primary_keys, clustering_key_idxs, min_state_clustering_keys, &index_key_idx, no_state_index_keys); assert(db_schema != NULL && "Schema creation failed"); // Create table: int ret = db_create_table(ACTORS_TABLE, db_schema, db, fastrandstate); log_info("%s - %s (%d)", "Create ACTORS_TABLE", ret==0?"OK":"FAILED", ret); ret = db_create_table(MSGS_TABLE, db_schema, db, fastrandstate); log_info("%s - %s (%d)", "Create MSGS_TABLE", ret==0?"OK":"FAILED", ret); return ret; } int create_queue_schema(db_t * db, unsigned int * fastrandstate) { int * col_types = (int *) malloc((no_queue_cols + 1) * sizeof(int)); col_types[0] = DB_TYPE_INT64; col_types[no_queue_cols] = DB_TYPE_BLOB; // Include blob int ret = create_queue_table(MSG_QUEUE, no_queue_cols + 1, col_types, db, fastrandstate); log_info("%s - %s (%d)", "Create MSG_QUEUE table", ret==0?"OK":"FAILED", ret); return ret; } db_schema_t * get_schema(db_t * db, WORD table_key) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return NULL; db_table_t * table = (db_table_t *) (node->value); return table->schema; } // Write message handlers: int get_ack_packet(int status, write_query * q, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { ack_message * ack = init_ack_message(get_cell_address(q->cell), status, q->txnid, q->nonce); #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_ack_message(ack, (char *) print_buff); log_info("Sending ack message: %s", print_buff); #endif int ret = serialize_ack_message(ack, snd_buf, snd_msg_len, vc); free_ack_message(ack); return ret; } int get_gossip_ack_packet(int status, gossip_listen_message * q, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { ack_message * ack = init_ack_message(NULL, status, NULL, q->nonce); #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_ack_message(ack, (char *) print_buff); log_info("Sending ack message: %s", print_buff); #endif int ret = serialize_ack_message(ack, snd_buf, snd_msg_len, vc); free_ack_message(ack); return ret; } int handle_write_query(write_query * wq, db_t * db, unsigned int * fastrandstate) { int total_cols = wq->cell->no_keys + wq->cell->no_columns; int total_cols_plus_blob = total_cols + ((wq->cell->last_blob_size > 0)?(1):(0)); db_schema_t * schema = get_schema(db, (WORD) wq->cell->table_key); int no_clustering_keys = wq->cell->no_keys - schema->no_primary_keys; switch(wq->msg_type) { case RPC_TYPE_WRITE: { assert(wq->cell->no_columns > 0 || (wq->cell->last_blob != NULL && wq->cell->last_blob_size > 0)); WORD * column_values = (WORD *) malloc(total_cols_plus_blob * sizeof(WORD)); int j = 0; for(;jcell->no_keys;j++) column_values[j] = (WORD) wq->cell->keys[j]; for(;jcell->columns[j-wq->cell->no_keys]; if(wq->cell->last_blob_size > 0) { assert(total_cols_plus_blob == total_cols + 1); column_values[total_cols] = malloc(wq->cell->last_blob_size); memcpy(column_values[total_cols], wq->cell->last_blob, wq->cell->last_blob_size); } if(wq->txnid == NULL) // Write out of txn return db_insert_transactional(column_values, total_cols_plus_blob, no_clustering_keys, wq->cell->last_blob_size, wq->cell->version, (WORD) wq->cell->table_key, db, fastrandstate); else // Write in txn return db_insert_in_txn(column_values, total_cols_plus_blob, schema->no_primary_keys, no_clustering_keys, wq->cell->last_blob_size, (WORD) wq->cell->table_key, wq->txnid, db, fastrandstate); } case RPC_TYPE_DELETE: { if(wq->txnid == NULL) // Delete out of txn { if(wq->cell->no_keys == schema->no_primary_keys) return db_delete_row_transactional((WORD *) wq->cell->keys, wq->cell->version, (WORD) wq->cell->table_key, db, fastrandstate); else assert(0); // db_delete_cell not implemented yet } else { if(wq->cell->no_keys == schema->no_primary_keys) return db_delete_row_in_txn((WORD *) wq->cell->keys, wq->cell->no_keys, (WORD) wq->cell->table_key, wq->txnid, db, fastrandstate); else return db_delete_cell_in_txn((WORD *) wq->cell->keys, schema->no_primary_keys, no_clustering_keys, (WORD) wq->cell->table_key, wq->txnid, db, fastrandstate); // TO DO: To support db_delete_by_index_in_txn (in RPCs and backend) } } } return 1; } vector_clock * get_empty_vc() { return init_vc(0, NULL, NULL, 0); } vector_clock * get_local_vc(int my_id) { int node_ids[] = {my_id}; int64_t counters[] = {0}; return init_vc(1, node_ids, counters, 0); } // Read (regular and range) message handlers: int count_cells(db_row_t* result, int * max_depth) { if(result == NULL) return 0; if(result->cells == NULL || result->cells->no_items == 0) return 1; *max_depth = *max_depth + 1; int no_cells = 0; for(snode_t * crt_cell = HEAD(result->cells); crt_cell != NULL; crt_cell = NEXT(crt_cell)) { db_row_t * child = (db_row_t*) crt_cell->value; no_cells += count_cells(child, max_depth); } return no_cells; } cell * serialize_cells(db_row_t* result, cell * cells, int64_t table_key, int64_t * key_path, int depth, int no_schema_keys) { if(result == NULL) return cells; key_path[depth-1] = (int64_t) result->key; if(result->cells == NULL || result->cells->no_items == 0) { assert(result->no_columns > 0); assert(depth >= no_schema_keys); if(result->last_blob_size <= 0) copy_cell(cells, table_key, key_path, depth, (int64_t *) result->column_array, result->no_columns, NULL, 0, result->version); else copy_cell(cells, table_key, key_path, depth, (int64_t *) result->column_array, result->no_columns - 1, result->column_array[result->no_columns - 1], result->last_blob_size, result->version); return cells + 1; } // log_debug("serialize_cells:"); // print_long_row(result); cell * cells_ptr = cells; for(snode_t * crt_cell = HEAD(result->cells); crt_cell != NULL; crt_cell = NEXT(crt_cell)) { db_row_t * child = (db_row_t*) crt_cell->value; cells_ptr = serialize_cells(child, cells_ptr, table_key, key_path, depth+1, no_schema_keys); } return cells_ptr; } int get_read_response_packet(db_row_t* result, read_query * q, db_schema_t * schema, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { range_read_response_message * m = NULL; if(result == NULL) { m = init_range_read_response_message(NULL, 0, q->txnid, q->nonce); } else if(result->cells == NULL || result->cells->no_items == 0) // Return a single cell read result { assert(result->no_columns > 0); assert(result->no_columns >= schema->min_no_cols); assert(q->cell_address->keys[q->cell_address->no_keys - 1] == (int64_t) result->key); cell * c = NULL; if(result->last_blob_size <= 0) { c = init_cell(q->cell_address->table_key, (int64_t *) &result->key, 1, // Result cell always points to last (inner-most) key of the query (int64_t *) result->column_array, result->no_columns, NULL, 0, result->version); } else { c = init_cell(q->cell_address->table_key, (int64_t *) &result->key, 1, // Result cell always points to last (inner-most) key of the query (int64_t *) result->column_array, result->no_columns - 1, result->column_array[result->no_columns - 1], result->last_blob_size, result->version); } m = init_range_read_response_message(c, 1, q->txnid, q->nonce); } else // Return a multi-cell read result; traverse db_row downwards and get all child cells recursively: { int schema_keys = schema->no_primary_keys + schema->min_no_clustering_keys; // We only use this schema data for sanity checking of read back results // int no_keys = schema_keys - q->cell_address->no_keys + 1; int max_depth = 1; int no_results = count_cells(result, &max_depth); cell * cells = malloc(no_results * sizeof(cell)); int64_t * key_path = (int64_t *) malloc(max_depth * sizeof(int64_t)); cell * last_cell_ptr = serialize_cells(result, cells, q->cell_address->table_key, key_path, 1, schema_keys); // no_keys assert(last_cell_ptr - cells == no_results); m = init_range_read_response_message(cells, no_results, q->txnid, q->nonce); } #if (VERBOSE_RPC > 0) char print_buff[PRINT_BUFSIZE]; to_string_range_read_response_message(m, (char *) print_buff); log_info("Sending range read response message: %s", print_buff); #endif int ret = serialize_range_read_response_message(m, snd_buf, snd_msg_len, vc); free_range_read_response_message(m); return ret; } db_row_t* handle_read_query(read_query * q, db_schema_t ** schema, db_t * db, unsigned int * fastrandstate) { int i=0; *schema = get_schema(db, (WORD) q->cell_address->table_key); int no_clustering_keys = q->cell_address->no_keys - (*schema)->no_primary_keys; if(no_clustering_keys == 0) { return db_search((WORD *) q->cell_address->keys, (WORD) q->cell_address->table_key, db); } else { return db_search_clustering((WORD *) q->cell_address->keys, (WORD *) (q->cell_address->keys + (*schema)->no_primary_keys), no_clustering_keys, (WORD) q->cell_address->table_key, db); } } remote_server * lookup_client_by_client_socket_addr(struct sockaddr_in * client_socket_addr, skiplist_t * clients) { for(snode_t * crt = HEAD(clients); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(sockaddr_cmp((WORD) client_socket_addr, (WORD) (&(rs->client_socket_addr))) == 0) return rs; } return NULL; } int handle_gossip_listen_message(gossip_listen_message * msg, client_descriptor * cd, membership * m, vector_clock * my_lc, membership_agreement_msg ** amr, unsigned int * fastrandstate) { struct sockaddr_in dummy_serveraddr; remote_server * rs = get_remote_server(msg->node_description->hostname, msg->node_description->portno, dummy_serveraddr, cd->addr, DUMMY_FD, 0, 1); rs->status = NODE_LIVE; log_info("Adding client %s:%d/%d/%d to membership.", rs->hostname, msg->node_description->portno, msg->node_description->node_id, rs->portno); int status = add_remote_server_to_list(rs, m->connected_clients, fastrandstate); return propose_local_membership(m, my_lc, amr, msg->nonce, fastrandstate); } int get_range_read_response_packet(snode_t* start_row, snode_t* end_row, int no_results, range_read_query * q, db_schema_t * schema, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { int schema_keys = schema->no_primary_keys + schema->min_no_clustering_keys; // We only use this schema data for sanity checking of read back results // int no_keys = schema_keys - q->start_cell_address->no_keys + 1; range_read_response_message * m = NULL; if(no_results == 0) { m = init_range_read_response_message(NULL, 0, q->txnid, q->nonce); } else { assert(start_row != NULL); int max_range_depth = 0; int no_cells = 0, i=0; for(snode_t * crt_row = start_row; ivalue; // print_long_row(result); int max_depth = 1; no_cells += count_cells(result, &max_depth); max_range_depth = (max_depth > max_range_depth)?max_depth:max_range_depth; } cell * cells = malloc(no_cells * sizeof(cell)); int64_t * key_path = (int64_t *) malloc(max_range_depth * sizeof(int64_t)); i=0; cell * last_cell_ptr = cells; for(snode_t * crt_row = start_row; ivalue; last_cell_ptr = serialize_cells(result, last_cell_ptr, q->start_cell_address->table_key, key_path, 1, schema_keys); // no_keys } assert(last_cell_ptr - cells == no_cells); m = init_range_read_response_message(cells, no_cells, q->txnid, q->nonce); } #if (VERBOSE_RPC > 0) char print_buff[PRINT_BUFSIZE]; to_string_range_read_response_message(m, (char *) print_buff); log_info("Sending range read response message: %s", print_buff); #endif int ret = serialize_range_read_response_message(m, snd_buf, snd_msg_len, vc); free_range_read_response_message(m); return ret; } int handle_range_read_query(range_read_query * q, snode_t** start_row, snode_t** end_row, db_schema_t ** schema, db_t * db, unsigned int * fastrandstate) { int i=0; assert(q->start_cell_address->table_key == q->end_cell_address->table_key); assert(q->start_cell_address->no_keys == q->end_cell_address->no_keys); *schema = get_schema(db, (WORD) q->start_cell_address->table_key); int no_clustering_keys = q->start_cell_address->no_keys - (*schema)->no_primary_keys; if(no_clustering_keys == 0) { return db_range_search((WORD *) q->start_cell_address->keys, (WORD *) q->end_cell_address->keys, start_row, end_row, (WORD) q->start_cell_address->table_key, db); } else { return db_range_search_clustering((WORD *) q->start_cell_address->keys, (WORD *) (q->start_cell_address->keys + (*schema)->no_primary_keys), (WORD *) (q->end_cell_address->keys + (*schema)->no_primary_keys), no_clustering_keys, start_row, end_row, (WORD) q->start_cell_address->table_key, db); } } // Queue message handlers: int get_queue_ack_packet(int status, queue_query_message * q, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { ack_message * ack = init_ack_message(q->cell_address, status, q->txnid, q->nonce); #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_ack_message(ack, (char *) print_buff); log_info("Sending queue ack message: %s", print_buff); #endif int ret = serialize_ack_message(ack, snd_buf, snd_msg_len, vc); free_ack_message(ack); return ret; } int get_queue_read_response_packet(snode_t* start_row, snode_t* end_row, int no_results, int64_t new_read_head, int status, db_schema_t * schema, queue_query_message * q, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { queue_query_message * m = NULL; if(no_results == 0) { m = init_read_queue_response(q->cell_address, NULL, 0, q->app_id, q->shard_id, q->consumer_id, q->group_id, new_read_head, (short) status, q->txnid, q->nonce); } else { assert(start_row != NULL); cell * cells = malloc(no_results * sizeof(cell)); int i=0; int64_t prev_id = -1; for(snode_t * crt_row = start_row; ivalue; int64_t id = (int64_t) result->key; assert(i==0 || prev_id == (id - 1)); prev_id = id; if(result->last_blob_size <= 0) copy_cell(cells+i, q->cell_address->table_key, (int64_t *) &result->key, 1, (int64_t *) result->column_array, result->no_columns, NULL, 0, result->version); else copy_cell(cells+i, q->cell_address->table_key, (int64_t *) &result->key, 1, (int64_t *) result->column_array, result->no_columns - 1, result->column_array[result->no_columns - 1], result->last_blob_size, result->version); } m = init_read_queue_response(q->cell_address, cells, no_results, q->app_id, q->shard_id, q->consumer_id, q->group_id, new_read_head, (short) status, q->txnid, q->nonce); } #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_queue_message(m, (char *) print_buff); log_info("Sending read queue response message: %s", print_buff); #endif int ret = serialize_queue_message(m, snd_buf, snd_msg_len, 0, vc); free_queue_message(m); return ret; } int handle_create_queue(queue_query_message * q, db_t * db, unsigned int * fastrandstate) { if(q->txnid == NULL) // Create queue out of txn return create_queue((WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], NULL, 1, db, fastrandstate); else // Create queue in txn return create_queue_in_txn((WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], q->txnid, db, fastrandstate); } int handle_delete_queue(queue_query_message * q, db_t * db, unsigned int * fastrandstate) { if(q->txnid == NULL) return delete_queue((WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], NULL, 1, db, fastrandstate); else return delete_queue_in_txn((WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], q->txnid, db, fastrandstate); } int handle_subscribe_queue(queue_query_message * q, int * clientfd, int64_t * prev_read_head, int64_t * prev_consume_head, db_t * db, unsigned int * fastrandstate) { if(q->txnid != NULL) // Create queue out of txn { assert(0); // Subscriptions in txns are not supported yet return 1; } else return register_remote_subscribe_queue((WORD) q->consumer_id, (WORD) q->shard_id, (WORD) q->app_id, (WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], (WORD) q->group_id, clientfd, prev_read_head, prev_consume_head, 1, db, fastrandstate); } int handle_unsubscribe_queue(queue_query_message * q, db_t * db, unsigned int * fastrandstate) { if(q->txnid != NULL) // Create queue out of txn { assert(0); // Unsubscriptions in txns are not supported yet return 1; } else return register_remote_unsubscribe_queue((WORD) q->consumer_id, (WORD) q->shard_id, (WORD) q->app_id, (WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], (WORD) q->group_id, 1, db); } int handle_enqueue(queue_query_message * q, db_t * db, unsigned int * fastrandstate) { assert(q->no_cells > 0 && q->cells != NULL); int status = -1; for(int i=0;ino_cells;i++) { int total_cols = q->cells[i].no_keys + q->cells[i].no_columns; int total_cols_plus_blob = total_cols + ((q->cells[i].last_blob_size > 0)?(1):(0)); int64_t * column_values = (int64_t *) malloc(total_cols_plus_blob * sizeof(int64_t)); int j = 0; for(;jcells[i].no_keys;j++) column_values[j] = q->cells[i].keys[j]; for(;jcells[i].columns[j-q->cells[i].no_keys]; if(q->cells[i].last_blob_size > 0) { assert(total_cols_plus_blob == total_cols + 1); column_values[total_cols] = (int64_t) malloc(q->cells[i].last_blob_size); memcpy((WORD) column_values[total_cols], q->cells[i].last_blob, q->cells[i].last_blob_size); } // Below will automatically trigger remote consumer notifications on the queue, either immediately or upon txn commit: if(q->txnid == NULL) // Enqueue out of txn status = enqueue((WORD *) column_values, total_cols_plus_blob, q->cells[i].last_blob_size, (WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], 1, db, fastrandstate); else // Enqueue in txn status = enqueue_in_txn((WORD *) column_values, total_cols_plus_blob, q->cells[i].last_blob_size, (WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], q->txnid, db, fastrandstate); if(status != 0) break; } return status; } int handle_read_queue(queue_query_message * q, int * entries_read, int64_t * new_read_head, vector_clock ** prh_version, snode_t** start_row, snode_t** end_row, db_schema_t ** schema, db_t * db, unsigned int * fastrandstate) { *schema = get_schema(db, (WORD) q->cell_address->table_key); if(q->txnid == NULL) // Read queue out of txn return read_queue((WORD) q->consumer_id, (WORD) q->shard_id, (WORD) q->app_id, (WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], q->queue_index, entries_read, new_read_head, prh_version, start_row, end_row, 1, db); else // Read queue in txn return read_queue_in_txn((WORD) q->consumer_id, (WORD) q->shard_id, (WORD) q->app_id, (WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], (int) q->queue_index, entries_read, new_read_head, start_row, end_row, q->txnid, db, fastrandstate); } int handle_consume_queue(queue_query_message * q, db_t * db, unsigned int * fastrandstate) { if(q->txnid == NULL) // Consume queue out of txn return consume_queue((WORD) q->consumer_id, (WORD) q->shard_id, (WORD) q->app_id, (WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], q->queue_index, db); else // Consume queue in txn return consume_queue_in_txn((WORD) q->consumer_id, (WORD) q->shard_id, (WORD) q->app_id, (WORD) q->cell_address->table_key, (WORD) q->cell_address->keys[0], q->queue_index, q->txnid, db, fastrandstate); } // Txn messages handlers: int get_txn_ack_packet(int status, txn_message * q, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { ack_message * ack = init_ack_message(NULL, status, q->txnid, q->nonce); #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_ack_message(ack, (char *) print_buff); log_info("Sending txn ack message: %s", print_buff); #endif int ret = serialize_ack_message(ack, snd_buf, snd_msg_len, vc); free_ack_message(ack); return ret; } int handle_new_txn(txn_message * q, db_t * db, unsigned int * fastrandstate) { assert(q->txnid != NULL); #if (MULTI_THREADED == 1) pthread_mutex_lock(db->txn_state_lock); #endif txn_state * ts = get_txn_state(q->txnid, db); if(ts != NULL) { #if (MULTI_THREADED == 1) pthread_mutex_unlock(db->txn_state_lock); #endif return DUPLICATE_TXN; // txnid already exists on server } ts = init_txn_state(); memcpy(&ts->txnid, q->txnid, sizeof(uuid_t)); skiplist_insert(db->txn_state, (WORD) ts->txnid, (WORD) ts, fastrandstate); #if (MULTI_THREADED == 1) pthread_mutex_unlock(db->txn_state_lock); #endif return 0; } int handle_validate_txn(txn_message * q, db_t * db, unsigned int * fastrandstate) { assert(q->txnid != NULL); assert(q->version != NULL); return validate_txn(q->txnid, q->version, db); } int handle_commit_txn(txn_message * q, db_t * db, unsigned int * fastrandstate) { assert(q->txnid != NULL); txn_state * ts = get_txn_state(q->txnid, db); // Make sure the txn has the right commit stamp (it c'd be that the current server missed the previous validation packet so the version was not set then): if(ts == NULL) return NO_SUCH_TXN; // txnid doesn't exist on server set_version(ts, q->version); return persist_txn(ts, db, fastrandstate); } int handle_abort_txn(txn_message * q, db_t * db, unsigned int * fastrandstate) { assert(q->txnid != NULL); return abort_txn(q->txnid, db); } int handle_socket_nop(int * childfd, int * status) { struct sockaddr_in address; int addrlen; getpeername(*childfd, (struct sockaddr*)&address, (socklen_t*)&addrlen); log_info("Host disconnected, ip %s, port %d, status=%d, fd, NOP %d" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port), *status, *childfd); *status = NODE_DEAD; return 0; } int handle_socket_close(int * childfd, int * status) { struct sockaddr_in address; int addrlen; getpeername(*childfd, (struct sockaddr*)&address, (socklen_t*)&addrlen); log_info("Host disconnected, ip %s, port %d, old_status=%d, closing fd %d" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port), *status, *childfd); //Close the socket and mark as -1 for reuse: close(*childfd); *childfd = -1; *status = NODE_DEAD; return 0; } int add_remote_server_to_list(remote_server * rs, skiplist_t * peer_list, unsigned int * seedptr) { snode_t * snode = skiplist_search(peer_list, &rs->serveraddr); if(snode != NULL) { log_info("Server address %s:%d was already added to membership, marking it as live!", rs->hostname, rs->portno); remote_server * existing_rs = (remote_server *) snode->value; existing_rs->status = NODE_LIVE; // Update client socket address: memcpy(&(existing_rs->client_socket_addr), &(rs->client_socket_addr), sizeof(struct sockaddr_in)); return -1; } int status = skiplist_insert(peer_list, &rs->serveraddr, rs, seedptr); if(status != 0) { log_error("Error adding server address %s:%d to membership!", rs->hostname, rs->portno); assert(0); return -2; } return 0; } int add_remote_server_to_membership(remote_server * rs, membership * m, short list, unsigned int * seedptr) { switch(list) { case AGREED_PEERS: return add_remote_server_to_list(rs, m->agreed_peers, seedptr); case LOCAL_PEERS: return add_remote_server_to_list(rs, m->local_peers, seedptr); case CONNECTED_PEERS: return add_remote_server_to_list(rs, m->connected_peers, seedptr); case CONNECTED_CLIENTS: return add_remote_server_to_list(rs, m->connected_clients, seedptr); } return -1; } int add_peer_to_membership(char *hostname, unsigned short portno, struct sockaddr_in serveraddr, int serverfd, int do_connect, membership * m, short list, remote_server ** rs, unsigned int * seedptr) { struct sockaddr_in dummy_serveraddr; *rs = get_remote_server(hostname, portno, serveraddr, dummy_serveraddr, serverfd, do_connect, 0); if(rs == NULL) { log_debug("ERROR: Failed joining server %s:%d (it looks down)!", hostname, portno); return 1; } int status = add_remote_server_to_membership(*rs, m, list, seedptr); if(status != 0) { assert(0); free_remote_server(*rs); *rs = NULL; } return status; } int handle_client_message(int childfd, int msg_len, db_t * db, membership * m, skiplist_t * clients, unsigned int * fastrandstate, vector_clock * my_lc, int my_id) { void * tmp_out_buf = NULL, * q = NULL; unsigned snd_msg_len; short msg_type; short is_gossip_message; db_schema_t * schema; int64_t nonce = -1; membership_agreement_msg * amr = NULL; vector_clock * lc_read = NULL; int status = parse_message(in_buf + sizeof(int), msg_len, &q, &msg_type, &is_gossip_message, &nonce, 1, &lc_read); if(status != 0) { log_error( "ERROR decoding client request"); return -1; } if(lc_read != NULL) { // If we were multi-threaded, we'd have to protect this snippet: #if (VERBOSE_RPC > 2) char msg_buf[1024]; log_debug("SERVER: Received client message with LC %s.", to_string_vc(lc_read, msg_buf)); log_debug("SERVER: My LC before update is %s.", to_string_vc(my_lc, msg_buf)); #endif update_vc(my_lc, lc_read); increment_vc(my_lc, my_id); free_vc(lc_read); #if (VERBOSE_RPC > 2) log_debug("SERVER: Updated local LC to %s.", to_string_vc(my_lc, msg_buf)); #endif } switch(msg_type) { case RPC_TYPE_WRITE: { status = handle_write_query((write_query *) q, db, fastrandstate); if(status != 0) { log_error("handle_write_query returned %d!", status); assert(0); } vector_clock * vc = (((write_query *) q)->txnid != NULL)?(copy_vc(my_lc)):(NULL); status = get_ack_packet(status, (write_query *) q, &tmp_out_buf, &snd_msg_len, vc); if(vc != NULL) free_vc(vc); free_write_query((write_query *) q); break; } case RPC_TYPE_READ: { db_row_t* result = handle_read_query((read_query *) q, &schema, db, fastrandstate); vector_clock * vc = (((read_query *) q)->txnid != NULL)?(copy_vc(my_lc)):(NULL); status = get_read_response_packet(result, (read_query *) q, schema, &tmp_out_buf, &snd_msg_len, vc); if(vc != NULL) free_vc(vc); free_read_query((read_query *) q); break; } case RPC_TYPE_RANGE_READ: { snode_t * start_row = NULL, * end_row = NULL; vector_clock * vc = (((range_read_query *) q)->txnid != NULL)?(copy_vc(my_lc)):(NULL); int no_results = handle_range_read_query((range_read_query *) q, &start_row, &end_row, &schema, db, fastrandstate); status = get_range_read_response_packet(start_row, end_row, no_results, (range_read_query *) q, schema, &tmp_out_buf, &snd_msg_len, vc); if(vc != NULL) free_vc(vc); free_range_read_query((range_read_query *) q); break; } case RPC_TYPE_QUEUE: { queue_query_message * qm = (queue_query_message *) q; vector_clock * vc = (qm->txnid != NULL)?(copy_vc(my_lc)):(NULL); switch(qm->msg_type) { case QUERY_TYPE_CREATE_QUEUE: { status = handle_create_queue(qm, db, fastrandstate); // assert(status == 0); status = get_queue_ack_packet(status, qm, &tmp_out_buf, &snd_msg_len, vc); break; } case QUERY_TYPE_DELETE_QUEUE: { status = handle_delete_queue(qm, db, fastrandstate); assert(status == 0); status = get_queue_ack_packet(status, qm, &tmp_out_buf, &snd_msg_len, vc); break; } case QUERY_TYPE_SUBSCRIBE_QUEUE: { int64_t prev_read_head = -1, prev_consume_head = -1; status = handle_subscribe_queue(qm, &childfd, &prev_read_head, &prev_consume_head, db, fastrandstate); // assert(status == 0); status = get_queue_ack_packet(status, qm, &tmp_out_buf, &snd_msg_len, vc); break; } case QUERY_TYPE_UNSUBSCRIBE_QUEUE: { status = handle_unsubscribe_queue(qm, db, fastrandstate); assert(status == 0); status = get_queue_ack_packet(status, qm, &tmp_out_buf, &snd_msg_len, vc); break; } case QUERY_TYPE_ADD_QUEUE_TO_GROUP: { // This is handled automatically, should not be called explicitly assert(0); break; } case QUERY_TYPE_ENQUEUE: { status = handle_enqueue(qm, db, fastrandstate); assert(status == 0); status = get_queue_ack_packet(status, qm, &tmp_out_buf, &snd_msg_len, vc); break; } case QUERY_TYPE_READ_QUEUE: { int entries_read = 0; int64_t new_read_head = -1; vector_clock * prh_version = NULL; snode_t * start_row = NULL, * end_row = NULL; db_schema_t * schema = NULL; status = handle_read_queue(qm, &entries_read, &new_read_head, &prh_version, &start_row, &end_row, &schema, db, fastrandstate); if(status != QUEUE_STATUS_READ_COMPLETE && status != QUEUE_STATUS_READ_INCOMPLETE && status != DB_ERR_NO_CONSUMER) { log_error("Unexpected status returned by handle_read_queue(): %d", status); assert(0); } status = get_queue_read_response_packet(start_row, end_row, entries_read, new_read_head, status, schema, qm, &tmp_out_buf, &snd_msg_len, vc); break; } case QUERY_TYPE_CONSUME_QUEUE: { status = handle_consume_queue(qm, db, fastrandstate); // assert(status == (int) qm->queue_index); status = get_queue_ack_packet(status, qm, &tmp_out_buf, &snd_msg_len, vc); break; } default: { assert(0); } } if(vc != NULL) free_vc(vc); free_queue_message(qm); break; } case RPC_TYPE_TXN: { txn_message * tm = (txn_message *) q; assert(tm->txnid != NULL); vector_clock * vc = copy_vc(my_lc); switch(tm->type) { case DB_TXN_BEGIN: { status = handle_new_txn(tm, db, fastrandstate); assert(status == 0 || status == DUPLICATE_TXN); status = get_txn_ack_packet(status, tm, &tmp_out_buf, &snd_msg_len, vc); break; } case DB_TXN_VALIDATION: { status = handle_validate_txn(tm, db, fastrandstate); if(status != VAL_STATUS_COMMIT) log_warn("BACKEND: handle_validate_txn() returned %d\n", status); assert(status == VAL_STATUS_COMMIT || status == VAL_STATUS_ABORT || status == VAL_STATUS_ABORT_SCHEMA || status == NO_SUCH_TXN); status = get_txn_ack_packet(status, tm, &tmp_out_buf, &snd_msg_len, vc); break; } case DB_TXN_COMMIT: { status = handle_commit_txn(tm, db, fastrandstate); if(status != 0) log_warn("BACKEND: handle_commit_txn() returned %d\n", status); status = get_txn_ack_packet(status, tm, &tmp_out_buf, &snd_msg_len, vc); break; } case DB_TXN_ABORT: { status = handle_abort_txn(tm, db, fastrandstate); assert(status == 0); status = get_txn_ack_packet(status, tm, &tmp_out_buf, &snd_msg_len, vc); break; } } if(vc != NULL) free_vc(vc); free_txn_message(tm); break; } case RPC_TYPE_GOSSIP_LISTEN: { client_descriptor * cd = lookup_client_by_fd(childfd, clients); int status = handle_gossip_listen_message((gossip_listen_message *) q, cd, m, copy_vc(my_lc), &amr, fastrandstate); assert(get_gossip_ack_packet(status, (gossip_listen_message *) q, &tmp_out_buf, &snd_msg_len, NULL) == 0); free_gossip_listen_msg(q); break; } case RPC_TYPE_ACK: { assert(0); // S'dn't happen currently break; } default: { assert(0); } } assert(status == 0); int n = write(childfd, tmp_out_buf, snd_msg_len); if (n < 0) log_error("ERROR writing to socket"); // There might be a view notification to send to client: if(amr != NULL) { assert(serialize_membership_agreement_msg(amr, &tmp_out_buf, &snd_msg_len) == 0); free_membership_agreement(amr); n = write(childfd, tmp_out_buf, snd_msg_len); if (n < 0) log_error("ERROR writing to socket"); } free(tmp_out_buf); return 0; } // Gossip message handling: int get_join_packet(int status, int rack_id, int dc_id, char * hostname, unsigned short portno, int64_t nonce, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { membership_agreement_msg * jm = get_membership_join_msg(status, rack_id, dc_id, hostname, portno, nonce, vc); #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_membership_agreement_msg(jm, (char *) print_buff); log_info("Sending Join message: %s", print_buff); #endif int ret = serialize_membership_agreement_msg(jm, snd_buf, snd_msg_len); free_membership_agreement(jm); return ret; } int get_agreement_propose_packet(int status, membership_state * membership, int64_t nonce, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { membership_agreement_msg * amr = get_membership_propose_msg(status, membership, nonce, vc); #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_membership_agreement_msg(amr, (char *) print_buff); log_info("Sending Membership Propose message: %s", print_buff); #endif int ret = serialize_membership_agreement_msg(amr, snd_buf, snd_msg_len); free_membership_agreement(amr); return ret; } int get_agreement_response_packet(int status, membership_state * membership, membership_agreement_msg * am, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { membership_agreement_msg * amr = get_membership_response_msg(status, membership, am->nonce, copy_vc(vc)); #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_membership_agreement_msg(amr, (char *) print_buff); log_info("Sending Membership Response message: %s", print_buff); #endif int ret = serialize_membership_agreement_msg(amr, snd_buf, snd_msg_len); free_membership_agreement(amr); return ret; } int get_agreement_notify_packet(int status, membership_state * membership, membership_agreement_msg * am, membership_agreement_msg ** amr, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc, vector_clock * prev_vc) { *amr = get_membership_notify_msg(status, membership, am->nonce, copy_vc(vc)); #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_membership_agreement_msg(*amr, (char *) print_buff); log_info("Sending Membership Notify message: %s", print_buff); #endif int ret = serialize_membership_agreement_msg(*amr, snd_buf, snd_msg_len); return ret; } int get_agreement_notify_ack_packet(int status, membership_agreement_msg * am, void ** snd_buf, unsigned * snd_msg_len, vector_clock * vc) { membership_agreement_msg * amr = get_membership_notify_ack_msg(status, am->nonce, copy_vc(vc)); #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_membership_agreement_msg(amr, (char *) print_buff); log_info("Sending Membership Notify ACK message: %s", print_buff); #endif int ret = serialize_membership_agreement_msg(amr, snd_buf, snd_msg_len); free_membership_agreement(amr); return ret; } membership_state * get_membership_state_from_server_list(skiplist_t * servers, skiplist_t * clients, vector_clock * my_lc) { if(servers->no_items == 0) return NULL; node_description * nds = (node_description *) malloc(servers->no_items * sizeof(node_description)); node_description * client_nds = (node_description *) malloc(clients->no_items * sizeof(node_description)); int i = 0; for(snode_t * crt = HEAD(servers); crt!=NULL; crt = NEXT(crt), i++) { remote_server * rs = (remote_server *) crt->value; copy_node_description(nds+i, rs->status, get_node_id((struct sockaddr *) &(rs->serveraddr)), 0, 0, rs->hostname, rs->portno); } int j = 0; for(snode_t * crt = HEAD(clients); crt!=NULL; crt = NEXT(crt), j++) { remote_server * rs = (remote_server *) crt->value; copy_node_description(client_nds+j, rs->status, get_node_id((struct sockaddr *) &(rs->serveraddr)), 0, 0, rs->hostname, rs->portno); } return init_membership_state(servers->no_items, nds, clients->no_items, client_nds, my_lc); } int no_live_nodes(skiplist_t * list) { int no_nodes = 0; for(snode_t * crt = HEAD(list); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(rs->status == NODE_LIVE) no_nodes++; } return no_nodes; } int no_live_or_unknown_nodes(skiplist_t * list) { int no_nodes = 0; for(snode_t * crt = HEAD(list); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(rs->status == NODE_LIVE) no_nodes++; } return no_nodes; } int is_min_live_node(int id, skiplist_t * list) { if(list->no_items == 0) return -2; // empty list int min_id = INT_MAX, id_in_list = 0; for(snode_t * crt = HEAD(list); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; int node_id = get_node_id((struct sockaddr *) &(rs->serveraddr)); if(node_id == id) id_in_list = 1; if(rs->status == NODE_LIVE) { min_id = (node_id < min_id)?node_id:min_id; } } if(!id_in_list) return -1; // Node not in list if(min_id == id) return 1; return 0; } int mark_live(membership * m, int sender_id) { for(snode_t * crt = HEAD(m->local_peers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; int node_id = get_node_id((struct sockaddr *) &(rs->serveraddr)); if(node_id == sender_id) { rs->status = NODE_LIVE; return 0; } } return 1; } int mark_dead(membership * m, int sender_id) { for(snode_t * crt = HEAD(m->local_peers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; int node_id = get_node_id((struct sockaddr *) &(rs->serveraddr)); if(node_id == sender_id) { rs->status = NODE_DEAD; return 0; } } return 1; } int send_join_message(int rack_id, int dc_id, char * hostname, unsigned short portno, vector_clock * my_vc, remote_server * dest_rs, unsigned int * fastrandstate) { void * tmp_out_buf = NULL; unsigned snd_msg_len; if(dest_rs->status != NODE_LIVE || dest_rs->sockfd <= 0) { #if (VERBOSE_RPC > 0) char msg_buf[1024]; log_warn("SERVER: Not sending JOIN request to %s, as its status is %d!", dest_rs->id, dest_rs->status); #endif return 1; } int status = get_join_packet(0, rack_id, dc_id, hostname, portno, _get_nonce(fastrandstate), &tmp_out_buf, &snd_msg_len, copy_vc(my_vc)); assert(status == 0); int n = write(dest_rs->sockfd, tmp_out_buf, snd_msg_len); if (n < 0) error("ERROR writing to socket"); free(tmp_out_buf); return 0; } int propose_local_membership(membership * m, vector_clock * my_vc, membership_agreement_msg ** amr, int64_t nonce, unsigned int * fastrandstate) { void * tmp_out_buf = NULL; unsigned snd_msg_len; int status = 0, skip_proposal = 0; char msg_buf[1024]; if(no_live_nodes(m->local_peers) <= 1) { #if (VERBOSE_RPC > 0) log_warn("SERVER: Skipping proposing new view, as no other nodes are live in local membership!"); #endif skip_proposal = 1; } if(is_min_live_node(m->my_id, m->local_peers) != 1) { #if (VERBOSE_RPC > 0) log_info("SERVER: Skipping proposing new view, as I am not the min live node!"); #endif skip_proposal = 1; } if(skip_proposal) { // In this case, there won't be an agreement proposal, but we must still notify the clients of the current local view if // this came from a listen_to_gossip(), for it to learn the client memberships in case we are the only server in the system: if(amr != NULL) { *amr = get_membership_notify_msg(0, get_membership_state_from_server_list(skiplist_clone(m->local_peers, fastrandstate), skiplist_clone(m->connected_clients, fastrandstate), copy_vc(my_vc)), nonce, copy_vc(my_vc)); #if (VERBOSE_RPC > 0) to_string_membership_agreement_msg(*amr, (char *) msg_buf); log_info("Sending Membership Notify message to clients: %s", msg_buf); #endif } return SKIP_PROPOSAL_STATUS; } if(m->outstanding_view_id != NULL) { #if (VERBOSE_RPC > 0) log_warn("SERVER: Proposing new view, aborting already outstanding view proposal %s!", to_string_vc(m->outstanding_view_id, msg_buf)); #endif skiplist_free(m->outstanding_proposal); skiplist_free(m->outstanding_proposal_clients); free_vc(m->outstanding_view_id); } m->outstanding_proposal = skiplist_clone(m->local_peers, fastrandstate); m->outstanding_proposal_clients = skiplist_clone(m->connected_clients, fastrandstate); m->outstanding_view_id = copy_vc(my_vc); m->outstanding_proposal_nonce = _get_nonce(fastrandstate); m->proposal_status = PROPOSAL_STATUS_ACTIVE; m->outstanding_proposal_acks = 0; m->merged_responses = skiplist_clone(m->local_peers, fastrandstate); // init merged responses for server list to "my response" m->merged_client_responses = skiplist_clone(m->connected_clients, fastrandstate); // init merged responses for client list to "my response" status = get_agreement_propose_packet(0, get_membership_state_from_server_list(m->outstanding_proposal, m->outstanding_proposal_clients, copy_vc(m->outstanding_view_id)), m->outstanding_proposal_nonce, &tmp_out_buf, &snd_msg_len, copy_vc(m->outstanding_view_id)); for(snode_t * crt = HEAD(m->local_peers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; #if (VERBOSE_RPC > 0) log_info("SERVER: propose_local_membership: Evaluating node (%s, %d, %d, %d), my_id = %d..", rs->id, rs->status, rs->sockfd, get_node_id((struct sockaddr *) &(rs->serveraddr)), m->my_id); #endif if(rs->status == NODE_LIVE && rs->sockfd > 0 && get_node_id((struct sockaddr *) &(rs->serveraddr)) != m->my_id) // skip myself, and nodes that are "down" in membership { #if (VERBOSE_RPC > 0) log_info("SERVER: Sending proposal!"); #endif int n = write(rs->sockfd, tmp_out_buf, snd_msg_len); if (n < 0) error("ERROR writing to socket"); m->outstanding_proposal_acks++; } } free(tmp_out_buf); return 0; } int merge_membership_agreement_msg_to_list(membership_agreement_msg * ma, skiplist_t * merged_list, membership * m, vector_clock * my_lc, unsigned int * fastrandstate) { int memberships_differ = 0; struct sockaddr_in dummy_serveraddr; for(int i=0;imembership->no_nodes;i++) { node_description nd = ma->membership->membership[i]; remote_server * rs = get_remote_server(nd.hostname, nd.portno, dummy_serveraddr, dummy_serveraddr, DUMMY_FD, 0, 0); rs->status = nd.status; snode_t * node = skiplist_search(merged_list, &rs->serveraddr); if(node == NULL) // I just learned about this node { #if (VERBOSE_RPC > 0) char msg_buf[1024]; log_info("SERVER: merge_membership_agreement_msg_to_list: Learned about node %s from proposal, status=%d.", rs->id, rs->status); #endif int status = connect_remote_server(rs); if(status != 0) { rs->status = NODE_DEAD; rs->sockfd = -1; if(nd.status == NODE_LIVE) memberships_differ = 1; } status = add_remote_server_to_list(rs, m->local_peers, fastrandstate); status = add_remote_server_to_list(rs, merged_list, fastrandstate); assert(status == 0); } else { free_remote_server(rs); remote_server * rs_local = (remote_server *) node->value; if(rs_local->status != nd.status) // if proposed server status is different than local one, and proposed clock is newer, use proposed status { int64_t local_counter = get_component_vc(my_lc, nd.node_id); int64_t proposed_counter = get_component_vc(ma->vc, nd.node_id); if((proposed_counter > local_counter) || (proposed_counter == -1 && local_counter == -1)) // -1 is for client (RTS membership entries), which do not participate in the vector_clock version { #if (VERBOSE_RPC > 0) log_info("SERVER: merge_membership_agreement_msg_to_list: Updating status of node %s from %d to %d, because local_counter=%" PRId64 ", proposed_counter=%" PRId64 ".", rs->id, rs_local->status, nd.status, local_counter, proposed_counter); #endif rs_local->status = nd.status; } else { #if (VERBOSE_RPC > 0) log_info("SERVER: merge_membership_agreement_msg_to_list: Requesting membership ammend, because for node %s, local_status=%d, proposed_status=%d, local_counter=%" PRId64 ", proposed_counter=%" PRId64 ".", rs->id, rs_local->status, nd.status, local_counter, proposed_counter); #endif memberships_differ = 1; } } } } return memberships_differ; } int merge_membership_agreement_msg_to_client_list(membership_agreement_msg * ma, skiplist_t * merged_list, membership * m, vector_clock * my_lc, unsigned int * fastrandstate) { int memberships_differ = 0; struct sockaddr_in dummy_serveraddr; int reverse_connect_to_clients = 0; for(int i=0;imembership->no_client_nodes;i++) { node_description nd = ma->membership->client_membership[i]; remote_server * rs = get_remote_server(nd.hostname, nd.portno, dummy_serveraddr, dummy_serveraddr, DUMMY_FD, 0, 1); rs->status = nd.status; snode_t * node = skiplist_search(merged_list, &rs->serveraddr); if(node == NULL) // I just learned about this client { #if (VERBOSE_RPC > 0) char msg_buf[1024]; log_info("SERVER: merge_membership_agreement_msg_to_list: Learned about client node %s from proposal, status=%d.", rs->id, rs->status); #endif int status = 0; if(reverse_connect_to_clients) { status = connect_remote_server(rs); if(status != 0) { rs->status = NODE_DEAD; rs->sockfd = -1; if(nd.status == NODE_LIVE) memberships_differ = 1; } } else { memberships_differ = 1; } status = add_remote_server_to_list(rs, m->connected_clients, fastrandstate); assert(status == 0); status = add_remote_server_to_list(rs, merged_list, fastrandstate); assert(status == 0); } else { free_remote_server(rs); remote_server * rs_local = (remote_server *) node->value; if(rs_local->status != nd.status) // if proposed server status is different than local one, and proposed clock is newer, use proposed status { int64_t local_counter = get_component_vc(my_lc, nd.node_id); int64_t proposed_counter = get_component_vc(ma->vc, nd.node_id); if((proposed_counter > local_counter) || (proposed_counter == -1 && local_counter == -1)) // -1 is for client (RTS membership entries), which do not participate in the vector_clock version { #if (VERBOSE_RPC > 0) log_info("SERVER: merge_membership_agreement_msg_to_list: Updating status of node %s from %d to %d, because local_counter=%" PRId64 ", proposed_counter=%" PRId64 ".", rs->id, rs_local->status, nd.status, local_counter, proposed_counter); #endif rs_local->status = nd.status; } else { #if (VERBOSE_RPC > 0) log_info("SERVER: merge_membership_agreement_msg_to_list: Requesting membership ammend, because for node %s, local_status=%d, proposed_status=%d, local_counter=%" PRId64 ", proposed_counter=%" PRId64 ".", rs->id, rs_local->status, nd.status, local_counter, proposed_counter); #endif memberships_differ = 1; } } } } return memberships_differ; } int handle_agreement_propose_message(membership_agreement_msg * ma, membership_state ** merged_membership, membership * m, db_t * db, vector_clock * my_lc, vector_clock * prev_lc, unsigned int * fastrandstate) { #if (VERBOSE_RPC > 0) char msg_buf[1024]; log_info("SERVER: Received new view proposal %s!", to_string_membership_agreement_msg(ma, msg_buf)); #endif if(compare_vc(m->view_id, ma->vc) > 0) { #if (VERBOSE_RPC > 0) log_info("SERVER: Rejecting proposed view %s because it is older than my installed view %s!", to_string_vc(m->view_id, msg_buf), to_string_vc(ma->vc, msg_buf)); #endif *merged_membership = NULL; return PROPOSAL_STATUS_REJECTED; } // Copy local view to merged list: skiplist_t * merged_list = skiplist_clone(m->local_peers, fastrandstate); skiplist_t * client_merged_list = skiplist_clone(m->connected_clients, fastrandstate); // Merge it with proposed view: int memberships_differ = merge_membership_agreement_msg_to_list(ma, merged_list, m, prev_lc, fastrandstate); int client_memberships_differ = merge_membership_agreement_msg_to_client_list(ma, client_merged_list, m, prev_lc, fastrandstate); *merged_membership = get_membership_state_from_server_list(merged_list, client_merged_list, my_lc); return (memberships_differ | client_memberships_differ)?PROPOSAL_STATUS_AMMENDED:PROPOSAL_STATUS_ACCEPTED; } int handle_agreement_response_message(membership_agreement_msg * ma, membership_state ** merged_membership, membership * m, db_t * db, vector_clock * my_lc, vector_clock * prev_vc, unsigned int * fastrandstate) { #if (VERBOSE_RPC > 0) char msg_buf[1024]; log_info("SERVER: Received agreement response message %s, outstanding_proposal_acks=%d!", to_string_membership_agreement_msg(ma, msg_buf), m->outstanding_proposal_acks); #endif *merged_membership = NULL; if(m->outstanding_view_id == NULL) { #if (VERBOSE_RPC > 0) log_warn("SERVER: Received Agreement Response message, but no outstanding view proposal is active!"); #endif return -2; } if(m->outstanding_proposal_nonce != ma->nonce) { #if (VERBOSE_RPC > 0) log_warn("SERVER: Received Agreement Response message, but nonce (%" PRId64 ") does not match outstanding view proposal nonce (%" PRId64 ")!", ma->nonce, m->outstanding_proposal_nonce); #endif return -1; } m->outstanding_proposal_acks--; assert(m->outstanding_proposal_acks >=0); if(ma->ack_status == PROPOSAL_STATUS_ACCEPTED) // view identical with proposed one { if(m->outstanding_proposal_acks == 0) { if(m->proposal_status == PROPOSAL_STATUS_ACTIVE) m->proposal_status = PROPOSAL_STATUS_ACCEPTED; // my proposal was accepted *merged_membership = get_membership_state_from_server_list(m->merged_responses, m->merged_client_responses, my_lc); assert(*merged_membership != NULL); } } else if(ma->ack_status == PROPOSAL_STATUS_AMMENDED) { int memberships_differ = merge_membership_agreement_msg_to_list(ma, m->merged_responses, m, prev_vc, fastrandstate); int client_memberships_differ = merge_membership_agreement_msg_to_client_list(ma, m->merged_client_responses, m, prev_vc, fastrandstate); // assert(memberships_differ); if(m->proposal_status != PROPOSAL_STATUS_REJECTED) m->proposal_status = PROPOSAL_STATUS_AMMENDED; // my proposal was ammended if(m->proposal_status == PROPOSAL_STATUS_AMMENDED && m->outstanding_proposal_acks == 0) { *merged_membership = get_membership_state_from_server_list(m->merged_responses, m->merged_client_responses, my_lc); assert(*merged_membership != NULL); } } else { assert(ma->ack_status == PROPOSAL_STATUS_REJECTED); m->proposal_status = PROPOSAL_STATUS_REJECTED; // my proposal was rejected } if((m->proposal_status == PROPOSAL_STATUS_AMMENDED || m->proposal_status == PROPOSAL_STATUS_ACCEPTED) && m->outstanding_proposal_acks == 0) assert(*merged_membership != NULL); return m->proposal_status; } int auto_update_group_queue_subscriptions(membership * m, db_t * db, unsigned int * fastrandstate) { char msg_buf[4096]; log_debug("SERVER: Auto-updating actor queue mapping to groups."); // Update queue group membership from gossip state: for(snode_t * crt_rts = HEAD(m->connected_clients); crt_rts!=NULL; crt_rts = NEXT(crt_rts)) { remote_server * rts = (remote_server *) (crt_rts->value); int rts_id = get_node_id((struct sockaddr *) &(rts->serveraddr)); int update_status = set_bucket_status(db->queue_groups, (WORD) rts_id, rts->status, &get_group_state_key, &get_group_state_live_field); if(update_status < 0) // We just learned of this group; add it { log_debug("SERVER: auto_update_group_queue_subscriptions: Bucket %d not found, adding it", rts_id); group_state * new_group = get_group((WORD) rts_id); add_bucket(db->queue_groups, new_group, &get_group_state_key, &get_group_state_live_field, fastrandstate); } } if(db->queue_groups->buckets->no_items < 1) // 2 { log_debug("SERVER: We only have %d groups in total, nothing to do", db->queue_groups->buckets->no_items); return 0; } // Update cached version of queue group subscriptions for all queues in all DB tables: for(snode_t * crt_table = HEAD(db->tables); crt_table!=NULL; crt_table = NEXT(crt_table)) { db_table_t * table = (db_table_t *) (crt_table->value); for(snode_t * crt_queue = HEAD(table->queues); crt_queue!=NULL; crt_queue = NEXT(crt_queue)) { db_row_t * row = (db_row_t *) (crt_queue->value); WORD result = get_buckets_for_object(db->queue_groups, (int) row->key, db->queue_group_replication_factor, &get_group_state_key, &get_group_state_live_field, fastrandstate); if(db->queue_group_replication_factor > 1 && row->group_subscriptions != NULL) { skiplist_free(row->group_subscriptions); } row->group_subscriptions = result; if(row->group_subscriptions != NULL) create_headers_for_group_subscribers(row, db, fastrandstate); } } return 0; } int install_agreed_view(membership_agreement_msg * ma, membership * m, vector_clock * my_lc, db_t * db, unsigned int * fastrandstate) { #if (VERBOSE_RPC > -1) char msg_buf[1024]; #endif if(compare_vc(m->view_id, ma->vc) > 0) { #if (VERBOSE_RPC > -1) log_info("SERVER: Skipping installing notified view %s because it is older than my installed view %s!", to_string_vc(ma->vc, msg_buf), to_string_vc(m->view_id, msg_buf)); #endif return 1; } // If servers are already connected in local membership, copy their entries from there into agreed membership. Otherwise create new connections for them: skiplist_t * new_membership = create_skiplist(&sockaddr_cmp); int local_view_disagrees = 0; struct sockaddr_in dummy_serveraddr; for(int i=0;imembership->no_nodes;i++) { node_description nd = ma->membership->membership[i]; remote_server * rs = get_remote_server(nd.hostname, nd.portno, dummy_serveraddr, dummy_serveraddr, DUMMY_FD, 0, 0); rs->status = nd.status; snode_t * node = skiplist_search(m->local_peers, &rs->serveraddr); if(node == NULL) // I just learned about this node { int status = connect_remote_server(rs); if(status != 0) { rs->status = NODE_DEAD; rs->sockfd = -1; local_view_disagrees = 1; } status = add_remote_server_to_list(rs, m->local_peers, fastrandstate); assert(status == 0); status = add_remote_server_to_list(rs, new_membership, fastrandstate); assert(status == 0); } else { free_remote_server(rs); remote_server * rs_local = (remote_server *) node->value; if(rs_local->status != nd.status) // if proposed server status is different than local one, and proposed clock is newer, use proposed status { int64_t local_counter = get_component_vc(my_lc, nd.node_id); int64_t proposed_counter = get_component_vc(ma->vc, nd.node_id); if(proposed_counter > local_counter) { rs_local->status = nd.status; } else { local_view_disagrees = 1; } } int status = add_remote_server_to_list(rs_local, new_membership, fastrandstate); assert(status == 0); } } if(m->agreed_peers != NULL) { skiplist_free(m->agreed_peers); } m->agreed_peers = new_membership; update_or_replace_vc(&(m->view_id), ma->vc); if(db->enable_auto_queue_group_subscriptions) { auto_update_group_queue_subscriptions(m, db, fastrandstate); } #if (VERBOSE_RPC > -1) log_info("SERVER: Installed new agreed view %s, local_view_disagrees=%d", to_string_membership_agreement_msg(ma, msg_buf), local_view_disagrees); #endif return local_view_disagrees; } int notify_new_view_to_clients(membership * m, membership_agreement_msg * ma, vector_clock * my_lc) { void * tmp_out_buf = NULL, * q = NULL; unsigned snd_msg_len; char msg_buf[1024]; membership_agreement_msg * amr = NULL; membership_state * mstate = get_membership_state_from_server_list(m->local_peers, m->connected_clients, my_lc); int status = get_agreement_notify_packet(PROPOSAL_STATUS_ACCEPTED, mstate, ma, &amr, &tmp_out_buf, &snd_msg_len, my_lc, my_lc); for(snode_t * crt = HEAD(m->connected_client_sockets); crt!=NULL; crt = NEXT(crt)) { client_descriptor * cd = (client_descriptor *) crt->value; if(cd->sockfd == 0) continue; char client_address2[INET_ADDRSTRLEN]; inet_ntop( AF_INET, &(cd->addr).sin_addr, client_address2, sizeof(client_address2)); log_info("SERVER: Notifying new agreed view %s to client %s:%d, fd=%d", to_string_membership_agreement_msg(ma, msg_buf), client_address2, ntohs(cd->addr.sin_port), cd->sockfd); int n = write(cd->sockfd, tmp_out_buf, snd_msg_len); if (n < 0) error("ERROR writing to socket"); } free_membership_agreement(amr); // free_membership_state(mstate, 0); free(tmp_out_buf); return 0; } int handle_agreement_notify_message(membership_agreement_msg * ma, membership * m, db_t * db, vector_clock * my_lc, vector_clock * prev_vc, unsigned int * fastrandstate) { int ret = install_agreed_view(ma, m, my_lc, db, fastrandstate); notify_new_view_to_clients(m, ma, my_lc); return ret; } int handle_agreement_notify_ack_message(membership_agreement_msg * ma, membership * m, db_t * db, unsigned int * fastrandstate) { return 0; } int parse_gossip_message(void * rcv_buf, size_t rcv_msg_len, membership_agreement_msg ** ma, int64_t * nonce, vector_clock ** vc) { int status = deserialize_membership_agreement_msg(rcv_buf, rcv_msg_len, ma); if(status == 0) { *nonce = (*ma)->nonce; *vc = (*ma)->vc; #if (VERBOSE_RPC > 0) char print_buff[PRINT_BUFSIZE]; to_string_membership_agreement_msg((*ma), (char *) print_buff); log_info("Received gossip message: %s", print_buff); #endif } else { *ma = NULL; *vc = NULL; *nonce = -1; } return status; } int handle_join_message(int childfd, int msg_len, membership * m, db_t * db, unsigned int * fastrandstate, vector_clock * my_lc, int old_id, int my_id, remote_server * rs) { membership_agreement_msg * ma = NULL; int64_t nonce = -1; vector_clock * lc_read = NULL; int local_membership_changed = 0; int status = parse_gossip_message(in_buf + sizeof(int), msg_len, &ma, &nonce, &lc_read); if(status != 0) { log_error("ERROR decoding server join request"); return -1; } if(ma->msg_type != MEMBERSHIP_AGREEMENT_JOIN) { return -1; } #if (VERBOSE_RPC > 0) char msg_buf[1024]; log_info("SERVER: Received new join message %s!", to_string_membership_agreement_msg(ma, msg_buf)); #endif // Update peer socket address to announced one: assert(ma->membership->no_nodes == 1); node_description nd = ma->membership->membership[0]; rs->status = NODE_LIVE; status = update_listen_socket(rs, nd.hostname, nd.portno, 0); assert(status == 0); // Check if newly joined server already existed in local peers. If so, and if announced address differs, update it: snode_t * node = skiplist_search(m->local_peers, &rs->serveraddr); if(node != NULL) { remote_server * old_rs_local = (remote_server *) node->value; if(strcmp((char *) &(rs->id), (char *) &(old_rs_local->id)) != 0) { #if (VERBOSE_RPC > 0) log_info("SERVER: Removing old peer entry from local_peers: %s", old_rs_local->id); #endif skiplist_delete(m->local_peers, &rs->serveraddr); free_remote_server(old_rs_local); } else // I knew of this peer, and entry is the same. Nothing changes in local membership, except for possibly marking that node as live and updating socketfd, of node was previously dead: { int old_status = old_rs_local->status; int new_joiner_id = get_node_id((struct sockaddr *) &(old_rs_local->serveraddr)); assert(my_id != new_joiner_id); if(old_status == NODE_DEAD || my_id < new_joiner_id) { assert(old_rs_local->sockfd <= 0 || my_id < new_joiner_id); #if (VERBOSE_RPC > 0) log_info("SERVER: Peer %s %s. Updating its sockfd from %d to %d, old_status=%d, and marking node live!", old_rs_local->id, (old_status == NODE_DEAD)?"came back up":"sent join request", old_rs_local->sockfd, rs->sockfd, old_rs_local->status); #endif old_rs_local->status = NODE_LIVE; old_rs_local->sockfd = rs->sockfd; } else { assert(old_rs_local->sockfd > 0); #if (VERBOSE_RPC > 0) log_debug("SERVER: I am already connected to peer %s (status = %d), and my id > his id. NOT updating its sockfd from %d to %d, and closing new socket!", old_rs_local->id, old_rs_local->status, old_rs_local->sockfd, rs->sockfd); #endif // close(rs->sockfd); } return old_rs_local->status != old_status; // We s'd propose new membership if local membership changed } } // Add newly joined peer to local_peers: status = add_remote_server_to_membership(rs, m, LOCAL_PEERS, fastrandstate); assert(status == 0); if(ma != NULL) free_membership_agreement(ma); return 1; } int handle_server_message(int childfd, int msg_len, membership * m, db_t * db, unsigned int * fastrandstate, vector_clock * my_lc, int sender_id) { void * tmp_out_buf = NULL; unsigned snd_msg_len; membership_agreement_msg * ma = NULL; int64_t nonce = -1; vector_clock * lc_read = NULL; short output_packet = 1; membership_state * merged_membership = NULL; int status = parse_gossip_message(in_buf + sizeof(int), msg_len, &ma, &nonce, &lc_read); if(status != 0) { log_error("ERROR decoding server gossip message"); return -1; } mark_live(m, sender_id); vector_clock * prev_vc = copy_vc(my_lc); #ifdef UPDATE_LC_ON_GOSSIP if(lc_read != NULL) { // If we were multi-threaded, we'd have to protect this snippet: #if (VERBOSE_RPC > 2) char msg_buf[1024]; log_debug("SERVER: Received server message with LC %s.", to_string_vc(lc_read, msg_buf)); log_debug("SERVER: My LC before update is %s.", to_string_vc(my_lc, msg_buf)); #endif update_vc(my_lc, lc_read); #if (VERBOSE_RPC > 2) log_debug("SERVER: Updated local LC to %s.", to_string_vc(my_lc, msg_buf)); #endif increment_vc(my_lc, m->my_id); #if (VERBOSE_RPC > 2) log_debug("SERVER: Incremented local LC to %s.", to_string_vc(my_lc, msg_buf)); #endif } #endif switch(ma->msg_type) { case MEMBERSHIP_AGREEMENT_PROPOSE: { status = handle_agreement_propose_message(ma, &merged_membership, m, db, copy_vc(my_lc), prev_vc, fastrandstate); // assert(status == 0); status = get_agreement_response_packet(status, merged_membership, ma, &tmp_out_buf, &snd_msg_len, copy_vc(my_lc)); break; } case MEMBERSHIP_AGREEMENT_RESPONSE: { status = handle_agreement_response_message(ma, &merged_membership, m, db, copy_vc(my_lc), prev_vc, fastrandstate); if(status < 0) { output_packet = 0; } else if(m->proposal_status == PROPOSAL_STATUS_REJECTED) { // NOP } else if(m->outstanding_proposal_acks == 0) { assert(merged_membership != NULL); if(m->proposal_status == PROPOSAL_STATUS_ACCEPTED) { membership_agreement_msg * amr = NULL; status = get_agreement_notify_packet(PROPOSAL_STATUS_ACCEPTED, merged_membership, ma, &amr, &tmp_out_buf, &snd_msg_len, copy_vc(my_lc), prev_vc); int local_view_disagrees = install_agreed_view(amr, m, copy_vc(my_lc), db, fastrandstate); notify_new_view_to_clients(m, amr, copy_vc(my_lc)); free_membership_agreement(amr); // if(local_view_disagrees) // { // propose_local_membership(m, copy_vc(my_lc), fastrandstate); // output_packet = 0; // } // } else if(m->proposal_status == PROPOSAL_STATUS_AMMENDED) // re-propose merged membership from previous round { m->outstanding_proposal = skiplist_clone(m->merged_responses, fastrandstate); m->outstanding_proposal_clients = skiplist_clone(m->merged_client_responses, fastrandstate); m->outstanding_view_id = copy_vc(my_lc); m->outstanding_proposal_nonce = _get_nonce(fastrandstate); m->proposal_status = PROPOSAL_STATUS_ACTIVE; m->outstanding_proposal_acks = 0; status = get_agreement_propose_packet(0, get_membership_state_from_server_list(m->outstanding_proposal, m->outstanding_proposal_clients, copy_vc(m->outstanding_view_id)), m->outstanding_proposal_nonce, &tmp_out_buf, &snd_msg_len, copy_vc(m->outstanding_view_id)); } } else { output_packet = 0; } break; } case MEMBERSHIP_AGREEMENT_NOTIFY: { int local_view_disagrees = handle_agreement_notify_message(ma, m, db, copy_vc(my_lc), prev_vc, fastrandstate); // if(local_view_disagrees) // propose_local_membership(m, copy_vc(my_lc), fastrandstate); status = get_agreement_notify_ack_packet(status, ma, &tmp_out_buf, &snd_msg_len, copy_vc(my_lc)); break; } case MEMBERSHIP_AGREEMENT_RETRY_LINK: { assert(0); break; } case MEMBERSHIP_AGREEMENT_NOTIFY_ACK: { status = handle_agreement_notify_ack_message(ma, m, db, fastrandstate); // assert(status == 0); output_packet = 0; break; } } // assert(status == 0); if(output_packet) { if(ma->msg_type == MEMBERSHIP_AGREEMENT_RESPONSE) // multicast notifications { assert(merged_membership != NULL); for(snode_t * crt = HEAD(m->merged_responses); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(rs->status == NODE_LIVE && rs->sockfd > 0 && get_node_id((struct sockaddr *) &(rs->serveraddr)) != m->my_id) // skip myself, and nodes that are "down" in membership { int n = write(rs->sockfd, tmp_out_buf, snd_msg_len); if (n < 0) error("ERROR writing to socket"); m->outstanding_proposal_acks++; } } } else // unicast back response { int n = write(childfd, tmp_out_buf, snd_msg_len); if (n < 0) error("ERROR writing to socket"); } free(tmp_out_buf); } // if(merged_membership != NULL) // free_membership_state(merged_membership); if(ma != NULL) free_membership_agreement(ma); return 0; } typedef struct argp_arguments { int verbosity; int portno; int gportno; char ** seeds; unsigned short * seed_ports; int no_seeds; char * local_iface; char *mon_socket_path; char *log_file_path; } argp_arguments; error_t parse_opt (int key, char *arg, struct argp_state *state) { argp_arguments * arguments = (argp_arguments *) state->input; char tmp_buff[10]; switch (key) { case 'v': arguments->verbosity = 2; break; case 'q': arguments->verbosity = 0; break; case 'p': arguments->portno = atoi(arg); break; case 'm': arguments->gportno = atoi(arg); break; case 's': assert(strnlen(arg, 256) > 1); arguments->no_seeds = 1; for (char * end_ptr = strchr(arg, ','); end_ptr != NULL; end_ptr = strchr(end_ptr + 1, ','), arguments->no_seeds++); arguments->seeds = (char **) malloc(arguments->no_seeds * sizeof(char *)); arguments->seed_ports = (unsigned short *) malloc(arguments->no_seeds * sizeof(int)); char * start_ptr = arg; char * end_ptr = NULL; int stop = 0; for(int i = 0; !stop; i++) { end_ptr = strchr(start_ptr, ','); char * separator_ptr = strchr(start_ptr, ':'); assert(separator_ptr != NULL); *separator_ptr = '\0'; arguments->seeds[i] = strndup(start_ptr, separator_ptr - start_ptr); arguments->seed_ports[i] = (unsigned short) atoi(separator_ptr + 1); if(end_ptr == NULL) { stop = 1; } else { *end_ptr = '\0'; start_ptr = end_ptr + 1; } } break; case 'S': arguments->mon_socket_path = arg; break; case 'i': assert(strnlen(arg, 256) > 1); arguments->local_iface = strndup(arg, 256); break; case 'l': arguments->log_file_path = arg; break; case ARGP_KEY_ARG: case ARGP_KEY_END: // argp_usage (state); break; default: return ARGP_ERR_UNKNOWN; } return 0; } const char* membership_to_json (membership *m) { yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); yyjson_mut_val *root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); yyjson_mut_obj_add_str(doc, root, "name", "membership"); yyjson_mut_obj_add_int(doc, root, "pid", pid); struct timeval tv; struct tm tm; gettimeofday(&tv, NULL); localtime_r(&tv.tv_sec, &tm); char dt[32]; // = "YYYY-MM-ddTHH:mm:ss.SSS+0000"; strftime(dt, 32, "%Y-%m-%dT%H:%M:%S.000%z", &tm); sprintf(dt + 20, "%03hu%s", (unsigned short)(tv.tv_usec / 1000), dt + 23); yyjson_mut_obj_add_str(doc, root, "datetime", dt); yyjson_mut_val *j_mbm = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, root, "membership", j_mbm); yyjson_mut_obj_add_int(doc, j_mbm, "my_id", m->my_id); char view_id[1024]; yyjson_mut_obj_add_str(doc, j_mbm, "view_id", to_string_vc(m->view_id, view_id)); yyjson_mut_val *j_nodes = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, root, "nodes", j_nodes); for(snode_t * crt = HEAD(m->agreed_peers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; yyjson_mut_val *j_node = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, j_nodes, rs->id, j_node); yyjson_mut_obj_add_str(doc, j_node, "type", "DDB"); yyjson_mut_obj_add_str(doc, j_node, "hostname", rs->hostname); yyjson_mut_obj_add_str(doc, j_node, "status", RS_status_name[rs->status]); } for(snode_t * crt = HEAD(m->connected_clients); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; yyjson_mut_val *j_node = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, j_nodes, rs->id, j_node); yyjson_mut_obj_add_str(doc, j_node, "type", "RTS"); yyjson_mut_obj_add_str(doc, j_node, "hostname", rs->hostname); yyjson_mut_obj_add_str(doc, j_node, "status", RS_status_name[rs->status]); } const char *json = yyjson_mut_write(doc, 0, NULL); yyjson_mut_doc_free(doc); return json; } int main(int argc, char **argv) { int parentfd, gparentfd, childfd; int portno, gportno; unsigned int clientlen; struct sockaddr_in serveraddr, gserveraddr, clientaddr; struct hostent *hostp; char *hostaddrp; int optval; /* flag value for setsockopt */ int msg_len; /* message byte size */ fd_set readfds; struct timeval timeout; timeout.tv_sec = 3; timeout.tv_usec = 0; unsigned int seed; int ret = 0; char msg_buf[1024]; int verbosity = SERVER_VERBOSITY; FILE *logf = NULL; pid = getpid(); // Do line buffered output setlinebuf(stdout); const char *argp_program_version = "ddb server 1.0"; static struct argp_option options[] = { {"verbose", 'v', 0, 0, "Produce verbose output" }, {"quiet", 'q', 0, 0, "Don't produce any output" }, {"port", 'p', "PORT", 0, "Port for client data requests" }, {"mon-socket-path", 'S', "PATH", 0, "Path to unix socket to expose mon stats" }, {"mport", 'm', "MPORT", 0, "Port for server gossip packets" }, {"seeds", 's', "SEEDS", 0, "Seeds, comma-separated" }, {"iface", 'i', "IFACE", 0, "Local interface to listen to" }, {"log-file", 'l', "FILE", 0, "Log file" }, { 0 } }; static struct argp argp = { options, parse_opt, NULL, "ddb - standalone server module" }; argp_arguments arguments; /* Default values. */ arguments.verbosity = 1; arguments.portno = DEFAULT_DATA_PORT; arguments.gportno = -1; arguments.local_iface = "127.0.0.1"; arguments.no_seeds = 0; arguments.mon_socket_path = NULL; arguments.log_file_path = NULL; argp_parse (&argp, argc, argv, 0, 0, &arguments); if (arguments.log_file_path) { logf = fopen(arguments.log_file_path, "w"); if (!logf) { log_error("Unable to open log file (%s) for writing", arguments.log_file_path); exit(1); } log_add_fp(logf, LOG_DEBUG); // LOG_TRACE // Turn off log output on stderr log_set_quiet(true); } // Ignore SIGPIPE: struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) == -1) { error("sigaction(SIG_IGN SIGPIPE) failed"); } portno = arguments.portno; // NOTE: gossip port is expected to be +1 from the RPC port. This is a current // limitation of the gossip protocol as it doesn't carry information about a // separate gossip port. if (arguments.gportno > 0) { // TODO: remove this once gossip protocol carries gossip port info if (arguments.gportno != arguments.portno+1) log_warn("Using a gossip port other than RPC port + 1 is not a supported configuration"); gportno = arguments.gportno; } else { gportno = arguments.portno+1; } verbosity = arguments.verbosity; log_info("Using args: portno=%d, gportno=%d, verbosity=%d, seeds:", portno, gportno, verbosity); for(int i=0;ih_name); log_info("%s:%d", arguments.seeds[i], arguments.seed_ports[i]); } skiplist_t * clients = create_skiplist(&sockaddr_cmp); // List of remote clients GET_RANDSEED(&seed, 0); // thread_id // Get db pointer: db_t * db = get_db(); // Create schema: ret = create_state_schema(db, &seed); if (ret == 0) { log_info("State schema successfully created"); } else { log_fatal("Failed to create state schema"); } ret = create_queue_schema(db, &seed); if (ret == 0) { log_info("Queue schema successfully created"); } else { log_fatal("Failed to create queue schema"); } struct hostent * local_iface_hostent = gethostbyname(arguments.local_iface); // Set up main data socket: parentfd = socket(AF_INET, SOCK_STREAM, 0); if (parentfd < 0) error("ERROR opening socket"); optval = 1; setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)); bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons((unsigned short) portno); // Set up main gossip socket: gparentfd = socket(AF_INET, SOCK_STREAM, 0); if (gparentfd < 0) error("ERROR opening gossip socket"); setsockopt(gparentfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)); bzero((char *) &gserveraddr, sizeof(serveraddr)); gserveraddr.sin_family = AF_INET; bcopy(local_iface_hostent->h_addr_list[0], (char *)&(gserveraddr.sin_addr.s_addr), local_iface_hostent->h_length); // gserveraddr.sin_addr.s_addr = htonl(INADDR_ANY); gserveraddr.sin_port = htons((uint16_t) gportno); int my_id = get_node_id((struct sockaddr *) &gserveraddr); char * my_address = strdup(inet_ntoa(gserveraddr.sin_addr)); unsigned short my_port = (unsigned short) ntohs(gserveraddr.sin_port); vector_clock * my_lc = init_local_vc_id(my_id); membership * m = get_membership(my_id); m->connected_client_sockets = clients; log_info("Started [%s:%d, %s:%d], my_lc = %s", inet_ntoa(serveraddr.sin_addr), ntohs(serveraddr.sin_port), my_address, my_port, to_string_vc(my_lc, msg_buf)); // Set up monitoring socket int mon_sock=-1, mon_client_sock=-1; struct sockaddr_un mon_addr, mon_client_addr; char mon_rbuf[64]; size_t mon_buf_used = 0; if (arguments.mon_socket_path) { if ((mon_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { log_error(LOGPFX "ERROR: Unable to create Monitor Socket"); exit(1); } mon_addr.sun_family = AF_UNIX; strcpy(mon_addr.sun_path, arguments.mon_socket_path); unlink(mon_addr.sun_path); if (bind(mon_sock, (struct sockaddr *)&mon_addr, sizeof(mon_addr.sun_path) + sizeof(mon_addr.sun_family)) == -1) { log_error(LOGPFX "ERROR: Unable to bind to Monitor Socket"); exit(1); } if (listen(mon_sock, 5) == -1) { log_error(LOGPFX "ERROR: Unable to listen on Monitor Socket"); exit(1); } } if (bind(parentfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) error("ERROR on binding client socket"); if (listen(parentfd, 100) < 0) /* allow 100 requests to queue up */ error("ERROR on listen client socket"); if (bind(gparentfd, (struct sockaddr *) &gserveraddr, sizeof(serveraddr)) < 0) error("ERROR on binding gossip socket"); if (listen(gparentfd, 100) < 0) /* allow 100 requests to queue up */ error("ERROR on listen gossip socket"); // Add myself to local membership: remote_server * rsp = NULL; ret = add_peer_to_membership(my_address, my_port, gserveraddr, OWN_FD, 0, m, LOCAL_PEERS, &rsp, &seed); // Now add seed servers: struct sockaddr_in dummy_serveraddr; for(int i=0;i 0) // Also skip connecting to seed nodes with IP:port bigger (lexicographycally) than myself (they will connect to me as they come up): if(cmp_res > 0 || ((cmp_res == 0) && (arguments.seed_ports[i] > my_port)) ) { log_debug("SERVER: Skipping connecting to seed %s:%d (> myself)", arguments.seeds[i], arguments.seed_ports[i]); } else { #endif log_debug("SERVER: Connecting to %s:%d..", arguments.seeds[i], arguments.seed_ports[i]); ret = add_peer_to_membership(arguments.seeds[i], arguments.seed_ports[i], dummy_serveraddr, DUMMY_FD, 1, m, LOCAL_PEERS, &rsp, &seed); if(ret == 0 && rsp->status == NODE_LIVE) { ret = send_join_message(0, 0, my_address, my_port, my_lc, rsp, &seed); } #if (DO_HIERARCHICAL_CONNECT > 0) } #endif } ret = propose_local_membership(m, copy_vc(my_lc), NULL, -1, &seed); clientlen = sizeof(clientaddr); while(1) { FD_ZERO(&readfds); // Add parent sockets to read set: FD_SET(parentfd, &readfds); FD_SET(gparentfd, &readfds); int max_fd = (parentfd>gparentfd)?(parentfd):(gparentfd); // Add active clients to read set: for(snode_t * crt = HEAD(clients); crt!=NULL; crt = NEXT(crt)) { client_descriptor * rs = (client_descriptor *) crt->value; if(rs->sockfd > 0) { // log_debug("SERVER: Listening to client socket %s..", rs->id); FD_SET(rs->sockfd, &readfds); max_fd = (rs->sockfd > max_fd)? rs->sockfd : max_fd; } else { // log_debug("SERVER: Not listening to disconnected client socket %s..", rs->id); } } // Add active peers to read set: for(snode_t * crt = HEAD(m->local_peers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(rs->sockfd > 0) { if(verbosity > 3) { ret = fcntl(rs->sockfd, F_GETFL); log_debug("active peer %s, sockfd=%d, status=%d, flags=%d", rs->id, rs->sockfd, rs->status, ret); } // log_debug("SERVER: Listening to peer socket %s..", rs->id); FD_SET(rs->sockfd, &readfds); max_fd = (rs->sockfd > max_fd)? rs->sockfd : max_fd; } else { // log_debug("SERVER: Not listening to disconnected peer socket %s..", rs->id); } } // Add active pre-joined peers to read set: for(snode_t * crt = HEAD(m->connected_peers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(rs->sockfd > 0 && rs->status == NODE_PREJOINED) { if(verbosity > 3) { ret = fcntl(rs->sockfd, F_GETFL); log_debug("pre-joined peer %s, sockfd=%d, status=%d, flags=%d", rs->id, rs->sockfd, rs->status, ret); } // log_debug("SERVER: Listening to peer socket %s..", rs->id); FD_SET(rs->sockfd, &readfds); max_fd = (rs->sockfd > max_fd)? rs->sockfd : max_fd; } else { // log_debug("SERVER: Not listening to disconnected peer socket %s..", rs->id); } } // Monitor socket if (mon_sock > 0) { FD_SET(mon_sock, &readfds); max_fd = (mon_sock > max_fd)? mon_sock : max_fd; } if (mon_client_sock > 0) { FD_SET(mon_client_sock, &readfds); max_fd = (mon_client_sock > max_fd)? mon_client_sock : max_fd; } int status = select(max_fd + 1, &readfds, NULL, NULL, NULL); // &timeout if (status < 0) { if ((errno != EINTR) && (errno != EBADF)) { log_error("select error, errno: %d", errno); assert(0); // EINVAL, ENOMEM } continue; } if(verbosity > 3) log_debug("select returned %d/%d!", status, errno); // Monitor socket if (mon_sock > 0 && FD_ISSET(mon_sock, &readfds)) { if (mon_client_sock == -1) { socklen_t t = sizeof(mon_client_sock); if ((mon_client_sock = accept(mon_sock, (struct sockaddr *)&mon_client_addr, &t)) == -1) { perror("accept"); exit(1); } } } // Monitor socket client requests if (mon_client_sock > 0 && FD_ISSET(mon_client_sock, &readfds)) { char *buf_base, *str; size_t len; ssize_t bytes_read = recv(mon_client_sock, &mon_rbuf[mon_buf_used], sizeof(mon_rbuf) - mon_buf_used, 0); if (bytes_read <= 0) { close(mon_client_sock); mon_client_sock = -1; } else { mon_buf_used += bytes_read; buf_base = mon_rbuf; while (1) { if (mon_buf_used == 0) break; int r = netstring_read(&buf_base, &mon_buf_used, &str, &len); if (r != 0) { log_error(LOGPFX "Mon socket: Error reading netstring: %d", r); break; } if (memcmp(str, "membership", len) == 0) { const char *json = membership_to_json(m); char *send_buf = malloc(strlen(json)+14); // maximum digits for length is 9 (999999999) + : + ; + \0 sprintf(send_buf, "%lu:%s,", strlen(json), json); int send_res = send(mon_client_sock, send_buf, strlen(send_buf), 0); free((void *)json); free((void *)send_buf); if (send_res < 0) { break; } } } if (buf_base > mon_rbuf && mon_buf_used > 0) memmove(mon_rbuf, buf_base, mon_buf_used); } } // Check if there's a new connection attempt from a client: if(FD_ISSET(parentfd, &readfds)) { childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen); if (childfd < 0) error("ERROR on accept"); #ifdef MACOS int option_set = 1; if (setsockopt (childfd, SOL_SOCKET, SO_NOSIGPIPE, &option_set, sizeof (option_set)) < 0) { error("setsockopt(SO_NOSIGPIPE)"); } #endif hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, sizeof(clientaddr.sin_addr.s_addr), AF_INET); if (hostp == NULL) error("ERROR on gethostbyaddr"); hostaddrp = strdup(inet_ntoa(clientaddr.sin_addr)); if (hostaddrp == NULL) error("ERROR on inet_ntoa"); log_info("SERVER: accepted connection from client: %s (%s:%d)", hostp->h_name, hostaddrp, ntohs(clientaddr.sin_port)); ret = add_client_to_membership(clientaddr, childfd, hostaddrp, ntohs(clientaddr.sin_port), clients, &seed); // hostp->h_name // assert(ret == 0); } // Check if there's a new connection attempt from a peer server: if(FD_ISSET(gparentfd, &readfds)) { childfd = accept(gparentfd, (struct sockaddr *) &clientaddr, &clientlen); if (childfd < 0) error("ERROR on accept"); #ifdef MACOS int option_set = 1; if (setsockopt (childfd, SOL_SOCKET, SO_NOSIGPIPE, &option_set, sizeof (option_set)) < 0) { error("setsockopt(SO_NOSIGPIPE)"); } #endif hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, sizeof(clientaddr.sin_addr.s_addr), AF_INET); if (hostp == NULL) error("ERROR on gethostbyaddr"); hostaddrp = strdup(inet_ntoa(clientaddr.sin_addr)); if (hostaddrp == NULL) error("ERROR on inet_ntoa"); log_info("SERVER: accepted connection from peer: %s (%s:%d), sockfd=%d", hostp->h_name, hostaddrp, ntohs(clientaddr.sin_port), childfd); ret = add_peer_to_membership(hostaddrp, ntohs(clientaddr.sin_port), clientaddr, childfd, 0, m, CONNECTED_PEERS, &rsp, &seed); // hostp->h_name rsp->status = NODE_PREJOINED; // assert(ret == 0); continue; } // Check if there are messages from existing clients: for(snode_t * crt = HEAD(clients); crt!=NULL; crt = NEXT(crt)) { client_descriptor * cd = (client_descriptor *) crt->value; if(cd->sockfd > 0 && FD_ISSET(cd->sockfd , &readfds)) // Received a msg from this client: { if(read_full_packet(&(cd->sockfd), (char *) in_buf, SERVER_BUFSIZE, &msg_len, &ret, &handle_socket_close)) { if(ret == NODE_DEAD) { remote_server * rs = lookup_client_by_client_socket_addr(&(cd->addr), m->connected_clients); if(rs != NULL) { rs->status = NODE_DEAD; log_debug("Client %s, sockfd=%d, status=%d went dead, proposing new membership..", rs->id, rs->sockfd, rs->status); propose_local_membership(m, copy_vc(my_lc), NULL, -1, &seed); } } continue; } if(handle_client_message(cd->sockfd, msg_len, db, m, clients, &seed, my_lc, my_id)) continue; } } // Check if there are messages from peer servers: for(snode_t * crt = HEAD(m->local_peers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(rs->sockfd > 0 && FD_ISSET(rs->sockfd , &readfds)) // Received a msg from this server: { log_trace("active peer %s, sockfd=%d, status=%d is ready for reading", rs->id, rs->sockfd, rs->status); ret = read_full_packet(&(rs->sockfd), (char *) in_buf, SERVER_BUFSIZE, &msg_len, &(rs->status), &handle_socket_close); if(rs->status == NODE_DEAD || rs->sockfd <= 0) // If peer closed socket, propose it removed from agreed membership { propose_local_membership(m, copy_vc(my_lc), NULL, -1, &seed); continue; } int sender_id = get_node_id((struct sockaddr *) &(rs->serveraddr)); if(handle_server_message(rs->sockfd, msg_len, m, db, &seed, my_lc, sender_id)) continue; } } // Check if there are messages from pre-joined peer servers: for(snode_t * crt = HEAD(m->connected_peers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(rs->status == NODE_PREJOINED && rs->sockfd > 0 && FD_ISSET(rs->sockfd , &readfds)) // Received a msg from this server: { log_trace("pre-joined peer %s, sockfd=%d, status=%d is ready for reading", rs->id, rs->sockfd, rs->status); ret = read_full_packet(&(rs->sockfd), (char *) in_buf, SERVER_BUFSIZE, &msg_len, &(rs->status), &handle_socket_nop); // TO DO: If peer closed socket before it sent join packet (rs->status == NODE_DEAD || rs->sockfd <= 0), also remove it from connected list to save some space if(ret) continue; int sender_id = get_node_id((struct sockaddr *) &(rs->serveraddr)); if((ret=handle_join_message(rs->sockfd, msg_len, m, db, &seed, my_lc, sender_id, my_id, rs)) < 0) { if(handle_server_message(rs->sockfd, msg_len, m, db, &seed, my_lc, sender_id)) continue; } if(ret > 0) // local membership changed { if(verbosity > 0) log_debug("Membership changed after %s/%d/%d joined, proposing new membership", rs->id, rs->sockfd, rs->status); propose_local_membership(m, copy_vc(my_lc), NULL, -1, &seed); } else { if(verbosity > 0) log_debug("Membership did not change after %s/%d/%d joined, NOT proposing new membership", rs->id, rs->sockfd, rs->status); } } } } // Close sockets to clients and peers: for(snode_t * crt = HEAD(clients); crt!=NULL; crt = NEXT(crt)) { client_descriptor * rs = (client_descriptor *) crt->value; if(rs->sockfd > 0) { close(rs->sockfd); } } for(snode_t * crt = HEAD(m->local_peers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(rs->sockfd > 0) { close(rs->sockfd); } } if (logf) { fclose(logf); } } ================================================ FILE: backend/client_api.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * client_api.c * * Author: aagapi */ #include "client_api.h" #include "hash_ring.h" #include "log.h" #define GC_THREADS 1 #include "gc.h" struct dbc_stat dbc_stats; void zeroize_dbc_ops_stats(struct dbc_ops_stat *ops_stat, const char *name) { ops_stat->name = name; ops_stat->called = 0; ops_stat->completed = 0; ops_stat->success = 0; ops_stat->error = 0; ops_stat->no_quorum = 0; ops_stat->time_sum = 0; ops_stat->time_100ns = 0; ops_stat->time_1us = 0; ops_stat->time_10us = 0; ops_stat->time_100us = 0; ops_stat->time_1ms = 0; ops_stat->time_10ms = 0; ops_stat->time_100ms = 0; ops_stat->time_1s = 0; ops_stat->time_10s = 0; ops_stat->time_100s = 0; ops_stat->time_inf = 0; } void init_dbc_stats() { #define X(ops_name) \ dbc_stats.ops_name = malloc(sizeof(struct dbc_ops_stat)); \ zeroize_dbc_ops_stats(dbc_stats.ops_name, #ops_name); LIST_OF_DBC_OPS #undef X } void stat_start(struct dbc_ops_stat *ops_stat, struct timespec *ts_start) { ops_stat->called++; clock_gettime(CLOCK_MONOTONIC, ts_start); } void stat_stop(struct dbc_ops_stat *ops_stat, struct timespec *ts_start, int status) { ops_stat->completed++; struct timespec ts_stop; clock_gettime(CLOCK_MONOTONIC, &ts_stop); long long int diff = (ts_stop.tv_sec * 1000000000 + ts_stop.tv_nsec) - ((long long int)ts_start->tv_sec * 1000000000 + (long long int)ts_start->tv_nsec); if (diff < 100) { ops_stat->time_100ns++; } else if (diff < 1 * 1000) { ops_stat->time_1us++; } else if (diff < 10 * 1000) { ops_stat->time_10us++; } else if (diff < 100 * 1000) { ops_stat->time_100us++; } else if (diff < 1 * 1000000) { ops_stat->time_1ms++; } else if (diff < 10 * 1000000) { ops_stat->time_10ms++; } else if (diff < 100 * 1000000) { ops_stat->time_100ms++; } else if (diff < 1 * 1000000000) { ops_stat->time_1s++; } else if (diff < (long long int)10 * 1000000000) { ops_stat->time_10s++; } else if (diff < (long long int)100 * 1000000000) { ops_stat->time_100s++; } else { ops_stat->time_inf++; } if (status == 0) { ops_stat->success++; } else if (status == NO_QUORUM_ERR) { ops_stat->error++; ops_stat->no_quorum++; } else if (status < 0) { ops_stat->error++; } else { log_error("Unknown ops status %d", status); assert(0); } } int64_t requests=0; int queue_callback_cmp(WORD e1, WORD e2) { queue_callback_args * a1 = (queue_callback_args *) e1; queue_callback_args * a2 = (queue_callback_args *) e2; if(a1->consumer_id != a2->consumer_id) return (int64_t) a1->consumer_id - (int64_t) a2->consumer_id; if(a1->queue_id != a2->queue_id) return (int64_t) a1->queue_id - (int64_t) a2->queue_id; if(a1->table_key != a2->table_key) return (int64_t) a1->table_key - (int64_t) a2->table_key; if(a1->shard_id != a2->shard_id) return (int64_t) a1->shard_id - (int64_t) a2->shard_id; if(a1->app_id != a2->app_id) return (int64_t) a1->app_id - (int64_t) a2->app_id; return 0; } int queue_group_callback_cmp(WORD e1, WORD e2) { queue_callback_args * a1 = (queue_callback_args *) e1; queue_callback_args * a2 = (queue_callback_args *) e2; if(a1->consumer_id != a2->consumer_id) return (int64_t) a1->consumer_id - (int64_t) a2->consumer_id; if(a1->group_id != a2->group_id) return (int64_t) a1->group_id - (int64_t) a2->group_id; if(a1->shard_id != a2->shard_id) return (int64_t) a1->shard_id - (int64_t) a2->shard_id; if(a1->app_id != a2->app_id) return (int64_t) a1->app_id - (int64_t) a2->app_id; return 0; } // Remote DB API: void * comm_thread_loop(void * args); remote_db_t * get_remote_db(int replication_factor, int rack_id, int dc_id, char * hostname, unsigned short local_rts_id, int no_seeds, char ** seed_hosts, int * seed_ports, unsigned int * seedptr) { remote_db_t * db = (remote_db_t *) malloc(sizeof(remote_db_t) + 5 * sizeof(pthread_mutex_t) + sizeof(pthread_cond_t)); memset(db, 0, sizeof(remote_db_t) + 5 * sizeof(pthread_mutex_t) + sizeof(pthread_cond_t)); db->servers = create_skiplist(&sockaddr_cmp); db->rtses = create_skiplist(&sockaddr_cmp); db->actors = create_skiplist_long(); db->_rts_ring = get_hash_ring(); db->txn_state = create_skiplist_uuid(); db->queue_subscriptions = create_skiplist(&queue_callback_cmp); db->group_queue_subscriptions = create_skiplist(&queue_group_callback_cmp); db->msg_callbacks = create_skiplist_long(); db->subscribe_lock = (pthread_mutex_t*) ((char*) db + sizeof(remote_db_t)); pthread_mutex_init(db->subscribe_lock, NULL); db->msg_callbacks_lock = (pthread_mutex_t*) ((char*) db + sizeof(remote_db_t) + sizeof(pthread_mutex_t)); pthread_mutex_init(db->msg_callbacks_lock, NULL); db->lc_lock = (pthread_mutex_t*) ((char*) db + sizeof(remote_db_t) + 2 * sizeof(pthread_mutex_t)); pthread_mutex_init(db->lc_lock, NULL); db->txn_state_lock = (pthread_mutex_t*) ((char*) db + sizeof(remote_db_t) + 3 * sizeof(pthread_mutex_t)); pthread_mutex_init(db->txn_state_lock, NULL); db->gossip_lock = (pthread_mutex_t*) ((char*) db + sizeof(remote_db_t) + 4 * sizeof(pthread_mutex_t)); pthread_mutex_init(db->gossip_lock, NULL); db->gossip_signal = (pthread_cond_t*) ((char*) db + sizeof(remote_db_t) + 5 * sizeof(pthread_mutex_t)); pthread_cond_init(db->gossip_signal, NULL); db->replication_factor = replication_factor; db->quorum_size = (int) (replication_factor / 2) + 1; db->rpc_timeout = 10; db->actor_replication_factor = 1; db->stop_comm = 0; int r = pipe(db->wakeup_pipe); #ifdef ACTON_THREADS assert(pthread_create(&(db->comm_thread), NULL, comm_thread_loop, db) == 0); #else assert(1==0 && "DB client API not supported in single-threaded mode!"); #endif db->my_lc = init_empty_vc(); db->current_view_id = NULL; for(int i=0; igossip_lock); if(db->current_view_id != NULL && (compare_vc(db->current_view_id, ma->vc) == VC_INCOMPARABLE || compare_vc(db->current_view_id, ma->vc) == VC_DISJOINT)) { #if (VERBOSE_RPC > -1) log_debug("CLIENT: Skipping installing notified view %s because it is incomparable to my installed view %s (client is remaining sticky to previous partition)!", to_string_vc(ma->vc, msg_buf), to_string_vc(db->current_view_id, msg_buf2)); #endif pthread_mutex_unlock(db->gossip_lock); return 1; } if(db->current_view_id != NULL && compare_vc(db->current_view_id, ma->vc) > 0) { #if (VERBOSE_RPC > -1) log_debug("CLIENT: Skipping installing notified view %s because it is older than my installed view %s!", to_string_vc(ma->vc, msg_buf), to_string_vc(db->current_view_id, msg_buf2)); #endif pthread_mutex_unlock(db->gossip_lock); return 1; } // The local RTS might transiently be marked dead in the gossip message, or might be missing from the view altogether, // in which case we should wait for the gossip to settle before installing local view. // This can happen for instance if a node quickly crashes and rejoins, or if a transient partition happens // and the gossip agreement round does not complete before the partition heals // This leads to issue https://github.com/actonlang/acton/issues/788 int found_local = 0; for(int i=0;imembership->no_client_nodes;i++) { node_description nd = ma->membership->client_membership[i]; if(get_node_id((struct sockaddr *) &(nd.address)) == db->local_rts_id) { found_local = 1; if(nd.status != NODE_LIVE) { #if (VERBOSE_RPC > -1) log_debug("CLIENT: Skipping installing notified view %s because it transiently marks local RTS as dead.", to_string_vc(ma->vc, msg_buf)); #endif pthread_mutex_unlock(db->gossip_lock); return 1; } } } if(found_local == 0) { #if (VERBOSE_RPC > -1) log_debug("CLIENT: Skipping installing notified view %s because it transiently lacks knowledge of local RTS.", to_string_vc(ma->vc, msg_buf)); #endif pthread_mutex_unlock(db->gossip_lock); return 1; } // Add DB servers we have recently found about to client's server membership: for(int i=0;imembership->no_nodes;i++) { node_description nd = ma->membership->membership[i]; add_server_to_membership(nd.hostname, nd.portno - 1, nd.status, db, fastrandstate); } // Add RTSs we have recently found about to client's RTS membership: for(int i=0;imembership->no_client_nodes;i++) { node_description nd = ma->membership->client_membership[i]; add_rts_to_membership(nd.rack_id, nd.dc_id, nd.hostname, nd.portno, nd.status, db->rtses, db->_rts_ring, fastrandstate); } // Update actor placement: update_actor_placement(db); update_or_replace_vc(&(db->current_view_id), ma->vc); pthread_mutex_unlock(db->gossip_lock); #if (VERBOSE_RPC > -1) log_debug("CLIENT: Installed new agreed view %s", to_string_membership_agreement_msg(ma, msg_buf)); #endif log_debug("CLIENT: RTS membership: %s", to_string_rts_membership(db, msg_buf)); return 0; } void comm_wake_up(remote_db_t *db) { // Write dummy data that wakes up the comms thread int r = write(db->wakeup_pipe[1], "!", 1); } void * comm_thread_loop(void * args) { remote_db_t * db = (remote_db_t *) args; struct timeval timeout; char in_buf[BUFSIZE]; int msg_len = -1; int announced_msg_len = -1; int read_buf_offset = 0; while(!db->stop_comm) { timeout.tv_sec = 3; timeout.tv_usec = 0; FD_ZERO(&(db->readfds)); FD_SET(db->wakeup_pipe[0], &(db->readfds)); int max_fd = db->wakeup_pipe[0]; for(snode_t * crt = HEAD(db->servers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(rs->sockfd > 0) { // log_info("Listening to server socket %s..", rs->id); FD_SET(rs->sockfd, &(db->readfds)); max_fd = (rs->sockfd > max_fd)? rs->sockfd : max_fd; } else { // log_info("Not listening to disconnected server socket %s..", rs->id); } } int status = select(max_fd + 1 , &(db->readfds) , NULL , NULL , &timeout); if (status < 0) { if (errno != EINTR && errno != EBADF) { log_error("select error, errno: %d", errno); assert(0); // EINVAL, ENOMEM } continue; } if (FD_ISSET(db->wakeup_pipe[0], &(db->readfds))) { char dummy; int r = read(db->wakeup_pipe[0], &dummy, 1); // Consume dummy data } for(snode_t * crt = HEAD(db->servers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; if(rs->sockfd > 0 && FD_ISSET(rs->sockfd , &(db->readfds))) // Received a msg from this server: { int skip_parsing = 0; while(1) // Loop until reading complete packet: { assert(read_buf_offset < BUFSIZE - sizeof(int)); if(read_buf_offset == 0) { // Read msg len header from packet: bzero(in_buf, BUFSIZE); msg_len = -1; int size_len = read(rs->sockfd, in_buf, sizeof(int)); if (size_len < 0) { continue; } else if (size_len == 0) { handle_socket_close(&(rs->sockfd)); skip_parsing = 1; break; } announced_msg_len = *((int *)in_buf); *((int *)in_buf) = 0; // 0 back buffer read_buf_offset = 0; } if(announced_msg_len <= 0) { read_buf_offset = 0; continue; } msg_len = read(rs->sockfd, in_buf + sizeof(int) + read_buf_offset, announced_msg_len - read_buf_offset); #if CLIENT_VERBOSITY > 1 log_info("announced_msg_len=%d, msg_len=%d, read_buf_offset=%d", announced_msg_len, msg_len, read_buf_offset); #endif if (msg_len < 0) { log_error("ERROR reading from socket"); continue; } else if(msg_len == 0) // client closed socket { handle_socket_close(&(rs->sockfd)); skip_parsing = 1; break; } else if(msg_len < announced_msg_len - read_buf_offset) { read_buf_offset += msg_len; continue; // Continue reading socket until full packet length } break; } if(skip_parsing) continue; if(announced_msg_len != msg_len) { log_info("2: announced_msg_len=%d, msg_len=%d, read_buf_offset=%d", announced_msg_len, msg_len, read_buf_offset); assert(0); } read_buf_offset = 0; // Reset #if CLIENT_VERBOSITY > 1 log_info("client received %d / %d bytes", announced_msg_len, msg_len); #endif void * tmp_out_buf = NULL, * q = NULL; short msg_type; short is_gossip_message; db_schema_t * schema; int64_t nonce = -1; vector_clock * lc_read = NULL; int status = parse_message(in_buf + sizeof(int), msg_len, &q, &msg_type, &is_gossip_message, &nonce, 0, &lc_read); if(status != 0) { log_error("ERROR decoding server response!"); continue; assert(0); } if(lc_read != NULL) { update_lc_protected(db, lc_read); free_vc(lc_read); } if(nonce > 0) // A server reply { status = add_reply_to_nonce(q, msg_type, nonce, db); } else if (msg_type == RPC_TYPE_QUEUE) // A queue notification { // Notify local subscriber if found: queue_query_message * qqm = (queue_query_message *) q; assert(qqm->msg_type == QUERY_TYPE_QUEUE_NOTIFICATION); WORD notif_table_key = (WORD) qqm->cell_address->table_key; WORD notif_queue_id = (WORD) qqm->cell_address->keys[0]; queue_callback * qc = get_queue_client_callback((WORD) qqm->consumer_id, (WORD) qqm->shard_id, (WORD) qqm->app_id, (WORD) qqm->group_id, notif_table_key, notif_queue_id, 1, db); if(qc == NULL) { log_error("CLIENT: No local subscriber subscriber %" PRId64 "/%" PRId64 "/%" PRId64 " exists for queue %" PRId64 "/%" PRId64 "!", (int64_t) qqm->consumer_id, (int64_t) qqm->shard_id, (int64_t) qqm->app_id, (int64_t) notif_table_key, (int64_t) notif_queue_id); continue; } queue_callback_args * qca = get_queue_callback_args(notif_table_key, notif_queue_id, (WORD) qqm->app_id, (WORD) qqm->shard_id, (WORD) qqm->consumer_id, (WORD) qqm->group_id, QUEUE_NOTIF_ENQUEUED); #if (CLIENT_VERBOSITY > 0) log_info("CLIENT: Attempting to notify local subscriber %" PRId64 " (%p/%p/%p/%p)", (int64_t) qqm->consumer_id, qc, qc->lock, qc->signal, qc->callback); #endif status = pthread_mutex_lock(qc->lock); #if (CLIENT_LOCK_VERBOSITY > 0) log_info("CLIENT: Locked consumer lock of %" PRId64 " (%p/%p), status=%d", (int64_t) qqm->consumer_id, qc, qc->lock, status); #endif pthread_cond_signal(qc->signal); qc->callback(qca); status = pthread_mutex_unlock(qc->lock); assert(status == 0); #if (CLIENT_LOCK_VERBOSITY > 0) log_info("CLIENT: Unlocked consumer lock of %" PRId64 " (%p/%p), status=%d", (int64_t) qqm->consumer_id, qc, qc->lock, status); #endif #if (CLIENT_VERBOSITY > 0) log_info("CLIENT: Notified local subscriber %" PRId64 " (%p/%p/%p/%p)", (int64_t) qqm->consumer_id, qc, qc->lock, qc->signal, qc->callback); #endif } else // a gossip notification { assert(is_gossip_message && msg_type == MEMBERSHIP_AGREEMENT_NOTIFY); membership_agreement_msg * ma = (membership_agreement_msg *) q; assert(ma->msg_type == MEMBERSHIP_AGREEMENT_NOTIFY); install_gossiped_view(ma, db, &(db->fastrandstate)); free_membership_agreement(ma); } // assert(status > 0); } } } return NULL; } int add_server_to_membership(char *hostname, int portno, int status, remote_db_t * db, unsigned int * seedptr) { struct sockaddr_in dummy_serveraddr; remote_server * rs = get_remote_server(hostname, portno, dummy_serveraddr, dummy_serveraddr, DUMMY_FD, 0, 0); rs->status = status; if(rs == NULL) { log_error("ERROR: Failed joining server %s:%d (DNS/network problem?)!", hostname, portno); return 1; } snode_t * prev_entry = skiplist_search(db->servers, &rs->serveraddr); if(prev_entry != NULL) { log_info("Server address %s:%d already in membership!", hostname, portno); remote_server * prev_rems = (remote_server *) prev_entry->value; if(rs->status == NODE_LIVE && (prev_rems->status == NODE_DEAD || prev_rems->sockfd <= 0)) { // Delete previous entry, reconnect to node and update socket descriptor if we've been disconnected in the mean time: log_info("Reconnecting to server %s:%d", hostname, portno); skiplist_delete(db->servers, &rs->serveraddr); } else { prev_rems->status = rs->status; free_remote_server(rs); return -1; } } free_remote_server(rs); rs = get_remote_server(hostname, portno, dummy_serveraddr, dummy_serveraddr, DUMMY_FD, 1, 0); if((skiplist_insert(db->servers, &rs->serveraddr, rs, seedptr)) != 0) { log_error("ERROR: Error adding server address %s:%d to membership!", hostname, portno); free_remote_server(rs); return -2; } if(rs->status == NODE_DEAD) { log_error("ERROR: Failed joining server %s:%d (it looks down)!", hostname, portno); return 1; } comm_wake_up(db); return 0; } rts_descriptor * get_rts_descriptor(int rack_id, int dc_id, char *hostname, int local_rts_id, int status) { rts_descriptor * rts_d = (rts_descriptor *) malloc(sizeof(struct rts_descriptor)); snprintf((char *) &rts_d->id, 262, "%s/%d", hostname, local_rts_id); rts_d->rack_id = rack_id; rts_d->dc_id = dc_id; rts_d->local_rts_id = local_rts_id; rts_d->status = status; struct hostent * host = gethostbyname(hostname); if (host == NULL) { log_error("ERROR, no such host %s", hostname); free_rts_descriptor(rts_d); return NULL; } bzero((void *) &rts_d->addr, sizeof(struct sockaddr_in)); rts_d->addr.sin_family = AF_INET; bcopy((char *) host->h_addr_list[0], (char *)&(rts_d->addr.sin_addr.s_addr), host->h_length); rts_d->addr.sin_port = htons(local_rts_id); rts_d->hostname = strndup(hostname, strnlen(hostname, 256) + 1); // free(host); return rts_d; } void free_rts_descriptor(WORD rts_d) { free(rts_d); } WORD get_rts_key(WORD rts) { return (WORD) ((rts_descriptor *) rts)->_local_rts_index; } WORD get_rts_live_field(WORD rts) { return (WORD) &(((rts_descriptor *) rts)->status); } int add_rts_to_membership(int rack_id, int dc_id, char *hostname, int local_rts_id, int node_status, skiplist_t * rtss, hash_ring * _rts_ring, unsigned int * seedptr) { rts_descriptor * rts_d = get_rts_descriptor(rack_id, dc_id, hostname, local_rts_id, node_status); snode_t * prev_entry = skiplist_search(rtss, &(rts_d->addr)); if(prev_entry != NULL) { log_debug("RTS address %s:%d already in membership, updating status and metadata!", hostname, local_rts_id); rts_descriptor * prev_descriptor = (rts_descriptor *) prev_entry->value; prev_descriptor->status = rts_d->status; prev_descriptor->rack_id = rts_d->rack_id; prev_descriptor->dc_id = rts_d->dc_id; free_rts_descriptor(rts_d); return -1; } rts_d->_local_rts_index = get_node_id((struct sockaddr *) &(rts_d->addr)); // rtss->no_items; int status = skiplist_insert(rtss, &(rts_d->addr), rts_d, seedptr); if(status != 0) { log_debug("ERROR: Error adding RTS %s:%d to membership!", hostname, local_rts_id); free_rts_descriptor(rts_d); return -2; } // Update RTS consistent hashing ring used for actor placement: status = add_bucket(_rts_ring, (WORD) rts_d, &get_rts_key, &get_rts_live_field, seedptr); assert(status == 0); log_debug("Added RTS %s:%d - %d to membership!", hostname, local_rts_id, rts_d->_local_rts_index); return 0; } char * to_string_rts_membership(remote_db_t * db, char * msg_buff) { char * crt_ptr = msg_buff; sprintf(crt_ptr, "RTS_membership("); crt_ptr += strlen(crt_ptr); for(snode_t * crt = HEAD(db->rtses); crt!=NULL; crt = NEXT(crt)) { rts_descriptor * nd = (rts_descriptor *) crt->value; sprintf(crt_ptr, "RTS(status=%d, rack_id=%d, dc_id=%d, hostname=%s, rts_id=%d, local_index=%d)", nd->status, nd->rack_id, nd->dc_id, (nd->hostname != NULL)?(nd->hostname):"NULL", nd->local_rts_id, nd->_local_rts_index); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", "); crt_ptr += 2; } sprintf(crt_ptr, ")"); return msg_buff; } actor_descriptor * get_actor_descriptor(long actor_id, rts_descriptor * host_rts, int is_local, int status) { actor_descriptor * a = (actor_descriptor *) malloc(sizeof(struct actor_descriptor)); a->actor_id = actor_id; a->host_rts = host_rts; a->is_local = is_local; a->status = status; return a; } void free_actor_descriptor(actor_descriptor * a) { free(a); } skiplist_t * get_rtses_for_actor(long actor_id, remote_db_t * db) { if(db->_rts_ring->live_buckets == 0) return NULL; if(db->actor_replication_factor == 1) { skiplist_t * result = create_skiplist_long(); rts_descriptor * rts_d = (rts_descriptor *) get_buckets_for_object(db->_rts_ring, (int) actor_id, 1, &get_rts_key, &get_rts_live_field, &(db->fastrandstate)); skiplist_insert(result, (WORD) rts_d->_local_rts_index, rts_d, &(db->fastrandstate)); return result; } return get_buckets_for_object(db->_rts_ring, (int) actor_id, db->actor_replication_factor, &get_rts_key, &get_rts_live_field, &(db->fastrandstate)); } rts_descriptor * get_first_rts_for_actor(long actor_id, remote_db_t * db) { if(db->_rts_ring->live_buckets == 0) return NULL; return (rts_descriptor *) get_buckets_for_object(db->_rts_ring, (int) actor_id, 1, &get_rts_key, &get_rts_live_field, &(db->fastrandstate)); } skiplist_t * get_local_actors(remote_db_t * db) { skiplist_t * result = create_skiplist_long(); int status = 0; for(snode_t * crt = HEAD(db->actors); crt!=NULL; crt = NEXT(crt)) { actor_descriptor * a = (actor_descriptor *) crt->value; if(a->is_local) { status = skiplist_insert(result, (WORD) a->actor_id, a, &(db->fastrandstate)); assert(status == 0); } } return result; } skiplist_t * get_remote_actors(remote_db_t * db) { skiplist_t * result = create_skiplist_long(); int status = 0; for(snode_t * crt = HEAD(db->actors); crt!=NULL; crt = NEXT(crt)) { actor_descriptor * a = (actor_descriptor *) crt->value; if(!a->is_local) { status = skiplist_insert(result, (WORD) a->actor_id, a, &(db->fastrandstate)); assert(status == 0); } } return result; } int is_actor_local(long actor_id, remote_db_t * db) { int host_id = -1; if(db->actor_replication_factor == 1) { rts_descriptor * host_rts = get_first_rts_for_actor(actor_id, db); assert(host_rts != NULL); host_id = get_node_id((struct sockaddr *) &(host_rts->addr)); return (host_id == db->local_rts_id); } else { skiplist_t * rtses = get_rtses_for_actor(actor_id, db); for(snode_t * crt = HEAD(rtses); crt!=NULL; crt = NEXT(crt)) { rts_descriptor * rts_d = (rts_descriptor *) crt->value; host_id = get_node_id((struct sockaddr *) &(rts_d->addr)); if(host_id == db->local_rts_id) return 1; } return 0; } } int update_actor_placement(remote_db_t * db) { char msg_buf[4096]; log_debug("CLIENT: Updating actor placement. Previous actor membership: %s", to_string_actor_membership(db, msg_buf)); int host_id = -1; for(snode_t * crt = HEAD(db->actors); crt!=NULL; crt = NEXT(crt)) { actor_descriptor * a = (actor_descriptor *) crt->value; if(db->actor_replication_factor == 1) { rts_descriptor * first_rts = get_first_rts_for_actor(a->actor_id, db); assert(first_rts != NULL); a->host_rts = first_rts; a->is_local = (first_rts->_local_rts_index == db->local_rts_id); } else { skiplist_t * rtses = get_rtses_for_actor(a->actor_id, db); int replica_no = 0; a->is_local = 0; for(snode_t * crt = HEAD(rtses); crt!=NULL; crt = NEXT(crt)) { rts_descriptor * rts_d = (rts_descriptor *) crt->value; host_id = get_node_id((struct sockaddr *) &(rts_d->addr)); if(host_id == db->local_rts_id) a->is_local = 1; if(replica_no == 0) { a->host_rts = rts_d; } replica_no++; } } } log_debug("CLIENT: Actor membership: %s", to_string_actor_membership(db, msg_buf)); return 0; } int add_actor_to_membership(long actor_id, remote_db_t * db) { char msg_buf[4096]; log_debug("Adding actor %ld to membership!", actor_id); actor_descriptor * a = get_actor_descriptor(actor_id, NULL, 1, ACTOR_STATUS_RUNNING); snode_t * prev_entry = skiplist_search(db->actors, (WORD) a->actor_id); if(prev_entry != NULL) { log_debug("Actor %ld was already added to membership, skipping.\n", a->actor_id); return -1; } int status = skiplist_insert(db->actors, (WORD) a->actor_id, a, &(db->fastrandstate)); if(status != 0) { log_debug("ERROR: Error adding actor %ld to membership!\n", a->actor_id); free_actor_descriptor(a); return -2; } a->host_rts = get_first_rts_for_actor(actor_id, db); if(a->host_rts != NULL) { int host_id = get_node_id((struct sockaddr *) &(a->host_rts->addr)); a->is_local = (host_id == db->local_rts_id); } else // RTS node has not installed a gossiped view yet, consider actors local until it does { a->is_local = 1; } log_debug("Added actor %ld to membership!", a->actor_id); log_debug("CLIENT: Actor membership: %s", to_string_actor_membership(db, msg_buf)); return 0; } char * to_string_actor_membership(remote_db_t * db, char * msg_buff) { char * crt_ptr = msg_buff; sprintf(crt_ptr, "actor_membership("); crt_ptr += strlen(crt_ptr); for(snode_t * crt = HEAD(db->actors); crt!=NULL; crt = NEXT(crt)) { actor_descriptor * a = (actor_descriptor *) crt->value; sprintf(crt_ptr, "Actor(actor_id=%ld, rts=%s:%d, rts_index=%d, rack_id=%d, dc_id=%d, status=%d)", a->actor_id, (a->host_rts != NULL && a->host_rts->hostname != NULL)?(a->host_rts->hostname):"local", (a->host_rts != NULL)?a->host_rts->local_rts_id:-1, (a->host_rts != NULL)?a->host_rts->_local_rts_index:-1, (a->host_rts != NULL)?a->host_rts->rack_id:-1, (a->host_rts != NULL)?a->host_rts->dc_id:-1, a->status); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", "); crt_ptr += 2; } sprintf(crt_ptr, ")"); return msg_buff; } msg_callback * add_msg_callback(int64_t nonce, void (*callback)(void *), remote_db_t * db) { pthread_mutex_lock(db->msg_callbacks_lock); snode_t * node = skiplist_search(db->msg_callbacks, (WORD) nonce); assert(node != NULL); assert(node->value == (WORD) 1); msg_callback * mc = get_msg_callback(nonce, NULL, callback, db->replication_factor); skiplist_insert(db->msg_callbacks, (WORD) nonce, mc, &(db->fastrandstate)); snode_t * node2 = skiplist_search(db->msg_callbacks, (WORD) nonce); assert(node2->value == mc); pthread_mutex_unlock(db->msg_callbacks_lock); return mc; } int add_reply_to_nonce(void * reply, short reply_type, int64_t nonce, remote_db_t * db) { int ret = 0; pthread_mutex_lock(db->msg_callbacks_lock); snode_t * node = skiplist_search(db->msg_callbacks, (WORD) nonce); if(node == NULL || node->value == (WORD) 1) { pthread_mutex_unlock(db->msg_callbacks_lock); // log_info("Nonce %" PRId64 " not found!", nonce); return -1; } msg_callback * mc = (msg_callback *) node->value; int no_replies = add_reply_to_msg_callback(reply, reply_type, mc); if(no_replies < 0) { pthread_mutex_unlock(db->msg_callbacks_lock); return no_replies; } // Signal consumer if a quorum of replies have arrived: if(no_replies >= db->quorum_size) { ret = pthread_mutex_lock(mc->lock); pthread_cond_signal(mc->signal); if((mc->callback) != NULL) { // log_debug("mc = %p, mc->callback = %p, calling..", mc, mc->callback); (mc->callback)(NULL); } ret = pthread_mutex_unlock(mc->lock); } pthread_mutex_unlock(db->msg_callbacks_lock); return no_replies; } int delete_msg_callback(int64_t nonce, remote_db_t * db) { pthread_mutex_lock(db->msg_callbacks_lock); snode_t * node = skiplist_search(db->msg_callbacks, (WORD) nonce); if(node == NULL) { pthread_mutex_unlock(db->msg_callbacks_lock); return 1; } msg_callback * mc = (msg_callback *) node->value; skiplist_delete(db->msg_callbacks, (WORD) nonce); free_msg_callback(mc); pthread_mutex_unlock(db->msg_callbacks_lock); return 0; } int64_t _get_nonce(remote_db_t * db) { #ifdef RANDOM_NONCES unsigned int randno1, randno2; int64_t randlong; FASTRAND(&(db->fastrandstate), randno1); FASTRAND(&(db->fastrandstate), randno2); return ((int64_t) randno1 << 32) | ((int64_t) randno2 & 0xFFFFFFFFL); #else return ++requests; #endif } int64_t get_nonce(remote_db_t * db) { int64_t nonce = -1; snode_t * node = (snode_t *) 1; while(node != NULL) { nonce = _get_nonce(db); pthread_mutex_lock(db->msg_callbacks_lock); node = skiplist_search(db->msg_callbacks, (WORD) nonce); if(node == NULL) { skiplist_insert(db->msg_callbacks, (WORD) nonce, (WORD) 1, &(db->fastrandstate)); } pthread_mutex_unlock(db->msg_callbacks_lock); } return nonce; } vector_clock * get_and_increment_lc(remote_db_t * db, int node_id) { pthread_mutex_lock(db->lc_lock); vector_clock * vc = copy_vc(db->my_lc); increment_vc(db->my_lc, node_id); pthread_mutex_unlock(db->lc_lock); return vc; } vector_clock * get_lc(remote_db_t * db) { return copy_vc(db->my_lc); } int update_lc_protected(remote_db_t * db, vector_clock * vc_in) { pthread_mutex_lock(db->lc_lock); int ret = update_vc(db->my_lc, vc_in); pthread_mutex_unlock(db->lc_lock); return ret; } int close_remote_db(remote_db_t * db) { db->stop_comm = 1; #ifdef ACTON_THREADS pthread_join(db->comm_thread, NULL); #endif for(snode_t * crt = HEAD(db->servers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; close(rs->sockfd); } return free_remote_db(db); } int free_remote_db(remote_db_t * db) { skiplist_free_val(db->servers, &free_remote_server_ptr); skiplist_free(db->txn_state); skiplist_free(db->queue_subscriptions); skiplist_free(db->group_queue_subscriptions); free_hash_ring(db->_rts_ring, NULL); skiplist_free_val(db->rtses, &free_rts_descriptor); skiplist_free(db->actors); free(db); free_vc(db->my_lc); return 0; } // Comm fctns: /* * error - wrapper for perror */ void error(char *msg) { perror(msg); } int send_packet(void * buf, unsigned len, int sockfd) { assert(sockfd != 0); int n = write(sockfd, buf, len); if (n < 0) { error("ERROR writing to socket"); } else { #if CLIENT_VERBOSITY > 2 log_info("Wrote %d bytes to socket", n); #endif } return 0; } int send_packet_wait_reply(void * out_buf, unsigned out_len, int sockfd, void * in_buf, unsigned in_buf_size, int * in_len) { int ret = send_packet(out_buf, out_len, sockfd); if(ret != 0) return ret; bzero(in_buf, in_buf_size); *in_len = -1; while(*in_len < 0) { *in_len = read(sockfd, in_buf, BUFSIZE); if (*in_len < 0) error("ERROR reading from socket"); else { #if CLIENT_VERBOSITY > 2 log_info("Read %d bytes from socket", *in_len); #endif } } return 0; } int wait_on_msg_callback(msg_callback * mc, remote_db_t * db) { if(mc == NULL) { assert(0); return NO_SUCH_MSG_CALLBACK; } // Wait for signal from comm thread. It will come when 'db->quorum_size' replies have arrived on that nonce: int ret = pthread_mutex_lock(mc->lock); if(mc->no_replies >= db->quorum_size) // Enough replies arrived already { pthread_mutex_unlock(mc->lock); return 0; } struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += db->rpc_timeout; ret = pthread_cond_timedwait(mc->signal, mc->lock, &ts); pthread_mutex_unlock(mc->lock); if(ret != 0 && ret != ETIMEDOUT) { log_info("pthread_cond_timedwait returned %d/%d", ret, errno); assert(0); } return 0; } int send_packet_wait_replies_async(void * out_buf, unsigned out_len, int64_t nonce, msg_callback ** mc, remote_db_t * db) { int ret = 0; *mc = add_msg_callback(nonce, NULL, db); assert (*mc != NULL); assert (*mc != (WORD) 1); for(snode_t * server_node = HEAD(db->servers); server_node!=NULL; server_node=NEXT(server_node)) { remote_server * rs = (remote_server *) server_node->value; if (rs->status != NODE_LIVE || rs->sockfd <= 0) continue; #if SYNC_SOCKET > 0 pthread_mutex_lock(rs->sockfd_lock); #endif ret = send_packet(out_buf, out_len, rs->sockfd); #if SYNC_SOCKET > 0 pthread_mutex_unlock(rs->sockfd_lock); #endif if(ret != 0) { assert(0); #if CLIENT_VERBOSITY > 0 log_error("Server %s seems down.", rs->id); #endif } } return 0; } int send_packet_wait_replies_sync(void * out_buf, unsigned out_len, int64_t nonce, msg_callback ** mc, remote_db_t * db) { int ret = send_packet_wait_replies_async(out_buf, out_len, nonce, mc, db); if(ret != 0) return ret; // Wait for signal from comm thread. It will come when 'db->quorum_size' replies have arrived on that nonce: return wait_on_msg_callback(*mc, db); } // Write ops: int remote_insert_in_txn(WORD * column_values, int no_cols, int no_primary_keys, int no_clustering_keys, WORD blob, size_t blob_size, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_insert_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *minority_status = 0; #if (DEBUG_BLOBS > 0) size_t print_size = 256 + no_cols * sizeof(long) + blob_size; char * printbuf = (char *) malloc(print_size); char * crt_ptr = printbuf; sprintf(crt_ptr, "cols={"); crt_ptr += strlen(crt_ptr); for(int i=0;i 0) { for(int i=0;iservers->no_items < db->quorum_size) { log_error("Not enough servers configured for quorum (%d/%d servers configured)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_insert_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_write_query(wq, (char *) print_buff); log_info("Sending write query to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, wq->nonce, &mc, db); assert(success == 0); free_write_query(wq); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_insert_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } int ok_status = 0; for(int i=0;ino_replies;i++) { ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0) ok_status++; else *minority_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_insert_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_insert_in_txn, &ts_start, 0); return 0; } int remote_update_in_txn(int * col_idxs, int no_cols, WORD * column_values, WORD blob, size_t blob_size, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db) { assert (0); // Not supported return 0; } int remote_delete_row_in_txn(WORD * column_values, int no_primary_keys, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_delete_row_in_txn, &ts_start); *minority_status = 0; unsigned len = 0; write_query * wq = build_delete_row_in_txn(column_values, no_primary_keys, table_key, txnid, get_nonce(db)); void * tmp_out_buf = NULL; int success = serialize_write_query(wq, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_delete_row_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_write_query(wq, (char *) print_buff); log_info("Sending delete row query to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, wq->nonce, &mc, db); assert(success == 0); free_write_query(wq); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_delete_row_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } int ok_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0) ok_status++; else *minority_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_delete_row_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_delete_row_in_txn, &ts_start, 0); return 0; } int remote_delete_cell_in_txn(WORD * column_values, int no_primary_keys, int no_clustering_keys, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_delete_cell_in_txn, &ts_start); *minority_status = 0; unsigned len = 0; write_query * wq = build_delete_cell_in_txn(column_values, no_primary_keys, no_clustering_keys, table_key, txnid, get_nonce(db)); void * tmp_out_buf = NULL; int success = serialize_write_query(wq, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_delete_cell_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_write_query(wq, (char *) print_buff); log_info("Sending delete cell query to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, wq->nonce, &mc, db); assert(success == 0); free_write_query(wq); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_delete_cell_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } int ok_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0) ok_status++; else *minority_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_delete_cell_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_delete_cell_in_txn, &ts_start, 0); return 0; } int remote_delete_by_index_in_txn(WORD index_key, int idx_idx, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db) { assert (0); // Not supported return 0; } // Read ops: int get_db_rows_forest_from_read_response(range_read_response_message * response, snode_t** start_row, snode_t** end_row, remote_db_t * db) // If a DB query returned multiple cells, accumulate them all in a forest of trees rooted at // elements of the returned list start_row->end_row. Return the number of roots found. For forests with a single root // (which e.g. results from non-range queries will be), a list with a single element (located at start_row==end_row) will be returned: { if(response->no_cells == 0) // No results { *start_row = NULL; *end_row = NULL; return 0; } skiplist_t * roots = create_skiplist_long(); db_row_t* result = create_db_row_schemaless2((WORD *) response->cells[0].keys, response->cells[0].no_keys, (WORD *) response->cells[0].columns, response->cells[0].no_columns, response->cells[0].last_blob, response->cells[0].last_blob_size, &(db->fastrandstate)); for(int i=0;ino_cells;i++) // We have a deeper result than 1 { db_row_t* root_cell = NULL; snode_t * root_cell_node = skiplist_search(roots, (WORD) response->cells[i].keys[0]); if(root_cell_node == NULL) { // log_info("Creating new root cell for cell %d (%" PRId64 ")", i, response->cells[i].keys[0]); root_cell = create_db_row_schemaless2((WORD *) response->cells[i].keys, response->cells[i].no_keys, (WORD *) response->cells[i].columns, response->cells[i].no_columns, response->cells[i].last_blob, response->cells[i].last_blob_size, &(db->fastrandstate)); skiplist_insert(roots, (WORD) response->cells[i].keys[0], (WORD) root_cell, &(db->fastrandstate)); continue; } else { root_cell = (db_row_t *) (root_cell_node->value); } db_row_t * cell = root_cell, * new_cell = NULL; for(int j=1;jcells[i].no_keys;j++, cell = new_cell) { snode_t * new_cell_node = skiplist_search(cell->cells, (WORD) response->cells[i].keys[j]); if(new_cell_node == NULL) { new_cell = create_db_row_schemaless2((WORD *) response->cells[i].keys + j, response->cells[i].no_keys - j, (WORD *) response->cells[i].columns, response->cells[i].no_columns, response->cells[i].last_blob, response->cells[i].last_blob_size, &(db->fastrandstate)); // log_info("Inserting cell %d (%" PRId64 ") into tree at level %d", i, response->cells[i].keys[j], j); skiplist_insert(cell->cells, (WORD) response->cells[i].keys[j], (WORD) new_cell, &(db->fastrandstate)); break; } else { new_cell = (db_row_t *) (new_cell_node->value); assert(j < response->cells[i].no_keys - 1); // there s'dn't be 2 cells returned with the exact same keypath } } } int no_roots = 1; *start_row = HEAD(roots); for(*end_row=*start_row;NEXT(*end_row) != NULL;*end_row=NEXT(*end_row), no_roots++); assert(roots->no_items == no_roots); // assert(roots->no_items == *end_row - *start_row + 1); return roots->no_items; } db_row_t* get_db_rows_tree_from_read_response(range_read_response_message * response, remote_db_t * db) // If a DB query returned multiple cells, accumulate them all in a single tree rooted at "result" // (assumes this is a non-range query, i.e. all cells will have a common parent on the key path): { if(response->no_cells == 0) // No results return NULL; db_row_t* result = create_db_row_schemaless2((WORD *) response->cells[0].keys, response->cells[0].no_keys, (WORD *) response->cells[0].columns, response->cells[0].no_columns, response->cells[0].last_blob, response->cells[0].last_blob_size, &(db->fastrandstate)); for(int i=1;ino_cells;i++) // We have a deeper result than 1 { db_row_t * cell = result, * new_cell = NULL; assert(response->cells[i].keys[0] == (int64_t) result->key); for(int j=1;jcells[i].no_keys;j++, cell = new_cell) { snode_t * new_cell_node = skiplist_search(cell->cells, (WORD) response->cells[i].keys[j]); if(new_cell_node == NULL) { new_cell = create_db_row_schemaless2((WORD *) response->cells[i].keys + j, response->cells[i].no_keys - j, (WORD *) response->cells[i].columns, response->cells[i].no_columns, response->cells[i].last_blob, response->cells[i].last_blob_size, &(db->fastrandstate)); // log_info("Inserting cell %d (%" PRId64 ") into tree at level %d", i, response->cells[i].keys[j], j); skiplist_insert(cell->cells, (WORD) response->cells[i].keys[j], (WORD) new_cell, &(db->fastrandstate)); break; } else { new_cell = (db_row_t *) (new_cell_node->value); assert(j < response->cells[i].no_keys - 1); // there s'dn't be 2 cells returned with the exact same keypath } } } // print_long_row(result); return result; } int remote_search_in_txn(WORD* primary_keys, int no_primary_keys, db_row_t** result_row, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_search_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *result_row = NULL; *minority_status = 0; read_query * q = build_search_in_txn(primary_keys, no_primary_keys, table_key, txnid, get_nonce(db)); int success = serialize_read_query(q, (void **) &tmp_out_buf, &len, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_search_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_read_query(q, (char *) print_buff); log_info("Sending read row query to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_read_query(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_search_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } range_read_response_message * response = NULL; int ok_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_RANGE_READ_RESPONSE); range_read_response_message * candidate_response = (range_read_response_message *) mc->replies[i]; #if CLIENT_VERBOSITY > 0 to_string_range_read_response_message(candidate_response, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif if(candidate_response->no_cells >= 0) { ok_status++; if(response == NULL) response = candidate_response; } else { *minority_status = candidate_response->no_cells; } } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_search_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } // If result returned multiple cells, accumulate them all in a single tree rooted at "result": *result_row = get_db_rows_tree_from_read_response(response, db); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_search_in_txn, &ts_start, 0); return 0; } int remote_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, db_row_t** result_row, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_search_clustering_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *result_row = NULL; *minority_status = 0; read_query * q = build_search_clustering_in_txn(primary_keys, no_primary_keys, clustering_keys, no_clustering_keys, table_key, txnid, get_nonce(db)); int success = serialize_read_query(q, (void **) &tmp_out_buf, &len, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_search_clustering_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_read_query(q, (char *) print_buff); log_info("Sending read cell query to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_read_query(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_search_clustering_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } range_read_response_message * response = NULL; int ok_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_RANGE_READ_RESPONSE); range_read_response_message * candidate_response = (range_read_response_message *) mc->replies[i]; #if CLIENT_VERBOSITY > 0 to_string_range_read_response_message(candidate_response, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif if(candidate_response->no_cells >= 0) { ok_status++; if(response == NULL) response = candidate_response; } else { *minority_status = candidate_response->no_cells; } } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_search_clustering_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } // If result returned multiple cells, accumulate them all in a single tree rooted at "result": *result_row = get_db_rows_tree_from_read_response(response, db); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_search_clustering_in_txn, &ts_start, 0); return 0; } int remote_search_columns_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD* col_keys, int no_columns, db_row_t** result_row, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db) { assert (0); // Not supported return 0; } int remote_search_index_in_txn(WORD index_key, int idx_idx, db_row_t** result_row, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db) { assert (0); // Not supported; TO DO return 0; } int remote_range_search_in_txn(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, snode_t** start_row, snode_t** end_row, WORD table_key, int * no_items, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_range_search_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *no_items = 0; *minority_status = 0; range_read_query * q = build_range_search_in_txn(start_primary_keys, end_primary_keys, no_primary_keys, table_key, txnid, get_nonce(db)); int success = serialize_range_read_query(q, (void **) &tmp_out_buf, &len, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_range_search_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_range_read_query(q, (char *) print_buff); log_info("Sending range read row query to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_range_read_query(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_range_search_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } range_read_response_message * response; int ok_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_RANGE_READ_RESPONSE); range_read_response_message * candidate_response = (range_read_response_message *) mc->replies[i]; #if CLIENT_VERBOSITY > 0 to_string_range_read_response_message(candidate_response, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif if(candidate_response->no_cells >= 0) { ok_status++; if(response == NULL) response = candidate_response; } else { *minority_status = candidate_response->no_cells; } } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_range_search_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } // If result returned multiple cells, accumulate them all in a forest of db_rows rooted at elements of list start_row->end_row: *no_items = get_db_rows_forest_from_read_response(response, start_row, end_row, db); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_range_search_in_txn, &ts_start, 0); return 0; } int remote_range_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, snode_t** start_row, snode_t** end_row, WORD table_key, int * no_items, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_range_search_clustering_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *no_items = 0; *minority_status = 0; range_read_query * q = build_range_search_clustering_in_txn(primary_keys, no_primary_keys, start_clustering_keys, end_clustering_keys, no_clustering_keys, table_key, txnid, get_nonce(db)); int success = serialize_range_read_query(q, (void **) &tmp_out_buf, &len, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_range_search_clustering_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_range_read_query(q, (char *) print_buff); log_info("Sending range read cell query to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_range_read_query(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_range_search_clustering_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } range_read_response_message * response = NULL; int ok_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_RANGE_READ_RESPONSE); range_read_response_message * candidate_response = (range_read_response_message *) mc->replies[i]; #if CLIENT_VERBOSITY > 0 to_string_range_read_response_message(candidate_response, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif if(candidate_response->no_cells >= 0) { ok_status++; if(response == NULL) response = candidate_response; } else { *minority_status = candidate_response->no_cells; } } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_range_search_clustering_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } // If result returned multiple cells, accumulate them all in a forest of db_rows rooted at elements of list start_row->end_row: *no_items = get_db_rows_forest_from_read_response(response, start_row, end_row, db); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_range_search_clustering_in_txn, &ts_start, 0); return 0; } int remote_range_search_index_in_txn(int idx_idx, WORD start_idx_key, WORD end_idx_key, snode_t** start_row, snode_t** end_row, WORD table_key, int * no_items, int * minority_status, uuid_t * txnid, remote_db_t * db) { assert (0); // Not supported; TO DO return 0; } int remote_read_full_table_in_txn(snode_t** start_row, snode_t** end_row, WORD table_key, int * no_items, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_read_full_table_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *no_items = 0; *minority_status = 0; range_read_query * q = build_wildcard_range_search_in_txn(table_key, txnid, get_nonce(db)); int success = serialize_range_read_query(q, (void **) &tmp_out_buf, &len, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_read_full_table_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_range_read_query(q, (char *) print_buff); log_info("Sending full table read query to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_range_read_query(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_read_full_table_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } range_read_response_message * response = NULL; int ok_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_RANGE_READ_RESPONSE); range_read_response_message * candidate_response = (range_read_response_message *) mc->replies[i]; #if CLIENT_VERBOSITY > 2 to_string_range_read_response_message(candidate_response, (char *) print_buff); log_info("Got back response from server: %s", print_buff); #endif if(candidate_response->no_cells >= 0) { ok_status++; if(response == NULL) response = candidate_response; } else { *minority_status = candidate_response->no_cells; } } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_read_full_table_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } // If result returned multiple cells, accumulate them all in a forest of db_rows rooted at elements of list start_row->end_row: *no_items = get_db_rows_forest_from_read_response(response, start_row, end_row, db); delete_msg_callback(mc->nonce, db); #if DEBUG_BLOBS > 0 log_info("remote_read_full_table_in_txn: Returning %" PRId64 " [%d rows]:", (int64_t) table_key, result); for(snode_t * node = *start_row; node!=NULL; node=NEXT(node)) print_long_row((db_row_t*) node->value); #endif stat_stop(dbc_stats.remote_read_full_table_in_txn, &ts_start, 0); return 0; } void remote_print_long_table(WORD table_key, remote_db_t * db) { snode_t* start_row = NULL, * end_row = NULL; int no_items = 0, minority_status = 0; int ret = remote_read_full_table_in_txn(&start_row, &end_row, table_key, &no_items, &minority_status, NULL, db); log_info("DB_TABLE: %" PRId64 " [%d rows]", (int64_t) table_key, no_items); if(ret == 0 && no_items > 0) { for(snode_t * node = start_row; node!=NULL; node=NEXT(node)) print_long_row((db_row_t*) node->value); } } // Queue ops: /* * * Note on status returns of queue operations: * * If there is a quorum of valid replies from servers, we return the appropriate non-err status. * In the case of a queue read for instance, this is QUEUE_STATUS_READ_INCOMPLETE or QUEUE_STATUS_READ_COMPLETE. * In addition, if there also were non-valid replies received (and there was still a quorum), * we also set the err status of the minority error response in the 'minority_status' variable to advise * the client that some schemas on a minority of nodes might need repairs. * If there is no quorum of *valid* replies, but there was a quorum of received replies * (e.g. we received schema mismatch errors), we return NO_QUORUM_ERR and set the minority status * with the received error status. * If there was no quorum of replies at all (not enough servers responded), we return NO_QUORUM_ERR and fill * in no minority_status (the client will not be able to recreate schemas anyway until there is a quorum). * As a result, in all cases when the client receives NO_QUORUM_ERR, he has to retry the operation. * In addition, if minority_status is set to a schema mismatch flavor of error, he can attempt schema correction after this, * whether or not he also needs to re-try the operation (if the operation succeeded, this will still help to install correct schemas on * the minority nodes). * */ int remote_create_queue_in_txn(WORD table_key, WORD queue_id, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_create_queue_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *minority_status = 0; queue_query_message * q = build_create_queue_in_txn(table_key, queue_id, txnid, get_nonce(db)); int success = serialize_queue_message(q, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_create_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_queue_message(q, (char *) print_buff); log_info("Sending queue message to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_queue_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_create_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } int ok_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0 || ack->status == DB_ERR_DUPLICATE_QUEUE) ok_status++; else *minority_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_create_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_create_queue_in_txn, &ts_start, 0); return 0; } int remote_delete_queue_in_txn(WORD table_key, WORD queue_id, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_delete_queue_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *minority_status = 0; queue_query_message * q = build_delete_queue_in_txn(table_key, queue_id, txnid, get_nonce(db)); int success = serialize_queue_message(q, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_delete_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_queue_message(q, (char *) print_buff); log_info("Sending queue message to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_queue_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_delete_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } int ok_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0) ok_status++; else *minority_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_delete_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_delete_queue_in_txn, &ts_start, 0); return 0; } int remote_enqueue_in_txn(WORD * column_values, int no_cols, WORD blob, size_t blob_size, WORD table_key, WORD queue_id, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_enqueue_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *minority_status = 0; queue_query_message * q = build_enqueue_in_txn(column_values, no_cols, blob, blob_size, table_key, queue_id, txnid, get_nonce(db)); int success = serialize_queue_message(q, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_enqueue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_queue_message(q, (char *) print_buff); log_info("Sending queue message to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_queue_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_enqueue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } int ok_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0) ok_status++; else *minority_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_enqueue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_enqueue_in_txn, &ts_start, 0); return 0; } int remote_read_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int max_entries, int * entries_read, int64_t * new_read_head, snode_t** start_row, snode_t** end_row, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_read_queue_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *minority_status = 0; queue_query_message * q = build_read_queue_in_txn(consumer_id, shard_id, app_id, table_key, queue_id, max_entries, txnid, get_nonce(db)); int success = serialize_queue_message(q, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_read_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_queue_message(q, (char *) print_buff); log_info("Sending queue message to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_queue_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_read_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } queue_query_message * candidate_response = NULL, * response = NULL; int valid_responses = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_QUEUE); candidate_response = (queue_query_message *) mc->replies[i]; assert(candidate_response->msg_type == QUERY_TYPE_READ_QUEUE_RESPONSE); #if CLIENT_VERBOSITY > 0 to_string_queue_message(candidate_response, (char *) print_buff); log_info("Got back response: %s", print_buff); #endif if(candidate_response->status < 0) { *minority_status = candidate_response->status; } else { // To determine whether the read was complete or incomplete, we use the status from the server reply // with the highest queue_index (since it will contain the latest persisted enqueues): if(response == NULL || candidate_response->queue_index > response->queue_index) response = candidate_response; valid_responses++; } } if(valid_responses < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", valid_responses, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_read_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } // Parse queue read response message to row list: skiplist_t * rows = create_skiplist_long(); for(int i=0;ino_cells;i++) { db_row_t * row = create_db_row_schemaless2((WORD *) response->cells[i].keys, response->cells[i].no_keys, (WORD *) response->cells[i].columns, response->cells[i].no_columns, response->cells[i].last_blob, response->cells[i].last_blob_size, &(db->fastrandstate)); // Note that cell versions are only kept on the server, we don't return them to the client skiplist_insert(rows, (WORD) response->cells[i].keys[0], (WORD) row, &(db->fastrandstate)); } *start_row = HEAD(rows); if((*start_row) != NULL) { for(*end_row = *start_row;NEXT(*end_row) != NULL;*end_row = NEXT(*end_row)); } *entries_read = response->no_cells; *new_read_head = response->queue_index; delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_read_queue_in_txn, &ts_start, 0); return response->status; } int remote_consume_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, int * minority_status, uuid_t * txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_consume_queue_in_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; *minority_status = 0; queue_query_message * q = build_consume_queue_in_txn(consumer_id, shard_id, app_id, table_key, queue_id, new_consume_head, txnid, get_nonce(db)); int success = serialize_queue_message(q, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_consume_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_queue_message(q, (char *) print_buff); log_info("Sending queue message to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_queue_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_consume_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } int ok_status = 0; for(int i=0;ino_replies;i++) { if(mc->reply_types[i] != RPC_TYPE_ACK) { log_error("Received unexpected reply type: %d", mc->reply_types[i]); assert(0); } ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0) ok_status++; else *minority_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_consume_queue_in_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_consume_queue_in_txn, &ts_start, 0); return 0; } int _remote_subscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, WORD group_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, int * minority_status, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_subscribe_queue, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; queue_query_message * q = NULL; if((int) group_id == -1) { q = build_subscribe_queue_in_txn(consumer_id, shard_id, app_id, table_key, queue_id, NULL, get_nonce(db)); // txnid } else { q = build_subscribe_group_in_txn(consumer_id, shard_id, app_id, group_id, NULL, get_nonce(db)); } *minority_status = 0; int success = serialize_queue_message(q, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_queue_message(q, (char *) print_buff); log_info("Sending queue message to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_queue_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } int ok_status = 0, subscription_exists = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0 || ack->status == DB_ERR_DUPLICATE_CONSUMER) { ok_status++; if(ack->status == DB_ERR_DUPLICATE_CONSUMER) subscription_exists = 1; } else { *minority_status = ack->status; } #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } delete_msg_callback(mc->nonce, db); // Add local subscription on client: int local_ret = -1; if((int) group_id == -1) { local_ret = subscribe_queue_client(consumer_id, shard_id, app_id, table_key, queue_id, callback, 1, db); } else { local_ret = subscribe_to_group(consumer_id, shard_id, app_id, group_id, callback, 1, db); } stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, 0); return (subscription_exists || local_ret == CLIENT_ERR_SUBSCRIPTION_EXISTS)?CLIENT_ERR_SUBSCRIPTION_EXISTS:0; } int _remote_unsubscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, WORD group_id, int * minority_status, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_unsubscribe_queue, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; queue_query_message * q = NULL; if((int) group_id == -1) { q = build_unsubscribe_queue_in_txn(consumer_id, shard_id, app_id, table_key, queue_id, NULL, get_nonce(db)); // txnid } else { q = build_unsubscribe_group_in_txn(consumer_id, shard_id, app_id, group_id, NULL, get_nonce(db)); } *minority_status = 0; int success = serialize_queue_message(q, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_unsubscribe_queue, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_queue_message(q, (char *) print_buff); log_info("Sending queue message to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_queue_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_unsubscribe_queue, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } int ok_status = 0, subscription_missing = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0 || ack->status == DB_ERR_NO_CONSUMER) { ok_status++; if(ack->status == DB_ERR_NO_CONSUMER) subscription_missing = 1; } else { *minority_status = ack->status; } #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received, minority_status=%d)", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_unsubscribe_queue, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } delete_msg_callback(mc->nonce, db); // Remove local subscription from client: int status = -1; if((int) group_id == -1) { status = unsubscribe_queue_client(consumer_id, shard_id, app_id, table_key, queue_id, 1, db); } else { status = unsubscribe_from_group(consumer_id, shard_id, app_id, group_id, 1, db); } int local_ret = unsubscribe_queue_client(consumer_id, shard_id, app_id, table_key, queue_id, 1, db); stat_stop(dbc_stats.remote_unsubscribe_queue, &ts_start, 0); return (subscription_missing || local_ret == CLIENT_ERR_NO_SUBSCRIPTION_EXISTS)?CLIENT_ERR_NO_SUBSCRIPTION_EXISTS:0; } int remote_subscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, int * minority_status, uuid_t * txnid, remote_db_t * db) { assert (0); // Not supported return 0; } int remote_unsubscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int * minority_status, uuid_t * txnid, remote_db_t * db) { assert (0); // Not supported return 0; } int remote_subscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, int * minority_status, remote_db_t * db) { return _remote_subscribe_queue(consumer_id, shard_id, app_id, table_key, queue_id, (WORD) -1, callback, prev_read_head, prev_consume_head, minority_status, db); } int remote_unsubscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int * minority_status, remote_db_t * db) { return _remote_unsubscribe_queue(consumer_id, shard_id, app_id, table_key, queue_id, (WORD) -1, minority_status, db); } int remote_subscribe_group(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, queue_callback * callback, int * minority_status, remote_db_t * db) { log_debug("remote_subscribe_group(consumer_id = %d, group_id = %d)", (int) consumer_id, (int) group_id); return _remote_subscribe_queue(consumer_id, shard_id, app_id, (WORD) -1, (WORD) -1, group_id, callback, NULL, NULL, minority_status, db); } int remote_unsubscribe_group(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, int * minority_status, remote_db_t * db) { return _remote_unsubscribe_queue(consumer_id, shard_id, app_id, (WORD) -1, (WORD) -1, group_id, minority_status, db); } int remote_add_queue_to_group(WORD table_key, WORD queue_id, WORD group_id, short use_lock, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_subscribe_queue, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; queue_query_message * q = build_add_queue_to_group_in_txn(table_key, queue_id, group_id, NULL, get_nonce(db)); int success = serialize_queue_message(q, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_queue_message(q, (char *) print_buff); log_debug("Sending queue message to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_queue_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == CLIENT_ERR_SUBSCRIPTION_EXISTS) { delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, SUBSCRIPTION_EXISTS); // TODO: align return value to use client API codes rather than server API? return CLIENT_ERR_SUBSCRIPTION_EXISTS; } #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_debug("Got back response from server %s: %s", rs->id, print_buff); #endif } delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, 0); return 0; } int remote_remove_queue_from_group(WORD table_key, WORD queue_id, WORD group_id, short use_lock, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_subscribe_queue, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; queue_query_message * q = build_remove_queue_from_group_in_txn(table_key, queue_id, group_id, NULL, get_nonce(db)); int success = serialize_queue_message(q, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_queue_message(q, (char *) print_buff); log_debug("Sending queue message to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_queue_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == CLIENT_ERR_SUBSCRIPTION_EXISTS) { delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, SUBSCRIPTION_EXISTS); // TODO: align return value to use client API codes rather than server API? return CLIENT_ERR_SUBSCRIPTION_EXISTS; } #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_debug("Got back response from server %s: %s", rs->id, print_buff); #endif } delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_subscribe_queue, &ts_start, 0); return 0; } // Subscription handling client-side: queue_callback * get_queue_client_callback(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, WORD table_key, WORD queue_id, short use_lock, remote_db_t * db) { queue_callback_args * qca = get_queue_callback_args(table_key, queue_id, app_id, shard_id, consumer_id, group_id, QUEUE_NOTIF_ENQUEUED); if(use_lock) pthread_mutex_lock(db->subscribe_lock); snode_t * subscription_node = NULL; if((int) group_id != -1) { subscription_node = skiplist_search(db->group_queue_subscriptions, (WORD) qca); } else { subscription_node = skiplist_search(db->queue_subscriptions, (WORD) qca); } if(use_lock) pthread_mutex_unlock(db->subscribe_lock); return (subscription_node != NULL)? ((queue_callback *) (subscription_node->value)):NULL; } int subscribe_queue_client(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, short use_lock, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.subscribe_queue_client, &ts_start); queue_callback_args * qca = get_queue_callback_args(table_key, queue_id, app_id, shard_id, consumer_id, (WORD) -1, QUEUE_NOTIF_ENQUEUED); if(use_lock) pthread_mutex_lock(db->subscribe_lock); snode_t * subscription_node = skiplist_search(db->queue_subscriptions, (WORD) qca); if(subscription_node != NULL) { if(use_lock) pthread_mutex_unlock(db->subscribe_lock); stat_stop(dbc_stats.subscribe_queue_client, &ts_start, SUBSCRIPTION_EXISTS); return CLIENT_ERR_SUBSCRIPTION_EXISTS; // Subscription already exists } int status = skiplist_insert(db->queue_subscriptions, (WORD) qca, (WORD) callback, &(db->fastrandstate)); if(use_lock) pthread_mutex_unlock(db->subscribe_lock); assert(status == 0); #if (VERBOSITY > 0) log_info("CLIENT: Subscriber %" PRId64 "/%" PRId64 "/%" PRId64 " subscribed queue %" PRId64 "/%" PRId64 " with callback %p", (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, (int64_t) table_key, (int64_t) queue_id, cs->callback); #endif stat_stop(dbc_stats.subscribe_queue_client, &ts_start, 0); return status; } int unsubscribe_queue_client(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, short use_lock, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.unsubscribe_queue_client, &ts_start); queue_callback_args * qca = get_queue_callback_args(table_key, queue_id, app_id, shard_id, consumer_id, (WORD) -1, QUEUE_NOTIF_ENQUEUED); if(use_lock) pthread_mutex_lock(db->subscribe_lock); queue_callback * callback = skiplist_delete(db->queue_subscriptions, (WORD) qca); if(use_lock) pthread_mutex_unlock(db->subscribe_lock); assert(callback != NULL); free_queue_callback(callback); #if (VERBOSITY > 0) log_info("CLIENT: Subscriber %" PRId64 "/%" PRId64 "/%" PRId64 " unsubscribed queue %" PRId64 "/%" PRId64 " with callback %p", (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, (int64_t) table_key, (int64_t) queue_id, cs->callback); #endif stat_stop(dbc_stats.unsubscribe_queue_client, &ts_start, 0); return (callback != NULL)?0:CLIENT_ERR_NO_SUBSCRIPTION_EXISTS; } int subscribe_to_group(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, queue_callback * callback, short use_lock, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.subscribe_queue_client, &ts_start); queue_callback_args * qca = get_queue_callback_args((WORD) -1, (WORD) -1, app_id, shard_id, consumer_id, group_id, GROUP_NOTIF_ENQUEUED); if(use_lock) pthread_mutex_lock(db->subscribe_lock); snode_t * subscription_node = skiplist_search(db->group_queue_subscriptions, (WORD) qca); if(subscription_node != NULL) { if(use_lock) pthread_mutex_unlock(db->subscribe_lock); stat_stop(dbc_stats.subscribe_queue_client, &ts_start, SUBSCRIPTION_EXISTS); return CLIENT_ERR_SUBSCRIPTION_EXISTS; // Subscription already exists } int status = skiplist_insert(db->group_queue_subscriptions, (WORD) qca, (WORD) callback, &(db->fastrandstate)); if(use_lock) pthread_mutex_unlock(db->subscribe_lock); assert(status == 0); #if (VERBOSITY > 0) log_debug("CLIENT: Subscriber %" PRId64 "/%" PRId64 "/%" PRId64 " subscribed group %" PRId64 " with callback %p", (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, (int64_t) group_id, cs->callback); #endif stat_stop(dbc_stats.subscribe_queue_client, &ts_start, 0); return status; } int unsubscribe_from_group(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, short use_lock, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.unsubscribe_queue_client, &ts_start); queue_callback_args * qca = get_queue_callback_args((WORD) -1, (WORD) -1, app_id, shard_id, consumer_id, group_id, QUEUE_NOTIF_ENQUEUED); if(use_lock) pthread_mutex_lock(db->subscribe_lock); queue_callback * callback = skiplist_delete(db->group_queue_subscriptions, (WORD) qca); if(use_lock) pthread_mutex_unlock(db->subscribe_lock); assert(callback != NULL); free_queue_callback(callback); #if (VERBOSITY > 0) log_info("CLIENT: Subscriber %" PRId64 "/%" PRId64 "/%" PRId64 " unsubscribed group %" PRId64 " with callback %p", (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, (int64_t) group_id, cs->callback); #endif stat_stop(dbc_stats.unsubscribe_queue_client, &ts_start, 0); return (callback != NULL)?0:CLIENT_ERR_NO_SUBSCRIPTION_EXISTS; } // Txn mgmt: uuid_t * remote_new_txn(remote_db_t * db) { uuid_t * txnid = NULL; unsigned len = 0; void * tmp_out_buf = NULL; int status = -2; if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); return NULL; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; while(status == -2) // txnid already exists on server { txnid = new_client_txn(db, &(db->fastrandstate)); txn_message * q = build_new_txn(txnid, get_nonce(db)); int success = serialize_txn_message(q, (void **) &tmp_out_buf, &len, 1, NULL); #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_txn_message(q, (char *) print_buff); log_info("Sending new txn to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_txn_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); return NULL; } int ok_status = 0, err_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0) ok_status++; else err_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } // TO DO: Update my_lc from each ACK reply received from servers: if(ok_status >= db->quorum_size) err_status = 0; delete_msg_callback(mc->nonce, db); status = err_status; } assert(status == 0); return txnid; } int _remote_validate_txn(uuid_t * txnid, vector_clock * version, remote_server * rs_in, int * minority_status, remote_db_t * db) { unsigned len = 0; void * tmp_out_buf = NULL; *minority_status = 0; txn_message * q = build_validate_txn(txnid, version, get_nonce(db)); int success = serialize_txn_message(q, (void **) &tmp_out_buf, &len, 1, version); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); return NO_QUORUM_ERR; } remote_server * rs = (rs_in != NULL)?(rs_in):((remote_server *) (HEAD(db->servers))->value); #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_txn_message(q, (char *) print_buff); log_info("Sending validate txn: %s", print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_txn_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); return NO_QUORUM_ERR; } int ok_status = 0, abort_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == VAL_STATUS_COMMIT) ok_status++; else if(ack->status == VAL_STATUS_ABORT) abort_status++; else if(ack->status == VAL_STATUS_ABORT_SCHEMA) *minority_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received (%d aborts), minority_status=%d)", ok_status, db->replication_factor, abort_status, *minority_status); delete_msg_callback(mc->nonce, db); return VAL_STATUS_ABORT; } delete_msg_callback(mc->nonce, db); return VAL_STATUS_COMMIT; } int remote_validate_txn(uuid_t * txnid, int * minority_status, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_validate_txn, &ts_start); vector_clock * version = get_lc(db); int ret = _remote_validate_txn(txnid, get_lc(db), NULL, minority_status, db); free_vc(version); stat_stop(dbc_stats.remote_validate_txn, &ts_start, 0); return ret; } int _remote_abort_txn(uuid_t * txnid, remote_server * rs_in, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_abort_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; txn_message * q = build_abort_txn(txnid, get_nonce(db)); int success = serialize_txn_message(q, (void **) &tmp_out_buf, &len, 1, NULL); if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_abort_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (rs_in != NULL)?(rs_in):((remote_server *) (HEAD(db->servers))->value); #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_txn_message(q, (char *) print_buff); log_info("Sending abort txn: %s", print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_txn_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_abort_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } int ok_status = 0, err_status = 0; for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0) ok_status++; else err_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status >= db->quorum_size) err_status = 0; delete_msg_callback(mc->nonce, db); stat_stop(dbc_stats.remote_abort_txn, &ts_start, 0); return err_status; } int remote_abort_txn(uuid_t * txnid, remote_db_t * db) { return _remote_abort_txn(txnid, NULL, db); } int _remote_persist_txn(uuid_t * txnid, vector_clock * version, remote_server * rs_in, int * minority_status, remote_db_t * db) { unsigned len = 0; void * tmp_out_buf = NULL; txn_message * q = build_commit_txn(txnid, version, get_nonce(db)); int success = serialize_txn_message(q, (void **) &tmp_out_buf, &len, 1, version); *minority_status = 0; if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); return NO_QUORUM_ERR; } remote_server * rs = (rs_in != NULL)?(rs_in):((remote_server *) (HEAD(db->servers))->value); #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_txn_message(q, (char *) print_buff); log_info("Sending commit txn: %s", print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_txn_message(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); return NO_QUORUM_ERR; } int ok_status = 0; for(int i=0;ino_replies;i++) { if(mc->reply_types[i] != RPC_TYPE_ACK) { log_error("Received unexpected reply type: %d", mc->reply_types[i]); assert(0); } ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == 0) ok_status++; else *minority_status = ack->status; #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } if(ok_status < db->quorum_size) { log_error("No valid quorum (%d/%d valid replies received), minority_status = %d", ok_status, db->replication_factor, *minority_status); delete_msg_callback(mc->nonce, db); return NO_QUORUM_ERR; } delete_msg_callback(mc->nonce, db); return 0; } int remote_commit_txn(uuid_t * txnid, int * minority_status, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.remote_commit_txn, &ts_start); unsigned len = 0; void * tmp_out_buf = NULL; #if (CLIENT_VERBOSITY > 0) char uuid_str[37]; uuid_unparse_lower(*txnid, uuid_str); #endif #if (CLIENT_VERBOSITY > 1) log_info("CLIENT: Attempting to validate txn %s", uuid_str); #endif if(db->servers->no_items < db->quorum_size) { log_error("No quorum (%d/%d servers alive)", db->servers->no_items, db->replication_factor); stat_stop(dbc_stats.remote_commit_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; vector_clock * commit_stamp = get_lc(db); int val_res = _remote_validate_txn(txnid, commit_stamp, rs, minority_status, db); #if (CLIENT_VERBOSITY > 0) log_info("CLIENT: validate txn %s from server %s returned %d, minority_status %d", uuid_str, rs->id, val_res, *minority_status); #endif switch(val_res) { case VAL_STATUS_COMMIT: { int persist_status = NO_SUCH_TXN, minority_status_persist, retry = 0; while(persist_status != 0) { persist_status = _remote_persist_txn(txnid, commit_stamp, rs, &minority_status_persist, db); #if (CLIENT_VERBOSITY > 0) log_info("CLIENT: persist txn %s from server %s returned %d, minority_status %d", uuid_str, rs->id, persist_status, minority_status_persist); #endif if(retry==1) sleep(1); retry=1; } int res = close_client_txn(*txnid, db); // Clear local cached txn state on client #if (CLIENT_VERBOSITY > 1) log_info("CLIENT: close txn %s returned %d", uuid_str, res); #endif break; } case VAL_STATUS_ABORT: case VAL_STATUS_ABORT_SCHEMA: { int res = _remote_abort_txn(txnid, rs, db); #if (CLIENT_VERBOSITY > 0) log_info("CLIENT: abort txn %s from server %s returned %d", uuid_str, rs->id, res); #endif res = close_client_txn(*txnid, db); // Clear local cached txn state on client #if (CLIENT_VERBOSITY > 1) log_info("CLIENT: close txn %s returned %d", uuid_str, res); #endif break; } case NO_QUORUM_ERR: { log_error("Validation round achieved no quorum"); free_vc(commit_stamp); stat_stop(dbc_stats.remote_commit_txn, &ts_start, NO_QUORUM_ERR); return NO_QUORUM_ERR; } default: { assert(0); } } free_vc(commit_stamp); stat_stop(dbc_stats.remote_commit_txn, &ts_start, 0); return val_res; } // Txn state handling client-side: txn_state * get_client_txn_state(uuid_t txnid, remote_db_t * db) { snode_t * txn_node = (snode_t *) skiplist_search(db->txn_state, (WORD) txnid); #if (CLIENT_VERBOSITY > 0) char uuid_str[37]; uuid_unparse_lower(txnid, uuid_str); log_info("CLIENT: get_client_txn_state(%s): skiplist_search() returned: %p / %p", uuid_str, txn_node, (txn_node != NULL)? (txn_state *) txn_node->value : NULL); #endif return (txn_node != NULL)? (txn_state *) txn_node->value : NULL; } uuid_t * new_client_txn(remote_db_t * db, unsigned int * seedptr) { txn_state * ts = NULL, * previous = NULL; pthread_mutex_lock(db->txn_state_lock); while(ts == NULL) { ts = init_txn_state(); previous = get_client_txn_state(ts->txnid, db); if(previous != NULL) { free_txn_state(ts); ts = NULL; } } skiplist_insert(db->txn_state, (WORD) (ts->txnid), (WORD) ts, seedptr); pthread_mutex_unlock(db->txn_state_lock); return &(ts->txnid); } int close_client_txn(uuid_t txnid, remote_db_t * db) { struct timespec ts_start; stat_start(dbc_stats.close_client_txn, &ts_start); pthread_mutex_lock(db->txn_state_lock); txn_state * ts = get_client_txn_state(txnid, db); if(ts == NULL) { // No such txn pthread_mutex_unlock(db->txn_state_lock); stat_stop(dbc_stats.close_client_txn, &ts_start, NO_SUCH_TXN); return NO_SUCH_TXN; } skiplist_delete(db->txn_state, (WORD) txnid); free_txn_state(ts); pthread_mutex_unlock(db->txn_state_lock); stat_stop(dbc_stats.close_client_txn, &ts_start, 0); return 0; } // Msg callback handling: msg_callback * get_msg_callback(int64_t nonce, WORD client_id, void (*callback)(void *), int replication_factor) { msg_callback * mc = (msg_callback *) malloc(sizeof(msg_callback) + 2 * sizeof(pthread_mutex_t) + sizeof(pthread_cond_t) + replication_factor * (sizeof(void *) + sizeof(short) )); mc->client_id = client_id; mc->nonce = nonce; mc->lock = (pthread_mutex_t *) ((char *)mc + sizeof(msg_callback)); mc->signal = (pthread_cond_t *) ((char *)mc + sizeof(msg_callback) + sizeof(pthread_mutex_t)); pthread_mutex_init(mc->lock, NULL); pthread_cond_init(mc->signal, NULL); mc->callback = callback; mc->no_replies = 0; mc->no_valid_replies = 0; mc->reply_lock = (pthread_mutex_t *) ((char *)mc + sizeof(msg_callback) + sizeof(pthread_mutex_t) + sizeof(pthread_cond_t)); pthread_mutex_init(mc->reply_lock, NULL); // mc->replies = (void **) ((char *)mc + sizeof(msg_callback) + 2 * sizeof(pthread_mutex_t) + sizeof(pthread_cond_t)); // mc->reply_types = (short *) ((char *)mc + sizeof(msg_callback) + 2 * sizeof(pthread_mutex_t) + sizeof(pthread_cond_t) + replication_factor * sizeof(void *)); mc->replies = (void **) malloc(replication_factor*sizeof(void *)); mc->reply_types = (short *) malloc(replication_factor*sizeof(short)); return mc; } int add_reply_to_msg_callback(void * reply, short reply_type, msg_callback * mc) { int no_replies = 0; int ret = pthread_mutex_lock(mc->reply_lock); mc->replies[mc->no_replies] = reply; mc->reply_types[mc->no_replies] = reply_type; mc->no_replies++; int status = 0, invalid_reply = 0; if(reply_type == RPC_TYPE_ACK) status = ((ack_message *) reply)->status; else if(reply_type == RPC_TYPE_QUEUE) status = ((queue_query_message *) reply)->status; if(status < 0 && status != DB_ERR_DUPLICATE_QUEUE && status != DB_ERR_DUPLICATE_CONSUMER) // valid statuses { #if (CLIENT_VERBOSITY > 0) log_debug("Received invalid ack with status %d", status); #endif invalid_reply=1; } if(!invalid_reply) mc->no_valid_replies++; no_replies = mc->no_valid_replies; ret = pthread_mutex_unlock(mc->reply_lock); return no_replies; } void free_msg_callback(msg_callback * mc) { free(mc->replies); free(mc->reply_types); free(mc); } // Gossip listener: #define DEBUG_GOSSIP_CALLBACK 0 gossip_callback_args * get_gossip_callback_args(membership_state * membership, int status) { gossip_callback_args * qca = (gossip_callback_args *) malloc(sizeof(gossip_callback_args)); qca->membership = membership; qca->status = status; return qca; } void free_gossip_callback_args(gossip_callback_args * qca) { free(qca); } gossip_callback * get_gossip_callback(void (*callback)(gossip_callback_args *)) { gossip_callback * qc = (gossip_callback *) malloc(sizeof(gossip_callback) + sizeof(pthread_mutex_t) + sizeof(pthread_cond_t)); qc->lock = (pthread_mutex_t *) ((char *)qc + sizeof(gossip_callback)); qc->signal = (pthread_cond_t *) ((char *)qc + sizeof(gossip_callback) + sizeof(pthread_mutex_t)); pthread_mutex_init(qc->lock, NULL); pthread_cond_init(qc->signal, NULL); qc->callback = callback; return qc; } int wait_on_gossip_callback(gossip_callback * qc) { int ret = pthread_mutex_lock(qc->lock); #if DEBUG_GOSSIP_CALLBACK > 0 log_info("Locked gossip lock %p/%p", qc, qc->lock); #endif struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 3; ret = pthread_cond_timedwait(qc->signal, qc->lock, &ts); pthread_mutex_unlock(qc->lock); #if DEBUG_GOSSIP_CALLBACK > 0 log_info("Unlocked gossip lock %p/%p", qc, qc->lock); #endif return ret; } void free_gossip_callback(gossip_callback * qc) { free(qc); } int listen_to_gossip(int status, int rack_id, int dc_id, char * hostname, unsigned short local_rts_id, remote_db_t * db) { unsigned len = 0; void * tmp_out_buf = NULL; node_description * nd = init_node_description(status, -1, rack_id, dc_id, hostname, local_rts_id); nd->node_id = get_node_id((struct sockaddr *) &(nd->address)); db->local_rts_id = nd->node_id; gossip_listen_message * q = build_gossip_listen_msg(nd, get_nonce(db)); int success = serialize_gossip_listen_msg(q, (void **) &tmp_out_buf, &len); if(db->servers->no_items < 1) { log_error("At least 1 server must be configured for the client to subscribe to gossip (%d servers configured)", db->servers->no_items); return NO_QUORUM_ERR; } remote_server * rs = (remote_server *) (HEAD(db->servers))->value; #if CLIENT_VERBOSITY > 0 char print_buff[1024]; to_string_gossip_listen_msg(q, (char *) print_buff); log_info("Sending gossip listen message to server %s: %s", rs->id, print_buff); #endif // Send packet to server and wait for reply: msg_callback * mc = NULL; success = send_packet_wait_replies_sync(tmp_out_buf, len, q->nonce, &mc, db); assert(success == 0); free_gossip_listen_msg(q); if(mc->no_replies < db->quorum_size) { log_error("No quorum (%d/%d replies received)", mc->no_replies, db->replication_factor); delete_msg_callback(mc->nonce, db); return NO_QUORUM_ERR; } for(int i=0;ino_replies;i++) { assert(mc->reply_types[i] == RPC_TYPE_ACK); ack_message * ack = (ack_message *) mc->replies[i]; if(ack->status == CLIENT_ERR_SUBSCRIPTION_EXISTS) { delete_msg_callback(mc->nonce, db); return CLIENT_ERR_SUBSCRIPTION_EXISTS; } #if CLIENT_VERBOSITY > 0 to_string_ack_message(ack, (char *) print_buff); log_info("Got back response from server %s: %s", rs->id, print_buff); #endif } delete_msg_callback(mc->nonce, db); return 0; } ================================================ FILE: backend/client_api.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * client_api.h * * Author: aagapi */ #ifndef BACKEND_CLIENT_API_H_ #define BACKEND_CLIENT_API_H_ #include "db.h" #include "queue_callback.h" #include "failure_detector/db_queries.h" #include "failure_detector/fd.h" #include "fastrand.h" #include "comm.h" #include #include #include #include #include #define RANDOM_NONCES #define CLIENT_VERBOSITY 0 #define CLIENT_LOCK_VERBOSITY 0 #define SYNC_SOCKET 1 #define NO_QUORUM_ERR -1 #define NO_SUCH_MSG_CALLBACK -2 #define NO_SUCH_TXN -3 #define SUBSCRIPTION_EXISTS -4 #define NO_SUBSCRIPTION_EXISTS -5 #define DEBUG_BLOBS 0 /* * Statistics per type of DB operation * * When a DB operation is called through the client API, we immediately * increment the "called" counter. When an operation ends successfully we * increment the success counter or if it fails, we increment the error counter. * This way, we can see the number of outstanding requests through * called-(success+error). no_quorum is a specific error type, and such errors * are counted both using the generic "error" counter as well as the more * specific no_quorum counter. The timing of each operation is recorded in the * time_ buckets, forming a histogram. */ struct dbc_ops_stat { const char *name; unsigned long long called; // Number of calls of this op, incremented on start unsigned long long completed; // Number of completed, incremented on completion // Currently outstanding / in-flight ops is the diff between called - completed unsigned long long success; // Number of successful calls of this op unsigned long long error; // Number of failed calls of this op, includes all errors // success + error = completed unsigned long long no_quorum; // Number of failed calls with NO_QUORUM_ERR unsigned long long time_sum; // nanoseconds spent waiting for op to complete unsigned long long time_100ns; // bucket for <100ns unsigned long long time_1us; // bucket for <1us unsigned long long time_10us; // bucket for <10us unsigned long long time_100us; // bucket for <100us unsigned long long time_1ms; // bucket for <1ms unsigned long long time_10ms; // bucket for <10ms unsigned long long time_100ms; // bucket for <100ms unsigned long long time_1s; // bucket for <1s unsigned long long time_10s; // bucket for <10s unsigned long long time_100s; // bucket for <100s unsigned long long time_inf; // bucket for <+Inf }; // List of operation types #define LIST_OF_DBC_OPS \ X(remote_insert_in_txn) \ X(remote_update_in_txn) \ X(remote_delete_row_in_txn) \ X(remote_delete_cell_in_txn) \ X(remote_delete_by_index_in_txn) \ X(remote_search_in_txn) \ X(remote_search_clustering_in_txn) \ X(remote_search_columns_in_txn) \ X(remote_search_index_in_txn) \ X(remote_range_search_in_txn) \ X(remote_range_search_clustering_in_txn) \ X(remote_range_search_index_in_txn) \ X(remote_read_full_table_in_txn) \ X(remote_create_queue_in_txn) \ X(remote_delete_queue_in_txn) \ X(remote_enqueue_in_txn) \ X(remote_read_queue_in_txn) \ X(remote_consume_queue_in_txn) \ X(remote_subscribe_queue) \ X(remote_unsubscribe_queue) \ X(remote_subscribe_queue_in_txn) \ X(remote_unsubscribe_queue_in_txn) \ X(subscribe_queue_client) \ X(unsubscribe_queue_client) \ X(remote_validate_txn) \ X(remote_abort_txn) \ X(remote_commit_txn) \ X(close_client_txn) // DB client statistics per operation type struct dbc_stat { // Generate the DB client stats structure, based on the list of operations #define X(ops_name) \ struct dbc_ops_stat *ops_name; LIST_OF_DBC_OPS #undef X }; void init_dbc_stats(); // Remote DB API: typedef struct msg_callback { void (*callback)(void *); WORD client_id; int64_t nonce; pthread_mutex_t * lock; pthread_cond_t * signal; pthread_mutex_t * reply_lock; void ** replies; short * reply_types; short no_replies; short no_valid_replies; } msg_callback; msg_callback * get_msg_callback(int64_t nonce, WORD client_id, void (*callback)(void *), int replication_factor); int add_reply_to_msg_callback(void * reply, short reply_type, msg_callback * mc); void free_msg_callback(msg_callback * mc); typedef struct remote_db { int db_id; skiplist_t * servers; // List of remote database servers skiplist_t * rtses; // List of connected rts-es skiplist_t * actors; // List of actors to be deployed in the system skiplist_t * txn_state; // Client cache of txn state skiplist_t * queue_subscriptions; // Client queue subscriptions skiplist_t * group_queue_subscriptions; // Group client queue subscriptions skiplist_t * msg_callbacks; // Client msg callbacks pthread_mutex_t* subscribe_lock; pthread_mutex_t* msg_callbacks_lock; pthread_mutex_t* txn_state_lock; int replication_factor; int quorum_size; int rpc_timeout; int actor_replication_factor; pthread_t comm_thread; short stop_comm; fd_set readfds; int wakeup_pipe[2]; int64_t requests; unsigned int fastrandstate; pthread_mutex_t* lc_lock; vector_clock * my_lc; vector_clock * current_view_id; pthread_mutex_t * gossip_lock; pthread_cond_t * gossip_signal; hash_ring * _rts_ring; // Consistent hashing ring for actor-to-rts placement int local_rts_id; } remote_db_t; typedef struct gossip_callback_args { membership_state * membership; int status; } gossip_callback_args; typedef struct gossip_callback { void (*callback)(gossip_callback_args *); pthread_mutex_t * lock; pthread_cond_t * signal; } gossip_callback; remote_db_t * get_remote_db(int replication_factor, int rack_id, int dc_id, char * hostname, unsigned short local_rts_id, int no_seeds, char ** seed_hosts, int * seed_ports, unsigned int * seedptr); int add_server_to_membership(char *hostname, int portno, int status, remote_db_t * db, unsigned int * seedptr); msg_callback * add_msg_callback(int64_t nonce, void (*callback)(void *), remote_db_t * db); int delete_msg_callback(int64_t nonce, remote_db_t * db); int wait_on_msg_callback(msg_callback * mc, remote_db_t * db); int add_reply_to_nonce(void * reply, short reply_type, int64_t nonce, remote_db_t * db); int64_t get_nonce(remote_db_t * db); vector_clock * get_lc(remote_db_t * db); vector_clock * get_and_increment_lc(remote_db_t * db, int node_id); int update_lc_protected(remote_db_t * db, vector_clock * vc_in); int free_remote_db(remote_db_t * db); int close_remote_db(remote_db_t * db); int sockaddr_cmp(WORD a1, WORD a2); int queue_callback_cmp(WORD e1, WORD e2); // Write ops: int remote_insert_in_txn(WORD * column_values, int no_cols, int no_primary_keys, int no_clustering_keys, WORD blob, size_t blob_size, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_update_in_txn(int * col_idxs, int no_cols, WORD * column_values, WORD blob, size_t blob_size, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_delete_row_in_txn(WORD * column_values, int no_primary_keys, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_delete_cell_in_txn(WORD * column_values, int no_primary_keys, int no_clustering_keys, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_delete_by_index_in_txn(WORD index_key, int idx_idx, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db); // Read ops: int remote_search_in_txn(WORD* primary_keys, int no_primary_keys, db_row_t** result_row, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, db_row_t** result_row, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_search_columns_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD* col_keys, int no_columns, db_row_t** result_row, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_search_index_in_txn(WORD index_key, int idx_idx, db_row_t** result_row, WORD table_key, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_range_search_in_txn(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, snode_t** start_row, snode_t** end_row, WORD table_key, int * no_items, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_range_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, snode_t** start_row, snode_t** end_row, WORD table_key, int * no_items, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_range_search_index_in_txn(int idx_idx, WORD start_idx_key, WORD end_idx_key, snode_t** start_row, snode_t** end_row, WORD table_key, int * no_items, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_read_full_table_in_txn(snode_t** start_row, snode_t** end_row, WORD table_key, int * no_items, int * minority_status, uuid_t * txnid, remote_db_t * db); void remote_print_long_table(WORD table_key, remote_db_t * db); // Queue ops: int remote_create_queue_in_txn(WORD table_key, WORD queue_id, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_delete_queue_in_txn(WORD table_key, WORD queue_id, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_enqueue_in_txn(WORD * column_values, int no_cols, WORD blob, size_t blob_size, WORD table_key, WORD queue_id, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_read_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int max_entries, int * entries_read, int64_t * new_read_head, snode_t** start_row, snode_t** end_row, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_consume_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_subscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, int * minority_status, remote_db_t * db); int remote_unsubscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int * minority_status, remote_db_t * db); int remote_subscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_unsubscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int * minority_status, uuid_t * txnid, remote_db_t * db); int remote_subscribe_group(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, queue_callback * callback, int * minority_status, remote_db_t * db); int remote_unsubscribe_group(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, int * minority_status, remote_db_t * db); // Subscription handling client-side: queue_callback * get_queue_client_callback(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, WORD table_key, WORD queue_id, short use_lock, remote_db_t * db); int subscribe_queue_client(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, short use_lock, remote_db_t * db); int unsubscribe_queue_client(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, short use_lock, remote_db_t * db); int remote_add_queue_to_group(WORD table_key, WORD queue_id, WORD group_id, short use_lock, remote_db_t * db); int remote_remove_queue_from_group(WORD table_key, WORD queue_id, WORD group_id, short use_lock, remote_db_t * db); int subscribe_to_group(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, queue_callback * callback, short use_lock, remote_db_t * db); int unsubscribe_from_group(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, short use_lock, remote_db_t * db); // Txn mgmt: uuid_t * remote_new_txn(remote_db_t * db); int remote_validate_txn(uuid_t * txnid, int * minority_status, remote_db_t * db); int remote_abort_txn(uuid_t * txnid, remote_db_t * db); int remote_commit_txn(uuid_t * txnid, int * minority_status, remote_db_t * db); // Txn state handling client-side: txn_state * get_client_txn_state(uuid_t txnid, remote_db_t * db); uuid_t * new_client_txn(remote_db_t * db, unsigned int * seedptr); int close_client_txn(uuid_t txnid, remote_db_t * db); // Gossip listener: gossip_callback_args * get_gossip_callback_args(membership_state * ms, int status); void free_gossip_callback_args(gossip_callback_args * qca); gossip_callback * get_gossip_callback(void (*callback)(gossip_callback_args *)); int wait_on_gossip_callback(gossip_callback *); void free_gossip_callback(gossip_callback * qc); int listen_to_gossip(int status, int rack_id, int dc_id, char * hostname, unsigned short local_rts_id, remote_db_t * db); // RTS mgmt: typedef struct rts_descriptor { char id[262]; int rack_id; int dc_id; char * hostname; unsigned short local_rts_id; unsigned int _local_rts_index; struct sockaddr_in addr; int status; } rts_descriptor; rts_descriptor * get_rts_descriptor(int rack_id, int dc_id, char *hostname, int local_rts_id, int status); void free_rts_descriptor(WORD rts_d); WORD get_rts_key(WORD); WORD get_rts_live_field(WORD); int add_rts_to_membership(int rack_id, int dc_id, char *hostname, int local_rts_id, int node_status, skiplist_t * rtss, hash_ring * _rts_ring, unsigned int * seedptr); char * to_string_rts_membership(remote_db_t * db, char * msg_buff); // Actor mgmt: #define ACTOR_STATUS_RUNNING 0 #define ACTOR_STATUS_MIGRATING 1 #define ACTOR_STATUS_STOPPED 2 static const char *Actor_status_name[] = {"running", "migrating", "stopped"}; typedef struct actor_descriptor { long actor_id; rts_descriptor * host_rts; int is_local; int status; } actor_descriptor; actor_descriptor * get_actor_descriptor(long actor_id, rts_descriptor * host_rts, int is_local, int status); void free_actor_descriptor(actor_descriptor * a); int add_actor_to_membership(long actor_id, remote_db_t * db); int update_actor_placement(remote_db_t * db); int is_actor_local(long actor_id, remote_db_t * db); skiplist_t * get_rtses_for_actor(long actor_id, remote_db_t * db); rts_descriptor * get_first_rts_for_actor(long actor_id, remote_db_t * db); skiplist_t * get_local_actors(remote_db_t * db); skiplist_t * get_remote_actors(remote_db_t * db); char * to_string_actor_membership(remote_db_t * db, char * msg_buff); #endif /* BACKEND_CLIENT_API_H_ */ ================================================ FILE: backend/comm.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * comm.c * * Author: aagapi */ #include "comm.h" #include "log.h" #include #include #include int parse_message_v1(void * rcv_buf, size_t rcv_msg_len, void ** out_msg, short * out_msg_type, int64_t * nonce, short is_server) { write_query * wq; read_query * rq; range_read_query * rrq; queue_query_message * qq; ack_message * am; txn_message * tm; range_read_response_message * rrr; #if (VERBOSE_RPC > 0) char print_buff[BUFSIZE]; #endif int status = 0; if(is_server) // RPCs received by server { status = deserialize_write_query(rcv_buf, rcv_msg_len, &wq); if(status == 0) { #if (VERBOSE_RPC > 0) to_string_write_query(wq, (char *) print_buff); log_debug("Received write query: %s", print_buff); #endif *out_msg = (void *) wq; *out_msg_type = RPC_TYPE_WRITE; *nonce = wq->nonce; return 0; } status = deserialize_read_query(rcv_buf, rcv_msg_len, &rq); if(status == 0) { #if (VERBOSE_RPC > 0) to_string_read_query(rq, (char *) print_buff); log_debug("Received read query: %s", print_buff); #endif *out_msg = (void *) rq; *out_msg_type = RPC_TYPE_READ; *nonce = rq->nonce; return 0; } status = deserialize_range_read_query(rcv_buf, rcv_msg_len, &rrq); if(status == 0) { #if (VERBOSE_RPC > 0) to_string_range_read_query(rrq, (char *) print_buff); log_debug("Received range read query: %s", print_buff); #endif *out_msg = (void *) rrq; *out_msg_type = RPC_TYPE_RANGE_READ; *nonce = rrq->nonce; return 0; } status = deserialize_txn_message(rcv_buf, rcv_msg_len, &tm); if(status == 0) { #if (VERBOSE_RPC > 0) to_string_txn_message(tm, (char *) print_buff); log_debug("Received txn message: %s", print_buff); #endif *out_msg = (void *) tm; *out_msg_type = RPC_TYPE_TXN; *nonce = tm->nonce; return 0; } status = deserialize_queue_message(rcv_buf, rcv_msg_len, &qq); if(status == 0) { #if (VERBOSE_RPC > 0) to_string_queue_message(qq, (char *) print_buff); log_debug("Received queue query: %s", print_buff); #endif *out_msg = (void *) qq; *out_msg_type = RPC_TYPE_QUEUE; *nonce = qq->nonce; return 0; } status = deserialize_ack_message(rcv_buf, rcv_msg_len, &am); if(status == 0) { #if (VERBOSE_RPC > 0) to_string_ack_message(am, (char *) print_buff); log_debug("Received ack message: %s", print_buff); #endif *out_msg = (void *) am; *out_msg_type = RPC_TYPE_ACK; *nonce = am->nonce; return 0; } } else // RPCs received by client { status = deserialize_ack_message(rcv_buf, rcv_msg_len, &am); if(status == 0) { #if (VERBOSE_RPC > 0) to_string_ack_message(am, (char *) print_buff); log_debug("Received ack message: %s", print_buff); #endif *out_msg = (void *) am; *out_msg_type = RPC_TYPE_ACK; *nonce = am->nonce; return 0; } status = deserialize_write_query(rcv_buf, rcv_msg_len, &wq); if(status == 0) { #if (VERBOSE_RPC > 0) to_string_write_query(wq, (char *) print_buff); log_debug("Received write query: %s", print_buff); #endif *out_msg = (void *) wq; *out_msg_type = RPC_TYPE_READ_RESPONSE; *nonce = wq->nonce; return 0; } status = deserialize_range_read_response_message(rcv_buf, rcv_msg_len, &rrr); if(status == 0) { #if (VERBOSE_RPC > 0) to_string_range_read_response_message(rrr, (char *) print_buff); log_debug("Received range read response: %s", print_buff); #endif *out_msg = (void *) rrr; *out_msg_type = RPC_TYPE_RANGE_READ_RESPONSE; *nonce = rrr->nonce; return 0; } status = deserialize_queue_message(rcv_buf, rcv_msg_len, &qq); if(status == 0) { #if (VERBOSE_RPC > 0) to_string_queue_message(qq, (char *) print_buff); log_debug("Received queue read response: %s", print_buff); #endif *out_msg = (void *) qq; *out_msg_type = RPC_TYPE_QUEUE; *nonce = qq->nonce; return 0; } } *out_msg = NULL; *out_msg_type = -1; *nonce = -1; return 1; } int parse_message(void * rcv_buf, size_t rcv_msg_len, void ** out_msg, short * out_msg_type, short * is_gossip_message, int64_t * nonce, short is_server, vector_clock ** vc) { read_query * rq; range_read_query * rrq; queue_query_message * qq; ack_message * am; txn_message * tm; range_read_response_message * rrr; #if (VERBOSE_RPC > 0) char print_buff[BUFSIZE]; #endif int status = 0; if(is_server) // RPCs received by server { status = deserialize_server_message(rcv_buf, rcv_msg_len, out_msg, out_msg_type, vc); if(status == 0) { switch(*out_msg_type) { case RPC_TYPE_WRITE: { write_query * wq = (write_query *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_write_query(wq, (char *) print_buff); log_debug("Received write query: %s", print_buff); #endif *nonce = wq->nonce; return 0; } case RPC_TYPE_READ: { read_query * wq = (read_query *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_read_query(wq, (char *) print_buff); log_debug("Received read query: %s", print_buff); #endif *nonce = wq->nonce; return 0; } case RPC_TYPE_RANGE_READ: { range_read_query * wq = (range_read_query *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_range_read_query(wq, (char *) print_buff); log_debug("Received range read query: %s", print_buff); #endif *nonce = wq->nonce; return 0; } case RPC_TYPE_QUEUE: { queue_query_message * wq = (queue_query_message *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_queue_message(wq, (char *) print_buff); log_debug("Received queue message: %s", print_buff); #endif *nonce = wq->nonce; return 0; } case RPC_TYPE_TXN: { txn_message * wq = (txn_message *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_txn_message(wq, (char *) print_buff); log_debug("Received txn message: %s", print_buff); #endif *nonce = wq->nonce; return 0; } case RPC_TYPE_GOSSIP_LISTEN: { gossip_listen_message * wq = (gossip_listen_message *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_gossip_listen_msg(wq, (char *) print_buff); log_debug("Received gossip listen message: %s", print_buff); #endif *nonce = wq->nonce; return 0; } default: { assert(0); } } } } else // RPCs received by client { status = deserialize_client_message(rcv_buf, rcv_msg_len, out_msg, out_msg_type, is_gossip_message, vc); if(status == 0) { if(*is_gossip_message) { return 0; } switch(*out_msg_type) { case RPC_TYPE_ACK: { ack_message * wq = (ack_message *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_ack_message(wq, (char *) print_buff); log_debug("Received ack message: %s", print_buff); #endif *nonce = wq->nonce; return 0; } case RPC_TYPE_WRITE: { write_query * wq = (write_query *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_write_query(wq, (char *) print_buff); log_debug("Received write query: %s", print_buff); #endif *nonce = wq->nonce; return 0; } case RPC_TYPE_RANGE_READ_RESPONSE: { range_read_response_message * wq = (range_read_response_message *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_range_read_response_message(wq, (char *) print_buff); log_debug("Received range read response message: %s", print_buff); #endif *nonce = wq->nonce; return 0; } case RPC_TYPE_QUEUE: { queue_query_message * wq = (queue_query_message *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_queue_message(wq, (char *) print_buff); log_debug("Received queue message: %s", print_buff); #endif *nonce = wq->nonce; return 0; } case RPC_TYPE_TXN: { txn_message * wq = (txn_message *) *(out_msg); #if (VERBOSE_RPC > 0) to_string_txn_message(wq, (char *) print_buff); log_debug("Received txn message: %s", print_buff); #endif *nonce = wq->nonce; return 0; } default: { assert(0); } } } } *out_msg = NULL; *out_msg_type = -1; *nonce = -1; return 1; } int read_full_packet(int * sockfd, char * inbuf, size_t inbuf_size, int * msg_len, int * statusp, int (*handle_socket_close)(int * sockfd, int * status)) { int announced_msg_len = -1; int read_buf_offset = 0; int status = 0; while(1) // Loop until reading complete packet: { assert(read_buf_offset < inbuf_size - sizeof(int)); if(read_buf_offset == 0) { // Read msg len header from packet: bzero(inbuf, inbuf_size); *msg_len = -1; int size_len = read(*sockfd, inbuf, sizeof(int)); if (size_len < 0) { log_error("ERROR reading from socket"); continue; } else if (size_len == 0) { handle_socket_close(sockfd, statusp); status = 1; break; } announced_msg_len = *((int *)inbuf); *((int *)inbuf) = 0; // 0 back buffer read_buf_offset = 0; } if(announced_msg_len <= 0) { read_buf_offset = 0; continue; } *msg_len = read(*sockfd, inbuf + sizeof(int) + read_buf_offset, announced_msg_len - read_buf_offset); #if COMM_VERBOSITY > 2 log_debug("announced_msg_len=%d, msg_len=%d, read_buf_offset=%d", announced_msg_len, *msg_len, read_buf_offset); #endif if (*msg_len < 0) { log_error("ERROR reading from socket"); continue; } else if(*msg_len == 0) // client closed socket { handle_socket_close(sockfd, statusp); status = 1; break; } else if(*msg_len < announced_msg_len - read_buf_offset) { read_buf_offset += *msg_len; continue; // Continue reading socket until full packet length } break; } assert(status != 0 || announced_msg_len == *msg_len); // read_buf_offset = 0; // Reset #if COMM_VERBOSITY > 2 log_debug("server received %d / %d bytes", announced_msg_len, *msg_len); #endif return status; } int sockaddr_cmp(WORD a1, WORD a2) { struct sockaddr * x = (struct sockaddr *) a1; struct sockaddr * y = (struct sockaddr *) a2; #define CMP(a, b) if (a != b) return a - b CMP(x->sa_family, y->sa_family); if (x->sa_family == AF_UNIX) { struct sockaddr_un *xun = (void*)x, *yun = (void*)y; int r = strcmp(xun->sun_path, yun->sun_path); if (r != 0) return r; } else if (x->sa_family == AF_INET) { struct sockaddr_in *xin = (void*)x, *yin = (void*)y; CMP(ntohl(xin->sin_addr.s_addr), ntohl(yin->sin_addr.s_addr)); CMP(ntohs(xin->sin_port), ntohs(yin->sin_port)); } else if (x->sa_family == AF_INET6) { struct sockaddr_in6 *xin6 = (void*)x, *yin6 = (void*)y; int r = memcmp(xin6->sin6_addr.s6_addr, yin6->sin6_addr.s6_addr, sizeof(xin6->sin6_addr.s6_addr)); if (r != 0) return r; CMP(ntohs(xin6->sin6_port), ntohs(yin6->sin6_port)); CMP(xin6->sin6_flowinfo, yin6->sin6_flowinfo); CMP(xin6->sin6_scope_id, yin6->sin6_scope_id); } else { assert(!"unknown sa_family"); } #undef CMP return 0; } // Remote server struct fctns: remote_server * get_remote_server(char *hostname, unsigned short portno, struct sockaddr_in serveraddr, struct sockaddr_in client_socket_addr, int serverfd, int do_connect, int is_rts) { remote_server * rs = (remote_server *) malloc(sizeof(remote_server)); bzero(rs, sizeof(remote_server)); rs->status = NODE_DEAD; assert(serverfd != NULL_FD); memcpy(&(rs->client_socket_addr), &client_socket_addr, sizeof(struct sockaddr_in)); if(serverfd > 0 || serverfd == OWN_FD) // For own node, use provided serveraddr and mark as live { memcpy(&(rs->serveraddr), &serveraddr, sizeof(struct sockaddr_in)); rs->sockfd = serverfd; rs->server = gethostbyname(hostname); assert(rs->server != NULL); rs->status = NODE_LIVE; } else { rs->server = gethostbyname(hostname); if (rs->server == NULL) { log_error("ERROR, no such host %s", hostname); free_remote_server(rs); return NULL; } bzero((void *) &rs->serveraddr, sizeof(struct sockaddr_in)); rs->serveraddr.sin_family = AF_INET; bcopy((char *)rs->server->h_addr_list[0], (char *)&(rs->serveraddr.sin_addr.s_addr), rs->server->h_length); rs->serveraddr.sin_port = htons(portno); if(do_connect) { rs->status = NODE_LIVE; rs->sockfd = socket(AF_INET, SOCK_STREAM, 0); if (rs->sockfd < 0) { log_error("ERROR opening socket!"); free_remote_server(rs); return NULL; } int connect_success = -1; for(int connect_retries = 0; connect_success != 0 && connect_retries < MAX_CONNECT_RETRIES; connect_retries++) { connect_success = connect(rs->sockfd, (struct sockaddr *) &rs->serveraddr, sizeof(struct sockaddr_in)); if(connect_success != 0) sleep(1); } if (connect_success != 0) { log_error("get_remote_server: ERROR connecting to %s:%d", hostname, portno); rs->status = NODE_DEAD; rs->sockfd = -1; } } } rs->sockfd_lock = (pthread_mutex_t*) malloc (sizeof(pthread_mutex_t)); pthread_mutex_init(rs->sockfd_lock, NULL); snprintf((char *) &rs->id, 262, "%s%s%d", hostname, is_rts?"/":":", portno); strncpy((char *) &(rs->hostname), hostname, strnlen(hostname, 256) + 1); rs->portno = portno; return rs; } int update_listen_socket(remote_server * rs, char *hostname, unsigned short portno, int do_connect) { struct hostent * old_hostent = rs->server; rs->server = gethostbyname(hostname); if (rs->server == NULL) { log_error("ERROR, no such host %s", hostname); rs->server = old_hostent; return -1; } bzero((void *) &rs->serveraddr, sizeof(struct sockaddr_in)); rs->serveraddr.sin_family = AF_INET; bcopy((char *)rs->server->h_addr_list[0], (char *)&(rs->serveraddr.sin_addr.s_addr), rs->server->h_length); rs->serveraddr.sin_port = htons(portno); if(do_connect) { int old_sockfd = rs->sockfd; rs->sockfd = socket(AF_INET, SOCK_STREAM, 0); if (rs->sockfd < 0) { log_error("update_listen_socket: ERROR opening socket!"); rs->sockfd = old_sockfd; return -2; } int connect_success = -1; for(int connect_retries = 0; connect_success != 0 && connect_retries < MAX_CONNECT_RETRIES; connect_retries++) { connect_success = connect(rs->sockfd, (struct sockaddr *) &rs->serveraddr, sizeof(struct sockaddr_in)); if(connect_success != 0) sleep(2); } if(connect_success != 0) { log_error("update_listen_socket: ERROR connecting to %s:%d", hostname, portno); rs->status = NODE_DEAD; rs->sockfd = -1; } else { log_debug("SERVER: Updated listen socket of %s/%s:%d (%s:%d) from %d to %d", rs->id, rs->hostname, rs->portno, hostname, portno, old_sockfd, rs->sockfd); } } log_debug("SERVER: Updating listen socket of %s/%s:%d (%d) to %s:%d", rs->id, rs->hostname, rs->portno, rs->sockfd, hostname, portno); snprintf((char *) &rs->id, 262, "%s:%d", hostname, portno); strncpy((char *) &(rs->hostname), hostname, strnlen(hostname, 256) + 1); rs->portno = portno; return 0; } int connect_remote_server(remote_server * rs) { if(rs->sockfd > 0) { log_error("connect_remote_server: Skipping connect, server %s:%d already connected!", rs->hostname, rs->portno); return 0; } rs->sockfd = socket(AF_INET, SOCK_STREAM, 0); if (rs->sockfd < 0) { log_error("connect_remote_server: ERROR opening socket!"); return -1; } int connect_success = -1; for(int connect_retries = 0; connect_success != 0 && connect_retries < MAX_CONNECT_RETRIES; connect_retries++) { connect_success = connect(rs->sockfd, (struct sockaddr *) &rs->serveraddr, sizeof(struct sockaddr_in)); if(connect_success != 0) sleep(2); } if(connect_success != 0) { log_error("connect_remote_server: ERROR connecting to %s:%d", rs->hostname, rs->portno); rs->status = NODE_DEAD; rs->sockfd = -1; } return connect_success; } void free_remote_server(remote_server * rs) { free(rs->sockfd_lock); free(rs); } void free_remote_server_ptr(WORD ptr) { free_remote_server((remote_server *) ptr); } ================================================ FILE: backend/comm.h ================================================ /* * comm.h * * Author: aagapi */ #ifndef BACKEND_COMM_H_ #define BACKEND_COMM_H_ #include "failure_detector/db_queries.h" #include #include #include #include #include #include #include #include #include #define VERBOSE_RPC 0 #define COMM_VERBOSITY 2 #define BUFSIZE 128 * 1024 #define MAX_CONNECT_RETRIES 5 #define NODE_LIVE 0 #define NODE_DEAD 1 #define NODE_PREJOINED 2 #define NULL_FD -1 #define OWN_FD -2 #define DUMMY_FD -3 static const char *RS_status_name[] = {"live", "dead", "unknown", "prejoined"}; // Comm loop fctns: int parse_message(void * rcv_buf, size_t rcv_msg_len, void ** out_msg, short * out_msg_type, short * is_gossip_message, int64_t * nonce, short is_server, vector_clock ** vc); int read_full_packet(int * sockfd, char * inbuf, size_t inbuf_size, int * msg_len, int * statusp, int (*handle_socket_close)(int * sockfd, int * status)); int sockaddr_cmp(WORD a1, WORD a2); // Remote server mgmt fctns: typedef struct remote_server { char hostname[256]; unsigned short portno; int sockfd; pthread_mutex_t* sockfd_lock; struct sockaddr_in serveraddr; struct sockaddr_in client_socket_addr; struct hostent *server; char id[262]; int status; char in_buf[BUFSIZE]; } remote_server; remote_server * get_remote_server(char *hostname, unsigned short portno, struct sockaddr_in serveraddr, struct sockaddr_in client_socket_addr, int serverfd, int do_connect, int is_rts); int update_listen_socket(remote_server * rs, char *hostname, unsigned short portno, int do_connect); int connect_remote_server(remote_server * rs); void free_remote_server(remote_server * rs); void free_remote_server_ptr(WORD ptr); #endif /* BACKEND_COMM_H_ */ ================================================ FILE: backend/common.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * common.h * Author: aagapi */ #ifndef BACKEND_COMMON_H_ #define BACKEND_COMMON_H_ typedef void *WORD; #define DB_TYPE_CHAR 0 #define DB_TYPE_INT16 1 #define DB_TYPE_INT32 2 #define DB_TYPE_INT64 3 #define DB_TYPE_FLOAT32 4 #define DB_TYPE_FLOAT64 5 #define DB_TYPE_BLOB 6 #define VERBOSE_BACKEND 0 #include #include #include #include #include #include #endif /* BACKEND_COMMON_H_ */ ================================================ FILE: backend/consumer_state.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * consumer_state.h * * Author: aagapi */ #ifndef BACKEND_CONSUMER_STATE_H_ #define BACKEND_CONSUMER_STATE_H_ #include "common.h" #include "failure_detector/vector_clock.h" typedef struct group_state group_state; typedef struct group_queue_consumer_state { int64_t private_read_head; int64_t private_consume_head; vector_clock * prh_version; vector_clock * pch_version; group_state * gs; } group_queue_consumer_state; typedef struct consumer_state { WORD consumer_id; WORD shard_id; WORD app_id; WORD group_id; int64_t private_read_head; int64_t private_consume_head; vector_clock * prh_version; vector_clock * pch_version; short notified; queue_callback* callback; // For local subscribers int * sockfd; // For remote subscribers } consumer_state; #endif /* BACKEND_CONSUMER_STATE_H_ */ ================================================ FILE: backend/db.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * db.c * * Author: aagapi */ #include #include #include #include #include #include "db.h" #include "queue_groups.h" #include "skiplist.h" #include "log.h" // DB API: db_row_t * create_empty_row(WORD key) { db_cell_t * row = (db_cell_t *) malloc(sizeof(db_cell_t)); memset(row, 0, sizeof(db_cell_t)); row->key = key; row->cells = NULL; row->column_array = NULL; row->no_columns=0; row->last_blob_size = 0; row->version = NULL; row->_next = NULL; row->no_entries = 0; return row; } db_row_t * create_db_row_schemaless(WORD * column_values, int * primary_key_idxs, int no_primary_keys, int * clustering_key_idxs, int no_clustering_keys, int no_schema_clustering_keys, int no_cols, size_t last_blob_size, unsigned int * fastrandstate) { assert(no_primary_keys == 1); assert(no_clustering_keys >= no_schema_clustering_keys); db_cell_t * row = create_empty_row(column_values[primary_key_idxs[0]]); // Several clustering keys mean several levels of depth (a la super columns): db_cell_t * crt_cell = row, * new_cell = NULL; for(int i=0; icells = create_skiplist_long(); int col_index = (ino_columns = no_cols - no_primary_keys - no_clustering_keys; new_cell->last_blob_size = last_blob_size; new_cell->column_array = (WORD *) malloc(new_cell->no_columns * sizeof(WORD)); int j=0; for(;jno_columns - 1;j++) { new_cell->column_array[j] = column_values[no_primary_keys + no_clustering_keys + j]; } if(last_blob_size <= 0) // last column is value { new_cell->column_array[j] = column_values[no_primary_keys + no_clustering_keys + j]; } else // last column is blob { new_cell->column_array[j] = malloc(last_blob_size); memcpy(new_cell->column_array[j], column_values[no_primary_keys + no_clustering_keys + j], last_blob_size); } } skiplist_insert(crt_cell->cells, column_values[col_index], (WORD) new_cell, fastrandstate); } return row; } // Assumes key indexes are in order (partition keys, followed by clustering keys, followed by columns). Also assumes a single partition key: db_row_t * create_db_row_schemaless2(WORD * keys, int no_keys, WORD * cols, int no_cols, WORD last_blob, size_t last_blob_size, unsigned int * fastrandstate) { db_cell_t * row = create_empty_row(keys[0]); db_cell_t * crt_cell = row, * new_cell = NULL; for(int i=1; icells = create_skiplist_long(); new_cell = create_empty_row(keys[i]); skiplist_insert(crt_cell->cells, keys[i], (WORD) new_cell, fastrandstate); } assert(crt_cell != NULL && crt_cell->cells == NULL); assert(last_blob == NULL || last_blob_size > 0); int total_cols = no_cols + ((last_blob != NULL)?1:0); crt_cell->no_columns = total_cols; crt_cell->column_array = (WORD *) malloc(total_cols * sizeof(WORD)); int j=0; for(;jcolumn_array[j] = cols[j]; } crt_cell->last_blob_size = last_blob_size; if(last_blob != NULL) { assert(total_cols == no_cols + 1); crt_cell->column_array[no_cols] = malloc(last_blob_size); memcpy(crt_cell->column_array[no_cols], last_blob, last_blob_size); } return row; } db_row_t * create_db_row_sf(WORD * column_values, db_schema_t * schema, int no_clustering_keys, int no_cols, size_t last_blob_size, unsigned int * fastrandstate) { return create_db_row_schemaless(column_values, schema->primary_key_idxs, schema->no_primary_keys, schema->clustering_key_idxs, no_clustering_keys, schema->min_no_clustering_keys, no_cols, last_blob_size, fastrandstate); } void free_db_cell(db_row_t * row, db_t * db) { if(row->cells != NULL) { for(snode_t * cell=HEAD(row->cells);cell!=NULL;cell=NEXT(cell)) if(cell->value != NULL) free_db_cell(cell->value, db); skiplist_free(row->cells); } if(row->column_array != NULL) { if(row->last_blob_size > 0 && row->no_columns > 0 && row->column_array[row->no_columns - 1] != NULL) { free(row->column_array[row->no_columns - 1]); } free(row->column_array); } if(row->group_subscriptions != NULL && db->queue_group_replication_factor > 1) { skiplist_free(row->group_subscriptions); } free(row); } void free_db_row(db_row_t * row, db_schema_t * schema, db_t * db) { free_db_cell(row, db); } db_t * get_db() { #if (MULTI_THREADED == 1) db_t * db = (db_t *) malloc(sizeof(db_t) + sizeof(pthread_mutex_t)); #else db_t * db = (db_t *) malloc(sizeof(db_t)); # endif db->tables = create_skiplist_long(); db->txn_state = create_skiplist_uuid(); db->queue_groups = get_hash_ring(); db->queue_group_replication_factor = 1; db->enable_auto_queue_group_subscriptions = ENABLE_AUTO_QUEUE_GROUP_SUBSCRIPTIONS; #if (MULTI_THREADED == 1) db->txn_state_lock = (pthread_mutex_t*) ((char*) db + sizeof(db_t)); pthread_mutex_init(db->txn_state_lock, NULL); # endif return db; } int db_delete_db(db_t * db) { skiplist_free(db->tables); skiplist_free(db->txn_state); free_hash_ring(db->queue_groups, free_group_state); free(db); return 0; } int db_dump_db(db_t * db) { assert(0 && "DB dump not implemented yet"); return 0; } // Deep copy constructor (to allow caller to free his structs): db_schema_t* db_create_schema(int * col_types, int no_cols, int * primary_key_idxs, int no_primary_keys, int * clustering_key_idxs, int no_clustering_keys, int * index_key_idxs, int no_index_keys) { assert(no_cols > 0 && "Schema must have at least 1 column"); assert(no_primary_keys > 0 && "Schema must have at least 1 primary key"); assert(no_primary_keys <= no_cols && "Schema must have less primary keys than columns"); assert(no_primary_keys == 1 && "Schemas don't currently support compound primary keys"); assert(primary_key_idxs[0] < no_cols && "Primary key index out of bounds"); db_schema_t * schema = (db_schema_t *) malloc(sizeof(db_schema_t)); schema->min_no_cols = no_cols; schema->col_types = NULL; if(col_types != NULL) { schema->col_types = (int *) malloc(no_cols * sizeof(int)); for(int i=0;icol_types[i] = col_types[i]; } schema->primary_key_idxs = (int *) malloc(no_primary_keys * sizeof(int)); schema->no_primary_keys = no_primary_keys; for(int i=0;iprimary_key_idxs[i] = primary_key_idxs[i]; schema->min_no_clustering_keys = no_clustering_keys; if(no_clustering_keys > 0) { schema->clustering_key_idxs = (int *) malloc(no_clustering_keys * sizeof(int)); for(int i=0;iclustering_key_idxs[i] = clustering_key_idxs[i]; } schema->no_index_keys = no_index_keys; if(no_index_keys > 0) { schema->index_key_idxs = (int *) malloc(no_index_keys * sizeof(int)); for(int i=0;iindex_key_idxs[i] = index_key_idxs[i]; } return schema; } void free_schema(db_schema_t * schema) { if(schema == NULL) return; if(schema->col_types != NULL) free(schema->col_types); if(schema->primary_key_idxs != NULL) free(schema->primary_key_idxs); if(schema->clustering_key_idxs != NULL) free(schema->clustering_key_idxs); if(schema->index_key_idxs != NULL) free(schema->index_key_idxs); free(schema); } int db_create_table(WORD table_key, db_schema_t* schema, db_t * db, unsigned int * fastrandstate) { db_table_t * table = (db_table_t *) malloc(sizeof(db_table_t)); table->table_key = table_key; // Deep copy of schema (to allow caller to free his copy): table->schema = db_create_schema(schema->col_types, schema->min_no_cols, schema->primary_key_idxs, schema->no_primary_keys, schema->clustering_key_idxs, schema->min_no_clustering_keys, schema->index_key_idxs, schema->no_index_keys); table->rows = create_skiplist_long(); table->row_tombstones = create_skiplist_long(); if(schema->no_index_keys > 0) table->indexes = (skiplist_t **) malloc(schema->no_index_keys * sizeof(skiplist_t *)); for(int i=0;ino_index_keys;i++) table->indexes[i] = create_skiplist_long(); table->queues = create_skiplist_long(); table->lock = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); pthread_mutex_init(table->lock, NULL); return skiplist_insert(db->tables, table_key, (WORD) table, fastrandstate); } int db_create_index(int new_index, WORD table_key, db_t * db, unsigned int * fastrandstate) { assert(0 && "Index creation post schema creation not supported yet"); return 0; } int db_delete_table(WORD table_key, db_t * db) { db_table_t * table = (db_table_t *) skiplist_delete(db->tables, table_key); if(table != NULL) { skiplist_free(table->rows); for(int i=0;ischema->no_index_keys;i++) skiplist_free(table->indexes[i]); if(table->schema->no_index_keys > 0) free(table->indexes); free_schema(table->schema); skiplist_free(table->queues); free(table); } return table != NULL; } // Table API: int table_insert(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, vector_clock * version, db_table_t * table, unsigned int * fastrandstate) { db_schema_t * schema = table->schema; assert(schema->no_primary_keys == 1 && "Compound primary keys unsupported for now"); if(no_clustering_keys < schema->min_no_clustering_keys) { log_error("SERVER: Row insert must contain at least %d schema clustering keys, only has %d keys", schema->min_no_clustering_keys, no_clustering_keys); assert(0); } assert(no_cols > (schema->no_primary_keys + no_clustering_keys) && "Insert must contain at least 1 non-key column or blob"); db_row_t * row = NULL; snode_t * row_node = skiplist_search(table->rows, column_values[schema->primary_key_idxs[0]]); if(row_node == NULL) { row = create_db_row_sf(column_values, schema, no_clustering_keys, no_cols, last_blob_size, fastrandstate); row->version = (version != NULL)? copy_vc(version) : NULL; skiplist_insert(table->rows, column_values[schema->primary_key_idxs[0]], (WORD) row, fastrandstate); } else { row = (db_row_t *) row_node->value; db_row_t * cell = row, * new_cell = NULL; for(int i=0;imin_no_clustering_keys)?(schema->clustering_key_idxs[i]):(i); snode_t * new_cell_node = skiplist_search(cell->cells, column_values[col_index]); if(new_cell_node == NULL) { new_cell = create_empty_row(column_values[col_index]); if(i < no_clustering_keys - 1) { new_cell->cells = create_skiplist_long(); } skiplist_insert(cell->cells, column_values[col_index], (WORD) new_cell, fastrandstate); } else { new_cell = (db_row_t *) (new_cell_node->value); } } // Populate columns and set version for newly created cell: assert(cell != NULL && cell->cells == NULL); cell->no_columns = no_cols - schema->no_primary_keys - no_clustering_keys; cell->last_blob_size = last_blob_size; cell->column_array = (WORD *) malloc(cell->no_columns * sizeof(WORD)); int j=0; for(;jno_columns - 1;j++) { cell->column_array[j] = column_values[schema->no_primary_keys + no_clustering_keys + j]; } if(last_blob_size <= 0) // last column is value { cell->column_array[j] = column_values[schema->no_primary_keys + no_clustering_keys + j]; } else // last column is blob { cell->column_array[j] = malloc(last_blob_size);; memcpy(cell->column_array[j], column_values[schema->no_primary_keys + no_clustering_keys + j], last_blob_size); } if(version != NULL) update_or_replace_vc(&(cell->version), version); } for(int i=0;ino_index_keys;i++) { if(schema->index_key_idxs[i] < no_cols) skiplist_insert(table->indexes[i], column_values[schema->index_key_idxs[i]], (WORD) row, fastrandstate); } return 0; } int table_update(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, int * col_idxs, vector_clock * version, db_table_t * table) { db_schema_t * schema = table->schema; assert(schema->no_primary_keys == 1 && "Compound primary keys unsupported for now"); assert(no_clustering_keys >= schema->min_no_clustering_keys); assert(no_cols > schema->no_primary_keys + no_clustering_keys && "Empty update"); assert(col_idxs[0] == schema->primary_key_idxs[0] && "Update must contain primary key as first element"); for(int i=0;imin_no_clustering_keys;i++) { assert(col_idxs[i+1] == schema->clustering_key_idxs[i] && "Update must contain all minimal clustering keys in the right order, right after primary key"); } db_row_t * row = NULL; snode_t * row_node = skiplist_search(table->rows, column_values[schema->primary_key_idxs[0]]); if(row_node == NULL) return -1; row = (db_row_t *) row_node->value; for(int i=0;icells, column_values[schema->clustering_key_idxs[i]]); if(row_node == NULL) return -1; row = (db_row_t *) (row_node->value); } int i=schema->no_primary_keys + no_clustering_keys; for(;icolumn_array[col_idxs[i] - schema->no_primary_keys - no_clustering_keys] = column_values[i]; } if(last_blob_size <= 0) // last column is value { row->column_array[col_idxs[i] - schema->no_primary_keys - no_clustering_keys] = column_values[i]; } else // last column is blob { row->column_array[col_idxs[i] - schema->no_primary_keys - no_clustering_keys] = malloc(last_blob_size); memcpy(row->column_array[col_idxs[i] - schema->no_primary_keys - no_clustering_keys], column_values[i], last_blob_size); } if(version != NULL) update_or_replace_vc(&(row->version), version); return 0; } db_row_t* table_search(WORD* primary_keys, db_table_t * table) { db_schema_t * schema = table->schema; assert(schema->no_primary_keys == 1 && "Compound primary keys unsupported for now"); snode_t * row_node = skiplist_search(table->rows, primary_keys[0]); if(row_node == NULL) return NULL; db_row_t* row = (db_row_t *) row_node->value; return row; } int table_range_search(WORD* start_primary_keys, WORD* end_primary_keys, snode_t** start_row, snode_t** end_row, db_table_t * table) { db_schema_t * schema = table->schema; int no_results = 0; assert(schema->no_primary_keys == 1 && "Compound primary keys unsupported for now"); if(start_primary_keys == NULL) assert(end_primary_keys == NULL); if(start_primary_keys == NULL || (start_primary_keys[0] == (WORD)LONG_MIN && end_primary_keys[0] == (WORD)(LONG_MAX - 1))) { // assert(end_primary_keys == NULL); *start_row = HEAD(table->rows); if(table->rows->no_items > 0 && (*start_row) != NULL) for(*end_row=*start_row; NEXT(*end_row) != NULL; *end_row = NEXT(*end_row)); return table->rows->no_items; } *start_row = skiplist_search_higher(table->rows, start_primary_keys[0]); if(*start_row == NULL) { *end_row = NULL; return 0; } for(*end_row = *start_row; NEXT(*end_row) != NULL && (int64_t) (*end_row)->key < (int64_t) end_primary_keys[0]; *end_row=NEXT(*end_row), no_results++); return no_results+1; } int table_verify_row_range_version(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, db_table_t * table) { int i = 0; assert(no_primary_keys == 1 && "Compound primary keys unsupported for now"); snode_t * start_row = skiplist_search_higher(table->rows, start_primary_keys[0]); for(snode_t * cell_row_node = start_row; cell_row_node != NULL && (int64_t) cell_row_node->key < (int64_t) end_primary_keys[0]; cell_row_node=NEXT(cell_row_node), i++) { db_row_t* cell_row = (db_row_t *) cell_row_node->value; // Some keys were removed from the backend since the range query happened: if(i>(no_range_results - 1)) return 1; if((int64_t) cell_row->key != range_result_keys[i]) return 1; int cmp = compare_vc(cell_row->version, range_result_versions[i]); if(cmp != 0) return cmp; } // Some extra keys were added to the backend since the range query happened: if(ischema; int no_results = 0; assert(schema->no_primary_keys == 1 && "Compound primary keys unsupported for now"); return skiplist_get_range(table->rows, start_primary_keys[0], end_primary_keys[0], (WORD**) rows, &no_results); } db_row_t* table_search_clustering(WORD* primary_keys, WORD* clustering_keys, int no_clustering_keys, db_table_t * table) { db_schema_t * schema = table->schema; assert(no_clustering_keys > 0 && "No clustering keys given"); // assert(no_clustering_keys <= schema->min_no_clustering_keys && "Too many clustering keys given"); db_row_t* row = table_search(primary_keys, table); if(row == NULL) #if (VERBOSE_BACKEND > 0) log_error("Row not found by primary key %" PRId64 "!", (int64_t) primary_keys[0]); #endif return NULL; for(int i=0;icells, clustering_keys[i]); if(row_node != NULL) { row = (db_row_t *) row_node->value; } else { #if (VERBOSE_BACKEND > 0) log_error("Row not found by clustering key %d / %" PRId64 "!", i, (int64_t) clustering_keys[i]); #endif return NULL; } } return row; } int table_verify_cell_version(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, vector_clock * version, db_table_t * table) { assert(no_primary_keys == 1); snode_t * row_node = skiplist_search(table->rows, primary_keys[0]); if(row_node == NULL) return DB_ERR_NO_QUEUE; db_row_t* row = (db_row_t *) row_node->value; for(int i=0;icells, clustering_keys[i]); if(row_node == NULL) return DB_ERR_NO_QUEUE; row = (db_row_t *) row_node->value; } return compare_vc(version, row->version); } int table_range_search_clustering(WORD* primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, snode_t** start_row, snode_t** end_row, db_table_t * table) { db_schema_t * schema = table->schema; assert(no_clustering_keys > 0 && "No clustering keys given"); // assert(no_clustering_keys <= schema->min_no_clustering_keys && "Too many clustering keys given"); db_row_t* row = table_search(primary_keys, table); if(row == NULL) return 0; for(int i=0;icells, start_clustering_keys[i]); if(row_node != NULL) { row = (db_row_t *) row_node->value; } else { return -1; } } *start_row = skiplist_search_higher(row->cells, start_clustering_keys[no_clustering_keys-1]); if(*start_row == NULL) { *end_row = NULL; return 0; } int no_results = 0; for(*end_row = *start_row; NEXT(*end_row) != NULL && (int64_t) (*end_row)->key < (int64_t) end_clustering_keys[no_clustering_keys-1]; *end_row=NEXT(*end_row), no_results++); return no_results+1; } void print_long_db(db_t * db) { log_info("DB: [%d tables]", db->tables->no_items); for(snode_t * node = HEAD(db->tables);node!=NULL;node=NEXT(node)) print_long_table((db_table_t *) node->value); } void print_long_table(db_table_t * table) { log_info("DB_TABLE: %" PRId64 " [%d rows]", (int64_t) table->table_key, table->rows->no_items); for(snode_t * node = HEAD(table->rows);node!=NULL;node=NEXT(node)) print_long_row((db_row_t*) node->value); } void print_long_row(db_row_t* row) { char to_string[MAX_PRINT_BUFF]; int len = 0; long_row_to_string(row, (char *) to_string, &len, (char *) to_string); log_info("DB_ROW [%d cells]: %s", (row->cells != NULL)?(row->cells->no_items):(0), to_string); } void long_row_to_string(db_row_t* row, char * to_string, int * len, char * orig_offset) { #define PRINT_BLOBS 1 #define PRINT_BLOBS_AS_LONG 1 sprintf(to_string, "{ %" PRId64 ", ", (int64_t) row->key); if(row->cells != NULL) { assert(row->no_columns == 0); for(snode_t* node = HEAD(row->cells); node != NULL; node = NEXT(node)) { if(to_string + strlen(to_string) - orig_offset > MAX_PRINT_BUFF - 10) { sprintf(to_string + strlen(to_string), ".."); break; } db_row_t * subrow = (db_row_t *) node->value; long_row_to_string(subrow, to_string + strlen(to_string), len, orig_offset); } } if(row->no_columns > 0) { sprintf(to_string + strlen(to_string), "[ "); for(int i=0; ino_columns; i++) { if(to_string + strlen(to_string) - orig_offset > MAX_PRINT_BUFF - 10) { sprintf(to_string + strlen(to_string), ".."); break; } #if (PRINT_BLOBS > 0) if(i<(row->no_columns - 1) || row->last_blob_size <= 0) { sprintf(to_string + strlen(to_string), "%" PRId64 ", ", (int64_t) row->column_array[i]); } else { #if (PRINT_BLOBS_AS_LONG > 0) for(int bi=0;bi < row->last_blob_size / sizeof(long);bi++) sprintf(to_string + strlen(to_string), "%lu ", *((unsigned long *) row->column_array[i] + bi)); #else sprintf(to_string + strlen(to_string), "%s, ", (char *) row->column_array[i]); #endif } #else sprintf(to_string + strlen(to_string), "%" PRId64 ", ", (int64_t) row->column_array[i]); #endif } sprintf(to_string + strlen(to_string), " ]"); } sprintf(to_string + strlen(to_string), "}, "); *len = strlen(to_string); } int table_verify_cell_range_version(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, db_table_t * table) { assert(no_primary_keys == 1); snode_t * row_node = skiplist_search(table->rows, primary_keys[0]); if(row_node == NULL) return -1; db_row_t* row = (db_row_t *) row_node->value; for(int i=0;icells, start_clustering_keys[i]); if(row_node == NULL) return -1; db_row_t* row = (db_row_t *) row_node->value; } snode_t * start_row = skiplist_search_higher(row->cells, start_clustering_keys[no_clustering_keys-1]); int i = 0; for(snode_t * cell_row_node = start_row; cell_row_node != NULL && (int64_t) cell_row_node->key < (int64_t) end_clustering_keys[no_clustering_keys-1]; cell_row_node=NEXT(cell_row_node), i++) { db_row_t* cell_row = (db_row_t *) cell_row_node->value; // Some keys were removed from the backend since the range query happened: if(i>(no_range_results - 1)) return 1; if((int64_t) cell_row->key != range_result_keys[i]) return 1; int cmp = compare_vc(cell_row->version, range_result_versions[i]); if(cmp != 0) return cmp; } // Some extra keys were added to the backend since the range query happened: if(ischema; assert(no_columns > 0 && "No column indexes given"); assert(no_clustering_keys >= schema->min_no_clustering_keys && "Not enough clustering keys given"); db_row_t* row = table_search_clustering(primary_keys, clustering_keys, no_clustering_keys, table); if(row == NULL) return NULL; assert(row->column_array != NULL && row->no_columns > 0); WORD* results = (WORD*) malloc(no_columns * sizeof(WORD)); for(int i=0;ino_columns + schema->no_primary_keys + no_clustering_keys && "Column index doesn't exist in backend (DB corrupted?)"); if(column_idxs[i] < schema->no_primary_keys) results[i] = primary_keys[column_idxs[i]]; else if(column_idxs[i] < schema->no_primary_keys + no_clustering_keys) results[i] = clustering_keys[column_idxs[i] - schema->no_primary_keys]; else results[i] = row->column_array[column_idxs[i] - schema->no_primary_keys - no_clustering_keys]; } return results; } db_row_t* table_search_index(WORD index_key, int idx_idx, db_table_t * table) { db_schema_t * schema = table->schema; assert(idx_idx <= schema->no_index_keys == 1 && "Index index out of range"); snode_t * row_node = skiplist_search(table->indexes[idx_idx], index_key); if(row_node != NULL) { return (db_row_t *) (row_node->value); } else { return NULL; } } int table_verify_index_version(WORD index_key, int idx_idx, vector_clock * version, db_table_t * table) { db_schema_t * schema = table->schema; assert(idx_idx <= schema->no_index_keys == 1 && "Index index out of range"); snode_t * row_node = skiplist_search(table->indexes[idx_idx], index_key); if(row_node == NULL) return 1; return compare_vc(version, ((db_row_t *) (row_node->value))->version); } int table_range_search_index(int idx_idx, WORD start_idx_key, WORD end_idx_key, snode_t** start_row, snode_t** end_row, db_table_t * table) { db_schema_t * schema = table->schema; int no_results = 0; assert(idx_idx <= schema->no_index_keys == 1 && "Index index out of range"); *start_row = skiplist_search_higher(table->indexes[idx_idx], start_idx_key); for(*end_row = *start_row; (*end_row != NULL) && ((int64_t) (*end_row)->key < (int64_t) end_idx_key); *end_row=NEXT(*end_row), no_results++); return no_results+1; } int table_verify_index_range_version(int idx_idx, WORD start_idx_key, WORD end_idx_key, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, db_table_t * table) { db_schema_t * schema = table->schema; int i = 0; assert(idx_idx <= schema->no_index_keys == 1 && "Index index out of range"); snode_t * start_row = skiplist_search_higher(table->indexes[idx_idx], start_idx_key); for(snode_t * cell_row_node = start_row; cell_row_node != NULL && (int64_t) cell_row_node->key < (int64_t) end_idx_key; cell_row_node=NEXT(cell_row_node), i++) { db_row_t* cell_row = (db_row_t *) cell_row_node->value; // Some keys were removed from the backend since the range query happened: if(i>(no_range_results - 1)) return 1; if((int64_t) cell_row->key != range_result_keys[i]) return 1; int cmp = compare_vc(cell_row->version, range_result_versions[i]); if(cmp != 0) return cmp; } // Some extra keys were added to the backend since the range query happened: if(irows, primary_keys[0])); snode_t * exists = skiplist_search(table->row_tombstones, primary_keys[0]); if(exists != NULL) skiplist_insert(table->row_tombstones, primary_keys[0], (version != NULL)? copy_vc(version) : NULL, fastrandstate); if(row != NULL) { free_db_row(row, table->schema, db); } else { log_warn("table_delete_row(): Row with pk %" PRId64 " doesn't exist!", (int64_t) primary_keys[0]); } return row == NULL; } int table_delete_by_index(WORD index_key, int idx_idx, db_table_t * table) { db_schema_t * schema = table->schema; assert(idx_idx <= schema->no_index_keys == 1 && "Index index out of range"); db_row_t* row = (db_row_t *) (skiplist_delete(table->indexes[idx_idx], index_key)); // TO DO: Re-enable this after enhancing indexes: // if(row != NULL) // free_db_row(row, table->schema); return row == NULL; } // DB API: int db_insert_transactional(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, vector_clock * version, WORD table_key, db_t * db, unsigned int * fastrandstate) { #if (VERBOSE_BACKEND > 0) log_info("BACKEND: db_insert_transactional: Attempting to insert %d total columns into backend:", min_no_cols); for(int i=0;itables, table_key); if(node == NULL) return -1; db_table_t * table = (db_table_t *) (node->value); return table_insert(column_values, no_cols, no_clustering_keys, last_blob_size, version, table, fastrandstate); } int db_insert(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, WORD table_key, db_t * db, unsigned int * fastrandstate) { return db_insert_transactional(column_values, no_cols, no_clustering_keys, last_blob_size, NULL, table_key, db, fastrandstate); } int db_update_transactional(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, int * col_idxs, vector_clock * version, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return -1; db_table_t * table = (db_table_t *) (node->value); return table_update(column_values, no_cols, no_clustering_keys, last_blob_size, col_idxs, version, table); } int db_update(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, int * col_idxs, WORD table_key, db_t * db) { return db_update_transactional(column_values, no_cols, no_clustering_keys, last_blob_size, col_idxs, NULL, table_key, db); } db_row_t* db_search(WORD* primary_keys, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return NULL; db_table_t * table = (db_table_t *) (node->value); return table_search(primary_keys, table); } int db_range_search(WORD* start_primary_keys, WORD* end_primary_keys, snode_t** start_row, snode_t** end_row, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return -1; db_table_t * table = (db_table_t *) (node->value); return table_range_search(start_primary_keys, end_primary_keys, start_row, end_row, table); } int db_verify_row_range_version(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, WORD table_key, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return -1; db_table_t * table = (db_table_t *) (node->value); return table_verify_row_range_version(start_primary_keys, end_primary_keys, no_primary_keys, range_result_keys, range_result_versions, no_range_results, table); } int db_range_search_copy(WORD* start_primary_keys, WORD* end_primary_keys, db_row_t** rows, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return -1; db_table_t * table = (db_table_t *) (node->value); return table_range_search_copy(start_primary_keys, end_primary_keys, rows, table); } db_row_t* db_search_clustering(WORD* primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return NULL; db_table_t * table = (db_table_t *) (node->value); return table_search_clustering(primary_keys, clustering_keys, no_clustering_keys, table); } int db_verify_cell_version(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD table_key, vector_clock * version, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return DB_ERR_NO_TABLE; db_table_t * table = (db_table_t *) (node->value); return table_verify_cell_version(primary_keys, no_primary_keys, clustering_keys, no_clustering_keys, version, table); } int db_range_search_clustering(WORD* primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, snode_t** start_row, snode_t** end_row, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return -1; db_table_t * table = (db_table_t *) (node->value); return table_range_search_clustering(primary_keys, start_clustering_keys, end_clustering_keys, no_clustering_keys, start_row, end_row, table); } int db_verify_cell_range_version(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, WORD table_key, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return -1; db_table_t * table = (db_table_t *) (node->value); return table_verify_cell_range_version(primary_keys, no_primary_keys, start_clustering_keys, end_clustering_keys, no_clustering_keys, range_result_keys, range_result_versions, no_range_results, table); } WORD* db_search_columns(WORD* primary_keys, WORD* clustering_keys, int no_clustering_keys, int* column_idxs, int no_columns, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return NULL; db_table_t * table = (db_table_t *) (node->value); return table_search_columns(primary_keys, clustering_keys, no_clustering_keys, column_idxs, no_columns, table); } db_row_t* db_search_index(WORD index_key, int idx_idx, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return NULL; db_table_t * table = (db_table_t *) (node->value); return table_search_index(index_key, idx_idx, table); } int db_verify_index_version(WORD index_key, int idx_idx, WORD table_key, vector_clock * version, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return -2; db_table_t * table = (db_table_t *) (node->value); return table_verify_index_version(index_key, idx_idx, version, table); } int db_range_search_index(int idx_idx, WORD start_idx_key, WORD end_idx_key, snode_t** start_row, snode_t** end_row, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return -1; db_table_t * table = (db_table_t *) (node->value); return table_range_search_index(idx_idx, start_idx_key, end_idx_key, start_row, end_row, table); } int db_verify_index_range_version(int idx_idx, WORD start_idx_key, WORD end_idx_key, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return -1; db_table_t * table = (db_table_t *) (node->value); return table_verify_index_range_version(idx_idx, start_idx_key, end_idx_key, range_result_keys, range_result_versions, no_range_results, table); } int db_delete_row_transactional(WORD* primary_keys, vector_clock * version, WORD table_key, db_t * db, unsigned int * fastrandstate) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) { log_warn("db_delete_row(): Table with pk %" PRId64 " doesn't exist!", (int64_t) table_key); return -1; } db_table_t * table = (db_table_t *) (node->value); return table_delete_row(primary_keys, version, table, db, fastrandstate); } int db_delete_row(WORD* primary_keys, WORD table_key, db_t * db, unsigned int * fastrandstate) { return db_delete_row_transactional(primary_keys, NULL, table_key, db, fastrandstate); } int db_delete_by_index(WORD index_key, int idx_idx, WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return -1; db_table_t * table = (db_table_t *) (node->value); return table_delete_by_index(index_key, idx_idx, table); } ================================================ FILE: backend/db.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * db.h * Author: aagapi */ #ifndef BACKEND_DB_H_ #define BACKEND_DB_H_ #include "common.h" #include "skiplist.h" #include "fastrand.h" #include "failure_detector/vector_clock.h" #include "hash_ring.h" // High level API: // Query types: #define QUERY_TYPE_UPDATE 0 #define QUERY_TYPE_DELETE 1 #define QUERY_TYPE_READ_COLS 2 #define QUERY_TYPE_READ_CELL 3 #define QUERY_TYPE_READ_CELL_RANGE 4 #define QUERY_TYPE_READ_ROW 5 #define QUERY_TYPE_READ_ROW_RANGE 6 #define QUERY_TYPE_READ_INDEX 7 #define QUERY_TYPE_READ_INDEX_RANGE 8 #define QUERY_TYPE_ENQUEUE 9 #define QUERY_TYPE_READ_QUEUE 10 #define QUERY_TYPE_CONSUME_QUEUE 11 #define QUERY_TYPE_CREATE_QUEUE 12 #define QUERY_TYPE_DELETE_QUEUE 13 #define QUERY_TYPE_SUBSCRIBE_QUEUE 14 #define QUERY_TYPE_UNSUBSCRIBE_QUEUE 15 #define QUERY_TYPE_READ_QUEUE_RESPONSE 16 #define QUERY_TYPE_QUEUE_NOTIFICATION 17 #define QUERY_TYPE_ADD_QUEUE_TO_GROUP 18 #define QUERY_TYPE_REMOVE_QUEUE_FROM_GROUP 19 // Return statuses: #define DB_ERR_NO_TABLE -1 #define DB_ERR_NO_QUEUE -2 #define DB_ERR_NO_CONSUMER -3 #define DB_ERR_QUEUE_COMPLETE -4 #define DB_ERR_QUEUE_HEAD_INVALID -5 #define DB_ERR_DUPLICATE_QUEUE -6 #define DB_ERR_DUPLICATE_CONSUMER -7 #define VAL_STATUS_ABORT_SCHEMA -8 #define QUEUE_STATUS_READ_INCOMPLETE 0 #define QUEUE_STATUS_READ_COMPLETE 1 #define QUEUE_NOTIF_ENQUEUED 0 #define QUEUE_NOTIF_DELETED 1 #define VERBOSE_BACKEND 0 #define MAX_PRINT_BUFF 128 * 1024 #define MULTI_THREADED 0 #define ENABLE_AUTO_QUEUE_GROUP_SUBSCRIPTIONS 1 typedef struct db_schema { int * col_types; int min_no_cols; int * primary_key_idxs; int no_primary_keys; int * clustering_key_idxs; int min_no_clustering_keys; int * index_key_idxs; int no_index_keys; } db_schema_t; typedef struct db_table { WORD table_key; db_schema_t * schema; skiplist_t * rows; skiplist_t ** indexes; skiplist_t * queues; skiplist_t * row_tombstones; pthread_mutex_t* lock; } db_table_t; // Cells: typedef struct db_cell { WORD key; skiplist_t * cells; WORD * column_array; int no_columns; int last_blob_size; // Queue metadata: skiplist_t * consumer_state; WORD group_subscriptions; // This field is either a group_state * or a skiplist_t * of group_states (if db->queue_group_replication_factor > 1) int64_t no_entries; pthread_mutex_t* enqueue_lock; pthread_mutex_t* read_lock; pthread_mutex_t* subscribe_lock; vector_clock * version; struct db_cell_t * _next; } db_cell_t; typedef db_cell_t db_row_t; typedef struct db { skiplist_t * tables; skiplist_t * txn_state; hash_ring * queue_groups; int queue_group_replication_factor; int enable_auto_queue_group_subscriptions; #if (MULTI_THREADED == 1) pthread_mutex_t* txn_state_lock; #endif } db_t; // DB high level API: // DB, schema and table manipulation: db_t * get_db(); int db_delete_db(db_t * db); int db_dump_db(db_t * db); db_schema_t* db_create_schema(int * col_types, int no_cols, int * primary_key_idxs, int no_primary_keys, int * clustering_key_idxs, int no_clustering_keys, int * index_key_idxs, int no_index_keys); void free_schema(db_schema_t * schema); int db_create_table(WORD table_key, db_schema_t* schema, db_t * db, unsigned int * fastrandstate); int db_create_index(int new_index, WORD table_key, db_t * db, unsigned int * fastrandstate); int db_delete_table(WORD table_key, db_t * db); // DB queries: int db_insert(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, WORD table_key, db_t * db, unsigned int * fastrandstate); int db_insert_transactional(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, vector_clock * version, WORD table_key, db_t * db, unsigned int * fastrandstate); int db_update(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, int * col_idxs, WORD table_key, db_t * db); int db_update_transactional(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, int * col_idxs, vector_clock * version, WORD table_key, db_t * db); db_row_t* db_search(WORD* primary_keys, WORD table_key, db_t * db); int db_range_search(WORD* start_primary_keys, WORD* end_primary_keys, snode_t** start_row, snode_t** end_row, WORD table_key, db_t * db); int db_range_search_copy(WORD* start_primary_keys, WORD* end_primary_keys, db_row_t** rows, WORD table_key, db_t * db); db_row_t* db_search_clustering(WORD* primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD table_key, db_t * db); int db_range_search_clustering(WORD* primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, snode_t** start_row, snode_t** end_row, WORD table_key, db_t * db); WORD* db_search_columns(WORD* primary_keys, WORD* clustering_keys, int no_clustering_keys, int* column_idxs, int no_columns, WORD table_key, db_t * db); db_row_t* db_search_index(WORD index_key, int idx_idx, WORD table_key, db_t * db); int db_range_search_index(int idx_idx, WORD start_idx_key, WORD end_idx_key, snode_t** start_row, snode_t** end_row, WORD table_key, db_t * db); int db_delete_row(WORD* primary_keys, WORD table_key, db_t * db, unsigned int * fastrandstate); int db_delete_row_transactional(WORD* primary_keys, vector_clock * version, WORD table_key, db_t * db, unsigned int * fastrandstate); // TO DO: int db_delete_cell(WORD* keys, int no_primary_keys, int no_clustering_keys, WORD table_key, db_t * db); int db_delete_by_index(WORD index_key, int idx_idx, WORD table_key, db_t * db); int db_verify_cell_version(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD table_key, vector_clock * version, db_t * db); int db_verify_row_range_version(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, WORD table_key, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, db_t * db); int db_verify_cell_range_version(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, WORD table_key, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, db_t * db); int db_verify_index_version(WORD index_key, int idx_idx, WORD table_key, vector_clock * version, db_t * db); int db_verify_index_range_version(int idx_idx, WORD start_idx_key, WORD end_idx_key, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, WORD table_key, db_t * db); // Lower level API: db_row_t * create_db_row_schemaless(WORD * column_values, int * primary_key_idxs, int no_primary_keys, int * clustering_key_idxs, int no_clustering_keys, int no_schema_clustering_keys, int no_cols, size_t last_blob_size, unsigned int * fastrandstate); // Assumes key indexes are in order (rartition keys, followed by clustering keys, followed by columns). Also assumes a single partition key db_row_t * create_db_row_schemaless2(WORD * keys, int no_keys, WORD * cols, int no_cols, WORD last_blob, size_t last_blob_size, unsigned int * fastrandstate); void free_db_row(db_row_t * row, db_schema_t * schema, db_t * db); void long_row_to_string(db_row_t* row, char * to_string, int * len, char * orig_offset); void print_long_db(db_t * db); void print_long_table(db_table_t * table); void print_long_row(db_row_t* row); int table_insert(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, vector_clock * version, db_table_t * table, unsigned int * fastrandstate); int table_update(WORD * column_values, int no_cols, int no_clustering_keys, size_t last_blob_size, int * col_idxs, vector_clock * version, db_table_t * table); db_row_t* table_search(WORD* primary_keys, db_table_t * table); int table_range_search(WORD* start_primary_keys, WORD* end_primary_keys, snode_t** start_row, snode_t** end_row, db_table_t * table); int table_range_search_copy(WORD* start_primary_keys, WORD* end_primary_keys, db_row_t** rows, db_table_t * table); db_row_t* table_search_clustering(WORD* primary_keys, WORD* clustering_keys, int no_clustering_keys, db_table_t * table); int table_range_search_clustering(WORD* primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, snode_t** start_row, snode_t** end_row, db_table_t * table); WORD* table_search_columns(WORD* primary_keys, WORD* clustering_keys, int no_clustering_keys, int* column_idxs, int no_columns, db_table_t * table); db_row_t* table_search_index(WORD index_key, int idx_idx, db_table_t * table); int table_range_search_index(int idx_idx, WORD start_idx_key, WORD end_idx_key, snode_t** start_row, snode_t** end_row, db_table_t * table); int table_delete_row(WORD* primary_keys, vector_clock * version, db_table_t * table, db_t * db, unsigned int * fastrandstate); int table_delete_by_index(WORD index_key, int idx_idx, db_table_t * table); int table_verify_cell_version(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, vector_clock * version, db_table_t * table); int table_verify_row_range_version(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, db_table_t * table); int table_verify_cell_range_version(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, db_table_t * table); int table_verify_index_version(WORD index_key, int idx_idx, vector_clock * version, db_table_t * table); int table_verify_index_range_version(int idx_idx, WORD start_idx_key, WORD end_idx_key, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, db_table_t * table); #endif /* BACKEND_DB_H_ */ ================================================ FILE: backend/db_client_api.h ================================================ /* * db_client_api.h * * Author: aagapi */ #ifndef BACKEND_DB_CLIENT_API_H_ #define BACKEND_DB_CLIENT_API_H_ #endif /* BACKEND_DB_CLIENT_API_H_ */ ================================================ FILE: backend/failure_detector/cells.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * cells.c * * Author: aagapi */ #include "cells.h" #include "../log.h" #include #include #include #include #include // Vector Clock serialization: int serialize_vc(vector_clock * vc, void ** buf, unsigned * len) { VectorClockMessage msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&msg, vc); *len = vector_clock_message__get_packed_size (&msg); *buf = malloc (*len); vector_clock_message__pack (&msg, *buf); free_vc_msg(&msg); return 0; } int deserialize_vc(void * buf, unsigned msg_len, vector_clock ** vc) { VectorClockMessage * msg = vector_clock_message__unpack (NULL, msg_len, buf); if (msg == NULL) { // Something failed log_error("error unpacking vector_clock message"); return 1; } assert(msg->n_ids == msg->n_counters); *vc = init_vc_from_msg(msg); vector_clock_message__free_unpacked(msg, NULL); return 0; } // Cell Address: cell_address * init_cell_address(int64_t table_key, int64_t * keys, int no_keys) { cell_address * ca = (cell_address *) malloc(sizeof(cell_address)); ca->table_key = table_key; ca->keys = keys; ca->no_keys = no_keys; return ca; } cell_address * init_cell_address_copy(int64_t table_key, int64_t * keys, int no_keys) { cell_address * ca = (cell_address *) malloc(sizeof(cell_address)); ca->table_key = table_key; ca->no_keys = no_keys; ca->keys = (int64_t *) malloc(no_keys * sizeof(int64_t)); for(int i=0;ikeys[i] = keys[i]; return ca; } cell_address * init_cell_address_copy2(int64_t table_key, int64_t * primary_keys, int no_primary_keys, int64_t * clustering_keys, int no_clustering_keys) { int i = 0; cell_address * c = (cell_address *) malloc(sizeof(cell_address)); c->table_key = (int64_t) table_key; c->no_keys = no_primary_keys + no_clustering_keys; assert(c->no_keys > 0); c->keys = (int64_t *) malloc(c->no_keys * sizeof(int64_t)); for(;ikeys[i] = (int64_t) primary_keys[i]; for(;ino_keys;i++) c->keys[i] = (int64_t) clustering_keys[i-no_primary_keys]; return c; } cell_address * init_cell_address_single_key_copy(int64_t table_key, int64_t key) { cell_address * ca = (cell_address *) malloc(sizeof(cell_address)); ca->table_key = table_key; ca->no_keys = 1; ca->keys = (int64_t *) malloc(sizeof(int64_t)); ca->keys[0] = key; return ca; } int copy_cell_address(cell_address * ca, int64_t table_key, int64_t * keys, int no_keys) { ca->table_key = table_key; ca->keys = keys; ca->no_keys = no_keys; return 0; } void free_cell_address(cell_address * ca) { free(ca->keys); free(ca); } void init_cell_address_msg(CellAddressMessage * msg, cell_address * ca) { msg->table_key = ca->table_key; msg->n_keys = ca->no_keys; msg->keys = (int64_t *) malloc(ca->no_keys * sizeof(int64_t)); for(int i=0;ino_keys;i++) msg->keys[i] = ca->keys[i]; } cell_address * init_cell_address_from_msg(CellAddressMessage * msg) { return init_cell_address_copy(msg->table_key, msg->keys, msg->n_keys); } void free_cell_address_msg(CellAddressMessage * msg) { free(msg->keys); } int serialize_cell_address(cell_address * ca, void ** buf, unsigned * len) { CellAddressMessage msg = CELL_ADDRESS_MESSAGE__INIT; init_cell_address_msg(&msg, ca); *len = cell_address_message__get_packed_size (&msg); *buf = malloc (*len); cell_address_message__pack (&msg, *buf); free_cell_address_msg(&msg); return 0; } int deserialize_cell_address(void * buf, unsigned msg_len, cell_address ** ca) { CellAddressMessage * msg = cell_address_message__unpack (NULL, msg_len, buf); if (msg == NULL) { log_error("error unpacking cell_address message"); return 1; } *ca = init_cell_address_from_msg(msg); cell_address_message__free_unpacked(msg, NULL); return 0; } int equals_cell_address(cell_address * ca1, cell_address * ca2) { if((ca1 != NULL && ca2 == NULL) || (ca1 == NULL && ca2 != NULL)) return 0; if(ca1->table_key != ca2->table_key || ca1->no_keys != ca2->no_keys) return 0; for(int i=0;ino_keys;i++) if(ca1->keys[i] != ca2->keys[i]) return 0; return 1; } char * to_string_cell_address(cell_address * ca, char * msg_buff) { char * crt_ptr = msg_buff; sprintf(crt_ptr, "CellAddress(table_key=%" PRId64 ", keys={", ca->table_key); crt_ptr += strlen(crt_ptr); for(int i=0;ino_keys;i++) { sprintf(crt_ptr, "%" PRId64 ", ", ca->keys[i]); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, "})"); return msg_buff; } // Cell: cell * init_cell(int64_t table_key, int64_t * keys, int no_keys, int64_t * columns, int no_columns, WORD last_blob, size_t last_blob_size, vector_clock * version) { cell * ca = (cell *) malloc(sizeof(cell)); ca->table_key = table_key; ca->keys = keys; ca->columns = columns; ca->no_keys = no_keys; ca->no_columns = no_columns; ca->last_blob = last_blob; ca->last_blob_size = last_blob_size; ca->version = version; return ca; } void copy_cell(cell * ca, int64_t table_key, int64_t * keys, int no_keys, int64_t * columns, int no_columns, WORD last_blob, size_t last_blob_size, vector_clock * version) { ca->table_key = table_key; ca->no_keys = no_keys; ca->keys = (int64_t *) malloc(no_keys * sizeof(int64_t)); for(int i=0;ikeys[i] = keys[i]; assert(last_blob == NULL || last_blob_size > 0); ca->no_columns = no_columns; ca->columns = (int64_t *) malloc(no_columns * sizeof(int64_t)); for(int i=0;icolumns[i] = columns[i]; ca->last_blob_size = last_blob_size; if(last_blob != NULL) { ca->last_blob = malloc(last_blob_size); memcpy(ca->last_blob, last_blob, last_blob_size); } else { ca->last_blob = NULL; } if(version != NULL) ca->version = copy_vc(version); else ca->version = NULL; } cell * init_cell_copy(int64_t table_key, int64_t * keys, int no_keys, int64_t * columns, int no_columns, WORD last_blob, size_t last_blob_size, vector_clock * version) { cell * ca = (cell *) malloc(sizeof(cell)); copy_cell(ca, table_key, keys, no_keys, columns, no_columns, last_blob, last_blob_size, version); return ca; } cell_address * get_cell_address(cell * c) { return init_cell_address_copy(c->table_key, c->keys, c->no_keys); } void free_cell_ptrs(cell * ca) { if(ca->keys != NULL) free(ca->keys); if(ca->columns != NULL) { free(ca->columns); } if(ca->last_blob != NULL) { assert(ca->last_blob_size > 0); free(ca->last_blob); } free_vc(ca->version); } void free_cell(cell * ca) { free_cell_ptrs(ca); free(ca); } void init_cell_msg(VersionedCellMessage * msg, cell * ca, VectorClockMessage * vc_msg) { msg->table_key = ca->table_key; msg->n_keys = ca->no_keys; msg->keys = (int64_t *) malloc(ca->no_keys * sizeof(int64_t)); for(int i=0;ino_keys;i++) msg->keys[i] = ca->keys[i]; msg->n_columns = ca->no_columns; if(ca->no_columns > 0) msg->columns = (int64_t *) malloc(ca->no_columns * sizeof(int64_t)); for(int i=0;ino_columns;i++) msg->columns[i] = ca->columns[i]; if(ca->last_blob != NULL) { assert(ca->last_blob_size > 0); msg->blob.len = ca->last_blob_size; msg->blob.data = malloc(ca->last_blob_size); memcpy(msg->blob.data, ca->last_blob, ca->last_blob_size); } else { msg->blob.data = NULL; msg->blob.len = 0; } if(ca->version != NULL) { init_vc_msg(vc_msg, ca->version); msg->version = vc_msg; } else { // msg->version = NULL; } } cell * copy_cell_from_msg(cell * c, VersionedCellMessage * msg) { copy_cell(c, msg->table_key, msg->keys, msg->n_keys, msg->columns, msg->n_columns, msg->blob.data, msg->blob.len, (msg->version != NULL)?(init_vc_from_msg(msg->version)):(NULL)); return c; } cell * init_cell_from_msg(VersionedCellMessage * msg) { if(msg == NULL) return NULL; vector_clock * vc = NULL; if(msg->version != NULL) vc = init_vc_from_msg(msg->version); cell * c = init_cell_copy(msg->table_key, msg->keys, msg->n_keys, msg->columns, msg->n_columns, msg->blob.data, msg->blob.len, vc); return c; } void free_cell_msg(VersionedCellMessage * msg) { if(msg->keys != NULL) free(msg->keys); if(msg->columns != NULL) free(msg->columns); if(msg->blob.data != NULL && msg->blob.len > 0) free(msg->blob.data); if(msg->version != NULL) free_vc_msg(msg->version); } int serialize_cell(cell * ca, void ** buf, unsigned * len) { VersionedCellMessage msg = VERSIONED_CELL_MESSAGE__INIT; VectorClockMessage vc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_cell_msg(&msg, ca, &vc_msg); *len = versioned_cell_message__get_packed_size (&msg); *buf = malloc (*len); versioned_cell_message__pack (&msg, *buf); free_cell_msg(&msg); return 0; } int deserialize_cell(void * buf, unsigned msg_len, cell ** ca) { VersionedCellMessage * msg = versioned_cell_message__unpack (NULL, msg_len, buf); if (msg == NULL) { log_error("error unpacking cell message"); return 1; } *ca = init_cell_from_msg(msg); versioned_cell_message__free_unpacked(msg, NULL); return 0; } int equals_cell(cell * ca1, cell * ca2) { if(ca1 == NULL && ca2 == NULL) return 1; if(ca1 != NULL && ca2 == NULL) return 0; if(ca1 == NULL && ca2 != NULL) return 0; if(ca1->table_key != ca2->table_key || ca1->no_keys != ca2->no_keys) return 0; for(int i=0;ino_keys;i++) if(ca1->keys[i] != ca2->keys[i]) return 0; for(int i=0;ino_columns;i++) if(ca1->columns[i] != ca2->columns[i]) return 0; if(ca1->last_blob_size != ca2->last_blob_size) return 0; if(ca1->last_blob_size > 0) { assert(ca1->last_blob != NULL && ca2->last_blob != NULL); if(memcmp(ca1->last_blob, ca2->last_blob, ca1->last_blob_size) != 0) return 0; } if(compare_vc(ca1->version, ca2->version)) return 0; return 1; } char * to_string_cell(cell * ca, char * msg_buff) { char * crt_ptr = msg_buff; sprintf(crt_ptr, "Cell(table_key=%" PRId64 ", keys={", ca->table_key); crt_ptr += strlen(crt_ptr); for(int i=0;ino_keys;i++) { sprintf(crt_ptr, "%" PRId64 ", ", ca->keys[i]); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, "}, columns={"); crt_ptr += strlen(crt_ptr); for(int i=0;ino_columns;i++) { sprintf(crt_ptr, "%" PRId64 ", ", ca->columns[i]); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, "}, version="); crt_ptr += strlen(crt_ptr); if(ca->version != NULL) { to_string_vc(ca->version, crt_ptr); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, ")"); return msg_buff; } ================================================ FILE: backend/failure_detector/cells.h ================================================ /* * cells.h * * Author: aagapi */ #ifndef BACKEND_FAILURE_DETECTOR_CELLS_H_ #define BACKEND_FAILURE_DETECTOR_CELLS_H_ #include "db_messages.pb-c.h" #include "vector_clock.h" typedef void * WORD; typedef struct cell_address { int64_t table_key; int64_t * keys; int no_keys; } cell_address; cell_address * init_cell_address(int64_t table_key, int64_t * keys, int no_keys); cell_address * init_cell_address_copy(int64_t table_key, int64_t * keys, int no_keys); cell_address * init_cell_address_copy2(int64_t table_key, int64_t * primary_keys, int no_primary_keys, int64_t * clustering_keys, int no_clustering_keys); cell_address * init_cell_address_single_key_copy(int64_t table_key, int64_t key); int copy_cell_address(cell_address * ca, int64_t table_key, int64_t * keys, int no_keys); void free_cell_address(cell_address * ca); void init_cell_address_msg(CellAddressMessage * msg, cell_address * ca); cell_address * init_cell_address_from_msg(CellAddressMessage * msg); void free_cell_address_msg(CellAddressMessage * msg); int serialize_cell_address(cell_address * ca, void ** buf, unsigned * len); int deserialize_cell_address(void * buf, unsigned msg_len, cell_address ** ca); int equals_cell_address(cell_address * ca1, cell_address * ca2); char * to_string_cell_address(cell_address * ca, char * msg_buff); typedef struct cell { int64_t table_key; int64_t * keys; int no_keys; int64_t * columns; int no_columns; WORD last_blob; size_t last_blob_size; vector_clock * version; } cell; cell * init_cell(int64_t table_key, int64_t * keys, int no_keys, int64_t * columns, int no_columns, WORD last_blob, size_t last_blob_size, vector_clock * version); cell * init_cell_copy(int64_t table_key, int64_t * keys, int no_keys, int64_t * columns, int no_columns, WORD last_blob, size_t last_blob_size, vector_clock * version); void copy_cell(cell * ca, int64_t table_key, int64_t * keys, int no_keys, int64_t * columns, int no_columns, WORD last_blob, size_t last_blob_size, vector_clock * version); cell_address * get_cell_address(cell * c); cell * init_cell_from_msg(VersionedCellMessage * msg); cell * copy_cell_from_msg(cell * c, VersionedCellMessage * msg); void free_cell(cell * ca); void free_cell_ptrs(cell * ca); void init_cell_msg(VersionedCellMessage * msg, cell * ca, VectorClockMessage * vc_msg); void free_cell_msg(VersionedCellMessage * msg); int serialize_cell(cell * ca, void ** buf, unsigned * len); int deserialize_cell(void * buf, unsigned msg_len, cell ** ca); int equals_cell(cell * ca1, cell * ca2); char * to_string_cell(cell * ca, char * msg_buff); int serialize_vc(vector_clock * vc, void ** buf, unsigned * len); int deserialize_vc(void * buf, unsigned msg_len, vector_clock ** vc); #endif /* BACKEND_FAILURE_DETECTOR_CELLS_H_ */ ================================================ FILE: backend/failure_detector/db_messages.pb-c.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: backend/failure_detector/db_messages.proto */ /* Do not generate deprecated warnings for self */ #ifndef PROTOBUF_C__NO_DEPRECATED #define PROTOBUF_C__NO_DEPRECATED #endif #include "db_messages.pb-c.h" void node_state_message__init (NodeStateMessage *message) { static const NodeStateMessage init_value = NODE_STATE_MESSAGE__INIT; *message = init_value; } size_t node_state_message__get_packed_size (const NodeStateMessage *message) { assert(message->base.descriptor == &node_state_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t node_state_message__pack (const NodeStateMessage *message, uint8_t *out) { assert(message->base.descriptor == &node_state_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t node_state_message__pack_to_buffer (const NodeStateMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &node_state_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } NodeStateMessage * node_state_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (NodeStateMessage *) protobuf_c_message_unpack (&node_state_message__descriptor, allocator, len, data); } void node_state_message__free_unpacked (NodeStateMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &node_state_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void vector_clock_message__init (VectorClockMessage *message) { static const VectorClockMessage init_value = VECTOR_CLOCK_MESSAGE__INIT; *message = init_value; } size_t vector_clock_message__get_packed_size (const VectorClockMessage *message) { assert(message->base.descriptor == &vector_clock_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t vector_clock_message__pack (const VectorClockMessage *message, uint8_t *out) { assert(message->base.descriptor == &vector_clock_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t vector_clock_message__pack_to_buffer (const VectorClockMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &vector_clock_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } VectorClockMessage * vector_clock_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (VectorClockMessage *) protobuf_c_message_unpack (&vector_clock_message__descriptor, allocator, len, data); } void vector_clock_message__free_unpacked (VectorClockMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &vector_clock_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void gossip_message__init (GossipMessage *message) { static const GossipMessage init_value = GOSSIP_MESSAGE__INIT; *message = init_value; } size_t gossip_message__get_packed_size (const GossipMessage *message) { assert(message->base.descriptor == &gossip_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t gossip_message__pack (const GossipMessage *message, uint8_t *out) { assert(message->base.descriptor == &gossip_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t gossip_message__pack_to_buffer (const GossipMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &gossip_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } GossipMessage * gossip_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (GossipMessage *) protobuf_c_message_unpack (&gossip_message__descriptor, allocator, len, data); } void gossip_message__free_unpacked (GossipMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &gossip_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void gossip_listen_message__init (GossipListenMessage *message) { static const GossipListenMessage init_value = GOSSIP_LISTEN_MESSAGE__INIT; *message = init_value; } size_t gossip_listen_message__get_packed_size (const GossipListenMessage *message) { assert(message->base.descriptor == &gossip_listen_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t gossip_listen_message__pack (const GossipListenMessage *message, uint8_t *out) { assert(message->base.descriptor == &gossip_listen_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t gossip_listen_message__pack_to_buffer (const GossipListenMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &gossip_listen_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } GossipListenMessage * gossip_listen_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (GossipListenMessage *) protobuf_c_message_unpack (&gossip_listen_message__descriptor, allocator, len, data); } void gossip_listen_message__free_unpacked (GossipListenMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &gossip_listen_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void membership_view_message__init (MembershipViewMessage *message) { static const MembershipViewMessage init_value = MEMBERSHIP_VIEW_MESSAGE__INIT; *message = init_value; } size_t membership_view_message__get_packed_size (const MembershipViewMessage *message) { assert(message->base.descriptor == &membership_view_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t membership_view_message__pack (const MembershipViewMessage *message, uint8_t *out) { assert(message->base.descriptor == &membership_view_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t membership_view_message__pack_to_buffer (const MembershipViewMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &membership_view_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } MembershipViewMessage * membership_view_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (MembershipViewMessage *) protobuf_c_message_unpack (&membership_view_message__descriptor, allocator, len, data); } void membership_view_message__free_unpacked (MembershipViewMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &membership_view_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void membership_agreement_message__init (MembershipAgreementMessage *message) { static const MembershipAgreementMessage init_value = MEMBERSHIP_AGREEMENT_MESSAGE__INIT; *message = init_value; } size_t membership_agreement_message__get_packed_size (const MembershipAgreementMessage *message) { assert(message->base.descriptor == &membership_agreement_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t membership_agreement_message__pack (const MembershipAgreementMessage *message, uint8_t *out) { assert(message->base.descriptor == &membership_agreement_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t membership_agreement_message__pack_to_buffer (const MembershipAgreementMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &membership_agreement_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } MembershipAgreementMessage * membership_agreement_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (MembershipAgreementMessage *) protobuf_c_message_unpack (&membership_agreement_message__descriptor, allocator, len, data); } void membership_agreement_message__free_unpacked (MembershipAgreementMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &membership_agreement_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void cell_address_message__init (CellAddressMessage *message) { static const CellAddressMessage init_value = CELL_ADDRESS_MESSAGE__INIT; *message = init_value; } size_t cell_address_message__get_packed_size (const CellAddressMessage *message) { assert(message->base.descriptor == &cell_address_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t cell_address_message__pack (const CellAddressMessage *message, uint8_t *out) { assert(message->base.descriptor == &cell_address_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t cell_address_message__pack_to_buffer (const CellAddressMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &cell_address_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } CellAddressMessage * cell_address_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (CellAddressMessage *) protobuf_c_message_unpack (&cell_address_message__descriptor, allocator, len, data); } void cell_address_message__free_unpacked (CellAddressMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &cell_address_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void cell_message__init (CellMessage *message) { static const CellMessage init_value = CELL_MESSAGE__INIT; *message = init_value; } size_t cell_message__get_packed_size (const CellMessage *message) { assert(message->base.descriptor == &cell_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t cell_message__pack (const CellMessage *message, uint8_t *out) { assert(message->base.descriptor == &cell_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t cell_message__pack_to_buffer (const CellMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &cell_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } CellMessage * cell_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (CellMessage *) protobuf_c_message_unpack (&cell_message__descriptor, allocator, len, data); } void cell_message__free_unpacked (CellMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &cell_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void versioned_cell_message__init (VersionedCellMessage *message) { static const VersionedCellMessage init_value = VERSIONED_CELL_MESSAGE__INIT; *message = init_value; } size_t versioned_cell_message__get_packed_size (const VersionedCellMessage *message) { assert(message->base.descriptor == &versioned_cell_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t versioned_cell_message__pack (const VersionedCellMessage *message, uint8_t *out) { assert(message->base.descriptor == &versioned_cell_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t versioned_cell_message__pack_to_buffer (const VersionedCellMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &versioned_cell_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } VersionedCellMessage * versioned_cell_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (VersionedCellMessage *) protobuf_c_message_unpack (&versioned_cell_message__descriptor, allocator, len, data); } void versioned_cell_message__free_unpacked (VersionedCellMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &versioned_cell_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void server_message__init (ServerMessage *message) { static const ServerMessage init_value = SERVER_MESSAGE__INIT; *message = init_value; } size_t server_message__get_packed_size (const ServerMessage *message) { assert(message->base.descriptor == &server_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t server_message__pack (const ServerMessage *message, uint8_t *out) { assert(message->base.descriptor == &server_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t server_message__pack_to_buffer (const ServerMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &server_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } ServerMessage * server_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (ServerMessage *) protobuf_c_message_unpack (&server_message__descriptor, allocator, len, data); } void server_message__free_unpacked (ServerMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &server_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void client_message__init (ClientMessage *message) { static const ClientMessage init_value = CLIENT_MESSAGE__INIT; *message = init_value; } size_t client_message__get_packed_size (const ClientMessage *message) { assert(message->base.descriptor == &client_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t client_message__pack (const ClientMessage *message, uint8_t *out) { assert(message->base.descriptor == &client_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t client_message__pack_to_buffer (const ClientMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &client_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } ClientMessage * client_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (ClientMessage *) protobuf_c_message_unpack (&client_message__descriptor, allocator, len, data); } void client_message__free_unpacked (ClientMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &client_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void write_query_message__init (WriteQueryMessage *message) { static const WriteQueryMessage init_value = WRITE_QUERY_MESSAGE__INIT; *message = init_value; } size_t write_query_message__get_packed_size (const WriteQueryMessage *message) { assert(message->base.descriptor == &write_query_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t write_query_message__pack (const WriteQueryMessage *message, uint8_t *out) { assert(message->base.descriptor == &write_query_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t write_query_message__pack_to_buffer (const WriteQueryMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &write_query_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } WriteQueryMessage * write_query_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (WriteQueryMessage *) protobuf_c_message_unpack (&write_query_message__descriptor, allocator, len, data); } void write_query_message__free_unpacked (WriteQueryMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &write_query_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void read_query_message__init (ReadQueryMessage *message) { static const ReadQueryMessage init_value = READ_QUERY_MESSAGE__INIT; *message = init_value; } size_t read_query_message__get_packed_size (const ReadQueryMessage *message) { assert(message->base.descriptor == &read_query_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t read_query_message__pack (const ReadQueryMessage *message, uint8_t *out) { assert(message->base.descriptor == &read_query_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t read_query_message__pack_to_buffer (const ReadQueryMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &read_query_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } ReadQueryMessage * read_query_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (ReadQueryMessage *) protobuf_c_message_unpack (&read_query_message__descriptor, allocator, len, data); } void read_query_message__free_unpacked (ReadQueryMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &read_query_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void ack_message__init (AckMessage *message) { static const AckMessage init_value = ACK_MESSAGE__INIT; *message = init_value; } size_t ack_message__get_packed_size (const AckMessage *message) { assert(message->base.descriptor == &ack_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t ack_message__pack (const AckMessage *message, uint8_t *out) { assert(message->base.descriptor == &ack_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t ack_message__pack_to_buffer (const AckMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &ack_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } AckMessage * ack_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (AckMessage *) protobuf_c_message_unpack (&ack_message__descriptor, allocator, len, data); } void ack_message__free_unpacked (AckMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &ack_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void range_read_query_message__init (RangeReadQueryMessage *message) { static const RangeReadQueryMessage init_value = RANGE_READ_QUERY_MESSAGE__INIT; *message = init_value; } size_t range_read_query_message__get_packed_size (const RangeReadQueryMessage *message) { assert(message->base.descriptor == &range_read_query_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t range_read_query_message__pack (const RangeReadQueryMessage *message, uint8_t *out) { assert(message->base.descriptor == &range_read_query_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t range_read_query_message__pack_to_buffer (const RangeReadQueryMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &range_read_query_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } RangeReadQueryMessage * range_read_query_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (RangeReadQueryMessage *) protobuf_c_message_unpack (&range_read_query_message__descriptor, allocator, len, data); } void range_read_query_message__free_unpacked (RangeReadQueryMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &range_read_query_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void range_read_response_message__init (RangeReadResponseMessage *message) { static const RangeReadResponseMessage init_value = RANGE_READ_RESPONSE_MESSAGE__INIT; *message = init_value; } size_t range_read_response_message__get_packed_size (const RangeReadResponseMessage *message) { assert(message->base.descriptor == &range_read_response_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t range_read_response_message__pack (const RangeReadResponseMessage *message, uint8_t *out) { assert(message->base.descriptor == &range_read_response_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t range_read_response_message__pack_to_buffer (const RangeReadResponseMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &range_read_response_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } RangeReadResponseMessage * range_read_response_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (RangeReadResponseMessage *) protobuf_c_message_unpack (&range_read_response_message__descriptor, allocator, len, data); } void range_read_response_message__free_unpacked (RangeReadResponseMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &range_read_response_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void txn_message__init (TxnMessage *message) { static const TxnMessage init_value = TXN_MESSAGE__INIT; *message = init_value; } size_t txn_message__get_packed_size (const TxnMessage *message) { assert(message->base.descriptor == &txn_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t txn_message__pack (const TxnMessage *message, uint8_t *out) { assert(message->base.descriptor == &txn_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t txn_message__pack_to_buffer (const TxnMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &txn_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } TxnMessage * txn_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (TxnMessage *) protobuf_c_message_unpack (&txn_message__descriptor, allocator, len, data); } void txn_message__free_unpacked (TxnMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &txn_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void queue_query_message__init (QueueQueryMessage *message) { static const QueueQueryMessage init_value = QUEUE_QUERY_MESSAGE__INIT; *message = init_value; } size_t queue_query_message__get_packed_size (const QueueQueryMessage *message) { assert(message->base.descriptor == &queue_query_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t queue_query_message__pack (const QueueQueryMessage *message, uint8_t *out) { assert(message->base.descriptor == &queue_query_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t queue_query_message__pack_to_buffer (const QueueQueryMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &queue_query_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } QueueQueryMessage * queue_query_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (QueueQueryMessage *) protobuf_c_message_unpack (&queue_query_message__descriptor, allocator, len, data); } void queue_query_message__free_unpacked (QueueQueryMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &queue_query_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void consumer_id__init (ConsumerID *message) { static const ConsumerID init_value = CONSUMER_ID__INIT; *message = init_value; } size_t consumer_id__get_packed_size (const ConsumerID *message) { assert(message->base.descriptor == &consumer_id__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t consumer_id__pack (const ConsumerID *message, uint8_t *out) { assert(message->base.descriptor == &consumer_id__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t consumer_id__pack_to_buffer (const ConsumerID *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &consumer_id__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } ConsumerID * consumer_id__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (ConsumerID *) protobuf_c_message_unpack (&consumer_id__descriptor, allocator, len, data); } void consumer_id__free_unpacked (ConsumerID *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &consumer_id__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void create_queue_message__init (CreateQueueMessage *message) { static const CreateQueueMessage init_value = CREATE_QUEUE_MESSAGE__INIT; *message = init_value; } size_t create_queue_message__get_packed_size (const CreateQueueMessage *message) { assert(message->base.descriptor == &create_queue_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t create_queue_message__pack (const CreateQueueMessage *message, uint8_t *out) { assert(message->base.descriptor == &create_queue_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t create_queue_message__pack_to_buffer (const CreateQueueMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &create_queue_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } CreateQueueMessage * create_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (CreateQueueMessage *) protobuf_c_message_unpack (&create_queue_message__descriptor, allocator, len, data); } void create_queue_message__free_unpacked (CreateQueueMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &create_queue_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void delete_queue_message__init (DeleteQueueMessage *message) { static const DeleteQueueMessage init_value = DELETE_QUEUE_MESSAGE__INIT; *message = init_value; } size_t delete_queue_message__get_packed_size (const DeleteQueueMessage *message) { assert(message->base.descriptor == &delete_queue_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t delete_queue_message__pack (const DeleteQueueMessage *message, uint8_t *out) { assert(message->base.descriptor == &delete_queue_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t delete_queue_message__pack_to_buffer (const DeleteQueueMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &delete_queue_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } DeleteQueueMessage * delete_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (DeleteQueueMessage *) protobuf_c_message_unpack (&delete_queue_message__descriptor, allocator, len, data); } void delete_queue_message__free_unpacked (DeleteQueueMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &delete_queue_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void subscribe_queue_message__init (SubscribeQueueMessage *message) { static const SubscribeQueueMessage init_value = SUBSCRIBE_QUEUE_MESSAGE__INIT; *message = init_value; } size_t subscribe_queue_message__get_packed_size (const SubscribeQueueMessage *message) { assert(message->base.descriptor == &subscribe_queue_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t subscribe_queue_message__pack (const SubscribeQueueMessage *message, uint8_t *out) { assert(message->base.descriptor == &subscribe_queue_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t subscribe_queue_message__pack_to_buffer (const SubscribeQueueMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &subscribe_queue_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } SubscribeQueueMessage * subscribe_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (SubscribeQueueMessage *) protobuf_c_message_unpack (&subscribe_queue_message__descriptor, allocator, len, data); } void subscribe_queue_message__free_unpacked (SubscribeQueueMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &subscribe_queue_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void unsubscribe_queue_message__init (UnsubscribeQueueMessage *message) { static const UnsubscribeQueueMessage init_value = UNSUBSCRIBE_QUEUE_MESSAGE__INIT; *message = init_value; } size_t unsubscribe_queue_message__get_packed_size (const UnsubscribeQueueMessage *message) { assert(message->base.descriptor == &unsubscribe_queue_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t unsubscribe_queue_message__pack (const UnsubscribeQueueMessage *message, uint8_t *out) { assert(message->base.descriptor == &unsubscribe_queue_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t unsubscribe_queue_message__pack_to_buffer (const UnsubscribeQueueMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &unsubscribe_queue_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } UnsubscribeQueueMessage * unsubscribe_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (UnsubscribeQueueMessage *) protobuf_c_message_unpack (&unsubscribe_queue_message__descriptor, allocator, len, data); } void unsubscribe_queue_message__free_unpacked (UnsubscribeQueueMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &unsubscribe_queue_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void enqueue_message__init (EnqueueMessage *message) { static const EnqueueMessage init_value = ENQUEUE_MESSAGE__INIT; *message = init_value; } size_t enqueue_message__get_packed_size (const EnqueueMessage *message) { assert(message->base.descriptor == &enqueue_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t enqueue_message__pack (const EnqueueMessage *message, uint8_t *out) { assert(message->base.descriptor == &enqueue_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t enqueue_message__pack_to_buffer (const EnqueueMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &enqueue_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } EnqueueMessage * enqueue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (EnqueueMessage *) protobuf_c_message_unpack (&enqueue_message__descriptor, allocator, len, data); } void enqueue_message__free_unpacked (EnqueueMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &enqueue_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void enqueue_response_message__init (EnqueueResponseMessage *message) { static const EnqueueResponseMessage init_value = ENQUEUE_RESPONSE_MESSAGE__INIT; *message = init_value; } size_t enqueue_response_message__get_packed_size (const EnqueueResponseMessage *message) { assert(message->base.descriptor == &enqueue_response_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t enqueue_response_message__pack (const EnqueueResponseMessage *message, uint8_t *out) { assert(message->base.descriptor == &enqueue_response_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t enqueue_response_message__pack_to_buffer (const EnqueueResponseMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &enqueue_response_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } EnqueueResponseMessage * enqueue_response_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (EnqueueResponseMessage *) protobuf_c_message_unpack (&enqueue_response_message__descriptor, allocator, len, data); } void enqueue_response_message__free_unpacked (EnqueueResponseMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &enqueue_response_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void read_queue_message__init (ReadQueueMessage *message) { static const ReadQueueMessage init_value = READ_QUEUE_MESSAGE__INIT; *message = init_value; } size_t read_queue_message__get_packed_size (const ReadQueueMessage *message) { assert(message->base.descriptor == &read_queue_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t read_queue_message__pack (const ReadQueueMessage *message, uint8_t *out) { assert(message->base.descriptor == &read_queue_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t read_queue_message__pack_to_buffer (const ReadQueueMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &read_queue_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } ReadQueueMessage * read_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (ReadQueueMessage *) protobuf_c_message_unpack (&read_queue_message__descriptor, allocator, len, data); } void read_queue_message__free_unpacked (ReadQueueMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &read_queue_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void read_queue_response_message__init (ReadQueueResponseMessage *message) { static const ReadQueueResponseMessage init_value = READ_QUEUE_RESPONSE_MESSAGE__INIT; *message = init_value; } size_t read_queue_response_message__get_packed_size (const ReadQueueResponseMessage *message) { assert(message->base.descriptor == &read_queue_response_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t read_queue_response_message__pack (const ReadQueueResponseMessage *message, uint8_t *out) { assert(message->base.descriptor == &read_queue_response_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t read_queue_response_message__pack_to_buffer (const ReadQueueResponseMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &read_queue_response_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } ReadQueueResponseMessage * read_queue_response_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (ReadQueueResponseMessage *) protobuf_c_message_unpack (&read_queue_response_message__descriptor, allocator, len, data); } void read_queue_response_message__free_unpacked (ReadQueueResponseMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &read_queue_response_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void consume_queue_message__init (ConsumeQueueMessage *message) { static const ConsumeQueueMessage init_value = CONSUME_QUEUE_MESSAGE__INIT; *message = init_value; } size_t consume_queue_message__get_packed_size (const ConsumeQueueMessage *message) { assert(message->base.descriptor == &consume_queue_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t consume_queue_message__pack (const ConsumeQueueMessage *message, uint8_t *out) { assert(message->base.descriptor == &consume_queue_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t consume_queue_message__pack_to_buffer (const ConsumeQueueMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &consume_queue_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } ConsumeQueueMessage * consume_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (ConsumeQueueMessage *) protobuf_c_message_unpack (&consume_queue_message__descriptor, allocator, len, data); } void consume_queue_message__free_unpacked (ConsumeQueueMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &consume_queue_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void consume_queue_response_message__init (ConsumeQueueResponseMessage *message) { static const ConsumeQueueResponseMessage init_value = CONSUME_QUEUE_RESPONSE_MESSAGE__INIT; *message = init_value; } size_t consume_queue_response_message__get_packed_size (const ConsumeQueueResponseMessage *message) { assert(message->base.descriptor == &consume_queue_response_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t consume_queue_response_message__pack (const ConsumeQueueResponseMessage *message, uint8_t *out) { assert(message->base.descriptor == &consume_queue_response_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t consume_queue_response_message__pack_to_buffer (const ConsumeQueueResponseMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &consume_queue_response_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } ConsumeQueueResponseMessage * consume_queue_response_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (ConsumeQueueResponseMessage *) protobuf_c_message_unpack (&consume_queue_response_message__descriptor, allocator, len, data); } void consume_queue_response_message__free_unpacked (ConsumeQueueResponseMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &consume_queue_response_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } static const ProtobufCFieldDescriptor node_state_message__field_descriptors[6] = { { "status", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(NodeStateMessage, status), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "node_id", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(NodeStateMessage, node_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "hostname", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(NodeStateMessage, hostname), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "port", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(NodeStateMessage, port), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "rack_id", 5, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(NodeStateMessage, rack_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "dc_id", 6, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(NodeStateMessage, dc_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned node_state_message__field_indices_by_name[] = { 5, /* field[5] = dc_id */ 2, /* field[2] = hostname */ 1, /* field[1] = node_id */ 3, /* field[3] = port */ 4, /* field[4] = rack_id */ 0, /* field[0] = status */ }; static const ProtobufCIntRange node_state_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 6 } }; const ProtobufCMessageDescriptor node_state_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "NodeStateMessage", "NodeStateMessage", "NodeStateMessage", "", sizeof(NodeStateMessage), 6, node_state_message__field_descriptors, node_state_message__field_indices_by_name, 1, node_state_message__number_ranges, (ProtobufCMessageInit) node_state_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor vector_clock_message__field_descriptors[2] = { { "ids", 1, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_INT32, offsetof(VectorClockMessage, n_ids), offsetof(VectorClockMessage, ids), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "counters", 2, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_INT64, offsetof(VectorClockMessage, n_counters), offsetof(VectorClockMessage, counters), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned vector_clock_message__field_indices_by_name[] = { 1, /* field[1] = counters */ 0, /* field[0] = ids */ }; static const ProtobufCIntRange vector_clock_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor vector_clock_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "VectorClockMessage", "VectorClockMessage", "VectorClockMessage", "", sizeof(VectorClockMessage), 2, vector_clock_message__field_descriptors, vector_clock_message__field_indices_by_name, 1, vector_clock_message__number_ranges, (ProtobufCMessageInit) vector_clock_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor gossip_message__field_descriptors[2] = { { "node_state", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(GossipMessage, node_state), &node_state_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "vc", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(GossipMessage, vc), &vector_clock_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned gossip_message__field_indices_by_name[] = { 0, /* field[0] = node_state */ 1, /* field[1] = vc */ }; static const ProtobufCIntRange gossip_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor gossip_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "GossipMessage", "GossipMessage", "GossipMessage", "", sizeof(GossipMessage), 2, gossip_message__field_descriptors, gossip_message__field_indices_by_name, 1, gossip_message__number_ranges, (ProtobufCMessageInit) gossip_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor gossip_listen_message__field_descriptors[2] = { { "node_state", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(GossipListenMessage, node_state), &node_state_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(GossipListenMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned gossip_listen_message__field_indices_by_name[] = { 0, /* field[0] = node_state */ 1, /* field[1] = nonce */ }; static const ProtobufCIntRange gossip_listen_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor gossip_listen_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "GossipListenMessage", "GossipListenMessage", "GossipListenMessage", "", sizeof(GossipListenMessage), 2, gossip_listen_message__field_descriptors, gossip_listen_message__field_indices_by_name, 1, gossip_listen_message__number_ranges, (ProtobufCMessageInit) gossip_listen_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor membership_view_message__field_descriptors[3] = { { "membership", 1, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(MembershipViewMessage, n_membership), offsetof(MembershipViewMessage, membership), &node_state_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "client_membership", 2, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(MembershipViewMessage, n_client_membership), offsetof(MembershipViewMessage, client_membership), &node_state_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "view_id", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(MembershipViewMessage, view_id), &vector_clock_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned membership_view_message__field_indices_by_name[] = { 1, /* field[1] = client_membership */ 0, /* field[0] = membership */ 2, /* field[2] = view_id */ }; static const ProtobufCIntRange membership_view_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor membership_view_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "MembershipViewMessage", "MembershipViewMessage", "MembershipViewMessage", "", sizeof(MembershipViewMessage), 3, membership_view_message__field_descriptors, membership_view_message__field_indices_by_name, 1, membership_view_message__number_ranges, (ProtobufCMessageInit) membership_view_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor membership_agreement_message__field_descriptors[5] = { { "msg_type", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(MembershipAgreementMessage, msg_type), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "ack_status", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(MembershipAgreementMessage, ack_status), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "view", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(MembershipAgreementMessage, view), &membership_view_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(MembershipAgreementMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "vc", 5, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(MembershipAgreementMessage, vc), &vector_clock_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned membership_agreement_message__field_indices_by_name[] = { 1, /* field[1] = ack_status */ 0, /* field[0] = msg_type */ 3, /* field[3] = nonce */ 4, /* field[4] = vc */ 2, /* field[2] = view */ }; static const ProtobufCIntRange membership_agreement_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 5 } }; const ProtobufCMessageDescriptor membership_agreement_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "MembershipAgreementMessage", "MembershipAgreementMessage", "MembershipAgreementMessage", "", sizeof(MembershipAgreementMessage), 5, membership_agreement_message__field_descriptors, membership_agreement_message__field_indices_by_name, 1, membership_agreement_message__number_ranges, (ProtobufCMessageInit) membership_agreement_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor cell_address_message__field_descriptors[2] = { { "table_key", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(CellAddressMessage, table_key), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "keys", 2, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_INT64, offsetof(CellAddressMessage, n_keys), offsetof(CellAddressMessage, keys), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned cell_address_message__field_indices_by_name[] = { 1, /* field[1] = keys */ 0, /* field[0] = table_key */ }; static const ProtobufCIntRange cell_address_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 2 } }; const ProtobufCMessageDescriptor cell_address_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "CellAddressMessage", "CellAddressMessage", "CellAddressMessage", "", sizeof(CellAddressMessage), 2, cell_address_message__field_descriptors, cell_address_message__field_indices_by_name, 1, cell_address_message__number_ranges, (ProtobufCMessageInit) cell_address_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor cell_message__field_descriptors[3] = { { "table_key", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(CellMessage, table_key), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "keys", 2, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_INT64, offsetof(CellMessage, n_keys), offsetof(CellMessage, keys), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "columns", 3, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_INT64, offsetof(CellMessage, n_columns), offsetof(CellMessage, columns), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned cell_message__field_indices_by_name[] = { 2, /* field[2] = columns */ 1, /* field[1] = keys */ 0, /* field[0] = table_key */ }; static const ProtobufCIntRange cell_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor cell_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "CellMessage", "CellMessage", "CellMessage", "", sizeof(CellMessage), 3, cell_message__field_descriptors, cell_message__field_indices_by_name, 1, cell_message__number_ranges, (ProtobufCMessageInit) cell_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor versioned_cell_message__field_descriptors[5] = { { "table_key", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(VersionedCellMessage, table_key), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "keys", 2, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_INT64, offsetof(VersionedCellMessage, n_keys), offsetof(VersionedCellMessage, keys), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "columns", 3, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_INT64, offsetof(VersionedCellMessage, n_columns), offsetof(VersionedCellMessage, columns), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "blob", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(VersionedCellMessage, blob), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "version", 5, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(VersionedCellMessage, version), &vector_clock_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned versioned_cell_message__field_indices_by_name[] = { 3, /* field[3] = blob */ 2, /* field[2] = columns */ 1, /* field[1] = keys */ 0, /* field[0] = table_key */ 4, /* field[4] = version */ }; static const ProtobufCIntRange versioned_cell_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 5 } }; const ProtobufCMessageDescriptor versioned_cell_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "VersionedCellMessage", "VersionedCellMessage", "VersionedCellMessage", "", sizeof(VersionedCellMessage), 5, versioned_cell_message__field_descriptors, versioned_cell_message__field_indices_by_name, 1, versioned_cell_message__number_ranges, (ProtobufCMessageInit) versioned_cell_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor server_message__field_descriptors[8] = { { "mtype", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(ServerMessage, mtype), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "wm", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ServerMessage, wm), &write_query_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "rm", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ServerMessage, rm), &read_query_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "rrm", 4, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ServerMessage, rrm), &range_read_query_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "qm", 5, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ServerMessage, qm), &queue_query_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "tm", 6, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ServerMessage, tm), &txn_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "gl", 7, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ServerMessage, gl), &gossip_listen_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "vc", 8, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ServerMessage, vc), &vector_clock_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned server_message__field_indices_by_name[] = { 6, /* field[6] = gl */ 0, /* field[0] = mtype */ 4, /* field[4] = qm */ 2, /* field[2] = rm */ 3, /* field[3] = rrm */ 5, /* field[5] = tm */ 7, /* field[7] = vc */ 1, /* field[1] = wm */ }; static const ProtobufCIntRange server_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 8 } }; const ProtobufCMessageDescriptor server_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "ServerMessage", "ServerMessage", "ServerMessage", "", sizeof(ServerMessage), 8, server_message__field_descriptors, server_message__field_indices_by_name, 1, server_message__number_ranges, (ProtobufCMessageInit) server_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor client_message__field_descriptors[7] = { { "mtype", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(ClientMessage, mtype), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "am", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ClientMessage, am), &ack_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "wm", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ClientMessage, wm), &write_query_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "rrrm", 4, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ClientMessage, rrrm), &range_read_response_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "qm", 5, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ClientMessage, qm), &queue_query_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "tm", 6, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ClientMessage, tm), &txn_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "vc", 7, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ClientMessage, vc), &vector_clock_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned client_message__field_indices_by_name[] = { 1, /* field[1] = am */ 0, /* field[0] = mtype */ 4, /* field[4] = qm */ 3, /* field[3] = rrrm */ 5, /* field[5] = tm */ 6, /* field[6] = vc */ 2, /* field[2] = wm */ }; static const ProtobufCIntRange client_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 7 } }; const ProtobufCMessageDescriptor client_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "ClientMessage", "ClientMessage", "ClientMessage", "", sizeof(ClientMessage), 7, client_message__field_descriptors, client_message__field_indices_by_name, 1, client_message__number_ranges, (ProtobufCMessageInit) client_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor write_query_message__field_descriptors[5] = { { "cell", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(WriteQueryMessage, cell), &versioned_cell_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(WriteQueryMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(WriteQueryMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "msg_type", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(WriteQueryMessage, msg_type), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "mtype", 5, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(WriteQueryMessage, mtype), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned write_query_message__field_indices_by_name[] = { 0, /* field[0] = cell */ 3, /* field[3] = msg_type */ 4, /* field[4] = mtype */ 2, /* field[2] = nonce */ 1, /* field[1] = txnid */ }; static const ProtobufCIntRange write_query_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 5 } }; const ProtobufCMessageDescriptor write_query_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "WriteQueryMessage", "WriteQueryMessage", "WriteQueryMessage", "", sizeof(WriteQueryMessage), 5, write_query_message__field_descriptors, write_query_message__field_indices_by_name, 1, write_query_message__number_ranges, (ProtobufCMessageInit) write_query_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor read_query_message__field_descriptors[4] = { { "cell_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ReadQueryMessage, cell_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(ReadQueryMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(ReadQueryMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "mtype", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(ReadQueryMessage, mtype), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned read_query_message__field_indices_by_name[] = { 0, /* field[0] = cell_address */ 3, /* field[3] = mtype */ 2, /* field[2] = nonce */ 1, /* field[1] = txnid */ }; static const ProtobufCIntRange read_query_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor read_query_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "ReadQueryMessage", "ReadQueryMessage", "ReadQueryMessage", "", sizeof(ReadQueryMessage), 4, read_query_message__field_descriptors, read_query_message__field_indices_by_name, 1, read_query_message__number_ranges, (ProtobufCMessageInit) read_query_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor ack_message__field_descriptors[5] = { { "cell_address", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(AckMessage, cell_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "status", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(AckMessage, status), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(AckMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(AckMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "mtype", 5, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(AckMessage, mtype), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned ack_message__field_indices_by_name[] = { 0, /* field[0] = cell_address */ 4, /* field[4] = mtype */ 3, /* field[3] = nonce */ 1, /* field[1] = status */ 2, /* field[2] = txnid */ }; static const ProtobufCIntRange ack_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 5 } }; const ProtobufCMessageDescriptor ack_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "AckMessage", "AckMessage", "AckMessage", "", sizeof(AckMessage), 5, ack_message__field_descriptors, ack_message__field_indices_by_name, 1, ack_message__number_ranges, (ProtobufCMessageInit) ack_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor range_read_query_message__field_descriptors[5] = { { "start_cell_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(RangeReadQueryMessage, start_cell_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "end_cell_address", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(RangeReadQueryMessage, end_cell_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(RangeReadQueryMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(RangeReadQueryMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "mtype", 5, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(RangeReadQueryMessage, mtype), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned range_read_query_message__field_indices_by_name[] = { 1, /* field[1] = end_cell_address */ 4, /* field[4] = mtype */ 3, /* field[3] = nonce */ 0, /* field[0] = start_cell_address */ 2, /* field[2] = txnid */ }; static const ProtobufCIntRange range_read_query_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 5 } }; const ProtobufCMessageDescriptor range_read_query_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "RangeReadQueryMessage", "RangeReadQueryMessage", "RangeReadQueryMessage", "", sizeof(RangeReadQueryMessage), 5, range_read_query_message__field_descriptors, range_read_query_message__field_indices_by_name, 1, range_read_query_message__number_ranges, (ProtobufCMessageInit) range_read_query_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor range_read_response_message__field_descriptors[4] = { { "cells", 1, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(RangeReadResponseMessage, n_cells), offsetof(RangeReadResponseMessage, cells), &versioned_cell_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(RangeReadResponseMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(RangeReadResponseMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "mtype", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(RangeReadResponseMessage, mtype), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned range_read_response_message__field_indices_by_name[] = { 0, /* field[0] = cells */ 3, /* field[3] = mtype */ 2, /* field[2] = nonce */ 1, /* field[1] = txnid */ }; static const ProtobufCIntRange range_read_response_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor range_read_response_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "RangeReadResponseMessage", "RangeReadResponseMessage", "RangeReadResponseMessage", "", sizeof(RangeReadResponseMessage), 4, range_read_response_message__field_descriptors, range_read_response_message__field_indices_by_name, 1, range_read_response_message__number_ranges, (ProtobufCMessageInit) range_read_response_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor txn_message__field_descriptors[9] = { { "type", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(TxnMessage, type), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "own_read_set", 2, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(TxnMessage, n_own_read_set), offsetof(TxnMessage, own_read_set), &versioned_cell_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "own_write_set", 3, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(TxnMessage, n_own_write_set), offsetof(TxnMessage, own_write_set), &versioned_cell_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "complete_read_set", 4, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(TxnMessage, n_complete_read_set), offsetof(TxnMessage, complete_read_set), &versioned_cell_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "complete_write_set", 5, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(TxnMessage, n_complete_write_set), offsetof(TxnMessage, complete_write_set), &versioned_cell_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 6, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(TxnMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 7, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(TxnMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "version", 8, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(TxnMessage, version), &vector_clock_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "mtype", 9, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(TxnMessage, mtype), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned txn_message__field_indices_by_name[] = { 3, /* field[3] = complete_read_set */ 4, /* field[4] = complete_write_set */ 8, /* field[8] = mtype */ 6, /* field[6] = nonce */ 1, /* field[1] = own_read_set */ 2, /* field[2] = own_write_set */ 5, /* field[5] = txnid */ 0, /* field[0] = type */ 7, /* field[7] = version */ }; static const ProtobufCIntRange txn_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 9 } }; const ProtobufCMessageDescriptor txn_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "TxnMessage", "TxnMessage", "TxnMessage", "", sizeof(TxnMessage), 9, txn_message__field_descriptors, txn_message__field_indices_by_name, 1, txn_message__number_ranges, (ProtobufCMessageInit) txn_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor queue_query_message__field_descriptors[12] = { { "queue_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, queue_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "msg_type", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, msg_type), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "app_id", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, app_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "shard_id", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, shard_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "consumer_id", 5, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, consumer_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "group_id", 6, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, group_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "queue_index", 7, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, queue_index), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "status", 8, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, status), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "cells", 9, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(QueueQueryMessage, n_cells), offsetof(QueueQueryMessage, cells), &versioned_cell_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 10, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 11, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "mtype", 12, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(QueueQueryMessage, mtype), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned queue_query_message__field_indices_by_name[] = { 2, /* field[2] = app_id */ 8, /* field[8] = cells */ 4, /* field[4] = consumer_id */ 5, /* field[5] = group_id */ 1, /* field[1] = msg_type */ 11, /* field[11] = mtype */ 10, /* field[10] = nonce */ 0, /* field[0] = queue_address */ 6, /* field[6] = queue_index */ 3, /* field[3] = shard_id */ 7, /* field[7] = status */ 9, /* field[9] = txnid */ }; static const ProtobufCIntRange queue_query_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 12 } }; const ProtobufCMessageDescriptor queue_query_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "QueueQueryMessage", "QueueQueryMessage", "QueueQueryMessage", "", sizeof(QueueQueryMessage), 12, queue_query_message__field_descriptors, queue_query_message__field_indices_by_name, 1, queue_query_message__number_ranges, (ProtobufCMessageInit) queue_query_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor consumer_id__field_descriptors[3] = { { "app_id", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(ConsumerID, app_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "shard_id", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(ConsumerID, shard_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "consumer_id", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(ConsumerID, consumer_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned consumer_id__field_indices_by_name[] = { 0, /* field[0] = app_id */ 2, /* field[2] = consumer_id */ 1, /* field[1] = shard_id */ }; static const ProtobufCIntRange consumer_id__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor consumer_id__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "ConsumerID", "ConsumerID", "ConsumerID", "", sizeof(ConsumerID), 3, consumer_id__field_descriptors, consumer_id__field_indices_by_name, 1, consumer_id__number_ranges, (ProtobufCMessageInit) consumer_id__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor create_queue_message__field_descriptors[3] = { { "queue_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(CreateQueueMessage, queue_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(CreateQueueMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(CreateQueueMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned create_queue_message__field_indices_by_name[] = { 2, /* field[2] = nonce */ 0, /* field[0] = queue_address */ 1, /* field[1] = txnid */ }; static const ProtobufCIntRange create_queue_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor create_queue_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "CreateQueueMessage", "CreateQueueMessage", "CreateQueueMessage", "", sizeof(CreateQueueMessage), 3, create_queue_message__field_descriptors, create_queue_message__field_indices_by_name, 1, create_queue_message__number_ranges, (ProtobufCMessageInit) create_queue_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor delete_queue_message__field_descriptors[3] = { { "queue_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(DeleteQueueMessage, queue_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(DeleteQueueMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(DeleteQueueMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned delete_queue_message__field_indices_by_name[] = { 2, /* field[2] = nonce */ 0, /* field[0] = queue_address */ 1, /* field[1] = txnid */ }; static const ProtobufCIntRange delete_queue_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor delete_queue_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "DeleteQueueMessage", "DeleteQueueMessage", "DeleteQueueMessage", "", sizeof(DeleteQueueMessage), 3, delete_queue_message__field_descriptors, delete_queue_message__field_indices_by_name, 1, delete_queue_message__number_ranges, (ProtobufCMessageInit) delete_queue_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor subscribe_queue_message__field_descriptors[4] = { { "queue_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(SubscribeQueueMessage, queue_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "consumer_id", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(SubscribeQueueMessage, consumer_id), &consumer_id__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(SubscribeQueueMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(SubscribeQueueMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned subscribe_queue_message__field_indices_by_name[] = { 1, /* field[1] = consumer_id */ 3, /* field[3] = nonce */ 0, /* field[0] = queue_address */ 2, /* field[2] = txnid */ }; static const ProtobufCIntRange subscribe_queue_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor subscribe_queue_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "SubscribeQueueMessage", "SubscribeQueueMessage", "SubscribeQueueMessage", "", sizeof(SubscribeQueueMessage), 4, subscribe_queue_message__field_descriptors, subscribe_queue_message__field_indices_by_name, 1, subscribe_queue_message__number_ranges, (ProtobufCMessageInit) subscribe_queue_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor unsubscribe_queue_message__field_descriptors[4] = { { "queue_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(UnsubscribeQueueMessage, queue_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "consumer_id", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(UnsubscribeQueueMessage, consumer_id), &consumer_id__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(UnsubscribeQueueMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(UnsubscribeQueueMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned unsubscribe_queue_message__field_indices_by_name[] = { 1, /* field[1] = consumer_id */ 3, /* field[3] = nonce */ 0, /* field[0] = queue_address */ 2, /* field[2] = txnid */ }; static const ProtobufCIntRange unsubscribe_queue_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor unsubscribe_queue_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "UnsubscribeQueueMessage", "UnsubscribeQueueMessage", "UnsubscribeQueueMessage", "", sizeof(UnsubscribeQueueMessage), 4, unsubscribe_queue_message__field_descriptors, unsubscribe_queue_message__field_indices_by_name, 1, unsubscribe_queue_message__number_ranges, (ProtobufCMessageInit) unsubscribe_queue_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor enqueue_message__field_descriptors[3] = { { "cells", 1, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(EnqueueMessage, n_cells), offsetof(EnqueueMessage, cells), &versioned_cell_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(EnqueueMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(EnqueueMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned enqueue_message__field_indices_by_name[] = { 0, /* field[0] = cells */ 2, /* field[2] = nonce */ 1, /* field[1] = txnid */ }; static const ProtobufCIntRange enqueue_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor enqueue_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "EnqueueMessage", "EnqueueMessage", "EnqueueMessage", "", sizeof(EnqueueMessage), 3, enqueue_message__field_descriptors, enqueue_message__field_indices_by_name, 1, enqueue_message__number_ranges, (ProtobufCMessageInit) enqueue_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor enqueue_response_message__field_descriptors[4] = { { "queue_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(EnqueueResponseMessage, queue_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "last_item_id", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(EnqueueResponseMessage, last_item_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(EnqueueResponseMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(EnqueueResponseMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned enqueue_response_message__field_indices_by_name[] = { 1, /* field[1] = last_item_id */ 3, /* field[3] = nonce */ 0, /* field[0] = queue_address */ 2, /* field[2] = txnid */ }; static const ProtobufCIntRange enqueue_response_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor enqueue_response_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "EnqueueResponseMessage", "EnqueueResponseMessage", "EnqueueResponseMessage", "", sizeof(EnqueueResponseMessage), 4, enqueue_response_message__field_descriptors, enqueue_response_message__field_indices_by_name, 1, enqueue_response_message__number_ranges, (ProtobufCMessageInit) enqueue_response_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor read_queue_message__field_descriptors[5] = { { "queue_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ReadQueueMessage, queue_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "consumer_id", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ReadQueueMessage, consumer_id), &consumer_id__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "max_items", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(ReadQueueMessage, max_items), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(ReadQueueMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 5, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(ReadQueueMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned read_queue_message__field_indices_by_name[] = { 1, /* field[1] = consumer_id */ 2, /* field[2] = max_items */ 4, /* field[4] = nonce */ 0, /* field[0] = queue_address */ 3, /* field[3] = txnid */ }; static const ProtobufCIntRange read_queue_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 5 } }; const ProtobufCMessageDescriptor read_queue_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "ReadQueueMessage", "ReadQueueMessage", "ReadQueueMessage", "", sizeof(ReadQueueMessage), 5, read_queue_message__field_descriptors, read_queue_message__field_indices_by_name, 1, read_queue_message__number_ranges, (ProtobufCMessageInit) read_queue_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor read_queue_response_message__field_descriptors[4] = { { "queue_entries", 1, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(ReadQueueResponseMessage, n_queue_entries), offsetof(ReadQueueResponseMessage, queue_entries), &versioned_cell_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "consumer_id", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ReadQueueResponseMessage, consumer_id), &consumer_id__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(ReadQueueResponseMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(ReadQueueResponseMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned read_queue_response_message__field_indices_by_name[] = { 1, /* field[1] = consumer_id */ 3, /* field[3] = nonce */ 0, /* field[0] = queue_entries */ 2, /* field[2] = txnid */ }; static const ProtobufCIntRange read_queue_response_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor read_queue_response_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "ReadQueueResponseMessage", "ReadQueueResponseMessage", "ReadQueueResponseMessage", "", sizeof(ReadQueueResponseMessage), 4, read_queue_response_message__field_descriptors, read_queue_response_message__field_indices_by_name, 1, read_queue_response_message__number_ranges, (ProtobufCMessageInit) read_queue_response_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor consume_queue_message__field_descriptors[5] = { { "queue_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ConsumeQueueMessage, queue_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "consumer_id", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ConsumeQueueMessage, consumer_id), &consumer_id__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "new_consume_head", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(ConsumeQueueMessage, new_consume_head), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(ConsumeQueueMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 5, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(ConsumeQueueMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned consume_queue_message__field_indices_by_name[] = { 1, /* field[1] = consumer_id */ 2, /* field[2] = new_consume_head */ 4, /* field[4] = nonce */ 0, /* field[0] = queue_address */ 3, /* field[3] = txnid */ }; static const ProtobufCIntRange consume_queue_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 5 } }; const ProtobufCMessageDescriptor consume_queue_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "ConsumeQueueMessage", "ConsumeQueueMessage", "ConsumeQueueMessage", "", sizeof(ConsumeQueueMessage), 5, consume_queue_message__field_descriptors, consume_queue_message__field_indices_by_name, 1, consume_queue_message__number_ranges, (ProtobufCMessageInit) consume_queue_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor consume_queue_response_message__field_descriptors[6] = { { "queue_address", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ConsumeQueueResponseMessage, queue_address), &cell_address_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "consumer_id", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(ConsumeQueueResponseMessage, consumer_id), &consumer_id__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "status", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ offsetof(ConsumeQueueResponseMessage, status), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "new_consume_head", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(ConsumeQueueResponseMessage, new_consume_head), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "txnid", 5, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(ConsumeQueueResponseMessage, txnid), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "nonce", 6, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_INT64, 0, /* quantifier_offset */ offsetof(ConsumeQueueResponseMessage, nonce), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned consume_queue_response_message__field_indices_by_name[] = { 1, /* field[1] = consumer_id */ 3, /* field[3] = new_consume_head */ 5, /* field[5] = nonce */ 0, /* field[0] = queue_address */ 2, /* field[2] = status */ 4, /* field[4] = txnid */ }; static const ProtobufCIntRange consume_queue_response_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 6 } }; const ProtobufCMessageDescriptor consume_queue_response_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "ConsumeQueueResponseMessage", "ConsumeQueueResponseMessage", "ConsumeQueueResponseMessage", "", sizeof(ConsumeQueueResponseMessage), 6, consume_queue_response_message__field_descriptors, consume_queue_response_message__field_indices_by_name, 1, consume_queue_response_message__number_ranges, (ProtobufCMessageInit) consume_queue_response_message__init, NULL,NULL,NULL /* reserved[123] */ }; ================================================ FILE: backend/failure_detector/db_messages.pb-c.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: backend/failure_detector/db_messages.proto */ #ifndef PROTOBUF_C_backend_2ffailure_5fdetector_2fdb_5fmessages_2eproto__INCLUDED #define PROTOBUF_C_backend_2ffailure_5fdetector_2fdb_5fmessages_2eproto__INCLUDED #include PROTOBUF_C__BEGIN_DECLS #if PROTOBUF_C_VERSION_NUMBER < 1000000 # error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. #elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION # error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. #endif typedef struct NodeStateMessage NodeStateMessage; typedef struct VectorClockMessage VectorClockMessage; typedef struct GossipMessage GossipMessage; typedef struct GossipListenMessage GossipListenMessage; typedef struct MembershipViewMessage MembershipViewMessage; typedef struct MembershipAgreementMessage MembershipAgreementMessage; typedef struct CellAddressMessage CellAddressMessage; typedef struct CellMessage CellMessage; typedef struct VersionedCellMessage VersionedCellMessage; typedef struct ServerMessage ServerMessage; typedef struct ClientMessage ClientMessage; typedef struct WriteQueryMessage WriteQueryMessage; typedef struct ReadQueryMessage ReadQueryMessage; typedef struct AckMessage AckMessage; typedef struct RangeReadQueryMessage RangeReadQueryMessage; typedef struct RangeReadResponseMessage RangeReadResponseMessage; typedef struct TxnMessage TxnMessage; typedef struct QueueQueryMessage QueueQueryMessage; typedef struct ConsumerID ConsumerID; typedef struct CreateQueueMessage CreateQueueMessage; typedef struct DeleteQueueMessage DeleteQueueMessage; typedef struct SubscribeQueueMessage SubscribeQueueMessage; typedef struct UnsubscribeQueueMessage UnsubscribeQueueMessage; typedef struct EnqueueMessage EnqueueMessage; typedef struct EnqueueResponseMessage EnqueueResponseMessage; typedef struct ReadQueueMessage ReadQueueMessage; typedef struct ReadQueueResponseMessage ReadQueueResponseMessage; typedef struct ConsumeQueueMessage ConsumeQueueMessage; typedef struct ConsumeQueueResponseMessage ConsumeQueueResponseMessage; /* --- enums --- */ /* --- messages --- */ struct NodeStateMessage { ProtobufCMessage base; /* * 0 - dead, 1 - ready, 2 - alive but not ready */ int32_t status; int32_t node_id; ProtobufCBinaryData hostname; int32_t port; int32_t rack_id; int32_t dc_id; }; #define NODE_STATE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&node_state_message__descriptor) \ , 0, 0, {0,NULL}, 0, 0, 0 } struct VectorClockMessage { ProtobufCMessage base; size_t n_ids; int32_t *ids; size_t n_counters; int64_t *counters; }; #define VECTOR_CLOCK_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&vector_clock_message__descriptor) \ , 0,NULL, 0,NULL } struct GossipMessage { ProtobufCMessage base; NodeStateMessage *node_state; VectorClockMessage *vc; }; #define GOSSIP_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&gossip_message__descriptor) \ , NULL, NULL } struct GossipListenMessage { ProtobufCMessage base; NodeStateMessage *node_state; int64_t nonce; }; #define GOSSIP_LISTEN_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&gossip_listen_message__descriptor) \ , NULL, 0 } struct MembershipViewMessage { ProtobufCMessage base; size_t n_membership; NodeStateMessage **membership; size_t n_client_membership; NodeStateMessage **client_membership; VectorClockMessage *view_id; }; #define MEMBERSHIP_VIEW_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&membership_view_message__descriptor) \ , 0,NULL, 0,NULL, NULL } struct MembershipAgreementMessage { ProtobufCMessage base; /* * 0 - PROPOSE, 1 - RESPONSE, 2 - NOTIFY, 3 - RETRY_LINK, 4 - NOTIFY_ACK */ int32_t msg_type; /* * 0 - ACK, 1 - NACK, 2 - UNINIT */ int32_t ack_status; MembershipViewMessage *view; int64_t nonce; VectorClockMessage *vc; }; #define MEMBERSHIP_AGREEMENT_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&membership_agreement_message__descriptor) \ , 0, 0, NULL, 0, NULL } struct CellAddressMessage { ProtobufCMessage base; int64_t table_key; size_t n_keys; int64_t *keys; }; #define CELL_ADDRESS_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&cell_address_message__descriptor) \ , 0, 0,NULL } struct CellMessage { ProtobufCMessage base; int64_t table_key; size_t n_keys; int64_t *keys; size_t n_columns; int64_t *columns; }; #define CELL_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&cell_message__descriptor) \ , 0, 0,NULL, 0,NULL } struct VersionedCellMessage { ProtobufCMessage base; int64_t table_key; size_t n_keys; int64_t *keys; size_t n_columns; int64_t *columns; ProtobufCBinaryData blob; /* * optional int64 version_no=6; */ VectorClockMessage *version; }; #define VERSIONED_CELL_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&versioned_cell_message__descriptor) \ , 0, 0,NULL, 0,NULL, {0,NULL}, NULL } struct ServerMessage { ProtobufCMessage base; /* * {RPC_TYPE_WRITE, RPC_TYPE_READ, RPC_TYPE_RANGE_READ, RPC_TYPE_QUEUE, RPC_TYPE_TXN, RPC_TYPE_GOSSIP_LISTEN} */ int32_t mtype; WriteQueryMessage *wm; ReadQueryMessage *rm; RangeReadQueryMessage *rrm; QueueQueryMessage *qm; TxnMessage *tm; GossipListenMessage *gl; VectorClockMessage *vc; }; #define SERVER_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&server_message__descriptor) \ , 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL } struct ClientMessage { ProtobufCMessage base; /* * {RPC_TYPE_ACK, RPC_TYPE_WRITE, RPC_TYPE_RANGE_READ_RESPONSE, RPC_TYPE_QUEUE, RPC_TYPE_TXN} */ int32_t mtype; AckMessage *am; WriteQueryMessage *wm; RangeReadResponseMessage *rrrm; QueueQueryMessage *qm; TxnMessage *tm; VectorClockMessage *vc; }; #define CLIENT_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&client_message__descriptor) \ , 0, NULL, NULL, NULL, NULL, NULL, NULL } struct WriteQueryMessage { ProtobufCMessage base; /* * CellMessage */ VersionedCellMessage *cell; ProtobufCBinaryData txnid; int64_t nonce; /* * {RPC_TYPE_WRITE, RPC_TYPE_DELETE} */ int32_t msg_type; int32_t mtype; }; #define WRITE_QUERY_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&write_query_message__descriptor) \ , NULL, {0,NULL}, 0, 0, 0 } struct ReadQueryMessage { ProtobufCMessage base; CellAddressMessage *cell_address; ProtobufCBinaryData txnid; int64_t nonce; int32_t mtype; }; #define READ_QUERY_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&read_query_message__descriptor) \ , NULL, {0,NULL}, 0, 0 } struct AckMessage { ProtobufCMessage base; CellAddressMessage *cell_address; /* * 0 - ACK, 1 - NACK */ int32_t status; ProtobufCBinaryData txnid; int64_t nonce; int32_t mtype; }; #define ACK_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&ack_message__descriptor) \ , NULL, 0, {0,NULL}, 0, 0 } struct RangeReadQueryMessage { ProtobufCMessage base; CellAddressMessage *start_cell_address; CellAddressMessage *end_cell_address; ProtobufCBinaryData txnid; int64_t nonce; int32_t mtype; }; #define RANGE_READ_QUERY_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&range_read_query_message__descriptor) \ , NULL, NULL, {0,NULL}, 0, 0 } struct RangeReadResponseMessage { ProtobufCMessage base; size_t n_cells; VersionedCellMessage **cells; ProtobufCBinaryData txnid; int64_t nonce; int32_t mtype; }; #define RANGE_READ_RESPONSE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&range_read_response_message__descriptor) \ , 0,NULL, {0,NULL}, 0, 0 } struct TxnMessage { ProtobufCMessage base; /* * BEGIN=0, VALIDATION=1, COMMIT=2, ABORT=3 */ int32_t type; size_t n_own_read_set; VersionedCellMessage **own_read_set; size_t n_own_write_set; VersionedCellMessage **own_write_set; size_t n_complete_read_set; VersionedCellMessage **complete_read_set; size_t n_complete_write_set; VersionedCellMessage **complete_write_set; ProtobufCBinaryData txnid; int64_t nonce; VectorClockMessage *version; int32_t mtype; }; #define TXN_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&txn_message__descriptor) \ , 0, 0,NULL, 0,NULL, 0,NULL, 0,NULL, {0,NULL}, 0, NULL, 0 } struct QueueQueryMessage { ProtobufCMessage base; CellAddressMessage *queue_address; /* * QUERY_TYPE_{CREATE_QUEUE, DELETE_QUEUE, SUBSCRIBE_QUEUE, UNSUBSCRIBE_QUEUE, ENQUEUE, READ_QUEUE, CONSUME_QUEUE, READ_QUEUE_RESPONSE, NOTIFICATION} */ int32_t msg_type; int32_t app_id; int32_t shard_id; int32_t consumer_id; int32_t group_id; int32_t queue_index; int32_t status; size_t n_cells; VersionedCellMessage **cells; ProtobufCBinaryData txnid; int64_t nonce; int32_t mtype; }; #define QUEUE_QUERY_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&queue_query_message__descriptor) \ , NULL, 0, 0, 0, 0, 0, 0, 0, 0,NULL, {0,NULL}, 0, 0 } struct ConsumerID { ProtobufCMessage base; int32_t app_id; int32_t shard_id; int32_t consumer_id; }; #define CONSUMER_ID__INIT \ { PROTOBUF_C_MESSAGE_INIT (&consumer_id__descriptor) \ , 0, 0, 0 } struct CreateQueueMessage { ProtobufCMessage base; CellAddressMessage *queue_address; ProtobufCBinaryData txnid; int64_t nonce; }; #define CREATE_QUEUE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&create_queue_message__descriptor) \ , NULL, {0,NULL}, 0 } struct DeleteQueueMessage { ProtobufCMessage base; CellAddressMessage *queue_address; ProtobufCBinaryData txnid; int64_t nonce; }; #define DELETE_QUEUE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&delete_queue_message__descriptor) \ , NULL, {0,NULL}, 0 } struct SubscribeQueueMessage { ProtobufCMessage base; CellAddressMessage *queue_address; ConsumerID *consumer_id; ProtobufCBinaryData txnid; int64_t nonce; }; #define SUBSCRIBE_QUEUE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&subscribe_queue_message__descriptor) \ , NULL, NULL, {0,NULL}, 0 } struct UnsubscribeQueueMessage { ProtobufCMessage base; CellAddressMessage *queue_address; ConsumerID *consumer_id; ProtobufCBinaryData txnid; int64_t nonce; }; #define UNSUBSCRIBE_QUEUE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&unsubscribe_queue_message__descriptor) \ , NULL, NULL, {0,NULL}, 0 } struct EnqueueMessage { ProtobufCMessage base; /* * CellMessage */ size_t n_cells; VersionedCellMessage **cells; ProtobufCBinaryData txnid; int64_t nonce; }; #define ENQUEUE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&enqueue_message__descriptor) \ , 0,NULL, {0,NULL}, 0 } struct EnqueueResponseMessage { ProtobufCMessage base; CellAddressMessage *queue_address; int64_t last_item_id; ProtobufCBinaryData txnid; int64_t nonce; }; #define ENQUEUE_RESPONSE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&enqueue_response_message__descriptor) \ , NULL, 0, {0,NULL}, 0 } struct ReadQueueMessage { ProtobufCMessage base; CellAddressMessage *queue_address; ConsumerID *consumer_id; int64_t max_items; ProtobufCBinaryData txnid; int64_t nonce; }; #define READ_QUEUE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&read_queue_message__descriptor) \ , NULL, NULL, 0, {0,NULL}, 0 } struct ReadQueueResponseMessage { ProtobufCMessage base; size_t n_queue_entries; VersionedCellMessage **queue_entries; ConsumerID *consumer_id; ProtobufCBinaryData txnid; int64_t nonce; }; #define READ_QUEUE_RESPONSE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&read_queue_response_message__descriptor) \ , 0,NULL, NULL, {0,NULL}, 0 } struct ConsumeQueueMessage { ProtobufCMessage base; CellAddressMessage *queue_address; ConsumerID *consumer_id; int64_t new_consume_head; ProtobufCBinaryData txnid; int64_t nonce; }; #define CONSUME_QUEUE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&consume_queue_message__descriptor) \ , NULL, NULL, 0, {0,NULL}, 0 } struct ConsumeQueueResponseMessage { ProtobufCMessage base; CellAddressMessage *queue_address; ConsumerID *consumer_id; /* * 0 - ACK, 1 - NACK */ int32_t status; int64_t new_consume_head; ProtobufCBinaryData txnid; int64_t nonce; }; #define CONSUME_QUEUE_RESPONSE_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&consume_queue_response_message__descriptor) \ , NULL, NULL, 0, 0, {0,NULL}, 0 } /* NodeStateMessage methods */ void node_state_message__init (NodeStateMessage *message); size_t node_state_message__get_packed_size (const NodeStateMessage *message); size_t node_state_message__pack (const NodeStateMessage *message, uint8_t *out); size_t node_state_message__pack_to_buffer (const NodeStateMessage *message, ProtobufCBuffer *buffer); NodeStateMessage * node_state_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void node_state_message__free_unpacked (NodeStateMessage *message, ProtobufCAllocator *allocator); /* VectorClockMessage methods */ void vector_clock_message__init (VectorClockMessage *message); size_t vector_clock_message__get_packed_size (const VectorClockMessage *message); size_t vector_clock_message__pack (const VectorClockMessage *message, uint8_t *out); size_t vector_clock_message__pack_to_buffer (const VectorClockMessage *message, ProtobufCBuffer *buffer); VectorClockMessage * vector_clock_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void vector_clock_message__free_unpacked (VectorClockMessage *message, ProtobufCAllocator *allocator); /* GossipMessage methods */ void gossip_message__init (GossipMessage *message); size_t gossip_message__get_packed_size (const GossipMessage *message); size_t gossip_message__pack (const GossipMessage *message, uint8_t *out); size_t gossip_message__pack_to_buffer (const GossipMessage *message, ProtobufCBuffer *buffer); GossipMessage * gossip_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void gossip_message__free_unpacked (GossipMessage *message, ProtobufCAllocator *allocator); /* GossipListenMessage methods */ void gossip_listen_message__init (GossipListenMessage *message); size_t gossip_listen_message__get_packed_size (const GossipListenMessage *message); size_t gossip_listen_message__pack (const GossipListenMessage *message, uint8_t *out); size_t gossip_listen_message__pack_to_buffer (const GossipListenMessage *message, ProtobufCBuffer *buffer); GossipListenMessage * gossip_listen_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void gossip_listen_message__free_unpacked (GossipListenMessage *message, ProtobufCAllocator *allocator); /* MembershipViewMessage methods */ void membership_view_message__init (MembershipViewMessage *message); size_t membership_view_message__get_packed_size (const MembershipViewMessage *message); size_t membership_view_message__pack (const MembershipViewMessage *message, uint8_t *out); size_t membership_view_message__pack_to_buffer (const MembershipViewMessage *message, ProtobufCBuffer *buffer); MembershipViewMessage * membership_view_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void membership_view_message__free_unpacked (MembershipViewMessage *message, ProtobufCAllocator *allocator); /* MembershipAgreementMessage methods */ void membership_agreement_message__init (MembershipAgreementMessage *message); size_t membership_agreement_message__get_packed_size (const MembershipAgreementMessage *message); size_t membership_agreement_message__pack (const MembershipAgreementMessage *message, uint8_t *out); size_t membership_agreement_message__pack_to_buffer (const MembershipAgreementMessage *message, ProtobufCBuffer *buffer); MembershipAgreementMessage * membership_agreement_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void membership_agreement_message__free_unpacked (MembershipAgreementMessage *message, ProtobufCAllocator *allocator); /* CellAddressMessage methods */ void cell_address_message__init (CellAddressMessage *message); size_t cell_address_message__get_packed_size (const CellAddressMessage *message); size_t cell_address_message__pack (const CellAddressMessage *message, uint8_t *out); size_t cell_address_message__pack_to_buffer (const CellAddressMessage *message, ProtobufCBuffer *buffer); CellAddressMessage * cell_address_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void cell_address_message__free_unpacked (CellAddressMessage *message, ProtobufCAllocator *allocator); /* CellMessage methods */ void cell_message__init (CellMessage *message); size_t cell_message__get_packed_size (const CellMessage *message); size_t cell_message__pack (const CellMessage *message, uint8_t *out); size_t cell_message__pack_to_buffer (const CellMessage *message, ProtobufCBuffer *buffer); CellMessage * cell_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void cell_message__free_unpacked (CellMessage *message, ProtobufCAllocator *allocator); /* VersionedCellMessage methods */ void versioned_cell_message__init (VersionedCellMessage *message); size_t versioned_cell_message__get_packed_size (const VersionedCellMessage *message); size_t versioned_cell_message__pack (const VersionedCellMessage *message, uint8_t *out); size_t versioned_cell_message__pack_to_buffer (const VersionedCellMessage *message, ProtobufCBuffer *buffer); VersionedCellMessage * versioned_cell_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void versioned_cell_message__free_unpacked (VersionedCellMessage *message, ProtobufCAllocator *allocator); /* ServerMessage methods */ void server_message__init (ServerMessage *message); size_t server_message__get_packed_size (const ServerMessage *message); size_t server_message__pack (const ServerMessage *message, uint8_t *out); size_t server_message__pack_to_buffer (const ServerMessage *message, ProtobufCBuffer *buffer); ServerMessage * server_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void server_message__free_unpacked (ServerMessage *message, ProtobufCAllocator *allocator); /* ClientMessage methods */ void client_message__init (ClientMessage *message); size_t client_message__get_packed_size (const ClientMessage *message); size_t client_message__pack (const ClientMessage *message, uint8_t *out); size_t client_message__pack_to_buffer (const ClientMessage *message, ProtobufCBuffer *buffer); ClientMessage * client_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void client_message__free_unpacked (ClientMessage *message, ProtobufCAllocator *allocator); /* WriteQueryMessage methods */ void write_query_message__init (WriteQueryMessage *message); size_t write_query_message__get_packed_size (const WriteQueryMessage *message); size_t write_query_message__pack (const WriteQueryMessage *message, uint8_t *out); size_t write_query_message__pack_to_buffer (const WriteQueryMessage *message, ProtobufCBuffer *buffer); WriteQueryMessage * write_query_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void write_query_message__free_unpacked (WriteQueryMessage *message, ProtobufCAllocator *allocator); /* ReadQueryMessage methods */ void read_query_message__init (ReadQueryMessage *message); size_t read_query_message__get_packed_size (const ReadQueryMessage *message); size_t read_query_message__pack (const ReadQueryMessage *message, uint8_t *out); size_t read_query_message__pack_to_buffer (const ReadQueryMessage *message, ProtobufCBuffer *buffer); ReadQueryMessage * read_query_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void read_query_message__free_unpacked (ReadQueryMessage *message, ProtobufCAllocator *allocator); /* AckMessage methods */ void ack_message__init (AckMessage *message); size_t ack_message__get_packed_size (const AckMessage *message); size_t ack_message__pack (const AckMessage *message, uint8_t *out); size_t ack_message__pack_to_buffer (const AckMessage *message, ProtobufCBuffer *buffer); AckMessage * ack_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void ack_message__free_unpacked (AckMessage *message, ProtobufCAllocator *allocator); /* RangeReadQueryMessage methods */ void range_read_query_message__init (RangeReadQueryMessage *message); size_t range_read_query_message__get_packed_size (const RangeReadQueryMessage *message); size_t range_read_query_message__pack (const RangeReadQueryMessage *message, uint8_t *out); size_t range_read_query_message__pack_to_buffer (const RangeReadQueryMessage *message, ProtobufCBuffer *buffer); RangeReadQueryMessage * range_read_query_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void range_read_query_message__free_unpacked (RangeReadQueryMessage *message, ProtobufCAllocator *allocator); /* RangeReadResponseMessage methods */ void range_read_response_message__init (RangeReadResponseMessage *message); size_t range_read_response_message__get_packed_size (const RangeReadResponseMessage *message); size_t range_read_response_message__pack (const RangeReadResponseMessage *message, uint8_t *out); size_t range_read_response_message__pack_to_buffer (const RangeReadResponseMessage *message, ProtobufCBuffer *buffer); RangeReadResponseMessage * range_read_response_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void range_read_response_message__free_unpacked (RangeReadResponseMessage *message, ProtobufCAllocator *allocator); /* TxnMessage methods */ void txn_message__init (TxnMessage *message); size_t txn_message__get_packed_size (const TxnMessage *message); size_t txn_message__pack (const TxnMessage *message, uint8_t *out); size_t txn_message__pack_to_buffer (const TxnMessage *message, ProtobufCBuffer *buffer); TxnMessage * txn_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void txn_message__free_unpacked (TxnMessage *message, ProtobufCAllocator *allocator); /* QueueQueryMessage methods */ void queue_query_message__init (QueueQueryMessage *message); size_t queue_query_message__get_packed_size (const QueueQueryMessage *message); size_t queue_query_message__pack (const QueueQueryMessage *message, uint8_t *out); size_t queue_query_message__pack_to_buffer (const QueueQueryMessage *message, ProtobufCBuffer *buffer); QueueQueryMessage * queue_query_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void queue_query_message__free_unpacked (QueueQueryMessage *message, ProtobufCAllocator *allocator); /* ConsumerID methods */ void consumer_id__init (ConsumerID *message); size_t consumer_id__get_packed_size (const ConsumerID *message); size_t consumer_id__pack (const ConsumerID *message, uint8_t *out); size_t consumer_id__pack_to_buffer (const ConsumerID *message, ProtobufCBuffer *buffer); ConsumerID * consumer_id__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void consumer_id__free_unpacked (ConsumerID *message, ProtobufCAllocator *allocator); /* CreateQueueMessage methods */ void create_queue_message__init (CreateQueueMessage *message); size_t create_queue_message__get_packed_size (const CreateQueueMessage *message); size_t create_queue_message__pack (const CreateQueueMessage *message, uint8_t *out); size_t create_queue_message__pack_to_buffer (const CreateQueueMessage *message, ProtobufCBuffer *buffer); CreateQueueMessage * create_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void create_queue_message__free_unpacked (CreateQueueMessage *message, ProtobufCAllocator *allocator); /* DeleteQueueMessage methods */ void delete_queue_message__init (DeleteQueueMessage *message); size_t delete_queue_message__get_packed_size (const DeleteQueueMessage *message); size_t delete_queue_message__pack (const DeleteQueueMessage *message, uint8_t *out); size_t delete_queue_message__pack_to_buffer (const DeleteQueueMessage *message, ProtobufCBuffer *buffer); DeleteQueueMessage * delete_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void delete_queue_message__free_unpacked (DeleteQueueMessage *message, ProtobufCAllocator *allocator); /* SubscribeQueueMessage methods */ void subscribe_queue_message__init (SubscribeQueueMessage *message); size_t subscribe_queue_message__get_packed_size (const SubscribeQueueMessage *message); size_t subscribe_queue_message__pack (const SubscribeQueueMessage *message, uint8_t *out); size_t subscribe_queue_message__pack_to_buffer (const SubscribeQueueMessage *message, ProtobufCBuffer *buffer); SubscribeQueueMessage * subscribe_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void subscribe_queue_message__free_unpacked (SubscribeQueueMessage *message, ProtobufCAllocator *allocator); /* UnsubscribeQueueMessage methods */ void unsubscribe_queue_message__init (UnsubscribeQueueMessage *message); size_t unsubscribe_queue_message__get_packed_size (const UnsubscribeQueueMessage *message); size_t unsubscribe_queue_message__pack (const UnsubscribeQueueMessage *message, uint8_t *out); size_t unsubscribe_queue_message__pack_to_buffer (const UnsubscribeQueueMessage *message, ProtobufCBuffer *buffer); UnsubscribeQueueMessage * unsubscribe_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void unsubscribe_queue_message__free_unpacked (UnsubscribeQueueMessage *message, ProtobufCAllocator *allocator); /* EnqueueMessage methods */ void enqueue_message__init (EnqueueMessage *message); size_t enqueue_message__get_packed_size (const EnqueueMessage *message); size_t enqueue_message__pack (const EnqueueMessage *message, uint8_t *out); size_t enqueue_message__pack_to_buffer (const EnqueueMessage *message, ProtobufCBuffer *buffer); EnqueueMessage * enqueue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void enqueue_message__free_unpacked (EnqueueMessage *message, ProtobufCAllocator *allocator); /* EnqueueResponseMessage methods */ void enqueue_response_message__init (EnqueueResponseMessage *message); size_t enqueue_response_message__get_packed_size (const EnqueueResponseMessage *message); size_t enqueue_response_message__pack (const EnqueueResponseMessage *message, uint8_t *out); size_t enqueue_response_message__pack_to_buffer (const EnqueueResponseMessage *message, ProtobufCBuffer *buffer); EnqueueResponseMessage * enqueue_response_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void enqueue_response_message__free_unpacked (EnqueueResponseMessage *message, ProtobufCAllocator *allocator); /* ReadQueueMessage methods */ void read_queue_message__init (ReadQueueMessage *message); size_t read_queue_message__get_packed_size (const ReadQueueMessage *message); size_t read_queue_message__pack (const ReadQueueMessage *message, uint8_t *out); size_t read_queue_message__pack_to_buffer (const ReadQueueMessage *message, ProtobufCBuffer *buffer); ReadQueueMessage * read_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void read_queue_message__free_unpacked (ReadQueueMessage *message, ProtobufCAllocator *allocator); /* ReadQueueResponseMessage methods */ void read_queue_response_message__init (ReadQueueResponseMessage *message); size_t read_queue_response_message__get_packed_size (const ReadQueueResponseMessage *message); size_t read_queue_response_message__pack (const ReadQueueResponseMessage *message, uint8_t *out); size_t read_queue_response_message__pack_to_buffer (const ReadQueueResponseMessage *message, ProtobufCBuffer *buffer); ReadQueueResponseMessage * read_queue_response_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void read_queue_response_message__free_unpacked (ReadQueueResponseMessage *message, ProtobufCAllocator *allocator); /* ConsumeQueueMessage methods */ void consume_queue_message__init (ConsumeQueueMessage *message); size_t consume_queue_message__get_packed_size (const ConsumeQueueMessage *message); size_t consume_queue_message__pack (const ConsumeQueueMessage *message, uint8_t *out); size_t consume_queue_message__pack_to_buffer (const ConsumeQueueMessage *message, ProtobufCBuffer *buffer); ConsumeQueueMessage * consume_queue_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void consume_queue_message__free_unpacked (ConsumeQueueMessage *message, ProtobufCAllocator *allocator); /* ConsumeQueueResponseMessage methods */ void consume_queue_response_message__init (ConsumeQueueResponseMessage *message); size_t consume_queue_response_message__get_packed_size (const ConsumeQueueResponseMessage *message); size_t consume_queue_response_message__pack (const ConsumeQueueResponseMessage *message, uint8_t *out); size_t consume_queue_response_message__pack_to_buffer (const ConsumeQueueResponseMessage *message, ProtobufCBuffer *buffer); ConsumeQueueResponseMessage * consume_queue_response_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void consume_queue_response_message__free_unpacked (ConsumeQueueResponseMessage *message, ProtobufCAllocator *allocator); /* --- per-message closures --- */ typedef void (*NodeStateMessage_Closure) (const NodeStateMessage *message, void *closure_data); typedef void (*VectorClockMessage_Closure) (const VectorClockMessage *message, void *closure_data); typedef void (*GossipMessage_Closure) (const GossipMessage *message, void *closure_data); typedef void (*GossipListenMessage_Closure) (const GossipListenMessage *message, void *closure_data); typedef void (*MembershipViewMessage_Closure) (const MembershipViewMessage *message, void *closure_data); typedef void (*MembershipAgreementMessage_Closure) (const MembershipAgreementMessage *message, void *closure_data); typedef void (*CellAddressMessage_Closure) (const CellAddressMessage *message, void *closure_data); typedef void (*CellMessage_Closure) (const CellMessage *message, void *closure_data); typedef void (*VersionedCellMessage_Closure) (const VersionedCellMessage *message, void *closure_data); typedef void (*ServerMessage_Closure) (const ServerMessage *message, void *closure_data); typedef void (*ClientMessage_Closure) (const ClientMessage *message, void *closure_data); typedef void (*WriteQueryMessage_Closure) (const WriteQueryMessage *message, void *closure_data); typedef void (*ReadQueryMessage_Closure) (const ReadQueryMessage *message, void *closure_data); typedef void (*AckMessage_Closure) (const AckMessage *message, void *closure_data); typedef void (*RangeReadQueryMessage_Closure) (const RangeReadQueryMessage *message, void *closure_data); typedef void (*RangeReadResponseMessage_Closure) (const RangeReadResponseMessage *message, void *closure_data); typedef void (*TxnMessage_Closure) (const TxnMessage *message, void *closure_data); typedef void (*QueueQueryMessage_Closure) (const QueueQueryMessage *message, void *closure_data); typedef void (*ConsumerID_Closure) (const ConsumerID *message, void *closure_data); typedef void (*CreateQueueMessage_Closure) (const CreateQueueMessage *message, void *closure_data); typedef void (*DeleteQueueMessage_Closure) (const DeleteQueueMessage *message, void *closure_data); typedef void (*SubscribeQueueMessage_Closure) (const SubscribeQueueMessage *message, void *closure_data); typedef void (*UnsubscribeQueueMessage_Closure) (const UnsubscribeQueueMessage *message, void *closure_data); typedef void (*EnqueueMessage_Closure) (const EnqueueMessage *message, void *closure_data); typedef void (*EnqueueResponseMessage_Closure) (const EnqueueResponseMessage *message, void *closure_data); typedef void (*ReadQueueMessage_Closure) (const ReadQueueMessage *message, void *closure_data); typedef void (*ReadQueueResponseMessage_Closure) (const ReadQueueResponseMessage *message, void *closure_data); typedef void (*ConsumeQueueMessage_Closure) (const ConsumeQueueMessage *message, void *closure_data); typedef void (*ConsumeQueueResponseMessage_Closure) (const ConsumeQueueResponseMessage *message, void *closure_data); /* --- services --- */ /* --- descriptors --- */ extern const ProtobufCMessageDescriptor node_state_message__descriptor; extern const ProtobufCMessageDescriptor vector_clock_message__descriptor; extern const ProtobufCMessageDescriptor gossip_message__descriptor; extern const ProtobufCMessageDescriptor gossip_listen_message__descriptor; extern const ProtobufCMessageDescriptor membership_view_message__descriptor; extern const ProtobufCMessageDescriptor membership_agreement_message__descriptor; extern const ProtobufCMessageDescriptor cell_address_message__descriptor; extern const ProtobufCMessageDescriptor cell_message__descriptor; extern const ProtobufCMessageDescriptor versioned_cell_message__descriptor; extern const ProtobufCMessageDescriptor server_message__descriptor; extern const ProtobufCMessageDescriptor client_message__descriptor; extern const ProtobufCMessageDescriptor write_query_message__descriptor; extern const ProtobufCMessageDescriptor read_query_message__descriptor; extern const ProtobufCMessageDescriptor ack_message__descriptor; extern const ProtobufCMessageDescriptor range_read_query_message__descriptor; extern const ProtobufCMessageDescriptor range_read_response_message__descriptor; extern const ProtobufCMessageDescriptor txn_message__descriptor; extern const ProtobufCMessageDescriptor queue_query_message__descriptor; extern const ProtobufCMessageDescriptor consumer_id__descriptor; extern const ProtobufCMessageDescriptor create_queue_message__descriptor; extern const ProtobufCMessageDescriptor delete_queue_message__descriptor; extern const ProtobufCMessageDescriptor subscribe_queue_message__descriptor; extern const ProtobufCMessageDescriptor unsubscribe_queue_message__descriptor; extern const ProtobufCMessageDescriptor enqueue_message__descriptor; extern const ProtobufCMessageDescriptor enqueue_response_message__descriptor; extern const ProtobufCMessageDescriptor read_queue_message__descriptor; extern const ProtobufCMessageDescriptor read_queue_response_message__descriptor; extern const ProtobufCMessageDescriptor consume_queue_message__descriptor; extern const ProtobufCMessageDescriptor consume_queue_response_message__descriptor; PROTOBUF_C__END_DECLS #endif /* PROTOBUF_C_backend_2ffailure_5fdetector_2fdb_5fmessages_2eproto__INCLUDED */ ================================================ FILE: backend/failure_detector/db_messages.proto ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ syntax = "proto2"; // Membership protocol: message NodeStateMessage { required int32 status=1; // 0 - dead, 1 - ready, 2 - alive but not ready required int32 node_id=2; required bytes hostname=3; required int32 port=4; required int32 rack_id=5; required int32 dc_id=6; } message VectorClockMessage { repeated int32 ids=1; repeated int64 counters=2; } message GossipMessage { required NodeStateMessage node_state=1; required VectorClockMessage vc=2; } message GossipListenMessage { required NodeStateMessage node_state=1; required int64 nonce=2; } message MembershipViewMessage { repeated NodeStateMessage membership=1; repeated NodeStateMessage client_membership=2; required VectorClockMessage view_id=3; } message MembershipAgreementMessage { required int32 msg_type=1; // 0 - PROPOSE, 1 - RESPONSE, 2 - NOTIFY, 3 - RETRY_LINK, 4 - NOTIFY_ACK required int32 ack_status=2; // 0 - ACK, 1 - NACK, 2 - UNINIT optional MembershipViewMessage view=3; required int64 nonce=4; required VectorClockMessage vc=5; } // DB cells and Queue entries: message CellAddressMessage { required int64 table_key=1; repeated int64 keys=2; } message CellMessage { required int64 table_key=1; repeated int64 keys=2; repeated int64 columns=3; } message VersionedCellMessage { required int64 table_key=1; repeated int64 keys=2; repeated int64 columns=3; required bytes blob=4; optional VectorClockMessage version=5; // optional int64 version_no=6; } // DB queries: message ServerMessage { required int32 mtype=1; // {RPC_TYPE_WRITE, RPC_TYPE_READ, RPC_TYPE_RANGE_READ, RPC_TYPE_QUEUE, RPC_TYPE_TXN, RPC_TYPE_GOSSIP_LISTEN} optional WriteQueryMessage wm=2; optional ReadQueryMessage rm=3; optional RangeReadQueryMessage rrm=4; optional QueueQueryMessage qm=5; optional TxnMessage tm=6; optional GossipListenMessage gl=7; optional VectorClockMessage vc=8; } message ClientMessage { required int32 mtype=1; // {RPC_TYPE_ACK, RPC_TYPE_WRITE, RPC_TYPE_RANGE_READ_RESPONSE, RPC_TYPE_QUEUE, RPC_TYPE_TXN} optional AckMessage am=2; optional WriteQueryMessage wm=3; optional RangeReadResponseMessage rrrm=4; optional QueueQueryMessage qm=5; optional TxnMessage tm=6; optional VectorClockMessage vc=7; } message WriteQueryMessage { optional VersionedCellMessage cell=1; // CellMessage required bytes txnid=2; required int64 nonce=3; required int32 msg_type=4; // {RPC_TYPE_WRITE, RPC_TYPE_DELETE} required int32 mtype=5; } message ReadQueryMessage { required CellAddressMessage cell_address=1; required bytes txnid=2; required int64 nonce=3; required int32 mtype=4; } message AckMessage { optional CellAddressMessage cell_address=1; required int32 status=2; // 0 - ACK, 1 - NACK required bytes txnid=3; required int64 nonce=4; required int32 mtype=5; } message RangeReadQueryMessage { required CellAddressMessage start_cell_address=1; required CellAddressMessage end_cell_address=2; required bytes txnid=3; required int64 nonce=4; required int32 mtype=5; } message RangeReadResponseMessage { repeated VersionedCellMessage cells=1; required bytes txnid=2; required int64 nonce=3; required int32 mtype=4; } // Txn messages: message TxnMessage { required int32 type=1; // BEGIN=0, VALIDATION=1, COMMIT=2, ABORT=3 repeated VersionedCellMessage own_read_set=2; repeated VersionedCellMessage own_write_set=3; repeated VersionedCellMessage complete_read_set=4; repeated VersionedCellMessage complete_write_set=5; required bytes txnid=6; required int64 nonce=7; optional VectorClockMessage version=8; required int32 mtype=9; } // Queue messages: message QueueQueryMessage { required CellAddressMessage queue_address=1; required int32 msg_type=2; // QUERY_TYPE_{CREATE_QUEUE, DELETE_QUEUE, SUBSCRIBE_QUEUE, UNSUBSCRIBE_QUEUE, ENQUEUE, READ_QUEUE, CONSUME_QUEUE, READ_QUEUE_RESPONSE, NOTIFICATION} required int32 app_id=3; required int32 shard_id=4; required int32 consumer_id=5; required int32 group_id=6; required int32 queue_index=7; required int32 status=8; repeated VersionedCellMessage cells=9; required bytes txnid=10; required int64 nonce=11; required int32 mtype=12; } // Below message types are obsolete: message ConsumerID { required int32 app_id=1; required int32 shard_id=2; required int32 consumer_id=3; } message CreateQueueMessage { required CellAddressMessage queue_address=1; required bytes txnid=2; required int64 nonce=3; } message DeleteQueueMessage { required CellAddressMessage queue_address=1; required bytes txnid=2; required int64 nonce=3; } message SubscribeQueueMessage { required CellAddressMessage queue_address=1; required ConsumerID consumer_id=2; required bytes txnid=3; required int64 nonce=4; } message UnsubscribeQueueMessage { required CellAddressMessage queue_address=1; required ConsumerID consumer_id=2; required bytes txnid=3; required int64 nonce=4; } message EnqueueMessage { repeated VersionedCellMessage cells=1; // CellMessage required bytes txnid=2; required int64 nonce=3; } message EnqueueResponseMessage { required CellAddressMessage queue_address=1; required int64 last_item_id=2; required bytes txnid=3; required int64 nonce=4; } message ReadQueueMessage { required CellAddressMessage queue_address=1; required ConsumerID consumer_id=2; required int64 max_items=3; required bytes txnid=4; required int64 nonce=5; } message ReadQueueResponseMessage { repeated VersionedCellMessage queue_entries=1; required ConsumerID consumer_id=2; required bytes txnid=3; required int64 nonce=4; } message ConsumeQueueMessage { required CellAddressMessage queue_address=1; required ConsumerID consumer_id=2; required int64 new_consume_head=3; required bytes txnid=4; required int64 nonce=5; } message ConsumeQueueResponseMessage { required CellAddressMessage queue_address=1; required ConsumerID consumer_id=2; required int32 status=3; // 0 - ACK, 1 - NACK required int64 new_consume_head=4; required bytes txnid=5; required int64 nonce=6; } ================================================ FILE: backend/failure_detector/db_messages_test.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * db_messages_test.c * * Author: aagapi */ #include "vector_clock.h" #include "fd.h" #include "cells.h" #include "db_queries.h" #include #include #include #include #include #define MAX_MSG_SIZE_VC 1024 int write_msg_to_file (unsigned char *buff, unsigned len, FILE * fp) { unsigned written = fwrite(buff, len, 1, fp); // printf("Wrote %d / %d bytes to file\n", written * len, len); return (written == 1)? 0 : -1; } int read_msg_from_file (unsigned max_length, unsigned char *buff, FILE * fp) { unsigned cur_len = 0; unsigned nread; while ((nread=fread(buff + cur_len, 1, max_length - cur_len, fp)) != 0) { printf("Read %d bytes\n", nread); cur_len += nread; if (cur_len == max_length) { fprintf(stderr, "max message length exceeded\n"); return -1; } } return cur_len; } void write_read_from_file(void * buf_w, unsigned len_w, unsigned char *buf_r, unsigned * len_r) { // Serialize it to file: FILE * fptr_w = fopen("/tmp/vc.test","wb"); int success = write_msg_to_file(buf_w, len_w, fptr_w); assert(success == 0); fclose(fptr_w); // Read it back: FILE * fptr_r = fopen("/tmp/vc.test","rb"); *len_r = read_msg_from_file(MAX_MSG_SIZE_VC, buf_r, fptr_r); if(*len_r != len_w) { printf("len_r=%d != len_w=%d\n", *len_r, len_w); assert(0); } fclose(fptr_r); } int main (int argc, const char * argv[]) { FILE *fptr_w = NULL, * fptr_r = NULL; void * buf_w; unsigned len_w; unsigned char buf_r[MAX_MSG_SIZE_VC]; // void * buf_r = malloc(MAX_MSG_SIZE_VC); unsigned len_r; char err_msg[1024], err_msg2[1024]; // Generate a dummy VC message: int node_ids[] = {0,1}; int64_t counters[] = {0,0}; vector_clock * vc = init_vc(2, node_ids, counters, 1), * vc_r = NULL; add_component_vc(vc, 2, 0); increment_vc(vc, 0); increment_vc(vc, 0); increment_vc(vc, 1); increment_vc(vc, 2); increment_vc(vc, 2); serialize_vc(vc, &buf_w, &len_w); write_read_from_file(buf_w, len_w, buf_r, &len_r); deserialize_vc(buf_r, len_r, &vc_r); printf("VC message: %s\n", to_string_vc(vc, err_msg)); if(compare_vc(vc, vc_r) != 0) { printf("VC read mismatch (%s)!\n", to_string_vc(vc_r, err_msg)); assert(0); } // Generate dummy GS message: gossip_state * gs = init_gossip_state(0, 0, 0, 0, "localhost", 32000, vc), * gs_r = NULL; serialize_gs(gs, &buf_w, &len_w); write_read_from_file(buf_w, len_w, buf_r, &len_r); deserialize_gs(buf_r, len_r, &gs_r); printf("GossipState message: %s\n", to_string_gs(gs, err_msg)); if(!equals_gs(gs, gs_r)) { printf("GS read mismatch (%s)!\n", to_string_gs(gs_r, err_msg)); assert(0); } // Generate dummy Membership State message: node_description * nds = (node_description *) malloc(3 * sizeof(node_description)); copy_node_description(&nds[0], 0, 0, 0, 0, "localhost", 32000); copy_node_description(&nds[1], 0, 1, 0, 0, "localhost", 32001); copy_node_description(&nds[2], 1, 2, 0, 0, "localhost", 32002); node_description * client_nds = (node_description *) malloc(1 * sizeof(node_description)); copy_node_description(&client_nds[0], 0, 0, 0, 0, "localhost", 22000); membership_state * ms = init_membership_state(3, nds, 1, client_nds, vc), * ms_r = NULL; serialize_membership_state(ms, &buf_w, &len_w); write_read_from_file(buf_w, len_w, buf_r, &len_r); deserialize_membership_state(buf_r, len_r, &ms_r); printf("MembershipState message: %s\n", to_string_membership_state(ms, err_msg)); if(!equals_membership_state(ms, ms_r)) { printf("MembershipState read mismatch (%s)!\n", to_string_membership_state(ms_r, err_msg)); assert(0); } // Generate dummy Membership Agreement message: membership_agreement_msg * ma = init_membership_agreement_msg(MEMBERSHIP_AGREEMENT_PROPOSE, 0, ms, 0, vc), * ma_r = NULL; serialize_membership_agreement_msg(ma, &buf_w, &len_w); write_read_from_file(buf_w, len_w, buf_r, &len_r); unsigned msg_len = ((unsigned *) buf_r)[0]; deserialize_membership_agreement_msg(buf_r + sizeof(int), msg_len, &ma_r); printf("MembershipAgreement message: %s\n", to_string_membership_agreement_msg(ma, err_msg)); if(!equals_membership_agreement_msg(ma, ma_r)) { printf("MembershipAgreement read mismatch (%s)!\n", to_string_membership_agreement_msg(ma_r, err_msg)); assert(0); } // Generate a dummy Cell and CellAddress: int64_t key = 1, end_key = 3; int64_t column = 1, end_column = 5; uuid_t txnid; uuid_generate(txnid); int no_cells = 2; cell * cll = (cell *) malloc(no_cells * sizeof(cell)); for(int i=0;i #include #include #include #include void free_server_msg(ServerMessage * m); void free_client_msg(ClientMessage * m); // Write Query: write_query * init_write_query(cell * cell, int msg_type, uuid_t * txnid, int64_t nonce) { write_query * ca = (write_query *) malloc(sizeof(write_query)); ca->cell = cell; ca->msg_type = msg_type; ca->txnid = txnid; ca->nonce = nonce; return ca; } write_query * init_write_query_copy(cell * cell, int msg_type, uuid_t * txnid, int64_t nonce) { write_query * ca = (write_query *) malloc(sizeof(write_query)); ca->cell = (cell != NULL)?(init_cell_copy(cell->table_key, cell->keys, cell->no_keys, cell->columns, cell->no_columns, cell->last_blob, cell->last_blob_size, cell->version)):(NULL); ca->msg_type = msg_type; if(txnid != NULL) { ca->txnid = malloc(sizeof(uuid_t)); memcpy(ca->txnid, txnid, sizeof(uuid_t)); } else { ca->txnid = NULL; } ca->nonce = nonce; return ca; } write_query * build_insert_in_txn(WORD * column_values, int no_cols, int no_primary_keys, int no_clustering_keys, WORD blob, size_t blob_size, WORD table_key, uuid_t * txnid, int64_t nonce) { int no_keys = no_primary_keys + no_clustering_keys; assert(no_cols > no_keys || (blob != NULL && blob_size > 0)); cell * c = init_cell((int64_t) table_key, (int64_t *) column_values, no_keys, ((int64_t *) column_values + no_keys), no_cols - no_keys, blob, blob_size, NULL); return init_write_query_copy(c, RPC_TYPE_WRITE, txnid, nonce); } write_query * build_delete_row_in_txn(WORD* primary_keys, int no_primary_keys, WORD table_key, uuid_t * txnid, int64_t nonce) { cell * c = init_cell((int64_t) table_key, (int64_t *) primary_keys, no_primary_keys, NULL, 0, NULL, 0, NULL); return init_write_query_copy(c, RPC_TYPE_DELETE, txnid, nonce); } write_query * build_delete_cell_in_txn(WORD* keys, int no_primary_keys, int no_clustering_keys, WORD table_key, uuid_t * txnid, int64_t nonce) { cell * c = init_cell((int64_t) table_key, (int64_t *) keys, no_primary_keys + no_clustering_keys, NULL, 0, NULL, 0, NULL); return init_write_query_copy(c, RPC_TYPE_DELETE, txnid, nonce); } write_query * build_delete_by_index_in_txn(WORD index_key, int idx_idx, WORD table_key, uuid_t * txnid, int64_t nonce) { assert (0); // Not supported return 0; } write_query * build_update_in_txn(int * col_idxs, int no_cols, WORD * column_values, WORD blob, size_t blob_size, WORD table_key, uuid_t * txnid, int64_t nonce) { assert (0); // Not supported return 0; } void free_write_query(write_query * ca) { free_cell(ca->cell); free(ca); } void init_write_query_msg(WriteQueryMessage * msg, write_query * ca, VersionedCellMessage * vcell_msg) { if(ca->txnid != NULL) { msg->txnid.len = sizeof(uuid_t); msg->txnid.data = malloc(sizeof(uuid_t)); memcpy(msg->txnid.data, ca->txnid, sizeof(uuid_t)); } else { msg->txnid.data = NULL; msg->txnid.len = 0; } msg->nonce = ca->nonce; msg->cell = vcell_msg; msg->msg_type = ca->msg_type; } write_query * init_write_query_from_msg(WriteQueryMessage * msg) { cell * cell = init_cell_from_msg(msg->cell); write_query * c = init_write_query_copy(cell, msg->msg_type, (uuid_t *) msg->txnid.data, msg->nonce); return c; } void free_write_query_msg(WriteQueryMessage * msg) { // if(msg->txnid.data != NULL) // free(msg->txnid.data); if(msg->cell != NULL) free_cell_msg(msg->cell); } int serialize_write_query(write_query * ca, void ** buf, unsigned * len, short for_server, vector_clock * vc) { WriteQueryMessage msg = WRITE_QUERY_MESSAGE__INIT; VersionedCellMessage vcell_msg = VERSIONED_CELL_MESSAGE__INIT; VectorClockMessage vc_msg = VECTOR_CLOCK_MESSAGE__INIT; if(ca->cell != NULL) init_cell_msg(&vcell_msg, ca->cell, &vc_msg); init_write_query_msg(&msg, ca, (ca->cell != NULL)?(&vcell_msg):(NULL)); msg.mtype = RPC_TYPE_WRITE; if(for_server) { ServerMessage sm = SERVER_MESSAGE__INIT; sm.mtype = RPC_TYPE_WRITE; sm.wm = &msg; sm.rm = NULL; sm.rrm = NULL; sm.qm = NULL; sm.tm = NULL; sm.gl = NULL; if(vc != NULL) { VectorClockMessage lc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&lc_msg, vc); sm.vc = &lc_msg; } else { sm.vc = NULL; } *len = server_message__get_packed_size (&sm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); server_message__pack (&sm, (void *) ((int *)(*buf) + 1)); free_server_msg(&sm); } else { ClientMessage cm = CLIENT_MESSAGE__INIT; cm.mtype = RPC_TYPE_WRITE; cm.am = NULL; cm.wm = &msg; cm.rrrm = NULL; cm.qm = NULL; cm.tm = NULL; if(vc != NULL) { VectorClockMessage lc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&lc_msg, vc); cm.vc = &lc_msg; } else { cm.vc = NULL; } *len = client_message__get_packed_size (&cm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); client_message__pack (&cm, (void *) ((int *)(*buf) + 1)); free_client_msg(&cm); } return 0; } int deserialize_write_query(void * buf, unsigned msg_len, write_query ** ca) { WriteQueryMessage * msg = write_query_message__unpack (NULL, msg_len, buf); if (msg == NULL) { log_error("Error unpacking write query message, msg is NULL"); return 1; } else if (msg->mtype != RPC_TYPE_WRITE) { log_error("Error unpacking write query message, msg->mtype is not RPC_TYPE_WRITE: %d", msg->mtype); return 1; } *ca = init_write_query_from_msg(msg); write_query_message__free_unpacked(msg, NULL); return 0; } char * to_string_write_query(write_query * ca, char * msg_buff) { char * crt_ptr = msg_buff; char uuid_str[37]; if(ca->txnid != NULL) uuid_unparse_lower(*(ca->txnid), uuid_str); else uuid_str[0]='\0'; sprintf(crt_ptr, "%s(txnid=%s, nonce=%" PRId64 ", cell=", (ca->msg_type == RPC_TYPE_WRITE)?("WriteQuery"):("DeleteQuery"), uuid_str, ca->nonce); crt_ptr += strlen(crt_ptr); if(ca->cell != NULL) { to_string_cell(ca->cell, crt_ptr); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, ")"); return msg_buff; } int equals_write_query(write_query * ca1, write_query * ca2) { if(ca1->nonce != ca2->nonce || ca1->msg_type != ca2->msg_type || !equals_cell(ca1->cell, ca2->cell)) return 0; if(ca1->txnid != NULL && ca2->txnid && uuid_compare(*(ca1->txnid), *(ca2->txnid))) return 0; return 1; } // Read Query: read_query * init_read_query(cell_address * cell_address, uuid_t * txnid, int64_t nonce) { read_query * ca = (read_query *) malloc(sizeof(read_query)); ca->cell_address = cell_address; ca->txnid = txnid; ca->nonce = nonce; return ca; } read_query * init_read_query_copy(cell_address * cell_address, uuid_t * txnid, int64_t nonce) { read_query * ca = (read_query *) malloc(sizeof(read_query)); ca->cell_address = init_cell_address_copy(cell_address->table_key, cell_address->keys, cell_address->no_keys); if(txnid != NULL) { ca->txnid = malloc(sizeof(uuid_t)); memcpy(ca->txnid, txnid, sizeof(uuid_t)); } else { ca->txnid = NULL; } ca->nonce = nonce; return ca; } read_query * build_search_in_txn(WORD* primary_keys, int no_primary_keys, WORD table_key, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_copy((int64_t) table_key, (int64_t *) primary_keys, no_primary_keys); return init_read_query_copy(c, txnid, nonce); } read_query * build_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD table_key, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_copy2((int64_t) table_key, (int64_t *) primary_keys, no_primary_keys, (int64_t *) clustering_keys, no_clustering_keys); return init_read_query_copy(c, txnid, nonce); } read_query * build_search_columns_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD* col_keys, int no_columns, WORD table_key, uuid_t * txnid, int64_t nonce) { assert(0); // Not supported return NULL; } read_query * build_search_index_in_txn(WORD index_key, int idx_idx, WORD table_key, uuid_t * txnid, int64_t nonce) { assert(0); // Not supported return NULL; } void free_read_query(read_query * ca) { free_cell_address(ca->cell_address); free(ca); } void init_read_query_msg(ReadQueryMessage * msg, read_query * ca, CellAddressMessage * cell_address_msg) { if(ca->txnid != NULL) { msg->txnid.len = sizeof(uuid_t); msg->txnid.data = malloc(sizeof(uuid_t)); memcpy(msg->txnid.data, ca->txnid, sizeof(uuid_t)); } else { msg->txnid.data = NULL; msg->txnid.len = 0; } msg->nonce = ca->nonce; msg->cell_address = cell_address_msg; } read_query * init_read_query_from_msg(ReadQueryMessage * msg) { cell_address * cell_address = init_cell_address_from_msg(msg->cell_address); read_query * c = init_read_query_copy(cell_address, (uuid_t *) msg->txnid.data, msg->nonce); return c; } void free_read_query_msg(ReadQueryMessage * msg) { free_cell_address_msg(msg->cell_address); // if(msg->txnid.data != NULL) // free(msg->txnid.data); } int serialize_read_query(read_query * ca, void ** buf, unsigned * len, vector_clock * vc) { ReadQueryMessage msg = READ_QUERY_MESSAGE__INIT; CellAddressMessage cell_address_msg = CELL_ADDRESS_MESSAGE__INIT; init_cell_address_msg(&cell_address_msg, ca->cell_address); init_read_query_msg(&msg, ca, &cell_address_msg); msg.mtype = RPC_TYPE_READ; ServerMessage sm = SERVER_MESSAGE__INIT; sm.mtype = RPC_TYPE_READ; sm.wm = NULL; sm.rm = &msg; sm.rrm = NULL; sm.qm = NULL; sm.tm = NULL; sm.gl = NULL; if(vc != NULL) { VectorClockMessage lc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&lc_msg, vc); sm.vc = &lc_msg; } else { sm.vc = NULL; } *len = server_message__get_packed_size (&sm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); server_message__pack (&sm, (void *) ((int *)(*buf) + 1)); free_server_msg(&sm); return 0; } int deserialize_read_query(void * buf, unsigned msg_len, read_query ** ca) { ReadQueryMessage * msg = read_query_message__unpack (NULL, msg_len, buf); if (msg == NULL) { log_error("Error unpacking read query message, msg is NULL"); return 1; } else if (msg->mtype != RPC_TYPE_READ) { log_error("Error unpacking read query message, msg->mtype is not RPC_TYPE_READ: %d", msg->mtype); return 1; } *ca = init_read_query_from_msg(msg); read_query_message__free_unpacked(msg, NULL); return 0; } char * to_string_read_query(read_query * ca, char * msg_buff) { char * crt_ptr = msg_buff; char uuid_str[37]; if(ca->txnid != NULL) uuid_unparse_lower(*(ca->txnid), uuid_str); else uuid_str[0]='\0'; sprintf(crt_ptr, "ReadQuery(txnid=%s, nonce=%" PRId64 ", ", uuid_str, ca->nonce); crt_ptr += strlen(crt_ptr); to_string_cell_address(ca->cell_address, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ")"); return msg_buff; } int equals_read_query(read_query * ca1, read_query * ca2) { if(ca1->nonce != ca2->nonce || !equals_cell_address(ca1->cell_address, ca2->cell_address)) return 0; if(ca1->txnid != NULL && ca2->txnid && uuid_compare(*(ca1->txnid), *(ca2->txnid))) return 0; return 1; } // Range read query: range_read_query * build_range_search_in_txn(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, WORD table_key, uuid_t * txnid, int64_t nonce) { cell_address * start_c = init_cell_address_copy((int64_t) table_key, (int64_t *) start_primary_keys, no_primary_keys); cell_address * end_c = init_cell_address_copy((int64_t) table_key, (int64_t *) end_primary_keys, no_primary_keys); return init_range_read_query_copy(start_c, end_c, txnid, nonce); } range_read_query * build_range_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, WORD table_key, uuid_t * txnid, int64_t nonce) { cell_address * start_c = init_cell_address_copy2((int64_t) table_key, (int64_t *) primary_keys, no_primary_keys, (int64_t *) start_clustering_keys, no_clustering_keys); cell_address * end_c = init_cell_address_copy2((int64_t) table_key, (int64_t *) primary_keys, no_primary_keys, (int64_t *) end_clustering_keys, no_clustering_keys); return init_range_read_query_copy(start_c, end_c, txnid, nonce); } range_read_query * build_range_search_index_in_txn(int idx_idx, WORD start_idx_key, WORD end_idx_key, WORD table_key, uuid_t * txnid, int64_t nonce) { assert(0); // Not supported return NULL; } range_read_query * build_wildcard_range_search_in_txn(WORD table_key, uuid_t * txnid, int64_t nonce) { int64_t min_key = LONG_MIN; int64_t max_key = LONG_MAX - 1; cell_address * start_c = init_cell_address_copy((int64_t) table_key, &min_key, 1); cell_address * end_c = init_cell_address_copy((int64_t) table_key, &max_key, 1); return init_range_read_query_copy(start_c, end_c, txnid, nonce); } range_read_query * init_range_read_query(cell_address * start_cell_address, cell_address * end_cell_address, uuid_t * txnid, int64_t nonce) { range_read_query * ca = (range_read_query *) malloc(sizeof(range_read_query)); ca->start_cell_address = start_cell_address; ca->end_cell_address = end_cell_address; ca->txnid = txnid; ca->nonce = nonce; return ca; } void free_range_read_query(range_read_query * ca) { free_cell_address(ca->start_cell_address); free_cell_address(ca->end_cell_address); free(ca); } range_read_query * init_range_read_query_copy(cell_address * start_cell_address, cell_address * end_cell_address, uuid_t * txnid, int64_t nonce) { range_read_query * ca = (range_read_query *) malloc(sizeof(range_read_query)); ca->start_cell_address = init_cell_address_copy(start_cell_address->table_key, start_cell_address->keys, start_cell_address->no_keys); ca->end_cell_address = init_cell_address_copy(end_cell_address->table_key, end_cell_address->keys, end_cell_address->no_keys); if(txnid != NULL) { ca->txnid = malloc(sizeof(uuid_t)); memcpy(ca->txnid, txnid, sizeof(uuid_t)); } else { ca->txnid = NULL; } ca->nonce = nonce; return ca; } void init_range_read_query_msg(RangeReadQueryMessage * msg, range_read_query * ca, CellAddressMessage * start_cell_address_msg, CellAddressMessage * end_cell_address_msg) { if(ca->txnid != NULL) { msg->txnid.len = sizeof(uuid_t); msg->txnid.data = malloc(sizeof(uuid_t)); memcpy(msg->txnid.data, ca->txnid, sizeof(uuid_t)); } else { msg->txnid.data = NULL; msg->txnid.len = 0; } msg->nonce = ca->nonce; msg->start_cell_address = start_cell_address_msg; msg->end_cell_address = end_cell_address_msg; } range_read_query * init_range_read_query_from_msg(RangeReadQueryMessage * msg) { cell_address * start_cell_address = init_cell_address_from_msg(msg->start_cell_address); cell_address * end_cell_address = init_cell_address_from_msg(msg->end_cell_address); range_read_query * c = init_range_read_query_copy(start_cell_address, end_cell_address, (uuid_t *) msg->txnid.data, msg->nonce); return c; } void free_range_read_query_msg(RangeReadQueryMessage * msg) { free_cell_address_msg(msg->start_cell_address); free_cell_address_msg(msg->end_cell_address); // if(msg->txnid.data != NULL) // free(msg->txnid.data); } int serialize_range_read_query(range_read_query * ca, void ** buf, unsigned * len, vector_clock * vc) { RangeReadQueryMessage msg = RANGE_READ_QUERY_MESSAGE__INIT; CellAddressMessage start_cell_address_msg = CELL_ADDRESS_MESSAGE__INIT; CellAddressMessage end_cell_address_msg = CELL_ADDRESS_MESSAGE__INIT; init_cell_address_msg(&start_cell_address_msg, ca->start_cell_address); init_cell_address_msg(&end_cell_address_msg, ca->end_cell_address); init_range_read_query_msg(&msg, ca, &start_cell_address_msg, &end_cell_address_msg); msg.mtype = RPC_TYPE_RANGE_READ; ServerMessage sm = SERVER_MESSAGE__INIT; sm.mtype = RPC_TYPE_RANGE_READ; sm.wm = NULL; sm.rm = NULL; sm.rrm = &msg; sm.qm = NULL; sm.tm = NULL; sm.gl = NULL; if(vc != NULL) { VectorClockMessage lc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&lc_msg, vc); sm.vc = &lc_msg; } else { sm.vc = NULL; } *len = server_message__get_packed_size (&sm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); server_message__pack (&sm, (void *) ((int *)(*buf) + 1)); free_server_msg(&sm); return 0; } int deserialize_range_read_query(void * buf, unsigned msg_len, range_read_query ** ca) { RangeReadQueryMessage * msg = range_read_query_message__unpack (NULL, msg_len, buf); if (msg == NULL) { log_error("Error unpacking range read query message, msg is NULL"); } else if (msg->mtype != RPC_TYPE_RANGE_READ) { log_error("Error unpacking range read query message, msg->mtype is not RPC_TYPE_RANGE_READ: %d", msg->mtype); return 1; } *ca = init_range_read_query_from_msg(msg); range_read_query_message__free_unpacked(msg, NULL); return 0; } char * to_string_range_read_query(range_read_query * ca, char * msg_buff) { char * crt_ptr = msg_buff; char uuid_str[37]; if(ca->txnid != NULL) uuid_unparse_lower(*(ca->txnid), uuid_str); else uuid_str[0]='\0'; sprintf(crt_ptr, "RangeReadQuery(txnid=%s, nonce=%" PRId64 ", start_key=", uuid_str, ca->nonce); crt_ptr += strlen(crt_ptr); to_string_cell_address(ca->start_cell_address, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", end_key="); crt_ptr += strlen(crt_ptr); to_string_cell_address(ca->end_cell_address, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ")"); return msg_buff; } int equals_range_read_query(range_read_query * ca1, range_read_query * ca2) { if(ca1->nonce != ca2->nonce || !equals_cell_address(ca1->start_cell_address, ca2->start_cell_address) || !equals_cell_address(ca1->end_cell_address, ca2->end_cell_address)) return 0; if(ca1->txnid != NULL && ca2->txnid && uuid_compare(*(ca1->txnid), *(ca2->txnid))) return 0; return 1; } // Ack Message: ack_message * init_ack_message(cell_address * cell_address, int status, uuid_t * txnid, int64_t nonce) { ack_message * ca = (ack_message *) malloc(sizeof(ack_message)); ca->cell_address = cell_address; ca->status = status; ca->txnid = txnid; ca->nonce = nonce; return ca; } ack_message * init_ack_message_copy(cell_address * cell_address, int status, uuid_t * txnid, int64_t nonce) { ack_message * ca = (ack_message *) malloc(sizeof(ack_message)); ca->cell_address = (cell_address != NULL)?(init_cell_address_copy(cell_address->table_key, cell_address->keys, cell_address->no_keys)):(NULL); ca->status = status; if(txnid != NULL) { ca->txnid = malloc(sizeof(uuid_t)); memcpy(ca->txnid, txnid, sizeof(uuid_t)); } else { ca->txnid = NULL; } ca->nonce = nonce; return ca; } void free_ack_message(ack_message * ca) { if(ca->cell_address != NULL) free_cell_address(ca->cell_address); free(ca); } void init_ack_message_msg(AckMessage * msg, ack_message * ca, CellAddressMessage * cell_address_msg) { msg->status = ca->status; if(ca->txnid != NULL) { msg->txnid.len = sizeof(uuid_t); msg->txnid.data = malloc(sizeof(uuid_t)); memcpy(msg->txnid.data, ca->txnid, sizeof(uuid_t)); } else { msg->txnid.data = NULL; msg->txnid.len = 0; } msg->nonce = ca->nonce; msg->cell_address = cell_address_msg; } ack_message * init_ack_message_from_msg(AckMessage * msg) { cell_address * cell_address = (msg->cell_address != NULL)?(init_cell_address_from_msg(msg->cell_address)):(NULL); ack_message * c = init_ack_message_copy(cell_address, msg->status, (uuid_t *) msg->txnid.data, msg->nonce); return c; } void free_ack_message_msg(AckMessage * msg) { if(msg->cell_address != NULL) free_cell_address_msg(msg->cell_address); // if(msg->txnid.data != NULL) // free(msg->txnid.data); } int serialize_ack_message(ack_message * ca, void ** buf, unsigned * len, vector_clock * vc) { AckMessage msg = ACK_MESSAGE__INIT; CellAddressMessage cell_address_msg = CELL_ADDRESS_MESSAGE__INIT; if(ca->cell_address != NULL) init_cell_address_msg(&cell_address_msg, ca->cell_address); init_ack_message_msg(&msg, ca, (ca->cell_address != NULL)?(&cell_address_msg):(NULL)); msg.mtype = RPC_TYPE_ACK; ClientMessage cm = CLIENT_MESSAGE__INIT; cm.mtype = RPC_TYPE_ACK; cm.am = &msg; cm.wm = NULL; cm.rrrm = NULL; cm.qm = NULL; cm.tm = NULL; if(vc != NULL) { VectorClockMessage lc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&lc_msg, vc); cm.vc = &lc_msg; } else { cm.vc = NULL; } *len = client_message__get_packed_size (&cm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); client_message__pack (&cm, (void *) ((int *)(*buf) + 1)); free_client_msg(&cm); return 0; } int deserialize_ack_message(void * buf, unsigned msg_len, ack_message ** ca) { AckMessage * msg = ack_message__unpack (NULL, msg_len, buf); char print_buff[100]; if (msg == NULL) { log_error("Error unpacking ack query message, msg is NULL"); return 1; } else if (msg->mtype != RPC_TYPE_ACK) { log_error("Error unpacking ack query message, msg->mtype is not RPC_TYPE_ACK: %d", msg->mtype); return 1; } *ca = init_ack_message_from_msg(msg); // to_string_ack_message(*ca, (char *) print_buff); // log_debug("Received ACK message: %s", print_buff); ack_message__free_unpacked(msg, NULL); return 0; } char * to_string_ack_message(ack_message * ca, char * msg_buff) { char * crt_ptr = msg_buff; char uuid_str[37]; if(ca->txnid != NULL) uuid_unparse_lower(*(ca->txnid), uuid_str); else uuid_str[0]='\0'; sprintf(crt_ptr, "AckMessage(status=%d, txnid=%s, nonce=%" PRId64 ", ", ca->status, uuid_str, ca->nonce); crt_ptr += strlen(crt_ptr); if(ca->cell_address != NULL) { to_string_cell_address(ca->cell_address, crt_ptr); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, ")"); return msg_buff; } int equals_ack_message(ack_message * ca1, ack_message * ca2) { if(ca1->nonce != ca2->nonce || ca1->status != ca2->status || !equals_cell_address(ca1->cell_address, ca2->cell_address)) return 0; if(ca1->txnid != NULL && ca2->txnid && uuid_compare(*(ca1->txnid), *(ca2->txnid))) return 0; return 1; } // Range read response: range_read_response_message * init_range_read_response_message(cell * cells, int no_cells, uuid_t * txnid, int64_t nonce) { range_read_response_message * ca = (range_read_response_message *) malloc(sizeof(range_read_response_message)); ca->cells = cells; ca->no_cells = no_cells; ca->txnid = txnid; ca->nonce = nonce; return ca; } range_read_response_message * init_range_read_response_message_copy(cell * cells, int no_cells, uuid_t * txnid, int64_t nonce) { range_read_response_message * ca = (range_read_response_message *) malloc(sizeof(range_read_response_message)); ca->no_cells = no_cells; ca->cells = (cell *) malloc(no_cells * sizeof(cell)); for(int i=0;icells + i, cells[i].table_key, cells[i].keys, cells[i].no_keys, cells[i].columns, cells[i].no_columns, cells[i].last_blob, cells[i].last_blob_size, cells[i].version); } if(txnid != NULL) { ca->txnid = malloc(sizeof(uuid_t)); memcpy(ca->txnid, txnid, sizeof(uuid_t)); } else { ca->txnid = NULL; } ca->nonce = nonce; return ca; } void init_range_read_response_message_msg(RangeReadResponseMessage * msg, range_read_response_message * ca) { if(ca->txnid != NULL) { msg->txnid.len = sizeof(uuid_t); msg->txnid.data = malloc(sizeof(uuid_t)); memcpy(msg->txnid.data, ca->txnid, sizeof(uuid_t)); } else { msg->txnid.data = NULL; msg->txnid.len = 0; } msg->nonce = ca->nonce; msg->n_cells = ca->no_cells; msg->cells = (VersionedCellMessage **) malloc(msg->n_cells * sizeof (VersionedCellMessage*)); VectorClockMessage ** vcs = (VectorClockMessage **) malloc(msg->n_cells * sizeof (VectorClockMessage*)); for(int i=0;ino_cells;i++) { msg->cells[i] = malloc (sizeof (VersionedCellMessage)); versioned_cell_message__init(msg->cells[i]); vcs[i] = malloc (sizeof (VectorClockMessage)); vector_clock_message__init(vcs[i]); init_cell_msg(msg->cells[i], ca->cells+i, vcs[i]); } free(vcs); } range_read_response_message * init_range_read_response_message_from_msg(RangeReadResponseMessage * msg) { cell * cells = (cell *) malloc(msg->n_cells * sizeof(cell)); for(int i=0;in_cells;i++) copy_cell_from_msg(cells + i, msg->cells[i]); range_read_response_message * c = init_range_read_response_message_copy(cells, msg->n_cells, (uuid_t *) msg->txnid.data, msg->nonce); return c; } void free_range_read_response_message_msg(RangeReadResponseMessage * msg) { for(int i=0;in_cells;i++) free_cell_msg(msg->cells[i]); if(msg->cells != NULL) free(msg->cells); // if(msg->txnid.data != NULL) // free(msg->txnid.data); } void free_range_read_response_message(range_read_response_message * ca) { for(int i=0;ino_cells;i++) free_cell_ptrs(ca->cells + i); if(ca->cells != NULL) free(ca->cells); free(ca); } int serialize_range_read_response_message(range_read_response_message * ca, void ** buf, unsigned * len, vector_clock * vc) { RangeReadResponseMessage msg = RANGE_READ_RESPONSE_MESSAGE__INIT; init_range_read_response_message_msg(&msg, ca); msg.mtype = RPC_TYPE_RANGE_READ_RESPONSE; ClientMessage cm = CLIENT_MESSAGE__INIT; cm.mtype = RPC_TYPE_RANGE_READ_RESPONSE; cm.am = NULL; cm.wm = NULL; cm.rrrm = &msg; cm.qm = NULL; cm.tm = NULL; if(vc != NULL) { VectorClockMessage lc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&lc_msg, vc); cm.vc = &lc_msg; } else { cm.vc = NULL; } *len = client_message__get_packed_size (&cm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); client_message__pack (&cm, (void *) ((int *)(*buf) + 1)); free_client_msg(&cm); return 0; } int deserialize_range_read_response_message(void * buf, unsigned msg_len, range_read_response_message ** ca) { RangeReadResponseMessage * msg = range_read_response_message__unpack (NULL, msg_len, buf); if (msg == NULL) { log_error("Error unpacking range read response message, msg is NULL"); return 1; } else if (msg->mtype != RPC_TYPE_RANGE_READ_RESPONSE) { log_error("Error unpacking range read response message, msg->mtype is not RPC_TYPE_RANGE_READ_RESPONSE: %d", msg->mtype); return 1; } *ca = init_range_read_response_message_from_msg(msg); range_read_response_message__free_unpacked(msg, NULL); return 0; } char * to_string_range_read_response_message(range_read_response_message * ca, char * msg_buff) { char * crt_ptr = msg_buff; char uuid_str[37]; if(ca->txnid != NULL) uuid_unparse_lower(*(ca->txnid), uuid_str); else uuid_str[0]='\0'; sprintf(crt_ptr, "RangeReadResponseMessage(txnid=%s, nonce=%" PRId64 "", uuid_str, ca->nonce); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", cells={"); crt_ptr += strlen(crt_ptr); for(int i=0;ino_cells;i++) { if(crt_ptr - msg_buff > MAX_PRINT_BUFF - 10) { sprintf(crt_ptr, ".."); crt_ptr += strlen(crt_ptr); break; } to_string_cell(ca->cells+i, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", "); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, "} )"); return msg_buff; } int equals_range_read_response_message(range_read_response_message * ca1, range_read_response_message * ca2) { if(ca1->nonce != ca2->nonce || ca1->no_cells != ca2->no_cells) return 0; if(ca1->txnid != NULL && ca2->txnid && uuid_compare(*(ca1->txnid), *(ca2->txnid))) return 0; for(int i=0;ino_cells;i++) if(!equals_cell(ca1->cells+i, ca2->cells+i)) return 0; return 1; } // Queue query (and response) messages: queue_query_message * init_query_message_basic(cell_address * cell_address, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = (queue_query_message *) malloc(sizeof(queue_query_message)); ca->cells = NULL; ca->no_cells = 0; ca->cell_address = cell_address; ca->queue_index = -1; ca->app_id = -1; ca->shard_id = -1; ca->consumer_id = -1; ca->group_id = -1; ca->status = -1; if(txnid != NULL) { ca->txnid = malloc(sizeof(uuid_t)); memcpy(ca->txnid, txnid, sizeof(uuid_t)); } else { ca->txnid = NULL; } ca->nonce = nonce; return ca; } queue_query_message * build_enqueue_in_txn(WORD * column_values, int no_cols, WORD blob, size_t blob_size, WORD table_key, WORD queue_id, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) table_key, (int64_t) queue_id); cell * entry = init_cell_copy((int64_t) table_key, (int64_t *) column_values, 0, (int64_t *) column_values, no_cols, blob, blob_size, NULL); return init_enqueue_message(c, entry, 1, txnid, nonce); } queue_query_message * build_read_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int max_entries, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) table_key, (int64_t) queue_id); return init_read_queue_message(c, (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, (int64_t) max_entries, txnid, nonce); } queue_query_message * build_consume_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) table_key, (int64_t) queue_id); return init_consume_queue_message(c, (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, new_consume_head, txnid, nonce); } queue_query_message * build_create_queue_in_txn(WORD table_key, WORD queue_id, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) table_key, (int64_t) queue_id); return init_create_queue_message(c, txnid, nonce); } queue_query_message * build_delete_queue_in_txn(WORD table_key, WORD queue_id, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) table_key, (int64_t) queue_id); return init_delete_queue_message(c, txnid, nonce); } queue_query_message * build_subscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) table_key, (int64_t) queue_id); return init_subscribe_queue_message(c, (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, -1, txnid, nonce); } queue_query_message * build_unsubscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) table_key, (int64_t) queue_id); return init_unsubscribe_queue_message(c, (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, -1, txnid, nonce); } queue_query_message * build_subscribe_group_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) -1, (int64_t) -1); return init_subscribe_queue_message(c, (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, (int64_t) group_id, txnid, nonce); } queue_query_message * build_unsubscribe_group_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) -1, (int64_t) -1); return init_unsubscribe_queue_message(c, (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, (int64_t) group_id, txnid, nonce); } queue_query_message * build_add_queue_to_group_in_txn(WORD table_key, WORD queue_id, WORD group_id, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) table_key, (int64_t) queue_id); return init_add_queue_to_group_message(c, (int64_t) group_id, txnid, nonce); } queue_query_message * build_remove_queue_from_group_in_txn(WORD table_key, WORD queue_id, WORD group_id, uuid_t * txnid, int64_t nonce) { cell_address * c = init_cell_address_single_key_copy((int64_t) table_key, (int64_t) queue_id); return init_remove_queue_from_group_message(c, (int64_t) group_id, txnid, nonce); } queue_query_message * init_create_queue_message(cell_address * cell_address, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_CREATE_QUEUE; return ca; } queue_query_message * init_delete_queue_message(cell_address * cell_address, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_DELETE_QUEUE; return ca; } queue_query_message * init_subscribe_queue_message(cell_address * cell_address, int app_id, int shard_id, int consumer_id, int group_id, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_SUBSCRIBE_QUEUE; ca->app_id = app_id; ca->shard_id = shard_id; ca->consumer_id = consumer_id; ca->group_id = group_id; return ca; } queue_query_message * init_unsubscribe_queue_message(cell_address * cell_address, int app_id, int shard_id, int consumer_id, int group_id, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_UNSUBSCRIBE_QUEUE; ca->app_id = app_id; ca->shard_id = shard_id; ca->consumer_id = consumer_id; ca->group_id = group_id; return ca; } queue_query_message * init_add_queue_to_group_message(cell_address * cell_address, int group_id, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_ADD_QUEUE_TO_GROUP; ca->group_id = group_id; return ca; } queue_query_message * init_remove_queue_from_group_message(cell_address * cell_address, int group_id, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_REMOVE_QUEUE_FROM_GROUP; ca->group_id = group_id; return ca; } queue_query_message * init_enqueue_message(cell_address * cell_address, cell * cells, int no_cells, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_ENQUEUE; ca->cells = cells; ca->no_cells = no_cells; return ca; } queue_query_message * init_read_queue_message(cell_address * cell_address, int app_id, int shard_id, int consumer_id, int64_t max_entries, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_READ_QUEUE; ca->queue_index = max_entries; ca->app_id = app_id; ca->shard_id = shard_id; ca->consumer_id = consumer_id; ca->group_id = -1; return ca; } queue_query_message * init_consume_queue_message(cell_address * cell_address, int app_id, int shard_id, int consumer_id, int64_t new_consume_head, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_CONSUME_QUEUE; ca->queue_index = new_consume_head; ca->app_id = app_id; ca->shard_id = shard_id; ca->consumer_id = consumer_id; ca->group_id = -1; return ca; } queue_query_message * init_read_queue_response(cell_address * cell_address, cell * cells, int no_cells, int app_id, int shard_id, int consumer_id, int group_id, int64_t new_read_head, short status, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_READ_QUEUE_RESPONSE; ca->queue_index = new_read_head; ca->app_id = app_id; ca->shard_id = shard_id; ca->consumer_id = consumer_id; ca->group_id = group_id; ca->cells = cells; ca->no_cells = no_cells; ca->status = status; return ca; } queue_query_message * init_queue_notification(cell_address * cell_address, cell * cells, int no_cells, int app_id, int shard_id, int consumer_id, int group_id, int64_t new_no_entries, short status, uuid_t * txnid, int64_t nonce) { queue_query_message * ca = init_query_message_basic(cell_address, txnid, nonce); ca->msg_type = QUERY_TYPE_QUEUE_NOTIFICATION; ca->queue_index = new_no_entries; ca->app_id = app_id; ca->shard_id = shard_id; ca->consumer_id = consumer_id; ca->group_id = group_id; ca->cells = cells; ca->no_cells = no_cells; ca->status = status; return ca; } void free_queue_message(queue_query_message * ca) { for(int i=0;ino_cells;i++) free_cell_ptrs(ca->cells + i); if(ca->cells != NULL) free(ca->cells); free(ca); } void init_queue_message_msg(QueueQueryMessage * msg, queue_query_message * ca, CellAddressMessage * cell_address_msg) { VectorClockMessage ** vcs = NULL; msg->msg_type = ca->msg_type; if(ca->txnid != NULL) { msg->txnid.len = sizeof(uuid_t); msg->txnid.data = malloc(sizeof(uuid_t)); memcpy(msg->txnid.data, ca->txnid, sizeof(uuid_t)); } else { msg->txnid.data = NULL; msg->txnid.len = 0; } msg->nonce = ca->nonce; msg->n_cells = ca->no_cells; msg->queue_address = cell_address_msg; msg->app_id = ca->app_id; msg->shard_id = ca->shard_id; msg->consumer_id = ca->consumer_id; msg->group_id = ca->group_id; msg->queue_index = ca->queue_index; msg->status = ca->status; if(ca->no_cells > 0) { msg->cells = (VersionedCellMessage **) malloc(msg->n_cells * sizeof (VersionedCellMessage*)); vcs = (VectorClockMessage **) malloc(msg->n_cells * sizeof (VectorClockMessage*)); for(int i=0;ino_cells;i++) { msg->cells[i] = malloc (sizeof (VersionedCellMessage)); versioned_cell_message__init(msg->cells[i]); vcs[i] = malloc (sizeof (VectorClockMessage)); vector_clock_message__init(vcs[i]); init_cell_msg(msg->cells[i], ca->cells+i, vcs[i]); } free(vcs); } } queue_query_message * init_queue_message_from_msg(QueueQueryMessage * msg) { cell * cells = NULL; cell_address * cell_address = init_cell_address_from_msg(msg->queue_address); switch(msg->msg_type) { case QUERY_TYPE_CREATE_QUEUE: { return init_create_queue_message(cell_address, (uuid_t *) msg->txnid.data, msg->nonce); } case QUERY_TYPE_DELETE_QUEUE: { return init_delete_queue_message(cell_address, (uuid_t *) msg->txnid.data, msg->nonce); } case QUERY_TYPE_SUBSCRIBE_QUEUE: { return init_subscribe_queue_message(cell_address, msg->app_id, msg->shard_id, msg->consumer_id, msg->group_id, (uuid_t *) msg->txnid.data, msg->nonce); } case QUERY_TYPE_UNSUBSCRIBE_QUEUE: { return init_unsubscribe_queue_message(cell_address, msg->app_id, msg->shard_id, msg->consumer_id, msg->group_id, (uuid_t *) msg->txnid.data, msg->nonce); } case QUERY_TYPE_ADD_QUEUE_TO_GROUP: { return init_add_queue_to_group_message(cell_address, msg->group_id, (uuid_t *) msg->txnid.data, msg->nonce); } case QUERY_TYPE_REMOVE_QUEUE_FROM_GROUP: { return init_remove_queue_from_group_message(cell_address, msg->group_id, (uuid_t *) msg->txnid.data, msg->nonce); } case QUERY_TYPE_ENQUEUE: { if(msg->n_cells > 0) { cells = (cell *) malloc(msg->n_cells * sizeof(cell)); for(int i=0;in_cells;i++) copy_cell_from_msg(cells + i, msg->cells[i]); } return init_enqueue_message(cell_address, cells, msg->n_cells, (uuid_t *) msg->txnid.data, msg->nonce); } case QUERY_TYPE_READ_QUEUE: { return init_read_queue_message(cell_address, msg->app_id, msg->shard_id, msg->consumer_id, msg->queue_index, (uuid_t *) msg->txnid.data, msg->nonce); } case QUERY_TYPE_CONSUME_QUEUE: { return init_consume_queue_message(cell_address, msg->app_id, msg->shard_id, msg->consumer_id, msg->queue_index, (uuid_t *) msg->txnid.data, msg->nonce); } case QUERY_TYPE_READ_QUEUE_RESPONSE: { if(msg->n_cells > 0) { cells = (cell *) malloc(msg->n_cells * sizeof(cell)); for(int i=0;in_cells;i++) copy_cell_from_msg(cells + i, msg->cells[i]); } return init_read_queue_response(cell_address, cells, msg->n_cells, msg->app_id, msg->shard_id, msg->consumer_id, msg->group_id, msg->queue_index, msg->status, (uuid_t *) msg->txnid.data, msg->nonce); } case QUERY_TYPE_QUEUE_NOTIFICATION: { return init_queue_notification(cell_address, NULL, 0, msg->app_id, msg->shard_id, msg->consumer_id, msg->group_id, msg->queue_index, msg->status, (uuid_t *) msg->txnid.data, msg->nonce); } default: { assert(0); } } return NULL; } void free_queue_message_msg(QueueQueryMessage * msg) { // if(msg->txnid.data != NULL) // free(msg->txnid.data); for(int i=0;in_cells;i++) free_cell_msg(msg->cells[i]); if(msg->cells != NULL) free(msg->cells); } int serialize_queue_message(queue_query_message * ca, void ** buf, unsigned * len, short for_server, vector_clock * vc) { QueueQueryMessage msg = QUEUE_QUERY_MESSAGE__INIT; CellAddressMessage cell_address_msg = CELL_ADDRESS_MESSAGE__INIT; init_cell_address_msg(&cell_address_msg, ca->cell_address); init_queue_message_msg(&msg, ca, &cell_address_msg); msg.mtype = RPC_TYPE_QUEUE; if(for_server) { ServerMessage sm = SERVER_MESSAGE__INIT; sm.mtype = RPC_TYPE_QUEUE; sm.wm = NULL; sm.rm = NULL; sm.rrm = NULL; sm.qm = &msg; sm.tm = NULL; sm.gl = NULL; if(vc != NULL) { VectorClockMessage lc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&lc_msg, vc); sm.vc = &lc_msg; } else { sm.vc = NULL; } *len = server_message__get_packed_size (&sm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); server_message__pack (&sm, (void *) ((int *)(*buf) + 1)); free_server_msg(&sm); } else { ClientMessage cm = CLIENT_MESSAGE__INIT; cm.mtype = RPC_TYPE_QUEUE; cm.am = NULL; cm.wm = NULL; cm.rrrm = NULL; cm.qm = &msg; cm.tm = NULL; if(vc != NULL) { VectorClockMessage lc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&lc_msg, vc); cm.vc = &lc_msg; } else { cm.vc = NULL; } *len = client_message__get_packed_size (&cm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); client_message__pack (&cm, (void *) ((int *)(*buf) + 1)); free_client_msg(&cm); } return 0; } int deserialize_queue_message(void * buf, unsigned msg_len, queue_query_message ** ca) { QueueQueryMessage * msg = queue_query_message__unpack (NULL, msg_len, buf); if (msg == NULL) { log_error("Error unpacking queue query message, msg is NULL"); return 1; } else if (msg->mtype != RPC_TYPE_QUEUE) { log_error("Error unpacking queue query message, msg->mtype is not RPC_TYPE_QUEUE: %d", msg->mtype); return 1; } *ca = init_queue_message_from_msg(msg); queue_query_message__free_unpacked(msg, NULL); return 0; } char * to_string_queue_message(queue_query_message * ca, char * msg_buff) { char * crt_ptr = msg_buff; char uuid_str[37]; if(ca->txnid != NULL) uuid_unparse_lower(*(ca->txnid), uuid_str); else uuid_str[0]='\0'; switch(ca->msg_type) { case QUERY_TYPE_CREATE_QUEUE: { sprintf(crt_ptr, "CreateQueue(txnid=%s, nonce=%" PRId64 ", ", uuid_str, ca->nonce); break; } case QUERY_TYPE_DELETE_QUEUE: { sprintf(crt_ptr, "DeleteQueue(txnid=%s, nonce=%" PRId64 ", ", uuid_str, ca->nonce); break; } case QUERY_TYPE_SUBSCRIBE_QUEUE: { sprintf(crt_ptr, "SubscribeQueue(txnid=%s, nonce=%" PRId64 ", app_id=%d, shard_id=%d, consumer_id=%d, ", uuid_str, ca->nonce, ca->app_id, ca->shard_id, ca->consumer_id); break; } case QUERY_TYPE_UNSUBSCRIBE_QUEUE: { sprintf(crt_ptr, "UnsubscribeQueue(txnid=%s, nonce=%" PRId64 ", app_id=%d, shard_id=%d, consumer_id=%d, ", uuid_str, ca->nonce, ca->app_id, ca->shard_id, ca->consumer_id); break; } case QUERY_TYPE_ADD_QUEUE_TO_GROUP: { sprintf(crt_ptr, "AddQueueToGroup(txnid=%s, nonce=%" PRId64 ", table_key=%" PRId64 ", queue_id=%" PRId64 ", group_id=%d, ", uuid_str, ca->nonce, ca->cell_address->table_key, ca->cell_address->keys[0], ca->group_id); break; } case QUERY_TYPE_REMOVE_QUEUE_FROM_GROUP: { sprintf(crt_ptr, "RemoveQueueFromGroup(txnid=%s, nonce=%" PRId64 ", table_key=%" PRId64 ", queue_id=%" PRId64 ", group_id=%d, ", uuid_str, ca->nonce, ca->cell_address->table_key, ca->cell_address->keys[0], ca->group_id); break; } case QUERY_TYPE_ENQUEUE: { sprintf(crt_ptr, "Enqueue(txnid=%s, nonce=%" PRId64 ", no_entries=%d, ", uuid_str, ca->nonce, ca->no_cells); break; } case QUERY_TYPE_READ_QUEUE: { sprintf(crt_ptr, "ReadQueue(txnid=%s, nonce=%" PRId64 ", app_id=%d, shard_id=%d, consumer_id=%d, max_items=%" PRId64 ", ", uuid_str, ca->nonce, ca->app_id, ca->shard_id, ca->consumer_id, ca->queue_index); break; } case QUERY_TYPE_CONSUME_QUEUE: { sprintf(crt_ptr, "ConsumeQueue(txnid=%s, nonce=%" PRId64 ", app_id=%d, shard_id=%d, consumer_id=%d, new_consume_head=%" PRId64 ", ", uuid_str, ca->nonce, ca->app_id, ca->shard_id, ca->consumer_id, ca->queue_index); break; } case QUERY_TYPE_READ_QUEUE_RESPONSE: { sprintf(crt_ptr, "ReadQueueResponse(txnid=%s, nonce=%" PRId64 ", app_id=%d, shard_id=%d, consumer_id=%d, no_entries=%d, new_read_head=%" PRId64 ", status=%d, ", uuid_str, ca->nonce, ca->app_id, ca->shard_id, ca->consumer_id, ca->no_cells, ca->queue_index, ca->status); break; } } crt_ptr += strlen(crt_ptr); to_string_cell_address(ca->cell_address, crt_ptr); crt_ptr += strlen(crt_ptr); if(ca->no_cells > 0) { sprintf(crt_ptr, ", cells={"); crt_ptr += strlen(crt_ptr); for(int i=0;ino_cells;i++) { if(crt_ptr - msg_buff > MAX_PRINT_BUFF - 5) { sprintf(crt_ptr, ".."); crt_ptr += strlen(crt_ptr); break; } to_string_cell(ca->cells+i, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", "); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, "} )"); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, ")"); return msg_buff; } int equals_queue_message(queue_query_message * ca1, queue_query_message * ca2) { if(ca1->nonce != ca2->nonce || ca1->msg_type != ca2->msg_type || ca1->queue_index != ca2->queue_index || ca1->no_cells != ca2->no_cells || !equals_cell_address(ca1->cell_address, ca2->cell_address)) return 0; if(ca1->txnid != NULL && ca2->txnid && uuid_compare(*(ca1->txnid), *(ca2->txnid))) return 0; return 1; } // Txn Message: txn_message * build_new_txn(uuid_t * txnid, int64_t nonce) { return init_txn_message_copy(DB_TXN_BEGIN, NULL, 0, // own_read_set, no_own_read_set, NULL, 0, // own_write_set, no_own_write_set, NULL, 0, // complete_read_set, no_complete_read_set, NULL, 0, // complete_write_set, no_complete_write_set, txnid, NULL, nonce); } txn_message * build_validate_txn(uuid_t * txnid, vector_clock * version, int64_t nonce) { // In the current implementation, the server mirrors the txn's complete read and write sets, so there is no reason to re-send them from client: return init_txn_message_copy(DB_TXN_VALIDATION, NULL, 0, // own_read_set, no_own_read_set, NULL, 0, // own_write_set, no_own_write_set, NULL, 0, // complete_read_set, no_complete_read_set, NULL, 0, // complete_write_set, no_complete_write_set, txnid, version, nonce); } txn_message * build_commit_txn(uuid_t * txnid, vector_clock * version, int64_t nonce) { // In the current implementation, the server mirrors the txn's complete read and write sets, so there is no reason to re-send them from client: return init_txn_message_copy(DB_TXN_COMMIT, NULL, 0, // own_read_set, no_own_read_set, NULL, 0, // own_write_set, no_own_write_set, NULL, 0, // complete_read_set, no_complete_read_set, NULL, 0, // complete_write_set, no_complete_write_set, txnid, version, nonce); } txn_message * build_abort_txn(uuid_t * txnid, int64_t nonce) { return init_txn_message_copy(DB_TXN_ABORT, NULL, 0, // own_read_set, no_own_read_set, NULL, 0, // own_write_set, no_own_write_set, NULL, 0, // complete_read_set, no_complete_read_set, NULL, 0, // complete_write_set, no_complete_write_set, txnid, NULL, nonce); } txn_message * init_txn_message(int type, cell * own_read_set, int no_own_read_set, cell * own_write_set, int no_own_write_set, cell * complete_read_set, int no_complete_read_set, cell * complete_write_set, int no_complete_write_set, uuid_t * txnid, vector_clock * version, int64_t nonce) { txn_message * ca = (txn_message *) malloc(sizeof(txn_message)); ca->type = type; ca->own_read_set = own_read_set; ca->no_own_read_set = no_own_read_set; ca->own_write_set = own_write_set; ca->no_own_write_set = no_own_write_set; ca->complete_read_set = complete_read_set; ca->no_complete_read_set = no_complete_read_set; ca->complete_write_set = complete_write_set; ca->no_complete_write_set = no_complete_write_set; ca->txnid = txnid; ca->version = version; ca->nonce = nonce; return ca; } txn_message * init_txn_message_copy(int type, cell * own_read_set, int no_own_read_set, cell * own_write_set, int no_own_write_set, cell * complete_read_set, int no_complete_read_set, cell * complete_write_set, int no_complete_write_set, uuid_t * txnid, vector_clock * version, int64_t nonce) { txn_message * ca = (txn_message *) malloc(sizeof(txn_message)); ca->type = type; if(txnid != NULL) { ca->txnid = malloc(sizeof(uuid_t)); memcpy(ca->txnid, txnid, sizeof(uuid_t)); } else { ca->txnid = NULL; } ca->version = (version != NULL)?copy_vc(version):NULL; ca->nonce = nonce; ca->no_own_read_set = no_own_read_set; ca->no_own_write_set = no_own_write_set; ca->no_complete_read_set = no_complete_read_set; ca->no_complete_write_set = no_complete_write_set; ca->own_read_set = (cell *) malloc (no_own_read_set * sizeof(cell)); for(int i=0;iown_read_set[i] = own_read_set[i]; ca->own_write_set = (cell *) malloc (no_own_write_set * sizeof(cell)); for(int i=0;iown_write_set[i] = own_write_set[i]; ca->complete_read_set = (cell *) malloc (no_complete_read_set * sizeof(cell)); for(int i=0;icomplete_read_set[i] = complete_read_set[i]; ca->complete_write_set = (cell *) malloc (no_complete_write_set * sizeof(cell)); for(int i=0;icomplete_write_set[i] = complete_write_set[i]; return ca; } void free_txn_message(txn_message * ca) { for(int i=0;ino_own_read_set;i++) free_cell_ptrs(ca->own_read_set+i); free(ca->own_read_set); for(int i=0;ino_own_write_set;i++) free_cell_ptrs(ca->own_write_set+i); free(ca->own_write_set); for(int i=0;ino_complete_read_set;i++) free_cell_ptrs(ca->complete_read_set+i); free(ca->complete_read_set); for(int i=0;ino_complete_write_set;i++) free_cell_ptrs(ca->complete_write_set+i); free(ca->complete_write_set); if(ca->version != NULL) free_vc(ca->version); free(ca); } void init_txn_message_msg(TxnMessage * msg, txn_message * ca, VectorClockMessage * vc_msg) { msg->n_own_read_set = ca->no_own_read_set; msg->n_own_write_set = ca->no_own_write_set; msg->n_complete_read_set = ca->no_complete_read_set; msg->n_complete_write_set = ca->no_complete_write_set; VersionedCellMessage **own_read_set = (VersionedCellMessage **) malloc(msg->n_own_read_set * sizeof (VersionedCellMessage*)); VectorClockMessage ** vc_msgs_own_read_set = (VectorClockMessage **) malloc(msg->n_own_read_set * sizeof (VectorClockMessage*)); for(int i = 0; i < msg->n_own_read_set; i++) { own_read_set[i] = malloc (sizeof (VersionedCellMessage)); versioned_cell_message__init(own_read_set[i]); vc_msgs_own_read_set[i] = malloc (sizeof (VectorClockMessage)); vector_clock_message__init(vc_msgs_own_read_set[i]); init_cell_msg(own_read_set[i], ca->own_read_set+i, vc_msgs_own_read_set[i]); } free(vc_msgs_own_read_set); VersionedCellMessage **own_write_set = (VersionedCellMessage **) malloc(msg->n_own_write_set * sizeof (VersionedCellMessage*)); VectorClockMessage ** vc_msgs_own_write_set = (VectorClockMessage **) malloc(msg->n_own_write_set * sizeof (VectorClockMessage*)); for(int i = 0; i < msg->n_own_write_set; i++) { own_write_set[i] = malloc (sizeof (VersionedCellMessage)); versioned_cell_message__init(own_write_set[i]); vc_msgs_own_write_set[i] = malloc (sizeof (VectorClockMessage)); vector_clock_message__init(vc_msgs_own_write_set[i]); init_cell_msg(own_write_set[i], ca->own_write_set+i, vc_msgs_own_write_set[i]); } free(vc_msgs_own_write_set); VersionedCellMessage **complete_read_set = (VersionedCellMessage **) malloc(msg->n_complete_read_set * sizeof (VersionedCellMessage*)); VectorClockMessage ** vc_msgs_complete_read_set = (VectorClockMessage **) malloc(msg->n_complete_read_set * sizeof (VectorClockMessage*)); for(int i = 0; i < msg->n_complete_read_set; i++) { complete_read_set[i] = malloc (sizeof (VersionedCellMessage)); versioned_cell_message__init(complete_read_set[i]); vc_msgs_complete_read_set[i] = malloc (sizeof (VectorClockMessage)); vector_clock_message__init(vc_msgs_complete_read_set[i]); init_cell_msg(complete_read_set[i], ca->complete_read_set+i, vc_msgs_complete_read_set[i]); } free(vc_msgs_complete_read_set); VersionedCellMessage **complete_write_set = (VersionedCellMessage **) malloc(msg->n_complete_write_set * sizeof (VersionedCellMessage*)); VectorClockMessage ** vc_msgs_complete_write_set = (VectorClockMessage **) malloc(msg->n_complete_write_set * sizeof (VectorClockMessage*)); for(int i = 0; i < msg->n_complete_write_set; i++) { complete_write_set[i] = malloc (sizeof (VersionedCellMessage)); versioned_cell_message__init(complete_write_set[i]); vc_msgs_complete_write_set[i] = malloc (sizeof (VectorClockMessage)); vector_clock_message__init(vc_msgs_complete_write_set[i]); init_cell_msg(complete_write_set[i], ca->complete_write_set+i, vc_msgs_complete_write_set[i]); } free(vc_msgs_complete_write_set); msg->own_read_set = own_read_set; msg->own_write_set = own_write_set; msg->complete_read_set = complete_read_set; msg->complete_write_set = complete_write_set; msg->type = ca->type; if(ca->txnid != NULL) { msg->txnid.len = sizeof(uuid_t); msg->txnid.data = malloc(sizeof(uuid_t)); memcpy(msg->txnid.data, ca->txnid, sizeof(uuid_t)); } else { msg->txnid.data = NULL; msg->txnid.len = 0; } if(ca->version != NULL) { init_vc_msg(vc_msg, ca->version); // msg->has_version = 1; msg->version = vc_msg; } else { // msg->has_version = 0; } msg->nonce = ca->nonce; } txn_message * init_txn_message_from_msg(TxnMessage * msg) { cell * own_read_set = (cell *) malloc(msg->n_own_read_set * sizeof(cell)); cell * own_write_set = (cell *) malloc(msg->n_own_write_set * sizeof(cell)); cell * complete_read_set = (cell *) malloc(msg->n_complete_read_set * sizeof(cell)); cell * complete_write_set = (cell *) malloc(msg->n_complete_write_set * sizeof(cell)); for(int i=0;in_own_read_set;i++) copy_cell_from_msg(own_read_set+i, msg->own_read_set[i]); for(int i=0;in_own_write_set;i++) copy_cell_from_msg(own_write_set+i, msg->own_write_set[i]); for(int i=0;in_complete_read_set;i++) copy_cell_from_msg(complete_read_set+i, msg->complete_read_set[i]); for(int i=0;in_complete_write_set;i++) copy_cell_from_msg(complete_write_set+i, msg->complete_write_set[i]); txn_message * c = init_txn_message_copy(msg->type, own_read_set, msg->n_own_read_set, own_write_set, msg->n_own_write_set, complete_read_set, msg->n_complete_read_set, complete_write_set, msg->n_complete_write_set, (uuid_t *) msg->txnid.data, (msg->version != NULL)?init_vc_from_msg(msg->version):NULL, msg->nonce); // msg->has_version return c; } void free_txn_message_msg(TxnMessage * msg) { for(int i=0;in_own_read_set;i++) free_cell_msg(msg->own_read_set[i]); free(msg->own_read_set); for(int i=0;in_own_write_set;i++) free_cell_msg(msg->own_write_set[i]); free(msg->own_write_set); for(int i=0;in_complete_read_set;i++) free_cell_msg(msg->complete_read_set[i]); free(msg->complete_read_set); for(int i=0;in_complete_write_set;i++) free_cell_msg(msg->complete_write_set[i]); free(msg->complete_write_set); if(msg->version != NULL) // msg->has_version free_vc_msg(msg->version); } int serialize_txn_message(txn_message * ca, void ** buf, unsigned * len, short for_server, vector_clock * vc) { TxnMessage msg = TXN_MESSAGE__INIT; VectorClockMessage vc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_txn_message_msg(&msg, ca, &vc_msg); msg.mtype = RPC_TYPE_TXN; if(for_server) { ServerMessage sm = SERVER_MESSAGE__INIT; sm.mtype = RPC_TYPE_TXN; sm.wm = NULL; sm.rm = NULL; sm.rrm = NULL; sm.qm = NULL; sm.tm = &msg; sm.gl = NULL; if(vc != NULL) { VectorClockMessage lc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&lc_msg, vc); sm.vc = &lc_msg; } else { sm.vc = NULL; } *len = server_message__get_packed_size (&sm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); server_message__pack (&sm, (void *) ((int *)(*buf) + 1)); free_server_msg(&sm); } else { ClientMessage cm = CLIENT_MESSAGE__INIT; cm.mtype = RPC_TYPE_TXN; cm.am = NULL; cm.wm = NULL; cm.rrrm = NULL; cm.qm = NULL; cm.tm = &msg; if(vc != NULL) { VectorClockMessage lc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&lc_msg, vc); cm.vc = &lc_msg; } else { cm.vc = NULL; } *len = client_message__get_packed_size (&cm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); client_message__pack (&cm, (void *) ((int *)(*buf) + 1)); free_client_msg(&cm); } return 0; } int deserialize_txn_message(void * buf, unsigned msg_len, txn_message ** ca) { TxnMessage * msg = txn_message__unpack (NULL, msg_len, buf); if (msg == NULL) { log_error("Error unpacking txn query message, msg is NULL"); return 1; } else if (msg->mtype != RPC_TYPE_TXN) { log_error("Error unpacking txn query message, msg->mtype is not RPC_TYPE_TXN: %d", msg->mtype); return 1; } *ca = init_txn_message_from_msg(msg); txn_message__free_unpacked(msg, NULL); return 0; } char * to_string_txn_message(txn_message * ca, char * msg_buff) { char * crt_ptr = msg_buff; char uuid_str[37]; if(ca->txnid != NULL) uuid_unparse_lower(*(ca->txnid), uuid_str); else uuid_str[0]='\0'; sprintf(crt_ptr, "TxnMessage(type=%d, txnid=%s, nonce=%" PRId64 "", ca->type, uuid_str, ca->nonce); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", own_read_set={"); crt_ptr += strlen(crt_ptr); for(int i=0;ino_own_read_set;i++) { to_string_cell(ca->own_read_set+i, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", "); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, "}, own_write_set={"); crt_ptr += strlen(crt_ptr); for(int i=0;ino_own_write_set;i++) { to_string_cell(ca->own_write_set+i, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", "); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, "}, complete_read_set={"); crt_ptr += strlen(crt_ptr); for(int i=0;ino_complete_read_set;i++) { to_string_cell(ca->complete_read_set+i, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", "); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, "}, complete_write_set={"); crt_ptr += strlen(crt_ptr); for(int i=0;ino_complete_write_set;i++) { to_string_cell(ca->complete_write_set+i, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, "}, "); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, "}, version="); crt_ptr += strlen(crt_ptr); if(ca->version != NULL) { to_string_vc(ca->version, crt_ptr); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, ")"); return msg_buff; } int equals_txn_message(txn_message * ca1, txn_message * ca2) { if(ca1->nonce != ca2->nonce || ca1->type != ca2->type || ca1->no_own_read_set != ca2->no_own_read_set || ca1->no_own_write_set != ca2->no_own_write_set || ca1->no_complete_read_set != ca2->no_complete_read_set || ca1->no_complete_write_set != ca2->no_complete_write_set) return 0; if(ca1->txnid != NULL && ca2->txnid && uuid_compare(*(ca1->txnid), *(ca2->txnid))) return 0; if(compare_vc(ca1->version, ca2->version)) return 0; for(int i=0;ino_own_read_set;i++) if(!equals_cell(ca1->own_read_set+i, ca2->own_read_set+i)) return 0; for(int i=0;ino_own_write_set;i++) if(!equals_cell(ca1->own_write_set+i, ca2->own_write_set+i)) return 0; for(int i=0;ino_complete_read_set;i++) if(!equals_cell(ca1->complete_read_set+i, ca2->complete_read_set+i)) return 0; for(int i=0;ino_complete_write_set;i++) if(!equals_cell(ca1->complete_write_set+i, ca2->complete_write_set+i)) return 0; return 1; } gossip_listen_message * build_gossip_listen_msg(node_description * nd, int64_t nonce) { gossip_listen_message * gs = (gossip_listen_message *) malloc(sizeof(gossip_listen_message)); gs->node_description = nd; gs->nonce = nonce; return gs; } void free_gossip_listen_msg(gossip_listen_message * gs) { free_node_description(gs->node_description); free(gs); } void free_gossip_listen_message_msg(GossipListenMessage * msg) { } int serialize_gossip_listen_msg(gossip_listen_message * gs, void ** buf, unsigned * len) { GossipListenMessage msg = GOSSIP_LISTEN_MESSAGE__INIT; NodeStateMessage ns_msg = NODE_STATE_MESSAGE__INIT; init_ns_msg_from_description(&ns_msg, gs->node_description); msg.node_state = &ns_msg; msg.nonce = gs->nonce; ServerMessage sm = SERVER_MESSAGE__INIT; sm.mtype = RPC_TYPE_GOSSIP_LISTEN; sm.wm = NULL; sm.rm = NULL; sm.rrm = NULL; sm.qm = NULL; sm.tm = NULL; sm.gl = &msg; sm.vc = NULL; *len = server_message__get_packed_size (&sm); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); server_message__pack (&sm, (void *) ((int *)(*buf) + 1)); free_server_msg(&sm); return 0; } int deserialize_gossip_listen_msg(void * buf, unsigned msg_len, gossip_listen_message ** gl) { GossipListenMessage * msg = gossip_listen_message__unpack(NULL, msg_len, buf); if (msg == NULL) { log_error("Error unpacking gossip_state message, msg is NULL"); return 1; } node_description * nd = init_node_description(msg->node_state->status, msg->node_state->node_id, msg->node_state->rack_id, msg->node_state->dc_id, (char *) msg->node_state->hostname.data, msg->node_state->port); *gl = build_gossip_listen_msg(nd, msg->nonce); return 0; } int equals_gossip_listen_msg(gossip_listen_message * gs1, gossip_listen_message * gs2) { return equals_node_description(gs1->node_description, gs2->node_description) && gs1->node_description->status == gs2->node_description->status && gs1->nonce == gs2->nonce; } char * to_string_gossip_listen_msg(gossip_listen_message * gs, char * msg_buff) { sprintf(msg_buff, "GossipListenMessage(node_description="); to_string_node_description(gs->node_description, msg_buff + strlen(msg_buff)); sprintf(msg_buff, ", nonce=%" PRId64 ")", gs->nonce); return msg_buff; } void free_server_msg(ServerMessage * sm) { switch(sm->mtype) { case RPC_TYPE_WRITE: { assert(sm->wm != NULL); free_write_query_msg(sm->wm); break; } case RPC_TYPE_READ: { assert(sm->rm != NULL); free_read_query_msg(sm->rm); break; } case RPC_TYPE_RANGE_READ: { assert(sm->rrm != NULL); free_range_read_query_msg(sm->rrm); break; } case RPC_TYPE_QUEUE: { assert(sm->qm != NULL); free_queue_message_msg(sm->qm); break; } case RPC_TYPE_TXN: { assert(sm->tm != NULL); free_txn_message_msg(sm->tm); break; } case RPC_TYPE_GOSSIP_LISTEN: { assert(sm->gl != NULL); free_gossip_listen_message_msg(sm->gl); break; } default: { log_fatal("Wrong server message type %d", sm->mtype); } } if(sm->vc != NULL) free_vc_msg(sm->vc); } int deserialize_server_message(void * buf, unsigned msg_len, void ** dest_buf, short * mtype, vector_clock ** vc) { ServerMessage * sm = server_message__unpack (NULL, msg_len, buf); if (sm == NULL) { *mtype = -1; log_error("Error unpacking server message, msg is NULL"); return 1; } switch(sm->mtype) { case RPC_TYPE_WRITE: { assert(sm->wm != NULL); *dest_buf = (write_query *) init_write_query_from_msg(sm->wm); break; } case RPC_TYPE_READ: { assert(sm->rm != NULL); *dest_buf = (read_query *) init_read_query_from_msg(sm->rm); break; } case RPC_TYPE_RANGE_READ: { assert(sm->rrm != NULL); *dest_buf = (range_read_query *) init_range_read_query_from_msg(sm->rrm); break; } case RPC_TYPE_QUEUE: { assert(sm->qm != NULL); *dest_buf = (queue_query_message *) init_queue_message_from_msg(sm->qm); break; } case RPC_TYPE_TXN: { assert(sm->tm != NULL); *dest_buf = (txn_message *) init_txn_message_from_msg(sm->tm); break; } case RPC_TYPE_GOSSIP_LISTEN: { assert(sm->gl != NULL); node_description * nd = init_node_description(sm->gl->node_state->status, sm->gl->node_state->node_id, sm->gl->node_state->rack_id, sm->gl->node_state->dc_id, (char *) sm->gl->node_state->hostname.data, sm->gl->node_state->port); *dest_buf = (gossip_listen_message *) build_gossip_listen_msg(nd, sm->gl->nonce); break; } default: { log_fatal("Wrong server message type %d", sm->mtype); return 1; } } *mtype = sm->mtype; *vc = (sm->vc != NULL)?(init_vc_from_msg(sm->vc)):(NULL); //printf("Deserialized message of type %d\n", sm->mtype); server_message__free_unpacked(sm, NULL); return 0; } void free_client_msg(ClientMessage * cm) { switch(cm->mtype) { case RPC_TYPE_ACK: { assert(cm->am != NULL); free_ack_message_msg(cm->am); break; } case RPC_TYPE_WRITE: { assert(cm->wm != NULL); free_write_query_msg(cm->wm); break; } case RPC_TYPE_RANGE_READ_RESPONSE: { assert(cm->rrrm != NULL); free_range_read_response_message_msg(cm->rrrm); break; } case RPC_TYPE_QUEUE: { assert(cm->qm != NULL); free_queue_message_msg(cm->qm); break; } case RPC_TYPE_TXN: { assert(cm->tm != NULL); free_txn_message_msg(cm->tm); break; } default: { log_fatal("Wrong client message type %d", cm->mtype); } } if(cm->vc != NULL) free_vc_msg(cm->vc); } int deserialize_client_message(void * buf, unsigned msg_len, void ** dest_buf, short * mtype, short * is_gossip_message, vector_clock ** vc) { ClientMessage * cm = client_message__unpack (NULL, msg_len, buf); *is_gossip_message = 0; if (cm == NULL) { log_error("Error unpacking client message, msg is NULL"); // This might be a gossiped membership notification: membership_agreement_msg * ma = NULL; int status = deserialize_membership_agreement_msg(buf, msg_len, &ma); // + sizeof(int) if(status == 0) { // #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_membership_agreement_msg(ma, (char *) print_buff); log_debug("Received gossip message: %s", print_buff); // #endif switch(ma->msg_type) { case MEMBERSHIP_AGREEMENT_NOTIFY: { *is_gossip_message = 1; *mtype = ma->msg_type; *dest_buf = ma; break; } default: { log_fatal("Wrong gossip message type %d", ma->msg_type); } } return 0; } else { log_error("Error unpacking gossip message"); return 1; } } switch(cm->mtype) { case RPC_TYPE_ACK: { assert(cm->am != NULL); *dest_buf = init_ack_message_from_msg(cm->am); break; } case RPC_TYPE_WRITE: { assert(cm->wm != NULL); *dest_buf = init_write_query_from_msg(cm->wm); break; } case RPC_TYPE_RANGE_READ_RESPONSE: { assert(cm->rrrm != NULL); *dest_buf = init_range_read_response_message_from_msg(cm->rrrm); break; } case RPC_TYPE_QUEUE: { assert(cm->qm != NULL); *dest_buf = init_queue_message_from_msg(cm->qm); break; } case RPC_TYPE_TXN: { assert(cm->tm != NULL); *dest_buf = init_txn_message_from_msg(cm->tm); break; } default: { log_fatal("Wrong client message type %d", cm->mtype); return 1; } } *mtype = cm->mtype; *vc = (cm->vc != NULL)?(init_vc_from_msg(cm->vc)):(NULL); client_message__free_unpacked(cm, NULL); return 0; } ================================================ FILE: backend/failure_detector/db_queries.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * db_queries.h * * Author: aagapi */ #ifndef BACKEND_FAILURE_DETECTOR_DB_QUERIES_H_ #define BACKEND_FAILURE_DETECTOR_DB_QUERIES_H_ #include "cells.h" #include "../db.h" #include "../txns.h" #include "fd.h" #include #define RPC_TYPE_WRITE 0 #define RPC_TYPE_DELETE 1 #define RPC_TYPE_READ 2 #define RPC_TYPE_RANGE_READ 3 #define RPC_TYPE_ACK 4 #define RPC_TYPE_READ_RESPONSE 5 #define RPC_TYPE_RANGE_READ_RESPONSE 6 #define RPC_TYPE_QUEUE 7 #define RPC_TYPE_TXN 8 #define RPC_TYPE_GOSSIP 9 #define RPC_TYPE_GOSSIP_LISTEN 10 #define DB_TXN_BEGIN 0 #define DB_TXN_VALIDATION 1 #define DB_TXN_COMMIT 2 #define DB_TXN_ABORT 3 #define DB_ACK 0 #define DB_NACK 1 #define CLIENT_ERR_SUBSCRIPTION_EXISTS 1 #define CLIENT_ERR_NO_SUBSCRIPTION_EXISTS 2 int deserialize_server_message(void * buf, unsigned msg_len, void ** sm, short * mtype, vector_clock ** vc); int deserialize_client_message(void * buf, unsigned msg_len, void ** cm, short * mtype, short * is_gossip_message, vector_clock ** vc); typedef struct write_query { cell * cell; int msg_type; // {RPC_TYPE_WRITE, RPC_TYPE_DELETE} uuid_t * txnid; int64_t nonce; } write_query; typedef write_query read_response_message; write_query * build_insert_in_txn(WORD * column_values, int no_cols, int no_primary_keys, int no_clustering_keys, WORD blob, size_t blob_size, WORD table_key, uuid_t * txnid, int64_t nonce); write_query * build_delete_row_in_txn(WORD* primary_keys, int no_primary_keys, WORD table_key, uuid_t * txnid, int64_t nonce); write_query * build_delete_cell_in_txn(WORD* keys, int no_primary_keys, int no_clustering_keys, WORD table_key, uuid_t * txnid, int64_t nonce); write_query * build_delete_by_index_in_txn(WORD index_key, int idx_idx, WORD table_key, uuid_t * txnid, int64_t nonce); write_query * build_update_in_txn(int * col_idxs, int no_cols, WORD * column_values, WORD blob, size_t blob_size, WORD table_key, uuid_t * txnid, int64_t nonce); write_query * init_write_query(cell * cell, int msg_type, uuid_t * txnid, int64_t nonce); write_query * init_write_query_copy(cell * cell, int msg_type, uuid_t * txnid, int64_t nonce); void free_write_query(write_query * ca); int serialize_write_query(write_query * ca, void ** buf, unsigned * len, short for_server, vector_clock * vc); int deserialize_write_query(void * buf, unsigned msg_len, write_query ** ca); char * to_string_write_query(write_query * ca, char * msg_buff); int equals_write_query(write_query * ca1, write_query * ca2); typedef struct read_query { cell_address * cell_address; uuid_t * txnid; int64_t nonce; } read_query; read_query * build_search_in_txn(WORD* primary_keys, int no_primary_keys, WORD table_key, uuid_t * txnid, int64_t nonce); read_query * build_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD table_key, uuid_t * txnid, int64_t nonce); read_query * build_search_columns_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD* col_keys, int no_columns, WORD table_key, uuid_t * txnid, int64_t nonce); read_query * build_search_index_in_txn(WORD index_key, int idx_idx, WORD table_key, uuid_t * txnid, int64_t nonce); read_query * init_read_query(cell_address * cell_address, uuid_t * txnid, int64_t nonce); read_query * init_read_query_copy(cell_address * cell_address, uuid_t * txnid, int64_t nonce); void free_read_query(read_query * ca); int serialize_read_query(read_query * ca, void ** buf, unsigned * len, vector_clock * vc); int deserialize_read_query(void * buf, unsigned msg_len, read_query ** ca); char * to_string_read_query(read_query * ca, char * msg_buff); int equals_read_query(read_query * ca1, read_query * ca2); typedef struct ack_message { cell_address * cell_address; int status; uuid_t * txnid; int64_t nonce; } ack_message; ack_message * init_ack_message(cell_address * cell_address, int status, uuid_t * txnid, int64_t nonce); void free_ack_message(ack_message * ca); int serialize_ack_message(ack_message * ca, void ** buf, unsigned * len, vector_clock * vc); int deserialize_ack_message(void * buf, unsigned msg_len, ack_message ** ca); char * to_string_ack_message(ack_message * ca, char * msg_buff); int equals_ack_message(ack_message * ca1, ack_message * ca2); typedef struct range_read_query { cell_address * start_cell_address; cell_address * end_cell_address; uuid_t * txnid; int64_t nonce; } range_read_query; range_read_query * build_range_search_in_txn(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, WORD table_key, uuid_t * txnid, int64_t nonce); range_read_query * build_range_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, WORD table_key, uuid_t * txnid, int64_t nonce); range_read_query * build_range_search_index_in_txn(int idx_idx, WORD start_idx_key, WORD end_idx_key, WORD table_key, uuid_t * txnid, int64_t nonce); range_read_query * build_wildcard_range_search_in_txn(WORD table_key, uuid_t * txnid, int64_t nonce); range_read_query * init_range_read_query(cell_address * start_cell_address, cell_address * end_cell_address, uuid_t * txnid, int64_t nonce); range_read_query * init_range_read_query_copy(cell_address * start_cell_address, cell_address * end_cell_address, uuid_t * txnid, int64_t nonce); void free_range_read_query(range_read_query * ca); int serialize_range_read_query(range_read_query * ca, void ** buf, unsigned * len, vector_clock * vc); int deserialize_range_read_query(void * buf, unsigned msg_len, range_read_query ** ca); char * to_string_range_read_query(range_read_query * ca, char * msg_buff); int equals_range_read_query(range_read_query * ca1, range_read_query * ca2); typedef struct range_read_response_message { cell * cells; int no_cells; uuid_t * txnid; int64_t nonce; } range_read_response_message; range_read_response_message * init_range_read_response_message(cell * cells, int no_cells, uuid_t * txnid, int64_t nonce); void free_range_read_response_message(range_read_response_message * ca); int serialize_range_read_response_message(range_read_response_message * ca, void ** buf, unsigned * len, vector_clock * vc); int deserialize_range_read_response_message(void * buf, unsigned msg_len, range_read_response_message ** ca); char * to_string_range_read_response_message(range_read_response_message * ca, char * msg_buff); int equals_range_read_response_message(range_read_response_message * ca1, range_read_response_message * ca2); typedef struct queue_query_message { cell_address * cell_address; // queue address short msg_type; // {CREATE, DELETE, SUBSCRIBE, UNSUBSCRIBE, ENQUEUE, READ_QUEUE, CONSUME_QUEUE, READ_QUEUE_RESPONSE} int app_id; int shard_id; int consumer_id; int group_id; // For ENQUEUE and READ_QUEUE_RESPONSE: cell * cells; int no_cells; // For READ_QUEUE (== max_entries) and CONSUME_QUEUE (== new_consume_head): int64_t queue_index; // For RESPONSE type messages: short status; uuid_t * txnid; int64_t nonce; } queue_query_message; queue_query_message * build_create_queue_in_txn(WORD table_key, WORD queue_id, uuid_t * txnid, int64_t nonce); queue_query_message * build_delete_queue_in_txn(WORD table_key, WORD queue_id, uuid_t * txnid, int64_t nonce); queue_query_message * build_enqueue_in_txn(WORD * column_values, int no_cols, WORD blob, size_t blob_size, WORD table_key, WORD queue_id, uuid_t * txnid, int64_t nonce); queue_query_message * build_read_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int max_entries, uuid_t * txnid, int64_t nonce); queue_query_message * build_consume_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, uuid_t * txnid, int64_t nonce); queue_query_message * build_subscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, uuid_t * txnid, int64_t nonce); queue_query_message * build_unsubscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, uuid_t * txnid, int64_t nonce); queue_query_message * build_subscribe_group_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, uuid_t * txnid, int64_t nonce); queue_query_message * build_unsubscribe_group_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, uuid_t * txnid, int64_t nonce); queue_query_message * build_add_queue_to_group_in_txn(WORD table_key, WORD queue_id, WORD group_id, uuid_t * txnid, int64_t nonce); queue_query_message * build_remove_queue_from_group_in_txn(WORD table_key, WORD queue_id, WORD group_id, uuid_t * txnid, int64_t nonce); queue_query_message * init_create_queue_message(cell_address * cell_address, uuid_t * txnid, int64_t nonce); queue_query_message * init_delete_queue_message(cell_address * cell_address, uuid_t * txnid, int64_t nonce); queue_query_message * init_subscribe_queue_message(cell_address * cell_address, int app_id, int shard_id, int consumer_id, int group_id, uuid_t * txnid, int64_t nonce); queue_query_message * init_unsubscribe_queue_message(cell_address * cell_address, int app_id, int shard_id, int consumer_id, int group_id, uuid_t * txnid, int64_t nonce); queue_query_message * init_add_queue_to_group_message(cell_address * cell_address, int group_id, uuid_t * txnid, int64_t nonce); queue_query_message * init_remove_queue_from_group_message(cell_address * cell_address, int group_id, uuid_t * txnid, int64_t nonce); queue_query_message * init_enqueue_message(cell_address * cell_address, cell * cells, int no_cells, uuid_t * txnid, int64_t nonce); queue_query_message * init_read_queue_message(cell_address * cell_address, int app_id, int shard_id, int consumer_id, int64_t max_entries, uuid_t * txnid, int64_t nonce); queue_query_message * init_consume_queue_message(cell_address * cell_address, int app_id, int shard_id, int consumer_id, int64_t new_consume_head, uuid_t * txnid, int64_t nonce); queue_query_message * init_read_queue_response(cell_address * cell_address, cell * cells, int no_cells, int app_id, int shard_id, int consumer_id, int group_id, int64_t new_read_head, short status, uuid_t * txnid, int64_t nonce); queue_query_message * init_queue_notification(cell_address * cell_address, cell * cells, int no_cells, int app_id, int shard_id, int consumer_id, int group_id, int64_t new_no_entries, short status, uuid_t * txnid, int64_t nonce); void free_queue_message(queue_query_message * ca); int serialize_queue_message(queue_query_message * ca, void ** buf, unsigned * len, short for_server, vector_clock * vc); int deserialize_queue_message(void * buf, unsigned msg_len, queue_query_message ** ca); char * to_string_queue_message(queue_query_message * ca, char * msg_buff); int equals_queue_message(queue_query_message * ca1, queue_query_message * ca2); typedef struct txn_message { int type; cell * own_read_set; int no_own_read_set; cell * own_write_set; int no_own_write_set; cell * complete_read_set; int no_complete_read_set; cell * complete_write_set; int no_complete_write_set; uuid_t * txnid; vector_clock * version; int64_t nonce; } txn_message; txn_message * build_new_txn(uuid_t * txnid, int64_t nonce); txn_message * build_validate_txn(uuid_t * txnid, vector_clock * version, int64_t nonce); txn_message * build_abort_txn(uuid_t * txnid, int64_t nonce); txn_message * build_commit_txn(uuid_t * txnid, vector_clock * version, int64_t nonce); txn_message * init_txn_message(int type, cell * own_read_set, int no_own_read_set, cell * own_write_set, int no_own_write_set, cell * complete_read_set, int no_complete_read_set, cell * complete_write_set, int no_complete_write_set, uuid_t * txnid, vector_clock * version, int64_t nonce); txn_message * init_txn_message_copy(int type, cell * own_read_set, int no_own_read_set, cell * own_write_set, int no_own_write_set, cell * complete_read_set, int no_complete_read_set, cell * complete_write_set, int no_complete_write_set, uuid_t * txnid, vector_clock * version, int64_t nonce); void free_txn_message(txn_message * ca); int serialize_txn_message(txn_message * ca, void ** buf, unsigned * len, short for_server, vector_clock * vc); int deserialize_txn_message(void * buf, unsigned msg_len, txn_message ** ca); char * to_string_txn_message(txn_message * ca, char * msg_buff); int equals_txn_message(txn_message * ca1, txn_message * ca2); typedef struct gossip_listen_message { node_description * node_description; int64_t nonce; } gossip_listen_message; gossip_listen_message * build_gossip_listen_msg(node_description * nd, int64_t nonce); void free_gossip_listen_msg(gossip_listen_message * gs); int serialize_gossip_listen_msg(gossip_listen_message * gs, void ** buf, unsigned * len); int deserialize_gossip_listen_msg(void * buf, unsigned msg_len, gossip_listen_message ** gl); int equals_gossip_listen_msg(gossip_listen_message * gs1, gossip_listen_message * gs2); char * to_string_gossip_listen_msg(gossip_listen_message * gs, char * msg_buff); #endif /* BACKEND_FAILURE_DETECTOR_DB_QUERIES_H_ */ ================================================ FILE: backend/failure_detector/fd.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * fd.c * Author: aagapi */ #include "fd.h" #include "db_messages.pb-c.h" #include "../log.h" #include #include #include #include #include #include #include #include /* Node description: */ void init_ns_msg_from_description(NodeStateMessage * ns_msg, node_description * nd) { ns_msg->status = nd->status; ns_msg->node_id = nd->node_id; ns_msg->rack_id = nd->rack_id; ns_msg->dc_id = nd->dc_id; ns_msg->port = nd->portno; assert(nd->hostname != NULL); ns_msg->hostname.len = strnlen(nd->hostname, 256) + 1; ns_msg->hostname.data = malloc(ns_msg->hostname.len); memcpy(ns_msg->hostname.data, nd->hostname, ns_msg->hostname.len); } int copy_node_description(node_description * nd, int status, int node_id, int rack_id, int dc_id, char * hostname, unsigned short portno) { nd->status = status; nd->node_id = node_id; nd->rack_id = rack_id; nd->dc_id = dc_id; nd->portno = portno; bzero((void *) &nd->address, sizeof(struct sockaddr_in)); nd->hostname = NULL; if(hostname != NULL) { struct hostent * host = gethostbyname(hostname); if (host == NULL) { log_error("ERROR, no such host %s", hostname); assert(0); return -1; } nd->address.sin_family = AF_INET; bcopy((char *)host->h_addr, (char *)&(nd->address.sin_addr.s_addr), host->h_length); nd->address.sin_port = htons(portno); nd->hostname = strndup(hostname, strnlen(hostname, 256) + 1); } return 0; } node_description * init_node_description(int status, int node_id, int rack_id, int dc_id, char * hostname, unsigned short portno) { node_description * nd = (node_description *) malloc(sizeof(node_description)); copy_node_description(nd, status, node_id, rack_id, dc_id, hostname, portno); return nd; } void free_node_description(node_description * nd) { if(nd->hostname != NULL) free(nd->hostname); free(nd); } int equals_node_description(node_description * nd1, node_description * nd2) { return nd1->node_id == nd2->node_id && nd1->rack_id == nd2->rack_id && nd1->dc_id == nd2->dc_id; } char * to_string_node_description(node_description * nd, char * msg_buff) { sprintf(msg_buff, "Node(status=%d, node_id=%d, rack_id=%d, dc_id=%d, hostname=%s, port=%d)", nd->status, nd->node_id, nd->rack_id, nd->dc_id, (nd->hostname != NULL)?(nd->hostname):"NULL", nd->portno); return msg_buff; } /* Gossip state: */ gossip_state * init_gossip_state(int status, int node_id, int rack_id, int dc_id, char * hostname, unsigned short portno, vector_clock * vc) { gossip_state * gs = (gossip_state *) malloc(sizeof(struct gossip_state)); bzero(gs, sizeof(struct gossip_state)); copy_node_description(&(gs->nd), status, node_id, rack_id, dc_id, hostname, portno); gs->vc = (vc != NULL)?vc:init_vc(0, NULL, NULL, 0); return gs; } void free_gossip_state(gossip_state * gs) { free_vc(gs->vc); free(gs); } void free_gossip_msg(GossipMessage * msg) { free_vc_msg(msg->vc); } void init_ns_msg(NodeStateMessage * ns_msg, gossip_state * gs) { init_ns_msg_from_description(ns_msg, &(gs->nd)); } int serialize_gs(gossip_state * gs, void ** buf, unsigned * len) { GossipMessage msg = GOSSIP_MESSAGE__INIT; VectorClockMessage vc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&vc_msg, gs->vc); NodeStateMessage ns_msg = NODE_STATE_MESSAGE__INIT; init_ns_msg(&ns_msg, gs); msg.vc = &vc_msg; msg.node_state = &ns_msg; *len = gossip_message__get_packed_size (&msg); *buf = malloc (*len); gossip_message__pack (&msg, *buf); free_gossip_msg(&msg); return 0; } int deserialize_gs(void * buf, unsigned msg_len, gossip_state ** gs) { GossipMessage * msg = gossip_message__unpack(NULL, msg_len, buf); if (msg == NULL) { // Something failed log_error("error unpacking gossip_state message"); return 1; } vector_clock * vc = init_vc_from_msg(msg->vc); *gs = init_gossip_state(msg->node_state->status, msg->node_state->node_id, msg->node_state->rack_id, msg->node_state->dc_id, (char *) msg->node_state->hostname.data, msg->node_state->port, vc); return 0; } int equals_gs(gossip_state * gs1, gossip_state * gs2) { return equals_node_description(&(gs1->nd), &(gs2->nd)) && gs1->nd.status == gs2->nd.status && compare_vc(gs1->vc, gs2->vc) == 0; } char * to_string_gs(gossip_state * gs, char * msg_buff) { sprintf(msg_buff, "GS(node_description="); to_string_node_description(&(gs->nd), msg_buff + strlen(msg_buff)); sprintf(msg_buff, ", vc="); to_string_vc(gs->vc, msg_buff + strlen(msg_buff)); sprintf(msg_buff + strlen(msg_buff), ")"); return msg_buff; } /* Membership: */ membership_state * init_membership_state(int no_nodes, node_description * membership, int no_client_nodes, node_description * client_membership, vector_clock * view_id) { membership_state * ms = (membership_state *) malloc(sizeof(membership_state)); ms->no_nodes = no_nodes; ms->membership = membership; ms->no_client_nodes = no_client_nodes; ms->client_membership = client_membership; ms->view_id = view_id; return ms; } membership_state * clone_membership(membership_state * m) { membership_state * ms = (membership_state *) malloc(sizeof(membership_state)); ms->no_nodes = m->no_nodes; ms->membership = (node_description *) malloc(m->no_nodes * sizeof(node_description)); for(int i=0;ino_nodes;i++) copy_node_description(ms->membership + i, m->membership[i].status, m->membership[i].node_id, m->membership[i].rack_id, m->membership[i].dc_id, m->membership[i].hostname, m->membership[i].portno); ms->no_client_nodes = m->no_client_nodes; ms->client_membership = (node_description *) malloc(m->no_client_nodes * sizeof(node_description)); for(int i=0;ino_client_nodes;i++) copy_node_description(ms->client_membership + i, m->client_membership[i].status, m->client_membership[i].node_id, m->client_membership[i].rack_id, m->client_membership[i].dc_id, m->client_membership[i].hostname, m->client_membership[i].portno); ms->view_id = (m->view_id != NULL)?(copy_vc(m->view_id)):(NULL); return ms; } void free_membership_state(membership_state * ms, int do_free_vc) { free(ms->membership); free(ms->client_membership); if(do_free_vc) free_vc(ms->view_id); free(ms); } void free_membership_msg(MembershipViewMessage * msg) { free_vc_msg(msg->view_id); for(int i=0;in_membership;i++) free(msg->membership[i]); free(msg->membership); for(int i=0;in_client_membership;i++) free(msg->client_membership[i]); free(msg->client_membership); } void init_membership_msg(MembershipViewMessage * msg, membership_state * m, VectorClockMessage * view_id_msg) { NodeStateMessage **membership_v = (NodeStateMessage **) malloc (m->no_nodes * sizeof (NodeStateMessage*)); NodeStateMessage **client_membership_v = NULL; if(m->no_client_nodes > 0) client_membership_v = (NodeStateMessage **) malloc (m->no_client_nodes * sizeof (NodeStateMessage*)); for(int i = 0; i < m->no_nodes; i++) { membership_v[i] = malloc (sizeof (NodeStateMessage)); node_state_message__init(membership_v[i]); init_ns_msg_from_description(membership_v[i], m->membership+i); } msg->n_membership = m->no_nodes; msg->membership = membership_v; for(int i = 0; i < m->no_client_nodes; i++) { client_membership_v[i] = malloc (sizeof (NodeStateMessage)); node_state_message__init(client_membership_v[i]); init_ns_msg_from_description(client_membership_v[i], m->client_membership+i); } msg->n_client_membership = m->no_client_nodes; msg->client_membership = client_membership_v; msg->view_id = view_id_msg; } int serialize_membership_state(membership_state * m, void ** buf, unsigned * len) { MembershipViewMessage msg = MEMBERSHIP_VIEW_MESSAGE__INIT; VectorClockMessage view_id_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&view_id_msg, m->view_id); init_membership_msg(&msg, m, &view_id_msg); *len = membership_view_message__get_packed_size (&msg); *buf = malloc (*len); membership_view_message__pack (&msg, *buf); free_membership_msg(&msg); return 0; } membership_state * init_membership_from_msg(MembershipViewMessage * msg) { vector_clock * view_id = init_vc_from_msg(msg->view_id); node_description * membership = (node_description *) malloc(msg->n_membership * sizeof(node_description)); for(int i=0;in_membership;i++) copy_node_description(membership+i, msg->membership[i]->status, msg->membership[i]->node_id, msg->membership[i]->rack_id, msg->membership[i]->dc_id, (char *) msg->membership[i]->hostname.data, (unsigned short) msg->membership[i]->port); node_description * client_membership = NULL; if(msg->n_client_membership > 0) { client_membership = (node_description *) malloc(msg->n_client_membership * sizeof(node_description)); for(int i=0;in_client_membership;i++) copy_node_description(client_membership+i, msg->client_membership[i]->status, msg->client_membership[i]->node_id, msg->client_membership[i]->rack_id, msg->client_membership[i]->dc_id, (char *) msg->client_membership[i]->hostname.data, (unsigned short) msg->client_membership[i]->port); } return init_membership_state(msg->n_membership, membership, msg->n_client_membership, client_membership, view_id); } int deserialize_membership_state(void * buf, unsigned msg_len, membership_state ** ms) { MembershipViewMessage * msg = membership_view_message__unpack(NULL, msg_len, buf); if (msg == NULL) { log_error("error unpacking membership view message"); return 1; } *ms = init_membership_from_msg(msg); return 0; } int equals_membership_state(membership_state * gs1, membership_state * gs2) { if(gs1->no_nodes != gs2->no_nodes) return 0; for(int i=0;ino_nodes;i++) if(!equals_node_description(gs1->membership + i, gs2->membership + i)) return 0; if(gs1->no_client_nodes != gs2->no_client_nodes) return 0; for(int i=0;ino_client_nodes;i++) if(!equals_node_description(gs1->client_membership + i, gs2->client_membership + i)) return 0; return 1; } char * to_string_membership_state(membership_state * gs, char * msg_buff) { char * crt_ptr = msg_buff; sprintf(crt_ptr, "Membership("); crt_ptr += strlen(crt_ptr); for(int i=0;ino_nodes;i++) { to_string_node_description(gs->membership+i, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", "); crt_ptr += 2; } sprintf(crt_ptr, "), Client Membership("); crt_ptr += strlen("), Client Membership("); for(int i=0;ino_client_nodes;i++) { to_string_node_description(gs->client_membership+i, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", "); crt_ptr += 2; } return msg_buff; } /* Membership agreement messages: */ membership_agreement_msg * init_membership_agreement_msg(int msg_type, int ack_status, membership_state * membership, int64_t nonce, vector_clock * vc) { membership_agreement_msg * ma = (membership_agreement_msg *) malloc(sizeof(membership_agreement_msg)); ma->msg_type = msg_type; ma->ack_status = ack_status; ma->membership = membership; ma->nonce = nonce; ma->vc = vc; return ma; } membership_agreement_msg * get_membership_propose_msg(int ack_status, membership_state * membership, int64_t nonce, vector_clock * vc) { return init_membership_agreement_msg(MEMBERSHIP_AGREEMENT_PROPOSE, ack_status, membership, nonce, vc); } membership_agreement_msg * get_membership_response_msg(int ack_status, membership_state * membership, int64_t nonce, vector_clock * vc) { return init_membership_agreement_msg(MEMBERSHIP_AGREEMENT_RESPONSE, ack_status, membership, nonce, vc); } membership_agreement_msg * get_membership_notify_msg(int ack_status, membership_state * membership, int64_t nonce, vector_clock * vc) { return init_membership_agreement_msg(MEMBERSHIP_AGREEMENT_NOTIFY, ack_status, membership, nonce, vc); } membership_agreement_msg * get_membership_notify_ack_msg(int ack_status, int64_t nonce, vector_clock * vc) { return init_membership_agreement_msg(MEMBERSHIP_AGREEMENT_NOTIFY_ACK, ack_status, NULL, nonce, vc); } membership_agreement_msg * get_membership_join_msg(int status, int rack_id, int dc_id, char * hostname, unsigned short portno, int64_t nonce, vector_clock * vc) { node_description * nd = init_node_description(status, -1, rack_id, dc_id, hostname, portno); nd->node_id = get_node_id((struct sockaddr *) &(nd->address)); membership_state * membership = init_membership_state(1, nd, 0, NULL, copy_vc(vc)); return init_membership_agreement_msg(MEMBERSHIP_AGREEMENT_JOIN, status, membership, nonce, vc); } void free_membership_agreement(membership_agreement_msg * ma) { if(ma->membership != NULL) free_membership_state(ma->membership, 1); if(ma->vc != NULL) free_vc(ma->vc); free(ma); } void free_membership_agreement_msg(MembershipAgreementMessage * msg) { if(msg->vc != NULL) free_vc_msg(msg->vc); if(msg->view != NULL) free_membership_msg(msg->view); } int serialize_membership_agreement_msg(membership_agreement_msg * ma, void ** buf, unsigned * len) { MembershipAgreementMessage msg = MEMBERSHIP_AGREEMENT_MESSAGE__INIT; VectorClockMessage vc_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&vc_msg, ma->vc); msg.vc = &vc_msg; if(ma->membership != NULL) { MembershipViewMessage mview_msg = MEMBERSHIP_VIEW_MESSAGE__INIT; VectorClockMessage view_id_msg = VECTOR_CLOCK_MESSAGE__INIT; init_vc_msg(&view_id_msg, ma->membership->view_id); init_membership_msg(&mview_msg, ma->membership, &view_id_msg); msg.view = &mview_msg; } else { msg.view = NULL; } msg.msg_type = ma->msg_type; msg.ack_status = ma->ack_status; msg.nonce = ma->nonce; *len = membership_agreement_message__get_packed_size (&msg); *len = (*len) + sizeof(int); *buf = malloc (*len); memset(*buf, 0 , *len); *((int *)(*buf)) = (*len) - sizeof(int); membership_agreement_message__pack (&msg, (void *) ((int *)(*buf) + 1)); free_membership_agreement_msg(&msg); return 0; } int deserialize_membership_agreement_msg(void * buf, unsigned msg_len, membership_agreement_msg ** ma) { MembershipAgreementMessage * msg = membership_agreement_message__unpack(NULL, msg_len, buf); if (msg == NULL) { log_error("error unpacking membership agreement message"); return 1; } vector_clock * vc = init_vc_from_msg(msg->vc); membership_state * membership = (msg->view != NULL)?(init_membership_from_msg(msg->view)):(NULL); *ma = init_membership_agreement_msg(msg->msg_type, msg->ack_status, membership, msg->nonce, vc); return 0; } int equals_membership_agreement_msg(membership_agreement_msg * ma1, membership_agreement_msg * ma2) { if(ma1->nonce != ma2->nonce || ma1->msg_type != ma2->msg_type || ma1->ack_status != ma2->ack_status) return 0; if((ma1->membership != NULL && ma2->membership == NULL) || (ma1->membership == NULL && ma2->membership != NULL) || !equals_membership_state(ma1->membership, ma2->membership)) return 0; if(compare_vc(ma1->vc, ma2->vc) != 0) return 0; return 1; } char * to_string_membership_agreement_msg(membership_agreement_msg * ma, char * msg_buff) { char * crt_ptr = msg_buff; sprintf(crt_ptr, "Membership_agreement_msg(type=%d, ack_status=%d, nonce=%" PRId64 ", ", ma->msg_type, ma->ack_status, ma->nonce); crt_ptr += strlen(crt_ptr); if(ma->membership != NULL) { to_string_membership_state(ma->membership, crt_ptr); crt_ptr += strlen(crt_ptr); sprintf(crt_ptr, ", "); crt_ptr += 2; } if(ma->vc != NULL) { to_string_vc(ma->vc, crt_ptr); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, ")"); return msg_buff; } ================================================ FILE: backend/failure_detector/fd.h ================================================ /* * fd.h * * Author: aagapi */ #ifndef BACKEND_FAILURE_DETECTOR_FD_H_ #define BACKEND_FAILURE_DETECTOR_FD_H_ #include "vector_clock.h" #define MAX_MSG_SIZE_GS (MAX_MSG_SIZE_VC + 16) #define SKIP_PROPOSAL_STATUS 10 /* Node description: */ typedef struct node_description { int status; int node_id; int rack_id; int dc_id; char * hostname; unsigned short portno; struct sockaddr_in address; } node_description; node_description * init_node_description(int status, int node_id, int rack_id, int dc_idm, char * hostname, unsigned short portno); int copy_node_description(node_description * nd, int status, int node_id, int rack_id, int dc_id, char * hostname, unsigned short portno); void free_node_description(node_description * vc); int equals_node_description(node_description * nd1, node_description * nd2); char * to_string_node_description(node_description * nd, char * msg_buff); void init_ns_msg_from_description(NodeStateMessage * ns_msg, node_description * nd); /* Gossip state: */ typedef struct gossip_state { node_description nd; vector_clock * vc; } gossip_state; gossip_state * init_gossip_state(int status, int node_id, int rack_id, int dc_id, char * hostname, unsigned short portno, vector_clock * vc); void free_gossip_state(gossip_state * vc); int serialize_gs(gossip_state * gs, void ** buf, unsigned * len); int deserialize_gs(void * buf, unsigned msg_len, gossip_state ** gs); int equals_gs(gossip_state * gs1, gossip_state * gs2); char * to_string_gs(gossip_state * gs, char * msg_buff); /* Membership view: */ typedef struct membership_state { int no_nodes; node_description * membership; int no_client_nodes; node_description * client_membership; vector_clock * view_id; } membership_state; membership_state * init_membership_state(int no_nodes, node_description * membership, int no_client_nodes, node_description * client_membership, vector_clock * view_id); void free_membership_state(membership_state * ms, int do_free_vc); int serialize_membership_state(membership_state * gs, void ** buf, unsigned * len); int deserialize_membership_state(void * buf, unsigned msg_len, membership_state ** gs); int equals_membership_state(membership_state * gs1, membership_state * gs2); char * to_string_membership_state(membership_state * gs, char * msg_buff); /* Membership agreement messages: */ #define MEMBERSHIP_AGREEMENT_PROPOSE 0 #define MEMBERSHIP_AGREEMENT_RESPONSE 1 #define MEMBERSHIP_AGREEMENT_NOTIFY 2 #define MEMBERSHIP_AGREEMENT_RETRY_LINK 3 #define MEMBERSHIP_AGREEMENT_NOTIFY_ACK 4 #define MEMBERSHIP_AGREEMENT_JOIN 5 #define ACK 0 #define NACK 1 #define UNINIT 2 typedef struct membership_agreement_msg { int msg_type; int ack_status; membership_state * membership; int64_t nonce; vector_clock * vc; } membership_agreement_msg; membership_agreement_msg * get_membership_propose_msg(int ack_status, membership_state * membership, int64_t nonce, vector_clock * vc); membership_agreement_msg * get_membership_response_msg(int ack_status, membership_state * membership, int64_t nonce, vector_clock * vc); membership_agreement_msg * get_membership_notify_msg(int ack_status, membership_state * membership, int64_t nonce, vector_clock * vc); membership_agreement_msg * get_membership_notify_ack_msg(int ack_status, int64_t nonce, vector_clock * vc); membership_agreement_msg * get_membership_join_msg(int status, int rack_id, int dc_id, char * hostname, unsigned short portno, int64_t nonce, vector_clock * vc); membership_agreement_msg * init_membership_agreement_msg(int msg_type, int ack_status, membership_state * membership, int64_t nonce, vector_clock * vc); void free_membership_agreement(membership_agreement_msg * ma); void free_membership_agreement_msg(MembershipAgreementMessage * msg); int serialize_membership_agreement_msg(membership_agreement_msg * gs, void ** buf, unsigned * len); int deserialize_membership_agreement_msg(void * buf, unsigned msg_len, membership_agreement_msg ** ma); int equals_membership_agreement_msg(membership_agreement_msg * ma1, membership_agreement_msg * ma2); char * to_string_membership_agreement_msg(membership_agreement_msg * gs, char * msg_buff); #endif /* BACKEND_FAILURE_DETECTOR_FD_H_ */ ================================================ FILE: backend/failure_detector/txns.h ================================================ /* * txns.h * Author: aagapi */ #ifndef BACKEND_FAILURE_DETECTOR_TXNS_H_ #define BACKEND_FAILURE_DETECTOR_TXNS_H_ typedef struct txn_message { int64_t txnid; } txn_message; #endif /* BACKEND_FAILURE_DETECTOR_TXNS_H_ */ ================================================ FILE: backend/failure_detector/vector_clock.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * vector_clock.c * * Author: aagapi */ #include "vector_clock.h" #include "db_messages.pb-c.h" #include #include #include // #include "cfuhash.h" int increment_vc(vector_clock * vc, int node_id) { // Binary search node_id: int found_idx = -1, exact_match = 0; BINARY_SEARCH_NODEID(vc, node_id, found_idx, exact_match); if(!exact_match) return -1; vc->node_ids[found_idx].counter++; return 0; } // Returns: // -2 of vc1 and vc2 are incomparable // -1 if vc1 < vc2 // 0 if vc1 == vc2 // 1 if vc1 > vc2 int compare_vc(vector_clock * vc1, vector_clock * vc2) { if(vc1 == NULL && vc2 == NULL) return 0; if(vc1 == NULL || vc2 == NULL) return VC_INCOMPARABLE; if(vc1->no_nodes != vc2->no_nodes) return VC_INCOMPARABLE; int first_bigger = 0, second_bigger = 0; for(int i=0;ino_nodes;i++) { if(vc1->node_ids[i].node_id != vc2->node_ids[i].node_id) return VC_INCOMPARABLE; if(vc1->node_ids[i].counter > vc2->node_ids[i].counter) first_bigger = 1; else if(vc1->node_ids[i].counter < vc2->node_ids[i].counter) second_bigger = 1; } if(first_bigger && second_bigger) return VC_DISJOINT; else if(first_bigger) return 1; else if(second_bigger) return -1; else return 0; } int update_vc(vector_clock * vc_dest, vector_clock * vc_src) { int dest_idx = 0; int status = 0; for(int i=0;ino_nodes;i++) { dest_idx = 0; while(vc_dest->node_ids[dest_idx].node_id < vc_src->node_ids[i].node_id && dest_idx < vc_dest->no_nodes) dest_idx++; if(dest_idx < vc_dest->no_nodes && vc_dest->node_ids[dest_idx].node_id == vc_src->node_ids[i].node_id) // We have found the i'th component. Update it to the maximum of the 2 vectors: { if(vc_src->node_ids[i].counter > vc_dest->node_ids[dest_idx].counter) vc_dest->node_ids[dest_idx].counter = vc_src->node_ids[i].counter; } else // Source vector has a component that dest vector doesn't. Add that component to the dest vector: { status = add_component_vc(vc_dest, vc_src->node_ids[i].node_id, vc_src->node_ids[i].counter); assert(status == 0); } } return 0; } int update_or_replace_vc(vector_clock ** vc_dest, vector_clock * vc_src) { int alloc_new_vc = (*vc_dest == NULL || (*vc_dest)->no_nodes != vc_src->no_nodes); if(!alloc_new_vc) { for(int n=0;nno_nodes;n++) { if((*vc_dest)->node_ids[n].node_id != vc_src->node_ids[n].node_id) { alloc_new_vc = 1; break; } else { (*vc_dest)->node_ids[n].counter = vc_src->node_ids[n].counter; } } } if(alloc_new_vc) { if(*vc_dest != NULL) free_vc(*vc_dest); (*vc_dest) = copy_vc(vc_src); } return 0; } int add_component_vc(vector_clock * vc, int node_id, int initial_counter) { // Binary search node_id: int found_idx = 0, exact_match = 0; BINARY_SEARCH_NODEID(vc, node_id, found_idx, exact_match); if(exact_match) return -1; // Component already existed if(vc->no_nodes == vc->capacity) grow_vc(vc); // Insert component in its location and shift rest to keep vector sorted // Note that this is a rare operation: for(int idx = vc->no_nodes;idx>found_idx+1;idx--) vc->node_ids[idx] = vc->node_ids[idx-1]; vc->node_ids[found_idx+1].node_id = node_id; vc->node_ids[found_idx+1].counter = (initial_counter > 0)?initial_counter:0; vc->no_nodes++; return 0; } int64_t get_component_vc(vector_clock * vc, int node_id) { // Binary search node_id: int found_idx = 0, exact_match = 0; BINARY_SEARCH_NODEID(vc, node_id, found_idx, exact_match); if(exact_match) return vc->node_ids[found_idx].counter; else return -1; } // S'd never call this in principle: int remove_component_vc(vector_clock * vc, int node_id) { // Binary search node_id: int found_idx = -1, exact_match = 0; BINARY_SEARCH_NODEID(vc, node_id, found_idx, exact_match); if(!exact_match) return -1; // Component doesn't exist // Remove component and shift the rest: for(int idx = found_idx; idx < vc->no_nodes ;idx++) vc->node_ids[idx] = vc->node_ids[idx+1]; vc->no_nodes--; return 0; } int cmpfunc (const void * a, const void * b) { return (((struct versioned_id *)a)->node_id - ((struct versioned_id *)b)->node_id); } vector_clock * init_vc(int init_no_nodes, int * node_ids, int64_t * counters, int sort_node_ids) { vector_clock * vc = (vector_clock *) malloc(sizeof(struct vector_clock)); memset(vc, 0, sizeof(struct vector_clock)); vc->no_nodes = (init_no_nodes > 0)? init_no_nodes:0; vc->capacity = (int)(((init_no_nodes > DEFAULT_SIZE)?init_no_nodes:DEFAULT_SIZE) * GROWTH_RATE); // printf("Alloc-ing vc of capacity %d for no_nodes = %d\n", vc->capacity, vc->no_nodes); vc->node_ids = (versioned_id *) malloc (vc->capacity * sizeof(struct versioned_id)); memset(vc->node_ids, 0, vc->capacity * sizeof(struct versioned_id)); for(int i=0;ino_nodes;i++) { vc->node_ids[i].node_id = (node_ids != NULL)? node_ids[i]:0; vc->node_ids[i].counter = (counters != NULL)?counters[i]:0; } if(sort_node_ids) // Only call with sort_node_ids true if input node_ids not already sorted { qsort(vc->node_ids, vc->no_nodes, sizeof(struct versioned_id), cmpfunc); } return vc; } int get_node_id(struct sockaddr * x) { #define LSB 16 assert(x->sa_family == AF_INET || x->sa_family == AF_INET6); // AF_UNIX? if (x->sa_family == AF_INET) { struct sockaddr_in *xin = (struct sockaddr_in *)x; return (ntohl(xin->sin_addr.s_addr) << LSB) | (ntohs(xin->sin_port)); } else if (x->sa_family == AF_INET6) { struct sockaddr_in6 *xin6 = (struct sockaddr_in6 *)x; uint32_t * addr = (uint32_t *) xin6->sin6_addr.s6_addr; return (ntohl(addr[1]) << LSB) | (ntohs(xin6->sin6_port)); // use least significant host bits of the host portion of a IPV6 address } return 0; } vector_clock * init_empty_vc() { return init_vc(0, NULL, NULL, 0); } vector_clock * init_local_vc_id(int local_id) { int64_t counter = 0; return init_vc(1, &local_id, &counter, 0); } vector_clock * init_local_vc(struct sockaddr * x) { assert(x != NULL); return init_local_vc_id(get_node_id(x)); } vector_clock * copy_vc(vector_clock * vc1) { vector_clock * vc = (vector_clock *) malloc(sizeof(struct vector_clock)); vc->no_nodes = vc1->no_nodes; vc->capacity = vc1->capacity; vc->node_ids = (versioned_id *) malloc (vc->capacity * sizeof(struct versioned_id)); for(int i=0;ino_nodes;i++) { vc->node_ids[i].node_id = vc1->node_ids[i].node_id; vc->node_ids[i].counter = vc1->node_ids[i].counter; } return vc; } vector_clock * init_vc_from_msg(VectorClockMessage * msg) { vector_clock * vc = init_vc(msg->n_ids, NULL, NULL, 0); for (int i = 0; i < vc->no_nodes; i++) { vc->node_ids[i].node_id = msg->ids[i]; vc->node_ids[i].counter = msg->counters[i]; } return vc; } int grow_vc(vector_clock * vc) { vc->capacity = (int)(vc->no_nodes * GROWTH_RATE); versioned_id * new_vector = (versioned_id *) malloc (vc->capacity * sizeof (struct versioned_id)); memcpy(new_vector, vc->node_ids, vc->no_nodes * sizeof (struct versioned_id)); free(vc->node_ids); vc->node_ids = new_vector; return 0; } void free_vc(vector_clock * vc) { if(vc == NULL) return; if(vc->node_ids != NULL) free(vc->node_ids); free(vc); } void init_vc_msg(VectorClockMessage * msg_ptr, vector_clock * vc) { msg_ptr->n_ids = vc->no_nodes; msg_ptr->ids = (int32_t *) malloc (msg_ptr->n_ids * sizeof(int32_t)); msg_ptr->n_counters = vc->no_nodes; msg_ptr->counters = (int64_t *) malloc (msg_ptr->n_counters * sizeof(int64_t)); for (int i = 0; i < msg_ptr->n_ids; i++) { (msg_ptr->ids)[i] = vc->node_ids[i].node_id; (msg_ptr->counters)[i] = vc->node_ids[i].counter; } } void free_vc_msg(VectorClockMessage * msg) { free(msg->ids); free(msg->counters); } char * to_string_vc(vector_clock * vc, char * msg_buff) { char * crt_ptr = msg_buff; if(vc == NULL) { sprintf(crt_ptr, "VC(NULL)"); return msg_buff; } sprintf(crt_ptr, "VC("); crt_ptr += strlen(crt_ptr); for(int i=0;ino_nodes;i++) { sprintf(crt_ptr, "%s%d:%" PRId64, i>0?", ":"", vc->node_ids[i].node_id, vc->node_ids[i].counter); crt_ptr += strlen(crt_ptr); } sprintf(crt_ptr, ")"); return msg_buff; } ================================================ FILE: backend/failure_detector/vector_clock.h ================================================ /* * vector_clock.h * * Author: aagapi */ #ifndef BACKEND_FAILURE_DETECTOR_VECTOR_CLOCK_H_ #define BACKEND_FAILURE_DETECTOR_VECTOR_CLOCK_H_ #define DEFAULT_SIZE 8 #define GROWTH_RATE 2.0 #define VC_INCOMPARABLE -2 #define VC_DISJOINT -3 #include "db_messages.pb-c.h" #include #include #include #include // Sets in found_idx index of node_id (if found), or first smallest index (if not found): #define BINARY_SEARCH_NODEID(vc, node_id, found_idx, exact_match) \ (exact_match) = 0; \ (found_idx) = -1; \ int first = 0, last = (vc)->no_nodes - 1; \ int middle = (first+last)/2; \ for(;first <= last; middle = (first + last)/2) \ { \ if((vc)->node_ids[middle].node_id == (node_id)) \ { \ (found_idx) = middle; \ (exact_match) = 1; \ break; \ } \ else if((vc)->node_ids[middle].node_id < (node_id)) \ { \ (found_idx) = middle; \ first = middle + 1; \ } \ else \ last = middle - 1; \ } \ typedef struct versioned_id { int node_id; int64_t counter; } versioned_id; typedef struct vector_clock { int no_nodes; int capacity; versioned_id * node_ids; } vector_clock; int increment_vc(vector_clock * vc, int node_id); int compare_vc(vector_clock * vc1, vector_clock * vc2); int update_vc(vector_clock * vc_dest, vector_clock * vc_src); int update_or_replace_vc(vector_clock ** vc_dest, vector_clock * vc_src); int add_component_vc(vector_clock * vc, int node_id, int initial_counter); int64_t get_component_vc(vector_clock * vc, int node_id); int remove_component_vc(vector_clock * vc, int node_id); vector_clock * init_vc(int init_no_nodes, int * node_ids, int64_t * counters, int sort_node_ids); vector_clock * init_empty_vc(); vector_clock * init_local_vc_id(int local_id); vector_clock * init_local_vc(struct sockaddr * x); vector_clock * copy_vc(vector_clock * vc1); vector_clock * init_vc_from_msg(VectorClockMessage * msg); void init_vc_msg(VectorClockMessage * msg_ptr, vector_clock * vc); void free_vc_msg(VectorClockMessage * msg); void free_vc(vector_clock * vc); int grow_vc(vector_clock * vc); // int serialize_vc(vector_clock * vc, void ** buf, unsigned * len); // int deserialize_vc(void * buf, unsigned msg_len, vector_clock ** vc); char * to_string_vc(vector_clock * vc, char * msg_buff); int get_node_id(struct sockaddr * x); #endif /* BACKEND_FAILURE_DETECTOR_VECTOR_CLOCK_H_ */ ================================================ FILE: backend/fastrand.h ================================================ #include #ifndef FASTRAND_H_ #define FASTRAND_H_ #if( defined _POSIX_THREADS && _POSIX_TIMERS >= 0 && _POSIX_MONOTONIC_CLOCK >= 0 ) #define GET_RANDSEED(seedptr, rand) \ { \ struct timespec tp; \ clock_gettime( CLOCK_MONOTONIC_RAW, &tp ); \ *(seedptr) = (unsigned int) ((tp.tv_nsec & 0xFFFFFFFF00000000) + (tp.tv_nsec & 0x00000000FFFFFFFF) + rand) ; \ } #else #define GET_RANDSEED(seedptr, rand) \ { \ int64_t now = time(NULL); \ *(seedptr) = (unsigned int) ((now & 0xFFFFFFFF00000000) + (now & 0x00000000FFFFFFFF) + rand) ; \ } #endif #define FASTRAND(seedptr, value) \ { *seedptr = (214013*(*seedptr)+2531011); \ value = ((*seedptr)>>16)&0x7FFF; \ } static unsigned int g_seed; inline static void fast_srand(int seed) { g_seed = seed; } inline static int fastrand() { g_seed = (214013*g_seed+2531011); return (g_seed>>16)&0x7FFF; } #endif /* FASTRAND_H_ */ ================================================ FILE: backend/hash_ring.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * hash_ring.c * - Thread safe consistent hashing API * Author: aagapi */ #include "hash_ring.h" #include "hashes.h" hash_ring * get_hash_ring() { hash_ring * ring = (hash_ring *) malloc(sizeof(hash_ring) + sizeof(pthread_mutex_t)); memset(ring, 0, sizeof(hash_ring) + sizeof(pthread_mutex_t)); ring->buckets = create_skiplist_long(); ring->live_buckets = 0; ring->lock = (pthread_mutex_t*) ((char*) ring + sizeof(hash_ring)); pthread_mutex_init(ring->lock, NULL); return ring; } void free_hash_ring(hash_ring * ring, void (*free_val)(WORD)) { if(free_val == NULL) { skiplist_free(ring->buckets); } else { skiplist_free_val(ring->buckets, free_val); } free(ring); } int add_bucket(hash_ring * ring, WORD bucket, void* (*get_key)(void *), void* (*get_live_field)(void *), unsigned int * fastrandstate) { pthread_mutex_lock(ring->lock); uint32_t id_hash = hash32((uint32_t) get_key(bucket)); if(skiplist_search(ring->buckets, (WORD) id_hash) != NULL) { pthread_mutex_unlock(ring->lock); return -1; } if(*((int *) get_live_field(bucket)) == BUCKET_LIVE) ring->live_buckets++; int status = skiplist_insert(ring->buckets, (WORD) id_hash, bucket, fastrandstate); pthread_mutex_unlock(ring->lock); return status; } snode_t * lookup_bucket(hash_ring * ring, WORD bucket_id) { WORD id_hash = (WORD) hash32((uint32_t) bucket_id); return skiplist_search(ring->buckets, id_hash); } int get_bucket_status(hash_ring * ring, WORD bucket, void* (*get_key)(void *), void* (*get_live_field)(void *)) { snode_t * node = NULL; pthread_mutex_lock(ring->lock); uint32_t id_hash = hash32((uint32_t) get_key(bucket)); node = skiplist_search(ring->buckets, (WORD) id_hash); if(node == NULL) { pthread_mutex_unlock(ring->lock); return -1; } int status = *((int *) get_live_field(node->value)); pthread_mutex_unlock(ring->lock); return status; } int set_bucket_status(hash_ring * ring, WORD bucket, int status, void* (*get_key)(void *), void* (*get_live_field)(void *)) { snode_t * node = NULL; pthread_mutex_lock(ring->lock); uint32_t id_hash = hash32((uint32_t) bucket); // hash32((uint32_t) get_key(bucket)); node = skiplist_search(ring->buckets, (WORD) id_hash); if(node == NULL) { pthread_mutex_unlock(ring->lock); return -1; } if(*((int *) get_live_field(node->value)) != status) { if(status == BUCKET_LIVE) ring->live_buckets++; else ring->live_buckets--; } *((int *) get_live_field(node->value)) = status; pthread_mutex_unlock(ring->lock); return 0; } int mark_bucket_dead(hash_ring * ring, WORD bucket, void* (*get_key)(void *), void* (*get_live_field)(void *)) { return set_bucket_status(ring, bucket, BUCKET_DEAD, get_key, get_live_field); } int mark_bucket_live(hash_ring * ring, WORD bucket, void* (*get_key)(void *), void* (*get_live_field)(void *)) { return set_bucket_status(ring, bucket, BUCKET_LIVE, get_key, get_live_field); } WORD get_buckets_for_object(hash_ring * ring, int object_id, int replication_factor, void* (*get_key)(void *), void* (*get_live_field)(void *), unsigned int * fastrandstate) { pthread_mutex_lock(ring->lock); skiplist_t * result = (replication_factor > 1)?create_skiplist_long():NULL; int status = 0; int replicas = (replication_factor < ring->live_buckets)?replication_factor:ring->live_buckets; if(replicas == 0) { pthread_mutex_unlock(ring->lock); return NULL; } snode_t * snode = skiplist_search_higher(ring->buckets, (WORD) hash32((uint32_t) object_id)); while(result == NULL || result->no_items < replicas) { if(snode == NULL) { // Wrap back to the beginning of the ring: snode = HEAD(ring->buckets); } if(*((int *) get_live_field(snode->value)) == BUCKET_LIVE) { if(replication_factor > 1) { status = skiplist_insert(result, (WORD) get_key(snode->value), snode->value, fastrandstate); assert(status == 0); } pthread_mutex_unlock(ring->lock); return (WORD) snode->value; } snode = NEXT(snode); } pthread_mutex_unlock(ring->lock); return (WORD) result; } ================================================ FILE: backend/hash_ring.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * hash_ring.h * - Thread safe consistent hashing API * Author: aagapi */ #ifndef BACKEND_HASH_RING_H_ #define BACKEND_HASH_RING_H_ #include "common.h" #include "skiplist.h" #define BUCKET_LIVE 0 #define BUCKET_DEAD 1 typedef struct hash_ring { skiplist_t * buckets; int live_buckets; pthread_mutex_t * lock; } hash_ring; hash_ring * get_hash_ring(); void free_hash_ring(hash_ring * ring, void (*free_val)(WORD)); int add_bucket(hash_ring * ring, WORD bucket, void * (*get_key)(void *), void * (*get_live_field)(void *), unsigned int * fastrandstate); snode_t * lookup_bucket(hash_ring * ring, WORD bucket_id); int get_bucket_status(hash_ring * ring, WORD bucket, void * (*get_key)(void *), void * (*get_live_field)(void *)); int set_bucket_status(hash_ring * ring, WORD bucket, int status, void * (*get_key)(void *), void * (*get_live_field)(void *)); int mark_bucket_dead(hash_ring * ring, WORD bucket, void * (*get_key)(void *), void * (*get_live_field)(void *)); int mark_bucket_live(hash_ring * ring, WORD bucket, void * (*get_key)(void *), void * (*get_live_field)(void *)); WORD get_buckets_for_object(hash_ring * ring, int object_id, int replication_factor, void * (*get_key)(void *), void * (*get_live_field)(void *), unsigned int * fastrandstate); #endif /* BACKEND_HASH_RING_H_ */ ================================================ FILE: backend/hashes.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef BACKEND_HASHES_H_ #define BACKEND_HASHES_H_ uint32_t hash32(uint32_t x) // Collision free, each input bit affects each output bit with ~50% probability { x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; return x; } #endif /* BACKEND_HASHES_H_ */ ================================================ FILE: backend/log.c ================================================ /* * Copyright (c) 2020 rxi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "log.h" #define MAX_CALLBACKS 32 typedef struct { log_LogFn fn; void *udata; int level; } Callback; static struct { void *udata; log_LockFn lock; int level; bool quiet; Callback callbacks[MAX_CALLBACKS]; } L; static const char *level_strings[] = { "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" }; #ifdef LOG_USE_COLOR static const char *level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" }; #endif static void stdout_callback(log_Event *ev) { char buf[16]; buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->date)] = '\0'; #ifdef LOG_USE_COLOR fprintf( ev->udata, "%s.%06lu %s%-5s\x1b[0m \x1b[90m%-20s:%5d:\x1b[0m ", buf, ev->ts.tv_nsec/1000, level_colors[ev->level], level_strings[ev->level], ev->file, ev->line); #else fprintf( ev->udata, "%s.%06lu %-5s %-20s:%5d: ", buf, ev->ts.tv_nsec/1000, level_strings[ev->level], ev->file, ev->line); #endif vfprintf(ev->udata, ev->fmt, ev->ap); fprintf(ev->udata, "\n"); fflush(ev->udata); } static void file_callback(log_Event *ev) { char buf[64]; buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->date)] = '\0'; fprintf( ev->udata, "%s.%09lu %-5s %-20s:%5d: ", buf, ev->ts.tv_nsec, level_strings[ev->level], ev->file, ev->line); vfprintf(ev->udata, ev->fmt, ev->ap); fprintf(ev->udata, "\n"); fflush(ev->udata); } static void lock(void) { if (L.lock) { L.lock(true, L.udata); } } static void unlock(void) { if (L.lock) { L.lock(false, L.udata); } } const char* log_level_string(int level) { return level_strings[level]; } void log_set_lock(log_LockFn fn, void *udata) { L.lock = fn; L.udata = udata; } void log_set_level(int level) { L.level = level; } void log_set_quiet(bool enable) { L.quiet = enable; } int log_add_callback(log_LogFn fn, void *udata, int level) { for (int i = 0; i < MAX_CALLBACKS; i++) { if (!L.callbacks[i].fn) { L.callbacks[i] = (Callback) { fn, udata, level }; return 0; } } return -1; } int log_add_fp(FILE *fp, int level) { return log_add_callback(file_callback, fp, level); } static void init_event(log_Event *ev, void *udata) { if (!ev->date) { clock_gettime(CLOCK_REALTIME, &ev->ts); ev->date = localtime(&ev->ts.tv_sec); } ev->udata = udata; } void log_log(int level, const char *file, int line, const char *fmt, ...) { log_Event ev = { .fmt = fmt, .file = file, .line = line, .level = level, }; lock(); if (!L.quiet && level >= L.level) { init_event(&ev, stderr); va_start(ev.ap, fmt); stdout_callback(&ev); va_end(ev.ap); } for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { Callback *cb = &L.callbacks[i]; if (level >= cb->level) { init_event(&ev, cb->udata); va_start(ev.ap, fmt); cb->fn(&ev); va_end(ev.ap); } } unlock(); } ================================================ FILE: backend/log.h ================================================ /** * Copyright (c) 2020 rxi * * This library is free software; you can redistribute it and/or modify it * under the terms of the MIT license. See `log.c` for details. */ #ifndef LOG_H #define LOG_H #include #include #include #include #define LOG_VERSION "0.1.0" typedef struct { va_list ap; const char *fmt; const char *file; struct timespec ts; struct tm *date; void *udata; int line; int level; } log_Event; typedef void (*log_LogFn)(log_Event *ev); typedef void (*log_LockFn)(bool lock, void *udata); enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) #define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) #define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) const char* log_level_string(int level); void log_set_lock(log_LockFn fn, void *udata); void log_set_level(int level); void log_set_quiet(bool enable); int log_add_callback(log_LogFn fn, void *udata, int level); int log_add_fp(FILE *fp, int level); void log_log(int level, const char *file, int line, const char *fmt, ...); #endif ================================================ FILE: backend/queue.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * queue.c * * Author: aagapi */ #include "queue.h" #include "log.h" #include "failure_detector/cells.h" #include "failure_detector/db_queries.h" #include #include #include #include #define MIN(x, y) (((x)<(y))?(x):(y)) #define MAX(x, y) (((x)>(y))?(x):(y)) #define VERBOSITY 1 #define LOCK_VERBOSITY 0 db_table_t * get_table_by_key(WORD table_key, db_t * db) { snode_t * node = skiplist_search(db->tables, table_key); if(node == NULL) return NULL; return (db_table_t *) (node->value); } int create_queue_table(WORD table_id, int no_cols, int * col_types, db_t * db, unsigned int * fastrandstate) { int primary_key_idx = 0; // queue_id int clustering_key_idx = 1; // entry_id int total_cols = no_cols+2; int * total_col_types = (int *) malloc(total_cols * sizeof(int)); for(int i=0;i 0) log_info("Queue table %" PRId64 " created", (int64_t) table_id); #endif return ret; } // Functions for handling remote notifications: int get_queue_notification_packet(WORD table_key, WORD queue_id, WORD app_id, WORD shard_id, WORD consumer_id, WORD group_id, int64_t new_no_entries, int status, void ** snd_buf, unsigned * snd_msg_len) { cell_address ca; copy_cell_address(&ca, (int64_t) table_key, (int64_t *) &queue_id, 1); queue_query_message * m = init_queue_notification(&ca, NULL, 0, (int) app_id, (int) shard_id, (int) consumer_id, (int) group_id, new_no_entries, status, NULL, -1); #if (VERBOSE_RPC > 0) char print_buff[1024]; to_string_queue_message(m, (char *) print_buff); log_debug("Sending queue notification message: %s", print_buff); #endif int ret = serialize_queue_message(m, snd_buf, snd_msg_len, 0, NULL); assert(ret == 0); free_queue_message(m); return ret; } int notify_remote_queue_subscribers(WORD table_key, WORD queue_id, db_t * db) { db_table_t * table = get_table_by_key(table_key, db); int status = 0; if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); // Notify remote subscribers if they haven't been notified: for(snode_t * cell=HEAD(db_row->consumer_state);cell!=NULL;cell=NEXT(cell)) { if(cell->value != NULL) { consumer_state * cs = (consumer_state *) (cell->value); if(cs->callback != NULL || cs->notified > 0) // Skip local subscribers or ones that have already been notified: continue; assert(cs->sockfd != NULL); if(*(cs->sockfd) == 0) { #if (VERBOSITY > 0) log_debug("SERVER: Skipping notifying disconnected subscriber %" PRId64 "", (int64_t) cs->consumer_id); continue; #endif } void * snd_buf = NULL; unsigned snd_msg_len = -1; status = get_queue_notification_packet(table_key, queue_id, cs->app_id, cs->shard_id, cs->consumer_id, cs->group_id, db_row->no_entries, 0, &snd_buf, &snd_msg_len); assert(status == 0); int n = write(*(cs->sockfd), snd_buf, snd_msg_len); if (n < 0) { log_error("ERROR writing notification to socket!"); continue; } free(snd_buf); cs->notified=1; #if (VERBOSITY > 0) log_debug("SERVER: Notified remote subscriber %" PRId64 "", (int64_t) cs->consumer_id); #endif } } return status; } void notify_subscriber(consumer_state * cs, WORD table_key, WORD queue_id, db_row_t * db_row) { int status = 0, ret = 0; if(cs->group_id >= 0) // Skip group subscribers (these will be notified via their group) { // #if (VERBOSITY > 0) // log_debug("BACKEND: Skipping notifying group subscriber %" PRId64 " for queue %d because it will be notified via group notifications", (int64_t) cs->consumer_id, (int) queue_id); // #endif return; } if(cs->notified > 0) // Skip already notified subscribers (whether local or remote) { // #if (VERBOSITY > 0) // log_debug("BACKEND: Skipping notifying subscriber %" PRId64 " for queue %d because it was already notified", (int64_t) cs->consumer_id); // #endif return; } if(cs->callback != NULL) // Local subscriber { assert(cs->sockfd == NULL); queue_callback_args * qca = get_queue_callback_args(table_key, queue_id, cs->app_id, cs->shard_id, cs->consumer_id, cs->group_id, QUEUE_NOTIF_ENQUEUED); #if (VERBOSITY > 0) log_debug("BACKEND: Attempting to notify local subscriber %" PRId64 " (%p/%p/%p/%p)", (int64_t) qca->consumer_id, cs->callback, cs->callback->lock, cs->callback->signal, cs->callback->callback); #endif ret = pthread_mutex_lock(cs->callback->lock); #if (LOCK_VERBOSITY > 0) log_debug("BACKEND: Locked consumer lock of %" PRId64 " (%p/%p), status=%d", (int64_t) qca->consumer_id, cs->callback, cs->callback->lock, ret); #endif pthread_cond_signal(cs->callback->signal); cs->callback->callback(qca); ret = pthread_mutex_unlock(cs->callback->lock); #if (LOCK_VERBOSITY > 0) log_debug("BACKEND: Unlocked consumer lock of %" PRId64 " (%p/%p), status=%d", (int64_t) qca->consumer_id, cs->callback, cs->callback->lock, ret); #endif } else // remote subscriber { assert(cs->sockfd != NULL); if(*(cs->sockfd) == 0) { #if (VERBOSITY > 0) log_debug("SERVER: Skipping notifying disconnected remote subscriber %" PRId64 "", (int64_t) cs->consumer_id); #endif return; } void * snd_buf = NULL; unsigned snd_msg_len = -1; status = get_queue_notification_packet(table_key, queue_id, cs->app_id, cs->shard_id, cs->consumer_id, cs->group_id, db_row->no_entries, 0, &snd_buf, &snd_msg_len); assert(status == 0); int n = write(*(cs->sockfd), snd_buf, snd_msg_len); if (n < 0) { fprintf(stderr, "ERROR writing notification to socket!\n"); return; } free(snd_buf); } cs->notified=1; #if (VERBOSITY > 0) log_debug("BACKEND: Notified %s subscriber %" PRId64 "", (cs->callback != NULL)?"local":"remote", (int64_t) cs->consumer_id); #endif } void notify_subscribers(skiplist_t * subscriber_list, WORD table_key, WORD queue_id, db_row_t * db_row) { for(snode_t * cell=HEAD(subscriber_list);cell!=NULL;cell=NEXT(cell)) { if(cell->value != NULL) { consumer_state * cs = (consumer_state *) (cell->value); notify_subscriber(cs, table_key, queue_id, db_row); } } } int enqueue(WORD * column_values, int no_cols, size_t last_blob_size, WORD table_key, WORD queue_id, short use_lock, db_t * db, unsigned int * fastrandstate) { db_table_t * table = get_table_by_key(table_key, db); int ret = 0; if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); if(use_lock) { pthread_mutex_lock(db_row->enqueue_lock); } int64_t entry_id = db_row->no_entries; db_row->no_entries++; if(use_lock) { pthread_mutex_unlock(db_row->enqueue_lock); } // Add queue_id as partition key and entry_id as clustering key: WORD * queue_column_values = (WORD *) malloc((no_cols + 2) * sizeof(WORD)); queue_column_values[0]=queue_id; queue_column_values[1]=(WORD) entry_id; for(int64_t i=2;i 0) log_debug("BACKEND: Inserted queue entry %" PRId64 " in queue %" PRId64 "/%" PRId64 ", status=%d", entry_id, (int64_t) table_key, (int64_t) queue_id, status); #endif // Notify individual queue subscribers if they haven't been notified: notify_subscribers(db_row->consumer_state, table_key, queue_id, db_row); // Similarly notify all group subscribers: if(db_row->group_subscriptions != NULL) { if(db->queue_group_replication_factor > 1) { for(snode_t * cell=HEAD((skiplist_t *) db_row->group_subscriptions);cell!=NULL;cell=NEXT(cell)) { group_state * gs = (group_state *) (cell->value); notify_subscribers(gs->consumers, table_key, queue_id, db_row); } } else { notify_subscribers(((group_state *) db_row->group_subscriptions)->consumers, table_key, queue_id, db_row); #if (VERBOSITY > 0) log_debug("BACKEND: Notified group subscribers from group %d (%d subscribers)", (int) ((group_state *) db_row->group_subscriptions)->group_id, ((group_state *) db_row->group_subscriptions)->consumers->no_items); #endif } } return status; } int lookup_consumer_state_in_group(WORD queue_id, WORD consumer_id, db_row_t * db_row, consumer_state ** cs, db_t * db) { if(db_row->group_subscriptions == NULL) // Queue's group is already cached by 'auto_update_group_queue_subscriptions()', no need to call 'get_buckets_for_object()' again { log_debug("SERVER: lookup_consumer_state_in_group(%d), found no group state!", (int) queue_id); *cs = NULL; return DB_ERR_NO_GROUP; } if(db->queue_group_replication_factor == 1) { group_state * gs = (group_state *) db_row->group_subscriptions; log_debug("SERVER: lookup_consumer_state_in_group(%d, %d), found group state: group_id = %d, status = %d, consumers = %d", (int) queue_id, (int) consumer_id, ((gs != NULL)?((int) gs->group_id):(-1)), ((gs != NULL)?((int) gs->status):(-1)), ((gs != NULL)?((int) gs->consumers->no_items):(-1))); return lookup_listener_in_group(gs, consumer_id, queue_id, cs); } else { skiplist_t * gss = (skiplist_t *) db_row->group_subscriptions; for(snode_t * cell=HEAD(gss);cell!=NULL;cell=NEXT(cell)) { if(cell->value != NULL) { group_state * gs = (group_state *) cell->value; int ret = lookup_listener_in_group(gs, consumer_id, queue_id, cs); if(ret == 0) { log_debug("SERVER: lookup_consumer_state_in_group(%d), found group state: group_id = %d, status = %d, consumers = %d", (int) queue_id, ((gs != NULL)?((int) gs->group_id):(-1)), ((gs != NULL)?((int) gs->status):(-1)), ((gs != NULL)?((int) gs->consumers->no_items):(-1))); return 0; } } } return DB_ERR_NO_CONSUMER; } } int lookup_consumer_state_in_row_or_group(WORD queue_id, WORD consumer_id, db_row_t * db_row, consumer_state ** cs, consumer_state ** group_cs, db_t * db) { *cs = NULL; *group_cs = NULL; snode_t * consumer_node = skiplist_search(db_row->consumer_state, consumer_id); if(consumer_node == NULL) return DB_ERR_NO_CONSUMER; *cs = (consumer_state *) (consumer_node->value); lookup_consumer_state_in_group(queue_id, consumer_id, db_row, group_cs, db); return 0; } void sanity_check_consumer_read_heads(int64_t old_read_head, int64_t old_consume_head, int64_t new_read_head) { assert(old_read_head <= new_read_head); assert(old_consume_head <= new_read_head); } void sanity_check_consumer_consume_heads(int64_t old_read_head, int64_t old_consume_head, int64_t new_consume_head) { assert(old_read_head >= new_consume_head); assert(old_consume_head <= new_consume_head); } int is_consumer_notified(consumer_state * cs, consumer_state * gqcs) { return (gqcs != NULL)?(gqcs->notified):(cs->notified); } void set_consumer_notified(consumer_state * cs, consumer_state * gqcs, int value) { if(gqcs != NULL) gqcs->notified=value; cs->notified=value; } int set_private_read_head(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_read_head, vector_clock * version, short use_lock, db_t * db) { db_table_t * table = get_table_by_key(table_key, db); if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); int64_t no_entries = db_row->no_entries; consumer_state * cs = NULL, * gqcs = NULL; int ret = lookup_consumer_state_in_row_or_group(queue_id, consumer_id, db_row, &cs, &gqcs, db); if(ret != 0) return ret; // Consumer or group doesn't exist assert (cs != NULL || gqcs != NULL); if(use_lock) { pthread_mutex_lock(db_row->read_lock); } assert(new_read_head <= no_entries - 1); assert(version != NULL); int64_t old_read_head = READ_HEAD(cs), old_consume_head = CONSUME_HEAD(cs); sanity_check_consumer_read_heads(old_read_head, old_consume_head, new_read_head); cs->private_read_head = new_read_head; update_or_replace_vc(&(cs->prh_version), version); if(use_lock) { pthread_mutex_unlock(db_row->read_lock); } return 0; } int set_private_consume_head(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, vector_clock * version, db_t * db) { db_table_t * table = get_table_by_key(table_key, db); if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); int64_t no_entries = db_row->no_entries; consumer_state * cs = NULL, * gqcs = NULL; int ret = lookup_consumer_state_in_row_or_group(queue_id, consumer_id, db_row, &cs, &gqcs, db); if(ret != 0) return ret; // Consumer or group doesn't exist assert (cs != NULL || gqcs != NULL); assert(new_consume_head <= no_entries - 1); assert(version != NULL); int64_t old_read_head = READ_HEAD(cs), old_consume_head = CONSUME_HEAD(cs); sanity_check_consumer_consume_heads(old_read_head, old_consume_head, new_consume_head); if(old_consume_head <= new_consume_head) { cs->private_consume_head = new_consume_head; update_or_replace_vc(&(cs->pch_version), version); } return 0; } int read_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int max_entries, int * entries_read, int64_t * new_read_head, vector_clock ** prh_version, snode_t** start_row, snode_t** end_row, short use_lock, db_t * db) { db_table_t * table = get_table_by_key(table_key, db); *entries_read=0; if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); int64_t no_entries = db_row->no_entries; consumer_state * cs = NULL, * gqcs = NULL; int ret = lookup_consumer_state_in_row_or_group(queue_id, consumer_id, db_row, &cs, &gqcs, db); if(ret != 0) return ret; // Consumer or group doesn't exist assert (cs != NULL || gqcs != NULL); if(use_lock) { pthread_mutex_lock(db_row->read_lock); } if(cs->private_read_head > no_entries - 1) { log_debug("BACKEND: ERROR Subscriber %" PRId64 " trying to read from queue %" PRId64 " , prev_read_head=%" PRId64 ", no_entries=%" PRId64 "", (int64_t) cs->consumer_id, queue_id, cs->private_read_head, no_entries); assert(0); } int64_t old_read_head = READ_HEAD(cs); vector_clock * old_prh_vsn = READ_HEAD_VERSION(cs); *prh_version = (old_prh_vsn != NULL)? copy_vc(old_prh_vsn) : NULL; if(old_read_head == no_entries - 1) { if(use_lock) { pthread_mutex_unlock(db_row->read_lock); } *new_read_head = old_read_head; return QUEUE_STATUS_READ_COMPLETE; // Nothing to read } *new_read_head = MIN(old_read_head + max_entries, no_entries - 1); int64_t start_index = old_read_head + 1; cs->private_read_head = *new_read_head; if(use_lock) { pthread_mutex_unlock(db_row->read_lock); } int64_t no_results = (int64_t) table_range_search_clustering((WORD *) &queue_id, (WORD*) &start_index, (WORD*) new_read_head, 1, start_row, end_row, table); assert(no_results == (*new_read_head - start_index + 1)); #if (VERBOSITY > 0) log_debug("BACKEND: Subscriber %" PRId64 " read %" PRId64 " queue entries from queue %" PRId64 ", new_read_head=%" PRId64 "", (int64_t) cs->consumer_id, no_results, queue_id, cs->private_read_head); #endif *entries_read = (int) no_results; ret = ((*new_read_head) == (no_entries - 1))? QUEUE_STATUS_READ_COMPLETE : QUEUE_STATUS_READ_INCOMPLETE; if(ret == QUEUE_STATUS_READ_COMPLETE) { set_consumer_notified(cs, gqcs, 0); } return ret; } int peek_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int max_entries, int64_t offset, int * entries_read, int64_t * new_read_head, vector_clock ** prh_version, snode_t** start_row, snode_t** end_row, db_t * db) { db_table_t * table = get_table_by_key(table_key, db); *entries_read=0; if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); int64_t no_entries = db_row->no_entries; consumer_state * cs = NULL, * gqcs = NULL; int ret = lookup_consumer_state_in_row_or_group(queue_id, consumer_id, db_row, &cs, &gqcs, db); if(ret != 0) return ret; // Consumer or group doesn't exist assert (cs != NULL || gqcs != NULL); int64_t old_read_head = READ_HEAD(cs); vector_clock * old_prh_vsn = READ_HEAD_VERSION(cs); int64_t start_offset = (offset >= 0)?offset:old_read_head; assert(start_offset <= no_entries - 1); *prh_version = (old_prh_vsn != NULL)? copy_vc(old_prh_vsn) : NULL; if(start_offset == no_entries - 1) { *new_read_head = start_offset; return QUEUE_STATUS_READ_COMPLETE; // Nothing to read } *new_read_head = MIN(start_offset + max_entries, no_entries - 1); int64_t start_index = start_offset + 1; int64_t no_results = (int64_t) table_range_search_clustering((WORD *) &queue_id, (WORD*) &start_index, (WORD*) new_read_head, 1, start_row, end_row, table); assert(no_results == (*new_read_head - start_index + 1)); #if (VERBOSITY > 0) log_debug("BACKEND: Subscriber %" PRId64 " peeked %" PRId64 " / %" PRId64 " queue entries, new_read_head=%" PRId64 ", private_read_head=%" PRId64 "", (int64_t) cs->consumer_id, no_results, no_entries, *new_read_head, old_read_head); #endif *entries_read = (int) no_results; ret = ((*new_read_head) == (no_entries - 1))? QUEUE_STATUS_READ_COMPLETE : QUEUE_STATUS_READ_INCOMPLETE; return ret; } int replay_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t replay_offset, int max_entries, int * entries_read, int64_t * new_replay_offset, snode_t** start_row, snode_t** end_row, db_t * db) { db_table_t * table = get_table_by_key(table_key, db); *entries_read=0; if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); int64_t no_entries = db_row->no_entries; consumer_state * cs = NULL, * gqcs = NULL; int ret = lookup_consumer_state_in_row_or_group(queue_id, consumer_id, db_row, &cs, &gqcs, db); if(ret != 0) return ret; // Consumer or group doesn't exist assert (cs != NULL || gqcs != NULL); // set_consumer_notified(cs, gqcs, 0); // Replays don't count as notification consumptions int64_t old_read_head = READ_HEAD(cs), old_consume_head = CONSUME_HEAD(cs); assert(old_read_head <= no_entries - 1); assert(old_consume_head + replay_offset <= old_read_head); if(old_consume_head + replay_offset == old_read_head) { return QUEUE_STATUS_READ_COMPLETE; // // Nothing to replay } *new_replay_offset = MIN(old_consume_head + replay_offset + max_entries, old_read_head); int64_t start_index = old_consume_head + replay_offset; int64_t no_results = (int64_t) table_range_search_clustering((WORD *) &queue_id, (WORD*) &start_index, (WORD*) new_replay_offset, 1, start_row, end_row, table); *entries_read = (int) no_results; if(no_results != (*new_replay_offset) - start_index) { log_debug("table_range_search_clustering(%" PRId64 "-%" PRId64 ") returned %" PRId64 " entries!", start_index, *new_replay_offset, no_results); print_long_db(db); assert(0); } #if (VERBOSITY > 0) log_debug("BACKEND: Subscriber %" PRId64 " replayed %" PRId64 " queue entries, new_replay_offset=%" PRId64 "", (int64_t) cs->consumer_id, no_results, *new_replay_offset); #endif ret = ((*new_replay_offset) == old_read_head)? QUEUE_STATUS_READ_COMPLETE : QUEUE_STATUS_READ_INCOMPLETE; return ret; } int consume_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, db_t * db) { db_table_t * table = get_table_by_key(table_key, db); if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); consumer_state * cs = NULL, * gqcs = NULL; int ret = lookup_consumer_state_in_row_or_group(queue_id, consumer_id, db_row, &cs, &gqcs, db); if(ret != 0) return ret; // Consumer or group doesn't exist assert (cs != NULL || gqcs != NULL); int64_t old_read_head = READ_HEAD(cs), old_consume_head = CONSUME_HEAD(cs); set_consumer_notified(cs, gqcs, 0); assert(old_consume_head <= old_read_head); if(new_consume_head > old_read_head) { return DB_ERR_QUEUE_HEAD_INVALID; // // Invalid consume } if(new_consume_head == old_consume_head) { return DB_ERR_QUEUE_COMPLETE; // // Nothing to consume } cs->private_consume_head = new_consume_head; #if (VERBOSITY > 0) log_debug("BACKEND: Subscriber %" PRId64 " consumed entries, new_consume_head=%" PRId64 ", read_head=%" PRId64 "", (int64_t) cs->consumer_id, new_consume_head, old_read_head); #endif return (int) new_consume_head; } int __subscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, db_row_t * db_row, WORD group_id, queue_callback * callback, int * sockfd, int64_t * prev_read_head, int64_t * prev_consume_head, short use_lock, db_t * db, unsigned int * fastrandstate) { if(use_lock) pthread_mutex_lock(db_row->subscribe_lock); *prev_read_head = -1; *prev_consume_head = -1; snode_t * consumer_node = skiplist_search(db_row->consumer_state, consumer_id); if(consumer_node != NULL) { consumer_state * found_cs = (consumer_state *) (consumer_node->value); log_debug("BACKEND: ERR: Found consumer state %" PRId64 " when searching for consumer_id %" PRId64 "!", (int64_t) found_cs->consumer_id, (int64_t) consumer_id); *prev_read_head = found_cs->private_read_head; *prev_consume_head = found_cs->private_consume_head; if(use_lock) pthread_mutex_unlock(db_row->subscribe_lock); return DB_ERR_DUPLICATE_CONSUMER; // Consumer already exists! } consumer_state * cs = get_consumer_state(consumer_id, shard_id, app_id, group_id, callback, sockfd, 0); int ret = skiplist_insert(db_row->consumer_state, consumer_id, cs, fastrandstate); if(use_lock) pthread_mutex_unlock(db_row->subscribe_lock); #if (VERBOSITY > 0) log_debug("BACKEND: Subscriber %" PRId64 "/%" PRId64 "/%" PRId64 "/%" PRId64 " subscribed queue %" PRId64 " with callback %p", (int64_t) cs->app_id, (int64_t) cs->shard_id, (int64_t) cs->consumer_id, (int64_t) cs->group_id, (int64_t) db_row->key, cs->callback); #endif return ret; } int _subscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, WORD group_id, queue_callback * callback, int * sockfd, int64_t * prev_read_head, int64_t * prev_consume_head, short use_lock, db_t * db, unsigned int * fastrandstate) { db_table_t * table = get_table_by_key(table_key, db); if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); int ret = __subscribe_queue(consumer_id, shard_id, app_id, db_row, group_id, callback, sockfd, prev_read_head, prev_consume_head, use_lock, db, fastrandstate); return ret; } int _subscribe_group(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, queue_callback * callback, int * sockfd, short use_lock, db_t * db, unsigned int * fastrandstate) { group_state * found_group = NULL; snode_t * group_node = lookup_bucket(db->queue_groups, group_id); int ret = 0; if(group_node == NULL) // Group doesn't exist { found_group = get_group((WORD) group_id); ret = add_listener_to_group(found_group, consumer_id, shard_id, app_id, callback, sockfd, fastrandstate); log_debug("BACKEND: Bucket %d not found, adding it as %p", group_id, found_group); add_bucket(db->queue_groups, found_group, &get_group_state_key, &get_group_state_live_field, fastrandstate); } else { found_group = (group_state *) (group_node->value); ret = add_listener_to_group(found_group, consumer_id, shard_id, app_id, callback, sockfd, fastrandstate); if(ret == DB_ERR_DUPLICATE_CONSUMER) { log_debug("BACKEND: Warning: Found previously existing consumer state in queue group %p, group_id = %" PRId64 " when searching for consumer_id %" PRId64 "!", found_group, (int64_t) group_id, (int64_t) consumer_id); } } #if (VERBOSITY > 0) log_debug("BACKEND: Subscriber %" PRId64 "/%" PRId64 "/%" PRId64 " subscribed to group %p, group_id=%" PRId64 " with callback %p, fd %d, group now has %d consumers", (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, found_group, (int64_t) group_id, callback, *sockfd, found_group->consumers->no_items); #endif return ret; } int _unsubscribe_group(WORD consumer_id, WORD group_id, db_t * db) { snode_t * group_node = lookup_bucket(db->queue_groups, group_id); if(group_node == NULL) return DB_ERR_NO_GROUP; // Group doesn't exist group_state * found_group = (group_state *) (group_node->value); int ret = remove_listener_from_group(found_group, consumer_id); if(ret == DB_ERR_NO_CONSUMER) { log_debug("BACKEND: Warning: Found no previously existing consumer state in queue group %" PRId64 " when attempting to remove consumer_id %" PRId64 "!", (int64_t) group_id, (int64_t) consumer_id); } #if (VERBOSITY > 0) log_debug("BACKEND: Subscriber %" PRId64 " unsubscribed from group %" PRId64 "", (int64_t) consumer_id, (int64_t) group_id); #endif return ret; } int subscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, short use_lock, db_t * db, unsigned int * fastrandstate) { assert(callback != NULL); return _subscribe_queue(consumer_id, shard_id, app_id, table_key, queue_id, (WORD) -1, callback, NULL, prev_read_head, prev_consume_head, use_lock, db, fastrandstate); } int register_remote_subscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, WORD group_id, int * sockfd, int64_t * prev_read_head, int64_t * prev_consume_head, short use_lock, db_t * db, unsigned int * fastrandstate) { assert(sockfd != NULL); #if (VERBOSITY > 0) log_debug("BACKEND: register_remote_subscribe_queue %" PRId64 "/%" PRId64 "/%" PRId64 " for group_id %" PRId64 ", queue_id %" PRId64 "/%" PRId64 "", (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, (int64_t) group_id, (int64_t) table_key, (int64_t) queue_id); #endif if((int) group_id == -1) { return _subscribe_queue(consumer_id, shard_id, app_id, table_key, queue_id, group_id, NULL, sockfd, prev_read_head, prev_consume_head, use_lock, db, fastrandstate); } else { return _subscribe_group(consumer_id, shard_id, app_id, group_id, NULL, sockfd, use_lock, db, fastrandstate); } } int _unsubscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, WORD group_id, short use_lock, db_t * db) { db_table_t * table = get_table_by_key(table_key, db); if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); if(use_lock) pthread_mutex_lock(db_row->subscribe_lock); snode_t * consumer_node = skiplist_delete(db_row->consumer_state, consumer_id); if(use_lock) pthread_mutex_unlock(db_row->subscribe_lock); if(node == NULL) return DB_ERR_NO_CONSUMER; // Consumer didn't exist #if (VERBOSITY > 0) log_debug("BACKEND: Subscriber %" PRId64 "/%" PRId64 "/%" PRId64 "/%" PRId64 " unsubscribed queue %" PRId64 "/%" PRId64 "", (int64_t) app_id, (int64_t) shard_id, (int64_t) consumer_id, (int64_t) group_id, (int64_t) table_key, (int64_t) queue_id); #endif return 0; } int unsubscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, WORD group_id, short use_lock, db_t * db) { return _unsubscribe_queue(consumer_id, shard_id, app_id, table_key, queue_id, group_id, use_lock, db); } int register_remote_unsubscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, WORD group_id, short use_lock, db_t * db) { if((int) group_id == -1) { return _unsubscribe_queue(consumer_id, shard_id, app_id, table_key, queue_id, group_id, use_lock, db); } else { return _unsubscribe_group(consumer_id, group_id, db); } } void _create_headers_for_group_subscribers(group_state * gs, db_row_t * row, db_t * db, unsigned int * fastrandstate) { int64_t prev_read_head, prev_consume_head; if(gs == NULL) return; for(snode_t * crt_consumer = HEAD(gs->consumers); crt_consumer!=NULL; crt_consumer = NEXT(crt_consumer)) { consumer_state * cs = (consumer_state *) crt_consumer->value; __subscribe_queue(cs->consumer_id, cs->shard_id, cs->app_id, row, gs->group_id, NULL, NULL, &prev_read_head, &prev_consume_head, 1, db, fastrandstate); } } void create_headers_for_group_subscribers(db_row_t * db_row, db_t * db, unsigned int * fastrandstate) { if(db_row->group_subscriptions == NULL) return; if(db->queue_group_replication_factor == 1) { group_state * gs = (group_state *) db_row->group_subscriptions; _create_headers_for_group_subscribers(gs, db_row, db, fastrandstate); log_debug("SERVER: Updated queue group bucket for queue %d, group_pointer=%p, group_id = %d, status = %d, consumers = %d", (int) db_row->key, gs, ((gs != NULL)?((int) gs->group_id):(-1)), ((gs != NULL)?((int) gs->status):(-1)), ((gs != NULL)?((int) gs->consumers->no_items):(-1))); } else { skiplist_t * groups = (skiplist_t *) db_row->group_subscriptions; for(snode_t * crt_group = HEAD(groups); crt_group!=NULL; crt_group = NEXT(crt_group)) { group_state * gs = (group_state *) crt_group->value; _create_headers_for_group_subscribers(gs, db_row, db, fastrandstate); log_debug("SERVER: Updated queue group bucket for queue %d, group_pointer=%p, group_id = %d, status = %d, consumers = %d", (int) db_row->key, gs, ((gs != NULL)?((int) gs->group_id):(-1)), ((gs != NULL)?((int) gs->status):(-1)), ((gs != NULL)?((int) gs->consumers->no_items):(-1))); } } } int create_queue(WORD table_key, WORD queue_id, vector_clock * version, short use_lock, db_t * db, unsigned int * fastrandstate) { db_table_t * table = get_table_by_key(table_key, db); if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist if(use_lock) pthread_mutex_lock(table->lock); snode_t * node = skiplist_search(table->rows, queue_id); if(node != NULL) { if(use_lock) pthread_mutex_unlock(table->lock); return DB_ERR_DUPLICATE_QUEUE; // Queue already exists! } db_schema_t* schema = table->schema; // Create sentinel queue entry: WORD * queue_column_values = (WORD *) malloc(3 * sizeof(WORD)); // schema->no_cols queue_column_values[0]=queue_id; queue_column_values[1]=(WORD) - 2; queue_column_values[2]=0; int status = table_insert(queue_column_values, 3, 1, 0, NULL, table, fastrandstate); // version? // schema->no_cols if(status) { if(use_lock) pthread_mutex_unlock(table->lock); return status; } // Get queue row: snode_t * qr_node = skiplist_search(table->rows, queue_id); if(qr_node == NULL) { if(use_lock) pthread_mutex_unlock(table->lock); return DB_ERR_NO_QUEUE; // Queue creation error } db_row_t * db_row = (db_row_t *) (qr_node->value); db_row->consumer_state = create_skiplist_long(); if(!db_row->consumer_state) { if(use_lock) pthread_mutex_unlock(table->lock); return DB_ERR_NO_QUEUE; // Queue creation error } db_row->enqueue_lock = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); pthread_mutex_init(db_row->enqueue_lock, NULL); db_row->read_lock = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); pthread_mutex_init(db_row->read_lock, NULL); db_row->subscribe_lock = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); pthread_mutex_init(db_row->subscribe_lock, NULL); db_row->group_subscriptions = get_buckets_for_object(db->queue_groups, (int) db_row->key, db->queue_group_replication_factor, &get_group_state_key, &get_group_state_live_field, fastrandstate); if(db_row->group_subscriptions != NULL) create_headers_for_group_subscribers(db_row, db, fastrandstate); if(version != NULL) update_or_replace_vc(&(db_row->version), version); skiplist_insert(table->queues, queue_id, (WORD) db_row, fastrandstate); if(use_lock) pthread_mutex_unlock(table->lock); #if (VERBOSITY > 0) log_debug("BACKEND: Queue %" PRId64 "/%" PRId64 " created", (int64_t) table_key, (int64_t) queue_id); #endif return 0; } int delete_queue(WORD table_key, WORD queue_id, vector_clock * version, short use_lock, db_t * db, unsigned int * fastrandstate) { db_table_t * table = get_table_by_key(table_key, db); int ret = 0; if(table == NULL) return DB_ERR_NO_TABLE; // Table doesn't exist snode_t * node = skiplist_search(table->rows, queue_id); if(node == NULL) return DB_ERR_NO_QUEUE; // Queue doesn't exist db_row_t * db_row = (db_row_t *) (node->value); if(use_lock) pthread_mutex_lock(table->lock); // Remove pointer to queue DB row from queue cache table: skiplist_delete(table->queues, queue_id); // Notify consumers of queue deletion: for(snode_t * cell=HEAD(db_row->consumer_state);cell!=NULL;cell=NEXT(cell)) { if(cell->value != NULL) { consumer_state * cs = (consumer_state *) (cell->value); if(cs->callback == NULL || cs->notified > 0) continue; queue_callback_args * qca = get_queue_callback_args(table_key, queue_id, cs->app_id, cs->shard_id, cs->consumer_id, cs->group_id, QUEUE_NOTIF_DELETED); #if (VERBOSITY > 0) log_debug("BACKEND: Attempting to notify subscriber %" PRId64 " (%p/%p/%p/%p)", (int64_t) qca->consumer_id, cs->callback, cs->callback->lock, cs->callback->signal, cs->callback->callback); #endif ret = pthread_mutex_lock(cs->callback->lock); #if (VERBOSITY > 0) log_debug("BACKEND: Locked consumer lock of %" PRId64 " (%p/%p), status=%d", (int64_t) qca->consumer_id, cs->callback, cs->callback->lock, ret); #endif pthread_cond_signal(cs->callback->signal); cs->callback->callback(qca); ret = pthread_mutex_unlock(cs->callback->lock); #if (VERBOSITY > 0) log_debug("BACKEND: Unlocked consumer lock of %" PRId64 " (%p/%p), status=%d", (int64_t) qca->consumer_id, cs->callback, cs->callback->lock, ret); #endif // cs->notified=1; #if (VERBOSITY > 0) log_debug("BACKEND: Notified subscriber %" PRId64 " (%p/%p/%p/%p)", (int64_t) qca->consumer_id, cs->callback, cs->callback->lock, cs->callback->signal, cs->callback->callback); #endif } } skiplist_free_val(db_row->consumer_state, free_consumer_state_sl); ret = table_delete_row((WORD*) &(queue_id), version, table, db, fastrandstate); if(use_lock) pthread_mutex_unlock(table->lock); #if (VERBOSITY > 0) log_debug("BACKEND: Queue %" PRId64 "/%" PRId64 " deleted", (int64_t) table_key, (int64_t) queue_id); #endif return ret; } consumer_state * get_consumer_state(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, queue_callback* callback, int * sockfd, int is_group_subscription) { consumer_state * cs = (consumer_state *) malloc(sizeof(consumer_state)); cs->consumer_id = consumer_id; cs->shard_id = shard_id; cs->app_id = app_id; cs->group_id = group_id; cs->private_read_head = -1; cs->private_consume_head = -1; cs->callback = callback; cs->sockfd = sockfd; cs->notified=0; cs->prh_version=NULL; cs->pch_version=NULL; return cs; } void free_consumer_state(consumer_state * cs) { if(cs->prh_version != NULL) free_vc(cs->prh_version); if(cs->pch_version != NULL) free_vc(cs->pch_version); if(cs->callback != NULL) free_queue_callback(cs->callback); free(cs); } void free_consumer_state_sl(void * cs) { free_consumer_state((consumer_state *) cs); } int add_consumer_state_to_group(WORD queue_id, consumer_state * cs, group_state *gs, unsigned int * fastrandstate) { snode_t * consumer_node = skiplist_search(gs->consumers, queue_id); if(consumer_node != NULL) { return 1; } return skiplist_insert(gs->consumers, queue_id, cs, fastrandstate); } int get_consumer_state_from_group(WORD queue_id, group_state * gs, consumer_state ** cs) { snode_t * consumer_node = skiplist_search(gs->consumers, queue_id); if(consumer_node != NULL) { *cs = (consumer_state *) (consumer_node->value); return 0; } return 1; } int pop_consumer_state_from_group(WORD queue_id, group_state * gs, consumer_state ** cs) { *cs = (consumer_state *) skiplist_delete(gs->consumers, queue_id); if(*cs != NULL) { return 0; } return 1; } void free_queue_table_state(WORD queue_table_state) { skiplist_free(queue_table_state); } ================================================ FILE: backend/queue.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * queue.h * * Author: aagapi */ #ifndef BACKEND_QUEUE_H_ #define BACKEND_QUEUE_H_ #include "db.h" #include "queue_callback.h" #include "consumer_state.h" #include "queue_groups.h" #define DB_ERR_NO_TABLE -1 #define DB_ERR_NO_QUEUE -2 #define DB_ERR_NO_CONSUMER -3 #define DB_ERR_QUEUE_COMPLETE -4 #define DB_ERR_QUEUE_HEAD_INVALID -5 #define DB_ERR_DUPLICATE_QUEUE -6 #define DB_ERR_DUPLICATE_CONSUMER -7 #define DB_ERR_NO_GROUP -8 #define QUEUE_STATUS_READ_INCOMPLETE 0 #define QUEUE_STATUS_READ_COMPLETE 1 #define QUEUE_NOTIF_ENQUEUED 0 #define QUEUE_NOTIF_DELETED 1 #define GROUP_NOTIF_ENQUEUED 2 #define READ_HEAD(cs) (cs->private_read_head) #define CONSUME_HEAD(cs) (cs->private_consume_head) #define READ_HEAD_VERSION(cs) (cs->prh_version) #define CONSUME_HEAD_VERSION(cs) (cs->pch_version) int enqueue(WORD * column_values, int no_cols, size_t last_blob_size, WORD table_key, WORD queue_id, short use_lock, db_t * db, unsigned int * fastrandstate); int read_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int max_entries, int * entries_read, int64_t * new_read_head, vector_clock ** prh_version, snode_t** start_row, snode_t** end_row, short use_lock, db_t * db); int peek_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int max_entries, int64_t offset, int * entries_read, int64_t * new_read_head, vector_clock ** prh_version, snode_t** start_row, snode_t** end_row, db_t * db); int replay_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t replay_offset, int max_entries, int * entries_read, int64_t * new_replay_offset, snode_t** start_row, snode_t** end_row, db_t * db); int consume_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, db_t * db); int subscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, short use_lock, db_t * db, unsigned int * fastrandstate); int __subscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, db_row_t * db_row, WORD group_id, queue_callback * callback, int * sockfd, int64_t * prev_read_head, int64_t * prev_consume_head, short use_lock, db_t * db, unsigned int * fastrandstate); int register_remote_subscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, WORD group_id, int * sockfd, int64_t * prev_read_head, int64_t * prev_consume_head, short use_lock, db_t * db, unsigned int * fastrandstate); int register_remote_unsubscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, WORD group_id, short use_lock, db_t * db); int unsubscribe_queue(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, WORD group_id, short use_lock, db_t * db); void create_headers_for_group_subscribers(db_row_t * db_row, db_t * db, unsigned int * fastrandstate); int create_queue(WORD table_key, WORD queue_id, vector_clock * version, short use_lock, db_t * db, unsigned int * fastrandstate); int delete_queue(WORD table_key, WORD queue_id, vector_clock * version, short use_lock, db_t * db, unsigned int * fastrandstate); int create_queue_table(WORD table_id, int no_cols, int * col_types, db_t * db, unsigned int * fastrandstate); int set_private_read_head(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_read_head, vector_clock * version, short use_lock, db_t * db); int set_private_consume_head(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, vector_clock * version, db_t * db); consumer_state * get_consumer_state(WORD consumer_id, WORD shard_id, WORD app_id, WORD group_id, queue_callback* callback, int * sockfd, int is_group_subscription); void free_consumer_state(consumer_state * cs); void free_consumer_state_sl(void * cs); int add_consumer_state_to_group(WORD queue_id, consumer_state * cs, group_state *gs, unsigned int * fastrandstate); int get_consumer_state_from_group(WORD queue_id, group_state * gs, consumer_state ** cs); int pop_consumer_state_from_group(WORD queue_id, group_state * gs, consumer_state ** cs); void free_queue_table_state(WORD queue_table_state); #endif /* BACKEND_QUEUE_H_ */ ================================================ FILE: backend/queue_callback.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * queue_callback.c * Author: aagapi */ #include "queue_callback.h" queue_callback_args * get_queue_callback_args(WORD table_key, WORD queue_id, WORD app_id, WORD shard_id, WORD consumer_id, WORD group_id, int status) { queue_callback_args * qca = (queue_callback_args *) malloc(sizeof(queue_callback_args)); qca->table_key = table_key; qca->queue_id = queue_id; qca->app_id = app_id; qca->shard_id = shard_id; qca->consumer_id = consumer_id; qca->group_id = group_id; qca->status = status; return qca; } void free_queue_callback_args(queue_callback_args * qca) { free(qca); } queue_callback * get_queue_callback(void (*callback)(queue_callback_args *)) { queue_callback * qc = (queue_callback *) malloc(sizeof(queue_callback) + sizeof(pthread_mutex_t) + sizeof(pthread_cond_t)); qc->lock = (pthread_mutex_t *) ((char *)qc + sizeof(queue_callback)); qc->signal = (pthread_cond_t *) ((char *)qc + sizeof(queue_callback) + sizeof(pthread_mutex_t)); pthread_mutex_init(qc->lock, NULL); pthread_cond_init(qc->signal, NULL); qc->callback = callback; return qc; } int wait_on_queue_callback(queue_callback * qc) { int ret = pthread_mutex_lock(qc->lock); #if DEBUG_QUEUE_CALLBACK > 0 printf("Locked consumer lock %p/%p\n", qc, qc->lock); #endif struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 3; ret = pthread_cond_timedwait(qc->signal, qc->lock, &ts); pthread_mutex_unlock(qc->lock); #if DEBUG_QUEUE_CALLBACK > 0 printf("Unlocked consumer lock %p/%p\n", qc, qc->lock); #endif return ret; } void free_queue_callback(queue_callback * qc) { free(qc); } ================================================ FILE: backend/queue_callback.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * queue_callback.h * Author: aagapi */ #ifndef BACKEND_QUEUE_CALLBACK_H_ #define BACKEND_QUEUE_CALLBACK_H_ #include "common.h" typedef struct queue_callback_args { WORD table_key; WORD queue_id; WORD consumer_id; WORD shard_id; WORD app_id; WORD group_id; int status; } queue_callback_args; typedef struct queue_callback { void (*callback)(queue_callback_args *); pthread_mutex_t * lock; pthread_cond_t * signal; } queue_callback; #define DEBUG_QUEUE_CALLBACK 0 queue_callback_args * get_queue_callback_args(WORD table_key, WORD queue_id, WORD app_id, WORD shard_id, WORD consumer_id, WORD group_id, int status); void free_queue_callback_args(queue_callback_args * qca); queue_callback * get_queue_callback(void (*callback)(queue_callback_args *)); int wait_on_queue_callback(queue_callback *); void free_queue_callback(queue_callback * qc); #endif /* BACKEND_QUEUE_CALLBACK_H_ */ ================================================ FILE: backend/queue_groups.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * queue_groups.c * Author: aagapi */ #include "queue_groups.h" // Queue group management fctns: group_state * get_group(WORD group_id) { group_state * group = (group_state *) malloc(sizeof(group_state) + sizeof(pthread_mutex_t)); group->group_id = group_id; group->consumers = create_skiplist_long(); group->queue_tables = create_skiplist_long(); group->status = GROUP_STATUS_ACTIVE; group->group_lock = (pthread_mutex_t*) ((char*) group + sizeof(group_state)); pthread_mutex_init(group->group_lock, NULL); return group; } void free_group_state(WORD gs) { delete_group((group_state *) gs); } WORD get_group_state_key(WORD rs) { return ((group_state *) rs)->group_id; } WORD get_group_state_live_field(WORD rs) { return (WORD) (&(((group_state *) rs)->status)); } int clear_group(group_state * group) { skiplist_free_val(group->consumers, free_group_state); group->consumers = create_skiplist_long(); skiplist_free_val(group->queue_tables, free_queue_table_state); group->queue_tables = create_skiplist_long(); return 0; } int delete_group(group_state * group) { skiplist_free_val(group->consumers, free_group_state); skiplist_free_val(group->queue_tables, free_queue_table_state); free(group); return 0; } void activate_group(group_state * group) { group->status = GROUP_STATUS_ACTIVE; } void deactivate_group(group_state * group) { group->status = GROUP_STATUS_INACTIVE; } int add_queue_to_group(group_state * group, WORD table_key, WORD queue_id, unsigned int * fastrandstate) { skiplist_t * queue_list = NULL; pthread_mutex_lock(group->group_lock); snode_t * table_list = skiplist_search(group->queue_tables, table_key); if(table_list != NULL) { skiplist_t * queue_list = (skiplist_t *) (table_list->value); } else { queue_list = create_skiplist_long(); skiplist_insert(group->queue_tables, table_key, queue_list, fastrandstate); } skiplist_insert(queue_list, queue_id, queue_id, fastrandstate); pthread_mutex_unlock(group->group_lock); return 0; } int remove_queue_from_group(group_state * group, WORD table_key, WORD queue_id) { pthread_mutex_lock(group->group_lock); snode_t * table_list = skiplist_search(group->queue_tables, table_key); if(table_list == NULL) { pthread_mutex_unlock(group->group_lock); return DB_ERR_NO_TABLE; } skiplist_t * queue_list = (skiplist_t *) (table_list->value); if(queue_list != NULL) { snode_t * queue_entry = skiplist_delete(queue_list, queue_id); pthread_mutex_unlock(group->group_lock); if(queue_entry == NULL) return DB_ERR_NO_QUEUE; } else { pthread_mutex_unlock(group->group_lock); return DB_ERR_NO_QUEUE; } return 0; } int is_queue_in_group(group_state * group, WORD table_key, WORD queue_id) { pthread_mutex_lock(group->group_lock); snode_t * table_list = skiplist_search(group->queue_tables, table_key); if(table_list == NULL) { pthread_mutex_unlock(group->group_lock); return 0; } skiplist_t * queue_list = (skiplist_t *) (table_list->value); if(queue_list != NULL) { snode_t * queue_entry = skiplist_search(queue_list, queue_id); pthread_mutex_unlock(group->group_lock); if(queue_entry == NULL) return 0; } else { pthread_mutex_unlock(group->group_lock); } return 1; } int add_listener_to_group(group_state * group, WORD consumer_id, WORD shard_id, WORD app_id, queue_callback * callback, int * sockfd, unsigned int * fastrandstate) { consumer_state * cs = get_consumer_state(consumer_id, shard_id, app_id, group->group_id, callback, sockfd, 1); pthread_mutex_lock(group->group_lock); snode_t * consumer_node = skiplist_search(group->consumers, consumer_id); int ret = 0; if(consumer_node != NULL) { ret = DB_ERR_DUPLICATE_CONSUMER; // We allow the consumer to update his previously existing callback and meta-data, but advise him that he has done so } skiplist_insert(group->consumers, consumer_id, cs, fastrandstate); pthread_mutex_unlock(group->group_lock); return ret; } int remove_listener_from_group(group_state * group, WORD consumer_id) { pthread_mutex_lock(group->group_lock); snode_t * consumer_node = skiplist_delete(group->consumers, consumer_id); pthread_mutex_unlock(group->group_lock); if(consumer_node == NULL) return DB_ERR_NO_CONSUMER; // Consumer didn't exist return 0; } int lookup_listener_in_group(group_state * group, WORD consumer_id, WORD queue_id, consumer_state ** cs) { pthread_mutex_lock(group->group_lock); snode_t * consumer_node = skiplist_search(group->consumers, consumer_id); pthread_mutex_unlock(group->group_lock); if(consumer_node == NULL) { *cs = NULL; return DB_ERR_NO_CONSUMER; // Consumer didn't exist } *cs = (consumer_state *) consumer_node->value; return 0; } ================================================ FILE: backend/queue_groups.h ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * queue_groups.h * Author: aagapi */ #ifndef BACKEND_QUEUE_GROUPS_H_ #define BACKEND_QUEUE_GROUPS_H_ #include "common.h" #include "queue_callback.h" #include "queue.h" #include "skiplist.h" #define GROUP_STATUS_ACTIVE 0 #define GROUP_STATUS_INACTIVE 1 typedef struct group_state { WORD group_id; skiplist_t * queue_tables; skiplist_t * consumers; pthread_mutex_t* group_lock; int status; } group_state; typedef struct consumer_state consumer_state; // Queue group management fctns: group_state * get_group(WORD group_id); int delete_group(group_state * group); int clear_group(group_state * group); void activate_group(group_state * group); void deactivate_group(group_state * group); int add_queue_to_group(group_state * group, WORD table_key, WORD queue_id, unsigned int * fastrandstate); int remove_queue_from_group(group_state * group, WORD table_key, WORD queue_id); int add_listener_to_group(group_state * group, WORD consumer_id, WORD shard_id, WORD app_id, queue_callback * callback, int * sockfd, unsigned int * fastrandstate); int lookup_listener_in_group(group_state * group, WORD consumer_id, WORD queue_id, consumer_state ** cs); int remove_listener_from_group(group_state * group, WORD consumer_id); int is_queue_in_group(group_state * group, WORD table_key, WORD queue_id); void free_group_state(WORD gs); WORD get_group_state_key(WORD rs); WORD get_group_state_live_field(WORD rs); #endif /* BACKEND_QUEUE_GROUPS_H_ */ ================================================ FILE: backend/skiplist.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * skiplist.c * */ #include #include #include #include #include #include #include "skiplist.h" #include "log.h" #include "fastrand.h" int long_cmp(WORD e1, WORD e2) { return (int) ((int64_t) e1 - (int64_t) e2); } int uuid_cmp(WORD e1, WORD e2) { return uuid_compare(e1, e2); } skiplist_t *create_skiplist_long() { return create_skiplist(NULL); } skiplist_t *create_skiplist_uuid() { return create_skiplist(&uuid_cmp); } skiplist_t *create_skiplist(int (*cmp)(WORD, WORD)) { skiplist_t * list = (skiplist_t *) malloc(sizeof(skiplist_t)); return skiplist_init(list, cmp); } skiplist_t *skiplist_init(skiplist_t *list, int (*cmp)(WORD, WORD)) { snode_t *header = (snode_t *) malloc(sizeof(struct snode)); list->header = header; header->key = (WORD) LONG_MAX; header->forward = (snode_t **) malloc(sizeof(snode_t*) * (SKIPLIST_MAX_LEVEL)); for (int i = 0; i < SKIPLIST_MAX_LEVEL; i++) { header->forward[i] = NULL; // list->header; } list->level = 0; list->no_items=0; list->cmp = (cmp != NULL)?(cmp):(&long_cmp); return list; } static int rand_level(unsigned int * seedptr) { unsigned int randno; FASTRAND(seedptr, randno); return randno % SKIPLIST_MAX_LEVEL; } int skiplist_insert(skiplist_t *list, WORD key, WORD value, unsigned int * seedptr) { snode_t *update[SKIPLIST_MAX_LEVEL]; snode_t *x = list->header; int i = list->level, level; for (; i >= 0; i--) { while (x->forward[i] != NULL && (list->cmp(x->forward[i]->key, key) < 0)) x = x->forward[i]; // log_debug("Item %" PRId64 " will update node %" PRId64 " at level %d", key, x->key, i); update[i] = x; } if (x->forward[0] != NULL && list->cmp(key, x->forward[0]->key) == 0) { x->forward[0]->value = value; return 0; } else { level = rand_level(seedptr); // log_debug("Item %" PRId64 ", picking level %d", key, level); if (level > list->level) { for (i = list->level + 1; i <= level; i++) { update[i] = list->header; } list->level = level; } x = (snode_t *) malloc(sizeof(snode_t)); x->key = key; x->value = value; x->forward = (snode_t **) malloc(sizeof(snode_t*) * (level+1)); for (i = 0; i <= level; i++) { // log_debug("Item %" PRId64 " chaining myself after node %" PRId64 " at level %d", key, update[i]->key, i); x->forward[i] = update[i]->forward[i]; update[i]->forward[i] = x; } list->no_items++; } return 0; } skiplist_t * skiplist_clone(skiplist_t * list, unsigned int * seedptr) { skiplist_t * dst_list = create_skiplist(list->cmp); for(snode_t * crt = HEAD(list); crt!=NULL; crt = NEXT(crt)) { skiplist_insert(dst_list, crt->key, crt->value, seedptr); } return dst_list; } snode_t *skiplist_search(skiplist_t *list, WORD key) { snode_t *x = list->header; for (int i = list->level; i >= 0; i--) { while (x->forward[i] != NULL && (list->cmp(x->forward[i]->key, key) <= 0) ) x = x->forward[i]; } if (x != NULL && ((int64_t) x->key) != LONG_MAX && list->cmp(key, x->key) == 0) { return x; } else { return NULL; } return NULL; } snode_t *skiplist_search_higher(skiplist_t *list, WORD key) { snode_t *x = list->header; for (int i = list->level; i >= 0; i--) { while (x->forward[i] != NULL && (list->cmp(x->forward[i]->key, key) < 0)) x = x->forward[i]; } if(x != NULL) return x->forward[0]; else assert(0); return NULL; } int skiplist_get_range(skiplist_t *list, WORD start_key, WORD end_key, WORD** result, int *no_nodes) { snode_t * start_node = NULL; int i=0; start_node = skiplist_search_higher(list, start_key); if(start_node != NULL) { *result = NULL; *no_nodes = 0; return -1; } *no_nodes=1; for(snode_t * x = start_node;list->cmp(x->forward[0]->key, end_key) < 0;x = x->forward[0]) (*no_nodes)++; *result = (WORD*) malloc(*no_nodes*sizeof(WORD)); for(snode_t * x = start_node;list->cmp(x->forward[0]->key, end_key) < 0;x = x->forward[0]) (*result)[i++] = x->value; return 0; } snode_t *skiplist_search_lower(skiplist_t *list, WORD key) { snode_t *x = list->header; for (int i = list->level; i >= 0; i--) { while (x->forward[i] != NULL && (list->cmp(x->forward[i]->key, key) <= 0)) x = x->forward[i]; } return x; } static void skiplist_node_free(snode_t *x) { if (x) { free(x->forward); free(x); } } WORD skiplist_delete(skiplist_t *list, WORD key) { WORD value = NULL; snode_t *update[SKIPLIST_MAX_LEVEL]; snode_t *x = list->header; for (int i = list->level; i >= 0; i--) { while (x->forward[i] != NULL && (list->cmp(x->forward[i]->key, key) < 0)) x = x->forward[i]; update[i] = x; } if(x->forward[0] != NULL) x = x->forward[0]; if (list->cmp(x->key, key) == 0) { for (int i = 0; i <= list->level; i++) { if (update[i]->forward[i] != x) break; update[i]->forward[i] = x->forward[i]; } value = x->value; skiplist_node_free(x); while (list->level > 0 && list->header->forward[list->level] == NULL) list->level--; list->no_items--; } return value; } void skiplist_free(skiplist_t *list) { snode_t *current_node = list->header->forward[0]; while(current_node != NULL) { snode_t *next_node = current_node->forward[0]; free(current_node->forward); free(current_node); current_node = next_node; } free(list->header->forward); free(list->header); free(list); } void skiplist_free_val(skiplist_t *list, void (*free_val)(WORD)) { snode_t *current_node = list->header->forward[0]; while(current_node != NULL) { snode_t *next_node = current_node->forward[0]; free(current_node->forward); free_val(current_node->value); free(current_node); current_node = next_node; } free(list->header->forward); free(list->header); free(list); } void skiplist_dump(skiplist_t *list) { snode_t *x = list->header; while (x && x->forward[0] != NULL) { log_trace("%" PRId64 "[%" PRId64 "]->", (int64_t) x->forward[0]->key, (int64_t) x->forward[0]->value); x = x->forward[0]; } log_trace("NIL"); } ================================================ FILE: backend/skiplist.h ================================================ /* * skiplist.h * */ #ifndef BACKEND_SKIPLIST_H_ #define BACKEND_SKIPLIST_H_ typedef void *WORD; #define SKIPLIST_MAX_LEVEL 6 #define HEAD(skiplist) ((skiplist)->header->forward[0]) #define NEXT(snode) ((snode)->forward[0]) typedef struct snode { WORD key; WORD value; struct snode **forward; } snode_t; typedef struct skiplist { int level; struct snode *header; int no_items; int (*cmp)(WORD, WORD); } skiplist_t; skiplist_t * create_skiplist_long(); skiplist_t *create_skiplist_uuid(); skiplist_t * create_skiplist(int (*cmp)(WORD, WORD)); skiplist_t * skiplist_init(skiplist_t *list, int (*cmp)(WORD, WORD)); skiplist_t * skiplist_clone(skiplist_t * list, unsigned int * seedptr); int skiplist_insert(skiplist_t *list, WORD key, WORD value, unsigned int * seedptr); snode_t * skiplist_search(skiplist_t *list, WORD key); snode_t *skiplist_search_higher(skiplist_t *list, WORD key); snode_t *skiplist_search_lower(skiplist_t *list, WORD key); int skiplist_get_range(skiplist_t *list, WORD start_key, WORD end_key, WORD** result, int *no_nodes); static void skiplist_node_free(snode_t *x); WORD skiplist_delete(skiplist_t *list, WORD key); void skiplist_free(skiplist_t *list); void skiplist_free_val(skiplist_t *list, void (*free_val)(WORD)); void skiplist_dump(skiplist_t *list); #endif /* BACKEND_SKIPLIST_H_ */ ================================================ FILE: backend/test/actor_ring_tests_local.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "txns.h" #define COLLECTION_ID_0 0 #define COLLECTION_ID_1 1 #define COLLECTION_ID_2 2 // local counter variable as int #define COLLECTION_ID_3 3 // local counter variable as char blob int no_actors = 2; int no_items = 10; int min_no_state_cols = 3; int no_state_primary_keys = 1; int min_state_clustering_keys = 1; int no_state_index_keys = 1; int no_queue_cols = 3; WORD state_table_key = (WORD) 0; WORD queue_table_key = (WORD) 1; int rand_sleep = 1; int debug = 1; int debug_lock = 0; typedef struct actor_collection_item { int actor_id; int collection_id; int item_id; int item_value; } actor_collection_item_t; typedef struct actor_queue_item { int sender_id; int item_value; } actor_queue_item_t; typedef struct actor_args { db_t * db; WORD state_table_key; WORD queue_table_key; WORD queue_id; int no_enqueues; WORD consumer_id; WORD shard_id; WORD app_id; skiplist_t * rcv_counters; skiplist_t * snd_counters; int64_t total_rcv; int64_t total_snd; int successful_enqueues; int successful_dequeues; int successful_consumes; int successful_replays; int64_t read_head; int64_t read_head_after_replay; queue_callback * qc; vector_clock * vc; int status; } actor_args; // Create schema: int create_state_schema(db_t * db, unsigned int * fastrandstate) { int primary_key_idx = 0; int clustering_key_idxs[2]; clustering_key_idxs[0]=1; clustering_key_idxs[1]=2; int index_key_idx=3; // Col types are not enforced: int * col_types = NULL; /* int * col_types = (int *) malloc(no_state_cols * sizeof(int)); for(int i=0;iapp_id, (int64_t) qca->shard_id, (int64_t) qca->consumer_id, (int64_t) qca->table_key, (int64_t) qca->queue_id, qca->status); } int read_queue_while_not_empty(actor_args * ca, int * entries_read, snode_t ** start_row, snode_t ** end_row) { int read_status = QUEUE_STATUS_READ_INCOMPLETE; vector_clock * prh_version; while(read_status != QUEUE_STATUS_READ_COMPLETE) { read_status = read_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->queue_table_key, ca->queue_id, 2, entries_read, &ca->read_head, &prh_version, start_row, end_row, 1, ca->db); increment_vc(ca->vc, (int) ca->consumer_id); if(read_status < 0) { printf("ERROR: read_queue returned %d\n", read_status); return read_status; } else { assert(read_status == QUEUE_STATUS_READ_COMPLETE || read_status == QUEUE_STATUS_READ_INCOMPLETE); ca->successful_dequeues += (*entries_read); if((*entries_read) > 0) { printf("CONSUMER %" PRId64 ": successful_dequeues=%d, last_entry_id=%" PRId64 "\n", (int64_t) ca->consumer_id, ca->successful_dequeues, (int64_t) (*end_row)->key); if(((int64_t) (*end_row)->key) != ca->successful_dequeues - 1) printf("Test %s - FAILED (%" PRId64 " != %d)\n", "last_entry_id", (int64_t) (*end_row)->key, ca->successful_dequeues - 1); } } } return read_status; } char digits[10][10] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; int checkpoint_local_state(actor_args * ca, uuid_t * txnid, unsigned int * fastrandstate) { int ret = 0; WORD * column_values = (WORD *) malloc(5 * sizeof(WORD)); column_values[0] = ca->consumer_id; for(snode_t * node = HEAD(ca->rcv_counters);node != NULL;node = NEXT(node)) { column_values[1] = (WORD) COLLECTION_ID_0; column_values[2] = node->key; column_values[3] = node->value; char * str_value = ((int) node->value <= 9)?(digits[(int) node->value]):"NaN"; column_values[4] = str_value; // For backend local API, when there is a blob, place blob pointer as the last col value, and set the corresponding blob_size in the insert call below ret = db_insert_in_txn(column_values, 5, no_state_primary_keys, 2, strnlen((const char *) str_value, 10) + 1, // blob size ca->state_table_key, txnid, ca->db, fastrandstate); assert(ret == 0); } for(snode_t * node = HEAD(ca->snd_counters);node != NULL;node = NEXT(node)) { column_values[1] = (WORD) COLLECTION_ID_1; column_values[2] = node->key; column_values[3] = node->value; char * str_value = ((int) node->value <= 9)?(digits[(int) node->value]):"NaN"; column_values[4] = str_value; // For backend local API, when there is a blob, place blob pointer as the last col value, and set the corresponding blob_size in the insert call below ret = db_insert_in_txn(column_values, 5, no_state_primary_keys, 2, strnlen((const char *) str_value, 10) + 1, // blob size ca->state_table_key, txnid, ca->db, fastrandstate); assert(ret == 0); } // Checkpoint the standalone counter variable, once in an int column, once in a char blob column: column_values[1] = (WORD) COLLECTION_ID_2; column_values[2] = (WORD) ca->total_rcv; // Note that there is no blob here (blob_size == 0 below) ret = db_insert_in_txn(column_values, 3, no_state_primary_keys, 1, 0, // blob size ca->state_table_key, txnid, ca->db, fastrandstate); char * str_value = ((int) ca->total_rcv <= 9)?(digits[(int) ca->total_rcv]):"NaN"; column_values[1] = (WORD) COLLECTION_ID_3; column_values[2] = (WORD) str_value; // For backend local API, when there is a blob, place blob pointer as the last col value, and set the corresponding blob_size in the insert call below ret = db_insert_in_txn(column_values, 3, no_state_primary_keys, 1, strnlen((const char *) str_value, 10) + 1, // blob size ca->state_table_key, txnid, ca->db, fastrandstate); free(column_values); return 0; } int send_seed_msgs(actor_args * ca, int * msgs_sent, unsigned int * fastrandstate) { int ret = 0; int64_t dest_id = ((int64_t) ca->consumer_id < no_actors - 1)? ((int64_t) ca->consumer_id + 1) : 0; int no_outgoing_counters = 2; assert(no_queue_cols == 3); *msgs_sent=0; WORD * column_values = (WORD *) malloc(no_queue_cols * sizeof(WORD)); for(int i=0;iconsumer_id; column_values[1] = (WORD) i; char * str_value = (i <= 9)?(digits[i]):"NaN"; column_values[2] = (WORD) str_value; ret = enqueue(column_values, no_queue_cols, strnlen((const char *) str_value, 10) + 1, ca->queue_table_key, (WORD) dest_id, 1, ca->db, fastrandstate); assert(ret == 0); (*msgs_sent)++; skiplist_insert(ca->snd_counters, (WORD) dest_id, (WORD) i, fastrandstate); ca->total_snd++; } free(column_values); return 0; } int send_outgoing_msgs(actor_args * ca, int outgoing_counters[], int no_outgoing_counters, int * msgs_sent, uuid_t * txnid, unsigned int * fastrandstate) { int ret = 0; int64_t dest_id = ((int64_t) ca->consumer_id < no_actors - 1)? ((int64_t) ca->consumer_id + 1) : 0; /* if(debug) printf("ACTOR %" PRId64 ": Sending %d msgs to ACTOR %" PRId64 ".\n", (int64_t) ca->consumer_id, no_outgoing_counters, dest_id); */ assert(no_queue_cols == 3); *msgs_sent=0; WORD * column_values = (WORD *) malloc(no_queue_cols * sizeof(WORD)); for(int i=0;iconsumer_id; column_values[1] = (WORD) outgoing_counters[i]; char * str_value = (outgoing_counters[i] <= 9)?(digits[outgoing_counters[i]]):"NaN"; column_values[2] = (WORD) str_value; ret = enqueue_in_txn(column_values, no_queue_cols, strnlen((const char *) str_value, 10) + 1, ca->queue_table_key, (WORD) dest_id, txnid, ca->db, fastrandstate); assert(ret == 0); (*msgs_sent)++; } free(column_values); return 0; } int process_messages(snode_t * start_row, snode_t * end_row, int entries_read, int outgoing_counters[], int * no_outgoing_counters, actor_args * ca, unsigned int * fastrandstate) { int ret = 0; int processed = 0; snode_t * crt_row = NULL; if(entries_read == 0 || start_row == NULL) { printf("ACTOR %" PRId64 ": No msgs to process!\n", (int64_t) ca->consumer_id); return 0; } if(debug) printf("ACTOR %" PRId64 ": %d msgs to process.\n", (int64_t) ca->consumer_id, entries_read); for(crt_row = start_row; processedvalue; // print_long_row(db_row); int64_t queue_entry_id = (int64_t) db_row->key; assert(db_row->no_columns == 3); int64_t sender_id = (int64_t) db_row->column_array[0]; int counter_val = (int) db_row->column_array[1]; char * str_value = (char *) db_row->column_array[2]; printf("ACTOR %" PRId64 ": Read queue entry: (id=%" PRId64 ", snd=%" PRId64 ", val=%d, str=%s)\n", (int64_t) ca->consumer_id, queue_entry_id, sender_id, counter_val, str_value); // skiplist_search(ca->rcv_counters, COLLECTION_ID_0, (WORD) entries_read); skiplist_insert(ca->rcv_counters, (WORD) sender_id, (WORD) counter_val, fastrandstate); ca->total_rcv++; counter_val++; outgoing_counters[*no_outgoing_counters] = counter_val; *no_outgoing_counters = (*no_outgoing_counters) + 1; int64_t dest_id = ((int64_t) ca->consumer_id < no_actors - 1)? ((int64_t) ca->consumer_id + 1) : 0; skiplist_insert(ca->snd_counters, (WORD) dest_id, (WORD) counter_val, fastrandstate); ca->total_snd++; assert(processed < entries_read-1 || crt_row == end_row); } assert(processed == entries_read); return processed; } int produce_effects(uuid_t * txnid, actor_args * ca, int * msgs_sent, int outgoing_counters[], int no_outgoing_counters, unsigned int * fastrandstate) { // Checkpoint local state in txn: int ret = checkpoint_local_state(ca, txnid, fastrandstate); assert(ret == 0); if(debug) printf("ACTOR %" PRId64 ": Chekpointed local state in txn.\n", (int64_t) ca->consumer_id); // Send outgoing msgs in txn: ret = send_outgoing_msgs(ca, outgoing_counters, no_outgoing_counters, msgs_sent, txnid, fastrandstate); assert(ret == 0); if(debug) printf("ACTOR %" PRId64 ": Sent %d outgoing msgs in txn.\n", (int64_t) ca->consumer_id, *msgs_sent); return 0; } void * actor(void * cargs) { unsigned int seed, randno; int ret = 0; snode_t * start_row, * end_row; int msgs_sent = 0; int outgoing_counters[100]; int no_outgoing_counters = 0; actor_args * ca = (actor_args *) cargs; queue_callback * qc = ca->qc; GET_RANDSEED(&seed, 0); // thread_id increment_vc(ca->vc, (int) ca->consumer_id); int64_t prev_read_head = -1, prev_consume_head = -1; ret = subscribe_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->queue_table_key, ca->queue_id, qc, &prev_read_head, &prev_consume_head, 1, ca->db, &seed); printf("Test %s - %s (%d)\n", "subscribe_queue", ret==0?"OK":"FAILED", ret); if(ret) return NULL; if(debug) printf("ACTOR %" PRId64 ": Subscribed to queue %" PRId64 "/%" PRId64 " with callback (%p/%p/%p/%p)\n", (int64_t) ca->consumer_id, (int64_t) ca->queue_table_key, (int64_t) ca->queue_id, qc, qc->lock, qc->signal, qc->callback); increment_vc(ca->vc, (int) ca->consumer_id); ca->rcv_counters = create_skiplist_long(); ca->snd_counters = create_skiplist_long(); int entries_read = (int) prev_read_head + 1; if((int64_t) ca->consumer_id == 0) { send_seed_msgs(ca, &msgs_sent, &seed); ca->successful_enqueues += msgs_sent; if(debug) printf("ACTOR %" PRId64 ": sent %d seed outgoing msgs.\n", (int64_t) ca->consumer_id, msgs_sent); } int read_status = read_queue_while_not_empty(ca, &entries_read, &start_row, &end_row); if(read_status < 0) { return (void *) read_status; } // Add app-specific message processing work here: no_outgoing_counters = 0; ret = process_messages(start_row, end_row, entries_read, outgoing_counters, &no_outgoing_counters, ca, &seed); if(entries_read > 0) { int checkpoint_success = 0; while(!checkpoint_success) { uuid_t * txnid = new_txn(ca->db, &seed); ret = produce_effects(txnid, ca, &msgs_sent, outgoing_counters, no_outgoing_counters, &seed); assert(ret == 0); // Consume input queue in same txn: ret = consume_queue_in_txn(ca->consumer_id, ca->shard_id, ca->app_id, ca->queue_table_key, ca->queue_id, (int64_t) ca->read_head, txnid, ca->db, &seed); if(ret < 0 && ret != DB_ERR_QUEUE_COMPLETE) printf("ERROR: consume_queue returned %d\n", ret); if(debug) printf("ACTOR %" PRId64 ": consumed input queue up to %" PRId64 " in txn.\n", (int64_t) ca->consumer_id, (int64_t) ca->read_head); ret = commit_txn(txnid, ca->vc, ca->db, &seed); if(debug) printf("ACTOR %" PRId64 ": Commit returned %d.\n", (int64_t) ca->consumer_id, ret); checkpoint_success = (ret == VAL_STATUS_COMMIT); } increment_vc(ca->vc, (int) ca->consumer_id); ca->successful_consumes = ca->successful_dequeues; ca->successful_enqueues += msgs_sent; printf("ACTOR %" PRId64 ": successful_dequeues=%d, successful_consumes=%d, no_enqueues=%d\n", (int64_t) ca->consumer_id, ca->successful_dequeues, ca->successful_consumes, ca->no_enqueues); } while(ca->successful_consumes < ca->no_enqueues) { if(debug) printf("ACTOR %" PRId64 ": Blocking for input (successful_consumes=%d, no_enqueues=%d)\n", (int64_t) ca->consumer_id, ca->successful_consumes, ca->no_enqueues); ret = wait_on_queue_callback(qc); if(ret == 0) { if(debug) printf("ACTOR %" PRId64 ": Was signaled, status=%d, reading queue..\n", (int64_t) ca->consumer_id, ret); } else { if(debug) printf("ACTOR %" PRId64 ": Wait timed out, status=%d, reading queue..\n", (int64_t) ca->consumer_id, ret); } // Received queue notification, reading: read_status = read_queue_while_not_empty(ca, &entries_read, &start_row, &end_row); if(read_status < 0) { return (void *) read_status; } // Add app-specific message processing work here: no_outgoing_counters = 0; ret = process_messages(start_row, end_row, entries_read, outgoing_counters, &no_outgoing_counters, ca, &seed); if(entries_read > 0) { int checkpoint_success = 0; while(!checkpoint_success) { uuid_t * txnid = new_txn(ca->db, &seed); ret = produce_effects(txnid, ca, &msgs_sent, outgoing_counters, no_outgoing_counters, &seed); // Consume input queue in same txn: ret = consume_queue_in_txn(ca->consumer_id, ca->shard_id, ca->app_id, ca->queue_table_key, ca->queue_id, (int64_t) ca->read_head, txnid, ca->db, &seed); if(ret < 0 && ret != DB_ERR_QUEUE_COMPLETE) printf("ERROR: consume_queue returned %d\n", ret); if(debug) printf("ACTOR %" PRId64 ": consumed input queue up to %" PRId64 " in txn.\n", (int64_t) ca->consumer_id, (int64_t) ca->read_head); ret = commit_txn(txnid, ca->vc, ca->db, &seed); if(debug) printf("ACTOR %" PRId64 ": Commit returned %d.\n", (int64_t) ca->consumer_id, ret); checkpoint_success = (ret == VAL_STATUS_COMMIT); } increment_vc(ca->vc, (int) ca->consumer_id); ca->successful_consumes = ca->successful_dequeues; ca->successful_enqueues += msgs_sent; printf("ACTOR %" PRId64 ": successful_dequeues=%d, successful_consumes=%d, successful_enqueues=%d, private_read_head=%" PRId64 ", no_enqueues=%d\n", (int64_t) ca->consumer_id, ca->successful_dequeues, ca->successful_consumes, ca->successful_enqueues, ca->read_head, ca->no_enqueues); // print_long_db(ca->db); } if(rand_sleep) { FASTRAND(&seed, randno); sleep((randno % 10) * 0.2); } } ret = unsubscribe_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->queue_table_key, ca->queue_id, 1, ca->db); printf("Test %s - %s (%d)\n", "unsubscribe_queue", ret==0?"OK":"FAILED", ret); free_queue_callback(qc); return (void *) ret; } int main(int argc, char **argv) { unsigned int seed; int ret = 0; if (argc != 3) { fprintf(stderr,"usage: %s \n", argv[0]); exit(0); } no_actors = atoi(argv[1]); no_items = atoi(argv[2]); GET_RANDSEED(&seed, 0); // thread_id // Get db pointer: db_t * db = get_db(); // Create state table: ret = create_state_schema(db, &seed); // Create queue table: ret = create_queue_schema(db, &seed); // Create and run producer and consumer threads (also test subscribe / unsubscribe): pthread_t actor_ts[50]; actor_args cargs[50]; int node_ids[50]; memset(&node_ids, 0, 50*sizeof(int)); int64_t counters[50]; memset(&counters, 0, 50*sizeof(int64_t)); for(int i=0;i=num_enqueues && cargs[i].successful_enqueues<=num_enqueues+1)?"OK":"FAILED", ret); // Test dequeues: printf("Test %s (%d) - %s (%d)\n", "dequeue", i, cargs[i].successful_dequeues==cargs[i].successful_enqueues-((i==0)?2:0)?"OK":"FAILED", ret); // Test read head sanity: printf("Test %s (%d) - %s (%d)\n", "read_head", i, ((int) cargs[i].read_head)==(cargs[i].successful_dequeues - 1)?"OK":"FAILED", ret); // Test consumes: printf("Test %s (%d) - %s (%d)\n", "consume", i, cargs[i].successful_consumes==cargs[i].successful_dequeues?"OK":"FAILED", ret); } print_long_db(db); return 0; } ================================================ FILE: backend/test/actor_ring_tests_remote.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include // #include "txns.h" #include #include #include #include #include #include "client_api.h" #include "fastrand.h" #define COLLECTION_ID_0 0 // rcv_counters map #define COLLECTION_ID_1 1 // snd_counters map #define COLLECTION_ID_2 2 // local counter variable as int #define COLLECTION_ID_3 3 // local counter variable as char blob int no_actors = 2; int no_items = 20; int min_no_state_cols = 3; int no_state_primary_keys = 1; int min_state_clustering_keys = 1; int no_state_index_keys = 1; int no_queue_cols = 2; WORD state_table_key = (WORD) 0; WORD queue_table_key = (WORD) 1; int rand_sleep = 1; int debug = 1; int debug_lock = 0; typedef struct actor_collection_item { int actor_id; int collection_id; int item_id; int item_value; } actor_collection_item_t; typedef struct actor_queue_item { int sender_id; int item_value; } actor_queue_item_t; typedef struct actor_args { remote_db_t * db; WORD state_table_key; WORD queue_table_key; WORD queue_id; int no_enqueues; WORD consumer_id; WORD shard_id; WORD app_id; skiplist_t * rcv_counters; skiplist_t * snd_counters; int64_t total_rcv; int64_t total_snd; int successful_enqueues; int successful_dequeues; int successful_consumes; int successful_replays; int64_t read_head; int64_t read_head_after_replay; queue_callback * qc; db_schema_t * schema; int status; } actor_args; // Create schema: db_schema_t* create_state_schema() { int primary_key_idx = 0; int clustering_key_idxs[2]; clustering_key_idxs[0]=1; clustering_key_idxs[1]=2; int index_key_idx=3; int * col_types = NULL; // Col types are not enforced: /* col_types = (int *) malloc((no_state_cols+1) * sizeof(int)); for(int i=0;iapp_id, (int64_t) qca->shard_id, (int64_t) qca->consumer_id, (int64_t) qca->table_key, (int64_t) qca->queue_id, qca->status); } int read_queue_while_not_empty(actor_args * ca, int * entries_read, snode_t ** start_row, snode_t ** end_row) { int read_status = QUEUE_STATUS_READ_INCOMPLETE, minority_status = 0; while(read_status != QUEUE_STATUS_READ_COMPLETE) { read_status = remote_read_queue_in_txn(ca->consumer_id, ca->shard_id, ca->app_id, ca->queue_table_key, ca->queue_id, 2, entries_read, &ca->read_head, start_row, end_row, &minority_status, NULL, ca->db); if(read_status < 0) { printf("ERROR: read_queue returned %d\n", read_status); return read_status; } else { assert(read_status == QUEUE_STATUS_READ_COMPLETE || read_status == QUEUE_STATUS_READ_INCOMPLETE); ca->successful_dequeues += (*entries_read); if((*entries_read) > 0) { printf("CONSUMER %" PRId64 ": successful_dequeues=%d, last_entry_id=%" PRId64 "\n", (int64_t) ca->consumer_id, ca->successful_dequeues, (int64_t) (*end_row)->key); if(((int64_t) (*end_row)->key) != ca->successful_dequeues - 1) printf("Test %s - FAILED (%" PRId64 " != %d)\n", "last_entry_id", (int64_t) (*end_row)->key, ca->successful_dequeues - 1); } } } return read_status; } char digits[10][10] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; int checkpoint_local_state(actor_args * ca, uuid_t * txnid, unsigned int * fastrandstate) { int ret = 0, minority_status = 0; WORD * column_values = (WORD *) malloc(4 * sizeof(WORD)); column_values[0] = ca->consumer_id; // Checkpoint the 2 maps: for(snode_t * node = HEAD(ca->rcv_counters); node != NULL;node = NEXT(node)) { column_values[1] = (WORD) COLLECTION_ID_0; column_values[2] = node->key; column_values[3] = node->value; char * str_value = ((int) node->value <= 9)?(digits[(int) node->value]):"NaN"; ret = remote_insert_in_txn(column_values, 4, no_state_primary_keys, 2, (WORD) str_value, strnlen((const char *) str_value, 10) + 1, ca->state_table_key, &minority_status, txnid, ca->db); assert(ret == 0); } for(snode_t * node = HEAD(ca->snd_counters);node != NULL;node = NEXT(node)) { column_values[1] = (WORD) COLLECTION_ID_1; column_values[2] = node->key; column_values[3] = node->value; char * str_value = ((int) node->value <= 9)?(digits[(int) node->value]):"NaN"; ret = remote_insert_in_txn(column_values, 4, no_state_primary_keys, 2, (WORD) str_value, strnlen((const char *) str_value, 10) + 1, ca->state_table_key, &minority_status, txnid, ca->db); assert(ret == 0); } // Checkpoint the standalone counter variable, once in an int column, once in a char blob column: column_values[1] = (WORD) COLLECTION_ID_2; column_values[2] = (WORD) ca->total_rcv; ret = remote_insert_in_txn(column_values, 3, no_state_primary_keys, 1, NULL, 0, ca->state_table_key, &minority_status, txnid, ca->db); char * str_value = ((int) ca->total_rcv <= 9)?(digits[(int) ca->total_rcv]):"NaN"; column_values[1] = (WORD) COLLECTION_ID_3; ret = remote_insert_in_txn(column_values, 2, no_state_primary_keys, 1, (WORD) str_value, strnlen((const char *) str_value, 10) + 1, ca->state_table_key, &minority_status, txnid, ca->db); free(column_values); return 0; } int send_seed_msgs(actor_args * ca, int * msgs_sent, unsigned int * fastrandstate) { int ret = 0; int64_t dest_id = ((int64_t) ca->consumer_id < no_actors - 1)? ((int64_t) ca->consumer_id + 1) : 0; int no_outgoing_counters = 2; *msgs_sent=0; assert(no_queue_cols == 2); WORD * column_values = (WORD *) malloc(no_queue_cols * sizeof(WORD)); int minority_status = 0; for(int i=0;iconsumer_id; column_values[1] = (WORD) i; char * str_value = (i <= 9)?(digits[i]):"NaN"; ret = remote_enqueue_in_txn(column_values, no_queue_cols, (WORD) str_value, strnlen((const char *) str_value, 10) + 1, ca->queue_table_key, (WORD) dest_id, &minority_status, NULL, ca->db); assert(ret == 0); (*msgs_sent)++; skiplist_insert(ca->snd_counters, (WORD) dest_id, (WORD) i, fastrandstate); ca->total_snd++; } free(column_values); return 0; } int send_outgoing_msgs(actor_args * ca, int outgoing_counters[], int no_outgoing_counters, int * msgs_sent, uuid_t * txnid, unsigned int * fastrandstate) { int ret = 0; int64_t dest_id = ((int64_t) ca->consumer_id < no_actors - 1)? ((int64_t) ca->consumer_id + 1) : 0; /* if(debug) printf("ACTOR %" PRId64 ": Sending %d msgs to ACTOR %" PRId64 ".\n", (int64_t) ca->consumer_id, no_outgoing_counters, dest_id); */ assert(no_queue_cols == 2); *msgs_sent=0; WORD * column_values = (WORD *) malloc(no_queue_cols * sizeof(WORD)); int minority_status = 0; for(int i=0;iconsumer_id; column_values[1] = (WORD) outgoing_counters[i]; char * str_value = (outgoing_counters[i] <= 9)?(digits[outgoing_counters[i]]):"NaN"; ret = remote_enqueue_in_txn(column_values, no_queue_cols, (WORD) str_value, strnlen((const char *) str_value, 10) + 1, ca->queue_table_key, (WORD) dest_id, &minority_status, txnid, ca->db); assert(ret == 0); (*msgs_sent)++; } free(column_values); return 0; } int process_messages(snode_t * start_row, snode_t * end_row, int entries_read, int outgoing_counters[], int * no_outgoing_counters, actor_args * ca, unsigned int * fastrandstate) { int ret = 0; int processed = 0; snode_t * crt_row = NULL; if(entries_read == 0 || start_row == NULL) { printf("ACTOR %" PRId64 ": No msgs to process!\n", (int64_t) ca->consumer_id); return 0; } if(debug) printf("ACTOR %" PRId64 ": %d msgs to process.\n", (int64_t) ca->consumer_id, entries_read); for(crt_row = start_row; processedvalue; // print_long_row(db_row); int64_t queue_entry_id = (int64_t) db_row->key; assert(db_row->no_columns == 3); int64_t sender_id = (int64_t) db_row->column_array[0]; int counter_val = (int) db_row->column_array[1]; char * str_value = (char *) db_row->column_array[2]; printf("ACTOR %" PRId64 ": Read queue entry: (id=%" PRId64 ", snd=%" PRId64 ", val=%d, str=%s)\n", (int64_t) ca->consumer_id, queue_entry_id, sender_id, counter_val, str_value); // skiplist_search(ca->rcv_counters, COLLECTION_ID_0, (WORD) entries_read); skiplist_insert(ca->rcv_counters, (WORD) sender_id, (WORD) counter_val, fastrandstate); ca->total_rcv++; counter_val++; outgoing_counters[*no_outgoing_counters] = counter_val; *no_outgoing_counters = (*no_outgoing_counters) + 1; int64_t dest_id = ((int64_t) ca->consumer_id < no_actors - 1)? ((int64_t) ca->consumer_id + 1) : 0; skiplist_insert(ca->snd_counters, (WORD) dest_id, (WORD) counter_val, fastrandstate); ca->total_snd++; assert(processed < entries_read-1 || crt_row == end_row); } assert(processed == entries_read); return processed; } int produce_effects(uuid_t * txnid, actor_args * ca, int * msgs_sent, int outgoing_counters[], int no_outgoing_counters, unsigned int * fastrandstate) { // Checkpoint local state in txn: int ret = checkpoint_local_state(ca, txnid, fastrandstate); assert(ret == 0); if(debug) printf("ACTOR %" PRId64 ": Chekpointed local state in txn.\n", (int64_t) ca->consumer_id); // Send outgoing msgs in txn: ret = send_outgoing_msgs(ca, outgoing_counters, no_outgoing_counters, msgs_sent, txnid, fastrandstate); assert(ret == 0); if(debug) printf("ACTOR %" PRId64 ": Sent %d outgoing msgs in txn.\n", (int64_t) ca->consumer_id, *msgs_sent); return 0; } void * actor(void * cargs) { unsigned int seed, randno; int ret = 0, minority_status = 0; snode_t * start_row, * end_row; int msgs_sent = 0; int outgoing_counters[100]; int no_outgoing_counters = 0; actor_args * ca = (actor_args *) cargs; queue_callback * qc = ca->qc; GET_RANDSEED(&seed, 0); // thread_id int64_t prev_read_head = -1, prev_consume_head = -1; int minority_status = 0; ret = remote_subscribe_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->queue_table_key, ca->queue_id, qc, &prev_read_head, &prev_consume_head, &minority_status, ca->db); printf("Test %s - %s (%d)\n", "subscribe_queue", ret==0?"OK":"FAILED", ret); if(ret) return NULL; if(debug) printf("ACTOR %" PRId64 ": Subscribed to queue %" PRId64 "/%" PRId64 " with callback (%p/%p/%p/%p)\n", (int64_t) ca->consumer_id, (int64_t) ca->queue_table_key, (int64_t) ca->queue_id, qc, qc->lock, qc->signal, qc->callback); ca->rcv_counters = create_skiplist_long(); ca->snd_counters = create_skiplist_long(); int entries_read = (int) prev_read_head + 1; if((int64_t) ca->consumer_id == 0) { ret = send_seed_msgs(ca, &msgs_sent, &seed); ca->successful_enqueues += msgs_sent; if(debug) printf("ACTOR %" PRId64 ": sent %d seed outgoing msgs (status = %d).\n", (int64_t) ca->consumer_id, msgs_sent, ret); // remote_print_long_table(state_table_key, ca->db); // remote_print_long_table(queue_table_key, ca->db); } int read_status = read_queue_while_not_empty(ca, &entries_read, &start_row, &end_row); if(read_status < 0) { return (void *) read_status; } // Add app-specific message processing work here: no_outgoing_counters = 0; ret = process_messages(start_row, end_row, entries_read, outgoing_counters, &no_outgoing_counters, ca, &seed); int minority_status = 0; if(entries_read > 0) { int checkpoint_success = 0; while(!checkpoint_success) { uuid_t * txnid = remote_new_txn(ca->db); ret = produce_effects(txnid, ca, &msgs_sent, outgoing_counters, no_outgoing_counters, &seed); assert(ret == 0); // Consume input queue in same txn: ret = remote_consume_queue_in_txn(ca->consumer_id, ca->shard_id, ca->app_id, ca->queue_table_key, ca->queue_id, (int64_t) ca->read_head, &minority_status, txnid, ca->db); if(ret < 0 && ret != DB_ERR_QUEUE_COMPLETE) printf("ERROR: consume_queue returned %d\n", ret); if(debug) printf("ACTOR %" PRId64 ": consumed input queue up to %" PRId64 " in txn.\n", (int64_t) ca->consumer_id, (int64_t) ca->read_head); ret = remote_commit_txn(txnid, &minority_status, ca->db); if(debug) printf("ACTOR %" PRId64 ": Commit returned %d.\n", (int64_t) ca->consumer_id, ret); checkpoint_success = (ret == VAL_STATUS_COMMIT); } // remote_print_long_table(state_table_key, ca->db); // remote_print_long_table(queue_table_key, ca->db); ca->successful_consumes = ca->successful_dequeues; ca->successful_enqueues += msgs_sent; printf("ACTOR %" PRId64 ": successful_dequeues=%d, successful_consumes=%d, no_enqueues=%d\n", (int64_t) ca->consumer_id, ca->successful_dequeues, ca->successful_consumes, ca->no_enqueues); } while(ca->successful_consumes < ca->no_enqueues) { if(debug) printf("ACTOR %" PRId64 ": Blocking for input (successful_consumes=%d, no_enqueues=%d)\n", (int64_t) ca->consumer_id, ca->successful_consumes, ca->no_enqueues); ret = wait_on_queue_callback(qc); if(ret == 0) { if(debug) printf("ACTOR %" PRId64 ": Was signaled, status=%d, reading queue..\n", (int64_t) ca->consumer_id, ret); } else { if(debug) printf("ACTOR %" PRId64 ": Wait timed out, status=%d, reading queue..\n", (int64_t) ca->consumer_id, ret); } // Received queue notification, reading: read_status = read_queue_while_not_empty(ca, &entries_read, &start_row, &end_row); if(read_status < 0) { return (void *) read_status; } no_outgoing_counters = 0; ret = process_messages(start_row, end_row, entries_read, outgoing_counters, &no_outgoing_counters, ca, &seed); if(entries_read > 0) { int checkpoint_success = 0; while(!checkpoint_success) { uuid_t * txnid = remote_new_txn(ca->db); ret = produce_effects(txnid, ca, &msgs_sent, outgoing_counters, no_outgoing_counters, &seed); // Consume input queue in same txn: ret = remote_consume_queue_in_txn(ca->consumer_id, ca->shard_id, ca->app_id, ca->queue_table_key, ca->queue_id, (int64_t) ca->read_head, &minority_status, txnid, ca->db); if(ret < 0 && ret != DB_ERR_QUEUE_COMPLETE) printf("ERROR: consume_queue returned %d\n", ret); if(debug) printf("ACTOR %" PRId64 ": consumed input queue up to %" PRId64 " in txn.\n", (int64_t) ca->consumer_id, (int64_t) ca->read_head); ret = remote_commit_txn(txnid, ca->db); if(debug) printf("ACTOR %" PRId64 ": Commit returned %d.\n", (int64_t) ca->consumer_id, ret); checkpoint_success = (ret == VAL_STATUS_COMMIT); } // remote_print_long_table(state_table_key, ca->db); // remote_print_long_table(queue_table_key, ca->db); ca->successful_consumes = ca->successful_dequeues; ca->successful_enqueues += msgs_sent; printf("ACTOR %" PRId64 ": successful_dequeues=%d, successful_consumes=%d, successful_enqueues=%d, private_read_head=%" PRId64 ", no_enqueues=%d\n", (int64_t) ca->consumer_id, ca->successful_dequeues, ca->successful_consumes, ca->successful_enqueues, ca->read_head, ca->no_enqueues); // print_long_db(ca->db); } if(rand_sleep) { FASTRAND(&seed, randno); sleep((randno % 10) * 0.2); } } ret = remote_unsubscribe_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->queue_table_key, ca->queue_id, &minority_status, ca->db); printf("Test %s - %s (%d)\n", "unsubscribe_queue", ret==0?"OK":"FAILED", ret); // free_queue_callback(qc); return (void *) ret; } int main(int argc, char **argv) { char *hostname; int portno; unsigned int seed; int ret = 0; GET_RANDSEED(&seed, 0); // thread_id // Get db pointer: /* check command line arguments */ if (argc != 5) { fprintf(stderr,"usage: %s \n", argv[0]); exit(0); } hostname = argv[1]; portno = atoi(argv[2]); no_actors = atoi(argv[3]); no_items = atoi(argv[4]); remote_db_t * db = get_remote_db(1); add_server_to_membership(hostname, portno, db, &seed); // add_server_to_membership(hostname, portno+1, db, &seed); // add_server_to_membership(hostname, portno+2, db, &seed); // Create state table: db_schema_t* schema = create_state_schema(); // Create queue table: ret = create_queue_schema(db, &seed); // Create and run producer and consumer threads (also test subscribe / unsubscribe): pthread_t actor_ts[50]; actor_args cargs[50]; int node_ids[50]; memset(&node_ids, 0, 50*sizeof(int)); int64_t counters[50]; memset(&counters, 0, 50*sizeof(int64_t)); for(int i=0;i=num_enqueues && cargs[i].successful_enqueues<=num_enqueues+1)?"OK":"FAILED", ret); // Test dequeues: printf("Test %s (%d) - %s (%d)\n", "dequeue", i, cargs[i].successful_dequeues==cargs[i].successful_enqueues-((i==0)?2:0)?"OK":"FAILED", ret); // Test read head sanity: printf("Test %s (%d) - %s (%d)\n", "read_head", i, ((int) cargs[i].read_head)==(cargs[i].successful_dequeues - 1)?"OK":"FAILED", ret); // Test consumes: printf("Test %s (%d) - %s (%d)\n", "consume", i, cargs[i].successful_consumes==cargs[i].successful_dequeues?"OK":"FAILED", ret); } remote_print_long_table(state_table_key, db); remote_print_long_table(queue_table_key, db); return 0; } ================================================ FILE: backend/test/db_unit_tests.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "db.h" typedef struct actor_collection_item { int actor_id; int collection_id; int item_id; int item_value; } actor_collection_item_t; int no_cols = 4; int no_primary_keys = 1; int no_clustering_keys = 2; int no_index_keys = 1; int no_actors = 2; int no_collections = 2; int no_items = 2; // Create schema: int create_schema(db_t * db, unsigned int * fastrandstate) { int primary_key_idx = 0; int clustering_key_idxs[2]; clustering_key_idxs[0]=1; clustering_key_idxs[1]=2; int index_key_idx=3; int * col_types = (int *) malloc(no_cols * sizeof(int)); for(int i=0;ikey != aid) { printf("Read back mismatched pk %" PRId64 " ( != %" PRId64 ")!\n", (int64_t) row->key, aid); return -1; } } return 0; } // Read by (PK, CK1): int test_search_pk_ck1(db_t * db) { for(int64_t aid=0;aidkey != cid) { printf("Read back mismatched ck1 %" PRId64 " ( != %" PRId64 ") in cell (%" PRId64 ", %" PRId64 ")!\n", (int64_t) row->key, cid, aid, cid); return -1; } } } return 0; } // Read by (PK, CK1, CK2): int test_search_pk_ck1_ck2(db_t * db) { for(int64_t aid=0;aidkey != iid) { printf("Read back mismatched ck2 %" PRId64 " ( != %" PRId64 ") in cell (%" PRId64 ", %" PRId64 ", %" PRId64 ")!\n", (int64_t) row->key, iid, aid, cid, iid); return -1; } } } } return 0; } // Read by secondary index: int test_search_index(db_t * db) { // TO DO: fix for(int64_t iid=0;iidkey); return -1; } } return 0; } // Delete by (PK, CK1): int test_delete_pk_ck1(db_t * db) { // TO DO: return 0; } // Delete by (PK, CK1, CK2): int test_delete_pk_ck1_ck2(db_t * db) { // TO DO: return 0; } // Delete by (PK, CK1, CK2, Column): int test_delete_col(db_t * db) { // TO DO: return 0; } // Delete by secondary index: int test_delete_index(db_t * db) { for(int64_t iid=0;iidkey); return -1; } } return 0; } // Range search by PK: int test_range_search_pk(db_t * db) { // TO DO: Improve (check returned keys): int64_t start_key = 0; int64_t end_key = no_actors - 1; snode_t* start_row = NULL, * end_row = NULL; return (db_range_search((WORD*) &start_key, (WORD*) &end_key, &start_row, &end_row, (WORD) 0, db) == no_actors); } int test_range_search_pk_copy(db_t * db) { // TO DO: Improve (check returned keys): int64_t start_key = 0; int64_t end_key = no_actors - 1; db_row_t* rows = NULL; return (db_range_search_copy((WORD*) &start_key, (WORD*) &end_key, &rows, (WORD) 0, db) == no_actors); } // Range search by (PK, CK1): int test_range_search_pk_ck1(db_t * db) { // TO DO: Improve (check returned keys): int64_t pk = 0; int64_t start_key = 0; int64_t end_key = no_collections - 1; snode_t* start_row = NULL, * end_row = NULL; int no_entries = db_range_search_clustering((WORD*) &pk,(WORD*) &start_key, (WORD*) &end_key, 1, &start_row, &end_row, (WORD) 0, db); if(no_entries != no_collections) { printf("ERROR: db_range_search_clustering(%" PRId64 ", %" PRId64 "-%" PRId64 ") returned %d entries!\n", pk, start_key, end_key, no_entries); print_long_db(db); assert(0); return 1; } return 0; } // Range search by (PK, CK1, CK2): int test_range_search_pk_ck1_ck2(db_t * db) { // TO DO: Improve (check returned keys): int64_t pk = 0; int64_t start_keys[2]; start_keys[0] = 0; start_keys[1] = 0; int64_t end_keys[2]; end_keys[0] = 0; end_keys[1] = no_items - 1; snode_t* start_row = NULL, * end_row = NULL; int no_entries = db_range_search_clustering((WORD*) &pk,(WORD*) start_keys, (WORD*) end_keys, 2, &start_row, &end_row, (WORD) 0, db); if(no_entries != no_items) { printf("ERROR: db_range_search_clustering(%" PRId64 ", %" PRId64 ", %" PRId64 "-%" PRId64 ") returned %d entries!\n", pk, start_keys[0], end_keys[0], end_keys[1], no_entries); print_long_db(db); assert(0); return 1; } return 0; } // Range search by secondary index: int test_range_search_index(db_t * db) { // TO DO: Improve (check returned keys): int64_t start_key = 1; int64_t end_key = no_items; snode_t* start_row = NULL, * end_row = NULL; return (db_range_search_index(0, (WORD) start_key, (WORD) end_key, &start_row, &end_row, (WORD) 0, db) == (no_items - 1)); } int main(int argc, char **argv) { unsigned int seed; int ret = 0; GET_RANDSEED(&seed, 0); // thread_id // Get db pointer: db_t * db = get_db(); // Create schema: ret = create_schema(db, &seed); printf("Test %s - %s\n", "create_schema", ret==0?"OK":"FAILED"); // Populate DB: ret = populate_db(db, &seed); printf("Test %s - %s\n", "populate_db", ret==0?"OK":"FAILED"); // Read by (PK): ret = test_search_pk(db); printf("Test %s - %s\n", "test_search_pk", ret==0?"OK":"FAILED"); // Read by (PK, CK1): ret = test_search_pk_ck1(db); printf("Test %s - %s\n", "test_search_pk_ck1", ret==0?"OK":"FAILED"); // Read by (PK, CK1, CK2): ret = test_search_pk_ck1_ck2(db); printf("Test %s - %s\n", "test_search_pk_ck1_ck2", ret==0?"OK":"FAILED"); // Read by (PK, CK1, CK2, Column): ret = test_search_column(db); printf("Test %s - %s\n", "test_search_column", ret==0?"OK":"FAILED"); // Read by secondary index: ret = test_search_index(db); printf("Test %s - %s\n", "test_search_index", ret==0?"OK":"FAILED"); // Update by (PK, CK1, CK2, Column): ret = test_update(db); printf("Test %s - %s\n", "test_update", ret==0?"OK":"FAILED"); // Delete by (PK, CK1, CK2, Column): ret = test_delete_col(db); printf("Test %s - %s\n", "test_delete_col", ret==0?"OK":"FAILED"); // Delete by (PK, CK1, CK2): ret = test_delete_pk_ck1_ck2(db); printf("Test %s - %s\n", "test_delete_pk_ck1_ck2", ret==0?"OK":"FAILED"); // Delete by (PK, CK1): ret = test_delete_pk_ck1(db); printf("Test %s - %s\n", "test_delete_pk_ck1", ret==0?"OK":"FAILED"); // Delete by (PK): ret = test_delete_pk(db, &seed); printf("Test %s - %s\n", "test_delete_pk", ret==0?"OK":"FAILED"); ret = populate_db(db, &seed); printf("Test %s - %s\n", "repopulate_db", ret==0?"OK":"FAILED"); // Delete by secondary index: // ret = test_delete_index(db); // printf("Test %s - %s\n", "", ret==0?"OK":"FAILED"); // ret = populate_db(db, &seed); // Range search by PK: ret = test_range_search_pk(db); printf("Test %s - %s\n", "test_delete_index", ret==0?"OK":"FAILED"); // Range search by PK (copy): ret = test_range_search_pk_copy(db); printf("Test %s - %s\n", "test_range_search_pk_copy", ret==0?"OK":"FAILED"); // Range search by (PK, CK1): ret = test_range_search_pk_ck1(db); printf("Test %s - %s\n", "test_range_search_pk_ck1", ret==0?"OK":"FAILED"); // Range search by (PK, CK1, CK2): ret = test_range_search_pk_ck1_ck2(db); printf("Test %s - %s\n", "test_range_search_pk_ck1_ck2", ret==0?"OK":"FAILED"); // Range search by secondary index: ret = test_range_search_index(db); printf("Test %s - %s\n", "test_range_search_index", ret==0?"OK":"FAILED"); return 0; } ================================================ FILE: backend/test/queue_unit_tests.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "queue.h" int no_cols = 2; int no_items = 10; WORD table_key = (WORD) 0; WORD queue_id = (WORD) 0; typedef struct actor_collection_item { int item_id; int item_value; } actor_collection_item_t; typedef struct producer_args { db_t * db; WORD table_key; WORD queue_id; int no_enqueues; int successful_enqueues; int status; } producer_args; typedef struct consumer_args { db_t * db; WORD table_key; WORD queue_id; int no_enqueues; WORD consumer_id; WORD shard_id; WORD app_id; int successful_dequeues; int successful_consumes; int successful_replays; int64_t read_head; int64_t read_head_after_replay; int status; } consumer_args; // Enqueue test: int do_enqueues(db_t * db, WORD table_id, WORD queue_id, int no_enqueues, int rand_sleep, int * successful_enqueues, unsigned int * fastrandstate) { unsigned int randno; for(int64_t iid=0;iiddb, pa->table_key, pa->queue_id, pa->no_enqueues, 1, &(pa->successful_enqueues), &seed); pa->status = ret; return (void *) pa->status; } void consumer_callback(queue_callback_args * qca) { printf("Consumer %" PRId64 "/%" PRId64 "/%" PRId64 " received notification for queue %" PRId64 "/%" PRId64 ", status %d\n", (int64_t) qca->app_id, (int64_t) qca->shard_id, (int64_t) qca->consumer_id, (int64_t) qca->table_key, (int64_t) qca->queue_id, qca->status); } int read_queue_while_not_empty(consumer_args * ca, int * entries_read) { snode_t * start_row, * end_row; int read_status = QUEUE_STATUS_READ_INCOMPLETE; vector_clock * prh_version; while(read_status != QUEUE_STATUS_READ_COMPLETE) { read_status = read_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->table_key, ca->queue_id, 2, entries_read, &ca->read_head, &prh_version, &start_row, &end_row, 1, ca->db); if(read_status < 0) { printf("ERROR: read_queue returned %d\n", read_status); return read_status; } else { assert(read_status == QUEUE_STATUS_READ_COMPLETE || read_status == QUEUE_STATUS_READ_INCOMPLETE); ca->successful_dequeues += (*entries_read); if((*entries_read) > 0) { printf("CONSUMER %" PRId64 ": successful_dequeues=%d, last_entry_id=%" PRId64 "\n", (int64_t) ca->consumer_id, ca->successful_dequeues, (int64_t) end_row->key); if(((int64_t) end_row->key) != ca->successful_dequeues - 1) printf("Test %s - FAILED (%" PRId64 " != %d)\n", "last_entry_id", (int64_t) end_row->key, ca->successful_dequeues - 1); } } } return read_status; } void * consumer(void * cargs) { unsigned int seed; int ret = 0; snode_t * start_row, * end_row; consumer_args * ca = (consumer_args *) cargs; pthread_cond_t signal = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; GET_RANDSEED(&seed, 0); // thread_id queue_callback qc; qc.lock = &lock; qc.signal = &signal; qc.callback = consumer_callback; int64_t prev_read_head = -1, prev_consume_head = -1; ret = subscribe_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->table_key, ca->queue_id, &qc, &prev_read_head, &prev_consume_head, 1, ca->db, &seed); printf("Test %s - %s (%d)\n", "subscribe_queue", ret==0?"OK":"FAILED", ret); if(ret) return NULL; int entries_read = (int) prev_read_head + 1; int read_status = read_queue_while_not_empty(ca, &entries_read); if(read_status < 0) { return (void *) read_status; } // Add app-specific message processing work here ret = consume_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->table_key, ca->queue_id, (int64_t) ca->read_head, ca->db); if(ret < 0 && ret != DB_ERR_QUEUE_COMPLETE) printf("ERROR: consume_queue returned %d\n", ret); else ca->successful_consumes = ca->successful_dequeues; printf("CONSUMER %" PRId64 ": successful_dequeues=%d, successful_consumes=%d\n", (int64_t) ca->consumer_id, ca->successful_dequeues, ca->successful_consumes); while(ca->successful_consumes < ca->no_enqueues) { pthread_mutex_lock(&lock); struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 3; pthread_cond_timedwait(&signal, &lock, &ts); // Received queue notification, reading: read_status = read_queue_while_not_empty(ca, &entries_read); if(read_status < 0) { return (void *) read_status; } // Add app-specific message processing work here ret = consume_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->table_key, ca->queue_id, (int64_t) ca->read_head, ca->db); if(ret < 0 && ret != DB_ERR_QUEUE_COMPLETE) printf("ERROR: consume_queue returned %d\n", ret); else ca->successful_consumes = ca->successful_dequeues; printf("CONSUMER %" PRId64 ": successful_dequeues=%d, successful_consumes=%d\n", (int64_t) ca->consumer_id, ca->successful_dequeues, ca->successful_consumes); pthread_mutex_unlock(&lock); } ret = unsubscribe_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->table_key, ca->queue_id, 1, ca->db); printf("Test %s - %s (%d)\n", "unsubscribe_queue", ret==0?"OK":"FAILED", ret); return (void *) ret; } void * consumer_replay(void * cargs) { unsigned int seed; int ret = 0; snode_t * start_row, * end_row; consumer_args * ca = (consumer_args *) cargs; pthread_cond_t signal = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; GET_RANDSEED(&seed, 0); // thread_id queue_callback qc; qc.lock = &lock; qc.signal = &signal; qc.callback = consumer_callback; int64_t prev_read_head = -1, prev_consume_head = -1; ret = subscribe_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->table_key, ca->queue_id, &qc, &prev_read_head, &prev_consume_head, 1, ca->db, &seed); int entries_read = (int) prev_read_head + 1; int read_status = read_queue_while_not_empty(ca, &entries_read); if(read_status < 0) { return (void *) read_status; } while(ca->successful_dequeues < ca->no_enqueues) { pthread_mutex_lock(&lock); struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 3; pthread_cond_timedwait(&signal, &lock, &ts); // Received queue notification, reading: read_status = read_queue_while_not_empty(ca, &entries_read); if(read_status < 0) { return (void *) read_status; } pthread_mutex_unlock(&lock); } ret = replay_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->table_key, ca->queue_id, 0, ca->successful_dequeues, &ca->successful_replays, &ca->read_head_after_replay, &start_row, &end_row, ca->db); assert(ret == QUEUE_STATUS_READ_COMPLETE); ret = unsubscribe_queue(ca->consumer_id, ca->shard_id, ca->app_id, ca->table_key, ca->queue_id, 1, ca->db); printf("Test %s - %s (%d)\n", "unsubscribe_queue", ret==0?"OK":"FAILED", ret); return (void *) ret; } int main(int argc, char **argv) { unsigned int seed; int ret = 0; GET_RANDSEED(&seed, 0); // thread_id // Get db pointer: db_t * db = get_db(); // Create queue table: int * col_types = (int *) malloc(no_cols * sizeof(int)); for(int i=0;i int main() { int arr[] = { 1, 3, 3, 6, 9, 9, 2, 11, 11, 1, 4, 4 }, i; skiplist_t * list; unsigned int randno; list = create_skiplist_long(); printf("Insert:--------------------\n"); for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { skiplist_insert(list, (WORD) arr[i], (WORD) arr[i], &randno); skiplist_dump(list); } // skiplist_dump(list); printf("Search:--------------------\n"); int keys[] = { 3, 4, 7, 10, 111 }; for (i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { snode_t *x = skiplist_search(list, (WORD) keys[i]); if (x) { printf("key = %d, value = %d\n", keys[i], (int) x->value); } else { printf("key = %d, not found\n", keys[i]); } } printf("Search:--------------------\n"); skiplist_delete(list, (WORD) 3); skiplist_dump(list); skiplist_delete(list, (WORD) 9); skiplist_dump(list); skiplist_delete(list, (WORD) 11); skiplist_dump(list); skiplist_delete(list, (WORD) 11); skiplist_dump(list); skiplist_delete(list, (WORD) 11); skiplist_dump(list); skiplist_delete(list, (WORD) 1); skiplist_dump(list); skiplist_delete(list, (WORD) 6); skiplist_dump(list); skiplist_delete(list, (WORD) 2); skiplist_dump(list); skiplist_delete(list, (WORD) 4); skiplist_dump(list); skiplist_free(list); return 0; } ================================================ FILE: backend/test/test_client.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * client.c * * Author: aagapi */ #include #include #include #include #include #include #include #include #include #include "client_api.h" #include "fastrand.h" typedef struct actor_collection_item { int actor_id; int collection_id; int item_id; int item_value; } actor_collection_item_t; int no_cols = 4; int no_primary_keys = 1; int no_clustering_keys = 2; int no_index_keys = 1; int no_queue_cols = 2; int no_enqueues = 5; int no_actors = 2; int no_collections = 2; int no_items = 2; int minority_status = 0; db_schema_t * create_schema() { int primary_key_idx = 0; int clustering_key_idxs[2]; clustering_key_idxs[0]=1; clustering_key_idxs[1]=2; int index_key_idx=3; int * col_types = (int *) malloc(no_cols * sizeof(int)); for(int i=0;ino_primary_keys, schema->min_no_clustering_keys, NULL, 0, (WORD) 0, &minority_status, txnid, db) != 0) return -1; } } } return 0; } int delete_test(db_schema_t * schema, remote_db_t * db, uuid_t * txnid, unsigned int * fastrandstate) // Deletes row for last actor { printf("TEST: delete_test\n"); WORD row_key = (WORD) no_actors - 1; return remote_delete_row_in_txn(&row_key, schema->no_primary_keys, (WORD) 0, &minority_status, txnid, db); } int delete_all(db_schema_t * schema, remote_db_t * db, uuid_t * txnid, unsigned int * fastrandstate) // Deletes row for last actor { printf("TEST: delete_test\n"); int ret = 0; for(int64_t aid = 0; aidno_primary_keys, (WORD) 0, &minority_status, txnid, db); return ret; } int test_search_pk(db_schema_t * schema, remote_db_t * db, uuid_t * txnid, unsigned int * fastrandstate) { printf("TEST: test_search_pk\n"); char print_buff[1024]; for(int64_t aid=0;aidno_primary_keys, &row, (WORD) 0, &minority_status, txnid, db); if(txnid != NULL && row == NULL) continue; print_long_row(row); if(row == NULL) { printf("Read back wrong NULL row for cell (%" PRId64 ")!\n", aid); return -1; } if((int64_t) row->key != aid) { printf("Read back mismatched pk %" PRId64 " ( != %" PRId64 ") in cell!\n", (int64_t) row->key, aid); return -1; } } return 0; } int test_search_pk_ck1(db_schema_t * schema, remote_db_t * db, uuid_t * txnid, unsigned int * fastrandstate) { printf("TEST: test_search_pk_ck1\n"); char print_buff[1024]; for(int64_t aid=0;aidno_primary_keys, (WORD *) &cid, 1, &row, (WORD) 0, &minority_status, txnid, db); if(txnid != NULL && row == NULL) continue; print_long_row(row); if(row == NULL) { printf("Read back wrong NULL row for cell (%" PRId64 ", %" PRId64 ")!\n", aid, cid); return -1; } if((int64_t) row->key != cid) { printf("Read back mismatched ck1 %" PRId64 " ( != %" PRId64 ") in cell (%" PRId64 ", %" PRId64 ")!\n", (int64_t) row->key, cid, aid, cid); return -1; } } } return 0; } int test_search_pk_ck1_ck2(db_schema_t * schema, remote_db_t * db, uuid_t * txnid, unsigned int * fastrandstate) { printf("TEST: test_search_pk_ck1_ck2\n"); char print_buff[1024]; WORD * cks = (WORD *) malloc(2 * sizeof(WORD)); for(int64_t aid=0;aidno_primary_keys, cks, 2, &row, (WORD) 0, &minority_status, txnid, db); if(txnid != NULL && row == NULL) continue; print_long_row(row); if((int64_t) row->key != iid) { printf("Read back mismatched ck1 %" PRId64 " ( != %" PRId64 ") in cell (%" PRId64 ", %" PRId64 ", %" PRId64 ")!\n", (int64_t) row->key, iid, aid, cid, iid); return -1; } } } } return 0; } // Queue tests: void consumer_callback(queue_callback_args * qca) { printf("Consumer %" PRId64 "/%" PRId64 "/%" PRId64 " received notification for queue %" PRId64 "/%" PRId64 ", status %d\n", (int64_t) qca->app_id, (int64_t) qca->shard_id, (int64_t) qca->consumer_id, (int64_t) qca->table_key, (int64_t) qca->queue_id, qca->status); } int test_create_queue(remote_db_t * db, uuid_t * txnid) // Creates 2 queues { printf("TEST: create_queue\n"); int ret = remote_create_queue_in_txn((WORD) 1, (WORD) 1, &minority_status, txnid, db); ret |= remote_create_queue_in_txn((WORD) 1, (WORD) 2, &minority_status, txnid, db); return ret; } int test_delete_queue(remote_db_t * db, uuid_t * txnid) { printf("TEST: delete_queue\n"); int ret = remote_delete_queue_in_txn((WORD) 1, (WORD) 1, &minority_status, txnid, db); ret |= remote_delete_queue_in_txn((WORD) 1, (WORD) 2, &minority_status, txnid, db); return ret; } int test_subscribe_queue(remote_db_t * db, WORD consumer_id, WORD queue_id) { printf("TEST: subscribe_queue\n"); int64_t prev_read_head = -1, prev_consume_head = -1; queue_callback * qc = get_queue_callback(consumer_callback); return remote_subscribe_queue(consumer_id, (WORD) 1, (WORD) 2, (WORD) 1, queue_id, qc, &prev_read_head, &prev_consume_head, &minority_status, db); // &txnid } int test_unsubscribe_queue(remote_db_t * db, WORD consumer_id, WORD queue_id) { printf("TEST: unsubscribe_queue\n"); return remote_unsubscribe_queue(consumer_id, (WORD) 1, (WORD) 2, (WORD) 1, queue_id, &minority_status, db); // &txnid } int test_enqueue(remote_db_t * db, WORD queue_id, uuid_t * txnid) { printf("TEST: enqueue\n"); WORD * column_values = (WORD *) malloc(no_queue_cols * sizeof(WORD)); for(int64_t i=0;ikey - start_row->key == (entries_read - 1)); return ret; } int test_consume_queue(remote_db_t * db, WORD consumer_id, WORD queue_id, uuid_t * txnid) { printf("TEST: consume_queue\n"); return remote_consume_queue_in_txn(consumer_id, (WORD) 1, (WORD) 2, (WORD) 1, queue_id, no_enqueues - 1, &minority_status, txnid, db); // &txnid } int test_txn(remote_db_t * db, db_schema_t * schema, unsigned * fastrandstate) { printf("TEST: txn\n"); int node_ids[] = {0,1}; int64_t counters[] = {0,0}; vector_clock * vc = init_vc(2, node_ids, counters, 0), * vc_r = NULL; add_component_vc(vc, 2, 0); increment_vc(vc, 0); increment_vc(vc, 0); increment_vc(vc, 1); increment_vc(vc, 2); increment_vc(vc, 2); update_vc(db->my_lc, vc); uuid_t * txnid = remote_new_txn(db); assert(txnid != NULL); int status = populate_db(schema, db, txnid, fastrandstate); printf("Test %s - %s (%d)\n", "populate_db_txn", status==0?"OK":"FAILED", status); status = test_search_pk_ck1_ck2(schema, db, txnid, fastrandstate); printf("Test %s - %s (%d)\n", "test_search_pk_ck1_ck2_txn", status==0?"OK":"FAILED", status); status = test_search_pk_ck1(schema, db, txnid, fastrandstate); printf("Test %s - %s (%d)\n", "test_search_pk_ck1_txn", status==0?"OK":"FAILED", status); status = test_search_pk(schema, db, txnid, fastrandstate); printf("Test %s - %s (%d)\n", "test_search_pk_txn", status==0?"OK":"FAILED", status); status = test_enqueue(db, (WORD) 2, txnid); printf("Test %s - %s (%d)\n", "enqueue_txn", status==0?"OK":"FAILED", status); status = test_subscribe_queue(db, (WORD) 1, (WORD) 1); printf("Test %s - %s (%d)\n", "subscribe_queue_txn", status==0?"OK":"FAILED", status); status = test_read_queue(db, (WORD) 1, (WORD) 1, txnid); printf("Test %s - %s (%d)\n", "read_queue_txn", status==QUEUE_STATUS_READ_COMPLETE?"OK":"FAILED", status); status = test_consume_queue(db, (WORD) 1, (WORD) 1, txnid); printf("Test %s - %s (%d)\n", "consume_queue_txn", status==0?"OK":"FAILED", status); status = remote_commit_txn(txnid, db); printf("Test %s - %s (%d)\n", "commit_txn", status==0?"OK":"FAILED", status); return 0; } int main(int argc, char **argv) { int portno, n, status; char *hostname; unsigned int seed; GET_RANDSEED(&seed, 0); // thread_id /* check command line arguments */ if (argc != 3) { fprintf(stderr,"usage: %s \n", argv[0]); exit(0); } hostname = argv[1]; portno = atoi(argv[2]); remote_db_t * db = get_remote_db(3); add_server_to_membership(hostname, portno, db, &seed); add_server_to_membership(hostname, portno+1, db, &seed); add_server_to_membership(hostname, portno+2, db, &seed); db_schema_t * schema = create_schema(); status = populate_db(schema, db, NULL, &seed); printf("Test %s - %s (%d)\n", "populate_db", status==0?"OK":"FAILED", status); status = test_search_pk_ck1_ck2(schema, db, NULL, &seed); printf("Test %s - %s (%d)\n", "test_search_pk_ck1_ck2", status==0?"OK":"FAILED", status); status = test_search_pk_ck1(schema, db, NULL, &seed); printf("Test %s - %s (%d)\n", "test_search_pk_ck1", status==0?"OK":"FAILED", status); status = test_search_pk(schema, db, NULL, &seed); printf("Test %s - %s (%d)\n", "test_search_pk", status==0?"OK":"FAILED", status); remote_print_long_table((WORD) 0, db); status = delete_all(schema, db, NULL, &seed); printf("Test %s - %s (%d)\n", "delete_all", status==0?"OK":"FAILED", status); status = test_create_queue(db, NULL); printf("Test %s - %s (%d)\n", "create_queue", status==0?"OK":"FAILED", status); status = test_subscribe_queue(db, (WORD) 0, (WORD) 1); printf("Test %s - %s (%d)\n", "subscribe_queue", status==0?"OK":"FAILED", status); status = test_enqueue(db, (WORD) 1, NULL); printf("Test %s - %s (%d)\n", "enqueue", status==0?"OK":"FAILED", status); status = test_read_queue(db, (WORD) 0, (WORD) 1, NULL); printf("Test %s - %s (%d)\n", "read_queue", status==QUEUE_STATUS_READ_COMPLETE?"OK":"FAILED", status); status = test_consume_queue(db, (WORD) 0, (WORD) 1, NULL); printf("Test %s - %s (%d)\n", "consume_queue", status==(no_enqueues - 1)?"OK":"FAILED", status); status = test_unsubscribe_queue(db, (WORD) 0, (WORD) 1); printf("Test %s - %s (%d)\n", "unsubscribe_queue", status==0?"OK":"FAILED", status); remote_print_long_table((WORD) 0, db); remote_print_long_table((WORD) 1, db); status = test_txn(db, schema, &seed); printf("Test %s - %s (%d)\n", "txn", status==0?"OK":"FAILED", status); remote_print_long_table((WORD) 0, db); remote_print_long_table((WORD) 1, db); status = test_delete_queue(db, NULL); printf("Test %s - %s (%d)\n", "delete_queue", status==0?"OK":"FAILED", status); status = close_remote_db(db); printf("Test %s - %s (%d)\n", "close_remote_db", status==0?"OK":"FAILED", status); return 0; } ================================================ FILE: backend/txn_state.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * txn_state.c */ #include #include #include #include #include "txn_state.h" int txn_write_cmp(WORD e1, WORD e2) { txn_write * tr1 = (txn_write *) e1; txn_write * tr2 = (txn_write *) e2; if(tr1->table_key != tr2->table_key) return (int) ((int64_t) tr1->table_key - (int64_t) tr2->table_key); if(tr1->query_type < QUERY_TYPE_ENQUEUE) // Regular ops ordering: { // Newer writes always overwrite older writes to the same objects in the same txn (even between updates/deletes to same object): int no_key_cols1 = tr1->no_primary_keys + tr1->no_clustering_keys; int no_key_cols2 = tr2->no_primary_keys + tr2->no_clustering_keys; if(no_key_cols1 != no_key_cols2) return no_key_cols1 - no_key_cols2; for(int i=0;icolumn_values[i] != tr2->column_values[i]) return (int) (int64_t) tr1->column_values[i] - (int64_t) tr2->column_values[i]; } } else // Queue ops ordering: { if(tr1->query_type != tr2->query_type) return tr1->query_type - tr2->query_type; // For queue reads and consumes, the last version of private read/consume head is kept in write set: if(tr1->query_type == QUERY_TYPE_READ_QUEUE || tr1->query_type == QUERY_TYPE_CONSUME_QUEUE) { if(tr1->queue_id != tr2->queue_id) return (int) ((int64_t) tr1->queue_id - (int64_t) tr2->queue_id); if(tr1->app_id != tr2->app_id) return (int) ((int64_t) tr1->app_id - (int64_t) tr2->app_id); if(tr1->shard_id != tr2->shard_id) return (int) ((int64_t) tr1->shard_id - (int64_t) tr2->shard_id); if(tr1->consumer_id != tr2->consumer_id) return (int) ((int64_t) tr1->consumer_id - (int64_t) tr2->consumer_id); } // All enqueues, queue creates, deletes, subscribes and unsubscribes are accumulated in the write set, in the local order they were issued in the txn: else if(tr1->query_type == QUERY_TYPE_ENQUEUE || tr1->query_type == QUERY_TYPE_CREATE_QUEUE || tr1->query_type == QUERY_TYPE_SUBSCRIBE_QUEUE || tr1->query_type == QUERY_TYPE_UNSUBSCRIBE_QUEUE) { if(tr1->local_order != tr2->local_order) return (int) ((int64_t) tr1->local_order - (int64_t) tr2->local_order); } } return 0; } int txn_read_cmp(WORD e1, WORD e2) { txn_read * tr1 = (txn_read *) e1; txn_read * tr2 = (txn_read *) e2; // Same read operations (individual or range, queried by various clustering levels) return the same object versions while the txn is open: if(tr1->query_type != tr2->query_type) return tr1->query_type - tr2->query_type; if(tr1->table_key != tr2->table_key) return (int) ((int64_t) tr1->table_key - (int64_t) tr2->table_key); if(tr1->query_type == QUERY_TYPE_READ_INDEX || tr1->query_type == QUERY_TYPE_READ_INDEX_RANGE) { if(tr1->idx_idx != tr2->idx_idx) return tr1->idx_idx - tr2->idx_idx; } if(tr1->no_primary_keys != tr2->no_primary_keys) return tr1->no_primary_keys - tr2->no_primary_keys; for(int i=0;ino_primary_keys;i++) { if(tr1->start_primary_keys[i] != tr2->start_primary_keys[i]) return tr1->start_primary_keys[i] - tr2->start_primary_keys[i]; } if(tr1->query_type == QUERY_TYPE_READ_ROW_RANGE || tr1->query_type == QUERY_TYPE_READ_INDEX_RANGE) { for(int i=0;ino_primary_keys;i++) { if(tr1->end_primary_keys[i] != tr2->end_primary_keys[i]) return tr1->end_primary_keys[i] - tr2->end_primary_keys[i]; } } if(tr1->query_type != QUERY_TYPE_READ_ROW && tr1->query_type != QUERY_TYPE_READ_ROW_RANGE) { if(tr1->no_clustering_keys != tr2->no_clustering_keys) return tr1->no_clustering_keys - tr2->no_clustering_keys; for(int i=0;ino_clustering_keys;i++) { if(tr1->start_clustering_keys[i] != tr2->start_clustering_keys[i]) return tr1->start_clustering_keys[i] - tr2->start_clustering_keys[i]; } if(tr1->query_type == QUERY_TYPE_READ_CELL_RANGE) { for(int i=0;ino_clustering_keys;i++) { if(tr1->end_clustering_keys[i] != tr2->end_clustering_keys[i]) return tr1->end_clustering_keys[i] - tr2->end_clustering_keys[i]; } } } if(tr1->query_type == QUERY_TYPE_READ_COLS) { if(tr1->no_col_keys != tr2->no_col_keys) return tr1->no_col_keys - tr2->no_col_keys; for(int i=0;ino_col_keys;i++) { if(tr1->col_keys[i] != tr2->col_keys[i]) return tr1->col_keys[i] - tr2->col_keys[i]; } } return 0; } txn_state * init_txn_state() { txn_state * ts = (txn_state *) malloc(sizeof(txn_state)); uuid_generate(ts->txnid); ts->read_set = create_skiplist(&txn_read_cmp); ts->write_set = create_skiplist(&txn_write_cmp); ts->state = TXN_STATUS_ACTIVE; ts->version = NULL; return ts; } void set_version(txn_state * ts, vector_clock * vc) { if(ts->version == NULL) ts->version = copy_vc(vc); else update_or_replace_vc(&(ts->version), vc); } void free_txn_state(txn_state * ts) { skiplist_free(ts->read_set); skiplist_free(ts->write_set); free(ts); } txn_write * get_txn_write(short query_type, WORD * column_values, int no_cols, int no_primary_keys, int no_clustering_keys, size_t blob_size, WORD table_key, int64_t local_order) { txn_write * tw = (txn_write *) malloc(sizeof(txn_write) + no_cols*sizeof(WORD)); memset(tw, 0, sizeof(txn_write) + no_cols*sizeof(WORD)); tw->table_key = table_key; tw->no_cols = no_cols; tw->no_primary_keys = no_primary_keys; tw->no_clustering_keys = no_clustering_keys; tw->blob_size = blob_size; tw->column_values = (WORD *) ((char *) tw + sizeof(txn_write)); for(int i=0;ino_cols;i++) tw->column_values[i] = column_values[i]; tw->query_type = query_type; tw->local_order = local_order; return tw; } txn_write * get_dummy_txn_write(short query_type, WORD * primary_keys, int no_primary_keys, WORD * clustering_keys, int no_clustering_keys, WORD table_key, int64_t local_order) { int no_cols = no_primary_keys + no_clustering_keys; txn_write * tw = (txn_write *) malloc(sizeof(txn_write) + no_cols*sizeof(WORD)); memset(tw, 0, sizeof(txn_write) + no_cols*sizeof(WORD)); tw->table_key = table_key; tw->no_cols = no_cols; tw->blob_size = 0; tw->no_primary_keys = no_primary_keys; tw->no_clustering_keys = no_clustering_keys; tw->column_values = (WORD *) ((char *) tw + sizeof(txn_write)); int i=0; for(;ino_primary_keys;i++) tw->column_values[i] = primary_keys[i]; for(;ino_cols;i++) tw->column_values[i] = primary_keys[i-no_primary_keys]; tw->query_type = query_type; tw->local_order = local_order; return tw; } txn_write * get_txn_queue_op(short query_type, WORD * column_values, int no_cols, size_t blob_size, WORD table_key, WORD queue_id, WORD consumer_id, WORD shard_id, WORD app_id, int64_t new_read_head, vector_clock * prh_version, int64_t new_consume_head, int64_t local_order) { assert(query_type >= QUERY_TYPE_ENQUEUE && query_type <= QUERY_TYPE_UNSUBSCRIBE_QUEUE); txn_write * tw = get_txn_write(query_type, column_values, no_cols, 0, 0, blob_size, table_key, local_order); tw->queue_id = queue_id; if(query_type == QUERY_TYPE_READ_QUEUE || query_type == QUERY_TYPE_CONSUME_QUEUE || query_type == QUERY_TYPE_SUBSCRIBE_QUEUE || query_type == QUERY_TYPE_UNSUBSCRIBE_QUEUE) { tw->consumer_id = consumer_id; tw->shard_id = shard_id; tw->app_id = app_id; } else { assert(consumer_id == NULL && shard_id == NULL && app_id == NULL); } if(query_type == QUERY_TYPE_READ_QUEUE) { tw->new_read_head = new_read_head; tw->prh_version = prh_version; } else { assert(new_read_head == -1); } if(query_type == QUERY_TYPE_CONSUME_QUEUE) { tw->new_consume_head = new_consume_head; } else { assert(new_consume_head == -1); } return tw; } void free_txn_write(txn_write * tw) { free(tw); } txn_read * get_txn_read(short query_type, WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, WORD* col_keys, int no_col_keys, int idx_idx, vector_clock * result_version, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, WORD table_key, int64_t local_order) { int total_col_count = no_primary_keys + no_clustering_keys; if(query_type == QUERY_TYPE_READ_ROW_RANGE) total_col_count += no_primary_keys; if(query_type == QUERY_TYPE_READ_CELL_RANGE) total_col_count += no_clustering_keys; if(query_type == QUERY_TYPE_READ_COLS) total_col_count += no_col_keys; txn_read * tr = (txn_read *) malloc(sizeof(txn_read) + total_col_count * sizeof(WORD)); memset(tr, 0, sizeof(txn_read) + total_col_count * sizeof(WORD)); tr->table_key = table_key; tr->query_type = query_type; tr->local_order = local_order; int offset = sizeof(txn_write); tr->no_primary_keys = no_primary_keys; tr->start_clustering_keys = (WORD *) ((char *) tr + offset); for(int i=0;ino_primary_keys;i++) tr->start_primary_keys[i] = start_primary_keys[i]; offset += tr->no_primary_keys * sizeof(WORD); if(query_type == QUERY_TYPE_READ_ROW_RANGE) { tr->end_clustering_keys = (WORD *) ((char *) tr + offset); for(int i=0;ino_primary_keys;i++) tr->end_clustering_keys[i] = end_clustering_keys[i]; offset += tr->no_primary_keys * sizeof(WORD); } if(query_type != QUERY_TYPE_READ_ROW && query_type != QUERY_TYPE_READ_ROW_RANGE) { tr->start_clustering_keys = (WORD *) ((char *) tr + offset); for(int i=0;ino_clustering_keys;i++) tr->start_clustering_keys[i] = start_clustering_keys[i]; offset += tr->no_clustering_keys * sizeof(WORD); } if(query_type == QUERY_TYPE_READ_CELL_RANGE) { tr->end_clustering_keys = (WORD *) ((char *) tr + offset); for(int i=0;ino_clustering_keys;i++) tr->end_clustering_keys[i] = end_clustering_keys[i]; offset += tr->no_clustering_keys * sizeof(WORD); } if(query_type == QUERY_TYPE_READ_COLS) { tr->col_keys = (WORD *) ((char *) tr + offset); for(int i=0;ino_col_keys;i++) tr->col_keys[i] = col_keys[i]; offset += tr->no_col_keys * sizeof(WORD); } if(query_type == QUERY_TYPE_READ_INDEX || query_type == QUERY_TYPE_READ_INDEX_RANGE) assert(idx_idx != -1); tr->idx_idx = idx_idx; tr->result_version = result_version; tr->range_result_keys = range_result_keys; tr->range_result_versions = range_result_versions; tr->no_range_results = no_range_results; return tr; } void free_txn_read(txn_read * tr) { if(tr->result_version != NULL) free_vc(tr->result_version); if(tr->range_result_keys && tr->no_range_results > 0) { free(tr->range_result_keys); for(int i=0;ino_range_results;i++) free_vc(tr->range_result_versions[i]); free(tr->range_result_versions); } free(tr); } int add_write_to_txn(short query_type, WORD * column_values, int no_cols, int no_primary_keys, int no_clustering_keys, size_t blob_size, WORD table_key, txn_state * ts, unsigned int * fastrandstate) { assert((query_type == QUERY_TYPE_UPDATE) || (query_type == QUERY_TYPE_DELETE)); txn_write * tw = get_txn_write(query_type, column_values, no_cols, no_primary_keys, no_clustering_keys, blob_size, table_key, (int64_t) ts->write_set->no_items); // Note that this will overwrite previous values written for the variable in the same txn (last write wins): snode_t * prev_tw_node = skiplist_search(ts->write_set, (WORD) tw); txn_write * prev_tw = (prev_tw_node != NULL)?prev_tw_node->value : NULL; int ret = skiplist_insert(ts->write_set, (WORD) tw, (WORD) tw, fastrandstate); if(prev_tw != NULL) free_txn_write(prev_tw); return ret; } int add_row_read_to_txn(WORD* primary_keys, int no_primary_keys, WORD table_key, db_row_t* result, txn_state * ts, unsigned int * fastrandstate) { txn_read * tr = get_txn_read(QUERY_TYPE_READ_ROW, primary_keys, NULL, no_primary_keys, NULL, NULL, 0, NULL, 0, -1, copy_vc(result->version), NULL, NULL, 0, table_key, (int64_t) ts->read_set->no_items); // Note that this will overwrite previous values read for the variable in the same txn (last read wins): snode_t * prev_tr_node = skiplist_search(ts->read_set, (WORD) tr); txn_read * prev_tr = (prev_tr_node != NULL)?prev_tr_node->value : NULL; int ret = skiplist_insert(ts->read_set, (WORD) tr, (WORD) tr, fastrandstate); if(prev_tr != NULL) free_txn_read(prev_tr); return ret; } int add_row_range_read_to_txn(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, WORD table_key, snode_t* start_row, snode_t* end_row, int no_results, txn_state * ts, unsigned int * fastrandstate) { int64_t * range_result_keys = (int64_t *) malloc(no_results * sizeof(int64_t)); vector_clock ** range_result_versions = (vector_clock **) malloc(no_results * sizeof(vector_clock *));; int i=0; for(snode_t* crt_row = start_row;crt_row != end_row;crt_row=NEXT(crt_row), i++) { db_row_t * row = (db_row_t *) crt_row->value; range_result_keys[i] = (int64_t) row->key; range_result_versions[i] = (row->version != NULL)? copy_vc(row->version) : NULL; } txn_read * tr = get_txn_read(QUERY_TYPE_READ_ROW_RANGE, start_primary_keys, end_primary_keys, no_primary_keys, NULL, NULL, 0, NULL, 0, -1, NULL, range_result_keys, range_result_versions, no_results, table_key, (int64_t) ts->read_set->no_items); snode_t * prev_tr_node = skiplist_search(ts->read_set, (WORD) tr); txn_read * prev_tr = (prev_tr_node != NULL)?prev_tr_node->value : NULL; int ret = skiplist_insert(ts->read_set, (WORD) tr, (WORD) tr, fastrandstate); // Note that this will overwrite previous values read for the variable in the same txn (last read wins) if(prev_tr != NULL) free_txn_read(prev_tr); return ret; } int add_cell_read_to_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD table_key, db_row_t* result, txn_state * ts, unsigned int * fastrandstate) { txn_read * tr = get_txn_read(QUERY_TYPE_READ_CELL, primary_keys, NULL, no_primary_keys, clustering_keys, NULL, no_clustering_keys, NULL, 0, -1, copy_vc(result->version), NULL, NULL, 0, table_key, (int64_t) ts->read_set->no_items); snode_t * prev_tr_node = skiplist_search(ts->read_set, (WORD) tr); txn_read * prev_tr = (prev_tr_node != NULL)?prev_tr_node->value : NULL; int ret = skiplist_insert(ts->read_set, (WORD) tr, (WORD) tr, fastrandstate); // Note that this will overwrite previous values read for the variable in the same txn (last read wins) if(prev_tr != NULL) free_txn_read(prev_tr); return ret; } int add_cell_range_read_to_txn(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, WORD table_key, snode_t* start_row, snode_t* end_row, int no_results, txn_state * ts, unsigned int * fastrandstate) { int64_t * range_result_keys = (int64_t *) malloc(no_results * sizeof(int64_t)); vector_clock ** range_result_versions = (vector_clock **) malloc(no_results * sizeof(vector_clock *));; int i=0; for(snode_t* crt_row = start_row;crt_row != end_row;crt_row=NEXT(crt_row), i++) { db_row_t * row = (db_row_t *) crt_row->value; range_result_keys[i] = (int64_t) row->key; range_result_versions[i] = (row->version != NULL)? copy_vc(row->version) : NULL; } txn_read * tr = get_txn_read(QUERY_TYPE_READ_CELL_RANGE, primary_keys, NULL, no_primary_keys, start_clustering_keys, end_clustering_keys, no_clustering_keys, NULL, 0, -1, NULL, range_result_keys, range_result_versions, no_results, table_key, (int64_t) ts->read_set->no_items); snode_t * prev_tr_node = skiplist_search(ts->read_set, (WORD) tr); txn_read * prev_tr = (prev_tr_node != NULL)?prev_tr_node->value : NULL; int ret = skiplist_insert(ts->read_set, (WORD) tr, (WORD) tr, fastrandstate); // Note that this will overwrite previous values read for the variable in the same txn (last read wins) if(prev_tr != NULL) free_txn_read(prev_tr); return ret; } int add_col_read_to_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD* col_keys, int no_columns, WORD table_key, db_row_t* result, txn_state * ts, unsigned int * fastrandstate) { txn_read * tr = get_txn_read(QUERY_TYPE_READ_COLS, primary_keys, NULL, no_primary_keys, clustering_keys, NULL, no_clustering_keys, col_keys, no_columns, -1, copy_vc(result->version), NULL, NULL, 0, table_key, (int64_t) ts->read_set->no_items); snode_t * prev_tr_node = skiplist_search(ts->read_set, (WORD) tr); txn_read * prev_tr = (prev_tr_node != NULL)?prev_tr_node->value : NULL; int ret = skiplist_insert(ts->read_set, (WORD) tr, (WORD) tr, fastrandstate); // Note that this will overwrite previous values read for the variable in the same txn (last read wins) if(prev_tr != NULL) free_txn_read(prev_tr); return ret; } int add_index_read_to_txn(WORD* index_key, int idx_idx, WORD table_key, db_row_t* result, txn_state * ts, unsigned int * fastrandstate) { txn_read * tr = get_txn_read(QUERY_TYPE_READ_INDEX, index_key, NULL, 1, NULL, NULL, 0, NULL, 0, idx_idx, copy_vc(result->version), NULL, NULL, 0, table_key, (int64_t) ts->read_set->no_items); snode_t * prev_tr_node = skiplist_search(ts->read_set, (WORD) tr); txn_read * prev_tr = (prev_tr_node != NULL)?prev_tr_node->value : NULL; int ret = skiplist_insert(ts->read_set, (WORD) tr, (WORD) tr, fastrandstate); // Note that this will overwrite previous values read for the variable in the same txn (last read wins) if(prev_tr != NULL) free_txn_read(prev_tr); return ret; } int add_index_range_read_to_txn(int idx_idx, WORD* start_idx_key, WORD* end_idx_key, snode_t* start_row, snode_t* end_row, int no_results, WORD table_key, txn_state * ts, unsigned int * fastrandstate) { int64_t * range_result_keys = (int64_t *) malloc(no_results * sizeof(int64_t)); vector_clock ** range_result_versions = (vector_clock **) malloc(no_results * sizeof(vector_clock *));; int i=0; for(snode_t* crt_row = start_row;crt_row != end_row;crt_row=NEXT(crt_row), i++) { db_row_t * row = (db_row_t *) crt_row->value; range_result_keys[i] = (int64_t) row->key; range_result_versions[i] = (row->version != NULL)? copy_vc(row->version) : NULL; } txn_read * tr = get_txn_read(QUERY_TYPE_READ_INDEX_RANGE, start_idx_key, end_idx_key, 1, NULL, NULL, 0, NULL, 0, idx_idx, NULL, range_result_keys, range_result_versions, no_results, table_key, (int64_t) ts->read_set->no_items); snode_t * prev_tr_node = skiplist_search(ts->read_set, (WORD) tr); txn_read * prev_tr = (prev_tr_node != NULL)?prev_tr_node->value : NULL; int ret = skiplist_insert(ts->read_set, (WORD) tr, (WORD) tr, fastrandstate); // Note that this will overwrite previous values read for the variable in the same txn (last read wins) if(prev_tr != NULL) free_txn_read(prev_tr); return ret; } // Queue ops: int add_enqueue_to_txn(WORD * column_values, int no_cols, size_t blob_size, WORD table_key, WORD queue_id, txn_state * ts, unsigned int * fastrandstate) { txn_write * tw = get_txn_queue_op(QUERY_TYPE_ENQUEUE, column_values, no_cols, blob_size, table_key, queue_id, NULL, NULL, NULL, -1, NULL, -1, (int64_t) ts->write_set->no_items); // Multiple enqueues in the same txn accumulate in write set (indexed by local_order = ts->write_set->no_items): return skiplist_insert(ts->write_set, (WORD) tw, (WORD) tw, fastrandstate); } int add_read_queue_to_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_read_head, vector_clock * prh_version, txn_state * ts, unsigned int * fastrandstate) { txn_write * tw = get_txn_queue_op(QUERY_TYPE_READ_QUEUE, NULL, 0, 0, table_key, queue_id, consumer_id, shard_id, app_id, new_read_head, prh_version, -1, (int64_t) ts->write_set->no_items); // Keep only latest private_read_head when doing multiple queue reads in the same txn: snode_t * prev_tw_node = skiplist_search(ts->write_set, (WORD) tw); txn_write * prev_tw = (prev_tw_node != NULL)?prev_tw_node->value : NULL; int ret = skiplist_insert(ts->write_set, (WORD) tw, (WORD) tw, fastrandstate); // TO DO: Handle multiple queue reads in the same txn if(prev_tw != NULL) free_txn_write(prev_tw); return ret; } int add_consume_queue_to_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, txn_state * ts, unsigned int * fastrandstate) { txn_write * tw = get_txn_queue_op(QUERY_TYPE_CONSUME_QUEUE, NULL, 0, 0, table_key, queue_id, consumer_id, shard_id, app_id, -1, NULL, new_consume_head, (int64_t) ts->write_set->no_items); // Keep only latest private_consume_head when doing multiple queue consumes in the same txn: snode_t * prev_tw_node = skiplist_search(ts->write_set, (WORD) tw); txn_write * prev_tw = (prev_tw_node != NULL)?prev_tw_node->value : NULL; int ret = skiplist_insert(ts->write_set, (WORD) tw, (WORD) tw, fastrandstate); // TO DO: Handle multiple queue reads in the same txn if(prev_tw != NULL) free_txn_write(prev_tw); return ret; } int add_create_queue_to_txn(WORD table_key, WORD queue_id, txn_state * ts, unsigned int * fastrandstate) { txn_write * tw = get_txn_queue_op(QUERY_TYPE_CREATE_QUEUE, NULL, 0, 0, table_key, queue_id, NULL, NULL, NULL, -1, NULL, -1, (int64_t) ts->write_set->no_items); // Multiple "create queue"-s in the same txn accumulate in write set (indexed by local_order = ts->write_set->no_items): return skiplist_insert(ts->write_set, (WORD) tw, (WORD) tw, fastrandstate); // TO DO: Handle multiple enqueues in the same txn } int add_delete_queue_to_txn(WORD table_key, WORD queue_id, txn_state * ts, unsigned int * fastrandstate) { txn_write * tw = get_txn_queue_op(QUERY_TYPE_DELETE_QUEUE, NULL, 0, 0, table_key, queue_id, NULL, NULL, NULL, -1, NULL, -1, (int64_t) ts->write_set->no_items); // Multiple "delete queue"-s in the same txn accumulate in write set (indexed by local_order = ts->write_set->no_items): return skiplist_insert(ts->write_set, (WORD) tw, (WORD) tw, fastrandstate); // TO DO: Handle multiple enqueues in the same txn } int add_subscribe_queue_to_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, txn_state * ts, unsigned int * fastrandstate) { assert (0); // Not implemented return 0; } int add_unsubscribe_queue_to_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, txn_state * ts) { assert (0); // Not implemented return 0; } ================================================ FILE: backend/txn_state.h ================================================ /* * txn_state.h */ #ifndef BACKEND_TXN_STATE_H_ #define BACKEND_TXN_STATE_H_ #include #include "db.h" #include "queue_callback.h" #define TXN_STATUS_ACTIVE 0 #define TXN_STATUS_VALIDATED 1 // #define TXN_STATUS_COMMITTED 2 // #define TXN_STATUS_ABORTED 3 typedef struct txn_write { short query_type; WORD table_key; WORD * column_values; int no_cols; int no_primary_keys; int no_clustering_keys; size_t blob_size; // For queue ops: WORD queue_id; WORD consumer_id; WORD shard_id; WORD app_id; int64_t new_read_head; // read_queue (out) int64_t new_consume_head; // consume_queue (in) vector_clock * prh_version; // vector_clock * pch_version; int64_t local_order; } txn_write; typedef struct txn_read { WORD table_key; WORD* start_primary_keys; WORD* end_primary_keys; int no_primary_keys; WORD* start_clustering_keys; WORD* end_clustering_keys; int no_clustering_keys; WORD* col_keys; int no_col_keys; // For idx queries: int idx_idx; short query_type; // For non-range queries: vector_clock * result_version; // For range queries: int64_t * range_result_keys; vector_clock ** range_result_versions; int no_range_results; snode_t* start_row; snode_t* end_row; int64_t local_order; } txn_read; typedef struct txn_state { uuid_t txnid; skiplist_t * read_set; skiplist_t * write_set; short state; vector_clock * version; } txn_state; int txn_write_cmp(WORD e1, WORD e2); int txn_read_cmp(WORD e1, WORD e2); txn_state * init_txn_state(); void free_txn_state(txn_state * ts); void set_version(txn_state * ts, vector_clock * vc); txn_write * get_txn_write(short query_type, WORD * column_values, int no_cols, int no_primary_keys, int no_clustering_keys, size_t blob_size, WORD table_key, int64_t local_order); txn_write * get_dummy_txn_write(short query_type, WORD * primary_keys, int no_primary_keys, WORD * clustering_keys, int no_clustering_keys, WORD table_key, int64_t local_order); void free_txn_write(txn_write * tw); txn_read * get_txn_read(short query_type, WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, WORD* col_keys, int no_col_keys, int idx_idx, vector_clock * result_version, int64_t * range_result_keys, vector_clock ** range_result_versions, int no_range_results, WORD table_key, int64_t local_order); void free_txn_read(txn_read * tr); // Txn ops mgmt API: int add_write_to_txn(short query_type, WORD * column_values, int no_cols, int no_primary_keys, int no_clustering_keys, size_t blob_size, WORD table_key, txn_state * ts, unsigned int * fastrandstate); int add_row_read_to_txn(WORD* primary_keys, int no_primary_keys, WORD table_key, db_row_t* result, txn_state * ts, unsigned int * fastrandstate); int add_row_range_read_to_txn(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, WORD table_key, snode_t* start_row, snode_t* end_row, int no_results, txn_state * ts, unsigned int * fastrandstate); int add_cell_read_to_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD table_key, db_row_t* result, txn_state * ts, unsigned int * fastrandstate); int add_cell_range_read_to_txn(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, WORD table_key, snode_t* start_row, snode_t* end_row, int no_results, txn_state * ts, unsigned int * fastrandstate); int add_col_read_to_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD* col_keys, int no_columns, WORD table_key, db_row_t* result, txn_state * ts, unsigned int * fastrandstate); int add_index_read_to_txn(WORD* index_key, int idx_idx, WORD table_key, db_row_t* result, txn_state * ts, unsigned int * fastrandstate); int add_index_range_read_to_txn(int idx_idx, WORD* start_idx_key, WORD* end_idx_key, snode_t* start_row, snode_t* end_row, int no_results, WORD table_key, txn_state * ts, unsigned int * fastrandstate); // Queue ops: int add_enqueue_to_txn(WORD * column_values, int no_cols, size_t blob_size, WORD table_key, WORD queue_id, txn_state * ts, unsigned int * fastrandstate); int add_read_queue_to_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_read_head, vector_clock * prh_version, txn_state * ts, unsigned int * fastrandstate); int add_consume_queue_to_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, txn_state * ts, unsigned int * fastrandstate); int add_create_queue_to_txn(WORD table_key, WORD queue_id, txn_state * ts, unsigned int * fastrandstate); int add_delete_queue_to_txn(WORD table_key, WORD queue_id, txn_state * ts, unsigned int * fastrandstate); int add_subscribe_queue_to_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, txn_state * ts, unsigned int * fastrandstate); int add_unsubscribe_queue_to_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, txn_state * ts); #endif /* BACKEND_TXN_STATE_H_ */ ================================================ FILE: backend/txns.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * txns.c * * Author: aagapi */ #include "txns.h" #include "log.h" #include #define VERBOSE_TXNS 1 #define VERBOSE_TXNS_PERSIST 0 // DB queries: txn_state * get_txn_state(uuid_t * txnid, db_t * db) { snode_t * txn_node = (snode_t *) skiplist_search(db->txn_state, (WORD) (*txnid)); return (txn_node != NULL)? (txn_state *) txn_node->value : NULL; } uuid_t * new_txn(db_t * db, unsigned int * seedptr) { txn_state * ts = NULL, * previous = NULL; #if (MULTI_THREADED == 1) pthread_mutex_lock(db->txn_state_lock); #endif while(ts == NULL) { ts = init_txn_state(); previous = get_txn_state(&(ts->txnid), db); if(previous != NULL) { free_txn_state(ts); ts = NULL; } } skiplist_insert(db->txn_state, (WORD) ts->txnid, (WORD) ts, seedptr); #if (MULTI_THREADED == 1) pthread_mutex_unlock(db->txn_state_lock); #endif return &(ts->txnid); } int close_txn_state(txn_state * ts, db_t * db) { #if (MULTI_THREADED == 1) pthread_mutex_lock(db->txn_state_lock); #endif skiplist_delete(db->txn_state, ts->txnid); free_txn_state(ts); #if (MULTI_THREADED == 1) pthread_mutex_unlock(db->txn_state_lock); #endif return 0; } int close_txn(uuid_t * txnid, db_t * db) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn return close_txn_state(ts, db); } int key_path_overlaps(txn_read * tr, txn_write * tw) { // Writes must be at least as specific as reads: assert(tr->no_primary_keys + tr->no_clustering_keys <= tw->no_primary_keys + tw->no_clustering_keys); int is_exact_read_query = (tr->query_type == QUERY_TYPE_READ_COLS || tr->query_type == QUERY_TYPE_READ_CELL || tr->query_type == QUERY_TYPE_READ_ROW); if(tr->query_type == QUERY_TYPE_READ_INDEX) { if((int64_t) tw->column_values[tr->idx_idx] == (int64_t) tr->start_primary_keys[0]) return 1; return 0; } if(tr->query_type == QUERY_TYPE_READ_INDEX_RANGE) { if((int64_t) tw->column_values[tr->idx_idx] <= (int64_t) tr->start_primary_keys[0] && (int64_t) tw->column_values[tr->idx_idx] >= (int64_t) tr->end_primary_keys[0]) return 1; return 0; } for(int i=0;ino_primary_keys;i++) { if(is_exact_read_query && tr->start_primary_keys[i] != tw->column_values[i]) return 0; if(!is_exact_read_query && ((int64_t) tr->start_primary_keys[i] > (int64_t) tw->column_values[i] || (int64_t) tr->end_primary_keys[i] < (int64_t) tw->column_values[i])) return 0; } for(int i=0;ino_clustering_keys;i++) { if(is_exact_read_query && tr->start_clustering_keys[i] != tw->column_values[tw->no_primary_keys + i]) return 0; if(!is_exact_read_query && ((int64_t) tr->start_clustering_keys[i] > (int64_t) tw->column_values[tw->no_primary_keys + i] || (int64_t) tr->end_clustering_keys[i] < (int64_t) tw->column_values[tw->no_primary_keys + i])) return 0; } return 1; } // Check if txn read op tr is invalidated by write op tw: int rw_conflict(txn_read * tr, txn_write * tw, int check_exact_match) { if(check_exact_match && tr->table_key != tw->table_key) return 0; // Check for RW conflicts only on regular data (all conflicts on queues are WW): if(tr->query_type >= QUERY_TYPE_READ_COLS && tr->query_type <= QUERY_TYPE_READ_INDEX_RANGE && (tw->query_type == QUERY_TYPE_UPDATE || tw->query_type == QUERY_TYPE_DELETE) ) { switch(tr->query_type) { case QUERY_TYPE_READ_COLS: case QUERY_TYPE_READ_CELL: case QUERY_TYPE_READ_CELL_RANGE: case QUERY_TYPE_READ_ROW: case QUERY_TYPE_READ_ROW_RANGE: case QUERY_TYPE_READ_INDEX: case QUERY_TYPE_READ_INDEX_RANGE: { if(check_exact_match && key_path_overlaps(tr, tw)) // && compare_vc(tr->version, vector_clock * vc2) return 1; } } } return 0; } // Check if queue op tw1 is invalidated by queue op tw2: int queue_op_conflict(txn_write * tw1, txn_write * tw2) { // Subscribes and unsubscribes are not currently supported in txns assert(tw1->query_type != QUERY_TYPE_SUBSCRIBE_QUEUE && tw1->query_type != QUERY_TYPE_UNSUBSCRIBE_QUEUE); assert(tw2->query_type != QUERY_TYPE_SUBSCRIBE_QUEUE && tw2->query_type != QUERY_TYPE_UNSUBSCRIBE_QUEUE); // Queue ops only conflict if they are on the same table and queue: if(tw1->table_key != tw2->table_key || tw1->queue_id != tw2->queue_id) return 0; // CREATE_QUEUE and DELETE_QUEUE conflict with everything: if(tw1->query_type == QUERY_TYPE_CREATE_QUEUE || tw1->query_type == QUERY_TYPE_DELETE_QUEUE || tw2->query_type == QUERY_TYPE_CREATE_QUEUE || tw2->query_type == QUERY_TYPE_DELETE_QUEUE) return 1; // Only ENQUEUE/ENQUEUE (by any producers), as well as READ_QUEUE / READ_QUEUE and // CONSUME_QUEUE / CONSUME_QUEUE *by the same consumer* are valid conflicts: if(tw1->query_type != tw2->query_type) return 0; if(tw1->query_type == QUERY_TYPE_ENQUEUE) return 1; if((tw1->query_type == QUERY_TYPE_READ_QUEUE || tw1->query_type == QUERY_TYPE_CONSUME_QUEUE) && tw1->consumer_id == tw2->consumer_id && tw1->shard_id == tw2->shard_id && tw1->app_id == tw2->app_id) return 1; return 0; } // Check if txn write op tw1 is invalidated by write op tw2: int ww_conflict(txn_write * tw1, txn_write * tw2) { short is_regular_op1 = (tw1->query_type == QUERY_TYPE_UPDATE || tw1->query_type == QUERY_TYPE_DELETE); short is_regular_op2 = (tw2->query_type == QUERY_TYPE_UPDATE || tw2->query_type == QUERY_TYPE_DELETE); if((is_regular_op1 && !is_regular_op2) || (!is_regular_op1&&is_regular_op2)) return 0; if(is_regular_op1) return (txn_write_cmp((WORD) tw1, (WORD) tw2) == 0); else return queue_op_conflict(tw1, tw2); } int is_read_invalidated(txn_read * tr, txn_state * rts, db_t * db) { // Check for conflicts with backend DB: switch(tr->query_type) { case QUERY_TYPE_READ_COLS: case QUERY_TYPE_READ_CELL: { return db_verify_cell_version(tr->start_primary_keys, tr->no_primary_keys, tr->start_clustering_keys, tr->no_clustering_keys, tr->table_key, tr->result_version, db); } case QUERY_TYPE_READ_ROW: { return db_verify_cell_version(tr->start_primary_keys, tr->no_primary_keys, NULL, 0, tr->table_key, tr->result_version, db); } case QUERY_TYPE_READ_INDEX: { return db_verify_index_version(tr->start_primary_keys, tr->idx_idx, tr->table_key, tr->result_version, db); } case QUERY_TYPE_READ_CELL_RANGE: { return db_verify_cell_range_version(tr->start_primary_keys, tr->no_primary_keys, tr->start_clustering_keys, tr->end_clustering_keys, tr->no_clustering_keys, tr->table_key, tr->range_result_keys, tr->range_result_versions, tr->no_range_results, db); } case QUERY_TYPE_READ_ROW_RANGE: { return db_verify_row_range_version(tr->start_primary_keys, tr->end_primary_keys, tr->no_primary_keys, tr->table_key, tr->range_result_keys, tr->range_result_versions, tr->no_range_results, db); } case QUERY_TYPE_READ_INDEX_RANGE: { return db_verify_index_range_version(tr->idx_idx, tr->start_primary_keys, tr->end_primary_keys, tr->range_result_keys, tr->range_result_versions, tr->no_range_results, tr->table_key, db); } } // Check for conflicts with the other txn write sets: // If exact (non-range) read, and not a secondary index query, create dummy write op on the same key path, to look it up in other txn's write set: int is_exact_query = (tr->query_type == QUERY_TYPE_READ_COLS || tr->query_type == QUERY_TYPE_READ_CELL || tr->query_type == QUERY_TYPE_READ_ROW); txn_write * dummy_tw_update = is_exact_query? get_dummy_txn_write(QUERY_TYPE_UPDATE, tr->start_primary_keys, tr->no_primary_keys, tr->start_clustering_keys, tr->no_clustering_keys, tr->table_key, 0) : NULL; #if (MULTI_THREADED == 1) pthread_mutex_lock(db->txn_state_lock); #endif for(snode_t * node=HEAD(db->txn_state); node!=NULL; node=NEXT(node)) { assert(node->value != NULL); txn_state * ts = (txn_state *) node->value; if(ts->state != TXN_STATUS_VALIDATED || uuid_compare(rts->txnid, ts->txnid) == 0) continue; if(is_exact_query) { snode_t * write_op_n = skiplist_search(ts->write_set, (WORD) dummy_tw_update); if(write_op_n != NULL) { assert(write_op_n->value != NULL); txn_write * tw = (txn_write *) write_op_n->value; if(rw_conflict(tr, tw, 0)) { #if (VERBOSE_TXNS > 0) log_debug("Invalidating txn due to rw conflict"); #endif #if (MULTI_THREADED == 1) pthread_mutex_unlock(db->txn_state_lock); #endif return 1; } } } else // For range or index queries, we need to iterate the other txn write sets to see if any writes conflict with our reads: { for(snode_t * write_op_n=HEAD(ts->write_set); write_op_n!=NULL; write_op_n=NEXT(write_op_n)) { assert(write_op_n->value != NULL); txn_write * tw = (txn_write *) write_op_n->value; if(rw_conflict(tr, tw, 1) && ts->state == TXN_STATUS_VALIDATED) { #if (MULTI_THREADED == 1) pthread_mutex_unlock(db->txn_state_lock); #endif return 1; } } } } #if (MULTI_THREADED == 1) pthread_mutex_unlock(db->txn_state_lock); #endif return 0; } int is_write_invalidated(txn_write * tw, txn_state * rts, int * schema_status, db_t * db) { // Check for invalidated queue reads / creation / deletion ops with backend DB: *schema_status = 0; switch(tw->query_type) { case QUERY_TYPE_READ_QUEUE: { int status = db_verify_cell_version(&tw->queue_id, 1, NULL, 0, tw->table_key, tw->prh_version, db); if(status == DB_ERR_NO_TABLE || status == DB_ERR_NO_QUEUE) { #if (VERBOSE_TXNS > 0) log_debug("read_queue(%ld) invalidating txn", tw->queue_id); #endif *schema_status = 1; } return (status != 0); } case QUERY_TYPE_CREATE_QUEUE: { return (db_search(&tw->queue_id, tw->table_key, db) != NULL); } case QUERY_TYPE_DELETE_QUEUE: case QUERY_TYPE_UNSUBSCRIBE_QUEUE: { return (db_search(&tw->queue_id, tw->table_key, db) == NULL); } case QUERY_TYPE_ENQUEUE: case QUERY_TYPE_CONSUME_QUEUE: case QUERY_TYPE_SUBSCRIBE_QUEUE: { if(db_search(&tw->queue_id, tw->table_key, db) == NULL) { #if (VERBOSE_TXNS > 0) log_debug("Query type %d (%ld) invalidating txn", tw->query_type, tw->queue_id); #endif *schema_status = 1; return 1; } return 0; } } // Check for WW conflicts with other txns' write sets: #if (MULTI_THREADED == 1) pthread_mutex_lock(db->txn_state_lock); #endif for(snode_t * node=HEAD(db->txn_state); node!=NULL; node=NEXT(node)) { assert(node->value != NULL); txn_state * ts = (txn_state *) node->value; if(ts->state != TXN_STATUS_VALIDATED || uuid_compare(rts->txnid, ts->txnid) == 0) continue; if(tw->query_type == QUERY_TYPE_UPDATE || tw->query_type == QUERY_TYPE_DELETE) // Regular ops { snode_t * write_op_n = skiplist_search(ts->write_set, (WORD) tw); if(write_op_n != NULL) { assert(write_op_n->value != NULL); txn_write * tw2 = (txn_write *) write_op_n->value; // if(ww_conflict(tw, tw2, 0)) // { #if (VERBOSE_TXNS > 0) char uuid_str1[37], uuid_str2[37]; uuid_unparse_lower(rts->txnid, uuid_str1); uuid_unparse_lower(ts->txnid, uuid_str2); log_debug("Invalidating txn due to ww conflict on table=%" PRId64 "/%" PRId64 ", write_type=%d/%d, key=%" PRId64 "/%" PRId64 ", txn=%s/%s", (int64_t) tw->table_key, (int64_t) tw2->table_key, tw->query_type, tw2->query_type, ((int64_t *) tw->column_values)[0], ((int64_t *) tw2->column_values)[0], uuid_str2, uuid_str1); #endif #if (MULTI_THREADED == 1) pthread_mutex_unlock(db->txn_state_lock); #endif return 1; // } } } else // Queue ops: { for(snode_t * write_op_n=HEAD(ts->write_set); write_op_n!=NULL; write_op_n=NEXT(write_op_n)) { assert(write_op_n->value != NULL); txn_write * tw2 = (txn_write *) write_op_n->value; // No conflict between regular ops and queue ops: if(tw->query_type == QUERY_TYPE_UPDATE || tw->query_type == QUERY_TYPE_DELETE) continue; if(queue_op_conflict(tw, tw2)) { #if (MULTI_THREADED == 1) pthread_mutex_unlock(db->txn_state_lock); #endif return 1; } } } } #if (MULTI_THREADED == 1) pthread_mutex_unlock(db->txn_state_lock); #endif return 0; } int validate_txn(uuid_t * txnid, vector_clock * version, db_t * db) { txn_state * ts = get_txn_state(txnid, db); int schema_status = 0; if(ts == NULL) return NO_SUCH_TXN; // No such txn assert(ts->state == TXN_STATUS_ACTIVE); // Txn now gets a new version stamp: set_version(ts, version); for(snode_t * read_op_n=HEAD(ts->read_set); read_op_n!=NULL; read_op_n=NEXT(read_op_n)) { if(read_op_n->value != NULL) { txn_read * tr = (txn_read *) read_op_n->value; if(is_read_invalidated(tr, ts, db)) { return VAL_STATUS_ABORT; } } } for(snode_t * write_op_n=HEAD(ts->write_set); write_op_n!=NULL; write_op_n=NEXT(write_op_n)) { if(write_op_n->value != NULL) { txn_write * tw = (txn_write *) write_op_n->value; if(is_write_invalidated(tw, ts, &schema_status, db)) { return (schema_status == 0)?VAL_STATUS_ABORT:VAL_STATUS_ABORT_SCHEMA; } } } ts->state = TXN_STATUS_VALIDATED; return VAL_STATUS_COMMIT; } int persist_write(txn_write * tw, vector_clock * version, db_t * db, unsigned int * fastrandstate) { switch(tw->query_type) { case QUERY_TYPE_UPDATE: { // Note: This also updates or creates the version of the updated / created cell: return db_insert_transactional(tw->column_values, tw->no_cols, tw->no_clustering_keys, tw->blob_size, version, tw->table_key, db, fastrandstate); } case QUERY_TYPE_DELETE: { // Update row tombstone version for handling shadow range reads and reads by incomplete partition / clustering key path? return db_delete_row_transactional(tw->column_values, version, tw->table_key, db, fastrandstate); // TO DO: use tw->no_primary_keys and tw->no_clustering_keys } case QUERY_TYPE_ENQUEUE: { return enqueue(tw->column_values, tw->no_cols, tw->blob_size, tw->table_key, tw->queue_id, 1, db, fastrandstate); } case QUERY_TYPE_READ_QUEUE: { // Note: This also updates queue private read head version: return set_private_read_head(tw->consumer_id, tw->shard_id, tw->app_id, tw->table_key, tw->queue_id, tw->new_read_head, version, 1, db); } case QUERY_TYPE_CONSUME_QUEUE: { return set_private_consume_head(tw->consumer_id, tw->shard_id, tw->app_id, tw->table_key, tw->queue_id, tw->new_consume_head, version, db); } case QUERY_TYPE_CREATE_QUEUE: { return create_queue(tw->table_key, tw->queue_id, version, 1, db, fastrandstate); } case QUERY_TYPE_DELETE_QUEUE: { // Note: This also updates queue tombstone version (if queue was not already deleted by a different txn, in which case earliest deletion timestamp is kept): return delete_queue(tw->table_key, tw->queue_id, version, 1, db, fastrandstate); } default: { assert(0); } } return 0; } int persist_txn(txn_state * ts, db_t * db, unsigned int * fastrandstate) { int res = 0; // Txn needs to have received a commit version by this point: assert(ts->version != NULL); #if (VERBOSE_TXNS_PERSIST > 0) char uuid_str[37]; uuid_unparse_lower(ts->txnid, uuid_str); log_debug("BACKEND: Txn %s has %d writes", uuid_str, ts->write_set->no_items); #endif for(snode_t * write_op_n=HEAD(ts->write_set); write_op_n!=NULL; write_op_n=NEXT(write_op_n)) { if(write_op_n->value != NULL) { txn_write * tw = (txn_write *) write_op_n->value; #if (VERBOSE_TXNS_PERSIST > 0) log_debug("BACKEND: Txn %s attempting to persist write of type %d", uuid_str, tw->query_type); #endif res = persist_write(tw, ts->version, db, fastrandstate); #if (VERBOSE_TXNS_PERSIST > 0) log_debug("BACKEND: Txn %s successfully persisted write of type %d", uuid_str, tw->query_type); #endif if(res != 0) log_debug("BACKEND: persist_write for txn, of type %d returned %d", tw->query_type, res); } } close_txn_state(ts, db); return res; } int abort_txn(uuid_t * txnid, db_t * db) { return close_txn(txnid, db); } int commit_txn(uuid_t * txnid, vector_clock * version, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn #if (VERBOSE_TXNS > 0) char uuid_str[37]; uuid_unparse_lower(*txnid, uuid_str); #endif #if (VERBOSE_TXNS > 1) log_debug("BACKEND: Attempting to validate txn %s", uuid_str); #endif int res = validate_txn(txnid, version, db); #if (VERBOSE_TXNS > 1) log_debug("BACKEND: validate txn %s returned %d", uuid_str, res); #endif if(res == VAL_STATUS_COMMIT) { res = persist_txn(ts, db, fastrandstate); #if (VERBOSE_TXNS > 0) log_debug("BACKEND: persist txn %s returned %d", uuid_str, res); #endif } else if(res == VAL_STATUS_ABORT || res == VAL_STATUS_ABORT_SCHEMA) { res = abort_txn(txnid, db); #if (VERBOSE_TXNS > 0) log_debug("BACKEND: abort txn %s returned %d", uuid_str, res); #endif } else { assert(0); } return res; } int db_insert_in_txn(WORD * column_values, int no_cols, int no_primary_keys, int no_clustering_keys, size_t blob_size, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn return add_write_to_txn(QUERY_TYPE_UPDATE, column_values, no_cols, no_primary_keys, no_clustering_keys, blob_size, table_key, ts, fastrandstate); } db_row_t* db_search_in_txn(WORD* primary_keys, int no_primary_keys, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NULL; // No such txn db_row_t* result = db_search(primary_keys, table_key, db); // Note that if result == NULL (no such row), we still add that query to the txn read set (to allow txn to be invalidated by "shadow writes") int ret = add_row_read_to_txn(primary_keys, no_primary_keys, table_key, result, ts, fastrandstate); assert(ret == 0); return result; } int db_range_search_in_txn(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, snode_t** start_row, snode_t** end_row, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn int no_rows = db_range_search(start_primary_keys, end_primary_keys, start_row, end_row, table_key, db); // Note that if no_rows == 0 (no rows read), we still add that query to the txn read set (to allow txn to be invalidated by "shadow writes") return add_row_range_read_to_txn(start_primary_keys, end_primary_keys, no_primary_keys, table_key, *start_row, *end_row, no_rows, ts, fastrandstate); } db_row_t* db_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NULL; // No such txn db_row_t* result = db_search_clustering(primary_keys, clustering_keys, no_clustering_keys, table_key, db); // Note that if result == NULL (no such row), we still add that query to the txn read set (to allow txn to be invalidated by "shadow writes") int ret = add_cell_read_to_txn(primary_keys, no_primary_keys, clustering_keys, no_clustering_keys, table_key, result, ts, fastrandstate); assert(ret == 0); return result; } int db_range_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, snode_t** start_row, snode_t** end_row, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn // Note that if ret == 0 (no rows read), we still add that query to the txn read set (to allow txn to be invalidated by "shadow writes") int no_results = db_range_search_clustering(primary_keys, start_clustering_keys, end_clustering_keys, no_clustering_keys, start_row, end_row, table_key, db); return add_cell_range_read_to_txn(primary_keys, no_primary_keys, start_clustering_keys, end_clustering_keys, no_clustering_keys, table_key, *start_row, *end_row, no_results, ts, fastrandstate); } // WORD* db_search_columns_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int* column_idxs, int no_columns, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) db_row_t* db_search_columns_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD* col_keys, int no_columns, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { assert (0); // This won't work until db_search_columns is refactored as per below: return 0; /* txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn // db_search_columns(primary_keys, clustering_keys, int* column_idxs, no_columns, table_key, db_t * db); db_row_t* result = db_search_columns_result(primary_keys, clustering_keys, col_keys, no_columns, table_key, db); return add_col_read_to_txn(primary_keys, no_primary_keys, clustering_keys, no_clustering_keys, col_keys, no_columns, table_key, result, ts, fastrandstate); */ } db_row_t* db_search_index_in_txn(WORD index_key, int idx_idx, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NULL; // No such txn db_row_t* result = db_search_index(index_key, idx_idx, table_key, db); int ret = add_index_read_to_txn(&index_key, idx_idx, table_key, result, ts, fastrandstate); assert(ret == 0); return result; } int db_range_search_index_in_txn(int idx_idx, WORD start_idx_key, WORD end_idx_key, snode_t** start_row, snode_t** end_row, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn int no_results = db_range_search_index(idx_idx, start_idx_key, end_idx_key, start_row, end_row, table_key, db); return add_index_range_read_to_txn(idx_idx, &start_idx_key, &end_idx_key, *start_row, *end_row, no_results, table_key, ts, fastrandstate); } int db_delete_row_in_txn(WORD* primary_keys, int no_primary_keys, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn return add_write_to_txn(QUERY_TYPE_DELETE, primary_keys, no_primary_keys, no_primary_keys, 0, 0, table_key, ts, fastrandstate); } int db_delete_cell_in_txn(WORD* keys, int no_primary_keys, int no_clustering_keys, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn return add_write_to_txn(QUERY_TYPE_DELETE, keys, no_primary_keys+no_clustering_keys, no_primary_keys, no_clustering_keys, 0, table_key, ts, fastrandstate); } int db_delete_by_index_in_txn(WORD index_key, int idx_idx, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { assert (0); // Not supported yet return 0; } int db_update_in_txn(int * col_idxs, int no_cols, size_t blob_size, WORD * column_values, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { assert (0); // Not supported in new schema-less model return 0; } // Queue ops: int enqueue_in_txn(WORD * column_values, int no_cols, size_t blob_size, WORD table_key, WORD queue_id, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn return add_enqueue_to_txn(column_values, no_cols, blob_size, table_key, queue_id, ts, fastrandstate); } int read_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int max_entries, int * entries_read, int64_t * new_read_head, snode_t** start_row, snode_t** end_row, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn int64_t prev_read_head = -1; // Lookup previously existing read head in this txn's read set: for(snode_t * write_op_n=HEAD(ts->write_set); write_op_n!=NULL; write_op_n=NEXT(write_op_n)) { if(write_op_n->value != NULL) { txn_write * tw = (txn_write *) write_op_n->value; if(tw->query_type == QUERY_TYPE_READ_QUEUE && tw->table_key == table_key && tw->queue_id == queue_id && tw->consumer_id == consumer_id && tw->shard_id == shard_id && tw->app_id == app_id) { prev_read_head = tw->new_read_head; break; } } } vector_clock * prh_version = NULL; int status = peek_queue(consumer_id, shard_id, app_id, table_key, queue_id, max_entries, prev_read_head, entries_read, new_read_head, &prh_version, start_row, end_row, db); int ret = add_read_queue_to_txn(consumer_id, shard_id, app_id, table_key, queue_id, *new_read_head, prh_version, ts, fastrandstate); return (ret==0)?(status):(ret); } int consume_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn return add_consume_queue_to_txn(consumer_id, shard_id, app_id, table_key, queue_id, new_consume_head, ts, fastrandstate); } int subscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { assert (0); // Not implemented return 0; } int unsubscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { assert (0); // Not implemented return 0; } int create_queue_in_txn(WORD table_key, WORD queue_id, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn return add_create_queue_to_txn(table_key, queue_id, ts, fastrandstate); } int delete_queue_in_txn(WORD table_key, WORD queue_id, uuid_t * txnid, db_t * db, unsigned int * fastrandstate) { txn_state * ts = get_txn_state(txnid, db); if(ts == NULL) return NO_SUCH_TXN; // No such txn return add_delete_queue_to_txn(table_key, queue_id, ts, fastrandstate); } ================================================ FILE: backend/txns.h ================================================ /* * txns.h * * Author: aagapi */ #ifndef BACKEND_TXNS_H_ #define BACKEND_TXNS_H_ #include "txn_state.h" #include "queue.h" #define VAL_STATUS_COMMIT 0 #define VAL_STATUS_ABORT 1 #define DUPLICATE_TXN -2 #define NO_SUCH_TXN -3 // DB queries: txn_state * get_txn_state(uuid_t * txnid, db_t * db); uuid_t * new_txn(db_t * db, unsigned int * seedptr); int close_txn(uuid_t * txnid, db_t * db); int close_txn_state(txn_state * ts, db_t * db); int validate_txn(uuid_t * txnid, vector_clock * version, db_t * db); int abort_txn(uuid_t * txnid, db_t * db); int commit_txn(uuid_t * txnid, vector_clock * version, db_t * db, unsigned int * fastrandstate); int db_insert_in_txn(WORD * column_values, int no_cols, int no_primary_keys, int no_clustering_keys, size_t blob_size, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); db_row_t* db_search_in_txn(WORD* primary_keys, int no_primary_keys, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); db_row_t* db_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); db_row_t* db_search_columns_in_txn(WORD* primary_keys, int no_primary_keys, WORD* clustering_keys, int no_clustering_keys, WORD* col_keys, int no_columns, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); db_row_t* db_search_index_in_txn(WORD index_key, int idx_idx, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int db_range_search_in_txn(WORD* start_primary_keys, WORD* end_primary_keys, int no_primary_keys, snode_t** start_row, snode_t** end_row, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int db_range_search_clustering_in_txn(WORD* primary_keys, int no_primary_keys, WORD* start_clustering_keys, WORD* end_clustering_keys, int no_clustering_keys, snode_t** start_row, snode_t** end_row, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int db_range_search_index_in_txn(int idx_idx, WORD start_idx_key, WORD end_idx_key, snode_t** start_row, snode_t** end_row, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int db_delete_row_in_txn(WORD* primary_keys, int no_primary_keys, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int db_delete_cell_in_txn(WORD* keys, int no_primary_keys, int no_clustering_keys, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int db_delete_by_index_in_txn(WORD index_key, int idx_idx, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int db_update_in_txn(int * col_idxs, int no_cols, size_t blob_size, WORD * column_values, WORD table_key, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); // Queue ops: int enqueue_in_txn(WORD * column_values, int no_cols, size_t blob_size, WORD table_key, WORD queue_id, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int read_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int max_entries, int * entries_read, int64_t * new_read_head, snode_t** start_row, snode_t** end_row, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int consume_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, int64_t new_consume_head, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int subscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, queue_callback * callback, int64_t * prev_read_head, int64_t * prev_consume_head, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int unsubscribe_queue_in_txn(WORD consumer_id, WORD shard_id, WORD app_id, WORD table_key, WORD queue_id, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int create_queue_in_txn(WORD table_key, WORD queue_id, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); int delete_queue_in_txn(WORD table_key, WORD queue_id, uuid_t * txnid, db_t * db, unsigned int * fastrandstate); // Lower level API: int persist_write(txn_write * tw, vector_clock * version, db_t * db, unsigned int * fastrandstate); int persist_txn(txn_state * ts, db_t * db, unsigned int * fastrandstate); #endif /* BACKEND_TXNS_H_ */ ================================================ FILE: base/.gitignore ================================================ ================================================ FILE: base/Build.act ================================================ name = "base" fingerprint = 0xc0b4fe61c0b4fe61 dependencies = { "actondb": ( path="../backend/" ) } zig_dependencies = { "libbsdnt": ( path="../deps/libbsdnt/" ), "libgc": ( path="../deps/libgc/" ), "libmbedtls": ( path="../deps/mbedtls/" ), "libnetstring": ( path="../deps/libnetstring/" ), "libpcre2": ( path="../deps/pcre2/" ), "libprotobuf_c": ( path="../deps/libprotobuf_c/" ), "libsnappy": ( path="../deps/libsnappy_c/" ), "libtlsuv": ( path="../deps/tlsuv/" ), "libutf8proc": ( path="../deps/libutf8proc/" ), "libuuid": ( path="../deps/libuuid/" ), "libuv": ( path="../deps/libuv/" ), "libxml2": ( path="../deps/libxml2/" ), "libyyjson": ( path="../deps/libyyjson/" ) } ================================================ FILE: base/CLAUDE.md ================================================ # Acton Base - Standard Library & Runtime System The base directory contains the Acton standard library and runtime system (RTS), providing core functionality for all Acton programs. ## Quick Reference ### Directory Structure ``` base/ ├── src/ # Standard library modules (Acton) ├── builtin/ # Builtin types implementation (C) ├── rts/ # Runtime system (C/Zig) ├── stdlib/ # Additional stdlib components ├── build.zig # Build configuration └── Build.act # Package definition ``` ### Build Commands ```bash # Build base (included in main build) make # Run stdlib tests make test-stdlib # Build specific module cd base && zig build ``` ## Standard Library Modules (`src/`) ### Core Modules #### `__builtin__.act` - Fundamental types and functions - Imported implicitly in all modules - Interfaces to C builtins #### `file.act` / `file.ext.c` - File I/O operations - Path manipulation - Directory operations #### `net.act` / `net.ext.c` - TCP/UDP networking - DNS resolution - Socket operations #### `process.act` / `process.ext.c` - Process spawning - Environment variables - Signal handling #### `time.act` / `time.ext.c` - Time operations - Sleep/delay functions - Time formatting ### Data Processing #### `json.act` / `json.ext.c` - JSON parsing and generation - Type-safe JSON handling #### `xml.act` / `xml.ext.c` - XML parsing - DOM manipulation #### `base64.act` / `base64.ext.c` - Base64 encoding/decoding ### Advanced Modules #### `http.act` - HTTP client/server - Request/response handling - WebSocket support #### `re.act` / `re.ext.c` - Regular expressions - Pattern matching - String substitution #### `numpy.act` / `numpy.c` - Numerical arrays - Mathematical operations - Compatible subset of NumPy ## Builtin Types (`builtin/`) ### Type Implementation Pattern Each builtin type typically has: ```c // type_name.h - Header with struct definition typedef struct { // ... internal representation } ActonType; // type_name.c - Implementation // - Constructor functions // - Method implementations // - Protocol implementations // - Memory management ``` ### Core Types #### Numeric Types - `int.c/h` - Arbitrary precision integers - `float.c/h` - 64-bit floating point - `complex.c/h` - Complex numbers - `i16.c/h`, `i32.c/h`, `i64.c/h` - Fixed-size integers - `u16.c/h`, `u32.c/h`, `u64.c/h` - Unsigned integers #### Collections - `list.c/h` - Dynamic arrays - `dict.c/h` - Hash maps - `set.c/h` - Hash sets - `tuple.c/h` - Immutable sequences #### Text and Binary - `str.c/h` - Unicode strings - `bytes.c/h` - Binary data ### Memory Management All builtin types follow Acton's memory model: - Reference counting with cycle detection - Automatic memory management - C integration points ## Runtime System (`rts/`) ### Core Components #### `rts.c/h` - Main runtime initialization - Actor system setup - Scheduler initialization #### `q.c/h` - Actor message queues - Lock-free implementations - Message routing #### `io.c/h` - Async I/O with libuv - File descriptors - Network operations #### `gc.zig` - Garbage collector - Reference counting - Cycle detection ### Actor Runtime - Lightweight actors - Message passing - Scheduling - Distribution support ## Adding Standard Library Modules ### 1. Pure Acton Module ```acton # src/mymodule.act def my_function(x: int) -> int: return x * 2 class MyClass: def method(self) -> str: return "hello" ``` ### 2. Module with C Extension ```acton # src/mymodule.act # C functions are declared as external def native_function(x: int) -> int: NotImplemented ``` ```c // src/mymodule.ext.c #include B_int native_function(B_int x) { return intFromInt(asInt(x) * 2); } ``` ### 3. Update Configuration ```toml # base/Build.act [dependencies] mymodule = { path = "src/mymodule.act" } ``` ## Working with Builtins ### Adding Methods to Builtin Types 1. **Declare in Acton** (`__builtin__.act`): ```acton extension list[T]: def my_new_method(self) -> T: NotImplemented ``` 2. **Implement in C** (`list.c`): ```c B_value list_my_new_method(B_list self) { // Implementation return result; } ``` 3. **Register Method** (`list.c`): ```c static struct method_entry list_methods[] = { {"my_new_method", (void*)list_my_new_method}, // ... }; ``` ### Memory Management in C Extensions ```c // Allocate Acton object B_str result = (B_str)GC_MALLOC(sizeof(struct B_str)); result->_class = &str_class; // Reference counting INCREF(obj); // Increase reference DECREF(obj); // Decrease reference // Conversion helpers int64_t val = asInt(acton_int); B_int result = intFromInt(val); ``` ## Testing ### Unit Tests - Place in `test/stdlib_auto/` - Naming: `test_module.act` - Auto-discovered by test runner ### C Extension Tests - Test through Acton interface - Use `testing` module assertions - Verify memory management ### Performance Tests - Use `test/perf/` for benchmarks - Compare against Python/C baselines - Track regression ## Common Patterns ### Async Operations ```c // In .ext.c file void async_operation(B_actor self, B_callback cb) { // Start async work uv_work_t *req = malloc(sizeof(uv_work_t)); req->data = cb; uv_queue_work(uv_default_loop(), req, do_work, after_work); } ``` ### Error Handling ```c // Throw Acton exception from C if (error_condition) { B_raise(B_ValueError, "Error message"); return NULL; } ``` ### Protocol Implementation ```c // Implement protocol for type static B_bool str_eq(B_str self, B_value other) { if (other->_class != &str_class) return B_False; return strcmp(self->data, ((B_str)other)->data) == 0 ? B_True : B_False; } ``` ## Performance Guidelines 1. **String Operations** - Use views when possible - Avoid unnecessary copies - Cache length calculations 2. **Collections** - Preallocate when size known - Use appropriate data structure - Consider memory locality 3. **I/O Operations** - Always async in actors - Buffer when appropriate - Use libuv efficiently ## Debugging ### Print Debugging ```c // In C extensions fprintf(stderr, "Debug: value=%ld\n", asInt(val)); // Force flush fflush(stderr); ``` ### GDB ```bash # Run with GDB gdb ./program (gdb) break function_name (gdb) run ``` ### Memory Debugging - Use Valgrind for leaks - Enable GC debugging - Check reference counts ## Integration Notes - Standard library available to all Acton programs - Modules lazy-loaded on import - C extensions loaded dynamically - Type information preserved at runtime ================================================ FILE: base/__root.zig ================================================ const std = @import("std"); const acton = @import("acton.zig"); const gc = @import("rts/gc.zig"); export fn base64Q_encode(data: *acton.bytes) callconv(.c) *acton.bytes { const alloc = gc.allocator(); const encoder = std.base64.standard.Encoder; // For possible Unicode input, bytes and chars may not be 1:1 const data_len: usize = @intCast(data.nbytes); const out_len = encoder.calcSize(data_len); const buffer = alloc.alloc(u8, out_len) catch @panic("OOM"); const data_slice = data.str[0..data_len]; const encoded = encoder.encode(buffer, data_slice); const res = alloc.create(acton.bytes) catch @panic("OOM"); res.* = .{ .class = data.class, .nbytes = @intCast(out_len), .str = @as([*:0]const u8, @ptrCast(encoded.ptr)) }; return res; } export fn base64Q_decode(data: *acton.bytes) callconv(.c) *acton.bytes { const alloc = gc.allocator(); const decoder = std.base64.standard.Decoder; // Convert null-terminated string to slice for decoder const data_len: usize = @intCast(data.nbytes); const data_slice = data.str[0..data_len]; // And then compute the exact number of bytes we need to decode, without padding const out_len = decoder.calcSizeForSlice(data_slice) catch { acton.raise_ValueError("Invalid base64 input data"); unreachable; // raise above does longjmp so this is unreachable }; const buffer = alloc.alloc(u8, out_len) catch @panic("OOM"); decoder.decode(buffer, data_slice) catch unreachable; const res = alloc.create(acton.bytes) catch @panic("OOM"); res.* = .{ .class = data.class, .nbytes = @intCast(out_len), .str = @as([*:0]const u8, @ptrCast(buffer.ptr)) }; return res; } export fn zig_crypto_hash_md5_init() callconv(.c) *std.crypto.hash.Md5 { const alloc = gc.allocator(); const hasher_ptr = alloc.create(std.crypto.hash.Md5) catch { unreachable("OOM while allocating Md5 hasher"); }; hasher_ptr.* = std.crypto.hash.Md5.init(.{}); return hasher_ptr; } export fn zig_crypto_hash_md5_update(hasher: *std.crypto.hash.Md5, data: *acton.bytes) callconv(.c) void { const len: usize = @intCast(data.nbytes); // destination type from context const slice = data.str[0..len]; hasher.update(slice); } export fn zig_crypto_hash_md5_finalize(hasher: *std.crypto.hash.Md5, output: *acton.bytes) callconv(.c) void { const digest_len = 16; const out_slice: *[16]u8 = @as([*]u8, @ptrCast(@constCast(output.str)))[0..digest_len]; hasher.final(out_slice); } export fn zig_hash_wyhash_init(seed: u64) callconv(.c) *std.hash.Wyhash { const alloc = gc.allocator(); const hasher_ptr = alloc.create(std.hash.Wyhash) catch { acton.raise_MemoryError("OOM while allocating Wyhash hasher"); unreachable; // raise above does longjmp so this is unreachable }; hasher_ptr.* = std.hash.Wyhash.init(seed); return hasher_ptr; } export fn zig_hash_wyhash_update(hasher: *std.hash.Wyhash, data: *acton.bytes) callconv(.c) void { const len: usize = @intCast(data.nbytes); // destination type from context const slice = data.str[0..len]; hasher.update(slice); } export fn zig_hash_wyhash_final(hasher: *std.hash.Wyhash) callconv(.c) u64 { return hasher.final(); } export fn zig_hash_wyhash_hash(seed: u64, data: *acton.bytes) callconv(.c) u64 { const len: usize = @intCast(data.nbytes); // destination type from context const slice = data.str[0..len]; return std.hash.Wyhash.hash(seed, slice); } ================================================ FILE: base/acton.zig ================================================ const std = @import("std"); const expect = std.testing.expect; const c_acton = @cImport({ @cInclude("builtin/builtin.h"); }); const gc = @import("rts/gc.zig"); // B_bytes pub const bytes = extern struct { class: usize, nbytes: i32, // length of str in bytes str: [*]const u8 // str is UTF-8 encoded. }; // B_NoneType pub const none = extern struct { class: usize, }; // B_str pub const str = extern struct { class: usize, nbytes: i32, // length of str in bytes nchars: i32, // length of str in Unicode chars str: [*:0]const u8 // str is UTF-8 encoded. }; // B_ValueError pub const ValueError = extern struct { class: *c_acton.B_ValueErrorG_class, error_message: c_acton.B_str, }; // This is the equivalent of the expanded macro in C: // $NEW(B_ValueError,to$str(message)) pub fn new_ValueError(message: []const u8) *c_acton.B_ValueError { const alloc = gc.allocator(); const error_ptr = alloc.create(ValueError) catch @panic("OOM"); const c_error_message = @constCast(message.ptr); const error_message_ptr = c_acton.to_str_noc(c_error_message); error_ptr.* = .{ .class = @ptrCast(&c_acton.B_ValueErrorG_methods), .error_message = null }; if (error_ptr.class.__init__) |init_fn| { _ = init_fn(@ptrCast(error_ptr), error_message_ptr); } return @ptrCast(error_ptr); } // This is the equivalent of the function call in C: // $RAISE((B_BaseException)$NEW(B_ValueError,to$str(message))) pub fn raise_ValueError(message: []const u8) void { const error_ptr = new_ValueError(message); // @ptrCast is used to cast the pointer to the correct type expected by the C function c_acton.@"$RAISE"(@ptrCast(error_ptr)); // RAISE does not return, it does a longjmp, so this code is unreachable unreachable; } // B_MemoryError pub const MemoryError = extern struct { class: *c_acton.B_MemoryErrorG_class, error_message: c_acton.B_str, }; // This is the equivalent of the expanded macro in C: // $NEW(B_MemoryError,to$str(message)) pub fn new_MemoryError(message: []const u8) *c_acton.B_MemoryError { const alloc = gc.allocator(); const error_ptr = alloc.create(MemoryError) catch @panic("OOM"); const c_error_message = @constCast(message.ptr); const error_message_ptr = c_acton.to_str_noc(c_error_message); error_ptr.* = .{ .class = @ptrCast(&c_acton.B_MemoryErrorG_methods), .error_message = null }; if (error_ptr.class.__init__) |init_fn| { _ = init_fn(@ptrCast(error_ptr), error_message_ptr); } return @ptrCast(error_ptr); } // This is the equivalent of the function call in C: // $RAISE((B_BaseException)$NEW(B_MemoryError,to$str(message))) pub fn raise_MemoryError(message: []const u8) void { const error_ptr = new_MemoryError(message); // @ptrCast is used to cast the pointer to the correct type expected by the C function c_acton.@"$RAISE"(@ptrCast(error_ptr)); // RAISE does not return, it does a longjmp, so this code is unreachable unreachable; } test "str struct" { // Check that our struct is the same size as the C struct, by using @typeInfo // B_str is a pointer to a C struct, so we need to "dereference" the pointer // type to get to the struct type, then check the size of the nbytes field switch (@typeInfo(c_acton.B_str)) { .Pointer => |info| switch (info.size) { .C => switch (@typeInfo(info.child)) { .Struct => |child_info| { inline for (child_info.fields) |field| { //std.debug.print("struct B_str field: {s} size: {d}\n", .{field.name, @sizeOf(field.type)}); if (std.mem.eql(u8, field.name, "nbytes")) { try expect(@sizeOf(field.type) == 4); } if (std.mem.eql(u8, field.name, "nchars")) { try expect(@sizeOf(field.type) == 4); } } }, else => { @compileError("Unhandled type: {s}" ++ @typeName(info.child)); } }, else => { @compileError("Unhandled type:"); } }, else => std.debug.print("unexpected type\n", .{}), } try expect(@sizeOf(str) == 24); // 8 + 4 + 4 + 8 // std.debug.print("size of str: {d}\n", .{ @sizeOf(str) }); // std.debug.print("size of B_str: {d}\n", .{ @sizeOf(B_str) }); // std.debug.print("size of imported c_acton.B_str: {d}\n", .{ @sizeOf(c_acton.B_str.*) }); //try expect(@sizeOf(c_acton.B_str) == 8); //try expect(@sizeOf(str) == @sizeOf(c_acton.B_str)); } ================================================ FILE: base/builtin/Iterator.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ B_Iterator B_IterableD_IteratorD___iter__(B_IterableD_Iterator wit, B_Iterator self) { return self; } $WORD $next(B_Iterator it) { return it->$class->__next__(it); } ================================================ FILE: base/builtin/Iterator.h ================================================ $WORD $next(B_Iterator); ================================================ FILE: base/builtin/atom.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ struct B_atomG_class B_atomG_methods = { "B_atom", UNASSIGNED, ($SuperG_class)&B_valueG_methods }; ================================================ FILE: base/builtin/atom.h ================================================ extern struct B_atomG_class B_atomG_methods; ================================================ FILE: base/builtin/bigint.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define GC_THREADS 1 #include "gc.h" // General methods /////////////////////////////////////////////////////////////////////// int set_str(zz_ptr a, unsigned char *str, B_int intbase); B_bigint malloc_bigint() { B_bigint res = acton_malloc(sizeof(struct B_bigint)); res->$class = &B_bigintG_methods; res->val.n = acton_malloc_atomic(sizeof(unsigned long)); res->val.size = 0; res->val.alloc = 1; return res; } void zz_malloc_fit(zz_ptr res, len_t m) { res->n = acton_malloc_atomic(sizeof(unsigned long) * m); res->size = 0; res->alloc = m; } B_bigint B_IntegralD_bigintD___lshift__(B_IntegralD_bigint wit, B_bigint a, B_int b); B_bigint B_bigintG_new(B_atom a, B_int base) { if (base) { if ($ISINSTANCE0(a,B_str)) { B_bigint res = malloc_bigint(); res->$class = &B_bigintG_methods; set_str(&res->val, ((B_str)a)->str, base); return res; } else { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "integer type constructor: base argument is only allowed when converting from a str"); $RAISE($NEW(B_BaseException,to$str(errmsg))); } } if ($ISINSTANCE0(a,B_bigint)) return (B_bigint)a; if ($ISINSTANCE0(a,B_int)) { return toB_bigint(((B_int)a)->val); } if ($ISINSTANCE0(a,B_i32)) { return toB_bigint((long)((B_i32)a)->val); } if ($ISINSTANCE0(a,B_i16)) { return toB_bigint((long)((B_i16)a)->val); } if ($ISINSTANCE0(a,B_i8)) { return toB_bigint((long)((B_i8)a)->val); } if ($ISINSTANCE0(a,B_u64)) { unsigned long v = ((B_u64)a)->val; if (v==0) return toB_bigint(0L); else { B_bigint res = malloc_bigint(); res->val.size=1; res->val.n[0] = v; return res; } } if ($ISINSTANCE0(a,B_u32)) { unsigned int v = ((B_u32)a)->val; if (v==0) return toB_bigint(0L); else { B_bigint res = malloc_bigint(); res->val.size=1; res->val.n[0] = (unsigned long)v; return res; } } if ($ISINSTANCE0(a,B_u16)) { unsigned short v = ((B_u16)a)->val; if (v==0) return toB_bigint(0L); else { B_bigint res = malloc_bigint(); res->val.size=1; res->val.n[0] = (unsigned long)v; return res; } } if ($ISINSTANCE0(a,B_u8)) { unsigned char v = ((B_u8)a)->val; if (v==0) return toB_bigint(0L); else { B_bigint res = malloc_bigint(); res->val.size=1; res->val.n[0] = (unsigned long)v; return res; } } if ($ISINSTANCE0(a,B_u1)) { unsigned char v = ((B_u8)a)->val; if (v==0) return toB_bigint(0L); else { B_bigint res = malloc_bigint(); res->val.size=1; res->val.n[0] = (unsigned long)v; return res; } } if ($ISINSTANCE0(a,B_float)) { double aval = ((B_float)a)->val; int e; double m = frexp(aval,&e); if (e>52) { B_bigint c = toB_bigint((long)(m*4503599627370496.0)); // (1<< 52); B_int d = toB_int(e-52); return B_IntegralD_bigintD___lshift__(NULL,c,d); } else { long al = (long)aval; B_bigint res = toB_bigint(al); return res; } } if ($ISINSTANCE0(a,B_bool)) return toB_bigint(((B_bool)a)->val); if ($ISINSTANCE0(a,B_str)) { B_bigint res = malloc_bigint(); res->$class = &B_bigintG_methods; set_str(&res->val, ((B_str)a)->str, base); return res; } fprintf(stderr,"internal error: B_bigintG_new: argument not of atomic type\n"); exit(-1); } B_NoneType B_bigintD___init__(B_bigint self, B_atom a, B_int base){ self->val = B_bigintG_new(a,base)->val; return B_None; } void B_bigintD___serialize__(B_bigint self,$Serial$state state) { B_bigint prevkey = (B_bigint)B_dictD_get(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,NULL); if (prevkey) { long pk = fromB_bigint(prevkey); $val_serialize(-INT_ID,&pk,state); return; } B_dictD_setitem(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,toB_bigint(state->row_no)); int blobsize = 1 + labs(self->val.size); $ROW row = $add_header(INT_ID,blobsize,state); row->blob[0] = ($WORD)self->val.size; memcpy(&row->blob[1],self->val.n,labs(self->val.size)*sizeof(long)); } B_bigint B_bigintD___deserialize__(B_bigint res,$Serial$state state) { $ROW this = state->row; state->row = this->next; state->row_no++; if (this->class_id < 0) { return (B_bigint)B_dictD_get(state->done,(B_Hashable)B_HashableD_intG_witness,toB_bigint((long)this->blob[0]),NULL); } else { if (!res) res = malloc_bigint(); res->val.size = (long)this->blob[0]; res->val.alloc = labs(res->val.size); res->val.n = acton_malloc(res->val.alloc*sizeof(long)); memcpy(res->val.n,&this->blob[1],res->val.alloc*sizeof(long)); B_dictD_setitem(state->done,(B_Hashable)B_HashableD_intG_witness,toB_bigint(state->row_no-1),res); res->$class = &B_bigintG_methods; return res; } } B_bool B_bigintD___bool__(B_bigint n) { return toB_bool(zz_cmpi(&n->val,0)); } B_str B_bigintD___str__(B_bigint n) { return to_str_noc(get_str(&n->val)); } B_str B_bigintD___repr__(B_bigint n) { return to_str_noc(get_str(&n->val)); } /* B_bigint zz$toB_bigint(zz_ptr n) { B_bigint res = malloc_bigint(); res->$class = &B_bigintG_methods; res->val.n = n->n; res->val.size = n->size; res->val.alloc = n->alloc; return res; } */ // B_IntegralD_bigint ///////////////////////////////////////////////////////////////////////// B_bigint B_IntegralD_bigintD___add__(B_IntegralD_bigint wit, B_bigint a, B_bigint b) { B_bigint res = malloc_bigint(); zz_add(&res->val,&a->val,&b->val); return res; } B_bigint B_IntegralD_bigintD___zero__(B_IntegralD_bigint wit) { return toB_bigint(0); } B_complex B_IntegralD_bigintD___complex__(B_IntegralD_bigint wit, B_bigint a) { $RAISE((B_BaseException)$NEW(B_NotImplementedError, to$str("Number.__complex__ not implemented for int"))); return NULL; // This is just to silence compiler warning, above RAISE will longjmp from here anyway } B_bigint B_IntegralD_bigintD___fromatom__(B_IntegralD_bigint wit, B_atom a) { return B_bigintG_new(a,NULL); } B_bigint B_IntegralD_bigintD___mul__(B_IntegralD_bigint wit, B_bigint a, B_bigint b) { B_bigint res = malloc_bigint(); zz_mul(&res->val,&a->val,&b->val); return res; } B_bigint B_IntegralD_bigintD___pow__(B_IntegralD_bigint wit, B_bigint a, B_bigint b) { zz_ptr val_b = &b->val; if (zz_cmpi(val_b,0) < 0) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "int.__pow__(): negative exponent: %s", get_str(val_b)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } if (zz_cmpi(val_b,LONG_MAX) > 0) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "int.__pow__(): exponent out of range (>LONG_MAX): %s", get_str(val_b)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } B_bigint res = malloc_bigint(); if (val_b->size == 0) zz_seti(&res->val, 1); else zz_powi(&res->val,&a->val,val_b->n[0]); // __pow__ should have an int64 exponent in the Acton protocol return res; } B_bigint B_IntegralD_bigintD___neg__(B_IntegralD_bigint wit, B_bigint a) { B_bigint res = malloc_bigint(); zz_neg(&res->val,&a->val); return res; } B_bigint B_IntegralD_bigintD___pos__(B_IntegralD_bigint wit, B_bigint a) { return a; } $WORD B_IntegralD_bigintD_real(B_IntegralD_bigint wit, B_bigint a, B_Real wit2) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("Number.__real__ not implemented for int"))); return NULL; // This is just to silence compiler warning, above RAISE will longjmp from here anyway } $WORD B_IntegralD_bigintD_imag(B_IntegralD_bigint wit, B_bigint a, B_Real wit2) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("Number.__imag__ not implemented for int"))); return NULL; // This is just to silence compiler warning, above RAISE will longjmp from here anyway } $WORD B_IntegralD_bigintD___abs__(B_IntegralD_bigint wit, B_bigint a, B_Real wit2) { B_bigint res = malloc_bigint(); zz_set(&res->val,&a->val); res->val.size = labs(a->val.size); return wit2->$class->__fromatom__(wit2,(B_atom)res); } B_bigint B_IntegralD_bigintD_conjugate(B_IntegralD_bigint wit, B_bigint a) { return a; } B_float B_IntegralD_bigintD___float__ (B_IntegralD_bigint wit, B_bigint n) { return B_floatG_new((B_atom)n); } $WORD B_IntegralD_bigintD___trunc__ (B_IntegralD_bigint wit, B_bigint n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_bigintD___floor__ (B_IntegralD_bigint wit, B_bigint n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_bigintD___ceil__ (B_IntegralD_bigint wit, B_bigint n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } B_bigint B_IntegralD_bigintD___floordiv__(B_IntegralD_bigint wit, B_bigint a, B_bigint b); B_bigint B_IntegralD_bigintD___round__ (B_IntegralD_bigint wit, B_bigint n, B_int p) { zz_struct nval = n->val; if (nval.size < 0) { B_bigint n1 = malloc_bigint(); zz_neg(&n1->val,&nval); B_bigint res = B_IntegralD_bigintD___round__(wit,n1,p); zz_neg(&res->val,&res->val); return res; } long pval = fromB_int(p); if (pval>=0) return n; B_bigint p10 = B_IntegralD_bigintD___pow__(NULL,toB_bigint(10), B_IntegralD_bigintD___neg__(NULL,toB_bigint(p->val))); B_bigint p10half = B_IntegralD_bigintD___floordiv__(NULL, p10,toB_bigint(2)); B_bigint n1 = B_IntegralD_bigintD___floordiv__(NULL,B_IntegralD_bigintD___add__(NULL,n,p10half),p10); return B_IntegralD_bigintD___mul__(NULL,n1,p10); } $WORD B_IntegralD_bigintD_numerator (B_IntegralD_bigint wit, B_bigint n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_bigintD_denominator (B_IntegralD_bigint wit, B_bigint n, B_Integral wit2) { B_bigint res = toB_bigint(1L); return wit2->$class->__fromatom__(wit2,(B_atom)res); } B_int B_IntegralD_bigintD___int__ (B_IntegralD_bigint wit, B_bigint n) { unsigned long k = n->val.n[0]; long sz = n->val.size; if (labs(sz) > 1 || (sz==1 && k > 0x7ffffffffffffffful) || sz == -1 && k > 0x8000000000000000ul) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "bigint.__int__: value %s out of range for type int",get_str(&n->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_int(k*sz); } B_int B_IntegralD_bigintD___index__ (B_IntegralD_bigint wit, B_bigint n) { unsigned long k = n->val.n[0]; long sz = n->val.size; if (labs(sz) > 1 || (sz==1 && k > 0x7ffffffffffffffful) || sz == -1 && k > 0x8000000000000000ul) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "bigint.__index__: value %s out of range for type int",get_str(&n->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_int(k*sz); } B_tuple B_IntegralD_bigintD___divmod__(B_IntegralD_bigint wit, B_bigint a, B_bigint b) { if (b->val.size == 0){ char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "integer divmod: divisor is zero"); $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str(errmsg))); } B_bigint q = malloc_bigint(); B_bigint r = malloc_bigint(); zz_divrem(&q->val,&r->val,&a->val,&b->val); return $NEWTUPLE(2, q, r); } B_bigint B_IntegralD_bigintD___floordiv__(B_IntegralD_bigint wit, B_bigint a, B_bigint b) { if (b->val.size == 0){ char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "integer floordiv: divisor is zero"); $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str(errmsg))); } B_bigint res = malloc_bigint(); zz_div(&res->val,&a->val,&b->val); return res; } B_bigint B_IntegralD_bigintD___mod__(B_IntegralD_bigint wit, B_bigint a, B_bigint b) { B_tuple t = B_IntegralD_bigintD___divmod__(wit,a,b); return t->components[1]; } B_bigint B_IntegralD_bigintD___lshift__(B_IntegralD_bigint wit, B_bigint a, B_int b) { zz_struct aval = a->val; long ma = aval.size; long bval = fromB_int(b); if (ma==0 || bval==0) return a; if (bval<0) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "bigint.__lshift__: negative shift count: %ld", bval); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } long shw = bval/64; long shb = bval%64; long mres = labs(ma) + shw + (shb > 0); B_bigint res = malloc_bigint(); zz_ptr rval = &res->val; zz_malloc_fit(rval,mres); word_t ci = nn_shl(rval->n, aval.n, labs(ma), shb); rval->n[labs(ma)] = ci; if (shw>0) { for (int i = labs(ma)-1+(shb>0); i >= 0; i--) rval->n[i+shw] = rval->n[i]; for (int i = 0; i < shw; i++) rval->n[i] = 0; } mres = mres - (rval->n[mres-1]==0); mres = ma<0? -mres:mres; rval->size = mres; return res; } B_bigint B_IntegralD_bigintD___rshift__(B_IntegralD_bigint wit, B_bigint a, B_int b) { zz_struct aval = a->val; long ma = aval.size; long bval = fromB_int(b); if (ma==0 || bval==0) return a; if (bval<0) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "bigint.__rshift__: negative shift count: %ld", bval); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } B_bigint res = malloc_bigint(); zz_ptr rval = &res->val; long shw = bval/64; long shb = bval%64; long mres = labs(ma) - shw; zz_malloc_fit(rval,mres); unsigned long tmp[mres]; for (int i = 0; i < mres; i++) tmp[i] = aval.n[i+shw]; word_t ci = nn_shr(rval->n, tmp, mres, shb); mres = mres - (rval->n[mres-1]==0); mres = ma<0?-mres:mres; res->val.size = mres; return res; } B_bigint B_IntegralD_bigintD___invert__(B_IntegralD_bigint wit, B_bigint a) { B_bigint res0 = malloc_bigint(); B_bigint res = malloc_bigint(); B_bigint one = toB_bigint(1); zz_neg(&res0->val,&a->val); zz_sub(&res->val,&res0->val,&one->val); return res; } // LogicalB_bigint //////////////////////////////////////////////////////////////////////////////////////// // Converts src (which must be non-zero), to two's complement form, stored in dst. // src and dst may be the same address. void twocompl(unsigned long *dst, unsigned long *src, long len) { unsigned long carry = 1; for (int i = 0; i < len; i++) { unsigned long t = src[i] ^ ULONG_MAX; if (t < ULONG_MAX || carry == 0) { dst[i] = t + carry; carry = 0; } else { dst[i] = 0; } } } B_bigint B_LogicalD_IntegralD_bigintD___and__(B_LogicalD_IntegralD_bigint wit, B_bigint a, B_bigint b) { long aneg = a->val.size < 0; long bneg = b->val.size < 0; long asize = labs(a->val.size); long bsize = labs(b->val.size); if (bsize==0) return toB_bigint(0); if (asize==0) return toB_bigint(0); unsigned long *a1, *b1; if (aneg) { a1 = acton_malloc(asize*sizeof(long)); twocompl(a1, a->val.n, asize); } else a1 = a->val.n; if (bneg) { b1 = acton_malloc(bsize*sizeof(long)); twocompl(b1, b->val.n, bsize); } else b1 = b->val.n; long rneg = aneg & bneg; if (asize < bsize) { unsigned long *t = a1; a1 = b1; b1 = t; long tsize = asize; asize = bsize; bsize = tsize; long tneg = aneg; aneg = bneg; bneg = tneg; } B_bigint res = malloc_bigint(); // if both are positive, rsize = bsize // if one is positive, use that size // if both are negative, rsize = asize zz_malloc_fit(&res->val,bneg ? asize : bsize); res->val.size = 0; if (bneg) { for (int i = asize-1; i >= bsize; i--) { res->val.n[i] = a1[i]; if (res->val.size == 0 && res->val.n[i] != 0L) res->val.size = i+1; } } for (int i = bsize-1; i >= 0; i--) { res->val.n[i] = a1[i] & b1[i]; if (res->val.size == 0 && res->val.n[i] != 0L) res->val.size = i+1; } if (rneg) { twocompl(res->val.n, res->val.n, res->val.size); res->val.size = -res->val.size; } return res; } B_bigint B_LogicalD_IntegralD_bigintD___or__(B_LogicalD_IntegralD_bigint wit, B_bigint a, B_bigint b) { long aneg = a->val.size < 0; long bneg = b->val.size < 0; long asize = labs(a->val.size); long bsize = labs(b->val.size); if (bsize==0) return a; if (asize==0) return b; unsigned long *a1, *b1; if (aneg) { a1 = acton_malloc(asize*sizeof(long)); twocompl(a1, a->val.n, asize); } else a1 = a->val.n; if (bneg) { b1 = acton_malloc(bsize*sizeof(long)); twocompl(b1, b->val.n, bsize); } else b1 = b->val.n; long rneg = aneg | bneg; if (asize < bsize) { unsigned long *t = a1; a1 = b1; b1 = t; long tsize = asize; asize = bsize; bsize = tsize; long tneg = aneg; aneg = bneg; bneg = tneg; } B_bigint res = malloc_bigint(); zz_malloc_fit(&res->val,bneg ? bsize : asize); res->val.size = 0; if (!bneg) { for (int i = asize-1; i >= bsize; i--) { res->val.n[i] = a1[i]; if (res->val.size == 0 && res->val.n[i] != 0L) res->val.size = i+1; } } for (int i = bsize-1; i >= 0; i--) { res->val.n[i] = a1[i] | b1[i]; if (res->val.size == 0 && res->val.n[i] != 0L) res->val.size = i+1; } if (rneg) { twocompl(res->val.n, res->val.n, res->val.size); res->val.size = -res->val.size; } return res; } B_bigint B_LogicalD_IntegralD_bigintD___xor__(B_LogicalD_IntegralD_bigint wit, B_bigint a, B_bigint b) { long aneg = a->val.size < 0; long bneg = b->val.size < 0; long asize = labs(a->val.size); long bsize = labs(b->val.size); if (bsize==0) return a; if (asize==0) return b; unsigned long *a1, *b1; if (aneg) { a1 = acton_malloc(asize*sizeof(long)); twocompl(a1, a->val.n, asize); } else a1 = a->val.n; if (bneg) { b1 = acton_malloc(bsize*sizeof(long)); twocompl(b1, b->val.n, bsize); } else b1 = b->val.n; long rneg = aneg ^ bneg; if (asize < bsize) { unsigned long *t = a1; a1 = b1; b1 = t; long tsize = asize; asize = bsize; bsize = tsize; long tneg = aneg; aneg = bneg; bneg = tneg; } B_bigint res = malloc_bigint(); zz_malloc_fit(&res->val,asize); res->val.size = 0; for (int i = asize-1; i >= bsize; i--) { res->val.n[i] = bneg ? (~a1[i]) : a1[i]; if (res->val.size == 0 && res->val.n[i] != 0L) res->val.size = i+1; } for (int i = bsize-1; i >= 0; i--) { res->val.n[i] = a1[i] ^ b1[i]; if (res->val.size == 0 && res->val.n[i] != 0L) res->val.size = i+1; } if (rneg) { twocompl(res->val.n, res->val.n, res->val.size); res->val.size = -res->val.size; } return res; } // B_MinusD_IntegralD_bigint //////////////////////////////////////////////////////////////////////////////////////// B_bigint B_MinusD_IntegralD_bigintD___sub__(B_MinusD_IntegralD_bigint wit, B_bigint a, B_bigint b) { B_bigint res = malloc_bigint(); zz_sub(&res->val,&a->val,&b->val); return res; } // B_DivD_bigint //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_bigintD___truediv__ (B_DivD_bigint wit, B_bigint a, B_bigint b) { if (zz_equal(&b->val, &toB_bigint(0)->val)) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); zz_ptr aval = &a->val; zz_ptr bval = &b->val; B_bigint ared = malloc_bigint(); B_bigint bred = malloc_bigint(); B_bigint q = malloc_bigint(); B_bigint r = malloc_bigint(); B_bigint g = malloc_bigint(); zz_gcd(&g->val,aval,bval); zz_div(&ared->val,aval,&g->val); zz_div(&bred->val,bval,&g->val); zz_divrem(&q->val,&r->val,&ared->val,&bred->val); return to$float(B_floatG_new((B_atom)q)->val + B_floatG_new((B_atom)r)->val/ B_floatG_new((B_atom)bred)->val); } // B_OrdD_bigint //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_bigintD___eq__ (B_OrdD_bigint wit, B_bigint a, B_bigint b) { return toB_bool(zz_equal(&a->val,&b->val)); } B_bool B_OrdD_bigintD___ne__ (B_OrdD_bigint wit, B_bigint a, B_bigint b) { return toB_bool(1-zz_equal(&a->val,&b->val)); } B_bool B_OrdD_bigintD___lt__ (B_OrdD_bigint wit, B_bigint a, B_bigint b) { return toB_bool(zz_cmp(&a->val,&b->val) < 0); } B_bool B_OrdD_bigintD___le__ (B_OrdD_bigint wit, B_bigint a, B_bigint b) { return toB_bool(zz_cmp(&a->val,&b->val) <= 0); } B_bool B_OrdD_bigintD___gt__ (B_OrdD_bigint wit, B_bigint a, B_bigint b) { return toB_bool(zz_cmp(&a->val,&b->val) > 0); } B_bool B_OrdD_bigintD___ge__ (B_OrdD_bigint wit, B_bigint a, B_bigint b) { return toB_bool(zz_cmp(&a->val,&b->val) >= 0); } // B_HashableD_bigint /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_bigintD___eq__(B_HashableD_bigint wit, B_bigint a, B_bigint b) { return toB_bool(zz_equal(&a->val,&b->val)); } B_bool B_HashableD_bigintD___ne__(B_HashableD_bigint wit, B_bigint a, B_bigint b) { return toB_bool(1-zz_equal(&a->val,&b->val)); } B_NoneType B_HashableD_bigintD_hash(B_HashableD_bigint wit, B_bigint a, B_hasher h) { long sz = a->val.size; unsigned long data; if (sz==0) data = 0UL; else data = (long)a->val.n[0]; zig_hash_wyhash_update(h->_hasher,to$bytesD_len((char *)&data,8)); return B_None; } long fromB_bigint(B_bigint n) { long sz = n->val.size; if (sz==0) return 0; unsigned long res = n->val.n[0]; if (res > LONG_MAX || labs(sz) > 1) { fprintf(stderr,"internal error: overflow in converting int to bounded int\n"); exit(1); } return sz<0 ? -res : res; } B_bigint toB_bigint(long n) { if (n >= 0 && n < 256) return &B_bigint_strs[n]; else { B_bigint res = malloc_bigint(); res->val.n[0] = n > 0 ? n : (n == LONG_MIN ? 9223372036854775808UL : -n); res->val.size = n < 0 ? -1 : n > 0; return res; } } B_bigint toB_bigint2(char *str) { B_bigint res = malloc_bigint(); res->$class = &B_bigintG_methods; set_str(&res->val, (unsigned char *)str, NULL); return res; } // Conversion to strings ///////////////////////////////////////////////////////////////////////////// // These four constants must be changed for a 32 bit machine int WORDSIZE = 64; int POW10INWORD = 18; // Largest power of 10 that fits in a signed long unsigned char POWINWORD[37] = {0,0,62,39,31,27,24,22,20,19,18,18,17,17,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,12,12,12,12,12,12,12,12}; //POWINWORD[b] is largest power of b that fits in a signed word double CCCC = 9.805415291306852e-2; // log2(WORDSIZE) - log2 (POW10INWORD) - log2 (log2(10)) // n is a valid digit in base b iff digvalue[n] < b. unsigned char digvalue[256] = { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99, 99, 99, 99, 99, 99, 99, 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, 99, 99, 99, 99, 99, 99, 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, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, }; int get_str0(bool ishead, zz_ptr n, zz_ptr dens[], int d, unsigned char *res, int pos) { if (d >= 0) { zz_ptr hi = acton_malloc(sizeof(zz_struct)); zz_ptr lo = acton_malloc(sizeof(zz_struct)); zz_init_fit(hi,dens[d]->size); zz_init_fit(lo,dens[d]->size); zz_divrem(hi, lo, n, dens[d]); if (hi->size==0 && ishead) { return get_str0(ishead, lo, dens, d-1, res, pos); } else { int newpos = get_str0(ishead, hi, dens, d-1, res, pos); return get_str0(false, lo, dens, d-1, res, newpos); } } else { char buf[POW10INWORD + 1]; sprintf(buf, "%lu", (unsigned long)n->n[0]); int len = strlen(buf); if (ishead) { memcpy(&res[pos], buf, len); return pos + len; } else { memcpy(&res[pos + POW10INWORD - len], buf, len); return pos + POW10INWORD; } } } char * get_str(zz_ptr nval) { if (nval->size == 0) return "0"; long nlen = BSDNT_ABS(nval->size); zz_ptr npos = acton_malloc(sizeof(zz_struct)); zz_init_fit(npos,nlen); nn_copy(npos->n, nval->n, nlen); npos->size = nlen; int is_neg_n = nval->size < 0; int d; zz_ptr *dens; if (nlen == 1) { d = 0; dens = NULL; } else { d = ceil(log2((double)nlen) + CCCC); //number of squarings dens = acton_malloc(d * sizeof(zz_ptr)); dens[0] = acton_malloc(sizeof(zz_struct)); zz_init_fit(dens[0], 1); zz_seti(dens[0], 10); zz_powi(dens[0], dens[0], POW10INWORD); for (int i=1; i < d; i++) { dens[i] = acton_malloc(sizeof(zz_struct)); zz_init_fit(dens[i], 2 * dens[i-1]->size); zz_mul(dens[i], dens[i-1], dens[i-1]); } } // strlen is for most n one more than necessary; this is a precaution for values of n where // the double value ... in ceil(...) is very close to an integer. So we often waste one byte. int strlen = ceil(log10((float)npos->n[nlen - 1]) + (nlen - 1) * WORD_BITS * log10(2) + is_neg_n) + 2; char *res = acton_malloc_atomic(strlen); memset(res,'0', strlen); int pos = 0; if (is_neg_n) { res[0] = '-'; pos++; } int newpos = get_str0(true, npos, dens, d-1, (unsigned char *)res, pos); res[newpos] = '\0'; return res; } int set_str0(zz_ptr a, unsigned char *nstr, unsigned char base, int parts) { // assert(parts > 0); if (parts == 1) { unsigned long val = 0; int i = 0; while (i < POWINWORD[base]) val = val * base + digvalue[nstr[i++]]; zz_seti(a, val); return POWINWORD[base]; } else { int hi = parts/2; int lo = parts - hi; zz_ptr hires = acton_malloc(sizeof(zz_struct)); zz_ptr lores = acton_malloc(sizeof(zz_struct)); zz_init(hires); zz_init(lores); int hidigs = set_str0(hires, nstr, base, hi); int lodigs = set_str0(lores, &nstr[hi * POWINWORD[base]], base, lo); zz_seti(a, base); zz_powi(a, a, POWINWORD[base] * lo); zz_mul(a, a, hires); zz_add(a, a, lores); return hidigs + lodigs; } } int set_str(zz_ptr a, unsigned char *nstr, B_int intbase) { int pre = 0; int sgn = 1; while(isspace(nstr[pre])) pre++; // should leading spaces be allowed? if(nstr[pre]=='+') pre++; else if (nstr[pre]=='-') { sgn = -1; pre++; } int len = 0; int pre_len = pre; unsigned char basefromstr = 0; if (nstr[pre]=='0') { pre++; if (nstr[pre]=='x' || nstr[pre]=='X') { basefromstr = 16; pre++; pre_len += 2; } else if (nstr[pre]=='o' || nstr[pre]=='O') { basefromstr = 8; pre++; pre_len += 2; } else if (nstr[pre]=='b' || nstr[pre]=='B') { basefromstr = 2; pre++; pre_len += 2; } else len++; } unsigned char basefrompar = 0; if (!intbase) basefrompar = 0; else { long baseval = fromB_int(intbase); if (baseval < 2 || baseval > 36) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "integer type constructor: base parameter %ld is out of range (must be between 2 and 36, inclusive)", baseval); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } else basefrompar = (unsigned char)baseval; } unsigned char base; if (basefrompar==0) base = basefromstr ? basefromstr : 10; else if (basefromstr==0) base = basefrompar; else if (basefromstr != basefrompar) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "integer type constructor: base specified in str (%d) is in conflict with base in parameter base (%d)", basefromstr, basefrompar); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } else base = basefromstr; // which is equal to basefrompar while (digvalue[nstr[pre]] < base) { len++; pre++; } if (len == 0 || nstr[pre] != 0) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "integer type constructor: string \"%s\" cannot be interpreted as an int in base %d", nstr,base); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } nstr += pre_len; int parts = len / POWINWORD[base]; int offset = len % POWINWORD[base]; if (offset == 0) { return set_str0(a, nstr, base, parts); a->size *= sgn; } else { unsigned long headval = 0; int partdigits = 0; int i = 0; while (i < offset) headval = headval * base + digvalue[nstr[i++]]; if (parts > 0) { zz_ptr res0 = acton_malloc(sizeof(zz_struct)); zz_init(res0); partdigits = set_str0(res0, &nstr[offset], base, parts); zz_seti(a, base); zz_powi(a, a, POWINWORD[base] * parts); zz_muli(a, a, headval); zz_add(a, a, res0); } else { zz_seti(a, headval); } a->size *= sgn; return pre; // we shouldn't return chars consumed since we throw exception if whole string not consumed. } } // gcd functions from BSDNT ////////////////////////////////// B_bigint $gcd(B_bigint a, B_bigint b) { B_bigint res = malloc_bigint(); zz_gcd(&res->val, &a->val, &b->val); return res; } B_tuple $xgcd(B_bigint a, B_bigint b) { B_bigint d = malloc_bigint(); B_bigint s = malloc_bigint(); B_bigint t = malloc_bigint(); zz_xgcd(&d->val, &s->val, &t->val, &a->val, &b->val); return $NEWTUPLE(3, d, s, t); } unsigned long B_bigint_longs[256] = { 0, 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, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 }; struct B_bigint B_bigint_strs[256] = {{&B_bigintG_methods, B_bigint_longs, 0, 1}, {&B_bigintG_methods, B_bigint_longs+1, 1, 1}, {&B_bigintG_methods, B_bigint_longs+2, 1, 1}, {&B_bigintG_methods, B_bigint_longs+3, 1, 1}, {&B_bigintG_methods, B_bigint_longs+4, 1, 1}, {&B_bigintG_methods, B_bigint_longs+5, 1, 1}, {&B_bigintG_methods, B_bigint_longs+6, 1, 1}, {&B_bigintG_methods, B_bigint_longs+7, 1, 1}, {&B_bigintG_methods, B_bigint_longs+8, 1, 1}, {&B_bigintG_methods, B_bigint_longs+9, 1, 1}, {&B_bigintG_methods, B_bigint_longs+10, 1, 1}, {&B_bigintG_methods, B_bigint_longs+11, 1, 1}, {&B_bigintG_methods, B_bigint_longs+12, 1, 1}, {&B_bigintG_methods, B_bigint_longs+13, 1, 1}, {&B_bigintG_methods, B_bigint_longs+14, 1, 1}, {&B_bigintG_methods, B_bigint_longs+15, 1, 1}, {&B_bigintG_methods, B_bigint_longs+16, 1, 1}, {&B_bigintG_methods, B_bigint_longs+17, 1, 1}, {&B_bigintG_methods, B_bigint_longs+18, 1, 1}, {&B_bigintG_methods, B_bigint_longs+19, 1, 1}, {&B_bigintG_methods, B_bigint_longs+20, 1, 1}, {&B_bigintG_methods, B_bigint_longs+21, 1, 1}, {&B_bigintG_methods, B_bigint_longs+22, 1, 1}, {&B_bigintG_methods, B_bigint_longs+23, 1, 1}, {&B_bigintG_methods, B_bigint_longs+24, 1, 1}, {&B_bigintG_methods, B_bigint_longs+25, 1, 1}, {&B_bigintG_methods, B_bigint_longs+26, 1, 1}, {&B_bigintG_methods, B_bigint_longs+27, 1, 1}, {&B_bigintG_methods, B_bigint_longs+28, 1, 1}, {&B_bigintG_methods, B_bigint_longs+29, 1, 1}, {&B_bigintG_methods, B_bigint_longs+30, 1, 1}, {&B_bigintG_methods, B_bigint_longs+31, 1, 1}, {&B_bigintG_methods, B_bigint_longs+32, 1, 1}, {&B_bigintG_methods, B_bigint_longs+33, 1, 1}, {&B_bigintG_methods, B_bigint_longs+34, 1, 1}, {&B_bigintG_methods, B_bigint_longs+35, 1, 1}, {&B_bigintG_methods, B_bigint_longs+36, 1, 1}, {&B_bigintG_methods, B_bigint_longs+37, 1, 1}, {&B_bigintG_methods, B_bigint_longs+38, 1, 1}, {&B_bigintG_methods, B_bigint_longs+39, 1, 1}, {&B_bigintG_methods, B_bigint_longs+40, 1, 1}, {&B_bigintG_methods, B_bigint_longs+41, 1, 1}, {&B_bigintG_methods, B_bigint_longs+42, 1, 1}, {&B_bigintG_methods, B_bigint_longs+43, 1, 1}, {&B_bigintG_methods, B_bigint_longs+44, 1, 1}, {&B_bigintG_methods, B_bigint_longs+45, 1, 1}, {&B_bigintG_methods, B_bigint_longs+46, 1, 1}, {&B_bigintG_methods, B_bigint_longs+47, 1, 1}, {&B_bigintG_methods, B_bigint_longs+48, 1, 1}, {&B_bigintG_methods, B_bigint_longs+49, 1, 1}, {&B_bigintG_methods, B_bigint_longs+50, 1, 1}, {&B_bigintG_methods, B_bigint_longs+51, 1, 1}, {&B_bigintG_methods, B_bigint_longs+52, 1, 1}, {&B_bigintG_methods, B_bigint_longs+53, 1, 1}, {&B_bigintG_methods, B_bigint_longs+54, 1, 1}, {&B_bigintG_methods, B_bigint_longs+55, 1, 1}, {&B_bigintG_methods, B_bigint_longs+56, 1, 1}, {&B_bigintG_methods, B_bigint_longs+57, 1, 1}, {&B_bigintG_methods, B_bigint_longs+58, 1, 1}, {&B_bigintG_methods, B_bigint_longs+59, 1, 1}, {&B_bigintG_methods, B_bigint_longs+60, 1, 1}, {&B_bigintG_methods, B_bigint_longs+61, 1, 1}, {&B_bigintG_methods, B_bigint_longs+62, 1, 1}, {&B_bigintG_methods, B_bigint_longs+63, 1, 1}, {&B_bigintG_methods, B_bigint_longs+64, 1, 1}, {&B_bigintG_methods, B_bigint_longs+65, 1, 1}, {&B_bigintG_methods, B_bigint_longs+66, 1, 1}, {&B_bigintG_methods, B_bigint_longs+67, 1, 1}, {&B_bigintG_methods, B_bigint_longs+68, 1, 1}, {&B_bigintG_methods, B_bigint_longs+69, 1, 1}, {&B_bigintG_methods, B_bigint_longs+70, 1, 1}, {&B_bigintG_methods, B_bigint_longs+71, 1, 1}, {&B_bigintG_methods, B_bigint_longs+72, 1, 1}, {&B_bigintG_methods, B_bigint_longs+73, 1, 1}, {&B_bigintG_methods, B_bigint_longs+74, 1, 1}, {&B_bigintG_methods, B_bigint_longs+75, 1, 1}, {&B_bigintG_methods, B_bigint_longs+76, 1, 1}, {&B_bigintG_methods, B_bigint_longs+77, 1, 1}, {&B_bigintG_methods, B_bigint_longs+78, 1, 1}, {&B_bigintG_methods, B_bigint_longs+79, 1, 1}, {&B_bigintG_methods, B_bigint_longs+80, 1, 1}, {&B_bigintG_methods, B_bigint_longs+81, 1, 1}, {&B_bigintG_methods, B_bigint_longs+82, 1, 1}, {&B_bigintG_methods, B_bigint_longs+83, 1, 1}, {&B_bigintG_methods, B_bigint_longs+84, 1, 1}, {&B_bigintG_methods, B_bigint_longs+85, 1, 1}, {&B_bigintG_methods, B_bigint_longs+86, 1, 1}, {&B_bigintG_methods, B_bigint_longs+87, 1, 1}, {&B_bigintG_methods, B_bigint_longs+88, 1, 1}, {&B_bigintG_methods, B_bigint_longs+89, 1, 1}, {&B_bigintG_methods, B_bigint_longs+90, 1, 1}, {&B_bigintG_methods, B_bigint_longs+91, 1, 1}, {&B_bigintG_methods, B_bigint_longs+92, 1, 1}, {&B_bigintG_methods, B_bigint_longs+93, 1, 1}, {&B_bigintG_methods, B_bigint_longs+94, 1, 1}, {&B_bigintG_methods, B_bigint_longs+95, 1, 1}, {&B_bigintG_methods, B_bigint_longs+96, 1, 1}, {&B_bigintG_methods, B_bigint_longs+97, 1, 1}, {&B_bigintG_methods, B_bigint_longs+98, 1, 1}, {&B_bigintG_methods, B_bigint_longs+99, 1, 1}, {&B_bigintG_methods, B_bigint_longs+100, 1, 1}, {&B_bigintG_methods, B_bigint_longs+101, 1, 1}, {&B_bigintG_methods, B_bigint_longs+102, 1, 1}, {&B_bigintG_methods, B_bigint_longs+103, 1, 1}, {&B_bigintG_methods, B_bigint_longs+104, 1, 1}, {&B_bigintG_methods, B_bigint_longs+105, 1, 1}, {&B_bigintG_methods, B_bigint_longs+106, 1, 1}, {&B_bigintG_methods, B_bigint_longs+107, 1, 1}, {&B_bigintG_methods, B_bigint_longs+108, 1, 1}, {&B_bigintG_methods, B_bigint_longs+109, 1, 1}, {&B_bigintG_methods, B_bigint_longs+110, 1, 1}, {&B_bigintG_methods, B_bigint_longs+111, 1, 1}, {&B_bigintG_methods, B_bigint_longs+112, 1, 1}, {&B_bigintG_methods, B_bigint_longs+113, 1, 1}, {&B_bigintG_methods, B_bigint_longs+114, 1, 1}, {&B_bigintG_methods, B_bigint_longs+115, 1, 1}, {&B_bigintG_methods, B_bigint_longs+116, 1, 1}, {&B_bigintG_methods, B_bigint_longs+117, 1, 1}, {&B_bigintG_methods, B_bigint_longs+118, 1, 1}, {&B_bigintG_methods, B_bigint_longs+119, 1, 1}, {&B_bigintG_methods, B_bigint_longs+120, 1, 1}, {&B_bigintG_methods, B_bigint_longs+121, 1, 1}, {&B_bigintG_methods, B_bigint_longs+122, 1, 1}, {&B_bigintG_methods, B_bigint_longs+123, 1, 1}, {&B_bigintG_methods, B_bigint_longs+124, 1, 1}, {&B_bigintG_methods, B_bigint_longs+125, 1, 1}, {&B_bigintG_methods, B_bigint_longs+126, 1, 1}, {&B_bigintG_methods, B_bigint_longs+127, 1, 1}, {&B_bigintG_methods, B_bigint_longs+128, 1, 1}, {&B_bigintG_methods, B_bigint_longs+129, 1, 1}, {&B_bigintG_methods, B_bigint_longs+130, 1, 1}, {&B_bigintG_methods, B_bigint_longs+131, 1, 1}, {&B_bigintG_methods, B_bigint_longs+132, 1, 1}, {&B_bigintG_methods, B_bigint_longs+133, 1, 1}, {&B_bigintG_methods, B_bigint_longs+134, 1, 1}, {&B_bigintG_methods, B_bigint_longs+135, 1, 1}, {&B_bigintG_methods, B_bigint_longs+136, 1, 1}, {&B_bigintG_methods, B_bigint_longs+137, 1, 1}, {&B_bigintG_methods, B_bigint_longs+138, 1, 1}, {&B_bigintG_methods, B_bigint_longs+139, 1, 1}, {&B_bigintG_methods, B_bigint_longs+140, 1, 1}, {&B_bigintG_methods, B_bigint_longs+141, 1, 1}, {&B_bigintG_methods, B_bigint_longs+142, 1, 1}, {&B_bigintG_methods, B_bigint_longs+143, 1, 1}, {&B_bigintG_methods, B_bigint_longs+144, 1, 1}, {&B_bigintG_methods, B_bigint_longs+145, 1, 1}, {&B_bigintG_methods, B_bigint_longs+146, 1, 1}, {&B_bigintG_methods, B_bigint_longs+147, 1, 1}, {&B_bigintG_methods, B_bigint_longs+148, 1, 1}, {&B_bigintG_methods, B_bigint_longs+149, 1, 1}, {&B_bigintG_methods, B_bigint_longs+150, 1, 1}, {&B_bigintG_methods, B_bigint_longs+151, 1, 1}, {&B_bigintG_methods, B_bigint_longs+152, 1, 1}, {&B_bigintG_methods, B_bigint_longs+153, 1, 1}, {&B_bigintG_methods, B_bigint_longs+154, 1, 1}, {&B_bigintG_methods, B_bigint_longs+155, 1, 1}, {&B_bigintG_methods, B_bigint_longs+156, 1, 1}, {&B_bigintG_methods, B_bigint_longs+157, 1, 1}, {&B_bigintG_methods, B_bigint_longs+158, 1, 1}, {&B_bigintG_methods, B_bigint_longs+159, 1, 1}, {&B_bigintG_methods, B_bigint_longs+160, 1, 1}, {&B_bigintG_methods, B_bigint_longs+161, 1, 1}, {&B_bigintG_methods, B_bigint_longs+162, 1, 1}, {&B_bigintG_methods, B_bigint_longs+163, 1, 1}, {&B_bigintG_methods, B_bigint_longs+164, 1, 1}, {&B_bigintG_methods, B_bigint_longs+165, 1, 1}, {&B_bigintG_methods, B_bigint_longs+166, 1, 1}, {&B_bigintG_methods, B_bigint_longs+167, 1, 1}, {&B_bigintG_methods, B_bigint_longs+168, 1, 1}, {&B_bigintG_methods, B_bigint_longs+169, 1, 1}, {&B_bigintG_methods, B_bigint_longs+170, 1, 1}, {&B_bigintG_methods, B_bigint_longs+171, 1, 1}, {&B_bigintG_methods, B_bigint_longs+172, 1, 1}, {&B_bigintG_methods, B_bigint_longs+173, 1, 1}, {&B_bigintG_methods, B_bigint_longs+174, 1, 1}, {&B_bigintG_methods, B_bigint_longs+175, 1, 1}, {&B_bigintG_methods, B_bigint_longs+176, 1, 1}, {&B_bigintG_methods, B_bigint_longs+177, 1, 1}, {&B_bigintG_methods, B_bigint_longs+178, 1, 1}, {&B_bigintG_methods, B_bigint_longs+179, 1, 1}, {&B_bigintG_methods, B_bigint_longs+180, 1, 1}, {&B_bigintG_methods, B_bigint_longs+181, 1, 1}, {&B_bigintG_methods, B_bigint_longs+182, 1, 1}, {&B_bigintG_methods, B_bigint_longs+183, 1, 1}, {&B_bigintG_methods, B_bigint_longs+184, 1, 1}, {&B_bigintG_methods, B_bigint_longs+185, 1, 1}, {&B_bigintG_methods, B_bigint_longs+186, 1, 1}, {&B_bigintG_methods, B_bigint_longs+187, 1, 1}, {&B_bigintG_methods, B_bigint_longs+188, 1, 1}, {&B_bigintG_methods, B_bigint_longs+189, 1, 1}, {&B_bigintG_methods, B_bigint_longs+190, 1, 1}, {&B_bigintG_methods, B_bigint_longs+191, 1, 1}, {&B_bigintG_methods, B_bigint_longs+192, 1, 1}, {&B_bigintG_methods, B_bigint_longs+193, 1, 1}, {&B_bigintG_methods, B_bigint_longs+194, 1, 1}, {&B_bigintG_methods, B_bigint_longs+195, 1, 1}, {&B_bigintG_methods, B_bigint_longs+196, 1, 1}, {&B_bigintG_methods, B_bigint_longs+197, 1, 1}, {&B_bigintG_methods, B_bigint_longs+198, 1, 1}, {&B_bigintG_methods, B_bigint_longs+199, 1, 1}, {&B_bigintG_methods, B_bigint_longs+200, 1, 1}, {&B_bigintG_methods, B_bigint_longs+201, 1, 1}, {&B_bigintG_methods, B_bigint_longs+202, 1, 1}, {&B_bigintG_methods, B_bigint_longs+203, 1, 1}, {&B_bigintG_methods, B_bigint_longs+204, 1, 1}, {&B_bigintG_methods, B_bigint_longs+205, 1, 1}, {&B_bigintG_methods, B_bigint_longs+206, 1, 1}, {&B_bigintG_methods, B_bigint_longs+207, 1, 1}, {&B_bigintG_methods, B_bigint_longs+208, 1, 1}, {&B_bigintG_methods, B_bigint_longs+209, 1, 1}, {&B_bigintG_methods, B_bigint_longs+210, 1, 1}, {&B_bigintG_methods, B_bigint_longs+211, 1, 1}, {&B_bigintG_methods, B_bigint_longs+212, 1, 1}, {&B_bigintG_methods, B_bigint_longs+213, 1, 1}, {&B_bigintG_methods, B_bigint_longs+214, 1, 1}, {&B_bigintG_methods, B_bigint_longs+215, 1, 1}, {&B_bigintG_methods, B_bigint_longs+216, 1, 1}, {&B_bigintG_methods, B_bigint_longs+217, 1, 1}, {&B_bigintG_methods, B_bigint_longs+218, 1, 1}, {&B_bigintG_methods, B_bigint_longs+219, 1, 1}, {&B_bigintG_methods, B_bigint_longs+220, 1, 1}, {&B_bigintG_methods, B_bigint_longs+221, 1, 1}, {&B_bigintG_methods, B_bigint_longs+222, 1, 1}, {&B_bigintG_methods, B_bigint_longs+223, 1, 1}, {&B_bigintG_methods, B_bigint_longs+224, 1, 1}, {&B_bigintG_methods, B_bigint_longs+225, 1, 1}, {&B_bigintG_methods, B_bigint_longs+226, 1, 1}, {&B_bigintG_methods, B_bigint_longs+227, 1, 1}, {&B_bigintG_methods, B_bigint_longs+228, 1, 1}, {&B_bigintG_methods, B_bigint_longs+229, 1, 1}, {&B_bigintG_methods, B_bigint_longs+230, 1, 1}, {&B_bigintG_methods, B_bigint_longs+231, 1, 1}, {&B_bigintG_methods, B_bigint_longs+232, 1, 1}, {&B_bigintG_methods, B_bigint_longs+233, 1, 1}, {&B_bigintG_methods, B_bigint_longs+234, 1, 1}, {&B_bigintG_methods, B_bigint_longs+235, 1, 1}, {&B_bigintG_methods, B_bigint_longs+236, 1, 1}, {&B_bigintG_methods, B_bigint_longs+237, 1, 1}, {&B_bigintG_methods, B_bigint_longs+238, 1, 1}, {&B_bigintG_methods, B_bigint_longs+239, 1, 1}, {&B_bigintG_methods, B_bigint_longs+240, 1, 1}, {&B_bigintG_methods, B_bigint_longs+241, 1, 1}, {&B_bigintG_methods, B_bigint_longs+242, 1, 1}, {&B_bigintG_methods, B_bigint_longs+243, 1, 1}, {&B_bigintG_methods, B_bigint_longs+244, 1, 1}, {&B_bigintG_methods, B_bigint_longs+245, 1, 1}, {&B_bigintG_methods, B_bigint_longs+246, 1, 1}, {&B_bigintG_methods, B_bigint_longs+247, 1, 1}, {&B_bigintG_methods, B_bigint_longs+248, 1, 1}, {&B_bigintG_methods, B_bigint_longs+249, 1, 1}, {&B_bigintG_methods, B_bigint_longs+250, 1, 1}, {&B_bigintG_methods, B_bigint_longs+251, 1, 1}, {&B_bigintG_methods, B_bigint_longs+252, 1, 1}, {&B_bigintG_methods, B_bigint_longs+253, 1, 1}, {&B_bigintG_methods, B_bigint_longs+254, 1, 1}, {&B_bigintG_methods, B_bigint_longs+255, 1, 1}}; ================================================ FILE: base/builtin/bigint.h ================================================ #include struct B_bigint { struct B_bigintG_class *$class; zz_struct val; }; // B_int zz$to$int(zz_ptr val); long fromB_bigint(B_bigint n); B_bigint toB_bigint(long n); B_bigint toB_bigint2(char *str); char *get_str(zz_ptr n); B_bigint B_bigintG_new(B_atom a, B_int base); B_bigint $gcd(B_bigint, B_bigint); B_tuple $xgcd(B_bigint, B_bigint); extern struct B_bigint B_bigint_strs[256]; #define ORD_B_bigint__eq__(a,b) (zz_equal(&a->val,&b->val)) #define ORD_B_bigint__ne__(a,b) (1-zz_equal(&a->val,&b->val)) #define ORD_B_bigint__lt__(a,b) (zz_cmp(&a->val,&b->val) < 0) #define ORD_B_bigint__le__(a,b) (zz_cmp(&a->val,&b->val) <= 0) #define ORD_B_bigint__gt__(a,b) (zz_cmp(&a->val,&b->val) > 0) #define ORD_B_bigint__ge__(a,b) (zz_cmp(&a->val,&b->val) >= 0) ================================================ FILE: base/builtin/bool.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Serialization /////////////////////////////////////////////////////////////////////// B_NoneType B_boolD___init__(B_bool self, B_value s){ self->val = (s->$class->__bool__(s))->val; return B_None; } B_bool B_boolD___bool__(B_bool self) { return self; } B_str B_boolD___str__(B_bool self) { if (self->val) return to$str("True"); else return to$str("False"); } B_str B_boolD___repr__(B_bool self) { if (self->val) return to$str("True"); else return to$str("False"); } void B_boolD___serialize__(B_bool self, $Serial$state state) { $val_serialize(BOOL_ID,&self->val,state); } B_bool B_boolD___deserialize__(B_bool self, $Serial$state state) { return toB_bool((long)$val_deserialize(state)); } B_bool B_boolG_new(B_value s) { return $NEW(B_bool, s); } B_bool toB_bool(long b) { return b ? B_True : B_False; } long fromB_bool(B_bool b) { return b->val; } struct B_bool $t = {&B_boolG_methods,1L}; struct B_bool $f = {&B_boolG_methods,0L}; B_bool B_True = &$t; B_bool B_False = &$f; B_bool $default__bool__(B_value self) { return B_True; } // B_HashableD_bool /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_boolD___eq__(B_HashableD_bool wit, B_bool a, B_bool b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_boolD___ne__(B_HashableD_bool wit, B_bool a, B_bool b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_boolD_hash(B_HashableD_bool wit, B_bool a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val), 8)); return B_None; } ================================================ FILE: base/builtin/bool.h ================================================ struct B_bool { struct B_boolG_class *$class; long val; }; B_bool toB_bool(long b); long fromB_bool(B_bool b); extern B_bool B_True, B_False; B_bool $default__bool__(B_value); ================================================ FILE: base/builtin/box.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ B_NoneType $BoxD___init__($Box self, $WORD val) { self->val = val; return B_None; } B_bool $BoxD___bool__($Box self) { B_value it = (B_value)self->val; return it->$class->__bool__(it); } B_str $BoxD___str__($Box self) { B_value it = (B_value)self->val; return it->$class->__str__(it); } B_str $BoxD___repr__($Box self) { B_value it = (B_value)self->val; return it->$class->__repr__(it); } void $BoxD___serialize__ ($Box self, $Serial$state state) { $step_serialize(self->val, state); } $Box $BoxD___deserialize__ ($Box self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct $Box)); self->$class = &$BoxG_methods; return self; } self = $DNEW($Box, state); } self->val = $step_deserialize(state); return self; } $Box $BoxG_new($WORD G_1) { $Box $tmp = acton_malloc(sizeof(struct $Box)); $tmp->$class = &$BoxG_methods; $BoxG_methods.__init__($tmp, G_1); return $tmp; } struct $BoxG_class $BoxG_methods = { .$GCINFO = "$Box", .$superclass = ($SuperG_class)&B_ExceptionG_methods, .__init__ = $BoxD___init__, .__bool__ = $BoxD___bool__, .__str__ = $BoxD___str__, .__repr__ = $BoxD___repr__, .__serialize__ = $BoxD___serialize__, .__deserialize__ = $BoxD___deserialize__ }; ================================================ FILE: base/builtin/box.h ================================================ struct $Box; typedef struct $Box *$Box; struct $Box { struct $BoxG_class *$class; $WORD val; }; struct $BoxG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) ($Box, $WORD); void (*__serialize__) ($Box, $Serial$state); $Box (*__deserialize__) ($Box, $Serial$state); B_bool (*__bool__) ($Box); B_str (*__str__) ($Box); B_str (*__repr__) ($Box); }; $Box $BoxG_new($WORD); extern struct $BoxG_class $BoxG_methods; ================================================ FILE: base/builtin/builtin.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef __linux__ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #endif #include "builtin.h" #include "common.c" #include "class_hierarchy.c" #include "none.c" #include "box.c" // #include "atom.c" #include "int.c" #include "i32.c" #include "i16.c" #include "i8.c" #include "u64.c" #include "u32.c" #include "u16.c" #include "u8.c" #include "u1.c" #include "bigint.c" #include "float.c" #include "bool.c" #include "complex.c" #include "Iterator.c" #include "slice.c" //#include "hash.c" #include "timsort.c" #include "list.c" #include "dict.c" #include "str.c" #include "set.c" #include "tuple.c" #include "range.c" #include "exceptions.c" #include "serialize.c" #include "registration.c" #include "function.c" #include "builtin_functions.c" #include "env.c" #include "staticWitnesses.c" #include "utils.c" #include "hasher.c" ================================================ FILE: base/builtin/builtin.h ================================================ #pragma once #ifdef __linux__ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #endif #include #include #include #include #include #include #include #include #include "../rts/common.h" #include "common.h" struct B_NoneType; typedef struct B_NoneType *B_NoneType; struct B_tuple; typedef struct B_tuple *B_tuple; struct $Serial$state; typedef struct $Serial$state *$Serial$state; struct $SuperG_class; typedef struct $SuperG_class *$SuperG_class; struct $Super; typedef struct $Super *$Super; struct $SerializableG_class; typedef struct $SerializableG_class *$SerializableG_class; struct $Serializable; typedef struct $Serializable *$Serializable; // The following declarations moved here from function.h struct $proc; struct $action; struct $mut; struct $pure; struct $Cont; typedef struct $proc *$proc; typedef struct $action *$action; typedef struct $mut *$mut; typedef struct $pure *$pure; typedef struct $Cont *$Cont; enum $RTAG { $RDONE, $RFAIL, $RCONT, $RWAIT }; typedef enum $RTAG $RTAG; struct $R { $RTAG tag; $Cont cont; $WORD value; }; typedef struct $R $R; #define $R_CONT(cont, arg) ($R){$RCONT, (cont), ($WORD)(arg)} #define $R_DONE(value) ($R){$RDONE, NULL, (value)} #define $R_FAIL(value) ($R){$RFAIL, NULL, (value)} #define $R_WAIT(cont, value) ($R){$RWAIT, (cont), (value)} ///////////////////////////////////////////////////////// // And the following from rts.h ///////////////////////// struct $Actor; struct $Catcher; typedef struct $Actor *$Actor; typedef struct $Catcher *$Catcher; #define $Lock volatile atomic_flag /////////////////////////////////////////////////////////// #include "../out/types/__builtin__.h" #include "class_hierarchy.h" #include "serialize.h" #include "registration.h" #include "exceptions.h" #include "Iterator.h" #include "complx.h" #include "box.h" #include "none.h" #include "slice.h" #include "float.h" #include "bool.h" #include "list.h" #include "dict.h" #include "str.h" #include "set.h" #include "tuple.h" //#include "hash.h" #include "int.h" #include "i32.h" #include "i16.h" #include "i8.h" #include "u64.h" #include "u32.h" #include "u16.h" #include "u8.h" #include "u1.h" #include "bigint.h" #include "range.h" #include "function.h" #include "builtin_functions.h" #include "env.h" #include "staticWitnesses.h" #include "utils.h" #include "hasher.h" ================================================ FILE: base/builtin/builtin_functions.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include // print ////////////////////////////////////////////////////////////////////////////// static $WORD mkstr($WORD w) { B_value w1 = (B_value)w; return w1->$class->__str__(w); } /* B_NoneType B_print(int size, ...) { va_list args; va_start(args,size); if (size > 0) { B_value elem = va_arg(args,B_value); fputs((const char*)elem->$class->__str__(elem)->str,stdout); } for (int i=1; i$class->__str__(elem)->str,stdout); } putchar('\n'); va_end(args); return B_None; } */ B_str __str__(B_value x) { if (x == B_None) return to$str("None"); else return x->$class->__str__(x); } B_NoneType B_print(B_tuple t, B_str sep_arg, B_str end_arg, B_bool stderr_arg, B_bool flush_arg) { FILE *outfd = stdout; if (stderr_arg && stderr_arg->val) { outfd = stderr; } B_str sep = to$str(" "); if (sep_arg) sep = sep_arg; B_str end = to$str("\n"); if (end_arg) end = end_arg; // Write to temporary buffer first, making us much less prone to interleaved // output from multiple threads. It costs a malloc and some copies but print // should not be used in performance critical code. int tlen = 0; for (int i=0; isize; i++) { B_value elem = (B_value)t->components[i]; tlen += __str__(elem)->nbytes + sep->nbytes; } tlen += end->nbytes; char *s = acton_malloc(tlen+1); int pos = 0; for (int i=0; isize; i++) { if (i > 0) { memcpy(s+pos, sep->str, sep->nbytes); pos += sep->nbytes; } B_value elem = (B_value)t->components[i]; memcpy(s+pos, __str__(elem)->str, __str__(elem)->nbytes); pos += __str__(elem)->nbytes; } memcpy(s+pos, end->str, end->nbytes); pos += end->nbytes; s[pos] = '\0'; fputs(s, outfd); if (flush_arg && flush_arg->val) fflush(outfd); return B_None; } // enumerate ////////////////////////////////////////////////////////////////////////// void B_IteratorD_enumerate_init(B_IteratorD_enumerate self, B_Iterator it, B_int n) { self->it = it; self->nxt = fromB_int(n); } B_bool B_IteratorD_enumerate_bool(B_IteratorD_enumerate self) { return B_True; } B_str B_IteratorD_enumerate_str(B_IteratorD_enumerate self) { return $FORMAT("", self); } void B_IteratorD_enumerate_serialize(B_IteratorD_enumerate self,$Serial$state state) { $step_serialize(self->it,state); $step_serialize(toB_int(self->nxt),state); } B_IteratorD_enumerate B_IteratorD_enumerate$_deserialize(B_IteratorD_enumerate res,$Serial$state state) { if (!res) res = $DNEW(B_IteratorD_enumerate,state); res->it = $step_deserialize(state); res->nxt = fromB_int((B_int)$step_deserialize(state)); return res; } $WORD B_IteratorD_enumerate_next(B_IteratorD_enumerate it) { $WORD w = it->it->$class->__next__(it->it); return $NEWTUPLE(2,toB_int(it->nxt++),w); } struct B_IteratorD_enumerateG_class B_IteratorD_enumerateG_methods = {"B_IteratorD_enumerate",UNASSIGNED,($SuperG_class)&B_IteratorG_methods,B_IteratorD_enumerate_init, B_IteratorD_enumerate_serialize, B_IteratorD_enumerate$_deserialize, B_IteratorD_enumerate_bool,B_IteratorD_enumerate_str,B_IteratorD_enumerate_str, B_IteratorD_enumerate_next}; B_IteratorD_enumerate B_IteratorD_enumerateG_new(B_Iterator it, B_int n) { return $NEW(B_IteratorD_enumerate, it, n); } B_Iterator B_enumerate(B_Iterable wit, $WORD iter, B_int start) { B_Iterator it = wit->$class->__iter__(wit,iter); if (!start) start = toB_int(0); return (B_Iterator)B_IteratorD_enumerateG_new(it,start); } // filter //////////////////////////////////////////////////////////////////////////////// void B_IteratorD_filter_init(B_IteratorD_filter self, B_Iterator it, $pure f) { self->it = it; self->f = f; } B_bool B_IteratorD_filter_bool(B_IteratorD_filter self) { return B_True; } B_str B_IteratorD_filter_str(B_IteratorD_filter self) { return $FORMAT("", self); } void B_IteratorD_filter_serialize(B_IteratorD_filter self,$Serial$state state) { $step_serialize(self->it,state); } B_IteratorD_filter B_IteratorD_filter$_deserialize(B_IteratorD_filter res, $Serial$state state) { if (!res) res = $DNEW(B_IteratorD_filter,state); res->it = $step_deserialize(state); return res; } $WORD B_IteratorD_filter_next(B_IteratorD_filter it) { $WORD w; do w = it->it->$class->__next__(it->it); while (!fromB_bool(it->f->$class->__eval__(it->f, w))); return w; } struct B_IteratorD_filterG_class B_IteratorD_filterG_methods = {"B_IteratorD_filter",UNASSIGNED,($SuperG_class)&B_IteratorG_methods,B_IteratorD_filter_init, B_IteratorD_filter_serialize, B_IteratorD_filter$_deserialize, B_IteratorD_filter_bool,B_IteratorD_filter_str,B_IteratorD_filter_str, B_IteratorD_filter_next}; B_IteratorD_filter B_IteratorD_filterG_new(B_Iterator it, $pure f) { return $NEW(B_IteratorD_filter, it, f); } B_Iterator B_filter(B_Iterable wit, $pure f, $WORD iter) { B_Iterator it = wit->$class->__iter__(wit,iter); return (B_Iterator)B_IteratorD_filterG_new(it,f); } // map //////////////////////////////////////////////////////////////////////////////// void B_IteratorD_map_init(B_IteratorD_map self, B_Iterator it, $pure f) { self->it = it; self->f = f; } B_bool B_IteratorD_map_bool(B_IteratorD_map self) { return B_True; } B_str B_IteratorD_map_str(B_IteratorD_map self) { return $FORMAT("", self); } void B_IteratorD_map_serialize(B_IteratorD_map self,$Serial$state state) { $step_serialize(self->it,state); } B_IteratorD_map B_IteratorD_map$_deserialize(B_IteratorD_map res, $Serial$state state) { if (!res) res = $DNEW(B_IteratorD_map,state); res->it = $step_deserialize(state); return res; } $WORD B_IteratorD_map_next(B_IteratorD_map it) { $WORD w = it->it->$class->__next__(it->it); return it->f->$class->__eval__(it->f, w); } struct B_IteratorD_mapG_class B_IteratorD_mapG_methods = {"B_IteratorD_map",UNASSIGNED,($SuperG_class)&B_IteratorG_methods,B_IteratorD_map_init, B_IteratorD_map_serialize, B_IteratorD_map$_deserialize, B_IteratorD_map_bool,B_IteratorD_map_str,B_IteratorD_map_str, B_IteratorD_map_next}; B_IteratorD_map B_IteratorD_mapG_new(B_Iterator it, $pure f) { return $NEW(B_IteratorD_map, it, f); } B_Iterator B_map(B_Iterable wit, $pure f, $WORD iter) { B_Iterator it = wit->$class->__iter__(wit,iter); return (B_Iterator)B_IteratorD_mapG_new(it,f); } // max, min /////////////////////////////////////////////////////////////////////////////////// $WORD B_max(B_Ord wit, B_Iterable wit2, $WORD iter, $WORD dflt) { $WORD res = dflt; B_Iterator it = wit2->$class->__iter__(wit2,iter); while(1) { if ($PUSH()) { $WORD nxt = it->$class->__next__(it); if (!res || fromB_bool(wit->$class->__lt__(wit,res,nxt))) res = nxt; $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } // If no value was found in the iterable if (!res) { if (dflt) { return dflt; // Return the provided default value } else { $RAISE(((B_BaseException)B_ValueErrorG_new($FORMAT("max() arg is an empty sequence")))); } } return res; } $WORD B_max_def(B_Ord wit, B_Iterable wit2, $WORD iter, $WORD dflt) { $WORD res = dflt; B_Iterator it = wit2->$class->__iter__(wit2,iter); while(1) { if ($PUSH()) { $WORD nxt = it->$class->__next__(it); if (fromB_bool(wit->$class->__lt__(wit,res,nxt))) res = nxt; $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } return res; } $WORD B_min(B_Ord wit, B_Iterable wit2, $WORD iter, $WORD dflt) { $WORD res = NULL; B_Iterator it = wit2->$class->__iter__(wit2,iter); while(1) { if ($PUSH()) { $WORD nxt = it->$class->__next__(it); if (!res || fromB_bool(wit->$class->__gt__(wit,res,nxt))) res = nxt; $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } // If no value was found in the iterable if (!res) { if (dflt) { return dflt; // Return the provided default value } else { $RAISE((B_BaseException)B_ValueErrorG_new($FORMAT("min() arg is an empty sequence"))); } } return res; } $WORD B_min_def(B_Ord wit, B_Iterable wit2, $WORD iter, $WORD dflt) { $WORD res = dflt; B_Iterator it = wit2->$class->__iter__(wit2,iter); while(1) { if ($PUSH()) { $WORD nxt = it->$class->__next__(it); if (fromB_bool(wit->$class->__gt__(wit,res,nxt))) res = nxt; $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } return res; } B_list B_sorted(B_Ord wit, B_Iterable wit2, $WORD iter) { B_CollectionD_SequenceD_list w = B_CollectionD_SequenceD_listG_witness; B_list res = w->$class->__fromiter__(w, wit2, iter); B_tim_sort(wit, res->data, res->length); return res; } // sum ///////////////////////////////////////////////////////////////////////////////// $WORD B_sum(B_Plus wit, B_Iterable wit2, $WORD iter, $WORD start) { B_Iterator it = wit2->$class->__iter__(wit2,iter); $WORD res = start; if (start == NULL) { res = wit->$class->__zero__(wit); } $WORD nxt; while(1) { if ($PUSH()) { nxt = it->$class->__next__(it); res = wit->$class->__add__(wit,res,nxt); $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } return res; } // zip //////////////////////////////////////////////////////////////////////////////// void B_IteratorD_zip_init(B_IteratorD_zip self, B_Iterator it1, B_Iterator it2) { self->it1 = it1; self->it2 = it2; } B_bool B_IteratorD_zip_bool(B_IteratorD_zip self) { return B_True; } B_str B_IteratorD_zip_str(B_IteratorD_zip self) { return $FORMAT("", self); } void B_IteratorD_zip_serialize(B_IteratorD_zip self,$Serial$state state) { $step_serialize(self->it1,state); $step_serialize(self->it2,state); } B_IteratorD_zip B_IteratorD_zip$_deserialize(B_IteratorD_zip res, $Serial$state state) { if (!res) res = $DNEW(B_IteratorD_zip,state); res->it1 = $step_deserialize(state); res->it2 = $step_deserialize(state); return res; } $WORD B_IteratorD_zip_next(B_IteratorD_zip it) { $WORD w1 = it->it1->$class->__next__(it->it1); $WORD w2 = it->it2->$class->__next__(it->it2); return $NEWTUPLE(2,w1,w2); } struct B_IteratorD_zipG_class B_IteratorD_zipG_methods = {" B_IteratorD_zip",UNASSIGNED,($SuperG_class)&B_IteratorG_methods,B_IteratorD_zip_init, B_IteratorD_zip_serialize, B_IteratorD_zip$_deserialize, B_IteratorD_zip_bool,B_IteratorD_zip_str,B_IteratorD_zip_str, B_IteratorD_zip_next}; B_IteratorD_zip B_IteratorD_zipG_new(B_Iterator iter1, B_Iterator iter2) { return $NEW(B_IteratorD_zip, iter1, iter2); } // Note dubious pairings of witnesses and WORDs. This fixes #2140 without breaking any test. B_Iterator B_zip (B_Iterable wit1, B_Iterable wit2, $WORD iter1, $WORD iter2) { B_Iterator it1 = wit2->$class->__iter__(wit2,iter1); B_Iterator it2 = wit1->$class->__iter__(wit1,iter2); return (B_Iterator)B_IteratorD_zipG_new(it1,it2); } // EqOpt ////////////////////////////////////////////////////// extern struct $EqOptG_class $EqOptG_methods; void $EqOptD___init__($EqOpt wit, B_Eq W_Eq$A) { wit->W_Eq$A = W_Eq$A; } B_bool $EqOptD_bool($EqOpt self) { return B_True; } B_str $EqOptD_str($EqOpt self) { return $FORMAT("", self); } void $EqOptD_serialize($EqOpt self,$Serial$state state) { $step_serialize(self->W_Eq$A,state); } $EqOpt $EqOptD_deserialize($EqOpt res, $Serial$state state) { if (!res) res = $DNEW($EqOpt,state); res->W_Eq$A = $step_deserialize(state); return res; } B_bool $EqOptD___eq__($EqOpt wit, $WORD a, $WORD b) { if (a && b) { return wit->W_Eq$A->$class->__eq__(wit->W_Eq$A, a, b); } return (!a && !b) ? B_True : B_False; } B_bool $EqOptD___ne__($EqOpt wit, $WORD a, $WORD b) { if (a && b) return wit->W_Eq$A->$class->__ne__(wit->W_Eq$A, a, b); return (!a && !b) ? B_False : B_True; } struct $EqOptG_class $EqOptG_methods = {"$EqOpt", UNASSIGNED, NULL, $EqOptD___init__, $EqOptD_serialize, $EqOptD_deserialize, $EqOptD_bool, $EqOptD_str, $EqOptD_str, $EqOptD___eq__, $EqOptD___ne__}; $EqOpt $EqOptG_new(B_Eq W_Eq$A) { return $NEW($EqOpt, W_Eq$A); } // IdentityActor ////////////////////////////////////////////////////// extern struct $IdentityActorG_class $IdentityActorG_methods; void $IdentityActorD___init__($IdentityActor wit) { } B_bool $IdentityActorD_bool($IdentityActor self) { return B_True; } B_str $IdentityActorD_str($IdentityActor self) { return $FORMAT("", self); } void $IdentityActorD_serialize($IdentityActor self,$Serial$state state) { } $IdentityActor $IdentityActorD_deserialize($IdentityActor res, $Serial$state state) { if (!res) res = $DNEW($IdentityActor,state); return res; } B_bool $IdentityActorD___is__($IdentityActor wit, $WORD a, $WORD b) { return (a == b) ? B_True : B_False; } B_bool $IdentityActorD___isnot__($IdentityActor wit, $WORD a, $WORD b) { return (a == b) ? B_False : B_True; } struct $IdentityActorG_class $IdentityActorG_methods = {"$IdentityActor", UNASSIGNED, NULL, $IdentityActorD___init__, $IdentityActorD_serialize, $IdentityActorD_deserialize, $IdentityActorD_bool, $IdentityActorD_str, $IdentityActorD_str, $IdentityActorD___is__, $IdentityActorD___isnot__}; $IdentityActor $IdentityActorG_new() { return $NEW($IdentityActor); } // Various small functions ////////////////////////////////////////////////////////////// // Code generated by acton /* $WORD B_abs (B_Number W_149, B_Real W_148, $WORD x) { return W_149->$class->__abs__(W_149, x, W_148); } B_bool B_all (B_Iterable W_164, $WORD it) { B_Iterator nB_iter = W_164->$class->__iter__(W_164, it); $WORD n$1val = nB_iter->$class->__next__(nB_iter); while ($ISNOTNONE(n$1val)) { B_value x = (B_value)n$1val; if (!x->$class->__bool__(x)->val) { return (B_bool)B_False; } n$1val = nB_iter->$class->__next__(nB_iter); } return (B_bool)B_True; } B_bool B_any (B_Iterable W_179, $WORD it) { B_Iterator n$2iter = W_179->$class->__iter__(W_179, it); $WORD n$3val = n$2iter->$class->__next__(n$2iter); while ($ISNOTNONE(n$3val)) { B_value x = (B_value)n$3val; if (x->$class->__bool__(x)->val) { return (B_bool)B_True; } n$3val = n$2iter->$class->__next__(n$2iter); } return (B_bool)B_False; } B_tuple B_divmod (B_Integral W_225, $WORD a, $WORD b) { return W_225->$class->__divmod__(W_225, a, b); } B_Iterator B_iter (B_Iterable W_278, $WORD x) { return W_278->$class->__iter__(W_278, x); } B_int B_len (B_Collection W_301, $WORD x) { return W_301->$class->__len__(W_301, x); } $WORD B_pow (B_Number W_344, $WORD a, $WORD b) { return W_344->$class->__pow__(W_344, a, b); } B_str B_repr(B_value x) { return x->$class->__repr__(x); } B_Iterator B_reversed (B_Sequence W_369, $WORD seq) { return W_369->$class->__reversed__(W_369, seq); } $WORD B_round (B_Real W_395, $WORD x, B_int n) { return W_395->$class->__round__(W_395, x, n); } */ $WORD $ASSERT(B_bool test, B_str msg) { if (!test->val) { $RAISE((B_BaseException)$NEW(B_AssertionError,msg)); return NULL; // to avoid compiler warning } return B_None; } ================================================ FILE: base/builtin/builtin_functions.h ================================================ #pragma once // #include "function.h" // enumerate //////////////////////////////////////////////////////////// struct B_IteratorD_enumerate; typedef struct B_IteratorD_enumerate *B_IteratorD_enumerate; struct B_IteratorD_enumerateG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_IteratorD_enumerate, B_Iterator,B_int); void (*__serialize__)(B_IteratorD_enumerate,$Serial$state); B_IteratorD_enumerate (*__deserialize__)(B_IteratorD_enumerate,$Serial$state); B_bool (*__bool__)(B_IteratorD_enumerate); B_str (*__str__)(B_IteratorD_enumerate); B_str (*__repr__)(B_IteratorD_enumerate); $WORD(*__next__)(B_IteratorD_enumerate); }; struct B_IteratorD_enumerate { struct B_IteratorD_enumerateG_class *$class; B_Iterator it; int nxt; }; extern struct B_IteratorD_enumerateG_class B_IteratorD_enumerateG_methods; B_IteratorD_enumerate B_IteratorD_enumerateG_new(B_Iterator,B_int); // filter //////////////////////////////////////////////////////////// B_Iterator B_filter (B_Iterable, $pure, $WORD); struct B_IteratorD_filter; typedef struct B_IteratorD_filter *B_IteratorD_filter; struct B_IteratorD_filterG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_IteratorD_filter, B_Iterator, $pure); void (*__serialize__)(B_IteratorD_filter,$Serial$state); B_IteratorD_filter (*__deserialize__)(B_IteratorD_filter,$Serial$state); B_bool (*__bool__)(B_IteratorD_filter); B_str (*__str__)(B_IteratorD_filter); B_str (*__repr__)(B_IteratorD_filter); $WORD(*__next__)(B_IteratorD_filter); }; struct B_IteratorD_filter { struct B_IteratorD_filterG_class *$class; B_Iterator it; $pure f; }; extern struct B_IteratorD_filterG_class B_IteratorD_filterG_methods; B_IteratorD_filter B_IteratorD_filterG_new(B_Iterator, $pure); // map //////////////////////////////////////////////////////////// B_Iterator B_map (B_Iterable, $pure, $WORD); struct B_IteratorD_map; typedef struct B_IteratorD_map *B_IteratorD_map; struct B_IteratorD_mapG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_IteratorD_map, B_Iterator, $pure); void (*__serialize__)(B_IteratorD_map,$Serial$state); B_IteratorD_map (*__deserialize__)(B_IteratorD_map,$Serial$state); B_bool (*__bool__)(B_IteratorD_map); B_str (*__str__)(B_IteratorD_map); B_str (*__repr__)(B_IteratorD_map); $WORD(*__next__)(B_IteratorD_map); }; struct B_IteratorD_map { struct B_IteratorD_mapG_class *$class; B_Iterator it; $pure f; }; extern struct B_IteratorD_mapG_class B_IteratorD_mapG_methods; B_IteratorD_map B_IteratorD_mapG_new(B_Iterator, $pure); // zip //////////////////////////////////////////////////////////// struct B_IteratorD_zip; typedef struct B_IteratorD_zip *B_IteratorD_zip; struct B_IteratorD_zipG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_IteratorD_zip, B_Iterator, B_Iterator); void (*__serialize__)(B_IteratorD_zip,$Serial$state); B_IteratorD_zip (*__deserialize__)(B_IteratorD_zip,$Serial$state); B_bool (*__bool__)(B_IteratorD_zip); B_str (*__str__)(B_IteratorD_zip); B_str (*__repr__)(B_IteratorD_zip); $WORD(*__next__)(B_IteratorD_zip); }; struct B_IteratorD_zip { struct B_IteratorD_zipG_class *$class; B_Iterator it1; B_Iterator it2; }; extern struct B_IteratorD_zipG_class B_IteratorD_zipG_methods; B_IteratorD_zip B_IteratorD_zipG_new(B_Iterator, B_Iterator); B_Iterator B_zip(B_Iterable wit1, B_Iterable wit2, $WORD iter1, $WORD iter2); // EqOpt ////////////////////////////////////////////////////// struct $EqOpt; typedef struct $EqOpt *$EqOpt; struct $EqOptG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($EqOpt, B_Eq); void (*__serialize__)($EqOpt,$Serial$state); $EqOpt (*__deserialize__)($EqOpt,$Serial$state); B_bool (*__bool__)($EqOpt); B_str (*__str__)($EqOpt); B_str (*__repr__)($EqOpt); B_bool (*__eq__)($EqOpt, $WORD, $WORD); B_bool (*__ne__)($EqOpt, $WORD, $WORD); }; struct $EqOpt { struct $EqOptG_class *$class; B_Eq W_Eq$A; }; $EqOpt $EqOptG_new(B_Eq); // IdentityActor ////////////////////////////////////////////////////// struct $IdentityActor; typedef struct $IdentityActor *$IdentityActor; struct $IdentityActorG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($IdentityActor); void (*__serialize__)($IdentityActor,$Serial$state); $IdentityActor (*__deserialize__)($IdentityActor,$Serial$state); B_bool (*__bool__)($IdentityActor); B_str (*__str__)($IdentityActor); B_str (*__repr__)($IdentityActor); B_bool (*__is__)($IdentityActor, $WORD, $WORD); B_bool (*__isnot__)($IdentityActor, $WORD, $WORD); }; struct $IdentityActor { struct $IdentityActorG_class *$class; }; $IdentityActor $IdentityActorG_new(); // Various small functions ////////////////////////////////////////////////////////// $WORD B_min(B_Ord wit, B_Iterable wit2, $WORD iter, $WORD deflt); $WORD B_max(B_Ord wit, B_Iterable wit2, $WORD iter, $WORD deflt); $WORD B_min_def(B_Ord wit, B_Iterable wit2, $WORD iter, $WORD deflt); $WORD B_max_def(B_Ord wit, B_Iterable wit2, $WORD iter, $WORD deflt); // Signatures generated by acton /* $WORD B_abs (B_Real, B_Number, $WORD); B_bool B_all (B_Iterable, $WORD); B_bool B_any (B_Iterable, $WORD); B_tuple B_divmod (B_Integral, $WORD, $WORD); B_u64 B_hash (B_Hashable, $WORD); B_Iterator B_iter (B_Iterable, $WORD); B_int B_len (B_Collection, $WORD); $WORD $next (B_Iterator); $WORD B_pow (B_Number, $WORD, $WORD); B_str B_repr(B_value); B_Iterator B_reversed (B_Sequence, $WORD); $WORD B_round (B_Real, $WORD, B_int); $WORD B_sum(B_Plus, B_Iterable, $WORD, $WORD); */ $WORD $ASSERT(B_bool, B_str); ================================================ FILE: base/builtin/class_hierarchy.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ $Serializable $SerializableG_new() { return $NEW($Serializable); } B_NoneType $SerializableD___init__ ($Serializable self) { return B_None; } /* B_value B_valueG_new() { return $NEW(B_value); } B_NoneType B_valueD___init__ (B_value self) { return B_None; } B_object B_objectG_new() { return $NEW(B_object); } B_NoneType B_objectD___init__ (B_object self) { return B_None; } */ B_str B_valueD___str__(B_value self) { return $FORMAT("<%s object at %p>", unmangle_name(self->$class->$GCINFO), self); } B_str B_valueD___repr__(B_value self) { return $FORMAT("<%s object at %p>", unmangle_name(self->$class->$GCINFO), self); } B_str B_objectD___str__(B_object self) { return $FORMAT("<%s object at %p>", unmangle_name(self->$class->$GCINFO), self); } B_bool B_valueD___bool__(B_value self) { return B_True; } B_bool B_objectD___bool__(B_object self) { return B_True; } struct $SerializableG_class $SerializableG_methods = {"$Serializable",UNASSIGNED,NULL, $SerializableD___init__,NULL,NULL}; //struct B_valueG_class B_valueG_methods = {"B_value",UNASSIGNED,($SuperG_class)&$SerializableG_methods,B_valueD___init__,NULL,NULL, B_valueD___bool__,B_valueD___str__,B_valueD___str__}; //struct B_objectG_class B_objectG_methods = {"B_object",UNASSIGNED,($SuperG_class)&B_valueG_methods,B_objectD___init__,NULL,NULL,B_objectD___bool__,B_objectD___str__,B_objectD___str__}; ================================================ FILE: base/builtin/class_hierarchy.h ================================================ // Super ////////////////////////////////////////////////////////////// // This is only used for typing the $superclass field in classes. struct $SuperG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; }; struct $Super { $SuperG_class $class; }; /* typedef struct $InitializableG_class *$InitializableG_class; typedef struct $Initializable *$Initializable; struct $InitializableG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; // = NULL B_NoneType (*__init__)($Initializable); }; struct $Initializable { struct $InitializableG_class *$class; }; extern struct $InitializableG_class $InitializableG_methods; $Initializable $InitializableG_new(); */ // Serializable ////////////////////////////////////////////////////// struct $SerializableG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; // = InitializableG_methods B_NoneType (*__init__)($Serializable); void (*__serialize__)($Serializable, $Serial$state); $Serializable (*__deserialize__)($Serializable, $Serial$state); }; struct $Serializable { struct $SerializableG_class *$class; }; extern struct $SerializableG_class $SerializableG_methods; $Serializable $SerializableG_new(); ================================================ FILE: base/builtin/common.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ void $default__init__($WORD s) { return; } /* void B_printobj(char *mess,$WORD obj) { B_value obj1 = (B_value)obj; printf("%s %s\n",mess,obj1->$class->__str__(obj1)->str); } */ char *unmangle_name(char *input) { // Check for NULL input if (input == NULL) { return NULL; } char *output = GC_malloc(strlen(input) + 1); // Check for allocation failure if (output == NULL) { return NULL; } // Check if string starts with "B_" if (strncmp(input, "B_", 2) == 0) { // Copy string without "B_" strcpy(output, input + 2); } else { // Copy string as is strcpy(output, input); } // Handle "Q_" mangling for nested modules char *pos; while ((pos = strstr(output, "Q_")) != NULL) { *pos = '.'; memmove(pos + 1, pos + 2, strlen(pos + 2) + 1); } return output; } ================================================ FILE: base/builtin/common.h ================================================ typedef void *$WORD; #define B_None ($WORD)0 #define $long long #define $int64 int64_t void $default__init__($WORD); // void B_printobj(char *mess,$WORD obj); #define $NEW($T, ...) ({ $T $t = acton_malloc(sizeof(struct $T)); \ $t->$class = &$T ## G_methods; \ $t->$class->__init__($t, ##__VA_ARGS__); \ $t; }) #define $NEWCC($X, $c, ...) ({ $X $x = acton_malloc(sizeof(struct $X)); \ $x->$class = &$X ## G_methods; \ $x->$class->__init__($x, ##__VA_ARGS__, $CONSTCONT($x,$c)); }) #define $DNEW($T, $state) ({ $T $t = acton_malloc(sizeof(struct $T)); \ $t->$class = &$T ## G_methods; \ B_dictD_setitem($state->done,(B_Hashable)B_HashableD_intG_witness,toB_bigint($state->row_no-1),$t); \ $t; }) #define $AND(T, a, b) ({ T $a = (a); ($a && ((B_value)$a)->$class->__bool__((B_value)$a)->val) ? (b) : $a; }) #define $OR(T, a, b) ({ T $a = (a); ($a && ((B_value)$a)->$class->__bool__((B_value)$a)->val) ? $a : (b); }) #define $NOT(T, a) ({ T $a = (a); ($a && ((B_value)$a)->$class->__bool__((B_value)$a)->val) ? B_False : B_True; }) #define $ISINSTANCE($x,$T) ({ \ /* If object is NULL (None), return False */ \ ($x) == B_None ? B_False : ({ \ $SuperG_class $c = (($Super)$x)->$class; \ while($c && $c != ($SuperG_class)&$T ## G_methods) $c = $c->$superclass; \ toB_bool($c != 0); \ }); \ }) #define $ISINSTANCE0($x,$T) ({ \ /* If object is NULL (None), return 0 (False) */ \ ($x) == B_None ? 0 : ({ \ $SuperG_class $c = (($Super)$x)->$class; \ while($c && $c != ($SuperG_class)&$T ## G_methods) $c = $c->$superclass; \ $c != 0; \ }); \ }) #define $ISNOTNONE(x) ((x) != B_None ? B_True : B_False) #define $ISNOTNONE0(x) ((x) != B_None) #define $ISNONE(x) ((x) != B_None ? B_False : B_True) #define $ISNONE0(x) ((x) == B_None) #define $SKIPRES(cont) (cont) #define RAISE($T, ...) $RAISE((B_BaseException)$NEW($T, ##__VA_ARGS__)) // $FORMAT is now a C function in str.c char *unmangle_name(char *input); ================================================ FILE: base/builtin/complex.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ B_complex toB_complex(complex double c) { B_complex res = acton_malloc(sizeof(struct B_complex)); res->$class = &B_complexG_methods; res->val = c; return res; } B_complex B_complexG_new(B_Number wit, $WORD c) { return $NEW(B_complex,wit,c); } B_complex B_complexD_from_real_imag (B_Real wit1, B_Real wit2, $WORD real, $WORD imag) { double re = wit1->$class->__float__(wit1, real)->val; double im = wit2->$class->__float__(wit2, imag)->val; return toB_complex(re + im * _Complex_I); } B_NoneType B_complexD___init__(B_complex self, B_Number wit, $WORD c){ self->val = wit->$class->__complx__(wit,c)->val; return B_None; } void B_complexD___serialize__(B_complex c,$Serial$state state) { $ROW row = $add_header(COMPLEX_ID,2,state); double re = creal(c->val); double im = cimag(c->val); memcpy(row->blob,&re,sizeof(double)); memcpy(row->blob+1,&im,sizeof(double)); } B_complex B_complexD___deserialize__(B_complex self, $Serial$state state) { $ROW this = state->row; state->row =this->next; state->row_no++; double re, im; memcpy(&re,this->blob,sizeof(double)); memcpy(&im,this->blob+1,sizeof(double)); return toB_complex(re + im * _Complex_I); } B_bool B_complexD___bool__(B_complex n) { return toB_bool(n->val != 0.0); } B_str B_complexD___str__(B_complex c) { return $FORMAT("%f + %f*I", creal(c->val), cimag(c->val)); } B_str B_complexD___repr__(B_complex c) { return $FORMAT("%f + %f*I", creal(c->val), cimag(c->val)); } // B_NumberD_complex //////////////////////////////////////////////////////////////////////////////////////// B_complex B_NumberD_complexD___add__(B_NumberD_complex wit, B_complex a, B_complex b) { return toB_complex(a->val + b->val); } B_complex B_NumberD_complexD___zero__(B_NumberD_complex wit) { return toB_complex(0.0); } B_complex B_NumberD_complexD___complex__ (B_NumberD_complex wit, B_complex c) { return c; } B_complex B_NumberD_complexD___mul__ (B_NumberD_complex wit, B_complex a, B_complex b){ return toB_complex(a->val * b->val); } B_complex B_NumberD_complexD___fromatom__(B_NumberD_complex wit, B_atom a) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("__fromatom__ not implemented for complex"))); return B_None; } B_complex B_NumberD_complexD___pow__ (B_NumberD_complex wit, B_complex a, B_complex b) { return toB_complex(cpow(a->val,b->val)); } B_complex B_NumberD_complexD___neg__ (B_NumberD_complex wit, B_complex c){ return toB_complex(-c->val); } B_complex B_NumberD_complexD___pos__ (B_NumberD_complex wit, B_complex c) { return c; } $WORD B_NumberD_complexD_real (B_NumberD_complex wit, B_complex c, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)to$float(creal(c->val))); } $WORD B_NumberD_complexD_imag (B_NumberD_complex wit, B_complex c, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)to$float(cimag(c->val))); } $WORD B_NumberD_complexD___abs__ (B_NumberD_complex wit, B_complex c, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)to$float(cabs(c->val))); } B_complex B_NumberD_complexD_conjugate (B_NumberD_complex wit, B_complex c) { return toB_complex(conj(c->val)); } // B_DivD_complex ///////////////////////////////////////////////////////////////////////////////////////// B_complex B_DivD_complexD___truediv__ (B_DivD_complex wit, B_complex a, B_complex b) { if (b->val == 0.0) { RAISE(B_ZeroDivisionError, to_str_noc("complex truediv: divisor is zero")); } return toB_complex(a->val/b->val); } // B_MinusD_NumberD_complex //////////////////////////////////////////////////////////////////////////////////////// B_complex B_MinusD_NumberD_complexD___sub__(B_MinusD_NumberD_complex wit, B_complex a, B_complex b) { return toB_complex(a->val - b->val); } // B_EqD_complex //////////////////////////////////////////////////////////////////////////////////////// B_bool B_EqD_complexD___eq__ (B_EqD_complex wit, B_complex a, B_complex b) { return toB_bool(creal(a->val) == creal(b->val) && cimag(a->val) == cimag(b->val)); } B_bool B_EqD_complexD___ne__ (B_EqD_complex wit, B_complex a, B_complex b) { return toB_bool(!fromB_bool(B_EqD_complexD___eq__(wit,a,b))); } // B_HashableD_complex //////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_complexD___eq__(B_HashableD_complex wit, B_complex a, B_complex b) { return toB_bool(creal(a->val) == creal(b->val) && cimag(a->val) == cimag(b->val)); } B_bool B_HashableD_complexD___ne__(B_HashableD_complex wit, B_complex a, B_complex b) { return toB_bool(!fromB_bool(B_HashableD_complexD___eq__(wit,a,b))); } B_NoneType B_HashableD_complexD_hash(B_HashableD_complex wit, B_complex a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val), 16)); return B_None; } // init methods //////////////////////////////////////////////////////////////////////////////////////////////// /* B_NoneType B_NumberD_complex_init (B_NumberD_complex wit) { wit-> W_Minus = (B_Minus)$NEW(B_MinusD_NumberD_complex,(B_Number)wit); return B_None; } B_NoneType B_MinusD_NumberD_complex_init(B_MinusD_NumberD_complex wit, B_Number W_Number) { wit->W_Number = W_Number; return B_None; } B_NoneType B_EqD_complex_init(B_EqD_complex wit) { return B_None; } B_NoneType B_DivD_complex_init(B_DivD_complex wit) { return B_None; } B_NoneType B_HashableD_complex_init(B_HashableD_complex wit) { return B_None; } B_NumberD_complex B_NumberD_complexG_new() { return $NEW(B_NumberD_complex); } B_MinusD_NumberD_complex B_MinusD_NumberD_complexG_new(B_Number wit) { return $NEW(B_MinusD_NumberD_complex,wit); } B_EqD_complex B_EqD_complexG_new() { return $NEW(B_EqD_complex); } B_HashableD_complex B_HashableD_complexG_new() { return $NEW(B_HashableD_complex); } struct B_NumberD_complex B_NumberD_complex_instance; struct B_MinusD_NumberD_complex B_MinusD_NumberD_complex_instance; struct B_EqD_complex B_EqD_complex_instance; struct B_HashableD_complex B_HashableD_complex_instance; struct B_NumberD_complexG_class B_NumberD_complexG_methods = { "B_NumberD_complex", UNASSIGNED, ($SuperG_class)&B_NumberG_methods, B_NumberD_complex_init, B_NumberD_complexD___serialize__, B_NumberD_complexD___deserialize__, (B_bool (*)(B_NumberD_complex))$default__bool__, (B_str (*)(B_NumberD_complex))$default__str__, (B_str (*)(B_NumberD_complex))$default__str__, B_NumberD_complexD___add__, (B_complex (*)(B_NumberD_complex, B_complex, B_complex))B_PlusD___iadd__, B_NumberD_complexD___mul__, (B_complex (*)(B_NumberD_complex, B_complex, B_complex))B_TimesD___imul__, NULL, // fromatom B_NumberD_complexD___complx__, B_NumberD_complexD___pow__, (B_complex (*)(B_NumberD_complex, B_complex, B_complex))B_NumberD___ipow__, B_NumberD_complexD___neg__, B_NumberD_complexD___pos__, B_NumberD_complex$real, B_NumberD_complex$imag, B_NumberD_complexD___abs__, B_NumberD_complex$conjugate }; struct B_NumberD_complex B_NumberD_complex_instance = {&B_NumberD_complexG_methods, (B_Minus)&B_MinusD_NumberD_complex_instance}; B_NumberD_complex B_NumberD_complexG_witness = &B_NumberD_complex_instance; struct B_DivD_complexG_class B_DivD_complexG_methods = { "B_DivD_complex", UNASSIGNED, ($SuperG_class)&B_DivG_methods, B_DivD_complex_init, B_DivD_complexD___serialize__, B_DivD_complexD___deserialize__, (B_bool (*)(B_DivD_complex))$default__bool__, (B_str (*)(B_DivD_complex))$default__str__, (B_str (*)(B_DivD_complex))$default__str__, B_DivD_complexD___truediv__, (B_complex (*)(B_DivD_complex, B_complex, B_complex))B_DivD___itruediv__, }; struct B_DivD_complex B_DivD_complex_instance = {&B_DivD_complexG_methods}; B_DivD_complex B_DivD_complexG_witness = &B_DivD_complex_instance; struct B_MinusD_NumberD_complexG_class B_MinusD_NumberD_complexG_methods = { "B_MinusD_NumberD_complex", UNASSIGNED, ($SuperG_class)&B_MinusG_methods, B_MinusD_NumberD_complex_init, B_MinusD_NumberD_complexD___serialize__, B_MinusD_NumberD_complexD___deserialize__, (B_bool (*)(B_MinusD_NumberD_complex))$default__bool__, (B_str (*)(B_MinusD_NumberD_complex))$default__str__, (B_str (*)(B_MinusD_NumberD_complex))$default__str__, B_MinusD_NumberD_complexD___sub__, (B_complex (*)(B_MinusD_NumberD_complex, B_complex, B_complex))B_MinusD___isub__ }; struct B_MinusD_NumberD_complex B_MinusD_NumberD_complex_instance = {&B_MinusD_NumberD_complexG_methods, (B_Number)&B_NumberD_complex_instance}; B_MinusD_NumberD_complex B_MinusD_NumberD_complexG_witness = &B_MinusD_NumberD_complex_instance; struct B_EqD_complexG_class B_EqD_complexG_methods = { "B_EqD_complex", UNASSIGNED, ($SuperG_class)&B_EqG_methods, B_EqD_complex_init, B_EqD_complexD___serialize__, B_EqD_complexD___deserialize__, (B_bool (*)(B_EqD_complex))$default__bool__, (B_str (*)(B_EqD_complex))$default__str__, (B_str (*)(B_EqD_complex))$default__str__, B_EqD_complexD___eq__, B_EqD_complexD___ne__ }; struct B_EqD_complex B_EqD_complex_instance = {&B_EqD_complexG_methods}; B_EqD_complex B_EqD_complexG_witness = &B_EqD_complex_instance; struct B_HashableD_complexG_class B_HashableD_complexG_methods = { "B_HashableD_complex", UNASSIGNED, ($SuperG_class)&B_HashableG_methods, B_HashableD_complex_init, B_HashableD_complexD___serialize__, B_HashableD_complexD___deserialize__, (B_bool (*)(B_HashableD_complex))$default__bool__, (B_str (*)(B_HashableD_complex))$default__str__, (B_str (*)(B_HashableD_complex))$default__str__, B_HashableD_complexD___eq__, B_HashableD_complexD___ne__ }; struct B_HashableD_complex B_HashableD_complex_instance = {&B_HashableD_complexG_methods}; B_HashableD_complex B_HashableD_complexG_witness = &B_HashableD_complex_instance; */ ================================================ FILE: base/builtin/complx.h ================================================ /* * This file is deliberately named complx.h to avoid collisions under gcc or * clang. Details are murky, is it with the standard complex.h? (Path should be * different, no?) Björn should know the details.. */ #include struct B_complex { struct B_complexG_class *$class; complex double val; }; B_complex toB_complex(complex double c); ================================================ FILE: base/builtin/csiphash.c ================================================ /* ************************************************************************** Copyright (c) 2013 Marek Majkowski Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Original location: https://github.com/majek/csiphash/ Solution inspired by code from: Samuel Neves (supercop/crypto_auth/siphash24/little) djb (supercop/crypto_auth/siphash24/little2) Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c) Modified for Python by Christian Heimes: - C89 / MSVC compatibility - _rotl64() on Windows - letoh64() fallback */ #include /* byte swap little endian to host endian * Endian conversion not only ensures that the hash function returns the same * value on all platforms. It is also required to for a good dispersion of * the hash values' least significant bits. */ #if PY_LITTLE_ENDIAN # define _le64toh(x) ((uint64_t)(x)) #elif defined(__APPLE__) # define _le64toh(x) OSSwapLittleToHostInt64(x) #elif defined(HAVE_LETOH64) # define _le64toh(x) le64toh(x) #else # define _le64toh(x) (((uint64_t)(x) << 56) | \ (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \ (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \ (((uint64_t)(x) << 8) & 0xff00000000ULL) | \ (((uint64_t)(x) >> 8) & 0xff000000ULL) | \ (((uint64_t)(x) >> 24) & 0xff0000ULL) | \ (((uint64_t)(x) >> 40) & 0xff00ULL) | \ ((uint64_t)(x) >> 56)) #endif #ifdef _MSC_VER # define ROTATE(x, b) _rotl64(x, b) #else # define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) #endif #define HALF_ROUND(a,b,c,d,s,t) \ a += b; c += d; \ b = ROTATE(b, s) ^ a; \ d = ROTATE(d, t) ^ c; \ a = ROTATE(a, 32); #define DOUBLE_ROUND(v0,v1,v2,v3) \ HALF_ROUND(v0,v1,v2,v3,13,16); \ HALF_ROUND(v2,v1,v0,v3,17,21); \ HALF_ROUND(v0,v1,v2,v3,13,16); \ HALF_ROUND(v2,v1,v0,v3,17,21); static uint64_t siphash24(uint64_t k0, uint64_t k1, const void *src, ssize_t src_sz) { uint64_t b = (uint64_t)src_sz << 56; const uint8_t *in = (uint8_t*)src; uint64_t v0 = k0 ^ 0x736f6d6570736575ULL; uint64_t v1 = k1 ^ 0x646f72616e646f6dULL; uint64_t v2 = k0 ^ 0x6c7967656e657261ULL; uint64_t v3 = k1 ^ 0x7465646279746573ULL; uint64_t t; uint8_t *pt; while (src_sz >= 8) { uint64_t mi; memcpy(&mi, in, sizeof(mi)); mi = _le64toh(mi); in += sizeof(mi); src_sz -= sizeof(mi); v3 ^= mi; DOUBLE_ROUND(v0,v1,v2,v3); v0 ^= mi; } t = 0; pt = (uint8_t *)&t; switch (src_sz) { case 7: pt[6] = in[6]; /* fall through */ case 6: pt[5] = in[5]; /* fall through */ case 5: pt[4] = in[4]; /* fall through */ case 4: memcpy(pt, in, sizeof(uint32_t)); break; case 3: pt[2] = in[2]; /* fall through */ case 2: pt[1] = in[1]; /* fall through */ case 1: pt[0] = in[0]; /* fall through */ } b |= _le64toh(t); v3 ^= b; DOUBLE_ROUND(v0,v1,v2,v3); v0 ^= b; v2 ^= 0xff; DOUBLE_ROUND(v0,v1,v2,v3); DOUBLE_ROUND(v0,v1,v2,v3); /* modified */ t = (v0 ^ v1) ^ (v2 ^ v3); return t; } ================================================ FILE: base/builtin/dict.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // types ////////////////////////////////////////////////////////////////////////////////////// typedef struct $entry_struct { long hash; $WORD key; $WORD value; // deleted entry has value DELETED } *$entry_t; struct $table_struct { char *$GCINFO; long tb_size; // size of dk_indices array; must be power of 2 long tb_usable; // nr of unused entries in tb_entries (deleted entries are counted as used) long tb_nentries; // nr of used entries in tb_entries int tb_indices[]; // array of indices // after this follows tb_entries array; }; #define DELETED (($WORD)1) #define INIT_SIZE 4 #define DKIX_EMPTY (-1) #define DKIX_DUMMY (-2) /* Used internally */ #define TB_ENTRIES(tb) \ (($entry_t)(&((int*)((tb)->tb_indices))[(tb)->tb_size])) #define PERTURB_SHIFT 5 // Internal routines ////////////////////////////////////////////////////////////////// /* Internal routine used by dictresize() to build a hashtable of entries. %*/ static void build_indices(B_Hashable hashwit, $table oldtable, $table newtable, $entry_t ep, long n) { long mask = newtable->tb_size - 1; for (int ix = 0; ix < n; ix++, ep++) { uint64_t hash; if (oldtable->tb_size > INIT_SIZE) hash = ep->hash; else { hash = fromB_u64(B_hash(hashwit, ep->key)); ep->hash = hash; } unsigned long i = (unsigned long)hash & mask; for (unsigned long perturb = hash; newtable->tb_indices[i] != DKIX_EMPTY;) { perturb >>= PERTURB_SHIFT; i = mask & (i*5 + perturb + 1); } newtable->tb_indices[i] = ix; } } /* Restructure the table by allocating a new table and reinserting all items again. When entries have been deleted, the new table may actually be smaller than the old one. */ static int dictresize(B_Hashable hashwit, B_dict d) { $table oldtable = d->table; long numelements = d->numelements; long newsize, minsize = 3*numelements; $entry_t oldentries, newentries; for (newsize = INIT_SIZE; newsize < minsize; newsize <<= 1); /* Allocate a new table. */ $table newtable = acton_malloc(sizeof(char*) + 3*sizeof(long) + newsize*sizeof(int) + (2*newsize/3)*sizeof(struct $entry_struct)); newtable->tb_size = newsize; newtable->tb_usable = 2*newsize/3-numelements; newtable->tb_nentries = numelements; memset(&(newtable->tb_indices[0]), 0xff, newsize*sizeof(int)); newentries = TB_ENTRIES(newtable); if (numelements > 0) { oldentries = TB_ENTRIES(oldtable); if (oldtable->tb_nentries == numelements) { memcpy(newentries, oldentries, numelements*sizeof(struct $entry_struct)); } else { $entry_t ep = oldentries; for (int i = 0; i < numelements; i++) { while (ep->value == DELETED) ep++; newentries[i] = *ep++; } } if (newsize > INIT_SIZE) build_indices(hashwit, oldtable, newtable, newentries, numelements); } // for (int i=0; i < newsize; i++) printf("%d -> %d\n",i,newtable->tb_indices[i]); // for (int i=0; i < newtable->tb_nentries; i++){ // $entry_t e = newentries + i; // printf("%ld %lu\n", e->hash, ((B_int)e->key)->val.n[0]) d->table = newtable; return 0; } // Search index of hash table from offset of entry table // Only called when the dict is a hashtable (i.e. table->tb_size > INIT_SIZE) static int $lookdict_index($table table, uint64_t hash, int index) { unsigned long mask = (table->tb_size)-1; unsigned long perturb = hash; unsigned long i = (unsigned long)hash & mask; for (;;) { int ix = table->tb_indices[i]; if (ix == index) { return i; } if (ix == DKIX_EMPTY) { return DKIX_EMPTY; } perturb >>= PERTURB_SHIFT; i = mask & (i*5 + perturb + 1); } // unreachable } // Returns index into compact array where hash/key is found // (and returns corresponding value in *res) // or DKIX_EMPTY if no such entry exists int $lookdict(B_dict dict, B_Hashable hashwit, uint64_t hash, $WORD key, $WORD *res) { $table table = dict->table; if (!table) { *res = NULL; //printf("no table\n"); return DKIX_EMPTY; } if (table->tb_size == INIT_SIZE) { // Ignore hash and do linear search for (int ix = 0; ix < (int)table->tb_nentries; ix++) { $entry_t entry = &TB_ENTRIES(table)[ix]; if (entry->value != DELETED && (entry->key == key || (hashwit->$class->__eq__(hashwit,key,entry->key)->val))) { // found an entry with the same or equal key *res = entry->value; return ix; } } //printf("failed linear search\n"); return DKIX_EMPTY; } else { unsigned long mask = (table->tb_size)-1, i = (unsigned long)hash & mask, perturb = hash; int ix; for(;;) { ix = table->tb_indices[i]; // printf("ix = %d\n",ix); if (ix == DKIX_EMPTY) { // Unused slot *res = NULL; // printf("found unused slot\n"); return ix; } if (ix >= 0) { $entry_t entry = &TB_ENTRIES(table)[ix]; if (entry->value != DELETED && (entry->key == key || (entry->hash == hash && hashwit->$class->__eq__(hashwit,key,entry->key)->val))) { // found an entry with the same or equal key *res = entry->value; return ix; } // collision; probe another location } perturb >>= PERTURB_SHIFT; i = (i*5 + perturb + 1) & mask; // printf("collision; perturb is %ld, hash is %ld, mask is %ld, next probe is %ld\n", perturb, hash, mask, i); } // this should be unreachable } } // Internal function to find slot in index array for an item from its hash // when it is known that the key is not present in the dict. static long find_empty_slot($table table, uint64_t hash) { if (table->tb_size==INIT_SIZE) return table->tb_nentries; const unsigned long mask = table->tb_size-1; unsigned long i = (unsigned long)hash & mask; int ix = table->tb_indices[i]; for (unsigned long perturb = hash; ix >= 0;) { perturb >>= PERTURB_SHIFT; i = (i*5 + perturb + 1) & mask; ix = table->tb_indices[i]; } return i; } static void insertdict(B_dict dict, B_Hashable hashwit, uint64_t hash, $WORD key, $WORD value) { $WORD old_value; $table table; $entry_t ep; if (!dict->table || dict->table->tb_usable <= 0) dictresize(hashwit,dict); if (dict->table->tb_size == 2*INIT_SIZE) hash = fromB_u64(B_hash(hashwit, key)); int ix = $lookdict(dict,hashwit,hash,key,&old_value); if (ix == DKIX_EMPTY) { table = dict->table; long newpos = find_empty_slot(table,hash); ep = &TB_ENTRIES(table)[table->tb_nentries]; table->tb_indices[newpos] = table->tb_nentries; ep->key = key; ep->hash = hash; ep->value = value; table->tb_usable--; table->tb_nentries++; dict->numelements++; return; } if (old_value != value) //eq ?? TB_ENTRIES(dict->table)[ix].value = value; return; } // General methods ///////////////////////////////////////////////////////////////////////// B_dict B_dictG_new(B_Hashable hashwit, B_Iterable wit, $WORD iterable) { return $NEW(B_dict,hashwit, wit, iterable); } B_NoneType B_dictD___init__(B_dict dict, B_Hashable hashwit, B_Iterable wit, $WORD iterable) { dict->numelements = 0; dict->table = NULL; if (wit && iterable) { B_Iterator it = wit->$class->__iter__(wit,iterable); while(1) { if ($PUSH()) { B_tuple nxt = (B_tuple)it->$class->__next__(it); B_dictD_setitem(dict,hashwit,nxt->components[0],nxt->components[1]); $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } } return B_None; } B_bool B_dictD___bool__(B_dict self) { return toB_bool(self->numelements>0); } B_str B_dictD___str__(B_dict self) { B_list s2 = B_listD_new(self->numelements); B_IteratorD_dict_items iter = $NEW(B_IteratorD_dict_items,self); B_tuple item; B_SequenceD_list wit = B_SequenceD_listG_witness; for (int i=0; inumelements; i++) { item = (B_tuple)iter->$class->__next__(iter); B_value key = ((B_value)item->components[0]); B_value value = ((B_value)item->components[1]); B_str keystr = key->$class->__repr__(key); B_str valuestr = value ? value->$class->__repr__(value) : to$str("None"); B_str elem = acton_malloc(sizeof(struct B_str)); elem->$class = &B_strG_methods; elem->nbytes = keystr->nbytes+valuestr->nbytes+1; elem->nchars = keystr->nchars+valuestr->nchars+1; elem->str = acton_malloc(elem->nbytes+1); memcpy(elem->str,keystr->str,keystr->nbytes); elem->str[keystr->nbytes] = ':'; memcpy(&elem->str[keystr->nbytes+1],valuestr->str,valuestr->nbytes); elem->str[elem->nbytes] = '\0'; wit->$class->append(wit,s2,elem); } return B_strD_join_par('{',s2,'}'); } B_str B_dictD___repr__(B_dict self) { return B_dictD___str__(self); } void B_dictD___serialize__(B_dict self,$Serial$state state) { B_int prevkey = (B_int)B_dictD_get(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,NULL); if (prevkey) { long pk = fromB_int(prevkey); $val_serialize(-DICT_ID,&pk,state); return; } B_dictD_setitem(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,toB_int(state->row_no)); int blobsize = 4 + (self->table->tb_size + 1) * sizeof(int)/sizeof($WORD); $ROW row = $add_header(DICT_ID,blobsize,state); row->blob[0] = ($WORD)self->numelements; row->blob[1] = ($WORD)self->table->tb_size; row->blob[2] = ($WORD)self->table->tb_usable; row->blob[3] = ($WORD)self->table->tb_nentries; memcpy(&row->blob[4],self->table->tb_indices,self->table->tb_size*sizeof(int)); for (int i=0; itable->tb_nentries; i++) { $entry_t entry = &TB_ENTRIES(self->table)[i]; $step_serialize(toB_u64(entry->hash),state); $step_serialize(entry->key,state); $step_serialize(entry->value,state); } } B_dict B_dictD___deserialize__(B_dict res, $Serial$state state) { $ROW this = state->row; state->row = this->next; state->row_no++; if (this->class_id < 0) { return B_dictD_get(state->done,(B_Hashable)B_HashableD_intG_witness,toB_int((long)this->blob[0]),NULL); } else { if (!res) res = acton_malloc(sizeof(struct B_dict)); B_dictD_setitem(state->done,(B_Hashable)B_HashableD_intG_witness,toB_int(state->row_no-1),res); res->$class = &B_dictG_methods; res->numelements = (long)this->blob[0]; long tb_size = (long)this->blob[1]; res->table = acton_malloc(sizeof(char*) + 3*sizeof(long) + tb_size*sizeof(int) + (2*tb_size/3)*sizeof(struct $entry_struct)); res->table->tb_size = tb_size; res->table->tb_usable = (long)this->blob[2]; res->table->tb_nentries = (long)this->blob[3]; memcpy(res->table->tb_indices,&this->blob[4],tb_size*sizeof(int)); for (int i=0; itable->tb_nentries; i++) { $entry_t entry = &TB_ENTRIES(res->table)[i]; entry->hash = fromB_u64((B_u64)$step_deserialize(state)); entry->key = $step_deserialize(state); entry->value = $step_deserialize(state); } return res; } } // B_OrdD_dict //////////////////////////////////////////////////////////////////////// B_bool B_dictrel(bool directfalse,B_OrdD_dict w, B_dict a, B_dict b) { if (directfalse) { return B_False; }; if (a->numelements == 0) return B_True; B_Hashable wH = w->W_HashableD_AD_OrdD_dict; B_Eq wB = w->W_EqD_BD_OrdD_dict; B_MappingD_dict m = B_MappingD_dictG_new(wH); B_Iterator it = m->$class->keys(m,a); $WORD x,resa,resb; if ($PUSH()) { while(1) { x = it->$class->__next__(it); long h = 0; if (a->table->tb_size > INIT_SIZE) h = fromB_u64(B_hash(wH, x)); int ixa = $lookdict(a, wH, h, x, &resa); int ixb = $lookdict(b, wH, h, x ,&resb); if (ixb<0 || wB->$class->__ne__(wB,resa,resb)->val) { $DROP(); return B_False; } } $DROP(); } else { B_BaseException ex = $POP(); if (! $ISINSTANCE0(ex, B_StopIteration)) $RAISE(ex); } return B_True; } B_bool B_OrdD_dictD___eq__ (B_OrdD_dict w, B_dict a, B_dict b) { return B_dictrel(a->numelements != b->numelements,w,a,b); } B_bool B_OrdD_dictD___ne__ (B_OrdD_dict w, B_dict a, B_dict b) { return toB_bool(!(w->$class->__eq__(w,a,b)->val)); } B_bool B_OrdD_dictD___lt__ (B_OrdD_dict w, B_dict a, B_dict b) { return B_dictrel(a->numelements >= b->numelements,w,a,b); } B_bool B_OrdD_dictD___le__ (B_OrdD_dict w, B_dict a, B_dict b) { return B_dictrel(a->numelements > b->numelements,w,a,b); } B_bool B_OrdD_dictD___gt__ (B_OrdD_dict w, B_dict a, B_dict b) { return toB_bool(!(w->$class->__lt__(w,b,a)->val)); } B_bool B_OrdD_dictD___ge__ (B_OrdD_dict w, B_dict a, B_dict b) { return toB_bool(!(w->$class->__le__(w,b,a)->val)); } // B_MappingD_dict /////////////////////////////////////////////////////////////// // First, define Iterator class for keys ////////////////////////////////////////////////////////////////////////////// static $WORD B_IteratorD_dictD_next(B_IteratorD_dict self) { if (!self->src->table) $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("dict keys iterator terminated"))); int i = self->nxt; $table table = self->src->table; int n = table->tb_nentries; while (i < n) { $entry_t entry = &TB_ENTRIES(table)[i]; if (entry->value != DELETED) { self->nxt = i+1; return entry->key; } i++; } $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("dict keys iterator terminated"))); return NULL; } B_IteratorD_dict B_IteratorD_dictG_new(B_dict dict) { return $NEW(B_IteratorD_dict, dict); } void B_IteratorD_dictD_init(B_IteratorD_dict self, B_dict dict) { self->src = dict; self->nxt = 0; } B_bool B_IteratorD_dictD_bool(B_IteratorD_dict self) { return B_True; } B_str B_IteratorD_dictD_str(B_IteratorD_dict self) { return $FORMAT("", self); } void B_IteratorD_dictD_serialize(B_IteratorD_dict self, $Serial$state state) { $step_serialize(self->src,state); $step_serialize(toB_int(self->nxt),state); } B_IteratorD_dict B_IteratorD_dict__deserialize(B_IteratorD_dict res, $Serial$state state) { if (!res) res = $DNEW( B_IteratorD_dict,state); res->src = (B_dict)$step_deserialize(state); res->nxt = fromB_int((B_int)$step_deserialize(state)); return res; } struct B_IteratorD_dictG_class B_IteratorD_dictG_methods = {"B_IteratorD_dict",UNASSIGNED,($SuperG_class)&B_IteratorG_methods, B_IteratorD_dictD_init, B_IteratorD_dictD_serialize, B_IteratorD_dict__deserialize, B_IteratorD_dictD_bool,B_IteratorD_dictD_str,B_IteratorD_dictD_str, B_IteratorD_dictD_next}; B_Iterator B_MappingD_dictD___iter__ (B_MappingD_dict wit, B_dict dict) { return (B_Iterator)$NEW(B_IteratorD_dict,dict); } B_dict B_MappingD_dictD___fromiter__ (B_MappingD_dict wit, B_Iterable wit2, $WORD iter) { return B_dictG_new(wit->W_HashableD_AD_MappingD_dict, wit2, iter); /* B_Iterator it = wit2->$class->__iter__(wit2,iter); B_Hashable hashwit = wit->W_HashableD_AD_MappingD_dict; B_dict dict = $NEW(B_dict,hashwit,NULL,NULL); B_tuple nxt; while((nxt = (B_tuple)it->$class->__next__(it))) { B_dictD_setitem(dict,hashwit,nxt->components[0],nxt->components[1]); } return dict; */ } B_int B_MappingD_dictD___len__ (B_MappingD_dict wit, B_dict dict) { return toB_int(dict->numelements); } B_bool B_MappingD_dictD___contains__ (B_MappingD_dict wit, B_dict dict, $WORD key) { if (dict->numelements == 0) return B_False; B_Hashable hashwit = wit->W_HashableD_AD_MappingD_dict; $WORD res; long h = 0; if (dict->table->tb_size > INIT_SIZE) h = fromB_u64(B_hash(hashwit, key)); return toB_bool($lookdict(dict,hashwit,h,key,&res) >= 0); } B_bool B_MappingD_dictD___containsnot__ (B_MappingD_dict wit, B_dict dict, $WORD key) { return toB_bool(!B_MappingD_dictD___contains__(wit, dict, key)->val); } $WORD B_MappingD_dictD_get (B_MappingD_dict wit, B_dict dict, $WORD key) { if (!dict->table) return B_None; uint64_t hash = 0; B_Hashable hashwit = wit->W_HashableD_AD_MappingD_dict; if (dict->table->tb_size > INIT_SIZE) hash = fromB_u64(B_hash(hashwit, key)); $WORD res; int ix = $lookdict(dict,hashwit,hash,key,&res); if (ix < 0) return B_None; else return res; } $WORD B_MappingD_dictD_get_def (B_MappingD_dict wit, B_dict dict, $WORD key, $WORD deflt) { if (!dict->table) return deflt; uint64_t hash = 0; B_Hashable hashwit = wit->W_HashableD_AD_MappingD_dict; if (dict->table->tb_size > INIT_SIZE) hash = fromB_u64(B_hash(hashwit, key)); $WORD res; int ix = $lookdict(dict,hashwit,hash,key,&res); if (ix < 0) return deflt; else return res; } $WORD B_MappingD_dictD_pop(B_MappingD_dict wit, B_dict dict, $WORD key) { if (dict->numelements == 0) return B_None; $table table = dict->table; uint64_t hash = 0; B_Hashable hashwit = wit->W_HashableD_AD_MappingD_dict; if (table->tb_size > INIT_SIZE) { hash = fromB_u64(B_hash(hashwit, key)); } $WORD res; int ix = $lookdict(dict,hashwit,hash,key,&res); if (ix < 0) return B_None; else { $entry_t entry = &TB_ENTRIES(table)[ix]; int i = $lookdict_index(table,hash,ix); table->tb_indices[i] = DKIX_DUMMY; res = entry->value; entry->value = DELETED; dict->numelements--; if (10*dict->numelements < dict->table->tb_size) dictresize(hashwit,dict); return res; } } $WORD B_MappingD_dictD_pop_def(B_MappingD_dict wit, B_dict dict, $WORD key, $WORD deflt) { if (dict->numelements == 0) return deflt; $table table = dict->table; uint64_t hash = 0; B_Hashable hashwit = wit->W_HashableD_AD_MappingD_dict; if (table->tb_size > INIT_SIZE) { hash = fromB_u64(B_hash(hashwit, key)); } $WORD res; int ix = $lookdict(dict,hashwit,hash,key,&res); if (ix < 0) return deflt; else { $entry_t entry = &TB_ENTRIES(table)[ix]; int i = $lookdict_index(table,hash,ix); table->tb_indices[i] = DKIX_DUMMY; res = entry->value; entry->value = DELETED; dict->numelements--; if (10*dict->numelements < dict->table->tb_size) dictresize(hashwit,dict); return res; } } B_Iterator B_MappingD_dictD_keys (B_MappingD_dict wit, B_dict dict) { return (B_Iterator)$NEW(B_IteratorD_dict,dict); } // Iterator classes for values and items // values iterator static $WORD B_IteratorD_dict_values_next(B_IteratorD_dict_values self) { int i = self->nxt; $table table = self->src->table; if(!table) $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("dict values iterator terminated"))); int n = table->tb_nentries; while (i < n) { $entry_t entry = &TB_ENTRIES(table)[i]; if (entry->value != DELETED) { self->nxt = i+1; return entry->value; } i++; } $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("dict values iterator terminated"))); return NULL; // to avoid compiler warning } B_IteratorD_dict_values B_IteratorD_dict_valuesG_new(B_dict dict) { return $NEW(B_IteratorD_dict_values, dict); } void B_IteratorD_dict_values_init(B_IteratorD_dict_values self, B_dict dict) { self->src = dict; self->nxt = 0; } B_bool B_IteratorD_dict_values_bool(B_IteratorD_dict_values self) { return B_True; } B_str B_IteratorD_dict_values_str(B_IteratorD_dict_values self) { return $FORMAT("", self); } void B_IteratorD_dict_values_serialize(B_IteratorD_dict_values self, $Serial$state state) { $step_serialize(self->src,state); $step_serialize(toB_int(self->nxt),state); } B_IteratorD_dict_values B_IteratorD_dict_values_deserialize(B_IteratorD_dict_values res, $Serial$state state) { if (!res) res = $DNEW(B_IteratorD_dict_values,state); res->src = (B_dict)$step_deserialize(state); res->nxt = fromB_int((B_int)$step_deserialize(state)); return res; } struct B_IteratorD_dict_valuesG_class B_IteratorD_dict_valuesG_methods = {"B_IteratorD_dict_values",UNASSIGNED,($SuperG_class)&B_IteratorG_methods, B_IteratorD_dict_values_init, B_IteratorD_dict_values_serialize, B_IteratorD_dict_values_deserialize, B_IteratorD_dict_values_bool, B_IteratorD_dict_values_str,B_IteratorD_dict_values_str, B_IteratorD_dict_values_next}; // items iterator static $WORD B_IteratorD_dict_items_next(B_IteratorD_dict_items self) { int i = self->nxt; $table table = self->src->table; if(!table) $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("dict items iterator terminated"))); int n = table->tb_nentries; while (i < n) { $entry_t entry = &TB_ENTRIES(table)[i]; if (entry->value != DELETED) { self->nxt = i+1; return $NEWTUPLE(2,entry->key,entry->value); } i++; } $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("dict items iterator terminated"))); return NULL; // to avoid compiler warning } B_IteratorD_dict_items B_IteratorD_dict_itemsG_new(B_dict dict) { return $NEW(B_IteratorD_dict_items, dict); } void B_IteratorD_dict_items_init(B_IteratorD_dict_items self, B_dict dict) { self->src = dict; self->nxt = 0; } B_bool B_IteratorD_dict_items_bool(B_IteratorD_dict_items self) { return B_True; } B_str B_IteratorD_dict_items_str(B_IteratorD_dict_items self) { return $FORMAT("", self); } void B_IteratorD_dict_items_serialize(B_IteratorD_dict_items self, $Serial$state state) { $step_serialize(self->src,state); $step_serialize(toB_int(self->nxt),state); } B_IteratorD_dict_items B_IteratorD_dict_items_deserialize(B_IteratorD_dict_items res, $Serial$state state) { if (!res) res = $DNEW(B_IteratorD_dict_items,state); res->src = (B_dict)$step_deserialize(state); res->nxt = fromB_int((B_int)$step_deserialize(state)); return res; } struct B_IteratorD_dict_itemsG_class B_IteratorD_dict_itemsG_methods = {"B_IteratorD_dict_items",UNASSIGNED,($SuperG_class)&B_IteratorG_methods, B_IteratorD_dict_items_init, B_IteratorD_dict_items_serialize, B_IteratorD_dict_items_deserialize,B_IteratorD_dict_items_bool, B_IteratorD_dict_items_str, B_IteratorD_dict_items_str, B_IteratorD_dict_items_next}; B_Iterator B_MappingD_dictD_values (B_MappingD_dict wit, B_dict dict) { return (B_Iterator)$NEW(B_IteratorD_dict_values, dict); } B_Iterator B_MappingD_dictD_items (B_MappingD_dict wit, B_dict dict) { return (B_Iterator)$NEW(B_IteratorD_dict_items, dict); } B_NoneType B_MappingD_dictD_update (B_MappingD_dict wit, B_dict dict, B_Iterable wit2, $WORD other) { B_Hashable hashwit = wit->W_HashableD_AD_MappingD_dict; B_Iterator it = wit2->$class->__iter__(wit2,other); while(1) { if ($PUSH()) { B_tuple item = it->$class->__next__(it); B_dictD_setitem(dict,hashwit,item->components[0],item->components[1]); $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } return B_None; } B_tuple B_MappingD_dictD_popitem (B_MappingD_dict wit, B_dict dict) { if (dict->numelements == 0) { return NULL; } B_Hashable hashwit = wit->W_HashableD_AD_MappingD_dict; $table table = dict->table; int ix = table->tb_nentries-1; while (ix >= 0) { $entry_t entry = &TB_ENTRIES(table)[ix]; if (entry->value != DELETED) { if (table->tb_size > INIT_SIZE) { uint64_t hash = fromB_u64(B_hash(hashwit, entry->key)); int i = $lookdict_index(table,hash,ix); table->tb_indices[i] = DKIX_DUMMY; } dict->numelements--; table->tb_nentries = ix; return $NEWTUPLE(2,entry->key,entry->value); } ix--; } return NULL; } $WORD B_MappingD_dictD_setdefault (B_MappingD_dict wit, B_dict dict, $WORD key, $WORD deflt) { if (!deflt) deflt = B_None; B_Hashable hashwit = wit->W_HashableD_AD_MappingD_dict; uint64_t hash = fromB_u64(B_hash(hashwit, key)); $WORD value; int ix = $lookdict(dict,hashwit,hash,key,&value); if (ix >= 0) return value; insertdict(dict, hashwit, hash, key, deflt); return deflt; } // B_IndexedD_MappingD_dict /////////////////////////////////////////////////////////////////////// $WORD B_IndexedD_MappingD_dictD___getitem__(B_IndexedD_MappingD_dict wit, B_dict dict, $WORD key) { if(dict->numelements == 0) $RAISE((B_BaseException)$NEW(B_KeyError, key, to$str("getitem: empty dictionary"))); B_Hashable hashwit = ((B_MappingD_dict)wit->W_Mapping)->W_HashableD_AD_MappingD_dict; uint64_t hash = 0; if (dict->table->tb_size > INIT_SIZE) { hash = fromB_u64(B_hash(hashwit, key)); } $WORD res; int ix = $lookdict(dict,hashwit,hash,key,&res); if (ix < 0) { $RAISE((B_BaseException)$NEW(B_KeyError, key, to$str("getitem: key not in dictionary"))); } return res; } B_NoneType B_IndexedD_MappingD_dictD___setitem__ (B_IndexedD_MappingD_dict wit, B_dict dict, $WORD key, $WORD value) { B_Hashable hashwit = ((B_MappingD_dict)wit->W_Mapping)->W_HashableD_AD_MappingD_dict; uint64_t hash = 0; if (dict->table && dict->table->tb_size > INIT_SIZE) { hash = fromB_u64(B_hash(hashwit, key)); } insertdict(dict, hashwit, hash, key, value); return B_None; } B_NoneType B_IndexedD_MappingD_dictD___delitem__ (B_IndexedD_MappingD_dict wit, B_dict dict, $WORD key) { if (dict->numelements == 0) { return B_None; } $table table = dict->table; uint64_t hash = 0; B_Hashable hashwit = ((B_MappingD_dict)wit->W_Mapping)->W_HashableD_AD_MappingD_dict; if (dict->table->tb_size > INIT_SIZE) { hash = fromB_u64(B_hash(hashwit, key)); } $WORD res; int ix = $lookdict(dict,hashwit,hash,key,&res); //printf("ix = %d\n",ix); if (ix < 0) { // No such key return B_None; } $entry_t entry = &TB_ENTRIES(table)[ix]; int i = $lookdict_index(table,hash,ix); table->tb_indices[i] = DKIX_DUMMY; res = entry->value; //if (res == DELETED) { // $RAISE((B_BaseException)$NEW(B_KeyError, key, to$str("delitem: key already deleted"))); //} entry->value = DELETED; dict->numelements--; if (10*dict->numelements < dict->table->tb_size) dictresize(hashwit,dict); return B_None; } void B_dictD_setitem(B_dict dict, B_Hashable hashwit, $WORD key, $WORD value) { uint64_t hash = 0; if (dict->table && dict->table->tb_size > INIT_SIZE) { hash = fromB_u64(B_hash(hashwit, key)); } insertdict(dict, hashwit, hash, key, value); } $WORD B_dictD_get(B_dict dict, B_Hashable hashwit, $WORD key, $WORD deflt) { if (dict->numelements == 0) return deflt; uint64_t hash = 0; if (dict->table->tb_size > INIT_SIZE) { hash = fromB_u64(B_hash(hashwit, key)); } $WORD res; int ix = $lookdict(dict,hashwit,hash,key,&res); if (ix < 0) return deflt; else return res; } $WORD B_dictD_pop(B_dict dict, B_Hashable hashwit, $WORD key, $WORD deflt) { if (dict->numelements == 0) return deflt; $table table = dict->table; uint64_t hash = 0; if (table->tb_size > INIT_SIZE) { hash = fromB_u64(B_hash(hashwit, key)); } $WORD res; int ix = $lookdict(dict,hashwit,hash,key,&res); if (ix < 0) return deflt; else { $entry_t entry = &TB_ENTRIES(table)[ix]; int i = $lookdict_index(table,hash,ix); table->tb_indices[i] = DKIX_DUMMY; res = entry->value; entry->value = DELETED; dict->numelements--; if (10*dict->numelements < dict->table->tb_size) dictresize(hashwit,dict); return res; } } /* B_dict B_dictD_copy(B_dict dict, B_Hashable hashwit) { B_Iterable w = (B_Iterable)B_MappingD_dictG_witness; return B_dictG_new(hashwit, w, dict); } B_NoneType B_dictD_clear(B_dict dict, B_Hashable hashwit) { $table table = NULL; dict->numelements = 0; return B_None; } */ ================================================ FILE: base/builtin/dict.h ================================================ typedef struct $table_struct *$table; struct B_dict { struct B_dictG_class *$class; long numelements; // nr of elements in dictionary $table table; // the hashtable }; // Iterators over dicts /////////////////////////////////////////////////////// // keys iterator typedef struct B_IteratorD_dict *B_IteratorD_dict; struct B_IteratorD_dictG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_IteratorD_dict, B_dict); void (*__serialize__)(B_IteratorD_dict,$Serial$state); B_IteratorD_dict (*__deserialize__)(B_IteratorD_dict,$Serial$state); B_bool (*__bool__)(B_IteratorD_dict); B_str (*__str__)(B_IteratorD_dict); B_str (*__repr__)(B_IteratorD_dict); $WORD(*__next__)(B_IteratorD_dict); }; struct B_IteratorD_dict { struct B_IteratorD_dictG_class *$class; B_dict src; int nxt; }; extern struct B_IteratorD_dictG_class B_IteratorD_dictG_methods; B_IteratorD_dict B_IteratorD_dictG_new(B_dict); // values iterator typedef struct B_IteratorD_dict_values *B_IteratorD_dict_values; struct B_IteratorD_dict_valuesG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_IteratorD_dict_values, B_dict); void (*__serialize__)(B_IteratorD_dict_values,$Serial$state); B_IteratorD_dict_values (*__deserialize__)(B_IteratorD_dict_values,$Serial$state); B_bool (*__bool__)(B_IteratorD_dict_values); B_str (*__str__)(B_IteratorD_dict_values); B_str (*__repr__)(B_IteratorD_dict_values); $WORD(*__next__)(B_IteratorD_dict_values); }; struct B_IteratorD_dict_values { struct B_IteratorD_dict_valuesG_class *$class; B_dict src; int nxt; }; extern struct B_IteratorD_dict_valuesG_class B_IteratorD_dict_valuesG_methods; B_IteratorD_dict_values B_IteratorD_dict_valuesG_new(B_dict); // items iterator typedef struct B_IteratorD_dict_items *B_IteratorD_dict_items; struct B_IteratorD_dict_itemsG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_IteratorD_dict_items, B_dict); void (*__serialize__)(B_IteratorD_dict_items,$Serial$state); B_IteratorD_dict_items (*__deserialize__)(B_IteratorD_dict_items,$Serial$state); B_bool (*__bool__)(B_IteratorD_dict_items); B_str (*__str__)(B_IteratorD_dict_items); B_str (*__repr__)(B_IteratorD_dict_items); $WORD(*__next__)(B_IteratorD_dict_items); }; struct B_IteratorD_dict_items { struct B_IteratorD_dict_itemsG_class *$class; B_dict src; int nxt; }; extern struct B_IteratorD_dict_itemsG_class B_IteratorD_dict_itemsG_methods; B_IteratorD_dict_items B_IteratorD_dict_itemsG_new(B_dict); // Convenience methods used for (de)serialization void B_dictD_setitem(B_dict dict, B_Hashable hashwit, $WORD key, $WORD value); $WORD B_dictD_get(B_dict dict, B_Hashable hashwit, $WORD key, $WORD deflt); ================================================ FILE: base/builtin/env.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef __linux__ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #endif #define GC_THREADS 1 #include #if defined(_WIN32) || defined(_WIN64) #else #include #endif #include #include #include "env.h" #include "../rts/io.h" #include "../rts/log.h" extern char rts_exit; extern int return_val; // Env ///////////////////////////////////////////////////////////////////////// $R B_EnvD_stdout_writeG_local (B_Env self, $Cont c$cont, B_str s) { printf("%s", s->str); return $R_CONT(c$cont, B_None); } $R B_EnvD_set_stdinG_local (B_Env self, $Cont c$cont, B_bool canonical, B_bool echo) { #if defined(_WIN32) || defined(_WIN64) #else struct termios attr; tcgetattr(STDIN_FILENO, &attr); if (canonical != NULL) { if (fromB_bool(canonical) == true) { attr.c_lflag |= ICANON; // Set ICANON flag } else { attr.c_lflag &= ~ICANON; // Remove ICANON flag } } if (echo != NULL) { if (fromB_bool(echo) == true) { attr.c_lflag |= ECHO; } else { attr.c_lflag &= ~ECHO; } } tcsetattr(STDIN_FILENO, TCSANOW, &attr); #endif return $R_CONT(c$cont, B_None); } void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { if (nread < 0){ if (nread == UV_EOF) { uv_close((uv_handle_t *)stream, NULL); } } else if (nread > 0) { if (stream->data) { $action cb = stream->data; cb->$class->__asyn__(cb, to$bytesD_len(buf->base, nread)); } } } $R B_EnvD__on_stdin_bytesG_local (B_Env self, $Cont c$cont, $action cb) { // This should be the only call in env that does IO stuff, so it is safe to // pin affinity here (and not earlier).. pin_actor_affinity(); uv_tty_t *tty = acton_malloc(sizeof(uv_tty_t)); uv_tty_init(get_uv_loop(), tty, STDIN_FILENO, 1); tty->data = cb; uv_read_start((uv_stream_t*)tty, alloc_buffer, read_stdin); return $R_CONT(c$cont, B_None); } $R B_EnvD_exitG_local (B_Env self, $Cont c$cont, B_int n) { return_val = fromB_int(n); rts_shutdown(); return $R_CONT(c$cont, B_None); } B_Env B_EnvG_newactor(B_WorldCap wc, B_SysCap sc, B_list args) { B_Env $tmp = $NEWACTOR(B_Env); $tmp->cap = wc; $tmp->args = args; $tmp->syscap = sc; $tmp->auth = $tmp->cap; $tmp->argv = $tmp->args; $tmp->$affinity = 0; // hard-coded to special worker on the main thread serialize_state_shortcut(($Actor)$tmp); return $tmp; } B_SysCap B_SysCapG_new() { B_SysCap $tmp = acton_malloc(sizeof(struct B_SysCap)); $tmp->$class = &B_SysCapG_methods; // B_SysCapG_methods.__init__($tmp); return $tmp; } B_NoneType B_SysCapD___init__ (B_SysCap self) { return B_None; } B_WorldCap B_WorldCapG_new() { B_WorldCap $tmp = acton_malloc(sizeof(struct B_WorldCap)); $tmp->$class = &B_WorldCapG_methods; // B_WorldCapG_methods.__init__($tmp); return $tmp; } B_NoneType B_WorldCapD___init__ (B_WorldCap self) { return B_None; } ================================================ FILE: base/builtin/env.h ================================================ #pragma once B_Env B_EnvG_newactor (B_WorldCap, B_SysCap, B_list); B_SysCap B_SysCapG_new(); B_NoneType B_SysCapD___init__ (B_SysCap self); B_WorldCap B_WorldCapG_new(); B_NoneType B_WorldCapD___init__ (B_WorldCap self); ================================================ FILE: base/builtin/exceptions.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ void B_BaseExceptionD___serialize__ (B_BaseException, $Serial$state); B_bool B_valueD___bool__ (B_value); B_str B_valueD___str__ (B_value); B_str B_valueD___repr__ (B_value); B_NoneType $SEQD___init__ ($SEQ self) { self->error_message = NULL; return B_None; } $SEQ $SEQD___deserialize__ ($SEQ self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct $SEQ)); self->$class = &$SEQG_methods; return self; } self = $DNEW($SEQ, state); } self->error_message = $step_deserialize(state); return self; } $SEQ $SEQG_new() { $SEQ $tmp = acton_malloc(sizeof(struct $SEQ)); $tmp->$class = &$SEQG_methods; $SEQG_methods.__init__($tmp); return $tmp; } struct $SEQG_class $SEQG_methods = { .$GCINFO = "$SEQ", .$superclass = ($SuperG_class)&B_ExceptionG_methods, .__init__ = $SEQD___init__, .__bool__ = (B_bool (*) ($SEQ))B_valueD___bool__, .__str__ = (B_str (*) ($SEQ))B_valueD___str__, .__repr__ = (B_str (*) ($SEQ))B_valueD___repr__, .__serialize__ = (void (*) ($SEQ, $Serial$state))B_BaseExceptionD___serialize__, .__deserialize__ = $SEQD___deserialize__ }; $BRK $BRKD___deserialize__ ($BRK self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct $BRK)); self->$class = &$BRKG_methods; return self; } self = $DNEW($BRK, state); } self->error_message = NULL; return self; } $BRK $BRKG_new() { $BRK $tmp = acton_malloc(sizeof(struct $BRK)); $tmp->$class = &$BRKG_methods; $BRKG_methods.__init__($tmp); return $tmp; } struct $BRKG_class $BRKG_methods = { .$GCINFO = "$BRK", .$superclass = ($SuperG_class)&B_ExceptionG_methods, .__init__ = (B_NoneType (*) ($BRK))$SEQD___init__, .__bool__ = (B_bool (*) ($BRK))B_valueD___bool__, .__str__ = (B_str (*) ($BRK))B_valueD___str__, .__repr__ = (B_str (*) ($BRK))B_valueD___repr__, .__serialize__ = (void (*) ($BRK, $Serial$state))B_BaseExceptionD___serialize__, .__deserialize__ = $BRKD___deserialize__ }; $CNT $CNTD___deserialize__ ($CNT self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct $CNT)); self->$class = &$CNTG_methods; return self; } self = $DNEW($CNT, state); } self->error_message = $step_deserialize(state); return self; } $CNT $CNTG_new() { $CNT $tmp = acton_malloc(sizeof(struct $CNT)); $tmp->$class = &$CNTG_methods; $CNTG_methods.__init__($tmp); return $tmp; } struct $CNTG_class $CNTG_methods = { .$GCINFO = "$CNT", .$superclass = ($SuperG_class)&B_ExceptionG_methods, .__init__ = (B_NoneType (*) ($CNT))$SEQD___init__, .__bool__ = (B_bool (*) ($CNT))B_valueD___bool__, .__str__ = (B_str (*) ($CNT))B_valueD___str__, .__repr__ = (B_str (*) ($CNT))B_valueD___repr__, .__serialize__ = (void (*) ($CNT, $Serial$state))B_BaseExceptionD___serialize__, .__deserialize__ = $CNTD___deserialize__ }; B_NoneType $RETD___init__ ($RET self, B_value val) { self->error_message = NULL; self->val = val; return B_None; } void $RETD___serialize__ ($RET self, $Serial$state state) { $step_serialize(self->val, state); } $RET $RETD___deserialize__ ($RET self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct $RET)); self->$class = &$RETG_methods; return self; } self = $DNEW($RET, state); } self->error_message = $step_deserialize(state); self->val = $step_deserialize(state); return self; } $RET $RETG_new(B_value G_1) { $RET $tmp = acton_malloc(sizeof(struct $RET)); $tmp->$class = &$RETG_methods; $RETG_methods.__init__($tmp, G_1); return $tmp; } struct $RETG_class $RETG_methods = { .$GCINFO = "$RET", .$superclass = ($SuperG_class)&B_ExceptionG_methods, .__init__ = $RETD___init__, .__bool__ = (B_bool (*) ($RET))B_valueD___bool__, .__str__ = (B_str (*) ($RET))B_valueD___str__, .__repr__ = (B_str (*) ($RET))B_valueD___repr__, .__serialize__ = $RETD___serialize__, .__deserialize__ = $RETD___deserialize__ }; $WORD $raiseValueError(B_str msg) { $RAISE((B_BaseException)$NEW(B_ValueError,msg)); return ($WORD)0; } ================================================ FILE: base/builtin/exceptions.h ================================================ #include struct JumpBuf; typedef struct JumpBuf *JumpBuf; struct JumpBuf { jmp_buf buf; B_BaseException xval; JumpBuf prev; }; void $RAISE(B_BaseException e); JumpBuf $PUSH_BUF(); void $DROP(); B_BaseException $POP(); #define $PUSH() (!setjmp($PUSH_BUF()->buf)) /* Exceptions hierarchy in Python 3.8 according to https://docs.python.org/3/library/exceptions.html BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StopAsyncIteration +-- ArithmeticError | +-- FloatingPointError *** | +-- OverflowError | +-- ZeroDivisionError +-- AssertionError +-- AttributeError +-- BufferError *** +-- EOFError +-- ImportError *** | +-- ModuleNotFoundError *** +-- LookupError | +-- IndexError | +-- KeyError +-- MemoryError +-- NameError *** | +-- UnboundLocalError *** +-- OSError | +-- BlockingIOError | +-- ChildProcessError | +-- ConnectionError | | +-- BrokenPipeError | | +-- ConnectionAbortedError | | +-- ConnectionRefusedError | | +-- ConnectionResetError | +-- FileExistsError | +-- FileNotFoundError | +-- InterruptedError | +-- IsADirectoryError | +-- NotADirectoryError | +-- PermissionError | +-- ProcessLookupError | +-- TimeoutError +-- ReferenceError *** +-- RuntimeError | +-- NotImplementedError | +-- RecursionError +-- SyntaxError *** | +-- IndentationError | +-- TabError +-- SystemError +-- TypeError *** +-- ValueError | +-- UnicodeError | +-- UnicodeDecodeError | +-- UnicodeEncodeError | +-- UnicodeTranslateError +-- Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning +-- ResourceWarning Plus the (hidden) primitive exceptions that implement control flow in the presence of finalizers: +-- $SEQ +-- $BRK +-- $CNT +-- $RET */ struct $SEQ; struct $BRK; struct $CNT; struct $RET; typedef struct $SEQ *$SEQ; typedef struct $BRK *$BRK; typedef struct $CNT *$CNT; typedef struct $RET *$RET; struct $SEQG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) ($SEQ); void (*__serialize__) ($SEQ, $Serial$state); $SEQ (*__deserialize__) ($SEQ, $Serial$state); B_bool (*__bool__) ($SEQ); B_str (*__str__) ($SEQ); B_str (*__repr__) ($SEQ); }; struct $SEQ { struct $SEQG_class *$class; B_str error_message; }; struct $BRKG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) ($BRK); void (*__serialize__) ($BRK, $Serial$state); $BRK (*__deserialize__) ($BRK, $Serial$state); B_bool (*__bool__) ($BRK); B_str (*__str__) ($BRK); B_str (*__repr__) ($BRK); }; struct $BRK { struct $BRKG_class *$class; B_str error_message; }; struct $CNTG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) ($CNT); void (*__serialize__) ($CNT, $Serial$state); $CNT (*__deserialize__) ($CNT, $Serial$state); B_bool (*__bool__) ($CNT); B_str (*__str__) ($CNT); B_str (*__repr__) ($CNT); }; struct $CNT { struct $CNTG_class *$class; B_str error_message; }; struct $RETG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) ($RET, B_value); void (*__serialize__) ($RET, $Serial$state); $RET (*__deserialize__) ($RET, $Serial$state); B_bool (*__bool__) ($RET); B_str (*__str__) ($RET); B_str (*__repr__) ($RET); }; struct $RET { struct $RETG_class *$class; B_str error_message; B_value val; }; extern struct $SEQG_class $SEQG_methods; extern struct $BRKG_class $BRKG_methods; extern struct $CNTG_class $CNTG_methods; extern struct $RETG_class $RETG_methods; $SEQ $SEQG_new(); $BRK $BRKG_new(); $CNT $CNTG_new(); $RET $RETG_new(B_value); $WORD $raiseValueError(B_str str); ================================================ FILE: base/builtin/float.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include // General methods /////////////////////////////////////////////////////////////////////// B_float B_floatG_new(B_atom a) { if ($ISINSTANCE0(a,B_int)) return to$float((double)((B_int)a)->val); if ($ISINSTANCE0(a,B_i32)) return to$float((double)((B_i32)a)->val); if ($ISINSTANCE0(a,B_i16)) return to$float((double)((B_i16)a)->val); if ($ISINSTANCE0(a,B_u64)) return to$float((double)((B_u64)a)->val); if ($ISINSTANCE0(a,B_u32)) return to$float((double)((B_u32)a)->val); if ($ISINSTANCE0(a,B_u16)) return to$float((double)((B_u16)a)->val); if ($ISINSTANCE0(a,B_bigint)) { zz_struct aval = ((B_bigint)a)->val; if (aval.size == 0) return to$float(0.0); if (labs(aval.size) > 16) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("float(): int value too big for type float"))); double pow = 1.0; double res = 0.0; for (int i = 0; i<(labs(aval.size)); i++) { res += aval.n[i] * pow; pow *= 18446744073709551616.0; // literal is 2^64 } return to$float(aval.size<0 ? -res : res); } if ($ISINSTANCE0(a,B_float)) return (B_float)a; if ($ISINSTANCE0(a,B_bool)) return to$float((double)((B_bool)a)->val); if ($ISINSTANCE0(a,B_str)) { double x; int c; sscanf((char *)((B_str)a)->str,"%lf%n",&x,&c); if (c==((B_str)a)->nbytes) return to$float(x); else $RAISE((B_BaseException)$NEW(B_ValueError,to$str("float_fromatom(): invalid str literal for type float"))); } fprintf(stderr,"internal error: float_fromatom: argument not of atomic type"); exit(-1); } B_NoneType B_floatD___init__(B_float self, B_atom a){ self->val = B_floatG_new(a)->val; return B_None; } void B_floatD___serialize__(B_float self, $Serial$state state) { $val_serialize(FLOAT_ID,&self->val,state); } B_float B_floatD___deserialize__(B_float self, $Serial$state state) { $WORD w = $val_deserialize(state); double x; memcpy(&x,&w,sizeof($WORD)); return to$float(x); } B_bool B_floatD___bool__(B_float x) { return toB_bool(x->val != 0.0); } B_str B_floatD___str__(B_float x) { return $FORMAT("%g", x->val); } B_str B_floatD___repr__(B_float x) { return $FORMAT("%g", x->val); } B_float to$float(double x) { B_float res = acton_malloc(sizeof(struct B_float)); res->$class = &B_floatG_methods; res->val = x; return res; } B_float toB_float(double x) { B_float res = acton_malloc(sizeof(struct B_float)); res->$class = &B_floatG_methods; res->val = x; return res; } double fromB_float(B_float x) { return x->val; } // B_RealFloatD_float ///////////////////////////////////////////////////////////////////////// B_float B_RealFloatD_floatD___add__(B_RealFloatD_float wit, B_float a, B_float b) { return to$float(fromB_float(a) + fromB_float(b)); } B_float B_RealFloatD_floatD___zero__(B_RealFloatD_float wit) { return to$float(0.0); } B_float B_RealFloatD_floatD___fromatom__(B_RealFloatD_float wit, B_atom a) { return B_floatG_new(a); } B_complex B_RealFloatD_floatD___complex__(B_RealFloatD_float wit, B_float a) { return toB_complex(a->val); } B_float B_RealFloatD_floatD___mul__(B_RealFloatD_float wit, B_float a, B_float b) { return to$float(fromB_float(a) * fromB_float(b)); } B_float B_RealFloatD_floatD___pow__(B_RealFloatD_float wit, B_float a, B_float b) { return to$float(exp(fromB_float(b) * log(fromB_float(a)))); } B_float B_RealFloatD_floatD___neg__(B_RealFloatD_float wit, B_float a) { return to$float(-fromB_float(a)); } B_float B_RealFloatD_floatD___pos__(B_RealFloatD_float wit, B_float a) { return a; } $WORD B_RealFloatD_floatD_real(B_RealFloatD_float wit, B_float a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } $WORD B_RealFloatD_floatD_imag(B_RealFloatD_float wit, B_float a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)to$float(0.0)); } $WORD B_RealFloatD_floatD___abs__(B_RealFloatD_float wit, B_float a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)to$float(fabs(fromB_float(a)))); } B_float B_RealFloatD_floatD_conjugate(B_RealFloatD_float wit, B_float a) { return a; } B_float B_RealFloatD_floatD___float__ (B_RealFloatD_float wit, B_float x) { return x; } $WORD B_RealFloatD_floatD___trunc__ (B_RealFloatD_float wit, B_float x, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_int((long)trunc(fromB_float(x)))); } $WORD B_RealFloatD_floatD___floor__ (B_RealFloatD_float wit, B_float x, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_int((long)floor(fromB_float(x)))); } $WORD B_RealFloatD_floatD___ceil__ (B_RealFloatD_float wit, B_float x, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_int((long)ceil(fromB_float(x)))); } B_float B_RealFloatD_floatD___round__ (B_RealFloatD_float wit, B_float x, B_int p) { double pval = p==NULL ? 0.0 : (double)fromB_int(p); double p10 = pow(10.0,pval); return to$float(round(x->val * p10)/p10); } // B_MinusD_RealFloatD_float //////////////////////////////////////////////////////////////////////////////////////// B_float B_MinusD_RealFloatD_floatD___sub__(B_MinusD_RealFloatD_float wit, B_float a, B_float b) { return to$float(fromB_float(a) - fromB_float(b)); } // B_DivD_float //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_floatD___truediv__(B_DivD_float wit, B_float a, B_float b) { return to$float(fromB_float(a) / fromB_float(b)); } // B_OrdD_float //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_floatD___eq__ (B_OrdD_float wit, B_float a, B_float b) { return toB_bool(a->val == b->val); } B_bool B_OrdD_floatD___ne__ (B_OrdD_float wit, B_float a, B_float b) { return toB_bool(a->val != b->val); } B_bool B_OrdD_floatD___lt__ (B_OrdD_float wit, B_float a, B_float b) { return toB_bool(a->val < b->val); } B_bool B_OrdD_floatD___le__ (B_OrdD_float wit, B_float a, B_float b) { return toB_bool(a->val <= b->val); } B_bool B_OrdD_floatD___gt__ (B_OrdD_float wit, B_float a, B_float b) { return toB_bool(a->val > b->val); } B_bool B_OrdD_floatD___ge__ (B_OrdD_float wit, B_float a, B_float b) { return toB_bool(a->val >= b->val); } // B_HashableD_float /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_floatD___eq__(B_HashableD_float wit, B_float a, B_float b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_floatD___neq__(B_HashableD_float wit, B_float a, B_float b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_floatD_hash(B_HashableD_float wit, B_float a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val), 8)); return B_None; } ================================================ FILE: base/builtin/float.h ================================================ struct B_float { struct B_floatG_class *$class; double val; }; // #define B_RealD_floatG_new(...) B_RealFloatG_new(__VA_ARGS__) // #define B_RealD_float B_RealFloat B_float to$float(double x); // Dare not remove this; possibly used in compiler...? B_float toB_float(double x); double fromB_float(B_float x); B_float B_floatG_new(B_atom a); #define float_DIV(x,y) (x/y) #define float_pow(x,y) (pow(x,y)) ================================================ FILE: base/builtin/function.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //////////////////////////////////////////////////////////////////////////////////////// B_bool $procD___bool__($proc self) { return B_True; } B_str $procD___str__($proc self) { return $FORMAT("", self); } B_bool $actionD___bool__($action self) { return B_True; } B_str $actionD___str__($action self) { return $FORMAT("", self); } B_bool $mutD___bool__($mut self) { return B_True; } B_str $mutD___str__($mut self) { return $FORMAT("", self); } B_bool $pureD___bool__($pure self) { return B_True; } B_str $pureD___str__($pure self) { return $FORMAT("", self); } void $ContD___init__($Cont $this) { // Empty } B_bool $ContD___bool__($Cont self) { return B_True; } B_str $ContD___str__($Cont self) { return $FORMAT("<$Cont closure at %p>", self); } void $ContD___serialize__($Cont self, $Serial$state state) { // Empty } $Cont $ContD___deserialize__($Cont self, $Serial$state state) { return $DNEW($Cont,state); } struct $ContG_class $ContG_methods = { "$Cont", UNASSIGNED, NULL, $ContD___init__, $ContD___serialize__, $ContD___deserialize__, $ContD___bool__, $ContD___str__, $ContD___str__, NULL /* __call__ */ }; struct $procG_class $procG_methods = { "$proc", UNASSIGNED, NULL, NULL, /* __init__ */ NULL, /* __serialize__ */ NULL, /* __deserialize__ */ $procD___bool__, $procD___str__, $procD___str__, NULL, /* __call__ */ NULL /* __exec__ */ }; struct $actionG_class $actionG_methods = { "$action", UNASSIGNED, NULL, NULL, /* __init__ */ NULL, /* __serialize__ */ NULL, /* __deserialize__ */ $actionD___bool__, $actionD___str__, $actionD___str__, NULL, /* __call__ */ NULL, /* __exec__ */ NULL /* __asyn__ */ }; struct $mutG_class $mutG_methods = { "$mut", UNASSIGNED, NULL, NULL, /* __init__ */ NULL, /* __serialize__ */ NULL, /* __deserialize__ */ $mutD___bool__, $mutD___str__, $mutD___str__, NULL, /* __call__ */ NULL, /* __exec__ */ NULL /* __eval__ */ }; struct $pureG_class $pureG_methods = { "$pure", UNASSIGNED, NULL, NULL, /* __init__ */ NULL, /* __serialize__ */ NULL, /* __deserialize__ */ $pureD___bool__, $pureD___str__, $pureD___str__, NULL, /* __call__ */ NULL, /* __exec__ */ NULL /* __eval__ */ }; ================================================ FILE: base/builtin/function.h ================================================ #pragma once struct $ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($Cont); void (*__serialize__)($Cont, $Serial$state); $Cont (*__deserialize__)($Cont, $Serial$state); B_bool (*__bool__)($Cont); B_str (*__str__)($Cont); B_str (*__repr__)($Cont); $R (*__call__)($Cont, $WORD); }; struct $Cont { struct $ContG_class *$class; }; extern struct $ContG_class $ContG_methods; void $ContD___init__($Cont); B_bool $ContD___bool__($Cont); B_str $ContD___str__($Cont); void $ContD___serialize__($Cont, $Serial$state); $Cont $ContD___deserialize__($Cont, $Serial$state); struct $procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($proc); void (*__serialize__)($proc, $Serial$state); $proc (*__deserialize__)($proc, $Serial$state); B_bool (*__bool__)($proc); B_str (*__str__)($proc); B_str (*__repr__)($proc); $R (*__call__)($proc, $Cont, $WORD); $R (*__exec__)($proc, $Cont, $WORD); }; struct $proc { struct $procG_class *$class; }; extern struct $procG_class $procG_methods; struct $actionG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($action); void (*__serialize__)($action, $Serial$state); $action (*__deserialize__)($action, $Serial$state); B_bool (*__bool__)($action); B_str (*__str__)($action); B_str (*__repr__)($action); $R (*__call__)($action, $Cont, $WORD); $R (*__exec__)($action, $Cont, $WORD); B_Msg (*__asyn__)($action, $WORD); }; struct $action { struct $actionG_class *$class; }; extern struct $actionG_class $actionG_methods; struct $mutG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($mut); void (*__serialize__)($mut, $Serial$state); $mut (*__deserialize__)($mut, $Serial$state); B_bool (*__bool__)($mut); B_str (*__str__)($mut); B_str (*__repr__)($mut); $R (*__call__)($mut, $Cont, $WORD); $R (*__exec__)($mut, $Cont, $WORD); $WORD (*__eval__)($mut, $WORD); }; struct $mut { struct $mutG_class *$class; }; extern struct $mutG_class $mutG_methods; struct $pureG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($pure); void (*__serialize__)($pure, $Serial$state); $pure (*__deserialize__)($pure, $Serial$state); B_bool (*__bool__)($pure); B_str (*__str__)($pure); B_str (*__repr__)($pure); $R (*__call__)($pure, $Cont, $WORD); $R (*__exec__)($pure, $Cont, $WORD); $WORD (*__eval__)($pure, $WORD); }; struct $pure { struct $pureG_class *$class; }; extern struct $pureG_class $pureG_methods; ////////////////////////////////////////////////////////////////////////////////// struct $action2; typedef struct $action2 *$action2; struct $action2G_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($action2); void (*__serialize__)($action2, $Serial$state); $action2 (*__deserialize__)($action2, $Serial$state); B_bool (*__bool__)($action2); B_str (*__str__)($action2); B_str (*__repr__)($action2); $R (*__call__)($action2, $Cont, $WORD, $WORD); $R (*__exec__)($action2, $Cont, $WORD, $WORD); B_Msg (*__asyn__)($action2, $WORD, $WORD); }; struct $action2 { struct $action2G_class *$class; }; struct $action3; typedef struct $action3 *$action3; struct $action3G_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($action3); void (*__serialize__)($action3, $Serial$state); $action3 (*__deserialize__)($action3, $Serial$state); B_bool (*__bool__)($action3); B_str (*__str__)($action3); B_str (*__repr__)($action3); $R (*__call__)($action3, $Cont, $WORD, $WORD, $WORD); $R (*__exec__)($action3, $WORD, $WORD, $WORD); B_Msg (*__asyn__)($action3, $WORD, $WORD, $WORD); }; struct $action3 { struct $action3G_class *$class; }; ================================================ FILE: base/builtin/hasher.c ================================================ B_NoneType B_hasherD___init__ (B_hasher self, B_u64 seed) { self->_hasher = zig_hash_wyhash_init(seed ? fromB_u64(seed) : 0); return B_None; } B_NoneType B_hasherD_update (B_hasher self, B_bytes data) { zig_hash_wyhash_update(self->_hasher, data); return B_None; } B_u64 B_hasherD_finalize (B_hasher self) { uint64_t h = zig_hash_wyhash_final(self->_hasher); B_u64 result = toB_u64(h); return result; } B_bool B_hasherD___bool__(B_hasher h) { return B_True; } B_str B_hasherD___str__(B_hasher self) { return $FORMAT("", self); } B_str B_hasherD___repr__(B_hasher self) { return $FORMAT("",self); } B_hasher B_hasherG_new(B_u64 seed) { return $NEW(B_hasher, seed); } void B_hasherD___serialize__(B_hasher self, $Serial$state state) { // TODO } B_hasher B_hasherD___deserialize__(B_hasher self, $Serial$state state) { // TODO return B_hasherG_new(toB_u64(0)); } ================================================ FILE: base/builtin/hasher.h ================================================ struct B_hasher; typedef struct B_hasher *B_hasher; /* struct B_hasherG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (B_hasher, u64); void (*__serialize__) (B_hasher, $Serial$state); B_hasher (*__deserialize__) (B_hasher, $Serial$state); B_bool (*__bool__) (B_hasher); B_str (*__str__) (B_hasher); B_str (*__repr__) (B_hasher); B_NoneType (*update) (B_hasher, B_bytes); B_u64 (*finalize) (B_hasher); }; */ struct B_hasher { struct B_hasherG_class *$class; void *_hasher; }; extern struct B_hasherG_class B_hasherG_methods; B_hasher B_hasherG_new(B_u64); void *zig_hash_wyhash_init(uint64_t seed); void zig_hash_wyhash_update(void *hasher, B_bytes data); uint64_t zig_hash_wyhash_final(void *hasher); uint64_t zig_hash_wyhash_hash(uint64_t seed, B_bytes data); ================================================ FILE: base/builtin/i16.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Auxiliary ////////////////////////////////////////////////////////////////////////////// // only called with e>=0. short i16_pow(short a, short e) { if (e == 0) return 1; if (e == 1) return a; if (e%2 == 0) return i16_pow(a*a,e/2); return a * i16_pow(a*a,e/2); } // General methods /////////////////////////////////////////////////////////////////////// B_i16 B_i16G_new(B_atom a, B_int base) { B_bigint b = B_bigintG_new(a, base); unsigned long n = b->val.n[0]; long sz = b->val.size; if (labs(sz) > 1 || (sz==1 && n > 0x7ffful) || sz == -1 && n > 0x8000ul) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "i16(): value %s out of range for type i16",get_str(&b->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_i16((short)(n*sz)); } B_NoneType B_i16D___init__(B_i16 self, B_atom a, B_int base){ self->val = B_i16G_new(a,base)->val; return B_None; } void B_i16D___serialize__(B_i16 n, $Serial$state state) { $val_serialize(I16_ID,&n->val,state); } B_i16 B_i16D___deserialize__(B_i16 n, $Serial$state state) { return toB_i16((short)(uintptr_t)$val_deserialize(state)); } B_bool B_i16D___bool__(B_i16 n) { return toB_bool(n->val != 0); } B_str B_i16D___str__(B_i16 n) { return $FORMAT("%hd", n->val); } B_str B_i16D___repr__(B_i16 n) { return $FORMAT("%hd", n->val); } B_i16 toB_i16(short i) { B_i16 res = acton_malloc(sizeof(struct B_i16)); res->$class = &B_i16G_methods; res->val = i; return res; } short fromB_i16(B_i16 w) { return w->val; } // B_IntegralD_i16 ///////////////////////////////////////////////////////////////////////// B_i16 B_IntegralD_i16D___add__(B_IntegralD_i16 wit, B_i16 a, B_i16 b) { return toB_i16(a->val + b->val); } B_i16 B_IntegralD_i16D___zero__(B_IntegralD_i16 wit) { return toB_i16(0); } B_complex B_IntegralD_i16D___complex__(B_IntegralD_i16 wit, B_i16 a) { return toB_complex((double)a->val); } B_i16 B_IntegralD_i16D___fromatom__(B_IntegralD_i16 wit, B_atom a) { return B_i16G_new(a,NULL); } B_i16 B_IntegralD_i16D___mul__(B_IntegralD_i16 wit, B_i16 a, B_i16 b) { return toB_i16(a->val * b->val); } B_i16 B_IntegralD_i16D___pow__(B_IntegralD_i16 wit, B_i16 a, B_i16 b) { if ( b->val < 0) { // raise VALUEERROR; return NULL; } return toB_i16(i16_pow(a->val,b->val)); } B_i16 B_IntegralD_i16D___neg__(B_IntegralD_i16 wit, B_i16 a) { return toB_i16(-a->val); } B_i16 B_IntegralD_i16D___pos__(B_IntegralD_i16 wit, B_i16 a) { return a; } $WORD B_IntegralD_i16D_real(B_IntegralD_i16 wit, B_i16 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } $WORD B_IntegralD_i16D_imag(B_IntegralD_i16 wit, B_i16 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_i16(0L)); } $WORD B_IntegralD_i16D___abs__(B_IntegralD_i16 wit, B_i16 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_i16(labs(a->val))); } B_i16 B_IntegralD_i16D_conjugate(B_IntegralD_i16 wit, B_i16 a) { return a; } B_float B_IntegralD_i16D___float__ (B_IntegralD_i16 wit, B_i16 n) { return to$float((double)n->val); } $WORD B_IntegralD_i16D___trunc__ (B_IntegralD_i16 wit, B_i16 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_i16D___floor__ (B_IntegralD_i16 wit, B_i16 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_i16D___ceil__ (B_IntegralD_i16 wit, B_i16 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } B_i16 B_IntegralD_i16D___round__ (B_IntegralD_i16 wit, B_i16 n, B_int p) { short nval = n->val; if (nval<0) return toB_i16(-B_IntegralD_i16D___round__(wit,toB_i16(-nval),p)->val); short pval = p==NULL ? 0 : fromB_int(p); if (pval>=0) return n; short p10 = i16_pow(10,-pval); short res = nval/p10; if (nval%p10 * 2 > p10) res++; return toB_i16 (res * p10); } $WORD B_IntegralD_i16D_numerator (B_IntegralD_i16 wit, B_i16 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_i16D_denominator (B_IntegralD_i16 wit, B_i16 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_i16(1L)); } B_int B_IntegralD_i16D___int__ (B_IntegralD_i16 wit, B_i16 n) { return B_intG_new((B_atom)n,NULL); } B_int B_IntegralD_i16D___index__(B_IntegralD_i16 wit, B_i16 n) { return B_intG_new((B_atom)n,NULL); } B_tuple B_IntegralD_i16D___divmod__(B_IntegralD_i16 wit, B_i16 a, B_i16 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); short n = a->val; short d = b->val; return $NEWTUPLE(2, toB_i16(n/d), toB_i16(n%d)); } B_i16 B_IntegralD_i16D___floordiv__(B_IntegralD_i16 wit, B_i16 a, B_i16 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return toB_i16(a->val / b->val); } B_i16 B_IntegralD_i16D___mod__(B_IntegralD_i16 wit, B_i16 a, B_i16 b) { return toB_i16(a->val % b->val); } B_i16 B_IntegralD_i16D___lshift__(B_IntegralD_i16 wit, B_i16 a, B_int b) { return toB_i16(a->val << fromB_int(b)); } B_i16 B_IntegralD_i16D___rshift__(B_IntegralD_i16 wit, B_i16 a, B_int b) { return toB_i16(a->val >> fromB_int(b)); } B_i16 B_IntegralD_i16D___invert__(B_IntegralD_i16 wit, B_i16 a) { return toB_i16(~a->val); } // B_LogicalD_IntegralD_i16 //////////////////////////////////////////////////////////////////////////////////////// B_i16 B_LogicalD_IntegralD_i16D___and__(B_LogicalD_IntegralD_i16 wit, B_i16 a, B_i16 b) { return toB_i16(a->val & b->val); } B_i16 B_LogicalD_IntegralD_i16D___or__(B_LogicalD_IntegralD_i16 wit, B_i16 a, B_i16 b) { return toB_i16(a->val | b->val); } B_i16 B_LogicalD_IntegralD_i16D___xor__(B_LogicalD_IntegralD_i16 wit, B_i16 a, B_i16 b) { return toB_i16(a->val ^ b->val); } // B_MinusD_IntegralD_i16 //////////////////////////////////////////////////////////////////////////////////////// B_i16 B_MinusD_IntegralD_i16D___sub__(B_MinusD_IntegralD_i16 wit, B_i16 a, B_i16 b) { return toB_i16(a->val - b->val); } // B_DivD_i16 //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_i16D___truediv__ (B_DivD_i16 wit, B_i16 a, B_i16 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return to$float((double)a->val/(double)b->val); } // B_OrdD_i16 //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_i16D___eq__ (B_OrdD_i16 wit, B_i16 a, B_i16 b) { return toB_bool(a->val == b->val); } B_bool B_OrdD_i16D___ne__ (B_OrdD_i16 wit, B_i16 a, B_i16 b) { return toB_bool(a->val != b->val); } B_bool B_OrdD_i16D___lt__ (B_OrdD_i16 wit, B_i16 a, B_i16 b) { return toB_bool(a->val < b->val); } B_bool B_OrdD_i16D___le__ (B_OrdD_i16 wit, B_i16 a, B_i16 b) { return toB_bool(a->val <= b->val); } B_bool B_OrdD_i16D___gt__ (B_OrdD_i16 wit, B_i16 a, B_i16 b) { return toB_bool(a->val > b->val); } B_bool B_OrdD_i16D___ge__ (B_OrdD_i16 wit, B_i16 a, B_i16 b) { return toB_bool(a->val >= b->val); } // B_HashableD_i16 /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_i16D___eq__(B_HashableD_i16 wit, B_i16 a, B_i16 b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_i16D___ne__(B_HashableD_i16 wit, B_i16 a, B_i16 b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_i16D_hash(B_HashableD_i16 wit, B_i16 a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val), 2)); return B_None; } ================================================ FILE: base/builtin/i16.h ================================================ struct B_i16 { struct B_i16G_class *$class; short val; }; B_i16 toB_i16(short n); short fromB_i16(B_i16 n); B_i16 B_i16G_new(B_atom a, B_int base); #define i16_DIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("i16 truediv: division by zero"))); (double)a/(double)b;} ) #define i16_FLOORDIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("i16 floordiv: division by zero"))); a/b;} ) #define i16_MOD(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("i16 mod: division by zero"))); a%b;} ) short i16_pow(short a, short b); ================================================ FILE: base/builtin/i32.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Auxiliary ////////////////////////////////////////////////////////////////////////////// // only called with e>=0. int i32_pow(int a, int e) { if (e == 0) return 1; if (e == 1) return a; if (e%2 == 0) return i32_pow(a*a,e/2); return a * i32_pow(a*a,e/2); } // General methods /////////////////////////////////////////////////////////////////////// B_i32 B_i32G_new(B_atom a, B_int base) { B_bigint b = B_bigintG_new(a, base); unsigned long n = b->val.n[0]; long sz = b->val.size; if (labs(sz) > 1 || (sz==1 && n > 0x7ffffffful) || sz == -1 && n > 0x80000000ul) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "i32(): value %s out of range for type i32",get_str(&b->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_i32((int)(n*sz)); } B_NoneType B_i32D___init__(B_i32 self, B_atom a, B_int base){ self->val = B_i32G_new(a,base)->val; return B_None; } void B_i32D___serialize__(B_i32 n, $Serial$state state) { $val_serialize(I32_ID,&n->val,state); } B_i32 B_i32D___deserialize__(B_i32 n, $Serial$state state) { return toB_i32((int)(uintptr_t)$val_deserialize(state)); } B_bool B_i32D___bool__(B_i32 n) { return toB_bool(n->val != 0); } B_str B_i32D___str__(B_i32 n) { return $FORMAT("%d", n->val); } B_str B_i32D___repr__(B_i32 n) { return $FORMAT("%d", n->val); } B_i32 toB_i32(int i) { B_i32 res = acton_malloc(sizeof(struct B_i32)); res->$class = &B_i32G_methods; res->val = i; return res; } int fromB_i32(B_i32 w) { return w->val; } // B_IntegralD_i32 ///////////////////////////////////////////////////////////////////////// B_i32 B_IntegralD_i32D___add__(B_IntegralD_i32 wit, B_i32 a, B_i32 b) { return toB_i32(a->val + b->val); } B_i32 B_IntegralD_i32D___zero__(B_IntegralD_i32 wit) { return toB_i32(0); } B_complex B_IntegralD_i32D___complex__(B_IntegralD_i32 wit, B_i32 a) { return toB_complex((double)a->val); } B_i32 B_IntegralD_i32D___fromatom__(B_IntegralD_i32 wit, B_atom a) { return B_i32G_new(a,NULL); } B_i32 B_IntegralD_i32D___mul__(B_IntegralD_i32 wit, B_i32 a, B_i32 b) { return toB_i32(a->val * b->val); } B_i32 B_IntegralD_i32D___pow__(B_IntegralD_i32 wit, B_i32 a, B_i32 b) { if ( b->val < 0) { // raise VALUEERROR; return NULL; } return toB_i32(i32_pow(a->val,b->val)); } B_i32 B_IntegralD_i32D___neg__(B_IntegralD_i32 wit, B_i32 a) { return toB_i32(-a->val); } B_i32 B_IntegralD_i32D___pos__(B_IntegralD_i32 wit, B_i32 a) { return a; } $WORD B_IntegralD_i32D_real(B_IntegralD_i32 wit, B_i32 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } $WORD B_IntegralD_i32D_imag(B_IntegralD_i32 wit, B_i32 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_i32(0L)); } $WORD B_IntegralD_i32D___abs__(B_IntegralD_i32 wit, B_i32 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_i32(labs(a->val))); } B_i32 B_IntegralD_i32D_conjugate(B_IntegralD_i32 wit, B_i32 a) { return a; } B_float B_IntegralD_i32D___float__ (B_IntegralD_i32 wit, B_i32 n) { return to$float((double)n->val); } $WORD B_IntegralD_i32D___trunc__ (B_IntegralD_i32 wit, B_i32 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_i32D___floor__ (B_IntegralD_i32 wit, B_i32 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_i32D___ceil__ (B_IntegralD_i32 wit, B_i32 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } B_i32 B_IntegralD_i32D___round__ (B_IntegralD_i32 wit, B_i32 n, B_int p) { int nval = n->val; if (nval<0) return toB_i32(-B_IntegralD_i32D___round__(wit,toB_i32(-nval),p)->val); int pval = p==NULL ? 0 : fromB_int(p); if (pval>=0) return n; int p10 = i32_pow(10,-pval); int res = nval/p10; if (nval%p10 * 2 > p10) res++; return toB_i32 (res * p10); } $WORD B_IntegralD_i32D_numerator (B_IntegralD_i32 wit, B_i32 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_i32D_denominator (B_IntegralD_i32 wit, B_i32 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_i32(1L)); } B_int B_IntegralD_i32D___int__ (B_IntegralD_i32 wit, B_i32 n) { return B_intG_new((B_atom)n,NULL); } B_int B_IntegralD_i32D___index__(B_IntegralD_i32 wit, B_i32 n) { return B_intG_new((B_atom)n,NULL); } B_tuple B_IntegralD_i32D___divmod__(B_IntegralD_i32 wit, B_i32 a, B_i32 b) { int n = a->val; int d = b->val; return $NEWTUPLE(2, toB_i32(n/d), toB_i32(n%d)); } B_i32 B_IntegralD_i32D___floordiv__(B_IntegralD_i32 wit, B_i32 a, B_i32 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return toB_i32(a->val / b->val); } B_i32 B_IntegralD_i32D___mod__(B_IntegralD_i32 wit, B_i32 a, B_i32 b) { return toB_i32(a->val % b->val); } B_i32 B_IntegralD_i32D___lshift__(B_IntegralD_i32 wit, B_i32 a, B_int b) { return toB_i32(a->val << fromB_int(b)); } B_i32 B_IntegralD_i32D___rshift__(B_IntegralD_i32 wit, B_i32 a, B_int b) { return toB_i32(a->val >> fromB_int(b)); } B_i32 B_IntegralD_i32D___invert__(B_IntegralD_i32 wit, B_i32 a) { return toB_i32(~a->val); } // B_LogicalD_IntegralD_i32 //////////////////////////////////////////////////////////////////////////////////////// B_i32 B_LogicalD_IntegralD_i32D___and__(B_LogicalD_IntegralD_i32 wit, B_i32 a, B_i32 b) { return toB_i32(a->val & b->val); } B_i32 B_LogicalD_IntegralD_i32D___or__(B_LogicalD_IntegralD_i32 wit, B_i32 a, B_i32 b) { return toB_i32(a->val | b->val); } B_i32 B_LogicalD_IntegralD_i32D___xor__(B_LogicalD_IntegralD_i32 wit, B_i32 a, B_i32 b) { return toB_i32(a->val ^ b->val); } // B_MinusD_IntegralD_i32 //////////////////////////////////////////////////////////////////////////////////////// B_i32 B_MinusD_IntegralD_i32D___sub__(B_MinusD_IntegralD_i32 wit, B_i32 a, B_i32 b) { return toB_i32(a->val - b->val); } // B_DivD_i32 //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_i32D___truediv__ (B_DivD_i32 wit, B_i32 a, B_i32 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return to$float((double)a->val/(double)b->val); } // B_OrdD_i32 //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_i32D___eq__ (B_OrdD_i32 wit, B_i32 a, B_i32 b) { return toB_bool(a->val == b->val); } B_bool B_OrdD_i32D___ne__ (B_OrdD_i32 wit, B_i32 a, B_i32 b) { return toB_bool(a->val != b->val); } B_bool B_OrdD_i32D___lt__ (B_OrdD_i32 wit, B_i32 a, B_i32 b) { return toB_bool(a->val < b->val); } B_bool B_OrdD_i32D___le__ (B_OrdD_i32 wit, B_i32 a, B_i32 b) { return toB_bool(a->val <= b->val); } B_bool B_OrdD_i32D___gt__ (B_OrdD_i32 wit, B_i32 a, B_i32 b) { return toB_bool(a->val > b->val); } B_bool B_OrdD_i32D___ge__ (B_OrdD_i32 wit, B_i32 a, B_i32 b) { return toB_bool(a->val >= b->val); } // B_HashableD_i32 /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_i32D___eq__(B_HashableD_i32 wit, B_i32 a, B_i32 b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_i32D___ne__(B_HashableD_i32 wit, B_i32 a, B_i32 b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_i32D_hash(B_HashableD_i32 wit, B_i32 a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val), 4)); return B_None; } ================================================ FILE: base/builtin/i32.h ================================================ struct B_i32 { struct B_i32G_class *$class; int val; }; B_i32 toB_i32(int n); int fromB_i32(B_i32 n); B_i32 B_i32G_new(B_atom a, B_int base); #define i32_DIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("i32 truediv: division by zero"))); (double)a/(double)b;} ) #define i32_FLOORDIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("i32 floordiv: division by zero"))); a/b;} ) #define i32_MOD(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("i32 mod: division by zero"))); a%b;} ) int i32_pow(int a, int b); ================================================ FILE: base/builtin/i8.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Auxiliary ////////////////////////////////////////////////////////////////////////////// // only called with e>=0. int8_t i8_pow(int8_t a, int8_t e) { if (e == 0) return 1; if (e == 1) return a; if (e%2 == 0) return i8_pow(a*a,e/2); return a * i8_pow(a*a,e/2); } // General methods /////////////////////////////////////////////////////////////////////// B_i8 B_i8G_new(B_atom a, B_int base) { B_bigint b = B_bigintG_new(a, base); unsigned long n = b->val.n[0]; long sz = b->val.size; if (labs(sz) > 1 || (sz==1 && n > SCHAR_MAX) || sz == -1 && n > labs(SCHAR_MIN)) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "i8(): value %s out of range for type i8",get_str(&b->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_i8(n); } B_NoneType B_i8D___init__(B_i8 self, B_atom a, B_int base){ self->val = B_i8G_new(a,base)->val; return B_None; } void B_i8D___serialize__(B_i8 n, $Serial$state state) { $val_serialize(I8_ID,&n->val,state); } B_i8 B_i8D___deserialize__(B_i8 n, $Serial$state state) { return toB_i8((int8_t)$val_deserialize(state)); } B_bool B_i8D___bool__(B_i8 n) { return toB_bool(n->val != 0); } B_str B_i8D___str__(B_i8 n) { return $FORMAT("%d", n->val); } B_str B_i8D___repr__(B_i8 n) { return $FORMAT("%d", n->val); } B_i8 toB_i8(int8_t i) { B_i8 res = acton_malloc(sizeof(struct B_i8)); res->$class = &B_i8G_methods; res->val = i; return res; } int8_t fromB_i8(B_i8 w) { return w->val; } // B_IntegralD_i8 ///////////////////////////////////////////////////////////////////////// B_i8 B_IntegralD_i8D___add__(B_IntegralD_i8 wit, B_i8 a, B_i8 b) { return toB_i8(a->val + b->val); } B_i8 B_IntegralD_i8D___zero__(B_IntegralD_i8 wit) { return toB_i8(0); } B_complex B_IntegralD_i8D___complex__(B_IntegralD_i8 wit, B_i8 a) { return toB_complex((double)a->val); } B_i8 B_IntegralD_i8D___fromatom__(B_IntegralD_i8 wit, B_atom a) { return B_i8G_new(a,NULL); } B_i8 B_IntegralD_i8D___mul__(B_IntegralD_i8 wit, B_i8 a, B_i8 b) { return toB_i8(a->val * b->val); } B_i8 B_IntegralD_i8D___pow__(B_IntegralD_i8 wit, B_i8 a, B_i8 b) { if ( b->val < 0) { // raise VALUEERROR; return NULL; } return toB_i8(i8_pow(a->val,b->val)); } B_i8 B_IntegralD_i8D___neg__(B_IntegralD_i8 wit, B_i8 a) { return toB_i8(-a->val); } B_i8 B_IntegralD_i8D___pos__(B_IntegralD_i8 wit, B_i8 a) { return a; } $WORD B_IntegralD_i8D_real(B_IntegralD_i8 wit, B_i8 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } $WORD B_IntegralD_i8D_imag(B_IntegralD_i8 wit, B_i8 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_i8(0L)); } $WORD B_IntegralD_i8D___abs__(B_IntegralD_i8 wit, B_i8 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_i8(labs(a->val))); } B_i8 B_IntegralD_i8D_conjugate(B_IntegralD_i8 wit, B_i8 a) { return a; } B_float B_IntegralD_i8D___float__ (B_IntegralD_i8 wit, B_i8 n) { return to$float((double)n->val); } $WORD B_IntegralD_i8D___trunc__ (B_IntegralD_i8 wit, B_i8 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_i8D___floor__ (B_IntegralD_i8 wit, B_i8 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_i8D___ceil__ (B_IntegralD_i8 wit, B_i8 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } B_i8 B_IntegralD_i8D___round__ (B_IntegralD_i8 wit, B_i8 n, B_int p) { int8_t nval = n->val; if (nval<0) return toB_i8(-B_IntegralD_i8D___round__(wit,toB_i8(-nval),p)->val); long pval = p==NULL ? 0 : fromB_int(p); if (pval>=0) return n; int8_t p10 = i8_pow(10,-pval); int8_t res = nval/p10; if (nval%p10 * 2 > p10) res++; return toB_i8 (res * p10); } $WORD B_IntegralD_i8D_numerator (B_IntegralD_i8 wit, B_i8 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_i8D_denominator (B_IntegralD_i8 wit, B_i8 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_i8(1L)); } B_int B_IntegralD_i8D___int__ (B_IntegralD_i8 wit, B_i8 n) { return B_intG_new((B_atom)n,NULL); } B_int B_IntegralD_i8D___index__(B_IntegralD_i8 wit, B_i8 n) { return B_intG_new((B_atom)n,NULL); } B_tuple B_IntegralD_i8D___divmod__(B_IntegralD_i8 wit, B_i8 a, B_i8 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); int8_t n = a->val; int8_t d = b->val; return $NEWTUPLE(2, toB_i8(n/d), toB_i8(n%d)); } B_i8 B_IntegralD_i8D___floordiv__(B_IntegralD_i8 wit, B_i8 a, B_i8 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return toB_i8(a->val / b->val); } B_i8 B_IntegralD_i8D___mod__(B_IntegralD_i8 wit, B_i8 a, B_i8 b) { return toB_i8(a->val % b->val); } B_i8 B_IntegralD_i8D___lshift__(B_IntegralD_i8 wit, B_i8 a, B_int b) { return toB_i8(a->val << fromB_int(b)); } B_i8 B_IntegralD_i8D___rshift__(B_IntegralD_i8 wit, B_i8 a, B_int b) { return toB_i8(a->val >> fromB_int(b)); } B_i8 B_IntegralD_i8D___invert__(B_IntegralD_i8 wit, B_i8 a) { return toB_i8(~a->val); } // B_LogicalD_IntegralD_i8 //////////////////////////////////////////////////////////////////////////////////////// B_i8 B_LogicalD_IntegralD_i8D___and__(B_LogicalD_IntegralD_i8 wit, B_i8 a, B_i8 b) { return toB_i8(a->val & b->val); } B_i8 B_LogicalD_IntegralD_i8D___or__(B_LogicalD_IntegralD_i8 wit, B_i8 a, B_i8 b) { return toB_i8(a->val | b->val); } B_i8 B_LogicalD_IntegralD_i8D___xor__(B_LogicalD_IntegralD_i8 wit, B_i8 a, B_i8 b) { return toB_i8(a->val ^ b->val); } // B_MinusD_IntegralD_i8 //////////////////////////////////////////////////////////////////////////////////////// B_i8 B_MinusD_IntegralD_i8D___sub__(B_MinusD_IntegralD_i8 wit, B_i8 a, B_i8 b) { return toB_i8(a->val - b->val); } // B_DivD_i8 //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_i8D___truediv__ (B_DivD_i8 wit, B_i8 a, B_i8 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return to$float((double)a->val/(double)b->val); } // B_OrdD_i8 //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_i8D___eq__ (B_OrdD_i8 wit, B_i8 a, B_i8 b) { return toB_bool(a->val == b->val); } B_bool B_OrdD_i8D___ne__ (B_OrdD_i8 wit, B_i8 a, B_i8 b) { return toB_bool(a->val != b->val); } B_bool B_OrdD_i8D___lt__ (B_OrdD_i8 wit, B_i8 a, B_i8 b) { return toB_bool(a->val < b->val); } B_bool B_OrdD_i8D___le__ (B_OrdD_i8 wit, B_i8 a, B_i8 b) { return toB_bool(a->val <= b->val); } B_bool B_OrdD_i8D___gt__ (B_OrdD_i8 wit, B_i8 a, B_i8 b) { return toB_bool(a->val > b->val); } B_bool B_OrdD_i8D___ge__ (B_OrdD_i8 wit, B_i8 a, B_i8 b) { return toB_bool(a->val >= b->val); } // B_HashableD_i8 /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_i8D___eq__(B_HashableD_i8 wit, B_i8 a, B_i8 b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_i8D___ne__(B_HashableD_i8 wit, B_i8 a, B_i8 b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_i8D_hash(B_HashableD_i8 wit, B_i8 a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val),1)); return B_None; } ================================================ FILE: base/builtin/i8.h ================================================ struct B_i8 { struct B_i8G_class *$class; int8_t val; }; B_i8 toB_i8(int8_t n); int8_t fromB_i8(B_i8 n); B_i8 B_i8G_new(B_atom a, B_int base); #define i8_DIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("i8 truediv: division by zero"))); (double)a/(double)b;} ) #define i8_FLOORDIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("i8 floordiv: division by zero"))); a/b;} ) #define i8_MOD(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("i8 mod: division by zero"))); a%b;} ) int8_t i8_pow(int8_t a, int8_t b); ================================================ FILE: base/builtin/int.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Auxiliary ////////////////////////////////////////////////////////////////////////////// // only called with e>=0. long int_pow(long a, long e) { if (e == 0) return 1; if (e == 1) return a; if (e%2 == 0) return int_pow(a*a,e/2); return a * int_pow(a*a,e/2); } // General methods /////////////////////////////////////////////////////////////////////// B_int B_intG_new(B_atom a, B_int base) { B_bigint b = B_bigintG_new(a, base); unsigned long n = b->val.n[0]; long sz = b->val.size; if (labs(sz) > 1 || (sz==1 && n > 0x7ffffffffffffffful) || sz == -1 && n > 0x8000000000000000ul) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "int(): value %s out of range for type int",get_str(&b->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_int(n*sz); } B_NoneType B_intD___init__(B_int self, B_atom a, B_int base){ self->val = B_intG_new(a,base)->val; return B_None; } void B_intD___serialize__(B_int n, $Serial$state state) { $val_serialize(INT_ID,&n->val,state); } B_int B_intD___deserialize__(B_int n, $Serial$state state) { return toB_int((long)$val_deserialize(state)); } B_bool B_intD___bool__(B_int n) { return toB_bool(n->val != 0); } B_str B_intD___str__(B_int n) { return $FORMAT("%lld", n->val); } B_str B_intD___repr__(B_int n) { return $FORMAT("%lld", n->val); } B_int toB_int(int64_t i) { B_int res = acton_malloc(sizeof(struct B_int)); res->$class = &B_intG_methods; res->val = i; return res; } B_int to$int(int64_t n) { return toB_int(n); } int64_t fromB_int(B_int w) { return w->val; } // B_IntegralD_int ///////////////////////////////////////////////////////////////////////// B_int B_IntegralD_intD___add__(B_IntegralD_int wit, B_int a, B_int b) { return toB_int(a->val + b->val); } B_int B_IntegralD_intD___zero__(B_IntegralD_int wit) { return toB_int(0); } B_complex B_IntegralD_intD___complex__(B_IntegralD_int wit, B_int a) { return toB_complex((double)a->val); } B_int B_IntegralD_intD___fromatom__(B_IntegralD_int wit, B_atom a) { return B_intG_new(a,NULL); } B_int B_IntegralD_intD___mul__(B_IntegralD_int wit, B_int a, B_int b) { return toB_int(a->val * b->val); } B_int B_IntegralD_intD___pow__(B_IntegralD_int wit, B_int a, B_int b) { if ( b->val < 0) { // raise VALUEERROR; return NULL; } return toB_int(int_pow(a->val,b->val)); } B_int B_IntegralD_intD___neg__(B_IntegralD_int wit, B_int a) { return toB_int(-a->val); } B_int B_IntegralD_intD___pos__(B_IntegralD_int wit, B_int a) { return a; } $WORD B_IntegralD_intD_real(B_IntegralD_int wit, B_int a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } $WORD B_IntegralD_intD_imag(B_IntegralD_int wit, B_int a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_int(0L)); } $WORD B_IntegralD_intD___abs__(B_IntegralD_int wit, B_int a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_int(labs(a->val))); } B_int B_IntegralD_intD_conjugate(B_IntegralD_int wit, B_int a) { return a; } B_float B_IntegralD_intD___float__ (B_IntegralD_int wit, B_int n) { return to$float((double)n->val); } $WORD B_IntegralD_intD___trunc__ (B_IntegralD_int wit, B_int n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_intD___floor__ (B_IntegralD_int wit, B_int n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_intD___ceil__ (B_IntegralD_int wit, B_int n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } B_int B_IntegralD_intD___round__ (B_IntegralD_int wit, B_int n, B_int p) { long nval = n->val; if (nval<0) return toB_int(-B_IntegralD_intD___round__(wit,toB_int(-nval),p)->val); long pval = p==NULL ? 0 : fromB_int(p); if (pval>=0) return n; long p10 = int_pow(10,-pval); long res = nval/p10; if (nval%p10 * 2 > p10) res++; return toB_int (res * p10); } $WORD B_IntegralD_intD_numerator (B_IntegralD_int wit, B_int n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_intD_denominator (B_IntegralD_int wit, B_int n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_int(1L)); } B_int B_IntegralD_intD___int__ (B_IntegralD_int wit, B_int n) { return B_intG_new((B_atom)n,NULL); } B_int B_IntegralD_intD___index__(B_IntegralD_int wit, B_int n) { return B_intG_new((B_atom)n,NULL); } B_tuple B_IntegralD_intD___divmod__(B_IntegralD_int wit, B_int a, B_int b) { long n = a->val; long d = b->val; return $NEWTUPLE(2, toB_int(n/d), toB_int(n%d)); } B_int B_IntegralD_intD___floordiv__(B_IntegralD_int wit, B_int a, B_int b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return toB_int(a->val / b->val); } B_int B_IntegralD_intD___mod__(B_IntegralD_int wit, B_int a, B_int b) { return toB_int(a->val % b->val); } B_int B_IntegralD_intD___lshift__(B_IntegralD_int wit, B_int a, B_int b) { return toB_int(a->val << fromB_int(b)); } B_int B_IntegralD_intD___rshift__(B_IntegralD_int wit, B_int a, B_int b) { return toB_int(a->val >> fromB_int(b)); } B_int B_IntegralD_intD___invert__(B_IntegralD_int wit, B_int a) { return toB_int(~a->val); } // B_LogicalD_IntegralD_int //////////////////////////////////////////////////////////////////////////////////////// B_int B_LogicalD_IntegralD_intD___and__(B_LogicalD_IntegralD_int wit, B_int a, B_int b) { return toB_int(a->val & b->val); } B_int B_LogicalD_IntegralD_intD___or__(B_LogicalD_IntegralD_int wit, B_int a, B_int b) { return toB_int(a->val | b->val); } B_int B_LogicalD_IntegralD_intD___xor__(B_LogicalD_IntegralD_int wit, B_int a, B_int b) { return toB_int(a->val ^ b->val); } // B_MinusD_IntegralD_int //////////////////////////////////////////////////////////////////////////////////////// B_int B_MinusD_IntegralD_intD___sub__(B_MinusD_IntegralD_int wit, B_int a, B_int b) { return toB_int(a->val - b->val); } // B_DivD_int //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_intD___truediv__ (B_DivD_int wit, B_int a, B_int b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return to$float((double)a->val/(double)b->val); } // B_OrdD_int //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_intD___eq__ (B_OrdD_int wit, B_int a, B_int b) { return toB_bool(a->val == b->val); } B_bool B_OrdD_intD___ne__ (B_OrdD_int wit, B_int a, B_int b) { return toB_bool(a->val != b->val); } B_bool B_OrdD_intD___lt__ (B_OrdD_int wit, B_int a, B_int b) { return toB_bool(a->val < b->val); } B_bool B_OrdD_intD___le__ (B_OrdD_int wit, B_int a, B_int b) { return toB_bool(a->val <= b->val); } B_bool B_OrdD_intD___gt__ (B_OrdD_int wit, B_int a, B_int b) { return toB_bool(a->val > b->val); } B_bool B_OrdD_intD___ge__ (B_OrdD_int wit, B_int a, B_int b) { return toB_bool(a->val >= b->val); } // B_HashableD_int /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_intD___eq__(B_HashableD_int wit, B_int a, B_int b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_intD___ne__(B_HashableD_int wit, B_int a, B_int b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_intD_hash(B_HashableD_int wit, B_int a, B_hasher h) { zig_hash_wyhash_update(h->_hasher,to$bytesD_len((char *)&(a->val),8)); return B_None; } ================================================ FILE: base/builtin/int.h ================================================ struct B_int { struct B_intG_class *$class; int64_t val; }; B_int toB_int(int64_t n); B_int to$int(int64_t n); int64_t fromB_int(B_int n); B_int B_intG_new(B_atom a, B_int base); // only called with e>=0. long int_pow(long a, long e); // used also for ndarrays #define int_DIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("int truediv: division by zero"))); (double)a/(double)b;} ) #define int_FLOORDIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("int floordiv: division by zero"))); a/b;} ) #define int_MOD(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("int mod: division by zero"))); a%b;} ) ================================================ FILE: base/builtin/list.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Auxiliary functions ///////////////////////////////////////////////////////////////////////////////////////////////////// // For now, expansion doubles capacity. static void expand(B_list lst, int n) { if (lst->capacity >= lst->length + n) return; int newcapacity = lst->capacity==0 ? 1 : lst->capacity; while (newcapacity < lst->length+n) newcapacity <<= 1; $WORD* newptr = lst->data==NULL ? acton_malloc(newcapacity*sizeof($WORD)) : acton_realloc(lst->data,newcapacity*sizeof($WORD)); if (newptr == NULL) { $RAISE((B_BaseException)$NEW(B_MemoryError,to$str("memory allocation failed"))); } lst->data = newptr; lst->capacity = newcapacity; } static void shrink(B_list lst) { if (lst->capacity > 20 && 2*lst->length < lst->capacity) { int newcapacity = lst->length; $WORD old = lst->data; lst->data = acton_malloc(newcapacity * sizeof($WORD)); lst->capacity = newcapacity; assert(old != NULL); memcpy(lst->data, old, newcapacity * sizeof($WORD)); } } B_list B_listD_new(int capacity) { if (capacity < 0) { fprintf(stderr,"Internal error list_new: negative capacity"); exit(-1); } B_list lst = acton_malloc(sizeof(struct B_list)); if (lst == NULL) { $RAISE((B_BaseException)$NEW(B_MemoryError,to$str("memory allocation failed"))); } if (capacity>0) { lst->data = acton_malloc(capacity*sizeof($WORD)); if (lst->data == NULL) { $RAISE((B_BaseException)$NEW(B_MemoryError,to$str("memory allocation failed"))); } } else { lst->data = NULL; } lst->length = 0; lst->capacity = capacity; lst->$class = &B_listG_methods; return lst; } // General methods /////////////////////////////////////// B_list B_listG_new(B_Iterable wit, $WORD iterable) { return $NEW(B_list, wit, iterable); } B_NoneType B_listD___init__(B_list lst, B_Iterable wit, $WORD iterable) { lst->length = 0; lst->capacity = 0; lst->data = NULL; if (!iterable || !wit) { return B_None; } $WORD w; B_Iterator it = wit->$class->__iter__(wit,iterable); B_SequenceD_list wit2 = B_SequenceD_listG_new(); while(1) { if ($PUSH()) { $WORD e = it->$class->__next__(it); wit2->$class->append(wit2, lst, e); $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } return B_None; } B_bool B_listD___bool__(B_list self) { return toB_bool(self->length>0); } B_str B_listD___str__(B_list self) { B_list s2 = B_listD_new(self->length); B_SequenceD_list wit2 = B_SequenceD_listG_new(); for (int i=0; i< self->length; i++) { B_value elem = (B_value)self->data[i]; if (elem == B_None) { wit2->$class->append(wit2, s2, to$str("None")); } else { wit2->$class->append(wit2, s2, elem->$class->__repr__(elem)); } } return B_strD_join_par('[',s2,']'); } B_str B_listD___repr__(B_list self) { return B_listD___str__(self); } void B_listD___serialize__(B_list self,$Serial$state state) { B_int prevkey = (B_int)B_dictD_get(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,NULL); if (prevkey) { long pk = fromB_int(prevkey); $val_serialize(-LIST_ID,&pk,state); return; } B_dictD_setitem(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,toB_int(state->row_no)); long len = (long)self->length; $val_serialize(LIST_ID,&len,state); for (int i=0; ilength; i++) { $step_serialize(self->data[i],state); } } B_list B_listD___deserialize__(B_list res, $Serial$state state) { $ROW this = state->row; state->row = this->next; state->row_no++; if (this->class_id < 0) { return (B_list)B_dictD_get(state->done,(B_Hashable)B_HashableD_intG_witness,toB_int((long)this->blob[0]),NULL); } else { if (!res) res = B_listD_new((int)(long)this->blob[0]); B_dictD_setitem(state->done,(B_Hashable)B_HashableD_intG_witness,toB_int(state->row_no-1),res); res->length = res->capacity; for (int i = 0; i < res->length; i++) res->data[i] = $step_deserialize(state); return res; } } B_list B_listD_copy(B_list lst) { int len = lst->length; B_list res = B_listD_new(len); res->length = len; if (len > 0) memcpy(res->data, lst->data, len*sizeof($WORD)); return res; } B_NoneType B_listD_clear(B_list lst) { lst->data = NULL; lst->capacity = 0; lst->length = 0; return B_None; } B_NoneType B_listD_extend(B_list lst, B_list other) { if (other->length == 0) return B_None; expand(lst, other->length); memcpy(lst->data + lst->length, other->data, other->length * sizeof($WORD)); lst->length += other->length; return B_None; } $WORD B_listD_pop(B_list lst, B_int i) { long ix; int len =lst->length; if (!i) ix = len-1; else ix = fromB_int(i); long ix0 = ix < 0 ? len + ix : ix; if (ix0 < 0 || ix0 >= len) { $RAISE((B_BaseException)$NEW(B_IndexError, toB_int(ix0), to$str("pop: index outside list"))); } $WORD res = lst->data[ix0]; memmove(lst->data + ix0, lst->data + (ix0 + 1), (len-(ix0+1))*sizeof($WORD)); lst->data[len-1] = NULL; lst->length--; shrink(lst); return res; } B_int B_listD_index(B_list self, B_Eq W_EqD_B, $WORD val, B_int start, B_int stop) { int strt = 0; if (start) strt = fromB_int(start); if (strt < 0) $RAISE((B_BaseException)$NEW(B_ValueError, to$str("start position must be >= 0"))); if (strt > self->length) $RAISE((B_BaseException)$NEW(B_ValueError, to$str("start position must not exceed list length"))); int stp = self->length; if (stop) { stp = fromB_int(stop); if (stp <= strt) $RAISE((B_BaseException)$NEW(B_ValueError, to$str("stop position must be higher than start position"))); } if (stp > self->length) stp = self->length; for (int i=strt; i < stp; i++) { B_value elem = (B_value)self->data[i]; B_bool eq = W_EqD_B->$class->__eq__(W_EqD_B, val, elem); if (eq->val) return toB_int(i); } $RAISE((B_BaseException)$NEW(B_KeyError, val, to$str("element is not in list"))); return NULL; //to prevent compiler warning } B_int B_listD_count(B_list self, B_Eq W_EqD_B, $WORD val) { int count = 0; for (int i = 0; i < self->length; i++) { B_value elem = (B_value)self->data[i]; B_bool eq = W_EqD_B->$class->__eq__(W_EqD_B, val, elem); if (eq->val) count++; } return to$int(count); } // B_OrdD_list //////////////////////////////////////////////////////// B_bool B_OrdD_listD___eq__ (B_OrdD_list w, B_list a, B_list b) { if (a->length != b->length) return B_False; B_Ord w2 = w->W_OrdD_AD_OrdD_list; for (int i = 0; ilength; i++) { if ((w2->$class->__ne__(w2,a->data[i],b->data[i]))->val) return B_False; } return B_True; } B_bool B_OrdD_listD___ne__ (B_OrdD_list w, B_list a, B_list b) { return toB_bool(!(w->$class->__eq__(w,a,b)->val)); } B_bool B_OrdD_listD___lt__ (B_OrdD_list w, B_list a, B_list b) { int minl = a->lengthlength ? a->length : b->length; B_Ord wA = w->W_OrdD_AD_OrdD_list; int i=0; while (i$class->__eq__(wA,a->data[i],b->data[i])) i++; if (i==a->length) return toB_bool(ilength); if (i==b->length) return B_False; return wA->$class->__lt__(wA,a->data[i],b->data[i]); } B_bool B_OrdD_listD___le__ (B_OrdD_list w, B_list a, B_list b) { int minl = a->lengthlength ? a->length : b->length; B_Ord wA = w->W_OrdD_AD_OrdD_list; int i=0; while (i$class->__eq__(wA,a->data[i],b->data[i])) i++; if (i==a->length) return toB_bool(i<=b->length); if (i==b->length) return B_False; return wA->$class->__lt__(wA,a->data[i],b->data[i]); } B_bool B_OrdD_listD___gt__ (B_OrdD_list w, B_list a, B_list b) { return B_OrdD_listD___lt__ (w,b,a); } B_bool B_OrdD_listD___ge__ (B_OrdD_list w, B_list a, B_list b) { return B_OrdD_listD___le__ (w,b,a); } // B_TimesD_SequenceD_list ///////////////////////////////////////////////////////// B_list B_TimesD_SequenceD_listD___add__ (B_TimesD_SequenceD_list wit, B_list lst, B_list other) { int lstlen = lst->length; int otherlen = other->length; int reslen = lstlen + otherlen; B_list res = B_listD_new(reslen); if (lstlen > 0) memcpy(res->data,lst->data,lstlen*sizeof($WORD)); if (otherlen > 0) memcpy(res->data+lstlen,other->data,otherlen*sizeof($WORD)); res->length = reslen; return res; } B_list B_TimesD_SequenceD_listD___zero__ (B_TimesD_SequenceD_list wit) { return B_listD_new(0); } B_list B_TimesD_SequenceD_listD___mul__ (B_TimesD_SequenceD_list wit, B_list lst, B_int n) { int lstlen = lst->length; long n64 = fromB_int(n); if (lstlen == 0 || n64 <= 0) return B_listD_new(0); else { B_list res = B_listD_new(lstlen * n64); for (int i=0; idata + i*lstlen, lst->data, lstlen * sizeof($WORD)); res->length = lstlen * n64; return res; } } // B_CollectionD_SequenceD_list /////////////////////////////////////////////////////// // first define the Iterator instance /// static $WORD B_IteratorD_listD_next(B_IteratorD_list self) { if (self->nxt >= self->src->length) $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("list iterator terminated"))); return self->src->data[self->nxt++]; } B_IteratorD_list B_IteratorD_listG_new(B_list lst) { return $NEW(B_IteratorD_list, lst); } void B_IteratorD_listD_init(B_IteratorD_list self, B_list lst) { self->src = lst; self->nxt = 0; } B_bool B_IteratorD_listD_bool(B_IteratorD_list self) { return B_True; } B_str B_IteratorD_listD_str(B_IteratorD_list self) { return $FORMAT("", self); } void B_IteratorD_listD_serialize(B_IteratorD_list self,$Serial$state state) { $step_serialize(self->src,state); $step_serialize(toB_int(self->nxt),state); } B_IteratorD_list B_IteratorD_list$_deserialize(B_IteratorD_list res, $Serial$state state) { if(!res) res = $DNEW(B_IteratorD_list,state); res->src = (B_list)$step_deserialize(state); res->nxt = fromB_int((B_int)$step_deserialize(state)); return res; } struct B_IteratorD_listG_class B_IteratorD_listG_methods = {"B_IteratorD_list",UNASSIGNED,($SuperG_class)&B_IteratorG_methods, B_IteratorD_listD_init, B_IteratorD_listD_serialize, B_IteratorD_list$_deserialize,B_IteratorD_listD_bool,B_IteratorD_listD_str,B_IteratorD_listD_str,B_IteratorD_listD_next}; // Now, we can define the protocol methods B_Iterator B_CollectionD_SequenceD_listD___iter__(B_CollectionD_SequenceD_list wit, B_list lst) { return (B_Iterator)$NEW(B_IteratorD_list,lst); } B_list B_CollectionD_SequenceD_listD___fromiter__ (B_CollectionD_SequenceD_list wit, B_Iterable wit2, $WORD iter) { return B_listG_new(wit2, iter); /* B_list res = B_listD_new(4); B_SequenceD_list wit3 = B_SequenceD_listG_new(); B_Iterator it = wit2->$class->__iter__(wit2,iter); $WORD nxt; while ((nxt = it->$class->__next__(it))) { wit3->$class->append(wit3, res, nxt); } return res; */ } B_int B_CollectionD_SequenceD_listD___len__(B_CollectionD_SequenceD_list wit, B_list self) { return toB_int(self->length); } // B_SequenceD_list ////////////////////////////////////////////////////////////////// $WORD $listD_U__getitem__(B_list lst, int64_t n) { int len = lst->length; int ix0 = n < 0 ? len + n : n; if (ix0 < 0 || ix0 >= len) { $RAISE((B_BaseException)$NEW(B_IndexError, toB_int(ix0), to$str("getitem: index outside list"))); } return lst->data[ix0]; } $WORD B_SequenceD_listD___getitem__(B_SequenceD_list wit, B_list lst, B_int n) { return $listD_U__getitem__(lst, fromB_int(n)); } B_NoneType listD_U__setitem__(B_list lst, int64_t n, $WORD val) { int len = lst->length; int ix0 = n < 0 ? len + n : n; if (ix0 < 0 || ix0 >= len) { $RAISE((B_BaseException)$NEW(B_IndexError, toB_int(ix0), to$str("setitem: index outside list"))); } lst->data[ix0] = val; return B_None; } B_NoneType B_SequenceD_listD___setitem__(B_SequenceD_list wit, B_list lst, B_int n, $WORD val) { return listD_U__setitem__(lst, fromB_int(n), val); } B_NoneType B_SequenceD_listD___delitem__(B_SequenceD_list wit, B_list lst, B_int n) { int len = lst->length; int64_t ix = fromB_int(n); int ix0 = ix < 0 ? len + ix : ix; if(ix0 < 0 || ix0 >= len) { return B_None; } memmove(lst->data + ix0, lst->data + (ix0 + 1), (len-(ix0+1))*sizeof($WORD)); lst->data[lst->length-1] = NULL; lst->length--; shrink(lst); return B_None; } B_NoneType B_SequenceD_listD_append(B_SequenceD_list wit, B_list lst, $WORD elem); B_list B_SequenceD_listD___getslice__(B_SequenceD_list wit, B_list lst, B_slice slc) { int len = lst->length; int64_t start, stop, step, slen; normalize_slice(slc, len, &slen, &start, &stop, &step); // slice notation has been eliminated and default values applied. // slen is now the length of the slice B_list rlst = B_listD_new(slen); int64_t t = start; for (int i=0; idata[t]); t += step; } return rlst; } B_NoneType B_SequenceD_listD___setslice__(B_SequenceD_list wit, B_list lst, B_Iterable wit2, B_slice slc, $WORD iter) { int len = lst->length; B_list other = B_listD_new(0); B_SequenceD_list wit3 = B_SequenceD_listG_new(); B_Iterator it = wit2->$class->__iter__(wit2,iter); while(1) { if ($PUSH()) { $WORD w = it->$class->__next__(it); wit3->$class->append(wit3, other, w); $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } int olen = other->length; int64_t start, stop, step, slen; normalize_slice(slc, len, &slen, &start, &stop, &step); if (step != 1 && olen != slen) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("setslice: illegal slice"))); } int copy = olen <= slen ? olen : slen; int t = start; for (int i= 0; idata[t] = other->data[i]; t += step; } if (olen == slen) return B_None; // now we know that step=1 if (olen < slen) { memmove(lst->data + start + copy, lst->data + start + slen, (len-(start+slen))*sizeof($WORD)); lst->length-=slen-olen; return B_None; } else { expand(lst,olen-slen); int rest = len - (start+copy); int incr = olen - slen; memmove(lst->data + start + copy + incr, lst->data + start + copy, rest*sizeof($WORD)); for (int i = copy; i < olen; i++) lst->data[start+i] = other->data[i]; lst->length += incr; } return B_None; } B_NoneType B_SequenceD_listD___delslice__(B_SequenceD_list wit, B_list lst, B_slice slc) { int len = lst->length; int64_t start, stop, step, slen; normalize_slice(slc, len, &slen, &start, &stop, &step); if (slen==0) return B_None; $WORD *p = lst->data + start; for (int i=0; ilength-=slen; return B_None; } B_NoneType B_SequenceD_listD_reverse(B_SequenceD_list wit, B_list lst) { int len = lst->length; for (int i = 0; i < len/2; i++) { $WORD tmp = lst->data[i]; lst->data[i] = lst->data[len-1-i]; lst->data[len-1-i] = tmp; } return B_None; } B_Iterator B_SequenceD_listD___reversed__(B_SequenceD_list wit, B_list lst) { B_list copy = B_listD_copy(lst); B_SequenceD_listD_reverse(wit, copy); return B_CollectionD_SequenceD_listD___iter__((B_CollectionD_SequenceD_list)wit->W_Collection, copy); } B_NoneType B_SequenceD_listD_insert(B_SequenceD_list wit, B_list lst, B_int n, $WORD elem) { int len = lst->length; long ix = fromB_int(n); expand(lst,1); long ix0 = ix < 0 ? (len+ix < 0 ? 0 : len+ix) : (ix < len ? ix : len); memmove(lst->data + (ix0 + 1), lst->data + ix0 , (len - ix0) * sizeof($WORD)); lst->data[ix0] = elem; lst->length++; return B_None; } B_NoneType B_SequenceD_listD_append(B_SequenceD_list wit, B_list lst, $WORD elem) { expand(lst,1); lst->data[lst->length++] = elem; return B_None; } // B_ContainerD_list /////////////////////////////////////////////////////////////////// B_bool B_ContainerD_listD___contains__(B_ContainerD_list wit, B_list lst, $WORD elem) { long res = 0; B_Eq w = wit->W_EqD_AD_ContainerD_list; for (int i=0; i < lst->length; i++) { if (fromB_bool(w->$class->__eq__(w,elem,lst->data[i]))) { res = 1; break; } } return toB_bool(res); } B_bool B_ContainerD_listD___containsnot__(B_ContainerD_list wit, B_list lst, $WORD elem) { return toB_bool(!B_ContainerD_listD___contains__(wit,lst,elem)->val); } // Witnesses used in code generation // The initialization code that registers method tables in a list indexed by classid uses list append; // so we need to initialize the below method table here, even if it is done in B___init__. struct B_SequenceD_listG_class B_SequenceD_listG_methods = { "B_SequenceD_list", UNASSIGNED, ($SuperG_class)&B_SequenceG_methods, NULL, //B_SequenceD_listD___init__, NULL, //B_SequenceD_listD___serialize__, NULL, //B_SequenceD_listD___deserialize__, (B_bool (*)(B_SequenceD_list))$default__bool__, (B_str (*)(B_SequenceD_list))$default__str__, (B_str (*)(B_SequenceD_list))$default__str__, B_SequenceD_listD___getitem__, B_SequenceD_listD___setitem__, B_SequenceD_listD___delitem__, B_SequenceD_listD___getslice__, B_SequenceD_listD___setslice__, B_SequenceD_listD___delslice__, B_SequenceD_listD___reversed__, B_SequenceD_listD_insert, B_SequenceD_listD_append, B_SequenceD_listD_reverse }; /* struct B_TimesD_SequenceD_list B_TimesD_SequenceD_list_instance; struct B_SequenceD_list B_SequenceD_list_instance; struct B_CollectionD_SequenceD_list B_CollectionD_SequenceD_list_instance = { &B_CollectionD_SequenceD_listG_methods, (B_Sequence)&B_SequenceD_list_instance }; B_CollectionD_SequenceD_list B_CollectionD_SequenceD_listG_witness = &B_CollectionD_SequenceD_list_instance; struct B_SequenceD_list B_SequenceD_list_instance = { &B_SequenceD_listG_methods, (B_Eq)&B_OrdD_intG_methods, (B_Collection)&B_CollectionD_SequenceD_list_instance, (B_Times)&B_TimesD_SequenceD_list_instance }; B_SequenceD_list B_SequenceD_listG_witness = &B_SequenceD_list_instance; struct B_TimesD_SequenceD_list B_TimesD_SequenceD_list_instance = { &B_TimesD_SequenceD_listG_methods, (B_Sequence)&B_SequenceD_list_instance }; B_TimesD_SequenceD_list B_TimesD_SequenceD_listG_witness = &B_TimesD_SequenceD_list_instance; */ ================================================ FILE: base/builtin/list.h ================================================ struct B_list { struct B_listG_class *$class; $WORD *data; int length; int capacity; }; /* extern struct B_SequenceD_list *B_SequenceD_listG_witness; extern struct B_CollectionD_SequenceD_list *B_CollectionD_SequenceD_listG_witness; */ // Iterators over lists /////////////////////////////////////////////////////// typedef struct B_IteratorD_list *B_IteratorD_list; ; struct B_IteratorD_listG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_IteratorD_list, B_list); void (*__serialize__)(B_IteratorD_list,$Serial$state); B_IteratorD_list (*__deserialize__)(B_IteratorD_list,$Serial$state); B_bool (*__bool__)(B_IteratorD_list); B_str (*__str__)(B_IteratorD_list); B_str (*__repr__)(B_IteratorD_list); $WORD(*__next__)(B_IteratorD_list); }; struct B_IteratorD_list { struct B_IteratorD_listG_class *$class; B_list src; int nxt; }; extern struct B_IteratorD_listG_class B_IteratorD_listG_methods; B_IteratorD_list B_IteratorD_listG_new(B_list); //convenience functions used at various places. B_list B_listD_new(int capacity); B_list B_listD_copy(B_list lst); $WORD $listD_U__getitem__(B_list lst, int64_t n); B_NoneType listD_U__setitem__(B_list lst, int64_t n, $WORD val); ================================================ FILE: base/builtin/none.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ B_NoneType B_NoneTypeG_new() { return $NEW(B_NoneType); } void B_NoneTypeD__serialize__(B_NoneType self, $Serial$state state) { $add_header(NONE_ID,0,state); } B_NoneType B_NoneTypeD__deserialize__(B_NoneType self, $Serial$state state) { state->row = state->row->next; state->row_no++; return NULL; } B_bool B_NoneTypeD__bool__(B_NoneType self) { return B_False; } B_str B_NoneTypeD__str__(B_NoneType self) { return to$str("None"); } struct B_NoneTypeG_class B_NoneTypeG_methods = {"B_NoneType",UNASSIGNED,($SuperG_class)&B_valueG_methods,(void (*)(B_NoneType))$default__init__, B_NoneTypeD__serialize__, B_NoneTypeD__deserialize__, B_NoneTypeD__bool__, B_NoneTypeD__str__, B_NoneTypeD__str__}; ================================================ FILE: base/builtin/none.h ================================================ struct B_NoneTypeG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_NoneType); void (*__serialize__)(B_NoneType,$Serial$state); B_NoneType (*__deserialize__)(B_NoneType,$Serial$state); B_bool (*__bool__)(B_NoneType); B_str (*__str__)(B_NoneType); B_str (*__repr__)(B_NoneType); }; struct B_NoneType { struct B_NoneTypeG_class *$class; }; extern struct B_NoneTypeG_class B_NoneTypeG_methods; B_NoneType B_NoneTypeG_new(); ================================================ FILE: base/builtin/range.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ B_range B_rangeG_new(B_int start, B_int stop, B_int step) { return $NEW(B_range, start, stop, step); } B_NoneType B_rangeD___init__(B_range self, B_int start, B_int stop, B_int step) { int64_t ustart, ustop, ustep, stp; if (stop) { ustart = start->val; ustop = stop->val; } else { ustart = 0; ustop = start->val; } if (step) { stp = step->val; if (stp == 0) { $RAISE((B_BaseException)$NEW(B_ValueError, to$str("range() step size must not be zero"))); } else { ustep = stp; } } else { ustep = 1; } stp = self->step = ustep; int64_t r = ustop - ustart; self->nxt = ustart - stp; self->remaining = r/stp + (r%stp != 0); return B_None; } /* B_bool B_rangeD___bool__(B_range self) { return toB_bool ((self->step > 0 && self->stop > self->start) || (self->start > self->stop)); } B_str B_rangeD___str__(B_range self) { return $FORMAT("range(%ld,%ld,%ld)", self->start, self->stop, self->step); } B_str B_rangeD___repr__(B_range self) { return $FORMAT("range(%ld,%ld,%ld)", self->start, self->stop, self->step); } void B_rangeD___serialize__(B_range self, $Serial$state state) { $ROW row = $add_header(RANGE_ID,3,state); row->blob[0] = ($WORD)self->start; row->blob[1] = ($WORD)self->stop; row->blob[2] = ($WORD)self->step; } B_range B_rangeD___deserialize__(B_range self, $Serial$state state) { $ROW this = state->row; state->row = this->next; state->row_no++; B_range res = acton_malloc(sizeof(struct B_range)); res->$class = &B_rangeG_methods; res->start = (int64_t)this->blob[0]; res->stop = (int64_t)this->blob[1]; res->step = (int64_t)this->blob[2]; return res; } */ int64_t rangeD_U__next__(B_range self) { if (self->remaining-- <= 0) $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("range iterator terminated"))); return self->nxt += self->step; } B_int B_rangeD___next__(B_range self) { return toB_int(rangeD_U__next__(self)); } /* void B_IteratorD_rangeD_init(B_IteratorD_range self, B_range rng) { int64_t stp = self->step = rng->step; int64_t r = rng->stop - rng->start; self->nxt = rng->start - stp; self->remaining = r/stp + (r%stp != 0); self->box = rng->box; } */ B_bool B_rangeD___bool__(B_range self) { return B_True; } B_str B_rangeD___repr__(B_range self) { return $FORMAT("", self); } B_str B_rangeD___str__(B_range self) { return $FORMAT("", self); } void B_rangeD___serialize__(B_range self, $Serial$state state) { $step_serialize(toB_int(self->nxt),state); $step_serialize(toB_int(self->step),state); $step_serialize(toB_int(self->remaining),state); } B_range B_rangeD___deserialize__(B_range self, $Serial$state state) { B_range res = $DNEW(B_range,state); res->nxt = fromB_int((B_int)$step_deserialize(state)); res->step = fromB_int((B_int)$step_deserialize(state)); res->remaining = fromB_int((B_int)$step_deserialize(state)); return res; } /* struct B_IteratorD_rangeG_class B_IteratorD_rangeG_methods = { "B_IteratorD_range", UNASSIGNED, ($SuperG_class)&B_IteratorG_methods, B_IteratorD_rangeD_init, B_IteratorD_rangeD_serialize, B_IteratorD_range$_deserialize, B_IteratorD_rangeD_bool, B_IteratorD_rangeD_str, B_IteratorD_rangeD_str, B_IteratorD_rangeD_next }; B_Iterator B_IterableD_rangeD___iter__ (B_IterableD_range wit, B_range rng) { return (B_Iterator)$NEW(B_IteratorD_range,rng); } */ ================================================ FILE: base/builtin/range.h ================================================ struct B_range { struct B_rangeG_class *$class; int64_t nxt; int64_t step; int64_t remaining; }; int64_t $rangeD_U__next__(B_range); ================================================ FILE: base/builtin/registration.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // classid generation and retrieval //////////////////////////////////////////////////////// /* * Note that this does not attempt to be thread-safe. * We need to sort out how initialization is to be done. */ B_list G_methods; //key is classid; values are method tables void $register_force(int classid, $WORD meths) { // we require that G_methods is big enough to index it at classid. See register_builtin below. G_methods->data[classid] = meths; (($SerializableG_class)meths)->$class_id = classid; } void $register($WORD meths) { B_SequenceD_list wit = B_SequenceD_listG_witness; wit->$class->append(wit,G_methods,meths); (($SerializableG_class)meths)->$class_id = G_methods->length-1; //printf("$register class %s at index %d\n", (($SerializableG_class)meths)->$GCINFO, G_methods->length-1); } /* * We do not register rts classid's here, since we want to be able to serialize without including all of rts.o with its * special main and handling of $ROOT. Doing so would complicate testing of builtin types significantly. */ void $register_builtin() { G_methods = B_listD_new(2*PREASSIGNED); //preallocate space for PREASSIGNED user classes before doubling needed memset(G_methods->data,0,PREASSIGNED*sizeof($WORD)); // initiate PREASSIGNED first slots to NULL; G_methods->length = PREASSIGNED; $register_force(NONE_ID,&B_NoneTypeG_methods); // $register_force(ATOM_ID,&B_atomG_methods); $register_force(INT_ID,&B_intG_methods); $register_force(FLOAT_ID,&B_floatG_methods); // $register_force(COMPLEX_ID,&B_complexG_methods); $register_force(BOOL_ID,&B_boolG_methods); $register_force(STR_ID,&B_strG_methods); $register_force(LIST_ID,&B_listG_methods); $register_force(DICT_ID,&B_dictG_methods); $register_force(SET_ID,&B_setG_methods); $register_force(RANGE_ID,&B_rangeG_methods); $register_force(TUPLE_ID,&B_tupleG_methods); $register_force(BYTEARRAY_ID,&B_bytearrayG_methods); $register_force(STRITERATOR_ID,&B_IteratorB_strG_methods); $register_force(LISTITERATOR_ID,&B_IteratorD_listG_methods); $register_force(DICTITERATOR_ID,&B_IteratorD_dictG_methods); $register_force(VALUESITERATOR_ID,&B_IteratorD_dict_valuesG_methods); $register_force(ITEMSITERATOR_ID,&B_IteratorD_dict_itemsG_methods); $register_force(SETITERATOR_ID,&B_IteratorD_setG_methods); // $register_force(RANGEITERATOR_ID,&B_IteratorD_rangeG_methods); $register_force(ENUMERATEITERATOR_ID,&B_IteratorD_enumerateG_methods); // $register_force(FILTERITERATOR_ID,&B_IteratorD_filterG_methods); // $register_force(MAPITERATOR_ID,&B_IteratorD_mapG_methods); $register_force(ZIPITERATOR_ID,&B_IteratorD_zipG_methods); $register_force(BASEEXCEPTION_ID,&B_BaseExceptionG_methods); $register_force(SYSTEMEXIT_ID,&B_SystemExitG_methods); $register_force(KEYBOARDINTERRUPT_ID,&B_KeyboardInterruptG_methods); $register_force(EXCEPTION_ID,&B_ExceptionG_methods); $register_force(ASSERTIONERROR_ID,&B_AssertionErrorG_methods); $register_force(LOOKUPERROR_ID,&B_LookupErrorG_methods); $register_force(INDEXERROR_ID,&B_IndexErrorG_methods); $register_force(KEYERROR_ID,&B_KeyErrorG_methods); $register_force(MEMORYERROR_ID,&B_MemoryErrorG_methods); $register_force(OSERROR_ID,&B_OSErrorG_methods); $register_force(RUNTIMEERROR_ID,&B_RuntimeErrorG_methods); $register_force(NOTIMPLEMENTEDERROR_ID,&B_NotImplementedErrorG_methods); $register_force(VALUEERROR_ID,&B_ValueErrorG_methods); // $register_builtin_protocols(); $register_force(SEQ_ID,&$SEQG_methods); $register_force(BRK_ID,&$BRKG_methods); $register_force(CNT_ID,&$CNTG_methods); $register_force(RET_ID,&$RETG_methods); $register_force(I8_ID,&B_i8G_methods); $register_force(I16_ID,&B_i16G_methods); $register_force(I32_ID,&B_i32G_methods); $register_force(I64_ID,&B_intG_methods); $register_force(U1_ID,&B_u1G_methods); $register_force(U8_ID,&B_u8G_methods); $register_force(U16_ID,&B_u16G_methods); $register_force(U32_ID,&B_u32G_methods); $register_force(U64_ID,&B_u64G_methods); } B_bool issubtype(int sub_id, int ancestor_id) { if (sub_id == ancestor_id) return B_True; $SuperG_class c = ($SuperG_class)$GET_METHODS(sub_id)->$superclass; while(c) if(c->$class_id == ancestor_id) return B_True; else c = c->$superclass; return B_False; } ================================================ FILE: base/builtin/registration.h ================================================ /* * During initialization of an Acton program we need to establish a one-to-one mapping between method tables and non-negative integers. * The latter are called class id's and for each object being serialized, its class id is stored together with serialization of its * local state. During deserialization, the class id is used to find the object's method table and hence its __deserialize__ method. * Builtin classes and classes in the runtime system have predefined class id's, mainly to ease debugging (e.g. to make reading * hexdumps of serialized files slightly less painful). * * This mechanism requires that the mapping between method tables and integers is the same in the serializing and the * deserializing system. This will be the case if they do registration for the same classes in the same order, typically * by being the same piece of software. */ #define UNASSIGNED -1 #define NONE_ID 0 #define ATOM_ID 1 #define INT_ID 2 #define FLOAT_ID 3 #define COMPLEX_ID 4 #define BOOL_ID 5 #define STR_ID 6 #define LIST_ID 7 #define DICT_ID 8 #define SET_ID 9 #define RANGE_ID 10 #define TUPLE_ID 11 #define BYTEARRAY_ID 12 #define ITEM_ID 13 #define MSG_ID 14 #define ACTOR_ID 15 #define CATCHER_ID 16 #define SLICE_ID 17 // Adding SLICE_ID by using a gap in the numbering... #define CONT_ID 18 #define DONE_ID 19 #define CONSTCONT_ID 20 #define STRITERATOR_ID 21 #define LISTITERATOR_ID 22 #define DICTITERATOR_ID 23 #define VALUESITERATOR_ID 24 #define ITEMSITERATOR_ID 25 #define SETITERATOR_ID 26 #define RANGEITERATOR_ID 27 #define ENUMERATEITERATOR_ID 28 #define FILTERITERATOR_ID 29 #define MAPITERATOR_ID 30 #define ZIPITERATOR_ID 31 #define BASEEXCEPTION_ID 32 #define SYSTEMEXIT_ID 33 #define KEYBOARDINTERRUPT_ID 34 #define EXCEPTION_ID 35 #define ASSERTIONERROR_ID 36 #define LOOKUPERROR_ID 37 #define INDEXERROR_ID 38 #define KEYERROR_ID 39 #define MEMORYERROR_ID 40 #define OSERROR_ID 41 #define RUNTIMEERROR_ID 42 #define NOTIMPLEMENTEDERROR_ID 43 #define VALUEERROR_ID 44 #define PROC_ID 45 #define ACTION_ID 46 #define MUT_ID 47 #define PURE_ID 48 #define SEQ_ID 49 #define BRK_ID 50 #define CNT_ID 51 #define RET_ID 52 #define I8_ID 53 #define I16_ID 54 #define I32_ID 55 #define I64_ID 56 #define U1_ID 57 #define U8_ID 58 #define U16_ID 59 #define U32_ID 60 #define U64_ID 61 #define PREASSIGNED 62 /* * Register the builtin classes (those with the above class id's except MSG_ID -- CONSTCONT_ID). * This must be the first registration call, since it also initializes the data structures containing the mapping. * This call does *not* register the rts class id's MSG_ID -- CONSTCONT_ID, which must be registered by * a call to register_rts in rts.h. */ void $register_builtin(); /* * Register a user defined class by supplying the address to its method table. A fresh class id is generated and * the internal mapping extended. Each class whose objects may be serialized must be registered. */ void $register($WORD meths); /* * Registering a class with predetermined class id. To be used for builtin and rts classes only. * */ void $register_force(int classid, $WORD meths); #define $GET_CLASSID(meths) ((meths)->$class_id) #define $GET_METHODS(classid) (($SerializableG_class)G_methods->data[classid]) // list of method tables indexed by class_id. Only accessed via GET_METHODS above extern B_list G_methods; B_bool issubtype(int sub_id, int ancestor_id); ================================================ FILE: base/builtin/serialize.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define BUF_SIZE 8192 // Queue implementation ////////////////////////////////////////////////////////////////// void $enqueue($Serial$state state, $ROW elem) { if (state->row) state->row->next = elem; else state->fst = elem; state->row = elem; } void $enqueue2(struct $ROWLISTHEADER *header, $ROW elem) { if (header->last) header->last->next = elem; else header->fst = elem; header->last = elem; } // Hashable$WORD methods ////////////////////////////////////////////////// void B_HashableD_WORDD___serialize__(B_HashableD_WORD self, $Serial$state state) { } B_HashableD_WORD B_HashableD_WORDD___deserialize__(B_HashableD_WORD self, $Serial$state state) { B_HashableD_WORD res = $DNEW(B_HashableD_WORD,state); return res; } B_bool B_HashableD_WORD_eq(B_HashableD_WORD wit, $WORD a, $WORD b) { return toB_bool(a==b); } B_bool B_HashableD_WORD_ne(B_HashableD_WORD wit, $WORD a, $WORD b) { return toB_bool(a != b); } B_NoneType B_HashableD_WORD_hash(B_HashableD_WORD wit, $WORD a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&a, 8)); return B_None; } struct B_HashableD_WORDG_class B_HashableD_WORDG_methods = { "B_HashableD_WORD", UNASSIGNED, ($SuperG_class)&B_HashableG_methods, (void (*)(B_HashableD_WORD))$default__init__, B_HashableD_WORDD___serialize__, B_HashableD_WORDD___deserialize__, (B_bool (*)(B_HashableD_WORD))$default__bool__, (B_str (*)(B_HashableD_WORD))$default__str__, (B_str (*)(B_HashableD_WORD))$default__str__, B_HashableD_WORD_eq, B_HashableD_WORD_ne, B_HashableD_WORD_hash }; struct B_HashableD_WORD B_HashableD_WORD_instance = {&B_HashableD_WORDG_methods}; struct B_HashableD_WORD *B_HashableD_WORDG_witness = &B_HashableD_WORD_instance; // small-step functions for (de)serializing the next object ///////////////////////////////////////////////// $ROW $add_header(int class_id, int blob_size, $Serial$state state) { $ROW res = acton_malloc(2 * sizeof(int) + (1+blob_size)*sizeof($WORD)); res->class_id = class_id; state->row_no++; res->blob_size = blob_size; res->next = NULL; $enqueue(state,res); return res; } void $step_serialize($WORD self, $Serial$state state) { if (self) { int class_id = $GET_CLASSID((($Serializable)self)->$class); if (class_id > ITEM_ID) { // not one of the Acton builtin datatypes, which have hand-crafted serializations if (state->globmap) { long key = (long)state->globmap(self); if (key < 0) { $val_serialize(-class_id,&key,state); return; } } B_int prevkey = (B_int)B_dictD_get(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,NULL); if (prevkey) { $val_serialize(-class_id,&prevkey->val,state); } else { B_dictD_setitem(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,toB_int(state->row_no)); $add_header(class_id,0,state); (($Serializable)self)->$class->__serialize__(self,state); } } else (($Serializable)self)->$class->__serialize__(self,state); } else $add_header(NONE_ID,0,state); } $WORD $step_deserialize($Serial$state state) { if (abs(state->row->class_id) > ITEM_ID) { $ROW this = state->row; state->row = this->next; state->row_no++; if (this->class_id < 0) { long key = (long)this->blob[0]; if (key < 0) return state->globmap(($WORD)key); else return B_dictD_get(state->done,(B_Hashable)B_HashableD_intG_witness,toB_int(key),NULL); } else return $GET_METHODS(this->class_id)->__deserialize__(NULL, state); } else return $GET_METHODS(abs(state->row->class_id))->__deserialize__(NULL, state); } void $val_serialize(int class_id, $WORD val,$Serial$state state) { $ROW row = $add_header(class_id,1,state); memcpy(row->blob,val,sizeof($WORD)); } $WORD $val_deserialize($Serial$state state) { $WORD res; memcpy(&res,(state->row)->blob,sizeof($WORD)); state->row = state->row->next; state->row_no++; return res; } // Serialization methods /////////////////////////////////////////////////////////////////////////////// void $write_serialized($ROW row, char *file) { char buf[BUF_SIZE]; char *p = buf; char *bufend = buf + BUF_SIZE; FILE *fileptr = fopen(file,"wb"); int chunk_size; char *start; while(row) { chunk_size = 2*sizeof(int); start = (char*)row; if (p+chunk_size > bufend) { int fits = bufend - p; memcpy(p,start,fits); fwrite(buf,1,sizeof(buf),fileptr); // TODO: handle file write error p = buf; chunk_size -= fits; start += fits; } memcpy(p,start,chunk_size); p+=chunk_size; chunk_size = (row->blob_size)*sizeof($WORD); start = (char*)row->blob; while (p+chunk_size > bufend) { int fits = bufend - p; memcpy(p,start,fits); fwrite(buf,1,sizeof(buf),fileptr); // TODO: handle file write error p = buf; chunk_size -= fits; start += fits; } memcpy(p,start,chunk_size); p+=chunk_size; row = row->next; } fwrite(buf,1,p-buf,fileptr); // TODO: handle file write error fclose(fileptr); } $ROW $serialize($Serializable s, $WORD (*globmap)($WORD)) { $Serial$state state = acton_malloc(sizeof(struct $Serial$state)); state->done = $NEW(B_dict,(B_Hashable)B_HashableD_WORDG_witness,NULL,NULL); state->globmap = globmap; state->row_no=0; state->row = NULL; state->fst = NULL; $step_serialize(s,state); return state->fst; } $ROW $glob_serialize($Serializable self, $WORD (*globmap)($WORD)) { $Serial$state state = acton_malloc(sizeof(struct $Serial$state)); state->done = $NEW(B_dict,(B_Hashable)B_HashableD_WORDG_witness,NULL,NULL); state->globmap = globmap; state->row_no=0; state->row = NULL; state->fst = NULL; $add_header(self->$class->$class_id,0,state); self->$class->__serialize__(self,state); return state->fst; } void $serialize_file($Serializable s, char *file) { $write_serialized($serialize(s,NULL),file); } $Serializable $deserialize($ROW row, $WORD (*globmap)($WORD)) { $Serial$state state = acton_malloc(sizeof(struct $Serial$state)); state->done = $NEW(B_dict,(B_Hashable)B_HashableD_intG_witness,NULL,NULL); state->globmap = globmap; state->row_no=0; state->row = row; state->fst = NULL; return $step_deserialize(state); } $Serializable $glob_deserialize($Serializable self, $ROW row, $WORD (*globmap)($WORD)) { $Serial$state state = acton_malloc(sizeof(struct $Serial$state)); state->done = $NEW(B_dict,(B_Hashable)B_HashableD_intG_witness,NULL,NULL); state->globmap = globmap; state->row_no=1; state->row = row->next; state->fst = NULL; return self->$class->__deserialize__(self,state); } $ROW $read_serialized(char *file) { char buf[BUF_SIZE]; char *p = buf; char *bufend; FILE *fileptr = fopen(file,"rb"); int chunk_size; char *start; struct $ROWLISTHEADER header; header.fst = NULL; header.last = NULL; bufend = buf + fread(buf,1,sizeof(buf),fileptr); while(p < bufend || !feof(fileptr)) { int init[2];//4 chunk_size = 2*sizeof(int); start = (char*)init; if (p + chunk_size > bufend) { int fits = bufend - p; memcpy(start,p,fits); bufend = buf + fread(buf,1,sizeof(buf),fileptr); // TODO: handle file write error p = buf; chunk_size -= fits; start += fits; } memcpy(start,p,chunk_size); p+=chunk_size; $ROW row = acton_malloc(2*sizeof(int) + (init[1]+1) * sizeof($WORD)); memcpy(row,init,2*sizeof(int));//4 row->next = NULL; chunk_size = (init[1]) * sizeof($WORD); start = (char*)row->blob; while (p + chunk_size > bufend) { int fits = bufend - p; memcpy(start,p,fits); bufend = buf + fread(buf,1,sizeof(buf),fileptr); // TODO: handle file write error p = buf; chunk_size -= fits; start += fits; } memcpy(start,p,chunk_size); p+=chunk_size; $enqueue2(&header,row); } return header.fst; } $Serializable $deserialize_file(char *file) { return $deserialize($read_serialized(file), NULL); } ================================================ FILE: base/builtin/serialize.h ================================================ // Types for serialization //////////////////////////////////////////////////////////////////////////// // The serialization of an Acton object/value is a linked list of $ROW:s. typedef struct $ROW *$ROW; struct $ROW { $ROW next; int class_id; int blob_size; $WORD blob[]; }; struct $ROWLISTHEADER { $ROW fst; $ROW last; }; //typedef struct $Serial$state *$Serial$state; struct $Serial$state { char *$GCINFO; B_dict done; $WORD (*globmap)($WORD); long row_no; $ROW row; $ROW fst; //not used in deserialization }; // small-step helpers for defining serializations ////////////////////////////////////////////////// void $step_serialize($WORD self, $Serial$state state); $WORD $step_deserialize($Serial$state state); void $val_serialize(int class_id, $WORD val, $Serial$state state); $WORD $val_deserialize($Serial$state state); $ROW $add_header(int class_id, int blob_size, $Serial$state state); // top-level functions for serialization of an object //////////////////////////////////////////////// long $total_rowsize($ROW); $ROW $serialize($Serializable s, $WORD (*globmap)($WORD)); $ROW $glob_serialize($Serializable s, $WORD (*globmap)($WORD)); void $write_serialized($ROW row, char *file); // $serialize_file just calls the above two functions void $serialize_file($Serializable s, char *file); $Serializable $deserialize($ROW row, $WORD (*globmap)($WORD)); $Serializable $glob_deserialize($Serializable s, $ROW row, $WORD (*globmap)($WORD)); $ROW $read_serialized(char *file); // $deserialize_file just calls the above two functions $Serializable $deserialize_file(char *file); // B_HashableD_WORD (for pointers) //////////////////////////////////////////////////////////////////////// // B_HashableD_WORDG_witness is needed to create the MappingB_dict witness necessary for serialization. typedef struct B_HashableD_WORD *B_HashableD_WORD; struct B_HashableD_WORDG_class { char *$GCINFO; int $class_id; $SuperG_class superclass; void (*__init__)(B_HashableD_WORD); void (*__serialize__)(B_HashableD_WORD,$Serial$state); B_HashableD_WORD (*__deserialize__)(B_HashableD_WORD,$Serial$state); B_bool (*__bool__)(B_HashableD_WORD); B_str (*__str__)(B_HashableD_WORD); B_str (*__repr__)(B_HashableD_WORD); B_bool (*__eq__)(B_HashableD_WORD, $WORD, $WORD); B_bool (*__ne__)(B_HashableD_WORD, $WORD, $WORD); B_NoneType (* hash)(B_HashableD_WORD, $WORD, B_hasher); }; struct B_HashableD_WORD { struct B_HashableD_WORDG_class *$class; }; extern struct B_HashableD_WORDG_class B_HashableD_WORDG_methods; B_HashableD_WORD B_HashableD_WORDG_new(); extern struct B_HashableD_WORD *B_HashableD_WORDG_witness; ================================================ FILE: base/builtin/set.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DISCARD_NOTFOUND 0 #define DISCARD_FOUND 1 #define PERTURB_SHIFT 5 #define MIN_SIZE 8 static $WORD _dummy; #define dummy (&_dummy) // Auxiliary functions /////////////////////////////////////////////////////////////////////////////// static void B_set_insert_clean(B_setentry *table, long mask, $WORD *key, long hash) { B_setentry *entry; long perturb = hash; long i = hash & mask; long j; while (1) { entry = &table[i]; if (entry->key == NULL) goto found_null; perturb >>= PERTURB_SHIFT; i = (i * 5 + 1 + perturb) & mask; } found_null: entry->key = key; entry->hash = hash; } static int B_set_table_resize(B_set so, int minsize) { B_setentry *oldtable, *newtable, *entry; long oldmask = so->mask; long newmask; /* Find the smallest table size > minsize. */ long newsize = MIN_SIZE; while (newsize <= (long)minsize) { newsize <<= 1; // The largest possible value is PY_SSIZE_T_MAX + 1. } /* Get space for a new table. */ oldtable = so->table; newtable = acton_malloc(sizeof(B_setentry) * newsize); if (newtable == NULL) { return -1; } /* Make the B_set empty, using the new table. */ memset(newtable, 0, sizeof(B_setentry) * newsize); so->mask = newsize - 1; so->table = newtable; /* Copy the data over; dummy entries aren't copied over, of course */ newmask = (long)so->mask; if (so->fill == so->numelements) { for (entry = oldtable; entry <= oldtable + oldmask; entry++) { if (entry->key != NULL) { B_set_insert_clean(newtable, newmask, entry->key, entry->hash); } } } else { so->fill = so->numelements; for (entry = oldtable; entry <= oldtable + oldmask; entry++) { if (entry->key != NULL && entry->key != dummy) { B_set_insert_clean(newtable, newmask, entry->key, entry->hash); } } } acton_free(oldtable); return 0; } static B_setentry *B_set_lookkey(B_set set, B_Hashable hashwit, $WORD key, long hash) { B_setentry *entry; long perturb; long mask = set->mask; long i = hash & mask; entry = &set->table[i]; if (entry->key == NULL) return entry; perturb = hash; while (1) { if (entry->hash == hash) { $WORD *startkey = entry->key; // startkey cannot be a dummy because the dummy hash field is -1 // assert(startkey != dummy); if (startkey == key || hashwit->$class->__eq__(hashwit,startkey,key)) return entry; } perturb >>= PERTURB_SHIFT; i = (i * 5 + 1 + perturb) & mask; entry = &set->table[i]; if (entry->key == NULL) return entry; } } static int B_set_contains_entry(B_set set, B_Hashable hashwit, $WORD elem, long hash) { return B_set_lookkey(set, hashwit, elem, hash)->key != NULL; } void B_set_add_entry(B_set set, B_Hashable hashwit, $WORD key, long hash) { B_setentry *freeslot; B_setentry *entry; long perturb; long mask; long i; mask = set->mask; i = hash & mask; entry = &set->table[i]; if (entry->key == NULL) goto found_unused; freeslot = NULL; perturb = hash; while (1) { if (entry->hash == hash) { $WORD startkey = entry->key; // startkey cannot be a dummy because the dummy hash field is -1 if (startkey == key || hashwit->$class->__eq__(hashwit,startkey,key)) goto found_active; } else if (entry->hash == -1) freeslot = entry; perturb >>= PERTURB_SHIFT; i = (i * 5 + 1 + perturb) & mask; entry = &set->table[i]; if (entry->key == NULL) goto found_unused_or_dummy; } found_unused_or_dummy: if (freeslot == NULL) goto found_unused; set->numelements++; freeslot->key = key; freeslot->hash = hash; return; found_unused: set->fill++; set->numelements++; entry->key = key; entry->hash = hash; if ((size_t)set->fill*5 < mask*3) return; B_set_table_resize(set, set->numelements>50000 ? set->numelements*2 : set->numelements*4); return; found_active: return; } B_set B_set_copy(B_set set, B_Hashable hashwit) { B_set res = acton_malloc(sizeof(struct B_set)); memcpy(res,set,sizeof(struct B_set)); res->table = acton_malloc((set->mask+1)*sizeof(B_setentry)); memcpy(res->table,set->table,(set->mask+1)*sizeof(B_setentry)); return res; } static int B_set_discard_entry(B_set set, B_Hashable hashwit, $WORD elem, long hash) { B_setentry *entry = B_set_lookkey(set,hashwit,elem, hash); if (entry->key != NULL) { entry->key = dummy; entry->hash = -1; set->numelements--; return DISCARD_FOUND; } else return DISCARD_NOTFOUND; } // General methods /////////////////////////////////////////////////////////////////////////////////// B_set B_setG_new(B_Hashable hashwit, B_Iterable wit, $WORD iterable) { return $NEW(B_set, hashwit, wit, iterable); } B_NoneType B_setD___init__(B_set set, B_Hashable hashwit, B_Iterable wit, $WORD iterable) { set->numelements = 0; set->fill = 0; set->mask = MIN_SIZE-1; set->finger = 0; set->table = acton_malloc(MIN_SIZE*sizeof(B_setentry)); memset(set->table,0,MIN_SIZE*sizeof(B_setentry)); if (wit && iterable) { B_Iterator it = wit->$class->__iter__(wit,iterable); while(1) { if ($PUSH()) { $WORD nxt = it->$class->__next__(it); B_set_add_entry(set,hashwit,nxt,fromB_u64(B_hash(hashwit, nxt))); $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } } return B_None; } B_bool B_setD___bool__(B_set self) { return toB_bool(self->numelements>0); } B_str B_setD___str__(B_set self) { B_list s2 = B_listD_new(self->numelements); B_SequenceD_list wit = B_SequenceD_listG_witness; B_IteratorD_set iter = $NEW(B_IteratorD_set,self); B_value elem; for (int i=0; inumelements; i++) { elem = (B_value)iter->$class->__next__(iter); wit->$class->append(wit,s2,elem->$class->__repr__(elem)); } return B_strD_join_par('{',s2,'}'); } B_str B_setD___repr__(B_set self) { return B_setD___str__(self); } void B_setD___serialize__(B_set self, $Serial$state state) { B_int prevkey = (B_int)B_dictD_get(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,NULL); if (prevkey) { long pk = fromB_int(prevkey); $val_serialize(-SET_ID,&pk,state); return; } B_dictD_setitem(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,toB_int(state->row_no)); $ROW row = $add_header(SET_ID,4,state); row->blob[0] = ($WORD)self->numelements; row->blob[1] = ($WORD)self->fill; row->blob[2] = ($WORD)self->mask; row->blob[3] = ($WORD)self->finger; for (long i=0; i<=self->mask; i++) { B_setentry *entry = &self->table[i]; $step_serialize(toB_int(entry->hash),state); $step_serialize(entry->key,state); } } B_set B_setD___deserialize__ (B_set res, $Serial$state state) { $ROW this = state->row; state->row = this->next; state->row_no++; if (this->class_id < 0) { return B_dictD_get(state->done,(B_Hashable)B_HashableD_intG_witness,toB_int((long)this->blob[0]),NULL); } else { if (!res) res = acton_malloc(sizeof(struct B_set)); B_dictD_setitem(state->done,(B_Hashable)B_HashableD_intG_witness,toB_int(state->row_no-1),res); res->$class = &B_setG_methods; res->numelements = (long)this->blob[0]; res->fill = (long)this->blob[1]; res->mask = (long)this->blob[2]; res->finger = (long)this->blob[3]; res->table = acton_malloc((res->mask+1)*sizeof(B_setentry)); memset(res->table,0,(res->mask+1)*sizeof(B_setentry)); for (int i=0; i<=res->mask;i++) { B_setentry *entry = &res->table[i]; entry->hash = fromB_int((B_int)$step_deserialize(state)); entry->key = $step_deserialize(state); if (entry->hash==-1) entry->key = dummy; } return res; } } // B_Set // Iterable /////////////////////////////////////////////////////////////////////////////////////// Leif static $WORD B_IteratorD_set_next_entry(B_IteratorD_set self) { B_setentry *table = self->src->table; long n = self->src->mask; long i = self->nxt; while (i <= n) { B_setentry *entry = &table[i]; if (entry->key != NULL && entry->key != dummy) { self->nxt = i+1; return entry; } i++; } $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("set iterator terminated"))); return NULL; //to avoid compiler warning } static B_Iterator B_set_iter_entry(B_set set) { B_IteratorD_set iter = acton_malloc(sizeof(struct B_IteratorD_set)); struct B_IteratorD_setG_class *methods = acton_malloc(sizeof(struct B_IteratorD_setG_class)); iter->$class = methods; methods->__next__ = B_IteratorD_set_next_entry; iter->src = set; iter->nxt = 0; return (B_Iterator)iter; } static $WORD B_IteratorD_set_next(B_IteratorD_set self) { $WORD res; if((res = B_IteratorD_set_next_entry(self))) { return ((B_setentry*)res)->key; } return NULL; } B_IteratorD_set B_IteratorD_setG_new(B_set s) { return $NEW(B_IteratorD_set, s); } void B_IteratorD_set_init(B_IteratorD_set self, B_set set) { self->src = set; self->nxt = 0; } B_bool B_IteratorD_set_bool(B_IteratorD_set self) { return B_True; } B_str B_IteratorD_set_str(B_IteratorD_set self) { return $FORMAT("", self); } void B_IteratorD_set_serialize(B_IteratorD_set self, $Serial$state state) { $step_serialize(self->src,state); $step_serialize(toB_int(self->nxt),state); } B_IteratorD_set B_IteratorD_setD__deserialize(B_IteratorD_set res, $Serial$state state) { if (!res) res = $DNEW(B_IteratorD_set,state); res->src = (B_set)$step_deserialize(state); res->nxt = fromB_int((B_int)$step_deserialize(state)); return res; } struct B_IteratorD_setG_class B_IteratorD_setG_methods = {"B_IteratorD_set",UNASSIGNED,($SuperG_class)&B_IteratorG_methods, B_IteratorD_set_init, B_IteratorD_set_serialize, B_IteratorD_setD__deserialize,B_IteratorD_set_bool,B_IteratorD_set_str,B_IteratorD_set_str, B_IteratorD_set_next}; B_Iterator B_SetD_setD___iter__ (B_SetD_set wit, B_set set) { return (B_Iterator)$NEW(B_IteratorD_set,set); } B_NoneType B_SetD_setD_add (B_SetD_set wit, B_set set, $WORD elem) { B_Hashable hashwit = wit->W_HashableD_AD_SetD_set; B_set_add_entry(set,hashwit,elem,fromB_u64(B_hash(hashwit, elem))); return B_None; } B_set B_SetD_setD___fromiter__(B_SetD_set wit, B_Iterable wit2, $WORD iter) { return B_setG_new(wit->W_HashableD_AD_SetD_set, wit2, iter); /* B_Iterator it = wit2->$class->__iter__(wit2,iter); B_set res = $NEW(B_set,hashwit,NULL,NULL); res->numelements = 0; res->fill = 0; res->mask = MIN_SIZE-1; res->finger = 0; res->table = acton_malloc(MIN_SIZE*sizeof(B_setentry)); memset(res->table,0,MIN_SIZE*sizeof(B_setentry)); $WORD nxt; while((nxt = it->$class->__next__(it))) { B_set_add_entry(res,hashwit,nxt,fromB_u64(B_hash(hashwit, nxt))); } return res; */ } B_int B_SetD_setD___len__ (B_SetD_set wit, B_set set) { return toB_int(set->numelements); } B_bool B_SetD_setD___contains__ (B_SetD_set wit, B_set set, $WORD val) { B_Hashable hashwit = wit->W_HashableD_AD_SetD_set; return toB_bool(B_set_contains_entry(set,hashwit,val,fromB_u64(B_hash(hashwit, val)))); } B_bool B_SetD_setD___containsnot__ (B_SetD_set wit, B_set set, $WORD v) { return toB_bool(!B_SetD_setD___contains__(wit,set,v)->val); } B_bool B_SetD_setD_isdisjoint (B_SetD_set wit, B_set set, B_set other) { B_Hashable hashwit = wit->W_HashableD_AD_SetD_set; if (set == other) return toB_bool(set->numelements == 0); if (other->numelements > set->numelements) return B_SetD_setD_isdisjoint(wit,other,set); B_Iterator iter = B_set_iter_entry(other); $WORD w; long res = 1; while((w = $next(iter))){ if(B_set_contains_entry(set, hashwit,((B_setentry*)w)->key, ((B_setentry*)w)->hash)) { res = 0; break; } } return toB_bool(res); } // TODO: ideally this could be defined in .act file instead of C since we just // need to call the .add() method, but that doesn't currently seem to work B_NoneType B_SetD_setD_update (B_SetD_set wit, B_set set, B_Iterable otherwit, $WORD other) { B_Hashable hashwit = wit->W_HashableD_AD_SetD_set; if (set == other) return B_None; B_Iterator it = otherwit->$class->__iter__(otherwit, other); while(1) { if ($PUSH()) { $WORD e = it->$class->__next__(it); B_set_add_entry(set, hashwit, e, fromB_u64(B_hash(hashwit, e))); $DROP(); } else { B_BaseException ex = $POP(); if ($ISINSTANCE0(ex, B_StopIteration)) break; else $RAISE(ex); } } return B_None; } B_NoneType B_SetD_setD_discard (B_SetD_set wit, B_set set, $WORD elem) { B_Hashable hashwit = wit->W_HashableD_AD_SetD_set; B_set_discard_entry(set,hashwit,elem,fromB_u64(B_hash(hashwit, elem))); return B_None; } $WORD B_SetD_setD_pop (B_SetD_set wit, B_set set) { if (set->numelements == 0) $RAISE((B_BaseException)$NEW(B_ValueError, to$str("pop from an empty set"))); $WORD res; // Make sure the search finger is in bounds B_setentry *entry = set->table + (set->finger & set->mask); B_setentry *limit = set->table + set->mask; while (entry->key == NULL || entry->key==dummy) { entry++; if (entry > limit) entry = set->table; } res = entry->key; entry->key = dummy; entry->hash = -1; set->numelements--; set->finger = entry - set->table + 1; // next place to start return res; } // B_Ord B_bool B_OrdD_SetD_setD___eq__ (B_OrdD_SetD_set wit, B_set set, B_set other) { B_Hashable hashwit = ((B_SetD_set)wit->W_Set)->W_HashableD_AD_SetD_set; if (set == other) return B_True; if (set->numelements != other->numelements) return B_False; B_Iterator iter = B_set_iter_entry(other); long n = 0; while(n < set->numelements) { $WORD w = $next(iter); if(!B_set_contains_entry(set, hashwit, ((B_setentry*)w)->key, ((B_setentry*)w)->hash)) return B_False; n++; } return B_True; } B_bool B_OrdD_SetD_setD___ne__ (B_OrdD_SetD_set wit, B_set set, B_set other) { return toB_bool(!B_OrdD_SetD_setD___eq__ (wit,set,other)->val); } B_bool B_OrdD_SetD_setD___gt__ (B_OrdD_SetD_set wit, B_set set, B_set other) { B_Hashable hashwit = ((B_SetD_set)wit->W_Set)->W_HashableD_AD_SetD_set; if (set == other) return B_False; if (set->numelements <= other->numelements) return B_False; B_Iterator iter = B_set_iter_entry(other); long n = 0; while(n < other->numelements) { $WORD w = $next(iter); if(!B_set_contains_entry(set, hashwit, ((B_setentry*)w)->key, ((B_setentry*)w)->hash)) return B_False; n++; } return B_True; } B_bool B_OrdD_SetD_setD___ge__ (B_OrdD_SetD_set wit, B_set set, B_set other) { B_Hashable hashwit = ((B_SetD_set)wit->W_Set)->W_HashableD_AD_SetD_set; if (set == other) return B_False; if (set->numelements < other->numelements) return B_False; B_Iterator iter = B_set_iter_entry(other); long n = 0; while(n < other->numelements) { $WORD w = $next(iter); if(!B_set_contains_entry(set, hashwit, ((B_setentry*)w)->key, ((B_setentry*)w)->hash)) return B_False; n++; } return B_True; } B_bool B_OrdD_SetD_setD___lt__ (B_OrdD_SetD_set wit, B_set set, B_set other) { return B_OrdD_SetD_setD___gt__(wit, other, set); } B_bool B_OrdD_SetD_setD___le__ (B_OrdD_SetD_set wit, B_set set, B_set other) { return B_OrdD_SetD_setD___ge__(wit, other, set); } // B_Minus B_set B_MinusD_SetD_setD___sub__ (B_MinusD_SetD_set wit, B_set set, B_set other) { B_Hashable hashwit = ((B_SetD_set)wit->W_Set)->W_HashableD_AD_SetD_set; B_set res = B_set_copy(set,hashwit); B_Iterator iter = B_set_iter_entry(other); long n = 0; while(n < other->numelements) { $WORD w = $next(iter); $WORD key = ((B_setentry*)w)->key; long hash = ((B_setentry*)w)->hash; B_set_discard_entry(res,hashwit,key,hash); n++; } return res; } // B_Logical B_set B_LogicalD_SetD_setD___and__(B_LogicalD_SetD_set wit, B_set set, B_set other) { B_Hashable hashwit = ((B_SetD_set)wit->W_Set)->W_HashableD_AD_SetD_set; if (other->numelements > set->numelements) return B_LogicalD_SetD_setD___and__(wit,other,set); B_set res = $NEW(B_set,hashwit,NULL,NULL); B_Iterator iter = B_set_iter_entry(set); long n = 0; while(n < set->numelements) { $WORD w = $next(iter); $WORD key = ((B_setentry*)w)->key; long hash = ((B_setentry*)w)->hash; if (B_set_contains_entry(other,hashwit,key,hash)) B_set_add_entry(res,hashwit,key,hash); n++; } return res; } B_set B_LogicalD_SetD_setD___or__ (B_LogicalD_SetD_set wit, B_set set, B_set other) { B_Hashable hashwit = ((B_SetD_set)wit->W_Set)->W_HashableD_AD_SetD_set; if (other->numelements > set->numelements) return B_LogicalD_SetD_setD___or__ (wit,other,set); B_set res = B_set_copy(set, hashwit); B_Iterator iter = B_set_iter_entry(other); long n = 0; while(n < other->numelements) { $WORD w = $next(iter); $WORD key = ((B_setentry*)w)->key; long hash = ((B_setentry*)w)->hash; B_set_add_entry(res,hashwit,key,hash); n++; } return res; } B_set B_LogicalD_SetD_setD___xor__(B_LogicalD_SetD_set wit, B_set set, B_set other) { B_Hashable hashwit = ((B_SetD_set)wit->W_Set)->W_HashableD_AD_SetD_set; B_set res = B_set_copy(set, hashwit); B_Iterator iter = B_set_iter_entry(other); long n = 0; while(n < other->numelements) { $WORD w = $next(iter); $WORD key = ((B_setentry*)w)->key; long hash = ((B_setentry*)w)->hash; if(!B_set_discard_entry(res,hashwit,key,hash)) B_set_add_entry(res,hashwit,key,hash); n++; } return res; } #undef dummy ================================================ FILE: base/builtin/set.h ================================================ typedef struct { $WORD key; long hash; } B_setentry; struct B_set { struct B_setG_class *$class; long numelements; // nr of elements in B_set long fill; // numelements + #dummy entries long mask; long finger; // Search finger for pop() B_setentry *table; // the hashtable }; // Iterators over sets /////////////////////////////////////////////////////// typedef struct B_IteratorD_set *B_IteratorD_set; ; struct B_IteratorD_setG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_IteratorD_set, B_set); void (*__serialize__)(B_IteratorD_set, $Serial$state); B_IteratorD_set (*__deserialize__)(B_IteratorD_set, $Serial$state); B_bool (*__bool__)(B_IteratorD_set); B_str (*__str__)(B_IteratorD_set); B_str (*__repr__)(B_IteratorD_set); $WORD(*__next__)(B_IteratorD_set); }; struct B_IteratorD_set { struct B_IteratorD_setG_class *$class; B_set src; int nxt; }; extern struct B_IteratorD_setG_class B_IteratorD_setG_methods; B_IteratorD_set B_IteratorD_setG_new(B_set); void B_set_add_entry(B_set set, B_Hashable hashwit, $WORD key, long hash); ================================================ FILE: base/builtin/slice.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Normalize slice notation, so that - if step == 0, VALUEERROR is raised - Otherwise, - on input, len must be the # of elements in the sequence being sliced - on output - 0 <= *start <= len is the starting position - 0 <= *stop <= len is the ending position (*non-inclusive*!) - *step is the step size (which may be negative) - *slen is the # of elements in the slice. */ void normalize_slice(B_slice slc, int64_t len, int64_t *slen, int64_t *start, int64_t *stop, int64_t *step) { if (slc->step == NULL) *step = 1; else *step = *slc->step; if (*step == 0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("step size 0 in slice"))); } if (slc->start == NULL) *start = *step > 0 ? 0 : len-1; else { *start = *slc->start; *start = *start >=0 ? (*start < len ? *start : len-1 + (*step > 0)) : (*start > -len ? len+*start : 0); } if (slc->stop == NULL) *stop = *step > 0 ? len : -1; else { *stop = *slc->stop; *stop = *stop >= 0 ? (*stop < len ? *stop : len-1 + (*step > 0)) : (*stop > -len ? len+*stop : 0); } if ((*step > 0 && *start >= *stop) || (*step < 0 && *start <= *stop)) *slen = 0; else *slen = (*stop-*start)/ *step + ((*stop-*start)%*step != 0); } B_slice B_sliceG_new(B_int start, B_int stop, B_int step) { return $NEW(B_slice,start,stop,step); } B_NoneType B_sliceD___init__(B_slice s, B_int start, B_int stop, B_int step) { if (start) { s->start = acton_malloc(sizeof(int64_t)); *s->start = fromB_int(start); } else s->start = NULL; if (stop) { s->stop = acton_malloc(sizeof(int64_t)); *s->stop = fromB_int(stop); } else s->stop = NULL; if (step) { s->step = acton_malloc(sizeof(int64_t)); *s->step = fromB_int(step); } else s->step = NULL; return B_None; } void B_sliceD___serialize__ (B_slice self, $Serial$state state) { $ROW row = $add_header(SLICE_ID,3,state); row->blob[0] = ($WORD)*self->start; row->blob[1] = ($WORD)*self->stop; row->blob[2] = ($WORD)*self->step; } B_slice B_sliceD___deserialize__ (B_slice self, $Serial$state state) { $ROW this = state->row; state->row = this->next; state->row_no++; B_slice res = acton_malloc(sizeof(struct B_slice)); res->$class = &B_sliceG_methods; res->start = acton_malloc(sizeof(long)); res->stop = acton_malloc(sizeof(long)); res->step = acton_malloc(sizeof(long)); *res->start = (long)this->blob[0]; *res->stop = (long)this->blob[1]; *res->step = (long)this->blob[2]; return res; } B_bool B_sliceD___bool__(B_slice s) { return B_True; } B_str B_sliceD___str__(B_slice s) { return $FORMAT("Slice [%ld:%ld:%ld]", *s->start, *s->stop, *s->step); } B_str B_sliceD___repr__(B_slice s) { return B_sliceD___str__(s); } ================================================ FILE: base/builtin/slice.h ================================================ struct B_slice { struct B_sliceG_class *$class; int64_t *start; int64_t *stop; int64_t *step; }; void normalize_slice(B_slice slc, int64_t len, int64_t *slen, int64_t *start, int64_t *stop, int64_t *step); ================================================ FILE: base/builtin/staticWitnesses.c ================================================ struct B_HashableD_bytes B_HashableD_bytesG_instance; struct B_TimesD_bytes B_TimesD_bytesG_instance; struct B_ContainerD_bytes B_ContainerD_bytesG_instance; struct B_SliceableD_bytes B_SliceableD_bytesG_instance; struct B_OrdD_bytes B_OrdD_bytesG_instance; struct B_ContainerD_bytearray B_ContainerD_bytearrayG_instance; struct B_TimesD_SequenceD_bytearray B_TimesD_SequenceD_bytearrayG_instance; struct B_CollectionD_SequenceD_bytearray B_CollectionD_SequenceD_bytearrayG_instance; struct B_SequenceD_bytearray B_SequenceD_bytearrayG_instance; struct B_OrdD_bytearray B_OrdD_bytearrayG_instance; struct B_HashableD_str B_HashableD_strG_instance; struct B_TimesD_str B_TimesD_strG_instance; struct B_SliceableD_str B_SliceableD_strG_instance; struct B_ContainerD_str B_ContainerD_strG_instance; struct B_OrdD_str B_OrdD_strG_instance; // struct B_IterableD_range B_IterableD_rangeG_instance; struct B_IterableD_Iterator B_IterableD_IteratorG_instance; struct B_SetD_set B_SetD_setG_instance; struct B_OrdD_dict B_OrdD_dictG_instance; struct B_MappingD_dict B_MappingD_dictG_instance; struct B_OrdD_list B_OrdD_listG_instance; struct B_ContainerD_list B_ContainerD_listG_instance; struct B_TimesD_SequenceD_list B_TimesD_SequenceD_listG_instance; struct B_CollectionD_SequenceD_list B_CollectionD_SequenceD_listG_instance; struct B_SequenceD_list B_SequenceD_listG_instance; struct B_SequenceD_list B_SequenceD_listG_instance; struct B_HashableD_complex B_HashableD_complexG_instance; struct B_EqD_complex B_EqD_complexG_instance; struct B_DivD_complex B_DivD_complexG_instance; struct B_MinusD_NumberD_complex B_MinusD_NumberD_complexG_instance; struct B_NumberD_complex B_NumberD_complexG_instance; struct B_HashableD_float B_HashableD_floatG_instance; struct B_OrdD_float B_OrdD_floatG_instance; struct B_DivD_float B_DivD_floatG_instance; struct B_MinusD_RealFloatD_float B_MinusD_RealFloatD_floatG_instance; struct B_RealFloatD_float B_RealFloatD_floatG_instance; struct B_HashableD_u1 B_HashableD_u1G_instance; struct B_OrdD_u1 B_OrdD_u1G_instance; struct B_DivD_u1 B_DivD_u1G_instance; struct B_LogicalD_IntegralD_u1 B_LogicalD_IntegralD_u1G_instance; struct B_MinusD_IntegralD_u1 B_MinusD_IntegralD_u1G_instance; struct B_IntegralD_u1 B_IntegralD_u1G_instance; struct B_HashableD_u8 B_HashableD_u8G_instance; struct B_OrdD_u8 B_OrdD_u8G_instance; struct B_DivD_u8 B_DivD_u8G_instance; struct B_LogicalD_IntegralD_u8 B_LogicalD_IntegralD_u8G_instance; struct B_MinusD_IntegralD_u8 B_MinusD_IntegralD_u8G_instance; struct B_IntegralD_u8 B_IntegralD_u8G_instance; struct B_HashableD_u16 B_HashableD_u16G_instance; struct B_OrdD_u16 B_OrdD_u16G_instance; struct B_DivD_u16 B_DivD_u16G_instance; struct B_LogicalD_IntegralD_u16 B_LogicalD_IntegralD_u16G_instance; struct B_MinusD_IntegralD_u16 B_MinusD_IntegralD_u16G_instance; struct B_IntegralD_u16 B_IntegralD_u16G_instance; struct B_HashableD_u32 B_HashableD_u32G_instance; struct B_OrdD_u32 B_OrdD_u32G_instance; struct B_DivD_u32 B_DivD_u32G_instance; struct B_LogicalD_IntegralD_u32 B_LogicalD_IntegralD_u32G_instance; struct B_MinusD_IntegralD_u32 B_MinusD_IntegralD_u32G_instance; struct B_IntegralD_u32 B_IntegralD_u32G_instance; struct B_HashableD_u64 B_HashableD_u64G_instance; struct B_OrdD_u64 B_OrdD_u64G_instance; struct B_DivD_u64 B_DivD_u64G_instance; struct B_LogicalD_IntegralD_u64 B_LogicalD_IntegralD_u64G_instance; struct B_MinusD_IntegralD_u64 B_MinusD_IntegralD_u64G_instance; struct B_IntegralD_u64 B_IntegralD_u64G_instance; struct B_HashableD_i8 B_HashableD_i8G_instance; struct B_OrdD_i8 B_OrdD_i8G_instance; struct B_DivD_i8 B_DivD_i8G_instance; struct B_LogicalD_IntegralD_i8 B_LogicalD_IntegralD_i8G_instance; struct B_MinusD_IntegralD_i8 B_MinusD_IntegralD_i8G_instance; struct B_IntegralD_i8 B_IntegralD_i8G_instance; struct B_HashableD_i16 B_HashableD_i16G_instance; struct B_OrdD_i16 B_OrdD_i16G_instance; struct B_DivD_i16 B_DivD_i16G_instance; struct B_LogicalD_IntegralD_i16 B_LogicalD_IntegralD_i16G_instance; struct B_MinusD_IntegralD_i16 B_MinusD_IntegralD_i16G_instance; struct B_IntegralD_i16 B_IntegralD_i16G_instance; struct B_HashableD_i32 B_HashableD_i32G_instance; struct B_OrdD_i32 B_OrdD_i32G_instance; struct B_DivD_i32 B_DivD_i32G_instance; struct B_LogicalD_IntegralD_i32 B_LogicalD_IntegralD_i32G_instance; struct B_MinusD_IntegralD_i32 B_MinusD_IntegralD_i32G_instance; struct B_IntegralD_i32 B_IntegralD_i32G_instance; struct B_HashableD_int B_HashableD_intG_instance; struct B_OrdD_int B_OrdD_intG_instance; struct B_DivD_int B_DivD_intG_instance; struct B_LogicalD_IntegralD_int B_LogicalD_IntegralD_intG_instance; struct B_MinusD_IntegralD_int B_MinusD_IntegralD_intG_instance; struct B_IntegralD_int B_IntegralD_intG_instance; struct B_HashableD_bigint B_HashableD_bigintG_instance; struct B_OrdD_bigint B_OrdD_bigintG_instance; struct B_DivD_bigint B_DivD_bigintG_instance; struct B_LogicalD_IntegralD_bigint B_LogicalD_IntegralD_bigintG_instance; struct B_MinusD_IntegralD_bigint B_MinusD_IntegralD_bigintG_instance; struct B_IntegralD_bigint B_IntegralD_bigintG_instance; struct B_HashableD_bool B_HashableD_boolG_instance; struct B_HashableD_bytes B_HashableD_bytesG_instance = {&B_HashableD_bytesG_methods}; struct B_TimesD_bytes B_TimesD_bytesG_instance = {&B_TimesD_bytesG_methods}; struct B_ContainerD_bytes B_ContainerD_bytesG_instance = {&B_ContainerD_bytesG_methods}; struct B_SliceableD_bytes B_SliceableD_bytesG_instance = {&B_SliceableD_bytesG_methods}; struct B_OrdD_bytes B_OrdD_bytesG_instance = {&B_OrdD_bytesG_methods}; struct B_ContainerD_bytearray B_ContainerD_bytearrayG_instance = {&B_ContainerD_bytearrayG_methods}; struct B_TimesD_SequenceD_bytearray B_TimesD_SequenceD_bytearrayG_instance = {&B_TimesD_SequenceD_bytearrayG_methods, (B_Sequence)&B_SequenceD_bytearrayG_instance}; struct B_CollectionD_SequenceD_bytearray B_CollectionD_SequenceD_bytearrayG_instance = {&B_CollectionD_SequenceD_bytearrayG_methods, (B_Sequence)&B_SequenceD_bytearrayG_instance}; struct B_SequenceD_bytearray B_SequenceD_bytearrayG_instance = {&B_SequenceD_bytearrayG_methods, (B_Eq)&B_OrdD_bigintG_methods, (B_Collection)&B_CollectionD_SequenceD_bytearrayG_instance, (B_Times)&B_TimesD_SequenceD_bytearrayG_instance}; struct B_OrdD_bytearray B_OrdD_bytearrayG_instance = {&B_OrdD_bytearrayG_methods}; struct B_HashableD_str B_HashableD_strG_instance = {&B_HashableD_strG_methods}; struct B_TimesD_str B_TimesD_strG_instance = {&B_TimesD_strG_methods}; struct B_SliceableD_str B_SliceableD_strG_instance = {&B_SliceableD_strG_methods}; struct B_ContainerD_str B_ContainerD_strG_instance = {&B_ContainerD_strG_methods}; struct B_OrdD_str B_OrdD_strG_instance = {&B_OrdD_strG_methods}; //struct B_IterableD_range B_IterableD_rangeG_instance = {&B_IterableD_rangeG_methods}; struct B_IterableD_Iterator B_IterableD_IteratorG_instance = {&B_IterableD_IteratorG_methods}; struct B_SetD_set B_SetD_setG_instance = {&B_SetD_setG_methods}; struct B_OrdD_dict B_OrdD_dictG_instance = {&B_OrdD_dictG_methods}; struct B_MappingD_dict B_MappingD_dictG_instance = {&B_MappingD_dictG_methods}; struct B_OrdD_list B_OrdD_listG_instance = {&B_OrdD_listG_methods}; struct B_ContainerD_list B_ContainerD_listG_instance = {&B_ContainerD_listG_methods}; struct B_TimesD_SequenceD_list B_TimesD_SequenceD_listG_instance = {&B_TimesD_SequenceD_listG_methods, (B_Sequence)&B_SequenceD_listG_instance}; struct B_CollectionD_SequenceD_list B_CollectionD_SequenceD_listG_instance = {&B_CollectionD_SequenceD_listG_methods, (B_Sequence)&B_SequenceD_listG_instance}; struct B_SequenceD_list B_SequenceD_listG_instance = {&B_SequenceD_listG_methods, (B_Eq)&B_OrdD_bigintG_methods, (B_Collection)&B_CollectionD_SequenceD_listG_instance, (B_Times)&B_TimesD_SequenceD_listG_instance}; struct B_HashableD_complex B_HashableD_complexG_instance = {&B_HashableD_complexG_methods}; struct B_EqD_complex B_EqD_complexG_instance = {&B_EqD_complexG_methods}; struct B_DivD_complex B_DivD_complexG_instance = {&B_DivD_complexG_methods}; struct B_MinusD_NumberD_complex B_MinusD_NumberD_complexG_instance = {&B_MinusD_NumberD_complexG_methods, (B_Number)&B_NumberD_complexG_instance}; struct B_NumberD_complex B_NumberD_complexG_instance = {&B_NumberD_complexG_methods, (B_Minus)&B_MinusD_NumberD_complexG_instance}; struct B_HashableD_float B_HashableD_floatG_instance = {&B_HashableD_floatG_methods}; struct B_OrdD_float B_OrdD_floatG_instance = {&B_OrdD_floatG_methods}; struct B_DivD_float B_DivD_floatG_instance = {&B_DivD_floatG_methods}; struct B_MinusD_RealFloatD_float B_MinusD_RealFloatD_floatG_instance = {&B_MinusD_RealFloatD_floatG_methods, (B_Number)&B_RealFloatD_floatG_instance}; struct B_RealFloatD_float B_RealFloatD_floatG_instance = {&B_RealFloatD_floatG_methods, (B_Minus)&B_MinusD_RealFloatD_floatG_instance}; struct B_HashableD_u1 B_HashableD_u1G_instance = {&B_HashableD_u1G_methods}; struct B_OrdD_u1 B_OrdD_u1G_instance = {&B_OrdD_u1G_methods}; struct B_DivD_u1 B_DivD_u1G_instance = {&B_DivD_u1G_methods}; struct B_LogicalD_IntegralD_u1 B_LogicalD_IntegralD_u1G_instance = {&B_LogicalD_IntegralD_u1G_methods, (B_Integral)&B_IntegralD_u1G_instance}; struct B_MinusD_IntegralD_u1 B_MinusD_IntegralD_u1G_instance = {&B_MinusD_IntegralD_u1G_methods, (B_Number)&B_IntegralD_u1G_instance}; struct B_IntegralD_u1 B_IntegralD_u1G_instance = {&B_IntegralD_u1G_methods, (B_Minus)&B_MinusD_IntegralD_u1G_instance, (B_Logical)&B_LogicalD_IntegralD_u1G_instance}; struct B_HashableD_u8 B_HashableD_u8G_instance = {&B_HashableD_u8G_methods}; struct B_OrdD_u8 B_OrdD_u8G_instance = {&B_OrdD_u8G_methods}; struct B_DivD_u8 B_DivD_u8G_instance = {&B_DivD_u8G_methods}; struct B_LogicalD_IntegralD_u8 B_LogicalD_IntegralD_u8G_instance = {&B_LogicalD_IntegralD_u8G_methods, (B_Integral)&B_IntegralD_u8G_instance}; struct B_MinusD_IntegralD_u8 B_MinusD_IntegralD_u8G_instance = {&B_MinusD_IntegralD_u8G_methods, (B_Number)&B_IntegralD_u8G_instance}; struct B_IntegralD_u8 B_IntegralD_u8G_instance = {&B_IntegralD_u8G_methods, (B_Minus)&B_MinusD_IntegralD_u8G_instance, (B_Logical)&B_LogicalD_IntegralD_u8G_instance}; struct B_HashableD_u16 B_HashableD_u16G_instance = {&B_HashableD_u16G_methods}; struct B_OrdD_u16 B_OrdD_u16G_instance = {&B_OrdD_u16G_methods}; struct B_DivD_u16 B_DivD_u16G_instance = {&B_DivD_u16G_methods}; struct B_LogicalD_IntegralD_u16 B_LogicalD_IntegralD_u16G_instance = {&B_LogicalD_IntegralD_u16G_methods, (B_Integral)&B_IntegralD_u16G_instance}; struct B_MinusD_IntegralD_u16 B_MinusD_IntegralD_u16G_instance = {&B_MinusD_IntegralD_u16G_methods, (B_Number)&B_IntegralD_u16G_instance}; struct B_IntegralD_u16 B_IntegralD_u16G_instance = {&B_IntegralD_u16G_methods, (B_Minus)&B_MinusD_IntegralD_u16G_instance, (B_Logical)&B_LogicalD_IntegralD_u16G_instance}; struct B_HashableD_u32 B_HashableD_u32G_instance = {&B_HashableD_u32G_methods}; struct B_OrdD_u32 B_OrdD_u32G_instance = {&B_OrdD_u32G_methods}; struct B_DivD_u32 B_DivD_u32G_instance = {&B_DivD_u32G_methods}; struct B_LogicalD_IntegralD_u32 B_LogicalD_IntegralD_u32G_instance = {&B_LogicalD_IntegralD_u32G_methods, (B_Integral)&B_IntegralD_u32G_instance}; struct B_MinusD_IntegralD_u32 B_MinusD_IntegralD_u32G_instance = {&B_MinusD_IntegralD_u32G_methods, (B_Number)&B_IntegralD_u32G_instance}; struct B_IntegralD_u32 B_IntegralD_u32G_instance = {&B_IntegralD_u32G_methods, (B_Minus)&B_MinusD_IntegralD_u32G_instance, (B_Logical)&B_LogicalD_IntegralD_u32G_instance}; struct B_HashableD_u64 B_HashableD_u64G_instance = {&B_HashableD_u64G_methods}; struct B_OrdD_u64 B_OrdD_u64G_instance = {&B_OrdD_u64G_methods}; struct B_DivD_u64 B_DivD_u64G_instance = {&B_DivD_u64G_methods}; struct B_LogicalD_IntegralD_u64 B_LogicalD_IntegralD_u64G_instance = {&B_LogicalD_IntegralD_u64G_methods, (B_Integral)&B_IntegralD_u64G_instance}; struct B_MinusD_IntegralD_u64 B_MinusD_IntegralD_u64G_instance = {&B_MinusD_IntegralD_u64G_methods, (B_Number)&B_IntegralD_u64G_instance}; struct B_IntegralD_u64 B_IntegralD_u64G_instance = {&B_IntegralD_u64G_methods, (B_Minus)&B_MinusD_IntegralD_u64G_instance, (B_Logical)&B_LogicalD_IntegralD_u64G_instance}; struct B_HashableD_i8 B_HashableD_i8G_instance = {&B_HashableD_i8G_methods}; struct B_OrdD_i8 B_OrdD_i8G_instance = {&B_OrdD_i8G_methods}; struct B_DivD_i8 B_DivD_i8G_instance = {&B_DivD_i8G_methods}; struct B_LogicalD_IntegralD_i8 B_LogicalD_IntegralD_i8G_instance = {&B_LogicalD_IntegralD_i8G_methods, (B_Integral)&B_IntegralD_i8G_instance}; struct B_MinusD_IntegralD_i8 B_MinusD_IntegralD_i8G_instance = {&B_MinusD_IntegralD_i8G_methods, (B_Number)&B_IntegralD_i8G_instance}; struct B_IntegralD_i8 B_IntegralD_i8G_instance = {&B_IntegralD_i8G_methods, (B_Minus)&B_MinusD_IntegralD_i8G_instance, (B_Logical)&B_LogicalD_IntegralD_i8G_instance}; struct B_HashableD_i16 B_HashableD_i16G_instance = {&B_HashableD_i16G_methods}; struct B_OrdD_i16 B_OrdD_i16G_instance = {&B_OrdD_i16G_methods}; struct B_DivD_i16 B_DivD_i16G_instance = {&B_DivD_i16G_methods}; struct B_LogicalD_IntegralD_i16 B_LogicalD_IntegralD_i16G_instance = {&B_LogicalD_IntegralD_i16G_methods, (B_Integral)&B_IntegralD_i16G_instance}; struct B_MinusD_IntegralD_i16 B_MinusD_IntegralD_i16G_instance = {&B_MinusD_IntegralD_i16G_methods, (B_Number)&B_IntegralD_i16G_instance}; struct B_IntegralD_i16 B_IntegralD_i16G_instance = {&B_IntegralD_i16G_methods, (B_Minus)&B_MinusD_IntegralD_i16G_instance, (B_Logical)&B_LogicalD_IntegralD_i16G_instance}; struct B_HashableD_i32 B_HashableD_i32G_instance = {&B_HashableD_i32G_methods}; struct B_OrdD_i32 B_OrdD_i32G_instance = {&B_OrdD_i32G_methods}; struct B_DivD_i32 B_DivD_i32G_instance = {&B_DivD_i32G_methods}; struct B_LogicalD_IntegralD_i32 B_LogicalD_IntegralD_i32G_instance = {&B_LogicalD_IntegralD_i32G_methods, (B_Integral)&B_IntegralD_i32G_instance}; struct B_MinusD_IntegralD_i32 B_MinusD_IntegralD_i32G_instance = {&B_MinusD_IntegralD_i32G_methods, (B_Number)&B_IntegralD_i32G_instance}; struct B_IntegralD_i32 B_IntegralD_i32G_instance = {&B_IntegralD_i32G_methods, (B_Minus)&B_MinusD_IntegralD_i32G_instance, (B_Logical)&B_LogicalD_IntegralD_i32G_instance}; struct B_HashableD_int B_HashableD_intG_instance = {&B_HashableD_intG_methods}; struct B_OrdD_int B_OrdD_intG_instance = {&B_OrdD_intG_methods}; struct B_DivD_int B_DivD_intG_instance = {&B_DivD_intG_methods}; struct B_LogicalD_IntegralD_int B_LogicalD_IntegralD_intG_instance = {&B_LogicalD_IntegralD_intG_methods, (B_Integral)&B_IntegralD_intG_instance}; struct B_MinusD_IntegralD_int B_MinusD_IntegralD_intG_instance = {&B_MinusD_IntegralD_intG_methods, (B_Number)&B_IntegralD_intG_instance}; struct B_IntegralD_int B_IntegralD_intG_instance = {&B_IntegralD_intG_methods, (B_Minus)&B_MinusD_IntegralD_intG_instance, (B_Logical)&B_LogicalD_IntegralD_intG_instance}; struct B_HashableD_bigint B_HashableD_bigintG_instance = {&B_HashableD_bigintG_methods}; struct B_OrdD_bigint B_OrdD_bigintG_instance = {&B_OrdD_bigintG_methods}; struct B_DivD_bigint B_DivD_bigintG_instance = {&B_DivD_bigintG_methods}; struct B_LogicalD_IntegralD_bigint B_LogicalD_IntegralD_bigintG_instance = {&B_LogicalD_IntegralD_bigintG_methods, (B_Integral)&B_IntegralD_bigintG_instance}; struct B_MinusD_IntegralD_bigint B_MinusD_IntegralD_bigintG_instance = {&B_MinusD_IntegralD_bigintG_methods, (B_Number)&B_IntegralD_bigintG_instance}; struct B_IntegralD_bigint B_IntegralD_bigintG_instance = {&B_IntegralD_bigintG_methods, (B_Minus)&B_MinusD_IntegralD_bigintG_instance, (B_Logical)&B_LogicalD_IntegralD_bigintG_instance}; struct B_HashableD_bool B_HashableD_boolG_instance = {&B_HashableD_boolG_methods}; B_HashableD_bytes B_HashableD_bytesG_witness = &B_HashableD_bytesG_instance; B_TimesD_bytes B_TimesD_bytesG_witness = &B_TimesD_bytesG_instance; B_ContainerD_bytes B_ContainerD_bytesG_witness = &B_ContainerD_bytesG_instance; B_SliceableD_bytes B_SliceableD_bytesG_witness = &B_SliceableD_bytesG_instance; B_OrdD_bytes B_OrdD_bytesG_witness = &B_OrdD_bytesG_instance; B_ContainerD_bytearray B_ContainerD_bytearrayG_witness = &B_ContainerD_bytearrayG_instance; B_TimesD_SequenceD_bytearray B_TimesD_SequenceD_bytearrayG_witness = &B_TimesD_SequenceD_bytearrayG_instance; B_CollectionD_SequenceD_bytearray B_CollectionD_SequenceD_bytearrayG_witness = &B_CollectionD_SequenceD_bytearrayG_instance; B_SequenceD_bytearray B_SequenceD_bytearrayG_witness = &B_SequenceD_bytearrayG_instance; B_OrdD_bytearray B_OrdD_bytearrayG_witness = &B_OrdD_bytearrayG_instance; B_HashableD_str B_HashableD_strG_witness = &B_HashableD_strG_instance; B_TimesD_str B_TimesD_strG_witness = &B_TimesD_strG_instance; B_SliceableD_str B_SliceableD_strG_witness = &B_SliceableD_strG_instance; B_ContainerD_str B_ContainerD_strG_witness = &B_ContainerD_strG_instance; B_OrdD_str B_OrdD_strG_witness = &B_OrdD_strG_instance; //B_IterableD_range B_IterableD_rangeG_witness = &B_IterableD_rangeG_instance; B_IterableD_Iterator B_IterableD_IteratorG_witness = &B_IterableD_IteratorG_instance; //B_MinusD_SetD_set B_MinusD_SetD_setG_witness = &B_MinusD_SetD_setG_instance; //B_LogicalD_SetD_set B_LogicalD_SetD_setG_witness = &B_LogicalD_SetD_setG_instance; //B_OrdD_SetD_set B_OrdD_SetD_setG_witness = &B_OrdD_SetD_setG_instance; B_SetD_set B_SetD_setG_witness = &B_SetD_setG_instance; B_OrdD_dict B_OrdD_dictG_witness = &B_OrdD_dictG_instance; //B_IndexedD_MappingD_dict B_IndexedD_MappingD_dictG_witness = &B_IndexedD_MappingD_dictG_instance; B_MappingD_dict B_MappingD_dictG_witness = &B_MappingD_dictG_instance; B_OrdD_list B_OrdD_listG_witness = &B_OrdD_listG_instance; B_ContainerD_list B_ContainerD_listG_witness = &B_ContainerD_listG_instance; B_TimesD_SequenceD_list B_TimesD_SequenceD_listG_witness = &B_TimesD_SequenceD_listG_instance; B_CollectionD_SequenceD_list B_CollectionD_SequenceD_listG_witness = &B_CollectionD_SequenceD_listG_instance; B_SequenceD_list B_SequenceD_listG_witness = &B_SequenceD_listG_instance; B_HashableD_complex B_HashableD_complexG_witness = &B_HashableD_complexG_instance; B_EqD_complex B_EqD_complexG_witness = &B_EqD_complexG_instance; B_DivD_complex B_DivD_complexG_witness = &B_DivD_complexG_instance; B_MinusD_NumberD_complex B_MinusD_NumberD_complexG_witness = &B_MinusD_NumberD_complexG_instance; B_NumberD_complex B_NumberD_complexG_witness = &B_NumberD_complexG_instance; B_HashableD_float B_HashableD_floatG_witness = &B_HashableD_floatG_instance; B_OrdD_float B_OrdD_floatG_witness = &B_OrdD_floatG_instance; B_DivD_float B_DivD_floatG_witness = &B_DivD_floatG_instance; B_MinusD_RealFloatD_float B_MinusD_RealFloatD_floatG_witness = &B_MinusD_RealFloatD_floatG_instance; B_RealFloatD_float B_RealFloatD_floatG_witness = &B_RealFloatD_floatG_instance; B_HashableD_u1 B_HashableD_u1G_witness = &B_HashableD_u1G_instance; B_OrdD_u1 B_OrdD_u1G_witness = &B_OrdD_u1G_instance; B_DivD_u1 B_DivD_u1G_witness = &B_DivD_u1G_instance; B_LogicalD_IntegralD_u1 B_LogicalD_IntegralD_u1G_witness = &B_LogicalD_IntegralD_u1G_instance; B_MinusD_IntegralD_u1 B_MinusD_IntegralD_u1G_witness = &B_MinusD_IntegralD_u1G_instance; B_IntegralD_u1 B_IntegralD_u1G_witness = &B_IntegralD_u1G_instance; B_HashableD_u8 B_HashableD_u8G_witness = &B_HashableD_u8G_instance; B_OrdD_u8 B_OrdD_u8G_witness = &B_OrdD_u8G_instance; B_DivD_u8 B_DivD_u8G_witness = &B_DivD_u8G_instance; B_LogicalD_IntegralD_u8 B_LogicalD_IntegralD_u8G_witness = &B_LogicalD_IntegralD_u8G_instance; B_MinusD_IntegralD_u8 B_MinusD_IntegralD_u8G_witness = &B_MinusD_IntegralD_u8G_instance; B_IntegralD_u8 B_IntegralD_u8G_witness = &B_IntegralD_u8G_instance; B_HashableD_u16 B_HashableD_u16G_witness = &B_HashableD_u16G_instance; B_OrdD_u16 B_OrdD_u16G_witness = &B_OrdD_u16G_instance; B_DivD_u16 B_DivD_u16G_witness = &B_DivD_u16G_instance; B_LogicalD_IntegralD_u16 B_LogicalD_IntegralD_u16G_witness = &B_LogicalD_IntegralD_u16G_instance; B_MinusD_IntegralD_u16 B_MinusD_IntegralD_u16G_witness = &B_MinusD_IntegralD_u16G_instance; B_IntegralD_u16 B_IntegralD_u16G_witness = &B_IntegralD_u16G_instance; B_HashableD_u32 B_HashableD_u32G_witness = &B_HashableD_u32G_instance; B_OrdD_u32 B_OrdD_u32G_witness = &B_OrdD_u32G_instance; B_DivD_u32 B_DivD_u32G_witness = &B_DivD_u32G_instance; B_LogicalD_IntegralD_u32 B_LogicalD_IntegralD_u32G_witness = &B_LogicalD_IntegralD_u32G_instance; B_MinusD_IntegralD_u32 B_MinusD_IntegralD_u32G_witness = &B_MinusD_IntegralD_u32G_instance; B_IntegralD_u32 B_IntegralD_u32G_witness = &B_IntegralD_u32G_instance; B_HashableD_u64 B_HashableD_u64G_witness = &B_HashableD_u64G_instance; B_OrdD_u64 B_OrdD_u64G_witness = &B_OrdD_u64G_instance; B_DivD_u64 B_DivD_u64G_witness = &B_DivD_u64G_instance; B_LogicalD_IntegralD_u64 B_LogicalD_IntegralD_u64G_witness = &B_LogicalD_IntegralD_u64G_instance; B_MinusD_IntegralD_u64 B_MinusD_IntegralD_u64G_witness = &B_MinusD_IntegralD_u64G_instance; B_IntegralD_u64 B_IntegralD_u64G_witness = &B_IntegralD_u64G_instance; B_HashableD_i16 B_HashableD_i16G_witness = &B_HashableD_i16G_instance; B_OrdD_i16 B_OrdD_i16G_witness = &B_OrdD_i16G_instance; B_DivD_i16 B_DivD_i16G_witness = &B_DivD_i16G_instance; B_LogicalD_IntegralD_i16 B_LogicalD_IntegralD_i16G_witness = &B_LogicalD_IntegralD_i16G_instance; B_MinusD_IntegralD_i16 B_MinusD_IntegralD_i16G_witness = &B_MinusD_IntegralD_i16G_instance; B_IntegralD_i16 B_IntegralD_i16G_witness = &B_IntegralD_i16G_instance; B_HashableD_i32 B_HashableD_i32G_witness = &B_HashableD_i32G_instance; B_OrdD_i32 B_OrdD_i32G_witness = &B_OrdD_i32G_instance; B_DivD_i32 B_DivD_i32G_witness = &B_DivD_i32G_instance; B_LogicalD_IntegralD_i32 B_LogicalD_IntegralD_i32G_witness = &B_LogicalD_IntegralD_i32G_instance; B_MinusD_IntegralD_i32 B_MinusD_IntegralD_i32G_witness = &B_MinusD_IntegralD_i32G_instance; B_IntegralD_i32 B_IntegralD_i32G_witness = &B_IntegralD_i32G_instance; B_HashableD_i8 B_HashableD_i8G_witness = &B_HashableD_i8G_instance; B_OrdD_i8 B_OrdD_i8G_witness = &B_OrdD_i8G_instance; B_DivD_i8 B_DivD_i8G_witness = &B_DivD_i8G_instance; B_LogicalD_IntegralD_i8 B_LogicalD_IntegralD_i8G_witness = &B_LogicalD_IntegralD_i8G_instance; B_MinusD_IntegralD_i8 B_MinusD_IntegralD_i8G_witness = &B_MinusD_IntegralD_i8G_instance; B_IntegralD_i8 B_IntegralD_i8G_witness = &B_IntegralD_i8G_instance; B_HashableD_int B_HashableD_intG_witness = &B_HashableD_intG_instance; B_OrdD_int B_OrdD_intG_witness = &B_OrdD_intG_instance; B_DivD_int B_DivD_intG_witness = &B_DivD_intG_instance; B_LogicalD_IntegralD_int B_LogicalD_IntegralD_intG_witness = &B_LogicalD_IntegralD_intG_instance; B_MinusD_IntegralD_int B_MinusD_IntegralD_intG_witness = &B_MinusD_IntegralD_intG_instance; B_IntegralD_int B_IntegralD_intG_witness = &B_IntegralD_intG_instance; B_HashableD_bigint B_HashableD_bigintG_witness = &B_HashableD_bigintG_instance; B_OrdD_bigint B_OrdD_bigintG_witness = &B_OrdD_bigintG_instance; B_DivD_bigint B_DivD_bigintG_witness = &B_DivD_bigintG_instance; B_LogicalD_IntegralD_bigint B_LogicalD_IntegralD_bigintG_witness = &B_LogicalD_IntegralD_bigintG_instance; B_MinusD_IntegralD_bigint B_MinusD_IntegralD_bigintG_witness = &B_MinusD_IntegralD_bigintG_instance; B_IntegralD_bigint B_IntegralD_bigintG_witness = &B_IntegralD_bigintG_instance; B_HashableD_bool B_HashableD_boolG_witness = &B_HashableD_boolG_instance; struct B_OrdD_list B_OrdD_listD_bytesG_instance = {&B_OrdD_listG_methods, (B_Ord)&B_OrdD_bytesG_instance}; B_OrdD_list B_OrdD_listD_bytesG_witness = &B_OrdD_listD_bytesG_instance; struct B_IndexedD_MappingD_dict B_IndexedD_MappingD_dictD_strG_instance; struct B_IndexedD_MappingD_dict B_IndexedD_MappingD_dictD_intG_instance; struct B_MappingD_dict B_MappingD_dictD_strG_instance = {&B_MappingD_dictG_methods, (B_Eq)&B_HashableD_strG_instance, (B_Eq)&B_HashableD_strG_instance, (B_Indexed)&B_IndexedD_MappingD_dictD_strG_instance, (B_Hashable)&B_HashableD_strG_instance}; struct B_MappingD_dict B_MappingD_dictD_intG_instance = {&B_MappingD_dictG_methods, (B_Eq)&B_HashableD_intG_instance, (B_Eq)&B_HashableD_intG_instance, (B_Indexed)&B_IndexedD_MappingD_dictD_intG_instance, (B_Hashable)&B_HashableD_intG_instance}; struct B_IndexedD_MappingD_dict B_IndexedD_MappingD_dictD_strG_instance = {&B_IndexedD_MappingD_dictG_methods, (B_Eq)&B_HashableD_strG_instance, (B_Eq)&B_HashableD_strG_instance, (B_Mapping)&B_MappingD_dictD_strG_instance, (B_Hashable)&B_HashableD_strG_instance}; struct B_IndexedD_MappingD_dict B_IndexedD_MappingD_dictD_intG_instance = {&B_IndexedD_MappingD_dictG_methods, (B_Eq)&B_HashableD_intG_instance, (B_Eq)&B_HashableD_intG_instance, (B_Mapping)&B_MappingD_dictD_intG_instance, (B_Hashable)&B_HashableD_intG_instance}; B_MappingD_dict B_MappingD_dictD_strG_witness = &B_MappingD_dictD_strG_instance; B_MappingD_dict B_MappingD_dictD_intG_witness = &B_MappingD_dictD_intG_instance; ================================================ FILE: base/builtin/staticWitnesses.h ================================================ extern B_HashableD_bytes B_HashableD_bytesG_witness; extern B_TimesD_bytes B_TimesD_bytesG_witness; extern B_ContainerD_bytes B_ContainerD_bytesG_witness; extern B_SliceableD_bytes B_SliceableD_bytesG_witness; extern B_OrdD_bytes B_OrdD_bytesG_witness; extern B_ContainerD_bytearray B_ContainerD_bytearrayG_witness; extern B_TimesD_SequenceD_bytearray B_TimesD_SequenceD_bytearrayG_witness; extern B_CollectionD_SequenceD_bytearray B_CollectionD_SequenceD_bytearrayG_witness; extern B_SequenceD_bytearray B_SequenceD_bytearrayG_witness; extern B_OrdD_bytearray B_OrdD_bytearrayG_witness; extern B_HashableD_str B_HashableD_strG_witness; extern B_TimesD_str B_TimesD_strG_witness; extern B_SliceableD_str B_SliceableD_strG_witness; extern B_ContainerD_str B_ContainerD_strG_witness; extern B_OrdD_str B_OrdD_strG_witness; // extern B_IterableD_range B_IterableD_rangeG_witness; extern B_IterableD_Iterator B_IterableD_IteratorG_witness; extern B_MinusD_SetD_set B_MinusD_SetD_setG_witness; extern B_LogicalD_SetD_set B_LogicalD_SetD_setG_witness; extern B_OrdD_SetD_set B_OrdD_SetD_setG_witness; extern B_SetD_set B_SetD_setG_witness; extern B_OrdD_dict B_OrdD_dictG_witness; extern B_IndexedD_MappingD_dict B_IndexedD_MappingD_dictG_witness; extern B_MappingD_dict B_MappingD_dictG_witness; extern B_OrdD_list B_OrdD_listG_witness; extern B_ContainerD_list B_ContainerD_listG_witness; extern B_TimesD_SequenceD_list B_TimesD_SequenceD_listG_witness; extern B_CollectionD_SequenceD_list B_CollectionD_SequenceD_listG_witness; extern B_SequenceD_list B_SequenceD_listG_witness; extern B_HashableD_complex B_HashableD_complexG_witness; extern B_EqD_complex B_EqD_complexG_witness; extern B_DivD_complex B_DivD_complexG_witness; extern B_MinusD_NumberD_complex B_MinusD_NumberD_complexG_witness; extern B_NumberD_complex B_NumberD_complexG_witness; extern B_HashableD_float B_HashableD_floatG_witness; extern B_OrdD_float B_OrdD_floatG_witness; extern B_DivD_float B_DivD_floatG_witness; extern B_MinusD_RealFloatD_float B_MinusD_RealFloatD_floatG_witness; extern B_RealFloatD_float B_RealFloatD_floatG_witness; extern B_HashableD_u1 B_HashableD_u1G_witness; extern B_OrdD_u1 B_OrdD_u1G_witness; extern B_DivD_u1 B_DivD_u1G_witness; extern B_LogicalD_IntegralD_u1 B_LogicalD_IntegralD_u1G_witness; extern B_MinusD_IntegralD_u1 B_MinusD_IntegralD_u1G_witness; extern B_IntegralD_u1 B_IntegralD_u1G_witness; extern B_HashableD_u8 B_HashableD_u8G_witness; extern B_OrdD_u8 B_OrdD_u8G_witness; extern B_DivD_u8 B_DivD_u8G_witness; extern B_LogicalD_IntegralD_u8 B_LogicalD_IntegralD_u8G_witness; extern B_MinusD_IntegralD_u8 B_MinusD_IntegralD_u8G_witness; extern B_IntegralD_u8 B_IntegralD_u8G_witness; extern B_HashableD_u16 B_HashableD_u16G_witness; extern B_OrdD_u16 B_OrdD_u16G_witness; extern B_DivD_u16 B_DivD_u16G_witness; extern B_LogicalD_IntegralD_u16 B_LogicalD_IntegralD_u16G_witness; extern B_MinusD_IntegralD_u16 B_MinusD_IntegralD_u16G_witness; extern B_IntegralD_u16 B_IntegralD_u16G_witness; extern B_HashableD_u32 B_HashableD_u32G_witness; extern B_OrdD_u32 B_OrdD_u32G_witness; extern B_DivD_u32 B_DivD_u32G_witness; extern B_LogicalD_IntegralD_u32 B_LogicalD_IntegralD_u32G_witness; extern B_MinusD_IntegralD_u32 B_MinusD_IntegralD_u32G_witness; extern B_IntegralD_u32 B_IntegralD_u32G_witness; extern B_HashableD_u64 B_HashableD_u64G_witness; extern B_OrdD_u64 B_OrdD_u64G_witness; extern B_DivD_u64 B_DivD_u64G_witness; extern B_LogicalD_IntegralD_u64 B_LogicalD_IntegralD_u64G_witness; extern B_MinusD_IntegralD_u64 B_MinusD_IntegralD_u64G_witness; extern B_IntegralD_u64 B_IntegralD_u64G_witness; extern B_HashableD_i16 B_HashableD_i16G_witness; extern B_OrdD_i16 B_OrdD_i16G_witness; extern B_DivD_i16 B_DivD_i16G_witness; extern B_LogicalD_IntegralD_i16 B_LogicalD_IntegralD_i16G_witness; extern B_MinusD_IntegralD_i16 B_MinusD_IntegralD_i16G_witness; extern B_IntegralD_i16 B_IntegralD_i16G_witness; extern B_HashableD_i32 B_HashableD_i32G_witness; extern B_OrdD_i32 B_OrdD_i32G_witness; extern B_DivD_i32 B_DivD_i32G_witness; extern B_LogicalD_IntegralD_i32 B_LogicalD_IntegralD_i32G_witness; extern B_MinusD_IntegralD_i32 B_MinusD_IntegralD_i32G_witness; extern B_IntegralD_i32 B_IntegralD_i32G_witness; extern B_HashableD_i8 B_HashableD_i8G_witness; extern B_OrdD_i8 B_OrdD_i8G_witness; extern B_DivD_i8 B_DivD_i8G_witness; extern B_LogicalD_IntegralD_i8 B_LogicalD_IntegralD_i8G_witness; extern B_MinusD_IntegralD_i8 B_MinusD_IntegralD_i8G_witness; extern B_IntegralD_i8 B_IntegralD_i8G_witness; extern B_HashableD_int B_HashableD_intG_witness; extern B_OrdD_int B_OrdD_intG_witness; extern B_DivD_int B_DivD_intG_witness; extern B_LogicalD_IntegralD_int B_LogicalD_IntegralD_intG_witness; extern B_MinusD_IntegralD_int B_MinusD_IntegralD_intG_witness; extern B_IntegralD_int B_IntegralD_intG_witness; extern B_HashableD_bigint B_HashableD_bigintG_witness; extern B_OrdD_bigint B_OrdD_bigintG_witness; extern B_DivD_bigint B_DivD_bigintG_witness; extern B_LogicalD_IntegralD_bigint B_LogicalD_IntegralD_bigintG_witness; extern B_MinusD_IntegralD_bigint B_MinusD_IntegralD_bigintG_witness; extern B_IntegralD_bigint B_IntegralD_bigintG_witness; extern B_HashableD_bool B_HashableD_boolG_witness; extern B_OrdD_list B_OrdD_listD_bytesG_witness; extern B_MappingD_dict B_MappingD_dictD_strG_witness; extern B_MappingD_dict B_MappingD_dictD_intG_witness; extern B_MappingD_dict B_MappingD_dictD_bigintG_witness; #define $SequenceD_listG_witness B_SequenceD_listG_witness #define $CollectionD_listG_witness B_CollectionD_SequenceD_listG_witness ================================================ FILE: base/builtin/str.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #define GC_THREADS 1 #include "gc.h" #include "utf8proc.h" // Auxiliaries, some used for both str and bytearray implementations //////////////////////////////////////////////////////// static unsigned char nul = 0; static struct B_str null_struct = {&B_strG_methods,0,0,&nul}; static B_str null_str = &null_struct; // Prebuilt immutable one-byte ASCII strings used by indexing and iteration. #define ASCII_CHAR_TABLE_SIZE 128 static unsigned char ascii_char_data[ASCII_CHAR_TABLE_SIZE][2] = { [1] = {1, 0}, [2] = {2, 0}, [3] = {3, 0}, [4] = {4, 0}, [5] = {5, 0}, [6] = {6, 0}, [7] = {7, 0}, [8] = {8, 0}, [9] = {9, 0}, [10] = {10, 0}, [11] = {11, 0}, [12] = {12, 0}, [13] = {13, 0}, [14] = {14, 0}, [15] = {15, 0}, [16] = {16, 0}, [17] = {17, 0}, [18] = {18, 0}, [19] = {19, 0}, [20] = {20, 0}, [21] = {21, 0}, [22] = {22, 0}, [23] = {23, 0}, [24] = {24, 0}, [25] = {25, 0}, [26] = {26, 0}, [27] = {27, 0}, [28] = {28, 0}, [29] = {29, 0}, [30] = {30, 0}, [31] = {31, 0}, [32] = {32, 0}, [33] = {33, 0}, [34] = {34, 0}, [35] = {35, 0}, [36] = {36, 0}, [37] = {37, 0}, [38] = {38, 0}, [39] = {39, 0}, [40] = {40, 0}, [41] = {41, 0}, [42] = {42, 0}, [43] = {43, 0}, [44] = {44, 0}, [45] = {45, 0}, [46] = {46, 0}, [47] = {47, 0}, [48] = {48, 0}, [49] = {49, 0}, [50] = {50, 0}, [51] = {51, 0}, [52] = {52, 0}, [53] = {53, 0}, [54] = {54, 0}, [55] = {55, 0}, [56] = {56, 0}, [57] = {57, 0}, [58] = {58, 0}, [59] = {59, 0}, [60] = {60, 0}, [61] = {61, 0}, [62] = {62, 0}, [63] = {63, 0}, [64] = {64, 0}, [65] = {65, 0}, [66] = {66, 0}, [67] = {67, 0}, [68] = {68, 0}, [69] = {69, 0}, [70] = {70, 0}, [71] = {71, 0}, [72] = {72, 0}, [73] = {73, 0}, [74] = {74, 0}, [75] = {75, 0}, [76] = {76, 0}, [77] = {77, 0}, [78] = {78, 0}, [79] = {79, 0}, [80] = {80, 0}, [81] = {81, 0}, [82] = {82, 0}, [83] = {83, 0}, [84] = {84, 0}, [85] = {85, 0}, [86] = {86, 0}, [87] = {87, 0}, [88] = {88, 0}, [89] = {89, 0}, [90] = {90, 0}, [91] = {91, 0}, [92] = {92, 0}, [93] = {93, 0}, [94] = {94, 0}, [95] = {95, 0}, [96] = {96, 0}, [97] = {97, 0}, [98] = {98, 0}, [99] = {99, 0}, [100] = {100, 0}, [101] = {101, 0}, [102] = {102, 0}, [103] = {103, 0}, [104] = {104, 0}, [105] = {105, 0}, [106] = {106, 0}, [107] = {107, 0}, [108] = {108, 0}, [109] = {109, 0}, [110] = {110, 0}, [111] = {111, 0}, [112] = {112, 0}, [113] = {113, 0}, [114] = {114, 0}, [115] = {115, 0}, [116] = {116, 0}, [117] = {117, 0}, [118] = {118, 0}, [119] = {119, 0}, [120] = {120, 0}, [121] = {121, 0}, [122] = {122, 0}, [123] = {123, 0}, [124] = {124, 0}, [125] = {125, 0}, [126] = {126, 0}, [127] = {127, 0} }; static struct B_str ascii_char_strs[ASCII_CHAR_TABLE_SIZE] = { [1] = {&B_strG_methods, 1, 1, ascii_char_data[1]}, [2] = {&B_strG_methods, 1, 1, ascii_char_data[2]}, [3] = {&B_strG_methods, 1, 1, ascii_char_data[3]}, [4] = {&B_strG_methods, 1, 1, ascii_char_data[4]}, [5] = {&B_strG_methods, 1, 1, ascii_char_data[5]}, [6] = {&B_strG_methods, 1, 1, ascii_char_data[6]}, [7] = {&B_strG_methods, 1, 1, ascii_char_data[7]}, [8] = {&B_strG_methods, 1, 1, ascii_char_data[8]}, [9] = {&B_strG_methods, 1, 1, ascii_char_data[9]}, [10] = {&B_strG_methods, 1, 1, ascii_char_data[10]}, [11] = {&B_strG_methods, 1, 1, ascii_char_data[11]}, [12] = {&B_strG_methods, 1, 1, ascii_char_data[12]}, [13] = {&B_strG_methods, 1, 1, ascii_char_data[13]}, [14] = {&B_strG_methods, 1, 1, ascii_char_data[14]}, [15] = {&B_strG_methods, 1, 1, ascii_char_data[15]}, [16] = {&B_strG_methods, 1, 1, ascii_char_data[16]}, [17] = {&B_strG_methods, 1, 1, ascii_char_data[17]}, [18] = {&B_strG_methods, 1, 1, ascii_char_data[18]}, [19] = {&B_strG_methods, 1, 1, ascii_char_data[19]}, [20] = {&B_strG_methods, 1, 1, ascii_char_data[20]}, [21] = {&B_strG_methods, 1, 1, ascii_char_data[21]}, [22] = {&B_strG_methods, 1, 1, ascii_char_data[22]}, [23] = {&B_strG_methods, 1, 1, ascii_char_data[23]}, [24] = {&B_strG_methods, 1, 1, ascii_char_data[24]}, [25] = {&B_strG_methods, 1, 1, ascii_char_data[25]}, [26] = {&B_strG_methods, 1, 1, ascii_char_data[26]}, [27] = {&B_strG_methods, 1, 1, ascii_char_data[27]}, [28] = {&B_strG_methods, 1, 1, ascii_char_data[28]}, [29] = {&B_strG_methods, 1, 1, ascii_char_data[29]}, [30] = {&B_strG_methods, 1, 1, ascii_char_data[30]}, [31] = {&B_strG_methods, 1, 1, ascii_char_data[31]}, [32] = {&B_strG_methods, 1, 1, ascii_char_data[32]}, [33] = {&B_strG_methods, 1, 1, ascii_char_data[33]}, [34] = {&B_strG_methods, 1, 1, ascii_char_data[34]}, [35] = {&B_strG_methods, 1, 1, ascii_char_data[35]}, [36] = {&B_strG_methods, 1, 1, ascii_char_data[36]}, [37] = {&B_strG_methods, 1, 1, ascii_char_data[37]}, [38] = {&B_strG_methods, 1, 1, ascii_char_data[38]}, [39] = {&B_strG_methods, 1, 1, ascii_char_data[39]}, [40] = {&B_strG_methods, 1, 1, ascii_char_data[40]}, [41] = {&B_strG_methods, 1, 1, ascii_char_data[41]}, [42] = {&B_strG_methods, 1, 1, ascii_char_data[42]}, [43] = {&B_strG_methods, 1, 1, ascii_char_data[43]}, [44] = {&B_strG_methods, 1, 1, ascii_char_data[44]}, [45] = {&B_strG_methods, 1, 1, ascii_char_data[45]}, [46] = {&B_strG_methods, 1, 1, ascii_char_data[46]}, [47] = {&B_strG_methods, 1, 1, ascii_char_data[47]}, [48] = {&B_strG_methods, 1, 1, ascii_char_data[48]}, [49] = {&B_strG_methods, 1, 1, ascii_char_data[49]}, [50] = {&B_strG_methods, 1, 1, ascii_char_data[50]}, [51] = {&B_strG_methods, 1, 1, ascii_char_data[51]}, [52] = {&B_strG_methods, 1, 1, ascii_char_data[52]}, [53] = {&B_strG_methods, 1, 1, ascii_char_data[53]}, [54] = {&B_strG_methods, 1, 1, ascii_char_data[54]}, [55] = {&B_strG_methods, 1, 1, ascii_char_data[55]}, [56] = {&B_strG_methods, 1, 1, ascii_char_data[56]}, [57] = {&B_strG_methods, 1, 1, ascii_char_data[57]}, [58] = {&B_strG_methods, 1, 1, ascii_char_data[58]}, [59] = {&B_strG_methods, 1, 1, ascii_char_data[59]}, [60] = {&B_strG_methods, 1, 1, ascii_char_data[60]}, [61] = {&B_strG_methods, 1, 1, ascii_char_data[61]}, [62] = {&B_strG_methods, 1, 1, ascii_char_data[62]}, [63] = {&B_strG_methods, 1, 1, ascii_char_data[63]}, [64] = {&B_strG_methods, 1, 1, ascii_char_data[64]}, [65] = {&B_strG_methods, 1, 1, ascii_char_data[65]}, [66] = {&B_strG_methods, 1, 1, ascii_char_data[66]}, [67] = {&B_strG_methods, 1, 1, ascii_char_data[67]}, [68] = {&B_strG_methods, 1, 1, ascii_char_data[68]}, [69] = {&B_strG_methods, 1, 1, ascii_char_data[69]}, [70] = {&B_strG_methods, 1, 1, ascii_char_data[70]}, [71] = {&B_strG_methods, 1, 1, ascii_char_data[71]}, [72] = {&B_strG_methods, 1, 1, ascii_char_data[72]}, [73] = {&B_strG_methods, 1, 1, ascii_char_data[73]}, [74] = {&B_strG_methods, 1, 1, ascii_char_data[74]}, [75] = {&B_strG_methods, 1, 1, ascii_char_data[75]}, [76] = {&B_strG_methods, 1, 1, ascii_char_data[76]}, [77] = {&B_strG_methods, 1, 1, ascii_char_data[77]}, [78] = {&B_strG_methods, 1, 1, ascii_char_data[78]}, [79] = {&B_strG_methods, 1, 1, ascii_char_data[79]}, [80] = {&B_strG_methods, 1, 1, ascii_char_data[80]}, [81] = {&B_strG_methods, 1, 1, ascii_char_data[81]}, [82] = {&B_strG_methods, 1, 1, ascii_char_data[82]}, [83] = {&B_strG_methods, 1, 1, ascii_char_data[83]}, [84] = {&B_strG_methods, 1, 1, ascii_char_data[84]}, [85] = {&B_strG_methods, 1, 1, ascii_char_data[85]}, [86] = {&B_strG_methods, 1, 1, ascii_char_data[86]}, [87] = {&B_strG_methods, 1, 1, ascii_char_data[87]}, [88] = {&B_strG_methods, 1, 1, ascii_char_data[88]}, [89] = {&B_strG_methods, 1, 1, ascii_char_data[89]}, [90] = {&B_strG_methods, 1, 1, ascii_char_data[90]}, [91] = {&B_strG_methods, 1, 1, ascii_char_data[91]}, [92] = {&B_strG_methods, 1, 1, ascii_char_data[92]}, [93] = {&B_strG_methods, 1, 1, ascii_char_data[93]}, [94] = {&B_strG_methods, 1, 1, ascii_char_data[94]}, [95] = {&B_strG_methods, 1, 1, ascii_char_data[95]}, [96] = {&B_strG_methods, 1, 1, ascii_char_data[96]}, [97] = {&B_strG_methods, 1, 1, ascii_char_data[97]}, [98] = {&B_strG_methods, 1, 1, ascii_char_data[98]}, [99] = {&B_strG_methods, 1, 1, ascii_char_data[99]}, [100] = {&B_strG_methods, 1, 1, ascii_char_data[100]}, [101] = {&B_strG_methods, 1, 1, ascii_char_data[101]}, [102] = {&B_strG_methods, 1, 1, ascii_char_data[102]}, [103] = {&B_strG_methods, 1, 1, ascii_char_data[103]}, [104] = {&B_strG_methods, 1, 1, ascii_char_data[104]}, [105] = {&B_strG_methods, 1, 1, ascii_char_data[105]}, [106] = {&B_strG_methods, 1, 1, ascii_char_data[106]}, [107] = {&B_strG_methods, 1, 1, ascii_char_data[107]}, [108] = {&B_strG_methods, 1, 1, ascii_char_data[108]}, [109] = {&B_strG_methods, 1, 1, ascii_char_data[109]}, [110] = {&B_strG_methods, 1, 1, ascii_char_data[110]}, [111] = {&B_strG_methods, 1, 1, ascii_char_data[111]}, [112] = {&B_strG_methods, 1, 1, ascii_char_data[112]}, [113] = {&B_strG_methods, 1, 1, ascii_char_data[113]}, [114] = {&B_strG_methods, 1, 1, ascii_char_data[114]}, [115] = {&B_strG_methods, 1, 1, ascii_char_data[115]}, [116] = {&B_strG_methods, 1, 1, ascii_char_data[116]}, [117] = {&B_strG_methods, 1, 1, ascii_char_data[117]}, [118] = {&B_strG_methods, 1, 1, ascii_char_data[118]}, [119] = {&B_strG_methods, 1, 1, ascii_char_data[119]}, [120] = {&B_strG_methods, 1, 1, ascii_char_data[120]}, [121] = {&B_strG_methods, 1, 1, ascii_char_data[121]}, [122] = {&B_strG_methods, 1, 1, ascii_char_data[122]}, [123] = {&B_strG_methods, 1, 1, ascii_char_data[123]}, [124] = {&B_strG_methods, 1, 1, ascii_char_data[124]}, [125] = {&B_strG_methods, 1, 1, ascii_char_data[125]}, [126] = {&B_strG_methods, 1, 1, ascii_char_data[126]}, [127] = {&B_strG_methods, 1, 1, ascii_char_data[127]} }; static B_str space_str = &ascii_char_strs[(unsigned char)' ']; static struct B_str whitespace_struct = {&B_strG_methods,6,6,(unsigned char *)" \t\n\r\x0b\x0c"}; static B_str whitespace_str = &whitespace_struct; static struct B_bytes null_bytes_struct = {&B_bytesG_methods,0,&nul}; static B_bytes null_bytes = &null_bytes_struct; static struct B_bytes space_bytes_struct = {&B_bytesG_methods,1,(unsigned char *)" "}; static B_bytes space_bytes = &space_bytes_struct; static struct B_bytes whitespace_bytes_struct = {&B_bytesG_methods,6,(unsigned char *)" \t\n\r\x0b\x0c"}; static B_bytes whitespace_bytes = &whitespace_bytes_struct; // We avoid returning the bytearray singleton from bytearray methods, this is // just used internally as a default value for the fill character. static struct B_bytearray space_bytearray_struct = {&B_bytearrayG_methods,1,(unsigned char *)" ",1}; static B_bytearray space_bytearray = &space_bytearray_struct; static struct B_bytearray whitespace_bytearray_struct = {&B_bytearrayG_methods,6,(unsigned char *)" \t\n\r\x0b\x0c",6}; static B_bytearray whitespace_bytearray = &whitespace_bytearray_struct; #define NEW_UNFILLED_STR(nm,nchrs,nbtes) \ assert(nbtes >= nchrs); \ nm = acton_malloc(sizeof(struct B_str)); \ (nm)->$class = &B_strG_methods; \ (nm)->nchars = nchrs; \ (nm)->nbytes = nbtes; \ (nm)->str = acton_malloc_atomic(nbtes + 1); \ (nm)->str[nbtes] = 0 #define NEW_UNFILLED_BYTEARRAY(nm,nbtes) \ nm = acton_malloc(sizeof(struct B_bytearray)); \ (nm)->$class = &B_bytearrayG_methods; \ (nm)->nbytes = nbtes; \ (nm)->capacity = nbtes; \ (nm)->str = acton_malloc_atomic(nbtes + 1); \ (nm)->str[nbtes] = 0 #define NEW_UNFILLED_BYTES(nm,nbtes) \ nm = acton_malloc(sizeof(struct B_bytes)); \ (nm)->$class = &B_bytesG_methods; \ (nm)->nbytes = nbtes; \ (nm)->str = acton_malloc_atomic(nbtes + 1); \ (nm)->str[nbtes] = 0 // Conversion to and from C strings B_str to$str(char *str) { B_str res; int nbytes = 0; int nchars = 0; bool isascii = true; unsigned char *p = (unsigned char*)str; while (*p != 0) { if (*p >= 0x80) { isascii = false; break; } p++; } if (isascii) { nbytes = p - (unsigned char*)str; if (nbytes == 0) return null_str; if (nbytes == 1 && str[0] > 0 && (unsigned char)str[0] < ASCII_CHAR_TABLE_SIZE) return &ascii_char_strs[(unsigned char)str[0]]; NEW_UNFILLED_STR(res, nbytes, nbytes); memcpy(res->str, str, nbytes); return res; } p = (unsigned char*)str; int cp, cpnbytes; while(1) { if (*p == '\0') { NEW_UNFILLED_STR(res,nchars, nbytes); memcpy(res->str,str,nbytes); return res; } cpnbytes = utf8proc_iterate(p,-1,&cp); if (cpnbytes < 0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("to$str: Unicode decode error"))); return NULL; } nbytes += cpnbytes; nchars++; p += cpnbytes; } } // No-copy version B_str to_str_noc(char *str) { B_str res = acton_malloc(sizeof(struct B_str)); res->$class = &B_strG_methods; res->nbytes = strlen(str); res->nchars = res->nbytes; res->str = (unsigned char*)str; bool isascii = true; unsigned char *p = (unsigned char*)str; while (*p != 0) { if (*p >= 0x80) { isascii = false; break; } p++; } p = (unsigned char*)str; int cp, cpnbytes; if (!isascii) { res->nchars = 0; while (1) { if (*p == '\0') break; cpnbytes = utf8proc_iterate(p, -1, &cp); if (cpnbytes < 0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("to_str_noc: Unicode decode error"))); return NULL; } p += cpnbytes; res->nchars++; } } return res; } unsigned char *fromB_str(B_str str) { return str->str; } // #bytes in UTF-8 to represent codepoint cp static int byte_length(unsigned int cp) { if (cp < 0x80) return 1; else if (cp < 0x800) return 2; else if (cp < 0x10000) return 3; else return 4; } // #bytes in UTF-8 for char starting with byte c static int byte_length2(unsigned char c) { if (c < 0x80) return 1; else if (c < 0xe0) return 2; else if (c < 0xf0) return 3; else return 4; } typedef int (*transform)(int codepoint); // Mapping a codepoint transform over an entire string // For the moment only used for str_upper and str_lower; // maybe not worthwhile to keep. static B_str str_transform(B_str s, transform f) { if (s->nchars == 0) { return null_str; } int cp, cpu, cplen, cpulen; unsigned char *p = s->str; unsigned char buffer[4*s->nchars]; unsigned char *up = buffer; for (int i=0; i < s->nchars; i++) { cplen = utf8proc_iterate(p,-1,&cp); cpu = f(cp); cpulen = utf8proc_encode_char(cpu,up); p+=cplen; up += cpulen; } int nbytes = (int)(up-buffer); B_str res; NEW_UNFILLED_STR(res,s->nchars,nbytes); memcpy(res->str,buffer,nbytes); return res; } // Find char position in text from byte position. // Assume that i is first byte of a char in text. static int char_no(B_str text,int i) { if (text->nbytes == text->nchars) // ASCII string return i; int res = 0; int k=0; unsigned char *t = text->str; while (k= 0) { for (int i=0; i> 6 == 2) res--; } } return res; } // Find byte position in text from char position. // Assume i is a valid char index in text static int byte_no(B_str text, int i) { int res = 0; unsigned char *t = text->str; for (int k=0; k= 0) { if (i= -nchars) return nchars+i; } $RAISE((B_BaseException)$NEW(B_IndexError, toB_int(i), to$str("index outside str"))); return 0; } // Eliminates slice notation in find, index, count and other methods // with optional start and end and adds defaults for omitted parameters. static int fix_start_end(int nchars, B_int *start, B_int *end) { if (*start==NULL) { *start = acton_malloc(sizeof(struct B_int)); *start = toB_int(0); } else { int st = fromB_int(*start); if (st > nchars) { return -1; } if (st < 0) st += nchars+1; st = st < 0 ? 0 : st; *start = toB_int(st); } if (*end==NULL) { *end = acton_malloc(sizeof(struct B_int)); *end = toB_int(nchars); } else { int en = fromB_int(*end); if (en > nchars) en = nchars; else if (en < 0) en += nchars+1; en = en < 0 ? 0 : en; *end = toB_int(en); } return 0; } // Builds a new one-char string starting at p. static B_str mk_char(unsigned char *p) { unsigned char c = *p; if (c > 0 && c < ASCII_CHAR_TABLE_SIZE) return &ascii_char_strs[c]; B_str res; NEW_UNFILLED_STR(res,1,byte_length2(*p)); for (int i=0; inbytes; i++) res->str[i] = p[i]; return res; } int equal_bytes(unsigned char *p, unsigned char *q, int len) { int i; for (i=0; icategory; int bidi = utf8proc_get_property(codepoint)->bidi_class; return (cat == UTF8PROC_CATEGORY_ZS || (bidi >= UTF8PROC_BIDI_CLASS_B && bidi <= UTF8PROC_BIDI_CLASS_WS)); } static int islinebreak_codepoint(int codepoint) { // category not useful; all the seven codepoints we handle are in category Other, control. return (codepoint <= 0x0a && codepoint <= 0x0d) || (codepoint >= 0x1c && codepoint <= 0x1e); // For now we ignore the three codepoints below which are counted as linebreaks by // Python's splitlines for strings. // || codepoint == 0x85 || codepoint == 0x2028 ||codepoint == 0x2029; } // The Boyer-Moore-Horspool algorithm for searching for pattern in text. // For very short patterns, this should be replaced by brute force. // Returns byte position in text where first occurrence of pattern starts, // or -1 if it does not occur. // Start search from the left end of text. int bmh( unsigned char *text, unsigned char *pattern, int tbytes, int pbytes) { if (pbytes>tbytes) return -1; int skip[256]; for (int i=0; i<256; i++) skip[i] = pbytes; for (int i=0; i=0 && text[i] == pattern[j]) { j--; i--; } if (j==-1) return i+1; k += skip[(int)text[k]]; } return -1; } // Start search from the right end of text. static int rbmh( unsigned char *text, unsigned char *pattern, int tbytes, int pbytes) { if (pbytes>tbytes) return -1; int skip[256]; for (int i=0; i<256; i++) skip[i] = pbytes; for (int i=pbytes-1; i>0; i--) skip[(int)pattern[i]] = i; int k = tbytes - pbytes; int i, j; while (k >= 0) { j = 0; i = k; while (j < pbytes && text[i] == pattern[j]) { j++; i++; } if (j==pbytes) return i-pbytes; k -= skip[(int)text[k]]; } return -1; } struct byte_counts { int printable, squotes, dquotes, escaped, non_printable, non_ascii, braces; }; struct byte_counts byte_count(unsigned char *s, int len) { struct byte_counts res = {0,0,0,0,0,0,0}; unsigned char c; for (int i=0; i \"\"\" *p = '\\'; p++; *p = '"'; p++; *p = '\\'; p++; *p = '"'; p++; *p = '\\'; p++; *p = '"'; p++; i += 2; // Skip the other two quotes continue; } if ((c < 32 && c != '\t' && c != '\r' && c != '\n') || ( c > 126 && c <= max_esc)) { *p = '\\'; p++; *p = 'x'; p++; *p = hexdigits[c >> 4]; p++; *p = hexdigits[c & 0xf]; p++; } else { switch (c) { case '\\': *p = '\\'; p++; *p = '\\'; p++; break; case '\'': if (esc_squote) { *p = '\\'; p++; } *p = '\''; p++; break; case '"': if (esc_dquote) { *p = '\\'; p++; } *p = '"'; p++; break; case '{': if (esc_braces) { *p = '{'; p++; } *p = '{'; p++; break; case '}': if (esc_braces) { *p = '}'; p++; } *p = '}'; p++; break; case '\t': *p = '\\'; p++; *p = 't'; p++; break; case '\n': *p = '\\'; p++; *p = 'n'; p++; break; case '\r': *p = '\\'; p++; *p = 'r'; p++; break; default: *p = c; p++; } } } } // General methods ////////////////////////////////////////////////////////////// B_str B_strG_new(B_value s) { return $NEW(B_str, s); } B_NoneType B_strD___init__(B_str self, B_value s) { // If s is None (C NULL) we use the "None" string. if (s == NULL) { self->nchars = 4; self->nbytes = 4; self->str = (unsigned char *)"None"; return B_None; } B_str res = s->$class->__str__(s); self->nchars = res->nchars; self->nbytes = res->nbytes; self->str = res->str; return B_None; } B_bool B_strD___bool__(B_str s) { return toB_bool(s->nchars > 0); }; B_str B_strD___str__(B_str s) { return s; } B_str B_strD___repr__(B_str s) { struct byte_counts bs = byte_count(s->str, s->nbytes); // We aim to produce a simple, readable representation of the string // - Default to single quotes unless string contains single quotes // - Use double quotes if string contains single quotes // - Use triple quotes (""") if both quote types are present // - If """ appears in the content, escape it as \"\"\" bool use_triple_quotes = (bs.dquotes > 0 && bs.squotes > 0); // Use triple quotes if both types are present bool use_double_quotes = false; // Default to single quotes if (use_triple_quotes) { // Always use """ for triple quotes use_double_quotes = true; } else { // Simple case: use single quotes unless string contains single quotes use_double_quotes = (bs.squotes > 0); } int quotes_per_side = use_triple_quotes ? 3 : 1; int quote_bytes = quotes_per_side * 2; // Count how many """ sequences need escaping (only relevant if using """ delimiters) int escape_triple_bytes = 0; if (use_triple_quotes) { unsigned char *p = s->str; int remaining = s->nbytes; int pos; while ((pos = bmh(p, (unsigned char*)"\"\"\"", remaining, 3)) >= 0) { escape_triple_bytes += 3; // Each quote needs a backslash: """ -> \"\"\" p += pos + 3; remaining = s->nbytes - (p - s->str); } } int newbytes = quote_bytes + bs.escaped + 3*bs.non_printable + bs.braces + escape_triple_bytes; B_str res; NEW_UNFILLED_STR(res, s->nchars + newbytes, s->nbytes + newbytes); char quote_char = use_double_quotes ? '"' : '\''; // Add opening quotes for (int i = 0; i < quotes_per_side; i++) res->str[i] = quote_char; escape_str(res->str + quotes_per_side, s->str, res->nbytes - quote_bytes, s->nbytes, 127, false, false, true, use_triple_quotes); // Add closing quotes for (int i = 0; i < quotes_per_side; i++) res->str[res->nbytes - quotes_per_side + i] = quote_char; return res; } void B_strD___serialize__(B_str str,$Serial$state state) { int nWords = str->nbytes/sizeof($WORD) + 1; // # $WORDS needed to store str->str, including terminating 0. $ROW row = $add_header(STR_ID,2+nWords,state); long nbytes = (int)str->nbytes; // We could pack nbytes and nchars in one $WORD, memcpy(row->blob,&nbytes,sizeof($WORD)); // but we should think of a better, general approach. long nchars = (int)str->nchars; memcpy(row->blob+1,&nchars,sizeof($WORD)); memcpy(row->blob+2,str->str,nbytes+1); } B_str B_strD___deserialize__(B_str self, $Serial$state state) { $ROW this = state->row; state->row =this->next; state->row_no++; B_str res = acton_malloc(sizeof(struct B_str)); long nbytes; memcpy(&nbytes,this->blob,sizeof($WORD)); res->$class = &B_strG_methods; res->nbytes = (int)nbytes; long nchars; memcpy(&nchars,this->blob+1,sizeof($WORD)); res->nchars = (int)nchars; res->str = acton_malloc_atomic(nbytes+1); memcpy(res->str,this->blob+2,nbytes+1); return res; } // str-specific methods //////////////////////////////////////////////////////// B_str B_strD_capitalize(B_str s) { if (s->nchars==0) { return null_str; } int cp, cpu, cplen, cpulen; unsigned char *p = s->str; unsigned char buffer[4*s->nchars]; unsigned char *up = buffer; for (int i=0; i < s->nchars; i++) { cplen = utf8proc_iterate(p,-1,&cp); cpu = i==0? utf8proc_totitle(cp) : utf8proc_tolower(cp); cpulen = utf8proc_encode_char(cpu,up); p+=cplen; up += cpulen; } long nbytes = (long)(up-buffer); B_str res; NEW_UNFILLED_STR(res,s->nchars,nbytes); memcpy(res->str,buffer,nbytes); return res; } B_str B_strD_center(B_str s, B_int width, B_str fill) { int wval = fromB_int(width); if (!fill) fill = space_str; if (fill->nchars != 1) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("center: fill string not single char"))); } if (wval <= s->nchars) { return s; } int pad = (wval-s->nchars); int padleft = pad/2; // Below we make use of the fact padright >= padleft. int padright = pad-padleft; int fillbytes = fill->nbytes; int sbytes = s->nbytes; B_str res; NEW_UNFILLED_STR(res, wval,sbytes+pad*fillbytes); unsigned char *c = fill->str; unsigned char *p = res->str; p += padleft*fillbytes+sbytes; for (int i = 0; istr,p,padleft*fillbytes); p -= sbytes; memcpy(p,s->str,sbytes); return res; } B_int B_strD_count(B_str s, B_str sub, B_int start, B_int end) { int isascii = s->nchars == s->nbytes; B_int st = start; B_int en = end; if (fix_start_end(s->nchars,&st,&en) < 0) return toB_int(0); unsigned char *p = skip_chars(s->str,fromB_int(st),isascii); unsigned char *q = skip_chars(p,fromB_int(en)-fromB_int(st),isascii); int res = 0; int n = bmh(p,sub->str,q-p,sub->nbytes); while (n>=0) { res++; p += n + (sub->nbytes>0 ? sub->nbytes : 1); n = bmh(p,sub->str,q-p,sub->nbytes); } return toB_int(res); } B_bytes B_strD_encode(B_str s) { B_bytes res; NEW_UNFILLED_BYTES(res,s->nbytes); memcpy(res->str,s->str,s->nbytes); return res; } B_bool B_strD_endswith(B_str s, B_str sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nchars,&st,&en) < 0) return B_False; if (en->val-st->val < sub->nbytes) return B_False; int isascii = s->nchars==s->nbytes; unsigned char *p = skip_chars(s->str + s->nbytes,fromB_int(en) - s->nchars,isascii) - sub->nbytes; unsigned char *q = sub->str; for (int i=0; inbytes; i++) { if (*p == 0 || *p++ != *q++) { return B_False; } } return B_True; } B_str B_strD_expandtabs(B_str s, B_int tabsize){ if (s->nchars == 0) { return null_str; } int tabsz = tabsize?fromB_int(tabsize):8; int pos = 0; int expanded = 0; tabsz = tabsz <= 0 ? 1 : tabsz; unsigned char buffer[tabsz * s->nchars]; unsigned char *p = s->str; unsigned char *q = buffer; for (int i=0; inchars; i++) { if (*p == '\t') { int n = tabsz - pos % tabsz; for (int j=0; j < n; j++) { *q++ = ' '; } p++; expanded += n-1; pos+=n; } else if (*p=='\n' || *p == '\r') { *q++ = *p++; pos = 0; } else { for (int j=0; j< byte_length2(*p); j++) { *q++ = *p++; pos++; } } } B_str res; NEW_UNFILLED_STR(res,s->nchars+expanded,s->nbytes+expanded); memcpy(res->str,buffer,s->nbytes+expanded); return res; } B_int B_strD_find(B_str s, B_str sub, B_int start, B_int end) { int isascii = s->nchars == s->nbytes; B_int st = start; B_int en = end; if (fix_start_end(s->nchars,&st,&en) < 0) return toB_int(-1); unsigned char *p = skip_chars(s->str,fromB_int(st),isascii); unsigned char *q = skip_chars(p,fromB_int(en)-fromB_int(st),isascii); int n = bmh(p,sub->str,q-p,sub->nbytes); if (n<0) return toB_int(-1); return toB_int(char_no(s,n+p-s->str)); } B_int B_strD_index(B_str s, B_str sub, B_int start, B_int end) { B_int n = B_strD_find(s,sub,start,end); if (fromB_int(n)<0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("index: substring not found"))); } return n; } B_bool B_strD_isalnum(B_str s) { unsigned char *p = s->str; int codepoint; int nbytes; if (s->nchars == 0) return B_False; for (int i=0; i < s->nchars; i++) { nbytes = utf8proc_iterate(p,-1,&codepoint); utf8proc_category_t cat = utf8proc_category(codepoint); if ((cat < UTF8PROC_CATEGORY_LU || cat > UTF8PROC_CATEGORY_LO) && cat != UTF8PROC_CATEGORY_ND) return B_False; p += nbytes; } return B_True; } B_bool B_strD_isalpha(B_str s) { unsigned char *p = s->str; int codepoint; int nbytes; if (s->nchars == 0) return B_False; for (int i=0; i < s->nchars; i++) { nbytes = utf8proc_iterate(p,-1,&codepoint); utf8proc_category_t cat = utf8proc_category(codepoint); if (cat < UTF8PROC_CATEGORY_LU || cat > UTF8PROC_CATEGORY_LO) return B_False; p += nbytes; } return B_True; } B_bool B_strD_isascii(B_str s) { unsigned char *p = s->str; for (int i=0; i < s->nbytes; i++) { if (*p > 127) return B_False; p++; } return B_True; } B_bool B_strD_isdecimal(B_str s) { unsigned char *p = s->str; int codepoint; int nbytes; if (s->nchars == 0) return B_False; for (int i=0; i < s->nchars; i++) { nbytes = utf8proc_iterate(p,-1,&codepoint); utf8proc_category_t cat = utf8proc_category(codepoint); if (cat != UTF8PROC_CATEGORY_ND) return B_False; p += nbytes; } return B_True; } B_bool B_strD_islower(B_str s) { unsigned char *p = s->str; int codepoint; int nbytes; int has_cased = 0; if (s->nchars == 0) return B_False; for (int i=0; i < s->nchars; i++) { nbytes = utf8proc_iterate(p,-1,&codepoint); utf8proc_category_t cat = utf8proc_category(codepoint); if (cat == UTF8PROC_CATEGORY_LT|| cat == UTF8PROC_CATEGORY_LU) return B_False; if (cat == UTF8PROC_CATEGORY_LL) has_cased = 1; p += nbytes; } return toB_bool(has_cased); } B_bool B_strD_isprintable(B_str s) { unsigned char *p = s->str; int codepoint; int nbytes; if (s->nchars == 0) return B_False; for (int i=0; i < s->nchars; i++) { nbytes = utf8proc_iterate(p,-1,&codepoint); utf8proc_category_t cat = utf8proc_category(codepoint); if (cat >= UTF8PROC_CATEGORY_ZS && codepoint != 0x20) return B_False; p += nbytes; } return B_True; } B_bool B_strD_isspace(B_str s) { unsigned char *p = s->str; int codepoint; int nbytes; if (s->nchars == 0) return B_False; for (int i=0; i < s->nchars; i++) { nbytes = utf8proc_iterate(p,-1,&codepoint); if (!isspace_codepoint(codepoint)) return B_False; p += nbytes; } return B_True; } B_bool B_strD_istitle(B_str s) { unsigned char *p = s->str; int codepoint; int nbytes; int hascased = 0; int incasedrun = 0; if (s->nchars == 0) return B_False; for (int i=0; i < s->nchars; i++) { nbytes = utf8proc_iterate(p,-1,&codepoint); utf8proc_category_t cat = utf8proc_category(codepoint); if (cat == UTF8PROC_CATEGORY_LU || cat == UTF8PROC_CATEGORY_LT ) { hascased = 1; if (incasedrun) return B_False; incasedrun = 1; } else if (cat == UTF8PROC_CATEGORY_LL) { hascased = 1; if (!incasedrun) return B_False; } else incasedrun = 0; p += nbytes; } return toB_bool(hascased); } B_bool B_strD_isupper(B_str s) { unsigned char *p = s->str; int codepoint; int nbytes; int hascased = 0; if (s->nchars == 0) return B_False; for (int i=0; i < s->nchars; i++) { nbytes = utf8proc_iterate(p,-1,&codepoint); utf8proc_category_t cat = utf8proc_category(codepoint); if (cat == UTF8PROC_CATEGORY_LL) return B_False; if (cat == UTF8PROC_CATEGORY_LU || cat == UTF8PROC_CATEGORY_LT) hascased = 1; p += nbytes; } return toB_bool(hascased); } B_str B_strD_join(B_str s, B_Iterable wit, $WORD iter) { int totchars = 0; int totbytes = 0; B_CollectionD_SequenceD_list wit2 = B_CollectionD_SequenceD_listG_witness; B_list lst = wit2->$class->__fromiter__(wit2,wit,iter); B_str nxt; int len = lst->length; for (int i=0; idata[i]; totchars += nxt->nchars; totbytes += nxt->nbytes; } if (len > 1) { totchars += (len-1) * s->nchars; totbytes += (len-1) * s->nbytes; } B_str res; NEW_UNFILLED_STR(res,totchars,totbytes); if (len > 0) { nxt = (B_str)lst->data[0]; unsigned char *p = res->str; memcpy(p,nxt->str,nxt->nbytes); p += nxt->nbytes; for (int i=1; idata[i]; memcpy(p,s->str,s->nbytes); p += s->nbytes; memcpy(p,nxt->str,nxt->nbytes); p += nxt->nbytes; } } return res; } B_str B_strD_ljust(B_str s, B_int width, B_str fill) { if (!fill) fill = space_str; if (fill->nchars != 1) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("ljust: fill str not single char"))); } int wval = fromB_int(width); if (wval <= s->nchars) { return s; } int pad = (wval-s->nchars); B_str res; NEW_UNFILLED_STR(res,wval, s->nbytes+pad*fill->nbytes); unsigned char *c = fill->str; unsigned char *p = res->str + s->nbytes; for (int i = 0; inbytes; j++) *p++ = c[j]; } memcpy(res->str,s->str,s->nbytes); return res; } B_str B_strD_lower(B_str s) { return str_transform(s,utf8proc_tolower); } B_str B_strD_lstrip(B_str s, B_str cs) { if (s->nchars == 0) return s; if (cs==NULL) cs = whitespace_str; unsigned char *p = s->str; int i, k; for (i = 0; i < s->nchars; i++) { unsigned char *q = cs->str; for (k = 0; k < cs->nchars; k++) { if (equal_bytes(p,q,byte_length2(*q))) break; else q += byte_length2(*q); } if (k == cs->nchars) break; p += byte_length2(*p); } B_str res; NEW_UNFILLED_STR(res,s->nchars-i,s->str+s->nbytes-p); memcpy(res->str,p,res->nbytes); return res; } B_tuple B_strD_partition(B_str s, B_str sep) { int n = fromB_int(B_strD_find(s,sep,NULL,NULL)); if (n<0) { return $NEWTUPLE(3,s,null_str,null_str); } else { int isascii = s->nchars == s->nbytes; int nb = (int)(skip_chars(s->str,n,isascii)-s->str); B_str ls; NEW_UNFILLED_STR(ls,n,nb); memcpy(ls->str,s->str,nb); B_str rs; int nbr = s->nbytes - sep->nbytes - nb; NEW_UNFILLED_STR(rs,s->nchars-n-sep->nchars,nbr); memcpy(rs->str,s->str+nb+sep->nbytes,nbr); return $NEWTUPLE(3,ls,sep,rs); } } B_str B_strD_replace(B_str s, B_str old, B_str new, B_int count) { if (count==NULL) count = toB_int(INT_MAX); int c = fromB_int(B_strD_count(s,old,NULL,NULL)); int c0 = fromB_int(count) < c ? fromB_int(count) : c; if (c0==0){ return s; } int nbytes = s->nbytes + c0*(new->nbytes-old->nbytes); int nchars = s->nchars+c0*(new->nchars-old->nchars); B_str res; NEW_UNFILLED_STR(res,nchars,nbytes); unsigned char *p = s->str; unsigned char *q = res->str; unsigned char *pold = old->str; unsigned char *pnew = new->str; int plen = s->nbytes; int n; for (int i=0; i0 && old->nbytes==0 ? 1 : bmh(p,pold,plen,old->nbytes); if (n>0) { memcpy(q,p,n); p+=n; q+=n; } memcpy(q,pnew,new->nbytes); p += old->nbytes; q += new->nbytes; plen -= n+old->nbytes; } if (plen>0) memcpy(q,p,plen); return res; } B_int B_strD_rfind(B_str s, B_str sub, B_int start, B_int end) { int isascii = s->nchars == s->nbytes; B_int st = start; B_int en = end; if (fix_start_end(s->nchars,&st,&en) < 0) return toB_int(-1); unsigned char *p = skip_chars(s->str,fromB_int(st),isascii); unsigned char *q = skip_chars(p,fromB_int(en)-fromB_int(st),isascii); int n = rbmh(p,sub->str,q-p,sub->nbytes); if (n<0) return toB_int(-1); return toB_int(char_no(s,n+p-s->str)); } B_int B_strD_rindex(B_str s, B_str sub, B_int start, B_int end) { B_int n = B_strD_rfind(s,sub,start,end); if (fromB_int(n)<0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("rindex: substring not found"))); }; return n; } B_str B_strD_rjust(B_str s, B_int width, B_str fill) { if (!fill) fill = space_str; if (fill->nchars != 1) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("rjust: fill string not single char"))); } int wval = fromB_int(width); if (wval <= s->nchars) { return s; } int pad = (wval-s->nchars); B_str res; NEW_UNFILLED_STR(res,wval,s->nbytes+pad*fill->nbytes); unsigned char *c = fill->str; unsigned char *p = res->str; for (int i = 0; inbytes; j++) *p++ = c[j]; } memcpy(p,s->str,s->nbytes); return res; } B_tuple B_strD_rpartition(B_str s, B_str sep) { int n = fromB_int(B_strD_rfind(s,sep,NULL,NULL)); if (n<0) { return $NEWTUPLE(3,null_str,null_str,s); } else { int isascii = s->nchars == s->nbytes; int nb = (int)(skip_chars(s->str,n,isascii)-s->str); B_str ls; NEW_UNFILLED_STR(ls,n,nb); memcpy(ls->str,s->str,nb); int nbr = s->nbytes - sep->nbytes - nb; B_str rs; NEW_UNFILLED_STR(rs,s->nchars-n-sep->nchars,nbr); memcpy(rs->str,s->str+nb+sep->nbytes,nbr); return $NEWTUPLE(3,ls,sep,rs); } } B_list B_strD_split(B_str s, B_str sep, B_int maxsplit) { B_list res = $NEW(B_list,NULL,NULL); B_SequenceD_list wit = B_SequenceD_listG_witness; if (maxsplit == NULL || fromB_int(maxsplit) < 0) maxsplit = toB_int(INT_MAX); int remaining = s->nchars; if (sep == NULL) { unsigned char *p = s->str; int nbytes, codepoint, wordlength; if (remaining==0) { return res; } wordlength = 0; int inword = 0; unsigned char *q; while (remaining > 0) { nbytes = utf8proc_iterate(p,-1,&codepoint); if (!isspace_codepoint(codepoint)) { if (!inword) { inword = 1; q = p; wordlength = 1; if (res->length == fromB_int(maxsplit)) break; // we have now removed leading whitespace in remainder } else wordlength++; } else { if (inword) { inword = 0; B_str word; NEW_UNFILLED_STR(word,wordlength,p-q); memcpy(word->str,q,p-q); wit->$class->append(wit,res,word); wordlength = 0; } } remaining--; p += nbytes; } // this if statement should be simplified; almost code duplication. if (remaining == 0) { if (inword) { B_str word; NEW_UNFILLED_STR(word,wordlength,p-q); memcpy(word->str,q,p-q); wit->$class->append(wit,res,word); } } else { B_str word; p = s->str+s->nbytes; NEW_UNFILLED_STR(word,remaining,p-q); memcpy(word->str,q,p-q); wit->$class->append(wit,res,word); } // $WORD w = list_getitem(res,0); return res; } else { // separator given if (sep->nchars==0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("split: separator is empty string"))); } if (remaining==0) { // for some unfathomable reason, this is the behaviour of the Python method wit->$class->append(wit,res,null_str); return res; } B_str ls, rs, ssep; rs = s; // Note: This builds many intermediate rs strings... while (rs->nchars>0 && res->length < fromB_int(maxsplit)) { B_tuple t = B_strD_partition(rs,sep); ssep = (B_str)t->components[1]; rs = (B_str)t->components[2]; wit->$class->append(wit,res,(B_str)t->components[0]); } if (ssep->nchars>0) wit->$class->append(wit,res,rs); return res; } } B_list B_strD_splitlines(B_str s, B_bool keepends) { B_SequenceD_list wit = B_SequenceD_listG_witness; if (!keepends) keepends = B_False; B_list res = $NEW(B_list,NULL,NULL); unsigned char *p = s->str; unsigned char *q = p; int nbytes, codepoint, linelength; if (s->nbytes==0) { return res; } linelength = 0; while (p < s->str + s->nbytes) { nbytes = utf8proc_iterate(p,-1,&codepoint); utf8proc_category_t cat = utf8proc_category(codepoint); if (!islinebreak_codepoint(codepoint)) { linelength++; p += nbytes; } else { // all the codepoints we count as linebreaks are ascii bytes, i.e. nbytes = 1. B_str line; int winend = *p=='\r' && *(p+1)=='\n'; int size = p-q + (keepends->val ? 1 + winend : 0); NEW_UNFILLED_STR(line,linelength + (keepends->val ? 1 + winend : 0),size); memcpy(line->str,q,size); p += 1 + winend; q = p; wit->$class->append(wit,res,line); linelength = 0; } } if (q < p) { B_str line; NEW_UNFILLED_STR(line,linelength,p-q); memcpy(line->str,q,p-q); wit->$class->append(wit,res,line); } return res; } B_str B_strD_rstrip(B_str s, B_str cs) { if (s->nchars == 0) return s; if (cs==NULL) cs = whitespace_str; unsigned char *p = s->str + s->nbytes; int i, k; for (i = 0; i < s->nchars; i++) { unsigned char *q = cs->str; p = skip_chars(p,-1,0); for (k = 0; k < cs->nchars; k++) { if (equal_bytes(p,q,byte_length2(*q))) break; else q += byte_length2(*q); } if (k == cs->nchars) break; } p = skip_chars(p,1,0); B_str res; NEW_UNFILLED_STR(res,s->nchars-i,p-s->str); memcpy(res->str,s->str,res->nbytes); return res; } B_bool B_strD_startswith(B_str s, B_str sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nchars,&st,&en) < 0) return B_False; int isascii = s->nchars==s->nbytes; unsigned char *p = skip_chars(s->str,fromB_int(st),isascii); unsigned char *q = sub->str; for (int i=0; inbytes; i++) { if (*p == 0 || *p++ != *q++) { return B_False; } } return B_True; } B_str B_strD_strip(B_str s, B_str cs) { return B_strD_lstrip(B_strD_rstrip(s,cs),cs); } B_str B_strD_upper(B_str s) { return str_transform(s,utf8proc_toupper); } B_str B_strD_zfill(B_str s, B_int width) { int wval = fromB_int(width); int fill = wval - s->nchars; if (fill < 0) return s; B_str res; NEW_UNFILLED_STR(res,wval,s->nbytes+fill); unsigned char *p = s->str; unsigned char *q = res->str; int hassign = (*p=='+' | *p=='-'); if (hassign) { *q = *p; q++; } for (int i=0; i < fill; i++) *q++ = '0'; memcpy(res->str+hassign+fill,s->str+hassign,s->nbytes-hassign); return res; } // Protocol methods; string implementations ///////////////////////////////////////////////////////////////////////////// /* Note: We make str instances for Indexed and Sliceable even though these protocols include mutating methods. */ // B_Ord /////////////////////////////////////////////////////////////////////////////////////////////// // TODO: We should consider how to normalize strings before comparisons // The comparisons below do lexicographic byte-wise comparisons. // Thus they do not in general reflect locale-dependent order conventions. B_bool B_OrdD_strD___eq__ (B_OrdD_str wit, B_str a, B_str b) { return toB_bool(strcmp((char *)a->str,(char *)b->str) == 0); } B_bool B_OrdD_strD___ne__ (B_OrdD_str wit, B_str a, B_str b) { return toB_bool(strcmp((char *)a->str,(char *)b->str) != 0); } B_bool B_OrdD_strD___lt__ (B_OrdD_str wit, B_str a, B_str b) { return toB_bool(strcmp((char *)a->str,(char *)b->str) < 0); } B_bool B_OrdD_strD___le__ (B_OrdD_str wit, B_str a, B_str b) { return toB_bool(strcmp((char *)a->str,(char *)b->str) <= 0); } B_bool B_OrdD_strD___gt__ (B_OrdD_str wit, B_str a, B_str b) { return toB_bool(strcmp((char *)a->str,(char *)b->str) > 0); } B_bool B_OrdD_strD___ge__ (B_OrdD_str wit, B_str a, B_str b) { return toB_bool(strcmp((char *)a->str,(char *)b->str) >= 0); } // B_Hashable /////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_strD___eq__ (B_HashableD_str wit, B_str a, B_str b) { return toB_bool(strcmp((char *)a->str,(char *)b->str) == 0); } B_bool B_HashableD_strD___ne__ (B_HashableD_str wit, B_str a, B_str b) { return toB_bool(strcmp((char *)a->str,(char *)b->str) != 0); } B_NoneType B_HashableD_strD_hash(B_HashableD_str wit, B_str a, B_hasher h) { zig_hash_wyhash_update(h->_hasher,to$bytes((char *)a->str)); return B_None; } // B_Times ///////////////////////////////////////////////////////////////////////////////////////////// B_str B_TimesD_strD___add__ (B_TimesD_str wit, B_str s, B_str t) { B_str res; NEW_UNFILLED_STR(res,s->nchars + t->nchars,s->nbytes + t->nbytes); memcpy(res->str,s->str,s->nbytes); memcpy(res->str+s->nbytes,t->str,t->nbytes); return res; } B_str B_TimesD_strD___zero__ (B_TimesD_str wit) { return null_str; } B_str B_TimesD_strD___mul__ (B_TimesD_str wit, B_str a, B_int n) { int nval = fromB_int(n); if (nval <= 0) return null_str; else { B_str res; NEW_UNFILLED_STR(res,a->nchars * nval, a->nbytes * nval); for (int i=0; istr + i*a->nbytes,a->str,a->nbytes); return res; } } // Collection /////////////////////////////////////////////////////////////////////////////////////// B_str B_ContainerD_strD___fromiter__ (B_ContainerD_str wit, B_Iterable wit2, $WORD iter) { return B_strD_join(null_str,wit2,iter); } B_int B_ContainerD_strD___len__ (B_ContainerD_str wit, B_str s){ return toB_int(s->nchars); } // B_Container /////////////////////////////////////////////////////////////////////////// B_bool B_ContainerD_strD___contains__ (B_ContainerD_str wit, B_str s, B_str sub) { return toB_bool(bmh(s->str,sub->str,s->nbytes,sub->nbytes) >= 0); } B_bool B_ContainerD_strD___containsnot__ (B_ContainerD_str wit, B_str s, B_str sub) { return toB_bool(!B_ContainerD_strD___contains__(wit, s, sub)->val); } // Iterable /////////////////////////////////////////////////////////////////////////// // first define Iterator class B_IteratorB_str B_IteratorB_strG_new(B_str str) { return $NEW(B_IteratorB_str, str); } B_NoneType B_IteratorB_strD_init(B_IteratorB_str self, B_str str) { self->src = str; self->nxt = 0; return B_None; } void B_IteratorB_strD_serialize(B_IteratorB_str self,$Serial$state state) { $step_serialize(self->src,state); $step_serialize(toB_int(self->nxt),state); } B_IteratorB_str B_IteratorB_str$_deserialize(B_IteratorB_str res, $Serial$state state) { if (!res) res = $DNEW(B_IteratorB_str,state); res->src = (B_str)$step_deserialize(state); res->nxt = fromB_int((B_int)$step_deserialize(state)); return res; } B_bool B_IteratorB_strD_bool(B_IteratorB_str self) { return B_True; } B_str B_IteratorB_strD_str(B_IteratorB_str self) { return $FORMAT("", self); } // this is next function for forward iteration static B_str B_IteratorB_strD_next(B_IteratorB_str self) { unsigned char *p = &self->src->str[self->nxt]; if (*p != 0) { self->nxt +=byte_length2(*p); return mk_char(p); } $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("str iterator terminated"))); return NULL; // to avoid compiler warning } struct B_IteratorB_strG_class B_IteratorB_strG_methods = {"B_IteratorB_str",UNASSIGNED,($SuperG_class)&B_IteratorG_methods, B_IteratorB_strD_init, B_IteratorB_strD_serialize, B_IteratorB_str$_deserialize, B_IteratorB_strD_bool, B_IteratorB_strD_str, B_IteratorB_strD_str, B_IteratorB_strD_next}; // now, define __iter__ B_Iterator B_ContainerD_strD___iter__ (B_ContainerD_str wit, B_str s) { return (B_Iterator)$NEW(B_IteratorB_str,s); } // Indexed /////////////////////////////////////////////////////////////////////////// B_str B_SliceableD_strD___getitem__ (B_SliceableD_str wit, B_str s, B_int i) { unsigned char *p = s->str; int ix = get_index(fromB_int(i),s->nchars); p = skip_chars(p,ix,s->nchars == s->nbytes); return mk_char(p); } B_NoneType B_SliceableD_strD___setitem__ (B_SliceableD_str wit, B_str str, B_int i, B_str val) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method setitem on string"))); return B_None; } B_NoneType B_SliceableD_strD___delitem__ (B_SliceableD_str wit, B_str str, B_int i) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method delitem on string"))); return B_None; } // Sliceable ////////////////////////////////////////////////////////////////////////////////////// B_str B_SliceableD_strD___getslice__ (B_SliceableD_str wit, B_str s, B_slice slc) { int isascii = s->nchars == s->nbytes; int nchars = s->nchars; int nbytes = 0; int64_t start, stop, step, slen; normalize_slice(slc, nchars, &slen, &start, &stop, &step); if (slen == 0) { return null_str; } if (slen == 1) { return mk_char(skip_chars(s->str, start, isascii)); } //slice notation have been eliminated and default values applied. unsigned char buffer[4*slen]; // very conservative buffer size. unsigned char *p = buffer; unsigned char *t = skip_chars(s->str, start, isascii); for (int i=0; i 0) memcpy(res->str,buffer,nbytes); return res; } B_NoneType B_SliceableD_strD___setslice__ (B_SliceableD_str wit, B_str str, B_Iterable wit2, B_slice slc, $WORD iter) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method setslice on string"))); return B_None; } B_NoneType B_SliceableD_strD___delslice__ (B_SliceableD_str wit, B_str str, B_slice slc) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method delslice on string"))); return B_None; } // End of str implementation //////////////////////////////////////////////////// // bytearray implementation ////////////////////////////////////////////////////////////////////////////// // Conversion to and from C strings B_bytearray toB_bytearray(char *str) { B_bytearray res; int len = strlen(str); NEW_UNFILLED_BYTEARRAY(res,len); memcpy(res->str,str,len); return res; } B_bytearray to$bytearrayD_len(char *str, int len) { B_bytearray res; NEW_UNFILLED_BYTEARRAY(res, len); memcpy(res->str, str, len); return res; } B_bytearray actBytearrayFromCString(char *str) { B_bytearray res; int len = strlen(str); NEW_UNFILLED_BYTEARRAY(res,len); memcpy(res->str,str,len); return res; } B_bytearray actBytearrayFromCStringNoCopy(char *str) { B_bytearray res = acton_malloc(sizeof(struct B_bytearray)); res->$class = &B_bytearrayG_methods; res->nbytes = strlen(str); res->str = (unsigned char*)str; return res; } B_bytearray actBytearrayFromCStringLength(char *str, int len) { B_bytearray res; NEW_UNFILLED_BYTEARRAY(res, len); memcpy(res->str, str, len); return res; } B_bytearray actBytearrayFromCStringLengthNoCopy(char *str, int length) { B_bytearray res = acton_malloc(sizeof(struct B_bytearray)); res->$class = &B_bytearrayG_methods; res->nbytes = length; res->str = (unsigned char*)str; return res; } unsigned char *fromB_bytearray(B_bytearray b) { return b->str; } // Auxiliaries static void expand_bytearray(B_bytearray b,int n) { if (b->capacity >= b->nbytes + n) return; int newcapacity = b->capacity==0 ? 1 : b->capacity; while (newcapacity < b->nbytes+n) newcapacity <<= 1; unsigned char *newstr = b->str==NULL ? acton_malloc_atomic(newcapacity+1) : acton_realloc(b->str,newcapacity+1); if (newstr == NULL) { $RAISE((B_BaseException)$NEW(B_MemoryError,to$str("memory allocation failed"))); } b->str = newstr; b->capacity = newcapacity; } static B_bytearray B_bytearrayD_copy(B_bytearray s) { B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,s->nbytes); res->nbytes = s->nbytes; memcpy(res->str,s->str,s->nbytes); return res; } // General methods B_bytearray B_bytearrayG_new(B_bytes b) { return $NEW(B_bytearray, b); } B_NoneType B_bytearrayD___init__(B_bytearray self, B_bytes b) { int len = b->nbytes; self->nbytes = len; self->capacity = len; self->str = acton_malloc_atomic(len+1); memcpy(self->str,b->str,len+1); return B_None; } B_bool B_bytearrayD___bool__(B_bytearray s) { return toB_bool(s->nbytes > 0); }; B_str B_bytearrayD___str__(B_bytearray s) { struct byte_counts bs = byte_count(s->str, s->nbytes); bool use_single_quotes = !(bs.dquotes==0 && bs.squotes>0); int escaped_quotes = use_single_quotes ? bs.dquotes : bs.squotes; int newbytes = 14+bs.escaped+3*bs.non_printable+escaped_quotes+3*bs.non_ascii; B_str res; int nbytes = s->nbytes+newbytes; NEW_UNFILLED_STR(res,nbytes,nbytes); escape_str(res->str+12,s->str,res->nbytes-12,s->nbytes,255,!use_single_quotes,use_single_quotes,false,false); if (use_single_quotes) { res->str[11] = '\''; res->str[res->nbytes-2] = '\''; } else { res->str[11] = '"'; res->str[res->nbytes-2] = '"'; } memcpy(res->str, "bytearray(b",11); res->str[res->nbytes-1] = ')'; return res; } B_str B_bytearrayD___repr__(B_bytearray s) { return B_bytearrayD___str__(s); } void B_bytearrayD___serialize__(B_bytearray str,$Serial$state state) { int nWords = str->nbytes/sizeof($WORD) + 1; // # $WORDS needed to store str->str, including terminating 0. $ROW row = $add_header(BYTEARRAY_ID,1+nWords,state); long nbytes = (long)str->nbytes; memcpy(row->blob,&nbytes,sizeof($WORD)); memcpy(row->blob+1,str->str,nbytes+1); } B_bytearray B_bytearrayD___deserialize__(B_bytearray res, $Serial$state state) { $ROW this = state->row; state->row =this->next; state->row_no++; if(!res) res = acton_malloc(sizeof(struct B_bytearray)); long nbytes; memcpy(&nbytes,this->blob,sizeof($WORD)); res->$class = &B_bytearrayG_methods; res->nbytes = (long)nbytes; res->str = acton_malloc_atomic(nbytes+1); memcpy(res->str,this->blob+1,nbytes+1); return res; } // bytearray methods B_bytearray B_bytearrayD_capitalize(B_bytearray s) { if (s->nbytes==0) { return toB_bytearray(""); } B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,s->nbytes); res->str[0] = toupper(s->str[0]); for (int i=1; inbytes; i++) res->str[i] = tolower(s->str[i]); return res; } B_bytearray B_bytearrayD_center(B_bytearray s, B_int width, B_bytearray fill) { if (!fill) fill = space_bytearray; if (fill->nbytes != 1) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("center: fill bytearray not single char"))); } int wval = fromB_int(width); if (wval <= s->nbytes) { return B_bytearrayD_copy(s); } int pad = (wval-s->nbytes); int padleft = pad/2; int padright = pad-padleft; int sbytes = s->nbytes; B_bytearray res; NEW_UNFILLED_BYTEARRAY(res, wval); unsigned char c = fill->str[0]; unsigned char *p = res->str; p += padleft+sbytes; for (int i = 0; istr,p,padleft); p -= sbytes; memcpy(p,s->str,sbytes); return res; } B_int B_bytearrayD_count(B_bytearray s, B_bytearray sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nbytes,&st,&en) < 0) return toB_int(0); int stval = fromB_int(st); int enval = fromB_int(en); unsigned char *p = &s->str[stval]; unsigned char *q = &p[enval-stval]; int res = 0; int n = bmh(p,sub->str,q-p,sub->nbytes); while (n>=0) { res++; p += n + (sub->nbytes>0 ? sub->nbytes : 1); n = bmh(p,sub->str,q-p,sub->nbytes); } return toB_int(res); } B_str B_bytearrayD_decode(B_bytearray s) { return to$str((char*)s->str); } B_bool B_bytearrayD_endswith(B_bytearray s, B_bytearray sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nbytes,&st,&en) < 0) return B_False; int enval = fromB_int(en); unsigned char *p = &s->str[enval-sub->nbytes]; unsigned char *q = sub->str; for (int i=0; inbytes; i++) { if (*p == 0 || *p++ != *q++) { return B_False; } } return B_True; } B_bytearray B_bytearrayD_expandtabs(B_bytearray s, B_int tabsz){ if (s->nbytes == 0) { return toB_bytearray(""); } int pos = 0; int expanded = 0; int tabsize = fromB_int(tabsz); tabsize = tabsize <= 0 ? 1 : tabsize; unsigned char buffer[tabsize * s->nbytes]; unsigned char *p = s->str; unsigned char *q = buffer; for (int i=0; inbytes; i++) { if (*p == '\t') { int n = tabsize - pos % tabsize; for (int j=0; j < n; j++) { *q++ = ' '; } p++; expanded += n-1; pos+=n; } else if (*p=='\n' || *p == '\r') { *q++ = *p++; pos = 0; } else { for (int j=0; j< byte_length2(*p); j++) { *q++ = *p++; pos++; } } } B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,s->nbytes+expanded); memcpy(res->str,buffer,s->nbytes+expanded); return res; } B_int B_bytearrayD_find(B_bytearray s, B_bytearray sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nbytes,&st,&en) < 0) return toB_int(-1); unsigned char *p = &s->str[fromB_int(st)]; unsigned char *q = &s->str[fromB_int(en)]; int n = bmh(p,sub->str,q-p,sub->nbytes); if (n<0) return toB_int(-1); return toB_int(n+p-s->str); } B_bytearray B_bytearrayD_from_hex(B_str s) { // Each byte is represented by 2 hex chars int strlen = s->nbytes; // Changed from len to nbytes if (strlen % 2 != 0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("from_hex: hex string must have even length"))); } int bytelen = strlen / 2; char *result = acton_malloc_atomic(bytelen); for (int i = 0; i < strlen; i += 2) { char high = s->str[i]; char low = s->str[i + 1]; // Convert hex chars to values 0-15 int high_val, low_val; // Handle high nibble if (high >= '0' && high <= '9') high_val = high - '0'; else if (high >= 'a' && high <= 'f') high_val = high - 'a' + 10; else if (high >= 'A' && high <= 'F') high_val = high - 'A' + 10; else { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("from_hex: invalid hex character"))); } // Handle low nibble if (low >= '0' && low <= '9') low_val = low - '0'; else if (low >= 'a' && low <= 'f') low_val = low - 'a' + 10; else if (low >= 'A' && low <= 'F') low_val = low - 'A' + 10; else { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("from_hex: invalid hex character"))); } // Combine into byte result[i/2] = (high_val << 4) | low_val; } return actBytearrayFromCStringLengthNoCopy(result, bytelen); } B_str B_bytearrayD_hex(B_bytearray s) { // Each byte becomes 2 hex chars, so output length is 2 * number of bytes int len = s->nbytes * 2; char *result = acton_malloc_atomic(len); // Hex digit lookup table const char hex_digits[] = "0123456789abcdef"; // Convert each byte to two hex digits for (int i = 0; i < s->nbytes; i++) { unsigned char byte = s->str[i]; result[i*2] = hex_digits[byte >> 4]; // High nibble result[i*2 + 1] = hex_digits[byte & 0xf]; // Low nibble } // Convert to Acton string without copying return to_str_noc(result); } B_int B_bytearrayD_index(B_bytearray s, B_bytearray sub, B_int start, B_int end) { B_int n = B_bytearrayD_find(s,sub,start,end); if (fromB_int(n)<0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("index: substring not found"))); } return n; } B_bool B_bytearrayD_isalnum(B_bytearray s) { if (s->nbytes==0) return B_False; for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; if (c < '0' || c > 'z' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a')) return B_False; } return B_True; } B_bool B_bytearrayD_isalpha(B_bytearray s) { if (s->nbytes==0) return B_False; for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; if (c < 'A' || c > 'z' || (c > 'Z' && c < 'a')) return B_False; } return B_True; } B_bool B_bytearrayD_isascii(B_bytearray s) { for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; if (c > 0x7f) return B_False; } return B_True; } B_bool B_bytearrayD_isdigit(B_bytearray s) { if (s->nbytes==0) return B_False; for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; if (c<'0' || c > '9') return B_False; } return B_True; } B_bool B_bytearrayD_islower(B_bytearray s) { int has_lower = 0; for (int i=0; i < s->nbytes; i++) { unsigned char c = s->str[i]; if (c >= 'A' && c <= 'Z') return B_False; if (c >= 'a' && c <= 'z') has_lower = 1; } return toB_bool(has_lower); } B_bool B_bytearrayD_isspace(B_bytearray s) { if (s->nbytes==0) return B_False; for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; if (c !=' ' && c != '\t' && c != '\n' && c != '\r' && c != '\x0b' && c != '\f') return B_False; } return B_True; } B_bool B_bytearrayD_istitle(B_bytearray s) { if (s->nbytes==0) return B_False; int incasedrun = 0; for (int i=0; i < s->nbytes; i++) { unsigned char c = s->str[i]; if (c >='A' && c <= 'Z') { if (incasedrun) return B_False; incasedrun = 1; } else if (c >='a' && c <= 'z') { if (!incasedrun) return B_False; } else incasedrun = 0; } return B_True; } B_bool B_bytearrayD_isupper(B_bytearray s) { int has_upper = 0; for (int i=0; i < s->nbytes; i++) { unsigned char c = s->str[i]; if (c >= 'a' && c <= 'z') return B_False; if (c >= 'a' && c <= 'z') has_upper = 1; } return toB_bool(has_upper); } B_bytearray B_bytearrayD_join(B_bytearray s, B_Iterable wit, $WORD iter) { int totbytes = 0; B_CollectionD_SequenceD_list wit2 = B_CollectionD_SequenceD_listG_witness; B_list lst = wit2->$class->__fromiter__(wit2,wit,iter); B_bytearray nxt; int len = lst->length; for (int i=0; idata[i]; totbytes += nxt->nbytes; } if (len > 1) { totbytes += (len-1) * s->nbytes; } B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,totbytes); if (len > 0) { nxt = (B_bytearray)lst->data[0]; unsigned char *p = res->str; memcpy(p,nxt->str,nxt->nbytes); p += nxt->nbytes; for (int i=1; idata[i]; memcpy(p,s->str,s->nbytes); p += s->nbytes; memcpy(p,nxt->str,nxt->nbytes); p += nxt->nbytes; } } return res; } B_bytearray B_bytearrayD_ljust(B_bytearray s, B_int width, B_bytearray fill) { if (!fill) fill = space_bytearray; int wval = fromB_int(width); if (fill->nbytes != 1) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("bytearray ljust: fill array not single char"))); } if (wval <= s->nbytes) { return B_bytearrayD_copy(s); } B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,wval); memcpy(res->str,s->str,s->nbytes); unsigned char c = fill->str[0]; for (int i = s->nbytes; istr[i] = c; } return res; } B_bytearray B_bytearrayD_lower(B_bytearray s) { B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,s->nbytes); for (int i=0; i< s->nbytes; i++) res->str[i] = tolower(res->str[i]); return res; } B_bytearray B_bytearrayD_lstrip(B_bytearray s, B_bytearray cs) { if (!cs) cs = whitespace_bytearray; int nstrip = 0; for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; int found = 0; for (int j=0; jnbytes; j++) if (c == cs->str[j]) { found = 1; break; } if (!found) break; nstrip++; } B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,s->nbytes-nstrip); memcpy(res->str,s->str+nstrip,res->nbytes); return res; } B_tuple B_bytearrayD_partition(B_bytearray s, B_bytearray sep) { int n = fromB_int(B_bytearrayD_find(s,sep,NULL,NULL)); if (n<0) { return $NEWTUPLE(3,s,toB_bytearray(""),toB_bytearray("")); } else { int nb = bmh(s->str,sep->str,s->nbytes,sep->nbytes); B_bytearray ls; NEW_UNFILLED_BYTEARRAY(ls,nb); memcpy(ls->str,s->str,nb); B_bytearray rs; int nbr = s->nbytes - sep->nbytes - nb; NEW_UNFILLED_BYTEARRAY(rs,nbr); memcpy(rs->str,s->str+nb+sep->nbytes,nbr); return $NEWTUPLE(3,ls,sep,rs); } } B_bytearray B_bytearrayD_replace(B_bytearray s, B_bytearray old, B_bytearray new, B_int count) { if (count==NULL) count = toB_int(INT_MAX); int c = fromB_int(B_bytearrayD_count(s,old,NULL,NULL)); int c0 = fromB_int(count) < c ? fromB_int(count) : c; if (c0==0){ return B_bytearrayD_copy(s); } int nbytes = s->nbytes + c0*(new->nbytes-old->nbytes); B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,nbytes); unsigned char *p = s->str; unsigned char *q = res->str; unsigned char *pold = old->str; unsigned char *pnew = new->str; int plen = s->nbytes; int n; for (int i=0; i0 && old->nbytes==0 ? 1 : bmh(p,pold,plen,old->nbytes); if (n>0) { memcpy(q,p,n); p+=n; q+=n; } memcpy(q,pnew,new->nbytes); p += old->nbytes; q += new->nbytes; plen -= n+old->nbytes; } if (plen>0) memcpy(q,p,plen); return res; } B_int B_bytearrayD_rfind(B_bytearray s, B_bytearray sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nbytes,&st,&en) < 0) return toB_int(-1); unsigned char *p = &s->str[fromB_int(st)]; unsigned char *q = &s->str[fromB_int(en)]; int n = rbmh(p,sub->str,q-p,sub->nbytes); if (n<0) return toB_int(-1); return toB_int(n+p-s->str); } B_int B_bytearrayD_rindex(B_bytearray s, B_bytearray sub, B_int start, B_int end) { B_int n = B_bytearrayD_rfind(s,sub,start,end); if (fromB_int(n)<0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("rindex for bytearray: substring not found"))); }; return n; } B_bytearray B_bytearrayD_rjust(B_bytearray s, B_int width, B_bytearray fill) { if (!fill) fill = space_bytearray; int wval = fromB_int(width); if (fill->nbytes != 1) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("rjust: fill string not single char"))); } if (wval <= s->nbytes) { return B_bytearrayD_copy(s); } int pad = (wval-s->nbytes); B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,wval); unsigned char c = fill->str[0]; for (int i = 0; istr[i] = c; } memcpy(&res->str[pad],s->str,s->nbytes); return res; } B_tuple B_bytearrayD_rpartition(B_bytearray s, B_bytearray sep) { int n = fromB_int(B_bytearrayD_rfind(s,sep,NULL,NULL)); if (n<0) { return $NEWTUPLE(3,toB_bytearray(""),toB_bytearray(""),s); } else { int nb = rbmh(s->str,sep->str,s->nbytes,sep->nbytes); B_bytearray ls; NEW_UNFILLED_BYTEARRAY(ls,nb); memcpy(ls->str,s->str,nb); int nbr = s->nbytes - sep->nbytes - nb; B_bytearray rs; NEW_UNFILLED_BYTEARRAY(rs,nbr); memcpy(rs->str,s->str+nb+sep->nbytes,nbr); return $NEWTUPLE(3,ls,sep,rs); } } B_bytearray B_bytearrayD_rstrip(B_bytearray s, B_bytearray cs) { if (!cs) cs = whitespace_bytearray; int nstrip = 0; for (int i=s->nbytes-1; i>=0; i--) { unsigned char c = s->str[i]; int found = 0; for (int j=0; jnbytes; j++) if (c == cs->str[j]) { found = 1; break; } if (!found) break; nstrip++; } B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,s->nbytes-nstrip); memcpy(res->str,s->str,res->nbytes); return res; } B_list B_bytearrayD_split(B_bytearray s, B_bytearray sep, B_int maxsplit) { B_list res = $NEW(B_list,NULL,NULL); B_SequenceD_list wit = B_SequenceD_listG_witness; if (maxsplit == NULL || fromB_int(maxsplit) < 0) maxsplit = toB_int(INT_MAX); if (sep == NULL) { unsigned char *p = s->str; if (s->nbytes==0) { return res; } int inword = 0; unsigned char *q; while (p < s->str + s->nbytes) { if (*p !=' ' && *p != '\t' && *p != '\n' && *p != '\r' && *p != '\x0b' && *p != '\f') { if (!inword) { inword = 1; q = p; if (res->length == fromB_int(maxsplit)) break; // we have now removed leading whitespace in remainder } } else { if (inword) { inword = 0; B_bytearray word; NEW_UNFILLED_BYTEARRAY(word,p-q); memcpy(word->str,q,p-q); wit->$class->append(wit,res,word); } } p++; } // this if statement should be simplified; almost code duplication. if (p < s->str + s->nbytes) { // we did not break out of the while loop if (inword) { B_bytearray word; NEW_UNFILLED_BYTEARRAY(word,p-q); memcpy(word->str,q,p-q); wit->$class->append(wit,res,word); } } else { B_bytearray word; p = s->str+s->nbytes; NEW_UNFILLED_BYTEARRAY(word,p-q); memcpy(word->str,q,p-q); wit->$class->append(wit,res,word); } return res; } else { // separator given if (sep->nbytes==0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("split for bytearray: separator is empty string"))); } if (s->nbytes==0) { // for some unfathomable reason, this is the behaviour of the Python method wit->$class->append(wit,res,toB_bytearray("")); return res; } B_bytearray ls, rs, ssep; rs = s; // Note: This builds many intermediate rs strings... while (rs->nbytes>0 && res->length < fromB_int(maxsplit)) { B_tuple t = B_bytearrayD_partition(rs,sep); ssep = (B_bytearray)t->components[1]; rs = (B_bytearray)t->components[2]; wit->$class->append(wit,res,(B_bytearray)t->components[0]); } if (ssep->nbytes>0) wit->$class->append(wit,res,rs); return res; } } B_list B_bytearrayD_splitlines(B_bytearray s, B_bool keepends) { if (!keepends) keepends = B_False; B_SequenceD_list wit = B_SequenceD_listG_witness; B_list res = $NEW(B_list,NULL,NULL); if (s->nbytes==0) { return res; } int winend; unsigned char *p = s->str; unsigned char *q = p; while (p < s->str + s->nbytes) { if (*p != '\n' && *p != '\r') { p++; } else { B_bytearray line; winend = *p=='\r' && *(p+1)=='\n'; int size = p-q + (keepends->val ? 1 + winend : 0); NEW_UNFILLED_BYTEARRAY(line,size); memcpy(line->str,q,size); p+= 1 + winend; q = p; wit->$class->append(wit,res,line); } } if (q < p) { B_bytearray line; NEW_UNFILLED_BYTEARRAY(line,p-q); memcpy(line->str,q,p-q); wit->$class->append(wit,res,line); } return res; } B_bool B_bytearrayD_startswith(B_bytearray s, B_bytearray sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nbytes,&st,&en) < 0) return B_False; unsigned char *p = s->str + fromB_int(st); if (sub->nbytes > 0 && p+sub->nbytes > s->str+s->nbytes) return B_False; unsigned char *q = sub->str; for (int i=0; inbytes; i++) { if (p >= s->str + fromB_int(en) || *p++ != *q++) { return B_False; } } return B_True; } B_bytearray B_bytearrayD_strip(B_bytearray s, B_bytearray cs) { return B_bytearrayD_lstrip(B_bytearrayD_rstrip(s,cs),cs); } B_bytearray B_bytearrayD_upper(B_bytearray s) { B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,s->nbytes); for (int i=0; i< s->nbytes; i++) res->str[i] = toupper(res->str[i]); return res; } B_bytearray B_bytearrayD_zfill(B_bytearray s, B_int width) { int wval = fromB_int(width); int fill = wval - s->nbytes; if (fill < 0) return B_bytearrayD_copy(s); B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,wval); unsigned char *p = s->str; unsigned char *q = res->str; int hassign = (*p=='+' | *p=='-'); if (hassign) { *q = *p; q++; } for (int i=0; i < fill; i++) *q++ = '0'; memcpy(res->str+hassign+fill,s->str+hassign,s->nbytes-hassign); return res; } // Ord B_bool B_OrdD_bytearrayD___eq__ (B_OrdD_bytearray wit, B_bytearray a, B_bytearray b) { return toB_bool(strcmp((char *)a->str,(char *)b->str)==0); } B_bool B_OrdD_bytearrayD___ne__ (B_OrdD_bytearray wit, B_bytearray a, B_bytearray b) { return toB_bool(strcmp((char *)a->str,(char *)b->str)!=0); } B_bool B_OrdD_bytearrayD___lt__ (B_OrdD_bytearray wit, B_bytearray a, B_bytearray b) { return toB_bool(strcmp((char *)a->str,(char *)b->str)<0); } B_bool B_OrdD_bytearrayD___le__ (B_OrdD_bytearray wit, B_bytearray a, B_bytearray b){ return toB_bool(strcmp((char *)a->str,(char *)b->str)<=0); } B_bool B_OrdD_bytearrayD___gt__ (B_OrdD_bytearray wit, B_bytearray a, B_bytearray b){ return toB_bool(strcmp((char *)a->str,(char *)b->str)>0); } B_bool B_OrdD_bytearrayD___ge__ (B_OrdD_bytearray wit, B_bytearray a, B_bytearray b){ return toB_bool(strcmp((char *)a->str,(char *)b->str)>=0); } // Container // Iterable static B_int B_IteratorB_bytearrayD_next(B_IteratorB_bytearray self) { if (self->nxt >= self->src->nbytes) $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("bytearray iterator terminated"))); return toB_int(self->src->str[self->nxt++]); } B_NoneType B_IteratorB_bytearrayD_init(B_IteratorB_bytearray self, B_bytearray b) { self->src = b; self->nxt = 0; return B_None; } B_bool B_IteratorB_bytearrayD_bool(B_IteratorB_bytearray self) { return B_True; } B_str B_IteratorB_bytearrayD_str(B_IteratorB_bytearray self) { return $FORMAT("", self); } void B_IteratorB_bytearrayD_serialize(B_IteratorB_bytearray self,$Serial$state state) { $step_serialize(self->src,state); $step_serialize(toB_int(self->nxt),state); } B_IteratorB_bytearray B_IteratorB_bytearray$_deserialize(B_IteratorB_bytearray res, $Serial$state state) { if(!res) res = $DNEW(B_IteratorB_bytearray,state); res->src = (B_bytearray)$step_deserialize(state); res->nxt = fromB_int((B_int)$step_deserialize(state)); return res; } struct B_IteratorB_bytearrayG_class B_IteratorB_bytearrayG_methods = { "", UNASSIGNED, ($SuperG_class)&B_IteratorG_methods, B_IteratorB_bytearrayD_init, B_IteratorB_bytearrayD_serialize, B_IteratorB_bytearray$_deserialize, B_IteratorB_bytearrayD_bool, B_IteratorB_bytearrayD_str, B_IteratorB_bytearrayD_str, B_IteratorB_bytearrayD_next }; B_Iterator B_ContainerD_bytearrayD___iter__ (B_ContainerD_bytearray wit, B_bytearray str) { return (B_Iterator)$NEW(B_IteratorB_bytearray,str); } B_bytearray B_ContainerD_bytearrayD___fromiter__ (B_ContainerD_bytearray wit, B_Iterable wit2, $WORD iter) { return B_bytearrayD_join(toB_bytearray(""),wit2,iter); } B_int B_ContainerD_bytearrayD___len__ (B_ContainerD_bytearray wit, B_bytearray str) { return toB_int(str->nbytes); } B_bool B_ContainerD_bytearrayD___contains__(B_ContainerD_bytearray wit, B_bytearray self, B_int n) { long res = 0; for (int i=0; i < self->nbytes; i++) { if (self->str[i] == (unsigned char)fromB_int(n)) { res = 1; break; } } return toB_bool(res); } B_bool B_ContainerD_bytearrayD___containsnot__(B_ContainerD_bytearray wit, B_bytearray self, B_int n) { return toB_bool(!B_ContainerD_bytearrayD___contains__(wit,self,n)->val); } // Sequence B_int B_SequenceD_bytearrayD___getitem__ (B_SequenceD_bytearray wit, B_bytearray self, B_int n) { int64_t ix = fromB_int(n); int64_t ix0 = ix < 0 ? self->nbytes + ix : ix; if (ix0<0 || ix0 >= self->nbytes) $RAISE((B_BaseException)$NEW(B_IndexError, toB_int(ix0), to$str("getitem: index outside bytearray"))); return toB_int((long)self->str[ix0]); } B_NoneType B_SequenceD_bytearrayD___setitem__ (B_SequenceD_bytearray wit, B_bytearray self, B_int n, B_int v) { int64_t ix = fromB_int(n); int64_t ix0 = ix < 0 ? self->nbytes + ix : ix; long val = fromB_int(v); if (ix0<0 || ix0 >= self->nbytes) $RAISE((B_BaseException)$NEW(B_IndexError, toB_int(ix0), to$str("setitem: index outside bytearray"))); if (val<0 || val>255) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("setitem for bytearray: value outside [0..255]"))); self->str[ix0] = (unsigned char)val; return B_None; } B_NoneType B_SequenceD_bytearrayD___delitem__ (B_SequenceD_bytearray wit, B_bytearray self, B_int n) { int64_t ix = fromB_int(n); int64_t ix0 = ix < 0 ? self->nbytes + ix : ix; int len = self->nbytes; if (ix0 < 0 || ix0 >= len) $RAISE((B_BaseException)$NEW(B_IndexError, toB_int(ix0), to$str("delitem: index outside bytearray"))); memmove(self->str + ix0,self->str + (ix0 + 1),len-(ix0+1)); self->nbytes--; return B_None; } B_NoneType B_SequenceD_bytearrayD_insert(B_SequenceD_bytearray wit, B_bytearray self, B_int n, B_int elem) { long ix = fromB_int(n); int len = self->nbytes; expand_bytearray(self,1); int ix0 = ix < 0 ? (len+ix < 0 ? 0 : len+ix) : (ix < len ? ix : len); memmove(self->str + (ix0 + 1), self->str + ix0 , len - ix0 + 1); // +1 to move also terminating '\0' self->str[ix0] = (unsigned char)fromB_int(elem) & 0xff; self->nbytes++; return B_None; } B_NoneType B_SequenceD_bytearrayD_append(B_SequenceD_bytearray wit, B_bytearray self, B_int elem) { expand_bytearray(self,1); self->str[self->nbytes++] = (unsigned char)fromB_int(elem) & 0xff; self->str[self->nbytes] = '\0'; return B_None; } B_NoneType B_SequenceD_bytearrayD_reverse(B_SequenceD_bytearray wit, B_bytearray self) { int len = self->nbytes; for (int i = 0; i < len/2; i++) { unsigned char tmp = self->str[i]; self->str[i] = self->str[len-1-i]; self->str[len-1-i] = tmp; } return B_None; } B_Iterator B_SequenceD_bytearrayD___reversed__(B_SequenceD_bytearray wit, B_bytearray self) { B_bytearray copy = B_bytearrayD_copy(self); B_SequenceD_bytearrayD_reverse(wit,copy); return B_ContainerD_bytearrayD___iter__ (NULL, copy); } B_bytearray B_SequenceD_bytearrayD___getslice__ (B_SequenceD_bytearray wit, B_bytearray self, B_slice slc) { int len = self->nbytes; int64_t start, stop, step, slen; normalize_slice(slc, len, &slen, &start, &stop, &step); B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,slen); long t = start; for (int i=0; i$class->__iter__(wit2,iter); int len = self->nbytes; B_bytearray other; NEW_UNFILLED_BYTEARRAY(other,0); $WORD w; while ((w=it->$class->__next__(it))) B_SequenceD_bytearrayD_append(wit, other,(B_int)w); int olen = other->nbytes; int64_t start, stop, step, slen; normalize_slice(slc, len, &slen, &start, &stop, &step); if (step != 1 && olen != slen) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("setslice for bytearray: illegal slice"))); } int copy = olen <= slen ? olen : slen; int t = start; for (int i= 0; istr[t] = other->str[i]; t += step; } if (olen == slen) return B_None; // now we know that step=1 if (olen < slen) { memmove(self->str + start + copy, self->str + start + slen, len-(start+slen)); self->nbytes-=slen-olen; return B_None; } else { expand_bytearray(self,olen-slen); int rest = len - (start+copy); int incr = olen - slen; memmove(self->str + start + copy + incr, self->str + start + copy, rest); for (int i = copy; i < olen; i++) self->str[start+i] = other->str[i]; self->nbytes += incr; } return B_None; } B_NoneType B_SequenceD_bytearrayD___delslice__ (B_SequenceD_bytearray wit, B_bytearray self, B_slice slc) { int len = self->nbytes; int64_t start, stop, step, slen; normalize_slice(slc, len, &slen, &start, &stop, &step); if (slen==0) return B_None; unsigned char *p = self->str + start; for (int i=0; inbytes-=slen; self->str[self->nbytes] = '\0'; return B_None; } // Collection B_Iterator B_CollectionD_SequenceD_bytearrayD___iter__ (B_CollectionD_SequenceD_bytearray wit, B_bytearray str) { return (B_Iterator)$NEW(B_IteratorB_bytearray,str); } B_bytearray B_CollectionD_SequenceD_bytearrayD___fromiter__ (B_CollectionD_SequenceD_bytearray wit, B_Iterable wit2, $WORD iter) { return B_bytearrayD_join(toB_bytearray(""),wit2,iter); } B_int B_CollectionD_SequenceD_bytearrayD___len__ (B_CollectionD_SequenceD_bytearray wit, B_bytearray str) { return toB_int(str->nbytes); } // Times B_bytearray B_TimesD_SequenceD_bytearrayD___add__ (B_TimesD_SequenceD_bytearray wit, B_bytearray a, B_bytearray b) { B_bytearray res; NEW_UNFILLED_BYTEARRAY(res,a->nbytes+b->nbytes); memcpy(res->str,a->str,a->nbytes); memcpy(res->str+a->nbytes,b->str,b->nbytes); return res; } B_bytearray B_TimesD_SequenceD_bytearrayD___zero__ (B_TimesD_SequenceD_bytearray wit) { return toB_bytearray(""); } B_bytearray B_TimesD_SequenceD_bytearrayD___mul__ (B_TimesD_SequenceD_bytearray wit, B_bytearray a, B_int n) { int nval = fromB_int(n); if (nval <= 0) return toB_bytearray(""); else { B_bytearray res; NEW_UNFILLED_BYTEARRAY(res, a->nbytes * nval); for (int i=0; istr + i*a->nbytes,a->str,a->nbytes); return res; } } // End of bytearray implementation //////////////////////////////////////////////// // bytes implementation /////////////////////////////////////////////////////////// // Conversion to and from C strings B_bytes to$bytes(char *str) { B_bytes res; int len = strlen(str); NEW_UNFILLED_BYTES(res,len); memcpy(res->str,str,len); return res; } B_bytes to$bytesD_len(char *str, int len) { B_bytes res; NEW_UNFILLED_BYTES(res, len); memcpy(res->str, str, len); return res; } B_bytes actBytesFromCString(char *str) { B_bytes res; int len = strlen(str); NEW_UNFILLED_BYTES(res,len); memcpy(res->str,str,len); return res; } B_bytes actBytesFromCStringNoCopy(char *str) { B_bytes res = acton_malloc(sizeof(struct B_bytes)); res->$class = &B_bytesG_methods; res->nbytes = strlen(str); res->str = (unsigned char*)str; return res; } B_bytes actBytesFromCStringLength(char *str, int len) { B_bytes res; NEW_UNFILLED_BYTES(res, len); memcpy(res->str, str, len); return res; } B_bytes actBytesFromCStringLengthNoCopy(char *str, int length) { B_bytes res = acton_malloc(sizeof(struct B_bytes)); res->$class = &B_bytesG_methods; res->nbytes = length; res->str = (unsigned char*)str; return res; } unsigned char *fromB_bytes(B_bytes b) { return b->str; } // Auxiliaries static B_bytes B_bytesD_copy(B_bytes s) { B_bytes res; NEW_UNFILLED_BYTES(res,s->nbytes); res->nbytes = s->nbytes; memcpy(res->str,s->str,s->nbytes); return res; } // Bytes methods, implementations // General methods ////////////////////////////////////////////////////////////// B_bytes B_bytesG_new(B_Iterable iter, $WORD wit) { return $NEW(B_bytes, iter, wit); } B_NoneType B_bytesD___init__(B_bytes self, B_Iterable wit, $WORD iter) { B_CollectionD_SequenceD_list wit2 = B_CollectionD_SequenceD_listG_witness; B_list lst = wit2->$class->__fromiter__(wit2,wit,iter); int len = lst->length; self->nbytes = len; self->str = acton_malloc_atomic(len+1); self->str[len] = 0; for (int i=0; i< len; i++) { int n = fromB_int((B_int)lst->data[i]); if (0<=n && n <= 255) self->str[i] = n; else $RAISE((B_BaseException)$NEW(B_ValueError,to$str("bytes constructor: element outside [0..255]"))); } return B_None; } B_bool B_bytesD___bool__(B_bytes s) { return toB_bool(s->nbytes > 0); }; B_str B_bytesD___str__(B_bytes s) { struct byte_counts bs = byte_count(s->str, s->nbytes); bool use_single_quotes = !(bs.dquotes==0 && bs.squotes>0); int escaped_quotes = use_single_quotes ? bs.dquotes : bs.squotes; int newbytes = 3+bs.escaped+3*bs.non_printable+escaped_quotes+3*bs.non_ascii; B_str res; int nbytes = s->nbytes+newbytes; NEW_UNFILLED_STR(res,nbytes,nbytes); escape_str(res->str+2,s->str,res->nbytes-2,s->nbytes,255,!use_single_quotes,use_single_quotes,false,false); if (use_single_quotes) { res->str[1] = '\''; res->str[res->nbytes-1] = '\''; } else { res->str[1] = '"'; res->str[res->nbytes-1] = '"'; } res->str[0] = 'b'; return res; } B_str B_bytesD___repr__(B_bytes s) { return B_bytesD___str__(s); } void B_bytesD___serialize__(B_bytes str,$Serial$state state) { int nWords = str->nbytes/sizeof($WORD) + 1; // # $WORDS needed to store str->str, including terminating 0. $ROW row = $add_header(STR_ID,1+nWords,state); long nbytes = (long)str->nbytes; memcpy(row->blob,&nbytes,sizeof($WORD)); memcpy(row->blob+1,str->str,nbytes+1); } B_bytes B_bytesD___deserialize__(B_bytes self, $Serial$state state) { $ROW this = state->row; state->row =this->next; state->row_no++; B_bytes res = acton_malloc(sizeof(struct B_bytes)); long nbytes; memcpy(&nbytes,this->blob,sizeof($WORD)); res->$class = &B_bytesG_methods; res->nbytes = (long)nbytes; res->str = acton_malloc_atomic(nbytes+1); memcpy(res->str,this->blob+2,nbytes+1); return res; } B_bytes B_bytesD_capitalize(B_bytes s) { if (s->nbytes==0) { return s; } B_bytes res; NEW_UNFILLED_BYTES(res,s->nbytes); res->str[0] = toupper(s->str[0]); for (int i = 1; i < s->nbytes; i++) res->str[i] = tolower(s->str[i]); return res; } B_bytes B_bytesD_center(B_bytes s, B_int width, B_bytes fill) { int wval = fromB_int(width); if (!fill) fill = to$bytes(" "); if (fill->nbytes != 1) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("center: fill bytes not single char"))); } if (wval <= s->nbytes) { return s; } int pad = (wval-s->nbytes); int padleft = pad/2; int padright = pad-padleft; int sbytes = s->nbytes; B_bytes res; NEW_UNFILLED_BYTES(res, wval); unsigned char c = fill->str[0]; unsigned char *p = res->str; p += padleft+sbytes; for (int i = 0; istr,p,padleft); p -= sbytes; memcpy(p,s->str,sbytes); return res; } B_int B_bytesD_count(B_bytes s, B_bytes sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nbytes,&st,&en) < 0) return toB_int(0); int stval = fromB_int(st); unsigned char *p = &s->str[stval]; unsigned char *q = &p[fromB_int(en)-stval]; int res = 0; int n = bmh(p,sub->str,q-p,sub->nbytes); while (n>=0) { res++; p += n + (sub->nbytes>0 ? sub->nbytes : 1); n = bmh(p,sub->str,q-p,sub->nbytes); } return toB_int(res); } B_str B_bytesD_decode(B_bytes s) { return to$str((char*)s->str); } B_bool B_bytesD_endswith(B_bytes s, B_bytes sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nbytes,&st,&en) < 0) return B_False; unsigned char *p = &s->str[fromB_int(en)-sub->nbytes]; unsigned char *q = sub->str; for (int i=0; inbytes; i++) { if (*p == 0 || *p++ != *q++) { return B_False; } } return B_True; } B_bytes B_bytesD_expandtabs(B_bytes s, B_int tabsz){ if (s->nbytes == 0) { return null_bytes; } int pos = 0; int expanded = 0; int tabsize = fromB_int(tabsz); tabsize = tabsize <= 0 ? 1 : tabsize; unsigned char buffer[tabsize * s->nbytes]; unsigned char *p = s->str; unsigned char *q = buffer; for (int i=0; inbytes; i++) { if (*p == '\t') { int n = tabsize - pos % tabsize; for (int j=0; j < n; j++) { *q++ = ' '; } p++; expanded += n-1; pos+=n; } else if (*p=='\n' || *p == '\r') { *q++ = *p++; pos = 0; } else { for (int j=0; j< byte_length2(*p); j++) { *q++ = *p++; pos++; } } } B_bytes res; NEW_UNFILLED_BYTES(res,s->nbytes+expanded); memcpy(res->str,buffer,s->nbytes+expanded); return res; } B_int B_bytesD_find(B_bytes s, B_bytes sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nbytes,&st,&en) < 0) return toB_int(-1); unsigned char *p = &s->str[fromB_int(st)]; unsigned char *q = &s->str[fromB_int(en)]; int n = bmh(p,sub->str,q-p,sub->nbytes); if (n<0) return toB_int(-1); return toB_int(n+p-s->str); } B_bytes B_bytesD_from_hex(B_str s) { if (s->nbytes == 0) return null_bytes; // Each byte is represented by 2 hex chars int strlen = s->nbytes; // Changed from len to nbytes if (strlen % 2 != 0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("from_hex: hex string must have even length"))); } int bytelen = strlen / 2; char *result = acton_malloc_atomic(bytelen); for (int i = 0; i < strlen; i += 2) { char high = s->str[i]; char low = s->str[i + 1]; // Convert hex chars to values 0-15 int high_val, low_val; // Handle high nibble if (high >= '0' && high <= '9') high_val = high - '0'; else if (high >= 'a' && high <= 'f') high_val = high - 'a' + 10; else if (high >= 'A' && high <= 'F') high_val = high - 'A' + 10; else { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("from_hex: invalid hex character"))); } // Handle low nibble if (low >= '0' && low <= '9') low_val = low - '0'; else if (low >= 'a' && low <= 'f') low_val = low - 'a' + 10; else if (low >= 'A' && low <= 'F') low_val = low - 'A' + 10; else { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("from_hex: invalid hex character"))); } // Combine into byte result[i/2] = (high_val << 4) | low_val; } return actBytesFromCStringLengthNoCopy(result, bytelen); } B_str B_bytesD_hex(B_bytes s) { if (s->nbytes == 0) return null_str; // Each byte becomes 2 hex chars, so output length is 2 * number of bytes int len = s->nbytes * 2; char *result = acton_malloc_atomic(len); // Hex digit lookup table const char hex_digits[] = "0123456789abcdef"; // Convert each byte to two hex digits for (int i = 0; i < s->nbytes; i++) { unsigned char byte = s->str[i]; result[i*2] = hex_digits[byte >> 4]; // High nibble result[i*2 + 1] = hex_digits[byte & 0xf]; // Low nibble } // Convert to Acton string without copying return to_str_noc(result); } B_int B_bytesD_index(B_bytes s, B_bytes sub, B_int start, B_int end) { B_int n = B_bytesD_find(s,sub,start,end); if (fromB_int(n)<0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("index: substring not found"))); } return n; } B_bool B_bytesD_isalnum(B_bytes s) { if (s->nbytes==0) return B_False; for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; if (c < '0' || c > 'z' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a')) return B_False; } return B_True; } B_bool B_bytesD_isalpha(B_bytes s) { if (s->nbytes==0) return B_False; for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; if (c < 'A' || c > 'z' || (c > 'Z' && c < 'a')) return B_False; } return B_True; } B_bool B_bytesD_isascii(B_bytes s) { for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; if (c > 0x7f) return B_False; } return B_True; } B_bool B_bytesD_isdigit(B_bytes s) { if (s->nbytes==0) return B_False; for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; if (c<'0' || c > '9') return B_False; } return B_True; } B_bool B_bytesD_islower(B_bytes s) { int has_lower = 0; for (int i=0; i < s->nbytes; i++) { unsigned char c = s->str[i]; if (c >= 'A' && c <= 'Z') return B_False; if (c >= 'a' && c <= 'z') has_lower = 1; } return toB_bool(has_lower); } B_bool B_bytesD_isspace(B_bytes s) { if (s->nbytes==0) return B_False; for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; if (c !=' ' && c != '\t' && c != '\n' && c != '\r' && c != '\x0b' && c != '\f') return B_False; } return B_True; } B_bool B_bytesD_istitle(B_bytes s) { if (s->nbytes==0) return B_False; int incasedrun = 0; for (int i=0; i < s->nbytes; i++) { unsigned char c = s->str[i]; if (c >='A' && c <= 'Z') { if (incasedrun) return B_False; incasedrun = 1; } else if (c >='a' && c <= 'z') { if (!incasedrun) return B_False; } else incasedrun = 0; } return B_True; } B_bool B_bytesD_isupper(B_bytes s) { int has_upper = 0; for (int i=0; i < s->nbytes; i++) { unsigned char c = s->str[i]; if (c >= 'a' && c <= 'z') return B_False; if (c >= 'a' && c <= 'z') has_upper = 1; } return toB_bool(has_upper); } B_bytes B_bytesD_join(B_bytes s, B_Iterable wit, $WORD iter) { int totbytes = 0; B_CollectionD_SequenceD_list wit2 = B_CollectionD_SequenceD_listG_witness; B_list lst = wit2->$class->__fromiter__(wit2,wit,iter); B_bytes nxt; int len = lst->length; for (int i=0; idata[i]; totbytes += nxt->nbytes; } if (len > 1) { totbytes += (len-1) * s->nbytes; } B_bytes res; NEW_UNFILLED_BYTES(res,totbytes); if (len > 0) { nxt = (B_bytes)lst->data[0]; unsigned char *p = res->str; memcpy(p,nxt->str,nxt->nbytes); p += nxt->nbytes; for (int i=1; idata[i]; memcpy(p,s->str,s->nbytes); p += s->nbytes; memcpy(p,nxt->str,nxt->nbytes); p += nxt->nbytes; } } return res; } B_bytes B_bytesD_ljust(B_bytes s, B_int width, B_bytes fill) { if (!fill) fill = space_bytes; int wval = fromB_int(width); if (fill->nbytes != 1) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("bytes ljust: fill array not single char"))); } if (wval <= s->nbytes) { return B_bytesD_copy(s); } B_bytes res; NEW_UNFILLED_BYTES(res,wval); memcpy(res->str,s->str,s->nbytes); unsigned char c = fill->str[0]; for (int i = s->nbytes; istr[i] = c; } return res; } B_bytes B_bytesD_lower(B_bytes s) { B_bytes res; NEW_UNFILLED_BYTES(res,s->nbytes); for (int i=0; i< s->nbytes; i++) res->str[i] = tolower(res->str[i]); return res; } B_bytes B_bytesD_lstrip(B_bytes s, B_bytes cs) { if (!cs) cs = whitespace_bytes; int nstrip = 0; for (int i=0; inbytes; i++) { unsigned char c = s->str[i]; int found = 0; for (int j=0; jnbytes; j++) if (c == cs->str[j]) { found = 1; break; } if (!found) break; nstrip++; } B_bytes res; NEW_UNFILLED_BYTES(res,s->nbytes-nstrip); memcpy(res->str,s->str+nstrip,res->nbytes); return res; } B_tuple B_bytesD_partition(B_bytes s, B_bytes sep) { int n = fromB_int(B_bytesD_find(s,sep,NULL,NULL)); if (n<0) { return $NEWTUPLE(3,s,to$bytes(""),to$bytes("")); } else { int nb = bmh(s->str,sep->str,s->nbytes,sep->nbytes); B_bytes ls; NEW_UNFILLED_BYTES(ls,nb); memcpy(ls->str,s->str,nb); B_bytes rs; int nbr = s->nbytes - sep->nbytes - nb; NEW_UNFILLED_BYTES(rs,nbr); memcpy(rs->str,s->str+nb+sep->nbytes,nbr); return $NEWTUPLE(3,ls,sep,rs); } } B_bytes B_bytesD_removeprefix(B_bytes s, B_bytes prefix) { int bytes_to_remove; if (prefix->nbytes > s->nbytes || memcmp(s->str,prefix->str,prefix->nbytes)) bytes_to_remove = 0; else bytes_to_remove = prefix->nbytes; B_bytes res; int resbytes = s->nbytes - bytes_to_remove; NEW_UNFILLED_BYTES(res,resbytes); memcpy(res->str,s->str+bytes_to_remove,resbytes); return res; } B_bytes B_bytesD_removesuffix(B_bytes s, B_bytes suffix) { int bytes_to_remove; if (suffix->nbytes > s->nbytes || memcmp(s->str+s->nbytes-suffix->nbytes,suffix->str,suffix->nbytes)) bytes_to_remove = 0; else bytes_to_remove = suffix->nbytes; B_bytes res; int resbytes = s->nbytes - bytes_to_remove; NEW_UNFILLED_BYTES(res,resbytes); memcpy(res->str,s->str,resbytes); return res; } B_bytes B_bytesD_replace(B_bytes s, B_bytes old, B_bytes new, B_int count) { if (count==NULL) count = toB_int(INT_MAX); int c = fromB_int(B_bytesD_count(s,old,NULL,NULL)); int c0 = fromB_int(count) < c ? fromB_int(count) : c; if (c0==0){ return B_bytesD_copy(s); } int nbytes = s->nbytes + c0*(new->nbytes-old->nbytes); B_bytes res; NEW_UNFILLED_BYTES(res,nbytes); unsigned char *p = s->str; unsigned char *q = res->str; unsigned char *pold = old->str; unsigned char *pnew = new->str; int plen = s->nbytes; int n; for (int i=0; i0 && old->nbytes==0 ? 1 : bmh(p,pold,plen,old->nbytes); if (n>0) { memcpy(q,p,n); p+=n; q+=n; } memcpy(q,pnew,new->nbytes); p += old->nbytes; q += new->nbytes; plen -= n+old->nbytes; } if (plen>0) memcpy(q,p,plen); return res; } B_int B_bytesD_rfind(B_bytes s, B_bytes sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nbytes,&st,&en) < 0) return toB_int(-1); unsigned char *p = &s->str[fromB_int(st)]; unsigned char *q = &s->str[fromB_int(en)]; int n = rbmh(p,sub->str,q-p,sub->nbytes); if (n<0) return toB_int(-1); return toB_int(n+p-s->str); } B_int B_bytesD_rindex(B_bytes s, B_bytes sub, B_int start, B_int end) { B_int n = B_bytesD_rfind(s,sub,start,end); if (fromB_int(n)<0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("rindex for bytes: substring not found"))); }; return n; } B_bytes B_bytesD_rjust(B_bytes s, B_int width, B_bytes fill) { if (!fill) fill = space_bytes; if (fill->nbytes != 1) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("rjust: fill string not single char"))); } int wval = fromB_int(width); if (wval <= s->nbytes) { return B_bytesD_copy(s); } int pad = (wval-s->nbytes); B_bytes res; NEW_UNFILLED_BYTES(res,wval); unsigned char c = fill->str[0]; for (int i = 0; istr[i] = c; } memcpy(&res->str[pad],s->str,s->nbytes); return res; } B_tuple B_bytesD_rpartition(B_bytes s, B_bytes sep) { int n = fromB_int(B_bytesD_rfind(s,sep,NULL,NULL)); if (n<0) { return $NEWTUPLE(3,to$bytes(""),to$bytes(""),s); } else { int nb = rbmh(s->str,sep->str,s->nbytes,sep->nbytes); B_bytes ls; NEW_UNFILLED_BYTES(ls,nb); memcpy(ls->str,s->str,nb); int nbr = s->nbytes - sep->nbytes - nb; B_bytes rs; NEW_UNFILLED_BYTES(rs,nbr); memcpy(rs->str,s->str+nb+sep->nbytes,nbr); return $NEWTUPLE(3,ls,sep,rs); } } B_bytes B_bytesD_rstrip(B_bytes s, B_bytes cs) { if (!cs) cs = whitespace_bytes; int nstrip = 0; for (int i=s->nbytes-1; i>=0; i--) { unsigned char c = s->str[i]; int found = 0; for (int j=0; jnbytes; j++) if (c == cs->str[j]) { found = 1; break; } if (!found) break; nstrip++; } B_bytes res; NEW_UNFILLED_BYTES(res,s->nbytes-nstrip); memcpy(res->str,s->str,res->nbytes); return res; } B_list B_bytesD_split(B_bytes s, B_bytes sep, B_int maxsplit) { B_list res = $NEW(B_list,NULL,NULL); B_SequenceD_list wit = B_SequenceD_listG_witness; if (maxsplit == NULL || fromB_int(maxsplit) < 0) maxsplit = toB_int(INT_MAX); if (sep == NULL) { unsigned char *p = s->str; if (s->nbytes==0) { return res; } int inword = 0; unsigned char *q; while (p < s->str + s->nbytes) { if (*p !=' ' && *p != '\t' && *p != '\n' && *p != '\r' && *p != '\x0b' && *p != '\f') { if (!inword) { inword = 1; q = p; if (res->length == fromB_int(maxsplit)) break; // we have now removed leading whitespace in remainder } } else { if (inword) { inword = 0; B_bytes word; NEW_UNFILLED_BYTES(word,p-q); memcpy(word->str,q,p-q); wit->$class->append(wit,res,word); } } p++; } // this if statement should be simplified; almost code duplication. if (p < s->str + s->nbytes) { // we did not break out of the while loop if (inword) { B_bytes word; NEW_UNFILLED_BYTES(word,p-q); memcpy(word->str,q,p-q); wit->$class->append(wit,res,word); } } else { B_bytes word; p = s->str+s->nbytes; NEW_UNFILLED_BYTES(word,p-q); memcpy(word->str,q,p-q); wit->$class->append(wit,res,word); } return res; } else { // separator given if (sep->nbytes==0) { $RAISE((B_BaseException)$NEW(B_ValueError,to$str("split for bytes: separator is empty string"))); } if (s->nbytes==0) { // for some unfathomable reason, this is the behaviour of the Python method wit->$class->append(wit,res,null_bytes); return res; } B_bytes ls, rs, ssep; rs = s; // Note: This builds many intermediate rs strings... while (rs->nbytes>0 && res->length < fromB_int(maxsplit)) { B_tuple t = B_bytesD_partition(rs,sep); ssep = (B_bytes)t->components[1]; rs = (B_bytes)t->components[2]; wit->$class->append(wit,res,(B_bytes)t->components[0]); } if (ssep->nbytes>0) wit->$class->append(wit,res,rs); return res; } } B_list B_bytesD_splitlines(B_bytes s, B_bool keepends) { if (!keepends) keepends = B_False; B_list res = $NEW(B_list,NULL,NULL); B_SequenceD_list wit = B_SequenceD_listG_witness; if (s->nbytes==0) { return res; } int winend; unsigned char *p = s->str; unsigned char *q = p; while (p < s->str + s->nbytes) { if (*p != '\n' && *p != '\r') { p++; } else { B_bytes line; winend = *p=='\r' && *(p+1)=='\n'; int size = p-q + (keepends->val ? 1 + winend : 0); NEW_UNFILLED_BYTES(line,size); memcpy(line->str,q,size); p+= 1 + winend; q = p; wit->$class->append(wit,res,line); } } if (q < p) { B_bytes line; NEW_UNFILLED_BYTES(line,p-q); memcpy(line->str,q,p-q); wit->$class->append(wit,res,line); } return res; } B_bool B_bytesD_startswith(B_bytes s, B_bytes sub, B_int start, B_int end) { B_int st = start; B_int en = end; if (fix_start_end(s->nbytes,&st,&en) < 0) return B_False; unsigned char *p = s->str + fromB_int(st); if (sub->nbytes > 0 && p+sub->nbytes > s->str+s->nbytes) return B_False; unsigned char *q = sub->str; for (int i=0; inbytes; i++) { if (p >= s->str + fromB_int(en) || *p++ != *q++) { return B_False; } } return B_True; } B_bytes B_bytesD_strip(B_bytes s, B_bytes cs) { return B_bytesD_lstrip(B_bytesD_rstrip(s,cs),cs); } B_bytes B_bytesD_upper(B_bytes s) { B_bytes res; NEW_UNFILLED_BYTES(res,s->nbytes); for (int i=0; i< s->nbytes; i++) res->str[i] = toupper(res->str[i]); return res; } B_bytes B_bytesD_zfill(B_bytes s, B_int width) { int wval = fromB_int(width); int fill = wval - s->nbytes; if (fill < 0) return B_bytesD_copy(s); B_bytes res; NEW_UNFILLED_BYTES(res,wval); unsigned char *p = s->str; unsigned char *q = res->str; int hassign = (*p=='+' | *p=='-'); if (hassign) { *q = *p; q++; } for (int i=0; i < fill; i++) *q++ = '0'; memcpy(res->str+hassign+fill,s->str+hassign,s->nbytes-hassign); return res; } // protocol methods /////////////////////////////////////////////////// // Ord B_bool B_OrdD_bytesD___eq__ (B_OrdD_bytes wit, B_bytes a, B_bytes b) { if (a->nbytes != b->nbytes) return B_False; for (int i=0; i < a->nbytes; i++) if (a->str[i] != b->str[i]) return B_False; return B_True; } B_bool B_OrdD_bytesD___ne__ (B_OrdD_bytes wit, B_bytes a, B_bytes b) { return toB_bool(!B_OrdD_bytesD___eq__(wit,a,b)->val); } B_bool B_OrdD_bytesD___lt__ (B_OrdD_bytes wit, B_bytes a, B_bytes b) { int minl = a->nbytesnbytes ? a->nbytes : b->nbytes; int i=0; while (istr[i]==b->str[i]) i++; if (i==a->nbytes) return toB_bool(inbytes); if (i==b->nbytes) return B_False; return toB_bool(a->str[i]str[i]); } B_bool B_OrdD_bytesD___le__ (B_OrdD_bytes wit, B_bytes a, B_bytes b){ return toB_bool(!B_OrdD_bytesD___lt__(wit,b,a)->val); } B_bool B_OrdD_bytesD___gt__ (B_OrdD_bytes wit, B_bytes a, B_bytes b){ return B_OrdD_bytesD___lt__(wit,b,a); } B_bool B_OrdD_bytesD___ge__ (B_OrdD_bytes wit, B_bytes a, B_bytes b){ return toB_bool(!B_OrdD_bytesD___lt__(wit,a,b)->val); } // Container // Iterable /////////////////////////////////////////////////////////////////////////// B_IteratorB_bytes B_IteratorB_bytesG_new(B_bytes str) { return $NEW(B_IteratorB_bytes, str); } B_NoneType B_IteratorB_bytesD_init(B_IteratorB_bytes self, B_bytes str) { self->src = str; self->nxt = 0; return B_None; } void B_IteratorB_bytesD_serialize(B_IteratorB_bytes self,$Serial$state state) { $step_serialize(self->src,state); $step_serialize(toB_int(self->nxt),state); } B_IteratorB_bytes B_IteratorB_bytes$_deserialize(B_IteratorB_bytes res, $Serial$state state) { if (!res) res = $DNEW(B_IteratorB_bytes,state); res->src = (B_bytes)$step_deserialize(state); res->nxt = fromB_int((B_int)$step_deserialize(state)); return res; } B_bool B_IteratorB_bytesD_bool(B_IteratorB_bytes self) { return B_True; } B_str B_IteratorB_bytesD_str(B_IteratorB_bytes self) { return $FORMAT("", self); } // this is next function for forward iteration static B_int B_IteratorB_bytesD_next(B_IteratorB_bytes self) { if (self->nxt >= self->src->nbytes) $RAISE ((B_BaseException)$NEW(B_StopIteration, to$str("bytes iterator terminated"))); return toB_int(self->src->str[self->nxt++]); } struct B_IteratorB_bytesG_class B_IteratorB_bytesG_methods = {"B_IteratorB_bytes",UNASSIGNED,($SuperG_class)&B_IteratorG_methods, B_IteratorB_bytesD_init, B_IteratorB_bytesD_serialize, B_IteratorB_bytes$_deserialize, B_IteratorB_bytesD_bool, B_IteratorB_bytesD_str, B_IteratorB_bytesD_str, B_IteratorB_bytesD_next}; B_Iterator B_ContainerD_bytesD___iter__ (B_ContainerD_bytes wit, B_bytes str) { return (B_Iterator)$NEW(B_IteratorB_bytes,str); } B_bytes B_ContainerD_bytesD___fromiter__ (B_ContainerD_bytes wit, B_Iterable wit2, $WORD iter) { return B_bytesD_join(to$bytes(""),wit2,iter); } B_int B_ContainerD_bytesD___len__ (B_ContainerD_bytes wit, B_bytes str) { return toB_int(str->nbytes); } B_bool B_ContainerD_bytesD___contains__ (B_ContainerD_bytes wit, B_bytes str, B_int n) { long res = 0; for (int i=0; i < str->nbytes; i++) { if (str->str[i] == (unsigned char)fromB_int(n)) { res = 1; break; } } return toB_bool(res); } B_bool B_ContainerD_bytesD___containsnot__ (B_ContainerD_bytes wit, B_bytes str, B_int n) { return toB_bool(!B_ContainerD_bytesD___contains__(wit, str, n)->val); } // Sliceable B_int B_SliceableD_bytesD___getitem__ (B_SliceableD_bytes wit, B_bytes str, B_int n) { long ix = fromB_int(n); long ix0 = ix < 0 ? str->nbytes + ix : ix; if (ix0<0 || ix0 >= str->nbytes) $RAISE((B_BaseException)$NEW(B_IndexError, toB_int(ix0), to$str("getitem: index outside bytesarray"))); return toB_int((long)str->str[ix0]); } B_NoneType B_SliceableD_bytesD___setitem__ (B_SliceableD_bytes wit, B_bytes str, B_int i, B_int val) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method setitem on bytes"))); return B_None; } B_NoneType B_SliceableD_bytesD___delitem__ (B_SliceableD_bytes wit, B_bytes str, B_int i) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method delitem on bytes"))); return B_None; } B_bytes B_SliceableD_bytesD___getslice__ (B_SliceableD_bytes wit, B_bytes str, B_slice slc) { int64_t start, stop, step, slen; normalize_slice(slc, str->nbytes, &slen, &start, &stop, &step); //slice notation has been eliminated and default values applied B_bytes res; NEW_UNFILLED_BYTES(res,slen); int t = start; for (int i=0; istr[i] = str->str[t]; t += step; } return res; } B_NoneType B_SliceableD_bytesD___setslice__ (B_SliceableD_bytes wit, B_bytes str, B_Iterable wit2, B_slice slc, $WORD iter) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method setslice on bytes"))); return B_None; } B_NoneType B_SliceableD_bytesD___delslice__ (B_SliceableD_bytes wit, B_bytes str, B_slice slc) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method delslice on bytes"))); return B_None; } // Times B_bytes B_TimesD_bytesD___add__ (B_TimesD_bytes wit, B_bytes s, B_bytes t) { B_bytes res; NEW_UNFILLED_BYTES(res,s->nbytes + t->nbytes); memcpy(res->str,s->str,s->nbytes); memcpy(res->str+s->nbytes,t->str,t->nbytes); return res; } B_bytes B_TimesD_bytesD___zero__ (B_TimesD_bytes wit) { return to$bytes(""); } B_bytes B_TimesD_bytesD___mul__ (B_TimesD_bytes wit, B_bytes a, B_int n) { int nval = fromB_int(n); if (nval <= 0) return to$bytes(""); else { B_bytes res; NEW_UNFILLED_BYTES(res, a->nbytes * nval); for (int i=0; istr + i*a->nbytes,a->str,a->nbytes); return res; } } // Hashable B_bool B_HashableD_bytesD___eq__ (B_HashableD_bytes wit, B_bytes a, B_bytes b) { if (a->nbytes != b->nbytes) return B_False; for (int i=0; i < a->nbytes; i++) if (a->str[i] != b->str[i]) return B_False; return B_True; } B_bool B_HashableD_bytesD___ne__ (B_HashableD_bytes wit, B_bytes a, B_bytes b) { return toB_bool(!B_HashableD_bytesD___eq__(wit,a,b)->val); } B_NoneType B_HashableD_bytesD_hash(B_HashableD_bytes wit, B_bytes a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, a); return B_None; } // Builtin functions involving strings ///////////////////////////////////////////// B_str B_ascii(B_value v) { B_str s = v->$class->__str__(v); struct byte_counts bs = byte_count(s->str, s->nbytes); // printf("%d %d %d %d %d %d\n",bs.escaped,bs.squotes,bs.dquotes,bs.printable,bs.non_printable,bs.non_ascii); bool use_single_quotes = !(bs.dquotes==0 && bs.squotes>0); int escaped_quotes = use_single_quotes ? bs.dquotes : bs.squotes; int newbytes = 2+bs.escaped+3*bs.non_printable+escaped_quotes+3*bs.non_ascii; B_str res; NEW_UNFILLED_STR(res,s->nchars+newbytes,s->nbytes+newbytes); escape_str(res->str+1,s->str,res->nbytes-1,s->nbytes,255,!use_single_quotes,use_single_quotes,false,false); if (use_single_quotes) { res->str[0] = '\''; res->str[res->nbytes-1] = '\''; } else { res->str[0] = '"'; res->str[res->nbytes-1] = '"'; } return res; } B_str B_bin(B_Integral wit, $WORD n) { long v = fromB_int(wit->$class->__int__(wit,n)); int sign = v<0; int nbits = 1; unsigned long u = labs(v); if (u & 0xffffffff00000000) { u >>= 32; nbits += 32; } if (u & 0x00000000ffff0000) { u >>= 16; nbits += 16; } if (u & 0x000000000000ff00) { u >>= 8; nbits += 8; } if (u & 0x00000000000000f0) { u >>= 4; nbits += 4; } if (u & 0x000000000000000c) { u >>= 2; nbits += 2; } if (u & 0x0000000000000002) { u >>= 1; nbits += 1; } B_str res; int nbytes = sign+2+nbits; NEW_UNFILLED_STR(res,nbytes,nbytes); unsigned char *p = res->str; if (sign) { *p = '-'; p++; } *p = '0'; p++; *p = 'b'; p++; u = labs(v); for (int i = nbits-1; i>=0; i--) { *p = u & (1L << i) ? '1' : '0'; p++; } return res; } B_str B_chr(B_Integral wit, $WORD n) { long v = fromB_int(wit->$class->__int__(wit,n)); if (v >= 0x110000) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("chr: argument is not a valid Unicode code point"))); if (v > 0 && v < ASCII_CHAR_TABLE_SIZE) return &ascii_char_strs[v]; unsigned char code[4]; int nbytes = utf8proc_encode_char((int)v,(unsigned char*)&code); if (nbytes==0) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("chr: argument is not a valid Unicode code point"))); B_str res; NEW_UNFILLED_STR(res,1,nbytes); for (int i=0; istr[i] = code[i]; return res; } B_str B_hex(B_Integral wit, $WORD n) { unsigned char *hexdigits = (unsigned char *)"0123456789abcdef"; long v = fromB_int(wit->$class->__int__(wit,n)); int sign = v<0; int nhexs = 1; unsigned long u = labs(v); if (u & 0xffffffff00000000) { u >>= 32; nhexs += 8; } if (u & 0x00000000ffff0000) { u >>= 16; nhexs += 4; } if (u & 0x000000000000ff00) { u >>= 8; nhexs += 2; } if (u & 0x00000000000000f0) { u >>= 4; nhexs += 1; } B_str res; int nbytes = sign+2+nhexs; NEW_UNFILLED_STR(res,nbytes,nbytes); unsigned char *p = res->str; if (sign) { *p = '-'; p++; } *p = '0'; p++; *p = 'x'; p++; u = labs(v); for (int i = nhexs-1; i>=0; i--) { *p = hexdigits[(u>>(4*i)) & 0xf]; p++; } return res; } int64_t B_U_6ord(B_str c) { if(c->nchars != 1) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("ord: argument is not a single Unicode char"))); int cp; int cpnbytes = utf8proc_iterate(c->str,-1,&cp); if (cpnbytes < 0) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("ord: argument is not a single Unicode char"))); return (int64_t)cp; } // Auxiliary function used in __str__ for collections //////////////////////////// B_str B_strD_join_par(char lpar, B_list elems, char rpar) { char *s = ", "; int len = elems->length; int totchars = 2; //parens int totbytes = 2; B_str nxt; for (int i=0; idata[i]; totchars += nxt->nchars; totbytes += nxt->nbytes; } if (len > 1) { totchars += (len-1) * 2; // 2 is length of ", " totbytes += (len-1) * 2; } B_str res; NEW_UNFILLED_STR(res,totchars,totbytes); res->str[0] = lpar; res->str[totbytes-1] = rpar; if (len > 0) { unsigned char *p = res->str+1; nxt = elems->data[0]; memcpy(p,nxt->str,nxt->nbytes); p += nxt->nbytes; for (int i=1; idata[i]; memcpy(p,s,2); p += 2; memcpy(p,nxt->str,nxt->nbytes); p += nxt->nbytes; } } return res; } B_str $default__str__(B_value self) { return $FORMAT("<%s object at %p>", self->$class->$GCINFO, self); } // Static witnesses /* struct B_OrdD_strG_class B_OrdD_strG_methods = { "B_OrdD_str", UNASSIGNED, ($SuperG_class)&B_OrdG_methods, (B_NoneType (*)(B_OrdD_str))$default__init__, B_OrdD_strD___serialize__, B_OrdD_strD___deserialize__, (B_bool (*)(B_OrdD_str))$default__bool__, (B_str (*)(B_OrdD_str))$default__str__, (B_str (*)(B_OrdD_str))$default__str__, B_OrdD_strD___eq__, B_OrdD_strD___ne__, B_OrdD_strD___lt__, B_OrdD_strD___le__, B_OrdD_strD___gt__, B_OrdD_strD___ge__ }; struct B_OrdD_str B_OrdD_str_instance = {&B_OrdD_strG_methods}; B_OrdD_str B_OrdD_strG_witness = &B_OrdD_str_instance; struct B_ContainerD_strG_class B_ContainerD_strG_methods = { "B_ContainerD_str", UNASSIGNED, ($SuperG_class)&B_ContainerG_methods, (B_NoneType (*)(B_ContainerD_str))$default__init__, B_ContainerD_strD___serialize__, B_ContainerD_strD___deserialize__, (B_bool (*)(B_ContainerD_str))$default__bool__, (B_str (*)(B_ContainerD_str))$default__str__, (B_str (*)(B_ContainerD_str))$default__str__, B_ContainerD_strD___iter__, NULL, B_ContainerD_strD___len__, B_ContainerD_strD___contains__, B_ContainerD_strD___containsnot__ }; struct B_ContainerD_str B_ContainerD_str_instance = {&B_ContainerD_strG_methods}; B_ContainerD_str B_ContainerD_strG_witness = &B_ContainerD_str_instance; struct B_SliceableD_strG_class B_SliceableD_strG_methods = { "B_SliceableD_str", UNASSIGNED, ($SuperG_class)&B_SliceableG_methods, (B_NoneType (*)(B_SliceableD_str))$default__init__, B_SliceableD_strD___serialize__, B_SliceableD_strD___deserialize__, (B_bool (*)(B_SliceableD_str))$default__bool__, (B_str (*)(B_SliceableD_str))$default__str__, (B_str (*)(B_SliceableD_str))$default__str__, B_SliceableD_strD___getitem__, B_SliceableD_strD___setitem__, B_SliceableD_strD___delitem__, B_SliceableD_strD___getslice__, B_SliceableD_strD___setslice__, B_SliceableD_strD___delslice__ }; struct B_SliceableD_str B_SliceableD_str_instance = {&B_SliceableD_strG_methods}; B_SliceableD_str B_SliceableD_strG_witness = &B_SliceableD_str_instance; struct B_TimesD_strG_class B_TimesD_strG_methods = { "B_TimesD_str", UNASSIGNED, ($SuperG_class)&B_TimesG_methods, (B_NoneType (*)(B_TimesD_str))$default__init__, B_TimesD_strD___serialize__, B_TimesD_strD___deserialize__, (B_bool (*)(B_TimesD_str))$default__bool__, (B_str (*)(B_TimesD_str))$default__str__, (B_str (*)(B_TimesD_str))$default__str__, B_TimesD_strD___add__, (B_str (*)(B_TimesD_str, B_str, B_str))B_PlusD___iadd__, B_TimesD_strD___mul__, (B_str (*)(B_TimesD_str, B_str, B_int))B_TimesD___imul__, }; struct B_TimesD_str B_TimesD_str_instance = {&B_TimesD_strG_methods}; B_TimesD_str B_TimesD_strG_witness = &B_TimesD_str_instance; struct B_HashableD_strG_class B_HashableD_strG_methods = { "B_HashableD_str", UNASSIGNED, ($SuperG_class)&B_HashableG_methods, (B_NoneType (*)(B_HashableD_str))$default__init__, B_HashableD_strD___serialize__, B_HashableD_strD___deserialize__, (B_bool (*)(B_HashableD_str))$default__bool__, (B_str (*)(B_HashableD_str))$default__str__, (B_str (*)(B_HashableD_str))$default__str__, B_HashableD_strD___eq__, B_HashableD_strD___ne__ }; struct B_HashableD_str B_HashableD_str_instance = {&B_HashableD_strG_methods}; B_HashableD_str B_HashableD_strG_witness = &B_HashableD_str_instance; struct B_SequenceD_bytearray B_SequenceD_bytearray_instance; struct B_CollectionD_SequenceD_bytearray B_CollectionD_SequenceD_bytearray_instance; struct B_TimesD_SequenceD_bytearray B_TimesD_SequenceD_bytearray_instance; struct B_OrdD_bytearrayG_class B_OrdD_bytearrayG_methods = { "B_OrdD_bytearray", UNASSIGNED, ($SuperG_class)&B_OrdG_methods, (B_NoneType (*)(B_OrdD_bytearray))$default__init__, B_OrdD_bytearrayD___serialize__, B_OrdD_bytearrayD___deserialize__, (B_bool (*)(B_OrdD_bytearray))$default__bool__, (B_str (*)(B_OrdD_bytearray))$default__str__, (B_str (*)(B_OrdD_bytearray))$default__str__, B_OrdD_bytearrayD___eq__, B_OrdD_bytearrayD___ne__, B_OrdD_bytearrayD___lt__, B_OrdD_bytearrayD___le__, B_OrdD_bytearrayD___gt__, B_OrdD_bytearrayD___ge__ }; struct B_OrdD_bytearray B_OrdD_bytearray_instance = {&B_OrdD_bytearrayG_methods}; B_OrdD_bytearray B_OrdD_bytearrayG_witness = &B_OrdD_bytearray_instance; struct B_SequenceD_bytearrayG_class B_SequenceD_bytearrayG_methods = { "B_SequenceD_bytearray", UNASSIGNED, ($SuperG_class)&B_SequenceG_methods, (B_NoneType (*)(B_SequenceD_bytearray))$default__init__, B_SequenceD_bytearrayD___serialize__, B_SequenceD_bytearrayD___deserialize__, (B_bool (*)(B_SequenceD_bytearray))$default__bool__, (B_str (*)(B_SequenceD_bytearray))$default__str__, (B_str (*)(B_SequenceD_bytearray))$default__str__, B_SequenceD_bytearrayD___getitem__, B_SequenceD_bytearrayD___setitem__, B_SequenceD_bytearrayD___delitem__, B_SequenceD_bytearrayD___getslice__, B_SequenceD_bytearrayD___setslice__, B_SequenceD_bytearrayD___delslice__, B_SequenceD_bytearrayD___reversed__, B_SequenceD_bytearray$insert, B_SequenceD_bytearray$append, B_SequenceD_bytearray$reverse }; struct B_SequenceD_bytearray B_SequenceD_bytearray_instance = { &B_SequenceD_bytearrayG_methods, (B_Eq)&B_OrdD_intG_methods, (B_Collection)&B_CollectionD_SequenceD_bytearray_instance, (B_Times)&B_TimesD_SequenceD_bytearray_instance }; B_SequenceD_bytearray B_SequenceD_bytearrayG_witness = &B_SequenceD_bytearray_instance; struct B_CollectionD_SequenceD_bytearrayG_class B_CollectionD_SequenceD_bytearrayG_methods = { "B_CollectionD_SequenceD_bytearray", UNASSIGNED, ($SuperG_class)&B_CollectionG_methods, B_CollectionD_SequenceD_bytearrayD___init__, B_CollectionD_SequenceD_bytearrayD___serialize__, B_CollectionD_SequenceD_bytearrayD___deserialize__, (B_bool (*)(B_CollectionD_SequenceD_bytearray))$default__bool__, (B_str (*)(B_CollectionD_SequenceD_bytearray))$default__str__, (B_str (*)(B_CollectionD_SequenceD_bytearray))$default__str__, B_CollectionD_SequenceD_bytearrayD___iter__, B_CollectionD_SequenceD_bytearrayD___fromiter__, B_CollectionD_SequenceD_bytearrayD___len__ }; struct B_CollectionD_SequenceD_bytearray B_CollectionD_SequenceD_bytearray_instance = {&B_CollectionD_SequenceD_bytearrayG_methods,(B_Sequence)&B_SequenceD_bytearray_instance}; B_CollectionD_SequenceD_bytearray B_CollectionD_SequenceD_bytearrayG_witness = &B_CollectionD_SequenceD_bytearray_instance; struct B_TimesD_SequenceD_bytearrayG_class B_TimesD_SequenceD_bytearrayG_methods = { "B_TimesD_SequenceD_bytearray", UNASSIGNED, ($SuperG_class)&B_TimesG_methods, B_TimesD_SequenceD_bytearrayD___init__, B_TimesD_SequenceD_bytearrayD___serialize__, B_TimesD_SequenceD_bytearrayD___deserialize__, (B_bool (*)(B_TimesD_SequenceD_bytearray))$default__bool__, (B_str (*)(B_TimesD_SequenceD_bytearray))$default__str__, (B_str (*)(B_TimesD_SequenceD_bytearray))$default__str__, B_TimesD_SequenceD_bytearrayD___add__, (B_bytearray (*)(B_TimesD_SequenceD_bytearray, B_bytearray, B_bytearray))B_PlusD___iadd__, B_TimesD_SequenceD_bytearrayD___mul__, (B_bytearray (*)(B_TimesD_SequenceD_bytearray, B_bytearray, B_int))B_TimesD___imul__, }; struct B_TimesD_SequenceD_bytearray B_TimesD_SequenceD_bytearray_instance = {&B_TimesD_SequenceD_bytearrayG_methods}; B_TimesD_SequenceD_bytearray B_TimesD_SequenceD_bytearrayG_witness = &B_TimesD_SequenceD_bytearray_instance; struct B_ContainerD_bytearrayG_class B_ContainerD_bytearrayG_methods = { "B_ContainerD_bytearray", UNASSIGNED, ($SuperG_class)&B_ContainerG_methods, B_ContainerD_bytearrayD___init__, B_ContainerD_bytearrayD___serialize__, B_ContainerD_bytearrayD___deserialize__, (B_bool (*)(B_ContainerD_bytearray))$default__bool__, (B_str (*)(B_ContainerD_bytearray))$default__str__, (B_str (*)(B_ContainerD_bytearray))$default__str__, B_ContainerD_bytearrayD___iter__, B_ContainerD_bytearrayD___fromiter__, B_ContainerD_bytearrayD___len__, B_ContainerD_bytearrayD___contains__, B_ContainerD_bytearrayD___containsnot__ }; struct B_ContainerD_bytearray B_ContainerD_bytearray_instance = {&B_ContainerD_bytearrayG_methods}; B_ContainerD_bytearray B_ContainerD_bytearrayG_witness = &B_ContainerD_bytearray_instance; struct B_OrdD_bytesG_class B_OrdD_bytesG_methods = { "B_OrdD_bytes", UNASSIGNED, ($SuperG_class)&B_OrdG_methods, (B_NoneType (*)(B_OrdD_bytes))$default__init__, B_OrdD_bytesD___serialize__, B_OrdD_bytesD___deserialize__, (B_bool (*)(B_OrdD_bytes))$default__bool__, (B_str (*)(B_OrdD_bytes))$default__str__, (B_str (*)(B_OrdD_bytes))$default__str__, B_OrdD_bytesD___eq__, B_OrdD_bytesD___ne__, B_OrdD_bytesD___lt__, B_OrdD_bytesD___le__, B_OrdD_bytesD___gt__, B_OrdD_bytesD___ge__ }; struct B_OrdD_bytes B_OrdD_bytes_instance = {&B_OrdD_bytesG_methods}; B_OrdD_bytes B_OrdD_bytesG_witness = &B_OrdD_bytes_instance; struct B_ContainerD_bytesG_class B_ContainerD_bytesG_methods = { "B_ContainerD_bytes", UNASSIGNED, ($SuperG_class)&B_ContainerG_methods, B_ContainerD_bytesD___init__, B_ContainerD_bytesD___serialize__, B_ContainerD_bytesD___deserialize__, (B_bool (*)(B_ContainerD_bytes))$default__bool__, (B_str (*)(B_ContainerD_bytes))$default__str__, (B_str (*)(B_ContainerD_bytes))$default__str__, B_ContainerD_bytesD___iter__, NULL, B_ContainerD_bytesD___len__, B_ContainerD_bytesD___contains__, B_ContainerD_bytesD___containsnot__ }; struct B_ContainerD_bytes B_ContainerD_bytes_instance = {&B_ContainerD_bytesG_methods}; B_ContainerD_bytes B_ContainerD_bytesG_witness = &B_ContainerD_bytes_instance; struct B_SliceableD_bytesG_class B_SliceableD_bytesG_methods = { "B_SliceableD_bytes", UNASSIGNED, ($SuperG_class)&B_SliceableG_methods, (B_NoneType (*)(B_SliceableD_bytes))$default__init__, B_SliceableD_bytesD___serialize__, B_SliceableD_bytesD___deserialize__, (B_bool (*)(B_SliceableD_bytes))$default__bool__, (B_str (*)(B_SliceableD_bytes))$default__str__, (B_str (*)(B_SliceableD_bytes))$default__str__, B_SliceableD_bytesD___getitem__, B_SliceableD_bytesD___setitem__, B_SliceableD_bytesD___delitem__, B_SliceableD_bytesD___getslice__, B_SliceableD_bytesD___setslice__, B_SliceableD_bytesD___delslice__ }; struct B_SliceableD_bytes B_SliceableD_bytes_instance = {&B_SliceableD_bytesG_methods}; B_SliceableD_bytes B_SliceableD_bytesG_witness = &B_SliceableD_bytes_instance; struct B_TimesD_bytesG_class B_TimesD_bytesG_methods = { "B_TimesD_bytes", UNASSIGNED, ($SuperG_class)&B_TimesG_methods, (B_NoneType (*)(B_TimesD_bytes))$default__init__, B_TimesD_bytesD___serialize__, B_TimesD_bytesD___deserialize__, (B_bool (*)(B_TimesD_bytes))$default__bool__, (B_str (*)(B_TimesD_bytes))$default__str__, (B_str (*)(B_TimesD_bytes))$default__str__, B_TimesD_bytesD___add__, (B_bytes (*)(B_TimesD_bytes, B_bytes, B_bytes))B_PlusD___iadd__, B_TimesD_bytesD___mul__, (B_bytes (*)(B_TimesD_bytes, B_bytes, B_int))B_TimesD___imul__, }; struct B_TimesD_bytes B_TimesD_bytes_instance = {&B_TimesD_bytesG_methods}; B_TimesD_bytes B_TimesD_bytesG_witness = &B_TimesD_bytes_instance; struct B_HashableD_bytesG_class B_HashableD_bytesG_methods = { "B_HashableD_bytes", UNASSIGNED, ($SuperG_class)&B_HashableG_methods, (B_NoneType (*)(B_HashableD_bytes))$default__init__, B_HashableD_bytesD___serialize__, B_HashableD_bytesD___deserialize__, (B_bool (*)(B_HashableD_bytes))$default__bool__, (B_str (*)(B_HashableD_bytes))$default__str__, (B_str (*)(B_HashableD_bytes))$default__str__, B_HashableD_bytesD___eq__, B_HashableD_bytesD___ne__ }; struct B_HashableD_bytes B_HashableD_bytes_instance = {&B_HashableD_bytesG_methods}; B_HashableD_bytes B_HashableD_bytesG_witness = &B_HashableD_bytes_instance; */ B_str $FORMAT(const char *format, ...) { va_list args; va_start(args, format); va_list args_copy; va_copy(args_copy, args); int size = vsnprintf(NULL, 0, format, args_copy); va_end(args_copy); if (size < 0) { va_end(args); RAISE(B_ValueError, to_str_noc("Invalid format string")); } char *buffer = (char *)acton_malloc_atomic(size + 1); if (buffer == NULL) { va_end(args); RAISE(B_MemoryError, to_str_noc("Failed to allocate memory for formatted string")); } vsnprintf(buffer, size + 1, format, args); va_end(args); return to_str_noc(buffer); } ================================================ FILE: base/builtin/str.h ================================================ struct B_strG_class; struct B_str { struct B_strG_class *$class; int nbytes; // length of str in bytes int nchars; // length of str in Unicode chars unsigned char *str; // str is UTF-8 encoded. }; // Constructor; str must be a null-terminated, correctly UTF-8-encoded string. // The constructor checks this and returns a B_str value. B_str to$str(char *str); //Dare not remove this B_str toB_str(char *str); B_str to_str_noc(char *str); // Destructor; recover the internal string. unsigned char *fromB_str(B_str str); B_str $FORMAT(const char *format, ...); // Iterators over str's /////////////////////////////////////////////////////// typedef struct B_IteratorB_str *B_IteratorB_str; ; struct B_IteratorB_strG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__)(B_IteratorB_str, B_str); void (*__serialize__)(B_IteratorB_str,$Serial$state); B_IteratorB_str (*__deserialize__)(B_IteratorB_str,$Serial$state); B_bool (*__bool__)(B_IteratorB_str); B_str (*__str__)(B_IteratorB_str); B_str (*__repr__)(B_IteratorB_str); B_str (*__next__)(B_IteratorB_str); }; struct B_IteratorB_str { struct B_IteratorB_strG_class *$class; B_str src; int nxt; }; extern struct B_IteratorB_strG_class B_IteratorB_strG_methods; B_IteratorB_str B_IteratorB_strG_new(B_str); // bytearray ///////////////////////////////////////////////////////////////////////////////////// struct B_bytearray { struct B_bytearrayG_class *$class; int nbytes; unsigned char *str; int capacity; }; B_bytearray toB_bytearray(char *str); unsigned char *fromB_bytearray(B_bytearray b); // Iterators over bytearrays /////////////////////////////////////////////////////// typedef struct B_IteratorB_bytearray *B_IteratorB_bytearray; ; struct B_IteratorB_bytearrayG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__)(B_IteratorB_bytearray, B_bytearray); void (*__serialize__)(B_IteratorB_bytearray,$Serial$state); B_IteratorB_bytearray (*__deserialize__)(B_IteratorB_bytearray,$Serial$state); B_bool (*__bool__)(B_IteratorB_bytearray); B_str (*__str__)(B_IteratorB_bytearray); B_str (*__repr__)(B_IteratorB_bytearray); B_int (*__next__)(B_IteratorB_bytearray); }; struct B_IteratorB_bytearray { struct B_IteratorB_bytearrayG_class *$class; B_bytearray src; int nxt; }; extern struct B_IteratorB_bytearrayG_class B_IteratorB_bytearrayG_methods; B_IteratorB_bytearray B_IteratorB_bytearrayG_new(B_bytearray); // bytes ///////////////////////////////////////////////////////////////////////////////////// struct B_bytes { struct B_bytesG_class *$class; int nbytes; unsigned char *str; }; B_bytes to$bytes(char *str); B_bytes to$bytesD_len(char *str, int len); B_bytes actBytesFromCString(char *str); B_bytes actBytesFromCStringNoCopy(char *str); B_bytes actBytesFromCStringLength(char *str, int len); B_bytes actBytesFromCStringLengthNoCopy(char *str, int length); unsigned char *fromB_bytes(B_bytes b); // Iterators over bytes /////////////////////////////////////////////////////// typedef struct B_IteratorB_bytes *B_IteratorB_bytes; ; struct B_IteratorB_bytesG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__)(B_IteratorB_bytes, B_bytes); void (*__serialize__)(B_IteratorB_bytes,$Serial$state); B_IteratorB_bytes (*__deserialize__)(B_IteratorB_bytes,$Serial$state); B_bool (*__bool__)(B_IteratorB_bytes); B_str (*__str__)(B_IteratorB_bytes); B_str (*__repr__)(B_IteratorB_bytes); B_int (*__next__)(B_IteratorB_bytes); }; struct B_IteratorB_bytes { struct B_IteratorB_bytesG_class *$class; B_bytes src; int nxt; }; extern struct B_IteratorB_bytesG_class B_IteratorB_bytesG_methods; B_IteratorB_bytes B_IteratorB_bytesG_new(B_bytes); // Internal auxiliary function ///////////////////////////////////////////// // used in defining __str__ method for collection types (list, dict, set) B_str B_strD_join_par(char lpar,B_list elems, char rpar); B_str $default__str__(B_value); ================================================ FILE: base/builtin/timsort.c ================================================ #define SORT_NAME B #define SORT_TYPE $WORD /* An implementation of simplified Timsort (no galloping). * Slightly modified from https://github.com/GNOME/libxml2/blob/master/timsort.h#L531 * (STR_COMP is modified and takes an extra witness parameter. Consequently several methods from the main function downwards * need take this parameter. * * The following is the comment in the libxml2 file. * * Taken from https://github.com/swenson/sort * Revision: 05fd77bfec049ce8b7c408c4d3dd2d51ee061a15 * Removed all code unrelated to Timsort and made minor adjustments for * cross-platform compatibility. */ /* * The MIT License (MIT) * * Copyright (c) 2010-2017 Christopher Swenson. * Copyright (c) 2012 Vojtech Fried. * Copyright (c) 2012 Google Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ // #include // #include // #include // #ifdef HAVE_STDINT_H // #include // #elif defined(_WIN32) // typedef unsigned __int64 uint64_t; // #endif #ifndef SORT_NAME #error "Must declare SORT_NAME" #endif #ifndef SORT_TYPE #error "Must declare SORT_TYPE" #endif #ifndef SORT_CMP #define SORT_CMP(w, x, y) (w->$class->__lt__(w, x, y)->val ? -1 : (w->$class->__eq__(w, x, y)->val ? 0 : 1)) //((x) < (y) ? -1 : ((x) == (y) ? 0 : 1)) #endif #ifndef TIM_SORT_STACK_SIZE #define TIM_SORT_STACK_SIZE 128 #endif #define SORT_SWAP(x,y) {SORT_TYPE __SORT_SWAP_t = (x); (x) = (y); (y) = __SORT_SWAP_t;} /* Common, type-agnostic functions and constants that we don't want to declare twice. */ #ifndef SORT_COMMON_H #define SORT_COMMON_H #ifndef MAX #define MAX(x,y) (((x) > (y) ? (x) : (y))) #endif #ifndef MIN #define MIN(x,y) (((x) < (y) ? (x) : (y))) #endif static int compute_minrun(const uint64_t); #ifndef CLZ #if defined(__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ > 3)) #define CLZ __builtin_clzll #else static int clzll(uint64_t); /* adapted from Hacker's Delight */ static int clzll(uint64_t x) { int n; if (x == 0) { return 64; } n = 0; if (x <= 0x00000000FFFFFFFFL) { n = n + 32; x = x << 32; } if (x <= 0x0000FFFFFFFFFFFFL) { n = n + 16; x = x << 16; } if (x <= 0x00FFFFFFFFFFFFFFL) { n = n + 8; x = x << 8; } if (x <= 0x0FFFFFFFFFFFFFFFL) { n = n + 4; x = x << 4; } if (x <= 0x3FFFFFFFFFFFFFFFL) { n = n + 2; x = x << 2; } if (x <= 0x7FFFFFFFFFFFFFFFL) { n = n + 1; } return n; } #define CLZ clzll #endif #endif static __inline int compute_minrun(const uint64_t size) { const int top_bit = 64 - CLZ(size); const int shift = MAX(top_bit, 6) - 6; const int minrun = size >> shift; const uint64_t mask = (1ULL << shift) - 1; if (mask & size) { return minrun + 1; } return minrun; } #endif /* SORT_COMMON_H */ #define SORT_CONCAT(x, y) x ## _ ## y #define SORT_MAKE_STR1(x, y) SORT_CONCAT(x,y) #define SORT_MAKE_STR(x) SORT_MAKE_STR1(SORT_NAME,x) #define BINARY_INSERTION_FIND SORT_MAKE_STR(binary_insertion_find) #define BINARY_INSERTION_SORT_START SORT_MAKE_STR(binary_insertion_sort_start) #define BINARY_INSERTION_SORT SORT_MAKE_STR(binary_insertion_sort) #define REVERSE_ELEMENTS SORT_MAKE_STR(reverse_elements) #define COUNT_RUN SORT_MAKE_STR(count_run) #define CHECK_INVARIANT SORT_MAKE_STR(check_invariant) #define TIM_SORT SORT_MAKE_STR(tim_sort) #define TIM_SORT_RESIZE SORT_MAKE_STR(tim_sort_resize) #define TIM_SORT_MERGE SORT_MAKE_STR(tim_sort_merge) #define TIM_SORT_COLLAPSE SORT_MAKE_STR(tim_sort_collapse) #ifndef MAX #define MAX(x,y) (((x) > (y) ? (x) : (y))) #endif #ifndef MIN #define MIN(x,y) (((x) < (y) ? (x) : (y))) #endif typedef struct { size_t start; size_t length; } TIM_SORT_RUN_T; void BINARY_INSERTION_SORT(B_Ord w, SORT_TYPE *dst, const size_t size); void TIM_SORT(B_Ord w, SORT_TYPE *dst, const size_t size); /* Function used to do a binary search for binary insertion sort */ static __inline size_t BINARY_INSERTION_FIND(B_Ord w, SORT_TYPE *dst, const SORT_TYPE x, const size_t size) { size_t l, c, r; SORT_TYPE cx; l = 0; r = size - 1; c = r >> 1; /* check for out of bounds at the beginning. */ if (SORT_CMP(w, x, dst[0]) < 0) { return 0; } else if (SORT_CMP(w, x, dst[r]) > 0) { return r; } cx = dst[c]; while (1) { const int val = SORT_CMP(w, x, cx); if (val < 0) { if (c - l <= 1) { return c; } r = c; } else { /* allow = for stability. The binary search favors the right. */ if (r - c <= 1) { return c + 1; } l = c; } c = l + ((r - l) >> 1); cx = dst[c]; } } /* Binary insertion sort, but knowing that the first "start" entries are sorted. Used in timsort. */ static void BINARY_INSERTION_SORT_START(B_Ord w, SORT_TYPE *dst, const size_t start, const size_t size) { size_t i; for (i = start; i < size; i++) { size_t j; SORT_TYPE x; size_t location; /* If this entry is already correct, just move along */ if (SORT_CMP(w, dst[i - 1], dst[i]) <= 0) { continue; } /* Else we need to find the right place, shift everything over, and squeeze in */ x = dst[i]; location = BINARY_INSERTION_FIND(w, dst, x, i); for (j = i - 1; j >= location; j--) { dst[j + 1] = dst[j]; if (j == 0) { /* check edge case because j is unsigned */ break; } } dst[location] = x; } } /* Binary insertion sort */ void BINARY_INSERTION_SORT(B_Ord w, SORT_TYPE *dst, const size_t size) { /* don't bother sorting an array of size <= 1 */ if (size <= 1) { return; } BINARY_INSERTION_SORT_START(w, dst, 1, size); } /* timsort implementation, based on timsort.txt */ static __inline void REVERSE_ELEMENTS(SORT_TYPE *dst, size_t start, size_t end) { while (1) { if (start >= end) { return; } SORT_SWAP(dst[start], dst[end]); start++; end--; } } static size_t COUNT_RUN(B_Ord w, SORT_TYPE *dst, const size_t start, const size_t size) { size_t curr; if (size - start == 1) { return 1; } if (start >= size - 2) { if (SORT_CMP(w, dst[size - 2], dst[size - 1]) > 0) { SORT_SWAP(dst[size - 2], dst[size - 1]); } return 2; } curr = start + 2; if (SORT_CMP(w, dst[start], dst[start + 1]) <= 0) { /* increasing run */ while (1) { if (curr == size - 1) { break; } if (SORT_CMP(w, dst[curr - 1], dst[curr]) > 0) { break; } curr++; } return curr - start; } else { /* decreasing run */ while (1) { if (curr == size - 1) { break; } if (SORT_CMP(w, dst[curr - 1], dst[curr]) <= 0) { break; } curr++; } /* reverse in-place */ REVERSE_ELEMENTS(dst, start, curr - 1); return curr - start; } } static int CHECK_INVARIANT(TIM_SORT_RUN_T *stack, const int stack_curr) { size_t A, B, C; if (stack_curr < 2) { return 1; } if (stack_curr == 2) { const size_t A1 = stack[stack_curr - 2].length; const size_t B1 = stack[stack_curr - 1].length; if (A1 <= B1) { return 0; } return 1; } A = stack[stack_curr - 3].length; B = stack[stack_curr - 2].length; C = stack[stack_curr - 1].length; if ((A <= B + C) || (B <= C)) { return 0; } return 1; } typedef struct { size_t alloc; SORT_TYPE *storage; } TEMP_STORAGE_T; static void TIM_SORT_RESIZE(TEMP_STORAGE_T *store, const size_t new_size) { if (store->alloc < new_size) { SORT_TYPE *tempstore = (SORT_TYPE *)acton_realloc(store->storage, new_size * sizeof(SORT_TYPE)); if (tempstore == NULL) { fprintf(stderr, "Error allocating temporary storage for tim sort: need %lu bytes", (unsigned long)(sizeof(SORT_TYPE) * new_size)); exit(1); } store->storage = tempstore; store->alloc = new_size; } } static void TIM_SORT_MERGE(B_Ord w, SORT_TYPE *dst, const TIM_SORT_RUN_T *stack, const int stack_curr, TEMP_STORAGE_T *store) { const size_t A = stack[stack_curr - 2].length; const size_t B = stack[stack_curr - 1].length; const size_t curr = stack[stack_curr - 2].start; SORT_TYPE *storage; size_t i, j, k; TIM_SORT_RESIZE(store, MIN(A, B)); storage = store->storage; /* left merge */ if (A < B) { memcpy(storage, &dst[curr], A * sizeof(SORT_TYPE)); i = 0; j = curr + A; for (k = curr; k < curr + A + B; k++) { if ((i < A) && (j < curr + A + B)) { if (SORT_CMP(w, storage[i], dst[j]) <= 0) { dst[k] = storage[i++]; } else { dst[k] = dst[j++]; } } else if (i < A) { dst[k] = storage[i++]; } else { break; } } } else { /* right merge */ memcpy(storage, &dst[curr + A], B * sizeof(SORT_TYPE)); i = B; j = curr + A; k = curr + A + B; while (k > curr) { k--; if ((i > 0) && (j > curr)) { if (SORT_CMP(w, dst[j - 1], storage[i - 1]) > 0) { dst[k] = dst[--j]; } else { dst[k] = storage[--i]; } } else if (i > 0) { dst[k] = storage[--i]; } else { break; } } } } static int TIM_SORT_COLLAPSE(B_Ord w, SORT_TYPE *dst, TIM_SORT_RUN_T *stack, int stack_curr, TEMP_STORAGE_T *store, const size_t size) { while (1) { size_t A, B, C, D; int ABC, BCD, CD; /* if the stack only has one thing on it, we are done with the collapse */ if (stack_curr <= 1) { break; } /* if this is the last merge, just do it */ if ((stack_curr == 2) && (stack[0].length + stack[1].length == size)) { TIM_SORT_MERGE(w, dst, stack, stack_curr, store); stack[0].length += stack[1].length; stack_curr--; break; } /* check if the invariant is off for a stack of 2 elements */ else if ((stack_curr == 2) && (stack[0].length <= stack[1].length)) { TIM_SORT_MERGE(w, dst, stack, stack_curr, store); stack[0].length += stack[1].length; stack_curr--; break; } else if (stack_curr == 2) { break; } B = stack[stack_curr - 3].length; C = stack[stack_curr - 2].length; D = stack[stack_curr - 1].length; if (stack_curr >= 4) { A = stack[stack_curr - 4].length; ABC = (A <= B + C); } else { ABC = 0; } BCD = (B <= C + D) || ABC; CD = (C <= D); /* Both invariants are good */ if (!BCD && !CD) { break; } /* left merge */ if (BCD && !CD) { TIM_SORT_MERGE(w, dst, stack, stack_curr - 1, store); stack[stack_curr - 3].length += stack[stack_curr - 2].length; stack[stack_curr - 2] = stack[stack_curr - 1]; stack_curr--; } else { /* right merge */ TIM_SORT_MERGE(w, dst, stack, stack_curr, store); stack[stack_curr - 2].length += stack[stack_curr - 1].length; stack_curr--; } } return stack_curr; } static __inline int PUSH_NEXT(B_Ord w, SORT_TYPE *dst, const size_t size, TEMP_STORAGE_T *store, const size_t minrun, TIM_SORT_RUN_T *run_stack, size_t *stack_curr, size_t *curr) { size_t len = COUNT_RUN(w, dst, *curr, size); size_t run = minrun; if (run > size - *curr) { run = size - *curr; } if (run > len) { BINARY_INSERTION_SORT_START(w, &dst[*curr], len, run); len = run; } run_stack[*stack_curr].start = *curr; run_stack[*stack_curr].length = len; (*stack_curr)++; *curr += len; if (*curr == size) { /* finish up */ while (*stack_curr > 1) { TIM_SORT_MERGE(w, dst, run_stack, *stack_curr, store); run_stack[*stack_curr - 2].length += run_stack[*stack_curr - 1].length; (*stack_curr)--; } if (store->storage != NULL) { acton_free(store->storage); store->storage = NULL; } return 0; } return 1; } void TIM_SORT(B_Ord w, SORT_TYPE *dst, const size_t size) { size_t minrun; TEMP_STORAGE_T _store, *store; TIM_SORT_RUN_T run_stack[TIM_SORT_STACK_SIZE]; size_t stack_curr = 0; size_t curr = 0; /* don't bother sorting an array of size 1 */ if (size <= 1) { return; } if (size < 64) { BINARY_INSERTION_SORT(w, dst, size); return; } /* compute the minimum run length */ minrun = compute_minrun(size); /* temporary storage for merges */ store = &_store; store->alloc = 0; store->storage = NULL; if (!PUSH_NEXT(w, dst, size, store, minrun, run_stack, &stack_curr, &curr)) { return; } if (!PUSH_NEXT(w, dst, size, store, minrun, run_stack, &stack_curr, &curr)) { return; } if (!PUSH_NEXT(w, dst, size, store, minrun, run_stack, &stack_curr, &curr)) { return; } while (1) { if (!CHECK_INVARIANT(run_stack, stack_curr)) { stack_curr = TIM_SORT_COLLAPSE(w, dst, run_stack, stack_curr, store, size); continue; } if (!PUSH_NEXT(w, dst, size, store, minrun, run_stack, &stack_curr, &curr)) { return; } } } #undef SORT_CONCAT #undef SORT_MAKE_STR1 #undef SORT_MAKE_STR #undef SORT_NAME #undef SORT_TYPE #undef SORT_CMP #undef TEMP_STORAGE_T #undef TIM_SORT_RUN_T #undef PUSH_NEXT #undef SORT_SWAP #undef SORT_CONCAT #undef SORT_MAKE_STR1 #undef SORT_MAKE_STR #undef BINARY_INSERTION_FIND #undef BINARY_INSERTION_SORT_START #undef BINARY_INSERTION_SORT #undef REVERSE_ELEMENTS #undef COUNT_RUN #undef TIM_SORT #undef TIM_SORT_RESIZE #undef TIM_SORT_COLLAPSE #undef TIM_SORT_RUN_T #undef TEMP_STORAGE_T ================================================ FILE: base/builtin/tuple.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include B_NoneType B_tupleD___init__(B_tuple self,int size ,...) { va_list args; va_start(args,size); self->size = size; self->components = acton_malloc(size*sizeof($WORD)); for (int i=0; icomponents[i] = va_arg(args,$WORD); va_end(args); return B_None; } B_bool B_tupleD___bool__(B_tuple self) { return toB_bool(self->size>0); } B_str B_tupleD___str__(B_tuple self) { B_list s2 = B_listD_new(self->size); B_SequenceD_list wit = B_SequenceD_listG_witness; for (int i=0; i< self->size; i++) { B_value elem = (B_value)self->components[i]; if (elem == NULL) { wit->$class->append(wit,s2,to$str("None")); } else { wit->$class->append(wit,s2,elem->$class->__repr__(elem)); } } return B_strD_join_par('(',s2,')'); } void B_tupleD___serialize__(B_tuple self, $Serial$state state) { B_int prevkey = (B_int)B_dictD_get(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,NULL); if (prevkey) { $val_serialize(-TUPLE_ID,&prevkey->val,state); return; } B_dictD_setitem(state->done,(B_Hashable)B_HashableD_WORDG_witness,self,toB_int(state->row_no)); long len = (long)self->size; $val_serialize(TUPLE_ID,&len,state); for (int i=0; isize; i++) { $step_serialize(self->components[i],state); } } B_tuple B_tupleD___deserialize__(B_tuple self, $Serial$state state) { $ROW this = state->row; state->row = this->next; state->row_no++; if (this->class_id < 0) { return (B_tuple)B_dictD_get(state->done,(B_Hashable)B_HashableD_intG_witness,toB_int((long)this->blob[0]),NULL); } else { int len = (int)(long)this->blob[0]; B_tuple res = acton_malloc(sizeof(struct B_tuple)); B_dictD_setitem(state->done,(B_Hashable)B_HashableD_intG_witness,toB_int(state->row_no-1),res); res->components = acton_malloc(len * sizeof($WORD)); res->$class = &B_tupleG_methods; res->size = len; for (int i = 0; i < len; i++) res->components[i] = $step_deserialize(state); return res; } } struct B_tupleG_class B_tupleG_methods = { "tuple", UNASSIGNED, ($SuperG_class)&B_valueG_methods, B_tupleD___init__, B_tupleD___serialize__, B_tupleD___deserialize__, B_tupleD___bool__, B_tupleD___str__, B_tupleD___str__ }; // Iterators over tuples /////////////////////////////////////////////////////// static $WORD B_IteratorD_tupleD_next(B_IteratorD_tuple self) { return self->nxt >= self->src->size ? NULL : self->src->components[self->nxt++]; } B_NoneType B_IteratorD_tupleD_init(B_IteratorD_tuple self, B_tuple lst) { self->src = lst; self->nxt = 0; return B_None; } B_bool B_IteratorD_tupleD_bool(B_IteratorD_tuple self) { return B_True; } B_str B_IteratorD_tupleD_str(B_IteratorD_tuple self) { return $FORMAT("", self); } void B_IteratorD_tupleD_serialize(B_IteratorD_tuple self,$Serial$state state) { $step_serialize(self->src,state); $step_serialize(toB_int(self->nxt),state); } B_IteratorD_tuple B_IteratorD_tuple$_deserialize(B_IteratorD_tuple res, $Serial$state state) { if (!res) res = $DNEW(B_IteratorD_tuple,state); res->src = $step_deserialize(state); res->nxt = fromB_int((B_int)$step_deserialize(state)); return res; } struct B_IteratorD_tupleG_class B_IteratorD_tupleG_methods = {"B_IteratorD_tuple",UNASSIGNED,($SuperG_class)&B_IteratorG_methods,B_IteratorD_tupleD_init, B_IteratorD_tupleD_serialize,B_IteratorD_tuple$_deserialize,B_IteratorD_tupleD_bool,B_IteratorD_tupleD_str,B_IteratorD_tupleD_str,B_IteratorD_tupleD_next}; // Iterable /////////////////////////////////////////////////////////////// B_Iterator B_IterableD_tupleD___iter__(B_IterableD_tuple wit, B_tuple self) { return (B_Iterator)$NEW(B_IteratorD_tuple,self); } B_NoneType B_IterableD_tupleD___init__(B_IterableD_tuple self) { return B_None; } void B_IterableD_tupleD___serialize__(B_IterableD_tuple self, $Serial$state state) { } B_IterableD_tuple B_IterableD_tupleD___deserialize__(B_IterableD_tuple self, $Serial$state state) { B_IterableD_tuple res = $DNEW(B_IterableD_tuple,state); return res; } struct B_IterableD_tupleG_class B_IterableD_tupleG_methods = { "B_IterableD_tuple", UNASSIGNED, ($SuperG_class)&B_IterableG_methods, B_IterableD_tupleD___init__, B_IterableD_tupleD___serialize__, B_IterableD_tupleD___deserialize__, (B_bool (*)(B_IterableD_tuple))$default__bool__, (B_str (*)(B_IterableD_tuple))$default__str__, (B_str (*)(B_IterableD_tuple))$default__str__, B_IterableD_tupleD___iter__ }; //struct B_IterableD_tuple B_IterableD_tuple$instance = {&B_IterableD_tupleG_methods}; //struct B_IterableD_tuple *B_IterableD_tupleG_witness = &B_IterableD_tuple$instance; // Sliceable /////////////////////////////////////////////////////////////// void B_SliceableD_tupleD___serialize__(B_SliceableD_tuple self, $Serial$state state) { } B_SliceableD_tuple B_SliceableD_tupleD___deserialize__(B_SliceableD_tuple self, $Serial$state state) { B_SliceableD_tuple res = $DNEW(B_SliceableD_tuple,state); return res; } B_NoneType B_SliceableD_tupleD___init__ (B_SliceableD_tuple wit) { return B_None; } $WORD B_SliceableD_tupleD___getitem__ (B_SliceableD_tuple wit, B_tuple self, B_int n) { int size = self->size; int ix = fromB_int(n); int ix0 = ix < 0 ? size + ix : ix; if (ix0 < 0 || ix0 >= size) { $RAISE((B_BaseException)$NEW(B_IndexError, toB_int(ix0), to$str("tuple.getitem: index outside tuple"))); } return self->components[ix0]; } B_NoneType B_SliceableD_tupleD___setitem__ (B_SliceableD_tuple wit, B_tuple self, B_int ix, $WORD elem) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method setitem on tuple"))); return B_None; } B_NoneType B_SliceableD_tupleD___delitem__ (B_SliceableD_tuple wit, B_tuple self, B_int ix) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method delitem on tuple"))); return B_None; } B_tuple B_SliceableD_tupleD___getslice__ (B_SliceableD_tuple wit, B_tuple self, B_slice slc) { int size = self->size; int64_t start, stop, step, slen; normalize_slice(slc, size, &slen, &start, &stop, &step); //slice notation have been eliminated and default values applied. // slen now is the length of the slice B_tuple res = acton_malloc(sizeof(struct B_tuple)); res->$class = self->$class; res->size = slen; res->components = acton_malloc(slen * sizeof($WORD)); int t = start; for (int i=0; icomponents[i] = self->components[t]; t += step; } return res; } B_NoneType B_SliceableD_tupleD___setslice__ (B_SliceableD_tuple wit, B_tuple self, B_Iterable wit2, B_slice slc, $WORD iter) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method setslice on tuple"))); return B_None; } B_NoneType B_SliceableD_tupleD___delslice__ (B_SliceableD_tuple wit, B_tuple self, B_slice slc) { $RAISE((B_BaseException)$NEW(B_NotImplementedError,to$str("call to mutating method delslice on tuple"))); return B_None; } struct B_SliceableD_tupleG_class B_SliceableD_tupleG_methods = { "B_SliceableD_tuple", UNASSIGNED, ($SuperG_class)&B_SliceableG_methods, B_SliceableD_tupleD___init__, B_SliceableD_tupleD___serialize__, B_SliceableD_tupleD___deserialize__, (B_bool (*)(B_SliceableD_tuple))$default__bool__, (B_str (*)(B_SliceableD_tuple))$default__str__, (B_str (*)(B_SliceableD_tuple))$default__str__, B_SliceableD_tupleD___getitem__, B_SliceableD_tupleD___setitem__, B_SliceableD_tupleD___delitem__, B_SliceableD_tupleD___getslice__, B_SliceableD_tupleD___setslice__, B_SliceableD_tupleD___delslice__ }; // Hashable /////////////////////////////////////////////////////////////// B_NoneType B_HashableD_tupleD___init__ (B_HashableD_tuple wit, int n, B_Hashable *comps) { wit->W_HashableB_tuple$size = n; wit->W_Hashable = comps; return B_None; } void B_HashableD_tupleD___serialize__(B_HashableD_tuple self, $Serial$state state) { $step_serialize(toB_int(self->W_HashableB_tuple$size), state); // we need to serialize the array of Hashables!! } B_HashableD_tuple B_HashableD_tupleD___deserialize__(B_HashableD_tuple self, $Serial$state state) { B_HashableD_tuple res = $DNEW(B_HashableD_tuple,state); res->W_HashableB_tuple$size = fromB_int($step_deserialize(state)); res->W_Hashable = NULL; // We do not get hash functions for the tuple! return res; } B_bool B_HashableD_tupleD___eq__ (B_HashableD_tuple wit, B_tuple tup1, B_tuple tup2) { //type-checking guarantees that sizes are equal for (int i=0; isize; i++) if (!wit->W_Hashable[i]->$class->__eq__(wit->W_Hashable[i],tup1->components[i],tup2->components[i])) return B_False; return B_True; } B_bool B_HashableD_tupleD___ne__ (B_HashableD_tuple wit, B_tuple tup1, B_tuple tup2) { return toB_bool(!fromB_bool(B_HashableD_tupleD___eq__(wit,tup1,tup2))); } // B_int B_HashableD_tupleD___hash__ (B_HashableD_tuple wit, B_tuple tup) { // return toB_int(B_tupleD_hash(wit,tup)); // } struct B_HashableD_tupleG_class B_HashableD_tupleG_methods = { "B_HashableD_tuple", UNASSIGNED, ($SuperG_class)&B_HashableG_methods, B_HashableD_tupleD___init__, B_HashableD_tupleD___serialize__, B_HashableD_tupleD___deserialize__, (B_bool (*)(B_HashableD_tuple))$default__bool__, (B_str (*)(B_HashableD_tuple))$default__str__, (B_str (*)(B_HashableD_tuple))$default__str__, B_HashableD_tupleD___eq__, B_HashableD_tupleD___ne__ }; ================================================ FILE: base/builtin/tuple.h ================================================ struct B_tupleG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__)(B_tuple,int,...); void (*__serialize__)(B_tuple,$Serial$state); B_tuple (*__deserialize__)(B_tuple,$Serial$state); B_bool (*__bool__)(B_tuple); B_str (*__str__)(B_tuple); B_str (*__repr__)(B_tuple); }; struct B_tuple { struct B_tupleG_class *$class; int size; $WORD *components; }; extern struct B_tupleG_class B_tupleG_methods; B_tuple B_tupleG_new(int,...); #define $NEWTUPLE(B_len, ...) ({ B_tuple $t = acton_malloc(sizeof(struct B_tuple)+B_len*sizeof($WORD)); \ $t->$class = &B_tupleG_methods; \ $t->$class->__init__($t, B_len, __VA_ARGS__); \ $t; }) #define $NEWTUPLE0 ({ B_tuple $t = acton_malloc(sizeof(struct B_tuple)); \ $t->$class = &B_tupleG_methods; \ $t->$class->__init__($t,0); \ $t; }) // struct definitions for tuple protocol instances are not in __builtin__.h // (They cannot be expressed in __builtin__.act for lack of syntax) struct B_IterableD_tuple; typedef struct B_IterableD_tuple *B_IterableD_tuple; struct B_IterableD_tupleG_class; typedef struct B_IterableD_tupleG_class *B_IterableD_tupleG_class; struct B_SliceableD_tuple; typedef struct B_SliceableD_tuple *B_SliceableD_tuple; struct B_SliceableD_tupleG_class; typedef struct B_SliceableD_tupleG_class *B_SliceableD_tupleG_class; struct B_HashableD_tuple; typedef struct B_HashableD_tuple *B_HashableD_tuple; struct B_HashableD_tupleG_class; typedef struct B_HashableD_tupleG_class *B_HashableD_tupleG_class; // B_IterableD_tuple //////////////////////////////////////////////////////////// struct B_IterableD_tuple { B_IterableD_tupleG_class $class; }; struct B_IterableD_tupleG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__)(B_IterableD_tuple); void (*__serialize__)(B_IterableD_tuple,$Serial$state); B_IterableD_tuple (*__deserialize__)(B_IterableD_tuple,$Serial$state); B_bool (*__bool__)(B_IterableD_tuple); B_str (*__str__)(B_IterableD_tuple); B_str (*__repr__)(B_IterableD_tuple); B_Iterator (*__iter__)(B_IterableD_tuple, B_tuple); }; B_NoneType B_IterableD_tupleD___init__ (B_IterableD_tuple); void B_IterableD_tupleD___serialize__(B_IterableD_tuple, $Serial$state); B_IterableD_tuple B_IterableD_tupleD___deserialize__(B_IterableD_tuple, $Serial$state); B_Iterator B_IterableD_tupleD___iter__ (B_IterableD_tuple, B_tuple); extern struct B_IterableD_tupleG_class B_IterableD_tupleG_methods; B_IterableD_tuple B_IterableD_tupleG_new(); // B_SliceableD_tuple //////////////////////////////////////////////////////////// // all methods except getitem and getslice will raise NotImplementedError struct B_SliceableD_tuple { B_SliceableD_tupleG_class $class; }; struct B_SliceableD_tupleG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__)(B_SliceableD_tuple); void (*__serialize__)(B_SliceableD_tuple,$Serial$state); B_SliceableD_tuple (*__deserialize__)(B_SliceableD_tuple,$Serial$state); B_bool (*__bool__)(B_SliceableD_tuple); B_str (*__str__)(B_SliceableD_tuple); B_str (*__repr__)(B_SliceableD_tuple); $WORD (*__getitem__)(B_SliceableD_tuple, B_tuple, B_int); B_NoneType (*__setitem__)(B_SliceableD_tuple, B_tuple, B_int, $WORD); B_NoneType (*__delitem__)(B_SliceableD_tuple, B_tuple, B_int); B_tuple (*__getslice__)(B_SliceableD_tuple, B_tuple, B_slice); B_NoneType (*__setslice__)(B_SliceableD_tuple, B_tuple, B_Iterable, B_slice, $WORD); B_NoneType (*__delslice__)(B_SliceableD_tuple, B_tuple, B_slice); }; B_NoneType B_SliceableD_tupleD___init__ (B_SliceableD_tuple); void B_SliceableD_tupleD___serialize__(B_SliceableD_tuple, $Serial$state); B_SliceableD_tuple B_SliceableD_tupleD___deserialize__(B_SliceableD_tuple, $Serial$state); $WORD B_SliceableD_tupleD___getitem__ (B_SliceableD_tuple, B_tuple, B_int); B_NoneType B_SliceableD_tupleD___setitem__ (B_SliceableD_tuple, B_tuple, B_int, $WORD); B_NoneType B_SliceableD_tupleD___delitem__ (B_SliceableD_tuple, B_tuple, B_int); B_tuple B_SliceableD_tupleD___getslice__ (B_SliceableD_tuple, B_tuple, B_slice); B_NoneType B_SliceableD_tupleD___setslice__ (B_SliceableD_tuple, B_tuple, B_Iterable, B_slice, $WORD); B_NoneType B_SliceableD_tupleD___delslice__ (B_SliceableD_tuple, B_tuple, B_slice); extern struct B_SliceableD_tupleG_class B_SliceableD_tupleG_methods; B_SliceableD_tuple B_SliceableD_tupleG_new(); // B_HashableD_tuple //////////////////////////////////////////////////////////// struct B_HashableD_tuple { B_HashableD_tupleG_class $class; int W_HashableB_tuple$size; B_Hashable *W_Hashable; }; struct B_HashableD_tupleG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__)(B_HashableD_tuple,int,B_Hashable*); void (*__serialize__)(B_HashableD_tuple,$Serial$state); B_HashableD_tuple (*__deserialize__)(B_HashableD_tuple,$Serial$state); B_bool (*__bool__)(B_HashableD_tuple); B_str (*__str__)(B_HashableD_tuple); B_str (*__repr__)(B_HashableD_tuple); B_bool (*__eq__)(B_HashableD_tuple, B_tuple, B_tuple); B_bool (*__ne__)(B_HashableD_tuple, B_tuple, B_tuple); B_NoneType (*hash) (B_HashableD_tuple, B_tuple, B_hasher); }; B_NoneType B_HashableD_tupleD___init__ (B_HashableD_tuple,int,B_Hashable*); void B_HashableD_tupleD___serialize__(B_HashableD_tuple, $Serial$state); B_HashableD_tuple B_HashableD_tupleD___deserialize__(B_HashableD_tuple, $Serial$state); B_bool B_HashableD_tupleD___eq__ (B_HashableD_tuple, B_tuple, B_tuple); B_bool B_HashableD_tupleD___ne__ (B_HashableD_tuple, B_tuple, B_tuple); B_NoneType B_HashableD_tupleD_hash (B_HashableD_tuple, B_tuple, B_hasher); extern struct B_HashableD_tupleG_class B_HashableD_tupleG_methods; B_HashableD_tuple B_HashableD_tupleG_new(); extern struct B_IterableD_tupleG_class B_IterableD_tupleG_methods; B_IterableD_tuple B_IterableD_tupleG_new(); extern struct B_SliceableD_tupleG_class B_SliceableD_tupleG_methods; B_SliceableD_tuple B_SliceableD_tupleG_new(); extern struct B_HashableD_tupleG_class B_HashableD_tupleG_methods; B_HashableD_tuple B_HashableD_tupleG_new(); extern struct B_HashableD_tuple *B_HashableD_tuple_new(int,B_Hashable*); // Iterators over tuples /////////////////////////////////////////////////////// typedef struct B_IteratorD_tuple *B_IteratorD_tuple; struct B_IteratorD_tupleG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__)(B_IteratorD_tuple, B_tuple); void (*__serialize__)(B_IteratorD_tuple,$Serial$state); B_IteratorD_tuple (*__deserialize__)(B_IteratorD_tuple,$Serial$state); B_bool (*__bool__)(B_IteratorD_tuple); B_str (*__str__)(B_IteratorD_tuple); B_str (*__repr__)(B_IteratorD_tuple); $WORD(*__next__)(B_IteratorD_tuple); }; struct B_IteratorD_tuple { struct B_IteratorD_tupleG_class *$class; B_tuple src; int nxt; }; extern struct B_IteratorD_tupleG_class B_IteratorD_tupleG_methods; B_IteratorD_tuple B_IteratorD_tupleG_new(B_tuple); ================================================ FILE: base/builtin/u1.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Auxiliary ////////////////////////////////////////////////////////////////////////////// // only called with e>=0. uint8_t u1_pow(uint8_t a, uint8_t e) { if (e == 0) return 1; return a; } // General methods /////////////////////////////////////////////////////////////////////// B_u1 B_u1G_new(B_atom a, B_int base) { B_bigint b = B_bigintG_new(a, base); long sz = b->val.size; if (sz == 0) return toB_u1(0); unsigned long n = b->val.n[0]; if (sz != 1 || n > 1) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "u1(): value %s out of range for type u1",get_str(&b->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_u1(n); } B_NoneType B_u1D___init__(B_u1 self, B_atom a, B_int base){ self->val = B_u1G_new(a,base)->val; return B_None; } void B_u1D___serialize__(B_u1 n, $Serial$state state) { $val_serialize(U1_ID,&n->val,state); } B_u1 B_u1D___deserialize__(B_u1 n, $Serial$state state) { return toB_u1((uint8_t)$val_deserialize(state)); } B_bool B_u1D___bool__(B_u1 n) { return toB_bool(n->val); } B_str B_u1D___str__(B_u1 n) { return $FORMAT("%d", n->val); } B_str B_u1D___repr__(B_u1 n) { return $FORMAT("%d", n->val); } B_u1 toB_u1(uint8_t i) { B_u1 res = acton_malloc(sizeof(struct B_u1)); res->$class = &B_u1G_methods; res->val = i; return res; } uint8_t fromB_u1(B_u1 w) { return w->val; } // B_IntegralD_u1 ///////////////////////////////////////////////////////////////////////// B_u1 B_IntegralD_u1D___add__(B_IntegralD_u1 wit, B_u1 a, B_u1 b) { return toB_u1((a->val + b->val)%2); } B_u1 B_IntegralD_u1D___zero__(B_IntegralD_u1 wit) { return toB_u1(0); } B_complex B_IntegralD_u1D___complex__(B_IntegralD_u1 wit, B_u1 a) { return toB_complex((double)a->val); } B_u1 B_IntegralD_u1D___fromatom__(B_IntegralD_u1 wit, B_atom a) { return B_u1G_new(a,NULL); } B_u1 B_IntegralD_u1D___mul__(B_IntegralD_u1 wit, B_u1 a, B_u1 b) { return toB_u1((a->val * b->val)); } B_u1 B_IntegralD_u1D___pow__(B_IntegralD_u1 wit, B_u1 a, B_u1 b) { return toB_u1(u1_pow(a->val,b->val)); } B_u1 B_IntegralD_u1D___neg__(B_IntegralD_u1 wit, B_u1 a) { if (a->val > 0L) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("u1.neg: cannot negate non-zero value in u1"))); return a; } B_u1 B_IntegralD_u1D___pos__(B_IntegralD_u1 wit, B_u1 a) { return a; } $WORD B_IntegralD_u1D_real(B_IntegralD_u1 wit, B_u1 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } $WORD B_IntegralD_u1D_imag(B_IntegralD_u1 wit, B_u1 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_u1(0)); } $WORD B_IntegralD_u1D___abs__(B_IntegralD_u1 wit, B_u1 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } B_u1 B_IntegralD_u1D_conjugate(B_IntegralD_u1 wit, B_u1 a) { return a; } B_float B_IntegralD_u1D___float__ (B_IntegralD_u1 wit, B_u1 n) { return to$float((double)n->val); } $WORD B_IntegralD_u1D___trunc__ (B_IntegralD_u1 wit, B_u1 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u1D___floor__ (B_IntegralD_u1 wit, B_u1 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u1D___ceil__ (B_IntegralD_u1 wit, B_u1 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } B_u1 B_IntegralD_u1D___round__ (B_IntegralD_u1 wit, B_u1 n, B_int p) { uint8_t nval = n->val; long pval = p==NULL ? 0 : fromB_int(p); if (pval>=0) return n; uint8_t p10 = u1_pow(10,-pval); uint8_t res = nval/p10; if (nval%p10 * 2 > p10) res++; return toB_u1 (res * p10); // is this what we want? } $WORD B_IntegralD_u1D_numerator (B_IntegralD_u1 wit, B_u1 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u1D_denominator (B_IntegralD_u1 wit, B_u1 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_u1(1L)); } B_int B_IntegralD_u1D___int__ (B_IntegralD_u1 wit, B_u1 n) { return B_intG_new((B_atom)n,NULL); } B_int B_IntegralD_u1D___index__(B_IntegralD_u1 wit, B_u1 n) { return B_intG_new((B_atom)n,NULL); } B_tuple B_IntegralD_u1D___divmod__(B_IntegralD_u1 wit, B_u1 a, B_u1 b) { int n = a->val; int d = b->val; return $NEWTUPLE(2, toB_u1(n/d), toB_u1(n%d)); } B_u1 B_IntegralD_u1D___floordiv__(B_IntegralD_u1 wit, B_u1 a, B_u1 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return toB_u1(a->val / b->val); } B_u1 B_IntegralD_u1D___mod__(B_IntegralD_u1 wit, B_u1 a, B_u1 b) { return toB_u1(a->val % b->val); } B_u1 B_IntegralD_u1D___lshift__(B_IntegralD_u1 wit, B_u1 a, B_int b) { return toB_u1(a->val << fromB_int(b)); } B_u1 B_IntegralD_u1D___rshift__(B_IntegralD_u1 wit, B_u1 a, B_int b) { return toB_u1(a->val >> fromB_int(b)); } B_u1 B_IntegralD_u1D___invert__(B_IntegralD_u1 wit, B_u1 a) { return toB_u1(~a->val); } // B_LogicalD_IntegralD_u1 //////////////////////////////////////////////////////////////////////////////////////// B_u1 B_LogicalD_IntegralD_u1D___and__(B_LogicalD_IntegralD_u1 wit, B_u1 a, B_u1 b) { return toB_u1(a->val & b->val); } B_u1 B_LogicalD_IntegralD_u1D___or__(B_LogicalD_IntegralD_u1 wit, B_u1 a, B_u1 b) { return toB_u1(a->val | b->val); } B_u1 B_LogicalD_IntegralD_u1D___xor__(B_LogicalD_IntegralD_u1 wit, B_u1 a, B_u1 b) { return toB_u1(a->val ^ b->val); } // B_MinusD_IntegralD_u1 //////////////////////////////////////////////////////////////////////////////////////// B_u1 B_MinusD_IntegralD_u1D___sub__(B_MinusD_IntegralD_u1 wit, B_u1 a, B_u1 b) { return toB_u1(a->val - b->val); } // B_DivD_u1 //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_u1D___truediv__ (B_DivD_u1 wit, B_u1 a, B_u1 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return to$float((double)a->val/(double)b->val); } // B_OrdD_u1 //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_u1D___eq__ (B_OrdD_u1 wit, B_u1 a, B_u1 b) { return toB_bool(a->val == b->val); } B_bool B_OrdD_u1D___ne__ (B_OrdD_u1 wit, B_u1 a, B_u1 b) { return toB_bool(a->val != b->val); } B_bool B_OrdD_u1D___lt__ (B_OrdD_u1 wit, B_u1 a, B_u1 b) { return toB_bool(a->val < b->val); } B_bool B_OrdD_u1D___le__ (B_OrdD_u1 wit, B_u1 a, B_u1 b) { return toB_bool(a->val <= b->val); } B_bool B_OrdD_u1D___gt__ (B_OrdD_u1 wit, B_u1 a, B_u1 b) { return toB_bool(a->val > b->val); } B_bool B_OrdD_u1D___ge__ (B_OrdD_u1 wit, B_u1 a, B_u1 b) { return toB_bool(a->val >= b->val); } // B_HashableD_u1 /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_u1D___eq__(B_HashableD_u1 wit, B_u1 a, B_u1 b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_u1D___ne__(B_HashableD_u1 wit, B_u1 a, B_u1 b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_u1D_hash(B_HashableD_u1 wit, B_u1 a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val),1)); return B_None; } ================================================ FILE: base/builtin/u1.h ================================================ struct B_u1 { struct B_u1G_class *$class; uint8_t val; }; B_u1 toB_u1(uint8_t n); uint8_t fromB_u1(B_u1 n); B_u1 B_u1G_new(B_atom a, B_int base); #define u1_DIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u1 truediv: division by zero"))); (double)a;} ) #define u1_FLOORDIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u1 floordiv: division by zero"))); a;} ) #define u1_MOD(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u1 mod: division by zero"))); a;} ) uint8_t u1_pow(uint8_t a, uint8_t b); ================================================ FILE: base/builtin/u16.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Auxiliary ////////////////////////////////////////////////////////////////////////////// // only called with e>=0. unsigned short u16_pow(unsigned short a, unsigned short e) { if (e == 0) return 1; if (e == 1) return a; if (e%2 == 0) return u16_pow(a*a,e/2); return a * u16_pow(a*a,e/2); } // General methods /////////////////////////////////////////////////////////////////////// B_u16 B_u16G_new(B_atom a, B_int base) { B_bigint b = B_bigintG_new(a, base); long sz = b->val.size; if (sz==0) return toB_u16(0); unsigned long n = b->val.n[0]; if (sz != 1 || n > 0xfffful) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "u16(): value %s out of range for type u16",get_str(&b->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_u16((unsigned short)n); } B_NoneType B_u16D___init__(B_u16 self, B_atom a, B_int base){ self->val = B_u16G_new(a,base)->val; return B_None; } void B_u16D___serialize__(B_u16 n, $Serial$state state) { $val_serialize(U16_ID,&n->val,state); } B_u16 B_u16D___deserialize__(B_u16 n, $Serial$state state) { return toB_u16((uint16_t)$val_deserialize(state)); } B_bool B_u16D___bool__(B_u16 n) { return toB_bool(n->val != 0); } B_str B_u16D___str__(B_u16 n) { return $FORMAT("%hu", n->val); } B_str B_u16D___repr__(B_u16 n) { return $FORMAT("%hu", n->val); } B_u16 toB_u16(unsigned short i) { B_u16 res = acton_malloc(sizeof(struct B_u16)); res->$class = &B_u16G_methods; res->val = i; return res; } unsigned short fromB_u16(B_u16 w) { return w->val; } // B_IntegralD_u16 ///////////////////////////////////////////////////////////////////////// B_u16 B_IntegralD_u16D___add__(B_IntegralD_u16 wit, B_u16 a, B_u16 b) { return toB_u16(a->val + b->val); } B_u16 B_IntegralD_u16D___zero__(B_IntegralD_u16 wit) { return toB_u16(0); } B_complex B_IntegralD_u16D___complex__(B_IntegralD_u16 wit, B_u16 a) { return toB_complex((double)a->val); } B_u16 B_IntegralD_u16D___fromatom__(B_IntegralD_u16 wit, B_atom a) { return B_u16G_new(a,NULL); } B_u16 B_IntegralD_u16D___mul__(B_IntegralD_u16 wit, B_u16 a, B_u16 b) { return toB_u16(a->val * b->val); } B_u16 B_IntegralD_u16D___pow__(B_IntegralD_u16 wit, B_u16 a, B_u16 b) { return toB_u16(u16_pow(a->val,b->val)); } B_u16 B_IntegralD_u16D___neg__(B_IntegralD_u16 wit, B_u16 a) { if (a->val > 0L) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("u16.neg: cannot negate non-zero value in u16"))); return a; } B_u16 B_IntegralD_u16D___pos__(B_IntegralD_u16 wit, B_u16 a) { return a; } $WORD B_IntegralD_u16D_real(B_IntegralD_u16 wit, B_u16 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } $WORD B_IntegralD_u16D_imag(B_IntegralD_u16 wit, B_u16 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_u16(0L)); } $WORD B_IntegralD_u16D___abs__(B_IntegralD_u16 wit, B_u16 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } B_u16 B_IntegralD_u16D_conjugate(B_IntegralD_u16 wit, B_u16 a) { return a; } B_float B_IntegralD_u16D___float__ (B_IntegralD_u16 wit, B_u16 n) { return to$float((double)n->val); } $WORD B_IntegralD_u16D___trunc__ (B_IntegralD_u16 wit, B_u16 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u16D___floor__ (B_IntegralD_u16 wit, B_u16 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u16D___ceil__ (B_IntegralD_u16 wit, B_u16 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } B_u16 B_IntegralD_u16D___round__ (B_IntegralD_u16 wit, B_u16 n, B_int p) { unsigned short nval = n->val; short pval = p==NULL ? 0 : fromB_int(p); if (pval>=0) return n; unsigned short p10 = u16_pow(10,-pval); unsigned short res = nval/p10; if (nval%p10 * 2 > p10) res++; return toB_u16 (res * p10); } $WORD B_IntegralD_u16D_numerator (B_IntegralD_u16 wit, B_u16 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u16D_denominator (B_IntegralD_u16 wit, B_u16 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_u16(1L)); } B_int B_IntegralD_u16D___int__ (B_IntegralD_u16 wit, B_u16 n) { return B_intG_new((B_atom)n,NULL); } B_int B_IntegralD_u16D___index__(B_IntegralD_u16 wit, B_u16 n) { return B_intG_new((B_atom)n,NULL); } B_tuple B_IntegralD_u16D___divmod__(B_IntegralD_u16 wit, B_u16 a, B_u16 b) { int n = a->val; int d = b->val; return $NEWTUPLE(2, toB_u16(n/d), toB_u16(n%d)); } B_u16 B_IntegralD_u16D___floordiv__(B_IntegralD_u16 wit, B_u16 a, B_u16 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return toB_u16(a->val / b->val); } B_u16 B_IntegralD_u16D___mod__(B_IntegralD_u16 wit, B_u16 a, B_u16 b) { return toB_u16(a->val % b->val); } B_u16 B_IntegralD_u16D___lshift__(B_IntegralD_u16 wit, B_u16 a, B_int b) { return toB_u16(a->val << fromB_int(b)); } B_u16 B_IntegralD_u16D___rshift__(B_IntegralD_u16 wit, B_u16 a, B_int b) { return toB_u16(a->val >> fromB_int(b)); } B_u16 B_IntegralD_u16D___invert__(B_IntegralD_u16 wit, B_u16 a) { return toB_u16(~a->val); } // B_LogicalD_IntegralD_u16 //////////////////////////////////////////////////////////////////////////////////////// B_u16 B_LogicalD_IntegralD_u16D___and__(B_LogicalD_IntegralD_u16 wit, B_u16 a, B_u16 b) { return toB_u16(a->val & b->val); } B_u16 B_LogicalD_IntegralD_u16D___or__(B_LogicalD_IntegralD_u16 wit, B_u16 a, B_u16 b) { return toB_u16(a->val | b->val); } B_u16 B_LogicalD_IntegralD_u16D___xor__(B_LogicalD_IntegralD_u16 wit, B_u16 a, B_u16 b) { return toB_u16(a->val ^ b->val); } // B_MinusD_IntegralD_u16 //////////////////////////////////////////////////////////////////////////////////////// B_u16 B_MinusD_IntegralD_u16D___sub__(B_MinusD_IntegralD_u16 wit, B_u16 a, B_u16 b) { return toB_u16(a->val - b->val); } // B_DivD_u16 //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_u16D___truediv__ (B_DivD_u16 wit, B_u16 a, B_u16 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return to$float((double)a->val/(double)b->val); } // B_OrdD_u16 //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_u16D___eq__ (B_OrdD_u16 wit, B_u16 a, B_u16 b) { return toB_bool(a->val == b->val); } B_bool B_OrdD_u16D___ne__ (B_OrdD_u16 wit, B_u16 a, B_u16 b) { return toB_bool(a->val != b->val); } B_bool B_OrdD_u16D___lt__ (B_OrdD_u16 wit, B_u16 a, B_u16 b) { return toB_bool(a->val < b->val); } B_bool B_OrdD_u16D___le__ (B_OrdD_u16 wit, B_u16 a, B_u16 b) { return toB_bool(a->val <= b->val); } B_bool B_OrdD_u16D___gt__ (B_OrdD_u16 wit, B_u16 a, B_u16 b) { return toB_bool(a->val > b->val); } B_bool B_OrdD_u16D___ge__ (B_OrdD_u16 wit, B_u16 a, B_u16 b) { return toB_bool(a->val >= b->val); } // B_HashableD_u16 /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_u16D___eq__(B_HashableD_u16 wit, B_u16 a, B_u16 b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_u16D___ne__(B_HashableD_u16 wit, B_u16 a, B_u16 b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_u16D_hash(B_HashableD_u16 wit, B_u16 a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val),2)); return B_None; } ================================================ FILE: base/builtin/u16.h ================================================ struct B_u16 { struct B_u16G_class *$class; unsigned short val; }; B_u16 toB_u16(unsigned short n); unsigned short fromB_u16(B_u16 n); B_u16 B_u16G_new(B_atom a, B_int base); #define u16_DIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u16 truediv: division by zero"))); (double)a/(double)b;} ) #define u16_FLOORDIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u16 floordiv: division by zero"))); a/b;} ) #define u16_MOD(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u16 mod: division by zero"))); a%b;} ) unsigned short u16_pow(unsigned short a, unsigned short b); ================================================ FILE: base/builtin/u32.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Auxiliary ////////////////////////////////////////////////////////////////////////////// // only called with e>=0. unsigned int u32_pow(unsigned int a, unsigned int e) { if (e == 0) return 1; if (e == 1) return a; if (e%2 == 0) return u32_pow(a*a,e/2); return a * u32_pow(a*a,e/2); } // General methods /////////////////////////////////////////////////////////////////////// B_u32 B_u32G_new(B_atom a, B_int base) { B_bigint b = B_bigintG_new(a, base); long sz = b->val.size; if (sz==0) return toB_u32(0); unsigned long n = b->val.n[0]; if ((sz != 1 || n > 0xfffffffful)) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "u32(): value %s out of range for type u32",get_str(&b->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_u32((unsigned int)n); } B_NoneType B_u32D___init__(B_u32 self, B_atom a, B_int base){ self->val = B_u32G_new(a,base)->val; return B_None; } void B_u32D___serialize__(B_u32 n, $Serial$state state) { $val_serialize(U32_ID,&n->val,state); } B_u32 B_u32D___deserialize__(B_u32 n, $Serial$state state) { return toB_u32((int)(uintptr_t)$val_deserialize(state)); } B_bool B_u32D___bool__(B_u32 n) { return toB_bool(n->val != 0); } B_str B_u32D___str__(B_u32 n) { return $FORMAT("%u", n->val); } B_str B_u32D___repr__(B_u32 n) { return $FORMAT("%u", n->val); } B_u32 toB_u32(unsigned int i) { B_u32 res = acton_malloc(sizeof(struct B_u32)); res->$class = &B_u32G_methods; res->val = i; return res; } unsigned int fromB_u32(B_u32 w) { return w->val; } // B_IntegralD_u32 ///////////////////////////////////////////////////////////////////////// B_u32 B_IntegralD_u32D___add__(B_IntegralD_u32 wit, B_u32 a, B_u32 b) { return toB_u32(a->val + b->val); } B_u32 B_IntegralD_u32D___zero__(B_IntegralD_u32 wit) { return toB_u32(0); } B_complex B_IntegralD_u32D___complex__(B_IntegralD_u32 wit, B_u32 a) { return toB_complex((double)a->val); } B_u32 B_IntegralD_u32D___fromatom__(B_IntegralD_u32 wit, B_atom a) { return B_u32G_new(a,NULL); } B_u32 B_IntegralD_u32D___mul__(B_IntegralD_u32 wit, B_u32 a, B_u32 b) { return toB_u32(a->val * b->val); } B_u32 B_IntegralD_u32D___pow__(B_IntegralD_u32 wit, B_u32 a, B_u32 b) { return toB_u32(u32_pow(a->val,b->val)); } B_u32 B_IntegralD_u32D___neg__(B_IntegralD_u32 wit, B_u32 a) { if (a->val > 0L) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("u32.neg: cannot negate non-zero value in u32"))); return a; } B_u32 B_IntegralD_u32D___pos__(B_IntegralD_u32 wit, B_u32 a) { return a; } $WORD B_IntegralD_u32D_real(B_IntegralD_u32 wit, B_u32 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } $WORD B_IntegralD_u32D_imag(B_IntegralD_u32 wit, B_u32 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_u32(0L)); } $WORD B_IntegralD_u32D___abs__(B_IntegralD_u32 wit, B_u32 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } B_u32 B_IntegralD_u32D_conjugate(B_IntegralD_u32 wit, B_u32 a) { return a; } B_float B_IntegralD_u32D___float__ (B_IntegralD_u32 wit, B_u32 n) { return to$float((double)n->val); } $WORD B_IntegralD_u32D___trunc__ (B_IntegralD_u32 wit, B_u32 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u32D___floor__ (B_IntegralD_u32 wit, B_u32 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u32D___ceil__ (B_IntegralD_u32 wit, B_u32 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } B_u32 B_IntegralD_u32D___round__ (B_IntegralD_u32 wit, B_u32 n, B_int p) { unsigned int nval = n->val; int pval = p==NULL ? 0 : fromB_int(p); if (pval>=0) return n; unsigned int p10 = u32_pow(10,-pval); unsigned int res = nval/p10; if (nval%p10 * 2 > p10) res++; return toB_u32 (res * p10); } $WORD B_IntegralD_u32D_numerator (B_IntegralD_u32 wit, B_u32 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u32D_denominator (B_IntegralD_u32 wit, B_u32 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_u32(1L)); } B_int B_IntegralD_u32D___int__ (B_IntegralD_u32 wit, B_u32 n) { return B_intG_new((B_atom)n,NULL); } B_int B_IntegralD_u32D___index__(B_IntegralD_u32 wit, B_u32 n) { return B_intG_new((B_atom)n,NULL); } B_tuple B_IntegralD_u32D___divmod__(B_IntegralD_u32 wit, B_u32 a, B_u32 b) { int n = a->val; int d = b->val; return $NEWTUPLE(2, toB_u32(n/d), toB_u32(n%d)); } B_u32 B_IntegralD_u32D___floordiv__(B_IntegralD_u32 wit, B_u32 a, B_u32 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return toB_u32(a->val / b->val); } B_u32 B_IntegralD_u32D___mod__(B_IntegralD_u32 wit, B_u32 a, B_u32 b) { return toB_u32(a->val % b->val); } B_u32 B_IntegralD_u32D___lshift__(B_IntegralD_u32 wit, B_u32 a, B_int b) { return toB_u32(a->val << fromB_int(b)); } B_u32 B_IntegralD_u32D___rshift__(B_IntegralD_u32 wit, B_u32 a, B_int b) { return toB_u32(a->val >> fromB_int(b)); } B_u32 B_IntegralD_u32D___invert__(B_IntegralD_u32 wit, B_u32 a) { return toB_u32(~a->val); } // B_LogicalD_IntegralD_u32 //////////////////////////////////////////////////////////////////////////////////////// B_u32 B_LogicalD_IntegralD_u32D___and__(B_LogicalD_IntegralD_u32 wit, B_u32 a, B_u32 b) { return toB_u32(a->val & b->val); } B_u32 B_LogicalD_IntegralD_u32D___or__(B_LogicalD_IntegralD_u32 wit, B_u32 a, B_u32 b) { return toB_u32(a->val | b->val); } B_u32 B_LogicalD_IntegralD_u32D___xor__(B_LogicalD_IntegralD_u32 wit, B_u32 a, B_u32 b) { return toB_u32(a->val ^ b->val); } // B_MinusD_IntegralD_u32 //////////////////////////////////////////////////////////////////////////////////////// B_u32 B_MinusD_IntegralD_u32D___sub__(B_MinusD_IntegralD_u32 wit, B_u32 a, B_u32 b) { return toB_u32(a->val - b->val); } // B_DivD_u32 //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_u32D___truediv__ (B_DivD_u32 wit, B_u32 a, B_u32 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return to$float((double)a->val/(double)b->val); } // B_OrdD_u32 //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_u32D___eq__ (B_OrdD_u32 wit, B_u32 a, B_u32 b) { return toB_bool(a->val == b->val); } B_bool B_OrdD_u32D___ne__ (B_OrdD_u32 wit, B_u32 a, B_u32 b) { return toB_bool(a->val != b->val); } B_bool B_OrdD_u32D___lt__ (B_OrdD_u32 wit, B_u32 a, B_u32 b) { return toB_bool(a->val < b->val); } B_bool B_OrdD_u32D___le__ (B_OrdD_u32 wit, B_u32 a, B_u32 b) { return toB_bool(a->val <= b->val); } B_bool B_OrdD_u32D___gt__ (B_OrdD_u32 wit, B_u32 a, B_u32 b) { return toB_bool(a->val > b->val); } B_bool B_OrdD_u32D___ge__ (B_OrdD_u32 wit, B_u32 a, B_u32 b) { return toB_bool(a->val >= b->val); } // B_HashableD_u32 /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_u32D___eq__(B_HashableD_u32 wit, B_u32 a, B_u32 b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_u32D___ne__(B_HashableD_u32 wit, B_u32 a, B_u32 b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_u32D_hash(B_HashableD_u32 wit, B_u32 a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val), 4)); return B_None; } ================================================ FILE: base/builtin/u32.h ================================================ struct B_u32 { struct B_u32G_class *$class; unsigned int val; }; B_u32 toB_u32(unsigned int n); unsigned int fromB_u32(B_u32 n); B_u32 B_u32G_new(B_atom a, B_int base); #define u32_DIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u32 truediv: division by zero"))); (double)a/(double)b;} ) #define u32_FLOORDIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u32 floordiv: division by zero"))); a/b;} ) #define u32_MOD(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u32 mod: division by zero"))); a%b;} ) unsigned int u32_pow(unsigned int a, unsigned int b); ================================================ FILE: base/builtin/u64.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Auxiliary ////////////////////////////////////////////////////////////////////////////// // only called with e>=0. uint64_t u64_pow(uint64_t a, uint64_t e) { if (e == 0) return 1; if (e == 1) return a; if (e%2 == 0) return u64_pow(a*a,e/2); return a * u64_pow(a*a,e/2); } // General methods /////////////////////////////////////////////////////////////////////// B_u64 B_u64G_new(B_atom a, B_int base) { B_bigint b = B_bigintG_new(a, base); long sz = b->val.size; if (sz==0) return toB_u64(0); uint64_t n = b->val.n[0]; if (sz != 1) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "u64(): value %s out of range for type u64",get_str(&b->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_u64(n); } B_NoneType B_u64D___init__(B_u64 self, B_atom a, B_int base){ self->val = B_u64G_new(a,base)->val; return B_None; } void B_u64D___serialize__(B_u64 n, $Serial$state state) { $val_serialize(U64_ID,&n->val,state); } B_u64 B_u64D___deserialize__(B_u64 n, $Serial$state state) { return toB_u64((long)$val_deserialize(state)); } B_bool B_u64D___bool__(B_u64 n) { return toB_bool(n->val != 0); } B_str B_u64D___str__(B_u64 n) { return $FORMAT("%llu", n->val); } B_str B_u64D___repr__(B_u64 n) { return $FORMAT("%llu", n->val); } B_u64 toB_u64(uint64_t i) { B_u64 res = acton_malloc(sizeof(struct B_u64)); res->$class = &B_u64G_methods; res->val = i; return res; } uint64_t fromB_u64(B_u64 w) { return w->val; } // B_IntegralD_u64 ///////////////////////////////////////////////////////////////////////// B_u64 B_IntegralD_u64D___add__(B_IntegralD_u64 wit, B_u64 a, B_u64 b) { return toB_u64(a->val + b->val); } B_u64 B_IntegralD_u64D___zero__(B_IntegralD_u64 wit) { return toB_u64(0); } B_complex B_IntegralD_u64D___complex__(B_IntegralD_u64 wit, B_u64 a) { return toB_complex((double)a->val); } B_u64 B_IntegralD_u64D___fromatom__(B_IntegralD_u64 wit, B_atom a) { return B_u64G_new(a,NULL); } B_u64 B_IntegralD_u64D___mul__(B_IntegralD_u64 wit, B_u64 a, B_u64 b) { return toB_u64(a->val * b->val); } B_u64 B_IntegralD_u64D___pow__(B_IntegralD_u64 wit, B_u64 a, B_u64 b) { return toB_u64(u64_pow(a->val,b->val)); } B_u64 B_IntegralD_u64D___neg__(B_IntegralD_u64 wit, B_u64 a) { if (a->val > 0L) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("u64.neg: cannot negate non-zero value in u64"))); return a; } B_u64 B_IntegralD_u64D___pos__(B_IntegralD_u64 wit, B_u64 a) { return a; } $WORD B_IntegralD_u64D_real(B_IntegralD_u64 wit, B_u64 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } $WORD B_IntegralD_u64D_imag(B_IntegralD_u64 wit, B_u64 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_u64(0L)); } $WORD B_IntegralD_u64D___abs__(B_IntegralD_u64 wit, B_u64 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } B_u64 B_IntegralD_u64D_conjugate(B_IntegralD_u64 wit, B_u64 a) { return a; } B_float B_IntegralD_u64D___float__ (B_IntegralD_u64 wit, B_u64 n) { return to$float((double)n->val); } $WORD B_IntegralD_u64D___trunc__ (B_IntegralD_u64 wit, B_u64 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u64D___floor__ (B_IntegralD_u64 wit, B_u64 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u64D___ceil__ (B_IntegralD_u64 wit, B_u64 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } B_u64 B_IntegralD_u64D___round__ (B_IntegralD_u64 wit, B_u64 n, B_int p) { uint64_t nval = n->val; long pval = p==NULL ? 0 : fromB_int(p); if (pval>=0) return n; uint64_t p10 = u64_pow(10,-pval); uint64_t res = nval/p10; if (nval%p10 * 2 > p10) res++; return toB_u64 (res * p10); } $WORD B_IntegralD_u64D_numerator (B_IntegralD_u64 wit, B_u64 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u64D_denominator (B_IntegralD_u64 wit, B_u64 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_u64(1L)); } B_int B_IntegralD_u64D___int__ (B_IntegralD_u64 wit, B_u64 n) { if (n->val > 0x7ffffffffffffffful) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("u64 value too large to be converted to int"))); return toB_int(n->val); } B_int B_IntegralD_u64D___index__(B_IntegralD_u64 wit, B_u64 n) { if (n->val > 0x7ffffffffffffffful) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("u64 value too large to be converted to int"))); return toB_int(n->val); } B_tuple B_IntegralD_u64D___divmod__(B_IntegralD_u64 wit, B_u64 a, B_u64 b) { int n = a->val; int d = b->val; return $NEWTUPLE(2, toB_u64(n/d), toB_u64(n%d)); } B_u64 B_IntegralD_u64D___floordiv__(B_IntegralD_u64 wit, B_u64 a, B_u64 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return toB_u64(a->val / b->val); } B_u64 B_IntegralD_u64D___mod__(B_IntegralD_u64 wit, B_u64 a, B_u64 b) { return toB_u64(a->val % b->val); } B_u64 B_IntegralD_u64D___lshift__(B_IntegralD_u64 wit, B_u64 a, B_int b) { return toB_u64(a->val << fromB_int(b)); } B_u64 B_IntegralD_u64D___rshift__(B_IntegralD_u64 wit, B_u64 a, B_int b) { return toB_u64(a->val >> fromB_int(b)); } B_u64 B_IntegralD_u64D___invert__(B_IntegralD_u64 wit, B_u64 a) { return toB_u64(~a->val); } // B_LogicalD_IntegralD_u64 //////////////////////////////////////////////////////////////////////////////////////// B_u64 B_LogicalD_IntegralD_u64D___and__(B_LogicalD_IntegralD_u64 wit, B_u64 a, B_u64 b) { return toB_u64(a->val & b->val); } B_u64 B_LogicalD_IntegralD_u64D___or__(B_LogicalD_IntegralD_u64 wit, B_u64 a, B_u64 b) { return toB_u64(a->val | b->val); } B_u64 B_LogicalD_IntegralD_u64D___xor__(B_LogicalD_IntegralD_u64 wit, B_u64 a, B_u64 b) { return toB_u64(a->val ^ b->val); } // B_MinusD_IntegralD_u64 //////////////////////////////////////////////////////////////////////////////////////// B_u64 B_MinusD_IntegralD_u64D___sub__(B_MinusD_IntegralD_u64 wit, B_u64 a, B_u64 b) { return toB_u64(a->val - b->val); } // B_DivD_u64 //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_u64D___truediv__ (B_DivD_u64 wit, B_u64 a, B_u64 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return to$float((double)a->val/(double)b->val); } // B_OrdD_u64 //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_u64D___eq__ (B_OrdD_u64 wit, B_u64 a, B_u64 b) { return toB_bool(a->val == b->val); } B_bool B_OrdD_u64D___ne__ (B_OrdD_u64 wit, B_u64 a, B_u64 b) { return toB_bool(a->val != b->val); } B_bool B_OrdD_u64D___lt__ (B_OrdD_u64 wit, B_u64 a, B_u64 b) { return toB_bool(a->val < b->val); } B_bool B_OrdD_u64D___le__ (B_OrdD_u64 wit, B_u64 a, B_u64 b) { return toB_bool(a->val <= b->val); } B_bool B_OrdD_u64D___gt__ (B_OrdD_u64 wit, B_u64 a, B_u64 b) { return toB_bool(a->val > b->val); } B_bool B_OrdD_u64D___ge__ (B_OrdD_u64 wit, B_u64 a, B_u64 b) { return toB_bool(a->val >= b->val); } // B_HashableD_u64 /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_u64D___eq__(B_HashableD_u64 wit, B_u64 a, B_u64 b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_u64D___ne__(B_HashableD_u64 wit, B_u64 a, B_u64 b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_u64D_hash(B_HashableD_u64 wit, B_u64 a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val), 8)); return B_None; } ================================================ FILE: base/builtin/u64.h ================================================ struct B_u64 { struct B_u64G_class *$class; uint64_t val; }; B_u64 toB_u64(uint64_t n); uint64_t fromB_u64(B_u64 n); B_u64 B_u64G_new(B_atom a, B_int base); #define u64_DIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u64 truediv: division by zero"))); (double)a/(double)b;} ) #define u64_FLOORDIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u64 floordiv: division by zero"))); a/b;} ) #define u64_MOD(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u64 mod: division by zero"))); a%b;} ) uint64_t u64_pow(uint64_t a, uint64_t b); ================================================ FILE: base/builtin/u8.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Auxiliary ////////////////////////////////////////////////////////////////////////////// // only called with e>=0. uint8_t u8_pow(uint8_t a, uint8_t e) { if (e == 0) return 1; if (e == 1) return a; if (e%2 == 0) return u8_pow(a*a,e/2); return a * u8_pow(a*a,e/2); } // General methods /////////////////////////////////////////////////////////////////////// B_u8 B_u8G_new(B_atom a, B_int base) { B_bigint b = B_bigintG_new(a, base); long sz = b->val.size; if (sz == 0) return toB_u8(0); unsigned long n = b->val.n[0]; if (sz != 1 || n > UCHAR_MAX) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "u8(): value %s out of range for type u8",get_str(&b->val)); $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg))); } return toB_u8(n); } B_NoneType B_u8D___init__(B_u8 self, B_atom a, B_int base){ self->val = B_u8G_new(a,base)->val; return B_None; } void B_u8D___serialize__(B_u8 n, $Serial$state state) { $val_serialize(U8_ID,&n->val,state); } B_u8 B_u8D___deserialize__(B_u8 n, $Serial$state state) { return toB_u8((uint8_t)$val_deserialize(state)); } B_bool B_u8D___bool__(B_u8 n) { return toB_bool(n->val != 0); } B_str B_u8D___str__(B_u8 n) { return $FORMAT("%u", n->val); } B_str B_u8D___repr__(B_u8 n) { return $FORMAT("%u", n->val); } B_u8 toB_u8(uint8_t i) { B_u8 res = acton_malloc(sizeof(struct B_u8)); res->$class = &B_u8G_methods; res->val = i; return res; } uint8_t fromB_u8(B_u8 w) { return w->val; } // B_IntegralD_u8 ///////////////////////////////////////////////////////////////////////// B_u8 B_IntegralD_u8D___add__(B_IntegralD_u8 wit, B_u8 a, B_u8 b) { return toB_u8(a->val + b->val); } B_u8 B_IntegralD_u8D___zero__(B_IntegralD_u8 wit) { return toB_u8(0); } B_complex B_IntegralD_u8D___complex__(B_IntegralD_u8 wit, B_u8 a) { return toB_complex((double)a->val); } B_u8 B_IntegralD_u8D___fromatom__(B_IntegralD_u8 wit, B_atom a) { return B_u8G_new(a,NULL); } B_u8 B_IntegralD_u8D___mul__(B_IntegralD_u8 wit, B_u8 a, B_u8 b) { return toB_u8(a->val * b->val); } B_u8 B_IntegralD_u8D___pow__(B_IntegralD_u8 wit, B_u8 a, B_u8 b) { return toB_u8(u8_pow(a->val,b->val)); } B_u8 B_IntegralD_u8D___neg__(B_IntegralD_u8 wit, B_u8 a) { if (a->val > 0L) $RAISE((B_BaseException)$NEW(B_ValueError,to$str("u8.neg: cannot negate non-zero value in u8"))); return a; } B_u8 B_IntegralD_u8D___pos__(B_IntegralD_u8 wit, B_u8 a) { return a; } $WORD B_IntegralD_u8D_real(B_IntegralD_u8 wit, B_u8 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } $WORD B_IntegralD_u8D_imag(B_IntegralD_u8 wit, B_u8 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_u8(0L)); } $WORD B_IntegralD_u8D___abs__(B_IntegralD_u8 wit, B_u8 a, B_Real wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)a); } B_u8 B_IntegralD_u8D_conjugate(B_IntegralD_u8 wit, B_u8 a) { return a; } B_float B_IntegralD_u8D___float__ (B_IntegralD_u8 wit, B_u8 n) { return to$float((double)n->val); } $WORD B_IntegralD_u8D___trunc__ (B_IntegralD_u8 wit, B_u8 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u8D___floor__ (B_IntegralD_u8 wit, B_u8 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u8D___ceil__ (B_IntegralD_u8 wit, B_u8 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } B_u8 B_IntegralD_u8D___round__ (B_IntegralD_u8 wit, B_u8 n, B_int p) { uint8_t nval = n->val; long pval = p==NULL ? 0 : fromB_int(p); if (pval>=0) return n; uint8_t p10 = u8_pow(10,-pval); uint8_t res = nval/p10; if (nval%p10 * 2 > p10) res++; return toB_u8 (res * p10); } $WORD B_IntegralD_u8D_numerator (B_IntegralD_u8 wit, B_u8 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)n); } $WORD B_IntegralD_u8D_denominator (B_IntegralD_u8 wit, B_u8 n, B_Integral wit2) { return wit2->$class->__fromatom__(wit2,(B_atom)toB_u8(1L)); } B_int B_IntegralD_u8D___int__ (B_IntegralD_u8 wit, B_u8 n) { return B_intG_new((B_atom)n,NULL); } B_int B_IntegralD_u8D___index__(B_IntegralD_u8 wit, B_u8 n) { return B_intG_new((B_atom)n,NULL); } B_tuple B_IntegralD_u8D___divmod__(B_IntegralD_u8 wit, B_u8 a, B_u8 b) { int n = a->val; int d = b->val; return $NEWTUPLE(2, toB_u8(n/d), toB_u8(n%d)); } B_u8 B_IntegralD_u8D___floordiv__(B_IntegralD_u8 wit, B_u8 a, B_u8 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return toB_u8(a->val / b->val); } B_u8 B_IntegralD_u8D___mod__(B_IntegralD_u8 wit, B_u8 a, B_u8 b) { return toB_u8(a->val % b->val); } B_u8 B_IntegralD_u8D___lshift__(B_IntegralD_u8 wit, B_u8 a, B_int b) { return toB_u8(a->val << fromB_int(b)); } B_u8 B_IntegralD_u8D___rshift__(B_IntegralD_u8 wit, B_u8 a, B_int b) { return toB_u8(a->val >> fromB_int(b)); } B_u8 B_IntegralD_u8D___invert__(B_IntegralD_u8 wit, B_u8 a) { return toB_u8(~a->val); } // B_LogicalD_IntegralD_u8 //////////////////////////////////////////////////////////////////////////////////////// B_u8 B_LogicalD_IntegralD_u8D___and__(B_LogicalD_IntegralD_u8 wit, B_u8 a, B_u8 b) { return toB_u8(a->val & b->val); } B_u8 B_LogicalD_IntegralD_u8D___or__(B_LogicalD_IntegralD_u8 wit, B_u8 a, B_u8 b) { return toB_u8(a->val | b->val); } B_u8 B_LogicalD_IntegralD_u8D___xor__(B_LogicalD_IntegralD_u8 wit, B_u8 a, B_u8 b) { return toB_u8(a->val ^ b->val); } // B_MinusD_IntegralD_u8 //////////////////////////////////////////////////////////////////////////////////////// B_u8 B_MinusD_IntegralD_u8D___sub__(B_MinusD_IntegralD_u8 wit, B_u8 a, B_u8 b) { return toB_u8(a->val - b->val); } // B_DivD_u8 //////////////////////////////////////////////////////////////////////////////////////// B_float B_DivD_u8D___truediv__ (B_DivD_u8 wit, B_u8 a, B_u8 b) { if (b->val == 0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError, to$str("division by zero"))); return to$float((double)a->val/(double)b->val); } // B_OrdD_u8 //////////////////////////////////////////////////////////////////////////////////////// B_bool B_OrdD_u8D___eq__ (B_OrdD_u8 wit, B_u8 a, B_u8 b) { return toB_bool(a->val == b->val); } B_bool B_OrdD_u8D___ne__ (B_OrdD_u8 wit, B_u8 a, B_u8 b) { return toB_bool(a->val != b->val); } B_bool B_OrdD_u8D___lt__ (B_OrdD_u8 wit, B_u8 a, B_u8 b) { return toB_bool(a->val < b->val); } B_bool B_OrdD_u8D___le__ (B_OrdD_u8 wit, B_u8 a, B_u8 b) { return toB_bool(a->val <= b->val); } B_bool B_OrdD_u8D___gt__ (B_OrdD_u8 wit, B_u8 a, B_u8 b) { return toB_bool(a->val > b->val); } B_bool B_OrdD_u8D___ge__ (B_OrdD_u8 wit, B_u8 a, B_u8 b) { return toB_bool(a->val >= b->val); } // B_HashableD_u8 /////////////////////////////////////////////////////////////////////////////////////////////////////// B_bool B_HashableD_u8D___eq__(B_HashableD_u8 wit, B_u8 a, B_u8 b) { return toB_bool(a->val == b->val); } B_bool B_HashableD_u8D___ne__(B_HashableD_u8 wit, B_u8 a, B_u8 b) { return toB_bool(a->val != b->val); } B_NoneType B_HashableD_u8D_hash(B_HashableD_u8 wit, B_u8 a, B_hasher h) { zig_hash_wyhash_update(h->_hasher, to$bytesD_len((char *)&(a->val),1)); return B_None; } ================================================ FILE: base/builtin/u8.h ================================================ struct B_u8 { struct B_u8G_class *$class; uint8_t val; }; B_u8 toB_u8(uint8_t n); uint8_t fromB_u8(B_u8 n); B_u8 B_u8G_new(B_atom a, B_int base); #define u8_DIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u8 truediv: division by zero"))); (double)a/(double)b;} ) #define u8_FLOORDIV(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u8 floordiv: division by zero"))); a/b;} ) #define u8_MOD(a,b) ( {if (b==0) $RAISE((B_BaseException)$NEW(B_ZeroDivisionError,to$str("u8 mod: division by zero"))); a%b;} ) uint8_t u8_pow(uint8_t a, uint8_t b); ================================================ FILE: base/builtin/utils.c ================================================ B_list B_mk_list(int len, ...) { B_list res = B_listD_new(len); res->length = len; va_list args; va_start(args, len); for (int i = 0; i < len; i++) res->data[i] = va_arg(args, $WORD); return res; } B_set B_mk_set(int len, B_Hashable w,...) { B_set res = B_setG_new(w, NULL, NULL); va_list args; va_start(args, w); for (int i=0; i < len; i++) { $WORD elem = va_arg(args, $WORD); B_set_add_entry(res,w,elem,fromB_u64(B_hash(w, elem))); } return res; } B_dict B_mk_dict(int len, B_Hashable w,...) { B_dict res = acton_malloc(sizeof(struct B_dict)); res->$class = &B_dictG_methods; res->numelements = 0; res->table = NULL; va_list args; va_start(args, w); for (int i=0; i < len; i++) { B_tuple t = va_arg(args, B_tuple); B_dictD_setitem(res, w, t->components[0], t->components[1]); } return res; } ================================================ FILE: base/builtin/utils.h ================================================ B_list B_mk_list(int len,...); B_dict B_mk_dict(int len, B_Hashable w,...); B_set B_mk_set(int len, B_Hashable w,...); ================================================ FILE: base/rts/common.c ================================================ #include #include #ifdef __linux__ #include #endif #include #define LIBXML_STATIC #include #include #include "rts/common.h" #if defined(_WIN32) || defined(_WIN64) #include // strndup() is not available on Windows char *strndup( const char *s1, size_t n) { char *copy= (char*)malloc( n+1 ); memcpy( copy, s1, n ); copy[n] = 0; return copy; }; #endif typedef struct { acton_malloc_func malloc; acton_malloc_func malloc_atomic; acton_realloc_func realloc; acton_calloc_func calloc; acton_free_func free; acton_strdup_func strdup; acton_strndup_func strndup; } acton__allocator_t; static acton__allocator_t acton__allocator = { malloc, malloc, realloc, calloc, free, strdup, strndup }; void acton_noop_free(void *ptr) { } void *GC_calloc(size_t count, size_t size) { return GC_malloc(count*size); } void acton_init_alloc() { // UV & TLSUV are used for IO, which is always done on the GC-heap. We don't // have any constants related to UV, so we can always use the GC uv_replace_allocator(GC_malloc, GC_realloc, GC_calloc, acton_noop_free); tlsuv_set_allocator(GC_malloc, GC_realloc, GC_calloc, acton_noop_free); } int acton_replace_allocator(acton_malloc_func malloc_func, acton_malloc_func malloc_atomic_func, acton_realloc_func realloc_func, acton_calloc_func calloc_func, acton_free_func free_func, acton_strdup_func strdup_func, acton_strndup_func strndup_func) { if (malloc_func == NULL || malloc_atomic_func == NULL || realloc_func == NULL || calloc_func == NULL || free_func == NULL || strdup_func == NULL || strndup_func == NULL ) { return -1; } acton__allocator.malloc = malloc_func; acton__allocator.malloc_atomic = malloc_atomic_func; acton__allocator.realloc = realloc_func; acton__allocator.calloc = calloc_func; acton__allocator.free = free_func; acton__allocator.strdup = strdup_func; acton__allocator.strndup = strndup_func; bsdnt_replace_allocator(acton__allocator.malloc, acton__allocator.realloc, acton__allocator.free); xmlMemSetup(acton__allocator.free, acton__allocator.malloc, acton__allocator.realloc, acton__allocator.strdup); mbedtls_platform_set_calloc_free(acton__allocator.calloc, acton_noop_free); return 0; } void* acton_malloc(size_t size) { return acton__allocator.calloc(1, size); } void* acton_malloc_atomic(size_t size) { return acton__allocator.malloc_atomic(size); } void* acton_realloc(void* ptr, size_t size) { return acton__allocator.realloc(ptr, size); } void* acton_calloc(size_t count, size_t size) { return acton__allocator.calloc(count, size); } void acton_free(void* ptr) { int saved_errno; /* The system allocator the assumption that errno is not modified but custom * allocators may not be so careful. */ saved_errno = errno; acton__allocator.free(ptr); errno = saved_errno; } char *acton_strdup(const char *s) { return acton__allocator.strdup(s); } char *acton_strndup(const char *s, size_t n) { return acton__allocator.strndup(s, n); } void* acton_gc_malloc(size_t size) { return GC_malloc(size); } void* acton_gc_malloc_atomic(size_t size) { return GC_malloc_atomic(size); } void* acton_gc_realloc(void* ptr, size_t size) { return GC_realloc(ptr, size); } void* acton_gc_calloc(size_t count, size_t size) { return GC_calloc(count, size); } void acton_gc_free(void* ptr) { return GC_free(ptr); } char *acton_gc_strdup(const char *s) { return GC_strdup(s); } char *acton_gc_strndup(const char *s, size_t n) { return GC_strndup(s, n); } ================================================ FILE: base/rts/common.h ================================================ #pragma once #include #include #define GC_THREADS 1 #ifdef _WIN32 #include #endif #include typedef void *(*acton_malloc_func)(size_t size); typedef void *(*acton_malloc_func)(size_t size); typedef void *(*acton_realloc_func)(void* ptr, size_t size); typedef void *(*acton_calloc_func)(size_t count, size_t size); typedef void (*acton_free_func)(void* ptr); typedef char *(*acton_strdup_func)(const char* s); typedef char *(*acton_strndup_func)(const char* s, size_t n); void acton_init_malloc(); int acton_replace_allocator(acton_malloc_func malloc_func, acton_malloc_func malloc_atomic_func, acton_realloc_func realloc_func, acton_calloc_func calloc_func, acton_free_func free_func, acton_strdup_func strdup_func, acton_strndup_func strndup_func); void *acton_malloc(size_t size); void *acton_malloc_atomic(size_t size); void *acton_realloc(void* ptr, size_t size); void *acton_calloc(size_t count, size_t size); void acton_free(void* ptr); char *acton_strdup(const char *s); char *acton_strndup(const char *s, size_t n); void *acton_gc_malloc(size_t size); void *acton_gc_malloc_atomic(size_t size); void *acton_gc_realloc(void* ptr, size_t size); void *acton_gc_calloc(size_t count, size_t size); void acton_gc_free(void* ptr); char *acton_gc_strdup(const char *s); char *acton_gc_strndup(const char *s, size_t n); ================================================ FILE: base/rts/gc.zig ================================================ const std = @import("std"); const assert = std.debug.assert; const testing = std.testing; const mem = std.mem; const Allocator = std.mem.Allocator; const gc = @cImport({ @cInclude("gc.h"); }); /// Returns the Allocator used for APIs in Zig pub fn allocator() Allocator { // Initialize libgc if (gc.GC_is_init_called() == 0) { gc.GC_init(); } return Allocator{ .ptr = undefined, .vtable = &gc_allocator_vtable, }; } /// Enable or disable interior pointers. /// If used, this must be called before the first allocator() call. pub fn setAllInteriorPointers(enable_interior_pointers: bool) void { gc.GC_set_all_interior_pointers(@intFromBool(enable_interior_pointers)); } /// Returns the current heap size of used memory. pub fn getHeapSize() u64 { return gc.GC_get_heap_size(); } /// Disable garbage collection. pub fn disable() void { gc.GC_disable(); } /// Enables garbage collection. GC is enabled by default so this is /// only useful if you called disable earlier. pub fn enable() void { gc.GC_enable(); } // Performs a full, stop-the-world garbage collection. With leak detection // enabled this will output any leaks as well. pub fn collect() void { gc.GC_gcollect(); } /// Perform some garbage collection. Returns zero when work is done. pub fn collectLittle() u8 { return @as(u8, @intCast(gc.GC_collect_a_little())); } /// Enables leak-finding mode. See the libgc docs for more details. pub fn setFindLeak(v: bool) void { return gc.GC_set_find_leak(@intFromBool(v)); } // TODO(mitchellh): there are so many more functions to add here // from gc.h, just add em as they're useful. /// GcAllocator is an implementation of std.mem.Allocator that uses /// libgc under the covers. This means that all memory allocated with /// this allocated doesn't need to be explicitly freed (but can be). /// /// The GC is a singleton that is globally shared. Multiple GcAllocators /// do not allocate separate pages of memory; they share the same underlying /// pages. /// // NOTE(mitchellh): this is basically just a copy of the standard CAllocator // since libgc has a malloc/free-style interface. There are very slight differences // due to API differences but overall the same. pub const GcAllocator = struct { fn alloc( _: *anyopaque, len: usize, alignment: mem.Alignment, return_address: usize, ) ?[*]u8 { _ = return_address; assert(len > 0); return alignedAlloc(len, alignment); } fn resize( _: *anyopaque, buf: []u8, alignment: mem.Alignment, new_len: usize, return_address: usize, ) bool { _ = alignment; _ = return_address; if (new_len <= buf.len) { return true; } const full_len = alignedAllocSize(buf.ptr); if (new_len <= full_len) { return true; } return false; } fn free( _: *anyopaque, buf: []u8, alignment: mem.Alignment, return_address: usize, ) void { _ = alignment; _ = return_address; alignedFree(buf.ptr); } fn getHeader(ptr: [*]u8) *[*]u8 { return @as(*[*]u8, @ptrFromInt(@intFromPtr(ptr) - @sizeOf(usize))); } fn alignedAlloc(len: usize, alignment: mem.Alignment) ?[*]u8 { const alignment_bytes = alignment.toByteUnits(); // Thin wrapper around regular malloc, overallocate to account for // alignment padding and store the orignal malloc()'ed pointer before // the aligned address. const unaligned_ptr = @as([*]u8, @ptrCast(gc.GC_malloc(len + alignment_bytes - 1 + @sizeOf(usize)) orelse return null)); const unaligned_addr = @intFromPtr(unaligned_ptr); const aligned_addr = mem.alignForward(usize, unaligned_addr + @sizeOf(usize), alignment_bytes); const aligned_ptr = unaligned_ptr + (aligned_addr - unaligned_addr); getHeader(aligned_ptr).* = unaligned_ptr; return aligned_ptr; } fn alignedFree(ptr: [*]u8) void { const unaligned_ptr = getHeader(ptr).*; gc.GC_free(unaligned_ptr); } fn alignedAllocSize(ptr: [*]u8) usize { const unaligned_ptr = getHeader(ptr).*; const delta = @intFromPtr(ptr) - @intFromPtr(unaligned_ptr); return gc.GC_size(unaligned_ptr) - delta; } fn remap( _: *anyopaque, _: []u8, _: mem.Alignment, _: usize, _: usize, ) ?[*]u8 { return null; } }; const gc_allocator_vtable = Allocator.VTable{ .alloc = GcAllocator.alloc, .resize = GcAllocator.resize, .remap = GcAllocator.remap, .free = GcAllocator.free, }; test "GcAllocator" { const alloc = allocator(); try std.heap.testAllocator(alloc); try std.heap.testAllocatorAligned(alloc); try std.heap.testAllocatorLargeAlignment(alloc); try std.heap.testAllocatorAlignedShrink(alloc); } test "heap size" { // No garbage so should be 0 try testing.expect(collectLittle() == 0); // Force a collection should work collect(); try testing.expect(getHeapSize() > 0); } ================================================ FILE: base/rts/io.c ================================================ #ifdef ACTON_THREADS #define GC_THREADS 1 #endif #include #include "io.h" #include #include #include "log.h" #include "log.h" extern char rts_exit; uv_loop_t *get_uv_loop() { WorkerCtx wctx = GET_WCTX(); return (uv_loop_t *)wctx->uv_loop; } void alloc_buffer(uv_handle_t *handle, size_t size, uv_buf_t *buf) { *buf = uv_buf_init((char*) acton_malloc_atomic(size), size); } ================================================ FILE: base/rts/io.h ================================================ #pragma once #ifdef __linux__ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #endif #define GC_THREADS 1 #include #include #ifdef __gnu_linux__ #define IS_GNU_LINUX #elif __APPLE__ && __MACH__ #define IS_MACOS #endif extern uv_loop_t *aux_uv_loop; uv_loop_t *get_uv_loop(); void alloc_buffer(uv_handle_t *handle, size_t size, uv_buf_t *buf); ================================================ FILE: base/rts/log.c ================================================ /* * Copyright (c) 2020 rxi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifdef ACTON_THREADS #include #endif #include #include "log.h" #define MAX_CALLBACKS 32 #ifdef ACTON_THREADS static pthread_mutex_t l_mutex; #endif typedef struct { log_LogFn fn; void *udata; int level; } Callback; static struct { void *udata; int level; bool quiet; Callback callbacks[MAX_CALLBACKS]; } L; static const char *level_strings[] = { "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" }; #ifdef LOG_USE_COLOR static const char *level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" }; #endif static void stdout_callback(log_Event *ev) { // Get a short thread name char tname[16] = ""; #ifdef ACTON_THREADS pthread_getname_np(pthread_self(), tname, 16); #endif if (strncmp(tname, "IO", 6) == 0) { } else if (strncmp(tname, "Worker", 6) == 0) { strncpy(tname, &tname[7], 4); } else { // main thread, ignore the name strcpy(tname, ""); } char buf[16]; buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->date)] = '\0'; #ifdef LOG_USE_COLOR fprintf( ev->udata, "%s.%06lu %s%-5s\x1b[0m \x1b[90m%-20s:%5d:\x1b[0m RTS %2s: ", buf, ev->ts.tv_nsec/1000, level_colors[ev->level], level_strings[ev->level], ev->file, ev->line, tname); #else fprintf( ev->udata, "%s.%06lu %-5s %-20s:%5d: RTS %2s: ", buf, ev->ts.tv_nsec/1000, level_strings[ev->level], ev->file, ev->line, tname); #endif vfprintf(ev->udata, ev->fmt, ev->ap); fprintf(ev->udata, "\n"); fflush(ev->udata); } static void file_callback(log_Event *ev) { // Get a short thread name char tname[16]; #ifdef ACTON_THREADS pthread_getname_np(pthread_self(), tname, 16); #endif if (strncmp(tname, "IO", 6) == 0) { } else if (strncmp(tname, "Worker", 6) == 0) { strncpy(tname, &tname[7], 4); } else { // main thread, ignore the name strcpy(tname, ""); } char buf[64]; buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->date)] = '\0'; fprintf( ev->udata, "%s.%09lu %-5s %-20s:%5d: RTS %2s: ", buf, ev->ts.tv_nsec, level_strings[ev->level], ev->file, ev->line, tname); vfprintf(ev->udata, ev->fmt, ev->ap); fprintf(ev->udata, "\n"); fflush(ev->udata); } static void lock(void) { #ifdef ACTON_THREADS pthread_mutex_lock(&l_mutex); #endif } static void unlock(void) { #ifdef ACTON_THREADS pthread_mutex_unlock(&l_mutex); #endif } const char* log_level_string(int level) { return level_strings[level]; } int log_get_level() { return L.level; } void log_set_level(int level) { L.level = level; } void log_set_quiet(bool enable) { L.quiet = enable; } int log_add_callback(log_LogFn fn, void *udata, int level) { for (int i = 0; i < MAX_CALLBACKS; i++) { if (!L.callbacks[i].fn) { L.callbacks[i] = (Callback) { fn, udata, level }; return 0; } } return -1; } int log_add_fp(FILE *fp, int level) { return log_add_callback(file_callback, fp, level); } static void init_event(log_Event *ev, void *udata) { if (!ev->date) { uv_clock_gettime(UV_CLOCK_REALTIME, &ev->ts); ev->date = localtime(&ev->ts.tv_sec); } ev->udata = udata; } void log_log(int level, const char *file, int line, const char *fmt, ...) { log_Event ev = { .fmt = fmt, .file = file, .line = line, .level = level, }; lock(); if (!L.quiet && level >= L.level) { init_event(&ev, stderr); va_start(ev.ap, fmt); stdout_callback(&ev); va_end(ev.ap); } for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { Callback *cb = &L.callbacks[i]; if (level >= cb->level) { init_event(&ev, cb->udata); va_start(ev.ap, fmt); cb->fn(&ev); va_end(ev.ap); } } unlock(); } ================================================ FILE: base/rts/log.h ================================================ /** * Copyright (c) 2020 rxi * * This library is free software; you can redistribute it and/or modify it * under the terms of the MIT license. See `log.c` for details. */ #ifndef LOG_H #define LOG_H #ifdef __linux__ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #endif #include #include #include #include #include "../rts/rts.h" #define LOG_VERSION "0.1.0" typedef struct { va_list ap; const char *fmt; const char *file; struct timespec ts; struct tm *date; void *udata; int line; int level; } log_Event; typedef void (*log_LogFn)(log_Event *ev); typedef void (*log_LockFn)(bool lock, void *udata); enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) #define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) #define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) const char* log_level_string(int level); int log_get_level(); void log_set_level(int level); void log_set_quiet(bool enable); int log_add_callback(log_LogFn fn, void *udata, int level); int log_add_fp(FILE *fp, int level); void log_log(int level, const char *file, int line, const char *fmt, ...); #endif ================================================ FILE: base/rts/netstring.c ================================================ /* Streaming API for netstrings. */ #include #include #include #include #include "netstring.h" /* Reads a netstring from a `buffer` of length `buffer_length`. Writes to `netstring_start` a pointer to the beginning of the string in the buffer, and to `netstring_length` the length of the string. Does not allocate any memory. If it reads successfully, then it returns 0. If there is an error, then the return value will be negative. The error values are: NETSTRING_ERROR_TOO_LONG More than 999999999 bytes in a field NETSTRING_ERROR_NO_COLON No colon was found after the number NETSTRING_ERROR_TOO_SHORT Number of bytes greater than buffer length NETSTRING_ERROR_NO_COMMA No comma was found at the end NETSTRING_ERROR_LEADING_ZERO Leading zeros are not allowed NETSTRING_ERROR_NO_LENGTH Length not given at start of netstring If you're sending messages with more than 999999999 bytes -- about 2 GB -- then you probably should not be doing so in the form of a single netstring. This restriction is in place partially to protect from malicious or erroneous input, and partly to be compatible with D. J. Bernstein's reference implementation. Example: if (netstring_read(&buf, &buflen, &str, &len) < 0) failed(); */ int netstring_read(char **pbuffer, size_t *pbuffer_length, char **netstring_start, size_t *netstring_length) { int i; size_t len = 0; char *buffer = *pbuffer; size_t buffer_length = *pbuffer_length; /* Write default values for outputs */ *netstring_start = NULL; *netstring_length = 0; /* Make sure buffer is big enough. Minimum size is 3. */ if (buffer_length < 3) return NETSTRING_ERROR_TOO_SHORT; /* No leading zeros allowed! */ if (buffer[0] == '0' && isdigit(buffer[1])) return NETSTRING_ERROR_LEADING_ZERO; /* The netstring must start with a number */ if (!isdigit(buffer[0])) return NETSTRING_ERROR_NO_LENGTH; /* Read the number of bytes */ for (i = 0; i < buffer_length && isdigit(buffer[i]); i++) { /* Error if more than 9 digits */ if (i >= 9) return NETSTRING_ERROR_TOO_LONG; /* Accumulate each digit, assuming ASCII. */ len = len*10 + (buffer[i] - '0'); } /* Check buffer length once and for all. Specifically, we make sure that the buffer is longer than the number we've read, the length of the string itself, and the colon and comma. */ if (i + len + 1 >= buffer_length) return NETSTRING_ERROR_TOO_SHORT; /* Read the colon */ if (buffer[i++] != ':') return NETSTRING_ERROR_NO_COLON; /* Test for the trailing comma */ if (buffer[i + len] != ',') return NETSTRING_ERROR_NO_COMMA; /* Set the return values */ *netstring_start = &buffer[i]; *netstring_length = len; *pbuffer = *netstring_start + len + 1; *pbuffer_length = buffer_length - (i + len + 1); return 0; } /* Retrieves the size of the concatenated netstrings */ int netstring_list_size(char *buffer, size_t size, size_t *ptotal) { char *str, *base = buffer; size_t len, remaining = size; int rc; while( remaining>0 && (rc=netstring_read(&base, &remaining, &str, &len))==0 ){ } if( rc==NETSTRING_ERROR_NO_LENGTH || rc==NETSTRING_ERROR_TOO_SHORT ) rc = 0; *ptotal = size - remaining; return rc; } /* Retrieves the number of concatenated netstrings */ int netstring_list_count(char *buffer, size_t size, int *pcount) { char *str, *base = buffer; size_t len, remaining = size; int rc, count = 0; while( remaining>0 && (rc=netstring_read(&base, &remaining, &str, &len))==0 ){ count++; } if( rc==NETSTRING_ERROR_NO_LENGTH || rc==NETSTRING_ERROR_TOO_SHORT ) rc = 0; *pcount = count; return rc; } /* count the number of digits (base 10) in a positive integer */ int numdigits(size_t len) { int n = 1; if ( len >= 100000000 ) { n += 8; len /= 100000000; } if ( len >= 10000 ) { n += 4; len /= 10000; } if ( len >= 100 ) { n += 2; len /= 100; } if ( len >= 10 ) { n += 1; } return n; } /* Return the length, in ASCII characters, of a netstring containing `data_length` bytes. */ size_t netstring_buffer_size(size_t data_length) { return (size_t)numdigits(data_length) + data_length + 2; } /* Allocate and create a netstring containing the first `len` bytes of `data`. This must be manually freed by the client. If `len` is 0 then no data will be read from `data`, and it may be NULL. Returns the netstring size not including the null terminator */ size_t netstring_add_ex(char **netstring, char *data, size_t len) { size_t num_len, size_prev=0, size_next; char *ptr; if (netstring == 0 || (len > 0 && data == 0)) return 0; num_len = numdigits(len); size_next = num_len + len + 2; if (*netstring == 0) { ptr = acton_malloc(size_next + 1); if (ptr == 0) return 0; *netstring = ptr; } else { size_prev = strlen(*netstring); ptr = acton_realloc(*netstring, size_prev + size_next + 1); if (ptr == 0) return 0; *netstring = ptr; ptr += size_prev; } if (len == 0) { strcpy(ptr, "0:,"); } else { sprintf(ptr, "%lu:", (unsigned long)len); ptr += num_len + 1; memcpy(ptr, data, len); ptr += len; *ptr = ','; ptr++; *ptr = 0; } return size_prev + size_next; } size_t netstring_add(char **netstring, char *data) { return netstring_add_ex(netstring, data, strlen(data)); } ================================================ FILE: base/rts/netstring.h ================================================ #ifndef __NETSTRING_STREAM_H #define __NETSTRING_STREAM_H #include size_t netstring_add(char **netstring, char *data); size_t netstring_add_ex(char **netstring, char *data, size_t len); int netstring_read(char **buffer_start, size_t *buffer_length, char **netstring_start, size_t *netstring_length); size_t netstring_buffer_size(size_t data_length); int netstring_list_size(char *buffer, size_t size, size_t *ptotal); int netstring_list_count(char *buffer, size_t size, int *pcount); /* Errors that can occur during netstring parsing */ #define NETSTRING_ERROR_TOO_LONG -1 #define NETSTRING_ERROR_NO_COLON -2 #define NETSTRING_ERROR_TOO_SHORT -3 #define NETSTRING_ERROR_NO_COMMA -4 #define NETSTRING_ERROR_LEADING_ZERO -5 #define NETSTRING_ERROR_NO_LENGTH -6 #endif ================================================ FILE: base/rts/q.c ================================================ #include "rts.h" #include "q.h" static inline void spinlock_lock($Lock *f) { while (atomic_flag_test_and_set(f) == true) { // spin until we could set the flag } } static inline void spinlock_unlock($Lock *f) { atomic_flag_clear(f); } #if defined MPMC && MPMC == 3 int ENQ_ready($Actor a) { // TODO: atomics! } #elif defined MPMC && MPMC == 2 int ENQ_ready($Actor a) { int i = a->$affinity; assert(a != NULL && a->$waitsfor == NULL); spinlock_lock(&rqs[i].lock); if (rqs[i].tail) { rqs[i].tail->$next = a; rqs[i].tail = a; } else { rqs[i].head = a; rqs[i].tail = a; } a->$next = NULL; rqs[i].count++; spinlock_unlock(&rqs[i].lock); // If we enqueue to someone who is not us, immediately wake them up... WorkerCtx wctx = GET_WCTX(); if (wctx != NULL) { long our_wtid = wctx->id; if (our_wtid != i) wake_wt(i); } return i; } #else int ENQ_ready($Actor a) { int i = a->$affinity; spinlock_lock(&rqs[i].lock); if (rqs[i].head) { $Actor x = rqs[i].head; while (x->$next) x = x->$next; x->$next = a; } else { rqs[i].head = a; } a->$next = NULL; spinlock_unlock(&rqs[i].lock); // If we enqueue to someone who is not us, immediately wake them up... WorkerCtx wctx = GET_WCTX(); if (wctx != NULL) { long our_wtid = wctx->id; if (our_wtid != i) wake_wt(i); } return i; } #endif // Atomically enqueue actor "a" onto the right ready-queue, either a thread // local one or the "default" shared one. // Atomically dequeue and return the first actor from a ready-queue, first // dequeueing from the thread specific queue and second from the global shared // readyQ or return NULL if no work is found. #if defined MPMC && MPMC == 3 $Actor _DEQ_ready(int idx) { // TODO: atomics! } #elif defined MPMC && MPMC == 2 $Actor _DEQ_ready(int idx) { $Actor res = NULL; if (rqs[idx].head == NULL) { return res; } spinlock_lock(&rqs[idx].lock); res = rqs[idx].head; if (res) { rqs[idx].head = res->$next; res->$next = NULL; if (rqs[idx].head == NULL) { rqs[idx].tail = NULL; } assert(res->$waitsfor == NULL); } else { rqs[idx].tail = NULL; } rqs[idx].count--; spinlock_unlock(&rqs[idx].lock); return res; } #else // First version $Actor _DEQ_ready(int idx) { $Actor res = NULL; if (rqs[idx].head == NULL) return res; spinlock_lock(&rqs[idx].lock); res = rqs[idx].head; if (res) { rqs[idx].head = res->$next; res->$next = NULL; } spinlock_unlock(&rqs[idx].lock); return res; } #endif $Actor DEQ_ready(int idx) { assert(idx >= 0 && idx < 256); $Actor res = _DEQ_ready(idx); if (res) return res; // Unless we are running without threads, worker thread 0 (our main thread) // is special and does not pick up work from the shared queue. It only // serves special actors scheduled on it. if (idx == 0) return NULL; res = _DEQ_ready(SHARED_RQ); return res; } #if MSGQ == 2 // Atomically enqueue message "m" onto the queue of actor "a", // return true if the queue was previously empty. bool ENQ_msg(B_Msg m, $Actor a) { bool did_enq = true; spinlock_lock(&a->B_Msg_lock); m->$next = NULL; if (a->B_Msg_tail) { a->B_Msg_tail->$next = m; a->B_Msg_tail = m; did_enq = false; } else { a->B_Msg = m; a->B_Msg_tail = m; } spinlock_unlock(&a->B_Msg_lock); return did_enq; } // Atomically dequeue the first message from the queue of actor "a", // return true if the queue still holds messages. bool DEQ_msg($Actor a) { bool has_more = false; spinlock_lock(&a->B_Msg_lock); B_Msg x = a->B_Msg; if (x) { a->B_Msg = x->$next; x->$next = NULL; if (a->B_Msg == NULL) { a->B_Msg_tail = NULL; } has_more = a->B_Msg != NULL; } else { a->B_Msg_tail = NULL; } spinlock_unlock(&a->B_Msg_lock); return has_more; } #else // MSGQ == 1 // Atomically enqueue message "m" onto the queue of actor "a", // return true if the queue was previously empty. bool ENQ_msg(B_Msg m, $Actor a) { bool did_enq = true; spinlock_lock(&a->B_Msg_lock); m->$next = NULL; if (a->B_Msg) { B_Msg x = a->B_Msg; while (x->$next) x = x->$next; x->$next = m; did_enq = false; } else { a->B_Msg = m; } spinlock_unlock(&a->B_Msg_lock); return did_enq; } // Atomically dequeue the first message from the queue of actor "a", // return true if the queue still holds messages. bool DEQ_msg($Actor a) { bool has_more = false; spinlock_lock(&a->B_Msg_lock); if (a->B_Msg) { B_Msg x = a->B_Msg; a->B_Msg = x->$next; x->$next = NULL; has_more = a->B_Msg != NULL; } spinlock_unlock(&a->B_Msg_lock); return has_more; } #endif // MSGQ ================================================ FILE: base/rts/q.h ================================================ #pragma once #define MPMC 2 #include "rts.h" #if defined MPMC && MPMC == 3 // TODO: do atomics! struct mpmcq { $Actor head; $Actor tail; unsigned long long count; $Lock lock; }; #else struct mpmcq { $Actor head; $Actor tail; unsigned long long count; $Lock lock; }; #endif extern struct mpmcq rqs[NUM_RQS]; ================================================ FILE: base/rts/rts.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef __linux__ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #endif #ifdef ACTON_THREADS #define GC_THREADS 1 #endif #include #if defined(_WIN32) || defined(_WIN64) #else #include #endif #include #ifdef ACTON_THREADS #include #endif #include #include #ifdef ACTON_DB #include #endif #include #include #include // Windows #ifdef _WIN32 #else #include #include #include #endif #ifdef __linux__ #include #endif #include "common.h" #include "common.c" #include "yyjson.h" #include "rts.h" #include #include "q.c" #include "io.c" #include "log.c" #include "netstring.h" #include "../builtin/env.h" #include "../builtin/function.h" #ifdef ACTON_DB #include "../backend/client_api.h" #include "../backend/fastrand.h" extern struct dbc_stat dbc_stats; #endif #ifndef _WIN32 struct sigaction sa_abrt, sa_ill, sa_int, sa_pipe, sa_segv, sa_term; #endif char rts_verbose = 0; char rts_debug = 0; long num_wthreads = -1; char rts_exit = 0; int return_val = 0; char *appname = NULL; pid_t pid; uv_loop_t *aux_uv_loop = NULL; uv_loop_t *uv_loops[MAX_WTHREADS]; uv_async_t stop_ev[MAX_WTHREADS]; uv_async_t wake_ev[MAX_WTHREADS]; uv_check_t work_ev[MAX_WTHREADS]; WorkerCtx wctxs[MAX_WTHREADS]; uv_timer_t *timer_ev; char *mon_log_path = NULL; int mon_log_period = 30; char *mon_socket_path = NULL; struct wt_stat wt_stats[MAX_WTHREADS]; // Conveys current thread status, like what is it doing? enum WT_State {WT_NoExist = 0, WT_Working = 1, WT_Idle = 2, WT_Sleeping = 3}; static const char *WT_State_name[] = {"poof", "work", "idle", "sleep"}; /* * Custom printf macros for printing verbose and debug information * RTS Debug Printf = rtsd_printf */ #ifdef DEV #define rtsd_printf(...) if (rts_debug) log_debug(__VA_ARGS__) #else #define rtsd_printf(...) #endif #if defined(IS_MACOS) #include #include #include #include #define SYSCTL_CORE_COUNT "machdep.cpu.core_count" typedef struct cpu_set { uint32_t count; } cpu_set_t; static inline void CPU_ZERO(cpu_set_t *cs) { cs->count = 0; } static inline void CPU_SET(int num, cpu_set_t *cs) { cs->count |= (1 << num); } static inline int CPU_ISSET(int num, cpu_set_t *cs) { return (cs->count & (1 << num)); } int sched_getaffinity(pid_t pid, size_t cpu_size, cpu_set_t *cpu_set) { int32_t core_count = 0; size_t len = sizeof(core_count); int ret = sysctlbyname(SYSCTL_CORE_COUNT, &core_count, &len, 0, 0); if (ret) { fprintf(stderr, "error getting the core count %d\n", ret); return -1; } cpu_set->count = 0; for (int i = 0; i < core_count; i++) { cpu_set->count |= (1 << i); } return 0; } kern_return_t thread_policy_set( thread_t thread, thread_policy_flavor_t flavor, thread_policy_t policy_info, mach_msg_type_number_t count); int pthread_setaffinity_np(pthread_t thread, size_t cpu_size, cpu_set_t *cpu_set) { int core = 0; for (core = 0; core < 8 * cpu_size; core++) { if (CPU_ISSET(core, cpu_set)) break; } thread_affinity_policy_data_t policy = { core }; thread_port_t mach_thread = pthread_mach_thread_np(thread); thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1); return 0; } #endif extern void $ROOTINIT(); extern $Actor $ROOT(); struct mpmcq rqs[NUM_RQS]; $Actor root_actor = NULL; B_Env env_actor = NULL; B_Msg timerQ = NULL; $Lock timerQ_lock; int64_t next_key = -10; $Lock next_key_lock; int64_t timer_consume_hd = 0; // Lacks protection, although spinlocks wouldn't help concurrent increments. Must fix in db! time_t current_time() { uv_timespec64_t now; if (uv_clock_gettime(UV_CLOCK_REALTIME, &now) != 0) { log_error("uv_clock_gettime() failed"); return 0; } return now.tv_sec * 1000000 + now.tv_nsec / 1000; } #ifdef ACTON_THREADS pthread_key_t self_key; pthread_key_t pkey_wctx; pthread_mutex_t rts_exit_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t rts_exit_signal = PTHREAD_COND_INITIALIZER; #define NUM_THREADS num_wthreads+1 void pin_actor_affinity() { $Actor a = ($Actor)pthread_getspecific(self_key); WorkerCtx wctx = (WorkerCtx)pthread_getspecific(pkey_wctx); long i = wctx->id; log_debug("Pinning affinity for %s actor %ld to current WT %d", a->$class->$GCINFO, a->$globkey, i); a->$affinity = i; } void set_actor_affinity(int wthread_id) { $Actor a = ($Actor)pthread_getspecific(self_key); log_debug("Setting affinity for %s actor %ld to WT %d", a->$class->$GCINFO, a->$globkey, wthread_id); a->$affinity = wthread_id; } #else // ACTON_THREADS $Actor self_actor; #define NUM_THREADS 1 void pin_actor_affinity() { } void set_actor_affinity(int wthread_id) { } #endif // ACTON_THREADS void wake_wt(int wtid) { // We are sometimes optimistically called, i.e. the caller sometimes does // not really know whether there is new work or not. We check and if there // is not, then there is no need to wake anyone up. if (!rqs[wtid].head) return; #ifdef ACTON_THREADS // wake up corresponding worker threads.... if (wtid == SHARED_RQ) { for (int i = 1; i <= num_wthreads; i++) { if (wt_stats[i].state == WT_Idle) { uv_async_send(&wake_ev[i]); return; } } } else { // thread specific queue uv_async_send(&wake_ev[wtid]); } #else uv_async_send(&wake_ev[wtid]); #endif } void reset_timeout() { // Wake up timerQ thread uv_async_send(&wake_ev[0]); } int64_t get_next_key() { spinlock_lock(&next_key_lock); int64_t res = --next_key; spinlock_unlock(&next_key_lock); return res; } #define ACTORS_TABLE ($WORD)0 #define MSGS_TABLE ($WORD)1 #define MSG_QUEUE ($WORD)2 #define TIMER_QUEUE 0 // Special key in table MSG_QUEUE #ifdef ACTON_DB remote_db_t * db = NULL; #endif #if defined(_WIN32) || defined(_WIN64) // TODO: termios support in windows? #else struct termios old_stdin_attr; #endif //////////////////////////////////////////////////////////////////////////////////////// /* The strangeness of the next 30 lines are caused by the unfortunate presence of Msg in __builtin__.act. -- This generates a stub of B_MsgD___init__ with wrong parameters, and its presence in the method table, so we define it here, but never use it. -- The out-commented version is how __init__ should really be defined -- The B_msgG_newXX function now inlines the proper __init__; it has to be renamed because of a generated and improper B_msgG_new. */ B_NoneType B_MsgD___init__ (B_Msg G_1p) { // Must (and will) never be called! return B_None; } /* void B_MsgD___init__(B_Msg m, $Actor to, $Cont cont, time_t baseline, $WORD value) { m->$next = NULL; m->$to = to; m->$cont = cont; m->$waiting = NULL; m->$baseline = baseline; m->value = value; atomic_flag_clear(&m->$wait_lock); m->$globkey = get_next_key(); } */ B_Msg B_MsgG_newXX( $Actor to, $Cont cont, time_t baseline, $WORD value) { B_Msg m = GC_malloc(sizeof(struct B_Msg)); m->$class = &B_MsgG_methods; m->$next = NULL; m->$to = to; m->$cont = cont; m->$waiting = NULL; m->$baseline = baseline; m->value = value; atomic_flag_clear(&m->$wait_lock); m->$globkey = get_next_key(); return m; } //////////////////////////////////////////////////////////////////////// B_bool B_MsgD___bool__(B_Msg self) { return B_True; } B_str B_MsgD___str__(B_Msg self) { return $FORMAT("", self); } B_str B_MsgD___repr__(B_Msg self) { return B_MsgD___str__(self); } void B_MsgD___serialize__(B_Msg self, $Serial$state state) { $step_serialize(self->$to,state); $step_serialize(self->$cont,state); $val_serialize(ITEM_ID,&self->$baseline,state); $step_serialize(self->value,state); } B_Msg B_MsgD___deserialize__(B_Msg res, $Serial$state state) { if (!res) { if (!state) { res = GC_malloc(sizeof (struct B_Msg)); res->$class = &B_MsgG_methods; return res; } res = $DNEW(B_Msg,state); } res->$next = NULL; res->$to = $step_deserialize(state); res->$cont = $step_deserialize(state); res->$waiting = NULL; res->$baseline = (time_t)$val_deserialize(state); res->value = $step_deserialize(state); atomic_flag_clear(&res->$wait_lock); return res; } //////////////////////////////////////////////////////////////////////////////////////// void $ActorD___init__($Actor a) { a->$next = NULL; a->B_Msg = NULL; a->$outgoing = NULL; a->$waitsfor = NULL; a->$consume_hd = 0; a->$catcher = NULL; atomic_flag_clear(&a->B_Msg_lock); a->$globkey = get_next_key(); a->$affinity = SHARED_RQ; rtsd_printf("# New Actor %ld at %p of class %s", a->$globkey, a, a->$class->$GCINFO); } B_bool $ActorD___bool__($Actor self) { return B_True; } B_str $ActorD___str__($Actor self) { return $FORMAT("<$Actor %ld %s at %p>", self->$globkey, self->$class->$GCINFO, self); } B_NoneType $ActorD___resume__($Actor self) { return B_None; } B_NoneType $ActorD___cleanup__($Actor self) { return B_None; } void $ActorD___serialize__($Actor self, $Serial$state state) { $step_serialize(self->$waitsfor,state); $val_serialize(ITEM_ID,&self->$consume_hd,state); $step_serialize(self->$catcher,state); } $Actor $ActorD___deserialize__($Actor res, $Serial$state state) { if (!res) { if (!state) { res = GC_malloc(sizeof(struct $Actor)); res->$class = &$ActorG_methods; return res; } res = $DNEW($Actor, state); } res->$next = NULL; res->B_Msg = NULL; res->$outgoing = NULL; res->$waitsfor = $step_deserialize(state); res->$consume_hd = (long)$val_deserialize(state); res->$catcher = $step_deserialize(state); atomic_flag_clear(&res->B_Msg_lock); if (res->$affinity > 0) res->$affinity = SHARED_RQ; return res; } //////////////////////////////////////////////////////////////////////////////////////// void $CatcherD___init__($Catcher c, $Cont cont) { c->$next = NULL; c->$cont = cont; c->xval = NULL; } B_bool $CatcherD___bool__($Catcher self) { return B_True; } B_str $CatcherD___str__($Catcher self) { return $FORMAT("<$Catcher object at %p>", self); } void $CatcherD___serialize__($Catcher self, $Serial$state state) { $step_serialize(self->$next,state); $step_serialize(self->$cont,state); $step_serialize(self->xval,state); } $Catcher $CatcherD___deserialize__($Catcher self, $Serial$state state) { $Catcher res = $DNEW($Catcher,state); res->$next = $step_deserialize(state); res->$cont = $step_deserialize(state); res->xval = $step_deserialize(state); return res; } /////////////////////////////////////////////////////////////////////////////////////// void $ConstContD___init__($ConstCont $this, $WORD val, $Cont cont) { $this->val = val; $this->cont = cont; } B_bool $ConstContD___bool__($ConstCont self) { return B_True; } B_str $ConstContD___str__($ConstCont self) { return $FORMAT("<$ConstCont object at %p>", self); } void $ConstContD___serialize__($ConstCont self, $Serial$state state) { $step_serialize(self->val,state); $step_serialize(self->cont,state); } $ConstCont $ConstContD___deserialize__($ConstCont self, $Serial$state state) { $ConstCont res = $DNEW($ConstCont,state); res->val = $step_deserialize(state); res->cont = $step_deserialize(state); return res; } $R $ConstContD___call__($ConstCont $this, $WORD _ignore) { $Cont cont = $this->cont; return cont->$class->__call__(cont, $this->val); } $Cont $CONSTCONT($WORD val, $Cont cont){ $ConstCont obj = GC_malloc(sizeof(struct $ConstCont)); obj->$class = &$ConstContG_methods; $ConstContG_methods.__init__(obj, val, cont); return ($Cont)obj; } //////////////////////////////////////////////////////////////////////////////////////// /* struct B_MsgG_class B_MsgG_methods = { MSG_HEADER, UNASSIGNED, NULL, NULL, B_MsgD___serialize__, B_MsgD___deserialize__, B_MsgD___bool__, B_MsgD___str__, B_MsgD___str__ }; */ struct $ActorG_class $ActorG_methods = { ACTOR_HEADER, UNASSIGNED, NULL, $ActorD___init__, $ActorD___serialize__, $ActorD___deserialize__, $ActorD___bool__, $ActorD___str__, $ActorD___str__, $ActorD___resume__, $ActorD___cleanup__ }; struct $CatcherG_class $CatcherG_methods = { CATCHER_HEADER, UNASSIGNED, NULL, $CatcherD___init__, $CatcherD___serialize__, $CatcherD___deserialize__, $CatcherD___bool__, $CatcherD___str__, $CatcherD___str__ }; struct $ConstContG_class $ConstContG_methods = { "$ConstCont", UNASSIGNED, NULL, $ConstContD___init__, $ConstContD___serialize__, $ConstContD___deserialize__, $ConstContD___bool__, $ConstContD___str__, $ConstContD___str__, $ConstContD___call__ }; //////////////////////////////////////////////////////////////////////////////////////// #define MARK_RESULT NULL #define MARK_EXCEPTION ($Cont)1 #define EXCEPTIONAL(m) (m->$cont == MARK_EXCEPTION) #define FROZEN(m) (m->$cont == MARK_RESULT || EXCEPTIONAL(m)) // Atomically add actor "a" to the waiting list of messasge "m" if it is not frozen (and return true), // else immediately return false. bool ADD_waiting($Actor a, B_Msg m) { bool did_add = false; assert(m != NULL); spinlock_lock(&m->$wait_lock); if (!FROZEN(m)) { a->$next = m->$waiting; m->$waiting = a; a->$waitsfor = m; did_add = true; } spinlock_unlock(&m->$wait_lock); return did_add; } // Atomically freeze message "m" using "mark", and return its list of waiting actors. $Actor FREEZE_waiting(B_Msg m, $Cont mark) { spinlock_lock(&m->$wait_lock); m->$cont = mark; $Actor res = m->$waiting; m->$waiting = NULL; spinlock_unlock(&m->$wait_lock); return res; } // Atomically enqueue timed message "m" onto the global timer-queue, at position // given by "m->baseline". bool ENQ_timed(B_Msg m) { time_t m_baseline = m->$baseline; bool new_head = false; spinlock_lock(&timerQ_lock); B_Msg x = timerQ; if (x && x->$baseline <= m_baseline) { B_Msg next = x->$next; while (next && next->$baseline <= m_baseline) { x = next; next = x->$next; } x->$next = m; m->$next = next; } else { timerQ = m; m->$next = x; new_head = true; } spinlock_unlock(&timerQ_lock); return new_head; } // Atomically dequeue and return the first message from the global timer-queue if // its baseline is less or equal to "now", else return NULL. B_Msg DEQ_timed(time_t now) { spinlock_lock(&timerQ_lock); B_Msg res = timerQ; if (res) { if (res->$baseline <= now) { timerQ = res->$next; res->$next = NULL; } else { res = NULL; } } spinlock_unlock(&timerQ_lock); return res; } //////////////////////////////////////////////////////////////////////////////////////// char *RTAG_name($RTAG tag) { switch (tag) { case $RDONE: return "RDONE"; break; case $RFAIL: return "RFAIL"; break; case $RCONT: return "RCONT"; break; case $RWAIT: return "RWAIT"; break; } } //////////////////////////////////////////////////////////////////////////////////////// $R $DoneD___call__($Cont $this, $WORD val) { return $R_DONE(val); } B_bool $DoneD___bool__($Cont self) { return B_True; } B_str $DoneD___str__($Cont self) { return $FORMAT("<$Done object at %p>", self); } void $Done__serialize__($Cont self, $Serial$state state) { return; } $Cont $Done__deserialize__($Cont self, $Serial$state state) { $Cont res = $DNEW($Cont,state); res->$class = &$DoneG_methods; return res; } struct $ContG_class $DoneG_methods = { "$Done", UNASSIGNED, NULL, $ContD___init__, $Done__serialize__, $Done__deserialize__, $DoneD___bool__, $DoneD___str__, $DoneD___str__, $DoneD___call__ }; struct $Cont $Done$instance = { &$DoneG_methods }; //////////////////////////////////////////////////////////////////////////////////////// $R $FailD___call__($Cont $this, $WORD ex) { return $R_FAIL(ex); } B_bool $FailD___bool__($Cont self) { return B_True; } B_str $FailD___str__($Cont self) { return $FORMAT("<$Fail object at %p>", self); } void $Fail__serialize__($Cont self, $Serial$state state) { return; } $Cont $Fail__deserialize__($Cont self, $Serial$state state) { $Cont res = $DNEW($Cont,state); res->$class = &$FailG_methods; return res; } struct $ContG_class $FailG_methods = { "$Fail", UNASSIGNED, NULL, $ContD___init__, $Fail__serialize__, $Fail__deserialize__, $FailD___bool__, $FailD___str__, $FailD___str__, $FailD___call__ }; struct $Cont $Fail$instance = { &$FailG_methods }; //////////////////////////////////////////////////////////////////////////////////////// $R $InitRootD___call__ ($Cont $this, $WORD val) { typedef $R(*ROOT__init__t)($Actor, $Cont, B_Env); // Assumed type of the ROOT actor's __init__ method return ((ROOT__init__t)root_actor->$class->__init__)(root_actor, ($Cont)val, env_actor); } struct $ContG_class $InitRootG_methods = { "$InitRoot", UNASSIGNED, NULL, $ContD___init__, $ContD___serialize__, $ContD___deserialize__, $ContD___bool__, $ContD___str__, $ContD___str__, $InitRootD___call__ }; struct $Cont $InitRoot$cont = { &$InitRootG_methods }; //////////////////////////////////////////////////////////////////////////////////////// #ifdef ACTON_DB void dummy_callback(queue_callback_args * qca) { } void queue_group_message_callback(queue_callback_args * qca) { // rtsd_printf(" # There are messages in actor queues for group %d, subscriber %d, status %d\n", (int) qca->group_id, (int) qca->consumer_id, qca->status); } void create_db_queue(long key) { int minority_status = 0; while(!rts_exit) { int ret = remote_create_queue_in_txn(MSG_QUEUE, ($WORD)key, &minority_status, NULL, db); rtsd_printf("#### Create queue %ld returns %d", key, ret); if(ret == NO_QUORUM_ERR) { sleep(3); continue; } if(ret == 0 || ret == CLIENT_ERR_SUBSCRIPTION_EXISTS) break; } } void init_db_queue(long key) { if (db) create_db_queue(key); } void register_actor(long key) { if (db) { int status = add_actor_to_membership(key, db); assert(status == 0); } } #endif void PUSH_outgoing($Actor self, B_Msg m) { m->$next = self->$outgoing; self->$outgoing = m; } void PUSH_catcher($Actor a, $Catcher c) { c->$next = a->$catcher; a->$catcher = c; } $Catcher POP_catcher($Actor a) { $Catcher c = a->$catcher; if (c) { a->$catcher = c->$next; c->$next = NULL; } return c; } B_Msg $ASYNC($Actor to, $Cont cont) { $Actor self = GET_SELF(); time_t baseline = 0; B_Msg m = B_MsgG_newXX(to, cont, baseline, &$Done$instance); if (self) { // $ASYNC called by actor code m->$baseline = self->B_Msg->$baseline; PUSH_outgoing(self, m); } else { // $ASYNC called by the event loop m->$baseline = current_time(); if (ENQ_msg(m, to)) { int wtid = ENQ_ready(to); wake_wt(wtid); } } return m; } B_Msg $AFTER(B_float sec, $Cont cont) { $Actor self = GET_SELF(); rtsd_printf("# AFTER by %ld", self->$globkey); time_t baseline = self->B_Msg->$baseline + sec->val * 1000000; B_Msg m = B_MsgG_newXX(self, cont, baseline, &$Done$instance); PUSH_outgoing(self, m); return m; } $R $AWAIT($Cont cont, B_Msg m) { return $R_WAIT(cont, m); } $R $PUSH_C($Cont cont) { $Actor self = GET_SELF(); $Catcher c = $NEW($Catcher, cont); PUSH_catcher(self, c); return $R_CONT(cont, B_True); // True indicates the "try" branch } B_BaseException $POP_C() { $Actor self = GET_SELF(); $Catcher c = POP_catcher(self); B_BaseException ex = c->xval; return ex; } void $DROP_C() { $Actor self = GET_SELF(); POP_catcher(self); } JumpBuf $PUSH_BUF() { WorkerCtx wctx = GET_WCTX(); assert(wctx != NULL); JumpBuf current = wctx->jump_top; JumpBuf new = (JumpBuf)GC_malloc(sizeof(struct JumpBuf)); new->prev = current; wctx->jump_top = new; return new; } B_BaseException $POP() { WorkerCtx wctx = GET_WCTX(); assert(wctx != NULL); JumpBuf current = wctx->jump_top; assert(current != NULL); // assert(current->prev != NULL); wctx->jump_top = current->prev; return current->xval; } void $DROP() { WorkerCtx wctx = GET_WCTX(); assert(wctx != NULL); JumpBuf current = wctx->jump_top; assert(current != NULL); // (current->prev != NULL); wctx->jump_top = current->prev; } void $RAISE(B_BaseException e) { WorkerCtx wctx = GET_WCTX(); JumpBuf jump = wctx->jump_top; jump->xval = e; longjmp(jump->buf, 1); } #ifdef ACTON_DB void create_all_actor_queues() { for(snode_t * node = HEAD(db->actors); node!=NULL; node=NEXT(node)) { create_db_queue((long) node->key); } } int handle_status_and_schema_mismatch(int ret, int minority_status, long key) { // If schema on any of the DB servers needs updating (based on minority_status), do that. // If there was a quorum of healthy servers, we can go on after this, the operation succeeded. // If schema was missing on a majority of servers, we'll in addition get NO_QUORUM_ERR, and // we also need to retry the operation. int queues_created = 0; switch(minority_status) { case DB_ERR_NO_QUEUE: case DB_ERR_NO_CONSUMER: case VAL_STATUS_ABORT_SCHEMA: { // Schema errs: // create_all_actor_queues(); create_db_queue(key); queues_created = 1; break; } case QUEUE_STATUS_READ_INCOMPLETE: case QUEUE_STATUS_READ_COMPLETE: case DB_ERR_DUPLICATE_CONSUMER: case DB_ERR_QUEUE_COMPLETE: case DB_ERR_DUPLICATE_QUEUE: { // These are OK: break; } default: { // DB_ERR_QUEUE_HEAD_INVALID, DB_ERR_NO_TABLE assert(0); } } if(ret == VAL_STATUS_ABORT_SCHEMA && !queues_created) { // create_all_actor_queues(); create_db_queue(key); } if(ret == NO_QUORUM_ERR) { sleep(3); return 1; } return 0; } #endif void reverse_outgoing_queue($Actor self) { B_Msg prev = NULL; B_Msg m = self->$outgoing; while (m) { B_Msg next = m->$next; m->$next = prev; prev = m; m = next; } self->$outgoing = prev; } #ifdef ACTON_DB // Send all buffered messages of the sender to global DB queues in a single txn, and retry it until success // Leaves no side effects in local queues if txns need to abort // Assumes the actor's outgoing queue has already been reversed in FIFO order void FLUSH_outgoing_db($Actor self, uuid_t *txnid) { rtsd_printf("#### FLUSH_outgoing messages from %ld to DB queues", self->$globkey); B_Msg m = self->$outgoing; while (m) { long dest = (m->$baseline == self->B_Msg->$baseline)? m->$to->$globkey : 0; int ret = 0, minority_status = 0; while(!rts_exit) { ret = remote_enqueue_in_txn(($WORD*)&m->$globkey, 1, NULL, 0, MSG_QUEUE, (WORD)dest, &minority_status, txnid, db); if (dest) { rtsd_printf(" # enqueue msg %ld to queue %ld returns %d, minority_status=%d", m->$globkey, dest, ret, minority_status); } else { rtsd_printf(" # enqueue msg %ld to TIMER_QUEUE returns %d, minority_status=%d", m->$globkey, ret, minority_status); } if(!handle_status_and_schema_mismatch(ret, minority_status, dest)) break; } m = m->$next; } } #endif // Actually send all buffered messages of the sender, using internal queues only // Assumes the actor's outgoing queue has already been reversed in FIFO order void FLUSH_outgoing_local($Actor self) { rtsd_printf("#### FLUSH_outgoing messages from %ld to RTS-internal queues", self->$globkey); B_Msg m = self->$outgoing; self->$outgoing = NULL; while (m) { B_Msg next = m->$next; m->$next = NULL; long dest; if (m->$baseline == self->B_Msg->$baseline) { $Actor to = m->$to; if (ENQ_msg(m, to)) { ENQ_ready(to); } dest = to->$globkey; } else { if (ENQ_timed(m)) reset_timeout(); dest = 0; } m = next; } } time_t next_timeout() { return timerQ ? timerQ->$baseline : 0; } void handle_timeout() { time_t now = current_time(); B_Msg m = DEQ_timed(now); if (m) { rtsd_printf("## Dequeued timed msg with baseline %ld (now is %ld)", m->$baseline, now); if (ENQ_msg(m, m->$to)) { int wtid = ENQ_ready(m->$to); wake_wt(wtid); } #ifdef ACTON_DB if (db) { int success = 0; while(!success && !rts_exit) { uuid_t *txnid = remote_new_txn(db); if(txnid == NULL) continue; timer_consume_hd++; long key = TIMER_QUEUE; snode_t *m_start, *m_end; int entries_read = 0, minority_status = 0; int64_t read_head = -1; int ret0 = remote_read_queue_in_txn(($WORD)db->local_rts_id, 0, 0, MSG_QUEUE, ($WORD)key, 1, &entries_read, &read_head, &m_start, &m_end, &minority_status, NULL, db); rtsd_printf(" # dummy read msg from TIMER_QUEUE returns %d, entries read: %d", ret0, entries_read); if(handle_status_and_schema_mismatch(ret0, minority_status, key)) continue; int ret1 = remote_consume_queue_in_txn(($WORD)db->local_rts_id, 0, 0, MSG_QUEUE, ($WORD)key, read_head, &minority_status, txnid, db); rtsd_printf(" # consume msg %ld from TIMER_QUEUE returns %d", m->$globkey, ret1); if(handle_status_and_schema_mismatch(ret1, minority_status, key)) continue; int ret2 = remote_enqueue_in_txn(($WORD*)&m->$globkey, 1, NULL, 0, MSG_QUEUE, (WORD)m->$to->$globkey, &minority_status, txnid, db); rtsd_printf(" # (timed) enqueue msg %ld to queue %ld returns %d", m->$globkey, m->$to->$globkey, ret2); if(handle_status_and_schema_mismatch(ret2, minority_status, key)) continue; int ret3 = remote_commit_txn(txnid, &minority_status, db); rtsd_printf("############## Commit returned %d, minority_status %d", ret3, minority_status); if(handle_status_and_schema_mismatch(ret3, minority_status, key)) continue; if(ret3 == VAL_STATUS_COMMIT) success = 1; } } #endif } } //////////////////////////////////////////////////////////////////////////////////////// B_dict globdict = NULL; $WORD try_globdict($WORD w) { long key = (long)w; $WORD obj = B_dictD_get(globdict, (B_Hashable)B_HashableD_intG_witness, toB_int(key), NULL); return obj; } #ifdef ACTON_DB long read_queued_msg(long key, int64_t *read_head) { snode_t *m_start, *m_end; int entries_read = 0, minority_status = 0, ret = 0; while(!rts_exit) { ret = remote_read_queue_in_txn(($WORD)db->local_rts_id, 0, 0, MSG_QUEUE, ($WORD)key, 1, &entries_read, read_head, &m_start, &m_end, &minority_status, NULL, db); rtsd_printf(" # read msg from queue %ld returns %d, entries read: %d, minority_status: %d", key, ret, entries_read, minority_status); if(!handle_status_and_schema_mismatch(ret, minority_status, key)) break; } if (!entries_read) return 0; db_row_t *r = (db_row_t*)m_start->value; rtsd_printf("# r %p, key: %ld, cells: %p, columns: %p, no_cols: %d, blobsize: %d", r, (long)r->key, r->cells, r->column_array, r->no_columns, r->last_blob_size); return (long)r->column_array[0]; } #endif typedef struct BlobHd { // C.f. $ROW int class_id; int blob_size; } BlobHd; $ROW extract_row($WORD *blob, size_t blob_size) { int words_left = blob_size / sizeof($WORD); if (words_left == 0) return NULL; BlobHd* head = (BlobHd*)blob; $ROW fst = GC_malloc(sizeof(struct $ROW) + head->blob_size*sizeof($WORD)); $ROW row = fst; while (!rts_exit) { long size = 1 + head->blob_size; memcpy(&row->class_id, blob, size*sizeof($WORD)); blob += size; words_left -= size; if (words_left == 0) break; head = (BlobHd*)blob; row->next = GC_malloc(sizeof(struct $ROW) + head->blob_size*sizeof($WORD)); row = row->next; }; row->next = NULL; return fst; } void print_rows($ROW row) { int n = 0; while (row) { char b[1024]; int len = 0; for (int i = 0; i < row->blob_size; i++) len += sprintf(b+len, "%ld ", (long)row->blob[i]); sprintf(b+len, "."); rtsd_printf("--- %2d: class_id %6d, blob_size: %3d, blob: %s", n, row->class_id, row->blob_size, b); n++; row = row->next; } } void print_msg(B_Msg m) { rtsd_printf("==== Message %p", m); rtsd_printf(" next: %p", m->$next); rtsd_printf(" to: %p", m->$to); rtsd_printf(" cont: %p", m->$cont); rtsd_printf(" waiting: %p", m->$waiting); rtsd_printf(" baseline: %ld", m->$baseline); rtsd_printf(" value: %p", m->value); rtsd_printf(" globkey: %ld", m->$globkey); } void print_actor($Actor a) { rtsd_printf("==== Actor %p", a); rtsd_printf(" next: %p", a->$next); rtsd_printf(" msg: %p", a->B_Msg); rtsd_printf(" outgoing: %p", a->$outgoing); rtsd_printf(" waitsfor: %p", a->$waitsfor); rtsd_printf(" consume_hd: %ld", (long)a->$consume_hd); rtsd_printf(" catcher: %p", a->$catcher); rtsd_printf(" globkey: %ld", a->$globkey); } #ifdef ACTON_DB void deserialize_system(snode_t *actors_start) { rtsd_printf("Deserializing system"); queue_callback * gqc = get_queue_callback(queue_group_message_callback); int ret = 0, minority_status = 0, no_items = 0; rtsd_printf("### remote_subscribe_group(consumer_id = %d, group_id = %d)\n", (int) db->local_rts_id, (int) db->local_rts_id); while(!rts_exit) { ret = remote_subscribe_group((WORD) db->local_rts_id, NULL, NULL, (WORD) db->local_rts_id, gqc, &minority_status, db); if(!handle_status_and_schema_mismatch(ret, minority_status, 0)) break; } snode_t *msgs_start, *msgs_end; while(!rts_exit) { ret = remote_read_full_table_in_txn(&msgs_start, &msgs_end, MSGS_TABLE, &no_items, &minority_status, NULL, db); if(!handle_status_and_schema_mismatch(ret, minority_status, 0)) break; } globdict = $NEW(B_dict,(B_Hashable)B_HashableD_intG_witness,NULL,NULL); long min_key = 0; rtsd_printf("#### Msg allocation:"); for(snode_t * node = msgs_start; node!=NULL; node=NEXT(node)) { db_row_t* r = (db_row_t*) node->value; rtsd_printf("# r %p, key: %ld, cells: %p, columns: %p, no_cols: %d, blobsize: %d", r, (long)r->key, r->cells, r->column_array, r->no_columns, r->last_blob_size); long key = (long)r->key; if (r->cells) { db_row_t* r2 = (HEAD(r->cells))->value; rtsd_printf("# r2 %p, key: %ld, cells: %p, columns: %p, no_cols: %d, blobsize: %d", r2, (long)r2->key, r2->cells, r2->column_array, r2->no_columns, r2->last_blob_size); BlobHd *head = (BlobHd*)r2->column_array[0]; B_Msg msg = (B_Msg)$GET_METHODS(head->class_id)->__deserialize__(NULL, NULL); msg->$globkey = key; B_dictD_setitem(globdict, (B_Hashable)B_HashableD_intG_witness, to$int(key), msg); rtsd_printf("# Allocated Msg %p = %ld of class %s = %d", msg, msg->$globkey, msg->$class->$GCINFO, msg->$class->$class_id); if (key < min_key) min_key = key; } } rtsd_printf("#### Actor allocation:"); for(snode_t * node = actors_start; node!=NULL; node=NEXT(node)) { db_row_t* r = (db_row_t*) node->value; rtsd_printf("# r %p, key: %ld, cells: %p, columns: %p, no_cols: %d, blobsize: %d", r, (long)r->key, r->cells, r->column_array, r->no_columns, r->last_blob_size); long key = (long)r->key; if (r->cells) { db_row_t* r2 = (HEAD(r->cells))->value; rtsd_printf("# r2 %p, key: %ld, cells: %p, columns: %p, no_cols: %d, blobsize: %d", r2, (long)r2->key, r2->cells, r2->column_array, r2->no_columns, r2->last_blob_size); BlobHd *head = (BlobHd*)r2->column_array[0]; $Actor act = ($Actor)$GET_METHODS(head->class_id)->__deserialize__(NULL, NULL); act->$globkey = key; B_dictD_setitem(globdict, (B_Hashable)B_HashableD_intG_witness, to$int(key), act); rtsd_printf("# Allocated Actor %p = %ld of class %s = %d", act, act->$globkey, act->$class->$GCINFO, act->$class->$class_id); if (key < min_key) min_key = key; } register_actor(key); } next_key = min_key; rtsd_printf("#### Msg contents:"); for(snode_t * node = msgs_start; node!=NULL; node=NEXT(node)) { db_row_t* r = (db_row_t*) node->value; long key = (long)r->key; if (r->cells) { db_row_t* r2 = (HEAD(r->cells))->value; $WORD *blob = ($WORD*)r2->column_array[0]; int blob_size = r2->last_blob_size; $ROW row = extract_row(blob, blob_size); B_Msg msg = (B_Msg)B_dictD_get(globdict, (B_Hashable)B_HashableD_intG_witness, to$int(key), NULL); rtsd_printf("####### Deserializing msg %p = %ld of class %s = %d", msg, msg->$globkey, msg->$class->$GCINFO, msg->$class->$class_id); print_rows(row); $glob_deserialize(($Serializable)msg, row, try_globdict); print_msg(msg); } } rtsd_printf("#### Actor contents:"); for(snode_t * node = actors_start; node!=NULL; node=NEXT(node)) { db_row_t* r = (db_row_t*) node->value; long key = (long)r->key; if (r->cells) { db_row_t* r2 = (HEAD(r->cells))->value; $WORD *blob = ($WORD*)r2->column_array[0]; int blob_size = r2->last_blob_size; $ROW row = extract_row(blob, blob_size); $Actor act = ($Actor)B_dictD_get(globdict, (B_Hashable)B_HashableD_intG_witness, to$int(key), NULL); rtsd_printf("####### Deserializing actor %p = %ld of class %s = %d", act, act->$globkey, act->$class->$GCINFO, act->$class->$class_id); print_rows(row); $glob_deserialize(($Serializable)act, row, try_globdict); B_Msg m = act->$waitsfor; if (m && !FROZEN(m)) { ADD_waiting(act, m); rtsd_printf("# Adding Actor %ld to wait for Msg %ld", act->$globkey, m->$globkey); } else { act->$waitsfor = NULL; } rtsd_printf("#### Reading msgs queue %ld contents:", key); int64_t prev_read_head = -1; //, prev_consume_head = -1; int ret = 0, minority_status = 0; while (!rts_exit) { long msg_key = read_queued_msg(key, &prev_read_head); if (!msg_key) break; m = B_dictD_get(globdict, (B_Hashable)B_HashableD_intG_witness, to$int(msg_key), NULL); rtsd_printf("# Adding Msg %ld to Actor %ld", m->$globkey, act->$globkey); ENQ_msg(m, act); } if (act->B_Msg && !act->$waitsfor) { ENQ_ready(act); rtsd_printf("# Adding Actor %ld to the readyQ", act->$globkey); } print_actor(act); } } rtsd_printf("#### Actor resume:"); for(snode_t * node = actors_start; node!=NULL; node=NEXT(node)) { db_row_t* r = (db_row_t*) node->value; long key = (long)r->key; $Actor act = ($Actor)B_dictD_get(globdict, (B_Hashable)B_HashableD_intG_witness, to$int(key), NULL); rtsd_printf("####### Resuming actor %p = %ld of class %s = %d", act, act->$globkey, act->$class->$GCINFO, act->$class->$class_id); act->$class->__resume__(act); } rtsd_printf("#### Reading timer queue contents:"); time_t now = current_time(); int64_t prev_read_head = -1; while(!rts_exit) { long msg_key = read_queued_msg(TIMER_QUEUE, &prev_read_head); if (!msg_key) break; B_Msg m = B_dictD_get(globdict, (B_Hashable)B_HashableD_intG_witness, to$int(msg_key), NULL); if (m->$baseline < now) m->$baseline = now; rtsd_printf("# Adding Msg %ld to the timerQ", m->$globkey); ENQ_timed(m); } /* * Actor IDs (-11 & -12) here chosen by fair dice roll... Haha, kidding. * These values are aligned with the IDs allocated by get_next_key() when * called in the BOOTSTRAP() function. The ID allocator next_key starts at * -10, so -11 is the first key handed out and with the env actor is created * first, it will get -11. Similarly for the root actor, which is assigned * ID -12 (via the $NEWROOT call embedded in the external function $ROOT). * These values must be kept in sync with next_key and the structure in * the BOOTSTRAP() function! */ env_actor = (B_Env)B_dictD_get(globdict, (B_Hashable)B_HashableD_intG_witness, to$int(-11), NULL); root_actor = ($Actor)B_dictD_get(globdict, (B_Hashable)B_HashableD_intG_witness, to$int(-12), NULL); globdict = NULL; rtsd_printf("System deserialized"); } #endif $WORD try_globkey($WORD obj) { $SerializableG_class c = (($Serializable)obj)->$class; if (c->$class_id == MSG_ID) { long key = ((B_Msg)obj)->$globkey; return ($WORD)key; } else if (c->$class_id == ACTOR_ID || c->$superclass && c->$superclass->$class_id == ACTOR_ID) { long key = (($Actor)obj)->$globkey; return ($WORD)key; } return 0; } long $total_rowsize($ROW r) { // In words long size = 0; while (r) { size += 1 + r->blob_size; // Two ints == one $WORD r = r->next; } return size; } #ifdef ACTON_DB void insert_row(long key, size_t total, $ROW row, $WORD table, uuid_t *txnid) { $WORD column[2] = {($WORD)key, 0}; $WORD blob[total]; $WORD *p = blob; int row_no = 0; while (row) { //printf(" # row %d: class %d, blob_size %d\n", row_no, row->class_id, row->blob_size); long size = 1 + row->blob_size; memcpy(p, &row->class_id, size*sizeof($WORD)); row_no++; p += size; row = row->next; } BlobHd *end = (BlobHd*)p; char b[1024]; int len = 0; for (int i = 0; i < total; i++) len += sprintf(b+len, "%lu ", (unsigned long)blob[i]); sprintf(b+len, "."); rtsd_printf("## Built blob, size: %ld, blob: %s", total, b); //printf("\n## Sanity check extract row:\n"); //$ROW row1 = extract_row(blob, total*sizeof($WORD)); //print_rows(row1); int ret = 0, minority_status = 0; while(!rts_exit) { ret = remote_insert_in_txn(column, 2, 1, 1, blob, total*sizeof($WORD), table, &minority_status, txnid, db); rtsd_printf(" # insert to table %ld, row %ld, returns %d", (long)table, key, ret); if(!handle_status_and_schema_mismatch(ret, minority_status, 0)) break; } } void serialize_msg(B_Msg m, uuid_t *txnid) { rtsd_printf("#### Serializing Msg %ld", m->$globkey); $ROW row = $glob_serialize(($Serializable)m, try_globkey); print_rows(row); insert_row(m->$globkey, $total_rowsize(row), row, MSGS_TABLE, txnid); } void serialize_actor($Actor a, uuid_t *txnid) { rtsd_printf("#### Serializing Actor %ld", a->$globkey); $ROW row = $glob_serialize(($Serializable)a, try_globkey); print_rows(row); insert_row(a->$globkey, $total_rowsize(row), row, ACTORS_TABLE, txnid); B_Msg out = a->$outgoing; while (out) { serialize_msg(out, txnid); out = out->$next; } } #endif void serialize_state_shortcut($Actor a) { #ifdef ACTON_DB if (db) { int success = 0, ret = 0, minority_status = 0; while(!success && !rts_exit) { uuid_t * txnid = remote_new_txn(db); if(txnid == NULL) continue; serialize_actor(a, txnid); ret = remote_commit_txn(txnid, &minority_status, db); rtsd_printf("############## Commit returned %d, minority_status %d", ret, minority_status); if(handle_status_and_schema_mismatch(ret, minority_status, a->$globkey)) continue; if(ret == VAL_STATUS_COMMIT) success = 1; } } #endif } void BOOTSTRAP(int argc, char *argv[]) { B_list args = B_listG_new(NULL,NULL); B_SequenceD_list wit = B_SequenceD_listG_witness; for (int i=0; i< argc; i++) wit->$class->append(wit,args,to$str(argv[i])); env_actor = B_EnvG_newactor(B_WorldCapG_new(), B_SysCapG_new(), args); env_actor->nr_wthreads = toB_int(num_wthreads); root_actor = $ROOT(); // Assumed to return $NEWACTOR(X) for the selected root actor X time_t now = current_time(); B_Msg m = B_MsgG_newXX(root_actor, &$InitRoot$cont, now, &$Done$instance); #ifdef ACTON_DB if (db) { int ret = 0, minority_status = 0; while(!rts_exit) { ret = remote_enqueue_in_txn(($WORD*)&m->$globkey, 1, NULL, 0, MSG_QUEUE, (WORD)root_actor->$globkey, &minority_status, NULL, db); rtsd_printf(" # enqueue bootstrap msg %ld to root actor queue %ld returns %d, minority_status %d", m->$globkey, root_actor->$globkey, ret, minority_status); if(!handle_status_and_schema_mismatch(ret, minority_status, root_actor->$globkey)) break; } } #endif if (ENQ_msg(m, root_actor)) { ENQ_ready(root_actor); } } void save_actor_state($Actor current, B_Msg m) { #ifdef ACTON_DB if (db) { int success = 0; reverse_outgoing_queue(current); while(!success && !rts_exit) { uuid_t * txnid = remote_new_txn(db); if(txnid == NULL) continue; current->$consume_hd++; serialize_actor(current, txnid); FLUSH_outgoing_db(current, txnid); serialize_msg(current->B_Msg, txnid); long key = current->$globkey; snode_t *m_start, *m_end; int entries_read = 0, minority_status = 0; int64_t read_head = -1; int ret0 = remote_read_queue_in_txn(($WORD) db->local_rts_id, 0, 0, MSG_QUEUE, ($WORD)key, 1, &entries_read, &read_head, &m_start, &m_end, &minority_status, NULL, db); rtsd_printf(" # dummy read msg from queue %ld returns %d, entries read: %d", key, ret0, entries_read); if(handle_status_and_schema_mismatch(ret0, minority_status, key)) continue; int ret1 = remote_consume_queue_in_txn(($WORD) db->local_rts_id, 0, 0, MSG_QUEUE, ($WORD)key, read_head, &minority_status, txnid, db); rtsd_printf(" # consume msg %ld from queue %ld returns %d", m->$globkey, key, ret1); if(handle_status_and_schema_mismatch(ret1, minority_status, key)) continue; int ret2 = remote_commit_txn(txnid, &minority_status, db); rtsd_printf("############## Commit returned %d, minority_status %d", ret2, minority_status); if(handle_status_and_schema_mismatch(ret2, minority_status, key)) continue; if(ret2 == VAL_STATUS_COMMIT) success = 1; } FLUSH_outgoing_local(current); } else { #endif reverse_outgoing_queue(current); FLUSH_outgoing_local(current); #ifdef ACTON_DB } #endif } //////////////////////////////////////////////////////////////////////////////////////// void main_stop_cb(uv_async_t *ev) { uv_stop(uv_loops[0]); } void arm_timer_ev(); void main_wake_cb(uv_async_t *ev) { // Wäjky-päjky arm_timer_ev(); } void main_timer_cb(uv_timer_t *ev) { handle_timeout(); arm_timer_ev(); } void arm_timer_ev() { time_t next_time = next_timeout(); if (next_time) { time_t now = current_time(); long long int offset = (next_time - now) / 1000; // offset in milliseconds // Negative offset means we missed to trigger in time. Set timeout to 0 // to directly run on next uv cycle. if (offset < 0) offset = 0; int r = uv_timer_start(timer_ev, main_timer_cb, offset, 0); if (r != 0) { char errmsg[1024] = "Unable to set timer: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_fatal(errmsg); } } else { int r = uv_timer_stop(timer_ev); if (r != 0) { char errmsg[1024] = "Unable to stop timer: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_fatal(errmsg); } } } void wt_stop_cb(uv_async_t *ev) { WorkerCtx wctx = GET_WCTX(); uv_stop((uv_loop_t *)wctx->uv_loop); } void wt_wake_cb(uv_async_t *ev) { // We just wake up the uv loop here if it is blocked waiting for IO, real // work is run later when wt_work_cb is called as part of the "check" phase. } void wt_work_cb(uv_check_t *ev) { WorkerCtx wctx = (WorkerCtx)ev->data; assert(wctx->id >= 0 && wctx->id < 256); uv_timespec64_t ts_start, ts1, ts2, ts3; long long int runtime = 0; uv_clock_gettime(UV_CLOCK_MONOTONIC, &ts_start); while (true) { if (rts_exit) { return; } volatile $Actor current = DEQ_ready(wctx->id); if (!current) return; wake_wt(SHARED_RQ); SET_SELF(current); volatile B_Msg m = current->B_Msg; $Cont cont = m->$cont; $WORD val = m->value; uv_clock_gettime(UV_CLOCK_MONOTONIC, &ts1); wt_stats[wctx->id].state = WT_Working; $R r; if (wctx->jump0 || $PUSH()) { // Normal path if (!wctx->jump0) { wctx->jump0 = wctx->jump_top; } rtsd_printf("## Running actor %ld : %s", current->$globkey, current->$class->$GCINFO); r = cont->$class->__call__(cont, val); uv_clock_gettime(UV_CLOCK_MONOTONIC, &ts2); long long int diff = (ts2.tv_sec * 1000000000 + ts2.tv_nsec) - (ts1.tv_sec * 1000000000 + ts1.tv_nsec); wt_stats[wctx->id].conts_count++; wt_stats[wctx->id].conts_sum += diff; if (diff < 100) { wt_stats[wctx->id].conts_100ns++; } else if (diff < 1 * 1000) { wt_stats[wctx->id].conts_1us++; } else if (diff < 10 * 1000) { wt_stats[wctx->id].conts_10us++; } else if (diff < 100 * 1000) { wt_stats[wctx->id].conts_100us++; } else if (diff < 1 * 1000000) { wt_stats[wctx->id].conts_1ms++; } else if (diff < 10 * 1000000) { wt_stats[wctx->id].conts_10ms++; } else if (diff < 100 * 1000000) { wt_stats[wctx->id].conts_100ms++; } else if (diff < 1 * 1000000000) { wt_stats[wctx->id].conts_1s++; } else if (diff < (long long int)10 * 1000000000) { wt_stats[wctx->id].conts_10s++; } else if (diff < (long long int)100 * 1000000000) { wt_stats[wctx->id].conts_100s++; } else { wt_stats[wctx->id].conts_inf++; } } else { // Exceptional path assert(wctx->jump0 != NULL); assert(wctx->jump0->xval != NULL); B_BaseException ex = wctx->jump0->xval; rtsd_printf("## (%d) Actor %ld : %s longjmp exception: %s", wctx->id, current->$globkey, current->$class->$GCINFO, ex->$class->$GCINFO); r = $R_FAIL(ex); } switch (r.tag) { case $RDONE: { save_actor_state(current, m); m->value = r.value; // m->value holds the message result, $Actor b = FREEZE_waiting(m, MARK_RESULT); // so mark this and stop further m->waiting additions while (b) { b->B_Msg->value = r.value; b->$waitsfor = NULL; $Actor c = b->$next; ENQ_ready(b); rtsd_printf("## Waking up actor %ld : %s", b->$globkey, b->$class->$GCINFO); b = c; } rtsd_printf("## DONE actor %ld : %s", current->$globkey, current->$class->$GCINFO); if (DEQ_msg(current)) { ENQ_ready(current); } break; } case $RCONT: { m->$cont = r.cont; m->value = r.value; rtsd_printf("## CONT actor %ld : %s", current->$globkey, current->$class->$GCINFO); ENQ_ready(current); break; } case $RFAIL: { $Catcher c = current->$catcher; if (c) { // Normal exception handling c->xval = (B_BaseException)r.value; m->$cont = c->$cont; m->value = B_False; // False signals the exceptional branch rtsd_printf("## FAIL/handle actor %ld : %s", current->$globkey, current->$class->$GCINFO); ENQ_ready(current); } else { // An unhandled exception save_actor_state(current, m); B_BaseException ex = (B_BaseException)r.value; m->value = r.value; // m->value holds the raised exception, $Actor b = FREEZE_waiting(m, MARK_EXCEPTION); // so mark this and stop further m->waiting additions // If any other actor is waiting for our result / exception, // then we consider the exception handled and we can avoid // printing the exception both in the originating actor and in // the waiting actor. Thus we only print Unhandled exception in // the originating actor when there is no one waiting for us. if (!b) fprintf(stderr, "Unhandled exception in actor: %s[%ld]:\n %s\n", unmangle_name(current->$class->$GCINFO), current->$globkey, fromB_str(ex->$class->__str__(ex))); while (b) { b->B_Msg->$cont = &$Fail$instance; b->B_Msg->value = r.value; b->$waitsfor = NULL; $Actor c = b->$next; ENQ_ready(b); rtsd_printf("## Propagating exception to actor %ld : %s", b->$globkey, b->$class->$GCINFO); b = c; } if (DEQ_msg(current)) { ENQ_ready(current); } rtsd_printf("## Done handling failed actor %ld : %s", current->$globkey, current->$class->$GCINFO); } break; } case $RWAIT: { #ifdef ACTON_DB if (db) { int success = 0, ret = 0, minority_status = 0; reverse_outgoing_queue(current); while(!success && !rts_exit) { uuid_t * txnid = remote_new_txn(db); if(txnid == NULL) continue; serialize_actor(current, txnid); FLUSH_outgoing_db(current, txnid); serialize_msg(current->B_Msg, txnid); ret = remote_commit_txn(txnid, &minority_status, db); rtsd_printf("############## Commit returned %d, minority_status %d", ret, minority_status); if(handle_status_and_schema_mismatch(ret, minority_status, current->$globkey)) continue; if(ret == VAL_STATUS_COMMIT) success = 1; } } else { #endif reverse_outgoing_queue(current); #ifdef ACTON_DB } #endif m->$cont = r.cont; B_Msg x = (B_Msg)r.value; assert(x != NULL); bool added_waiting = ADD_waiting(current, x); FLUSH_outgoing_local(current); if (added_waiting) { // x->cont is a proper $Cont: x is still being processed so current was added to x->waiting rtsd_printf("## AWAIT actor %ld : %s", current->$globkey, current->$class->$GCINFO); } else if (EXCEPTIONAL(x)) { // x->cont == MARK_EXCEPTION: x->value holds the raised exception, current is not in x->waiting rtsd_printf("## AWAIT/fail actor %ld : %s", current->$globkey, current->$class->$GCINFO); m->$cont = &$Fail$instance; m->value = x->value; ENQ_ready(current); } else { // x->cont == MARK_RESULT: x->value holds the final response, current is not in x->waiting rtsd_printf("## AWAIT/wakeup actor %ld : %s", current->$globkey, current->$class->$GCINFO); m->value = x->value; ENQ_ready(current); } break; } } SET_SELF(NULL); uv_clock_gettime(UV_CLOCK_MONOTONIC, &ts3); long long int diff = (ts3.tv_sec * 1000000000 + ts3.tv_nsec) - (ts2.tv_sec * 1000000000 + ts2.tv_nsec); wt_stats[wctx->id].bkeep_count++; wt_stats[wctx->id].bkeep_sum += diff; if (diff < 100) { wt_stats[wctx->id].bkeep_100ns++; } else if (diff < 1 * 1000) { wt_stats[wctx->id].bkeep_1us++; } else if (diff < 10 * 1000) { wt_stats[wctx->id].bkeep_10us++; } else if (diff < 100 * 1000) { wt_stats[wctx->id].bkeep_100us++; } else if (diff < 1 * 1000000) { wt_stats[wctx->id].bkeep_1ms++; } else if (diff < 10 * 1000000) { wt_stats[wctx->id].bkeep_10ms++; } else if (diff < 100 * 1000000) { wt_stats[wctx->id].bkeep_100ms++; } else if (diff < 1 * 1000000000) { wt_stats[wctx->id].bkeep_1s++; } else if (diff < (long long int)10 * 1000000000) { wt_stats[wctx->id].bkeep_10s++; } else if (diff < (long long int)100 * 1000000000) { wt_stats[wctx->id].bkeep_100s++; } else { wt_stats[wctx->id].bkeep_inf++; } wt_stats[wctx->id].state = WT_Idle; runtime = (ts3.tv_sec * 1000000000 + ts3.tv_nsec) - (ts_start.tv_sec * 1000000000 + ts_start.tv_nsec); // run for max 20ms before yielding to IO // NOTE: since we are not preemptive, a single long continuation can // exceed this cap if (runtime > 20*1000000) break; } // if there's more work, wake up ourselves again to process more but // interleave with some IO uv_async_send(&wake_ev[wctx->id]); } void *main_loop(void *idx) { WorkerCtx wctx = (WorkerCtx)GC_malloc(sizeof(struct WorkerCtx)); wctxs[(long)idx] = wctx; wctx->id = (long)idx; wctx->uv_loop = uv_loops[wctx->id]; wctx->jump_top = NULL; wctx->jump0 = NULL; #ifdef ACTON_THREADS pthread_setspecific(pkey_wctx, (void *)wctx); #endif char tname[11]; // Enough for "Worker XXX\0" snprintf(tname, sizeof(tname), "Worker %ld", wctx->id); #ifdef ACTON_THREADS #if defined(IS_MACOS) pthread_setname_np(tname); #else pthread_setname_np(pthread_self(), tname); #endif #endif uv_check_init(wctx->uv_loop, &work_ev[wctx->id]); work_ev[wctx->id].data = wctx; uv_check_start(&work_ev[wctx->id], (uv_check_cb)wt_work_cb); wt_stats[wctx->id].state = WT_Idle; int r = uv_run(wctx->uv_loop, UV_RUN_DEFAULT); wt_stats[wctx->id].state = WT_NoExist; rtsd_printf("Exiting..."); return NULL; } //////////////////////////////////////////////////////////////////////////////////////// void $register_rts () { $register_force(MSG_ID,&B_MsgG_methods); $register_force(ACTOR_ID,&$ActorG_methods); $register_force(CATCHER_ID,&$CatcherG_methods); $register_force(PROC_ID,&$procG_methods); $register_force(ACTION_ID,&$actionG_methods); $register_force(MUT_ID,&$mutG_methods); $register_force(PURE_ID,&$pureG_methods); $register_force(CONT_ID,&$ContG_methods); $register_force(DONE_ID,&$DoneG_methods); $register_force(CONSTCONT_ID,&$ConstContG_methods); $register(&$DoneG_methods); $register(&$InitRootG_methods); $register(&B_EnvG_methods); } //////////////////////////////////////////////////////////////////////////////////////// #ifdef ACTON_DB void dbc_ops_stats_to_json(yyjson_mut_doc *doc, yyjson_mut_val *j_mpoint, struct dbc_ops_stat *ops_stat) { yyjson_mut_val *j_ops_stat = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, j_mpoint, ops_stat->name, j_ops_stat); yyjson_mut_obj_add_int(doc, j_ops_stat, "called", ops_stat->called); yyjson_mut_obj_add_int(doc, j_ops_stat, "completed", ops_stat->completed); yyjson_mut_obj_add_int(doc, j_ops_stat, "success", ops_stat->success); yyjson_mut_obj_add_int(doc, j_ops_stat, "error", ops_stat->error); yyjson_mut_obj_add_int(doc, j_ops_stat, "no_quorum", ops_stat->no_quorum); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_sum", ops_stat->time_sum); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_100ns", ops_stat->time_100ns); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_1us", ops_stat->time_1us); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_10us", ops_stat->time_10us); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_100us", ops_stat->time_100us); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_1ms", ops_stat->time_1ms); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_10ms", ops_stat->time_10ms); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_100ms", ops_stat->time_100ms); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_1s", ops_stat->time_1s); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_10s", ops_stat->time_10s); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_100s", ops_stat->time_100s); yyjson_mut_obj_add_int(doc, j_ops_stat, "time_inf", ops_stat->time_inf); } #endif const char* stats_to_json () { yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); yyjson_mut_val *root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); yyjson_mut_obj_add_str(doc, root, "name", appname); yyjson_mut_obj_add_int(doc, root, "pid", pid); uv_timespec64_t ts; if (uv_clock_gettime(UV_CLOCK_REALTIME, &ts) != 0) { log_fatal("Unable to get precise time"); return NULL; } struct tm tm; #ifdef _WIN32 errno_t result = localtime_s(&tm, &ts.tv_sec); if (result != 0) { char errmsg[1024] = "Error getting time: "; uv_strerror_r(errno, errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg)); log_warn("%s", errmsg); return NULL; } #else localtime_r(&ts.tv_sec, &tm); #endif char dt[32]; // = "YYYY-MM-ddTHH:mm:ss.SSS+0000"; strftime(dt, 32, "%Y-%m-%dT%H:%M:%S.000%z", &tm); sprintf(dt + 20, "%03hu%s", (unsigned short)(ts.tv_nsec / 1000000), dt + 23); yyjson_mut_obj_add_str(doc, root, "datetime", dt); // Worker threads yyjson_mut_val *j_stat = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, root, "wt", j_stat); for (unsigned int i = 1; i < NUM_THREADS; i++) { yyjson_mut_val *j_wt = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, j_stat, wt_stats[i].key, j_wt); yyjson_mut_obj_add_str(doc, j_wt, "state", WT_State_name[wt_stats[i].state]); yyjson_mut_obj_add_int(doc, j_wt, "sleeps", wt_stats[i].sleeps); yyjson_mut_obj_add_int(doc, j_wt, "qlen", rqs[i].count); yyjson_mut_obj_add_int(doc, j_wt, "conts_count", wt_stats[i].conts_count); yyjson_mut_obj_add_int(doc, j_wt, "conts_sum", wt_stats[i].conts_sum); yyjson_mut_obj_add_int(doc, j_wt, "conts_100ns", wt_stats[i].conts_100ns); yyjson_mut_obj_add_int(doc, j_wt, "conts_1us", wt_stats[i].conts_1us); yyjson_mut_obj_add_int(doc, j_wt, "conts_10us", wt_stats[i].conts_10us); yyjson_mut_obj_add_int(doc, j_wt, "conts_100us", wt_stats[i].conts_100us); yyjson_mut_obj_add_int(doc, j_wt, "conts_1ms", wt_stats[i].conts_1ms); yyjson_mut_obj_add_int(doc, j_wt, "conts_10ms", wt_stats[i].conts_10ms); yyjson_mut_obj_add_int(doc, j_wt, "conts_100ms", wt_stats[i].conts_100ms); yyjson_mut_obj_add_int(doc, j_wt, "conts_1s", wt_stats[i].conts_1s); yyjson_mut_obj_add_int(doc, j_wt, "conts_10s", wt_stats[i].conts_10s); yyjson_mut_obj_add_int(doc, j_wt, "conts_100s", wt_stats[i].conts_100s); yyjson_mut_obj_add_int(doc, j_wt, "conts_inf", wt_stats[i].conts_inf); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_count", wt_stats[i].bkeep_count); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_sum", wt_stats[i].bkeep_sum); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_100ns", wt_stats[i].bkeep_100ns); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_1us", wt_stats[i].bkeep_1us); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_10us", wt_stats[i].bkeep_10us); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_100us", wt_stats[i].bkeep_100us); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_1ms", wt_stats[i].bkeep_1ms); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_10ms", wt_stats[i].bkeep_10ms); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_100ms", wt_stats[i].bkeep_100ms); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_1s", wt_stats[i].bkeep_1s); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_10s", wt_stats[i].bkeep_10s); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_100s", wt_stats[i].bkeep_100s); yyjson_mut_obj_add_int(doc, j_wt, "bkeep_inf", wt_stats[i].bkeep_inf); } // Database yyjson_mut_val *j_dbc = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, root, "db_client", j_dbc); #ifdef ACTON_DB #define X(ops_name) \ dbc_ops_stats_to_json(doc, j_dbc, dbc_stats.ops_name); LIST_OF_DBC_OPS #undef X #endif const char *json = yyjson_mut_write(doc, 0, NULL); yyjson_mut_doc_free(doc); return json; } #ifdef ACTON_DB const char* db_membership_to_json () { yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); yyjson_mut_val *root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); yyjson_mut_obj_add_str(doc, root, "name", appname); yyjson_mut_obj_add_int(doc, root, "pid", pid); uv_timespec64_t ts; if (uv_clock_gettime(UV_CLOCK_REALTIME, &ts) != 0) { log_fatal("Unable to get precise time"); return NULL; } struct tm tm; localtime_r(&ts.tv_sec, &tm); char dt[32]; // = "YYYY-MM-ddTHH:mm:ss.SSS+0000"; strftime(dt, 32, "%Y-%m-%dT%H:%M:%S.000%z", &tm); sprintf(dt + 20, "%03hu%s", (unsigned short)(ts.tv_nsec / 1000000), dt + 23); yyjson_mut_obj_add_str(doc, root, "datetime", dt); // Actual topology yyjson_mut_val *j_nodes = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, root, "nodes", j_nodes); for (snode_t * crt = HEAD(db->servers); crt!=NULL; crt = NEXT(crt)) { remote_server * rs = (remote_server *) crt->value; yyjson_mut_val *j_node = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, j_nodes, rs->id, j_node); yyjson_mut_obj_add_str(doc, j_node, "type", "DDB"); yyjson_mut_obj_add_str(doc, j_node, "hostname", rs->hostname); yyjson_mut_obj_add_str(doc, j_node, "status", RS_status_name[rs->status]); } for (snode_t * crt = HEAD(db->rtses); crt!=NULL; crt = NEXT(crt)) { rts_descriptor * nd = (rts_descriptor *) crt->value; yyjson_mut_val *j_node = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, j_nodes, nd->id, j_node); yyjson_mut_obj_add_str(doc, j_node, "type", "RTS"); yyjson_mut_obj_add_str(doc, j_node, "hostname", nd->hostname); yyjson_mut_obj_add_str(doc, j_node, "status", RS_status_name[nd->status]); yyjson_mut_obj_add_int(doc, j_node, "local_rts_id", nd->local_rts_id); yyjson_mut_obj_add_int(doc, j_node, "dc_id", nd->dc_id); yyjson_mut_obj_add_int(doc, j_node, "rack_id", nd->rack_id); } const char *json = yyjson_mut_write(doc, 0, NULL); yyjson_mut_doc_free(doc); return json; } #endif const char* actors_to_json () { yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); yyjson_mut_val *root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); yyjson_mut_obj_add_str(doc, root, "name", appname); yyjson_mut_obj_add_int(doc, root, "pid", pid); uv_timespec64_t ts; if (uv_clock_gettime(UV_CLOCK_REALTIME, &ts) != 0) { log_fatal("Unable to get precise time"); return NULL; } struct tm tm; #ifdef _WIN32 errno_t result = localtime_s(&tm, &ts.tv_sec); if (result != 0) { char errmsg[1024] = "Error getting time: "; uv_strerror_r(errno, errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg)); log_warn("%s", errmsg); return NULL; } #else localtime_r(&ts.tv_sec, &tm); #endif char dt[32]; // = "YYYY-MM-ddTHH:mm:ss.SSS+0000"; strftime(dt, 32, "%Y-%m-%dT%H:%M:%S.000%z", &tm); sprintf(dt + 20, "%03hu%s", (unsigned short)(ts.tv_nsec / 1000000), dt + 23); yyjson_mut_obj_add_str(doc, root, "datetime", dt); // Actual topology yyjson_mut_val *j_actors = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, root, "actors", j_actors); #ifdef ACTON_DB // TODO: implement similar option but local only for(snode_t * crt = HEAD(db->actors); crt!=NULL; crt = NEXT(crt)) { actor_descriptor * a = (actor_descriptor *) crt->value; char a_id_str[21]; // up to length of unsigned long long snprintf(a_id_str, 21, "%lld", (unsigned long long)a->actor_id); yyjson_mut_val *act_id = yyjson_mut_strcpy(doc, a_id_str); yyjson_mut_val *j_a = yyjson_mut_obj(doc); yyjson_mut_obj_put(j_actors, act_id, j_a); yyjson_mut_obj_add_str(doc, j_a, "rts", a->host_rts->id); yyjson_mut_obj_add_str(doc, j_a, "local", a->is_local?"yes":"no"); yyjson_mut_obj_add_str(doc, j_a, "status", Actor_status_name[a->status]); } #endif const char *json = yyjson_mut_write(doc, 0, NULL); yyjson_mut_doc_free(doc); return json; } #ifdef ACTON_THREADS void *$mon_log_loop(void *period) { log_info("Starting monitor log, with %ld second(s) period, to: %s", (long)period, mon_log_path); #if defined(IS_MACOS) pthread_setname_np("Monitor Log"); #else pthread_setname_np(pthread_self(), "Monitor Log"); #endif FILE *f; f = fopen(mon_log_path, "w"); if (!f) { fprintf(stderr, "ERROR: Unable to open RTS monitor log file (%s) for writing\n", mon_log_path); exit(1); } while (1) { const char *json = stats_to_json(); fputs(json, f); fputs("\n", f); if (rts_exit > 0) { log_info("Shutting down RTS Monitor log thread."); break; } pthread_mutex_lock(&rts_exit_lock); struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += (long)period; pthread_cond_timedwait(&rts_exit_signal, &rts_exit_lock, &ts); pthread_mutex_unlock(&rts_exit_lock); } fclose(f); return NULL; } void *$mon_socket_loop() { log_info("Starting monitor socket listen on %s", mon_socket_path); #if defined(IS_MACOS) pthread_setname_np("Monitor Socket"); #else pthread_setname_np(pthread_self(), "Monitor Socket"); #endif #ifdef _WIN32 // TODO: implement on windows!? #else int s, client_sock, len; struct sockaddr_un local, remote; char q[100]; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "ERROR: Unable to create Monitor Socket\n"); exit(1); } local.sun_family = AF_UNIX; strcpy(local.sun_path, mon_socket_path); unlink(local.sun_path); len = sizeof(local.sun_path) + sizeof(local.sun_family); if (bind(s, (struct sockaddr *)&local, len) == -1) { fprintf(stderr, "ERROR: Unable to bind to Monitor Socket\n"); exit(1); } if (listen(s, 5) == -1) { fprintf(stderr, "ERROR: Unable to listen on Monitor Socket\n"); exit(1); } while (1) { socklen_t t = sizeof(remote); if ((client_sock = accept(s, (struct sockaddr *)&remote, &t)) == -1) { perror("accept"); exit(1); } int n; char rbuf[64], *buf_base, *str; ssize_t bytes_read; size_t buf_used = 0, len; while (1) { bytes_read = recv(client_sock, &rbuf[buf_used], sizeof(rbuf) - buf_used, 0); if (bytes_read <= 0) break; buf_used += bytes_read; buf_base = rbuf; while (1) { if (buf_used == 0) break; int r = netstring_read(&buf_base, &buf_used, &str, &len); if (r != 0) { log_info("Mon socket: Error reading netstring: %d", r); break; } if (memcmp(str, "actors", len) == 0) { const char *json = actors_to_json(); char *send_buf = GC_malloc(strlen(json)+14); // 14 = maximum digits for length is 9 (999999999) + : + ; + \0 sprintf(send_buf, "%lu:%s,", strlen(json), json); int send_res = send(client_sock, send_buf, strlen(send_buf), 0); //free((void *)json); //free((void *)send_buf); if (send_res < 0) { log_info("Mon socket: Error sending"); break; } } #ifdef ACTON_DB if (memcmp(str, "membership", len) == 0) { const char *json = db_membership_to_json(); char *send_buf = GC_malloc(strlen(json)+14); // 14 = maximum digits for length is 9 (999999999) + : + ; + \0 sprintf(send_buf, "%lu:%s,", strlen(json), json); int send_res = send(client_sock, send_buf, strlen(send_buf), 0); //free((void *)json); //free((void *)send_buf); if (send_res < 0) { log_info("Mon socket: Error sending"); break; } } #endif if (memcmp(str, "WTS", len) == 0) { const char *json = stats_to_json(); char *send_buf = GC_malloc(strlen(json)+14); // 14 = maximum digits for length is 9 (999999999) + : + ; + \0 sprintf(send_buf, "%lu:%s,", strlen(json), json); int send_res = send(client_sock, send_buf, strlen(send_buf), 0); //free((void *)json); //free((void *)send_buf); if (send_res < 0) { log_info("Mon socket: Error sending"); break; } } } if (buf_base > rbuf && buf_used > 0) memmove(rbuf, buf_base, buf_used); } close(client_sock); } return NULL; #endif } #endif void rts_shutdown() { #if defined(_WIN32) || defined(_WIN64) #else tcsetattr(STDIN_FILENO, TCSANOW, &old_stdin_attr); #endif rts_exit = 1; // 0 = main thread, rest is wthreads, thus +1 for (int i = 0; i < NUM_THREADS; i++) { uv_async_send(&stop_ev[i]); } } #ifndef _WIN32 void print_trace() { char pid_buf[30]; sprintf(pid_buf, "%d", getpid()); char name_buf[512]; name_buf[readlink("/proc/self/exe", name_buf, 511)]=0; #ifdef __linux__ prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); #endif #ifdef __linux__ int child_pid = fork(); if (!child_pid) { dup2(2, 1); // redirect output to stderr execlp("lldb", "lldb", "-p", pid_buf, "--batch", "-o", "thread backtrace all", "-o", "exit", "--one-line-on-crash", "exit", name_buf, NULL); execlp("gdb", "gdb", "--quiet", "--batch", "-n", "-ex", "set confirm off", "-ex", "set pagination off", "-ex", "set debuginfod enabled off", "-ex", "thread", "-ex", "thread apply all backtrace full", name_buf, pid_buf, NULL); fprintf(stderr, "Unable to get detailed backtrace using lldb or gdb\n"); exit(0); /* If lldb/gdb failed to start */ } else { waitpid(child_pid, NULL, 0); } #else fprintf(stderr, "Unable to get detailed backtrace on this platform\n"); exit(0); /* If lldb/gdb failed to start */ #endif } void launch_debugger(int signum) { fprintf(stderr, "\nERROR: This is the automatic debug launcher for %s\n", appname); if (signum == SIGILL) fprintf(stderr, "\nERROR: illegal instruction\n"); if (signum == SIGSEGV) fprintf(stderr, "\nERROR: segmentation fault\n"); fprintf(stderr, "Starting interactive debugger...\n"); char pid_buf[30]; sprintf(pid_buf, "%d", getpid()); char name_buf[512]; name_buf[readlink("/proc/self/exe", name_buf, 511)]=0; #ifdef __linux__ prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); #endif int child_pid = fork(); if (!child_pid) { char findthread[40] = "thread find "; sprintf(findthread + strlen(findthread), "%p", (void *)pthread_self()); execlp("gdb", "gdb", "--quiet", "-n", "-ex", "set confirm off", "-ex", findthread, name_buf, pid_buf, NULL); fprintf(stderr, "Unable to get detailed backtrace using lldb or gdb"); exit(0); /* If lldb/gdb failed to start */ } else { waitpid(child_pid, NULL, 0); exit(0); } } void crash_handler(int signum) { fprintf(stderr, "\nERROR: This is the automatic crash handler for %s\n", appname); if (signum == SIGILL) fprintf(stderr, "ERROR: illegal instruction\n"); if (signum == SIGSEGV) fprintf(stderr, "ERROR: segmentation fault\n"); fprintf(stderr, "NOTE: this is likely a bug in acton, please report this at:\n"); fprintf(stderr, "NOTE: https://github.com/actonlang/acton/issues/new\n"); fprintf(stderr, "NOTE: include the backtrace printed below between -- 8< -- lines\n"); fprintf(stderr, "\n-- 8< --------- BACKTRACE --------------------\n"); print_trace(); fprintf(stderr, "\n-- 8< --------- END BACKTRACE ----------------\n"); if (signum == SIGILL) fprintf(stderr, "\nERROR: illegal instruction\n"); if (signum == SIGSEGV) fprintf(stderr, "\nERROR: segmentation fault\n"); fprintf(stderr, "NOTE: this is likely a bug in acton, please report this at:\n"); fprintf(stderr, "NOTE: https://github.com/actonlang/acton/issues/new\n"); fprintf(stderr, "NOTE: include the backtrace printed above between -- 8< -- lines\n"); // Restore / uninstall signal handlers for SIGILL & SIGSEGV sa_ill.sa_handler = NULL; if (sigaction(SIGILL, &sa_ill, NULL) == -1) { log_fatal("Failed to install signal handler for SIGILL: %s", strerror(errno)); exit(1); } sa_segv.sa_handler = NULL; if (sigaction(SIGSEGV, &sa_segv, NULL) == -1) { log_fatal("Failed to install signal handler for SIGSEGV: %s", strerror(errno)); exit(1); } // Kill ourselves with original signal sent to us kill(getpid(), signum); } void sigint_handler(int signum) { if (rts_exit == 0) { log_info("Received SIGINT, shutting down gracefully..."); rts_shutdown(); } else { log_info("Received SIGINT during graceful shutdown, exiting immediately"); exit(return_val); } } void sigterm_handler(int signum) { if (rts_exit == 0) { log_info("Received SIGTERM, shutting down gracefully..."); rts_shutdown(); } else { log_info("Received SIGTERM during graceful shutdown, exiting immediately"); exit(return_val); } } #endif void check_uv_fatal(int status, char msg[]) { if (status == 0) return; char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "%s", msg); uv_strerror_r(status, errmsg+strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_fatal(errmsg); exit(1); } struct option { const char *name; const char *arg_name; int val; const char *desc; }; void print_help(struct option *opt) { printf("The Acton RTS reads and consumes the following options and arguments. All\n" \ "other parameters are passed verbatim to the Acton application. Option\n" \ "arguments can be passed either with --rts-option=ARG or --rts-option ARG\n\n"); while (opt->name) { char optarg[64]; sprintf(optarg, "%s%s%s", opt->name, opt->arg_name?"=":"", opt->arg_name?opt->arg_name:""); printf(" --%-30s %s\n", optarg, opt->desc); opt++; } printf("\n"); exit(0); } void DaveNull () {} int main(int argc, char **argv) { // Init garbage collector and suppress warnings GC_INIT(); GC_set_warn_proc(DaveNull); acton_init_alloc(); acton_replace_allocator(GC_malloc, GC_malloc_atomic, GC_realloc, GC_calloc, acton_noop_free, GC_strdup, GC_strndup); int ddb_no_host = 0; char **ddb_host = NULL; char *rts_host = "localhost"; int ddb_port = 32000; int ddb_replication = 3; int rts_node_id = -1; int rts_rack_id = -1; int rts_dc_id = -1; int new_argc = argc; int cpu_pin; uv_cpu_info_t* cpu_infos; int num_cores; if (uv_cpu_info(&cpu_infos, &num_cores) != 0) { log_fatal("Unable to get CPU info"); exit(1); } bool mon_on_exit = false; bool auto_backtrace = true; bool interactive_backtrace = false; char *log_path = NULL; FILE *logf = NULL; bool log_stderr = false; appname = argv[0]; pid = getpid(); #ifndef _WIN32 // Do line buffered output setlinebuf(stdout); // Signal handling sigfillset(&sa_abrt.sa_mask); sigfillset(&sa_ill.sa_mask); sigfillset(&sa_int.sa_mask); sigfillset(&sa_pipe.sa_mask); sigfillset(&sa_segv.sa_mask); sigfillset(&sa_term.sa_mask); sa_abrt.sa_flags = SA_RESTART; sa_ill.sa_flags = SA_RESTART; sa_int.sa_flags = SA_RESTART; sa_pipe.sa_flags = SA_RESTART; sa_segv.sa_flags = SA_RESTART; sa_term.sa_flags = SA_RESTART; // Ignore SIGPIPE, like we get if the other end talking to us on the Monitor // socket (which is a Unix domain socket) goes away. sa_pipe.sa_handler = SIG_IGN; // Handle signals sa_int.sa_handler = &sigint_handler; sa_term.sa_handler = &sigterm_handler; if (sigaction(SIGPIPE, &sa_pipe, NULL) == -1) { log_fatal("Failed to install signal handler for SIGPIPE: %s", strerror(errno)); exit(1); } if (sigaction(SIGINT, &sa_int, NULL) == -1) { log_fatal("Failed to install signal handler for SIGINT: %s", strerror(errno)); exit(1); } if (sigaction(SIGTERM, &sa_term, NULL) == -1) { log_fatal("Failed to install signal handler for SIGTERM: %s", strerror(errno)); exit(1); } #endif #ifdef ACTON_THREADS pthread_key_create(&self_key, NULL); pthread_setspecific(self_key, NULL); pthread_key_create(&pkey_wctx, NULL); #else self_actor = NULL; #endif log_set_quiet(true); /* * A note on argument parsing: The RTS has its own command line arguments, * all prefixed with --rts-, which we need to parse out. The remainder of * the arguments should be passed on to the Acton program, thus we need to * fiddle with argv. To avoid modifying argv in place, we create a new argc * and argv which we bootstrap the Acton program with. The special -- means * to stop scanning for options, and any argument following it will be * passed verbatim. * For example (note the duplicate --rts-verbose) * Command line : ./app foo --rts-verbose --bar --rts-verbose * Application sees: [./app, foo, --bar] * Using -- to pass verbatim arguments: * Command line : ./app foo --rts-verbose --bar -- --rts-verbose * Application sees: [./app, foo, --bar, --, --rts-verbose] * * We support both styles of providing an option argument, e.g.: * ./app --rts-wthreads 8 * ./app --rts-wthreads=8 * Optional arguments aren't supported, an option either takes a required * argument or it does not. */ static struct option long_options[] = { {"rts-bt-dbg", NULL, 'x', "Interactively debug on SIGILL / SIGSEGV"}, {"rts-debug", NULL, 'd', "RTS debug, requires program to be compiled with --optimize Debug"}, {"rts-ddb-host", "HOST", 'h', "DDB hostname"}, {"rts-ddb-port", "PORT", 'p', "DDB port [32000]"}, {"rts-ddb-replication", "FACTOR", 'r', "DDB replication factor [3]"}, {"rts-node-id", "ID", 'i', "RTS node ID"}, {"rts-rack-id", "RACK", 'R', "RTS rack ID"}, {"rts-dc-id", "DATACENTER", 'D', "RTS datacenter ID"}, {"rts-host", "RTSHOST", 'N', "RTS hostname"}, {"rts-help", NULL, 'H', "Show this help"}, {"rts-mon-log-path", "PATH", 'l', "Path to RTS mon stats log"}, {"rts-mon-log-period", "PERIOD", 'k', "Periodicity of writing RTS mon stats log entry"}, {"rts-mon-on-exit", NULL, 'E', "Print RTS mon stats to stdout on exit"}, {"rts-mon-socket-path", "PATH", 'm', "Path to unix socket to expose RTS mon stats"}, {"rts-no-bt", NULL, 'B', "Disable automatic backtrace"}, {"rts-log-path", "PATH", 'L', "Path to RTS log"}, {"rts-log-stderr", NULL, 's', "Log to stderr in addition to log file"}, {"rts-verbose", NULL, 'v', "Enable verbose RTS output"}, {"rts-wthreads", "COUNT", 'w', "Number of worker threads [#CPU cores]"}, {NULL, 0, 0} }; // length of long_options array #define OPTLEN (sizeof(long_options) / sizeof(long_options[0]) - 1) int ch = 0; // where we map current (i) argc position into new_argc int new_argc_dst = 0; // stop scanning once we've seen '--', passing the rest verbatim int opt_scan = 1; char **new_argv = acton_malloc((argc+1) * sizeof *new_argv); char *optarg = NULL; for (int i = 0; i < argc; i++) { ch = 0; optarg = NULL; if (strcmp(argv[i], "--") == 0) opt_scan = 0; if (opt_scan) { for (int j=0; j 2 && strncmp(argv[i]+2, long_options[j].name, strlen(long_options[j].name)) == 0) { // argv[i] matches one of our options! ch = long_options[j].val; new_argc--; if (long_options[j].arg_name) { if (strlen(argv[i]) > 2+strlen(long_options[j].name) && argv[i][2+strlen(long_options[j].name)] == '=') { // option argument is in --opt=arg style, so dig out optarg = (char *)argv[i]+(2+strlen(long_options[j].name)+1); } else { // argument has to be next in argv if (i+1 == argc) { // check we are not at end fprintf(stderr, "ERROR: --%s requires an argument.\n", long_options[j].name); exit(1); } i++; optarg = argv[i]; new_argc--; } } break; } } } if (!ch) { // Didn't identify one of our options, so pass through new_argv[new_argc_dst++] = argv[i]; continue; } switch (ch) { case 'B': auto_backtrace = false; break; case 'd': #ifndef DEV fprintf(stderr, "ERROR: RTS debug not supported.\n"); fprintf(stderr, "HINT: Recompile this program using: acton --optimize Debug ...\n"); exit(1); #endif log_set_quiet(false); if (log_get_level() > LOG_DEBUG) log_set_level(LOG_DEBUG); rts_debug = 1; // Enabling rts debug implies verbose RTS output too rts_verbose = 10; break; case 'E': mon_on_exit = true; break; case 'H': print_help(long_options); break; case 'h': ddb_host = acton_realloc(ddb_host, ++ddb_no_host * sizeof *ddb_host); ddb_host[ddb_no_host-1] = optarg; break; case 'k': mon_log_period = atoi(optarg); break; case 'L': log_path = optarg; break; case 'l': mon_log_path = optarg; break; case 'm': mon_socket_path = optarg; break; case 'p': ddb_port = atoi(optarg); break; case 'r': ddb_replication = atoi(optarg); break; case 'i': rts_node_id = atoi(optarg); break; case 'R': rts_rack_id = atoi(optarg); break; case 'D': rts_dc_id = atoi(optarg); break; case 'N': rts_host = acton_strdup(optarg); break; case 's': log_stderr = true; break; case 'v': if (log_get_level() > LOG_INFO) log_set_level(LOG_INFO); rts_verbose = 1; break; case 'w': num_wthreads = atoi(optarg); break; case 'x': interactive_backtrace = true; break; } } new_argv[new_argc] = NULL; #ifndef _WIN32 if (interactive_backtrace) { sa_abrt.sa_handler = &launch_debugger; sa_ill.sa_handler = &launch_debugger; sa_segv.sa_handler = &launch_debugger; } else { sa_abrt.sa_handler = &crash_handler; sa_ill.sa_handler = &crash_handler; sa_segv.sa_handler = &crash_handler; } #endif if (auto_backtrace) { #ifndef _WIN32 if (sigaction(SIGABRT, &sa_abrt, NULL) == -1) { log_fatal("Failed to install signal handler for SIGABRT: %s", strerror(errno)); exit(1); } if (sigaction(SIGILL, &sa_ill, NULL) == -1) { log_fatal("Failed to install signal handler for SIGILL: %s", strerror(errno)); exit(1); } if (sigaction(SIGSEGV, &sa_segv, NULL) == -1) { log_fatal("Failed to install signal handler for SIGSEGV: %s", strerror(errno)); exit(1); } #endif } if (log_path) log_set_quiet(true); if (rts_verbose || log_stderr) log_set_quiet(false); if (log_path) { logf = fopen(log_path, "w"); if (!logf) { fprintf(stderr, "ERROR: Unable to open RTS log file (%s) for writing\n", log_path); exit(1); } log_add_fp(logf, LOG_TRACE); } #ifdef ACTON_THREADS if (num_wthreads > MAX_WTHREADS) { fprintf(stderr, "ERROR: Maximum of %d worker threads supported.\n", MAX_WTHREADS); fprintf(stderr, "HINT: Run this program with fewer worker threads: %s --rts-wthreads %d\n", argv[0], MAX_WTHREADS); exit(1); } // Determine number of worker threads, normally 1:1 per CPU thread / core // For low core count systems we do a minimum of 4 worker threads if (num_wthreads == -1 && num_cores < 4) { // auto, few CPU cores, so use 4 worker threads num_wthreads = 4; cpu_pin = 0; log_info("Detected %ld CPUs: Using %ld worker threads, due to low CPU count. No CPU affinity used.", num_cores, num_wthreads); } else if (num_wthreads == -1) { // auto, many CPU cores, use 1 worker thread per CPU core num_wthreads = num_cores; cpu_pin = 1; log_info("Detected %ld CPUs: Using %ld worker threads for 1:1 mapping with CPU affinity set.", num_cores, num_wthreads); } else { cpu_pin = 0; log_info("Detected %ld CPUs: Using %ld worker threads (manually set). No CPU affinity used.", num_cores, num_wthreads); } #else log_info("Running without threads, main thread will perform all work"); if (num_wthreads != -1) { fprintf(stderr, "ERROR: Threads disabled, provided --rts-wthreads argument has no effect.\n"); fprintf(stderr, "HINT: You cannot compile with --no-threads and use --rts-wthreads at run time.\n"); exit(1); } num_wthreads = 0; #endif // Zeroize statistics for (int i=0; i < MAX_WTHREADS; i++) { wt_stats[i].idx = i; sprintf(wt_stats[i].key, "%d", i); wt_stats[i].state = 0; wt_stats[i].sleeps = 0; wt_stats[i].conts_count = 0; wt_stats[i].conts_sum = 0; wt_stats[i].conts_100ns = 0; wt_stats[i].conts_1us = 0; wt_stats[i].conts_10us = 0; wt_stats[i].conts_100us = 0; wt_stats[i].conts_1ms = 0; wt_stats[i].conts_10ms = 0; wt_stats[i].conts_100ms = 0; wt_stats[i].conts_1s = 0; wt_stats[i].conts_10s = 0; wt_stats[i].conts_100s = 0; wt_stats[i].conts_inf = 0; wt_stats[i].bkeep_count = 0; wt_stats[i].bkeep_sum = 0; wt_stats[i].bkeep_100ns = 0; wt_stats[i].bkeep_1us = 0; wt_stats[i].bkeep_10us = 0; wt_stats[i].bkeep_100us = 0; wt_stats[i].bkeep_1ms = 0; wt_stats[i].bkeep_10ms = 0; wt_stats[i].bkeep_100ms = 0; wt_stats[i].bkeep_1s = 0; wt_stats[i].bkeep_10s = 0; wt_stats[i].bkeep_100s = 0; wt_stats[i].bkeep_inf = 0; } #ifdef ACTON_DB init_dbc_stats(); #endif wctxs[0] = NULL; for (int i=0; i <= num_wthreads; i++) { uv_loop_t *loop = GC_malloc(sizeof(uv_loop_t)); check_uv_fatal(uv_loop_init(loop), "Error initializing libuv loop: "); uv_loops[i] = loop; if (i == 0) { check_uv_fatal(uv_async_init(uv_loops[i], &stop_ev[i], main_stop_cb), "Error initializing libuv stop event: "); check_uv_fatal(uv_async_init(uv_loops[i], &wake_ev[i], main_wake_cb), "Error initializing libuv wake event: "); check_uv_fatal(uv_async_send(&wake_ev[i]), "Error sending initial work event: "); } else { check_uv_fatal(uv_async_init(uv_loops[i], &stop_ev[i], wt_stop_cb), "Error initializing libuv stop event: "); check_uv_fatal(uv_async_init(uv_loops[i], &wake_ev[i], wt_wake_cb), "Error initializing libuv wake event: "); check_uv_fatal(uv_async_send(&wake_ev[i]), "Error sending initial work event: "); } } aux_uv_loop = uv_loops[0]; for (int i=0; i < NUM_RQS; i++) { rqs[i].head = NULL; rqs[i].tail = NULL; rqs[i].count = 0; } #if defined(_WIN32) || defined(_WIN64) #else tcgetattr(STDIN_FILENO, &old_stdin_attr); #endif // RTS startup and module is static stuff, in particular module constants // which are created during module init are static and do not need to be // scanned. We therefore use the real_malloc (not GC_malloc) so that it is // not traced by the GC, thus saving loads of work scanning this memory // over and over. acton_replace_allocator(malloc, malloc, realloc, calloc, acton_noop_free, strdup, strndup); $register_builtin(); B___init__(); $register_rts(); WorkerCtx wctx = (WorkerCtx)GC_malloc(sizeof(struct WorkerCtx)); wctxs[0] = wctx; wctx->id = 0; wctx->uv_loop = uv_loops[wctx->id]; wctx->jump_top = NULL; wctx->jump0 = NULL; #ifdef ACTON_THREADS pthread_setspecific(pkey_wctx, (void *)wctx); #endif $ROOTINIT(); acton_replace_allocator(GC_malloc, GC_malloc_atomic, GC_realloc, GC_calloc, acton_noop_free, GC_strdup, GC_strndup); unsigned int seed; if (ddb_host) { #ifdef ACTON_DB GET_RANDSEED(&seed, 0); log_info("Starting distributed RTS node, host=%s, node_id=%d, rack_id=%d, datacenter_id=%d", rts_host, rts_node_id, rts_rack_id, rts_dc_id); log_info("Using distributed database backend replication factor of %d", ddb_replication); char ** seed_hosts = (char **) malloc(ddb_no_host * sizeof(char *)); int * seed_ports = (int *) malloc(ddb_no_host * sizeof(int)); for (int i=0; i 0) { log_info("Found %d existing actors; Restoring actor state from DDB.", no_items); deserialize_system(start_row); log_info("Actor state restored from DDB."); } else { log_info("No previous state in DDB; Initializing database...\n"); queue_callback * gqc = get_queue_callback(queue_group_message_callback); rtsd_printf("### initializing remote_subscribe_group(consumer_id = %d, group_id = %d)\n", (int) db->local_rts_id, (int) db->local_rts_id); while(!rts_exit) { ret = remote_subscribe_group((WORD) db->local_rts_id, NULL, NULL, (WORD) db->local_rts_id, gqc, &minority_status, db); if(!handle_status_and_schema_mismatch(ret, minority_status, 0)) { break; } } int indices[] = {0}; db_schema_t* db_schema = db_create_schema(NULL, 1, indices, 1, indices, 0, indices, 0); create_db_queue(TIMER_QUEUE); timer_consume_hd = 0; BOOTSTRAP(new_argc, new_argv); log_info("Database intialization complete."); } } else { #endif BOOTSTRAP(new_argc, new_argv); #ifdef ACTON_DB } #endif #ifdef ACTON_THREADS cpu_set_t cpu_set; size_t primary_thread_stack_size; size_t target_thread_stack_size; #if defined(IS_MACOS) primary_thread_stack_size = pthread_get_stacksize_np(pthread_self()); #else pthread_attr_t attr; pthread_getattr_np(pthread_self(), &attr); pthread_attr_getstacksize(&attr, &primary_thread_stack_size); pthread_attr_destroy(&attr); #endif target_thread_stack_size = REQUIRED_STACK_SIZE > primary_thread_stack_size ? (size_t)REQUIRED_STACK_SIZE : primary_thread_stack_size; if (primary_thread_stack_size < target_thread_stack_size) log_warn("Current primary thread stack size: %u, required thread stack size: %u", primary_thread_stack_size, target_thread_stack_size); pthread_attr_t ss_attr; size_t secondary_thread_stack_size = 0; pthread_attr_init(&ss_attr); pthread_attr_getstacksize(&ss_attr, &secondary_thread_stack_size); if (secondary_thread_stack_size < target_thread_stack_size) { log_debug("Secondary thread stack size: %d, required thread stack size: %d", secondary_thread_stack_size, target_thread_stack_size); int err = pthread_attr_setstacksize(&ss_attr, target_thread_stack_size); if (err) log_error("pthread_attr_setstacksize failed: %s", strerror(err)); } // RTS Monitor Log pthread_t mon_log_thread; if (mon_log_path) { pthread_create(&mon_log_thread, &ss_attr, $mon_log_loop, (void *)(intptr_t)mon_log_period); if (cpu_pin) { CPU_ZERO(&cpu_set); CPU_SET(0, &cpu_set); pthread_setaffinity_np(mon_log_thread, sizeof(cpu_set), &cpu_set); } } // RTS Monitor Socket pthread_t mon_socket_thread; if (mon_socket_path) { pthread_create(&mon_socket_thread, &ss_attr, $mon_socket_loop, NULL); if (cpu_pin) { CPU_ZERO(&cpu_set); CPU_SET(0, &cpu_set); pthread_setaffinity_np(mon_socket_thread, sizeof(cpu_set), &cpu_set); } } // Start worker threads pthread_t threads[MAX_WTHREADS]; // Worker threads run through 0..num_wthreads where 0 is the main thread, // thus we need to start 1..num_wthreads. Only need to keep track of // branches we start. for (int idx = 1; idx <= num_wthreads; idx++) { pthread_create(&threads[idx-1], &ss_attr, main_loop, (void*)(intptr_t)idx); // Index start at 1 and we pin wthreads to CPU 1...n // We use CPU 0 for misc threads, like IO / mon etc if (cpu_pin) { CPU_ZERO(&cpu_set); CPU_SET(idx, &cpu_set); //pthread_setaffinity_np(threads[idx-1], sizeof(cpu_set), &cpu_set); } } pthread_attr_destroy(&ss_attr); #endif uv_check_init(aux_uv_loop, &work_ev[wctx->id]); work_ev[wctx->id].data = wctx; uv_check_start(&work_ev[wctx->id], (uv_check_cb)wt_work_cb); // Run the timer queue and keep track of other periodic tasks timer_ev = GC_malloc(sizeof(uv_timer_t)); uv_timer_init(aux_uv_loop, timer_ev); uv_timer_start(timer_ev, main_timer_cb, 0, 0); #ifdef ACTON_THREADS // Set affinity for main thread if (cpu_pin) { CPU_ZERO(&cpu_set); CPU_SET(0, &cpu_set); pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set); } #endif // Run the uv loop for the main thread wt_stats[0].state = WT_Idle; int r = uv_run(aux_uv_loop, UV_RUN_DEFAULT); wt_stats[0].state = WT_NoExist; // -- SHUTDOWN -- #ifdef ACTON_THREADS // Join threads for (int idx = 1; idx <= num_wthreads; idx++) { pthread_join(threads[idx-1], NULL); } pthread_mutex_lock(&rts_exit_lock); pthread_cond_broadcast(&rts_exit_signal); pthread_mutex_unlock(&rts_exit_lock); if (mon_log_path) { pthread_join(mon_log_thread, NULL); } if (mon_on_exit) { const char *stats_json = stats_to_json(); printf("%s\n", stats_json); } #endif if (logf) { fclose(logf); } return return_val; } ================================================ FILE: base/rts/rts.h ================================================ #pragma once #include #include #include #include #include #ifdef ACTON_THREADS #include #endif #include #include #ifdef __gnu_linux__ #define IS_GNU_LINUX #elif __APPLE__ && __MACH__ #define IS_MACOS #endif #include "common.h" #include "../builtin/builtin.h" #define MSGQ 2 #ifdef ACTON_THREADS #define MAX_WTHREADS 256 #define NUM_RQS (MAX_WTHREADS+1) // The shared RQ is the top-most readyQ #define SHARED_RQ (NUM_RQS-1) #else #define MAX_WTHREADS 1 #define NUM_RQS 1 #define SHARED_RQ 0 #endif #define REQUIRED_STACK_SIZE 8*1024*1024 #include "q.h" extern long num_wthreads; struct wt_stat { unsigned int idx; // worker thread index char key[10]; // thread index as string for convenience unsigned int state; // current thread state unsigned long long sleeps; // number of times thread slept // Executing actor continuations is the primary work of the RTS, we measure // the execution time of each and count to buckets to get a rough idea of // how long it takes unsigned long long conts_count; // number of executed continuations unsigned long long conts_sum; // nanoseconds spent running continuations unsigned long long conts_100ns; // bucket for <100ns unsigned long long conts_1us; // bucket for <1us unsigned long long conts_10us; // bucket for <10us unsigned long long conts_100us; // bucket for <100us unsigned long long conts_1ms; // bucket for <1ms unsigned long long conts_10ms; // bucket for <10ms unsigned long long conts_100ms; // bucket for <100ms unsigned long long conts_1s; // bucket for <1s unsigned long long conts_10s; // bucket for <10s unsigned long long conts_100s; // bucket for <100s unsigned long long conts_inf; // bucket for <+Inf // Bookkeeping is all the other work we do not directly related to running // actor continuations, like taking locks, committing information, talking // to the database etc unsigned long long bkeep_count; // number of bookkeeping rounds unsigned long long bkeep_sum; // nanoseconds spent bookkeeping unsigned long long bkeep_100ns; // bucket for <100ns unsigned long long bkeep_1us; // bucket for <1us unsigned long long bkeep_10us; // bucket for <10us unsigned long long bkeep_100us; // bucket for <100us unsigned long long bkeep_1ms; // bucket for <1ms unsigned long long bkeep_10ms; // bucket for <10ms unsigned long long bkeep_100ms; // bucket for <100ms unsigned long long bkeep_1s; // bucket for <1s unsigned long long bkeep_10s; // bucket for <10s unsigned long long bkeep_100s; // bucket for <100s unsigned long long bkeep_inf; // bucket for <+Inf // Avoid cache trashing by aligning on cache line size (64!?) char padding[56]; }; extern struct wt_stat wt_stats[MAX_WTHREADS]; struct B_Msg; struct $ConstCont; #ifdef ACTON_THREADS extern pthread_key_t pkey_wctx; extern pthread_key_t pkey_uv_loop; extern pthread_key_t self_key; extern pthread_mutex_t sleep_lock; extern pthread_cond_t work_to_do; #define GET_WCTX() (WorkerCtx)pthread_getspecific(pkey_wctx) #else #define GET_WCTX() wctxs[0] #endif extern $Actor self_actor; typedef struct B_Msg *B_Msg; typedef struct $ConstCont *$ConstCont; extern struct B_MsgG_class B_MsgG_methods; extern struct $ActorG_class $ActorG_methods; extern struct $CatcherG_class $CatcherG_methods; extern struct $ContG_class $DoneG_methods; extern struct $ContG_class $FailG_methods; extern struct $ConstContG_class $ConstContG_methods; #define MSG_HEADER "Msg" #define ACTOR_HEADER "Actor" #define CATCHER_HEADER "Catcher" #define CLOS_HEADER "Clos" /* Defined in builtin/__builtin__.h with wrong type for __init__ struct B_MsgG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)(B_Msg, $Actor, $Cont, time_t, $WORD); void (*__serialize__)(B_Msg, $Serial$state); B_Msg (*__deserialize__)(B_Msg, $Serial$state); B_bool (*__bool__)(B_Msg); B_str (*__str__)(B_Msg); B_str (*__repr__)(B_Msg); }; */ struct B_Msg { struct B_MsgG_class *$class; B_Msg $next; $Actor $to; $Cont $cont; $Actor $waiting; time_t $baseline; $Lock $wait_lock; $WORD value; $long $globkey; }; struct $ActorG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($Actor); void (*__serialize__)($Actor, $Serial$state); $Actor (*__deserialize__)($Actor, $Serial$state); B_bool (*__bool__)($Actor); B_str (*__str__)($Actor); B_str (*__repr__)($Actor); B_NoneType (*__resume__)($Actor); B_NoneType (*__cleanup__)($Actor); }; struct $Actor { struct $ActorG_class *$class; $Actor $next; B_Msg B_Msg; B_Msg B_Msg_tail; $Lock B_Msg_lock; $int64 $affinity; B_Msg $outgoing; B_Msg $waitsfor; $int64 $consume_hd; $Catcher $catcher; $long $globkey; }; struct $CatcherG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($Catcher, $Cont); void (*__serialize__)($Catcher, $Serial$state); $Catcher (*__deserialize__)($Catcher, $Serial$state); B_bool (*__bool__)($Catcher); B_str (*__str__)($Catcher); B_str (*__repr__)($Catcher); }; struct $Catcher { struct $CatcherG_class *$class; $Catcher $next; $Cont $cont; B_BaseException xval; }; struct $ConstContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; void (*__init__)($ConstCont, $WORD, $Cont); void (*__serialize__)($ConstCont, $Serial$state); $ConstCont (*__deserialize__)($ConstCont, $Serial$state); B_bool (*__bool__)($ConstCont); B_str (*__str__)($ConstCont); B_str (*__repr__)($ConstCont); $R (*__call__)($ConstCont, $WORD); }; struct $ConstCont { struct $ConstContG_class *$class; $WORD val; $Cont cont; }; $Cont $CONSTCONT($WORD, $Cont); B_Msg $ASYNC($Actor, $Cont); B_Msg $AFTER(B_float, $Cont); $R $AWAIT($Cont, B_Msg); void init_db_queue(long); void register_actor(long key); void serialize_state_shortcut($Actor); #ifdef ACTON_DB #define INIT_DB_QUEUE(key) init_db_queue(key) #define REGISTER_ACTOR(key) register_actor(key) #else #define INIT_DB_QUEUE(key) #define REGISTER_ACTOR(key) #endif #define $NEWACTOR($T) ({ $T $t = GC_malloc(sizeof(struct $T)); \ $t->$class = &$T ## G_methods; \ $ActorG_methods.__init__(($Actor)$t); \ $t->$affinity = SHARED_RQ; \ INIT_DB_QUEUE($t->$globkey); \ REGISTER_ACTOR($t->$globkey); \ $t; }) #define $InstallFinalizer(act, fn) GC_register_finalizer(act, fn, NULL, NULL, NULL) #ifdef ACTON_THREADS #define GET_SELF() ($Actor)pthread_getspecific(self_key) #define SET_SELF(a) pthread_setspecific(self_key, (void *)a) #define GET_WTID() (int)pthread_getspecific(pkey_wtid); #else #define GET_SELF() self_actor #define SET_SELF(a) self_actor = a #define GET_WTID() 0 #endif $R $PUSH_C($Cont); B_BaseException $POP_C(); void $DROP_C(); #define $PUSHF_C $PUSH_C #define $RAISE_C $RAISE /* struct JumpBuf; typedef struct JumpBuf *JumpBuf; struct JumpBuf { jmp_buf buf; B_BaseException xval; JumpBuf prev; }; */ struct WorkerCtx; typedef struct WorkerCtx *WorkerCtx; struct WorkerCtx { long id; uv_loop_t *uv_loop; volatile JumpBuf jump_top; volatile JumpBuf jump0; }; extern WorkerCtx wctxs[MAX_WTHREADS]; JumpBuf $PUSH_BUF(); B_BaseException $POP(); void $DROP(); void $RAISE(B_BaseException e); #define $PUSH() (!setjmp($PUSH_BUF()->buf)) #define $PUSHF $PUSH extern pid_t pid; extern B_Msg timerQ; void wake_wt(int wtid); time_t current_time(); time_t next_timeout(); void handle_timeout(); void rts_shutdown(); void pin_actor_affinity(); void set_actor_affinity(int wthread_id); //typedef B_int B_Env; void $Actor$serialize($Actor, B_NoneType); void $Actor$deserialize($Actor, B_NoneType); B_NoneType $ActorD___cleanup__($Actor); B_bool B_MsgD___bool__(B_Msg self); B_str B_MsgD___str__(B_Msg self); B_str B_MsgD___repr__(B_Msg self); void B_MsgD___serialize__(B_Msg self, $Serial$state state); B_Msg B_MsgD___deserialize__(B_Msg res, $Serial$state state); $ROW $serialize_rts(); void $deserialize_rts($ROW); void $register_rts(); ================================================ FILE: base/src/__builtin__.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ## Built-in types ################################################################################## class value: __init__ : () -> None def __bool__(self) -> bool: NotImplemented def __str__(self) -> str: NotImplemented def __repr__(self) -> str: NotImplemented class object (value): pass class atom (value): pass class int (atom): def __init__(self, val: atom, base: ?int) -> None: NotImplemented class i32 (atom): def __init__(self, val: atom, base: ?int) -> None: NotImplemented class i16 (atom): def __init__(self, val: atom, base: ?int) -> None: NotImplemented class i8 (atom): def __init__(self, val: atom, base: ?int) -> None: NotImplemented class u64 (atom): def __init__(self, val: atom, base: ?int) -> None: NotImplemented class u32 (atom): def __init__(self, val: atom, base: ?int) -> None: NotImplemented class u16 (atom): def __init__(self, val: atom, base: ?int) -> None: NotImplemented class u8 (atom): def __init__(self, val: atom, base: ?int) -> None: NotImplemented class u1 (atom): def __init__(self, val: atom, base: ?int) -> None: NotImplemented class bigint (atom): def __init__(self, val: atom, base: ?int) -> None: NotImplemented class float (atom): def __init__(self, val: atom) -> None: NotImplemented class bool (atom): def __init__(self, val: value) -> None: NotImplemented class slice(value): def __init__(self, start: ?int, stop: ?int, step: ?int) -> None: NotImplemented class list[A] (object): def __init__(self, val: ?Iterable[A]) -> None: NotImplemented def clear(self) -> None: NotImplemented def copy(self) -> list[A]: NotImplemented def extend(self, other: list[A]) -> None: NotImplemented def pop(self, n :?int) -> A: NotImplemented # TODO: improve this, to like A(Eq) or something # generic type B should really just be A(Eq), but I don't think we can say # that A is a generic type without constraints in one place and then adds # constraints in another, so using B is a bit of a workaround. def index[B(Eq)](self, val: B, start: int=0, stop: ?int) -> int: """Return the index of the first occurrence of val in the list The optional arguments start and stop are interpreted as in slice notation and will limit the search to the slice of the list from start to stop. Raises KeyError if val is not in the searched list / slice. """ NotImplemented def count[B(Eq)](self, val: B) -> int: NotImplemented class Iterator[A] (object): __next__ : () -> A protocol Iterable[A]: __iter__ : () -> Iterator[A] class range(Iterator[int]): """Return an object that produces a sequence of integers from start (inclusive) to stop (exclusive) in step sizes as specified by the step argument, which is 1 per default. It is possible to call with just a single argument like `range(j)` where `j` is then interpreted to be the stop argument with an implicit default start of 0. - `range(0, 3, 1)` produces [0, 1, 2] - `range(0, 3)` produces [0, 1, 2] - `range(3)` produces [0, 1, 2] """ def __init__(self, start: int, stop: ?int, step: int=1) -> None: NotImplemented def __next__(self)->int: NotImplemented class str (atom): def __init__ (self, val: ?value) -> None: NotImplemented def capitalize (self) -> str: NotImplemented def center (self, width: int, fillchar: ?str) -> str: NotImplemented def count (self, sub: str, start: ?int, end: ?int) -> int: NotImplemented def encode (self) -> bytes: NotImplemented def endswith (self, suffix: str, start: ?int, end: ?int) -> bool: NotImplemented def expandtabs (self, tabsize: ?int) -> str: NotImplemented def find (self, sub: str, start: ?int, end: ?int) -> int: NotImplemented def index (self, sub: str, start: ?int, end: ?int) -> int: NotImplemented def isalnum (self) -> bool: NotImplemented def isalpha (self) -> bool: NotImplemented def isascii (self) -> bool: NotImplemented def isdecimal (self) -> bool: NotImplemented def islower (self) -> bool: NotImplemented def isprintable (self) -> bool: NotImplemented def isspace (self) -> bool: NotImplemented def istitle (self) -> bool: NotImplemented def isupper (self) -> bool: NotImplemented def join (self, iterable: Iterable[str]) -> str: NotImplemented def ljust (self, width: int, fillchar: ?str) -> str: NotImplemented def lower (self) -> str: NotImplemented def lstrip (self, chars: ?str) -> str: NotImplemented def partition (self, sep: str) -> (str,str,str): NotImplemented def replace (self, old: str, new: str, count: ?int) -> str: NotImplemented def rfind (self, sub: str, start: ?int, end: ?int) -> int: NotImplemented def rindex (self, sub: str, start: ?int, end: ?int) -> int: NotImplemented def rjust (self, width: int, fillchar: ?str) -> str: NotImplemented def rpartition (self, sep: str) -> (str,str,str): NotImplemented def rstrip (self, chars: ?str) -> str: NotImplemented def split (self, sep: str, maxsplit: ?int) -> list[str]: NotImplemented def splitlines (self, keepends: ?bool) -> list[str]: NotImplemented def startswith (self, prefix: str, start: ?int, end: ?int) -> bool: NotImplemented def strip (self, chars: ?str) -> str: NotImplemented def upper (self) -> str: NotImplemented def zfill (self, width: int) -> str: NotImplemented class bytes (value): def __init__ (self, iterable: Iterable[int]) -> None: NotImplemented def capitalize (self) -> bytes: NotImplemented def center (self, width: int, fillchar: ?bytes) -> bytes: NotImplemented def count (self, sub: bytes, start: ?int, end: ?int) -> int: NotImplemented def decode (self) -> str: NotImplemented def endswith (self, suffix: bytes, start: ?int, end: ?int) -> bool: NotImplemented def expandtabs (self, tabsize: ?int) -> bytes: NotImplemented def find (self, sub: bytes, start: ?int, end: ?int) -> int: NotImplemented @staticmethod def from_hex (s: str) -> bytes: NotImplemented def hex (self) -> str: NotImplemented def index (self, sub: bytes, start: ?int, end: ?int) -> int: NotImplemented def isalnum (self) -> bool: NotImplemented def isalpha (self) -> bool: NotImplemented def isascii (self) -> bool: NotImplemented def isdigit (self) -> bool: NotImplemented def islower (self) -> bool: NotImplemented def isspace (self) -> bool: NotImplemented def istitle (self) -> bool: NotImplemented def isupper (self) -> bool: NotImplemented def join (self, iterable: Iterable[bytes]) -> bytes: NotImplemented def ljust (self, width: int, fillchar: ?bytes) -> bytes: NotImplemented def lower (self) -> bytes: NotImplemented def lstrip (self, chars: ?bytes) -> bytes: NotImplemented def partition (self, sep: bytes) -> (bytes,bytes,bytes): NotImplemented def replace (self, old: bytes, new: bytes, count: ?int) -> bytes: NotImplemented def rfind (self, sub: bytes, start: ?int, end: ?int) -> int: NotImplemented def rindex (self, sub: bytes, start: ?int, end: ?int) -> int: NotImplemented def rjust (self, width: int, fillchar: ?bytes) -> bytes: NotImplemented def rpartition (self, sep: bytes) -> (bytes,bytes,bytes): NotImplemented def rstrip (self, chars: ?bytes) -> bytes: NotImplemented def split (self, sep: bytes, maxsplit: ?int) -> list[bytes]: NotImplemented def splitlines (self, keepends: ?bool) -> list[bytes]: NotImplemented def startswith (self, prefix: bytes, start: ?int, end: ?int) -> bool: NotImplemented def strip (self, chars: ?bytes) -> bytes: NotImplemented def upper (self) -> bytes: NotImplemented def zfill (self, width: int) -> bytes: NotImplemented class bytearray (object): def __init__ (self, val: bytes) -> None: NotImplemented def capitalize (self) -> bytearray: NotImplemented def center (self, width: int, fillchar: ?bytearray) -> bytearray: NotImplemented def count (self, sub: bytearray, start: ?int, end: ?int) -> int: NotImplemented def decode (self) -> str: NotImplemented def endswith (self, suffix: bytearray, start: ?int, end: ?int) -> bool: NotImplemented def expandtabs (self, tabsize: ?int) -> bytearray: NotImplemented def find (self, sub: bytearray, start: ?int, end: ?int) -> int: NotImplemented @staticmethod def from_hex (s: str) -> bytearray: NotImplemented def hex (self) -> str: NotImplemented def index (self, sub: bytearray, start: ?int, end: ?int) -> int: NotImplemented def isalnum (self) -> bool: NotImplemented def isalpha (self) -> bool: NotImplemented def isascii (self) -> bool: NotImplemented def isdigit (self) -> bool: NotImplemented def islower (self) -> bool: NotImplemented def isspace (self) -> bool: NotImplemented def istitle (self) -> bool: NotImplemented def isupper (self) -> bool: NotImplemented def join (self, iterable: Iterable[bytearray]) -> bytearray: NotImplemented def ljust (self, width: int, fillchar: ?bytearray) -> bytearray: NotImplemented def lower (self) -> bytearray: NotImplemented def lstrip (self, chars: ?bytearray) -> bytearray: NotImplemented def partition (self, sep: bytearray) -> (bytearray,bytearray,bytearray): NotImplemented def replace (self, old: bytearray, new: bytearray, count: ?int) -> bytearray: NotImplemented def rfind (self, sub: bytearray, start: ?int, end: ?int) -> int: NotImplemented def rindex (self, sub: bytearray, start: ?int, end: ?int) -> int: NotImplemented def rjust (self, width: int, fillchar: ?bytearray) -> bytearray: NotImplemented def rpartition (self, sep: bytearray) -> (bytearray,bytearray,bytearray): NotImplemented def rstrip (self, chars: ?bytearray) -> bytearray: NotImplemented def split (self, sep: bytearray, maxsplit: ?int) -> list[bytearray]: NotImplemented def splitlines (self, keepends: ?bool) -> list[bytearray]: NotImplemented def startswith (self, prefix: bytearray, start: ?int, end: ?int) -> bool: NotImplemented def strip (self, chars: ?bytearray) -> bytearray: NotImplemented def upper (self) -> bytearray: NotImplemented def zfill (self, width: int) -> bytearray: NotImplemented class Msg[A] (value): NotImplemented ## Exceptions ################################################################################## # All exceptions should have a human readable error in the error_message field. # It is generally set by the constructor for each exception class that inherits # from BaseException to something appropriate for that particular exception. It # is also a common convention to accept a message as an argument to the # constructor, which can be used to override the default message. class BaseException (value): error_message: str def __init__(self, msg: ?str) -> None: self.error_message = msg if msg is not None else "" def __str__(self): return f"{self._name()}: {self.error_message}" def __repr__(self): return "{self._name()}({self.error_message.__repr__()})" def _name(self) -> str: NotImplemented class SystemExit (BaseException): pass class KeyboardInterrupt (BaseException): pass class Exception (BaseException): pass class StopIteration (Exception): pass class AssertionError (Exception): pass class LookupError (Exception): pass class IndexError (LookupError): def __init__(self, index: int, msg: ?str=None): self.index = index self.error_message = msg if msg is not None else "List index out of range" def __str__(self): return f"{self._name()}: {self.error_message}, index: {self.index}" def __repr__(self): return "{self._name()}({self.index}, {self.error_message.__repr__()})" class KeyError(LookupError): def __init__(self, key: value, msg: ?str=None): self.key = key self.error_message = msg if msg is not None else "Key not found" def __str__(self): return f"{self._name()}: {self.error_message}, key: {str(self.key)}" def __repr__(self): return '{self._name()}({self.key.__repr__()}, {self.error_message.__repr__()})' class MemoryError (Exception): pass class OSError (Exception): pass class FileNotFoundError (OSError): def __init__(self, filename: str): self.error_message = "" self.filename = filename def __str__(self): return f"{self._name()}: No such file or directory: '{self.filename}'" def __repr__(self): return '{self._name()}({self.filename.__repr__()})' class RuntimeError (Exception): pass class NotImplementedError (RuntimeError): pass class ValueError (Exception): pass class ArithmeticError (Exception): pass class ZeroDivisionError (ArithmeticError): pass ## General protocols ############################################################################### protocol Identity: @staticmethod __is__ : (Self,Self) -> bool @staticmethod __isnot__ : (Self,Self) -> bool protocol Eq: @staticmethod __eq__ : (Self,Self) -> bool @staticmethod __ne__ : (Self,Self) -> bool def __ne__(a,b): return not (a == b) protocol Ord (Eq): @staticmethod __lt__ : (Self,Self) -> bool @staticmethod __le__ : (Self,Self) -> bool @staticmethod __gt__ : (Self,Self) -> bool @staticmethod __ge__ : (Self,Self) -> bool def __le__(a,b): return a < b or a == b def __gt__(a,b): return b < a def __ge__(a,b): return b <= a protocol Logical: @staticmethod __and__ : (Self,Self) -> Self @staticmethod __or__ : (Self,Self) -> Self @staticmethod __xor__ : (Self,Self) -> Self @staticmethod __iand__ : (Self,Self) -> Self @staticmethod __ior__ : (Self,Self) -> Self @staticmethod __ixor__ : (Self,Self) -> Self def __iand__(a,b): return a & b def __ior__(a,b): return a | b def __ixor__(a,b): return a ^ b protocol Plus: @staticmethod __add__ : (Self,Self) -> Self @staticmethod __iadd__ : (Self,Self) -> Self @staticmethod __zero__ : () -> Self def __iadd__(a,b): return a + b protocol Minus: @staticmethod __sub__ : (Self,Self) -> Self @staticmethod __isub__ : (Self,Self) -> Self def __isub__(a,b): return a - b protocol Times[A] (Plus): @staticmethod __mul__ : (Self,A) -> Self @staticmethod __imul__ : (Self,A) -> Self def __imul__(a,b): return a * b protocol Div[A]: @staticmethod __truediv__ : (Self,Self) -> A @staticmethod __itruediv__ : (Self,Self) -> A def __itruediv__(a,b): return a / b class hasher(object): def __init__(self, seed : u64 = 0) -> None: NotImplemented def update(self, b : bytes) -> None: NotImplemented def finalize(self) -> u64: NotImplemented protocol Hashable (Eq): hash : (hasher) -> None class complex (value): def __init__(self, val: Number) -> None: NotImplemented @staticmethod def from_real_imag(real: Real, imag: Real) -> complex: NotImplemented class dict[A(Hashable),B] (object): def __init__(self, iterable: ?Iterable[(A,B)]) -> None: NotImplemented # Code generation for calls to copy and clear becomes wrong, so we omit them for now # def clear(self) -> None: # NotImplemented # def copy(self) -> dict[A,B]: # NotImplemented class set[A(Hashable)] (object): def __init__(self, iterable: ?Iterable[A]) -> None: NotImplemented ## Number protocols ################################################################################ # Plus # | # | # Times Minus # | | # | | # Number <---------- # | # | # Real # | # | # Rational Logical # | | # | | # Integral <-------- protocol Number (Times[Self],Minus): @staticmethod __fromatom__ : (atom) -> Self __complex__ : () -> complex @staticmethod __pow__ : (Self,Self) -> Self @staticmethod __ipow__ : (Self,Self) -> Self def __ipow__(a,b): return a ** b __neg__ : () -> Self __pos__ : () -> Self real : () -> Real imag : () -> Real __abs__ : () -> Real # What about arg? conjugate : () -> Self protocol Real (Number): __float__ : () -> float __trunc__ : () -> Integral __floor__ : () -> Integral __ceil__ : () -> Integral __round__ : (?int) -> Self protocol RealFloat (Real): pass protocol Rational (Real): numerator : () -> Integral denominator : () -> Integral protocol Integral (Rational,Logical): __int__ : () -> int __index__ : () -> int @staticmethod __divmod__ : (Self,Self) -> (Self,Self) @staticmethod __floordiv__ : (Self,Self) -> Self @staticmethod __mod__ : (Self,Self) -> Self @staticmethod __ifloordiv__ : (Self,Self) -> Self @staticmethod __imod__ : (Self,Self) -> Self @staticmethod __lshift__ : (Self,int) -> Self @staticmethod __rshift__ : (Self,int) -> Self @staticmethod __ilshift__ : (Self,int) -> Self @staticmethod __irshift__ : (Self,int) -> Self def __ifloordiv__(a,b): return a // b def __imod__(a,b): return a % b def __ilshift__(a,b): return a << b def __irshift__(a,b): return a >> b __invert__ : () -> Self ## Number protocol extensions ###################################################################### #extension bool (Eq): pass extension bool (Hashable): NotImplemented extension int (Integral): NotImplemented extension int (Div[float]): NotImplemented extension int (Ord): NotImplemented extension int (Hashable): NotImplemented extension i32 (Integral): NotImplemented extension i32 (Div[float]): NotImplemented extension i32 (Ord): NotImplemented extension i32 (Hashable): NotImplemented extension i16 (Integral): NotImplemented extension i16 (Div[float]): NotImplemented extension i16 (Ord): NotImplemented extension i16 (Hashable): NotImplemented extension i8 (Integral): NotImplemented extension i8 (Div[float]): NotImplemented extension i8 (Ord): NotImplemented extension i8 (Hashable): NotImplemented extension u64 (Integral): NotImplemented extension u64 (Div[float]): NotImplemented extension u64 (Ord): NotImplemented extension u64 (Hashable): NotImplemented extension u32 (Integral): NotImplemented extension u32 (Div[float]): NotImplemented extension u32 (Ord): NotImplemented extension u32 (Hashable): NotImplemented extension u16 (Integral): NotImplemented extension u16 (Div[float]): NotImplemented extension u16 (Ord): NotImplemented extension u16 (Hashable): NotImplemented extension u8 (Integral): NotImplemented extension u8 (Div[float]): NotImplemented extension u8 (Ord): NotImplemented extension u8 (Hashable): NotImplemented extension u1 (Integral): NotImplemented extension u1 (Div[float]): NotImplemented extension u1 (Ord): NotImplemented extension u1 (Hashable): NotImplemented extension bigint (Integral): NotImplemented extension bigint (Div[float]): NotImplemented extension bigint (Ord): NotImplemented extension bigint (Hashable): NotImplemented extension float (RealFloat): NotImplemented extension float (Div[float]): NotImplemented extension float (Ord): NotImplemented extension float (Hashable): NotImplemented extension complex (Number): NotImplemented extension complex (Div[complex]): NotImplemented extension complex (Eq): NotImplemented extension complex (Hashable): NotImplemented ## Collection protocols ############################################################################ protocol Indexed[A (Eq),B]: __getitem__ : (A) -> B __setitem__ : mut(A,B) -> None __delitem__ : mut(A) -> None protocol Sliceable[A] (Indexed[int,A]): __getslice__ : (slice) -> Self __setslice__ : mut(slice,Iterable[A]) -> None __delslice__ : mut(slice) -> None protocol Collection[A] (Iterable[A]): @staticmethod __fromiter__ : (Iterable[A]) -> Self __len__ : () -> int protocol Container[A(Eq)] (Collection[A]): __contains__ : (A) -> bool __containsnot__ : (A) -> bool # Indexed Iterable Plus # | | | # | | | # Sliceable Collection Times # | | | # | | | # Sequence <-------- <-------------- protocol Sequence[A] (Sliceable[A], Collection[A], Times[int]): __reversed__ : () -> Iterator[A] insert : mut(int,A) -> None append : mut(A) -> None reverse : mut() -> None # Iterable # | # | # Collection # | # | # Container Indexed # | | # | | # Mapping <--------- protocol Mapping[A(Eq),B] (Container[A], Indexed[A,B]): get : (A) -> ?B get_def : (A,B) -> B pop : mut(A) -> ?B pop_def : mut(A,B) -> B keys : () -> Iterator[A] values : () -> Iterator[B] items : () -> Iterator[(A,B)] update : mut(Iterable[(A,B)]) -> None popitem : () -> (A,B) setdefault : mut(A,B) -> ?B # Iterable # | # | # Collection Eq # | | # | | # Container Ord Logical Minus # | | | | # | | | | # Set <------------- <-------------- <-------------- protocol Set[A (Eq)] (Container[A], Ord, Logical, Minus): @staticmethod isdisjoint : (Self,Self) -> bool add : mut(A) -> None discard : mut(A) -> None pop : mut() -> A update : mut(Iterable[A]) -> None ## Collection protocol extensions ######################################## extension list[A] (Sequence[A]): NotImplemented extension list[A(Eq)] (Container[A]): NotImplemented extension list[A(Ord)] (Ord): NotImplemented extension dict[A(Hashable),B] (Mapping[A,B]): NotImplemented extension dict[A(Hashable),B(Eq)] (Ord): NotImplemented extension set[A(Hashable)] (Set[A]): NotImplemented extension Iterator[A](Iterable[A]): NotImplemented # extension range[A](Iterable[A]): # NotImplemented extension str (Ord): NotImplemented extension str (Container[str]): NotImplemented extension str (Sliceable[str]): NotImplemented extension str (Times[int]): NotImplemented extension str (Hashable): NotImplemented extension bytearray (Ord): NotImplemented extension bytearray (Sequence[int]): NotImplemented extension bytearray (Container[int]): NotImplemented extension bytes (Ord): NotImplemented extension bytes (Sliceable[int]): NotImplemented extension bytes (Container[int]): NotImplemented extension bytes (Times[int]): NotImplemented extension bytes (Hashable): NotImplemented ## Builtin functions ##################################################### def abs(x : Number) -> Real: return x.__abs__() def all[A(value)](it: Iterable[A]) -> bool: for x in it: if bool(x) == False: return False return True def any[A(value)](it: Iterable[A]) -> bool: for x in it: if bool(x) == True: return True return False def ascii(x : value) -> str: NotImplemented def bin(x: Integral) -> str: NotImplemented def chr(i: Integral) -> str: NotImplemented def divmod [A(Integral)] (a : A, b : A) -> (A, A): return Integral.__divmod__(a,b) def enumerate(iterable: Iterable[A], start: ?int) -> Iterator[(int,A)]: NotImplemented def filter (function: ?((A) -> B), iterable: Iterable[A]) -> Iterator[A]: NotImplemented def hash(x: Hashable) -> u64: h = hasher() x.hash(h) return h.finalize() def seed_hash(seed: u64, x: Hashable) -> u64: h = hasher(seed) x.hash(h) return h.finalize() def hex(i: Integral) -> str: NotImplemented def iter(x : Iterable[A]) -> Iterator[A]: return x.__iter__() def len(x : Collection[A]) -> int: return x.__len__() def map(function: (A) -> B, iterable: Iterable[A]) -> Iterator[B]: NotImplemented def max [A(Ord)] (iter: Iterable[A], dflt: ?A) -> A: NotImplemented def min [A(Ord)] (iter: Iterable[A], dflt: ?A) -> A: NotImplemented def max_def [A(Ord)] (iter: Iterable[A], dflt: A) -> A: NotImplemented def min_def [A(Ord)] (iter: Iterable[A], dflt: A) -> A: NotImplemented def next(x : Iterator[A]) -> A: return x.__next__() def ord(c: str) -> int: NotImplemented def pow [A(Number)] (a : A, b : A) -> A: return Number.__pow__(a,b) def print(*args, sep: str=" ", end: str="\n", err: bool=False, flush: bool=False) -> None: """Prints values Values are printed per default to stdout, but can be printed to stderr by setting err=True. Multiple values are separated by the sep argument, a space per default. Each invocation will per default add a new line character at the end, which can be overridden through the end argument. Output can be flushed by setting flush=True. It is not possible to write to arbitrary file descriptors. Use the file IO functionality to write to files. """ NotImplemented def repr(x: ?value): if x is not None: return x.__repr__() return "None" def reversed[A](seq : Sequence[A]) -> Iterator[A]: return seq.__reversed__() def round [A(Real)] (x : A, n : ?int) -> A: return x.__round__(n) def sorted [A(Ord)] (iter: Iterable[A]) -> list[A]: NotImplemented def sum [A(Plus)] (iter: Iterable[A], start: ?A) -> A: NotImplemented def zip (a: Iterable[A], b: Iterable[B]) -> Iterator[(A,B)]: NotImplemented def gcd(a : bigint, b :bigint) -> bigint: NotImplemented def xgcd(a : bigint, b : bigint) -> (bigint, bigint, bigint): NotImplemented def type(a: ?value) -> str: """Get the name of the type of something as a string Do not use this for meta-programming. Use isinstance(). This is only meant for development use as an alternative to letting acton print inferred types and similar. It will be removed in a future version when there are better ways to debug types. """ NotImplemented def actorid() -> str: NotImplemented actor StringDecoder(cb_out: action(str) -> None, encoding: ?str="utf-8", on_error: ?action(str, bytes) -> None): """Bytes to string decoder Decodes bytes to string using the provided encoding. If no encoding is given UTF-8 is used. The decoder is stateful in order to buffer incomplete multi- byte characters. """ MAX_UNICODE_CHAR_SIZE: int = 4 var buf: bytes = b"" if encoding is not None: if encoding.lower() != "utf-8": raise ValueError("Only utf-8 encoding is supported") def decode(input: bytes) -> None: buf += input # Attempt to decode all of buf. If it fails we are likely in the middle # of a multi-byte character so we try again by removing the last bytes # iteratively until we succeed. UTF-8 has up to 4 bytes per character. for i in range(len(buf), len(buf)-MAX_UNICODE_CHAR_SIZE, -1): try: s = buf[:i].decode() buf = buf[i:] cb_out(s) return except ValueError: pass if on_error is not None: on_error("Invalid UTF-8", buf) else: raise ValueError(f"Invalid UTF-8: {str(buf)}") ## Environment ################################################ class WorldCap(): """WorldCap has the capability to access the entire world outside of Acton. It is the root of the capability hierarchy. In an actor world, access to actors (like being able to call their methods) requires a reference to the relevant actor. Anyone with a reference can access the actor in question. It is not possible to forge a reference. In Acton, things outside the actor world are represented as actors with the associated capabilities. For example, with a reference to the TCPConnectCap actor, we have the capability of using a POSIX socket to connect to a remote host over the network. TCPConnectCap is part of a capability hierarchy, starting with the generic WorldCap and becoming further and further refined: WorldCap > NetCap > TCPCap > TCPConnectCap There are other more refined Caps that each have a a subset of the capabilities of the world. Capability based privilege restriction prevent some deeply nested part of a program, perhaps in a dependency to a dependency, to perform operations unknown to the application author. Access to capabilities must be explicitly handed out and a program can only perform operations based on the capabilities it has access to. """ pass class SysCap(): """SysCap has the capability to access the internals of the Acton RTS system """ pass actor Env (wc: WorldCap, sc: SysCap, args: list[str]): cap = wc auth = wc syscap = sc argv = args nr_wthreads: int = 0 action def getenv(name: str) -> ?str: """Get the value of an environment variable""" res = getenvb(name.encode()) if res is not None: return res.decode() return None action def getenvb(name: bytes) -> ?bytes: """Get the value of an environment variable""" NotImplemented action def setenv(n: str, v: str) -> None: """Set the value of an environment variable""" setenvb(n.encode(), v.encode()) action def setenvb(n: bytes, v: bytes) -> None: """Set the value of an environment variable""" NotImplemented action def unsetenv(n: str) -> None: """Unset an environment variable""" unsetenvb(n.encode()) action def unsetenvb(n: bytes) -> None: """Unset an environment variable""" NotImplemented action def stdout_write(s: str) -> None: NotImplemented action def stdin_install(on_stdin: ?action(str) -> None, encoding: ?str=None, on_error: ?action(str, bytes) -> None, on_stdin_bytes: ?action(bytes) -> None) -> None: if on_stdin is None and on_stdin_bytes is None: raise ValueError("At least one of on_stdin or on_stdin_bytes must be set") elif on_stdin_bytes is not None: if encoding is not None: raise ValueError("encoding must not be set when on_stdin_bytes is set, it is only used for decoding stdin bytes to string") if on_error is not None: raise ValueError("on_error must not be set when on_stdin_bytes is set, it is only used for decoding error when decoding stdin bytes to string") _on_stdin_bytes(on_stdin_bytes) elif on_stdin is not None: if encoding is None: # If no encoding is given, attempt to discover the encoding used # Default to utf-8 if we're unable to discover the encoding encoding = "utf-8" # Read encoding from the LANG environment variable lang_env = getenv("LANG") if lang_env is not None: try: encoding = lang_env.split(".")[1].lower() except: pass # If stdin is attached to a terminal, attempt to discover the # encoding used by the terminal by inspecting the LANG environment # variable. sd = StringDecoder(on_stdin, encoding, on_error) _on_stdin_bytes(sd.decode) action def set_stdin(canonical: ?bool, echo: ?bool) -> None: NotImplemented action def is_tty() -> bool: NotImplemented action def _on_stdin_bytes(cb: action(bytes) -> None) -> None: NotImplemented action def exit(n: int): NotImplemented ================================================ FILE: base/src/__builtin__.ext.c ================================================ #include "rts/rts.c" void B___ext_init__() { B_HashableD_bigintG_methods.__eq__ = (B_bool (*)(B_HashableD_bigint, B_bigint, B_bigint))B_OrdD_bigintD___eq__; B_HashableD_intG_methods.__eq__ = (B_bool (*)(B_HashableD_int, B_int, B_int))B_OrdD_intD___eq__; B_HashableD_i32G_methods.__eq__ = (B_bool (*)(B_HashableD_i32, B_i32, B_i32))B_OrdD_i32D___eq__; B_HashableD_i16G_methods.__eq__ = (B_bool (*)(B_HashableD_i16, B_i16, B_i16))B_OrdD_i16D___eq__; B_HashableD_u64G_methods.__eq__ = (B_bool (*)(B_HashableD_u64, B_u64, B_u64))B_OrdD_u64D___eq__; B_HashableD_u32G_methods.__eq__ = (B_bool (*)(B_HashableD_u32, B_u32, B_u32))B_OrdD_u32D___eq__; B_HashableD_u16G_methods.__eq__ = (B_bool (*)(B_HashableD_u16, B_u16, B_u16))B_OrdD_u16D___eq__; B_HashableD_floatG_methods.__eq__ = (B_bool (*)(B_HashableD_float, B_float, B_float))B_OrdD_floatD___eq__; B_HashableD_strG_methods.__eq__ = (B_bool (*)(B_HashableD_str, B_str, B_str))B_OrdD_strD___eq__; B_HashableD_bytesG_methods.__eq__ = (B_bool (*)(B_HashableD_bytes, B_bytes, B_bytes))B_OrdD_bytesD___eq__; B_HashableD_complexG_methods.__eq__ = (B_bool (*)(B_HashableD_complex, B_complex, B_complex))B_HashableD_complexD___eq__; B_ContainerD_listG_methods.__len__ = (B_int (*)(B_ContainerD_list, B_list))B_CollectionD_SequenceD_listD___len__; B_ContainerD_listG_methods.__fromiter__ = (B_list (*)(B_ContainerD_list, B_Iterable, $WORD))B_CollectionD_SequenceD_listD___fromiter__; B_ContainerD_listG_methods.__iter__ = (B_Iterator (*)(B_ContainerD_list, B_list))B_CollectionD_SequenceD_listD___iter__; } B_str B_BaseExceptionD__name (B_BaseException self) { return to$str(unmangle_name(self->$class->$GCINFO)); } B_str B_type(B_value a) { if (a) return to$str(unmangle_name(a->$class->$GCINFO)); return to$str("None"); } $R B_EnvD_getenvbG_local (B_Env self, $Cont C_cont, B_bytes name) { // uv_os_getenv is not threadsafe but our Env actor forces serial execution // Try to use a small fixed size buffer size_t len = 256; char smallval[256]; char *value = smallval; const char* env_var = (char*)fromB_bytes(name); // First, query the required buffer size by passing NULL as the buffer int r = uv_os_getenv(env_var, value, &len); if (r == UV_ENOENT) { // The environment variable does not exist return $R_CONT(C_cont, B_None); } else if (r == UV_ENOBUFS) { // Allocate the buffer and actually get the environment variable value value = (char*)acton_malloc(len); r = uv_os_getenv(env_var, value, &len); } if (r < 0) { $RAISE((B_BaseException)B_RuntimeErrorG_new($FORMAT("Failed to read the environment variable %s: %s", env_var, uv_strerror(r)))); } return $R_CONT(C_cont, to$bytes(value)); } $R B_EnvD_setenvbG_local (B_Env self, $Cont C_cont, B_bytes name, B_bytes value) { const char* env_var = fromB_bytes(name); const char* env_val = fromB_bytes(value); int r = uv_os_setenv(env_var, env_val); if (r < 0) { $RAISE((B_BaseException)B_RuntimeErrorG_new($FORMAT("Failed to set the environment variable %s: %s", env_var, uv_strerror(r)))); } return $R_CONT(C_cont, B_None); } $R B_EnvD_unsetenvbG_local (B_Env self, $Cont C_cont, B_bytes name) { const char* env_var = fromB_bytes(name); int r = uv_os_unsetenv(env_var); if (r < 0) { $RAISE((B_BaseException)B_RuntimeErrorG_new($FORMAT("Failed to unset the environment variable %s: %s", env_var, uv_strerror(r)))); } return $R_CONT(C_cont, B_None); } // action def is_tty() -> bool: $R B_EnvD_is_ttyG_local (B_Env self, $Cont C_cont) { return $R_CONT(C_cont, toB_bool(isatty(1))); } B_str B_actorid() { $Actor a = GET_SELF(); return $FORMAT("%ld", a->$globkey); } ================================================ FILE: base/src/acton/rts.act ================================================ def gc(cap: SysCap) -> None: """Collect garbage Jedi level. This is not the function you are looking for. """ NotImplemented def enable_gc(cap: SysCap) -> None: """Enable the garbage collector Jedi level. This is not the function you are looking for. """ NotImplemented def disable_gc(cap: SysCap) -> None: """Disable the garbage collector Jedi level. This is not the function you are looking for. """ NotImplemented def start_gc_performance_measurement(cap: SysCap) -> None: """Start performance measurement of the garbage collector Jedi level. This is not the function you are looking for. """ NotImplemented def get_gc_time(cap: SysCap) -> (total: u64, mark: u64, sweep: u64): """Get GC time in milliseconds""" NotImplemented def get_mem_usage(cap: SysCap) -> u64: """Get memory usage in number of bytes Gets the approximate current memory usage by this program. This is not the same as the heap size (which is the amount of memory allocated to us from the OS). Computed by taking the heap size and subtracting unmapped bytes and free bytes as the GC thinks of it. It's approximate because the GC gives us an approximate value, usually on the order of ~10KB. Thus, it is hard to precisely measure small usage of memory whereas for applications consuming hundreds of KB or megabytes of memory, the precision is quite enough. """ NotImplemented def get_gc_total_bytes(cap: SysCap) -> u64: """Get total number of bytes allocated on the GC heap """ NotImplemented def get_gc_bytes_since_gc(cap: SysCap) -> u64: """Get number of bytes allocated on the GC heap since last GC """ NotImplemented def get_rss(cap: SysCap) -> u64: """Get Resident Set Size in number of bytes The Resident Set Size (RSS) is the amount of memory occupied by the process in RAM. It includes the heap, the stack, and the code segment. It does not include memory that is swapped out to disk. It is the amount of memory that the process is actually using in RAM. """ NotImplemented # sleep is sort of dangerous - it will actually put the RTS thread executing the # actor calling this function to sleep. This could be seen as ultrabad, like we # would want to just pause execution of one actor and let the RTS thread process # other actors meanwhile. There would be room for such a function, however, the # acton.rts.sleep() is deliberately putting the RTS thread to sleep. This is a # simple way of simulating heavy work without actually doing the heavy work, so # in a benchmark we can pretend some actors are doing relatively heavy work, yet # our CPU usage will be lower, so this is like laptop airplane mode friendly # (consumes less battery). def sleep(cap: SysCap, duration: float) -> None: """Put RTS worker thread to sleep""" NotImplemented def rss(cap: SysCap) -> int: """Get Resident Set Size""" NotImplemented def _io_handles(cap: SysCap) -> dict[u64, (typ: str, act: u64)]: """Return all I/O handles and their type for the current worker thread""" NotImplemented def rts_stats(cap: SysCap) -> dict[u64, (state: str, sleeps: u64, conts_count: u64, conts_sum: u64, conts_100ns: u64, conts_1us: u64, conts_10us: u64, conts_100us: u64, conts_1ms: u64, conts_10ms: u64, conts_100ms: u64, conts_1s: u64, conts_10s: u64, conts_100s: u64, conts_inf: u64, bkeep_count: u64, bkeep_sum: u64, bkeep_100ns: u64, bkeep_1us: u64, bkeep_10us: u64, bkeep_100us: u64, bkeep_1ms: u64, bkeep_10ms: u64, bkeep_100ms: u64, bkeep_1s: u64, bkeep_10s: u64, bkeep_100s: u64, bkeep_inf: u64)]: """Return all I/O handles and their type for the current worker thread""" NotImplemented actor WThreadMonitor(env: Env, arg_wthread_id: int): wthread_id = arg_wthread_id def io_handles(): return _io_handles(env.syscap) proc def _init(): """Implementation internal""" NotImplemented _init() actor Monitor(env: Env): tms: dict[int, WThreadMonitor] = {} for wthread_id in range(1, env.nr_wthreads+1): tm = WThreadMonitor(env, wthread_id) tms[wthread_id] = tm def io_handles(): res = {} for wthread_id, tm in tms.items(): res[wthread_id] = tm.io_handles() return res ================================================ FILE: base/src/acton/rts.ext.c ================================================ #define GC_THREADS 1 #include #include #include #include "rts/io.h" #include "rts/log.h" void actonQ_rtsQ___ext_init__() { // NOP } B_NoneType actonQ_rtsQ_gc (B_SysCap cap) { GC_gcollect_and_unmap(); return B_None; } B_NoneType actonQ_rtsQ_enable_gc (B_SysCap cap) { GC_enable(); return B_None; } B_NoneType actonQ_rtsQ_disable_gc (B_SysCap cap) { GC_disable(); return B_None; } // def start_gc_performance_measurement(cap: SysCap) -> None: B_NoneType actonQ_rtsQ_start_gc_performance_measurement (B_SysCap cap) { GC_start_performance_measurement(); return B_None; } // def get_gc_time(cap: SysCap) -> (total: u64, mark: u64, sweep: u64): B_tuple actonQ_rtsQ_get_gc_time (B_SysCap cap) { unsigned long total = GC_get_full_gc_total_time(); unsigned long mark = GC_get_stopped_mark_total_time(); unsigned long sweep = total - mark; B_tuple res = $NEWTUPLE(3, toB_u64(total), toB_u64(mark), toB_u64(sweep) ); return res; } B_u64 actonQ_rtsQ_get_heap_size (B_SysCap cap) { return toB_u64(GC_get_heap_size()); } uint64_t actonQ_rtsQ_U_get_mem_usage (B_SysCap cap) { return GC_get_heap_size() - GC_get_free_bytes(); } // def get_gc_total_bytes(cap: SysCap) -> u64: uint64_t actonQ_rtsQ_U_1get_gc_total_bytes (B_SysCap cap) { return GC_get_total_bytes(); } //def get_gc_bytes_since_gc(cap: SysCap) -> u64: uint64_t actonQ_rtsQ_U_2get_gc_bytes_since_gc (B_SysCap cap) { return GC_get_bytes_since_gc(); } // def get_rss(cap: SysCap) -> u64: uint64_t actonQ_rtsQ_U_3get_rss (B_SysCap cap) { uint64_t rsm; int r = uv_resident_set_memory(&rsm); return rsm; } int64_t actonQ_rtsQ_U_6rss (B_SysCap cap) { int64_t rsm; int r = uv_resident_set_memory(&rsm); return rsm; } B_NoneType actonQ_rtsQ_U_4sleep (B_SysCap cap, double sleep_time) { double st = sleep_time; struct timespec ts; ts.tv_sec = (int)st; ts.tv_nsec = (st - (float)ts.tv_sec)*1e9; // Handle overflow of nanoseconds into seconds if (ts.tv_nsec >= 1e9) { ts.tv_sec += 1; ts.tv_nsec -= 1e9; } // Use high precision nanosleep where available, otherwise fall back to uv_sleep. #if defined(__linux__) || defined(__APPLE__) // Unlike usleep, nanosleep() tolerates signal interrupts and will write the // remaining time (that it didn't sleep) into the third argument. We spin // until it completes successfully. while (nanosleep(&ts, &ts) != 0) { // Continue sleeping with remaining time } #else // For other platforms, fall back to uv_sleep (millisecond granularity) uv_sleep((uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000); #endif return B_None; } struct actonQ_rtsQ_io_handles_walk_res { B_dict d; B_Hashable wit; }; void actonQ_rtsQ_io_handles_walk_cb (uv_handle_t *handle, void *arg) { struct actonQ_rtsQ_io_handles_walk_res *walk_res = (struct actonQ_rtsQ_io_handles_walk_res *)arg; B_tuple val; if (uv_handle_get_type(handle) == UV_TCP) { $Actor hactor = handle->data; val = (B_tuple)$NEWTUPLE(2, to$str((char *)uv_handle_type_name(uv_handle_get_type(handle))), toB_u64((unsigned long)hactor) ); } else { val = (B_tuple)$NEWTUPLE(2, to$str((char *)uv_handle_type_name(uv_handle_get_type(handle))), toB_u64(0) // TODO: should be None type instead, right? ); } B_dictD_setitem(walk_res->d, walk_res->wit, toB_u64((long)handle), val); } B_dict actonQ_rtsQ__io_handles (B_SysCap cap) { B_Hashable wit = (B_Hashable)B_HashableD_u64G_witness; B_dict d = $NEW(B_dict, wit, NULL, NULL); struct actonQ_rtsQ_io_handles_walk_res walk_res; walk_res.wit = wit; walk_res.d = d; uv_walk(get_uv_loop(), actonQ_rtsQ_io_handles_walk_cb, (void *)&walk_res); return d; } B_dict actonQ_rtsQ_rts_stats (B_SysCap cap) { B_Hashable wit = (B_Hashable)B_HashableD_u64G_witness; B_dict d = $NEW(B_dict, wit, NULL, NULL); for (int i; i <= num_wthreads; i++) { B_tuple stats = $NEWTUPLE(28, to$str("TODO"), // state toB_u64(wt_stats[i].sleeps), toB_u64(wt_stats[i].conts_count), toB_u64(wt_stats[i].conts_sum), toB_u64(wt_stats[i].conts_100ns), toB_u64(wt_stats[i].conts_1us), toB_u64(wt_stats[i].conts_10us), toB_u64(wt_stats[i].conts_100us), toB_u64(wt_stats[i].conts_1ms), toB_u64(wt_stats[i].conts_10ms), toB_u64(wt_stats[i].conts_100ms), toB_u64(wt_stats[i].conts_1s), toB_u64(wt_stats[i].conts_10s), toB_u64(wt_stats[i].conts_100s), toB_u64(wt_stats[i].conts_inf), toB_u64(wt_stats[i].bkeep_count), toB_u64(wt_stats[i].bkeep_sum), toB_u64(wt_stats[i].bkeep_100ns), toB_u64(wt_stats[i].bkeep_1us), toB_u64(wt_stats[i].bkeep_10us), toB_u64(wt_stats[i].bkeep_100us), toB_u64(wt_stats[i].bkeep_1ms), toB_u64(wt_stats[i].bkeep_10ms), toB_u64(wt_stats[i].bkeep_100ms), toB_u64(wt_stats[i].bkeep_1s), toB_u64(wt_stats[i].bkeep_10s), toB_u64(wt_stats[i].bkeep_100s), toB_u64(wt_stats[i].bkeep_inf) ); B_dictD_setitem(d, wit, toB_u64(i), stats); } return d; } $R actonQ_rtsQ_WThreadMonitorD__initG_local (actonQ_rtsQ_WThreadMonitor self, $Cont C_cont) { set_actor_affinity(fromB_int(self->wthread_id)); return $R_CONT(C_cont, B_None); } ================================================ FILE: base/src/argparse.act ================================================ """Command line argument parsing The argparse module provides command-line argument parsing for Acton applications. It supports options (flags), positional arguments, sub-commands, and automatic help generation. ## Basic Usage ```acton import argparse actor main(env): def _parse_args(): p = argparse.Parser() p.add_option("lines", "int", default=10, help="Number of lines", short="n") p.add_bool("follow", "Follow file changes", short="f") p.add_arg("file", "File to tail") return p.parse(env.argv) try: args = _parse_args() num_lines = args.get_int("lines") follow = args.get_bool("follow") filename = args.get_str("file") print("Tailing", num_lines, "lines from", filename) if follow: print("Following file changes...") except argparse.PrintUsage as exc: print(exc.error_message) env.exit(0) except argparse.ArgumentError as exc: print(exc.error_message, err=True) env.exit(1) ``` The typical idiom is to define a `_parse_args()` function that sets up the parser and returns the parsed arguments, then wrap the main logic in a try/except block to handle help requests and argument errors gracefully. ## Positional arguments Positional arguments must appear in a specific order and as plain values, i.e. no leading `-` or `--`: ```acton p.add_arg("file", "File to tail") # required p.add_arg("backup", "Backup file", required=False) # optional p.add_arg("files", "Files to tail", nargs="+") # one or more # Usage: tail log.txt # Usage: tail log.txt backup.log # Usage: tail app.log error.log debug.log ``` ## Boolean flags Boolean flags are options that do not take a value. If present, they are `True`, otherwise they are `False`: ```acton p.add_bool("follow", "Follow file changes", short="f") p.add_bool("quiet", "Suppress headers", short="q") args = p.parse(["tail", "-f", "-q", "app.log"]) follow = args.get_bool("follow") # True quiet = args.get_bool("quiet") # True # Usage: tail -f app.log # Usage: tail --follow --quiet app.log # Usage: tail -fq app.log (grouped) ``` ## Options with values Options can take values of different types: ```acton # Integer option p.add_option("lines", "int", default=10, help="Number of lines", short="n") num_lines = args.get_int("lines") # String option p.add_option("format", "str", default="plain", help="Output format") fmt = args.get_str("format") # String list option p.add_option("exclude", "strlist", nargs="+", help="Patterns to exclude") patterns = args.get_strlist("exclude") # Usage: tail -n 20 --format json --exclude "ERROR" "DEBUG" app.log ``` ## Short options Short options are single character aliases prefixed with a single dash: ```acton p.add_option("lines", "int", default=10, help="Number of lines", short="n") p.add_bool("follow", "Follow file changes", short="f") # These are equivalent: # --lines 20 --follow # -n 20 -f # -n20 -f (inline value) # -fn 20 (grouped boolean + option) ``` ### Grouping rules - Boolean flags can be grouped: `-fq` = `-f -q` - Options with values: `-n 20` or `-n20` (inline) - Short options must be alphanumeric (a-z, A-Z, 0-9) - Each short option must be unique ## Sub-commands Sub-commands enable hierarchical CLIs like `git add` or `docker run`: ```acton def cmd_head(args): lines = args.get_int("lines") print("Head mode:", lines, "lines") def cmd_tail(args): lines = args.get_int("lines") follow = args.get_bool("follow") print("Tail mode:", lines, "lines, follow:", follow) p = argparse.Parser() p.add_bool("verbose", "Verbose output", short="v") head_cmd = p.add_cmd("head", "Show first lines", cmd_head) head_cmd.add_option("lines", "int", default=10, short="n") tail_cmd = p.add_cmd("tail", "Show last lines", cmd_tail) tail_cmd.add_option("lines", "int", default=10, short="n") tail_cmd.add_bool("follow", "Follow changes", short="f") # Usage: viewer -v tail -n 20 -f app.log ``` ## Command handlers and execution After parsing, execute the command handler if one was specified: ```acton args = parser.parse(env.argv) cmd = args.cmd if cmd is not None: cmd(args) # Execute the command function else: # No sub-command, default behavior filename = args.get_str("file") print("Processing", filename, "with default settings") ``` ## Help generation Help is automatically generated and displayed with `--help`: ``` Usage: tail [-n LINES] [-f] FILE Positional arguments: FILE File to tail Options: -n, --lines LINES Number of lines -f, --follow Follow file changes --help show this help message ``` ## Error handling The parser raises specific exceptions for different error conditions: - `ArgumentError`: Invalid arguments, missing values, unknown options - `PrintUsage`: Help requested (catch and print, then exit) Always wrap parsing in try/except to handle these gracefully. """ # TODO: mutually exclusive argument groups # TODO: argument metavar # TODO: required options (oxymoronic)? # TODO: bash completion # # Parsing Algorithm: Three-Phase Approach # # Phase 1 - Option Recognition and Collection: # Parser processes argv sequentially, identifying known long options (--option) and # short options (-x). For grouped short options (-abc), recognized options are processed # immediately while unknown options are reconstructed and added to 'rest'. Sub-commands # are detected and registered but parsing continues. All unrecognized arguments go to 'rest'. # # Phase 2 - Sub-command Processing (recursive): # If a sub-command was identified, its parser receives the 'rest' arguments and repeats # Phase 1 with its own option definitions. This happens recursively for nested sub-commands, # with each level processing its known options and passing unknowns down the chain. # # Phase 3 - Positional Argument Matching: # After all option processing, remaining arguments are matched to positional argument # definitions. Inner-most parsers (deepest sub-commands) process positional arguments # first, enabling optional positional arguments at higher levels while still consuming # required positional arguments in sub-commands. # # Grouped Short Options (-abc): # Recognized options are processed immediately, unknown options are reconstructed as # separate arguments for 'rest' (e.g., -a known, -bc unknown -> -bc goes to rest). # This enables mixed groups where some options belong to the main parser and others # to sub-command parsers. class ArgumentError(Exception): pass class PrintUsage(ArgumentError): pass class Args(object): cmd_parser: ?Parser options: dict[str, (type: str, value: value)] cmd: ?proc(Args) -> None def __init__(self): self.cmd_parser = None self.options = {} self.cmd = None def get_bool(self, name: str) -> bool: try: opt = self.options[name] if opt.type != "bool": raise ValueError(f"Option {name} is not a bool") val = opt.value if isinstance(val, bool): return val raise ValueError(f"Option value {str(val)} is not a bool") except KeyError: raise ArgumentError(f"Option '{name}' not found") def get_int(self, name: str) -> int: try: opt = self.options[name] if opt.type != "int": raise ValueError(f"Option '{name}' is not a int") val = opt.value if isinstance(val, int): return val raise ValueError(f"Option value '{str(val)}' is not a int") except KeyError: raise ArgumentError(f"Option '{name}' not found") def get_str(self, name: str) -> str: try: opt = self.options[name] if opt.type != "str": raise ValueError(f"Option '{name}' is not a str") val = opt.value if isinstance(val, str): return val raise ValueError(f"Option value '{str(val)}' is not a str") except KeyError: raise ArgumentError(f"Option '{name}' not found") def get_strlist(self, name: str) -> list[str]: try: opt = self.options[name] if opt.type != "strlist": raise ValueError(f"Option '{name}' is not a list[str]") val = opt.value if isinstance(val, list): return val raise ValueError(f"Option value '{str(val)}' is not a list[str]") except KeyError: raise ArgumentError(f"Option '{name}' not found") class Parser(object): cmd: str opts: dict[str, (name: str, type: str, nargs: str, default: ?value, help: str, short: ?str)] short_opts: dict[str, str] # short -> long name mapping args: list[(name: str, help: str, required: bool, nargs: str, left: int)] cmds: dict[str, (help: str, parser: Parser, fn: proc(Args) -> None)] prog: str def __init__(self, cmd=""): self.cmd = cmd self.opts = {} self.short_opts = {} self.args = [] self.cmds = {} self.prog = "" def add_bool(self, name: str, help: str, short: ?str=None): if short is not None: if len(short) != 1: raise ArgumentError("Short option must be exactly one character") if not short.isalnum(): raise ArgumentError("Short option must be alphanumeric") if short in self.short_opts: raise ArgumentError(f"Short option '{short}' already exists") self.short_opts[short] = name self.opts[name] = (name=name, type="bool", nargs="?", default=False, help=help, short=short) def add_option(self, name: str, type: str, nargs: str="?", default: ?value=None, help="", short: ?str=None): if name in self.opts: raise ArgumentError(f"Option '{name}' already exists") if type not in {"int", "str", "strlist"}: raise ArgumentError(f"Invalid option type '{type}'") if short is not None: if len(short) != 1: raise ArgumentError("Short option must be exactly one character") if not short.isalnum(): raise ArgumentError("Short option must be alphanumeric") if short in self.short_opts: raise ArgumentError(f"Short option '{short}' already exists") self.short_opts[short] = name self.opts[name] = (name=name, type=type, nargs=nargs, default=default, help=help, short=short) def add_arg(self, name: str, help: str="", required: bool=True, nargs: str="?"): if nargs == "+" or nargs == "*": for arg in self.args: if arg.nargs == "+" or arg.nargs == "*": raise ArgumentError("Only one positional argument with multiple values allowed") self.args.append((name=name, help=help, required=required, nargs=nargs, left=1)) def add_cmd(self, name: str, help: str="", fn: proc(Args) -> None): p = Parser(name) self.cmds[name] = (help=help, parser=p, fn=fn) return p def print_usage(self): print(self.get_usage()) def get_usage(self): usage_text = "" short_opts = "" for name in sorted(self.opts.keys()): opt = self.opts[name] short_opt = opt.short if opt.type == "bool": if short_opt is not None: short_opts += f" [-{short_opt}]" else: short_opts += f" [--{name}]" else: if short_opt is not None: short_opts += f" [-{short_opt} {name.upper()}]" else: short_opts += f" [--{name} {name.upper()}]" for arg in self.args: n = arg.name if n is not None: if arg.nargs == "?": if arg.required: short_opts += f" {n.upper()}" else: short_opts += f" [{n.upper()}]" elif arg.nargs == "+": short_opts += f" {n.upper()} [{n.upper()} ...]" if len(self.cmds) > 0: short_opts += " COMMAND" usage_text += f"Usage: {self.prog}{short_opts}\n" if len(self.cmds) > 0: usage_text += "\nCommands:\n" for name in sorted(self.cmds.keys()): usage_text += f" {name:<14} {self.cmds[name].help}\n" if len(self.args) > 0: usage_text += "\nPositional arguments:\n" for arg in self.args: n = arg.name if n is not None: usage_text += f" {n.upper():<14} {arg.help}\n" if len(self.opts) > 0: usage_text += "\nOptions:\n" for name in sorted(self.opts.keys()): opt = self.opts[name] opt_help = f"--{name}" short_opt = opt.short if short_opt is not None: opt_help = f"-{short_opt}, {opt_help}" if opt.type != "bool": opt_help += f" {name.upper()}" usage_text += f" {opt_help:<14} {opt.help}\n" return usage_text def parse(self, argv: list[str]) -> Args: return self._parse(argv) def _parse(self, argin: list[str], res_args: ?Args=None) -> Args: injected_help = False if "help" not in self.opts: injected_help = True self.add_bool("help", "show this help message") if res_args is None: # top level call self.prog = argin[0] args_to_parse = argin[1:] else: # recursively called args_to_parse = argin args, rest = self._parse_and_consume(args_to_parse, res_args, prog=self.prog) cmd_parser = args.cmd_parser if injected_help and args.get_bool("help"): if cmd_parser is not None: raise PrintUsage(cmd_parser.get_usage()) raise PrintUsage(self.get_usage()) for arg in self.args: if arg.required and arg.name not in args.options: raise ArgumentError(f"Missing positional argument: {arg.name}") return args def _parse_and_consume(self, argv: list[str], res_args: ?Args, prog="") -> (Args, list[str]): self.prog = prog #print(self, "_parse_and_consume, argv:", argv, "res_args:", res_args) rest: list[str] = [] cmd_parser = None if res_args is not None: res = res_args else: res = Args() # Insert default values for akey, aspec in self.opts.items(): defval = aspec.default if defval is not None: res.options[akey] = ("type"=aspec.type, "value"=defval) for arg in self.args: if not arg.required: if arg.nargs == "+": res.options[arg.name] = ("type"="strlist", "value"=[]) skip = 0 for i in range(len(argv)): p = i + skip if p >= len(argv): break arg = argv[p] start = 0 end = len(arg) if arg == '--': rest.extend(argv[p+1:]) break elif arg.startswith('--'): start = 2 val_in_arg = False if arg.find('=') != -1: val_in_arg = True end = arg.find('=') akey = arg[start:end] if akey in self.opts: aspec = self.opts[akey] val = False if aspec.type != "bool": # all other types take a value if val_in_arg: val = arg[end+1:] else: try: val = argv[p+1] except IndexError: raise ArgumentError(f"Missing value to option {arg}") skip += 1 if aspec.type == "bool": res.options[akey] = ("type"="bool", "value"=True) elif aspec.type == "int": try: res.options[akey] = ("type"="int", "value"=int(val)) except ValueError: raise ArgumentError(f"Option {akey} requires an integer value") elif aspec.type == "str": res.options[akey] = ("type"="str", "value"=val) elif aspec.type == "strlist": newval = [] if akey in res.options: curlist = res.options[akey].value if isinstance(curlist, list): newval = curlist newval.append(val) res.options[akey] = ("type"="strlist", "value"=newval) else: #raise ArgumentError(f"Unknown option {arg}") rest.append(arg) elif arg.startswith('-') and len(arg) > 1: # Handle short options (-x or -xyz for grouped bools only) short_chars = arg[1:] # Remove leading dash # Check if this is a single non-bool option with inline value if len(short_chars) > 1: first_char = short_chars[0] if first_char in self.short_opts: first_spec = self.opts[self.short_opts[first_char]] if first_spec.type != "bool": # Single non-bool option with inline value: -ofile.txt akey = self.short_opts[first_char] val = short_chars[1:] # Rest is the value if first_spec.type == "int": try: res.options[akey] = ("type"="int", "value"=int(val)) except ValueError: raise ArgumentError(f"Option -{first_char} requires an integer value") elif first_spec.type == "str": res.options[akey] = ("type"="str", "value"=val) elif first_spec.type == "strlist": newval = [] if akey in res.options: curlist = res.options[akey].value if isinstance(curlist, list): newval = curlist newval.append(val) res.options[akey] = ("type"="strlist", "value"=newval) continue # Skip to next argument # Process as grouped boolean options or single option unknown_chars = [] processed_any = False for j in range(len(short_chars)): short_char = short_chars[j] if short_char in self.short_opts: akey = self.short_opts[short_char] aspec = self.opts[akey] if aspec.type == "bool": res.options[akey] = ("type"="bool", "value"=True) processed_any = True else: # Non-bool short option in group context if j != len(short_chars) - 1: raise ArgumentError(f"Non-boolean option -{short_char} cannot be grouped (must be last or use separate argument)") # Single non-bool option, value comes from next arg val = "" try: val = argv[p+1] skip += 1 except IndexError: raise ArgumentError(f"Missing value to option -{short_char}") if aspec.type == "int": try: res.options[akey] = ("type"="int", "value"=int(val)) except ValueError: raise ArgumentError(f"Option -{short_char} requires an integer value") elif aspec.type == "str": res.options[akey] = ("type"="str", "value"=val) elif aspec.type == "strlist": newval = [] if akey in res.options: curlist = res.options[akey].value if isinstance(curlist, list): newval = curlist newval.append(val) res.options[akey] = ("type"="strlist", "value"=newval) processed_any = True break # Exit loop after processing value else: # Unknown short option, collect for later unknown_chars.append(short_char) # If we have unknown chars, add them to rest as separate arguments if len(unknown_chars) > 0: if len(unknown_chars) == 1: rest.append("-" + unknown_chars[0]) else: rest.append("-" + "".join(unknown_chars)) # If no known options were processed and we have unknowns, # it means the entire arg was unknown if not processed_any and len(unknown_chars) > 0: # We already added the reconstructed unknown args above pass else: if arg in self.cmds: # We found a sub-command, store which one but continue # parsing the rest of the options. Make sure not to set # pass rest of args to subparser for command if cmd_parser is None: cmd = self.cmds[arg] res.cmd = cmd.fn res.cmd_parser = cmd.parser cmd_parser = cmd.parser else: rest.append(arg) else: rest.append(arg) # Run sub-command parser if cmd_parser is not None: #print(self, ": cmd found, invoking cmd parser with", rest) res, posargs = cmd_parser._parse_and_consume(rest, res, prog=self.prog + " " + cmd_parser.cmd) #print(self, ": cmd parser done, res:", res, "posargs:", posargs, "res.cmd:", res.cmd) else: posargs = rest rest = [] #print(self, "Do second loop for optional posargs on rest:", posargs) for i in range(len(posargs)): arg = posargs[i] if len(self.args) == 0: rest.append(arg) else: posarg = self.args[0] if posarg.nargs == "?": res.options[posarg.name] = ("type"="str", "value"=arg) self.args.pop(0) elif posarg.nargs == "+": newval = [] if posarg.name in res.options: curlist = res.options[posarg.name].value if isinstance(curlist, list): newval = curlist newval.append(arg) res.options[posarg.name] = ("type"="strlist", "value"=newval) remaining_posargs = len(self.args) - 1 if len(posargs)-(i+1) == remaining_posargs: self.args.pop(0) return res, rest ================================================ FILE: base/src/base64.act ================================================ def encode(data: bytes) -> bytes: NotImplemented def decode(data: bytes) -> bytes: NotImplemented ================================================ FILE: base/src/base64.ext.c ================================================ void base64Q___ext_init__() {} ================================================ FILE: base/src/buildy.act ================================================ """Buildy stuff Our projects have a built.act and it collides with this module if it would be called just 'build', so it's buildy for buildy stuff. """ import file import json import re class BuildSpecError(ValueError): pass def zig_safe_name(name: str) -> str: m = re.match(r"^[a-zA-Z][a-zA-Z0-9_]*$", name) if m is None: raise BuildSpecError(f"Invalid dependency name '{name}', must start with a letter and only contain letters, numbers and underscores") return name class BuildSpec(object): """Build configuration, the content of Build.act - name is the project name - description is a human-readable project description (optional) - dependencies are dependencies on other Acton projects - zig_dependencies are dependencies on Zig projects, which could in turn be Zig, C or C++ libraries that get linked in with the project - fingerprint identifies the project lineage """ name: str description: ?str dependencies: dict[str, PkgDependency] zig_dependencies: dict[str, ZigDependency] # Acton-managed package fingerprint (string, e.g. "0x1234abcd...") fingerprint: str def __init__(self, name: str, fingerprint: str, description: ?str=None, dependencies: dict[str, PkgDependency]={}, zig_dependencies: dict[str, ZigDependency]={}): self.name = name self.fingerprint = fingerprint self.description = description self.dependencies = dependencies self.zig_dependencies = zig_dependencies @staticmethod def from_json(data: str): jd = json.decode(data) name = "" has_name = False description = None new_dependencies = {} new_zig_dependencies = {} fingerprint = "" has_fingerprint = False if isinstance(jd, dict): for key, value in jd.items(): if isinstance(key, str): if key == "name": if value is None: has_name = False elif isinstance(value, str): name = value has_name = True else: raise ValueError("Invalid build spec JSON, name should be a string") elif key == "description": if value is None: description = None elif isinstance(value, str): description = value else: raise ValueError("Invalid build spec JSON, description should be a string") elif key == "dependencies": if value is None: new_dependencies = {} elif isinstance(value, dict): for dep_name, dep_attrs in value.items(): if isinstance(dep_name, str) and isinstance(dep_attrs, dict): dep = PkgDependency.from_json(dep_name, dep_attrs) new_dependencies[dep_name] = dep else: raise ValueError("Invalid build spec JSON, dependencies should be a dict") else: raise ValueError("Invalid build spec JSON, dependencies should be a dict") elif key == "zig_dependencies": if value is None: new_zig_dependencies = {} elif isinstance(value, dict): for dep_name, dep_attrs in value.items(): if isinstance(dep_name, str) and isinstance(dep_attrs, dict): dep = ZigDependency.from_json(dep_name, dep_attrs) new_zig_dependencies[dep_name] = dep else: raise ValueError("Invalid build spec JSON, zig_dependencies should be a dict") else: raise ValueError("Invalid build spec JSON, zig_dependencies should be a dict") elif key == "fingerprint": if value is None: has_fingerprint = False elif isinstance(value, str): fingerprint = value has_fingerprint = True else: raise ValueError("Invalid build spec JSON, fingerprint should be a string like 0xdeadbeef...") else: raise ValueError(f"Invalid build spec JSON, unknown key '{key}'") else: raise ValueError("Invalid build spec JSON, non-string key found in top level dict") if not has_name: raise ValueError("Invalid build spec JSON, name is required") if not has_fingerprint: raise ValueError("Invalid build spec JSON, fingerprint is required") return BuildSpec(name, fingerprint, description, new_dependencies, new_zig_dependencies) raise ValueError("Invalid build spec JSON, top level should be a dict") def to_json(self) -> str: res_deps = {} res_zigdeps = {} for dep_name, dep in self.dependencies.items(): res_deps[dep_name] = dep.to_json() for dep_name, dep in self.zig_dependencies.items(): res_zigdeps[dep_name] = dep.to_json() res = { "name": self.name, "fingerprint": self.fingerprint, "dependencies": res_deps, "zig_dependencies": res_zigdeps, } description = self.description if description is not None: res["description"] = description return json.encode(res, pretty=True) def extract_fingerprint(zon_text: str) -> ?str: for line in zon_text.split("\n"): sline = line.strip() if sline.startswith(".fingerprint"): parts = sline.split("=", 1) if len(parts) == 2: value = parts[1].strip().rstrip(",") if re.match(r"^0x[0-9a-fA-F]+$", value) is not None and value != "0xacedf00dacedf00d": return value return None class Dependency(object): name: str url: ?str hash: ?str path: ?str repo_url: ?str repo_ref: ?str class PkgDependency(Dependency): def __init__(self, name: str, url: ?str, hash: ?str, path: ?str, repo_url: ?str, repo_ref: ?str): if path is not None and url is not None: raise ValueError(f"Dependency '{name}' has both path and url set. Set only path or url. You can override path for a dep, e.g.: acton build --dep {name}={path}") self.name = zig_safe_name(name) self.url = url self.hash = hash self.path = path self.repo_url = repo_url self.repo_ref = repo_ref @staticmethod def from_json(dep_name, data: dict[str, str]): dep_url = None dep_hash = None dep_path = None dep_repo_url = None dep_repo_ref = None for key, value in data.items(): if key == "url": data_url = data["url"] if isinstance(data_url, str): dep_url = data_url elif key == "hash": data_hash = data["hash"] if isinstance(data_hash, str): dep_hash = data_hash elif key == "path": data_path = data["path"] if isinstance(data_path, str): dep_path = data_path elif key == "repo_url": data_repo_url = data["repo_url"] if isinstance(data_repo_url, str): dep_repo_url = data_repo_url elif key == "repo_ref": data_repo_ref = data["repo_ref"] if isinstance(data_repo_ref, str): dep_repo_ref = data_repo_ref else: raise ValueError(f"Invalid build spec JSON, unknown key '{key}' in dependency '{dep_name}'") return PkgDependency(dep_name, dep_url, dep_hash, dep_path, dep_repo_url, dep_repo_ref) def to_json(self) -> dict[str, str]: res = {} repo_url = self.repo_url if repo_url is not None: res["repo_url"] = repo_url repo_ref = self.repo_ref if repo_ref is not None: res["repo_ref"] = repo_ref url = self.url if url is not None: res["url"] = url hash = self.hash if hash is not None: res["hash"] = hash path = self.path if path is not None: res["path"] = path return res def to_zon(self, deps_path) -> str: path = "" self_path = self.path if self_path is not None: path = self_path else: dep_hash = self.hash if dep_hash is not None: path = file.join_path([deps_path, f"{self.name}-{dep_hash}"]) else: raise ValueError(f"Invalid build spec JSON, dependency '{self.name}' has no path or hash") return """ .%s = .{{ .path = "%s" }}, """ % ( self.name, path ) class ZigDependency(Dependency): options: dict[str, str] artifacts: list[str] def __init__(self, name: str, url: ?str, hash: ?str, path: ?str, options: dict[str, str], artifacts: list[str]): self.name = zig_safe_name(name) self.url = url self.hash = hash self.path = path self.repo_url = None self.repo_ref = None self.options = options self.artifacts = artifacts @staticmethod def from_json(dep_name, data: dict[str, str]): dep_url: ?str = None dep_hash: ?str = None dep_path: ?str = None dep_options: dict[str, str] = {} dep_artifacts: list[str] = [] for key, value in data.items(): if key == "url": data_url = value if isinstance(data_url, str): dep_url = data_url elif key == "hash": data_hash = value if isinstance(data_hash, str): dep_hash = data_hash elif key == "path": data_path = value if isinstance(data_path, str): dep_path = data_path elif key == "options": data_options = value if isinstance(data_options, dict): dep_options = data_options elif key == "artifacts": data_artifacts = value if isinstance(data_artifacts, list): dep_artifacts = data_artifacts else: raise ValueError(f"Invalid build spec JSON, unknown key '{key}' in dependency '{dep_name}'") return ZigDependency(dep_name, dep_url, dep_hash, dep_path, dep_options, dep_artifacts) def to_json(self) -> dict[str, value]: res = {} url = self.url if url is not None: res["url"] = url hash = self.hash if hash is not None: res["hash"] = hash path = self.path if path is not None: res["path"] = path options = self.options if len(options) > 0: res["options"] = options artifacts = self.artifacts if len(artifacts) > 0: res["artifacts"] = artifacts return res def to_zon(self) -> str: url = self.url hash = self.hash self_path = self.path if self_path is not None: return """ .%s = .{{ .path = "%s", }}, """ % (self.name, self_path) return """ .%s = .{{ .url = "%s", .hash = "%s", }}, """ % ( self.name, url if url is not None else "", hash if hash is not None else "", ) def gen_buildzig(template: str, build_config: BuildSpec) -> str: deps_defs = "" liblink_lines = "" exelink_lines = "" for dep in build_config.dependencies.values(): deps_defs += " const actdep_" + dep.name + " = b.dependency(\"" + dep.name + "\", .{{\n" deps_defs += " .target = target,\n" deps_defs += " .optimize = optimize,\n" deps_defs += " }});\n" liblink_lines += " libActonProject.linkLibrary(actdep_" + dep.name + ".artifact(\"ActonProject\"));\n" exelink_lines += " executable.linkLibrary(actdep_" + dep.name + ".artifact(\"ActonProject\"));\n" for dep_name, dep in build_config.zig_dependencies.items(): if len(dep.artifacts) > 0: deps_defs += " const dep_" + dep.name + " = b.dependency(\"" + dep.name + "\", .{{\n" deps_defs += " .target = target,\n" deps_defs += " .optimize = optimize,\n" for key, value in dep.options.items(): deps_defs += " ." + key + " = " + value + ",\n" deps_defs += " }});\n" for artifact in dep.artifacts: liblink_lines += " libActonProject.linkLibrary(dep_" + dep.name + ".artifact(\"" + artifact + "\"));\n" exelink_lines += " executable.linkLibrary(dep_" + dep.name + ".artifact(\"" + artifact + "\"));\n" res = [ "// AUTOMATICALLY GENERATED BY ACTON BUILD SYSTEM", "// DO NOT EDIT, CHANGES WILL BE OVERWRITTEN!!!!!", "", ] for line in template.split("\n"): res.append(line) sline = line.strip() if sline == "// Dependencies from Build.act": res.append(deps_defs) if sline == "// lib: link with dependencies / get headers from Build.act": res.append(liblink_lines) if sline == "// exe: link with dependencies / get headers from Build.act": res.append(exelink_lines) return "\n".join(res) def gen_buildzigzon(template: str, build_config: BuildSpec, relative_syspath: str, deps_path: str) -> str: deps = "" for dep_name, dep in build_config.dependencies.items(): deps += dep.to_zon(deps_path) for dep_name, dep in build_config.zig_dependencies.items(): deps += dep.to_zon() res = [ "// AUTOMATICALLY GENERATED BY ACTON BUILD SYSTEM", "// DO NOT EDIT, CHANGES WILL BE OVERWRITTEN!!!!!", "", ] for line in template.split("\n"): line = line.replace(r"{{syspath}}", relative_syspath) if "{{fingerprint}}" in line: line = line.replace(r"{{fingerprint}}", str(build_config.fingerprint)) res.append(line) sline = line.strip() if sline == "// Dependencies from Build.act": res.append(deps) return "\n".join(res) ================================================ FILE: base/src/crypto/hash/md5.act ================================================ class Hasher(object): _hasher: u64 def __init__(self): """Initialize a new MD5 hashing context """ self._hasher = 0 self._init() def _init(self): """C function to reach out to Zig code""" NotImplemented def update(self, data: bytes) -> None: """Update the hasher state with the given chunk of data""" NotImplemented def finalize(self) -> bytes: """Finalize the hash and return the 16-byte MD5 digest as bytes After final() is called, this instance should not be used again. """ NotImplemented def hash(data: bytes) -> bytes: """Compute and return the MD5 digest of the given data""" m = Hasher() m.update(data) return m.finalize() ================================================ FILE: base/src/crypto/hash/md5.ext.c ================================================ void cryptoQ_hashQ_md5Q___ext_init__() {} void *zig_crypto_hash_md5_init(); void *zig_crypto_hash_md5_update(void *hasher, B_bytes data); void *zig_crypto_hash_md5_finalize(void *hasher, B_bytes output); B_NoneType cryptoQ_hashQ_md5Q_HasherD__init (cryptoQ_hashQ_md5Q_Hasher self) { self->_hasher = zig_crypto_hash_md5_init(); return B_None; } B_NoneType cryptoQ_hashQ_md5Q_HasherD_update (cryptoQ_hashQ_md5Q_Hasher self, B_bytes data) { zig_crypto_hash_md5_update(self->_hasher, data); return B_None; } B_bytes cryptoQ_hashQ_md5Q_HasherD_finalize (cryptoQ_hashQ_md5Q_Hasher self) { B_bytes output = to$bytes("1234567890abcdef"); zig_crypto_hash_md5_finalize(self->_hasher, output); return output; } ================================================ FILE: base/src/diff.act ================================================ import term # Implementation of Myers-inspired diff algorithm, which is efficient and produces # good results for typical text file differences. # This algorithm uses a divide-and-conquer approach with features from Myers and # Patience diff algorithms to identify changes between two sequences. # The algorithm focuses on finding common sequences and anchors to produce # minimal, readable diffs. # Myers algorithm is documented at: http://blog.robertelder.org/diff-algorithm/ def myers_diff(e: list[str], f: list[str], i: int = 0, j: int = 0) -> list[Op]: """ Myers-inspired diff algorithm implementation - finds the minimal edit script between two sequences. This algorithm combines elements of Myers diff and Patience diff to efficiently find differences between sequences. It uses a divide-and-conquer approach that: 1. Quickly identifies common prefixes and suffixes 2. Finds matching sections in the middle ("middle snake") 3. Uses unique lines as anchors to align content 4. Handles special cases efficiently (empty sequences, single elements) The implementation creates Keep/Insert/Delete operations directly, compatible with the unified diff format. Args: e: First sequence (old) f: Second sequence (new) i: Starting position in first sequence (used in recursion) j: Starting position in second sequence (used in recursion) Returns: List of diff operations (Keep, Insert, Delete) representing the minimal edit script """ # Handle edge cases first if len(e) == 0: # All lines in f were inserted result = [] for n in range(0, len(f)): result.append(Insert(f[n], j + n)) return result if len(f) == 0: # All lines in e were deleted result = [] for n in range(0, len(e)): result.append(Delete(e[n], i + n)) return result # Find the longest common prefix prefix_len = 0 while prefix_len < len(e) and prefix_len < len(f) and e[prefix_len] == f[prefix_len]: prefix_len += 1 # Generate Keep operations for the common prefix prefix_ops = [] for n in range(0, prefix_len): prefix_ops.append(Keep(e[n], i + n, j + n)) # Find the longest common suffix suffix_len = 0 while suffix_len < len(e) - prefix_len and suffix_len < len(f) - prefix_len and e[len(e) - 1 - suffix_len] == f[len(f) - 1 - suffix_len]: suffix_len += 1 # Generate Keep operations for the common suffix suffix_ops = [] for n in range(0, suffix_len): old_idx = len(e) - suffix_len + n new_idx = len(f) - suffix_len + n suffix_ops.append(Keep(e[old_idx], i + old_idx, j + new_idx)) # If we have a common prefix or suffix, recursively diff the middle part if prefix_len > 0 or suffix_len > 0: middle_ops = myers_diff( e[prefix_len:len(e)-suffix_len], f[prefix_len:len(f)-suffix_len], i + prefix_len, j + prefix_len ) return prefix_ops + middle_ops + suffix_ops # If e is just one element and f has multiple elements, delete e and insert all of f if len(e) == 1 and len(f) > 1: result = [Delete(e[0], i)] for n in range(0, len(f)): result.append(Insert(f[n], j + n)) return result # If f is just one element and e has multiple elements, delete all of e and insert f if len(f) == 1 and len(e) > 1: result = [] for n in range(0, len(e)): result.append(Delete(e[n], i + n)) result.append(Insert(f[0], j)) return result # If both have just one element, compare them if len(e) == 1 and len(f) == 1: if e[0] == f[0]: return [Keep(e[0], i, j)] else: return [Delete(e[0], i), Insert(f[0], j)] # Divide and conquer: find the middle snake middle = len(e) // 2 # Find best matching line in f for the middle of e best_match_pos = -1 best_match_len = -1 for pos in range(0, len(f)): match_len = 0 while middle + match_len < len(e) and pos + match_len < len(f) and e[middle + match_len] == f[pos + match_len]: match_len += 1 if match_len > best_match_len: best_match_len = match_len best_match_pos = pos if best_match_len > 0: # Generate Keep operations for the matching segment match_ops = [] for n in range(0, best_match_len): match_ops.append(Keep(e[middle + n], i + middle + n, j + best_match_pos + n)) # Recursively diff the segments before and after the match before_ops = myers_diff(e[0:middle], f[0:best_match_pos], i, j) after_ops = myers_diff( e[middle+best_match_len:], f[best_match_pos+best_match_len:], i + middle + best_match_len, j + best_match_pos + best_match_len ) return before_ops + match_ops + after_ops # No good match in the middle, use Patience diff approach # Try to identify unique lines and align around them unique_lines_e = {} for idx, line in enumerate(e): if line not in unique_lines_e: unique_lines_e[line] = [] unique_lines_e[line].append(idx) unique_lines_f = {} for idx, line in enumerate(f): if line not in unique_lines_f: unique_lines_f[line] = [] unique_lines_f[line].append(idx) # Find lines that appear exactly once in both sequences anchors: list[(int, int)] = [] for line, e_indices in unique_lines_e.items(): if len(e_indices) == 1 and line in unique_lines_f and len(unique_lines_f[line]) == 1: e_idx = e_indices[0] f_idx = unique_lines_f[line][0] anchors.append((e_idx, f_idx)) # Sort anchors by position in e # We'll do a simple bubble sort that uses a temporary variable for the swap sorted_anchors = list(anchors) # Make a copy for i in range(len(sorted_anchors)): for j in range(len(sorted_anchors) - i - 1): if sorted_anchors[j].0 > sorted_anchors[j+1].0: # Swap using a temporary variable temp = sorted_anchors[j] sorted_anchors[j] = sorted_anchors[j+1] sorted_anchors[j+1] = temp # Extract sorted indices sorted_e_indices = [] sorted_f_indices = [] for anchor in sorted_anchors: sorted_e_indices.append(anchor.0) sorted_f_indices.append(anchor.1) if len(sorted_e_indices) > 0: # We found unique matching lines, use them as anchors result = [] # Initialize with starting positions last_e = 0 last_f = 0 for idx in range(len(sorted_e_indices)): e_idx = sorted_e_indices[idx] f_idx = sorted_f_indices[idx] # Recursively diff the segment before this anchor if e_idx > last_e or f_idx > last_f: before_ops = myers_diff(e[last_e:e_idx], f[last_f:f_idx], i + last_e, j + last_f) result.extend(before_ops) # Add the anchor line as a Keep operation result.append(Keep(e[e_idx], i + e_idx, j + f_idx)) # Update last positions last_e = e_idx + 1 last_f = f_idx + 1 # Process the last segment after the last anchor if last_e < len(e) or last_f < len(f): after_ops = myers_diff(e[last_e:], f[last_f:], i + last_e, j + last_f) result.extend(after_ops) return result # Fall back to simple edit script if no anchors found result = [] for n in range(0, len(e)): result.append(Delete(e[n], i + n)) for n in range(0, len(f)): result.append(Insert(f[n], j + n)) return result # Base operation class class Op: def __init__(self): pass def format_with_color(self) -> str: return "" class Gap(Op): def __init__(self): pass def __str__(self) -> str: return "..." def format_with_color(self) -> str: return term.grey20 + "..." + term.normal # Keep operation class (for context lines) class Keep(Op): content: str index_old: int index_new: int def __init__(self, content: str, index_old: int, index_new: int): self.content = content self.index_old = index_old self.index_new = index_new def __str__(self) -> str: return f" {self.content}" def format_with_color(self) -> str: return term.grey20 + str(self) + term.normal # Delete operation class class Delete(Op): content: str index_old: int def __init__(self, content: str, index_old: int): self.content = content self.index_old = index_old def __str__(self) -> str: return f"-{self.content}" def format_with_color(self) -> str: return term.red + str(self) + term.normal # Insert operation class class Insert(Op): content: str index_new: int def __init__(self, content: str, index_new: int): self.content = content self.index_new = index_new def __str__(self) -> str: return f"+{self.content}" def format_with_color(self) -> str: return term.green + str(self) + term.normal def filter_operations_with_context(operations: list[Op], context_lines: int) -> list[Op]: """ Filter operations to only include changes and their surrounding context. Args: operations: List of diff operations context_lines: Number of unchanged lines to include around each change Returns: Filtered list of operations with only changes and their context """ if context_lines < 0: # Show all context return operations # Find the indices of operations with changes (deletes and inserts) change_indices = [] for i in range(len(operations)): if isinstance(operations[i], Delete) or isinstance(operations[i], Insert): change_indices.append(i) # If no changes, return empty list if len(change_indices) == 0: return [] # Determine which lines should be included include_line = [False] * len(operations) # Mark lines within context_lines of any change for i in range(len(operations)): for change_idx in change_indices: if abs(i - change_idx) <= context_lines: include_line[i] = True break # Create filtered list filtered_ops = [] # Add operations with Gap markers for gaps in_chunk = False for i in range(len(operations)): if include_line[i]: # If starting a new chunk after a gap, add a marker line if not in_chunk and i > 0 and len(filtered_ops) > 0: filtered_ops.append(Gap()) filtered_ops.append(operations[i]) in_chunk = True else: in_chunk = False return filtered_ops def generate_chunk_header(chunk_ops: list[Op]) -> str: """ Generate a unified diff chunk header showing line numbers. Format: @@ -, +, @@ Args: chunk_ops: List of operations for this chunk Returns: Chunk header string in unified diff format """ # Find line numbers for old and new files old_start = -1 old_count = 0 new_start = -1 new_count = 0 for op in chunk_ops: if isinstance(op, Gap): continue if isinstance(op, Keep): # Line exists in both files if old_start == -1: old_start = op.index_old if new_start == -1: new_start = op.index_new old_count += 1 new_count += 1 elif isinstance(op, Delete): # Line only exists in old file if old_start == -1: old_start = op.index_old old_count += 1 elif isinstance(op, Insert): # Line only exists in new file if new_start == -1: new_start = op.index_new new_count += 1 # Default to 1 if no valid index found (shouldn't happen) if old_start == -1: old_start = 0 if new_start == -1: new_start = 0 # Line numbers in display are 1-based return f"@@ -{old_start+1},{old_count} +{new_start+1},{new_count} @@" def find_chunks(operations: list[Op]) -> list[list[Op]]: """ Split operations into chunks, using Gap operations as dividers. Args: operations: List of diff operations, potentially including Gap markers Returns: List of operation chunks, where each chunk is a list of operations """ chunks = [] current_chunk = [] for op in operations: if isinstance(op, Gap): # End the current chunk if it has operations if len(current_chunk) > 0: chunks.append(current_chunk) current_chunk = [] else: # Add to the current chunk current_chunk.append(op) # Add the last chunk if it exists if len(current_chunk) > 0: chunks.append(current_chunk) return chunks def diff(old_text: str, new_text: str, color=False, context_lines=3) -> str: """ Generate a unified diff between two text strings Uses the Myers diff algorithm. Args: old_text: Original text content new_text: New text content color: Whether to add terminal color codes to the output (default False) context_lines: Number of unchanged lines to show around each change (default 3 lines), use -1 for showing all lines Returns: Empty string if texts are identical, otherwise returns a unified diff. If context_lines is specified, only shows that many unchanged lines around changes. """ if old_text == new_text: return "" old_lines = old_text.splitlines(True) new_lines = new_text.splitlines(True) # Handle case where last line doesn't have newline if len(old_lines) > 0 and old_text[-1] != '\n': old_lines[-1] = old_lines[-1] + '\n' if len(new_lines) > 0 and new_text[-1] != '\n': new_lines[-1] = new_lines[-1] + '\n' operations = myers_diff(old_lines, new_lines) if context_lines >= 0: operations = filter_operations_with_context(operations, context_lines) if len(operations) == 0: return "" result = [] # Skip headers only when context_lines=-1 (showing full file) # We're going to simplify our approach here skip_headers = context_lines < 0 for chunk in find_chunks(operations): if not skip_headers: # Generate and add chunk header header = generate_chunk_header(chunk) if color: result.append(term.grey20 + header + "\n" + term.normal) else: result.append(header + "\n") # Add the operations for this chunk for op in chunk: if color: result.append(op.format_with_color()) else: result.append(str(op)) return "".join(result).rstrip() ================================================ FILE: base/src/file.act ================================================ class FileCap(): def __init__(self, cap: WorldCap): pass class ReadFileCap(): def __init__(self, cap: FileCap): pass class WriteFileCap(): def __init__(self, cap: FileCap): pass def get_relative_path(target_path: str, from_path: str) -> str: """ Compute the relative path from one absolute path to another. Args: target_path: The absolute path we want to reach from_path: The absolute path we're starting from Returns: A relative path that will reach target_path from from_path Raises: ValueError: If either path is not absolute (doesn't start with '/') """ # Validate inputs are absolute paths if not target_path.startswith('/') or not from_path.startswith('/'): raise ValueError("Both paths must be absolute (start with '/')") # Split paths into components and remove empty strings target_parts = [] for p in target_path.split('/'): if p: target_parts.append(p) from_parts = [] for p in from_path.split('/'): if p: from_parts.append(p) # Find common prefix common_length = 0 for t, f in zip(target_parts, from_parts): if t != f: break common_length += 1 # Build the relative path # First go up as many levels as needed up_levels = len(from_parts) - common_length up_path = [] for _ in range(up_levels): up_path.append('..') # Then add the path to the target down_path = [] for i in range(common_length, len(target_parts)): down_path.append(target_parts[i]) # Combine the parts relative_parts = [] relative_parts.extend(up_path) relative_parts.extend(down_path) # Handle special case where paths are identical if not relative_parts: return '.' # Join with forward slashes return '/'.join(relative_parts) def resolve_relative_path(start_dir: str, rel_path: str) -> str: """ Resolve a relative path against a working directory to get an absolute path. Args: start_dir: Start directory (must be absolute) rel_path: Relative path to resolve Returns: The resulting absolute path Raises: ValueError: If start_dir is not absolute or if rel_path is absolute """ if not start_dir.startswith('/'): raise ValueError("Working directory must be absolute (start with '/')") if rel_path.startswith('/'): # Relative path is already absolute return rel_path # Handle empty or current directory case if not rel_path or rel_path == '.': return start_dir # Split both paths into components sd_parts = [] for p in start_dir.split('/'): if p: sd_parts.append(p) rel_parts = [] for p in rel_path.split('/'): if p != '.': rel_parts.append(p) # Start with the working directory components result_parts = [] result_parts.extend(sd_parts) # Process each component of the relative path for part in rel_parts: if part == '..': if not result_parts: raise ValueError("Relative path goes above root directory") result_parts.pop() else: result_parts.append(part) # Construct the final path if not result_parts: return '/' return '/' + '/'.join(result_parts) class FileStat(value): name: str dev: u64 mode: u64 nlink: u64 uid: u64 gid: u64 rdev: u64 ino: u64 size: u64 blksize: u64 blocks: u64 flags: u64 gen: u64 atime: float mtime: float ctime: float birthtime: float def __init__(self, name: str, dev: u64, mode: u64, nlink: u64, uid: u64, gid: u64, rdev: u64, ino: u64, size: u64, blksize: u64, blocks: u64, flags: u64, gen: u64, atime: float, mtime: float, ctime: float, birthtime: float): self.name = name self.dev = dev self.mode = mode self.nlink = nlink self.uid = uid self.gid = gid self.rdev = rdev self.ino = ino self.size = size self.blksize = blksize self.blocks = blocks self.flags = flags self.gen = gen self.atime = atime self.mtime = mtime self.ctime = ctime self.birthtime = birthtime def is_dir(self) -> bool: """Return True if the file is a directory""" NotImplemented def is_file(self) -> bool: """Return True if the file is a regular file""" NotImplemented def is_symlink(self) -> bool: """Return True if the file is a symbolic link""" NotImplemented def is_block_device(self) -> bool: """Return True if the file is a block device""" NotImplemented def is_char_device(self) -> bool: """Return True if the file is a character device""" NotImplemented def is_fifo(self) -> bool: """Return True if the file is a FIFO""" NotImplemented def is_socket(self) -> bool: """Return True if the file is a socket""" NotImplemented extension FileStat (Eq): def __eq__(self, other) -> bool: return self.name == other.name and self.dev == other.dev and self.mode == other.mode and self.nlink == other.nlink and self.uid == other.uid and self.gid == other.gid and self.rdev == other.rdev and self.ino == other.ino and self.size == other.size and self.blksize == other.blksize and self.blocks == other.blocks and self.flags == other.flags and self.gen == other.gen and self.atime == other.atime and self.mtime == other.mtime and self.ctime == other.ctime and self.birthtime == other.birthtime def join_path(parts: list[str], sep: ?str=None) -> str: """Join two paths""" # TODO: support more than just / as separator based on platform psep = "/" if sep is not None: psep = sep return psep.join(parts) # TODO: refactor into a read-only version and one for writing!? actor FS(cap: FileCap): """File system operations """ proc def _pin_affinity() -> None: NotImplemented _pin_affinity() action def copyfile(src: str, dst: str) -> None: """Copy a file""" NotImplemented action def copytree(src: str, dst: str) -> None: """Copy a directory tree""" for entry in listdir(src): s = lstat(join_path([src, entry])) if s.is_dir(): mkdir(join_path([dst, entry])) copytree(join_path([src, entry]), join_path([dst, entry])) else: copyfile(join_path([src, entry]), join_path([dst, entry])) action def cwd() -> str: """Get the current working directory""" NotImplemented action def exepath() -> str: """Get the path to the executable""" NotImplemented action def homedir() -> str: """Get the home directory""" NotImplemented action def mkdir(filename: str): """Make a directory""" NotImplemented action def mktmpdir(prefix: str="") -> str: """Make a temporary directory""" NotImplemented action def listdir(path: str) -> list[str]: """List directory contents""" NotImplemented action def lstat(filename: str) -> FileStat: """Get file status without following symlinks""" NotImplemented action def remove(filename: str) -> None: """Remove a file""" NotImplemented action def rmdir(dirname: str) -> None: """Remove a directory""" NotImplemented action def rmtree(d: str) -> None: """Recursively remove a directory tree""" try: for entry in listdir(d): try: s = lstat(d + "/" + entry) if s.is_dir(): rmtree(d + "/" + entry) rmdir(d + "/" + entry) else: remove(d + "/" + entry) except OSError: # probably a symlink or permission denied pass except OSError: # dir doesn't exist pass action def tmpdir() -> str: """Get temporary directory""" NotImplemented action def stat(filename: str) -> FileStat: """Get file status""" NotImplemented action def walk(d: str, follow_symlinks: bool=False) -> list[FileStat]: """Recursively walk a directory tree""" # TODO: this should be a generator res = [] try: for entry in listdir(d): try: if follow_symlinks: s = stat(d + "/" + entry) else: s = lstat(d + "/" + entry) res.append(s) if s.is_dir(): res.extend(walk(d + "/" + entry)) except OSError: # probably a symlink or permission denied pass except OSError: # dir doesn't exist pass return res actor ReadFile(cap: ReadFileCap, filename: str, lock=False): """Read a file """ var _fd = -1 proc def _open_file(): """C magic""" NotImplemented proc def _lock_file(): NotImplemented _open_file() if lock: _lock_file() action def read() -> bytes: """Read content of file""" NotImplemented action def close() -> None: """Close file""" NotImplemented actor WriteFile(cap: WriteFileCap, filename: str, lock=False): """Write a file """ var _fd = -1 proc def _open_file(): """C magic""" NotImplemented proc def _lock_file(): NotImplemented _open_file() if lock: _lock_file() action def write(data: bytes) -> None: """Write data to file""" NotImplemented action def close() -> None: """Close file""" NotImplemented ================================================ FILE: base/src/file.ext.c ================================================ #define GC_THREADS 1 #include "gc.h" #include #include #include #include #include "../rts/io.h" #include "../rts/log.h" #include "../out/types/file.h" void fileQ___ext_init__() { } $R fileQ_FSD__pin_affinityG_local (fileQ_FS self, $Cont c$cont) { pin_actor_affinity(); return $R_CONT(c$cont, B_None); } // def is_dir(self) -> bool: B_bool fileQ_FileStatD_is_dir (fileQ_FileStat self) { return toB_bool(S_ISDIR(fromB_u64(self->mode))); } // def is_file(self) -> bool: B_bool fileQ_FileStatD_is_file (fileQ_FileStat self) { return toB_bool(S_ISREG(fromB_u64(self->mode))); } // def is_symlink(self) -> bool: B_bool fileQ_FileStatD_is_symlink (fileQ_FileStat self) { #if defined(_WIN32) || defined(_WIN64) // TODO: do better return B_False; #else return toB_bool(S_ISLNK(fromB_u64(self->mode))); #endif } // def is_block_device(self) -> bool: B_bool fileQ_FileStatD_is_block_device (fileQ_FileStat self) { return toB_bool(S_ISBLK(fromB_u64(self->mode))); } // def is_char_device(self) -> bool: B_bool fileQ_FileStatD_is_char_device (fileQ_FileStat self) { return toB_bool(S_ISCHR(fromB_u64(self->mode))); } // def is_fifo(self) -> bool: B_bool fileQ_FileStatD_is_fifo (fileQ_FileStat self) { #if defined(_WIN32) || defined(_WIN64) // TODO: do better return B_False; #else return toB_bool(S_ISFIFO(fromB_u64(self->mode))); #endif } // def is_socket(self) -> bool: B_bool fileQ_FileStatD_is_socket (fileQ_FileStat self) { #if defined(_WIN32) || defined(_WIN64) // TODO: do better return B_False; #else return toB_bool(S_ISSOCK(fromB_u64(self->mode))); #endif } // action def copyfile(src: str, dst: str) -> None: $R fileQ_FSD_copyfileG_local (fileQ_FS self, $Cont C_cont, B_str src, B_str dst) { uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); int r = uv_fs_copyfile(get_uv_loop(), req, (char *)fromB_str(src), (char *)fromB_str(dst), 0, NULL); if (r < 0) { char errmsg[1024] = "Error copying file: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } uv_fs_req_cleanup(req); return $R_CONT(C_cont, B_None); } // action def cwd() -> str: $R fileQ_FSD_cwdG_local (fileQ_FS self, $Cont C_cont) { char cwd[1024]; size_t size = sizeof(cwd); int r = uv_cwd(cwd, &size); if (r < 0) { char errmsg[1024] = "Error getting cwd: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } return $R_CONT(C_cont, to$str(cwd)); } // action def exepath() -> str: $R fileQ_FSD_exepathG_local (fileQ_FS self, $Cont C_cont) { char exepath[1024]; size_t size = sizeof(exepath); int r = uv_exepath(exepath, &size); if (r < 0) { char errmsg[1024] = "Error getting exepath: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } return $R_CONT(C_cont, to$str(exepath)); } // action def homedir() -> str: $R fileQ_FSD_homedirG_local (fileQ_FS self, $Cont C_cont) { char homedir[1024]; size_t size = sizeof(homedir); int r = uv_os_homedir(homedir, &size); if (r < 0) { char errmsg[1024] = "Error getting homedir: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } return $R_CONT(C_cont, to$str(homedir)); } // action def mkdir(filename: str): $R fileQ_FSD_mkdirG_local (fileQ_FS self, $Cont C_cont, B_str filename) { uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); int r = uv_fs_mkdir(get_uv_loop(), req, (char *)fromB_str(filename), 0777, NULL); if (r < 0 && r != UV_EEXIST) { char errmsg[1024] = "Error creating directory: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } uv_fs_req_cleanup(req); return $R_CONT(C_cont, B_None); } // action def mktmpdir(prefix: str=""): $R fileQ_FSD_mktmpdirG_local (fileQ_FS self, $Cont C_cont, B_str prefix) { uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); size_t size = 128; char *tmpdir; int r; while (1) { tmpdir = (char *)acton_malloc(size); size_t requested = size; r = uv_os_tmpdir(tmpdir, &requested); if (r == UV_ENOBUFS) { size = requested; continue; } if (r < 0) { char errmsg[1024] = "Error getting temporary directory: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } break; } const char *cprefix = prefix == B_None ? "" : (const char *)fromB_str(prefix); size_t template_size = strlen(tmpdir) + 1 + strlen(cprefix) + 6 + 1; char *tpl = (char *)acton_malloc(template_size); snprintf(tpl, template_size, "%s/%sXXXXXX", tmpdir, cprefix); r = uv_fs_mkdtemp(get_uv_loop(), req, tpl, NULL); if (r < 0) { char errmsg[1024] = "Error creating temporary directory: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } // libuv stores the resolved path in req->path, not in the template buffer. B_str path = to$str(req->path); uv_fs_req_cleanup(req); return $R_CONT(C_cont, path); } // action def listdir(path: str) -> list[str]: $R fileQ_FSD_listdirG_local (fileQ_FS self, $Cont C_cont, B_str path) { B_SequenceD_list wit = B_SequenceD_listG_witness; uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); B_list res = B_listD_new(0); res->length = 0; int r = uv_fs_scandir(get_uv_loop(), req, (char *)fromB_str(path), 0, NULL); if (r < 0) { char errmsg[1024] = "Error listing directory: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } uv_dirent_t ent; while (uv_fs_scandir_next(req, &ent) != UV_EOF) { wit->$class->append(wit, res, to$str(ent.name)); } uv_fs_req_cleanup(req); return $R_CONT(C_cont, res); } // action def lstat(filename: str) -> FileStat: $R fileQ_FSD_lstatG_local (fileQ_FS self, $Cont C_cont, B_str filename) { uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); int r = uv_fs_lstat(get_uv_loop(), req, (char *)fromB_str(filename), NULL); if (r < 0) { char errmsg[1024] = "Error getting file stat: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE((B_BaseException)B_OSErrorG_new(to$str(errmsg))); } uv_stat_t *stat = (uv_stat_t *)req->ptr; fileQ_FileStat res = fileQ_FileStatG_new(filename, toB_u64(stat->st_dev), toB_u64(stat->st_mode), toB_u64(stat->st_nlink), toB_u64(stat->st_uid), toB_u64(stat->st_gid), toB_u64(stat->st_rdev), toB_u64(stat->st_ino), toB_u64(stat->st_size), toB_u64(stat->st_blksize), toB_u64(stat->st_blocks), toB_u64(stat->st_flags), toB_u64(stat->st_gen), toB_float(stat->st_atim.tv_sec + stat->st_atim.tv_nsec / 1e9), toB_float(stat->st_mtim.tv_sec + stat->st_mtim.tv_nsec / 1e9), toB_float(stat->st_ctim.tv_sec + stat->st_ctim.tv_nsec / 1e9), toB_float(stat->st_birthtim.tv_sec + stat->st_birthtim.tv_nsec / 1e9) ); uv_fs_req_cleanup(req); return $R_CONT(C_cont, res); } // action def rmdir(dirname: str) -> None: $R fileQ_FSD_rmdirG_local (fileQ_FS self, $Cont C_cont, B_str dirname) { uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); int r = uv_fs_rmdir(get_uv_loop(), req, (char *)fromB_str(dirname), NULL); if (r < 0 && r != UV_ENOENT) { char errmsg[1024] = "Error removing directory: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } uv_fs_req_cleanup(req); return $R_CONT(C_cont, B_None); } // action def remove(filename: str) -> None: $R fileQ_FSD_removeG_local (fileQ_FS self, $Cont C_cont, B_str filename) { uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); int r = uv_fs_unlink(get_uv_loop(), req, (char *)fromB_str(filename), NULL); if (r < 0) { char errmsg[1024] = "Error removing file: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } uv_fs_req_cleanup(req); return $R_CONT(C_cont, B_None); } // action def stat(filename: str) -> FileStat: $R fileQ_FSD_statG_local (fileQ_FS self, $Cont C_cont, B_str filename) { uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); int r = uv_fs_stat(get_uv_loop(), req, (char *)fromB_str(filename), NULL); if (r == UV_ENOENT) { uv_fs_req_cleanup(req); $RAISE(((B_BaseException)B_FileNotFoundErrorG_new(filename))); } else if (r < 0) { char errmsg[1024] = "Error getting file stat: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } uv_stat_t *stat = (uv_stat_t *)req->ptr; fileQ_FileStat res = fileQ_FileStatG_new(filename, toB_u64(stat->st_dev), toB_u64(stat->st_mode), toB_u64(stat->st_nlink), toB_u64(stat->st_uid), toB_u64(stat->st_gid), toB_u64(stat->st_rdev), toB_u64(stat->st_ino), toB_u64(stat->st_size), toB_u64(stat->st_blksize), toB_u64(stat->st_blocks), toB_u64(stat->st_flags), toB_u64(stat->st_gen), toB_float(stat->st_atim.tv_sec + stat->st_atim.tv_nsec / 1e9), toB_float(stat->st_mtim.tv_sec + stat->st_mtim.tv_nsec / 1e9), toB_float(stat->st_ctim.tv_sec + stat->st_ctim.tv_nsec / 1e9), toB_float(stat->st_birthtim.tv_sec + stat->st_birthtim.tv_nsec / 1e9) ); uv_fs_req_cleanup(req); return $R_CONT(C_cont, res); } $R fileQ_FSD_tmpdirG_local (fileQ_FS self, $Cont C_cont) { size_t size = 128; int r; while (1) { char *buffer = (char *)acton_malloc(size); size_t requested = size; r = uv_os_tmpdir(buffer, &requested); if (r == UV_ENOBUFS) { size = requested; continue; } if (r < 0) { char errmsg[1024] = "Error getting temporary directory: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } return $R_CONT(C_cont, to$str(buffer)); } } $R fileQ_ReadFileD__open_fileG_local (fileQ_ReadFile self, $Cont c$cont) { pin_actor_affinity(); uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); int r = uv_fs_open(get_uv_loop(), req, (char *)fromB_str(self->filename), UV_FS_O_RDONLY, 0, NULL); if (r == UV_ENOENT) { uv_fs_req_cleanup(req); $RAISE(((B_BaseException)B_FileNotFoundErrorG_new(self->filename))); } else if (r < 0) { char errmsg[1024] = "Error opening file for reading: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } self->_fd = toB_int(r); uv_fs_req_cleanup(req); return $R_CONT(c$cont, B_None); } $R fileQ_ReadFileD__lock_fileG_local (fileQ_ReadFile self, $Cont c$cont) { #if defined(_WIN32) || defined(_WIN64) assert(0 && "fileQ_ReadFileD__lock_fileG_local not implemented on Windows"); #else int r = flock(fromB_int(self->_fd), LOCK_EX + LOCK_NB); if (r < 0) { char errmsg[1024] = "Error locking file: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } #endif return $R_CONT(c$cont, B_None); } $R fileQ_ReadFileD_closeG_local (fileQ_ReadFile self, $Cont c$cont) { uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); int r = uv_fs_close(get_uv_loop(), req, (uv_file)fromB_int(self->_fd), NULL); if (r < 0) { char errmsg[1024] = "Error closing file: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } uv_fs_req_cleanup(req); return $R_CONT(c$cont, B_None); } $R fileQ_ReadFileD_readG_local (fileQ_ReadFile self, $Cont c$cont) { B_SequenceD_list wit = B_SequenceD_listG_witness; uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); char buf[1024] = {0}; uv_buf_t iovec = uv_buf_init(buf, sizeof(buf)); int r = uv_fs_read(get_uv_loop(), req, (uv_file)fromB_int(self->_fd), &iovec, 1, -1, NULL); B_list res = B_listD_new(0); res->length = 0; while (r > 0) { wit->$class->append(wit, res, to$bytesD_len(buf,r)); uv_fs_req_cleanup(req); iovec = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(get_uv_loop(), req, (uv_file)fromB_int(self->_fd), &iovec, 1, -1, NULL); } if (r < 0) { char errmsg[1024] = "Error reading from file: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } uv_fs_req_cleanup(req); B_bytes nullb = to$bytes(""); B_Iterable wit2 = ((B_Iterable)((B_Collection)B_SequenceD_listG_new()->W_Collection)); return $R_CONT(c$cont, nullb->$class->join(nullb,wit2,res)); } $R fileQ_WriteFileD__open_fileG_local (fileQ_WriteFile self, $Cont c$cont) { pin_actor_affinity(); uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); int r = uv_fs_open(get_uv_loop(), req, (char *)fromB_str(self->filename), UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH, NULL); if (r < 0) { char errmsg[1024] = "Error opening file for writing: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } self->_fd = toB_int(r); uv_fs_req_cleanup(req); return $R_CONT(c$cont, B_None); } $R fileQ_WriteFileD__lock_fileG_local (fileQ_WriteFile self, $Cont c$cont) { #if defined(_WIN32) || defined(_WIN64) assert(0 && "fileQ_ReadFileD__lock_fileG_local not implemented on Windows"); #else int r = flock(fromB_int(self->_fd), LOCK_EX + LOCK_NB); if (r < 0) { char errmsg[1024] = "Error locking file: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } #endif return $R_CONT(c$cont, B_None); } $R fileQ_WriteFileD_closeG_local (fileQ_WriteFile self, $Cont c$cont) { uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); int r = uv_fs_close(get_uv_loop(), req, (uv_file)fromB_int(self->_fd), NULL); if (r < 0) { char errmsg[1024] = "Error closing file: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } uv_fs_req_cleanup(req); return $R_CONT(c$cont, B_None); } $R fileQ_WriteFileD_writeG_local (fileQ_WriteFile self, $Cont c$cont, B_bytes data) { uv_fs_t *req = (uv_fs_t *)acton_malloc(sizeof(uv_fs_t)); uv_buf_t buf = uv_buf_init((char *)data->str, data->nbytes); int r = uv_fs_write(get_uv_loop(), req, (uv_file)fromB_int(self->_fd), &buf, 1, 0, NULL); if (r < 0) { char errmsg[1024] = "Error writing to file: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); uv_fs_req_cleanup(req); log_warn(errmsg); $RAISE(((B_BaseException)B_OSErrorG_new(to$str(errmsg)))); } uv_fs_req_cleanup(req); return $R_CONT(c$cont, B_None); } ================================================ FILE: base/src/fs.act ================================================ def path_separator() -> str: """Get the path separator for the current platform.""" # TODO: Implement this function return "/" # The local platform's path separator sep: str = path_separator() def join_path(parts: list[str], path_separator: ?str=None) -> str: """Join path components together""" psep = path_separator if path_separator is not None else sep return psep.join(parts) def glob(pattern: str, path: str, path_separator: ?str=None) -> bool: r"""Match a glob pattern against a file path. Supports the following glob features: - '*': Matches any sequence of characters within a single path segment - '**': Matches any sequence of characters across multiple path segments - '?': Matches any single character - '[abc]': Matches any character in the set (a, b, or c) - '[a-z]': Matches any character in the range (a through z) - '[^abc]': Matches any character NOT in the set (negated character class) - Escaping special characters with backslash - '{a,b,c}': Matches any of the comma-separated terms Args: pattern: The glob pattern to match against path: The file path to match path_separator: The path separator character to use. Defaults to fs.sep. Returns: True if the path matches the pattern, False otherwise """ separator = path_separator if path_separator is not None else sep return _glob_recursive(pattern, 0, path, 0, separator) def _glob_recursive(pattern: str, p_idx: int, path: str, s_idx: int, separator: str) -> bool: """ Recursive helper function for pattern matching. Args: pattern: The glob pattern to match against p_idx: Current index in the pattern path: The file path to match s_idx: Current index in the path separator: The path separator character Returns: True if the remainder of the path matches the remainder of the pattern """ # Base case: if we've reached the end of the pattern if p_idx == len(pattern): # Match if we've also reached the end of the path return s_idx == len(path) # Handle escaping with backslash if p_idx < len(pattern) - 1 and pattern[p_idx] == '\\': # Match the escaped character literally if s_idx < len(path) and pattern[p_idx + 1] == path[s_idx]: return _glob_recursive(pattern, p_idx + 2, path, s_idx + 1, separator) return False # Handle ** wildcard (matches across multiple path segments) if p_idx + 1 < len(pattern) and pattern[p_idx:p_idx+2] == '**': # Check if the next character after ** is a path separator if p_idx + 2 < len(pattern) and pattern[p_idx + 2] == separator: # Handle **/ pattern - match any number of directories next_idx = p_idx + 3 # Skip past **/ # Try to match the rest of the pattern at every position in the path for i in range(s_idx, len(path) + 1): if _glob_recursive(pattern, next_idx, path, i, separator): return True return False else: # Treat ** as * if not followed by separator # Skip both * characters and match any sequence return (_glob_recursive(pattern, p_idx + 2, path, s_idx, separator) or (s_idx < len(path) and _glob_recursive(pattern, p_idx, path, s_idx + 1, separator))) # Handle * wildcard (matches any sequence within a path segment) if pattern[p_idx] == '*': # Find the next path separator in both pattern and path next_sep_pattern = pattern.find(separator, p_idx + 1) if next_sep_pattern == -1: next_sep_pattern = len(pattern) next_sep_path = path.find(separator, s_idx) if next_sep_path == -1: next_sep_path = len(path) # Try to match the rest of the pattern with the rest of the path # but don't cross path separators return (_glob_recursive(pattern, p_idx + 1, path, s_idx, separator) or (s_idx < len(path) and s_idx < next_sep_path and _glob_recursive(pattern, p_idx, path, s_idx + 1, separator))) # Handle ? wildcard (matches any single character) if pattern[p_idx] == '?': return s_idx < len(path) and _glob_recursive(pattern, p_idx + 1, path, s_idx + 1, separator) # Handle character class [...] if pattern[p_idx] == '[' and p_idx < len(pattern) - 1: # Find the closing bracket close_idx = pattern.find(']', p_idx + 1) if close_idx == -1: # If no closing bracket, treat [ as a literal character return s_idx < len(path) and pattern[p_idx] == path[s_idx] and _glob_recursive(pattern, p_idx + 1, path, s_idx + 1, separator) # If we're at the end of the path, no match if s_idx >= len(path): return False # Extract the character class content char_class = pattern[p_idx + 1:close_idx] # Check if it's a negated class negated = char_class.startswith('!') or char_class.startswith('^') if negated: char_class = char_class[1:] # Check if the character matches the class match_found = False # Handle character ranges like a-z i = 0 while i < len(char_class): if i + 2 < len(char_class) and char_class[i + 1] == '-': # It's a range if char_class[i] <= path[s_idx] and path[s_idx] <= char_class[i + 2]: match_found = True break i += 3 else: # It's a single character if char_class[i] == path[s_idx]: match_found = True break i += 1 # If negated, invert the result if negated: match_found = not match_found # If the character matched the class, continue matching if match_found: return _glob_recursive(pattern, close_idx + 1, path, s_idx + 1, separator) return False # Handle brace expansion {a,b,c} if pattern[p_idx] == r'{' and p_idx < len(pattern) - 1: close_idx = pattern.find(r'}', p_idx + 1) if close_idx == -1: # If no closing brace, treat { as a literal character return s_idx < len(path) and pattern[p_idx] == path[s_idx] and _glob_recursive(pattern, p_idx + 1, path, s_idx + 1, separator) # Extract the options options = pattern[p_idx + 1:close_idx].split(',') # Try to match each option with the remainder of the pattern for option in options: # Create a new pattern with this option replacing the brace expression new_pattern = pattern[:p_idx] + option + pattern[close_idx + 1:] if _glob_recursive(new_pattern, 0, path, 0, separator): return True return False # Default case: literal character match return (s_idx < len(path) and pattern[p_idx] == path[s_idx] and _glob_recursive(pattern, p_idx + 1, path, s_idx + 1, separator)) ================================================ FILE: base/src/hash/wyhash.act ================================================ class Hasher(object): _hasher: u64 def __init__(self, seed: u64 = 0): """Initialize a new MD5 hashing context """ self._hasher = 0 # type: u64 self._init(seed) def _init(self, seed: u64) -> None: """C function to reach out to Zig code""" NotImplemented def update(self, data: bytes) -> None: """Update the hasher state with the given chunk of data""" NotImplemented def finalize(self) -> u64: """Finalize and return the hash """ NotImplemented def hash(seed: u64, data: bytes) -> u64: """Compute and return the Wyash digest of the given data""" NotImplemented ================================================ FILE: base/src/hash/wyhash.ext.c ================================================ void hashQ_wyhashQ___ext_init__() {} void *zig_hash_wyhash_init(uint64_t seed); void zig_hash_wyhash_update(void *hasher, B_bytes data); uint64_t zig_hash_wyhash_final(void *hasher); uint64_t zig_hash_wyhash_hash(uint64_t seed, B_bytes data); B_NoneType hashQ_wyhashQ_HasherD__init (hashQ_wyhashQ_Hasher self, B_u64 seed) { self->_hasher = zig_hash_wyhash_init(fromB_u64(seed)); return B_None; } B_NoneType hashQ_wyhashQ_HasherD_update (hashQ_wyhashQ_Hasher self, B_bytes data) { zig_hash_wyhash_update(self->_hasher, data); return B_None; } B_u64 hashQ_wyhashQ_HasherD_finalize (hashQ_wyhashQ_Hasher self) { uint64_t h = zig_hash_wyhash_final(self->_hasher); B_u64 result = toB_u64(h); return result; } uint64_t hashQ_wyhashQ_U_1hash (uint64_t seed, B_bytes data) { uint64_t result = zig_hash_wyhash_hash(seed, data); return result; } ================================================ FILE: base/src/http.act ================================================ import acton.rts import json import logging import net import time responses : dict[int,bytes] = { 100: b"Continue", 101: b"Switching Protocols", 102: b"Processing", 103: b"Early Hints", 200: b"OK", 201: b"Created", 202: b"Accepted", 203: b"Non-Authoritative Information", 204: b"No Content", 205: b"Reset Content", 206: b"Partial Content", 207: b"Multi-Status", 208: b"Already Reported", 226: b"IM Used", 300: b"Multiple Choices", 301: b"Moved Permanently", 302: b"Found", 303: b"See Other", 304: b"Not Modified", 305: b"Use Proxy", 306: b"(Unused)", 307: b"Temporary Redirect", 308: b"Permanent Redirect", 400: b"Bad Request", 401: b"Unauthorized", 402: b"Payment Required", 403: b"Forbidden", 404: b"Not Found", 405: b"Method Not Allowed", 406: b"Not Acceptable", 407: b"Proxy Authentication Required", 408: b"Request Timeout", 409: b"Conflict", 410: b"Gone", 411: b"Length Required", 412: b"Precondition Failed", 413: b"Content Too Large", 414: b"URI Too Long", 415: b"Unsupported Media Type", 416: b"Range Not Satisfiable", 417: b"Expectation Failed", 418: b"(Unused)", 421: b"Misdirected Request", 422: b"Unprocessable Content", 423: b"Locked", 424: b"Failed Dependency", 425: b"Too Early", 426: b"Upgrade Required", 428: b"Precondition Required", 429: b"Too Many Requests", 431: b"Request Header Fields Too Large", 451: b"Unavailable For Legal Reasons", 500: b"Internal Server Error", 501: b"Not Implemented", 502: b"Bad Gateway", 503: b"Service Unavailable", 504: b"Gateway Timeout", 505: b"HTTP Version Not Supported", 506: b"Variant Also Negotiates", 507: b"Insufficient Storage", 508: b"Loop Detected", 510: b"Not Extended (OBSOLETED)", 511: b"Network Authentication Required" } def build_request(host: str, method: bytes, path: bytes, version: bytes, headers: dict[str, str], body: bytes) -> bytes: r = [ method + b" " + path + b" HTTP/" + version ] lheaders: dict[str, str] = {} for k in headers: lheaders[k.lower()] = k if "host" not in lheaders: headers["Host"] = host if "user-agent" not in lheaders: headers["User-Agent"] = "Acton HTTP Client" if "accept" not in lheaders: headers["Accept"] = "*/*" # if "accept-encoding" not in lheaders: # headers["Accept-Encoding"] = "gzip, deflate" if "connection" not in lheaders: headers["Connection"] = "keep-alive" if "content-length" not in lheaders: headers["Content-Length"] = str(len(body)) for k, v in headers.items(): r.append(k.encode() + b": " + v.encode()) r.append(b"\r\n") res = b"\r\n".join(r) if len(body) > 0: res += body return res def build_response(version: bytes, status: int, headers: dict[str, str], body: str): b = body.encode() # TODO: Add Connection? status_line: bytes = b"HTTP/" + version + b" " + str(status).encode() if status in responses: status_line += b" " + responses[status] r = [ status_line ] header_keys = [k.lower() for k in headers.keys()] if "server" not in header_keys: headers["Server"] = "Acton HTTP Server" if "content-type" not in header_keys: headers["Content-Type"] = "text/html; charset=utf-8" if "date" not in header_keys: headers["Date"] = time.now().str_rfc1123() for k, v in headers.items(): if k.lower() == "content-length": # Disregard content-length, we'll compute it from body length continue r.append(k.encode() + b": " + v.encode()) r.append(b"Content-Length: " + str(len(b)).encode()) r.append(b"\r\n") res = b"\r\n".join(r) if len(b) > 0: res += b return res class Message(object): def __init__(self, start_line: bytes, headers: dict[str, str], body: bytes): self.start_line = start_line self.headers = headers self.body = body class Request(object): @property method: str @property path: str @property version: bytes @property headers: dict[str, str] @property body: bytes def __init__(self, method: str, path: str, version: bytes, headers: dict[str, str], body: bytes): self.method = method self.path = path self.version = version self.headers = headers self.body = body def __str__(self): return f"" extension Request(Eq): def __eq__(self, other): return self.method == other.method and self.path == other.path and self.version == other.version and self.headers == other.headers and self.body == other.body class Response(object): @property version: bytes @property status: int @property headers: dict[str, str] @property body: bytes def __init__(self, version: bytes, status: int, headers: dict[str, str], body: bytes) -> None: self.version = version self.status = status self.headers = headers self.body = body def __str__(self) -> str: return f"" def decode_json(self): return json.decode(self.body.decode()) extension Response(Eq): def __eq__(self, other): return self.version == other.version and self.status == other.status and self.headers == other.headers and self.body == other.body def parse_message(i: bytes, log: logging.Logger) -> (?Message, bytes): rs = i.split(b"\r\n\r\n", 1) if len(rs) == 1: return None, i else: header_lines = rs[0].split(b"\r\n", None) start_line = header_lines[0].rstrip(b"\r\n") headers : dict[str, str] = {} for hline in header_lines[1:]: hv = hline.split(b":", 1) if len(hv) == 1: # TODO: silently ignore or explicitly throw error or something? pass else: try: hname = hv[0].decode().strip(" ").lower() headers[hname] = hv[1].decode().strip(" ") except ValueError: log.debug("Invalid header") return None, i # TODO: why do we have to init body & rest here? seems we segfault otherwise... body = b"" rest = b"" if "content-length" in headers: clen = int(headers["content-length"].strip(" ")) log.trace(f"Got content-length in headers, expecting {clen} bytes", None) if len(rs[1]) >= clen: body = rs[1][:clen] rest = rs[1][clen:] log.trace("Enough data to reach content-length!", None) msg = Message(start_line, headers, body) return msg, rest else: log.trace("Not enough data to reach content-length", None) return None, i elif "transfer-encoding" in headers: tenc = set(headers["transfer-encoding"].strip(" ").split(",", None)) if "chunked" in tenc: log.trace("Got chunked transfer-encoding", None) reached_end = False rest = rs[1] log.trace(f"Rest: {str(rest)}", None) body = b"" while not reached_end: maybe_chunk = rest.split(b"\r\n", 1) if len(maybe_chunk) == 1: log.trace("No chunk header found", None) return None, i elif len(maybe_chunk) == 2: chunk_header = maybe_chunk[0].strip(b"\r\n") if chunk_header == b"": log.trace("Empty chunk header", None) return None, i try: chunk_header_str = chunk_header.decode() except ValueError: log.debug("Invalid chunk header") return None, i else: rest = maybe_chunk[1] log.trace(f"Chunk header: {chunk_header[:20]}", None) try: clen = int(chunk_header_str, 16) log.trace(f"Chunk length: {clen}", None) except ValueError: log.trace("Chunk header not a length", None) else: if len(rest) >= clen: gap = rest[clen-10:clen+10] chunk = rest[:clen] log.trace(f"Read chunk: {str(chunk)}", None) rest = rest[clen:] if len(rest) < 2 and rest[0:2] != b"\r\n": log.trace("Could not find chunk end marker", None) return None, i rest = rest[2:] #log.trace("Enough data to reach end of chunk", None) chunk_preview = str(chunk[-5:]) rest_preview = str(rest[:5]) log.trace(f"Enough data to reach end of chunk, chunk gap: {chunk_preview}|{rest_preview}", None) body += chunk if clen == 0: reached_end = True msg = Message(start_line, headers, body) log.trace("Reached end of chunked message", None) return msg, rest else: log.trace("Not enough data to reach end of chunk", None) return None, i else: # TODO: InternalError? raise ValueError("Unreachable") else: body = b"" rest = rs[1] msg = Message(start_line, headers, body) return msg, rest return None, i def parse_request(i: bytes, log: logging.Logger) -> (?Request, bytes): msg, rest = parse_message(i, log) if msg is not None: slparts = msg.start_line.split(b" ", None) if len(slparts) != 3: # HTTP request must have exactly 3 parts: METHOD PATH HTTP/VERSION return None, b"" try: method = slparts[0].decode() path = slparts[1].decode() except ValueError: log.debug("Invalid method/path") return None, b"" else: verparts = slparts[2].split(b"/", 1) if len(verparts) != 2: # invalid request # TODO: actually HTTP 0.9 might only have 2 parts, but we don't support that return None, b"" version = verparts[1] if version != b"1.1" and version != b"1.0": return None, b"" req = Request(method, path, version, msg.headers, msg.body) return req, rest return None, i def parse_response(i: bytes, log: logging.Logger) -> (?Response, bytes): msg, rest = parse_message(i, log) if msg is not None: slparts = msg.start_line.split(b" ", None) if len(slparts) < 2: # HTTP response must have at least 2 parts: HTTP/VERSION STATUS_CODE [REASON_PHRASE] return None, b"" verparts = slparts[0].split(b"/", 1) if len(verparts) != 2: # invalid request # TODO: actually HTTP 0.9 might only have 2 parts, but we don't support that return None, b"" version = verparts[1] if version != b"1.1" and version != b"1.0": log.trace("Invalid HTTP version", None) return None, b"" try: status = int(slparts[1].decode()) except ValueError: log.debug("Invalid status") return None, b"" else: resp = Response(version, status, msg.headers, msg.body) return resp, b"" return None, i actor Server(conn: net.TCPListenConnection, on_accept: action(Server) -> None, log_handler: ?logging.Handler): """Server serves a single client connection""" _log = logging.Logger(log_handler) var on_request_cb: ?action(Server, Request, action(int, dict[str, str], str) -> None) -> None = None var on_error_cb: ?action(Server, str) -> None = None var version: ?bytes = None var buf = b"" var close_connection: bool = True var query_count: u64 = 0 var response_count: u64 = 0 var outstanding_requests: dict[u64, Response] = {} def cb_install(new_on_request: action(Server, Request, action(int, dict[str, str], str) -> None) -> None, new_on_error: action(Server, str) -> None): on_request_cb = new_on_request on_error_cb = new_on_error if buf != b"": req, buf = parse_request(buf, _log) def on_conn_receive(conn_obj, data: bytes) -> None: # TODO: do we really need a buf? if on_request_cb is None: buf += data return None else: if buf != b"": data = buf + data req, buf = parse_request(data, _log) if req is not None: if version is None: version = req.version elif version is not None and version != req.version: _log.debug("Version mismatch", None) conn.close() if version is not None and version == b"1.0": if "connection" in req.headers: if req.headers["connection"] == "close": _log.debug("HTTP 1.0 with connection: close, closing connection...", None) close_connection = True else: _log.debug("HTTP 1.0 with connection header, not closing connection...", None) _log.trace("connection header", {"connection": req.headers["connection"]}) else: close_connection = True elif version is not None and version == b"1.1": if "connection" in req.headers and req.headers["connection"] == "close": _log.debug("HTTP 1.1, closing connection...", None) close_connection = True else: close_connection = False query_count += 1 def respond(status_code: int, headers: dict[str, str], body: str): _log.trace("Going to respond with query id", {"query_count": query_count}) if query_count == response_count + 1: # In order, send response immediately _log.trace("Sending response immediately", None) send_response(status_code, headers, body) response_count += 1 else: # Buffer up response _log.trace("Buffering response", None) # TODO: actually implement buffering? #outstanding_requests[query_count] = Response("GABBA", version, status_code, headers, body.encode()) if on_request_cb is not None: response = on_request_cb(self, req, respond) if response is not None: _log.trace("Sending response immediately", None) else: _log.trace("Async response", None) else: _log.notice("No on_request callback set", None) def on_conn_error(conn, error): # TODO: the conn should really be in here, but type error!? _log.trace(f"There was an error: {str(error)} from: {str("")}", None) def close(): conn.close() def send_response(status_code: int, headers: dict[str, str], data: str): if version is not None: res = build_response(version, status_code, headers, data) conn.write(res) if close_connection: conn.close() actor TLSServer(conn: net.TLSListenConnection, on_accept: action(TLSServer) -> None, log_handler: ?logging.Handler): """Server serves a single TLS client connection""" _log = logging.Logger(log_handler) var on_request_cb: ?action(TLSServer, Request, action(int, dict[str, str], str) -> None) -> None = None var on_error_cb: ?action(TLSServer, str) -> None = None var version: ?bytes = None var buf = b"" var close_connection: bool = True var query_count: u64 = 0 var response_count: u64 = 0 var outstanding_requests: dict[u64, Response] = {} def cb_install(new_on_request: action(TLSServer, Request, action(int, dict[str, str], str) -> None) -> None, new_on_error: action(TLSServer, str) -> None): on_request_cb = new_on_request on_error_cb = new_on_error if buf != b"": req, buf = parse_request(buf, _log) def on_conn_receive(conn_obj, data: bytes) -> None: # TODO: do we really need a buf? if on_request_cb is None: buf += data return None else: if buf != b"": data = buf + data req, buf = parse_request(data, _log) if req is not None: if version is None: version = req.version elif version is not None and version != req.version: _log.debug("Version mismatch", None) conn.close() if version is not None and version == b"1.0": if "connection" in req.headers: if req.headers["connection"] == "close": _log.debug("HTTP 1.0 with connection: close, closing connection...", None) close_connection = True else: _log.debug("HTTP 1.0 with connection header, not closing connection...", None) _log.trace("connection header", {"connection": req.headers["connection"]}) else: close_connection = True elif version is not None and version == b"1.1": if "connection" in req.headers and req.headers["connection"] == "close": _log.debug("HTTP 1.1, closing connection...", None) close_connection = True else: close_connection = False query_count += 1 def respond(status_code: int, headers: dict[str, str], body: str): _log.trace("Going to respond with query id", {"query_count": query_count}) if query_count == response_count + 1: # In order, send response immediately _log.trace("Sending response immediately", None) send_response(status_code, headers, body) response_count += 1 else: # Buffer up response _log.trace("Buffering response", None) # TODO: actually implement buffering? #outstanding_requests[query_count] = Response("GABBA", version, status_code, headers, body.encode()) if on_request_cb is not None: response = on_request_cb(self, req, respond) if response is not None: _log.trace("Sending response immediately", None) else: _log.trace("Async response", None) else: _log.notice("No on_request callback set", None) def on_conn_error(conn, error): # TODO: the conn should really be in here, but type error!? _log.trace(f"There was an error: {str(error)} from: {str("")}", None) def close(): conn.close() def send_response(status_code: int, headers: dict[str, str], data: str): if version is not None: res = build_response(version, status_code, headers, data) conn.write(res) if close_connection: conn.close() # TODO: change port to u16, when u16 has a sub-type relationship to int # TODO: the on_listen_error default should be some action that just automatically retries with a backoff # TODO: add restart method to restart the listener actor Listener(cap: net.TCPListenCap, address: str, port: int, on_accept: action(Server) -> None, on_listen_error: ?action(net.TCPListener, str) -> None = None, log_handler: ?logging.Handler = None): """HTTP Server Listener""" _log = logging.Logger(log_handler) var bufs = [] def on_conn_listen(listener, error): if error is not None: _log.notice("There was an error with the listener socket", {"error": error}) if on_listen_error is not None: on_listen_error(listener, error) def on_listener_accept(conn): s = Server(conn, on_accept, log_handler) await async on_accept(s) await async conn.cb_install(s.on_conn_receive, s.on_conn_error, None) var _listener = net.TCPListener(cap, address, port, on_conn_listen, on_listener_accept) # TODO: change port to u16, when u16 has a sub-type relationship to int # TODO: the on_listen_error default should be some action that just automatically retries with a backoff # TODO: add restart method to restart the listener actor TLSListener(cap: net.TCPListenCap, address: str, port: int, cert_pem: bytes, key_pem: bytes, on_accept: action(TLSServer) -> None, on_listen_error: ?action(net.TLSListener, str) -> None = None, log_handler: ?logging.Handler = None): """HTTPS Server Listener""" _log = logging.Logger(log_handler) var bufs = [] def on_conn_listen(listener, error): if error is not None: _log.notice("There was an error with the listener socket", {"error": error}) if on_listen_error is not None: on_listen_error(listener, error) def on_listener_accept(conn): s = TLSServer(conn, on_accept, log_handler) await async on_accept(s) await async conn.cb_install(s.on_conn_receive, s.on_conn_error, None) var _listener = net.TLSListener(cap, address, port, cert_pem, key_pem, on_conn_listen, on_listener_accept) # TODO: change port to u16, when u16 has a sub-type relationship to int actor Client(cap: net.TCPConnectCap, address: str, on_connect: action(Client) -> None, on_error: action(Client, str) -> None, scheme: str="https", port: ?int=None, tls_verify: bool=True, log_handler: ?logging.Handler): """HTTP(S) Client scheme is either 'http' or 'https', the default is 'https' port is optional, if not provided, it will be inferred from the scheme where http=80 and https=443 """ _log = logging.Logger(log_handler) var _on_response: list[(bytes, action(Client, Response) -> None)] = [] var version: ?bytes = None var buf = b"" var close_connection: bool = True var tcp_conn: ?net.TCPConnection = None var tls_conn: ?net.TLSConnection = None def _connect(): if scheme == "http": _log.verbose("Using http scheme and port 80", None) tcp_port = port if port is not None else 80 tcp_conn = net.TCPConnection(cap, address, tcp_port, _on_tcp_connect, _on_tcp_receive, _on_tcp_error, None, connect_timeout=10.0) elif scheme == "https": _log.verbose("Using https scheme and port 443", None) tls_port = port if port is not None else 443 tls_conn = net.TLSConnection(cap, address, tls_port, _on_tls_connect, _on_tls_receive, _on_tls_error, None, tls_verify) else: raise ValueError(f"Only http and https schemes are supported. Unsupported scheme: {scheme}") def _on_conn_connect(): # If there are outstanding requests, it probably means we were for r in _on_response: _conn_write(r.0) await async on_connect(self) def _on_tcp_connect(conn: net.TCPConnection) -> None: _on_conn_connect() def _on_tls_connect(conn: net.TLSConnection) -> None: _on_conn_connect() def _on_tcp_receive(conn: net.TCPConnection, data: bytes) -> None: _on_con_receive(data) def _on_tls_receive(conn: net.TLSConnection, data: bytes) -> None: _on_con_receive(data) def _on_con_receive(data: bytes) -> None: buf += data _log.debug("Received data", {"bytes": len(data)}) #_log.trace("Received data", {"data": data}) while True: r, buf = parse_response(buf, _log) if r is not None: if "connection" in r.headers and r.headers["connection"] == "close": close_connection = True _conn_close() _log.debug("Closing TCP connection due to header: Connection: close", None) _connect() if len(_on_response) == 0: _log.notice("Data received with no on_response callback set", None) break outreq = _on_response[0] del _on_response[0] cb = outreq.1 await async cb(self, r) else: break def _on_tcp_error(conn: net.TCPConnection, error: str) -> None: _on_con_error(error) def _on_tls_error(conn: net.TLSConnection, error: str) -> None: _on_con_error(error) def _on_con_error(error: str) -> None: on_error(self, error) def _conn_close() -> None: if tcp_conn is not None: def _noop(c): pass tcp_conn.close(_noop) elif tls_conn is not None: def _noop(c): pass tls_conn.close(_noop) def _conn_write(data: bytes) -> None: _log.trace("Sending data", {"data": data}) if tcp_conn is not None: tcp_conn.write(data) elif tls_conn is not None: tls_conn.write(data) def close(): _conn_close() # HTTP methods def get(path: str, on_response: action(Client, Response) -> None, headers: dict[str, str] = {}): req = build_request(address, b"GET", path.encode(), b"1.1", headers, b"") _log.debug("Sending request", {"method": "GET", "path": path}) _on_response.append((req, on_response)) _conn_write(req) def head(path: str, on_response: action(Client, Response) -> None, headers: dict[str, str] = {}): req = build_request(address, b"HEAD", path.encode(), b"1.1", headers, b"") _log.debug("Sending request", {"method": "HEAD", "path": path}) _on_response.append((req, on_response)) _conn_write(req) def post(path: str, body: bytes, on_response: action(Client, Response) -> None, headers: dict[str, str] = {}): if "Content-Type" not in headers: headers["Content-Type"] = "application/x-www-form-urlencoded" req = build_request(address, b"POST", path.encode(), b"1.1", headers, body) _log.debug("Sending request", {"method": "POST", "path": path}) _on_response.append((req, on_response)) _conn_write(req) def put(path: str, body: bytes, on_response: action(Client, Response) -> None, headers: dict[str, str] = {}): req = build_request(address, b"PUT", path.encode(), b"1.1", headers, body) _log.debug("Sending request", {"method": "PUT", "path": path}) _on_response.append((req, on_response)) _conn_write(req) def delete(path: str, on_response: action(Client, Response) -> None, headers: dict[str, str] = {}): req = build_request(address, b"DELETE", path.encode(), b"1.1", headers, b"") _log.debug("Sending request", {"method": "DELETE", "path": path}) _on_response.append((req, on_response)) _conn_write(req) _connect() ================================================ FILE: base/src/json.act ================================================ actor Json(): """JSON actor for distributed async processing This actor can be used to process JSON data in a asynchronous distributed fashion. The `encode` and `decode` methods are identical to the free `encode` and `decode` functions in this module but by being wrapped in an actor, they can be: - called asynchronously - the Json actor can be run by a different worker Thus, by using one or multiple Json actors, the work of encoding or decoding JSON can be distributed across multiple actors / workers / CPUs. """ action def decode(data: str) -> dict[str, ?value]: return decode(data) action def decode_list(data: str) -> list[?value]: return decode_list(data) action def encode(data: dict[str, ?value]) -> str: return encode(data) action def encode_list(data: list[?value], pretty=False) -> str: return encode_list(data, pretty) def decode(data: str) -> dict[str, ?value]: """Decode a JSON string into a dictionary of values """ NotImplemented def decode_list(data: str) -> list[?value]: """Decode a JSON string (containing an array) into a list of values """ NotImplemented def encode(data: dict[str, ?value], pretty=False) -> str: """Encode a dictionary into a JSON string """ NotImplemented def encode_list(data: list[?value], pretty=False) -> str: """Encode a list into a JSON array string """ NotImplemented ================================================ FILE: base/src/json.ext.c ================================================ #include "../rts/io.h" #include "../rts/log.h" #include "yyjson.h" static void *my_malloc(void *ctx, size_t size) { return acton_malloc(size); } static void *my_realloc(void *ctx, void *ptr, size_t size) { return acton_realloc(ptr, size); } static void my_free(void *ctx, void *ptr) { acton_free(ptr); } yyjson_alc acton_alc; void jsonQ___ext_init__() { acton_alc.malloc = my_malloc; acton_alc.realloc = my_realloc; acton_alc.free = my_free; } void jsonQ_encode_list_into(yyjson_mut_doc *doc, yyjson_mut_val *node, B_list data); void jsonQ_encode_dict(yyjson_mut_doc *doc, yyjson_mut_val *node, B_dict data) { B_IteratorD_dict_items iter = $NEW(B_IteratorD_dict_items, data); B_tuple item; for (int i=0; i < data->numelements; i++) { item = (B_tuple)iter->$class->__next__(iter); char *key = (char *)fromB_str((B_str)item->components[0]); B_value v = item->components[1]; if (v) { switch (v->$class->$class_id) { case INT_ID:; yyjson_mut_obj_add_int(doc, node, key, fromB_int((B_int)v)); break; case FLOAT_ID:; yyjson_mut_obj_add_real(doc, node, key, fromB_float((B_float)v)); break; case BOOL_ID:; yyjson_mut_obj_add_bool(doc, node, key, fromB_bool((B_bool)v)); break; case STR_ID:; yyjson_mut_obj_add_str(doc, node, key, (char *)fromB_str((B_str)v)); break; case LIST_ID:; yyjson_mut_val *l = yyjson_mut_arr(doc); yyjson_mut_obj_add_val(doc, node, key, l); jsonQ_encode_list_into(doc, l, (B_list)v); break; case DICT_ID:; yyjson_mut_val *d = yyjson_mut_obj(doc); yyjson_mut_obj_add_val(doc, node, key, d); jsonQ_encode_dict(doc, d, (B_dict)v); break; case I8_ID:; yyjson_mut_obj_add_int(doc, node, key, ((B_i8)v)->val); break; case I16_ID:; yyjson_mut_obj_add_int(doc, node, key, ((B_i16)v)->val); break; case I32_ID:; yyjson_mut_obj_add_int(doc, node, key, ((B_i32)v)->val); break; case I64_ID:; yyjson_mut_obj_add_int(doc, node, key, ((B_int)v)->val); break; case U1_ID:; yyjson_mut_obj_add_uint(doc, node, key, ((B_u1)v)->val); break; case U8_ID:; yyjson_mut_obj_add_uint(doc, node, key, ((B_u8)v)->val); break; case U16_ID:; yyjson_mut_obj_add_uint(doc, node, key, ((B_u16)v)->val); break; case U32_ID:; yyjson_mut_obj_add_uint(doc, node, key, ((B_u32)v)->val); break; case U64_ID:; yyjson_mut_obj_add_uint(doc, node, key, ((B_u64)v)->val); break; default:; // TODO: hmm, at least handle all builtin types? and that's it, // maybe? like we really shouldn't accept user-defined types // here, just throw an exception? or when we have unions, just // accept union of the types we support $RAISE(((B_BaseException)B_ValueErrorG_new($FORMAT("jsonQ_encode_dict: for key %s unknown type: %s", key, v->$class->$GCINFO)))); } } else { yyjson_mut_obj_add_null(doc, node, key); } } } void jsonQ_encode_list_into(yyjson_mut_doc *doc, yyjson_mut_val *node, B_list data) { for (int i = 0; i < data->length; i++) { B_value v = data->data[i]; if (v) { switch (v->$class->$class_id) { case INT_ID:; yyjson_mut_arr_add_int(doc, node, fromB_int((B_int)v)); break; case FLOAT_ID:; yyjson_mut_arr_add_real(doc, node, fromB_float((B_float)v)); break; case BOOL_ID:; yyjson_mut_arr_add_bool(doc, node, fromB_bool((B_bool)v)); break; case STR_ID:; yyjson_mut_arr_add_str(doc, node, (char *)fromB_str((B_str)v)); break; case LIST_ID:; yyjson_mut_val *l = yyjson_mut_arr_add_arr(doc, node); if (l) { jsonQ_encode_list_into(doc, l, (B_list)v); } else { // TODO: raise exception } break; case DICT_ID:; yyjson_mut_val *d = yyjson_mut_arr_add_obj(doc, node); if (d) { jsonQ_encode_dict(doc, d, (B_dict)v); } else { // TODO: raise exception } break; case I8_ID:; yyjson_mut_arr_add_int(doc, node, ((B_i8)v)->val); break; case I16_ID:; yyjson_mut_arr_add_int(doc, node, ((B_i16)v)->val); break; case I32_ID:; yyjson_mut_arr_add_int(doc, node, ((B_i32)v)->val); break; case I64_ID:; yyjson_mut_arr_add_int(doc, node, ((B_int)v)->val); break; case U1_ID:; yyjson_mut_arr_add_uint(doc, node, ((B_u1)v)->val); break; case U8_ID:; yyjson_mut_arr_add_uint(doc, node, ((B_u8)v)->val); break; case U16_ID:; yyjson_mut_arr_add_uint(doc, node, ((B_u16)v)->val); break; case U32_ID:; yyjson_mut_arr_add_uint(doc, node, ((B_u32)v)->val); break; case U64_ID:; yyjson_mut_arr_add_uint(doc, node, ((B_u64)v)->val); break; default:; // TODO: hmm, at least handle all builtin types? and that's it, // maybe? like we really shouldn't accept user-defined types // here, just throw an exception? or when we have unions, just // accept union of the types we support $RAISE(((B_BaseException)B_ValueErrorG_new($FORMAT("jsonQ_encode_list: unknown type: %s", v->$class->$GCINFO)))); } } else { yyjson_mut_arr_add_null(doc, node); } } } B_list jsonQ_decode_arr(yyjson_val *); B_dict jsonQ_decode_obj(yyjson_val *obj) { B_Hashable wit = (B_Hashable)B_HashableD_strG_witness; B_dict res = $NEW(B_dict, wit, NULL, NULL); yyjson_obj_iter iter; yyjson_obj_iter_init(obj, &iter); yyjson_val *key, *val; while ((key = yyjson_obj_iter_next(&iter))) { val = yyjson_obj_iter_get_val(key); switch (yyjson_get_type(val)) { case YYJSON_TYPE_NONE:; break; case YYJSON_TYPE_NULL:; B_dictD_setitem(res, wit, to$str(yyjson_get_str(key)), B_None); break; case YYJSON_TYPE_BOOL:; B_dictD_setitem(res, wit, to$str(yyjson_get_str(key)), toB_bool(yyjson_get_bool(val))); break; case YYJSON_TYPE_NUM:; switch (yyjson_get_subtype(val)) { case YYJSON_SUBTYPE_UINT:; B_dictD_setitem(res, wit, to$str(yyjson_get_str(key)), toB_int(yyjson_get_int(val))); break; case YYJSON_SUBTYPE_SINT:; B_dictD_setitem(res, wit, to$str(yyjson_get_str(key)), toB_int(yyjson_get_int(val))); break; case YYJSON_SUBTYPE_REAL:; B_dictD_setitem(res, wit, to$str(yyjson_get_str(key)), to$float(yyjson_get_real(val))); break; } break; case YYJSON_TYPE_STR:; B_dictD_setitem(res, wit, to$str(yyjson_get_str(key)), to$str(yyjson_get_str(val))); break; case YYJSON_TYPE_ARR:; B_list l = jsonQ_decode_arr(val); B_dictD_setitem(res, wit, to$str(yyjson_get_str(key)), l); break; case YYJSON_TYPE_OBJ:; B_dict d = jsonQ_decode_obj(val); B_dictD_setitem(res, wit, to$str(yyjson_get_str(key)), d); break; default:; // unreachable $RAISE(((B_BaseException)B_ValueErrorG_new($FORMAT("jsonQ_encode_list: unknown type: %d", yyjson_get_type(val))))); } } return res; } B_list jsonQ_decode_arr(yyjson_val *arr) { B_SequenceD_list wit = B_SequenceD_listG_witness; B_list res = B_listG_new(NULL, NULL); yyjson_val *val; yyjson_arr_iter iter; yyjson_arr_iter_init(arr, &iter); while ((val = yyjson_arr_iter_next(&iter))) { switch (yyjson_get_type(val)) { case YYJSON_TYPE_NONE: break; case YYJSON_TYPE_NULL:; wit->$class->append(wit, res, B_None); break; case YYJSON_TYPE_BOOL:; wit->$class->append(wit, res, toB_bool(yyjson_get_bool(val))); break; case YYJSON_TYPE_NUM:; switch (yyjson_get_subtype(val)) { case YYJSON_SUBTYPE_UINT:; wit->$class->append(wit, res, toB_int(yyjson_get_int(val))); break; case YYJSON_SUBTYPE_SINT:; wit->$class->append(wit, res, toB_int(yyjson_get_int(val))); break; case YYJSON_SUBTYPE_REAL:; wit->$class->append(wit, res, to$float(yyjson_get_real(val))); break; } break; case YYJSON_TYPE_STR:; wit->$class->append(wit, res, to$str(yyjson_get_str(val))); break; case YYJSON_TYPE_ARR:; B_list l = jsonQ_decode_arr(val); wit->$class->append(wit, res, l); break; case YYJSON_TYPE_OBJ:; B_dict d = jsonQ_decode_obj(val); wit->$class->append(wit, res, d); break; default:; // TODO: just handle all types? $RAISE(((B_BaseException)B_ValueErrorG_new($FORMAT("jsonQ_decode_arr: unknown type: %d", yyjson_get_type(val))))); } } return res; } B_dict jsonQ_decode (B_str data) { // Read JSON and get root yyjson_read_err err; yyjson_doc *doc = yyjson_read_opts(fromB_str(data), strlen(fromB_str(data)), 0, &acton_alc, &err); yyjson_val *root = yyjson_doc_get_root(doc); B_dict res = $NEW(B_dict,(B_Hashable)B_HashableD_strG_witness,NULL,NULL); // Iterate over the root object if (doc) { yyjson_val *obj = yyjson_doc_get_root(doc); res = jsonQ_decode_obj(obj); } else { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "JSON parsing error: %s (%u) at position %ld", err.msg, err.code, err.pos); $RAISE((B_BaseException)$NEW(B_ValueError, to$str(errmsg))); } yyjson_doc_free(doc); return res; } B_list jsonQ_decode_list (B_str data) { // Read JSON and get root yyjson_read_err err; yyjson_doc *doc = yyjson_read_opts(fromB_str(data), strlen(fromB_str(data)), 0, &acton_alc, &err); if (!doc) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "JSON parsing error: %s (%u) at position %ld", err.msg, err.code, err.pos); $RAISE((B_BaseException)$NEW(B_ValueError, to$str(errmsg))); } yyjson_val *root = yyjson_doc_get_root(doc); if (yyjson_get_type(root) != YYJSON_TYPE_ARR) { yyjson_doc_free(doc); $RAISE(((B_BaseException)B_ValueErrorG_new(to$str("JSON root is not an array")))); } B_list res = jsonQ_decode_arr(root); yyjson_doc_free(doc); return res; } B_str jsonQ_encode (B_dict data, B_bool pretty) { if (pretty == NULL) pretty = B_False; // Create JSON document yyjson_mut_doc *doc = yyjson_mut_doc_new(&acton_alc); yyjson_mut_val *root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); jsonQ_encode_dict(doc, root, data); yyjson_write_err err; int flags = 0; if (pretty == B_True) flags += YYJSON_WRITE_PRETTY; char *json = yyjson_mut_write_opts(doc, flags, &acton_alc, NULL, &err); //yyjson_doc_free(doc); return to$str(json); } B_str jsonQ_encode_list (B_list data, B_bool pretty) { if (pretty == NULL) pretty = B_False; // Create JSON document yyjson_mut_doc *doc = yyjson_mut_doc_new(&acton_alc); yyjson_mut_val *root = yyjson_mut_arr(doc); yyjson_mut_doc_set_root(doc, root); jsonQ_encode_list_into(doc, root, data); yyjson_write_err err; int flags = 0; if (pretty == B_True) flags += YYJSON_WRITE_PRETTY; char *json = yyjson_mut_write_opts(doc, flags, &acton_alc, NULL, &err); //yyjson_doc_free(doc); return to$str(json); } ================================================ FILE: base/src/logging.act ================================================ r"""Advanced actor based logging There are three main components to the logging system: - Loggers: each actor that wants to emit logs creates its own Logger object - Handlers: the Logger object sends log messages to an Handler actor - Sinks: Handlers sends log messages to a Sink actor for final output Together, these components form a chain of actors that can be used to propagate, filter, transform and output log messages. The Logger object is the main interface for emitting log messages. Each actor that wants to emit log messages needs to create at least one Logger object. The Logger forwards messages to a log Handler. It provides convenience methods for each log level, e.g. `.info(msg, data)` or `.error(msg, data)`. Each of these methods takes a log message and an optional data dictionary for structured data, keyed by strings. It is also possible to only log structured data. Not all destination Sinks support structured data, in which case the structured data is flattened into a string representation. The Handler receives log messages from Loggers. It can forward the messages to a parent handler, making it possible to build a hierarchy of Handlers. At the top of the hierarchy is the root Handler, which does not have a parent Handler. For output, the Handler can also send the log messages to one or more Sinks. Each Handler has an associated output log level and only log messages of that level or higher importance will be propagated. By using a single log Handler for a group of related actors, the log level can be controlled for all actors in the group with a single setting. Sinks receives log messages from Handlers and are responsible for finally outputting the log messages. For example, the StdoutSink writes log messages to the stdout while FileSink can write log messages to a file. Here's an illustrative example of Logger, Handler and Sink hierarchy: .------------. .---->| SyslogSink | .---------. | '------------' | Handler |---------+ '---------' | .------------. ^ ^ '---->| FileSink | | | '------------' | '----------. | | .---------. .---------. .------------. | Handler | | Handler |-->| StdoutSink | '---------' '---------' '------------' ^^^ ^^^ ^^^ ||| ||| ||'----------. ||| ||| |'----------.| ||| ||| '----------.|| ||| ||| ||| .----------. .----------. .----------. | Actor w/ |. | Actor w/ |. | Actor w/ |. | Logger ||. | Logger ||. | Logger ||. '----------'|| '----------'|| '----------'|| '----------'| '----------'| '----------'| '----------' '----------' '----------' For a simple application and in fact many large programs too, a single root Handler and a Sink or two is enough. Log Messages include the originating actor class and actor id. The Logger can be given a name, which can be useful if there is a human friendly name to the actor instance like "HTTP Worker 3". The path taken by the message through the Handler hierarchy is recorded and is also included in the outputted form. .------------------------------- date | .------------ time | | .--------- timezone offset | | | .--- level | | | | vvvvvvvvvv vvvvvvvvvvvvvvvvvv vv vvvvv 2023-09-11T22:23:39.185147227+02 DEBUG MyApp>http>HTTP Worker 3: my_app.http.server[-17]: Received query - {'method': 'GET', 'path': '/foo'} ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | | | handler path -----' | | | | actor class -------------------------------' | | | actor id --------------------------------------------------' | | log message --------------------------------------------------------' | structured data -------------------------------------------------------------------------' """ import file import time # Log levels UNSET, OFF, EMERGENCY, ALERT, CRITICAL, ERR, WARNING, INFO, NOTICE, DEBUG, VERBOSE, TRACE, ALL : int UNSET = -2 OFF = -1 EMERGENCY = 0 ALERT = 1 CRITICAL = 2 # TODO: 'ERROR' name conflicts on Windows as it is some macro on C-level ERR = 3 WARNING = 4 INFO = 5 NOTICE = 6 DEBUG = 7 VERBOSE = 8 TRACE = 9 ALL = 999 lvl_names = { EMERGENCY : 'EMERG', ALERT : 'ALERT', CRITICAL : 'CRIT', ERR : 'ERROR', WARNING : 'WARN', INFO : 'INFO', NOTICE : 'NOTICE', DEBUG : 'DEBUG', VERBOSE : 'VERB', TRACE : 'TRACE', } class Message(): """A log message """ ts: time.DateTime level: int actor_class: str actor_id: int name: ?str path: list[str] msg: ?str data: ?dict[str, ?value] def __init__(self, level: int, path: list[str], name: ?str, msg: ?str, data: ?dict[str, ?value]): self.ts = time.now() self.level = level self.name = name self.path = path self.msg = msg self.data = data self.actor_class = "" self.actor_id = 0 self.actor_class = self._get_actor_class() self.actor_id = self._get_actor_id() def _get_actor_class(self) -> str: NotImplemented def _get_actor_id(self) -> int: NotImplemented class Formatter: def __init__(self): pass def format(self, m: Message) -> ?str: raise NotImplementedError("") class DefaultFormatter(Formatter): def format(self, m: Message) -> ?str: lvl_name = lvl_names[m.level] msg = m.msg data = m.data if msg is None and data is None: return str_path = '>'.join(m.path) text = f"{str(m.ts)} {lvl_name:<7}" if len(str_path) > 0: text += str_path + ": " text += f"{m.actor_class}[{str(m.actor_id)}]: " if msg is not None: text += msg return text class Sink(object): """A log sink """ formatter: Formatter def __init__(self): self.formatter = DefaultFormatter() def set_formatter(self, formatter: Formatter): self.formatter = formatter proc def handle(self, m: Message): raise NotImplementedError("") class StdoutSink(Sink): """Log sink that writes to stdout """ def handle(self, m: Message): text = self.formatter.format(m) if text is not None: data = m.data if data is not None: text += " - " + str(data) print(text) class ConsoleSink(Sink): """Log sink that writes to the console, i.e. stderr """ def handle(self, m: Message): text = self.formatter.format(m) if text is not None: data = m.data if data is not None: text += " - " + str(data) print(text, err=True) # Untested and doesn't work yet? # TODO: implement this! #class FileSink(Sink): # filename: str # fh: file.WriteFile # # def __init__(self, cap: file.WriteFileCap, filename: str): # self.formatter = DefaultFormatter() # self.filename = filename # self.f = file.WriteFile(cap, filename) # # def handle(self, m: Message): # text = self.formatter.format(m) # self.fh.write(text.encode()) actor Handler(name: ?str): var parent_handler: ?Handler = None var sinks: list[Sink] = [] var output_level: int = ALL def add_sink(sink: Sink): sinks.append(sink) def handle(m: Message): if m.level <= output_level: if name is not None: m.path.insert(0, name) if parent_handler is not None: parent_handler.handle(m) for sink in sinks: sink.handle(m) def set_handler(h: Handler): parent_handler = h def set_output_level(level: int): output_level = level def get_level() -> int: return output_level class Logger(object): """A logger""" name: ?str handler: ?Handler output_level: int last_check: time.Stopwatch # TODO: Default name to actor type and ID def __init__(self, handler: ?Handler): self.name = None self.handler = handler self.output_level = UNSET # TODO: enable, but it currently crashes? # if handler is not None: # self.output_level = handler.get_level() self.last_check = time.Stopwatch() def _set_level(self, level: int): self.output_level = level def log(self, level, msg, data: ?dict[str, ?value]): handler = self.handler if handler is not None: path = [] n = self.name if n is not None: path = [n] m = Message(level, path, self.name, msg, data) # TODO: remove async here. It is an async call, but removing it leads to invalid AWAIT call, see if self.output_level == UNSET or self.last_check.elapsed().to_float() > 0.1: # TODO: do this async with a callback instead to avoid blocking self.output_level = handler.get_level() self.last_check = time.Stopwatch() if level <= self.output_level: async handler.handle(m) def emergency(self, msg: ?str, data: ?dict[str, ?value]): self.log(EMERGENCY, msg, data) def alert(self, msg: ?str, data: ?dict[str, ?value]): self.log(ALERT, msg, data) def critical(self, msg: ?str, data: ?dict[str, ?value]): self.log(CRITICAL, msg, data) def error(self, msg: ?str, data: ?dict[str, ?value]): self.log(ERR, msg, data) def warning(self, msg: ?str, data: ?dict[str, ?value]): self.log(WARNING, msg, data) def info(self, msg: ?str, data: ?dict[str, ?value]): self.log(INFO, msg, data) def notice(self, msg: ?str, data: ?dict[str, ?value]): self.log(NOTICE, msg, data) def debug(self, msg: ?str, data: ?dict[str, ?value]): self.log(DEBUG, msg, data) def verbose(self, msg: ?str, data: ?dict[str, ?value]): self.log(VERBOSE, msg, data) def trace(self, msg: ?str, data: ?dict[str, ?value]): self.log(TRACE, msg, data) ================================================ FILE: base/src/logging.ext.c ================================================ void loggingQ___ext_init__() {} B_int loggingQ_MessageD__get_actor_id (loggingQ_Message self) { $Actor actor_self = GET_SELF(); return toB_int(actor_self->$globkey); } B_str loggingQ_MessageD__get_actor_class (loggingQ_Message self) { $Actor actor_self = GET_SELF(); return to$str(unmangle_name(actor_self->$class->$GCINFO)); } ================================================ FILE: base/src/math.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # pi = 3.141592653589793 protocol RealFuns: @staticmethod sqrt : (Self) -> Self @staticmethod exp : (Self) -> Self @staticmethod log : (Self) -> Self @staticmethod sin : (Self) -> Self @staticmethod cos : (Self) -> Self @staticmethod tan : (Self) -> Self @staticmethod asin : (Self) -> Self @staticmethod acos : (Self) -> Self @staticmethod atan : (Self) -> Self @staticmethod sinh : (Self) -> Self @staticmethod cosh : (Self) -> Self @staticmethod tanh : (Self) -> Self @staticmethod asinh : (Self) -> Self @staticmethod acosh : (Self) -> Self @staticmethod atanh : (Self) -> Self extension float (RealFuns): NotImplemented def sqrt(x: float): return RealFuns.sqrt(x) def exp(x: float): return RealFuns.exp(x) def log(x: float): return RealFuns.log(x) def sin(x: float): return RealFuns.sin(x) def cos(x: float): return RealFuns.cos(x) def tan(x: float): return RealFuns.tan(x) def asin(x: float): return RealFuns.asin(x) def acos(x: float): return RealFuns.acos(x) def atan(x: float): return RealFuns.atan(x) def sinh(x: float): return RealFuns.sinh(x) def cosh(x: float): return RealFuns.cosh(x) def tanh(x: float): return RealFuns.tanh(x) def asinh(x: float): return RealFuns.asinh(x) def acosh(x: float): return RealFuns.acosh(x) def atanh(x: float): return RealFuns.atanh(x) ================================================ FILE: base/src/math.ext.c ================================================ B_float mathQ_RealFunsD_floatD_sqrt(mathQ_RealFunsD_float wit, B_float x) { return to$float(sqrt(x->val)); } B_float mathQ_RealFunsD_floatD_exp(mathQ_RealFunsD_float wit, B_float x) { return to$float(exp(x->val)); } B_float mathQ_RealFunsD_floatD_log(mathQ_RealFunsD_float wit, B_float x) { return to$float(log(x->val)); } B_float mathQ_RealFunsD_floatD_sin(mathQ_RealFunsD_float wit, B_float x) { return to$float(sin(x->val)); } B_float mathQ_RealFunsD_floatD_cos(mathQ_RealFunsD_float wit, B_float x) { return to$float(cos(x->val)); } B_float mathQ_RealFunsD_floatD_tan(mathQ_RealFunsD_float wit, B_float x) { return to$float(tan(x->val)); } B_float mathQ_RealFunsD_floatD_asin(mathQ_RealFunsD_float wit, B_float x) { return to$float(asin(x->val)); } B_float mathQ_RealFunsD_floatD_acos(mathQ_RealFunsD_float wit, B_float x) { return to$float(acos(x->val)); } B_float mathQ_RealFunsD_floatD_atan(mathQ_RealFunsD_float wit, B_float x) { return to$float(atan(x->val)); } B_float mathQ_RealFunsD_floatD_sinh(mathQ_RealFunsD_float wit, B_float x) { return to$float(sinh(x->val)); } B_float mathQ_RealFunsD_floatD_cosh(mathQ_RealFunsD_float wit, B_float x) { return to$float(cosh(x->val)); } B_float mathQ_RealFunsD_floatD_tanh(mathQ_RealFunsD_float wit, B_float x) { return to$float(tanh(x->val)); } B_float mathQ_RealFunsD_floatD_asinh(mathQ_RealFunsD_float wit, B_float x) { return to$float(asinh(x->val)); } B_float mathQ_RealFunsD_floatD_acosh(mathQ_RealFunsD_float wit, B_float x) { return to$float(acosh(x->val)); } B_float mathQ_RealFunsD_floatD_atanh(mathQ_RealFunsD_float wit, B_float x) { return to$float(atanh(x->val)); } void mathQ___ext_init__() { //NOP }; ================================================ FILE: base/src/net.act ================================================ """Network IO """ class NetCap(): """Capability to access network""" def __init__(self, cap: WorldCap): pass class DNSCap(): """Capability to perform DNS queries""" def __init__(self, cap: NetCap): pass class TCPCap(): """Capability to connect or listen with TCP""" def __init__(self, cap: NetCap): pass class TCPConnectCap(): """Capability to connect using TCP to a remote host""" def __init__(self, cap: TCPCap): pass class TCPListenCap(): """Capability to listen with TCP""" def __init__(self, cap: TCPCap): pass class _TCPListenConnectCap(): """Internal use only""" pass def is_ipv4(address: str) -> bool: NotImplemented def is_ipv6(address: str) -> bool: NotImplemented def _lookup_a(name: str, on_resolve: action(list[str]) -> None, on_error: action(str, str) -> None) -> None: """Perform DNS lookup for name of record type A """ NotImplemented def _lookup_aaaa(name: str, on_resolve: action(list[str]) -> None, on_error: action(str, str) -> None) -> None: """Perform DNS lookup for name of record type AAAA """ NotImplemented def lookup_a(cap: DNSCap, name: str, on_resolve: action(list[str]) -> None, on_error: action(str, str) -> None) -> None: """Perform DNS lookup for name of record type A """ _lookup_a(name, on_resolve, on_error) def lookup_aaaa(cap: DNSCap, name: str, on_resolve: action(list[str]) -> None, on_error: action(str, str) -> None) -> None: """Perform DNS lookup for name of record type AAAA """ _lookup_aaaa(name, on_resolve, on_error) actor TCPConnection(cap: TCPConnectCap, address: str, port: int, on_connect: action(TCPConnection) -> None, on_receive: action(TCPConnection, bytes) -> None, on_error: action(TCPConnection, str) -> None, on_remote_close: ?action(TCPConnection) -> None, connect_timeout: float=10.0): """TCP IP Connection""" var _a_res: list[str] = [] var _aaaa_res: list[str] = [] var _sock = -1 var _sock4 = -1 var _sock4_state = 0 var _sock4_error = "" var _sock6 = -1 var _sock6_state = 0 var _sock6_error = "" STATE_NONE = 0 STATE_RESOLVING = 1 # Resolving DNS STATE_CONNECTING = 2 # Got DNS response or input was IP address so now doing TCP connect STATE_CONNECTED = 3 # TCP Connected STATE_CLOSED = 4 # TCP Connection disconnected / closed (it might never have been connected) var _state = STATE_NONE var _connections = 0 var _consecutive_connect_errors = 0 var _bytes_in: u64 = 0 var _bytes_out: u64 = 0 proc def _pin_affinity() -> None: NotImplemented _pin_affinity() # TODO: we should not just connect to the first IPv4 and first IPv6 result # but rather arrange them in order of preference and try them in that order, # more details in Happy Eye Balls v2 https://tools.ietf.org/html/rfc8305 # DNS A def _on_dns_a_resolve(result): _a_res = result _sock4_state = STATE_CONNECTING _state = STATE_CONNECTING _connect4(result[0]) def _on_dns_a_error(name, msg): if _state == STATE_RESOLVING: after 0.1: _lookup_a(address, _on_dns_a_resolve, _on_dns_a_error) # DNS AAAA def _on_dns_aaaa_resolve(result): _aaaa_res = result _sock6_state = STATE_CONNECTING _state = STATE_CONNECTING _connect6(result[0]) def _on_dns_aaaa_error(name, msg): if _state == STATE_RESOLVING: after 0.1: _lookup_aaaa(address, _on_dns_aaaa_resolve, _on_dns_aaaa_error) action def _on_tcp_error(sockfamily: int, err: int, errmsg: str): if sockfamily == 4: if _sock6_state == STATE_NONE: # IPv4 only connection _consecutive_connect_errors += 1 on_error(self, errmsg) else: # dual stack connection # wait for other socket to connect or fail if _sock6_error != "": _consecutive_connect_errors += 1 on_error(self, errmsg + " IPv6 error: " + _sock6_error) _sock4_error = errmsg elif sockfamily == 6: if _sock4_state == STATE_NONE: # IPv6 only connection _consecutive_connect_errors += 1 on_error(self, errmsg) else: # dual stack connection # wait for other socket to connect or fail if _sock4_error != "": _consecutive_connect_errors += 1 on_error(self, errmsg + " IPv4 error: " + _sock4_error) _sock6_error = errmsg # TCP connect over IPv4 proc def _connect4(ip_address: str): NotImplemented # TCP connect over IPv6 proc def _connect6(ip_address: str): NotImplemented action def _on_connect4(): _sock4_state = STATE_CONNECTED _sock4_error = "" if _sock6_state == STATE_CONNECTED: # If IPv6 is already connected, we (IPv4) lost, so close our socket # TODO: close IPv4 socket return _on_connect(_sock4) action def _on_connect6(): _sock6_state = STATE_CONNECTED _sock6_error = "" if _sock4_state == STATE_CONNECTED: # If IPv4 is already connected, we (IPv6) lost, so close our socket # TODO: close IPv6 socket return _on_connect(_sock6) # Handle on_connect event proc def _on_connect(sock: int): if _state == STATE_CONNECTING: _state = STATE_CONNECTED _sock = sock _read_start() _connections += 1 _consecutive_connect_errors = 0 on_connect(self) elif _state == STATE_CONNECTED: # It is normal to get multiple on_connect events since we are doing # Happy Eyeballs and letting IPv4 race against IPv6, however, those # should be cancelled out in the _on_connect[46] functions above. pass else: # We don't expect to establish a connection in any other state # TODO: use RTS log instead print("Unexpected state", _state) proc def _read_start(): NotImplemented action def write(data: bytes) -> None: """Write data to remote""" NotImplemented action def close(on_close: action(TCPConnection) -> None) -> None: """Close the connection""" NotImplemented def _connect_timeout(): if _state == STATE_CONNECTING: _state = STATE_CLOSED _consecutive_connect_errors += 1 def _on_close(c): on_error(self, "Connection attempt failed due to timeout") close(_on_close) def reconnect(): close(_connect) def _connect(c): # TODO: would be nice to cancel connect_timeout when connection succeeds after connect_timeout: _connect_timeout() if is_ipv4(address): _sock4_state = STATE_CONNECTING _state = STATE_CONNECTING _connect4(address) elif is_ipv6(address): _sock6_state = STATE_CONNECTING _state = STATE_CONNECTING _connect6(address) else: _state = STATE_RESOLVING _lookup_aaaa(address, _on_dns_aaaa_resolve, _on_dns_aaaa_error) # TODO: delay this by a few milliseconds to give IPv6 a slight preference _lookup_a(address, _on_dns_a_resolve, _on_dns_a_error) mut def __resume__() -> None: NotImplemented action def ip_version() -> ?int: NotImplemented action def local_address() -> str: NotImplemented action def remote_address() -> str: NotImplemented action def metrics(): return (connections=_connections, consecutive_connect_errors=_consecutive_connect_errors, bytes_in=_bytes_in, bytes_out=_bytes_out) _connect(self) actor TCPListenConnection(cap: _TCPListenConnectCap, server_client: int): """TCP Listener Connection""" var client: int = -1 var on_receive: ?action(TCPListenConnection, bytes) -> None = None var on_error: ?action(TCPListenConnection, str) -> None = None var on_remote_close: ?action(TCPListenConnection) -> None = None var _initialized = False proc def _read_start(): """Implementation internal""" NotImplemented action def cb_install(new_on_receive: action(TCPListenConnection, bytes) -> None, new_on_error: action(TCPListenConnection, str) -> None, new_on_remote_close: ?action(TCPListenConnection) -> None) -> None: """Install callback handlers""" on_receive = new_on_receive on_error = new_on_error on_remote_close = new_on_remote_close if not _initialized: _read_start() _initialized = True action def close() -> None: """Close connection""" NotImplemented action def write(data: bytes) -> None: """Write data to remote""" NotImplemented mut def __resume__() -> None: NotImplemented proc def _init() -> None: """Implementation internal""" NotImplemented _init() actor TCPListener(cap: TCPListenCap, address: str, port: int, on_listen: action(TCPListener, ?str) -> None, on_accept: action(TCPListenConnection) -> None): """TCP Listener""" _stream = -1 def create_tcp_listen_connection(cap: _TCPListenConnectCap, client: int): """Implementation internal""" c = TCPListenConnection(cap, client) on_accept(c) mut def __resume__() -> None: NotImplemented proc def _init(): """Implementation internal""" NotImplemented _init() actor TLSListenConnection(cap: _TCPListenConnectCap, server_stream: int): """TLS Listener Connection""" var _stream = -1 var on_receive: ?action(TLSListenConnection, bytes) -> None = None var on_error: ?action(TLSListenConnection, str) -> None = None var on_remote_close: ?action(TLSListenConnection) -> None = None var _initialized = False proc def _read_start(): """Implementation internal""" NotImplemented action def cb_install(new_on_receive: action(TLSListenConnection, bytes) -> None, new_on_error: action(TLSListenConnection, str) -> None, new_on_remote_close: ?action(TLSListenConnection) -> None) -> None: """Install callback handlers""" on_receive = new_on_receive on_error = new_on_error on_remote_close = new_on_remote_close if not _initialized: _read_start() _initialized = True action def close() -> None: """Close connection""" NotImplemented action def write(data: bytes) -> None: """Write data to remote""" NotImplemented mut def __resume__() -> None: NotImplemented proc def _init() -> None: """Implementation internal""" NotImplemented _init() actor TLSListener(cap: TCPListenCap, address: str, port: int, cert_pem: bytes, key_pem: bytes, on_listen: action(TLSListener, ?str) -> None, on_accept: action(TLSListenConnection) -> None): """TLS Listener""" _stream = -1 _tls_ctx = -1 def create_tls_listen_connection(cap: _TCPListenConnectCap, stream: int): """Implementation internal""" c = TLSListenConnection(cap, stream) on_accept(c) mut def __resume__() -> None: NotImplemented proc def _init(): """Implementation internal""" NotImplemented _init() actor TLSConnection(cap: TCPConnectCap, address: str, port: int, on_connect: action(TLSConnection) -> None, on_receive: action(TLSConnection, bytes) -> None, on_error: action(TLSConnection, str) -> None, on_remote_close: ?action(TLSConnection) -> None, verify_tls: bool=True, protocols: list[str]=[]): # TODO: support hostname/CN mismatch, good when connecting with IP address? # TODO: do DNS lookup in Acton # TODO: support ALPN # TODO: support SNI # TODO: support client certificates # TODO: implement state machine # TODO: support timeout # TODO: do Happy Eyeballs var _stream = -1 var _on_close: ?action(TLSConnection) -> None = None var _connections = 0 var _consecutive_connect_errors = 0 var _bytes_in: u64 = 0 var _bytes_out: u64 = 0 proc def _pin_affinity() -> None: NotImplemented _pin_affinity() action def _on_tls_connect(): _connections += 1 on_connect(self) action def _on_tls_error(sockfamily: int, err: int, errmsg: str): on_error(self, errmsg) action def close(on_close: action(TLSConnection) -> None) -> None: """Close the connection""" NotImplemented action def write(data: bytes) -> None: """Write data to remote""" NotImplemented def reconnect(): close(_connect) proc def _connect_tls(): NotImplemented proc def _connect(c): _connect_tls() _connect(self) ================================================ FILE: base/src/net.ext.c ================================================ #define GC_THREADS 1 #ifdef _WIN32 #include #endif #include #include #include #include #include #include #include #ifndef _WIN32 #include #endif #include "../rts/io.h" #include "../rts/log.h" void netQ___ext_init__() { // NOP } B_bool netQ_is_ipv4 (B_str address) { struct sockaddr_in sa; if (inet_pton(AF_INET, (const char *)fromB_str(address), &(sa.sin_addr)) == 0) { return B_False; } else { return B_True; } } B_bool netQ_is_ipv6 (B_str address) { struct sockaddr_in6 sa; if (inet_pton(AF_INET6, (const char *)fromB_str(address), &(sa.sin6_addr)) == 0) { return B_False; } else { return B_True; } } struct dns_cb_data { struct addrinfo *hints; char* hostname; $action on_resolve; $action2 on_error; }; static void _lookup_a__on_resolve (uv_getaddrinfo_t *req, int status, struct addrinfo *dns_res) { struct dns_cb_data *cb_data = req->data; B_list $res = B_listG_new(NULL, NULL); if (status != 0) { char errmsg[1024] = "DNS lookup error: "; uv_strerror_r(status, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); $action2 f = ($action2)cb_data->on_error; f->$class->__asyn__(f, to$str(cb_data->hostname), to$str(errmsg)); // No free with GC, but maybe one day we do this explicitly? //uv_freeaddrinfo(dns_res); //free(cb_data->hints); //free(cb_data); //free(req); return; } struct addrinfo *rp; char addr[17] = {'\0'}; for (rp = dns_res; rp != NULL; rp = rp->ai_next) { uv_ip4_name((struct sockaddr_in*) rp->ai_addr, addr, 16); B_SequenceD_listG_witness->$class->append(B_SequenceD_listG_witness, $res, to$str(addr)); } $action f = ($action)cb_data->on_resolve; f->$class->__asyn__(f, $res); // No free with GC, but maybe one day we do this explicitly? //uv_freeaddrinfo(dns_res); //free(cb_data->hints); //free(cb_data); //free(req); } B_NoneType netQ__lookup_a (B_str name, $action on_resolve, $action on_error) { struct addrinfo *hints = (struct addrinfo *)acton_malloc(sizeof(struct addrinfo)); hints->ai_family = PF_INET; hints->ai_socktype = SOCK_STREAM; hints->ai_protocol = IPPROTO_TCP; hints->ai_flags = 0; struct dns_cb_data *cb_data = (struct dns_cb_data *)acton_malloc(sizeof(struct dns_cb_data)); cb_data->hints = hints; cb_data->hostname = (char *)fromB_str(name); cb_data->on_resolve = on_resolve; cb_data->on_error = ($action2) on_error; uv_getaddrinfo_t *req = (uv_getaddrinfo_t*)acton_malloc(sizeof(uv_getaddrinfo_t)); req->data = cb_data; int r = uv_getaddrinfo(get_uv_loop(), req, _lookup_a__on_resolve, (const char *)fromB_str(name), NULL, hints); if (r != 0) { char errmsg[1024] = "Unable to run DNS query: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)cb_data->on_error; f->$class->__asyn__(f, name, to$str(errmsg)); // NOTE: free() here if do manual memory management in I/O one day return B_None; } return B_None; } static void _lookup_aaaa__on_resolve (uv_getaddrinfo_t *req, int status, struct addrinfo *dns_res) { struct dns_cb_data *cb_data = req->data; B_list $res = B_listG_new(NULL, NULL); if (status != 0) { char errmsg[1024] = "DNS lookup error: "; uv_strerror_r(status, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); $action2 f = ($action2)cb_data->on_error; f->$class->__asyn__(f, to$str(cb_data->hostname), to$str(errmsg)); // No free with GC, but maybe one day we do this explicitly? //uv_freeaddrinfo(dns_res); //free(cb_data->hints); //free(cb_data); //free(req); return; } struct addrinfo *rp; char addr[40] = {'\0'}; for (rp = dns_res; rp != NULL; rp = rp->ai_next) { uv_ip6_name((struct sockaddr_in6*)rp->ai_addr, addr, 39); B_SequenceD_listG_witness->$class->append(B_SequenceD_listG_witness, $res, to$str(addr)); } $action f = ($action)cb_data->on_resolve; f->$class->__asyn__(f, $res); // No free with GC, but maybe one day we do this explicitly? //uv_freeaddrinfo(dns_res); //free(cb_data->hints); //free(cb_data); //free(req); } B_NoneType netQ__lookup_aaaa (B_str name, $action on_resolve, $action on_error) { struct addrinfo *hints = (struct addrinfo *)acton_malloc(sizeof(struct addrinfo)); hints->ai_family = PF_INET6; hints->ai_socktype = SOCK_STREAM; hints->ai_protocol = IPPROTO_TCP; hints->ai_flags = 0; struct dns_cb_data *cb_data = (struct dns_cb_data *)acton_malloc(sizeof(struct dns_cb_data)); cb_data->hints = hints; cb_data->hostname = (char *)fromB_str(name); cb_data->on_resolve = on_resolve; cb_data->on_error = ($action2)on_error; uv_getaddrinfo_t *req = (uv_getaddrinfo_t*)acton_malloc(sizeof(uv_getaddrinfo_t)); req->data = cb_data; int r = uv_getaddrinfo(get_uv_loop(), req, _lookup_aaaa__on_resolve, (const char *)fromB_str(name), NULL, hints); if (r != 0) { char errmsg[1024] = "Unable to run DNS query: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)cb_data->on_error; f->$class->__asyn__(f, name, to$str(errmsg)); // NOTE: free() here if do manual memory management in I/O one day return B_None; } return B_None; } void netQ_TCPConnection__on_receive(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { if (nread < 0){ if (nread == UV_EOF) { netQ_TCPConnection self = stream->data; if ((intptr_t)stream != -1) uv_close((uv_handle_t *)stream, NULL); self->_sock = toB_int(-1); self->_sock4 = toB_int(-1); self->_sock6 = toB_int(-1); if (self->on_remote_close) { $action f = ($action)self->on_remote_close; f->$class->__asyn__(f, self); } } } else if (nread > 0) { if (stream->data) { netQ_TCPConnection self = stream->data; $action2 f = ($action2)self->on_receive; f->$class->__asyn__(f, self, to$bytesD_len(buf->base, nread)); self->_bytes_in->val += nread; } } } $R netQ_TCPConnectionD__pin_affinityG_local (netQ_TCPConnection self, $Cont c$cont) { pin_actor_affinity(); return $R_CONT(c$cont, B_None); } void on_connect4(uv_connect_t *connect_req, int status) { netQ_TCPConnection self = (netQ_TCPConnection)connect_req->data; if (status != 0) { char errmsg[1024] = "Error in TCP connect over IPv4: "; uv_strerror_r(status, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); self->$class->_on_tcp_error(self, toB_int(4), toB_int(status), to$str(errmsg)); return; } self->$class->_on_connect4(self); } void on_connect6(uv_connect_t *connect_req, int status) { netQ_TCPConnection self = (netQ_TCPConnection)connect_req->data; if (status != 0) { char errmsg[1024] = "Error in TCP connect over IPv6: "; uv_strerror_r(status, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); self->$class->_on_tcp_error(self, toB_int(6), toB_int(status), to$str(errmsg)); return; } self->$class->_on_connect6(self); } $R netQ_TCPConnectionD__connect4G_local (netQ_TCPConnection self, $Cont c$cont, B_str ip_address) { log_debug("TCP connecting over IPv4 to %s", fromB_str(ip_address)); uv_tcp_t* socket = (uv_tcp_t*)acton_malloc(sizeof(uv_tcp_t)); uv_tcp_init(get_uv_loop(), socket); self->_sock4 = toB_int((int64_t)(intptr_t)socket); uv_connect_t* connect_req = (uv_connect_t*)acton_malloc(sizeof(uv_connect_t)); connect_req->data = (void *)self; struct sockaddr_in dest; uv_ip4_addr((const char *)fromB_str(ip_address), fromB_int(self->port), &dest); uv_tcp_connect(connect_req, socket, (const struct sockaddr*)&dest, on_connect4); return $R_CONT(c$cont, B_None); } $R netQ_TCPConnectionD__connect6G_local (netQ_TCPConnection self, $Cont c$cont, B_str ip_address) { log_debug("TCP connecting over IPv6 to %s", fromB_str(ip_address)); uv_tcp_t* socket = (uv_tcp_t*)acton_malloc(sizeof(uv_tcp_t)); uv_tcp_init(get_uv_loop(), socket); self->_sock6 = toB_int((int64_t)(intptr_t)socket); uv_connect_t* connect_req = (uv_connect_t*)acton_malloc(sizeof(uv_connect_t)); connect_req->data = (void *)self; struct sockaddr_in6 dest; uv_ip6_addr((const char *)fromB_str(ip_address), fromB_int(self->port), &dest); uv_tcp_connect(connect_req, socket, (const struct sockaddr*)&dest, on_connect6); return $R_CONT(c$cont, B_None); } $R netQ_TCPConnectionD__read_startG_local (netQ_TCPConnection self, $Cont c$cont) { uv_tcp_t* socket = (uv_tcp_t *)fromB_int(self->_sock); socket->data = self; int r = uv_read_start((uv_stream_t *)socket, alloc_buffer, netQ_TCPConnection__on_receive); if (r < 0) { char errmsg[1024] = "Failed to start reading from TCP client socket: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_error; f->$class->__asyn__(f, self, to$str(errmsg)); return $R_CONT(c$cont, B_None); } return $R_CONT(c$cont, B_None); } $R netQ_TCPConnectionD_writeG_local (netQ_TCPConnection self, $Cont c$cont, B_bytes data) { uv_stream_t *stream = (uv_stream_t *)fromB_int(self->_sock); // fd == -1 means invalid FD and can happen after __resume__ if ((intptr_t)stream == -1) return $R_CONT(c$cont, B_None); uv_write_t *req = (uv_write_t *)acton_malloc(sizeof(uv_write_t)); uv_buf_t buf = uv_buf_init((char *)data->str, data->nbytes); int r = uv_write(req, stream, &buf, 1, NULL); if (r < 0) { char errmsg[1024] = "Failed to write to TCP socket: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_error; f->$class->__asyn__(f, self, to$str(errmsg)); } self->_bytes_out->val += data->nbytes; return $R_CONT(c$cont, B_None); } B_NoneType netQ_TCPConnectionD___resume__ (netQ_TCPConnection self) { self->_sock = toB_int(-1); self->_sock4 = toB_int(-1); self->_sock6 = toB_int(-1); $action2 f = ($action2)self->on_error; f->$class->__asyn__(f, self, to$str("resume")); return B_None; } struct close_cb_data { netQ_TCPConnection self; $action on_close; }; static void after_shutdown(uv_shutdown_t* req, int status) { log_debug("TCP Shutdown complete, closing handle"); if (status < 0) log_warn("Error in TCP shutdown: %s", uv_strerror(status)); uv_close((uv_handle_t*)req->handle, NULL); struct close_cb_data *cb_data = (struct close_cb_data *)req->data; $action on_close = ($action)cb_data->on_close; on_close->$class->__asyn__(on_close, cb_data->self); } $R netQ_TCPConnectionD_closeG_local (netQ_TCPConnection self, $Cont c$cont, $action on_close) { uv_stream_t *stream = (uv_stream_t *)fromB_int(self->_sock); // fd == -1 means invalid FD and can happen after __resume__ if ((intptr_t)stream == -1) { on_close->$class->__asyn__(on_close, self); return $R_CONT(c$cont, B_None); } log_debug("Closing TCP connection"); struct close_cb_data *cb_data = (struct close_cb_data *)acton_malloc(sizeof(struct close_cb_data)); cb_data->self = self; cb_data->on_close = on_close; uv_shutdown_t *req = (uv_shutdown_t *)acton_malloc(sizeof(uv_shutdown_t)); req->data = (void *)cb_data; int r = uv_shutdown(req, stream, after_shutdown); self->_sock = toB_int(-1); self->_sock4 = toB_int(-1); self->_sock6 = toB_int(-1); if (r < 0) { // TODO: we could probably ignore most or all of these errors as the // purpose is to shutdown our side of the connection and many of these // errors are about "not connected" or "already closed", turning this // into a NOP char errmsg[1024] = "Failed to shutdown TCP client socket: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); on_close->$class->__asyn__(on_close, self); // TODO: we should always call uv_close() here return $R_CONT(c$cont, B_None); } return $R_CONT(c$cont, B_None); } $R netQ_TCPConnectionD_ip_versionG_local (netQ_TCPConnection self, $Cont c$cont) { struct sockaddr_storage peername; int namelen = sizeof(peername); if (uv_tcp_getpeername((const uv_tcp_t *)fromB_int(self->_sock), (struct sockaddr*)&peername, &namelen) == 0) { if (peername.ss_family == AF_INET) { return $R_CONT(c$cont, toB_int(4)); } else if (peername.ss_family == AF_INET6) { return $R_CONT(c$cont, toB_int(6)); } else { log_error("Unhandled AFI"); } } else { log_error("Failed to get peer name from handle %d", fromB_int(self->_sock)); } return $R_CONT(c$cont, B_None); } $R netQ_TCPConnectionD_local_addressG_local (netQ_TCPConnection self, $Cont c$cont) { struct sockaddr_storage sockname; int namelen = sizeof(sockname); char addr[INET6_ADDRSTRLEN] = { '\0' }; if (uv_tcp_getsockname((const uv_tcp_t *)fromB_int(self->_sock), (struct sockaddr*)&sockname, &namelen) == 0) { if (sockname.ss_family == AF_INET) { uv_ip4_name((struct sockaddr_in*)&sockname, addr, sizeof(addr)); } else if (sockname.ss_family == AF_INET6) { uv_ip6_name((struct sockaddr_in6*)&sockname, addr, sizeof(addr)); } else { log_error("Unhandled AFI"); } } else { log_error("Failed to get sock name from handle %d", fromB_int(self->_sock)); } return $R_CONT(c$cont, to$str(addr)); } $R netQ_TCPConnectionD_remote_addressG_local (netQ_TCPConnection self, $Cont c$cont) { struct sockaddr_storage peername; int namelen = sizeof(peername); char addr[INET6_ADDRSTRLEN] = { '\0' }; if (uv_tcp_getpeername((const uv_tcp_t *)fromB_int(self->_sock), (struct sockaddr*)&peername, &namelen) == 0) { if (peername.ss_family == AF_INET) { uv_ip4_name((struct sockaddr_in*)&peername, addr, sizeof(addr)); } else if (peername.ss_family == AF_INET6) { uv_ip6_name((struct sockaddr_in6*)&peername, addr, sizeof(addr)); } else { log_error("Unhandled AFI"); } } else { log_error("Failed to get peer name from handle %d", fromB_int(self->_sock)); } return $R_CONT(c$cont, to$str(addr)); } void on_new_connection(uv_stream_t *server, int status) { netQ_TCPListener self = (netQ_TCPListener)server->data; if (status != 0) { char errmsg[1024] = "Error on new TCP client connection: "; uv_strerror_r(status, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); // NOTE: free() here if do manual memory management in I/O one day return; } uv_tcp_t *client = (uv_tcp_t*)acton_malloc(sizeof(uv_tcp_t)); uv_tcp_init(get_uv_loop(), client); int r = uv_accept(server, (uv_stream_t *)client); if (r != 0) { char errmsg[1024] = "Error in accepting TCP client connection: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); // NOTE: free() here if do manual memory management in I/O one day return; } self->$class->create_tcp_listen_connection(self, B_None, toB_int((int64_t)(intptr_t)client)); // NOTE: free() here if do manual memory management in I/O one day } $R netQ_TCPListenerD__initG_local (netQ_TCPListener self, $Cont c$cont) { pin_actor_affinity(); uv_tcp_t *server = (uv_tcp_t *)acton_malloc(sizeof(uv_tcp_t)); uv_tcp_init(get_uv_loop(), server); server->data = (void *)self; int r; struct sockaddr_in addr4; struct sockaddr_in6 addr6; if (inet_pton(AF_INET, (const char *)fromB_str(self->address), &(addr4.sin_addr)) == 1) { r = uv_ip4_addr((const char *)fromB_str(self->address), fromB_int(self->port), &addr4); } else if (inet_pton(AF_INET6, (const char *)fromB_str(self->address), &(addr6.sin6_addr)) == 1) { r = uv_ip6_addr((const char *)fromB_str(self->address), fromB_int(self->port), &addr6); } else { B_str errmsg = $FORMAT("Address is not an IPv4 or IPv6 address: %s", fromB_str(self->address)); log_warn((const char *)fromB_str(errmsg)); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, errmsg); // NOTE: free() here if do manual memory management in I/O one day return $R_CONT(c$cont, B_None); } if (r != 0) { char errmsg[1024] = "Unable to parse address: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); // NOTE: free() here if do manual memory management in I/O one day return $R_CONT(c$cont, B_None); } if (inet_pton(AF_INET, (const char *)fromB_str(self->address), &(addr4.sin_addr)) == 1) { r = uv_tcp_bind(server, (const struct sockaddr *)&addr4, 0); } else if (inet_pton(AF_INET6, (const char *)fromB_str(self->address), &(addr6.sin6_addr)) == 1) { r = uv_tcp_bind(server, (const struct sockaddr *)&addr6, 0); } if (r != 0) { char errmsg[1024] = "Error in TCP bind: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); // NOTE: free() here if do manual memory management in I/O one day return $R_CONT(c$cont, B_None); } r = uv_listen((uv_stream_t *)server, 1024, on_new_connection); if (r != 0) { char errmsg[1024] = "Error in TCP listen: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); // NOTE: free() here if do manual memory management in I/O one day return $R_CONT(c$cont, B_None); } $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, B_None); return $R_CONT(c$cont, B_None); } B_NoneType netQ_TCPListenerD___resume__ (netQ_TCPListener self) { self->_stream = toB_int(-1); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str("resume")); return B_None; } $R netQ_TCPListenConnectionD__initG_local (netQ_TCPListenConnection self, $Cont c$cont) { pin_actor_affinity(); uv_stream_t *client = (uv_stream_t *)fromB_int(self->server_client); uv_os_fd_t fd; uv_fileno((uv_handle_t *)client, &fd); uv_tcp_t* client_handle = (uv_tcp_t*)acton_malloc(sizeof(uv_tcp_t)); uv_tcp_init(get_uv_loop(), client_handle); uv_tcp_open(client_handle, (uv_os_sock_t)fd); self->client = toB_int((int64_t)(intptr_t)client_handle); return $R_CONT(c$cont, B_None); } void netQ_TCPListenConnection__on_receive(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { if (nread < 0){ if (nread == UV_EOF) { netQ_TCPListenConnection self = stream->data; if ((intptr_t)stream != -1) uv_close((uv_handle_t *)stream, NULL); self->client = toB_int(-1); if (self->on_remote_close) { $action f = ($action)self->on_remote_close; f->$class->__asyn__(f, self); } } } else if (nread > 0) { if (stream->data) { netQ_TCPListenConnection self = stream->data; $action2 f = ($action2)self->on_receive; f->$class->__asyn__(f, self, to$bytesD_len(buf->base, nread)); } } // No free with GC, but maybe one day we do this explicitly? //if (buf->base) // free(buf->base); } $R netQ_TCPListenConnectionD__read_startG_local (netQ_TCPListenConnection self, $Cont c$cont) { uv_stream_t *client = (uv_stream_t *)fromB_int(self->client); client->data = self; int r = uv_read_start(client, alloc_buffer, netQ_TCPListenConnection__on_receive); if (r < 0) { char errmsg[1024] = "Failed to start reading from TCP socket: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_error; f->$class->__asyn__(f, self, to$str(errmsg)); return $R_CONT(c$cont, B_None); } return $R_CONT(c$cont, B_None); } $R netQ_TCPListenConnectionD_writeG_local (netQ_TCPListenConnection self, $Cont c$cont, B_bytes data) { uv_stream_t *stream = (uv_stream_t *)fromB_int(self->client); // fd == -1 means invalid FD and can happen after __resume__ if ((intptr_t)stream == -1) return $R_CONT(c$cont, B_None); uv_write_t *req = (uv_write_t *)acton_malloc(sizeof(uv_write_t)); uv_buf_t buf = uv_buf_init((char *)data->str, data->nbytes); int r = uv_write(req, stream, &buf, 1, NULL); if (r < 0) { char errmsg[1024] = "Failed to write to TCP socket: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_error; f->$class->__asyn__(f, self, to$str(errmsg)); } return $R_CONT(c$cont, B_None); } $R netQ_TCPListenConnectionD_closeG_local (netQ_TCPListenConnection self, $Cont c$cont) { log_debug("Closing TCP connection, affinity=%d", self->$affinity); uv_stream_t *client = (uv_stream_t *)fromB_int(self->client); // fd == -1 means invalid FD and can happen after __resume__ or if the socket was closed if ((intptr_t)client == -1) return $R_CONT(c$cont, B_None); // TODO: shouldn't we call uv_shutdown() first? uv_read_stop() is not needed I think uv_read_stop(client); if (uv_is_closing((uv_handle_t *)client) == 0) { uv_close((uv_handle_t *)client, NULL); } self->client = toB_int(-1); return $R_CONT(c$cont, B_None); } B_NoneType netQ_TCPListenConnectionD___resume__ (netQ_TCPListenConnection self) { self->server_client = toB_int(-1); self->client = toB_int(-1); return B_None; } struct tls_listener_conn { netQ_TLSListener listener; tlsuv_stream_t *stream; }; static void tls_listener_on_close(uv_handle_t *stream) { log_debug("TLS listener handle closed, stream: %p stream->data: %p", stream, stream->data); } static void tls_listener_close_stream(tlsuv_stream_t *stream) { tlsuv_stream_close(stream, tls_listener_on_close); } static void tls_listener_on_connect(uv_connect_t *creq, int status) { struct tls_listener_conn *conn = (struct tls_listener_conn *)creq->data; netQ_TLSListener listener = conn->listener; tlsuv_stream_t *stream = conn->stream; if (status != 0) { char errmsg[1024] = "TLS handshake failed: "; uv_strerror_r(status, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)listener->on_listen; f->$class->__asyn__(f, listener, to$str(errmsg)); tls_listener_close_stream(stream); return; } listener->$class->create_tls_listen_connection(listener, B_None, toB_int((int64_t)(intptr_t)stream)); } static void tls_listener_on_receive(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { netQ_TLSListenConnection self = ((tlsuv_stream_t *)stream)->data; if (nread > 0) { if (stream->data) { $action2 f = ($action2)self->on_receive; B_bytes data = to$bytesD_len(buf->base, nread); f->$class->__asyn__(f, self, data); } } else if (nread == UV_EOF) { log_debug("TLS listen connection closed %p", stream); tls_listener_close_stream((tlsuv_stream_t *)stream); self->_stream = toB_int(-1); if (self->on_remote_close) { $action f = ($action)self->on_remote_close; f->$class->__asyn__(f, self); } } else if (nread < 0) { log_debug("TLS listen read error %ld: %s", nread, uv_strerror((int)nread)); tls_listener_close_stream((tlsuv_stream_t *)stream); if (stream->data) { self->_stream = toB_int(-1); } } } static void tls_listener_write_cb(uv_write_t *wreq, int status) { if (status < 0) { char errmsg[1024] = "Failed to write to TLS listen socket: "; uv_strerror_r(status, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); netQ_TLSListenConnection self = (netQ_TLSListenConnection)wreq->data; $action2 on_error = ($action2)self->on_error; on_error->$class->__asyn__(on_error, self, to$str(errmsg)); tls_listener_close_stream((tlsuv_stream_t *)wreq->handle); } } static void on_new_tls_connection(uv_stream_t *server, int status) { netQ_TLSListener self = (netQ_TLSListener)server->data; if (status != 0) { char errmsg[1024] = "Error on new TLS client connection: "; uv_strerror_r(status, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); return; } uv_tcp_t *client = (uv_tcp_t *)acton_malloc(sizeof(uv_tcp_t)); uv_tcp_init(get_uv_loop(), client); int r = uv_accept(server, (uv_stream_t *)client); if (r != 0) { char errmsg[1024] = "Error in accepting TLS client connection: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); return; } uv_os_fd_t fd; r = uv_fileno((uv_handle_t *)client, &fd); if (r != 0) { char errmsg[1024] = "Error getting TLS client socket fd: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); return; } #ifdef _WIN32 // NOTE: Windows socket duplication path is untested. SOCKET orig_sock = (SOCKET)fd; WSAPROTOCOL_INFOA dup_info; if (WSADuplicateSocket(orig_sock, GetCurrentProcessId(), &dup_info) != 0) { char errmsg[1024] = "Error duplicating TLS client socket: "; snprintf(errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg), "WSA error %d", WSAGetLastError()); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); uv_close((uv_handle_t *)client, NULL); return; } SOCKET dup_sock = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &dup_info, 0, WSA_FLAG_OVERLAPPED); uv_close((uv_handle_t *)client, NULL); if (dup_sock == INVALID_SOCKET) { char errmsg[1024] = "Error duplicating TLS client socket: "; snprintf(errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg), "WSA error %d", WSAGetLastError()); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); return; } uv_os_sock_t sock = (uv_os_sock_t)dup_sock; #else int dup_fd = dup((int)fd); uv_close((uv_handle_t *)client, NULL); if (dup_fd < 0) { char errmsg[1024] = "Error duplicating TLS client socket: "; snprintf(errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg), "%s", strerror(errno)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); return; } uv_os_sock_t sock = (uv_os_sock_t)dup_fd; #endif tls_context *tls = (tls_context *)fromB_int(self->_tls_ctx); tlsuv_stream_t *stream = (tlsuv_stream_t *)acton_malloc(sizeof(tlsuv_stream_t)); tlsuv_stream_init(get_uv_loop(), stream, tls); tlsuv_stream_set_server(stream, 1); stream->authmode = 0; struct tls_listener_conn *conn = (struct tls_listener_conn *)acton_malloc(sizeof(*conn)); conn->listener = self; conn->stream = stream; uv_connect_t *connect_req = (uv_connect_t *)acton_calloc(1, sizeof(uv_connect_t)); connect_req->data = conn; r = tlsuv_stream_open(connect_req, stream, sock, tls_listener_on_connect); if (r != 0) { char errmsg[1024] = "Failed to start TLS handshake: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); tls_listener_close_stream(stream); return; } } $R netQ_TLSListenerD__initG_local (netQ_TLSListener self, $Cont c$cont) { pin_actor_affinity(); tls_context *tls = default_tls_context(NULL, 0); if (tls == NULL) { $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str("Failed to initialize TLS context")); return $R_CONT(c$cont, B_None); } tlsuv_private_key_t key = NULL; tlsuv_certificate_t cert = NULL; int rc = tls->load_key(&key, (const char *)self->key_pem->str, self->key_pem->nbytes); if (rc != 0) { const char *err = tls->strerror(rc); B_str errmsg = $FORMAT("Failed to load TLS key: %s", err); log_warn((const char *)fromB_str(errmsg)); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, errmsg); return $R_CONT(c$cont, B_None); } rc = tls->load_cert(&cert, (const char *)self->cert_pem->str, self->cert_pem->nbytes); if (rc != 0) { const char *err = tls->strerror(rc); B_str errmsg = $FORMAT("Failed to load TLS cert: %s", err); log_warn((const char *)fromB_str(errmsg)); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, errmsg); return $R_CONT(c$cont, B_None); } rc = tls->set_own_cert(tls, key, cert); if (rc != 0) { $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str("Failed to set TLS certificate")); return $R_CONT(c$cont, B_None); } self->_tls_ctx = toB_int((int64_t)(intptr_t)tls); uv_tcp_t *server = (uv_tcp_t *)acton_malloc(sizeof(uv_tcp_t)); uv_tcp_init(get_uv_loop(), server); server->data = (void *)self; int r; struct sockaddr_in addr4; struct sockaddr_in6 addr6; if (inet_pton(AF_INET, (const char *)fromB_str(self->address), &(addr4.sin_addr)) == 1) { r = uv_ip4_addr((const char *)fromB_str(self->address), fromB_int(self->port), &addr4); } else if (inet_pton(AF_INET6, (const char *)fromB_str(self->address), &(addr6.sin6_addr)) == 1) { r = uv_ip6_addr((const char *)fromB_str(self->address), fromB_int(self->port), &addr6); } else { B_str errmsg = $FORMAT("Address is not an IPv4 or IPv6 address: %s", fromB_str(self->address)); log_warn((const char *)fromB_str(errmsg)); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, errmsg); return $R_CONT(c$cont, B_None); } if (r != 0) { char errmsg[1024] = "Unable to parse address: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); return $R_CONT(c$cont, B_None); } if (inet_pton(AF_INET, (const char *)fromB_str(self->address), &(addr4.sin_addr)) == 1) { r = uv_tcp_bind(server, (const struct sockaddr *)&addr4, 0); } else if (inet_pton(AF_INET6, (const char *)fromB_str(self->address), &(addr6.sin6_addr)) == 1) { r = uv_tcp_bind(server, (const struct sockaddr *)&addr6, 0); } if (r != 0) { char errmsg[1024] = "Error in TLS bind: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); return $R_CONT(c$cont, B_None); } r = uv_listen((uv_stream_t *)server, 1024, on_new_tls_connection); if (r != 0) { char errmsg[1024] = "Error in TLS listen: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str(errmsg)); return $R_CONT(c$cont, B_None); } self->_stream = toB_int((int64_t)(intptr_t)server); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, B_None); return $R_CONT(c$cont, B_None); } B_NoneType netQ_TLSListenerD___resume__ (netQ_TLSListener self) { self->_stream = toB_int(-1); self->_tls_ctx = toB_int(-1); $action2 f = ($action2)self->on_listen; f->$class->__asyn__(f, self, to$str("resume")); return B_None; } $R netQ_TLSListenConnectionD__initG_local (netQ_TLSListenConnection self, $Cont c$cont) { pin_actor_affinity(); tlsuv_stream_t *stream = (tlsuv_stream_t *)fromB_int(self->server_stream); stream->data = self; self->_stream = toB_int((int64_t)(intptr_t)stream); return $R_CONT(c$cont, B_None); } $R netQ_TLSListenConnectionD__read_startG_local (netQ_TLSListenConnection self, $Cont c$cont) { tlsuv_stream_t *stream = (tlsuv_stream_t *)fromB_int(self->_stream); if ((intptr_t)stream == -1) return $R_CONT(c$cont, B_None); int r = tlsuv_stream_read_start(stream, alloc_buffer, tls_listener_on_receive); if (r < 0) { char errmsg[1024] = "Failed to start reading from TLS listen socket: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_error; f->$class->__asyn__(f, self, to$str(errmsg)); return $R_CONT(c$cont, B_None); } return $R_CONT(c$cont, B_None); } $R netQ_TLSListenConnectionD_writeG_local (netQ_TLSListenConnection self, $Cont c$cont, B_bytes data) { tlsuv_stream_t *stream = (tlsuv_stream_t *)fromB_int(self->_stream); if ((intptr_t)stream == -1) return $R_CONT(c$cont, B_None); uv_write_t *wreq = (uv_write_t *)acton_malloc(sizeof(uv_write_t)); wreq->data = self; uv_buf_t buf = uv_buf_init((char *)data->str, data->nbytes); int r = tlsuv_stream_write(wreq, stream, &buf, tls_listener_write_cb); if (r < 0) { char errmsg[1024] = "Failed to write to TLS listen socket: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_error; f->$class->__asyn__(f, self, to$str(errmsg)); } return $R_CONT(c$cont, B_None); } $R netQ_TLSListenConnectionD_closeG_local (netQ_TLSListenConnection self, $Cont c$cont) { tlsuv_stream_t *stream = (tlsuv_stream_t *)fromB_int(self->_stream); if ((intptr_t)stream == -1) return $R_CONT(c$cont, B_None); tls_listener_close_stream(stream); self->_stream = toB_int(-1); return $R_CONT(c$cont, B_None); } B_NoneType netQ_TLSListenConnectionD___resume__ (netQ_TLSListenConnection self) { self->server_stream = toB_int(-1); self->_stream = toB_int(-1); return B_None; } //netQ_DNSCap netQ_TCPConnectionD__dnscap (netQ_TCPConnection self) { // netQ_DNSCap c = netQ_DNSCapG_new(void); // return c; //} static void tls_on_close(uv_handle_t* stream) { log_debug("TLS handle closed, stream: %p stream->data: %p", stream, stream->data); } static void tls_close(tlsuv_stream_t *stream) { log_debug("Closing TLS stream: %p stream->data: %p", stream, stream->data); netQ_TLSConnection self = (netQ_TLSConnection)stream->data; $action on_close = self->_on_close; if (on_close) on_close->$class->__asyn__(on_close, self); tlsuv_stream_close(stream, tls_on_close); self->_stream = toB_int(-1); } void tls_on_receive(uv_stream_t *stream, ssize_t nread, const uv_buf_t* buf) { netQ_TLSConnection self = ((tlsuv_stream_t *)stream)->data; if (nread > 0) { if (stream->data) { $action2 f = ($action2)self->on_receive; B_bytes data = to$bytesD_len(buf->base, nread); f->$class->__asyn__(f, self, data); self->_bytes_in->val += nread; } } else if (nread == UV_EOF) { log_debug("TLS connection closed %p", stream); tls_close((tlsuv_stream_t *)stream); if (self->on_remote_close) { $action f = ($action)self->on_remote_close; f->$class->__asyn__(f, self); } } else if (nread < 0) { log_debug("TLS read error %ld: %s", nread, uv_strerror((int) nread)); tls_close((tlsuv_stream_t *)stream); } } void tls_write_cb(uv_write_t *wreq, int status) { if (status < 0) { log_debug("TLS write error %d: %s", status, uv_strerror(status)); char errmsg[1024] = "Failed to write to TLS TCP socket: "; uv_strerror_r(status, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_debug(errmsg); netQ_TLSConnection self = (netQ_TLSConnection)wreq->data; $action2 on_error = ($action2)self->on_error; on_error->$class->__asyn__(on_error, self, to$str(errmsg)); tls_close((tlsuv_stream_t *)wreq->handle); } } $R netQ_TLSConnectionD_closeG_local (netQ_TLSConnection self, $Cont c$cont, $action on_close) { uv_stream_t *stream = (uv_stream_t *)fromB_int(self->_stream); // fd == -1 means invalid FD and can happen after __resume__ if ((intptr_t)stream == -1) return $R_CONT(c$cont, B_None); self->_on_close = on_close; log_debug("Closing TLS TCP connection"); tls_close((tlsuv_stream_t *)stream); // TODO: implement on_error? but tlsuv_stream_close always returns 0 and in // the on_close callback the ->data is already NULL so how to find our actor // and real callback? return $R_CONT(c$cont, B_None); } $R netQ_TLSConnectionD_writeG_local (netQ_TLSConnection self, $Cont c$cont, B_bytes data) { tlsuv_stream_t *stream = (tlsuv_stream_t *)fromB_int(self->_stream); // fd == -1 means invalid FD and can happen after __resume__ if ((intptr_t)stream == -1) return $R_CONT(c$cont, B_None); uv_write_t *wreq = (uv_write_t *)acton_malloc(sizeof(uv_write_t)); wreq->data = self; uv_buf_t buf = uv_buf_init((char *)data->str, data->nbytes); int r = tlsuv_stream_write(wreq, stream, &buf, tls_write_cb); if (r < 0) { char errmsg[1024] = "Failed to write to TLS TCP socket: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_debug(errmsg); $action2 f = ($action2)self->on_error; f->$class->__asyn__(f, self, to$str(errmsg)); } self->_bytes_out->val += data->nbytes; return $R_CONT(c$cont, B_None); } static void tls_on_connect(uv_connect_t *creq, int status) { netQ_TLSConnection self = (netQ_TLSConnection)creq->data; if (status != 0) { char errmsg[1024] = "Error in TLS TCP connect: "; uv_strerror_r(status, errmsg + strlen(errmsg), sizeof(errmsg)-strlen(errmsg)); log_debug(errmsg); tls_close((tlsuv_stream_t *)creq->handle); self->$class->_on_tls_error(self, toB_int(-1), toB_int(status), to$str(errmsg)); return; } tlsuv_stream_t *stream = (tlsuv_stream_t *) creq->handle; tlsuv_stream_read_start(stream, alloc_buffer, tls_on_receive); self->$class->_on_tls_connect(self); } void tlsuv_logger(int level, const char *file, unsigned int line, const char *msg) { // Map tlsuv log levels to our RTS log levels int log_level; if (level == 0) { // NONE, used to say "we don't want logs" // not actually used for any log messages, so this should be unreachable return; } else if (level == 1) { // ERR log_level = LOG_ERROR; } else if (level == 2) { // WARN log_level = LOG_WARN; } else if (level == 3) { // INFO log_level = LOG_INFO; } else if (level == 4) { // DEBG log_level = LOG_DEBUG; } else if (level == 5) { // VERB log_level = LOG_DEBUG; } else if (level == 6) { // TRACE log_level = LOG_TRACE; } log_log(log_level, file, line, msg); } $R netQ_TLSConnectionD__connect_tlsG_local (netQ_TLSConnection self, $Cont c$cont) { uv_connect_t* connect_req = (uv_connect_t*)acton_calloc(1, sizeof(uv_connect_t)); connect_req->data = (void *)self; //tlsuv_set_debug(5, tlsuv_logger); tlsuv_stream_t *stream = (tlsuv_stream_t *)acton_malloc(sizeof(tlsuv_stream_t)); tlsuv_stream_init(get_uv_loop(), stream, NULL); // Default is to verify TLS certificate. Should we disable verification? if (fromB_bool(self->verify_tls) == false) { log_debug("TLS certificate verification disabled"); stream->authmode = 0; // 0=none, 2=require (mbedtls specific) } // TODO: take ALPN as input to TLSConnection actor //const char *alpn[] = { "http/1.1" }; int num_protocols = self->protocols->length; if (num_protocols > 0) { const char **protocols = (const char **)acton_calloc(num_protocols, sizeof(char*)); for(int i = 0; i < num_protocols; ++i) { protocols[i] = (const char *)fromB_str(self->protocols->data[i]); } tlsuv_stream_set_protocols(stream, num_protocols, protocols); } //tlsuv_stream_set_protocols(stream, 1, alpn); // No ALPN for now. // TODO: take SNI as input to TLSConnection actor stream->data = (void *)self; tlsuv_stream_connect(connect_req, stream, (const char *)fromB_str(self->address), fromB_int(self->port), tls_on_connect); self->_stream = toB_int((int64_t)(intptr_t)stream); return $R_CONT(c$cont, B_None); } $R netQ_TLSConnectionD__pin_affinityG_local (netQ_TLSConnection self, $Cont c$cont) { pin_actor_affinity(); return $R_CONT(c$cont, B_None); } ================================================ FILE: base/src/process.act ================================================ """Constructs for spawning and interacting with sub-processes """ def _get_env_path() -> ?str: """Get the PATH environment variable""" NotImplemented class ProcessCap(): """Capability to start processes""" def __init__(self, cap: WorldCap): pass actor Process(cap: ProcessCap, cmd: list[str], on_stdout: action(Process, ?bytes) -> None, on_stderr: action(Process, ?bytes) -> None, on_exit: action(Process, int, int) -> None, on_error: action(Process, str) -> None, workdir: ?str=None, env: ?dict[str, str]=None, timeout: ?float=None): """A process - cap: capability to start processes - cmd: the command to run - on_stdout: stdout callback actor method - on_stderr: stderr callback actor method - on_exit: exit callback - process - exit code - signal that caused program to exit - on_error: error callback - workdir: working directory, use None for current directory - env: environment for process, use None to inherit current environment When a new env is provided and it does not have PATH set, PATH is inherited from the current env. The PATH variable in the new env, regardless if the new env is inherited or provided, is used to find the executable specified by cmd (unless cmd is a path). - timeout: time in seconds before process is stopped """ _p = 0 var new_env = env action def aid() -> int: """Actor ID of process actor Workaround for lack of working repr on actors. """ NotImplemented proc def _create_process(): """Do the C magic to actually create a process and talk to it """ NotImplemented action def done_writing() -> None: """Close stdin of process Closing stdin allows cat to terminate """ NotImplemented action def pid() -> ?int: """Get PID of process or None if the process is not running """ NotImplemented action def signal(signal: int) -> None: """Send signal to process Sends the provided signal to the process. """ NotImplemented action def write(data: bytes) -> None: """Write data to stdin of process """ NotImplemented action def kill(): """Abrubtly kill process by sending SIGKILL """ signal(9) action def terminate(): """Stop process by sending SIGTERM """ signal(15) def stop(): """Stop process Attempts to stop process using normal means, which means SIGTERM on a Unix system. After 1 second, SIGKILL is sent to ensure the process is stopped. """ terminate() after 1.0: kill() # Handle PATH inheritance for custom environments # When PATH is not explicitly set in the provided environment, inherit it # from the current environment (if set in the current environment). if env is not None and "PATH" not in env: parent_path = _get_env_path() if parent_path is not None: new = dict(env.items()) new["PATH"] = parent_path new_env = new _create_process() if timeout is not None: after timeout: stop() actor RunProcess(cap: ProcessCap, cmd: list[str], on_exit: action(Process, int, int, bytes, bytes) -> None, on_error: action(Process, str) -> None, workdir: ?str, env: ?dict[str, str], timeout: ?float=None): """Run a process and wait for it to finish """ var out_buf = b"" var err_buf = b"" var _out_done = False var _err_done = False var _exited = False var _exit_code = 0 var _signal = 0 var _process: ?Process = None def _on_stdout(p: Process, data: ?bytes): if data is not None: out_buf += data else: _out_done = True _check_done() def _on_stderr(p: Process, data: ?bytes): if data is not None: err_buf += data else: _err_done = True _check_done() def _on_exit(p: Process, exit_code: int, signal: int): _exited = True _exit_code = exit_code _signal = signal _check_done() def _check_done(): if _process is not None: if _out_done and _err_done and _exited: on_exit(_process, _exit_code, _signal, out_buf, err_buf) _p = Process(cap, cmd, _on_stdout, _on_stderr, _on_exit, on_error, workdir, env, timeout) _process = _p def signal(sig: int): """Send signal to process""" _p.signal(sig) def kill(): """Abrubtly kill process by sending SIGKILL """ _p.kill() def terminate(): """Stop process by sending SIGTERM """ _p.terminate() def stop(): """Stop process Attempts to stop process using normal means, which means SIGTERM on a Unix system. After kill_after seconds (defaults to 1), SIGKILL is sent to ensure the process is stopped. """ _p.stop() ================================================ FILE: base/src/process.ext.c ================================================ #include "rts/common.h" #include #include "../rts/io.h" #include "../rts/log.h" void processQ___ext_init__() { // NOP } struct process_data { processQ_Process process; $action on_stdout; $action on_stderr; $action on_exit; uv_pipe_t stdin_pipe; uv_pipe_t stdout_pipe; uv_pipe_t stderr_pipe; }; void exit_handler(uv_process_t *req, int64_t exit_status, int term_signal) { struct process_data *process_data = req->data; uv_handle_t *stdin_handle = (uv_handle_t *)&process_data->stdin_pipe; // Ensure stdin is closed properly. stdin might be closed already from // done_writing, so check if it's closing first if (uv_is_closing(stdin_handle) == 0) uv_close(stdin_handle, NULL); // Close the process handle uv_close((uv_handle_t *)req, NULL); process_data->process->_p = toB_int(0); // Trigger the on_exit callback $action3 f = ($action3)process_data->on_exit; f->$class->__asyn__(f, process_data->process, toB_int(exit_status), toB_int(term_signal)); } void read_stderr(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { struct process_data *process_data = (struct process_data *)stream->data; processQ_Process self = process_data->process; $action2 f = ($action2)process_data->on_stderr; if (nread < 0) { if (nread == UV_EOF) { uv_close((uv_handle_t *)stream, NULL); f->$class->__asyn__(f, self, B_None); } else { // Log and handle read error log_warn("Error reading from stderr"); } } else if (nread > 0) { if (stream->data) { f->$class->__asyn__(f, self, to$bytesD_len(buf->base, nread)); } } } void read_stdout(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { struct process_data *process_data = (struct process_data *)stream->data; processQ_Process self = process_data->process; $action2 f = ($action2)process_data->on_stdout; if (nread < 0) { if (nread == UV_EOF) { uv_close((uv_handle_t *)stream, NULL); f->$class->__asyn__(f, self, B_None); } else { // Log and handle read error log_warn("Error reading from stdout"); } } else if (nread > 0) { if (stream->data) { f->$class->__asyn__(f, self, to$bytesD_len(buf->base, nread)); } } } $R processQ_ProcessD_aidG_local(processQ_Process self, $Cont c$cont) { return $R_CONT(c$cont, toB_int(self->$globkey)); } $R processQ_ProcessD__create_processG_local(processQ_Process self, $Cont c$cont) { pin_actor_affinity(); struct process_data *process_data = acton_calloc(1, sizeof(struct process_data)); process_data->process = self; process_data->on_stdout = self->on_stdout; process_data->on_stderr = self->on_stderr; process_data->on_exit = self->on_exit; uv_process_options_t *options = acton_calloc(1, sizeof(uv_process_options_t)); uv_process_t *req = acton_calloc(1, sizeof(uv_process_t)); self->_p = toB_int((long)req); req->data = process_data; char **args = (char **)acton_malloc((self->cmd->length + 1) * sizeof(char *)); for (int i = 0; i < self->cmd->length; i++) { args[i] = (char *)fromB_str(self->cmd->data[i]); } args[self->cmd->length] = NULL; if (self->workdir != B_None) { options->cwd = fromB_str(self->workdir); } if (self->new_env == B_None) { options->env = NULL; } else { char **env = (char **)acton_calloc((self->new_env->numelements + 1), sizeof(char *)); B_IteratorD_dict_items iter = $NEW(B_IteratorD_dict_items, self->new_env); B_tuple item; for (int i = 0; i < self->new_env->numelements; i++) { item = (B_tuple)iter->$class->__next__(iter); char *key = fromB_str((B_str)item->components[0]); char *value = fromB_str((B_str)item->components[1]); size_t env_size = strlen(key) + strlen(value) + 2; char *env_var = acton_malloc(env_size); snprintf(env_var, env_size, "%s=%s", key, value); env[i] = env_var; } env[self->new_env->numelements] = NULL; options->env = env; } uv_pipe_init(get_uv_loop(), &process_data->stdin_pipe, 0); uv_pipe_init(get_uv_loop(), &process_data->stdout_pipe, 0); process_data->stdout_pipe.data = process_data; uv_pipe_init(get_uv_loop(), &process_data->stderr_pipe, 0); process_data->stderr_pipe.data = process_data; uv_stdio_container_t process_stdio[3]; options->stdio = process_stdio; process_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; process_stdio[0].data.stream = (uv_stream_t *)&(process_data->stdin_pipe); process_stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; process_stdio[1].data.stream = (uv_stream_t *)&(process_data->stdout_pipe); process_stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; process_stdio[2].data.stream = (uv_stream_t *)&(process_data->stderr_pipe); options->stdio_count = 3; options->exit_cb = exit_handler; options->file = args[0]; options->args = args; int r = uv_spawn(get_uv_loop(), req, options); if (r != 0) { char errmsg[1024] = "Failed to spawn process: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg)); log_warn(errmsg); $action2 f = ($action2)self->on_error; f->$class->__asyn__(f, process_data->process, to$str(errmsg)); return $R_CONT(c$cont, B_None); } // TODO: do we need to do some magic to read any data produced before this // callback is installed? uv_read_start((uv_stream_t *)&process_data->stdout_pipe, alloc_buffer, read_stdout); uv_read_start((uv_stream_t *)&process_data->stderr_pipe, alloc_buffer, read_stderr); return $R_CONT(c$cont, B_None); } void close_cb(uv_handle_t *handle) { // TODO: clean something up? } $R processQ_ProcessD_done_writingG_local(processQ_Process self, $Cont c$cont) { uv_process_t *p = (uv_process_t *)fromB_int(self->_p); struct process_data *process_data = (struct process_data *)p->data; uv_handle_t *stdin_handle = (uv_handle_t *)&process_data->stdin_pipe; // Ensure stdin is closed properly. stdin might be closed already from // exit_handler, so check if it's closing first if (uv_is_closing(stdin_handle) == 0) uv_close(stdin_handle, close_cb); return $R_CONT(c$cont, B_None); } $R processQ_ProcessD_pidG_local(processQ_Process self, $Cont c$cont) { uv_process_t *p = (uv_process_t *)fromB_int(self->_p); if (p == 0) { log_warn("Process has exited, ignoring PID request"); return $R_CONT(c$cont, B_None); } return $R_CONT(c$cont, (B_atom)toB_int(p->pid)); } $R processQ_ProcessD_signalG_local(processQ_Process self, $Cont c$cont, B_int signal) { uv_process_t *p = (uv_process_t *)fromB_int(self->_p); if (p == 0) { log_warn("Process has exited, ignoring signal request"); return $R_CONT(c$cont, B_None); } uv_process_kill(p, fromB_int(signal)); return $R_CONT(c$cont, B_None); } $R processQ_ProcessD_writeG_local(processQ_Process self, $Cont c$cont, B_bytes data) { uv_process_t *p = (uv_process_t *)fromB_int(self->_p); if (p == 0) { log_warn("Process has exited, ignoring write request"); return $R_CONT(c$cont, B_None); } uv_write_t *req = (uv_write_t *)acton_malloc(sizeof(uv_write_t)); uv_buf_t buf = uv_buf_init(data->str, data->nbytes); struct process_data *process_data = (struct process_data *)p->data; uv_stream_t *stdin_handle = (uv_stream_t *)&process_data->stdin_pipe; int r = uv_write(req, stdin_handle, &buf, 1, NULL); if (r != 0) { char errmsg[1024] = "Error writing to stdin of process: "; uv_strerror_r(r, errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg)); log_warn(errmsg); } return $R_CONT(c$cont, B_None); } B_str processQ__get_env_path() { size_t path_size = 1024; // Initial buffer size char *path_buf = acton_malloc(path_size); int r = uv_os_getenv("PATH", path_buf, &path_size); if (r == UV_ENOBUFS) { // Buffer too small, reallocate with required size acton_free(path_buf); path_buf = acton_malloc(path_size); r = uv_os_getenv("PATH", path_buf, &path_size); } if (r != 0) { // If PATH is not set or other error occurred, return None acton_free(path_buf); return (B_str)B_None; } B_str result = to$str(path_buf); acton_free(path_buf); return result; } ================================================ FILE: base/src/qcheck.act ================================================ from random import * def qcheck_int_1(name: str, prop: (int) -> bool, verbose = False)->int: print("Testing",name) i: int = 1 while i <= 100: m = i*i a = randint(-m,m) if not prop(a): print(" ",name,"failed after",i,"tests:\n",a,"\n") return 1 else: if verbose: print(" Argument =",a,"; passed") i += 1 print(" OK,",name,"passed 100 tests\n") return 0 def qcheck_int_2(name: str, prop: (int, int) -> bool, verbose = False)->int: print("Testing",name) i: int = 1 while i <= 100: m = i*i a = randint(-m,m) b = randint(-m,m) if not prop(a,b): print(" ",name,"failed after",i,"tests:\n",a,"\n",b) return 1 else: if verbose: print(" Argument 1 =",a," argument 2 =",b,"; passed") i += 1 print(" OK,",name,"passed 100 tests\n") return 0 def qcheck_bigint_1(name: str, prop: (bigint) -> bool, verbose = False)->int: print("Testing",name) i= 1 while i <= 100: m = 2+i//2 a = rand_bigint(m) if not prop(a): print(" ",name,"failed after",i,"tests:\n",a) return 1 else: if verbose: print(" Argument =",a,"; passed") i += 1 print(" OK,",name,"passed 100 tests\n") return 0 def qcheck_bigint_2(name: str, prop: (bigint, bigint) -> bool, verbose = False)->int: print("Testing",name) i= 1 while i <= 100: a = rand_bigint(randint(2,i+2)) b = rand_bigint(randint(2,i+2)) if not prop(a,b): print(" ",name,"failed after",i,"tests:\n",a,"\n",b) return 1 else: if verbose: print(" Argument 1 =",a," argument 2 =",b,"; passed") i += 1 print(" OK,",name,"passed 100 tests\n") return 0 def qcheck_bigint_int(name: str, prop: (bigint, int) -> bool, verbose = False)->int: print("Testing",name) i= 1 while i <= 100: a = rand_bigint(randint(2,i+2)) b = randint(-i*i,i*i) if not prop(a,b): print(" ",name,"failed after",i,"tests:\n",a,"\n",b) return 1 else: if verbose: print(" Argument 1 =",a," argument 2 =",b,"; passed") i += 1 print(" OK,",name,"passed 100 tests\n") return 0 def qcheck_0(name: str, prop: () -> bool)->int: print("Testing",name) if prop (): print(" OK,",name,"passed\n") return 0 else: print(" ",name,"failed") return 1 def qcheck_list_2(name: str, prop: (list[int], list[int]) -> bool, verbose = False)->int: print("Testing",name) i = 1 while i <= 100: a = rand_list(i) b = rand_list(i) if not prop(a,b): print(" *************",name,"FAILED AFTER",i,"TESTS:*************\n",a,"\n",b) return 1 else: if verbose: print(" Argument 1 =",a," argument 2 =",b,"; passed") i += 1 print(" OK,",name,"passed 100 tests\n") return 0 ================================================ FILE: base/src/random.act ================================================ # TODO: randint should not be pure!!! but what should it be? def randint(min: int, max: int) -> int: NotImplemented def randstr(length: int) -> str: char_set = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") res = "" for i in range(length): res += choice(char_set) return res def choice[T](sequence: Sequence[T]) -> T: """ Return a random element from the non-empty sequence. :param sequence: List or sequence to choose from. :return: A random element from the sequence. """ if len(sequence) == 0: raise ValueError('Cannot choose from an empty sequence') index = randint(0, len(sequence)) return sequence[index] def sample[T](population: list[T], k: int) -> list[T]: """ Chooses k unique random elements from a population sequence. :param population: List from which to sample. :param k: Number of unique elements to pick. :return: A new list containing elements from the population while maintaining the original sequence order. """ if not (0 <= k and k <= len(population)): raise ValueError("Sample larger than population or is negative") result = [] indices = list(range(len(population))) for _ in range(k): idx_to_pop = choice(indices) idx = 0 for i in range(len(indices)): if indices[i] == idx_to_pop: idx = i break indices.pop(idx) result.append(population[idx_to_pop]) return result def rand_bigint(size): """ Returns a randomly chosen integer (positive, zero or negative) :param size: Maximal number of decimal digits (must be positive) """ if (size <= 0): raise ValueError('decimal length of int must be positive') digits = [choice(["","-"])] for i in range(size): digits.append(choice(["0","1","2","3","4","5","6","7","8","9"])) return bigint("".join(digits)) def rand_list(size)->list[int]: """ Returns a randomly chosen list of integers. :param size: Maximal number of elements and maximal size of list elements (must be positive) """ if (size <= 0): raise ValueError('decimal length of int must be positive') res = [] for i in range(randint(0,size)): res.append(randint(-size, size)) return res ================================================ FILE: base/src/random.ext.c ================================================ #include void randomQ___ext_init__() { // seed the random number generator with nanoseconds since the epoch and our // PID uv_timespec64_t ts; uv_clock_gettime(UV_CLOCK_MONOTONIC, &ts); srand(ts.tv_nsec ^ pid); } // NOTE: the standard srand / rand functions are not thread safe, but what does // that really mean in this context? While we could use thread safe functions // for deterministic random numbers (based on the seed), we won't guarantee // deterministic scheduling of actors on our RTS threads and so there still // would not be a guarantee for thread safe random numbers. Also, having to call // srand to seed reflects the C implementation, which we're not keen on doing - // rather we want it Pythonic - you should be able to get a random number with a // single call to random.randint(1, 3). So instead we just seed on startup with // the time, which is prolly good enough for now. In a future, we could cook up // something better. long randlong (long min, long max) { // ensure we have a valid range where min is smaller than max if (min > max) { $RAISE(((B_BaseException)B_ValueErrorG_new(to$str("min value must be smaller than max")))); } // upper end of the range we want when "based to 0" long range = max - min; // chop off all values that would cause skew, leaving only things within the // range that maps up to a multiple of the specified range long end = RAND_MAX / range; // new end end *= range; // run rand() until we get a value below end long r; // spin getting new values until we find one in range while ((r = rand()) >= end); // normalize back to the requested range return min + r%range; } int64_t randomQ_U_randint(int64_t min, int64_t max) { return randlong(min,max); } ================================================ FILE: base/src/re.act ================================================ #class Pattern(): # pass # #class Or(Pattern): # def __init__(self, p: list[Pattern]): # self.p = p # # def __str__(self): # res = "(" # l = len(self.p) # for i in range(l): # res += str(self.p[i]) # if i < l-1: # res += "|" # res += ")" # return res # #class Text(Pattern): # """Literal text # """ # def __init__(self, t: str): # self.text = t # # TODO: complete patterns for escaping re patterns # self.re_text = t.replace(".", r"\.", None).replace("?", r"\?", None) # # def __str__(self): # return self.re_text class Match: def __init__(self, pattern: str, string: str, start_pos: int, end_pos: int, group: list[?str], named_group: dict[str, ?str]) -> None: self.pattern = pattern self.string = string self.start_pos = start_pos self.end_pos = end_pos self.group = group self.named = named_group # TODO: add _compile function to compile a pattern to a regex, and use it in # _match function to avoid recompiling the pattern each time def _match(pattern: str, string: str, start_pos: int) -> ?Match: NotImplemented def match(pattern: str, string: str, start_pos: int=0) -> ?Match: """Scan through string looking for a match to the pattern, returning a match object, or None if no match was found. start_pos sets the index to begin scanning at. """ return _match(pattern, string, start_pos) def matches(pattern: str, string: str) -> list[Match]: """Find all non-overlapping matches in string """ # TODO: implement as a generator instead res = [] pos = 0 str_len = len(string) while True: if pos >= str_len: break m = _match(pattern, string, pos) if m is None: break if m is not None: res.append(m) if m.end_pos == pos: # Zero-width match: move forward one character if possible if pos < str_len: pos += 1 else: # At the very end, just break break else: pos = m.end_pos return res def split(pattern: str, subject: str, max_split: int=0) -> list[str]: if pattern == "": raise ValueError("empty pattern") result = [] splits_done = 0 pos = 0 str_len = len(subject) while True: if max_split != 0 and splits_done >= max_split: # Reached maximum number of splits break m = _match(pattern, subject, pos) if m is not None: # Append substring before match (normal match) if m.end_pos > pos: result.append(subject[pos:m.start_pos]) if len(m.group) > 1: for g in m.group[1:]: result.append(g if g is not None else "") pos = m.end_pos splits_done += 1 else: # Zero-width match if pos == 0: # At the start: append empty substring to indicate a split at the start result.append(subject[pos:m.start_pos]) else: # Not at the start: do not append empty substring # If there are capturing groups, append them (if any) if len(m.group) > 1: for g in m.group[1:]: result.append(g if g is not None else "") # After handling zero-width match, break to avoid infinite loops break else: # No match found break # Append remainder result.append(subject[pos:]) return result ================================================ FILE: base/src/re.ext.c ================================================ #define PCRE2_CODE_UNIT_WIDTH 8 #include static void *pcre2_malloc(size_t size, void *data) { (void)data; return acton_malloc(size); } static void pcre2_free(void *ptr, void *data) {} pcre2_compile_context *compile_context; pcre2_general_context *general_context; void reQ___ext_init__() { general_context = pcre2_general_context_create(pcre2_malloc, pcre2_free, NULL); if (general_context == NULL) { // Handle error assert(0); } compile_context = pcre2_compile_context_create(general_context); } // TODO: use u64 instead of int for arg_start_pos reQ_Match reQ_U__match (B_str arg_pattern, B_str arg_text, int64_t arg_start_pos) { B_Hashable hwit = (B_Hashable)B_HashableD_strG_witness; B_SequenceD_list swit = B_SequenceD_listG_witness; B_list groups = B_listG_new(NULL, NULL); B_dict named_groups = $NEW(B_dict, hwit, NULL, NULL); PCRE2_SPTR pattern = (PCRE2_SPTR)fromB_str(arg_pattern); PCRE2_SPTR text = (PCRE2_SPTR)fromB_str(arg_text); size_t text_length = strlen((char *)text); // TODO: use u64 instead of int to eradicate possibility of < 0 // Validate start_pos long start_offset = arg_start_pos; if (start_offset < 0) { $RAISE(((B_BaseException)B_ValueErrorG_new(to_str_noc("PCRE2 matching failed: negative start_pos")))); } if ((size_t)start_offset > text_length) { $RAISE(((B_BaseException)B_ValueErrorG_new(to_str_noc("start position is greater than string length")))); } int errornumber; PCRE2_SIZE erroroffset; pcre2_code *re = pcre2_compile( pattern, PCRE2_ZERO_TERMINATED, PCRE2_UTF, &errornumber, &erroroffset, compile_context ); if (re == NULL) { PCRE2_UCHAR buffer[256]; pcre2_get_error_message(errornumber, buffer, sizeof(buffer)); char errmsg[1024] = "regex compilation failed at offset "; snprintf(errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg), "%d: %s", (int)erroroffset, buffer); $RAISE(((B_BaseException)B_ValueErrorG_new(to$str(errmsg)))); } pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL); int rc = pcre2_match( re, text, text_length, (PCRE2_SIZE)start_offset, 0, match_data, NULL ); if (rc < 0) { pcre2_match_data_free(match_data); pcre2_code_free(re); if (rc == PCRE2_ERROR_NOMATCH) { return B_None; } else { // Some other error char errmsg[256]; snprintf(errmsg, sizeof(errmsg), "PCRE2 matching error: %d", rc); $RAISE(((B_BaseException)B_RuntimeErrorG_new(to$str(errmsg)))); } } PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data); if (rc == 0) { pcre2_match_data_free(match_data); pcre2_code_free(re); $RAISE(((B_BaseException)B_RuntimeErrorG_new(to_str_noc("ovector was not big enough for all captured substrings")))); } // Extract all unnamed groups // group 0 is the entire match, group 1... are subgroups for (int i = 0; i < rc; i++) { PCRE2_SIZE ss_start = ovector[2*i]; PCRE2_SIZE ss_end = ovector[2*i+1]; if (ss_start == PCRE2_UNSET || ss_end == PCRE2_UNSET) { swit->$class->append(swit, groups, B_None); } else { size_t substring_length = ss_end - ss_start; char *substring = acton_malloc_atomic(substring_length + 1); memcpy(substring, text + ss_start, substring_length); substring[substring_length] = '\0'; swit->$class->append(swit, groups, to_str_noc(substring)); } } // Named groups int namecount; pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &namecount); if (namecount > 0) { PCRE2_SPTR name_table; int name_entry_size; pcre2_pattern_info(re, PCRE2_INFO_NAMETABLE, &name_table); pcre2_pattern_info(re, PCRE2_INFO_NAMEENTRYSIZE, &name_entry_size); PCRE2_SPTR tabptr = name_table; for (int i = 0; i < namecount; i++) { int n = (tabptr[0] << 8) | tabptr[1]; // group number for this name // The name itself starts at tabptr+2 and has length (name_entry_size-2) int namelen = name_entry_size - 2; char *group_name = acton_malloc_atomic(namelen + 1); memcpy(group_name, tabptr+2, namelen); group_name[namelen] = '\0'; PCRE2_SIZE ss_start = ovector[2*n]; PCRE2_SIZE ss_end = ovector[2*n+1]; if (ss_start == PCRE2_UNSET || ss_end == PCRE2_UNSET) { B_dictD_setitem(named_groups, hwit, to_str_noc(group_name), B_None); } else { size_t substring_length = ss_end - ss_start; char *substring = acton_malloc_atomic(substring_length + 1); memcpy(substring, text + ss_start, substring_length); substring[substring_length] = '\0'; B_dictD_setitem(named_groups, hwit, to_str_noc(group_name), to_str_noc(substring)); } tabptr += name_entry_size; } } // Entire match offsets PCRE2_SIZE match_start = ovector[0]; PCRE2_SIZE match_end = ovector[1]; pcre2_match_data_free(match_data); pcre2_code_free(re); return reQ_MatchG_new(arg_pattern, arg_text, toB_int(match_start), toB_int(match_end), groups, named_groups); } ================================================ FILE: base/src/snappy.act ================================================ def compress(data: bytes) -> bytes: """Compress data using Snappy """ NotImplemented def decompress(data: bytes) -> bytes: """Decompress Snappy data """ NotImplemented ================================================ FILE: base/src/snappy.ext.c ================================================ #include "../rts/io.h" #include "../rts/log.h" #include void snappyQ___ext_init__() { // NOP } B_bytes snappyQ_compress (B_bytes data) { char *input; char *compressed; size_t input_len; size_t compressed_len; snappy_status status; B_bytes ret; input = (char*)fromB_bytes(data); input_len = (size_t)data->nbytes; compressed_len = snappy_max_compressed_length(input_len); compressed = acton_malloc(compressed_len); status = snappy_compress(input, input_len, compressed, &compressed_len); if (SNAPPY_OK == status) { ret = to$bytesD_len(compressed, (int)compressed_len); } else { char *errmsg = SNAPPY_INVALID_INPUT == status ? "Invalid input" : "Buffer too small"; $RAISE((B_BaseException)$NEW(B_ValueError, to$str(errmsg))); } return ret; } B_bytes snappyQ_decompress (B_bytes data) { char *input; char *uncompressed; size_t input_len; size_t uncompressed_len; snappy_status status; B_bytes ret; input = (char*)fromB_bytes(data); input_len = (size_t)data->nbytes; status = snappy_uncompressed_length(input, input_len, &uncompressed_len); if (SNAPPY_OK != status) { char *errmsg = (SNAPPY_INVALID_INPUT == status) ? "Invalid input" : "Buffer too small"; $RAISE((B_BaseException)$NEW(B_ValueError, to$str(errmsg))); } uncompressed = acton_malloc(uncompressed_len); snappy_uncompress(input, input_len, uncompressed, &uncompressed_len); if (SNAPPY_OK == status) { ret = to$bytesD_len(uncompressed, (int)uncompressed_len); } else { char *errmsg = SNAPPY_INVALID_INPUT == status ? "Invalid input" : "Buffer too small"; $RAISE((B_BaseException)$NEW(B_ValueError, to$str(errmsg))); } return ret; } ================================================ FILE: base/src/term.act ================================================ normal = "\x1b[0m" bold = "\x1b[1m" underline = "\x1b[4m" blink = "\x1b[5m" reverse = "\x1b[7m" # colors red = "\x1b[31m" green = "\x1b[32m" yellow = "\x1b[33m" blue = "\x1b[34m" magenta = "\x1b[35m" cyan = "\x1b[36m" white = "\x1b[37m" grey1 = "\x1b[38;5;232m" grey2 = "\x1b[38;5;233m" grey3 = "\x1b[38;5;234m" grey4 = "\x1b[38;5;235m" grey5 = "\x1b[38;5;236m" grey6 = "\x1b[38;5;237m" grey7 = "\x1b[38;5;238m" grey8 = "\x1b[38;5;239m" grey9 = "\x1b[38;5;240m" grey10 = "\x1b[38;5;241m" grey11 = "\x1b[38;5;242m" grey12 = "\x1b[38;5;243m" grey13 = "\x1b[38;5;244m" grey14 = "\x1b[38;5;245m" grey15 = "\x1b[38;5;246m" grey16 = "\x1b[38;5;247m" grey17 = "\x1b[38;5;248m" grey18 = "\x1b[38;5;249m" grey19 = "\x1b[38;5;250m" grey20 = "\x1b[38;5;251m" grey21 = "\x1b[38;5;252m" grey22 = "\x1b[38;5;253m" grey23 = "\x1b[38;5;254m" grey24 = "\x1b[38;5;255m" # background colors bg_red = "\x1b[41m" bg_green = "\x1b[42m" bg_yellow = "\x1b[43m" bg_blue = "\x1b[44m" bg_magenta = "\x1b[45m" bg_cyan = "\x1b[46m" bg_white = "\x1b[47m" clear = "\x1b[0J" top = "\x1b[H" def up(n=1): """Move cursor up n lines. """ if n < 0: raise ValueError("n must be >= 0") res = "" for i in range(n): res += "\x1b[A" return res def down(n=1): """Move cursor down n lines. """ if n < 0: raise ValueError("n must be >= 0") res = "" for i in range(n): res += "\x1b[B" return res def right(n=1): """Move cursor right n columns. """ if n < 0: raise ValueError("n must be >= 0") res = "" for i in range(n): res += "\x1b[C" return res def left(n=1): """Move cursor left n columns. """ if n < 0: raise ValueError("n must be >= 0") res = "" for i in range(n): res += "\x1b[D" return res clearline = "\x1b[0G\x1b[2K" ================================================ FILE: base/src/testing.act ================================================ import acton.rts import argparse import diff import file import json import logging import term import time # -- assert --------------------------------------------------------------------- def opt_str[T](s: ?T) -> str: return str(s) if s is not None else "None" class NotEqualError[T](AssertionError): a: ?T b: ?T def __init__(self, a, b, msg: ?str=None, print_vals: bool=True, diff_str: ?str=None): self.a = a self.b = b self.error_message = msg if msg is not None else "Expected equal values but they are non-equal." self.print_vals = print_vals self.diff_str = diff_str def __str__(self): msg = f"{self._name()}: {self.error_message}" if self.print_vals: msg += f" A: {self.a}" msg += f" B: {self.b}" ds = self.diff_str if ds is not None: msg += "\n" + ds return msg def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.b)}, {repr(self.error_message)}, {repr(self.print_vals)}, {repr(self.diff_str)})" class EqualError[T](AssertionError): a: ?T b: ?T def __init__(self, a, b, msg: ?str=None, print_vals: bool=True): self.a = a self.b = b self.error_message = msg if msg is not None else "Expected non-equal values but they are equal." self.print_vals = print_vals def __str__(self): msg = f"{self._name()}: {self.error_message}" if self.print_vals: msg += f" A: {self.a}" msg += f" B: {self.b}" return msg def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.b)}, {repr(self.error_message)}, {repr(self.print_vals)})" class NotTrueError[T](AssertionError): a: ?T def __init__(self, a, msg: ?str=None, print_vals: bool=True): self.a = a self.error_message = msg if msg is not None else "Expected True but got non-True" self.print_vals = print_vals def __str__(self): msg = f"{self._name()}: {self.error_message}" if self.print_vals: msg += f", value: {self.a}" return msg def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.error_message)}, {repr(self.print_vals)})" class NotFalseError[T](AssertionError): a: ?T def __init__(self, a, msg: ?str=None, print_vals: bool=True): self.a = a self.error_message = msg if msg is not None else "Expected False but got non-False." self.print_vals = print_vals def __str__(self): msg = f"{self._name()}: {self.error_message}" if self.print_vals: msg += f", value: {self.a}" return msg def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.error_message)}, {repr(self.print_vals)})" class NotNoneError[T](AssertionError): a: ?T def __init__(self, a, msg: ?str=None, print_vals: bool=True): self.a = a self.error_message = msg if msg is not None else "Expected None but got non-None." self.print_vals = print_vals def __str__(self): msg = f"{self._name()}: {self.error_message}" if self.print_vals: msg += f", value: {self.a}" return msg def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.error_message)}, {repr(self.print_vals)})" class NoneError[T](AssertionError): a: ?T def __init__(self, a, msg: ?str=None, print_vals: bool=True): self.a = a self.error_message = msg if msg is not None else "Expected non-None but got None." self.print_vals = print_vals def __str__(self): msg = f"{self._name()}: {self.error_message}" if self.print_vals: a = self.a msg += f", value: {a}" return msg def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.error_message)}, {repr(self.print_vals)})" class NotInError[T,U](AssertionError): a: ?T b: ?U def __init__(self, a, b, msg: ?str=None, print_vals: bool=True): self.a = a self.b = b self.error_message = msg if msg is not None else "Expected element not in container" self.print_vals = print_vals def __str__(self): msg = f"{self._name()}: {self.error_message}" if self.print_vals: msg += f", element: {self.a}" msg += f", container: {self.b}" return msg def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.b)}, {repr(self.error_message)}, {repr(self.print_vals)})" class InError[T,U](AssertionError): a: ?T b: ?U def __init__(self, a, b, msg: ?str=None, print_vals: bool=True): self.a = a self.b = b self.error_message = msg if msg is not None else "Expected element in container" self.print_vals = print_vals def __str__(self): msg = f"{self._name()}: {self.error_message}" if self.print_vals: msg += f", element: {self.a}" msg += f", container: {self.b}" return msg def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.b)}, {repr(self.error_message)}, {repr(self.print_vals)})" class NotIsError[T](AssertionError): a: T b: T def __init__(self, a, b, msg: ?str=None, print_vals: bool=True): self.a = a self.b = b self.error_message = msg if msg is not None else "Expected both objects to be the same identity (is)" self.print_vals = print_vals def __str__(self): msg = f"{self._name()}: {self.error_message}" if self.print_vals: msg += f" A: {str(self.a)}" msg += f" B: {str(self.b)}" return msg def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.b)}, {repr(self.error_message)}, {repr(self.print_vals)})" class IsError[T](AssertionError): a: T b: T def __init__(self, a, b, msg: ?str=None, print_vals: bool=True): self.a = a self.b = b self.error_message = msg if msg is not None else "Expected both objects to be different identities (is not)" self.print_vals = print_vals def __str__(self): msg = f"{self._name()}: {self.error_message}" if self.print_vals: msg += f" A: {str(self.a)}" msg += f" B: {str(self.b)}" return msg def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.b)}, {repr(self.error_message)}, {repr(self.print_vals)})" class NotRaisesError(AssertionError): def __init__(self, msg: ?str=None, print_vals: bool=True): self.error_message = msg if msg is not None else "Expected exception not raised" self.print_vals = print_vals def __repr__(self): return f"{self._name()}({repr(self.error_message)}, {repr(self.print_vals)})" class IsInstanceError[T](AssertionError): a: ?T t: str def __init__(self, a, t: str, msg: ?str=None, print_vals: bool=True): self.a = a self.t = t self.error_message = msg if msg is not None else "expected type of specific instance" self.print_vals = print_vals def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.t)}, {repr(self.error_message)}, {repr(self.print_vals)})" class NotIsInstanceError[T](AssertionError): a: ?T t: str def __init__(self, a, t: str, msg: ?str=None, print_vals: bool=True): self.a = a self.t = t self.error_message = msg if msg is not None else "expected type of specific instance" self.print_vals = print_vals def __repr__(self): return f"{self._name()}({repr(self.a)}, {repr(self.t)}, {repr(self.error_message)}, {repr(self.print_vals)})" def assertEqual[T(Eq)](a: ?T, b: ?T, msg: ?str, print_vals: bool=True, print_diff: bool=True): """Assert that two values are equal """ if ((a is None and b is not None) or (a is not None and b is None) or (a is not None and b is not None and not (a == b))): diff_str = None if print_diff: # We calculate diff here and not in NotEqualError.__str__ because the # "mut" effect leaks out of the diff() function, but __str__() must be pure diff_str = f"{term.normal}{diff.diff(str(a), str(b), color=True)}{term.normal}" raise NotEqualError(a, b, msg, print_vals, diff_str) def assertNotEqual[T(Eq)](a: ?T, b: ?T, msg: ?str, print_vals: bool=True): """Assert that two values are not equal """ if ((a is None and b is None) or (a is not None and b is not None and a == b)): raise EqualError(a, b, msg, print_vals) def assertTrue(a, msg: ?str, print_vals: bool=True): """Assert that the boolean evaluation of a value is True """ if not bool(a): raise NotTrueError(a, msg, print_vals) def assertFalse(a, msg: ?str, print_vals: bool=True): """Assert that the boolean evaluation of a value is False """ if bool(a): raise NotFalseError(a, msg, print_vals) def assertIs[T(Identity)](a: T, b: T, msg: ?str, print_vals: bool=True): """Assert that two values are the same identity, i.e. the same object """ if not (a is b): raise NotIsError(a, b, msg) def assertIsNot[T(Identity)](a: T, b: T, msg: ?str, print_vals: bool=True): """Assert that two values are not the same identity, i.e. different objects """ if a is b: raise IsError(a, b, msg) def assertNone(a, msg: ?str, print_vals: bool=True): """Assert that a value equals None """ if not (a is None): raise NotNoneError(a, msg, print_vals) def assertNotNone(a, msg: ?str, print_vals: bool=True): """Assert that a value does not equal None """ if not (a is not None): raise NoneError(a, msg, print_vals) def assertIn(a, b, msg: ?str, print_vals: bool=True): """Assert that a value is in a container """ if not (a in b): raise NotInError(a, b, msg, print_vals) def assertNotIn(a, b, msg: ?str, print_vals: bool=True): """Assert that a value is not in a container """ if a in b: raise InError(a, b, msg, print_vals) def error(msg: ?str): """Raise a generic test error""" raise AssertionError(msg if msg is not None else "Test error") # ------------------------------------------------------------------------------- def eq_opt[T(Eq)](a: ?T, b: ?T) -> bool: return a is not None and b is not None and a == b or a is None and b is None class TestLogger(logging.Logger): pass class SkipTest(AssertionError): pass class AbortTest(Exception): pass class SyncT(value): def __init__(self, log_handler: logging.Handler, tags: set[str]): self.log_handler = log_handler self.tags = tags def skip(self, reason: ?str="Skipped"): raise SkipTest(reason) def require(self, tag: str): if tag not in self.tags: self.skip(f"Missing required capability '{tag}' (enable with --tag {tag})") class AsyncT(value): def __init__(self, report_result: action(?bool, ?Exception, ?str) -> None, log_handler: logging.Handler, tags: set[str]): self.report_result = report_result self.log_handler = log_handler self.tags = tags def success(self, output: ?str=None): self.report_result(True, None, output) def failure(self, exception: Exception): self.report_result(False, exception, None) def error(self, exception: Exception): self.report_result(None, exception, None) def skip(self, reason: ?str="Skipped"): self.report_result(True, SkipTest(reason), None) raise AbortTest(reason) def require(self, tag: str): if tag not in self.tags: self.skip(f"Missing required capability '{tag}' (enable with --tag {tag})") class EnvT(value): def __init__(self, report_result: action(?bool, ?Exception, ?str) -> None, env: Env, log_handler: logging.Handler, tags: set[str]): self.report_result = report_result self.env = env self.log_handler = log_handler self.tags = tags def success(self, output: ?str=None): self.report_result(True, None, output) def failure(self, exception: Exception): self.report_result(False, exception, None) def error(self, exception: Exception): self.report_result(None, exception, None) def skip(self, reason: ?str="Skipped"): self.report_result(True, SkipTest(reason), None) raise AbortTest(reason) def require(self, tag: str): if tag not in self.tags: self.skip(f"Missing required capability '{tag}' (enable with --tag {tag})") class Test(object): module: str name: str desc: str def __init__(self, name: str, desc: str, module): self.name = name self.desc = desc self.module = module def display_name(self) -> str: """Return a pretty display name for the test""" n = self.name # Remove _test_ prefix if n.startswith("_test_"): n = n[6:] # Remove _wrapper suffix if n.endswith("_wrapper"): n = n[:-8] return n def run(self, report_result: action(?bool, ?Exception, ?str) -> None, env: Env, log_handler: logging.Handler, tags: set[str]): if isinstance(self, UnitTest): self.run_test(report_result, env, log_handler, tags) elif isinstance(self, SimpleSyncTest): self.run_test(report_result, env, log_handler, tags) elif isinstance(self, SyncTest): self.run_test(report_result, env, log_handler, tags) elif isinstance(self, AsyncTest): self.run_test(report_result, env, log_handler, tags) elif isinstance(self, EnvTest): self.run_test(report_result, env, log_handler, tags) else: raise ValueError("Test: Invalid test type") def to_json(self): return { "module": self.module, "name": self.name, "desc": self.desc, } @staticmethod def from_json(data: dict[str, ?value]): module = data["module"] name = data["name"] desc = data["desc"] if isinstance(module, str) and isinstance(name, str) and isinstance(desc, str): return Test(name, desc, module) raise ValueError("Test: Invalid JSON") def safe_hash(h: int) -> int: # TODO: Remove when https://github.com/actonlang/acton/issues/1348 is fixed limit = 2**63-1 sign = 1 if h < 0: limit = 2**63 sign = -1 h = -h while h > limit: f = h // limit h %= limit h += f return sign * h extension Test(Hashable): def __eq__(self, other: Test) -> bool: return self.module == other.module and self.name == other.name def hash(self, h): self.module.hash(h) self.name.hash(h) #h.update(self.module.encode()) #h.update(self.name.encode()) # def __hash__(self) -> int: # #return hash(self.data) # return safe_hash(2*hash(self.module) + 3*hash(self.name)) class UnitTest(Test): def __init__(self, fn: mut() -> None, name: str, desc: str, module: str): self.fn = fn self.name = name self.desc = desc self.module = module def run_test(self, report_result: action(?bool, ?Exception, ?str) -> None, env: Env, log_handler: logging.Handler, tags: set[str]): output = None success = None exception = None try: output = self.fn() success = True exception = None except SkipTest as e: success = True exception = e except AssertionError as e: success = False exception = e except Exception as e: success = None exception = e report_result(success, exception, output) class SimpleSyncTest(Test): def __init__(self, fn: proc() -> None, name: str, desc: str, module: str): self.fn = fn self.name = name self.desc = desc self.module = module def run_test(self, report_result: action(?bool, ?Exception, ?str) -> None, env: Env, log_handler: logging.Handler, tags: set[str]): output = None success = None exception = None try: output = self.fn() success = True exception = None except SkipTest as e: success = True exception = e except AssertionError as e: success = False exception = e except Exception as e: success = None exception = e report_result(success, exception, output) class SyncTest(Test): def __init__(self, fn: proc(SyncT) -> None, name: str, desc: str, module: str): self.fn = fn self.name = name self.desc = desc self.module = module def run_test(self, report_result: action(?bool, ?Exception, ?str) -> None, env: Env, log_handler: logging.Handler, tags: set[str]): output = None success = None exception = None try: output = self.fn(SyncT(log_handler, tags)) success = True exception = None except SkipTest as e: success = True exception = e except AssertionError as e: success = False exception = e except Exception as e: success = None exception = e report_result(success, exception, output) class AsyncTest(Test): def __init__(self, fn: proc(AsyncT) -> None, name: str, desc: str, module: str): self.fn = fn self.name = name self.desc = desc self.module = module def run_test(self, report_result: action(?bool, ?Exception, ?str) -> None, env: Env, log_handler: logging.Handler, tags: set[str]): try: self.fn(AsyncT(report_result, log_handler, tags)) except AbortTest: pass class EnvTest(Test): def __init__(self, fn: proc(EnvT) -> None, name: str, desc: str, module: str): self.fn = fn self.name = name self.desc = desc self.module = module def run_test(self, report_result: action(?bool, ?Exception, ?str) -> None, env: Env, log_handler: logging.Handler, tags: set[str]): try: self.fn(EnvT(report_result, env, log_handler, tags)) except AbortTest: pass class TestResult(object): """ There are three possible outcomes for a test: - success: the test ran to completion with the expected results - for unit tests & synchronous actor tests, it means the function returned - for asynchronous actor & env tests, the report_result callback was called with TestResult(success=True, exception=None) - failure: the test encountered an unexpected value - for unit tests & synchronous actor tests, an AssertionError (or child thereof) was raiesd - for asynchronous actor & env tests, the report_result callback was called with TestResult(success=False, exception=AssertionError) - error: the test was unable to run to completion, encountering some other error in test setup or similar - for unit tests & synchronous actor tests, an Exception (or child thereof) was raised, but not an AssertionError - for asynchronous actor & env tests, the report_result callback was called with TestResult(success=None, exception=AssertionError) """ success: ?bool skipped: bool skip_reason: ?str exception: ?str output: ?str duration: float mem_usage_delta: int non_gc_mem_usage_delta: int def __init__(self, success: ?bool, exception: ?str, output: ?str, duration: float, mem_usage_delta: int, non_gc_mem_usage_delta: int, skipped: bool=False, skip_reason: ?str=None): self.success = success self.skipped = skipped self.skip_reason = skip_reason self.exception = exception self.output = output self.duration = duration self.mem_usage_delta = mem_usage_delta self.non_gc_mem_usage_delta = non_gc_mem_usage_delta def to_json(self): return { "success": self.success, "skipped": self.skipped, "skip_reason": self.skip_reason, "exception": self.exception, "output": self.output, "duration": self.duration, "mem_usage_delta": self.mem_usage_delta, "non_gc_mem_usage_delta": self.non_gc_mem_usage_delta, } @staticmethod def from_json(data: dict[str, str]) -> TestResult: success = data["success"] skipped = False if "skipped" in data: skipped = data["skipped"] skip_reason = None if "skip_reason" in data: skip_reason = data["skip_reason"] exception = data["exception"] output = data["output"] duration = data["duration"] mem_usage_delta = data["mem_usage_delta"] non_gc_mem_usage_delta = data["non_gc_mem_usage_delta"] if (isinstance(success, bool) and isinstance(skipped, bool) and (skip_reason is None or isinstance(skip_reason, str)) and (exception is None or isinstance(exception, str)) and (output is None or isinstance(output, str)) and isinstance(duration, float) and isinstance(mem_usage_delta, int) and isinstance(non_gc_mem_usage_delta, int) ): return TestResult(success, exception, output, duration, mem_usage_delta, non_gc_mem_usage_delta, skipped, skip_reason) raise ValueError("Invalid TestResult JSON") class TestInfo(object): definition: Test complete: bool success: ?bool skipped: bool skip_reason: ?str exception: ?str output: ?str std_out: ?str std_err: ?str flaky_output: bool flaky: bool leaky: bool min_duration: float max_duration: float avg_duration: float total_duration: float test_duration: float num_iterations: int num_skipped: int num_failures: int num_errors: int mem_usage_delta_avg: int non_gc_mem_usage_delta_avg: int non_gc_mem_inc_count: int results: list[TestResult] def __init__(self, definition: Test, complete: bool=False, success: ?bool=None, skipped: bool=False, skip_reason: ?str=None, exception: ?str=None, output: ?str=None, std_out: ?str=None, std_err: ?str=None, flaky: bool=False, min_duration: float=-1.0, max_duration: float=-1.0, avg_duration: float=-1.0, total_duration: float=0.0, test_duration: float=0.0, num_iterations: int=0, num_skipped: int=0, num_failures: int=0, num_errors: int=0, mem_usage_delta_avg: int=0, non_gc_mem_usage_delta_avg: int=0, non_gc_mem_inc_count: int=0, results: list[TestResult]=[]): self.definition = definition self.complete = complete self.success = success self.skipped = skipped self.skip_reason = skip_reason self.exception = exception self.output = output self.std_out = std_out self.std_err = std_err self.flaky_output = False self.flaky = flaky self.leaky = False self.min_duration = min_duration self.max_duration = max_duration self.avg_duration = avg_duration self.total_duration = total_duration self.test_duration = test_duration self.num_iterations = num_iterations self.num_skipped = num_skipped self.num_failures = num_failures self.num_errors = num_errors self.mem_usage_delta_avg = mem_usage_delta_avg self.non_gc_mem_usage_delta_avg = non_gc_mem_usage_delta_avg self.non_gc_mem_inc_count = non_gc_mem_inc_count self.results = results def update(self, complete, result: TestResult, test_duration: float=-1.0): self.complete = complete first_result = len(self.results) == 0 prev_iterations = self.num_iterations if first_result: # First result self.output = result.output self.exception = result.exception self.skip_reason = result.skip_reason self.results.append(result) if not eq_opt(self.output, result.output): self.flaky_output = True if self.exception is None and result.exception is not None: self.exception = result.exception if self.skip_reason is None and result.skip_reason is not None: self.skip_reason = result.skip_reason if test_duration > 0.0: self.test_duration = test_duration self.num_iterations = prev_iterations + 1 if result.skipped: self.num_skipped += 1 elif result.success == False: self.num_failures += 1 elif result.success is None: self.num_errors += 1 if first_result: self.min_duration = result.duration self.max_duration = result.duration self.total_duration = result.duration self.avg_duration = result.duration self.mem_usage_delta_avg = result.mem_usage_delta self.non_gc_mem_usage_delta_avg = result.non_gc_mem_usage_delta self.non_gc_mem_inc_count = 1 if result.non_gc_mem_usage_delta > 0 else 0 else: if result.duration < self.min_duration or self.min_duration < 0.0: self.min_duration = result.duration if result.duration > self.max_duration or self.max_duration < 0.0: self.max_duration = result.duration self.total_duration += result.duration self.avg_duration = self.total_duration / float(self.num_iterations) self.mem_usage_delta_avg = ((self.mem_usage_delta_avg * prev_iterations) + result.mem_usage_delta) // self.num_iterations self.non_gc_mem_usage_delta_avg = ((self.non_gc_mem_usage_delta_avg * prev_iterations) + result.non_gc_mem_usage_delta) // self.num_iterations if result.non_gc_mem_usage_delta > 0: self.non_gc_mem_inc_count += 1 if self.non_gc_mem_inc_count > min_def([1, self.num_iterations // 2],1) and self.non_gc_mem_usage_delta_avg > 0: self.leaky = True if self.num_failures > 0: self.success = False elif self.num_errors > 0: self.success = None else: self.success = True self.skipped = self.num_skipped > 0 and self.num_failures == 0 and self.num_errors == 0 if (self.num_failures == 0 and self.num_errors == 0) or self.num_failures == self.num_iterations or self.num_errors == self.num_iterations: self.flaky = False else: self.flaky = True def diff(self, old: ?TestInfo) -> (min_duration: str, max_duration: str, avg_duration: str, mem_usage_delta_avg: str, non_gc_mem_usage_delta_avg: str, non_gc_mem_inc_count: str): def fmt_diff(new, old, unit="") -> str: if old is not None: diff = float(new) - float(old) pct_diff = diff / float(old) * 100 sign = "+" if diff > 0 else "" color = term.green if diff < 0 else term.red diff_str = f"{sign}{pct_diff:.2f}" + "%" return f"{color}{diff_str:<10}{term.normal}" else: return f"{'':>10}" #return (min_duration=fmt_diff(self.min_duration, old.min_duration if old is not None else None, "ms")) return ( fmt_diff(self.min_duration, old.min_duration if old is not None else None, "ms"), fmt_diff(self.max_duration, old.max_duration if old is not None else None, "ms"), fmt_diff(self.avg_duration, old.avg_duration if old is not None else None, "ms"), fmt_diff(self.mem_usage_delta_avg, old.mem_usage_delta_avg if old is not None else None, "B"), fmt_diff(self.non_gc_mem_usage_delta_avg, old.non_gc_mem_usage_delta_avg if old is not None else None, "B"), fmt_diff(self.non_gc_mem_inc_count, old.non_gc_mem_inc_count if old is not None else None) ) def to_json(self, include_results: bool=False): test_results = [] if include_results: for r in self.results: test_results.append(r.to_json()) return { "definition": self.definition.to_json(), "complete": self.complete, "success": self.success, "skipped": self.skipped, "skip_reason": self.skip_reason, "exception": self.exception, "output": self.output, "std_out": self.std_out, "std_err": self.std_err, "flaky": self.flaky, "min_duration": self.min_duration, "max_duration": self.max_duration, "avg_duration": self.avg_duration, "total_duration": self.total_duration, "test_duration": self.test_duration, "num_iterations": self.num_iterations, "num_skipped": self.num_skipped, "num_failures": self.num_failures, "num_errors": self.num_errors, "mem_usage_delta_avg": self.mem_usage_delta_avg, "non_gc_mem_usage_delta_avg": self.non_gc_mem_usage_delta_avg, "non_gc_mem_inc_count": self.non_gc_mem_inc_count, "results": test_results } @staticmethod def from_json(json_data: dict[str, ?value]) -> TestInfo: def take_definition(jd: dict[str, ?value]) -> Test: if "definition" in jd: test_definition = jd["definition"] if isinstance(test_definition, dict): return Test.from_json(test_definition) raise ValueError("Invalid Test JSON: " + str(jd)) definition: Test = take_definition(json_data) complete = json_data["complete"] suc = json_data["success"] success: ?bool = None if suc is not None and isinstance(suc, bool): success = suc sk = False if "skipped" in json_data: sk = json_data["skipped"] skipped = False if isinstance(sk, bool): skipped = sk skip_reason_d = None if "skip_reason" in json_data: skip_reason_d = json_data["skip_reason"] skip_reason: ?str = None if skip_reason_d is not None and isinstance(skip_reason_d, str): skip_reason = skip_reason_d exc = json_data["exception"] exception: ?str = None if exc is not None and isinstance(exc, str): exception = exc out = json_data["output"] output: ?str = None if out is not None and isinstance(out, str): output = out std_out_d = json_data["std_out"] std_out: ?str = None if std_out_d is not None and isinstance(std_out_d, str): std_out = std_out_d std_err_d = json_data["std_err"] std_err: ?str = None if std_err_d is not None and isinstance(std_err_d, str): std_err = std_err_d flaky = json_data["flaky"] min_duration = json_data["min_duration"] max_duration = json_data["max_duration"] avg_duration = json_data["avg_duration"] total_duration = json_data["total_duration"] test_duration = json_data["test_duration"] num_iterations = json_data["num_iterations"] num_skipped = 0 if "num_skipped" in json_data: num_skipped = json_data["num_skipped"] num_failures = json_data["num_failures"] num_errors = json_data["num_errors"] mem_usage_delta_avg = json_data["mem_usage_delta_avg"] non_gc_mem_usage_delta_avg = json_data["non_gc_mem_usage_delta_avg"] non_gc_mem_inc_count = json_data["non_gc_mem_inc_count"] results: list[TestResult] = [] # We don't support results in the JSON, since we don't want it for # performance reasons but for very generic JSON serialization support it # would be correct to support it. if (isinstance(complete, bool) and isinstance(flaky, bool) and isinstance(min_duration, float) and isinstance(max_duration, float) and isinstance(avg_duration, float) and isinstance(total_duration, float) and isinstance(test_duration, float) and isinstance(num_iterations, int) and isinstance(num_skipped, int) and isinstance(num_failures, int) and isinstance(num_errors, int) and isinstance(mem_usage_delta_avg, int) and isinstance(non_gc_mem_usage_delta_avg, int) and isinstance(non_gc_mem_inc_count, int) ): return TestInfo(definition, complete, success, skipped, skip_reason, exception, output, std_out, std_err, flaky, min_duration, max_duration, avg_duration, total_duration, test_duration, num_iterations, num_skipped, num_failures, num_errors, mem_usage_delta_avg, non_gc_mem_usage_delta_avg, non_gc_mem_inc_count, results) else: raise ValueError("Invalid TestInfo JSON") class TestRunnerConfig(object): perf_mode: bool stress_mode: bool max_iter: int min_iter: int max_time: float min_time: float stress_workers: int output_enabled: bool tags: set[str] def __init__(self, perf_mode: bool, stress_mode: bool, args): def split_tags(tag_args: list[str]) -> set[str]: tags = set() for raw_tags in tag_args: for t in raw_tags.split(","): tag = t.strip() if tag != "": tags.add(tag) return tags self.perf_mode = perf_mode self.stress_mode = stress_mode self.output_enabled = False if stress_mode or args.get_bool("no_output") else True self.min_iter = args.get_int("min-iter") raw_max_iter = args.get_int("max-iter") if raw_max_iter <= 0: self.max_iter = 0 else: self.max_iter = max([raw_max_iter, self.min_iter]) self.min_time = float(args.get_int("min-time")) / 1000.0 raw_max_time = args.get_int("max-time") if raw_max_time <= 0: self.max_time = 0.0 else: self.max_time = max([float(raw_max_time) / 1000.0, self.min_time]) self.stress_workers = max([0, args.get_int("stress-workers")]) self.tags = split_tags(args.get_strlist("tag")) class TimeoutError(Exception): pass actor TestExecutor(syscap, config, t: Test, report_complete, report_progress, env, executor_id: int, stress_workers: int, stress_nodrift_workers: int): """The actual executor of tests """ log_handler = logging.Handler() log_handler.add_sink(logging.ConsoleSink()) fcap = file.FileCap(env.cap) rfcap = file.ReadFileCap(fcap) fs = file.FS(fcap) var test_sw = time.Stopwatch() var last_report = time.Stopwatch() var progress_report_sw = time.Stopwatch() var test_info = None var iteration = 0 var stress_drift_rank = max([0, executor_id - stress_nodrift_workers]) var stress_drift_workers = max([1, stress_workers - stress_nodrift_workers]) var stress_last_drift_us = 0 var stress_total_drift_us = 0 var stress_est_iter_ms = 0.0 var stress_base_drift_us = 0 var stress_worker_drift_us = 0 var stress_startup_offset_us = 0 var stress_startup_done = False var stress_phase_resolution_us = 0 var stress_target_sweep_iters = 16 var stress_calib_samples = 0 var stress_calib_target_samples = 4 var stress_calibrating = config.stress_mode and not config.perf_mode and executor_id >= stress_nodrift_workers var stress_refine_enabled = config.stress_mode and not config.perf_mode and executor_id >= stress_nodrift_workers var stress_refine_next_iter = 0 var stress_refine_max_sweep_iters = 0 def _update_stress_timing_estimate(iter_ms: float): if iter_ms <= 0.0: return if stress_est_iter_ms <= 0.0: stress_est_iter_ms = iter_ms else: stress_est_iter_ms = (stress_est_iter_ms * 0.8) + (iter_ms * 0.2) def _set_stress_sweep_iters(target_sweep_iters: int): if stress_est_iter_ms <= 0.0: return stress_target_sweep_iters = max([1, target_sweep_iters]) stress_base_drift_us = max([1, int((stress_est_iter_ms * 1000.0) / float(stress_target_sweep_iters))]) stress_phase_resolution_us = stress_base_drift_us stress_worker_drift_us = stress_base_drift_us * (stress_drift_rank + 1) def _stress_plan_time_s() -> float: if config.max_time > 0.0: return config.max_time if config.min_time > 0.0: return config.min_time return 1.0 def _stress_round_down_pow2(n: int) -> int: if n <= 1: return 1 p = 1 while p <= n // 2: p *= 2 return p def _stress_planned_total_iters() -> int: if stress_est_iter_ms <= 0.0: return 0 plan_time_s = _stress_plan_time_s() if plan_time_s <= 0.0: return 0 return max([16, int((plan_time_s * 1000.0) / max([0.1, stress_est_iter_ms]))]) def _stress_refine_cap_iters() -> int: if stress_est_iter_ms <= 0.0: return 0 # A 1us phase step is the practical ceiling of the current delay model. est_phase_cap = max([1, int(stress_est_iter_ms * 1000.0)]) if config.max_time <= 0.0: return est_phase_cap planned_iters = _stress_planned_total_iters() if planned_iters <= 0: return est_phase_cap planned_cap = max([1, _stress_round_down_pow2(planned_iters)]) return max([1, min([est_phase_cap, planned_cap])]) def _maybe_refine_stress_phase(completed_iterations: int): if not stress_refine_enabled or stress_calibrating: return if stress_base_drift_us <= 1: return if completed_iterations <= 0: return if stress_refine_next_iter <= 0: stress_refine_next_iter = max([1, stress_target_sweep_iters]) while completed_iterations >= stress_refine_next_iter and stress_base_drift_us > 1: next_sweep = stress_target_sweep_iters * 2 if stress_refine_max_sweep_iters > 0 and next_sweep > stress_refine_max_sweep_iters: next_sweep = stress_refine_max_sweep_iters if next_sweep <= stress_target_sweep_iters: break _set_stress_sweep_iters(next_sweep) stress_refine_next_iter += stress_target_sweep_iters def _finalize_stress_calibration(): if not stress_calibrating: return if stress_est_iter_ms <= 0.0: return est_total_iters = _stress_planned_total_iters() if est_total_iters >= 512: stress_target_sweep_iters = 256 elif est_total_iters >= 128: stress_target_sweep_iters = 64 else: stress_target_sweep_iters = 16 _set_stress_sweep_iters(stress_target_sweep_iters) stress_startup_offset_us = max([0, int((stress_est_iter_ms * 1000.0) * float(stress_drift_rank + 1) / float(stress_drift_workers + 1))]) if stress_refine_enabled: stress_refine_next_iter = max([1, stress_target_sweep_iters]) stress_refine_max_sweep_iters = max([stress_target_sweep_iters, _stress_refine_cap_iters()]) stress_calibrating = False def _stress_drift_delay() -> int: if not config.stress_mode or config.perf_mode: return 0 if executor_id < stress_nodrift_workers: stress_last_drift_us = 0 return 0 if stress_calibrating: stress_last_drift_us = 0 return 0 if not stress_startup_done: if stress_startup_offset_us > 0: acton.rts.sleep(syscap, float(stress_startup_offset_us) / 1000000.0) stress_total_drift_us += stress_startup_offset_us stress_startup_done = True drift_us = stress_worker_drift_us if drift_us <= 0: drift_us = max([1, stress_drift_rank + 1]) stress_last_drift_us = drift_us stress_total_drift_us += drift_us acton.rts.sleep(syscap, float(drift_us) / 1000000.0) return drift_us def _read_expected(path: str) -> ?str: try: exp_file = file.ReadFile(rfcap, path) try: exp_data = exp_file.read().decode() exp_file.close() return exp_data except: exp_file.close() except: return None def get_expected(module: str, test: str) -> ?str: snapshot_path = file.join_path([fs.cwd(), "snapshots", "expected", module, test]) exp_val = _read_expected(snapshot_path) if exp_val is not None: return exp_val # TODO: remove this legacy path once ecosystem is on the new path legacy_path = file.join_path([fs.cwd(), "test", "golden", module, test]) return _read_expected(legacy_path) action def _report_result(test: Test, sw, non_gc_mem_usage_before, gc_total_bytes_start, gc_time_start, success: ?bool, exception: ?Exception, val: ?str): full_dur = sw.elapsed().to_float() * 1000.0 gc_time_end = acton.rts.get_gc_time(syscap).total gc_dur = float(gc_time_end - gc_time_start) testiter_dur = full_dur - gc_dur gc_total_bytes_end = int(acton.rts.get_gc_total_bytes(syscap)) mem_usage_delta = gc_total_bytes_end - gc_total_bytes_start test_dur = test_sw.elapsed().to_float() if config.stress_mode and not config.perf_mode: _update_stress_timing_estimate(testiter_dur) if stress_calibrating: stress_calib_samples += 1 if stress_calib_samples >= stress_calib_target_samples: _finalize_stress_calibration() if config.perf_mode: acton.rts.gc(syscap) acton.rts.gc(syscap) non_gc_mem_usage_after = int(acton.rts.get_rss(syscap) - acton.rts.get_mem_usage(syscap)) non_gc_mem_usage_delta = non_gc_mem_usage_after - non_gc_mem_usage_before #print(f"non-GC memory before: {non_gc_mem_usage_before} after: {non_gc_mem_usage_after} delta: {non_gc_mem_usage_delta}") skipped = isinstance(exception, SkipTest) skip_reason = None if skipped: skip_exc = exception if skip_exc is not None: skip_reason = str(skip_exc) success = True exception = None completed_iterations = iteration + 1 complete = False if skipped: complete = True if config.stress_mode: if config.max_time > 0.0 and test_dur > config.max_time: complete = True if config.max_iter > 0 and completed_iterations >= config.max_iter: complete = True else: if test_dur > config.min_time and completed_iterations > config.min_iter: complete = True if config.max_time > 0 and test_dur > config.max_time: complete = True if config.max_iter > 0 and completed_iterations >= config.max_iter: complete = True if test_info is not None: exc = str(exception) if exception is not None else None test_info.update(complete, TestResult(success, exc, val, testiter_dur, mem_usage_delta, non_gc_mem_usage_delta, skipped=skipped, skip_reason=skip_reason), test_dur*1000.0) if config.stress_mode and not config.perf_mode and executor_id >= stress_nodrift_workers: _maybe_refine_stress_phase(test_info.num_iterations) iteration = completed_iterations if last_report.elapsed().to_float() > 0.05 or complete: if test_info is not None and config.output_enabled: print("\n" + json.encode({"test_info": test_info.to_json()}), err=True) last_report.reset() if config.stress_mode and (iteration == 1 or iteration % 32 == 0 or progress_report_sw.elapsed().to_float() > 0.08 or complete): report_progress(executor_id, iteration, stress_last_drift_us, stress_total_drift_us, stress_est_iter_ms, stress_phase_resolution_us, stress_target_sweep_iters, stress_calibrating) progress_report_sw.reset() if not complete: # Re-schedule the next iteration instead of recursing so stress # workers stop promptly once they cross the time budget. after 0: _run_fn(test) else: report_complete(executor_id, t, test_info) def _run_fn(t: Test): _stress_drift_delay() print("\n== Running test, iteration:", iteration) print("\n== Running test, iteration:", iteration, err=True) # Run GC to get accurate memory usage if config.perf_mode: acton.rts.gc(syscap) acton.rts.gc(syscap) non_gc_mem_usage_before = int(acton.rts.get_rss(syscap) - acton.rts.get_mem_usage(syscap)) gc_total_bytes_start = int(acton.rts.get_gc_total_bytes(syscap)) gc_time_start = acton.rts.get_gc_time(syscap).total sw = time.Stopwatch() def repres(s: ?bool, e: ?Exception, val: ?str) -> None: # Compare expected snapshot value if val is not None: exp_val = get_expected(t.module, t.display_name()) if exp_val is None or exp_val is not None and val != exp_val: exc = NotEqualError(val, exp_val, f"Test output does not match expected snapshot value.", diff_str=f"{term.normal}{diff.diff(str(exp_val), val, color=True)}", print_vals=False) _report_result(t, sw, non_gc_mem_usage_before, gc_total_bytes_start, gc_time_start, False, exc, val) return _report_result(t, sw, non_gc_mem_usage_before, gc_total_bytes_start, gc_time_start, s, e, val) try: t.run(repres, env, log_handler, config.tags) except SkipTest as e: _report_result(t, sw, non_gc_mem_usage_before, gc_total_bytes_start, gc_time_start, True, e, None) except AssertionError as e: _report_result(t, sw, non_gc_mem_usage_before, gc_total_bytes_start, gc_time_start, False, e, None) except Exception as e: _report_result(t, sw, non_gc_mem_usage_before, gc_total_bytes_start, gc_time_start, None, e, None) def _run_test(): """Get the next available test and run it""" test_sw = time.Stopwatch() test_info = TestInfo(t) _run_fn(t) after 0: _run_test() class ProjectTestResults(object): results: dict[str, dict[str, TestInfo]] last_results: dict[str, dict[str, TestInfo]] sw: time.Stopwatch expected_modules: set[str] printed_lines: int up_to_date: bool perf_mode: bool def __init__(self, perf_data: str, perf_mode: bool=False): self.results = {} self.sw = time.Stopwatch() self.expected_modules = set(['']) self.printed_lines = 0 self.up_to_date = False self.perf_mode = perf_mode self.last_results = {} self.last_results = self.parse_perf_data(perf_data) def parse_perf_data(self, perf_data: str) -> dict[str, dict[str, TestInfo]]: """Parse performance data from a file """ try: pd = json.decode(perf_data) res = {} for modname, modres in pd.items(): resmodres = {} if isinstance(modname, str) and isinstance(modres, dict): for tname, tinfo in modres.items(): resmodres[tname] = TestInfo.from_json(tinfo) res[modname] = resmodres return res except: print("Failed to parse performance data") return {} def update(self, module_name: str, test_name: str, test_info: TestInfo): """Update result for individual test """ self.up_to_date = False if module_name not in self.results: self.results[module_name] = {} self.results[module_name][test_name] = test_info def num_tests(self): cnt = 0 for module_name in self.results: cnt += len(self.results[module_name]) return cnt def skip_show(self): if len(self.expected_modules) > 0 and set(self.results.keys()) != self.expected_modules: return True return False def is_test_done(self, modname, name): if modname in self.results and name in self.results[modname]: test_info = self.results[modname][name] return test_info.complete return False def is_module_done(self, modname): if modname in self.results: for tname, test_info in self.results[modname].items(): if not test_info.complete: return False return True def to_json(self): """Return JSON encoded results that can be saved to a file """ # TODO: rewrite using comprehensions res = {} for modname in self.results: modres = {} for tname, tinfo in self.results[modname].items(): modres[tname] = tinfo.to_json() res[modname] = modres return json.encode(res) def show(self, show_ongoing: bool=False, show_log: bool=False, perf_mem: bool=True)->?int: def format_diff(new, old, unit=""): diff = float(new) - float(old) pct_diff = diff / float(old) * 100 sign = "+" if diff > 0 else "" color = term.green if diff < 0 else term.red diff_str = f"{sign}{pct_diff:.2f}" + "%" return f"{color}{diff_str:<10}{term.normal}" def format_timing(module_name, test_name): tinfo = self.results[module_name][test_name] min_dur = "--" avg_dur = "--" max_dur = "--" min_dur_diff = "--" avg_dur_diff = "--" max_dur_diff = "--" if tinfo.num_iterations > 0: min_dur = f"{tinfo.min_duration:6.2f}{term.grey13}ms{term.normal}" avg_dur = f"{tinfo.avg_duration:6.2f}{term.grey13}ms{term.normal}" max_dur = f"{tinfo.max_duration:6.2f}{term.grey13}ms{term.normal}" min_dur_diff = "" avg_dur_diff = "" max_dur_diff = "" try: last_tinfo = self.last_results[module_name][test_name] min_dur_diff = format_diff(tinfo.min_duration, last_tinfo.min_duration) avg_dur_diff = format_diff(tinfo.avg_duration, last_tinfo.avg_duration) max_dur_diff = format_diff(tinfo.max_duration, last_tinfo.max_duration) except: pass return f"{min_dur:>8} {min_dur_diff:>10} {term.grey18}Avg:{term.normal} {avg_dur:>8} {avg_dur_diff:>10} {max_dur:>8} {max_dur_diff:>10}" if self.skip_show() or self.up_to_date: return self.up_to_date = True errors = 0 failures = 0 skipped = 0 complete = True if set(self.results.keys()) != self.expected_modules: complete = False for module_name in self.results: for test_name, test_info in self.results[module_name].items(): if not test_info.complete: complete = False if not show_ongoing and not complete: return for i in range(self.printed_lines): print(term.clearline + term.up() + term.clearline, end="") self.printed_lines = 0 tname_width = 20 for modname in self.results: for tname, tinfo in self.results[modname].items(): tname_width = max_def([tname_width, len(tinfo.definition.display_name())],0) tname_width += 5 for module_name in sorted(self.results): if module_name == "": print("\nTests") self.printed_lines += 2 elif len(self.results[module_name]) > 0: print(f"\nTests - module {module_name}:") self.printed_lines += 2 for test_name, tinfo in self.results[module_name].items(): last_tinfo = None if module_name in self.last_results and test_name in self.last_results[module_name]: last_tinfo = self.last_results[module_name][test_name] prefix = " {tinfo.definition.display_name()}: " prefix += " " * (tname_width - len(prefix)) success = tinfo.success exc = tinfo.exception status = "" msg = "" run_info = "" if tinfo.complete: if tinfo.skipped: skipped += 1 msg += term.yellow + "SKIP" + term.normal elif exc is not None: msg += term.bold + term.red if tinfo.flaky: msg += "FLAKY " if tinfo.num_errors > 0: msg += "ERR" errors += 1 run_info += f"{tinfo.num_errors} errors" if tinfo.num_errors > 0 and tinfo.num_failures > 0: msg += "/" run_info += " and " if tinfo.num_failures > 0: msg += "FAIL" failures += 1 run_info += f"{tinfo.num_failures} failures" if tinfo.num_errors > 0 or tinfo.num_failures > 0: run_info += " out of " else: msg += term.green + "OK" + term.normal msg += ": " if self.perf_mode: msg += format_timing(module_name, test_name) + " " msg += f"{tinfo.num_iterations:4d} runs in {tinfo.test_duration:3.3f}ms{term.normal}" else: msg = term.yellow + "**" + term.normal l = prefix + msg print(l) self.printed_lines += 1 success_runs = max([0, tinfo.num_iterations - tinfo.num_skipped - tinfo.num_failures - tinfo.num_errors]) if tinfo.num_iterations > 1 and (tinfo.num_failures > 0 or tinfo.num_errors > 0 or tinfo.num_skipped > 0): outcome_parts = [] if success_runs > 0: outcome_parts.append(f"{success_runs} ok") if tinfo.num_failures > 0: outcome_parts.append(f"{tinfo.num_failures} fail") if tinfo.num_errors > 0: outcome_parts.append(f"{tinfo.num_errors} err") if tinfo.num_skipped > 0: outcome_parts.append(f"{tinfo.num_skipped} skip") if len(outcome_parts) > 0: print(" outcomes: " + ", ".join(outcome_parts)) self.printed_lines += 1 if self.perf_mode and perf_mem: indent = " " * 10 diffs = tinfo.diff(last_tinfo) print(f"{indent}Memory usage : {tinfo.mem_usage_delta_avg // 1024:6d}KB {diffs.mem_usage_delta_avg}") print(f"{indent}non-GC usage : {tinfo.non_gc_mem_usage_delta_avg // 1024:6d}KB {diffs.non_gc_mem_usage_delta_avg}") print(indent + "non-GC usage > 0 : %d%% (%d out of %d)" % ((tinfo.non_gc_mem_inc_count * 100 // tinfo.num_iterations) if tinfo.num_iterations > 0 else 0, tinfo.non_gc_mem_inc_count, tinfo.num_iterations)) self.printed_lines += 3 if tinfo.complete: if tinfo.skipped and tinfo.skip_reason is not None: print(f"{term.yellow} skipped: {tinfo.skip_reason}{term.normal}") self.printed_lines += 1 if exc is not None: for line in str(exc).splitlines(None): print(f"{term.red} {line}{term.normal}") self.printed_lines += 1 # Print std_out/std_err if the test failed if show_log or tinfo.num_failures > 0 or tinfo.num_errors > 0: def test_output(msgs: str): for line in msgs.splitlines(): if not (line.startswith("== Running test,") or line == ""): return True return False def dedup(buf: str) -> dict[str, set[int]]: # Initialize result dictionary result = {} # Split buffer into individual test iterations iterations = buf.split("== Running test, iteration: ") # Clean up iterations - remove empty entries cleaned_iterations = [] for it in iterations: if it.strip(): cleaned_iterations.append(it.strip()) # Process each iteration for iteration in cleaned_iterations: # Extract iteration number and content lines = iteration.split('\n', 1) iteration_num = int(lines[0]) content = "" if len(lines) > 1: # might not be any real test output yet!? content = lines[1].strip() # Add to result dictionary if content not in result: result[content] = set() result[content].add(iteration_num) return result std_out = tinfo.std_out if std_out is not None and test_output(std_out): print(" STDOUT:") self.printed_lines += 1 chunks = dedup(std_out.strip()) for chunk, test_runs in chunks.items(): if len(chunks) == 1: pass else: print(f" == {len(test_runs)} test runs with this output:") self.printed_lines += 1 for line in chunk.splitlines(): print(" " + line) self.printed_lines += 1 print("") self.printed_lines += 1 std_err = tinfo.std_err if std_err is not None and test_output(std_err): print(" STDERR:") self.printed_lines += 1 chunks = dedup(std_err.strip()) for chunk, test_runs in chunks.items(): if len(chunks) == 1: pass else: print(f" == {len(test_runs)} test runs with this output:") self.printed_lines += 1 for line in chunk.splitlines(): print(" " + line) self.printed_lines += 1 print("") self.printed_lines += 1 print("") if complete: if self.num_tests() == 0: print("Nothing to test") print() return 0 elif errors > 0 and failures > 0: print(f"{term.bold}{term.red}{errors} error and {failures} failure out of {self.num_tests()} tests ({self.sw.elapsed().str_ms()}s){term.normal}") print() return 2 elif errors > 0: print(f"{term.bold}{term.red}{errors} out of {self.num_tests()} tests errored ({self.sw.elapsed().str_ms()}s){term.normal}") print() return 2 elif failures > 0: print(f"{term.bold}{term.red}{failures} out of {self.num_tests()} tests failed ({self.sw.elapsed().str_ms()}s){term.normal}") print() return 1 else: if skipped > 0: print(f"{term.green}All {self.num_tests()} tests passed, {skipped} skipped ({self.sw.elapsed().str_ms()}s){term.normal}") else: print(f"{term.green}All {self.num_tests()} tests passed ({self.sw.elapsed().str_ms()}s){term.normal}") print() return 0 else: print("Running tests...") print() self.printed_lines += 3 actor test_runner(env: Env, unit_tests: dict[str, UnitTest], simple_sync_tests: dict[str, SimpleSyncTest], sync_tests: dict[str, SyncTest], async_tests: dict[str, AsyncTest], env_tests: dict[str, EnvTest]): sw = time.Stopwatch() var all_tests = {} for name, t in unit_tests.items(): all_tests[name] = t for name, t in simple_sync_tests.items(): all_tests[name] = t for name, t in sync_tests.items(): all_tests[name] = t for name, t in async_tests.items(): all_tests[name] = t for name, t in env_tests.items(): all_tests[name] = t proc def _cmd_list(args): res = {} for test_name, test_def in all_tests.items(): test_info = TestInfo(test_def) res[test_name] = test_info.to_json() print("\n" + json.encode({"tests": res}), err=True) env.exit(0) proc def _run_tests(args, perf_mode: bool=False, stress_mode: bool=False): config = TestRunnerConfig(perf_mode, stress_mode, args) if config.perf_mode: acton.rts.start_gc_performance_measurement(env.syscap) def _default_stress_workers() -> int: # Stress runs benefit from oversubscription so worker actors must # share RTS worker threads instead of mapping one-to-one. base_workers = max([1, env.nr_wthreads]) extra_workers = max([1, base_workers // 2]) return base_workers + extra_workers def _stress_timeout_slack_s() -> float: if not config.stress_mode or config.perf_mode: return 1.0 # Oversubscribed stress runs can take several extra seconds to # drain workers and emit the final aggregate result. return max([5.0, min([10.0, config.min_time * 0.9])]) test_concurrency = 1 stress_nodrift_workers = 0 if config.stress_mode and not config.perf_mode: if config.stress_workers > 0: test_concurrency = config.stress_workers else: test_concurrency = _default_stress_workers() stress_nodrift_workers = min([test_concurrency, max([2, (test_concurrency + 3) // 4])]) test_timeout = 0.0 if config.max_time > 0: test_timeout = max([config.max_time, 2.0]) + _stress_timeout_slack_s() test_name = args.get_str("name") if test_name not in all_tests: print(f"Test not found: {test_name}") env.exit(1) the_test = all_tests[test_name] workers_complete = set() combined_info = TestInfo(the_test) combined_sw = time.Stopwatch() worker_iterations = {} worker_drift_us = {} worker_drift_total_us = {} worker_est_iter_ms = {} worker_phase_resolution_us = {} worker_target_sweep_iters = {} worker_calibrating = {} stress_phase_cov = { "bins_total": 0, "res_us": 0, "seen_count": 0, "epoch": 1 } stress_phase_bins_epoch = {} for idx in range(test_concurrency): worker_iterations[idx] = 0 worker_drift_us[idx] = 0 worker_drift_total_us[idx] = 0 worker_est_iter_ms[idx] = 0.0 worker_phase_resolution_us[idx] = 0 if idx < stress_nodrift_workers: worker_target_sweep_iters[idx] = 0 worker_calibrating[idx] = False else: worker_target_sweep_iters[idx] = 16 worker_calibrating[idx] = config.stress_mode def _total_worker_iterations() -> int: total = 0 for idx in range(test_concurrency): total += worker_iterations[idx] return total def _stress_workers_json(): workers = [] for idx in range(test_concurrency): workers.append({ "id": idx, "iterations": worker_iterations[idx], "drift_us": worker_drift_us[idx], "drift_total_us": worker_drift_total_us[idx], "est_iter_ms": worker_est_iter_ms[idx], "phase_resolution_us": worker_phase_resolution_us[idx], "target_sweep_iters": worker_target_sweep_iters[idx], "calibrating": worker_calibrating[idx], "sync": idx < stress_nodrift_workers }) return workers def _stress_est_iteration_ms() -> float: total = 0.0 count = 0 for idx in range(test_concurrency): est = worker_est_iter_ms[idx] if est > 0.0: total += est count += 1 if count > 0: return total / float(count) return 0.0 def _stress_phase_resolution_ms() -> float: worst_us = 0 for idx in range(stress_nodrift_workers, test_concurrency): res_us = worker_phase_resolution_us[idx] if res_us > worst_us: worst_us = res_us if worst_us > 0: return float(worst_us) / 1000.0 est_ms = _stress_est_iteration_ms() if est_ms > 0.0: return est_ms / 16.0 return 0.0 def _stress_target_sweep_iters() -> int: target = 0 for idx in range(stress_nodrift_workers, test_concurrency): if worker_target_sweep_iters[idx] > target: target = worker_target_sweep_iters[idx] return target def _stress_calibrating_workers() -> int: count = 0 for idx in range(stress_nodrift_workers, test_concurrency): if worker_calibrating[idx]: count += 1 return count def _update_stress_phase_coverage(): if not config.stress_mode or config.perf_mode: return if test_concurrency <= stress_nodrift_workers: return phase_res_ms = _stress_phase_resolution_ms() est_ms = _stress_est_iteration_ms() if phase_res_ms <= 0.0 or est_ms <= 0.0: return phase_res_us = max([1, int(phase_res_ms * 1000.0)]) bins_total = _stress_target_sweep_iters() if bins_total <= 0: est_us = max([phase_res_us, int(est_ms * 1000.0)]) bins_total = max([1, est_us // phase_res_us]) if bins_total != stress_phase_cov["bins_total"] or phase_res_us != stress_phase_cov["res_us"]: stress_phase_cov["bins_total"] = bins_total stress_phase_cov["res_us"] = phase_res_us stress_phase_cov["seen_count"] = 0 stress_phase_cov["epoch"] = stress_phase_cov["epoch"] + 1 for idx in range(stress_nodrift_workers, test_concurrency): if worker_calibrating[idx]: continue drift_total = worker_drift_total_us[idx] if drift_total <= 0: continue bin_idx = (drift_total // phase_res_us) % bins_total current_epoch = stress_phase_cov["epoch"] if bin_idx in stress_phase_bins_epoch and stress_phase_bins_epoch[bin_idx] == current_epoch: continue stress_phase_bins_epoch[bin_idx] = current_epoch stress_phase_cov["seen_count"] = stress_phase_cov["seen_count"] + 1 def _stress_payload(info: TestInfo): payload = info.to_json() payload["stress_worker_count"] = test_concurrency payload["stress_no_drift_workers"] = stress_nodrift_workers payload["stress_est_iteration_ms"] = _stress_est_iteration_ms() payload["stress_phase_resolution_ms"] = _stress_phase_resolution_ms() payload["stress_target_sweep_iters"] = _stress_target_sweep_iters() payload["stress_calibrating_workers"] = _stress_calibrating_workers() payload["stress_phase_bins_seen"] = stress_phase_cov["seen_count"] payload["stress_phase_bins_total"] = stress_phase_cov["bins_total"] payload["stress_workers"] = _stress_workers_json() return payload def _emit_stress_live(): if not config.stress_mode or len(workers_complete) >= test_concurrency: return _update_stress_phase_coverage() payload = _stress_payload(combined_info) total_iterations = _total_worker_iterations() payload["complete"] = False payload["success"] = None payload["exception"] = None payload["num_failures"] = 0 payload["num_errors"] = 0 payload["num_iterations"] = total_iterations payload["test_duration"] = combined_sw.elapsed().to_float() * 1000.0 if total_iterations > 0: print("\n" + json.encode({"test_info": payload}), err=True) after 0.08: _emit_stress_live() def _merge_worker_info(worker_info: ?TestInfo): if worker_info is not None: for result in worker_info.results: combined_info.update(False, result) def report_progress(executor_id: int, iterations: int, drift_us: int, drift_total_us: int, est_iter_ms: float, phase_resolution_us: int, target_sweep_iters: int, calibrating: bool): if executor_id in worker_iterations: if iterations > worker_iterations[executor_id]: worker_iterations[executor_id] = iterations worker_drift_us[executor_id] = drift_us worker_drift_total_us[executor_id] = max([worker_drift_total_us[executor_id], drift_total_us]) worker_est_iter_ms[executor_id] = est_iter_ms worker_phase_resolution_us[executor_id] = phase_resolution_us if target_sweep_iters > 0: worker_target_sweep_iters[executor_id] = target_sweep_iters worker_calibrating[executor_id] = calibrating _update_stress_phase_coverage() def _check_timeout(): if test_timeout <= 0.0: return if len(workers_complete) >= test_concurrency: # Report after we hit timeout return time_s = test_timeout * 1000.0 if config.stress_mode: if len(combined_info.results) > 0: combined_info.update( True, TestResult( None, "Test timeout", None, time_s, 0, 0), time_s) _update_stress_phase_coverage() payload = _stress_payload(combined_info) payload["complete"] = True payload["test_duration"] = time_s payload["num_iterations"] = max([combined_info.num_iterations, _total_worker_iterations()]) print("\n" + json.encode({"test_info": payload}), err=True) env.exit(0) timeout_info = TestInfo( the_test, complete=True, success=None, exception="Test timeout", min_duration=time_s, max_duration=time_s, avg_duration=time_s, total_duration=time_s, test_duration=time_s, num_iterations=max([1, _total_worker_iterations()]), num_failures=0, num_errors=1 ) _update_stress_phase_coverage() payload = _stress_payload(timeout_info) payload["num_iterations"] = max([timeout_info.num_iterations, _total_worker_iterations()]) print("\n" + json.encode({"test_info": payload}), err=True) env.exit(0) test_info = TestInfo( the_test, complete=True, success=None, exception="Test timeout", min_duration=time_s, max_duration=time_s, avg_duration=time_s, total_duration=time_s, test_duration=time_s, num_iterations=1, num_failures=0, num_errors=1 ) print("\n" + json.encode({"test_info": test_info.to_json()}), err=True) env.exit(0) def report_complete(executor_id: int, t, worker_info: ?TestInfo): if executor_id in workers_complete: return workers_complete.add(executor_id) if not config.stress_mode: env.exit(0) return _merge_worker_info(worker_info) if len(workers_complete) >= test_concurrency: combined_info.complete = True combined_info.test_duration = combined_sw.elapsed().to_float() * 1000.0 _update_stress_phase_coverage() payload = _stress_payload(combined_info) payload["num_iterations"] = max([combined_info.num_iterations, _total_worker_iterations()]) print("\n" + json.encode({"test_info": payload}), err=True) env.exit(0) test_executors = [] for idx in range(test_concurrency): te = TestExecutor(env.syscap, config, the_test, report_complete, report_progress, env, idx, test_concurrency, stress_nodrift_workers) test_executors.append(te) if config.stress_mode: after 0.08: _emit_stress_live() if test_timeout > 0.0: after test_timeout: _check_timeout() proc def _run_perf_tests(args): _run_tests(args, perf_mode=True) proc def _run_stress_tests(args): _run_tests(args, stress_mode=True) def _parse_args(): p = argparse.Parser() p.add_bool("json", "Output results as JSON") p.add_bool("no_output", "No result output") lp = p.add_cmd("list", "list tests", _cmd_list) tp = p.add_cmd("test", "Run tests", _run_tests) tp.add_arg("name", "Name of the test to run") tp.add_option("max-iter", "int", default=10**6, help="Maximum number of iterations to run") tp.add_option("min-iter", "int", default=3, help="Minumum number of iterations to run") tp.add_option("max-time", "int", default=1000, help="Maximum time to run a test in milliseconds (0 = no time limit)") tp.add_option("min-time", "int", default=50, help="Minimum time to run a test in milliseconds") tp.add_option("stress-workers", "int", default=0, help="Concurrent stress workers to run (0 = auto)") tp.add_option("tag", "strlist", default=[], help="Enable test capability tag") pp = tp.add_cmd("perf", "Performance benchmark tests", _run_perf_tests) sp = tp.add_cmd("stress", "Stress tests by running concurrent workers of the same test", _run_stress_tests) args = p.parse(env.argv) _cmd = args.cmd if _cmd is not None: _cmd(args) else: env.exit(0) try: _parse_args() except argparse.PrintUsage as exc: print(exc.error_message) env.exit(0) except argparse.ArgumentError as exc: print(exc.error_message) env.exit(1) ================================================ FILE: base/src/time.act ================================================ """Stopwatch, time, dates and calendars There are primarily two uses of time - measuring elapsed time (e.g. for benchmarking) - telling the current date and time (e.g. for logging) Use a Stopwatch to measure elapsed time, e.g.: s = time.Stopwatch() # do something elapsed = s.elapsed() print("Elapsed time:", elapsed.str_us()) # Elapsed time: 1.234567 s Call `now()` to get the current date and time: dt = time.now() print("Current time:", dt) # Current time: 2023-03-07T15:33:02.238251863+01 `utcnow()` returns the current date and time in UTC: dt = time.utcnow() print("UTC time:", dt) # UTC time: 2023-03-07T14:33:02.238251863Z Instant and Duration store time using two 64 bit fields for seconds and fractional seconds. It amounts to a range of +-292 billion years for Instant and an elapsed time of 585 billion years for Duration. The resolution is 1 attosecond. It's a lot of zeros, which is why you might want to use str_us(), str_ms() or str_ns() to get a more humanly readable representation. Information about the clock source is kept and used as part of various operations to indicate precision and error in resulting values. """ # TODO: localization? MONTHS = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ] MNTHS = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ] WEEKDAYS = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ] WKDAYS = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ] def _get_incarnation() -> int: """Get clock instance ID """ NotImplemented def get_realtime() -> (int, int): """clock_gettime for CLOCK_REALTIME Returns time represented as seconds and nanoseconds since the Epoch, 1st of January 1970 00:00:00 UTC. """ NotImplemented def get_monotonic() -> (int, int): """clock_gettime for CLOCK_MONOTONIC Returns time represented as seconds and nanoseconds since an arbitrary start time. """ NotImplemented class clock_data: def __init__(self, status: int, offset: int, error: int) -> (status: int, offset: int, error: int): return (status=status, offset=offset, error=error) def get_clock_data() -> (status: int, offset: int, error: int): """Get clock data This uses ntp_adjtime to get the current clock data. The returned tuple contains the synchronization status, the offset and the estimated error in microseconds. """ NotImplemented # TODO: use named tuple for return value def localtime(seconds: int) -> (int, int, int, int, int, int, int, int, int, str, int): """C localtime() function """ NotImplemented # TODO: use named tuple for return value def gmtime(seconds: int) -> (int, int, int, int, int, int, int, int, int): """C gmtime() function """ NotImplemented class Clock: """Clock information A clock is a source of time. A Clock object stores information about a clock and additional data about the precision and error of a particular reading from the clock. Every object that represent time, like Instant and DateTime, has a clock attribute which is used to trace where the time came from and if it is comparable to other time. There are two types of clocks on most POSIX systems today: - real time clock - `RealtimeClock()` - monotonic clock - `MonotonicClock()` It is not possible to compare time between different clock types as they have different starting points. The monotonic clock has an arbitrary starting point whereas the realtime clock starts at Epoch (1970-01-01 00:00:00 UTC). For an Instant from a monotonic clock, it is only comparable with another Instant from the same monotonic clock. The start time of a monotonic clock is arbitrary which means that not only is it not comparable between two machines, it is also not comparable on the same machines between reboots. In order to determine if we are on the same machine and have not rebooted, we keep track of the clock incarnation which is essentially a unique identifier for the start of a clock. On Linux, this is the boot-id, which is unique per machine and boot. On other platforms we use a random incarnation identifier per start of an Acton node, so time will only be comparable within that running instance of the RTS. The local real time clock is typically used to track real world time, which on planet earth practically means Coordinated Universal Time (UTC). Like a wristwatch or any other clock, the local clock needs to be periodically set. The NTP/NTS protocols can be used to synchronize the clock over a network connection. A computer clock without some form of clock synchronization can be wildly incorrect and suffer from discontinuous jumps in time if a system administrator changes the local clock, rendering comparisons of different instants invalid even when they are from the same computer. Across multiple computers, as is the case for for distributed Acton systems, there has to be clock synchronization in use for time to be comparable. The precision of comparisons will only be as good as the clock synchronization allows. NTP is the most common clock synchronization protocol and it can usually achieve synchronization on the order of milliseconds, even sub-ms on local networks. It largely depends on how good the network is. PTP can achieve sub-microsecond synchronization. It is not possible to compare time from two unsynchronized clocks as we have no idea of their drift from UTC. Linux, MacOS and various BSD platforms provides detail information about the real time clock, like if it is synchronized, the estimated error etc. This information is retrieved and kept in a Clock object associated with the retrieved time so that we may track the precision of the final result. The information is provided by the NTP or PTP daemon and is only accurate while that daemon is running. A particularly nasty scenario is when an NTPd has been running, updating the kernel information that the clock is synchronized and with a certain error, but has since stopped, leaving the clock information stale. The kernel has no facility to mark it as stale and thus, we will run under the belief that we get good precision time when in fact we are free running, uncoordinated with UTC. It is ultimately up to the system administrator to ensure that clocks on the system(s) running an Acton system are synchronized, preferrably using NTP or similar. """ # TODO: turn into constants? but getting acton compiler error @property standard: str # Which time standard this clock provides # "monotonic": monotonic clock # "UTC": real time (UTC) clock @property incarnation: int @property sync: int @property offset: int @property error: int def comparable(self, other: Clock) -> bool: """Check if two clocks produce comparable time """ return False class RealtimeClock(Clock): """Realtime clock """ def __init__(self, sync: int, offset: int, error: int, standard="UTC"): self.standard = standard self.incarnation = _get_incarnation() self.sync = sync self.offset = offset self.error = error def comparable(self, other: Clock) -> bool: """Check if two clocks produce comparable time """ if isinstance(other, RealtimeClock): return self.standard == other.standard and self.sync == other.sync else: return False class MonotonicClock(Clock): """Monotonic clock """ def __init__(self, sync: int, offset: int, error: int): self.standard = "monotonic" self.incarnation = _get_incarnation() self.sync = sync self.offset = offset self.error = error def comparable(self, other: Clock) -> bool: """Check if two clocks produce comparable time """ if isinstance(other, MonotonicClock): return self.incarnation == other.incarnation else: return False class Calendar(object): """A calendar, like gregorian or julian. """ pass class Timezone: @property name: str @property offset: int def __init__(self, name: str, offset: int): self.name = name self.offset = offset def str_offset(self) -> str: """Return the timezone offset from UTC in ISO8601 style """ tz_str = "" if self.offset == 0: tz_str = "Z" else: if self.offset > 0: tz_str = "+" else: tz_str = "-" tz_str += f"{self.offset // 3600:02d}" if self.offset % 3600 > 0: tz_str += f":{(self.offset % 3600) // 60:02d}" return tz_str class DateTime(object): """A date and time according to a calendar and time zone. """ @property calendar: ?Calendar @property timezone: ?Timezone @property clock: ?Clock @property era: ?int @property year: int @property month: int @property day: int @property hour: int @property minute: int @property second: int @property attosecond: int @property weekday: int @property yearday: int def __init__(self, calendar: ?Calendar, timezone: ?Timezone, clock: ?Clock, era: ?int, year: int, month: int, day: int, hour: int, minute: int, second: int, attosecond: int, weekday: int, yearday: int): self.calendar = calendar self.timezone = timezone self.clock = clock self.era = era self.year = year self.month = month self.day = day self.hour = hour self.minute = minute self.second = second self.attosecond = attosecond self.weekday = weekday self.yearday = yearday def __str__(self): return self.str_iso8601_ns() def str_iso8601_ns(self): tz_str = "" # if self.timezone is not None: # tz_str = self.timezone.str_short() # TODO: remove this superfluous t variable and use above code, which # currently acton borks out on t = self.timezone if t is not None: tz_str = t.str_offset() # Most of the clocks return f"{self.year:04d}-{self.month:02d}-{self.day:02d}T{self.hour:02d}:{self.minute:02d}:{self.second:02d}.{self.attosecond // 10**9:09d}{tz_str}" @staticmethod def now(): cd = get_clock_data() c = RealtimeClock(cd.status, cd.offset, cd.error) s, ns = get_realtime() tm = localtime(s) tm_year = tm.0 tm_month = tm.1 tm_day = tm.2 tm_hour = tm.3 tm_minute = tm.4 tm_second = tm.5 tm_wday = tm.6 tm_yday = tm.7 tm_isdst = tm.8 attosecond = ns * 10**9 return DateTime(None, None, None, None, tm_year, tm_month, tm_day, tm_hour, tm_minute, tm_second, attosecond, tm_wday, tm_yday) @staticmethod def utcnow(): cd = get_clock_data() c = RealtimeClock(cd.status, cd.offset, cd.error) s, ns = get_realtime() tm = gmtime(s) tm_year = tm.0 tm_month = tm.1 tm_day = tm.2 tm_hour = tm.3 tm_minute = tm.4 tm_second = tm.5 tm_wday = tm.6 tm_yday = tm.7 tm_isdst = tm.8 attosecond = ns * 10**9 return DateTime(None, None, None, None, tm_year, tm_month, tm_day, tm_hour, tm_minute, tm_second, attosecond, tm_wday, tm_yday) def str_rfc1123(self): # TODO: heh, lol, actually convert to GMT first # web servers want rfc1123 and it should always be in GMT, but I suppose there are other uses of rfc1123 return "%s, %02d %s %04d %02d:%02d:%02d GMT" % ( WKDAYS[self.weekday], self.day, MNTHS[self.month-1], self.year, self.hour, self.minute, self.second) def str_asctime(self): return "%s %s %2d %02d:%02d:%02d %04d" % ( WEEKDAYS[self.weekday][0:3], MONTHS[self.month][0:3], self.day, self.hour, self.minute, self.second, self.year) class Instant(object): """A specific point in time as measured with a monotonically increasing clock. Only useful with ~Duration~ and ~Stopwatch~ to measure elapsed time. An Instant does not carry calendar or time zone information. Stores time using: - i64 second - u64 attosecond Which gives a range of ±292 billion years with a precision down to atto-second (2^10-18). """ @property second: int @property attosecond: int @property clock: Clock # TODO: compiler bug? why isn't c allowed to be maybe Clock? the effect of # __init__ is that self.clock is always a Clock anyway... #def __init__(self, sec: int, asec: int, c: ?Clock=None): def __init__(self, sec: int, asec: int, c: Clock): self.second = sec self.attosecond = asec self.clock = c def __str__(self): return f"{self.second}.{self.attosecond:018d}" def __repr__(self): return f"Instant({self.second}, {self.attosecond})" def str_ms(self): """Return a string representation of the duration with milliseconds. """ return f"{self.second}.{self.attosecond // 10**15:03d}" def str_us(self): """Return a string representation of the duration with microseconds. """ return f"{self.second}.{self.attosecond // 10**12:06d}" def str_ns(self): """Return a string representation of the duration with nanoseconds. """ return f"{self.second}.{self.attosecond // 10**9:09d}" # TODO: fix this # def __sub__(self, other: Instant) -> Duration: # if (self.second == other.second and self.attosecond > other.attosecond) or self.second > other.second: # return Duration(self.second - other.second, self.attosecond - other.attosecond) # else: # return Duration(other.second - self.second, other.attosecond - self.attosecond) def add(self, duration: Duration) -> Instant: attosecond_sum = self.attosecond + duration.attosecond return Instant(self.second + duration.second + attosecond_sum // 10**18, attosecond_sum % 10**18, self.clock) def sub(self, duration: Duration) -> Instant: result_attoseconds = self.attosecond - duration.attosecond result_seconds = self.second - duration.second if result_attoseconds < 0: result_seconds -= 1 result_attoseconds += 10**18 # 1 second = 10^18 attoseconds return Instant(result_seconds, result_attoseconds, self.clock) def since(self, other: Instant) -> Duration: """Return the duration since this instant. """ result_attoseconds = self.attosecond - other.attosecond result_seconds = self.second - other.second # Handle underflow if result_attoseconds < 0: result_seconds -= 1 result_attoseconds += 10**18 # 1 second = 10^18 attoseconds return Duration(result_seconds, result_attoseconds, self.clock) def comparable(self, other: Instant) -> bool: return self.clock.comparable(other.clock) def unix_s(self) -> int: """Return the time in seconds since the Unix epoch """ return self.second def unix_ms(self) -> int: """Return the time in milliseconds since the Unix epoch """ return self.second * 1000 + self.attosecond // 10**15 def unix_us(self) -> int: """Return the time in microseconds since the Unix epoch """ return self.second * 1000000 + self.attosecond // 10**12 def unix_ns(self) -> int: """Return the time in nanoseconds since the Unix epoch """ return self.second * 1000000000 + self.attosecond // 10**9 extension Instant(Ord): def __eq__(self, other): return self.second == other.second and self.attosecond == other.attosecond def __lt__(self, other): return self.second < other.second or self.second == other.second and self.attosecond < other.attosecond class Duration(object): """Duration represents elapsed time Stored using seconds and attoseconds. """ @property second: int @property attosecond: int @property clock: ?Clock def __init__(self, sec: int, asec: int, c: Clock): self.second = sec self.attosecond = asec self.clock = c def __str__(self): return self.str_human() def __repr__(self): return f"{self.second}.{self.attosecond:018d}" @staticmethod def from_parts(week: int, day: int, hour: int, minute: int, second: int, attosecond: int, c: Clock) -> Duration: return Duration( week * 7 * 24 * 60 * 60 + day * 24 * 60 * 60 + hour * 60 * 60 + minute * 60 + second, attosecond, c) def str_human(self) -> str: """Return a human readable string representation Like: 4w 3d 2h 1m 5s 123ms Weeks is the biggest unit as it has a fixed size (7 days). Months vary in length so we cannot convert to months without having absolute point in times to compare with. Years are explicitly not used since they are not exact, a year is usually thought of as 365 days but they're actually 365.25 (actually actually 365.2422) so it becomes error prone and less precise. """ weeks = self.second // (7 * 24 * 60 * 60) days = (self.second % (7 * 24 * 60 * 60)) // (24 * 60 * 60) hours = (self.second % (24 * 60 * 60)) // (60 * 60) minutes = (self.second % (60 * 60)) // 60 seconds = self.second % 60 return f"{weeks}w {days}d {hours}h {minutes}m {seconds}s {self.attosecond // 10**9}ns" def str_ms(self): """Return a string representation of the duration with milliseconds. """ return f"{self.second}.{self.attosecond // 10**15:03d}" def str_us(self): """Return a string representation of the duration with microseconds. """ return f"{self.second}.{self.attosecond // 10**12:06d}" def str_ns(self): """Return a string representation of the duration with nanoseconds. """ return f"{self.second}.{self.attosecond // 10**9:09d}" def to_float(self) -> float: return float(self.second) + (float(self.attosecond) / 10**18) def monotonic() -> Instant: """Get monotonic time """ c = MonotonicClock(0, 0, 0) t = get_monotonic() return Instant(t.0, t.1 * 10**9, c) def time() -> Instant: """Get real clock time """ cd = get_clock_data() c = RealtimeClock(cd.status, cd.offset, cd.error) t = get_realtime() return Instant(t.0, t.1 * 10**9, c) def now() -> DateTime: """Get the current date and time in the local timezone """ t = time() tm = localtime(t.second) tm_year = tm.0 tm_month = tm.1 tm_day = tm.2 tm_hour = tm.3 tm_minute = tm.4 tm_second = tm.5 tm_wday = tm.6 tm_yday = tm.7 tm_isdst = tm.8 tz = Timezone(tm.9, tm.10) return DateTime(None, tz, None, None, tm_year, tm_month, tm_day, tm_hour, tm_minute, tm_second, t.attosecond, tm_wday, tm_yday) def utcnow() -> DateTime: """Get the current date and time in UTC """ t = time() tm = gmtime(t.second) tm_year = tm.0 tm_month = tm.1 tm_day = tm.2 tm_hour = tm.3 tm_minute = tm.4 tm_second = tm.5 tm_wday = tm.6 tm_yday = tm.7 tm_isdst = tm.8 tz = Timezone("UTC", 0) return DateTime(None, tz, None, None, tm_year, tm_month, tm_day, tm_hour, tm_minute, tm_second, t.attosecond, tm_wday, tm_yday) class Stopwatch(object): """Stopwatch measures elapsed time The watch is started when it is created and the elapsed time can be retrieved using the elapsed() method. The watch can be reset using the reset() method. The system's monotonic clock is primarily used but a real clock time measurement is also kept as a fallback. Normally the monotonic clock is excellent for measuring elapsed time as it has high precision and is not affected by discontinuous jumps in the system time. However, the start time of the monotonic clock is arbitrary and thus is only comparable to itself on the same machine while that machine is running. Rebooting might reset the monotonic time. Actor migrations might mean that the Stopwatch was started on one machine and later migrated to another at which point comparing to the monotonic start time is no longer valid. In this case we fall back to comparing the real time, which is not as precise but is at least theoretically comparable between machines or after reboots. > A man with a watch knows what time it is. A man with two watches is never > sure. -- Segal’s Law The precision of the real clock is normally high when compared on the same machine (intra-machine). It is affected by reboots, where it relies on a hardware clock to keep the time, and is affected by discontinuous jumps in the system time (e.g., if the system administrator manually changes the clock), but otherwise it is comparable to the monotonic clock. When compared between different machines (inter-machine) it is entirely up to the precision and accuracy of the synchronization solution. NTP usually achieves a level on the order milliseconds while PTP is on the order of microseconds or tens of microseconds. There is no way to capture the monotonic and real clock time at the same time, so there will be a slight offset between them. We capture the monotonic time first, which is what we use for precise measurements. If we need to fall back to using the real clock, the offset to the monotonic clock is negligible compared to other sources of error. Each Instant keeps information about the source clock which is used to produce a result with an estimated precision and error. Use PrecisionStopwatch if you need guaranteed precision (but which will fail if that precision is unattainable). """ def __init__(self): self.start_mono = monotonic() self.start_real = time() def elapsed(self) -> Duration: """Return the elapsed time since start """ n = monotonic() if n.comparable(self.start_mono): return n.since(self.start_mono) return time().since(self.start_real) def reset(self): self.start_mono = monotonic() self.start_real = time() class PrecisionStopwatch(object): """A precision stopwatch to measure elapsed time using the monotonic clock. Similar to Stopwatch but if there is no reliable monotonic clock available, such as after actor migration, PrecisionStopwatch will fail rather than produce lower precision measurements like Stopwatch will. The monotonic clock has an arbitrary start time and as such only works reliably on the same machine while that machine is running. Rebooting will reset the monotonic time. Actor migrations might mean that the PrecisionStopwatch was started on one machine and later migrated to another at which point comparing to the monotonic start time is no longer valid. In this case we throw an exception since we can not guarantee the precision of the result. Use Stopwatch if you want to be able to always compare the elapsed time, such as after actor resumption or migrations between machines, even when that means that the precision is lower. """ def __init__(self): self.start = monotonic() def elapsed(self) -> Duration: """Return the elapsed time since start """ n = monotonic() if not n.comparable(self.start): raise Exception("Monotonic clock not comparable") return n.since(self.start) def reset(self): self.start = monotonic() ================================================ FILE: base/src/time.ext.c ================================================ #define GC_THREADS 1 #include #ifdef _WIN32 #else #include #endif #include #include "../rts/io.h" #include "../rts/log.h" unsigned long time__incarnation = 0; // Clock data int time__realclock_status = 0; #ifdef _WIN32 #else struct timex time__realclock_tx = {0}; #endif // Reduce UUID to 64 bits. Good enough for our purposes. unsigned long time__uuid_to_ulong(const char* uuid) { unsigned long result = 0; unsigned long value; int i; for (i = 0; i < 16; i++) { if (i == 8 || i == 13 || i == 18 || i == 23) { if (uuid[i] != '-') { return 0; } } else { value = isdigit(uuid[i]) ? uuid[i] - '0' : toupper(uuid[i]) - 'A' + 10; result = (result << 4) | (value & 0xF); } } return result; } void time__get_clock_data_cb(uv_timer_t *ev) { #ifdef __linux__ time__realclock_status = adjtimex(&time__realclock_tx); #elif defined(_WIN32) // Windows // TODO: implement Windows support? time__realclock_status = 0; #else time__realclock_status = ntp_adjtime(&time__realclock_tx); #endif } void timeQ___ext_init__() { // Monotonic clocks have an arbitrary starting point, so we need to keep // track of which "incarnation" of the clock we're using, thus // time__incarnation. We really want to track a boot-id, which is unique to // a particular boot of a particular machine. Linux provides this in the // /proc/sys/kernel/random/boot_id file, but that's not available on all // platforms. Our fallback method is to track the "boot-id" of an Acton // node, which we effectively accomplish by just setting time__incarnation // to a random value at startup. As we do this once on startup of an Acton // node, it means we will be able to compare the measurements within the // same Acton node and during that node's lifetime. If the node is // restarted, we will get a new ID and will thus not be able to compare. Nor // are we able to compare between Acton nodes, as it should. // Using Linux boot-id as incarnation FILE* boot_id = fopen("/proc/sys/kernel/random/boot_id", "r"); if (boot_id != NULL) { // Read the contents of the file. char buf[64]; size_t nread = fread(buf, 1, sizeof(buf), boot_id); if (nread > 0) { // Convert the contents to an integer. time__incarnation = time__uuid_to_ulong(buf); log_debug("Using Linux boot-id for clock incarnation id: %lu", time__incarnation); } fclose(boot_id); } // Fallback to random incarnation ID. if (time__incarnation == 0) { // We failed to read the boot ID or don't have one on this platform, so // we just use a random value. time__incarnation = rand(); log_debug("Using random value for clock incarnation id: %lu", time__incarnation); } // Schedule background work to get clock data. Fetching this data using // ntp_adjtime is considerably slower than a simple clock_gettime call, so // we do it in the background. Once every 10 seconds should be enough. // To get an idea, benching on my machine ntp_adjtime is about 50x slower: // ntp_adjtime time per call: 586.459146 ns // ntp_adjtime operations per second: 1705148.614052 // clock_gettime time per call: 17.545191 ns // clock_gettime operations per second: 56995674.769229 // We don't want to slow down our programs like that, getting the time // should be cheap, which is why we do this somewhat elaborate dance. uv_timer_t *time__get_clock_data_ev = acton_malloc(sizeof(uv_timer_t)); uv_timer_init(aux_uv_loop, time__get_clock_data_ev); uv_timer_start(time__get_clock_data_ev, time__get_clock_data_cb, 10000, 10000); time__get_clock_data_cb(NULL); } int64_t timeQ_U__get_incarnation () { return time__incarnation; } B_tuple timeQ_get_monotonic () { uv_timespec64_t ts; if (uv_clock_gettime(UV_CLOCK_MONOTONIC, &ts) == -1) { char errmsg[1024] = "Error getting time: "; uv_strerror_r(errno, errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg)); log_warn("%s", errmsg); $RAISE(((B_BaseException)B_RuntimeErrorG_new(to$str(errmsg)))); } return $NEWTUPLE(2, toB_int(ts.tv_sec), toB_int(ts.tv_nsec)); } B_tuple timeQ_get_realtime () { uv_timespec64_t ts; if (uv_clock_gettime(UV_CLOCK_REALTIME, &ts) == -1) { char errmsg[1024] = "Error getting time: "; uv_strerror_r(errno, errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg)); log_warn("%s", errmsg); $RAISE(((B_BaseException)B_RuntimeErrorG_new(to$str(errmsg)))); } return $NEWTUPLE(2, toB_int(ts.tv_sec), toB_int(ts.tv_nsec)); } B_tuple timeQ_get_clock_data () { #ifdef _WIN32 return $NEWTUPLE(3, toB_int(time__realclock_status), toB_int(0), toB_int(0)); #else return $NEWTUPLE(3, toB_int(time__realclock_status), toB_int(time__realclock_tx.offset), toB_int(time__realclock_tx.esterror)); #endif } B_tuple timeQ_U_1localtime (int64_t seconds) { time_t t = seconds; struct tm tm; #ifdef _WIN32 errno_t result = localtime_s(&tm, &t); if (result != 0) { char errmsg[1024] = "Error getting time: "; uv_strerror_r(errno, errmsg + strlen(errmsg), sizeof(errmsg) - strlen(errmsg)); log_warn("%s", errmsg); $RAISE(((B_BaseException)B_RuntimeErrorG_new(to$str(errmsg)))); } return $NEWTUPLE(11, toB_int(tm.tm_year + 1900), toB_int(tm.tm_mon + 1), toB_int(tm.tm_mday), toB_int(tm.tm_hour), toB_int(tm.tm_min), toB_int(tm.tm_sec), toB_int(tm.tm_wday), toB_int(tm.tm_yday), toB_int(tm.tm_isdst), to$str(""), toB_int(0)); #else localtime_r(&t, &tm); return $NEWTUPLE(11, toB_int(tm.tm_year + 1900), toB_int(tm.tm_mon + 1), toB_int(tm.tm_mday), toB_int(tm.tm_hour), toB_int(tm.tm_min), toB_int(tm.tm_sec), toB_int(tm.tm_wday), toB_int(tm.tm_yday), toB_int(tm.tm_isdst), to$str(tm.tm_zone), toB_int(tm.tm_gmtoff)); #endif } B_tuple timeQ_U_3gmtime (int64_t seconds) { time_t t = seconds; struct tm tm; #ifdef _WIN32 // TODO: implement this! return $NEWTUPLE(9, toB_int(0), toB_int(0), toB_int(0), toB_int(0), toB_int(0), toB_int(0), toB_int(0), toB_int(0), toB_int(0)); #else gmtime_r(&t, &tm); return $NEWTUPLE(9, toB_int(tm.tm_year + 1900), toB_int(tm.tm_mon + 1), toB_int(tm.tm_mday), toB_int(tm.tm_hour), toB_int(tm.tm_min), toB_int(tm.tm_sec), toB_int(tm.tm_wday), toB_int(tm.tm_yday), toB_int(tm.tm_isdst)); #endif } ================================================ FILE: base/src/uri.act ================================================ _UNRESERVED = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~" _HEX_DIGITS = "0123456789ABCDEF" def quote(text: str, safe: str="/") -> str: """Percent-encode a string for use in a URI. Unreserved characters defined by RFC 3986 are preserved. Characters in the safe set are also preserved when they are ASCII bytes. """ allowed = set(_UNRESERVED + safe) encoded = text.encode() parts: list[str] = [] for i in range(len(encoded)): byte = encoded[i] if byte < 128 and chr(byte) in allowed: parts.append(chr(byte)) else: parts.append(_quote_byte(byte)) return "".join(parts) def unquote(text: str) -> str: """Decode percent-escaped bytes in a URI string as UTF-8.""" result = bytearray(b"") i = 0 while i < len(text): if text[i] != "%": _append_bytes(result, text[i].encode()) i += 1 continue if i + 2 >= len(text): raise ValueError("Incomplete percent escape: {text[i:]}") escape = text[i:i+3] hi = _hex_value(text[i+1]) lo = _hex_value(text[i+2]) result.append(hi * 16 + lo) i += 3 try: return result.decode() except ValueError: raise ValueError("Invalid UTF-8 in percent-escaped text") def _append_bytes(result: bytearray, data: bytes) -> None: for i in range(len(data)): result.append(data[i]) def _quote_byte(byte: int) -> str: return "%" + _HEX_DIGITS[byte // 16] + _HEX_DIGITS[byte % 16] def _hex_value(char: str) -> int: idx = _HEX_DIGITS.find(char.upper()) if idx == -1: raise ValueError("Invalid percent escape: %%{char}") return idx class URI(object): """A class representing a Uniform Resource Identifier (URI). Implements parsing according to RFC 1630. Attributes: scheme (str): The URI scheme (e.g. 'http', 'https', 'file') authority (str | None): The authority component (e.g. 'example.com:8080') host (str | None): The hostname part of the authority port (int | None): The port number if specified path (str | None): The path component query (str | None): The query string if present fragment (str | None): The fragment identifier if present """ scheme: ?str authority: ?str host: ?str port: ?int path: ?str query: ?str fragment: ?str def __init__(self, uri_string: str): """Parse a URI string into its components. Args: uri_string: The URI string to parse Raises: ValueError: If the URI string is invalid """ # Parse scheme scheme, remainder = parse_schema(uri_string) self.scheme = scheme # Parse authority authority, host, port, remainder = parse_authority(remainder) self.authority = authority self.host = host self.port = port # Parse path path, remainder = parse_path(remainder) self.path = path # Parse query query, remainder = parse_query(remainder) self.query = query # Parse fragment self.fragment = parse_fragment(remainder) def __str__(self) -> str: """Return the canonical string representation of the URI.""" scheme_sep = "://" if self.scheme is not None else "" query_sep = "?" if self.query is not None else "" frag_sep = "#" if self.fragment is not None else "" return (e_str(self.scheme) + scheme_sep + e_str(self.authority) + e_str(self.path) + query_sep + e_str(self.query) + frag_sep + e_str(self.fragment)) def __repr__(self) -> str: """Return a detailed string representation for debugging.""" return f"URI(scheme='{self.scheme}', authority='{self.authority}', host='{self.host}', port={self.port}, path='{self.path}', query='{self.query}', fragment='{self.fragment}')" def e_str[T](s: ?T) -> str: return str(s) if s is not None else "" def opt_str[T](s: ?T) -> str: return str(s) if s is not None else "None" def is_valid_scheme(scheme: str) -> bool: """ Validate if a scheme string follows RFC 3986 rules: 1. Must begin with a letter 2. Can contain letters, digits, plus (+), period (.), or hyphen (-) 3. Case-insensitive Args: scheme: The scheme string to validate Returns: bool: True if scheme is valid, False otherwise """ if not scheme or not scheme[0].isalpha(): return False # Check each character is valid valid_chars = set('abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' '0123456789' '+.-') return all(map(lambda c: c in valid_chars, scheme)) def parse_schema(uri: str) -> (?str, str): if ":" not in uri: return None, uri split_result = uri.split(":", 1) if len(split_result) == 1: return None, split_result[0] elif len(split_result) == 2: scheme = split_result[0] remainder = split_result[1] if not remainder.startswith("//"): raise ValueError("Invalid separator after scheme") if not is_valid_scheme(scheme): raise ValueError("Invalid scheme") return scheme, remainder[2:] raise ValueError("Invalid URI, unable to parse scheme") def parse_authority(uri: str) -> (?str, ?str, ?int, str): """Parse authority component, returning authority, host, port, and remainder.""" if uri == "": return None, None, None, "" # Find end of authority component slash_idx = uri.find("/") question_idx = uri.find("?") hash_idx = uri.find("#") # Find the first occurring delimiter end_idx = -1 if slash_idx != -1: end_idx = slash_idx if question_idx != -1 and (end_idx == -1 or question_idx < end_idx): end_idx = question_idx if hash_idx != -1 and (end_idx == -1 or hash_idx < end_idx): end_idx = hash_idx # Extract authority and remainder if end_idx == -1: authority = uri remainder = "" else: authority = uri[:end_idx] remainder = uri[end_idx:] if not authority: return None, None, None, remainder # Parse host and port if ":" in authority: host_part = authority.split(":", 1) try: port = int(host_part[1]) if port < 0 or port > 65535: raise ValueError(f"Port must be between 0 and 65535: {host_part[1]}") return authority, host_part[0], port, remainder except ValueError: raise ValueError(f"Invalid port: {host_part[1]}") else: return authority, authority, None, remainder def parse_path(uri: str) -> (?str, str): """Parse path component, returning path and remainder.""" if not uri: return None, "" if uri[0] != "/": uri = "/" + uri question_idx = uri.find("?") hash_idx = uri.find("#") if question_idx != -1 and (hash_idx == -1 or question_idx < hash_idx): return uri[:question_idx], uri[question_idx:] elif hash_idx != -1: return uri[:hash_idx], uri[hash_idx:] else: return uri, "" def parse_query(uri: str) -> (?str, str): """Parse query component, returning query and remainder.""" if not uri or uri[0] != "?": return None, uri hash_idx = uri.find("#") if hash_idx != -1: query = uri[1:hash_idx] return "" if not query else query, uri[hash_idx:] else: query = uri[1:] return "" if not query else query, "" def parse_fragment(uri: str) -> ?str: """Parse fragment component.""" if not uri or uri[0] != "#": return None return "" if len(uri) == 1 else uri[1:] ================================================ FILE: base/src/xml.act ================================================ class Node(): """ A node is an abstract syntax tree for XML. It is similar to Python's xml.etree.ElementTree.Element. A node always represent an XML tagged element; so also the children are elements. Text is represented in the attributes text and tail: in node n, - n.text is the string before n's first child; - n.tail is the string before n's next sibling. So, to get the text at top level of node n, one must concatenate n.text and c.tail for all children of n. """ def __init__(self, tag: str, nsdefs: list[(?str,str)]=[], prefix: ?str=None, attributes: list[(str, str)]=[], children: list[Node]=[], text: ?str=None, tail: ?str=None): self.tag = tag self.nsdefs = nsdefs self.prefix = prefix self.attributes = attributes self.children = children self.text = text self.tail = tail def encode(self, pretty=False) -> str: NotImplemented class XmlParseError(ValueError): """Exception raised for XML parsing errors Attributes: line: The line number where the error occurred (if available) column: The column number where the error occurred (if available) """ line: ?int column: ?int def __init__(self, msg: ?str, line: ?int=None, column: ?int=None): self.error_message = msg if msg is not None else "" self.line = line self.column = column def __str__(self): context = "" if self.line is not None: context += ":{self.line}" if self.column is not None: context += ":{self.column}" return "{self._name()}{context}: {self.error_message}" def __repr__(self): return "{self._name()}({repr(self.error_message)}, {repr(self.line)}, {repr(self.column)})" def decode(data : str) -> Node: NotImplemented def encode(node: Node, pretty=False) -> str: return node.encode(pretty) def toplevel_text(node): """Returns the toplevel text in node, as if all subelements were replaced by sep""" sep = ' ' chunks = [] txt = node.text if txt is not None: chunks.append(txt) for c in node.children: tl = c.tail if tl is not None: chunks.append(tl) return sep.join(chunks) def encode_nodes(nodes: list[Node], pretty=False) -> str: sep = "\n" if pretty else "" return sep.join([node.encode(pretty) for node in nodes]) ================================================ FILE: base/src/xml.ext.c ================================================ #define LIBXML_STATIC #include #include // TODO: The macro below is from builtin/str.c. We should not duplicate it... #define NEW_UNFILLED_STR(nm, nchrs, nbtes) \ assert(nbtes >= nchrs); \ nm = acton_malloc(sizeof(struct B_str)); \ (nm)->$class = &B_strG_methods; \ (nm)->nchars = nchrs; \ (nm)->nbytes = nbtes; \ (nm)->str = acton_malloc_atomic((nm)->nbytes + 1); \ (nm)->str[(nm)->nbytes] = 0 // Helper function to count extra bytes needed for XML escaping // Returns the number of extra bytes needed to replace the special character // with encoded entity (not total bytes) // static int count_xml_escape_extra(B_str str, int escape_quotes) { int extra = 0; // Note: It's safe to iterate byte-by-byte even for UTF-8 strings because we // only check for ASCII characters (&, <, "). The codepoints for ASCII // characters are backwards compatible (0x00-0x7F -> 00000000-01111111). // Continuation bytes (2nd, ...) in multi-byte UTF-8 characters always have // the same pattern 10xxxxxx (0x80-0xBF) so no UTF-8 continuation byte can // be mistaken for an ASCII character. for (int i = 0; i < str->nbytes; i++) { switch (str->str[i]) { case '&': extra += 4; break; // & = 5 bytes instead of 1 case '<': extra += 3; break; // < = 4 bytes instead of 1 case '"': if (escape_quotes) extra += 5; // " = 6 bytes instead of 1 break; } } return extra; } // Helper function to copy string with XML escaping // Returns pointer to position after copied data static unsigned char* copy_with_xml_escape(unsigned char *dst, B_str src, int escape_quotes) { for (int i = 0; i < src->nbytes; i++) { // Note: It's safe to iterate byte-for-byte here because we're only // inserting ASCII and copying (maybe UTF-8 multi-byte) characters as // individual bytes, iterating over the total byte length of B_str switch (src->str[i]) { case '&': memcpy(dst, "&", 5); dst += 5; break; case '<': memcpy(dst, "<", 4); dst += 4; break; case '"': if (escape_quotes) { memcpy(dst, """, 6); dst += 6; } else { *dst++ = src->str[i]; } break; default: *dst++ = src->str[i]; break; } } return dst; } // Helper function to collect text from consecutive TEXT and CDATA nodes // Returns the combined string and updates the node pointer to the first non-text node // Note: cur_ptr is passed by reference (pointer to pointer) so we can update the caller's pointer // to skip past all consumed text/CDATA nodes static B_str collect_text_cdata_nodes(xmlNodePtr *cur_ptr) { xmlNodePtr cur = *cur_ptr; if (!cur || (cur->type != XML_TEXT_NODE && cur->type != XML_CDATA_SECTION_NODE)) { return NULL; } // Count total length of combined text and CDATA nodes size_t text_len = 0; xmlNodePtr text_start = cur; while (cur && (cur->type == XML_TEXT_NODE || cur->type == XML_CDATA_SECTION_NODE)) { if (cur->content) text_len += strlen((char *)cur->content); cur = cur->next; } // Create combined string if (text_len > 0) { char *combined = acton_malloc_atomic(text_len + 1); char *p = combined; xmlNodePtr t = text_start; while (t != cur) { if (t->content) { size_t len = strlen((char *)t->content); memcpy(p, t->content, len); p += len; } t = t->next; } *p = '\0'; B_str result = to_str_noc(combined); *cur_ptr = cur; return result; } *cur_ptr = cur; return NULL; } xmlQ_Node $NodePtr2Node(xmlNodePtr node) { B_SequenceD_list wit = B_SequenceD_listG_witness; if (node->type == XML_COMMENT_NODE) { return NULL; } if (node->type != XML_ELEMENT_NODE) { char *errmsg = NULL; RAISE(xmlQ_XmlParseError, $FORMAT("Unexpected nodetype %d, content is %s", node->type, node->content), NULL, NULL); } B_list nsdefs = B_listG_new(NULL, NULL); xmlNsPtr nsDef = node->nsDef; while (nsDef) { B_str prefix = NULL; if (nsDef->prefix) prefix = to$str((char *)nsDef->prefix); B_str href = to$str((char *)nsDef->href); wit->$class->append(wit,nsdefs, $NEWTUPLE(2, prefix, href)); nsDef=nsDef->next; } B_str prefix = NULL; if (node->ns && node->ns->prefix) prefix = to$str((char *)node->ns->prefix); B_list attributes = B_listG_new(NULL, NULL); xmlAttrPtr attr = node->properties; while (attr) { B_str attr_name; // libxml2 handles namespace prefixes in two ways: // 1. Defined namespaces: attr->ns is set, attr->name has local name only // e.g., xmlns:ns="http://foo" ns:op="x" -> attr->ns->prefix="ns", attr->name="op" // 2. Undefined namespaces: attr->ns is NULL, attr->name contains the full prefixed name // e.g., ns:op="x" (no xmlns:ns) -> attr->ns=NULL, attr->name="ns:op" if (attr->ns && attr->ns->prefix) { // Reconstruct prefixed name for defined namespace attr_name = $FORMAT("%s:%s", attr->ns->prefix, attr->name); } else { // Use name as-is (either unprefixed or undefined prefix already in name) attr_name = to$str((char *)attr->name); } wit->$class->append(wit,attributes, $NEWTUPLE(2, attr_name, to$str((char *)xmlGetProp(node, attr->name)))); attr = attr->next; } B_list children = B_listG_new(NULL, NULL); xmlNodePtr cur = node->xmlChildrenNode; // Collect initial text/CDATA nodes B_str text = collect_text_cdata_nodes(&cur); while (cur != NULL) { xmlQ_Node child = $NodePtr2Node(cur); if (child) wit->$class->append(wit,children, child); cur = cur->next; } // Collect tail text/CDATA nodes after we have exhausted the child nodes cur = node->next; B_str tail = collect_text_cdata_nodes(&cur); // Update the tree structure to skip consumed tail text/CDATA nodes. // This prevents the parent from seeing these text nodes again during its // child iteration, since tail text of an element is part of the parent's // child list in the XML tree. node->next = cur; return (xmlQ_Node)$NEW(xmlQ_Node, to$str((char *)node->name), nsdefs, prefix, attributes, children, text, tail); } xmlQ_Node xmlQ_decode(B_str data) { // With XML_PARSE_NOERROR we suppress printing error and warning reports to stderr xmlDocPtr doc = xmlReadMemory((char *)data->str, data->nbytes, NULL, NULL, XML_PARSE_NOERROR); if (!doc) { xmlErrorPtr err = xmlGetLastError(); B_str errmsg; B_int line = NULL; B_int column = NULL; if (err && err->message) { if (err->line > 0) { line = toB_int(err->line); } if (err->int2 > 0) { // int2 contains the column in libxml2 column = toB_int(err->int2); } // Strip trailing whitespace from error message if needed int orig_len = strlen(err->message); int len = orig_len; while (len > 0 && isspace((unsigned char)err->message[len-1])) { len--; } if (len < orig_len) { // Only copy if we actually stripped something char msg_clean[len + 1]; strncpy(msg_clean, err->message, len); msg_clean[len] = '\0'; errmsg = to$str(msg_clean); } else { // Use original message as-is errmsg = to$str(err->message); } } else { errmsg = to$str("XML parse error"); } RAISE(xmlQ_XmlParseError, errmsg, line, column); } xmlNodePtr root = xmlDocGetRootElement(doc); xmlQ_Node t = $NodePtr2Node(root); xmlFreeDoc(doc); return t; } static B_str xmlQ_encode_nsdefs(B_list nsdefs); static B_str xmlQ_encode_attrs(B_list attrs); B_str xmlQ_node2str(xmlQ_Node node, bool pretty, int depth) { B_str nsdefs = xmlQ_encode_nsdefs(node->nsdefs); B_str attrs = xmlQ_encode_attrs(node->attributes); // Is this an empty element (no text, no children), then use self-closing tag bool is_empty = !node->text && node->children->length == 0; // Encode the child nodes to a single string (pretty-printed) bool has_children = node->children->length > 0; B_str nul = to$str(""); B_str children_str; if (has_children) { B_list children = B_listD_new(node->children->length); children->length = node->children->length; for (int i = 0; i < node->children->length; i++) { xmlQ_Node ch = (xmlQ_Node)node->children->data[i]; children->data[i] = xmlQ_node2str(ch, pretty, depth + 1); } if (pretty) { // Join with newlines B_str separator = to$str("\n"); children_str = separator->$class->join(separator, B_SequenceD_listG_witness->W_Collection, children); } else { // Join with empty string children_str = nul->$class->join(nul, B_SequenceD_listG_witness->W_Collection, children); } } else { children_str = nul; } // Calculate extra bytes needed for escaping text and tail int text_extra = node->text ? count_xml_escape_extra(node->text, 0) : 0; int tail_extra = node->tail ? count_xml_escape_extra(node->tail, 0) : 0; int indent_size = pretty ? depth * 2 : 0; // Calculate total size int res_bytes = indent_size + (is_empty ? 1 : 2) * (node->tag->nbytes + (node->prefix ? node->prefix->nbytes + 1 : 0)) + nsdefs->nbytes + attrs->nbytes + (is_empty ? 0 : (node->text ? node->text->nbytes + text_extra : 0)) + (is_empty ? 0 : (has_children && pretty ? 1 : 0)) + // newline before children (is_empty ? 0 : children_str->nbytes) + (is_empty ? 0 : (has_children && pretty ? 1 + indent_size : 0)) + // newline + indent before closing (node->tail ? node->tail->nbytes + tail_extra : 0) + (is_empty ? 3 : 5); // self-closing tag - 3 bytes (< / >); open+close tag - 5 bytes (< > < / >) int res_chars = indent_size + (is_empty ? 1 : 2) * (node->tag->nchars + (node->prefix ? node->prefix->nchars + 1 : 0)) + nsdefs->nchars + attrs->nchars + (is_empty ? 0 : (node->text ? node->text->nchars + text_extra : 0)) + (is_empty ? 0 : (has_children && pretty ? 1 : 0)) + (is_empty ? 0 : children_str->nchars) + (is_empty ? 0 : (has_children && pretty ? 1 + indent_size : 0)) + (node->tail ? node->tail->nchars + tail_extra : 0) + (is_empty ? 3 : 5); // Build the result string B_str res; NEW_UNFILLED_STR(res, res_chars, res_bytes); unsigned char *p = res->str; // Write initial indentation for (int i = 0; i < indent_size; i++) { *p++ = ' '; } // Write opening tag *p++ = '<'; if (node->prefix) { memcpy(p, node->prefix->str, node->prefix->nbytes); p += node->prefix->nbytes; *p++ = ':'; } memcpy(p, node->tag->str, node->tag->nbytes); p += node->tag->nbytes; memcpy(p, nsdefs->str, nsdefs->nbytes); p += nsdefs->nbytes; memcpy(p, attrs->str, attrs->nbytes); p += attrs->nbytes; // Write self-closing tag or children followed by explicit close tag if (is_empty) { *p++ = '/'; *p++ = '>'; } else { *p++ = '>'; // Write text content if (node->text) { p = copy_with_xml_escape(p, node->text, 0); } if (has_children) { // Write newline after opening tag, write children if (pretty) { *p++ = '\n'; } memcpy(p, children_str->str, children_str->nbytes); p += children_str->nbytes; // Write newline and indent before closing tag if needed if (pretty) { *p++ = '\n'; for (int i = 0; i < indent_size; i++) { *p++ = ' '; } } } // Write closing tag *p++ = '<'; *p++ = '/'; if (node->prefix) { memcpy(p, node->prefix->str, node->prefix->nbytes); p += node->prefix->nbytes; *p++ = ':'; } memcpy(p, node->tag->str, node->tag->nbytes); p += node->tag->nbytes; *p++ = '>'; } // Write tail if (node->tail) { p = copy_with_xml_escape(p, node->tail, 0); } return res; } static B_str xmlQ_encode_nsdefs(B_list nsdefs) { int res_bytes = 0; int res_chars = 0; for (int i=0; ilength;i++) { B_tuple nsdef = nsdefs->data[i]; B_str prefix = (B_str)nsdef->components[0]; B_str href = (B_str)nsdef->components[1]; // Count extra bytes needed for escaping href int href_extra = count_xml_escape_extra(href, 1); res_bytes += (prefix ? prefix->nbytes+1 : 0) + href->nbytes + href_extra + 9; // 9 = len(" xmlns" + "=" + '"' + '"') res_chars += (prefix ? prefix->nchars+1 : 0) + href->nchars + href_extra + 9; } B_str res; NEW_UNFILLED_STR(res, res_chars, res_bytes); unsigned char *p = res->str; for (int i=0; ilength; i++) { B_tuple nsdef = nsdefs->data[i]; *p++ = ' '; B_str prefix = (B_str)nsdef->components[0]; B_str href = (B_str)nsdef->components[1]; char * xmlns = "xmlns"; memcpy(p, xmlns, 5); p += 5; if (prefix) { *p++ = ':'; memcpy(p, prefix->str, prefix->nbytes); p += prefix->nbytes; } *p++ = '='; *p++ = '"'; p = copy_with_xml_escape(p, href, 1); *p++ = '"'; } return res; } static B_str xmlQ_encode_attrs(B_list attrs) { int res_bytes = 0; int res_chars = 0; for (int i=0; i < attrs->length; i++) { B_tuple attr = attrs->data[i]; B_str key = (B_str)attr->components[0]; B_str value = (B_str)attr->components[1]; // Count extra bytes needed for escaping int extra_bytes = count_xml_escape_extra(value, 1); res_bytes += key->nbytes + value->nbytes + extra_bytes + 4; // 4 = len(" " + "=" + "'" + "'") res_chars += key->nchars + value->nchars + extra_bytes + 4; } B_str res; NEW_UNFILLED_STR(res, res_chars, res_bytes); unsigned char *p = res->str; for (int i=0; i < attrs->length; i++) { B_tuple attr = attrs->data[i]; B_str key = (B_str)attr->components[0]; B_str value = (B_str)attr->components[1]; *p++ = ' '; memcpy(p, key->str, key->nbytes); p += key->nbytes; *p++ = '='; *p++ = '"'; p = copy_with_xml_escape(p, value, 1); *p++ = '"'; } return res; } B_str xmlQ_NodeD_encode(xmlQ_Node self, B_bool pretty) { // Use the internal function with depth 0 for the root node return xmlQ_node2str(self, pretty ? pretty->val != 0 : false, 0); } void xmlQ___ext_init__() { // NOP } ================================================ FILE: bin/runacton ================================================ #!/bin/sh # runacton, through use of a shebang line, allows execution of Acton source # files a la "shell script" style. Start your .act source code file with: # # #!/usr/bin/env runacton # # And you can execute it directly! Under the hood the .act source file is # compiled by acton into a binary which is then executed. The original # arguments are passed through. set -e if [ $# -lt 1 ]; then echo "runacton: missing .act file path (runacton is meant to be invoked via shebang)" >&2 exit 2 fi script="$1" ACTON_RUNACTON=1 acton --quiet "$script" EXEC="${script%.act}" shift exec "$EXEC" "$@" ================================================ FILE: compiler/.gitignore ================================================ acton.cabal ================================================ FILE: compiler/CLAUDE.md ================================================ # Acton Compiler - Development Guide The Acton compiler (`acton`) is written in Haskell and compiled Acton source code into C code that can be compiled and linked with the runtime system. ## Quick Reference ### Build & Test ```bash # Build just the compiler (fastest iteration) make dist/bin/acton # Run compiler tests make test-compiler # Run specific test suite cd compiler && stack test --test-arguments "--filter pattern" # Build with profiling cd compiler && stack build --profile ``` ### Key Directories ``` compiler/ ├── lib/ # Main compiler library │ ├── src/Acton/ # Core compiler modules │ └── test/ # Compiler unit tests ├── acton/ # Compiler executable │ ├── Main.hs # Entry point │ └── test/ # Snapshot tests └── lsp-server/ # Language server ``` ## Compilation Pipeline The compiler transforms Acton code through multiple stages: ``` Source Code (.act) ↓ Parser AST (Abstract Syntax Tree) ↓ Type Checker Typed AST ↓ Normalizer Normalized AST ↓ Deactorizer Deactorized AST ↓ CPS Transform CPS Form ↓ Lambda Lifter Lifted Form ↓ Boxing Boxed Form ↓ Code Generator C Code (.c, .h) ``` ## Key Modules ### Core Pipeline (`compiler/lib/src/Acton/`) #### Parser.hs - Megaparsec-based parser - Produces AST from source code - Handles Python-like syntax with Acton extensions - Entry point: `parseModule` #### Types.hs & TypeEnv.hs - Type system definitions - Type inference engine - Constraint solving - Key types: `Type`, `Scheme`, `TyEnv` #### Normalizer.hs - Simplifies AST for easier processing - Desugars complex expressions - Handles pattern matching expansion #### Deactorizer.hs - Transforms actor methods into regular functions - Converts actor state into explicit parameters - Handles message passing semantics #### CPS.hs - Continuation-Passing Style transformation - Makes control flow explicit - Prepares for async operations #### LambdaLifter.hs - Lifts nested functions to top level - Closure conversion - Prepares for C code generation #### Boxing.hs - Converts between boxed/unboxed representations - Handles primitive type optimizations #### CodeGen.hs - Generates C code from final AST - Produces `.c` and `.h` files - Integrates with runtime system ### Supporting Modules #### Env.hs - Environment management - Module system handling - Import resolution #### Diagnostics.hs - Error message generation - Source location tracking - Pretty printing errors #### QuickType.hs - Fast type checking for IDE support - Incremental type inference ## Working with the Compiler ### Adding a New Language Feature 1. **Update Parser** (`Parser.hs`) - Add new syntax rules - Update AST types in `Syntax.hs` 2. **Update Type System** (`Types.hs`) - Add type rules for new construct - Update type inference 3. **Update Normalizer** (`Normalizer.hs`) - Add normalization rules - Ensure simplified form 4. **Update Code Generation** (`CodeGen.hs`) - Generate appropriate C code - Link with runtime if needed 5. **Add Tests** - Parser tests in `lib/test/` - Type error tests in `acton/test/typeerrors/` - Snapshot tests for code generation ### Debugging the Compiler ```haskell -- Add debug prints in any module import Debug.Trace -- In your code traceShow ("Debug info", someValue) $ restOfExpression -- Or use the built-in pretty printer import Pretty traceShow (renderDoc $ pp someAst) $ ... ``` ### Testing Documentation Generation Documentation generation tests are located in `test/test_doc_printing/`. This directory contains various test files demonstrating different documentation scenarios. To test documentation generation: ```bash acton doc src/basics.act # Whole project acton doc ``` ### Error Messages Error messages are crucial for user experience. When adding new errors: 1. Create descriptive error in `Diagnostics.hs` 2. Add snapshot test in `acton/test/typeerrors/` 3. Include: - Clear description of the problem - Source location - Suggested fix if possible Example: ```haskell throwError $ TypeError loc $ "Cannot unify types" <+> pp ty1 <+> "and" <+> pp ty2 ``` ## Type System Details ### Type Inference - Hindley-Milner with extensions - Row polymorphism for records - Subtyping for actors - Protocol constraints ### Special Types - `World` - Represents side effects - `Msg` - Actor message types - `Cap` - Capability types - `Ref` - Reference types ## Testing Strategy ### Unit Tests (`lib/test/`) - Test individual compiler phases - Use sydtest framework - Fast, focused tests ### Snapshot Tests (`acton/test/`) - Compare compiler output against expected - Syntax errors: `syntaxerrors/` - Type errors: `typeerrors/` - Update with: `--accept` flag ### Integration Tests - Full compilation tests in `test/` - Ensure generated C code works ## Common Tasks ### Adding a Builtin Function 1. Add signature in `Builtin.hs` 2. Add type in builtin environment 3. Generate C call in `CodeGen.hs` ### Improving Error Messages 1. Identify error location in type checker 2. Add case in `Diagnostics.hs` 3. Create snapshot test 4. Iterate on message clarity ### Optimizing Compilation 1. Profile with `stack build --profile` 2. Run with `+RTS -p` 3. Check `.prof` file 4. Focus on hot paths in type checker ## Haskell Style Guide ```haskell -- Module header module Acton.Parser ( parseModule , parseExpression , ParseError ) where -- Explicit imports import qualified Data.Text as T import Data.Maybe (fromMaybe) -- Type signatures for all top-level functions parseModule :: T.Text -> Either ParseError Module parseModule input = ... -- Use where clauses for clarity processAst :: Ast -> Result processAst ast = process initialEnv ast where initialEnv = mkEnv process env node = ... -- Pattern match explicitly compile :: Source -> Either Error Output compile (Source file content) = do ast <- parse content typed <- typeCheck ast generateCode typed ``` ### Whiteboard Layout Style The Acton compiler uses a distinctive "whiteboard layout" style in many places, especially in the type system and constraint solving code. This style uses very deep indentation to create mathematical equation-like layouts: ```haskell -- Function signatures and implementations aligned far from left margin infTop :: Env -> Suite -> TypeM (TEnv,Suite) infTop env ss = do -- Implementation starts at column 41+ pushFX fxPure tNone (cs,te,ss) <- infSuiteEnv env ss ss <- msubst ss return (te, ss) -- Pattern matching with deep alignment infEnv env (For l p e b els) | nodup p = do -- Guard at column 41 (cs1,te,t1,p') <- infEnvT env p t2 <- newTVar return (cs1++cs2, [], result) -- Where clauses with mathematical alignment addTyping env n s t c = c {info = addT n (simp env s) t (info c)} where addT n s t (DfltInfo l m mbe ts) = DfltInfo l m mbe ((n,s,t):ts) -- Continuation aligned for visual clarity ``` **Key characteristics of whiteboard layout:** 1. **Deep indentation** (often columns 40-50) for do-blocks and expressions 2. **Vertical alignment** of related terms for easy visual comparison 3. **Mathematical appearance** - equations and expressions laid out like on a whiteboard 4. **Structural emphasis** - the layout highlights the logical structure of complex expressions 5. **Common in type inference** - especially prevalent in Types.hs, TypeEnv.hs, and constraint solving code This style helps when working with complex mathematical algorithms by making the structure visually apparent, similar to how one would write equations on a whiteboard with careful spacing and alignment. ## Acton Compiler Style Guide These patterns represent the ideal coding style for the Acton compiler. These principles apply broadly across the entire codebase and should be followed in all contributions: ### 1. **Simplify and Remove Dead Code** ```haskell -- BAD: Keep unused data types, functions, or complex abstractions data CompInfo = CompInfo Expr | CompWithWit Expr Expr -- Dead code normalize' env x = normalize env x -- Unnecessary wrapper -- GOOD: Keep only what's needed type NormM a = State (Int,[(Name,PosPar,Expr)]) a normalize env x = ... -- Direct implementation ``` ### 2. **Separate Concerns Clearly** ```haskell -- BAD: Mix different responsibilities in one function processExpr env expr = case expr of Add x y -> let tx = typeOf x ty = typeOf y in if tx == ty then ... else error ... Mul x y -> ... -- Similar mixed logic -- GOOD: Separate type checking from transformation typeCheck env expr = ... -- Just type checking transform env expr = ... -- Just transformation -- Or factor out common patterns processExpr env expr = transform env (typeCheck env expr) ``` ### 3. **Use Generic Abstractions Over Ad-Hoc Solutions** ```haskell -- BAD: Create specific functions for each use case handleListError :: Error -> String handleDictError :: Error -> String handleSetError :: Error -> String -- GOOD: One generic function that handles all cases handleError :: Error -> String handleError (TypeError t) = "Type error: " ++ show t handleError (SyntaxError s) = "Syntax error: " ++ s ``` ### 4. **Consistent Naming and Alignment** ```haskell -- Use consistent variable names across the codebase: -- env - Environment -- t - Type -- e - Expression -- p - Pattern or Parameter -- n - Name -- l - Location -- s - Statement or String -- c - Constraint or Context -- w - Witness -- r - Result or Row -- Align related definitions for visual clarity tInt = tCon (TC qnInt []) tFloat = tCon (TC qnFloat []) tString = tCon (TC qnString []) tBool = tCon (TC qnBool []) ``` ### 5. **Factor Out Common Patterns** ```haskell -- BAD: Repeat similar code in multiple places infer env (Add e1 e2) = do (cs1, t1, e1') <- infer env e1 (cs2, t2, e2') <- infer env e2 t <- newTVar return (cs1 ++ cs2 ++ [Cast t1 t, Cast t2 t], t, Add e1' e2') infer env (Mul e1 e2) = do (cs1, t1, e1') <- infer env e1 (cs2, t2, e2') <- infer env e2 t <- newTVar return (cs1 ++ cs2 ++ [Cast t1 t, Cast t2 t], t, Mul e1' e2') -- GOOD: Extract common binary operation pattern inferBinOp env op e1 e2 = do (cs1, t1, e1') <- infer env e1 (cs2, t2, e2') <- infer env e2 t <- newTVar return (cs1 ++ cs2 ++ [Cast t1 t, Cast t2 t], t, op e1' e2') ``` ### 6. **Clear Data Flow with Where Clauses** ```haskell -- Structure where clauses to show data dependencies clearly processExpr env expr = finalResult where -- 1. Extract/compute base values baseType = typeOf env expr location = loc expr -- 2. Build intermediate results constraints = gatherConstraints baseType simplified = simplify expr -- 3. Construct final result finalResult = Result simplified constraints location -- Each binding depends only on earlier bindings -- Clear progression from inputs to outputs ``` ### 7. **Handle Each Case in Its Own Context** ```haskell -- BAD: Share state across unrelated computations processAll items = do state <- initState mapM (process state) items -- Shared mutable state -- GOOD: Each computation gets fresh context processAll items = mapM processOne items where processOne item = do state <- initState -- Fresh state for each process state item ``` ### 8. **Prefer Explicit Over Implicit** ```haskell -- BAD: Rely on implicit behavior findThing xs = head xs -- Crashes on empty list -- GOOD: Make expectations explicit findThing xs = case xs of [] -> error "findThing: empty list" (x:_) -> x -- Or better, use Maybe findThing :: [a] -> Maybe a findThing [] = Nothing findThing (x:_) = Just x ``` ### Key Principle: These Patterns Apply Everywhere The above patterns aren't specific to any particular feature or module. They represent the ideal coding style throughout: - **Parser**: Clean separation of lexing/parsing concerns - **Type Checker**: Generic constraint handling, clear error messages - **Normalizer**: Simple transformations, no unnecessary complexity - **Code Generator**: Explicit mappings, clear output structure - **All modules**: Consistent naming, factored patterns, clean data flow When in doubt, look at recent high-quality commits in the repository for examples of how to refactor code to match these ideals. ## AI-Assisted Development Process When working with AI assistants on the Acton compiler, follow this structured approach: ### 1. **Problem Discussion Phase** - Thoroughly discuss the problem and solution requirements - Identify affected compiler phases - Consider edge cases and interactions with existing features ### 2. **Test-Driven Development** ```haskell -- AI writes test cases based on requirements -- Human reviews and approves test suite -- Example: test/comprehensions/generic_test.act def test_generic_list_comp(): result = [x * 2 for x in [1, 2, 3]] testing.assertEqual(result, [2, 4, 6]) ``` ### 3. **Implementation Phase** - AI implements code to pass tests - Iteratively compile and run tests - Fix errors until all tests pass ### 4. **Code Review and Cleanup Phase** ⚠️ **CRITICAL** After getting tests to pass, AI MUST perform a holistic code review: #### Checklist for AI Code Review: - [ ] **Remove dead code** - Delete unused functions, data types, imports - [ ] **Simplify complex patterns** - Look for opportunities to factor out common code - [ ] **Check naming consistency** - Ensure variables and functions follow conventions - [ ] **Verify error handling** - Proper error messages with source locations - [ ] **Review data flow** - Ensure clean separation of concerns - [ ] **Check integration** - Verify the change fits well with existing code - [ ] **Update related code** - Ensure all affected areas are updated #### Example Cleanup Pattern: ```haskell -- BEFORE: Quick fix to pass tests addCompWithWit :: (Name,PosPar,Expr,Expr) -> NormM () addComp :: (Name,PosPar,Expr) -> NormM () -- Two similar functions, ad-hoc solution -- AFTER: Unified clean design addComp :: (Name,PosPar,Expr) -> NormM () -- Single function, witness handled through annotation ``` ### 5. **Final Review Before Commit** - Ensure code follows the Acton compiler style guide - Verify no regression in existing functionality - Check that the solution is elegant and maintainable - Confirm error messages are helpful ## Common Pitfalls to Avoid 1. **Tunnel Vision**: Don't focus only on making tests pass 2. **Ad-hoc Solutions**: Avoid quick fixes that complicate the codebase 3. **Inconsistent Patterns**: Match existing code style and patterns 4. **Missing Edge Cases**: Consider all variants (e.g., nested comprehensions) 5. **Poor Error Messages**: Always include helpful context in errors ## Performance Considerations 1. **Parser Performance** - Use strict Text, not String - Careful with backtracking 2. **Type Checker Performance** - Cache type environments - Minimize constraint solving 3. **Code Generation** - Stream output when possible - Batch C file writes ## Integration with Build System The compiler is invoked by: - Zig build system for Acton projects - CLI tool for user commands - Test harness for testing Key interfaces: - Command line arguments - JSON output for errors - File system conventions ================================================ FILE: compiler/acton/Main.hs ================================================ {-# LANGUAGE CPP #-} -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- module Main where import Prelude hiding (readFile, writeFile) import qualified Acton.Parser import qualified Acton.Syntax as A import qualified Acton.NameInfo as I import Text.Megaparsec.Error (ParseErrorBundle) import Acton.Parser (CustomParseError) import qualified Acton.CommandLineParser as C import Acton.Printer () import qualified Acton.Env import Acton.Env (simp, define, setMod) import qualified Acton.QuickType import qualified Acton.Kinds import qualified Acton.Types import qualified Acton.Solver import qualified Acton.Normalizer import qualified Acton.CPS import qualified Acton.Deactorizer import qualified Acton.LambdaLifter import qualified Acton.Boxing import qualified Acton.CodeGen import qualified Acton.BuildSpec as BuildSpec import qualified Acton.Builtin import qualified Acton.DocPrinter as DocP import qualified Acton.Diagnostics as Diag import qualified Acton.Fingerprint as Fingerprint import qualified Acton.SourceProvider as Source import Acton.Compile import Utils import qualified Pretty import qualified InterfaceFiles import qualified PkgCommands import Control.Concurrent.MVar import Control.Exception (throw,catch,finally,IOException,try,SomeException,bracket,bracket_,onException,evaluate) import Control.Exception (bracketOnError) import Control.Concurrent (ThreadId, forkIO, killThread, threadDelay) import Control.Concurrent.Chan (Chan, newChan, writeChan, readChan) import Control.Monad import Data.Bits import Data.Default.Class (def) import Data.List.Split import Data.IORef import Data.Maybe (catMaybes, isJust) import Data.Monoid ((<>)) import Data.Word (Word32) import Data.Graph import Data.String.Utils (replace) import Data.Version (showVersion) import Data.Char (toLower) import qualified Data.List import Data.Either (partitionEithers) import qualified Data.Map as M import qualified Data.Set import Data.Time.Clock (UTCTime) import Error.Diagnose import Error.Diagnose.Style (defaultStyle) import qualified Filesystem.Path.CurrentOS as Fsco import GHC.Conc (getNumCapabilities, getNumProcessors, setNumCapabilities, myThreadId, threadCapability) import Prettyprinter (unAnnotate) import Prettyprinter.Render.Text (hPutDoc) import Data.List (isPrefixOf, isSuffixOf, find, partition, foldl', nub, intercalate) import System.Clock import System.Directory import System.Directory.Recursive import System.Environment (lookupEnv) import System.Exit import System.FileLock import System.FilePath ((), addTrailingPathSeparator) import System.FilePath.Posix import System.IO hiding (readFile, writeFile) import Text.PrettyPrint (renderStyle, style, Style(..), Mode(PageMode)) import Text.Show.Pretty (ppDoc) import System.IO.Temp import System.IO.Unsafe (unsafePerformIO) import System.Info import System.Posix.Files import System.Posix.IO (createPipe, setFdOption, closeFd, FdOption(..)) import System.Process hiding (createPipe) import qualified System.FSNotify as FS import qualified System.Environment import qualified System.Exit import qualified Paths_acton import System.Random (randomRIO) import Text.Printf import qualified Data.ByteString.Lazy as BL import TestRunner import TerminalProgress import TerminalSize import ZigProgress main = do hSetBuffering stdout LineBuffering arg <- C.parseCmdLine let gopts = case arg of C.CmdOpt g _ -> g C.CompileOpt _ g _ -> g ensureCapabilities gopts let run = case arg of C.CmdOpt gopts (C.New opts) -> createProject (C.file opts) C.CmdOpt gopts (C.Build bopts) -> let opts = C.buildCompile bopts files = C.buildFiles bopts in if null files then buildProject gopts opts else buildFiles gopts opts files C.CmdOpt gopts (C.Install opts) -> PkgCommands.installCommand gopts opts C.CmdOpt gopts (C.Uninstall opts) -> PkgCommands.uninstallCommand gopts opts C.CmdOpt gopts (C.Sig opts) -> sigCommand gopts opts C.CmdOpt gopts (C.Test tcmd) -> runTests gopts tcmd C.CmdOpt gopts C.Fetch -> fetchCommand gopts C.CmdOpt gopts C.PkgShow -> pkgShow gopts C.CmdOpt gopts (C.PkgAdd opts) -> PkgCommands.pkgAddCommand gopts opts C.CmdOpt gopts (C.PkgRemove opts) -> PkgCommands.pkgRemoveCommand gopts opts C.CmdOpt gopts (C.PkgUpgrade opts) -> PkgCommands.pkgUpgradeCommand gopts opts C.CmdOpt gopts C.PkgUpdate -> PkgCommands.pkgUpdateCommand gopts C.CmdOpt gopts (C.PkgSearch opts) -> PkgCommands.pkgSearchCommand gopts opts C.CmdOpt gopts (C.BuildSpecCmd o) -> buildSpecCommand o C.CmdOpt gopts (C.Cloud opts) -> undefined C.CmdOpt gopts (C.Doc opts) -> printDocs gopts opts C.CmdOpt gopts (C.ZigPkgAdd opts) -> PkgCommands.zigPkgAddCommand gopts opts C.CmdOpt gopts (C.ZigPkgRemove opts) -> PkgCommands.zigPkgRemoveCommand gopts opts C.CmdOpt gopts C.Version -> printVersion C.CompileOpt nms gopts opts -> runFile gopts opts (head nms) run `catch` \(ProjectError msg) -> printErrorAndExit msg -- Apply global options to compile options applyGlobalOpts :: C.GlobalOptions -> C.CompileOptions -> C.CompileOptions applyGlobalOpts gopts opts = opts runFile :: C.GlobalOptions -> C.CompileOptions -> FilePath -> IO () runFile gopts opts fname = case takeExtension fname of ".act" -> buildFile gopts (applyGlobalOpts gopts opts) fname ".ty" -> printDocs gopts (C.DocOptions fname (Just C.AsciiFormat) Nothing) _ -> printErrorAndExit ("Unknown filetype: " ++ fname) -- Ensure enough capabilities: honor --jobs if set, otherwise at least 2 or #procs. ensureCapabilities :: C.GlobalOptions -> IO () ensureCapabilities gopts = do caps0 <- getNumCapabilities let req = C.jobs gopts when (req > 0 && caps0 < req) $ setNumCapabilities req when (req == 0 && caps0 < 2) $ do procs <- getNumProcessors setNumCapabilities (max 2 procs) -- Auxiliary functions --------------------------------------------------------------------------------------- optimizeModeToZig :: C.OptimizeMode -> String optimizeModeToZig C.Debug = "Debug" optimizeModeToZig C.ReleaseSafe = "ReleaseSafe" optimizeModeToZig C.ReleaseSmall = "ReleaseSmall" optimizeModeToZig C.ReleaseFast = "ReleaseFast" zig :: Paths -> FilePath zig paths = sysPath paths ++ "/zig/zig" -- Try to acquire a lock, return Nothing if failed, Just (FileLock, FilePath) if succeeded tryLock :: FilePath -> IO (Maybe (FileLock, FilePath)) tryLock lockPath = do maybeLock <- tryLockFile lockPath Exclusive -- This will fail immediately if locked case maybeLock of Nothing -> return Nothing -- Lock failed Just lock -> return $ Just (lock, lockPath) -- Try locks sequentially until one succeeds or all fail findAvailableScratch :: FilePath -> IO (Maybe (FileLock, FilePath)) findAvailableScratch basePath = go [0..31] -- 32 possible scratch directories where go [] = return Nothing -- All attempts failed go (x:xs) = do let lockPath = joinPath [basePath, "scratch" ++ show x ++ ".lock"] result <- tryLock lockPath case result of Just lockInfo -> return $ Just lockInfo Nothing -> go xs -- Try next number printErrorAndExit msg = do errorWithoutStackTrace msg System.Exit.exitFailure -- our own readFile & writeFile with hard-coded utf-8 encoding (atomic writes) readFile f = do h <- openFile f ReadMode hSetEncoding h utf8 c <- hGetContents h return c writeFile :: FilePath -> String -> IO () writeFile = writeFileUtf8Atomic ignoreIOException :: IOException -> IO () ignoreIOException _ = return () writeFileAtomic :: FilePath -> String -> IO () writeFileAtomic f c = do let dir = takeDirectory f bracketOnError (openTempFile dir ".acton-tmp") (\(tmpPath, tmpHandle) -> do hClose tmpHandle `catch` ignoreIOException removeFile tmpPath `catch` ignoreIOException) (\(tmpPath, tmpHandle) -> do hSetEncoding tmpHandle utf8 hPutStr tmpHandle c hClose tmpHandle renameFile tmpPath f `catch` handleRenameError tmpPath) where handleRenameError :: FilePath -> IOException -> IO () handleRenameError tmpPath _ = do removeFile f `catch` ignoreIOException renameFile tmpPath f -- | Format a TimeSpec as seconds with millisecond precision. fmtTimePrecise :: TimeSpec -> String fmtTimePrecise t = printf "%6.3f s" secs where secs :: Float secs = (fromIntegral (sec t)) + (fromIntegral (nsec t) / 1000000000) -- | Format a TimeSpec with second granularity for compact narrow logs. fmtTimeCompact :: TimeSpec -> String fmtTimeCompact t = if wholeSecs <= 0 && remNanos > 0 then "<1s" else show roundedSecs ++ "s" where wholeSecs = fromIntegral (sec t) :: Integer remNanos = nsec t roundedSecs = wholeSecs + if remNanos >= 500000000 then 1 else 0 -- | Pad a string with trailing spaces for aligned output. padRight :: Int -> String -> String padRight width s | len >= width' = s | otherwise = s ++ replicate (width' - len) ' ' where width' = max 0 width len = length s -- | Pad a string with leading spaces for aligned output. padLeft :: Int -> String -> String padLeft width s | len >= width' = s | otherwise = replicate (width' - len) ' ' ++ s where width' = max 0 width len = length s progressSpinnerThreshold :: Int progressSpinnerThreshold = 25 progressPrefixWidth :: Int -> Int progressPrefixWidth cols | cols >= progressSpinnerThreshold = 3 | otherwise = 0 -- | Truncate a string on the right with an ellipsis when it does not fit. abbreviateRight :: Int -> String -> String abbreviateRight width s | width <= 0 = "" | length s <= width = s | width <= 3 = take width s | otherwise = take (width - 3) s ++ "..." -- | Compress a module label to preserve the root and as much of the tail as fits. fitBuildModuleLabel :: Int -> String -> String fitBuildModuleLabel width label | width <= 0 = "" | length label <= width = label | width < 10 = termFitPlainLeft width label | otherwise = case break (== '.') label of (root, '.':rest) -> let rootBudget = min (length root) (max 1 (width - 4)) tailBudget = max 0 (width - rootBudget - 3) in if tailBudget <= 0 then termFitPlainLeft width label else take rootBudget root ++ "..." ++ termFitPlainLeft tailBudget rest _ -> abbreviateRight width label type StatusRenderer = Int -> Maybe String staticStatusRenderer :: String -> String -> StatusRenderer staticStatusRenderer full short budget | budget < 10 = Nothing | length full <= budget = Just full | length short <= budget = Just short | otherwise = Just (abbreviateRight budget full) data BuildLineLayout = BuildLineLayout { bllText :: String , bllAligned :: Bool , bllLabelCols :: Int , bllHasStatus :: Bool } emptyBuildLineLayout :: BuildLineLayout emptyBuildLineLayout = BuildLineLayout "" False 0 False -- | Fit a build line body to width while preserving module/status columns when possible. fitBuildLineLayout :: Int -> Int -> Int -> Bool -> String -> StatusRenderer -> BuildLineLayout fitBuildLineLayout width labelWidth statusWidth preserveBlankLabel modLbl renderStatus | width <= 0 = emptyBuildLineLayout | hasLabelColumn = case renderAligned of Just line -> line Nothing -> if null modLbl then fitStatusOnly else BuildLineLayout (fitBuildModuleLabel width modLbl) False (min width labelWidth) False | otherwise = fitStatusOnly where minStatusWidth = 10 minLabelWidth = 10 hasLabelColumn = preserveBlankLabel || not (null modLbl) renderAligned | width < 2 + minStatusWidth = Nothing | labelCols <= 0 && not (null modLbl) = Nothing | not (null modLbl) && labelCols < min minLabelWidth (length modLbl) = Nothing | statusCols < minStatusWidth = Nothing | otherwise = case renderStatus statusCols of Just status -> let labelText = if null modLbl then "" else fitBuildModuleLabel labelCols modLbl core = padRight labelCols labelText ++ " " ++ padRight statusCols status in Just (BuildLineLayout core True labelCols True) Nothing -> Nothing labelCols = min labelWidth (max 0 (width - 2 - minStatusWidth)) statusCols = min statusWidth (max 0 (width - labelCols - 2)) fitStatusOnly = case renderStatus (min statusWidth width) of Just status -> BuildLineLayout (termFitPlainRight width status) False 0 True Nothing -> emptyBuildLineLayout -- | Fit an active build line to the current terminal width. fitBuildActiveLineAligned :: Int -> Int -> Int -> String -> StatusRenderer -> String fitBuildActiveLineAligned width labelWidth statusWidth modLbl renderStatus = bllText (fitBuildLineLayout width labelWidth statusWidth False modLbl renderStatus) safeLiveWidth :: Int -> Int safeLiveWidth width | width <= 0 = 0 | width == 1 = 1 | otherwise = width - 1 -- Version handling ------------------------------------------------------------------------------------------ printVersion = putStrLn getVer getVer = showVersion Paths_acton.version printIce errMsg = putStrLn( "ERROR: internal compiler error: " ++ errMsg ++ "\nNOTE: this is likely a bug in acton, please report this at:" ++ "\nNOTE: https://github.com/actonlang/acton/issues/new?template=ice.yaml" ++ "\nNOTE: acton " ++ getVer ) -- Create a project --------------------------------------------------------------------------------------------- -- | Create a new Acton project skeleton (files, dirs, optional git init). createProject :: String -> IO () createProject name = do curDir <- getCurrentDirectory projDirExists <- doesDirectoryExist name iff (projDirExists) $ printErrorAndExit ("Unable to create project " ++ name ++ ", directory already exists.") fp <- generateFingerprint name let projDir = joinPath [curDir, name] srcRoot = joinPath [projDir, "src"] buildActPath = joinPath [projDir, "Build.act"] buildSpec = BuildSpec.BuildSpec { BuildSpec.specName = name , BuildSpec.specDescription = Nothing , BuildSpec.fingerprint = fp , BuildSpec.dependencies = M.empty , BuildSpec.zig_dependencies = M.empty } createDirectoryIfMissing True srcRoot writeFile buildActPath (BuildSpec.renderBuildAct buildSpec) paths <- findPaths buildActPath defaultCompileOptions writeFile (joinPath [ projDir, ".gitignore" ]) ( ".acton.compile.lock\n" ++ ".acton.lock\n" ++ "build.zig\n" ++ "build.zig.zon\n" ++ "out\n" ) writeFile (joinPath [ projDir, "README.md" ]) ( "# " ++ name ++ "\n\n" ++ "```sh\nacton build\n./out/bin/" ++ name ++ "\n```\n" ) createDirectoryIfMissing True (srcDir paths) writeFile (joinPath [(srcDir paths), name ++ ".act"]) "#\n#\n\nactor main(env):\n print(\"Hello World!\")\n env.exit(0)\n" putStrLn("Created project " ++ name) putStrLn("Next: cd " ++ name ++ " && acton build && ./out/bin/" ++ name) gitAvailable <- isGitAvailable iff (gitAvailable) $ do putStrLn("") setCurrentDirectory name callProcess "git" ["init"] callProcess "git" ["add", "."] setCurrentDirectory curDir -- BuildSpec ----------------------------------------------------------------------------------------------------- buildSpecCommand :: C.BuildSpecCommand -> IO () buildSpecCommand cmd = case cmd of C.BuildSpecUpdate jsonPath -> do exists <- doesFileExist "Build.act" unless exists $ printErrorAndExit "Build.act not found in current directory" let actPath = "Build.act" content <- readFile actPath json <- if jsonPath == "-" then BL.getContents else BL.readFile jsonPath case BuildSpec.updateBuildActFromJSON content json of Left err -> printErrorAndExit ("Failed to update Build.act: \n" ++ err) Right updated -> writeFile actPath updated >> putStrLn "Updated Build.act" C.BuildSpecDump -> do spec <- loadBuildSpec "." BL.putStr (BuildSpec.encodeBuildSpecJSON spec) -- Build a project ----------------------------------------------------------------------------------------------- -- | Dispatch a project build, routing to watch or single-shot compilation. buildProject :: C.GlobalOptions -> C.CompileOptions -> IO () buildProject gopts opts = do iff (not (null $ (C.root opts)) && (length $ splitOn "." (C.root opts)) == 1) $ printErrorAndExit("Project build requires a qualified root actor name, like foo.main") if C.watch opts then do curDir <- getCurrentDirectory watchProjectAt gopts opts curDir else buildProjectOnce gopts opts -- | Handle "acton build FILE..." by compiling multiple .act files together -- when they share a project root; otherwise fall back to per-file handling. buildFiles :: C.GlobalOptions -> C.CompileOptions -> [FilePath] -> IO () buildFiles gopts opts files = case files of [single] -> runFile gopts opts single _ -> do when (C.watch opts) $ printErrorAndExit "Cannot use --watch with multiple files. Use `acton build --watch` for projects or `acton build FILE --watch` (or `acton FILE --watch`) for a single file." absFiles <- mapM canonicalizePath files let onlyAct = all ((== ".act") . takeExtension) files projDirs <- mapM findProjectDir absFiles let projRoots = nub (catMaybes projDirs) case projRoots of [proj] | onlyAct && all (== Just proj) projDirs -> do let sp = Source.diskSourceProvider runBuild opts' = withProjectLockNotice gopts proj $ compileFiles sp gopts opts' absFiles False runBuild opts _ -> mapM_ (runFile gopts opts) files -- | Collect all source files in a project's src/ directory. projectSourceFiles :: Paths -> IO [FilePath] projectSourceFiles paths = do allFiles <- getFilesRecursive (srcDir paths) return (catMaybes (map filterActFile allFiles)) withBackgroundCompilerLockOrExit :: FilePath -> String -> IO a -> IO a withBackgroundCompilerLockOrExit projDir msg action = do mlock <- tryBackgroundCompilerLock projDir case mlock of Nothing -> printErrorAndExit msg Just lock -> action `finally` releaseBackgroundCompilerLock lock withProjectLockNotice :: C.GlobalOptions -> FilePath -> IO a -> IO a withProjectLockNotice gopts projDir action = withProjectLockOnWait projDir onWait action where onWait = unless (C.quiet gopts) $ putStrLn ("Waiting for compiler lock in " ++ projDir) withProjectLockForGen :: C.GlobalOptions -> CompileScheduler -> Int -> FilePath -> IO () -> IO () withProjectLockForGen gopts sched gen projDir action = whenCurrentGen sched gen $ withProjectLockNotice gopts projDir $ whenCurrentGen sched gen action requireProjectLayout :: Paths -> IO () requireProjectLayout paths = do exists <- doesDirectoryExist (srcDir paths) unless exists $ printErrorAndExit "Missing src/ directory" -- | Strict path resolution: require a project config in the given directory. loadProjectPathsAt :: FilePath -> C.CompileOptions -> IO Paths loadProjectPathsAt curDir opts = do actPath <- requireProjectConfigPath curDir let projDir = takeDirectory actPath srcExists <- doesDirectoryExist (joinPath [projDir, "src"]) unless srcExists $ printErrorAndExit "Missing src/ directory" paths <- findPaths actPath opts requireProjectLayout paths return paths loadProjectPaths :: C.CompileOptions -> IO Paths loadProjectPaths opts = do curDir <- getCurrentDirectory loadProjectPathsAt curDir opts requireProjectConfigPath :: FilePath -> IO FilePath requireProjectConfigPath curDir = do let candidates = [ joinPath [curDir, "Build.act"] ] mpath <- firstExisting candidates case mpath of Just path -> return path Nothing -> printErrorAndExit "Project config not found in current directory (expected Build.act)" where firstExisting [] = return Nothing firstExisting (p:ps) = do exists <- doesFileExist p if exists then return (Just p) else firstExisting ps ignoreNotExists :: IOException -> IO () ignoreNotExists _ = return () withScratchDirLock :: (FilePath -> IO a) -> IO a withScratchDirLock action = do home <- getHomeDirectory let basePath = joinPath [home, ".cache", "acton", "scratch"] createDirectoryIfMissing True basePath maybeLockInfo <- findAvailableScratch basePath case maybeLockInfo of Nothing -> error "Could not acquire any scratch directory lock" Just (lock, lockPath) -> do let scratchDir = dropExtension lockPath removeDirectoryRecursive scratchDir `catch` ignoreNotExists action scratchDir `finally` unlockFile lock withTempDirOpts :: C.CompileOptions -> (C.CompileOptions -> Bool -> IO a) -> IO a withTempDirOpts opts action | C.tempdir opts /= "" = action opts False | otherwise = withScratchDirLock $ \scratchDir -> action opts { C.tempdir = scratchDir } True initCompileWatchContext :: C.GlobalOptions -> IO (CompileScheduler, ProgressUI, ProgressState) initCompileWatchContext gopts = do maxParallel <- compileMaxParallel gopts sched <- newCompileScheduler gopts maxParallel progressUI <- initProgressUI gopts maxParallel progressState <- newProgressState return (sched, progressUI, progressState) logProjectBuild :: C.GlobalOptions -> ProgressUI -> ProgressState -> FilePath -> IO () logProjectBuild gopts progressUI progressState projDir = iff (not(C.quiet gopts)) $ do progressReset progressUI progressState progressLogLine progressUI ("Building project in " ++ projDir) -- | Run a single project build under lock and generate docs. buildProjectOnce :: C.GlobalOptions -> C.CompileOptions -> IO () buildProjectOnce gopts opts = do let sp = Source.diskSourceProvider paths <- loadProjectPaths opts iff (not(C.quiet gopts)) $ do putStrLn("Building project in " ++ projPath paths) let projDir = projPath paths runBuild opts' = withProjectLockNotice gopts projDir $ do srcFiles <- projectSourceFiles paths compileFiles sp gopts opts' srcFiles True generateProjectDocIndex sp gopts opts' paths srcFiles runBuild opts -- Test runner ------------------------------------------------------------------------------------------------- -- | Entry point for acton test; configures options and selects mode/watch. runTests :: C.GlobalOptions -> C.TestCommand -> IO () runTests gopts cmd = do let (mode, topts) = case cmd of C.TestRun opts -> (TestModeRun, opts) C.TestList opts -> (TestModeList, opts) C.TestPerf opts -> (TestModePerf, opts) C.TestStress opts -> (TestModeStress, opts) gopts' = if C.testJson topts then gopts { C.quiet = True } else gopts opts0 = C.testCompile topts let opts = opts0 { C.test = True , C.skip_build = mode == TestModeList , C.only_build = False } paths <- loadProjectPaths opts if C.watch opts0 then case mode of TestModeList -> runTestsOnce gopts' opts topts mode paths _ -> runTestsWatch gopts' opts topts mode paths else runTestsOnce gopts' opts topts mode paths -- | Build once and then list/run tests based on the selected mode. runTestsOnce :: C.GlobalOptions -> C.CompileOptions -> C.TestOptions -> TestMode -> Paths -> IO () runTestsOnce gopts opts topts mode paths = do buildProjectOnce gopts opts modules <- listTestModules opts paths case mode of TestModeList -> listProjectTests opts paths topts modules _ -> do maxParallel0 <- testMaxParallel gopts let maxParallel = if mode == TestModeStress then 1 else maxParallel0 useColorOut <- useColor gopts exitCode <- runProjectTests useColorOut gopts opts paths topts mode modules maxParallel exitWithTestCode exitCode -- | Watch mode for tests that rebuilds incrementally and reruns changed modules. runTestsWatch :: C.GlobalOptions -> C.CompileOptions -> C.TestOptions -> TestMode -> Paths -> IO () runTestsWatch gopts opts topts mode paths = do let sp = Source.diskSourceProvider projDir = projPath paths srcRoot = srcDir paths withBackgroundCompilerLockOrExit projDir "Another long-running Acton compiler is already running; cannot start test watch." $ do (sched, progressUI, progressState) <- initCompileWatchContext gopts testParallel0 <- testMaxParallel gopts let testParallel = if mode == TestModeStress then 1 else testParallel0 let runOnce gen mChanged = do withProjectLockForGen gopts sched gen projDir $ do logProjectBuild gopts progressUI progressState projDir srcFiles <- projectSourceFiles paths hadErrors <- compileFilesChanged sp gopts opts srcFiles True mChanged (Just (sched, gen)) (Just (progressUI, progressState)) unless hadErrors $ do testModules <- listTestModules opts paths modulesToTest <- selectTestModules paths srcFiles mChanged testModules unless (null modulesToTest) $ do useColorOut <- useColor gopts void $ runProjectTests useColorOut gopts opts paths topts mode modulesToTest testParallel runWatchProject gopts projDir srcRoot sched runOnce selectTestModules :: Paths -> [FilePath] -> Maybe [FilePath] -> [String] -> IO [String] selectTestModules paths srcFiles mChanged testModules = case mChanged of Nothing -> return testModules Just changedPaths -> do changedModules <- changedModulesFromPaths paths changedPaths affected <- dependentTestModulesFromHeaders paths srcFiles changedModules return (filter (`elem` testModules) affected) -- | Compute parallelism for test runs from jobs or core count. testMaxParallel :: C.GlobalOptions -> IO Int testMaxParallel gopts = do nCaps <- getNumCapabilities return (max 1 (if C.jobs gopts > 0 then C.jobs gopts else max 1 (nCaps `div` 2))) -- | Exit with a status derived from test errors and failures. exitWithTestCode :: Int -> IO () exitWithTestCode code | code <= 0 = System.Exit.exitSuccess | otherwise = System.Exit.exitWith (ExitFailure code) changedModulesFromPaths :: Paths -> [FilePath] -> IO [String] changedModulesFromPaths paths files = do mods <- forM files $ \file -> do mn <- moduleNameFromFile (srcDir paths) file return (modNameToString mn) return (Data.List.sort (nub mods)) readModuleImports :: Paths -> A.ModName -> IO [A.ModName] readModuleImports paths mn = do let tyFile = outBase paths mn ++ ".ty" exists <- doesFileExist tyFile if not exists then return [] else do hdrE <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readHeader tyFile case hdrE of Left _ -> return [] Right (_sourceMeta, _hash, _ih, _implH, imps, _nameHashes, _roots, _tests, _doc) -> return (map fst imps) dependentTestModulesFromHeaders :: Paths -> [FilePath] -> [String] -> IO [String] dependentTestModulesFromHeaders paths srcFiles changedModules = do depsByMod <- forM srcFiles $ \file -> do mn <- moduleNameFromFile (srcDir paths) file imps <- readModuleImports paths mn return (modNameToString mn, map modNameToString imps) let revMap = foldl' (\acc (mn, deps) -> foldl' (\a dep -> M.insertWith (++) dep [mn] a) acc deps) M.empty depsByMod affected = reverseClosure revMap (Data.Set.fromList changedModules) return (Data.List.sort (Data.Set.toList affected)) where reverseClosure revMap start = go start (Data.Set.toList start) where go seen [] = seen go seen (k:ks) = let ds = M.findWithDefault [] k revMap new = filter (`Data.Set.notMember` seen) ds seen' = foldl' (flip Data.Set.insert) seen new in go seen' (ks ++ new) -- | Watch a project directory and rebuild on source or build spec changes. watchProjectAt :: C.GlobalOptions -> C.CompileOptions -> FilePath -> IO () watchProjectAt gopts opts projDir = do let sp = Source.diskSourceProvider paths <- loadProjectPathsAt projDir opts withBackgroundCompilerLockOrExit (projPath paths) "Another long-running Acton compiler is already running; cannot start watch." $ do (sched, progressUI, progressState) <- initCompileWatchContext gopts let runOnce gen mChanged = withProjectLockForGen gopts sched gen (projPath paths) $ do logProjectBuild gopts progressUI progressState (projPath paths) srcFiles <- projectSourceFiles paths void $ compileFilesChanged sp gopts opts srcFiles True mChanged (Just (sched, gen)) (Just (progressUI, progressState)) when (isNothing mChanged) $ generateProjectDocIndex sp gopts opts paths srcFiles runWatchProject gopts (projPath paths) (srcDir paths) sched runOnce -- | Build a single file, optionally running in watch mode. buildFile :: C.GlobalOptions -> C.CompileOptions -> FilePath -> IO () buildFile gopts opts file | C.watch opts = watchFile gopts opts file | otherwise = buildFileOnce gopts opts file -- | Compile one file in project or scratch mode with locking. buildFileOnce :: C.GlobalOptions -> C.CompileOptions -> FilePath -> IO () buildFileOnce gopts opts file = do let sp = Source.diskSourceProvider absFile <- canonicalizePath file curDir <- getCurrentDirectory -- Determine if we are in a project projDir <- findProjectDir absFile case projDir of Just proj -> do let relProj = makeRelative curDir proj -- In a project, use project directory for compilation. iff (not(C.quiet gopts)) $ do putStrLn("Building file " ++ file ++ " in project " ++ relProj) let runBuild opts' = withProjectLockNotice gopts proj $ compileFiles sp gopts opts' [file] False runBuild opts Nothing -> do -- Not in a project, use scratch directory for compilation unless -- --tempdir is provided - then use that withTempDirOpts opts $ \opts' usedScratch -> do iff (not(C.quiet gopts)) $ do if usedScratch then do let scratch_dir = if (C.verbose gopts) then " " ++ C.tempdir opts' else "" putStrLn("Building file " ++ file ++ " using temporary scratch directory" ++ scratch_dir) else putStrLn("Building file " ++ file ++ " using temporary directory " ++ C.tempdir opts') compileFiles sp gopts opts' [file] False -- | Watch a single file and rebuild on changes. watchFile :: C.GlobalOptions -> C.CompileOptions -> FilePath -> IO () watchFile gopts opts file = do absFile <- canonicalizePath file projDir <- findProjectDir absFile case projDir of Just proj -> watchProjectAt gopts opts proj Nothing -> do let sp = Source.diskSourceProvider (sched, progressUI, progressState) <- initCompileWatchContext gopts let runWatch opts' = let runOnce gen mChanged = whenCurrentGen sched gen $ void $ compileFilesChanged sp gopts opts' [absFile] False mChanged (Just (sched, gen)) (Just (progressUI, progressState)) in runWatchFile gopts absFile sched runOnce withTempDirOpts opts $ \opts' _ -> runWatch opts' data WatchTrigger = WatchFull | WatchIncremental FilePath deriving (Eq, Show) data FileStamp = FileStamp UTCTime Integer deriving (Eq, Show) readFileStamp :: FilePath -> IO (Maybe FileStamp) readFileStamp path = do res <- try (do exists <- doesFileExist path if not exists then return Nothing else do stampTime <- getModificationTime path stampSize <- getFileSize path return (Just (FileStamp stampTime stampSize)) ) :: IO (Either IOException (Maybe FileStamp)) case res of Left _ -> return Nothing Right stamp -> return stamp shouldTriggerFile :: IORef (M.Map FilePath FileStamp) -> FilePath -> IO Bool shouldTriggerFile stampsRef path = do mstamp <- readFileStamp path atomicModifyIORef' stampsRef $ \stamps -> case mstamp of Nothing -> (M.delete path stamps, True) Just stamp -> case M.lookup path stamps of Just old | old == stamp -> (stamps, False) _ -> (M.insert path stamp stamps, True) -- | Translate watch triggers into optional path notifications. dispatchWatchTrigger :: (Maybe FilePath -> IO ()) -> WatchTrigger -> IO () dispatchWatchTrigger notify trigger = case trigger of WatchFull -> notify Nothing WatchIncremental path -> notify (Just path) -- | Classify project FS events into full or incremental rebuild triggers. actWatchTrigger :: FS.Event -> Maybe WatchTrigger actWatchTrigger ev = case FS.eventIsDirectory ev of FS.IsDirectory -> case ev of FS.Added{} -> Just WatchFull FS.Removed{} -> Just WatchFull FS.WatchedDirectoryRemoved{} -> Just WatchFull FS.Unknown{} -> Just WatchFull _ -> Nothing FS.IsFile -> if takeExtension (FS.eventPath ev) /= ".act" then Nothing else case ev of FS.ModifiedAttributes{} -> Nothing FS.Added{} -> Just WatchFull FS.Removed{} -> Just WatchFull FS.WatchedDirectoryRemoved{} -> Just WatchFull FS.Unknown{} -> Just WatchFull _ -> Just (WatchIncremental (FS.eventPath ev)) -- | Classify FS events for a specific file path. fileWatchTrigger :: FilePath -> FS.Event -> Maybe WatchTrigger fileWatchTrigger target ev = let evPath = normalise (FS.eventPath ev) in if evPath /= target then Nothing else case ev of FS.ModifiedAttributes{} -> Nothing _ -> Just (WatchIncremental (FS.eventPath ev)) -- | Run the project watch loop and schedule compiles on events. runWatchProject :: C.GlobalOptions -> FilePath -> FilePath -> CompileScheduler -> (Int -> Maybe [FilePath] -> IO ()) -> IO () runWatchProject gopts projDir srcRoot sched runOnce = do stampsRef <- newIORef M.empty let schedule mpath = void $ startCompile sched 0 $ \gen -> runOnce gen (fmap (:[]) mpath) scheduleMaybe mpath = case mpath of Nothing -> schedule Nothing Just path -> do should <- shouldTriggerFile stampsRef path when should (schedule (Just path)) onAct ev = forM_ (actWatchTrigger ev) $ \trigger -> do when (C.verbose gopts) $ putStrLn ("[debug] watch event: " ++ show ev ++ " -> " ++ show trigger) dispatchWatchTrigger scheduleMaybe trigger onRoot _ = schedule Nothing isActEvent ev = isJust (actWatchTrigger ev) isRootEvent ev = let name = takeFileName (FS.eventPath ev) in name == "Build.act" FS.withManager $ \mgr -> do _ <- FS.watchTree mgr srcRoot isActEvent onAct _ <- FS.watchDir mgr projDir isRootEvent onRoot schedule Nothing unless (C.quiet gopts) $ putStrLn ("Watching for changes in " ++ projDir) forever $ threadDelay maxBound -- | Run the single-file watch loop and schedule compiles on events. runWatchFile :: C.GlobalOptions -> FilePath -> CompileScheduler -> (Int -> Maybe [FilePath] -> IO ()) -> IO () runWatchFile gopts absFile sched runOnce = do stampsRef <- newIORef M.empty let watchDir = takeDirectory absFile watchPath = normalise absFile isTarget ev = normalise (FS.eventPath ev) == watchPath onEvent ev = do forM_ (fileWatchTrigger watchPath ev) $ \trigger -> case trigger of WatchFull -> dispatchWatchTrigger schedule trigger WatchIncremental path -> do should <- shouldTriggerFile stampsRef path when should (dispatchWatchTrigger schedule trigger) schedule mpath = void $ startCompile sched 0 $ \gen -> runOnce gen (fmap (:[]) mpath) FS.withManager $ \mgr -> do _ <- FS.watchDir mgr watchDir isTarget onEvent schedule Nothing unless (C.quiet gopts) $ putStrLn ("Watching for changes in " ++ absFile) forever $ threadDelay maxBound -- | Fetch dependencies for the current project without compiling. fetchCommand :: C.GlobalOptions -> IO () fetchCommand gopts = do paths <- loadProjectPaths defaultCompileOptions res <- try (fetchDependencies gopts paths []) :: IO (Either ProjectError ()) case res of Left (ProjectError msg) -> printErrorAndExit msg Right () -> unless (C.quiet gopts) $ putStrLn "Dependencies fetched" data SigTarget = SigSourceTarget ProjCtx A.ModName (Maybe A.Name) FilePath | SigTyTarget A.ModName (Maybe A.Name) FilePath sigCommand :: C.GlobalOptions -> C.SigOptions -> IO () sigCommand gopts sigOpts = do let opts0 = (C.sigCompile sigOpts) { C.skip_build = True , C.only_build = False , C.sigs = False } queryGopts = if C.verbose gopts then gopts else gopts { C.quiet = True } paths0 <- loadProjectPaths opts0 depOverrides <- normalizeDepOverrides (projPath paths0) (C.dep_overrides opts0) let opts = opts0 { C.dep_overrides = depOverrides } paths <- loadProjectPaths opts rootProj <- normalizePathSafe (projPath paths) sysAbs <- normalizePathSafe (sysPath paths) withProjectLockNotice queryGopts rootProj $ do fetchDependencies queryGopts paths depOverrides projMap <- discoverProjects queryGopts sysAbs rootProj depOverrides target <- resolveSigTarget opts paths rootProj projMap (C.sigTarget sigOpts) tyFile <- case target of SigSourceTarget ctx mn _ srcPath -> compileSigTarget gopts queryGopts opts paths rootProj sysAbs depOverrides ctx mn srcPath SigTyTarget _ _ tyPath -> return tyPath case target of SigSourceTarget _ mn mName _ -> printSigInterface paths mn mName tyFile SigTyTarget mn mName _ -> printSigInterface paths mn mName tyFile compileSigTarget :: C.GlobalOptions -> C.GlobalOptions -> C.CompileOptions -> Paths -> FilePath -> FilePath -> [(String, FilePath)] -> ProjCtx -> A.ModName -> FilePath -> IO FilePath compileSigTarget gopts queryGopts opts paths rootProj sysAbs depOverrides targetCtx mn srcPath = do buildStamp <- readBuildSpecStamp (projPath paths) let sp = Source.diskSourceProvider cctx = CompileContext { ccOpts = opts , ccDepOverrides = depOverrides , ccPathsRoot = paths , ccRootProj = rootProj , ccSysAbs = sysAbs , ccBuildStamp = buildStamp } plan <- prepareCompilePlanFromContext sp queryGopts cctx [srcPath] False Nothing let cctx' = cpContext plan opts' = ccOpts cctx' callbacks = defaultCompileCallbacks { ccOnDiagnostics = \_ optsT diags -> printDiagnostics gopts optsT diags , ccOnInfo = \msg -> when (C.verbose gopts) $ putStrLn msg , ccOnBackJob = \_ -> return () } compileRes <- compileTasks sp queryGopts opts' (ccPathsRoot cctx') (ccRootProj cctx') (cpNeededTasks plan) callbacks case compileRes of Left err -> printErrorAndExit (compileFailureMessage err) Right (_, hadErrors) -> when hadErrors System.Exit.exitFailure let targetCtx' = case M.lookup (projRoot targetCtx) (cpProjMap plan) of Just ctx -> ctx Nothing -> targetCtx targetPaths <- pathsForModule opts' (cpProjMap plan) targetCtx' mn return (outBase targetPaths mn ++ ".ty") resolveSigTarget :: C.CompileOptions -> Paths -> FilePath -> M.Map FilePath ProjCtx -> String -> IO SigTarget resolveSigTarget opts paths rootProj projMap rawTarget = do parts <- parseSigTarget rawTarget moduleIndex <- sigModuleIndex projMap rootProj let fullMod = A.modName parts case lookup fullMod moduleIndex of Just (ctx, srcPath) -> return (SigSourceTarget ctx fullMod Nothing srcPath) Nothing -> do mFullTy <- findSigTyFile tySearchPath fullMod case mFullTy of Just tyPath -> return (SigTyTarget fullMod Nothing tyPath) Nothing -> resolveNameTarget parts moduleIndex where tySearchPath = sigTySearchPath opts paths rootProj projMap resolveNameTarget parts moduleIndex | length parts < 2 = printErrorAndExit ("Module not found: " ++ rawTarget) | otherwise = do let modParts = init parts namePart = last parts mn = A.modName modParts n = A.name namePart case lookup mn moduleIndex of Just (ctx, srcPath) -> return (SigSourceTarget ctx mn (Just n) srcPath) Nothing -> do mTy <- findSigTyFile tySearchPath mn case mTy of Just tyPath -> return (SigTyTarget mn (Just n) tyPath) Nothing -> printErrorAndExit ("Module not found: " ++ intercalate "." modParts ++ " (while resolving " ++ rawTarget ++ ")") parseSigTarget :: String -> IO [String] parseSigTarget rawTarget = do let parts = splitOn "." rawTarget if null rawTarget || any null parts then printErrorAndExit ("Invalid signature target: " ++ rawTarget) else return parts sigModuleIndex :: M.Map FilePath ProjCtx -> FilePath -> IO [(A.ModName, (ProjCtx, FilePath))] sigModuleIndex projMap rootProj = do let roots = sigProjectSearchOrder projMap rootProj fmap concat $ forM roots $ \root -> case M.lookup root projMap of Nothing -> return [] Just ctx -> do mods <- enumerateProjectModules ctx return [ (mn, (ctx, srcPath)) | (srcPath, mn) <- mods ] sigProjectSearchOrder :: M.Map FilePath ProjCtx -> FilePath -> [FilePath] sigProjectSearchOrder projMap rootProj = rootProj : snd (go (Data.Set.singleton rootProj) rootProj) where go seen root = case M.lookup root projMap of Nothing -> (seen, []) Just ctx -> foldl' step (seen, []) (projDeps ctx) step (seen, acc) (_, depRoot) | Data.Set.member depRoot seen = (seen, acc) | otherwise = let seen' = Data.Set.insert depRoot seen (seenNext, sub) = go seen' depRoot in (seenNext, acc ++ [depRoot] ++ sub) sigTySearchPath :: C.CompileOptions -> Paths -> FilePath -> M.Map FilePath ProjCtx -> [FilePath] sigTySearchPath opts paths rootProj projMap = case M.lookup rootProj projMap of Just rootCtx -> searchPathForProject opts projMap rootCtx Nothing -> searchPath paths findSigTyFile :: [FilePath] -> A.ModName -> IO (Maybe FilePath) findSigTyFile = Acton.Env.findTyFile printSigInterface :: Paths -> A.ModName -> Maybe A.Name -> FilePath -> IO () printSigInterface paths mn mName tyFile = do exists <- doesFileExist tyFile unless exists $ printErrorAndExit ("Type interface not found for " ++ modNameToString mn) tyRes <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readFile tyFile case tyRes of Left err -> printErrorAndExit ("Could not read type interface for " ++ modNameToString mn ++ ": " ++ show err) Right (ms, nmod, _, _, _, _, _, _, _, _, _, _) -> do env0 <- Acton.Env.initEnv (sysTypes paths) False let I.NModule imps te _ = nmod envImports = foldr Acton.Env.addImport env0 ms selected = case mName of Nothing -> te Just n -> filter ((== n) . fst) te envForPrint = case mName of Nothing -> envImports Just _ -> define te (setMod mn envImports) case mName of Just n | null selected -> printErrorAndExit ("Name not found: " ++ modNameToString mn ++ "." ++ nameToString n) _ -> putStrLn (Acton.Types.prettySigs envForPrint mn imps selected) -- Show dependency tree with overrides applied from root pins pkgShow :: C.GlobalOptions -> IO () pkgShow gopts = do curDir <- getCurrentDirectory _ <- requireProjectConfigPath curDir spec <- loadBuildSpec curDir let rootPins = BuildSpec.dependencies spec unless (C.quiet gopts) $ putStrLn "Dependency tree (hash overrides shown):" partial <- showTree rootPins curDir spec 0 when (partial && not (C.quiet gopts)) $ putStrLn "Note: dependency tree is partial; some dependencies are not fetched yet. Run 'acton fetch'." where describeDep dep = case BuildSpec.hash dep of Just h -> "hash=" ++ h Nothing -> case BuildSpec.path dep of Just p | not (null p) -> "path=" ++ p _ -> "unversioned" isHashDep dep = case BuildSpec.path dep of Just p | not (null p) -> False _ -> case BuildSpec.hash dep of Just _ -> True Nothing -> False showTree pins dir spec depth = do let deps = M.toList (BuildSpec.dependencies spec) foldM (step pins dir depth) False deps step pins dir depth partial (depName, dep) = do let (chosen, conflict) = case M.lookup depName pins of Nothing -> (dep, False) Just pinDep -> if pinDep == dep then (dep, False) else (pinDep, True) depBase <- resolveDepBase dir depName chosen depExists <- doesDirectoryExist depBase let notFetched = isHashDep chosen && not depExists prefix = replicate (2*depth) ' ' ++ "- " suffix = if notFetched then " (not fetched)" else "" line = prefix ++ depName ++ " (" ++ describeDep dep ++ (if conflict then " overridden -> " ++ describeDep chosen else "") ++ ")" ++ suffix putStrLn line if not depExists then if notFetched then return (partial || True) else do throwProjectError ("Dependency " ++ depName ++ " path does not exist: " ++ depBase ++ "\n" ++ "Hint: Local dependency paths must point to an Acton project root\n" ++ "(directory with src/ and Build.act).") else do spec' <- loadBuildSpec depBase childPartial <- showTree pins depBase spec' (depth + 1) return (partial || childPartial) -- Print documentation ------------------------------------------------------------------------------------------- -- | Detect if we're running in a GUI environment -- On macOS: Always assume GUI unless SSH_CONNECTION is set -- On Linux: Check for DISPLAY variable -- On Windows: Always assume GUI detectGuiEnvironment :: IO Bool detectGuiEnvironment = do case System.Info.os of "darwin" -> do -- On macOS, assume GUI unless we're in SSH session sshConn <- lookupEnv "SSH_CONNECTION" return $ isNothing sshConn "linux" -> do -- On Linux, check for DISPLAY display <- lookupEnv "DISPLAY" return $ isJust display && display /= Just "" _ -> -- Windows or other, assume GUI return True -- | Generate and display documentation for Acton modules -- -- Behavior summary: -- * No format flag + GUI environment → HTML to file + open browser -- * No format flag + terminal/SSH → ASCII to stdout -- * Explicit format (-t, --html, --md) → Always to stdout (unless -o specified) -- * -o flag → Always to that file -- * -o - → Always to stdout -- -- GUI detection: -- * macOS: Assumes GUI unless SSH_CONNECTION is set -- * Linux: Checks for DISPLAY variable -- * Windows: Always assumes GUI -- -- The command line parser just parses options without making behavior decisions. -- All logic is centralized here in printDocs for predictable, intuitive behavior. openFileInGui :: FilePath -> IO () openFileInGui path = do let openCmd = case System.Info.os of "darwin" -> "open" "linux" -> "xdg-open" _ -> "" unless (null openCmd) $ void $ system $ openCmd ++ " " ++ path -- | Generate and display documentation based on CLI options and environment. printDocs :: C.GlobalOptions -> C.DocOptions -> IO () printDocs gopts opts = do case C.inputFile opts of "" -> do -- No file provided - check what to do case C.outputFormat opts of Just C.AsciiFormat -> printErrorAndExit "Terminal output requires a specific file. Usage: acton doc -t " Just C.MarkdownFormat -> printErrorAndExit "Markdown output requires a specific file. Usage: acton doc --md " _ -> do -- HTML or auto mode - check if we're in a project curDir <- getCurrentDirectory projDir <- findProjectDir curDir case projDir of Just _ -> do -- We're in a project - open the documentation index let indexFile = "out/doc/index.html" indexExists <- doesFileExist indexFile if indexExists then openFileInGui indexFile else printErrorAndExit "No documentation found. Run 'acton build' first to generate documentation." Nothing -> printErrorAndExit "Not in an Acton project. Please specify a file to document." filename -> do let (fileBody,fileExt) = splitExtension $ takeFileName filename case fileExt of ".ty" -> do paths <- findPaths filename defaultCompileOptions env0 <- Acton.Env.initEnv (sysTypes paths) False Acton.Types.showTyFile env0 (modName paths) filename (C.verbose gopts) ".act" -> do let modname = A.modName $ map (replace ".act" "") $ splitOn "/" $ fileBody paths <- findPaths filename defaultCompileOptions parsedRes <- parseActFile defaultCompileOptions Source.diskSourceProvider modname filename Nothing (_snap, parsed) <- case parsedRes of Left diags -> do printDiagnostics gopts defaultCompileOptions diags System.Exit.exitFailure Right res -> return res -- Run compiler passes to get type information env0 <- Acton.Env.initEnv (sysTypes paths) False env <- Acton.Env.mkEnv (searchPath paths) env0 parsed kchecked <- Acton.Kinds.check env parsed (nmod, _, env', _) <- Acton.Types.reconstruct Nothing Nothing env kchecked let I.NModule _ tenv mdoc = nmod -- 1. If format is explicitly set (via -t, --html, --markdown), use it -- 2. Otherwise, check if we're in a GUI environment inGui <- detectGuiEnvironment let format = case C.outputFormat opts of Just fmt -> fmt Nothing -> if inGui then C.HtmlFormat else C.AsciiFormat docOutput <- case format of C.HtmlFormat -> return $ DocP.printHtmlDoc nmod parsed C.AsciiFormat -> do shouldColor <- useColor gopts return $ DocP.printAsciiDoc shouldColor nmod parsed C.MarkdownFormat -> return $ DocP.printMdDoc nmod parsed -- Handle output destination case C.outputFile opts of Just "-" -> -- Explicit stdout putStr docOutput Just outFile -> do -- Write to specified file createDirectoryIfMissing True (takeDirectory outFile) writeFile outFile docOutput putStrLn $ "Documentation written to: " ++ outFile Nothing | isJust (C.outputFormat opts) || format == C.AsciiFormat -> -- Explicit format or auto ASCII: write to stdout putStr docOutput | otherwise -> do -- Auto-detected HTML (DISPLAY set), write to file and open browser curDir <- getCurrentDirectory projDir <- findProjectDir curDir outputPath <- case projDir of Just _ -> do -- In project: use out/doc/ let modPath = map (replace ".act" "") $ splitOn "/" filename cleanPath = case modPath of "src":rest -> rest path -> path docFile = if null cleanPath then "out/doc/unnamed.html" else joinPath ("out" : "doc" : init cleanPath) last cleanPath <.> "html" return docFile Nothing -> -- Outside project: use temp file writeSystemTempFile "acton-doc.html" docOutput case projDir of Just _ -> do createDirectoryIfMissing True (takeDirectory outputPath) writeFile outputPath docOutput Nothing -> return () putStrLn $ "HTML documentation written to: " ++ outputPath openFileInGui outputPath _ -> printErrorAndExit ("Unknown filetype: " ++ filename) -- Compile Acton files --------------------------------------------------------------------------------------------- -- | Compute parallelism for compilation based on jobs or cores. compileMaxParallel :: C.GlobalOptions -> IO Int compileMaxParallel gopts = do nCaps <- getNumCapabilities return (max 1 (if C.jobs gopts > 0 then C.jobs gopts else nCaps)) -- | Compile a set of files in a single-shot build. compileFiles :: Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> [String] -> Bool -> IO () compileFiles sp gopts opts srcFiles allowPrune = void $ compileFilesChanged sp gopts opts srcFiles allowPrune Nothing Nothing Nothing -- | Compile with optional change set, wiring progress UI and back jobs. compileFilesChanged :: Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> [String] -> Bool -> Maybe [FilePath] -> Maybe (CompileScheduler, Int) -> Maybe (ProgressUI, ProgressState) -> IO Bool compileFilesChanged sp gopts opts srcFiles allowPrune mChangedPaths mSched mProgress = do maxParallel <- compileMaxParallel gopts (progressUI, progressState) <- case mProgress of Just ps -> return ps Nothing -> do ui <- initProgressUI gopts maxParallel st <- newProgressState return (ui, st) let logLine = progressLogLine progressUI (sched, gen) <- case mSched of Just sg -> return sg Nothing -> do sched' <- newCompileScheduler gopts maxParallel return (sched', 0) let cleanupProgress = whenCurrentGen sched gen (progressReset progressUI progressState) cleanupProgress let runCompile = do sp' <- overlayChangedPaths sp mChangedPaths planRes <- try $ prepareCompilePlan sp' gopts sched opts srcFiles allowPrune mChangedPaths let reportPlanError (ProjectError msg) = do if C.watch opts then logLine msg else printErrorAndExit msg return True runPlan plan = do let cctx = cpContext plan opts' = ccOpts cctx watchMode = C.watch opts' cliHooks <- initCliCompileHooks progressUI progressState gopts sched gen plan let clearProgress = whenCurrentGen sched gen (cchClearProgress cliHooks) finalizeCompile onError = do clearProgress onError return True reportCompileError msg = finalizeCompile $ if watchMode then logLine msg else printErrorAndExit msg reportCompileErrors = finalizeCompile $ unless watchMode System.Exit.exitFailure compileRes <- runCompilePlan sp gopts plan sched gen (cchHooks cliHooks) case compileRes of Left err -> reportCompileError (compileFailureMessage err) Right (env, hadErrors) -> do backFailure <- if C.only_build opts' then return Nothing else backQueueWait (csBackQueue sched) gen case backFailure of Just failure -> reportCompileError (backPassFailureMessage failure) Nothing -> if hadErrors then reportCompileErrors else do clearProgress whenCurrentGen sched gen (runCliPostCompile cliHooks gopts plan env) return False either reportPlanError runPlan planRes runCompile `finally` cleanupProgress overlayChangedPaths :: Source.SourceProvider -> Maybe [FilePath] -> IO Source.SourceProvider overlayChangedPaths sp mPaths = do case mPaths of Nothing -> return sp Just paths -> do overlays <- catMaybes <$> mapM readOverlay paths let overlayMap = M.fromList overlays return sp { Source.spReadOverlay = \path -> do existing <- Source.spReadOverlay sp path case existing of Just snap -> return (Just snap) Nothing -> return (M.lookup (normalise path) overlayMap) } where readOverlay path = do res <- (try :: IO a -> IO (Either SomeException a)) (Source.spReadFile sp path) case res of Left _ -> return Nothing Right snap -> return (Just (normalise path, snap { Source.ssIsOverlay = True })) data CliCompileHooks = CliCompileHooks { cchHooks :: CompileHooks , cchLogLine :: String -> IO () , cchClearProgress :: IO () , cchFinalStart :: IO () , cchFinalDone :: Maybe TimeSpec -> IO () , cchProgressUI :: ProgressUI } -- | Build compile hooks and state for CLI progress and completion logs. initCliCompileHooks :: ProgressUI -> ProgressState -> C.GlobalOptions -> CompileScheduler -> Int -> CompilePlan -> IO CliCompileHooks initCliCompileHooks progressUI progressState gopts sched gen plan = do let neededTasks = cpNeededTasks plan rootProj = ccRootProj (cpContext plan) optsPlan = ccOpts (cpContext plan) isBuiltinTask t = tkMod (gtKey t) == A.modName ["__builtin__"] parseNeeded t = case gtTask t of ParseTask{} -> not (isBuiltinTask t) && not (C.only_build optsPlan) _ -> False sizeEntries <- forM neededTasks $ \t -> do let key = gtKey t path = srcFile (gtPaths t) (tkMod key) exists <- doesFileExist path sz <- if exists then getFileSize path else return 0 return (key, sz) progressRef <- newIORef (0 :: Double) marksRef <- newIORef (M.empty :: M.Map TaskKey (Double, Double, Bool)) -- sizeMap is used for the progress bar indicator to determine how much a -- modules compilation should contribute to the overall progress. We use -- file size as a heuristic for this, but if all sizes are zero (e.g. due to -- missing files or all files being empty), we fall back to equal weighting -- to avoid division by zero. Since our compilation is split into front and -- back passes, we also compute a share for each task that determines how -- much of the total progress it should contribute to, which is used to give -- a more accurate progress indication during the compile. let sizeMap = M.fromList sizeEntries totalSize = sum (map snd sizeEntries) useEqual = totalSize <= 0 totalWeight :: Double totalWeight = if useEqual then fromIntegral (max 1 (length neededTasks)) else fromIntegral totalSize weightFor key = if useEqual then 1 / totalWeight else fromIntegral (M.findWithDefault 0 key sizeMap) / totalWeight compilePhaseTotal = 85.0 parseRatio = 0.1 frontRatio = 0.6 backRatio = 0.3 totalPhaseWeight = sum [ weightFor (gtKey t) * (frontRatio + backRatio + if parseNeeded t then parseRatio else 0) | t <- neededTasks ] shareForPhase t ratio = if totalPhaseWeight <= 0 then 0 else compilePhaseTotal * weightFor (gtKey t) * ratio / totalPhaseWeight shareMap = M.fromList [ (gtKey t, (shareForPhase t (if parseNeeded t then parseRatio else 0) , shareForPhase t frontRatio , shareForPhase t backRatio)) | t <- neededTasks ] let gate = whenCurrentGen sched gen logLine msg = gate $ do progressLogLine progressUI msg logRendered render = gate $ do if puWidthAware progressUI then do (_, cols) <- termSizeRead (puTermSize progressUI) progressLogLine progressUI (render (safeLiveWidth cols)) else progressLogLine progressUI (render plainLogWidth) logDiagnostics optsT diags = gate (progressWithLog progressUI (printDiagnostics gopts optsT diags)) termProgress = puTermProgress progressUI termEnabled = termProgressEnabled termProgress modLabel mn = modNameToString mn timeSep = " " parseDoneStatus = "Parse done" frontDoneStatus = "Type check done" backDoneStatus = "Compilation done" backFailStatus msg = "Compilation failed: " ++ msg finalDoneStatus = "Final compilation done" projMap = cpProjMap plan depNameMap = let rootDeps = maybe [] projDeps (M.lookup rootProj projMap) otherDeps = concatMap projDeps (M.elems projMap) in M.fromListWith (\_ old -> old) [ (p, n) | (n, p) <- rootDeps ++ otherDeps ] projectLabelFor proj | proj == rootProj = "" | otherwise = case M.lookup proj depNameMap of Just name -> name Nothing -> projectLabel rootProj proj projectModuleLabel proj mn = case projectLabelFor proj of "" -> modLabel mn label -> label ++ "." ++ modLabel mn labelWidth = maximum (0 : [ length (projectModuleLabel (tkProj (gtKey t)) (tkMod (gtKey t))) | t <- neededTasks ]) statusWidth = 68 nameWidth = labelWidth + 2 + statusWidth timePadWidth = nameWidth + length timeSep timerMinWidth = length "999.999 s" plainLogWidth = timePadWidth + timerMinWidth detailStmtIndentWide = replicate 5 ' ' detailBindsIndentWide = replicate 7 ' ' detailStmtIndentNarrow = " " detailBindsIndentNarrow = " " plainDoneIndent = replicate 3 ' ' plainStatusColumns modLbl status = padRight labelWidth modLbl ++ " " ++ padRight statusWidth (abbreviateRight statusWidth status) plainDoneTimedLine modLbl status t = padRight timePadWidth (plainDoneIndent ++ plainStatusColumns modLbl status) ++ fmtTimePrecise t plainDoneLine modLbl status = plainDoneIndent ++ plainStatusColumns modLbl status pickBestLine candidates = case foldl' betterCandidate Nothing candidates of Just (_, line) -> line Nothing -> "" betterCandidate best Nothing = best betterCandidate Nothing cand = cand betterCandidate best@(Just (bestScore, _)) cand@(Just (candScore, _)) | candScore > bestScore = cand | otherwise = best buildLineCandidate width preserveBlankLabel modLbl statusRender timerRank timerWidth timer = let doneIndent = replicate (progressPrefixWidth width) ' ' timerCols = if null timer then 0 else 1 + timerWidth bodyWidth = max 0 (width - length doneIndent - timerCols) layout = fitBuildLineLayout bodyWidth labelWidth statusWidth preserveBlankLabel modLbl statusRender body = bllText layout line = doneIndent ++ body ++ if null timer then "" else " " ++ padLeft timerWidth timer score = ( if bllAligned layout then 1 :: Int else 0 , if bllHasStatus layout then 1 :: Int else 0 , bllLabelCols layout , timerRank ) in if null body || length line > width then Nothing else Just (score, line) doneStatusLine width modLbl statusRender shortStatus mt = let preciseTimer = maybe "" fmtTimePrecise mt compactTimer = maybe "" fmtTimeCompact mt timerWidth = max timerMinWidth (length preciseTimer) fullRenderer budget = case statusRender budget of Just status | length status <= budget -> Just status _ -> Nothing shortRenderer = staticStatusRenderer shortStatus shortStatus preserveBlankLabel = null modLbl in pickBestLine [ buildLineCandidate width preserveBlankLabel modLbl fullRenderer 2 timerWidth preciseTimer , buildLineCandidate width preserveBlankLabel modLbl fullRenderer 1 timerWidth compactTimer , buildLineCandidate width preserveBlankLabel modLbl fullRenderer 0 0 "" , buildLineCandidate width preserveBlankLabel modLbl shortRenderer 1 timerWidth compactTimer , buildLineCandidate width preserveBlankLabel modLbl shortRenderer 0 0 "" ] detailLine width indentWide indentNarrow msg = let wide = indentWide ++ msg in if width >= length wide then wide else indentNarrow ++ msg detailTimedLine width indentWide indentNarrow msg t = let precise = fmtTimePrecise t wideBase = indentWide ++ msg wideLine = padRight timePadWidth wideBase ++ precise in if width >= length wideLine then wideLine else indentNarrow ++ msg ++ " " ++ fmtTimeCompact t frontTimingLine ft = "Front timing: env " ++ fmtTimePrecise (ftEnv ft) ++ ", kinds " ++ fmtTimePrecise (ftKinds ft) ++ ", types " ++ fmtTimePrecise (ftTypes ft) typeStmtTimingLine st = "Type stmt " ++ show (tstCompleted st) ++ "/" ++ show (tstTotal st) typeStmtBindsLine st = "binds: " ++ intercalate ", " (tstNames st) inferredSignatureLine sig = "Non-total inferred signature: " ++ intercalate ", " (isigNames sig) backTimingLine bt = "Back timing: normalize " ++ fmtTimePrecise (btNormalize bt) ++ ", deactorize " ++ fmtTimePrecise (btDeactorize bt) ++ ", cps " ++ fmtTimePrecise (btCPS bt) ++ ", llift " ++ fmtTimePrecise (btLLift bt) ++ ", boxing " ++ fmtTimePrecise (btBoxing bt) ++ ", codegen " ++ fmtTimePrecise (btCodeGen bt) ++ maybe "" (\t -> ", write " ++ fmtTimePrecise t) (btWriteCode bt) parseDoneRenderer = staticStatusRenderer parseDoneStatus "Parsed" frontDoneRenderer = staticStatusRenderer frontDoneStatus "Typed" backDoneRenderer = staticStatusRenderer backDoneStatus "Built" backFailRenderer msg = \budget -> if budget < 10 then Nothing else Just (abbreviateRight budget (backFailStatus msg)) finalDoneRenderer = staticStatusRenderer finalDoneStatus "Final" parseDoneLine width proj mn t = if puWidthAware progressUI then doneStatusLine width (projectModuleLabel proj mn) parseDoneRenderer "Parsed" (Just t) else plainDoneTimedLine (projectModuleLabel proj mn) parseDoneStatus t frontDoneLine width proj mn t = if puWidthAware progressUI then doneStatusLine width (projectModuleLabel proj mn) frontDoneRenderer "Typed" (Just t) else plainDoneTimedLine (projectModuleLabel proj mn) frontDoneStatus t backDoneLine width proj mn mt = if puWidthAware progressUI then case mt of Just t -> doneStatusLine width (projectModuleLabel proj mn) backDoneRenderer "Built" (Just t) Nothing -> doneStatusLine width (projectModuleLabel proj mn) backDoneRenderer "Built" Nothing else case mt of Just t -> plainDoneTimedLine (projectModuleLabel proj mn) backDoneStatus t Nothing -> plainDoneLine (projectModuleLabel proj mn) backDoneStatus backFailLine width proj mn msg = if puWidthAware progressUI then doneStatusLine width (projectModuleLabel proj mn) (backFailRenderer msg) "Failed" Nothing else plainDoneLine (projectModuleLabel proj mn) (backFailStatus msg) finalDoneLine width t = if puWidthAware progressUI then doneStatusLine width "" finalDoneRenderer "Final" (Just t) else plainDoneTimedLine "" finalDoneStatus t renderProjectLine proj mn statusRender width = let modLbl = projectModuleLabel proj mn in fitBuildLineLayout width labelWidth statusWidth False modLbl statusRender parseActiveLine proj mn = renderProjectLine proj mn (staticStatusRenderer "Parsing" "Parse") parseProgressLine proj mn p = renderProjectLine proj mn (parseStatusRenderer p) frontInitialLine proj mn = renderProjectLine proj mn (staticStatusRenderer "Kinds check" "Kinds") backActiveLine proj mn = renderProjectLine proj mn (staticStatusRenderer "Back passes" "Back") finalActiveLine width = fitBuildLineLayout width labelWidth statusWidth True "" (staticStatusRenderer "Final compilation" "Final") clamp01 x = max 0 (min 1 x) parseProgressRatio p = let total = ppTotal p in if total <= 0 then 1 else clamp01 (fromIntegral (ppCompleted p) / fromIntegral total) progressRatio p = let total = fppTotal p in if total <= 0 then 1 else clamp01 (fromIntegral (fppCompleted p) / fromIntegral total) frontPassFraction p = case fppPass p of FrontPassKinds -> 0.10 * progressRatio p FrontPassTypes -> 0.10 + 0.90 * progressRatio p frontStatusRenderer p budget | budget < 10 = Nothing | otherwise = let total = max 0 (fppTotal p) completed = min total (max 0 (fppCompleted p)) countPart | total > 0 = " " ++ show completed ++ "/" ++ show total | otherwise = "" compact = let base = if total > 0 then "Types" ++ countPart else "Types" in if length base <= budget then base else "Types" fullTypeStatus mCurrent = let prefix = "Type checking " staticLen = length prefix + length countPart in if staticLen < budget then case mCurrent of Just nm -> prefix ++ abbreviateRight (budget - staticLen) nm ++ countPart Nothing -> "Type checking" ++ countPart else compact in case fppPass p of FrontPassKinds -> staticStatusRenderer "Kinds check" "Kinds" budget FrontPassTypes -> Just (fullTypeStatus (fppCurrent p)) parseStatusRenderer p budget | budget < 10 = Nothing | otherwise = let pct = floor (100 * parseProgressRatio p :: Double) full = "Parsing " ++ show pct ++ "%" short = "Parse " ++ show pct ++ "%" in if length full <= budget then Just full else if length short <= budget then Just short else Just (show pct ++ "%") frontProgressLine proj mn p = renderProjectLine proj mn (frontStatusRenderer p) finalKey = TaskKey rootProj (A.modName ["__final__"]) withTerm action = when termEnabled $ gate (withProgressLock progressUI action) setPercent pct = withTerm (termProgressPercent termProgress pct) addProgress delta = when (termEnabled && delta > 0) $ do new <- atomicModifyIORef' progressRef (\x -> let x' = min compilePhaseTotal (x + delta) in (x', x')) setPercent (floor new) shareFor key = M.findWithDefault (0, 0, 0) key shareMap creditParseTo key parseFrac = gate $ do let (parseShare, _, _) = shareFor key delta <- atomicModifyIORef' marksRef $ \m -> let (parseDoneFrac, frontDoneFrac, backDone) = M.findWithDefault (0, 0, False) key m parseDoneFrac' = max parseDoneFrac (clamp01 parseFrac) deltaFrac = max 0 (parseDoneFrac' - parseDoneFrac) in (M.insert key (parseDoneFrac', frontDoneFrac, backDone) m, parseShare * deltaFrac) addProgress delta creditFrontTo key frontFrac = gate $ do let (_, frontShare, _) = shareFor key delta <- atomicModifyIORef' marksRef $ \m -> let (parseDoneFrac, frontDoneFrac, backDone) = M.findWithDefault (0, 0, False) key m frontDoneFrac' = max frontDoneFrac (clamp01 frontFrac) deltaFrac = max 0 (frontDoneFrac' - frontDoneFrac) in (M.insert key (parseDoneFrac, frontDoneFrac', backDone) m, frontShare * deltaFrac) addProgress delta creditParse key = creditParseTo key 1 creditParseProgress key p = creditParseTo key (parseProgressRatio p) creditFront key = creditFrontTo key 1 creditFrontProgress key p = creditFrontTo key (frontPassFraction p) creditBack key = gate $ do let (_, _, backShare) = shareFor key delta <- atomicModifyIORef' marksRef $ \m -> let (parseDoneFrac, frontDoneFrac, backDone) = M.findWithDefault (0, 0, False) key m in if backDone then (m, 0) else (M.insert key (parseDoneFrac, frontDoneFrac, True) m, backShare) addProgress delta setPercent 0 let backJobKey job = TaskKey (projPath (bjPaths job)) (A.modname (biTypedMod (bjInput job))) onBackStart job = let proj = projPath (bjPaths job) mn = A.modname (biTypedMod (bjInput job)) in do gate (progressStartTask progressUI progressState (backJobKey job) (backActiveLine proj mn) (Just 0)) onBackDone job result = do gate (progressDoneTask progressUI progressState (backJobKey job)) creditBack (backJobKey job) when (not (quiet gopts optsPlan)) $ case result of BackJobOk mtime mtiming -> do logRendered (\cols -> backDoneLine cols (projPath (bjPaths job)) (A.modname (biTypedMod (bjInput job))) mtime) when (C.timing gopts) $ forM_ mtiming $ \bt -> logRendered (\cols -> detailLine cols detailStmtIndentWide detailStmtIndentNarrow (backTimingLine bt)) BackJobFailed failure -> logRendered (\cols -> backFailLine cols (projPath (bjPaths job)) (A.modname (biTypedMod (bjInput job))) (bpfMessage failure)) hooks = defaultCompileHooks { chOnDiagnostics = \t optsT diags -> do gate (progressDoneTask progressUI progressState (gtKey t)) logDiagnostics optsT diags , chOnParseStart = \t -> let key = gtKey t proj = tkProj key mn = tkMod key in gate (progressStartTask progressUI progressState key (parseActiveLine proj mn) (Just 0)) , chOnParseProgress = \t p -> let key = gtKey t proj = tkProj key mn = tkMod key in do gate (progressUpdateTask progressUI progressState key (parseProgressLine proj mn p) (Just (parseProgressRatio p))) creditParseProgress key p , chOnParseDone = \t mtime -> do gate (progressDoneTask progressUI progressState (gtKey t)) creditParse (gtKey t) when (not (quiet gopts optsPlan)) $ forM_ mtime $ \tParse -> do let proj = tkProj (gtKey t) mn = tkMod (gtKey t) logRendered (\cols -> parseDoneLine cols proj mn tParse) , chOnFrontResult = \t fr -> do forM_ (frFrontTime fr) $ \tFront -> do let proj = tkProj (gtKey t) mn = tkMod (gtKey t) logRendered (\cols -> frontDoneLine cols proj mn tFront) when (C.timing gopts) $ forM_ (frFrontTiming fr) $ \ft -> do logRendered (\cols -> detailLine cols detailStmtIndentWide detailStmtIndentNarrow (frontTimingLine ft)) forM_ (ftTypeStmtTimings ft) $ \st -> do logRendered (\cols -> detailTimedLine cols detailStmtIndentWide detailStmtIndentNarrow (typeStmtTimingLine st) (tstTime st)) logRendered (\cols -> detailLine cols detailBindsIndentWide detailBindsIndentNarrow (typeStmtBindsLine st)) when (C.timing gopts || C.verbose gopts) $ forM_ (frInferredSigs fr) $ \sig -> do logRendered (\cols -> detailLine cols detailStmtIndentWide detailStmtIndentNarrow (inferredSignatureLine sig)) forM_ (lines (isigSignature sig)) $ \line -> logRendered (\cols -> detailLine cols detailBindsIndentWide detailBindsIndentNarrow line) case frBackJob fr of Nothing -> creditBack (gtKey t) Just _ -> return () , chOnFrontStart = \t -> let key = gtKey t proj = tkProj key mn = tkMod key in gate (progressStartTask progressUI progressState key (frontInitialLine proj mn) (Just 0)) , chOnFrontProgress = \t p -> let key = gtKey t proj = tkProj key mn = tkMod key in do gate (progressUpdateTask progressUI progressState key (frontProgressLine proj mn p) (Just (frontPassFraction p))) creditFrontProgress key p , chOnFrontDone = \t -> do gate (progressDoneTask progressUI progressState (gtKey t)) creditFront (gtKey t) , chOnBackQueued = \_ _ -> return () , chOnBackStart = onBackStart , chOnBackDone = onBackDone , chOnInfo = logLine } onFinalStart = do gate (progressStartTask progressUI progressState finalKey finalActiveLine Nothing) setPercent 85 onFinalDone mtime = do gate (progressDoneTask progressUI progressState finalKey) setPercent 100 forM_ mtime $ \tFinal -> when (not (quiet gopts optsPlan)) $ logRendered (\cols -> finalDoneLine cols tFinal) return CliCompileHooks { cchHooks = hooks , cchLogLine = logLine , cchClearProgress = progressReset progressUI progressState , cchFinalStart = onFinalStart , cchFinalDone = onFinalDone , cchProgressUI = progressUI } -- | Run CLI-only post-compile steps. runCliPostCompile :: CliCompileHooks -> C.GlobalOptions -> CompilePlan -> Acton.Env.Env0 -> IO () runCliPostCompile cliHooks gopts plan env = do let logLine = cchLogLine cliHooks let cctx = cpContext plan opts' = ccOpts cctx pathsRoot = ccPathsRoot cctx rootProj = ccRootProj cctx sysAbs = ccSysAbs cctx rootTasks = cpRootTasks plan rootPins = cpRootPins plan allowPrune' = cpAllowPrune plan globalTasks = cpGlobalTasks plan neededTasks = cpNeededTasks plan projMap = cpProjMap plan sysRoot = addTrailingPathSeparator sysAbs rootSpec <- case M.lookup rootProj projMap of Just ctx -> return (projBuildSpec ctx) Nothing -> throwProjectError ("Missing root project context for " ++ rootProj) let rootParts = splitOn "." (C.root opts') rootMod = init rootParts guessMod = if length rootParts == 1 then modName pathsRoot else A.modName rootMod binTask = BinTask False (prstr guessMod) (A.GName guessMod (A.name $ last rootParts)) False preBinTasks | null (C.root opts') = map (\t -> BinTask True (modNameToString (name t)) (A.GName (name t) (A.name "main")) False) rootTasks | otherwise = [binTask] preTestBinTasks = map (\t -> BinTask True (modNameToString (name t)) (A.GName (name t) (A.name "test_main")) True) rootTasks selectedTasksByProj = selectedTasksWithProvidersByProj globalTasks neededTasks depModuleOptsByProj = depModuleOptionsByProj selectedTasksByProj projMap rootModuleEntries = selectedCSourceEntriesForProj rootProj (M.findWithDefault [] rootProj selectedTasksByProj) rootDepModuleOpts = M.findWithDefault M.empty rootProj depModuleOptsByProj rootDepPathOverrides = projectDepPathOverrides projMap rootProj -- Generate build.zig(.zon) for dependencies too, to satisfy Zig builder links. let projKeys = Data.Set.fromList (map (tkProj . gtKey) globalTasks) forM_ (Data.Set.toList projKeys) $ \p -> do let isRootProj = p == rootProj isSysProj = p == sysAbs || sysRoot `isPrefixOf` p unless (isRootProj || isSysProj) $ case M.lookup p projMap of Just pctx -> do when (C.verbose gopts) $ logLine ("Generating build.zig for dependency project " ++ p) dummyPaths <- pathsForModule opts' projMap pctx (A.modName ["__gen_build__"]) let depOpts = M.findWithDefault M.empty p depModuleOptsByProj depPathOverrides = projectDepPathOverrides projMap p genBuildZigFiles (projBuildSpec pctx) rootPins (ccDepOverrides cctx) dummyPaths depOpts depPathOverrides Nothing -> return () let runFinal action = do cchFinalStart cliHooks mtime <- action `onException` cchFinalDone cliHooks Nothing cchFinalDone cliHooks (Just mtime) if C.skip_build opts' then logLine " Skipping final build step" else if C.test opts' then do testBinTasks <- catMaybes <$> mapM (filterMainActor env pathsRoot) preTestBinTasks unless (altOutput opts') $ runFinal (compileBins gopts opts' pathsRoot env rootSpec rootTasks testBinTasks allowPrune' rootModuleEntries rootDepModuleOpts rootDepPathOverrides (Just (cchProgressUI cliHooks))) else do unless (altOutput opts') $ runFinal (compileBins gopts opts' pathsRoot env rootSpec rootTasks preBinTasks allowPrune' rootModuleEntries rootDepModuleOpts rootDepPathOverrides (Just (cchProgressUI cliHooks))) -- Generate documentation index for a project build by reading module names and -- docstrings from cached .ty headers or source headers. generateProjectDocIndex :: Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> Paths -> [String] -> IO () generateProjectDocIndex sp gopts opts paths srcFiles = do unless (C.skip_build opts || C.only_build opts || isTmp paths) $ do let docDir = joinPath [projPath paths, "out", "doc"] createDirectoryIfMissing True docDir entries <- catMaybes <$> forM srcFiles (\f -> do p <- findPaths f opts readModuleDoc sp gopts opts p f) DocP.generateDocIndex docDir entries -- | Relative C source paths for selected tasks in one project. selectedCSourceEntriesForProj :: FilePath -> [GlobalTask] -> [FilePath] selectedCSourceEntriesForProj proj tasks = nub [ collapseDots (makeRelativeOrAbsolute proj (outBase (gtPaths t) (name (gtTask t)) ++ ".c")) | t <- tasks ] -- | For incremental builds, include providers so link inputs stay complete. selectedTasksWithProvidersByProj :: [GlobalTask] -> [GlobalTask] -> M.Map FilePath [GlobalTask] selectedTasksWithProvidersByProj globalTasks neededTasks = M.fromListWith (++) [ (tkProj (gtKey t), [t]) | t <- selectedTasks ] where taskKeys = Data.Set.fromList (map gtKey globalTasks) depMap = M.fromList [ (gtKey t, Data.Set.fromList (filter (`Data.Set.member` taskKeys) (M.elems (gtImportProviders t)))) | t <- globalTasks ] start = Data.Set.fromList (map gtKey neededTasks) selectedKeys = reachable depMap start selectedTasks = [ t | t <- globalTasks, Data.Set.member (gtKey t) selectedKeys ] reachable deps startKeys = go (Data.Set.toList startKeys) Data.Set.empty where go [] seen = seen go (k:ks) seen = if Data.Set.member k seen then go ks seen else let ds = Data.Set.toList (M.findWithDefault Data.Set.empty k deps) in go (ds ++ ks) (Data.Set.insert k seen) -- | Relative root-stub C paths for selected binaries. selectedRootStubEntriesForBins :: Paths -> [BinTask] -> [FilePath] selectedRootStubEntriesForBins paths bins = nub [ collapseDots (makeRelativeOrAbsolute (projPath paths) (binTaskRoot paths b)) | b <- bins ] -- | For each consuming project, map dep name to selected C-source CSV. depModuleOptionsByProj :: M.Map FilePath [GlobalTask] -> M.Map FilePath ProjCtx -> M.Map FilePath (M.Map String String) depModuleOptionsByProj tasksByProj projMap = M.map mkForProj projMap where mkForProj ctx = M.fromList [ (depName, mkCsv depProj) | (depName, depProj) <- projDeps ctx ] mkCsv depProj = intercalate "," (selectedCSourceEntriesForProj depProj (M.findWithDefault [] depProj tasksByProj)) -- | Canonical package dependency roots reachable from one project. -- -- These paths come from project discovery, so they already reflect root pin -- overrides and fingerprint deduplication. Reusing them for build.zig.zon keeps -- Zig pointed at the same dependency roots where we generated build.zig files. projectDepPathOverrides :: M.Map FilePath ProjCtx -> FilePath -> M.Map String FilePath projectDepPathOverrides projMap rootProj = snd (go Data.Set.empty rootProj M.empty) where go seen proj acc | Data.Set.member proj seen = (seen, acc) | otherwise = case M.lookup proj projMap of Nothing -> (Data.Set.insert proj seen, acc) Just ctx -> let seen' = Data.Set.insert proj seen in foldl' step (seen', acc) (projDeps ctx) step (seen, acc) (depName, depProj) = let acc' = M.insertWith (\_ old -> old) depName depProj acc in go seen depProj acc' -- | Remove orphaned files in out/types. -- Non-root files are removed if their module isn’t part of this build (i.e. -- no corresponding source .act in this build). The 'roots' argument lists the -- exact set of root stub files (*.root.c, *.test_root.c) to keep; others are -- removed. removeOrphanFiles :: Paths -> [CompileTask] -> [FilePath] -> IO () removeOrphanFiles paths tasks roots = do let dir = projTypes paths absOutFiles <- getFilesRecursive dir let allowedBases = [ outBase paths (name t) | t <- tasks ] forM_ absOutFiles $ \absFile -> do let isC = takeExtension absFile == ".c" isH = takeExtension absFile == ".h" isTy = takeExtension absFile == ".ty" bext = takeExtension (takeBaseName absFile) isRootStub = isC && (bext == ".root" || bext == ".test_root") base = dropExtension absFile modBase = if isRootStub then dropExtension base else base if isRootStub then when (not (absFile `elem` roots) || not (modBase `elem` allowedBases)) (removeIfExists absFile) else when (isC || isH || isTy) $ do unless (base `elem` allowedBases) (removeIfExists absFile) where removeIfExists f = removeFile f `catch` handleNotExists handleNotExists :: IOException -> IO () handleNotExists _ = return () -- | Determine which root stub files should be preserved for the current build. -- We read the freshly written .ty headers (post-compile) for each task to keep -- whichever roots are still declared. This lets us drop stale root stubs when -- a module loses its root actor while still retaining stubs that belong to -- other build modes (e.g. keeping .root.c when running `acton test`). expectedRootStubs :: Paths -> [CompileTask] -> IO [FilePath] expectedRootStubs paths tasks = do roots <- forM tasks $ \t -> do let mn = name t outbase = outBase paths mn tyPath = outbase ++ ".ty" hdrE <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readHeader tyPath case hdrE of Right (_sourceMeta, _, _, _implH, _imps, _nameHashes, rs, _tests, _) -> return (map (mkStub outbase) rs) _ -> return [] return (concat roots) where mkStub outbase n = if nameToString n == "test_main" then outbase ++ ".test_root.c" else outbase ++ ".root.c" data BinTask = BinTask { isDefaultRoot :: Bool, binName :: String, rootActor :: A.QName, isTest :: Bool } deriving (Show) binTaskRoot :: Paths -> BinTask -> FilePath binTaskRoot paths binTask = let A.GName m _ = rootActor binTask outbase = outBase paths m in if isTest binTask then outbase ++ ".test_root.c" else outbase ++ ".root.c" {- ================================================================================ Build Pipeline Overview ================================================================================ We want the compiler to be fast. The primary principle by which to achieve this is to avoid doing unnecessary work. Practically, this happens by caching information in .ty files and only selectively reading what we need. We do not eagerly load whole .ty files but rather read the header fields: moduleSrcBytesHash, modulePubHash, moduleImplHash, imports, per-name hashes (src/pub/impl + deps), roots, tests, and docstrings. This lets us quickly decide which passes to rerun and reuse work from previous compilations. Public hashing: each top-level name gets a pubHash computed from its doc-free signature plus the pub hashes of its public dependencies. The modulePubHash is then the hash of pubHash values for exported names. Doc-only edits do not affect pubHash, and a downstream module only needs front passes when a pubHash changes. Implementation hashing: each top-level name gets an implHash computed from its source hash plus the impl hashes of its dependencies. The moduleImplHash is the hash of all per-name impl hashes. We embed moduleImplHash into generated .c/.h files so we can skip back passes when codegen is already up to date, and we use it (with impl deps) to drive the test cache. Terminology - ParseTask: a source-backed module whose imports are known but whose full AST has not been materialized yet - ActonTask: a fully parsed source module ready for front passes - TyTask: a module loaded from the cached .ty file on disk. Note how there are two variants, a stubbed TyTask where only header fields are loaded and the full TyTask where all module content is available. High-level Steps 1) Discover and read tasks using header-first strategy (readModuleTask) - For each module, try to use its .ty header to avoid parsing: - If .ty is missing/unreadable → read source and parse only the import header (ParseTask). - If the compiler compatibility guard says the cache is stale → read source and parse the import header now (ParseTask). - If source metadata in the .ty header still matches the current .act and the source mtime is strictly older than the .ty mtime → trust .ty header imports and create a TyTask stub (no heavy decode) for graph building. - If metadata differs, or source/.ty mtimes are equal, verify by content hash: – If stored moduleSrcBytesHash == current bytes hash → header is still valid (TyTask) and refresh cached source metadata. – Else → read source and parse the import header now (ParseTask) - Equal source/.ty mtimes are treated as ambiguous because coarse-mtime filesystems can assign the same visible timestamp to a changed source and the cached .ty written from an earlier version of that source. - This ensures that .ty is up to date with the .act source and lets us read module imports/roots/docstring from the header, which is much faster than parsing the full .act file. 2) Expand to include transitive project imports (readImports) - For project builds, we enumerate all modules under src/ upfront, so chasing is typically a no-op. - For single-file builds (or partial sets), we chase imports from the seeded tasks to ensure all project-local dependencies are included. We prefer .ty headers to avoid parsing; we parse only when a .ty is missing/unreadable. 3) Compile and build - compileTasks builds a stage graph and prefers front work over parse work: - ParseTask stages have no dependencies and can run opportunistically. - Front stages depend on the module's parse stage (if any) plus provider front stages. - Front-stage rebuild decisions are then made per module: - Source changed (ParseTask/ActonTask) → run front passes - Otherwise, compare each used pub dependency hash from the dependent’s .ty header with the provider’s current pub hash. If any differ → front. - Otherwise, compare each used impl dependency hash from the dependent’s .ty header with the provider’s current impl hash. If any differ → refresh impl hashes and run back passes. - Otherwise, if generated .c/.h hashes do not match moduleImplHash → run back passes. - Otherwise → module is fresh (no work). - We maintain a pubMap while walking modules in topological order. After a module compiles, we insert its freshly computed public hash; when a module is fresh (TyTask), we insert the recorded header hash. Dependents then consult pubMap to detect public deltas among their imports. - TyTask items remain lazy; code that needs only small bits (e.g., writeRootC) reads roots/doc from the header instead of forcing heavy loads. - Final Zig C compilation... ================================================================================ -} compileBins:: C.GlobalOptions -> C.CompileOptions -> Paths -> Acton.Env.Env0 -> BuildSpec.BuildSpec -> [CompileTask] -> [BinTask] -> Bool -> [FilePath] -> M.Map String String -> M.Map String FilePath -> Maybe ProgressUI -> IO TimeSpec compileBins gopts opts paths env rootSpec tasks binTasks allowPrune rootModules depModuleOpts depPathOverrides mProgressUI = zigBuild env gopts opts paths rootSpec tasks binTasks allowPrune rootModules depModuleOpts depPathOverrides mProgressUI printDiag :: C.GlobalOptions -> C.CompileOptions -> Diagnostic String -> IO () printDiag gopts opts d = do -- TODO: change to print to stderr! current tests presume stdout so we print to stdout for now.. shouldColor <- useColor gopts if shouldColor then printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle d else hPutDoc stdout $ unAnnotate (prettyDiagnostic WithoutUnicode (TabSize 4) d) printDiagnostics :: C.GlobalOptions -> C.CompileOptions -> [Diagnostic String] -> IO () printDiagnostics gopts opts diags = mapM_ (printDiag gopts opts) diags -- | Generate a root actor C file when a root is still declared. writeRootC :: Acton.Env.Env0 -> C.GlobalOptions -> C.CompileOptions -> Paths -> [CompileTask] -> BinTask -> IO (Maybe BinTask) writeRootC env gopts opts paths tasks binTask = do let qn@(A.GName m n) = rootActor binTask mn = A.mname qn outbase = outBase paths mn rootFile = if (isTest binTask) then outbase ++ ".test_root.c" else outbase ++ ".root.c" -- In --only-build mode, reuse existing root stubs; generate only if missing. existing <- if C.only_build opts then doesFileExist rootFile else return False if C.only_build opts && existing then return (Just binTask) else do -- Read the up-to-date roots from the on-disk .ty header (post-compile) -- Avoid using preloaded TyTask roots, which may be stale if the module -- was rebuilt during this run. tyPath <- Acton.Env.findTyFile (searchPath paths) m rootsHeader <- case tyPath of Just ty -> do (_sourceMeta, _, _, _implH, _imps, _nameHashes, roots, _tests, _) <- InterfaceFiles.readHeader ty; return roots Nothing -> return [] let rootsEnv = case Acton.Env.lookupMod m env of Nothing -> [] Just te -> [ n' | (n', i) <- te, rootEligible i ] shouldGen = n `elem` rootsHeader || n `elem` rootsEnv if shouldGen then do res <- (try :: IO a -> IO (Either SomeException a)) $ do c <- Acton.CodeGen.genRoot env qn createDirectoryIfMissing True (takeDirectory rootFile) writeFile rootFile c case res of Right _ -> return (Just binTask) Left _ -> return Nothing else return Nothing -- | Check whether a target triple refers to Windows. isWindowsOS :: String -> Bool isWindowsOS targetTriple = case splitOn "-" targetTriple of (_:os:_) -> os == "windows" _ -> False -- | Run a process and capture output, canceling on exceptions. readProcessWithExitCodeCancelable :: CreateProcess -> (ProcessHandle -> IO ()) -> IO (ExitCode, String, String) readProcessWithExitCodeCancelable cp onStart = do let cp' = cp { std_in = NoStream, std_out = CreatePipe, std_err = CreatePipe } withCreateProcess cp' $ \_ mOut mErr ph -> do onStart ph outVar <- newEmptyMVar errVar <- newEmptyMVar let readHandle mH var = case mH of Nothing -> putMVar var "" Just h -> do txt <- hGetContents h _ <- evaluate (length txt) hClose h putMVar var txt _ <- forkIO $ readHandle mOut outVar _ <- forkIO $ readHandle mErr errVar code <- waitForProcess ph `onException` do terminateProcess ph void (waitForProcess ph) out <- takeMVar outVar err <- takeMVar errVar return (code, out, err) runZig gopts opts zigExe zigArgs paths wd mProgressUI = do let display = showCommandForUser zigExe zigArgs iff (C.ccmd opts || C.verbose gopts) $ putStrLn ("zigCmd: " ++ display) env0 <- System.Environment.getEnvironment let ignoreIO :: IOException -> IO () ignoreIO _ = return () withLock = case mProgressUI of Just ui -> withProgressLock ui Nothing -> \action -> action mTermProgress = do ui <- mProgressUI let tp = puTermProgress ui if termProgressEnabled tp then Just tp else Nothing (envOverride, onStart, onStop, closeFds) <- case mTermProgress of Nothing -> return (Nothing, \_ -> return (), return (), True) Just tp -> do (readFd, writeFd) <- createPipe setFdOption writeFd CloseOnExec False setFdOption readFd CloseOnExec True doneVar <- newEmptyMVar pctRef <- newIORef (85 :: Int) let updatePercent ratio = do let clamped = max 0 (min 0.999 ratio) pctRaw = 85 + floor (clamped * 15) pct <- atomicModifyIORef' pctRef (\prev -> let next = max prev pctRaw in (next, next)) withLock (termProgressPercent tp pct) reader = do readZigProgressStream readFd $ \msg -> case zigProgressRatio msg of Nothing -> return () Just ratio -> updatePercent ratio _ <- forkIO (reader `finally` putMVar doneVar ()) let envVal = show (fromIntegral writeFd :: Int) onStart' _ = closeFd writeFd `catch` ignoreIO onStop' = do closeFd writeFd `catch` ignoreIO closeFd readFd `catch` ignoreIO takeMVar doneVar return (Just ("ZIG_PROGRESS", envVal), onStart', onStop', False) let env1 = if System.Info.os == "darwin" && not (any ((== "DEVELOPER_DIR") . fst) env0) then ("DEVELOPER_DIR", "/dev/null") : env0 else env0 env2 = case envOverride of Nothing -> Just env1 Just (k, v) -> Just ((k, v) : filter ((/= k) . fst) env1) cpBase = (proc zigExe zigArgs){ cwd = wd, env = env2 } cp = if closeFds then cpBase else cpBase { close_fds = False } (returnCode, zigStdout, zigStderr) <- readProcessWithExitCodeCancelable cp onStart `finally` onStop case returnCode of ExitSuccess -> do iff (C.verboseZig gopts) $ putStrLn zigStderr return () ExitFailure ret -> do printIce ("compilation of generated Zig code failed, returned error code" ++ show ret) putStrLn $ "zig stdout:\n" ++ zigStdout putStrLn $ "zig stderr:\n" ++ zigStderr unless (C.watch opts) System.Exit.exitFailure generateFingerprint :: String -> IO String generateFingerprint name = do ident <- randomRIO (1, 0xfffffffe :: Word32) let prefix = Fingerprint.fingerprintPrefixForName name fp = (fromIntegral prefix `shiftL` 32) .|. fromIntegral ident return (Fingerprint.formatFingerprint fp) -- Render build.zig and build.zig.zon from templates and BuildSpec. -- rootPins: dependency pins from the main project (applied to all deps, including transitive) genBuildZigFiles :: BuildSpec.BuildSpec -> M.Map String BuildSpec.PkgDep -> [(String, FilePath)] -> Paths -> M.Map String String -> M.Map String FilePath -> IO () genBuildZigFiles spec rootPins depOverrides paths depModuleOpts depPathOverrides = do let proj = projPath paths projAbs <- canonicalizePath proj let sys = sysPath paths buildZigPath = joinPath [proj, "build.zig"] buildZonPath = joinPath [proj, "build.zig.zon"] distBuildZigPath = joinPath [sys, "builder", "build.zig"] distBuildZonPath = joinPath [sys, "builder", "build.zig.zon"] buildZigTemplate <- readFile distBuildZigPath buildZonTemplate <- readFile distBuildZonPath let zonName = BuildSpec.specName spec fp = BuildSpec.fingerprint spec (transPkgs, transZigs) <- collectDepsRecursive spec proj rootPins depOverrides absSys <- canonicalizePath sys let relSys = relativeViaRoot projAbs absSys homeDir <- getHomeDirectory depsRootAbs <- normalizePathSafe (joinPath [homeDir, ".cache", "acton", "deps"]) normalizedSpec <- normalizeSpecPaths proj spec let directZigs = [ ZigDepRef depName (rebaseZigDep projAbs proj dep) | (depName, dep) <- M.toList (BuildSpec.zig_dependencies normalizedSpec) ] applyPins deps = M.mapWithKey (\n d -> M.findWithDefault d n rootPins) deps mergedSpec0 = normalizedSpec { BuildSpec.dependencies = applyPins (BuildSpec.dependencies normalizedSpec) `M.union` transPkgs } mergedSpec = applyPkgDepPathOverrides projAbs depPathOverrides mergedSpec0 resolvedZigs = resolveZigDepRefs (M.keys (BuildSpec.dependencies mergedSpec)) (directZigs ++ transZigs) zonWithFp = replace "{{fingerprint}}" fp . replace "{{name}}" zonName writeFile buildZigPath (genBuildZig buildZigTemplate mergedSpec resolvedZigs depModuleOpts) writeFileAtomic buildZonPath (genBuildZigZon buildZonTemplate relSys depsRootAbs projAbs fp zonName mergedSpec resolvedZigs) applyPkgDepPathOverrides :: FilePath -> M.Map String FilePath -> BuildSpec.BuildSpec -> BuildSpec.BuildSpec applyPkgDepPathOverrides projRoot depPathOverrides spec = spec { BuildSpec.dependencies = M.mapWithKey rewriteDep (BuildSpec.dependencies spec) } where rewriteDep depName dep = case M.lookup depName depPathOverrides of Nothing -> dep Just depPath -> dep { BuildSpec.path = Just (collapseDots (makeRelativeOrAbsolute projRoot depPath)) } data ZigDepRef = ZigDepRef { zigDepRefName :: String , zigDepRefDep :: BuildSpec.ZigDep } data ZigDepResolved = ZigDepResolved { zigDepResolvedVarName :: String , zigDepResolvedPkgName :: String , zigDepResolvedDep :: BuildSpec.ZigDep } data ZigDepIdentity = ZigDepPathIdentity FilePath (M.Map String String) | ZigDepHashIdentity String (M.Map String String) | ZigDepUrlIdentity (Maybe String) (M.Map String String) deriving (Eq, Ord, Show) zigDepIdentity :: BuildSpec.ZigDep -> ZigDepIdentity zigDepIdentity dep = case BuildSpec.zpath dep of Just p | not (null p) -> ZigDepPathIdentity p (BuildSpec.options dep) _ -> case BuildSpec.zhash dep of Just h | not (null h) -> ZigDepHashIdentity h (BuildSpec.options dep) _ -> ZigDepUrlIdentity (BuildSpec.zurl dep) (BuildSpec.options dep) mergeUniqueStrings :: [String] -> [String] -> [String] mergeUniqueStrings xs ys = xs ++ [ y | y <- ys, y `notElem` xs ] mergeZigDeps :: BuildSpec.ZigDep -> BuildSpec.ZigDep -> BuildSpec.ZigDep mergeZigDeps dep0 dep1 = dep0 { BuildSpec.artifacts = mergeUniqueStrings (BuildSpec.artifacts dep0) (BuildSpec.artifacts dep1) } dedupZigDepRefs :: [ZigDepRef] -> [(String, BuildSpec.ZigDep)] dedupZigDepRefs refs = let (orderRev, byIdentity) = foldl' step ([], M.empty) refs in [ let ref = byIdentity M.! ident in (zigDepRefName ref, zigDepRefDep ref) | ident <- reverse orderRev ] where step (orderRev, byIdentity) ref = let ident = zigDepIdentity (zigDepRefDep ref) in case M.lookup ident byIdentity of Nothing -> (ident : orderRev, M.insert ident ref byIdentity) Just prevRef -> let mergedRef = prevRef { zigDepRefDep = mergeZigDeps (zigDepRefDep prevRef) (zigDepRefDep ref) } in (orderRev, M.insert ident mergedRef byIdentity) nextAvailableName :: Data.Set.Set String -> String -> String nextAvailableName usedNames baseName = go 0 where go 0 | Data.Set.member baseName usedNames = go 2 | otherwise = baseName go n = let candidate = baseName ++ "_" ++ show n in if Data.Set.member candidate usedNames then go (n + 1) else candidate -- | Zig and Acton package dependencies share one Zig package namespace at -- generation time. Keep generated zig package keys disjoint from package deps -- and reserved builder deps so a wrapper package and its underlying zig pkg can -- reuse the same logical dependency name. resolveZigDepRefs :: [String] -> [ZigDepRef] -> [ZigDepResolved] resolveZigDepRefs pkgDepNames refs = reverse resolvedRev where reservedNames = Data.Set.fromList (["actondb", "base"] ++ pkgDepNames) uniqueRefs = dedupZigDepRefs refs (_, _, resolvedRev) = foldl' assign (reservedNames, Data.Set.empty, []) uniqueRefs assign (usedPkgNames, usedVarNames, acc) (depName, dep) = let pkgName = nextAvailableName usedPkgNames ("acton_zig_" ++ depName) varName = nextAvailableName usedVarNames depName resolved = ZigDepResolved { zigDepResolvedVarName = varName , zigDepResolvedPkgName = pkgName , zigDepResolvedDep = dep } in ( Data.Set.insert pkgName usedPkgNames , Data.Set.insert varName usedVarNames , resolved : acc ) genBuildZig :: String -> BuildSpec.BuildSpec -> [ZigDepResolved] -> M.Map String String -> String genBuildZig template spec zigDeps depModuleOpts = let depsDefs = concatMap pkgDepDef (M.toList (BuildSpec.dependencies spec)) zigDefs = concatMap zigDepDef zigDeps depsAll = depsDefs ++ zigDefs libLinks = concatMap pkgLibLink (M.toList (BuildSpec.dependencies spec)) ++ concatMap zigLibLink zigDeps exeLinks = concatMap pkgExeLink (M.toList (BuildSpec.dependencies spec)) ++ concatMap zigExeLink zigDeps header = [ "// AUTOMATICALLY GENERATED BY ACTON BUILD SYSTEM" , "// DO NOT EDIT, CHANGES WILL BE OVERWRITTEN!!!!!" , "" ] inject line = let sline = dropWhile (== ' ') line in [line] ++ (if sline == "// Dependencies from Build.act" then [depsAll] else []) ++ (if sline == "// lib: link with dependencies / get headers from Build.act" then [libLinks] else []) ++ (if sline == "// exe: link with dependencies / get headers from Build.act" then [exeLinks] else []) in unlines $ header ++ concatMap inject (lines template) where pkgDepDef (name, _) = let selectedCsv = M.findWithDefault "" name depModuleOpts in unlines [ " const actdep_" ++ name ++ " = b.dependency(\"" ++ name ++ "\", .{" , " .target = target," , " .optimize = optimize," , " .acton_modules = " ++ show selectedCsv ++ "," , " .acton_root_stubs = \"\"," , " });" ] pkgLibLink (name, _) = " libActonProject.linkLibrary(actdep_" ++ name ++ ".artifact(\"ActonProject\"));\n" pkgExeLink (name, _) = " executable.linkLibrary(actdep_" ++ name ++ ".artifact(\"ActonProject\"));\n" zigDepDef resolved | null (BuildSpec.artifacts dep) = "" | otherwise = let opts = concat [ " ." ++ k ++ " = " ++ v ++ ",\n" | (k, v) <- M.toList (BuildSpec.options dep) ] in unlines [ " const dep_" ++ zigDepResolvedVarName resolved ++ " = b.dependency(\"" ++ zigDepResolvedPkgName resolved ++ "\", .{" , " .target = target," , " .optimize = optimize," , opts ++ " });" ] where dep = zigDepResolvedDep resolved zigLibLink resolved = concat [ " libActonProject.linkLibrary(dep_" ++ zigDepResolvedVarName resolved ++ ".artifact(\"" ++ art ++ "\"));\n" | art <- BuildSpec.artifacts (zigDepResolvedDep resolved) ] zigExeLink resolved = concat [ " executable.linkLibrary(dep_" ++ zigDepResolvedVarName resolved ++ ".artifact(\"" ++ art ++ "\"));\n" | art <- BuildSpec.artifacts (zigDepResolvedDep resolved) ] genBuildZigZon :: String -> String -> FilePath -> FilePath -> String -> String -> BuildSpec.BuildSpec -> [ZigDepResolved] -> String genBuildZigZon template relSys depsRootAbs projAbs fingerprint zonName spec zigDepsResolved = let pkgDeps = concatMap (pkgToZon projAbs depsRootAbs) (M.toList (BuildSpec.dependencies spec)) zigDeps = concatMap zigToZon zigDepsResolved deps = pkgDeps ++ zigDeps replaced = map (replace "{{fingerprint}}" fingerprint . replace "{{syspath}}" relSys . replace "{{name}}" zonName) (lines template) header = [ "// AUTOMATICALLY GENERATED BY ACTON BUILD SYSTEM" , "// DO NOT EDIT, CHANGES WILL BE OVERWRITTEN!!!!!" , "" ] inject line = let sline = dropWhile (== ' ') line in [line] ++ (if sline == "// Dependencies from Build.act" then [deps] else []) in unlines $ header ++ concatMap inject replaced where pkgToZon projRoot depsRoot (name, dep) = let rawPath = case BuildSpec.path dep of Just p | not (null p) -> p _ -> case BuildSpec.hash dep of Just h -> joinPath [depsRoot, name ++ "-" ++ h] Nothing -> errorWithoutStackTrace ("Dependency " ++ name ++ " has no path or hash") pathAbs = collapseDots $ if isAbsolutePath rawPath then normalise rawPath else normalise (rebasePath projRoot rawPath) path = relativeViaRoot projRoot pathAbs in unlines [ " ." ++ name ++ " = .{" , " .path = \"" ++ path ++ "\"," , " }," ] zigToZon resolved = case BuildSpec.zpath dep of Just p -> let absPath = collapseDots $ if isAbsolutePath p then normalise p else normalise (rebasePath projAbs p) relPath = relativeViaRoot projAbs absPath in unlines [ " ." ++ zigDepResolvedPkgName resolved ++ " = .{" , " .path = \"" ++ relPath ++ "\"," , " }," ] Nothing -> unlines [ " ." ++ zigDepResolvedPkgName resolved ++ " = .{" , " .url = \"" ++ maybeEmpty (BuildSpec.zurl dep) ++ "\"," , " .hash = \"" ++ maybeEmpty (BuildSpec.zhash dep) ++ "\"," , " }," ] where dep = zigDepResolvedDep resolved maybeEmpty (Just s) = s maybeEmpty Nothing = "" #if defined(darwin_HOST_OS) && defined(aarch64_HOST_ARCH) defCpuFlag = ["-Dcpu=apple_m1"] #elif defined(aarch64_HOST_ARCH) defCpuFlag = ["-Dcpu=generic+crypto"] #elif defined(x86_64_HOST_ARCH) defCpuFlag = ["-Dcpu=x86_64_v2+aes"] #else #error "Unsupported platform" #endif -- | Run zig build for generated artifacts and prune stale outputs. zigBuild :: Acton.Env.Env0 -> C.GlobalOptions -> C.CompileOptions -> Paths -> BuildSpec.BuildSpec -> [CompileTask] -> [BinTask] -> Bool -> [FilePath] -> M.Map String String -> M.Map String FilePath -> Maybe ProgressUI -> IO TimeSpec zigBuild env gopts opts paths rootSpec tasks binTasks allowPrune rootModules depModuleOpts depPathOverrides mProgressUI = do allBinTasks <- mapM (writeRootC env gopts opts paths tasks) binTasks let realBinTasks = catMaybes allBinTasks let pruningAllowed = allowPrune && not (C.only_build opts) when pruningAllowed $ do -- Clean out/types: drop stray outputs and stale root stubs based on the -- current headers. Also keep the roots we attempted to build in this run -- so they survive even if a header failed to list them (defensive). let requestedRoots = map (binTaskRoot paths) realBinTasks headerRoots <- expectedRootStubs paths tasks let roots = nub (headerRoots ++ requestedRoots) removeOrphanFiles paths tasks roots unless (isTmp paths) $ -- Clean old binaries from out/bin removeOrphanExecutables (binDir paths) (projTypes paths) realBinTasks timeStart <- getTime Monotonic homeDir <- getHomeDirectory let local_cache_dir = joinPath [ homeDir, ".cache", "acton", "zig-local-cache" ] global_cache_dir = joinPath [ homeDir, ".cache", "acton", "zig-global-cache" ] no_threads = if isWindowsOS (C.target opts) then True else C.no_threads opts projAbs <- normalizePathSafe (projPath paths) sysAbs <- normalizePathSafe (sysPath paths) depOverrides <- normalizeDepOverrides (projPath paths) (C.dep_overrides opts) let sysRoot = addTrailingPathSeparator sysAbs isSysProj = projAbs == sysAbs || sysRoot `isPrefixOf` projAbs -- Generate build.zig and build.zig.zon directly from Build.act. iff (not isSysProj) $ do let pins = BuildSpec.dependencies rootSpec genBuildZigFiles rootSpec pins depOverrides paths depModuleOpts depPathOverrides let zigExe = zig paths baseArgs = ["build","--cache-dir", local_cache_dir, "--global-cache-dir", global_cache_dir] ++ (if (C.verboseZig gopts) then ["--verbose"] else []) prefixArgs = ["--prefix", projOut paths, "--prefix-exe-dir", "bin"] ++ (if (C.verboseZig gopts) then ["--verbose"] else []) targetArgs = ["-Dtarget=" ++ C.target opts] cpuArgs = if (C.cpu opts /= "") then ["-Dcpu=" ++ C.cpu opts] else case (splitOn "-" (C.target opts)) of ("native":_) -> defCpuFlag ("aarch64":"macos":_) -> ["-Dcpu=apple_m1"] ("aarch64":_) -> ["-Dcpu=generic+crypto"] ("x86_64":_) -> ["-Dcpu=x86_64_v2+aes"] (_:_) -> defCpuFlag [] -> defCpuFlag optArgs = ["-Doptimize=" ++ optimizeModeToZig (C.optimize opts)] rootModulesCsv = intercalate "," rootModules rootStubsCsv = intercalate "," (selectedRootStubEntriesForBins paths realBinTasks) moduleArgs = [ "-Dacton_modules=" ++ rootModulesCsv , "-Dacton_root_stubs=" ++ rootStubsCsv ] featureArgs = concat [ if C.db opts then ["-Ddb"] else [] , if no_threads then ["-Dno_threads"] else [] , if C.cpedantic opts then ["-Dcpedantic"] else [] ] zigArgs = baseArgs ++ prefixArgs ++ targetArgs ++ cpuArgs ++ optArgs ++ moduleArgs ++ featureArgs runZig gopts opts zigExe zigArgs paths (Just (projPath paths)) mProgressUI -- if we are in a temp acton project, copy the outputted binary next to the source file if (isTmp paths && not (null realBinTasks)) then do let baseName = binName (head binTasks) exeName = if isWindowsOS (C.target opts) then baseName ++ ".exe" else baseName srcBinFile = joinPath [ projOut paths, "bin", exeName ] dstBinFile = joinPath [ binDir paths, exeName ] copyFile srcBinFile dstBinFile else return () timeEnd <- getTime Monotonic return (timeEnd - timeStart) -- Remove executables that no longer have corresponding root actors -- | Remove binaries that no longer have corresponding roots. removeOrphanExecutables :: FilePath -> FilePath -> [BinTask] -> IO () removeOrphanExecutables binDir projTypes binTasks = do binDirExists <- doesDirectoryExist binDir when binDirExists $ do binFiles <- listDirectory binDir forM_ binFiles $ \exeFile -> do let exeName = takeBaseName exeFile modPath = map (\c -> if c == '.' then '/' else c) exeName rootCFile = projTypes modPath <.> "root.c" testRootCFile = projTypes modPath <.> "test_root.c" let isCurrentBin = any (\t -> binName t == exeName) binTasks rootExists <- doesFileExist rootCFile testRootExists <- doesFileExist testRootCFile when (not isCurrentBin && not rootExists && not testRootExists) $ do let fileName = binDir exeFile removeFile fileName `catch` handleNotExists where handleNotExists :: IOException -> IO () handleNotExists _ = return () -- | Compute a relative path when possible, otherwise a safe absolute form. makeRelativeOrAbsolute :: FilePath -> FilePath -> FilePath makeRelativeOrAbsolute base target = let (bDriveRaw, bPath) = splitDrive (normalise base) (tDriveRaw, tPath) = splitDrive (normalise target) bDrive = map toLower bDriveRaw tDrive = map toLower tDriveRaw bParts = cleanParts bPath tParts = cleanParts tPath common = length (takeWhile (uncurry (==)) (zip bParts tParts)) ups = replicate (length bParts - common) ".." relParts = ups ++ drop common tParts rel = if null relParts then "." else joinPath relParts in if bDrive /= tDrive && (not (null bDrive) || not (null tDrive)) then joinPath (replicate (length bParts) ".." ++ (tDriveRaw : tParts)) else rel where cleanParts = filter (\c -> not (null c) && c /= "/") . splitDirectories -- | Compute a path relative to the project root with drive handling. relativeViaRoot :: FilePath -> FilePath -> FilePath relativeViaRoot baseAbs targetAbs | not (isAbsolutePath targetAbs) = targetAbs | otherwise = let (bDriveRaw, bPath) = splitDrive (normalise baseAbs) (tDriveRaw, tPath) = splitDrive (normalise targetAbs) bDrive = map toLower bDriveRaw tDrive = map toLower tDriveRaw in if bDrive /= tDrive && (not (null bDrive) || not (null tDrive)) then makeRelativeOrAbsolute baseAbs targetAbs else let ups = replicate (length (cleanParts bPath)) ".." tParts = cleanParts tPath in joinPath (ups ++ tParts) where cleanParts = filter (\c -> not (null c) && c /= "/") . splitDirectories -- | Walk BuildSpec dependencies to collect transitive packages and zig deps. collectDepsRecursive :: BuildSpec.BuildSpec -> FilePath -> M.Map String BuildSpec.PkgDep -> [(String, FilePath)] -> IO (M.Map String BuildSpec.PkgDep, [ZigDepRef]) collectDepsRecursive rootSpec projDir pins overrides = do root <- normalizePathSafe projDir spec <- applyDepOverrides root overrides rootSpec (\(_, pkgs, zigs) -> (pkgs, zigs)) <$> foldM (step root root) (Data.Set.empty, M.empty, []) (M.toList (BuildSpec.dependencies spec)) where go root seen dir mSpec = do spec0 <- case mSpec of Just s -> return s Nothing -> loadBuildSpec dir spec <- applyDepOverrides dir overrides spec0 let depsHere = BuildSpec.dependencies spec zigsHere = [ ZigDepRef depName (rebaseZigDep root dir dep) | (depName, dep) <- M.toList (BuildSpec.zig_dependencies spec) ] foldM (step root dir) (seen, M.empty, zigsHere) (M.toList depsHere) step root base (seen, pkgAcc, zigAcc) (depName, dep) = do let depChosen = case M.lookup depName pins of Nothing -> dep Just pdep -> pdep depBase <- resolveDepBase base depName depChosen let seen' = Data.Set.insert depBase seen rebasePkgPath d = case BuildSpec.path d of Just p | not (null p) -> let absP = rebasePath base p relP = makeRelativeOrAbsolute root absP in d { BuildSpec.path = Just (collapseDots relP) } _ -> d dep' = rebasePkgPath depChosen if Data.Set.member depBase seen then return (seen', pkgAcc, zigAcc) else do (seenNext, subPkgs, subZigs) <- go root seen' depBase Nothing let pkgAcc' = M.insertWith (\_ old -> old) depName dep' pkgAcc return (seenNext, pkgAcc' `M.union` subPkgs, zigAcc ++ subZigs) rebaseZigDep :: FilePath -> FilePath -> BuildSpec.ZigDep -> BuildSpec.ZigDep rebaseZigDep root base dep = case BuildSpec.zpath dep of Just p | not (null p) -> let absP = rebasePath base p relP = makeRelativeOrAbsolute root absP in dep { BuildSpec.zpath = Just (collapseDots relP) } _ -> dep -- | Normalize dependency paths in a BuildSpec. normalizeSpecPaths :: FilePath -> BuildSpec.BuildSpec -> IO BuildSpec.BuildSpec normalizeSpecPaths base spec = do deps <- normalizePkgDeps base (BuildSpec.dependencies spec) zigs <- normalizeZigDeps base (BuildSpec.zig_dependencies spec) return spec { BuildSpec.dependencies = deps , BuildSpec.zig_dependencies = zigs } where normalizePkgDeps b = fmap M.fromList . mapM (\(k,v) -> do v' <- normalizePkgDep b v; return (k,v')) . M.toList normalizePkgDep b dep = case BuildSpec.path dep of Just p | not (null p) -> do if isAbsolutePath p then do p' <- normalizePathSafe p return dep { BuildSpec.path = Just p' } else return dep { BuildSpec.path = Just (collapseDots (normalise p)) } _ -> return dep normalizeZigDeps b = fmap M.fromList . mapM (\(k,v) -> do v' <- normalizeZigDep b v; return (k,v')) . M.toList -- | Normalize a zig dependency path entry. normalizeZigDep :: FilePath -> BuildSpec.ZigDep -> IO BuildSpec.ZigDep normalizeZigDep b dep = case BuildSpec.zpath dep of Just p | not (null p) -> do if isAbsolutePath p then do p' <- normalizePathSafe p return dep { BuildSpec.zpath = Just p' } else return dep { BuildSpec.zpath = Just (collapseDots (normalise p)) } _ -> return dep -- | Filter bin tasks to those with a valid root actor. filterMainActor :: Acton.Env.Env0 -> Paths -> BinTask -> IO (Maybe BinTask) filterMainActor env paths binTask = do let qn@(A.GName m n) = rootActor binTask let checkEnv = case Acton.Env.lookupMod m env of Nothing -> return Nothing Just te -> do let rootsEnv = [ n' | (n', i) <- te, rootEligible i ] if n `elem` rootsEnv then return (Just binTask) else return Nothing mty <- Acton.Env.findTyFile (searchPath paths) m case mty of Just ty -> do hdrE <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readHeader ty case hdrE of Right (_sourceMeta, _, _, _implH, _imps, _nameHashes, roots, _tests, _) | n `elem` roots -> return (Just binTask) _ -> checkEnv Nothing -> checkEnv -- | Check whether git is available on PATH. isGitAvailable :: IO Bool isGitAvailable = do (exitCode, _, _) <- readProcessWithExitCode "git" ["--version"] "" return $ exitCode == ExitSuccess -- | Decide whether to emit colored diagnostics. useColor :: C.GlobalOptions -> IO Bool useColor gopts = do noColorEnv <- lookupEnv "NO_COLOR" case noColorEnv of Just _ -> return False Nothing -> case C.color gopts of C.Never -> return False C.Always -> return True C.Auto -> do tty <- hIsTerminalDevice stdout return (tty || C.tty gopts) data ProgressUI = ProgressUI { puEnabled :: Bool , puWidthAware :: Bool , puMaxLines :: Int , puLinesRef :: IORef [String] , puVisibleRef :: IORef Int , puSpinnerRef :: IORef Int , puUseColor :: Bool , puCursorHiddenRef :: IORef Bool , puTickerRef :: IORef (Maybe ThreadId) , puTermProgress :: TermProgress , puTermSize :: TermSize , puLock :: MVar () } data ProgressState = ProgressState { psActive :: IORef (M.Map TaskKey ProgressTask) , psOrder :: IORef [TaskKey] } data ProgressTask = ProgressTask { ptRenderLine :: Int -> BuildLineLayout , ptStart :: TimeSpec , ptProgress :: Maybe Double } -- | Initialize terminal progress UI state and enablement. initProgressUI :: C.GlobalOptions -> Int -> IO ProgressUI initProgressUI gopts maxLines = do tty <- hIsTerminalDevice stdout let widthAware = (tty || C.tty gopts) && not (C.quiet gopts) enabled = widthAware && not (C.noProgress gopts) useColorOut <- useColor gopts linesRef <- newIORef [] visibleRef <- newIORef 0 spinnerRef <- newIORef 0 cursorHiddenRef <- newIORef False tickerRef <- newIORef Nothing termProgress <- initTermProgress gopts termSize <- initTermSize widthAware lock <- newMVar () return ProgressUI { puEnabled = enabled , puWidthAware = widthAware , puMaxLines = max 1 maxLines , puLinesRef = linesRef , puVisibleRef = visibleRef , puSpinnerRef = spinnerRef , puUseColor = useColorOut , puCursorHiddenRef = cursorHiddenRef , puTickerRef = tickerRef , puTermProgress = termProgress , puTermSize = termSize , puLock = lock } -- | Initialize tracking for active progress tasks. newProgressState :: IO ProgressState newProgressState = do active <- newIORef M.empty order <- newIORef [] return ProgressState { psActive = active, psOrder = order } -- | Serialize progress UI updates when rendering is enabled. withProgressLock :: ProgressUI -> IO a -> IO a withProgressLock ui action = if not (puEnabled ui) then action else withMVar (puLock ui) (\_ -> action) -- | Clear the progress area, run a log action, then redraw. progressWithLog :: ProgressUI -> IO () -> IO () progressWithLog ui action = withProgressLock ui $ do if not (puEnabled ui) then action else do progressClearUnlocked ui action progressRenderUnlocked ui -- | Log a line while preserving the progress display. progressLogLine :: ProgressUI -> String -> IO () progressLogLine ui msg = progressWithLog ui (putStrLn msg) -- | Clear the progress area from the terminal. progressClearUnlocked :: ProgressUI -> IO () progressClearUnlocked ui = do visible <- readIORef (puVisibleRef ui) when (visible > 0) $ do replicateM_ visible $ do putStr "\ESC[1A" putStr "\r\ESC[2K" hFlush stdout writeIORef (puVisibleRef ui) 0 -- | Progress heartbeat interval in microseconds. progressTickMicros :: Int progressTickMicros = 80000 -- | Spinner frames used by the progress UI. spinnerChars :: [Char] spinnerChars = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏" -- | Hide or show the cursor during progress rendering. setCursorHidden :: ProgressUI -> Bool -> IO () setCursorHidden ui hidden = when (puEnabled ui) $ do cur <- readIORef (puCursorHiddenRef ui) when (cur /= hidden) $ do putStr (if hidden then "\ESC[?25l" else "\ESC[?25h") writeIORef (puCursorHiddenRef ui) hidden -- | Render the current progress lines with one terminal row per live line. progressRenderUnlocked :: ProgressUI -> IO () progressRenderUnlocked ui = do (_, rows, cols) <- termSizeSync (puTermSize ui) allLines <- readIORef (puLinesRef ui) prevVisible <- readIORef (puVisibleRef ui) let renderWidth = safeLiveWidth cols visibleCap = min (puMaxLines ui) (max 0 (rows - 1)) lines = take visibleCap allLines newVisible = length lines if newVisible == 0 then do setCursorHidden ui False progressClearUnlocked ui else do when (prevVisible > 0) $ replicateM_ prevVisible (putStr "\ESC[1A") spinnerIx <- readIORef (puSpinnerRef ui) let spinner = spinnerChars !! (spinnerIx `mod` length spinnerChars) useSpinner = progressPrefixWidth cols > 0 prefix line | useSpinner = termFitAnsiRight renderWidth (' ' : spinner : ' ' : line) | otherwise = termFitAnsiRight renderWidth line let renderLine i = do putStr "\r\ESC[2K" when (i < newVisible) $ putStr (prefix (lines !! i)) putStr "\n" setCursorHidden ui True mapM_ renderLine [0 .. max prevVisible newVisible - 1] hFlush stdout writeIORef (puVisibleRef ui) (max prevVisible newVisible) -- | Start the progress heartbeat thread when needed. startProgressTicker :: ProgressUI -> ProgressState -> IO () startProgressTicker ui st = when (puEnabled ui) $ do m <- readIORef (puTickerRef ui) case m of Just _ -> return () Nothing -> do tid <- forkIO (progressTickerLoop ui st) writeIORef (puTickerRef ui) (Just tid) -- | Stop the progress heartbeat thread. stopProgressTicker :: ProgressUI -> IO () stopProgressTicker ui = do m <- atomicModifyIORef' (puTickerRef ui) (\cur -> (Nothing, cur)) forM_ m killThread -- | Heartbeat loop that redraws when the terminal is resized. progressTickerLoop :: ProgressUI -> ProgressState -> IO () progressTickerLoop ui st = do tid <- myThreadId let loop = do threadDelay progressTickMicros keep <- withProgressLock ui $ do active <- readIORef (psActive st) if M.null active || not (puEnabled ui) then return False else do modifyIORef' (puSpinnerRef ui) (+ 1) progressRefreshUnlocked ui st return True when keep loop loop atomicModifyIORef' (puTickerRef ui) $ \cur -> if cur == Just tid then (Nothing, ()) else (cur, ()) -- | Replace progress lines and redraw the UI. progressSetLines :: ProgressUI -> ProgressState -> [String] -> IO () progressSetLines ui st lines = withProgressLock ui $ do when (puEnabled ui) $ do writeIORef (puLinesRef ui) lines if null lines then stopProgressTicker ui else startProgressTicker ui st progressRenderUnlocked ui -- | Clear active task state and remove any rendered progress lines. progressReset :: ProgressUI -> ProgressState -> IO () progressReset ui st = withProgressLock ui $ do writeIORef (psActive st) M.empty writeIORef (psOrder st) [] writeIORef (puLinesRef ui) [] termProgressClear (puTermProgress ui) when (puEnabled ui) $ do stopProgressTicker ui progressRenderUnlocked ui -- | Mark a task as active in the progress UI. progressStartTask :: ProgressUI -> ProgressState -> TaskKey -> (Int -> BuildLineLayout) -> Maybe Double -> IO () progressStartTask ui st key renderLine mprog = withProgressLock ui $ do now <- getTime Monotonic modifyIORef' (psActive st) (M.insert key (ProgressTask renderLine now (fmap (\x -> max 0 (min 1 x)) mprog))) modifyIORef' (psOrder st) (\xs -> if key `elem` xs then xs else xs ++ [key]) progressRefreshUnlocked ui st -- | Update the rendered line for an active progress task. progressUpdateTask :: ProgressUI -> ProgressState -> TaskKey -> (Int -> BuildLineLayout) -> Maybe Double -> IO () progressUpdateTask ui st key renderLine mprog = withProgressLock ui $ do modifyIORef' (psActive st) (M.adjust (\task -> task { ptRenderLine = renderLine , ptProgress = fmap (\x -> max 0 (min 1 x)) mprog }) key) progressRefreshUnlocked ui st -- | Remove a task from the progress UI. progressDoneTask :: ProgressUI -> ProgressState -> TaskKey -> IO () progressDoneTask ui st key = withProgressLock ui $ do modifyIORef' (psActive st) (M.delete key) modifyIORef' (psOrder st) (filter (/= key)) progressRefreshUnlocked ui st -- | Recompute and render progress lines from active tasks. progressRefreshUnlocked :: ProgressUI -> ProgressState -> IO () progressRefreshUnlocked ui st = do active <- readIORef (psActive st) order <- readIORef (psOrder st) now <- getTime Monotonic (_, _, cols) <- termSizeSync (puTermSize ui) let renderCols = safeLiveWidth cols spinnerPrefixWidth = progressPrefixWidth cols timerMinWidth = length "999.999 s" let progressDone = "\ESC[48;5;24m" progressReset = "\ESC[0m" paintProgressLine mprog line = case mprog of Just frac0 | puUseColor ui -> let n = length line frac = max 0 (min 1 frac0) doneChars = max 0 (min n (floor (frac * fromIntegral n))) (done, todo) = splitAt doneChars line in if null done then todo else progressDone ++ done ++ progressReset ++ todo _ -> line betterLine best Nothing = best betterLine Nothing cand = cand betterLine best@(Just (bestScore, _)) cand@(Just (candScore, _)) | candScore > bestScore = cand | otherwise = best formatLine task = let elapsedPrecise = fmtTimePrecise (diffTimeSpec now (ptStart task)) elapsedCompact = fmtTimeCompact (diffTimeSpec now (ptStart task)) timerWidth = max timerMinWidth (length elapsedPrecise) liveCandidate timerRank timer = let timerCols = if null timer then 0 else 1 + timerWidth bodyWidth = max 0 (renderCols - spinnerPrefixWidth - timerCols) layout = ptRenderLine task bodyWidth body = bllText layout line = body ++ if null timer then "" else " " ++ padLeft timerWidth timer score = ( if bllAligned layout then 1 :: Int else 0 , if bllHasStatus layout then 1 :: Int else 0 , bllLabelCols layout , timerRank ) in if null body || renderCols < spinnerPrefixWidth + length line then Nothing else Just (score, line) line = case foldl' betterLine Nothing [ liveCandidate 2 elapsedPrecise , liveCandidate 1 elapsedCompact , liveCandidate 0 "" ] of Just (_, bestLine) -> bestLine Nothing -> bllText (ptRenderLine task (max 0 (renderCols - spinnerPrefixWidth))) in paintProgressLine (ptProgress task) line lines = [ formatLine task | key <- order, Just task <- [M.lookup key active] ] when (puEnabled ui) $ do writeIORef (puLinesRef ui) lines if null lines then stopProgressTicker ui else startProgressTicker ui st progressRenderUnlocked ui termProgressHeartbeat (puTermProgress ui) -- | Format project labels relative to the root for logs. projectLabel :: FilePath -> FilePath -> String projectLabel root proj = let rel = makeRelative root proj in if rel == "." || ".." `isPrefixOf` rel then takeFileName proj else rel ================================================ FILE: compiler/acton/PkgCommands.hs ================================================ {-# LANGUAGE OverloadedStrings #-} module PkgCommands ( installCommand , uninstallCommand , pkgAddCommand , pkgRemoveCommand , pkgUpgradeCommand , pkgUpdateCommand , pkgSearchCommand , zigPkgAddCommand , zigPkgRemoveCommand , PackageEntry(..) , RepoInfo(..) , githubCloneUrl , isGithubCommitSha , parseGithubRepoUrl , decodePackageIndex , decodeAppPackageIndex , matchesAllTerms ) where import Prelude hiding (readFile, writeFile) import qualified Acton.BuildSpec as BuildSpec import qualified Acton.CommandLineParser as C import Acton.Compile (loadBuildSpec, throwProjectError) import Control.Exception (IOException, SomeException, try, displayException, evaluate) import Control.Concurrent (threadDelay) import Control.Monad (filterM, forM, forM_, unless, when) import Data.Char (isHexDigit, isSpace) import Data.Foldable (toList) import Data.List (dropWhileEnd, isPrefixOf, isSuffixOf, sortOn) import Data.List.Split (splitOn) import Data.Maybe (isJust) import qualified Data.Map as M import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy as BL import qualified Data.Aeson as Aeson import qualified Data.Aeson.Key as AesonKey import qualified Data.Aeson.KeyMap as AesonKM import qualified Data.Text as T import Network.HTTP.Client (Manager, Response, httpLbs, parseRequest, requestHeaders, responseBody, responseStatus) import Network.HTTP.Client.TLS (newTlsManager) import Network.HTTP.Types.Header (Header) import Network.HTTP.Types.Status (statusCode) import System.Directory (Permissions, canonicalizePath, copyFile, createDirectoryIfMissing, doesDirectoryExist, doesFileExist, doesPathExist, getCurrentDirectory, getHomeDirectory, getPermissions, listDirectory, removeFile, setPermissions) import System.Environment (getExecutablePath, lookupEnv) import System.Exit (ExitCode(..)) import System.FilePath ((), takeDirectory) import System.IO (IOMode(ReadMode, WriteMode), hClose, hGetContents, hPutStr, hPutStrLn, hSetEncoding, openFile, stderr, utf8) import System.Process (CreateProcess(cwd), proc, readCreateProcessWithExitCode) import qualified Text.Regex.TDFA as TDFA data PackageEntry = PackageEntry { pkgName :: String , pkgDescription :: String , pkgRepoUrl :: String } deriving (Eq, Show) data PackageIndexEntry = PackageIndexEntry { indexName :: String , indexKinds :: [String] , indexDescription :: String , indexRepoUrl :: String } deriving (Eq, Show) data InstallManifest = InstallManifest { manifestName :: String , manifestRepoUrl :: String , manifestRepoRef :: Maybe String , manifestCommit :: String , manifestHash :: String , manifestSourceDir :: FilePath , manifestBinaries :: [String] } deriving (Eq, Show) data RepoInfo = RepoInfo { repoOwner :: String , repoName :: String , repoRef :: Maybe String } deriving (Eq, Show) installCommand :: C.GlobalOptions -> C.InstallOptions -> IO () installCommand gopts opts = do let appName = C.installName opts repoUrlArg = C.installRepoUrl opts repoRefArg = normalizeMaybe (C.installRepoRef opts) pkgNameArg = C.installPkgName opts validateInstallName appName manager <- newTlsManager token <- resolveGithubToken (normalizeMaybe (C.installGithubToken opts)) repoUrl <- if null repoUrlArg then lookupRepoUrlFromIndexByKind "app" appName pkgNameArg else do ensureGithubUrl "install" repoUrlArg return repoUrlArg archiveUrl <- requireRight =<< resolveGithubArchiveUrl manager token repoUrl repoRefArg commitSha <- requireRight (commitShaFromArchiveUrl archiveUrl) zigExe <- getZigExe archiveHash <- requireRight =<< zigFetchHash zigExe archiveUrl sourceDir <- prepareInstallSource appName repoUrl commitSha unless (C.quiet gopts) $ putStrLn ("Building " ++ appName ++ " with acton build --release") actonExe <- getExecutablePath runProcessChecked (Just sourceDir) actonExe ["build", "--release"] binaries <- discoverBuiltBinaries sourceDir installBuiltBinaries appName repoUrl repoRefArg commitSha archiveHash sourceDir binaries unless (C.quiet gopts) $ do home <- getHomeDirectory let binDir = home ".acton" "bin" putStrLn ("Installed " ++ appName ++ " to " ++ binDir) uninstallCommand :: C.GlobalOptions -> C.UninstallOptions -> IO () uninstallCommand gopts opts = do let appName = C.uninstallName opts validateInstallName appName home <- getHomeDirectory let binDir = home ".acton" "bin" installedDir = home ".acton" "installed" manifestPath = installedDir appName ++ ".json" exists <- doesFileExist manifestPath if not exists then unless (C.quiet gopts) $ putStrLn ("Application package " ++ appName ++ " is not installed. Nothing to do.") else do manifest <- readInstallManifest manifestPath when (manifestName manifest /= appName) $ throwProjectError ("ERROR: Install manifest " ++ manifestPath ++ " belongs to " ++ manifestName manifest) manifests <- readInstallManifests installedDir let otherOwners = M.fromList [ (bin, manifestName other) | other <- manifests , manifestName other /= appName , bin <- manifestBinaries other ] forM_ (manifestBinaries manifest) $ \binName -> case M.lookup binName otherOwners of Just owner -> throwProjectError ("ERROR: Cannot uninstall " ++ appName ++ ": " ++ binName ++ " is also owned by " ++ owner) Nothing -> do let dest = binDir binName pathExists <- doesPathExist dest fileExists <- doesFileExist dest when (pathExists && not fileExists) $ throwProjectError ("ERROR: Cannot uninstall " ++ appName ++ ": " ++ dest ++ " is not a regular file") when fileExists (removeFile dest) removeFile manifestPath unless (C.quiet gopts) $ putStrLn ("Uninstalled " ++ appName) pkgAddCommand :: C.GlobalOptions -> C.PkgAddOptions -> IO () pkgAddCommand _ opts = do let depName = C.pkgAddName opts validateDepName depName cwd <- getCurrentDirectory spec0 <- loadBuildSpec cwd manager <- newTlsManager token <- resolveGithubToken (normalizeMaybe (C.pkgAddGithubToken opts)) let urlArg = C.pkgAddUrl opts repoUrlArg = C.pkgAddRepoUrl opts repoRefArg = normalizeMaybe (C.pkgAddRepoRef opts) pkgNameArg = C.pkgAddPkgName opts (depUrl, depRepoUrl, depRepoRef) <- decideUrl manager token depName urlArg repoUrlArg repoRefArg pkgNameArg zigExe <- getZigExe hash <- requireRight =<< zigFetchHash zigExe depUrl let (spec1, msgs) = upsertPkgDep spec0 depName depUrl hash depRepoUrl depRepoRef mapM_ putStrLn msgs writeBuildSpec spec1 where decideUrl manager token depName urlArg repoUrlArg repoRefArg pkgNameArg | not (null urlArg) && not (null repoUrlArg) = throwProjectError "ERROR: Specify either --url or --repo-url, not both." | not (null urlArg) = return (urlArg, Nothing, Nothing) | not (null repoUrlArg) = do ensureGithubUrl "pkg add" repoUrlArg archive <- requireRight =<< resolveGithubArchiveUrl manager token repoUrlArg repoRefArg return (archive, Just repoUrlArg, repoRefArg) | otherwise = do repoUrl <- lookupRepoUrlFromIndex depName pkgNameArg ensureGithubUrl "pkg add" repoUrl archive <- requireRight =<< resolveGithubArchiveUrl manager token repoUrl repoRefArg return (archive, Just repoUrl, repoRefArg) pkgRemoveCommand :: C.GlobalOptions -> C.PkgRemoveOptions -> IO () pkgRemoveCommand _ opts = do let depName = C.pkgRemoveName opts validateDepName depName cwd <- getCurrentDirectory spec <- loadBuildSpec cwd let deps = BuildSpec.dependencies spec if M.member depName deps then do putStrLn ("Removed package dependency " ++ depName) let spec' = spec { BuildSpec.dependencies = M.delete depName deps } writeBuildSpec spec' else putStrLn ("Dependency " ++ depName ++ " not found in build configuration. Nothing to do.") pkgUpgradeCommand :: C.GlobalOptions -> C.PkgUpgradeOptions -> IO () pkgUpgradeCommand _ opts = do cwd <- getCurrentDirectory spec <- loadBuildSpec cwd let deps = BuildSpec.dependencies spec manager <- newTlsManager token <- resolveGithubToken (normalizeMaybe (C.pkgUpgradeGithubToken opts)) resolved <- mapM (resolveDep manager token) (M.toList deps) let newUrls = M.fromList [ (n,u) | Just (n,u) <- resolved ] if M.null newUrls then putStrLn "No dependencies to upgrade" else do zigExe <- getZigExe hashes <- mapM (fetchHash zigExe deps) (M.toList newUrls) let newHashes = M.fromList [ (n,h) | Just (n,h) <- hashes ] if M.null newHashes then putStrLn "No dependencies to upgrade" else do let (spec', updated) = applyUpgrades spec newUrls newHashes if updated then do putStrLn "Wrote changes to Build.act" writeBuildSpec spec' else putStrLn "No changes to Build.act" where resolveDep manager token (depName, dep) = case BuildSpec.repo_url dep of Nothing -> do hPutStrLn stderr (depName ++ " - skipping upgrade: repo_url not set") return Nothing Just repoUrl -> do if not (isGithubUrl repoUrl) then do hPutStrLn stderr (depName ++ " - skipping upgrade: Unsupported git forge URL for " ++ depName ++ ": " ++ repoUrl ++ " only https://github.com is supported") return Nothing else do putStrLn (depName ++ " - fetching ref from " ++ repoUrl) res <- resolveGithubArchiveUrl manager token repoUrl (BuildSpec.repo_ref dep) case res of Left err -> do hPutStrLn stderr ("Error fetching ref for " ++ depName ++ ": " ++ err) return Nothing Right url -> return (Just (depName, url)) fetchHash zigExe deps (depName, url) = case M.lookup depName deps of Nothing -> return Nothing Just dep -> case BuildSpec.url dep of Just oldUrl | oldUrl == url -> return Nothing _ -> do res <- zigFetchHash zigExe url case res of Left err -> do putStrLn ("Error fetching updated hash for " ++ depName ++ " " ++ err) return Nothing Right h -> return (Just (depName, h)) applyUpgrades spec newUrls newHashes = let deps = BuildSpec.dependencies spec (deps', updated) = M.foldlWithKey' applyOne (deps, False) deps in (spec { BuildSpec.dependencies = deps' }, updated) where applyOne (acc, changed) depName dep = case (M.lookup depName newUrls, M.lookup depName newHashes) of (Just newUrl, Just newHash) -> if BuildSpec.url dep /= Just newUrl || BuildSpec.hash dep /= Just newHash then let dep' = dep { BuildSpec.url = Just newUrl, BuildSpec.hash = Just newHash } in (M.insert depName dep' acc, True) else (acc, changed) _ -> (acc, changed) pkgUpdateCommand :: C.GlobalOptions -> IO () pkgUpdateCommand _ = do let indexUrl = "https://actonlang.github.io/package-index/index.json" manager <- newTlsManager body <- requireRightWith ("ERROR: Failed to download package index from " ++ indexUrl ++ ": ") =<< httpGet manager [] indexUrl home <- getHomeDirectory let indexDir = home ".cache" "acton" indexPath = indexDir "package-index.json" createDirectoryIfMissing True indexDir BL.writeFile indexPath body putStrLn ("Updated package index at " ++ indexPath) pkgSearchCommand :: C.GlobalOptions -> C.PkgSearchOptions -> IO () pkgSearchCommand _ opts = do home <- getHomeDirectory let indexPath = home ".cache" "acton" "package-index.json" exists <- doesFileExist indexPath unless exists $ throwProjectError ("No package index found at " ++ indexPath ++ "\nHINT: Run 'acton pkg update' to create or refresh it.") content <- readIndexFile indexPath pkgs <- requireRight (decodePackageIndex content) let terms = C.pkgSearchTerms opts regexes <- compileTerms terms let matched = filter (matchesAllRegexes regexes) pkgs let printPkg pkg = do putStrLn (pkgName pkg) putStrLn (" " ++ pkgDescription pkg) putStrLn (" " ++ pkgRepoUrl pkg) putStrLn "" if null matched then putStrLn "No packages matched your search." else forM_ (sortOn pkgName matched) printPkg zigPkgAddCommand :: C.GlobalOptions -> C.ZigPkgAddOptions -> IO () zigPkgAddCommand _ opts = do let depName = C.zigPkgAddName opts depUrl = C.zigPkgAddUrl opts depArtifacts = C.zigPkgAddArtifacts opts validateDepName depName cwd <- getCurrentDirectory spec0 <- loadBuildSpec cwd zigExe <- getZigExe hash <- requireRight =<< zigFetchHash zigExe depUrl let (spec1, msgs) = upsertZigDep spec0 depName depUrl hash depArtifacts mapM_ putStrLn msgs writeBuildSpec spec1 zigPkgRemoveCommand :: C.GlobalOptions -> C.ZigPkgRemoveOptions -> IO () zigPkgRemoveCommand _ opts = do let depName = C.zigPkgRemoveName opts validateDepName depName cwd <- getCurrentDirectory spec <- loadBuildSpec cwd let deps = BuildSpec.zig_dependencies spec if M.member depName deps then do putStrLn ("Removed Zig package dependency " ++ depName) let spec' = spec { BuildSpec.zig_dependencies = M.delete depName deps } writeBuildSpec spec' else putStrLn ("Zig dependency " ++ depName ++ " not found in build configuration. Nothing to do.") prepareInstallSource :: String -> String -> String -> IO FilePath prepareInstallSource appName repoUrl commitSha = do home <- getHomeDirectory let appsDir = home ".cache" "acton" "apps" sourceDir = appsDir appName ++ "-" ++ take 12 commitSha cloneUrl = githubCloneUrl repoUrl createDirectoryIfMissing True appsDir exists <- doesDirectoryExist sourceDir unless exists $ runProcessChecked Nothing "git" ["clone", "--quiet", "--no-checkout", cloneUrl, sourceDir] runProcessChecked (Just sourceDir) "git" ["fetch", "--quiet", "origin", commitSha] runProcessChecked (Just sourceDir) "git" ["checkout", "--quiet", "--force", "--detach", commitSha] runProcessChecked (Just sourceDir) "git" ["clean", "-fdx", "--quiet"] return sourceDir githubCloneUrl :: String -> String githubCloneUrl = takeWhile (/= '#') discoverBuiltBinaries :: FilePath -> IO [(FilePath, String, Permissions)] discoverBuiltBinaries sourceDir = do let binDir = sourceDir "out" "bin" exists <- doesDirectoryExist binDir unless exists $ throwProjectError ("ERROR: Build produced no out/bin directory in " ++ sourceDir) names <- listDirectory binDir files <- filterM (\name -> doesFileExist (binDir name)) names when (null files) $ throwProjectError ("ERROR: Build produced no binaries in " ++ binDir) forM (sortOn id files) $ \name -> do let src = binDir name perms <- getPermissions src return (src, name, perms) installBuiltBinaries :: String -> String -> Maybe String -> String -> String -> FilePath -> [(FilePath, String, Permissions)] -> IO () installBuiltBinaries appName repoUrl repoRefArg commitSha archiveHash sourceDir binaries = do home <- getHomeDirectory let actonDir = home ".acton" binDir = actonDir "bin" installedDir = actonDir "installed" manifestPath = installedDir appName ++ ".json" createDirectoryIfMissing True binDir createDirectoryIfMissing True installedDir manifests <- readInstallManifests installedDir let ownerByBin = M.fromList [ (bin, manifestName manifest) | manifest <- manifests , bin <- manifestBinaries manifest ] oldManifest = findManifest appName manifests forM_ binaries $ \(_, binName, _) -> do let dest = binDir binName case M.lookup binName ownerByBin of Just owner | owner /= appName -> throwProjectError ("ERROR: Cannot install " ++ appName ++ ": " ++ dest ++ " is owned by " ++ owner) _ -> return () exists <- doesPathExist dest when (exists && M.lookup binName ownerByBin == Nothing) $ throwProjectError ("ERROR: Cannot install " ++ appName ++ ": " ++ dest ++ " already exists and is not managed by Acton") forM_ binaries $ \(src, binName, perms) -> do let dest = binDir binName copyFile src dest setPermissions dest perms case oldManifest of Nothing -> return () Just manifest -> do let newBins = map (\(_, binName, _) -> binName) binaries staleBins = filter (`notElem` newBins) (manifestBinaries manifest) forM_ staleBins $ \binName -> do let dest = binDir binName exists <- doesFileExist dest when exists (removeFile dest) writeInstallManifest manifestPath InstallManifest { manifestName = appName , manifestRepoUrl = repoUrl , manifestRepoRef = repoRefArg , manifestCommit = commitSha , manifestHash = archiveHash , manifestSourceDir = sourceDir , manifestBinaries = map (\(_, binName, _) -> binName) binaries } findManifest :: String -> [InstallManifest] -> Maybe InstallManifest findManifest appName = go where go [] = Nothing go (manifest:rest) | manifestName manifest == appName = Just manifest | otherwise = go rest readInstallManifests :: FilePath -> IO [InstallManifest] readInstallManifests installedDir = do exists <- doesDirectoryExist installedDir if not exists then return [] else do names <- listDirectory installedDir let jsonFiles = filter (".json" `isSuffixOf`) names mapM (readInstallManifest . (installedDir )) jsonFiles readInstallManifest :: FilePath -> IO InstallManifest readInstallManifest path = do content <- readIndexFile path case Aeson.eitherDecode content of Left err -> throwProjectError ("ERROR: Failed to parse install manifest " ++ path ++ ": " ++ err) Right (Aeson.Object obj) -> case ( lookupString "name" obj , lookupString "repo_url" obj , lookupString "commit" obj , lookupString "hash" obj , lookupString "source_dir" obj , lookupStringList "binaries" obj ) of (Just n, Just ru, Just c, Just h, Just src, Just bins) -> return InstallManifest { manifestName = n , manifestRepoUrl = ru , manifestRepoRef = lookupString "repo_ref" obj , manifestCommit = c , manifestHash = h , manifestSourceDir = src , manifestBinaries = bins } _ -> throwProjectError ("ERROR: Invalid install manifest " ++ path) Right _ -> throwProjectError ("ERROR: Invalid install manifest " ++ path) writeInstallManifest :: FilePath -> InstallManifest -> IO () writeInstallManifest path manifest = BL.writeFile path (Aeson.encode (Aeson.object (manifestFields manifest))) where manifestFields manifest = [ "name" Aeson..= manifestName manifest , "repo_url" Aeson..= manifestRepoUrl manifest , "commit" Aeson..= manifestCommit manifest , "hash" Aeson..= manifestHash manifest , "source_dir" Aeson..= manifestSourceDir manifest , "binaries" Aeson..= manifestBinaries manifest ] ++ repoRefField manifest repoRefField manifest = case manifestRepoRef manifest of Nothing -> [] Just repoRef -> ["repo_ref" Aeson..= repoRef] upsertPkgDep :: BuildSpec.BuildSpec -> String -> String -> String -> Maybe String -> Maybe String -> (BuildSpec.BuildSpec, [String]) upsertPkgDep spec depName depUrl depHash depRepoUrl depRepoRef = case M.lookup depName (BuildSpec.dependencies spec) of Just dep -> let (msgs1, dep1) = updateUrl dep (msgs2, dep2) = updateHash dep1 dep3 = case depRepoUrl of Nothing -> dep2 Just ru -> dep2 { BuildSpec.repo_url = Just ru, BuildSpec.repo_ref = depRepoRef } deps' = M.insert depName dep3 (BuildSpec.dependencies spec) in (spec { BuildSpec.dependencies = deps' }, msgs1 ++ msgs2) Nothing -> let newDep = BuildSpec.PkgDep { BuildSpec.url = Just depUrl , BuildSpec.hash = Just depHash , BuildSpec.path = Nothing , BuildSpec.repo_url = depRepoUrl , BuildSpec.repo_ref = depRepoRef } deps' = M.insert depName newDep (BuildSpec.dependencies spec) in (spec { BuildSpec.dependencies = deps' }, ["Added new package dependency " ++ depName ++ " with hash " ++ depHash]) where updateUrl dep = case BuildSpec.url dep of Just old | old /= depUrl -> (["Updated existing dependency " ++ depName ++ " with new URL " ++ depUrl ++ " (old " ++ showMaybe (Just old) ++ ")"], dep { BuildSpec.url = Just depUrl }) Nothing -> (["Updated existing dependency " ++ depName ++ " with new URL " ++ depUrl ++ " (old " ++ showMaybe Nothing ++ ")"], dep { BuildSpec.url = Just depUrl }) _ -> ([], dep) updateHash dep = case BuildSpec.hash dep of Just old | old == depHash -> (["Dependency " ++ depName ++ " is already up to date, hash: " ++ depHash], dep) Just old -> (["Updated existing dependency " ++ depName ++ " with new hash " ++ depHash ++ " (old " ++ showMaybe (Just old) ++ ")"], dep { BuildSpec.hash = Just depHash }) Nothing -> (["Updated existing dependency " ++ depName ++ " with new hash " ++ depHash ++ " (old " ++ showMaybe Nothing ++ ")"], dep { BuildSpec.hash = Just depHash }) upsertZigDep :: BuildSpec.BuildSpec -> String -> String -> String -> [String] -> (BuildSpec.BuildSpec, [String]) upsertZigDep spec depName depUrl depHash depArtifacts = case M.lookup depName (BuildSpec.zig_dependencies spec) of Just dep -> let (msgs1, dep1) = updateUrl dep (msgs2, dep2) = updateHash dep1 deps' = M.insert depName dep2 (BuildSpec.zig_dependencies spec) in (spec { BuildSpec.zig_dependencies = deps' }, msgs1 ++ msgs2) Nothing -> let newDep = BuildSpec.ZigDep { BuildSpec.zurl = Just depUrl , BuildSpec.zhash = Just depHash , BuildSpec.zpath = Nothing , BuildSpec.options = M.empty , BuildSpec.artifacts = depArtifacts } deps' = M.insert depName newDep (BuildSpec.zig_dependencies spec) in (spec { BuildSpec.zig_dependencies = deps' }, ["Added new Zig package dependency " ++ depName ++ " with hash " ++ depHash]) where updateUrl dep = case BuildSpec.zurl dep of Just old | old /= depUrl -> (["Updated existing dependency " ++ depName ++ " with new URL " ++ depUrl ++ " (old " ++ showMaybe (Just old) ++ ")"], dep { BuildSpec.zurl = Just depUrl }) Nothing -> (["Updated existing dependency " ++ depName ++ " with new URL " ++ depUrl ++ " (old " ++ showMaybe Nothing ++ ")"], dep { BuildSpec.zurl = Just depUrl }) _ -> ([], dep) updateHash dep = case BuildSpec.zhash dep of Just old | old == depHash -> (["Dependency " ++ depName ++ " is already up to date, hash: " ++ depHash], dep) Just old -> (["Updated existing dependency " ++ depName ++ " with new hash " ++ depHash ++ " (old " ++ showMaybe (Just old) ++ ")"], dep { BuildSpec.zhash = Just depHash }) Nothing -> (["Updated existing dependency " ++ depName ++ " with new hash " ++ depHash ++ " (old " ++ showMaybe Nothing ++ ")"], dep { BuildSpec.zhash = Just depHash }) writeBuildSpec :: BuildSpec.BuildSpec -> IO () writeBuildSpec spec = do buildActExists <- doesFileExist "Build.act" if not buildActExists then throwProjectError "Build.act not found in current directory" else do content <- readFile "Build.act" let jsonDoc = BuildSpec.encodeBuildSpecJSON spec case BuildSpec.updateBuildActFromJSON content jsonDoc of Left err -> throwProjectError ("Failed to update Build.act: \n" ++ err) Right updated -> writeFile "Build.act" updated lookupRepoUrlFromIndex :: String -> String -> IO String lookupRepoUrlFromIndex = lookupRepoUrlFromIndexByKind "library" lookupRepoUrlFromIndexByKind :: String -> String -> String -> IO String lookupRepoUrlFromIndexByKind wantedKind depName pkgNameArg = do home <- getHomeDirectory let indexPath = home ".cache" "acton" "package-index.json" exists <- doesFileExist indexPath unless exists $ throwProjectError ("ERROR: Package index not found at " ++ indexPath ++ "\nHINT: Run: acton pkg update") content <- readIndexFile indexPath entries <- requireRight (decodePackageIndexEntries content) let pkgName = if null pkgNameArg then depName else pkgNameArg matchEntry e = indexName e == pkgName case filter matchEntry entries of [] -> throwProjectError ("ERROR: Package " ++ pkgName ++ " not found in package index") entriesForName -> case filter (elem wantedKind . indexKinds) entriesForName of (entry:_) -> return (indexRepoUrl entry) [] -> throwProjectError ("ERROR: Package " ++ pkgName ++ " is not an acton-" ++ wantedKind ++ " package") decodePackageIndex :: BL.ByteString -> Either String [PackageEntry] decodePackageIndex = decodePackageIndexByKind "library" decodeAppPackageIndex :: BL.ByteString -> Either String [PackageEntry] decodeAppPackageIndex = decodePackageIndexByKind "app" decodePackageIndexByKind :: String -> BL.ByteString -> Either String [PackageEntry] decodePackageIndexByKind wantedKind content = do entries <- decodePackageIndexEntries content let pkgs = [ PackageEntry n d r | PackageIndexEntry n ks d r <- entries , wantedKind `elem` ks ] return pkgs decodePackageIndexEntries :: BL.ByteString -> Either String [PackageIndexEntry] decodePackageIndexEntries content = case Aeson.eitherDecode content of Left err -> Left ("ERROR: Failed to parse package index JSON: " ++ err) Right (Aeson.Object obj) -> case AesonKM.lookup (AesonKey.fromString "packages") obj of Just (Aeson.Array arr) -> mapM parseEntry (zip [0 :: Int ..] (toList arr)) _ -> Left "ERROR: Invalid package index: top-level 'packages' list missing or wrong type" Right _ -> Left "ERROR: Invalid package index: top-level 'packages' list missing or wrong type" where parseEntry (idx, Aeson.Object o) = case ( lookupString "name" o , lookupStringList "kinds" o , lookupString "description" o , lookupString "repo_url" o ) of (Just n, Just ks, Just d, Just r) | null ks -> Left ("ERROR: Invalid package index entry " ++ show idx ++ ": expected at least one kind") | all validPackageKind ks -> Right (PackageIndexEntry n ks d r) | otherwise -> Left ("ERROR: Invalid package index entry " ++ show idx ++ ": unsupported kind in 'kinds'") _ -> Left ("ERROR: Invalid package index entry " ++ show idx ++ ": expected name, kinds, description, and repo_url") parseEntry (idx, _) = Left ("ERROR: Invalid package index entry " ++ show idx ++ ": expected object") validPackageKind k = k == "library" || k == "app" matchesAllTerms :: [String] -> PackageEntry -> IO Bool matchesAllTerms terms pkg = do regexes <- compileTerms terms return (matchesAllRegexes regexes pkg) compileTerms :: [String] -> IO [TDFA.Regex] compileTerms terms = mapM compileRegex (filter (not . null) terms) compileRegex :: String -> IO TDFA.Regex compileRegex pattern = do res <- try (evaluate (TDFA.makeRegex ("^" ++ pattern) :: TDFA.Regex)) :: IO (Either SomeException TDFA.Regex) case res of Left err -> throwProjectError ("ERROR: Invalid regex '" ++ pattern ++ "': " ++ displayException err) Right re -> return re matchesAllRegexes :: [TDFA.Regex] -> PackageEntry -> Bool matchesAllRegexes regexes pkg = let haystack = pkgName pkg ++ " " ++ pkgDescription pkg ++ " " ++ pkgRepoUrl pkg in all (\re -> isJust (TDFA.matchOnceText re haystack)) regexes parseGithubRepoUrl :: String -> Either String RepoInfo parseGithubRepoUrl url = case stripPrefixGithub url of Nothing -> Left "Unsupported git forge URL" Just rest -> do let (pathPart, refPart) = break (== '#') rest refVal = if null refPart then Nothing else Just (drop 1 refPart) path = dropWhile (== '/') (dropGitSuffix pathPart) parts = filter (not . null) (splitOn "/" path) if length parts < 2 then Left "No path in URL" else do let owner = parts !! (length parts - 2) repo = parts !! (length parts - 1) Right (RepoInfo owner repo refVal) where stripPrefixGithub s | prefix `isPrefixOf` s = Just (drop (length prefix) s) | otherwise = Nothing where prefix = "https://github.com" :: String dropGitSuffix s = if ".git" `isSuffixOf` s then take (length s - 4) s else s commitShaFromArchiveUrl :: String -> Either String String commitShaFromArchiveUrl url = case splitOn "/archive/" url of [_, archiveName] | ".zip" `isSuffixOf` archiveName -> let zipSuffix = ".zip" :: String sha = take (length archiveName - length zipSuffix) archiveName in if null sha then Left ("Unable to determine commit SHA from " ++ url) else Right sha _ -> Left ("Unable to determine commit SHA from " ++ url) resolveGithubArchiveUrl :: Manager -> Maybe String -> String -> Maybe String -> IO (Either String String) resolveGithubArchiveUrl manager token repoUrl repoRefArg = do case parseGithubRepoUrl repoUrl of Left err -> return (Left err) Right info -> do ref <- selectRef manager token info repoRefArg case ref of Left err -> return (Left err) Right refName -> do sha <- fetchRefSha manager token info refName case sha of Left err -> return (Left err) Right shaVal -> return (Right ("https://github.com/" ++ repoOwner info ++ "/" ++ repoName info ++ "/archive/" ++ shaVal ++ ".zip")) where selectRef manager token info refArg = case refArg of Just refVal -> case repoRef info of Just urlRef | urlRef /= refVal -> return (Left "Ref mismatch") _ -> return (Right refVal) Nothing -> case repoRef info of Just urlRef -> return (Right urlRef) Nothing -> fetchDefaultBranch manager token info fetchDefaultBranch :: Manager -> Maybe String -> RepoInfo -> IO (Either String String) fetchDefaultBranch manager token info = do let url = "https://api.github.com/repos/" ++ repoOwner info ++ "/" ++ repoName info obj <- fetchGithubObject manager token url case obj of Left err -> return (Left err) Right o -> case lookupMessage o of Just msg -> return (Left ("Unable to retrieve branch information: " ++ msg)) Nothing -> case lookupString "default_branch" o of Just branch -> return (Right branch) Nothing -> return (Left ("No default branch:" ++ B.unpack (BL.toStrict (Aeson.encode (Aeson.Object o))))) fetchRefSha :: Manager -> Maybe String -> RepoInfo -> String -> IO (Either String String) fetchRefSha manager token info refName = do if isGithubCommitSha refName then return (Right refName) else do branch <- fetchGitRefSha manager token info ("heads/" ++ refName) case branch of Right shaVal -> return (Right shaVal) Left branchErr -> do tag <- fetchGitRefSha manager token info ("tags/" ++ refName) case tag of Right shaVal -> return (Right shaVal) Left tagErr -> do commit <- fetchCommitSha manager token info refName case commit of Right shaVal -> return (Right shaVal) Left commitErr -> return (Left ("Unable to resolve ref '" ++ refName ++ "' as branch, tag, or commit SHA: " ++ branchErr ++ "; " ++ tagErr ++ "; " ++ commitErr)) isGithubCommitSha :: String -> Bool isGithubCommitSha refName = length refName == 40 && all isHexDigit refName fetchGitRefSha :: Manager -> Maybe String -> RepoInfo -> String -> IO (Either String String) fetchGitRefSha manager token info refName = do let url = "https://api.github.com/repos/" ++ repoOwner info ++ "/" ++ repoName info ++ "/git/refs/" ++ refName obj <- fetchGithubObject manager token url case obj of Left err -> return (Left err) Right o -> case lookupMessage o of Just msg -> return (Left ("Unable to retrieve ref information: " ++ msg)) Nothing -> case AesonKM.lookup (AesonKey.fromString "object") o of Just (Aeson.Object obj) -> case (lookupString "type" obj, lookupString "sha" obj) of (Just objType, Just shaVal) -> resolveGitObjectSha manager token info objType shaVal (_, Nothing) -> return (Left "No SHA") (Nothing, _) -> return (Left "No object type") _ -> return (Left "No object") resolveGitObjectSha :: Manager -> Maybe String -> RepoInfo -> String -> String -> IO (Either String String) resolveGitObjectSha manager token info objType shaVal | objType == "commit" = return (Right shaVal) | objType == "tag" = fetchTagTargetSha manager token info shaVal 5 | otherwise = return (Left ("Unsupported Git object type " ++ objType)) fetchTagTargetSha :: Manager -> Maybe String -> RepoInfo -> String -> Int -> IO (Either String String) fetchTagTargetSha _ _ _ _ 0 = return (Left "Annotated tag nesting too deep") fetchTagTargetSha manager token info tagSha depth = do let url = "https://api.github.com/repos/" ++ repoOwner info ++ "/" ++ repoName info ++ "/git/tags/" ++ tagSha obj <- fetchGithubObject manager token url case obj of Left err -> return (Left err) Right o -> case lookupMessage o of Just msg -> return (Left ("Unable to retrieve tag information: " ++ msg)) Nothing -> case AesonKM.lookup (AesonKey.fromString "object") o of Just (Aeson.Object target) -> case (lookupString "type" target, lookupString "sha" target) of (Just objType, Just shaVal) | objType == "tag" -> fetchTagTargetSha manager token info shaVal (depth - 1) | otherwise -> resolveGitObjectSha manager token info objType shaVal (_, Nothing) -> return (Left "No tag target SHA") (Nothing, _) -> return (Left "No tag target object type") _ -> return (Left "No tag target object") fetchCommitSha :: Manager -> Maybe String -> RepoInfo -> String -> IO (Either String String) fetchCommitSha manager token info refName = do let url = "https://api.github.com/repos/" ++ repoOwner info ++ "/" ++ repoName info ++ "/commits/" ++ refName obj <- fetchGithubObject manager token url case obj of Left err -> return (Left err) Right o -> case lookupMessage o of Just msg -> return (Left ("Unable to retrieve commit information: " ++ msg)) Nothing -> case lookupString "sha" o of Just shaVal -> return (Right shaVal) Nothing -> return (Left "No commit SHA") fetchGithubObject :: Manager -> Maybe String -> String -> IO (Either String Aeson.Object) fetchGithubObject manager token url = do let authHeader = case token of Just t -> [("Authorization", B.pack ("Bearer " ++ t))] Nothing -> [] headers = ("Accept", "application/vnd.github.v3+json") : authHeader body <- httpGet manager headers url case body of Left err -> return (Left ("Failed to download " ++ url ++ ": " ++ err)) Right bs -> case Aeson.eitherDecode bs of Left err -> return (Left err) Right (Aeson.Object obj) -> return (Right obj) Right _ -> return (Left "Invalid JSON response") httpGet :: Manager -> [Header] -> String -> IO (Either String BL.ByteString) httpGet manager extraHeaders url = do req0 <- parseRequest url let headers = ("User-Agent", "acton") : extraHeaders req = req0 { requestHeaders = headers ++ requestHeaders req0 } let maxAttempts = 10 baseDelay = 500000 maxDelay = 120000000 let go attempt delay = do res <- try (httpLbs req manager) :: IO (Either SomeException (Response BL.ByteString)) case res of Left err -> retryOrFail attempt delay (displayException err) Right response -> do let status = statusCode (responseStatus response) body = responseBody response if status >= 200 && status < 300 then return (Right body) else if shouldRetry status then retryOrFail attempt delay (httpErrorMessage status body) else return (Left (httpErrorMessage status body)) retryOrFail attempt delay errMsg | attempt >= maxAttempts = return (Left errMsg) | otherwise = do threadDelay delay go (attempt + 1) (min maxDelay (delay * 2)) go 1 baseDelay where shouldRetry status = status == 403 || status == 429 || status >= 500 httpErrorMessage status body = let raw = trim (B.unpack (BL.toStrict body)) clipped = take 200 raw suffix = if length raw > length clipped then "..." else "" detail = if null clipped then "" else ": " ++ clipped ++ suffix in "HTTP " ++ show status ++ detail lookupString :: String -> Aeson.Object -> Maybe String lookupString key obj = case AesonKM.lookup (AesonKey.fromString key) obj of Just (Aeson.String s) -> Just (T.unpack s) _ -> Nothing lookupStringList :: String -> Aeson.Object -> Maybe [String] lookupStringList key obj = case AesonKM.lookup (AesonKey.fromString key) obj of Just (Aeson.Array arr) -> mapM valueString (toList arr) _ -> Nothing where valueString (Aeson.String s) = Just (T.unpack s) valueString _ = Nothing lookupMessage :: Aeson.Object -> Maybe String lookupMessage = lookupString "message" normalizeMaybe :: String -> Maybe String normalizeMaybe s | null s = Nothing | otherwise = Just s resolveGithubToken :: Maybe String -> IO (Maybe String) resolveGithubToken tokenOpt = do envToken <- lookupEnv "GITHUB_TOKEN" return (selectToken tokenOpt envToken) where normalizeToken Nothing = Nothing normalizeToken (Just s) = normalizeMaybe (trim s) selectToken opt env = case normalizeToken opt of Just token -> Just token Nothing -> normalizeToken env showMaybe :: Maybe String -> String showMaybe = maybe "None" id isGithubUrl :: String -> Bool isGithubUrl url = "https://github.com" `isPrefixOf` url ensureGithubUrl :: String -> String -> IO () ensureGithubUrl cmd url = unless (isGithubUrl url) $ throwProjectError ("ERROR: Unsupported git forge URL for " ++ cmd ++ ": " ++ url ++ " only https://github.com is supported") requireRight :: Either String a -> IO a requireRight (Left err) = throwProjectError err requireRight (Right val) = return val requireRightWith :: String -> Either String a -> IO a requireRightWith prefix (Left err) = throwProjectError (prefix ++ err) requireRightWith _ (Right val) = return val readIndexFile :: FilePath -> IO BL.ByteString readIndexFile path = do res <- try (BL.readFile path) :: IO (Either IOException BL.ByteString) case res of Left err -> throwProjectError ("ERROR: Failed to read package index at " ++ path ++ ": " ++ displayException err) Right content -> return content zigFetchHash :: FilePath -> String -> IO (Either String String) zigFetchHash zigExe depUrl = do home <- getHomeDirectory let globalCache = home ".cache" "acton" "zig-global-cache" createDirectoryIfMissing True globalCache let cmd = proc zigExe ["fetch", "--global-cache-dir", globalCache, depUrl] let maxAttempts = 10 baseDelay = 500000 maxDelay = 120000000 let go attempt delay = do res <- try (readCreateProcessWithExitCode cmd "") :: IO (Either SomeException (ExitCode, String, String)) case res of Left err -> retryOrFail attempt delay ("Error fetching " ++ displayException err) Right (ExitSuccess, out, _) -> return (Right (trim out)) Right (ExitFailure _, _, err) -> retryOrFail attempt delay ("Error fetching " ++ trim err) retryOrFail attempt delay errMsg | attempt >= maxAttempts = return (Left errMsg) | otherwise = do threadDelay delay go (attempt + 1) (min maxDelay (delay * 2)) go 1 baseDelay runProcessChecked :: Maybe FilePath -> FilePath -> [String] -> IO () runProcessChecked cwdOpt exe args = do res <- try (readCreateProcessWithExitCode command "") :: IO (Either SomeException (ExitCode, String, String)) case res of Left err -> throwProjectError ("ERROR: Failed to run " ++ unwords (exe:args) ++ ": " ++ displayException err) Right (ExitSuccess, _, _) -> return () Right (ExitFailure code, out, err) -> throwProjectError $ "ERROR: Command failed (" ++ show code ++ "): " ++ unwords (exe:args) ++ renderOutput "stdout" out ++ renderOutput "stderr" err where command = (proc exe args) { cwd = cwdOpt } renderOutput label output = let body = trim output in if null body then "" else "\n" ++ label ++ ":\n" ++ body getZigExe :: IO FilePath getZigExe = do execDir <- takeDirectory <$> getExecutablePath sysPath <- canonicalizePath (execDir "..") return (sysPath "zig" "zig") validateDepName :: String -> IO () validateDepName name = unless (isValidDepName name) $ throwProjectError ("Invalid dependency name '" ++ name ++ "', must start with a letter and only contain letters, numbers and underscores") validateInstallName :: String -> IO () validateInstallName name = unless (isValidInstallName name) $ throwProjectError ("Invalid application package name '" ++ name ++ "', must only contain letters, numbers, '.', '_' and '-'") isValidInstallName :: String -> Bool isValidInstallName name = not (null name) && name /= "." && name /= ".." && all isValidInstallNameChar name isValidInstallNameChar :: Char -> Bool isValidInstallNameChar c = isAsciiAlphaNumUnderscore c || c == '-' || c == '.' isValidDepName :: String -> Bool isValidDepName [] = False isValidDepName (c:cs) = isAsciiAlpha c && all isAsciiAlphaNumUnderscore cs isAsciiAlpha :: Char -> Bool isAsciiAlpha c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') isAsciiAlphaNumUnderscore :: Char -> Bool isAsciiAlphaNumUnderscore c = isAsciiAlpha c || (c >= '0' && c <= '9') || c == '_' trim :: String -> String trim = dropWhileEnd isSpace . dropWhile isSpace readFile :: FilePath -> IO String readFile f = do h <- openFile f ReadMode hSetEncoding h utf8 c <- hGetContents h return c writeFile :: FilePath -> String -> IO () writeFile f c = do h <- openFile f WriteMode hSetEncoding h utf8 hPutStr h c hClose h ================================================ FILE: compiler/acton/TerminalProgress.hs ================================================ module TerminalProgress ( TermProgress , initTermProgress , termProgressEnabled , termProgressPercent , termProgressIndeterminate , termProgressClear , termProgressHeartbeat ) where import qualified Acton.CommandLineParser as C import Control.Monad (when) import Data.Char (toLower) import Data.IORef import System.Environment (lookupEnv) import System.IO (hFlush, hIsTerminalDevice, stdout) import System.Clock (Clock(Monotonic), TimeSpec, getTime, toNanoSecs) data TermProgress = TermProgress { tpEnabled :: Bool , tpLastRef :: IORef (Maybe (Int, Maybe Int)) , tpLastSentRef :: IORef (Maybe TimeSpec) } termProgressEnabled :: TermProgress -> Bool termProgressEnabled = tpEnabled initTermProgress :: C.GlobalOptions -> IO TermProgress initTermProgress gopts = do tty <- hIsTerminalDevice stdout env <- lookupEnv "ACTON_OSC_PROGRESS" let envSetting = env >>= parseBool enabledByTty = (tty || C.tty gopts) && not (C.quiet gopts) && not (C.noProgress gopts) enabled = if C.noProgress gopts then False else case envSetting of Just True -> not (C.quiet gopts) Just False -> False Nothing -> enabledByTty lastRef <- newIORef Nothing lastSentRef <- newIORef Nothing return TermProgress { tpEnabled = enabled , tpLastRef = lastRef , tpLastSentRef = lastSentRef } parseBool :: String -> Maybe Bool parseBool raw = case map toLower raw of "1" -> Just True "true" -> Just True "yes" -> Just True "on" -> Just True "0" -> Just False "false" -> Just False "no" -> Just False "off" -> Just False _ -> Nothing termProgressPercent :: TermProgress -> Int -> IO () termProgressPercent tp pct = termProgressSet tp 1 (Just pct) termProgressIndeterminate :: TermProgress -> IO () termProgressIndeterminate tp = termProgressSet tp 3 Nothing termProgressClear :: TermProgress -> IO () termProgressClear tp = termProgressSet tp 0 Nothing termProgressSet :: TermProgress -> Int -> Maybe Int -> IO () termProgressSet tp st mpr = when (tpEnabled tp) $ do let st' = clamp 0 4 st pr' = fmap (clamp 0 100) mpr newState = if st' == 0 then Nothing else Just (st', pr') prev <- readIORef (tpLastRef tp) when (prev /= newState) $ do putStr (oscSequence st' pr') hFlush stdout writeIORef (tpLastRef tp) newState now <- getTime Monotonic writeIORef (tpLastSentRef tp) (Just now) oscSequence :: Int -> Maybe Int -> String oscSequence st mpr = let esc = "\x1b" bel = "\x07" base = esc ++ "]9;4;" ++ show st body = case mpr of Nothing -> base Just p -> base ++ ";" ++ show p in body ++ bel clamp :: Int -> Int -> Int -> Int clamp lo hi v = max lo (min hi v) keepaliveMicros :: Integer keepaliveMicros = 1000000 termProgressHeartbeat :: TermProgress -> IO () termProgressHeartbeat tp = when (tpEnabled tp) $ do mstate <- readIORef (tpLastRef tp) case mstate of Just (st, pr) -> do now <- getTime Monotonic mlast <- readIORef (tpLastSentRef tp) let due = case mlast of Nothing -> True Just t -> let elapsed = toNanoSecs now - toNanoSecs t in elapsed >= keepaliveMicros * 1000 when due $ do putStr (oscSequence st pr) hFlush stdout writeIORef (tpLastSentRef tp) (Just now) Nothing -> return () ================================================ FILE: compiler/acton/TerminalSize.hs ================================================ {-# LANGUAGE CApiFFI #-} module TerminalSize ( TermSize , initTermSize , termSizeCurrent , termSizeSync , termSizeRead , termVisibleLength , termFitAnsiRight , termFitPlainLeft , termFitPlainRight , termRenderedRows , termRenderedRowsTotal ) where import Control.Exception (SomeException, try) import Control.Monad (when) import Data.IORef import Data.List (isInfixOf) import Foreign import Foreign.C.Types import System.Environment (lookupEnv) import System.Posix.IO (stdOutput) import System.Posix.Signals (Handler(..), installHandler) data TermSize = TermSize { tsEnabled :: Bool , tsRowsRef :: IORef Int , tsColsRef :: IORef Int , tsDirtyRef :: IORef Bool } data WinSize = WinSize { wsRows :: CUShort , wsCols :: CUShort , wsXPixel :: CUShort , wsYPixel :: CUShort } instance Storable WinSize where sizeOf _ = 8 alignment _ = alignment (undefined :: CUShort) peek ptr = WinSize <$> peekByteOff ptr 0 <*> peekByteOff ptr 2 <*> peekByteOff ptr 4 <*> peekByteOff ptr 6 poke ptr (WinSize rows cols xp yp) = do pokeByteOff ptr 0 rows pokeByteOff ptr 2 cols pokeByteOff ptr 4 xp pokeByteOff ptr 6 yp foreign import capi unsafe "sys/ioctl.h value TIOCGWINSZ" c_TIOCGWINSZ :: CULong foreign import capi unsafe "signal.h value SIGWINCH" c_SIGWINCH :: CInt foreign import capi unsafe "sys/ioctl.h ioctl" c_ioctlWinsize :: CInt -> CULong -> Ptr WinSize -> IO CInt defaultRows :: Int defaultRows = 24 defaultCols :: Int defaultCols = 80 initTermSize :: Bool -> IO TermSize initTermSize enabled = do rows <- envOrDefault "LINES" defaultRows cols <- envOrDefault "COLUMNS" defaultCols rowsRef <- newIORef rows colsRef <- newIORef cols dirtyRef <- newIORef enabled let ts = TermSize { tsEnabled = enabled , tsRowsRef = rowsRef , tsColsRef = colsRef , tsDirtyRef = dirtyRef } when enabled $ do _ <- try (installHandler (fromIntegral c_SIGWINCH) (Catch (writeIORef dirtyRef True)) Nothing) :: IO (Either SomeException Handler) _ <- termSizeSync ts return () return ts termSizeSync :: TermSize -> IO (Bool, Int, Int) termSizeSync ts | not (tsEnabled ts) = do (rows, cols) <- termSizeCurrent ts return (False, rows, cols) | otherwise = do dirty <- atomicModifyIORef' (tsDirtyRef ts) (\cur -> (False, cur)) if not dirty then do rows <- readIORef (tsRowsRef ts) cols <- readIORef (tsColsRef ts) return (False, rows, cols) else do prevRows <- readIORef (tsRowsRef ts) prevCols <- readIORef (tsColsRef ts) msize <- queryTermSize case msize of Just (rows, cols) -> do writeIORef (tsRowsRef ts) rows writeIORef (tsColsRef ts) cols return (rows /= prevRows || cols /= prevCols, rows, cols) Nothing -> return (False, prevRows, prevCols) termSizeCurrent :: TermSize -> IO (Int, Int) termSizeCurrent ts = do rows <- readIORef (tsRowsRef ts) cols <- readIORef (tsColsRef ts) return (rows, cols) termSizeRead :: TermSize -> IO (Int, Int) termSizeRead ts = do (_, rows, cols) <- termSizeSync ts return (rows, cols) termVisibleLength :: String -> Int termVisibleLength = go 0 where go acc [] = acc go acc ('\ESC':'[':xs) = go acc (dropAnsi xs) go acc (_:xs) = go (acc + 1) xs termFitAnsiRight :: Int -> String -> String termFitAnsiRight width s | width <= 0 = "" | termVisibleLength s <= width = s | otherwise = let trimmed = go width s in if "\ESC[" `isInfixOf` trimmed then trimmed ++ "\ESC[0m" else trimmed where go _ [] = [] go n _ | n <= 0 = [] go n ('\ESC':'[':xs) = let (esc, rest) = spanAnsi xs in '\ESC' : '[' : esc ++ go n rest go n (x:xs) = x : go (n - 1) xs termFitPlainRight :: Int -> String -> String termFitPlainRight width s | width <= 0 = "" | length s <= width = s | otherwise = take width s termFitPlainLeft :: Int -> String -> String termFitPlainLeft width s | width <= 0 = "" | length s <= width = s | otherwise = drop (length s - width) s termRenderedRows :: Int -> String -> Int termRenderedRows width s | width <= 0 = 1 | otherwise = let visible = max 0 (termVisibleLength s) in max 1 ((visible + width - 1) `div` width) termRenderedRowsTotal :: Int -> [String] -> Int termRenderedRowsTotal width = sum . map (termRenderedRows width) queryTermSize :: IO (Maybe (Int, Int)) queryTermSize = alloca $ \ptr -> do rc <- c_ioctlWinsize (fromIntegral stdOutput) c_TIOCGWINSZ ptr if rc == -1 then return Nothing else do WinSize rows cols _ _ <- peek ptr let rows' = fromIntegral rows cols' = fromIntegral cols if rows' > 0 && cols' > 0 then return (Just (rows', cols')) else return Nothing envOrDefault :: String -> Int -> IO Int envOrDefault name fallback = do raw <- lookupEnv name case raw >>= readMaybeInt of Just n | n > 0 -> return n _ -> return fallback readMaybeInt :: String -> Maybe Int readMaybeInt s = case reads s of [(n, "")] -> Just n _ -> Nothing dropAnsi :: String -> String dropAnsi [] = [] dropAnsi (c:cs) | c >= '@' && c <= '~' = cs | otherwise = dropAnsi cs spanAnsi :: String -> (String, String) spanAnsi [] = ([], []) spanAnsi (c:cs) | c >= '@' && c <= '~' = ([c], cs) | otherwise = let (prefix, rest) = spanAnsi cs in (c : prefix, rest) ================================================ FILE: compiler/acton/TestFormat.hs ================================================ module TestFormat ( formatTestStatus , formatTestStatusLive , formatTestLineWith , formatTestLineFitted , formatTestFinalLineRenderer , formatTestLiveLineRenderer , formatTestDetailLines , testColorApply , testColorBold , testColorRed , testColorGreen , testColorYellow , testColorReset ) where import Acton.Testing (TestResult(..)) import Data.Char (isSpace) import Data.List (foldl', isPrefixOf, isInfixOf, intercalate) import Data.Maybe (catMaybes, fromMaybe, isJust, listToMaybe, mapMaybe) import qualified Data.Map as M import TerminalSize (termFitPlainRight, termVisibleLength) import qualified Data.Aeson as Aeson import qualified Data.Aeson.Types as AesonTypes import qualified Data.Aeson.Key as AesonKey import qualified Data.Aeson.KeyMap as AesonKM import Text.Printf (printf) -- | Compute the status label (OK/FAIL/ERR/FLAKY) for a test. formatTestStatus :: TestResult -> String formatTestStatus res = let ok = trSuccess res == Just True && trException res == Nothing && not (trSkipped res) base | trSnapshotUpdated res = "UPDATED" | trSkipped res = "SKIP" | ok = "OK" | trNumErrors res > 0 && trNumFailures res > 0 = "ERR/FAIL" | trNumErrors res > 0 = "ERR" | trNumFailures res > 0 = "FAIL" | trSuccess res == Just False = "FAIL" | otherwise = "ERR" prefix = if not ok && trFlaky res then "FLAKY " else "" in prefix ++ base -- | Compute a live status label for an in-progress test. formatTestStatusLive :: TestResult -> String formatTestStatusLive res | trSnapshotUpdated res = "UPDATED" | trSkipped res = "SKIP" | isJust (trException res) = "ERR" | trFlaky res = "FLAKY" | trNumErrors res > 0 && trNumFailures res > 0 = "ERR/FAIL" | trNumErrors res > 0 = "ERR" | trNumFailures res > 0 = "FAIL" | trSuccess res == Just False = "FAIL" | trNumIterations res > 0 || trSuccess res == Just True = "OK" | otherwise = "RUN" testColorReset :: String testColorReset = "\ESC[0m" testColorBold :: String testColorBold = "\ESC[1m" testColorRed :: String testColorRed = "\ESC[31m" testColorGreen :: String testColorGreen = "\ESC[32m" testColorYellow :: String testColorYellow = "\ESC[33m" testColorApply :: Bool -> [String] -> String -> String testColorApply useColor codes msg = if useColor then concat codes ++ msg ++ testColorReset else msg testStatusWidth :: Int testStatusWidth = (maximum (map length [ "RUN" , "OK" , "SKIP" , "UPDATED" , "FAIL" , "ERR" , "ERR/FAIL" , "FLAKY FAIL" , "FLAKY ERR" , "FLAKY ERR/FAIL" ])) + 1 colorizeStatusPart :: Bool -> Bool -> String -> String -> String colorizeStatusPart useColor cached statusRaw runs = let suffix = if cached then "*" else "" statusWithStar = statusRaw ++ suffix pad = replicate (max 0 (testStatusWidth - length statusWithStar)) ' ' strip pref s = if pref `isPrefixOf` s then drop (length pref) s else s core = strip "FLAKY " statusRaw statusColored = case core of "RUN" -> testColorApply useColor [testColorYellow] statusRaw "SKIP" -> testColorApply useColor [testColorYellow] statusRaw "OK" -> testColorApply useColor [testColorGreen] statusRaw "UPDATED" -> testColorApply useColor [testColorYellow] statusRaw _ -> testColorApply useColor [testColorBold, testColorRed] statusRaw star = if cached then if useColor then testColorYellow ++ "*" ++ testColorReset else "*" else "" in statusColored ++ star ++ pad ++ ": " ++ runs renderStatusField :: Bool -> Bool -> String -> (String, String) renderStatusField useColor cached statusRaw = let (statusPlain, statusRendered) = renderStatusToken useColor cached statusRaw pad = replicate (max 0 (testStatusWidth - length statusPlain)) ' ' in (statusPlain ++ pad ++ ":", statusRendered ++ pad ++ ":") renderStatusToken :: Bool -> Bool -> String -> (String, String) renderStatusToken useColor cached statusRaw = let suffix = if cached then "*" else "" strip pref s = if pref `isPrefixOf` s then drop (length pref) s else s core = strip "FLAKY " statusRaw statusColored = case core of "RUN" -> testColorApply useColor [testColorYellow] statusRaw "SKIP" -> testColorApply useColor [testColorYellow] statusRaw "OK" -> testColorApply useColor [testColorGreen] statusRaw "UPDATED" -> testColorApply useColor [testColorYellow] statusRaw _ -> testColorApply useColor [testColorBold, testColorRed] statusRaw star = if cached then if useColor then testColorYellow ++ "*" ++ testColorReset else "*" else "" in (statusRaw ++ suffix, statusColored ++ star) formatSecondsCompact :: Double -> String formatSecondsCompact ms | ms <= 0 = "0s" | ms < 1000 = "<1s" | otherwise = let secs = ms / 1000 in show (max 1 (round secs :: Int)) ++ "s" formatSecondsCompactPadded :: Double -> Double -> String formatSecondsCompactPadded expectedMs actualMs = let expected = formatSecondsCompact expectedMs actual = formatSecondsCompact actualMs width = max (length expected) (length actual) in replicate (max 0 (width - length actual)) ' ' ++ actual formatMillisPadded :: Double -> Double -> String formatMillisPadded expectedMs actualMs = let digits ms = max 1 (length (show (max 0 (floor ms :: Int)))) width = max (digits expectedMs) (digits actualMs) + 4 in printf ("%*.*fms" :: String) width (3 :: Int) actualMs fitTestDisplay :: Int -> String -> String fitTestDisplay width display | width <= 0 = "" | length display <= width = display | width <= 3 = take width display | otherwise = termFitPlainRight (width - 3) display ++ "..." -- | Format a single test result line with alignment and timing. formatTestLineWith :: Bool -> (TestResult -> String) -> Double -> Int -> String -> TestResult -> String formatTestLineWith useColor statusFn expectedDurationMs nameWidth display res = let prefix0 = " " ++ display ++ ": " padding = replicate (max 0 (nameWidth - length prefix0)) ' ' statusRaw = statusFn res runs = printf "%4d runs in %s @ %6.1f/s" (trNumIterations res) (formatMillisPadded expectedDurationMs (trTestDuration res)) (testsPerSecond (trNumIterations res) (trTestDuration res)) statusPart = colorizeStatusPart useColor (trCached res) statusRaw runs stressPart = case stressWorkerOverview res of Just txt -> " | " ++ txt Nothing -> "" in prefix0 ++ padding ++ statusPart ++ stressPart stressWorkerOverview :: TestResult -> Maybe String stressWorkerOverview res = case trRaw res of Aeson.Object obj -> let mEstMs = lookupDouble obj "stress_est_iteration_ms" mPhaseResMs = lookupDouble obj "stress_phase_resolution_ms" mSweep = lookupInt obj "stress_target_sweep_iters" mCalib = lookupInt obj "stress_calibrating_workers" mCovSeen = lookupInt obj "stress_phase_bins_seen" mCovTotal = lookupInt obj "stress_phase_bins_total" extraParts = catMaybes [ case mEstMs of Just est | est > 0 -> Just (printf "iter~%0.3fms" est) _ -> Nothing , case mPhaseResMs of Just resMs | resMs > 0 -> Just (printf "coarse~%0.3fms" resMs) _ -> Nothing , case mSweep of Just sweep | sweep > 0 -> Just ("sweep=" ++ show sweep) _ -> Nothing , case mCalib of Just calib | calib > 0 -> Just ("calib=" ++ show calib) _ -> Nothing , case (mCovSeen, mCovTotal) of (Just seen, Just total) | total > 0 -> let pct :: Double pct = (fromIntegral seen * 100.0) / fromIntegral total in Just (printf "cov=%d/%d(%0.1f%%)" seen total pct) _ -> Nothing ] in if null extraParts then Nothing else Just (unwords extraParts) _ -> Nothing where lookupInt :: Aeson.Object -> String -> Maybe Int lookupInt o key = case AesonKM.lookup (AesonKey.fromString key) o of Just v -> AesonTypes.parseMaybe Aeson.parseJSON v _ -> Nothing lookupDouble :: Aeson.Object -> String -> Maybe Double lookupDouble o key = case AesonKM.lookup (AesonKey.fromString key) o of Just v -> AesonTypes.parseMaybe Aeson.parseJSON v _ -> Nothing testsPerSecond :: Int -> Double -> Double testsPerSecond iterations durationMs | iterations <= 0 = 0 | durationMs <= 0 = 0 | otherwise = (fromIntegral iterations * 1000.0) / durationMs -- | Format a live test line to the current terminal width. formatTestLineFitted :: Bool -> (TestResult -> String) -> Double -> Int -> Int -> String -> TestResult -> String formatTestLineFitted useColor statusFn expectedDurationMs nameWidth width display res | width <= 0 = "" | otherwise = fromMaybe fallback (firstFit (legacyLine : map alignedLine summaries ++ map compactLine summaries)) where indent = if width >= 4 then " " else "" statusRaw = statusFn res (statusPlain, statusRendered) = renderStatusToken useColor (trCached res) statusRaw (statusFieldPlain, statusFieldRendered) = renderStatusField useColor (trCached res) statusRaw duration = formatSecondsCompactPadded expectedDurationMs (trTestDuration res) summaryFull = show (trNumIterations res) ++ " runs " ++ duration summaryCompact = show (trNumIterations res) ++ "r " ++ duration summaries = [Just summaryFull, Just summaryCompact, Nothing] legacyRendered = formatTestLineWith useColor statusFn expectedDurationMs nameWidth display res legacyLine | termVisibleLength legacyRendered <= width = Just legacyRendered | otherwise = Nothing prefix0 = indent ++ display ++ ": " alignedPrefix = prefix0 ++ replicate (max 0 (nameWidth - length prefix0)) ' ' alignedLine mSummary = let summaryPad = maybe 0 (\s -> 1 + length s) mSummary fixed = length alignedPrefix + length statusFieldPlain + summaryPad in if fixed <= width then Just (alignedPrefix ++ statusFieldRendered ++ maybe "" (\s -> " " ++ s) mSummary) else Nothing compactLine mSummary = let summaryPad = maybe 0 (\s -> 1 + length s) mSummary fixed = length indent + 2 + length statusPlain + summaryPad nameBudget = width - fixed in if nameBudget >= 1 then Just (indent ++ fitTestDisplay nameBudget display ++ ": " ++ statusRendered ++ maybe "" (\s -> " " ++ s) mSummary) else Nothing firstFit = listToMaybe . mapMaybe id fallback | width >= length statusPlain = statusRendered | otherwise = fitTestDisplay width display formatTestFinalLineRenderer :: Bool -> Double -> Int -> String -> TestResult -> Int -> String formatTestFinalLineRenderer useColor expectedDurationMs nameWidth display res cols = formatTestLineFitted useColor formatTestStatus expectedDurationMs nameWidth cols display res formatTestLiveLineRenderer :: Bool -> Double -> Int -> String -> TestResult -> Int -> String formatTestLiveLineRenderer useColor expectedDurationMs nameWidth display res cols = formatTestLineFitted useColor formatTestStatusLive expectedDurationMs nameWidth cols display res formatTestDetailLines :: Bool -> Bool -> TestResult -> [String] formatTestDetailLines useColor showLog res = let skipped = trSkipped res ok = trSuccess res == Just True && trException res == Nothing && not skipped wantDetails = showLog || skipped || not ok outcomeLines = case formatOutcomeSummaryLine useColor res of Just line -> [line] Nothing -> [] skipLines = case trSkipReason res of Just reason -> [ testColorApply useColor [testColorYellow] (" skipped: " ++ reason) ] Nothing -> [] excLines = case trException res of Just exc | not skipped -> [ testColorApply useColor [testColorRed] (" " ++ line) | line <- lines exc ] Nothing -> [] outputLines = if wantDetails then formatCombinedLogLines (trStdOut res) (trStdErr res) else [] in if wantDetails then outcomeLines ++ skipLines ++ excLines ++ outputLines else [] where formatOutcomeSummaryLine useColor' result | trNumIterations result <= 1 = Nothing | trNumFailures result <= 0 && trNumErrors result <= 0 && trNumSkipped result <= 0 = Nothing | otherwise = let (numSuccesses, numFailures, numErrors, numSkipped) = outcomeCounts result parts = catMaybes [ formatOutcomePart useColor' [testColorGreen] numSuccesses "ok" , formatOutcomePart useColor' [testColorRed] numFailures "fail" , formatOutcomePart useColor' [testColorBold, testColorRed] numErrors "err" , formatOutcomePart useColor' [testColorYellow] numSkipped "skip" ] in if null parts then Nothing else Just (" outcomes: " ++ intercalate ", " parts) outcomeCounts result = let numSkipped = max 0 (trNumSkipped result) numFailures = max 0 (trNumFailures result) numErrors = max 0 (trNumErrors result) numSuccesses = max 0 (trNumIterations result - numSkipped - numFailures - numErrors) in (numSuccesses, numFailures, numErrors, numSkipped) formatOutcomePart useColor' styles count label | count <= 0 = Nothing | otherwise = Just (testColorApply useColor' styles (show count ++ " " ++ label)) formatCombinedLogLines mOut mErr = let out = maybe "" id mOut err = maybe "" id mErr in if not (testOutputMeaningful out) && not (testOutputMeaningful err) then [] else let chunks = dedupCombinedOutput out err multi = length chunks > 1 in concatMap (renderChunk multi) chunks renderChunk multi (chunk, count) = let header = if multi then [" == " ++ show count ++ " test runs with this output:"] else [] body = map (" " ++) (lines chunk) in header ++ body ++ [""] testOutputMeaningful msgs = any (\line -> not (all isSpace line) && not ("== Running test," `isPrefixOf` line)) (lines msgs) splitTestOutput buf = let ls = lines buf isMarker line = "== Running test, iteration:" `isInfixOf` stripAnsi (trim line) step (chunks, current, seenMarker) line | isMarker line = if seenMarker then (chunks ++ [trim current], "", True) else (chunks, "", True) | otherwise = let current' = if null current then line else current ++ "\n" ++ line in (chunks, current', seenMarker) (chunks0, current0, seenMarker) = foldl' step ([], "", False) ls chunks1 = if seenMarker then chunks0 ++ [trim current0] else if null (trim buf) then [] else [trim buf] in chunks1 renderIterationOutput out err = let out' = trim out err' = trim err renderSection label content = label ++ ":\n" ++ unlines (map (" " ++) (lines content)) parts = catMaybes [ if null out' then Nothing else Just (renderSection "STDOUT" out') , if null err' then Nothing else Just (renderSection "STDERR" err') ] in intercalate "\n" parts dedupCombinedOutput out err = let outChunks = splitTestOutput out errChunks = splitTestOutput err n = max (length outChunks) (length errChunks) getChunk xs i = if i < length xs then xs !! i else "" combined = [ renderIterationOutput (getChunk outChunks i) (getChunk errChunks i) | i <- [0..n-1] ] parts = filter (not . null . trim) combined stepCount (order, acc) chunk = let acc' = M.insertWith (+) chunk 1 acc order' = if M.member chunk acc then order else order ++ [chunk] in (order', acc') (order, acc) = foldl' stepCount ([], M.empty) parts in [ (chunk, M.findWithDefault 0 chunk acc) | chunk <- order ] trim s = let dropEnd = reverse . dropWhile isSpace . reverse in dropWhile isSpace (dropEnd s) stripAnsi [] = [] stripAnsi ('\ESC':'[':xs) = stripAnsi (dropAnsi xs) stripAnsi (x:xs) = x : stripAnsi xs dropAnsi [] = [] dropAnsi (c:cs) | c == 'm' = cs | otherwise = dropAnsi cs ================================================ FILE: compiler/acton/TestGolden.hs ================================================ {-# LANGUAGE OverloadedStrings #-} module TestGolden ( normalizeProgressTimingLine , normalizeProgressTimings ) where import Data.Char (isDigit) import qualified Data.Text as T -- | Replace trailing durations like "12.345 s" with a stable token. normalizeProgressTimingLine :: T.Text -> T.Text normalizeProgressTimingLine t = case T.stripSuffix " s" t of Nothing -> t Just pre -> let field = T.takeWhileEnd (\c -> isDigit c || c == '.') pre pre' = T.dropEnd (T.length field) pre in case T.splitOn "." field of [intPart, frac] | not (T.null intPart) && T.length frac == 3 && T.all isDigit intPart && T.all isDigit frac -> let base = "0.000" padding = if T.length field > T.length base then " " else "" in pre' <> padding <> base <> " s" _ -> t normalizeProgressTimings :: String -> String normalizeProgressTimings = unlines . map (T.unpack . normalizeProgressTimingLine . T.pack) . lines ================================================ FILE: compiler/acton/TestRunner.hs ================================================ module TestRunner ( TestMode(..) , listTestModules , listProjectTests , runProjectTests ) where import qualified Acton.CommandLineParser as C import Acton.Testing import Acton.Compile import qualified Acton.Syntax as A import qualified InterfaceFiles import TestFormat import TestUI import Control.Concurrent (forkIO) import Control.Concurrent.Async import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar) import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan) import Control.Monad import Data.IORef import Data.Char (isSpace) import Data.List (isPrefixOf, isSuffixOf, foldl', isInfixOf, intercalate) import qualified Data.List import Data.Maybe (catMaybes, listToMaybe, isJust) import qualified Data.Map as M import qualified Data.Set as Set import System.Clock import System.Directory import System.Exit import System.FilePath ((), (<.>), joinPath, takeExtension) import System.IO (hClose, hGetContents, hGetLine, hIsEOF) import System.Process import Text.Printf import qualified Data.Aeson as Aeson import qualified Data.Aeson.Types as AesonTypes import qualified Data.Aeson.Key as AesonKey import qualified Data.Aeson.KeyMap as AesonKM import qualified Data.ByteString.Lazy as BL import qualified Data.Text as T import qualified Data.Text.Encoding as TE import Data.Time.Clock (UTCTime) import Control.Exception (SomeException, AsyncException(..), displayException, evaluate, onException, try, fromException, throwIO) import TerminalSize (termFitAnsiRight) import qualified Text.Regex.TDFA as TDFA import Data.Version (showVersion) import qualified Paths_acton data TestMode = TestModeRun | TestModeList | TestModePerf | TestModeStress deriving (Eq, Show) data TestSpec = TestSpec { tsModule :: String , tsName :: String , tsDisplay :: String } deriving (Show) data TestEvent = TestEventDone TestResult | TestEventRoom data TestProgressCallbacks = TestProgressCallbacks { tpcOnLive :: TestResult -> IO () , tpcOnDone :: TestResult -> IO () , tpcOnFinal :: TestResult -> IO () } data StressWorkerRow = StressWorkerRow { swrId :: Int , swrSync :: Bool , swrIterations :: Int , swrDriftUs :: Int , swrDriftTotalUs :: Int , swrCalibrating :: Bool , swrPhaseResolutionUs :: Int , swrTargetSweepIters :: Int } data StressPhaseLane = StressPhaseLane { splPhaseResolutionUs :: Int , splTargetSweepIters :: Int } getVer :: String getVer = showVersion Paths_acton.version printErrorAndExit :: String -> IO a printErrorAndExit msg = do errorWithoutStackTrace msg exitFailure moduleHeaderLine :: String -> String moduleHeaderLine modName | null modName = "Tests" | otherwise = "Tests - module " ++ modName ++ ":" -- | List test modules by reading discovered tests from .ty headers. listTestModules :: C.CompileOptions -> Paths -> IO [String] listTestModules _opts paths = do srcFiles <- listActFilesRecursive (srcDir paths) mods <- forM srcFiles $ \file -> do mn <- moduleNameFromFile (srcDir paths) file tests <- readModuleTests paths mn return $ if null tests then Nothing else Just (modNameToString mn) return (Data.List.sort (catMaybes mods)) -- | Compute the test binary path for a module and target. testBinaryPath :: C.CompileOptions -> Paths -> String -> FilePath testBinaryPath opts paths modName = let base = ".test_" ++ modName exe = if isWindowsTarget (C.target opts) then base <.> "exe" else base in binDir paths exe -- | Check whether a target triple refers to Windows. isWindowsTarget :: String -> Bool isWindowsTarget targetTriple = case break (== '-') targetTriple of (_, "") -> False (_, '-' : rest) -> let (os, _) = break (== '-') rest in os == "windows" -- | List tests for selected modules and print them in a stable order. listProjectTests :: C.CompileOptions -> Paths -> C.TestOptions -> [String] -> IO () listProjectTests opts paths topts modules = do let wantedModules = Data.List.sort (filterModules (C.testModules topts) modules) nameRegexes <- compileTestNameRegexes (C.testNames topts) tests <- forM wantedModules $ \modName -> do names <- listModuleTests opts paths modName return (modName, Data.List.sort (filterTests nameRegexes names)) let nonEmpty = [ (modName, names) | (modName, names) <- tests, not (null names) ] if C.testJson topts then do let testObj raw = let display = displayTestName raw in Aeson.object [ AesonKey.fromString "name" Aeson..= display , AesonKey.fromString "raw_name" Aeson..= raw ] moduleObj (modName, names) = Aeson.object [ AesonKey.fromString "name" Aeson..= modName , AesonKey.fromString "tests" Aeson..= map testObj names ] report = Aeson.object [ AesonKey.fromString "modules" Aeson..= map moduleObj (Data.List.sortOn fst nonEmpty) ] BL.putStr (Aeson.encode report) putStrLn "" exitSuccess else if null nonEmpty then do putStrLn "No tests found" exitSuccess else do forM_ (Data.List.sortOn fst nonEmpty) $ \(modName, names) -> do putStrLn ("Module " ++ modName ++ ":") forM_ names $ \name -> do let display = displayTestName name if display /= name then putStrLn (" " ++ display ++ " (" ++ name ++ ")") else putStrLn (" " ++ display) putStrLn "" exitSuccess -- | Run selected tests concurrently, stream results, and return an exit code. runProjectTests :: Bool -> C.GlobalOptions -> C.CompileOptions -> Paths -> C.TestOptions -> TestMode -> [String] -> Int -> IO Int runProjectTests useColorOut gopts opts paths topts mode modules maxParallel = do timeStart <- getTime Monotonic let emitJson = C.testJson topts nameRegexes <- compileTestNameRegexes (C.testNames topts) let wantedModules = Data.List.sort (filterModules (C.testModules topts) modules) testsByModule <- forM wantedModules $ \modName -> do names <- listModuleTests opts paths modName let wantedNames = Data.List.sort (filterTests nameRegexes names) return (modName, wantedNames) let specs = [ TestSpec modName testName (displayTestName testName) | (modName, names) <- testsByModule , testName <- names ] allTests = [ (tsModule spec, tsName spec) | spec <- specs ] if null specs then do if emitJson then do timeEnd <- getTime Monotonic outputJsonReport (timeEnd - timeStart) [] return 0 else do putStrLn "Nothing to test" return 0 else do let maxNameLen = maximum (0 : map (length . tsDisplay) specs) nameWidth = max 20 (maxNameLen + 5) runContext = mkRunContext opts topts mode ctxHash = contextHashBytes runContext useCache = not (C.testNoCache topts) && mode /= TestModeStress cache <- if useCache then readTestCache (testCachePath paths) runContext else return TestCache { tcVersion = testCacheVersion , tcContext = runContext , tcTests = M.empty } testHashInfos <- if useCache then buildTestHashInfos paths ctxHash testsByModule else return M.empty let cacheEntries = if useCache then tcTests cache else M.empty when (C.verbose gopts && useCache) $ putStrLn (formatTestCacheContext ctxHash (testCachePath paths)) let logCache = if C.verbose gopts then putStrLn else \_ -> return () (cachedResults0, _testsToRun) <- if useCache then classifyCachedTests logCache cacheEntries testHashInfos allTests else return ([], allTests) cachedResults1 <- if useCache then filterReusableCachedSnapshotResults logCache paths cachedResults0 else return [] cachedResults <- if C.testSnapshotUpdate topts then mapM (applySnapshotUpdate paths) cachedResults1 else return cachedResults1 let showCached = C.testShowCached topts when (not emitJson && not useCache) $ if mode == TestModeStress then putStrLn "Skipping test result cache in stress mode; running all selected tests" else putStrLn "Skipping test result cache (--no-cache); running all selected tests" when (not emitJson && showCached && not (null cachedResults)) $ putStrLn ("Using cached results for " ++ show (length cachedResults) ++ " tests") ui <- initTestProgressUI gopts nameWidth (C.testShowLog topts) useColorOut let totalTests = length specs progressDoneRef <- newIORef 0 let (effectiveMinTime, effectiveMaxTime) = effectiveTestTiming mode topts expectedDurationMs = fromIntegral (if effectiveMaxTime > 0 then effectiveMaxTime else effectiveMinTime) let progressStep = do done <- atomicModifyIORef' progressDoneRef (\x -> let x' = x + 1 in (x', x')) let pct = if totalTests <= 0 then 100 else min 100 ((done * 100) `div` totalTests) testUiProgressPercent ui pct testUiProgressPercent ui 0 eventChan <- newChan let cachedMap = M.fromList [ (TestKey (trModule res) (trName res), res) | res <- cachedResults ] shouldShowCached res = let ok = trSuccess res == Just True && trException res == Nothing && not (trSkipped res) in showCached || not ok || trSnapshotUpdated res startSpec spec running results = do let key = TestKey (tsModule spec) (tsName spec) display = tsDisplay spec useColorLine = tpuUseColor ui showLog = tpuShowLog ui case M.lookup key cachedMap of Just cachedRes -> do let line = formatTestFinalLineRenderer useColorLine expectedDurationMs nameWidth display cachedRes details = formatTestDetailLines useColorLine showLog cachedRes if shouldShowCached cachedRes then do ok <- testUiAppendFinal ui key (tsModule spec) line if not ok then return Nothing else do inserted <- testUiInsertDetails ui key details unless inserted $ queuePendingDetails ui key details progressStep return (Just (running, cachedRes : results)) else do progressStep return (Just (running, cachedRes : results)) Nothing -> do if running >= maxParallel then return Nothing else do let initRes = TestResult { trModule = tsModule spec , trName = tsName spec , trComplete = False , trSuccess = Nothing , trSkipped = False , trSkipReason = Nothing , trException = Nothing , trOutput = Nothing , trStdOut = Nothing , trStdErr = Nothing , trFlaky = False , trNumSkipped = 0 , trNumFailures = 0 , trNumErrors = 0 , trNumIterations = 0 , trTestDuration = 0 , trRaw = Aeson.Null , trSnapshotUpdated = False , trCached = False } initLine = formatTestLiveLineRenderer useColorLine expectedDurationMs nameWidth display initRes started <- testUiStart ui key (tsModule spec) initLine if not started then return Nothing else do callbacks <- testProgressCallbacks ui eventChan key display expectedDurationMs void $ async $ do res <- runModuleTestStreaming opts paths topts mode (tsModule spec) (tsName spec) (tpuEnabled ui) callbacks writeChan eventChan (TestEventDone res) return (Just (running + 1, results)) startAvailable pending running results = do case pending of [] -> return ([], running, results) (spec:rest) -> do mnext <- startSpec spec running results case mnext of Nothing -> return (pending, running, results) Just (running', results') -> startAvailable rest running' results' loop pending running results = do flushPendingDetails ui (pending', running', results') <- startAvailable pending running results if null pending' && running' == 0 then do flushPendingDetails ui return results' else do evt <- readChan eventChan case evt of TestEventDone res -> do progressStep let pending'' = if testResultInterrupted res then [] else pending' loop pending'' (running' - 1) (res : results') TestEventRoom -> loop pending' running' results' results <- loop specs 0 [] timeEnd <- getTime Monotonic writeSnapshotOutputs paths results let resultsRun = if C.testSnapshotUpdate topts then filter (\r -> not (trCached r) || trSnapshotUpdated r) results else filter (not . trCached) results when (C.testRecord topts) $ writePerfData paths resultsRun let cacheEntries' = foldl' (updateTestCacheEntry testHashInfos) cacheEntries resultsRun newCache = TestCache { tcVersion = testCacheVersion , tcContext = runContext , tcTests = cacheEntries' } when useCache $ writeTestCache (testCachePath paths) newCache if emitJson then do outputJsonReport (timeEnd - timeStart) results testUiProgressClear ui return (testExitCode results) else do when (not (tpuEnabled ui)) $ printTestResultsOrdered (tpuUseColor ui) (tpuShowLog ui) showCached nameWidth specs results _ <- printTestSummary (tpuUseColor ui) (timeEnd - timeStart) showCached results testUiProgressClear ui return (testExitCode results) where mkRunContext opts' topts' mode' = TestRunContext { trcCompilerVersion = getVer , trcTarget = C.target opts' , trcOptimize = show (C.optimize opts') , trcMode = show mode' , trcArgs = testCmdArgs mode' topts' } testExitCode :: [TestResult] -> Int testExitCode results = let failures = length [ r | r <- results, trSuccess r == Just False ] errors = length [ r | r <- results, trSuccess r == Nothing ] in if errors > 0 then 2 else if failures > 0 then 1 else 0 outputJsonReport :: TimeSpec -> [TestResult] -> IO () outputJsonReport elapsed results = do let total = length results failures = length [ r | r <- results, trSuccess r == Just False ] errors = length [ r | r <- results, trSuccess r == Nothing ] skipped = length [ r | r <- results, trSkipped r ] elapsedMs :: Double elapsedMs = let secs :: Double secs = (fromIntegral (sec elapsed)) + (fromIntegral (nsec elapsed) / 1000000000) in secs * 1000 isOk res = trSuccess res == Just True && trException res == Nothing && not (trSkipped res) formatCombinedOutput mOut mErr = let out = maybe "" id mOut err = maybe "" id mErr in if not (testOutputMeaningful out) && not (testOutputMeaningful err) then Nothing else let chunks = dedupCombinedOutput out err multi = length chunks > 1 rendered = concatMap (renderChunk multi) chunks rendered' = stripTrailingBlanks rendered joined = unlines rendered' in if null (trim joined) then Nothing else Just joined testObj res = let status = formatTestStatus res includeOutput = not (isOk res) name = displayTestName (trName res) combinedOutput = if includeOutput then formatCombinedOutput (trStdOut res) (trStdErr res) else Nothing in Aeson.object [ AesonKey.fromString "module" Aeson..= trModule res , AesonKey.fromString "name" Aeson..= name , AesonKey.fromString "raw_name" Aeson..= trName res , AesonKey.fromString "status" Aeson..= status , AesonKey.fromString "cached" Aeson..= trCached res , AesonKey.fromString "flaky" Aeson..= trFlaky res , AesonKey.fromString "iterations" Aeson..= trNumIterations res , AesonKey.fromString "duration_ms" Aeson..= trTestDuration res , AesonKey.fromString "skipped" Aeson..= trSkipped res , AesonKey.fromString "skip_reason" Aeson..= trSkipReason res , AesonKey.fromString "exception" Aeson..= trException res , AesonKey.fromString "output" Aeson..= combinedOutput ] report = Aeson.object [ AesonKey.fromString "summary" Aeson..= Aeson.object [ AesonKey.fromString "total" Aeson..= total , AesonKey.fromString "failures" Aeson..= failures , AesonKey.fromString "errors" Aeson..= errors , AesonKey.fromString "skipped" Aeson..= skipped , AesonKey.fromString "elapsed_ms" Aeson..= elapsedMs ] , AesonKey.fromString "tests" Aeson..= map testObj results ] BL.putStr (Aeson.encode report) putStrLn "" renderChunk :: Bool -> (String, Int) -> [String] renderChunk multi (chunk, count) = let header = if multi then ["== " ++ show count ++ " test runs with this output:"] else [] body = lines chunk in header ++ body ++ [""] stripTrailingBlanks :: [String] -> [String] stripTrailingBlanks = reverse . dropWhile null . reverse testOutputMeaningful :: String -> Bool testOutputMeaningful msgs = any (\line -> not (all isSpace line) && not ("== Running test," `isPrefixOf` line)) (lines msgs) splitTestOutput :: String -> [String] splitTestOutput buf = let ls = lines buf isMarker line = "== Running test, iteration:" `isInfixOf` stripAnsi (trim line) step (chunks, current, seenMarker) line | isMarker line = if seenMarker then (chunks ++ [trim current], "", True) else (chunks, "", True) | otherwise = let current' = if null current then line else current ++ "\n" ++ line in (chunks, current', seenMarker) (chunks0, current0, seenMarker) = foldl' step ([], "", False) ls chunks1 = if seenMarker then chunks0 ++ [trim current0] else if null (trim buf) then [] else [trim buf] in chunks1 renderIterationOutput :: String -> String -> String renderIterationOutput out err = let out' = trim out err' = trim err renderSection label content = let body = intercalate "\n" (map (" " ++) (lines content)) in label ++ ":\n" ++ body parts = catMaybes [ if null out' then Nothing else Just (renderSection "STDOUT" out') , if null err' then Nothing else Just (renderSection "STDERR" err') ] in intercalate "\n" parts dedupCombinedOutput :: String -> String -> [(String, Int)] dedupCombinedOutput out err = let outChunks = splitTestOutput out errChunks = splitTestOutput err n = max (length outChunks) (length errChunks) getChunk xs i = if i < length xs then xs !! i else "" combined = [ renderIterationOutput (getChunk outChunks i) (getChunk errChunks i) | i <- [0..n-1] ] parts = filter (not . null . trim) combined stepCount (order, acc) chunk = let acc' = M.insertWith (+) chunk 1 acc order' = if M.member chunk acc then order else order ++ [chunk] in (order', acc') (order, acc) = foldl' stepCount ([], M.empty) parts in [ (chunk, M.findWithDefault 0 chunk acc) | chunk <- order ] trim :: String -> String trim s = let dropEnd = reverse . dropWhile isSpace . reverse in dropWhile isSpace (dropEnd s) stripAnsi :: String -> String stripAnsi [] = [] stripAnsi ('\ESC':'[':xs) = stripAnsi (dropAnsi xs) stripAnsi (x:xs) = x : stripAnsi xs dropAnsi :: String -> String dropAnsi [] = [] dropAnsi (c:cs) | c == 'm' = cs | otherwise = dropAnsi cs -- | Filter module names based on CLI-provided allow lists. filterModules :: [String] -> [String] -> [String] filterModules [] mods = mods filterModules wanted mods = filter (`elem` wanted) mods -- | Filter test names, matching raw or display names. filterTests :: [TDFA.Regex] -> [String] -> [String] filterTests [] names = names filterTests regexes names = filter matches names where matches name = let display = displayTestName name in any (\re -> regexMatches re name || regexMatches re display) regexes compileTestNameRegexes :: [String] -> IO [TDFA.Regex] compileTestNameRegexes patterns = mapM compileRegex (filter (not . null) patterns) where compileRegex pattern = do let anchored = "^" ++ pattern ++ "$" res <- try (evaluate (TDFA.makeRegex anchored :: TDFA.Regex)) :: IO (Either SomeException TDFA.Regex) case res of Left err -> printErrorAndExit ("ERROR: Invalid regex '" ++ pattern ++ "': " ++ displayException err) Right re -> return re regexMatches :: TDFA.Regex -> String -> Bool regexMatches re text = isJust (TDFA.matchOnceText re text) -- | Read the discovered tests for a module from its .ty header. listModuleTests :: C.CompileOptions -> Paths -> String -> IO [String] listModuleTests _opts paths modName = readModuleTests paths (modNameFromString modName) -- | Read tests from a module's .ty header, returning [] on any error. readModuleTests :: Paths -> A.ModName -> IO [String] readModuleTests paths mn = do let tyFile = outBase paths mn ++ ".ty" exists <- doesFileExist tyFile if not exists then return [] else do hdrE <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readHeader tyFile case hdrE of Left _ -> return [] Right (_sourceMeta, _srcH, _ih, _implH, _imps, _nameHashes, _roots, tests, _doc) -> return tests modNameFromString :: String -> A.ModName modNameFromString s = A.modName (splitOnChar '.' s) splitOnChar :: Char -> String -> [String] splitOnChar ch input = case break (== ch) input of (chunk, []) -> [chunk] (chunk, _ : rest) -> chunk : splitOnChar ch rest listActFilesRecursive :: FilePath -> IO [FilePath] listActFilesRecursive dir = do exists <- doesDirectoryExist dir if not exists then return [] else do entries <- listDirectory dir paths <- forM entries $ \entry -> do let path = dir entry isDir <- doesDirectoryExist path if isDir then listActFilesRecursive path else return [path] return (filter (\f -> takeExtension f == ".act") (concat paths)) -- | Run a single test case and stream JSON updates. runModuleTestStreaming :: C.CompileOptions -> Paths -> C.TestOptions -> TestMode -> String -> String -> Bool -> TestProgressCallbacks -> IO TestResult runModuleTestStreaming opts paths topts mode modName testName allowLive callbacks = do let binPath = testBinaryPath opts paths modName modeArgs = case mode of TestModePerf -> ["perf"] TestModeStress -> ["stress"] _ -> [] cmd = ["test", testName] ++ modeArgs ++ testCmdArgs mode topts updatesRef <- newIORef [] lineDoneRef <- newIORef False stdErrRef <- newIORef [] let onUpdate res = do modifyIORef' updatesRef (\xs -> xs ++ [res]) done <- readIORef lineDoneRef when (not done && allowLive) $ do if trComplete res then do tpcOnDone callbacks res writeIORef lineDoneRef True else tpcOnLive callbacks res addStdErr line = modifyIORef' stdErrRef (line :) onErrLine line = case parseJsonLine line of Nothing -> addStdErr line Just val -> case parseTestInfo val of Just res -> onUpdate res Nothing -> addStdErr line let procSpec = (proc binPath cmd){ cwd = Just (projPath paths), delegate_ctlc = True } procRes <- try (readProcessWithExitCodeStreaming procSpec onErrLine) :: IO (Either SomeException (ExitCode, String, String)) (exitCode, out, _err, interruptedByUser) <- case procRes of Right (code, outTxt, errTxt) -> return (code, outTxt, errTxt, False) Left ex -> case fromException ex of Just UserInterrupt -> return (ExitFailure (-2), "", "", True) _ -> throwIO ex infos <- readIORef updatesRef stdErrLines <- reverse <$> readIORef stdErrRef let stdErrText = unlines stdErrLines let final = pickFinalTestInfo infos fallback = TestResult { trModule = modName , trName = testName , trComplete = False , trSuccess = Nothing , trSkipped = False , trSkipReason = Nothing , trException = Just "No test result received" , trOutput = Nothing , trStdOut = Nothing , trStdErr = Nothing , trFlaky = False , trNumSkipped = 0 , trNumFailures = 0 , trNumErrors = 1 , trNumIterations = 0 , trTestDuration = 0 , trRaw = Aeson.Null , trSnapshotUpdated = False , trCached = False } res0 = maybe fallback id final mergedStd field captured = case field of Just txt | not (null txt) -> Just txt _ -> if null captured then field else Just captured res1 = res0 { trStdOut = mergedStd (trStdOut res0) out , trStdErr = mergedStd (trStdErr res0) stdErrText } interrupted = interruptedByUser || isInterruptExitCode exitCode incompleteSuccessExit = mode == TestModeStress && exitCode == ExitSuccess && not (trComplete res1) res | mode == TestModeStress && (interrupted || incompleteSuccessExit) = finalizeInterruptedStressResult res1 | otherwise = case exitCode of ExitSuccess -> res1 ExitFailure code -> res1 { trException = Just ("Test process exited with code " ++ show code) } res' <- if C.testSnapshotUpdate topts then applySnapshotUpdate paths res else return res done <- readIORef lineDoneRef if done then tpcOnFinal callbacks res' else do tpcOnDone callbacks res' tpcOnFinal callbacks res' return res' where isInterruptExitCode ExitSuccess = False isInterruptExitCode (ExitFailure code) = code == (-2) || code == 130 finalizeInterruptedStressResult res = let success' = case trSuccess res of Just _ -> trSuccess res Nothing -> if trNumFailures res == 0 && trNumErrors res == 0 then Just True else Nothing exception' = if trNumFailures res == 0 && trNumErrors res == 0 then Nothing else trException res in res { trComplete = True , trSuccess = success' , trException = exception' , trRaw = markInterruptedRaw (trRaw res) } markInterruptedRaw raw = case raw of Aeson.Object o -> Aeson.Object (AesonKM.insert (AesonKey.fromString "interrupted") (Aeson.Bool True) o) _ -> Aeson.object [AesonKey.fromString "interrupted" Aeson..= True] testProgressCallbacks :: TestProgressUI -> Chan TestEvent -> TestKey -> String -> Double -> IO TestProgressCallbacks testProgressCallbacks ui eventChan key display expectedDurationMs = do workerKeysRef <- newIORef M.empty let nameWidth = tpuNameWidth ui useColorOut = tpuUseColor ui showLog = tpuShowLog ui liveLine res = formatTestLiveLineRenderer useColorOut expectedDurationMs nameWidth display res finalLine res = formatTestFinalLineRenderer useColorOut expectedDurationMs nameWidth display res detailLines res = formatTestDetailLines useColorOut showLog res workerLine done durationMs laneSpec row cols = let role = if swrSync row then "sync" else "drift" phase = if done then "DONE" else if swrCalibrating row then "CAL " else "RUN " iterations = swrIterations row rate = testsPerSecond iterations durationMs baseLine = printf " w%-3d %-5s %s : %7d iters @ %7.1f/s cur=%6dus tot=%8dus" (swrId row) role phase iterations rate (swrDriftUs row) (swrDriftTotalUs row) line = baseLine ++ renderStressPhaseLane useColorOut cols baseLine laneSpec row in termFitAnsiRight cols line workerKey wid = TestKey (tkModule key) (tkName key ++ "#worker" ++ show wid) updateStressWorkers done res = do let rows = stressWorkerRows res laneSpec = stressPhaseLaneSpec res unless (null rows) $ do existing <- readIORef workerKeysRef existing' <- foldM (\acc row -> do let wid = swrId row line = workerLine done (trTestDuration res) laneSpec row case M.lookup wid acc of Just wk -> do if done then do removed <- testUiFinalize ui wk line when removed $ writeChan eventChan TestEventRoom else testUiUpdateLive ui wk line return acc Nothing -> if done then return acc else do let wk = workerKey wid started <- testUiStart ui wk (tkModule key) line if started then return (M.insert wid wk acc) else return acc ) existing rows writeIORef workerKeysRef existing' return TestProgressCallbacks { tpcOnLive = \res -> testUiUpdateLive ui key (liveLine res) >> updateStressWorkers False res , tpcOnDone = \res -> do updateStressWorkers True res removed <- testUiFinalize ui key (finalLine res) when removed $ writeChan eventChan TestEventRoom , tpcOnFinal = \res -> do testUiUpdateFinal ui key (finalLine res) let details = detailLines res inserted <- testUiInsertDetails ui key details unless inserted $ queuePendingDetails ui key details } stressWorkerRows :: TestResult -> [StressWorkerRow] stressWorkerRows res = case trRaw res of Aeson.Object obj -> case AesonKM.lookup (AesonKey.fromString "stress_workers") obj of Just (Aeson.Array workers) -> catMaybes (map parseWorker (foldr (:) [] workers)) _ -> [] _ -> [] where parseWorker val = case val of Aeson.Object o -> do wid <- lookupInt o "id" iterations <- lookupInt o "iterations" driftUs <- lookupIntDefault o "drift_us" 0 driftTotalUs <- lookupIntDefault o "drift_total_us" 0 syncW <- lookupBool o "sync" calibrating <- lookupBoolDefault o "calibrating" False phaseResolutionUs <- lookupIntDefault o "phase_resolution_us" 0 targetSweepIters <- lookupIntDefault o "target_sweep_iters" 0 return StressWorkerRow { swrId = wid , swrSync = syncW , swrIterations = iterations , swrDriftUs = driftUs , swrDriftTotalUs = driftTotalUs , swrCalibrating = calibrating , swrPhaseResolutionUs = phaseResolutionUs , swrTargetSweepIters = targetSweepIters } _ -> Nothing lookupInt o keyName = case AesonKM.lookup (AesonKey.fromString keyName) o of Just v -> AesonTypes.parseMaybe Aeson.parseJSON v _ -> Nothing lookupIntDefault o keyName defVal = case lookupInt o keyName of Just n -> Just n Nothing -> Just defVal lookupBool o keyName = case AesonKM.lookup (AesonKey.fromString keyName) o of Just v -> AesonTypes.parseMaybe Aeson.parseJSON v _ -> Nothing lookupBoolDefault o keyName defVal = case lookupBool o keyName of Just b -> Just b Nothing -> Just defVal stressPhaseLaneSpec :: TestResult -> Maybe StressPhaseLane stressPhaseLaneSpec res = case trRaw res of Aeson.Object obj -> do phaseResolutionMs <- lookupDouble obj "stress_phase_resolution_ms" targetSweepIters <- lookupInt obj "stress_target_sweep_iters" let phaseResolutionUs = max 0 (round (phaseResolutionMs * 1000.0)) guard (phaseResolutionUs > 0 && targetSweepIters > 0) return StressPhaseLane { splPhaseResolutionUs = phaseResolutionUs , splTargetSweepIters = targetSweepIters } _ -> Nothing where lookupInt o keyName = case AesonKM.lookup (AesonKey.fromString keyName) o of Just v -> AesonTypes.parseMaybe Aeson.parseJSON v _ -> Nothing lookupDouble o keyName = case AesonKM.lookup (AesonKey.fromString keyName) o of Just v -> (AesonTypes.parseMaybe Aeson.parseJSON v :: Maybe Double) _ -> Nothing resolveStressPhaseLane :: Maybe StressPhaseLane -> StressWorkerRow -> Maybe StressPhaseLane resolveStressPhaseLane baseSpec row | swrPhaseResolutionUs row > 0 && swrTargetSweepIters row > 0 = Just StressPhaseLane { splPhaseResolutionUs = swrPhaseResolutionUs row , splTargetSweepIters = swrTargetSweepIters row } | otherwise = baseSpec renderStressPhaseLane :: Bool -> Int -> String -> Maybe StressPhaseLane -> StressWorkerRow -> String renderStressPhaseLane useColorOut cols baseLine baseSpec row | not useColorOut = "" | swrCalibrating row = "" | otherwise = case resolveStressPhaseLane baseSpec row of Just spec -> let avail = cols - length baseLine in case stressPhaseLaneWidth avail of Just laneWidth -> " " ++ stressPhaseLaneText laneWidth spec row Nothing -> "" Nothing -> "" stressPhaseLaneWidth :: Int -> Maybe Int stressPhaseLaneWidth avail | avail < 11 = Nothing | otherwise = let width = min 32 (avail - 3) in if width < 8 then Nothing else Just width stressPhaseLaneText :: Int -> StressPhaseLane -> StressWorkerRow -> String stressPhaseLaneText laneWidth spec row = "|" ++ concatMap renderCell [0 .. laneWidth - 1] ++ testColorReset ++ "|" where totalPhaseUs = fromIntegral (max 1 (splPhaseResolutionUs spec * splTargetSweepIters spec)) :: Double windowUs = fromIntegral (max 1 (splPhaseResolutionUs spec)) :: Double phaseStartUs | swrSync row = 0.0 | otherwise = fromIntegral (swrDriftTotalUs row `mod` max 1 (splPhaseResolutionUs spec * splTargetSweepIters spec)) centerUs = wrapPhase (phaseStartUs + (windowUs / 2.0)) windowCells = fromIntegral laneWidth / fromIntegral (max 1 (splTargetSweepIters spec)) :: Double baselineBg = ansiBgReset edgeBg = ansiBg 17 haloBg = ansiBg 18 coreBg | windowCells < 0.35 = ansiBg 24 | windowCells < 0.70 = ansiBg 24 | otherwise = ansiBg 24 renderCell idx = let cellStartUs = totalPhaseUs * fromIntegral idx / fromIntegral laneWidth cellEndUs = totalPhaseUs * fromIntegral (idx + 1) / fromIntegral laneWidth overlapFrac = circularOverlap phaseStartUs (phaseStartUs + windowUs) cellStartUs cellEndUs totalPhaseUs isCore = circularContains centerUs cellStartUs cellEndUs totalPhaseUs bg | isCore = coreBg | overlapFrac >= 0.66 = haloBg | overlapFrac > 0.0 = edgeBg | otherwise = baselineBg in bg ++ " " wrapPhase x | totalPhaseUs <= 0.0 = 0.0 | otherwise = let wrapped = x - (fromIntegral (floor (x / totalPhaseUs)) * totalPhaseUs) in if wrapped < 0.0 then wrapped + totalPhaseUs else wrapped circularContains point start end total = overlapLinear start end point (point + 0.0001) total > 0.0 circularOverlap start end cellStart cellEnd total = let segments = circularSegments start end total cellSegments = circularSegments cellStart cellEnd total overlapSum = sum [ overlapLinear' s1 e1 s2 e2 | (s1, e1) <- segments, (s2, e2) <- cellSegments ] cellWidth = max 0.000001 (cellEnd - cellStart) in overlapSum / cellWidth circularSegments start end total | total <= 0.0 = [(0.0, 1.0)] | otherwise = let start' = wrapPhase start end' = start' + (end - start) in if end' <= total then [(start', end')] else [(start', total), (0.0, end' - total)] overlapLinear start end point pointEnd total = let segments = circularSegments start end total pointSegments = circularSegments point pointEnd total in sum [ overlapLinear' s1 e1 s2 e2 | (s1, e1) <- segments, (s2, e2) <- pointSegments ] overlapLinear' start1 end1 start2 end2 = max 0.0 (min end1 end2 - max start1 start2) ansiBg code = "\ESC[48;5;" ++ show code ++ "m" ansiBgReset = "\ESC[49m" testsPerSecond :: Int -> Double -> Double testsPerSecond iterations durationMs | iterations <= 0 = 0 | durationMs <= 0 = 0 | otherwise = (fromIntegral iterations * 1000.0) / durationMs effectiveTestTiming :: TestMode -> C.TestOptions -> (Int, Int) effectiveTestTiming mode topts = let rawMinTime = C.testMinTime topts minTime = case mode of TestModePerf -> if not (C.testMinTimeSet topts) then 1000 else rawMinTime TestModeStress -> if not (C.testMinTimeSet topts) then 1000 else rawMinTime _ -> rawMinTime rawMaxTime = C.testMaxTime topts modeDefaultMaxTime = case mode of TestModeRun -> minTime TestModePerf -> 1000 TestModeStress -> 5000 _ -> 1000 maxTime | C.testMaxTimeSet topts && rawMaxTime == 0 = 0 | C.testMaxTimeSet topts = max rawMaxTime minTime | otherwise = modeDefaultMaxTime in (minTime, maxTime) -- | Build test runner arguments from TestOptions limits. testCmdArgs :: TestMode -> C.TestOptions -> [String] testCmdArgs mode topts = let iter = C.testIter topts rawMaxIter = C.testMaxIter topts (minTime, maxTime) = effectiveTestTiming mode topts stressWorkerArgs | mode == TestModeStress && C.testStressWorkers topts > 0 = ["--stress-workers", show (C.testStressWorkers topts)] | otherwise = [] maxIter | mode == TestModeStress && maxTime == 0 && not (C.testMaxIterSet topts) = 0 | otherwise = rawMaxIter baseArgs = if iter > 0 then ["--max-iter", show iter, "--min-iter", show iter, "--max-time", show (10^6), "--min-time", "1"] else [ "--max-iter", show maxIter , "--min-iter", show (C.testMinIter topts) , "--max-time", show maxTime , "--min-time", show minTime ] tagArgs = concatMap (\tag -> ["--tag", tag]) (C.testTags topts) in baseArgs ++ stressWorkerArgs ++ tagArgs -- | Normalize test names by stripping prefixes and wrappers. displayTestName :: String -> String displayTestName name = let withoutPrefix = if "_test_" `isPrefixOf` name then drop 6 name else name in if "_wrapper" `isSuffixOf` withoutPrefix then take (length withoutPrefix - length "_wrapper") withoutPrefix else withoutPrefix -- | Parse a single JSON line emitted by test binaries. parseJsonLine :: String -> Maybe Aeson.Value parseJsonLine line = let trimmed = dropWhile isSpace line in if null trimmed then Nothing else Aeson.decodeStrict' (TE.encodeUtf8 (T.pack trimmed)) -- | Extract test result payloads from JSON events. extractTestInfo :: [Aeson.Value] -> [TestResult] extractTestInfo values = catMaybes (map parseTestInfo values) -- | Parse a JSON value into a TestResult when test_info is present. parseTestInfo :: Aeson.Value -> Maybe TestResult parseTestInfo val = case val of Aeson.Object obj -> case AesonKM.lookup (AesonKey.fromString "test_info") obj of Just infoVal -> AesonTypes.parseMaybe parseTestInfoValue infoVal Nothing -> Nothing _ -> Nothing -- | Aeson parser for the test_info object. parseTestInfoValue :: Aeson.Value -> AesonTypes.Parser TestResult parseTestInfoValue = Aeson.withObject "TestInfo" $ \o -> do def <- o Aeson..: AesonKey.fromString "definition" moduleName <- def Aeson..: AesonKey.fromString "module" name <- def Aeson..: AesonKey.fromString "name" complete <- o Aeson..: AesonKey.fromString "complete" success <- o Aeson..:? AesonKey.fromString "success" skipped <- o Aeson..:? AesonKey.fromString "skipped" Aeson..!= False skipReason <- o Aeson..:? AesonKey.fromString "skip_reason" exception <- o Aeson..:? AesonKey.fromString "exception" output <- o Aeson..:? AesonKey.fromString "output" stdOut <- o Aeson..:? AesonKey.fromString "std_out" stdErr <- o Aeson..:? AesonKey.fromString "std_err" flaky <- o Aeson..:? AesonKey.fromString "flaky" Aeson..!= False numSkipped <- o Aeson..:? AesonKey.fromString "num_skipped" Aeson..!= 0 numFailures <- o Aeson..:? AesonKey.fromString "num_failures" Aeson..!= 0 numErrors <- o Aeson..:? AesonKey.fromString "num_errors" Aeson..!= 0 numIterations <- o Aeson..:? AesonKey.fromString "num_iterations" Aeson..!= 0 testDuration <- o Aeson..:? AesonKey.fromString "test_duration" Aeson..!= 0 return TestResult { trModule = moduleName , trName = name , trComplete = complete , trSuccess = success , trSkipped = skipped , trSkipReason = skipReason , trException = exception , trOutput = output , trStdOut = stdOut , trStdErr = stdErr , trFlaky = flaky , trNumSkipped = numSkipped , trNumFailures = numFailures , trNumErrors = numErrors , trNumIterations = numIterations , trTestDuration = testDuration , trRaw = Aeson.Object o , trSnapshotUpdated = False , trCached = False } -- | Pick the final or last-seen TestResult from a stream. pickFinalTestInfo :: [TestResult] -> Maybe TestResult pickFinalTestInfo infos = case reverse infos of [] -> Nothing xs -> case listToMaybe [i | i <- xs, trComplete i] of Just i -> Just i Nothing -> Just (head xs) testResultInterrupted :: TestResult -> Bool testResultInterrupted res = case trRaw res of Aeson.Object obj -> case AesonKM.lookup (AesonKey.fromString "interrupted") obj of Just v -> case AesonTypes.parseMaybe Aeson.parseJSON v of Just True -> True _ -> False _ -> False _ -> False -- | Print a summary line and return the failure/error exit code. printTestSummary :: Bool -> TimeSpec -> Bool -> [TestResult] -> IO Int printTestSummary useColor elapsed showCached results = do let total = length results failures = length [ r | r <- results, trSuccess r == Just False ] errors = length [ r | r <- results, trSuccess r == Nothing ] skipped = length [ r | r <- results, trSkipped r ] hiddenCachedSuccess = not showCached && any (\r -> trCached r && trSuccess r == Just True && not (trSkipped r)) results interrupted = any testResultInterrupted results hasCached = any trCached results case total of 0 -> do putStrLn "Nothing to test" return 0 _ -> do putStrLn "" if errors > 0 && failures > 0 then putStrLn (testColorApply useColor [testColorBold, testColorRed] (show errors ++ " error and " ++ show failures ++ " failure out of " ++ show total ++ " tests (" ++ fmtTime elapsed ++ ")")) else if errors > 0 then putStrLn (testColorApply useColor [testColorBold, testColorRed] (show errors ++ " out of " ++ show total ++ " tests errored (" ++ fmtTime elapsed ++ ")")) else if failures > 0 then putStrLn (testColorApply useColor [testColorBold, testColorRed] (show failures ++ " out of " ++ show total ++ " tests failed (" ++ fmtTime elapsed ++ ")")) else if skipped > 0 then putStrLn (testColorApply useColor [testColorGreen] ("All " ++ show total ++ " tests passed, " ++ show skipped ++ " skipped (" ++ fmtTime elapsed ++ ")")) else putStrLn (testColorApply useColor [testColorGreen] ("All " ++ show total ++ " tests passed (" ++ fmtTime elapsed ++ ")")) putStrLn "" when hasCached $ putStrLn (if useColor then testColorYellow ++ "*" ++ testColorReset ++ " = cached test result" else "* = cached test result") when interrupted $ putStrLn "Stress run interrupted by user; showing partial results collected so far." when hiddenCachedSuccess $ putStrLn "Cached successful tests are hidden. Cached failures/errors are shown. Use --show-cached to include cached successes, or --no-cache to force rerunning selected tests." if errors > 0 then return 2 else if failures > 0 then return 1 else return 0 printTestResultsOrdered :: Bool -> Bool -> Bool -> Int -> [TestSpec] -> [TestResult] -> IO () printTestResultsOrdered useColor showLog showCached nameWidth specs results = do let resMap = M.fromList [ (TestKey (trModule res) (trName res), res) | res <- results ] isOk res = trSuccess res == Just True && trException res == Nothing && not (trSkipped res) shouldShow res = not (trCached res) || showCached || not (isOk res) || trSnapshotUpdated res formatLine spec res = formatTestLineWith useColor formatTestStatus (trTestDuration res) nameWidth (tsDisplay spec) res let go _ _ [] = return () go printedMods printedAny (spec:rest) = case M.lookup (TestKey (tsModule spec) (tsName spec)) resMap of Nothing -> go printedMods printedAny rest Just res -> if not (shouldShow res) then go printedMods printedAny rest else do let modName = tsModule spec printedMods' <- if Set.member modName printedMods then return printedMods else do when printedAny $ putStrLn "" putStrLn (moduleHeaderLine modName) return (Set.insert modName printedMods) putStrLn (formatLine spec res) mapM_ putStrLn (formatTestDetailLines useColor showLog res) mapM_ putStrLn (formatStressWorkerFinalLines useColor res) go printedMods' True rest go Set.empty False specs formatStressWorkerFinalLines :: Bool -> TestResult -> [String] formatStressWorkerFinalLines useColorOut res = map renderRow (stressWorkerRows res) where durationMs = trTestDuration res laneSpec = stressPhaseLaneSpec res renderRow row = let role = if swrSync row then "sync" else "drift" iterations = swrIterations row rate = testsPerSecond iterations durationMs baseLine = printf " w%-3d %-5s DONE : %7d iters @ %7.1f/s cur=%6dus tot=%8dus" (swrId row) role iterations rate (swrDriftUs row) (swrDriftTotalUs row) in baseLine ++ renderStressPhaseLane useColorOut (maxBound :: Int) baseLine laneSpec row -- | Write snapshot outputs for all tests that produced output. writeSnapshotOutputs :: Paths -> [TestResult] -> IO () writeSnapshotOutputs paths results = mapM_ (writeSnapshotOutput paths) results writeSnapshotOutput :: Paths -> TestResult -> IO () writeSnapshotOutput paths res = case trOutput res of Just out -> do let fileName = displayTestName (trName res) outDir = joinPath [projPath paths, "snapshots", "output", trModule res] createDirectoryIfMissing True outDir writeFile (outDir fileName) out Nothing -> return () -- | Update snapshot expected files from NotEqualError outputs. applySnapshotUpdate :: Paths -> TestResult -> IO TestResult applySnapshotUpdate paths res = case (trException res, trOutput res) of (Just exc, Just out) | isSnapshotMismatch exc -> do let fileName = displayTestName (trName res) snapshotDir = joinPath [projPath paths, "snapshots", "expected", trModule res] createDirectoryIfMissing True snapshotDir writeFile (snapshotDir fileName) out return (markSnapshotUpdated res) _ -> return res -- | Reuse cached snapshot results only when the on-disk snapshot metadata still -- | shows that the expected file predates the last produced output. Any -- | uncertainty forces a rerun. filterReusableCachedSnapshotResults :: (String -> IO ()) -> Paths -> [TestResult] -> IO [TestResult] filterReusableCachedSnapshotResults logCache paths = fmap catMaybes . mapM keepIfReusable where keepIfReusable res = case trOutput res of Nothing -> return (Just res) Just _ -> do reusable <- snapshotMetadataAllowsCacheHit logCache paths res if reusable then return (Just res) else return Nothing snapshotCacheLabel :: TestResult -> String snapshotCacheLabel res = trModule res ++ "." ++ trName res snapshotMetadataAllowsCacheHit :: (String -> IO ()) -> Paths -> TestResult -> IO Bool snapshotMetadataAllowsCacheHit logCache paths res = do mExpected <- readFirstExistingSnapshotMeta expectedPaths case mExpected of Nothing -> miss "missing expected snapshot" Just (expectedSize, expectedMTime) -> do mOutput <- readSnapshotMeta outputPath case mOutput of Nothing -> miss "missing snapshot output" Just (outputSize, outputMTime) | expectedSize /= outputSize -> miss "snapshot size changed" | expectedMTime >= outputMTime -> miss "snapshot expected is newer than output" | otherwise -> return True where fileName = displayTestName (trName res) expectedPaths = [ joinPath [projPath paths, "snapshots", "expected", trModule res, fileName] , joinPath [projPath paths, "test", "golden", trModule res, fileName] ] outputPath = joinPath [projPath paths, "snapshots", "output", trModule res, fileName] miss reason = do logCache ("[test-cache] " ++ snapshotCacheLabel res ++ " cache=miss (" ++ reason ++ ")") return False readFirstExistingSnapshotMeta :: [FilePath] -> IO (Maybe (Integer, UTCTime)) readFirstExistingSnapshotMeta [] = return Nothing readFirstExistingSnapshotMeta (path:rest) = do mMeta <- readSnapshotMeta path case mMeta of Just meta -> return (Just meta) Nothing -> readFirstExistingSnapshotMeta rest readSnapshotMeta :: FilePath -> IO (Maybe (Integer, UTCTime)) readSnapshotMeta path = do exists <- doesFileExist path if not exists then return Nothing else do sizeE <- (try :: IO a -> IO (Either SomeException a)) $ getFileSize path timeE <- (try :: IO a -> IO (Either SomeException a)) $ getModificationTime path case (sizeE, timeE) of (Right size, Right mtime) -> return (Just (size, mtime)) _ -> return Nothing snapshotMismatchPrefix :: String snapshotMismatchPrefix = "testing.NotEqualError: Test output does not match expected snapshot value" isSnapshotMismatch :: String -> Bool isSnapshotMismatch exc = snapshotMismatchPrefix `isPrefixOf` exc markSnapshotUpdated :: TestResult -> TestResult markSnapshotUpdated res = res { trSnapshotUpdated = True , trSuccess = Just True , trSkipped = False , trSkipReason = Nothing , trException = Nothing , trNumSkipped = 0 , trNumFailures = 0 , trNumErrors = 0 } -- | Write perf data JSON for the current test run. writePerfData :: Paths -> [TestResult] -> IO () writePerfData paths results = do let addTest acc res = let modKey = AesonKey.fromString (trModule res) testKey = AesonKey.fromString (trName res) entry = case AesonKM.lookup modKey acc of Just (Aeson.Object obj) -> obj _ -> AesonKM.empty entry' = AesonKM.insert testKey (trRaw res) entry acc' = AesonKM.insert modKey (Aeson.Object entry') acc in acc' modulesObj = foldl' addTest AesonKM.empty results outVal = Aeson.Object modulesObj outPath = joinPath [projPath paths, "perf_data"] BL.writeFile outPath (Aeson.encode outVal) -- | Run a process and stream stderr lines to a callback while capturing output. readProcessWithExitCodeStreaming :: CreateProcess -> (String -> IO ()) -> IO (ExitCode, String, String) readProcessWithExitCodeStreaming cp onErrLine = do let cp' = cp { std_in = NoStream, std_out = CreatePipe, std_err = CreatePipe } withCreateProcess cp' $ \_ mOut mErr ph -> do outVar <- newEmptyMVar errVar <- newEmptyMVar let readStdout mH var = case mH of Nothing -> putMVar var "" Just h -> do txt <- hGetContents h _ <- evaluate (length txt) hClose h putMVar var txt readStderr mH var = case mH of Nothing -> putMVar var "" Just h -> do txt <- readErrLines h hClose h putMVar var txt readErrLines h = go [] where go acc = do eof <- hIsEOF h if eof then return (unlines (reverse acc)) else do line <- hGetLine h onErrLine line go (line : acc) _ <- forkIO $ readStdout mOut outVar _ <- forkIO $ readStderr mErr errVar code <- waitForProcess ph `onException` do terminateProcess ph void (waitForProcess ph) out <- takeMVar outVar err <- takeMVar errVar return (code, out, err) fmtTime :: TimeSpec -> String fmtTime t = printf "%6.3f s" secs where secs :: Float secs = (fromIntegral (sec t)) + (fromIntegral (nsec t) / 1000000000) ================================================ FILE: compiler/acton/TestUI.hs ================================================ module TestUI ( TestKey(..) , TestProgressUI(..) , initTestProgressUI , testUiStart , testUiAppendFinal , testUiUpdateLive , testUiFinalize , testUiUpdateFinal , testUiInsertDetails , testUiProgressPercent , testUiProgressClear , queuePendingDetails , flushPendingDetails ) where import qualified Acton.CommandLineParser as C import Control.Concurrent (ThreadId, forkIO, killThread, myThreadId, threadDelay) import Control.Concurrent.MVar import Control.Monad import Data.IORef import qualified Data.List import qualified Data.Map as M import Data.Ord (Down(..)) import qualified Data.Set as Set import System.IO (hFlush, hIsTerminalDevice, stdout) import TerminalProgress import TerminalSize data TestKey = TestKey { tkModule :: String , tkName :: String } deriving (Eq, Ord, Show) type TestLine = Int -> String data TestProgressUI = TestProgressUI { tpuEnabled :: Bool , tpuTotalLinesRef :: IORef Int , tpuLinesRef :: IORef [String] , tpuLineRenderRef :: IORef [TestLine] , tpuLineIndexRef :: IORef (M.Map TestKey Int) , tpuLiveOrderRef :: IORef [TestKey] , tpuLiveSetRef :: IORef (Set.Set TestKey) , tpuLiveLineRef :: IORef (M.Map TestKey TestLine) , tpuPrintedModulesRef :: IORef (Set.Set String) , tpuPendingDetailsRef :: IORef (M.Map TestKey [String]) , tpuSpinnerRef :: IORef Int , tpuTickerThreadRef :: IORef (Maybe ThreadId) , tpuTermProgress :: TermProgress , tpuTermSize :: TermSize , tpuLock :: MVar () , tpuNameWidth :: Int , tpuUseColor :: Bool , tpuShowLog :: Bool } initTestProgressUI :: C.GlobalOptions -> Int -> Bool -> Bool -> IO TestProgressUI initTestProgressUI gopts nameWidth showLog useColorOut = do tty <- hIsTerminalDevice stdout let enabled = (tty || C.tty gopts) && not (C.quiet gopts) totalLinesRef <- newIORef 0 linesRef <- newIORef [] lineRenderRef <- newIORef [] lineIndexRef <- newIORef M.empty liveOrderRef <- newIORef [] liveSetRef <- newIORef Set.empty liveLineRef <- newIORef M.empty printedModulesRef <- newIORef Set.empty pendingDetailsRef <- newIORef M.empty spinnerRef <- newIORef 0 tickerThreadRef <- newIORef Nothing termProgress <- initTermProgress gopts termSize <- initTermSize enabled lock <- newMVar () return TestProgressUI { tpuEnabled = enabled , tpuTotalLinesRef = totalLinesRef , tpuLinesRef = linesRef , tpuLineRenderRef = lineRenderRef , tpuLineIndexRef = lineIndexRef , tpuLiveOrderRef = liveOrderRef , tpuLiveSetRef = liveSetRef , tpuLiveLineRef = liveLineRef , tpuPrintedModulesRef = printedModulesRef , tpuPendingDetailsRef = pendingDetailsRef , tpuSpinnerRef = spinnerRef , tpuTickerThreadRef = tickerThreadRef , tpuTermProgress = termProgress , tpuTermSize = termSize , tpuLock = lock , tpuNameWidth = nameWidth , tpuUseColor = useColorOut , tpuShowLog = showLog } withTestProgressLock :: TestProgressUI -> IO a -> IO a withTestProgressLock ui action = if not (tpuEnabled ui) then action else withMVar (tpuLock ui) (\_ -> action) testUiProgressPercent :: TestProgressUI -> Int -> IO () testUiProgressPercent ui pct = withTestProgressLock ui (termProgressPercent (tpuTermProgress ui) pct) testUiProgressClear :: TestProgressUI -> IO () testUiProgressClear ui = withTestProgressLock ui (termProgressClear (tpuTermProgress ui)) testTickMicros :: Int testTickMicros = 80000 testSpinnerThreshold :: Int testSpinnerThreshold = 25 testSpinnerChars :: [Char] testSpinnerChars = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏" testSpinnerEnabled :: Int -> Bool testSpinnerEnabled cols = cols >= testSpinnerThreshold testSpinnerChar :: TestProgressUI -> IO Char testSpinnerChar ui = do ix <- readIORef (tpuSpinnerRef ui) return (testSpinnerChars !! (ix `mod` length testSpinnerChars)) moduleHeaderLine :: String -> String moduleHeaderLine modName | null modName = "Tests" | otherwise = "Tests - module " ++ modName ++ ":" safeLiveWidth :: Int -> Int safeLiveWidth width | width <= 0 = 0 | width == 1 = 1 | otherwise = width - 1 staticLine :: String -> TestLine staticLine line cols = termFitAnsiRight cols line visibleLineCapacity :: Int -> Int visibleLineCapacity rows = max 0 (rows - 1) visibleStartIndex :: Int -> Int -> Int visibleStartIndex rows total = max 0 (total - visibleLineCapacity rows) startTestTicker :: TestProgressUI -> IO () startTestTicker ui = when (tpuEnabled ui) $ do m <- readIORef (tpuTickerThreadRef ui) case m of Just _ -> return () Nothing -> do tid <- forkIO (testTickerLoop ui) writeIORef (tpuTickerThreadRef ui) (Just tid) stopTestTicker :: TestProgressUI -> IO () stopTestTicker ui = do m <- atomicModifyIORef' (tpuTickerThreadRef ui) (\cur -> (Nothing, cur)) forM_ m killThread testTickerLoop :: TestProgressUI -> IO () testTickerLoop ui = do tid <- myThreadId let loop = do threadDelay testTickMicros keep <- withTestProgressLock ui $ do liveSet <- readIORef (tpuLiveSetRef ui) if Set.null liveSet || not (tpuEnabled ui) then return False else do (_, cols) <- ensureViewportUnlocked ui when (testSpinnerEnabled cols) $ do modifyIORef' (tpuSpinnerRef ui) (+ 1) refreshTestSpinnersUnlocked ui cols termProgressHeartbeat (tpuTermProgress ui) return True when keep loop loop atomicModifyIORef' (tpuTickerThreadRef ui) $ \cur -> if cur == Just tid then (Nothing, ()) else (cur, ()) currentViewportUnlocked :: TestProgressUI -> IO (Int, Int) currentViewportUnlocked ui = termSizeCurrent (tpuTermSize ui) ensureViewportUnlocked :: TestProgressUI -> IO (Int, Int) ensureViewportUnlocked ui | not (tpuEnabled ui) = return (0, 0) | otherwise = do (oldRows, _) <- termSizeCurrent (tpuTermSize ui) (changed, rows, cols) <- termSizeSync (tpuTermSize ui) when changed $ rerenderVisibleUnlocked ui oldRows rows cols return (rows, cols) appendLineUnlocked :: TestProgressUI -> TestLine -> IO Int appendLineUnlocked ui lineFn = do idx <- readIORef (tpuTotalLinesRef ui) rendered <- renderIndexedLineUnlocked ui idx lineFn putStrLn rendered modifyIORef' (tpuLinesRef ui) (\xs -> xs ++ [rendered]) modifyIORef' (tpuLineRenderRef ui) (\xs -> xs ++ [lineFn]) writeIORef (tpuTotalLinesRef ui) (idx + 1) return idx updateLineListAt :: Int -> a -> [a] -> [a] updateLineListAt idx line xs = case splitAt idx xs of (prefix, _ : rest) -> prefix ++ [line] ++ rest _ -> xs insertLinesListAfter :: Int -> [a] -> [a] -> [a] insertLinesListAfter idx newLines xs = let (prefix, rest) = splitAt (idx + 1) xs in prefix ++ newLines ++ rest rerenderVisibleUnlocked :: TestProgressUI -> Int -> Int -> Int -> IO () rerenderVisibleUnlocked ui rowsBefore rowsAfter cols = do total <- readIORef (tpuTotalLinesRef ui) lineFns <- readIORef (tpuLineRenderRef ui) renderedAll <- mapM (\(idx, lineFn) -> renderIndexedLineWithColsUnlocked ui cols idx lineFn) (zip [0..] lineFns) let oldStartIdx = visibleStartIndex rowsBefore total newStartIdx = visibleStartIndex rowsAfter total oldVisibleCount = max 0 (total - oldStartIdx) newVisible = drop newStartIdx renderedAll when (oldVisibleCount > 0) $ putStr ("\ESC[" ++ show oldVisibleCount ++ "A") when (oldVisibleCount > 0 || not (null newVisible)) $ do putStr "\r\ESC[J" forM_ newVisible $ \line -> do putStr "\r\ESC[2K" putStr line putStr "\n" hFlush stdout writeIORef (tpuLinesRef ui) renderedAll refreshTestSpinnersUnlocked :: TestProgressUI -> Int -> IO () refreshTestSpinnersUnlocked ui cols = do idxMap <- readIORef (tpuLineIndexRef ui) liveLines <- readIORef (tpuLiveLineRef ui) forM_ (M.toList liveLines) $ \(key, lineFn) -> case M.lookup key idxMap of Just idx -> updateLineAtUnlockedWithCols ui cols idx lineFn Nothing -> return () renderLiveLine :: Int -> Char -> String -> String renderLiveLine cols spinner line | not (testSpinnerEnabled cols) = line | otherwise = case line of ' ':' ':' ':rest -> ' ' : spinner : ' ' : rest _ -> line isLiveLineIndexUnlocked :: TestProgressUI -> Int -> IO Bool isLiveLineIndexUnlocked ui idx = do liveSet <- readIORef (tpuLiveSetRef ui) idxMap <- readIORef (tpuLineIndexRef ui) return (any (\key -> M.lookup key idxMap == Just idx) (Set.toList liveSet)) renderIndexedLineWithColsUnlocked :: TestProgressUI -> Int -> Int -> TestLine -> IO String renderIndexedLineWithColsUnlocked ui cols idx lineFn = do let base = lineFn (safeLiveWidth cols) live <- isLiveLineIndexUnlocked ui idx if live then do spinner <- testSpinnerChar ui return (renderLiveLine cols spinner base) else return base renderIndexedLineUnlocked :: TestProgressUI -> Int -> TestLine -> IO String renderIndexedLineUnlocked ui idx lineFn = do (_, cols) <- currentViewportUnlocked ui renderIndexedLineWithColsUnlocked ui cols idx lineFn ensureModuleHeaderUnlocked :: TestProgressUI -> String -> IO () ensureModuleHeaderUnlocked ui modName = do printed <- readIORef (tpuPrintedModulesRef ui) unless (Set.member modName printed) $ do total <- readIORef (tpuTotalLinesRef ui) when (total > 0) $ void (appendLineUnlocked ui (staticLine "")) _ <- appendLineUnlocked ui (staticLine (moduleHeaderLine modName)) writeIORef (tpuPrintedModulesRef ui) (Set.insert modName printed) canAppendLinesUnlocked :: TestProgressUI -> Int -> IO Bool canAppendLinesUnlocked ui n | not (tpuEnabled ui) = return True | n <= 0 = return True | otherwise = do (rows, _) <- currentViewportUnlocked ui if rows <= 0 then return True else do liveOrder <- readIORef (tpuLiveOrderRef ui) case liveOrder of [] -> return True (oldest:_) -> do total <- readIORef (tpuTotalLinesRef ui) idxMap <- readIORef (tpuLineIndexRef ui) case M.lookup oldest idxMap of Nothing -> return True Just idx -> do let offset = total - idx return (offset + n < rows) testUiStart :: TestProgressUI -> TestKey -> String -> TestLine -> IO Bool testUiStart ui key modName lineFn = withTestProgressLock ui $ do if not (tpuEnabled ui) then return True else do void (ensureViewportUnlocked ui) printed <- readIORef (tpuPrintedModulesRef ui) total <- readIORef (tpuTotalLinesRef ui) let headerNeeded = not (Set.member modName printed) headerLines = if headerNeeded then if total > 0 then 2 else 1 else 0 linesNeeded = headerLines + 1 ok <- canAppendLinesUnlocked ui linesNeeded if not ok then return False else do ensureModuleHeaderUnlocked ui modName idx <- readIORef (tpuTotalLinesRef ui) modifyIORef' (tpuLineIndexRef ui) (M.insert key idx) modifyIORef' (tpuLiveOrderRef ui) (\xs -> if key `elem` xs then xs else xs ++ [key]) modifyIORef' (tpuLiveSetRef ui) (Set.insert key) modifyIORef' (tpuLiveLineRef ui) (M.insert key lineFn) _ <- appendLineUnlocked ui lineFn startTestTicker ui return True testUiAppendFinal :: TestProgressUI -> TestKey -> String -> TestLine -> IO Bool testUiAppendFinal ui key modName lineFn = withTestProgressLock ui $ do if not (tpuEnabled ui) then return True else do void (ensureViewportUnlocked ui) printed <- readIORef (tpuPrintedModulesRef ui) total <- readIORef (tpuTotalLinesRef ui) let headerNeeded = not (Set.member modName printed) headerLines = if headerNeeded then if total > 0 then 2 else 1 else 0 linesNeeded = headerLines + 1 ok <- canAppendLinesUnlocked ui linesNeeded if not ok then return False else do ensureModuleHeaderUnlocked ui modName idx <- appendLineUnlocked ui lineFn modifyIORef' (tpuLineIndexRef ui) (M.insert key idx) return True updateLineAtUnlocked :: TestProgressUI -> Int -> TestLine -> IO () updateLineAtUnlocked ui idx lineFn = do (_, cols) <- currentViewportUnlocked ui updateLineAtUnlockedWithCols ui cols idx lineFn updateLineAtUnlockedWithCols :: TestProgressUI -> Int -> Int -> TestLine -> IO () updateLineAtUnlockedWithCols ui cols idx lineFn = do rendered <- renderIndexedLineWithColsUnlocked ui cols idx lineFn modifyIORef' (tpuLineRenderRef ui) (updateLineListAt idx lineFn) modifyIORef' (tpuLinesRef ui) (updateLineListAt idx rendered) total <- readIORef (tpuTotalLinesRef ui) (rows, _) <- currentViewportUnlocked ui let offset = total - idx when (offset > 0 && (rows <= 0 || offset < rows)) $ do putStr ("\ESC[" ++ show offset ++ "A") putStr "\r\ESC[2K" putStr rendered putStr ("\ESC[" ++ show offset ++ "B") putStr "\r" hFlush stdout testUiUpdateLive :: TestProgressUI -> TestKey -> TestLine -> IO () testUiUpdateLive ui key lineFn = withTestProgressLock ui $ do when (tpuEnabled ui) $ do void (ensureViewportUnlocked ui) idxMap <- readIORef (tpuLineIndexRef ui) case M.lookup key idxMap of Nothing -> return () Just idx -> do modifyIORef' (tpuLiveLineRef ui) (M.insert key lineFn) updateLineAtUnlocked ui idx lineFn testUiFinalize :: TestProgressUI -> TestKey -> TestLine -> IO Bool testUiFinalize ui key lineFn = withTestProgressLock ui $ do liveSet <- readIORef (tpuLiveSetRef ui) let wasLive = Set.member key liveSet when wasLive $ do writeIORef (tpuLiveSetRef ui) (Set.delete key liveSet) modifyIORef' (tpuLiveOrderRef ui) (filter (/= key)) modifyIORef' (tpuLiveLineRef ui) (M.delete key) when (tpuEnabled ui) $ do void (ensureViewportUnlocked ui) idxMap <- readIORef (tpuLineIndexRef ui) case M.lookup key idxMap of Nothing -> return () Just idx -> updateLineAtUnlocked ui idx lineFn if wasLive then do liveSet' <- readIORef (tpuLiveSetRef ui) when (tpuEnabled ui && Set.null liveSet') $ stopTestTicker ui return True else return False testUiUpdateFinal :: TestProgressUI -> TestKey -> TestLine -> IO () testUiUpdateFinal ui key lineFn = withTestProgressLock ui $ do when (tpuEnabled ui) $ do void (ensureViewportUnlocked ui) idxMap <- readIORef (tpuLineIndexRef ui) case M.lookup key idxMap of Nothing -> return () Just idx -> updateLineAtUnlocked ui idx lineFn canInsertLinesUnlocked :: TestProgressUI -> Int -> Int -> IO Bool canInsertLinesUnlocked ui insertIdx n | not (tpuEnabled ui) = return True | n <= 0 = return True | otherwise = do (rows, _) <- currentViewportUnlocked ui if rows <= 0 then return True else do liveSet <- readIORef (tpuLiveSetRef ui) idxMap <- readIORef (tpuLineIndexRef ui) let idxs = [ idx | key <- Set.toList liveSet , Just idx <- [M.lookup key idxMap] , idx <= insertIdx ] case idxs of [] -> return True _ -> do total <- readIORef (tpuTotalLinesRef ui) return ((total + n - minimum idxs) < rows) insertLinesAfterUnlocked :: TestProgressUI -> Int -> [String] -> IO Bool insertLinesAfterUnlocked ui idx lines = do let n = length lines if n <= 0 then return True else do (rows, cols) <- currentViewportUnlocked ui total <- readIORef (tpuTotalLinesRef ui) liveSet <- readIORef (tpuLiveSetRef ui) let lineFns = map staticLine lines rendered = map ($ safeLiveWidth cols) lineFns startIdx = idx + 1 offsetNew = (total + n) - startIdx visibleOk = Set.null liveSet || not (tpuEnabled ui) || rows <= 0 || offsetNew < rows ok <- canInsertLinesUnlocked ui idx n if not ok || not visibleOk then return False else do modifyIORef' (tpuLineRenderRef ui) (insertLinesListAfter idx lineFns) modifyIORef' (tpuLinesRef ui) (insertLinesListAfter idx rendered) modifyIORef' (tpuTotalLinesRef ui) (+ n) modifyIORef' (tpuLineIndexRef ui) (M.map (\i -> if i > idx then i + n else i)) if not (tpuEnabled ui) then mapM_ putStrLn rendered else rerenderFromUnlocked ui startIdx total return True rerenderFromUnlocked :: TestProgressUI -> Int -> Int -> IO () rerenderFromUnlocked ui startIdx oldTotal = do let offset = oldTotal - startIdx renderedLines <- readIORef (tpuLinesRef ui) (rows, _) <- currentViewportUnlocked ui let renderedTail = drop startIdx renderedLines if offset <= 0 then do forM_ renderedTail $ \line -> do putStr "\r\ESC[2K" putStr line putStr "\n" hFlush stdout else when (rows <= 0 || offset < rows) $ do putStr ("\ESC[" ++ show offset ++ "A") putStr "\r\ESC[J" forM_ renderedTail $ \line -> do putStr "\r\ESC[2K" putStr line putStr "\n" hFlush stdout testUiInsertDetails :: TestProgressUI -> TestKey -> [String] -> IO Bool testUiInsertDetails ui key lines = withTestProgressLock ui $ do if null lines then return True else if not (tpuEnabled ui) then return True else do void (ensureViewportUnlocked ui) idxMap <- readIORef (tpuLineIndexRef ui) case M.lookup key idxMap of Nothing -> return False Just idx -> insertLinesAfterUnlocked ui idx lines queuePendingDetails :: TestProgressUI -> TestKey -> [String] -> IO () queuePendingDetails ui key lines = withTestProgressLock ui $ do unless (null lines) $ modifyIORef' (tpuPendingDetailsRef ui) (M.insert key lines) flushPendingDetails :: TestProgressUI -> IO () flushPendingDetails ui = withTestProgressLock ui $ do void (ensureViewportUnlocked ui) pending <- readIORef (tpuPendingDetailsRef ui) unless (M.null pending) $ do idxMap <- readIORef (tpuLineIndexRef ui) let withIdx = Data.List.sortOn (\(idx, _, _) -> Down idx) [ (idx, key, lines) | (key, lines) <- M.toList pending , Just idx <- [M.lookup key idxMap] ] let go cur [] = return cur go cur ((idx, key, lines):rest) = do ok <- insertLinesAfterUnlocked ui idx lines if ok then go (M.delete key cur) rest else go cur rest pending' <- go pending withIdx writeIORef (tpuPendingDetailsRef ui) pending' ================================================ FILE: compiler/acton/ZigProgress.hs ================================================ module ZigProgress ( ZigProgress(..) , ZigNode(..) , parseZigProgressMessages , zigProgressRatio , readZigProgressStream ) where import Control.Exception (IOException, try) import Data.Bits import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as BSC import Data.List (foldl') import qualified Data.Set as Set import Data.Word (Word8, Word32) import qualified System.Posix.IO.ByteString as PIOB import System.Posix.Types (Fd) data ZigNode = ZigNode { znCompleted :: Word32 , znTotal :: Word32 , znName :: String , znParent :: Maybe Int } deriving (Show) data ZigProgress = ZigProgress { zpNodes :: [ZigNode] } deriving (Show) readZigProgressStream :: Fd -> (ZigProgress -> IO ()) -> IO () readZigProgressStream fd onMsg = go BS.empty where go buf = do res <- (try (PIOB.fdRead fd 4096) :: IO (Either IOException BS.ByteString)) case res of Left _ -> return () Right chunk | BS.null chunk -> return () Right chunk -> do let buf' = BS.append buf chunk (msgs, rest) = parseZigProgressMessages buf' mapM_ onMsg msgs go rest parseZigProgressMessages :: BS.ByteString -> ([ZigProgress], BS.ByteString) parseZigProgressMessages bs = go [] bs where go acc buf | BS.length buf < 1 = (reverse acc, buf) | otherwise = let len = fromIntegral (BS.index buf 0) :: Int in if len == 0xfe || len == 0xff then go acc (BS.drop 1 buf) else let msgLen = 1 + (len * 49) in if BS.length buf < msgLen then (reverse acc, buf) else let msgBytes = BS.take msgLen buf rest = BS.drop msgLen buf msg = decodeMessage len msgBytes in go (msg : acc) rest decodeMessage :: Int -> BS.ByteString -> ZigProgress decodeMessage len msgBytes = let nodeBytes = BS.take (len * 48) (BS.drop 1 msgBytes) parentBytes = BS.drop (1 + len * 48) msgBytes nodes = [ decodeNode i nodeBytes parentBytes | i <- [0..len - 1] ] in ZigProgress { zpNodes = nodes } decodeNode :: Int -> BS.ByteString -> BS.ByteString -> ZigNode decodeNode ix nodeBytes parentBytes = let base = ix * 48 completed = word32le nodeBytes base total = word32le nodeBytes (base + 4) nameBytes = BS.take 40 (BS.drop (base + 8) nodeBytes) name = BSC.unpack (BS.takeWhile (/= 0) nameBytes) parentRaw = if ix < BS.length parentBytes then BS.index parentBytes ix else 0xff parent = if parentRaw == 0xff then Nothing else Just (fromIntegral parentRaw) in ZigNode { znCompleted = completed , znTotal = total , znName = name , znParent = parent } word32le :: BS.ByteString -> Int -> Word32 word32le bs offset = let b0 = byteAt 0 b1 = byteAt 1 b2 = byteAt 2 b3 = byteAt 3 in (fromIntegral b0) .|. (fromIntegral b1 `shiftL` 8) .|. (fromIntegral b2 `shiftL` 16) .|. (fromIntegral b3 `shiftL` 24) where byteAt i = if offset + i < BS.length bs then BS.index bs (offset + i) else (0 :: Word8) zigProgressRatio :: ZigProgress -> Maybe Double zigProgressRatio progress = let nodes = zpNodes progress indexed = zip [0..] nodes totals = [ (i, clampTotal (znCompleted n) (znTotal n), znTotal n, znParent n) | (i, n) <- indexed , znTotal n > 0 ] parentsWithTotals = Set.fromList [ p | (_, _, _, Just p) <- totals ] candidates = [ (c, t) | (i, c, t, _) <- totals, not (Set.member i parentsWithTotals) ] (sumC, sumT) = foldl' (\(cAcc, tAcc) (c, t) -> (cAcc + fromIntegral c, tAcc + fromIntegral t)) (0, 0) candidates in if sumT <= 0 then Nothing else Just (min 1.0 (sumC / sumT)) where clampTotal c t = if c > t then t else c ================================================ FILE: compiler/acton/package.yaml.in ================================================ name: acton version: BUILD_VERSION # github: "/simple" license: BSD3 author: "Johan Nordlander, Björn von Sydow, Kristian Larsson" maintainer: "example@example.com" copyright: "Data Ductus, Deutsche Telekom" # Metadata used when publishing your package # synopsis: Short description of your package # category: Web # To avoid duplicated efforts in documentation and dealing with the # complications of embedding Haddock markup inside cabal files, it is # common to point users to the README.md file. description: Please see the README on Github at dependencies: - MissingH - libacton - aeson - async - base >= 4.7 && < 5 - base16-bytestring - binary - bytestring - clock - containers - pretty - cryptohash-sha256 - data-default-class - diagnose - dir-traverse - directory >= 1.3.1 - filelock - filepath - fsnotify - http-client - http-client-tls - http-types - optparse-applicative - megaparsec - prettyprinter - pretty-show - process - random - split - system-filepath - sydtest - tasty - tasty-expected-failure - tasty-golden - tasty-hunit - text - temporary - time - timeit - unix - unordered-containers - regex-tdfa executables: acton: main: Main.hs source-dirs: . other-modules: - PkgCommands - Paths_acton - TerminalProgress - TerminalSize - ZigProgress - TestFormat - TestRunner - TestUI ghc-options: - -threaded - -rtsopts - '"-with-rtsopts=-N -A64M"' when: - condition: os(linux) ghc-options: - -no-pie - -optl-no-pie - -pgml=../tools/ld-wrapper.sh tests: test_acton: main: test.hs source-dirs: . ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N incremental: main: test_incremental.hs source-dirs: . ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N test_acton_online: main: test_online.hs source-dirs: . ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N ================================================ FILE: compiler/acton/test/incremental_cases/.gitignore ================================================ /Build.act /src/ /deps/ /out/ /build.zig* /.acton.compile.lock /.acton.lock ================================================ FILE: compiler/acton/test/parse/simple.act ================================================ def main(): print("Hello parse!") ================================================ FILE: compiler/acton/test/parse/simple.all.golden ================================================ == parse: simple ================================ def main (): print("Hello parse!") ================================================= == kinds: simple ================================ T_9w def main () -> T_5w: print("Hello parse!") ================================================= == types: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](*("Hello parse!",), sep = None, end = None, err = None, flush = None) ================================================= == sigs: simple ================================ main : () -> None ================================================ == norm: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](("\"Hello parse!\"",), None, None, None, None) return None ================================================ == deact: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](("\"Hello parse!\"",), None, None, None, None) return None ================================================= == cps: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](("\"Hello parse!\"",), None, None, None, None) return None =============================================== == llift: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](("\"Hello parse!\"",), None, None, None, None) return None ================================================= == box: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](("\"Hello parse!\"",), None, None, None, None) return None =============================================== /* Acton impl hash: 90d154672dec39acdfe73f54da1124538a944a4989833b41555c4693f4283455 */ #pragma once #include "builtin/builtin.h" #include "rts/rts.h" B_NoneType simpleQ_main (); void simpleQ___init__ (); ================================================ FILE: compiler/acton/test/parse/simple.box.golden ================================================ == box: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](("\"Hello parse!\"",), None, None, None, None) return None =============================================== ================================================ FILE: compiler/acton/test/parse/simple.cgen.golden ================================================ /* Acton impl hash: 90d154672dec39acdfe73f54da1124538a944a4989833b41555c4693f4283455 */ #include "rts/common.h" #include "out/types/simple.h" B_NoneType simpleQ_main () { ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("Hello parse!")), B_None, B_None, B_None, B_None); return B_None; } int simpleQ_done$ = 0; void simpleQ___init__ () { if (simpleQ_done$) return; simpleQ_done$ = 1; } ================================================ FILE: compiler/acton/test/parse/simple.cps.golden ================================================ == cps: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](("\"Hello parse!\"",), None, None, None, None) return None =============================================== ================================================ FILE: compiler/acton/test/parse/simple.deact.golden ================================================ == deact: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](("\"Hello parse!\"",), None, None, None, None) return None ================================================= ================================================ FILE: compiler/acton/test/parse/simple.golden ================================================ == parse: simple ================================ def main (): print("Hello parse!") ================================================= ================================================ FILE: compiler/acton/test/parse/simple.hgen.golden ================================================ /* Acton impl hash: 90d154672dec39acdfe73f54da1124538a944a4989833b41555c4693f4283455 */ #pragma once #include "builtin/builtin.h" #include "rts/rts.h" B_NoneType simpleQ_main (); void simpleQ___init__ (); ================================================ FILE: compiler/acton/test/parse/simple.kinds.golden ================================================ == kinds: simple ================================ T_9w def main () -> T_5w: print("Hello parse!") ================================================= ================================================ FILE: compiler/acton/test/parse/simple.llift.golden ================================================ == llift: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](("\"Hello parse!\"",), None, None, None, None) return None ================================================= ================================================ FILE: compiler/acton/test/parse/simple.norm.golden ================================================ == norm: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](("\"Hello parse!\"",), None, None, None, None) return None ================================================ ================================================ FILE: compiler/acton/test/parse/simple.sigs.golden ================================================ == sigs: simple ================================ main : () -> None ================================================ ================================================ FILE: compiler/acton/test/parse/simple.types.golden ================================================ == types: simple ================================ pure def main () -> None: print@[(__builtin__.str,)](*("Hello parse!",), sep = None, end = None, err = None, flush = None) ================================================= ================================================ FILE: compiler/acton/test/project/auto_root/.gitignore ================================================ build.zig* ================================================ FILE: compiler/acton/test/project/auto_root/Build.act ================================================ name = "auto_root" fingerprint = 0x25d729578a471226 ================================================ FILE: compiler/acton/test/project/auto_root/src/b.act ================================================ def foo(): print("auto_root foo") ================================================ FILE: compiler/acton/test/project/auto_root/src/test.act ================================================ import b actor main(env): b.foo() env.exit(0) ================================================ FILE: compiler/acton/test/project/conf_2bin/.gitignore ================================================ build.zig* ================================================ FILE: compiler/acton/test/project/conf_2bin/Build.act ================================================ name = "conf_2bin" fingerprint = 0x3a0f2be8959f1099 bins = { "a": "a.main", "b": "b.main", "b2": "b.altroot" } ================================================ FILE: compiler/acton/test/project/conf_2bin/src/a.act ================================================ actor main(env): print("a") env.exit(0) ================================================ FILE: compiler/acton/test/project/conf_2bin/src/b.act ================================================ actor main(env): print("b") env.exit(0) ================================================ FILE: compiler/acton/test/project/missing_src/.gitignore ================================================ build.zig* ================================================ FILE: compiler/acton/test/project/missing_src/Build.act ================================================ name = "missing_src" fingerprint = 0x3d6d0220ba420c23 ================================================ FILE: compiler/acton/test/project/prune_executables/.gitignore ================================================ build.zig* ================================================ FILE: compiler/acton/test/project/prune_executables/Build.act ================================================ name = "prune_executables" fingerprint = 0xdd6b7ba1f8e40503 ================================================ FILE: compiler/acton/test/project/prune_executables/src/bar.act ================================================ actor main(env): print("bar") env.exit(0) ================================================ FILE: compiler/acton/test/project/prune_executables/src/foo.act ================================================ import testing def _test_basic(): testing.assertEqual(1, 1) actor main(env): print("foo") env.exit(0) ================================================ FILE: compiler/acton/test/project/prune_executables/src/tests/simple.act ================================================ import testing def _test_basic(): testing.assertEqual(1, 1) ================================================ FILE: compiler/acton/test/project/prune_partials/.gitignore ================================================ build.zig* ================================================ FILE: compiler/acton/test/project/prune_partials/Build.act ================================================ name = "prune_partials" fingerprint = 0x014428b3365086ba ================================================ FILE: compiler/acton/test/project/prune_partials/src/bar.act ================================================ actor main(env): print("bar") env.exit(0) ================================================ FILE: compiler/acton/test/project/prune_partials/src/foo.act ================================================ actor main(env): print("foo") env.exit(0) ================================================ FILE: compiler/acton/test/project/prune_roots/.gitignore ================================================ build.zig* ================================================ FILE: compiler/acton/test/project/prune_roots/Build.act ================================================ name = "prune_roots" fingerprint = 0x1d991f5a9ab61159 ================================================ FILE: compiler/acton/test/project/prune_roots/src/foo.act ================================================ actor main(env): print("foo") env.exit(0) ================================================ FILE: compiler/acton/test/project/qualified_root/.gitignore ================================================ build.zig* ================================================ FILE: compiler/acton/test/project/qualified_root/Build.act ================================================ name = "qualified_root" fingerprint = 0xe20efcacd51a52a5 ================================================ FILE: compiler/acton/test/project/qualified_root/src/b.act ================================================ def foo(): print("qualified_root foo") ================================================ FILE: compiler/acton/test/project/qualified_root/src/test.act ================================================ import b actor main(env): b.foo() env.exit(0) ================================================ FILE: compiler/acton/test/project/simple/.gitignore ================================================ build.zig* ================================================ FILE: compiler/acton/test/project/simple/Build.act ================================================ name = "simple" fingerprint = 0xc17b3d02f0801944 ================================================ FILE: compiler/acton/test/project/simple/src/a.act ================================================ import b ================================================ FILE: compiler/acton/test/project/simple/src/b.act ================================================ def foo(): print("b") ================================================ FILE: compiler/acton/test/rebuild/.gitignore ================================================ /src/ /deps/ /out/ /build.zig* /.acton.compile.lock /.acton.lock ================================================ FILE: compiler/acton/test/rebuild/Build.act ================================================ name = "rebuild" fingerprint = 0xc5208553327e37b8 ================================================ FILE: compiler/acton/test/rebuild/golden/file_02-initial-build.golden ================================================ Building file src/c.act in project . Resolving dependencies (fetching if missing)... a Parse done 0.000 s Stale a: source changed a Type check done 0.000 s Non-total inferred signature: aaa aaa : int b Parse done 0.000 s Stale b: source changed b Type check done 0.000 s Non-total inferred signature: baa baa : () -> int c Parse done 0.000 s Stale c: source changed c Type check done 0.000 s a Compilation done 0.000 s b Compilation done 0.000 s c Compilation done 0.000 s Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/file_03-up-to-date.golden ================================================ Building file src/c.act in project . Resolving dependencies (fetching if missing)... Fresh a: using cached .ty Fresh b: using cached .ty Fresh c: using cached .ty Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/file_04-touch-no-rebuild.golden ================================================ Building file src/c.act in project . Resolving dependencies (fetching if missing)... Fresh a: using cached .ty Fresh b: using cached .ty Fresh c: using cached .ty Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/file_06-change-a-impl.golden ================================================ Building file src/c.act in project . Resolving dependencies (fetching if missing)... a Parse done 0.000 s Stale a: source changed Hash deltas a: ~aaa{src HASH1 -> HASH2, impl HASH1 -> HASH2} a Type check done 0.000 s Non-total inferred signature: aaa aaa : int Stale b: impl changes in a.aaa HASH1 → HASH2 (used by baa) Stale c: impl changes in b.baa HASH1 → HASH2 (used by main) a Compilation done 0.000 s b Compilation done 0.000 s c Compilation done 0.000 s Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/file_08-change-b-impl.golden ================================================ Building file src/c.act in project . Resolving dependencies (fetching if missing)... Fresh a: using cached .ty b Parse done 0.000 s Stale b: source changed Hash deltas b: +DocInfo, ~baa{src HASH1 -> HASH2, impl HASH1 -> HASH2} b Type check done 0.000 s Non-total inferred signature: baa baa : () -> int Non-total inferred signature: DocInfo class DocInfo (value): G_init : () -> None get : () -> int Stale c: impl changes in b.baa HASH1 → HASH2 (used by main) b Compilation done 0.000 s c Compilation done 0.000 s Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/project_02-initial-build.golden ================================================ Resolving dependencies (fetching if missing)... a Parse done 0.000 s Stale a: source changed a Type check done 0.000 s Non-total inferred signature: aaa aaa : int b Parse done 0.000 s Stale b: source changed b Type check done 0.000 s Non-total inferred signature: baa baa : () -> int Non-total inferred signature: DocInfo class DocInfo (value): G_init : () -> None get : () -> int c Parse done 0.000 s Stale c: source changed c Type check done 0.000 s a Compilation done 0.000 s b Compilation done 0.000 s c Compilation done 0.000 s Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/project_03-up-to-date.golden ================================================ Resolving dependencies (fetching if missing)... Fresh a: using cached .ty Fresh b: using cached .ty Fresh c: using cached .ty Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/project_04-touch-no-rebuild.golden ================================================ Resolving dependencies (fetching if missing)... Fresh a: using cached .ty Fresh b: using cached .ty Fresh c: using cached .ty Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/project_06-change-a-impl.golden ================================================ Resolving dependencies (fetching if missing)... a Parse done 0.000 s Stale a: source changed Hash deltas a: ~aaa{src HASH1 -> HASH2, impl HASH1 -> HASH2} a Type check done 0.000 s Non-total inferred signature: aaa aaa : int Stale b: impl changes in a.aaa HASH1 → HASH2 (used by baa) Stale c: impl changes in b.baa HASH1 → HASH2 (used by main) a Compilation done 0.000 s b Compilation done 0.000 s c Compilation done 0.000 s Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/project_08-change-b-impl.golden ================================================ Resolving dependencies (fetching if missing)... Fresh a: using cached .ty b Parse done 0.000 s Stale b: source changed Hash deltas b: ~baa{src HASH1 -> HASH2, impl HASH1 -> HASH2} b Type check done 0.000 s Non-total inferred signature: baa baa : () -> int Non-total inferred signature: DocInfo class DocInfo (value): G_init : () -> None get : () -> int Stale c: impl changes in b.baa HASH1 → HASH2 (used by main) b Compilation done 0.000 s c Compilation done 0.000 s Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/project_10-change-a-iface.golden ================================================ Resolving dependencies (fetching if missing)... a Parse done 0.000 s Stale a: source changed Hash deltas a: -W_aaa_3, ~aaa{src HASH1 -> HASH2, pub HASH1 -> HASH2, impl HASH1 -> HASH2} a Type check done 0.000 s Non-total inferred signature: aaa aaa : str Stale b: pub changes in a.aaa HASH1 → HASH2 (used by baa) Hash deltas b: ~baa{pub HASH1 -> HASH2, impl HASH1 -> HASH2} b Type check done 0.000 s Non-total inferred signature: baa baa : () -> str Non-total inferred signature: DocInfo class DocInfo (value): G_init : () -> None get : () -> int Stale c: pub changes in b.baa HASH1 → HASH2 (used by main) Hash deltas c: ~main{impl HASH1 -> HASH2} c Type check done 0.000 s a Compilation done 0.000 s b Compilation done 0.000 s c Compilation done 0.000 s Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/project_11-change-b-doc.golden ================================================ Resolving dependencies (fetching if missing)... Fresh a: using cached .ty b Parse done 0.000 s Stale b: source changed Hash deltas b: ~DocInfo{src HASH1 -> HASH2, impl HASH1 -> HASH2} b Type check done 0.000 s Non-total inferred signature: baa baa : () -> str Non-total inferred signature: DocInfo class DocInfo (value): G_init : () -> None get : () -> int Fresh c: using cached .ty b Compilation done 0.000 s Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/rebuild/golden/project_12-codegen-stale.golden ================================================ Resolving dependencies (fetching if missing)... Fresh a: using cached .ty Stale b: generated code out of date {impl c missing -> HASH2, h missing -> HASH2} Fresh c: using cached .ty b Compilation done 0.000 s Final compilation done 0.000 s ================================================ FILE: compiler/acton/test/root/test.act ================================================ actor main(env): env.exit(0) ================================================ FILE: compiler/acton/test/syntaxerrors/err1.act ================================================ def f(x): if x>pass: return 1 else return 2 ================================================ FILE: compiler/acton/test/syntaxerrors/err1.golden ================================================ Building file test/syntaxerrors/err1.act using temporary scratch directory [error Parse error]: unexpected "if x>pass: " expecting end of line or simple statement +--> test/syntaxerrors/err1.act@1:11-1:12 | 1 | def f(x): if x>pass: : ^ : `- unexpected "if x>pass: " : expecting end of line or simple statement : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err10.act ================================================ # Missing colon after if statement def check(x): if x > 0 return True return False ================================================ FILE: compiler/acton/test/syntaxerrors/err10.golden ================================================ Building file test/syntaxerrors/err10.act using temporary scratch directory [error Parse error]: unexpected newline expecting ':', call arguments, slice/index expression, digit, if clause, or operator +--> test/syntaxerrors/err10.act@3:13-3:14 | 3 | if x > 0 : ^ : `- unexpected newline : expecting ':', call arguments, slice/index expression, digit, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err11.act ================================================ # Unclosed string literal def greet(name): msg = "Hello, return msg ================================================ FILE: compiler/acton/test/syntaxerrors/err11.golden ================================================ Building file test/syntaxerrors/err11.act using temporary scratch directory [error Syntax error]: Missing closing " +--> test/syntaxerrors/err11.act@3:11-3:19 | 3 | msg = "Hello, : ^------- : `- Missing closing " : | Hint: Add a closing quote (") to match the opening one -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err12.act ================================================ # Invalid character in identifier def my-function(x): return x + 1 ================================================ FILE: compiler/acton/test/syntaxerrors/err12.golden ================================================ Building file test/syntaxerrors/err12.act using temporary scratch directory [error Parse error]: unexpected '-' expecting '(' or '[' +--> test/syntaxerrors/err12.act@2:7-2:8 | 2 | def my-function(x): : ^ : `- unexpected '-' : expecting '(' or '[' : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err13.act ================================================ # Missing comma in list literal def make_list(): return [1 2 3] ================================================ FILE: compiler/acton/test/syntaxerrors/err13.golden ================================================ Building file test/syntaxerrors/err13.act using temporary scratch directory [error Parse error]: unexpected '2' expecting "for", call arguments, slice/index expression, closing ']', comma, if clause, or operator +--> test/syntaxerrors/err13.act@3:15-3:16 | 3 | return [1 2 3] : ^ : `- unexpected '2' : expecting "for", call arguments, slice/index expression, closing ']', comma, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err14.act ================================================ # Invalid assignment target def bad_assign(): 1 + 2 = 3 ================================================ FILE: compiler/acton/test/syntaxerrors/err14.golden ================================================ Building file test/syntaxerrors/err14.act using temporary scratch directory [error Parse error]: unexpected "= " expecting ';', call arguments, slice/index expression, comma, end of line, if clause, or operator +--> test/syntaxerrors/err14.act@3:11-3:12 | 3 | 1 + 2 = 3 : ^ : `- unexpected "= " : expecting ';', call arguments, slice/index expression, comma, end of line, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err15.act ================================================ # Mismatched brackets def access_item(): arr = [1, 2, 3] return arr[0} ================================================ FILE: compiler/acton/test/syntaxerrors/err15.golden ================================================ Building file test/syntaxerrors/err15.act using temporary scratch directory [error Parse error]: unexpected '}' expecting call arguments, slice/index expression, closing ']', comma, digit, if clause, or operator +--> test/syntaxerrors/err15.act@4:17-4:18 | 4 | return arr[0} : ^ : `- unexpected '}' : expecting call arguments, slice/index expression, closing ']', comma, digit, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err16.act ================================================ # Invalid for loop syntax (missing 'in') def loop(): for x [1, 2, 3]: print(x) ================================================ FILE: compiler/acton/test/syntaxerrors/err16.golden ================================================ Building file test/syntaxerrors/err16.act using temporary scratch directory [error Parse error]: unexpected "[1" expecting "in", ':', or comma +--> test/syntaxerrors/err16.act@3:11-3:12 | 3 | for x [1, 2, 3]: : ^ : `- unexpected "[1" : expecting "in", ':', or comma : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err17.act ================================================ # Double dots in dictionary def make_dict(): return {x:: 1} ================================================ FILE: compiler/acton/test/syntaxerrors/err17.golden ================================================ Building file test/syntaxerrors/err17.act using temporary scratch directory [error Parse error]: unexpected ':' expecting "for", call arguments, slice/index expression, closing '}', comma, if clause, or operator +--> test/syntaxerrors/err17.act@3:14-3:15 | 3 | return {x:: 1} : ^ : `- unexpected ':' : expecting "for", call arguments, slice/index expression, closing '}', comma, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err18.act ================================================ # Invalid lambda syntax def higher_order(): f = x => x + 1 return f(5) ================================================ FILE: compiler/acton/test/syntaxerrors/err18.golden ================================================ Building file test/syntaxerrors/err18.act using temporary scratch directory [error Parse error]: unexpected "> x + 1 re" expecting "action", "lambda", "mut", "proc", "pure", "yield", '*', '=', '_', comma, or relational expression +--> test/syntaxerrors/err18.act@3:12-3:13 | 3 | f = x => x + 1 : ^ : `- unexpected "> x + 1 re" : expecting "action", "lambda", "mut", "proc", "pure", "yield", '*', '=', '_', comma, or relational expression : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err19.act ================================================ # Invalid use of else without if def orphan_else(): else: pass ================================================ FILE: compiler/acton/test/syntaxerrors/err19.golden ================================================ Building file test/syntaxerrors/err19.act using temporary scratch directory [error Parse error]: unexpected "else: " expecting statement +--> test/syntaxerrors/err19.act@3:5-3:6 | 3 | else: : ^ : `- unexpected "else: " : expecting statement : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err2.act ================================================ def f(x): actor a(): pass return 2+x ================================================ FILE: compiler/acton/test/syntaxerrors/err2.golden ================================================ Building file test/syntaxerrors/err2.act using temporary scratch directory [error Context error]: actor declaration only allowed on the module top level +--> err2.act@2:5-2:10 | 2 | actor a(): : ^---- : `- actor declaration only allowed on the module top level -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err20.act ================================================ # Invalid decorator syntax @ def decorated(): pass ================================================ FILE: compiler/acton/test/syntaxerrors/err20.golden ================================================ Building file test/syntaxerrors/err20.act using temporary scratch directory [error Parse error]: unexpected "@def decorate" expecting statement +--> test/syntaxerrors/err20.act@2:1-2:2 | 2 | @ : ^ : `- unexpected "@def decorate" : expecting statement : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err21.act ================================================ # Class definition without colon class MyClass pass ================================================ FILE: compiler/acton/test/syntaxerrors/err21.golden ================================================ Building file test/syntaxerrors/err21.act using temporary scratch directory [error Parse error]: unexpected newline expecting '(', ':', or '[' +--> test/syntaxerrors/err21.act@2:14-2:15 | 2 | class MyClass : ^ : `- unexpected newline : expecting '(', ':', or '[' : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err22.act ================================================ # Invalid comprehension syntax def bad_comp(): return [x for x in] ================================================ FILE: compiler/acton/test/syntaxerrors/err22.golden ================================================ Building file test/syntaxerrors/err22.act using temporary scratch directory [error Parse error]: unexpected "]" expecting relational expression +--> test/syntaxerrors/err22.act@3:23-3:24 | 3 | return [x for x in] : ^ : `- unexpected "]" : expecting relational expression : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err23.act ================================================ # Invalid f-string syntax def bad_fstring(): name = "world" return f"Hello {name" ================================================ FILE: compiler/acton/test/syntaxerrors/err23.golden ================================================ Building file test/syntaxerrors/err23.act using temporary scratch directory [error Syntax error]: Missing closing '}' for expression +--> test/syntaxerrors/err23.act@4:21-4:25 | 4 | return f"Hello {name" : ^--- : `- Missing closing '}' for expression : | Hint: Add a closing brace to complete the interpolation -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err24.act ================================================ # Double colon in type annotation def typed_func() :: int: return 42 ================================================ FILE: compiler/acton/test/syntaxerrors/err24.golden ================================================ Building file test/syntaxerrors/err24.act using temporary scratch directory [error Parse error]: unexpected ": int: ret" expecting end of line or simple statement +--> test/syntaxerrors/err24.act@2:19-2:20 | 2 | def typed_func() :: int: : ^ : `- unexpected ": int: ret" : expecting end of line or simple statement : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err25.act ================================================ # Invalid use of def inside expression def expr_def(): x = def inner(): pass ================================================ FILE: compiler/acton/test/syntaxerrors/err25.golden ================================================ Building file test/syntaxerrors/err25.act using temporary scratch directory [error Parse error]: unexpected "def inner(): " expecting "action", "lambda", "mut", "proc", "pure", "yield", '*', '=', '_', comma, or relational expression +--> test/syntaxerrors/err25.act@3:9-3:10 | 3 | x = def inner(): : ^ : `- unexpected "def inner(): " : expecting "action", "lambda", "mut", "proc", "pure", "yield", '*', '=', '_', comma, or relational expression : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err26.act ================================================ # Multiple statements on same line without semicolon def multiple(): x = 1 y = 2 ================================================ FILE: compiler/acton/test/syntaxerrors/err26.golden ================================================ Building file test/syntaxerrors/err26.act using temporary scratch directory [error Parse error]: unexpected "y " expecting ';', call arguments, slice/index expression, comma, end of line, if clause, or operator +--> test/syntaxerrors/err26.act@3:11-3:12 | 3 | x = 1 y = 2 : ^ : `- unexpected "y " : expecting ';', call arguments, slice/index expression, comma, end of line, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err27.act ================================================ # Invalid numeric literal def bad_number(): return 123abc ================================================ FILE: compiler/acton/test/syntaxerrors/err27.golden ================================================ Building file test/syntaxerrors/err27.act using temporary scratch directory [error Parse error]: unexpected "ab" expecting ';', call arguments, slice/index expression, comma, digit, end of line, if clause, or operator +--> test/syntaxerrors/err27.act@3:15-3:16 | 3 | return 123abc : ^ : `- unexpected "ab" : expecting ';', call arguments, slice/index expression, comma, digit, end of line, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err28.act ================================================ # Missing expression between commas def bad_args(): print(1,,2) ================================================ FILE: compiler/acton/test/syntaxerrors/err28.golden ================================================ Building file test/syntaxerrors/err28.act using temporary scratch directory [error Parse error]: unexpected '2' expecting closing ')' +--> test/syntaxerrors/err28.act@3:14-3:15 | 3 | print(1,,2) : ^ : `- unexpected '2' : expecting closing ')' : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err29.act ================================================ # Invalid slice syntax def bad_slice(): arr = [1, 2, 3, 4, 5] return arr[1:::] ================================================ FILE: compiler/acton/test/syntaxerrors/err29.golden ================================================ Building file test/syntaxerrors/err29.act using temporary scratch directory [error Parse error]: unexpected ':' expecting "action", "lambda", "mut", "proc", "pure", '_', closing ']', or relational expression +--> test/syntaxerrors/err29.act@4:19-4:20 | 4 | return arr[1:::] : ^ : `- unexpected ':' : expecting "action", "lambda", "mut", "proc", "pure", '_', closing ']', or relational expression : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err3.act ================================================ def f(x): return 2+ ================================================ FILE: compiler/acton/test/syntaxerrors/err3.golden ================================================ Building file test/syntaxerrors/err3.act using temporary scratch directory [error Parse error]: unexpected newline expecting atomic expression or unary operator +--> test/syntaxerrors/err3.act@2:14-2:15 | 2 | return 2+ : ^ : `- unexpected newline : expecting atomic expression or unary operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err30.act ================================================ # Tab/space mixing indentation error def mixed_indent(): x = 1 y = 2 # This line starts with a tab ================================================ FILE: compiler/acton/test/syntaxerrors/err30.golden ================================================ Building file test/syntaxerrors/err30.act using temporary scratch directory [error Indentation error]: Too much indentation +--> err30.act@4:9-4:9 | 4 | y = 2 # This line starts with a tab : : `- Too much indentation -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err31.act ================================================ # Invalid operator combination def bad_op(): return 5 ** ** 2 ================================================ FILE: compiler/acton/test/syntaxerrors/err31.golden ================================================ Building file test/syntaxerrors/err31.act using temporary scratch directory [error Parse error]: unexpected "** 2" expecting atomic expression or unary operator +--> test/syntaxerrors/err31.act@3:17-3:18 | 3 | return 5 ** ** 2 : ^ : `- unexpected "** 2" : expecting atomic expression or unary operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err32.act ================================================ # Missing parenthesis in tuple def bad_tuple(): return (1, 2, 3 ================================================ FILE: compiler/acton/test/syntaxerrors/err32.golden ================================================ Building file test/syntaxerrors/err32.act using temporary scratch directory [error Parse error]: unexpected end of input expecting call arguments, slice/index expression, closing ')', comma, if clause, or operator +--> test/syntaxerrors/err32.act@4:1-4:2 | 4 | : ^ : `- unexpected end of input : expecting call arguments, slice/index expression, closing ')', comma, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err33.act ================================================ # Invalid import statement import ================================================ FILE: compiler/acton/test/syntaxerrors/err33.golden ================================================ Building file test/syntaxerrors/err33.act using temporary scratch directory [error Parse error]: unexpected newline expecting identifier +--> test/syntaxerrors/err33.act@2:7-2:8 | 2 | import : ^ : `- unexpected newline : expecting identifier : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err34.act ================================================ # Protocol with invalid syntax protocol MyProto: def method() ================================================ FILE: compiler/acton/test/syntaxerrors/err34.golden ================================================ Building file test/syntaxerrors/err34.act using temporary scratch directory [error Parse error]: unexpected newline expecting "->" or ':' +--> test/syntaxerrors/err34.act@3:17-3:18 | 3 | def method() : ^ : `- unexpected newline : expecting "->" or ':' : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err35.act ================================================ # Actor with invalid method definition actor MyActor: def ================================================ FILE: compiler/acton/test/syntaxerrors/err35.golden ================================================ Building file test/syntaxerrors/err35.act using temporary scratch directory [error Parse error]: unexpected ':' expecting '(' or '[' +--> test/syntaxerrors/err35.act@2:14-2:15 | 2 | actor MyActor: : ^ : `- unexpected ':' : expecting '(' or '[' : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err36.act ================================================ # Invalid match/case syntax def matcher(x): match x: case 1 return "one" ================================================ FILE: compiler/acton/test/syntaxerrors/err36.golden ================================================ Building file test/syntaxerrors/err36.act using temporary scratch directory [error Parse error]: unexpected "x:" expecting "%=", "&=", "**=", "*=", "+=", "-=", "//=", "/=", "<<=", ">>=", "@=", "^=", "|=", ':', '=', call arguments, slice/index expression, or comma +--> test/syntaxerrors/err36.act@3:11-3:12 | 3 | match x: : ^ : `- unexpected "x:" : expecting "%=", "&=", "**=", "*=", "+=", "-=", "//=", "/=", "<<=", ">>=", "@=", "^=", "|=", ':', '=', call arguments, slice/index expression, or comma : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err37.act ================================================ # Binary literal error def bad_binary(): return 0b102 ================================================ FILE: compiler/acton/test/syntaxerrors/err37.golden ================================================ Building file test/syntaxerrors/err37.act using temporary scratch directory [error Parse error]: unexpected "b1" expecting ';', call arguments, slice/index expression, comma, digit, end of line, if clause, or operator +--> test/syntaxerrors/err37.act@3:13-3:14 | 3 | return 0b102 : ^ : `- unexpected "b1" : expecting ';', call arguments, slice/index expression, comma, digit, end of line, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err38.act ================================================ # Hex literal error def bad_hex(): return 0xGHI ================================================ FILE: compiler/acton/test/syntaxerrors/err38.golden ================================================ Building file test/syntaxerrors/err38.act using temporary scratch directory [error Parse error]: unexpected 'G' expecting hexadecimal integer +--> test/syntaxerrors/err38.act@3:14-3:15 | 3 | return 0xGHI : ^ : `- unexpected 'G' : expecting hexadecimal integer : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err39.act ================================================ # Invalid attribute access def bad_attr(): return obj. ================================================ FILE: compiler/acton/test/syntaxerrors/err39.golden ================================================ Building file test/syntaxerrors/err39.act using temporary scratch directory [error Parse error]: unexpected newline expecting """"", "'''", '"', ''', '~', identifier, or integer +--> test/syntaxerrors/err39.act@3:16-3:17 | 3 | return obj. : ^ : `- unexpected newline : expecting """"", "'''", '"', ''', '~', identifier, or integer : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err4.act ================================================ def f(x): return x+pass ================================================ FILE: compiler/acton/test/syntaxerrors/err4.golden ================================================ Building file test/syntaxerrors/err4.act using temporary scratch directory [error Parse error]: unexpected "pass" expecting atomic expression or unary operator +--> test/syntaxerrors/err4.act@2:14-2:15 | 2 | return x+pass : ^ : `- unexpected "pass" : expecting atomic expression or unary operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err40.act ================================================ # Unexpected token after valid statement def unexpected(): x = 5 ] ================================================ FILE: compiler/acton/test/syntaxerrors/err40.golden ================================================ Building file test/syntaxerrors/err40.act using temporary scratch directory [error Parse error]: unexpected "]" expecting ';', call arguments, slice/index expression, comma, end of line, if clause, or operator +--> test/syntaxerrors/err40.act@3:11-3:12 | 3 | x = 5 ] : ^ : `- unexpected "]" : expecting ';', call arguments, slice/index expression, comma, end of line, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err41.act ================================================ class Z(value): pass ================================================ FILE: compiler/acton/test/syntaxerrors/err41.golden ================================================ Building file test/syntaxerrors/err41.act using temporary scratch directory [error Parse error]: Invalid name (reserved for type variables) +--> test/syntaxerrors/err41.act@1:7-1:8 | 1 | class Z(value): : ^ : `- Invalid name 'Z' : | Note: Single upper case character (optionally followed by digits) are reserved for type variables | Hint: Use a longer name -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err42.act ================================================ def Z(): pass ================================================ FILE: compiler/acton/test/syntaxerrors/err42.golden ================================================ Building file test/syntaxerrors/err42.act using temporary scratch directory [error Parse error]: Invalid name (reserved for type variables) +--> test/syntaxerrors/err42.act@1:5-1:6 | 1 | def Z(): : ^ : `- Invalid name 'Z' : | Note: Single upper case character (optionally followed by digits) are reserved for type variables | Hint: Use a longer name -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err5.act ================================================ def f(x: y = x * 2 return x + y ================================================ FILE: compiler/acton/test/syntaxerrors/err5.golden ================================================ Building file test/syntaxerrors/err5.act using temporary scratch directory [error Parse error]: unexpected 'r' expecting call arguments, slice/index expression, closing ')', comma, if clause, or operator +--> test/syntaxerrors/err5.act@3:5-3:6 | 3 | return x + y : ^ : `- unexpected 'r' : expecting call arguments, slice/index expression, closing ')', comma, if clause, or operator : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err6.act ================================================ def f(X): a = 2 return X+a ================================================ FILE: compiler/acton/test/syntaxerrors/err6.golden ================================================ Building file test/syntaxerrors/err6.act using temporary scratch directory [error Parse error]: Invalid name (reserved for type variables) +--> test/syntaxerrors/err6.act@1:7-1:8 | 1 | def f(X): : ^ : `- Invalid name 'X' : | Note: Single upper case character (optionally followed by digits) are reserved for type variables | Hint: Use a longer name -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err7.act ================================================ f : [a (Eq)] => (a,a) -> bool ================================================ FILE: compiler/acton/test/syntaxerrors/err7.golden ================================================ Building file test/syntaxerrors/err7.act using temporary scratch directory [error Parse error]: unexpected 'a' expecting type variable (upper case letter optionally followed by digits) +--> test/syntaxerrors/err7.act@1:6-1:7 | 1 | f : [a (Eq)] => (a,a) -> bool : ^ : `- unexpected 'a' : expecting type variable (upper case letter optionally followed by digits) : -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err8.act ================================================ def f(x): y = 2 z = x+y return z ================================================ FILE: compiler/acton/test/syntaxerrors/err8.golden ================================================ Building file test/syntaxerrors/err8.act using temporary scratch directory [error Indentation error]: Too much indentation +--> err8.act@3:6-3:6 | 3 | z = x+y : : `- Too much indentation -----+ ================================================ FILE: compiler/acton/test/syntaxerrors/err9.act ================================================ f : [A] ================================================ FILE: compiler/acton/test/syntaxerrors/err9.golden ================================================ Building file test/syntaxerrors/err9.act using temporary scratch directory [error Parse error]: unexpected newline expecting "=>" +--> test/syntaxerrors/err9.act@1:8-1:9 | 1 | f : [A] : ^ : `- unexpected newline : expecting "=>" : -----+ ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_assignment.act ================================================ actor Test(): self, x = 1, 2 ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_assignment.golden ================================================ Building file test/typeerrors/actor_self_reserved_assignment.act using temporary scratch directory actor_self_reserved_assignment Parse done 0.000 s [error Compilation error]: 'self' cannot be used as a parameter name in actors. +--> actor_self_reserved_assignment.act@2:5-2:9 | 2 | self, x = 1, 2 : ^--- : `- 'self' cannot be used as a parameter name in actors. -----+ ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_constructor_param.act ================================================ actor Test(first, self): def test_method(): pass ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_constructor_param.golden ================================================ Building file test/typeerrors/actor_self_reserved_constructor_param.act using temporary scratch directory actor_self_reserved_constructor_param Parse done 0.000 s [error Compilation error]: 'self' cannot be used as a parameter name in actors. +--> actor_self_reserved_constructor_param.act@1:19-1:23 | 1 | actor Test(first, self): : ^--- : `- 'self' cannot be used as a parameter name in actors. -----+ ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_except_as.act ================================================ actor Test(): try: raise ValueError("test") except ValueError as self: print(self) ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_except_as.golden ================================================ Building file test/typeerrors/actor_self_reserved_except_as.act using temporary scratch directory actor_self_reserved_except_as Parse done 0.000 s [error Compilation error]: 'self' cannot be used as a parameter name in actors. +--> actor_self_reserved_except_as.act@4:26-4:30 | 4 | except ValueError as self: : ^--- : `- 'self' cannot be used as a parameter name in actors. -----+ ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_loop_var.act ================================================ actor Test(): for self in [1, 2, 3]: pass ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_loop_var.golden ================================================ Building file test/typeerrors/actor_self_reserved_loop_var.act using temporary scratch directory actor_self_reserved_loop_var Parse done 0.000 s [error Compilation error]: 'self' cannot be used as a parameter name in actors. +--> actor_self_reserved_loop_var.act@2:9-2:13 | 2 | for self in [1, 2, 3]: : ^--- : `- 'self' cannot be used as a parameter name in actors. -----+ ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_method_name.act ================================================ actor Test(): def self(): pass ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_method_name.golden ================================================ Building file test/typeerrors/actor_self_reserved_method_name.act using temporary scratch directory actor_self_reserved_method_name Parse done 0.000 s [error Compilation error]: 'self' cannot be used as a parameter name in actors. +--> actor_self_reserved_method_name.act@2:9-2:13 | 2 | def self(): : ^--- : `- 'self' cannot be used as a parameter name in actors. -----+ ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_method_param.act ================================================ actor Test(): def test_method(first, self): pass ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_method_param.golden ================================================ Building file test/typeerrors/actor_self_reserved_method_param.act using temporary scratch directory actor_self_reserved_method_param Parse done 0.000 s [error Compilation error]: 'self' cannot be used as a parameter name in actors. +--> actor_self_reserved_method_param.act@2:28-2:32 | 2 | def test_method(first, self): : ^--- : `- 'self' cannot be used as a parameter name in actors. -----+ ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_method_param2.act ================================================ actor Test(): def ok_method(param): def test_method(first, self): pass ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_method_param2.golden ================================================ Building file test/typeerrors/actor_self_reserved_method_param2.act using temporary scratch directory actor_self_reserved_method_param2 Parse done 0.000 s [error Compilation error]: 'self' cannot be used as a parameter name in actors. +--> actor_self_reserved_method_param2.act@3:32-3:36 | 3 | def test_method(first, self): : ^--- : `- 'self' cannot be used as a parameter name in actors. -----+ ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_variable.act ================================================ actor Test(): var self = 42 ================================================ FILE: compiler/acton/test/typeerrors/actor_self_reserved_variable.golden ================================================ Building file test/typeerrors/actor_self_reserved_variable.act using temporary scratch directory actor_self_reserved_variable Parse done 0.000 s [error Compilation error]: 'self' cannot be used as a parameter name in actors. +--> actor_self_reserved_variable.act@2:9-2:13 | 2 | var self = 42 : ^--- : `- 'self' cannot be used as a parameter name in actors. -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex1.act ================================================ def f(x,y): return x+y a = f(3) ================================================ FILE: compiler/acton/test/typeerrors/ex1.golden ================================================ Building file test/typeerrors/ex1.act using temporary scratch directory ex1 Parse done 0.000 s [error]: Incompatible types +--> ex1.act@4:5-4:9 | 1 | def f(x,y): : ^ : `- f is defined here : 4 | a = f(3) : ^--- : `- keyword argument(s) 'y' is missing in call to f -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex10.act ================================================ def f(x): try: y = x+2 except int: pass ================================================ FILE: compiler/acton/test/typeerrors/ex10.golden ================================================ Building file test/typeerrors/ex10.act using temporary scratch directory ex10 Parse done 0.000 s [error]: Constraint violation +--> ex10.act@4:5-4:15 | 4 | except int: : ^--------- : `- __builtin__.int must be a subclass of __builtin__.Exception -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex11.act ================================================ def f(s): return s + "!" a = f([8]) ================================================ FILE: compiler/acton/test/typeerrors/ex11.golden ================================================ Building file test/typeerrors/ex11.act using temporary scratch directory ex11 Parse done 0.000 s [error]: Constraint violation +--> ex11.act@4:5-4:11 | 1 | def f(s): : ^ : `- f is defined here : 4 | a = f([8]) : ^----- : `- Type incompatibility between definition of and call of f (__builtin__.list[_] must be a subclass of __builtin__.str) -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex13.act ================================================ actor main(env): a = Act(7) actor Act(s:int,t:str): a = s b = t ================================================ FILE: compiler/acton/test/typeerrors/ex13.golden ================================================ Building file test/typeerrors/ex13.act using temporary scratch directory ex13 Parse done 0.000 s [error]: Incompatible types +--> ex13.act@2:7-2:13 | 2 | a = Act(7) : ^----- : `- keyword component(s) 't' is missing in tuple -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex14.act ================================================ def f(x): return g(x) def g(x,y): return x+y ================================================ FILE: compiler/acton/test/typeerrors/ex14.golden ================================================ Building file test/typeerrors/ex14.act using temporary scratch directory ex14 Parse done 0.000 s [error]: Incompatible types +--> ex14.act@2:12-2:16 | 2 | return g(x) : ^--- : `- keyword argument(s) 'y' is missing in call to g : 4 | def g(x,y): : ^ : `- g is defined here -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex15.act ================================================ def f(x : str): y = 1 raise y # y = y + x[7] return y ================================================ FILE: compiler/acton/test/typeerrors/ex15.golden ================================================ Building file test/typeerrors/ex15.act using temporary scratch directory ex15 Parse done 0.000 s [error]: Cannot satisfy the following simultaneous constraints for the unknown types +--> ex15.act@2:9-2:10 | 2 | y = 1 : ^ : |- The type of the indicated expression (which we call t1) must implement __builtin__.Number : `- The type of the indicated expression (which we call t1) must be a subtype of t0 3 | raise y : ^ : `- The type of the indicated expression (which we call t0) must be a subclass of __builtin__.Exception : -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex16.act ================================================ actor main(env): def test(): foo: ?list[int] = None foo = [1, 2, 3] # if foo is not None: foo.append(4) print(foo) test() await async env.exit(0) ================================================ FILE: compiler/acton/test/typeerrors/ex16.golden ================================================ Building file test/typeerrors/ex16.act using temporary scratch directory ex16 Parse done 0.000 s [error]: Constraint violation +--> ex16.act@6:9-6:22 | 6 | foo.append(4) : ^------------ : `- ?__builtin__.list[__builtin__.int] does not have an attribute append : Hint: you may need to test if foo is not None -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex17.act ================================================ a = pow(3,"hej") ================================================ FILE: compiler/acton/test/typeerrors/ex17.golden ================================================ Building file test/typeerrors/ex17.act using temporary scratch directory ex17 Parse done 0.000 s [error]: Cannot satisfy the following simultaneous constraints for the unknown types +--> ex17.act@2:9-2:10 | 2 | a = pow(3,"hej") : ^---^------- : | `- The type of the indicated expression (which we call t0) must implement __builtin__.Number : | : |- pow has had its polymorphic type [A(Number)] => (a: A, b: A) -> A instantiated to (a: t1, b: t1) -> t1, so t1 must implement __builtin__.Number : |- The type of the indicated expression (which we call t1) must be a subtype of _ : |- The type of the indicated expression (which we call t0) must be a subtype of t1 : `- The type of the indicated expression (inferred to be __builtin__.str) must be a subtype of t1 -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex18.act ================================================ def f(ls : list[A]): return len(ls) + "hej" ================================================ FILE: compiler/acton/test/typeerrors/ex18.golden ================================================ Building file test/typeerrors/ex18.act using temporary scratch directory ex18 Parse done 0.000 s [error]: Cannot satisfy the following simultaneous constraints for the unknown type t0 +--> ex18.act@2:12-2:27 | 2 | return len(ls) + "hej" : ^-------------- : `- The type of the indicated expression (which we call t0) must implement __builtin__.Plus : __builtin__.atom must be a subclass of t0 -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex19.act ================================================ def f(x,y): if x ex19.act@1:5-1:6 | 1 | def f(x,y): : ^ : |- : |- : `- : 7 | a = f(3,"hej") : ^-^------- : | `- The type of the indicated expression (which we call t0) must implement __builtin__.Number : | : |- f has had its polymorphic type [A(Plus, Ord)] => (x: A, y: A) -> A instantiated to (x: t1, y: t1) -> t1, so t1 must implement __builtin__.Ord : |- f has had its polymorphic type [A(Plus, Ord)] => (x: A, y: A) -> A instantiated to (x: t1, y: t1) -> t1, so t1 must implement __builtin__.Plus : |- Type incompatibility between definition of and call of f (t1 must be a subtype of _) : |- Type incompatibility between definition of and call of f (t0 must be a subtype of t1) : `- Type incompatibility between definition of and call of f (__builtin__.str must be a subtype of t1) -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex2.act ================================================ def f(x,y): return x+y a = f(3,4,5) ================================================ FILE: compiler/acton/test/typeerrors/ex2.golden ================================================ Building file test/typeerrors/ex2.act using temporary scratch directory ex2 Parse done 0.000 s [error]: Incompatible types +--> ex2.act@4:5-4:13 | 1 | def f(x,y): : ^ : `- f is defined here : 4 | a = f(3,4,5) : ^------- : `- too many positional argument(s) in call to f -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex20.act ================================================ f : (str,str) -> str def f(s : str, a): return s * a ================================================ FILE: compiler/acton/test/typeerrors/ex20.golden ================================================ Building file test/typeerrors/ex20.act using temporary scratch directory ex20 Parse done 0.000 s [error]: Constraint violation +--> ex20.act@1:1-1:2 | 1 | f : (str,str) -> str : ^ : `- Type incompatibility between signature for and definition of f (__builtin__.str must be a subclass of __builtin__.int) : 3 | +> def f(s : str, a): 4 | |> return s * a : | : `- f is defined here -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex21.act ================================================ import math actor main(env): print(math.sin("hej")) env.exit(0) ================================================ FILE: compiler/acton/test/typeerrors/ex21.golden ================================================ Building file test/typeerrors/ex21.act using temporary scratch directory ex21 Parse done 0.000 s [error]: Constraint violation +--> ex21.act@4:10-4:25 | 4 | print(math.sin("hej")) : ^-------------- : `- The type of the indicated expression (inferred to be __builtin__.str) must be a subclass of __builtin__.float -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex22.act ================================================ f : [A(Plus)] => (A) -> A def f(x,y): return x ================================================ FILE: compiler/acton/test/typeerrors/ex22.golden ================================================ Building file test/typeerrors/ex22.act using temporary scratch directory ex22 Parse done 0.000 s [error]: Incompatible types +--> ex22.act@1:1-1:2 | 1 | f : [A(Plus)] => (A) -> A : ^ : `- keyword argument(s) 'y' is missing in call to f : 3 | +> def f(x,y): 4 | |> return x : | : `- f is defined here -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex23.act ================================================ def f(x,s : str): if s==7: return x else: return x+x # This gives a misleading error message; the last constraint is # # | # 2 | if s==7: # | ^^^^ # The type of s == 7 (which we call t1) must implement __builtin__.Eq # # Instead of "The type of s == 7" one wants "a common supertype of s and 7" (?) # # Fix should be done in the # # infer env e@(CompOp l e1 [OpArg op e2]) # # case in Types.hs. # # Similar problems show up for other binary operators. ================================================ FILE: compiler/acton/test/typeerrors/ex23.golden ================================================ Building file test/typeerrors/ex23.act using temporary scratch directory ex23 Parse done 0.000 s [error]: Cannot satisfy the following simultaneous constraints for the unknown types +--> ex23.act@2:11-2:12 | 2 | if s==7: : ^--^ : | |- The type of the indicated expression (which we call t0) must implement __builtin__.Number : | : | `- The type of the indicated expression (which we call t0) must be a subtype of t1 : |- The type of the indicated expression (inferred to be __builtin__.str) must be a subtype of t1 : `- The type of the indicated expression (which we call t1) must implement __builtin__.Eq -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex24.act ================================================ # TODO: error should print line numbers def foo(): a : ?str = "" b: dict[str, str] = {} b[a] = "hej" ================================================ FILE: compiler/acton/test/typeerrors/ex24.golden ================================================ Building file test/typeerrors/ex24.act using temporary scratch directory ex24 Parse done 0.000 s [error]: Type unification error +--> ex24.act@5:13-5:16 | 5 | b: dict[str, str] = {} : ^-- : `- Incompatible types __builtin__.str and ?T_12 -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex25.act ================================================ actor Bob(): def foo(cb): pass actor Rob(): def bar(): b = Bob() b.foo() ================================================ FILE: compiler/acton/test/typeerrors/ex25.golden ================================================ Building file test/typeerrors/ex25.act using temporary scratch directory ex25 Parse done 0.000 s [error]: Incompatible types +--> ex25.act@8:9-8:16 | 8 | b.foo() : ^------ : `- keyword component(s) 'cb' is missing in tuple -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex26.act ================================================ class Foo(object): thing: ?bool def __init__(self, thing): self.thing = thing mut def remove_thing(foos): for f in foos: f.thing = None def process(): p = [] foos = [Foo(True)] # This is obviously wrong, remove_thing() does not return Iterable p.extend(remove_thing(foos)) ================================================ FILE: compiler/acton/test/typeerrors/ex26.golden ================================================ Building file test/typeerrors/ex26.act using temporary scratch directory ex26 Parse done 0.000 s [error]: Constraint violation +--> ex26.act@15:5-15:33 | 15 | p.extend(remove_thing(foos)) : ^--------------------------- : `- None must be a subclass of __builtin__.list[_] -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex27.act ================================================ class Foo(object): def __init__(self): pass def foo(a: int): return 42 ================================================ FILE: compiler/acton/test/typeerrors/ex27.golden ================================================ Building file test/typeerrors/ex27.act using temporary scratch directory ex27 Parse done 0.000 s [error]: Type unification error +--> ex27.act@5:5-6:1 | 5 | +> def foo(a: int): 6 | |> return 42 : | : `- Type of first parameter of class method does not unify with Self -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex4.act ================================================ def f(x,y): return x+y actor main(env): print("a".center(f(3))) ================================================ FILE: compiler/acton/test/typeerrors/ex4.golden ================================================ Building file test/typeerrors/ex4.act using temporary scratch directory ex4 Parse done 0.000 s [error]: Incompatible types +--> ex4.act@5:22-5:26 | 1 | def f(x,y): : ^ : `- f is defined here : 5 | print("a".center(f(3))) : ^--- : `- keyword argument(s) 'y' is missing in call to f -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex5.act ================================================ def f(x,y): return x+y def apply(g,x): return g(x) a = apply(f,3) ================================================ FILE: compiler/acton/test/typeerrors/ex5.golden ================================================ Building file test/typeerrors/ex5.act using temporary scratch directory ex5 Parse done 0.000 s [error]: Incompatible types +--> ex5.act@7:5-7:15 | 4 | def apply(g,x): : ^---- : `- apply is defined here : 7 | a = apply(f,3) : ^--------- : `- keyword argument(s) 'y' is missing in call to apply -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex6.act ================================================ (a,b) = (1,3,5) ================================================ FILE: compiler/acton/test/typeerrors/ex6.golden ================================================ Building file test/typeerrors/ex6.act using temporary scratch directory ex6 Parse done 0.000 s [error]: Incompatible types +--> ex6.act@1:9-1:16 | 1 | (a,b) = (1,3,5) : ^------ : `- too many positional component(s) in tuple -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex7.act ================================================ actor main(env): var k = 3 pure def g(): return k ================================================ FILE: compiler/acton/test/typeerrors/ex7.golden ================================================ Building file test/typeerrors/ex7.act using temporary scratch directory ex7 Parse done 0.000 s [error]: Constraint violation +--> ex7.act@4:16-4:17 | 4 | return k : ^ : `- State variable may only be accessed in a proc -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex8.act ================================================ actor main(env): n : int = 7 for x in n: pass ================================================ FILE: compiler/acton/test/typeerrors/ex8.golden ================================================ Building file test/typeerrors/ex8.act using temporary scratch directory ex8 Parse done 0.000 s [error]: Cannot satisfy the following simultaneous constraints for the unknown type t0 +--> ex8.act@3:14-3:15 | 3 | for x in n: : ^ : |- The type of the indicated expression (inferred to be __builtin__.int) must be a subtype of t0 : : `- The type of the indicated expression (which we call t0) must implement __builtin__.Iterable[_] -----+ ================================================ FILE: compiler/acton/test/typeerrors/ex9.act ================================================ def f(x,y): return x+y a = f(3,"hej") ================================================ FILE: compiler/acton/test/typeerrors/ex9.golden ================================================ Building file test/typeerrors/ex9.act using temporary scratch directory ex9 Parse done 0.000 s [error]: Cannot satisfy the following simultaneous constraints for the unknown types +--> ex9.act@1:5-1:6 | 1 | def f(x,y): : ^ : |- : |- : `- : 4 | a = f(3,"hej") : ^-^------- : | `- The type of the indicated expression (which we call t0) must implement __builtin__.Number : | : |- f has had its polymorphic type [A(Plus)] => (x: A, y: A) -> A instantiated to (x: t1, y: t1) -> t1, so t1 must implement __builtin__.Plus : |- Type incompatibility between definition of and call of f (t1 must be a subtype of _) : |- Type incompatibility between definition of and call of f (t0 must be a subtype of t1) : `- Type incompatibility between definition of and call of f (__builtin__.str must be a subtype of t1) -----+ ================================================ FILE: compiler/acton/test/typeerrors/funargs1.act ================================================ def f(x,y): return x+y a = f(3,x=3,y=3) ================================================ FILE: compiler/acton/test/typeerrors/funargs1.golden ================================================ Building file test/typeerrors/funargs1.act using temporary scratch directory funargs1 Parse done 0.000 s [error]: Unexpected keyword argument +--> funargs1.act@4:9-4:10 | 4 | a = f(3,x=3,y=3) : ^ : `- Unexpected keyword argument 'x' -----+ ================================================ FILE: compiler/acton/test/typeerrors/funargs2.act ================================================ def f(x,y): return x+y a = f(3,z=3,y=3) ================================================ FILE: compiler/acton/test/typeerrors/funargs2.golden ================================================ Building file test/typeerrors/funargs2.act using temporary scratch directory funargs2 Parse done 0.000 s [error]: Unexpected keyword argument +--> funargs2.act@4:9-4:10 | 4 | a = f(3,z=3,y=3) : ^ : `- Unexpected keyword argument 'z' -----+ ================================================ FILE: compiler/acton/test/typeerrors/funargs3.act ================================================ def f(x,y): return x+y a = f(x=3,4) ================================================ FILE: compiler/acton/test/typeerrors/funargs3.golden ================================================ Building file test/typeerrors/funargs3.act using temporary scratch directory [error Parse error]: unexpected '4' expecting "**" or closing ')' +--> test/typeerrors/funargs3.act@4:11-4:12 | 4 | a = f(x=3,4) : ^ : `- unexpected '4' : expecting "**" or closing ')' : -----+ ================================================ FILE: compiler/acton/test/typeerrors/funargs4.act ================================================ def f(x,y): return x+y a = f(4,x=3,y=4) ================================================ FILE: compiler/acton/test/typeerrors/funargs4.golden ================================================ Building file test/typeerrors/funargs4.act using temporary scratch directory funargs4 Parse done 0.000 s [error]: Unexpected keyword argument +--> funargs4.act@4:9-4:10 | 4 | a = f(4,x=3,y=4) : ^ : `- Unexpected keyword argument 'x' -----+ ================================================ FILE: compiler/acton/test/typeerrors/funargs5.act ================================================ def f(x,y,*z,w): return x a = f(3,4,5,6) ================================================ FILE: compiler/acton/test/typeerrors/funargs5.golden ================================================ Building file test/typeerrors/funargs5.act using temporary scratch directory funargs5 Parse done 0.000 s [error]: Incompatible types +--> funargs5.act@4:5-4:15 | 1 | def f(x,y,*z,w): : ^ : `- f is defined here : 4 | a = f(3,4,5,6) : ^--------- : `- keyword argument(s) 'w' is missing in call to f -----+ ================================================ FILE: compiler/acton/test/typeerrors/funargs6.act ================================================ def f(x,y,*z,w): return x a = f(3,w=6) ================================================ FILE: compiler/acton/test/typeerrors/funargs6.golden ================================================ Building file test/typeerrors/funargs6.act using temporary scratch directory funargs6 Parse done 0.000 s [error]: Incompatible types +--> funargs6.act@4:5-4:13 | 1 | def f(x,y,*z,w): : ^ : `- f is defined here : 4 | a = f(3,w=6) : ^------- : `- too few argument(s) in call to f -----+ ================================================ FILE: compiler/acton/test.hs ================================================ {-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-} import Control.Monad import Data.Char (isAlphaNum, isSpace) import Data.List import Data.List.Split import Data.Maybe (catMaybes) import Data.Ord import Data.Time.Clock.POSIX import qualified Data.ByteString.Lazy.Char8 as LBS import Control.Exception (catch, IOException) import System.Directory import System.Directory.Recursive import System.Environment (getEnvironment) import System.Exit import System.FilePath import System.FilePath.Posix import System.Process import System.TimeIt import System.IO.Temp (withSystemTempDirectory) import Test.Tasty import Test.Tasty.ExpectedFailure import Test.Tasty.Golden (goldenVsString) import Test.Tasty.HUnit import qualified PkgCommands import qualified Acton.CommandLineParser as C import qualified Acton.Fingerprint as Fingerprint import qualified Options.Applicative as OA import qualified Paths_acton import qualified TestGolden -- The default is to build and run each test program with the expectation that -- both compilation and running the program is successful as determined by exit -- status of 0. If a test is expected to fail compilation, it should be named -- __bf.act (for Build Failure). If a test is expected to fail at run time, name -- the file with __rf.act (for Run Failure). main = do #if defined(darwin_HOST_OS) let segfault_exitcode = (ExitFailure (-11)) #else let segfault_exitcode = (ExitFailure 139) #endif builtinsAutoTests <- createAutoTests "Builtins auto" "../../test/builtins_auto" coreLangAutoTests <- createAutoTests "Core language auto" "../../test/core_lang_auto" dbAutoTests <- createAutoTests "DB auto" "../../test/db_auto" exampleTests <- createTests "Examples" "../../examples" False [] (testBuild "" ExitSuccess) regressionTests <- createAutoTests "Regression auto" "../../test/regression_auto" regressionSegfaultTests <- createTests "Regression segfaults" "../../test/regression_segfault" False [] (testBuild "" ExitSuccess) rtsAutoTests <- createAutoTests "RTS auto" "../../test/rts_auto" stdlibAutoTests <- createAutoTests "stdlib auto" "../../test/stdlib_auto" syntaxErrorAutoTests <- createGoldenErrorAutoTests "syntax errors" "test/syntaxerrors" typeErrorAutoTests <- createGoldenErrorAutoTests "type errors" "test/typeerrors" defaultMain $ localOption timeout $ testGroup "Tests" $ [ builtinsAutoTests , coreLangAutoTests , coreLangTests , dbAutoTests , compilerTests , actonProjTests , actonRootArgTests , exampleTests , regressionTests , regressionSegfaultTests , rtsAutoTests , rtsTests , stdlibTests , stdlibAutoTests , syntaxErrorAutoTests , typeErrorAutoTests , parseFlagTests , crossCompileTests , pkgCliTests ] where timeout :: Timeout timeout = mkTimeout (30*60*1000000) -- this normally doesn't take long on a local machine but in GitHub -- Actions CI, in particular the MacOS workers can be really slow so it -- has taken longer than 3 minutes, thus the rather lengthy timeout coreLangTests = testGroup "Core language" [ testCase "async context" $ do (returnCode, cmdOut, cmdErr) <- buildAndRun "" "" "../../test/core_lang/async-context.act" assertEqual "should compile" ExitSuccess returnCode assertEqual "should see 2 pongs" "pong\npong\n" cmdOut ] compilerTests = testGroup "compiler tests" [ testCase "target native" $ do testBuild "--target native" ExitSuccess False "test/project/simple" , testCase "mixed dots in qualified name" $ do (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (shell $ "rm -rf ../../test/compiler/mixed-dots/out") "" testBuild "" ExitSuccess False "../../test/compiler/mixed-dots/" testBuild "" ExitSuccess False "../../test/compiler/mixed-dots/" , testCase "sub-modules and dashes" $ do (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (shell $ "rm -rf ../../test/compiler/subdash/out") "" testBuild "" ExitSuccess False "../../test/compiler/subdash/" testBuild "" ExitSuccess False "../../test/compiler/subdash/" , testCase "deps" $ do (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (shell $ "rm -rf ../../test/compiler/test_deps/build.zig*") "" (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (shell $ "rm -rf ../../test/compiler/test_deps/out") "" (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (shell $ "rm -rf ../../test/compiler/test_deps/deps/a/build.zig*") "" (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (shell $ "rm -rf ../../test/compiler/test_deps/deps/a/out") "" runActon "build" ExitSuccess False "../../test/compiler/test_deps/" , testCase "path dependency fetches transitive cached deps before discovery" $ do withSystemTempDirectory "acton-transitive-path-fetch" $ \tmp -> do actonExe <- canonicalizePath "../../dist/bin/acton" env0 <- getEnvironment let homeDir = tmp "home" rootProj = tmp "root" specProj = rootProj "spec" fakeHash = "transitive-hash-does-not-exist" envWithHome = ("HOME", homeDir) : filter ((/= "HOME") . fst) env0 mkFp name = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix (Fingerprint.fingerprintPrefixForName name) 1) createDirectoryIfMissing True homeDir createDirectoryIfMissing True (rootProj "src") createDirectoryIfMissing True (specProj "src") writeFile (rootProj "Build.act") $ unlines [ "name = \"root_proj\"" , "fingerprint = " ++ mkFp "root_proj" , "dependencies = {" , " \"spec\": (path=\"spec\")" , "}" , "zig_dependencies = {}" ] writeFile (rootProj "src" "main.act") $ unlines [ "actor main(env):" , " env.exit(0)" ] writeFile (specProj "Build.act") $ unlines [ "name = \"spec_proj\"" , "fingerprint = " ++ mkFp "spec_proj" , "dependencies = {" , " \"ghost\": (hash=\"" ++ fakeHash ++ "\")" , "}" , "zig_dependencies = {}" ] writeFile (specProj "src" "specproj.act") "def marker() -> int:\n return 1\n" (returnCode, _cmdOut, cmdErr) <- readCreateProcessWithExitCode (proc actonExe ["build"]) { cwd = Just rootProj, env = Just envWithHome } "" assertEqual "acton should fail for unfetchable transitive dependency" (ExitFailure 1) returnCode assertBool "should fail during dependency fetch/copy, not later Build.act load" ("not present in Zig cache after fetch" `isInfixOf` cmdErr) assertBool "should not fail with missing Build.act in unresolved deps cache path" (not ("Missing Build.act in " `isInfixOf` cmdErr)) , testCase "build.zig.zon uses canonical dep roots" $ do withSystemTempDirectory "acton-buildzig-zon-dedup" $ \tmp -> do actonExe <- canonicalizePath "../../dist/bin/acton" env0 <- getEnvironment let homeDir = tmp "home" rootProj = tmp "root" depKeep = rootProj "dep_keep" midProj = rootProj "mid" depDrop = tmp "dep_drop" envWithHome = ("HOME", homeDir) : filter ((/= "HOME") . fst) env0 mkFp name = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix (Fingerprint.fingerprintPrefixForName name) 1) writeBuildActAt :: FilePath -> String -> [(String, FilePath)] -> IO () writeBuildActAt dir name deps = do createDirectoryIfMissing True (dir "src") let depsBody = intercalate ",\n" [ " \"" ++ depName ++ "\": (\n" ++ " path=" ++ show depPath ++ "\n" ++ " )" | (depName, depPath) <- deps ] depsSection = if null deps then "dependencies = {}" else "dependencies = {\n" ++ depsBody ++ "\n}" writeFile (dir "Build.act") $ unlines [ "name = " ++ show name , "fingerprint = " ++ mkFp name , "" , depsSection , "" , "zig_dependencies = {}" ] runBuild dir = readCreateProcessWithExitCode (proc actonExe ["build", "--always-build"]) { cwd = Just dir, env = Just envWithHome } "" createDirectoryIfMissing True homeDir writeBuildActAt depKeep "dep" [] writeFile (depKeep "src" "dep.act") $ unlines [ "def keep() -> int:" , " return 1" ] writeBuildActAt depDrop "dep" [] writeFile (depDrop "src" "dep.act") $ unlines [ "def drop() -> int:" , " return 2" ] writeBuildActAt midProj "mid" [("dep", depDrop)] writeFile (midProj "src" "mid.act") $ unlines [ "def marker() -> int:" , " return 41" ] writeBuildActAt rootProj "root_proj" [("dep", depKeep), ("mid", midProj)] writeFile (rootProj "src" "main.act") $ unlines [ "import mid" , "" , "actor main(env):" , " env.exit(mid.marker())" ] (returnCode, cmdOut, cmdErr) <- runBuild rootProj when (returnCode /= ExitSuccess) $ assertFailure ("root build failed:\nstdout:\n" ++ cmdOut ++ "\nstderr:\n" ++ cmdErr) midBuildZon <- readFile (midProj "build.zig.zon") assertBool "mid build.zig.zon should point at the canonical dep root" ("dep_keep" `isInfixOf` midBuildZon) assertBool "mid build.zig.zon should not keep the overridden raw dep path" (not ("dep_drop" `isInfixOf` midBuildZon)) , testCase "path dep build ignores stale dep out/types modules" $ do withSystemTempDirectory "acton-stale-path-dep" $ \tmp -> do actonExe <- canonicalizePath "../../dist/bin/acton" createDirectoryIfMissing True (tmp "home") env0 <- getEnvironment let depV1 = tmp "dep_v1" depV2 = tmp "dep_v2" midProj = tmp "mid" appProj = tmp "app" envWithHome = ("HOME", tmp "home") : filter ((/= "HOME") . fst) env0 mkFp name = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix (Fingerprint.fingerprintPrefixForName name) 1) writeBuildActAt dir name deps = do createDirectoryIfMissing True (dir "src") let depsBody = intercalate ",\n" [ " \"" ++ depName ++ "\": (\n" ++ " path=\"" ++ depPath ++ "\"\n" ++ " )" | (depName, depPath) <- deps ] depsSection = if null deps then "dependencies = {}" else "dependencies = {\n" ++ depsBody ++ "\n}" writeFile (dir "Build.act") $ unlines [ "name = \"" ++ name ++ "\"" , "fingerprint = " ++ mkFp name , "" , depsSection , "" , "zig_dependencies = {}" , "" ] runBuild dir = readCreateProcessWithExitCode (proc actonExe ["build", "--always-build"]) { cwd = Just dir, env = Just envWithHome } "" assertBuildOk label (code, out, err) = when (code /= ExitSuccess) $ assertFailure (label ++ " failed:\nstdout:\n" ++ out ++ "\nstderr:\n" ++ err) writeBuildActAt depV1 "dep" [] createDirectoryIfMissing True (depV1 "src" "dep") writeFile (depV1 "src" "dep.act") $ unlines [ "def base() -> int:" , " return 1" ] writeFile (depV1 "src" "dep" "legacy.act") $ unlines [ "def legacy() -> int:" , " return 7" ] writeBuildActAt depV2 "dep" [] writeFile (depV2 "src" "dep.act") $ unlines [ "def base() -> int:" , " return 1" ] writeBuildActAt midProj "mid" [("dep", depV1)] createDirectoryIfMissing True (midProj "src" "mid") writeFile (midProj "src" "mid" "used.act") $ unlines [ "import dep" , "" , "def value() -> int:" , " return dep.base()" ] writeFile (midProj "src" "mid" "stale.act") $ unlines [ "import dep.legacy" , "" , "def stale() -> int:" , " return dep.legacy.legacy()" ] writeBuildActAt appProj "app" [("mid", midProj), ("dep", depV2)] writeFile (appProj "src" "main.act") $ unlines [ "import mid.used" , "" , "actor main(env: Env):" , " print(mid.used.value())" , " env.exit(0)" ] assertBuildOk "initial build of mid dependency" =<< runBuild midProj staleCExists <- doesFileExist (midProj "out" "types" "mid" "stale.c") assertBool "expected stale dependency C output to exist" staleCExists assertBuildOk "build of app with transitive dep override" =<< runBuild appProj , testCase "build.zig.zon name matches Build.act" $ do let prefix = "acton-long-project-name-12345678901234567890-" withSystemTempDirectory prefix $ \proj -> do let name = "long_project_name_1234567890" fp = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix (Fingerprint.fingerprintPrefixForName name) 1) srcDir = proj "src" actFile = srcDir "main.act" createDirectoryIfMissing True srcDir writeFile (proj "Build.act") $ unlines [ "name = \"" ++ name ++ "\"" , "fingerprint = " ++ fp , "" ] writeFile actFile $ unlines [ "actor main(env):" , " print(\"Hello, world\")" , " env.exit(0)" ] runActon "build" ExitSuccess False proj zon <- readFile (proj "build.zig.zon") let nameVal = let isNameLine l = ".name = ." `isPrefixOf` dropWhile isSpace l in case find isNameLine (lines zon) of Just line -> case stripPrefix ".name = ." (dropWhile isSpace line) of Just rest -> takeWhile (\c -> isAlphaNum c || c == '_') rest Nothing -> "" Nothing -> "" assertEqual "build.zig.zon name should match Build.act" name nameVal assertBool "build.zig.zon name should be <= 32 chars" (length nameVal <= 32) , testCase "build without Build.act" $ do withSystemTempDirectory "acton-build" $ \proj -> do let actFile = proj "acton-test.act" writeFile actFile $ unlines [ "#!/usr/bin/env runacton" , "actor main(env):" , " print(\"Hello, world\")" , " env.exit(0)" ] perms <- getPermissions actFile setPermissions actFile perms{ executable = True } actonExe <- canonicalizePath "../../dist/bin/acton" (returnCode, _cmdOut, cmdErr) <- readCreateProcessWithExitCode (proc actonExe ["build"]) { cwd = Just proj } "" assertEqual "acton should fail without Build.act" (ExitFailure 1) returnCode assertBool "error should mention Build.act" ("Build.act" `isInfixOf` cmdErr) #if !defined(mingw32_HOST_OS) , testCase "runacton shebang runs standalone script" $ do withSystemTempDirectory "acton-runacton" $ \proj -> do let script = proj "hello.act" writeFile script $ unlines [ "#!/usr/bin/env runacton" , "actor main(env):" , " print(\"Hello from runacton\")" , " env.exit(0)" ] perms <- getPermissions script setPermissions script perms{ executable = True } (returnCode, cmdOut, cmdErr) <- runRunacton script [] proj assertEqual "runacton should succeed" ExitSuccess returnCode assertEqual "runacton output" "Hello from runacton\n" cmdOut assertEqual "runacton stderr" "" cmdErr , testCase "runacton ignores project Build.act" $ do withSystemTempDirectory "acton-runacton-proj" $ \proj -> do let name = "demo" fp = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix (Fingerprint.fingerprintPrefixForName name) 1) srcDir = proj "src" mainFile = srcDir "main.act" script = proj "script.act" createDirectoryIfMissing True srcDir writeFile (proj "Build.act") $ unlines [ "name = \"" ++ name ++ "\"" , "fingerprint = " ++ fp , "" ] writeFile mainFile $ unlines [ "actor main(env):" , " print(\"Project main\")" , " env.exit(0)" ] writeFile script $ unlines [ "#!/usr/bin/env runacton" , "actor main(env):" , " print(\"Script main\")" , " env.exit(0)" ] perms <- getPermissions script setPermissions script perms{ executable = True } (returnCode, cmdOut, cmdErr) <- runRunacton script [] proj assertEqual "runacton should succeed" ExitSuccess returnCode assertEqual "runacton output" "Script main\n" cmdOut assertEqual "runacton stderr" "" cmdErr #endif ] parseFlagTests = testGroup "acton compiler flags" [ flagGolden "parse flag prints AST" "test/parse/simple.golden" ["--quiet", "--parse"] , flagGolden "kinds flag prints kinds" "test/parse/simple.kinds.golden" ["--quiet", "--kinds"] , flagGolden "types flag prints types" "test/parse/simple.types.golden" ["--quiet", "--types"] , flagGolden "sigs flag prints signatures" "test/parse/simple.sigs.golden" ["--quiet", "--sigs"] , flagGolden "norm flag prints normalized" "test/parse/simple.norm.golden" ["--quiet", "--norm"] , flagGolden "deact flag prints deactorized" "test/parse/simple.deact.golden" ["--quiet", "--deact"] , flagGolden "cps flag prints CPS" "test/parse/simple.cps.golden" ["--quiet", "--cps"] , flagGolden "llift flag prints lifted" "test/parse/simple.llift.golden" ["--quiet", "--llift"] , flagGolden "box flag prints boxing" "test/parse/simple.box.golden" ["--quiet", "--box"] -- Avoid #line directives (absolute paths) so hgen/cgen goldens stay stable across machines , flagGolden "hgen flag prints header" "test/parse/simple.hgen.golden" ["--quiet", "--dbg-no-lines", "--hgen"] , flagGolden "cgen flag prints c" "test/parse/simple.cgen.golden" ["--quiet", "--dbg-no-lines", "--cgen"] , flagGolden "all flags combined" "test/parse/simple.all.golden" ["--quiet", "--parse", "--kinds", "--types", "--sigs", "--norm", "--deact", "--cps", "--llift", "--box", "--dbg-no-lines", "--hgen"] , testCase "optimize parser accepts release aliases" $ do assertParsedBuildOptimize ["build", "--release"] C.ReleaseFast assertParsedBuildOptimize ["build", "--release=safe"] C.ReleaseSafe assertParsedBuildOptimize ["build", "--release=SmAlL"] C.ReleaseSmall assertParsedBuildOptimize ["build", "--release=FAST"] C.ReleaseFast assertParsedBuildOptimize ["build", "--optimize=release"] C.ReleaseFast assertParsedBuildOptimize ["build", "--optimize=ReLeAsE"] C.ReleaseFast assertParsedBuildOptimize ["build", "--optimize=dEbUg"] C.Debug assertParsedBuildOptimize ["build", "--optimize=reLeAsEsMaLl"] C.ReleaseSmall assertParsedBuildOptimize ["build", "--optimize=RELEASEFAST"] C.ReleaseFast , testCase "explicit --optimize overrides --release alias" $ do assertParsedBuildOptimize ["build", "--release", "--optimize=releasesmall"] C.ReleaseSmall assertParsedBuildOptimize ["build", "--release=fast", "--optimize=debug"] C.Debug assertParsedBuildOptimize ["build", "--optimize=debug", "--release"] C.Debug , testCase "build parser accepts --parse-serial" $ do parsed <- parseArgs ["build", "--parse-serial"] case parsed of C.CmdOpt _ (C.Build buildOpts) -> assertBool "serial parser flag should be set" (C.parse_serial (C.buildCompile buildOpts)) _ -> assertFailure "expected build command" , testCase "build parser help includes --release alias" $ do helpText <- renderParserHelp ["build", "--help"] assertBool "help text should include --release" ("--release" `isInfixOf` helpText) assertBool "help text should mention release variants" ("=safe or =small" `isInfixOf` helpText) assertBool "help text should mention default release mode" ("same as --release=fast" `isInfixOf` helpText) , testCase "sig parser accepts target and project options" $ do parsed <- parseArgs ["sig", "--always-build", "--dep", "dep=../dep", "--searchpath", "out/types", "foo.bar"] case parsed of C.CmdOpt _ (C.Sig sigOpts) -> do let opts = C.sigCompile sigOpts assertEqual "sig target" "foo.bar" (C.sigTarget sigOpts) assertBool "sig should force rebuild when requested" (C.alwaysbuild opts) assertEqual "sig searchpath" ["out/types"] (C.searchpath opts) assertEqual "sig dep overrides" [("dep", "../dep")] (C.dep_overrides opts) assertBool "sig should skip final build" (C.skip_build opts) _ -> assertFailure "expected sig command" , testCase "install parser accepts package options" $ do parsed <- parseArgs ["install", "ncurl", "--repo-url", "https://github.com/stratoweave/ncurl", "--repo-ref", "main", "--pkg-name", "ncurl-index", "--github-token", "tok"] case parsed of C.CmdOpt _ (C.Install installOpts) -> do assertEqual "install name" "ncurl" (C.installName installOpts) assertEqual "repo url" "https://github.com/stratoweave/ncurl" (C.installRepoUrl installOpts) assertEqual "repo ref" "main" (C.installRepoRef installOpts) assertEqual "pkg name" "ncurl-index" (C.installPkgName installOpts) assertEqual "github token" "tok" (C.installGithubToken installOpts) _ -> assertFailure "expected install command" , testCase "uninstall parser accepts app name" $ do parsed <- parseArgs ["uninstall", "ncurl"] case parsed of C.CmdOpt _ (C.Uninstall uninstallOpts) -> assertEqual "uninstall name" "ncurl" (C.uninstallName uninstallOpts) _ -> assertFailure "expected uninstall command" , testCase "sig finds prebuilt dependency interfaces" $ do withSystemTempDirectory "acton-sig-prebuilt-dep" $ \tmp -> do actonBinDir <- Paths_acton.getBinDir let actonCandidate = actonBinDir "acton" distActon = "../../dist/bin/acton" hasActonCandidate <- doesFileExist actonCandidate actonExe <- canonicalizePath $ if hasActonCandidate then actonCandidate else distActon sysPath <- canonicalizePath "../../dist" env0 <- getEnvironment let homeDir = tmp "home" rootProj = tmp "root" depProj = tmp "dep" envWithHome = ("HOME", homeDir) : filter ((/= "HOME") . fst) env0 mkFp name = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix (Fingerprint.fingerprintPrefixForName name) 1) writeBuildActAt :: FilePath -> String -> [(String, FilePath)] -> IO () writeBuildActAt dir name deps = do createDirectoryIfMissing True (dir "src") let depsBody = intercalate ",\n" [ " \"" ++ depName ++ "\": (\n" ++ " path=" ++ show depPath ++ "\n" ++ " )" | (depName, depPath) <- deps ] depsSection = if null deps then "dependencies = {}" else "dependencies = {\n" ++ depsBody ++ "\n}" writeFile (dir "Build.act") $ unlines [ "name = " ++ show name , "fingerprint = " ++ mkFp name , "" , depsSection , "" , "zig_dependencies = {}" ] createDirectoryIfMissing True homeDir writeBuildActAt depProj "sig_dep" [] writeFile (depProj "src" "prebuilt.act") $ unlines [ "def count() -> int:" , " return 1" ] (buildCode, buildOut, buildErr) <- readCreateProcessWithExitCode (proc actonExe ["build", "--syspath", sysPath, "--skip-build", "src/prebuilt.act"]) { cwd = Just depProj, env = Just envWithHome } "" when (buildCode /= ExitSuccess) $ assertFailure ("dependency build failed:\nstdout:\n" ++ buildOut ++ "\nstderr:\n" ++ buildErr) removeFile (depProj "src" "prebuilt.act") writeBuildActAt rootProj "sig_root" [("sig_dep", depProj)] writeFile (rootProj "src" "main.act") $ unlines [ "actor main(env):" , " env.exit(0)" ] (sigCode, sigOut, sigErr) <- readCreateProcessWithExitCode (proc actonExe ["sig", "--syspath", sysPath, "prebuilt"]) { cwd = Just rootProj, env = Just envWithHome } "" when (sigCode /= ExitSuccess) $ assertFailure ("acton sig failed:\nstdout:\n" ++ sigOut ++ "\nstderr:\n" ++ sigErr) assertBool "sig output should include the dependency function" ("count : () -> int" `isInfixOf` sigOut) , testCase "sig prints private names without importing them" $ do withSystemTempDirectory "acton-sig-private-names" $ \tmp -> do actonExe <- canonicalizePath "../../dist/bin/acton" sysPath <- canonicalizePath "../../dist" env0 <- getEnvironment let homeDir = tmp "home" proj = tmp "proj" srcDir = proj "src" rootProj = tmp "root" rootSrcDir = rootProj "src" envWithHome = ("HOME", homeDir) : filter ((/= "HOME") . fst) env0 mkFp name = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix (Fingerprint.fingerprintPrefixForName name) 1) writeBuildActAt :: FilePath -> String -> [(String, FilePath)] -> IO () writeBuildActAt dir pkgName deps = do createDirectoryIfMissing True (dir "src") let depsBody = intercalate ",\n" [ " \"" ++ depName ++ "\": (\n" ++ " path=" ++ show depPath ++ "\n" ++ " )" | (depName, depPath) <- deps ] depsSection = if null deps then "dependencies = {}" else "dependencies = {\n" ++ depsBody ++ "\n}" writeFile (dir "Build.act") $ unlines [ "name = " ++ show pkgName , "fingerprint = " ++ mkFp pkgName , depsSection , "zig_dependencies = {}" ] createDirectoryIfMissing True homeDir writeBuildActAt proj "sig_private" [] writeFile (srcDir "lib.act") $ unlines [ "def _private() -> int:" , " return 1" , "" , "def public() -> int:" , " return _private()" ] (buildCode, buildOut, buildErr) <- readCreateProcessWithExitCode (proc actonExe ["build", "--syspath", sysPath, "--skip-build", "src/lib.act"]) { cwd = Just proj, env = Just envWithHome } "" when (buildCode /= ExitSuccess) $ assertFailure ("library build failed:\nstdout:\n" ++ buildOut ++ "\nstderr:\n" ++ buildErr) (sigCode, sigOut, sigErr) <- readCreateProcessWithExitCode (proc actonExe ["sig", "--syspath", sysPath, "lib"]) { cwd = Just proj, env = Just envWithHome } "" when (sigCode /= ExitSuccess) $ assertFailure ("acton sig failed:\nstdout:\n" ++ sigOut ++ "\nstderr:\n" ++ sigErr) assertBool "sig output should include private function" ("_private : () -> int" `isInfixOf` sigOut) assertBool "sig output should include public function" ("public : () -> int" `isInfixOf` sigOut) writeFile (srcDir "main.act") $ unlines [ "from lib import _private" , "" , "actor main(env):" , " env.exit(0)" ] (importCode, _importOut, importErr) <- readCreateProcessWithExitCode (proc actonExe ["build", "--syspath", sysPath, "--skip-build", "src/main.act"]) { cwd = Just proj, env = Just envWithHome } "" assertBool ("private import should fail, stderr:\n" ++ importErr) (importCode /= ExitSuccess) removeFile (srcDir "lib.act") (cachedSigCode, cachedSigOut, cachedSigErr) <- readCreateProcessWithExitCode (proc actonExe ["sig", "--syspath", sysPath, "lib._private"]) { cwd = Just proj, env = Just envWithHome } "" when (cachedSigCode /= ExitSuccess) $ assertFailure ("cached acton sig failed:\nstdout:\n" ++ cachedSigOut ++ "\nstderr:\n" ++ cachedSigErr) assertBool "cached sig output should include private function" ("_private : () -> int" `isInfixOf` cachedSigOut) writeBuildActAt rootProj "sig_private_root" [("sig_private", proj)] writeFile (rootSrcDir "main.act") $ unlines [ "from lib import _private" , "" , "actor main(env):" , " env.exit(0)" ] (cachedImportCode, _cachedImportOut, cachedImportErr) <- readCreateProcessWithExitCode (proc actonExe ["build", "--syspath", sysPath, "--skip-build", "src/main.act"]) { cwd = Just rootProj, env = Just envWithHome } "" assertBool ("cached private import should fail, stderr:\n" ++ cachedImportErr) (cachedImportCode /= ExitSuccess) , testCase "acton test --help includes --no-cache and --tag" $ do acton <- canonicalizePath "../../dist/bin/acton" (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (proc acton ["test", "--help"]) "" assertEqual "acton test --help should succeed" ExitSuccess returnCode assertEqual "acton test --help stderr" "" cmdErr assertBool "acton test --help should include --no-cache" ("--no-cache" `isInfixOf` cmdOut) assertBool "acton test --help should include --tag" ("--tag" `isInfixOf` cmdOut) , testCase "acton test reruns cached snapshot when expected file changes" $ do withSystemTempDirectory "acton-test-snapshot-cache" $ \proj -> do actonBinDir <- Paths_acton.getBinDir let distActon = "../../dist/bin/acton" actonCandidate = actonBinDir "acton" hasDistActon <- doesFileExist distActon acton <- canonicalizePath $ if hasDistActon then distActon else actonCandidate let name = "snapshot_cache" fp = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix (Fingerprint.fingerprintPrefixForName name) 1) srcDir = proj "src" modName = "snap" srcFile = srcDir modName <.> "act" expectedDir = proj "snapshots" "expected" modName expectedFile = expectedDir "stable" runTest args = readCreateProcessWithExitCode (proc acton ("test" : args)) { cwd = Just proj } "" createDirectoryIfMissing True srcDir createDirectoryIfMissing True expectedDir writeFile (proj "Build.act") $ unlines [ "name = \"" ++ name ++ "\"" , "fingerprint = " ++ fp , "" ] writeFile srcFile $ unlines [ "import testing" , "" , "def _test_stable() -> str:" , " return \"snapshot v1\"" ] writeFile expectedFile "snapshot v1" (code1, out1, err1) <- runTest ["--iter", "1"] when (code1 /= ExitSuccess) $ assertFailure ("initial acton test failed:\nstdout:\n" ++ out1 ++ "\nstderr:\n" ++ err1) (code2, out2, err2) <- runTest ["--iter", "1", "--show-cached"] when (code2 /= ExitSuccess) $ assertFailure ("cached acton test failed:\nstdout:\n" ++ out2 ++ "\nstderr:\n" ++ err2) assertBool "second run should reuse cached snapshot result" ("Using cached results for 1 tests" `isInfixOf` out2) assertBool "cached run should mark the result as cached" ("* = cached test result" `isInfixOf` out2) writeFile expectedFile "snapshot v2" (code3, out3, err3) <- runTest ["--iter", "1", "--show-cached"] assertEqual "changed expected snapshot should invalidate cached success" (ExitFailure 1) code3 assertBool "rerun should report snapshot mismatch" ("Test output does not match expected snapshot value" `isInfixOf` out3 || "Test output does not match expected snapshot value" `isInfixOf` err3) assertBool "stale cached snapshot result should not be reused after expected change" (not ("Using cached results for 1 tests" `isInfixOf` out3)) ] where parserInfo = OA.info (C.cmdLineParser OA.<**> OA.helper) C.descr parseArgs args = case OA.execParserPure OA.defaultPrefs parserInfo args of OA.Success result -> return result OA.Failure failure -> do let (msg, _) = OA.renderFailure failure "acton" assertFailure ("parser failed for " ++ unwords args ++ ":\n" ++ msg) OA.CompletionInvoked _ -> assertFailure ("parser requested shell completion for " ++ unwords args) assertParsedBuildOptimize args expected = do parsed <- parseArgs args case parsed of C.CmdOpt _ (C.Build buildOpts) -> assertEqual ("unexpected optimize mode for " ++ unwords args) expected (C.optimize (C.buildCompile buildOpts)) _ -> assertFailure ("expected build command for " ++ unwords args) renderParserHelp args = case OA.execParserPure OA.defaultPrefs parserInfo args of OA.Failure failure -> pure (fst (OA.renderFailure failure "acton")) OA.Success _ -> assertFailure ("expected parser help for " ++ unwords args) OA.CompletionInvoked _ -> assertFailure ("parser requested shell completion for " ++ unwords args) flagGolden label golden flags = goldenVsString label golden $ do acton <- canonicalizePath "../../dist/bin/acton" sample <- canonicalizePath "test/parse/simple.act" (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (proc acton (flags ++ [sample])) "" assertEqual ("acton " ++ unwords flags ++ " should succeed") ExitSuccess returnCode assertEqual ("acton " ++ unwords flags ++ " stderr") "" cmdErr return (LBS.pack cmdOut) actonProjTests = testGroup "compiler project tests" [ testCase "simple project" $ do testBuild "" ExitSuccess False "test/project/simple" testBuild "" ExitSuccess False "test/project/simple" , testCase "with missing src/ dir" $ do testBuild "" (ExitFailure 1) False "test/project/missing_src" , testCase "qualified --root test.main" $ do testBuild "--root test.main" ExitSuccess False "test/project/qualified_root" -- after used to avoid races on files in same project dir as above test , after AllFinish "qualified_root" $ testCase "unqualified --root main" $ do (returnCode, cmdOut, cmdErr) <- buildThing "--root main" "test/project/qualified_root" assertEqual "acton should error out" (ExitFailure 1) returnCode assertEqual "acton should report error" "acton: Project build requires a qualified root actor name, like foo.main\n" cmdErr , testCase "project with nested path deps" $ do let proj = "../../test/compiler/acton_proj_deps" depA = proj "deps/dep_a" depB = proj "deps/dep_b" wipe p = void $ readCreateProcessWithExitCode (shell $ "rm -rf " ++ p ++ "/build.zig " ++ p ++ "/build.zig.zon " ++ p ++ "/out") "" mapM_ wipe [proj, depA, depB] -- Build main project via acton; dependencies should be built automatically testBuild "" ExitSuccess False proj -- Run produced binary (cRun, _outRun, _errRun) <- readCreateProcessWithExitCode (shell "./out/bin/main"){ cwd = Just proj } "" assertEqual "project binary should run" ExitSuccess cRun zon <- readFile (proj "build.zig.zon") assertBool "build.zig.zon should declare dep_a" (".dep_a" `isInfixOf` zon) assertBool "build.zig.zon should declare dep_b" (".dep_b" `isInfixOf` zon) , testCase "builds dependencies even if unused in imports" $ do let proj = "../../test/compiler/unused_dep" depU = proj "deps/dep_unused" wipe p = void $ readCreateProcessWithExitCode (shell $ "rm -rf " ++ p ++ "/build.zig " ++ p ++ "/build.zig.zon " ++ p ++ "/out") "" mapM_ wipe [proj, depU] testBuild "" ExitSuccess False proj let depObj = depU "out/types/acton_empty.c" exists <- doesFileExist depObj assertBool "dependency output should be generated even if unused (dummy allowed)" exists , testCase "dep overrides propagate to build.zig.zon" $ do let proj = "../../test/compiler/dep_override" depA = proj "deps/dep_a" depB = proj "deps/dep_b" depC = proj "deps/dep_c" wipe p = void $ readCreateProcessWithExitCode (shell $ "rm -rf " ++ p ++ "/build.zig " ++ p ++ "/build.zig.zon " ++ p ++ "/out") "" expect needle hay msg = assertBool msg (needle `isInfixOf` hay) expectAny needles hay msg = assertBool msg (any (`isInfixOf` hay) needles) mapM_ wipe [proj, depA, depB, depC] runActon "build --dep dep_a=deps/dep_a --dep dep_b=deps/dep_b --dep ghost=deps/ghost" ExitSuccess False proj rootZon <- readFile (proj "build.zig.zon") depAZon <- readFile (depA "build.zig.zon") expect ".dep_a = .{" rootZon "root build.zig.zon should declare dep_a" expectAny ["dep_override/deps/dep_a", "dep_override\\deps\\dep_a"] rootZon "root build.zig.zon should use dep_a override path" expect ".dep_b = .{" rootZon "root build.zig.zon should declare dep_b" expectAny ["dep_override/deps/dep_b", "dep_override\\deps\\dep_b"] rootZon "root build.zig.zon should use dep_b override path transitively" assertBool "root build.zig.zon should not use cached dep_b hash path" (not ("dep_b-" `isInfixOf` rootZon)) expect ".dep_c = .{" rootZon "root build.zig.zon should declare dep_c (non-overridden) transitively" expectAny ["dep_override/deps/dep_c", "dep_override\\deps\\dep_c"] rootZon "root build.zig.zon should keep dep_c path" assertBool "root build.zig.zon should not include undeclared ghost override" (not ("ghost" `isInfixOf` rootZon)) expect ".dep_b = .{" depAZon "dep_a build.zig.zon should declare dep_b" expectAny ["dep_override/deps/dep_b", "dep_override\\deps\\dep_b", "../dep_b", "..\\dep_b"] depAZon "dep_a build.zig.zon should use dep_b override path" assertBool "dep_a build.zig.zon should not use cached dep_b hash path" (not ("dep_b-" `isInfixOf` depAZon)) expect ".dep_c = .{" depAZon "dep_a build.zig.zon should declare dep_c" expectAny ["dep_override/deps/dep_c", "dep_override\\deps\\dep_c", "../dep_c", "..\\dep_c"] depAZon "dep_a build.zig.zon should keep dep_c path" assertBool "dep_a build.zig.zon should not include undeclared ghost override" (not ("ghost" `isInfixOf` depAZon)) , testCase "zig deps do not collide with package deps in build.zig.zon" $ do withSystemTempDirectory "acton-zig-dep-name-collision" $ \tmp -> do actonExe <- canonicalizePath "../../dist/bin/acton" let rootProj = tmp "root" wrapperProj = rootProj "deps" "acton_lmdb" zigProj = rootProj "deps" "lmdb_zig" mkFp name = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix (Fingerprint.fingerprintPrefixForName name) 1) createDirectoryIfMissing True (rootProj "src") createDirectoryIfMissing True (wrapperProj "src") createDirectoryIfMissing True (zigProj "src") writeFile (rootProj "Build.act") $ unlines [ "name = \"root_proj\"" , "fingerprint = " ++ mkFp "root_proj" , "dependencies = {" , " \"lmdb\": (path=\"deps/acton_lmdb\")" , "}" , "zig_dependencies = {}" ] writeFile (rootProj "src" "main.act") $ unlines [ "from lmdb import ready" , "" , "actor main(env):" , " if ready():" , " env.exit(0)" , " else:" , " env.exit(1)" ] writeFile (wrapperProj "Build.act") $ unlines [ "name = \"acton_lmdb\"" , "fingerprint = " ++ mkFp "acton_lmdb" , "dependencies = {}" , "zig_dependencies = {" , " \"lmdb\": (path=\"../lmdb_zig\", artifacts=[\"lmdb\"])" , "}" ] writeFile (wrapperProj "src" "lmdb.act") $ unlines [ "def ready() -> bool:" , " return True" ] writeFile (zigProj "build.zig") $ unlines [ "const std = @import(\"std\");" , "" , "pub fn build(b: *std.Build) void {" , " const target = b.standardTargetOptions(.{});" , " const optimize = b.standardOptimizeOption(.{});" , " const lib = b.addLibrary(.{" , " .name = \"lmdb\"," , " .linkage = .static," , " .root_module = b.createModule(.{" , " .root_source_file = b.path(\"src/root.zig\")," , " .target = target," , " .optimize = optimize," , " })," , " });" , " b.installArtifact(lib);" , "}" ] writeFile (zigProj "build.zig.zon") $ unlines [ ".{" , " .name = .lmdb_zig," , " .version = \"0.0.0\"," , " .fingerprint = 0xd571f8beb86c413e," , " .minimum_zig_version = \"0.15.2\"," , " .dependencies = .{}," , " .paths = .{\"\"}," , "}" ] writeFile (zigProj "src" "root.zig") $ unlines [ "pub export fn lmdb_test() void {}" ] (returnCode, _cmdOut, cmdErr) <- readCreateProcessWithExitCode (proc actonExe ["build"]){ cwd = Just rootProj } "" assertEqual "acton should build when package and zig deps share a name" ExitSuccess returnCode assertBool "acton should not report the old dependency option collision" (not ("invalid option: -Dacton_modules" `isInfixOf` cmdErr)) rootZon <- readFile (rootProj "build.zig.zon") rootBuildZig <- readFile (rootProj "build.zig") assertBool "root build.zig.zon should keep the package dep key" (" .lmdb = .{" `isInfixOf` rootZon) assertBool "root build.zig.zon should namespace the zig dep key" (" .acton_zig_lmdb = .{" `isInfixOf` rootZon) assertEqual "root build.zig.zon should emit the package dep key only once" 1 (length (filter (== " .lmdb = .{") (lines rootZon))) assertBool "root build.zig should keep the package dep lookup" ("const actdep_lmdb = b.dependency(\"lmdb\"" `isInfixOf` rootBuildZig) assertBool "root build.zig should namespace the zig dep lookup" ("const dep_lmdb = b.dependency(\"acton_zig_lmdb\"" `isInfixOf` rootBuildZig) , testCase "transitive zig deps deduplicate by identity and split on collision" $ do withSystemTempDirectory "acton-zig-transitive-dedup" $ \tmp -> do actonExe <- canonicalizePath "../../dist/bin/acton" let rootProj = tmp "root" depAProj = rootProj "deps" "dep_a" depBProj = rootProj "deps" "dep_b" depCProj = rootProj "deps" "dep_c" zigCommonProj = rootProj "deps" "zig_common" zigOtherProj = rootProj "deps" "zig_other" mkFp name = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix (Fingerprint.fingerprintPrefixForName name) 1) writeWrapper proj name zigPath moduleName = do createDirectoryIfMissing True (proj "src") writeFile (proj "Build.act") $ unlines [ "name = " ++ show name , "fingerprint = " ++ mkFp name , "dependencies = {}" , "zig_dependencies = {" , " \"shared\": (path=" ++ show zigPath ++ ", artifacts=[\"shared\"])" , "}" ] writeFile (proj "src" (moduleName ++ ".act")) $ unlines [ "def ready() -> bool:" , " return True" ] writeZigPkg proj = do createDirectoryIfMissing True (proj "src") writeFile (proj "build.zig") $ unlines [ "const std = @import(\"std\");" , "" , "pub fn build(b: *std.Build) void {" , " const target = b.standardTargetOptions(.{});" , " const optimize = b.standardOptimizeOption(.{});" , " const lib = b.addLibrary(.{" , " .name = \"shared\"," , " .linkage = .static," , " .root_module = b.createModule(.{" , " .root_source_file = b.path(\"src/root.zig\")," , " .target = target," , " .optimize = optimize," , " })," , " });" , " b.installArtifact(lib);" , "}" ] writeFile (proj "build.zig.zon") $ unlines [ ".{" , " .name = .lmdb_zig," , " .version = \"0.0.0\"," , " .fingerprint = 0xd571f8beb86c413e," , " .minimum_zig_version = \"0.15.2\"," , " .dependencies = .{}," , " .paths = .{\"\"}," , "}" ] writeFile (proj "src" "root.zig") $ unlines [ "pub export fn shared_test() void {}" ] createDirectoryIfMissing True (rootProj "src") writeFile (rootProj "Build.act") $ unlines [ "name = \"root_proj\"" , "fingerprint = " ++ mkFp "root_proj" , "dependencies = {" , " \"dep_a\": (path=\"deps/dep_a\")," , " \"dep_b\": (path=\"deps/dep_b\")," , " \"dep_c\": (path=\"deps/dep_c\")" , "}" , "zig_dependencies = {}" ] writeFile (rootProj "src" "main.act") $ unlines [ "import dep_a" , "import dep_b" , "import dep_c" , "" , "actor main(env):" , " if dep_a.ready() and dep_b.ready() and dep_c.ready():" , " env.exit(0)" , " else:" , " env.exit(1)" ] writeWrapper depAProj "dep_a" "../zig_common" "dep_a" writeWrapper depBProj "dep_b" "../zig_common" "dep_b" writeWrapper depCProj "dep_c" "../zig_other" "dep_c" writeZigPkg zigCommonProj writeZigPkg zigOtherProj (returnCode, _cmdOut, cmdErr) <- readCreateProcessWithExitCode (proc actonExe ["build"]){ cwd = Just rootProj } "" assertEqual "acton should build with colliding transitive zig dep names" ExitSuccess returnCode assertBool "acton should not report the old dependency option collision" (not ("invalid option: -Dacton_modules" `isInfixOf` cmdErr)) rootZon <- readFile (rootProj "build.zig.zon") rootBuildZig <- readFile (rootProj "build.zig") assertBool "root build.zig.zon should include the first local zig dep name" (" .acton_zig_shared = .{" `isInfixOf` rootZon) assertBool "root build.zig.zon should include the second colliding zig dep name" (" .acton_zig_shared_2 = .{" `isInfixOf` rootZon) assertBool "root build.zig.zon should not emit a third deduped copy" (not (" .acton_zig_shared_3 = .{" `isInfixOf` rootZon)) assertBool "root build.zig should bind the deduped zig dep once" ("const dep_shared = b.dependency(\"acton_zig_shared\"" `isInfixOf` rootBuildZig) assertBool "root build.zig should bind the colliding zig dep separately" ("const dep_shared_2 = b.dependency(\"acton_zig_shared_2\"" `isInfixOf` rootBuildZig) , testCase "dep override path must be an Acton project root" $ do withSystemTempDirectory "acton-invalid-dep-override" $ \proj -> do let srcDir = proj "src" buildAct = proj "Build.act" mainAct = srcDir "main.act" createDirectoryIfMissing True srcDir createDirectoryIfMissing True (proj "deps") writeFile buildAct $ unlines [ "name = \"invalid_dep_override\"" , "fingerprint = 0xb33bef4512345678" , "" , "dependencies = {" , " \"dep_a\": (path=\"deps/dep_a_missing\")" , "}" ] writeFile mainAct $ unlines [ "actor main(env):" , " print(\"hello\")" , " env.exit(0)" ] actonExe <- canonicalizePath "../../dist/bin/acton" (returnCode, _cmdOut, cmdErr) <- readCreateProcessWithExitCode (proc actonExe ["build", "--dep", "dep_a=deps"]){ cwd = Just proj } "" assertEqual "acton should fail for invalid --dep path" (ExitFailure 1) returnCode assertBool "error should mention bad dependency path" ("Dependency dep_a path is not an Acton project root" `isInfixOf` cmdErr) assertBool "error should mention required project files" ("Build.act" `isInfixOf` cmdErr) assertBool "error should mention src requirement" ("src/" `isInfixOf` cmdErr) -- Verify pruning keeps binaries for modules that still have roots across build / test runs. , testCase "executable pruning" $ do let proj = "test/project/prune_executables" cleanOut proj -- Build once, then run tests: binaries should stay and both build/test -- root .c stubs should coexist. testBuild "" ExitSuccess False proj let binFoo = proj "out/bin/foo" binBar = proj "out/bin/bar" testRoot = proj "out/types/tests/simple.test_root.c" buildRoot = proj "out/types/foo.root.c" assertBool "foo binary should exist after build" =<< doesFileExist binFoo assertBool "bar binary should exist after build" =<< doesFileExist binBar runActon "test" ExitSuccess False proj assertBool "foo binary should exist after acton test" =<< doesFileExist binFoo assertBool "bar binary should exist after acton test" =<< doesFileExist binBar assertBool "build root.c should exist after acton test" =<< doesFileExist buildRoot assertBool "test_root.c should exist after acton test" =<< doesFileExist testRoot -- Partial single-file rebuild must not prune other modules' outputs. , testCase "partial build leaves unrelated outputs" $ do let proj = "test/project/prune_partials" srcDir = proj "src" fooAct = srcDir "foo.act" barAct = srcDir "bar.act" fooContent = "actor main(env):\n print(\"foo\")\n env.exit(0)\n" barContent = "actor main(env):\n print(\"bar\")\n env.exit(0)\n" barC = proj "out/types/bar.c" barH = proj "out/types/bar.h" barTy = proj "out/types/bar.ty" createDirectoryIfMissing True srcDir writeFile fooAct fooContent writeFile barAct barContent cleanOut proj -- Full build first to create bar artifacts. testBuild "" ExitSuccess False proj acton <- canonicalizePath "../../dist/bin/acton" -- Single-file build of foo must not prune outputs from other moduels -- since we don't have full visibility, so bar should remain (returnCode, _, _) <- readCreateProcessWithExitCode (proc acton ["--skip-build", "--always-build", "src/foo.act"]){ cwd = Just proj } "" assertEqual "acton single-file build should succeed" ExitSuccess returnCode mapM_ (\p -> doesFileExist p >>= assertBool (p ++ " should exist")) [barC, barH, barTy] -- Full rebuild should prune roots / bins when the source module is removed. , testCase "full build prunes stale roots and bins" $ do let proj = "test/project/prune_roots" barAct = proj "src/bar.act" barContent = "#\n# removed in test to trigger pruning\n\nactor main(env):\n print(\"bar\")\n env.exit(0)\n" barRoot = proj "out/types/bar.root.c" barBin = proj "out/bin/bar" -- Start from a clean slate and write bar.act to ensure it exists cleanOut proj writeFile barAct barContent -- Initial build should emit bar root & bin. testBuild "" ExitSuccess False proj assertBool "bar root stub should exist after initial build" =<< doesFileExist barRoot assertBool "bar binary should exist after initial build" =<< doesFileExist barBin -- Delete source; full build should prune root/bin. removeFile barAct `catch` (\(_ :: IOException) -> return ()) testBuild "" ExitSuccess False proj assertBool "bar root stub should be removed after source deletion" . not =<< doesFileExist barRoot assertBool "bar binary should be removed after source deletion" . not =<< doesFileExist barBin ] actonRootArgTests = testGroup "compiler acton --root tests" [ testCase "qualified --root test.main" $ testBuild "--root test.main" ExitSuccess False "test/root/test.act" , testCase "unqualified --root main" $ testBuild "--root main" ExitSuccess False "test/root/test.act" , after AllFinish "qualified --root" $ after AllFinish "unqualified --root" $ testCase "discover root actor" $ testBuildAndRun "" "" ExitSuccess False "test/root/test.act" ] rtsTests = testGroup "RTS" [ testCase "arg parsing: foo --bar --rts-verbose" $ do testBuildAndRun "" "foo --bar --rts-verbose" ExitSuccess False "../../test/rts/argv1.act" , testCase "arg parsing: --rts-verbose --rts-wthreads 7 foo --bar" $ do testBuildAndRun "" "--rts-verbose --rts-wthreads 7 foo --bar" ExitSuccess False "../../test/rts/argv2.act" , testCase "arg parsing: --rts-verbose --rts-wthreads=7 foo --bar" $ do testBuildAndRun "" "--rts-verbose --rts-wthreads=7 foo --bar" ExitSuccess False "../../test/rts/argv3.act" , testCase "arg parsing: --rts-wthreads 7 count" $ do testBuildThing "" ExitSuccess False "../../test/rts/argv4.act" (returnCode, cmdOut, cmdErr) <- runThing "--rts-verbose --rts-wthreads 7 foo --bar" "../../test/rts/argv4.act" assertEqual "RTS wthreads success retCode" ExitSuccess returnCode assertEqual "RTS wthreads output" True (isInfixOf "Using 7 worker threads" cmdErr) , testCase "arg parsing: --rts-wthreads 7 count" $ do testBuildThing "" ExitSuccess False "../../test/rts/argv5.act" (returnCode, cmdOut, cmdErr) <- runThing "--rts-verbose --rts-wthreads=7 foo --bar" "../../test/rts/argv5.act" assertEqual "RTS wthreads success retCode" ExitSuccess returnCode assertEqual "RTS wthreads output" True (isInfixOf "Using 7 worker threads" cmdErr) , testCase "arg parsing: --rts-verbose --rts-wthreads=7 -- foo --bar --rts-verbose" $ do testBuildAndRun "" "--rts-verbose --rts-wthreads=7 -- foo --bar --rts-verbose" ExitSuccess False "../../test/rts/argv6.act" , testCase "arg parsing: --rts-wthreads" $ do testBuildThing "" ExitSuccess False "../../test/rts/argv7.act" (returnCode, cmdOut, cmdErr) <- runThing "--rts-wthreads" "../../test/rts/argv7.act" assertEqual "RTS wthreads error retCode" (ExitFailure 1) returnCode assertEqual "RTS wthreads error cmdErr" "ERROR: --rts-wthreads requires an argument.\n" cmdErr ] stdlibTests = testGroup "stdlib" [ testCase "time" $ do epoch <- getCurrentTime >>= pure . utcTimeToPOSIXSeconds >>= pure . round testBuildAndRun "" (show epoch) ExitSuccess False "../../test/stdlib/test_time.act" ] crossCompileTests = testGroup "cross-compilation tests" [ testCase "build hello --target aarch64-macos-none --db" $ do runActon "build --target aarch64-macos-none --db" ExitSuccess False "../../test/compiler/hello/" , testCase "build hello --target aarch64-windows-gnu" $ do runActon "build --target aarch64-windows-gnu" ExitSuccess False "../../test/compiler/hello/" , testCase "build hello --target x86_64-macos-none --db" $ do runActon "build --target x86_64-macos-none --db" ExitSuccess False "../../test/compiler/hello/" , testCase "build hello --target x86_64-linux-gnu.2.27 --db" $ do runActon "build --target x86_64-linux-gnu.2.27 --db" ExitSuccess False "../../test/compiler/hello/" , testCase "build hello --target x86_64-linux-musl --db" $ do runActon "build --target x86_64-linux-musl --db" ExitSuccess False "../../test/compiler/hello/" , testCase "build hello --target x86_64-windows-gnu" $ do runActon "build --target x86_64-windows-gnu" ExitSuccess False "../../test/compiler/hello/" ] pkgCliTests = testGroup "pkg CLI" [ testCase "parse github repo url" $ do case PkgCommands.parseGithubRepoUrl "https://github.com/actonlang/foo.git#main" of Left err -> assertFailure err Right info -> do assertEqual "owner" "actonlang" (PkgCommands.repoOwner info) assertEqual "repo" "foo" (PkgCommands.repoName info) assertEqual "ref" (Just "main") (PkgCommands.repoRef info) , testCase "github clone url strips ref fragment" $ do assertEqual "clone url" "https://github.com/actonlang/foo.git" (PkgCommands.githubCloneUrl "https://github.com/actonlang/foo.git#main") , testCase "github commit sha recognizer requires full sha" $ do assertBool "full sha" (PkgCommands.isGithubCommitSha "0123456789abcdef0123456789abcdef01234567") assertBool "short sha is resolved through GitHub" (not (PkgCommands.isGithubCommitSha "0123456")) , testCase "pkg search matches prefix" $ do let pkg = PkgCommands.PackageEntry "foo" "desc" "https://github.com/actonlang/foo" ok <- PkgCommands.matchesAllTerms ["foo"] pkg assertBool "prefix matches" ok ok2 <- PkgCommands.matchesAllTerms ["bar"] pkg assertBool "non-prefix does not match" (not ok2) , testCase "decode package index returns only libraries" $ do let body = concat [ "{\"packages\":[" , "{\"name\":\"foo\",\"kinds\":[\"library\",\"app\"],\"description\":\"desc\",\"repo_url\":\"https://github.com/actonlang/foo\"}" , ",{\"name\":\"bar\",\"kinds\":[\"app\"],\"description\":\"app\",\"repo_url\":\"https://github.com/actonlang/bar\"}" , "]}" ] case PkgCommands.decodePackageIndex (LBS.pack body) of Left err -> assertFailure err Right pkgs -> do assertEqual "one package" 1 (length pkgs) assertEqual "name" "foo" (PkgCommands.pkgName (head pkgs)) , testCase "decode package index returns apps" $ do let body = concat [ "{\"packages\":[" , "{\"name\":\"foo\",\"kinds\":[\"library\",\"app\"],\"description\":\"desc\",\"repo_url\":\"https://github.com/actonlang/foo\"}" , ",{\"name\":\"bar\",\"kinds\":[\"app\"],\"description\":\"app\",\"repo_url\":\"https://github.com/actonlang/bar\"}" , ",{\"name\":\"baz\",\"kinds\":[\"library\"],\"description\":\"lib\",\"repo_url\":\"https://github.com/actonlang/baz\"}" , "]}" ] case PkgCommands.decodeAppPackageIndex (LBS.pack body) of Left err -> assertFailure err Right pkgs -> do assertEqual "two apps" ["bar", "foo"] (sort (map PkgCommands.pkgName pkgs)) , testCase "decode package index requires kinds" $ do let body = concat [ "{\"packages\":[" , "{\"name\":\"foo\",\"description\":\"desc\",\"repo_url\":\"https://github.com/actonlang/foo\"}" , "]}" ] case PkgCommands.decodePackageIndex (LBS.pack body) of Left _ -> return () Right _ -> assertFailure "package index entry without kinds should fail" ] -- Creates testgroup from .act files found in specified directory --createTests :: String -> String -> List -> TestTree createTests name dir allExpFail fails testFunc = do actFiles <- findThings dir return $ testGroup name $ map (createTest allExpFail fails testFunc) actFiles createTest allExpFail fails testFunc file = do let fileExpFail = elem fileBody fails expFail = if fileExpFail == True then fileExpFail else allExpFail failWrap (testFunc expFail) file expFail where (fileBody, fileExt) = splitExtension $ takeFileName file createAutoTests name dir = do actFiles <- findThings dir return $ testGroup name $ map createAutoTest actFiles createAutoTest file = do -- guesstimate how to run this test -- no suffix = compile and run test program and expect success (exit 0) -- __bf = build failure, expect acton to exit 1 -- __rf = run failure: compile, run and expect exit 1 let fileParts = splitOn "__" fileBody testExp = if (length fileParts) == 2 then last fileParts else "" testName = if testExp == "" then head fileParts else (head fileParts) ++ " (" ++testExp ++ ")" testFunc = case testExp of "bf" -> testBuild "" _ -> testBuildAndRunRepeat "" "" 2 expRet = case testExp of "bf" -> (ExitFailure 1) "rf" -> (ExitFailure 1) _ -> ExitSuccess testCase testName $ testFunc expRet False file where (fileBody, fileExt) = splitExtension $ takeFileName file createGoldenErrorAutoTests name dir = do actFiles <- findThings dir return $ testGroup name $ map (createGoldenErrorAutoTest dir) actFiles createGoldenErrorAutoTest dir file = do let testName = fileBody goldenFile = joinPath [dir, fileBody ++ ".golden"] goldenVsString testName goldenFile (getCompileError file) where (fileBody, fileExt) = splitExtension $ takeFileName file getCompileError file = do (returnCode, cmdOut, cmdErr) <- buildThing "" file assertEqual "compile error retCode" (ExitFailure 1) returnCode return (LBS.pack (TestGolden.normalizeProgressTimings cmdOut)) findThings dir = do items <- listDirectory dir let absItems = map ((dir ++ "/") ++) items actFiles = catMaybes $ map filterActFile absItems projDirs <- catMaybes <$> mapM isActProj absItems return $ actFiles ++ projDirs where filterActFile file = case fileExt of ".act" -> Just file _ -> Nothing where (fileBody, fileExt) = splitExtension $ takeFileName file isActProj dir = do isDir <- doesDirectoryExist dir if isDir then do let projectFiles = ["Build.act"] hasProjectFile <- or <$> mapM (\file -> doesFileExist $ dir ++ "/" ++ file) projectFiles hasSrcDir <- doesDirectoryExist $ dir ++ "/src" if hasProjectFile && hasSrcDir then return $ Just dir else return Nothing else return Nothing failWrap testFunc thing True = expectFail $ testWrap testFunc thing failWrap testFunc thing False = testWrap testFunc thing testWrap testFunc thing = testCase fileBody $ testFunc thing where (fileBody, fileExt) = splitExtension $ takeFileName thing cleanOut :: FilePath -> IO () cleanOut proj = removePathForcibly (proj "out") `catch` (\(_ :: IOException) -> return ()) -- Actual test functions -- expRet refers to the return code of acton testBuild opts expRet expFail thing = do testBuildThing opts expRet expFail thing -- expFail & expRet refers to the acton program, we always assume compilation -- with acton succeeds testBuildAndRun buildOpts runOpts expRet expFail thing = testBuildAndRunRepeat buildOpts runOpts 1 expRet expFail thing testBuildAndRunRepeat buildOpts runOpts numRuns expRet expFail thing = do testBuildThing buildOpts ExitSuccess False thing replicateM_ numRuns $ do (returnCode, cmdOut, cmdErr) <- runThing runOpts thing when (expFail == False && returnCode /= expRet) $ putStrLn("\nERROR: when running application " ++ thing ++ ", the return code (" ++ show returnCode ++ ") not as expected (" ++ show expRet ++ ")\nSTDOUT:\n" ++ cmdOut ++ "STDERR:\n" ++ cmdErr) assertEqual ("application should return " ++ show expRet) expRet returnCode -- (returnCode, cmdOut, cmdErr) <- runThing runOpts thing -- iff (expFail == False && returnCode /= expRet) ( -- putStrLn("\nERROR: when running application " ++ thing ++ ", the return code (" ++ (show returnCode) ++ ") not as expected (" ++ (show expRet) ++ ")\nSTDOUT:\n" ++ cmdOut ++ "STDERR:\n" ++ cmdErr) -- ) -- assertEqual ("application should return " ++ (show expRet)) expRet returnCode buildAndRun :: String -> String -> FilePath -> IO (ExitCode, String, String) buildAndRun buildOpts runOpts thing = do buildThing buildOpts thing (returnCode, cmdOut, cmdErr) <- runThing runOpts thing return (returnCode, cmdOut, cmdErr) -- when in a project, expect the binary to be named the same as the project -- without our ending, like __bf. For example, if the project is -- import_actor__bf, then we will run ./import_actor in -- import_actor__bf/rel/bin runThing opts thing = do twd <- canonicalizePath $ takeDirectory thing isProj <- doesDirectoryExist thing projBinPath <- canonicalizePath $ thing ++ "/out/bin" let wd = if isProj then projBinPath else twd let exe = if isProj then binName else fileBody (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (proc ("./" ++ exe) (words opts)){ cwd = Just wd } "" return (returnCode, cmdOut, cmdErr) where (fileBody, fileExt) = splitExtension $ takeFileName thing fileParts = splitOn "__" fileBody binName = head fileParts testBuildThing opts expRet expFail thing = do (returnCode, cmdOut, cmdErr) <- buildThing opts thing iff (expFail == False && returnCode /= expRet) ( putStrLn("\nERROR: when building " ++ thing ++ ", acton returned code (" ++ (show returnCode) ++ ") not as expected (" ++ (show expRet) ++ ")\nSTDOUT:\n" ++ cmdOut ++ "STDERR:\n" ++ cmdErr) ) assertEqual ("acton should return " ++ (show expRet)) expRet returnCode buildThing opts thing = do actonExe <- canonicalizePath "../../dist/bin/acton" proj <- doesDirectoryExist thing projPath <- canonicalizePath thing curDir <- getCurrentDirectory let wd = if proj then projPath else curDir args0 = if proj then ["build"] else [thing] args = args0 ++ ["--always-build"] ++ words opts (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (proc actonExe args){ cwd = Just wd } "" return (returnCode, cmdOut, cmdErr) runRunacton :: FilePath -> [String] -> FilePath -> IO (ExitCode, String, String) runRunacton script args cwd = do actonBin <- canonicalizePath "../../dist/bin" env0 <- getEnvironment let pathVal = case lookup "PATH" env0 of Just p -> p Nothing -> "" env1 = ("PATH", actonBin ++ ":" ++ pathVal) : filter ((/= "PATH") . fst) env0 readCreateProcessWithExitCode (proc script args){ cwd = Just cwd, env = Just env1 } "" runActon opts expRet expFail proj = do actonExe <- canonicalizePath "../../dist/bin/acton" projPath <- canonicalizePath proj (returnCode, cmdOut, cmdErr) <- readCreateProcessWithExitCode (proc actonExe (words opts)){ cwd = Just projPath } "" iff (expFail == False && returnCode /= expRet) ( putStrLn("\nERROR: when running acton " ++ opts ++ ", acton returned code (" ++ (show returnCode) ++ ") not as expected (" ++ (show expRet) ++ ")\nSTDOUT:\n" ++ cmdOut ++ "STDERR:\n" ++ cmdErr) ) assertEqual ("acton should return " ++ (show expRet)) expRet returnCode iff True m = m >> return () iff False _ = return () ================================================ FILE: compiler/acton/test_incremental.hs ================================================ {-# LANGUAGE OverloadedStrings #-} module Main (main) where import Control.Monad (unless, when) import qualified Data.Binary as Binary import qualified Data.ByteString.Lazy.Char8 as LBS import qualified Data.ByteString as B import qualified Data.Text as T import qualified Data.Text.IO as T import qualified Data.Text.Encoding as TE import Data.Char (isHexDigit, isSpace) import Data.Bits (shiftL, (.|.)) import Data.Word (Word64) import qualified Acton.Fingerprint as Fingerprint import qualified Crypto.Hash.SHA256 as SHA256 import Data.List (find, partition, sort) import qualified Data.Map.Strict as M import Data.Maybe (isJust) import System.Directory import System.Exit import System.FilePath import System.IO (Handle) import System.Posix.Files (deviceID, fileID, fileSize, getFileStatus, modificationTimeHiRes, statusChangeTimeHiRes) import System.Process import Data.Time.Clock (addUTCTime, getCurrentTime) import Data.Time.Clock.POSIX (posixSecondsToUTCTime) import System.Directory (setModificationTime) import qualified Control.Exception as E import Control.Concurrent (threadDelay) import Test.Tasty import Test.Tasty.Runners (NumThreads(..)) import Test.Tasty (DependencyType(..), after, TestName) import Test.Tasty.Golden (goldenVsString) import Test.Tasty.HUnit import TestGolden (normalizeProgressTimingLine) import qualified Acton.Compile as Compile import qualified Acton.CommandLineParser as C import qualified Acton.SourceProvider as Source import qualified Acton.NameInfo as I import qualified Acton.Syntax as A import qualified InterfaceFiles import Utils (prstr) -- Paths ---------------------------------------------------------------------- projDir :: FilePath projDir = "test" "rebuild" srcDir :: FilePath srcDir = projDir "src" goldenDir :: FilePath goldenDir = projDir "golden" casesProjDir :: FilePath casesProjDir = "test" "incremental_cases" casesSrcDir :: FilePath casesSrcDir = casesProjDir "src" casesProjName :: String casesProjName = "incremental_cases" -- When running commands under compiler/acton/test, the acton binary at -- repo-root/dist/bin/acton is four levels up. actonExe :: FilePath actonExe = ".." ".." ".." ".." "dist" "bin" "acton" -- | Build an acton command line with fixed job count. actonCmd :: String -> String actonCmd args = actonExe ++ " " ++ args ++ " --jobs 1" -- Utils ---------------------------------------------------------------------- -- | Normalize build output for golden comparisons. sanitize :: T.Text -> LBS.ByteString sanitize = LBS.fromStrict . TE.encodeUtf8 . T.unlines . reorderBackLines . map censorHashes . map normalizeProgressTimingLine . dropPaths . filter (not . isVolatile) . T.lines where isVolatile :: T.Text -> Bool isVolatile t = T.isInfixOf "zigCmd" t || T.isInfixOf "Building project in" t || T.isInfixOf "Building [cap" t -- Rewrite volatile hash literals in log lines to stable placeholders. -- We keep semantic position in deltas: -- old hash values -> HASH1 -- new hash values -> HASH2 -- Values like "missing" are intentionally left unchanged. censorHashes :: T.Text -> T.Text censorHashes txt = go 0 where n = T.length txt go :: Int -> T.Text go i | i >= n = T.empty | isHexStart i = let j = spanHex i run = T.take (j - i) (T.drop i txt) in if isHashRun run then hashTag i j <> go j else run <> go j | otherwise = T.singleton (T.index txt i) <> go (i + 1) isHexStart :: Int -> Bool isHexStart i = isHexDigit (T.index txt i) spanHex :: Int -> Int spanHex i | i < n && isHexDigit (T.index txt i) = spanHex (i + 1) | otherwise = i isHashRun :: T.Text -> Bool isHashRun h = let len = T.length h in len == 8 || len == 64 hashTag :: Int -> Int -> T.Text hashTag i j | isRightValue i = "HASH2" | isLeftValue j = "HASH1" | otherwise = "HASH" isRightValue :: Int -> Bool isRightValue i = case skipSpacesLeft (i - 1) of Nothing -> False Just k | T.index txt k == '→' -> True | k >= 1 && T.index txt (k - 1) == '-' && T.index txt k == '>' -> True | otherwise -> False isLeftValue :: Int -> Bool isLeftValue j = case skipSpacesRight j of Nothing -> False Just k | T.index txt k == '→' -> True | k + 1 < n && T.index txt k == '-' && T.index txt (k + 1) == '>' -> True | otherwise -> False skipSpacesLeft :: Int -> Maybe Int skipSpacesLeft k | k < 0 = Nothing | isSpace (T.index txt k) = skipSpacesLeft (k - 1) | otherwise = Just k skipSpacesRight :: Int -> Maybe Int skipSpacesRight k | k >= n = Nothing | isSpace (T.index txt k) = skipSpacesRight (k + 1) | otherwise = Just k -- Remove the verbose Paths: block (and its per-field lines) to avoid -- machine-specific absolute paths in goldens. dropPaths :: [T.Text] -> [T.Text] dropPaths [] = [] dropPaths (l:ls) | T.isPrefixOf "Paths:" (T.stripStart l) = dropWhile isPathField ls | otherwise = l : dropPaths ls where isPathField :: T.Text -> Bool isPathField x = let s = T.stripStart x in any (`T.isPrefixOf` s) [ "sysPath" , "sysTypes" , "projPath" , "projOut" , "projTypes" , "binDir" , "srcDir" , "modName" ] reorderBackLines :: [T.Text] -> [T.Text] reorderBackLines ls = let (backLines, otherLines) = partition isBackLine ls (pre, post) = break isFinalLine otherLines in pre ++ sort backLines ++ post where isBackLine t = T.isPrefixOf " Finished compilation of" t || (T.isInfixOf "Compilation done" t && not (isFinalLine t)) isFinalLine t = T.isPrefixOf " Finished final compilation" t || T.isPrefixOf " Finished final compilation step" t || T.isInfixOf "Final compilation done" t || T.isPrefixOf " Skipping final build step" t -- | Atomically write UTF-8 text to a file. writeFileUtf8 :: FilePath -> T.Text -> IO () writeFileUtf8 p t = do let tmp = p <.> "tmp" T.writeFile tmp t let handler :: IOError -> IO () handler _ = do exists <- doesFileExist p let handler2 :: IOError -> IO (); handler2 _ = pure () when exists $ E.catch (removeFile p) handler2 renameFile tmp p E.catch (renameFile tmp p) handler fingerprintForName :: String -> String fingerprintForName name = let prefix = Fingerprint.fingerprintPrefixForName name fp = (fromIntegral prefix `shiftL` 32) .|. (1 :: Word64) in Fingerprint.formatFingerprint fp -- | Update a file's modification time to now. touch :: FilePath -> IO () touch p = do now <- getCurrentTime setModificationTime p now -- | Reset the default rebuild project to a clean state. ensureClean :: IO () ensureClean = do ensureCleanAt projDir -- | Reset a project directory to a clean state. ensureCleanAt :: FilePath -> IO () ensureCleanAt proj = do createDirectoryIfMissing True proj let src = proj "src" -- Reset src dir fully to avoid leftover temp/lock files let handler :: IOError -> IO (); handler _ = pure () E.catch (removeDirectoryRecursive src) handler createDirectoryIfMissing True src let buildAct = proj "Build.act" exists <- doesFileExist buildAct unless exists $ writeBuildAct proj (takeFileName proj) [] -- Remove previous build output if present let outDir = proj "out" outExists <- doesDirectoryExist outDir when outExists $ E.catch (removeDirectoryRecursive outDir) handler -- Remove potential leftover project lock file let lockFile = proj ".acton.lock" lockExists <- doesFileExist lockFile when lockExists $ E.catch (removeFile lockFile) handler let bgLockFile = proj ".acton.compile.lock" bgLockExists <- doesFileExist bgLockFile when bgLockExists $ E.catch (removeFile bgLockFile) handler -- | Run a shell command in a directory and capture stdout+stderr. runIn :: FilePath -> String -> IO (ExitCode, T.Text) runIn cwd cmd = do (ec,out,err) <- readCreateProcessWithExitCode (shell cmd){ cwd = Just cwd } "" pure (ec, T.pack out <> T.pack err) -- | Run a project build and return raw output. buildOut :: IO T.Text buildOut = do let cmd = actonCmd "build --color never --verbose" (_ec,out) <- runIn projDir cmd pure out -- | Run a project build and return sanitized output. goldenBuild :: IO LBS.ByteString goldenBuild = do let cmd = actonCmd "build --color never --verbose" (_ec,out) <- runIn projDir cmd pure (sanitize out) -- | Run a single-file build and return sanitized output. goldenBuildFile :: IO LBS.ByteString goldenBuildFile = do let cmd = actonCmd "src/c.act --color never --verbose" (_ec,out) <- runIn projDir cmd pure (sanitize out) -- | Run a single-file build and return raw output. buildOutFile :: IO T.Text buildOutFile = do let cmd = actonCmd "src/c.act --color never --verbose" (_ec,out) <- runIn projDir cmd pure out -- | Check whether build output reports typechecking for a module. typechecked :: T.Text -> T.Text -> Bool typechecked out modName = any (\line -> isTypecheckLine line && matchesModule line modName) (T.lines out) where isTypecheckLine line = "Finished type check of" `T.isInfixOf` line || "Type check done" `T.isInfixOf` line -- | Check whether build output reports compilation for a module. compiled :: T.Text -> T.Text -> Bool compiled out modName = any (\line -> isCompiledLine line && matchesModule line modName) (T.lines out) where isCompiledLine line = "Finished compilation of" `T.isInfixOf` line || "Compilation done" `T.isInfixOf` line -- | Match module labels across legacy "proj/mod" and new "proj.mod" formats. matchesModule :: T.Text -> T.Text -> Bool matchesModule line modName = let dotName = T.replace "/" "." modName leafName = T.takeWhileEnd (/= '/') modName tokens = T.words line in any (`elem` tokens) [modName, dotName, leafName] -- | Remove a file if it exists. removeIfExists :: FilePath -> IO () removeIfExists p = do exists <- doesFileExist p when exists $ removeFile p -- | Remove a directory if it exists. removeDirIfExists :: FilePath -> IO () removeDirIfExists p = do exists <- doesDirectoryExist p when exists $ removeDirectoryRecursive p -- | Reset a project directory including deps and build outputs. ensureCleanProjectAt :: FilePath -> IO () ensureCleanProjectAt proj = do ensureCleanAt proj removeDirIfExists (proj "deps") removeIfExists (proj "build.zig") removeIfExists (proj "build.zig.zon") removeIfExists (proj ".acton.compile.lock") removeIfExists (proj ".acton.lock") withBackgroundCompilerLockHeld :: FilePath -> IO a -> IO a withBackgroundCompilerLockHeld proj action = do mlock <- Compile.tryBackgroundCompilerLock proj case mlock of Nothing -> assertFailure ("failed to acquire .acton.compile.lock in " ++ proj) Just lock -> action `E.finally` Compile.releaseBackgroundCompilerLock lock -- | Write a Build.act file with optional path deps. writeBuildAct :: FilePath -> String -> [(String, FilePath)] -> IO () writeBuildAct proj name deps = do let header = [ T.pack ("name = \"" ++ name ++ "\"") , T.pack ("fingerprint = " ++ fingerprintForName name) ] depLines | null deps = [] | otherwise = [ "" , "dependencies = {" ] ++ [ T.pack (" \"" ++ depName ++ "\": (path=\"" ++ depPath ++ "\")") | (depName, depPath) <- deps ] ++ [ "}" ] writeFileUtf8 (proj "Build.act") (T.unlines (header ++ depLines)) -- | Create a dependency project under deps/. ensureDepProject :: FilePath -> String -> IO FilePath ensureDepProject proj depName = do let depDir = proj "deps" depName createDirectoryIfMissing True (depDir "src") writeBuildAct depDir depName [] pure depDir ensureCasesProject :: IO () ensureCasesProject = ensureCasesProjectWithDeps [] ensureCasesProjectWithDeps :: [(String, FilePath)] -> IO () ensureCasesProjectWithDeps deps = do ensureCleanProjectAt casesProjDir writeBuildAct casesProjDir casesProjName deps -- | Replace the first line of a file with a new string. rewriteFirstLine :: FilePath -> String -> IO () rewriteFirstLine path newLine = do content <- T.readFile path let rest = snd (T.breakOn "\n" content) T.writeFile path (T.pack newLine <> rest) -- | Resolve the acton binary path. actonPath :: IO FilePath actonPath = canonicalizePath (".." ".." "dist" "bin" "acton") -- | Run acton in a directory with fixed job count. runActonIn :: FilePath -> [String] -> IO (ExitCode, T.Text) runActonIn cwd args = do actonExe <- actonPath let args' = args ++ ["--jobs", "1"] (ec,out,err) <- readCreateProcessWithExitCode (proc actonExe args'){ cwd = Just cwd } "" pure (ec, T.pack out <> T.pack err) -- | Assert an exit success and include output on failure. assertExitSuccess :: String -> (ExitCode, T.Text) -> IO () assertExitSuccess label (ec, out) = case ec of ExitSuccess -> pure () ExitFailure c -> assertFailure (label ++ " failed (exit " ++ show c ++ ")\n" ++ T.unpack out) -- | Assert a specific exit failure and include output on mismatch. assertExitFailure :: String -> Int -> (ExitCode, T.Text) -> IO () assertExitFailure label code (ec, out) = case ec of ExitFailure c | c == code -> pure () ExitFailure c -> assertFailure (label ++ " failed (expected exit " ++ show code ++ ", got " ++ show c ++ ")\n" ++ T.unpack out) ExitSuccess -> assertFailure (label ++ " unexpectedly succeeded\n" ++ T.unpack out) -- | Run a verbose build in a project directory and return raw output. buildOutIn :: FilePath -> IO T.Text buildOutIn proj = do res@(ec, out) <- runActonIn proj ["build", "--color", "never", "--verbose"] assertExitSuccess ("build in " ++ proj) res pure out -- | Run a verbose build with extra args and return raw output. buildOutInArgs :: FilePath -> [String] -> IO T.Text buildOutInArgs proj args = do res@(ec, out) <- runActonIn proj (["build", "--color", "never", "--verbose"] ++ args) assertExitSuccess ("build in " ++ proj) res pure out -- | Format a module label for output comparisons. modLabel :: FilePath -> String -> T.Text modLabel proj mod = T.pack (takeFileName proj ++ "/" ++ mod) -- | Build the default rebuild project. buildProject :: IO () buildProject = do let cmd = actonCmd "build --color never" (ec,out) <- runIn projDir cmd case ec of ExitSuccess -> pure () ExitFailure c -> assertFailure ("acton build failed: " ++ show c ++ "\n" ++ T.unpack out) -- | Read name hashes from a .ty file. readTyNameHashes :: FilePath -> IO [InterfaceFiles.NameHashInfo] readTyNameHashes tyPath = do (_, _, _, _, _, _, _, _, nameHashes, _, _, _) <- InterfaceFiles.readFile tyPath pure nameHashes -- | Read pub/impl dependency names for a binding in a .ty file. readTyDeps :: FilePath -> String -> IO ([String], [String]) readTyDeps tyPath nameLabel = do nameHashes <- readTyNameHashes tyPath let matchName nh = prstr (InterfaceFiles.nhName nh) == nameLabel case find matchName nameHashes of Nothing -> do assertFailure ("missing name " ++ nameLabel ++ " in " ++ tyPath) pure ([], []) Just nh -> do let pubDeps = sort (map (prstr . fst) (InterfaceFiles.nhPubDeps nh)) implDeps = sort (map (prstr . fst) (InterfaceFiles.nhImplDeps nh)) pure (pubDeps, implDeps) -- | Rewrite source hash and name-hash section of a .ty file. rewriteTySrcHashAndNameHashes :: FilePath -> B.ByteString -> ([InterfaceFiles.NameHashInfo] -> [InterfaceFiles.NameHashInfo]) -> IO () rewriteTySrcHashAndNameHashes tyPath srcHash' f = do (_mods, nmod, tmod, sourceMeta, _srcHash, pubHash, implHash, imps, nameHashes, roots, tests, mdoc) <- InterfaceFiles.readFile tyPath InterfaceFiles.writeFile tyPath srcHash' pubHash implHash sourceMeta imps (f nameHashes) roots tests mdoc nmod tmod rewriteTySourceMeta :: FilePath -> Maybe InterfaceFiles.SourceFileMeta -> IO () rewriteTySourceMeta tyPath sourceMeta' = do (_mods, nmod, tmod, _sourceMeta, srcHash, pubHash, implHash, imps, nameHashes, roots, tests, mdoc) <- InterfaceFiles.readFile tyPath InterfaceFiles.writeFile tyPath srcHash pubHash implHash sourceMeta' imps nameHashes roots tests mdoc nmod tmod rewriteTyVersion :: FilePath -> [Int] -> IO () rewriteTyVersion tyPath version' = do (_mods, nmod, tmod, sourceMeta, srcHash, pubHash, implHash, imps, nameHashes, roots, tests, mdoc) <- InterfaceFiles.readFile tyPath LBS.writeFile tyPath $ Binary.encode ((version', sourceMeta, srcHash, pubHash, implHash), imps, nameHashes, roots, tests, mdoc, nmod, tmod) readTySourceMeta :: FilePath -> IO (Maybe InterfaceFiles.SourceFileMeta) readTySourceMeta tyPath = do (sourceMeta, _srcHash, _pubHash, _implHash, _imps, _nameHashes, _roots, _tests, _doc) <- InterfaceFiles.readHeader tyPath pure sourceMeta sourceFileMetaForPath :: FilePath -> IO InterfaceFiles.SourceFileMeta sourceFileMetaForPath path = do st <- getFileStatus path let mtimeNs = floor (toRational (modificationTimeHiRes st) * 1000000000) ctimeNs = floor (toRational (statusChangeTimeHiRes st) * 1000000000) pure InterfaceFiles.SourceFileMeta { InterfaceFiles.sfmMTimeNs = mtimeNs , InterfaceFiles.sfmCTimeNs = ctimeNs , InterfaceFiles.sfmSize = fromIntegral (fileSize st) , InterfaceFiles.sfmDevice = Just (fromIntegral (deviceID st)) , InterfaceFiles.sfmInode = Just (fromIntegral (fileID st)) } setFileMTimeNs :: FilePath -> Integer -> IO () setFileMTimeNs path mtimeNs = setModificationTime path (posixSecondsToUTCTime (fromRational (toRational mtimeNs / 1000000000))) -- | Drop a qualified dependency label from all stored pub/impl dep lists. dropTyDepByLabel :: String -> [InterfaceFiles.NameHashInfo] -> [InterfaceFiles.NameHashInfo] dropTyDepByLabel depLabel = map dropFromInfo where keepDep (qn, _h) = prstr qn /= depLabel dropFromInfo nh = nh { InterfaceFiles.nhPubDeps = filter keepDep (InterfaceFiles.nhPubDeps nh) , InterfaceFiles.nhImplDeps = filter keepDep (InterfaceFiles.nhImplDeps nh) } -- | Assert that a dependency list includes all expected names. assertDepsContain :: String -> [String] -> [String] -> IO () assertDepsContain label expected actual = let missing = filter (`notElem` actual) expected in unless (null missing) $ assertFailure (label ++ " missing deps: " ++ show missing ++ "\nactual: " ++ show actual) -- | Run a project binary and capture stdout. runBinaryIn :: FilePath -> String -> IO T.Text runBinaryIn proj name = do let bin = "out" "bin" name (ec,out,err) <- readCreateProcessWithExitCode (proc bin []){ cwd = Just proj } "" case ec of ExitSuccess -> pure (T.pack out) ExitFailure c -> assertFailure ("Binary failed (exit " ++ show c ++ ") stderr: " ++ err) runBinary :: String -> IO T.Text runBinary = runBinaryIn projDir -- Project scenario steps ------------------------------------------------------ p01_init :: TestTree p01_init = testCase "01-init" $ do ensureClean writeFileUtf8 (srcDir "a.act") "aaa = 123\n" writeFileUtf8 (srcDir "b.act") $ T.unlines [ "import a" , "def baa():" , " return a.aaa" , "" , "class DocInfo:" , " def get(self) -> int:" , " \"get value\"" , " return 1" ] writeFileUtf8 (srcDir "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " print(b.baa())" , " env.exit(0)" ] p02_initial_build :: TestTree p02_initial_build = goldenVsString "02-initial-build.golden" (goldenDir "project_02-initial-build.golden") goldenBuild p03_up_to_date :: TestTree p03_up_to_date = goldenVsString "03-up-to-date.golden" (goldenDir "project_03-up-to-date.golden") goldenBuild p04_touch_no_rebuild :: TestTree p04_touch_no_rebuild = goldenVsString "04-touch-no-rebuild.golden" (goldenDir "project_04-touch-no-rebuild.golden") $ do touch (srcDir "a.act") goldenBuild p05_run_123 :: TestTree p05_run_123 = testCase "05-run 123" $ do out <- runBinary "c" out @?= "123\n" p06_change_a_impl :: TestTree p06_change_a_impl = goldenVsString "06-change-a-impl.golden" (goldenDir "project_06-change-a-impl.golden") $ do writeFileUtf8 (srcDir "a.act") "aaa = 124\n" out <- buildOut -- Expect only a.act to type check; b/c should re-run codegen only. assertBool "expected a.act to compile" (typechecked out "rebuild/a") assertBool "did not expect b.act to compile" (not (typechecked out "rebuild/b")) assertBool "did not expect c.act to compile" (not (typechecked out "rebuild/c")) assertBool "expected b.act to compile codegen" (compiled out "rebuild/b") assertBool "expected c.act to compile codegen" (compiled out "rebuild/c") pure (sanitize out) p06_impl_change_fresh :: TestTree p06_impl_change_fresh = testCase "06-impl-change-up-to-date" $ do out <- buildOut assertBool "did not expect a.act to compile" (not (typechecked out "rebuild/a")) assertBool "did not expect b.act to compile" (not (typechecked out "rebuild/b")) assertBool "did not expect c.act to compile" (not (typechecked out "rebuild/c")) assertBool "did not expect b.act to compile codegen" (not (compiled out "rebuild/b")) assertBool "did not expect c.act to compile codegen" (not (compiled out "rebuild/c")) p07_run_124 :: TestTree p07_run_124 = testCase "07-run 124" $ do out <- runBinary "c" out @?= "124\n" p08_change_b_impl :: TestTree p08_change_b_impl = goldenVsString "08-change-b-impl.golden" (goldenDir "project_08-change-b-impl.golden") $ do writeFileUtf8 (srcDir "b.act") $ T.unlines [ "import a" , "def baa():" , " tmp = a.aaa" , " return tmp" , "" , "class DocInfo:" , " def get(self) -> int:" , " \"get value\"" , " return 1" ] out <- buildOut -- Expect b.act to compile, but not a.act or c.act in project build assertBool "did not expect a.act to compile" (not (typechecked out "rebuild/a")) assertBool "expected b.act to compile" (typechecked out "rebuild/b") assertBool "did not expect c.act to compile" (not (typechecked out "rebuild/c")) pure (sanitize out) p09_run_124 :: TestTree p09_run_124 = testCase "09-run 124" $ do out <- runBinary "c" out @?= "124\n" -- Public-hash behavior tests ----------------------------------------------- -- Changing public interface of an import should rebuild dependents that use it p10_change_a_iface :: TestTree p10_change_a_iface = goldenVsString "10-change-a-iface.golden" (goldenDir "project_10-change-a-iface.golden") $ do -- Change the type of a.aaa (public signature change). writeFileUtf8 (srcDir "a.act") "aaa = \"125\"\n" out <- buildOut -- Should rebuild a.act and b.act; with import-augmented public hashing, b's -- public hash changes when a's interface changes assertBool "expected a.act to compile" (typechecked out "rebuild/a") assertBool "expected b.act to compile" (typechecked out "rebuild/b") -- c should rebuild too, since it imports b which has now changed since its import a changed.. assertBool "expected c.act to compile" (typechecked out "rebuild/c") pure (sanitize out) -- Docstring-only change in an imported module should not rebuild dependents p11_change_b_doc :: TestTree p11_change_b_doc = goldenVsString "11-change-b-doc.golden" (goldenDir "project_11-change-b-doc.golden") $ do -- Change only the docstring of a method in b.act; this should recompile b -- (source changed) but not its dependent c (public hash is doc-free). writeFileUtf8 (srcDir "b.act") $ T.unlines [ "import a" , "def baa():" , " tmp = a.aaa" , " return tmp" , "" , "class DocInfo:" , " def get(self) -> int:" , " \"GET VALUE v2\"" , " return 1" ] out <- buildOut assertBool "expected b.act to compile" (typechecked out "rebuild/b") assertBool "did not expect c.act to compile" (not (typechecked out "rebuild/c")) pure (sanitize out) p12_codegen_stale :: TestTree p12_codegen_stale = goldenVsString "12-codegen-stale.golden" (goldenDir "project_12-codegen-stale.golden") $ do let bBase = projDir "out" "types" "b" removeIfExists (bBase ++ ".c") removeIfExists (bBase ++ ".h") out <- buildOut assertBool "expected b.act to compile codegen" (compiled out "rebuild/b") assertBool "did not expect b.act to type check" (not (typechecked out "rebuild/b")) assertBool "did not expect a.act to type check" (not (typechecked out "rebuild/a")) assertBool "did not expect c.act to compile codegen" (not (compiled out "rebuild/c")) pure (sanitize out) f01_init :: TestTree f01_init = testCase "01-init" $ do ensureClean writeFileUtf8 (srcDir "a.act") "aaa = 123\n" writeFileUtf8 (srcDir "b.act") $ T.unlines [ "import a" , "def baa():" , " return a.aaa" ] writeFileUtf8 (srcDir "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " print(b.baa())" , " env.exit(0)" ] f02_initial_build :: TestTree f02_initial_build = goldenVsString "02-initial-build.golden" (goldenDir "file_02-initial-build.golden") goldenBuildFile f03_up_to_date :: TestTree f03_up_to_date = goldenVsString "03-up-to-date.golden" (goldenDir "file_03-up-to-date.golden") goldenBuildFile f04_touch_no_rebuild :: TestTree f04_touch_no_rebuild = goldenVsString "04-touch-no-rebuild.golden" (goldenDir "file_04-touch-no-rebuild.golden") $ do touch (srcDir "a.act") goldenBuildFile f05_run_123 :: TestTree f05_run_123 = testCase "05-run 123" $ do out <- runBinary "c" out @?= "123\n" f06_change_a_impl :: TestTree f06_change_a_impl = goldenVsString "06-change-a-impl.golden" (goldenDir "file_06-change-a-impl.golden") $ do writeFileUtf8 (srcDir "a.act") "aaa = 124\n" out <- buildOutFile -- Expect only a.act to compile in single-file build assertBool "expected a.act to compile" (typechecked out "rebuild/a") assertBool "did not expect b.act to compile" (not (typechecked out "rebuild/b")) assertBool "did not expect c.act to compile" (not (typechecked out "rebuild/c")) pure (sanitize out) f07_run_124 :: TestTree f07_run_124 = testCase "07-run 124" $ do out <- runBinary "c" out @?= "124\n" f08_change_b_impl :: TestTree f08_change_b_impl = goldenVsString "08-change-b-impl.golden" (goldenDir "file_08-change-b-impl.golden") $ do writeFileUtf8 (srcDir "b.act") $ T.unlines [ "import a" , "def baa():" , " tmp = a.aaa" , " return tmp" , "" , "class DocInfo:" , " def get(self) -> int:" , " \"get value\"" , " return 1" ] out <- buildOutFile -- Expect b.act to compile; c.act should not re-typecheck on impl-only changes. assertBool "did not expect a.act to compile" (not (typechecked out "rebuild/a")) assertBool "expected b.act to compile" (typechecked out "rebuild/b") assertBool "did not expect c.act to compile" (not (typechecked out "rebuild/c")) pure (sanitize out) f09_run_124 :: TestTree f09_run_124 = testCase "09-run 124" $ do out <- runBinary "c" out @?= "124\n" -- Alt-output behavior -------------------------------------------------------- -- When requesting alternative output (e.g., --types), ensure the compiler runs -- the relevant passes and prints the output even if the file is otherwise -- up-to-date. f10_alt_output :: TestTree f10_alt_output = testCase "10-alt output" $ do -- Run build an extra time to make sure we are up to date _ <- buildOutFile -- Now request alternative output on the same file without modifying sources let cmd = actonCmd "src/c.act --color never --types" (_ec,out) <- runIn projDir cmd -- Expect a types dump header for module c assertBool "expected types dump for module c" (T.isInfixOf "== types: c" out) -- Project case tests -------------------------------------------------------- p14_partial_rebuild :: TestTree p14_partial_rebuild = testCase "14-partial rebuild" $ do ensureCasesProject writeFileUtf8 (casesSrcDir "rebuild.act") $ T.unlines [ "actor main(env: Env):" , " env.exit(0)" ] res1 <- runActonIn casesProjDir ["build", "--color", "never"] assertExitSuccess "initial build" res1 touch (casesSrcDir "rebuild.act") res2 <- runActonIn casesProjDir ["build", "--color", "never"] assertExitSuccess "rebuild after touch" res2 p15_rebuild_import :: TestTree p15_rebuild_import = testCase "15-rebuild with stdlib import" $ do ensureCasesProject writeFileUtf8 (casesSrcDir "rebuild.act") $ T.unlines [ "import json" , "" , "actor main(env: Env):" , " env.exit(0)" ] res1 <- runActonIn casesProjDir ["build", "--color", "never"] assertExitSuccess "initial build" res1 res2 <- runActonIn casesProjDir ["build", "--color", "never"] assertExitSuccess "second build" res2 p16_dep_api_change :: TestTree p16_dep_api_change = testCase "16-dependency API change triggers rebuild" $ do let originalContent = T.unlines [ "# Initial version" , "def calculate(x: int) -> int:" , " return x * 2" ] modifiedContent = T.unlines [ "# Modified version" , "def calculate(x: int, y: int) -> int:" , " return x * y" ] ensureCasesProjectWithDeps [("libfoo", "deps/libfoo")] depDir <- ensureDepProject casesProjDir "libfoo" let depSrc = depDir "src" "libfoo.act" writeFileUtf8 depSrc originalContent writeFileUtf8 (casesSrcDir "main.act") $ T.unlines [ "import libfoo" , "" , "actor main(env: Env):" , " result = libfoo.calculate(21)" , " print(\"Result: %d\" % result)" , " env.exit(0)" ] res1 <- runActonIn casesProjDir ["build", "--color", "never"] assertExitSuccess "initial build" res1 writeFileUtf8 depSrc modifiedContent res2 <- runActonIn casesProjDir ["build", "--color", "never"] assertExitFailure "rebuild after API change" 1 res2 p17_dep_impl_change :: TestTree p17_dep_impl_change = testCase "17-dependency impl change triggers back job" $ do let originalContent = T.unlines [ "# Initial version" , "def calculate(x: int) -> int:" , " return x * 2" ] modifiedContent = T.unlines [ "# Modified version" , "def calculate(x: int) -> int:" , " return x * 3" ] modMain = modLabel casesProjDir "main" ensureCasesProjectWithDeps [("libfoo", "deps/libfoo")] depDir <- ensureDepProject casesProjDir "libfoo" let depSrc = depDir "src" "libfoo.act" writeFileUtf8 depSrc originalContent writeFileUtf8 (casesSrcDir "main.act") $ T.unlines [ "import libfoo" , "" , "actor main(env: Env):" , " result = libfoo.calculate(21)" , " print(\"Result: %d\" % result)" , " env.exit(0)" ] res1 <- runActonIn casesProjDir ["build", "--color", "never"] assertExitSuccess "initial build" res1 writeFileUtf8 depSrc modifiedContent res2@(ec2, out2) <- runActonIn casesProjDir ["build", "--color", "never", "--verbose"] assertExitSuccess "rebuild after impl change" res2 assertBool "expected impl change log" (T.isInfixOf "impl changes in libfoo.calculate" out2) assertBool "did not expect main to type check" (not (typechecked out2 modMain)) assertBool "expected main to compile codegen" (compiled out2 modMain) -- Incremental/hash case coverage -------------------------------------------- p18_type_only_deps :: TestTree p18_type_only_deps = testCase "18-type-only deps in signatures" $ do let proj = casesProjDir src = casesSrcDir modB = modLabel proj "b" modC = modLabel proj "c" ensureCasesProject writeFileUtf8 (src "a.act") $ T.unlines [ "class Foo:" , " def get(self) -> int:" , " return 1" ] writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def takes(x: a.Foo) -> int:" , " return 0" ] writeFileUtf8 (src "c.act") $ T.unlines [ "actor main(env: Env):" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 (src "a.act") $ T.unlines [ "class Foo:" , " def get(self) -> int:" , " return 2" ] out1 <- buildOutIn proj assertBool "did not expect b.act to type check" (not (typechecked out1 modB)) assertBool "did not expect c.act to type check" (not (typechecked out1 modC)) writeFileUtf8 (src "a.act") $ T.unlines [ "class Foo:" , " def get(self) -> float:" , " return 2.0" ] out2 <- buildOutIn proj assertBool "expected b.act to type check" (typechecked out2 modB) assertBool "did not expect c.act to type check" (not (typechecked out2 modC)) p19_unused_import :: TestTree p19_unused_import = testCase "19-unused import does not propagate" $ do let proj = casesProjDir src = casesSrcDir modB = modLabel proj "b" modC = modLabel proj "c" ensureCasesProject writeFileUtf8 (src "a.act") $ T.unlines [ "def foo() -> int:" , " return 1" ] writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.foo()" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " b.bar()" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "import testing" , "" , "def bar() -> int:" , " return a.foo()" ] out <- buildOutIn proj assertBool "expected b.act to type check" (typechecked out modB) assertBool "did not expect c.act to type check" (not (typechecked out modC)) p20_add_remove_names :: TestTree p20_add_remove_names = testCase "20-add/remove top-level names" $ do let proj = casesProjDir src = casesSrcDir modB = modLabel proj "b" modC = modLabel proj "c" ensureCasesProject writeFileUtf8 (src "a.act") "foo = 1\n" writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.foo" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " b.bar()" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 (src "a.act") $ T.unlines [ "foo = 1" , "bar = 2" ] out1 <- buildOutIn proj let addDelta = "+bar" assertBool "expected +bar hash delta" (addDelta `T.isInfixOf` out1) assertBool "did not expect b.act to type check" (not (typechecked out1 modB)) assertBool "did not expect c.act to type check" (not (typechecked out1 modC)) writeFileUtf8 (src "a.act") "foo = 1\n" out2 <- buildOutIn proj let removeDelta = "-bar" assertBool "expected -bar hash delta" (removeDelta `T.isInfixOf` out2) assertBool "did not expect b.act to type check" (not (typechecked out2 modB)) assertBool "did not expect c.act to type check" (not (typechecked out2 modC)) p21_recursive_group :: TestTree p21_recursive_group = testCase "21-recursive group impl change propagates" $ do let proj = casesProjDir src = casesSrcDir modB = modLabel proj "b" ensureCasesProject writeFileUtf8 (src "a.act") $ T.unlines [ "def even(n: int) -> bool:" , " if n == 0:" , " return True" , " else:" , " return odd(n - 1)" , "" , "def odd(n: int) -> bool:" , " if n == 0:" , " return False" , " else:" , " return even(n - 1)" ] writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def use() -> bool:" , " return a.even(2)" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " b.use()" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 (src "a.act") $ T.unlines [ "def even(n: int) -> bool:" , " if n == 0:" , " return True" , " else:" , " return odd(n - 1)" , "" , "def odd(n: int) -> bool:" , " if n == 0:" , " return True" , " else:" , " return even(n - 1)" ] out <- buildOutIn proj assertBool "expected even impl delta" (T.isInfixOf "~even{impl" out) assertBool "expected odd src delta" (T.isInfixOf "~odd{src" out) assertBool "expected b.act to compile codegen" (compiled out modB) assertBool "did not expect b.act to type check" (not (typechecked out modB)) p22_multibind :: TestTree p22_multibind = testCase "22-multi-binding updates per-name hashes" $ do let proj = casesProjDir src = casesSrcDir modB = modLabel proj "b" ensureCasesProject writeFileUtf8 (src "a.act") "x, y = 1, 2\n" writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def get() -> int:" , " return a.x" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " b.get()" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 (src "a.act") "x, y = 1, 3\n" out <- buildOutIn proj assertBool "expected x src delta" (T.isInfixOf "~x{src" out) assertBool "expected y src delta" (T.isInfixOf "~y{src" out) assertBool "expected b.act to compile codegen" (compiled out modB) p23_codegen_mismatch :: TestTree p23_codegen_mismatch = testCase "23-codegen hash mismatch triggers rebuild" $ do let proj = casesProjDir src = casesSrcDir modB = modLabel proj "b" bC = proj "out" "types" "b.c" ensureCasesProject writeFileUtf8 (src "a.act") $ T.unlines [ "def foo() -> int:" , " return 1" ] writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.foo()" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " b.bar()" , " env.exit(0)" ] _ <- buildOutIn proj rewriteFirstLine bC "/* Acton impl hash: deadbeef */" out <- buildOutIn proj assertBool "expected codegen stale message" (T.isInfixOf "generated code out of date" out) assertBool "expected b.act to compile codegen" (compiled out modB) assertBool "did not expect b.act to type check" (not (typechecked out modB)) p24_codegen_equal_hash :: TestTree p24_codegen_equal_hash = testCase "24-codegen equal hash mismatch formats single delta" $ do let proj = casesProjDir src = casesSrcDir modB = modLabel proj "b" bC = proj "out" "types" "b.c" bH = proj "out" "types" "b.h" ensureCasesProject writeFileUtf8 (src "a.act") $ T.unlines [ "def foo() -> int:" , " return 1" ] writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.foo()" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " b.bar()" , " env.exit(0)" ] _ <- buildOutIn proj rewriteFirstLine bC "/* Acton impl hash: deadbeef */" rewriteFirstLine bH "/* Acton impl hash: deadbeef */" out <- buildOutIn proj assertBool "expected single-delta codegen message" (T.isInfixOf "generated code out of date {impl deadbeef ->" out) assertBool "expected b.act to compile codegen" (compiled out modB) assertBool "did not expect b.act to type check" (not (typechecked out modB)) p25_whitespace_change :: TestTree p25_whitespace_change = testCase "25-whitespace-only change does not propagate" $ do let proj = casesProjDir src = casesSrcDir modB = modLabel proj "b" modC = modLabel proj "c" ensureCasesProject writeFileUtf8 (src "a.act") $ T.unlines [ "def foo() -> int:" , " return 1" ] writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.foo()" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " b.bar()" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 (src "a.act") $ T.unlines [ "# comment" , "def foo() -> int:" , " return 1" ] out <- buildOutIn proj assertBool "did not expect b.act to type check" (not (typechecked out modB)) assertBool "did not expect c.act to type check" (not (typechecked out modC)) p26_corrupt_ty_header :: TestTree p26_corrupt_ty_header = testCase "26-corrupt .ty header forces re-parse" $ do let proj = casesProjDir src = casesSrcDir modA = modLabel proj "a" tyA = proj "out" "types" "a.ty" ensureCasesProject writeFileUtf8 (src "a.act") "aaa = 1\n" writeFileUtf8 (src "c.act") $ T.unlines [ "import a" , "" , "actor main(env: Env):" , " print(a.aaa)" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 tyA "garbage\n" out <- buildOutIn proj assertBool "expected a.act to type check after corrupt .ty" (typechecked out modA) p26_ty_version_mismatch :: TestTree p26_ty_version_mismatch = testCase "26b-.ty version mismatch forces re-parse" $ do let proj = casesProjDir src = casesSrcDir modA = modLabel proj "a" tyA = proj "out" "types" "a.ty" ensureCasesProject writeFileUtf8 (src "a.act") "aaa = 1\n" writeFileUtf8 (src "c.act") $ T.unlines [ "import a" , "" , "actor main(env: Env):" , " print(a.aaa)" , " env.exit(0)" ] _ <- buildOutIn proj rewriteTyVersion tyA (map (+ 1) A.version) out <- buildOutIn proj assertBool "expected a.act to type check after .ty version mismatch" (typechecked out modA) assertBool "did not expect raw .ty version mismatch" $ not (".ty version mismatch" `T.isInfixOf` out) p27_overlay_source_provider :: TestTree p27_overlay_source_provider = testCase "27-overlay snapshots drive readModuleTask" $ do let proj = casesProjDir src = casesSrcDir actA = src "a.act" ensureCasesProject writeFileUtf8 actA "aaa = 1\n" writeFileUtf8 (src "c.act") $ T.unlines [ "import a" , "" , "actor main(env: Env):" , " print(a.aaa)" , " env.exit(0)" ] _ <- buildOutIn proj actAAbs <- canonicalizePath actA bytes <- B.readFile actAAbs let text = T.unpack (TE.decodeUtf8 bytes) snapSame = Source.SourceSnapshot { Source.ssText = text , Source.ssBytes = bytes , Source.ssIsOverlay = True } disk = Source.diskSourceProvider spSame = disk { Source.spReadOverlay = \path -> return (if path == actAAbs then Just snapSame else Nothing) } gopts = C.GlobalOptions { C.color = C.Never , C.quiet = True , C.noProgress = False , C.timing = False , C.tty = False , C.verbose = False , C.verboseZig = False , C.jobs = 1 } paths <- Compile.findPaths actAAbs Compile.defaultCompileOptions taskSame <- Compile.readModuleTask spSame gopts Compile.defaultCompileOptions paths actAAbs case taskSame of Compile.TyTask{} -> pure () _ -> assertFailure "expected TyTask when overlay matches header" let textDiff = "\"\"\"Overlay doc\"\"\"\naaa = 2\n" bytesDiff = TE.encodeUtf8 (T.pack textDiff) snapDiff = Source.SourceSnapshot { Source.ssText = textDiff , Source.ssBytes = bytesDiff , Source.ssIsOverlay = True } spDiff = disk { Source.spReadOverlay = \path -> return (if path == actAAbs then Just snapDiff else Nothing) } taskDiff <- Compile.readModuleTask spDiff gopts Compile.defaultCompileOptions paths actAAbs case taskDiff of Compile.ParseTask{ Compile.src = srcText, Compile.srcBytes = srcBytes } -> do srcText @?= textDiff srcBytes @?= bytesDiff _ -> assertFailure "expected ParseTask when overlay differs from header" docDiff <- Compile.readModuleDoc spDiff gopts Compile.defaultCompileOptions paths actAAbs case docDiff of Just (mn, Just doc) -> do mn @?= A.modName ["a"] doc @?= "Overlay doc" _ -> assertFailure "expected module doc from overlay header" p28_protocol_extension_deps :: TestTree p28_protocol_extension_deps = testCase "28-protocol/extension deps are recorded by name" $ do let proj = casesProjDir src = casesSrcDir tyA = proj "out" "types" "a.ty" tyB = proj "out" "types" "b.ty" ensureCasesProject writeFileUtf8 (src "a.act") $ T.unlines [ "protocol FooProto:" , " foo : () -> int" , "" , "protocol BazProto:" , " baz : () -> int" , "" , "protocol BarProto (FooProto, BazProto):" , " bar : () -> int" , "" , "class Widget:" , " def __init__(self):" , " pass" , "" , "extension Widget(BarProto):" , " def foo(self) -> int:" , " return 0" , " def baz(self) -> int:" , " return 2" , " def bar(self) -> int:" , " return 1" , "" , "def uses_proto(x: BarProto) -> int:" , " return 0" , "" , "def uses_class(x: Widget) -> int:" , " return 0" ] writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def runner(x: a.BarProto) -> int:" , " return a.uses_class(a.Widget())" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import a" , "import b" , "" , "actor main(env: Env):" , " b.runner(a.Widget())" , " env.exit(0)" ] _ <- buildOutIn proj nameHashesA <- readTyNameHashes tyA let namesA = sort (map (prstr . InterfaceFiles.nhName) nameHashesA) assertBool "expected generated protocol sibling name" ("BazProtoD_BarProto" `elem` namesA) assertBool "expected generated extension name" ("BarProtoD_Widget" `elem` namesA) (_, nmod, _, _, _, _, _, _, _, _, _, _) <- InterfaceFiles.readFile tyA let I.NModule _ iface _ = nmod extMatch (n, _) = prstr n == "BarProtoD_Widget" case find extMatch iface of Just (_, I.NExt _ _ ps _ _ _) -> do let protoNames = sort [ prstr (A.tcname p) | (_, p) <- ps ] assertEqual "extension protocol mro" (sort ["a.BarProto", "a.BazProto", "a.FooProto"]) protoNames _ -> assertFailure "missing extension NameInfo for BarProtoD_Widget" (pubDeps, implDeps) <- readTyDeps tyB "runner" let expectedPub = sort ["__builtin__.int", "a.BarProto", "a.Widget", "a.uses_class"] expectedImpl = sort ["a.BarProto", "a.Widget", "a.uses_class"] assertEqual "runner pub deps" expectedPub pubDeps assertEqual "runner impl deps" expectedImpl implDeps p29_protocol_impl_rebuild :: TestTree p29_protocol_impl_rebuild = testCase "29-protocol impl change triggers back jobs and new binary" $ do let proj = casesProjDir src = casesSrcDir modA = modLabel proj "a" modB = modLabel proj "b" modC = modLabel proj "c" ensureCasesProject writeFileUtf8 (src "a.act") $ T.unlines [ "protocol FooProto:" , " foo : () -> int" , "" , "protocol BazProto:" , " baz : () -> int" , "" , "protocol BarProto (FooProto, BazProto):" , " bar : () -> int" , "" , "class Widget:" , " def __init__(self):" , " pass" , "" , "extension Widget(BarProto):" , " def foo(self) -> int:" , " return 1" , " def baz(self) -> int:" , " return 2" , " def bar(self) -> int:" , " return 3" , "" , "def value() -> int:" , " return Widget().bar()" ] writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def calc() -> int:" , " return a.value()" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " print(b.calc())" , " env.exit(0)" ] _ <- buildOutIn proj out1 <- runBinaryIn proj "c" out1 @?= "3\n" writeFileUtf8 (src "a.act") $ T.unlines [ "protocol FooProto:" , " foo : () -> int" , "" , "protocol BazProto:" , " baz : () -> int" , "" , "protocol BarProto (FooProto, BazProto):" , " bar : () -> int" , "" , "class Widget:" , " def __init__(self):" , " pass" , "" , "extension Widget(BarProto):" , " def foo(self) -> int:" , " return 1" , " def baz(self) -> int:" , " return 5" , " def bar(self) -> int:" , " return 6" , "" , "def value() -> int:" , " return Widget().bar()" ] out2 <- buildOutIn proj assertBool "expected a.act to type check" (typechecked out2 modA) assertBool "did not expect b.act to type check" (not (typechecked out2 modB)) assertBool "did not expect c.act to type check" (not (typechecked out2 modC)) assertBool "expected b.act to compile codegen" (compiled out2 modB) assertBool "expected c.act to compile codegen" (compiled out2 modC) out2Run <- runBinaryIn proj "c" out2Run @?= "6\n" p30_only_build :: TestTree p30_only_build = testCase "30-only-build skips front passes" $ do let proj = casesProjDir src = casesSrcDir modA = modLabel proj "a" modB = modLabel proj "b" modC = modLabel proj "c" ensureCasesProject writeFileUtf8 (src "a.act") "aaa = 1\n" writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.aaa" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " b.bar()" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 (src "a.act") "aaa = 2\n" res2@(ec2, out2) <- runActonIn proj ["build", "--color", "never", "--verbose", "--only-build"] assertExitSuccess "only-build" res2 assertBool "did not expect a.act to type check" (not (typechecked out2 modA)) assertBool "did not expect b.act to type check" (not (typechecked out2 modB)) assertBool "did not expect c.act to type check" (not (typechecked out2 modC)) assertBool "did not expect b.act to compile codegen" (not (compiled out2 modB)) assertBool "did not expect c.act to compile codegen" (not (compiled out2 modC)) writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.aaa" , ")" ] res3@(ec3, out3) <- runActonIn proj ["build", "--color", "never", "--verbose", "--only-build"] assertExitSuccess "only-build with invalid body" res3 assertBool "did not expect invalid b.act to type check in only-build" (not (typechecked out3 modB)) assertBool "did not expect c.act to type check after invalid b.act in only-build" (not (typechecked out3 modC)) assertBool "did not expect parse diagnostics in only-build" (not ("Syntax error" `T.isInfixOf` out3)) p31_always_build :: TestTree p31_always_build = testCase "31-always-build forces front passes" $ do let proj = casesProjDir src = casesSrcDir modA = modLabel proj "a" modB = modLabel proj "b" modC = modLabel proj "c" ensureCasesProject writeFileUtf8 (src "a.act") "aaa = 1\n" writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.aaa" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " b.bar()" , " env.exit(0)" ] _ <- buildOutIn proj out <- buildOutInArgs proj ["--always-build"] assertBool "expected a.act to type check" (typechecked out modA) assertBool "expected b.act to type check" (typechecked out modB) assertBool "expected c.act to type check" (typechecked out modC) p32_project_alt_output :: TestTree p32_project_alt_output = testCase "32-project --types emits output" $ do let proj = casesProjDir src = casesSrcDir ensureCasesProject writeFileUtf8 (src "a.act") "aaa = 1\n" writeFileUtf8 (src "c.act") $ T.unlines [ "import a" , "" , "actor main(env: Env):" , " print(a.aaa)" , " env.exit(0)" ] _ <- buildOutIn proj res@(ec, out) <- runActonIn proj ["build", "--color", "never", "--types"] assertExitSuccess "project types" res assertBool "expected types dump" (T.isInfixOf "== types:" out) p33_comprehensive_hashes :: TestTree p33_comprehensive_hashes = testCase "33-comprehensive hash propagation" $ do let proj = casesProjDir src = casesSrcDir modA = modLabel proj "a" modB = modLabel proj "b" modC = modLabel proj "c" tyA = proj "out" "types" "a.ty" tyB = proj "out" "types" "b.ty" ensureCasesProjectWithDeps [("libfoo", "deps/libfoo")] depDir <- ensureDepProject proj "libfoo" let depSrc = depDir "src" "libfoo.act" libfooSource depConst addBonus = let bonusLines = if addBonus then [ " bonus : () -> int" , " def bonus(self) -> int:" , " return self.mega() + 1" ] else [] in T.unlines $ concat [ [ "protocol BaseProto:" , " base : () -> int" , " def base(self) -> int:" , " return 1" , "" , "protocol ExtraProto:" , " extra : () -> int" , " def extra(self) -> int:" , " return 2" , "" , "protocol MegaProto (BaseProto, ExtraProto):" , " mega : () -> int" , " def mega(self) -> int:" , " return self.base() + self.extra()" ] , bonusLines , [ "" , "class DepClass:" , " def __init__(self, v: int):" , " self.v = v" , " def base(self) -> int:" , " return self.v" , " def extra(self) -> int:" , " return self.v + 1" , "" , "extension DepClass(MegaProto):" , " def mega(self) -> int:" , " return self.base() + self.extra()" , "" , "dep_const = " <> T.pack (show depConst) , "" , "def dep_value() -> int:" , " return DepClass(dep_const).mega()" ] ] writeFileUtf8 depSrc (libfooSource 5 False) writeFileUtf8 (src "a.act") $ T.unlines [ "import libfoo" , "" , "const = 7" , "x, y = 1, 2" , "" , "def add(n: int) -> int:" , " return n + const" , "" , "class Local:" , " def __init__(self, v: int):" , " self.v = v" , " def get(self) -> int:" , " return self.v" , "" , "actor Worker(v: int):" , " pass" , "" , "def dep_call() -> int:" , " return libfoo.dep_value()" ] writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "import libfoo" , "" , "def use_types(x: a.Local, w: a.Worker) -> int:" , " return a.add(x.get())" , "" , "def use_values() -> int:" , " return a.add(libfoo.dep_const) + a.dep_call()" , "" , "def use_method(x: a.Local) -> int:" , " return x.get()" , "" , "def use_actor(w: a.Worker) -> int:" , " return 0" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import a" , "import b" , "" , "actor main(env: Env):" , " l = a.Local(3)" , " print(b.use_values() + b.use_method(l))" , " env.exit(0)" ] _ <- buildOutIn proj let tyDep = depDir "out" "types" "libfoo.ty" depNameHashes <- readTyNameHashes tyDep let depNames = sort (map (prstr . InterfaceFiles.nhName) depNameHashes) assertBool "expected derived proto name" ("ExtraProtoD_MegaProto" `elem` depNames) assertBool "expected extension name" ("MegaProtoD_DepClass" `elem` depNames) case find (\nh -> prstr (InterfaceFiles.nhName nh) == "ExtraProtoD_MegaProto") depNameHashes of Nothing -> assertFailure "missing ExtraProtoD_MegaProto in libfoo" Just nh -> assertBool "expected empty pub hash for derived proto" (B.null (InterfaceFiles.nhPubHash nh)) (pubTypes, implTypes) <- readTyDeps tyB "use_types" assertDepsContain "use_types pub deps" ["a.Local", "a.Worker", "a.add"] pubTypes assertDepsContain "use_types impl deps" ["a.add"] implTypes (pubVals, implVals) <- readTyDeps tyB "use_values" assertDepsContain "use_values pub deps" ["a.add", "a.dep_call", "libfoo.dep_const"] pubVals assertDepsContain "use_values impl deps" ["a.add", "a.dep_call", "libfoo.dep_const"] implVals (pubActor, _) <- readTyDeps tyB "use_actor" assertDepsContain "use_actor pub deps" ["a.Worker"] pubActor (_, implDepCall) <- readTyDeps tyA "dep_call" assertDepsContain "dep_call impl deps" ["libfoo.dep_value"] implDepCall out1 <- runBinaryIn proj "c" out1 @?= "26\n" writeFileUtf8 depSrc (libfooSource 5 True) out2 <- buildOutIn proj assertBool "did not expect a.act to type check" (not (typechecked out2 modA)) assertBool "did not expect b.act to type check" (not (typechecked out2 modB)) assertBool "did not expect c.act to type check" (not (typechecked out2 modC)) out2Run <- runBinaryIn proj "c" out2Run @?= "26\n" writeFileUtf8 depSrc (libfooSource 8 True) out3 <- buildOutIn proj assertBool "did not expect a.act to type check" (not (typechecked out3 modA)) assertBool "did not expect b.act to type check" (not (typechecked out3 modB)) assertBool "did not expect c.act to type check" (not (typechecked out3 modC)) assertBool "expected a.act to compile codegen" (compiled out3 modA) assertBool "expected b.act to compile codegen" (compiled out3 modB) assertBool "expected c.act to compile codegen" (compiled out3 modC) out3Run <- runBinaryIn proj "c" out3Run @?= "35\n" p34_removed_import_module :: TestTree p34_removed_import_module = testCase "34-removed imported module fails before Zig" $ do let proj = casesProjDir src = casesSrcDir outA = proj "out" "types" "a" ensureCasesProject writeFileUtf8 (src "a.act") "aaa = 1\n" writeFileUtf8 (src "b.act") $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.aaa" ] writeFileUtf8 (src "c.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " print(b.bar())" , " env.exit(0)" ] _ <- buildOutIn proj removeFile (src "a.act") res@(ec, out) <- runActonIn proj ["build", "--color", "never", "--verbose"] assertExitFailure "build after deleting imported module" 1 res mapM_ (\ext -> do exists <- doesFileExist (outA ++ ext) assertBool ("did not expect stale generated " ++ outA ++ ext) (not exists)) [".ty", ".c", ".h"] assertBool "expected missing import diagnostic" (T.isInfixOf "Type interface file not found or unreadable for a" out) assertBool "did not expect Zig build to run" (not (T.isInfixOf "zigCmd:" out)) p35_changed_path_keeps_unaffected_provider :: TestTree p35_changed_path_keeps_unaffected_provider = testCase "35-changed-path incremental keeps unchanged providers" $ do let proj = casesProjDir src = casesSrcDir actA = src "a.act" actB = src "b.act" actC = src "c.act" actMain = src "main.act" gopts = C.GlobalOptions { C.color = C.Never , C.quiet = True , C.noProgress = False , C.timing = False , C.tty = False , C.verbose = False , C.verboseZig = False , C.jobs = 1 } opts = Compile.defaultCompileOptions { C.only_build = True } ensureCasesProject writeFileUtf8 actA "aaa = 1\n" writeFileUtf8 actC "ccc = 10\n" writeFileUtf8 actB $ T.unlines [ "import a" , "import c" , "" , "def bar() -> int:" , " return a.aaa + c.ccc" ] writeFileUtf8 actMain $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " print(b.bar())" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 actA "aaa = 2\n" actAAbs <- canonicalizePath actA actMainAbs <- canonicalizePath actMain sched <- Compile.newCompileScheduler gopts 1 plan <- Compile.prepareCompilePlan Source.diskSourceProvider gopts sched opts [actMainAbs] False (Just [actAAbs]) bTask <- case find (\t -> Compile.name (Compile.gtTask t) == A.modName ["b"]) (Compile.cpNeededTasks plan) of Just t -> pure t Nothing -> assertFailure "expected b in changed-path compile plan" >> fail "missing b task" let bProviders = Compile.gtImportProviders bTask assertBool "expected provider for changed import a" (M.member (A.modName ["a"]) bProviders) assertBool "expected provider for unchanged import c" (M.member (A.modName ["c"]) bProviders) p36_removed_dep_name_triggers_front_refresh :: TestTree p36_removed_dep_name_triggers_front_refresh = testCase "36-removed dep name forces front refresh" $ do let proj = casesProjDir src = casesSrcDir ensureCasesProjectWithDeps [("libfoo", "deps/libfoo")] depDir <- ensureDepProject proj "libfoo" let depSrc = depDir "src" "libfoo.act" writeFileUtf8 depSrc $ T.unlines [ "def foo() -> int:" , " return 1" ] writeFileUtf8 (src "main.act") $ T.unlines [ "import libfoo" , "" , "actor main(env: Env):" , " print(libfoo.foo())" , " env.exit(0)" ] res1 <- runActonIn proj ["build", "--color", "never", "--skip-build"] assertExitSuccess "initial build" res1 writeFileUtf8 depSrc $ T.unlines [ "def bar() -> int:" , " return 2" ] res2@(_ec2, out2) <- runActonIn proj ["build", "--color", "never", "--verbose", "--skip-build"] assertExitFailure "rebuild after removing imported dep name" 1 res2 assertBool "expected stale-cache log for missing dep hash" (T.isInfixOf "missing dep hashes in" out2 && T.isInfixOf "libfoo.foo" out2) assertBool "did not expect internal hash-missing diagnostic" (not (T.isInfixOf "Hash info missing for libfoo.foo" out2)) p37_impl_refresh_missing_dep_hashes_reruns_front :: TestTree p37_impl_refresh_missing_dep_hashes_reruns_front = testCase "37-impl refresh missing dep hashes reruns front passes" $ do let proj = casesProjDir src = casesSrcDir modMain = modLabel proj "main" ensureCasesProjectWithDeps [("libfoo", "deps/libfoo")] depDir <- ensureDepProject proj "libfoo" let depSrc = depDir "src" "libfoo.act" tyMain = proj "out" "types" "main.ty" writeFileUtf8 depSrc $ T.unlines [ "def foo() -> int:" , " return 1" , "" , "def bar() -> int:" , " return 2" ] writeFileUtf8 (src "main.act") $ T.unlines [ "import libfoo" , "" , "def value() -> int:" , " return libfoo.foo() + libfoo.bar()" , "" , "actor main(env: Env):" , " print(value())" , " env.exit(0)" ] res1 <- runActonIn proj ["build", "--color", "never", "--skip-build"] assertExitSuccess "initial build" res1 let mainV2 = T.unlines [ "import libfoo" , "" , "def value() -> int:" , " return libfoo.foo()" , "" , "actor main(env: Env):" , " print(value())" , " env.exit(0)" ] writeFileUtf8 (src "main.act") mainV2 rewriteTySrcHashAndNameHashes tyMain (SHA256.hash (TE.encodeUtf8 mainV2)) (dropTyDepByLabel "libfoo.bar") writeFileUtf8 depSrc $ T.unlines [ "def foo() -> int:" , " return 10" ] res2@(_ec2, out2) <- runActonIn proj ["build", "--color", "never", "--verbose", "--skip-build"] assertExitSuccess "rebuild after impl refresh dep hash miss" res2 assertBool ("expected impl-refresh fallback log\n" ++ T.unpack out2) (T.isInfixOf "impl refresh encountered unresolved dep hashes; rerunning front passes" out2) assertBool ("did not expect internal hash-missing diagnostic\n" ++ T.unpack out2) (not (T.isInfixOf "Hash info missing for libfoo.bar" out2)) assertBool ("did not expect internal NoItem failure\n" ++ T.unpack out2) (not (T.isInfixOf "NoItem" out2)) assertBool ("expected main.act to type check after fallback\n" ++ T.unpack out2) (typechecked out2 modMain) p38_project_lock_blocks_build :: TestTree p38_project_lock_blocks_build = testCase "38-project lock blocks concurrent build" $ do let proj = casesProjDir src = casesSrcDir ensureCasesProject writeFileUtf8 (src "main.act") $ T.unlines [ "actor main(env: Env):" , " env.exit(0)" ] actonExe <- actonPath res <- Compile.withProjectLock proj $ do (_, mOut, mErr, ph) <- createProcess (proc actonExe ["build", "--color", "never", "--jobs", "1"]) { cwd = Just proj , std_out = CreatePipe , std_err = CreatePipe } let outH = requirePipe "stdout" mOut errH = requirePipe "stderr" mErr (do threadDelay 500000 mExit <- getProcessExitCode ph case mExit of Nothing -> pure () Just ec -> assertFailure ("build should have blocked on .acton.lock, exited early with " ++ show ec) pure (ph, outH, errH)) `E.onException` do terminateProcess ph _ <- waitForProcess ph pure () let (ph, outH, errH) = res ec <- waitForProcess ph out <- T.hGetContents outH err <- T.hGetContents errH assertEqual "build should succeed after lock is released" ExitSuccess ec let combined = out <> err assertBool ("expected wait message while build was blocked\n" ++ T.unpack combined) (T.isInfixOf "Waiting for compiler lock in" combined) where requirePipe :: String -> Maybe Handle -> Handle requirePipe label = maybe (error ("missing " ++ label ++ " pipe for lock wait test")) id p39_background_lock_does_not_block_build :: TestTree p39_background_lock_does_not_block_build = testCase "39-background compiler lock does not block build" $ do let proj = casesProjDir src = casesSrcDir ensureCasesProject writeFileUtf8 (src "main.act") $ T.unlines [ "actor main(env: Env):" , " env.exit(0)" ] withBackgroundCompilerLockHeld proj $ do res@(_ec, out) <- runActonIn proj ["build", "--color", "never", "--verbose"] assertExitSuccess "build should run under .acton.compile.lock" res assertBool ("expected build to rerun front passes while background lock is held\n" ++ T.unpack out) (typechecked out "main") p40_background_lock_blocks_watch :: TestTree p40_background_lock_blocks_watch = testCase "40-background compiler lock blocks watch" $ do let proj = casesProjDir src = casesSrcDir ensureCasesProject writeFileUtf8 (src "main.act") $ T.unlines [ "actor main(env: Env):" , " env.exit(0)" ] withBackgroundCompilerLockHeld proj $ do actonExe <- actonPath (_, _, _, ph) <- createProcess (proc actonExe ["build", "--watch", "--color", "never", "--jobs", "1"]) { cwd = Just proj } (do threadDelay 500000 mExit <- getProcessExitCode ph case mExit of Nothing -> do terminateProcess ph _ <- waitForProcess ph assertFailure "watch should fail quickly when .acton.compile.lock is already held" Just ExitSuccess -> assertFailure "watch should not succeed when .acton.compile.lock is already held" Just (ExitFailure _) -> pure ()) `E.onException` do terminateProcess ph _ <- waitForProcess ph pure () p41_stale_header_missing_import_reparses_source :: TestTree p41_stale_header_missing_import_reparses_source = testCase "41-stale header missing import reparses source" $ do let proj = casesProjDir src = casesSrcDir actA = src "a.act" actB = src "b.act" tyB = proj "out" "types" "b.ty" outA = proj "out" "types" "a" modB = modLabel proj "b" ensureCasesProject writeFileUtf8 actA "aaa = 1\n" writeFileUtf8 actB $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.aaa" ] writeFileUtf8 (src "main.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " print(b.bar())" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 actB $ T.unlines [ "def bar() -> int:" , " return 7" ] tyTime <- getModificationTime tyB setModificationTime actB (addUTCTime (-10) tyTime) removeFile actA res@(_ec, out) <- runActonIn proj ["build", "--color", "never", "--verbose"] assertExitSuccess "build after stale header import removal" res mapM_ (\ext -> do exists <- doesFileExist (outA ++ ext) assertBool ("did not expect stale generated " ++ outA ++ ext) (not exists)) [".ty", ".c", ".h"] assertBool "expected b.act to type check after stale header reparse" (typechecked out modB) assertBool ("did not expect stale import diagnostic\n" ++ T.unpack out) (not (T.isInfixOf "Type interface file not found or unreadable for a" out)) p42_metadata_drift_refreshes_header :: TestTree p42_metadata_drift_refreshes_header = testCase "42-metadata drift refreshes header" $ do let proj = casesProjDir src = casesSrcDir actA = src "a.act" tyA = proj "out" "types" "a.ty" modA = modLabel proj "a" ensureCasesProject writeFileUtf8 actA "aaa = 1\n" writeFileUtf8 (src "main.act") $ T.unlines [ "import a" , "" , "actor main(env: Env):" , " print(a.aaa)" , " env.exit(0)" ] _ <- buildOutIn proj metaBefore <- readTySourceMeta tyA threadDelay 1000000 touch actA out <- buildOutIn proj metaAfter <- readTySourceMeta tyA currentMeta <- sourceFileMetaForPath actA assertBool "did not expect a.act to type check after metadata-only drift" (not (typechecked out modA)) assertBool "expected .ty header to carry source metadata" (isJust metaAfter) assertBool "expected metadata drift to update cached source metadata" (metaBefore /= metaAfter) metaAfter @?= Just currentMeta p43_equal_act_ty_mtime_hashes_source :: TestTree p43_equal_act_ty_mtime_hashes_source = testCase "43-equal act/ty mtimes still hash source" $ do let proj = casesProjDir src = casesSrcDir actA = src "a.act" actB = src "b.act" tyB = proj "out" "types" "b.ty" outA = proj "out" "types" "a" modB = modLabel proj "b" ensureCasesProject writeFileUtf8 actA "aaa = 1\n" writeFileUtf8 actB $ T.unlines [ "import a" , "" , "def bar() -> int:" , " return a.aaa" ] writeFileUtf8 (src "main.act") $ T.unlines [ "import b" , "" , "actor main(env: Env):" , " print(b.bar())" , " env.exit(0)" ] _ <- buildOutIn proj writeFileUtf8 actB $ T.unlines [ "def bar() -> int:" , " return 7" ] rewriteTySourceMeta tyB Nothing tyStatus <- getFileStatus tyB let tyMTimeNs = floor (toRational (modificationTimeHiRes tyStatus) * 1000000000) setFileMTimeNs actB tyMTimeNs currentMeta <- sourceFileMetaForPath actB rewriteTySourceMeta tyB (Just currentMeta) setFileMTimeNs tyB tyMTimeNs metaAfter <- readTySourceMeta tyB metaAfter @?= Just currentMeta removeFile actA res@(_ec, out) <- runActonIn proj ["build", "--color", "never", "--verbose"] assertExitSuccess "build after equal act/ty mtime stale header" res mapM_ (\ext -> do exists <- doesFileExist (outA ++ ext) assertBool ("did not expect stale generated " ++ outA ++ ext) (not exists)) [".ty", ".c", ".h"] assertBool "expected b.act to type check after equal-mtime hash check" (typechecked out modB) assertBool ("did not expect stale import diagnostic\n" ++ T.unpack out) (not (T.isInfixOf "Type interface file not found or unreadable for a" out)) p44_provider_import_rename_reruns_dependent_front :: TestTree p44_provider_import_rename_reruns_dependent_front = testCase "44-provider import rename reruns dependent front passes" $ do let proj = casesProjDir src = casesSrcDir actMain = src "main.act" actBase = src "base.act" oldPkgDir = src "oldpkg" newPkgDir = src "newpkg" modMain = modLabel proj "main" modBase = modLabel proj "base" ensureCasesProject createDirectoryIfMissing True oldPkgDir writeFileUtf8 actMain $ T.unlines [ "import base" , "" , "class Derived(base.Base):" , " pass" , "" , "actor main(env: Env):" , " env.exit(0)" ] writeFileUtf8 actBase $ T.unlines [ "import oldpkg.ttt as ttt" , "" , "class Base(ttt.TransformFunction):" , " pass" ] writeFileUtf8 (src "oldpkg.act") "" writeFileUtf8 (oldPkgDir "ttt.act") $ T.unlines [ "class TransformFunction(object):" , " pass" ] res1 <- runActonIn proj ["build", "--color", "never", "--skip-build"] assertExitSuccess "initial build before provider import rename" res1 createDirectoryIfMissing True newPkgDir writeFileUtf8 actBase $ T.unlines [ "import newpkg.ttt as ttt" , "" , "class Base(ttt.TransformFunction):" , " pass" ] writeFileUtf8 (src "newpkg.act") "" writeFileUtf8 (newPkgDir "ttt.act") $ T.unlines [ "class TransformFunction(object):" , " pass" ] removeFile (src "oldpkg.act") removeFile (oldPkgDir "ttt.act") removeDirIfExists oldPkgDir res2@(_ec2, out2) <- runActonIn proj ["build", "--color", "never", "--verbose", "--skip-build"] assertExitSuccess "rebuild after provider import rename" res2 assertBool ("expected base.act to type check after provider import rename\n" ++ T.unpack out2) (typechecked out2 modBase) assertBool ("expected main.act to type check after provider import rename\n" ++ T.unpack out2) (typechecked out2 modMain) assertBool ("did not expect stale transitive import diagnostic\n" ++ T.unpack out2) (not (T.isInfixOf "Type interface file not found or unreadable for oldpkg.ttt" out2)) assertBool ("expected stale-cache log for missing transitive dep hash\n" ++ T.unpack out2) (T.isInfixOf "missing dep hashes in" out2 && T.isInfixOf "oldpkg.ttt.TransformFunction" out2) -- Main ----------------------------------------------------------------------- -- | Tasty entry point for incremental tests. main :: IO () main = defaultMain $ localOption (NumThreads 1) $ testGroup "incremental" [ sequentialTestGroup "incremental-project" AllSucceed [ p01_init , p02_initial_build , p03_up_to_date , p04_touch_no_rebuild , p05_run_123 , p06_change_a_impl , p06_impl_change_fresh , p07_run_124 , p08_change_b_impl , p09_run_124 , p10_change_a_iface , p11_change_b_doc , p12_codegen_stale ] , sequentialTestGroup "incremental-file" AllSucceed [ f01_init , f02_initial_build , f03_up_to_date , f04_touch_no_rebuild , f05_run_123 , f06_change_a_impl , f07_run_124 , f08_change_b_impl , f09_run_124 , f10_alt_output ] , sequentialTestGroup "incremental-project-cases" AllSucceed [ p14_partial_rebuild , p15_rebuild_import , p16_dep_api_change , p17_dep_impl_change , p18_type_only_deps , p19_unused_import , p20_add_remove_names , p21_recursive_group , p22_multibind , p23_codegen_mismatch , p24_codegen_equal_hash , p25_whitespace_change , p26_corrupt_ty_header , p26_ty_version_mismatch , p27_overlay_source_provider , p28_protocol_extension_deps , p29_protocol_impl_rebuild , p30_only_build , p31_always_build , p32_project_alt_output , p33_comprehensive_hashes , p34_removed_import_module , p35_changed_path_keeps_unaffected_provider , p36_removed_dep_name_triggers_front_refresh , p37_impl_refresh_missing_dep_hashes_reruns_front , p38_project_lock_blocks_build , p39_background_lock_does_not_block_build , p40_background_lock_blocks_watch ] , sequentialTestGroup "incremental-cache-cases" AllSucceed [ p41_stale_header_missing_import_reparses_source , p42_metadata_drift_refreshes_header , p43_equal_act_ty_mtime_hashes_source , p44_provider_import_rename_reruns_dependent_front ] ] ================================================ FILE: compiler/acton/test_online.hs ================================================ import Control.Exception (finally) import qualified Data.Map as M import System.Directory (canonicalizePath) import System.Environment (lookupEnv, setEnv, unsetEnv) import System.Exit import System.FilePath import System.IO.Temp (withSystemTempDirectory) import System.Process import Test.Tasty import Test.Tasty.HUnit import Data.Bits (shiftL, (.|.)) import Data.Word (Word64) import qualified Acton.BuildSpec as BuildSpec import qualified Acton.Fingerprint as Fingerprint main :: IO () main = defaultMain $ testGroup "Online tests" [pkgCliIntegrationTests] fingerprintForName :: String -> String fingerprintForName name = let prefix = Fingerprint.fingerprintPrefixForName name fp = (fromIntegral prefix `shiftL` 32) .|. (1 :: Word64) in Fingerprint.formatFingerprint fp writeBuildAct :: FilePath -> String -> IO () writeBuildAct dir name = do let fp = fingerprintForName name content = unlines [ "name = \"" ++ name ++ "\"" , "fingerprint = " ++ fp , "" , "dependencies = {}" , "" , "zig_dependencies = {}" , "" ] writeFile (dir "Build.act") content readBuildSpecAct :: FilePath -> IO BuildSpec.BuildSpec readBuildSpecAct path = do content <- readFile path case BuildSpec.parseBuildAct content of Left err -> assertFailure err >> error "unreachable" Right (spec, _, _) -> return spec pkgCliIntegrationTests :: TestTree pkgCliIntegrationTests = testGroup "pkg CLI integration" [ testCase "pkg add/upgrade/remove (network)" $ do withTempHome $ \_ -> withSystemTempDirectory "acton-pkg" $ \proj -> do let depName = "foo" repoUrl = "https://github.com/actonlang/foo" projName = "acton_pkg_test" writeBuildAct proj projName (codeAdd, outAdd, errAdd) <- runActonIn proj ["pkg", "add", depName, "--repo-url", repoUrl] assertExit "pkg add" ExitSuccess codeAdd outAdd errAdd spec1 <- readBuildSpecAct (proj "Build.act") dep1 <- requirePkgDep spec1 depName assertEqual "repo_url" (Just repoUrl) (BuildSpec.repo_url dep1) assertBool "url set" (hasText (BuildSpec.url dep1)) assertBool "hash set" (hasText (BuildSpec.hash dep1)) (codeUp, outUp, errUp) <- runActonIn proj ["pkg", "upgrade"] assertExit "pkg upgrade" ExitSuccess codeUp outUp errUp spec2 <- readBuildSpecAct (proj "Build.act") dep2 <- requirePkgDep spec2 depName assertEqual "repo_url after upgrade" (Just repoUrl) (BuildSpec.repo_url dep2) (codeRm, outRm, errRm) <- runActonIn proj ["pkg", "remove", depName] assertExit "pkg remove" ExitSuccess codeRm outRm errRm spec3 <- readBuildSpecAct (proj "Build.act") assertBool "dep removed" (M.notMember depName (BuildSpec.dependencies spec3)) ] withTempHome :: (FilePath -> IO a) -> IO a withTempHome action = withSystemTempDirectory "acton-home" $ \home -> do oldHome <- lookupEnv "HOME" setEnv "HOME" home action home `finally` restoreHome oldHome where restoreHome Nothing = unsetEnv "HOME" restoreHome (Just val) = setEnv "HOME" val runActonIn :: FilePath -> [String] -> IO (ExitCode, String, String) runActonIn wd args = do actonExe <- canonicalizePath "../../dist/bin/acton" readCreateProcessWithExitCode (proc actonExe args){ cwd = Just wd } "" assertExit :: String -> ExitCode -> ExitCode -> String -> String -> IO () assertExit label expected actual out err = if actual == expected then return () else assertFailure $ unlines [ label ++ " exit" , "expected: " ++ show expected , " but got: " ++ show actual , "stdout:" , out , "stderr:" , err ] requirePkgDep :: BuildSpec.BuildSpec -> String -> IO BuildSpec.PkgDep requirePkgDep spec depName = case M.lookup depName (BuildSpec.dependencies spec) of Nothing -> assertFailure ("Missing dependency " ++ depName) >> error "unreachable" Just dep -> return dep hasText :: Maybe String -> Bool hasText val = maybe False (not . null) val ================================================ FILE: compiler/diagnose/.gitignore ================================================ .stack-work/ *~ *.lock # This is a lib, we'd rather not commit the lock file... ================================================ FILE: compiler/diagnose/LICENSE ================================================ Copyright Ghilain Bergeron (Mesabloo) (c) 2019-2020 All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Ghilain Bergeron (Mesabloo) nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: compiler/diagnose/PATCHES.md ================================================ # Diagnose Vendor Notes Baseline: upstream `mesabloo/diagnose` commit `d3ffbb7f376ddc64f3f349fe3a6a8e49d405cde0` (`master`, package version `2.5.1`). This baseline is newer than the Hackage `diagnose-2.5.1` release. It includes upstream PR #24, which removes the direct `text` dependency instead of forcing consumers onto `text <=2.0`. Maintenance policy: - Treat this directory as a forkable upstream package, not project-specific code. - Keep local changes generic and suitable for a standalone `diagnose` fork or upstream pull request. - Document each local patch here with its rationale. - Prefer separate commits for the upstream baseline import and each local patch. - If local changes grow beyond small dependency/build fixes, extract this directory to a dedicated fork and pin this build to that repository commit. Local patches: - None beyond vendoring this upstream snapshot and this note. ================================================ FILE: compiler/diagnose/README.md ================================================ # Error reporting made easy Diagnose is a small library used to report compiler/interpreter errors in a beautiful yet readable way. It was in the beginning heavily inspired by [ariadne](https://github.com/zesterer/ariadne), but ended up quickly becoming its own thing. As a great example, here's the output of the last test: ![first example](./assets/real-world-example-unicode.png) If you do not like unicode characters, or choose to target platforms which cannot output them natively; you may alternatively print the whole diagnostic with ASCII characters, like this: ![second example](./assets/real-world-example-ascii.png) Colors are also optional, and you may choose not to print them. ## Features - Show diagnostics with/without 8-bit colors, with/without Unicode characters - Inline and multiline markers are nicely displayed - The order of markers matters! If there are multiple markers on the same line, they are ordered according to how they were put in each report - Reports spanning across multiple files are handled as well - Generic over the type of message which can be displayed, meaning that you can output custom data types as well as they can be pretty-printed - Diagnostics can be exported to JSON, if you don't quite like the rendering as it is, or if you need to transmit them to e.g. a website - Plug and play (mega)parsec integration and it magically works with your parsers! - Support for optional custom error codes, if you want to go the Rust way - Variable width Unicode characters are handled in a crossplatform manner - TAB characters have custom sizes specified when printing a diagnostic, so that *you* decide the width of a TAB, not your terminal emulator! - Colors can be tweaked thanks to the ability to export diagnostics as `Doc`uments ## Usage You only need to `import Error.Diagnose`, and everything should be ready to go. You don't even need to `import Prettyprinter`, as it is already provided to you by `Error.Diagnose`! -------- A diagnostic can be viewed as a collection of reports, spanning on files. This is what the `Diagnostic` type embodies. It is an instance of `Monoid`, which can be used to construct an empty diagnostic (contains no reports, and has no files). The second step is to add some reports. There are two kinds of reports: - Error reports, created through `Err` - Warning reports, created by using `Warn` Both of these fonctions have the following type: ```haskell -- | An optional error code, shown right after @error@ or @warning@ in the square brackets Maybe msg -> -- | The main message, which is output at the top right after @[error]@ or @[warning]@ msg -> -- | A list of markers, along with the positions they span on [(Position, Marker msg)] -> -- | Some hints to be output at the bottom of the report [Note msg] -> -- | The created report Report msg ``` Each report contains markers, which are what underlines the code in the screenshots above. They come in three flavors: - A `This` marker indicates the main reason of the error. It is highlighted in red (for errors) or yellow (for warnings). Ideally, there is only one per report, but this isn't strictly required. - A `Where` marker adds additional context to the error by adding highlighted code to the error. This can be used to remind used that a variable was found of a given type earlier, or even where a previous declaration was found in another file. This is output in blue by default. - A `Maybe` marker is probably the rarest one. It is basically a way of suggesting fixes (as when GCC tells you that you probably mistyped a variable name). These markers are highlighted in green. The `Position` datatype is however required to be used with this library. If you use another way of keeping track of position information, you will need to convert them to the `Position` datatype. Once your reports are created, you will need to add them inside the diagnostic using `addReport`. You will also need to put your files into the diagnostic with `addFile`, else lines won't be printed and you will get `` in your reports. After all of this is done, you may choose to either: - print the diagnostic onto a file `Handle` (most likely `stdout` or `stderr`) using `printDiagnostic`; - create a `Doc`ument which can be further altered using `prettyDiagnostic`; - or export it to JSON with `diagnosticToJson` or the `ToJSON` class of Aeson (the output format is documented under the `diagnosticToJson` function). ## Example Here is how the above screenshot was generated: ```haskell let beautifulExample = err Nothing "Could not deduce constraint 'Num(a)' from the current context" [ (Position (1, 25) (2, 6) "somefile.zc", This "While applying function '+'"), (Position (1, 11) (1, 16) "somefile.zc", Where "'x' is supposed to have type 'a'"), (Position (1, 8) (1, 9) "somefile.zc", Where "type 'a' is bound here without constraints") ] ["Adding 'Num(a)' to the list of constraints may solve this problem."] -- ^^^^ This is a 'Note' not a 'Hint', as specified by its 'IsString' instance -- Create the diagnostic let diagnostic = addFile mempty "somefile.zc" "let id(x : a) : a := x\n + 1" let diagnostic' = addReport diagnostic beautifulExample -- Print with unicode characters, and the default (colorful) style printDiagnostic stdout WithUnicode 4 defaultStyle diagnostic' ``` More examples are given in the [`test/rendering`](./test/rendering) folder (execute `stack test` to see the output). ## TODO list << empty, for now >> ## License This work is licensed under the BSD-3 clause license. Copyright (c) 2021-2022 Mesabloo, all rights reserved. ================================================ FILE: compiler/diagnose/diagnose.cabal ================================================ cabal-version: 1.12 -- This file has been generated from package.yaml by hpack version 0.35.2. -- -- see: https://github.com/sol/hpack name: diagnose version: 2.5.1 synopsis: Beautiful error reporting done easily description: This package provides a simple way of getting beautiful compiler/interpreter errors using a very simple interface for the programmer. . A quick tutorial is available in the module "Error.Diagnose", which goes on most of the basis of how to use it. category: Error Reporting homepage: https://github.com/mesabloo/diagnose#readme bug-reports: https://github.com/mesabloo/diagnose/issues author: Ghilain Bergeron maintainer: Ghilain Bergeron copyright: 2021-2022 Ghilain Bergeron license: BSD3 license-file: LICENSE build-type: Simple extra-source-files: README.md source-repository head type: git location: https://github.com/mesabloo/diagnose flag json description: Allows exporting diagnostics as JSON. This is disabled by default as this relies on the very heavy dependency Aeson. manual: True default: False flag megaparsec-compat description: Includes a small compatibility layer (in the module `Error.Diagnose.Compat.Megaparsec`) to transform megaparsec errors into reports for this library. manual: True default: False flag parsec-compat description: Includes a small compatibility layer (in the module `Error.Diagnose.Compat.Parsec`) to transform parsec errors into reports for this library. manual: True default: False library exposed-modules: Error.Diagnose Error.Diagnose.Diagnostic Error.Diagnose.Position Error.Diagnose.Pretty Error.Diagnose.Report Error.Diagnose.Style other-modules: Data.List.Safe Error.Diagnose.Compat.Hints Error.Diagnose.Diagnostic.Internal Error.Diagnose.Report.Internal Paths_diagnose hs-source-dirs: src default-extensions: OverloadedStrings LambdaCase BlockArguments ghc-options: -Wall -Wextra build-depends: array ==0.5.* , base >=4.7 && <5 , data-default >=0.7 && <1 , dlist ==1.0.* , hashable >=1.3 && <2 , prettyprinter >=1.7.0 && <2 , prettyprinter-ansi-terminal >=1.1.2 && <2 , unordered-containers >=0.2.11 && <0.3 , wcwidth >=0.0.1 && <1 default-language: Haskell2010 if flag(json) cpp-options: -DUSE_AESON build-depends: aeson >=1.5 && <3 , bytestring >=0.9 && <1 if flag(megaparsec-compat) build-depends: containers ==0.6.* , megaparsec >=9.0.0 if flag(parsec-compat) build-depends: parsec >=3.1.14 if flag(megaparsec-compat) exposed-modules: Error.Diagnose.Compat.Megaparsec if flag(parsec-compat) exposed-modules: Error.Diagnose.Compat.Parsec test-suite diagnose-megaparsec-tests type: exitcode-stdio-1.0 main-is: Spec.hs other-modules: Instances Repro6 Paths_diagnose hs-source-dirs: test/megaparsec default-extensions: OverloadedStrings LambdaCase BlockArguments ghc-options: -Wall -Wextra -threaded -rtsopts -with-rtsopts=-N build-depends: array ==0.5.* , base >=4.7 && <5 , data-default >=0.7 && <1 , diagnose , dlist ==1.0.* , hashable >=1.3 && <2 , prettyprinter >=1.7.0 && <2 , prettyprinter-ansi-terminal >=1.1.2 && <2 , text >=1.2 && <3 , unordered-containers >=0.2.11 && <0.3 , wcwidth >=0.0.1 && <1 default-language: Haskell2010 if flag(json) cpp-options: -DUSE_AESON build-depends: aeson >=1.5 && <3 , bytestring >=0.9 && <1 if flag(megaparsec-compat) build-depends: containers ==0.6.* , megaparsec >=9.0.0 if flag(parsec-compat) build-depends: parsec >=3.1.14 if !(flag(megaparsec-compat)) buildable: False test-suite diagnose-parsec-tests type: exitcode-stdio-1.0 main-is: Spec.hs other-modules: Repro2 Paths_diagnose hs-source-dirs: test/parsec default-extensions: OverloadedStrings LambdaCase BlockArguments ghc-options: -Wall -Wextra -threaded -rtsopts -with-rtsopts=-N build-depends: array ==0.5.* , base >=4.7 && <5 , data-default >=0.7 && <1 , diagnose , dlist ==1.0.* , hashable >=1.3 && <2 , prettyprinter >=1.7.0 && <2 , prettyprinter-ansi-terminal >=1.1.2 && <2 , text >=1.2 && <3 , unordered-containers >=0.2.11 && <0.3 , wcwidth >=0.0.1 && <1 default-language: Haskell2010 if flag(json) cpp-options: -DUSE_AESON build-depends: aeson >=1.5 && <3 , bytestring >=0.9 && <1 if flag(megaparsec-compat) build-depends: containers ==0.6.* , megaparsec >=9.0.0 if flag(parsec-compat) build-depends: parsec >=3.1.14 if !(flag(parsec-compat)) buildable: False test-suite diagnose-rendering-tests type: exitcode-stdio-1.0 main-is: Spec.hs other-modules: Paths_diagnose hs-source-dirs: test/rendering default-extensions: OverloadedStrings LambdaCase BlockArguments ghc-options: -Wall -Wextra -threaded -rtsopts -with-rtsopts=-N build-depends: array ==0.5.* , base >=4.7 && <5 , data-default >=0.7 && <1 , diagnose , dlist ==1.0.* , hashable >=1.3 && <2 , prettyprinter >=1.7.0 && <2 , prettyprinter-ansi-terminal >=1.1.2 && <2 , unordered-containers >=0.2.11 && <0.3 , wcwidth >=0.0.1 && <1 default-language: Haskell2010 if flag(json) cpp-options: -DUSE_AESON build-depends: aeson >=1.5 && <3 , bytestring >=0.9 && <1 if flag(megaparsec-compat) build-depends: containers ==0.6.* , megaparsec >=9.0.0 if flag(parsec-compat) build-depends: parsec >=3.1.14 ================================================ FILE: compiler/diagnose/hie.yaml ================================================ cradle: stack: - path: "./test/rendering" component: "diagnose:test:diagnose-rendering-tests" - path: "./test/megaparsec" component: "diagnose:test:diagnose-megaparsec-tests" - path: "./test/parsec" component: "diagnose:test:diagnose-parsec-tests" - path: "./src" component: "diagnose:lib" ================================================ FILE: compiler/diagnose/nix/nixpkgs-pinned.nix ================================================ import (builtins.fetchTarball { name = "nixpkgs-pinned"; url = "https://github.com/nixos/nixpkgs/archive/a7ecde854aee5c4c7cd6177f54a99d2c1ff28a31.tar.gz"; # Use `nix-prefetch-url --unpack ` sha256 = "162dywda2dvfj1248afxc45kcrg83appjd0nmdb541hl7rnncf02"; }) { } ================================================ FILE: compiler/diagnose/nix/stack.nix ================================================ { pkgs ? import ./nixpkgs-pinned.nix , ghc ? pkgs.ghc }: pkgs.haskell.lib.buildStackProject { inherit ghc; buildInputs = with pkgs; [ ]; name = "diagnose"; } ================================================ FILE: compiler/diagnose/package.yaml ================================================ name: diagnose version: 2.5.1 github: "mesabloo/diagnose" license: BSD3 author: "Ghilain Bergeron" copyright: "2021-2022 Ghilain Bergeron" category: "Error Reporting" dependencies: - base >= 4.7 && < 5 - array >= 0.5 && < 0.6 - data-default >= 0.7 && < 1 - dlist >= 1.0 && < 1.1 - hashable >= 1.3 && < 2 - prettyprinter >= 1.7.0 && < 2 - prettyprinter-ansi-terminal >= 1.1.2 && < 2 - unordered-containers >= 0.2.11 && < 0.3 - wcwidth >= 0.0.1 && <1 default-extensions: - OverloadedStrings - LambdaCase - BlockArguments library: source-dirs: src exposed-modules: - Error.Diagnose - Error.Diagnose.Diagnostic - Error.Diagnose.Position - Error.Diagnose.Pretty - Error.Diagnose.Report - Error.Diagnose.Style when: - condition: flag(megaparsec-compat) exposed-modules: - Error.Diagnose.Compat.Megaparsec - condition: flag(parsec-compat) exposed-modules: - Error.Diagnose.Compat.Parsec flags: json: description: "Allows exporting diagnostics as JSON. This is disabled by default as this relies on the very heavy dependency Aeson." manual: true default: false megaparsec-compat: description: "Includes a small compatibility layer (in the module `Error.Diagnose.Compat.Megaparsec`) to transform megaparsec errors into reports for this library." manual: true default: false parsec-compat: description: "Includes a small compatibility layer (in the module `Error.Diagnose.Compat.Parsec`) to transform parsec errors into reports for this library." manual: true default: false # do the same for other parsing libraries like parsec or attoparsec when: - condition: flag(json) dependencies: - aeson >= 1.5 && <3 - bytestring >= 0.9 && < 1 cpp-options: - -DUSE_AESON - condition: flag(megaparsec-compat) dependencies: - megaparsec >= 9.0.0 - containers == 0.6.* - condition: flag(parsec-compat) dependencies: - parsec >= 3.1.14 ghc-options: - -Wall - -Wextra # - -Wmissing-local-signatures # - -Wmonomorphism-restriction extra-source-files: - README.md tests: diagnose-rendering-tests: main: Spec.hs source-dirs: test/rendering ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N dependencies: - diagnose diagnose-megaparsec-tests: main: Spec.hs source-dirs: test/megaparsec ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N dependencies: - diagnose - text >= 1.2 && < 3 when: - condition: ! '!(flag(megaparsec-compat))' buildable: false diagnose-parsec-tests: main: Spec.hs source-dirs: test/parsec ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N dependencies: - diagnose - text >= 1.2 && < 3 when: - condition: ! '!(flag(parsec-compat))' buildable: false # This is put at the end for convenience. synopsis: Beautiful error reporting done easily description: | This package provides a simple way of getting beautiful compiler/interpreter errors using a very simple interface for the programmer. A quick tutorial is available in the module "Error.Diagnose", which goes on most of the basis of how to use it. ================================================ FILE: compiler/diagnose/src/Data/List/Safe.hs ================================================ module Data.List.Safe where import Data.Bifunctor (first) -- | Analogous to 'Data.List.last', but returns 'Nothing' on an empty list, instead of throwing an error. safeLast :: [a] -> Maybe a safeLast [] = Nothing safeLast l = Just $ last l -- | Analogous to `Data.List.head`, but returns 'Nothing' in case of an empty list. safeHead :: [a] -> Maybe a safeHead [] = Nothing safeHead (x : _) = Just x -- | Analogous tu 'Data.List.!!', but does not throw an error on missing index. safeIndex :: Int -> [a] -> Maybe a safeIndex _ [] = Nothing safeIndex 0 (x : _) = Just x safeIndex n (_ : xs) | n < 0 = Nothing | otherwise = safeIndex (n - 1) xs -- | Safely deconstructs a list from the end. -- -- More efficient than @(init x, last x)@ safeUnsnoc :: [a] -> Maybe ([a], a) safeUnsnoc [] = Nothing safeUnsnoc [x] = Just ([], x) safeUnsnoc (x : xs) = first (x :) <$> safeUnsnoc xs -- | Safely deconstructs a list from the beginning, returning 'Nothing' if the list is empty. safeUncons :: [a] -> Maybe (a, [a]) safeUncons [] = Nothing safeUncons (x : xs) = Just (x, xs) ================================================ FILE: compiler/diagnose/src/Error/Diagnose/Compat/Hints.hs ================================================ {-# LANGUAGE MultiParamTypeClasses #-} module Error.Diagnose.Compat.Hints where import Error.Diagnose (Note) -- | A class mapping custom errors of type @e@ with messages of type @msg@. class HasHints e msg where -- | Defines all the hints associated with a given custom error. hints :: e -> [Note msg] -- this is a sane default for 'Void' -- but this can be redefined -- -- instance HasHints Void msg where -- hints _ = mempty ================================================ FILE: compiler/diagnose/src/Error/Diagnose/Compat/Megaparsec.hs ================================================ {-# LANGUAGE BlockArguments #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-} {-# OPTIONS -Wno-name-shadowing #-} -- | -- Module : Error.Diagnose.Compat.Megaparsec -- Description : Compatibility layer for megaparsec -- Copyright : (c) Mesabloo, 2021-2022 -- License : BSD3 -- Stability : experimental -- Portability : Portable module Error.Diagnose.Compat.Megaparsec ( diagnosticFromBundle, errorDiagnosticFromBundle, warningDiagnosticFromBundle, module Error.Diagnose.Compat.Hints, ) where import Data.Bifunctor (second) import Data.Maybe (fromMaybe) import qualified Data.Set as Set (toList) import Data.String (IsString (..)) import Error.Diagnose import Error.Diagnose.Compat.Hints (HasHints (..)) import qualified Text.Megaparsec as MP -- | Transforms a megaparsec 'MP.ParseErrorBundle' into a well-formated 'Diagnostic' ready to be shown. diagnosticFromBundle :: forall msg s e. (IsString msg, MP.Stream s, HasHints e msg, MP.ShowErrorComponent e, MP.VisualStream s, MP.TraversableStream s) => -- | How to decide whether this is an error or a warning diagnostic (MP.ParseError s e -> Bool) -> -- | An optional error code Maybe msg -> -- | The error message of the diagnostic msg -> -- | Default hints when trivial errors are reported Maybe [Note msg] -> -- | The bundle to create a diagnostic from MP.ParseErrorBundle s e -> Diagnostic msg diagnosticFromBundle isError code msg (fromMaybe [] -> trivialHints) MP.ParseErrorBundle {..} = foldl addReport mempty (toLabeledPosition <$> bundleErrors) where toLabeledPosition :: MP.ParseError s e -> Report msg toLabeledPosition error = let (_, pos) = MP.reachOffset (MP.errorOffset error) bundlePosState source = fromSourcePos (MP.pstateSourcePos pos) msgs = fromString @msg <$> lines (MP.parseErrorTextPretty error) in flip (if isError error then Err code msg else Warn code msg) (errorHints error) if | [m] <- msgs -> [(source, This m)] | [m1, m2] <- msgs -> [(source, This m1), (source, Where m2)] | otherwise -> [(source, This $ fromString "<>")] fromSourcePos :: MP.SourcePos -> Position fromSourcePos MP.SourcePos {..} = let start = both (fromIntegral . MP.unPos) (sourceLine, sourceColumn) end = second (+ 1) start in Position start end sourceName errorHints :: MP.ParseError s e -> [Note msg] errorHints MP.TrivialError {} = trivialHints errorHints (MP.FancyError _ errs) = Set.toList errs >>= \case MP.ErrorCustom e -> hints e _ -> mempty -- | Creates an error diagnostic from a megaparsec 'MP.ParseErrorBundle'. errorDiagnosticFromBundle :: forall msg s e. (IsString msg, MP.Stream s, HasHints e msg, MP.ShowErrorComponent e, MP.VisualStream s, MP.TraversableStream s) => -- | An optional error code Maybe msg -> -- | The error message of the diagnostic msg -> -- | Default hints when trivial errors are reported Maybe [Note msg] -> -- | The bundle to create a diagnostic from MP.ParseErrorBundle s e -> Diagnostic msg errorDiagnosticFromBundle = diagnosticFromBundle (const True) -- | Creates a warning diagnostic from a megaparsec 'MP.ParseErrorBundle'. warningDiagnosticFromBundle :: forall msg s e. (IsString msg, MP.Stream s, HasHints e msg, MP.ShowErrorComponent e, MP.VisualStream s, MP.TraversableStream s) => -- | An optional error code Maybe msg -> -- | The error message of the diagnostic msg -> -- | Default hints when trivial errors are reported Maybe [Note msg] -> -- | The bundle to create a diagnostic from MP.ParseErrorBundle s e -> Diagnostic msg warningDiagnosticFromBundle = diagnosticFromBundle (const False) ------------------------------------ ------------ INTERNAL -------------- ------------------------------------ -- | Applies a computation to both element of a tuple. -- -- > both f = bimap @(,) f f both :: (a -> b) -> (a, a) -> (b, b) both f ~(x, y) = (f x, f y) ================================================ FILE: compiler/diagnose/src/Error/Diagnose/Compat/Parsec.hs ================================================ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ViewPatterns #-} {-# OPTIONS -Wno-name-shadowing #-} -- | -- Module : Error.Diagnose.Compat.Parsec -- Description : Compatibility layer for parsec -- Copyright : (c) Mesabloo, 2021-2022 -- License : BSD3 -- Stability : experimental -- Portability : Portable module Error.Diagnose.Compat.Parsec ( diagnosticFromParseError, errorDiagnosticFromParseError, warningDiagnosticFromParseError, module Error.Diagnose.Compat.Hints, ) where import Data.Bifunctor (second) import Data.List (intercalate, nub) import Data.Maybe (fromMaybe) import Data.String (IsString (..)) import Data.Void (Void) import Error.Diagnose import Error.Diagnose.Compat.Hints (HasHints (..)) import qualified Text.Parsec.Error as PE import qualified Text.Parsec.Pos as PP -- | Generates a diagnostic from a 'PE.ParseError'. diagnosticFromParseError :: forall msg. (IsString msg, HasHints Void msg) => -- | Determine whether the diagnostic is an error or a warning (PE.ParseError -> Bool) -> -- | An optional error code Maybe msg -> -- | The main error of the diagnostic msg -> -- | Default hints Maybe [Note msg] -> -- | The 'PE.ParseError' to transform into a 'Diagnostic' PE.ParseError -> Diagnostic msg diagnosticFromParseError isError code msg (fromMaybe [] -> defaultHints) error = let pos = fromSourcePos $ PE.errorPos error markers = toMarkers pos $ PE.errorMessages error report = (if isError error then Err code msg else Warn code msg) markers (defaultHints <> hints (undefined :: Void)) in addReport mempty report where fromSourcePos :: PP.SourcePos -> Position fromSourcePos pos = let start = both fromIntegral (PP.sourceLine pos, PP.sourceColumn pos) end = second (+ 1) start in Position start end (PP.sourceName pos) toMarkers :: Position -> [PE.Message] -> [(Position, Marker msg)] toMarkers source [] = [(source, This $ fromString "<>")] toMarkers source msgs = let putTogether [] = ([], [], [], []) putTogether (PE.SysUnExpect thing : ms) = let (a, b, c, d) = putTogether ms in (thing : a, b, c, d) putTogether (PE.UnExpect thing : ms) = let (a, b, c, d) = putTogether ms in (a, thing : b, c, d) putTogether (PE.Expect thing : ms) = let (a, b, c, d) = putTogether ms in (a, b, thing : c, d) putTogether (PE.Message thing : ms) = let (a, b, c, d) = putTogether ms in (a, b, c, thing : d) (nub -> sysUnexpectedList, nub -> unexpectedList, nub -> expectedList, nub -> messages) = putTogether msgs firstSysUnexpectedMessage = head sysUnexpectedList unexpectedMessage = "unexpected " <> if null unexpectedList then if null firstSysUnexpectedMessage then "end of line" else firstSysUnexpectedMessage else intercalate ", " (filter (not . null) unexpectedList) in [ (source, This $ fromString unexpectedMessage) ] <> [ (source, This $ fromString msg) | msg <- messages ] <> [ (source, Where $ fromString $ "expecting any of " <> intercalate ", " (filter (not . null) expectedList)) ] -- | Generates an error diagnostic from a 'PE.ParseError'. errorDiagnosticFromParseError :: forall msg. (IsString msg, HasHints Void msg) => -- | An optional error code Maybe msg -> -- | The main error message of the diagnostic msg -> -- | Default hints Maybe [Note msg] -> -- | The 'PE.ParseError' to convert PE.ParseError -> Diagnostic msg errorDiagnosticFromParseError = diagnosticFromParseError (const True) -- | Generates a warning diagnostic from a 'PE.ParseError'. warningDiagnosticFromParseError :: forall msg. (IsString msg, HasHints Void msg) => -- | An optional error code Maybe msg -> -- | The main error message of the diagnostic msg -> -- | Default hints Maybe [Note msg] -> -- | The 'PE.ParseError' to convert PE.ParseError -> Diagnostic msg warningDiagnosticFromParseError = diagnosticFromParseError (const False) ------------------------------------ ------------ INTERNAL -------------- ------------------------------------ -- | Applies a computation to both element of a tuple. -- -- > both f = bimap @(,) f f both :: (a -> b) -> (a, a) -> (b, b) both f ~(x, y) = (f x, f y) ================================================ FILE: compiler/diagnose/src/Error/Diagnose/Diagnostic/Internal.hs ================================================ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleInstances #-} -- | -- Module : Error.Diagnose.Diagnostic.Internal -- Description : Internal workings for diagnostic definitions and pretty printing. -- Copyright : (c) Mesabloo, 2021-2022 -- License : BSD3 -- Stability : experimental -- Portability : Portable -- -- /Warning/: The API of this module can break between two releases, therefore you should not rely on it. -- It is also highly undocumented. -- -- Please limit yourself to the "Error.Diagnose.Diagnostic" module, which exports some of the useful functions defined here. module Error.Diagnose.Diagnostic.Internal (module Error.Diagnose.Diagnostic.Internal, WithUnicode(..), TabSize(..)) where import Control.Monad.IO.Class (MonadIO, liftIO) #ifdef USE_AESON import Data.Aeson (ToJSON(..), encode, object, (.=)) import Data.ByteString.Lazy (ByteString) #endif import Data.Array (listArray) import Data.DList (DList) import qualified Data.DList as DL import Data.Foldable (fold, toList) import qualified Data.HashMap.Lazy as HashMap import Data.List (intersperse) import Error.Diagnose.Report (Report) import Error.Diagnose.Report.Internal (FileMap, errorToWarning, prettyReport, warningToError, WithUnicode(..), TabSize(..)) import Error.Diagnose.Style (Annotation, Style) import Prettyprinter (Doc, Pretty, hardline, pretty, defaultLayoutOptions, reAnnotateS, layoutPretty) import Prettyprinter.Render.Terminal (renderIO) import System.IO (Handle) -- | The data type for diagnostic containing messages of an abstract type. -- -- Users can use 'mempty' to create a new empty diagnostic, and 'addFile' and -- 'addReport' to alter its internal state. data Diagnostic msg = Diagnostic (DList (Report msg)) -- ^ All the reports contained in a diagnostic. -- -- Reports are output one by one, without connections in between. !FileMap -- ^ A map associating files with their content as lists of lines. deriving (Functor, Foldable, Traversable) instance Monoid (Diagnostic msg) where mempty = Diagnostic mempty mempty instance Semigroup (Diagnostic msg) where Diagnostic rs1 files1 <> Diagnostic rs2 files2 = Diagnostic (rs1 <> rs2) (files1 <> files2) #ifdef USE_AESON instance ToJSON msg => ToJSON (Diagnostic msg) where toJSON (Diagnostic reports files) = object [ "files" .= fmap toJSONFile (fmap toList <$> (HashMap.toList files)) , "reports" .= reports ] where toJSONFile (path, content) = object [ "name" .= path , "content" .= content ] #endif -- | Checks whether the given diagnostic has any report or not (if it is effectively empty). hasReports :: Diagnostic msg -> Bool hasReports (Diagnostic DL.Nil _) = False hasReports _ = True -- | Retrieves the reports for this diagnostic. reportsOf :: Diagnostic msg -> [Report msg] reportsOf (Diagnostic reports _) = toList reports -- | Transforms every warning report in this diagnostic into an error report. warningsToErrors :: Diagnostic msg -> Diagnostic msg warningsToErrors (Diagnostic reports files) = Diagnostic (warningToError <$> reports) files -- | Transforms every error report in this diagnostic into a warning report. errorsToWarnings :: Diagnostic msg -> Diagnostic msg errorsToWarnings (Diagnostic reports files) = Diagnostic (errorToWarning <$> reports) files -- | Pretty prints a 'Diagnostic' into a 'Doc'ument that can be output using 'hPutDoc'. -- -- Colors are put by default. -- If you do not want these, just 'unAnnotate' the resulting document like so: -- -- >>> let doc = unAnnotate (prettyDiagnostic withUnicode tabSize diagnostic) -- -- Changing the style is also rather easy: -- -- >>> let myCustomStyle :: Style = _ -- >>> let doc = myCustomStyle (prettyDiagnostic withUnicode tabSize diagnostic) prettyDiagnostic :: Pretty msg => -- | Should we use unicode when printing paths? WithUnicode -> -- | The number of spaces each TAB character will span. TabSize -> -- | The diagnostic to print. Diagnostic msg -> Doc (Annotation ann) prettyDiagnostic withUnicode tabSize = prettyDiagnostic' withUnicode tabSize . fmap pretty {-# INLINE prettyDiagnostic #-} -- | Like 'prettyDiagnostic' except that instead of requiring a 'pretty' -- instance for messages, this allows passing in your own 'Doc'. Custom -- annotations are retained in 'OtherStyle' prettyDiagnostic' :: -- | Should we use unicode when printing paths? WithUnicode -> -- | The number of spaces each TAB character will span. TabSize -> -- | The diagnostic to print. Diagnostic (Doc ann) -> Doc (Annotation ann) prettyDiagnostic' withUnicode tabSize (Diagnostic reports file) = fold . intersperse hardline $ prettyReport file withUnicode tabSize <$> toList reports -- | Prints a 'Diagnostic' onto a specific 'Handle'. printDiagnostic :: (MonadIO m, Pretty msg) => -- | The handle onto which to output the diagnostic. Handle -> -- | Should we print with unicode characters? WithUnicode -> -- | The number of spaces each TAB character will span. TabSize -> -- | The style in which to output the diagnostic. Style ann -> -- | The diagnostic to output. Diagnostic msg -> m () printDiagnostic handle withUnicode tabSize style = printDiagnostic' handle withUnicode tabSize style . fmap pretty {-# INLINE printDiagnostic #-} -- | Like 'printDiagnostic' except that instead of requiring a 'pretty' -- instance for messages, this allows passing in your own 'Doc'. printDiagnostic' :: MonadIO m => -- | The handle onto which to output the diagnostic. Handle -> -- | Should we print with unicode characters? WithUnicode -> -- | The number of spaces each TAB character will span. TabSize -> -- | The style in which to output the diagnostic. Style ann -> -- | The diagnostic to output. Diagnostic (Doc ann) -> m () printDiagnostic' handle withUnicode tabSize style = liftIO . renderIO handle . reAnnotateS style . layoutPretty defaultLayoutOptions . prettyDiagnostic' withUnicode tabSize -- | Inserts a new referenceable file within the diagnostic. addFile :: Diagnostic msg -> -- | The path to the file. FilePath -> -- | The content of the file as a single string, where lines are ended by @\\n@. String -> Diagnostic msg addFile (Diagnostic reports files) path content = let fileLines = lines content lineCount = length fileLines lineArray = listArray (0, lineCount - 1) fileLines in Diagnostic reports (HashMap.insert path lineArray files) {-# INLINE addFile #-} -- | Inserts a new report into a diagnostic. addReport :: Diagnostic msg -> -- | The new report to add to the diagnostic. Report msg -> Diagnostic msg addReport (Diagnostic reports files) report = Diagnostic (reports `DL.snoc` report) files {-# INLINE addReport #-} #ifdef USE_AESON -- | Creates a JSON object from a diagnostic, containing those fields (only types are indicated): -- -- > { files: -- > { name: string -- > , content: string[] -- > }[] -- > , reports: -- > { kind: 'error' | 'warning' -- > , code: T? -- > , message: T -- > , markers: -- > { kind: 'this' | 'where' | 'maybe' -- > , position: -- > { beginning: { line: int, column: int } -- > , end: { line: int, column: int } -- > , file: string -- > } -- > , message: T -- > }[] -- > , hints: ({ note: T } | { hint: T })[] -- > }[] -- > } -- -- where @T@ is the type of the JSON representation for the @msg@ type variable. diagnosticToJson :: ToJSON msg => Diagnostic msg -> ByteString diagnosticToJson = encode #endif ================================================ FILE: compiler/diagnose/src/Error/Diagnose/Diagnostic.hs ================================================ {-# LANGUAGE CPP #-} -- | -- Module : Error.Diagnose.Diagnostic -- Description : Diagnostic definition and pretty printing -- Copyright : (c) Mesabloo, 2021-2022 -- License : BSD3 -- Stability : experimental -- Portability : Portable module Error.Diagnose.Diagnostic ( -- * Re-exports module Export, ) where import Error.Diagnose.Diagnostic.Internal as Export ( Diagnostic, #ifdef USE_AESON diagnosticToJson, #endif addFile, addReport, errorsToWarnings, hasReports, reportsOf, prettyDiagnostic, prettyDiagnostic', printDiagnostic, printDiagnostic', warningsToErrors, WithUnicode(..), TabSize(..), ) import System.IO as Export (stderr, stdout) ================================================ FILE: compiler/diagnose/src/Error/Diagnose/Position.hs ================================================ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeApplications #-} -- | -- Module : Error.Diagnose.Diagnostic -- Description : Defines location information as a simple record. -- Copyright : (c) Mesabloo, 2021-2022 -- License : BSD3 -- Stability : experimental -- Portability : Portable module Error.Diagnose.Position (Position (..)) where #ifdef USE_AESON import Data.Aeson (ToJSON(..), object, (.=)) #endif import Data.Default (Default, def) import Data.Hashable (Hashable) import GHC.Generics (Generic (..)) import Prettyprinter (Pretty (..), colon) -- import Text.PrettyPrint.ANSI.Leijen (Pretty(..), text, colon, int) -- | Contains information about the location of something. -- -- It is best used in a datatype like: -- -- > data Located a -- > = a :@ Position -- > deriving (Show, Eq, Ord, Functor, Traversable) -- -- Columns are specified in amount of Unicode codepoints from the beginning of the line. -- Lines and columns start at 1. data Position = Position { -- | The beginning line and column of the span. begin :: (Int, Int), -- | The end line and column of the span. end :: (Int, Int), -- | The file this position spans in. file :: FilePath } deriving (Show, Eq, Ord, Generic) instance Pretty Position where pretty (Position (bl, bc) (el, ec) f) = pretty f <> at <> pretty bl <> colon <> pretty bc <> dash <> pretty el <> colon <> pretty ec where at = pretty @String "@" dash = pretty @String "-" instance Hashable Position instance Default Position where def = Position (1, 1) (1, 1) "" #ifdef USE_AESON instance ToJSON Position where toJSON (Position (bl, bc) (el, ec) file) = object [ "beginning" .= object [ "line" .= bl, "column" .= bc ] , "end" .= object [ "line" .= el, "column" .= ec ] , "file" .= file ] #endif ================================================ FILE: compiler/diagnose/src/Error/Diagnose/Pretty.hs ================================================ module Error.Diagnose.Pretty (module Export) where import qualified Prettyprinter as Export ================================================ FILE: compiler/diagnose/src/Error/Diagnose/Report/Internal.hs ================================================ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE PatternSynonyms #-} {-# OPTIONS -Wno-name-shadowing #-} -- | -- Module : Error.Diagnose.Report.Internal -- Description : Internal workings for report definitions and pretty printing. -- Copyright : (c) Mesabloo, 2021-2022 -- License : BSD3 -- Stability : experimental -- Portability : Portable -- -- /Warning/: The API of this module can break between two releases, therefore you should not rely on it. -- It is also highly undocumented. -- -- Please limit yourself to the "Error.Diagnose.Report" module, which exports some of the useful functions defined here. module Error.Diagnose.Report.Internal ( module Error.Diagnose.Report.Internal , Report(.., Warn, Err) , WithUnicode(..) , TabSize(..) ) where #ifdef USE_AESON import Data.Aeson (ToJSON(..), object, (.=)) #endif import Control.Applicative ((<|>)) import qualified Data.Array.IArray as Array import Data.Array.Unboxed (Array, IArray, Ix, UArray, listArray, (!)) import Data.Bifunctor (bimap, first, second) import Data.Char.WCWidth (wcwidth) import Data.Default (def) import Data.Foldable (fold) import Data.Function (on) import Data.Functor ((<&>), void) import Data.HashMap.Lazy (HashMap) import qualified Data.HashMap.Lazy as HashMap import qualified Data.List as List import qualified Data.List.Safe as List import Data.Maybe import Data.String (IsString (fromString)) import Error.Diagnose.Position import Error.Diagnose.Style (Annotation (..)) import Prettyprinter (Doc, Pretty (..), align, annotate, colon, hardline, lbracket, rbracket, space, width, (<+>), reAnnotate, SimpleDocStream (..), layoutCompact) import Prettyprinter.Internal (Doc (..), textSpaces) import Data.Bool (bool) type FileMap = HashMap FilePath (Array Int String) type WidthTable = UArray Int Int -- | The type of diagnostic reports with abstract message type. data Report msg = Report Bool -- ^ Is the report a warning or an error? (Maybe msg) -- ^ An optional error code to print at the top. msg -- ^ The message associated with the error. [(Position, Marker msg)] -- ^ A map associating positions with marker to show under the source code. [Note msg] -- ^ A list of notes to add at the end of the report. deriving (Functor, Foldable, Traversable) -- | Pattern synonym for a warning report. pattern Warn :: Maybe msg -> msg -> [(Position, Marker msg)] -> [Note msg] -> Report msg pattern Warn errCode msg reports notes = Report False errCode msg reports notes -- | Pattern synonym for an error report. pattern Err :: Maybe msg -> msg -> [(Position, Marker msg)] -> [Note msg] -> Report msg pattern Err errCode msg reports notes = Report True errCode msg reports notes {-# COMPLETE Warn, Err #-} instance Semigroup msg => Semigroup (Report msg) where Report isError1 code1 msg1 pos1 hints1 <> Report isError2 code2 msg2 pos2 hints2 = Report (isError1 || isError2) (code1 <|> code2) (msg1 <> msg2) (pos1 <> pos2) (hints1 <> hints2) instance Monoid msg => Monoid (Report msg) where mempty = Report False Nothing mempty mempty mempty #ifdef USE_AESON instance ToJSON msg => ToJSON (Report msg) where toJSON (Report isError code msg markers hints) = object [ "kind" .= (if isError then "error" else "warning" :: String) , "code" .= code , "message" .= msg , "markers" .= fmap showMarker markers , "hints" .= hints ] where showMarker (pos, marker) = object $ [ "position" .= pos ] <> case marker of This m -> [ "message" .= m , "kind" .= ("this" :: String) ] Where m -> [ "message" .= m , "kind" .= ("where" :: String) ] Maybe m -> [ "message" .= m , "kind" .= ("maybe" :: String) ] Blank -> [ "kind" .= ("blank" :: String) ] #endif -- | The type of markers with abstract message type, shown under code lines. data Marker msg = -- | A red or yellow marker under source code, marking important parts of the code. This msg | -- | A blue marker symbolizing additional information. Where msg | -- | A magenta marker to report potential fixes. Maybe msg | -- | An empty marker, whose sole purpose is to include a line of code in the report without markers under. Blank deriving (Eq, Ord, Functor, Foldable, Traversable) isBlank :: Marker msg -> Bool isBlank = \case Blank -> True _ -> False -- | A note is a piece of information that is found at the end of a report. data Note msg = -- | A note, which is meant to give valuable information related to the encountered error. Note msg | -- | A hint, to propose potential fixes or help towards fixing the issue. Hint msg deriving (Eq, Ord, Show, Functor, Foldable, Traversable) #ifdef USE_AESON instance ToJSON msg => ToJSON (Note msg) where toJSON (Note msg) = object [ "note" .= msg ] toJSON (Hint msg) = object [ "hint" .= msg ] #endif -- | Constructs a 'Note' from the given message as a literal string. instance IsString msg => IsString (Note msg) where fromString = Note . fromString -- | Constructs a warning or an error report. warn, err :: -- | An optional error code to be shown right next to "error" or "warning". Maybe msg -> -- | The report message, shown at the very top. msg -> -- | A list associating positions with markers. [(Position, Marker msg)] -> -- | A possibly mempty list of hints to add at the end of the report. [Note msg] -> Report msg warn = Report False {-# INLINE warn #-} {-# DEPRECATED warn "'warn' is deprecated. Use 'Warn' instead." #-} err = Report True {-# INLINE err #-} {-# DEPRECATED err "'err' is deprecated. Use 'Err' instead." #-} -- | Transforms a warning report into an error report. warningToError :: Report msg -> Report msg warningToError (Report False code msg markers notes) = Report True code msg markers notes warningToError r@(Report True _ _ _ _) = r -- | Transforms an error report into a warning report. errorToWarning :: Report msg -> Report msg errorToWarning (Report True code msg markers notes) = Report False code msg markers notes errorToWarning r@(Report False _ _ _ _) = r data WithUnicode = WithoutUnicode | WithUnicode newtype TabSize = TabSize Int -- | Pretty prints a report to a 'Doc' handling colors. prettyReport :: -- | The content of the file the reports are for FileMap -> -- | Should we print paths in unicode? WithUnicode -> -- | The number of spaces each TAB character will span TabSize -> -- | The whole report to output Report (Doc ann) -> Doc (Annotation ann) prettyReport fileContent withUnicode tabSize (Report isError code message markers hints) = let sortedMarkers = List.sortOn (fst . begin . fst) markers -- sort the markers so that the first lines of the reports are the first lines of the file groupedMarkers = groupMarkersPerFile sortedMarkers -- group markers by the file they appear in, and put `This` markers at the top of the report maxLineNumberLength = maybe 3 (max 3 . length . show . fst . end . fst) $ List.safeLast markers -- if there are no markers, then default to 3, else get the maximum between 3 and the length of the last marker header = annotate (KindColor isError) ( lbracket <> ( if isError then "error" else "warning" ) <> case code of Nothing -> rbracket Just code -> space <> annotated code <> rbracket ) in {- A report is of the form: (1) [error|warning]: (2) +--> (3) : (4) | : : (5) : : (6) -------+ -} {- (1) -} header <> colon <+> align (annotated message) <> {- (2), (3), (4) -} fold (uncurry (prettySubReport fileContent withUnicode isError tabSize maxLineNumberLength) <$> groupedMarkers) <> {- (5) -} ( if | null hints && null markers -> mempty | null hints -> mempty | otherwise -> hardline <+> dotPrefix maxLineNumberLength withUnicode ) <> prettyAllHints hints maxLineNumberLength withUnicode <> hardline <> {- (6) -} ( if null markers && null hints then mempty else annotate RuleColor (pad (maxLineNumberLength + 2) (unicode '-' '─' withUnicode) mempty <> unicode "+" "╯" withUnicode) <> hardline ) ------------------------------------------------------------------------------------- ----- INTERNAL STUFF ---------------------------------------------------------------- ------------------------------------------------------------------------------------- -- | Inserts a given number of character after a 'Doc'ument. pad :: Int -> Char -> Doc ann -> Doc ann pad n c d = width d \w -> pretty $ replicate (n - w) c -- | Creates a "dot"-prefix for a report line where there is no code. -- -- Pretty printing yields those results: -- -- [with unicode] "@␣␣␣␣␣•␣@" -- [without unicode] "@␣␣␣␣␣:␣@" dotPrefix :: -- | The length of the left space before the bullet. Int -> -- | Whether to print with unicode characters or not. WithUnicode -> Doc (Annotation ann) dotPrefix leftLen withUnicode = pad leftLen ' ' mempty <+> annotate RuleColor (unicode ":" "•" withUnicode) {-# INLINE dotPrefix #-} -- | Creates a "pipe"-prefix for a report line where there is no code. -- -- Pretty printing yields those results: -- -- [with unicode] "@␣␣␣␣␣│␣@" -- [without unicode] "@␣␣␣␣␣|␣@" pipePrefix :: -- | The length of the left space before the pipe. Int -> -- | Whether to print with unicode characters or not. WithUnicode -> Doc (Annotation ann) pipePrefix leftLen withUnicode = pad leftLen ' ' mempty <+> annotate RuleColor (unicode "|" "│" withUnicode) {-# INLINE pipePrefix #-} -- | Creates a line-prefix for a report line containing source code -- -- Pretty printing yields those results: -- -- [with unicode] "@␣␣␣3␣│␣@" -- [without unicode] "@␣␣␣3␣|␣@" -- -- Results may be different, depending on the length of the line number. linePrefix :: -- | The length of the amount of space to span before the vertical bar. Int -> -- | The line number to show. Int -> -- | Whether to use unicode characters or not. WithUnicode -> Doc (Annotation ann) linePrefix leftLen lineNo withUnicode = let lineNoLen = length (show lineNo) in annotate RuleColor $ mempty <+> pad (leftLen - lineNoLen) ' ' mempty <> pretty lineNo <+> unicode "|" "│" withUnicode {-# INLINE linePrefix #-} -- | Creates an ellipsis-prefix, when some line numbers are not consecutive. -- -- Pretty printing yields those results: -- -- [with unicode] "@␣␣␣␣␣⋮␣@" -- [without unicode] "@␣␣␣␣...@" ellipsisPrefix :: Int -> WithUnicode -> Doc (Annotation ann) ellipsisPrefix leftLen withUnicode = pad leftLen ' ' mempty <> annotate RuleColor (unicode "..." (space <> "⋮") withUnicode) groupMarkersPerFile :: [(Position, Marker msg)] -> [(Bool, [(Position, Marker msg)])] groupMarkersPerFile [] = [] groupMarkersPerFile markers = let markersPerFile = List.foldl' (HashMap.unionWith (<>)) mempty $ markers <&> \tup@(p, _) -> HashMap.singleton (file p) [tup] in -- put all markers on the same file together -- NOTE: it's a shame that `HashMap.unionsWith f = foldl' (HashMap.unionWith f) mempty` does not exist onlyFirstToTrue $ putThisMarkersAtTop $ HashMap.elems markersPerFile where onlyFirstToTrue = go True [] go _ acc [] = reverse acc go t acc (x : xs) = go False ((t, x) : acc) xs putThisMarkersAtTop = List.sortBy \ms1 ms2 -> if | any isThisMarker (snd <$> ms1) -> LT | any isThisMarker (snd <$> ms2) -> GT | otherwise -> EQ -- | Prettyprint a sub-report, which is a part of the report spanning across a single file prettySubReport :: -- | The content of files in the diagnostics FileMap -> -- | Is the output done with Unicode characters? WithUnicode -> -- | Is the current report an error report? Bool -> -- | The number of spaces each TAB character will span TabSize -> -- | The size of the biggest line number Int -> -- | Is this sub-report the first one in the list? Bool -> -- | The list of line-ordered markers appearing in a single file [(Position, Marker (Doc ann))] -> Doc (Annotation ann) prettySubReport fileContent withUnicode isError tabSize maxLineNumberLength isFirst markers = let (markersPerLine, multilineMarkers) = splitMarkersPerLine markers -- split the list on whether markers are multiline or not sortedMarkersPerLine = {- second (List.sortOn (first $ snd . begin)) <$> -} List.sortOn fst (HashMap.toList markersPerLine) reportFile = maybe (pretty @Position def) (pretty . fst) $ List.safeHead (List.sortOn (void . snd) markers) -- the reported file is the file of the first 'This' marker (only one must be present) allLineNumbers = List.sort $ List.nub $ (fst <$> sortedMarkersPerLine) <> (multilineMarkers >>= \(Position (bl, _) (el, _) _, _) -> [bl .. el]) fileMarker = ( if isFirst then space <> pad maxLineNumberLength ' ' mempty <+> annotate RuleColor (unicode "+-->" "╭──▶" withUnicode) else space <> dotPrefix maxLineNumberLength withUnicode <> hardline <> annotate RuleColor (pad (maxLineNumberLength + 2) (unicode '-' '─' withUnicode) mempty) <> annotate RuleColor (unicode "+-->" "┼──▶" withUnicode) ) <+> annotate FileColor reportFile in {- (2) -} hardline <> fileMarker <> hardline <+> {- (3) -} {- (3) -} pipePrefix maxLineNumberLength withUnicode <> {- (4) -} prettyAllLines fileContent withUnicode isError tabSize maxLineNumberLength sortedMarkersPerLine multilineMarkers allLineNumbers isThisMarker :: Marker msg -> Bool isThisMarker (This _) = True isThisMarker _ = False -- | splitMarkersPerLine :: [(Position, Marker msg)] -> (HashMap Int [(Position, Marker msg)], [(Position, Marker msg)]) splitMarkersPerLine [] = (mempty, mempty) splitMarkersPerLine (m@(Position {..}, _) : ms) = let (bl, _) = begin (el, _) = end in (if bl == el then first (HashMap.insertWith (<>) bl [m]) else second (m :)) (splitMarkersPerLine ms) -- | prettyAllLines :: FileMap -> WithUnicode -> Bool -> -- | The number of spaces each TAB character will span TabSize -> Int -> [(Int, [(Position, Marker (Doc ann))])] -> [(Position, Marker (Doc ann))] -> [Int] -> Doc (Annotation ann) prettyAllLines files withUnicode isError tabSize leftLen inline multiline lineNumbers = case lineNumbers of [] -> showMultiline True multiline [l] -> let (ms, doc) = showForLine True l in doc <> prettyAllLines files withUnicode isError tabSize leftLen inline ms [] l1 : l2 : ls -> let (ms, doc) = showForLine False l1 in doc <> (if l2 /= l1 + 1 then hardline <+> dotPrefix leftLen withUnicode else mempty) <> prettyAllLines files withUnicode isError tabSize leftLen inline ms (l2 : ls) where showForLine isLastLine line = {- A line of code is composed of: (1) | (2) : (3) : Multline markers may also take additional space (2 characters) on the right of the bar -} let allInlineMarkersInLine = snd =<< filter ((==) line . fst) inline allMultilineMarkersInLine = flip filter multiline \(Position (bl, _) (el, _) _, _) -> bl == line || el == line allMultilineMarkersSpanningLine = flip filter multiline \(Position (bl, _) (el, _) _, _) -> bl < line && el > line inSpanOfMultiline = flip any multiline \(Position (bl, _) (el, _) _, _) -> bl <= line && el >= line colorOfFirstMultilineMarker = maybe id (annotate . markerColor isError . snd) (List.safeHead $ allMultilineMarkersInLine <> allMultilineMarkersSpanningLine) -- take the first multiline marker to color the entire line, if there is one (multilineEndingOnLine, otherMultilines) = flip List.partition multiline \(Position _ (el, _) _, _) -> el == line shouldShowMultiLine = isLastLine || ((==) `on` fmap (fmap void)) (List.safeLast multilineEndingOnLine) (List.safeLast multiline) !additionalPrefix = case allMultilineMarkersInLine of [] -> if not $ null multiline then if not $ null allMultilineMarkersSpanningLine then colorOfFirstMultilineMarker (unicode "| " "│ " withUnicode) else " " else mempty (p@(Position _ (el, _) _), marker) : _ -> let hasPredecessor = el == line || maybe False ((/=) p . fst . fst) (List.safeUncons multiline) in colorOfFirstMultilineMarker (unicode (bool "+" "|" hasPredecessor ) (bool "╭" "├" hasPredecessor) withUnicode) <> annotate (markerColor isError marker) (unicode ">" "┤" withUnicode) <> space -- we need to remove all blank markers because they are irrelevant to the display allInlineMarkersInLine' = filter (not . isBlank . snd) allInlineMarkersInLine allMultilineMarkersSpanningLine' = filter (not . isBlank . snd) allMultilineMarkersSpanningLine (widths, renderedCode) = getLine_ files (allInlineMarkersInLine <> allMultilineMarkersInLine <> allMultilineMarkersSpanningLine') line tabSize isError in ( otherMultilines, hardline <> {- (1) -} linePrefix leftLen line withUnicode <+> additionalPrefix <> renderedCode <> {- (2) -} showAllMarkersInLine (not $ null multiline) inSpanOfMultiline colorOfFirstMultilineMarker withUnicode isError leftLen widths allInlineMarkersInLine' <> showMultiline shouldShowMultiLine multilineEndingOnLine ) showMultiline _ [] = mempty showMultiline isLastMultiline multiline = let colorOfFirstMultilineMarker = markerColor isError . snd <$> List.safeHead multiline -- take the color of the last multiline marker in case we need to add additional bars prefix = space <> dotPrefix leftLen withUnicode <> space prefixWithBar color = prefix <> maybe id annotate color (unicode "| " "│ " withUnicode) showMultilineMarkerMessage (_, Blank) _ = mempty showMultilineMarkerMessage (_, marker) isLast = annotate (markerColor isError marker) $ ( if isLast && isLastMultiline then unicode "`- " "╰╸ " withUnicode else unicode "|- " "├╸ " withUnicode ) <> replaceLinesWith (if isLast then prefix <> " " else prefixWithBar (Just $ markerColor isError marker) <> space) 0 (annotated $ markerMessage marker) showMultilineMarkerMessages [] = [] showMultilineMarkerMessages [m] = [showMultilineMarkerMessage m True] showMultilineMarkerMessages (m : ms) = showMultilineMarkerMessage m False : showMultilineMarkerMessages ms in hardline <> prefixWithBar colorOfFirstMultilineMarker <> hardline <> prefix <> fold (List.intersperse (hardline <> prefix) $ showMultilineMarkerMessages multiline) -- | getLine_ :: FileMap -> [(Position, Marker msg)] -> Int -> TabSize -> Bool -> (WidthTable, Doc (Annotation ann)) getLine_ files markers line (TabSize tabSize) isError = case safeArrayIndex (line - 1) =<< (HashMap.!?) files . file . fst =<< List.safeHead markers of Nothing -> ( mkWidthTable "", annotate NoLineColor "" ) Just code -> ( mkWidthTable code, flip foldMap (zip [1 ..] code) \(n, c) -> let cdoc = ifTab (pretty (replicate tabSize ' ')) pretty c colorizingMarkers = flip filter markers \case (Position (bl, bc) (el, ec) _, _) | bl == el -> n >= bc && n < ec | otherwise -> (bl == line && n >= bc) || (el == line && n < ec) || (bl < line && el > line) in maybe (annotate CodeStyle) ((\m -> annotate (MarkerStyle $ markerColor isError m)) . snd) (List.safeHead colorizingMarkers) cdoc ) where ifTab :: a -> (Char -> a) -> Char -> a ifTab a _ '\t' = a ifTab _ f c = f c mkWidthTable :: String -> WidthTable mkWidthTable s = listArray (1, length s) (ifTab tabSize wcwidth <$> s) -- | showAllMarkersInLine :: Bool -> Bool -> (Doc (Annotation ann) -> Doc (Annotation ann)) -> WithUnicode -> Bool -> Int -> WidthTable -> [(Position, Marker (Doc ann))] -> Doc (Annotation ann) showAllMarkersInLine _ _ _ _ _ _ _ [] = mempty showAllMarkersInLine hasMultilines inSpanOfMultiline colorMultilinePrefix withUnicode isError leftLen widths ms = let maxMarkerColumn = snd $ end $ fst $ List.last $ List.sortOn (snd . end . fst) ms specialPrefix | inSpanOfMultiline = colorMultilinePrefix (unicode "| " "│ " withUnicode) <> space | hasMultilines = colorMultilinePrefix " " <> space | otherwise = mempty in -- get the maximum end column, so that we know when to stop looking for other markers on the same line hardline <+> dotPrefix leftLen withUnicode <+> (if List.null ms then mempty else specialPrefix <> showMarkers 1 maxMarkerColumn <> showMessages specialPrefix ms maxMarkerColumn) where widthAt i = 0 `fromMaybe` safeArrayIndex i widths widthsBetween start end = sum $ take (end - start) $ drop (start - 1) $ Array.elems widths showMarkers n lineLen | n > lineLen = mempty -- reached the end of the line | otherwise = let allMarkers = flip filter ms \(Position (_, bc) (_, ec) _, mark) -> not (isBlank mark) && n >= bc && n < ec in -- only consider markers which span onto the current column case allMarkers of [] -> fold (replicate (widthAt n) space) <> showMarkers (n + 1) lineLen (Position {..}, marker) : _ -> annotate (markerColor isError marker) ( if snd begin == n then unicode "^" "┬" withUnicode <> fold (replicate (widthAt n - 1) (unicode "-" "─" withUnicode)) else fold (replicate (widthAt n) (unicode "-" "─" withUnicode)) ) <> showMarkers (n + 1) lineLen showMessages specialPrefix ms lineLen = case List.safeUncons ms of Nothing -> mempty -- no more messages to show Just ((Position b@(_, bc) _ _, msg), pipes) -> let filteredPipes = filter (uncurry (&&) . bimap ((/= b) . begin) (not . isBlank)) pipes -- record only the pipes corresponding to markers on different starting positions nubbedPipes = List.nubBy ((==) `on` (begin . fst)) filteredPipes -- and then remove all duplicates allColumns _ [] = (1, []) allColumns n ms@((Position (_, bc) _ _, col) : ms') | n == bc = bimap (+ 1) (col :) (allColumns (n + 1) ms') | n < bc = bimap (+ 1) (replicate (widthAt n) space <>) (allColumns (n + 1) ms) | otherwise = bimap (+ 1) (replicate (widthAt n) space <>) (allColumns (n + 1) ms') -- transform the list of remaining markers into a single document line hasSuccessor = length filteredPipes /= length pipes lineStart pipes = let (n, docs) = allColumns 1 $ List.sortOn (snd . begin . fst) pipes numberOfSpaces = widthsBetween n bc in dotPrefix leftLen withUnicode <+> specialPrefix <> fold docs <> pretty (replicate numberOfSpaces ' ') -- the start of the line contains the "dot"-prefix as well as all the pipes for all the still not rendered marker messages prefix = let (pipesBefore, pipesAfter) = List.partition ((< bc) . snd . begin . fst) nubbedPipes -- split the list so that all pipes before can have `|`s but pipes after won't pipesBeforeRendered = pipesBefore <&> second \marker -> annotate (markerColor isError marker) (unicode "|" "│" withUnicode) -- pre-render pipes which are before because they will be shown lastBeginPosition = snd . begin . fst <$> List.safeLast (List.sortOn (snd . begin . fst) pipesAfter) lineLen = case lastBeginPosition of Nothing -> 0 Just col -> widthsBetween bc col currentPipe = unicode (bool "`" "|" hasSuccessor) (bool "╰" "├" hasSuccessor) withUnicode lineChar = unicode '-' '─' withUnicode pointChar = unicode "-" "╸" withUnicode bc' = bc + lineLen + 2 pipesBeforeMessageStart = List.filter ((< bc') . snd . begin . fst) pipesAfter -- consider pipes before, as well as pipes which came before the text rectangle bounds pipesBeforeMessageRendered = (pipesBefore <> pipesBeforeMessageStart) <&> second \marker -> annotate (markerColor isError marker) (unicode "|" "│" withUnicode) in -- also pre-render pipes which are before the message text bounds, because they will be shown if the message is on -- multiple lines lineStart pipesBeforeRendered <> annotate (markerColor isError msg) (currentPipe <> pretty (replicate lineLen lineChar) <> pointChar) <+> annotate (markerColor isError msg) (replaceLinesWith (space <> lineStart pipesBeforeMessageRendered <+> if List.null pipesBeforeMessageStart then " " else " ") 0 $ annotated $ markerMessage msg) in hardline <+> prefix <> showMessages specialPrefix pipes lineLen -- WARN: uses the internal of the library -- -- DO NOT use a wildcard here, in case the internal API exposes one more constructor replaceLinesWith :: Doc ann -> Int -> Doc ann -> Doc ann replaceLinesWith repl = go where replWidth = sdsWidth . layoutCompact $ repl sdsWidth = \case SFail -> 0 SEmpty -> 0 SChar _ sds -> 1 + sdsWidth sds SText l _ sds -> l + sdsWidth sds SLine _ _ -> error "replaceLinesWith was given a prefix with a line break" SAnnPush _ sds -> sdsWidth sds SAnnPop sds -> sdsWidth sds replWithNesting n = hardline <> repl <> pretty (textSpaces n) go n = \case Line -> replWithNesting n Fail -> Fail Empty -> Empty Char c -> Char c Text l txt -> Text l txt FlatAlt f d -> FlatAlt (go n f) (go n d) Cat c d -> Cat (go n c) (go n d) Nest n' d -> go (n + n') d Union c d -> Union (go n c) (go n d) Column f -> Column (go n . f) -- In this case we add both our fake nesting level (from the 'Nest' -- constructors we've eliminated) and the nesting level from the line -- prefixes Nesting f -> Nesting (go n . f . (+ replWidth) . (+ n)) Annotated ann doc -> Annotated ann (go n doc) WithPageWidth f -> WithPageWidth (go n . f) -- | Extracts the color of a marker as a 'Doc' coloring function. markerColor :: -- | Whether the marker is in an error context or not. -- This really makes a difference for a 'This' marker. Bool -> -- | The marker to extract the color from. Marker msg -> -- | A function used to color a 'Doc'. Annotation ann markerColor isError (This _) = ThisColor isError markerColor _ (Where _) = WhereColor markerColor _ (Maybe _) = MaybeColor markerColor _ Blank = CodeStyle -- we take the same color as the code, for it to be invisible {-# INLINE markerColor #-} -- | Retrieves the message held by a marker. markerMessage :: Marker msg -> msg markerMessage (This m) = m markerMessage (Where m) = m markerMessage (Maybe m) = m markerMessage Blank = undefined {-# INLINE markerMessage #-} -- | Pretty prints all hints. prettyAllHints :: [Note (Doc ann)] -> Int -> WithUnicode -> Doc (Annotation ann) prettyAllHints [] _ _ = mempty prettyAllHints (h : hs) leftLen withUnicode = {- A hint is composed of: (1) : Hint: -} let prefix = space <> pipePrefix leftLen withUnicode in hardline <> prefix <+> annotate HintColor (notePrefix h <+> replaceLinesWith prefix 7 (annotated $ noteMessage h)) <> prettyAllHints hs leftLen withUnicode where notePrefix (Note _) = "Note:" notePrefix (Hint _) = "Hint:" noteMessage (Note msg) = msg noteMessage (Hint msg) = msg safeArrayIndex :: (Ix i, IArray a e) => i -> a i e -> Maybe e safeArrayIndex i a | Array.inRange (Array.bounds a) i = Just (a ! i) | otherwise = Nothing annotated :: Doc ann -> Doc (Annotation ann) annotated = reAnnotate OtherStyle unicode :: a -> a -> WithUnicode -> a unicode f t = \case WithoutUnicode -> f WithUnicode -> t ================================================ FILE: compiler/diagnose/src/Error/Diagnose/Report.hs ================================================ -- | -- Module : Error.Diagnose.Report -- Description : Report definition and pretty printing -- Copyright : (c) Mesabloo, 2021-2022 -- License : BSD3 -- Stability : experimental -- Portability : Portable module Error.Diagnose.Report ( -- * Re-exports module Export, ) where import Error.Diagnose.Report.Internal as Export (Marker (..), Note (..), Report(Warn, Err), err, errorToWarning, warn, warningToError) ================================================ FILE: compiler/diagnose/src/Error/Diagnose/Style.hs ================================================ {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE DeriveGeneric #-} -- | -- Module : Error.Diagnose.Style -- Description : Custom style definitions -- Copyright : (c) Mesabloo, 2021-2022 -- License : BSD3 -- Stability : experimental -- Portability : Portable module Error.Diagnose.Style ( -- * Defining new style Annotation (..), Style, -- $defining_new_styles -- * Styles defaultStyle, unadornedStyle, ) where import GHC.Generics import Prettyprinter.Render.Terminal (AnsiStyle, Color (..), bold, color, colorDull) -- $defining_new_styles -- -- Defining new color styles (one may call them "themes") is actually rather easy. -- -- A 'Style' is a function from an annotated 'Doc'ument to another annotated 'Doc'ument. -- Note that only the annotation type changes, hence the need of only providing a unidirectional mapping between those. -- -- 'Annotation's are used when creating a 'Doc'ument and are simply placeholders to specify custom colors. -- 'AnsiStyle' is the concrete annotation to specify custom colors when rendering a 'Doc'ument. -- -- One may define additional styles as follows: -- -- > myNewCustomStyle :: Style -- > myNewCustomStyle = reAnnotate \case -- > -- all cases for all annotations -- -- For simplicity's sake, a default style is given as 'defaultStyle'. -- | Some annotations as placeholders for colors in a 'Doc'. data Annotation a = -- | The color of 'Error.Diagnose.Report.This' markers, depending on whether the report is an error -- report or a warning report. ThisColor Bool | -- | The color of 'Error.Diagnose.Report.Maybe' markers. MaybeColor | -- | The color of 'Error.Diagnose.Report.Where' markers. WhereColor | -- | The color for hints. -- -- Note that the beginning @Hint:@ text will always be in bold. HintColor | -- | The color for file names. FileColor | -- | The color of the rule separating the code/markers from the line numbers. RuleColor | -- | The color of the @[error]@/@[warning]@ at the top, depending on whether -- this is an error or warning report. KindColor Bool | -- | The color in which to output the @@ information when the file was not found. NoLineColor | -- | Additional style to apply to marker rules (e.g. bold) on top of some -- already processed color annotation. MarkerStyle (Annotation a) | -- | The color of the code when no marker is present. CodeStyle | -- | Something else, could be provided by the user OtherStyle a deriving (Eq, Ord, Show, Generic, Functor, Foldable, Traversable) -- | A style is a function which can be applied using 'reAnnotate'. -- -- It transforms a 'Doc'ument containing 'Annotation's into a 'Doc'ument containing -- color information. type Style a = Annotation a -> AnsiStyle ------------------------------------------- -- | A style which disregards all annotations unadornedStyle :: Style a unadornedStyle = const mempty -- | The default style for diagnostics, where: -- -- * 'Error.Diagnose.Report.This' markers are colored in red for errors and yellow for warnings -- * 'Error.Diagnose.Report.Where' markers are colored in dull blue -- * 'Error.Diagnose.Report.Maybe' markers are colored in magenta -- * Marker rules are of the same color of the marker, but also in bold -- * Hints are output in cyan -- * The left rules are colored in bold black -- * File names are output in dull green -- * The @[error]@/@[warning]@ at the top is colored in red for errors and yellow for warnings -- * The code is output in normal white defaultStyle :: Style AnsiStyle defaultStyle = \case ThisColor isError -> color if isError then Red else Yellow MaybeColor -> color Magenta WhereColor -> colorDull Blue HintColor -> color Cyan FileColor -> bold <> colorDull Green RuleColor -> bold <> color Black KindColor isError -> bold <> defaultStyle (ThisColor isError) NoLineColor -> bold <> colorDull Magenta MarkerStyle st -> let ann = defaultStyle st in if ann == defaultStyle CodeStyle then ann else bold <> ann CodeStyle -> color White OtherStyle s -> s ================================================ FILE: compiler/diagnose/src/Error/Diagnose.hs ================================================ module Error.Diagnose ( -- $header -- * How to use this module -- $usage -- ** Generating a report -- $generate_report -- ** Creating diagnostics from reports -- $create_diagnostic -- *** Pretty-printing a diagnostic onto a file 'System.IO.Handle' -- $diagnostic_pretty -- *** Pretty-printing a diagnostic as a document -- $diagnostic_to_doc -- *** Exporting a diagnostic to JSON -- $diagnostic_json -- ** Compatibility layers for popular parsing libraries -- $compatibility_layers -- *** megaparsec >= 9.0.0 ("Error.Diagnose.Compat.Megaparsec") -- $compatibility_megaparsec -- *** parsec >= 3.1.14.0 ("Error.Diagnose.Compat.Parsec") -- $compatibility_parsec -- *** Common errors -- $compatibility_errors -- * Re-exports module Export, ) where import Error.Diagnose.Diagnostic as Export import Error.Diagnose.Position as Export import Error.Diagnose.Pretty as Export import Error.Diagnose.Report as Export import Error.Diagnose.Style as Export -- $header -- -- This module exports all the needed data types to use this library. -- It should be sufficient to only @import "Error.Diagnose"@. -- $usage -- -- This library is intended to provide a very simple way of creating beautiful errors, by exposing -- a small yet simple API to the user. -- -- The basic idea is that a diagnostic is a collection of reports (which embody errors or warnings) along -- with the files which can be referenced in those reports. -- $generate_report -- -- A report contains: -- -- - A message, to be shown at the top -- -- - A list of located markers, used to underline parts of the source code and to emphasize it with a message -- -- - A list of hints, shown at the very bottom -- -- __Note__: The message type contained in a report is abstracted by a type variable. -- In order to render the report, the message must also be able to be rendered in some way -- (that we'll see later). -- -- This library allows defining two kinds of reports: -- -- - Errors, using 'Err' -- -- - Warnings, using 'Warn' -- -- Both take an optional error code, a message, a list of located markers and a list of hints. -- -- A very simple example is: -- -- > exampleReport :: Report String -- > exampleReport = -- > Err -- > -- vv OPTIONAL ERROR CODE -- > Nothing -- > -- vv ERROR MESSAGE -- > "This is my first error report" -- > -- vv MARKERS -- > [ (Position (1, 3) (1, 8) "some_test.txt", This "Some text under the marker") ] -- > -- vv HINTS -- > [] -- -- In general, 'Position's are returned by either a lexer or a parser, so that you never have to construct them -- directly in the code. -- -- __Note__: If using any parser library, you will have to convert from the internal positioning system to a 'Position' -- to be able to use this library. -- -- Markers put in the report can be one of (the colors specified are used only when pretty-printing): -- -- - A 'Error.Diagnose.Report.This' marker, which is the primary marker of the report. -- While it is allowed to have multiple of these inside one report, it is encouraged not to, because the position at the top of -- the report will only be the one of the /first/ 'Error.Diagnose.Report.This' marker, and because the resulting report may be harder to understand. -- -- This marker is output in red in an error report, and yellow in a warning report. -- -- - A 'Error.Diagnose.Report.Where' marker contains additional information\/provides context to the error\/warning report. -- For example, it may underline where a given variable @x@ is bound to emphasize it. -- -- This marker is output in blue. -- -- - A 'Error.Diagnose.Report.Maybe' marker may contain possible fixes (if the text is short, else hints are recommended for this use). -- -- This marker is output in magenta. -- -- - A 'Error.Diagnose.Report.Blank' marker is useful only to output additional lines of code in the report. -- -- This marker is not output and has no color. -- $create_diagnostic -- -- To create a new diagnostic, you need to use its 'Data.Default.Default' instance (which exposes a 'def' function, returning a new empty 'Diagnostic'). -- Once the 'Diagnostic' is created, you can use either 'addReport' (which takes a 'Diagnostic' and a 'Report', abstract by the same message type, -- and returns a 'Diagnostic') to insert a new report inside the diagnostic, or 'addFile' (which takes a 'Diagnostic', a 'FilePath' and a @['String']@, -- and returns a 'Diagnostic') to insert a new file reference in the diagnostic. -- -- You can then either pretty-print the diagnostic obtained (which requires all messages to be instances of the 'Prettyprinter.Pretty') -- -- directly onto a file handle or as a plain 'Prettyprinter.Doc'ument -- -- or export it to a lazy JSON 'Data.Bytestring.Lazy.ByteString' (e.g. in a LSP context). -- $diagnostic_pretty -- -- 'Diagnostic's can be output to any 'System.IO.Handle' using the 'printDiagnostic' function. -- This function takes several parameters: -- -- - The 'System.IO.Handle' onto which to output the 'Diagnostic'. -- It __must__ be a 'System.IO.Handle' capable of outputting data. -- -- - A 'Bool' used to indicate whether you want to output the 'Diagnostic' with unicode characters, or simple ASCII characters. -- -- Here are two examples of the same diagnostic, the first output with unicode characters, and the second output with ASCII characters: -- -- > [error]: Error with one marker in bounds -- > ╭──▶ test.zc@1:25-1:30 -- > │ -- > 1 │ let id(x : a) : a := x + 1 -- > • ┬──── -- > • ╰╸ Required here -- > ─────╯ -- -- > [error]: Error with one marker in bounds -- > +--> test.zc@1:25-1:30 -- > | -- > 1 | let id(x : a) : a := x + 1 -- > : ^---- -- > : `- Required here -- > -----+ -- -- - A 'Bool' set to 'False' if you don't want colors in the end result. -- -- - A 'Int' describing the number of spaces with which to output a TAB character. -- -- - The 'Style' describing colors of the report. -- See the module "Error.Diagnose.Style" for how to define new styles. -- -- - And finally the 'Diagnostic' to output. -- $diagnostic_to_doc -- -- 'Diagnostic's can be “output” (at least ready to be rendered) to a 'Prettyprinter.Doc' using 'prettyDiagnostic', which allows it to be easily added to other 'Prettyprinter.Doc' outputs. -- This makes it easy to customize the error messages further (though not the internal parts, only adding to it). -- As a 'Prettyprinter.Doc', there is also the possibility of altering internal annotations (styles) much easier (although this is already possible when printing the diagnostic). -- -- The arguments of the function mostly follow the ones from 'printDiagnostic'. -- The style is not one, as it can be applied by simply applying the styling function to the resulting function (if wanted). -- $diagnostic_json -- -- 'Diagnostic's can be exported to a JSON record of the following type, using the 'diagnosticToJson' function: -- -- > { files: -- > { name: string -- > , content: string[] -- > }[] -- > , reports: -- > { kind: 'error' | 'warning' -- > , code: string? -- > , message: string -- > , markers: -- > { kind: 'this' | 'where' | 'maybe' -- > , position: -- > { beginning: { line: int, column: int } -- > , end: { line: int, column: int } -- > , file: string -- > } -- > , message: string -- > }[] -- > , hints: ({ note: string } | { hint: string })[] -- > }[] -- > } -- -- This is particularly useful in the context of a LSP server, where outputting or parsing a raw error yields strange results or is unnecessarily complicated. -- -- Please note that this requires the flag @diagnose:json@ to be enabled (it is disabled by default in order not to include @aeson@, which is a heavy library). -- $compatibility_layers -- -- There are many parsing libraries available in the Haskell ecosystem, each coming with its own way of handling errors. -- Eventually, one needs to be able to map errors from these libraries to 'Diagnostic's, without having to include additional code for doing so. -- This is where compatibility layers come in handy. -- -- As of now, there are compatibility layers for these libraries: -- $compatibility_megaparsec -- -- This needs the flag @diagnose:megaparsec-compat@ to be enabled. -- -- Using the compatibility layer is very easy, as it is designed to be as simple as possible. -- One simply needs to convert the 'Text.Megaparsec.ParseErrorBundle' which is returned by running a parser into a 'Diagnostic' by using 'Error.Diagnose.Compat.Megaparsec.diagnosticFromBundle'. -- Several wrappers are included for easy creation of kinds (error, warning) of diagnostics. -- -- __Note:__ the returned diagnostic does not include file contents, which needs to be added manually afterwards. -- -- As a quick example: -- -- > import qualified Text.Megaparsec as MP -- > import qualified Text.Megaparsec.Char as MP -- > import qualified Text.Megaparsec.Char.Lexer as MP -- > -- > let filename = "" -- > content = "00000a2223266" -- > -- > let myParser = MP.some MP.decimal <* MP.eof -- > -- > let res = MP.runParser myParser filename content -- > -- > case res of -- > Left bundle -> -- > let diag = errorDiagnosticFromBundle Nothing "Parse error on input" Nothing bundle -- > -- Creates a new diagnostic with no default hints from the bundle returned by megaparsec -- > diag' = addFile diag filename content -- > -- Add the file used when parsing with the same filename given to 'MP.runParser' -- > in printDiagnostic stderr True 4 diag' -- > Right res -> print res -- -- This example will return the following error message (assuming default instances for @'Error.Diagnose.Compat.Megaparsec.HasHints' 'Data.Void.Void' msg@): -- -- > [error]: Parse error on input -- > ╭──▶ @1:6-1:7 -- > │ -- > 1 │ 00000a2223266 -- > • ┬ -- > • ├╸ unexpected 'a' -- > • ╰╸ expecting digit, end of input, or integer -- > ─────╯ -- $compatibility_parsec -- -- This needs the flag @diagnose:parsec-compat@ to be enabled. -- -- This compatibility layer allows easily converting 'Text.Parsec.Error.ParseError's into a single-report diagnostic containing all available information such -- as unexpected/expected tokens or error messages. -- The function 'Error.Diagnose.Compat.Parsec.diagnosticFromParseError' is used to perform the conversion between a 'Text.Parsec.Error.ParseError' and a 'Diagnostic'. -- -- __Note:__ the returned diagnostic does not include file contents, which needs to be added manually afterwards. -- -- Quick example: -- -- > import qualified Text.Parsec as P -- > -- > let filename = "" -- > content = "00000a2223266" -- > -- > let myParser = P.many1 P.digit <* P.eof -- > -- > let res = P.parse myParser filename content -- > -- > case res of -- > Left error -> -- > let diag = errorDiagnosticFromParseError Nothing "Parse error on input" Nothing error -- > -- Creates a new diagnostic with no default hints from the bundle returned by megaparsec -- > diag' = addFile diag filename content -- > -- Add the file used when parsing with the same filename given to 'MP.runParser' -- > in printDiagnostic stderr True 4 diag' -- > Right res -> print res -- -- This will output the following error on @stderr@: -- -- > [error]: Parse error on input -- > ╭──▶ @1:6-1:7 -- > │ -- > 1 │ 00000a2223266 -- > • ┬ -- > • ├╸ unexpected 'a' -- > • ╰╸ expecting any of digit, end of input -- > ─────╯ -- $compatibility_errors -- -- - @No instance for (HasHints ??? msg) arising from a use of ‘errorDiagnosticFromBundle’@ (@???@ is any type, depending on your parser's custom error type): -- -- The typeclass 'Error.Diagnose.Compat.Megaparsec.HasHints' does not have any default instances, because treatments of custom errors is highly dependent on who is using the library. -- As such, you will need to create orphan instances for your parser's error type. -- -- Note that the message type @msg@ can be left abstract if the implements of 'Error.Diagnose.Compat.Hints.hints' is @hints _ = mempty@. ================================================ FILE: compiler/diagnose/stack.yaml ================================================ # This file was automatically generated by 'stack init' # # Some commonly used options have been documented as comments in this file. # For advanced use and comprehensive documentation of the format, please see: # https://docs.haskellstack.org/en/stable/yaml_configuration/ # Resolver to choose a 'specific' stackage snapshot or a compiler version. # A snapshot resolver dictates the compiler version and the set of packages # to be used for project dependencies. For example: # # resolver: lts-3.5 # resolver: nightly-2015-09-21 # resolver: ghc-7.10.2 # # The location of a snapshot can be provided as a file or url. Stack assumes # a snapshot provided as a file might change, whereas a url resource does not. # # resolver: ./custom-snapshot.yaml # resolver: https://example.com/snapshots/2018-01-01.yaml resolver: lts-18.28 # User packages to be built. # Various formats can be used as shown in the example below. # # packages: # - some-directory # - https://example.com/foo/bar/baz-0.0.2.tar.gz # subdirs: # - auto-update # - wai packages: - . # Dependency packages to be pulled from upstream that are not in the resolver. # These entries can reference officially published versions as well as # forks / in-progress versions pinned to a git hash. For example: # # extra-deps: # - acme-missiles-0.3 # - git: https://github.com/commercialhaskell/stack.git # commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a # # extra-deps: [] extra-deps: # Override default flag values for local packages and extra-deps # flags: {} # Extra package databases containing global packages # extra-package-dbs: [] # Control whether we use the GHC we find on the path # system-ghc: true # # Require a specific version of stack, using version ranges # require-stack-version: -any # Default # require-stack-version: ">=2.3" # # Override the architecture used by stack, especially useful on Windows # arch: i386 # arch: x86_64 # # Extra directories used by stack for building # extra-include-dirs: [/path/to/dir] # extra-lib-dirs: [/path/to/dir] # # Allow a newer minor version of GHC than the snapshot specifies # compiler-check: newer-minor nix: shell-file: nix/stack.nix ================================================ FILE: compiler/diagnose/test/megaparsec/Instances.hs ================================================ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} module Instances where import Data.Void (Void) import Error.Diagnose import Error.Diagnose.Compat.Megaparsec instance HasHints Void msg where hints _ = mempty ================================================ FILE: compiler/diagnose/test/megaparsec/Repro6.hs ================================================ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# OPTIONS -Wno-orphans #-} module Repro6 where import Data.Bifunctor (first) import Data.Char (isAlpha) import Data.Text (Text) import qualified Data.Text as Text (unpack) import Data.Void (Void) import Error.Diagnose import Error.Diagnose.Compat.Megaparsec import Instances () import qualified Text.Megaparsec as MP import qualified Text.Megaparsec.Char as MP import qualified Text.Megaparsec.Char.Lexer as MP main :: IO () main = do let filename :: FilePath = "" content1 :: Text = "0000000123456" content2 :: Text = "00000a2223266" content3 :: Text = "aaa\naab\naba\na\nb\n" let res1 = first (errorDiagnosticFromBundle Nothing "Parse error on input" Nothing) $ MP.runParser @Void (MP.some MP.decimal <* MP.eof) filename content1 res2 = first (errorDiagnosticFromBundle Nothing "Parse error on input" Nothing) $ MP.runParser @Void (MP.some MP.decimal <* MP.eof) filename content2 res3 = first (errorDiagnosticFromBundle Nothing "Parse error on input" Nothing) $ let a = MP.char 'a' errSkip e = do MP.registerParseError e _ <- MP.takeWhileP Nothing isAlpha <* MP.eol return "" in MP.runParser @Void (MP.many (MP.withRecovery errSkip (MP.some a <* MP.eol)) <* MP.eof) filename content3 case res1 of Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content1) :: Diagnostic String) Right res -> print res case res2 of Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content2) :: Diagnostic String) Right res -> print res putStrLn "------------- res3 ----------------" case res3 of Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content3) :: Diagnostic String) Right res -> print res ================================================ FILE: compiler/diagnose/test/megaparsec/Spec.hs ================================================ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# OPTIONS -Wno-orphans #-} import Data.Bifunctor (first) import Data.Text (Text) import qualified Data.Text as Text (unpack) import Data.Void (Void) import Error.Diagnose import Error.Diagnose.Compat.Megaparsec import Instances () import qualified Repro6 import qualified Text.Megaparsec as MP import qualified Text.Megaparsec.Char.Lexer as MP main :: IO () main = do let filename :: FilePath = "" content1 :: Text = "0000000123456" content2 :: Text = "00000a2223266" let res1 = first (errorDiagnosticFromBundle Nothing "Parse error on input" Nothing) $ MP.runParser @Void (MP.some MP.decimal <* MP.eof) filename content1 res2 = first (errorDiagnosticFromBundle Nothing "Parse error on input" Nothing) $ MP.runParser @Void (MP.some MP.decimal <* MP.eof) filename content2 case res1 of Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content1) :: Diagnostic String) Right res -> print @[Integer] res case res2 of Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content2) :: Diagnostic String) Right res -> print @[Integer] res putStrLn "---------------------------------------------------" Repro6.main ================================================ FILE: compiler/diagnose/test/parsec/Repro2.hs ================================================ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Repro2 where import Data.Void import Error.Diagnose import Error.Diagnose.Compat.Parsec import Text.Parsec import Text.Parsec.Token instance HasHints Void String where hints _ = mempty type Parser = Parsec String () diagParse :: Parser a -> SourceName -> String -> Either (Diagnostic String) a diagParse p filename content = either (Left . diag) Right (parse p filename content) where diag e = addFile (errorDiagnosticFromParseError Nothing "Parse error on input" Nothing e) filename content parser1 :: Parser Char parser1 = op "\\" *> letter parser2 :: Parser Char parser2 = op' "\\" *> letter main :: IO () main = do either (printDiagnostic stderr WithUnicode (TabSize 4) defaultStyle) print $ diagParse parser1 "issues/2.txt" "\\1" either (printDiagnostic stderr WithUnicode (TabSize 4) defaultStyle) print $ diagParse parser2 "issues/2.txt" "\\1" -- smaller example op' :: String -> Parser String op' name = string name <* spaces op :: String -> Parser () op = reservedOp $ makeTokenParser LanguageDef { commentStart = "{-", commentEnd = "-}", commentLine = "--", reservedOpNames = ["\\"], opStart = oneOf "\\", opLetter = oneOf "\\" } ================================================ FILE: compiler/diagnose/test/parsec/Spec.hs ================================================ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS -Wno-orphans #-} import Data.Bifunctor (first) import Data.Text (Text) import qualified Data.Text as Text (unpack) import Data.Void (Void) import Error.Diagnose import Error.Diagnose.Compat.Parsec -- import qualified Repro2 as Issue2 -- import qualified Text.Parsec as P instance HasHints Void Text where hints _ = mempty main :: IO () main = do let filename :: FilePath = "" content1 :: Text = "0000000123456" content2 :: Text = "00000a2223266" content3 :: Text = "aab" let res1 = first (errorDiagnosticFromParseError Nothing "Parse error on input" Nothing) $ P.parse (P.many1 P.digit <* P.eof) filename content1 res2 = first (errorDiagnosticFromParseError Nothing "Parse error on input" Nothing) $ P.parse (P.many1 P.digit <* P.eof) filename content2 res3 = first (errorDiagnosticFromParseError Nothing "Parse error on input" Nothing) $ P.parse (test1 <* P.eof) filename content3 case res1 of Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content1) :: Diagnostic String) Right res -> print res case res2 of Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content2) :: Diagnostic String) Right res -> print res case res3 of Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content3) :: Diagnostic String) Right res -> print res -- all issue reproduction Issue2.main test1 = P.many (P.string "a") *> P.string "b" *> P.many1 (P.string "c") ================================================ FILE: compiler/diagnose/test/rendering/Spec.hs ================================================ {-# LANGUAGE CPP #-} {-# LANGUAGE ParallelListComp #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} #ifdef USE_AESON import qualified Data.ByteString.Lazy as BS import Error.Diagnose(diagnosticToJson) #endif import Data.HashMap.Lazy (HashMap) import qualified Data.HashMap.Lazy as HashMap import Error.Diagnose ( Marker (..), Note (..), Position (..), Report(..), addFile, addReport, defaultStyle, printDiagnostic, printDiagnostic', stdout, WithUnicode (..), TabSize (..), ) import System.IO (hPutStrLn) import Prettyprinter (Doc, annotate, pretty, hsep, indent, vsep, nest, (<+>), align, list) import Prettyprinter.Util (reflow) import Prettyprinter.Render.Terminal (AnsiStyle, Color (..), color, bold, italicized, underlined) import Data.Traversable (mapAccumL) import Data.Functor.Compose (Compose(..)) main :: IO () main = do let files :: HashMap FilePath String = HashMap.fromList [ ("test.zc", "let id(x : a) : a := x + 1\nrec fix(f) := f(fix(f))\nlet const(x : a, y : b) : a := x"), ("somefile.zc", "let id(x : a) : a := x\n + 1"), ("err.nst", "\n\n\n\n = jmp g\n\n g: forall(s: Ts, e: Tc).{ %r0: *s64 | s -> e }"), ("unsized.nst", "main: forall(a: Ta, s: Ts, e: Tc).{ %r5: forall().{| s -> e } | s -> %r5 }\n = salloc a\n ; sfree\n"), ("unicode.txt", "±⅀\t★♲♥🎉汉⑳⓴ჳᏁℳ爪"), ("gaps.txt", "abc\ndef\nghi\njkl\nmno\npqr"), ("repro3.file", "\n\n ayo yoa\n a b\n c d e f g\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlayer qwertyy using yoooo: \"a\" \"b\" \"c\"\n") ] let reports = [ errorNoMarkersNoHints, errorSingleMarkerNoHints, warningSingleMarkerNoHints, errorTwoMarkersSameLineNoOverlapNoHints, errorSingleMarkerOutOfBoundsNoHints, errorTwoMarkersSameLineOverlapNoHints, errorTwoMarkersSameLinePartialOverlapNoHints, errorTwoMarkersTwoLinesNoHints, realWorldExample, errorTwoMarkersSamePositionNoHints, errorThreeMarkersWithOverlapNoHints, errorWithMultilineErrorNoMarkerNoHints, errorSingleMultilineMarkerMessageNoHints, errorTwoMarkersSameOriginOverlapNoHints, errorNoMarkersSingleHint, errorNoMarkersSingleMultilineHint, errorNoMarkersTwoHints, errorSingleMultilineMarkerNoHints, errorTwoMarkersWithMultilineNoHints, errorTwoMultilineMarkersNoHints, errorSingleMultilineMarkerMultilineMessageNoHints, errorTwoMultilineMarkersFirstMultilineMessageNoHints, errorThreeMultilineMarkersTwoMultilineMessageNoHints, errorOrderSensitive, errorMultilineAfterSingleLine, errorOnEmptyLine, errorMultipleFiles, errorWithCode, errorWithStrangeUnicodeInput, errorWithMultilineMarkerOn3Lines, errorMultilineMarkerNotAtEnd, errorWithLineGap, repro3, errorWithMultilineMarkerMessage, errorWithMultilineMarkerMessage', errorWithSingleBlankMarker, errorWithBlankAndNormalMarkerInLine, beautifulExample ] customAnnReports = [ colorfulReport, indentedReport, nestingReport ] let diag = HashMap.foldlWithKey' addFile (foldl addReport mempty reports) files customDiag = HashMap.foldlWithKey' addFile (foldl addReport mempty customAnnReports) files hPutStrLn stdout "\n\nWith unicode: ─────────────────────────\n" printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle diag hPutStrLn stdout "\n\nWithout unicode: ----------------------\n" printDiagnostic stdout WithoutUnicode (TabSize 4) defaultStyle diag hPutStrLn stdout "\n\nWith custom annotations: ----------------------\n" printDiagnostic' stdout WithUnicode (TabSize 4) defaultStyle customDiag #ifdef USE_AESON hPutStrLn stdout "\n\nAs JSON: ------------------------------\n" BS.hPutStr stdout (diagnosticToJson diag) #endif hPutStrLn stdout "\n" colorfulReport :: Report (Doc AnsiStyle) colorfulReport = fmap hsep . getCompose . snd . mapAccumL (\(c : cs) s -> (cs, annotate c (pretty s))) styles . Compose . fmap words $ realWorldExample where styles = [ color fg <> e | fg <- cycle [Black, Red, Green, Yellow, Blue, Magenta, Cyan, White] | e <- cycle [bold, italicized, underlined] ] indentedReport :: Report (Doc AnsiStyle) indentedReport = Err Nothing ("Indent..." <> indent 3 (vsep ["foo", "bar", "baz"])) [ (Position (1, 15) (1, 16) "test.zc", Maybe a) , (Position (1, 11) (1, 12) "test.zc", This b) ] [Note c] where a = vsep [ "A woman’s face with Nature’s own hand painted" , "Hast thou, the master-mistress of my passion;" , "A woman’s gentle heart, but not acquainted" , "With shifting change, as is false women’s fashion;" ] b = vsep [ "An eye more bright than theirs, less false in rolling," , "Gilding the object whereupon it gazeth;" , "A man in hue, all “hues” in his controlling," , "Which steals men’s eyes and women’s souls amazeth." ] c = vsep [ "And for a woman wert thou first created;" , "Till Nature, as she wrought thee, fell a-doting," , "And by addition me of thee defeated," , "By adding one thing to my purpose nothing." , indent 4 "But since she prick’d thee out for women’s pleasure," , indent 4 "Mine be thy love and thy love’s use their treasure." ] nestingReport :: Report (Doc AnsiStyle) nestingReport = Err Nothing (nest 4 $ vsep ["Nest...", "foo", "bar", "baz"]) [ (Position (1, 15) (1, 16) "test.zc", Maybe a) ] [Note b, Hint c] where a = nest 3 $ vsep [ "'What day is it?' asked Pooh." , "'It's today,' squeaked Piglet." , "'My favourite day,' said Pooh." ] b = foldr1 (\p q -> nest 2 (vsep [p, q])) [ "It's a very funny thought that, if Bears were Bees," , "They'd build their nests at the bottom of trees." , "And that being so (if the Bees were Bears)," , "We shouldn't have to climb up all these stairs." ] c = "The elements:" <+> align ( list [ "antimony" , "arsenic" , "aluminum" , "selenium" , "hydrogen" , "oxygen" , "nitrogen" , "rhenium" , align $ reflow "And there may be many others, but they haven't been discovered" ] ) errorNoMarkersNoHints :: Report String errorNoMarkersNoHints = Err Nothing "Error with no marker" [] [] errorSingleMarkerNoHints :: Report String errorSingleMarkerNoHints = Err Nothing "Error with one marker in bounds" [(Position (1, 25) (1, 30) "test.zc", This "Required here")] [] warningSingleMarkerNoHints :: Report String warningSingleMarkerNoHints = Warn Nothing "Warning with one marker in bounds" [(Position (1, 25) (1, 30) "test.zc", This "Required here")] [] errorTwoMarkersSameLineNoOverlapNoHints :: Report String errorTwoMarkersSameLineNoOverlapNoHints = Err Nothing "Error with two markers in bounds (no overlap) on the same line" [ (Position (1, 5) (1, 10) "test.zc", This "First"), (Position (1, 15) (1, 22) "test.zc", Where "Second") ] [] errorSingleMarkerOutOfBoundsNoHints :: Report String errorSingleMarkerOutOfBoundsNoHints = Err Nothing "Error with one marker out of bounds" [(Position (10, 5) (10, 15) "test2.zc", This "Out of bounds")] [] errorTwoMarkersSameLineOverlapNoHints :: Report String errorTwoMarkersSameLineOverlapNoHints = Err Nothing "Error with two overlapping markers in bounds" [ (Position (1, 6) (1, 13) "test.zc", This "First"), (Position (1, 10) (1, 15) "test.zc", Where "Second") ] [] errorTwoMarkersSameLinePartialOverlapNoHints :: Report String errorTwoMarkersSameLinePartialOverlapNoHints = Err Nothing "Error with two partially overlapping markers in bounds" [ (Position (1, 5) (1, 25) "test.zc", This "First"), (Position (1, 12) (1, 20) "test.zc", Where "Second") ] [] errorTwoMarkersTwoLinesNoHints :: Report String errorTwoMarkersTwoLinesNoHints = Err Nothing "Error with two markers on two lines in bounds" [ (Position (1, 5) (1, 12) "test.zc", This "First"), (Position (2, 3) (2, 4) "test.zc", Where "Second") ] [] realWorldExample :: Report String realWorldExample = Err Nothing "Could not deduce constraint 'Num(a)' from the current context" [ (Position (1, 25) (1, 30) "test.zc", This "While applying function '+'"), (Position (1, 11) (1, 16) "test.zc", Where "'x' is supposed to have type 'a'"), (Position (1, 8) (1, 9) "test.zc", Where "type 'a' is bound here without constraints") ] ["Adding 'Num(a)' to the list of constraints may solve this problem."] errorTwoMarkersSamePositionNoHints :: Report String errorTwoMarkersSamePositionNoHints = Err Nothing "Error with two markers on the same exact position in bounds" [ (Position (1, 6) (1, 10) "test.zc", This "First"), (Position (1, 6) (1, 10) "test.zc", Maybe "Second") ] [] errorThreeMarkersWithOverlapNoHints :: Report String errorThreeMarkersWithOverlapNoHints = Err Nothing "Error with three markers with overlapping in bounds" [ (Position (1, 9) (1, 15) "test.zc", This "First"), (Position (1, 9) (1, 18) "test.zc", Maybe "Second"), (Position (1, 6) (1, 10) "test.zc", Where "Third") ] [] errorWithMultilineErrorNoMarkerNoHints :: Report String errorWithMultilineErrorNoMarkerNoHints = Err Nothing "Error with multi\nline message and no markers" [] [] errorSingleMultilineMarkerMessageNoHints :: Report String errorSingleMultilineMarkerMessageNoHints = Err Nothing "Error with single marker with multiline message" [(Position (1, 9) (1, 15) "test.zc", This "First\nmultiline")] [] errorTwoMarkersSameOriginOverlapNoHints :: Report String errorTwoMarkersSameOriginOverlapNoHints = Err Nothing "Error with two markers with same origin but partial overlap in bounds" [ (Position (1, 9) (1, 15) "test.zc", This "First"), (Position (1, 9) (1, 20) "test.zc", Maybe "Second") ] [] errorNoMarkersSingleHint :: Report String errorNoMarkersSingleHint = Err Nothing "Error with no marker and one hint" [] ["First hint"] errorNoMarkersSingleMultilineHint :: Report String errorNoMarkersSingleMultilineHint = Err Nothing "Error with no marker and one multiline hint" [] ["First multi\nline hint"] errorNoMarkersTwoHints :: Report String errorNoMarkersTwoHints = Err Nothing "Error with no markers and two hints" [] [ "First note", Hint "Second hint" ] errorSingleMultilineMarkerNoHints :: Report String errorSingleMultilineMarkerNoHints = Err Nothing "Error with single marker spanning across multiple lines" [(Position (1, 15) (2, 6) "test.zc", This "First")] [] errorTwoMarkersWithMultilineNoHints :: Report String errorTwoMarkersWithMultilineNoHints = Err Nothing "Error with two markers, one single line and one multiline, in bounds" [ (Position (1, 9) (1, 13) "test.zc", This "First"), (Position (1, 14) (2, 6) "test.zc", Where "Second") ] [] errorTwoMultilineMarkersNoHints :: Report String errorTwoMultilineMarkersNoHints = Err Nothing "Error with two multiline markers in bounds" [ (Position (1, 9) (2, 5) "test.zc", This "First"), (Position (2, 1) (3, 10) "test.zc", Where "Second") ] [] errorSingleMultilineMarkerMultilineMessageNoHints :: Report String errorSingleMultilineMarkerMultilineMessageNoHints = Err Nothing "Error with one multiline marker with a multiline message in bounds" [(Position (1, 9) (2, 5) "test.zc", This "Multi\nline message")] [] errorTwoMultilineMarkersFirstMultilineMessageNoHints :: Report String errorTwoMultilineMarkersFirstMultilineMessageNoHints = Err Nothing "Error with two multiline markers with one multiline message in bounds" [ (Position (1, 9) (2, 5) "test.zc", This "First"), (Position (1, 9) (2, 6) "test.zc", Where "Multi\nline message") ] [] errorThreeMultilineMarkersTwoMultilineMessageNoHints :: Report String errorThreeMultilineMarkersTwoMultilineMessageNoHints = Err Nothing "Error with three multiline markers with two multiline messages in bounds" [ (Position (1, 9) (2, 5) "test.zc", This "First"), (Position (1, 9) (2, 6) "test.zc", Where "Multi\nline message"), (Position (1, 9) (2, 7) "test.zc", Maybe "Multi\nline message #2") ] [] errorOrderSensitive :: Report String errorOrderSensitive = Err Nothing "Order-sensitive labels with crossing" [ (Position (1, 1) (1, 7) "somefile.zc", This "Leftmost label"), (Position (1, 9) (1, 16) "somefile.zc", Where "Rightmost label") ] [] beautifulExample :: Report String beautifulExample = Err Nothing "Could not deduce constraint 'Num(a)' from the current context" [ (Position (1, 25) (2, 6) "somefile.zc", This "While applying function '+'"), (Position (1, 11) (1, 16) "somefile.zc", Where "'x' is supposed to have type 'a'"), (Position (1, 8) (1, 9) "somefile.zc", Where "type 'a' is bound here without constraints") ] ["Adding 'Num(a)' to the list of constraints may solve this problem."] errorMultilineAfterSingleLine :: Report String errorMultilineAfterSingleLine = Err Nothing "Multiline after single line" [ (Position (1, 17) (1, 18) "unsized.nst", Where "Kind is infered from here"), (Position (2, 14) (3, 0) "unsized.nst", This "is an error") ] [] errorOnEmptyLine :: Report String errorOnEmptyLine = Err Nothing "Error on empty line" [(Position (1, 5) (3, 8) "err.nst", This "error on empty line")] [] errorMultipleFiles :: Report String errorMultipleFiles = Err Nothing "Error on multiple files" [ (Position (1, 5) (1, 7) "test.zc", Where "Function already declared here"), (Position (1, 5) (1, 7) "somefile.zc", This "Function `id` is already declared in another module") ] [] errorWithCode :: Report String errorWithCode = Err (Just "E0123") "Error with code and markers" [(Position (1, 5) (1, 7) "test.zc", This "is an error")] [] errorWithStrangeUnicodeInput :: Report String errorWithStrangeUnicodeInput = Err (Just "❎") "ⓈⓉⓇⒶⓃⒼⒺ ⓊⓃⒾⒸⓄⒹⒺ" [ (Position (1, 1) (1, 7) "unicode.txt", This "should work fine 🎉"), (Position (1, 7) (1, 9) "unicode.txt", Where "After TAB") ] [] errorWithMultilineMarkerOn3Lines :: Report String errorWithMultilineMarkerOn3Lines = Err Nothing "Multiline marker on 3 lines" [(Position (1, 3) (3, 10) "test.zc", This "should color all 3 lines correctly")] [] errorMultilineMarkerNotAtEnd :: Report String errorMultilineMarkerNotAtEnd = Err Nothing "Multiline marker not at end of report" [ (Position (1, 10) (2, 3) "test.zc", This "is a multline marker"), (Position (3, 5) (3, 13) "test.zc", Where "inline marker found after") ] [] errorWithLineGap :: Report String errorWithLineGap = Err Nothing "Error with line gaps between two markers" [ (Position (1, 1) (1, 3) "gaps.txt", Where "is a first marker"), (Position (5, 2) (5, 4) "gaps.txt", This "is the main marker") ] [] errorWithMultilineMarkerMessage :: Report String errorWithMultilineMarkerMessage = Err Nothing "Error with multiline message in first marker" [ (Position (1, 5) (1, 10) "test.zc", This "First\nmarker"), (Position (1, 15) (1, 22) "test.zc", Where "Second") ] [] errorWithMultilineMarkerMessage' :: Report String errorWithMultilineMarkerMessage' = Err Nothing "Error with multiline message in first marker" [ (Position (1, 5) (1, 10) "test.zc", This "First\nmarker"), (Position (1, 15) (1, 22) "test.zc", Where "Second"), (Position (1, 10) (1, 15) "test.zc", Maybe "Third") ] [] repro3 :: Report String repro3 = Err (Just "WrongStaticLayerLength") "The length of the static layer does not match the length of the template it uses" [ (Position (3, 3) (5, 16) "repro3.file", Where "This template has 9 elements"), (Position (24, 28) (24, 39) "repro3.file", This "... but this layer only has 3 members"), (Position (24, 21) (24, 26) "repro3.file", Where "This is the template being used"), (Position (24, 7) (24, 15) "repro3.file", Where "while checking this static layer") ] [] errorWithSingleBlankMarker :: Report String errorWithSingleBlankMarker = Err Nothing "Error with a single blank marker" [(Position (1, 5) (1, 10) "test.zc", Blank)] [] errorWithBlankAndNormalMarkerInLine :: Report String errorWithBlankAndNormalMarkerInLine = Err Nothing "Error with a single blank marker" [(Position (1, 5) (1, 10) "test.zc", Blank), (Position (1, 15) (1, 22) "test.zc", This "After a blank")] [] ================================================ FILE: compiler/lib/bench/KindsBench.hs ================================================ import qualified Acton.Env as Env import qualified Acton.Kinds as Kinds import qualified Acton.NameInfo as NameInfo import qualified Acton.Parser as Parser import qualified Acton.Syntax as Syntax import Control.DeepSeq (rnf) import qualified Control.Exception as E import qualified Data.HashMap.Strict as HashMap import Data.Time.Clock (diffUTCTime, getCurrentTime) import GHC.Stats import System.Environment (getArgs) import System.FilePath (takeBaseName) import System.IO (BufferMode(LineBuffering), hSetBuffering, stdout) -- Usage: -- stack build libacton:exe:kinds-bench -- stack exec kinds-bench -- ../dist/base/out/types path/to/file.act +RTS -T -RTS -- -- This uses Parser.parseModule, the normal parallel parser entrypoint. The RTS -- flag is optional. With -T, the driver also prints per-phase allocation and -- GC deltas. elapsed label t0 t1 = putStrLn $ label ++ " " ++ show (diffUTCTime t1 t0) printStats label before after = putStrLn $ label ++ " alloc " ++ show alloc ++ " gc_elapsed " ++ show gcElapsed ++ " gcs " ++ show collections where alloc = allocated_bytes after - allocated_bytes before gcElapsed = gc_elapsed_ns after - gc_elapsed_ns before collections = gcs after - gcs before getStats enabled = if enabled then Just <$> getRTSStats else return Nothing printStatsMaybe label (Just before) (Just after) = printStats label before after printStatsMaybe _ _ _ = return () forceHTEnv = HashMap.foldl' forceHNameInfo () where forceHNameInfo () (NameInfo.HNModule _ te _) = forceHTEnv te forceHNameInfo () hni = hni `seq` () main = do hSetBuffering stdout LineBuffering args <- getArgs case args of [typesPath, sourcePath] -> do statsEnabled <- getRTSStatsEnabled src <- readFile sourcePath env0 <- Env.initEnv typesPath False let modName = Syntax.modName [takeBaseName sourcePath] s0 <- getStats statsEnabled t0 <- getCurrentTime parsed <- Parser.parseModule modName sourcePath src Nothing E.evaluate (rnf parsed) t1 <- getCurrentTime s1 <- getStats statsEnabled elapsed "parse" t0 t1 printStatsMaybe "parse_stats" s0 s1 env <- Env.mkEnv [typesPath] env0 parsed E.evaluate (forceHTEnv (Env.hnames env)) E.evaluate (forceHTEnv (Env.hmodules env)) t2 <- getCurrentTime s2 <- getStats statsEnabled elapsed "env" t1 t2 printStatsMaybe "env_stats" s1 s2 kchecked <- Kinds.check env parsed E.evaluate (rnf kchecked) t3 <- getCurrentTime s3 <- getStats statsEnabled elapsed "kinds" t2 t3 printStatsMaybe "kinds_stats" s2 s3 _ -> error "usage: kinds-bench TYPES_PATH SOURCE.act" ================================================ FILE: compiler/lib/bench/TypesBench.hs ================================================ import qualified Acton.Env as Env import qualified Acton.Kinds as Kinds import qualified Acton.NameInfo as NameInfo import qualified Acton.Parser as Parser import qualified Acton.Syntax as Syntax import qualified Acton.Types as Types import Control.DeepSeq (rnf) import qualified Control.Exception as E import qualified Data.HashMap.Strict as HashMap import Data.Time.Clock (diffUTCTime, getCurrentTime) import GHC.Stats import System.Environment (getArgs) import System.FilePath (takeBaseName) import System.IO (BufferMode(LineBuffering), hSetBuffering, stdout) -- Usage: -- stack build libacton:exe:types-bench -- stack exec types-bench -- ../dist/base/out/types path/to/file.act +RTS -T -RTS -- -- This uses Parser.parseModule, the normal parallel parser entrypoint. The RTS -- flag is optional. With -T, the driver also prints per-phase allocation and -- GC deltas. elapsed label t0 t1 = putStrLn $ label ++ " " ++ show (diffUTCTime t1 t0) printStats label before after = putStrLn $ label ++ " alloc " ++ show alloc ++ " gc_elapsed " ++ show gcElapsed ++ " gcs " ++ show collections where alloc = allocated_bytes after - allocated_bytes before gcElapsed = gc_elapsed_ns after - gc_elapsed_ns before collections = gcs after - gcs before getStats enabled = if enabled then Just <$> getRTSStats else return Nothing printStatsMaybe label (Just before) (Just after) = printStats label before after printStatsMaybe _ _ _ = return () forceHTEnv = HashMap.foldl' forceHNameInfo () where forceHNameInfo () (NameInfo.HNModule _ te _) = forceHTEnv te forceHNameInfo () hni = hni `seq` () main = do hSetBuffering stdout LineBuffering args <- getArgs case args of [typesPath, sourcePath] -> do statsEnabled <- getRTSStatsEnabled src <- readFile sourcePath env0 <- Env.initEnv typesPath False let modName = Syntax.modName [takeBaseName sourcePath] s0 <- getStats statsEnabled t0 <- getCurrentTime parsed <- Parser.parseModule modName sourcePath src Nothing E.evaluate (rnf parsed) t1 <- getCurrentTime s1 <- getStats statsEnabled elapsed "parse" t0 t1 printStatsMaybe "parse_stats" s0 s1 env <- Env.mkEnv [typesPath] env0 parsed E.evaluate (forceHTEnv (Env.hnames env)) E.evaluate (forceHTEnv (Env.hmodules env)) t2 <- getCurrentTime s2 <- getStats statsEnabled elapsed "env" t1 t2 printStatsMaybe "env_stats" s1 s2 kchecked <- Kinds.check env parsed E.evaluate (rnf kchecked) t3 <- getCurrentTime s3 <- getStats statsEnabled elapsed "kinds" t2 t3 printStatsMaybe "kinds_stats" s2 s3 (nmod, tchecked, typeEnv, tests) <- Types.reconstruct Nothing Nothing env kchecked E.evaluate (rnf nmod) E.evaluate (rnf tchecked) E.evaluate (forceHTEnv (Env.hnames typeEnv)) E.evaluate (forceHTEnv (Env.hmodules typeEnv)) E.evaluate (length tests) t4 <- getCurrentTime s4 <- getStats statsEnabled elapsed "types" t3 t4 printStatsMaybe "types_stats" s3 s4 _ -> error "usage: types-bench TYPES_PATH SOURCE.act" ================================================ FILE: compiler/lib/package.yaml.in ================================================ name: libacton version: BUILD_VERSION # github: "/simple" license: BSD3 author: "Author name here" maintainer: "example@example.com" copyright: "2018 Author name here" # Metadata used when publishing your package # synopsis: Short description of your package # category: Web # To avoid duplicated efforts in documentation and dealing with the # complications of embedding Haddock markup inside cabal files, it is # common to point users to the README.md file. description: Please see the README on Github at dependencies: - aeson - aeson-pretty - array - async - base - base16-bytestring - binary - bytestring - clock - containers - cryptohash-sha256 - deepseq - diagnose - dir-traverse - directory >= 1.3.1 - filelock - filepath - hashable - http-client - http-client-tls - http-types - megaparsec - mtl - optparse-applicative - parser-combinators - pretty - pretty-show - prettyprinter - process - random - scientific - stm - sydtest - sydtest-discover - temporary - text - time - transformers - unix - unordered-containers - utf8-string library: source-dirs: src exposed-modules: - Acton.Boxing - Acton.BuildSpec - Acton.Builtin - Acton.CPS - Acton.CodeGen - Acton.Completion - Acton.Compile - Acton.CommandLineParser - Acton.Deactorizer - Acton.Diagnostics - Acton.DocPrinter - Acton.Env - Acton.Fingerprint - Acton.Hashing - Acton.Kinds - Acton.LambdaLifter - Acton.NameInfo - Acton.Normalizer - Acton.Parser - Acton.Printer - Acton.QuickType - Acton.Solver - Acton.SourceProvider - Acton.Syntax - Acton.Testing - Acton.Types - Acton.TypeEnv - Acton.WitKnots - Utils - Pretty - InterfaceFiles tests: test_lib: main: ActonSpec.hs source-dirs: test dependencies: - libacton ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N executables: kinds-bench: main: KindsBench.hs source-dirs: bench other-modules: [] dependencies: - libacton ghc-options: - -threaded - -rtsopts - '"-with-rtsopts=-N -A64M"' types-bench: main: TypesBench.hs source-dirs: bench other-modules: [] dependencies: - libacton ghc-options: - -threaded - -rtsopts - '"-with-rtsopts=-N -A64M"' ================================================ FILE: compiler/lib/src/Acton/Boxing.hs ================================================ {-# LANGUAGE FlexibleInstances #-} module Acton.Boxing where import Acton.Syntax import Acton.Names import Acton.NameInfo import Acton.Env import Acton.QuickType import Acton.Prim import Acton.Builtin import Acton.Subst import Pretty import Utils import Debug.Trace import Control.Monad.State.Strict import Control.Monad.Except doBoxing :: Acton.Env.Env0 -> Module -> IO Module doBoxing env m = do return m{mbody = ss} where (_,ss) = runBoxM (boxing (boxEnv env) (mbody m)) -- Boxing monad --------------------------------------------------------------------------------------------------- type BoxM a = State Int a newName :: String -> BoxM Name newName s = do n <- get put (n+1) return $ Internal BoxPass s n newNames (n : ns) = do un <- newName (nstr n) ps <- newNames ns return ((n,un) : ps) newNames [] = return [] runBoxM ss = evalState ss 0 data BoxX = BoxX { unboxedVarsX :: [(Name,Name)], isTopLevelX :: Bool, delayedUnboxX :: Bool, inClassX :: Bool } type BoxEnv = EnvF BoxX boxEnv :: Env0 -> BoxEnv boxEnv env0 = setX env0 (BoxX [] True False False) addUnboxedVars :: [(Name,Name)] -> BoxEnv -> BoxEnv addUnboxedVars ps env = modX env $ \x -> x{unboxedVarsX = ps ++ unboxedVarsX x} unboxedVars :: BoxEnv -> [(Name,Name)] unboxedVars env = unboxedVarsX $ envX env setTopLevel b env = modX env $ \x -> x{isTopLevelX = b} isTopLevel env = isTopLevelX $ envX env setDelayedUnbox b env = modX env $ \x -> x{delayedUnboxX = b} isDelayedUnbox env = delayedUnboxX $ envX env -- Auxiliaries --------------------------------------------------------------------------------------------------- -- unboxing integralTypes = [tBigint, tInt, tI32, tI16, tU64, tU32, tU16] numericTypes = integralTypes ++ [tFloat] unboxableTypes = tail numericTypes isUnboxable t = t `elem` unboxableTypes prims = [primISINSTANCE, primISNOTNONE, primISNONE] unboxedPrim p | p == primISINSTANCE = primISINSTANCE0 | p == primISNOTNONE = primISNOTNONE0 | p == primISNONE = primISNONE0 qMath str = QName (ModName [name "math"]) (name str) mathfuns = map qMath ["sqrt", "exp", "log", "sin", "cos", "tan", "asin", "acos", "atan", "sinh", "cosh", "tanh", "asinh", "acosh", "atanh"] -- class UnBoxClass --------------------------------------------------------------------------------------------------- class UnboxClass a where unbox :: Type -> a -> a instance UnboxClass Expr where unbox _ (Box _ e) = e unbox t e = UnBox t e instance UnboxClass PosArg where unbox t (PosArg e p) = PosArg (unbox t e) (unbox t p) unbox t (PosStar e) = PosStar (unbox t e) unbox t PosNil = PosNil -- Walking the syntax tree to place Box/UnBox annotations and sometimes restructure code to mimic C code on unboxed values --------------- class Boxing a where boxing :: BoxEnv -> a -> BoxM ([Name],a) instance {-# OVERLAPS #-} Boxing ([Stmt]) where boxing env [] = return ([],[]) boxing env (x@(Assign _ [PVar _ n _] _) : xs) | isWitness n = do (ws1,x') <- boxing env x (ws2,xs') <- boxing env1 xs return $ if n `elem` ws2 then (ws1++ws2,x':xs') else (ws2,xs') where te = envOf x env1 = define te env boxing env (x@(Assign l [p@(PVar _ n (Just t))] e) : xs) | isUnboxable t = do case lookup n (unboxedVars env) of Nothing -> do (ws1, e') <- boxing env e un <- newName (nstr n) let env1 = define (envOf x) (addUnboxedVars [(n,un)] env) (ws2,p') <- boxing env1 p (ws3,xs') <- boxing env1 xs let ss = if isTopLevel env1 then [sAssign p (Box t (eVar un))] else [] return (ws1++ws2++ws3, Assign l [p'] (if isUnboxed (pn p') then unbox t e' else e') : ss ++ xs') Just un -> do (ws1,x') <- boxing env x (ws2,xs') <- boxing (define (envOf x) env) xs let ss = if isTopLevel env then [sAssign p (Box t (eVar un))] else [] return (ws1++ws2, x' : ss ++ xs') boxing env (x@If{} : xs) = do ns <- newNames [ n | (n,NVar t) <- te, isUnboxable t ] let env1 = addUnboxedVars ns env (ws1,x') <- boxing env1 x (ws2,xs') <- boxing (define te env1) xs return (ws1++ws2, x' : xs') where te = envOf x boxing env (x : xs) = do ps <- if (inClass env) then return [] else newNames [n | (n,NDef (TSchema _ [] (TFun _ _ p _ t)) _ _) <- te, isUnboxable t || hasUnboxableType p] (ws1,x') <- boxing (addUnboxedVars ps env) x (ws2,xs') <- boxing (addUnboxedVars ps env1) xs return (ws1++ws2, x' : xs') where te = envOf x env1 = define te env hasUnboxableType (TRow _ _ _ t r) = isUnboxable t || hasUnboxableType r hasUnboxableType _ = False instance (Boxing a) => Boxing ([a]) where boxing env [] = return ([],[]) boxing env (x : xs) = do (ws1,x1) <- boxing env x (ws2,xs2) <- boxing env xs return (ws1++ws2, x1:xs2) instance Boxing a => Boxing (Maybe a) where boxing env (Just x) = do (ws1, x1) <- boxing env x return (ws1, Just x1) boxing env Nothing = return ([], Nothing) instance Boxing Expr where boxing env e@(Var l (NoQ n)) | isWitness n = return ([n], e) | otherwise = case lookup n ps of Just un -> return ([], Box (typeOf env e) (eVar un)) Nothing -> return ([], e) where ps = unboxedVars env boxing env v@Var{} = return ([], v) boxing env (Call _ (Dot _ e@(Var _ w@(NoQ n)) attr) p KwdNil) | isWitness n = do (ws1,p1) <- boxing env p (ws2,e1) <- boxingWitness env w attr ws1 p1 return (ws1++ws2,e1) | attr == nextKW = return ([n], eCallP (eDot (eQVar w) attr) p) where boxingWitness :: BoxEnv -> QName -> Name -> [Name] ->PosArg -> BoxM ([Name],Expr) boxingWitness env w attr ws p = case findQName w env of NVar (TCon _ (TC _ ts)) | any (not . vFree) ts -> return ([n], eCallP (eDot (eQVar w) attr) p) | attr == fromatomKW -> boxingFromAtom w ts es | attr == getitemKW -> boxingGetItem w ts es | attr `elem` binopKWs -> boxingBinop w attr es ts | attr `elem` eqordKWs -> boxingCompop w attr es ts _ -> return ([n], eCallP (eDot (eQVar w) attr) p) where es = posargs p vFree (TCon _ (TC _ _))= True vFree _ = False boxingFromAtom w ts [i@Int{}] | t == tBigint = return ([], i) | t `elem` numericTypes = return ([], Box (last ts) (unbox t i)) where t = head ts boxingFromAtom w ts [x@Float{}] = return ([], Box (last ts) (unbox (head ts) x)) boxingFromAtom w ts es = return ([n], eCall (eDot (eQVar w) fromatomKW) es) boxingGetItem w (t0:t:t1:_) es@[a, k] | t == tInt && tn == qnList = return ([], eCall (tApp (eQVar primUGetItem) [t1]) [a, unbox t k]) -- only list indexing optimized. TODO: str indexing where TCon _ (TC tn _) = t0 boxingGetItem w ts es = return ([n], eCall (eDot (eQVar w) attr) es) -- boxingNext w ts [] boxingBinop w attr es@[x1, x2] ts | isUnboxable t = return ([], Box (last ts) $ Paren NoLoc $ BinOp NoLoc (unbox t x1) op (unbox t x2)) where t = head ts op = bin2Binary attr boxingBinop w attr es _ = return ([n], eCall (eDot (eQVar w) attr) es) boxingCompop w attr es@[x1, x2] ts | isUnboxable t = return ([], Box tBool $ Paren NoLoc $ CompOp NoLoc (unbox t x1) [OpArg op (unbox t x2)]) where t = head ts op = cmp2Comparison attr boxingCompop w attr es _ = return ([n], eCall (eDot (eQVar w) attr) es) boxing env (Call l e@(TApp _ (Var _ f) ts) p KwdNil) | f `elem` prims = do (ws1,p1) <- boxing env p return (ws1,Box tBool $ eCallP e' p1) | otherwise = do (ws1,p1) <- boxing env p return (ws1, eCallP e p1) where e' = tApp (eQVar (unboxedPrim f)) ts boxing env c@(Call l e@(Var _ (NoQ n)) p KwdNil) | isUnboxable t = do (ws1,p1) <- boxing env p case lookup n (unboxedVars env) of Just un -> return (ws1, Box t (eCallP (eVar un) (ub env p1))) Nothing -> return (ws1, eCallP e p1) where t = typeOf env c ub env (PosArg e p) | isUnboxable t = PosArg (unbox t e) (ub env p) | otherwise = PosArg e (ub env p) where t = typeOf env e ub env (PosStar e) | isUnboxable t = PosStar (unbox t e) | otherwise = PosStar e where t = typeOf env e ub env PosNil = PosNil boxing env (Call l e@(Var _ f) p KwdNil) | f `elem`prims = do (ws1,p1) <- boxing env p return (ws1,Box tBool $ eCallP e' p1) | f `elem` mathfuns = do (ws1,p1) <- boxing env p return (ws1,Box tFloat $ eCallP e (unbox tFloat p1)) | otherwise = do (ws1,p1) <- boxing env p return (ws1, eCallP e p1) where e' = eQVar (unboxedPrim f) boxing env (Call l f p KwdNil) = do (ws1,f1) <- boxing env f (ws2,p1) <- boxing env p return (ws1++ws2, eCallP f1 p1) boxing env (TApp l f ts) = do (ws1,f1) <- boxing env f return (ws1, TApp l f1 ts) boxing env (Let l ss e) = do (ws1, ss') <- boxing env ss (ws2, e') <- boxing env e return (ws1++ws2, Let l ss' e') boxing env (Async l e) = do (ws1,e1) <- boxing env e return (ws1, Async l e1) boxing env (Await l e) = do (ws1,e1) <- boxing env e return (ws1, Await l e1) boxing env (Index l e1 e2) = do (ws1,e1') <- boxing env e1 (ws2,e2') <- boxing env e2 return (ws1++ws2, Index l e1' e2') boxing env (Cond l e1 e2 e3) = do (ws1,e1') <- boxing env e1 (ws2,e2') <- boxing env e2 (ws3,e3') <- boxing env e3 return (ws1++ws2++ws3, Cond l e1' e2' e3') boxing env (IsInstance l e qn) = do (ws1,e1) <- boxing env e return (ws1, IsInstance l e1 qn) boxing env e@(BinOp l e1 op e2) = do (ws1,e1') <- boxing env e1 -- op is And or Or (ws2,e2') <- boxing env e2 return (ws1++ws2, BinOp l e1' op e2') where t = typeOf env e boxing env (CompOp l e os) = do (ws1,e1) <- boxing env e (ws2,e2) <- boxing env os return (ws1++ws2, CompOp l e1 e2) boxing env (UnOp l uop e) = do (ws1,e') <- boxing env e --uop is Not return (ws1, UnOp l uop e') where t = typeOf env e boxing env (Dot l e n) = do (ws1,e1) <- boxing env e return (ws1, Dot l e1 n) boxing env (DotI l e i) = do (ws1,e1) <- boxing env e return (ws1, DotI l e1 i) boxing env (Rest l e n) = do (ws1,e1) <- boxing env e return (ws1, Rest l e1 n) boxing env (RestI l e i) = do (ws1,e1) <- boxing env e return (ws1, RestI l e1 i) -- boxing env (Lambda l p k f fx) = Lambda l <$> boxing env p <*> boxing env k <*> boxing env f <*> return fx -- boxing env (Yield l mbe) = Yield l <$> boxing env mbe -- boxing env (YieldFrom l e) = YieldFrom l <$> boxing env e boxing env (Tuple l p k) = do (ws1,p1) <- boxing env p return (ws1,Tuple l p1 k) boxing env (List l es) = do (ws1,es1) <- boxing env es return (ws1, List l es1) boxing env (Set l es) = do (ws1,es1) <- boxing env es return (ws1, Set l es1) boxing env (Dict l es) = do (ws1,es1) <- boxing env es return (ws1, Dict l es1) boxing env (Paren l e) = do (ws1,e1) <- boxing env e return (ws1, Paren l e1) boxing env (Box t e) = do (ws1,e1) <- boxing env e case e1 of UnBox _ e' -> return (ws1,e') _ -> return (ws1,Box t e1) return (ws1, e1) -- boxing env (Box _ (UnBox _ e)) = do (ws1,e1) <- boxing env e -- return (ws1, e1) boxing env e = return ([],e) instance Boxing OpArg where boxing env (OpArg op e) = do (ws1,e1) <- boxing env e return (ws1, OpArg op e1) instance Boxing Stmt where boxing env (Expr l e) = do (ws1,e1) <- boxing env e return (ws1, Expr l e1) boxing env (Assign l [pt@(PVar _ x Nothing)] e@(Call _ (Dot _ (Var _ w@(NoQ n)) attr) p KwdNil)) | isWitness n = do (ws1,p1) <- boxing env p (ws2,pt2) <- boxing env pt (ws3,s3) <- boxingWitness env pt2 w attr p1 return (ws1++ws2++ws3,s3) where boxingWitness env pt w attr p = case findQName w env of NVar (TCon _ (TC _ ts)) | any (not . vFree) ts -> return ([n], Assign l [pt] (eCallP (eDot (eQVar w) attr) p)) | attr `elem` incrBinopKWs -> boxingincrBinop pt w attr es ts _ -> do (ws,e') <- boxing env e return (ws, Assign l [pt] (if isUnboxed (pn pt) then unbox t e' else e')) where es = posargs p vFree (TCon _ (TC _ _))= True vFree _ = False t = typeOf env e boxingincrBinop pt w attr es@[x1,x2] ts | isUnboxable t = return ([], AugAssign NoLoc (unbox t x1) op (unbox t x2)) where t = head ts op = bin2Aug attr boxingincrBinop pt w attr es _ = return ([n], Assign l [pt] (eCall (eDot (eQVar w) attr) es)) boxing env (Assign l [pt@PVar{}] e) = do (ws1,pt1) <- boxing env pt (ws2,e2) <- boxing env e return (ws1++ws2, Assign l [pt1] (if isUnboxed (pn pt1) then unbox t e2 else e2)) where t = typeOf env e boxing env (Assign l ps e) = do (ws1,ps1) <- boxing env ps (ws2,e2) <- boxing env e return (ws1++ws2, Assign l ps1 e2) {- This does not work. It may cause mutable updates to integer-typed varibles. boxing env (MutAssign l tg@Dot{} e@(Call _ (Dot _ (Var _ w@(NoQ n)) attr) p KwdNil)) | isWitness n = do (ws0,tg1) <- boxing env tg (ws1,p1) <- boxing env p (ws2,s2) <- boxingWitness env tg1 w attr p1 return (ws1++ws2,s2) where t = typeOf env tg boxingWitness env tg w attr p = case findQName w env of NVar (TCon _ (TC _ ts)) | any (not . vFree) ts -> return ([n], MutAssign l tg (eCallP (eDot (eQVar w) attr) p)) | attr `elem` incrBinopKWs -> boxingincrBinop tg w attr es ts _ -> do (ws,e') <- boxing env e return (ws, if isUnboxable t then MutAssign l tg e' else MutAssign l tg e') where es = posargs p vFree (TCon _ (TC _ _))= True vFree _ = False boxingincrBinop tg w attr es@[x1,x2] ts | isUnboxable t = return ([], AugAssign NoLoc (unbox t x1) op (unbox t x2)) where t = head ts op = bin2Aug attr boxingincrBinop w attr es _ = return ([n], MutAssign l tg (eCall (eDot (eQVar w) attr) es)) -} boxing env (MutAssign l t e) = do (ws0,t1) <- boxing env t (ws1,e1) <- boxing env e return (ws0++ws1, MutAssign l t1 e1) boxing env (AugAssign l t aop e)= do (ws0,t1) <- boxing env t (ws1,e1) <- boxing env e return (ws0++ws1, AugAssign l t aop e1) boxing env (Assert l e mbe) = do (ws1,e1) <- boxing env e (ws2,mbe1) <- boxing env mbe return (ws1++ws2, Assert l e1 mbe1) boxing env (Pass l) = return ([], Pass l) boxing env (Delete l t) = return ([], Delete l t) boxing env (Return l (Just e)) = do (ws1,e1) <- boxing env e if (isUnboxable t && isDelayedUnbox env) then return (ws1, Return l (Just (unbox t e1))) else return (ws1, Return l (Just e1)) where t = typeOf env e boxing env (Return l Nothing) = return ([], Return l Nothing) boxing env (Raise l e) = do (ws1,e1) <- boxing env e return (ws1, Raise l e1) boxing env (Break l) = return ([], Break l) boxing env (Continue l) = return ([], Continue l) boxing env (If l bs ss) = do (ws1,bs1) <- boxing env1 bs (ws2,ss1) <- boxing env1 ss return (ws1++ws2,If l bs1 ss1) where env1 = setTopLevel False env boxing env (While l e ss els) = do (ws1,e1) <- boxing env e (ws2,ss1) <- boxing env1 ss (ws3,els1) <- boxing env1 els return (ws1++ws2++ws3, While l e1 ss1 els1) where env1 = setTopLevel False env boxing env (Try l ss hs els fs) = do (ws1,ss1) <- boxing env1 ss (ws2,hs1) <- boxing env1 hs (ws3,els1) <- boxing env1 els (ws4,fs1) <- boxing env1 fs return (ws1++ws2++ws3++ws4, Try l ss1 hs1 els1 fs1) where env1 = setTopLevel False env boxing env (With l ws ss) = do (ws1,ws') <- boxing env ws (ws2,ss1) <- boxing (setTopLevel False env) ss return (ws1++ws2, With l ws' ss1) boxing env (VarAssign l ps e) = do (ws1,e1) <- boxing env e return (ws1, VarAssign l ps e) boxing env (After l e1 e2) = do (ws1,e1') <- boxing env e1 (ws2,e2') <- boxing env e2 return (ws1++ws2, After l e1' e2') boxing env s@(Signature l ns sc d) = return ([], s) boxing env g@(Decl l ds) = do (ws1, ds1) <- boxing env1 ds return (ws1, Decl l ds1) where te = envOf g env1 = setTopLevel False $ define te env instance {-# OVERLAPS #-} Boxing [Decl] where boxing env (c@Class{} : ds) = do (ws1,c1) <- boxing (setInClass env) c (ws2,ds2) <- boxing env ds return (ws1++ws2,c1:ds2) boxing env (d@Def{} : ds) -- | hasNotImpl (dbody d) = do (ws,ds1) <- boxing env ds -- return (ws, d : ds1) -- | otherwise = case lookup (dname d) (unboxedVars env) of = case lookup (dname d) (unboxedVars env) of Just un -> do (ws1,d1) <- boxing (setDelayedUnbox True env) d{dname = un} let ds1 = [mkWrapper d un] (ws2,ds2) <- boxing env ds return (ws1++ws2,d1 : ds1 ++ ds2) _ -> do (ws1,d1) <- boxing env d (ws2,ds2) <- boxing env ds return (ws1++ws2,d1:ds2) where mkWrapper (Def l n q p _ (Just t) ss dec fx ddoc) un | isUnboxable t = Def l n q p KwdNIL (Just t) [Return NoLoc (Just (Box t (eCallP (eVar un) (ub p))))] dec fx ddoc | otherwise = Def l n q p KwdNIL (Just t) [Return NoLoc (Just (eCallP (eVar un) (ub p)))] dec fx ddoc ub (PosPar n (Just t) _ p) | isUnboxable t = PosArg (unbox t (eVar n)) (ub p) | otherwise = PosArg (eVar n) (ub p) ub (PosSTAR n _) = PosStar (eVar n) ub PosNIL = PosNil boxing env [] = return ([],[]) instance Boxing Decl where boxing env (Class l n q cs ss ddoc) = do (ws1, ss1) <- boxing env1 ss' return (ws1, Class l n q cs ss1 ddoc) where ss' = vsubst [(tvSelf, tCon c)] ss c = TC (NoQ n) (map tVar $ qbound q) env1 = defineTVars q env boxing env (Def l n q p KwdNIL t ss dec fx ddoc) = do ps <- if (inClass env || not (isUnboxed n)) then return [] else newNames [n | (n,NVar t) <- te, isUnboxable t] let env2 = addUnboxedVars ps $ env1 (ws1,p1) <- boxing env2 p (ws2,ss1) <- boxing env2 ss return (ws1++ws2,Def l n q p1 KwdNIL t ss1 dec fx ddoc) where te = envOf p env1 = define te env instance Boxing Branch where boxing env (Branch e ss) = do (ws1,e1) <- boxing env e (ws2,ss1) <- boxing env ss return (ws1++ws2, Branch e1 ss1) instance Boxing Handler where boxing env (Handler ex b) = do (ws1, b1) <- boxing env b return (ws1, Handler ex b1) instance Boxing PosPar where boxing env (PosPar n t e p) = do (ws1, e1) <- boxing env e (ws2, p2) <- boxing env p case lookup n (unboxedVars env) of Just un -> return (ws1++ws2, PosPar un t e1 p2) _ -> return (ws1++ws2, PosPar n t e1 p2) boxing env (PosSTAR n t) = return ([],PosSTAR n t) boxing env PosNIL = return ([],PosNIL) instance Boxing PosArg where boxing env (PosArg e p) = do (ws1,e1) <- boxing env e (ws2,p1) <- boxing env p return (ws1++ws2, PosArg e1 p1) boxing env (PosStar e) = do (ws1,e1) <- boxing env e return (ws1, PosStar e1) boxing env PosNil = return ([],PosNil) instance Boxing Elem where boxing env (Elem e) = do (ws1,e1) <- boxing env e return (ws1, Elem e1) boxing env (Star e) = do (ws1,e1) <- boxing env e return (ws1, Star e1) instance Boxing Assoc where boxing env (Assoc k v) = do (ws1,k1) <- boxing env k (ws2,v1) <- boxing env v return (ws1++ws2, Assoc k1 v1) boxing env (StarStar e) = do (ws1,e1) <- boxing env e return (ws1, StarStar e1) instance Boxing WithItem where boxing env (WithItem e mbp) = do (ws1,e1) <- boxing env e return (ws1, WithItem e1 mbp) instance Boxing Pattern where boxing env v@(PVar l n mbt) = case lookup n ps of Just un -> return ([], PVar l un mbt) Nothing -> return ([], v) where ps = unboxedVars env boxing env (PParen l p) = do (ws,p') <- boxing env p return (ws, PParen l p') boxing env (PList l ps mbp) = do (ws1, ps1) <- boxing env ps (ws2, mbp2) <- boxing env mbp return (ws1++ws2, PList l ps1 mbp2) bin2Binary kw | kw == addKW = Plus | kw == subKW = Minus | kw == mulKW = Mult | kw == powKW = Pow | kw == truedivKW = Div | kw == modKW = Mod | kw == floordivKW = EuDiv | kw == lshiftKW = ShiftL | kw == rshiftKW = ShiftR | kw == orKW = BOr | kw == xorKW = BXor | kw == andKW = BAnd cmp2Comparison kw | kw == eqKW = Eq | kw == neKW = NEq | kw == ltKW = Lt | kw == leKW = LE | kw == gtKW = Gt | kw == geKW = GE | kw == isKW = Is | kw == isnotKW = IsNot bin2Aug kw | kw == iaddKW = PlusA | kw == isubKW = MinusA | kw == imulKW = MultA | kw == ipowKW = PowA | kw == itruedivKW = DivA | kw == imodKW = ModA | kw == ifloordivKW = EuDivA | kw == ilshiftKW = ShiftLA | kw == irshiftKW = ShiftRA | kw == iorKW = BOrA | kw == ixorKW = BXorA | kw == iandKW = BAndA ================================================ FILE: compiler/lib/src/Acton/BuildSpec.hs ================================================ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DeriveGeneric #-} module Acton.BuildSpec ( PkgDep(..) , ZigDep(..) , BuildSpec(..) , encodeBuildSpecJSON , renderBuildAct , parseBuildAct , parseBuildActDetailed , BuildSpecParseError(..) , updateBuildActFromJSON ) where import GHC.Generics (Generic) import Data.Aeson (FromJSON(..), ToJSON(..), (.:), (.:?), (.=)) import qualified Data.Aeson as Ae import qualified Data.ByteString.Lazy as BL import qualified Data.Map as Map import Data.Map (Map) import Data.Char (isSpace) import Data.Maybe (catMaybes, fromMaybe, isNothing, mapMaybe) import qualified Data.List as L import qualified Control.Exception as E import System.IO.Unsafe (unsafePerformIO) import Control.Applicative ((<|>)) import qualified Acton.Fingerprint as Fingerprint import qualified Acton.Parser as AP import qualified Acton.Syntax as S import qualified Acton.Printer as Pr import Utils (SrcLoc(..)) import qualified Data.Aeson.KeyMap as KM -- Acton build configuration data model -- We use this to specify various bits of information for an Acton project. The -- canonical way is to have a Build.act file, for example: -- -- name = "myproject" -- -- dependencies = { -- "http2": (repo_url="https://github.com/actonlang/http2", repo_ref="v1.2.3"), -- "local": (path="deps/local-lib") -- } -- -- zig_dependencies = { -- "zlib": (url="https://example.com/zlib.tar.gz", hash="sha256:deadbeef...", artifacts=["z"]), -- "ssl": (path="/opt/zig/ssl", options={"with_tls": "true"}) -- } -- data PkgDep = PkgDep { url :: Maybe String , hash :: Maybe String , path :: Maybe String , repo_url :: Maybe String , repo_ref :: Maybe String } deriving (Eq, Show, Generic) instance FromJSON PkgDep where parseJSON = Ae.withObject "PkgDep" $ \o -> PkgDep <$> o .:? "url" <*> o .:? "hash" <*> o .:? "path" <*> o .:? "repo_url" <*> o .:? "repo_ref" instance ToJSON PkgDep where toJSON (PkgDep u h p ru rr) = Ae.object $ catMaybes [ ("url" .=) <$> u , ("hash" .=) <$> h , ("path" .=) <$> p , ("repo_url" .=) <$> ru , ("repo_ref" .=) <$> rr ] data ZigDep = ZigDep { zurl :: Maybe String , zhash :: Maybe String , zpath :: Maybe String , options :: Map String String , artifacts :: [String] } deriving (Eq, Show, Generic) instance FromJSON ZigDep where parseJSON = Ae.withObject "ZigDep" $ \o -> ZigDep <$> o .:? "url" <*> o .:? "hash" <*> o .:? "path" <*> (o .:? "options" Ae..!= Map.empty) <*> (o .:? "artifacts" Ae..!= []) instance ToJSON ZigDep where toJSON (ZigDep u h p opts arts) = Ae.object $ catMaybes [ ("url" .=) <$> u , ("hash" .=) <$> h , ("path" .=) <$> p ] ++ [ "options" .= opts , "artifacts" .= arts ] data BuildSpec = BuildSpec { specName :: String , specDescription :: Maybe String , fingerprint :: String , dependencies :: Map String PkgDep , zig_dependencies :: Map String ZigDep } deriving (Eq, Show, Generic) data BuildSpecParseError = ParseError String | MissingProjectName | MissingFingerprint String | InvalidFingerprint String String deriving (Eq, Show) renderBuildSpecParseError :: BuildSpecParseError -> String renderBuildSpecParseError err = case err of ParseError msg -> msg MissingProjectName -> "Missing project name (add: name = \"my_project\")" MissingFingerprint _ -> "Missing fingerprint (add: fingerprint = 0x1234abcd5678ef00)" InvalidFingerprint name raw -> "Invalid fingerprint " ++ raw ++ " (project name: " ++ show name ++ "). " ++ "Expected an unquoted 64-bit hex fingerprint like " ++ "0x1234abcd5678ef00" instance FromJSON BuildSpec where parseJSON = Ae.withObject "BuildSpec" $ \o -> do nm <- o .: "name" desc <- o .:? "description" fp <- o .: "fingerprint" deps <- o .:? "dependencies" Ae..!= Map.empty zig <- o .:? "zig_dependencies" Ae..!= Map.empty return (BuildSpec nm desc fp deps zig) instance ToJSON BuildSpec where toJSON (BuildSpec nm desc fp deps zig) = Ae.object $ [ "name" .= nm , "fingerprint" .= fp , "dependencies" .= deps , "zig_dependencies" .= zig ] ++ catMaybes [ ("description" .=) <$> desc ] -- Render an Acton Build.act file from BuildSpec -- Example: -- dependencies = { -- "http2": (repo_url="https://github.com/...", hash="..."), -- } -- zig_dependencies = { -- "zlib": (url="...", hash="...", options={"opt":"val"}, artifacts=["z"]), -- } renderBuildAct :: BuildSpec -> String renderBuildAct (BuildSpec nm mdesc fp deps zdeps) = unlines $ [ "# Autogenerated from BuildSpec (acton)" , "# Edit this file to update your project configuration." , "" , "name = " ++ show nm ] ++ maybe [] (\d -> ["description = " ++ show d]) mdesc ++ [ "fingerprint = " ++ renderFingerprint fp , "" , renderBlockText "dependencies" deps (Map.keys deps) renderPkgTuple , "" , "" , renderBlockText "zig_dependencies" zdeps (Map.keys zdeps) renderZigTuple , "" ] updateBuildActFromJSON :: String -> BL.ByteString -> Either String String updateBuildActFromJSON content json = do modAST <- parseModuleForSpec content currSpec <- case extractSpecFromModule modAST of Left err -> Left (renderBuildSpecParseError err) Right spec -> Right spec val <- Ae.eitherDecode' json case val of Ae.Object obj -> do patch <- case Ae.fromJSON val of Ae.Error e -> Left e Ae.Success s -> Right s let depsPresent = KM.member "dependencies" obj zigPresent = KM.member "zig_dependencies" obj namePresent = KM.member "name" obj descPresent = KM.member "description" obj fpPresent = KM.member "fingerprint" obj name' <- if namePresent then requireField "name" (patchName patch) else Right (specName currSpec) fp' <- if fpPresent then do fpVal <- requireField "fingerprint" (patchFingerprint patch) validatePatchFingerprint fpVal else Right (fingerprint currSpec) desc' <- if descPresent then requireField "description" (patchDescription patch) else Right (specDescription currSpec) let deps' = if depsPresent then patchDependencies patch else dependencies currSpec zigs' = if zigPresent then patchZigDependencies patch else zig_dependencies currSpec merged = currSpec { specName = name' , specDescription = desc' , fingerprint = fp' , dependencies = deps' , zig_dependencies = zigs' } content1 <- applyTopLevelPatches content modAST merged namePresent descPresent fpPresent modAST1 <- parseModuleForSpec content1 let bodyOffsets = Map.fromList $ catMaybes [ fmap (\off -> ("dependencies", off)) (findBodyOffsetsFromAST content1 "dependencies" modAST1) , fmap (\off -> ("zig_dependencies", off)) (findBodyOffsetsFromAST content1 "zig_dependencies" modAST1) ] content2 = spliceManyWithBodyOffsets content1 blockRenderers merged bodyOffsets Right content2 _ -> Left "Expected top-level JSON object for BuildSpec" where requireField label mval = case mval of Just v -> Right v Nothing -> Left ("Expected '" ++ label ++ "' to be present and non-null in JSON") validatePatchFingerprint fp = case Fingerprint.parseFingerprint fp of Just _ -> Right fp Nothing -> Left ("Expected 'fingerprint' to be a 64-bit hex literal " ++ "like 0x1234abcd5678ef00") applyTopLevelPatches :: String -> S.Module -> BuildSpec -> Bool -> Bool -> Bool -> Either String String applyTopLevelPatches content modAST spec namePresent descPresent fpPresent = do nameRepl <- if namePresent then case findAssignExprOffsetsFromAST "name" modAST of Just (s,e) -> Right (Just (s,e, show (specName spec))) Nothing -> Left "Missing name assignment in Build.act" else Right Nothing fpRepl <- if fpPresent then case findAssignExprOffsetsFromAST "fingerprint" modAST of Just (s,e) -> Right (Just (s,e, renderFingerprint (fingerprint spec))) Nothing -> Left "Missing fingerprint assignment in Build.act" else Right Nothing descRepls <- if descPresent then case specDescription spec of Just descVal -> case findAssignExprOffsetsFromAST "description" modAST of Just (s,e) -> Right [(s,e, show descVal)] Nothing -> case findAssignStmtOffsetsFromAST "name" modAST of Just (_,e) -> let pos = insertAfterLine content e in Right [(pos,pos, "description = " ++ show descVal ++ "\n")] Nothing -> Left "Missing name assignment in Build.act" Nothing -> case findAssignStmtOffsetsFromAST "description" modAST of Just (s,e) -> let e' = extendToLineEnd content e in Right [(s,e', "")] Nothing -> Right [] else Right [] let replacements = catMaybes [nameRepl, fpRepl] ++ descRepls Right (applyReplacements content replacements) applyReplacements :: String -> [(Int,Int,String)] -> String applyReplacements content reps = let sorted = L.sortBy (\(s1,_,_) (s2,_,_) -> compare s2 s1) reps in L.foldl' (\acc (s,e,r) -> take s acc ++ r ++ drop e acc) content sorted insertAfterLine :: String -> Int -> Int insertAfterLine content end = extendToLineEnd content end extendToLineEnd :: String -> Int -> Int extendToLineEnd content end = case L.elemIndex '\n' (drop end content) of Nothing -> length content Just off -> end + off + 1 -- JSON encoding helper encodeBuildSpecJSON :: BuildSpec -> BL.ByteString encodeBuildSpecJSON = Ae.encode parseBuildAct :: String -> Either String (BuildSpec, Maybe (Int,Int), Maybe (Int,Int)) parseBuildAct content = case parseBuildActDetailed content of Left err -> Left (renderBuildSpecParseError err) Right res -> Right res parseBuildActDetailed :: String -> Either BuildSpecParseError (BuildSpec, Maybe (Int,Int), Maybe (Int,Int)) parseBuildActDetailed content = do -- Parse with Acton parser and extract BuildSpec from AST modAST <- case parseModuleForSpec content of Left err -> Left (ParseError err) Right m -> Right m specFromAST <- extractSpecFromModule modAST -- Compute body offsets using AST locations let mDepsOff = findBodyOffsetsFromAST content "dependencies" modAST mZigsOff = findBodyOffsetsFromAST content "zig_dependencies" modAST Right (specFromAST, mDepsOff, mZigsOff) srcLocToPair :: SrcLoc -> Maybe (Int,Int) srcLocToPair NoLoc = Nothing srcLocToPair (Loc s e) = Just (s,e) patternVarName :: S.Pattern -> Maybe String patternVarName (S.PVar _ (S.Name _ v) _) = Just v patternVarName (S.PParen _ p) = patternVarName p patternVarName _ = Nothing findAssignStmtOffsetsFromAST :: String -> S.Module -> Maybe (Int,Int) findAssignStmtOffsetsFromAST varName (S.Module _ _ _ stmts) = case firstAssign stmts of Just loc -> srcLocToPair loc Nothing -> Nothing where firstAssign [] = Nothing firstAssign (S.Assign loc pats _ : rest) | varName `elem` mapMaybe patternVarName pats = Just loc | otherwise = firstAssign rest firstAssign (_:rest) = firstAssign rest findAssignExprOffsetsFromAST :: String -> S.Module -> Maybe (Int,Int) findAssignExprOffsetsFromAST varName (S.Module _ _ _ stmts) = case firstAssign stmts of Just expr -> srcLocToPair (S.eloc expr) Nothing -> Nothing where firstAssign [] = Nothing firstAssign (S.Assign _ pats expr : rest) | varName `elem` mapMaybe patternVarName pats = Just expr | otherwise = firstAssign rest firstAssign (_:rest) = firstAssign rest -- Find the inner-body offsets (start,end) between braces of the dict assigned -- to a given top-level variable, using AST locations only. The returned range -- is the content between '{' and '}', excluding the braces themselves. findBodyOffsetsFromAST :: String -> String -> S.Module -> Maybe (Int,Int) findBodyOffsetsFromAST content varName (S.Module _ _ _ stmts) = case firstDictLoc stmts of Just (s,e) -> braceBody content s e Nothing -> Nothing where firstDictLoc [] = Nothing firstDictLoc (S.Assign _ [S.PVar _ (S.Name _ v) _] (S.Dict l _) : rest) | v == varName = srcLocToPair l <|> firstDictLoc rest firstDictLoc (_:rest) = firstDictLoc rest -- Given a range [s,e) covering the dict, return the inner body [s+1,e-1]. -- We assume the Acton parser locates the Dict to start at '{' and end -- just after '}'. If that is not the case, we conservatively return Nothing. braceBody txt s e = let n = length txt in if s >= 0 && e <= n && s+1 <= e-1 && txt !! s == '{' && txt !! (e-1) == '}' then Just (s+1, e-1) else Nothing -- Parse build.act using the real Acton parser parseModuleForSpec :: String -> Either String S.Module parseModuleForSpec content = let qn = S.ModName [] -- anonymous module in case unsafePerformIO (E.try (AP.parseModule qn "Build.act" content Nothing) :: IO (Either E.SomeException S.Module)) of Left e -> Left (show e) Right m -> Right m -- Extract name, description, dependencies and zig_dependencies from the AST extractSpecFromModule :: S.Module -> Either BuildSpecParseError BuildSpec extractSpecFromModule (S.Module _ _ _ stmts) = let (mname, mdesc, mfp, mfpErr, deps, zigs) = foldl step (Nothing, Nothing, Nothing, Nothing, Map.empty, Map.empty) stmts in case (mname, mfp, mfpErr) of (Nothing, _, _) -> Left MissingProjectName (Just name, Nothing, Just raw) -> Left (InvalidFingerprint name raw) (Just name, Nothing, Nothing) -> Left (MissingFingerprint name) (Just name, Just fp, _) -> Right BuildSpec { specName = name , specDescription = mdesc , fingerprint = fp , dependencies = deps , zig_dependencies = zigs } where step (mname, mdesc, mfp, mfpErr, deps, zigs) stmt = case stmt of S.Assign _ pats expr -> let names = mapMaybe patternVarName pats mname' = if "name" `elem` names then exprToSimpleString expr <|> mname else mname mdesc' = if "description" `elem` names then exprToSimpleString expr <|> mdesc else mdesc (mfp', mfpErr') = if "fingerprint" `elem` names then case exprToFingerprint expr of Just fp -> (Just fp, Nothing) Nothing -> (mfp, if isNothing mfp then mfpErr <|> Just (renderExpr expr) else mfpErr) else (mfp, mfpErr) deps' = if "dependencies" `elem` names then fromMaybe deps (exprToPkgDeps expr) else deps zigs' = if "zig_dependencies" `elem` names then fromMaybe zigs (exprToZigDeps expr) else zigs in (mname', mdesc', mfp', mfpErr', deps', zigs') _ -> (mname, mdesc, mfp, mfpErr, deps, zigs) data BuildSpecPatch = BuildSpecPatch { patchName :: Maybe String , patchDescription :: Maybe (Maybe String) , patchFingerprint :: Maybe String , patchDependencies :: Map.Map String PkgDep , patchZigDependencies :: Map.Map String ZigDep } deriving (Eq, Show) instance FromJSON BuildSpecPatch where parseJSON = Ae.withObject "BuildSpecPatch" $ \o -> do let hasName = KM.member "name" o hasDesc = KM.member "description" o hasFp = KM.member "fingerprint" o name <- if hasName then Just <$> o .: "name" else pure Nothing desc <- if hasDesc then Just <$> o .:? "description" else pure Nothing fp <- if hasFp then Just <$> o .: "fingerprint" else pure Nothing deps <- o .:? "dependencies" Ae..!= Map.empty zigs <- o .:? "zig_dependencies" Ae..!= Map.empty pure (BuildSpecPatch name desc fp deps zigs) -- Generic block rendering and splicing ------------------------------------------------- -- Order here defines append order for missing blocks. type BlockDef = (String, BuildSpec -> [String], BuildSpec -> String) blockRenderers :: [BlockDef] blockRenderers = [ ( "dependencies" , \spec -> Map.keys (dependencies spec) , \spec -> renderBlockText "dependencies" (dependencies spec) (Map.keys (dependencies spec)) renderPkgTuple ) , ( "zig_dependencies" , \spec -> Map.keys (zig_dependencies spec) , \spec -> renderBlockText "zig_dependencies" (zig_dependencies spec) (Map.keys (zig_dependencies spec)) renderZigTuple ) ] -- Splice multiple blocks by label using precomputed inner-body offsets. -- Replaces present blocks in-place (preserving surrounding text) and appends -- any missing non-empty blocks at the end in declared order. spliceManyWithBodyOffsets :: String -> [BlockDef] -> BuildSpec -> Map.Map String (Int,Int) -> String spliceManyWithBodyOffsets content defs spec bodyOffsets = let reps = [ (s,e, (if s < length content && content !! s == '\n' then "\n" else "") ++ renderInner lbl) | (lbl,_,_) <- defs , Just (s,e) <- [Map.lookup lbl bodyOffsets] ] missing = [ renderFull lbl | (lbl, keysFn, _) <- defs , Map.notMember lbl bodyOffsets , not (null (keysFn spec)) ] replaced = applyReplacements' content (L.sortOn (\(s,_,_) -> s) reps) appended = if null missing then replaced else appendBlocks' replaced missing in appended where renderInner lbl = case lookup lbl [(l, keysFn) | (l, keysFn, _renderer) <- defs] of Just keysFn -> renderInnerBlock lbl (keysFn spec) Nothing -> "" renderFull lbl = case lookup lbl [(l, renderer) | (l, _keysFn, renderer) <- defs] of Just renderer -> renderer spec Nothing -> "" renderInnerBlock lbl keys | lbl == "dependencies" = renderInnerText (dependencies spec) keys renderPkgTuple | lbl == "zig_dependencies" = renderInnerText (zig_dependencies spec) keys renderZigTuple | otherwise = "" -- Render only the inner lines of a dict block, no label/braces renderInnerText :: (Show k, Ord k) => Map k v -> [k] -> (v -> String) -> String renderInnerText m keys renderTuple = let total = length keys comma i = if i < total then "," else "" lines' = [ " " ++ show k ++ ": " ++ renderTuple (m Map.! k) ++ comma i | (i,k) <- zip [1..] keys ] in unlines lines' -- Local helpers (replacements and append) applyReplacements' :: String -> [(Int,Int,String)] -> String applyReplacements' txt reps = let go pos acc [] = acc ++ drop pos txt go pos acc ((s,e,newT):xs) = let pre = take (s - pos) (drop pos txt) in go e (acc ++ pre ++ newT) xs in go 0 "" reps appendBlocks' :: String -> [String] -> String appendBlocks' txt blks = let base = if lastLineEndsNewline' txt then txt else txt ++ "\n" in base ++ L.intercalate "\n" blks lastLineEndsNewline' :: String -> Bool lastLineEndsNewline' s = not (null s) && last s == '\n' -- Rendering helpers renderBlockText :: (Show k, Ord k) => String -> Map k v -> [k] -> (v -> String) -> String renderBlockText label m keys renderTuple = let lines' = [ " " ++ show k ++ ": " ++ renderTuple (m Map.! k) ++ comma i | (i,k) <- zip [1..] keys ] in unlines $ [label ++ " = {"] ++ lines' ++ ["}"] where comma i = if i < length keys then "," else "" renderExpr :: S.Expr -> String renderExpr e = Pr.render (Pr.pretty e) -- Turn a PkgDep into a multi-line parenthesized key=value tuple string, e.g.: -- ( -- key1="val1", -- key2="val2" -- ) renderPkgTuple :: PkgDep -> String renderPkgTuple (PkgDep u h p ru rr) = let fields = catMaybes [ fmap (\x -> ("repo_url", mkStr x)) ru , fmap (\x -> ("repo_ref", mkStr x)) rr , fmap (\x -> ("url", mkStr x)) u , fmap (\x -> ("hash", mkStr x)) h , fmap (\x -> ("path", mkStr x)) p ] in case fields of [] -> "()" _ -> let total = length fields fieldLines = [ " " ++ k ++ "=" ++ renderExpr v ++ comma i | (i, (k,v)) <- zip [1..] fields ] comma i = if i < total then "," else "" in "(\n" ++ L.intercalate "\n" fieldLines ++ "\n )" -- Turn a ZigDep into a multi-line parenthesized key=value tuple string renderZigTuple :: ZigDep -> String renderZigTuple (ZigDep u h p opts arts) = let optExpr = if Map.null opts then Nothing else Just (mkOptions opts) artExpr = if null arts then Nothing else Just (mkList arts) fields = catMaybes [ fmap (\x -> ("url", mkStr x)) u , fmap (\x -> ("hash", mkStr x)) h , fmap (\x -> ("path", mkStr x)) p , fmap (\x -> ("options", x)) optExpr , fmap (\x -> ("artifacts", x)) artExpr ] in case fields of [] -> "()" _ -> let total = length fields fieldLines = [ " " ++ k ++ "=" ++ renderExpr v ++ comma i | (i, (k,v)) <- zip [1..] fields ] comma i = if i < total then "," else "" in "(\n" ++ L.intercalate "\n" fieldLines ++ "\n )" -- Compose a tuple string with no spaces around '=' and comma+space between pairs renderTuple :: [(String, S.Expr)] -> String renderTuple pairs = let items = [ k ++ "=" ++ renderExpr v | (k,v) <- pairs ] in "(" ++ L.intercalate ", " items ++ ")" -- Minimal Expr builders used for value rendering mkStr :: String -> S.Expr mkStr s = S.Strings NoLoc [s] mkOptions :: Map String String -> S.Expr mkOptions mp = S.Dict NoLoc [ S.Assoc (mkStr k) (mkStr v) | (k,v) <- Map.toList mp ] mkList :: [String] -> S.Expr mkList xs = S.List NoLoc [ S.Elem (mkStr x) | x <- xs ] exprToSimpleString :: S.Expr -> Maybe String exprToSimpleString (S.Strings _ [s]) = Just s exprToSimpleString _ = Nothing exprToFingerprint :: S.Expr -> Maybe String exprToFingerprint (S.Int _ _ lexeme) = Just lexeme exprToFingerprint (S.Paren _ e) = exprToFingerprint e exprToFingerprint _ = Nothing renderFingerprint :: String -> String renderFingerprint fp | Just formatted <- normalizeHexFingerprint fp = formatted | otherwise = show fp where normalizeHexFingerprint raw = case dropWhile isSpace raw of '0':'x':_ -> Fingerprint.formatFingerprint <$> Fingerprint.parseFingerprint raw '0':'X':_ -> Fingerprint.formatFingerprint <$> Fingerprint.parseFingerprint raw _ -> Nothing exprToPkgDeps :: S.Expr -> Maybe (Map.Map String PkgDep) exprToPkgDeps (S.Dict _ assocs) = Just $ Map.fromList (mapMaybe assocToPkg assocs) where assocToPkg (S.Assoc k v) = do key <- exprToSimpleString k dep <- tupleToPkg v pure (key, dep) assocToPkg _ = Nothing exprToPkgDeps _ = Nothing tupleToPkg :: S.Expr -> Maybe PkgDep tupleToPkg (S.Tuple _ _ kargs) = let m = kwdToMap kargs in Just PkgDep { url = Map.lookup "url" m >>= exprToSimpleString , hash = Map.lookup "hash" m >>= exprToSimpleString , path = Map.lookup "path" m >>= exprToSimpleString , repo_url = Map.lookup "repo_url" m >>= exprToSimpleString , repo_ref = Map.lookup "repo_ref" m >>= exprToSimpleString } tupleToPkg (S.Paren _ e) = tupleToPkg e tupleToPkg _ = Nothing exprToZigDeps :: S.Expr -> Maybe (Map.Map String ZigDep) exprToZigDeps (S.Dict _ assocs) = Just $ Map.fromList (mapMaybe assocToZig assocs) where assocToZig (S.Assoc k v) = do key <- exprToSimpleString k dep <- tupleToZig v pure (key, dep) assocToZig _ = Nothing exprToZigDeps _ = Nothing tupleToZig :: S.Expr -> Maybe ZigDep tupleToZig (S.Tuple _ _ kargs) = let m = kwdToMap kargs in Just ZigDep { zurl = Map.lookup "url" m >>= exprToSimpleString , zhash = Map.lookup "hash" m >>= exprToSimpleString , zpath = Map.lookup "path" m >>= exprToSimpleString , options = fromMaybe Map.empty (Map.lookup "options" m >>= exprToOptions) , artifacts = fromMaybe [] (Map.lookup "artifacts" m >>= exprToListStrings) } tupleToZig (S.Paren _ e) = tupleToZig e tupleToZig _ = Nothing kwdToMap :: S.KwdArg -> Map.Map String S.Expr kwdToMap S.KwdNil = Map.empty kwdToMap (S.KwdArg (S.Name _ n) e rest) = Map.insert n e (kwdToMap rest) kwdToMap (S.KwdStar _) = Map.empty exprToOptions :: S.Expr -> Maybe (Map.Map String String) exprToOptions (S.Dict _ assocs) = Just $ Map.fromList (mapMaybe kv assocs) where kv (S.Assoc k v) = do key <- exprToSimpleString k <|> (case k of { S.Var _ (S.NoQ n) -> Just (S.nstr n); _ -> Nothing }) val <- exprToSimpleString v pure (key, val) kv _ = Nothing exprToOptions _ = Nothing exprToListStrings :: S.Expr -> Maybe [String] exprToListStrings (S.List _ elems) = Just $ mapMaybe elemStr elems where elemStr (S.Elem e) = exprToSimpleString e elemStr _ = Nothing exprToListStrings _ = Nothing -- No fallback text parsing; we rely on the AST exclusively for semantics and -- use source locations only to find brace body spans for splicing. ================================================ FILE: compiler/lib/src/Acton/Builtin.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- module Acton.Builtin where import Utils import Acton.Syntax selfKW = name "self" initKW = name "__init__" fromiterKW = name "__fromiter__" fromatomKW = name "__fromatom__" lenKW = name "__len__" enterKW = name "__enter__" exitKW = name "__exit__" iterKW = name "__iter__" nextKW = name "__next__" containsKW = name "__contains__" containsnotKW = name "__containsnot__" getitemKW = name "__getitem__" setitemKW = name "__setitem__" delitemKW = name "__delitem__" getsliceKW = name "__getslice__" setsliceKW = name "__setslice__" delsliceKW = name "__delslice__" appendKW = name "append" boolKW = name "__bool__" strKW = name "__str__" reprKW = name "__repr__" cleanupKW = name "__cleanup__" resumeKW = name "__resume__" valueKWs = [boolKW, strKW, reprKW] iaddKW = name "__iadd__" isubKW = name "__isub__" imulKW = name "__imul__" ipowKW = name "__ipow__" itruedivKW = name "__itruediv__" imodKW = name "__imod__" ifloordivKW = name "__ifloordiv__" ilshiftKW = name "__ilshift__" irshiftKW = name "__irshift__" iorKW = name "__ior__" ixorKW = name "__ixor__" iandKW = name "__iand__" imatmulKW = name "__imatmul__" incrBinopKWs = [iaddKW, isubKW, imulKW, ipowKW, itruedivKW, imodKW, ifloordivKW, ilshiftKW, irshiftKW, iorKW, ixorKW, iandKW, imatmulKW] addKW = name "__add__" subKW = name "__sub__" mulKW = name "__mul__" powKW = name "__pow__" truedivKW = name "__truediv__" modKW = name "__mod__" floordivKW = name "__floordiv__" lshiftKW = name "__lshift__" rshiftKW = name "__rshift__" orKW = name "__or__" xorKW = name "__xor__" andKW = name "__and__" matmulKW = name "__matmul__" binopKWs = [addKW, subKW, mulKW, powKW, truedivKW, modKW, floordivKW, lshiftKW, rshiftKW, orKW, xorKW, andKW, matmulKW] posKW = name "__pos__" negKW = name "__neg__" invertKW = name "__invert__" unopKWs = [posKW, negKW, invertKW] eqKW = name "__eq__" neKW = name "__ne__" ltKW = name "__lt__" leKW = name "__le__" gtKW = name "__gt__" geKW = name "__ge__" isKW = name "__is__" isnotKW = name "__isnot__" compareKWs = [eqKW, neKW, ltKW, leKW, gtKW, geKW, isKW, isnotKW] eqordKWs = [eqKW, neKW, ltKW, leKW, gtKW, geKW] nBuiltin = name "__builtin__" mBuiltin = ModName [nBuiltin] gBuiltin n = GName mBuiltin n nValue = name "value" nAtom = name "atom" nObject = name "object" nInt = name "int" nI32 = name "i32" nI16 = name "i16" nU64 = name "u64" nU32 = name "u32" nU16 = name "u16" nBigint = name "bigint" nFloat = name "float" nComplex = name "complex" nBool = name "bool" nStr = name "str" nRepr = name "repr" nBytes = name "bytes" nRef = name "Ref" nMsg = name "Msg" nBaseException = name "BaseException" nException = name "Exception" nStopIteration = name "StopIteration" nValueError = name "ValueError" --- nRange = name "range" nLen = name "len" nPrint = name "print" nPrintn = name "printn" nDict = name "dict" nList = name "list" nSetT = name "set" nSlice = name "slice" nIterator = name "Iterator" --- nSequence = name "Sequence" nMapping = name "Mapping" nSetP = name "Set" nIndexed = name "Indexed" nSliceable = name "Sliceable" nHashable = name "Hashable" nPlus = name "Plus" nMinus = name "Minus" nTimes = name "Times" nDiv = name "Div" nNumber = name "Number" nReal = name "Real" nRealFloat = name "RealFloat" nRational = name "Rational" nIntegral = name "Integral" nLogical = name "Logical" nMatrix = name "Matrix" nEq = name "Eq" nOrd = name "Ord" nIdentity = name "Identity" nCollection = name "Collection" nContainer = name "Container" nIterable = name "Iterable" nContextManager = name "ContextManager" nShow = name "Show" --- nTuple = name "tuple" nNoneType = name "NoneType" nNone = name "None" nTrue = name "True" nFalse = name "False" qnValue = gBuiltin nValue qnAtom = gBuiltin nAtom qnObject = gBuiltin nObject qnInt = gBuiltin nInt qnI32 = gBuiltin nI32 qnI16 = gBuiltin nI16 qnU64 = gBuiltin nU64 qnU32 = gBuiltin nU32 qnU16 = gBuiltin nU16 qnBigint = gBuiltin nBigint qnFloat = gBuiltin nFloat qnComplex = gBuiltin nComplex qnBool = gBuiltin nBool qnStr = gBuiltin nStr qnRepr = gBuiltin nRepr qnBytes = gBuiltin nBytes qnRef = gBuiltin nRef qnMsg = gBuiltin nMsg qnBaseException = gBuiltin nBaseException qnException = gBuiltin nException qnStopIteration = gBuiltin nStopIteration qnValueError = gBuiltin nValueError --- qnRange = gBuiltin nRange qnPrint = gBuiltin nPrint qnPrintn = gBuiltin nPrintn qnDict = gBuiltin nDict qnList = gBuiltin nList qnSetT = gBuiltin nSetT qnSlice = gBuiltin nSlice qnIterator = gBuiltin nIterator --- qnSequence = gBuiltin nSequence qnMapping = gBuiltin nMapping qnSetP = gBuiltin nSetP qnIndexed = gBuiltin nIndexed qnSliceable = gBuiltin nSliceable qnHashable = gBuiltin nHashable qnPlus = gBuiltin nPlus qnMinus = gBuiltin nMinus qnTimes = gBuiltin nTimes qnDiv = gBuiltin nDiv qnNumber = gBuiltin nNumber qnReal = gBuiltin nReal qnRealFloat = gBuiltin nRealFloat qnRational = gBuiltin nRational qnIntegral = gBuiltin nIntegral qnLogical = gBuiltin nLogical qnMatrix = gBuiltin nMatrix qnEq = gBuiltin nEq qnOrd = gBuiltin nOrd qnIdentity = gBuiltin nIdentity qnCollection = gBuiltin nCollection qnContainer = gBuiltin nContainer qnIterable = gBuiltin nIterable qnContextManager = gBuiltin nContextManager qnShow = gBuiltin nShow --- qnTuple = gBuiltin nTuple qnNoneType = gBuiltin nNoneType qnNone = gBuiltin nNone qnTrue = gBuiltin nTrue qnFalse = gBuiltin nFalse cValue = TC qnValue [] cAtom = TC qnAtom [] cObject = TC qnObject [] cInt = TC qnInt [] cI32 = TC qnI32 [] cI16 = TC qnI16 [] cU64 = TC qnU64 [] cU32 = TC qnU32 [] cU16 = TC qnU16 [] cBigint = TC qnBigint [] cFloat = TC qnFloat [] cComplex = TC qnComplex [] cBool = TC qnBool [] cStr = TC qnStr [] cRepr = TC qnRepr [] cBytes = TC qnBytes [] cRef = TC qnRef [] cMsg a = TC qnMsg [a] cList a = TC qnList [a] cDict a b = TC qnDict [a,b] cSet a = TC qnSetT [a] cSlice = TC qnSlice [] cIterator a = TC qnIterator [a] cBaseException = TC qnBaseException [] cException = TC qnException [] cStopIteration = TC qnStopIteration [] cValueError = TC qnValueError [] --- pSequence a = TC qnSequence [a] pMapping a b = TC qnMapping [a,b] pSet a = TC qnSetP [a] pIndexed a b = TC qnIndexed [a,b] pSliceable a = TC qnSliceable [a] pHashable = TC qnHashable [] pPlus = TC qnPlus [] pMinus = TC qnMinus [] pTimes a = TC qnTimes [a] pDiv a = TC qnDiv [a] pNumber = TC qnNumber [] pReal = TC qnReal [] pRealFloat = TC qnRealFloat [] pRational = TC qnRational [] pIntegral = TC qnIntegral [] pLogical = TC qnLogical [] pMatrix = TC qnMatrix [] pEq = TC qnEq [] pOrd = TC qnOrd [] pIdentity = TC qnIdentity [] pCollection a = TC qnCollection [a] pContainer a = TC qnContainer [a] pIterable a = TC qnIterable [a] pContextManager = TC qnContextManager [] pShow = TC qnShow [] tValue = tCon cValue tAtom = tCon cAtom tObject = tCon cObject tInt = tCon cInt tI32 = tCon cI32 tI16 = tCon cI16 tU64 = tCon cU64 tU32 = tCon cU32 tU16 = tCon cU16 tBigint = tCon cBigint tFloat = tCon cFloat tComplex = tCon cComplex tBool = tCon cBool tStr = tCon cStr tBytes = tCon cBytes tRef = tCon cRef tMsg a = tCon (cMsg a) tList a = tCon (cList a) tDict a b = tCon (cDict a b) tSet a = tCon (cSet a) tSlice = tCon cSlice tIterator a = tCon (cIterator a) tBaseException = tCon cBaseException tException = tCon cException tStopIteration = tCon cStopIteration tValueError = tCon cValueError --- tSequenceW self a = tCon (TC qnSequence [self,a]) tMappingW self a b = tCon (TC qnMapping [self, a, b]) tSetW self a = tCon (TC qnSetP [self, a]) tCollectionW self a = tCon (TC qnCollection [self, a]) tHashableW self = tCon (TC qnHashable [self]) witSequenceList = gBuiltin (Derived nSequence nList) witSetSet = gBuiltin (Derived nSetP nSetT) witMappingDict = gBuiltin (Derived nMapping nDict) ================================================ FILE: compiler/lib/src/Acton/CPS.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} module Acton.CPS(convert) where import Debug.Trace import Control.Monad.State.Strict import Control.Monad.Writer import Utils import Pretty import Acton.Syntax import Acton.Printer import Acton.Names import Acton.Builtin import Acton.Prim import Acton.NameInfo import Acton.Env import Acton.QuickType convert :: Env0 -> Module -> IO (Module, Env0) convert env0 m = return (runCpsM (convMod m), mapModules1 (conv env) env0) where env = cpsEnv env0 convMod (Module m imps mdoc ss) = do ss' <- preSuite env ss --traceM ("######## preCPS:\n" ++ render (vcat $ map pretty ss') ++ "\n########") Module m imps mdoc <$> cps env ss' type CpsM a = State CpsState a type CpsState = ([Int], [Stmt]) runCpsM :: CpsM a -> a runCpsM m = evalState m ([1..], []) contKW = Internal CPSPass "cont" 0 newName :: String -> CpsM Name newName s = state (\(uniq:supply, stmts) -> (Internal CPSPass s uniq, (supply, stmts))) prefix :: [Stmt] -> CpsM () prefix ss = state (\(supply, stmts) -> ((), (supply, reverse ss ++ stmts))) swapPrefixes :: [Stmt] -> CpsM [Stmt] swapPrefixes ss = state (\(supply, stmts) -> (stmts, (supply, ss))) withPrefixes :: CpsM a -> CpsM ([Stmt],a) withPrefixes m = do ss0 <- swapPrefixes [] r <- m ss1 <- swapPrefixes ss0 return (reverse ss1, r) data Frame = Meth Name Type -- contParam with type | Seq Name [Name] -- nextCont with extra args | Loop Name [Name] -- loopEntry with extra args deriving (Eq,Show) instance Pretty Frame where pretty (Meth n t) = text "Meth" <+> pretty n pretty (Seq n ns) = text "Seq" <+> pretty n pretty (Loop n ns) = text "Loop" <+> pretty n type CPSEnv = EnvF CPSX data CPSX = CPSX { ctxtX :: [Frame], volatileX :: [Name] } data Where = OnTop | InClass | InDef | InInnerLoop deriving (Eq,Show) cpsEnv env0 = setX env0 CPSX{ ctxtX = [], volatileX = [] } ctxt env = ctxtX $ envX env infixr +: frame +: env = modX env $ \x -> x{ ctxtX = frame : ctxtX x } clearCtxt env = modX env $ \x -> x{ ctxtX = [] } setVolatiles ns env = modX env $ \x -> x{ volatileX = ns } volatiles env = volatileX (envX env) eCallCont e (c,t) = eCall (tApp (eQVar primRContc) [t]) [c, e] eCallCont0 (c, ns) = eCallCont eNone (c',tNone) where c' = kRef c ns g_skip tNone cntcont (Seq _ _ : ctx) = cntcont ctx -- 'continue' followed by some cmd: ignore it cntcont (Loop c ns : ctx) = (c, ns) -- inside a loop: jump to its top brkcont (Seq _ _ : ctx) = brkcont ctx -- 'break' followed by some cmd: ignore it brkcont (Loop _ _ : ctx) = seqcont ctx -- inside a loop: jump to what follows seqcont (Seq c ns : ctx) = (c, ns) -- end of sequence followed by some cmd: jump to it seqcont (Loop c ns : ctx) = (c, ns) -- inside a loop: jump to its top seqcont (Meth c _ : _) = (c, []) -- in a method: jump to its continuation retcont (Seq _ _ : ctx) = retcont ctx -- 'return' followed by some cmd: ignore it retcont (Loop _ _ : ctx) = retcont ctx -- inside a loop: ignore it retcont (Meth c t : _) = (eVar c, t) -- in a method: jump to its continuation class CPS a where cps :: CPSEnv -> a -> CpsM a instance CPS [Stmt] where cps env [] | inCont env = return [sReturn $ eCallCont0 $ seqcont $ ctxt env] cps env (Continue _ : _) | inCont env = return [sReturn $ eCallCont0 $ cntcont $ ctxt env] cps env (Break _ : _) | inCont env = return [sReturn $ eCallCont0 $ brkcont $ ctxt env] cps env (Return _ Nothing : _) | inCont env = return [sReturn $ eCallCont eNone $ retcont $ ctxt env] cps env (Return _ (Just e) : _) | contCall env e = return [sReturn $ addContArg env (conv env e) $ fst $ retcont $ ctxt env] | inCont env = return [sReturn $ eCallCont (conv env e) $ retcont $ ctxt env] cps env (Assign _ [PVar _ n (Just _)] e : Return _ (Just e') : _) | contCall env e, e' == eVar n = return [sReturn $ addContArg env (conv env e) $ fst $ retcont $ ctxt env] cps env [Expr _ e] | contCall env e = return [sReturn $ addContArg env (conv env e) $ cont $ seqcont $ ctxt env] where t = typeOf env e cont (c,ns) = if t == tNone then c' else eCall (tApp (eQVar primSKIPRESc) [t]) [c'] where c' = kRef c ns g_skip t cps env (Expr _ e : ss) | contCall env e = do k <- newName "cont" x <- newName "res" ss' <- cps env ss --traceM ("## kDef Expr " ++ prstr k ++ ", updates: " ++ prstrs nts) return $ kDef env k nts x t ss' : sReturn (addContArg env (conv env e) (kRef k (dom nts) x t)) : [] where t = typeOf env e nts = extraBinds env ss cps env ss0@(Assign l [p] e : ss) | contCall env e = do k <- newName "cont" x <- newName "res" ss' <- cps (define [(x,NVar t)] env) (Assign l [p] (eVar x) : ss) --traceM ("## kDef Assign " ++ prstr k ++ ", updates: " ++ prstrs nts) return $ kDef env k nts x t ss' : sReturn (addContArg env (conv env e) (kRef k (dom nts) x t)) : [] where t = typeOf env e nts = extraBinds env ss0 cps env (MutAssign l tg e : ss) | contCall env e = do k <- newName "cont" x <- newName "res" ss' <- cps env (MutAssign l tg (eVar x) : ss) --traceM ("## kDef MutAssign " ++ prstr k ++ ", updates: " ++ prstrs nts) return $ kDef env k nts x t ss' : sReturn (addContArg env (conv env e) (kRef k (dom nts) x t)) : [] where t = typeOf env e nts = extraBinds env ss cps env (Decl l ds : ss) = do ds' <- mapM (cps env1) ds ss' <- cps env1 ss return $ sDecl ds' : ss' where env1 = define (envOf ds) env cps env (s : ss) | not (needCont env s) = do ss' <- cps env1 ss --traceM ("### SIMPLE: " ++ prstr s) return $ conv env s : ss' where env1 = define (envOf s) env cps env s@[If _ [Branch e ss1] ss2] | isPUSH e = do k <- newName "try" x <- newName "res" ss1 <- cps env (map convPOPDROP ss1) ss2 <- cps env (map convPOPDROP ss2) let body = sIf1 (eVar x) ss1 ss2 : [] --traceM ("## kDef PUSH " ++ prstr k ++ ", updates: " ++ prstrs nts) return $ kDef env k nts x tBool body : sReturn (convPUSH e $ kRef k (dom nts) x tBool) : [] where nts = extraBinds env s cps env [If _ bs els] = do bs' <- mapM (cps env) bs els' <- cps env els return $ sIf bs' els' : [] cps env (If l bs els : s@(Expr _ e) : _) | isRAISE e = cps env [If l [ Branch e (ss++[s]) | Branch e ss <- bs ] (els++[s])] cps env s@[While _ e b els] = do k <- newName "loop" x <- newName "res" b' <- cps (Loop k (dom nts) +: env) b els' <- cps env els let body = sIf1 (conv env e) b' els' : [] --traceM ("## kDef While " ++ prstr k ++ ", updates: " ++ prstrs nts) return $ kDef env k nts x tNone body : kJump k nts where nts = extraBinds env s cps env (s : ss) = do k <- newName "cont" x <- newName "res" ss' <- cps env1 ss s' <- cps (Seq k (dom nts) +: env) [s] --traceM ("## kDef Seq " ++ prstr k ++ ", live/updates: " ++ prstrs nts) return $ kDef env k nts x tNone ss' : s' where env1 = define (envOf s) env nts0 = nvarsOf (envOf s) `restrict` free ss nts = nts0 ++ extraBinds env1 ss cps env [] = return [] extraBinds env ss = [ (x, t) | x <- nub $ updatesOf ss, x `notElem` volatiles env, Just t <- [lookupVar x env] ] volatileVars env stmts = nub $ vols env stmts where vols env [] = [] vols env (s:ss) = vol env s ++ vols (define (envOf s) env) ss vol env s@(If _ [Branch e ss] els) | isPUSH e, needCont env s = updatesOf ss ++ vols env ss ++ vols env els vol env (If _ bs els) = concat [ vols env ss | Branch _ ss <- bs ] ++ vols env els vol env (While _ _ ss els) = vols env ss ++ vols env els vol env _ = [] instance CPS Decl where cps env (Class l n q cs b ddoc) = do b' <- cps env1 b return $ Class l n (conv env q) (conv env cs) b' ddoc where env1 = defineTVars (selfQuant (NoQ n) q) $ clearCtxt $ setInClass env cps env (Def l n q p KwdNIL (Just t) b dec fx ddoc) | contFX fx = do --traceM ("#### Converting " ++ prstr n) b' <- cps env2 b return $ Def l n q' (addContPar env dec p' fx t') KwdNIL (Just tR) (volinits ++ b') dec fx ddoc | otherwise = do --traceM ("#### Preserving " ++ prstr n) b' <- cps env1 b return $ Def l n q' p' KwdNIL (Just t') b' dec fx ddoc where env2 = setVolatiles volvs $ Meth contKW t' +: env1 env1 = define (envOf p) $ defineTVars q $ clearCtxt $ setInDef env volvs = volatileVars env2 b volinits = [ sAssign (pVar v (tBox t)) (eCall (tApp (eQVar primBox) [t]) [eVar v]) | (v,NVar t) <- envOf p, v `elem` volvs ] q' = conv env q p' = conv env p t' = conv env t cps env d = error ("cps unexpected: " ++ prstr d) instance CPS Branch where cps env (Branch e ss) = Branch (conv env e) <$> cps env ss kJump k nts = sReturn (eCall (eVar k) $ eNone : map eVar (dom nts)) : [] addContArg env (Call l e p KwdNil) c = Call NoLoc e (PosArg c p) KwdNil addContPar env dec (PosPar n a Nothing p) fx t | inClass env && dec /= Static = PosPar n a Nothing (addContPar0 p fx t) addContPar env dec p fx t = addContPar0 p fx t addContPar0 p fx t = PosPar contKW (Just $ tCont1 fx t) Nothing p tCont0 = tFun fxProc (posRow tNone posNil) kwdNil tR tCont1 fx t = tFun fx (posRow t posNil) kwdNil tR kDef env k nts x t b = sDef k (conv env $ pospar $ (x,t):nts) tR b fxProc kRef k [] x t = eVar k kRef k ns x t = eLambda' [(x,t)] $ eCall (eVar k) (map eVar (x:ns)) fxCall env test (Call _ Async{} p k) = False fxCall env test (Call _ e p k) = test fx where TFun _ fx _ _ _ = typeOf env e fxCall env test e = False contCall env e = fxCall env contFX e mutCall env e = fxCall env mutFX e contFX (TFX _ FXProc) = True contFX _ = False mutFX (TFX _ FXMut) = True mutFX (TFX _ FXProc) = True mutFX _ = False inCont env = length (ctxt env) > 0 convPOPDROP s@(If _ [Branch e _] _) | isPUSH e = s convPOPDROP (If l bs els) = If l [ Branch e (map convPOPDROP ss) | Branch e ss <- bs ] (map convPOPDROP els) convPOPDROP (While l e ss els) = While l e (map convPOPDROP ss) (map convPOPDROP els) convPOPDROP (Expr l (Call l1 e ps ks)) | Var l2 x <- e, x == primDROP = Expr l (Call l1 (Var l2 primDROP_C) ps ks) convPOPDROP (Assign l p (Call l1 e ps ks)) | Var l2 x <- e, x == primPOP = Assign l p (Call l1 (Var l2 primPOP_C) ps ks) convPOPDROP s = s convPUSH (Call _ (Var _ x) _ _) arg | x == primPUSH = eCall (eQVar primPUSH_Cc) [arg] | x == primPUSHF = eCall (eQVar primPUSHF_Cc) [arg] class NeedCont a where needCont :: CPSEnv -> a -> Bool instance (NeedCont a, EnvOf a) => NeedCont [a] where needCont env [] = False needCont env (s : ss) = needCont env s || needCont (define (envOf s) env) ss instance NeedCont Branch where needCont env (Branch e ss) = needCont env ss instance NeedCont Stmt where needCont env (Return _ _) = inCont env needCont env (Continue _) | inLoop env = False | otherwise = inCont env needCont env (Break _) | inLoop env = False | otherwise = inCont env needCont env (Expr _ e) = contCall env e needCont env (Assign _ _ e) = contCall env e needCont env (MutAssign _ _ e) = contCall env e needCont env (If _ bs els) = needCont env bs || needCont env els needCont env (While _ _ ss els) = needCont (setInLoop env) ss || needCont env els needCont env (Decl _ ds) = needCont (define (envOf ds) env) ds needCont env _ = False instance NeedCont Decl where needCont env Class{} = True needCont env d@Def{} = contFX (dfx d) ------------------------------------------------ ------------------------------------------------ ------------------------------------------------ class PreCPS a where pre :: CPSEnv -> a -> CpsM a preTop :: CPSEnv -> a -> CpsM a preTop env = pre env instance PreCPS Module where pre env (Module m imps mdoc ss) = Module m imps mdoc <$> preSuite env ss preSuite env [] = return [] preSuite env (s : ss) = do (prefixes,s') <- withPrefixes $ pre env s ss' <- preSuite (define (envOf s) env) ss return (prefixes ++ s' : ss') instance (PreCPS a, EnvOf a) => PreCPS [a] where pre env [] = return [] pre env (a:as) = (:) <$> pre env a <*> pre env1 as where env1 = define (envOf a) env instance PreCPS a => PreCPS (Maybe a) where pre env Nothing = return Nothing pre env (Just a) = fmap Just (pre env a) preTop env Nothing = return Nothing preTop env (Just a) = fmap Just (preTop env a) instance PreCPS Stmt where pre env (Expr l e) = Expr l <$> preTop env e pre env (Assign l ps e) = Assign l ps <$> preTop env e pre env (MutAssign l t e) = MutAssign l <$> pre env t <*> preTop env e pre env (Return l e) = Return l <$> preTop env e pre env (If l bs els) = If l <$> pre env bs <*> preSuite env els -- TODO: rewrite in case the 'bs' produce out-of-order prefixes pre env (While l e b els) = While l <$> pre env e <*> preSuite env b <*> preSuite env els pre env (Decl l ds) = Decl l <$> pre env1 ds where env1 = define (envOf ds) env pre env s = return s instance PreCPS Decl where pre env (Class l n q cs b ddoc) = Class l n q cs <$> pre env1 b <*> pure ddoc where env1 = defineTVars (selfQuant (NoQ n) q) env pre env (Def l n q p _k a b d fx ddoc) = Def l n q p _k a <$> preSuite env1 b <*> pure d <*> pure fx <*> pure ddoc where env1 = define (envOf p) $ defineTVars q env instance PreCPS Branch where pre env (Branch e ss) = Branch <$> pre env e <*> preSuite env ss instance PreCPS Handler where pre env (Handler ex ss) = Handler ex <$> preSuite env1 ss where env1 = define (envOf ex) env instance PreCPS PosArg where pre env (PosArg e p) = PosArg <$> pre env e <*> pre env p pre env PosNil = return PosNil instance PreCPS Expr where pre env e0@(Call l e ps KwdNil) | mutCall env e0 = do e1 <- pre env e ps1 <- pre env ps v <- newName "pre" prefix [sAssign (pVar v t) (Call l e1 ps1 KwdNil)] return (eVar v) | otherwise = Call l <$> pre env e <*> pre env ps <*> pure KwdNil where t = typeOf env e0 pre env (Async l e) = Async l <$> pre env e pre env (TApp l e ts) = TApp l <$> pre env e <*> pure ts pre env (Let l ss e) = do ss' <- preSuite env ss (prefixes,e') <- withPrefixes $ pre env1 e -- Let suites are emitted directly by CodeGen and never -- pass through the statement-level CPS conversion, so we -- must lift their rewritten statements into outer prefixes. prefix (ss' ++ prefixes) return e' where env1 = define (envOf ss) env pre env (Cond l e1 e e2) = do (pre1,e1') <- withPrefixes $ pre env e1 (pre2,e2') <- withPrefixes $ pre env e2 (pre0,e0') <- withPrefixes $ pre env e case pre1++pre2 of [] -> do prefix pre0 return $ Cond l e1' e0' e2' _ -> do v <- newName "pre" let s1 = pre1 ++ [sAssign (pVar v t) e1'] s2 = pre2 ++ [sAssign (pVar v t) e2'] prefix $ pre0 ++ [sIf1 e0' s1 s2] return $ eVar v where t = upbound env $ map (typeOf env) [e1,e2] pre env (IsInstance l e c) = IsInstance l <$> pre env e <*> return c pre env (BinOp l e1 Or e2) = do (pre1,e1') <- withPrefixes $ pre env e1 (pre2,e2') <- withPrefixes $ pre env e2 case pre2 of [] -> do prefix pre1 return $ BinOp l e1' Or e2' _ -> do x <- newName "pre" v <- newName "pre" let s1 = [sAssign (pVar v t) (eVar x)] s2 = pre2 ++ [sAssign (pVar v t) e2'] prefix $ pre1 ++ [sAssign (pVar x t1) e1', sIf1 (eVar x) s1 s2] return $ eVar v where t = upbound env $ map (typeOf env) [e1,e2] t1 = typeOf env e1 pre env (BinOp l e1 And e2) = do (pre1,e1') <- withPrefixes $ pre env e1 (pre2,e2') <- withPrefixes $ pre env e2 case pre2 of [] -> do prefix pre1 return $ BinOp l e1' And e2' _ -> do x <- newName "pre" v <- newName "pre" let s1 = pre2 ++ [sAssign (pVar v t) e2'] s2 = [sAssign (pVar v t) (eVar x)] prefix $ pre1 ++ [sAssign (pVar x t1) e1', sIf1 (eVar x) s1 s2] return $ eVar v where t = upbound env $ map (typeOf env) [e1,e2] t1 = typeOf env e1 pre env (UnOp l Not e) = UnOp l Not <$> pre env e pre env (Dot l e n) = Dot l <$> pre env e <*> return n pre env (DotI l e i) = DotI l <$> pre env e <*> return i pre env (RestI l e i) = RestI l <$> pre env e <*> return i pre env (Lambda l p KwdNIL e fx) = do (prefixes,e') <- withPrefixes $ preTop env1 e case prefixes of [] | contFX fx -> let p' = conv env p; t' = conv env t e1 = if contCall env e then addContArg env1 e' econt else eCallCont e' (econt,t') in return $ Lambda l (addContPar0 p' fx t') KwdNIL e1 fx | otherwise -> return $ Lambda l p KwdNIL e' fx _ -> do f <- newName "lambda" prefix [sDecl [Def l f [] p KwdNIL (Just t) (prefixes ++ [sReturn e']) NoDec fx Nothing]] return (Var l0 (NoQ f)) where env1 = define (envOf p) env t = typeOf env1 e econt = eVar contKW pre env (Yield l e) = Yield l <$> pre env e pre env (YieldFrom l e) = YieldFrom l <$> pre env e pre env (Tuple l es KwdNil) = Tuple l <$> pre env es <*> pure KwdNil pre env (List l es) = List l <$> pre env es pre env (Dict l as) = Dict l <$> pre env as pre env (Set l es) = Set l <$> pre env es pre env e = return e preTop env e0@(Call l e ps KwdNil) | mutCall env e0 = Call l <$> pre env e <*> pre env ps <*> pure KwdNil preTop env e = pre env e instance PreCPS Elem where pre env (Elem e) = Elem <$> pre env e instance PreCPS Assoc where pre env (Assoc k v) = Assoc <$> pre env k <*> pre env v -- Convert types ---------------------------------------------------------------------------------------- class Conv a where conv :: CPSEnv -> a -> a instance (Conv a) => Conv [a] where conv env = map $ conv env instance (Conv a) => Conv (Maybe a) where conv env = fmap $ conv env instance (Conv a) => Conv (Name, a) where conv env (n, x) = (n, conv env x) instance Conv NameInfo where conv env (NClass q ps te doc) = NClass q (conv env ps) (conv env te) doc conv env (NSig sc dec doc) = NSig (conv env sc) dec doc conv env (NDef sc dec doc) = NDef (conv env sc) dec doc conv env (NVar t) = NVar (conv env t) conv env (NSVar t) = NSVar (conv env t) conv env ni = ni instance Conv WTCon where conv env (w,c) = (w, conv env c) instance Conv TSchema where conv env (TSchema l q t) = TSchema l (conv env q) (conv env t) instance Conv QBind where conv env (QBind v cs) = QBind v (conv env cs) instance Conv Type where conv env t0@(TFun l fx p TNil{} t) | contFX fx && t /= tR = TFun l fx (addCont (conv env p) (conv env t)) kwdNil tR | otherwise = TFun l fx (conv env p) kwdNil (conv env t) where addCont p c = posRow (tFun fx (posRow c posNil) kwdNil tR) p conv env (TCon l c) = TCon l (conv env c) conv env (TTuple l p k) = TTuple l (conv env p) (conv env k) conv env (TOpt l t) = TOpt l (conv env t) conv env (TRow l k n t r) = TRow l k n (conv env t) (conv env r) conv env t = t instance Conv TCon where conv env (TC c ts) = TC c (conv env ts) instance Conv PosPar where conv env (PosPar n t Nothing p) = PosPar n (conv env t) Nothing (conv env p) conv env PosNIL = PosNIL instance Conv Stmt where conv env (Expr l e) = Expr l (conv env e) conv env (Assign l [PVar _ n Nothing] e) | n `elem` volatiles env = MutAssign l (eDot (eVar n) valKW) (conv env e) conv env (Assign l [PVar _ n (Just t)] e) | n `elem` volatiles env = Assign l [pVar n (tBox t)] (eCall (tApp (eQVar primBox) [t]) [conv env e]) conv env (Assign l ps e) = Assign l (conv env ps) (conv env e) conv env (MutAssign l tg e) = MutAssign l (conv env tg) (conv env e) conv env (Return l e) = Return l (conv env e) conv env (If l bs els) = If l (conv env bs) (conv env els) conv env (While l e b els) = While l (conv env e) (conv env b) (conv env els) conv env (Signature l ns sc dec) = Signature l ns (conv env sc) dec conv env s = s instance Conv Branch where conv env (Branch e ss) = Branch (conv env e) (conv env ss) instance Conv Pattern where conv env (PVar l n t) = PVar l n (conv env t) conv env p = p instance Conv Expr where conv env (Var l (NoQ n)) | n `elem` volatiles env = Dot l (Var l (NoQ n)) valKW conv env (Var l n) | n == primASYNCf = Var l primASYNCc | n == primAFTERf = Var l primAFTERc | n == primAWAITf = Var l primAWAITc | otherwise = Var l n conv env (Call l e ps KwdNil) = Call l (conv env e) (conv env ps) KwdNil conv env (Async l e) = Async l (conv env e) conv env (TApp l e ts) = TApp l (conv env e) (conv env ts) conv env (Let l ss e) = Let l (conv env1 ss) (conv env1 e) where env1 = define (envOf ss) env conv env (Cond l e1 e e2) = Cond l (conv env e1) (conv env e) (conv env e2) conv env (IsInstance l e c) = IsInstance l (conv env e) c conv env (BinOp l e1 Or e2) = BinOp l (conv env e1) Or (conv env e2) conv env (BinOp l e1 And e2) = BinOp l (conv env e1) And (conv env e2) conv env (UnOp l Not e) = UnOp l Not (conv env e) conv env (Dot l e n) = Dot l (conv env e) n conv env (DotI l e i) = DotI l (conv env e) i conv env (RestI l e i) = RestI l (conv env e) i conv env (Lambda l p KwdNIL e fx) = Lambda l (conv env p) KwdNIL (conv env e) fx conv env (Yield l e) = Yield l (conv env e) conv env (YieldFrom l e) = YieldFrom l (conv env e) conv env (Tuple l es ks) = Tuple l (conv env es) (conv env ks) conv env (List l es) = List l (conv env es) conv env (Dict l as) = Dict l (conv env as) conv env (Set l es) = Set l (conv env es) conv env e = e instance Conv PosArg where conv env (PosArg e p) = PosArg (conv env e) (conv env p) conv env PosNil = PosNil instance Conv KwdArg where conv env (KwdArg n e p) = KwdArg n (conv env e) (conv env p) conv env KwdNil = KwdNil instance Conv Elem where conv env (Elem e) = Elem (conv env e) instance Conv Assoc where conv env (Assoc k v) = Assoc (conv env k) (conv env v) ================================================ FILE: compiler/lib/src/Acton/CodeGen.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, DeriveGeneric #-} module Acton.CodeGen where import qualified Data.Set import qualified Data.List import qualified Acton.Env import Utils import Pretty import Acton.Syntax import Acton.Names import Acton.Builtin import Acton.Printer import Acton.Prim import Acton.NameInfo import Acton.Env import Acton.QuickType import Acton.Subst import qualified Acton.Boxing as B import Control.Monad.State.Lazy import Prelude hiding ((<>)) import System.FilePath.Posix import Numeric -- For fast SrcLoc offset->line lookup when emitting #line import qualified Data.IntMap.Strict as IM generate :: Acton.Env.Env0 -> FilePath -> String -> Bool -> Module -> String -> IO (String,String,String) generate env srcbase srcText emitLines m hash = do return (n, h, c) where n = concat (Data.List.intersperse "." (modPath (modname m))) --render $ quotes $ gen env0 (modname m) hashComment = text "/* Acton impl hash:" <+> text hash <+> text "*/" h = render $ hashComment $+$ hModule env0 m c = render $ hashComment $+$ cModule env0 srcbase srcText emitLines m env0 = genEnv $ setMod (modname m) env genRoot :: Acton.Env.Env0 -> QName -> IO String genRoot env0 qn@(GName m n) = do return $ render (cInclude $+$ cIncludeMods $+$ cInit $+$ cRoot) where env = genEnv $ setMod m env0 cInclude = text "#include \"rts/common.h\"" cIncludeMods = include env "out/types" m cInit = (text "void" <+> gen env primROOTINIT <+> parens empty <+> char '{') $+$ nest 4 (gen env (GName m initKW) <> parens empty <> semi) $+$ char '}' cRoot = (gen env tActor <+> gen env primROOT <+> parens empty <+> char '{') $+$ nest 4 (text "return" <+> parens (gen env tActor) <> gen env primNEWACTOR <> parens (gen env qn) <> semi) $+$ char '}' myPretty (GName m n) | m == mBuiltin = text ("B_" ++ nstr n) | otherwise = pretty m <> dot <> pretty n myPretty (NoQ w@(Internal _ _ _)) = pretty w instName (GName m n) = GName m (Derived n (globalName "instance")) methName (GName m n) = GName m (Derived n (globalName "methods")) derivedHead (Derived d@(Derived{}) _) = derivedHead d derivedHead (Derived n _) = n staticWitnessName (Dot _ c@(Call _ _ _ KwdNil) a) = (nm, NoQ a:as) where (nm,as) = staticWitnessName c staticWitnessName (Call _ (Var _ v@(GName m n)) PosNil KwdNil) | m == mBuiltin = (Just v, []) staticWitnessName (Call _ (TApp _ (Var _ (GName m n@(Derived n1 n2))) [TCon _ (TC gn1 []), _]) _ KwdNil) | m == mBuiltin && n1 == nMapping && n2 == nDict && gn1 == qnInt = (Just (gBuiltin (Derived n nInt)),[]) staticWitnessName (Call _ (TApp _ (Var _ (GName m n@(Derived n1 n2))) [TCon _ (TC gn1 []), _]) _ KwdNil) | m == mBuiltin && n1 == nMapping && n2 == nDict && gn1 == qnStr = (Just (gBuiltin (Derived n nStr)),[]) staticWitnessName (Call _ (TApp _ (Var _ v@(GName m n)) _) PosNil KwdNil) | m == mBuiltin = (Just v, []) staticWitnessName _ = (Nothing, []) -- Environment -------------------------------------------------------------------------------------- genEnv env0 = setX env0 GenX{ globalX = [], localX = [], retX = tNone, volVarsX = [], lineEmitX = Nothing } type GenEnv = EnvF GenX data GenX = GenX { globalX :: [Name] , localX :: [Name] , retX :: Type , volVarsX :: [Name] , lineEmitX :: Maybe (SrcLoc -> Doc) } gdefine te env = modX env1 $ \x -> x{ globalX = dom te ++ globalX x } where env1 = define te env ldefine te env = modX env1 $ \x -> x{ localX = dom te ++ localX x } where env1 = define te env classdefine stmts env = gdefine [ (n,i) | (n,i@NClass{}) <- envOf stmts ] env setRet t env = modX env $ \x -> x{ retX = t } global env = globalX (envX env) \\ localX (envX env) defined env = globalX (envX env) ++ localX (envX env) ret env = retX $ envX env setVolVars as env = modX env $ \x -> x{ volVarsX = as } isVolVar a env = a `elem` volVarsX (envX env) -- Line emission helpers setLineEmit :: (SrcLoc -> Doc) -> GenEnv -> GenEnv setLineEmit f env = modX env $ \x -> x{ lineEmitX = Just f } getLineEmit :: GenEnv -> (SrcLoc -> Doc) getLineEmit env = case lineEmitX (envX env) of Just f -> f Nothing -> const empty -- Helpers ------------------------------------------------------------------------------------------ include :: GenEnv -> String -> ModName -> Doc include env dir m = text "#include" <+> doubleQuotes (text (joinPath $ dir : modPath m) <> text ".h") modNames (Import _ ms : is) = [ m | ModuleItem m _ <- ms ] ++ modNames is modNames (FromImport _ (ModRef (0,Just m)) _ : is) = m : modNames is modNames (FromImportAll _ (ModRef (0,Just m)) : is) = m : modNames is modNames [] = [] -- Header ------------------------------------------------------------------------------------------- hModule env (Module m imps _ stmts) = text "#pragma" <+> text "once" $+$ (if inBuiltin env then empty else text "#include \"builtin/builtin.h\"" $+$ -- TODO: can we include out/types/__builtin__.h instead? include env "rts" (modName ["rts"])) $+$ vcat (map (include env "out/types") $ modNames imps) $+$ hSuite 1 env1 stmts $+$ hSuite 2 env1 stmts $+$ text "void" <+> genTopName env initKW <+> parens empty <> semi where env1 = classdefine stmts env hSuite phase env [] = empty hSuite phase env (s:ss) = hStmt phase env s $+$ hSuite phase (gdefine (envOf s) env) ss hStmt 1 env (Decl _ ds) = vmap (declstub env1) ds $+$ vmap (typedef env1) ds $+$ vmap (decl env1) ds $+$ vmap (methstub env1) ds where env1 = gdefine (envOf ds) env hStmt 2 env s = vcat [ text "extern" <+> genTypeDecl env n t <+> genTopName env n <> semi | (n,NVar t) <- envOf s] hStmt _ env s = empty declstub env (Class _ n q a b ddoc) = text "struct" <+> genTopName env n <> semi declstub env Def{} = empty typedef env (Class _ n q a b ddoc) = text "typedef" <+> text "struct" <+> genTopName env n <+> char '*' <> genTopName env n <> semi typedef env Def{} = empty decl env (Class _ n q a b ddoc) = (text "struct" <+> classname env n <+> char '{') $+$ nest 4 (vcat $ stdprefix env ++ initdef : serialize env tc : deserialize env tc : meths) $+$ char '}' <> semi $+$ inst_struct where tc = TC (NoQ n) [ tVar v | QBind v _ <- q ] initdef : meths = fields env tc properties = [ varsig env n (sctype sc) <> semi | (n, NSig sc Property _) <- fullAttrEnv env tc ] inst_struct | initNotImpl = empty | otherwise = (text "struct" <+> genTopName env n <+> char '{') $+$ nest 4 (classlink env n $+$ vcat properties) $+$ char '}' <> semi initNotImpl = any hasNotImpl [ b' | Decl _ ds <- b, Def{dname=n',dbody=b'} <- ds, n' == initKW ] decl env (Def _ n q p _ (Just t) _ _ fx ddoc) = genTypeDecl env n (exposeMsg fx t) <+> genTopName env n <+> parens (par env $ prowOf p) <> semi where par = if isUnboxed n then uparams else params methstub env (Class _ n q a b ddoc) = text "extern" <+> text "struct" <+> classname env n <+> methodtable env n <> semi $+$ constub env t n r b where TFun _ _ r _ t = sctype $ fst $ schemaOf env (eVar n) methstub env Def{} = empty constub env t n r b | null ns || hasNotImpl b = gen env t <+> newcon env n <> parens (params env r) <> semi | otherwise = empty where ns = abstractAttrs env (NoQ n) fields env c = map field (vsubst [(tvSelf,tCon c)] te) where te = fullAttrEnv env c field (n, NDef sc Static _) = funsig env n (sctype sc) <> semi field (n, NDef sc NoDec _) = methsig env c n (sctype sc) <> semi field (n, NVar t) = varsig env n t <> semi field (n, NSig sc Static _) = funsig env n (sctype sc) <> semi field (n, NSig sc NoDec _) = methsig env c n (sctype sc) <> semi field (n, NSig sc Property _) = empty funsig env n (TFun _ _ r _ t) = gen env t <+> parens (char '*' <> gen env n) <+> parens (params env r) funsig env n t = varsig env n t methsig env c n (TFun _ fx r _ t) = gen env (exposeMsg fx t) <+> parens (char '*' <> gen env n) <+> parens (params env $ posRow (tCon c) r) methsig env c n t = varsig env n t params env (TNil _ _) = empty params env (TRow _ _ _ t r@TRow{}) = gen env t <> comma <+> params env r params env (TRow _ _ _ t TNil{}) = gen env t params env (TRow _ _ _ t TVar{}) = gen env t -- Ignore param tails for now... params env t = error ("codegen unexpected row: " ++ prstr t) uparams env (TNil _ _) = empty uparams env (TRow _ _ _ t r@TRow{}) = utype env t <> comma <+> uparams env r uparams env (TRow _ _ _ t TNil{}) = utype env t uparams env (TRow _ _ _ t TVar{}) = utype env t -- Ignore param tails for now... uparams env t = error ("codegen unexpected row: " ++ prstr t) utype env t | B.isUnboxable t = text (unboxed_c_type t) | otherwise = gen env t exposeMsg fx t = if fx == fxAction then tMsg t else t exposeMsg' t@TFun{} = t{ restype = exposeMsg (effect t) (restype t) } exposeMsg' t = t varsig env n t = gen env t <+> gen env n stdprefix env = [gcinfo env, classid env, superlink env] gcinfo env = text "char" <+> text "*" <> gen env gcinfoKW <> semi classid env = text "int" <+> gen env classidKW <> semi superlink env = gen env tSuperclass <+> gen env superclassKW <> semi where tSuperclass = tCon $ TC qnSuperClass [] qnSuperClass = GName mPrim (Derived (name "Super") suffixClass) serialize env c = text "void" <+> parens (char '*' <> gen env serializeKW) <+> parens (gen env c <> comma <+> gen env tSerialstate) <> semi deserialize env c = gen env (tCon c) <+> parens (char '*' <> gen env deserializeKW) <+> parens (gen env c <> comma <+> gen env tSerialstate) <> semi classlink env n = text "struct" <+> classname env n <+> text "*" <> gen env classKW <> semi classname env n = genTopName env (Derived n suffixClass) methodtable env n = gen env (tableName $ gname env n) staticwitness env n = gen env (witName n) methodtable' env (NoQ n) = methodtable env n methodtable' env n = gen env $ tableName (unalias env n) tableName (GName m n) = GName m (Derived n suffixMethods) tableName n = error ("#### tableName " ++ show n) witName (GName m n) = GName m (Derived n suffixWitness) witName n = error ("#### witName " ++ show n) newcon env n = gen env (conName $ gname env n) newcon' env (NoQ n) = newcon env n newcon' env n = gen env $ conName $ unalias env n conName (GName m n) = GName m (Derived n suffixNew) serializeSup env c = methodtable' env c <> dot <> gen env serializeKW deserializeSup env c = methodtable' env c <> dot <> gen env deserializeKW classKW = primKW "class" gcinfoKW = primKW "GCINFO" classidKW = primKW "class_id" superclassKW = primKW "superclass" componentsKW = name "components" serializeKW = name "__serialize__" deserializeKW = name "__deserialize__" primAND = gPrim "AND" primOR = gPrim "OR" primNOT = gPrim "NOT" primROOT = gPrim "ROOT" primROOTINIT = gPrim "ROOTINIT" primRegister = gPrim "register" primToInt = name "toB_int" primToU64 = name "toB_u64" primToBigInt = name "toB_bigint" primToBigInt2 = name "toB_bigint2" primToFloat = name "to$float" primToStr = name "to$str" primToBytearray = name "to$bytearray" primToBytes = Derived (name "to$bytes") (name "len") tmpV = primKW "tmp" tSerialstate = tCon $ TC (GName mPrim (name "Serial$state")) [] primStepSerialize = gPrim "step_serialize" primStepDeserialize = gPrim "step_deserialize" primDNEW = gPrim "DNEW" primNEWTUPLE = gPrim "NEWTUPLE" primNEWTUPLE0 = gPrim "NEWTUPLE0" -- Implementation ----------------------------------------------------------------------------------- cModule env srcbase srcText emitLines (Module m imps _ stmts) = (if inBuiltin env then text "#include \"builtin/builtin.c\"" else empty) $+$ text "#include \"rts/common.h\"" $+$ include env (if inBuiltin env then "" else "out/types") m $+$ ext_include $+$ declModule envWithLine stmts $+$ text "int" <+> genTopName env initFlag <+> equals <+> text "0" <> semi $+$ (text "void" <+> genTopName env initKW <+> parens empty <+> char '{') $+$ nest 4 (text "if" <+> parens (genTopName env initFlag) <+> text "return" <> semi $+$ genTopName env initFlag <+> equals <+> text "1" <> semi $+$ ext_init $+$ initImports $+$ initTables env1 stmts $+$ initGlobals env1 stmts) $+$ char '}' where initImports = vcat [ gen env (GName m initKW) <> parens empty <> semi | m <- modNames imps ] external = notImpl && not (inBuiltin env) ext_include = if notImpl then text "#include" <+> doubleQuotes (text srcbase <> text ".ext.c") else empty ext_init = if notImpl then genTopName env (name "__ext_init__") <+> parens empty <> semi else empty notImpl = hasNotImpl stmts env1 = classdefine stmts env -- Emit a C #line directive for a given Acton SrcLoc if available actFile = srcbase ++ ".act" -- Our AST source locations (SrcLoc) carry byte offsets (start,end), not (row,col). -- C's #line requires a 1-based line number, so we convert offsets -> line numbers. -- We precompute line start offsets and use an IntMap + lookupLE for O(log n) mapping. lineStarts :: [Int] lineStarts = 0 : [ i+1 | (i,c) <- zip ([0..] :: [Int]) srcText, c == '\n' ] lineMap :: IM.IntMap Int lineMap = IM.fromList (zip lineStarts ([1..] :: [Int])) offsetToLine :: Int -> Int offsetToLine off = case IM.lookupLE off lineMap of Just (_, ln) -> ln Nothing -> 1 emitLine NoLoc = empty emitLine (Loc startOffset _) = text "#line" <+> pretty (offsetToLine startOffset) <+> doubleQuotes (text actFile) envWithLine = if emitLines then setLineEmit emitLine env1 else env1 declModule env [] = empty declModule env (Decl _ ds : ss) = vcat [ declDecl env1 d | d <- ds ] $+$ declModule env1 ss where env1 = gdefine (envOf ds) env te = envOf ds declModule env (Signature{} : ss) = declModule env ss declModule env (s : ss) = vcat [ genTypeDecl env n t <+> genTopName env n <> semi | (n,NVar t) <- te ] $+$ declModule env1 ss where te = envOf s `exclude` defined env env1 = gdefine te env declDecl env (Def dloc n q p KwdNIL (Just t) b d fx ddoc) | hasNotImpl b = genTypeDecl env n t1 <+> genTopName env n <+> parens (gen env p) <> semi $+$ text "/*" $+$ decl $+$ text "*/" | otherwise = decl where (ss',vs) = genSuite env1 b decl = emit dloc $+$ (genTypeDecl env n t1 <+> genTopName env n <+> parens (gen (setVolVars vs env) p) <+> char '{') $+$ nest 4 ss' $+$ char '}' env1 = setRet t1 $ ldefine (envOf p) $ defineTVars q env t1 = exposeMsg fx t emit = getLineEmit env declDecl env (Class _ n q as b ddoc) | cDefinedClass = vcat [ declDecl env1 d{ dname = methodname n (dname d) } | Decl _ ds <- b', d@Def{} <- ds ] $+$ text "struct" <+> classname env n <+> methodtable env n <> semi | otherwise = vcat [ declDecl env1 d{ dname = methodname n (dname d) } | Decl _ ds <- b', d@Def{} <- ds ] $+$ declSerialize env1 n c props sup_c $+$ declDeserialize env1 n c props sup_c $+$ declCleanup env1 n sup_c $+$ declCon env1 n q b $+$ text "struct" <+> classname env n <+> methodtable env n <> semi where b' = vsubst [(tvSelf, tCon c)] b c = TC (NoQ n) (map tVar $ qbound q) env1 = defineTVars q env props = [ n | (n, NSig sc Property _) <- fullAttrEnv env c ] sup_c = filter ((`elem` special_repr) . tcname) as special_repr = [primActor] -- To be extended... cDefinedClass = inBuiltin env && any hasNotImpl [b' | Decl _ ds <- b, Def{dname=n',dbody=b'} <- ds, n' == initKW ] declCleanup env n sup_c -- TODO: only match if this is an actor, or even better if this actor has a __cleanup__ method defined (not empty!?) | not (null sup_c) = -- Only for actors text "void" <+> genTopName env (methodname n attr_finalizer) <+> parens (text "void *obj, void *cdata") <+> char '{' $+$ -- t_cleanupQ_Foo self = (t_cleanupQ_Foo)obj; -- self->$class->__cleanup__(self); nest 4 ((genTopName env n) <+> gen env self <+> equals <+> parens (genTopName env n) <> text "obj" <> semi $+$ gen env self <> text "->" <> gen env classKW <> text "->" <> gen env cleanupKW <> parens (gen env self) <> semi) $+$ char '}' | otherwise = empty where self = name "self" declSerialize env n c props sup_c = (text "void" <+> genTopName env (methodname n serializeKW) <+> parens (gen env pars) <+> char '{') $+$ nest 4 (super_step $+$ vcat [ step i | i <- props \\ super_attrs ]) $+$ char '}' where pars = PosPar self (Just $ tCon c) Nothing $ PosPar st (Just tSerialstate) Nothing PosNIL st = name "state" self = name "self" super_step | [c] <- sup_c = serializeSup env (tcname c) <> parens (parens (gen env $ tcname c) <> gen env self <> comma <+> gen env st) <> semi | otherwise = empty super_attrs = [ i | c <- sup_c, i <- conAttrs env (tcname c) ] step i = gen env primStepSerialize <> parens (gen env self <> text "->" <> gen env i <> comma <+> gen env st) <> semi declDeserialize env n c props sup_c = (gen env (tCon c) <+> genTopName env (methodname n deserializeKW) <+> parens (gen env pars) <+> char '{') $+$ nest 4 (optcreate $+$ super_step $+$ vcat [ step i | i <- props \\ super_attrs ] $+$ ret) $+$ char '}' where pars = PosPar self (Just $ tCon c) Nothing $ PosPar st (Just tSerialstate) Nothing PosNIL st = name "state" self = name "self" env1 = ldefine [(st, NVar tSerialstate)] env optcreate = (text "if" <+> parens (text "!" <> gen env self) <+> char '{') $+$ nest 4 ((text "if" <+> parens (text "!" <> gen env st) <+> char '{') $+$ nest 4 (alloc $+$ text "return" <+> gen env self <> semi) $+$ char '}' $+$ create) $+$ char '}' create = gen env self <+> text "=" <+> gen env primDNEW <> parens (genTopName env n <> comma <+> gen env st) <> semi alloc = gen env self <+> equals <+> acton_malloc env (gname env n) <> semi $+$ gen env self <> text "->" <> gen env1 classKW <+> equals <+> char '&' <> methodtable env1 n <> semi super_step | [c] <- sup_c = deserializeSup env (tcname c) <> parens (parens (gen env $ tcname c) <> gen env self <> comma <+> gen env st) <> semi | otherwise = empty super_attrs = [ i | c <- sup_c, i <- conAttrs env (tcname c) ] step i = gen env self <> text "->" <> gen env i <+> text "=" <+> gen env primStepDeserialize <> parens (gen env st) <> semi ret = text "return" <+> gen env self <> semi initTables env [] = empty initTables env (Decl _ ds : ss) = vcat [ char '{' $+$ nest 4 (initClassBase env1 n q as hC $+$ initClass env1 n b hC) $+$ char '}' | Class _ n q as b ddoc <- ds, let hC = hasCDef b ] $+$ initTables env1 ss where env1 = gdefine (envOf ds) env hasCDef b = inBuiltin env && any hasNotImpl [b' | Decl _ ds <- b, Def{dname=n',dbody=b'} <- ds, n' == initKW ] initTables env (s : ss) = initTables env ss initGlobals env [] = empty initGlobals env (Decl _ ds : ss) = initGlobals env1 ss where env1 = gdefine (envOf ds) env initGlobals env (Signature{} : ss) = initGlobals env ss initGlobals env (s : ss) = genStmt1 env s $+$ vcat [ genTopName env n <+> equals <+> gen env n <> semi | (n,_) <- te ] $+$ initGlobals env1 ss where te = envOf s `exclude` defined env env1 = gdefine te env initClassBase env c q as hasCDef = methodtable env c <> dot <> gen env gcinfoKW <+> equals <+> doubleQuotes (genTopName env c) <> semi $+$ methodtable env c <> dot <> gen env superclassKW <+> equals <+> super <> semi $+$ vcat [ inherit c' n | (c',n) <- inheritedAttrs env (NoQ c) ] where super = if null as then text "NULL" else parens (gen env qnSuperClass) <> text "&" <> methodtable' env (tcname $ head as) selfsubst = selfSubst (NoQ c) q inherit c' n | hasCDef = methodtable env c <> dot <> gen env n <+> equals <+> genTopName env (methodname c n) <> semi | otherwise = methodtable env c <> dot <> gen env n <+> equals <+> cast (fromJust $ lookup n te) <> methodtable' env c' <> dot <> gen env n <> semi cast (NSig sc dec _) = parens (gen env (selfsubst $ addSelf (sctype sc) (Just dec))) cast (NDef sc dec _) = parens (gen env (selfsubst $ addSelf (sctype sc) (Just dec))) cast (NVar t) = parens (gen env $ selfsubst t) te = fullAttrEnv env $ TC (NoQ c) [ tVar v | QBind v _ <- q ] initClass env c [] hasCDef = vcat [ methodtable env c <> dot <> gen env n <+> equals <+> genTopName env (methodname c n) <> semi | n <- [serializeKW,deserializeKW] ] $+$ if hasCDef then empty else gen env primRegister <> parens (char '&' <> methodtable env c) <> semi initClass env c (Decl _ ds : ss) b = vcat [ methodtable env c <> dot <> gen env n <+> equals <+> genTopName env (methodname c n) <> semi | Def{dname=n} <- ds ] $+$ initClass env1 c ss b where env1 = gdefine (envOf ds) env initClass env c (Signature{} : ss) b = initClass env c ss b initClass env c (s : ss) b | isNotImpl s = initClass env c ss b | otherwise = genStmt1 env s $+$ vcat [ genTopName env c <> dot <> gen env n <+> equals <+> gen env n <> semi | (n,_) <- te ] $+$ initClass env1 c ss b where te = envOf s `exclude` defined env env1 = ldefine te env initFlag = name "done$" methodname c n = Derived c n class Gen a where gen :: GenEnv -> a -> Doc genV :: GenEnv -> a -> (Doc,[Name]) genV env x = (gen env x,[]) gen env x = fst(genV env x) instance (Gen a) => Gen (Maybe a) where gen env x = maybe empty (gen env) x genV env x = maybe (empty,[]) (genV env) x instance Gen ModName where gen env (ModName ns) = hcat $ punctuate (text "Q_") $ map (gen env) ns instance Gen QName where gen env (GName m n) | m == mPrim = char '$' <> text (rawstr n) | m == mBuiltin = text "B_" <> text (nstr n) | otherwise = gen env m <> text "Q_" <> text (mkCident $ nstr n) gen env (NoQ n) = gen env n gen env n@QName{} | n `elem` B.mathfuns = text (nstr (noq n)) | otherwise = gen env (unalias env n) instance Gen Name where gen env nm = text $ unCkeyword $ mkCident $ nstr nm genTopName env n = gen env (gname env n) genQName env (NoQ n) | n `elem` global env = genTopName env n | isAlias n env = genTopName env n genQName env n = gen env n gname env n = unalias env (NoQ n) mkCident "complex" = "complx" mkCident "__complex__" = "__complx__" mkCident "complx" = "A_complex" mkCident "__complx__" = "A___complex__" mkCident (c:s) | isAlpha c = c : esc s | otherwise = hex c ++ esc s where isAlpha c = c `elem` ['a'..'z'] || c `elem` ['A'..'Z'] || c `elem` ['_','$'] isAlphaNum c = isAlpha c || c `elem` ['0'..'9'] esc (c:s) | isAlphaNum c = c : esc s | otherwise = hex c ++ esc s esc "" = "" hex c = "X_" ++ showHex (fromEnum c) "_" unCkeyword str | str `Data.Set.member` rws = preEscape str | otherwise = str where rws = Data.Set.fromDistinctAscList [ "alignas", "alignof", "auto", "bool", "break", "case", "char", "const", "constexpr", "continue", "default", "do", "double", "else", "enum", "extern", "false", "float", "for", "goto", "if", "inline", "int", "long", "nullptr", "register", "restrict", "return", "short", "signed", "sizeof", "static", "static_assert", "struct", "switch", "thread_local", "true", "typedef", "typeof", "typeof_unequal", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_BitInt", "_Bool", "_Complex", "_Decimal128", "_Decimal32", "_Decimal64", "_Generic", "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local" ] preEscape str = "A_" ++ str word = text "$WORD" genSuite :: GenEnv -> Suite -> (Doc,[Name]) genSuite env [] = (empty,[]) genSuite env (s:ss) = ((emit (sloc s) $+$ c) $+$ cs, vs' ++ (vs `intersect` defined env)) where (cs,vs) = genSuite (ldefine (envOf s) env) ss (c,vs') = genStmt (setVolVars vs env) s emit = getLineEmit env genTypeDecl env n t = (if isVolVar n env then text "volatile" else empty) <+> if isUnboxed n && B.isUnboxable t then text (unboxed_c_type t) else gen env t genStmt env (Decl _ ds) = (empty, []) genStmt env (Assign _ [PVar _ n (Just t)] e) | n `notElem` defined env = (genTypeDecl env n t <+> gen env n <+> equals <+> rhs <> semi, []) where rhs = if isWitness n then case staticWitnessName e of (Just nm,as) -> foldr (\x y -> y <> text "->" <> myPretty x) (parens (myPretty (tcname (tcon t))) <> myPretty (witName nm)) as _ -> genExp env t e else genExp env t e genStmt env s = (vcat [ genTypeDecl env n t <+> gen env n <> semi | (n,NVar t) <- te ] $+$ s', vs) where te = envOf s `exclude` defined env env1 = ldefine te env (s', vs) = genV env1 s genStmt1 env s = fst $ genStmt env s instance Gen Stmt where genV env s | isNotImpl s = (text "//" <+> text "NotImplemented", []) genV env (Expr _ Strings{}) = (semi, []) genV env (Expr _ e) = (genExp' env e <> semi, []) genV env (Assign _ [p] e) | B.isUnboxable t = (gen env p <+> equals <+> gen env e <> semi, []) | otherwise = (gen env p <+> equals <+> genExp env t e <> semi, []) where t = typeOf env p genV env (AugAssign _ tg op e) = (genTarget env tg <+> augPretty op <+> genExp env t e <> semi, []) where t = targetType env tg genV env (MutAssign _ tg e) = (genTarget env tg <+> equals <+> genExp env t e <> semi, []) where t = targetType env tg genV env (Pass _) = (empty, []) genV env (Return _ Nothing) = (text "return" <+> gen env eNone <> semi, []) genV env (Return _ (Just e)) = (text "return" <+> genExp env (ret env) e <> semi, []) genV env (Break _) = (text "break" <> semi, []) genV env (Continue _) = (text "continue" <> semi, []) genV _ (If _ (Branch (Bool _ True) [Pass _] : _) _) = (empty, []) genV env (If _ [b@(Branch e ss)] fin) | isPUSH e = (b' $+$ fin', v1 ++ v2 ++ volatiles) where (b',v1) = genBranch env "if" b (fin',v2) = genElse env fin volatiles = bound ss `intersect` defined env genV env (If _ (b:bs) b2) = (b' $+$ vcat bs' $+$ b2', v1 ++ concat v2 ++ v3) where (b',v1) = genBranch env "if" b (bs',v2) = unzip (map (genBranch env "else if") bs) (b2',v3) = genElse env b2 genV env (While _ e b []) = genBranch env "while" (Branch e b) genV env _ = (empty, []) genBranch env kw (Branch e b) = ((text kw <+> parens(genBool env (B.unbox t e)) <+> char '{') $+$ nest 4 b' $+$ char '}', vs) where (b',vs) = genSuite env b t = typeOf env e genElse env [] = (empty, []) genElse env b = ((text "else" <+> char '{') $+$ nest 4 b' $+$ char '}', vs) where (b',vs) = genSuite env b instance Gen PosPar where gen env (PosPar n (Just t) _ PosNIL) = genTypeDecl env n t <+> gen env n gen env (PosPar n (Just t) _ p) = genTypeDecl env n t <+> gen env n <> comma <+> gen env p gen env PosNIL = empty instance Gen PosArg where gen env (PosArg e PosNil) = gen env e gen env (PosArg e p) = gen env e <> comma <+> gen env p gen env PosNil = empty formatLit (Strings l ss) = Strings l [format $ concat ss] where format [] = [] format ('%':s) = '%' : flags s format (c:s) = c : format s flags (f:s) | f `elem` "#0- +" = f : flags s flags s = width s width ('*':s) = '*' : dot s width (n:s) | n `elem` "123456789" = let (n',s') = span (`elem` "0123456789") s in n : n' ++ dot s' width s = dot s dot ('.':s) = '.' : prec s dot s = len s prec ('*':s) = '*' : len s prec (n:s) | n `elem` "0123456789" = let (n',s') = span (`elem` "0123456789") s in n : n' ++ len s' prec s = len s len (l:s) | l `elem` "hlL" = 'l' : conv s len s = conv0 s conv0 (t:s) | t `elem` "diouxXc" = 'l' : conv (t:s) conv0 s = conv s conv (t:s) = t : format s castLit env (Strings l ss) p = format (concat ss) p where format [] p = empty format ('%':s) p = flags s p format (c:s) p = format s p flags (f:s) p | f `elem` "#0- +" = flags s p flags s p = width s p width ('*':s) (PosArg e p) = comma <+> parens (text "int") <> expr <> dot s p where expr = text "fromB_int" <> parens (gen env e) width (n:s) p | n `elem` "123456789" = let (n',s') = span (`elem` "0123456789") s in dot s' p width s p = dot s p dot ('.':s) p = prec s p dot s p = len s p prec ('*':s) (PosArg e p) = comma <+> parens (text "int") <> expr <> len s p where expr = text "fromB_int" <> parens (gen env e) --parens (parens (gen env tInt) <> gen env e) <> text "->val" prec (n:s) p | n `elem` "0123456789" = let (n',s') = span (`elem` "0123456789") s in len s' p prec s p = len s p len (l:s) p | l `elem` "hlL" = conv s p len s p = conv s p conv (t:s) (PosArg e p) | t `elem` "diouxXc" = comma <+> expr <> format s p where expr = text "fromB_int" <> parens (gen env e) --parens (parens (gen env tInt) <> gen env e) <> text "->val" conv (t:s) (PosArg e p) | t `elem` "eEfFgG" = comma <+> expr <> format s p where expr = parens (parens (gen env tFloat) <> gen env e) <> text "->val" conv (t:s) (PosArg e p) | t `elem` "rsa" = comma <+> expr <> format s p where expr = parens (parens (gen env tStr) <> gen env e) <> text "->str" conv ('%':s) p = format s p genCall env [] (TApp _ e ts) p = genCall env ts e p genCall env [_,t] (Var _ n) (PosArg e PosNil) | n == primCAST = parens (parens (genTypeDecl env (noq n) t) <> gen env e) genCall env [row] (Var _ n) (PosArg s@Strings{} (PosArg tup PosNil)) | n == primFORMAT = gen env n <> parens (genStr env (formatLit s) <> castLit env s (flatten tup)) where unbox (TNil _ _) p = empty unbox (TRow _ _ _ t r) (PosArg e p) | t == tStr = comma <+> expr <> text "->str" <> unbox r p | otherwise = comma <+> expr <> text "->val" <> unbox r p where expr = parens (parens (gen env t) <> gen env e) flatten (Tuple _ p KwdNil) = p flatten e = foldr PosArg PosNil $ map (DotI l0 e) [0..] genCall env [t] (Var _ n) PosNil | n == primNEWACTOR = gen env n <> parens (gen env t) -- Only install GCfinalizer if one is defined, i.e. we don't have the default -- $ActorD___cleanup__ -- TODO: would be even better to determine this in the compiler and not emit -- this line rather than inspect the method table at run time genCall env [TCon _ tc] (Var _ n) p | n == primInstallFinalizer = text "if" <+> parens (text "(void*)" <> gen env p <> text "->" <> gen env classKW <> text "->" <> gen env cleanupKW <+> text "!= (void*)$ActorD___cleanup__") <+> gen env n <> parens (gen env p <> comma <+> genTopName env (methodname (noq $ tcname tc) attr_finalizer)) genCall env ts e@(Var _ n) p | NClass{} <- info = genNew env n p | NDef{} <- info = (instCast env ts e $ gen env e) <> parens (gen env p) where info = findQName n env genCall env ts (Async _ e) p = genCall env ts e p genCall env ts e0@(Dot _ e n) p = genDotCall env ts (snd $ schemaOf env e0) e n p genCall env ts e p = gen env e <> parens (gen env p) instCast env [] e = id instCast env ts e@(Var _ x) | x == primUGetItem = case typeInstOf env ts e of TFun _ fx (TRow _ _ _ t1 (TRow _ _ _ t2 _)) _ r -> parens . (parens (gen env r <+> parens (char '*') <+> parens (gen env t1 <> comma <+> text (unboxed_c_type t2))) <>) t -> error("Interal error: unexpected typecast for list indexing") | GName m _ <- x, m == mPrim = id instCast env ts e = parens . (parens (gen env t) <>) where t = typeInstOf env ts e targetType env (Dot _ e n) = sctype sc where t0 = typeOf env e (_,c0) = case t0 of TCon _ tc -> splitTC env tc TVar _ tv -> splitTC env (findTVBound env tv) (sc, dec) = findAttr' env c0 n targetType env e = typeOf env e -- Must be a Var with a monomorphic type since it is assignable dotCast env ent ts (Var _ x) n | GName m _ <- x, m == mPrim = id dotCast env ent ts e n | gen_t == gen env t1 = id | otherwise = parens . (parens gen_t <>) where t0 = typeOf env e (argsubst, c0) = case t0 of TCon _ tc -> splitTC env tc TVar _ tv -> splitTC env (findTVBound env tv) TTuple{} -> ([], cValue) (sc, dec) = findAttr' env c0 n t = vsubst fullsubst $ if ent then addSelf t1 dec else t1 t1 = exposeMsg' (sctype sc) fullsubst = (tvSelf,t0) : (qbound (scbind sc) `zip` ts) ++ argsubst gen_t = gen env t classCast env ts x q n = parens . (parens (gen env t) <>) where (ts0,ts1) = splitAt (length q) ts tc = TC x ts0 (sc, dec) = findAttr' env tc n t = vsubst fullsubst $ addSelf (sctype sc) dec fullsubst = (tvSelf,tCon tc) : (qbound (scbind sc) `zip` ts1) genNew env n p = newcon' env n <> parens (gen env p) declCon env n q b | null abstr || hasNotImpl b = (gen env tRes <+> newcon env n <> parens (gen env pars) <+> char '{') $+$ nest 4 (gen env tObj <+> gen env tmpV <+> equals <+> acton_malloc env (gname env n) <> semi $+$ gen env tmpV <> text "->" <> gen env1 classKW <+> equals <+> char '&' <> methodtable env1 n <> semi $+$ altcall $+$ initcall) $+$ char '}' | otherwise = empty where TFun _ fx r _ t = sctype $ fst $ schemaOf env (eVar n) tc = TC (NoQ n) (map tVar $ qbound q) tObj = tCon tc tRes = if t == tR then tR else tObj pars = pPar paramNames r args = pArg pars altcall | Just (_,sc,_) <- alt = let i = arity $ posrow $ sctype sc args' = pArg (chop i pars) in methodtable env n <> dot <> gen env altInit <> parens (gen env1 tmpV <> comma' (gen env1 args')) <> semi | otherwise = empty where alt = findAttr env tc altInit initcall | t == tR = text "return" <+> methodtable env n <> dot <> gen env initKW <> parens (gen env1 tmpV <> comma <+> gen env1 (retobj args)) <> semi | otherwise = methodtable env n <> dot <> gen env initKW <> parens (gen env1 tmpV <> comma' (gen env1 args)) <> semi $+$ text "return" <+> gen env tmpV <> semi retobj (PosArg e p) = PosArg (eCall (tApp (eQVar primCONSTCONT) [tObj]) [eVar tmpV, e]) p env1 = ldefine ((tmpV, NVar tObj) : envOf pars) env abstr = abstractAttrs env (NoQ n) acton_malloc env n = text "acton_malloc" <> parens (text "sizeof" <> parens (text "struct" <+> gen env n)) comma' x = if isEmpty x then empty else comma <+> x genDotCall env ts dec e@(Var _ x) n p | NClass q _ _ _ <- info, Just _ <- dec = classCast env ts x q n (methodtable' env x <> text "." <> gen env n) <> parens (gen env p) where info = findQName x env genDotCall env ts dec e n p | Just NoDec <- dec = genEnter env ts e n p | Just Static <- dec = dotCast env False ts e n (gen env e <> text "->" <> gen env classKW <> text "->" <> gen env n) <> parens (gen env p) genDot env ts e@(Var _ x) n | NClass q _ _ _ <- findQName x env = classCast env ts x q n $ methodtable' env x <> text "." <> gen env n genDot env ts e n = dotCast env False ts e n $ gen env e <> text "->" <> gen env n -- NOTE: all method references are eta-expanded by the lambda-lifter at this point, so n cannot be a method (i.e., require methodtable lookup) here genTarget env (Dot _ e n) = gen env e <> text "->" <> gen env n genTarget env e = gen env e genEnter env ts e n p | costly e = parens (lbrace <+> (gen env t <+> gen env tmpV <+> equals <+> gen env e <> semi $+$ genEnter env1 ts (eVar tmpV) n p <> semi) <+> rbrace) where costly Var{} = False costly (Dot _ e n) = costly e costly (DotI _ e i) = costly e costly e = True t = typeOf env e env1 = ldefine [(tmpV,NVar t)] env genEnter env ts e n p = dotCast env True ts e n (gen env e <> text "->" <> gen env classKW <> text "->" <> gen env n) <> parens (gen env e <> comma' (gen env p)) genInst env ts e@Var{} = instCast env ts e $ gen env e genInst env ts (Dot _ e n) = genDot env ts e n adjust t t' e | t == t' = e adjust (TOpt _ t) t' e = adjust t t' e adjust t (TOpt _ t') e = adjust t t' e adjust TNone{} t' e = e adjust t t'@TVar{} e = e adjust (TCon _ c) (TCon _ c') e | tcname c == tcname c' = e adjust t t' e | B.isUnboxable t' = e | otherwise = typecast t t' e genExp env t' e = gen env (adjust t t' e') where (t, fx, e') = qType env adjust e genExp' env e = gen env e' where (t, fx, e') = qType env adjust e instance Gen Expr where gen env (Var _ n) | NClass{} <- findQName n env = newcon' env n | otherwise = genQName env n gen env (Int _ i str) | i < 0 = gen env primToBigInt2 <> parens (doubleQuotes $ text str) -- negative → string | i <= 9223372036854775807 = gen env primToBigInt <> parens (text (str++"UL")) -- fits i64 → toB_bigint | i <= 18446744073709551615 = gen env primToU64 <> parens (text (str++"UL")) -- fits u64 → toB_u64 | otherwise = gen env primToBigInt2 <> parens (doubleQuotes $ text str) -- large → string gen env (Float _ _ str) = gen env primToFloat <> parens (text str) gen env (Bool _ True) = gen env qnTrue gen env (Bool _ False) = gen env qnFalse gen env (None _) = gen env qnNone gen env e@Strings{} = gen env primToStr <> parens(hsep (map pretty (sval e))) gen env e@BStrings{} = gen env primToBytes <> parens( hsep (map pretty es) <> comma <+>text(show(length(read(concat es) :: String)))) where es = sval e gen env (Call l (TApp _ e@(Var _ mk) _) p@(PosArg w (PosArg (Set _ es) PosNil)) KwdNil) | mk == primMkSet = text "B_mk_set" <> parens (pretty (length es) <> comma <+> gen env w <> hsep [comma <+> gen env e | e <- es]) gen env (Call l (TApp _ e@(Var _ mk) _) p@(PosArg w (PosArg (Dict _ es) PosNil)) KwdNil) | mk == primMkDict = text "B_mk_dict" <> parens (pretty (length es) <> comma <+> gen env w <> hsep [comma <+> gen env e | e <- es]) gen env c@(Call _ e p _) = genCall env [] e p gen env (Async _ e) = gen env e gen env (TApp _ e ts) = genInst env ts e gen env (Let _ ss e) = text "({" <+> fst(genSuite env ss) $+$ gen (ldefine (envOf ss) env) e <> text ";})" gen env (IsInstance _ e c) = gen env primISINSTANCE <> parens (gen env e <> comma <+> genQName env c) gen env (Dot _ e n) = genDot env [] e n gen env e0@(DotI _ e i) = parens $ parens (gen env t) <> gen env e <> text "->" <> gen env componentsKW <> brackets (pretty i) where t = typeOf env e0 gen env (RestI _ e i) = gen env eNone <> semi <+> text "// CodeGen for tuple tail not implemented" gen env (Tuple _ p KwdNil) | n == 0 = gen env primNEWTUPLE0 | otherwise = gen env primNEWTUPLE <> parens (text (show n) <> comma' (gen env p)) where n = nargs p gen env (List _ es) = text "B_mk_list" <> parens (pretty (length es) <> hsep [comma <+> gen env e | e <- es]) gen env (BinOp _ e1 And e2) = gen env primAND <> parens (gen env t <> comma <+> gen env e1 <> comma <+> gen env e2) where t = typeOf env e1 gen env (BinOp _ e1 Or e2) = gen env primOR <> parens (gen env t <> comma <+> gen env e1 <> comma <+> gen env e2) where t = typeOf env e1 gen env (BinOp _ e1 op e2) | op == Div && t /= tFloat || op `elem` [Pow, Mod, EuDiv] -- Pow since there is no C operator, the others since they need to check for division by zero = gencFunCall env (tstr ++ '_' : opstr op) [e1, e2] | otherwise = gen env e1 <+> binPretty op <+> gen env e2 where t = typeOf env e1 tstr = nstr (noq (tcname (tcon t))) opstr Pow = "pow" opstr Div = "DIV" opstr Mod = "MOD" opstr EuDiv = "FLOORDIV" gen env (CompOp _ e [a]) = gen env e <+> gen env a gen env (UnOp _ Not e) = gen env primNOT <> parens (gen env t <> comma <+> gen env e) where t = typeOf env e gen env (Cond _ e1 e e2) = parens (parens (gen env (B.unbox tBool e)) <+> text "?" <+> gen env e1 <+> text ":" <+> gen env e2) gen env (Paren _ e) = parens (gen env e) gen env (Box t e) = text ("toB_"++render(pretty (noq (tcname(tcon t))))) <> parens (gen env e) gen env (UnBox _ e@(Call _ (Var _ f) p KwdNil)) | f == primISNOTNONE = genCall env [] (Var NoLoc primISNOTNONE0) p | f == primISNONE = genCall env [] (Var NoLoc primISNONE0) p | f `elem` [primPUSH,primPUSHF] = gen env f <> parens(empty) | f `elem` B.mathfuns = genCall env [] e p | tCon (TC (gBuiltin (noq f)) []) `elem` B.integralTypes -- f is the constructor for an integer type, so check if argument e is a literal = genUnboxedInt env (posargs p) e gen env (UnBox t e@(Call _ (Dot _ (Var _ w) op) (PosArg x (PosArg y PosNil)) KwdNil)) -- use macro for int (in)equality tests = case findQName w env of NVar (TCon _ (TC p [TCon _ (TC t [])])) | (p==qnOrd || p==qnEq) && t == qnBigint -> text "ORD_" <> tname <> text (nstr op) <> parens(parens (parens tname <> gen env x) <> comma <+> parens (parens tname <> gen env y)) _ -> parens (parens (gen env t) <> gen env e) <> text "->val" where tname = genQName env qnBigint gen env (UnBox _ (IsInstance _ e c)) = gen env primISINSTANCE0 <> parens(gen env e <> comma <+> genQName env c) gen env (UnBox t (Int _ n s)) = text (s++ suffix t) where suffix t | t == tInt = "LL" | t == tU64 = "UL" | otherwise = "" gen env (UnBox _ (Float _ x s)) = text s gen env (UnBox _ (Bool _ b)) = if b then text "true" else text "false" gen env (UnBox _ v@(Var _ (NoQ n))) | isUnboxed n = gen env v gen env (UnBox t e) = parens (parens (gen env t) <> gen env e) <> text "->val" -- gen env (UnBox t e) = parens (gen env e) <> text "->val" gen env e = error ("CodeGen.gen for Expr: e = " ++ show e) gencFunCall env nm [] = text nm <> parens empty gencFunCall env nm (x : xs) = text nm <> parens (gen env x <> hsep [ comma <+> gen env x | x <- xs ]) genUnboxedInt env [Int _ n s, None _] _ = text s genUnboxedInt env _ c = parens (gen env c) <> text "->val" instance Gen OpArg where gen env (OpArg op e) = compPretty op <+> gen env e -- compPretty Is = text "==" -- compPretty IsNot = text "!=" compPretty op = pretty op binPretty And = text "&&" binPretty Or = text "||" binPretty EuDiv = text "/" binPretty op = pretty op augPretty EuDivA = text "/=" augPretty op = pretty op genStr env s = text $ head $ sval s genBool env e = genExp env tBool e where t = typeOf env e nargs :: PosArg -> Int nargs PosNil = 0 nargs (PosArg _ p) = 1 + nargs p instance Gen Elem where gen env (Elem e) = gen env e instance Gen Assoc where gen env (Assoc e1 e2) = gen env primNEWTUPLE <> parens (text "2" <> comma <+> gen env e1 <> comma <+> gen env e2) instance Gen Pattern where gen env (PVar _ n _) = gen env n instance Gen TSchema where gen env (TSchema _ _ t) = gen env t instance Gen TVar where gen env (TV k n) = word instance Gen TCon where gen env (TC n ts) = gen env (unalias env n) instance Gen Type where gen env (TVar _ v) = gen env v gen env (TCon _ c) = gen env c gen env (TFun _ _ p _ t) = gen env t <+> parens (char '*') <+> parens (gen env p) gen env (TTuple _ pos _) = gen env qnTuple gen env (TOpt _ t) = gen env t gen env (TNone _) = gen env qnNoneType gen env (TWild _) = word gen env (TRow _ _ _ t TNil{}) = gen env t gen env (TRow _ _ _ t r) = gen env t <> comma <+> gen env r gen env (TNil _ _) = empty unboxed_c_type t | t == tInt = "int64_t" | t == tU64 = "uint64_t" | t == tI32 = "int32_t" | t == tU32 = "uint32_t" | t == tI16 = "int16_t" | t == tU16 = "uint16_t" | t == tFloat = "double" | otherwise = error ("Internal error: trying to find unboxed type for " ++ show t) ================================================ FILE: compiler/lib/src/Acton/CommandLineParser.hs ================================================ {-# LANGUAGE CPP #-} module Acton.CommandLineParser where import Options.Applicative import Data.Char (toLower) import Data.Maybe (fromMaybe, isJust) #if defined(darwin_HOST_OS) && defined(aarch64_HOST_ARCH) defTarget = "aarch64-macos-none" #elif defined(darwin_HOST_OS) && defined(x86_64_HOST_ARCH) defTarget = "x86_64-macos-none" #elif defined(linux_HOST_OS) && defined(aarch64_HOST_ARCH) defTarget = "aarch64-linux-gnu.2.27" #elif defined(linux_HOST_OS) && defined(x86_64_HOST_ARCH) defTarget = "x86_64-linux-gnu.2.27" #else #error "Unsupported platform" #endif parseCmdLine :: IO CmdLineOptions parseCmdLine = execParser (info (cmdLineParser <**> helper) descr) data CmdLineOptions = CompileOpt [String] GlobalOptions CompileOptions | CmdOpt GlobalOptions Command deriving Show data ColorWhen = Auto | Always | Never deriving (Show, Eq) data OptimizeMode = Debug | ReleaseSafe | ReleaseSmall | ReleaseFast deriving (Show, Eq) data GlobalOptions = GlobalOptions { color :: ColorWhen, quiet :: Bool, noProgress :: Bool, timing :: Bool, tty :: Bool, verbose :: Bool, verboseZig :: Bool, jobs :: Int } deriving Show data Command = New NewOptions | Build BuildOptions | Install InstallOptions | Uninstall UninstallOptions | Sig SigOptions | Test TestCommand | Fetch | PkgShow | PkgAdd PkgAddOptions | PkgRemove PkgRemoveOptions | PkgUpgrade PkgUpgradeOptions | PkgUpdate | PkgSearch PkgSearchOptions | BuildSpecCmd BuildSpecCommand | Cloud CloudOptions | Doc DocOptions | ZigPkgAdd ZigPkgAddOptions | ZigPkgRemove ZigPkgRemoveOptions | Version deriving Show data NewOptions = NewOptions { file :: String } deriving Show data CompileOptions = CompileOptions { alwaysbuild :: Bool, ignore_compiler_version :: Bool, db :: Bool, parse :: Bool, parse_ast :: Bool, kinds :: Bool, types :: Bool, sigs :: Bool, norm :: Bool, deact :: Bool, cps :: Bool, llift :: Bool, box :: Bool, hgen :: Bool, cgen :: Bool, ccmd :: Bool, ty :: Bool, cpedantic :: Bool, dbg_no_lines:: Bool, optimize :: OptimizeMode, only_build :: Bool, skip_build :: Bool, watch :: Bool, no_threads :: Bool, parse_serial :: Bool, root :: String, tempdir :: String, syspath :: String, target :: String, cpu :: String, test :: Bool, searchpath :: [String], dep_overrides :: [(String,String)] } deriving Show data BuildOptions = BuildOptions { buildCompile :: CompileOptions , buildFiles :: [String] } deriving Show data InstallOptions = InstallOptions { installName :: String , installRepoUrl :: String , installRepoRef :: String , installPkgName :: String , installGithubToken :: String } deriving Show data UninstallOptions = UninstallOptions { uninstallName :: String } deriving Show data SigOptions = SigOptions { sigCompile :: CompileOptions , sigTarget :: String } deriving Show data CloudOptions = CloudOptions { run :: Bool, list :: Bool, show :: Bool, stop :: Bool } deriving Show data DocOptions = DocOptions { inputFile :: String, outputFormat :: Maybe DocFormat, outputFile :: Maybe String } deriving Show data DocFormat = AsciiFormat | MarkdownFormat | HtmlFormat deriving (Show, Eq) data TestCommand = TestRun TestOptions | TestList TestOptions | TestPerf TestOptions | TestStress TestOptions deriving Show data TestOptions = TestOptions { testCompile :: CompileOptions , testShowLog :: Bool , testShowCached :: Bool , testNoCache :: Bool , testJson :: Bool , testRecord :: Bool , testSnapshotUpdate :: Bool , testIter :: Int , testMaxIter :: Int , testMinIter :: Int , testMaxTime :: Int , testMinTime :: Int , testStressWorkers :: Int , testTags :: [String] , testMaxIterSet :: Bool , testMaxTimeSet :: Bool , testMinTimeSet :: Bool , testModules :: [String] , testNames :: [String] } deriving Show data PkgAddOptions = PkgAddOptions { pkgAddName :: String , pkgAddUrl :: String , pkgAddRepoUrl :: String , pkgAddRepoRef :: String , pkgAddPkgName :: String , pkgAddHash :: String , pkgAddGithubToken :: String } deriving Show data PkgRemoveOptions = PkgRemoveOptions { pkgRemoveName :: String } deriving Show data PkgUpgradeOptions = PkgUpgradeOptions { pkgUpgradeGithubToken :: String } deriving Show data PkgSearchOptions = PkgSearchOptions { pkgSearchTerms :: [String] } deriving Show data ZigPkgAddOptions = ZigPkgAddOptions { zigPkgAddUrl :: String , zigPkgAddName :: String , zigPkgAddArtifacts :: [String] } deriving Show data ZigPkgRemoveOptions = ZigPkgRemoveOptions { zigPkgRemoveName :: String } deriving Show -------------------------------------------------------------------- -- Internal stuff cmdLineParser :: Parser CmdLineOptions cmdLineParser = hsubparser ( command "new" (info (CmdOpt <$> globalOptions <*> (New <$> newOptions)) (progDesc "Create a new Acton project")) <> command "build" (info (CmdOpt <$> globalOptions <*> (Build <$> buildOptions)) (progDesc "Build an Acton project")) <> command "install" (info (CmdOpt <$> globalOptions <*> (Install <$> installOptions)) (progDesc "Install an Acton application package")) <> command "uninstall" (info (CmdOpt <$> globalOptions <*> (Uninstall <$> uninstallOptions)) (progDesc "Uninstall an Acton application package")) <> command "sig" (info (CmdOpt <$> globalOptions <*> (Sig <$> sigOptions)) (progDesc "Show inferred type signatures")) <> command "test" (info (CmdOpt <$> globalOptions <*> (Test <$> testCommand)) (progDesc "Build and run project tests")) <> command "fetch" (info (CmdOpt <$> globalOptions <*> pure Fetch) (progDesc "Fetch project dependencies (offline prep)")) <> command "pkg" (info (CmdOpt <$> globalOptions <*> pkgSubcommands) (progDesc "Library package/dependency commands")) <> command "zig-pkg" (info (CmdOpt <$> globalOptions <*> zigPkgSubcommands) (progDesc "Zig package dependency commands")) <> command "spec" (info (CmdOpt <$> globalOptions <*> (BuildSpecCmd <$> buildSpecCommand)) (progDesc "Inspect or update build specification")) <> command "cloud" (info (CmdOpt <$> globalOptions <*> (Cloud <$> cloudOptions)) (progDesc "Run an Acton project in the cloud")) <> command "doc" (info (CmdOpt <$> globalOptions <*> (Doc <$> docOptions)) (progDesc "Show type and docstring info")) <> command "version" (info (CmdOpt <$> globalOptions <*> pure Version) (progDesc "Show version")) ) <|> (CompileOpt <$> (fmap (:[]) $ argument str (metavar "ACTONFILE" <> help "Compile Acton file" <> completer (bashCompleter "file -X '!*.act' -o plusdirs"))) <*> globalOptions <*> compileOptions) globalOptions :: Parser GlobalOptions globalOptions = GlobalOptions <$> option colorReader (long "color" <> metavar "WHEN" <> value Auto <> help "Use colored output (WHEN: auto, always, never)" ) <*> switch (long "quiet" <> help "Don't print stuff") <*> switch (long "no-progress" <> help "Disable live progress UI") <*> switch (long "timing" <> help "Print timing information") <*> switch (long "tty" <> help "Act as if run from interactive TTY") <*> switch (long "verbose" <> help "Verbose output") <*> switch (long "verbose-zig" <> help "Verbose Zig output") <*> option auto (long "jobs" <> metavar "N" <> value 0 <> help "Max parallel compiler jobs (0 = auto)") where colorReader :: ReadM ColorWhen colorReader = eitherReader $ \s -> case s of "auto" -> Right Auto "always" -> Right Always "never" -> Right Never _ -> Left $ "Invalid color option: " ++ s ++ " (expected: auto, always, never)" optimizeReader :: ReadM OptimizeMode optimizeReader = eitherReader $ \s -> case map toLower s of "debug" -> Right Debug "release" -> Right ReleaseFast "releasesafe" -> Right ReleaseSafe "releasesmall" -> Right ReleaseSmall "releasefast" -> Right ReleaseFast _ -> Left $ "Invalid optimize option: " ++ s ++ " (expected: Debug, Release, ReleaseSafe, ReleaseSmall, ReleaseFast)" releaseModeReader :: ReadM OptimizeMode releaseModeReader = eitherReader $ \s -> case map toLower s of "safe" -> Right ReleaseSafe "small" -> Right ReleaseSmall "fast" -> Right ReleaseFast _ -> Left $ "Invalid release option: " ++ s ++ " (expected: safe, small, fast)" {- generalOptions = GeneralOptions <$> strOption (long "tempdir" <> metavar "TEMPDIR" <> value "" <> help "Set temporary directory for build files") <*> strOption (long "syspath" <> metavar "TARGETDIR" <> value "" <> help "Set syspath") <*> switch (long "dev" <> help "Development mode; include debug symbols etc") -} newOptions = NewOptions <$> argument (str :: ReadM String) (metavar "PROJECTDIR") buildOptions :: Parser BuildOptions buildOptions = BuildOptions <$> compileOptions <*> many (argument str (metavar "ACTONFILE" <> help "Specific .act file(s) to build")) installOptions :: Parser InstallOptions installOptions = InstallOptions <$> argument str (metavar "NAME" <> help "Name of application package") <*> strOption (long "repo-url" <> metavar "URL" <> value "" <> help "Git repository URL of application package") <*> strOption (long "repo-ref" <> metavar "REF" <> value "" <> help "Git ref (branch, tag or SHA) to use") <*> strOption (long "pkg-name" <> metavar "NAME" <> value "" <> help "Package name in index (defaults to NAME)") <*> githubTokenOption uninstallOptions :: Parser UninstallOptions uninstallOptions = UninstallOptions <$> argument str (metavar "NAME" <> help "Name of application package") sigOptions :: Parser SigOptions sigOptions = SigOptions <$> sigCompileOptions <*> argument str (metavar "TARGET" <> help "Module or module.name to show, e.g. foo.bar") sigCompileOptions :: Parser CompileOptions sigCompileOptions = mkSigCompileOptions <$> switch (long "always-build" <> help "Recompute signatures instead of reusing fresh cached interfaces") <*> switch (long "ignore-compiler-version" <> help "Ignore acton version when checking .ty freshness") <*> strOption (long "syspath" <> metavar "TARGETDIR" <> value "" <> help "Set syspath") <*> many (strOption (long "searchpath" <> metavar "DIR" <> help "Add search path")) <*> many (option depOverrideReader (long "dep" <> metavar "NAME=PATH" <> help "Override dependency NAME with local PATH")) where mkSigCompileOptions always ignore syspath' search depOverrides = CompileOptions { alwaysbuild = always , ignore_compiler_version = ignore , db = False , parse = False , parse_ast = False , kinds = False , types = False , sigs = False , norm = False , deact = False , cps = False , llift = False , box = False , hgen = False , cgen = False , ccmd = False , ty = False , cpedantic = False , dbg_no_lines = False , optimize = Debug , only_build = False , skip_build = True , watch = False , no_threads = False , parse_serial = False , root = "" , tempdir = "" , syspath = syspath' , target = defTarget , cpu = "" , test = False , searchpath = search , dep_overrides = depOverrides } compileOptions = CompileOptions <$> switch (long "always-build" <> help "Show the result of parsing") <*> switch (long "ignore-compiler-version" <> help "Ignore acton version when checking .ty freshness") <*> switch (long "db" <> help "Enable DB backend") <*> switch (long "parse" <> help "Show the result of parsing") <*> switch (long "parse-ast" <> help "Show the raw AST (Haskell Show)") <*> switch (long "kinds" <> help "Show all the result after kind-checking") <*> switch (long "types" <> help "Show all inferred expression types") <*> switch (long "sigs" <> help "Show the inferred type signatures") <*> switch (long "norm" <> help "Show the result after syntactic normalization") <*> switch (long "deact" <> help "Show the result after deactorization") <*> switch (long "cps" <> help "Show the result after CPS conversion") <*> switch (long "llift" <> help "Show the result of lambda-lifting") <*> switch (long "box" <> help "Show the result of (un)boxing") <*> switch (long "hgen" <> help "Show the generated .h header") <*> switch (long "cgen" <> help "Show the generated .c code") <*> switch (long "ccmd" <> help "Show CC / LD commands") <*> switch (long "ty" <> help "Write .ty file to src file directory") <*> switch (long "cpedantic" <> help "Pedantic C compilation with -Werror") <*> switch (long "dbg-no-lines" <> help "Disable emission of C #line directives (for debugging codegen)") <*> optimizeOption <*> switch (long "only-build" <> help "Only perform final build of .c files, do not compile .act files") <*> switch (long "skip-build" <> help "Skip final bulid of .c files") <*> switch (long "watch" <> help "Rebuild on file changes") <*> switch (long "no-threads" <> help "Don't use threads") <*> switch (long "parse-serial" <> help "Use the serial whole-file parser") <*> strOption (long "root" <> metavar "ROOTACTOR" <> value "" <> help "Set root actor") <*> strOption (long "tempdir" <> metavar "TEMPDIR" <> value "" <> help "Set directory for build files") <*> strOption (long "syspath" <> metavar "TARGETDIR" <> value "" <> help "Set syspath") <*> strOption (long "target" <> metavar "TARGET" <> value defTarget <> help "Target, e.g. x86_64-linux-gnu.2.28") <*> strOption (long "cpu" <> metavar "CPU" <> value "" <> help "CPU, e.g. skylake") <*> switch (long "test" <> help "Build tests") <*> many (strOption (long "searchpath" <> metavar "DIR" <> help "Add search path")) <*> many (option depOverrideReader (long "dep" <> metavar "NAME=PATH" <> help "Override dependency NAME with local PATH")) pkgSubcommands :: Parser Command pkgSubcommands = hsubparser ( command "show" (info (pure PkgShow) (progDesc "Show dependency tree with overrides")) <> command "add" (info (PkgAdd <$> pkgAddOptions) (progDesc "Add library package dependency")) <> command "remove" (info (PkgRemove <$> pkgRemoveOptions) (progDesc "Remove library package dependency")) <> command "upgrade" (info (PkgUpgrade <$> pkgUpgradeOptions) (progDesc "Upgrade (or downgrade) library package dependency")) <> command "update" (info (pure PkgUpdate) (progDesc "Update package index")) <> command "search" (info (PkgSearch <$> pkgSearchOptions) (progDesc "Search library package index")) ) githubTokenOption :: Parser String githubTokenOption = strOption ( long "github-token" <> metavar "TOKEN" <> value "" <> help "GitHub token for API requests (env: GITHUB_TOKEN)" ) pkgAddOptions :: Parser PkgAddOptions pkgAddOptions = PkgAddOptions <$> argument str (metavar "NAME" <> help "Name of dependency") <*> strOption (long "url" <> metavar "URL" <> value "" <> help "URL of dependency") <*> strOption (long "repo-url" <> metavar "URL" <> value "" <> help "Git repository URL of dependency") <*> strOption (long "repo-ref" <> metavar "REF" <> value "" <> help "Git ref (branch, tag or SHA) to use") <*> strOption (long "pkg-name" <> metavar "NAME" <> value "" <> help "Package name in index (defaults to NAME)") <*> strOption (long "hash" <> metavar "HASH" <> value "" <> help "Hash of dependency") <*> githubTokenOption pkgRemoveOptions :: Parser PkgRemoveOptions pkgRemoveOptions = PkgRemoveOptions <$> argument str (metavar "NAME" <> help "Name of dependency") pkgUpgradeOptions :: Parser PkgUpgradeOptions pkgUpgradeOptions = PkgUpgradeOptions <$> githubTokenOption pkgSearchOptions :: Parser PkgSearchOptions pkgSearchOptions = PkgSearchOptions <$> many (argument str (metavar "TERM" <> help "Search term (regex, ANDed)")) zigPkgSubcommands :: Parser Command zigPkgSubcommands = hsubparser ( command "add" (info (ZigPkgAdd <$> zigPkgAddOptions) (progDesc "Add Zig package dependency")) <> command "remove" (info (ZigPkgRemove <$> zigPkgRemoveOptions) (progDesc "Remove Zig package dependency")) ) zigPkgAddOptions :: Parser ZigPkgAddOptions zigPkgAddOptions = ZigPkgAddOptions <$> argument str (metavar "URL" <> help "URL of dependency") <*> argument str (metavar "NAME" <> help "Name of dependency") <*> many (strOption (long "artifact" <> metavar "NAME" <> help "Library artifact to link with")) zigPkgRemoveOptions :: Parser ZigPkgRemoveOptions zigPkgRemoveOptions = ZigPkgRemoveOptions <$> argument str (metavar "NAME" <> help "Name of dependency") cloudOptions = CloudOptions <$> switch (long "run" <> help "Help run!") <*> switch (long "list" <> help "Help list!") <*> switch (long "show" <> help "Help show!") <*> switch (long "stop" <> help "Help stop!") docOptions = DocOptions <$> (argument str (metavar "FILE" <> help "Input file (.act or .ty) - optional in projects" <> completer (bashCompleter "file -X '!*.act' -X '!*.ty' -o plusdirs")) <|> pure "") <*> formatFlags <*> optional (strOption (long "output" <> short 'o' <> metavar "FILE" <> help "Output file (default: stdout)")) where -- Parse format flags - simple and explicit formatFlags = optional ( flag' AsciiFormat (long "terminal" <> short 't' <> help "Terminal output (ASCII format)") <|> flag' MarkdownFormat (long "md" <> long "markdown" <> help "Output in Markdown format") <|> flag' HtmlFormat (long "html" <> help "Output in HTML format") ) optimizeOption :: Parser OptimizeMode optimizeOption = resolveOptimizeOption <$> optional releaseOption <*> optional (option optimizeReader (long "optimize" <> metavar "MODE" <> help "Optimization mode (case-insensitive: Debug, Release/ReleaseFast, ReleaseSafe, ReleaseSmall)" )) where releaseOption = flag' ReleaseFast (long "release" <> help "Release build mode; same as --release=fast and also accepts =safe or =small" ) <|> option releaseModeReader (long "release" <> internal ) resolveOptimizeOption _ (Just mode) = mode resolveOptimizeOption (Just mode) _ = mode resolveOptimizeOption Nothing Nothing = Debug data TestModeTag = ModeList | ModePerf | ModeStress deriving Show testCommand :: Parser TestCommand testCommand = toCmd <$> optional (argument testModeReader (metavar "MODE" <> help "list | perf | stress")) <*> testOptions where toCmd mMode opts = case mMode of Just ModeList -> TestList opts Just ModePerf -> TestPerf opts Just ModeStress -> TestStress opts Nothing -> TestRun opts testModeReader :: ReadM TestModeTag testModeReader = eitherReader $ \s -> case s of "list" -> Right ModeList "perf" -> Right ModePerf "stress" -> Right ModeStress _ -> Left "Expected 'list', 'perf' or 'stress'" testOptions :: Parser TestOptions testOptions = mkTestOptions <$> compileOptions <*> switch (long "show-log" <> help "Show test log output") <*> switch (long "show-cached" <> help "Show cached test results") <*> switch (long "no-cache" <> help "Always run tests instead of reusing cached results") <*> switch (long "json" <> help "Output final test results as JSON") <*> switch (long "record" <> help "Record test performance results") <*> switch (long "snapshot-update" <> long "golden-update" <> long "accept" <> help "Accept current test output as expected snapshot values") <*> option auto (long "iter" <> metavar "N" <> value (-1) <> help "Number of iterations to run a test") <*> optional (option auto (long "max-iter" <> metavar "N" <> help "Maximum number of iterations to run a test (mode defaults when omitted)")) <*> option auto (long "min-iter" <> metavar "N" <> value 3 <> help "Minimum number of iterations to run a test") <*> optional (option auto (long "max-time" <> metavar "MS" <> help "Maximum time to run a test in milliseconds (0 = no time limit, mode defaults when omitted)")) <*> optional (option auto (long "min-time" <> metavar "MS" <> help "Minimum time to run a test in milliseconds")) <*> option auto (long "stress-workers" <> metavar "N" <> value 0 <> help "Concurrent stress workers to run in stress mode (0 = auto)") <*> many (strOption (long "tag" <> metavar "TAG" <> help "Enable test capability TAG for testing.require()")) <*> many (strOption (long "module" <> metavar "MODULE" <> help "Filter on test module name")) <*> many (strOption (long "name" <> metavar "NAME" <> help "Filter on test name (regex, anchored; use .* for substrings)")) where mkTestOptions testCompile testShowLog testShowCached testNoCache testJson testRecord testSnapshotUpdate testIter testMaxIterOpt testMinIter testMaxTimeOpt testMinTimeOpt testStressWorkers testTags testModules testNames = TestOptions { testCompile = testCompile , testShowLog = testShowLog , testShowCached = testShowCached , testNoCache = testNoCache , testJson = testJson , testRecord = testRecord , testSnapshotUpdate = testSnapshotUpdate , testIter = testIter , testMaxIter = fromMaybe (10^6) testMaxIterOpt , testMinIter = testMinIter , testMaxTime = fromMaybe 1000 testMaxTimeOpt , testMinTime = fromMaybe 50 testMinTimeOpt , testStressWorkers = testStressWorkers , testTags = testTags , testMaxIterSet = isJust testMaxIterOpt , testMaxTimeSet = isJust testMaxTimeOpt , testMinTimeSet = isJust testMinTimeOpt , testModules = testModules , testNames = testNames } depOverrideReader :: ReadM (String,String) depOverrideReader = eitherReader $ \s -> case break (== '=') s of (name, '=':path) | not (null name) && not (null path) -> Right (name, path) _ -> Left "Expected NAME=PATH" descr = fullDesc <> progDesc "Compilation and management of Acton source code and projects" <> header "acton - the Acton compiler" -- main = do -- f <- parseCmdLine -- print(f) data BuildSpecCommand = BuildSpecDump | BuildSpecUpdate FilePath deriving Show buildSpecCommand :: Parser BuildSpecCommand buildSpecCommand = hsubparser ( command "dump" (info (pure BuildSpecDump) (progDesc "Dump build spec as JSON to stdout (from Build.act)")) <> command "update" (info (BuildSpecUpdate <$> argument str (metavar "FILE")) (progDesc "Update Build.act using JSON file; override entries present in JSON only")) ) ================================================ FILE: compiler/lib/src/Acton/Compile.hs ================================================ {-# LANGUAGE CPP #-} {-| Overview This module implements the shared Acton compilation pipeline that both the acton CLI and the LSP server drive. It builds a dependency graph across projects, runs the front passes (parse, kinds, types) to produce .ty interface files and diagnostics, and then emits the back passes (normalizer through codegen) as separate jobs. The design is intentionally incremental and event-friendly. While the compiler scheduler is running and actively compiling modules, we can receive a new event about a modified module, cancel running tasks and restart compilation of that module from that point. This is used by watch mode and LSP where updates to files or in-editor buffers trigger recompilation. Dependencies are considered so that updates to a module only cause the affected part of the subgraph, i.e. the modified module and downstream dependencies to be recompiled. Cached .ty headers are reused when public module interfaces are unchanged. Per-name pub/impl hashes stored in the header drive front-pass vs back-pass decisions, and moduleImplHash is embedded in generated .c/.h to detect stale codegen. Inter-module dependencies only depend on the front passes completion, which is why they are separated from back jobs. As soon as the front passes of a module have completed, dependent modules can start compilation while the back pass job is scheduled in the background. This maximizes parallelism. It is only the front passes that can generate user facing errors, which means that the LSP server can return with feedback to the user (module type checked successfully) immediately after the front passes are done while the back passes can be run asynchronously in the background. This maximizes responsiveness of the LSP server. The CLI/LSP layers handle progress UI, file watching, and event sources; this module focuses on deterministic compilation and structured callbacks. Call flow: - Shared pipeline (acton build, acton watch, LSP): 1) prepareCompilePlan (via prepareCompileContext, readModuleTask/ buildGlobalTasks/readImports, and selectNeededTasks/selectAffectedTasks) builds a CompilePlan for the requested subgraph. Parsing is performed through parseActSource/parseActSnapshot/parseActFile so SourceProvider overlays can supply unsaved buffers. 2) runCompilePlan drives compileTasks. As each module finishes its front passes, the CompileHooks callbacks (for example chOnFrontResult) enqueue a BackJob into the scheduler's BackQueue, so back passes begin as soon as they are ready and can overlap remaining front passes. 3) Callers either wait for backQueueWait (CLI builds) or let back jobs run in the background. CLI builds wait before invoking Zig. 4) runBackJobs/runBackPasses can be used for standalone back-pass execution when a caller already has BackJobs to run. - Triggering: - acton build runs the pipeline once for the requested files/project. - acton watch and LSP call startCompile on each event; callers can gate output with generation checks (e.g. whenCurrentGen), and BackQueue ignores back jobs for stale generations. - Callers may supply a delay (debounce) before startCompile runs (LSP uses debounceMicros on change events; acton watch uses 0). - Finalization: - CLI waits on backQueueWait before running Zig build - LSP does not implicitly run the Zig build, it is only run explicitly when the user asks to build / run a module State and orchestration: - Acton.Compile holds only small in-process caches (tyPathCache, pubHashCache, and nameHashCache) to speed up .ty lookups; all orchestration state is owned by the caller. - Callers allocate and hold a CompileScheduler from this module. The scheduler encapsulates mutable state (generation id, cancelable async handle, build-spec stamp, and a shared back-queue); callers pass it into startCompile and backQueueEnqueue rather than mutating it directly. - LSP additionally keeps overlaysRef for in-memory buffers and builds an overlay-aware SourceProvider on top of disk reads. acton watch reads directly from disk. - Each event bumps the generation via startCompile; callers may pass a delay (LSP uses debounceMicros, acton watch uses 0). Back jobs are filtered by generation inside BackQueue; front-pass diagnostics should be gated by the caller if needed. - CLI builds share the same pipeline and enqueue back jobs as soon as front passes finish, overlapping work without needing a watch event source. TODO: - Make generation invalidation more precise so unrelated in-flight modules (e.g. long-running B) are not discarded when A changes. -} module Acton.Compile ( Paths(..) , ProjCtx(..) , TaskKey(..) , GlobalTask(..) , CompileTask(..) , BackInput(..) , BackJob(..) , FrontResult(..) , FrontTiming(..) , TypeStmtTiming(..) , InferredSignature(..) , BackTiming(..) , FrontPass(..) , FrontPassProgress(..) , ParseProgress(..) , CompileCallbacks(..) , defaultCompileCallbacks , BackJobCallbacks(..) , defaultBackJobCallbacks , BackQueue , newBackQueue , backQueueEnqueue , backQueueWait , CompileScheduler(..) , newCompileScheduler , startCompile , whenCurrentGen , BuildSpecStamp(..) , readBuildSpecStamp , checkBuildSpecChange , CompileContext(..) , prepareCompileContext , CompilePlan(..) , prepareCompilePlan , prepareCompilePlanFromContext , CompileHooks(..) , defaultCompileHooks , runCompilePlan , CompileFailure(..) , compileFailureMessage , BackPassFailure(..) , backPassFailureMessage , BackJobResult(..) , defaultCompileOptions , ProjectError(..) , throwProjectError , fetchDependencies , parseActSource , parseActSnapshot , parseActFile , readModuleTask , readModuleDoc , readImports , buildGlobalTasks , selectNeededTasks , selectAffectedTasks , compileTasks , runFrontPasses , runBackPasses , runBackJobs , findProjectDir , BackgroundCompilerLock , backgroundCompilerLockPath , tryBackgroundCompilerLock , releaseBackgroundCompilerLock , projectLockPath , withProjectLockOnWait , withProjectLock , findPaths , discoverProjects , pathsForModule , searchPathForProject , moduleNameFromFile , enumerateProjectModules , normalizeDepOverrides , applyDepOverrides , collectDepTypePaths , depTypePathsFromMap , resolveDepBase , loadBuildSpec , filterActFile , srcFile , outBase , srcBase , getModPath , modNameToFilename , modNameToString , nameToString , importsOf , quiet , altOutput , missingIfaceDiagnostics , getPubHashCached , updatePubHashCache , rootEligible , normalizePathSafe , isAbsolutePath , collapseDots , rebasePath ) where import Prelude hiding (readFile, writeFile) import qualified Acton.Parser import Acton.Parser (CustomParseError, CustomParseException, ChunkScanError(..), ContextError, IndentationError) import qualified Acton.Syntax as A import qualified Acton.NameInfo as I import Text.Megaparsec.Error (ParseErrorBundle) import qualified Acton.CommandLineParser as C import Acton.Printer () import qualified Acton.Env import qualified Acton.TypeEnv import Acton.Env (simp, define, setMod) import qualified Acton.Hashing as Hashing import qualified Acton.Names as Names import qualified Acton.Kinds import qualified Acton.Types import qualified Acton.Converter as Converter import qualified Acton.Normalizer import qualified Acton.CPS import qualified Acton.Deactorizer import qualified Acton.LambdaLifter import qualified Acton.Boxing import qualified Acton.CodeGen import Acton.Prim (mPrim) import qualified Acton.BuildSpec as BuildSpec import qualified Acton.DocPrinter as DocP import qualified Acton.Fingerprint as Fingerprint import qualified Acton.Diagnostics as Diag import qualified Acton.SourceProvider as Source import Utils import qualified Pretty import qualified InterfaceFiles import Control.Applicative ((<|>)) import Control.Concurrent.Async import Control.Concurrent.MVar import Control.Concurrent (forkIO, myThreadId, threadCapability, threadDelay) import Control.Concurrent.STM (TChan, TVar, atomically, check, modifyTVar', newTChanIO, newTVarIO, readTChan, readTVar, writeTChan) import Control.DeepSeq (rnf) import Control.Exception (Exception, IOException, SomeAsyncException, SomeException, catch, displayException, evaluate, finally, fromException, mask_, throwIO, try) import Control.Monad import Data.Bits (shiftL, shiftR, (.|.)) import Data.Char (isAlpha, isDigit, isHexDigit, isSpace, toLower) import Data.Either (partitionEithers) import Data.Graph import Data.List (find, foldl', intercalate, intersperse, isPrefixOf, isSuffixOf, nub, partition) import qualified Data.List import Data.IORef import Data.Maybe (catMaybes, isJust, listToMaybe, mapMaybe) import qualified Data.HashMap.Strict as HM import qualified Data.Map as M import Data.Ord (Down(..)) import qualified Data.Set import Data.Time.Clock (UTCTime) import Data.Word (Word8, Word32, Word64) import Error.Diagnose (Diagnostic) import GHC.Conc (getNumCapabilities) import qualified Network.HTTP.Client as HTTP import Network.HTTP.Client.TLS (tlsManagerSettings) import Network.HTTP.Types.Header (hContentDisposition, hContentType) import Network.HTTP.Types.Status (statusCode) import System.Clock import System.Directory import System.Directory.Recursive import System.Environment (getExecutablePath, lookupEnv) import System.FileLock (FileLock, SharedExclusive(Exclusive), tryLockFile, unlockFile, withFileLock) import System.FilePath (()) import System.FilePath.Posix import System.Exit (ExitCode(..)) import System.IO hiding (readFile, writeFile) import System.IO.Unsafe (unsafePerformIO) import System.Posix.Files (FileStatus, deviceID, fileID, fileSize, getFileStatus, modificationTimeHiRes, statusChangeTimeHiRes) import System.Process (readCreateProcessWithExitCode, proc) import System.Random (randomRIO) import Text.PrettyPrint (renderStyle, style, Style(..), Mode(PageMode)) import Text.Show.Pretty (ppDoc) import Text.Printf import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Base16 as Base16 import qualified Crypto.Hash.SHA256 as SHA256 newtype ProjectError = ProjectError String deriving (Show) instance Exception ProjectError -- | Raise a ProjectError for library callers. -- Used by project discovery and path helpers to stop on unrecoverable errors. throwProjectError :: String -> IO a throwProjectError msg = throwIO (ProjectError msg) data CompileFailure = CompileCycleFailure String | CompileBuiltinFailure | CompileInternalFailure String deriving (Eq, Show) -- | Render internal compile failures as user-facing messages. -- Centralizes wording so CLI output and tests stay consistent. compileFailureMessage :: CompileFailure -> String compileFailureMessage (CompileCycleFailure msg) = msg compileFailureMessage CompileBuiltinFailure = "Builtin compilation failed" compileFailureMessage (CompileInternalFailure msg) = msg data BackPassFailure = BackPassFailure { bpfKey :: TaskKey , bpfMessage :: String } deriving (Eq, Show) backPassFailureMessage :: BackPassFailure -> String backPassFailureMessage (BackPassFailure key msg) = "Back pass failed for " ++ tkProj key ++ "/" ++ modNameToString (tkMod key) ++ ": " ++ msg data BackJobResult = BackJobOk (Maybe TimeSpec) (Maybe BackTiming) | BackJobFailed BackPassFailure deriving (Eq, Show) data FrontPass = FrontPassKinds | FrontPassTypes deriving (Eq, Show) data FrontPassProgress = FrontPassProgress { fppPass :: FrontPass , fppCompleted :: Int , fppTotal :: Int , fppCurrent :: Maybe String } deriving (Eq, Show) data ParseProgress = ParseProgress { ppCompleted :: Int , ppTotal :: Int } deriving (Eq, Show) data TypeStmtTiming = TypeStmtTiming { tstCompleted :: Int , tstTotal :: Int , tstLabel :: String , tstNames :: [String] , tstTime :: TimeSpec } deriving (Eq, Show) data InferredSignature = InferredSignature { isigNames :: [String] , isigSignature :: String } deriving (Eq, Show) data FrontTiming = FrontTiming { ftEnv :: TimeSpec , ftKinds :: TimeSpec , ftTypes :: TimeSpec , ftTypeStmtTimings :: [TypeStmtTiming] } deriving (Eq, Show) data BackTiming = BackTiming { btNormalize :: TimeSpec , btDeactorize :: TimeSpec , btCPS :: TimeSpec , btLLift :: TimeSpec , btBoxing :: TimeSpec , btCodeGen :: TimeSpec , btWriteCode :: Maybe TimeSpec } deriving (Eq, Show) data CompileCallbacks = CompileCallbacks { ccOnDiagnostics :: GlobalTask -> C.CompileOptions -> [Diagnostic String] -> IO () , ccOnParseStart :: GlobalTask -> C.CompileOptions -> IO () , ccOnParseProgress :: GlobalTask -> C.CompileOptions -> ParseProgress -> IO () , ccOnParseDone :: GlobalTask -> C.CompileOptions -> Maybe TimeSpec -> IO () , ccOnFrontResult :: GlobalTask -> C.CompileOptions -> FrontResult -> IO () , ccOnFrontStart :: GlobalTask -> C.CompileOptions -> IO () , ccOnFrontDone :: GlobalTask -> C.CompileOptions -> IO () , ccOnFrontProgress :: GlobalTask -> C.CompileOptions -> FrontPassProgress -> IO () , ccOnBackJob :: BackJob -> IO () , ccOnInfo :: String -> IO () } -- | Default no-op callbacks for the compilation pipeline. -- Callers can start from this and override only the events they care about. defaultCompileCallbacks :: CompileCallbacks defaultCompileCallbacks = CompileCallbacks { ccOnDiagnostics = \_ _ _ -> return () , ccOnParseStart = \_ _ -> return () , ccOnParseProgress = \_ _ _ -> return () , ccOnParseDone = \_ _ _ -> return () , ccOnFrontResult = \_ _ _ -> return () , ccOnFrontStart = \_ _ -> return () , ccOnFrontDone = \_ _ -> return () , ccOnFrontProgress = \_ _ _ -> return () , ccOnBackJob = \_ -> return () , ccOnInfo = \_ -> return () } data BackJobCallbacks = BackJobCallbacks { bjcOnStart :: BackJob -> IO () , bjcOnDone :: BackJob -> BackJobResult -> IO () } -- | Default no-op callbacks for back-pass execution. defaultBackJobCallbacks :: BackJobCallbacks defaultBackJobCallbacks = BackJobCallbacks { bjcOnStart = \_ -> return () , bjcOnDone = \_ _ -> return () } data BackQueue = BackQueue { backQueueEnqueue :: Int -> BackJob -> BackJobCallbacks -> IO Bool , backQueueWait :: Int -> IO (Maybe BackPassFailure) } data BuildSpecStamp = BuildSpecStamp { bssBuildAct :: Maybe UTCTime } deriving (Eq, Show) readBuildSpecStamp :: FilePath -> IO BuildSpecStamp readBuildSpecStamp projDir = do buildAct <- stampFor "Build.act" return BuildSpecStamp { bssBuildAct = buildAct } where stampFor name = do let path = projDir name exists <- doesFileExist path if exists then Just <$> getModificationTime path else return Nothing checkBuildSpecChange :: CompileScheduler -> BuildSpecStamp -> IO Bool checkBuildSpecChange sched stamp = atomicModifyIORef' (csBuildStampRef sched) $ \prev -> let changed = prev /= Just stamp in (Just stamp, changed) -- | Create a concurrent back-pass queue gated by a generation counter. -- Each job is tagged with a generation id; stale jobs are skipped. newBackQueue :: IORef Int -> C.GlobalOptions -> Int -> IO BackQueue newBackQueue genRef gopts maxPar = do queue <- newTChanIO counts <- newTVarIO M.empty failures <- newTVarIO M.empty let incPending gen = M.insertWith (+) gen 1 decPending gen m = case M.lookup gen m of Nothing -> m Just n -> let n' = n - 1 in if n' <= 0 then M.delete gen m else M.insert gen n' m recordFailure gen failure = M.insertWith (\_ old -> old) gen failure enqueue gen job callbacks = do current <- readIORef genRef if current /= gen then return False else do atomically $ do modifyTVar' counts (incPending gen) writeTChan queue (gen, job, callbacks) return True waitDone gen = atomically $ do failuresNow <- readTVar failures case M.lookup gen failuresNow of Just failure -> do modifyTVar' failures (M.delete gen) return (Just failure) Nothing -> do pending <- readTVar counts let n = M.findWithDefault 0 gen pending check (n == 0) return Nothing worker = forever $ do (gen, job, callbacks) <- atomically $ readTChan queue current <- readIORef genRef if current /= gen then atomically $ modifyTVar' counts (decPending gen) else do failed <- atomically $ do failuresNow <- readTVar failures return (M.member gen failuresNow) if failed then atomically $ modifyTVar' counts (decPending gen) else do let shouldWrite = do currentWrite <- readIORef genRef return (currentWrite == gen) bjcOnStart callbacks job res <- (try $ runBackPasses gopts (bjOpts job) (bjPaths job) (bjInput job) shouldWrite) :: IO (Either SomeException (Maybe TimeSpec, Maybe BackTiming)) currentDone <- readIORef genRef when (currentDone == gen) $ case res of Left err -> do let key = TaskKey (projPath (bjPaths job)) (A.modname (biTypedMod (bjInput job))) failure = BackPassFailure key (displayException err) atomically $ modifyTVar' failures (recordFailure gen failure) bjcOnDone callbacks job (BackJobFailed failure) Right (t, bt) -> bjcOnDone callbacks job (BackJobOk t bt) atomically $ modifyTVar' counts (decPending gen) let workers = max 1 maxPar replicateM_ workers (forkIO worker) return BackQueue { backQueueEnqueue = enqueue , backQueueWait = waitDone } data CompileScheduler = CompileScheduler { csGenRef :: IORef Int , csAsyncRef :: MVar (Maybe (Async ())) , csBackQueue :: BackQueue , csBuildStampRef :: IORef (Maybe BuildSpecStamp) } -- | Create a scheduler with generation tracking and a shared back queue. newCompileScheduler :: C.GlobalOptions -> Int -> IO CompileScheduler newCompileScheduler gopts maxPar = do genRef <- newIORef 0 asyncRef <- newMVar Nothing backQueue <- newBackQueue genRef gopts maxPar buildStampRef <- newIORef Nothing return CompileScheduler { csGenRef = genRef , csAsyncRef = asyncRef , csBackQueue = backQueue , csBuildStampRef = buildStampRef } -- | Start a new compile action, canceling any in-flight run. -- Returns the generation id associated with this run. startCompile :: CompileScheduler -> Int -> (Int -> IO ()) -> IO Int startCompile sched delay run = do gen <- atomicModifyIORef' (csGenRef sched) $ \g -> let g' = g + 1 in (g', g') modifyMVar_ (csAsyncRef sched) $ \m -> do forM_ m cancel a <- async $ do when (delay > 0) $ threadDelay delay current <- readIORef (csGenRef sched) when (current == gen) $ run gen return (Just a) return gen -- | Run an action only if the generation still matches. whenCurrentGen :: CompileScheduler -> Int -> IO () -> IO () whenCurrentGen sched gen action = do current <- readIORef (csGenRef sched) when (current == gen) action data CompileContext = CompileContext { ccOpts :: C.CompileOptions , ccDepOverrides :: [(String, FilePath)] , ccPathsRoot :: Paths , ccRootProj :: FilePath , ccSysAbs :: FilePath , ccBuildStamp :: BuildSpecStamp } prepareCompileContext :: C.CompileOptions -> [FilePath] -> IO CompileContext prepareCompileContext opts srcFiles = do when (null srcFiles) $ throwProjectError "No source files found" cwd <- getCurrentDirectory maybeRoot <- findProjectDir (takeDirectory (head srcFiles)) let baseForOverrides = maybe cwd id maybeRoot depOverrides <- normalizeDepOverrides baseForOverrides (C.dep_overrides opts) let opts' = opts { C.dep_overrides = depOverrides } pathsRoot <- findPaths (head srcFiles) opts' rootProj <- normalizePathSafe (projPath pathsRoot) sysAbs <- normalizePathSafe (sysPath pathsRoot) buildStamp <- readBuildSpecStamp (projPath pathsRoot) return CompileContext { ccOpts = opts' , ccDepOverrides = depOverrides , ccPathsRoot = pathsRoot , ccRootProj = rootProj , ccSysAbs = sysAbs , ccBuildStamp = buildStamp } -- | Prepare a compile plan, refreshing dependencies if the build spec changed. prepareCompilePlan :: Source.SourceProvider -> C.GlobalOptions -> CompileScheduler -> C.CompileOptions -> [FilePath] -> Bool -> Maybe [FilePath] -> IO CompilePlan prepareCompilePlan sp gopts sched opts srcFiles allowPrune mChangedPaths = do ctx <- prepareCompileContext opts srcFiles specChanged <- checkBuildSpecChange sched (ccBuildStamp ctx) when specChanged $ fetchDependencies gopts (ccPathsRoot ctx) (ccDepOverrides ctx) let mChanged = if specChanged then Nothing else mChangedPaths prepareCompilePlanFromContext sp gopts ctx srcFiles allowPrune mChanged data CompilePlan = CompilePlan { cpContext :: CompileContext , cpProjMap :: M.Map FilePath ProjCtx , cpGlobalTasks :: [GlobalTask] , cpNeededTasks :: [GlobalTask] , cpRootTasks :: [CompileTask] , cpRootPins :: M.Map String BuildSpec.PkgDep , cpIncremental :: Bool , cpAllowPrune :: Bool , cpChangedPaths :: Maybe [FilePath] , cpSrcFiles :: [FilePath] } prepareCompilePlanFromContext :: Source.SourceProvider -> C.GlobalOptions -> CompileContext -> [FilePath] -> Bool -> Maybe [FilePath] -> IO CompilePlan prepareCompilePlanFromContext sp gopts ctx srcFiles allowPrune mChangedPaths = do let opts' = ccOpts ctx depOverrides = ccDepOverrides ctx pathsRoot = ccPathsRoot ctx rootProj = ccRootProj ctx sysAbs = ccSysAbs ctx incremental = isJust mChangedPaths allowPrune' = allowPrune && not incremental projMap <- if isTmp pathsRoot then do let ctx' = ProjCtx { projRoot = rootProj , projOutDir = projOut pathsRoot , projTypesDir = projTypes pathsRoot , projSrcDir = srcDir pathsRoot , projSysPath = sysAbs , projSysTypes = joinPath [sysAbs, "base", "out", "types"] , projBuildSpec = scratchBuildSpec rootProj , projDeps = [] } return (M.singleton rootProj ctx') else discoverProjects gopts sysAbs rootProj depOverrides -- Keep generated module artifacts in sync with source removals. -- For full builds, scan and prune all orphan outputs. -- For incremental builds, prune only modules whose changed .act paths are now missing. if incremental then maybe (return ()) (pruneMissingChangedModuleOutputs (M.elems projMap)) mChangedPaths else mapM_ pruneMissingModuleOutputs (M.elems projMap) (globalTasks, _) <- buildGlobalTasks sp gopts opts' projMap (if incremental || allowPrune then Nothing else Just srcFiles) neededTasks <- case mChangedPaths of Nothing -> selectNeededTasks pathsRoot rootProj globalTasks srcFiles Just changed -> selectAffectedTasks globalTasks changed let rootTasks = [ gtTask t | t <- neededTasks, tkProj (gtKey t) == rootProj ] rootPins = maybe M.empty (BuildSpec.dependencies . projBuildSpec) (M.lookup rootProj projMap) return CompilePlan { cpContext = ctx , cpProjMap = projMap , cpGlobalTasks = globalTasks , cpNeededTasks = neededTasks , cpRootTasks = rootTasks , cpRootPins = rootPins , cpIncremental = incremental , cpAllowPrune = allowPrune' , cpChangedPaths = mChangedPaths , cpSrcFiles = srcFiles } data CompileHooks = CompileHooks { chOnDiagnostics :: GlobalTask -> C.CompileOptions -> [Diagnostic String] -> IO () , chOnParseStart :: GlobalTask -> IO () , chOnParseProgress :: GlobalTask -> ParseProgress -> IO () , chOnParseDone :: GlobalTask -> Maybe TimeSpec -> IO () , chOnFrontStart :: GlobalTask -> IO () , chOnFrontDone :: GlobalTask -> IO () , chOnFrontProgress :: GlobalTask -> FrontPassProgress -> IO () , chOnFrontResult :: GlobalTask -> FrontResult -> IO () , chOnBackQueued :: TaskKey -> Bool -> IO () , chOnBackStart :: BackJob -> IO () , chOnBackDone :: BackJob -> BackJobResult -> IO () , chOnInfo :: String -> IO () } defaultCompileHooks :: CompileHooks defaultCompileHooks = CompileHooks { chOnDiagnostics = \_ _ _ -> return () , chOnParseStart = \_ -> return () , chOnParseProgress = \_ _ -> return () , chOnParseDone = \_ _ -> return () , chOnFrontStart = \_ -> return () , chOnFrontDone = \_ -> return () , chOnFrontProgress = \_ _ -> return () , chOnFrontResult = \_ _ -> return () , chOnBackQueued = \_ _ -> return () , chOnBackStart = \_ -> return () , chOnBackDone = \_ _ -> return () , chOnInfo = \_ -> return () } runCompilePlan :: Source.SourceProvider -> C.GlobalOptions -> CompilePlan -> CompileScheduler -> Int -> CompileHooks -> IO (Either CompileFailure (Acton.Env.Env0, Bool)) runCompilePlan sp gopts plan sched gen hooks = do let ctx = cpContext plan opts' = ccOpts ctx pathsRoot = ccPathsRoot ctx rootProj = ccRootProj ctx backQueue = csBackQueue sched backCallbacks = BackJobCallbacks { bjcOnStart = chOnBackStart hooks , bjcOnDone = chOnBackDone hooks } callbacks = defaultCompileCallbacks { ccOnDiagnostics = \t optsT diags -> chOnDiagnostics hooks t optsT diags , ccOnParseStart = \t _ -> chOnParseStart hooks t , ccOnParseProgress = \t _ p -> chOnParseProgress hooks t p , ccOnParseDone = \t _ mtime -> chOnParseDone hooks t mtime , ccOnFrontResult = \t _ fr -> chOnFrontResult hooks t fr , ccOnFrontStart = \t _ -> chOnFrontStart hooks t , ccOnFrontDone = \t _ -> chOnFrontDone hooks t , ccOnFrontProgress = \t _ p -> chOnFrontProgress hooks t p , ccOnBackJob = \job -> do let key = TaskKey (projPath (bjPaths job)) (A.modname (biTypedMod (bjInput job))) enqueued <- backQueueEnqueue backQueue gen job backCallbacks chOnBackQueued hooks key enqueued , ccOnInfo = chOnInfo hooks } compileTasks sp gopts opts' pathsRoot rootProj (cpNeededTasks plan) callbacks -- | Baseline compile options for internal helpers and tests. -- This mirrors CLI defaults so path discovery and parsing behave predictably -- when no command-line flags are present. defaultCompileOptions :: C.CompileOptions defaultCompileOptions = C.CompileOptions { C.alwaysbuild = False , C.ignore_compiler_version = False , C.db = False , C.parse = False , C.parse_ast = False , C.kinds = False , C.types = False , C.sigs = False , C.norm = False , C.deact = False , C.cps = False , C.llift = False , C.box = False , C.hgen = False , C.cgen = False , C.ccmd = False , C.ty = False , C.cpedantic = False , C.dbg_no_lines = False , C.optimize = C.Debug , C.only_build = False , C.skip_build = False , C.watch = False , C.no_threads = False , C.parse_serial = False , C.root = "" , C.tempdir = "" , C.syspath = "" , C.target = C.defTarget , C.cpu = "" , C.test = False , C.searchpath = [] , C.dep_overrides = [] } -- | Debug helper for pass dumps. -- Prints a header and footer around the given text so pass output is easy to -- spot in verbose logs. dump :: A.ModName -> String -> String -> IO () dump mn h txt = putStrLn ("\n\n== " ++ h ++ ": " ++ modNameToString mn ++ " ================================\n" ++ txt ++ '\n' : replicate (38 + length h + length (modNameToString mn)) '=' ++ "\n") -- | Compute the subdirectory for a module within a types root. -- Used when creating directories before writing .ty files. getModPath :: FilePath -> A.ModName -> FilePath getModPath path mn = joinPath [path, joinPath $ init $ A.modPath mn] -- Global caches (process‑wide) to reduce repeated .ty lookups during parallel builds -- -- We deliberately create top‑level MVars via unsafePerformIO and mark them -- NOINLINE so their initializer runs exactly once. Without NOINLINE, GHC could -- inline or float the initializer, accidentally creating multiple MVars under -- optimization. This guarantees a single cache per process. -- -- Thread‑safety: all access goes through modifyMVar/modifyMVar_ so read/modify/ -- write is atomic. These caches are best‑effort for performance; correctness -- does not depend on them. On a miss we fall back to reading .ty headers from -- disk. After a successful compile we update pubHashCache so dependents in -- this process see the new public hash. -- -- tyPathCache :: ModName -> absolute .ty path (resolved from searchPath) -- pubHashCache :: ModName -> current public hash (from header or compile) -- nameHashCache :: ModName -> per-name hash info (from header or compile) {-# NOINLINE tyPathCache #-} tyPathCache :: MVar (M.Map A.ModName FilePath) tyPathCache = unsafePerformIO (newMVar M.empty) {-# NOINLINE pubHashCache #-} pubHashCache :: MVar (M.Map A.ModName B.ByteString) pubHashCache = unsafePerformIO (newMVar M.empty) {-# NOINLINE nameHashCache #-} nameHashCache :: MVar (M.Map A.ModName (M.Map A.Name InterfaceFiles.NameHashInfo)) nameHashCache = unsafePerformIO (newMVar M.empty) -- | Resolve the on-disk .ty path for a module, using a process-wide cache. -- Avoids repeated filesystem walks when many modules share dependencies. getTyFileCached :: [FilePath] -> A.ModName -> IO (Maybe FilePath) getTyFileCached spaths mn = modifyMVar tyPathCache $ \m -> do normSearch <- mapM normalizePathSafe spaths let inSearchPath p = let pNorm = normalise p in any (\dir -> let dirNorm = addTrailingPathSeparator (normalise dir) in Data.List.isPrefixOf dirNorm pNorm) normSearch refresh cache = do mty <- Acton.Env.findTyFile spaths mn case mty of Just p -> return (M.insert mn p cache, Just p) Nothing -> return (M.delete mn cache, Nothing) case M.lookup mn m of Just p -> do pNorm <- normalizePathSafe p exists <- doesFileExist pNorm if exists && inSearchPath pNorm then return (m, Just pNorm) else refresh m Nothing -> refresh m -- | Read a module's public hash using the cache and .ty header. -- This drives dependency invalidation when an imported interface changes. getPubHashCached :: Paths -> A.ModName -> IO (Maybe B.ByteString) getPubHashCached paths mn = modifyMVar pubHashCache $ \m -> do case M.lookup mn m of Just ih -> return (m, Just ih) Nothing -> do mty <- getTyFileCached (searchPath paths) mn case mty of Just ty -> do hdrE <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readHeader ty case hdrE of Right (_sourceMetaH, _srcH, ih, _implH, _impsH, _nameHashesH, _rootsH, _testsH, _docH) -> return (M.insert mn ih m, Just ih) _ -> return (m, Nothing) Nothing -> return (m, Nothing) -- | Update the public-hash cache after a successful compile. -- Keeps in-process dependency checks consistent for later modules. updatePubHashCache :: A.ModName -> B.ByteString -> IO () updatePubHashCache mn ih = modifyMVar_ pubHashCache $ \m -> return (M.insert mn ih m) -- | Build a name hash map keyed by Name. nameHashMapFromList :: [InterfaceFiles.NameHashInfo] -> M.Map A.Name InterfaceFiles.NameHashInfo nameHashMapFromList infos = M.fromList [ (InterfaceFiles.nhName i, i) | i <- infos ] publicIfaceTE :: [(A.Name, I.NameInfo)] -> [(A.Name, I.NameInfo)] publicIfaceTE = filter (Names.isPublicName . fst) publicNameHashes :: [InterfaceFiles.NameHashInfo] -> [InterfaceFiles.NameHashInfo] publicNameHashes = filter (Names.isPublicName . InterfaceFiles.nhName) -- | Read a module's per-name hash map using the cache and .ty header. getNameHashMapCached :: Paths -> A.ModName -> IO (Maybe (M.Map A.Name InterfaceFiles.NameHashInfo)) getNameHashMapCached paths mn = modifyMVar nameHashCache $ \m -> do case M.lookup mn m of Just hm -> return (m, Just hm) Nothing -> do mty <- getTyFileCached (searchPath paths) mn case mty of Just ty -> do hdrE <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readHeader ty case hdrE of Right (_sourceMetaH, _srcH, _ih, _implH, _impsH, nameHashes, _rootsH, _testsH, _docH) -> do let hm = nameHashMapFromList (publicNameHashes nameHashes) return (M.insert mn hm m, Just hm) _ -> return (m, Nothing) Nothing -> return (m, Nothing) -- | Update the name-hash cache after a successful compile. updateNameHashCache :: A.ModName -> [InterfaceFiles.NameHashInfo] -> IO () updateNameHashCache mn infos = modifyMVar_ nameHashCache $ \m -> return (M.insert mn (nameHashMapFromList infos) m) -- Handling Acton files ----------------------------------------------------------------------------- -- | Keep only .act files when scanning directories. -- Returns Just the file path for Acton sources and Nothing otherwise. filterActFile :: FilePath -> Maybe FilePath filterActFile file = case fileExt of ".act" -> Just file _ -> Nothing where (fileBody, fileExt) = splitExtension $ takeFileName file -- | Turn a list of (location, message) pairs into diagnostics. -- Used to normalize errors from different compiler subsystems. errsToDiagnostics :: String -> FilePath -> String -> [(SrcLoc, String)] -> [Diagnostic String] errsToDiagnostics errKind filename src errs = [ Diag.actErrToDiagnostic errKind filename src loc msg | (loc, msg) <- errs ] -- | Emit diagnostics when a dependency .ty file is missing or unreadable. -- Anchors the error to the owning module's filename for consistent reporting. missingIfaceDiagnostics :: A.ModName -> String -> A.ModName -> [Diagnostic String] missingIfaceDiagnostics ownerMn src missingMn = errsToDiagnostics "Compilation error" (modNameToFilename ownerMn) src [(NoLoc, "Type interface file not found or unreadable for " ++ modNameToString missingMn)] -- | Parse a module from source text, returning diagnostics on failure. -- Wraps parser, context, and indentation errors into a uniform format. parseActSource :: C.CompileOptions -> A.ModName -> FilePath -> String -> Maybe (ParseProgress -> IO ()) -> IO (Either [Diagnostic String] A.Module) parseActSource opts mn actFile srcContent mOnProgress = do let parseModule | C.parse_serial opts = Acton.Parser.parseModuleSerial | otherwise = Acton.Parser.parseModule (Right <$> parseModule mn actFile srcContent (fmap wrapProgress mOnProgress)) `catch` handleParseBundle `catch` handleCustomParse `catch` handleChunkScanError `catch` handleContextError `catch` handleIndentationError where wrapProgress onProgress completed total = onProgress (ParseProgress completed total) handleParseBundle :: ParseErrorBundle String CustomParseError -> IO (Either [Diagnostic String] A.Module) handleParseBundle bundle = return $ Left [Diag.parseDiagnosticFromBundle actFile srcContent bundle] handleCustomParse :: CustomParseException -> IO (Either [Diagnostic String] A.Module) handleCustomParse err = return $ Left [Diag.customParseExceptionToDiagnostic actFile srcContent err] handleChunkScanError :: ChunkScanError -> IO (Either [Diagnostic String] A.Module) handleChunkScanError (ChunkScanError loc msg) = return $ Left (errsToDiagnostics "Parse error" actFile srcContent [(loc, msg)]) handleContextError :: ContextError -> IO (Either [Diagnostic String] A.Module) handleContextError err = return $ Left (errsToDiagnostics "Context error" (modNameToFilename mn) srcContent (Acton.Parser.contextError err)) handleIndentationError :: IndentationError -> IO (Either [Diagnostic String] A.Module) handleIndentationError err = return $ Left (errsToDiagnostics "Indentation error" (modNameToFilename mn) srcContent (Acton.Parser.indentationError err)) -- | Parse only the module header from a SourceSnapshot. parseActHeaderSnapshot :: A.ModName -> FilePath -> Source.SourceSnapshot -> IO (Either [Diagnostic String] ([A.ModName], Maybe String)) parseActHeaderSnapshot mn actFile snap = do cwd <- getCurrentDirectory let displayFile = makeRelative cwd actFile srcContent = Source.ssText snap (Right <$> do (imps, mdoc) <- Acton.Parser.parseModuleHeader displayFile srcContent return (A.importsOf (A.Module mn imps Nothing []), mdoc)) `catch` handleParseBundle displayFile srcContent `catch` handleCustomParse displayFile srcContent `catch` handleContextError srcContent `catch` handleIndentationError srcContent where handleParseBundle file srcContent bundle = return $ Left [Diag.parseDiagnosticFromBundle file srcContent bundle] handleCustomParse file srcContent err = return $ Left [Diag.customParseExceptionToDiagnostic file srcContent err] handleContextError srcContent err = return $ Left (errsToDiagnostics "Context error" (modNameToFilename mn) srcContent (Acton.Parser.contextError err)) handleIndentationError srcContent err = return $ Left (errsToDiagnostics "Indentation error" (modNameToFilename mn) srcContent (Acton.Parser.indentationError err)) -- | Parse a SourceSnapshot with a display path relative to cwd. -- Keeps diagnostics stable regardless of absolute paths or overlays. parseActSnapshot :: C.CompileOptions -> A.ModName -> FilePath -> Source.SourceSnapshot -> IO (Either [Diagnostic String] A.Module) parseActSnapshot opts mn actFile snap = do cwd <- getCurrentDirectory let displayFile = makeRelative cwd actFile parseActSource opts mn displayFile (Source.ssText snap) Nothing -- | Read and parse a source file via SourceProvider (overlay-aware). -- Returns both the snapshot and the parsed AST for reuse by callers. parseActFile :: C.CompileOptions -> Source.SourceProvider -> A.ModName -> FilePath -> Maybe (ParseProgress -> IO ()) -> IO (Either [Diagnostic String] (Source.SourceSnapshot, A.Module)) parseActFile opts sp mn actFile mOnProgress = do snap <- Source.readSource sp actFile cwd <- getCurrentDirectory let displayFile = makeRelative cwd actFile emod <- parseActSource opts mn displayFile (Source.ssText snap) mOnProgress return $ fmap (\m -> (snap, m)) emod -- | Read stable source metadata used for quick .ty reuse checks. -- Device/inode act as file identity on POSIX so metadata drift from copies or -- restores falls back to content hashing instead of blindly trusting mtimes. readSourceFileMeta :: FilePath -> IO InterfaceFiles.SourceFileMeta readSourceFileMeta path = do st <- getFileStatus path let mtimeNs = fileStatusMTimeNs st ctimeNs = fileStatusCTimeNs st return InterfaceFiles.SourceFileMeta { InterfaceFiles.sfmMTimeNs = mtimeNs , InterfaceFiles.sfmCTimeNs = ctimeNs , InterfaceFiles.sfmSize = fromIntegral (fileSize st) , InterfaceFiles.sfmDevice = Just (fromIntegral (deviceID st)) , InterfaceFiles.sfmInode = Just (fromIntegral (fileID st)) } where fileStatusMTimeNs st = floor (toRational (modificationTimeHiRes st) * 1000000000) fileStatusCTimeNs st = floor (toRational (statusChangeTimeHiRes st) * 1000000000) -- Compilation tasks, chasing imported modules, compilation and building executables ----------------- data BackInput = BackInput { biTypeEnv :: Acton.Env.Env0 , biTypedMod :: A.Module , biSrc :: String , biImplHash :: B.ByteString } data BackJob = BackJob { bjPaths :: Paths , bjOpts :: C.CompileOptions , bjInput :: BackInput } data FrontResult = FrontResult { frIfaceTE :: [(A.Name, I.NameInfo)] , frImps :: [A.ModName] , frDoc :: Maybe String , frPubHash :: B.ByteString , frNameHashes :: [InterfaceFiles.NameHashInfo] , frFrontTime :: Maybe TimeSpec , frFrontTiming :: Maybe FrontTiming , frInferredSigs :: [InferredSignature] , frBackJob :: Maybe BackJob } data CompileTask = ParseTask { name :: A.ModName, src :: String, srcBytes :: B.ByteString, sourceMeta :: Maybe InterfaceFiles.SourceFileMeta, parseImports :: [A.ModName] } | ActonTask { name :: A.ModName, src :: String, srcBytes :: B.ByteString, sourceMeta :: Maybe InterfaceFiles.SourceFileMeta, atree:: A.Module } | TyTask { name :: A.ModName , tyHash :: B.ByteString -- raw source bytes hash , tyPubHash :: B.ByteString -- module public hash , tyImplHash :: B.ByteString -- module impl hash , tyImports :: [(A.ModName, B.ByteString)] -- imports with pub hash used , tyNameHashes :: [InterfaceFiles.NameHashInfo] , tyRoots :: [A.Name] , tyTests :: [String] , tyDoc :: Maybe String , iface :: I.NameInfo , typed :: A.Module } | ParseErrorTask { name :: A.ModName, parseDiagnostics :: [Diagnostic String] } instance Show CompileTask where show ParseTask{ name = mn } = "ParseTask " ++ modNameToString mn show ActonTask{ name = mn } = "ActonTask " ++ modNameToString mn show TyTask{ name = mn } = "TyTask " ++ modNameToString mn show ParseErrorTask{ name = mn, parseDiagnostics = ds } = "ParseErrorTask " ++ modNameToString mn ++ " (" ++ show (length ds) ++ " diagnostics)" -- TODO: replace binName String type with ModName just like for CompileTask. -- ModName is a array so a hierarchy with submodules is represented, we can then -- get it use joinPath (modPath) to get a path or modName to get a string -- representation. We need both of BinTask when generating build.zig, so it -- would be more robust to use that type rather than a hacky character -- replacement (replaceDot in genBuildZigExe) data TaskKey = TaskKey { tkProj :: FilePath, tkMod :: A.ModName } deriving (Eq, Ord, Show) data StageKey = ParseStage TaskKey | FrontStage TaskKey deriving (Eq, Ord, Show) data StageSuccess = StageParsed CompileTask (Maybe TimeSpec) | StageFronted FrontResult forceHTEnv :: I.HTEnv -> () forceHTEnv hte = HM.foldl' forceHNameInfo () hte where forceHNameInfo () (I.HNModule _ te _) = forceHTEnv te forceHNameInfo () hni = hni `seq` () forceTypeResult :: I.NameInfo -> A.Module -> Acton.Env.EnvF x -> [String] -> IO () forceTypeResult nmod tchecked typeEnv tests = do evaluate (rnf nmod) evaluate (rnf tchecked) evaluate (forceHTEnv (Acton.Env.hnames typeEnv)) evaluate (forceHTEnv (Acton.Env.hmodules typeEnv)) evaluate (rnf tests) data GlobalTask = GlobalTask { gtKey :: TaskKey , gtPaths :: Paths , gtTask :: CompileTask , gtImportProviders :: M.Map A.ModName TaskKey -- resolved in-graph providers (if any) for imports } -- | Extract imported module names from a CompileTask. -- TyTask uses header imports, ActonTask uses the parsed AST, and parse errors -- yield no imports. importsOf :: CompileTask -> [A.ModName] importsOf (ParseTask _ _ _ _ imps) = imps importsOf (ActonTask _ _ _ _ m) = A.importsOf m importsOf (TyTask { tyImports = ms }) = map fst ms importsOf (ParseErrorTask _ _) = [] -- | Resolve imports to in-graph providers using project search order. -- This chooses the first project in the search order that declares the module, -- producing TaskKeys for dependency edges. resolveProviders :: [FilePath] -> M.Map FilePath (Data.Set.Set A.ModName) -> [A.ModName] -> M.Map A.ModName TaskKey resolveProviders order modSets imps = M.fromList $ catMaybes $ map (\mn -> fmap (\p -> (mn, TaskKey p mn)) (findProvider mn)) imps where findProvider mn = listToMaybe [ p | p <- order, maybe False (Data.Set.member mn) (M.lookup p modSets) ] -- | Build GlobalTasks for all discovered projects. -- Crawls project sources, resolves provider edges, and optionally limits the -- seed set to specific files to keep the DAG small for incremental builds. buildGlobalTasks :: Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> M.Map FilePath ProjCtx -> Maybe [String] -- optional seed source files; Nothing = all modules -> IO ([GlobalTask], M.Map FilePath (Data.Set.Set A.ModName)) buildGlobalTasks sp gopts opts projMap mSeeds = do perProj <- forM (M.elems projMap) $ \ctx -> do mods <- enumerateProjectModules ctx return (ctx, mods) let modMaps = M.fromList [ (projRoot ctx, M.fromList [ (mn, actFile) | (actFile, mn) <- mods ]) | (ctx, mods) <- perProj ] modSets = M.map Data.Set.fromList (M.map M.keys modMaps) orderCache = M.fromList [ (projRoot ctx, projRoot ctx : projDepClosure projMap (projRoot ctx)) | (ctx, _) <- perProj ] allKeys = [ TaskKey (projRoot ctx) mn | (ctx, mods) <- perProj, (_, mn) <- mods ] seedKeys <- case mSeeds of Nothing -> return allKeys Just files -> do absFiles <- mapM canonicalizePath files let pathIndex = M.fromList [ (actFile, TaskKey (projRoot ctx) mn) | (ctx, mods) <- perProj, (actFile, mn) <- mods ] found = mapMaybe (`M.lookup` pathIndex) absFiles return (if null found then allKeys else found) tasks <- go modMaps modSets orderCache Data.Set.empty seedKeys [] return (reverse tasks, modSets) where go modMaps modSets orderCache seen [] acc = return acc go modMaps modSets orderCache seen (k:qs) acc | Data.Set.member k seen = go modMaps modSets orderCache seen qs acc | otherwise = case M.lookup (tkProj k) modMaps >>= M.lookup (tkMod k) of Nothing -> go modMaps modSets orderCache (Data.Set.insert k seen) qs acc Just actFile -> do let ctx = projMap M.! tkProj k paths <- pathsForModule opts projMap ctx (tkMod k) task <- readModuleTask sp gopts opts paths actFile let order = M.findWithDefault [tkProj k] (tkProj k) orderCache providers = resolveProviders order modSets (importsOf task) newKeys = M.elems providers acc' = GlobalTask { gtKey = k , gtPaths = paths , gtTask = task , gtImportProviders = providers } : acc go modMaps modSets orderCache (Data.Set.insert k seen) (qs ++ newKeys) acc' -- | Select the subgraph needed for a given build request. -- Maps file paths to TaskKeys, adds __builtin__, and computes the reachable -- dependency closure. selectNeededTasks :: Paths -> FilePath -> [GlobalTask] -> [FilePath] -> IO [GlobalTask] selectNeededTasks pathsRoot rootProj globalTasks srcFiles = do requestedKeys <- catMaybes <$> mapM (lookupTaskKey globalTasks) srcFiles let wantedNames = map takeFileName srcFiles requestedKeys' = if null requestedKeys then [ gtKey t | t <- globalTasks , takeFileName (srcFile (gtPaths t) (tkMod (gtKey t))) `elem` wantedNames ] else requestedKeys builtinKeys = [ gtKey t | t <- globalTasks, tkMod (gtKey t) == A.modName ["__builtin__"] ] startKeys = if null requestedKeys' then map gtKey globalTasks else requestedKeys' ++ builtinKeys depMapSet = M.fromList [ (gtKey t, Data.Set.fromList (M.elems (gtImportProviders t))) | t <- globalTasks ] neededKeys = reachable depMapSet (Data.Set.fromList startKeys) return [ t | t <- globalTasks, Data.Set.member (gtKey t) neededKeys ] where lookupTaskKey ts f = do absF <- canonicalizePath f let byPath = listToMaybe [ gtKey t | t <- ts , let k = gtKey t pths = gtPaths t , srcFile pths (tkMod k) == absF ] case byPath of Just k -> return (Just k) Nothing -> do mn <- moduleNameFromFile (srcDir pathsRoot) absF return $ listToMaybe [ gtKey t | t <- ts , tkProj (gtKey t) == rootProj , tkMod (gtKey t) == mn ] reachable depMap start = go (Data.Set.toList start) Data.Set.empty where go [] seen = seen go (k:ks) seen = if Data.Set.member k seen then go ks seen else let deps = Data.Set.toList (M.findWithDefault Data.Set.empty k depMap) in go (deps ++ ks) (Data.Set.insert k seen) -- | Select the minimal subgraph affected by a set of changed files. -- Computes reverse dependencies so we rebuild dependents while keeping -- unrelated modules untouched. selectAffectedTasks :: [GlobalTask] -> [FilePath] -> IO [GlobalTask] selectAffectedTasks globalTasks changedFiles = do if null changedFiles then return globalTasks else do absChanged <- mapM normalizePathSafe changedFiles taskPaths <- forM globalTasks $ \t -> do let k = gtKey t pths = gtPaths t p <- normalizePathSafe (srcFile pths (tkMod k)) return (p, k) let pathIndex = M.fromList taskPaths changedKeys = catMaybes [ M.lookup p pathIndex | p <- absChanged ] if null changedKeys then return globalTasks else do let taskKeys = Data.Set.fromList (map gtKey globalTasks) depMap = M.fromList [ (gtKey t, filter (`Data.Set.member` taskKeys) (M.elems (gtImportProviders t))) | t <- globalTasks ] revMap = foldl' (\acc (k, ds) -> foldl' (\a d -> M.insertWith (++) d [k] a) acc ds) M.empty (M.toList depMap) affected = reverseClosure revMap (Data.Set.fromList changedKeys) -- Keep original provider mappings so unchanged imports can still -- resolve via cached interfaces during incremental checks. return [ t | t <- globalTasks, Data.Set.member (gtKey t) affected ] where reverseClosure revMap start = go start (Data.Set.toList start) where go seen [] = seen go seen (k:ks) = let ds = M.findWithDefault [] k revMap new = filter (`Data.Set.notMember` seen) ds seen' = foldl' (flip Data.Set.insert) seen new in go seen' (ks ++ new) data ModuleHead = TyHead { mhName :: A.ModName , mhSrcHash :: B.ByteString , mhPubHash :: B.ByteString , mhImplHash :: B.ByteString , mhTyImports :: [(A.ModName, B.ByteString)] , mhNameHashes :: [InterfaceFiles.NameHashInfo] , mhRoots :: [A.Name] , mhTests :: [String] , mhDoc :: Maybe String } | SrcHead { mhName :: A.ModName , mhSrc :: String , mhBytes :: B.ByteString , mhSourceMeta :: Maybe InterfaceFiles.SourceFileMeta , mhSrcImports :: [A.ModName] , mhDoc :: Maybe String } | HeadError { mhName :: A.ModName , mhDiagnostics :: [Diagnostic String] } -- | Read the cheap module header used by discovery and doc indexing. -- Reuse a valid .ty header when possible; otherwise read the source snapshot -- and parse only the module docstring plus imports. readModuleHeader :: Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> Paths -> String -> IO ModuleHead readModuleHeader sp gopts opts paths actFile = do let mn = modName paths tyFile = outBase paths mn ++ ".ty" tyExists <- doesFileExist tyFile if not tyExists then readSourceHead mn else do -- .ty exists: read the cached header and validate it against compiler -- compatibility plus source metadata/content as needed. hdrE <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readHeader tyFile case hdrE of Left _ -> readSourceHead mn Right (cachedSourceMeta, moduleSrcBytesHash, modulePubHash, moduleImplHash, imps, nameHashes, roots, tests, mdoc) -> do tyStatus <- getFileStatus tyFile let tyMTimeNs = fileStatusMTimeNs tyStatus newCompiler <- compilerNewerThan tyMTimeNs mOverlay <- Source.spReadOverlay sp actFile case mOverlay of Just snap -> if newCompiler then sourceHeadFromSnapshot mn snap else verifyOrParse mn snap moduleSrcBytesHash modulePubHash moduleImplHash cachedSourceMeta Nothing imps nameHashes roots tests mdoc Nothing -> do if newCompiler then readSourceHead mn else do currentSourceMeta <- readSourceFileMeta actFile if canReuseHeader cachedSourceMeta currentSourceMeta tyMTimeNs then return (mkTyHead mn moduleSrcBytesHash modulePubHash moduleImplHash imps nameHashes roots tests mdoc) else do snap <- Source.spReadFile sp actFile verifyOrParse mn snap moduleSrcBytesHash modulePubHash moduleImplHash cachedSourceMeta (Just currentSourceMeta) imps nameHashes roots tests mdoc where fileStatusMTimeNs st = floor (toRational (modificationTimeHiRes st) * 1000000000) mkTyHead mn moduleSrcBytesHash modulePubHash moduleImplHash imps nameHashes roots tests mdoc = TyHead { mhName = mn , mhSrcHash = moduleSrcBytesHash , mhPubHash = modulePubHash , mhImplHash = moduleImplHash , mhTyImports = imps , mhNameHashes = nameHashes , mhRoots = roots , mhTests = tests , mhDoc = mdoc } metadataMatches cached current = case cached of Nothing -> False Just meta -> meta == current canReuseHeader cached current tyMTimeNs = metadataMatches cached current && InterfaceFiles.sfmMTimeNs current < tyMTimeNs readSourceHead mn = do snap <- Source.readSource sp actFile sourceHeadFromSnapshot mn snap sourceHeadFromSnapshot mn snap = do headerRes <- parseActHeaderSnapshot mn actFile snap case headerRes of Left diags -> return $ HeadError mn diags Right (imps, mdoc) -> do mSourceMeta <- snapshotSourceMeta snap return $ SrcHead mn (Source.ssText snap) (Source.ssBytes snap) mSourceMeta imps mdoc snapshotSourceMeta snap | Source.ssIsOverlay snap = return Nothing | otherwise = Just <$> readSourceFileMeta actFile compilerNewerThan tyMTimeNs | C.ignore_compiler_version opts = return False | otherwise = do exePathE <- (try getExecutablePath :: IO (Either SomeException FilePath)) case exePathE of Left _ -> return False Right exePath -> do exeStatusE <- (try (getFileStatus exePath) :: IO (Either SomeException FileStatus)) case exeStatusE of Left _ -> return False Right exeStatus -> return (fileStatusMTimeNs exeStatus > tyMTimeNs) refreshCachedSourceMeta currentSourceMeta = do let tyFilePath = outBase paths (modName paths) ++ ".ty" tyRes <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readFile tyFilePath case tyRes of Left _ -> return () Right (_ms, nmod, tmod, _oldSourceMeta, srcHash, pubHash, implHash, imps, nameHashes, roots, tests, mdoc) -> InterfaceFiles.writeFile tyFilePath srcHash pubHash implHash currentSourceMeta imps nameHashes roots tests mdoc nmod tmod verifyOrParse mn snap moduleSrcBytesHash modulePubHash moduleImplHash cachedSourceMeta currentSourceMeta imps nameHashes roots tests mdoc = do let curHash = SHA256.hash (Source.ssBytes snap) short8 bs = take 8 (B.unpack $ Base16.encode bs) same = curHash == moduleSrcBytesHash when (C.verbose gopts && Source.ssIsOverlay snap) $ do actTime <- Source.spGetModTime sp actFile tyTime <- getModificationTime (outBase paths mn ++ ".ty") let len = B.length (Source.ssBytes snap) putStrLn ("[debug] readModuleHeader " ++ modNameToString mn ++ " act=" ++ show actTime ++ " ty=" ++ show tyTime ++ " hash=" ++ short8 curHash ++ " header=" ++ short8 moduleSrcBytesHash ++ " len=" ++ show len ++ if same then " (match)" else " (diff)") if same then do when (currentSourceMeta /= Nothing && currentSourceMeta /= cachedSourceMeta) $ refreshCachedSourceMeta currentSourceMeta return (mkTyHead mn moduleSrcBytesHash modulePubHash moduleImplHash imps nameHashes roots tests mdoc) else sourceHeadFromSnapshot mn snap -- | Prepare a task for dependency graph construction. -- The full source parse is deferred for modules whose .ty header cannot be -- reused, but discovery still gets accurate imports from the source header. readModuleTask :: Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> Paths -> String -> IO CompileTask readModuleTask sp gopts opts paths actFile = do h <- readModuleHeader sp gopts opts paths actFile return $ case h of TyHead{ mhName = mn , mhSrcHash = srcHash , mhPubHash = pubHash , mhImplHash = implHash , mhTyImports = imps , mhNameHashes = nameHashes , mhRoots = roots , mhTests = tests , mhDoc = mdoc } -> let nmodStub = I.NModule [] [] mdoc tmodStub = A.Module mn [] mdoc [] in TyTask { name = mn , tyHash = srcHash , tyPubHash = pubHash , tyImplHash = implHash , tyImports = imps , tyNameHashes = nameHashes , tyRoots = roots , tyTests = tests , tyDoc = mdoc , iface = nmodStub , typed = tmodStub } SrcHead{ mhName = mn , mhSrc = srcContent , mhBytes = bytes , mhSourceMeta = mSourceMeta , mhSrcImports = imps } -> ParseTask mn srcContent bytes mSourceMeta imps HeadError{ mhName = mn, mhDiagnostics = diags } -> ParseErrorTask mn diags readModuleDoc :: Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> Paths -> String -> IO (Maybe (A.ModName, Maybe String)) readModuleDoc sp gopts opts paths actFile = do h <- readModuleHeader sp gopts opts paths actFile return $ case h of TyHead{ mhName = mn, mhDoc = mdoc } -> Just (mn, mdoc) SrcHead{ mhName = mn, mhDoc = mdoc } -> Just (mn, mdoc) HeadError{} -> Nothing -- | Materialize a source-backed task into a fully parsed ActonTask. -- ParseTask reuses the snapshot captured during graph discovery; TyTask reparses -- from the current source file because the cached header was deemed stale. materializeTask :: C.CompileOptions -> Source.SourceProvider -> A.ModName -> FilePath -> Maybe (ParseProgress -> IO ()) -> CompileTask -> IO CompileTask materializeTask opts sp mn actFile mOnProgress task = case task of ActonTask{} -> return task ParseErrorTask{} -> return task ParseTask{ src = srcContent, srcBytes = bytes, sourceMeta = mSourceMeta } -> do emod <- parseStoredSource mn actFile srcContent case emod of Left diags -> return (ParseErrorTask mn diags) Right m -> return (ActonTask mn srcContent bytes mSourceMeta m) TyTask{} -> do parsedRes <- parseActFile opts sp mn actFile mOnProgress case parsedRes of Left diags -> return (ParseErrorTask mn diags) Right (snap, m) -> do mSourceMeta <- if Source.ssIsOverlay snap then return Nothing else Just <$> readSourceFileMeta actFile return $ ActonTask mn (Source.ssText snap) (Source.ssBytes snap) mSourceMeta m where parseStoredSource mn' file srcContent = do cwd <- getCurrentDirectory let displayFile = makeRelative cwd file parseActSource opts mn' displayFile srcContent mOnProgress -- | Recursively read imports for a set of tasks within the same project. -- Any missing module is added by parsing or reading its .ty header via -- readModuleTask, yielding a self-contained task list. readImports :: Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> Paths -> [CompileTask] -> IO [CompileTask] readImports sp gopts opts paths tasks = do let tasks' = filter (\t -> name t /= modName paths) tasks chaseRecursively tasks' [] (concatMap importsOf tasks') where readAFile tasks mn = case lookUp mn tasks of Just _ -> return Nothing Nothing -> do let actFile = srcFile paths mn ok <- doesFileExist actFile if ok then do p <- findPaths actFile opts t <- readModuleTask sp gopts opts p actFile return (Just t) else return Nothing lookUp mn (t:ts) | name t == mn = Just t | otherwise = lookUp mn ts lookUp _ [] = Nothing chaseRecursively tasks mns [] = return tasks chaseRecursively tasks mns (imn:imns) | imn `elem` mns = chaseRecursively tasks mns imns | otherwise = do t <- readAFile tasks imn chaseRecursively (maybe tasks (:tasks) t) (imn:mns) (imns ++ concatMap importsOf (maybe [] (:[]) t)) -- | Decide whether to suppress per-module timing/log output. -- We also treat any alternate output mode (parse/sigs/cgen/etc) as quiet. quiet :: C.GlobalOptions -> C.CompileOptions -> Bool quiet gopts opts = C.quiet gopts || altOutput opts -- | Read an interface from a .ty file and return its NameInfo and public hash. -- This is used when a module is deemed fresh and we want to avoid reparsing. readIfaceFromTy :: Paths -> A.ModName -> String -> Maybe B.ByteString -> IO (Either [Diagnostic String] ([A.ModName], [(A.Name, I.NameInfo)], Maybe String, B.ByteString)) readIfaceFromTy paths mn src mHash = do mty <- Acton.Env.findTyFile (searchPath paths) mn case mty of Nothing -> return $ Left (missingIfaceDiagnostics mn src mn) Just tyF -> do fileRes <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readFile tyF case fileRes of Left _ -> return $ Left (missingIfaceDiagnostics mn src mn) Right (_ms, nmod, _tmod, _sourceMeta, _srcH, _pubH, _implH, _imps, _nameHashes, _roots, _tests, _tm) -> do let I.NModule ms teFull mdoc = nmod te = publicIfaceTE teFull ih <- case mHash of Just h -> return h Nothing -> do hdrE <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readHeader tyF case hdrE of Right (_sourceMetaH, _srcH, ihash, _implH, _impsH, _nameHashesH, _rootsH, _testsH, _docH) -> return ihash _ -> return B.empty return $ Right (ms, te, mdoc, ih) -- | Snapshot of expected/recorded impl hashes for generated code. data CodegenStatus = CodegenStatus { csExpected :: String , csC :: Maybe String , csH :: Maybe String } -- | Header prefix used to tag generated code with the module impl hash. codegenHashTag :: String codegenHashTag = "/* Acton impl hash:" -- | Parse a tagged hash line from generated output. extractCodegenHash :: String -> Maybe String extractCodegenHash line = do rest <- Data.List.stripPrefix codegenHashTag line let rest' = dropWhile isSpace rest hex = takeWhile isHexDigit rest' if null hex then Nothing else Just hex -- | Read the tagged hash from a generated file, if present. readCodegenHash :: FilePath -> IO (Maybe String) readCodegenHash path = do exists <- doesFileExist path if not exists then return Nothing else do res <- (try :: IO a -> IO (Either SomeException a)) $ withFile path ReadMode hGetLine case res of Left _ -> return Nothing Right line -> return (extractCodegenHash line) -- | Collect codegen hash status for a module. codegenStatus :: Paths -> A.ModName -> B.ByteString -> IO CodegenStatus codegenStatus paths mn implHash = do let expected = B.unpack $ Base16.encode implHash cFile = outBase paths mn ++ ".c" hFile = outBase paths mn ++ ".h" cHash <- readCodegenHash cFile hHash <- readCodegenHash hFile return CodegenStatus { csExpected = expected, csC = cHash, csH = hHash } -- | Check whether generated .c/.h hashes match the expected impl hash. codegenUpToDate :: CodegenStatus -> Bool codegenUpToDate status = csC status == Just (csExpected status) && csH status == Just (csExpected status) -- | Format a short delta message for stale codegen. formatCodegenDelta :: CodegenStatus -> String formatCodegenDelta status = let expected = take 8 (csExpected status) short actual = maybe "missing" (take 8) actual in case (csC status, csH status) of (Just c, Just h) | c == h -> " {impl " ++ take 8 c ++ " -> " ++ expected ++ "}" _ -> " {impl c " ++ short (csC status) ++ " -> " ++ expected ++ ", h " ++ short (csH status) ++ " -> " ++ expected ++ "}" -- | Run the front passes for a single module. -- Builds the environment, runs kinds/types, computes per-name src/pub/impl -- hashes plus module pub/impl hashes, and writes the .ty header. Returns the -- front result plus a BackJob for later passes when compilation is needed. runFrontPasses :: C.GlobalOptions -> C.CompileOptions -> Paths -> Acton.Env.Env0 -> A.Module -> String -> B.ByteString -> Maybe InterfaceFiles.SourceFileMeta -> (A.ModName -> IO (Maybe B.ByteString)) -> (A.ModName -> IO (Maybe (M.Map A.Name InterfaceFiles.NameHashInfo))) -> (FrontPassProgress -> IO ()) -> IO (Either [Diagnostic String] FrontResult) runFrontPasses gopts opts paths env0 parsed srcContent srcBytes sourceMeta resolveImportHash resolveNameHashMap onFrontProgress = do createDirectoryIfMissing True (getModPath (projTypes paths) mn) core `catch` handleGeneral `catch` handleCompilation `catch` handleTypeErrors `catch` handleTypeError where mn = A.modname parsed filename = modNameToFilename mn outbase = outBase paths mn absSrcBase = srcBase paths mn actFile = absSrcBase ++ ".act" prettyAstStyle = style { mode = PageMode, lineLength = 120, ribbonsPerLine = 1.0 } handleGeneral :: GeneralError -> IO (Either [Diagnostic String] FrontResult) handleGeneral err = return $ Left (errsToDiagnostics "Compilation error" filename srcContent (generalError err)) handleCompilation :: Acton.Env.CompilationError -> IO (Either [Diagnostic String] FrontResult) handleCompilation err = return $ Left (errsToDiagnostics "Compilation error" filename srcContent (Acton.Env.compilationError err)) handleTypeError :: Acton.TypeEnv.TypeError -> IO (Either [Diagnostic String] FrontResult) handleTypeError err = return $ Left [Acton.TypeEnv.mkErrorDiagnostic filename srcContent (Acton.TypeEnv.typeReport err filename srcContent)] handleTypeErrors :: Acton.Types.TypeErrors -> IO (Either [Diagnostic String] FrontResult) handleTypeErrors (Acton.Types.TypeErrors errs) = return $ Left [ Acton.TypeEnv.mkErrorDiagnostic filename srcContent (Acton.TypeEnv.typeReport err filename srcContent) | err <- errs ] resolveImportHashes :: [A.ModName] -> IO (Either [Diagnostic String] [(A.ModName, B.ByteString)]) resolveImportHashes mrefs = do resolved <- forM mrefs $ \mref -> do mh <- resolveImportHash mref case mh of Just ih -> return (Right (mref, ih)) Nothing -> return (Left (missingIfaceDiagnostics mn srcContent mref)) let (errs, vals) = partitionEithers resolved if null errs then return (Right vals) else return (Left (concat errs)) missingNameHashDiagnostics :: A.QName -> [Diagnostic String] missingNameHashDiagnostics qn = errsToDiagnostics "Compilation error" filename srcContent [(NoLoc, "Hash info missing for " ++ prstr qn)] missingDepHashDiagnostics :: String -> A.Name -> SrcLoc -> A.QName -> [Diagnostic String] missingDepHashDiagnostics label owner loc qn = errsToDiagnostics "Compilation error" filename srcContent [(loc, label ++ " hash missing for " ++ prstr qn ++ " (used by " ++ A.nstr owner ++ ")")] resolveNameHashMaps :: [A.ModName] -> IO (Either [Diagnostic String] (M.Map A.ModName (M.Map A.Name InterfaceFiles.NameHashInfo))) resolveNameHashMaps mrefs = do resolved <- forM mrefs $ \mref -> do mh <- resolveNameHashMap mref case mh of Just hm -> return (Right (mref, hm)) Nothing -> return (Left (missingIfaceDiagnostics mn srcContent mref)) let (errs, vals) = partitionEithers resolved if null errs then return (Right (M.fromList vals)) else return (Left (concat errs)) resolveDepHashes :: String -> (InterfaceFiles.NameHashInfo -> B.ByteString) -> M.Map A.Name [A.QName] -> M.Map A.ModName (M.Map A.Name InterfaceFiles.NameHashInfo) -> M.Map A.Name SrcLoc -> Either [Diagnostic String] (M.Map A.Name [(A.QName, B.ByteString)]) resolveDepHashes label getHash deps extMaps nameLocs = let resolveQName owner qn = case qn of A.GName m n -> lookupName owner m n A.QName m n -> lookupName owner m n A.NoQ _ -> Left (missingNameHashDiagnostics qn) lookupName owner m n = case M.lookup m extMaps of Nothing -> Left (missingIfaceDiagnostics mn srcContent m) Just hm -> case M.lookup n hm of Just info -> let h = getHash info loc = M.findWithDefault NoLoc owner nameLocs in if B.null h then Left (missingDepHashDiagnostics label owner loc (A.GName m n)) else Right (Just (A.GName m n, h)) Nothing -> Left (missingNameHashDiagnostics (A.GName m n)) resolveForName (n, qns) = let qnsSorted = Data.List.sortOn Hashing.qnameKey (Data.Set.toList (Data.Set.fromList qns)) resolved = map (resolveQName n) qnsSorted (errs, vals) = partitionEithers resolved in if null errs then Right (n, catMaybes vals) else Left (concat errs) (errs, vals) = partitionEithers (map resolveForName (M.toList deps)) in if null errs then Right (M.fromList vals) else Left (concat errs) emitFrontProgress pass completed total current = onFrontProgress FrontPassProgress { fppPass = pass , fppCompleted = completed , fppTotal = total , fppCurrent = current } core = do timeStart <- getTime Monotonic let isRoot = mn == modName paths when (C.parse opts && isRoot) $ dump mn "parse" (Pretty.print parsed) when (C.parse_ast opts && isRoot) $ dump mn "parse-ast" (renderStyle prettyAstStyle (ppDoc parsed)) typeStmtTimingsRef <- newIORef ([] :: [TypeStmtTiming]) inferredSigsRef <- newIORef ([] :: [InferredSignature]) typeActiveRef <- newIORef Nothing let onTypeProgress total completed current names _weight = do now <- getTime Monotonic mActive <- readIORef typeActiveRef forM_ mActive $ \(label, bindNames, activeTotal, t0) -> modifyIORef' typeStmtTimingsRef ( TypeStmtTiming { tstCompleted = completed , tstTotal = activeTotal , tstLabel = label , tstNames = bindNames , tstTime = now - t0 } : ) case current of Just label -> writeIORef typeActiveRef (Just (label, names, total, now)) Nothing -> writeIORef typeActiveRef Nothing emitFrontProgress FrontPassTypes completed total current onInferredSignature names sig = modifyIORef' inferredSigsRef (InferredSignature names sig :) inferredSignatureCb = if C.timing gopts || C.verbose gopts then Just onInferredSignature else Nothing env <- Acton.Env.mkEnv (searchPath paths) env0 parsed timeEnv <- getTime Monotonic emitFrontProgress FrontPassKinds 0 1 Nothing kchecked <- Acton.Kinds.check env parsed emitFrontProgress FrontPassKinds 1 1 Nothing iff (C.kinds opts && isRoot) $ dump mn "kinds" (Pretty.print kchecked) timeKindsCheck <- getTime Monotonic -- Type-check and return both the typed AST and the interface NameInfo. (nmod,tchecked,typeEnv,tests) <- Acton.Types.reconstruct (Just onTypeProgress) inferredSignatureCb env kchecked forceTypeResult nmod tchecked typeEnv tests -- Module-level src hash uses raw bytes so any source edit forces re-parse. let moduleSrcBytesHash = SHA256.hash srcBytes -- Store roots so later builds can discover entry points without reparse. let I.NModule imps fullIface mdoc = nmod publicIface = publicIfaceTE fullIface let roots = [ n | (n,i) <- fullIface, rootEligible i ] -- Import hashes are recorded in the .ty header so dep changes can be detected. impsRes <- resolveImportHashes imps case impsRes of Left diags -> return (Left diags) Right impsWithHash -> do -- Extract top-level items from parsed and typed ASTs for per-name hashes. let srcItems = Hashing.topLevelItems parsed implItems = Hashing.topLevelItems tchecked -- src hashes come only from parsed AST fragments. nameSrcHashes = Hashing.nameHashesFromItems srcItems -- impl hashes are derived from the typed AST bodies. this is the -- local function hash, implDeps are added later nameImplHashes = Hashing.nameHashesFromItems implItems -- NameInfo defines the full local environment for this module. nameInfoMap = M.fromList fullIface nameSrcKeys = M.keysSet nameSrcHashes nameImplKeys = M.keysSet nameImplHashes nameKeys = Data.Set.union nameSrcKeys nameImplKeys nameLocsParsed = M.fromListWith (\a _ -> a) [ (n, A.dloc d) | Hashing.TLDecl n d <- srcItems ] `M.union` M.fromListWith (\a _ -> a) [ (n, A.sloc s) | Hashing.TLStmt n s <- srcItems ] nameLocsTyped = M.fromListWith (\a _ -> a) [ (n, A.dloc d) | Hashing.TLDecl n d <- implItems ] `M.union` M.fromListWith (\a _ -> a) [ (n, A.sloc s) | Hashing.TLStmt n s <- implItems ] nameLocs = M.union nameLocsParsed nameLocsTyped -- pubSigDeps: signature-level deps from NameInfo (types only). let isDerivedName n = case n of A.Derived{} -> True _ -> False isDerivedQName qn = case qn of A.GName _ n -> isDerivedName n A.QName _ n -> isDerivedName n A.NoQ n -> isDerivedName n dropDerived = filter (not . isDerivedQName) pubSigDepsRaw = M.fromList [ (n, dropDerived (Names.freeQ info)) | (n, info) <- M.toList nameInfoMap ] -- implDeps: term-level deps from typed bodies. implDepsRaw = Hashing.implDepsFromItems implItems -- pubDeps include signature deps plus any term-level deps for reuse in pubHash. -- Derived names are internal and should never require a pub hash. pubDepsRaw = M.map dropDerived (M.unionWith (++) pubSigDepsRaw implDepsRaw) hashEnv = setMod mn env -- Split deps into local (same module) vs external (qualified) names. (pubSigLocalDeps, pubSigExtDeps) = Hashing.splitDeps mn hashEnv nameKeys pubSigDepsRaw (_, pubExtDeps) = Hashing.splitDeps mn hashEnv nameKeys pubDepsRaw (implLocalDeps, implExtDeps) = Hashing.splitDeps mn hashEnv nameKeys implDepsRaw -- Load .ty maps for any external modules referenced by deps. extMods = Data.Set.toList (Hashing.externalModules pubExtDeps `Data.Set.union` Hashing.externalModules implExtDeps) extMapsRes <- resolveNameHashMaps extMods case extMapsRes of Left diags -> return (Left diags) Right extMaps -> do -- Resolve external deps to their recorded hashes. let pubSigExtRes = resolveDepHashes "pub" InterfaceFiles.nhPubHash pubSigExtDeps extMaps nameLocs pubExtRes = resolveDepHashes "pub" InterfaceFiles.nhPubHash pubExtDeps extMaps nameLocs implExtRes = resolveDepHashes "impl" InterfaceFiles.nhImplHash implExtDeps extMaps nameLocs case (pubSigExtRes, pubExtRes, implExtRes) of (Left diags, _, _) -> return (Left diags) (_, Left diags, _) -> return (Left diags) (_, _, Left diags) -> return (Left diags) (Right pubSigExtHashes, Right pubExtHashes, Right implExtHashes) -> do -- Build per-name hash records (src/pub/impl + deps) for .ty. let nameHashes = Hashing.buildNameHashes nameKeys nameSrcHashes nameImplHashes nameInfoMap pubSigLocalDeps pubSigExtHashes implLocalDeps implExtHashes pubExtHashes -- Module-level hashes summarize the per-name hashes. let modulePubHash = Hashing.modulePubHashFromIface nmod nameHashes moduleImplHash = Hashing.moduleImplHashFromNameHashes nameHashes -- Write .ty now so later builds can reuse this front-pass work. InterfaceFiles.writeFile (outbase ++ ".ty") moduleSrcBytesHash modulePubHash moduleImplHash sourceMeta impsWithHash nameHashes roots tests mdoc nmod tchecked iff (C.types opts && isRoot) $ dump mn "types" (Pretty.print tchecked) iff (C.sigs opts && isRoot) $ dump mn "sigs" (Acton.Types.prettySigs env mn imps fullIface) -- Generate documentation, if building for a project when (not (C.skip_build opts) && not (isTmp paths)) $ do let docDir = joinPath [projPath paths, "out", "doc"] modPathList = A.modPath mn docFile = if null modPathList then docDir "unnamed" <.> "html" else joinPath (docDir : init modPathList) last modPathList <.> "html" docFileDir = takeDirectory docFile -- Get the type environment for this module modTypeEnv = case Acton.Env.lookupMod mn typeEnv of Just te -> te Nothing -> publicIface -- Apply the same simplification as --sigs uses env1 = define publicIface $ setMod mn env simplifiedTypeEnv = simp env1 modTypeEnv createDirectoryIfMissing True docFileDir -- Use parsed (original AST) to preserve docstrings let htmlDoc = DocP.printHtmlDoc (I.NModule imps simplifiedTypeEnv mdoc) parsed writeFile docFile htmlDoc timeTypeCheck <- getTime Monotonic typeStmtTimings <- reverse <$> readIORef typeStmtTimingsRef timeFrontEnd <- getTime Monotonic inferredSigs <- reverse <$> readIORef inferredSigsRef let frontTime = timeFrontEnd - timeStart frontTimeMaybe = if not (quiet gopts opts) then Just frontTime else Nothing frontTimingMaybe = if C.timing gopts then Just FrontTiming { ftEnv = timeEnv - timeStart , ftKinds = timeKindsCheck - timeEnv , ftTypes = timeTypeCheck - timeKindsCheck , ftTypeStmtTimings = typeStmtTimings } else Nothing backJob = Just BackJob { bjPaths = paths , bjOpts = opts , bjInput = BackInput { biTypeEnv = typeEnv , biTypedMod = tchecked , biSrc = srcContent , biImplHash = moduleImplHash } } return $ Right FrontResult { frIfaceTE = publicIface , frImps = imps , frDoc = mdoc , frPubHash = modulePubHash , frNameHashes = publicNameHashes nameHashes , frFrontTime = frontTimeMaybe , frFrontTiming = frontTimingMaybe , frInferredSigs = inferredSigs , frBackJob = backJob } -- | Run the back passes for a single module. -- Executes normalization through codegen, writes .c/.h output as needed, and -- returns the back-pass elapsed time for logging. runBackPasses :: C.GlobalOptions -> C.CompileOptions -> Paths -> BackInput -> IO Bool -> IO (Maybe TimeSpec, Maybe BackTiming) runBackPasses gopts opts paths backInput shouldWrite = do let mn = A.modname (biTypedMod backInput) outbase = outBase paths mn relSrcBase = makeRelative (projPath paths) (srcBase paths mn) timeStart <- getTime Monotonic writeTimingRef <- newIORef Nothing (normalized, normEnv) <- Acton.Normalizer.normalize (biTypeEnv backInput) (biTypedMod backInput) iff (C.norm opts && mn == (modName paths)) $ dump mn "norm" (Pretty.print normalized) timeNormalized <- getTime Monotonic (deacted,deactEnv) <- Acton.Deactorizer.deactorize normEnv normalized iff (C.deact opts && mn == (modName paths)) $ dump mn "deact" (Pretty.print deacted) timeDeactorizer <- getTime Monotonic (cpstyled,cpsEnv) <- Acton.CPS.convert deactEnv deacted iff (C.cps opts && mn == (modName paths)) $ dump mn "cps" (Pretty.print cpstyled) timeCPS <- getTime Monotonic (lifted,liftEnv) <- Acton.LambdaLifter.liftModule cpsEnv cpstyled iff (C.llift opts && mn == (modName paths)) $ dump mn "llift" (Pretty.print lifted) timeLLift <- getTime Monotonic boxed <- Acton.Boxing.doBoxing liftEnv lifted iff (C.box opts && mn == (modName paths)) $ dump mn "box" (Pretty.print boxed) timeBoxing <- getTime Monotonic let hexHash = B.unpack $ Base16.encode (biImplHash backInput) emitLines = not (C.dbg_no_lines opts) (n,h,c) <- Acton.CodeGen.generate liftEnv relSrcBase (biSrc backInput) emitLines boxed hexHash timeCodeGen <- getTime Monotonic let finish = do timeEnd <- getTime Monotonic let backTime = timeEnd - timeStart mWriteTime <- readIORef writeTimingRef let backTimingMaybe = if C.timing gopts then Just BackTiming { btNormalize = timeNormalized - timeStart , btDeactorize = timeDeactorizer - timeNormalized , btCPS = timeCPS - timeDeactorizer , btLLift = timeLLift - timeCPS , btBoxing = timeBoxing - timeLLift , btCodeGen = timeCodeGen - timeBoxing , btWriteCode = mWriteTime } else Nothing if not (quiet gopts opts) then return (Just backTime, backTimingMaybe) else return (Nothing, backTimingMaybe) forceOut s = evaluate (rnf s) if C.hgen opts then do forceOut h putStrLn h finish else if C.cgen opts then do forceOut c putStrLn c finish else do forceOut h forceOut c iff (not (altOutput opts)) (do ok <- shouldWrite when ok $ do let cFile = outbase ++ ".c" hFile = outbase ++ ".h" writeFile hFile h writeFile cFile c let tyFileName = modNameToString(modName paths) ++ ".ty" iff (C.ty opts) $ copyFileWithMetadata (joinPath [projTypes paths, tyFileName]) (joinPath [srcDir paths, tyFileName]) timeCodeWrite <- getTime Monotonic writeIORef writeTimingRef (Just (timeCodeWrite - timeCodeGen)) ) finish -- | Compile a set of GlobalTasks using a parallel, dependency-aware scheduler. -- This drives front passes, emits diagnostics via callbacks, and collects -- back-pass jobs for later execution. -- -- Total build graph scheduler: this compiles all tasks across all projects, -- i.e. dependencies of the main project are also compiled here, as well as -- their dependencies, etc. We construct a large DAG of all modules to be -- compiled and then compile in topological order using concurrent async -- workers. -- -- What we build the graph from: -- - Input is a list of GlobalTask. Each carries a CompileTask (ActonTask or -- TyTask), its Paths, and a pre-resolved provider map (gtImportProviders :: -- Map ModName TaskKey) telling us which in-graph node satisfies a given -- import. TaskKey is (projectRoot, modName). -- - We always read an initial set of modules (either all src/ files in the -- root project for a project build or the user-specified files). From those -- keys we chase imports via gtImportProviders to pull in exactly the -- reachable dependencies across projects. __builtin__ is compiled first if -- present, i.e. we are building the base lib. -- -- 1) Construct a dependency graph over non-builtin tasks and topologically order it. -- 2) Compile __builtin__ first if present. -- 3) Walk modules in topo order, deciding per module whether to compile or reuse cached .ty, -- and update the shared environment. -- 4) Track per-name pub/impl hashes and only redo the work that changed: -- pub changes trigger front passes; impl changes trigger back passes (with -- an impl-hash refresh); codegen hash mismatches trigger back passes only. -- -- Key ideas (ActonTask vs TyTask caching): -- - TyTask is lightweight, read from the .ty header: moduleSrcBytesHash, modulePubHash, -- moduleImplHash, imports annotated with the pub hash used, per-name hashes (src/pub/impl -- + deps), roots, tests, and docstring. It avoids decoding heavy sections. -- - ParseTask carries source text plus discovered imports; full parsing is -- deferred until front passes are needed. -- - ActonTask carries parsed source and must be compiled. -- - pubMap :: Map TaskKey ByteString and nameMap :: Map TaskKey (Map Name NameHashInfo) are -- maintained during the run. TyTask compares recorded dependency hashes against current -- provider hashes (in-graph via pubMap/nameMap, otherwise via cached .ty headers). Pub deltas -- trigger front passes; impl deltas trigger back passes with an impl-hash refresh. -- - When a TyTask is stale for public reasons (or altOutput on the root), we convert it to an -- ActonTask by parsing the .act file and run front passes; when it is fresh we reuse the -- header and carry forward the recorded hashes. -- -- Scheduling: -- - Critical-path heuristic (file size proxy) picks among ready tasks; runs up to job cap. -- - Each worker uses an env snapshot; coordinator merges the resulting interface/doc and -- updates indegrees/ready sets. Dependents receive public hashes via pubMap. -- - Non-root projects are compiled with depOpts (skip_build/test) while the root keeps user opts. compileTasks :: Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> Paths -- root project paths (for alt output root selection) -> FilePath -- root project path -> [GlobalTask] -> CompileCallbacks -> IO (Either CompileFailure (Acton.Env.Env0, Bool)) compileTasks sp gopts opts rootPaths rootProj tasks callbacks = do runningRef <- newIORef [] let cancelRunning = readIORef runningRef >>= mapM_ cancel let compileMain = do -- Reject cycles if not (null cycles) then return $ Left (CompileCycleFailure ("Cyclic imports: " ++ concatMap showTaskGraph cycles)) else do -- Compile __builtin__ first if present anywhere in the graph case builtinOrder of [t] -> do res <- compileBuiltin t case res of Left err -> return (Left err) Right () -> continue runningRef _ -> continue runningRef compileMain `finally` cancelRunning where continue runningRef = do baseEnv <- Acton.Env.initEnv builtinPath False costMap <- fmap M.fromList $ forM otherOrder $ \t -> do let mn = name (gtTask t) pth = gtPaths t fp = srcFile pth mn ok <- doesFileExist fp sz <- if ok then getFileSize fp else return 0 return (gtKey t, sz) let cwMap = computeCriticalWeights costMap nCaps <- getNumCapabilities let maxParallel = max 1 (if C.jobs gopts > 0 then C.jobs gopts else nCaps) (envFinal, hadErrors) <- loop runningRef stageInitialReady [] M.empty M.empty M.empty stageIndeg stagePending0 baseEnv False maxParallel cwMap return (Right (envFinal, hadErrors)) -- Basic maps/sets ---------------------------------------------------- taskMap = M.fromList [ (gtKey t, t) | t <- tasks ] isBuiltinKey k = tkMod k == A.modName ["__builtin__"] builtinOrder = [ t | t <- tasks, isBuiltinKey (gtKey t) ] nonBuiltinTasks = [ t | t <- tasks, not (isBuiltinKey (gtKey t)) ] nonBuiltinKeys = Data.Set.fromList [ gtKey t | t <- nonBuiltinTasks ] depsOf t = nub [ d | d <- M.elems (gtImportProviders t), Data.Set.member d nonBuiltinKeys ] nodes = [ (t, gtKey t, depsOf t) | t <- nonBuiltinTasks ] sccs = stronglyConnComp nodes cycles = [ ts | ts@(CyclicSCC _) <- sccs ] order = [ t | AcyclicSCC t <- sccs ] showTaskGraph (CyclicSCC ts) = "\n" ++ concatMap fmt ts showTaskGraph _ = "" fmt t = tkProj (gtKey t) ++ ":" ++ modNameToString (name (gtTask t)) ++ " " otherOrder = order revMap :: M.Map TaskKey [TaskKey] revMap = foldl' (\acc (k, ds) -> foldl' (\a d -> M.insertWith (++) d [k] a) acc ds) M.empty (M.toList depMap) depMap :: M.Map TaskKey [TaskKey] depMap = M.fromList [ (gtKey t, depsOf t) | t <- order ] indeg = M.map length depMap depOpts = opts { C.skip_build = True, C.test = False } optsFor k = if tkProj k == rootProj then opts else depOpts needsParseStage t = case gtTask t of ParseTask{} -> not (C.only_build (optsFor (gtKey t))) _ -> False stageDepsOf t = let k = gtKey t parseDeps = [ParseStage k | needsParseStage t] frontDeps = map FrontStage (depsOf t) in (parseDeps ++ frontDeps) stageDepMap :: M.Map StageKey [StageKey] stageDepMap = M.fromList $ [ (ParseStage (gtKey t), []) | t <- order , needsParseStage t ] ++ [ (FrontStage (gtKey t), stageDepsOf t) | t <- order ] stageRevMap :: M.Map StageKey [StageKey] stageRevMap = foldl' (\acc (k, ds) -> foldl' (\a d -> M.insertWith (++) d [k] a) acc ds) M.empty (M.toList stageDepMap) stageIndeg :: M.Map StageKey Int stageIndeg = M.map length stageDepMap stageInitialReady :: [StageKey] stageInitialReady = [ k | (k, d) <- M.toList stageIndeg, d == 0 ] stagePending0 :: Data.Set.Set StageKey stagePending0 = Data.Set.fromList (M.keys stageIndeg) rootAlt = modName rootPaths builtinPath = case builtinOrder of (t:_) -> projTypes (gtPaths t) _ -> sysTypes rootPaths computeCriticalWeights :: M.Map TaskKey Integer -> M.Map TaskKey Integer computeCriticalWeights cm = cwMap where costOf m = M.findWithDefault 0 m cm depsOfK m = M.findWithDefault [] m revMap cwMap = M.fromList [ (m, costOf m + max0 [ weight d | d <- depsOfK m ]) | m <- M.keys indeg ] weight m = M.findWithDefault 0 m cwMap max0 [] = 0 max0 xs = maximum xs dependentClosure :: TaskKey -> Data.Set.Set TaskKey dependentClosure k = go Data.Set.empty [k] where go seen [] = seen go seen (x:xs) = let ds = M.findWithDefault [] x revMap new = filter (`Data.Set.notMember` seen) ds seen' = foldl' (flip Data.Set.insert) seen new in go seen' (new ++ xs) -- TODO: can we reintegrate this into the normal loop to avoid duplication? -- NOTE: FYI, it was originally part of the main loop but factored out for -- clarity when we changed to use async, front/back jobs etc. There were so -- many other changes so at the time it was easier to separate builtin -- compilation but perhaps we can find a way to merge it back in to one -- general loop. compileBuiltin :: GlobalTask -> IO (Either CompileFailure ()) compileBuiltin t = do let bPaths = gtPaths t mn = name (gtTask t) optsBuiltin = optsFor (gtKey t) actFile = srcFile bPaths mn forceAlt = altOutput optsBuiltin && mn == rootAlt if C.only_build optsBuiltin then return (Right ()) else do t' <- case gtTask t of TyTask{} | forceAlt -> materializeTask optsBuiltin sp mn actFile Nothing (gtTask t) ParseTask{} -> materializeTask optsBuiltin sp mn actFile Nothing (gtTask t) _ -> return (gtTask t) case t' of ParseErrorTask{ parseDiagnostics = diags } -> do ccOnDiagnostics callbacks t optsBuiltin diags return (Left CompileBuiltinFailure) TyTask{} -> return (Right ()) ParseTask{} -> error ("Internal error: unmaterialized ParseTask " ++ modNameToString mn) ActonTask{ src = srcContent, srcBytes = srcBytes, sourceMeta = mSourceMeta, atree = m } -> do ccOnFrontStart callbacks t optsBuiltin builtinEnv0 <- Acton.Env.initEnv (projTypes bPaths) True res <- runFrontPasses gopts optsBuiltin bPaths builtinEnv0 m srcContent srcBytes mSourceMeta (getPubHashCached bPaths) (getNameHashMapCached bPaths) (\p -> ccOnFrontProgress callbacks t optsBuiltin p) case res of Left diags -> do ccOnFrontDone callbacks t optsBuiltin ccOnDiagnostics callbacks t optsBuiltin diags return (Left CompileBuiltinFailure) Right fr -> do ccOnFrontDone callbacks t optsBuiltin ccOnFrontResult callbacks t optsBuiltin fr updatePubHashCache mn (frPubHash fr) updateNameHashCache mn (frNameHashes fr) forM_ (frBackJob fr) $ ccOnBackJob callbacks return (Right ()) -- One module --------------------------------------------------------- doOne :: Acton.Env.Env0 -> M.Map TaskKey B.ByteString -> M.Map TaskKey (M.Map A.Name InterfaceFiles.NameHashInfo) -> M.Map TaskKey CompileTask -> TaskKey -> IO (TaskKey, Either [Diagnostic String] FrontResult) doOne envSnap pubMap nameMap parsedTasks key = do t <- case M.lookup key taskMap of Just x -> return x Nothing -> error ("Internal error: missing task for key " ++ show key) let taskCurrent = M.findWithDefault (gtTask t) key parsedTasks paths = gtPaths t mn = name (gtTask t) optsT = optsFor key providers = gtImportProviders t actFile = srcFile paths mn tyFile = outBase paths mn ++ ".ty" short8 bs = take 8 (B.unpack $ Base16.encode bs) mkFrontResult imps ifaceTE mdoc pubHash nameHashes backJob = FrontResult { frIfaceTE = ifaceTE , frImps = imps , frDoc = mdoc , frPubHash = pubHash , frNameHashes = nameHashes , frFrontTime = Nothing , frFrontTiming = Nothing , frInferredSigs = [] , frBackJob = backJob } emptyFrontResult = FrontResult { frIfaceTE = [] , frImps = [] , frDoc = Nothing , frPubHash = B.empty , frNameHashes = [] , frFrontTime = Nothing , frFrontTiming = Nothing , frInferredSigs = [] , frBackJob = Nothing } cacheFrontResult fr = do updatePubHashCache mn (frPubHash fr) updateNameHashCache mn (frNameHashes fr) return (key, Right fr) readTyFile = do tyRes <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readFile tyFile case tyRes of Left _ -> return (Left (missingIfaceDiagnostics mn "" mn)) Right ty -> return (Right ty) mkBackJob env1 tmod srcText moduleImplHash = BackJob { bjPaths = paths , bjOpts = optsT , bjInput = BackInput { biTypeEnv = Converter.convEnvProtos env1 , biTypedMod = tmod , biSrc = srcText , biImplHash = moduleImplHash } } resolveImportHash m = case M.lookup m providers of Just depKey -> case M.lookup depKey pubMap of Just h -> return (Just h) Nothing -> if M.member depKey taskMap then error ("Internal error: missing pub hash for dep " ++ modNameToString m) else getPubHashCached paths m Nothing -> getPubHashCached paths m resolveNameHashMap' m = case M.lookup m providers of Just depKey -> case M.lookup depKey nameMap of Just hm -> return (Just hm) Nothing -> if M.member depKey taskMap then error ("Internal error: missing name hashes for dep " ++ modNameToString m) else getNameHashMapCached paths m Nothing -> getNameHashMapCached paths m missingNameHashDiagnostics qn = errsToDiagnostics "Compilation error" (modNameToFilename mn) "" [(NoLoc, "Hash info missing for " ++ prstr qn)] missingDepHashDiagnostics label qn users = errsToDiagnostics "Compilation error" (modNameToFilename mn) "" [(NoLoc, label ++ " hash missing for " ++ prstr qn ++ users)] checkMissingImports imps = do userSearchAbs <- mapM normalizePathSafe (C.searchpath optsT) sysTypesAbs <- normalizePathSafe (sysTypes paths) searchAbs <- mapM normalizePathSafe (searchPath paths) let userSearchSet = Data.Set.fromList (map normalise userSearchAbs) managedTypeDirs = [ p | p <- searchAbs , let pNorm = normalise p , pNorm /= normalise sysTypesAbs , Data.Set.notMember pNorm userSearchSet ] isUnder dir path = let dir' = addTrailingPathSeparator (normalise dir) path' = normalise path in Data.List.isPrefixOf dir' path' isManagedTyPath path = any (\dir -> isUnder dir path) managedTypeDirs missing <- foldM (\acc (depMn, _depHash) -> if M.member depMn providers then return acc else do mTy <- getTyFileCached (searchPath paths) depMn case mTy of Nothing -> return (Data.Set.insert depMn acc) Just tyPath -> do tyAbs <- normalizePathSafe tyPath if isManagedTyPath tyAbs then return (Data.Set.insert depMn acc) else return acc ) Data.Set.empty imps if Data.Set.null missing then return (Right ()) else do let missingSorted = Data.List.sortOn modNameToString (Data.Set.toList missing) diags = concatMap (\depMn -> missingIfaceDiagnostics mn "" depMn) missingSorted return (Left diags) collectDiags results = let (errs, vals) = partitionEithers results in if null errs then Right vals else Left (concat errs) traverseDiags f items = collectDiags <$> mapM f items depMap getDeps infos = M.fromListWith (\a _ -> a) (concatMap getDeps infos) depUsers getDeps infos = foldl' add M.empty infos where add acc info = foldl' (\m (qn, _) -> M.insertWith (++) qn [InterfaceFiles.nhName info] m) acc (getDeps info) fmtUsers users qn = case M.lookup qn users of Nothing -> "" Just ns -> let uniq = Data.Set.toList (Data.Set.fromList ns) names = map A.nstr (Data.List.sortOn Hashing.nameKey uniq) in if null names then "" else " (used by " ++ intercalate ", " names ++ ")" nameHashSummary prevMap newInfos = let newMap = nameHashMapFromList newInfos oldKeys = Data.Set.fromList (M.keys prevMap) newKeys = Data.Set.fromList (M.keys newMap) added = Data.Set.toList (Data.Set.difference newKeys oldKeys) removed = Data.Set.toList (Data.Set.difference oldKeys newKeys) shared = Data.Set.toList (Data.Set.intersection oldKeys newKeys) fieldChange label getHash old new | getHash old == getHash new = Nothing | otherwise = Just (label ++ " " ++ short8 (getHash old) ++ " -> " ++ short8 (getHash new)) changesFor n = let oldInfo = prevMap M.! n newInfo = newMap M.! n fields = catMaybes [ fieldChange "src" InterfaceFiles.nhSrcHash oldInfo newInfo , fieldChange "pub" InterfaceFiles.nhPubHash oldInfo newInfo , fieldChange "impl" InterfaceFiles.nhImplHash oldInfo newInfo ] in if null fields then Nothing else Just ("~" ++ A.nstr n ++ "{" ++ intercalate ", " fields ++ "}") addedItems = [ "+" ++ A.nstr n | n <- Data.List.sortOn Hashing.nameKey added ] removedItems = [ "-" ++ A.nstr n | n <- Data.List.sortOn Hashing.nameKey removed ] changedItems = mapMaybe changesFor (Data.List.sortOn Hashing.nameKey shared) items = addedItems ++ removedItems ++ changedItems in if null items then Nothing else Just (intercalate ", " items) resolveNameHashInfo m n = do hm <- resolveNameHashMap' m case hm of Nothing -> return (Left (missingIfaceDiagnostics mn "" m)) Just hmap -> case M.lookup n hmap of Just info -> return (Right info) Nothing -> return (Left (missingNameHashDiagnostics (A.GName m n))) resolveQNameHash label getHash users qn = case qn of A.GName m n -> resolveNameHashInfo m n >>= \res -> return $ case res of Left diags -> Left diags Right info -> let h = getHash info in if B.null h then Left (missingDepHashDiagnostics label (A.GName m n) users) else Right h A.QName m n -> resolveNameHashInfo m n >>= \res -> return $ case res of Left diags -> Left diags Right info -> let h = getHash info in if B.null h then Left (missingDepHashDiagnostics label (A.GName m n) users) else Right h A.NoQ _ -> return (Left (missingNameHashDiagnostics qn)) resolveDepHashes label getHash deps = do resolved <- traverseDiags (\(n, qns) -> do let qnsSorted = Data.List.sortOn Hashing.qnameKey (Data.Set.toList (Data.Set.fromList qns)) users = " (used by " ++ A.nstr n ++ ")" resolvedQns <- traverseDiags (\qn -> do currE <- resolveQNameHash label getHash users qn return (fmap (\curr -> (qn, curr)) currE)) qnsSorted return (fmap (\vals -> (n, vals)) resolvedQns)) (M.toList deps) return (fmap M.fromList resolved) -- For stale checks on cached .ty tasks we treat missing names/hashes -- as "stale cache" signals and force front passes, instead of failing -- early with internal hash diagnostics. resolveQNameHashForStaleCheck getHash qn = case qn of A.GName m n -> resolveNameHashMap' m >>= \hm -> return $ case hm of Nothing -> Right Nothing Just hmap -> case M.lookup n hmap of Nothing -> Right Nothing Just info -> let h = getHash info in if B.null h then Right Nothing else Right (Just h) A.QName m n -> resolveNameHashMap' m >>= \hm -> return $ case hm of Nothing -> Right Nothing Just hmap -> case M.lookup n hmap of Nothing -> Right Nothing Just info -> let h = getHash info in if B.null h then Right Nothing else Right (Just h) A.NoQ _ -> return (Right Nothing) checkDeps _label getHash _users deps = do resolved <- traverseDiags (\(qn, recorded) -> do currE <- resolveQNameHashForStaleCheck getHash qn return (fmap (\curr -> (qn, recorded, curr)) currE)) (M.toList deps) return (fmap (\triples -> let deltas = [ (qn, old, new) | (qn, old, Just new) <- triples, old /= new ] missing = [ qn | (qn, _old, Nothing) <- triples ] in (deltas, missing)) resolved) case taskCurrent of ParseErrorTask{ parseDiagnostics = diags } -> return (key, Left diags) _ | C.only_build optsT -> do ifaceRes <- case taskCurrent of TyTask{ tyPubHash = h } -> readIfaceFromTy paths mn "" (Just h) ParseTask{ src = srcContent } -> readIfaceFromTy paths mn srcContent Nothing ActonTask{ src = srcContent } -> readIfaceFromTy paths mn srcContent Nothing case ifaceRes of Right (imps, ifaceTE, mdoc, ih) -> do let cachedNameHashes = case taskCurrent of TyTask{ tyNameHashes = nhs } -> publicNameHashes nhs _ -> [] fr = mkFrontResult imps ifaceTE mdoc ih cachedNameHashes Nothing cacheFrontResult fr Left _ -> return (key, Right emptyFrontResult) _ -> do -- For cached .ty tasks, compare recorded dep hashes against current deps. -- This is the up-to-date check that decides if we can skip work. If -- any implDeps have changed we need to rerun out back passes and if -- any pubDeps have changed we need to rerun front passes (and back -- passes) needByDepsRes <- case taskCurrent of TyTask{ tyImports = imps, tyNameHashes = nameHashes } -> do missingImportsRes <- checkMissingImports imps case missingImportsRes of Left diags -> return (Left diags) Right () -> do -- Build dep maps and reverse "used by" index for logging. let pubDeps = depMap InterfaceFiles.nhPubDeps nameHashes implDeps = depMap InterfaceFiles.nhImplDeps nameHashes pubUsers = depUsers InterfaceFiles.nhPubDeps nameHashes implUsers = depUsers InterfaceFiles.nhImplDeps nameHashes -- Resolve current hashes for each dep and report any deltas. pubRes <- checkDeps "pub" InterfaceFiles.nhPubHash pubUsers pubDeps implRes <- checkDeps "impl" InterfaceFiles.nhImplHash implUsers implDeps case (pubRes, implRes) of (Left diags, _) -> return (Left diags) (_, Left diags) -> return (Left diags) (Right (pubDeltas, pubMissing), Right (implDeltas, implMissing)) -> return (Right (pubDeltas, implDeltas, pubMissing, implMissing, pubUsers, implUsers)) -- Source tasks always run front passes, so deps are irrelevant. _ -> return (Right ([], [], [], [], M.empty, M.empty)) case needByDepsRes of Left diags -> return (key, Left diags) Right (pubDeltas, implDeltas, pubMissing, implMissing, pubUsers, implUsers) -> do let needBySource = case taskCurrent of { ParseTask{} -> True; ActonTask{} -> True; _ -> False } -- Public deltas require front passes; impl deltas only need back jobs. needByPub = not (null pubDeltas) needByMissing = not (null pubMissing) || not (null implMissing) needByImpl = not (null implDeltas) forceAlt = altOutput optsT && mn == rootAlt forceAlways = C.alwaysbuild optsT -- Front passes run on source or API changes, or when forced. needFront = needBySource || needByPub || needByMissing || forceAlt || forceAlways mModuleImplHash = case taskCurrent of TyTask{ tyImplHash = implHash } -> Just implHash _ -> Nothing let canCheckCodegen = not needFront && not needByImpl && not (altOutput optsT) mCodegenStatus <- case mModuleImplHash of Just implHash | canCheckCodegen -> Just <$> codegenStatus paths mn implHash _ -> return Nothing let needByCodegen = maybe False (not . codegenUpToDate) mCodegenStatus let runFront = do prevNameHashes <- if C.verbose gopts then case taskCurrent of TyTask{ tyNameHashes = nhs } -> return (Just (nameHashMapFromList (publicNameHashes nhs))) _ -> getNameHashMapCached paths mn else return Nothing when (C.verbose gopts) $ do if needBySource then ccOnInfo callbacks (" Stale " ++ modNameToString mn ++ ": source changed") else do when needByPub $ do let fmtDelta (qn, old, new) = prstr qn ++ " " ++ short8 old ++ " → " ++ short8 new ++ fmtUsers pubUsers qn ccOnInfo callbacks (" Stale " ++ modNameToString mn ++ ": pub changes in " ++ Data.List.intercalate ", " (map fmtDelta pubDeltas)) when needByMissing $ do let fmtMissing users qn = prstr qn ++ fmtUsers users qn pubMissingItems = [ "pub " ++ fmtMissing pubUsers qn | qn <- Data.List.sortOn Hashing.qnameKey pubMissing ] implMissingItems = [ "impl " ++ fmtMissing implUsers qn | qn <- Data.List.sortOn Hashing.qnameKey implMissing ] ccOnInfo callbacks (" Stale " ++ modNameToString mn ++ ": missing dep hashes in " ++ Data.List.intercalate ", " (pubMissingItems ++ implMissingItems)) t' <- case taskCurrent of ActonTask{} -> return taskCurrent _ -> materializeTask optsT sp mn actFile Nothing taskCurrent case t' of ParseErrorTask{ parseDiagnostics = diags } -> return (key, Left diags) ActonTask{ src = srcContent, srcBytes = srcBytes, sourceMeta = mSourceMeta, atree = m } -> do res <- runFrontPasses gopts optsT paths envSnap m srcContent srcBytes mSourceMeta resolveImportHash resolveNameHashMap' (\p -> ccOnFrontProgress callbacks t optsT p) case res of Left diags -> return (key, Left diags) Right fr -> do when (C.verbose gopts) $ forM_ prevNameHashes $ \prevMap -> forM_ (nameHashSummary prevMap (frNameHashes fr)) $ \summary -> ccOnInfo callbacks (" Hash deltas " ++ modNameToString mn ++ ": " ++ summary) cacheFrontResult fr ParseTask{} -> error ("Internal error: unmaterialized ParseTask " ++ modNameToString mn) _ -> error ("Internal error: unexpected task " ++ show t') runImplRefresh = do let rerunFront = do when (C.verbose gopts) $ ccOnInfo callbacks (" Stale " ++ modNameToString mn ++ ": impl refresh encountered unresolved dep hashes; rerunning front passes") runFront handleSyncFailure :: SomeException -> IO (TaskKey, Either [Diagnostic String] FrontResult) handleSyncFailure err = if isJust (fromException err :: Maybe SomeAsyncException) then throwIO err else rerunFront handleImplRefreshException :: SomeException -> IO (TaskKey, Either [Diagnostic String] FrontResult) handleImplRefreshException = handleSyncFailure (do when (C.verbose gopts) $ do let fmtDelta (qn, old, new) = prstr qn ++ " " ++ short8 old ++ " → " ++ short8 new ++ fmtUsers implUsers qn ccOnInfo callbacks (" Stale " ++ modNameToString mn ++ ": impl changes in " ++ Data.List.intercalate ", " (map fmtDelta implDeltas)) tyRes <- readTyFile case tyRes of Left diags -> return (key, Left diags) Right (_ms, nmod, tmod, sourceMeta, moduleSrcBytesHash, modulePubHash, _moduleImplHash, imps, nameHashes, roots, tests, mdoc) -> do parsedRes <- parseActFile optsT sp mn actFile Nothing case parsedRes of Left diags -> return (key, Left diags) Right (snap, parsedMod) -> do let nameSrcHashes = M.fromList [ (InterfaceFiles.nhName nh, InterfaceFiles.nhSrcHash nh) | nh <- nameHashes ] nameKeys = M.keysSet nameSrcHashes nameImplHashes0 = Hashing.nameHashesFromItems (Hashing.topLevelItems tmod) nameImplHashes = M.filterWithKey (\k _ -> Data.Set.member k nameKeys) nameImplHashes0 localNames = nameKeys implDepsRaw0 = Hashing.implDepsFromItems (Hashing.topLevelItems tmod) implDepsRaw = M.fromList [ (n, M.findWithDefault [] n implDepsRaw0) | n <- M.keys nameSrcHashes ] envRes <- (try :: IO Acton.Env.Env0 -> IO (Either SomeException Acton.Env.Env0)) $ Acton.Env.mkEnv (searchPath paths) envSnap parsedMod case envRes of Left err -> handleSyncFailure err Right env1 -> do depRes <- (try :: IO a -> IO (Either SomeException a)) $ do let hashEnv = setMod mn env1 (implLocalDeps, implExtDeps) = Hashing.splitDeps mn hashEnv localNames implDepsRaw depCount = sum (map length (M.elems implLocalDeps)) + sum (map length (M.elems implExtDeps)) -- Force dep maps now so stale aliases/missing names -- are handled via the front-pass fallback path. _ <- evaluate depCount implExtRes <- resolveDepHashes "impl" InterfaceFiles.nhImplHash implExtDeps return (implLocalDeps, implExtRes) case depRes of Left err -> handleSyncFailure err Right (_, Left _) -> rerunFront Right (implLocalDeps, Right implExtHashes) -> do let updatedNameHashes = Hashing.refreshImplHashes nameHashes nameImplHashes implLocalDeps implExtHashes moduleImplHash = Hashing.moduleImplHashFromNameHashes updatedNameHashes InterfaceFiles.writeFile tyFile moduleSrcBytesHash modulePubHash moduleImplHash sourceMeta imps updatedNameHashes roots tests mdoc nmod tmod let I.NModule imps ifaceFull _mdoc = nmod ifaceTE = publicIfaceTE ifaceFull backJob = Just (mkBackJob env1 tmod (Source.ssText snap) moduleImplHash) fr = mkFrontResult imps ifaceTE mdoc modulePubHash (publicNameHashes updatedNameHashes) backJob cacheFrontResult fr ) `catch` handleImplRefreshException runCodegenRefresh = do when (C.verbose gopts) $ do let suffix = maybe "" formatCodegenDelta mCodegenStatus ccOnInfo callbacks (" Stale " ++ modNameToString mn ++ ": generated code out of date" ++ suffix) tyRes <- readTyFile case tyRes of Left diags -> return (key, Left diags) Right (_ms, nmod, tmod, _sourceMeta, _moduleSrcBytesHash, modulePubHash, moduleImplHashStored, _imps, nameHashes, _roots, _tests, mdoc) -> do snap <- Source.readSource sp actFile env1 <- Acton.Env.mkEnv (searchPath paths) envSnap tmod let I.NModule imps ifaceFull _mdoc = nmod ifaceTE = publicIfaceTE ifaceFull backJob = Just (mkBackJob env1 tmod (Source.ssText snap) moduleImplHashStored) fr = mkFrontResult imps ifaceTE mdoc modulePubHash (publicNameHashes nameHashes) backJob cacheFrontResult fr runReuse = do when (C.verbose gopts) $ ccOnInfo callbacks (" Fresh " ++ modNameToString mn ++ ": using cached .ty") ifaceRes <- case taskCurrent of TyTask{ tyPubHash = h } -> readIfaceFromTy paths mn "" (Just h) _ -> readIfaceFromTy paths mn "" Nothing case ifaceRes of Left diags -> return (key, Left diags) Right (imps, ifaceTE, mdoc, ih) -> do let cachedNameHashes = case taskCurrent of TyTask{ tyNameHashes = nhs } -> publicNameHashes nhs _ -> [] fr = mkFrontResult imps ifaceTE mdoc ih cachedNameHashes Nothing cacheFrontResult fr case () of _ | needFront -> runFront _ | needByImpl -> runImplRefresh _ | needByCodegen -> runCodegenRefresh _ -> runReuse stageTaskKey :: StageKey -> TaskKey stageTaskKey sk = case sk of ParseStage k -> k FrontStage k -> k stagePriority :: M.Map TaskKey Integer -> StageKey -> (Int, Integer) stagePriority cw sk = let phase = case sk of FrontStage _ -> 1 ParseStage _ -> 0 in (phase, M.findWithDefault 0 (stageTaskKey sk) cw) runParseStage :: TaskKey -> IO (StageKey, Either [Diagnostic String] StageSuccess) runParseStage key = do t <- case M.lookup key taskMap of Just x -> return x Nothing -> error ("Internal error: missing task for key " ++ show key) let optsT = optsFor key mn = name (gtTask t) actFile = srcFile (gtPaths t) mn onProgress p = ccOnParseProgress callbacks t optsT p timeStart <- getTime Monotonic parsed <- if C.only_build optsT then return (gtTask t) else case gtTask t of ParseTask{} -> materializeTask optsT sp mn actFile (Just onProgress) (gtTask t) _ -> return (gtTask t) case parsed of ParseTask{} -> return (ParseStage key, Right (StageParsed parsed Nothing)) ActonTask{ atree = m } -> do _ <- evaluate (rnf m) timeEnd <- getTime Monotonic let parseTime = if not (quiet gopts optsT) then Just (timeEnd - timeStart) else Nothing return (ParseStage key, Right (StageParsed parsed parseTime)) ParseErrorTask{} -> return (ParseStage key, Right (StageParsed parsed Nothing)) _ -> error ("Internal error: parse stage did not materialize " ++ modNameToString mn) runFrontStage :: Acton.Env.Env0 -> M.Map TaskKey B.ByteString -> M.Map TaskKey (M.Map A.Name InterfaceFiles.NameHashInfo) -> M.Map TaskKey CompileTask -> TaskKey -> IO (StageKey, Either [Diagnostic String] StageSuccess) runFrontStage envSnap res nameRes parsedTasks key = do (doneKey, outcome) <- doOne envSnap res nameRes parsedTasks key return (FrontStage doneKey, fmap StageFronted outcome) scheduleMore :: Int -> [StageKey] -> [(Async (StageKey, Either [Diagnostic String] StageSuccess), StageKey)] -> M.Map TaskKey B.ByteString -> M.Map TaskKey (M.Map A.Name InterfaceFiles.NameHashInfo) -> M.Map TaskKey CompileTask -> Acton.Env.Env0 -> M.Map TaskKey Integer -> IO ([StageKey] , [(Async (StageKey, Either [Diagnostic String] StageSuccess), StageKey)]) scheduleMore k rdy running res nameRes parsedTasks envSnap cw = do let rdySorted = Data.List.sortOn (Down . stagePriority cw) rdy (toStart, rdy') = splitAt k rdySorted new <- forM toStart $ \sk -> do case sk of FrontStage key -> case M.lookup key taskMap of Just t -> ccOnFrontStart callbacks t (optsFor key) Nothing -> return () ParseStage key -> case M.lookup key taskMap of Just t -> ccOnParseStart callbacks t (optsFor key) Nothing -> return () a <- async $ case sk of ParseStage key -> runParseStage key FrontStage key -> runFrontStage envSnap res nameRes parsedTasks key return (a, sk) return (rdy', new ++ running) loop :: IORef [Async (StageKey, Either [Diagnostic String] StageSuccess)] -> [StageKey] -> [(Async (StageKey, Either [Diagnostic String] StageSuccess), StageKey)] -> M.Map TaskKey B.ByteString -> M.Map TaskKey (M.Map A.Name InterfaceFiles.NameHashInfo) -> M.Map TaskKey CompileTask -> M.Map StageKey Int -> Data.Set.Set StageKey -> Acton.Env.Env0 -> Bool -> Int -> M.Map TaskKey Integer -> IO (Acton.Env.Env0, Bool) loop runningRef rdy running res nameRes parsedTasks ind pend envAcc hadErrors maxPar cw = do (rdy1, running1) <- mask_ $ do res@(rdy1', running1') <- scheduleMore (maxPar - length running) rdy running res nameRes parsedTasks envAcc cw writeIORef runningRef (map fst running1') return res if null running1 && null rdy1 then if Data.Set.null pend then do writeIORef runningRef [] return (envAcc, hadErrors) else return (envAcc, True) else do (doneA, (stageDone, outcome)) <- waitAny $ map fst running1 let running2 = filter ((/= doneA) . fst) running1 writeIORef runningRef (map fst running2) let keyDone = stageTaskKey stageDone tDone = taskMap M.! keyDone optsDone = optsFor keyDone case outcome of Left diags -> do case stageDone of FrontStage _ -> ccOnFrontDone callbacks tDone optsDone ParseStage _ -> ccOnParseDone callbacks tDone optsDone Nothing ccOnDiagnostics callbacks tDone optsDone diags let blockedMods = dependentClosure keyDone blockedStages = Data.Set.fromList $ concatMap (\m -> [ParseStage m, FrontStage m]) (Data.Set.toList blockedMods) (blockedRunning, running3) = partition (\(_, sk) -> Data.Set.member sk blockedStages) running2 mapM_ (cancel . fst) blockedRunning writeIORef runningRef (map fst running3) let pend2 = Data.Set.delete stageDone (pend `Data.Set.difference` blockedStages) rdy2 = filter (`Data.Set.notMember` blockedStages) rdy1 dropKeys = keyDone : Data.Set.toList blockedMods parsedTasks2 = foldl' (flip M.delete) parsedTasks dropKeys loop runningRef rdy2 running3 res nameRes parsedTasks2 ind pend2 envAcc True maxPar cw Right success -> do let pend2 = Data.Set.delete stageDone pend ind2 = case M.lookup stageDone stageRevMap of Nothing -> ind Just ds -> foldl' (\m d -> M.adjust (\x -> x-1) d m) ind ds runningKeys = map snd running2 newlyReady = [ sk | sk <- Data.Set.toList pend2 , M.findWithDefault 0 sk ind2 == 0 , not (sk `elem` rdy1) , not (sk `elem` runningKeys) ] rdy2 = rdy1 ++ newlyReady case success of StageParsed parsed mParseTime -> do ccOnParseDone callbacks tDone optsDone mParseTime let parsedTasks2 = M.insert keyDone parsed parsedTasks loop runningRef rdy2 running2 res nameRes parsedTasks2 ind2 pend2 envAcc hadErrors maxPar cw StageFronted fr -> do ccOnFrontDone callbacks tDone optsDone ccOnFrontResult callbacks tDone optsDone fr forM_ (frBackJob fr) $ ccOnBackJob callbacks let res2 = M.insert keyDone (frPubHash fr) res nameRes2 = M.insert keyDone (nameHashMapFromList (frNameHashes fr)) nameRes parsedTasks2 = M.delete keyDone parsedTasks envAcc' = Acton.Env.addMod (tkMod keyDone) (frImps fr) (frIfaceTE fr) (frDoc fr) envAcc loop runningRef rdy2 running2 res2 nameRes2 parsedTasks2 ind2 pend2 envAcc' hadErrors maxPar cw -- | Execute back-pass jobs in parallel while keeping output order stable. -- Jobs are started up to the concurrency limit, then completions are buffered -- and flushed in job order so logs are deterministic. runBackJobs :: C.GlobalOptions -> Int -> (BackJob -> IO ()) -> (BackJob -> Maybe TimeSpec -> IO ()) -> [BackJob] -> IO () runBackJobs _ _ _ _ [] = return () runBackJobs gopts maxPar onStart onDone jobs = do runningRef <- newIORef [] let cancelRunning = readIORef runningRef >>= mapM_ cancel let runMain = loopBack runningRef indexed [] M.empty 0 runMain `finally` cancelRunning where indexed = zip [0..] (orderBackJobs jobs) backJobKey :: BackJob -> TaskKey backJobKey job = TaskKey (projPath (bjPaths job)) (A.modname (biTypedMod (bjInput job))) orderBackJobs :: [BackJob] -> [BackJob] orderBackJobs js = Data.List.sortOn backJobKey js loopBack runningRef pending running results nextIx = do let capacity = maxPar - length running (toStart, pending') = splitAt capacity pending running' <- mask_ $ do new <- forM toStart $ \(ix, job) -> async $ do onStart job (res, _timing) <- runBackPasses gopts (bjOpts job) (bjPaths job) (bjInput job) (return True) return (ix, job, res) let running' = running ++ new writeIORef runningRef running' return running' if null running' && null pending' then do (_, _) <- flushReady results nextIx return () else do (doneA, (ix, job, res)) <- waitAny running' let running'' = filter (/= doneA) running' results' = M.insert ix (job, res) results writeIORef runningRef running'' (results'', nextIx') <- flushReady results' nextIx loopBack runningRef pending' running'' results'' nextIx' flushReady :: M.Map Int (BackJob, Maybe TimeSpec) -> Int -> IO (M.Map Int (BackJob, Maybe TimeSpec), Int) flushReady res ix = case M.lookup ix res of Nothing -> return (res, ix) Just (job, mline) -> do onDone job mline flushReady (M.delete ix res) (ix + 1) -- Paths handling ------------------------------------------------------------------------------------- data Paths = Paths { searchPath :: [FilePath], sysPath :: FilePath, sysTypes :: FilePath, projPath :: FilePath, projOut :: FilePath, projTypes :: FilePath, binDir :: FilePath, srcDir :: FilePath, isTmp :: Bool, fileExt :: String, modName :: A.ModName } -- Per-project context used for multi-project orchestration. -- Identified by projRoot (absolute path). Keeps directories and BuildSpec if present. data ProjCtx = ProjCtx { projRoot :: FilePath, projOutDir :: FilePath, projTypesDir:: FilePath, projSrcDir :: FilePath, projSysPath :: FilePath, projSysTypes:: FilePath, projBuildSpec :: BuildSpec.BuildSpec, projDeps :: [(String, FilePath)] -- resolved dependency roots (abs paths) } deriving (Show) type FingerprintMap = M.Map String FilePath scratchBuildSpec :: FilePath -> BuildSpec.BuildSpec scratchBuildSpec projRoot = let name = "acton_scratch" prefix = Fingerprint.fingerprintPrefixForName name suffix = Fingerprint.fingerprintPrefixForName projRoot fp = Fingerprint.formatFingerprint (Fingerprint.updateFingerprintPrefix prefix (fromIntegral suffix)) in BuildSpec.BuildSpec { BuildSpec.specName = name , BuildSpec.specDescription = Nothing , BuildSpec.fingerprint = fp , BuildSpec.dependencies = M.empty , BuildSpec.zig_dependencies = M.empty } normalizeFingerprintKey :: String -> Maybe String normalizeFingerprintKey raw = Fingerprint.formatFingerprint <$> Fingerprint.parseFingerprint raw fingerprintKeyFromSpec :: BuildSpec.BuildSpec -> String fingerprintKeyFromSpec spec = case normalizeFingerprintKey (BuildSpec.fingerprint spec) of Just fp -> fp Nothing -> BuildSpec.fingerprint spec applyFingerprint :: FilePath -> BuildSpec.BuildSpec -> FingerprintMap -> (FilePath, FingerprintMap, String) applyFingerprint path spec fpMap = let fp = fingerprintKeyFromSpec spec in case M.lookup fp fpMap of Just canonical -> (canonical, fpMap, fp) Nothing -> (path, M.insert fp path fpMap, fp) -- | Discover all projects reachable from a root project. -- Follows Build.act dependencies, applies overrides/pins, and -- returns a map from project root to ProjCtx while skipping duplicates. discoverProjects :: C.GlobalOptions -> FilePath -> FilePath -> [(String, FilePath)] -> IO (M.Map FilePath ProjCtx) discoverProjects gopts sysAbs rootProj depOverrides = do rootAbs <- normalizePathSafe rootProj rootSpec0 <- loadBuildSpec rootAbs rootSpec <- applyDepOverrides rootAbs depOverrides rootSpec0 let rootPins = BuildSpec.dependencies rootSpec (_, fpMap0, _) = applyFingerprint rootAbs rootSpec M.empty fst <$> go rootAbs Data.Set.empty M.empty fpMap0 rootPins rootAbs (Just rootSpec) where go root seen acc fpMap pins dir mSpec = do dirAbs <- normalizePathSafe dir if Data.Set.member dirAbs seen then return (acc, fpMap) else do spec0 <- case mSpec of Just s -> return s Nothing -> loadBuildSpec dirAbs spec <- applyDepOverrides dirAbs depOverrides spec0 let (_, fpMap1, _) = applyFingerprint dirAbs spec fpMap (deps, fpMap2) <- do let depsList = M.toList (BuildSpec.dependencies spec) foldM (collectDep pins dirAbs) ([], fpMap1) depsList let outDir = joinPath [dirAbs, "out"] typesDir = joinPath [outDir, "types"] srcDir' = joinPath [dirAbs, "src"] ctx = ProjCtx { projRoot = dirAbs , projOutDir = outDir , projTypesDir = typesDir , projSrcDir = srcDir' , projSysPath = sysAbs , projSysTypes = joinPath [sysAbs, "base", "out", "types"] , projBuildSpec = spec , projDeps = [ (n, p) | (n, p, _) <- reverse deps ] } acc' = M.insert dirAbs ctx acc seen' = Data.Set.insert dirAbs seen foldM (step root seen' pins) (acc', fpMap2) (reverse deps) collectDep pins base (accDeps, fpMap) (depName, dep) = do let (chosenDep, conflict) = case M.lookup depName pins of Nothing -> (dep, Nothing) Just pinDep -> if pinDep == dep then (dep, Nothing) else (pinDep, Just dep) when (isJust conflict) $ unless (C.quiet gopts) $ putStrLn ("Warning: dependency '" ++ depName ++ "' in " ++ base ++ " overridden by root pin") depBase <- resolveDepBase base depName chosenDep depAbs <- normalizePathSafe depBase (depPath, fpMap', depSpec) <- canonicalizeDep depAbs fpMap return ((depName, depPath, depSpec) : accDeps, fpMap') canonicalizeDep depAbs fpMap = do spec0 <- loadBuildSpec depAbs spec <- applyDepOverrides depAbs depOverrides spec0 let (canonPath, fpMap', fp) = applyFingerprint depAbs spec fpMap when (canonPath /= depAbs) $ unless (C.quiet gopts) $ putStrLn ("Warning: dependency fingerprint " ++ fp ++ " at " ++ depAbs ++ " deduplicated to " ++ canonPath) let depSpec = if canonPath == depAbs then Just spec else Nothing return (canonPath, fpMap', depSpec) step root seen pins (acc, fpMap) (_, depBase, mSpec) = go root seen acc fpMap pins depBase mSpec -- Given a FILE and optionally --syspath PATH: -- 'sysPath' is the path to the system directory as given by PATH, defaulting to the acton executable directory. -- 'sysTypes' is directory "types" under 'sysPath'. -- 'projPath' is the closest parent directory of FILE that contains a Build.act -- file, or a temporary directory in "/tmp" if no such parent exists. -- 'projOut' is directory "out" under 'projPath'. -- 'projTypes' is directory "types" under 'projOut'. -- 'binDir' is the directory prefix of FILE if 'projPath' is temporary, otherwise it is directory "bin" under 'projOut' -- 'srcDir' is the directory prefix of FILE if 'projPath' is temporary, otherwise it is directory "src" under 'projPath' -- 'fileExt' is file suffix of FILE. -- 'modName' is the module name of FILE (its path after 'src' except 'fileExt', split at every '/') -- | Compute the source file path for a module under its project src dir. srcFile :: Paths -> A.ModName -> FilePath srcFile paths mn = joinPath (srcDir paths : A.modPath mn) ++ ".act" -- | Compute the output base path (without extension) for a module. -- Used to locate .ty/.c/.h output under the project's types directory. outBase :: Paths -> A.ModName -> FilePath outBase paths mn = joinPath (projTypes paths : A.modPath mn) -- | Compute the module path without extension under the project's src dir. -- Used to derive the .act path or related per-module files. srcBase :: Paths -> A.ModName -> FilePath srcBase paths mn = joinPath (srcDir paths : A.modPath mn) -- | Walk upward from a path to find a project root. -- A project root is identified by Build.act plus a -- src/ directory; returns Nothing if we reach filesystem root. -- | Check whether a directory is an Acton project root. -- Requires Build.act and a src/ directory. isActonProjectRoot :: FilePath -> IO Bool isActonProjectRoot path = do runacton <- lookupEnv "ACTON_RUNACTON" if isJust runacton then return False else do hasBuildAct <- doesFileExist (path "Build.act") hasSrcDir <- doesDirectoryExist (path "src") return (hasBuildAct && hasSrcDir) findProjectDir :: FilePath -> IO (Maybe FilePath) findProjectDir path = do isProjectRoot <- isActonProjectRoot path if isProjectRoot then return (Just path) else if path == takeDirectory path -- Check if we're at root then return Nothing else findProjectDir (takeDirectory path) -- | Opaque handle for the lifetime lock of a long-running project compiler. data BackgroundCompilerLock = BackgroundCompilerLock FileLock FilePath -- | Path to the lock held for the lifetime of a long-running project compiler. -- -- This lock only establishes unique ownership of a background compiler -- process such as LSP or watch mode. It does not imply that project state -- is current, so all compile/build work must still take 'withProjectLock'. backgroundCompilerLockPath :: FilePath -> FilePath backgroundCompilerLockPath projDir = joinPath [projDir, ".acton.compile.lock"] -- | Acquire the long-running compiler lock for a project root, if available. tryBackgroundCompilerLock :: FilePath -> IO (Maybe BackgroundCompilerLock) tryBackgroundCompilerLock projDir = do let lockPath = backgroundCompilerLockPath projDir mlock <- tryLockFile lockPath Exclusive return ((\lock -> BackgroundCompilerLock lock lockPath) <$> mlock) -- | Release the long-running compiler lock and remove its lock file if possible. releaseBackgroundCompilerLock :: BackgroundCompilerLock -> IO () releaseBackgroundCompilerLock (BackgroundCompilerLock lock lockPath) = do unlockFile lock mlock <- tryLockFile lockPath Exclusive case mlock of Nothing -> return () Just lock2 -> do removeFile lockPath `catch` handleNotExists unlockFile lock2 where handleNotExists :: IOException -> IO () handleNotExists _ = return () -- | Path to the single per-project compiler work lock. projectLockPath :: FilePath -> FilePath projectLockPath projDir = joinPath [projDir, ".acton.lock"] -- | Run an action while holding the single per-project compiler work lock. -- -- If the lock is not immediately available, run the callback once before -- blocking until the lock can be acquired. withProjectLockOnWait :: FilePath -> IO () -> IO a -> IO a withProjectLockOnWait projDir onWait action = do let lockPath = projectLockPath projDir mlock <- tryLockFile lockPath Exclusive case mlock of Just lock -> action `finally` unlockFile lock Nothing -> do onWait withFileLock lockPath Exclusive (\_ -> action) -- | Run an action while holding the single per-project compiler work lock. withProjectLock :: FilePath -> IO a -> IO a withProjectLock projDir action = withProjectLockOnWait projDir (return ()) action -- | Compute Paths for a given source file and compile options. -- Resolves the project root (or temp root), output dirs, and search path, -- creating required directories along the way. findPaths :: FilePath -> C.CompileOptions -> IO Paths findPaths actFile opts = do execDir <- takeDirectory <$> getExecutablePath sysPath <- canonicalizePath (if null $ C.syspath opts then execDir ++ "/.." else C.syspath opts) absSrcFile <- canonicalizePath actFile (isTmp, projPath, dirInSrc) <- analyze (takeDirectory absSrcFile) [] let sysTypes = joinPath [sysPath, "base", "out", "types"] srcDir = if isTmp then takeDirectory absSrcFile else joinPath [projPath, "src"] projOut = joinPath [projPath, "out"] projTypes = joinPath [projOut, "types"] binDir = if isTmp then srcDir else joinPath [projOut, "bin"] modName = A.modName $ dirInSrc ++ [fileBody] -- join the search paths from command line options with the ones found in the deps directory depOverrides <- normalizeDepOverrides projPath (C.dep_overrides opts) depTypePaths <- if isTmp then return [] else collectDepTypePaths projPath depOverrides let sPaths = [projTypes] ++ depTypePaths ++ (C.searchpath opts) ++ [sysTypes] createDirectoryIfMissing True binDir createDirectoryIfMissing True projOut createDirectoryIfMissing True projTypes createDirectoryIfMissing True (getModPath projTypes modName) return $ Paths sPaths sysPath sysTypes projPath projOut projTypes binDir srcDir isTmp fileExt modName where (fileBody,fileExt) = splitExtension $ takeFileName actFile analyze "/" ds = do tmp <- canonicalizePath (C.tempdir opts) return (True, tmp, []) analyze pre ds = do isProjectRoot <- isActonProjectRoot pre if isProjectRoot then case ds of [] -> return $ (False, pre, []) "src":dirs -> return $ (False, pre, dirs) "out":"types":dirs -> return $ (False, pre, dirs) _ -> throwProjectError ("Source file is not in a valid project directory: " ++ joinPath ds) else analyze (takeDirectory pre) (takeFileName pre : ds) -- Module helpers for multi-project builds --------------------------------------------------------- -- | Derive a module name from a file path under a project's src root. -- The result uses path segments and strips the .act extension. moduleNameFromFile :: FilePath -> FilePath -> IO A.ModName moduleNameFromFile srcBase actFile = do base <- normalizePathSafe srcBase file <- normalizePathSafe actFile let rel = dropExtension (makeRelative base file) return $ A.modName (splitDirectories rel) -- | Enumerate all .act files in a project and pair them with module names. -- Used to seed the project module index for graph construction. enumerateProjectModules :: ProjCtx -> IO [(FilePath, A.ModName)] enumerateProjectModules ctx = do exists <- doesDirectoryExist (projSrcDir ctx) if not exists then return [] else do files <- getFilesRecursive (projSrcDir ctx) let actFiles = filter (\f -> takeExtension f == ".act") files forM actFiles $ \f -> do mn <- moduleNameFromFile (projSrcDir ctx) f return (f, mn) -- | Remove stale generated module artifacts when source modules disappear. -- Prunes orphan .ty/.c/.h outputs under out/types before task planning so -- cached headers cannot mask deleted .act modules. pruneMissingModuleOutputs :: ProjCtx -> IO () pruneMissingModuleOutputs ctx = do let srcRoot = projSrcDir ctx typesRoot = projTypesDir ctx typesExists <- doesDirectoryExist typesRoot when typesExists $ do srcExists <- doesDirectoryExist srcRoot srcMods <- if srcExists then do srcFiles <- getFilesRecursive srcRoot let actFiles = filter (\f -> takeExtension f == ".act") srcFiles modBases = map (normalise . dropExtension . makeRelative srcRoot) actFiles return (Data.Set.fromList modBases) else return Data.Set.empty outFiles <- getFilesRecursive typesRoot mapM_ (pruneFile srcMods typesRoot) outFiles where isRootStub rel ext = ext == ".c" && (".root" `Data.List.isSuffixOf` dropExtension rel || ".test_root" `Data.List.isSuffixOf` dropExtension rel) moduleBase rel ext | isRootStub rel ext = dropExtension (dropExtension rel) | otherwise = dropExtension rel pruneFile srcMods typesRoot absFile = do let ext = takeExtension absFile when (ext == ".ty" || ext == ".c" || ext == ".h") $ do let rel = normalise (makeRelative typesRoot absFile) base = normalise (moduleBase rel ext) unless (Data.Set.member base srcMods) $ removeFile absFile `catch` ignoreNotExists ignoreNotExists :: IOException -> IO () ignoreNotExists _ = return () -- | Incremental variant: prune only modules whose changed .act file no longer exists. pruneMissingChangedModuleOutputs :: [ProjCtx] -> [FilePath] -> IO () pruneMissingChangedModuleOutputs ctxs changedPaths = do absChanged <- mapM normalizePathSafe changedPaths let actPaths = filter (\p -> takeExtension p == ".act") absChanged forM_ actPaths $ \actPath -> do exists <- doesFileExist actPath unless exists $ mapM_ (pruneForCtx actPath) ctxs where pruneForCtx actPath ctx = do srcRoot <- normalizePathSafe (projSrcDir ctx) let srcRoot' = addTrailingPathSeparator (normalise srcRoot) actPath' = normalise actPath when (Data.List.isPrefixOf srcRoot' actPath') $ do let modBase = normalise (dropExtension (makeRelative srcRoot actPath')) outBase = projTypesDir ctx modBase mapM_ (\ext -> removeFile (outBase ++ ext) `catch` ignoreNotExists) [".ty", ".c", ".h"] ignoreNotExists :: IOException -> IO () ignoreNotExists _ = return () -- | Build a search path for module interfaces for a project. -- Includes the project's types dir, dependency types, user searchpath, and -- the system types directory. searchPathForProject :: C.CompileOptions -> M.Map FilePath ProjCtx -> ProjCtx -> [FilePath] searchPathForProject opts projMap ctx = let deps = depTypePathsFromMap projMap (projRoot ctx) in [projTypesDir ctx] ++ deps ++ (C.searchpath opts) ++ [projSysTypes ctx] -- | Construct a Paths record for a module within a project context. -- Creates output directories and ensures the types directory exists. pathsForModule :: C.CompileOptions -> M.Map FilePath ProjCtx -> ProjCtx -> A.ModName -> IO Paths pathsForModule opts projMap ctx mn = do let sPaths = searchPathForProject opts projMap ctx bin = joinPath [projOutDir ctx, "bin"] src = projSrcDir ctx p = Paths sPaths (projSysPath ctx) (projSysTypes ctx) (projRoot ctx) (projOutDir ctx) (projTypesDir ctx) bin src False ".act" mn createDirectoryIfMissing True bin createDirectoryIfMissing True (projOutDir ctx) createDirectoryIfMissing True (projTypesDir ctx) createDirectoryIfMissing True (getModPath (projTypesDir ctx) mn) return p -- | Load a BuildSpec from Build.act. -- Throws ProjectError on parse or validation failure. loadBuildSpec :: FilePath -> IO BuildSpec.BuildSpec loadBuildSpec dir = do let actPath = joinPath [dir, "Build.act"] actExists <- doesFileExist actPath if actExists then do content <- readFile actPath case BuildSpec.parseBuildActDetailed content of Left err -> case err of BuildSpec.MissingFingerprint name -> do suggestion <- suggestFingerprint name throwProjectError ("Missing fingerprint in " ++ actPath ++ ".\n" ++ "ERROR: Build.act requires `fingerprint`. For example: fingerprint = " ++ suggestion ++ "\n" ++ "HINT: Fingerprint = CRC32(name) in the high 32 bits + random low 32 bits. You may choose a different value.") BuildSpec.InvalidFingerprint name raw -> do suggestion <- suggestFingerprint name throwProjectError ("Invalid fingerprint " ++ raw ++ " in " ++ actPath ++ " (project name: " ++ show name ++ ").\n" ++ "Expected an unquoted 64-bit hex fingerprint like 0x1234abcd5678ef00.\n" ++ "Suggested fingerprint: " ++ suggestion) BuildSpec.MissingProjectName -> do suggestion <- suggestProjectName dir throwProjectError ("Missing project name in " ++ actPath ++ ".\n" ++ "Add: name = " ++ show suggestion) BuildSpec.ParseError msg -> throwProjectError ("Failed to parse Build.act in " ++ dir ++ ":\n" ++ msg) Right (spec, _, _) -> validateBuildSpec actPath spec else throwProjectError ("Missing Build.act in " ++ dir ++ ".\n" ++ "Create Build.act with required name and fingerprint fields.") validateBuildSpec :: FilePath -> BuildSpec.BuildSpec -> IO BuildSpec.BuildSpec validateBuildSpec sourcePath spec = do validateProjectName sourcePath (BuildSpec.specName spec) validateFingerprint sourcePath (BuildSpec.specName spec) (BuildSpec.fingerprint spec) return spec validateProjectName :: FilePath -> String -> IO () validateProjectName sourcePath name = if not (isProjectIdent name) then throwProjectError ("Invalid project name '" ++ name ++ "' in " ++ sourcePath ++ ".\n" ++ "The name must be a valid Acton project name (letters, digits, underscore; cannot start with a digit).") else if length name > projectNameMax then throwProjectError ("Invalid project name '" ++ name ++ "' in " ++ sourcePath ++ ".\n" ++ "The name must be at most " ++ show projectNameMax ++ " characters.") else return () where isProjectIdent [] = False isProjectIdent (c:cs) = (isAlpha c || c == '_') && all isIdentChar cs where isIdentChar x = isAlpha x || isDigit x || x == '_' suggestProjectName :: FilePath -> IO String suggestProjectName dir = do resolved <- normalizePathSafe dir let base = takeBaseName resolved if null base || base == "." then return "my_project" else return base suggestFingerprint :: String -> IO String suggestFingerprint name = do let prefix = Fingerprint.fingerprintPrefixForName name low <- randomRIO (1, maxBound :: Word32) let fp = (fromIntegral prefix `shiftL` 32) .|. (fromIntegral low :: Word64) return (Fingerprint.formatFingerprint fp) validateFingerprint :: FilePath -> String -> String -> IO () validateFingerprint sourcePath name fpRaw = case Fingerprint.parseFingerprint fpRaw of Nothing -> do suggestion <- suggestFingerprint name throwProjectError ("Invalid fingerprint '" ++ fpRaw ++ "' in " ++ sourcePath ++ " (project name: " ++ show name ++ ").\n" ++ "Expected an unquoted 64-bit hex fingerprint like 0x1234abcd5678ef00.\n" ++ "Suggested fingerprint: " ++ suggestion) Just fp -> do let formatted = Fingerprint.formatFingerprint fp expectedPrefix = Fingerprint.fingerprintPrefixForName name expectedPrefixHex = Fingerprint.formatFingerprintPrefix expectedPrefix actualPrefix = fromIntegral (fp `shiftR` 32) if formatted == Fingerprint.fingerprintPlaceholder then do suggestion <- suggestFingerprint name throwProjectError ("Fingerprint placeholder " ++ formatted ++ " in " ++ sourcePath ++ " is not valid.\n" ++ "Suggested fingerprint: " ++ suggestion) else if expectedPrefix == actualPrefix then return () else do suggestion <- suggestFingerprint name throwProjectError ("Fingerprint mismatch in " ++ sourcePath ++ " for project name " ++ show name ++ ".\n" ++ "Expected prefix: " ++ expectedPrefixHex ++ " (CRC32 of name).\n" ++ "Current fingerprint: " ++ formatted ++ "\n" ++ "Renames and forks require a new fingerprint for this name.\n" ++ "Suggested fingerprint: " ++ suggestion) projectNameMax :: Int projectNameMax = 32 -- | Treat drive-letter paths as absolute in addition to POSIX roots. -- This keeps path normalization consistent on Windows hosts. isAbsolutePath :: FilePath -> Bool isAbsolutePath p = isAbsolute p || case p of (c:':':_) -> isAlpha c _ -> False -- | Normalize a path without failing if it does not exist. -- Falls back to normalise for non-existent paths (useful for temporary builds). normalizePathSafe :: FilePath -> IO FilePath normalizePathSafe p = do res <- try (canonicalizePath p) :: IO (Either IOException FilePath) return $ either (const (normalise p)) id res -- | Trim leading and trailing whitespace from a string. -- Used when parsing or normalizing BuildSpec inputs. trim :: String -> String trim = f . f where f = reverse . dropWhile isSpace -- | Collapse "." and ".." segments without dropping leading ".." on relative paths. -- Example: "a/b/../c/./d" becomes "a/c/d". collapseDots :: FilePath -> FilePath collapseDots p = let parts = splitDirectories p (root, rest) = case parts of (r:xs) | isRoot r -> (Just r, xs) xs -> (Nothing, xs) (revAcc, ups) = foldl step ([], 0) rest cleaned = replicate ups ".." ++ reverse revAcc prefix = maybe [] (\r -> [r]) root in joinPath (prefix ++ cleaned) where isRoot r = r == "/" || (length r >= 2 && r !! 1 == ':') step (acc, ups) comp = case comp of "." -> (acc, ups) "" -> (acc, ups) ".." -> case acc of (_:as) -> (as, ups) [] -> (acc, ups + 1) _ -> (comp:acc, ups) -- | Rebase a path against a base directory and normalize it. -- Absolute paths are left as-is; relative paths are joined to the base. rebasePath :: FilePath -> FilePath -> FilePath rebasePath base p | isAbsolutePath p = normalise p | otherwise = normalise (joinPath [base, p]) -- | Normalize --dep overrides relative to a base directory. -- Absolute override paths are kept, relative paths are rebased and normalized. normalizeDepOverrides :: FilePath -> [(String, FilePath)] -> IO [(String, FilePath)] normalizeDepOverrides base overrides = mapM (\(n,p) -> do let absP0 = if isAbsolutePath p then p else joinPath [base, p] p' <- normalizePathSafe absP0 return (n, p')) overrides -- | Apply --dep overrides (NAME=PATH) to a BuildSpec. -- Resolves override paths relative to the given base directory when needed. applyDepOverrides :: FilePath -> [(String, FilePath)] -> BuildSpec.BuildSpec -> IO BuildSpec.BuildSpec applyDepOverrides base overrides spec = do deps' <- foldM applyOne (BuildSpec.dependencies spec) overrides return spec { BuildSpec.dependencies = deps' } where applyOne depsMap (depName, depPath) = case M.lookup depName depsMap of Nothing -> return depsMap Just dep -> do let absP0 = if isAbsolutePath depPath then depPath else joinPath [base, depPath] absP <- normalizePathSafe absP0 validateDepOverridePath depName absP let dep' = dep { BuildSpec.path = Just absP } return (M.insert depName dep' depsMap) validateDepOverridePath :: String -> FilePath -> IO () validateDepOverridePath depName depPath = do exists <- doesDirectoryExist depPath unless exists $ throwProjectError ("Dependency " ++ depName ++ " path does not exist: " ++ depPath ++ "\n" ++ "Hint: Local dependency paths must point to an Acton project root\n" ++ "(directory with src/ and Build.act).") isProjectRoot <- isActonProjectRoot depPath unless isProjectRoot $ throwProjectError ("Dependency " ++ depName ++ " path is not an Acton project root: " ++ depPath ++ "\n" ++ "Hint: Local dependency paths must point to an Acton project root\n" ++ "(directory with src/ and Build.act).") fetchDependencies :: C.GlobalOptions -> Paths -> [(String, FilePath)] -> IO () fetchDependencies gopts paths depOverrides = do if isTmp paths then return () else do rootSpec0 <- loadBuildSpec (projPath paths) rootSpec <- applyDepOverrides (projPath paths) depOverrides rootSpec0 unless (C.quiet gopts) $ putStrLn "Resolving dependencies (fetching if missing)..." home <- getHomeDirectory let zigExe = joinPath [sysPath paths, "zig", "zig"] globalCache = joinPath [home, ".cache", "acton", "zig-global-cache"] depsCache = joinPath [home, ".cache", "acton", "deps"] cacheDir h = joinPath [globalCache, "p", h] createDirectoryIfMissing True globalCache createDirectoryIfMissing True depsCache let rootPins = BuildSpec.dependencies rootSpec _ <- walkProject rootPins cacheDir zigExe globalCache depsCache Data.Set.empty (projPath paths) rootSpec return () where walkProject rootPins cacheDir zigExe globalCache depsCache seen projDir spec = do projAbs <- normalizePathSafe projDir if Data.Set.member projAbs seen then return seen else do selectedDeps <- forM (M.toList (BuildSpec.dependencies spec)) $ selectDependency rootPins projAbs let pkgFetches = catMaybes [ mkPkgFetch cacheDir zigExe globalCache name dep | (name, dep) <- selectedDeps ] zigFetches = catMaybes [ mkZigFetch cacheDir zigExe globalCache name dep | (name, dep) <- M.toList (BuildSpec.zig_dependencies spec) ] results <- mapConcurrently id (pkgFetches ++ zigFetches) let errs = [ e | Left e <- results ] unless (null errs) $ throwProjectError (unlines errs) forM_ selectedDeps $ \(name, dep) -> copyPkgDep cacheDir depsCache name dep let seen' = Data.Set.insert projAbs seen foldM (walkDependency rootPins cacheDir zigExe globalCache depsCache projAbs) seen' selectedDeps selectDependency rootPins base (depName, dep) = do let (chosenDep, conflict) = case M.lookup depName rootPins of Nothing -> (dep, Nothing) Just pinDep -> if pinDep == dep then (dep, Nothing) else (pinDep, Just dep) when (isJust conflict) $ unless (C.quiet gopts) $ putStrLn ("Warning: dependency '" ++ depName ++ "' in " ++ base ++ " overridden by root pin") return (depName, chosenDep) walkDependency rootPins cacheDir zigExe globalCache depsCache base seen (depName, dep) = do depBase <- resolveDepBase base depName dep depAbs <- normalizePathSafe depBase depExists <- doesDirectoryExist depAbs if not depExists then case BuildSpec.path dep of Just p | not (null p) -> throwProjectError ("Dependency " ++ depName ++ " path does not exist: " ++ depAbs ++ "\n" ++ "Hint: Local dependency paths must point to an Acton project root\n" ++ "(directory with src/ and Build.act).") _ -> return seen else do depSpec0 <- loadBuildSpec depAbs depSpec <- applyDepOverrides depAbs depOverrides depSpec0 walkProject rootPins cacheDir zigExe globalCache depsCache seen depAbs depSpec mkPkgFetch cacheDir zigExe globalCache name dep = case BuildSpec.path dep of Just p | not (null p) -> Nothing _ -> case (BuildSpec.url dep, BuildSpec.hash dep) of (Just u, Just h) -> Just (fetchOne "pkg" name u (Just h) cacheDir zigExe globalCache) (Just _, Nothing) -> Just (return (Left ("Dependency " ++ name ++ " is missing hash"))) _ -> Nothing mkZigFetch cacheDir zigExe globalCache name dep = case BuildSpec.zpath dep of Just p | not (null p) -> Nothing _ -> case (BuildSpec.zurl dep, BuildSpec.zhash dep) of (Just u, Just h) -> Just (fetchOne "zig" name u (Just h) cacheDir zigExe globalCache) (Just _, Nothing) -> Just (return (Left ("Zig dependency " ++ name ++ " is missing hash"))) _ -> Nothing copyPkgDep cacheDir depsCache name dep = case BuildSpec.path dep of Just p | not (null p) -> return () _ -> case BuildSpec.hash dep of Nothing -> return () Just h -> do let src = cacheDir h dst = joinPath [depsCache, name ++ "-" ++ h] exists <- doesDirectoryExist dst unless exists $ do srcOk <- doesDirectoryExist src unless srcOk $ throwProjectError ("Dependency " ++ name ++ " not present in Zig cache after fetch: " ++ src) when (C.verbose gopts) $ putStrLn ("Copying dependency " ++ name ++ " (" ++ h ++ ") from Zig cache") copyTree src dst fetchOne kind name url mh cacheDir zigExe globalCache = do case mh of Just h -> do present <- doesDirectoryExist (cacheDir h) if present then do unless (C.quiet gopts) $ putStrLn ("Using cached " ++ kind ++ " dependency " ++ name ++ " (" ++ h ++ ")") return (Right h) else runFetch kind name url mh cacheDir zigExe globalCache Nothing -> runFetch kind name url mh cacheDir zigExe globalCache runFetch kind name url mh cacheDir zigExe globalCache = do unless (C.quiet gopts) $ putStrLn ("Fetching " ++ kind ++ " dependency " ++ name ++ " from " ++ url) if isHttpUrl url then fetchViaDownloadedArchive kind name url mh cacheDir zigExe globalCache else do -- other URLs, like file:// - not very common, maybe we want to constrain this somehow? res <- runZigFetch zigExe globalCache url case res of Left ex -> return (Left ("Failed to fetch dependency " ++ name ++ ": " ++ displayException ex)) Right (ExitSuccess, out, _) -> validateFetchOutput name mh cacheDir out Right (ExitFailure _, _, err) -> return (Left ("Failed to fetch dependency " ++ name ++ ":\n" ++ err)) runZigFetch :: FilePath -> FilePath -> FilePath -> IO (Either SomeException (ExitCode, String, String)) runZigFetch zigExe globalCache target = do let cmd = proc zigExe ["fetch", "--global-cache-dir", globalCache, target] try (readCreateProcessWithExitCode cmd "") :: IO (Either SomeException (ExitCode, String, String)) validateFetchOutput :: String -> Maybe String -> (String -> FilePath) -> String -> IO (Either String String) validateFetchOutput name mh cacheDir out = do let hashVal = trim out case mh of Just h | h /= hashVal -> return (Left ("Hash mismatch for dependency " ++ name ++ " (expected " ++ h ++ ", got " ++ hashVal ++ ")")) _ -> do exists <- doesDirectoryExist (cacheDir hashVal) if exists then return (Right hashVal) else return (Left ("Dependency " ++ name ++ " not present in Zig cache after fetch: " ++ cacheDir hashVal)) fetchViaDownloadedArchive kind name depUrl mh cacheDir zigExe globalCache = do dl <- downloadToLocalArchive kind name depUrl case dl of Left dlErr -> do direct <- runZigFetch zigExe globalCache depUrl case direct of Left ex -> return (Left ("Failed to fetch dependency " ++ name ++ ":\nDownload step failed: " ++ dlErr ++ "\nDirect zig fetch failed: " ++ displayException ex)) Right (ExitSuccess, out, _) -> validateFetchOutput name mh cacheDir out Right (ExitFailure _, _, err) -> return (Left ("Failed to fetch dependency " ++ name ++ ":\nDownload step failed: " ++ dlErr ++ "\nDirect zig fetch failed:\n" ++ err)) Right localArchive -> do fetched <- runZigFetch zigExe globalCache localArchive _ <- try (removeFile localArchive) :: IO (Either IOException ()) case fetched of Left ex -> return (Left ("Failed to fetch dependency " ++ name ++ ": " ++ displayException ex)) Right (ExitSuccess, out, _) -> validateFetchOutput name mh cacheDir out Right (ExitFailure _, _, err) -> return (Left ("Failed to fetch dependency " ++ name ++ ":\n" ++ err)) isHttpUrl :: String -> Bool isHttpUrl depUrl = let u = map toLower depUrl in "http://" `isPrefixOf` u || "https://" `isPrefixOf` u downloadToLocalArchive :: String -> String -> String -> IO (Either String FilePath) downloadToLocalArchive _kind _name depUrl = do parsedReq <- try (HTTP.parseRequest depUrl) :: IO (Either SomeException HTTP.Request) case parsedReq of Left ex -> return (Left ("Invalid dependency URL: " ++ displayException ex)) Right req -> do let settings = HTTP.managerSetProxy (HTTP.proxyEnvironment Nothing) tlsManagerSettings manager <- HTTP.newManager settings opened <- try (HTTP.responseOpen req manager) :: IO (Either SomeException (HTTP.Response HTTP.BodyReader)) case opened of Left ex -> return (Left (displayException ex)) Right response -> do let code = statusCode (HTTP.responseStatus response) if code < 200 || code >= 300 then do _ <- try (HTTP.responseClose response) :: IO (Either SomeException ()) return (Left ("HTTP error " ++ show code)) else do tmpDir <- getTemporaryDirectory (tmpPath, tmpHandle) <- openBinaryTempFile tmpDir "acton-fetch" let initialSuffix = archiveSuffixForRequestResponse req response streamRes <- try (streamDownloadToFile (HTTP.responseBody response) tmpHandle) :: IO (Either SomeException BS.ByteString) _ <- try (hClose tmpHandle) :: IO (Either IOException ()) _ <- try (HTTP.responseClose response) :: IO (Either SomeException ()) case streamRes of Left ex -> do _ <- try (removeFile tmpPath) :: IO (Either IOException ()) return (Left ("Unable to save downloaded archive: " ++ displayException ex)) Right sniffBytes -> case initialSuffix <|> detectArchiveSuffixFromBytes sniffBytes of Nothing -> do _ <- try (removeFile tmpPath) :: IO (Either IOException ()) return (Left "Could not determine archive type from URL path, response headers, or file bytes") Just suffix -> do let finalPath = tmpPath ++ suffix moveRes <- try (renameFile tmpPath finalPath) :: IO (Either IOException ()) case moveRes of Left ex -> do _ <- try (removeFile tmpPath) :: IO (Either IOException ()) return (Left ("Unable to finalize downloaded archive path: " ++ displayException ex)) Right _ -> return (Right finalPath) streamDownloadToFile :: HTTP.BodyReader -> Handle -> IO BS.ByteString streamDownloadToFile bodyReader outHandle = loop BS.empty where sniffLimit = 600 loop sniff = do chunk <- HTTP.brRead bodyReader if BS.null chunk then return sniff else do BS.hPut outHandle chunk let sniff' = if BS.length sniff >= sniffLimit then sniff else BS.take sniffLimit (sniff <> chunk) loop sniff' archiveSuffixForRequestResponse :: HTTP.Request -> HTTP.Response HTTP.BodyReader -> Maybe String archiveSuffixForRequestResponse req response = case archiveSuffixFromPath (B.unpack (HTTP.path req)) of Just suffix -> Just suffix Nothing -> case archiveSuffixFromContentDisposition (lookup hContentDisposition (HTTP.responseHeaders response)) of Just suffix -> Just suffix Nothing -> archiveSuffixFromContentType (lookup hContentType (HTTP.responseHeaders response)) archiveSuffixFromPath :: String -> Maybe String archiveSuffixFromPath rawPath = let p = map toLower rawPath in if ".tar.gz" `isSuffixOf` p then Just ".tar.gz" else if ".tgz" `isSuffixOf` p then Just ".tgz" else if ".tar.xz" `isSuffixOf` p then Just ".tar.xz" else if ".txz" `isSuffixOf` p then Just ".txz" else if ".tar.zst" `isSuffixOf` p then Just ".tar.zst" else if ".tzst" `isSuffixOf` p then Just ".tzst" else if ".tar" `isSuffixOf` p then Just ".tar" else if ".zip" `isSuffixOf` p then Just ".zip" else if ".jar" `isSuffixOf` p then Just ".jar" else Nothing archiveSuffixFromContentType :: Maybe B.ByteString -> Maybe String archiveSuffixFromContentType mType = case map toLower . trim . takeWhile (/= ';') . B.unpack <$> mType of Just "application/x-tar" -> Just ".tar" Just "application/gzip" -> Just ".tar.gz" Just "application/x-gzip" -> Just ".tar.gz" Just "application/tar+gzip" -> Just ".tar.gz" Just "application/x-tar-gz" -> Just ".tar.gz" Just "application/x-gtar-compressed" -> Just ".tar.gz" Just "application/x-xz" -> Just ".tar.xz" Just "application/zstd" -> Just ".tar.zst" Just "application/zip" -> Just ".zip" Just "application/x-zip-compressed" -> Just ".zip" Just "application/java-archive" -> Just ".zip" _ -> Nothing archiveSuffixFromContentDisposition :: Maybe B.ByteString -> Maybe String archiveSuffixFromContentDisposition mVal = do headerVal <- mVal filenameVal <- extractField (B.pack "filename*=") headerVal <|> extractField (B.pack "filename=") headerVal archiveSuffixFromPath (B.unpack filenameVal) where extractField key raw = let lowerRaw = B.map toLower raw (prefix, rest) = B.breakSubstring key lowerRaw in if B.null rest then Nothing else let origRest = B.drop (B.length prefix) raw val0 = B.drop (B.length key) origRest val1 = B.takeWhile (/= ';') val0 val2 = stripQuotes (B.dropWhile isSpace (trimBS val1)) val3 = case B.breakSubstring (B.pack "''") val2 of (_, t) | B.null t -> val2 (_, t) -> B.drop 2 t in if B.null val3 then Nothing else Just val3 trimBS = B.dropWhileEnd isSpace . B.dropWhile isSpace stripQuotes s | B.length s >= 2 && B.head s == '"' && B.last s == '"' = B.tail (B.init s) | otherwise = s detectArchiveSuffixFromBytes :: BS.ByteString -> Maybe String detectArchiveSuffixFromBytes bytes | startsWith [0x50, 0x4b, 0x03, 0x04] bytes = Just ".zip" | startsWith [0x50, 0x4b, 0x05, 0x06] bytes = Just ".zip" | startsWith [0x50, 0x4b, 0x07, 0x08] bytes = Just ".zip" | startsWith [0x1f, 0x8b] bytes = Just ".tar.gz" | startsWith [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00] bytes = Just ".tar.xz" | startsWith [0x28, 0xb5, 0x2f, 0xfd] bytes = Just ".tar.zst" | hasUstar bytes = Just ".tar" | otherwise = Nothing where startsWith :: [Word8] -> BS.ByteString -> Bool startsWith sig bs = BS.length bs >= length sig && BS.take (length sig) bs == BS.pack sig hasUstar bs = BS.length bs >= 262 && BS.take 5 (BS.drop 257 bs) == BS.pack [0x75, 0x73, 0x74, 0x61, 0x72] copyTree :: FilePath -> FilePath -> IO () copyTree src dst = do exists <- doesDirectoryExist src unless exists $ throwProjectError ("Source path for copyTree does not exist: " ++ src) createDirectoryIfMissing True dst entries <- listDirectory src forM_ entries $ \e -> do let s = src e d = dst e isDir <- doesDirectoryExist s if isDir then copyTree s d else do createDirectoryIfMissing True (takeDirectory d) copyFile s d -- | Collect dependency type directories using an existing ProjCtx map. -- Traverses dependency edges so downstream lookups can build search paths. depTypePathsFromMap :: M.Map FilePath ProjCtx -> FilePath -> [FilePath] depTypePathsFromMap ctxs root = snd (go Data.Set.empty root) where go seen node = case M.lookup node ctxs of Nothing -> (seen, []) Just ctx -> foldl' step (Data.Set.insert node seen, []) (projDeps ctx) step (seen, acc) (_, depRoot) = case M.lookup depRoot ctxs of Nothing -> (Data.Set.insert depRoot seen, acc) Just depCtx -> if Data.Set.member depRoot seen then (seen, acc) else let seen' = Data.Set.insert depRoot seen (seenNext, sub) = go seen' depRoot in (seenNext, acc ++ [projTypesDir depCtx] ++ sub) -- | Resolve a dependency's base directory from a BuildSpec PkgDep. -- Prefers explicit path, otherwise uses the hashed cache location. resolveDepBase :: FilePath -> String -> BuildSpec.PkgDep -> IO FilePath resolveDepBase base name dep = case BuildSpec.path dep of Just p | not (null p) -> normalizePathSafe (rebasePath base p) _ -> case BuildSpec.hash dep of Just h -> do home <- getHomeDirectory normalizePathSafe (joinPath [home, ".cache", "acton", "deps", name ++ "-" ++ h]) Nothing -> throwProjectError ("Dependency " ++ name ++ " has no path or hash") -- | Recursively collect out/types paths for all declared dependencies. -- Reads Build.act and follows dependency edges. collectDepTypePaths :: FilePath -> [(String, FilePath)] -> IO [FilePath] collectDepTypePaths projDir overrides = do root <- normalizePathSafe projDir (_, _, paths) <- go Data.Set.empty M.empty root Nothing return paths where go seen fpMap dir mSpec = do spec0 <- case mSpec of Just s -> return s Nothing -> loadBuildSpec dir spec <- applyDepOverrides dir overrides spec0 let (_, fpMap1, _) = applyFingerprint dir spec fpMap foldM (step dir) (seen, fpMap1, []) (M.toList (BuildSpec.dependencies spec)) step base (seen, fpMap, acc) (depName, dep) = do depBase <- resolveDepBase base depName dep depAbs <- normalizePathSafe depBase depExists <- doesDirectoryExist depAbs if not depExists then case BuildSpec.path dep of Just p | not (null p) -> throwProjectError ("Dependency " ++ depName ++ " path does not exist: " ++ depAbs ++ "\n" ++ "Hint: Local dependency paths must point to an Acton project root\n" ++ "(directory with src/ and Build.act).") _ -> return (seen, fpMap, acc) else do (depPath, fpMap') <- canonicalizeDep depAbs fpMap let typesDir = joinPath [depPath, "out", "types"] if Data.Set.member depPath seen then return (seen, fpMap', acc) else do let seen' = Data.Set.insert depPath seen (seenNext, fpMapNext, sub) <- go seen' fpMap' depPath Nothing return (seenNext, fpMapNext, acc ++ [typesDir] ++ sub) canonicalizeDep depAbs fpMap = do spec0 <- loadBuildSpec depAbs spec <- applyDepOverrides depAbs overrides spec0 let (canonPath, fpMap', _) = applyFingerprint depAbs spec fpMap return (canonPath, fpMap') -- | Convert a module name to its source filename (path + .act). -- This is used for diagnostics and display output. modNameToFilename :: A.ModName -> String modNameToFilename mn = joinPath (map nameToString names) ++ ".act" where A.ModName names = mn -- | Render a module name as a dotted string (foo.bar.baz). modNameToString :: A.ModName -> String modNameToString (A.ModName names) = intercalate "." (map nameToString names) -- | Render a name identifier to a plain string. nameToString :: A.Name -> String nameToString (A.Name _ s) = s -- | Check whether a NameInfo represents a root-eligible actor. -- Used to decide which roots to include in .ty headers and root generation. rootEligible :: I.NameInfo -> Bool rootEligible (I.NAct [] p k _ _) = case (p,k) of (A.TNil{}, A.TRow _ _ _ t A.TNil{}) -> prstr t == "Env" || prstr t == "None" || prstr t == "__builtin__.Env" || prstr t == "__builtin__.None" _ -> False rootEligible _ = False -- | Determine whether any non-standard output mode is enabled. -- Used to suppress normal timing/output when dumping parse/sigs/cgen, etc. altOutput :: C.CompileOptions -> Bool altOutput opts = (C.parse opts) || (C.parse_ast opts) || (C.kinds opts) || (C.types opts) || (C.sigs opts) || (C.norm opts) || (C.deact opts) || (C.cps opts) || (C.llift opts) || (C.box opts) || (C.hgen opts) || (C.cgen opts) -- | Read a UTF-8 text file with explicit encoding. -- Keeps compiler IO consistent across platforms. readFile :: FilePath -> IO String readFile f = do h <- openFile f ReadMode hSetEncoding h utf8 c <- hGetContents h return c -- | Write a UTF-8 text file atomically. -- Used for generated sources and BuildSpec parsing. writeFile :: FilePath -> String -> IO () writeFile = writeFileUtf8Atomic -- | Format a TimeSpec as a fixed-width seconds string. -- Used for stable logging and snapshot test output. fmtTime :: TimeSpec -> String fmtTime t = printf "%6.3f s" secs where secs :: Float secs = (fromIntegral(sec t)) + (fromIntegral (nsec t) / 1000000000) -- | Topologically order projects so dependencies come first. -- Used to build search paths and providers in dependency order. projDepClosure :: M.Map FilePath ProjCtx -> FilePath -> [FilePath] projDepClosure ctxs root = reverse (dfs Data.Set.empty [] root) where depsOf p = maybe [] (map snd . projDeps) (M.lookup p ctxs) dfs seen acc node | Data.Set.member node seen = acc | otherwise = let seen' = Data.Set.insert node seen acc' = foldl' (\a n -> dfs seen' a n) acc (depsOf node) in node : acc' ================================================ FILE: compiler/lib/src/Acton/Completion.hs ================================================ {-# LANGUAGE ScopedTypeVariables #-} module Acton.Completion ( Completion(..) , CompletionKind(..) , CallSignature(..) , HoverInfo(..) , SignatureParameter(..) , CallRequest(..) , ArgumentRequest(..) , MemberRequest(..) , argumentCompletions , argumentCompletionsWithEnv , callContextAt , callSignatures , callSignaturesWithEnv , completionImportKey , hoverInfo , hoverInfoWithEnv , memberContextAt , memberCompletions , memberCompletionsWithEnv , prepareCompletionEnv ) where import qualified Control.Exception as E import Control.Monad (foldM) import qualified Control.Monad.Trans.State.Strict as St import Data.Char (isAlpha, isAlphaNum, isSpace) import Data.List (find, findIndex, intercalate, isPrefixOf, nubBy) import Data.Maybe (listToMaybe, mapMaybe) import qualified Data.HashMap.Strict as HM import qualified InterfaceFiles as IF import Text.Megaparsec (eof, runParser) import qualified Acton.Env as Env import qualified Acton.NameInfo as I import qualified Acton.Parser as P import qualified Acton.Syntax as S import Utils (prstr) data CompletionKind = CompletionField | CompletionMethod | CompletionProperty | CompletionValue | CompletionKeyword deriving (Eq, Show) data Completion = Completion { completionLabel :: String , completionKind :: CompletionKind , completionDetail :: Maybe String } deriving (Eq, Show) data MemberRequest = MemberRequest { memberReceiver :: String , memberPrefix :: String } deriving (Eq, Show) data CallRequest = CallRequest { callTarget :: [String] , callActiveParameter :: Int , callArgumentText :: String } deriving (Eq, Show) data ArgumentRequest = ArgumentRequest { argumentTarget :: [String] , argumentPrefix :: String , argumentSuppliedKeywords :: [String] } deriving (Eq, Show) data SignatureParameter = SignatureParameter { signatureParameterLabel :: String } deriving (Eq, Show) data CallSignature = CallSignature { callSignatureLabel :: String , callSignatureParameters :: [SignatureParameter] , callSignatureActiveParameter :: Int } deriving (Eq, Show) data HoverInfo = HoverInfo { hoverLabel :: String , hoverDetail :: String , hoverDocumentation :: Maybe String } deriving (Eq, Show) data StringState = StringState Char Bool deriving (Eq, Show) data SourceContext = SourceContext { sourceClass :: Maybe ClassContext , sourceDef :: Maybe DefContext , sourceLocalBindings :: [LocalBinding] } deriving (Eq, Show) data ClassContext = ClassContext { className :: String , classParents :: [String] , classIndent :: Int } deriving (Eq, Show) data DefContext = DefContext { defName :: String , defParams :: [Param] , defIndent :: Int } deriving (Eq, Show) data Param = Param { paramName :: String , paramAnn :: Maybe String } deriving (Eq, Show) data LocalBinding = LocalBinding { localName :: String , localClassName :: Maybe String , localClassIndent :: Maybe Int , localDefName :: String , localDefIndent :: Int , localKind :: LocalKind } deriving (Eq, Show) data LocalKind = LocalAnnotated String | LocalCallResult [String] | LocalMemberPath [String] deriving (Eq, Show) data HoverTarget = HoverTarget { hoverResolvedType :: S.Type , hoverResolvedDoc :: Maybe String } deriving (Eq, Show) data KeywordParameter = KeywordParameter { keywordParameterName :: String , keywordParameterType :: S.Type } deriving (Eq, Show) data Scope = ScopeClass ClassContext | ScopeDef DefContext deriving (Eq, Show) data ScanState = ScanState { scanScopes :: [Scope] , scanLocals :: [LocalBinding] } deriving (Eq, Show) memberCompletions :: Env.Env0 -> [FilePath] -> S.ModName -> FilePath -> String -> Int -> IO [Completion] memberCompletions baseEnv searchPath modName fileName src cursor = do res <- E.try $ do case memberContextAt src cursor of Nothing -> return [] Just req -> do env <- prepareCompletionEnv baseEnv searchPath modName fileName src let ctx = scanSourceContext src cursor comps = completeMember env ctx req E.evaluate (forceCompletions comps) case res of Left (_ :: E.SomeException) -> return [] Right comps -> return comps memberCompletionsWithEnv :: Env.Env0 -> String -> Int -> [Completion] memberCompletionsWithEnv env src cursor = case memberContextAt src cursor of Nothing -> [] Just req -> let ctx = scanSourceContext src cursor in completeMember env ctx req argumentCompletions :: Env.Env0 -> [FilePath] -> S.ModName -> FilePath -> String -> Int -> IO [Completion] argumentCompletions baseEnv searchPath modName fileName src cursor = do res <- E.try $ do case argumentContextAt src cursor of Nothing -> return [] Just req -> do env <- prepareCompletionEnv baseEnv searchPath modName fileName src let ctx = scanSourceContext src cursor comps = completeArguments env ctx req E.evaluate (forceCompletions comps) case res of Left (_ :: E.SomeException) -> return [] Right comps -> return comps argumentCompletionsWithEnv :: Env.Env0 -> String -> Int -> [Completion] argumentCompletionsWithEnv env src cursor = case argumentContextAt src cursor of Nothing -> [] Just req -> let ctx = scanSourceContext src cursor in completeArguments env ctx req callSignatures :: Env.Env0 -> [FilePath] -> S.ModName -> FilePath -> String -> Int -> IO [CallSignature] callSignatures baseEnv searchPath modName fileName src cursor = do res <- E.try $ do case callContextAt src cursor of Nothing -> return [] Just req -> do env <- prepareCompletionEnv baseEnv searchPath modName fileName src let ctx = scanSourceContext src cursor sigs = maybe [] (:[]) (callSignature env ctx req) E.evaluate (forceSignatures sigs) case res of Left (_ :: E.SomeException) -> return [] Right sigs -> return sigs callSignaturesWithEnv :: Env.Env0 -> String -> Int -> [CallSignature] callSignaturesWithEnv env src cursor = case callContextAt src cursor of Nothing -> [] Just req -> let ctx = scanSourceContext src cursor in maybe [] (:[]) (callSignature env ctx req) hoverInfo :: Env.Env0 -> [FilePath] -> S.ModName -> FilePath -> String -> Int -> IO (Maybe HoverInfo) hoverInfo baseEnv searchPath modName fileName src cursor = do res <- E.try $ do case hoverTargetAt src cursor of Nothing -> return Nothing Just parts -> do env <- prepareCompletionEnv baseEnv searchPath modName fileName src let ctx = scanSourceContext src cursor info = hoverInfoForParts env ctx parts E.evaluate (forceMaybeHover info) case res of Left (_ :: E.SomeException) -> return Nothing Right info -> return info hoverInfoWithEnv :: Env.Env0 -> String -> Int -> Maybe HoverInfo hoverInfoWithEnv env src cursor = do parts <- hoverTargetAt src cursor let ctx = scanSourceContext src cursor hoverInfoForParts env ctx parts prepareCompletionEnv :: Env.Env0 -> [FilePath] -> S.ModName -> FilePath -> String -> IO Env.Env0 prepareCompletionEnv baseEnv searchPath modName fileName src = do imps <- parseImports fileName src completionEnv searchPath baseEnv modName imps completionImportKey :: FilePath -> String -> IO String completionImportKey fileName src = do imps <- parseImports fileName src return (show imps) memberContextAt :: String -> Int -> Maybe MemberRequest memberContextAt src cursor = case restAfterPrefix of '.':rest -> let receiver = reverse (takeWhile receiverChar rest) receiver' = trimDots receiver in if null receiver' then Nothing else Just MemberRequest { memberReceiver = receiver' , memberPrefix = reverse prefixRev } _ -> Nothing where before = take (max 0 (min cursor (length src))) src (prefixRev, restAfterPrefix) = span identChar (reverse before) identChar c = isAlphaNum c || c == '_' receiverChar c = identChar c || c == '.' || c == '?' trimDots = reverse . dropWhile (== '.') . reverse . dropWhile (== '.') hoverTargetAt :: String -> Int -> Maybe [String] hoverTargetAt src cursor = do let cursor' = max 0 (min cursor (length src)) before = take cursor' src after = drop cursor' src identPrefix = reverse (takeWhile identChar (reverse before)) identSuffix = takeWhile identChar after ident = identPrefix ++ identSuffix identStart = cursor' - length identPrefix if not (validIdent ident) then Nothing else do let beforeIdent = take identStart src target = case reverse beforeIdent of '.':rest -> let receiver = reverse (takeWhile receiverChar rest) in receiver ++ "." ++ ident _ -> ident parts = receiverParts target if all validIdent parts && not (null parts) then Just parts else Nothing where receiverChar c = identChar c || c == '.' || c == '?' callContextAt :: String -> Int -> Maybe CallRequest callContextAt src cursor = do openIx <- activeOpenParen before let args = drop (openIx + 1) before calleeBeforeParen = take openIx before callee = reverse $ takeWhile callPathChar $ dropWhile isSpace $ reverse calleeBeforeParen target = receiverParts callee if null target then Nothing else Just CallRequest { callTarget = target , callActiveParameter = activeArgIndex args , callArgumentText = args } where before = take (max 0 (min cursor (length src))) src callPathChar c = identChar c || c == '.' || c == '?' argumentContextAt :: String -> Int -> Maybe ArgumentRequest argumentContextAt src cursor = do req <- callContextAt src cursor prefix <- activeKeywordPrefix (callArgumentText req) return ArgumentRequest { argumentTarget = callTarget req , argumentPrefix = prefix , argumentSuppliedKeywords = suppliedKeywordNames (callArgumentText req) } activeKeywordPrefix :: String -> Maybe String activeKeywordPrefix args = do current <- lastMaybe (splitArgSegments args) if topLevelContains '=' current then Nothing else let prefix = reverse (takeWhile identChar (reverse current)) beforePrefix = take (length current - length prefix) current in if all isSpace beforePrefix then Just prefix else Nothing suppliedKeywordNames :: String -> [String] suppliedKeywordNames args = mapMaybe keywordName (splitArgSegments args) where keywordName segment = let (lhs, eqPart) = breakArgTopLevel '=' segment nm = trim lhs in case eqPart of '=':_ | validIdent nm -> Just nm _ -> Nothing splitArgSegments :: String -> [String] splitArgSegments = reverse . map reverse . go 0 0 0 Nothing [[]] where go _ _ _ _ acc [] = acc go p b c str (x:xs) (ch:chs) | Just st <- str = go p b c (advanceString st ch) ((ch:x):xs) chs | isStringQuote ch = go p b c (Just (StringState ch False)) ((ch:x):xs) chs | ch == ',' && p == 0 && b == 0 && c == 0 = go p b c str ([]:x:xs) chs | ch == '(' = go (p + 1) b c str ((ch:x):xs) chs | ch == ')' = go (max 0 (p - 1)) b c str ((ch:x):xs) chs | ch == '[' = go p (b + 1) c str ((ch:x):xs) chs | ch == ']' = go p (max 0 (b - 1)) c str ((ch:x):xs) chs | ch == '{' = go p b (c + 1) str ((ch:x):xs) chs | ch == '}' = go p b (max 0 (c - 1)) str ((ch:x):xs) chs | otherwise = go p b c str ((ch:x):xs) chs go _ _ _ _ [] _ = [] topLevelContains :: Char -> String -> Bool topLevelContains needle = go 0 0 0 Nothing where go _ _ _ _ [] = False go p b c str (ch:chs) | Just st <- str = go p b c (advanceString st ch) chs | isStringQuote ch = go p b c (Just (StringState ch False)) chs | ch == needle && p == 0 && b == 0 && c == 0 = True | ch == '(' = go (p + 1) b c str chs | ch == ')' = go (max 0 (p - 1)) b c str chs | ch == '[' = go p (b + 1) c str chs | ch == ']' = go p (max 0 (b - 1)) c str chs | ch == '{' = go p b (c + 1) str chs | ch == '}' = go p b (max 0 (c - 1)) str chs | otherwise = go p b c str chs breakArgTopLevel :: Char -> String -> (String, String) breakArgTopLevel needle = go 0 0 0 Nothing [] where go _ _ _ _ acc [] = (reverse acc, []) go p b c str acc s@(ch:chs) | Just st <- str = go p b c (advanceString st ch) (ch:acc) chs | isStringQuote ch = go p b c (Just (StringState ch False)) (ch:acc) chs | ch == needle && p == 0 && b == 0 && c == 0 = (reverse acc, s) | ch == '(' = go (p + 1) b c str (ch:acc) chs | ch == ')' = go (max 0 (p - 1)) b c str (ch:acc) chs | ch == '[' = go p (b + 1) c str (ch:acc) chs | ch == ']' = go p (max 0 (b - 1)) c str (ch:acc) chs | ch == '{' = go p b (c + 1) str (ch:acc) chs | ch == '}' = go p b (max 0 (c - 1)) str (ch:acc) chs | otherwise = go p b c str (ch:acc) chs lastMaybe :: [a] -> Maybe a lastMaybe [] = Nothing lastMaybe xs = Just (last xs) activeOpenParen :: String -> Maybe Int activeOpenParen = listToMaybe . go 0 Nothing [] where go _ _ stack [] = stack go ix str stack (ch:chs) | Just st <- str = go (ix + 1) (advanceString st ch) stack chs | isStringQuote ch = go (ix + 1) (Just (StringState ch False)) stack chs | ch == '(' = go (ix + 1) str (ix:stack) chs | ch == ')' = go (ix + 1) str (drop 1 stack) chs | otherwise = go (ix + 1) str stack chs activeArgIndex :: String -> Int activeArgIndex = go 0 0 0 0 Nothing where go arg _ _ _ _ [] = arg go arg p b c str (x:xs) | Just st <- str = go arg p b c (advanceString st x) xs | isStringQuote x = go arg p b c (Just (StringState x False)) xs | x == '(' = go arg (p + 1) b c str xs | x == ')' = go arg (max 0 (p - 1)) b c str xs | x == '[' = go arg p (b + 1) c str xs | x == ']' = go arg p (max 0 (b - 1)) c str xs | x == '{' = go arg p b (c + 1) str xs | x == '}' = go arg p b (max 0 (c - 1)) str xs | x == ',' && p == 0 && b == 0 && c == 0 = go (arg + 1) p b c str xs | otherwise = go arg p b c str xs isStringQuote :: Char -> Bool isStringQuote ch = ch == '"' || ch == '\'' advanceString :: StringState -> Char -> Maybe StringState advanceString (StringState quote escaped) ch | escaped = Just (StringState quote False) | ch == '\\' = Just (StringState quote True) | ch == quote = Nothing | otherwise = Just (StringState quote False) completeMember :: Env.Env0 -> SourceContext -> MemberRequest -> [Completion] completeMember env ctx req = case resolveReceiverType env ctx (receiverParts (memberReceiver req)) of Nothing -> [] Just typ -> attrsForType env typ (memberPrefix req) completeArguments :: Env.Env0 -> SourceContext -> ArgumentRequest -> [Completion] completeArguments env ctx req = case resolveCallableInfo env ctx (argumentTarget req) >>= typeOfInfo of Just typ -> case Env.unalias env typ of S.TFun _ _ _ kw _ -> [ Completion (keywordParameterName param ++ "=") CompletionKeyword (Just (displayType (keywordParameterType param))) | param <- keywordParameterRows kw , argumentPrefix req `isPrefixOf` keywordParameterName param , keywordParameterName param `notElem` argumentSuppliedKeywords req ] _ -> [] _ -> [] callSignature :: Env.Env0 -> SourceContext -> CallRequest -> Maybe CallSignature callSignature env ctx req = do info <- resolveCallableInfo env ctx (callTarget req) typ <- typeOfInfo info case Env.unalias env typ of S.TFun _ _ pos kw ret -> let params = signatureParameters pos kw active = if null params then 0 else min (callActiveParameter req) (length params - 1) label = intercalate "." (callTarget req) ++ "(" ++ intercalate ", " (map signatureParameterLabel params) ++ ") -> " ++ displayType ret in Just CallSignature { callSignatureLabel = label , callSignatureParameters = params , callSignatureActiveParameter = active } _ -> Nothing hoverInfoForParts :: Env.Env0 -> SourceContext -> [String] -> Maybe HoverInfo hoverInfoForParts env ctx parts = do target <- hoverTarget env ctx parts let label = intercalate "." parts return HoverInfo { hoverLabel = label , hoverDetail = label ++ ": " ++ displayType (hoverResolvedType target) , hoverDocumentation = hoverResolvedDoc target } hoverTarget :: Env.Env0 -> SourceContext -> [String] -> Maybe HoverTarget hoverTarget env ctx parts = memberHoverTarget env ctx parts <|> baseHoverTarget env ctx parts <|> globalHoverTarget env parts memberHoverTarget :: Env.Env0 -> SourceContext -> [String] -> Maybe HoverTarget memberHoverTarget env ctx parts = do (receiver, attr) <- unsnoc parts typ <- resolveReceiverType env ctx receiver tc <- typeTCon env typ info <- attrInfo env tc (S.name attr) attrTyp <- Env.unalias env <$> typeOfInfo info return HoverTarget { hoverResolvedType = attrTyp , hoverResolvedDoc = docOfInfo info <|> typeDoc env attrTyp } baseHoverTarget :: Env.Env0 -> SourceContext -> [String] -> Maybe HoverTarget baseHoverTarget env ctx parts = do typ <- resolveReceiverType env ctx parts return HoverTarget { hoverResolvedType = typ , hoverResolvedDoc = typeDoc env typ } globalHoverTarget :: Env.Env0 -> [String] -> Maybe HoverTarget globalHoverTarget env parts = do info <- lookupPathInfo env parts typ <- Env.unalias env <$> typeOfInfo info return HoverTarget { hoverResolvedType = typ , hoverResolvedDoc = docOfInfo info <|> typeDoc env typ } resolveCallableInfo :: Env.Env0 -> SourceContext -> [String] -> Maybe I.NameInfo resolveCallableInfo env ctx parts = memberCallableInfo env ctx parts <|> lookupPathInfo env parts memberCallableInfo :: Env.Env0 -> SourceContext -> [String] -> Maybe I.NameInfo memberCallableInfo env ctx parts = do (receiver, attr) <- unsnoc parts typ <- resolveReceiverType env ctx receiver tc <- typeTCon env typ attrInfo env tc (S.name attr) unsnoc :: [a] -> Maybe ([a], a) unsnoc [] = Nothing unsnoc xs = Just (init xs, last xs) signatureParameters :: S.Type -> S.Type -> [SignatureParameter] signatureParameters pos kw = zipWith positional [1..] (positionalTypes pos) ++ keywordParameters kw where positional ix typ = SignatureParameter ("arg" ++ show (ix :: Int) ++ ": " ++ displayType typ) positionalTypes :: S.Type -> [S.Type] positionalTypes row = case row of S.TRow _ S.PRow _ typ rest -> typ : positionalTypes rest S.TStar _ S.PRow rest -> [S.tTupleP rest] _ -> [] keywordParameters :: S.Type -> [SignatureParameter] keywordParameters row = case row of S.TRow _ S.KRow name typ rest -> SignatureParameter (S.rawstr name ++ ": " ++ displayType typ) : keywordParameters rest S.TStar _ S.KRow rest -> [SignatureParameter ("**kwargs: " ++ displayType (S.tTupleK rest))] _ -> [] keywordParameterRows :: S.Type -> [KeywordParameter] keywordParameterRows row = case row of S.TRow _ S.KRow name typ rest -> KeywordParameter (S.rawstr name) typ : keywordParameterRows rest _ -> [] completionEnv :: [FilePath] -> Env.Env0 -> S.ModName -> [S.Import] -> IO Env.Env0 completionEnv searchPath baseEnv modName imps = Env.mkEnv searchPath baseEnv mod `E.catch` \(_ :: E.SomeException) -> shallowCompletionEnv searchPath baseEnv imps where mod = S.Module modName imps Nothing [] -- Completion should still work when an otherwise usable direct import records -- stale transitive interfaces. Load only the imported modules themselves as a -- fallback, which is enough for generated base classes and typed constructors. shallowCompletionEnv :: [FilePath] -> Env.Env0 -> [S.Import] -> IO Env.Env0 shallowCompletionEnv searchPath baseEnv imps = refreshHModules <$> foldM (shallowImport searchPath) baseEnv imps refreshHModules :: Env.Env0 -> Env.Env0 refreshHModules env = env { Env.hmodules = I.convTEnv2HTEnv (Env.modules env) } shallowImport :: [FilePath] -> Env.Env0 -> S.Import -> IO Env.Env0 shallowImport searchPath env imp = case imp of S.Import _ items -> foldM (shallowModuleItem searchPath) env items S.FromImport _ (S.ModRef (0, Just m)) items -> shallowModule searchPath env m $ \te env' -> Env.importSome items m te env' S.FromImportAll _ (S.ModRef (0, Just m)) -> shallowModule searchPath env m $ \te env' -> Env.importAll m te env' _ -> return env shallowModuleItem :: [FilePath] -> Env.Env0 -> S.ModuleItem -> IO Env.Env0 shallowModuleItem searchPath env (S.ModuleItem m as) = shallowModule searchPath env m $ \te env' -> case as of Nothing -> Env.addImport m env' Just n -> Env.defineClosed [(n, I.NMAlias m)] env' shallowModule :: [FilePath] -> Env.Env0 -> S.ModName -> (I.TEnv -> Env.Env0 -> Env.Env0) -> IO Env.Env0 shallowModule searchPath env m applyImport = do loaded <- readModuleInterface searchPath m case loaded of Nothing -> return env Just (ms, te, mdoc) -> return $ applyImport te (Env.addMod m ms te mdoc env) readModuleInterface :: [FilePath] -> S.ModName -> IO (Maybe ([S.ModName], I.TEnv, Maybe String)) readModuleInterface searchPath m = do mty <- Env.findTyFile searchPath m case mty of Nothing -> return Nothing Just ty -> do res <- (Just <$> IF.readFile ty) `E.catch` \(_ :: E.SomeException) -> return Nothing case res of Just (_, I.NModule imps te mdoc, _, _, _, _, _, _, _, _, _, _) -> return (Just (imps, te, mdoc)) _ -> return Nothing resolveReceiverType :: Env.Env0 -> SourceContext -> [String] -> Maybe S.Type resolveReceiverType _ _ [] = Nothing resolveReceiverType env ctx (base:attrs) = do baseType <- resolveBaseType env ctx base foldl step (Just baseType) attrs where step Nothing _ = Nothing step (Just typ) attr = do tc <- typeTCon env typ attrType env tc (S.name attr) resolveBaseType :: Env.Env0 -> SourceContext -> String -> Maybe S.Type resolveBaseType env ctx name = localBindingType env ctx name <|> explicitParamType env ctx name <|> inheritedParamType env ctx name localBindingType :: Env.Env0 -> SourceContext -> String -> Maybe S.Type localBindingType env ctx name = listToMaybe $ mapMaybe bindingType matching where matching = case sourceDef ctx of Nothing -> [] Just def -> filter (sameDef def) $ filter ((== name) . localName) (sourceLocalBindings ctx) sameDef def binding = localDefName binding == defName def && localDefIndent binding == defIndent def && localClassKey binding == sourceClassKey sourceClassKey = fmap (\cls -> (className cls, classIndent cls)) (sourceClass ctx) localClassKey binding = (,) <$> localClassName binding <*> localClassIndent binding bindingType binding = case localKind binding of LocalAnnotated ann -> parseTypeText env ann LocalCallResult callee -> callResultType env ctx callee LocalMemberPath path -> resolveReceiverType env ctx path explicitParamType :: Env.Env0 -> SourceContext -> String -> Maybe S.Type explicitParamType env ctx name = do def <- sourceDef ctx param <- find ((== name) . paramName) (defParams def) ann <- paramAnn param parseTypeText env ann inheritedParamType :: Env.Env0 -> SourceContext -> String -> Maybe S.Type inheritedParamType env ctx name = do cls <- sourceClass ctx def <- sourceDef ctx paramIx <- methodParamIndex name (defParams def) listToMaybe $ mapMaybe (parentParamType paramIx name (defName def)) (classParents cls) where parentParamType ix pname method parentText = do parentType <- parseTypeText env parentText parentTc <- typeTCon env parentType (_, schema, _) <- Env.findAttr env parentTc (S.name method) parentMod <- qnameModule (S.tcname parentTc) Env.unalias (Env.setMod parentMod env) <$> paramTypeFromSchema ix pname schema qnameModule qn = case qn of S.QName mn _ -> Just mn S.GName mn _ -> Just mn S.NoQ _ -> Nothing methodParamIndex :: String -> [Param] -> Maybe Int methodParamIndex name params = do ix <- findIndex ((== name) . paramName) params let selfOffset = case params of Param "self" _ : _ -> 1 _ -> 0 ix' = ix - selfOffset if ix' < 0 then Nothing else Just ix' paramTypeFromSchema :: Int -> String -> S.TSchema -> Maybe S.Type paramTypeFromSchema ix pname (S.TSchema _ _ typ) = case typ of S.TFun _ _ pos kwd _ -> positionalType ix pos <|> keywordType (S.name pname) kwd _ -> Nothing positionalType :: Int -> S.Type -> Maybe S.Type positionalType ix row = case row of S.TRow _ S.PRow _ typ rest | ix == 0 -> Just typ | otherwise -> positionalType (ix - 1) rest _ -> Nothing keywordType :: S.Name -> S.Type -> Maybe S.Type keywordType name row = case row of S.TRow _ S.KRow n typ rest | S.rawstr n == S.rawstr name -> Just typ | otherwise -> keywordType name rest _ -> Nothing attrsForType :: Env.Env0 -> S.Type -> String -> [Completion] attrsForType env typ prefix = case typeTCon env typ of Nothing -> [] Just tc -> dedup $ [ Completion (S.rawstr n) (kindOf info) (detailOf info) | (n, info) <- Env.fullAttrEnv env tc , prefix `isPrefixOf` S.rawstr n ] attrType :: Env.Env0 -> S.TCon -> S.Name -> Maybe S.Type attrType env tc attr = attrInfo env tc attr >>= typeOfInfo attrInfo :: Env.Env0 -> S.TCon -> S.Name -> Maybe I.NameInfo attrInfo env tc attr = snd <$> find ((== S.rawstr attr) . S.rawstr . fst) (Env.fullAttrEnv env tc) typeOfInfo :: I.NameInfo -> Maybe S.Type typeOfInfo info = case info of I.NVar t -> Just t I.NSVar t -> Just t I.NDef schema _ _ -> Just (S.sctype schema) I.NSig schema _ _ -> Just (S.sctype schema) _ -> Nothing callResultType :: Env.Env0 -> SourceContext -> [String] -> Maybe S.Type callResultType env ctx parts = do info <- resolveCallableInfo env ctx parts functionReturnType env info lookupPathInfo :: Env.Env0 -> [String] -> Maybe I.NameInfo lookupPathInfo _ [] = Nothing lookupPathInfo env [n] = lookupQNameInfo env (S.NoQ (S.name n)) lookupPathInfo env parts = let modPart = init parts n = last parts qn = S.QName (S.ModName (map S.name modPart)) (S.name n) in lookupQNameInfo env qn lookupQNameInfo :: Env.Env0 -> S.QName -> Maybe I.NameInfo lookupQNameInfo env qn = case qn of S.NoQ n -> lookupNoQ n S.QName m n -> lookupModuleItem env (Env.findHMod m env) n S.GName m n | Just m == Env.thismod env -> lookupQNameInfo env (S.NoQ n) | otherwise -> lookupModuleItem env (Env.lookupHMod m env) n where lookupNoQ n = resolve =<< Env.lookupName n env resolve (I.HNAlias qn') = lookupQNameInfo env qn' resolve info = Just (I.convHNameInfo2NameInfo info) lookupModuleItem :: Env.Env0 -> Maybe I.HTEnv -> S.Name -> Maybe I.NameInfo lookupModuleItem env mtenv n = do tenv <- mtenv info <- HM.lookup n tenv case info of I.HNAlias qn -> lookupQNameInfo env qn _ -> Just (I.convHNameInfo2NameInfo info) functionReturnType :: Env.Env0 -> I.NameInfo -> Maybe S.Type functionReturnType env info = do typ <- typeOfInfo info case typ of S.TFun _ _ _ _ ret -> Just (Env.unalias env ret) _ -> Nothing kindOf :: I.NameInfo -> CompletionKind kindOf info = case info of I.NSig schema dec _ | dec == S.Property -> CompletionProperty | isFun (S.sctype schema) -> CompletionMethod | otherwise -> CompletionField I.NDef schema dec _ | dec == S.Property -> CompletionProperty | isFun (S.sctype schema) -> CompletionMethod | otherwise -> CompletionValue I.NVar{} -> CompletionField I.NSVar{} -> CompletionField _ -> CompletionValue where isFun S.TFun{} = True isFun _ = False detailOf :: I.NameInfo -> Maybe String detailOf info = fmap displayType (typeOfInfo info) docOfInfo :: I.NameInfo -> Maybe String docOfInfo info = cleanDoc $ case info of I.NDef _ _ doc -> doc I.NSig _ _ doc -> doc I.NAct _ _ _ _ doc -> doc I.NClass _ _ _ doc -> doc I.NProto _ _ _ doc -> doc I.NExt _ _ _ _ _ doc -> doc I.NModule _ _ doc -> doc _ -> Nothing typeDoc :: Env.Env0 -> S.Type -> Maybe String typeDoc env typ = do tc <- typeTCon env typ info <- lookupTConInfo env tc docOfInfo info lookupTConInfo :: Env.Env0 -> S.TCon -> Maybe I.NameInfo lookupTConInfo env tc = lookupQNameInfo env (S.tcname tc) cleanDoc :: Maybe String -> Maybe String cleanDoc Nothing = Nothing cleanDoc (Just doc) = let doc' = trim doc in if null doc' then Nothing else Just doc' displayType :: S.Type -> String displayType = stripBuiltinPrefix . prstr stripBuiltinPrefix :: String -> String stripBuiltinPrefix [] = [] stripBuiltinPrefix s | builtinPrefix `isPrefixOf` s = stripBuiltinPrefix (drop (length builtinPrefix) s) | otherwise = head s : stripBuiltinPrefix (tail s) where builtinPrefix = "__builtin__." typeTCon :: Env.Env0 -> S.Type -> Maybe S.TCon typeTCon env typ = case typ of S.TCon _ tc -> Just tc S.TOpt _ inner -> typeTCon env inner S.TVar _ tv -> Just (Env.findTVBound env tv) _ -> Nothing parseTypeText :: Env.Env0 -> String -> Maybe S.Type parseTypeText env raw = case runParser (St.evalStateT (P.ttype <* eof) P.initState) "" raw of Left _ -> Nothing Right typ -> Just (Env.unalias env typ) parseImports :: FilePath -> String -> IO [S.Import] parseImports fileName src = do res <- E.try (P.parseModuleHeader fileName src) case res of Left (_ :: E.SomeException) -> return [] Right (imps, _) -> return imps scanSourceContext :: String -> Int -> SourceContext scanSourceContext src cursor = let st = foldl scanLine (ScanState [] []) (contextLines src cursor) scopes = scanScopes st in SourceContext { sourceClass = listToMaybe [ c | ScopeClass c <- scopes ] , sourceDef = listToMaybe [ d | ScopeDef d <- scopes ] , sourceLocalBindings = scanLocals st } scanLine :: ScanState -> String -> ScanState scanLine st line | null stripped = st | "#" `isPrefixOf` stripped = st | otherwise = let indent = lineIndent line scopes' = popClosed indent (scanScopes st) in case parseClass indent stripped of Just cls -> st { scanScopes = ScopeClass cls : scopes' } Nothing -> case parseDef indent stripped of Just def -> st { scanScopes = ScopeDef def : scopes' } Nothing -> st { scanScopes = scopes' , scanLocals = scanLocal scopes' stripped (scanLocals st) } where stripped = trimLeft line scanLocal :: [Scope] -> String -> [LocalBinding] -> [LocalBinding] scanLocal scopes stripped locals | Just def <- activeDef = case parseLocalBinding stripped of Just (nm, kind) -> LocalBinding { localName = nm , localClassName = className <$> activeClass , localClassIndent = classIndent <$> activeClass , localDefName = defName def , localDefIndent = defIndent def , localKind = kind } : locals Nothing -> locals | otherwise = locals where activeDef = listToMaybe [ d | ScopeDef d <- scopes ] activeClass = listToMaybe [ c | ScopeClass c <- scopes ] popClosed :: Int -> [Scope] -> [Scope] popClosed indent = dropWhile ((>= indent) . scopeIndent) scopeIndent :: Scope -> Int scopeIndent (ScopeClass cls) = classIndent cls scopeIndent (ScopeDef def) = defIndent def parseClass :: Int -> String -> Maybe ClassContext parseClass indent line | "class " `isPrefixOf` line = do let rest = dropWhile isSpace (drop (length "class ") line) (nm, afterName) = span identChar rest if null nm then Nothing else Just ClassContext { className = nm , classParents = parseParents (skipTypeBinder afterName) , classIndent = indent } | otherwise = Nothing parseParents :: String -> [String] parseParents afterName = case dropWhile isSpace afterName of '(':rest -> case balancedContent '(' ')' rest of Just inside -> filter (not . null) (map trim (splitTopLevel ',' inside)) Nothing -> [] _ -> [] parseDef :: Int -> String -> Maybe DefContext parseDef indent line = do afterDef <- afterDefKeyword line let (nm, afterName) = span identChar (dropWhile isSpace afterDef) paramsText <- case skipTypeBinder afterName of '(':rest -> balancedContent '(' ')' rest _ -> Nothing return DefContext { defName = nm , defParams = mapMaybe parseParam (splitTopLevel ',' paramsText) , defIndent = indent } afterDefKeyword :: String -> Maybe String afterDefKeyword line | "def " `isPrefixOf` line = Just (drop 4 line) | otherwise = case stripEffect line of Just rest | "def " `isPrefixOf` rest -> Just (drop 4 rest) _ -> Nothing where stripEffect s = case words s of w:_ | w `elem` ["mut", "proc", "pure", "action"] -> Just (dropWhile isSpace (drop (length w) s)) _ -> Nothing parseParam :: String -> Maybe Param parseParam raw | null nm = Nothing | otherwise = Just Param { paramName = nm, paramAnn = ann } where s0 = trim raw s = dropWhile (== '*') s0 (beforeDefault, _) = breakTopLevel '=' s (namePart, annPart) = breakTopLevel ':' beforeDefault nm = trim namePart ann = case annPart of ':' : rest -> let a = trim rest in if null a then Nothing else Just a _ -> Nothing parseLocalBinding :: String -> Maybe (String, LocalKind) parseLocalBinding line = do let (lhs, eqPart) = breakTopLevel '=' line rhs <- case eqPart of '=' : rest -> Just rest _ -> Nothing let (namePart, annPart) = breakTopLevel ':' lhs nm = trim namePart if not (validIdent nm) then Nothing else case annPart of ':' : annRaw -> let ann = trim annRaw in if null ann then Nothing else Just (nm, LocalAnnotated ann) _ -> case parseCallTarget rhs of Just callee -> Just (nm, LocalCallResult callee) Nothing -> do path <- parseMemberPath rhs return (nm, LocalMemberPath path) parseCallTarget :: String -> Maybe [String] parseCallTarget raw = let s = trim raw (callee, rest) = span callPathChar s in case (strictReceiverParts callee, dropWhile isSpace rest) of (Just parts, '(' : _) | validCallPath parts -> Just parts _ -> Nothing where callPathChar c = identChar c || c == '.' || c == '?' validCallPath parts = all validIdent parts && not (null parts) parseMemberPath :: String -> Maybe [String] parseMemberPath raw = let s = trim raw (path, rest) = span memberPathChar s in case strictReceiverParts path of Just parts | all isSpace rest && validMemberPath parts -> Just parts _ -> Nothing where memberPathChar c = identChar c || c == '.' || c == '?' validMemberPath parts = length parts > 1 && all validIdent parts validIdent :: String -> Bool validIdent [] = False validIdent (c:cs) = (isAlpha c || c == '_') && all identChar cs contextLines :: String -> Int -> [String] contextLines src cursor = let before = take (max 0 (min cursor (length src))) src ls = lines before in case reverse before of '\n':_ -> ls _ -> case ls of [] -> [] _ -> init ls receiverParts :: String -> [String] receiverParts = filter (not . null) . map stripOptionalMarker . splitOn '.' strictReceiverParts :: String -> Maybe [String] strictReceiverParts raw = let parts = map stripOptionalMarker (splitOn '.' raw) in if any null parts then Nothing else Just parts stripOptionalMarker :: String -> String stripOptionalMarker = reverse . dropWhile (== '?') . reverse lineIndent :: String -> Int lineIndent = go 0 where go n (' ':xs) = go (n + 1) xs go n ('\t':xs) = go (n + 8) xs go n _ = n identChar :: Char -> Bool identChar c = isAlphaNum c || c == '_' splitOn :: Char -> String -> [String] splitOn sep = splitTopLevel sep splitTopLevel :: Char -> String -> [String] splitTopLevel sep = reverse . map reverse . go 0 0 0 [[]] where go _ _ _ acc [] = acc go p b c (x:xs) (ch:chs) | ch == sep && p == 0 && b == 0 && c == 0 = go p b c ([]:x:xs) chs | ch == '(' = go (p + 1) b c ((ch:x):xs) chs | ch == ')' = go (max 0 (p - 1)) b c ((ch:x):xs) chs | ch == '[' = go p (b + 1) c ((ch:x):xs) chs | ch == ']' = go p (max 0 (b - 1)) c ((ch:x):xs) chs | ch == '{' = go p b (c + 1) ((ch:x):xs) chs | ch == '}' = go p b (max 0 (c - 1)) ((ch:x):xs) chs | otherwise = go p b c ((ch:x):xs) chs go _ _ _ [] _ = [] breakTopLevel :: Char -> String -> (String, String) breakTopLevel needle = go 0 0 0 [] where go _ _ _ acc [] = (reverse acc, []) go p b c acc s@(ch:chs) | ch == needle && p == 0 && b == 0 && c == 0 = (reverse acc, s) | ch == '(' = go (p + 1) b c (ch:acc) chs | ch == ')' = go (max 0 (p - 1)) b c (ch:acc) chs | ch == '[' = go p (b + 1) c (ch:acc) chs | ch == ']' = go p (max 0 (b - 1)) c (ch:acc) chs | ch == '{' = go p b (c + 1) (ch:acc) chs | ch == '}' = go p b (max 0 (c - 1)) (ch:acc) chs | otherwise = go p b c (ch:acc) chs skipTypeBinder :: String -> String skipTypeBinder raw = case dropWhile isSpace raw of '[':rest -> case balancedContentRest '[' ']' rest of Just (_, after) -> dropWhile isSpace after Nothing -> dropWhile isSpace raw rest -> rest balancedContent :: Char -> Char -> String -> Maybe String balancedContent open close src = fst <$> balancedContentRest open close src balancedContentRest :: Char -> Char -> String -> Maybe (String, String) balancedContentRest open close = go 1 [] where go 0 acc rest = Just (reverse acc, rest) go _ _ [] = Nothing go n acc (ch:chs) | ch == open = go (n + 1) (ch:acc) chs | ch == close = if n == 1 then Just (reverse acc, chs) else go (n - 1) (ch:acc) chs | otherwise = go n (ch:acc) chs trimLeft :: String -> String trimLeft = dropWhile isSpace trim :: String -> String trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace dedup :: [Completion] -> [Completion] dedup = nubBy (\a b -> completionLabel a == completionLabel b) forceCompletions :: [Completion] -> [Completion] forceCompletions xs = sum [ length (completionLabel c) + maybe 0 length (completionDetail c) + kindCode (completionKind c) | c <- xs ] `seq` xs where kindCode CompletionField = 1 kindCode CompletionMethod = 2 kindCode CompletionProperty = 3 kindCode CompletionValue = 4 kindCode CompletionKeyword = 5 forceSignatures :: [CallSignature] -> [CallSignature] forceSignatures xs = sum [ length (callSignatureLabel sig) + callSignatureActiveParameter sig + sum (map (length . signatureParameterLabel) (callSignatureParameters sig)) | sig <- xs ] `seq` xs forceMaybeHover :: Maybe HoverInfo -> Maybe HoverInfo forceMaybeHover info = case info of Nothing -> Nothing Just hover -> length (hoverLabel hover) + length (hoverDetail hover) + maybe 0 length (hoverDocumentation hover) `seq` info (<|>) :: Maybe a -> Maybe a -> Maybe a Nothing <|> b = b a <|> _ = a ================================================ FILE: compiler/lib/src/Acton/Converter.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances, FlexibleContexts #-} module Acton.Converter where import Pretty import Utils import Acton.Syntax import Acton.Names import Acton.Builtin import Acton.Prim import Acton.NameInfo import Acton.Env import Acton.Subst import Acton.TypeEnv import qualified Data.Map.Strict as Map import Data.Map.Strict (Map) pruneStmts xs (Signature l ns t d : ss) | null ns' = pruneStmts xs ss | otherwise = Signature l ns' t d : pruneStmts xs ss where ns' = ns `intersect` xs pruneStmts xs (Decl l ds : ss) | null ds' = pruneStmts xs ss | otherwise = Decl l ds' : pruneStmts xs ss where ds' = filter ((`elem`xs) . dname) ds pruneStmts xs (s@Assign{} : ss) | null ns = pruneStmts xs ss | otherwise = s : pruneStmts xs ss where ns = bound s `intersect` xs pruneStmts xs (s : ss) = s : pruneStmts xs ss pruneStmts xs [] = [] pruneBody env n ss = pruneStmts xs ss where xs = directAttrs env n convProtocol env n0 q ps0 eq wmap b = mainClass : sibClasses where ps = trim ps0 q1 = qSelf' : noqual env q p0 = TC (NoQ n0) $ map tVar $ qbound q t0 = tCon $ convProto p0 w0 = witAttr (NoQ n0) main = head bases bases = [ convProto p | (ws,p) <- ps0, null (catRight ws) ] ++ [cValue] immsibs = [ (witAttr w, tCon $ convProto p, inherited ws0) | ([w],ws0,p) <- ps ] mainClass = --trace ("### MRO for " ++ prstr n0 ++ ": " ++ prstrs ps0) $ --trace (" # SIBS for " ++ prstr n0 ++ ": " ++ prstrs [ sibName ws n0 | (ws,_,_,_,_) <- allsibs ]) $ Class NoLoc n0 q1 bases mainClassBody Nothing where mainClassBody = qsigs ++ psigs ++ bindWits eq ++ Decl NoLoc [mainInit] : convStmts tSelf' eq1 (pruneBody env (NoQ n0) b) psigs = [ Signature NoLoc [n] (monotype t) Property | (n,t,False) <- immsibs ] mainInit = Def NoLoc initKW [] mainParams KwdNIL (Just tNone) (mkBody mainInitBody) NoDec fxPure Nothing mainParams = wit2par ((selfKW',tSelf) : qpars ++ [ (n,t) | (n,t,_) <- immsibs ]) PosNIL mainInitBody = bindWits eq0 ++ initCall (tcargs main) mainArgs main ++ mainCopies mainArgs = witArgs (tcname main) wmap ++ [ eVar n | (n,_,True) <- immsibs ] mainCopies = qcopies ++ [ MutAssign NoLoc (eDot (eVar selfKW') n) (eVar n) | (n,t,False) <- immsibs ] eq0 = mkEqn env (tvarWit tvSelf p0) t0 (eVar selfKW') : [] eq1 = mkEqn env (tvarWit tvSelf p0) t0 (eVar selfKW') : qcopies' allsibs = [ sib ws ws0 p | (ws,ws0,p) <- ps, not (null ws) ] where sib ws ws0 p = (ws, tcname p, us, witArgs w0 wmap, inherited ws0) where us = us0 ++ us1 us1 = [ convProto p | (ws',p) <- ps0, catRight ws' == ws ] ++ [cValue] us0 = [ TC (baseGName w) (tcargs $ head us1) | w <- zipWith (:) (wheads ws0) (wtails ws0) ] w0 = if inherited ws0 then tcname main else tcname p sibClasses = [ Class NoLoc (sibName ws n0) q1 us (sibClassBody ws n (head us) wes inh) Nothing | (ws,n,us,wes,inh) <- allsibs ] sibClassBody ws n p wes inh = qsigs ++ psigs ++ bindWits eq ++ Decl NoLoc [sibInit] : convStmts tSelf' eq1 (pruneBody env n b) where sibInit = Def NoLoc initKW [] sibParams KwdNIL (Just tNone) (mkBody sibInitBody) NoDec fxPure Nothing sibParams = wit2par ((selfKW',tSelf) : qpars ++ sibSubParams ++ sibCtxt) PosNIL sibCtxt = witCtxt ps ws ++ [(w0,t0)] sibInitBody = bindWits eq0 ++ initCall (tcargs p) (wes ++ sibSubArgs ++ sibCtxtArgs) p ++ sibCopies sibCopies = qcopies ++ [ MutAssign NoLoc (eDot (eVar selfKW') w0) (eVar w0) ] sibSubParams = [ (witAttr (last ws'), tCon $ convProto p') | (ws',_,p') <- ps, truePrefix ws ws' ] sibSubArgs = [ eVar (witAttr (last ws')) | (ws',_,p') <- ps, truePrefix ws ws' ] sibCtxtArgs = (if inh then id else init) [ eVar n | (n,t) <- sibCtxt ] eq0 = mkEqn env (tvarWit tvSelf p0) t0 (eVar w0) : [] eq1 = mkEqn env (tvarWit tvSelf p0) t0 (eDot (eVar selfKW') w0) : qcopies' qsigs = [ Signature NoLoc [qualAttr p v n0] (monotype $ proto2type (tVar v) p) Property | (v,p) <- quals env q ] psigs = [ Signature NoLoc [w0] (monotype t0) Property ] qpars = [ (tvarWit v p, proto2type (tVar v) p) | (v,p) <- quals env q ] qcopies = [ MutAssign NoLoc (eDot (eVar selfKW') $ qualAttr p v n0) (eVar $ tvarWit v p) | (v,p) <- quals env q ] qcopies' = [ mkEqn env (tvarWit v p) (proto2type (tVar v) p) (eDot (eVar selfKW') $ qualAttr p v n0) | (v,p) <- quals env q ] inherited (Left _ : _) = True inherited _ = False wtails (w:ws) | null ws' = [] | otherwise = ws' : wtails ws where ws' = catRight ws wheads (Right w:ws) | null $ catRight ws = [] | otherwise = w : wheads ws wheads (Left w:ws) = w : wheads ws groupBranch ([],_) m = m groupBranch p@(w:_,_) m = Map.insertWith (++) w [p] m convExtension env n1 c0 q ps0 eq wmap b opts = mainClass : sibClasses where pss = Map.elems $ foldr groupBranch Map.empty ps0 ps = trim ps0 q1 = noqual env q tvs = map tVar $ qbound q1 t0 = tCon c0 w0 = witAttr (tcname main) ts = tcargs main main = head bases bases = [ instProto t0 p | (ws,p) <- ps0, null (catRight ws) ] ++ [cValue] mainClass = --trace ("### mro for " ++ prstr n1 ++ ": " ++ prstrs ps0) $ --trace ("### branches for " ++ prstr n1 ++ "\n" ++ render (nest 4 $ vcat [ commaSep pretty ps1 | ps1 <- pss ])) $ --trace (" # sibs for " ++ prstr n1 ++ ": " ++ prstrs [ sibName ws n1 | (ws,_,_,_,_) <- allsibs ]) $ Class NoLoc n1 q1 bases mainClassBody Nothing where mainClassBody = qsigs ++ bindWits eq ++ Decl NoLoc [mainInit] : convStmts t0 eq1 (pruneBody env (tcname main) b) mainInit = Def NoLoc initKW [] mainParams KwdNIL (Just tNone) (mkBody mainInitBody) NoDec fxPure Nothing mainParams = wit2par ((selfKW',tSelf) : qpars ++ optpars) PosNIL optpars = [ (witAttr (NoQ n), tCon (TC (NoQ n) (map tVar $ qbound q1))) | n <- opts ] mainInitBody = bindWits eq0 ++ initCall ts (witArgs (tcname main) wmap ++ sibSubs []) main ++ qcopies eq0 = mkEqn env thisKW' (tCon main) (eVar selfKW') : [] eq1 = mkEqn env thisKW' (tCon main) (eVar selfKW') : qcopies' allsibs = [ sib ws ws0 p | (ws,ws0,p) <- ps, not (null ws) ] where sib ws ws0 p = (ws, tcname p, us, witArgs w0 wmap, inherited ws0) where us = us0 ++ us1 us1 = [ instProto t0 p | (ws',p) <- ps0, catRight ws' == ws ] ++ [cValue] us0 = [ TC (baseGName w) (tcargs $ head us1) | w <- zipWith (:) (wheads ws0) (wtails ws0) ] w0 = if inherited ws0 then tcname main else tcname p sibClasses = [ Class NoLoc (sibName ws n1) q1 us (sibClassBody ws n (head us) wes inh) Nothing | (ws,n,us,wes,inh) <- allsibs ] sibClassBody ws n p wes inh = qsigs ++ bindWits eq ++ Decl NoLoc [sibInit] : convStmts t0 eq1 (pruneBody env n b) where sibInit = Def NoLoc initKW [] sibParams KwdNIL (Just tNone) (mkBody sibInitBody) NoDec fxPure Nothing sibParams = wit2par ((selfKW',tSelf) : qpars ++ sibCtxt) PosNIL sibCtxt = witCtxt ps ws ++ [(w0,tCon main)] sibInitBody = bindWits eq0 ++ initCall ts (wes ++ sibSubs ws ++ sibArgs ws) p ++ qcopies eq0 = mkEqn env thisKW' (tCon main) (eVar w0) : [] eq1 = mkEqn env thisKW' (tCon main) (eDot (eVar selfKW') w0) : qcopies' sibSubs ws = [ eCall (tApp (eVar $ sibName ws' n1) tvs) (qargs ++ eVar selfKW' : sibArgs ws) | (ws',_,p') <- ps, truePrefix ws ws' ] sibArgs [] = [] sibArgs ws = map eVar (map witAttr $ init ws) ++ [eVar w0] qsigs = [ Signature NoLoc [qualAttr p v n1] (monotype $ proto2type (tVar v) p) Property | (v,p) <- quals env q ] qpars = [ (tvarWit v p, proto2type (tVar v) p) | (v,p) <- quals env q ] qargs = [ eVar n | (n,p) <- qpars ] qcopies = [ MutAssign NoLoc (eDot (eVar selfKW') $ qualAttr p v n1) (eVar $ tvarWit v p) | (v,p) <- quals env q ] qcopies' = [ mkEqn env (tvarWit v p) (proto2type (tVar v) p) (eDot (eVar selfKW') $ qualAttr p v n1) | (v,p) <- quals env q ] trim ps0 = nubBy eqWit [ (catRight ws0, ws0, p) | (ws0,p) <- ps0 ] where eqWit (ws1,_,_) (ws2,_,_) = ws1 == ws2 truePrefix pre ws | Just [_] <- stripPrefix pre ws = True | otherwise = False witCtxt ps ws = ctxt $ tail $ reverse ws where ctxt [] = [] ctxt (w:ws) = (witAttr w, fromJust $ lookup (w:ws) typemap) : ctxt ws typemap = [ (reverse ws, tCon $ convProto p) | (ws,_,p) <- ps ] initCall ts args p | tcname p == qnValue = [] | otherwise = [Expr NoLoc (eCall (tApp (eDot (eQVar (tcname p)) initKW) ts) (eVar selfKW' : args))] witArgs w wmap = case lookup w wmap of Just es -> es Nothing -> [] -- must be 'value' -- Nothing -> trace ("##### wmap empty for " ++ prstrs ws) [] noqual env q = [ QBind v (filter (not . isProto env . tcname) us) | QBind v us <- q ] quals env q = [ (v, p) | QBind v ps <- q, p <- ps, isProto env (tcname p) ] qualAttr p v n = Derived (tvarWit v p) n sibName ws n = Derived (baseName ws) n baseName [w] = deriveQ w baseName (w : ws) = Derived (baseName ws) (deriveQ w) baseGName ws = modOf (head ws) $ baseName ws modOf (NoQ _) = NoQ modOf (QName m _) = QName m modOf (GName m _) = GName m convProto (TC n ts) = TC n (tSelf' : convSelf tSelf' ts) instProto t (TC n ts) = TC n (t : convSelf t ts) selfpar = TV KType g_self tSelf' = tVar selfpar qSelf' = QBind selfpar [] convSelf t0 t = vsubst [(tvSelf, t0)] t convStmts t0 eq stmts = map conv stmts where conv (Signature l ns sc Static) = Signature l ns (convSelf t0 sc) NoDec conv (Signature l ns sc _) = Signature l ns (convSelf t0 $ convS sc) NoDec conv (Decl l ds) = Decl l (map convD ds) conv s = s convS (TSchema l q t) = TSchema l (q) (convT t) convT (TFun l fx p k t) = TFun l fx (posRow (tVar tvSelf) p) k t convT t = t convD (Def l n q p k t b _ x ddoc) = Def l n (convSelf t0 q) (wit2par [(selfKW',tSelf)] $ convSelf t0 p) (convSelf t0 k) (convSelf t0 t) b' NoDec x ddoc where b' = bindWits eq ++ b convD d = d fixupSelf (Decl l ds) = Decl l (map fixup ds) where fixup c@Class{} = c{ dbody = map fixupSelf (dbody c) } fixup d@Def{pos = PosPar n t e p} | n == selfKW' = d{ pos = PosPar n t e (fix p), kwd = fix (kwd d), ann = fix (ann d), dbody = fix (dbody d) } fixup d = d fix x = convSelf tSelf' x fixupSelf s = s -- Convert a TEnv ------------------------------------------------------------------------------------------- convEnvProtos env = mapModules conv env where conv env1 m (n, NDef sc d doc) = [(n, NDef (convS sc) d doc)] conv env1 m (n, NSig sc d doc) = [(n, NSig (convS sc) d doc)] conv env1 m (n, NAct q p k te doc) = [(n, NAct (noqual env q) (qualWRow env q p) k (concat $ map (conv env m) te) doc)] conv env1 m ni@(n, NProto q us te doc) = map (fromClass env) $ convProtocol (define [ni] env) n q us [] [] (fromTEnv te) conv env1 m ni@(n, NExt q c us te opts doc) = map (fromClass env) $ convExtension (define [ni] env) n c q us [] [] (fromTEnv te) opts conv env1 m (n, NClass q us te doc) = [(n, NClass (noqual env q) us (convClassTEnv env q te) doc)] conv env1 m ni = [ni] convS (TSchema l q t) = TSchema l (noqual env q) (convT q t) convT q (TFun l x p k t) = TFun l x (qualWRow env q p) k t convT q t = t fromClass env (Class _ n q us b ddoc) = (n, NClass q (leftpath us) (fromStmts env b) ddoc) fromStmts env (Signature _ ns sc d : ss)= [ (n, NSig (convS sc) d Nothing) | n <- ns ] ++ fromStmts env ss where convS (TSchema l q t) = TSchema l (noqual env q) (convT q t) convT q (TFun l x p k t) = TFun l x (qualWRow env q p) k t convT q t = t fromStmts env (Decl _ ds : ss) = fromDefs env ds ++ fromStmts env ss fromStmts env (Assign _ [PVar _ n (Just t)] _ : ss) = (n, NVar t) : fromStmts env ss fromStmts env (_ : ss) = fromStmts env ss fromStmts env [] = [] fromDefs env (Def l n q p k a _ d fx ddoc : ds) = (n, NDef (TSchema NoLoc q (TFun NoLoc fx (prowOf' p d) (krowOf k) (fromJust a))) d ddoc) : fromDefs env ds where prowOf' p Static = prowOf p prowOf' (PosPar _ _ _ p) _ = prowOf p fromDefs env (_ : ds) = fromDefs env ds fromDefs env [] = [] fromTEnv ((n, NSig sc dec doc) : te) = Signature NoLoc [n] sc dec : fromTEnv te fromTEnv ((n, NDef sc dec doc) : te) = Decl NoLoc [def] : fromTEnv te where TSchema _ q (TFun _ fx p k t) = sc def = Def NoLoc n q (pPar' dec p) (kPar attrKW k) (Just t) [sNotImpl] dec fx doc pPar' Static p = pPar pNames p pPar' _ p = pPar pNames (posRow tSelf p) fromTEnv ((n, NVar t) : te) = sAssign (pVar n t) eNotImpl : fromTEnv te fromTEnv (_ : te) = fromTEnv te fromTEnv [] = [] convClassTEnv env q0 te = [ conv n i | (n,i) <- te ] where conv n (NSig sc dec doc) = (n, NSig (convS n dec sc) dec doc) conv n (NDef sc dec doc) = (n, NDef (convS n dec sc) dec doc) conv n i = (n, i) convS n dec (TSchema l q t) | n==initKW || dec==Static = TSchema l (noqual env q) (convT (q0++q) t) | otherwise = TSchema l (noqual env q) (convT q t) convT q (TFun l x p k t) = TFun l x (qualWRow env q p) k t convT q t = t {- f : [A(Eq),B,C(Ord)] => (A,B) -> C f : [A,B,C] => (Eq[A],Ord[C],A,B) -> C class c[A(Eq),B] (b[A]): class c[A,B] (b[A]): f : [C(Ord)] => (A,B) -> C f : [C] => (Eq[A],Ord[C],A,B) -> C @static @static g : [C(Ord)] => (Self,Self) -> C g : [C] => (Eq[A],Ord[C],Self,Self) -> C protocol p[A(Eq),B] (q[A]): class p[S,A,B] (q[S,A]): f : [C(Ord)] => (A,B) -> C __init__ : (Eq[A]) -> None @static f : [C] => (S,Ord[C],A,B) -> C g : [C(Ord)] => (Self,Self) -> C g : [C] => (Ord[C],S,S) -> C extension c[A(Eq),B] (p[A,B]): class p$c[A,B] (p[c[A,B],A,B]): ... __init__ : (Eq[A]) -> None actor[ a[A(Eq),B] (b[A]): class a[A,B] ($Actor[]): f : [C(Ord)] => action(A,B) -> C __init__ : (Eq[A],b[A]) -> None f : [C] => action(Ord[C],A,B) -> C f$local : [C] => proc(Ord[C],A,B) -> C -} ================================================ FILE: compiler/lib/src/Acton/Deactorizer.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances #-} module Acton.Deactorizer where import Acton.Syntax import Acton.Names import Acton.Subst import Acton.Prim import Acton.Builtin import Acton.NameInfo import Acton.QuickType import Acton.Env import Acton.Transform import Utils import Pretty import Control.Monad.State.Strict deactorize :: Env0 -> Module -> IO (Module, Env0) deactorize env0 (Module m imps mdoc b) = return (Module m imps mdoc (runDeactM $ deactSuite env b), mapModules conv env0) where env = deactEnv env0 -- Deactorizing monad type DeactM a = State DeactState a type DeactState = [Int] runDeactM :: DeactM a -> a runDeactM m = evalState m [1..] type DeactEnv = EnvF DeactX data DeactX = DeactX { wrappedX :: [Name], stvarsX :: [Name], localsX :: [Name], sampledX :: [Name] } deactEnv :: Env0 -> DeactEnv deactEnv env0 = setX env0 DeactX{ wrappedX = [], stvarsX = [], localsX = [], sampledX = [] } defineAndShadow :: TEnv -> DeactEnv -> DeactEnv defineAndShadow te env = modX (define te env) $ \x -> x{ wrappedX = wrapped env \\ ns, localsX = locals env \\ ns } where ns = dom te wrapped env = wrappedX $ envX env stvars env = stvarsX $ envX env locals env = localsX $ envX env sampled env = sampledX $ envX env setActor wrapped stvars locals env = modX env $ \x -> x{ wrappedX = wrapped, stvarsX = stvars, localsX = locals, sampledX = [] } setSampled ns env = modX env $ \x -> x{ sampledX = ns ++ sampled env } clearSampled env = modX env $ \x -> x{ sampledX = [] } -- Deactorize actor declarations ----------------------------------------------------------------------- class Deact a where deact :: DeactEnv -> a -> DeactM a instance Deact a => Deact (Maybe a) where deact env = traverse (deact env) instance Deact a => Deact [a] where deact env = traverse (deact env) deactSuite env [] = return [] deactSuite env (s : ss) = do s' <- deact (setSampled ns env) s ss' <- deactSuite env1 ss return (samples ++ s' : ss') where env1 = define (envOf s) env ns = nub $ stvars env `intersect` lamfree s samples = [ sAssign (pVar n $ typeOf env (eVar n)) (eDot (eVar selfKW) n) | n <- ns ] instance Deact Stmt where deact env s@(Expr _ (NotImplemented _)) = return s deact env (Expr l (Call l' e p KwdNil)) | fx == fxAction = Expr l <$> (Call l' <$> deact env (eAsync e) <*> deact env p <*> pure KwdNil) where TFun{effect=fx} = typeOf env e deact env (Expr l e) = Expr l <$> deact env e deact env (Assign l [p@(PVar _ n _)] e) | n `elem` locals env = MutAssign l (selfRef n) <$> deact env e | otherwise = Assign l [p] <$> deact env e where t = typeOf env p deact env (MutAssign l tg e) = MutAssign l <$> deact env tg <*> deact env e where t = typeOf env tg deact env (Pass l) = return $ Pass l deact env (Return l Nothing) = return $ Return l Nothing deact env (Return l (Just e)) = Return l . Just <$> deact env e deact env (Break l) = return $ Break l deact env (Continue l) = return $ Continue l deact env (If l bs els) = If l <$> deact env bs <*> deactSuite env1 els where env1 = clearSampled env deact env (While l e b els) = While l <$> deact env e <*> deactSuite env1 b <*> deactSuite env1 els where env1 = clearSampled env deact env (VarAssign l [p@(PVar _ n _)] e) = MutAssign l (selfRef n) <$> deact env e where t = typeOf env p deact env (After l e1 e2) = do delta <- deact env e1 lambda <- deact env $ Lambda l0 PosNIL KwdNIL e2 fxProc return $ Expr l $ Call l0 (tApp (eQVar primAFTERf) [t2]) (PosArg delta $ PosArg lambda PosNil) KwdNil where t2 = typeOf env e2 t = tFun fxProc posNil kwdNil t2 deact env (Decl l ds) = do ds1 <- deact env1 ds return $ Decl l $ ds1 ++ [ newact env1 n q p Nothing | Actor _ n q p _ _ _ <- ds, not $ abstractActor env1 (NoQ n) ] where env1 = define (envOf ds) env deact env (Signature l ns t d) = return $ Signature l ns t d deact env s = error ("deact unexpected stmt: " ++ prstr s) instance Deact Decl where deact env (Actor l n q params KwdNIL body ddoc) = do inits1 <- deactSuite (define (envOf decls) env1) inits decls1 <- deactSuite (define (envOf inits) env1) decls let _init_ = Def l0 initKW [] (addSelfPar params) KwdNIL (Just tNone) (mkBody $ copies++inits1) NoDec fxProc Nothing decls2 = [ Decl l $ map deactMeth ds | Decl l ds <- decls1 ] return $ Class l n q [TC primActor [], cValue] (propsigs ++ [Decl l0 [_init_]] ++ decls2 ++ wraps) ddoc where env1 = setActor wrapped stvars locals $ define (envOf params) $ define [(selfKW, NVar t0)] $ defineTVars q env t0 = tCon $ TC (NoQ n) (map tVar $ qbound q) (decls,ss) = partition isDecl body inits = filter (not . isSig) ss stvars = statevars body fvs = free decls live_vars | hasNotImpl body = bound params ++ dom (envOf inits) | otherwise = bound params `intersect` fvs ++ [ n | n <- dom $ envOf inits, not (isHidden n) || n `elem` (stvars++fvs) ] locals = nub $ live_vars ++ bound decls wrapped = bound wrapdefs wrapdefs = [ d | Decl _ ds <- decls, d@Def{dname=n, dfx=fx} <- ds, fx == fxProc || fx == fxAction ] propsigs = [ Signature l0 [n] (monotype t) Property | (n,t) <- concat $ props' params : map props inits ] props (VarAssign _ p _) = [ (n, t) | PVar _ n (Just t) <- p ] props (Assign _ p _) = [ (n, t) | PVar _ n (Just t) <- p, n `elem` locals ] props (If _ bs els) = restrict (concat $ map props els) (foldr1 intersect [ assigned b | Branch _ b <- bs ]) props _ = [] props' (PosPar n a _ p) | n `elem` locals = (n, fromJust a) : props' p | otherwise = props' p props' (PosSTAR n a) | n `elem` locals = [(n, fromJust a)] props' _ = [] copies = [ MutAssign l0 (selfRef n) (Var l0 (NoQ n)) | n <- bound params, n `elem` locals ] deactMeth (Def l n q p KwdNIL t b d fx ddoc) = Def l n' q (addSelfPar p) KwdNIL t b d fx ddoc where n' = if n `elem` wrapped then localName n else n wraps = [ wrap n q p t | Def _ n q p KwdNIL (Just t) _ _ _ _ <- wrapdefs ] wrap n q p t = Decl l0 [Def l0 n q (addSelfPar p) KwdNIL (Just t) [ret] NoDec fxAction Nothing] where ret = sReturn $ eCall (tApp (eQVar primASYNCf) [t]) [self,lam] lam = Lambda l0 PosNIL KwdNIL (eCallP (tApp (eDot self $ localName n) (map tVar $ qbound q)) (pArg p)) fxProc self = eVar selfKW deact env (Def l n q p KwdNIL (Just t) b d fx ddoc) = do b <- deactSuite env1 b return $ Def l n q p KwdNIL (Just t) b d fx ddoc where env1 = defineAndShadow (envOf p) $ defineTVars q env deact env (Class l n q u b ddoc) = Class l n q u <$> deactSuite env1 b <*> pure ddoc where env1 = defineTVars (selfQuant (NoQ n) q) env deact env d = error ("deact unexpected decl: " ++ prstr d) newact env n q p ddoc = Def l0 (newactName n) q p KwdNIL (Just t) [newassign, install_gc_finalizer, waitinit, sReturn x] NoDec fxProc ddoc where t = tCon $ TC (NoQ n) (map tVar $ qbound q) x = eVar g_act newassign = sAssign (pVar g_act t) (eCall (tApp (eQVar primNEWACTOR) [t]) []) install_gc_finalizer = sExpr $ eCall (tApp (eQVar primInstallFinalizer) [t]) [x] waitinit = sExpr $ eCall (tApp (eQVar primAWAITf) [tNone]) [asyncmsg] asyncmsg = eCall (tApp (eQVar primASYNCf) [tNone]) [x, closure] closure = Lambda l0 PosNIL KwdNIL initcall fxProc initcall = Call l0 (eDot x initKW) (pArg p) KwdNil newactQName (QName m n) = QName m (newactName n) newactQName (NoQ n) = NoQ (newactName n) newactQName (GName m n) = GName m (newactName n) qnName :: QName -> Name qnName (NoQ n) = n qnName (QName _ n) = n qnName (GName _ n) = n addSelfPar p = PosPar selfKW (Just tSelf) Nothing p selfRef n = Dot l0 (Var l0 (NoQ selfKW)) n -- $ASYNCf : [A] => action($Actor, proc()->A) -> Msg[A] -- $AFTERf : [A] => proc(int, proc()->A) -> Msg[A] -- $AWAITf : [A] => proc(Msg[A]) -> A instance Deact Branch where deact env (Branch e ss) = Branch <$> deact env e <*> deactSuite env1 ss where env1 = clearSampled env isProcMeth env e | Just n <- isQVar e, NDef sc _ _ <- findQName n env, TFun{effect=fx} <- sctype sc = fx == fxProc isProcMeth env _ = False sealedMeth env e | Just n <- isVar e, n `elem` wrapped env = Just n sealedMeth env _ = Nothing instance Deact Expr where deact env (Var l (NoQ n)) | n `elem` sampled env = return $ Var l (NoQ n) | n `elem` locals env = return $ Dot l (Var l (NoQ selfKW)) n' where n' = if n `elem` wrapped env then localName n else n deact env (Var l n) | isActor env n = return $ Var l $ newactQName (unalias env n) | otherwise = return $ Var l n deact env (Async l e) = Async l <$> deact env e deact env (Await l e) = do e' <- deact env e return $ Call l (tApp (eQVar primAWAITf) ts) (PosArg e' PosNil) KwdNil where TCon _ msg = typeOf env e ts = tcargs msg deact env (Int l i s) = return $ Int l i s deact env (Float l f s) = return $ Float l f s deact env (Imaginary l i s) = return $ Imaginary l i s deact env (Bool l b) = return $ Bool l b deact env (None l) = return $ None l deact env (NotImplemented l) = return $ NotImplemented l deact env (Ellipsis l) = return $ Ellipsis l deact env (Strings l s) = return $ Strings l s deact env (BStrings l s) = return $ BStrings l s deact env (Call l e as KwdNil) = deactCall env True l e as deact env (TApp l e ts) = TApp l <$> deact env e <*> pure ts deact env (Let l ss e) = Let l <$> deact env1 ss <*> deact env1 e where env1 = define (envOf ss) env deact env (Cond l e1 e e2) = Cond l <$> deact env e1 <*> deact env e <*> deact env e2 deact env (IsInstance l e c) = IsInstance l <$> deact env e <*> return c deact env (BinOp l e1 Or e2) = BinOp l <$> deact env e1 <*> pure Or <*> deact env e2 deact env (BinOp l e1 And e2) = BinOp l <$> deact env e1 <*> pure And <*> deact env e2 deact env (UnOp l Not e) = UnOp l Not <$> deact env e deact env (Dot l e nm) = Dot l <$> deact env e <*> return nm deact env (DotI l e i) = DotI l <$> deact env e <*> return i deact env (RestI l e i) = RestI l <$> deact env e <*> return i deact env (Lambda l p KwdNIL e fx) | Call l' e' as KwdNil <- e = Lambda l p KwdNIL <$> deactCall env1 False l' e' as <*> return fx | otherwise = Lambda l p KwdNIL <$> deact env1 e <*> return fx where env1 = defineAndShadow (envOf p) env deact env (Yield l e) = Yield l <$> deact env e deact env (YieldFrom l e) = YieldFrom l <$> deact env e deact env (Tuple l es KwdNil) = Tuple l <$> deact env es <*> pure KwdNil deact env (List l es) = List l <$> deact env es deact env (Dict l as) = Dict l <$> deact env as deact env (Set l es) = Set l <$> deact env es deact env e = error ("deact unexpected expr: " ++ prstr e) deactCall env unwrap l (TApp _ (Var _ n) ts) (PosArg self (PosArg e PosNil)) | n == primWRAP, Just n' <- sealedMeth env e = return $ Dot l (Var l (NoQ selfKW)) n' | n == primWRAP = do e <- deact env e self <- deact env self let lam = Lambda l0 PosNIL KwdNIL (eCallP e (pArg ps)) fxProc return $ Lambda l0 ps KwdNIL (eCall (tApp (eQVar primASYNCf) [t]) [self,lam]) fxAction where TFun _ fx p _ t = typeOf env e ps = pPar paramNames p deactCall env unwrap l e as | fx == fxAction && unwrap = deact env (eAwait $ Call l (eAsync e) as KwdNil) | otherwise = do e <- deact env e as <- deact env as case e of Lambda _ ps KwdNIL e' _ | Just s <- pzip ps as -> return $ termsubst s e' _ -> return $ Call l e as KwdNil where TFun{effect=fx} = typeOf env e instance Deact PosArg where deact env (PosArg e p) = PosArg <$> deact env e <*> deact env p deact env PosNil = return PosNil instance Deact Elem where deact env (Elem e) = Elem <$> deact env e deact env (Star e) = Star <$> deact env e instance Deact Assoc where deact env (Assoc k v) = Assoc <$> deact env k <*> deact env v deact env (StarStar e) = StarStar <$> deact env e -- Variables free in a lambda ----------------------------------------------------------------------------------- class LambdaFree a where lamfree :: a -> [Name] instance (LambdaFree a) => LambdaFree [a] where lamfree = concat . map lamfree instance (LambdaFree a) => LambdaFree (Maybe a) where lamfree = maybe [] lamfree instance LambdaFree Stmt where lamfree (Expr _ e) = lamfree e lamfree (Assign _ p e) = lamfree e lamfree (MutAssign _ t e) = lamfree t ++ lamfree e lamfree (Return _ e) = maybe [] lamfree e lamfree (If _ bs els) = concat [ lamfree e | Branch e ss <- bs ] lamfree (While _ e b els) = lamfree e lamfree (VarAssign _ p e) = lamfree e lamfree (After l e1 e2) = lamfree e1 ++ free e2 -- deact will turn e2 into a lambda lamfree _ = [] instance LambdaFree Expr where lamfree (Await _ e) = lamfree e lamfree (Call _ e ps KwdNil) = lamfree e ++ lamfree ps lamfree (TApp _ e ts) = lamfree e lamfree (Cond _ e1 e e2) = lamfree e1 ++ lamfree e ++ lamfree e2 lamfree (IsInstance _ e c) = lamfree e lamfree (BinOp _ e1 Or e2) = lamfree e1 ++ lamfree e2 lamfree (BinOp _ e1 And e2) = lamfree e1 ++ lamfree e2 lamfree (UnOp _ Not e) = lamfree e lamfree (Dot _ e n) = lamfree e lamfree (DotI _ e i) = lamfree e lamfree (RestI _ e i) = lamfree e lamfree (Yield _ e) = lamfree e lamfree (YieldFrom _ e) = lamfree e lamfree (Tuple _ p k) = lamfree p ++ lamfree k lamfree (List _ es) = lamfree es lamfree e@Lambda{} = free e -- Free in lambda! lamfree _ = [] instance LambdaFree PosArg where lamfree (PosArg e p) = lamfree e ++ lamfree p lamfree PosNil = [] instance LambdaFree KwdArg where lamfree (KwdArg n e k) = lamfree e ++ lamfree k lamfree KwdNil = [] instance LambdaFree Elem where lamfree (Elem e) = lamfree e -- Convert types and environments ----------------------------------------------------------------------- conv env m (n, NAct q p k te' doc) = (n, NClass q (leftpath [TC primActor [], cValue]) (convActorEnv q p k te') doc) : (newactName n, NDef (tSchema q (tFun fxProc p k t)) NoDec Nothing) : [] where convActorEnv q0 p k te' = (initKW, NDef t0 NoDec Nothing) : te' where t0 = tSchema q0 (tFun fxProc p k tNone) t = tCon $ TC (GName m n) (map tVar $ qbound q) conv env m ni = [ni] ================================================ FILE: compiler/lib/src/Acton/Diagnostics.hs ================================================ {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- | Bridge between Acton error representations and the diagnose pretty-printing library module Acton.Diagnostics where import Error.Diagnose.Diagnostic import Error.Diagnose.Report import Error.Diagnose.Position import Error.Diagnose.Style import Error.Diagnose (addReport, addFile, printDiagnostic, prettyDiagnostic) import Error.Diagnose.Report (Note(..)) import Data.List (intersperse, isPrefixOf, isInfixOf, intercalate) import Data.Maybe (fromMaybe) import Control.Exception (Exception(..), SomeException) import qualified Data.List.NonEmpty as NE import Text.Read (readMaybe) import Data.Char (isDigit, isSpace) import qualified Data.Set as S import Text.Megaparsec (PosState(..), reachOffset) import Text.Megaparsec.Error (ParseErrorBundle(..), parseErrorPretty, bundleErrors, errorBundlePretty, ShowErrorComponent(..), ParseError(..), errorOffset, parseErrorTextPretty, ErrorFancy(..)) import Text.Megaparsec.Pos (SourcePos(..), unPos, sourceLine, sourceColumn, mkPos) import qualified Text.Megaparsec.Error as ME import Acton.Syntax import SrcLocation import Utils (SrcLoc(..), loc) import Acton.Parser (CustomParseError(..), CustomParseException(..), ContextError(..), IndentationError(..), ctxMsg) -- Import for custom error types import qualified Utils as U import qualified Acton.Env as Env import Pretty (render, pretty, text, (<+>), (<>), comma, equals) import Prelude hiding ((<>)) -- | Convert CustomParseError to diagnostic components (error message and hints/notes) customParseErrorToDiagnostic :: CustomParseError -> (String, [Note String]) customParseErrorToDiagnostic (TypeVariableNameError name) = ("Invalid name '" ++ name ++ "'", [Note "Single upper case character (optionally followed by digits) are reserved for type variables", Hint "Use a longer name"]) customParseErrorToDiagnostic (InvalidFormatSpecifier spec) = ("Invalid format specifier" ++ if null spec then "" else ": " ++ spec, []) customParseErrorToDiagnostic (TooManyQuotesError quote) = ("Too many quote characters", [Note "Triple-quoted strings accept 3-5 quotes at the end", Hint "Using 4 quotes results in a string with 1 quote at the end, e.g. \"\"\"text\"\"\"\" -> text\"", Hint "Using 5 quotes results in a string with 2 quotes at the end, e.g. \"\"\"text\"\"\"\"\" -> text\"\"", Hint "Use escape sequences for quotes inside strings, e.g. \"\"\"text \\\"with quotes\\\"\"\" -> text \"with quotes\""]) customParseErrorToDiagnostic (MissingClosingQuote quote) = ("Missing closing " ++ quote, [Hint $ "Add a closing quote (" ++ quote ++ ") to match the opening one"]) customParseErrorToDiagnostic InvalidModuleStatement = ("Only declarations and assignments are allowed at the module top level", [Hint "Assign the value to a name or move runtime work into an actor or function"]) customParseErrorToDiagnostic InvalidTopLevelAssignmentPattern = ("Module top-level assignments must bind at least one name", [Note "Module top-level assignments define constants by name", Hint "Bind the value to a name or move the computation into an actor or function"]) customParseErrorToDiagnostic (DuplicateTopLevelAssignment name) = ("Module top-level name '" ++ name ++ "' cannot be assigned more than once", [Note "Module top-level assignments define constants", Hint "Use a fresh name or move mutable state into an actor"]) -- String interpolation errors customParseErrorToDiagnostic EmptyInterpolationExpression = ("Empty expression in string interpolation", [Hint "Add an expression between the braces, e.g. {name}"]) customParseErrorToDiagnostic MissingExpressionBeforeFormat = ("Missing expression before format specifier", [Hint "Add an expression before the colon, e.g. {value:10}"]) customParseErrorToDiagnostic UnclosedInterpolationBrace = ("Missing closing '}' for expression", [Hint "Add a closing brace to complete the interpolation"]) customParseErrorToDiagnostic EmptyFormatSpecifierError = ("Empty format specifier after ':'", [Hint "Add a format specification or remove the colon"]) customParseErrorToDiagnostic TabInFormatSpecifier = ("Tab character not allowed in format specifier", []) customParseErrorToDiagnostic NewlineInFormatSpecifier = ("Newline not allowed in format specifier", [Hint "Keep format specifiers on a single line"]) customParseErrorToDiagnostic (InvalidCharInFormatSpecifier c) = ("Invalid character '" ++ [c] ++ "' in format specifier", [Note "Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters", Hint "Use a format specifier, e.g. '{name:<18}'"]) customParseErrorToDiagnostic MissingFormatPrecisionDigits = ("Expected digits after '.' in format specifier", [Hint "Add precision digits, e.g. .2f for 2 decimal places"]) -- Escape sequence errors customParseErrorToDiagnostic (IncompleteHexEscape c) = ("Incomplete hex character", [Note "Hex-escaped characters must be specified by two hexadecimal digits", Hint "Use two characters, e.g. \\x9a"]) customParseErrorToDiagnostic OctalEscapeOutOfRange = ("Octal escape sequence out of range", [Note "Octal values must be between \\000 and \\377"]) customParseErrorToDiagnostic (IncompleteUnicodeEscape exp found) = ("Incomplete universal character name", [Note $ "Expected " ++ show exp ++ " hex digits, found " ++ show found]) customParseErrorToDiagnostic NonAsciiInBytesLiteral = ("Only ASCII characters allowed in bytes literal", [Hint "Use escape sequences for non-ASCII values"]) customParseErrorToDiagnostic UnknownEscapeSequence = ("Unknown escape sequence", [Note "Valid escape sequences: \\\\, \\\", \\', \\n, \\r, \\t, \\a, \\b, \\f, \\v, \\xHH, \\ooo, \\uHHHH, \\UHHHHHHHH"]) customParseErrorToDiagnostic (OtherError msg) = (msg, []) -- | Convert Megaparsec parse errors to diagnose format -- Handles syntax errors from the parsing phase with rich error information -- like expected/unexpected tokens and parse positions. parseDiagnosticFromBundle :: String -> String -> ParseErrorBundle String CustomParseError -> Diagnostic String parseDiagnosticFromBundle filename src bundle = let -- Extract the first error (most relevant) firstError = NE.head (bundleErrors bundle) -- Get the error offset offset = errorOffset firstError -- Get the position state and calculate source position posState = bundlePosState bundle (_, newPosState) = reachOffset offset posState sourcePos = pstateSourcePos newPosState line = unPos (sourceLine sourcePos) col = unPos (sourceColumn sourcePos) msg = parseErrorTextPretty firstError -- For parse errors, we only have a single position, not a span -- Just highlight one character at the error position -- Create position span position = Position (line, col) (line, col + 1) filename -- Check if this is a custom error and get the text message & hints / notes (prettyMsg, hints) = case firstError of ME.FancyError _ errs -> case findCustomError (S.toList errs) of Just customErr -> customParseErrorToDiagnostic customErr Nothing -> (msg, []) _ -> (msg, []) findCustomError :: [ErrorFancy CustomParseError] -> Maybe CustomParseError findCustomError [] = Nothing findCustomError (ErrorCustom err : _) = Just err findCustomError (_ : rest) = findCustomError rest report = Err (Just "Parse error") msg [(position, This prettyMsg)] hints diagnostic = addReport mempty report in addFile diagnostic filename src -- | Convert CustomParseException to diagnostic format directly -- CustomParseExceptions are essentially an exception container for -- CustomParseError, so extract the error and convert that customParseExceptionToDiagnostic :: String -> String -> CustomParseException -> Diagnostic String customParseExceptionToDiagnostic filename src (CustomParseException loc customErr) = customParseErrorDiagnostic "Syntax error" filename src loc customErr -- | Convert CustomParseError to Diagnostic -- This is used by tests to ensure consistent error formatting customParseErrorDiagnostic :: String -> String -> String -> SrcLoc -> CustomParseError -> Diagnostic String customParseErrorDiagnostic errKind filename src srcLoc customErr = let (msg, hints) = customParseErrorToDiagnostic customErr (line, col, endCol) = case srcLoc of NoLoc -> (1, 1, 2) Loc startOffset endOffset -> let initialState = PosState { pstateInput = src , pstateOffset = 0 , pstateSourcePos = SourcePos filename (mkPos 1) (mkPos 1) , pstateTabWidth = mkPos 8 , pstateLinePrefix = "" } (_, startState) = reachOffset startOffset initialState (_, endState) = reachOffset endOffset initialState startPos = pstateSourcePos startState endPos = pstateSourcePos endState in (unPos (sourceLine startPos), unPos (sourceColumn startPos), unPos (sourceColumn endPos)) position = Position (line, col) (line, endCol) filename report = Err (Just errKind) msg [(position, This msg)] hints diagnostic = addReport mempty report in addFile diagnostic filename src -- | Convert Acton compiler errors to diagnose format -- Classic Acton errors consist of (loc, msg). Wrap in OtherError and convert to -- Diagnostic. -- One day we'll convert everything to more structured errors and get rid of -- this function actErrToDiagnostic errKind filename src srcLoc msg = customParseErrorDiagnostic errKind filename src srcLoc (OtherError msg) ================================================ FILE: compiler/lib/src/Acton/DocPrinter.hs ================================================ -- Copyright (C) 2019-2025 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances #-} module Acton.DocPrinter ( -- * Main documentation functions printAsciiDoc , printMdDoc , printHtmlDoc , generateDocIndex ) where import Utils import Acton.Printer (Pretty(..), Doc, render, text, (<+>), ($+$), (<>), blank, vcat, empty, nest, brackets, parens, colon, comma, punctuate, commaSep, commaList, isEmpty, hcat) import Acton.Syntax import Acton.Builtin (qnList, qnDict, qnSetT, nBuiltin) import Acton.Prim import Acton.NameInfo import Data.List (nub) import Prelude hiding ((<>)) import Data.List (intercalate, intersperse, sortBy) import Data.Ord (comparing) import Data.Char (isDigit) import Data.Set (Set) import qualified Data.Set as Set import System.FilePath ((), (<.>), joinPath) -- | Generate documentation from a module in Markdown format with types docModuleWithTypes :: NameInfo -> Module -> Doc docModuleWithTypes (NModule _ tenv mdocstring) (Module qn _ _ stmts) = -- Use module docstring from NModule let moduleDocstring = mdocstring (title, restDoc) = case moduleDocstring of Just ds -> splitDocstring ds Nothing -> ("", Nothing) header = if null title then text "#" <+> pretty qn else text "#" <+> text "`" <> pretty qn <> text "`:" <+> text title bodyDoc = case restDoc of Just body -> blank $+$ text body $+$ blank Nothing -> empty in header $+$ bodyDoc $+$ blank $+$ docTopLevelWithTypes tenv stmts -- | Split docstring into first line (title) and rest splitDocstring :: String -> (String, Maybe String) splitDocstring s = let ls = lines s in case ls of [] -> ("", Nothing) [l] -> (l, Nothing) (l:rest) -> let remainder = dropWhile null rest -- Skip blank lines after title in if null remainder then (l, Nothing) else (l, Just $ unlines remainder) -- | Extract and document top-level definitions with types docTopLevelWithTypes :: TEnv -> Suite -> Doc docTopLevelWithTypes tenv stmts = let docs = concatMap (extractTopLevelWithTypes tenv) stmts separated = case docs of [] -> [] [d] -> [d] (d:ds) -> d : map (blank $+$ blank $+$) ds in vcat separated -- | Extract documentation-worthy top-level statements with types extractTopLevelWithTypes :: TEnv -> Stmt -> [Doc] extractTopLevelWithTypes tenv (Decl _ decls) = map (docDeclWithTypes tenv) decls extractTopLevelWithTypes tenv (With _ _ body) = concatMap (extractTopLevelWithTypes tenv) body extractTopLevelWithTypes _ _ = [] -- | Extract docstring from NameInfo extractNameDocstring :: NameInfo -> Maybe String extractNameDocstring (NDef _ _ mdoc) = mdoc extractNameDocstring (NSig _ _ mdoc) = mdoc extractNameDocstring (NAct _ _ _ _ mdoc) = mdoc extractNameDocstring (NClass _ _ _ mdoc) = mdoc extractNameDocstring (NProto _ _ _ mdoc) = mdoc extractNameDocstring (NExt _ _ _ _ _ mdoc) = mdoc extractNameDocstring (NModule _ _ mdoc) = mdoc extractNameDocstring _ = Nothing -- | Document a declaration in Markdown format with types docDeclWithTypes :: TEnv -> Decl -> Doc docDeclWithTypes tenv (Def _ n q p k a b d x ddoc) = let -- Look up inferred type information (inferredType, qConstraints, mdocstring) = case lookup n tenv of Just info@(NDef schema _ _) -> (Just schema, getQBindsFromSchema schema, extractNameDocstring info) Just info@(NSig schema _ _) -> (Just schema, getQBindsFromSchema schema, extractNameDocstring info) _ -> (Nothing, [], Nothing) -- Create a mapping from ugly type vars to nice generic names uglyTypeVarsFromQBinds = collectUglyTypeVars qConstraints uglyTypeVarsFromType = case inferredType of Just (TSchema _ _ t) -> collectUglyTypeVarsFromType t _ -> [] allUglyTypeVars = nub (uglyTypeVarsFromQBinds ++ uglyTypeVarsFromType) typeVarMapping = createTypeVarMapping allUglyTypeVars -- Process the type information with cleanup (paramsWithTypes, retType, cleanedQ) = case inferredType of Just (TSchema _ qConstraints (TFun _ _ posRow kwdRow resType)) -> let cleanPosRow = cleanupTypeVars typeVarMapping posRow cleanKwdRow = cleanupTypeVars typeVarMapping kwdRow cleanRetType = cleanupTypeVars typeVarMapping resType cleanConstraints = cleanupQBinds typeVarMapping qConstraints in (enrichParamsMarkdown cleanPosRow cleanKwdRow p k, Just cleanRetType, if null q then cleanConstraints else q) _ -> (docParamsWithTypes p k, a, q) -- Use docstring from AST declaration docstr = case mdocstring of Just ds -> Just ds Nothing -> ddoc -- Use cleaned up constraints for generics display genericsDoc = if null cleanedQ then empty else docGenericsMarkdown cleanedQ header = text "##" <+> text "`" <> pretty n <> text "`" <> genericsDoc <> paramsWithTypes <> docRetTypeFormatted retType docstrDoc = case docstr of Just ds -> blank $+$ text ds Nothing -> empty in header $+$ docstrDoc where isJust (Just _) = True isJust Nothing = False enrichParamsMarkdown :: PosRow -> KwdRow -> PosPar -> KwdPar -> Doc enrichParamsMarkdown posRow kwdRow p k = parens $ enrichPosParamsMarkdown posRow p <> kwdParSepLocal p k <> enrichKwdParamsMarkdown kwdRow k kwdParSepLocal :: PosPar -> KwdPar -> Doc kwdParSepLocal PosNIL KwdNIL = empty kwdParSepLocal PosNIL _ = empty kwdParSepLocal _ KwdNIL = empty kwdParSepLocal _ _ = text ", " enrichPosParamsMarkdown :: PosRow -> PosPar -> Doc enrichPosParamsMarkdown _ PosNIL = empty enrichPosParamsMarkdown posRow (PosPar n t e p) = -- Skip witness parameters if isWitnessParam n then enrichPosParamsMarkdown (advanceRow posRow) p else let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatType paramType <> formatDefault e nextParams = enrichPosParamsMarkdown (advanceRow posRow) p in case p of PosNIL -> param _ -> if isEmpty nextParams then param else param <> comma <+> nextParams enrichPosParamsMarkdown _ (PosSTAR n t) = text "*" <> pretty n <> formatType t enrichKwdParamsMarkdown :: KwdRow -> KwdPar -> Doc enrichKwdParamsMarkdown _ KwdNIL = empty enrichKwdParamsMarkdown kwdRow (KwdPar n t e k) = let inferredType = extractParamTypeFromRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatType paramType <> formatDefault e in case k of KwdNIL -> param _ -> param <> comma <+> enrichKwdParamsMarkdown kwdRow k enrichKwdParamsMarkdown _ (KwdSTAR n t) = text "**" <> pretty n <> formatType t extractParamTypeFromRow :: String -> Type -> Maybe Type extractParamTypeFromRow _ (TNil _ _) = Nothing extractParamTypeFromRow name (TRow _ _ n t rest) | nstr n == name = Just t | otherwise = extractParamTypeFromRow name rest extractParamTypeFromRow _ _ = Nothing advanceRow :: Type -> Type advanceRow (TRow _ _ _ _ rest) = rest advanceRow t = t docDeclWithTypes tenv (Actor _ n q p k b ddoc) = let mdocstring = case lookup n tenv of Just info -> extractNameDocstring info _ -> Nothing -- Use docstring from AST declaration docstr = case mdocstring of Just ds -> Just ds Nothing -> ddoc header = text "##" <+> text "*actor*" <+> text "`" <> pretty n <> text "`" <> docGenerics q <> docParamsWithTypes p k docstrDoc = case docstr of Just ds -> blank $+$ text ds Nothing -> empty in header $+$ docstrDoc docDeclWithTypes tenv (Class _ n q a b ddoc) = let mdocstring = case lookup n tenv of Just info -> extractNameDocstring info _ -> Nothing -- Use docstring from AST declaration docstr = case mdocstring of Just ds -> Just ds Nothing -> ddoc header = text "##" <+> text "*class*" <+> text "`" <> pretty n <> text "`" <> docGenerics q <> docAncestors a docstrDoc = case docstr of Just ds -> blank $+$ text ds Nothing -> empty methods = docClassBodyWithTypes tenv b in header $+$ docstrDoc $+$ (if isEmpty methods then empty else blank $+$ methods) docDeclWithTypes tenv (Protocol _ n q a b ddoc) = let mdocstring = case lookup n tenv of Just info -> extractNameDocstring info _ -> Nothing -- Fall back to extracting from body if not in TEnv docstr = case mdocstring of Just ds -> Just ds Nothing -> ddoc header = text "##" <+> text "*protocol*" <+> text "`" <> pretty n <> text "`" <> docGenerics q <> docAncestors a docstrDoc = case docstr of Just ds -> blank $+$ text ds Nothing -> empty methods = docProtocolBodyWithTypes tenv b in header $+$ docstrDoc $+$ (if isEmpty methods then empty else blank $+$ methods) docDeclWithTypes tenv (Extension _ q c a b ddoc) = let mdocstring = Nothing -- Extensions don't have their own docstrings in TEnv -- Use docstring from AST declaration docstr = ddoc header = text "##" <+> text "*extension*" <+> text "`" <> pretty c <> text "`" <> docGenerics q <> docAncestors a docstrDoc = case docstr of Just ds -> blank $+$ text ds Nothing -> empty in header $+$ docstrDoc -- | Helper functions for Markdown generation docGenerics :: QBinds -> Doc docGenerics [] = empty docGenerics q = brackets (commaList q) -- | Document generics for Markdown format docGenericsMarkdown :: QBinds -> Doc docGenericsMarkdown [] = empty docGenericsMarkdown qbs = brackets $ hcat $ punctuate comma $ map renderQBind qbs where renderQBind (QBind tv []) = pretty (tvname tv) renderQBind (QBind tv constraints) = pretty (tvname tv) <> parens (hcat $ punctuate comma $ map pretty constraints) -- | Document generic constraints in ASCII format (showing type variable names and constraints) docGenericsAscii :: QBinds -> Doc docGenericsAscii [] = empty docGenericsAscii qbs = brackets $ commaList qbs docRetType :: Maybe Type -> Doc docRetType Nothing = empty docRetType (Just t) = text " ->" <+> pretty t docRetTypeFormatted :: Maybe Type -> Doc docRetTypeFormatted Nothing = empty docRetTypeFormatted (Just t) = text " → " <> text "*" <> pretty (SimplifiedType t) <> text "*" docAncestors :: Pretty a => [a] -> Doc docAncestors [] = empty docAncestors as = parens (commaList as) -- | Format parameters with italicized types docParamsWithTypes :: PosPar -> KwdPar -> Doc docParamsWithTypes p k = parens $ docPosParFormatted p <> docKwdParSep p k <> docKwdParFormatted k where docKwdParSep PosNIL KwdNIL = empty docKwdParSep PosNIL _ = empty docKwdParSep _ KwdNIL = empty docKwdParSep _ _ = text ", " docPosParFormatted :: PosPar -> Doc docPosParFormatted PosNIL = empty docPosParFormatted (PosPar n t e p) = let param = pretty n <> formatType t <> formatDefault e in case p of PosNIL -> param _ -> param <> comma <+> docPosParFormatted p docPosParFormatted (PosSTAR n t) = text "*" <> pretty n <> formatType t docKwdParFormatted :: KwdPar -> Doc docKwdParFormatted KwdNIL = empty docKwdParFormatted (KwdPar n t e k) = let param = pretty n <> formatType t <> formatDefault e in case k of KwdNIL -> param _ -> param <> comma <+> docKwdParFormatted k docKwdParFormatted (KwdSTAR n t) = text "**" <> pretty n <> formatType t formatType :: Maybe Type -> Doc formatType Nothing = empty formatType (Just t) = colon <+> text "*" <> pretty (SimplifiedType t) <> text "*" formatDefault :: Maybe Expr -> Doc formatDefault Nothing = empty formatDefault (Just e) = text " = " <> pretty e -- | Document class body with types - extract attributes and methods in Markdown docClassBodyWithTypes :: TEnv -> Suite -> Doc docClassBodyWithTypes tenv stmts = let (attrs, methods) = partitionClassMembersWithTypes tenv stmts attrsDoc = if null attrs then empty else text "**Attributes:**" $+$ blank $+$ vcat (punctuate blank attrs) methodsDoc = if null methods then empty else text "**Methods:**" $+$ blank $+$ vcat (punctuate blank methods) in case (isEmpty attrsDoc, isEmpty methodsDoc) of (True, True) -> empty (False, True) -> attrsDoc (True, False) -> methodsDoc (False, False) -> attrsDoc $+$ blank $+$ methodsDoc -- | Document protocol body with types - extract method signatures in Markdown docProtocolBodyWithTypes :: TEnv -> Suite -> Doc docProtocolBodyWithTypes tenv stmts = let methods = concatMap (extractMethodsWithTypes tenv) stmts in if null methods then empty else text "**Methods:**" $+$ blank $+$ vcat (punctuate blank methods) -- | Partition class members into attributes and methods with types partitionClassMembersWithTypes :: TEnv -> Suite -> ([Doc], [Doc]) partitionClassMembersWithTypes tenv stmts = foldl partition ([], []) stmts where partition (attrs, methods) (Signature _ vs sc d) = (attrs ++ [docAttribute vs sc], methods) partition (attrs, methods) (Decl _ decls) = (attrs, methods ++ map (docMethodWithTypes tenv) decls) partition acc _ = acc -- | Extract method documentation from statements with types extractMethodsWithTypes :: TEnv -> Stmt -> [Doc] extractMethodsWithTypes tenv (Decl _ decls) = map (docMethodWithTypes tenv) decls extractMethodsWithTypes _ (Signature _ vs sc d) = [docMethodSignature vs sc] extractMethodsWithTypes _ _ = [] -- | Document an attribute in Markdown docAttribute :: [Name] -> TSchema -> Doc docAttribute vs (TSchema _ _ t) = text "-" <+> text "`" <> commaList vs <> text "`:" <+> text "*" <> pretty (SimplifiedType t) <> text "*" -- | Document a method signature in Markdown docMethodSignature :: [Name] -> TSchema -> Doc docMethodSignature vs (TSchema _ _ t) = text "-" <+> text "`" <> commaList vs <> text "`:" <+> text "*" <> pretty (SimplifiedType t) <> text "*" -- | Document a method in Markdown with types docMethodWithTypes :: TEnv -> Decl -> Doc docMethodWithTypes tenv (Def _ n q p k a b _ _ ddoc) = let (inferredType, paramsWithTypes, retType) = case lookup n tenv of Just (NDef (TSchema _ _ t@(TFun _ _ posRow kwdRow resType)) _ _) -> (Just t, enrichParamsMarkdown posRow kwdRow p k, Just resType) Just (NSig (TSchema _ _ t@(TFun _ _ posRow kwdRow resType)) _ _) -> (Just t, enrichParamsMarkdown posRow kwdRow p k, Just resType) _ -> (Nothing, docParamsWithTypes p k, a) signature = text "-" <+> text "`" <> pretty n <> text "`" <> docGenerics q <> paramsWithTypes <> docRetTypeFormatted (if isJust retType then retType else a) docstr = case ddoc of Just ds -> nest 2 (text ds) Nothing -> empty in signature $+$ (if isEmpty docstr then empty else blank $+$ docstr) where isJust (Just _) = True isJust Nothing = False enrichParamsMarkdown :: PosRow -> KwdRow -> PosPar -> KwdPar -> Doc enrichParamsMarkdown posRow kwdRow p k = parens $ enrichPosParamsMarkdown posRow p <> kwdParSepLocal p k <> enrichKwdParamsMarkdown kwdRow k kwdParSepLocal :: PosPar -> KwdPar -> Doc kwdParSepLocal PosNIL KwdNIL = empty kwdParSepLocal PosNIL _ = empty kwdParSepLocal _ KwdNIL = empty kwdParSepLocal _ _ = text ", " enrichPosParamsMarkdown :: PosRow -> PosPar -> Doc enrichPosParamsMarkdown _ PosNIL = empty enrichPosParamsMarkdown posRow (PosPar n t e p) = -- Skip witness parameters if isWitnessParam n then enrichPosParamsMarkdown (advanceRow posRow) p else let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatType paramType <> formatDefault e nextParams = enrichPosParamsMarkdown (advanceRow posRow) p in case p of PosNIL -> param _ -> if isEmpty nextParams then param else param <> comma <+> nextParams enrichPosParamsMarkdown _ (PosSTAR n t) = text "*" <> pretty n <> formatType t enrichKwdParamsMarkdown :: KwdRow -> KwdPar -> Doc enrichKwdParamsMarkdown _ KwdNIL = empty enrichKwdParamsMarkdown kwdRow (KwdPar n t e k) = let inferredType = extractParamTypeFromRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatType paramType <> formatDefault e in case k of KwdNIL -> param _ -> param <> comma <+> enrichKwdParamsMarkdown kwdRow k enrichKwdParamsMarkdown _ (KwdSTAR n t) = text "**" <> pretty n <> formatType t extractParamTypeFromRow :: String -> Type -> Maybe Type extractParamTypeFromRow _ (TNil _ _) = Nothing extractParamTypeFromRow name (TRow _ _ n t rest) | nstr n == name = Just t | otherwise = extractParamTypeFromRow name rest extractParamTypeFromRow _ _ = Nothing advanceRow :: Type -> Type advanceRow (TRow _ _ _ _ rest) = rest advanceRow t = t docMethodWithTypes _ _ = empty -- | Print documentation as Markdown with type information printMdDoc :: NameInfo -> Module -> String printMdDoc nmod m = render (docModuleWithTypes nmod m) -- | Print documentation as ASCII with optional styling and type information -- Parameters: -- useStyle: Enable ANSI control codes (bold + color) -- tenv: Type environment for enhanced type information -- module: The module to document printAsciiDoc :: Bool -> NameInfo -> Module -> String printAsciiDoc useStyle nmod m = render (docModuleAsciiUnified useStyle nmod m) ++ "\n" -- Terminal formatting codes bold, underline, reset :: Bool -> String bold True = "\ESC[1m" bold False = "" underline True = "\ESC[4m" underline False = "" reset True = "\ESC[0m" reset False = "" -- Color codes (only when color is enabled) cyan, yellow, green, dim :: Bool -> String cyan True = "\ESC[36m" cyan False = "" yellow True = "\ESC[33m" yellow False = "" green True = "\ESC[32m" green False = "" dim True = "\ESC[2m" dim False = "" -- | Generate ASCII documentation from a module with unified style and type handling docModuleAsciiUnified :: Bool -> NameInfo -> Module -> Doc docModuleAsciiUnified useStyle (NModule _ tenv mdocstring) (Module qn _ _ stmts) = -- Use module docstring from NModule let moduleDocstring = mdocstring (title, restDoc) = case moduleDocstring of Just ds -> splitDocstring ds Nothing -> ("", Nothing) -- Module header with visual emphasis header = text (bold useStyle) <> pretty qn <> text (reset useStyle) <> (if null title then empty else text " - " <> text title) bodyDoc = case restDoc of Just body -> blank $+$ text body $+$ blank Nothing -> empty in header $+$ bodyDoc $+$ blank $+$ docTopLevelAsciiUnified useStyle tenv stmts -- | Document top-level definitions with unified style and type handling docTopLevelAsciiUnified :: Bool -> TEnv -> Suite -> Doc docTopLevelAsciiUnified useStyle tenv stmts = let docs = concatMap (extractTopLevelUnified useStyle tenv) stmts separated = case docs of [] -> [] [d] -> [d] (d:ds) -> d : map (blank $+$) ds in vcat separated -- | Extract and document top-level declarations with unified handling extractTopLevelUnified :: Bool -> TEnv -> Stmt -> [Doc] extractTopLevelUnified useStyle tenv (Decl _ decls) = map (docDeclUnified useStyle tenv) decls extractTopLevelUnified useStyle tenv (With _ _ body) = concatMap (extractTopLevelUnified useStyle tenv) body extractTopLevelUnified _ _ _ = [] -- | Extract QBinds from a type schema getQBindsFromSchema :: TSchema -> QBinds getQBindsFromSchema (TSchema _ qb _) = qb -- | Collect all ugly type variable names from QBinds collectUglyTypeVars :: QBinds -> [Name] collectUglyTypeVars qbs = [tvname tv | QBind tv _ <- qbs, isUglyName (tvname tv)] where isUglyName n = let name = nstr n in length name > 2 && elem '_' name && all isDigit (drop 2 name) -- | Collect all ugly type variable names from a Type collectUglyTypeVarsFromType :: Type -> [Name] collectUglyTypeVarsFromType (TVar _ tv) = let name = tvname tv in if isUglyName name then [name] else [] where isUglyName n = let nameStr = nstr n in length nameStr > 2 && elem '_' nameStr && all isDigit (drop 2 nameStr) collectUglyTypeVarsFromType (TFun _ _ posRow kwdRow resType) = collectUglyTypeVarsFromType posRow ++ collectUglyTypeVarsFromType kwdRow ++ collectUglyTypeVarsFromType resType collectUglyTypeVarsFromType (TCon _ (TC _ ts)) = concatMap collectUglyTypeVarsFromType ts collectUglyTypeVarsFromType (TRow _ _ _ t rest) = collectUglyTypeVarsFromType t ++ collectUglyTypeVarsFromType rest collectUglyTypeVarsFromType (TTuple _ posRow kwdRow) = collectUglyTypeVarsFromType posRow ++ collectUglyTypeVarsFromType kwdRow collectUglyTypeVarsFromType (TOpt _ t) = collectUglyTypeVarsFromType t collectUglyTypeVarsFromType _ = [] -- | Create a mapping from ugly names to nice generic names (A, B, C...) createTypeVarMapping :: [Name] -> [(Name, Name)] createTypeVarMapping uglyNames = zip uglyNames niceNames where niceNames = [Name NoLoc [c] | c <- ['A'..'Z']] -- | Replace ugly type vars with nice names in a type cleanupTypeVars :: [(Name, Name)] -> Type -> Type cleanupTypeVars mapping (TVar l tv) = case lookup (tvname tv) mapping of Just niceName -> TVar l (TV (tvkind tv) niceName) Nothing -> TVar l tv cleanupTypeVars mapping (TFun l fx posRow kwdRow resType) = TFun l fx (cleanupTypeVars mapping posRow) (cleanupTypeVars mapping kwdRow) (cleanupTypeVars mapping resType) cleanupTypeVars mapping (TCon l (TC qn ts)) = TCon l (TC qn (map (cleanupTypeVars mapping) ts)) cleanupTypeVars mapping (TRow l k n t rest) = TRow l k n (cleanupTypeVars mapping t) (cleanupTypeVars mapping rest) cleanupTypeVars mapping (TTuple l posRow kwdRow) = TTuple l (cleanupTypeVars mapping posRow) (cleanupTypeVars mapping kwdRow) cleanupTypeVars mapping (TOpt l t) = TOpt l (cleanupTypeVars mapping t) cleanupTypeVars _ t = t -- | Replace ugly type vars with nice names in QBinds cleanupQBinds :: [(Name, Name)] -> [QBind] -> [QBind] cleanupQBinds mapping = map cleanupQBind where cleanupQBind (QBind tv tcons) = case lookup (tvname tv) mapping of Just niceName -> QBind (TV (tvkind tv) niceName) (map (cleanupTCon mapping) tcons) Nothing -> QBind tv (map (cleanupTCon mapping) tcons) cleanupTCon :: [(Name, Name)] -> TCon -> TCon cleanupTCon mapping (TC qn ts) = TC qn (map (cleanupTypeVars mapping) ts) -- | Document a declaration with unified style and type handling docDeclUnified :: Bool -> TEnv -> Decl -> Doc docDeclUnified useStyle tenv decl@(Def _ n q p k a b d x ddoc) = let explicitGenerics = extractGenerics q -- Look up inferred type information (inferredType, qConstraints, docstringFromTEnv) = case lookup n tenv of Just info@(NDef schema _ _) -> (Just schema, getQBindsFromSchema schema, extractNameDocstring info) Just info@(NSig schema _ _) -> (Just schema, getQBindsFromSchema schema, extractNameDocstring info) _ -> (Nothing, [], Nothing) -- Create a mapping from ugly type vars to nice generic names uglyTypeVarsFromQBinds = collectUglyTypeVars qConstraints uglyTypeVarsFromType = case inferredType of Just (TSchema _ _ t) -> collectUglyTypeVarsFromType t _ -> [] allUglyTypeVars = nub (uglyTypeVarsFromQBinds ++ uglyTypeVarsFromType) typeVarMapping = createTypeVarMapping allUglyTypeVars -- Transform the inferred types using the mapping (paramsWithTypes, retType) = case inferredType of Just (TSchema _ _ (TFun _ _ posRow kwdRow resType)) -> let cleanPosRow = cleanupTypeVars typeVarMapping posRow cleanKwdRow = cleanupTypeVars typeVarMapping kwdRow cleanRetType = cleanupTypeVars typeVarMapping resType in (enrichParamsStyledAsciiDecl useStyle cleanPosRow cleanKwdRow p k, Just cleanRetType) _ -> (docParamsStyledAscii useStyle useStyle p k, a) -- Use docstring from AST declaration docstr = case docstringFromTEnv of Just ds -> Just ds Nothing -> ddoc -- Show generics if we have them (either explicit or inferred) allGenerics = if null q && not (null typeVarMapping) then map snd typeVarMapping -- Use the nice names from mapping else map (\(QBind tv _) -> tvname tv) q genericsDoc = if null allGenerics then empty else brackets $ hcat $ punctuate comma $ map pretty allGenerics header = text (bold useStyle) <> pretty n <> text (reset useStyle) <> genericsDoc <> paramsWithTypes <> docRetTypeStyled useStyle useStyle retType docstrDoc = case docstr of Just ds -> nest 2 (text ds) Nothing -> empty in header $+$ (if isEmpty docstrDoc then empty else docstrDoc) where -- Check if a QBind contains ugly type variable names like T_638 isUglyTypeVar :: QBind -> Bool isUglyTypeVar (QBind tv _) = let name = nstr (tvname tv) in length name > 2 && elem '_' name && all isDigit (drop 2 name) -- Check if a type contains ugly type variable names containsUglyTypeVar :: Type -> Bool containsUglyTypeVar (TVar _ tv) = let name = nstr (tvname tv) in length name > 2 && elem '_' name && all isDigit (drop 2 name) containsUglyTypeVar (TFun _ _ posRow kwdRow resType) = containsUglyTypeVar posRow || containsUglyTypeVar kwdRow || containsUglyTypeVar resType containsUglyTypeVar (TCon _ (TC _ ts)) = any containsUglyTypeVar ts containsUglyTypeVar (TRow _ _ _ t rest) = containsUglyTypeVar t || containsUglyTypeVar rest containsUglyTypeVar (TTuple _ posRow kwdRow) = containsUglyTypeVar posRow || containsUglyTypeVar kwdRow containsUglyTypeVar (TOpt _ t) = containsUglyTypeVar t containsUglyTypeVar _ = False isNothing :: Maybe a -> Bool isNothing Nothing = True isNothing _ = False -- Simple parameter display without types docParamsSimpleAscii :: PosPar -> KwdPar -> Doc docParamsSimpleAscii p k = parens $ docPosParSimple p <> docKwdParSepAscii p k <> docKwdParSimple k docPosParSimple :: PosPar -> Doc docPosParSimple PosNIL = empty docPosParSimple (PosPar n _ _ p) = let param = pretty n in case p of PosNIL -> param _ -> param <> comma <+> docPosParSimple p docPosParSimple (PosSTAR n _) = text "*" <> pretty n docKwdParSimple :: KwdPar -> Doc docKwdParSimple KwdNIL = empty docKwdParSimple (KwdPar n _ _ k) = let param = pretty n in case k of KwdNIL -> param _ -> param <> comma <+> docKwdParSimple k docKwdParSimple (KwdSTAR n _) = text "**" <> pretty n enrichParamsStyledAsciiDecl :: Bool -> PosRow -> KwdRow -> PosPar -> KwdPar -> Doc enrichParamsStyledAsciiDecl useStyle posRow kwdRow p k = parens $ enrichPosParamsStyledDecl useStyle posRow p <> docKwdParSepAscii p k <> enrichKwdParamsStyledDecl useStyle kwdRow k enrichPosParamsStyledDecl :: Bool -> PosRow -> PosPar -> Doc enrichPosParamsStyledDecl _ _ PosNIL = empty enrichPosParamsStyledDecl useStyle posRow (PosPar n t e p) = -- Skip witness parameters if isWitnessParam n then enrichPosParamsStyledDecl useStyle (advanceRow posRow) p else let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatTypeStyled useStyle useStyle paramType <> formatDefault e nextParams = enrichPosParamsStyledDecl useStyle (advanceRow posRow) p in case p of PosNIL -> param _ -> if isEmpty nextParams then param else param <> comma <+> nextParams enrichKwdParamsStyledDecl :: Bool -> KwdRow -> KwdPar -> Doc enrichKwdParamsStyledDecl _ _ KwdNIL = empty enrichKwdParamsStyledDecl useStyle kwdRow (KwdPar n t e k) = -- Skip witness parameters if isWitnessParam n then enrichKwdParamsStyledDecl useStyle (advanceRow kwdRow) k else let inferredType = extractParamTypeFromKwdRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatTypeStyled useStyle useStyle paramType <> formatDefault e nextParams = enrichKwdParamsStyledDecl useStyle (advanceRow kwdRow) k in case k of KwdNIL -> param _ -> if isEmpty nextParams then param else param <> comma <+> nextParams docDeclUnified useStyle tenv (Actor _ n q p k b ddoc) = let (paramsWithTypes, docstringFromTEnv) = case lookup n tenv of Just info@(NAct _ posRow kwdRow _ mdoc) -> (enrichParamsStyledAsciiActr useStyle posRow kwdRow p k, mdoc) _ -> (docParamsStyledAscii useStyle useStyle p k, Nothing) -- Use docstring from AST declaration docstr = case docstringFromTEnv of Just ds -> Just ds Nothing -> ddoc header = text (cyan useStyle ++ "actor" ++ reset useStyle) <+> text (bold useStyle) <> pretty n <> text (reset useStyle) <> docGenerics q <> paramsWithTypes docstrDoc = case docstr of Just ds -> nest 2 (text ds) Nothing -> empty in header $+$ (if isEmpty docstrDoc then empty else docstrDoc) where enrichParamsStyledAsciiActr useStyle posRow kwdRow p k = parens $ enrichPosParamsStyledDecl useStyle posRow p <> docKwdParSepAscii p k <> enrichKwdParamsStyledDecl useStyle kwdRow k enrichPosParamsStyledDecl _ _ PosNIL = empty enrichPosParamsStyledDecl useStyle posRow (PosPar n t e p) = if isWitnessParam n then enrichPosParamsStyledDecl useStyle (advanceRow posRow) p else let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatTypeStyled useStyle useStyle paramType <> formatDefault e nextParams = enrichPosParamsStyledDecl useStyle (advanceRow posRow) p in case p of PosNIL -> param _ -> if isEmpty nextParams then param else param <> comma <+> nextParams enrichKwdParamsStyledDecl _ _ KwdNIL = empty enrichKwdParamsStyledDecl useStyle kwdRow (KwdPar n t e k) = if isWitnessParam n then enrichKwdParamsStyledDecl useStyle (advanceRow kwdRow) k else let inferredType = extractParamTypeFromKwdRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatTypeStyled useStyle useStyle paramType <> formatDefault e nextParams = enrichKwdParamsStyledDecl useStyle (advanceRow kwdRow) k in case k of KwdNIL -> param _ -> if isEmpty nextParams then param else param <> comma <+> nextParams docDeclUnified useStyle tenv (Class _ n q a b ddoc) = let docstringFromTEnv = case lookup n tenv of Just info -> extractNameDocstring info _ -> Nothing -- Always get docstring from either TEnv or AST docstr = case docstringFromTEnv of Just ds -> Just ds Nothing -> ddoc header = text (cyan useStyle ++ "class" ++ reset useStyle) <+> text (bold useStyle) <> pretty n <> text (reset useStyle) <> docGenerics q <> docAncestors a docstrDoc = case docstr of Just ds -> nest 2 (text ds) Nothing -> empty -- Document methods and attributes (attrs, methods) = extractClassMembers b attrsDoc = if null attrs then empty else blank $+$ nest 2 (text (yellow useStyle ++ "Attributes:" ++ reset useStyle)) $+$ vcat [nest 4 (docAttrUnified useStyle attr) | attr <- attrs] methodsDoc = if null methods then empty else blank $+$ nest 2 (text (yellow useStyle ++ "Methods:" ++ reset useStyle)) $+$ vcat [nest 4 (docMethodUnified useStyle tenv n meth) | meth <- methods] in header $+$ (if isEmpty docstrDoc then empty else docstrDoc) $+$ attrsDoc $+$ methodsDoc where -- Document a single attribute docAttrUnified :: Bool -> (Name, Maybe Type) -> Doc docAttrUnified useStyle (name, mtype) = pretty name <> case mtype of Just t -> text ": " <> pretty (SimplifiedType t) Nothing -> empty -- Document a method signature docMethodUnified :: Bool -> TEnv -> Name -> (Name, QBinds, PosPar, KwdPar, Maybe Type, Maybe String) -> Doc docMethodUnified useStyle tenv className (methodName, q, p, k, retType, docstr) = let (paramsWithTypes, inferredRetType) = -- Try to get type info from TEnv case lookup className tenv of Just (NClass _ _ methods _) -> case lookup methodName methods of Just info -> case extractTypeFromNameInfo info of Just (TFun _ _ posRow kwdRow resType) -> (enrichParamsStyledAsciiDecl useStyle posRow kwdRow p k, Just resType) _ -> (docParamsStyledAscii useStyle useStyle p k, retType) _ -> (docParamsStyledAscii useStyle useStyle p k, retType) _ -> (docParamsStyledAscii useStyle useStyle p k, retType) -- Don't show return type for __init__ methods or methods that return None showRetType = case fromMaybe retType inferredRetType of Just (TNone _) -> empty Just t -> if nstr methodName == "__init__" then empty else docRetTypeStyled useStyle useStyle (Just t) Nothing -> empty header = text (bold useStyle) <> pretty methodName <> text (reset useStyle) <> docGenerics q <> paramsWithTypes <> showRetType docstrDoc = case docstr of Just ds -> text ds Nothing -> empty in header $+$ (if isEmpty docstrDoc then empty else nest 2 docstrDoc) where fromMaybe def Nothing = def fromMaybe _ (Just x) = Just x extractTypeFromNameInfo :: NameInfo -> Maybe Type extractTypeFromNameInfo (NDef (TSchema _ _ t) _ _) = Just t extractTypeFromNameInfo (NSig (TSchema _ _ t) _ _) = Just t extractTypeFromNameInfo _ = Nothing enrichParamsStyledAsciiDecl useStyle posRow kwdRow p k = parens $ enrichPosParamsStyledMeth useStyle posRow p <> docKwdParSepAscii p k <> enrichKwdParamsStyledMeth useStyle kwdRow k enrichPosParamsStyledMeth _ _ PosNIL = empty enrichPosParamsStyledMeth useStyle posRow (PosPar n t e p) = if isWitnessParam n then enrichPosParamsStyledMeth useStyle (advanceRow posRow) p else let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatTypeStyled useStyle useStyle paramType <> formatDefault e nextParams = enrichPosParamsStyledMeth useStyle (advanceRow posRow) p in case p of PosNIL -> param _ -> if isEmpty nextParams then param else param <> comma <+> nextParams enrichKwdParamsStyledMeth _ _ KwdNIL = empty enrichKwdParamsStyledMeth useStyle kwdRow (KwdPar n t e k) = if isWitnessParam n then enrichKwdParamsStyledMeth useStyle (advanceRow kwdRow) k else let inferredType = extractParamTypeFromKwdRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatTypeStyled useStyle useStyle paramType <> formatDefault e nextParams = enrichKwdParamsStyledMeth useStyle (advanceRow kwdRow) k in case k of KwdNIL -> param _ -> if isEmpty nextParams then param else param <> comma <+> nextParams docDeclUnified useStyle tenv (Protocol _ n q a b ddoc) = let docstringFromTEnv = case lookup n tenv of Just info -> extractNameDocstring info _ -> Nothing -- Always get docstring from either TEnv or AST docstr = case docstringFromTEnv of Just ds -> Just ds Nothing -> ddoc header = text (cyan useStyle ++ "protocol" ++ reset useStyle) <+> text (bold useStyle) <> pretty n <> text (reset useStyle) <> docGenerics q <> docAncestors a docstrDoc = case docstr of Just ds -> nest 2 (text ds) Nothing -> empty -- Document protocol methods methods = extractProtocolMethods b methodsDoc = if null methods then empty else blank $+$ nest 2 (text (yellow useStyle ++ "Methods:" ++ reset useStyle)) $+$ vcat (intersperse blank [nest 4 (docProtocolMethod meth) | meth <- methods]) in header $+$ (if isEmpty docstrDoc then empty else docstrDoc) $+$ methodsDoc where -- Document a protocol method docProtocolMethod :: (Name, QBinds, PosPar, KwdPar, Maybe Type, Maybe String) -> Doc docProtocolMethod (methodName, q, p, k, retType, docstr) = -- Protocol methods are just signatures let header = pretty methodName <> text ":" <+> case retType of Just t -> pretty (SimplifiedType t) Nothing -> text "()" docstrDoc = case docstr of Just ds -> nest 2 (text ds) Nothing -> empty in header $+$ (if isEmpty docstrDoc then empty else docstrDoc) docDeclUnified useStyle tenv (Extension _ q c a b ddoc) = let docstringFromTEnv = Nothing -- Extensions don't have docstrings in TEnv -- Get docstring from AST docstr = ddoc header = text (cyan useStyle ++ "extension" ++ reset useStyle) <+> pretty c <> docAncestors a docstrDoc = case docstr of Just ds -> nest 2 (text ds) Nothing -> empty in header $+$ (if isEmpty docstrDoc then empty else docstrDoc) -- | Document a declaration with man-page visual style and types -- | Format parameters with visual styling docParamsStyledAscii :: Bool -> Bool -> PosPar -> KwdPar -> Doc docParamsStyledAscii useBold useColor p k = parens $ docPosParStyled useBold useColor p <> docKwdParSepAscii p k <> docKwdParStyled useBold useColor k docPosParStyled :: Bool -> Bool -> PosPar -> Doc docPosParStyled _ _ PosNIL = empty docPosParStyled useBold useColor (PosPar n t e p) = let param = pretty n <> formatTypeStyled useBold useColor t <> formatDefault e in case p of PosNIL -> param _ -> param <> comma <+> docPosParStyled useBold useColor p docPosParStyled useBold useColor (PosSTAR n t) = text "*" <> pretty n <> formatTypeStyled useBold useColor t docKwdParStyled :: Bool -> Bool -> KwdPar -> Doc docKwdParStyled _ _ KwdNIL = empty docKwdParStyled useBold useColor (KwdPar n t e k) = let param = pretty n <> formatTypeStyled useBold useColor t <> formatDefault e in case k of KwdNIL -> param _ -> param <> comma <+> docKwdParStyled useBold useColor k docKwdParStyled useBold useColor (KwdSTAR n t) = text "**" <> pretty n <> formatTypeStyled useBold useColor t formatTypeStyled :: Bool -> Bool -> Maybe Type -> Doc formatTypeStyled _ _ Nothing = empty formatTypeStyled useBold useColor (Just t) = if useColor then colon <+> text (green True) <> pretty (SimplifiedType t) <> text (reset True) else colon <+> text (underline useBold) <> pretty (SimplifiedType t) <> text (reset useBold) docRetTypeStyled :: Bool -> Bool -> Maybe Type -> Doc docRetTypeStyled _ _ Nothing = empty docRetTypeStyled useBold useColor (Just t) = if useColor then text " -> " <> text (green True) <> pretty (SimplifiedType t) <> text (reset True) else text " -> " <> text (underline useBold) <> pretty (SimplifiedType t) <> text (reset useBold) -- | Document class body with visual styling -- | Document class body with visual styling and types docClassBodyStyledWithTypes :: Bool -> Bool -> TEnv -> Suite -> Doc docClassBodyStyledWithTypes useBold useColor tenv stmts = let (attrs, methods) = partitionClassMembersStyledWithTypes useBold useColor tenv stmts attrsDoc = if null attrs then empty else nest 2 (text "Attributes:" $+$ vcat attrs) methodsDoc = if null methods then empty else nest 2 (text "Methods:" $+$ vcatWithSpacing methods) in case (isEmpty attrsDoc, isEmpty methodsDoc) of (True, True) -> empty (False, True) -> attrsDoc (True, False) -> methodsDoc (False, False) -> attrsDoc $+$ blank $+$ methodsDoc where vcatWithSpacing [] = empty vcatWithSpacing [m] = m vcatWithSpacing (m:ms) = m $+$ vcat (map addSpacing ms) addSpacing m = blank $+$ m -- | Document protocol body with visual styling and types docProtocolBodyStyledWithTypes :: Bool -> Bool -> TEnv -> Suite -> Doc docProtocolBodyStyledWithTypes useBold useColor tenv stmts = let methods = concatMap (extractMethodsStyledWithTypes useBold useColor tenv) stmts in if null methods then empty else nest 2 (text "Methods:" $+$ vcatWithSpacing methods) where vcatWithSpacing [] = empty vcatWithSpacing [m] = m vcatWithSpacing (m:ms) = m $+$ vcat (map addSpacing ms) addSpacing m = blank $+$ m -- | Partition class members into attributes and methods with styling partitionClassMembersStyled :: Bool -> Bool -> Suite -> ([Doc], [Doc]) partitionClassMembersStyled useBold useColor stmts = foldl partition ([], []) stmts where partition (attrs, methods) (Signature _ vs sc d) = (attrs ++ [docAttributeStyled useBold useColor vs sc], methods) partition (attrs, methods) (Decl _ decls) = (attrs, methods ++ map (docMethodStyled useBold useColor) decls) partition acc _ = acc -- | Partition class members into attributes and methods with styling and types partitionClassMembersStyledWithTypes :: Bool -> Bool -> TEnv -> Suite -> ([Doc], [Doc]) partitionClassMembersStyledWithTypes useBold useColor tenv stmts = foldl partition ([], []) stmts where partition (attrs, methods) (Signature _ vs sc d) = (attrs ++ [docAttributeStyled useBold useColor vs sc], methods) partition (attrs, methods) (Decl _ decls) = (attrs, methods ++ map (docMethodStyledWithTypes useBold useColor tenv) decls) partition acc _ = acc -- | Extract method documentation with styling extractMethodsStyled :: Bool -> Bool -> Stmt -> [Doc] extractMethodsStyled useBold useColor (Decl _ decls) = map (docMethodStyled useBold useColor) decls extractMethodsStyled useBold useColor (Signature _ vs sc d) = [docMethodSignatureStyled useBold useColor vs sc] extractMethodsStyled _ _ _ = [] -- | Extract method documentation with styling and types extractMethodsStyledWithTypes :: Bool -> Bool -> TEnv -> Stmt -> [Doc] extractMethodsStyledWithTypes useBold useColor tenv (Decl _ decls) = map (docMethodStyledWithTypes useBold useColor tenv) decls extractMethodsStyledWithTypes useBold useColor _ (Signature _ vs sc d) = [docMethodSignatureStyled useBold useColor vs sc] extractMethodsStyledWithTypes _ _ _ _ = [] -- | Document an attribute with styling docAttributeStyled :: Bool -> Bool -> [Name] -> TSchema -> Doc docAttributeStyled useBold useColor vs (TSchema _ _ t) = if useColor then nest 2 $ text "- " <> commaList vs <> text ": " <> text (green True) <> pretty (SimplifiedType t) <> text (reset True) else nest 2 $ text "- " <> commaList vs <> text ": " <> text (underline useBold) <> pretty (SimplifiedType t) <> text (reset useBold) -- | Document a method with styling docMethodStyled :: Bool -> Bool -> Decl -> Doc docMethodStyled useBold useColor (Def _ n q p k a b _ _ ddoc) = let signature = nest 2 $ text "- " <> text (bold useBold) <> pretty n <> text (reset useBold) <> docGenerics q <> docParamsStyledAscii useBold useColor p k <> docRetTypeStyled useBold useColor a docstr = case ddoc of Just ds -> nest 4 (text ds) Nothing -> empty in signature $+$ (if isEmpty docstr then empty else docstr) docMethodStyled _ _ _ = empty -- | Document a method signature with styling docMethodSignatureStyled :: Bool -> Bool -> [Name] -> TSchema -> Doc docMethodSignatureStyled useBold useColor vs (TSchema _ _ t) = if useColor then nest 2 $ text "- " <> commaList vs <> text ": " <> text (green True) <> pretty (SimplifiedType t) <> text (reset True) else nest 2 $ text "- " <> commaList vs <> text ": " <> text (underline useBold) <> pretty (SimplifiedType t) <> text (reset useBold) -- | Document a method with styling and types docMethodStyledWithTypes :: Bool -> Bool -> TEnv -> Decl -> Doc docMethodStyledWithTypes useBold useColor tenv (Def _ n q p k a b _ _ ddoc) = let (inferredType, paramsWithTypes, retType) = case lookup n tenv of Just (NDef (TSchema _ _ t@(TFun _ _ posRow kwdRow resType)) _ _) -> (Just t, enrichParamsStyledAscii useBold useColor posRow kwdRow p k, Just resType) Just (NSig (TSchema _ _ t@(TFun _ _ posRow kwdRow resType)) _ _) -> (Just t, enrichParamsStyledAscii useBold useColor posRow kwdRow p k, Just resType) _ -> (Nothing, docParamsStyledAscii useBold useColor p k, a) signature = nest 2 $ text "- " <> text (bold useBold) <> pretty n <> text (reset useBold) <> docGenerics q <> paramsWithTypes <> docRetTypeStyled useBold useColor (if isJust retType then retType else a) docstr = case ddoc of Just ds -> nest 4 (text ds) Nothing -> empty in signature $+$ (if isEmpty docstr then empty else docstr) where isJust (Just _) = True isJust Nothing = False enrichParamsStyledAscii :: Bool -> Bool -> PosRow -> KwdRow -> PosPar -> KwdPar -> Doc enrichParamsStyledAscii useBold useColor posRow kwdRow p k = parens $ enrichPosParamsStyled useBold useColor posRow p <> docKwdParSepAscii p k <> enrichKwdParamsStyled useBold useColor kwdRow k enrichPosParamsStyled :: Bool -> Bool -> PosRow -> PosPar -> Doc enrichPosParamsStyled _ _ _ PosNIL = empty enrichPosParamsStyled useBold useColor posRow (PosPar n t e p) = -- Skip witness parameters if isWitnessParam n then enrichPosParamsStyled useBold useColor (advanceRow posRow) p else let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatTypeStyled useBold useColor paramType <> formatDefault e nextParams = enrichPosParamsStyled useBold useColor (advanceRow posRow) p in case p of PosNIL -> param _ -> if isEmpty nextParams then param else param <> comma <+> nextParams enrichPosParamsStyled useBold useColor _ (PosSTAR n t) = text "*" <> pretty n <> formatTypeStyled useBold useColor t enrichKwdParamsStyled :: Bool -> Bool -> KwdRow -> KwdPar -> Doc enrichKwdParamsStyled _ _ _ KwdNIL = empty enrichKwdParamsStyled useBold useColor kwdRow (KwdPar n t e k) = let inferredType = extractParamTypeFromRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t param = pretty n <> formatTypeStyled useBold useColor paramType <> formatDefault e in case k of KwdNIL -> param _ -> param <> comma <+> enrichKwdParamsStyled useBold useColor kwdRow k enrichKwdParamsStyled useBold useColor _ (KwdSTAR n t) = text "**" <> pretty n <> formatTypeStyled useBold useColor t extractParamTypeFromRow :: String -> Type -> Maybe Type extractParamTypeFromRow _ (TNil _ _) = Nothing extractParamTypeFromRow name (TRow _ _ n t rest) | nstr n == name = Just t | otherwise = extractParamTypeFromRow name rest extractParamTypeFromRow _ _ = Nothing advanceRow :: Type -> Type advanceRow (TRow _ _ _ _ rest) = rest advanceRow t = t docMethodStyledWithTypes _ _ _ _ = empty -- | Format parameters for ASCII docParamsAscii :: PosPar -> KwdPar -> Doc docParamsAscii p k = parens $ docPosParAscii p <> docKwdParSepAscii p k <> docKwdParAscii k docKwdParSepAscii :: PosPar -> KwdPar -> Doc docKwdParSepAscii PosNIL KwdNIL = empty docKwdParSepAscii PosNIL _ = empty docKwdParSepAscii _ KwdNIL = empty docKwdParSepAscii _ _ = text ", " docPosParAscii :: PosPar -> Doc docPosParAscii PosNIL = empty docPosParAscii (PosPar n t e p) = let param = pretty n <> formatTypeAscii t <> formatDefault e in case p of PosNIL -> param _ -> param <> comma <+> docPosParAscii p docPosParAscii (PosSTAR n t) = text "*" <> pretty n <> formatTypeAscii t docKwdParAscii :: KwdPar -> Doc docKwdParAscii KwdNIL = empty docKwdParAscii (KwdPar n t e k) = let param = pretty n <> formatTypeAscii t <> formatDefault e in case k of KwdNIL -> param _ -> param <> comma <+> docKwdParAscii k docKwdParAscii (KwdSTAR n t) = text "**" <> pretty n <> formatTypeAscii t formatTypeAscii :: Maybe Type -> Doc formatTypeAscii Nothing = empty formatTypeAscii (Just t) = colon <+> pretty (SimplifiedType t) docRetTypeAscii :: Maybe Type -> Doc docRetTypeAscii Nothing = empty docRetTypeAscii (Just t) = text " -> " <> pretty (SimplifiedType t) -- | Print documentation as HTML with type information printHtmlDoc :: NameInfo -> Module -> String printHtmlDoc nmod m = unlines [ "" , "" , "" , " " , " " , " " ++ moduleTitle m ++ "" , " " , " " , "" , "" , "
" , render (docModuleHtmlWithTypes nmod m) , "
" , "" , "" ] -- | Get module title for HTML moduleTitle :: Module -> String moduleTitle (Module qn _ _ _) = render (pretty qn) -- | CSS styles for HTML documentation htmlStyles :: String htmlStyles = unlines [ " /* Light theme colors (default) */" , " :root {" , " --text-primary: #24292e;" , " --text-secondary: #6a737d;" , " --text-link: #0366d6;" , " --bg-primary: #ffffff;" , " --bg-secondary: #f6f8fa;" , " --border: #e1e4e8;" , " --code-bg: #f6f8fa;" , " --type-color: #6f42c1;" , " --keyword-color: #d73a49;" , " --generic-color: #e36209;" , " --generic-hover: #fb8532;" , " --shadow: rgba(27, 31, 35, 0.04);" , " --shadow-medium: rgba(27, 31, 35, 0.12);" , " }" , " " , " /* Dark theme colors (activated by OS preference) */" , " @media (prefers-color-scheme: dark) {" , " :root {" , " --text-primary: #c9d1d9;" , " --text-secondary: #8b949e;" , " --text-link: #58a6ff;" , " --bg-primary: #0d1117;" , " --bg-secondary: #161b22;" , " --border: #30363d;" , " --code-bg: #161b22;" , " --type-color: #d2a8ff;" , " --keyword-color: #ff7b72;" , " --generic-color: #ffa657;" , " --generic-hover: #ffb77c;" , " --shadow: rgba(0, 0, 0, 0.3);" , " --shadow-medium: rgba(0, 0, 0, 0.5);" , " }" , " }" , " " , " * { box-sizing: border-box; }" , " " , " body {" , " font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;" , " font-size: 16px;" , " line-height: 1.5;" , " color: var(--text-primary);" , " background: var(--bg-primary);" , " margin: 0;" , " padding: 0;" , " }" , " " , " .container {" , " max-width: 960px;" , " margin: 0 auto;" , " padding: 2rem;" , " }" , " " , " /* Typography */" , " h1 {" , " font-size: 2rem;" , " font-weight: 600;" , " margin: 0 0 1rem 0;" , " padding-bottom: 0.3rem;" , " border-bottom: 1px solid var(--border);" , " }" , " " , " h2 {" , " font-size: 1.25rem;" , " font-weight: 600;" , " margin: 2.5rem 0 1rem 0;" , " }" , " " , " h3 {" , " font-size: 1rem;" , " font-weight: 600;" , " color: var(--text-secondary);" , " margin: 1.5rem 0 0.5rem 0;" , " text-transform: uppercase;" , " letter-spacing: 0.02em;" , " }" , " " , " /* Indent ATTRIBUTES/METHODS headers under classes/actors */" , " .declaration-block h3 {" , " margin-left: 2rem;" , " }" , " " , " p {" , " margin: 0 0 1rem 0;" , " }" , " " , " /* Code */" , " code {" , " font-family: 'SF Mono', Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;" , " font-size: 0.875em;" , " background: var(--code-bg);" , " padding: 0.2em 0.4em;" , " border-radius: 3px;" , " border: 1px solid var(--border);" , " }" , " " , " h2 code {" , " background: none;" , " padding: 0;" , " font-size: 1em;" , " border: none;" , " }" , " " , " /* Type coloring */" , " .type {" , " color: var(--type-color);" , " }" , " " , " /* Type links */" , " .type-link {" , " color: var(--type-color);" , " text-decoration: none;" , " border-bottom: 1px dotted var(--type-color);" , " }" , " " , " .type-link:hover {" , " text-decoration: none;" , " border-bottom: 1px solid var(--type-color);" , " }" , " " , " .keyword {" , " color: var(--keyword-color);" , " font-weight: 500;" , " font-size: 1rem;" , " }" , " " , " .param-name {" , " font-weight: 500;" , " }" , " " , " .default-value {" , " color: var(--text-secondary);" , " }" , " " , " /* Generic type parameters */" , " .generic-type {" , " color: var(--generic-color);" , " cursor: pointer;" , " transition: color 0.2s ease;" , " position: relative;" , " display: inline-block;" , " }" , " " , " .generic-type:hover," , " .generic-type.highlight {" , " color: var(--generic-hover);" , " text-decoration: underline;" , " text-decoration-style: dotted;" , " }" , " " , " /* Tooltip for generic types - default position below */" , " .generic-type[data-tooltip]:hover::after {" , " content: attr(data-tooltip);" , " display: block;" , " position: absolute;" , " top: 100%;" , " left: 50%;" , " transform: translateX(-50%);" , " margin-top: 5px;" , " padding: 8px 12px;" , " background-color: rgba(0, 0, 0, 0.8);" , " color: white;" , " font-size: 0.75rem;" , " font-weight: normal;" , " white-space: pre-wrap;" , " max-width: 700px;" , " min-width: 200px;" , " text-align: left;" , " border-radius: 4px;" , " pointer-events: none;" , " opacity: 0;" , " animation: fadeIn 0.2s ease-in-out forwards;" , " z-index: 1000;" , " }" , " " , " /* Tooltip positioned above when not near top */" , " .generic-type[data-tooltip]:not(.tooltip-below):hover::after {" , " top: auto;" , " bottom: 100%;" , " margin-top: 0;" , " margin-bottom: 5px;" , " }" , " " , " @keyframes fadeIn {" , " from { opacity: 0; }" , " to { opacity: 1; }" , " }" , " " , " /* Documentation strings */" , " .docstring {" , " color: var(--text-secondary);" , " margin: 0.5rem 0 1.5rem 0;" , " padding-left: 1rem;" , " }" , " " , " .module-doc {" , " margin: 1rem 0 2rem 0;" , " color: var(--text-primary);" , " font-size: 1.1rem;" , " line-height: 1.6;" , " }" , " " , " /* Sections */" , " .section {" , " margin: 1.5rem 0;" , " padding-left: 2rem;" , " }" , " " , " /* Lists */" , " ul {" , " list-style: none;" , " padding: 0;" , " margin: 0;" , " }" , " " , " li {" , " margin: 0.5rem 0;" , " }" , " " , " /* Attribute items */" , " .attribute-item {" , " margin: 0.5rem 0;" , " padding-left: 1rem;" , " border-left: 3px solid var(--border);" , " }" , " " , " .attribute-item code {" , " background: none;" , " padding: 0;" , " border: none;" , " }" , " " , " /* Method items */" , " .method-item {" , " margin: 1rem 0;" , " }" , " " , " .method-signature {" , " font-family: 'SF Mono', Monaco, Consolas, monospace;" , " font-size: 0.875rem;" , " padding-left: 1rem;" , " border-left: 3px solid var(--border);" , " }" , " " , " .method-signature code {" , " background: none;" , " padding: 0;" , " border: none;" , " }" , " " , " .method-doc {" , " color: var(--text-secondary);" , " margin: 0.25rem 0 0 1.5rem;" , " font-size: 0.875rem;" , " }" , " " , " /* Attributes and methods sections */" , " .attributes, .methods {" , " margin: 1.5rem 0 1.5rem 2rem;" , " }" , " " , " /* Declaration blocks - no visual boxes, just spacing */" , " .declaration-block {" , " margin: 2rem 0;" , " }" , " " , " /* Module index styles */" , " .module-list {" , " list-style: none;" , " padding: 0;" , " margin: 0;" , " }" , " " , " .module-item {" , " margin: 0.5rem 0;" , " padding: 0.75rem 1rem;" , " background: var(--bg-secondary);" , " border-radius: 6px;" , " border: 1px solid var(--border);" , " transition: all 0.2s ease;" , " }" , " " , " .module-item:hover {" , " border-color: var(--text-link);" , " transform: translateY(-1px);" , " }" , " " , " .module-link {" , " text-decoration: none;" , " color: var(--text-link);" , " font-weight: 500;" , " display: block;" , " }" , " " , " .module-path {" , " font-family: 'SF Mono', Monaco, Consolas, monospace;" , " font-size: 0.875rem;" , " }" , " " , " .module-doc {" , " color: var(--text-secondary);" , " font-size: 0.875rem;" , " margin-top: 0.25rem;" , " }" , " " , " /* Smooth transitions for theme changes */" , " * {" , " transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;" , " }" , " " , " /* Responsive */" , " @media (max-width: 768px) {" , " .container {" , " padding: 1rem;" , " }" , " h1 {" , " font-size: 1.75rem;" , " }" , " h2 {" , " font-size: 1.25rem;" , " }" , " }" ] -- | JavaScript for generic type hover effects htmlScript :: String htmlScript = unlines [ " document.addEventListener('DOMContentLoaded', function() {" , " const genericTypes = document.querySelectorAll('.generic-type');" , " " , " genericTypes.forEach(function(elem) {" , " elem.addEventListener('mouseenter', function() {" , " const typeName = elem.getAttribute('data-generic');" , " " , " // Check if tooltip would go off-screen at the top" , " const rect = elem.getBoundingClientRect();" , " const tooltipHeight = 200; // Approximate height" , " if (rect.top < tooltipHeight) {" , " elem.classList.add('tooltip-below');" , " } else {" , " elem.classList.remove('tooltip-below');" , " }" , " " , " // Get the scope attribute - all generic types should have this" , " const scope = elem.getAttribute('data-scope');" , " " , " // Only highlight elements with same type name AND same scope" , " document.querySelectorAll('.generic-type[data-generic=\"' + typeName + '\"][data-scope=\"' + scope + '\"]').forEach(function(t) {" , " t.classList.add('highlight');" , " });" , " });" , " " , " elem.addEventListener('mouseleave', function() {" , " const typeName = elem.getAttribute('data-generic');" , " document.querySelectorAll('.generic-type[data-generic=\"' + typeName + '\"].highlight').forEach(function(t) {" , " t.classList.remove('highlight');" , " });" , " });" , " });" , " });" ] -- | Generate HTML documentation from a module with type information docModuleHtmlWithTypes :: NameInfo -> Module -> Doc docModuleHtmlWithTypes (NModule _ tenv mdocstring) (Module modName _ _ stmts) = -- Use module docstring from NModule let moduleDocstring = mdocstring (title, restDoc) = case moduleDocstring of Just ds -> splitDocstring ds Nothing -> ("", Nothing) header = text "

" <> text (render (pretty modName)) <> (if null title then empty else text " - " <> text (htmlEscape title)) <> text "

" bodyDoc = case restDoc of Just body -> text "
" <> text (nl2br $ htmlEscape body) <> text "
" Nothing -> empty -- Collect class info from both local module and type environment classInfos = collectClassInfos modName tenv stmts in header $+$ bodyDoc $+$ docTopLevelHtmlWithTypesAndClassInfo tenv modName classInfos stmts where nl2br = intercalate "
" . lines -- | Collect class information from local module and imported modules collectClassInfos :: ModName -> TEnv -> Suite -> Set ClassInfo collectClassInfos currentModule tenv stmts = let localClasses = Set.map (\n -> ClassInfo n currentModule True) (collectClassNames stmts) importedClasses = Set.fromList $ concatMap extractClassFromTEnv tenv in Set.union localClasses importedClasses where extractClassFromTEnv (n, NClass _ _ _ _) = [ClassInfo n currentModule False] -- Mark as imported extractClassFromTEnv _ = [] -- | Collect all class names defined in the module collectClassNames :: Suite -> Set Name collectClassNames stmts = Set.fromList $ concatMap extractClassNames stmts where extractClassNames :: Stmt -> [Name] extractClassNames (Decl _ decls) = concatMap extractClassNamesFromDecl decls extractClassNames (With _ _ body) = concatMap extractClassNames body extractClassNames _ = [] extractClassNamesFromDecl :: Decl -> [Name] extractClassNamesFromDecl (Class _ n _ _ _ _) = [n] extractClassNamesFromDecl _ = [] -- | Data type to track class locations for cross-module linking data ClassInfo = ClassInfo { ciName :: Name , ciModule :: ModName , ciIsLocal :: Bool -- True if in current module } deriving (Eq, Ord, Show) -- | Build URL for a class reference buildClassUrl :: ModName -> ClassInfo -> String buildClassUrl currentModule ci | ciIsLocal ci = "#class-" ++ render (pretty (ciName ci)) | otherwise = let targetPath = modPath (ciModule ci) currentPath = modPath currentModule relativePath = computeRelativePath currentPath targetPath in relativePath ++ "#class-" ++ render (pretty (ciName ci)) where -- Compute relative path from current module to target module computeRelativePath :: [String] -> [String] -> String computeRelativePath current target = let upLevels = length current - 1 -- -1 because we're in a file, not a directory prefix = concat (replicate upLevels "../") targetFile = intercalate "/" target ++ ".html" in if upLevels == 0 then targetFile else prefix ++ targetFile -- | Compute relative path between two module paths computeRelativeModulePath :: ModName -> ModName -> String computeRelativeModulePath currentModule targetModule = let currentPath = modPath currentModule targetPath = modPath targetModule -- Number of directories to go up from current module -- For modules in the root (length 1), we don't go up any levels -- For nested modules, we go up (length - 1) levels upLevels = if length currentPath > 1 then length currentPath - 1 else 0 prefix = concat (replicate upLevels "../") targetFile = if null targetPath then "index.html" -- Root module else intercalate "/" targetPath ++ ".html" in if upLevels == 0 then targetFile else prefix ++ targetFile -- | Extract and document top-level definitions in HTML docTopLevelHtml :: Suite -> Doc docTopLevelHtml = docTopLevelHtmlWithTypes [] -- | Extract and document top-level definitions in HTML with types docTopLevelHtmlWithTypes :: TEnv -> Suite -> Doc docTopLevelHtmlWithTypes tenv stmts = docTopLevelHtmlWithTypesAndClasses tenv Set.empty stmts -- | Extract and document top-level definitions in HTML with types and class links docTopLevelHtmlWithTypesAndClasses :: TEnv -> Set Name -> Suite -> Doc docTopLevelHtmlWithTypesAndClasses tenv classNames stmts = let docs = concatMap (extractTopLevelHtmlWithTypesAndClasses tenv classNames) stmts separated = case docs of [] -> [] [d] -> [d] (d:ds) -> d : map (blank $+$) ds in vcat separated -- | Extract and document top-level definitions in HTML with types and class info docTopLevelHtmlWithTypesAndClassInfo :: TEnv -> ModName -> Set ClassInfo -> Suite -> Doc docTopLevelHtmlWithTypesAndClassInfo tenv currentModule classInfos stmts = let docs = concatMap (extractTopLevelHtmlWithTypesAndClassInfo tenv currentModule classInfos) stmts separated = case docs of [] -> [] [d] -> [d] (d:ds) -> d : map (blank $+$) ds in vcat separated -- | Extract documentation-worthy top-level statements for HTML extractTopLevelHtml :: Stmt -> [Doc] extractTopLevelHtml = extractTopLevelHtmlWithTypes [] -- | Extract documentation-worthy top-level statements for HTML with types extractTopLevelHtmlWithTypes :: TEnv -> Stmt -> [Doc] extractTopLevelHtmlWithTypes tenv (Decl _ decls) = map (docDeclHtmlWithTypes tenv) decls extractTopLevelHtmlWithTypes tenv (With _ _ body) = concatMap (extractTopLevelHtmlWithTypes tenv) body extractTopLevelHtmlWithTypes _ _ = [] -- | Extract documentation-worthy top-level statements for HTML with types and class links extractTopLevelHtmlWithTypesAndClasses :: TEnv -> Set Name -> Stmt -> [Doc] extractTopLevelHtmlWithTypesAndClasses tenv classNames (Decl _ decls) = map (docDeclHtmlWithTypesAndClasses tenv classNames) decls extractTopLevelHtmlWithTypesAndClasses tenv classNames (With _ _ body) = concatMap (extractTopLevelHtmlWithTypesAndClasses tenv classNames) body extractTopLevelHtmlWithTypesAndClasses _ _ _ = [] -- | Extract documentation-worthy top-level statements for HTML with types and class info extractTopLevelHtmlWithTypesAndClassInfo :: TEnv -> ModName -> Set ClassInfo -> Stmt -> [Doc] extractTopLevelHtmlWithTypesAndClassInfo tenv currentModule classInfos (Decl _ decls) = map (docDeclHtmlWithTypesAndClassInfo tenv currentModule classInfos) decls extractTopLevelHtmlWithTypesAndClassInfo tenv currentModule classInfos (With _ _ body) = concatMap (extractTopLevelHtmlWithTypesAndClassInfo tenv currentModule classInfos) body extractTopLevelHtmlWithTypesAndClassInfo _ _ _ _ = [] -- | Escape HTML special characters htmlEscape :: String -> String htmlEscape [] = [] htmlEscape ('<':xs) = "<" ++ htmlEscape xs htmlEscape ('>':xs) = ">" ++ htmlEscape xs htmlEscape ('&':xs) = "&" ++ htmlEscape xs htmlEscape ('"':xs) = """ ++ htmlEscape xs htmlEscape ('\'':xs) = "'" ++ htmlEscape xs htmlEscape (x:xs) = x : htmlEscape xs -- | Extract generic type names from QBinds extractGenerics :: QBinds -> Set Name extractGenerics binds = Set.fromList [tvname tv | QBind tv _ <- binds] -- | Check if a parameter name is a witness parameter isWitnessParam :: Name -> Bool isWitnessParam n = case nstr n of 'W':'_':rest -> all isDigit rest && not (null rest) _ -> False where isDigit c = c >= '0' && c <= '9' -- | Simplify a qualified name by removing builtin module prefix simplifyQName :: QName -> QName simplifyQName (GName m n) | modPath m == ["__builtin__"] = NoQ n simplifyQName qn = qn -- | Wrapper for simplified type pretty printing newtype SimplifiedType = SimplifiedType Type instance Pretty SimplifiedType where pretty (SimplifiedType t) = prettySimplifiedType t -- | Pretty print a type with simplified qualified names prettySimplifiedType :: Type -> Doc prettySimplifiedType (TVar _ tv) = pretty tv prettySimplifiedType (TCon _ tc) = prettySimplifiedTCon tc prettySimplifiedType (TFun _ _ posrow kwdrow restype) = let args = prettySimplifiedFunArgs posrow kwdrow in if isEmpty args then prettySimplifiedType restype else args <+> text "->" <+> prettySimplifiedType restype prettySimplifiedType (TTuple _ posrow kwdrow) = parens (prettySimplifiedTupleArgs posrow kwdrow) prettySimplifiedType (TOpt _ t) = text "?" <> prettySimplifiedType t prettySimplifiedType (TNone _) = text "None" prettySimplifiedType (TWild _) = text "_" prettySimplifiedType (TNil _ _) = empty prettySimplifiedType (TRow _ _ label rtype rtail) = pretty label <> colon <+> prettySimplifiedType rtype <> case rtail of TNil _ _ -> empty _ -> comma <+> prettySimplifiedType rtail prettySimplifiedType (TStar _ _ rtail) = text "*" <> prettySimplifiedType rtail prettySimplifiedType (TFX _ fx) = pretty fx prettySimplifiedTCon :: TCon -> Doc prettySimplifiedTCon (TC qn ts) | qn == qnList && length ts == 1 = text "list" <> brackets (prettySimplifiedType (head ts)) | qn == qnDict && length ts == 2 = text "dict" <> brackets (prettySimplifiedType (head ts) <> comma <+> prettySimplifiedType (ts !! 1)) | qn == qnSetT && length ts == 1 = text "set" <> brackets (prettySimplifiedType (head ts)) | otherwise = pretty (simplifyQName qn) <> if null ts then empty else brackets (hcat $ punctuate comma [pretty (SimplifiedType t) | t <- ts]) where hcat [] = empty hcat [x] = x hcat (x:xs) = x <> hcat xs prettySimplifiedFunArgs :: PosRow -> KwdRow -> Doc prettySimplifiedFunArgs posrow kwdrow = let posArgs = prettySimplifiedPosRow posrow kwdArgs = prettySimplifiedKwdRow kwdrow in case (isEmpty posArgs, isEmpty kwdArgs) of (True, True) -> empty (False, True) -> parens posArgs (True, False) -> parens kwdArgs (False, False) -> parens (posArgs <> comma <+> kwdArgs) prettySimplifiedTupleArgs :: PosRow -> KwdRow -> Doc prettySimplifiedTupleArgs posrow kwdrow = let posArgs = prettySimplifiedPosRow posrow kwdArgs = prettySimplifiedKwdRow kwdrow in case (isEmpty posArgs, isEmpty kwdArgs) of (True, True) -> empty (False, True) -> posArgs (True, False) -> kwdArgs (False, False) -> posArgs <> comma <+> kwdArgs prettySimplifiedPosRow :: PosRow -> Doc prettySimplifiedPosRow (TNil _ _) = empty prettySimplifiedPosRow (TRow _ _ _ rtype rtail) = prettySimplifiedType rtype <> case rtail of TNil _ _ -> empty _ -> comma <+> prettySimplifiedPosRow rtail prettySimplifiedPosRow (TStar _ _ _) = text "*args" prettySimplifiedPosRow t = prettySimplifiedType t prettySimplifiedKwdRow :: KwdRow -> Doc prettySimplifiedKwdRow (TNil _ _) = empty prettySimplifiedKwdRow (TRow _ _ label rtype rtail) = pretty label <> colon <+> prettySimplifiedType rtype <> case rtail of TNil _ _ -> empty _ -> comma <+> prettySimplifiedKwdRow rtail prettySimplifiedKwdRow (TStar _ _ _) = text "**kwargs" prettySimplifiedKwdRow t = prettySimplifiedType t -- | Render type with generic type highlighting renderTypeWithGenerics :: Set Name -> Type -> String renderTypeWithGenerics generics t = renderTypeWithGenericsAndConstraints generics [] t -- | Render type with generic type highlighting and constraints renderTypeWithGenericsAndConstraints :: Set Name -> QBinds -> Type -> String renderTypeWithGenericsAndConstraints generics constraints t = renderTypeHtml generics constraints t where renderTypeHtml :: Set Name -> QBinds -> Type -> String renderTypeHtml gens cons (TVar _ tv) | Set.member (tvname tv) gens = let nameStr = render (pretty (tvname tv)) -- Find constraints for this type variable tvConstraints = [preds | QBind qtv preds <- cons, tvname qtv == tvname tv] tooltip = case tvConstraints of [] -> "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type." (preds:_) -> if null preds then "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type." else "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type.\n\n" ++ nameStr ++ " must support:\n" ++ concatMap formatPredAsListItem preds formatPredAsListItem p = " • " ++ formatConstraintNameLocal p ++ " protocol (" ++ formatExampleForPredLocal p ++ ")\n" formatConstraintNameLocal (TC qn _) = render . pretty . simplifyQName $ qn formatExampleForPredLocal (TC (NoQ (Name _ "Plus")) _) = "+ operator" formatExampleForPredLocal (TC (NoQ (Name _ "Minus")) _) = "- operator" formatExampleForPredLocal (TC (NoQ (Name _ "Times")) _) = "* operator" formatExampleForPredLocal (TC (NoQ (Name _ "Divide")) _) = "/ operator" formatExampleForPredLocal (TC (NoQ (Name _ "Eq")) _) = "== operator" formatExampleForPredLocal (TC (NoQ (Name _ "Ord")) _) = "< > operators" formatExampleForPredLocal (TC (NoQ (Name _ "Hash")) _) = "hash function" formatExampleForPredLocal _ = "protocol methods" in "" ++ nameStr ++ "" | otherwise = let simplified = render (pretty (SimplifiedType (TVar NoLoc tv))) in if simplified == render (pretty (tvname tv)) then simplified -- Already simplified else simplified renderTypeHtml gens cons (TCon _ tc) = renderTConHtmlSimplified gens cons tc renderTypeHtml gens cons (TFun _ _ posrow kwdrow restype) = let args = renderFunArgs gens cons posrow kwdrow in if null args then renderTypeHtml gens cons restype else args ++ " -> " ++ renderTypeHtml gens cons restype renderTypeHtml gens cons (TTuple _ posrow kwdrow) = "(" ++ renderTupleArgs gens cons posrow kwdrow ++ ")" renderTypeHtml gens cons (TOpt _ t) = "?" ++ renderTypeHtml gens cons t renderTypeHtml gens _ (TNone _) = "None" renderTypeHtml gens _ (TWild _) = "_" renderTypeHtml gens _ (TNil _ _) = "" renderTypeHtml gens cons (TRow _ _ label rtype rtail) = render (pretty label) ++ ": " ++ renderTypeHtml gens cons rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderTypeHtml gens cons rtail renderTypeHtml gens cons (TStar _ _ rtail) = "*" ++ renderTypeHtml gens cons rtail renderTypeHtml gens _ (TFX _ fx) = render (pretty fx) renderTypeHtml gens _ t = render (pretty (SimplifiedType t)) -- Fallback for any other type renderTConHtml :: Set Name -> QBinds -> TCon -> String renderTConHtml gens cons (TC qn ts) | qn == qnList && length ts == 1 = "[" ++ renderTypeHtml gens cons (head ts) ++ "]" | qn == qnDict && length ts == 2 = "{" ++ renderTypeHtml gens cons (head ts) ++ ": " ++ renderTypeHtml gens cons (ts !! 1) ++ "}" | qn == qnSetT && length ts == 1 = "{" ++ renderTypeHtml gens cons (head ts) ++ "}" | otherwise = render (pretty (simplifyQName qn)) ++ if null ts then "" else "[" ++ intercalate ", " (map (renderTypeHtml gens cons) ts) ++ "]" renderTConHtmlSimplified :: Set Name -> QBinds -> TCon -> String renderTConHtmlSimplified gens cons (TC qn ts) | qn == qnList && length ts == 1 = "[" ++ renderTypeHtml gens cons (head ts) ++ "]" | qn == qnDict && length ts == 2 = "{" ++ renderTypeHtml gens cons (head ts) ++ ": " ++ renderTypeHtml gens cons (ts !! 1) ++ "}" | qn == qnSetT && length ts == 1 = "{" ++ renderTypeHtml gens cons (head ts) ++ "}" | otherwise = render (pretty (SimplifiedType (TCon NoLoc (TC qn ts)))) renderFunArgs :: Set Name -> QBinds -> PosRow -> KwdRow -> String renderFunArgs gens cons posrow kwdrow = let posArgs = renderPosRow gens cons posrow kwdArgs = renderKwdRow gens cons kwdrow in case (posArgs, kwdArgs) of ("", "") -> "" (p, "") -> "(" ++ p ++ ")" ("", k) -> "(" ++ k ++ ")" (p, k) -> "(" ++ p ++ ", " ++ k ++ ")" renderTupleArgs :: Set Name -> QBinds -> PosRow -> KwdRow -> String renderTupleArgs gens cons posrow kwdrow = let posArgs = renderPosRow gens cons posrow kwdArgs = renderKwdRow gens cons kwdrow in case (posArgs, kwdArgs) of ("", "") -> "" (p, "") -> p ("", k) -> k (p, k) -> p ++ ", " ++ k renderPosRow :: Set Name -> QBinds -> PosRow -> String renderPosRow gens _ (TNil _ _) = "" renderPosRow gens cons (TRow _ _ _ rtype rtail) = renderTypeHtml gens cons rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderPosRow gens cons rtail renderPosRow gens _ (TStar _ _ _) = "*args" renderPosRow gens cons t = renderTypeHtml gens cons t renderKwdRow :: Set Name -> QBinds -> KwdRow -> String renderKwdRow gens _ (TNil _ _) = "" renderKwdRow gens cons (TRow _ _ label rtype rtail) = render (pretty label) ++ "=" ++ renderTypeHtml gens cons rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderKwdRow gens cons rtail renderKwdRow gens _ (TStar _ _ _) = "**kwargs" renderKwdRow gens cons t = renderTypeHtml gens cons t -- | Render type with generic type highlighting, constraints and class links (with current module for relative paths) renderTypeWithGenericsConstraintsAndClassesAndModule :: ModName -> Set Name -> QBinds -> Set Name -> Type -> String renderTypeWithGenericsConstraintsAndClassesAndModule currentModule generics constraints classNames t = renderTypeHtmlWithClassesAndModule currentModule generics constraints classNames t where renderTypeHtmlWithClassesAndModule :: ModName -> Set Name -> QBinds -> Set Name -> Type -> String renderTypeHtmlWithClassesAndModule curMod gens cons classes (TVar _ tv) | Set.member (tvname tv) gens = let nameStr = render (pretty (tvname tv)) -- Find constraints for this type variable tvConstraints = [preds | QBind qtv preds <- cons, tvname qtv == tvname tv] tooltip = case tvConstraints of [] -> "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type." (preds:_) -> if null preds then "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type." else "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type.\n\n" ++ nameStr ++ " must support:\n" ++ concatMap formatPredAsListItem preds formatPredAsListItem p = " • " ++ formatConstraintNameLocal p ++ " protocol (" ++ formatExampleForPredLocal p ++ ")\n" formatConstraintNameLocal (TC qn _) = render . pretty . simplifyQName $ qn formatExampleForPredLocal (TC (NoQ (Name _ "Plus")) _) = "+ operator" formatExampleForPredLocal (TC (NoQ (Name _ "Minus")) _) = "- operator" formatExampleForPredLocal (TC (NoQ (Name _ "Times")) _) = "* operator" formatExampleForPredLocal (TC (NoQ (Name _ "Divide")) _) = "/ operator" formatExampleForPredLocal (TC (NoQ (Name _ "Eq")) _) = "== operator" formatExampleForPredLocal (TC (NoQ (Name _ "Ord")) _) = "< > operators" formatExampleForPredLocal (TC (NoQ (Name _ "Hash")) _) = "hash function" formatExampleForPredLocal _ = "protocol methods" in "" ++ nameStr ++ "" | otherwise = let simplified = render (pretty (SimplifiedType (TVar NoLoc tv))) in if simplified == render (pretty (tvname tv)) then simplified -- Already simplified else simplified renderTypeHtmlWithClassesAndModule curMod gens cons classes (TCon _ tc) = renderTConHtmlSimplifiedWithClassesAndModule curMod gens cons classes tc renderTypeHtmlWithClassesAndModule curMod gens cons classes (TFun _ _ posrow kwdrow restype) = let args = renderFunArgsWithClassesAndModule curMod gens cons classes posrow kwdrow in if null args then renderTypeHtmlWithClassesAndModule curMod gens cons classes restype else args ++ " -> " ++ renderTypeHtmlWithClassesAndModule curMod gens cons classes restype renderTypeHtmlWithClassesAndModule curMod gens cons classes (TTuple _ posrow kwdrow) = "(" ++ renderTupleArgsWithClassesAndModule curMod gens cons classes posrow kwdrow ++ ")" renderTypeHtmlWithClassesAndModule curMod gens cons classes (TOpt _ t) = "?" ++ renderTypeHtmlWithClassesAndModule curMod gens cons classes t renderTypeHtmlWithClassesAndModule _ gens _ _ (TNone _) = "None" renderTypeHtmlWithClassesAndModule _ gens _ _ (TWild _) = "_" renderTypeHtmlWithClassesAndModule _ gens _ _ (TNil _ _) = "" renderTypeHtmlWithClassesAndModule curMod gens cons classes (TRow _ _ label rtype rtail) = render (pretty label) ++ ": " ++ renderTypeHtmlWithClassesAndModule curMod gens cons classes rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderTypeHtmlWithClassesAndModule curMod gens cons classes rtail renderTypeHtmlWithClassesAndModule curMod gens cons classes (TStar _ _ rtail) = "*" ++ renderTypeHtmlWithClassesAndModule curMod gens cons classes rtail renderTypeHtmlWithClassesAndModule _ gens _ _ (TFX _ fx) = render (pretty fx) renderTypeHtmlWithClassesAndModule curMod gens _ classes t = render (pretty (SimplifiedType t)) -- Fallback for any other type renderTConHtmlSimplifiedWithClassesAndModule :: ModName -> Set Name -> QBinds -> Set Name -> TCon -> String renderTConHtmlSimplifiedWithClassesAndModule curMod gens cons classes (TC qn ts) | qn == qnList && length ts == 1 = "[" ++ renderTypeHtmlWithClassesAndModule curMod gens cons classes (head ts) ++ "]" | qn == qnDict && length ts == 2 = "{" ++ renderTypeHtmlWithClassesAndModule curMod gens cons classes (head ts) ++ ": " ++ renderTypeHtmlWithClassesAndModule curMod gens cons classes (ts !! 1) ++ "}" | qn == qnSetT && length ts == 1 = "{" ++ renderTypeHtmlWithClassesAndModule curMod gens cons classes (head ts) ++ "}" | otherwise = let simpleName = simplifyQName qn nameStr = render (pretty simpleName) -- Generate link based on qualified name with relative paths linkStr = case qn of NoQ n -> if Set.member n classes then "
" ++ nameStr ++ "" else nameStr QName m n -> -- This is a qualified name from another module let relativePath = computeRelativeModulePath curMod m url = relativePath ++ "#class-" ++ render (pretty n) in "" ++ nameStr ++ "" GName m n -> -- Global name (e.g., from __builtin__) let modPathList = modPath m in if modPathList == ["__builtin__"] then nameStr -- Don't link builtin types else let relativePath = computeRelativeModulePath curMod m url = relativePath ++ "#class-" ++ render (pretty n) in "" ++ nameStr ++ "" in linkStr ++ if null ts then "" else "[" ++ intercalate ", " (map (renderTypeHtmlWithClassesAndModule curMod gens cons classes) ts) ++ "]" renderFunArgsWithClassesAndModule :: ModName -> Set Name -> QBinds -> Set Name -> PosRow -> KwdRow -> String renderFunArgsWithClassesAndModule curMod gens cons classes posrow kwdrow = let posArgs = renderPosRowWithClassesAndModule curMod gens cons classes posrow kwdArgs = renderKwdRowWithClassesAndModule curMod gens cons classes kwdrow in case (posArgs, kwdArgs) of ("", "") -> "" (p, "") -> "(" ++ p ++ ")" ("", k) -> "(" ++ k ++ ")" (p, k) -> "(" ++ p ++ ", " ++ k ++ ")" renderTupleArgsWithClassesAndModule :: ModName -> Set Name -> QBinds -> Set Name -> PosRow -> KwdRow -> String renderTupleArgsWithClassesAndModule curMod gens cons classes posrow kwdrow = let posArgs = renderPosRowWithClassesAndModule curMod gens cons classes posrow kwdArgs = renderKwdRowWithClassesAndModule curMod gens cons classes kwdrow in case (posArgs, kwdArgs) of ("", "") -> "" (p, "") -> p ("", k) -> k (p, k) -> p ++ ", " ++ k renderPosRowWithClassesAndModule :: ModName -> Set Name -> QBinds -> Set Name -> PosRow -> String renderPosRowWithClassesAndModule _ _ _ _ (TNil _ _) = "" renderPosRowWithClassesAndModule curMod gens cons classes (TRow _ _ _ rtype rtail) = renderTypeHtmlWithClassesAndModule curMod gens cons classes rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderPosRowWithClassesAndModule curMod gens cons classes rtail renderPosRowWithClassesAndModule _ _ _ _ (TStar _ _ _) = "*args" renderPosRowWithClassesAndModule curMod gens cons classes t = renderTypeHtmlWithClassesAndModule curMod gens cons classes t renderKwdRowWithClassesAndModule :: ModName -> Set Name -> QBinds -> Set Name -> KwdRow -> String renderKwdRowWithClassesAndModule _ _ _ _ (TNil _ _) = "" renderKwdRowWithClassesAndModule curMod gens cons classes (TRow _ _ label rtype rtail) = render (pretty label) ++ "=" ++ renderTypeHtmlWithClassesAndModule curMod gens cons classes rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderKwdRowWithClassesAndModule curMod gens cons classes rtail renderKwdRowWithClassesAndModule _ _ _ _ (TStar _ _ _) = "**kwargs" renderKwdRowWithClassesAndModule curMod gens cons classes t = renderTypeHtmlWithClassesAndModule curMod gens cons classes t -- | Render type with generic type highlighting, constraints, class links and scope renderTypeWithGenericsConstraintsClassesModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> Type -> String renderTypeWithGenericsConstraintsClassesModuleAndScope currentModule generics constraints classNames scope t = renderTypeHtmlWithClassesModuleAndScope currentModule generics constraints classNames scope t where renderTypeHtmlWithClassesModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> Type -> String renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (TVar _ tv) | Set.member (tvname tv) gens = let nameStr = render (pretty (tvname tv)) -- Find constraints for this type variable tvConstraints = [preds | QBind qtv preds <- cons, tvname qtv == tvname tv] tooltip = case tvConstraints of [] -> "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type." (preds:_) -> if null preds then "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type." else "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type.\n\n" ++ nameStr ++ " must support:\n" ++ concatMap formatPredAsListItem preds formatPredAsListItem p = " • " ++ formatConstraintNameLocal p ++ " protocol (" ++ formatExampleForPredLocal p ++ ")\n" formatConstraintNameLocal (TC qn _) = render . pretty . simplifyQName $ qn formatExampleForPredLocal (TC (NoQ (Name _ "Plus")) _) = "+ operator" formatExampleForPredLocal (TC (NoQ (Name _ "Minus")) _) = "- operator" formatExampleForPredLocal (TC (NoQ (Name _ "Times")) _) = "* operator" formatExampleForPredLocal (TC (NoQ (Name _ "Divide")) _) = "/ operator" formatExampleForPredLocal (TC (NoQ (Name _ "Eq")) _) = "== operator" formatExampleForPredLocal (TC (NoQ (Name _ "Ord")) _) = "< > operators" formatExampleForPredLocal (TC (NoQ (Name _ "Hash")) _) = "hash function" formatExampleForPredLocal _ = "protocol methods" in "" ++ nameStr ++ "" | otherwise = let simplified = render (pretty (SimplifiedType (TVar NoLoc tv))) in if simplified == render (pretty (tvname tv)) then simplified -- Already simplified else simplified renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (TCon _ tc) = renderTConHtmlSimplifiedWithClassesModuleAndScope curMod gens cons classes scope tc renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (TFun _ _ posrow kwdrow restype) = let args = renderFunArgsWithClassesModuleAndScope curMod gens cons classes scope posrow kwdrow in if null args then renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope restype else args ++ " -> " ++ renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope restype renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (TTuple _ posrow kwdrow) = "(" ++ renderTupleArgsWithClassesModuleAndScope curMod gens cons classes scope posrow kwdrow ++ ")" renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (TOpt _ t) = "?" ++ renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope t renderTypeHtmlWithClassesModuleAndScope _ _ _ _ _ (TNone _) = "None" renderTypeHtmlWithClassesModuleAndScope _ _ _ _ _ (TWild _) = "_" renderTypeHtmlWithClassesModuleAndScope _ _ _ _ _ (TNil _ _) = "" renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (TRow _ _ label rtype rtail) = render (pretty label) ++ ": " ++ renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope rtail renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (TStar _ _ rtail) = "*" ++ renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope rtail renderTypeHtmlWithClassesModuleAndScope _ _ _ _ _ (TFX _ fx) = render (pretty fx) renderTypeHtmlWithClassesModuleAndScope curMod gens _ classes scope t = render (pretty (SimplifiedType t)) -- Fallback for any other type renderTConHtmlSimplifiedWithClassesModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> TCon -> String renderTConHtmlSimplifiedWithClassesModuleAndScope curMod gens cons classes scope (TC qn ts) | qn == qnList && length ts == 1 = "[" ++ renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (head ts) ++ "]" | qn == qnDict && length ts == 2 = "{" ++ renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (head ts) ++ ": " ++ renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (ts !! 1) ++ "}" | qn == qnSetT && length ts == 1 = "{" ++ renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope (head ts) ++ "}" | otherwise = let simpleName = simplifyQName qn nameStr = render (pretty simpleName) -- Generate link based on qualified name with relative paths linkStr = case qn of NoQ n -> if Set.member n classes then "" ++ nameStr ++ "" else nameStr QName m n -> -- This is a qualified name from another module let relativePath = computeRelativeModulePath curMod m url = relativePath ++ "#class-" ++ render (pretty n) in "" ++ nameStr ++ "" GName m n -> -- Global name (e.g., from __builtin__) let modPathList = modPath m in if modPathList == ["__builtin__"] then nameStr -- Don't link builtin types else let relativePath = computeRelativeModulePath curMod m url = relativePath ++ "#class-" ++ render (pretty n) in "" ++ nameStr ++ "" in linkStr ++ if null ts then "" else "[" ++ intercalate ", " (map (renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope) ts) ++ "]" renderFunArgsWithClassesModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> PosRow -> KwdRow -> String renderFunArgsWithClassesModuleAndScope curMod gens cons classes scope posrow kwdrow = let posArgs = renderPosRowWithClassesModuleAndScope curMod gens cons classes scope posrow kwdArgs = renderKwdRowWithClassesModuleAndScope curMod gens cons classes scope kwdrow in case (posArgs, kwdArgs) of ("", "") -> "" (p, "") -> "(" ++ p ++ ")" ("", k) -> "(" ++ k ++ ")" (p, k) -> "(" ++ p ++ ", " ++ k ++ ")" renderTupleArgsWithClassesModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> PosRow -> KwdRow -> String renderTupleArgsWithClassesModuleAndScope curMod gens cons classes scope posrow kwdrow = let posArgs = renderPosRowWithClassesModuleAndScope curMod gens cons classes scope posrow kwdArgs = renderKwdRowWithClassesModuleAndScope curMod gens cons classes scope kwdrow in case (posArgs, kwdArgs) of ("", "") -> "" (p, "") -> p ("", k) -> k (p, k) -> p ++ ", " ++ k renderPosRowWithClassesModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> PosRow -> String renderPosRowWithClassesModuleAndScope _ _ _ _ _ (TNil _ _) = "" renderPosRowWithClassesModuleAndScope curMod gens cons classes scope (TRow _ _ _ rtype rtail) = renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderPosRowWithClassesModuleAndScope curMod gens cons classes scope rtail renderPosRowWithClassesModuleAndScope _ _ _ _ _ (TStar _ _ _) = "*args" renderPosRowWithClassesModuleAndScope curMod gens cons classes scope t = renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope t renderKwdRowWithClassesModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> KwdRow -> String renderKwdRowWithClassesModuleAndScope _ _ _ _ _ (TNil _ _) = "" renderKwdRowWithClassesModuleAndScope curMod gens cons classes scope (TRow _ _ label rtype rtail) = render (pretty label) ++ "=" ++ renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderKwdRowWithClassesModuleAndScope curMod gens cons classes scope rtail renderKwdRowWithClassesModuleAndScope _ _ _ _ _ (TStar _ _ _) = "**kwargs" renderKwdRowWithClassesModuleAndScope curMod gens cons classes scope t = renderTypeHtmlWithClassesModuleAndScope curMod gens cons classes scope t -- | Render type with generic type highlighting, constraints and class links renderTypeWithGenericsConstraintsAndClasses :: Set Name -> QBinds -> Set Name -> Type -> String renderTypeWithGenericsConstraintsAndClasses generics constraints classNames t = renderTypeHtmlWithClasses generics constraints classNames t where renderTypeHtmlWithClasses :: Set Name -> QBinds -> Set Name -> Type -> String renderTypeHtmlWithClasses gens cons classes (TVar _ tv) | Set.member (tvname tv) gens = let nameStr = render (pretty (tvname tv)) -- Find constraints for this type variable tvConstraints = [preds | QBind qtv preds <- cons, tvname qtv == tvname tv] tooltip = case tvConstraints of [] -> "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type." (preds:_) -> if null preds then "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type." else "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type.\n\n" ++ nameStr ++ " must support:\n" ++ concatMap formatPredAsListItem preds formatPredAsListItem p = " • " ++ formatConstraintNameLocal p ++ " protocol (" ++ formatExampleForPredLocal p ++ ")\n" formatConstraintNameLocal (TC qn _) = render . pretty . simplifyQName $ qn formatExampleForPredLocal (TC (NoQ (Name _ "Plus")) _) = "+ operator" formatExampleForPredLocal (TC (NoQ (Name _ "Minus")) _) = "- operator" formatExampleForPredLocal (TC (NoQ (Name _ "Times")) _) = "* operator" formatExampleForPredLocal (TC (NoQ (Name _ "Divide")) _) = "/ operator" formatExampleForPredLocal (TC (NoQ (Name _ "Eq")) _) = "== operator" formatExampleForPredLocal (TC (NoQ (Name _ "Ord")) _) = "< > operators" formatExampleForPredLocal (TC (NoQ (Name _ "Hash")) _) = "hash function" formatExampleForPredLocal _ = "protocol methods" in "" ++ nameStr ++ "" | otherwise = let simplified = render (pretty (SimplifiedType (TVar NoLoc tv))) in if simplified == render (pretty (tvname tv)) then simplified -- Already simplified else simplified renderTypeHtmlWithClasses gens cons classes (TCon _ tc) = renderTConHtmlSimplifiedWithClasses gens cons classes tc renderTypeHtmlWithClasses gens cons classes (TFun _ _ posrow kwdrow restype) = let args = renderFunArgsWithClasses gens cons classes posrow kwdrow in if null args then renderTypeHtmlWithClasses gens cons classes restype else args ++ " -> " ++ renderTypeHtmlWithClasses gens cons classes restype renderTypeHtmlWithClasses gens cons classes (TTuple _ posrow kwdrow) = "(" ++ renderTupleArgsWithClasses gens cons classes posrow kwdrow ++ ")" renderTypeHtmlWithClasses gens cons classes (TOpt _ t) = "?" ++ renderTypeHtmlWithClasses gens cons classes t renderTypeHtmlWithClasses gens _ _ (TNone _) = "None" renderTypeHtmlWithClasses gens _ _ (TWild _) = "_" renderTypeHtmlWithClasses gens _ _ (TNil _ _) = "" renderTypeHtmlWithClasses gens cons classes (TRow _ _ label rtype rtail) = render (pretty label) ++ ": " ++ renderTypeHtmlWithClasses gens cons classes rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderTypeHtmlWithClasses gens cons classes rtail renderTypeHtmlWithClasses gens cons classes (TStar _ _ rtail) = "*" ++ renderTypeHtmlWithClasses gens cons classes rtail renderTypeHtmlWithClasses gens _ _ (TFX _ fx) = render (pretty fx) renderTypeHtmlWithClasses gens _ classes t = render (pretty (SimplifiedType t)) -- Fallback for any other type renderTConHtmlSimplifiedWithClasses :: Set Name -> QBinds -> Set Name -> TCon -> String renderTConHtmlSimplifiedWithClasses gens cons classes (TC qn ts) | qn == qnList && length ts == 1 = "[" ++ renderTypeHtmlWithClasses gens cons classes (head ts) ++ "]" | qn == qnDict && length ts == 2 = "{" ++ renderTypeHtmlWithClasses gens cons classes (head ts) ++ ": " ++ renderTypeHtmlWithClasses gens cons classes (ts !! 1) ++ "}" | qn == qnSetT && length ts == 1 = "{" ++ renderTypeHtmlWithClasses gens cons classes (head ts) ++ "}" | otherwise = let simpleName = simplifyQName qn nameStr = render (pretty simpleName) -- Generate link based on qualified name linkStr = case qn of NoQ n -> if Set.member n classes then "" ++ nameStr ++ "" else nameStr QName m n -> -- This is a qualified name from another module let modPathList = modPath m modPathStr = intercalate "/" modPathList modFile = if null modPathStr then "index.html" -- Root module else modPathStr ++ ".html" url = modFile ++ "#class-" ++ render (pretty n) in "" ++ nameStr ++ "" GName m n -> -- Global name (e.g., from __builtin__) let modPathList = modPath m in if modPathList == ["__builtin__"] then nameStr -- Don't link builtin types else let modPathStr = intercalate "/" modPathList modFile = if null modPathStr then "index.html" else modPathStr ++ ".html" url = modFile ++ "#class-" ++ render (pretty n) in "" ++ nameStr ++ "" in linkStr ++ if null ts then "" else "[" ++ intercalate ", " (map (renderTypeHtmlWithClasses gens cons classes) ts) ++ "]" renderFunArgsWithClasses :: Set Name -> QBinds -> Set Name -> PosRow -> KwdRow -> String renderFunArgsWithClasses gens cons classes posrow kwdrow = let posArgs = renderPosRowWithClasses gens cons classes posrow kwdArgs = renderKwdRowWithClasses gens cons classes kwdrow in case (posArgs, kwdArgs) of ("", "") -> "" (p, "") -> "(" ++ p ++ ")" ("", k) -> "(" ++ k ++ ")" (p, k) -> "(" ++ p ++ ", " ++ k ++ ")" renderTupleArgsWithClasses :: Set Name -> QBinds -> Set Name -> PosRow -> KwdRow -> String renderTupleArgsWithClasses gens cons classes posrow kwdrow = let posArgs = renderPosRowWithClasses gens cons classes posrow kwdArgs = renderKwdRowWithClasses gens cons classes kwdrow in case (posArgs, kwdArgs) of ("", "") -> "" (p, "") -> p ("", k) -> k (p, k) -> p ++ ", " ++ k renderPosRowWithClasses :: Set Name -> QBinds -> Set Name -> PosRow -> String renderPosRowWithClasses gens _ _ (TNil _ _) = "" renderPosRowWithClasses gens cons classes (TRow _ _ _ rtype rtail) = renderTypeHtmlWithClasses gens cons classes rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderPosRowWithClasses gens cons classes rtail renderPosRowWithClasses gens _ _ (TStar _ _ _) = "*args" renderPosRowWithClasses gens cons classes t = renderTypeHtmlWithClasses gens cons classes t renderKwdRowWithClasses :: Set Name -> QBinds -> Set Name -> KwdRow -> String renderKwdRowWithClasses gens _ _ (TNil _ _) = "" renderKwdRowWithClasses gens cons classes (TRow _ _ label rtype rtail) = render (pretty label) ++ "=" ++ renderTypeHtmlWithClasses gens cons classes rtype ++ case rtail of TNil _ _ -> "" _ -> ", " ++ renderKwdRowWithClasses gens cons classes rtail renderKwdRowWithClasses gens _ _ (TStar _ _ _) = "**kwargs" renderKwdRowWithClasses gens cons classes t = renderTypeHtmlWithClasses gens cons classes t -- | Helper function to enrich parameter display with inferred types and constraints enrichParamsWithTypesHtml :: Set Name -> QBinds -> PosRow -> KwdRow -> PosPar -> KwdPar -> Doc enrichParamsWithTypesHtml generics constraints posRow kwdRow p k = let posParams = enrichPosParamsHtml generics constraints posRow p kwdParams = enrichKwdParamsHtml generics constraints kwdRow k sep = if isEmpty posParams || isEmpty kwdParams then empty else text ", " in text "(" <> posParams <> sep <> kwdParams <> text ")" -- | Helper function to enrich parameter display with inferred types, constraints and class links enrichParamsWithTypesHtmlAndClasses :: Set Name -> QBinds -> Set Name -> PosRow -> KwdRow -> PosPar -> KwdPar -> Doc enrichParamsWithTypesHtmlAndClasses generics constraints classNames posRow kwdRow p k = let posParams = enrichPosParamsHtmlWithClasses generics constraints classNames posRow p kwdParams = enrichKwdParamsHtmlWithClasses generics constraints classNames kwdRow k sep = if isEmpty posParams || isEmpty kwdParams then empty else text ", " in text "(" <> posParams <> sep <> kwdParams <> text ")" enrichPosParamsHtml :: Set Name -> QBinds -> PosRow -> PosPar -> Doc enrichPosParamsHtml _ _ _ PosNIL = empty enrichPosParamsHtml generics constraints posRow (PosPar n t e p) = -- Skip witness parameters if isWitnessParam n then enrichPosParamsHtml generics constraints (advanceRow posRow) p else let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t param = text "" <> pretty n <> text "" <> formatTypeHtmlWithGenericsAndConstraints generics constraints paramType <> formatDefaultHtml e nextParams = enrichPosParamsHtml generics constraints (advanceRow posRow) p in if isEmpty nextParams then param else param <> text ", " <> nextParams enrichPosParamsHtml generics constraints _ (PosSTAR n t) = text "*" <> pretty n <> text "" <> formatTypeHtmlWithGenericsAndConstraints generics constraints t enrichKwdParamsHtml :: Set Name -> QBinds -> KwdRow -> KwdPar -> Doc enrichKwdParamsHtml _ _ _ KwdNIL = empty enrichKwdParamsHtml generics constraints kwdRow (KwdPar n t e k) = let inferredType = extractParamTypeFromRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t param = text "" <> pretty n <> text "" <> formatTypeHtmlWithGenericsAndConstraints generics constraints paramType <> formatDefaultHtml e in case k of KwdNIL -> param _ -> param <> text ", " <> enrichKwdParamsHtml generics constraints kwdRow k enrichKwdParamsHtml generics constraints _ (KwdSTAR n t) = text "**" <> pretty n <> text "" <> formatTypeHtmlWithGenericsAndConstraints generics constraints t enrichPosParamsHtmlWithClasses :: Set Name -> QBinds -> Set Name -> PosRow -> PosPar -> Doc enrichPosParamsHtmlWithClasses _ _ _ _ PosNIL = empty enrichPosParamsHtmlWithClasses generics constraints classNames posRow (PosPar n t e p) = -- Skip witness parameters if isWitnessParam n then enrichPosParamsHtmlWithClasses generics constraints classNames (advanceRow posRow) p else let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t param = text "" <> pretty n <> text "" <> formatTypeHtmlWithGenericsConstraintsAndClasses generics constraints classNames paramType <> formatDefaultHtml e nextParams = enrichPosParamsHtmlWithClasses generics constraints classNames (advanceRow posRow) p in if isEmpty nextParams then param else param <> text ", " <> nextParams enrichPosParamsHtmlWithClasses generics constraints classNames _ (PosSTAR n t) = text "*" <> pretty n <> text "" <> formatTypeHtmlWithGenericsConstraintsAndClasses generics constraints classNames t enrichKwdParamsHtmlWithClasses :: Set Name -> QBinds -> Set Name -> KwdRow -> KwdPar -> Doc enrichKwdParamsHtmlWithClasses _ _ _ _ KwdNIL = empty enrichKwdParamsHtmlWithClasses generics constraints classNames kwdRow (KwdPar n t e k) = let inferredType = extractParamTypeFromRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t param = text "" <> pretty n <> text "" <> formatTypeHtmlWithGenericsConstraintsAndClasses generics constraints classNames paramType <> formatDefaultHtml e in case k of KwdNIL -> param _ -> param <> text ", " <> enrichKwdParamsHtmlWithClasses generics constraints classNames kwdRow k enrichKwdParamsHtmlWithClasses generics constraints classNames _ (KwdSTAR n t) = text "**" <> pretty n <> text "" <> formatTypeHtmlWithGenericsConstraintsAndClasses generics constraints classNames t -- Extract parameter type from row extractParamTypeFromRow :: String -> Type -> Maybe Type extractParamTypeFromRow _ (TNil _ _) = Nothing extractParamTypeFromRow name (TRow _ _ n t rest) | nstr n == name = Just t | otherwise = extractParamTypeFromRow name rest extractParamTypeFromRow _ _ = Nothing -- Advance to next position in row advanceRow :: Type -> Type advanceRow (TRow _ _ _ _ rest) = rest advanceRow t = t -- Extract parameter type from keyword row extractParamTypeFromKwdRow :: String -> Type -> Maybe Type extractParamTypeFromKwdRow _ (TNil _ _) = Nothing extractParamTypeFromKwdRow name (TRow _ _ n t rest) | nstr n == name = Just t | otherwise = extractParamTypeFromKwdRow name rest extractParamTypeFromKwdRow _ _ = Nothing -- | Document a declaration in HTML format docDeclHtml :: Decl -> Doc docDeclHtml = docDeclHtmlWithTypes [] -- | Document a declaration in HTML format with type information docDeclHtmlWithTypes :: TEnv -> Decl -> Doc docDeclHtmlWithTypes tenv = docDeclHtmlWithTypesAndClasses tenv Set.empty -- | Document a declaration in HTML format with type information and class links -- | Document a declaration in HTML with types and class info for cross-module linking docDeclHtmlWithTypesAndClassInfo :: TEnv -> ModName -> Set ClassInfo -> Decl -> Doc docDeclHtmlWithTypesAndClassInfo tenv currentModule classInfos decl = let classNames = Set.map ciName $ Set.filter ciIsLocal classInfos in docDeclHtmlWithTypesAndClassesAndModule tenv currentModule classNames decl -- | Document a declaration in HTML with module context for proper cross-module links docDeclHtmlWithTypesAndClassesAndModule :: TEnv -> ModName -> Set Name -> Decl -> Doc docDeclHtmlWithTypesAndClassesAndModule tenv currentModule classNames decl = -- Update all type rendering to use the module-aware version case decl of Def _ n q p k a b d x ddoc -> docDefHtmlWithModule tenv currentModule classNames n q p k a b d ddoc Actor _ n q p k b ddoc -> docActorHtmlWithModule tenv currentModule classNames n q p k b ddoc Class _ n q a b ddoc -> let wtcons = map (\tc -> ([], tc)) a -- PCon is just a type alias for TCon in docClassHtmlWithModule tenv currentModule classNames n q wtcons b ddoc Protocol _ n q a b ddoc -> let wtcons = map (\pc -> ([], pc)) a in docProtocolHtmlWithModule tenv currentModule classNames n q wtcons b ddoc Extension _ q c a b ddoc -> let wtcons = map (\pc -> ([], pc)) a in docExtensionHtmlWithModule tenv currentModule classNames q c wtcons b ddoc where docDefHtmlWithModule tenv curMod classNames n q p k a b d ddoc = let explicitGenerics = extractGenerics q funcScope = "def-" ++ nstr n -- Look up inferred type information (inferredType, qConstraints) = case lookup n tenv of Just (NDef schema _ _) -> (Just schema, getQBindsFromSchema schema) Just (NSig schema _ _) -> (Just schema, getQBindsFromSchema schema) _ -> (Nothing, []) -- Create a mapping from ugly type vars to nice generic names uglyTypeVarsFromQBinds = collectUglyTypeVars qConstraints uglyTypeVarsFromType = case inferredType of Just (TSchema _ _ t) -> collectUglyTypeVarsFromType t _ -> [] allUglyTypeVars = nub (uglyTypeVarsFromQBinds ++ uglyTypeVarsFromType) typeVarMapping = createTypeVarMapping allUglyTypeVars -- Process the type information with cleanup (paramsWithTypes, inferredRetType, constraints, allGenerics) = case inferredType of Just (TSchema _ qConstraints (TFun _ _ posRow kwdRow retType)) -> let cleanPosRow = cleanupTypeVars typeVarMapping posRow cleanKwdRow = cleanupTypeVars typeVarMapping kwdRow cleanRetType = cleanupTypeVars typeVarMapping retType cleanConstraints = cleanupQBinds typeVarMapping qConstraints inferredGenerics = extractGenerics cleanConstraints mappedGenerics = if null q && not (null typeVarMapping) then Set.fromList (map snd typeVarMapping) else explicitGenerics combinedGenerics = Set.union mappedGenerics inferredGenerics in (enrichParamsWithTypesHtmlAndClassesModuleAndScope curMod combinedGenerics cleanConstraints classNames funcScope cleanPosRow cleanKwdRow p k, Just cleanRetType, cleanConstraints, combinedGenerics) _ -> (docParamsHtmlWithGenericsAndClassesModuleAndScope curMod explicitGenerics classNames funcScope p k, a, [], explicitGenerics) -- Use inferred return type if available, otherwise use annotation actualRetType = case inferredRetType of Just t -> docRetTypeHtmlWithGenericsConstraintsAndClassesModuleAndScope curMod allGenerics constraints classNames funcScope (Just t) Nothing -> docRetTypeHtmlWithGenericsConstraintsAndClassesModuleAndScope curMod allGenerics constraints classNames funcScope a -- Format constraints if present, or generics if no constraints (constraintsDoc, genericsDoc) = if null constraints then (empty, docGenericsHtmlWithHighlightAndScope allGenerics funcScope q) else (docConstraintsHtmlWithScope allGenerics funcScope constraints <> text " => ", empty) header = text "

" <> pretty n <> text "" <> constraintsDoc <> genericsDoc <> paramsWithTypes <> actualRetType <> text "

" docstr = case ddoc of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty in header $+$ docstr docActorHtmlWithModule tenv curMod classNames n q p k b ddoc = let explicitGenerics = extractGenerics q -- Look up inferred type information for actors (paramsWithTypes, allGenerics, constraints) = case lookup n tenv of Just (NAct qConstraints posRow kwdRow _ _) -> let inferredGenerics = extractGenerics qConstraints combinedGenerics = Set.union explicitGenerics inferredGenerics in (enrichParamsWithTypesHtmlAndClassesModule curMod combinedGenerics qConstraints classNames posRow kwdRow p k, combinedGenerics, qConstraints) _ -> (docParamsHtmlWithGenericsAndClassesModule curMod explicitGenerics classNames p k, explicitGenerics, []) -- Always use docConstraintsHtml for rich tooltips - it handles both constrained and unconstrained generics genericsDoc = if null q && null constraints then empty -- No generics at all else if null constraints then docConstraintsHtml allGenerics q else docConstraintsHtml allGenerics constraints header = text "

actor " <> pretty n <> text "" <> genericsDoc <> paramsWithTypes <> text "

" docstr = case ddoc of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty -- Process actor body to extract public constants, internal attributes and methods body = docActorBodyHtmlWithGenericsTypesAndClassesModule tenv curMod allGenerics classNames b in text "
" $+$ header $+$ docstr $+$ (if isEmpty body then empty else blank $+$ body) $+$ text "
" docClassHtmlWithModule tenv curMod classNames n q a b ddoc = let generics = extractGenerics q -- Always use docConstraintsHtml for rich tooltips - it handles both constrained and unconstrained generics classScope = "class-" ++ nstr n genericsDoc = if null q then empty -- No generics at all else docConstraintsHtmlWithScope generics classScope q header = text "

text (nstr n) <> text "\" class=\"type-context\">class " <> pretty n <> text "" <> genericsDoc <> docAncestorsHtmlWithGenericsAndClassesModule curMod generics classNames a <> text "

" docstr = case ddoc of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty methods = docClassBodyHtmlWithGenericsTypesAndClassesModule tenv curMod generics classNames b in text "
" $+$ header $+$ docstr $+$ (if isEmpty methods then empty else blank $+$ methods) $+$ text "
" docProtocolHtmlWithModule tenv curMod classNames n q a b ddoc = let generics = extractGenerics q -- Always use docConstraintsHtml for rich tooltips - it handles both constrained and unconstrained generics protocolScope = "protocol-" ++ nstr n genericsDoc = if null q then empty -- No generics at all else docConstraintsHtmlWithScope generics protocolScope q header = text "

protocol " <> pretty n <> text "" <> genericsDoc <> docAncestorsHtmlWithGenericsAndClassesModule curMod generics classNames a <> text "

" docstr = case ddoc of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty methods = docProtocolBodyHtmlWithGenericsTypesAndClassesModule tenv curMod generics classNames b in text "
" $+$ header $+$ docstr $+$ (if isEmpty methods then empty else blank $+$ methods) $+$ text "
" docExtensionHtmlWithModule tenv curMod classNames q c a b ddoc = let generics = extractGenerics q -- Always use docConstraintsHtml for rich tooltips - it handles both constrained and unconstrained generics genericsDoc = if null q then empty -- No generics at all else docConstraintsHtml generics q header = text "

extension " <> pretty c <> text "" <> genericsDoc <> docAncestorsHtmlWithGenericsAndClassesModule curMod generics classNames a <> text "

" docstr = case ddoc of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty methods = docClassBodyHtmlWithGenericsTypesAndClassesModule tenv curMod generics classNames b in text "
" $+$ header $+$ docstr $+$ (if isEmpty methods then empty else blank $+$ methods) $+$ text "
" nl2br = intercalate "
" . lines docDeclHtmlWithTypesAndClasses :: TEnv -> Set Name -> Decl -> Doc docDeclHtmlWithTypesAndClasses tenv classNames (Def _ n q p k a b d x ddoc) = let explicitGenerics = extractGenerics q -- Look up inferred type information (inferredType, qConstraints) = case lookup n tenv of Just (NDef schema _ _) -> (Just schema, getQBindsFromSchema schema) Just (NSig schema _ _) -> (Just schema, getQBindsFromSchema schema) _ -> (Nothing, []) -- Create a mapping from ugly type vars to nice generic names uglyTypeVarsFromQBinds = collectUglyTypeVars qConstraints uglyTypeVarsFromType = case inferredType of Just (TSchema _ _ t) -> collectUglyTypeVarsFromType t _ -> [] allUglyTypeVars = nub (uglyTypeVarsFromQBinds ++ uglyTypeVarsFromType) typeVarMapping = createTypeVarMapping allUglyTypeVars -- Process the type information with cleanup (paramsWithTypes, inferredRetType, constraints, allGenerics) = case inferredType of Just (TSchema _ qConstraints (TFun _ _ posRow kwdRow retType)) -> let cleanPosRow = cleanupTypeVars typeVarMapping posRow cleanKwdRow = cleanupTypeVars typeVarMapping kwdRow cleanRetType = cleanupTypeVars typeVarMapping retType cleanConstraints = cleanupQBinds typeVarMapping qConstraints inferredGenerics = extractGenerics cleanConstraints mappedGenerics = if null q && not (null typeVarMapping) then Set.fromList (map snd typeVarMapping) else explicitGenerics combinedGenerics = Set.union mappedGenerics inferredGenerics in (enrichParamsWithTypesHtmlAndClasses combinedGenerics cleanConstraints classNames cleanPosRow cleanKwdRow p k, Just cleanRetType, cleanConstraints, combinedGenerics) _ -> (docParamsHtmlWithGenericsAndClasses explicitGenerics classNames p k, a, [], explicitGenerics) -- Use inferred return type if available, otherwise use annotation actualRetType = case inferredRetType of Just t -> docRetTypeHtmlWithGenericsConstraintsAndClasses allGenerics constraints classNames (Just t) Nothing -> docRetTypeHtmlWithGenericsConstraintsAndClasses allGenerics constraints classNames a -- Format constraints if present, or generics if no constraints (constraintsDoc, genericsDoc) = if null constraints then (empty, docGenericsHtmlWithHighlight allGenerics q) else (docConstraintsHtml allGenerics constraints <> text " => ", empty) header = text "

" <> pretty n <> text "" <> constraintsDoc <> genericsDoc <> paramsWithTypes <> actualRetType <> text "

" mdocstring = case lookup n tenv of Just info -> extractNameDocstring info _ -> Nothing docstr = case mdocstring of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty in header $+$ docstr where nl2br = intercalate "
" . lines docDeclHtmlWithTypesAndClasses tenv classNames (Actor _ n q p k b ddoc) = let explicitGenerics = extractGenerics q -- Look up inferred type information for actors (paramsWithTypes, allGenerics, constraints) = case lookup n tenv of Just (NAct qConstraints posRow kwdRow _ _) -> let inferredGenerics = extractGenerics qConstraints combinedGenerics = Set.union explicitGenerics inferredGenerics in (enrichParamsWithTypesHtmlAndClasses combinedGenerics qConstraints classNames posRow kwdRow p k, combinedGenerics, qConstraints) _ -> (docParamsHtmlWithGenericsAndClasses explicitGenerics classNames p k, explicitGenerics, []) header = text "

actor " <> pretty n <> text "" <> docGenericsHtmlWithHighlight allGenerics q <> paramsWithTypes <> text "

" mdocstring = case lookup n tenv of Just info -> extractNameDocstring info _ -> Nothing docstr = case mdocstring of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty -- Process actor body to extract attributes and methods body = docActorBodyHtmlWithGenericsTypesAndClasses tenv allGenerics classNames b in header $+$ docstr $+$ (if isEmpty body then empty else blank $+$ body) where nl2br = intercalate "
" . lines docDeclHtmlWithTypesAndClasses tenv classNames (Class _ n q a b ddoc) = let generics = extractGenerics q header = text "

text (nstr n) <> text "\" class=\"type-context\">class " <> pretty n <> text "" <> docGenericsHtmlWithHighlight generics q <> docAncestorsHtmlWithGenericsAndClasses generics classNames a <> text "

" mdocstring = case lookup n tenv of Just info -> extractNameDocstring info _ -> Nothing docstr = case mdocstring of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty methods = docClassBodyHtmlWithGenericsTypesAndClasses tenv generics classNames b in header $+$ docstr $+$ (if isEmpty methods then empty else blank $+$ methods) where nl2br = intercalate "
" . lines docDeclHtmlWithTypesAndClasses tenv classNames (Protocol _ n q a b ddoc) = let generics = extractGenerics q protocolScope = "protocol-" ++ nstr n header = text "

protocol " <> pretty n <> text "" <> docGenericsHtmlWithHighlightAndScope generics protocolScope q <> docAncestorsHtmlWithGenericsAndClasses generics classNames a <> text "

" mdocstring = case lookup n tenv of Just info -> extractNameDocstring info _ -> Nothing docstr = case mdocstring of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty methods = docProtocolBodyHtmlWithGenericsTypesAndClasses tenv generics classNames b in header $+$ docstr $+$ (if isEmpty methods then empty else blank $+$ methods) where nl2br = intercalate "
" . lines docDeclHtmlWithTypesAndClasses tenv classNames (Extension _ q c a b ddoc) = let generics = extractGenerics q header = text "

extension " <> pretty c <> text "" <> docGenericsHtmlWithHighlight generics q <> docAncestorsHtmlWithGenericsAndClasses generics classNames a <> text "

" mdocstring = Nothing -- Extensions don't have their own docstrings in TEnv docstr = case mdocstring of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty in header $+$ docstr where nl2br = intercalate "
" . lines -- | Module-aware helper functions for type rendering in HTML enrichParamsWithTypesHtmlAndClassesModule :: ModName -> Set Name -> QBinds -> Set Name -> PosRow -> KwdRow -> PosPar -> KwdPar -> Doc enrichParamsWithTypesHtmlAndClassesModule curMod generics constraints classNames posRow kwdRow p k = text "(" <> enrichPosParamsHtmlModule curMod generics constraints classNames posRow p <> docKwdParSepHtml p k <> enrichKwdParamsHtmlModule curMod generics constraints classNames kwdRow k <> text ")" -- | Enrich parameters with types from type environment in HTML format with scope enrichParamsWithTypesHtmlAndClassesModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> PosRow -> KwdRow -> PosPar -> KwdPar -> Doc enrichParamsWithTypesHtmlAndClassesModuleAndScope curMod generics constraints classNames scope posRow kwdRow p k = text "(" <> enrichPosParamsHtmlModuleAndScope curMod generics constraints classNames scope posRow p <> docKwdParSepHtml p k <> enrichKwdParamsHtmlModuleAndScope curMod generics constraints classNames scope kwdRow k <> text ")" enrichPosParamsHtmlModule :: ModName -> Set Name -> QBinds -> Set Name -> PosRow -> PosPar -> Doc enrichPosParamsHtmlModule _ _ _ _ _ PosNIL = empty enrichPosParamsHtmlModule curMod generics constraints classNames posRow (PosPar n t e p) = -- Skip witness parameters if isWitnessParam n then enrichPosParamsHtmlModule curMod generics constraints classNames (advanceRow posRow) p else let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t param = text "" <> pretty n <> text "" <> formatTypeHtmlModule curMod generics constraints classNames paramType <> formatDefaultHtml e nextParams = enrichPosParamsHtmlModule curMod generics constraints classNames (advanceRow posRow) p in if isEmpty nextParams then param else param <> text ", " <> nextParams enrichKwdParamsHtmlModule :: ModName -> Set Name -> QBinds -> Set Name -> KwdRow -> KwdPar -> Doc enrichKwdParamsHtmlModule _ _ _ _ _ KwdNIL = empty enrichKwdParamsHtmlModule curMod generics constraints classNames kwdRow (KwdPar n t e k) = let inferredType = extractParamTypeFromKwdRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t param = text "" <> pretty n <> text "" <> formatTypeHtmlModule curMod generics constraints classNames paramType <> formatDefaultHtml e nextParams = enrichKwdParamsHtmlModule curMod generics constraints classNames kwdRow k in if isEmpty nextParams then param else param <> text ", " <> nextParams -- | Enrich positional parameters with types from row and add scope enrichPosParamsHtmlModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> PosRow -> PosPar -> Doc enrichPosParamsHtmlModuleAndScope _ _ _ _ _ _ PosNIL = empty enrichPosParamsHtmlModuleAndScope curMod generics constraints classNames scope posRow (PosSTAR n t) = let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t in text "*" <> pretty n <> text "" <> formatTypeHtmlModuleAndScope curMod generics constraints classNames scope paramType enrichPosParamsHtmlModuleAndScope curMod generics constraints classNames scope posRow (PosPar n t e p) = -- Skip witness parameters if isWitnessParam n then enrichPosParamsHtmlModuleAndScope curMod generics constraints classNames scope (advanceRow posRow) p else let inferredType = extractParamTypeFromRow (nstr n) posRow paramType = case inferredType of Just it -> Just it Nothing -> t param = text "" <> pretty n <> text "" <> formatTypeHtmlModuleAndScope curMod generics constraints classNames scope paramType <> formatDefaultHtml e nextParams = enrichPosParamsHtmlModuleAndScope curMod generics constraints classNames scope (advanceRow posRow) p in if isEmpty nextParams then param else param <> text ", " <> nextParams -- | Enrich keyword parameters with types from row and add scope enrichKwdParamsHtmlModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> KwdRow -> KwdPar -> Doc enrichKwdParamsHtmlModuleAndScope _ _ _ _ _ _ KwdNIL = empty enrichKwdParamsHtmlModuleAndScope curMod generics constraints classNames scope kwdRow (KwdSTAR n t) = let inferredType = extractParamTypeFromKwdRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t in text "**" <> pretty n <> text "" <> formatTypeHtmlModuleAndScope curMod generics constraints classNames scope paramType enrichKwdParamsHtmlModuleAndScope curMod generics constraints classNames scope kwdRow (KwdPar n t e k) = let inferredType = extractParamTypeFromKwdRow (nstr n) kwdRow paramType = case inferredType of Just it -> Just it Nothing -> t param = text "" <> pretty n <> text "" <> formatTypeHtmlModuleAndScope curMod generics constraints classNames scope paramType <> formatDefaultHtml e nextParams = enrichKwdParamsHtmlModuleAndScope curMod generics constraints classNames scope kwdRow k in if isEmpty nextParams then param else param <> text ", " <> nextParams formatTypeHtmlModule :: ModName -> Set Name -> QBinds -> Set Name -> Maybe Type -> Doc formatTypeHtmlModule _ _ _ _ Nothing = empty formatTypeHtmlModule curMod generics constraints classNames (Just t) = text ": " <> text (renderTypeWithGenericsConstraintsAndClassesAndModule curMod generics constraints classNames t) <> text "" formatTypeHtmlModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> Maybe Type -> Doc formatTypeHtmlModuleAndScope _ _ _ _ _ Nothing = empty formatTypeHtmlModuleAndScope curMod generics constraints classNames scope (Just t) = text ": " <> text (renderTypeWithGenericsConstraintsClassesModuleAndScope curMod generics constraints classNames scope t) <> text "" docParamsHtmlWithGenericsAndClassesModule :: ModName -> Set Name -> Set Name -> PosPar -> KwdPar -> Doc docParamsHtmlWithGenericsAndClassesModule _ _ _ PosNIL KwdNIL = text "()" docParamsHtmlWithGenericsAndClassesModule curMod generics classNames p k = text "(" <> docPosParamsHtmlWithGenericsAndClassesModule curMod generics classNames p <> docKwdParSepHtml p k <> docKwdParamsHtmlWithGenericsAndClassesModule curMod generics classNames k <> text ")" docPosParamsHtmlWithGenericsAndClassesModule :: ModName -> Set Name -> Set Name -> PosPar -> Doc docPosParamsHtmlWithGenericsAndClassesModule _ _ _ PosNIL = empty docPosParamsHtmlWithGenericsAndClassesModule curMod generics classNames (PosPar n t e p) = -- Skip witness parameters if isWitnessParam n then docPosParamsHtmlWithGenericsAndClassesModule curMod generics classNames p else let param = text "" <> pretty n <> text "" <> formatTypeHtmlModule curMod generics [] classNames t <> formatDefaultHtml e nextParams = docPosParamsHtmlWithGenericsAndClassesModule curMod generics classNames p in if isEmpty nextParams then param else param <> text ", " <> nextParams docPosParamsHtmlWithGenericsAndClassesModule curMod generics classNames (PosSTAR n t) = text "*" <> pretty n <> text "" <> formatTypeHtmlModule curMod generics [] classNames t docKwdParamsHtmlWithGenericsAndClassesModule :: ModName -> Set Name -> Set Name -> KwdPar -> Doc docKwdParamsHtmlWithGenericsAndClassesModule _ _ _ KwdNIL = empty docKwdParamsHtmlWithGenericsAndClassesModule curMod generics classNames (KwdPar n t e k) = let param = text "" <> pretty n <> text "" <> formatTypeHtmlModule curMod generics [] classNames t <> formatDefaultHtml e nextParams = docKwdParamsHtmlWithGenericsAndClassesModule curMod generics classNames k in if isEmpty nextParams then param else param <> text ", " <> nextParams docKwdParamsHtmlWithGenericsAndClassesModule curMod generics classNames (KwdSTAR n t) = text "**" <> pretty n <> text "" <> formatTypeHtmlModule curMod generics [] classNames t -- | Document parameters with scope for generic type highlighting docParamsHtmlWithGenericsAndClassesModuleAndScope :: ModName -> Set Name -> Set Name -> String -> PosPar -> KwdPar -> Doc docParamsHtmlWithGenericsAndClassesModuleAndScope _ _ _ _ PosNIL KwdNIL = text "()" docParamsHtmlWithGenericsAndClassesModuleAndScope curMod generics classNames scope p k = text "(" <> docPosParamsHtmlWithGenericsAndClassesModuleAndScope curMod generics classNames scope p <> docKwdParSepHtml p k <> docKwdParamsHtmlWithGenericsAndClassesModuleAndScope curMod generics classNames scope k <> text ")" docPosParamsHtmlWithGenericsAndClassesModuleAndScope :: ModName -> Set Name -> Set Name -> String -> PosPar -> Doc docPosParamsHtmlWithGenericsAndClassesModuleAndScope _ _ _ _ PosNIL = empty docPosParamsHtmlWithGenericsAndClassesModuleAndScope curMod generics classNames scope (PosPar n t e p) = -- Skip witness parameters if isWitnessParam n then docPosParamsHtmlWithGenericsAndClassesModuleAndScope curMod generics classNames scope p else let param = text "" <> pretty n <> text "" <> formatTypeHtmlModuleAndScope curMod generics [] classNames scope t <> formatDefaultHtml e nextParams = docPosParamsHtmlWithGenericsAndClassesModuleAndScope curMod generics classNames scope p in if isEmpty nextParams then param else param <> text ", " <> nextParams docPosParamsHtmlWithGenericsAndClassesModuleAndScope curMod generics classNames scope (PosSTAR n t) = text "*" <> pretty n <> text "" <> formatTypeHtmlModuleAndScope curMod generics [] classNames scope t docKwdParamsHtmlWithGenericsAndClassesModuleAndScope :: ModName -> Set Name -> Set Name -> String -> KwdPar -> Doc docKwdParamsHtmlWithGenericsAndClassesModuleAndScope _ _ _ _ KwdNIL = empty docKwdParamsHtmlWithGenericsAndClassesModuleAndScope curMod generics classNames scope (KwdPar n t e k) = let param = text "" <> pretty n <> text "" <> formatTypeHtmlModuleAndScope curMod generics [] classNames scope t <> formatDefaultHtml e nextParams = docKwdParamsHtmlWithGenericsAndClassesModuleAndScope curMod generics classNames scope k in if isEmpty nextParams then param else param <> text ", " <> nextParams docKwdParamsHtmlWithGenericsAndClassesModuleAndScope curMod generics classNames scope (KwdSTAR n t) = text "**" <> pretty n <> text "" <> formatTypeHtmlModuleAndScope curMod generics [] classNames scope t docRetTypeHtmlWithGenericsConstraintsAndClassesModule :: ModName -> Set Name -> QBinds -> Set Name -> Maybe Type -> Doc docRetTypeHtmlWithGenericsConstraintsAndClassesModule _ _ _ _ Nothing = empty docRetTypeHtmlWithGenericsConstraintsAndClassesModule curMod generics constraints classNames (Just t) = text " → " <> text (renderTypeWithGenericsConstraintsAndClassesAndModule curMod generics constraints classNames t) <> text "" -- | Document return type in HTML format with scope docRetTypeHtmlWithGenericsConstraintsAndClassesModuleAndScope :: ModName -> Set Name -> QBinds -> Set Name -> String -> Maybe Type -> Doc docRetTypeHtmlWithGenericsConstraintsAndClassesModuleAndScope _ _ _ _ _ Nothing = empty docRetTypeHtmlWithGenericsConstraintsAndClassesModuleAndScope curMod generics constraints classNames scope (Just t) = text " → " <> text (renderTypeWithGenericsConstraintsClassesModuleAndScope curMod generics constraints classNames scope t) <> text "" docAncestorsHtmlWithGenericsAndClassesModule :: ModName -> Set Name -> Set Name -> [WTCon] -> Doc docAncestorsHtmlWithGenericsAndClassesModule _ _ _ [] = empty docAncestorsHtmlWithGenericsAndClassesModule curMod generics classNames (a:_) = let (_, tc) = a in text "(" <> text (renderTypeWithGenericsConstraintsAndClassesAndModule curMod generics [] classNames (TCon NoLoc tc)) <> text ")" -- | Extract class members (attributes and methods) from a class body extractClassMembers :: Suite -> ([(Name, Maybe Type)], [(Name, QBinds, PosPar, KwdPar, Maybe Type, Maybe String)]) extractClassMembers stmts = foldr extractMember ([], []) stmts where extractMember (Assign _ [PVar _ n _] _) (attrs, methods) = ((n, Nothing) : attrs, methods) extractMember (VarAssign _ [PVar _ n ann] _) (attrs, methods) = ((n, ann) : attrs, methods) extractMember (Signature _ [n] (TSchema _ _ t) _) (attrs, methods) = case t of TFun {} -> (attrs, methods) -- Function signatures are handled separately _ -> ((n, Just t) : attrs, methods) extractMember (Decl _ decls) (attrs, methods) = foldr extractDeclMember (attrs, methods) decls extractMember _ acc = acc extractDeclMember (Def _ n q p k ret body _ _ ddoc) (attrs, methods) = (attrs, (n, q, p, k, ret, ddoc) : methods) extractDeclMember _ acc = acc -- | Extract actor members (public constants, internal attributes, and methods) from an actor body extractActorMembers :: Suite -> ([(Name, Maybe Type)], [(Name, Maybe Type)], [(Name, QBinds, PosPar, KwdPar, Maybe Type, Maybe String)]) extractActorMembers stmts = foldr extractMember ([], [], []) stmts where extractMember (Assign _ [PVar _ n ann] _) (publics, internals, methods) = ((n, ann) : publics, internals, methods) extractMember (VarAssign _ [PVar _ n ann] _) (publics, internals, methods) = (publics, (n, ann) : internals, methods) extractMember (Signature _ [n] (TSchema _ _ t) _) (publics, internals, methods) = case t of TFun {} -> (publics, internals, methods) -- Function signatures are handled separately _ -> ((n, Just t) : publics, internals, methods) -- Type signatures for public constants extractMember (Decl _ decls) (publics, internals, methods) = foldr extractDeclMember (publics, internals, methods) decls extractMember _ acc = acc extractDeclMember (Def _ n q p k ret body _ _ ddoc) (publics, internals, methods) = (publics, internals, (n, q, p, k, ret, ddoc) : methods) extractDeclMember _ acc = acc -- | Extract protocol methods from a protocol body extractProtocolMethods :: Suite -> [(Name, QBinds, PosPar, KwdPar, Maybe Type, Maybe String)] extractProtocolMethods stmts = foldr extractMethod [] stmts where extractMethod (Decl _ decls) methods = foldr extractDeclMethod methods decls extractMethod (Signature _ names (TSchema _ q t) _) methods = case t of TFun _ _ posRow kwdRow retType -> -- Convert signature to method format let (p, k) = rowsToParams posRow kwdRow in [(n, q, p, k, Just retType, Nothing) | n <- names] ++ methods _ -> [(n, q, PosNIL, KwdNIL, Just t, Nothing) | n <- names] ++ methods -- Non-function signatures extractMethod _ methods = methods extractDeclMethod (Def _ n q p k ret body _ _ ddoc) methods = (n, q, p, k, ret, ddoc) : methods extractDeclMethod _ methods = methods -- Convert rows to parameters for protocol methods rowsToParams :: PosRow -> KwdRow -> (PosPar, KwdPar) rowsToParams posRow kwdRow = (PosNIL, KwdNIL) -- Simplified for now docClassBodyHtmlWithGenericsTypesAndClassesModule :: TEnv -> ModName -> Set Name -> Set Name -> Suite -> Doc docClassBodyHtmlWithGenericsTypesAndClassesModule tenv curMod generics classNames body = let (attrs, methods) = extractClassMembers body attrDocs = if null attrs then empty else text "

Attributes

" $+$ text "
" $+$ vcat (map (docAttributeHtmlWithGenericsAndClassesModule curMod generics classNames) attrs) $+$ text "
" methodDocs = if null methods then empty else text "

Methods

" $+$ text "
" $+$ vcat (map (docMethodHtmlWithGenericsTypesAndClassesModule tenv curMod generics classNames) methods) $+$ text "
" in attrDocs $+$ (if isEmpty attrDocs || isEmpty methodDocs then empty else blank) $+$ methodDocs docProtocolBodyHtmlWithGenericsTypesAndClassesModule :: TEnv -> ModName -> Set Name -> Set Name -> Suite -> Doc docProtocolBodyHtmlWithGenericsTypesAndClassesModule tenv curMod generics classNames body = let methods = extractProtocolMethods body methodDocs = if null methods then empty else text "

Required Methods

" $+$ text "
" $+$ vcat (map (docMethodHtmlWithGenericsTypesAndClassesModule tenv curMod generics classNames) methods) $+$ text "
" in methodDocs docAttributeHtmlWithGenericsAndClassesModule :: ModName -> Set Name -> Set Name -> (Name, Maybe Type) -> Doc docAttributeHtmlWithGenericsAndClassesModule curMod generics classNames (n, t) = text "
" <> pretty n <> text "" <> formatTypeHtmlModule curMod generics [] classNames t <> text "
" docActorBodyHtmlWithGenericsTypesAndClassesModule :: TEnv -> ModName -> Set Name -> Set Name -> Suite -> Doc docActorBodyHtmlWithGenericsTypesAndClassesModule tenv curMod generics classNames body = let (publics, internals, methods) = extractActorMembers body -- Enrich public constants with type information from TEnv enrichedPublics = map enrichAttribute publics where enrichAttribute (n, Nothing) = case lookup n tenv of Just (NSig (TSchema _ _ t) _ _) -> (n, Just t) Just (NDef (TSchema _ _ t) _ _) -> (n, Just t) _ -> (n, Nothing) enrichAttribute attr = attr publicDocs = if null publics then empty else text "

Public Constants

" $+$ text "
" $+$ vcat (map (docAttributeHtmlWithGenericsAndClassesModule curMod generics classNames) enrichedPublics) $+$ text "
" internalDocs = if null internals then empty else text "

Internal Attributes

" $+$ text "
" $+$ vcat (map (docAttributeHtmlWithGenericsAndClassesModule curMod generics classNames) internals) $+$ text "
" methodDocs = if null methods then empty else text "

Methods

" $+$ text "
" $+$ vcat (map (docMethodHtmlWithGenericsTypesAndClassesModule tenv curMod generics classNames) methods) $+$ text "
" in publicDocs $+$ internalDocs $+$ methodDocs docMethodHtmlWithGenericsTypesAndClassesModule :: TEnv -> ModName -> Set Name -> Set Name -> (Name, QBinds, PosPar, KwdPar, Maybe Type, Maybe String) -> Doc docMethodHtmlWithGenericsTypesAndClassesModule tenv curMod generics classNames (n, q, p, k, ret, docstr) = let nl2br = intercalate "
" . lines inferredParams = case lookup n tenv of Just (NDef (TSchema _ _ (TFun _ _ posRow kwdRow retType)) _ _) -> (enrichParamsWithTypesHtmlAndClassesModule curMod generics [] classNames posRow kwdRow p k, Just retType) Just (NSig (TSchema _ _ (TFun _ _ posRow kwdRow retType)) _ _) -> (enrichParamsWithTypesHtmlAndClassesModule curMod generics [] classNames posRow kwdRow p k, Just retType) _ -> (docParamsHtmlWithGenericsAndClassesModule curMod generics classNames p k, ret) (params, retType) = inferredParams -- Extract method-specific generics methodGenerics = extractGenerics q allGenerics = Set.union generics methodGenerics genericsDoc = if null q then empty else docConstraintsHtml methodGenerics q methodSig = text "
" $+$ text "
" <> pretty n <> text "" <> genericsDoc <> params <> docRetTypeHtmlWithGenericsConstraintsAndClassesModule curMod allGenerics [] classNames retType <> text "
" methodDoc = case docstr of Just ds -> text "
" <> text (nl2br $ htmlEscape ds) <> text "
" Nothing -> empty in methodSig $+$ methodDoc $+$ text "
" -- | Helper functions for HTML generation docGenericsHtml :: QBinds -> Doc docGenericsHtml [] = empty docGenericsHtml q = text "[" <> commaList q <> text "]" -- | Render generics with highlighting for HTML docGenericsHtmlWithHighlight :: Set Name -> QBinds -> Doc docGenericsHtmlWithHighlight generics q = docGenericsHtmlWithHighlightAndScope generics "" q -- | Render generics with highlighting and scope for HTML docGenericsHtmlWithHighlightAndScope :: Set Name -> String -> QBinds -> Doc docGenericsHtmlWithHighlightAndScope _ _ [] = empty docGenericsHtmlWithHighlightAndScope generics scope q = let renderGeneric (QBind tv _) = let name = tvname tv nameStr = render (pretty name) in if Set.member name generics then text $ "" ++ nameStr ++ "" else text nameStr genericsDoc = punctuate (text ", ") (map renderGeneric q) in text "[" <> hcat genericsDoc <> text "]" -- | Document type constraints in HTML format docConstraintsHtml :: Set Name -> QBinds -> Doc docConstraintsHtml generics constraints = docConstraintsHtmlWithScope generics "" constraints -- | Document type constraints in HTML format with scope docConstraintsHtmlWithScope :: Set Name -> String -> QBinds -> Doc docConstraintsHtmlWithScope _ _ [] = empty docConstraintsHtmlWithScope generics scope constraints = let renderConstraint (QBind tv preds) = let name = tvname tv nameStr = render (pretty name) tooltip = if null preds then "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type." else "Generic type " ++ nameStr ++ "\n\nThis is a placeholder for any type.\nAll " ++ nameStr ++ "s must be the same type.\n\n" ++ nameStr ++ " must support:\n" ++ concatMap (\p -> " • " ++ formatConstraintName p ++ " protocol (" ++ formatExampleForPred p ++ ")\n") preds nameDoc = if Set.member name generics then text $ "" ++ nameStr ++ "" else text nameStr formatConstraintName (TC qn _) = render . pretty . simplifyQName $ qn formatExampleForPred :: TCon -> String formatExampleForPred (TC (NoQ (Name _ "Plus")) _) = "+ operator" formatExampleForPred (TC (NoQ (Name _ "Minus")) _) = "- operator" formatExampleForPred (TC (NoQ (Name _ "Times")) _) = "* operator" formatExampleForPred (TC (NoQ (Name _ "Divide")) _) = "/ operator" formatExampleForPred (TC (NoQ (Name _ "Eq")) _) = "== operator" formatExampleForPred (TC (NoQ (Name _ "Ord")) _) = "< > operators" formatExampleForPred (TC (NoQ (Name _ "Hash")) _) = "hash function" formatExampleForPred _ = "protocol methods" formatExampleOperators :: [TCon] -> String formatExampleOperators preds = intercalate ", " $ map getExample preds where getExample (TC (NoQ (Name _ "Plus")) _) = "+ operator" getExample (TC (NoQ (Name _ "Minus")) _) = "- operator" getExample (TC (NoQ (Name _ "Times")) _) = "* operator" getExample (TC (NoQ (Name _ "Divide")) _) = "/ operator" getExample (TC (NoQ (Name _ "Eq")) _) = "== operator" getExample (TC (NoQ (Name _ "Ord")) _) = "< > operators" getExample (TC (NoQ (Name _ "Hash")) _) = "hash function" getExample _ = "protocol methods" -- Format predicates/constraints predsDoc = if null preds then empty else text "(" <> hcat (punctuate (text ", ") (map formatConstraint preds)) <> text ")" formatConstraint (TC qn _) = text . render . pretty . simplifyQName $ qn in nameDoc <> predsDoc constraintsDoc = punctuate (text ", ") (map renderConstraint constraints) in text "[" <> hcat constraintsDoc <> text "]" -- | Parameter rendering with generic type support docParamsHtmlWithGenerics :: Set Name -> PosPar -> KwdPar -> Doc docParamsHtmlWithGenerics generics p k = text "(" <> docPosParHtmlWithGenerics generics p <> docKwdParSepHtml p k <> docKwdParHtmlWithGenerics generics k <> text ")" -- | Parameter rendering with generic type support and class links docParamsHtmlWithGenericsAndClasses :: Set Name -> Set Name -> PosPar -> KwdPar -> Doc docParamsHtmlWithGenericsAndClasses generics classNames p k = text "(" <> docPosParHtmlWithGenericsAndClasses generics classNames p <> docKwdParSepHtml p k <> docKwdParHtmlWithGenericsAndClasses generics classNames k <> text ")" docPosParHtmlWithGenerics :: Set Name -> PosPar -> Doc docPosParHtmlWithGenerics _ PosNIL = empty docPosParHtmlWithGenerics generics (PosPar n t e p) = let param = text "" <> pretty n <> text "" <> formatTypeHtmlWithGenerics generics t <> formatDefaultHtml e in case p of PosNIL -> param _ -> param <> text ", " <> docPosParHtmlWithGenerics generics p docPosParHtmlWithGenerics generics (PosSTAR n t) = text "*" <> pretty n <> text "" <> formatTypeHtmlWithGenerics generics t docKwdParHtmlWithGenerics :: Set Name -> KwdPar -> Doc docKwdParHtmlWithGenerics _ KwdNIL = empty docKwdParHtmlWithGenerics generics (KwdPar n t e k) = let param = text "" <> pretty n <> text "" <> formatTypeHtmlWithGenerics generics t <> formatDefaultHtml e in case k of KwdNIL -> param _ -> param <> text ", " <> docKwdParHtmlWithGenerics generics k docKwdParHtmlWithGenerics generics (KwdSTAR n t) = text "**" <> pretty n <> text "" <> formatTypeHtmlWithGenerics generics t docPosParHtmlWithGenericsAndClasses :: Set Name -> Set Name -> PosPar -> Doc docPosParHtmlWithGenericsAndClasses _ _ PosNIL = empty docPosParHtmlWithGenericsAndClasses generics classNames (PosPar n t e p) = let param = text "" <> pretty n <> text "" <> formatTypeHtmlWithGenericsAndClasses generics classNames t <> formatDefaultHtml e in case p of PosNIL -> param _ -> param <> text ", " <> docPosParHtmlWithGenericsAndClasses generics classNames p docPosParHtmlWithGenericsAndClasses generics classNames (PosSTAR n t) = text "*" <> pretty n <> text "" <> formatTypeHtmlWithGenericsAndClasses generics classNames t docKwdParHtmlWithGenericsAndClasses :: Set Name -> Set Name -> KwdPar -> Doc docKwdParHtmlWithGenericsAndClasses _ _ KwdNIL = empty docKwdParHtmlWithGenericsAndClasses generics classNames (KwdPar n t e k) = let param = text "" <> pretty n <> text "" <> formatTypeHtmlWithGenericsAndClasses generics classNames t <> formatDefaultHtml e in case k of KwdNIL -> param _ -> param <> text ", " <> docKwdParHtmlWithGenericsAndClasses generics classNames k docKwdParHtmlWithGenericsAndClasses generics classNames (KwdSTAR n t) = text "**" <> pretty n <> text "" <> formatTypeHtmlWithGenericsAndClasses generics classNames t formatTypeHtmlWithGenerics :: Set Name -> Maybe Type -> Doc formatTypeHtmlWithGenerics generics t = formatTypeHtmlWithGenericsAndConstraints generics [] t formatTypeHtmlWithGenericsAndClasses :: Set Name -> Set Name -> Maybe Type -> Doc formatTypeHtmlWithGenericsAndClasses generics classNames t = formatTypeHtmlWithGenericsConstraintsAndClasses generics [] classNames t formatTypeHtmlWithGenericsAndConstraints :: Set Name -> QBinds -> Maybe Type -> Doc formatTypeHtmlWithGenericsAndConstraints _ _ Nothing = empty formatTypeHtmlWithGenericsAndConstraints generics constraints (Just t) = text ": " <> text (renderTypeWithGenericsAndConstraints generics constraints t) <> text "" formatTypeHtmlWithGenericsConstraintsAndClasses :: Set Name -> QBinds -> Set Name -> Maybe Type -> Doc formatTypeHtmlWithGenericsConstraintsAndClasses _ _ _ Nothing = empty formatTypeHtmlWithGenericsConstraintsAndClasses generics constraints classNames (Just t) = text ": " <> text (renderTypeWithGenericsConstraintsAndClasses generics constraints classNames t) <> text "" docRetTypeHtmlWithGenerics :: Set Name -> Maybe Type -> Doc docRetTypeHtmlWithGenerics generics t = docRetTypeHtmlWithGenericsAndConstraints generics [] t docRetTypeHtmlWithGenericsAndConstraints :: Set Name -> QBinds -> Maybe Type -> Doc docRetTypeHtmlWithGenericsAndConstraints _ _ Nothing = empty docRetTypeHtmlWithGenericsAndConstraints generics constraints (Just t) = text " → " <> text (renderTypeWithGenericsAndConstraints generics constraints t) <> text "" docRetTypeHtmlWithGenericsConstraintsAndClasses :: Set Name -> QBinds -> Set Name -> Maybe Type -> Doc docRetTypeHtmlWithGenericsConstraintsAndClasses _ _ _ Nothing = empty docRetTypeHtmlWithGenericsConstraintsAndClasses generics constraints classNames (Just t) = text " → " <> text (renderTypeWithGenericsConstraintsAndClasses generics constraints classNames t) <> text "" docAncestorsHtmlWithGenerics :: Pretty a => Set Name -> [a] -> Doc docAncestorsHtmlWithGenerics _ [] = empty docAncestorsHtmlWithGenerics _ as = text "(" <> commaList as <> text ")" docAncestorsHtmlWithGenericsAndClasses :: Pretty a => Set Name -> Set Name -> [a] -> Doc docAncestorsHtmlWithGenericsAndClasses _ _ [] = empty docAncestorsHtmlWithGenericsAndClasses _ _ as = text "(" <> commaList as <> text ")" -- | Original parameter rendering (without generics) docParamsHtml :: PosPar -> KwdPar -> Doc docParamsHtml p k = text "(" <> docPosParHtml p <> docKwdParSepHtml p k <> docKwdParHtml k <> text ")" docKwdParSepHtml :: PosPar -> KwdPar -> Doc docKwdParSepHtml PosNIL KwdNIL = empty docKwdParSepHtml PosNIL _ = empty docKwdParSepHtml _ KwdNIL = empty docKwdParSepHtml _ _ = text ", " docPosParHtml :: PosPar -> Doc docPosParHtml PosNIL = empty docPosParHtml (PosPar n t e p) = let param = text "" <> pretty n <> text "" <> formatTypeHtml t <> formatDefaultHtml e in case p of PosNIL -> param _ -> param <> text ", " <> docPosParHtml p docPosParHtml (PosSTAR n t) = text "*" <> pretty n <> text "" <> formatTypeHtml t docKwdParHtml :: KwdPar -> Doc docKwdParHtml KwdNIL = empty docKwdParHtml (KwdPar n t e k) = let param = text "" <> pretty n <> text "" <> formatTypeHtml t <> formatDefaultHtml e in case k of KwdNIL -> param _ -> param <> text ", " <> docKwdParHtml k docKwdParHtml (KwdSTAR n t) = text "**" <> pretty n <> text "" <> formatTypeHtml t formatTypeHtml :: Maybe Type -> Doc formatTypeHtml Nothing = empty formatTypeHtml (Just t) = text ": " <> pretty (SimplifiedType t) <> text "" formatDefaultHtml :: Maybe Expr -> Doc formatDefaultHtml Nothing = empty formatDefaultHtml (Just e) = text " = " <> pretty e <> text "" docRetTypeHtml :: Maybe Type -> Doc docRetTypeHtml Nothing = empty docRetTypeHtml (Just t) = text " → " <> pretty (SimplifiedType t) <> text "" docAncestorsHtml :: Pretty a => [a] -> Doc docAncestorsHtml [] = empty docAncestorsHtml as = text "(" <> commaList as <> text ")" -- | Document class body in HTML with generic type support docClassBodyHtmlWithGenerics :: Set Name -> Suite -> Doc docClassBodyHtmlWithGenerics = docClassBodyHtmlWithGenericsAndTypes [] -- | Document class body in HTML with generic type support and type environment docClassBodyHtmlWithGenericsAndTypes :: TEnv -> Set Name -> Suite -> Doc docClassBodyHtmlWithGenericsAndTypes tenv generics stmts = docClassBodyHtmlWithGenericsTypesAndClasses tenv generics Set.empty stmts -- | Document class body in HTML with generic type support, type environment and class links docClassBodyHtmlWithGenericsTypesAndClasses :: TEnv -> Set Name -> Set Name -> Suite -> Doc docClassBodyHtmlWithGenericsTypesAndClasses tenv generics classNames stmts = let (attrs, methods) = partitionClassMembersHtmlWithGenericsTypesAndClasses tenv generics classNames stmts attrsDoc = if null attrs then empty else text "
" $+$ text "

Attributes:

" $+$ text "
    " $+$ vcat (map wrapLi attrs) $+$ text "
" $+$ text "
" methodsDoc = if null methods then empty else text "
" $+$ text "

Methods:

" $+$ text "
    " $+$ vcat methods $+$ text "
" $+$ text "
" in case (isEmpty attrsDoc, isEmpty methodsDoc) of (True, True) -> empty (False, True) -> attrsDoc (True, False) -> methodsDoc (False, False) -> attrsDoc $+$ methodsDoc where wrapLi doc = text "
  • " <> doc <> text "
  • " -- | Document actor body in HTML with generic type support, type environment and class links docActorBodyHtmlWithGenericsTypesAndClasses :: TEnv -> Set Name -> Set Name -> Suite -> Doc docActorBodyHtmlWithGenericsTypesAndClasses tenv generics classNames stmts = let (publicConstants, internalAttrs, methods) = partitionActorMembersHtmlWithGenericsTypesAndClasses tenv generics classNames stmts publicDoc = if null publicConstants then empty else text "

    Public Constants

    " $+$ text "
    " $+$ vcat publicConstants $+$ text "
    " internalDoc = if null internalAttrs then empty else text "

    Internal Attributes

    " $+$ text "
    " $+$ vcat internalAttrs $+$ text "
    " methodsDoc = if null methods then empty else text "

    Methods

    " $+$ text "
    " $+$ vcat (map renderMethod methods) $+$ text "
    " in vcat $ filter (not . isEmpty) [publicDoc, internalDoc, methodsDoc] where renderMethod (n, q, p, k, ret, docstr) = let nl2br = intercalate "
    " . lines methodGenerics = extractGenerics q allGenerics = Set.union generics methodGenerics inferredParams = case lookup n tenv of Just (NDef (TSchema _ _ (TFun _ _ posRow kwdRow retType)) _ _) -> (enrichParamsWithTypesHtmlAndClasses allGenerics [] classNames posRow kwdRow p k, Just retType) Just (NSig (TSchema _ _ (TFun _ _ posRow kwdRow retType)) _ _) -> (enrichParamsWithTypesHtmlAndClasses allGenerics [] classNames posRow kwdRow p k, Just retType) _ -> (docParamsHtmlWithGenericsAndClasses allGenerics classNames p k, ret) (params, retType) = inferredParams genericsDoc = if null q then empty else docConstraintsHtml methodGenerics q methodSig = text "
    " $+$ text "
    " <> pretty n <> text "" <> genericsDoc <> params <> docRetTypeHtmlWithGenericsConstraintsAndClasses allGenerics [] classNames retType <> text "
    " methodDoc = case docstr of Just ds -> text "
    " <> text (nl2br $ htmlEscape ds) <> text "
    " Nothing -> empty in methodSig $+$ methodDoc $+$ text "
    " -- | Partition actor members into public constants, internal attributes, and methods partitionActorMembersHtmlWithGenericsTypesAndClasses :: TEnv -> Set Name -> Set Name -> Suite -> ([Doc], [Doc], [(Name, QBinds, PosPar, KwdPar, Maybe Type, Maybe String)]) partitionActorMembersHtmlWithGenericsTypesAndClasses tenv generics classNames stmts = foldl partition ([], [], []) stmts where partition (publics, internals, methods) (Assign _ [PVar _ n ann] _) = let enrichedType = case ann of Just t -> Just t Nothing -> case lookup n tenv of Just (NSig (TSchema _ _ t) _ _) -> Just t Just (NDef (TSchema _ _ t) _ _) -> Just t _ -> Nothing doc = case enrichedType of Just t -> text "
    " <> pretty n <> text ": " <> text (renderTypeWithGenericsConstraintsAndClasses generics [] classNames t) <> text "
    " Nothing -> text "
    " <> pretty n <> text "
    " in (publics ++ [doc], internals, methods) partition (publics, internals, methods) (VarAssign _ [PVar _ n ann] _) = let doc = case ann of Just t -> text "
    " <> pretty n <> text ": " <> text (renderTypeWithGenericsConstraintsAndClasses generics [] classNames t) <> text "
    " Nothing -> text "
    " <> pretty n <> text "
    " in (publics, internals ++ [doc], methods) partition (publics, internals, methods) (Signature _ [n] (TSchema _ _ t) _) = case t of TFun {} -> (publics, internals, methods) -- Function signatures are handled separately _ -> let doc = text "
    " <> pretty n <> text ": " <> text (renderTypeWithGenericsConstraintsAndClasses generics [] classNames t) <> text "
    " in (publics ++ [doc], internals, methods) -- Type signatures for public constants partition (publics, internals, methods) (Decl _ decls) = foldl extractDeclMember (publics, internals, methods) decls partition acc _ = acc extractDeclMember (publics, internals, methods) (Def _ n q p k ret body _ _ ddoc) = (publics, internals, methods ++ [(n, q, p, k, ret, ddoc)]) extractDeclMember acc _ = acc -- | Document protocol body in HTML with generic type support docProtocolBodyHtmlWithGenerics :: Set Name -> Suite -> Doc docProtocolBodyHtmlWithGenerics = docProtocolBodyHtmlWithGenericsAndTypes [] -- | Document protocol body in HTML with generic type support and type environment docProtocolBodyHtmlWithGenericsAndTypes :: TEnv -> Set Name -> Suite -> Doc docProtocolBodyHtmlWithGenericsAndTypes tenv generics stmts = docProtocolBodyHtmlWithGenericsTypesAndClasses tenv generics Set.empty stmts -- | Document protocol body in HTML with generic type support, type environment and class links docProtocolBodyHtmlWithGenericsTypesAndClasses :: TEnv -> Set Name -> Set Name -> Suite -> Doc docProtocolBodyHtmlWithGenericsTypesAndClasses tenv generics classNames stmts = let methods = concatMap (extractMethodsHtmlWithGenericsTypesAndClasses tenv generics classNames) stmts in if null methods then empty else text "
    " $+$ text "

    Methods:

    " $+$ text "
      " $+$ vcat methods $+$ text "
    " $+$ text "
    " -- | Partition class members for HTML with generics partitionClassMembersHtmlWithGenerics :: Set Name -> Suite -> ([Doc], [Doc]) partitionClassMembersHtmlWithGenerics = partitionClassMembersHtmlWithGenericsAndTypes [] -- | Partition class members for HTML with generics and type environment partitionClassMembersHtmlWithGenericsAndTypes :: TEnv -> Set Name -> Suite -> ([Doc], [Doc]) partitionClassMembersHtmlWithGenericsAndTypes tenv generics stmts = partitionClassMembersHtmlWithGenericsTypesAndClasses tenv generics Set.empty stmts -- | Partition class members for HTML with generics, type environment and class links partitionClassMembersHtmlWithGenericsTypesAndClasses :: TEnv -> Set Name -> Set Name -> Suite -> ([Doc], [Doc]) partitionClassMembersHtmlWithGenericsTypesAndClasses tenv generics classNames stmts = foldl partition ([], []) stmts where partition (attrs, methods) (Signature _ vs sc d) = (attrs ++ [docAttributeHtmlWithGenericsAndClasses generics classNames vs sc], methods) partition (attrs, methods) (VarAssign _ [PVar _ n ann] _) = case ann of Just t -> (attrs ++ [text "
    " <> pretty n <> text ": " <> text (renderTypeWithGenericsConstraintsAndClasses generics [] classNames t) <> text "
    "], methods) Nothing -> (attrs ++ [text "
    " <> pretty n <> text "
    "], methods) partition (attrs, methods) (Assign _ [PVar _ n ann] _) = case ann of Just t -> (attrs ++ [text "
    " <> pretty n <> text ": " <> text (renderTypeWithGenericsConstraintsAndClasses generics [] classNames t) <> text "
    "], methods) Nothing -> (attrs ++ [text "
    " <> pretty n <> text "
    "], methods) partition (attrs, methods) (Decl _ decls) = (attrs, methods ++ map (docMethodHtmlWithGenericsTypesAndClasses tenv generics classNames) decls) partition acc _ = acc -- | Extract methods for HTML with generics extractMethodsHtmlWithGenerics :: Set Name -> Stmt -> [Doc] extractMethodsHtmlWithGenerics = extractMethodsHtmlWithGenericsAndTypes [] -- | Extract methods for HTML with generics and type environment extractMethodsHtmlWithGenericsAndTypes :: TEnv -> Set Name -> Stmt -> [Doc] extractMethodsHtmlWithGenericsAndTypes tenv generics stmts = extractMethodsHtmlWithGenericsTypesAndClasses tenv generics Set.empty stmts -- | Extract methods for HTML with generics, type environment and class links extractMethodsHtmlWithGenericsTypesAndClasses :: TEnv -> Set Name -> Set Name -> Stmt -> [Doc] extractMethodsHtmlWithGenericsTypesAndClasses tenv generics classNames (Decl _ decls) = map (docMethodHtmlWithGenericsTypesAndClasses tenv generics classNames) decls extractMethodsHtmlWithGenericsTypesAndClasses tenv generics classNames (Signature _ vs sc d) = [docMethodSignatureHtmlWithGenericsAndClasses generics classNames vs sc] extractMethodsHtmlWithGenericsTypesAndClasses _ _ _ _ = [] -- | Document an attribute in HTML with generics docAttributeHtmlWithGenerics :: Set Name -> [Name] -> TSchema -> Doc docAttributeHtmlWithGenerics generics vs ts = docAttributeHtmlWithGenericsAndClasses generics Set.empty vs ts -- | Document an attribute in HTML with generics and class links docAttributeHtmlWithGenericsAndClasses :: Set Name -> Set Name -> [Name] -> TSchema -> Doc docAttributeHtmlWithGenericsAndClasses generics classNames vs (TSchema _ _ t) = text "" <> commaList vs <> text ": " <> text (renderTypeWithGenericsConstraintsAndClasses generics [] classNames t) <> text "" -- | Document a method in HTML with generics docMethodHtmlWithGenerics :: Set Name -> Decl -> Doc docMethodHtmlWithGenerics = docMethodHtmlWithGenericsAndTypes [] -- | Document a method in HTML with generics and type environment docMethodHtmlWithGenericsAndTypes :: TEnv -> Set Name -> Decl -> Doc docMethodHtmlWithGenericsAndTypes tenv generics = docMethodHtmlWithGenericsTypesAndClasses tenv generics Set.empty -- | Document a method in HTML with generics, type environment and class links docMethodHtmlWithGenericsTypesAndClasses :: TEnv -> Set Name -> Set Name -> Decl -> Doc docMethodHtmlWithGenericsTypesAndClasses tenv generics classNames (Def _ n q p k a b _ _ ddoc) = let methodGenerics = Set.union generics (extractGenerics q) -- Look up inferred type information (paramsWithTypes, inferredRetType, constraints) = case lookup n tenv of Just (NDef (TSchema _ qConstraints (TFun _ _ posRow kwdRow retType)) _ _) -> (enrichParamsWithTypesHtmlAndClasses methodGenerics qConstraints classNames posRow kwdRow p k, Just retType, qConstraints) Just (NSig (TSchema _ qConstraints (TFun _ _ posRow kwdRow retType)) _ _) -> (enrichParamsWithTypesHtmlAndClasses methodGenerics qConstraints classNames posRow kwdRow p k, Just retType, qConstraints) _ -> (docParamsHtmlWithGenericsAndClasses methodGenerics classNames p k, a, []) -- Use inferred return type if available, otherwise use annotation actualRetType = case inferredRetType of Just t -> docRetTypeHtmlWithGenericsConstraintsAndClasses methodGenerics constraints classNames (Just t) Nothing -> docRetTypeHtmlWithGenericsConstraintsAndClasses methodGenerics constraints classNames a signature = text "
    " <> pretty n <> text "" <> docGenericsHtmlWithHighlight methodGenerics q <> paramsWithTypes <> actualRetType <> text "
    " docstr = case ddoc of Just ds -> text "
    " <> text (nl2br $ htmlEscape ds) <> text "
    " Nothing -> empty in text "
  • " <> signature <> docstr <> text "
  • " where nl2br = intercalate "
    " . lines docMethodHtmlWithGenericsTypesAndClasses _ _ _ _ = empty -- | Document a method signature in HTML with generics docMethodSignatureHtmlWithGenerics :: Set Name -> [Name] -> TSchema -> Doc docMethodSignatureHtmlWithGenerics generics vs ts = docMethodSignatureHtmlWithGenericsAndClasses generics Set.empty vs ts -- | Document a method signature in HTML with generics and class links docMethodSignatureHtmlWithGenericsAndClasses :: Set Name -> Set Name -> [Name] -> TSchema -> Doc docMethodSignatureHtmlWithGenericsAndClasses generics classNames vs (TSchema _ _ t) = text "
  • " <> commaList vs <> text ": " <> text (renderTypeWithGenericsConstraintsAndClasses generics [] classNames t) <> text "
  • " -- | Convert ModName to string representation modNameToString :: ModName -> String modNameToString (ModName names) = intercalate "." (map nstr names) -- | Generate HTML documentation index for a list of modules generateDocIndex :: FilePath -> [(ModName, Maybe String)] -> IO () generateDocIndex docDir tasks = do let indexFile = docDir "index.html" sortedTasks = sortBy (comparing (\(mn,_) -> modNameToString mn)) tasks moduleEntries = concatMap generateModuleEntry sortedTasks indexHtml = unlines $ [ "" , "" , "" , " " , " " , " Acton Documentation Index" , " " , "" , "" , "
    " , "

    Acton Project Documentation

    " , "

    Documentation for all modules in this project.

    " , "
      " ] ++ moduleEntries ++ [ "
    " , "
    " , "" , "" ] writeFileUtf8Atomic indexFile indexHtml where generateModuleEntry :: (ModName, Maybe String) -> [String] generateModuleEntry (mn, mDoc) = let modPaths = modPath mn -- Use different name to avoid shadowing modName = modNameToString mn htmlFile = if null modPaths then "unnamed.html" else joinPath (init modPaths) last modPaths <.> "html" docString = maybe "" (takeWhile (/= '\n')) mDoc in [ "
  • " , " " , " " ++ modName ++ "" , "
    " ++ htmlEscape docString ++ "
    " , "
    " , "
  • " ] ================================================ FILE: compiler/lib/src/Acton/Env.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances, FlexibleContexts, DeriveGeneric #-} module Acton.Env where import qualified Control.Exception import qualified Data.Binary import GHC.Generics (Generic) import Data.Typeable import Data.Char import System.FilePath.Posix (joinPath,takeDirectory) import System.Directory (doesFileExist) import System.Environment (getExecutablePath) import Control.Monad import Control.Monad.Except import qualified Data.HashMap.Strict as M import qualified Data.Set as S import Acton.Syntax import Acton.Builtin import Acton.Prim import Acton.Printer import Acton.Names import Acton.Subst import Acton.NameInfo import Utils import Pretty import InterfaceFiles import Prelude hiding ((<>)) mkEnv :: [FilePath] -> Env0 -> Module -> IO Env0 mkEnv spath env m = getImps spath env (imps m) -- Full environment ------------------------------------------------------------------------------- data EnvF x = EnvF { activeNames:: TEnv, closedNames:: TEnv, hnames :: HTEnv, closedHNames:: HTEnv, imports :: [ModName], improots :: [Name], modules :: TEnv, hmodules :: HTEnv, thismod :: Maybe ModName, context :: [EnvCtx], qlevel :: Int, envX :: x } deriving (Show) type Env0 = EnvF () -- activeNames may contain live unification variables; closedNames must not. -- hnames is the full active-over-closed lookup index, while closedHNames is -- the reusable closed-only part. setX :: EnvF y -> x -> EnvF x setX env x = EnvF { activeNames = activeNames env, closedNames = closedNames env, hnames = hnames env, closedHNames = closedHNames env, imports = imports env, improots = improots env, modules = modules env, hmodules = hmodules env, thismod = thismod env, context = context env, qlevel = qlevel env, envX = x } modX :: EnvF x -> (x -> x) -> EnvF x modX env f = env{ envX = f (envX env) } data EnvCtx = CtxDef | CtxAct | CtxClass | CtxLoop deriving (Eq,Show) setInAct env = env{ context = CtxAct : context env } setInDef env = env{ context = CtxDef : context env } setInClass env = env{ context = CtxClass : context env } setInLoop env = env{ context = CtxLoop : context env } onTop env = context env == [] contextIs env ctx = case context env of c:_ -> c == ctx; _ -> False contextHas env ctx = ctx `elem` context env inAct env = contextHas env CtxAct inDef env = contextIs env CtxDef inClass env = contextIs env CtxClass inLoop env = contextIs env CtxLoop mapModules1 :: ((Name,NameInfo) -> (Name,NameInfo)) -> Env0 -> Env0 mapModules1 f env = mapModules (\_ _ ni -> [f ni]) env mapModules :: (Env0 -> ModName -> (Name,NameInfo) -> TEnv) -> Env0 -> Env0 mapModules f env = env1 { hmodules = convTEnv2HTEnv (modules env1) } where env1 = walk env0 [] mods env0 = env{ modules = [prim] } prim : mods = modules env walk env ns [] = env walk env ns ((n,NModule ms te1 _):te) = walk env2 ns te where env1 = env{ modules = app ns (modules env) [(n, NModule ms [] Nothing)] } env2 = walk env1 (ns++[n]) te1 walk env ns (ni:te) = walk env1 ns te where env1 = env{ modules = app ns (modules env) (f env (ModName ns) ni) } app (n:ns) ((m,NModule ms te1 doc):te) te' | n == m = (m, NModule ms (app ns te1 te') doc) : te app ns (ni:te) te' = ni : app ns te te' app ns [] te' = te' instance (Pretty x) => Pretty (EnvF x) where pretty env = text "--- modules:" $+$ vcat (map pretty (modules env)) $+$ text "--- active names" <+> pretty (thismod env) <+> parens (text (show (qlevel env))) <> colon $+$ vcat (map pretty (activeNames env)) $+$ text "--- closed names" <+> pretty (thismod env) <> colon $+$ vcat (map pretty (closedNames env)) $+$ text "--- imports" <+> pretty (thismod env) <> colon $+$ vcat (map pretty (imports env)) $+$ pretty (envX env) $+$ text "." closeDepVarsQ vs q | null vs' = nub vs | otherwise = closeDepVarsQ (vs'++vs) q where vs' = concat [ vfree us \\ vs | QBind v us <- q, v `elem` vs ] -- Unalias -------------------------------------------------------------------------------------- class Unalias a where unalias :: EnvF x -> a -> a unalias env = id instance (Unalias a) => Unalias [a] where unalias env = map (unalias env) instance (Unalias a) => Unalias (Maybe a) where unalias env = fmap (unalias env) instance Unalias ModName where unalias env m@(ModName ns) | inBuiltin env = m | otherwise = case lookupName (head ns) env of Just (HNMAlias m') -> m' Nothing | m `elem` (mPrim:mBuiltin:imports env) -> m _ -> noModule m instance Unalias QName where unalias env n0@(QName m n) = case findHMod m env of Just te -> case M.lookup n te of Just (HNAlias qn) -> setLoc (loc n0) qn Just _ -> GName m' n _ -> noItem m n Nothing -> error ("#### unalias fails for " ++ prstr (QName m n)) where m' = unalias env m unalias env (NoQ n) | inBuiltin env = GName mBuiltin n | otherwise = case lookupName n env of Just (HNAlias qn) -> setLoc (loc n) qn _ -> case thismod env of Just m -> GName m n; _ -> NoQ n unalias env (GName m n) -- | inBuiltin env, m==mBuiltin = NoQ n | otherwise = GName m n setLoc l (QName m n) = QName (setModLoc l m) (setNameLoc l n) setLoc l (GName m n) = GName (setModLoc l m) (setNameLoc l n) setLoc l (NoQ n) = NoQ (setNameLoc l n) setNameLoc l (Name _ s) = Name l s setNameLoc _ n = n setModLoc l (ModName ns) = ModName (map (setNameLoc l) ns) instance Unalias TSchema where unalias env (TSchema l q t) = TSchema l (unalias env q) (unalias env t) instance Unalias TCon where unalias env (TC qn ts) = TC (unalias env qn) (unalias env ts) instance Unalias QBind where unalias env (QBind tv cs) = QBind tv (unalias env cs) instance Unalias Type where unalias env (TCon l c) = TCon l (unalias env c) unalias env (TFun l e p r t) = TFun l (unalias env e) (unalias env p) (unalias env r) (unalias env t) unalias env (TTuple l p k) = TTuple l (unalias env p) (unalias env k) unalias env (TOpt l t) = TOpt l (unalias env t) unalias env (TRow l k n t r) = TRow l k n (unalias env t) (unalias env r) unalias env (TStar l k r) = TStar l k (unalias env r) unalias env t = t instance Unalias NameInfo where unalias env (NVar t) = NVar (unalias env t) unalias env (NSVar t) = NSVar (unalias env t) unalias env (NDef t d doc) = NDef (unalias env t) d doc unalias env (NSig t d doc) = NSig (unalias env t) d doc unalias env (NAct q p k te doc) = NAct (unalias env q) (unalias env p) (unalias env k) (unalias env te) doc unalias env (NClass q us te doc)= NClass (unalias env q) (unalias env us) (unalias env te) doc unalias env (NProto q us te doc)= NProto (unalias env q) (unalias env us) (unalias env te) doc unalias env (NExt q c ps te opts doc)= NExt (unalias env q) (unalias env c) (unalias env ps) (unalias env te) opts doc unalias env (NTVar k c ps) = NTVar k (unalias env c) (unalias env ps) unalias env (NAlias qn) = NAlias (unalias env qn) unalias env (NMAlias m) = NMAlias (unalias env m) unalias env (NModule ms te doc) = NModule (unalias env ms) (unalias env te) doc unalias env NReserved = NReserved instance Unalias (Name,NameInfo) where unalias env (n,i) = (n, unalias env i) instance Unalias WTCon where unalias env (w,u) = (unalias env w, unalias env u) instance Unalias (Either QName QName) where unalias env (Left n) = Left $ unalias env n unalias env (Right n) = Right $ unalias env n -- Env construction and modification ------------------------------------------------------------------------------------------- -- | Initialize the base environment; the builtin mode skips interface loading. -- first variant is special case for compiling __builtin__.act publicTEnv :: TEnv -> TEnv publicTEnv = filter (isPublicName . fst) initEnv :: FilePath -> Bool -> IO Env0 initEnv path True = return $ EnvF{ activeNames = [], closedNames = [(nPrim,NMAlias mPrim)], hnames = hnamesFrom [(nPrim,NMAlias mPrim)], closedHNames = hnamesFrom [(nPrim,NMAlias mPrim)], imports = [], improots = [], modules = [(nPrim,NModule [] primEnv Nothing)], hmodules = M.empty, thismod = Nothing, context = [], qlevel = 0, envX = () } initEnv path False = do (_,nmod,_,_,_,_,_,_,_,_,_,_) <- InterfaceFiles.readFile (joinPath [path,"__builtin__.ty"]) let NModule _ envBuiltin builtinDocstring = nmod envBuiltinPublic = publicTEnv envBuiltin initialNames = [(nPrim,NMAlias mPrim), (nBuiltin,NMAlias mBuiltin)] env0 = EnvF{ activeNames = [], closedNames = initialNames, hnames = hnamesFrom initialNames, closedHNames = hnamesFrom initialNames, imports = [], improots = [], modules = [(nPrim,NModule [] primEnv Nothing), (nBuiltin,NModule [] envBuiltin builtinDocstring)], hmodules = M.empty, thismod = Nothing, context = [], qlevel = 0, envX = () } env = importAll mBuiltin envBuiltinPublic env0 return env withModulesFrom :: EnvF x -> EnvF x -> EnvF x env `withModulesFrom` env' = env{modules = modules env'} hnamesFrom :: TEnv -> HTEnv hnamesFrom te = extendHNames te M.empty extendHNames :: TEnv -> HTEnv -> HTEnv extendHNames te hte = foldr add hte te where add (n,i) hte = M.insert n (convNameInfo2HNameInfo i) hte setActiveNames :: TEnv -> EnvF x -> EnvF x setActiveNames te env = env{ activeNames = te, hnames = extendHNames te (closedHNames env) } addActiveNames :: TEnv -> EnvF x -> EnvF x addActiveNames te env = env{ activeNames = te ++ activeNames env, hnames = extendHNames te (hnames env) } addClosedNames :: TEnv -> EnvF x -> EnvF x addClosedNames te env = env{ closedNames = te ++ closedNames env, hnames = extendHNames (activeNames env) hte, closedHNames = hte } where hte = extendHNames te (closedHNames env) lookupName :: Name -> EnvF x -> Maybe HNameInfo lookupName n env = M.lookup n (hnames env) reserve :: [Name] -> EnvF x -> EnvF x reserve xs env | not $ null badSelf = selfParamError (loc $ head badSelf) | otherwise = addActiveNames te env where badSelf = if inAct env then xs `intersect` [selfKW] else [] te = [ (x, NReserved) | x <- uniqueNames xs ] reserveClosed :: [Name] -> EnvF x -> EnvF x reserveClosed xs env | not $ null badSelf = selfParamError (loc $ head badSelf) | otherwise = addClosedNames te env where badSelf = if inAct env then xs `intersect` [selfKW] else [] te = [ (x, NReserved) | x <- uniqueNames xs ] uniqueNames :: [Name] -> [Name] uniqueNames ns = reverse $ snd $ foldl' add (M.empty, []) ns where add (seen, out) n | M.member n seen = (seen, out) | otherwise = (M.insert n () seen, n:out) define :: TEnv -> EnvF x -> EnvF x define te env | not $ null badSelf = selfParamError (loc $ head badSelf) | otherwise = addActiveNames te' env where badSelf = if inAct env then dom te `intersect` [selfKW] else [] te' = reverse te defineClosed :: TEnv -> EnvF x -> EnvF x defineClosed te env | not $ null badSelf = selfParamError (loc $ head badSelf) | otherwise = addClosedNames te' env where badSelf = if inAct env then dom te `intersect` [selfKW] else [] te' = reverse te addImport :: ModName -> EnvF x -> EnvF x addImport m env | m `elem` imports env = env | otherwise = env{ imports = m : imports env } addImpRoot m env = env{ improots = n : improots env } where ModName (n:_) = m getImports env = reverse (imports env) defineTVars :: QBinds -> EnvF x -> EnvF x defineTVars q env = foldr f env (unalias env q) where f (QBind tv us) env = addActiveNames [ni] (env{ qlevel = qlevel env + 1 }) where (c,ps) = case us of u:us' | not $ isProto env (tcname u) -> (u,us'); _ -> (cValue,us) ni = (tvname tv, NTVar (tvkind tv) c ps) selfSubst n q = vsubst [(tvSelf, tCon tc)] where tc = TC n (map tVar $ qbound q) selfQuant n q = QBind tvSelf [tc] : q where tc = TC n (map tVar $ qbound q) setMod :: ModName -> EnvF x -> EnvF x setMod m env = env{ thismod = Just m } addMod :: ModName -> [ModName] -> TEnv -> Maybe String -> EnvF x -> EnvF x addMod m ms newte mdoc env = env{ modules = addM ns (modules env) } where ModName ns = m addM [] te = newte ++ te addM (n:ns) te = update n ns te update n ns ((x,i):te) | n == x, NModule ms1 te1 doc <- i = (n, NModule ms1 (addM ns te1) doc) : te update n ns (ni:te) = ni : update n ns te update n ns [] = (n, NModule ms (addM ns []) mdoc) : [] -- General Env queries ----------------------------------------------------------------------------------------------------------- inBuiltin :: EnvF x -> Bool inBuiltin env = length (modules env) == 1 -- mPrim only stateScope :: EnvF x -> [Name] stateScope env = scopes (activeNames env) ++ scopes (closedNames env) where scopes te = [ z | (z, NSVar _) <- te ] quantScope0 :: EnvF x -> QBinds quantScope0 env = [ QBind (TV k n) (if c==cValue then ps else (c:ps)) | (n, NTVar k c ps) <- activeNames env ] quantScope :: EnvF x -> QBinds quantScope env = [ q | q@(QBind tv _) <- quantScope0 env, tv /= tvSelf ] tvarDescendants :: EnvF x -> [TCon] -> [TVar] tvarDescendants env cs = [ TV k n | (n, NTVar k c _) <- activeNames env, c `elem` cs ] selfScopeSubst :: EnvF x -> Substitution selfScopeSubst env = [ (TV k n, tCon c) | (n, NTVar k c ps) <- activeNames env, n == nSelf ] -- Name queries ------------------------------------------------------------------------------------------------------------------- findQName :: QName -> EnvF x -> NameInfo findQName n env = case tryQName n env of Just i -> convHNameInfo2NameInfo i Nothing -> nameNotFound (noq n) tryQName :: QName -> EnvF x -> Maybe HNameInfo tryQName (QName m n) env = case findHMod m env of Just te -> case M.lookup n te of Just (HNAlias qn) -> tryQName qn env Just i -> Just i _ -> noItem m n _ -> noModule m tryQName (NoQ n) env = case lookupName n env of Just (HNAlias qn) -> tryQName qn env Just ni -> Just ni Nothing -> Nothing tryQName (GName m n) env | Just m == thismod env = tryQName (NoQ n) env | inBuiltin env, m==mBuiltin = tryQName (NoQ n) env | otherwise = case lookupHMod m env of Just te -> case M.lookup n te of Just i -> Just i Nothing -> noItem m n -- error ("## Failed lookup of " ++ prstr n ++ " in module " ++ prstr m) Nothing -> noModule m -- error ("## Failed lookup of module " ++ prstr m) findSigLoc n env = findSL (activeNames env) (closedNames env) where findSL ((n',t):ps) rest | NSig{} <- t, n==n' = Just (loc n') | otherwise = findSL ps rest findSL [] [] = Nothing findSL [] rest = findSL rest [] findDefLoc n env = findSL (activeNames env) (closedNames env) where findSL ((n',t):ps) rest | NDef{} <- t, n==n' = Just (loc n') | otherwise = findSL ps rest findSL [] [] = Nothing findSL [] rest = findSL rest [] findName n env = findQName (NoQ n) env lookupVar n env = case lookupName n env of Just (HNVar t) -> Just t _ -> Nothing findHMod :: ModName -> EnvF x -> Maybe HTEnv -- m is modname part of a QName, so we must check for aliasing findHMod m env | inBuiltin env, m==mBuiltin = Just (hnames env) findHMod m@(ModName ns) env = case lookupName (head ns) env of Just (HNMAlias (ModName m')) -> lookupHMod (ModName $ m'++tail ns) env Nothing | m `elem` (mPrim:mBuiltin:imports env) -> lookupHMod m env _ -> Nothing lookupHMod :: ModName -> EnvF x -> Maybe HTEnv -- m is modname part of a GName, so search directly for module lookupHMod m env = case lookupHModule m env of Just (imps, te, doc) -> Just te; _ -> Nothing lookupHModule m env | inBuiltin env, m==mBuiltin = Just ([], hnames env, Nothing) lookupHModule (ModName ns) env = f ns (hmodules env) where f (n:ns) te = case M.lookup n te of Just (HNModule imps te' doc) -> g ns imps te' doc Just (HNMAlias (ModName m)) -> lookupHModule (ModName $ m++ns) env _ -> Nothing g ns imps te doc | null ns = Just (imps, te, doc) | otherwise = f ns te lookupMod :: ModName -> EnvF x -> Maybe TEnv lookupMod m env = case lookupModule m env of Just (imps, te, doc) -> Just te; _ -> Nothing lookupModule m env | inBuiltin env, m==mBuiltin = Just ([], activeNames env ++ closedNames env, Nothing) lookupModule (ModName ns) env = f ns (modules env) where f (n:ns) te = case lookup n te of Just (NModule imps te' doc) -> g ns imps te' doc Just (NMAlias (ModName m)) -> lookupModule (ModName $ m++ns) env _ -> Nothing g ns imps te doc | null ns = Just (imps, te, doc) | otherwise = f ns te isMod :: EnvF x -> [Name] -> Bool isMod env ns@(n:_) = maybe False (const True) (findHMod (ModName ns) env) && rooted where rooted = n `elem` improots env || isMAlias n env isMAlias :: Name -> EnvF x -> Bool isMAlias n env = case lookupName n env of Just HNMAlias{} -> True _ -> False isAlias :: Name -> EnvF x -> Bool isAlias n env = case lookupName n env of Just HNAlias{} -> True _ -> False kindOf env (TVar _ tv) = tvkind tv kindOf env (TUni _ uv) = uvkind uv kindOf env (TCon _ tc) = tconKind (tcname tc) env kindOf env TFun{} = KType kindOf env TTuple{} = KType kindOf env TOpt{} = KType kindOf env TNone{} = KType kindOf env TWild{} = KWild kindOf env r@TNil{} = rkind r kindOf env r@TRow{} = rkind r kindOf env r@TStar{} = rkind r kindOf env TFX{} = KFX tconKind :: QName -> EnvF x -> Kind tconKind n env = case findQName n env of NAct q _ _ _ _ -> kind KType q NClass q _ _ _ -> kind KType q NProto q _ _ _ -> kind KProto q NReserved -> nameReserved n _ -> notClassOrProto n where kind k [] = k kind k q = KFun [ tvkind v | QBind v _ <- q ] k actorSelf env = case lookupName selfKW env of Just (HNVar (TCon _ tc)) | isActor env (tcname tc) -> True _ -> False actorMethod env n0 = walk [] (activeNames env) (closedNames env) where walk ns ((n,NDef{}):te) rest = walk (n:ns) te rest walk ns ((n,NVar (TCon _ tc)):te) rest | n == selfKW = isActor env (tcname tc) && n0 `elem` ns walk ns (_ : te) rest = walk ns te rest walk ns [] [] = False walk ns [] rest = walk ns rest [] isDef :: EnvF x -> QName -> Bool isDef env n = case tryQName n env of Just HNDef{} -> True _ -> False isActor :: EnvF x -> QName -> Bool isActor env n = case tryQName n env of Just HNAct{} -> True _ -> False isClass :: EnvF x -> QName -> Bool isClass env n = case tryQName n env of Just HNClass{} -> True _ -> False isProto :: EnvF x -> QName -> Bool isProto env n = case tryQName n env of Just HNProto{} -> True _ -> False isDefOrClass :: EnvF x -> QName -> Bool isDefOrClass env n = case tryQName n env of Just HNDef{} -> True Just HNClass{} -> True _ -> False -- TCon queries ------------------------------------------------------------------------------------------------------------------ findAttr' :: EnvF x -> TCon -> Name -> (TSchema, Maybe Deco) findAttr' env tc n = case findAttr env tc n of Just (_, sc, mbdec) -> (sc, mbdec) Nothing -> error ("#### findAttr' fails for " ++ prstr tc ++ " . " ++ prstr n) splitTC :: EnvF x -> TCon -> (Substitution, TCon) splitTC env (TC n ts) = (qbound q `zip` ts, TC n $ map tVar $ qbound q) where (q,_,_) = findConName n env findAncestry :: EnvF x -> TCon -> [WTCon] findAncestry env tc = ([],tc) : fst (findCon env tc) findAncestor :: EnvF x -> TCon -> QName -> Maybe (Expr->Expr,TCon) findAncestor env p qn = listToMaybe [ (wexpr ws, p') | (ws,p') <- findAncestry env p, tcname p' == qn ] hasAncestor' :: EnvF x -> QName -> QName -> Bool hasAncestor' env qn qn' = qn' `elem` [ tcname c' | (w,c') <- us ] where (_,us,_) = findConName qn env hasAncestor :: EnvF x -> TCon -> TCon -> Bool hasAncestor env c c' = hasAncestor' env (tcname c) (tcname c') commonAncestors :: EnvF x -> TCon -> TCon -> [TCon] commonAncestors env c1 c2 = filter ((`elem` ns) . tcname) $ map snd (findAncestry env c1) where ns = map (tcname . snd) (findAncestry env c2) directAncestors :: EnvF x -> QName -> [QName] directAncestors env qn = [ tcname p | (ws,p) <- us, null $ catRight ws ] where (q,us,_) = findConName qn env allAncestors :: EnvF x -> TCon -> [TCon] allAncestors env tc = reverse [ schematic' c | (_, c) <- us ] where (us,te) = findCon env tc allDescendants :: EnvF x -> TCon -> [TCon] allDescendants env tc = [ schematic' c | c <- allCons env, hasAncestor' env (tcname c) (tcname tc) ] findCon :: EnvF x -> TCon -> ([WTCon],TEnv) findCon env (TC n ts) | map tVar tvs == ts = (us, te) | otherwise = (vsubst s us, vsubst s te) where (q,us,te) = findConName n env tvs = qbound q s = tvs `zip` ts findConName n env = case findQName n env of NAct q p k te _ -> (q,[],te) NClass q us te _ -> (q,us,te) NProto q us te _ -> (q,us,te) NExt q c us te _ _ -> (q,us,te) NReserved -> nameReserved n i -> err1 n ("findConName: Class or protocol name expected, got " ++ show i ++ " --- ") conAttrs :: EnvF x -> QName -> [Name] conAttrs env qn = dom te where (_,_,te) = findConName qn env attributes :: (WPath -> NameInfo -> Name -> Maybe a) -> EnvF x -> TCon -> [a] attributes f env tc = catMaybes [ f wp i n | n <- ns, let Just (wp,i) = lookup n aenv ] where ns = nub $ reverse $ dom aenv -- in offset order aenv = [ (n,(wp,i)) | (wp,c) <- findAncestry env tc, let (_,te) = findCon env c, (n,i) <- reverse te ] -- in override order fullAttrEnv :: EnvF x -> TCon -> TEnv fullAttrEnv = attributes f where f wp i n = Just (n,i) parentTEnv :: EnvF x -> [WTCon] -> TEnv parentTEnv env us = [ (n,i) | (_,c) <- us, let (_,te) = findCon env c, (n,i) <- reverse te ] -- in override order findAttr :: EnvF x -> TCon -> Name -> Maybe (Expr->Expr, TSchema, Maybe Deco) findAttr env tc n = listToMaybe $ attributes f env tc where f wp i x | x /= n = Nothing f wp (NSig sc d _) x = Just (wexpr wp, sc, Just d) f wp (NDef sc d _) x = Just (wexpr wp, sc, Just d) f wp (NVar t) x = Just (wexpr wp, monotype t, Nothing) f wp (NSVar t) x = Just (wexpr wp, monotype t, Nothing) attributes' :: (WPath -> NameInfo -> Name -> Maybe a) -> EnvF x -> QName -> [a] attributes' f env qn = catMaybes [ f wp i n | n <- ns, let Just (wp,i) = lookup n aenv ] where ns = nub $ reverse $ dom aenv -- in offset order aenv = [ (n,(wp,i)) | (wp,c) <- ([],tc) : us, let (_,_,te) = findConName (tcname c) env, (n,i) <- reverse te ] -- in override order (q,us,_) = findConName qn env tc = TC qn [ tVar v | QBind v _ <- q ] inheritedAttrs :: EnvF x -> QName -> [(QName,Name)] inheritedAttrs = attributes' f where f _ NSig{} _ = Nothing f wp _ n = case reverse wp of Left w : _ -> Just (w,n); _ -> Nothing allAttrs' :: EnvF x -> TCon -> [Name] allAttrs' env tc = allAttrs env (tcname tc) allAttrs :: EnvF x -> QName -> [Name] allAttrs = attributes' f where f _ _ n = Just n directAttrs :: EnvF x -> QName -> [Name] directAttrs = attributes' f where f wp _ n = if null (catRight wp) then Just n else Nothing abstractAttrs :: EnvF x -> QName -> [Name] abstractAttrs env n = attributes' f env n where f _ (NSig _ dec _) n = if dec == Property then Nothing else Just n f _ _ _ = Nothing closedAttr :: EnvF x -> TCon -> Name -> Bool closedAttr env tc n = n `elem` closedAttrs env (tcname tc) closedAttrs :: EnvF x -> QName -> [Name] closedAttrs = attributes' f where f _ i n | isClosed i = Just n f _ _ n = Nothing isClosed (NVar _) = True isClosed (NSVar _) = True isClosed (NSig _ Property _) = True isClosed (NSig sc _ _) | TFun{} <- sctype sc = False | otherwise = True -- 'closed' ~ 'not a function' isClosed _ = False abstractClass env n = not $ null (abstractAttrs env n) abstractActor env n = not $ null (abstractAttrs env n) abstractAttr :: EnvF x -> TCon -> Name -> Bool abstractAttr env tc n = n `elem` abstractAttrs env (tcname tc) transitiveImports env = mBuiltin : reverse (foldl trav [] (getImports env)) where trav seen m | m `elem` seen = seen | otherwise = m : foldl trav seen ms where ms = case lookupModule m env of Just (imps,_,_) -> imps allTypes :: (NameInfo -> Bool) -> EnvF x -> [TCon] allTypes select env = concatMap impcons mods ++ localcons where mods = transitiveImports env local te | inBuiltin env = [ TC (GName mBuiltin n) (wildargs i) | (n,i) <- te, select i ] | otherwise = [ TC (NoQ n) (wildargs i) | (n,i) <- te, select i ] localcons = local (reverse (closedNames env)) ++ local (reverse (activeNames env)) impcons m = [ TC (GName m n) (wildargs i) | (n,i) <- te, select i ] where Just te = lookupMod m env allCons :: EnvF x -> [TCon] allCons env = allTypes isCon env where isCon NClass{} = True isCon NAct{} = True isCon _ = False allActors :: EnvF x -> [TCon] allActors env = allTypes isActor env where isActor NAct{} = True isActor _ = False allProtos env = allTypes isProto env where isProto NProto{} = True isProto _ = False allConAttr :: EnvF x -> Name -> [TCon] allConAttr env n = [ tc | tc <- allCons env, n `elem` allAttrs' env tc ] allConAttrUFree :: EnvF x -> Name -> [TUni] allConAttrUFree env n = concat [ ufree $ fst $ findAttr' env tc n | tc <- activeConAttr env n ] activeConAttr :: EnvF x -> Name -> [TCon] activeConAttr env n = [ tc | (x,i) <- activeNames env, isCon i, let tc = TC (localQName x) (wildargs i), n `elem` allAttrs' env tc ] where isCon NClass{} = True isCon NAct{} = True isCon _ = False localQName x | inBuiltin env = GName mBuiltin x | otherwise = NoQ x allPConAttr :: EnvF x -> Name -> [PCon] allPConAttr env n = [ p | p <- allProtos env, n `elem` allAttrs' env p ] -- TVar queries ------------------------------------------------------------------------------------------------------------------ findSelf :: EnvF x -> TCon findSelf env = case findName (tvname tvSelf) env of NTVar _ c ps -> c findTVBound :: EnvF x -> TVar -> CCon findTVBound env tv = case findName (tvname tv) env of NTVar _ c ps -> c _ -> err1 tv "Unknown type variable" findTVAttr :: EnvF x -> TVar -> Name -> Maybe (Expr->Expr, TSchema, Maybe Deco) findTVAttr env tv n = findAttr env c n where c = findTVBound env tv tvarWit :: TVar -> PCon -> Name tvarWit tv p = Internal Witness (nstr $ Derived (deriveQ $ tcname p) (tvname tv)) 0 -- Method resolution order ------------------------------------------------------------------------------------------------------ mro2 :: EnvF x -> [TCon] -> ([WTCon],[WTCon]) mro2 env [] = ([], []) mro2 env (u:us) | isActor env (tcname u) = err1 u "Actor subclassing not allowed" | isProto env (tcname u) = ([], mro env (u:us)) | otherwise = (mro env [u], mro env us) mro1 env us = mro env us mro :: EnvF x -> [TCon] -> [WTCon] mro env us = merge [] $ map lin us' ++ [us'] where us' = case us of [] -> []; u:us -> ([Left (tcname u)],u) : [ ([Right (tcname u)],u) | u <- us ] lin :: WTCon -> [WTCon] lin (w,u) = (w,u) : [ (w++w',u') | (w',u') <- us' ] where (us',_) = findCon env u merge :: [WTCon] -> [[WTCon]] -> [WTCon] merge out lists | null heads = reverse out | h:_ <- good = merge (h:out) [ if equal hd h then tl else hd:tl | (hd,tl) <- zip heads tails ] | otherwise = err2 (map snd heads) "Inconsistent resolution order for" where (heads,tails) = unzip [ (hd,tl) | hd:tl <- lists ] good = [ h | h <- heads, all (absent h) tails] equal :: WTCon -> WTCon -> Bool equal (w1,u1) (w2,u2) | tcname u1 == tcname u2 = tcargs u1 == tcargs u2 || err2 [u1,u2] "Inconsistent protocol instantiations" | otherwise = False absent :: WTCon -> [WTCon] -> Bool absent (w,h) us = tcname h `notElem` map (tcname . snd) us ---------------------------------------------------------------------------------------------------------------------- -- castable predicate ---------------------------------------------------------------------------------------------------------------------- castable :: EnvF x -> Type -> Type -> Bool castable env (TWild _) t2 = True castable env t1 (TWild _) = True castable env (TCon _ c1) (TCon _ c2) | tcname c1 == tcname c2, tcname c1 `elem` covariant = all (uncurry $ castable env) (tcargs c1 `zip` tcargs c2) | Just (wf,c') <- search = tcargs c2 == tcargs c' where search = findAncestor env c1 (tcname c2) castable env (TFun _ fx1 p1 k1 t1) (TFun _ fx2 p2 k2 t2) = castable env fx1 fx2 && castable env p2 p1 && castable env k2 k1 && castable env t1 t2 castable env (TTuple _ p1 k1) (TTuple _ p2 k2) = castable env p1 p2 && castable env k1 k2 castable env (TOpt _ t1) (TOpt _ t2) = castable env t1 t2 castable env (TNone _) (TOpt _ t) = True castable env (TNone _) (TNone _) = True castable env (TFX _ fx1) (TFX _ fx2) = castable' fx1 fx2 where castable' FXPure FXPure = True castable' FXPure FXMut = True castable' FXPure FXProc = True castable' FXMut FXMut = True castable' FXMut FXProc = True castable' FXProc FXProc = True castable' FXAction FXAction = True castable' FXAction FXProc = True castable' fx1 fx2 = False castable env (TNil _ k1) (TNil _ k2) | k1 == k2 = True castable env (TRow _ k1 n1 t1 r1) (TRow _ k2 n2 t2 r2) | k1 == k2 && n1 == n2 = castable env t1 t2 && castable env r1 r2 castable env (TStar _ k1 r1) (TStar _ k2 r2) | k1 == k2 = castable env r1 r2 castable env (TVar _ tv1) (TVar _ tv2) | tv1 == tv2 = True castable env t1@(TVar _ tv) t2 = castable env (tCon c) t2 where c = findTVBound env tv castable env t1 t2@(TVar _ tv) = False castable env t1 (TOpt _ t2) = castable env t1 t2 castable env t1 t2 = False headcast env t1 t2 = castable env (schematic t1) (schematic t2) ---------------------------------------------------------------------------------------------------------------------- -- GLB ---------------------------------------------------------------------------------------------------------------------- glb env (TWild _) t2 = pure tWild glb env t1 (TWild _) = pure tWild glb env t1@TVar{} t2@TVar{} | t1 == t2 = pure t1 glb env (TUni _ u) _ = pure tWild glb env _ (TUni _ u) = pure tWild glb env (TCon _ c1) (TCon _ c2) | tcname c1 == tcname c2 = pure $ tCon c1 | hasAncestor env c1 c2 = pure $ tCon c1 | hasAncestor env c2 c1 = pure $ tCon c2 glb env (TFun _ e1 p1 k1 t1) (TFun _ e2 p2 k2 t2) = do e <- glb env e1 e2 (p, k) <- lub2 env p1 k1 p2 k2 t <- glb env t1 t2 return (tFun e p k t) glb env t1@(TTuple _ p1 k1) t2@(TTuple _ p2 k2) = do --traceM ("## GLB " ++ prstr t1 ++ " \\/ " ++ prstr t2) (p, k) <- glb2 env p1 k1 p2 k2 --traceM ("## GLB " ++ prstr t1 ++ " \\/ " ++ prstr t2 ++ " = " ++ prstr (tTuple p k)) return (tTuple p k) glb env (TOpt _ t1) (TOpt _ t2) = tOpt <$> glb env t1 t2 glb env (TNone _) t2 = pure tNone glb env t1 (TNone _) = pure tNone glb env (TOpt _ t1) t2 = glb env t1 t2 glb env t1 (TOpt _ t2) = glb env t1 t2 glb env t1@(TFX _ fx1) t2@(TFX _ fx2) | Just fx <- glfx fx1 fx2 = pure $ tTFX fx where glfx FXPure FXPure = Just FXPure glfx FXPure FXMut = Just FXPure glfx FXPure FXProc = Just FXPure glfx FXPure FXAction = Nothing glfx FXMut FXPure = Just FXPure glfx FXMut FXMut = Just FXMut glfx FXMut FXProc = Just FXMut glfx FXMut FXAction = Nothing glfx FXProc FXPure = Just FXPure glfx FXProc FXMut = Just FXMut glfx FXProc FXProc = Just FXProc glfx FXProc FXAction = Just FXAction glfx FXAction FXPure = Nothing glfx FXAction FXMut = Nothing glfx FXAction FXProc = Just FXAction glfx FXAction FXAction = Just FXAction glb env (TNil _ k1) (TNil _ k2) | k1 == k2 = pure $ tNil k1 glb env (TRow _ k1 n1 t1 r1) (TRow _ k2 n2 t2 r2) | k1 == k2 && n1 == n2 = tRow k1 n1 <$> glb env t1 t2 <*> glb env r1 r2 glb env (TStar _ k1 r1) (TStar _ k2 r2) | k1 == k2 = tStar k1 <$> glb env r1 r2 glb env t1 t2 = Nothing glb2 env (TRow _ _ _ t1 p1) k1 (TRow _ _ _ t2 p2) k2 = do t <- glb env t1 t2 (p,k) <- glb2 env p1 k1 p2 k2 return (posRow t p, k) glb2 env p1@TRow{} k1 p2@TNil{} (TRow _ _ _ t2 k2) = glb2 env p1 k1 (posRow t2 p2) k2 glb2 env p1@TNil{} (TRow _ _ _ t1 k1) p2@TRow{} k2 = glb2 env (posRow t1 p1) k1 p2 k2 glb2 env p1 k1 p2 k2 = do p <- glb env p1 p2 k <- glb env k1 k2 return (p, k) glbfold env ts = case filter (/= tWild) ts of [] -> pure tWild t:ts -> foldM (glb env) t ts ---------------------------------------------------------------------------------------------------------------------- -- LUB ---------------------------------------------------------------------------------------------------------------------- lub env (TWild _) t2 = pure tWild lub env t1 (TWild _) = pure tWild lub env t1@TVar{} t2@TVar{} | t1 == t2 = pure t1 lub env t (TVar _ v) = lub env t (tCon $ findTVBound env v) lub env (TVar _ v) t = lub env (tCon $ findTVBound env v) t lub env (TUni _ u) _ = pure tWild lub env _ (TUni _ u) = pure tWild lub env (TCon _ c1) (TCon _ c2) | tcname c1 == tcname c2 = pure $ tCon c1 | hasAncestor env c1 c2 = pure $ tCon c2 | hasAncestor env c2 c1 = pure $ tCon c1 | not $ null common = pure $ tCon $ head common where common = commonAncestors env c1 c2 lub env f1@(TFun _ e1 p1 k1 t1) f2@(TFun _ e2 p2 k2 t2) = do e <- lub env e1 e2 (p,k) <- glb2 env p1 k1 p2 k2 t <- lub env t1 t2 --traceM ("## LUB " ++ prstr f1 ++ " /\\ " ++ prstr f2 ++ " = " ++ prstr (tFun e p k t)) return $ tFun e p k t lub env t1@(TTuple _ p1 k1) t2@(TTuple _ p2 k2) = do (p,k) <- lub2 env p1 k1 p2 k2 --traceM ("## LUB " ++ prstr t1 ++ " /\\ " ++ prstr t2 ++ " = " ++ prstr (tTuple p k)) return $ tTuple p k lub env (TOpt _ t1) (TOpt _ t2) = tOpt <$> lub env t1 t2 lub env (TNone _) (TNone _) = pure tNone lub env (TNone _) t2@TOpt{} = pure t2 lub env t1@TOpt{} (TNone _) = pure t1 lub env (TNone _) t2 = pure $ tOpt t2 lub env t1 (TNone _) = pure $ tOpt t1 lub env (TOpt _ t1) t2 = tOpt <$> lub env t1 t2 lub env t1 (TOpt _ t2) = tOpt <$> lub env t1 t2 lub env t1@(TFX _ fx1) t2@(TFX _ fx2) = pure $ tTFX (lufx fx1 fx2) where lufx FXPure FXPure = FXPure lufx FXPure FXMut = FXMut lufx FXPure FXProc = FXProc lufx FXPure FXAction = FXProc lufx FXMut FXPure = FXMut lufx FXMut FXMut = FXMut lufx FXMut FXProc = FXProc lufx FXMut FXAction = FXProc lufx FXProc FXPure = FXProc lufx FXProc FXMut = FXProc lufx FXProc FXProc = FXProc lufx FXProc FXAction = FXProc lufx FXAction FXPure = FXProc lufx FXAction FXMut = FXProc lufx FXAction FXProc = FXProc lufx FXAction FXAction = FXAction lub env (TNil _ k1) (TNil _ k2) | k1 == k2 = pure $ tNil k1 lub env (TRow _ k1 n1 t1 r1) (TRow _ k2 n2 t2 r2) | k1 == k2 && n1 == n2 = tRow k1 n1 <$> lub env t1 t2 <*> lub env r1 r2 lub env (TStar _ k1 r1) (TStar _ k2 r2) | k1 == k2 = tStar k1 <$> lub env r1 r2 lub env t1 t2 = Nothing lub2 env (TRow _ _ _ t1 p1) k1 (TRow _ _ _ t2 p2) k2 = do t <- lub env t1 t2 (p,k) <- lub2 env p1 k1 p2 k2 return (posRow t p, k) lub2 env (TRow _ _ _ t1 p1) k1 p2@TNil{} k2@TRow{} = lub2 env p1 (kwdRow (label k2) t1 k1) p2 k2 lub2 env p1@TNil{} k1@TRow{} (TRow _ _ _ t2 p2) k2 = lub2 env p1 k1 p2 (kwdRow (label k1) t2 k2) lub2 env p1 k1 p2 k2 = do p <- lub env p1 p2 k <- lub env k1 k2 return (p, k) lubfold env ts = case filter (/= tWild) ts of [] -> pure tWild t:ts -> foldM (lub env) t ts -- Control flow -------------------- data Flow = RET | BRK | CNT | SEQ deriving (Eq, Show) class Flows a where flows :: a -> [Flow] fallsthru x = SEQ `elem` flows x brkseq flow = (if BRK `elem` flow then SEQ:flow else flow) \\ [BRK,CNT] instance Flows a => Flows [a] where flows [] = [SEQ] flows (s : ss) = flows s `seq` flows ss where f1 `seq` f2 = if SEQ `elem` f1 then (f1\\[SEQ])++f2 else f1 instance Flows Stmt where flows (Expr _ e) | e == eNotImpl = [] -- Not tracked | Call _ (Var _ n) _ _ <- e, n == primRAISE = [] -- Not tracked flows Raise{} = [] -- Not tracked flows Return{} = [RET] flows Break{} = [BRK] flows Continue{} = [CNT] flows (If _ bs els) = concatMap flows bs ++ flows els flows (While _ _ b els) = brkseq (flows b) ++ flows els flows (For _ _ _ b els) = brkseq (flows b) ++ flows els flows (With _ _ b) = flows b flows (Try _ b hs els fin) = flows (b++els) ++ concatMap flows hs ++ (flows fin \\ [SEQ]) flows _ = [SEQ] instance Flows Branch where flows (Branch _ ss) = flows ss instance Flows Handler where flows (Handler _ ss) = flows ss -- Import handling (local definitions only) ------------------------------------------------------------------------- --getImps :: [FilePath] -> EnvF x -> [Import] -> IO (EnvF x) getImps spath env [] = return env { hmodules = convTEnv2HTEnv (modules env) } getImps spath env (i:is) = do env' <- impModule spath env i getImps spath env' is --impModule :: [FilePath] -> EnvF x -> Import -> IO (EnvF x) impModule spath env (Import _ ms) = imp env ms where imp env [] = return env imp env (ModuleItem m as : is) = do (env1,te) <- doImp spath env m let env2 = maybe (addImpRoot m) (\n->defineClosed [(n, NMAlias m)]) as env1 imp env2 is impModule spath env (FromImport _ (ModRef (0,Just m)) items) = do (env1,te) <- doImp spath env m return $ importSome items m te env1 impModule spath env (FromImportAll _ (ModRef (0,Just m))) = do (env1,te) <- doImp spath env m return $ importAll m te env1 impModule _ _ i = illegalImport (loc i) subImp spath env [] = return env subImp spath env (m:ms) = do (env',_) <- doImp spath env m subImp spath env' ms findTyFile spaths mn = go spaths where go [] = return Nothing go (p:ps) = do let fullPath = joinPath (p : modPath mn) ++ ".ty" exists <- doesFileExist fullPath --traceM ("findTyFile: " ++ fullPath ++ " " ++ show exists) if exists then return (Just fullPath) else go ps -- | Import a module, loading its .ty and extending the environment. doImp :: [FilePath] -> EnvF x -> ModName -> IO (EnvF x, TEnv) doImp spath env m = do (env', te, _) <- doImpSeen S.empty env m return (addImport m env', te) where -- A cached module still needs its recorded import closure available in the -- environment. Otherwise later imports of that cached module can miss -- transitive dependencies that were never added to the shared module cache. doImpSeen seen env m | S.member m seen = case lookupMod m env of Just te -> return (env, te, seen) Nothing -> fileNotFound m | otherwise = let seen' = S.insert m seen in case lookupMod m env of Just te -> do hdr <- readFoundTy InterfaceFiles.readHeaderMaybe m case hdr of Nothing -> return (env, te, seen') Just (_sourceMeta, _, _, _, imps, _, _, _, _) -> do (env', seen'') <- subImpSeen seen' env (map fst imps) return (env', te, seen'') Nothing -> do ty <- readFoundTy InterfaceFiles.readFileMaybe m case ty of Nothing -> fileNotFound m Just (ms,nmod,_,_,_,_,_,_,_,_,_,_) -> do (env', seen'') <- subImpSeen seen' env ms let NModule ms' teFull mdoc = nmod te = publicTEnv teFull return (addMod m ms' te mdoc env', te, seen'') readFoundTy readTy m = do tyFile <- findTyFile spath m case tyFile of Nothing -> return Nothing Just tyF -> readTy tyF subImpSeen seen env [] = return (env, seen) subImpSeen seen env (m:ms) = do (env', _, seen') <- doImpSeen seen env m subImpSeen seen' env' ms importSome :: [ImportItem] -> ModName -> TEnv -> EnvF x -> EnvF x importSome items m te env = defineClosed (map pick items) env where te1 = impNames m te pick (ImportItem n mbn) = case lookup n te1 of Just i -> (maybe n id mbn, i) Nothing -> noItem m n importAll :: ModName -> TEnv -> EnvF x -> EnvF x importAll m te env = defineClosed (impNames m te) env impNames :: ModName -> TEnv -> TEnv impNames m te = mapMaybe imp (publicTEnv te) where imp (n, NAct _ _ _ _ _) = Just (n, NAlias (GName m n)) imp (n, NClass _ _ _ _) = Just (n, NAlias (GName m n)) imp (n, NProto _ _ _ _) = Just (n, NAlias (GName m n)) imp (n, NExt _ _ _ _ _ _) = Nothing imp (n, NAlias _) = Just (n, NAlias (GName m n)) imp (n, NVar t) = Just (n, NAlias (GName m n)) imp (n, NDef t d _) = Just (n, NAlias (GName m n)) imp _ = Nothing -- cannot happen -- Error handling ---------------------------------------------------------------------------------------------------- data CompilationError = KindError SrcLoc Kind Kind | InfiniteKind SrcLoc KUni Kind | VariableFX TVar | FileNotFound ModName | NameNotFound Name | NameReserved QName | NameBlocked QName | NameUnexpected QName | TypedReassign Pattern | IllegalRedef Name | IllegalSigOverride Name | IllegalExtension QName | MissingSelf Name | IllegalImport SrcLoc | DuplicateImport Name | NoItem ModName Name | NoModule ModName | NoClassOrProto QName | DecorationMismatch Name TSchema Deco | SelfParamError SrcLoc | OtherError SrcLoc String deriving (Show) instance Control.Exception.Exception CompilationError instance HasLoc CompilationError where loc (KindError l _ _) = l loc (InfiniteKind l _ _) = l loc (VariableFX tv) = loc tv loc (FileNotFound n) = loc n loc (NameNotFound n) = loc n loc (NameReserved n) = loc n loc (NameBlocked n) = loc n loc (NameUnexpected n) = loc n loc (TypedReassign p) = loc p loc (IllegalRedef n) = loc n loc (IllegalSigOverride n) = loc n loc (IllegalExtension n) = loc n loc (MissingSelf n) = loc n loc (IllegalImport l) = l loc (DuplicateImport n) = loc n loc (NoModule m) = loc m loc (NoItem m n) = loc n loc (NoClassOrProto n) = loc n loc (DecorationMismatch n t d) = loc n loc (SelfParamError l) = l loc (OtherError l str) = l compilationError :: CompilationError -> [(SrcLoc, String)] compilationError err = [(loc err, render (expl err))] where expl (KindError l k1 k2) = text "Expected a" <+> pretty k2 <> comma <+> text "actual kind is" <+> pretty k1 expl (InfiniteKind l v k) = text "Infinite kind inferred:" <+> pretty v <+> equals <+> pretty k expl (VariableFX tv) = text "Effect annotation cannot be a variable:" <+> pretty tv expl (FileNotFound n) = text "Type interface file not found for" <+> pretty n expl (NameNotFound n) = text "Name" <+> pretty n <+> text "is not in scope" expl (NameReserved n) = text "Name" <+> pretty n <+> text "is reserved but not yet defined" expl (NameBlocked n) = text "Name" <+> pretty n <+> text "is currently not accessible" expl (NameUnexpected n) = text "Unexpected variable name:" <+> pretty n expl (TypedReassign p) = text "Type annotation on reassignment:" <+> pretty p expl (IllegalRedef n) = text "Illegal redefinition of" <+> pretty n expl (IllegalSigOverride n) = text "Illegal signature override:" <+> pretty n expl (IllegalExtension n) = text "Illegal extension of" <+> pretty n expl (MissingSelf n) = text "Missing 'self' parameter in definition of" expl (IllegalImport l) = text "Relative import not yet supported" expl (DuplicateImport n) = text "Duplicate import of name" <+> pretty n expl (NoModule m) = text "Module" <+> pretty m <+> text "does not exist" expl (NoItem m n) = text "Module" <+> pretty m <+> text "does not export" <+> pretty n expl (NoClassOrProto n) = text "Class or protocol name expected, got" <+> pretty n expl (DecorationMismatch n t d) = text "Decoration for" <+> pretty n <+> text "does not match signature" <+> pretty d expl (SelfParamError l) = text "'self' cannot be used as a parameter name in actors." expl (OtherError l str) = text str noKUnify l k1 k2 = Control.Exception.throw $ KindError l k1 k2 infiniteKind l v k = Control.Exception.throw $ InfiniteKind l v k variableFX tv = Control.Exception.throw $ VariableFX tv nameNotFound n = Control.Exception.throw $ NameNotFound n nameReserved n = Control.Exception.throw $ NameReserved n nameBlocked n = Control.Exception.throw $ NameBlocked n nameUnexpected n = Control.Exception.throw $ NameUnexpected n typedReassign p = Control.Exception.throw $ TypedReassign p illegalRedef n = Control.Exception.throw $ IllegalRedef n illegalSigOverride n = Control.Exception.throw $ IllegalSigOverride n illegalExtension n = Control.Exception.throw $ IllegalExtension n missingSelf n = Control.Exception.throw $ MissingSelf n fileNotFound n = Control.Exception.throw $ FileNotFound n illegalImport l = Control.Exception.throw $ IllegalImport l duplicateImport n = Control.Exception.throw $ DuplicateImport n noItem m n = Control.Exception.throw $ NoItem m n noModule m = Control.Exception.throw $ NoModule m notClassOrProto n = Control.Exception.throw $ NoClassOrProto n decorationMismatch n t d = Control.Exception.throw $ DecorationMismatch n t d selfParamError l = Control.Exception.throw $ SelfParamError l err l s = Control.Exception.throw $ OtherError l s err0 xs s = err (loc $ head xs) s err1 x s = err (loc x) (s ++ " " ++ prstr x) err2 xs s = err (loc $ head xs) (s ++ " " ++ prstrs xs) err3 l xs s = err l (s ++ " " ++ prstrs xs) notYetExpr e = notYet (loc e) e stripQual q = [ QBind v [] | QBind v us <- q ] class Simp a where simp :: EnvF x -> a -> a instance (Simp a) => Simp [a] where simp env = map (simp env) instance Simp TSchema where simp env (TSchema l q t) = TSchema l q' (vsubst s $ simp env' t) where (q', s) = simpQuant env (simp env' q) (vfree t) env' = defineTVars (stripQual q) env simpQuant env q vs0 = (vsubst s [ QBind v ps | QBind v ps <- q2, not $ null ps ], s) where (q1,q2) = partition isEX q isEX (QBind v [p]) = length (filter (==v) vs) == 1 isEX _ = False vs = concat [ vfree ps | QBind v ps <- q ] ++ vs0 s = [ (v, tCon p) | QBind v [p] <- q1 ] -- Inline existentials instance Simp QBind where simp env (QBind v ps) = QBind v (simp env ps) instance Simp WTCon where simp env (w, c) = (w, simp env c) instance Simp (Name, NameInfo) where simp env (n, NSig sc dec doc) = (n, NSig (simp env sc) dec doc) simp env (n, NDef sc dec doc) = (n, NDef (simp env sc) dec doc) simp env (n, NVar t) = (n, NVar (simp env t)) simp env (n, NSVar t) = (n, NSVar (simp env t)) simp env (n, NClass q us te doc)= (n, NClass (simp env' q) (simp env' us) (simp env' te) doc) where env' = defineTVars (stripQual q) env simp env (n, NProto q us te doc)= (n, NProto (simp env' q) (simp env' us) (simp env' te) doc) where env' = defineTVars (stripQual q) env simp env (n, NExt q c us te opts doc) = (n, NExt q' (vsubst s $ simp env' c) (vsubst s $ simp env' us) (vsubst s $ simp env' te) opts doc) where (q', s) = simpQuant env (simp env' q) (vfree c ++ vfree us ++ vfree te) env' = defineTVars (stripQual q) env simp env (n, NAct q p k te doc) = (n, NAct (simp env' q) (simp env' p) (simp env' k) (simp env' te) doc) where env' = defineTVars (stripQual q) env simp env (n, i) = (n, i) instance Simp Type where simp env (TCon l c) = TCon l (simp env c) simp env (TFun l fx p k t) = TFun l (simp env fx) (simp env p) (simp env k) (simp env t) simp env (TTuple l p k) = TTuple l (simp env p) (simp env k) simp env (TOpt l t) = TOpt l (simp env t) simp env (TRow l k n t r) = TRow l k n (simp env t) (simp env r) simp env (TStar l k r) = TStar l k (simp env r) simp env t = t instance Simp TCon where simp env (TC n ts) = TC (simp env n) (simp env ts) -- Simplify constructor names instance Simp QName where simp env (GName m n) | inBuiltin env = NoQ n -- Restore builtins | Just m == thismod env = NoQ n -- Restore locals simp env n | Just n1 <- findAlias (activeNames env) = NoQ n1 -- Restore aliases | Just n1 <- findAlias (closedNames env) = NoQ n1 -- Restore aliases | otherwise = n where findAlias ((n1, NAlias n2):te) | n2 == n = Just n1 findAlias (_:te) = findAlias te findAlias [] = Nothing ================================================ FILE: compiler/lib/src/Acton/Fingerprint.hs ================================================ module Acton.Fingerprint ( fingerprintPlaceholder , fingerprintPrefixForName , formatFingerprint , formatFingerprintPrefix , parseFingerprint , updateFingerprintPrefix ) where import Data.Bits (shiftL, xor, shiftR, complement, (.|.), (.&.)) import Data.Char (isSpace, toLower) import Data.Word (Word32, Word64) import Numeric (readHex, showHex) import qualified Data.ByteString.Char8 as B import qualified Data.ByteString as BS fingerprintPlaceholder :: String fingerprintPlaceholder = "0xacedf00dacedf00d" crc32IsoHdlc :: BS.ByteString -> Word32 crc32IsoHdlc bs = complement (BS.foldl' update 0xffffffff bs) where update crc byte = go 0 (crc `xor` fromIntegral byte) go 8 crc = crc go n crc = let crc' = if (crc .&. 1) /= 0 then (crc `shiftR` 1) `xor` 0xEDB88320 else crc `shiftR` 1 in go (n + 1) crc' fingerprintPrefixForName :: String -> Word32 fingerprintPrefixForName name = crc32IsoHdlc (B.pack name) formatFingerprint :: Word64 -> String formatFingerprint fp = "0x" ++ padHex 16 fp formatFingerprintPrefix :: Word32 -> String formatFingerprintPrefix fp = "0x" ++ padHex 8 (fromIntegral fp :: Word64) updateFingerprintPrefix :: Word32 -> Word64 -> Word64 updateFingerprintPrefix prefix fp = (fromIntegral prefix `shiftL` 32) .|. (fp .&. 0xffffffff) parseFingerprint :: String -> Maybe Word64 parseFingerprint raw = let trimmed = trim raw in case trimmed of '0':'x':rest -> parseHex rest '0':'X':rest -> parseHex rest _ -> Nothing where trim = dropWhile isSpace . reverse . dropWhile isSpace . reverse parseHex s = case readHex (map toLower s) of [(n, "")] | n <= toInteger (maxBound :: Word64) -> Just (fromInteger n) _ -> Nothing padHex :: Int -> Word64 -> String padHex width value = let hex = showHex value "" zeros = replicate (max 0 (width - length hex)) '0' in zeros ++ hex ================================================ FILE: compiler/lib/src/Acton/Hashing.hs ================================================ module Acton.Hashing ( TopLevelItem(..) , topLevelItems , nameHashesFromItems , implDepsFromItems , splitDeps , externalModules , computeHashes , buildNameHashes , refreshImplHashes , modulePubHashFromIface , moduleImplHashFromNameHashes , nameKey , qnameKey ) where import qualified Acton.Env as Env import qualified Acton.NameInfo as I import qualified Acton.Names as Names import Acton.Prim (mPrim) import qualified Acton.Syntax as A import qualified InterfaceFiles import qualified Pretty import Data.Binary (encode) import qualified Crypto.Hash.SHA256 as SHA256 import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy as BL import Data.Graph (SCC(..), stronglyConnComp) import Data.List (foldl', intercalate, nub) import qualified Data.List import qualified Data.Map as M import Data.Maybe (mapMaybe) import qualified Data.Set data TopLevelItem = TLDecl A.Name A.Decl | TLStmt A.Name A.Stmt -- | Render a local name as a stable string key. nameKey :: A.Name -> String nameKey = A.nstr -- | Render a qualified name as a stable string key. qnameKey :: A.QName -> String qnameKey qn = case qn of A.GName m n -> modNameToString m ++ "." ++ A.nstr n A.QName m n -> modNameToString m ++ "." ++ A.nstr n A.NoQ n -> A.nstr n -- | Render a module name as dot-separated text. modNameToString :: A.ModName -> String modNameToString m = intercalate "." (A.modPath m) -- | Extract hashable top-level items from a module. topLevelItems :: A.Module -> [TopLevelItem] topLevelItems (A.Module _ _ _ suite) = concatMap items suite where items stmt = case stmt of A.Decl _ ds -> [ TLDecl (Names.dname' d) d | d <- ds ] A.Signature _ ns _ _ -> [ TLStmt n stmt | n <- ns ] A.Assign _ ps _ -> [ TLStmt n stmt | n <- nub (Names.bound ps) ] A.VarAssign _ ps _ -> [ TLStmt n stmt | n <- nub (Names.bound ps) ] _ -> [] -- | Collect pretty-printed fragments per top-level name. nameFragmentsFromItems :: [TopLevelItem] -> M.Map A.Name [String] nameFragmentsFromItems items = foldl' addFrag M.empty items where addFrag acc item = let (n, frag) = case item of TLDecl name decl -> (name, Pretty.print decl) TLStmt name stmt -> (name, Pretty.print stmt) in M.insertWith (flip (++)) n [frag] acc -- | Hash each name's pretty-printed fragments. nameHashesFromItems :: [TopLevelItem] -> M.Map A.Name B.ByteString nameHashesFromItems items = M.map (SHA256.hash . B.pack . intercalate "\n") (nameFragmentsFromItems items) -- | Collect qualified-name dependencies for each item body. implDepsFromItems :: [TopLevelItem] -> M.Map A.Name [A.QName] implDepsFromItems items = foldl' addDeps M.empty items where addDeps acc item = let (n, deps) = case item of TLDecl name decl -> (name, Names.freeQ decl) TLStmt name stmt -> (name, Names.freeQ stmt) in M.insertWith (++) n deps acc -- | Split deps into locals and external qualified names for hashing. splitDeps :: A.ModName -> Env.Env0 -> Data.Set.Set A.Name -> M.Map A.Name [A.QName] -> (M.Map A.Name [A.Name], M.Map A.Name [A.QName]) splitDeps mn env localNames depMap = let toLocalExt qns = foldl' step (Data.Set.empty, Data.Set.empty) qns step (locals, externals) qn = case Env.unalias env qn of A.GName m _ | m == mPrim -> (locals, externals) A.QName m _ | m == mPrim -> (locals, externals) A.GName m n | m == mn && Data.Set.member n localNames -> (Data.Set.insert n locals, externals) | m == mn -> (locals, externals) | otherwise -> (locals, Data.Set.insert (A.GName m n) externals) A.QName m n | m == mn && Data.Set.member n localNames -> (Data.Set.insert n locals, externals) | m == mn -> (locals, externals) | otherwise -> (locals, Data.Set.insert (A.GName m n) externals) A.NoQ n | Data.Set.member n localNames -> (Data.Set.insert n locals, externals) | otherwise -> (locals, externals) pairs = M.map toLocalExt depMap localMap = M.map (Data.Set.toList . fst) pairs extMap = M.map (Data.Set.toList . snd) pairs in (localMap, extMap) -- | Collect referenced external modules from dependency lists. externalModules :: M.Map A.Name [A.QName] -> Data.Set.Set A.ModName externalModules deps = Data.Set.fromList $ mapMaybe modOf (concat (M.elems deps)) where modOf qn = case qn of A.GName m _ -> Just m A.QName m _ -> Just m A.NoQ _ -> Nothing -- | Compute final hashes by folding in local and external deps. computeHashes :: M.Map A.Name B.ByteString -> M.Map A.Name [A.Name] -> M.Map A.Name [(A.QName, B.ByteString)] -> M.Map A.Name B.ByteString computeHashes selfHashes localDeps extDeps = foldl' addScc M.empty (stronglyConnComp nodes) where nodes = [ (n, n, M.findWithDefault [] n localDeps) | n <- M.keys selfHashes ] addScc acc scc = case scc of AcyclicSCC n -> let depHashes = depHashList acc (M.findWithDefault [] n localDeps) (M.findWithDefault [] n extDeps) finalHash = SHA256.hash (BL.toStrict (encode (selfHashes M.! n, depHashes))) in M.insert n finalHash acc CyclicSCC ns -> let nsSet = Data.Set.fromList ns selfHashesSorted = [ selfHashes M.! n | n <- Data.List.sortOn nameKey ns ] outsideDeps = Data.Set.toList $ Data.Set.fromList [ d | n <- ns, d <- M.findWithDefault [] n localDeps, Data.Set.notMember d nsSet ] externalDeps = Data.Set.toList $ Data.Set.fromList (concat [ M.findWithDefault [] n extDeps | n <- ns ]) depHashes = depHashList acc outsideDeps externalDeps groupHash = SHA256.hash (BL.toStrict (encode (selfHashesSorted, depHashes))) insertOne m n = let finalHash = SHA256.hash (BL.toStrict (encode (selfHashes M.! n, groupHash, nameKey n))) in M.insert n finalHash m in foldl' insertOne acc ns depHashList acc locals externals = let lookupHash n = case M.lookup n acc of Just h -> Just h Nothing -> M.lookup n selfHashes localHashes = [ h | n <- Data.List.sortOn nameKey locals , Just h <- [lookupHash n] ] externalHashes = [ h | (_, h) <- Data.List.sortOn (qnameKey . fst) externals ] in localHashes ++ externalHashes -- | Build NameHashInfo entries from per-name hashes and deps. buildNameHashes :: Data.Set.Set A.Name -> M.Map A.Name B.ByteString -> M.Map A.Name B.ByteString -> M.Map A.Name I.NameInfo -> M.Map A.Name [A.Name] -> M.Map A.Name [(A.QName, B.ByteString)] -> M.Map A.Name [A.Name] -> M.Map A.Name [(A.QName, B.ByteString)] -> M.Map A.Name [(A.QName, B.ByteString)] -> [InterfaceFiles.NameHashInfo] buildNameHashes nameKeys nameSrcHashes nameImplHashes nameInfoMap pubSigLocalDeps pubSigExtHashes implLocalDeps implExtHashes pubExtHashes = let hashNameInfo info = SHA256.hash (BL.toStrict $ encode (I.stripLocsNI (I.stripDocsNI info))) selfPubHashes = M.map hashNameInfo nameInfoMap selfImplHashes = nameImplHashes pubHashes = computeHashes selfPubHashes pubSigLocalDeps pubSigExtHashes implHashes = computeHashes selfImplHashes implLocalDeps implExtHashes namesSorted = Data.List.sortOn nameKey (Data.Set.toList nameKeys) in [ InterfaceFiles.NameHashInfo { InterfaceFiles.nhName = n , InterfaceFiles.nhSrcHash = M.findWithDefault B.empty n nameSrcHashes , InterfaceFiles.nhPubHash = M.findWithDefault B.empty n pubHashes , InterfaceFiles.nhImplHash = M.findWithDefault B.empty n implHashes , InterfaceFiles.nhPubDeps = M.findWithDefault [] n pubExtHashes , InterfaceFiles.nhImplDeps = M.findWithDefault [] n implExtHashes } | n <- namesSorted ] -- | Refresh impl hashes and impl deps for existing name hashes. refreshImplHashes :: [InterfaceFiles.NameHashInfo] -> M.Map A.Name B.ByteString -> M.Map A.Name [A.Name] -> M.Map A.Name [(A.QName, B.ByteString)] -> [InterfaceFiles.NameHashInfo] refreshImplHashes nameHashes nameImplHashes implLocalDeps implExtHashes = let implHashes = computeHashes nameImplHashes implLocalDeps implExtHashes infoMap = M.fromList [ (InterfaceFiles.nhName nh, nh) | nh <- nameHashes ] namesSorted = Data.List.sortOn nameKey (M.keys nameImplHashes) in [ let nh = infoMap M.! n in nh { InterfaceFiles.nhImplHash = M.findWithDefault B.empty n implHashes , InterfaceFiles.nhImplDeps = M.findWithDefault [] n implExtHashes } | n <- namesSorted ] -- | Hash the module public interface entries. modulePubHashFromIface :: I.NameInfo -> [InterfaceFiles.NameHashInfo] -> B.ByteString modulePubHashFromIface nmod nameHashes = let I.NModule _ iface _ = nmod pubHashMap = M.fromList [ (InterfaceFiles.nhName nh, InterfaceFiles.nhPubHash nh) | nh <- nameHashes ] pubNamesSorted = Data.List.sortOn nameKey [ n | (n, _) <- iface, Names.isPublicName n ] pubEntries = [ (nameKey n, M.findWithDefault B.empty n pubHashMap) | n <- pubNamesSorted ] in SHA256.hash (BL.toStrict $ encode pubEntries) -- | Hash the module impl entries from per-name impl hashes. moduleImplHashFromNameHashes :: [InterfaceFiles.NameHashInfo] -> B.ByteString moduleImplHashFromNameHashes infos = let items = [ (nameKey (InterfaceFiles.nhName nh), InterfaceFiles.nhImplHash nh) | nh <- Data.List.sortOn (nameKey . InterfaceFiles.nhName) infos ] in SHA256.hash (BL.toStrict (encode items)) ================================================ FILE: compiler/lib/src/Acton/Kinds.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} module Acton.Kinds(check) where import qualified Control.Exception import Control.DeepSeq (force) import qualified Data.Map.Strict as Map import Data.Map.Strict (Map) import Control.Monad.State.Strict import Control.Monad import Pretty import Utils import Acton.Syntax import Acton.Names import Acton.Builtin import Acton.Subst import Acton.NameInfo import Acton.Env check :: Env0 -> Module -> IO Module check env0 (Module m imps mdoc ss) = do Control.Exception.evaluate $ force checked where env = kindEnv env0 ss1 = runKindM (kchkTop env ss) checked = Module m imps mdoc ss1 data KindState = KindState { nextint :: Int, unisubst :: Map KUni Kind, xvars :: QBinds } type KindM a = State KindState a runKindM :: KindM a -> a runKindM m = evalState m $ KindState { nextint = 1, unisubst = Map.empty, xvars = [] } newUnique :: KindM Int newUnique = state $ \st -> (nextint st, st{ nextint = nextint st + 1 }) usubstitute :: KUni -> Kind -> KindM () usubstitute kv k = state $ \st -> ((), st{ unisubst = Map.insert kv k (unisubst st)}) usubstitution :: KindM (Map KUni Kind) usubstitution = state $ \st -> (unisubst st, st) storeXVar :: TVar -> TCon -> KindM () storeXVar xv p = state $ \st -> ((), st{ xvars = QBind xv [p] : xvars st }) swapXVars :: QBinds -> KindM QBinds swapXVars q = state $ \st -> (xvars st, st{ xvars = q }) newWildvar l = do k <- newKUni i <- newUnique return $ uniwild k l i newKUni = KUni <$> newUnique newXVar = TV KType <$> (Internal Xistvar "" <$> newUnique) type KindEnv = EnvF () kindEnv env0 = env0 tvars env = tvs (activeNames env) ++ tvs (closedNames env) where tvs te = [ TV k n | (n, NTVar k _ _) <- te ] extcons ke env = define ke env extvars vs env | not $ null clash = err1 (head clash) "Type variable already in scope:" -- No type variable shadowing | not $ null dups = err1 (head dups) "Duplicate type variable in binding:" | otherwise = return $ defineTVars [ QBind tv [] | tv <- vs ] env where clash = vs `intersect` tvars env dups = duplicates vs tcKind qn env = tconKind qn env tvKind v env = case filter (==v) (tvars env) of [] -> err1 v "Unbound type variable:" TV k _ : _ -> k instance Pretty (Name,Kind) where pretty (n,k) = pretty n <+> colon <+> pretty k autoQuantS env (TSchema l q t) = TSchema l (q ++ auto_q) t where auto_q = map qbind $ nub (vfree q ++ vfree t) \\ (tvSelf : qbound q ++ tvars env) autoQuantD env (Def l n q p k t b d x doc) = Def l n (q ++ auto_q) p k t b d x doc where auto_q = map qbind $ nub (vfree q ++ vfree p ++ vfree k ++ vfree t) \\ (tvSelf : qbound q ++ tvars env) autoQuantD env (Extension l q c ps b doc) = Extension l (q ++ auto_q) c ps b doc where auto_q = map qbind $ nub (vfree q ++ vfree c ++ vfree ps) \\ (tvSelf : qbound q ++ tvars env) autoQuantD env d = d -- TWild ~TWild -- ------------------------------------------- -- Exist | Def | TSchema,Extension | -- ------------------------------------------- -- ~Exist | Lambda,Pattern | Actor,Class,Protocol | -- ------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- -- instKWild ---------------------------------------------------------------------------------------------------------------------- class InstKWild a where instKWild :: a -> KindM a instance (InstKWild a) => InstKWild [a] where instKWild = mapM instKWild instance InstKWild Decl where instKWild d = do q <- instKWild (qbinds d); return d{ qbinds = q } instance InstKWild QBind where instKWild (QBind v us) = QBind <$> instKWild v <*> return us instance InstKWild TSchema where instKWild (TSchema l q t) = TSchema l <$> instKWild q <*> return t instance InstKWild TVar where instKWild (TV KWild n) = TV <$> newKUni <*> return n instKWild tv = return tv instance InstKWild TUni where instKWild (UV KWild l i) = do k <- newKUni; return $ UV k l i instKWild uv = return uv instance InstKWild (Maybe Type) where instKWild (Just (TVar l v)) = Just <$> TVar l <$> instKWild v instKWild x = return x ---------------------------------------------------------------------------------------------------------------------- -- convTWild ---------------------------------------------------------------------------------------------------------------------- class ConvTWild a where convTWild :: KindEnv -> a -> KindM a instance ConvTWild Type where convTWild env (TWild l) = TUni l <$> newWildvar (qlevel env) convTWild env (TFun l e p k t) = TFun l <$> convTWild env e <*> convTWild env p <*> convTWild env k <*> convTWild env t convTWild env (TTuple l p k) = TTuple l <$> convTWild env p <*> convTWild env k convTWild env (TOpt l t) = TOpt l <$> convTWild env t convTWild env (TCon l c) = TCon l <$> convTWild env c convTWild env (TRow l k n t r) = TRow l k n <$> convTWild env t <*> convTWild env r convTWild env (TStar l k r) = TStar l k <$> convTWild env r convTWild env t = return t instance ConvTWild TCon where convTWild env (TC n ts) = TC n <$> mapM (convTWild env) ts instance ConvTWild QBinds where convTWild env q = mapM instq q where instq (QBind v us) = QBind v <$> mapM (convTWild env) us instance ConvTWild (Maybe Type) where convTWild env Nothing = Just <$> convTWild env tWild convTWild env (Just t) = Just <$> convTWild env t maybeConvTWild env Nothing = return Nothing maybeConvTWild env x = convTWild env x instance ConvTWild PosPar where convTWild env (PosPar n t e p) = PosPar n <$> convTWild env t <*> return e <*> convTWild env p convTWild env (PosSTAR n Nothing) = PosSTAR n <$> Just <$> (TTuple NoLoc <$> convTWild env tWild <*> pure kwdNil) convTWild env (PosSTAR n (Just t)) | TTuple{} <- t = PosSTAR n <$> Just <$> convTWild env t | otherwise = err1 t "Tuple type expected" convTWild env PosNIL = return PosNIL instance ConvTWild KwdPar where convTWild env (KwdPar n t e k) = KwdPar n <$> convTWild env t <*> return e <*> convTWild env k convTWild env (KwdSTAR n Nothing) = KwdSTAR n <$> Just <$> (TTuple NoLoc posNil <$> convTWild env tWild) convTWild env (KwdSTAR n (Just t)) | TTuple{} <- t = KwdSTAR n <$> Just <$> convTWild env t | otherwise = err1 t "Tuple type expected" convTWild env KwdNIL = return KwdNIL ---------------------------------------------------------------------------------------------------------------------- -- convPExist ---------------------------------------------------------------------------------------------------------------------- class ConvPExist a where convPExist :: KindEnv -> a -> KindM a instance ConvPExist Type where convPExist env (TCon l c) = do c <- convPExist env c case khead $ tcKind (tcname c) env of KProto -> do xv <- newXVar storeXVar xv c return $ TVar l xv _ -> return $ TCon l c where khead (KFun _ k) = k khead k = k convPExist env (TFun l e p k t) = TFun l <$> convPExist env e <*> convPExist env p <*> convPExist env k <*> convPExist env t convPExist env (TTuple l p k) = TTuple l <$> convPExist env p <*> convPExist env k convPExist env (TOpt l t) = TOpt l <$> convPExist env t convPExist env (TRow l k n t r) = TRow l k n <$> convPExist env t <*> convPExist env r convPExist env (TStar l k r) = TStar l k <$> convPExist env r convPExist env t = return t instance ConvPExist TCon where convPExist env (TC n ts) = TC n <$> mapM (convPExist env) ts instance ConvPExist QBind where convPExist env (QBind v us) = QBind v <$> convPExist env us instance (ConvPExist a) => ConvPExist (Maybe a) where convPExist env t = sequence $ fmap (convPExist env) t instance (ConvPExist a) => ConvPExist [a] where convPExist env = mapM (convPExist env) instance ConvPExist PosPar where convPExist env (PosPar n t e p) = PosPar n <$> convPExist env t <*> return e <*> convPExist env p convPExist env (PosSTAR n t) = PosSTAR n <$> convPExist env t convPExist env PosNIL = return PosNIL instance ConvPExist KwdPar where convPExist env (KwdPar n t e k) = KwdPar n <$> convPExist env t <*> return e <*> convPExist env k convPExist env (KwdSTAR n t) = KwdSTAR n <$> convPExist env t convPExist env KwdNIL = return KwdNIL ---------------------------------------------------------------------------------------------------------------------- -- kchk ---------------------------------------------------------------------------------------------------------------------- kchkTop env ss = do ss <- kchkSuite env ss ksubst True ss class KCheck a where kchk :: KindEnv -> a -> KindM a instance KCheck a => KCheck [a] where kchk env = mapM (kchk env) instance KCheck a => KCheck (Maybe a) where kchk env = traverse (kchk env) instance (KCheck a, KCheck b) => KCheck (a,b) where kchk env (a, b) = (,) <$> kchk env a <*> kchk env b kchkSuite env [] = return [] kchkSuite env (Decl l ds : ss) = do ds <- instKWild (map (autoQuantD env) ds) let env1 = extcons (concatMap kinds ds) env ds <- kchk env1 ds ss <- kchkSuite env1 ss return (Decl l ds : ss) where kinds (Actor _ n q _ _ _ _) = [(n, NAct q posNil kwdNil [] Nothing)] kinds (Class _ n q _ _ _) = [(n, NClass q [] [] Nothing)] kinds (Protocol _ n q _ _ _)= [(n, NProto q [] [] Nothing)] kinds _ = [] kind k [] = k kind k q = KFun [ tvkind v | QBind v _ <- q ] k kchkSuite env (s : ss) = do s <- kchk env s; ss <- kchkSuite env ss; return (s:ss) instance KCheck Stmt where kchk env (Expr l e) = Expr l <$> kchk env e kchk env (Assign l ps e) = Assign l <$> kchk env ps <*> kchk env e kchk env (MutAssign l t e) = MutAssign l <$> kchk env t <*> kchk env e kchk env (AugAssign l t op e) = AugAssign l <$> kchk env t <*> return op <*> kchk env e kchk env (Assert l e mbe) = Assert l <$> kchk env e <*> kchk env mbe kchk env (Pass l) = return $ Pass l kchk env (Delete l t) = Delete l <$> kchk env t kchk env (Return l mbe) = Return l <$> kchk env mbe kchk env (Raise l e) = Raise l <$> kchk env e kchk env (Break l) = return $ Break l kchk env (Continue l) = return $ Continue l kchk env (If l bs els) = If l <$> kchk env bs <*> kchkSuite env els kchk env (While l e b els) = While l <$> kchk env e <*> kchkSuite env b <*> kchkSuite env els kchk env (For l p e b els) = For l <$> kchk env p <*> kchk env e <*> kchkSuite env b <*> kchkSuite env els kchk env (Try l b hs els fin) = Try l <$> kchkSuite env b <*> kchk env hs <*> kchkSuite env els <*> kchkSuite env fin kchk env (With l is b) = With l <$> kchk env is <*> kchkSuite env b kchk env (Data l mbt ss) = Data l <$> kchk env mbt <*> kchkSuite env ss kchk env (VarAssign l ps e) = VarAssign l <$> kchk env ps <*> kchk env e kchk env (After l e e') = After l <$> kchk env e <*> kchk env e' kchk env (Decl l ds) = Decl l <$> kchk env ds kchk env (Signature l ns sc d) = Signature l ns <$> (kchk env =<< instKWild (autoQuantS env sc)) <*> return d instance KCheck Decl where kchk env (Def l n q p k t b d x doc) | not $ null ambig = err2 ambig "Ambiguous type variable in annotation:" | otherwise = do tmp <- swapXVars [] q <- convPExist env q p <- convPExist env p k <- convPExist env k t <- convPExist env t x <- convPExist env x q <- (q++) <$> swapXVars tmp env1 <- extvars (qbound q) env q <- convTWild env1 q p <- convTWild env1 p k <- convTWild env1 k t <- convTWild env1 t x <- convTWild env1 x Def l n <$> kchkQBinds env1 q <*> kchk env1 p <*> kchk env1 k <*> kexp KType env1 t <*> kchkSuite env1 b <*> pure d <*> kfx env1 x <*> pure doc where ambig = qualbound q \\ closeDepVarsQ (vfree p ++ vfree k ++ vfree t ++ vfree x) q kchk env (Actor l n q p k b doc)= do tmp <- swapXVars [] p <- convPExist env p k <- convPExist env k q <- (q++) <$> swapXVars tmp env1 <- extvars (qbound q) env p <- convTWild env1 p k <- convTWild env1 k Actor l n <$> kchkQBinds env1 q <*> kchk env1 p <*> kchk env1 k <*> kchkSuite env1 b <*> pure doc kchk env (Class l n q us b doc) = do env1 <- extvars (tvSelf : qbound q) env Class l n <$> kchkQBinds env1 q <*> kchkBounds env1 us <*> kchkSuite env1 b <*> pure doc kchk env (Protocol l n q us b doc) = do env1 <- extvars (tvSelf : qbound q) env Protocol l n <$> kchkQBinds env1 q <*> kchkPBounds env1 us <*> kchkSuite env1 b <*> pure doc kchk env (Extension l q c us b doc) | not $ null ambig = err2 ambig "Ambiguous type variables in extension:" | not $ null undet = err2 undet "Type variables undetermined by extended class:" | otherwise = do tmp <- swapXVars [] q <- convPExist env q c <- convPExist env c us <- convPExist env us q <- (q++) <$> swapXVars tmp env1 <- extvars (tvSelf : qbound q) env Extension l <$> kchkQBinds env1 q <*> kexp KType env1 c <*> kchkPBounds env1 us <*> kchkSuite env1 b <*> pure doc where ambig = qualbound q \\ vs undet = vfree us \\ (tvSelf : vs) vs = closeDepVarsQ (vfree c) q instance KCheck Expr where kchk env (Var l n) = return $ Var l n kchk env (Int l i s) = return $ Int l i s kchk env (Float l f s) = return $ Float l f s kchk env (Imaginary l i s) = return $ Imaginary l i s kchk env (Bool l b) = return $ Bool l b kchk env (None l) = return $ None l kchk env (NotImplemented l) = return $ NotImplemented l kchk env (Ellipsis l) = return $ Ellipsis l kchk env (Strings l ss) = return $ Strings l ss kchk env (BStrings l ss) = return $ BStrings l ss kchk env (Call l e ps ks) = Call l <$> kchk env e <*> kchk env ps <*> kchk env ks kchk env (TApp l e ts) = internal l "Unexpected TApp in kchk" kchk env (Let l ss e) = Let l <$> kchk env ss <*> kchk env e kchk env (Async l e) = Async l <$> kchk env e kchk env (Await l e) = Await l <$> kchk env e kchk env (Index l e is) = Index l <$> kchk env e <*> kchk env is kchk env (Slice l e sl) = Slice l <$> kchk env e <*> kchk env sl kchk env (Cond l e1 e2 e3) = Cond l <$> kchk env e1 <*> kchk env e2 <*> kchk env e3 kchk env (IsInstance l e c) = IsInstance l <$> kchk env e <*> return (unalias env c) kchk env (BinOp l e1 op e2) = BinOp l <$> kchk env e1 <*> return op <*> kchk env e2 kchk env (CompOp l e ops) = CompOp l <$> kchk env e <*> kchk env ops kchk env (UnOp l op e) = UnOp l op <$> kchk env e kchk env (Dot l e n) | Just m <- isModule env e = return $ Var l (QName m n) | otherwise = Dot l <$> kchk env e <*> return n kchk env (Rest l e n) = Rest l <$> kchk env e <*> return n kchk env (DotI l e i) = DotI l <$> kchk env e <*> return i kchk env (RestI l e i) = RestI l <$> kchk env e <*> return i kchk env (Opt l e b) = Opt l <$> kchk env e <*> return b kchk env (OptChain l e) = OptChain l <$> kchk env e kchk env (Lambda l p k e x) = Lambda l <$> (kchk env =<< convTWild env p) <*> (kchk env =<< convTWild env k) <*> kchk env e <*> (kfx env =<< convTWild env x) kchk env (Yield l e) = Yield l <$> kchk env e kchk env (YieldFrom l e) = YieldFrom l <$> kchk env e kchk env (Tuple l es ks) = Tuple l <$> kchk env es <*> kchk env ks kchk env (List l es) = List l <$> kchk env es kchk env (ListComp l e c) = ListComp l <$> kchk env e <*> kchk env c kchk env (Dict l as) = Dict l <$> kchk env as kchk env (DictComp l a c) = DictComp l <$> kchk env a <*> kchk env c kchk env (Set l es) = Set l <$> kchk env es kchk env (SetComp l e c) = SetComp l <$> kchk env e <*> kchk env c kchk env (Paren l e) = Paren l <$> kchk env e isModule env e = fmap ModName $ mfilter (isMod env) $ fmap reverse $ dotChain e where dotChain (Var _ (NoQ n)) = Just [n] dotChain (Dot _ e n) = fmap (n:) (dotChain e) dotChain _ = Nothing instance KCheck Pattern where kchk env (PWild l t) = PWild l <$> (kexp KType env =<< maybeConvTWild env t) kchk env (PVar l n t) = PVar l n <$> (kexp KType env =<< maybeConvTWild env t) kchk env (PTuple l ps ks) = PTuple l <$> kchk env ps <*> kchk env ks kchk env (PList l ps p) = PList l <$> kchk env ps <*> kchk env p kchk env (PParen l p) = PParen l <$> kchk env p instance KCheck Branch where kchk env (Branch e ss) = Branch <$> kchk env e <*> kchkSuite env ss instance KCheck Handler where kchk env (Handler ex b) = Handler <$> kchk env ex <*> kchkSuite env b instance KCheck Except where kchk env (ExceptAll l) = return $ ExceptAll l kchk env (Except l x) = do kexp KType env (TC x []); return $ Except l x kchk env (ExceptAs l x n) = do kexp KType env (TC x []); return $ ExceptAs l x n instance KCheck PosPar where kchk env (PosPar n t e p) = PosPar n <$> kexp KType env t <*> kchk env e <*> kchk env p kchk env (PosSTAR n t) = PosSTAR n <$> kexp KType env t kchk env PosNIL = return PosNIL instance KCheck KwdPar where kchk env (KwdPar n t e k) = KwdPar n <$> kexp KType env t <*> kchk env e <*> kchk env k kchk env (KwdSTAR n t) = KwdSTAR n <$> kexp KType env t kchk env KwdNIL = return KwdNIL instance KCheck PosArg where kchk env (PosArg e p) = PosArg <$> kchk env e <*> kchk env p kchk env (PosStar e) = PosStar <$> kchk env e kchk env PosNil = return PosNil instance KCheck KwdArg where kchk env (KwdArg n e k) = KwdArg n <$> kchk env e <*> kchk env k kchk env (KwdStar e) = KwdStar <$> kchk env e kchk env KwdNil = return KwdNil instance KCheck PosPat where kchk env (PosPat p ps) = PosPat <$> kchk env p <*> kchk env ps kchk env (PosPatStar p) = PosPatStar <$> kchk env p kchk env PosPatNil = return PosPatNil instance KCheck KwdPat where kchk env (KwdPat n p ps) = KwdPat n <$> kchk env p <*> kchk env ps kchk env (KwdPatStar p) = KwdPatStar <$> kchk env p kchk env KwdPatNil = return KwdPatNil instance KCheck OpArg where kchk env (OpArg op e) = OpArg op <$> kchk env e instance KCheck Comp where kchk env (CompFor l p e c) = CompFor l <$> kchk env p <*> kchk env e <*> kchk env c kchk env (CompIf l e c) = CompIf l <$> kchk env e <*> kchk env c kchk env NoComp = return NoComp instance KCheck WithItem where kchk env (WithItem e p) = WithItem <$> kchk env e <*> kchk env p instance KCheck Elem where kchk env (Elem e) = Elem <$> kchk env e kchk env (Star e) = Star <$> kchk env e instance KCheck Assoc where kchk env (Assoc e1 e2) = Assoc <$> kchk env e1 <*> kchk env e2 kchk env (StarStar e) = StarStar <$> kchk env e instance KCheck Sliz where kchk env (Sliz l e1 e2 e3) = Sliz l <$> kchk env e1 <*> kchk env e2 <*> kchk env e3 instance KCheck TSchema where kchk env (TSchema l q t) | not $ null ambig = err2 ambig "Ambiguous type variable in schema:" | otherwise = do tmp <- swapXVars [] q <- convPExist env q t <- convPExist env t q <- (q++) <$> swapXVars tmp env1 <- extvars (qbound q) env TSchema l <$> kchkQBinds env1 q <*> kexp KType env1 t where ambig = qualbound q \\ closeDepVarsQ (vfree t) q kchkQBinds env [] = return [] kchkQBinds env (QBind v us : q) = do us <- kchkBounds env us q <- kchkQBinds env q return $ QBind v us : q kchkBounds env [] = return [] kchkBounds env (u:us) = do (k,u) <- kinfer env u case k of KProto -> (:) u <$> kchkPBounds env us _ -> do kunify (loc u) k KType; (:) u <$> kchkPBounds env us kchkPBounds env us = mapM (kexp KProto env) us ---------------------------------------------------------------------------------------------------------------------- -- kinfer ---------------------------------------------------------------------------------------------------------------------- class KInfer t where kinfer :: KindEnv -> t -> KindM (Kind,t) instance (KInfer t) => KInfer (Maybe t) where kinfer env Nothing = do k <- newKUni; return (k, Nothing) kinfer env (Just t) = do (k,t) <- kinfer env t; return (k, Just t) instance KInfer TVar where kinfer env tv = do tv <- instKWild tv return (tvkind tv, tv) instance KInfer TUni where kinfer env uv = do uv <- instKWild uv return (uvkind uv, uv) instance KInfer TCon where kinfer env (TC n []) = return (tcKind n env, TC (unalias env n) []) kinfer env (TC n ts) = do let kn = tcKind n env (ks,ts) <- fmap unzip $ mapM (kinfer env) ts k <- newKUni kunify (loc n) kn (KFun ks k) k <- ksubst False k return (k, TC (unalias env n) ts) envBound (TV k (Internal p _ _)) = False envBound _ = True instance KInfer Type where kinfer env (TWild l) = err1 l "Illegal wildcard type" kinfer env (TVar l v) = do (k,v) <- kinfer env v kunify l k (tvKind v env) return (k, TVar l v) kinfer env (TUni l u) = do (k,u) <- kinfer env u -- Internal tyvars are not in the environment return (k, TUni l u) kinfer env (TCon l c) = do c <- kexp KType env c return (KType, TCon l c) kinfer env (TFun l fx p k t) = do fx <- kfx env fx p <- kexp PRow env p k <- kexp KRow env k t <- kexp KType env t return (KType, TFun l fx p k t) kinfer env (TTuple l p k) = do p <- kexp PRow env p k <- kexp KRow env k return (KType, TTuple l p k) kinfer env (TOpt _ t@TOpt{}) = kinfer env t kinfer env (TOpt l t) = do t <- kexp KType env t return (KType, TOpt l t) kinfer env (TNone l) = return (KType, TNone l) kinfer env (TNil l k) = return (k, TNil l k) kinfer env (TRow l k n t r) = do t <- kexp KType env t r <- kexp k env r return (k, TRow l k n t r) kinfer env (TStar l k r) = do r <- kexp k env r return (k, TStar l k r) kinfer env (TFX l fx) = return (KFX, TFX l fx) kfx env (TVar _ tv) = variableFX tv kfx env t = kexp KFX env t kexp k env t = do (k',t') <- kinfer env t kunify (loc t) k' k return t' ---------------------------------------------------------------------------------------------------------------------- -- kunify ---------------------------------------------------------------------------------------------------------------------- kunify l k1 k2 = do k1 <- ksubst False k1; k2 <- ksubst False k2; kunify' l k1 k2 kunify' l (KUni v1) (KUni v2) | v1 == v2 = return () kunify' l (KUni v) k2 = do when (v `elem` kfree k2) (infiniteKind l v k2) usubstitute v k2 kunify' l k1 (KUni v) = do when (v `elem` kfree k1) (infiniteKind l v k1) usubstitute v k1 kunify' l (KFun ks1 k1) (KFun ks2 k2) | length ks1 == length ks2 = do mapM_ (uncurry $ kunify l) (ks1 `zip` ks2) kunify l k1 k2 kunify' l k1 k2 | k1 == k2 = return () | otherwise = noKUnify l k1 k2 kfree (KUni v) = [] kfree (KFun ks k) = concatMap kfree (k:ks) kfree _ = [] ---------------------------------------------------------------------------------------------------------------------- -- ksubst ---------------------------------------------------------------------------------------------------------------------- class KSubst s where ksubst :: Bool -> s -> KindM s -- Bool flag controls whether free KUnis are replaced with KType or not instance KSubst a => KSubst [a] where ksubst g = mapM (ksubst g) instance KSubst a => KSubst (Maybe a) where ksubst g = maybe (return Nothing) (\x -> Just <$> ksubst g x) instance (KSubst a, KSubst b) => KSubst (a,b) where ksubst g (a, b) = (,) <$> ksubst g a <*> ksubst g b instance KSubst Kind where ksubst g KWild = return KWild ksubst g (KUni i) = do s <- usubstitution case Map.lookup i s of Just k -> ksubst g k Nothing -> return (if g then KType else KUni i) ksubst g (KFun ks k) = KFun <$> mapM (ksubst g) ks <*> ksubst g k ksubst g k = return k instance KSubst TSchema where ksubst g (TSchema l q t) = TSchema l <$> ksubst g q <*> ksubst g t instance KSubst TVar where ksubst g (TV k n) = TV <$> ksubst g k <*> return n instance KSubst TUni where ksubst g (UV k l i) = do k <- ksubst g k; return $ UV k l i instance KSubst TCon where ksubst g (TC n ts) = TC n <$> ksubst g ts instance KSubst QBind where ksubst g (QBind v cs) = QBind <$> ksubst g v <*> ksubst g cs instance KSubst Type where ksubst g (TVar l v) = TVar l <$> ksubst g v ksubst g (TUni l u) = TUni l <$> ksubst g u ksubst g (TCon l c) = TCon l <$> ksubst g c ksubst g (TFun l fx p k t) = TFun l <$> ksubst g fx <*> ksubst g p <*> ksubst g k<*> ksubst g t ksubst g (TTuple l p k) = TTuple l <$> ksubst g p <*> ksubst g k ksubst g (TOpt l t) = TOpt l <$> ksubst g t ksubst g (TNone l) = return $ TNone l ksubst g (TNil l s) = return $ TNil l s ksubst g (TRow l k n t r) = TRow l k n <$> ksubst g t <*> ksubst g r ksubst g (TStar l k r) = TStar l k <$> ksubst g r ksubst g (TFX l fx) = return $ TFX l fx instance KSubst Stmt where ksubst g (Expr l e) = Expr l <$> ksubst g e ksubst g (Assign l ps e) = Assign l <$> ksubst g ps <*> ksubst g e ksubst g (MutAssign l t e) = MutAssign l <$> ksubst g t <*> ksubst g e ksubst g (AugAssign l t op e) = AugAssign l <$> ksubst g t <*> return op <*> ksubst g e ksubst g (Assert l e mbe) = Assert l <$> ksubst g e <*> ksubst g mbe ksubst g (Pass l) = return $ Pass l ksubst g (Delete l t) = Delete l <$> ksubst g t ksubst g (Return l mbe) = Return l <$> ksubst g mbe ksubst g (Raise l e) = Raise l <$> ksubst g e ksubst g (Break l) = return $ Break l ksubst g (Continue l) = return $ Continue l ksubst g (If l bs els) = If l <$> ksubst g bs <*> ksubst g els ksubst g (While l e b els) = While l <$> ksubst g e <*> ksubst g b <*> ksubst g els ksubst g (For l p e b els) = For l <$> ksubst g p <*> ksubst g e <*> ksubst g b <*> ksubst g els ksubst g (Try l b hs els fin) = Try l <$> ksubst g b <*> ksubst g hs <*> ksubst g els <*> ksubst g fin ksubst g (With l is b) = With l <$> ksubst g is <*> ksubst g b ksubst g (Data l mbt ss) = Data l <$> ksubst g mbt <*> ksubst g ss ksubst g (VarAssign l ps e) = VarAssign l <$> ksubst g ps <*> ksubst g e ksubst g (After l e e') = After l <$> ksubst g e <*> ksubst g e' ksubst g (Decl l ds) = Decl l <$> ksubst g ds ksubst g (Signature l ns t d) = Signature l ns <$> ksubst g t <*> return d instance KSubst Decl where ksubst g (Def l n q p k a b d x doc) = Def l n <$> ksubst g q <*> ksubst g p <*> ksubst g k <*> ksubst g a <*> ksubst g b <*> return d <*> ksubst g x <*> return doc ksubst g (Actor l n q p k b doc) = Actor l n <$> ksubst g q <*> ksubst g p <*> ksubst g k <*> ksubst g b <*> return doc ksubst g (Class l n q as b doc) = Class l n <$> ksubst g q <*> ksubst g as <*> ksubst g b <*> return doc ksubst g (Protocol l n q as b doc) = Protocol l n <$> ksubst g q <*> ksubst g as <*> ksubst g b <*> return doc ksubst g (Extension l q c as b doc) = Extension l <$> ksubst g q <*> ksubst g c <*> ksubst g as <*> ksubst g b <*> return doc instance KSubst Expr where ksubst g (Var l n) = return $ Var l n ksubst g (Int l i s) = return $ Int l i s ksubst g (Float l f s) = return $ Float l f s ksubst g (Imaginary l i s) = return $ Imaginary l i s ksubst g (Bool l b) = return $ Bool l b ksubst g (None l) = return $ None l ksubst g (NotImplemented l) = return $ NotImplemented l ksubst g (Ellipsis l) = return $ Ellipsis l ksubst g (Strings l ss) = return $ Strings l ss ksubst g (BStrings l ss) = return $ BStrings l ss ksubst g (Call l e ps ks) = Call l <$> ksubst g e <*> ksubst g ps <*> ksubst g ks ksubst g (TApp l e ts) = TApp l <$> ksubst g e <*> ksubst g ts ksubst g (Let l ss e) = Let l <$> ksubst g ss <*> ksubst g e ksubst g (Async l e) = Async l <$> ksubst g e ksubst g (Await l e) = Await l <$> ksubst g e ksubst g (Index l e is) = Index l <$> ksubst g e <*> ksubst g is ksubst g (Slice l e sl) = Slice l <$> ksubst g e <*> ksubst g sl ksubst g (Cond l e1 e2 e3) = Cond l <$> ksubst g e1 <*> ksubst g e2 <*> ksubst g e3 ksubst g (IsInstance l e c) = IsInstance l <$> ksubst g e <*> return c ksubst g (BinOp l e1 op e2) = BinOp l <$> ksubst g e1 <*> return op <*> ksubst g e2 ksubst g (CompOp l e ops) = CompOp l <$> ksubst g e <*> ksubst g ops ksubst g (UnOp l op e) = UnOp l op <$> ksubst g e ksubst g (Dot l e n) = Dot l <$> ksubst g e <*> return n ksubst g (Rest l e n) = Rest l <$> ksubst g e <*> return n ksubst g (DotI l e i) = DotI l <$> ksubst g e <*> return i ksubst g (RestI l e i) = RestI l <$> ksubst g e <*> return i ksubst g (Opt l e b) = Opt l <$> ksubst g e <*> return b ksubst g (OptChain l e) = OptChain l <$> ksubst g e ksubst g (Lambda l ps ks e fx) = Lambda l <$> ksubst g ps <*> ksubst g ks <*> ksubst g e <*> ksubst g fx ksubst g (Yield l e) = Yield l <$> ksubst g e ksubst g (YieldFrom l e) = YieldFrom l <$> ksubst g e ksubst g (Tuple l es ks) = Tuple l <$> ksubst g es <*> ksubst g ks ksubst g (List l es) = List l <$> ksubst g es ksubst g (ListComp l e c) = ListComp l <$> ksubst g e <*> ksubst g c ksubst g (Dict l as) = Dict l <$> ksubst g as ksubst g (DictComp l a c) = DictComp l <$> ksubst g a <*> ksubst g c ksubst g (Set l es) = Set l <$> ksubst g es ksubst g (SetComp l e c) = SetComp l <$> ksubst g e <*> ksubst g c ksubst g (Paren l e) = Paren l <$> ksubst g e instance KSubst Pattern where ksubst g (PWild l a) = PWild l <$> ksubst g a ksubst g (PVar l n a) = PVar l n <$> ksubst g a ksubst g (PTuple l ps ks) = PTuple l <$> ksubst g ps <*> ksubst g ks ksubst g (PList l ps p) = PList l <$> ksubst g ps <*> ksubst g p ksubst g (PParen l p) = PParen l <$> ksubst g p instance KSubst Branch where ksubst g (Branch e ss) = Branch <$> ksubst g e <*> ksubst g ss instance KSubst Handler where ksubst g (Handler ex b) = Handler ex <$> ksubst g b instance KSubst PosPar where ksubst g (PosPar n t e p) = PosPar n <$> ksubst g t <*> ksubst g e <*> ksubst g p ksubst g (PosSTAR n t) = PosSTAR n <$> ksubst g t ksubst g PosNIL = return PosNIL instance KSubst KwdPar where ksubst g (KwdPar n t e k) = KwdPar n <$> ksubst g t <*> ksubst g e <*> ksubst g k ksubst g (KwdSTAR n t) = KwdSTAR n <$> ksubst g t ksubst g KwdNIL = return KwdNIL instance KSubst PosArg where ksubst g (PosArg e p) = PosArg <$> ksubst g e <*> ksubst g p ksubst g (PosStar e) = PosStar <$> ksubst g e ksubst g PosNil = return PosNil instance KSubst KwdArg where ksubst g (KwdArg n e k) = KwdArg n <$> ksubst g e <*> ksubst g k ksubst g (KwdStar e) = KwdStar <$> ksubst g e ksubst g KwdNil = return KwdNil instance KSubst PosPat where ksubst g (PosPat p ps) = PosPat <$> ksubst g p <*> ksubst g ps ksubst g (PosPatStar p) = PosPatStar <$> ksubst g p ksubst g PosPatNil = return PosPatNil instance KSubst KwdPat where ksubst g (KwdPat n p ps) = KwdPat n <$> ksubst g p <*> ksubst g ps ksubst g (KwdPatStar p) = KwdPatStar <$> ksubst g p ksubst g KwdPatNil = return KwdPatNil instance KSubst OpArg where ksubst g (OpArg op e) = OpArg op <$> ksubst g e instance KSubst Comp where ksubst g (CompFor l p e c) = CompFor l <$> ksubst g p <*> ksubst g e <*> ksubst g c ksubst g (CompIf l e c) = CompIf l <$> ksubst g e <*> ksubst g c ksubst g NoComp = return NoComp instance KSubst WithItem where ksubst g (WithItem e p) = WithItem <$> ksubst g e <*> ksubst g p instance KSubst Elem where ksubst g (Elem e) = Elem <$> ksubst g e ksubst g (Star e) = Star <$> ksubst g e instance KSubst Assoc where ksubst g (Assoc e1 e2) = Assoc <$> ksubst g e1 <*> ksubst g e2 ksubst g (StarStar e) = StarStar <$> ksubst g e instance KSubst Sliz where ksubst g (Sliz l e1 e2 e3) = Sliz l <$> ksubst g e1 <*> ksubst g e2 <*> ksubst g e3 ================================================ FILE: compiler/lib/src/Acton/LambdaLifter.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances #-} module Acton.LambdaLifter(liftModule) where import Control.Monad.State.Strict import Utils import Acton.Syntax import Acton.Names import Acton.Builtin import Acton.Prim import Acton.Printer import Acton.NameInfo import Acton.Env import Acton.QuickType import Acton.Subst import Pretty import Prelude hiding((<>)) liftModule env0 (Module m imp mdoc stmts) = return $ (Module m imp mdoc stmts', mapModules1 conv env0) where stmts' = runL (llSuite (liftEnv env0) stmts) -- L :: list of all local variables and parameters in scope, initially empty (locals) -- F :: map of all function names in scope to their (expanded) set of free variables, initially empty (freemap) -- N :: map of all function names in scope to their unique aliases, initially empty (namemap) -- Lambda-lifting -- -------------- -- For each successive statement s in a function body: -- If s is a declaration group defining functions fs (classes cannot occur in function bodies): -- Let M be a map of each f in fs to its free variables (funfree0) -- For each f in fs and each g in M(f) such that M(g) exists: add M(g) to M(f) -- Iterate until M reaches a fixpoint (funfree) -- For each f in fs and each g in M(f) such that F(g) exists: add F(g) to M(f) -- For each f in fs: restrict M(f) to L -- Extend F with M -- Extend N by mapping each f in fs to a globally unique name -- For each def f[q](ws):b in s: -- Extend L with ws -- Recursively transform b into b' -- Add def N(f) [q] (*F(f),ws):b' to the module top level -- Replace s with 'pass' -- Otherwise s is a non-def statement binding names vs (possibly empty): -- Replace any call g@ts(es) in s, where g is in F, by N(g)@ts(*F(g),es) -- Replace all non-call references in s to any g@ts in F by lambda ws: g@ts(*F(g),ws), where ws are the parameters of g -- Extend L with vs -- Closure conversion -- ------------------ -- For each successive (non-def) statement s in any lambda-lifted statement list: -- Replace any lambda ws: e in s by Lam(vs), -- where Lam is a new class name defined as -- class Lam (function[x,p,(),t]): -- def __init__(self,vs'): self.vs' = vs' -- def __call__(self,ws): vs' = self.vs'; return e -- and x, p, t and vs' are the parameter row, return type and free variables (restricted to L) of the lambda expression -- Replace any call e(es) in s, where e has a closure type (not a known function or method), by e.__call__(es) -- Extend L with vs (the variables bound by s) -- Lift monad ---------------------------------------------------------------------------------------------------------- type LiftM a = State LiftState a type LiftState = ([Decl],[Int]) -- lifted defs, name supply runL :: LiftM a -> a runL m = evalState m ([],[1..]) newName :: String -> LiftM Name newName s = state (\(totop,uniq:supply) -> (Internal LLiftPass s uniq, (totop,supply))) liftToTop :: [Decl] -> LiftM () liftToTop ds = state (\(totop,supply) -> ((), (totop++ds,supply))) liftedToTop :: LiftM [Decl] liftedToTop = state (\(totop,supply) -> (totop, ([],supply))) llCont = Internal LLiftPass "cont" 0 llSelf = Internal LLiftPass "self" 0 -- Environment --------------------------------------------------------------------------------------------------------- type LiftEnv = EnvF LiftX data LiftX = LiftX { ctxtX :: LiftCtxt, localsX :: [(Name,Type)], freemapX :: [(Name,[Name])], quantmapX :: [(Name,[TVar])], namemapX :: [(Name,Name)] } deriving (Eq,Show) data LiftCtxt = OnTop | InDef | InClass deriving (Eq,Show) instance Pretty (Name, [Name]) where pretty (n,ns) = pretty n <+> braces (commaSep pretty ns) liftEnv env0 = setX env0 LiftX{ ctxtX = OnTop, localsX = [], freemapX = [], quantmapX = [], namemapX = [] } ctxt env = ctxtX $ envX env setCtxt c env = modX env $ \x -> x{ ctxtX = c } locals env = localsX $ envX env freemap env = freemapX $ envX env quantmap env = quantmapX $ envX env namemap env = namemapX $ envX env extLocals e env = modX env $ \x -> x{ localsX = vts ++ locals env `exclude` dom vts } where vts = [ (v, conv t) | (v,NVar t) <- envOf e ] extFree m env = modX env $ \x -> x{ freemapX = m ++ freemap env, quantmapX = [ (f, qbound $ quantScope env) | f <- dom m ] ++ quantmap env } extNames m env = modX env $ \x -> x{ namemapX = m ++ namemap env } findFree n env = case lookup n (freemap env) of Just vs -> Just [ (v,t) | v <- vs, Just t <- [lookup v $ locals env] ] _ -> Nothing liftedName env n = case lookup n (namemap env) of Just n' -> n' _ -> n extraArgs env n = case findFree n env of Just vts -> vts _ -> [] -- Helpers ------------------------------------------------------------------------------------------------------------------ expand funfree0 funfree = map exp1 funfree where exp1 (f,vs) = (f, nub (concat (vs : catMaybes [ lookup v funfree0 | v <- vs ]))) iterexpand funfree | len funfree == len funfree' = funfree | otherwise = iterexpand funfree' where funfree' = expand funfree funfree len = map (length . snd) addParams vts ps = foldr (\(n,t) p -> PosPar n (Just t) Nothing p) ps vts addArgs vts p = foldr (PosArg . eVar) p (dom vts) ---------------------------------------------------------------------------------------------------------- class Lift e where ll :: LiftEnv -> e -> LiftM e instance Lift a => Lift (Maybe a) where ll env = traverse (ll env) instance (Lift a, EnvOf a, Vars a) => Lift [a] where ll env [] = return [] ll env (a:as) | ctxt env == InDef = (:) <$> ll env a <*> ll (extLocals a env1) as | otherwise = (:) <$> ll env a <*> ll env1 as where env1 = define (envOf a) env llSuite env [] = return [] llSuite env (Decl l ds : ss) | ctxt env == InDef = do ns <- zip fs <$> mapM (newName . nstr) (bound ds) let env1 = extNames ns env' ds1 <- ll env1 ds liftToTop (vsubst (selfScopeSubst env) ds1) llSuite env1 ss | ctxt env == InClass = do ds' <- ll env1 ds ss' <- llSuite env1 ss return $ Decl l ds' : ss' | ctxt env == OnTop = do ds1 <- ll env1 ds ds2 <- liftedToTop ss' <- llSuite env1 ss return $ Decl l (ds2++ds1) : ss' where env' = extFree funfree $ define (envOf ds) env funfree = [ (n, vs \\ bound p) | (n,vs) <- funfree1, let p = [ pos d | d <- ds, dname d == n ] ] funfree1 = expand (freemap env) $ iterexpand funfree0 funfree0 = [ (dname d, nub $ free d) | d@Def{} <- ds ] fs = dom funfree0 env1 = define (envOf ds) env llSuite env (s : ss) | ctxt env == InDef = (:) <$> ll env s <*> llSuite (extLocals s env1) ss | ctxt env == InClass = (:) <$> ll env s <*> llSuite env1 ss | ctxt env == OnTop = do s' <- ll env s ds <- liftedToTop ss' <- llSuite env1 ss return $ if null ds then s':ss' else Decl l0 ds : s' : ss' where env1 = define (envOf s) env instance Lift Stmt where ll env (Return l (Just (Call _ e p KwdNil))) | closedType env e, effect t == fxProc, not (isCont t) = do e' <- llSub env e -- A CPS-converted proc, but not a $Cont! p' <- ll env p return $ Return l $ Just $ Call l (eDot e' attr_exec_) p' KwdNil where t = typeOf env e ll env (Expr l e) = Expr l <$> ll env e ll env (Assign l pats e) = Assign l <$> ll env pats <*> ll env e ll env (MutAssign l t e) = MutAssign l <$> ll env t <*> ll env e ll env (Return l e) = Return l <$> ll env e ll env s@(Pass _) = pure s ll env s@(Break _) = pure s ll env s@(Continue _) = pure s ll env (If l branches els) = If l <$> ll env branches <*> llSuite env els ll env (While l e b els) = While l <$> ll env e <*> llSuite env b <*> llSuite env els ll env (Signature l ns sc Property) = pure $ Signature l ns (conv sc) Property ll env (Signature l ns sc dec) = pure $ Signature l ns (convTop sc) dec ll env s = error ("ll unexpected: " ++ prstr s) instance Lift Decl where ll env (Def l n q p KwdNIL a b d fx doc) = do b' <- llSuite (setCtxt InDef env1) b return $ Def l n' q' p' KwdNIL (conv a) b' d fx doc where env1 = extLocals p $ define (envOf p) $ defineTVars q env q' = if ctxt env == InDef then quantScope env ++ q else q p' = addParams vts (conv p) n' = liftedName env n vts = extraArgs env n ll env (Class l n q cs b doc) = do b' <- llSuite (setCtxt InClass env1) b return $ Class l n q (conv cs) b' doc where env1 = defineTVars (selfQuant (NoQ n) q) env ll env d = error ("ll unexpected: " ++ prstr d) instance Lift Branch where ll env (Branch e ss) = Branch <$> ll env e <*> llSuite env ss freefun env e@(Var l qn@(NoQ n)) | Just vts <- findFree n env = Just (tApp (Var l (NoQ $ liftedName env n)) (map tVar tvs), vts) where Just tvs = lookup n (quantmap env) freefun env (Var l n) | isDefOrClass env n = Just (Var l (primSubst n), []) freefun env (TApp l e@(Var l' qn@(NoQ n)) ts) | Just vts <- findFree n env = Just (TApp l (Var l' (NoQ $ liftedName env n)) (map tVar tvs ++ conv ts), vts) where Just tvs = lookup n (quantmap env) freefun env (TApp l (Var l' n) ts) | isDefOrClass env n = Just (TApp l (Var l' (primSubst n)) (conv ts), []) freefun env e = Nothing closureConvert env lambda t0 vts0 es = do n <- newName (nstr $ noq basename) --traceM ("## closureConvert " ++ prstr lambda ++ " as " ++ prstr n) liftToTop [Class l0 n q bases body Nothing] return $ eCall (tApp (eVar n) (map tVar $ qbound q)) es where q = quantScope env s = selfScopeSubst env Lambda _ p _ e fx = vsubst s lambda t1 = vsubst s t0 cBase = conv $ closureCon fx (prowOf p) t1 basename = tcname cBase bases = map snd $ findAncestry env cBase vts = conv $ vsubst s vts0 body = props ++ [Decl l0 [initDef], Decl l0 defs] props = [ Signature l0 [v] (monotype t) Property | (v,t) <- vsubst s vts ] initDef = Def l0 initKW [] initPars KwdNIL (Just tNone) (initBody++[sReturn eNone]) NoDec fxPure Nothing initPars = PosPar llSelf (Just tSelf) Nothing $ pospar vts initBody = mkBody [ MutAssign l0 (eDot (eVar llSelf) v) (eVar v) | (v,t) <- vts ] mainDef attr = Def l0 attr [] pars KwdNIL (Just $ conv t1) mainBody NoDec fx Nothing pars = conv $ addSelfPar p args = pArg p methCall to = eCallP (eDot (eVar llSelf) to) args parsC tc = conv $ addSelfPar $ addContPar tc p mainBody = [ sAssign (pVar v t) (eDot (eVar llSelf) v) | (v,t) <- vts ] ++ [sReturn e] callDef = mainDef attr_call_ execDef = Def l0 attr_exec_ [] pars KwdNIL (Just t1) [ sReturn (methCall attr_call_) ] NoDec fxProc Nothing asynDef = mainDef attr_asyn_ callDefA = Def l0 attr_call_ [] (parsC t1) KwdNIL (Just tR) callBodyA NoDec fxProc Nothing callBodyA = [ sReturn $ eCall (tApp (eQVar primAWAIT) [t1]) [eVar llCont, methCall attr_asyn_] ] execDefA = delegate attr_exec_ attr_asyn_ tValue evalDef = mainDef attr_eval_ callDefF = delegate attr_call_ attr_eval_ t1 execDefF = delegate attr_exec_ attr_eval_ tValue delegate name to tc = Def l0 name [] (parsC tc) KwdNIL (Just tR) (delegateBody to tc) NoDec fxProc Nothing delegateBody to tc = [ sReturn $ eCall (tApp (eQVar primRCont) [tValue]) [eVar llCont, methCall to] ] defs | basename == primCont = [callDef] | basename == primProc = [callDef, execDef] | basename == primAction = [callDefA, execDefA, asynDef] | basename == primMut = [callDefF, execDefF, evalDef] | basename == primPure = [callDefF, execDefF, evalDef] addSelfPar p = PosPar llSelf (Just tSelf) Nothing p addContPar t p = PosPar llCont (Just $ tCont t) Nothing p closureCon fx p t | isCont (tFun fx p kwdNil t) = TC primCont [rtype p] | fx == fxProc = TC primProc [rtail p, contArg (rtype p)] | fx == fxAction = TC primAction [p,t] | fx == fxMut = TC primMut [p,t] | fx == fxPure = TC primPure [p,t] | otherwise = error ("### BAD closureCon fx: " ++ prstr fx) where contArg (TFun _ fx p _ r) = rtype p contArg t = error ("### BAD contArg " ++ prstr t) isCont (TFun _ fx p@TRow{} _ r) = fx == fxProc && r == tR && rtail p == posNil && not (isCont $ rtype p) isCont _ = False instance Lift Expr where ll env e@(Var l (NoQ n)) | n `elem` dom (locals env) = pure e ll env e | Just (e',vts) <- freefun env e = closureConvert env (Lambda l0 par KwdNIL (call e' vts) fx) t vts (map (eVar . fst) vts ) where par = pPar paramNames p call e' vts = Call l0 e' (addArgs vts $ pArg par) KwdNil TFun _ fx p _ t = typeOf env e ll env (Call l e p KwdNil) | Just (e',vts) <- freefun env e = do p' <- ll env p return $ Call l e' (addArgs vts p') KwdNil | Async _ e' <- e, closedType env e' = do e' <- ll env e' p' <- ll env p return $ Call l (eDot e' attr_asyn_) p' KwdNil | closedType env e = do let t@TFun{effect = fx} = typeOf env e attr | isCont t = attr_call_ | fx == fxProc = attr_call_ | fx == fxMut = attr_eval_ | fx == fxPure = attr_eval_ | fx == fxAction = attr_asyn_ e' <- llSub env e p' <- ll env p return $ Call l (eDot e' attr) p' KwdNil | otherwise = do e' <- llSub env e p' <- ll env p return $ Call l e' p' KwdNil ll env (Async l e) | closedType env e = do e <- ll env e let vts = restrict (locals env) (free e) call = Call l0 (eDot e attr_asyn_) (pArg par) KwdNil closureConvert env (Lambda l0 par KwdNIL call fxProc) (tMsg t) vts (map (eVar . fst) vts) | otherwise = do e <- ll env e return $ Async l e where par = pPar paramNames p TFun _ fx p _ t = typeOf env e ll env e0@(Lambda l p KwdNIL e fx) = do e' <- ll env1 e let vts = restrict (locals env) (free e' \\ bound p) closureConvert env (Lambda l p KwdNIL e' fx) t vts (map (eVar . fst) vts) where env1 = extLocals p $ define (envOf p) env t = typeOf env1 e ll env (Var l n) = pure $ Var l (primSubst n) ll env e@Int{} = pure e ll env e@Float{} = pure e ll env e@Imaginary{} = pure e ll env e@Bool{} = pure e ll env e@None{} = pure e ll env e@NotImplemented{} = pure e ll env e@Ellipsis{} = pure e ll env e@Strings{} = pure e ll env e@BStrings{} = pure e ll env (Cond l e1 e e2) = Cond l <$> ll env e1 <*> ll env e <*> ll env e2 ll env (IsInstance l e c) = IsInstance l <$> ll env e <*> pure c ll env (BinOp l e1 Or e2) = BinOp l <$> ll env e1 <*> pure Or <*> ll env e2 ll env (BinOp l e1 And e2) = BinOp l <$> ll env e1 <*> pure And <*> ll env e2 ll env (UnOp l Not e) = UnOp l Not <$> ll env e ll env (TApp _ (Dot l e n) ts) = llDot env l e n ts ll env (Dot l e n) = llDot env l e n [] ll env (TApp l e ts) = TApp l <$> ll env e <*> pure (conv ts) ll env (Let l ss e) = Let l <$> ll env1 ss <*> ll env1 e where env1 = define (envOf ss) env ll env (DotI l e i) = DotI l <$> llSub env e <*> pure i ll env (RestI l e i) = RestI l <$> llSub env e <*> pure i ll env (Yield l e) = Yield l <$> ll env e ll env (YieldFrom l e) = YieldFrom l <$> ll env e ll env (Tuple l es KwdNil) = Tuple l <$> ll env es <*> pure KwdNil ll env (List l es) = List l <$> ll env es ll env (Dict l as) = Dict l <$> ll env as ll env (Set l es) = Set l <$> ll env es ll env e = error ("ll unexpected: " ++ prstr e) llDot env l e n ts | closedType env e0 = Dot l <$> llSub env e <*> pure n | Var _ x <- e, NClass{} <- findQName x env = closureConvert env (Lambda l0 par KwdNIL (calldot x n) fx) t [] [] | otherwise = do e' <- llSub env e x <- newName "obj" closureConvert env (Lambda l0 par KwdNIL (calldot (NoQ x) n) fx) t [(x,t')] [e'] where par = pPar paramNames p TFun _ fx p _ t = typeOf env e0 calldot x n = Call l0 (eDot (eQVar x) n) (pArg par) KwdNil t' = typeOf env e e0 = tApp (Dot l e n) (conv ts) llSub :: LiftEnv -> Expr -> LiftM Expr llSub env (Var l n) = pure $ Var l (primSubst n) llSub env (Dot l e n) = Dot l <$> llSub env e <*> pure n llSub env (TApp l e ts) = TApp l <$> llSub env e <*> pure (conv ts) llSub env (Async l e) = Async l <$> llSub env e llSub env e = ll env e primSubst n | n == primASYNCc = primASYNC | n == primAFTERc = primAFTER | n == primAWAITc = primAWAIT | n == primPUSH_Cc = primPUSH_C | n == primPUSHF_Cc = primPUSHF_C | n == primRContc = primRCont | n == primSKIPRESc = primSKIPRES | otherwise = n instance Lift Elem where ll env (Elem e) = Elem <$> ll env e ll env (Star e) = Star <$> ll env e instance Lift Assoc where ll env (Assoc k v) = Assoc <$> ll env k <*> ll env v ll env (StarStar e) = StarStar <$> ll env e instance Lift PosArg where ll env (PosArg e p) = PosArg <$> ll env e <*> ll env p ll env PosNil = pure PosNil instance Lift Pattern where ll env (PVar l n t) = return (PVar l n (conv t)) -- Convert environment types ----------------------------------------------------------------------------------------- class Conv a where conv :: a -> a instance (Conv a) => Conv (Maybe a) where conv = fmap conv instance (Conv a) => Conv [a] where conv = map conv instance (Conv a) => Conv (Name, a) where conv (n, x) = (n, conv x) instance Conv NameInfo where conv (NClass q ps te doc) = NClass (conv q) (conv ps) (conv te) doc conv (NSig sc Property doc) = NSig (conv sc) Property doc conv (NSig sc dec doc) = NSig (convTop sc) dec doc conv (NDef sc dec doc) = NDef (convTop sc) dec doc conv (NVar t) = NVar (conv t) conv (NSVar t) = NSVar (conv t) conv ni = ni instance Conv QBind where conv (QBind tv cs) = QBind tv (conv cs) instance Conv WTCon where conv (w,c) = (w, conv c) convTop (TSchema l q t) = TSchema l (conv q) (convTop' t) where convTop' (TFun l fx p TNil{} t) = TFun l (conv fx) (conv p) kwdNil (conv t) convTop' t = conv t instance Conv TSchema where conv (TSchema l q t) = TSchema l (conv q) (conv t) instance Conv Type where conv t0@(TFun l fx p _ t) = TCon l (conv $ closureCon fx p t) conv (TCon l c) = TCon l (conv c) conv (TTuple l p k) = TTuple l (conv p) (conv k) conv (TOpt l t) = TOpt l (conv t) conv (TRow l k n t r) = TRow l k n (conv t) (conv r) conv (TFX l x) = TFX l x conv t = t instance Conv TCon where conv (TC c ts) = TC c (conv ts) instance Conv PosPar where conv (PosPar n t Nothing p) = PosPar n (conv t) Nothing (conv p) conv PosNIL = PosNIL ================================================ FILE: compiler/lib/src/Acton/NameInfo.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances, FlexibleContexts, DeriveGeneric, DeriveAnyClass #-} module Acton.NameInfo where import Control.DeepSeq import qualified Data.Binary import GHC.Generics (Generic) import Data.Typeable import qualified Data.HashMap.Strict as M import Prelude hiding ((<>)) import Utils import Acton.Syntax import Acton.Builtin import Acton.Names import Acton.Subst import Acton.Printer -- NameInfo ----------------------------------------------------------------------------------------------- {- TEnv principles: - A TEnv is an association of NameInfo details to a list of names. - NSig holds the schema of an explicit Signature, while NDef and NVar give schemas and types to names created by Defs and assignments. - NClass, NProto, NExt and NAct represent class, protocol, extension and actor declarations. They each contain a TEnv of visible local attributes. - Signatures must appear before the defs/assignments they describe, and every TEnv respects the order of the syntactic constructs binding each name. - The attribute TEnvs of NClass, NProto, NExt and NAct are searched left-to-right, thus favoring (explicit) NSigs over (inferred) NDefs/NVars. - The global inference environment is searched from active names to closed names, thereby prioritizing NDefs/NVars over NSigs, as well as any inner bindings in scope. - The NameInfo assumption on a (recursive) Def is always an NDef, initialized to the corresponding NSig if present, or a fresh unquantified variable. - The inferred schema for each def is checked to be no less general than the corresponding NDef assumption. - Unquantified NDefs are generalized at the close of the outermost recursive declaration in scope. - An NSig is always fully quantified, not possible to generalize - To enable method override (and disable method signature override), the NSigs of parent class are inserted into the global env when checking a child class - For the same reason, NDefs and NVars without an NSig of a parent class are inserted as NSigs when a child class is checked -} type TEnv = [(Name, NameInfo)] data NameInfo = NVar Type | NSVar Type | NDef TSchema Deco (Maybe String) | NSig TSchema Deco (Maybe String) | NAct QBinds PosRow KwdRow TEnv (Maybe String) | NClass QBinds [WTCon] TEnv (Maybe String) | NProto QBinds [WTCon] TEnv (Maybe String) | NExt QBinds TCon [WTCon] TEnv [Name] (Maybe String) | NTVar Kind CCon [PCon] | NAlias QName | NMAlias ModName | NModule [ModName] TEnv (Maybe String) | NReserved deriving (Eq,Show,Read,Generic,NFData) typeDecl (_,NDef{}) = False typeDecl _ = True type HTEnv = M.HashMap Name HNameInfo data HNameInfo = HNVar Type | HNSVar Type | HNDef TSchema Deco (Maybe String) | HNSig TSchema Deco (Maybe String) | HNAct QBinds PosRow KwdRow TEnv (Maybe String) | HNClass QBinds [WTCon] TEnv (Maybe String) | HNProto QBinds [WTCon] TEnv (Maybe String) | HNExt QBinds TCon [WTCon] TEnv [Name] (Maybe String) | HNTVar Kind CCon [PCon] | HNAlias QName | HNMAlias ModName | HNModule [ModName] HTEnv (Maybe String) | HNReserved deriving (Eq, Show, Read, Generic) instance Data.Binary.Binary NameInfo convNameInfo2HNameInfo :: NameInfo -> HNameInfo convNameInfo2HNameInfo (NModule ms te mdoc) = HNModule ms (convTEnv2HTEnv te) mdoc convNameInfo2HNameInfo (NVar t) = HNVar t convNameInfo2HNameInfo (NSVar t) = HNSVar t convNameInfo2HNameInfo (NDef sc dec mdoc) = HNDef sc dec mdoc convNameInfo2HNameInfo (NSig sc dec mdoc) = HNSig sc dec mdoc convNameInfo2HNameInfo (NAct q p k te mdoc) = HNAct q p k te mdoc convNameInfo2HNameInfo (NClass q ws te mdoc) = HNClass q ws te mdoc convNameInfo2HNameInfo (NProto q ws te mdoc) = HNProto q ws te mdoc convNameInfo2HNameInfo (NExt q tc ws te ns mdoc) = HNExt q tc ws te ns mdoc convNameInfo2HNameInfo (NTVar k c ps) = HNTVar k c ps convNameInfo2HNameInfo (NAlias qn) = HNAlias qn convNameInfo2HNameInfo (NMAlias mn) = HNMAlias mn convNameInfo2HNameInfo (NReserved) = HNReserved convHNameInfo2NameInfo :: HNameInfo -> NameInfo convHNameInfo2NameInfo (HNModule ms te mdoc) = NModule ms (convHTEnv2TEnv te) mdoc convHNameInfo2NameInfo (HNVar t) = NVar t convHNameInfo2NameInfo (HNSVar t) = NSVar t convHNameInfo2NameInfo (HNDef sc dec mdoc) = NDef sc dec mdoc convHNameInfo2NameInfo (HNSig sc dec mdoc) = NSig sc dec mdoc convHNameInfo2NameInfo (HNAct q p k te mdoc) = NAct q p k te mdoc convHNameInfo2NameInfo (HNClass q ws te mdoc) = NClass q ws te mdoc convHNameInfo2NameInfo (HNProto q ws te mdoc) = NProto q ws te mdoc convHNameInfo2NameInfo (HNExt q tc ws te ns mdoc) = NExt q tc ws te ns mdoc convHNameInfo2NameInfo (HNTVar k c ps) = NTVar k c ps convHNameInfo2NameInfo (HNAlias qn) = NAlias qn convHNameInfo2NameInfo (HNMAlias mn) = NMAlias mn convHNameInfo2NameInfo (HNReserved) = NReserved convTEnv2HTEnv :: TEnv -> HTEnv convTEnv2HTEnv te = M.fromList (map convPair te) where convPair (n, ni) = (n, convNameInfo2HNameInfo ni) convHTEnv2TEnv :: HTEnv -> TEnv convHTEnv2TEnv te = map convPair (M.toList te) where convPair (n, hni) = (n, convHNameInfo2NameInfo hni) -- | Strip all docstrings from NameInfo (and nested environments). -- This is used when computing a public-interface hash so that -- documentation-only edits do not cause dependents to rebuild. stripDocsNI :: NameInfo -> NameInfo stripDocsNI ni = case ni of NModule ms te _ -> NModule ms (map stripBind te) Nothing NAct q p k te _ -> NAct q p k (map stripBind te) Nothing NClass q cs te _ -> NClass q cs (map stripBind te) Nothing NProto q ps te _ -> NProto q ps (map stripBind te) Nothing NExt q c ps te o _ -> NExt q c ps (map stripBind te) o Nothing NDef sc dec _ -> NDef sc dec Nothing NSig sc dec _ -> NSig sc dec Nothing other -> other where stripBind (n, info) = (n, stripDocsNI info) -- | Strip source locations from NameInfo (and nested syntax fragments). -- This keeps public interface hashes independent from whitespace-only source -- edits while preserving locations in the cached .ty payload itself. stripLocsNI :: NameInfo -> NameInfo stripLocsNI ni = case ni of NVar t -> NVar (stripLocsType t) NSVar t -> NSVar (stripLocsType t) NDef sc dec doc -> NDef (stripLocsTSchema sc) dec doc NSig sc dec doc -> NSig (stripLocsTSchema sc) dec doc NAct q p k te doc -> NAct (stripLocsQBinds q) (stripLocsType p) (stripLocsType k) (stripLocsTEnv te) doc NClass q cs te doc -> NClass (stripLocsQBinds q) (map stripLocsWTCon cs) (stripLocsTEnv te) doc NProto q ps te doc -> NProto (stripLocsQBinds q) (map stripLocsWTCon ps) (stripLocsTEnv te) doc NExt q c ps te o doc -> NExt (stripLocsQBinds q) (stripLocsTCon c) (map stripLocsWTCon ps) (stripLocsTEnv te) (map stripLocsName o) doc NTVar k c ps -> NTVar k (stripLocsTCon c) (map stripLocsTCon ps) NAlias qn -> NAlias (stripLocsQName qn) NMAlias mn -> NMAlias (stripLocsModName mn) NModule ms te doc -> NModule ms (stripLocsTEnv te) doc NReserved -> NReserved where stripLocsTEnv :: TEnv -> TEnv stripLocsTEnv = map $ \(n, info) -> (stripLocsName n, stripLocsNI info) stripLocsTSchema :: TSchema -> TSchema stripLocsTSchema (TSchema _ q t) = TSchema NoLoc (stripLocsQBinds q) (stripLocsType t) stripLocsQBinds :: QBinds -> QBinds stripLocsQBinds = map stripLocsQBind stripLocsQBind :: QBind -> QBind stripLocsQBind (QBind tv cs) = QBind (stripLocsTVar tv) (map stripLocsTCon cs) stripLocsTVar :: TVar -> TVar stripLocsTVar (TV k n) = TV k (stripLocsName n) stripLocsTCon :: TCon -> TCon stripLocsTCon (TC qn ts) = TC (stripLocsQName qn) (map stripLocsType ts) stripLocsWTCon :: WTCon -> WTCon stripLocsWTCon (wpath, pcon) = (map stripLocsWStep wpath, stripLocsTCon pcon) stripLocsWStep :: Either QName QName -> Either QName QName stripLocsWStep (Left qn) = Left (stripLocsQName qn) stripLocsWStep (Right qn) = Right (stripLocsQName qn) stripLocsType :: Type -> Type stripLocsType t = case t of TUni _ u -> TUni NoLoc u TVar _ tv -> TVar NoLoc (stripLocsTVar tv) TCon _ tc -> TCon NoLoc (stripLocsTCon tc) TFun _ fx p k r -> TFun NoLoc (stripLocsType fx) (stripLocsType p) (stripLocsType k) (stripLocsType r) TTuple _ p k -> TTuple NoLoc (stripLocsType p) (stripLocsType k) TOpt _ opt -> TOpt NoLoc (stripLocsType opt) TNone _ -> TNone NoLoc TWild _ -> TWild NoLoc TNil _ k -> TNil NoLoc k TRow _ k n ty row -> TRow NoLoc k (stripLocsName n) (stripLocsType ty) (stripLocsType row) TStar _ k row -> TStar NoLoc k (stripLocsType row) TFX _ fx -> TFX NoLoc fx stripLocsQName :: QName -> QName stripLocsQName qn = case qn of QName mn n -> QName (stripLocsModName mn) (stripLocsName n) NoQ n -> NoQ (stripLocsName n) GName mn n -> GName (stripLocsModName mn) (stripLocsName n) stripLocsModName :: ModName -> ModName stripLocsModName (ModName ns) = ModName (map stripLocsName ns) stripLocsName :: Name -> Name stripLocsName n = case n of Name _ s -> Name NoLoc s Derived n1 n2 -> Derived (stripLocsName n1) (stripLocsName n2) Internal{} -> n instance Leaves NameInfo where leaves (NClass q cs te _) = leaves q ++ leaves cs ++ leaves te leaves (NProto q ps te _) = leaves q ++ leaves ps ++ leaves te leaves (NAct q p k te _) = leaves q ++ leaves [p,k] ++ leaves te leaves (NExt q c ps te _ _) = leaves q ++ leaves c ++ leaves ps ++ leaves te leaves (NDef sc dec _) = leaves sc leaves _ = [] instance Pretty TEnv where pretty tenv = vcat (map pretty $ normTEnv tenv) where normTEnv te = f [] te where f ns [] = [] f ns ((n,i):te) | n `elem` ns = f ns te | otherwise = (n,i) : f (n:ns) te instance Pretty (Name,NameInfo) where pretty (n, NVar t) = pretty n <+> colon <+> pretty t pretty (n, NSVar t) = text "var" <+> pretty n <+> colon <+> pretty t pretty (n, NDef t d doc) = prettyDec d $ pretty n <+> colon <+> pretty t $+$ nest 4 (prettyDocstring doc) pretty (n, NSig t d doc) = prettyDec d $ pretty n <+> colon <+> pretty t $+$ nest 4 (prettyDocstring doc) pretty (n, NAct q p k te doc) = text "actor" <+> pretty n <> nonEmpty brackets commaList q <+> parens (prettyFunRow p k) <> colon $+$ nest 4 (prettyDocstring doc) $+$ (nest 4 $ prettyOrPass te) pretty (n, NClass q us te doc) = text "class" <+> pretty n <> nonEmpty brackets commaList q <+> nonEmpty parens commaList us <> colon $+$ nest 4 (prettyDocstring doc) $+$ (nest 4 $ prettyOrPass te) pretty (n, NProto q us te doc) = text "protocol" <+> pretty n <> nonEmpty brackets commaList q <+> nonEmpty parens commaList us <> colon $+$ nest 4 (prettyDocstring doc) $+$ (nest 4 $ prettyOrPass te) pretty (w, NExt [] c ps te opts doc) = {-pretty w <+> colon <+> -} text "extension" <+> pretty c <+> parens (commaList ps) <> colon $+$ nest 4 (prettyDocstring doc) $+$ (nest 4 $ prettyOrPass te) pretty (w, NExt q c ps te opts doc) = {-pretty w <+> colon <+> -} text "extension" <+> pretty q <+> text "=>" <+> pretty c <+> parens (commaList ps) <> colon $+$ nest 4 (prettyDocstring doc) $+$ (nest 4 $ prettyOrPass te) pretty (n, NTVar k c ps) = pretty n <> parens (commaList (c:ps)) pretty (n, NAlias qn) = text "alias" <+> pretty n <+> equals <+> pretty qn pretty (n, NMAlias m) = text "module" <+> pretty n <+> equals <+> pretty m pretty (n, NModule ms te doc) = text "module" <+> pretty n <> colon $+$ nest 4 (vcat [ text "import" <+> pretty m | m <- ms ]) $+$ nest 4 (prettyDocstring doc) $+$ nest 4 (pretty te) pretty (n, NReserved) = pretty n <+> text "(reserved)" prettyOrPass te | isEmpty doc = text "pass" | otherwise = doc where doc = pretty te prettyDocstring :: Maybe String -> Doc prettyDocstring Nothing = empty prettyDocstring (Just docstring) = text "\"\"\"" <> text docstring <> text "\"\"\"" instance VFree NameInfo where vfree (NVar t) = vfree t vfree (NSVar t) = vfree t vfree (NDef t d _) = vfree t vfree (NSig t d _) = vfree t vfree (NAct q p k te _) = (vfree q ++ vfree p ++ vfree k ++ vfree te) \\ (tvSelf : qbound q) vfree (NClass q us te _) = (vfree q ++ vfree us ++ vfree te) \\ (tvSelf : qbound q) vfree (NProto q us te _) = (vfree q ++ vfree us ++ vfree te) \\ (tvSelf : qbound q) vfree (NExt q c ps te _ _) = (vfree q ++ vfree c ++ vfree ps ++ vfree te) \\ (tvSelf : qbound q) vfree (NTVar k c ps) = vfree c ++ vfree ps vfree (NAlias qn) = [] vfree (NMAlias qn) = [] vfree (NModule ms te doc) = [] -- actually vfree te, but a module has no free variables on the top level vfree NReserved = [] instance VSubst NameInfo where vsubst s (NVar t) = NVar (vsubst s t) vsubst s (NSVar t) = NSVar (vsubst s t) vsubst s (NDef t d x) = NDef (vsubst s t) d x vsubst s (NSig t d x) = NSig (vsubst s t) d x vsubst s (NAct q p k te x) = NAct (vsubst s q) (vsubst s p) (vsubst s k) (vsubst s te) x vsubst s (NClass q us te x) = NClass (vsubst s q) (vsubst s us) (vsubst s te) x vsubst s (NProto q us te x) = NProto (vsubst s q) (vsubst s us) (vsubst s te) x vsubst s (NExt q c ps te opts x) = NExt (vsubst s q) (vsubst s c) (vsubst s ps) (vsubst s te) opts x vsubst s (NTVar k c ps) = NTVar k (vsubst s c) (vsubst s ps) vsubst s (NAlias qn) = NAlias qn vsubst s (NMAlias m) = NMAlias m vsubst s (NModule ms te x) = NModule ms te x -- actually vsubst s te, but te has no free variables (top-level) vsubst s NReserved = NReserved instance UFree NameInfo where ufree (NVar t) = ufree t ufree (NSVar t) = ufree t ufree (NDef t d _) = ufree t ufree (NSig t d _) = ufree t ufree (NAct q p k te _) = ufree q ++ ufree p ++ ufree k ++ ufree te ufree (NClass q us te _) = ufree q ++ ufree us ++ ufree te ufree (NProto q us te _) = ufree q ++ ufree us ++ ufree te ufree (NExt q c ps te _ _) = ufree q ++ ufree c ++ ufree ps ++ ufree te ufree (NTVar k c ps) = ufree c ++ ufree ps ufree (NAlias qn) = [] ufree (NMAlias qn) = [] ufree (NModule ms te doc) = [] -- actually ufree te, but a module has no free variables on the top level ufree NReserved = [] instance Polarity (Name,NameInfo) where polvars (n, i) = polvars i instance Polarity NameInfo where polvars (NVar t) = polvars t polvars (NSVar t) = invvars t polvars (NDef t d _) = polvars t polvars (NSig t d _) = polvars t polvars (NAct q p k te _) = polvars q `polcat` polneg (polvars p `polcat` polvars k) `polcat` polvars te polvars (NClass q us te _) = polvars q `polcat` polvars us `polcat` polvars te polvars (NProto q us te _) = polvars q `polcat` polvars us `polcat` polvars te polvars (NExt q c ps te _ _) = polvars q `polcat` polvars c `polcat` polvars ps `polcat` polvars te polvars (NTVar k c ps) = polvars c `polcat` polvars ps polvars _ = ([],[]) instance Tailvars (Name, NameInfo) where tailvars (n, NVar t) = tailvars t tailvars (n, NSVar t) = tailvars t tailvars (n, NDef sc _ _) = tailvars sc tailvars _ = [] wildargs i = [ tWild | _ <- nbinds i ] where nbinds (NAct q _ _ _ _) = q nbinds (NClass q _ _ _) = q nbinds (NProto q _ _ _) = q nbinds (NExt q _ _ _ _ _) = q -- TEnv filters -------------------------------------------------------------------------------------------------------- nSigs :: TEnv -> TEnv nSigs te = [ (n,i) | (n, i@(NSig sc dec _)) <- te, not $ isProp dec sc ] propSigs :: TEnv -> TEnv propSigs te = [ (n,i) | (n, i@(NSig sc dec _)) <- te, isProp dec sc ] isProp :: Deco -> TSchema -> Bool isProp Property _ = True isProp NoDec sc = case sctype sc of TFun{} -> False; _ -> True isProp _ _ = False nTerms :: TEnv -> TEnv nTerms te = [ (n,i) | (n,i) <- te, isNTerm i ] isNTerm NDef{} = True isNTerm NVar{} = True isNTerm _ = False sigTerms :: TEnv -> (TEnv, TEnv) sigTerms te = (nSigs te, nTerms te) noDefs :: TEnv -> TEnv noDefs te = [ (n,i) | (n,i) <- te, keep i ] where keep NDef{} = False keep NAct{} = False keep _ = True unSig :: TEnv -> TEnv unSig te = map f te where f (n, NSig (TSchema _ [] t) Property _) = (n, NVar t) f (n, NSig sc@(TSchema _ _ TFun{}) dec doc) = (n, NDef sc dec doc) f (n, NSig (TSchema _ _ t) _ _) = (n, NVar t) f (n, i) = (n, i) -- Witnesses ----------------------------------------------------------------------------------------------- data Witness = WClass { binds::QBinds, wtype::Type, proto::PCon, wname::QName, wsteps::WPath, wopts::Int } | WInst { binds::QBinds, wtype::Type, proto::PCon, wname::QName, wsteps::WPath } deriving (Show) type WPath = [Either QName QName] type WTCon = (WPath,PCon) wexpr :: WPath -> Expr -> Expr wexpr [] e = e wexpr (Left _ : w) e = wexpr w e wexpr (Right n : w) e = wexpr w $ eDot e (witAttr n) instance Pretty Witness where pretty (WClass q t p w ws _) = text "WClass" <+> prettyQual q <+> pretty t <+> parens (pretty p) <+> equals <+> pretty (wexpr ws (eCall (eQVar w) [])) pretty (WInst q t p w ws) = text "WInst" <+> prettyQual q <+> pretty t <+> parens (pretty p) <+> equals <+> pretty (wexpr ws (eQVar w)) instance UFree Witness where ufree w@WClass{} = [] ufree w@WInst{} = ufree (wtype w) ++ ufree (proto w) instance Leaves WTCon where leaves (wp,p) = leaves p instance VFree WTCon where vfree (wpath, p) = vfree p instance UFree WTCon where ufree (wpath, p) = ufree p instance Tailvars WTCon where tailvars (wpath, p) = tailvars p instance VSubst WTCon where vsubst s (w,u) = (w, vsubst s u) instance Vars WTCon where freeQ (wpath, p) = freeQ p instance Vars NameInfo where freeQ ni = case ni of NVar t -> freeQ t NSVar t -> freeQ t NDef sc _ _ -> freeQ sc NSig sc _ _ -> freeQ sc NAct q p k te _ -> freeQ q ++ freeQ p ++ freeQ k ++ freeQTEnv te NClass q ws te _ -> freeQ q ++ freeQWTCons ws ++ freeQTEnv te NProto q ws te _ -> freeQ q ++ freeQWTCons ws ++ freeQTEnv te NExt q c ws te _ _ -> freeQ q ++ freeQ c ++ freeQWTCons ws ++ freeQTEnv te NTVar _ c ps -> freeQ c ++ freeQ ps NAlias qn -> freeQ qn NMAlias _ -> [] NModule ms te _ -> freeQTEnv te NReserved -> [] where freeQTEnv :: TEnv -> [QName] freeQTEnv tenv = concatMap (freeQ . snd) tenv freeQWTCons :: [WTCon] -> [QName] freeQWTCons = concatMap freeQWTCon freeQWTCon :: WTCon -> [QName] freeQWTCon (wpath, pcon) = freeQWPath wpath ++ freeQ pcon freeQWPath :: WPath -> [QName] freeQWPath = concatMap step where step (Left qn) = freeQ qn step (Right qn) = freeQ qn instance UWild WTCon where uwild (wpath, p) = (wpath, uwild p) instance Pretty WTCon where pretty (wpath, p) = pretty p instance Polarity WTCon where polvars (w, c) = polvars c ================================================ FILE: compiler/lib/src/Acton/Names.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances #-} module Acton.Names where import Utils import Acton.Syntax import Acton.Builtin import Debug.Trace isWitness (Internal Witness _ _) = True isWitness _ = False isInternal (Internal _ _ _) = True isInternal _ = False isUnboxed (Internal BoxPass _ _) = True isUnboxed _ = False self = Name NoLoc "self" localName n = Derived n suffixLocal newactName n = Derived n suffixNewact selfKW' = Internal Witness "self" 0 thisKW' = Internal Witness "this" 0 g_self = globalName "self" g_act = globalName "act" g_skip = globalName "skip" altInit = globalName "init" suffixLocal = globalName "local" suffixNewact = globalName "newact" suffixClass = globalName "class" suffixMethods = globalName "methods" suffixNew = globalName "new" suffixWitness = globalName "witness" paramNames = globalNames "" pNames = globalNames "p" xNames = globalNames "x" yNames = globalNames "y" tmpNames = globalNames "tmp" attrKW = globalName "kw" deriveQ (NoQ n) = n deriveQ (QName (ModName m) n) = deriveMod n m deriveQ (GName m n) | m == mBuiltin = n deriveQ (GName (ModName m) n) = deriveMod n m deriveMod n0 [] = n0 deriveMod n0 (n:m) = deriveMod (Derived n0 n) m deriveT (TVar _ v) = tvname v deriveT (TCon _ c) = deriveQ (tcname c) witAttr qn = Internal Witness (nstr $ deriveQ qn) 0 extensionName [] c = Derived (globalName "ext") (deriveQ $ tcname c) extensionName (p:_) c | length ts == length vs = n0 | otherwise = foldl Derived n0 (map deriveT ts) where ts = tcargs c vs = [ v | TVar _ v <- ts ] n0 = Derived (deriveQ $ tcname p) (deriveQ $ tcname c) -- Mutually recursive groups ------- declnames (Extension{} : ds) = declnames ds declnames (d : ds) = dname d : declnames ds declnames [] = [] dname' (Extension _ _ c us _ _) = extensionName us c dname' d = dname d splitDeclGroup [] = [] splitDeclGroup (d:ds) = join $ split (free d) [d] ds where split vs ds0 [] = [reverse ds0] split vs ds0 (d:ds) | any (`elem` ws) vs = split (free d++vs) (d:ds0) ds | otherwise = reverse ds0 : split (free d) [d] ds where ws = declnames (d:ds) join [] = [] join dss | not $ null dss1 = concat dss1 : join dss2 where (dss1,dss2) = span (all tydecl) dss tydecl Def{} = False tydecl _ = True join (ds:dss) = ds : join dss -- Data variables ------------------ class DataVars a where datavars :: Int -> a -> [Name] -- Variables in any lhs data pattern, with minimum arity instance DataVars a => DataVars [a] where datavars n = concatMap (datavars n) instance DataVars Stmt where datavars n (Assign _ ps _) = datavars n ps datavars n (Data _ p b) = maybe [] (datavars n) p datavars n (While _ e b els) = datavars n b ++ datavars n els datavars n (For _ p e b els) = datavars n b ++ datavars n els datavars n (If _ bs els) = concatMap (datavars n) bs ++ datavars n els datavars n _ = [] instance DataVars Branch where datavars n (Branch e ss) = datavars n ss instance DataVars Pattern where datavars n (PTuple _ ps ks) = bound ps ++ bound ks datavars n (PList _ ps p) = bound ps ++ bound p datavars n (PParen _ p) = bound p datavars n (PData _ v ixs) | length ixs >= n = [v] datavars n _ = [] -- Special attributes variables ---- methods b = [ n | Decl _ ds <- b, Def{dname=n} <- ds ] statevars b = concat [ bound ps | VarAssign _ ps _ <- b ] isHidden n@(Name _ str) = length (takeWhile (=='_') str) == 1 || n == resumeKW || n == cleanupKW isHidden _ = True notHidden = filter (not . isHidden) isPrivateName :: Name -> Bool isPrivateName n = case nstr n of ('_':_) -> True _ -> False isPublicName :: Name -> Bool isPublicName = not . isPrivateName -- Free and bound names ------------ class Vars a where free :: a -> [Name] freeQ :: a -> [QName] bound :: a -> [Name] free x = free $ freeQ x freeQ x = [] bound x = [] qns `diffQ` ns = filter f qns where f (NoQ n) = n `notElem` ns f _ = True instance Vars a => Vars [a] where free = concatMap free freeQ = concatMap freeQ bound = concatMap bound instance Vars a => Vars (Maybe a) where free = maybe [] free freeQ = maybe [] freeQ bound = maybe [] bound instance Vars Stmt where freeQ (Expr _ e) = freeQ e freeQ (Assign _ ps e) = freeQ ps ++ freeQ e freeQ (MutAssign _ t e) = freeQ t ++ freeQ e freeQ (AugAssign _ t op e) = freeQ t ++ freeQ e freeQ (Assert _ e mbe) = freeQ e ++ freeQ mbe freeQ (Pass _) = [] freeQ (Delete _ t) = freeQ t freeQ (Return _ e) = freeQ e freeQ (Raise _ e) = freeQ e freeQ (Break _) = [] freeQ (Continue _) = [] freeQ (If _ branches els) = freeQ branches ++ freeQ els freeQ (While _ e b els) = freeQ e ++ freeQ b ++ freeQ els freeQ (For _ p e b els) = freeQ p ++ freeQ e ++ (freeQ b `diffQ` bound p) ++ freeQ els freeQ (Try _ b hs els fin) = freeQ b ++ freeQ hs ++ freeQ els ++ freeQ fin freeQ (With _ items b) = freeQ items ++ (freeQ b `diffQ` bound items) freeQ (Data _ p b) = freeQ p ++ freeQ b freeQ (VarAssign _ ps e) = freeQ ps ++ freeQ e freeQ (After _ e e') = freeQ e ++ freeQ e' freeQ (Decl _ ds) = freeQ ds freeQ (Signature _ ns t d) = freeQ t bound (Assign _ ps _) = bound ps bound (VarAssign _ ps e) = bound ps bound (AugAssign _ t _ e) = free t bound (Decl _ ds) = bound ds bound (Signature _ ns t d) = ns bound (If _ bs els) = bound bs ++ bound els bound (While _ _ b els) = bound b ++ bound els bound (With _ items b) = bound b bound _ = [] assigned stmts = concatMap assig stmts where assig (While _ e b els) = assigned b ++ assigned els assig (For _ p e b els) = assigned b ++ assigned els ++ bound p assig (With _ items b) = assigned b ++ bound items assig (Try _ b hs els fin) = assigned b ++ concat [ bound ex ++ assigned b | Handler ex b <- hs ] ++ assigned els ++ assigned fin assig (If _ bs els) = concat [ assigned b | Branch _ b <- bs ] ++ assigned els assig (Assign _ ps _) = bound ps assig s = bound s instance Vars Decl where freeQ (Def _ n q ps ks t b d fx _) = (freeQ ps ++ freeQ ks ++ freeQ b ++ freeQ fx) `diffQ` (n : bound q ++ bound ps ++ bound ks ++ assigned b) freeQ (Actor _ n q ps ks b _) = (freeQ ps ++ freeQ ks ++ freeQ b) `diffQ` (n : self : bound q ++ bound ps ++ bound ks ++ assigned b) freeQ (Class _ n q cs b _) = (freeQ cs ++ freeQ b) `diffQ` (n : bound q ++ assigned b) freeQ (Protocol _ n q ps b _) = (freeQ ps ++ freeQ b) `diffQ` (n : bound q ++ assigned b) freeQ (Extension _ q c ps b _) = (freeQ c ++ freeQ ps ++ freeQ b) `diffQ` (bound q ++ assigned b) bound (Def _ n _ _ _ _ _ _ _ _) = [n] bound (Actor _ n _ _ _ _ _) = [n] bound (Class _ n _ _ _ _) = [n] bound (Protocol _ n _ _ _ _) = [n] bound (Extension _ _ _ _ _ _) = [] instance Vars Branch where freeQ (Branch e ss) = freeQ e ++ freeQ ss bound (Branch e ss) = bound ss instance Vars Handler where freeQ (Handler ex ss) = freeQ ex ++ (freeQ ss `diffQ` bound ex) bound (Handler ex ss) = bound ss ++ bound ex instance Vars Expr where freeQ (Var _ n) = [n] freeQ (Int _ _ str) = [] freeQ (Float _ _ str) = [] freeQ (Imaginary _ _ str) = [] freeQ (Bool _ v) = [] freeQ (None _) = [] freeQ (NotImplemented _) = [] freeQ (Ellipsis _) = [] freeQ (Strings _ ss) = [] freeQ (BStrings _ ss) = [] freeQ (Call _ e ps ks) = freeQ e ++ freeQ ps ++ freeQ ks freeQ (TApp _ e ts) = freeQ e ++ freeQ ts freeQ (Let _ ss e) = freeQ ss ++ (freeQ e `diffQ` bound ss) freeQ (Async _ e) = freeQ e freeQ (Await _ e) = freeQ e freeQ (Index _ e ix) = freeQ e ++ freeQ ix freeQ (Slice _ e sl) = freeQ e ++ freeQ sl freeQ (Cond _ e1 e e2) = freeQ [e1,e,e2] freeQ (IsInstance _ e c) = freeQ e ++ freeQ c freeQ (BinOp _ e1 o e2) = freeQ [e1,e2] freeQ (CompOp _ e ops) = freeQ e ++ freeQ ops freeQ (UnOp _ o e) = freeQ e freeQ (Dot _ e n) = freeQ e freeQ (Opt _ e _) = freeQ e freeQ (OptChain _ e) = freeQ e freeQ (Rest _ e n) = freeQ e freeQ (DotI _ e i) = freeQ e freeQ (RestI _ e i) = freeQ e freeQ (Lambda _ ps ks e fx) = freeQ ps ++ freeQ ks ++ (freeQ e `diffQ` (bound ps ++ bound ks)) freeQ (Yield _ e) = freeQ e freeQ (YieldFrom _ e) = freeQ e freeQ (Tuple _ ps ks) = freeQ ps ++ freeQ ks freeQ (List _ es) = freeQ es freeQ (ListComp _ e co) = (freeQ e `diffQ` bound co) ++ freeQ co freeQ (Dict _ es) = freeQ es freeQ (DictComp _ e co) = (freeQ e `diffQ` bound co) ++ freeQ co freeQ (Set _ es) = freeQ es freeQ (SetComp _ e co) = (freeQ e `diffQ` bound co) ++ freeQ co freeQ (Paren _ e) = freeQ e freeQ (UnBox t e) = freeQ e freeQ (Box t e) = freeQ e instance Vars Name where free n = [n] instance Vars ModName where free (ModName (n:ns)) = [n] instance Vars QName where free (QName m n) = free m free (NoQ n) = free n free (GName m n) = free m freeQ n = [n] instance Vars Except where freeQ (ExceptAll _) = [] freeQ (Except _ x) = freeQ x freeQ (ExceptAs _ x n) = freeQ x bound (ExceptAll _) = [] bound (Except _ x) = [] bound (ExceptAs _ x n) = [n] instance Vars PosPar where freeQ (PosPar n t e p) = freeQ t ++ freeQ e ++ freeQ p freeQ (PosSTAR n t) = freeQ t freeQ PosNIL = [] bound (PosPar n t e p) = n : bound p bound (PosSTAR n t) = [n] bound PosNIL = [] instance Vars KwdPar where freeQ (KwdPar n t e k) = freeQ t ++ freeQ e ++ freeQ k freeQ (KwdSTAR n t) = freeQ t freeQ KwdNIL = [] bound (KwdPar n t e k) = n : bound k bound (KwdSTAR n t) = [n] bound KwdNIL = [] instance Vars (PosPar,KwdPar) where freeQ (ppar,kpar) = freeQ ppar ++ freeQ kpar bound (ppar,kpar) = bound ppar ++ bound kpar instance Vars Elem where freeQ (Elem e) = freeQ e freeQ (Star e) = freeQ e bound (Elem p) = bound p bound (Star p) = bound p instance Vars Assoc where freeQ (Assoc k v) = freeQ k ++ freeQ v freeQ (StarStar e) = freeQ e instance Vars WithItem where freeQ (WithItem e p) = freeQ e ++ freeQ p bound (WithItem e p) = bound p instance Vars PosArg where freeQ (PosArg e p) = freeQ e ++ freeQ p freeQ (PosStar e) = freeQ e freeQ PosNil = [] instance Vars KwdArg where freeQ (KwdArg n e k) = freeQ e ++ freeQ k freeQ (KwdStar e) = freeQ e freeQ KwdNil = [] instance Vars OpArg where freeQ (OpArg o e) = freeQ e instance Vars Sliz where freeQ (Sliz _ e1 e2 e3) = freeQ e1 ++ freeQ e2 ++ freeQ e3 instance Vars Comp where freeQ (CompFor _ pat e c) = (freeQ e ++ freeQ c) `diffQ` bound pat freeQ (CompIf _ e c) = freeQ e ++ freeQ c freeQ NoComp = [] bound (CompFor _ pat e c) = bound pat ++ bound c bound (CompIf _ e c) = bound c bound NoComp = [] instance Vars PosPat where freeQ (PosPat p ps) = freeQ p ++ freeQ ps freeQ (PosPatStar p) = freeQ p freeQ PosPatNil = [] bound (PosPat p ps) = bound p ++ bound ps bound (PosPatStar p) = bound p bound PosPatNil = [] instance Vars KwdPat where freeQ (KwdPat n p ps) = freeQ p ++ freeQ ps freeQ (KwdPatStar p) = freeQ p freeQ KwdPatNil = [] bound (KwdPat n p ps) = bound p ++ bound ps bound (KwdPatStar p) = bound p bound KwdPatNil = [] instance Vars Pattern where freeQ (PWild _ _) = [] freeQ (PVar _ n a) = [] freeQ (PTuple _ ps ks) = freeQ ps ++ freeQ ks freeQ (PList _ ps p) = freeQ ps ++ freeQ p freeQ (PParen _ p) = freeQ p freeQ (PData _ n ixs) = freeQ ixs bound (PWild _ _) = [] bound (PVar _ n _) = [n] bound (PTuple _ ps ks) = bound ps ++ bound ks bound (PList _ ps p) = bound ps ++ bound p bound (PParen _ p) = bound p bound (PData _ n ixs) = [n] instance Vars ModuleItem where bound (ModuleItem qn Nothing) = free qn bound (ModuleItem qn (Just n)) = free n instance Vars ImportItem where free (ImportItem n1 as) = [] bound (ImportItem n Nothing) = free n bound (ImportItem n (Just as)) = free as instance Vars ModRef where bound (ModRef (0, n)) = free n bound _ = [] instance Vars TSchema where freeQ (TSchema _ q t) = freeQ q ++ freeQ t instance Vars TVar where freeQ (TV k v) = [] instance Vars TUni where freeQ (UV k l v) = [] instance Vars TCon where freeQ (TC n ts) = freeQ n ++ freeQ ts instance Vars QBind where freeQ (QBind v cs) = freeQ cs instance Vars Type where freeQ (TVar _ v) = freeQ v freeQ (TUni _ u) = freeQ u freeQ (TFun _ es p k t) = freeQ es ++ freeQ p ++ freeQ k ++ freeQ t freeQ (TTuple _ p k) = freeQ p ++ freeQ k freeQ (TOpt _ t) = freeQ t freeQ (TCon _ c) = freeQ c freeQ (TRow _ _ _ t r) = freeQ t ++ freeQ r freeQ (TStar _ _ r) = freeQ r freeQ _ = [] ================================================ FILE: compiler/lib/src/Acton/Normalizer.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances, FlexibleContexts #-} module Acton.Normalizer where import Acton.Syntax import Acton.Names import Acton.NameInfo import Acton.Env import Acton.QuickType import Acton.Prim import Acton.Builtin import Data.List import Pretty import Utils import Control.Monad.State.Strict import Debug.Trace normalize :: Env0 -> Module -> IO (Module, Env0) normalize env0 m = return (evalState (norm env m) (0,[]), env0') where env = normEnv env0 env0' = mapModules convEnv env0 -- Normalization: -- X All module aliases are replaced by their original module name -- X All parameters are positional -- X Comprehensions are translated into loops -- X String literals are concatenated and delimited by double quotes -- X Tuple (and list) patterns are replaced by a var pattern followed by explicit element assignments -- - With statemenmts are replaced by enter/exit prim calls + exception handling -- X The assert statement is replaced by a prim call ASSERT -- X Return without argument is replaced by return None -- - The else branch of a while loop is replaced by an explicit if statement enclosing the loop -- X Superclass lists are transitively closed -- Normalizing monad type NormM a = State (Int,[(Name,PosPar,Expr)]) a newName :: String -> NormM Name newName s = do (n,ts) <- get put (n+1,ts) return $ Internal NormPass s n addComp :: (Name,PosPar,Expr) -> NormM () addComp (n,p,e) = state (\(i,ts) -> ((),(i,(n,p,e):ts))) getComps :: NormM [(Name,PosPar,Expr)] getComps = state (\(n,ts) -> (ts, (n,[]))) type NormEnv = EnvF NormX data NormX = NormX { marksX :: [ContextMark], rtypeX :: Maybe Type, lambdavarsX :: PosPar, classattrsX :: [Name], selfparamX :: Maybe Name } data ContextMark = DROP | LOOP | FINAL deriving (Eq,Show) setMarks c env = modX env $ \x -> x{ marksX = c } pushMark c env = modX env $ \x -> x{ marksX = c : marksX x } marks env = marksX $ envX env setRet t env = modX env $ \x -> x{ rtypeX = t } getRet env = fromJust $ rtypeX $ envX env addLambdavars p env = modX env $ \x -> x{ lambdavarsX = joinP (lambdavarsX x) p } where joinP PosNIL p = p joinP (PosPar n mbt mbe p') p = PosPar n mbt mbe (joinP p' p) getLambdavars env = lambdavarsX $ envX env classattrs env = classattrsX $ envX env selfparam env = selfparamX $ envX env setClassAttrs ns env = modX env $ \x -> x{ classattrsX = ns } setSelfParam n env = modX env $ \x -> x{ selfparamX = Just n } normEnv env0 = setX env0 NormX{ marksX = [], rtypeX = Nothing, lambdavarsX = PosNIL, classattrsX = [], selfparamX = Nothing } -- Normalize terms --------------------------------------------------------------------------------------- normSuite env [] = return [] normSuite env (s : ss) = do s' <- norm' env s comps <- getComps ss' <- normSuite (define (envOf s) env) ss defs <- mapM mkCompFun comps return (concat defs ++ s' ++ ss') where mkCompFun (f,lambound,comp) = do w <- newName "w" r <- newName "res" let env0 = define (envOf lambound) env fx = fxOf env0 comp (tw,w1,tr,e0,stmt) = transComp env0 w r comp body = sAssign (pVar w tw) w1 : sAssign (pVar r tr) e0 : stmt : sReturn (eVar r) : [] norm' env (sDef f lambound tr body fx) transComp env w r (ListComp _ (Elem e) co) = (tw, w1, tr, e0, compStmt co e1) where env1 = define (envOf co) env te = typeOf env1 e tr = tList te tw = tSequenceW tr te e0 = List NoLoc [] e1 = eCall (eDot (eVar w) appendKW) [eVar r, e] w1 = eCall (tApp (eQVar witSequenceList) [te]) [] transComp env w r (SetComp _ (Elem annot_e) co) = (tw, w1, tr, e0, compStmt co e1) where env1 = define (envOf co) env te = typeOf env1 annot_e tr = tSet te tw = tSetW tr te (w0, e) = unAnnot (tHashableW te) annot_e e0 = eCall (tApp (eQVar primMkSet) [te]) [w0, Set NoLoc []] e1 = eCall (eDot (eVar w) (name "add")) [eVar r, e] w1 = eCall (tApp (eQVar witSetSet) [te]) [w0] transComp env w r (DictComp _ (Assoc annot_k v) co) = (tw, w1, tr, e0, compStmt co e1) where env1 = define (envOf co) env tk = typeOf env1 annot_k tv = typeOf env1 v tr = tDict tk tv tw = tMappingW tr tk tv (w0, k) = unAnnot (tHashableW tk) annot_k e0 = eCall (tApp (eQVar primMkDict) [tv,tk]) [w0, Dict NoLoc []] e1 = eCall (eDot (eDot (eVar w) (Internal Witness "Indexed" 0)) setitemKW) [eVar r, k, v] w1 = eCall (tApp (eQVar witMappingDict) [tk,tv]) [w0] compStmt (CompFor l p e c) x = For l p e [compStmt c x] [] compStmt (CompIf l e c) x = If l [Branch e [compStmt c x]] [] compStmt (NoComp) x = sExpr x normPat :: NormEnv -> Pattern -> NormM (Pattern,Suite) normPat _ (PWild l a) = do n <- newName "ignore" return (PVar l n $ conv a,[]) normPat _ (PVar l n a) = return (PVar l n $ conv a,[]) normPat env (PParen _ p) = normPat env p normPat env p@(PTuple _ pp kp) = do v <- newName "tup" ss <- normSuite (define [(v, NVar t)] env) $ normPP v 0 pp ++ normKP v [] kp return (pVar v $ conv t, ss) where normPP v n (PosPat p pp) = Assign NoLoc [p] (DotI NoLoc (eVar v) n) : normPP v (n+1) pp normPP v n (PosPatStar p) = [Assign NoLoc [p] (foldl (RestI NoLoc) (eVar v) [0..n-1])] normPP _ _ PosPatNil = [] normKP v ns (KwdPat n p kp) = Assign NoLoc [p] (Dot NoLoc (eVar v) n) : normKP v (n:ns) kp normKP v ns (KwdPatStar p) = [Assign NoLoc [p] (foldl (Rest NoLoc) (eVar v) (reverse ns))] normKP _ _ KwdPatNil = [] t = typeOf env p normPat env p@(PList _ ps pt) = do v <- newName "lst" ss <- normSuite env $ normList v 0 ps pt return (pVar v $ conv t, ss) where normList v n (p:ps) pt = s : normList v (n+1) ps pt where s = Assign NoLoc [p] (eCall (eDot (eQVar qnIndexed) getitemKW) [eVar v, Int NoLoc n (show n)]) normList v n [] (Just p) = [Assign NoLoc [p] (eCall (eDot (eQVar qnSliceable) getsliceKW) [eVar v, Int NoLoc n (show n), None NoLoc, None NoLoc])] normList v n [] Nothing = [] t = typeOf env p class Norm a where norm :: NormEnv -> a -> NormM a norm' :: NormEnv -> a -> NormM [a] norm' env x = (:[]) <$> norm env x instance (Norm a, EnvOf a) => Norm [a] where norm env [] = return [] norm env (a:as) = do as1 <- norm' env a as2 <- norm env1 as return (as1++as2) where env1 = define (envOf a) env instance Norm a => Norm (Maybe a) where norm env Nothing = return Nothing norm env (Just a) = Just <$> norm env a instance Norm Module where norm env (Module m imps mdoc ss) = Module m imps mdoc <$> normSuite env ss handle env x hs = do bs <- sequence [ branch e b | Handler e b <- hs ] return $ [sIf bs [sExpr $ eCall (eQVar primRAISE) [eVar x]]] where branch (ExceptAll _) b = Branch (eBool True) <$> normSuite env b branch (Except _ y) b = Branch (eIsInstance x y) <$> normSuite env b branch (ExceptAs _ y z) b = Branch (eIsInstance x y) <$> (bind:) <$> normSuite env' b where env' = define [(z,NVar t)] env bind = sAssign (pVar z $ conv t) (eVar x) t = tCon $ TC y [] exitContext env s | DROP:c <- marks env = sDROP : exitContext (setMarks c env) s | FINAL:c <- marks env = [sRAISE $ exn s] | LOOP:c <- marks env = if s `elem` [sBreak,sContinue] then [s] else exitContext (setMarks c env) s | otherwise = [s] where exn (Break _) = eCall (eQVar primBRK) [] exn (Continue _) = eCall (eQVar primCNT) [] exn (Return _ (Just e)) = eCall (eQVar primRET) [e] sDROP = sExpr (eCall (eQVar primDROP) []) sPOP x = sAssign (pVar x tBaseException) (eCall (eQVar primPOP) []) ePUSH = eCall (eQVar primPUSH) [] ePUSHF = eCall (eQVar primPUSHF) [] sSEQ = sExpr (eCall (eQVar primRAISE) [eCall (eQVar primSEQ) []]) sRAISE e = sExpr (eCall (eQVar primRAISE) [e]) -- TODO: maybe less approximation? isVal Var{} = True isVal Int{} = True isVal Float{} = True isVal Imaginary{} = True isVal Bool{} = True isVal None{} = True isVal Strings{} = True isVal BStrings{} = True isVal Lambda{} = True isVal (Call _ (TApp _ (Var _ n) _) (PosArg e PosNil) KwdNil) = n == primCAST && isVal e isVal (TApp _ e _) = isVal e isVal (Dot _ e _) = isVal e isVal (DotI _ e _) = isVal e isVal (Paren _ e) = isVal e isVal _ = False instance Norm Stmt where norm env (Expr l e) = Expr l <$> norm env e norm env (MutAssign l t e) = MutAssign l <$> norm env t <*> norm env e norm env (Assert l e mbe) = do e' <- normBool env e mbe' <- norm env mbe return $ Expr l $ eCall (eQVar primASSERT) [e', maybe eNone id mbe'] norm env (Pass l) = return $ Pass l norm env (Raise l e) = do e' <- norm env e return $ Expr l $ eCall (eQVar primRAISE) [e'] norm env (If l bs els) = If l <$> norm env bs <*> normSuite env els norm env (While l e b els) = While l (eBool True) <$> normSuite (pushMark LOOP env) (sIf1 e [sPass] (els++[sBreak]) : b) <*> return [] norm env (Data l mbp ss) = Data l <$> norm env mbp <*> normSuite env ss norm env (VarAssign l ps e) = VarAssign l <$> norm env ps <*> norm env e norm env (After l e e') = After l <$> norm env e <*> norm env e' norm env (Signature l ns t d) = return $ Signature l ns (conv t) d norm env s = error ("norm unexpected stmt: " ++ prstr s) norm' env (Decl l ds) = do (eqs,ds) <- normDecls env ds return $ eqs ++ [Decl l ds] norm' env (Try l b [] els []) = normSuite env (b ++ els) norm' env (Try l b hs els []) = do b <- normSuite (pushMark DROP env) b els <- normSuite (define (envOf b) env) els x <- newName "x" hdl <- handle env x hs return [sIf [Branch ePUSH (b ++ sDROP : els)] (sPOP x : hdl)] where ePUSH = eCall (eQVar primPUSH) [] norm' env (Try l b hs els fin) = do ss <- norm' (pushMark FINAL env) try0 x <- newName "xx" fin <- normSuite (define [(x,NVar tBaseException)] env) fin return [sIf [Branch ePUSHF (ss++mbseq)] (sPOP x : fin ++ relays x)] where try0 = Try l b hs els [] relays x = iff [ Branch (eIsInstance x n) s | (n,s) <- map (relay x) ctrl, valid s] [sRAISE $ eVar x] relay _ SEQ = (primSEQ, [sPass]) relay _ BRK = (primBRK, exitContext env sBreak) relay _ CNT = (primCNT, exitContext env sContinue) relay x RET = (primRET, downcast : exitContext env ret) where x' = Derived x (globalName "RET") downcast = sAssign (pVar x' tRET) (eCAST tBaseException tRET (eVar x)) ret = sReturn (eCAST tValue (getRet env) (eDot (eVar x') attrVal)) valid [Expr{}] = False valid [Assign{},Expr{}] = False valid _ = True mbseq = if SEQ `elem` ctrl then [sSEQ] else [] ctrl = nub (flows try0) iff [] els = els iff bs els = [sIf bs els] norm' env s@(Break l) = return $ exitContext env s norm' env s@(Continue l) = return $ exitContext env s norm' env (Return l Nothing) = return $ exitContext env (Return l $ Just eNone) norm' env (Return l (Just e)) = do e <- norm env e case isVal e of True -> return $ retContext e False -> do n <- newName "tmp" return $ sAssign (pVar n $ conv t) e : retContext (eVar n) where retContext e = exitContext env $ Return l $ Just e t = typeOf env e norm' env (Assign l ps e) = do e' <- norm env e (ps1,stmts) <- unzip <$> mapM (normPat env) ps ps2 <- norm env ps1 let p'@(PVar _ n _) : ps' = ps2 return $ Assign l [p'] e' : [ Assign l [p] (eVar n) | p <- ps' ] ++ concat stmts where t = typeOf env e norm' env s@(For l p e b els) = do i <- newName "iter" v <- newName "val" normSuite env [sAssign (pVar i $ conv t) e, handleStop (While l (eBool True) (body v i) []) els] where t@(TCon _ (TC c [t'])) = typeOf env e next i = eCall (eDot (eVar i) nextKW) [] handleStop loop els = Try l [loop] [Handler (Except l0 qnStopIteration) (mkBody els)] [] [] body v i | isPVar p = sAssign p (next i) : b | otherwise = sAssign (pVar v t') (next i) : sAssign p (eVar v) : b isPVar PVar{} = True isPVar _ = False {- with EXPRESSION as PATTERN: SUITE ===> $mgr = EXPRESSION $val = $mgr.__enter__() $exc = False try: PATTERN = $val SUITE except Exception as ex: $exc = True if not $mgr.__exit__(ex): raise finally: if not $exc: $mgr.__exit__(None) -} norm' env s@(With l (i:is) b) = do notYet l s -- TODO: remove m <- newName "mgr" v <- newName "val" x <- newName "exc" (e,mbp,ss) <- normItem env i b' <- normSuite env1 (ss ++ b) return undefined where env1 = define (envOf i) env norm' env (With l [] b) = normSuite env b norm' env s = do s' <- norm env s return [s'] normItem env (WithItem e Nothing) = do e' <- norm env e return (e', Nothing, []) normItem env (WithItem e (Just p)) = do e' <- norm env e (p',ss) <- normPat env p return (e', Just p', ss) normDecls env ds = do (pres, ds) <- unzip <$> mapM (normDecl env1 ns) ds pre <- normSuite env (concat pres) return (pre, ds) where env1 = define (envOf ds) env ns = bound ds normDecl env ns d@Class{} = do d <- norm env1 d{ dbody = props ++ body } pre <- normSuite env pre return (pre, d) where (pre,te,body) = fixupClassAttrs ns d env1 = define (envOf pre ++ te) $ setClassAttrs (dom te) env props = [ Signature NoLoc [w] (monotype t) Property | (w,NVar t) <- te ] normDecl env ns d = do d <- norm env d return ([], d) -- The type-checker may leave witness bindings on the level of classes, even though our class -- syntax does not yet support this in the same way as is does for actors. But the creation and -- reduction of witnesses that mutually depend on classes becomes so much easier if we allow -- ourselves to make use of this planned feature already today. The code below thus implements -- class level bindings, albeit limited to witnesses, by transforming them into either global -- binding prefixes (if the circular class dependencies actually got eliminated during witness -- reduction), __init__ method locals (if they are only referenced during initialization) or -- proper instance attributes (in the general case). -- dbody -- / \ -- / \ -- eqs defs -- / \ / \ -- / \ inits dynamic -- pre dep -- / \ -- / \ -- attr local fixupClassAttrs ns d0@Class{dname=n} | null eqs = ([], [], defs) | otherwise = --trace ("### Fixup class " ++ prstr n ++ ":") $ --trace (" # te:\n" ++ render (nest 8 $ vcat $ map pretty te)) $ --trace (" # pre: " ++ prstrs (bound pre)) $ --trace (" # attr: " ++ prstrs (bound attr)) $ --trace (" # local: " ++ prstrs (bound local)) $ --trace (" # defs:\n" ++ render (nest 4 $ vcat [ pretty d | Decl _ ds <- defs1, d <- ds, dname d `elem` [initKW, altInit]])) $ (pre, te, defs1) where (eqs, defs) = split [] [] (dbody d0) where split eqs defs [] = (reverse eqs, reverse defs) split eqs defs (s:ss) = case s of Assign _ [PVar _ (Internal Witness _ _) (Just _)] _ -> split(s:eqs) defs ss _ -> split eqs (s:defs) ss (dynref, initpar) = dvars [] [] $ concat [ ds | Decl _ ds <- defs ] where dvars dyn ini [] = (dyn `intersect` bound eqs, ini) dvars dyn ini (d:ds) | dname d == initKW = dvars dyn ([ n | n@(Internal Witness _ _) <- bound (pos d) ] ++ ini) ds | otherwise = dvars (free d ++ dyn) ini ds (pre, dep) = split ns [] [] eqs where split ns pre dep [] = (reverse pre, reverse dep) split ns pre dep (eq:eqs) | null fvs = split ns (eq:pre) dep eqs | otherwise = split (bound eq ++ ns) pre (eq:dep) eqs where fvs = free (expr eq) `intersect` (initpar++ns) (attr, local) = split [] [] dep where split attr local [] = (reverse attr, reverse local) split attr local (eq:eqs) | null fvs = split attr (eq:local) eqs | otherwise = split (eq:attr) local eqs where fvs = bound eq `intersect` (dynref++free eqs) initMeth = if altInit `elem` bound defs then altInit else initKW defs1 = map (initS initMeth) defs where initS n (Decl l ds) = Decl l $ map (initL . initD n) ds initS n s = s initD n d@Def{} | dname d == n, Just self <- selfPar d = d{ dbody = [ sMutAssign (eDot (eVar self) w) e | Assign _ [PVar _ w _] e <- attr ] ++ dbody d } | deco d == Static = d{ dbody = attr ++ dbody d } initD n d = d initL d@Def{} | dname d == initKW = d{ dbody = local ++ dbody d } initL d = d te = [ (w, NVar t) | Assign _ [PVar _ w (Just t)] _ <- attr ] instance Norm Decl where norm env (Def l n q p k t b d x doc) = do p' <- joinPar <$> norm env0 p <*> norm (define (envOf p) env0) k b' <- normSuite env1 b return $ Def l n q p' KwdNIL (conv t) (ret b') d x doc where env1 = setMarks [] $ setRet t $ define (envOf p ++ envOf k) env0 env0 = defineTVars q env00 env00 = case p of PosPar self _ _ _ | not $ null $ classattrs env, d /= Static -> setSelfParam self env _ -> env ret b | fallsthru b = b ++ [sReturn eNone] | otherwise = b norm env (Actor l n q p k b doc) = do p' <- joinPar <$> norm env0 p <*> norm (define (envOf p) env0) k b' <- normSuite env1 b return $ Actor l n q p' KwdNIL b' doc where env1 = setMarks [] $ define (envOf p ++ envOf k) env0 env0 = define [(selfKW, NVar t0)] $ defineTVars q env t0 = tCon $ TC (NoQ n) (map tVar $ qbound q) norm env (Class l n q as b doc) = Class l n q as <$> normSuite env1 b <*> return doc where env1 = defineTVars (selfQuant (NoQ n) q) env norm env d = error ("norm unexpected: " ++ prstr d) catStrings ss = map (quote . escape '"') ss where escape c [] = [] escape c ('\\':x:xs) = '\\' : x : escape c xs escape c (x:xs) | x == c = '\\' : x : escape c xs | otherwise = x : escape c xs quote s = '"' : s ++ "\"" normInst env ts e = norm env e normBool env e | t == tBool = norm env e | TOpt _ t' <- t, Var{} <- e = return $ eBinOp (eCall (tApp (eQVar primISNOTNONE) [t']) [e]) And (eCall (eDot (eCAST t t' e) boolKW) []) | BinOp l e1 op e2 <- e, op `elem` [And,Or] = do e1 <- normBool env e1 e2 <- normBool env e2 return $ BinOp l e1 op e2 | otherwise = do e' <- norm env e return $ eCall (eDot e' boolKW) [] where t = typeOf env e instance Norm Expr where norm env (Var l (NoQ n)) | n `elem` classattrs env, Just self <- selfparam env = return $ eDot (eVar self) n norm env (Var l nm) = return $ Var l nm norm env (Int l i s) = Int l <$> return i <*> return s norm env (Float l f s) = Float l <$> return f <*> return s norm env (Imaginary l i s) = Imaginary l <$> return i <*> return s norm env (Bool l b) = Bool l <$> return b norm env (None l) = return $ None l norm env (NotImplemented l) = return $ NotImplemented l norm env (Ellipsis l) = return $ Ellipsis l norm env (Strings l ss) = return $ Strings l (catStrings ss) norm env (BStrings l ss) = return $ BStrings l (catStrings ss) norm env (Call l e p k) = Call l <$> norm env e <*> norm env (joinArg p k) <*> pure KwdNil norm env (TApp l e ts) = TApp l <$> normInst env ts e <*> pure (conv ts) norm env (Let l ss e) = Let l <$> norm env ss <*> norm env e norm env (Dot l (Var l' x) n) | NClass{} <- findQName x env = pure $ Dot l (Var l' x) n norm env (Dot l e n) | TTuple _ p k <- t, n `notElem` valueKWs = DotI l <$> norm env e <*> pure (nargs p + narg n k) | otherwise = Dot l <$> norm env e <*> pure n where t = typeOf env e norm env (Async l e) = Async l <$> norm env e norm env (Await l e) = Await l <$> norm env e norm env (Cond l e1 e2 e3) = Cond l <$> norm env e1 <*> normBool env e2 <*> norm env e3 norm env (IsInstance l e c) = IsInstance l <$> norm env e <*> pure c norm env (BinOp l e1 Or e2) = BinOp l <$> norm env e1 <*> pure Or <*> norm env e2 norm env (BinOp l e1 And e2) = BinOp l <$> norm env e1 <*> pure And <*> norm env e2 norm env (UnOp l Not e) = UnOp l Not <$> normBool env e norm env (Rest l e n) = RestI l <$> norm env e <*> pure (nargs p + narg n k) where TTuple _ p k = typeOf env e norm env (DotI l e i) = DotI l <$> norm env e <*> pure i norm env (RestI l e i) = RestI l <$> norm env e <*> pure i norm env (Lambda l p k e fx) = do p' <- joinPar <$> norm env p <*> norm (define (envOf p) env) k let env1 = define (envOf p ++ envOf k) (addLambdavars p' env) eta <$> (Lambda l p' KwdNIL <$> norm env1 e <*> pure fx) norm env (Yield l e) = Yield l <$> norm env e norm env (YieldFrom l e) = YieldFrom l <$> norm env e norm env (Tuple l ps ks) = Tuple l <$> norm env (joinArg ps ks) <*> pure KwdNil norm env (List l es) = List l <$> norm env es norm env e@ListComp{} = deferComp env e norm env (Dict l as) = Dict l <$> norm env as norm env e@DictComp{} = deferComp env e norm env (Set l es) = Set l <$> norm env es norm env e@SetComp{} = deferComp env e norm env (Paren l e) = norm env e norm env e = error ("norm unexpected: " ++ prstr e) deferComp env e = do f <- newName "compfun" let p = getLambdavars env addComp (f,p,e) return (Call NoLoc (eVar f) (posarg $ map eVar $ pospars' p) KwdNil) eta (Lambda _ p KwdNIL (Call _ e p' KwdNil) fx) | eq1 p p' = e where eq1 (PosPar n _ _ p) (PosArg e p') = eVar n == e && eq1 p p' eq1 (PosSTAR n _) (PosStar e) = eVar n == e eq1 PosNIL PosNil = True eq1 _ _ = False eta e = e nargs (TRow _ _ _ _ r) = 1 + nargs r nargs (TStar _ _ _) = 1 nargs (TNil _ _) = 0 narg n (TRow _ _ n' _ r) | n == n' = 0 | otherwise = 1 + narg n r narg n (TStar _ _ _) | n == attrKW = 0 narg n k = error ("### Bad narg " ++ prstr n ++ " " ++ prstr k) instance Norm Pattern where norm env (PWild l a) = return $ PWild l (conv a) norm env (PVar l n a) = return $ PVar l n (conv a) norm env (PTuple l ps ks) = PTuple l <$> norm env ps <*> norm env ks norm env (PList l ps p) = PList l <$> norm env ps <*> norm env p -- TODO: eliminate here norm env (PParen l p) = norm env p instance Norm Branch where norm env (Branch e ss) = Branch <$> normBool env e <*> normSuite env ss instance Norm Handler where norm env (Handler ex b) = Handler ex <$> normSuite env1 b where env1 = define (envOf ex) env instance Norm PosPar where norm env (PosPar n t e p) = PosPar n (conv t) <$> norm env e <*> norm (define [(n,NVar $ fromJust t)] env) p norm env (PosSTAR n t) = return $ PosSTAR n (conv t) norm env PosNIL = return PosNIL instance Norm KwdPar where norm env (KwdPar n t e k) = KwdPar n (conv t) <$> norm env e <*> norm (define [(n,NVar $ fromJust t)] env) k norm env (KwdSTAR n t) = return $ KwdSTAR n (conv t) norm env KwdNIL = return KwdNIL joinPar (PosPar n t e p) k = PosPar n t e (joinPar p k) joinPar (PosSTAR n t) k = PosPar n t Nothing (kwdToPosPar k) joinPar PosNIL k = kwdToPosPar k kwdToPosPar (KwdPar n t e k) = PosPar n t e (kwdToPosPar k) kwdToPosPar (KwdSTAR n t) = PosPar n t Nothing PosNIL kwdToPosPar KwdNIL = PosNIL joinArg (PosArg e p) k = PosArg e (joinArg p k) joinArg (PosStar e) k = PosArg e (kwdToPosArg k) joinArg PosNil k = kwdToPosArg k kwdToPosArg (KwdArg n e k) = PosArg e (kwdToPosArg k) kwdToPosArg (KwdStar e) = PosArg e PosNil kwdToPosArg KwdNil = PosNil instance Norm PosArg where norm env (PosArg e p) = PosArg <$> norm env e <*> norm env p norm env (PosStar e) = PosStar <$> norm env e norm env PosNil = return PosNil instance Norm KwdArg where norm env (KwdArg n e k) = KwdArg n <$> norm env e <*> norm env k norm env (KwdStar e) = KwdStar <$> norm env e norm env KwdNil = return KwdNil instance Norm PosPat where norm env (PosPat p ps) = PosPat <$> norm env p <*> norm env ps norm env (PosPatStar p) = PosPatStar <$> norm env p norm env PosPatNil = return PosPatNil instance Norm KwdPat where norm env (KwdPat n p ps) = KwdPat n <$> norm env p <*> norm env ps norm env (KwdPatStar p) = KwdPatStar <$> norm env p norm env KwdPatNil = return KwdPatNil instance Norm Comp where norm env (CompFor l p e c) = CompFor l <$> norm env p <*> norm env e <*> norm (define (envOf p) env) c norm env (CompIf l e c) = CompIf l <$> normBool env e <*> norm env c norm env NoComp = return NoComp instance Norm Elem where norm env (Elem e) = Elem <$> norm env e norm env (Star e) = Star <$> norm env e -- TODO: eliminate here instance Norm Assoc where norm env (Assoc k v) = Assoc <$> norm env k <*> norm env v norm env (StarStar e) = StarStar <$> norm env e -- TODO: eliminate here -- Convert function types --------------------------------------------------------------------------------- convEnv env m (n, i) = [(n, conv i)] class Conv a where conv :: a -> a instance (Conv a) => Conv [a] where conv = map conv instance (Conv a) => Conv (Maybe a) where conv = fmap conv instance (Conv a) => Conv (Name, a) where conv (n, x) = (n, conv x) instance Conv NameInfo where conv (NAct q p k te doc) = NAct q (joinRow p k) kwdNil (conv te) doc conv (NClass q ps te doc) = NClass q (conv ps) (conv te) doc conv (NSig sc dec doc) = NSig (conv sc) dec doc conv (NDef sc dec doc) = NDef (conv sc) dec doc conv (NVar t) = NVar (conv t) conv (NSVar t) = NSVar (conv t) conv ni = ni instance Conv WTCon where conv (w,c) = (w, conv c) instance Conv TSchema where conv (TSchema l q t) = TSchema l q (conv t) instance Conv Type where conv (TFun l fx p k t) = TFun l fx (joinRow p k) kwdNil (conv t) conv (TCon l c) = TCon l (conv c) conv (TTuple l p k) = TTuple l (joinRow p k) kwdNil conv (TOpt l t) = TOpt l (conv t) conv (TRow l k n t r) = TRow l PRow nWild (conv t) (conv r) conv (TStar l k r) = TRow l PRow nWild (TTuple l (conv r) kwdNil) posNil conv (TNil l k) = TNil l PRow conv t = t instance Conv TCon where conv (TC c ts) = TC c (conv ts) joinRow (TRow l k n t p) r = TRow l PRow nWild (conv t) (joinRow p r) joinRow (TStar l k p) r = TRow l PRow nWild (TTuple l (conv p) kwdNil) (conv r) joinRow (TNil _ _) r = conv r -- To be removed: joinRow p (TNil _ _) = conv p joinRow p r = error ("##### joinRow " ++ prstr p ++ " AND " ++ prstr r) ================================================ FILE: compiler/lib/src/Acton/Parser.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Acton.Parser ( module Acton.Parser , CustomParseError(..) ) where import qualified Control.Monad.Trans.State.Strict as St import qualified Control.Exception import Control.Concurrent.Async (Async, async, cancel, wait) import Control.Concurrent.Chan import Control.Concurrent.MVar import Control.Concurrent.QSem import Control.Monad (replicateM, replicateM_, void, when, join) import Control.DeepSeq (rnf) import Data.IORef import Data.List (isPrefixOf) import Data.Maybe (fromMaybe) import Data.Void import Data.Char import qualified Data.List.NonEmpty as N import qualified Data.Set as Set import GHC.Conc (getNumCapabilities) import Numeric import Text.Megaparsec import Text.Megaparsec.Char import Text.Megaparsec.Error import Text.Megaparsec.Pos (mkPos) --import Control.Monad.Combinators.Expr import Text_Megaparsec_Expr import qualified Text.Megaparsec.Char.Lexer as L import qualified Text.Megaparsec.Debug as D import qualified Data.List.NonEmpty import qualified Acton.Syntax as S import qualified Acton.Builtin as Builtin import qualified Acton.Names as Names import Utils import Debug.Trace import System.IO.Unsafe -- Custom error types for better structured error handling data CustomParseError = TypeVariableNameError String -- Name that looks like type variable | InvalidFormatSpecifier String | MissingClosingQuote String -- String is the quote type (e.g., "\"\"\"" or "'") | TooManyQuotesError String | InvalidModuleStatement | InvalidTopLevelAssignmentPattern | DuplicateTopLevelAssignment String -- String interpolation errors | EmptyInterpolationExpression | MissingExpressionBeforeFormat | UnclosedInterpolationBrace | EmptyFormatSpecifierError | TabInFormatSpecifier | NewlineInFormatSpecifier | InvalidCharInFormatSpecifier Char | MissingFormatPrecisionDigits -- Escape sequence errors | IncompleteHexEscape String -- String is the 1 char found | OctalEscapeOutOfRange | IncompleteUnicodeEscape Int Int -- expected, found | NonAsciiInBytesLiteral | UnknownEscapeSequence -- General fallback | OtherError String deriving (Eq, Ord, Show) instance ShowErrorComponent CustomParseError where showErrorComponent (TypeVariableNameError name) = "Invalid name (reserved for type variables)" showErrorComponent (InvalidFormatSpecifier spec) = "Invalid format specifier" ++ if null spec then "" else ": " ++ spec showErrorComponent (MissingClosingQuote quote) = "missing closing " ++ quote showErrorComponent (TooManyQuotesError quote) = "too many quote characters" showErrorComponent InvalidModuleStatement = "Only declarations and assignments are allowed at the module top level" showErrorComponent InvalidTopLevelAssignmentPattern = "Module top-level assignments must bind at least one name" showErrorComponent (DuplicateTopLevelAssignment name) = "Module top-level name '" ++ name ++ "' cannot be assigned more than once" -- String interpolation errors showErrorComponent EmptyInterpolationExpression = "Empty expression in string interpolation" showErrorComponent MissingExpressionBeforeFormat = "Missing expression before format specifier" showErrorComponent UnclosedInterpolationBrace = "missing closing '}' for expression" showErrorComponent EmptyFormatSpecifierError = "Empty format specifier after ':'" showErrorComponent TabInFormatSpecifier = "Tab character not allowed in format specifier" showErrorComponent NewlineInFormatSpecifier = "Newline not allowed in format specifier" showErrorComponent (InvalidCharInFormatSpecifier c) = "Invalid character '" ++ [c] ++ "' in format specifier" showErrorComponent MissingFormatPrecisionDigits = "Expected digits after '.' in format specifier" -- Escape sequence errors showErrorComponent (IncompleteHexEscape n) = "\"\\x\" must be followed by two hexadecimal digits" showErrorComponent OctalEscapeOutOfRange = "octal escape sequence out of range" showErrorComponent (IncompleteUnicodeEscape expected found) = "Incomplete universal character name (" ++ show expected ++ " hex digits needed)" showErrorComponent NonAsciiInBytesLiteral = "Only ASCII chars allowed in bytes literal" showErrorComponent UnknownEscapeSequence = "unknown escape sequence in string/bytes literal" -- General fallback showErrorComponent (OtherError msg) = msg -- Context errors ------------------------------------------------------------------------------- tr :: Show a => String -> Parser a -> Parser a tr msg p = do r <- observing p case r of Left err -> trace ("failure "++msg ++": "++show err) (parseError err) Right ok -> trace ("success "++msg++": "++show ok) (return ok) makeReport ps src = errReport (map setSpan ps) src where setSpan (loc, msg) = (extractSrcSpan loc src, msg) --- Main parsing and error message functions ------------------------------------------------------ parseModule :: S.ModName -> String -> String -> Maybe (Int -> Int -> IO ()) -> IO S.Module parseModule qn fileName fileContent mReportProgress = do let contentWithNewline = addFinalNewline fileContent (is, mdoc, bodyStart) <- case runParser (St.evalStateT module_header_with_offset initState) fileName contentWithNewline of Left err -> Control.Exception.throwIO err Right h -> return h parsed <- parseTopLevelChunks fileName contentWithNewline bodyStart mReportProgress let suite = regroupTopDecls (concat parsed) case runParser (St.evalStateT (validateModuleSuite suite) initState) fileName contentWithNewline of Left err -> Control.Exception.throwIO err Right () -> do reportFinalParseProgress contentWithNewline mReportProgress return $ S.Module qn is mdoc suite parseModuleSerial :: S.ModName -> String -> String -> Maybe (Int -> Int -> IO ()) -> IO S.Module parseModuleSerial qn fileName fileContent mReportProgress = do let contentWithNewline = addFinalNewline fileContent st <- parserStateWithProgress contentWithNewline mReportProgress case runParser (St.evalStateT file_input st) fileName contentWithNewline of Left err -> Control.Exception.throw err Right (i,mdoc,s) -> return $ S.Module qn i mdoc s parseModuleImports :: String -> String -> IO [S.Import] parseModuleImports fileName fileContent = fst <$> parseModuleHeader fileName fileContent parseModuleHeader :: String -> String -> IO ([S.Import], Maybe String) parseModuleHeader fileName fileContent = let contentWithNewline = addFinalNewline fileContent in case runParser (St.evalStateT import_input initState) fileName contentWithNewline of Left err -> Control.Exception.throw err Right res -> return res addFinalNewline :: String -> String addFinalNewline s | null s || last s == '\n' = s | otherwise = s ++ "\n" -- parseTest file = snd (unsafePerformIO (do cont <- readFile file; parseModule (S.modName ["test"]) file cont)) parseTestStr p str = case runParser (St.evalStateT p initState) "" str of Left err -> putStrLn (errorBundlePretty err) Right t -> print t extractSrcSpan :: SrcLoc -> String -> SrcSpan extractSrcSpan NoLoc src = SpanEmpty extractSrcSpan (Loc l r) src = sp where Right sp = runParser (St.evalStateT (extractP l r) initState) "" src extractP :: Int -> Int -> Parser SrcSpan extractP l r = do setOffset l SourcePos f srow scol <- getSourcePos setOffset r SourcePos _ erow ecol <- getSourcePos if srow == erow then if scol == ecol then return $ SpanPoint f (unPos srow) (unPos scol) else return $ SpanCoLinear f (unPos srow) (unPos scol) (unPos ecol - 1) else return $ SpanMultiLine f (unPos srow) (unPos scol) (unPos erow) (unPos ecol - 1) -- Parser state ----------------------------------------------------------- data ParserState = ParserState { psContexts :: [CTX] , psProgress :: Maybe ParseProgressReporter } data ParseProgressReporter = ParseProgressReporter { pprTotal :: Int , pprLastPercent :: IORef Int , pprReport :: Int -> Int -> IO () } type Parser = St.StateT ParserState (Parsec CustomParseError String) pushCtx ctx st = st { psContexts = ctx : psContexts st } popCtx st = st { psContexts = tail (psContexts st) } getCtxs = psContexts initState = ParserState [] Nothing parserStateWithProgress :: String -> Maybe (Int -> Int -> IO ()) -> IO ParserState parserStateWithProgress contentWithNewline mReportProgress = case mReportProgress of Nothing -> return initState Just reportProgress -> do lastPercent <- newIORef 0 return initState { psProgress = Just (ParseProgressReporter (length contentWithNewline) lastPercent reportProgress) } reportFinalParseProgress :: String -> Maybe (Int -> Int -> IO ()) -> IO () reportFinalParseProgress contentWithNewline mReportProgress = case mReportProgress of Nothing -> return () Just reportProgress -> let total = length contentWithNewline in reportProgress total total reportParseProgress :: Parser () reportParseProgress = do st <- St.get case psProgress st of Nothing -> return () Just p -> do off <- getOffset emitParseProgressUnsafe p off `seq` return () -- The reporter is installed only when parseModule receives one and emits -- monotonic percent updates at successful statement/import boundaries. emitParseProgressUnsafe :: ParseProgressReporter -> Int -> () emitParseProgressUnsafe p off = unsafePerformIO (emitParseProgress p off) {-# NOINLINE emitParseProgressUnsafe #-} emitParseProgress :: ParseProgressReporter -> Int -> IO () emitParseProgress p off = do let total = pprTotal p completed = max 0 (min total off) percent | total <= 0 = 100 | otherwise = max 0 (min 100 ((completed * 100) `div` total)) prev <- readIORef (pprLastPercent p) let shouldReport = percent > prev when shouldReport $ writeIORef (pprLastPercent p) percent when shouldReport (pprReport p completed total) -- Parser contexts --------------------------------------------------------- data CTX = TOP | PAR | IF | SEQ | LOOP | DATA | DEF | CLASS | PROTO | EXT | ACTOR deriving (Show,Eq) withCtx ctx = between (St.modify (pushCtx ctx)) (St.modify popCtx) ifCtx accept ignore yes no = do cs <- St.gets getCtxs case filter (`notElem` ignore) cs of c:_ | c `elem` accept -> yes _ -> no ifNotCtx avoid ignore yes no = do cs <- St.gets getCtxs case filter (`notElem` ignore) cs of c:_ | c `elem` avoid -> no _ -> yes -- onlyIn s = fail ("statement only allowed inside " ++ s) -- notIn s = fail ("statement not allowed inside " ++ s) success = return () contextError :: ContextError -> [(SrcLoc, String)] contextError err = [(loc err, ctxMsg err)] data ContextError = OnlyTopLevel SrcLoc String | OnlyInActor SrcLoc String | OnlyInLoop SrcLoc String | OnlyInClassProtoExt SrcLoc String | OnlyInClass SrcLoc String | OnlyInFunction SrcLoc String | OnlyInFunctionOrActor SrcLoc String | NotInClassProtoExt SrcLoc String | NotInData SrcLoc String deriving (Show, Eq) instance Control.Exception.Exception ContextError instance HasLoc ContextError where loc (OnlyTopLevel l _) = l loc (OnlyInActor l _) = l loc (OnlyInLoop l _) = l loc (OnlyInClassProtoExt l _) = l loc (OnlyInClass l _) = l loc (OnlyInFunction l _) = l loc (OnlyInFunctionOrActor l _) = l loc (NotInClassProtoExt l _) = l loc (NotInData l _) = l ctxMsg (OnlyTopLevel loc str) = str ++ " declaration only allowed on the module top level" ctxMsg (OnlyInActor loc str) = str ++ " statement only allowed inside an actor body" ctxMsg (OnlyInLoop loc str) = str ++ " statement only allowed inside a loop" ctxMsg (OnlyInClassProtoExt loc str) = str ++ " decoration only allowed inside a class, protocol or extension" ctxMsg (OnlyInClass loc str) = str ++ " decoration only allowed inside a class" ctxMsg (OnlyInFunction loc str) = str ++ " statement only allowed inside a function" ctxMsg (OnlyInFunctionOrActor loc str) = str ++ " statement only allowed inside a function or actor" ctxMsg (NotInClassProtoExt loc str) = str ++ " statement not allowed inside a class, protocol or extension" ctxMsg (NotInData loc str) = str ++ " statement not allowed inside a data tree" assertTop loc str = ifCtx [TOP] [] success (Control.Exception.throw $ OnlyTopLevel loc str) assertActBody loc str = ifCtx [ACTOR] [] success (Control.Exception.throw $ OnlyInActor loc str) assertLoop loc str = ifCtx [LOOP] [IF,SEQ] success (Control.Exception.throw $ OnlyInLoop loc str) assertDecl loc str = ifCtx [CLASS,PROTO,EXT] [] success (Control.Exception.throw $ OnlyInClassProtoExt loc str) assertClass loc str = ifCtx [CLASS] [] success (Control.Exception.throw $ OnlyInClass loc str) assertDef loc str = ifCtx [DEF] [IF,SEQ,LOOP] success (Control.Exception.throw $ OnlyInFunction loc str) assertDefAct loc str = ifCtx [DEF,ACTOR] [IF,SEQ,LOOP] success (Control.Exception.throw $ OnlyInFunctionOrActor loc str) assertNotDecl loc str = ifNotCtx [CLASS,PROTO,EXT] [IF] success (Control.Exception.throw $ NotInClassProtoExt loc str) assertNotData loc str = ifNotCtx [DATA] [IF,SEQ,LOOP] success (Control.Exception.throw $ NotInData loc str) ifPar = ifCtx [PAR] [] --- Indentation error ------------------------------------------------------- data IndentationError = IndentationError SrcLoc deriving (Show, Eq) instance Control.Exception.Exception IndentationError instance HasLoc IndentationError where loc (IndentationError l) = l indentationError :: IndentationError -> [(SrcLoc, String)] indentationError err = [(loc err, "Too much indentation")] -- Parser Exceptions -------------------------------------------------------- data CustomParseException = CustomParseException SrcLoc CustomParseError deriving (Show, Eq) instance Control.Exception.Exception CustomParseException parseException :: SrcLoc -> CustomParseError -> a parseException loc customErr = Control.Exception.throw $ CustomParseException loc customErr data ChunkScanError = ChunkScanError SrcLoc String deriving (Show, Eq) instance Control.Exception.Exception ChunkScanError --- Whitespace consumers ---------------------------------------------------- -- Whitespace consumer, which *does not* consume newlines -- but accepts line joining. -- This is used outside parentheses/brackets/braces sc1 :: Parser () sc1 = void $ do sc0 optional (char '\\' *> eol *> sc0) "" where sc0 = L.space (void $ takeWhile1P Nothing f) lineCmnt empty f x = x == ' ' || x == '\t' lineCmnt = L.skipLineComment "#" -- Whitespace consumer, which *does* consume also newlines. -- Used inside parentheses/brackets/braces sc2 :: Parser () sc2 = L.space space1 (L.skipLineComment "#") empty currSC = ifPar sc2 sc1 --- Adding position info to a parser ------------------------------------------ -- fetching the start column of a construct withPos :: Parser a -> Parser (Pos,a) withPos p = do c <- L.indentLevel -- SourcePos f r c <- getSourcePos a <- p -- getSourcePos return (c,a) -- forcing a construct to start in prescribed column atPos :: Pos -> Parser a -> Parser a atPos p a = do p2 <- L.indentLevel if p2==p then a else L.incorrectIndent EQ p p2 withLoc :: Parser a -> Parser (SrcLoc,a) withLoc p = do off1 <- getOffset a <- p off2 <- getOffset return (Loc off1 off2, a) class AddLoc a where addLoc :: Parser a -> Parser a instance AddLoc S.Import where addLoc p = do (l,stmt) <- withLoc p return stmt{S.iloc = l} instance AddLoc S.Stmt where addLoc p = do (l,stmt) <- withLoc p return stmt{S.sloc = l} instance AddLoc S.Decl where addLoc p = do (l,stmt) <- withLoc p return stmt{S.dloc = l} instance AddLoc S.Expr where addLoc p = do (l,expr) <- withLoc p return expr{S.eloc = l} instance AddLoc S.Name where addLoc p = do (l,name) <- withLoc p case name of S.Name _ n -> return (S.Name l n) _ -> return name instance AddLoc S.Except where addLoc p = do (l,exc) <- withLoc p case exc of S.ExceptAll _ -> return (S.ExceptAll l) S.Except _ e -> return (S.Except l e) S.ExceptAs _ e nm -> return (S.ExceptAs l e nm) instance AddLoc S.Sliz where addLoc p = do (l,i) <- withLoc p case i of S.Sliz _ e1 e2 e3 -> return (S.Sliz l e1 e2 e3) instance AddLoc S.Comp where addLoc p = do (l,cmp) <- withLoc p case cmp of S.CompFor _ t e c -> return (S.CompFor l t e c) S.CompIf _ e c -> return (S.CompIf l e c) S.NoComp -> return S.NoComp instance AddLoc S.TSchema where addLoc p = do (l, S.TSchema _ q t) <- withLoc p return $ S.TSchema l q t instance AddLoc S.Type where addLoc p = do (l,ct) <- withLoc p return ct{S.tloc = l} instance AddLoc S.Pattern where addLoc p = do (l,pat) <- withLoc p return pat{S.ploc = l} rwordLoc :: String -> Parser SrcLoc rwordLoc word = do off <- getOffset rword word return $ Loc off (off+length word) locate (Loc l _) = setOffset l --- Functions recognizing lexical items ---------------------------------------- lexeme:: Parser a -> Parser a lexeme p = p <* currSC symbol :: String -> Parser String symbol str = lexeme (string str) newline1 :: Parser [S.Stmt] newline1 = const [] <$> (eol *> sc2) --- START OF STRING PARSING -------------------------------------------------------- {- The following principles for bytes and string literals are implemented by the following parse functions and the transformations in Acton.Normalize Literal syntax is as in subsections 2.4.1 and 2.4.2 in the Python Language Reference, version 3.10.4, except that only the following prefixes are allowed: - no prefix: string literal with interpolation - prefix 'f': string literal with interpolation. the f prefix is optional and has no effect, it is supported as a convenience for users coming from Python - prefix 'r': raw string literal with no interpolation - prefix 'b': plain bytes literal - prefix 'rb': raw bytes literals Thus we disallow - upper case versions of the above prefixes (for no particular reason other than the opinion that it is not an unreasonable burden on the programmer to have to stick to lower case prefixes). For similar reasons we disallow prefix 'br' and thus just form a raw literal by prefixing a plain literal with 'r'.) - the 'u' prefix which only exists in Python for legacy reasons. Prefix sequences are also as in subsection 2.4.1 with the following exceptions - unrecognized escape sequences (like \p or \z or any other sequence not listed in the table of 2.4.1) are disallowed (unlike Python where they are allowed but the language reference declares that they will become illegal in a future Python version.). - universal character names \uxxxx and \Uxxxxxxxx are unrecognized in bytes literals. - \x must be followed by exactly two hex digits (unlike in C). To avoid a compilation error in the generated C code, e.g. the string "\x12a" is changed to "\x12" "a" so that the 'a' is not interpreted by the C compiler as a third hexadecimal digit in the \x... sequence. Note that C allows sequences of string literals which are concatenated during C compilation. -} strings :: Parser S.Expr strings = addLoc $ bytesLiteral <|> rawStringLiteral <|> fstringLiteral -- Explicit f"..." syntax, with interpolation <|> stringLiteral -- "" strings - all strings support interpolation -- We use this `some` construct because Acton allows multiple adjacent strings -- to be effectively concatenated together without specifying any explicit -- operator. This is allowed in Python, and we have inherited this behavior. -- It's weird though, so we might want to change it in the future. -- For example, in Acton / Python, the following is valid: -- s = "Hello, " "world!" -- This will be parsed as a single string literal, not two separate ones. bytesLiteral :: Parser S.Expr bytesLiteral = S.BStrings NoLoc . concat <$> some bytesLiteralCombo -- | b"" and rb"" bytesLiteralCombo :: Parser [String] bytesLiteralCombo = plainbytesLiteral <|> rawbytesLiteral "bytes literal" -- | Raw string literals (r"...") that don't support interpolation rawStringLiteral :: Parser S.Expr rawStringLiteral = S.Strings NoLoc . concat <$> some rawstrLiteral "string literal" -- Docstring parser - parses strings with normal escape handling but no interpolation docstringLiteral :: Parser S.Expr docstringLiteral = (do parts <- some docstringPlainLiteral return $ S.Strings NoLoc [concat (concat parts)] ) "docstring" where docstringPlainLiteral = plainstrLiteral <|> rawstrLiteral -- Explicit f-string syntax (f"...") - kept for compatibility -- Note: Regular strings ("...") also support interpolation via the unified parser fstringLiteral :: Parser S.Expr fstringLiteral = concatStringLiterals singleFstring "string literal" where -- Parse a single f-string singleFstring = try (parseInterpolatedString "f\"\"\"" "\"\"\"" (parseTextPart "\"" True True)) <|> try (parseInterpolatedString "f'''" "'''" (parseTextPart "'" True True)) <|> try (parseInterpolatedString "f\"" "\"" (parseTextPart "\"" False False)) <|> parseInterpolatedString "f'" "'" (parseTextPart "'" False False) -- | Normal strings in Acton support interpolation -- This means literal { and } must be escaped as {{ and }} stringLiteral :: Parser S.Expr stringLiteral = concatStringLiterals singleInterpolatedString "string literal" where -- Parse a single string singleInterpolatedString = try (parseInterpolatedString "\"\"\"" "\"\"\"" (parseTextPart "\"" True True)) <|> try (parseInterpolatedString "'''" "'''" (parseTextPart "'" True True)) <|> try (parseInterpolatedString "\"" "\"" (parseTextPart "\"" False False)) <|> parseInterpolatedString "'" "'" (parseTextPart "'" False False) -- | Helper function to concatenate multiple adjacent string literals -- Supports both regular strings and f-strings with the same logic concatStringLiterals :: Parser S.Expr -> Parser S.Expr concatStringLiterals singleStringParser = do -- Parse one or more consecutive string literals which are concatenated into a single string -- like: a = 'foo' 'bar' or a = f'foo' f'bar' parts <- some singleStringParser -- Combine all parts into a single expression case parts of [single] -> return single -- Single string, return as-is multiple -> do -- Multiple strings need to be concatenated -- We need to combine all the format strings and collect all expressions let (formatParts, exprLists) = unzip $ map extractParts multiple combinedFormat = concat formatParts combinedExprs = concat exprLists if null combinedExprs then return $ S.Strings NoLoc [combinedFormat] else return $ S.BinOp NoLoc (S.Strings NoLoc [combinedFormat]) S.Mod (if length combinedExprs == 1 then head combinedExprs else S.Tuple NoLoc (foldr S.PosArg S.PosNil combinedExprs) S.KwdNil) where -- Extract format string and expressions from each part extractParts :: S.Expr -> (String, [S.Expr]) extractParts (S.Strings _ ss) = (concat ss, []) extractParts (S.BinOp _ (S.Strings _ [fmt]) S.Mod expr) = case expr of S.Tuple _ args _ -> (fmt, tupleToList args) e -> (fmt, [e]) extractParts _ = ("", []) -- Should not happen -- Convert tuple arguments to list tupleToList :: S.PosArg -> [S.Expr] tupleToList S.PosNil = [] tupleToList (S.PosArg e rest) = e : tupleToList rest -- | Parts of an interpolated string data StringPart = TextPart String -- ^ Regular text content | ExprPart S.Expr String -- ^ Expression with format specifier deriving Show -- | Convert f-string parts to a format string with specifiers buildFormatString :: [StringPart] -> String buildFormatString [] = "" buildFormatString (TextPart s : rest) = s ++ buildFormatString rest buildFormatString (ExprPart _ fmt : rest) = "%" ++ fmt ++ buildFormatString rest -- | Parse a string with optional interpolation expressions -- Both regular strings and f-strings support interpolation in Acton -- i.e. "{foo}" and f"{foo}" are equivalent parseInterpolatedString :: String -> String -> (Int -> Parser StringPart) -> Parser S.Expr parseInterpolatedString startQuote endQuote textPartParser = lexeme $ do startLoc <- getOffset try $ string startQuote let startQuoteCharOffset = startLoc + (length startQuote - length endQuote) let stringPart = choice [ -- Escaped braces - handle these BEFORE expression parsing try (string "{{" >> return (TextPart "{")), try (string "}}" >> return (TextPart "}")), -- Expression parts (now without the notFollowedBy check) try exprPart, -- Regular text textPartParser startQuoteCharOffset ] parts <- many stringPart string endQuote <|> do -- If we couldn't parse the closing quote, check why currentPos <- getOffset nextChar <- lookAhead (optional anySingle) let isMultiline = length endQuote == 3 -- Triple quotes indicate multiline strings case nextChar of Nothing -> if isMultiline then parseException (Loc (startLoc - length startQuote) startLoc) $ MissingClosingQuote endQuote else fail $ "string at position " ++ show startLoc ++ " is not closed" _ -> fail $ "missing closing " ++ endQuote -- Check if we found any expressions let exprs = [e | ExprPart e _ <- parts] if null exprs then do -- No expressions found, create a regular string let textContent = concat [s | TextPart s <- parts] -- Apply hex splitting to handle cases like "\x48ello" -> ["\x48", "ello"] return $ S.Strings NoLoc (hexSplitString textContent) else do -- Found expressions, create interpolated string format let formatStr = buildFormatString parts result = S.BinOp NoLoc (S.Strings NoLoc [formatStr]) S.Mod (if length exprs == 1 then head exprs else S.Tuple NoLoc (foldr S.PosArg S.PosNil exprs) S.KwdNil) return result -- | Create a text part parser for given quote style parseTextPart :: String -> Bool -> Bool -> Int -> Parser StringPart parseTextPart quoteStr isTriple handleNewlines startOfString = do chunks <- some $ choice [ -- Use existing escape sequence parsers with better error handling try (char '\\' >> choice [ -- Escaped quotes - handle quote-specific escaping try (string quoteStr >> return quoteStr), -- Use existing escape parsers for consistency and better error messages try hexEscape, try univ1Escape, try univ2Escape, try octEscape, try singleCharEscape, try newlineEscape, -- Handle unknown escape sequences with proper error anyC >>= \c -> unknownEscape (return c) ]), -- Handle newlines in triple-quoted strings if handleNewlines then try (string "\n" >> return "\\n") else empty, -- Handle quotes in triple-quoted strings if isTriple then try (do -- When we see a quote char, check if it's part of closing sequence c <- char (head quoteStr) quotes <- lookAhead $ many (char (head quoteStr)) let totalQuotes = 1 + length quotes case totalQuotes of -- 1-2 quotes: always consume as content 1 -> return [c] 2 -> char (head quoteStr) >> return [c, head quoteStr] -- 3 quotes exactly: this is the closing sequence, stop 3 -> empty -- 4 quotes: consume 1, leave 3 for closing 4 -> return [c] -- 5 quotes: consume 2, leave 3 for closing 5 -> char (head quoteStr) >> return [c, head quoteStr] -- 6+ quotes: this is an error _ -> do curPos <- getOffset let startPos = curPos - 1 endPos = startPos + totalQuotes parseException (Loc (startPos) endPos) (TooManyQuotesError quoteStr) ) else empty, -- Any other character not in braces or quotes if not isTriple then do -- Check for newline in single-line string nextChar <- lookAhead (optional (char '\n')) case nextChar of Just _ -> do pos <- getOffset parseException (Loc startOfString pos) $ MissingClosingQuote quoteStr Nothing -> do (loc, c) <- withLoc $ noneOf ("{}" ++ quoteStr ++ "\n") return [c] else (:[]) <$> noneOf ("{}" ++ quoteStr) ] -- Concatenate chunks return (TextPart (concat chunks)) -- | Parse an expression in braces with optional format specifier exprPart :: Parser StringPart exprPart = do openLoc <- getOffset char '{' -- Allow for spaces around the expression many (char ' ') -- Check for empty expression or immediate colon closeLoc <- getOffset nextChar <- lookAhead (optional (oneOf "}:")) case nextChar of Just '}' -> parseException (Loc closeLoc closeLoc) EmptyInterpolationExpression Just ':' -> parseException (Loc closeLoc closeLoc) MissingExpressionBeforeFormat _ -> return () -- Parse the expression - now allowing interpolated strings since f-prefix is optional parsedExpr <- expr "expression" -- Allow spaces before format specifier or closing brace many (char ' ') -- Check for optional format specifier formatInfo <- (char ':' *> formatSpec) <|> do closeBraceLoc <- getOffset char '}' <|> parseException (Loc (openLoc + 1) (closeBraceLoc)) UnclosedInterpolationBrace return ("s", False, Nothing, Nothing, False, Nothing) let (fmt, isZeroPad, precisionInfo, typeSpecInfo, isCenterAlign, widthInfo) = formatInfo -- Apply formatting logic finalExpr <- if isCenterAlign && widthInfo /= Nothing then do -- Handle center alignment by using str.center() method let widthExpr = case widthInfo of Just w -> S.Int NoLoc (read w) w Nothing -> S.Int NoLoc 0 "0" -- First convert the expression to a string strExpr = S.Call NoLoc (S.Var NoLoc (S.NoQ (S.Name NoLoc "str"))) (S.PosArg parsedExpr S.PosNil) S.KwdNil -- Then call the center method on the string centerMethod = S.Dot NoLoc strExpr (S.Name NoLoc "center") -- Call center(width) centeredExpr = S.Call NoLoc centerMethod (S.PosArg widthExpr S.PosNil) S.KwdNil return centeredExpr -- Handle float format specifiers directly else if isZeroPad || (precisionInfo /= Nothing) then -- For formatting with a type specifier (like .2f), pass the raw expression -- This allows printf to apply the format directly to the value return parsedExpr -- For normal formatting, convert to str else return $ S.Call NoLoc (S.Var NoLoc (S.NoQ (S.Name NoLoc "str"))) (S.PosArg parsedExpr S.PosNil) S.KwdNil return $ ExprPart finalExpr fmt -- | Parse format specifier after the colon (colon is already consumed) formatSpec :: Parser (String, Bool, Maybe String, Maybe Char, Bool, Maybe String) -- Returns (format, isZeroPadded, precision, typeSpec, isCenterAlign, width) formatSpec = do specLoc <- getOffset -- Allow spaces at the beginning many (char ' ') -- Check if there's any content before trying to parse beforeParseLoc <- getOffset nextChar <- lookAhead (optional anySingle) case nextChar of Just '}' -> parseException (Loc specLoc beforeParseLoc) EmptyFormatSpecifierError _ -> return () -- Try to parse fill character and alignment -- First, check if we have an invalid character at the start firstChar <- lookAhead (optional anySingle) _ <- case firstChar of Just c | c `notElem` "<>^+-#0123456789.} " && c /= '\t' && c /= '\n' -> do -- Check if this might be a fill character followed by alignment secondChar <- lookAhead (optional (anySingle >> anySingle)) case secondChar of Just a | a `elem` "<>^" -> return () -- Valid fill+align pattern _ -> do -- Record position before consuming badCharPos <- getOffset -- Consume the character to advance position _ <- anySingle parseException (Loc badCharPos (badCharPos + 1)) $ InvalidCharInFormatSpecifier c Just '\t' -> do tabPos <- getOffset _ <- anySingle parseException (Loc tabPos (tabPos + 1)) TabInFormatSpecifier Just '\n' -> do nlPos <- getOffset _ <- anySingle parseException (Loc nlPos (nlPos + 1)) NewlineInFormatSpecifier _ -> return () mbFillAlign <- optional $ try (do -- Try to parse fill + alignment (strict validation) try (do f <- anySingle a <- oneOf "<>^" "alignment character (<, >, or ^)" return (f, Just a) ) <|> do a <- oneOf "<>^" "alignment character (<, >, or ^)" return (' ', Just a) ) let (fill, align) = fromMaybe (' ', Nothing) mbFillAlign -- Optional sign _sign <- optional $ oneOf "+-" -- Optional # (alternate form) _alternate <- optional $ char '#' -- Optional zero padding (0 flag) zeroPad <- optional $ char '0' -- Optional width width <- optional $ some digitChar -- Optional precision precision <- optional $ do char '.' digitLoc <- getOffset digits <- optional $ some digitChar case digits of Nothing -> parseException (Loc digitLoc digitLoc) MissingFormatPrecisionDigits Just d -> return d -- Optional type specifier typeLoc <- getOffset typeSpec <- optional (oneOf "fdeEgGnoxX%bos" "type specifier") -- Allow spaces before closing brace many (char ' ') -- Check for any remaining invalid characters invalidCharLoc <- getOffset invalidChar <- lookAhead (optional (noneOf "}")) case invalidChar of Just c -> if c == '\t' then parseException (Loc invalidCharLoc invalidCharLoc) TabInFormatSpecifier else if c == '\n' then parseException (Loc invalidCharLoc invalidCharLoc) NewlineInFormatSpecifier else parseException (Loc invalidCharLoc invalidCharLoc) $ InvalidCharInFormatSpecifier c Nothing -> return () -- Check if we parsed nothing meaningful (this should be rare now) endLoc <- getOffset when (align == Nothing && _sign == Nothing && zeroPad == Nothing && width == Nothing && precision == Nothing && typeSpec == Nothing && beforeParseLoc == endLoc) $ parseException (Loc specLoc endLoc) $ InvalidFormatSpecifier "" -- Consume the closing brace char '}' "closing brace '}' after format specifier" -- Determine various format properties let isZeroPadding = zeroPad == Just '0' && width /= Nothing isCenterAlign = align == Just '^' -- Convert to printf format let fmt = case (precision, typeSpec) of -- Float with precision and width (e.g., 10.2f becomes %10.2f for printf) (Just p, Just 'f') -> case (zeroPad, width) of (Just '0', Just w) -> "0" ++ w ++ "." ++ p ++ "f" -- Zero-padded float (_, Just w) -> w ++ "." ++ p ++ "f" -- Regular float with width (_, Nothing) -> "." ++ p ++ "f" -- Just precision, no width -- Default to float if precision specified but no type (Just p, _) -> case (zeroPad, width) of (Just '0', Just w) -> "0" ++ w ++ "." ++ p ++ "f" (_, Just w) -> w ++ "." ++ p ++ "f" (_, Nothing) -> "." ++ p ++ "f" -- Float without precision (Nothing, Just 'f') -> "f" -- Other formats based on alignment and width (Nothing, _) -> case (zeroPad, align, width) of -- Zero padding with width (for numbers) - use integer format (Just '0', _, Just w) -> "0" ++ w ++ "d" -- Left-aligned with width (_, Just '<', Just w) -> "-" ++ w ++ "s" -- Right-aligned with width (_, Just '>', Just w) -> w ++ "s" -- Center-aligned with width (_, Just '^', Just w) -> "s" -- Width handled separately in expr processing -- Just width, no alignment (_, Nothing, Just w) -> w ++ "s" -- Default case _ -> "s" return (fmt, isZeroPadding, precision, typeSpec, isCenterAlign, width) -- Split string when hex escape is followed by hex digit (to prevent C compiler issues) -- Only splits if the string contains actual hex escapes (not literal \x patterns) hexSplitString :: String -> [String] hexSplitString "" = [""] hexSplitString s | hasActualHexEscapes s = filter (not . null) $ reverse $ map reverse $ process s [] [] | otherwise = [s] -- No splitting needed for raw strings or strings without hex escapes where -- Check if string has actual hex escapes (single backslash followed by x and hex digits) -- Raw strings produce \\x patterns (double backslashes) which should NOT be split hasActualHexEscapes [] = False hasActualHexEscapes ('\\':'\\':'x':rest) = hasActualHexEscapes rest -- Skip \\x pattern (raw string) hasActualHexEscapes ('\\':'x':h1:h2:rest) | isHex h1 && isHex h2 = True | otherwise = hasActualHexEscapes rest hasActualHexEscapes (_:rest) = hasActualHexEscapes rest process [] acc chunks = acc : chunks process ('\\':'x':h1:h2:rest) acc chunks | isHex h1 && isHex h2 && (not (null rest) && isHex (head rest)) = -- Next char is hex, split here - complete current chunk with hex escape let completedChunk = h2:h1:'x':'\\':acc in process rest [] (completedChunk : chunks) | isHex h1 && isHex h2 = -- Valid hex escape, continue accumulating process rest (h2:h1:'x':'\\':acc) chunks | otherwise = -- Invalid hex escape, keep as-is process (h1:h2:rest) ('x':'\\':acc) chunks process (c:cs) acc chunks = process cs (c:acc) chunks isHex c = c `elem` "0123456789abcdefABCDEF" newlineEscape = "" <$ newline singleCharEscape = (\c -> '\\':c:[]) <$> (oneOf ("\'\"\\abfnrtv")) hexEscape = do char 'x' (loc,cs) <- withLoc (count' 0 2 hexDigitChar) if length cs == 2 then return ("\\x" ++ cs) else parseException loc $ IncompleteHexEscape cs octEscape = do (loc,cs) <- withLoc (count' 1 3 octDigitChar) if length cs == 3 && head cs > '3' then parseException loc OctalEscapeOutOfRange else return ("\\" ++ cs) univ1Escape = do char 'u' (loc,cs) <- withLoc (count' 0 4 hexDigitChar) if length cs < 4 then parseException loc $ IncompleteUnicodeEscape 4 (length cs) else return ("\\u" ++ cs) univ2Escape = do char 'U' (loc,cs) <- withLoc (count' 0 8 hexDigitChar) if length cs < 8 then parseException loc $ IncompleteUnicodeEscape 8 (length cs) else return ("\\U" ++ cs) asciiC = do (loc,c) <- withLoc anySingle if c == '\n' then parseException loc (MissingClosingQuote "\"") else if isAscii c then return [c] else parseException loc NonAsciiInBytesLiteral anyC = do (loc,c) <- withLoc anySingle if c == '\n' then parseException loc (MissingClosingQuote "\"") else return [c] unknownEscape charParser = do (loc,c) <- withLoc charParser parseException loc UnknownEscapeSequence plainLiteral charParser prefix tailEscapes = stringTempl "\"\"\"" longItem esc prefix <|> stringTempl "'''" longItem esc prefix <|> stringTempl "\"" charParser esc prefix <|> stringTempl "'" charParser esc prefix where longItem = ("\\n" <$ newline) <|> charParser -- newlines allowed in triple-quoted literals esc = newlineEscape <|> singleCharEscape <|> hexEscape <|> octEscape <|> tailEscapes plainbytesLiteral = plainLiteral asciiC "b" (unknownEscape asciiC) plainstrLiteral = plainLiteral anyC "" ( univ1Escape <|> univ2Escape <|> unknownEscape anyC) rawLiteral charParser prefix = stringTempl "\"\"\"" longItem esc prefix <|> stringTempl "'''" longItem esc prefix <|> stringTempl "\"" charParser esc prefix <|> stringTempl "'" charParser esc prefix where longItem = ("\\n" <$ newline) <|> charParser esc = newlineEscapeRaw <|> singleCharEscapeRaw <|> generalEscapeRaw newlineEscapeRaw = "\\\\\\n" <$ newline singleCharEscapeRaw = (\c -> "\\\\\\" ++ [c]) <$> (oneOf ("\'\"")) generalEscapeRaw = return "\\\\" rawbytesLiteral = rawLiteral asciiC "rb" rawstrLiteral = rawLiteral ((:[]) <$> anySingle) "r" stringTempl :: String -> Parser String -> Parser String -> String -> Parser [String] stringTempl q single esc prefix = do startLoc <- getOffset _ <- string (prefix++q) -- For single-quoted strings, guard against newline before closing quote let startQuoteOffset = startLoc + length prefix guardedSingle = if length q == 1 then do -- If the next char is a newline, treat as unclosed string mb <- lookAhead (optional anySingle) case mb of Just '\n' -> do pos <- getOffset parseException (Loc startQuoteOffset pos) (MissingClosingQuote q) _ -> single else single content <- manyTillEsc guardedSingle esc (string q closingQuoteError startLoc q) currSC -- Apply lexeme whitespace consumption return $ hexSplitString . concat $ content where closingQuoteError startLoc quote | quote `elem` ["\"\"\"", "'''"] = "closing triple quote " ++ quote ++ " for string starting at position " ++ show startLoc | otherwise = "closing quote " ++ quote ++ " for string" manyTillEsc, someTillEsc :: Parser String -> Parser String -> Parser String -> Parser [String] manyTillEsc p esc end = (const [] <$> end) <|> (someTillEsc p esc end) someTillEsc p esc end = do a <- (char '\\' *> esc) <|> p b <- manyTillEsc p esc end return $ a : b --- END OF STRING PARSING -------------------------------------------------------- -- Reserved words, other symbols and names ---------------------------------------------------------- rword :: String -> Parser () rword w = (lexeme . try) (string w *> notFollowedBy (alphaNumChar <|> char '_')) comma = symbol "," "comma" colon = symbol ":" semicolon = symbol ";" equals = symbol "=" star = symbol "*" starstar = symbol "**" dot = symbol "." arrow = symbol "->" fatarrow = symbol "=>" qmark = symbol "?" vbar = symbol "|" -- Parser for operator that is a prefix of another operator -- Slightly hackish; depends on the (presently true) fact that chars in argument to oneOf are -- the only chars that can follow directly after the prefix operator in a longer operator name. opPref :: String -> Parser String opPref op = (lexeme . try) (string op <* notFollowedBy (oneOf "<>=/*")) singleStar = (lexeme . try) (char '*' <* notFollowedBy (char '*')) identifier :: Parser String identifier = (lexeme . try) $ do off <- getOffset c <- satisfy (\c -> isAlpha c || c=='_') "identifier" cs <- hidden (takeWhileP Nothing (\c -> isAlphaNum c || c=='_')) let x = c:cs if S.isKeyword x then parseError (TrivialError off (Just (Tokens (N.fromList x))) (Set.fromList [Label (N.fromList "identifier")])) else return x name, escname, tvarname :: Parser S.Name name = do off <- getOffset x <- identifier if isUpper (head x) && all isDigit (tail x) then parseError (FancyError off (Set.fromList [ErrorCustom (TypeVariableNameError x)])) else return $ S.Name (Loc off (off+length x)) x escname = name <|> addLoc (S.Name NoLoc . head <$> plainstrLiteral) -- Assumes an escname cannot contain hex escape sequences tvarname = do off <- getOffset x <- identifier if isUpper (head x) && all isDigit (tail x) then return $ S.Name (Loc off (off+length x)) x else parseError (TrivialError off (Just (Tokens (N.fromList x))) (Set.fromList [Label (N.fromList ("type variable (upper case letter optionally followed by digits)"))])) module_name :: Parser S.ModName module_name = do n <- name ns <- many (dot *> escname) return $ S.ModName (n:ns) qual_name :: Parser S.QName qual_name = do n <- name ns <- many (dot *> escname) case n:ns of [n] -> return $ S.NoQ n ns' -> return $ S.QName (S.ModName (init ns')) (last ns') -- recognizers for numbers are used directly in function atom below. --- Helper functions for parenthesised forms ----------------------------------- parens, brackets, braces :: Parser a -> Parser a parens p = withCtx PAR (L.symbol sc2 "(" *> p <* (char ')' "closing ')'")) <* currSC brackets p = withCtx PAR (L.symbol sc2 "[" *> p <* (char ']' "closing ']'")) <* currSC braces p = withCtx PAR (L.symbol sc2 "{" *> p <* (char '}' "closing '}'")) <* currSC --- Top-level parsers ------------------------------------------------------------ module_docstring :: Parser String module_docstring = do S.Strings _ ss <- addLoc docstringLiteral return (unescapeString (concat ss)) file_input :: Parser ([S.Import], Maybe String, S.Suite) file_input = sc2 *> do -- Allow optional module docstring before imports mbDocstring <- optional (try (L.nonIndented sc2 module_docstring <* eol <* sc2)) is <- imports s <- withCtx TOP top_suite validateModuleSuite s eof return (is, mbDocstring, s) -- (((,) <$> imports <*> withCtx TOP top_suite) <* eof) import_input :: Parser ([S.Import], Maybe String) import_input = do (is, mbDocstring, _) <- module_header_with_offset return (is, mbDocstring) module_header_with_offset :: Parser ([S.Import], Maybe String, Int) module_header_with_offset = sc2 *> do mbDocstring <- optional (try (L.nonIndented sc2 module_docstring <* eol <* sc2)) is <- imports off <- getOffset return (is, mbDocstring, off) imports :: Parser [S.Import] imports = many (L.nonIndented sc2 import_stmt <* eol <* sc2 <* reportParseProgress) top_suite :: Parser S.Suite top_suite = concat <$> (many (L.nonIndented sc2 (stmt <* reportParseProgress) <|> (newline1 <* reportParseProgress))) validateModuleSuite :: S.Suite -> Parser () validateModuleSuite = go Set.empty where go seen [] = return () go seen (stmt:stmts) = case stmt of S.Assign _ pats _ -> do let names = Names.bound pats if null names then parseException (loc pats) InvalidTopLevelAssignmentPattern else do seen' <- addNames seen names go seen' stmts S.Signature{} -> go seen stmts S.Decl{} -> go seen stmts _ -> parseException (S.sloc stmt) InvalidModuleStatement addNames seen [] = return seen addNames seen (n:ns) | n `Set.member` seen = parseException (loc n) (DuplicateTopLevelAssignment (S.rawstr n)) | otherwise = addNames (Set.insert n seen) ns data SourceSpan = SourceSpan !Int !Int deriving (Eq, Show) data TopLevelChunk = TopLevelChunk { chunkSpan :: !SourceSpan , chunkInput :: String , chunkLine :: !Int } deriving (Eq, Show) data ScanMode = ScanString { scanQuote :: Char , scanTriple :: Bool , scanInterpolate :: Bool , scanInterpDepth :: Int } deriving (Eq, Show) data ChunkScanState = ChunkScanState { scanActiveStart :: Maybe Int , scanActiveInput :: Maybe String , scanActiveLine :: Maybe Int , scanDepth :: Int , scanModes :: [ScanMode] , scanAtLineStart :: Bool , scanLine :: Int , scanContinued :: Bool , scanBackslash :: Bool , scanPrev1 :: Maybe Char , scanPrev2 :: Maybe Char } deriving (Eq, Show) scanTopLevelChunks :: String -> Int -> (TopLevelChunk -> IO ()) -> IO (Either ChunkScanError ()) scanTopLevelChunks src start emit | start < 0 || start > length src = return (Left (ChunkScanError NoLoc "invalid module body offset")) | otherwise = go start (drop start src) initScan where initScan = ChunkScanState { scanActiveStart = Nothing , scanActiveInput = Nothing , scanActiveLine = Nothing , scanDepth = 0 , scanModes = [] , scanAtLineStart = start == 0 || charBefore start == Just '\n' , scanLine = startLine , scanContinued = False , scanBackslash = False , scanPrev1 = charBefore start , scanPrev2 = if start >= 2 then Just (src !! (start - 2)) else Nothing } charBefore 0 = Nothing charBefore n = Just (src !! (n - 1)) startLine = 1 + length (filter (== '\n') (take start src)) go i [] st = do emitOpenChunk i st return (Right ()) go i xs@(c:_) st | startsBoundary c st = openChunk i xs st >>= scanCode i xs | scanActiveStart st == Nothing && null (scanModes st) && scanDepth st == 0 && not (isTriviaStart c) = return (Left (ChunkScanError (Loc i (i + 1)) "non-top-level text before first chunk")) | otherwise = scanStep i xs st startsBoundary c st = scanAtLineStart st && not (scanContinued st) && scanDepth st == 0 && null (scanModes st) && not (isTriviaStart c) isTriviaStart c = c == '\n' || c == '\r' || c == ' ' || c == '\t' || c == '#' openChunk i xs st = do emitOpenChunk i st return st { scanActiveStart = Just i , scanActiveInput = Just xs , scanActiveLine = Just (scanLine st) } emitOpenChunk i st = case scanActiveStart st of Just s | s < i -> emit (TopLevelChunk (SourceSpan s i) (fromMaybe [] (scanActiveInput st)) (fromMaybe (scanLine st) (scanActiveLine st))) _ -> return () scanStep i xs st = case scanModes st of [] -> scanCode i xs st _ -> scanString i xs st scanCode i xs@(c:_) st | c == '#' = skipComment i xs st { scanBackslash = False } | Just (mode, qlen) <- stringStartMode xs st = let (_, rest, st') = consumeMany False qlen i xs st in go (i + qlen) rest st' { scanModes = mode : scanModes st', scanBackslash = False } | c `elem` "([{" = let (_, rest, st') = consumeMany True 1 i xs st { scanDepth = scanDepth st + 1 } in go (i + 1) rest st' | c `elem` ")]}" = let depth' = max 0 (scanDepth st - 1) (_, rest, st') = consumeMany True 1 i xs st { scanDepth = depth' } in go (i + 1) rest st' | otherwise = let (_, rest, st') = consumeMany True 1 i xs st in go (i + 1) rest st' scanString i [] st = go i [] st scanString i xs@(c:_) st = case scanModes st of [] -> scanCode i xs st mode:rest | scanInterpDepth mode == 0 -> scanStringText i xs mode rest st | otherwise -> scanInterpolation i xs mode rest st scanStringText i xs@(c:_) mode rest st | c == '\\' = let n = case xs of _:_:_ -> 2 _ -> 1 (_, xs', st') = consumeMany False n i xs st in go (i + n) xs' st' | scanInterpolate mode && startsWith "{{" xs = let (_, xs', st') = consumeMany False 2 i xs st in go (i + 2) xs' st' | scanInterpolate mode && startsWith "}}" xs = let (_, xs', st') = consumeMany False 2 i xs st in go (i + 2) xs' st' | scanInterpolate mode && c == '{' = let mode' = mode { scanInterpDepth = 1 } (_, xs', st') = consumeMany False 1 i xs st { scanModes = mode' : rest } in go (i + 1) xs' st' | Just n <- tripleInterpolatedQuoteText xs mode = let (_, xs', st') = consumeMany False n i xs st in go (i + n) xs' st' | closesString xs mode = let n = if scanTriple mode then 3 else 1 (_, xs', st') = consumeMany False n i xs st { scanModes = rest } in go (i + n) xs' st' | otherwise = let (_, xs', st') = consumeMany False 1 i xs st in go (i + 1) xs' st' scanInterpolation i xs@(c:_) mode rest st | c == '#' = skipComment i xs st | Just (nested, qlen) <- stringStartMode xs st = let (_, xs', st') = consumeMany False qlen i xs st in go (i + qlen) xs' st' { scanModes = nested : scanModes st' } | c == '{' = let mode' = mode { scanInterpDepth = scanInterpDepth mode + 1 } (_, xs', st') = consumeMany False 1 i xs st { scanModes = mode' : rest } in go (i + 1) xs' st' | c == '}' = let depth' = scanInterpDepth mode - 1 modes' = if depth' == 0 then mode { scanInterpDepth = 0 } : rest else mode { scanInterpDepth = depth' } : rest (_, xs', st') = consumeMany False 1 i xs st { scanModes = modes' } in go (i + 1) xs' st' | otherwise = let (_, xs', st') = consumeMany False 1 i xs st in go (i + 1) xs' st' stringStartMode xs@(q:_) st | q == '"' || q == '\'' = let triple = startsWith [q, q, q] xs raw = scanPrev1 st == Just 'r' || (scanPrev2 st == Just 'r' && scanPrev1 st == Just 'b') bytes = scanPrev1 st == Just 'b' || (scanPrev2 st == Just 'r' && scanPrev1 st == Just 'b') interpolate = not raw && not bytes qlen = if triple then 3 else 1 in Just (ScanString q triple interpolate 0, qlen) | otherwise = Nothing stringStartMode [] _ = Nothing closesString xs mode | scanTriple mode = startsWith (replicate 3 (scanQuote mode)) xs | otherwise = case xs of c:_ -> c == scanQuote mode [] -> False tripleInterpolatedQuoteText xs mode | scanTriple mode && scanInterpolate mode = case quoteRunLength (scanQuote mode) xs of 4 -> Just 1 5 -> Just 2 _ -> Nothing | otherwise = Nothing quoteRunLength q = length . takeWhile (== q) startsWith prefix xs = prefix `isPrefixOf` xs skipComment i [] st = go i [] st skipComment i xs@(c:_) st | c == '\n' = let (_, xs', st') = consumeMany False 1 i xs st in go (i + 1) xs' st' | otherwise = let (_, xs', st') = consumeMany False 1 i xs st in skipComment (i + 1) xs' st' consumeMany _ 0 i xs st = (i, xs, st) consumeMany track n i (c:cs) st = let st' = advance track c st in consumeMany track (n - 1) (i + 1) cs st' consumeMany _ _ i [] st = (i, [], st) advance track c st = let stPrev = st { scanPrev2 = scanPrev1 st, scanPrev1 = Just c } in if c == '\n' then stPrev { scanAtLineStart = True , scanLine = scanLine st + 1 , scanContinued = scanBackslash st , scanBackslash = False } else stPrev { scanAtLineStart = False , scanContinued = False , scanBackslash = if track && c /= ' ' && c /= '\t' && c /= '\r' then c == '\\' else scanBackslash st } parseTopLevelChunk :: String -> String -> TopLevelChunk -> IO (Either Control.Exception.SomeException [S.Stmt]) parseTopLevelChunk fileName fileContent chunk = do parsed <- tryNonAsync $ Control.Exception.evaluate $ runParser (St.evalStateT (top_chunk_input fileName chunk) initState) fileName fileContent case parsed of Left err -> return (Left err) Right (Left bundle) -> return (Left (Control.Exception.toException bundle)) Right (Right stmts) -> do forced <- tryNonAsync (Control.Exception.evaluate (rnf stmts)) case forced of Left err -> return (Left err) Right () -> return (Right stmts) where tryNonAsync action = do result <- Control.Exception.try action case result of Left err -> case Control.Exception.fromException err :: Maybe Control.Exception.SomeAsyncException of Just _ -> Control.Exception.throwIO err Nothing -> return (Left err) Right ok -> return (Right ok) data ChunkProgressEvent = ChunkProgressDone Int | ChunkProgressStop data ChunkProgress = ChunkProgress (Chan ChunkProgressEvent) (Async ()) parseTopLevelChunks :: String -> String -> Int -> Maybe (Int -> Int -> IO ()) -> IO [[S.Stmt]] parseTopLevelChunks fileName fileContent bodyStart mReportProgress = do ncap <- getNumCapabilities let nworkers = max 1 ncap withChunkProgress mReportProgress (length fileContent) bodyStart $ \progress -> do let window = max 1 (10 * nworkers) slots <- newQSem window workQ <- newChan resultsRef <- newIORef [] workers <- replicateM nworkers (async (worker slots workQ progress)) let stopWorkers = replicateM_ nworkers (writeChan workQ Nothing) >> mapM_ wait workers run = do scanResult <- scanTopLevelChunks fileContent bodyStart $ \chunk -> do waitQSem slots result <- newEmptyMVar modifyIORef' resultsRef (result :) writeChan workQ (Just (chunk, result)) case scanResult of Left err -> Control.Exception.throwIO err Right () -> do stopWorkers finishChunkProgress progress results <- mapM readMVar . reverse =<< readIORef resultsRef collectParsedChunks results run `Control.Exception.finally` mapM_ cancel workers where worker slots workQ progress = do job <- readChan workQ case job of Nothing -> return () Just (chunk, result) -> do Control.Exception.finally (runWorker chunk result progress) (signalQSem slots) worker slots workQ progress runWorker chunk result progress = Control.Exception.mask $ \restore -> do parsed <- Control.Exception.try (restore (parseTopLevelChunk fileName fileContent chunk)) case parsed of Left err -> do putMVar result (Left err) case Control.Exception.fromException err :: Maybe Control.Exception.SomeAsyncException of Just _ -> Control.Exception.throwIO err Nothing -> return () Right chunkResult -> do putMVar result chunkResult reportChunkDone progress chunk collectParsedChunks :: [Either Control.Exception.SomeException [S.Stmt]] -> IO [[S.Stmt]] collectParsedChunks results = case [ err | Left err <- results ] of err:_ -> Control.Exception.throwIO err [] -> return [ stmts | Right stmts <- results ] withChunkProgress :: Maybe (Int -> Int -> IO ()) -> Int -> Int -> (Maybe ChunkProgress -> IO a) -> IO a withChunkProgress mReportProgress total done0 action = do progress <- startChunkProgress mReportProgress total done0 action progress `Control.Exception.finally` cancelChunkProgress progress startChunkProgress :: Maybe (Int -> Int -> IO ()) -> Int -> Int -> IO (Maybe ChunkProgress) startChunkProgress Nothing _ _ = return Nothing startChunkProgress (Just reportProgress) total done0 = do progressQ <- newChan progressA <- async $ do lastPercent <- emit done0 0 loop done0 lastPercent progressQ return (Just (ChunkProgress progressQ progressA)) where loop done lastPercent progressQ = do event <- readChan progressQ case event of ChunkProgressDone n -> do let done' = min total (done + n) lastPercent' <- emit done' lastPercent loop done' lastPercent' progressQ ChunkProgressStop -> return () emit done lastPercent = do let completed | total <= 1 = 0 | otherwise = max 0 (min (total - 1) done) percent | total <= 0 = 100 | otherwise = max 0 (min 99 ((completed * 100) `div` total)) if percent > lastPercent then reportProgress completed total >> return percent else return lastPercent finishChunkProgress :: Maybe ChunkProgress -> IO () finishChunkProgress Nothing = return () finishChunkProgress (Just (ChunkProgress progressQ progressA)) = writeChan progressQ ChunkProgressStop >> wait progressA cancelChunkProgress :: Maybe ChunkProgress -> IO () cancelChunkProgress Nothing = return () cancelChunkProgress (Just (ChunkProgress _ progressA)) = cancel progressA reportChunkDone :: Maybe ChunkProgress -> TopLevelChunk -> IO () reportChunkDone Nothing _ = return () reportChunkDone (Just (ChunkProgress progressQ _)) chunk = writeChan progressQ (ChunkProgressDone (topLevelChunkLength chunk)) topLevelChunkLength :: TopLevelChunk -> Int topLevelChunkLength chunk = let SourceSpan start end = chunkSpan chunk in end - start top_chunk_input :: String -> TopLevelChunk -> Parser [S.Stmt] top_chunk_input fileName chunk = do state <- getParserState let SourceSpan start end = chunkSpan chunk input = chunkInput chunk startPosState = (statePosState state) { pstateSourcePos = SourcePos fileName (mkPos (chunkLine chunk)) (mkPos 1) , pstateInput = input , pstateOffset = start , pstateLinePrefix = "" } let chunkState = state { stateInput = input , stateOffset = start , statePosState = startPosState } setParserState chunkState ss <- withCtx TOP (L.nonIndented sc2 top_chunk_stmt) sc2 off <- getOffset if off == end then return ss else fail ("chunk parser stopped at offset " ++ show off ++ ", expected " ++ show end) regroupTopDecls :: S.Suite -> S.Suite regroupTopDecls = go [] where go [] [] = [] go ds [] = flush ds go ds (S.Decl _ ds' : rest) = go (ds ++ ds') rest go ds (stmt : rest) = flush ds ++ stmt : go [] rest flush [] = [] flush ds = [ S.Decl (loc group) group | group <- Names.splitDeclGroup ds ] -- Row parsers ---------------------------------------------------------------------- -- non-empty positional row without trailing comma posItems:: (a -> b -> b) -> (c -> b) -> b -> Parser a -> Parser c -> Parser b posItems fCons fStar fNil item staritem = fStar <$> (star *> staritem) <|> do e <- item es <- many (try (comma *> item)) mbe <- optional (try (comma *> star *> staritem)) let tail = maybe fNil fStar mbe return (foldr fCons tail (e:es)) --non-empty kwd row with optional trailing comma kwdItems:: (a -> b -> b) -> (c -> b) -> b -> Parser a -> Parser c -> Parser b kwdItems fCons fStar fNil item staritem = fStar <$> (starstar *> staritem <* optional comma) <|> do b <- item bs <- many (try (comma *> item)) mbe <- optional (try (comma *> optional ((starstar *> staritem) <* optional comma ))) let tail = maybe fNil (maybe fNil fStar) mbe return (foldr fCons tail (b:bs)) -- parameter list consisting of posItems followed by kwdItems -- Unfortunately, the parser below does not make use of posItems funItems :: (a1 -> t1 -> t1) -> (a -> t1) -> t1 -> Parser a1 -> Parser a -> Parser t -> t -> Parser (Either (t1,t) a1) funItems posCons posStar posNil positem posstaritem kwdItems kwdNil = do i <- singleStar *> posstaritem mbc <- optional comma case mbc of Just _ -> do k <- kwdItems return (Left (posStar i, k)) <|> return (Left (posStar i, kwdNil)) Nothing -> return (Left (posStar i, kwdNil)) <|> try (do k <- kwdItems; return (Left (posNil, k))) <|> do i <- positem mbc <- optional comma case mbc of Just _ -> do r <- funItems posCons posStar posNil positem posstaritem kwdItems kwdNil case r of Left (p,k) -> return (Left (posCons i p, k)) Right p -> return (Left (posCons i (posCons p posNil),kwdNil)) <|> return (Left (posCons i posNil, kwdNil)) Nothing -> return (Right i) <|> do optional comma; return (Left (posNil, kwdNil)) tuple_or_single posItems headItems singleHead tup = do pa <- posItems mbc <- optional comma return (f pa mbc) where f pa mbc | singleHead pa = maybe (headItems pa) (const (tup pa)) mbc | otherwise = tup pa -- Patterns ------------------------------------------------------------------------------------ pospat :: Parser S.PosPat pospat = posItems S.PosPat S.PosPatStar S.PosPatNil apat apat kwdpat :: Parser S.KwdPat kwdpat = kwdItems (uncurry S.KwdPat) S.KwdPatStar S.KwdPatNil kpat apat where kpat = do v <- name equals p <- apat return (v,p) gen_pattern = do r <- funItems S.PosPat S.PosPatStar S.PosPatNil apat apat (fail "No kwdpat") S.KwdPatNil case r of Left (p,k) -> return $ S.PTuple NoLoc p k Right p -> return p gen_pattern1 = do r <- funItems S.PosPat S.PosPatStar S.PosPatNil apat apat kwdpat S.KwdPatNil case r of Left (p,k) -> return $ S.PTuple NoLoc p k Right p -> return p pelems ::Parser ([S.Pattern], Maybe S.Pattern) pelems = do p <- apat ps <- many (try (comma *> apat)) mbp <- optional (comma *> star *> apat) return (p:ps, mbp) apat :: Parser S.Pattern apat = addLoc ( (try $ rword "_" *> (S.PWild NoLoc <$> optannot)) <|> (try $ S.PVar NoLoc <$> name <*> optannot) <|> ((try . parens) $ return $ S.PParen NoLoc (S.PTuple NoLoc S.PosPatNil S.KwdPatNil)) <|> ((try . parens) $ S.PParen NoLoc <$> gen_pattern1) <|> (brackets $ (maybe (S.PList NoLoc [] Nothing) (\(ps,mbp)-> S.PList NoLoc ps mbp)) <$> optional pelems) ) where -- datapat = S.PData NoLoc <$> escname <*> many (brackets exprlist) optannot = try (Just <$> (colon *> ttype)) <|> return Nothing -- Targets ------------------------------------------------------------------------------------- target :: Parser S.Target target = try $ do tmp <- atom_expr case tmp of S.Var _ (S.NoQ n) -> return tmp S.Dot _ e n -> return tmp S.Index _ e ix -> return tmp S.Slice _ e sl -> return tmp _ -> locate (loc tmp) >> fail ("illegal target: " ++ show tmp) ------------------------------------------------------------------------------------------------ -- Statements ---------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------ stmt, simple_stmt :: Parser [S.Stmt] stmt = ((:[]) <$> compound_stmt) <|> try ((:[]) <$> (signature <* newline1)) <|> decl_group <|> simple_stmt "statement" top_chunk_stmt :: Parser [S.Stmt] top_chunk_stmt = ((:[]) <$> compound_stmt) <|> try ((:[]) <$> (signature <* newline1)) <|> ((\d -> [S.Decl (loc d) [d]]) <$> decl) <|> simple_stmt "statement" simple_stmt = (small_stmt `sepEndBy1` semicolon) <* newline1 "simple statement" --- Small statements --------------------------------------------------------------------------------- small_stmt :: Parser S.Stmt small_stmt = del_stmt <|> pass_stmt <|> flow_stmt <|> assert_stmt <|> var_stmt <|> after_stmt <|> expr_stmt expr_stmt :: Parser S.Stmt expr_stmt = addLoc $ do o <- getOffset S.Assign NoLoc <$> some (try assign) <*> rhs -- Single variable lhs matches here <|> (do t <- target ((S.AugAssign NoLoc t <$> augassign <*> rhs) <* assertNotData (Loc o o) "augmented assignment") <|> (S.MutAssign NoLoc t <$> (equals *> rhs))) -- and not here <|> (((S.Expr NoLoc <$> rhs) <* assertNotData (Loc o o) "call") "expression statement") where augassign :: Parser S.Aug augassign = augops where augops = S.PlusA <$ symbol "+=" <|> S.MinusA <$ symbol "-=" <|> S.MultA <$ symbol "*=" <|> S.MMultA <$ symbol "@=" <|> S.DivA <$ symbol "/=" <|> S.ModA <$ symbol "%=" <|> S.BAndA <$ symbol "&=" <|> S.BOrA <$ symbol "|=" <|> S.BXorA <$ symbol "^=" <|> S.ShiftLA <$ symbol "<<=" <|> S.ShiftRA <$ symbol ">>=" <|> S.PowA <$ symbol "**=" <|> S.EuDivA <$ symbol "//=" assign :: Parser S.Pattern assign = gen_pattern <* equals rhs :: Parser S.Expr rhs = yield_expr <|> exprlist trysome p = do x <- p; rest [x] where rest xs = (try p >>= \x -> rest (x:xs)) <|> return (reverse xs) after_stmt :: Parser S.Stmt after_stmt = addLoc $ do l <- rwordLoc "after" assertDefAct l "after" e <- expr colon e' <- expr return $ S.After NoLoc e e' var_stmt :: Parser S.Stmt var_stmt = addLoc $ do l <- rwordLoc "var" assertActBody l "var" S.VarAssign NoLoc <$> trysome assign <*> rhs del_stmt = addLoc $ do l <- rwordLoc "del" assertNotData l "del" S.Delete NoLoc <$> target pass_stmt = S.Pass <$> rwordLoc "pass" flow_stmt = break_stmt <|> continue_stmt <|> return_stmt <|> raise_stmt <|> yield_stmt break_stmt = do l <- rwordLoc "break" assertLoop l "break" return (S.Break l) continue_stmt = do l <- rwordLoc "continue" assertLoop l "continue" return (S.Continue l) return_stmt = addLoc $ do -- the notFollowedBy colon here is to avoid confusion with data_stmt return case l <- rwordLoc "return" <* notFollowedBy colon assertDef l "return" S.Return NoLoc <$> optional exprlist yield_stmt = yield_expr >>= \e -> return $ S.Expr (S.eloc e) e raise_stmt = addLoc $ do rword "raise" S.Raise NoLoc <$> expr import_stmt = import_name <|> import_from "import statement" where import_name = addLoc $ do rword "import" S.Import NoLoc <$> module_item `sepBy1` comma module_item = do dn <- module_name S.ModuleItem dn <$> optional (rword "as" *> name) import_from = addLoc $ do rword "from" mr <- import_module rword "import" is <- import_items case is of [] -> return $ S.FromImportAll NoLoc mr _ -> return $ S.FromImport NoLoc mr is import_module = do ds <- many dot mbn <- optional module_name return $ S.ModRef (length ds, mbn) import_items = ([] <$ star) -- Note: [] means all... <|> parens import_as_names <|> import_as_names import_as_name = S.ImportItem <$> name <*> optional (rword "as" *> name) import_as_names = (:) <$> import_as_name <*> commaList import_as_name -- global_stmt: 'global' NAME (',' NAME)* -- nonlocal_stmt: 'nonlocal' NAME (',' NAME)* -- assert_stmt: 'assert' expr [',' expr] assert_stmt = addLoc (rword "assert" >> S.Assert NoLoc <$> expr <*> optional (comma *> expr)) signature :: Parser S.Stmt signature = addLoc (do dec <- decorator True; (ns,t) <- tsig; return $ S.Signature NoLoc ns t dec) where tsig = do v <- name vs <- commaList name colon t <- tschema return (v:vs,t) -- Declaration groups ------------------------------------------------------------------ decl_group :: Parser [S.Stmt] decl_group = do p <- L.indentLevel g <- some (atPos p decl) return [ S.Decl (loc ds) ds | ds <- Names.splitDeclGroup g ] decl :: Parser S.Decl decl = funcdef <|> classdef <|> protodef <|> extdef <|> actordef decorator :: Bool -> Parser S.Deco decorator sig = do p <- L.indentLevel d <- decoration p1 <- L.indentLevel if (p /= p1) then fail "Decorated statement must have same indentation as decoration" else return d where property = do l <- rwordLoc "@property" assertClass l "@property" newline1 return S.Property static = do l <-rwordLoc "@staticmethod" <|> rwordLoc "@static" assertDecl l "@static" newline1 return S.Static decoration = (if sig then property <|> static else static) <|> return S.NoDec funcdef :: Parser S.Decl funcdef = addLoc $ do (p,(deco,fx,l)) <- withPos (((,,) <$> decorator False <*> optional effect <*> rwordLoc "def")) assertNotData l "def" n <- name q <- optbinds (ppar,kpar) <- params t <- optional (arrow *> ttype) (ss, docstring) <- suiteWithDocstring DEF p return $ S.Def NoLoc n q ppar kpar t ss deco (maybe S.tWild id fx) docstring params :: Parser (S.PosPar, S.KwdPar) params = try ((\k ->(S.PosNIL,k)) <$> parens (kwdpar True)) <|> parens (funpars True) binds :: Parser S.QBinds binds = brackets (do b <- qbind; bs <- many (comma *> qbind); return (b:bs)) optbinds :: Parser S.QBinds optbinds = binds <|> return [] actordef = addLoc $ do (s,l) <- withPos (rwordLoc "actor") assertTop l "actor" nm <- name "actor name" q <- optbinds (ppar,kpar) <- params (ss, docstring) <- suiteWithDocstring ACTOR s return $ S.Actor NoLoc nm q ppar kpar ss docstring -- classdef: 'class' NAME ['(' [arglist] ')'] ':' suite -- protodef: 'class' NAME ['(' [arglist] ')'] ':' suite -- extdef: 'class' NAME ['(' [arglist] ')'] ':' suite classdef = classdefGen "class" name CLASS S.Class protodef = classdefGen "protocol" name PROTO S.Protocol --extdef = classdefGen "extension" qual_name EXT S.Extension classdefGen k pname ctx con = addLoc $ do (s,l) <- withPos (rwordLoc k) assertTop l k nm <- pname q <- optbinds cs <- optbounds (ss, docstring) <- suiteWithDocstring ctx s return $ con NoLoc nm q cs ss docstring extdef = addLoc $ do (s,l) <- withPos (rwordLoc "extension") assertTop l "extension" (q,c) <- try head1 <|> try head2 <|> head3 cs <- optbounds (ss, docstring) <- suiteWithDocstring EXT s return $ S.Extension NoLoc q c cs ss docstring where head1 = do q <- binds fatarrow c <- tcon return (q, c) head2 = do c <- tcon return ([], c) head3 = do n <- qual_name q <- binds return (q, S.TC n [ S.tVar v | S.QBind v _ <- q ]) -- Compound statements ------------------------------------------------------------------------- compound_stmt :: Parser S.Stmt compound_stmt = if_stmt <|> while_stmt <|> for_stmt <|> try_stmt <|> with_stmt -- <|> data_stmt else_part p = atPos p (rword "else" *> suite SEQ p) if_stmt = addLoc $ do (p,_) <- withPos (rword "if") b <- branch p bs <- many (atPos p (rword "elif" *> branch p)) S.If NoLoc (b:bs) . maybe [] id <$> optional (else_part p) branch p = S.Branch <$> expr <*> suite IF p while_stmt = addLoc $ do (p,l) <- withPos (rwordLoc "while") assertNotDecl l "while" e <- expr ss1 <- suite LOOP p S.While NoLoc e ss1 . maybe [] id <$> optional (else_part p) for_stmt = addLoc $ do (p,l) <- withPos (rwordLoc "for") assertNotDecl l "for" pat <- gen_pattern rword "in" e <- exprlist ss <- suite LOOP p S.For NoLoc pat e ss . maybe [] id <$> optional (else_part p) except :: Parser S.Except except = addLoc $ do rword "except" mbx <- optional ((,) <$> qual_name <*> optional (rword "as" *> name)) return (maybe (S.ExceptAll NoLoc) (\(x,mbn) -> maybe (S.Except NoLoc x) (S.ExceptAs NoLoc x) mbn) mbx) try_stmt = addLoc $ do (p,l) <- withPos (rwordLoc "try") assertNotData l "try" assertNotDecl l "try" ss <- suite SEQ p do hs <- some (handler p) mbe <- optional (else_part p) S.Try NoLoc ss hs (maybe [] id mbe) . maybe [] id <$> optional (finally_part p) <|> S.Try NoLoc ss [] [] <$> finally_part p where handler :: Pos -> Parser S.Handler handler p = atPos p $ do exc <- except S.Handler exc <$> suite SEQ p finally_part p = atPos p $ do rword "finally" suite SEQ p with_stmt = addLoc $ do (s,l) <- withPos (rwordLoc "with") assertNotData l "with" assertNotDecl l "with" S.With NoLoc <$> (with_item `sepBy1` comma) <*> suite SEQ s where with_item = S.WithItem <$> expr <*> optional (rword "as" *> gen_pattern) data_stmt = addLoc $ do (s,pat) <- withPos gen_pattern S.Data NoLoc (Just pat) <$> suite DATA s <|> do (s,l) <- withPos (rwordLoc "return") assertDef l "data" S.Data NoLoc Nothing <$> suite DATA s suiteWithDocstring :: CTX -> Pos -> Parser (S.Suite, Maybe String) suiteWithDocstring c p = do withCtx c colon withCtx c (indentSuiteWithDocstring p <|> (simple_stmt_with_docstring <* reportParseProgress)) suite :: CTX -> Pos -> Parser S.Suite suite c p = do o <- getOffset withCtx c colon stmts <- withCtx c (indentSuite p <|> (simple_stmt <* reportParseProgress)) return stmts where indentSuite p = do newline1 p1 <- L.indentGuard sc1 GT p concat <$> some (stmtAtIndent p1) indentSuiteWithDocstring :: Pos -> Parser (S.Suite, Maybe String) indentSuiteWithDocstring p = do newline1 p1 <- L.indentGuard sc1 GT p (firstStmts, mbDoc) <- stmtAtIndentWithDocstring p1 rest <- concat <$> many (stmtAtIndent p1) return (firstStmts ++ rest, mbDoc) stmtAtIndentWithDocstring :: Pos -> Parser (S.Suite, Maybe String) stmtAtIndentWithDocstring p1 = do p2 <- L.indentLevel case compare p1 p2 of LT -> do o <- getOffset Control.Exception.throw $ IndentationError (Loc o o) EQ -> stmtWithDocstring <* reportParseProgress GT -> L.incorrectIndent GT p2 p1 stmtAtIndent :: Pos -> Parser S.Suite stmtAtIndent p1 = do p2 <- L.indentLevel case compare p1 p2 of LT -> do o <- getOffset Control.Exception.throw $ IndentationError (Loc o o) EQ -> stmt <* reportParseProgress GT -> L.incorrectIndent GT p2 p1 stmtWithDocstring :: Parser (S.Suite, Maybe String) stmtWithDocstring = ( ((\s -> ([s], Nothing)) <$> compound_stmt) <|> try ((\s -> ([s], Nothing)) <$> (signature <* newline1)) <|> ((\s -> (s, Nothing)) <$> decl_group) <|> simple_stmt_with_docstring ) "statement" simple_stmt_with_docstring :: Parser (S.Suite, Maybe String) simple_stmt_with_docstring = ( do (mbDoc, firstStmts) <- try docstringSmallStmt <|> ((\s -> (Nothing, [s])) <$> small_stmt) rest <- many (try (semicolon *> small_stmt)) _ <- optional semicolon newline1 return (firstStmts ++ rest, mbDoc) ) "simple statement" docstringSmallStmt :: Parser (Maybe String, S.Suite) docstringSmallStmt = do S.Strings _ ss <- addLoc docstringLiteral _ <- lookAhead (void (char ';') <|> void eol <|> eof) return (Just (unescapeString (concat ss)), []) unescapeString :: String -> String unescapeString [] = [] unescapeString ('\\':'n':xs) = '\n' : unescapeString xs unescapeString ('\\':'t':xs) = '\t' : unescapeString xs unescapeString ('\\':'r':xs) = '\r' : unescapeString xs unescapeString ('\\':'\\':xs) = '\\' : unescapeString xs unescapeString ('\\':'"':xs) = '"' : unescapeString xs unescapeString ('\\':'\'':xs) = '\'' : unescapeString xs unescapeString (x:xs) = x : unescapeString xs ------------------------------------------------------------------------------------------------ --- Expressions ---------------------------------------------------------------- ------------------------------------------------------------------------------------------------ -- The most general form of expression expr :: Parser S.Expr expr = lambdef <|> do e1 <- or_expr mbp <- optional if_part case mbp of Nothing -> return e1 Just (c,e2) -> return $ S.Cond (S.eloc e1) e1 c e2 where if_part = (,) <$> (rword "if" *> or_expr) <*> (rword "else" *> expr) "if clause" -- Non-empty list of comma-separated expressions. -- If more than one expr, build a tuple. -- if only one, leave as it is unless there is a trailing comma when we build a one-element tuple. exprlist :: Parser S.Expr exprlist = addLoc $ tuple_or_single posarg S.posArgHead S.singlePosArg (\p -> S.Tuple NoLoc p S.KwdNil) expr_nocond = or_expr <|> lambdef_nocond lambdefGen t = addLoc $ do fx <- optional effect rword "lambda" (ppar,kpar) <- funpars False colon S.Lambda NoLoc ppar kpar <$> t <*> return (maybe S.tWild id fx) lambdef = try $ lambdefGen expr lambdef_nocond = try $ lambdefGen expr_nocond -- Logical expressions ------------------------------------------------------------------ -- The intermediate levels between or_expr and comparison, i.e. expressions involving and, or and not, -- are handled by makeExprParser from Text.Megaparsec.Expr 6.4.0, here Text_Megaparsec_Expr -- Three auxiliary functions used in building tables for makeExprParser binary name op = InfixL $ do name return $ \e1 e2 -> S.BinOp (S.eloc e1 `upto` S.eloc e2) e1 op e2 unop name op = do (lop, _) <- withLoc name return $ \e -> case (op, e) of (S.UMinus, i@S.Int{}) -> let el = lop `upto` S.eloc i in i{ S.eloc = el , S.ival = negate (S.ival i) , S.lexeme = '-' : S.lexeme i } -- TODO: should loc cover operator + operand here?? _ -> S.UnOp (S.eloc e) op e prefix name op = Prefix (unop name op) or_expr = makeExprParser comparison btable btable :: [[Operator Parser S.Expr]] btable = [ [ prefix (rwordLoc "not") S.Not] , [ binary (rwordLoc "and") S.And] , [ binary (rwordLoc "or") S.Or] ] comparison = addLoc (do e <- arithexpr ps <- many (do op <- comp_op S.OpArg op <$> arithexpr) case ps of [] -> return e _ -> return $ S.CompOp NoLoc e ps) "relational expression" where comp_op = S.Lt <$ opPref "<" <|> S.Gt <$ opPref ">" <|> S.Eq <$ symbol "==" <|> S.GE <$ symbol ">=" <|> S.LE <$ symbol "<=" <|> S.LtGt <$ symbol "<>" <|> S.NEq <$ symbol "!=" <|> S.In <$ symbol "in" <|> S.NotIn <$ (symbol "not" *> symbol "in") <|> S.IsNot <$ try (symbol "is" *> symbol "not") <|> S.Is <$ (symbol "is") "operator" star_expr :: Parser S.Elem star_expr = S.Star <$> (star *> arithexpr) -- Arithmetic expressions ---------------------------------------------------------- -- Again, everything between arithexpr and factor is handled by makeExprParser arithexpr :: Parser S.Expr arithexpr = makeExprParser factor table table :: [[Operator Parser S.Expr]] table = [ [ binary (opPref "*") S.Mult, binary (opPref "/") S.Div, binary (opPref "@") S.MMult, binary (opPref "//") S.EuDiv, binary (opPref "%") S.Mod] , [ binary (opPref "+") S.Plus, binary (opPref "-") S.Minus] , [ binary (opPref "<<") S.ShiftL, binary (opPref ">>") S.ShiftR] , [ binary (opPref "&") S.BAnd] , [ binary (opPref "^") S.BXor] , [ binary (opPref "|") S.BOr] ] factor :: Parser S.Expr factor = (((unop (opPref "+") S.UPlus <|> unop (opPref "-") S.UMinus <|> unop (opPref "~") S.BNot) "unary operator") <*> factor) <|> power power = addLoc $ do ae <- atom_expr mbe <- optional expo return (maybe ae (S.BinOp NoLoc ae S.Pow) mbe) where expo = do opPref "**" factor "operator" isinstance = addLoc $ do rword "isinstance" (e,c) <- parens ((,) <$> expr <* comma <*> qual_name) return $ S.IsInstance NoLoc e c -- recurring pattern below commaList p = many (try (comma *> p)) <* optional comma data ChainKind = COpt | CCall | COther deriving Eq atom_expr = do await <- optional $ withLoc $ rword "await" *> return (S.Await NoLoc) async <- optional $ withLoc $ rword "async" *> return (S.Async NoLoc) a <- atom ts <- many trailer let (outerOpt,e) = foldapp async a ts e' = maybe e (app e) await return $ if outerOpt then wrapOptChain e' else e' "atomic expression" where app a (l,f) = (f a){S.eloc = exprLoc a `upto` l} appChain a (l,_,f) = app a (l,f) exprLoc S.OptChain{S.exp1=e} = exprLoc e exprLoc e = S.eloc e wrapOptChain e = S.OptChain (loc e) e foldapp async e = finish . go async False False e where closeChain True e = wrapOptChain e closeChain False e = e go async preAsyncOpt outerOpt e [] = (async,preAsyncOpt,outerOpt,e) go (Just a) preAsyncOpt outerOpt e (t@(_,kind,_):ts) | kind == CCall = let e' = appChain (app (closeChain preAsyncOpt e) a) t in go Nothing False outerOpt e' ts go async preAsyncOpt outerOpt e (t@(_,kind,_):ts) | kind == COpt = case async of Just _ -> let e' = appChain (closeChain preAsyncOpt e) t in go async True outerOpt e' ts Nothing -> let e' = appChain (closeChain outerOpt e) t in go async preAsyncOpt True e' ts go async preAsyncOpt outerOpt e (t:ts) = go async preAsyncOpt outerOpt (appChain e t) ts finish (Just a,preAsyncOpt,outerOpt,e) = (outerOpt, app (closeChain preAsyncOpt e) a) finish (Nothing,_,outerOpt,e) = (outerOpt,e) atom :: Parser S.Expr atom = addLoc (try strings <|> ((try . parens) $ return $ S.Paren NoLoc (S.Tuple NoLoc S.PosNil S.KwdNil)) <|> ((try . parens) $ S.Paren NoLoc <$> yield_expr) <|> (parens $ S.Paren NoLoc <$> expr_or_tuplemaker) <|> (brackets $ do mbe <- optional listmaker return $ maybe (S.List NoLoc []) id mbe) <|> (braces $ do mbe <- optional dictorsetmaker return $ maybe (S.Dict NoLoc []) id mbe) <|> var <|> isinstance <|> (try ((\f -> S.Imaginary NoLoc f (show f ++ "j")) <$> lexeme (L.float <* string "j"))) <|> (try ((\f -> S.Float NoLoc f (show f)) <$> lexeme L.float)) <|> (\i -> S.Int NoLoc i ("0o"++showOct i "")) <$> (string "0o" *> lexeme L.octal) <|> (\i -> S.Int NoLoc i ("0x"++showHex i "")) <$> (string "0x" *> lexeme L.hexadecimal) <|> (\i -> S.Int NoLoc i (show i)) <$> (lexeme L.decimal) <|> (S.Ellipsis <$> rwordLoc "...") <|> (S.None <$> rwordLoc "None") <|> (S.NotImplemented <$> rwordLoc "NotImplemented") <|> (\l -> S.Bool l True) <$> rwordLoc "True" <|> (\l -> S.Bool l False) <$> rwordLoc "False") expr_or_tuplemaker = do r <- funItems S.PosArg S.PosStar S.PosNil expr expr kwdarg S.KwdNil case r of Left (p,k) -> return (S.Tuple NoLoc p k) Right e -> return e -- common pattern in functions building lists, sets and dictionaries maker constr constrComp p = do (l,a) <- withLoc p (constrComp l a <$> comp_for) <|> ((\as -> (constr l (a:as))) <$> commaList p) -- exprlist_comp version used in brackets, building a list listmaker = maker S.List S.ListComp elem where elem = (S.Elem <$> expr) <|> star_expr dictorsetmaker :: Parser S.Expr dictorsetmaker = (try $ maker S.Dict S.DictComp assoc) <|> maker S.Set S.SetComp elem where elem = (S.Elem <$> expr) <|> star_expr assoc = (S.Assoc <$> expr) <*> (colon *> expr) <|> (S.StarStar <$> (starstar *> arithexpr)) var = do nm <- name return (S.Var (S.nloc nm) (S.NoQ nm)) trailer :: Parser (SrcLoc,ChainKind,S.Expr -> S.Expr) trailer = do (l,(kind,f)) <- withLoc ( (do (l,_) <- withLoc(symbol "?") return (COpt,\a -> S.Opt (loc a `upto` l) a True)) <|> (do (l,_) <- withLoc(opPref "!") return (COpt,\a -> S.Opt (loc a `upto` l) a False)) <|> (do f <- brackets sliceOrIndex return (COther,f)) <|> (do (ps,ks) <- parens funargs return (CCall,\a -> S.Call (loc a `upto` loc ks) a ps ks)) <|> (do dot f <- try intdot <|> iddot <|> strdot return (COther,f)) "call arguments, slice/index expression") return (l,kind,f) where iddot = do mb <- optional (opPref "~") nm <- name return (\a -> maybe (S.Dot (loc a `upto` loc nm) a nm) (const $ S.Rest (loc a `upto` loc nm) a nm) mb) intdot = do mb <- optional (opPref "~") (l,i) <- withLoc $ lexeme L.decimal return (\a -> maybe (S.DotI (loc a `upto` l) a i) (const $ S.RestI (loc a `upto` l) a i) mb) strdot = do (l,ss) <- withLoc plainstrLiteral return (\a -> S.Dot (loc a `upto` l) a (S.Name l (head ss))) -- Parse slice or index: try slice first since it can start with expr sliceOrIndex = try sliceParser <|> indexParser -- Parse slice notation: [start]:[stop][:[step]] sliceParser = do start <- optional expr colon stop <- optional expr step <- optional (colon *> optional expr) return (\a -> S.Slice NoLoc a (S.Sliz NoLoc start stop (join step))) -- Parse index: single expr or comma-separated exprs (tuple) indexParser = do es <- expr `sepBy1` comma return (\a -> S.Index NoLoc a (if length es == 1 then head es else S.eTuple es)) comp_iter, comp_for, comp_if :: Parser S.Comp comp_iter = comp_for <|> comp_if comp_for = addLoc (do rword "for" pat <- gen_pattern rword "in" e <- or_expr S.CompFor NoLoc pat e . maybe S.NoComp id <$> optional comp_iter) comp_if = addLoc $ do rword "if" e <- expr_nocond S.CompIf NoLoc e . maybe S.NoComp id <$> optional comp_iter yield_expr = addLoc $ do l <- rwordLoc "yield" assertDef l "yield" (S.YieldFrom NoLoc <$> (rword "from" *> expr) <|> S.Yield NoLoc <$> optional exprlist) --- Params --------------------------------------------------------------------- parm :: Bool -> Parser (S.Name, Maybe S.Type, Maybe S.Expr) parm ann = do n <- name mbt <- if ann then optional (colon *> ttype) else return Nothing mbe <- optional (equals *> expr) return (n, mbt, mbe) pstar :: Bool -> Parser S.Type -> Parser (S.Name, Maybe S.Type) pstar ann startype = do n <- name mbt <- if ann then optional (colon *> startype) else return Nothing return (n, mbt) pstartype :: Parser S.Type pstartype = parens (S.TTuple NoLoc <$> (posrow <|> return S.posNil) <*> return S.kwdNil <* optional comma) kstartype :: Parser S.Type kstartype = parens (S.TTuple NoLoc S.posNil <$> (kwdrow <|> return S.kwdNil) <* optional comma) pospar :: Bool -> Parser S.PosPar pospar ann = posItems (\(n,t,e) par -> S.PosPar n t e par) (uncurry S.PosSTAR) S.PosNIL (parm ann) (pstar ann pstartype) kwdpar :: Bool -> Parser S.KwdPar kwdpar ann = kwdItems (\(n,t,e) par -> S.KwdPar n t e par) (uncurry S.KwdSTAR) S.KwdNIL (parm ann) (pstar ann kstartype) funpars :: Bool -> Parser (S.PosPar, S.KwdPar) funpars ann = (\(n,mbt) -> (S.PosNIL,S.KwdSTAR n mbt)) <$> (starstar *> pstar ann kstartype <* optional comma) <|> do ps <- pospar ann mbmbks <- optional (comma *> optional (kwdpar ann)) return (maybe (ps,S.KwdNIL) (maybe (ps,S.KwdNIL) (\ks -> (ps,ks))) mbmbks) <|> return (S.PosNIL,S.KwdNIL) --- Args ----------------------------------------------------------------------- -- Position/Keyword lists of expr's. -- posarg is used in exprlist to build the general form of comma-separated expressions kwdbind :: Parser (S.Name, S.Expr) kwdbind = do v <- escname equals e <- expr return (v,e) posarg :: Parser S.PosArg posarg = posItems S.PosArg S.PosStar S.PosNil expr expr kwdarg :: Parser S.KwdArg kwdarg = kwdItems (uncurry S.KwdArg) S.KwdStar S.KwdNil kwdbind expr funargs :: Parser (S.PosArg, S.KwdArg) funargs = do r <- funItems S.PosArg S.PosStar S.PosNil expr expr kwdarg S.KwdNil case r of Left p -> return p Right t -> return (S.PosArg t S.PosNil, S.KwdNil) --- Types ---------------------------------------------------------------------- effect :: Parser S.Type effect = addLoc $ rword "_" *> return (S.TWild NoLoc) <|> rword "proc" *> return S.fxProc <|> rword "mut" *> return S.fxMut <|> rword "pure" *> return S.fxPure <|> rword "action" *> return S.fxAction posrow :: Parser S.PosRow posrow = posItems S.posRow S.posStar' S.posNil ttype (optional tvar) kwdrow :: Parser S.KwdRow kwdrow = kwdItems (uncurry S.kwdRow) S.kwdStar' S.kwdNil tsig1 (optional tvar) where tsig1 = do v <- name colon t <- ttype return (v,t) funrows :: Parser (S.PosRow, S.KwdRow) funrows = do r <- funItems S.posRow S.posStar' S.posNil ttype (optional tvar) kwdrow S.kwdNil case r of Left p -> return p Right t -> return (S.posRow t S.posNil, S.kwdNil) tcon :: Parser S.TCon tcon = do n <- qual_name args <- optional (brackets (do t <- ttype ts <- commaList ttype return (t:ts))) return $ S.TC n (maybe [] id args) tvar :: Parser S.TVar tvar = S.TV S.KWild <$> try tvarname qbind :: Parser S.QBind qbind = S.QBind <$> tvar <*> optbounds optbounds :: Parser [S.TCon] optbounds = do bounds <- optional (parens (optional ((:) <$> tcon <*> commaList tcon))) return $ maybe [] (maybe [] id) bounds tschema :: Parser S.TSchema tschema = addLoc $ do bs <- brackets (do n <- qbind ns <- commaList qbind return (n:ns)) fatarrow t <- ttype return (S.tSchema bs t) <|> (S.monotype <$> ttype) ttype :: Parser S.Type ttype = addLoc ( rword "None" *> return (S.TNone NoLoc) <|> (S.TVar NoLoc . S.TV S.KType) <$> (S.Name <$> rwordLoc "Self" <*> return "Self") <|> S.TOpt NoLoc <$> (qmark *> ttype) <|> try (do mbfx <- optional effect (p,k) <- parens funrows arrow t <- ttype return (S.TFun NoLoc (maybe S.fxPure id mbfx) p k t)) <|> try (do r <- parens (funItems S.posRow S.posStar' S.posNil ttype (optional tvar) kwdrow S.kwdNil) case r of Left (p,k) -> return (S.TTuple NoLoc p k) Right t -> return t) <|> parens (return (S.TTuple NoLoc S.posNil S.kwdNil)) <|> try (S.TVar NoLoc <$> tvar) <|> rword "_" *> return (S.TWild NoLoc) <|> S.TCon NoLoc <$> tcon) "type" ================================================ FILE: compiler/lib/src/Acton/Prim.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- module Acton.Prim where import Utils import Pretty import Acton.Syntax import Acton.Builtin import Acton.Names import Acton.NameInfo nPrim = name "$" mPrim = ModName [nPrim] gPrim s = GName mPrim (name s) primKW s = name ("$" ++ s) primProc = gPrim "proc" primAction = gPrim "action" primMut = gPrim "mut" primPure = gPrim "pure" cProc r t = TC primProc [r,t] cAction r t = TC primAction [r,t] cMut r t = TC primMut [r,t] cPure r t = TC primPure [r,t] attr_call_ = name "__call__" attr_exec_ = name "__exec__" attr_asyn_ = name "__asyn__" attr_eval_ = name "__eval__" primActor = gPrim "Actor" primR = gPrim "R" primCont = gPrim "Cont" primASYNCf = gPrim "ASYNCf" primAFTERf = gPrim "AFTERf" primAWAITf = gPrim "AWAITf" primASYNCc = gPrim "ASYNCc" primAFTERc = gPrim "AFTERc" primAWAITc = gPrim "AWAITc" primASYNC = gPrim "ASYNC" primAFTER = gPrim "AFTER" primAWAIT = gPrim "AWAIT" primPUSH_Cc = gPrim "PUSH_Cc" primPUSHF_Cc = gPrim "PUSHF_Cc" primPUSH_C = gPrim "PUSH_C" primPUSHF_C = gPrim "PUSHF_C" primPOP_C = gPrim "POP_C" primDROP_C = gPrim "DROP_C" primPUSH = gPrim "PUSH" primPUSHF = gPrim "PUSHF" primPOP = gPrim "POP" primDROP = gPrim "DROP" primRAISE = gPrim "RAISE" primSEQ = gPrim "SEQ" primBRK = gPrim "BRK" primCNT = gPrim "CNT" primRET = gPrim "RET" tSEQ = tCon $ TC primSEQ [] tBRK = tCon $ TC primBRK [] tCNT = tCon $ TC primCNT [] tRET = tCon $ TC primRET [] primASSERT = gPrim "ASSERT" primNEWACTOR = gPrim "NEWACTOR" primInstallFinalizer = gPrim "InstallFinalizer" attr_finalizer = name "GCfinalizer" primISINSTANCE = gPrim "ISINSTANCE" primISINSTANCE0 = gPrim "ISINSTANCE0" primCONSTCONT = gPrim "CONSTCONT" primCAST = gPrim "CAST" eCAST t t' e = eCall (tApp (eQVar primCAST) [t,t']) [e] primFORMAT = gPrim "FORMAT" primRContc = gPrim "R_CONTc" primRCont = gPrim "R_CONT" primRFail = gPrim "R_FAIL" primEqOpt = gPrim "EqOpt" primIdentityActor = gPrim "IdentityActor" primWEqNone = gPrim "wEqNone" witIntegralInt = GName mPrim $ Derived (deriveQ qnIntegral) $ Derived (deriveQ qnInt) suffixWitness witIntegralBigint = GName mPrim $ Derived (deriveQ qnIntegral) $ Derived (deriveQ qnBigint) suffixWitness primISNOTNONE = gPrim "ISNOTNONE" primISNOTNONE0 = gPrim "ISNOTNONE0" primISNONE = gPrim "ISNONE" primISNONE0 = gPrim "ISNONE0" primSKIPRESc = gPrim "SKIPRESc" primSKIPRES = gPrim "SKIPRES" primBox = gPrim "Box" tBox t = tCon $ TC primBox [t] valKW = name "val" cActor = TC primActor [] tActor = tCon cActor tR = tCon $ TC primR [] tCont t = tCon $ TC primCont [t] primWrappedP = gPrim "Wrapped" pWrapped x y = TC primWrappedP [x,y] primWrappedC = gPrim "WrappedC" tWrapped s x y = tCon $ TC primWrappedC [s,x,y] attrVal = name "val" attrWrap = name "wrap" attrUnwrap = name "unwrap" primWrapProc = gPrim "wWrapProc" primWrapAction = gPrim "wWrapAction" primWrapMut = gPrim "wWrapMut" primWrapPure = gPrim "wWrapPure" primWRAP = gPrim "WRAP" primMkSet = gPrim "mkSet" primMkDict = gPrim "mkDict" primAnnot = gPrim "annot" primRaiseValueError = gPrim "raiseValueError" primUGetItem = gPrim "listD_U__getitem__" primUNext = gPrim "rangeD_U__next__" annot t_ann ann t e = eCall (tApp (eQVar primAnnot) [t_ann, t]) [ann, e] unAnnot t_ann (Call _ (TApp _ (Var _ n) [t,_]) (PosArg w (PosArg e PosNil)) KwdNil) | n == primAnnot && t == t_ann = (w, e) primEnv = [ (noq primASYNCf, NDef scASYNCf NoDec Nothing), (noq primAFTERf, NDef scAFTERf NoDec Nothing), (noq primAWAITf, NDef scAWAITf NoDec Nothing), (noq primASYNCc, NDef scASYNCc NoDec Nothing), (noq primAFTERc, NDef scAFTERc NoDec Nothing), (noq primAWAITc, NDef scAWAITc NoDec Nothing), (noq primASYNC, NDef scASYNC NoDec Nothing), (noq primAFTER, NDef scAFTER NoDec Nothing), (noq primAWAIT, NDef scAWAIT NoDec Nothing), (noq primPUSH_Cc, NDef scPUSH_Cc NoDec Nothing), (noq primPUSHF_Cc, NDef scPUSHF_Cc NoDec Nothing), (noq primPUSH_C, NDef scPUSH_C NoDec Nothing), (noq primPUSHF_C, NDef scPUSHF_C NoDec Nothing), (noq primPOP_C, NDef scPOP_C NoDec Nothing), (noq primDROP_C, NDef scDROP_C NoDec Nothing), (noq primPUSH, NDef scPUSH NoDec Nothing), (noq primPUSHF, NDef scPUSHF NoDec Nothing), (noq primPOP, NDef scPOP NoDec Nothing), (noq primDROP, NDef scDROP NoDec Nothing), (noq primRAISE, NDef scRAISE NoDec Nothing), (noq primSEQ, clSEQ), (noq primBRK, clBRK), (noq primCNT, clCNT), (noq primRET, clRET), (noq primASSERT, NDef scASSERT NoDec Nothing), (noq primNEWACTOR, NDef scNEWACTOR NoDec Nothing), (noq primInstallFinalizer, NDef scGCfinalizer NoDec Nothing), (noq primISINSTANCE, NDef scISINSTANCE NoDec Nothing), (noq primISINSTANCE0, NDef scISINSTANCE NoDec Nothing), (noq primCAST, NDef scCAST NoDec Nothing), (noq primCONSTCONT, NDef scCONSTCONT NoDec Nothing), (noq primFORMAT, NDef scFORMAT NoDec Nothing), (noq primProc, clProc), (noq primAction, clAction), (noq primMut, clMut), (noq primPure, clPure), (noq primActor, clActor), (noq primR, clR), (noq primCont, clCont), (noq primBox, clBox), (noq primRContc, NDef scRContc NoDec Nothing), (noq primRCont, NDef scRCont NoDec Nothing), (noq primRFail, NDef scRFail NoDec Nothing), (noq primEqOpt, clEqOpt), (noq primIdentityActor, clIdentityActor), (noq primWEqNone, NVar tEqNone), (noq witIntegralInt, NVar tIntegralInt), (noq primISNOTNONE, NDef scISNOTNONE NoDec Nothing), (noq primISNONE, NDef scISNONE NoDec Nothing), (noq primISNOTNONE0, NDef scISNOTNONE NoDec Nothing), (noq primISNONE0, NDef scISNONE NoDec Nothing), (noq primSKIPRESc, NDef scSKIPRESc NoDec Nothing), (noq primSKIPRES, NDef scSKIPRES NoDec Nothing), (noq primWrappedP, proWrapped), (noq primWrappedC, clWrapped), -- (noq primWrapProc, NVar $ tWrapped fxProc fxProc fxProc), -- (noq primWrapAction, NVar $ tWrapped fxAction fxProc fxProc), (noq primWRAP, NDef scWRAP NoDec Nothing), (noq primMkSet, NDef scMkSet NoDec Nothing), (noq primMkDict, NDef scMkDict NoDec Nothing), (noq primAnnot, NDef scAnnot NoDec Nothing), (noq primRaiseValueError,NDef scRaiseValueError NoDec Nothing), (noq primUGetItem, NDef scUGetItem NoDec Nothing), (noq primUNext, NDef scUNext NoDec Nothing) ] -- class $Cont[T] (value): pass -- __call__ : proc(T) -> $R clCont = NClass [qbind t] (leftpath [cValue]) te Nothing where te = [ (attr_call_, NSig (monotype $ tFun fxProc (posRow (tVar t) posNil) kwdNil tR) NoDec Nothing) ] t = TV KType (name "T") -- class $proc[R,T] (value): -- __call__ : proc($Cont[T], *R) -> $R -- __exec__ : proc($Cont[value], *R) -> $R clProc = NClass [qbind r, qbind t] (leftpath [cValue]) te Nothing where te = [ (attr_call_, NSig (monotype $ tFun fxProc (posRow (tVar t) (tVar r)) kwdNil tR) NoDec Nothing), (attr_exec_, NSig (monotype $ tFun fxProc (posRow tValue (tVar r)) kwdNil tR) NoDec Nothing) ] r = TV PRow (name "R") t = TV KType (name "T") -- class $action[R,T] ($proc[R,T], value): -- __asyn__ : action(*R) -> T clAction = NClass [qbind r, qbind t] (leftpath [ cProc (tVar r) (tVar t), cValue]) te Nothing where te = [ (attr_asyn_, NSig (monotype $ tFun fxAction (tVar r) kwdNil (tVar t)) NoDec Nothing) ] r = TV PRow (name "R") t = TV KType (name "T") -- class $mut[R,T] ($proc[R,T], value): -- __eval__ : mut(*R) -> T clMut = NClass [qbind r, qbind t] (leftpath [ cProc (tVar r) (tVar t), cValue]) te Nothing where te = [ (attr_eval_, NSig (monotype $ tFun fxMut (tVar r) kwdNil (tVar t)) NoDec Nothing) ] r = TV PRow (name "R") t = TV KType (name "T") -- class $pure[R,T] ($mut[R,T], $proc[R,T], value): -- __eval__ : pure(*R) -> T clPure = NClass [qbind r, qbind t] (leftpath [ cMut (tVar r) (tVar t), cProc (tVar r) (tVar t), cValue]) te Nothing where te = [ (attr_eval_, NSig (monotype $ tFun fxPure (tVar r) kwdNil (tVar t)) NoDec Nothing) ] r = TV PRow (name "R") t = TV KType (name "T") -- class $Box[A] (object, value): -- ref : A -- __init__ : (A) -> None clBox = NClass [qbind a] (leftpath [cObject, cValue]) te Nothing where te = [ (valKW, NSig (monotype $ tVar a) Property Nothing), (initKW, NDef (monotype $ tFun fxPure (posRow (tVar a) posNil) kwdNil tNone) NoDec Nothing) ] a = TV KType (name "A") -- class $Actor (): pass clActor = NClass [] (leftpath [cValue]) te Nothing where te = [ (primKW "next", NSig (monotype tActor) Property Nothing), (primKW "msg", NSig (monotype (tMsg tWild)) Property Nothing), (primKW "msg_tail", NSig (monotype (tMsg tWild)) Property Nothing), (primKW "msg_lock", NSig (monotype $ tCon $ TC (gPrim "Lock") []) Property Nothing), (primKW "affinity", NSig (monotype $ tCon $ TC (gPrim "int64") []) Property Nothing), (primKW "outgoing", NSig (monotype (tMsg tWild)) Property Nothing), (primKW "waitsfor", NSig (monotype (tMsg tWild)) Property Nothing), (primKW "consume_hd", NSig (monotype $ tCon $ TC (gPrim "int64") []) Property Nothing), (primKW "catcher", NSig (monotype $ tCon $ TC (gPrim "Catcher") []) Property Nothing), (primKW "globkey", NSig (monotype $ tCon $ TC (gPrim "long") []) Property Nothing), (boolKW, NDef (monotype $ tFun fxPure posNil kwdNil tBool) NoDec Nothing), (strKW, NDef (monotype $ tFun fxPure posNil kwdNil tStr) NoDec Nothing), (reprKW, NDef (monotype $ tFun fxPure posNil kwdNil tStr) NoDec Nothing), (resumeKW, NDef (monotype $ tFun fxMut posNil kwdNil tNone) NoDec Nothing), (cleanupKW, NDef (monotype $ tFun fxMut posNil kwdNil tNone) NoDec Nothing) ] -- class $SEQ (BaseException, value): -- __init__ : () -> None clSEQ = NClass [] (leftpath [cBaseException, cValue]) te Nothing where te = [ (initKW, NSig (monotype $ tFun fxPure posNil kwdNil tNone) NoDec Nothing) ] -- class $BRK (BaseException, value): -- __init__ : () -> None clBRK = NClass [] (leftpath [cBaseException, cValue]) te Nothing where te = [ (initKW, NSig (monotype $ tFun fxPure posNil kwdNil tNone) NoDec Nothing) ] -- class $CNT (BaseException, value): -- __init__ : () -> None clCNT = NClass [] (leftpath [cBaseException, cValue]) te Nothing where te = [ (initKW, NSig (monotype $ tFun fxPure posNil kwdNil tNone) NoDec Nothing) ] -- class $RET (BaseException, value): -- @property -- val : value -- __init__ : (value) -> None clRET = NClass [] (leftpath [cBaseException, cValue]) te Nothing where te = [ (attrVal, NSig (monotype tValue) Property Nothing), (initKW, NSig (monotype $ tFun fxPure (posRow tValue posNil) kwdNil tNone) NoDec Nothing) ] -- class $R (): pass clR = NClass [] [] [] Nothing -- $ASYNCf : [A] => action($Actor, proc()->A) -> A scASYNCf = tSchema [qbind a] tASYNC where tASYNC = tFun fxAction (posRow tActor $ posRow tFun' posNil) kwdNil (tVar a) a = TV KType $ name "A" tFun' = tFun fxProc posNil kwdNil (tVar a) -- $AFTERf : [A] => action(int, proc()->A) -> A scAFTERf = tSchema [qbind a] tAFTER where tAFTER = tFun fxAction (posRow tFloat $ posRow tFun' posNil) kwdNil (tVar a) a = TV KType $ name "A" tFun' = tFun fxProc posNil kwdNil (tVar a) -- $AWAITf : [A] => proc(Msg[A]) -> A scAWAITf = tSchema [qbind a] tAWAIT where tAWAIT = tFun fxProc (posRow (tMsg $ tVar a) posNil) kwdNil (tVar a) a = TV KType $ name "T" -- $ASYNCc : [A] => action($Actor, proc(proc(A)->$R)->$R) -> A scASYNCc = tSchema [qbind a] tASYNC where tASYNC = tFun fxAction (posRow tActor $ posRow tCont' posNil) kwdNil (tVar a) a = TV KType $ name "A" tCont' = tFun fxProc (posRow tCont'' posNil) kwdNil tR tCont'' = tFun fxProc (posRow (tVar a) posNil) kwdNil tR -- $AFTERc : [A] => action(int, proc(proc(A)->$R)->$R) -> A scAFTERc = tSchema [qbind a] tAFTER where tAFTER = tFun fxAction (posRow tFloat $ posRow tCont' posNil) kwdNil (tVar a) a = TV KType $ name "A" tCont' = tFun fxProc (posRow tCont'' posNil) kwdNil tR tCont'' = tFun fxProc (posRow (tVar a) posNil) kwdNil tR -- $AWAITc : [A] => proc(proc(A)->$R, Msg[A]) -> $R scAWAITc = tSchema [qbind a] tAWAIT where tAWAIT = tFun fxProc (posRow tCont' $ posRow (tMsg $ tVar a) posNil) kwdNil tR a = TV KType $ name "A" tCont' = tFun fxProc (posRow (tVar a) posNil) kwdNil tR -- $ASYNC : [A] => action($Actor, $Cont[$Cont[A]]) -> A scASYNC = tSchema [qbind a] tASYNC where tASYNC = tFun fxAction (posRow tActor $ posRow tCont' posNil) kwdNil (tVar a) a = TV KType $ name "A" tCont' = tCont tCont'' tCont'' = tCont (tVar a) -- $AFTER : [A] => action(int, $Cont[$Cont[A]]) -> A scAFTER = tSchema [qbind a] tAFTER where tAFTER = tFun fxAction (posRow tFloat $ posRow tCont' posNil) kwdNil (tVar a) a = TV KType $ name "A" tCont' = tCont tCont'' tCont'' = tCont (tVar a) -- $AWAIT : [A] => proc($Cont[A], Msg[A]) -> $R scAWAIT = tSchema [qbind a] tAWAIT where tAWAIT = tFun fxProc (posRow tCont' $ posRow (tMsg $ tVar a) posNil) kwdNil tR a = TV KType $ name "A" tCont' = tCont (tVar a) -- $PUSH_Cc : pure (proc(bool)->$R) -> None scPUSH_Cc = tSchema [] tPUSH_C where tPUSH_C = tFun fxPure (posRow tCont' posNil) kwdNil tNone tCont' = tFun fxProc (posRow tBool posNil) kwdNil tR -- $PUSH_FCc : pure (proc(bool)->$R) -> None scPUSHF_Cc = tSchema [] tPUSHF_C where tPUSHF_C = tFun fxPure (posRow tCont' posNil) kwdNil tNone tCont' = tFun fxProc (posRow tBool posNil) kwdNil tR -- $PUSH_C : pure ($Cont[bool]) -> None scPUSH_C = tSchema [] tPUSH_C where tPUSH_C = tFun fxPure (posRow (tCont tBool) posNil) kwdNil tNone -- $PUSHF_C : pure ($Cont[bool]) -> None scPUSHF_C = tSchema [] tPUSHF_C where tPUSHF_C = tFun fxPure (posRow (tCont tBool) posNil) kwdNil tNone -- $POP_C : pure () -> BaseExceptiom scPOP_C = tSchema [] tPOP_C where tPOP_C = tFun fxPure posNil kwdNil tBaseException -- $DROP_C : pure () -> None scDROP_C = tSchema [] tDROP_C where tDROP_C = tFun fxPure posNil kwdNil tNone -- $PUSH : () -> bool scPUSH = tSchema [] tPUSH where tPUSH = tFun fxPure posNil kwdNil tBool -- $PUSHF : () -> bool scPUSHF = tSchema [] tPUSHF where tPUSHF = tFun fxPure posNil kwdNil tBool -- $POP : () -> BaseException scPOP = tSchema [] tPOP where tPOP = tFun fxPure posNil kwdNil tBaseException -- $DROP : () -> None scDROP = tSchema [] tDROP where tDROP = tFun fxPure posNil kwdNil tNone -- $RAISE : (BaseException) -> None scRAISE = tSchema [] tRAISE where tRAISE = tFun fxPure (posRow tBaseException posNil) kwdNil tNone -- $ASSERT : pure (bool, ?str) -> None scASSERT = tSchema [] tASSERT where tASSERT = tFun fxPure (posRow tBool $ posRow (tOpt tStr) posNil) kwdNil tNone -- $NEWACTOR : [A($Actor)] => pure () -> A scNEWACTOR = tSchema [QBind a [cActor]] tNEWACTOR where tNEWACTOR = tFun fxPure posNil kwdNil (tVar a) a = TV KType $ name "A" -- $GCfinalizer : [A($Actor)] => pure (A) -> None scGCfinalizer = tSchema [QBind a [cActor]] tGCfin where tGCfin = tFun fxPure (posRow (tVar a) posNil) kwdNil tNone a = TV KType $ name "A" -- $ISINSTANCE : pure (struct, _) -> bool scISINSTANCE = tSchema [] tISINSTANCE where tISINSTANCE = tFun fxPure (posRow tValue $ posRow tWild posNil) kwdNil tNone -- $CAST : [A, B] => (A) -> B scCAST = tSchema [qbind a, qbind b] tCAST where tCAST = tFun fxPure (posRow (tVar a) posNil) kwdNil (tVar b) a = TV KType $ name "A" b = TV KType $ name "B" -- $CONSTCONT : [A] => (A, $Cont[A]) -> $Cont[tNone] scCONSTCONT = tSchema [qbind a] tCONSTCONT where tCONSTCONT = tFun fxPure (posRow (tVar a) $ posRow tCont' posNil) kwdNil tCont'' tCont' = tCont (tVar a) tCont'' = tCont tNone a = TV KType $ name "A" -- $FORMAT : [P] => (str, (*P)) -> str scFORMAT = tSchema [qbind p] tFORMAT where tFORMAT = tFun fxPure (posRow tStr $ posRow (tTuple (tVar p) kwdNil) posNil) kwdNil tStr p = TV KType $ name "P" -- $R_CONTc : [A] => proc(proc(A)->$R, A) -> $R scRContc = tSchema [qbind a] tRCont where tRCont = tFun fxProc (posRow tCont' $ posRow (tVar a) posNil) kwdNil tR tCont' = tFun fxProc (posRow (tVar a) posNil) kwdNil tR a = TV KType $ name "A" -- $R_CONT : [A] => proc($Cont[A], A) -> $R scRCont = tSchema [qbind a] tRCont where tRCont = tFun fxProc (posRow tCont' $ posRow (tVar a) posNil) kwdNil tR tCont' = tCont (tVar a) a = TV KType $ name "A" -- $R_FAIL : proc(BaseException) -> $R scRFail = tSchema [] tRFail where tRFail = tFun fxProc (posRow tBaseException posNil) kwdNil tR -- class $EqOpt[A] (Eq[?A]): pass clEqOpt = NClass [qbind a] (leftpath [TC qnEq [tOpt $ tVar a]]) clTEnv Nothing where clTEnv = [ (initKW, NDef scInit NoDec Nothing) ] scInit = tSchema [] $ tFun fxPure (posRow (tCon $ TC qnEq [tVar a]) posNil) kwdNil tNone a = TV KType (name "A") -- class $IdentityActor (Identity[$Actor]): pass clIdentityActor = NClass [] (leftpath [TC qnIdentity [tActor]]) [] Nothing -- methods not modelled -- w$EqNone : Eq[None] tEqNone = tCon $ TC qnEq [tNone] -- $Integral$Int$witness : Integral[int] tIntegralInt = tCon $ TC qnIntegral [tInt] -- $Integral$Bigint$witness : Integral[bigint] tIntegralBigint = tCon $ TC qnIntegral [tBigint] -- $ISNOTNONE : [A] => pure (?A) -> bool scISNOTNONE = tSchema [qbind a] tISNOTNONE where tISNOTNONE = tFun fxPure (posRow (tOpt $ tVar a) posNil) kwdNil tBool a = TV KType (name "A") -- $ISNONE : [A] => pure (?A) -> bool scISNONE = tSchema [qbind a] tISNONE where tISNONE = tFun fxPure (posRow (tOpt $ tVar a) posNil) kwdNil tBool a = TV KType (name "A") -- $SKIPRESc : [A] => pure(proc(None)->$R) -> proc(A)->$R scSKIPRESc = tSchema [qbind a] tSKIPRES where tSKIPRES = tFun fxPure (posRow tCont' posNil) kwdNil tCont'' tCont' = tFun fxProc (posRow tNone posNil) kwdNil tR tCont'' = tFun fxProc (posRow (tVar a) posNil) kwdNil tR a = TV KType $ name "A" -- $SKIPRES : [X,A] => pure($Cont[None]) -> $Cont[A] scSKIPRES = tSchema [qbind a] tSKIPRES where tSKIPRES = tFun fxPure (posRow tCont' posNil) kwdNil tCont'' tCont' = tCont tNone tCont'' = tCont (tVar a) a = TV KType $ name "A" -- $MkSet : [A] => (Hashable[A], set[A]) -> set[A] scMkSet = tSchema [qbind a] tMkSet where tMkSet = tFun fxPure (posRow tHashableA (posRow (tSet (tVar a)) posNil)) kwdNil (tSet (tVar a)) tHashableA = tCon (TC qnHashable [tVar a]) a = TV KType $ name "A" -- $MkDict : [A] => (Hashable[A], dict[A]) -> dict[A] scMkDict = tSchema [qbind a, qbind b] tMkDict where tMkDict = tFun fxPure (posRow tHashableA (posRow (tDict (tVar a) (tVar b)) posNil)) kwdNil (tDict (tVar a)(tVar b)) tHashableA = tCon (TC qnHashable [tVar a]) a = TV KType $ name "A" b = TV KType $ name "B" -- $annot : [A,B] => (A,B) -> B scAnnot = tSchema [qbind a, qbind b] tAnnot where tAnnot = tFun fxPure (posRow (tVar a) (posRow (tVar b) posNil)) kwdNil (tVar b) a = TV KType $ name "A" b = TV KType $ name "B" -- $listD_U__getitem__ : [A] => (list[A], int) -> A scUGetItem = tSchema [qbind a] tUGetItem where tUGetItem = tFun fxPure (posRow (tList (tVar a)) (posRow tInt posNil)) kwdNil (tVar a) a = TV KType $ name "A" scRaiseValueError = tSchema [qbind a] tRaiseValErr where tRaiseValErr= tFun fxPure (posRow tStr posNil) kwdNil (tVar a) a = TV KType (name "A") -- $rangeD_U__next__ : [A] => (Iterator[A]) -> A will only be used to replace B_IteratorD_range.__next__ scUNext = tSchema [] tUNext where tUNext = tFun fxMut (posRow (tIterator (tInt)) posNil) kwdNil tInt -- $WRAP : [A,B,C] => ($Actor, proc(*A,**B)->C) -> action(*A,**B)->C scWRAP = tSchema [qbind a, qbind b, qbind c] tWRAP where tWRAP = tFun0 [tActor, abcFun fxProc] (abcFun fxAction) abcFun fx = tFun fx (tVar a) (tVar b) (tVar c) a = TV KType (name "A") b = TV KType (name "B") c = TV KType (name "C") -- protocol $Wrapped[X,Y]: -- @static -- wrap : [A,B,C] => ($Actor, X(*A,**B)->C) -> Self(*A,**B)->C -- @static -- unwrap : [A,B,C] => (Self(*A,**B)->C) -> Y(*A,**B)->C proWrapped = NProto [qbind x, qbind y] [] te Nothing where te = [(attrWrap,scWrap), (attrUnwrap,scUnwrap)] scWrap = NSig (tSchema q (tFun0 [tActor, fxFun tX] (fxFun tSelf))) Static Nothing scUnwrap = NSig (tSchema q (tFun0 [fxFun tSelf] (fxFun tY))) Static Nothing fxFun fx = tFun fx (tVar a) (tVar b) (tVar c) tX = tVar x tY = tVar y tSelf = tVar fxSelf q = [qbind a, qbind b, qbind c] x = TV KFX (name "X") y = TV KFX (name "Y") a = TV PRow (name "A") b = TV KRow (name "B") c = TV KType (name "C") -- class $WrappedC[S,X,Y]: pass -- wrap : [A,B,C] => ($Actor, X(*A,**B)->C) -> S(*A,**B)->C -- unwrap : [A,B,C] => (S(*A,**B)->C) -> X(*A,**B)->C clWrapped = NClass [qbind s, qbind x, qbind y] [] te Nothing where te = [(attrWrap,scWrap), (attrUnwrap,scUnwrap)] scWrap = NDef (tSchema q (tFun0 [tActor, fxFun tX] (fxFun tS))) NoDec Nothing scUnwrap = NDef (tSchema q (tFun0 [fxFun tS] (fxFun tY))) NoDec Nothing fxFun fx = tFun fx (tVar a) (tVar b) (tVar c) tS = tVar s tX = tVar x tY = tVar y q = [qbind a, qbind b, qbind c] s = TV KFX (name "S") x = TV KFX (name "X") y = TV KFX (name "Y") a = TV PRow (name "A") b = TV KRow (name "B") c = TV KType (name "C") primWits = [ WInst [] fxAction (pWrapped fxProc fxProc) primWrapAction path, WInst [] fxProc (pWrapped fxProc fxProc) primWrapProc path, WInst [] fxMut (pWrapped fxMut fxMut) primWrapMut path, WInst [qbind y] fxPure (pWrapped fxPure (tVar y)) primWrapPure path ] where path = [Left (noQ "_")] y = TV KFX (name "Y") isPUSH (Call _ (Var _ x) _ _) = x `elem` [primPUSH,primPUSHF] isPUSH _ = False isPUSHF (Call _ (Var _ x) _ _) = x == primPUSHF isPUSHF _ = False isRAISE (Call _ (Var _ x) _ _) = x == primRAISE isRAISE _ = False ================================================ FILE: compiler/lib/src/Acton/Printer.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, DeriveGeneric #-} module Acton.Printer (module Acton.Printer, module Pretty) where import Utils import Pretty import Acton.Syntax import Prelude hiding ((<>)) instance Pretty Module where pretty (Module qn imps doc stmts) = joinSections [prHead qn, prettyModDoc doc, vpretty imps, vpretty stmts] prHead qn = empty --prHead qn = text "module" <+> pretty qn <> colon $+$ blank instance Pretty Import where pretty (Import _ ms) = text "import" <+> commaSep pretty ms pretty (FromImport _ n ns) = text "from" <+> pretty n <+> text "import" <+> commaSep pretty ns pretty (FromImportAll _ n) = text "from" <+> pretty n <+> text "import" <+> text "*" prettySuite ss = nest 4 $ vcat $ map pretty ss joinSections :: [Doc] -> Doc joinSections = vcat . punctuate blank . filter (not . isEmpty) prettyModDoc :: Maybe String -> Doc prettyModDoc Nothing = empty prettyModDoc (Just doc) = text "\"\"\"" <> text (escapeDocstring doc) <> text "\"\"\"" -- Pretty print a suite with optional docstring at the beginning prettyDocSuite :: Maybe String -> Suite -> Doc prettyDocSuite Nothing ss = prettySuite ss prettyDocSuite (Just doc) ss = nest 4 $ vcat $ text "\"\"\"" <> text (escapeDocstring doc) <> text "\"\"\"" : map pretty ss -- Escape special characters in docstrings for pretty printing escapeDocstring :: String -> String escapeDocstring [] = [] escapeDocstring ('\\':xs) = '\\' : '\\' : escapeDocstring xs escapeDocstring ('"':xs) = '\\' : '"' : escapeDocstring xs escapeDocstring (x:xs) = x : escapeDocstring xs instance Pretty Stmt where pretty (Expr _ e) = pretty e pretty (Assign _ ps e) = hsep . punctuate (space <> equals) $ map pretty ps ++ [pretty e] pretty (MutAssign _ t e) = pretty t <+> equals <+> pretty e pretty (AugAssign _ t o e) = pretty t <+> pretty o <+> pretty e pretty (Assert _ e mbe) = text "assert" <+> pretty e <> nonEmpty (comma <+>) pretty mbe pretty (Pass _) = text "pass" pretty (Delete _ t) = text "del" <+> pretty t pretty (Return _ e) = text "return" <+> pretty e pretty (Raise _ e) = text "raise" <+> pretty e pretty (Break _) = text "break" pretty (Continue _) = text "continue" pretty (If _ (b:bs) b2) = prettyBranch "if" b $+$ vmap (prettyBranch "elif") bs $+$ prettyEnd "else" b2 pretty (While _ e b b2) = text "while" <+> pretty e <> colon $+$ prettySuite b $+$ prettyEnd "else" b2 pretty (For _ p e b b2) = text "for" <+> pretty p <+> text "in" <+> pretty e <> colon $+$ prettySuite b $+$ prettyEnd "else" b2 pretty (Try _ b hs b2 b3) = text "try" <> colon $+$ prettySuite b $+$ vmap pretty hs $+$ prettyEnd "else" b2 $+$ prettyEnd "finally" b3 pretty (With _ items b) = text "with" <+> commaSep pretty items <> colon $+$ prettySuite b pretty (Data _ (Just e) b) = pretty e <> colon $+$ prettySuite b pretty (Data _ Nothing b) = text "return" <> colon $+$ prettySuite b pretty (VarAssign _ ps e) = text "var" <+> (hsep . punctuate (space <> equals) $ map pretty ps ++ [pretty e]) pretty (After _ e e') = text "after" <+> pretty e <> colon <+> pretty e' pretty (Decl _ [d]) = pretty d pretty (Decl _ ds) = text "# recursive group:" $+$ (vcat $ map pretty ds) $+$ text "# (recursive group)" pretty (Signature _ vs sc d) = prettyDec d $ commaList vs <+> colon <+> pretty sc instance Pretty Decl where pretty (Def _ n q p k a b d x doc) = (prettyDecFX d x $ text "def" <+> pretty n <> nonEmpty brackets commaList q <+> parens (pretty (p,k)) <> nonEmpty (text " -> " <>) pretty a <> colon) $+$ prettyDocSuite doc b pretty (Actor _ n q p k b doc) = text "actor" <+> pretty n <> nonEmpty brackets commaList q <+> parens (pretty (p,k)) <> colon $+$ prettyDocSuite doc b pretty (Class _ n q a b doc) = text "class" <+> pretty n <> nonEmpty brackets commaList q <+> nonEmpty parens commaList a <> colon $+$ prettyDocSuite doc b pretty (Protocol _ n q a b doc) = text "protocol" <+> pretty n <> nonEmpty brackets commaList q <+> nonEmpty parens commaList a <> colon $+$ prettyDocSuite doc b pretty (Extension _ q c a b doc) | tvs == tcargs c = text "extension" <+> pretty (tcname c) <> nonEmpty brackets commaList q <+> nonEmpty parens commaList a <> colon $+$ prettyDocSuite doc b | otherwise = text "extension" <+> prettyQual q <+> pretty c <+> nonEmpty parens commaList a <> colon $+$ prettyDocSuite doc b where tvs = map tVar $ qbound q prettyDecFX d fx = prettyDec d . (prettyFXnoWild fx <+>) prettyFXnoWild (TWild _) = empty prettyFXnoWild fx = pretty fx prettyBranch kw (Branch e b) = text kw <+> pretty e <> colon $+$ prettySuite b prettyEnd kw [] = empty prettyEnd kw b = text kw <> colon $+$ prettySuite b prettyOpt sep Nothing = empty prettyOpt sep (Just a) = sep <+> pretty a instance Pretty PosPar where pretty (PosPar n t e PosNIL) = pretty n <+> prettyOpt colon t <+> prettyOpt equals e pretty (PosPar n t e p) = pretty n <+> prettyOpt colon t <+> prettyOpt equals e <> comma <+> pretty p pretty (PosSTAR n t) = text "*" <> pretty n <+> prettyOpt colon t pretty PosNIL = empty instance Pretty KwdPar where pretty (KwdPar n t e KwdNIL) = pretty n <+> prettyOpt colon t <+> prettyOpt equals e pretty (KwdPar n t e k) = pretty n <+> prettyOpt colon t <+> prettyOpt equals e <> comma <+> pretty k pretty (KwdSTAR n t) = text "**" <> pretty n <+> prettyOpt colon t pretty KwdNIL = empty instance Pretty (PosPar,KwdPar) where pretty (PosNIL, ks) = pretty ks pretty (ps, KwdNIL) = pretty ps pretty (ps, ks) = pretty ps <> comma <+> pretty ks instance Pretty PosArg where pretty (PosArg e PosNil) = pretty e pretty (PosArg e p) = pretty e <> comma <+> pretty p pretty (PosStar e) | atomic e = text "*" <> pretty e | otherwise = text "*" <> parens (pretty e) pretty PosNil = empty instance Pretty KwdArg where pretty (KwdArg n e KwdNil) = pretty n <+> equals <+> pretty e pretty (KwdArg n e k) = pretty n <+> equals <+> pretty e <> comma <+> pretty k pretty (KwdStar e) | atomic e = text "**" <> pretty e | otherwise = text "**" <> parens (pretty e) pretty KwdNil = empty instance Pretty (PosArg,KwdArg) where pretty (PosNil, ks) = pretty ks pretty (ps, KwdNil) = pretty ps pretty (ps, ks) = pretty ps <> comma <+> pretty ks atomic Await{} = False atomic Cond{} = False atomic BinOp{} = False atomic CompOp{} = False atomic UnOp{} = False atomic Lambda{} = False atomic Yield{} = False atomic YieldFrom{} = False atomic _ = True prettyAtom e | atomic e = pretty e | otherwise = parens (pretty e) instance Pretty Expr where pretty (Var _ n) = pretty n pretty (Int _ _ str) = text str pretty (Float _ _ str) = text str pretty (Imaginary _ _ str) = text str pretty (Bool _ v) = pretty v pretty (None _) = text "None" pretty (NotImplemented _) = text "NotImplemented" pretty (Ellipsis _) = text "..." pretty (Strings _ ss) = hsep (map (pretty . show) ss) pretty (BStrings _ ss) = hsep (map (\s -> text " b" <> pretty s) ss) pretty (Call _ e ps ks) = prettyAtom e <> parens (pretty (ps,ks)) pretty (TApp _ e ts) = pretty e <> text "@" <> brackets (commaSep pretty ts) pretty (Let _ ss e) = text "let:" $+$ prettySuite ss $+$ text "in" <+> pretty e pretty (Async _ e) = parens (text "async" <+> pretty e) pretty (Await _ e) = text "await" <+> pretty e pretty (Index _ e ix) = prettyAtom e <> brackets (pretty ix) pretty (Slice _ e sl) = prettyAtom e <> brackets (pretty sl) pretty (IsInstance _ e c) = text "isinstance" <> parens (pretty e <> comma <+> pretty c) pretty (Dot _ e n) = prettyAtom e <> dot <> pretty n pretty (Rest _ e n) = prettyAtom e <> dot <> text "~" <> pretty n pretty (DotI _ e i) = prettyAtom e <> dot <> pretty i pretty (RestI _ e i) = prettyAtom e <> dot <> text "~" <> pretty i pretty (Opt _ e True) = pretty e <> text "?" pretty (Opt _ e False) = pretty e <> text "!" pretty (OptChain _ e) = pretty e pretty (Lambda _ ps ks e fx) = prettyFXnoWild fx <+> text "lambda" <+> prettyLambdaPar ps ks <> colon <+> pretty e pretty (Yield _ e) = text "yield" <+> pretty e pretty (YieldFrom _ e) = text "yield" <+> text "from" <+> pretty e pretty (Tuple _ ps KwdNil) | singlePosArg ps = parens (pretty ps <> comma) pretty (Tuple _ ps ks) = parens (pretty (ps,ks)) pretty (List _ es) = brackets (commaList es) pretty (ListComp _ e co) = brackets (pretty e <+> pretty co) pretty (Dict _ es) = braces (commaList es) pretty (DictComp _ e co) = braces (pretty e <+> pretty co) pretty (Set _ []) = text "set" <> parens empty pretty (Set _ es) = braces (commaList es) pretty (SetComp _ e co) = braces (pretty e <+> pretty co) pretty (Paren _ e@Tuple{}) = pretty e pretty (Paren _ e) = parens (pretty e) pretty (Box t e) = parens (text "BOX" <+> pretty t <+> pretty e) pretty (UnBox t e) = parens (text "UNBOX" <+> pretty t <+> pretty e) pretty e = prettyPrec 0 e -- BinOp, CompOp, UnOp and Cond {- We assign precedences to operator expressions according to their main operator as follows. The Python language reference does not assign numerical precedences, but the precedence order implied by the syntax rules is consistent with the values below, with one exception: Quote from section 6.5 in The Python Language Reference (v 3.8.6): "The power operator binds more tightly than unary operators on its left; it binds less tightly than unary operators on its right." Printing here does not minimize the use of parentheses; unary operator expressions are put in parenthesis (for clarity) in all operator contexts, also where the parser does not need them. 12 ** 11 (unary) + - ~ 10 * / // / @ 9 + - 8 << >> 7 & 6 ^ 5 | 4 < > <= >= == !=, is, is not, in, not in 3 not 2 and 1 or 0 _ if _ else _ -} prettyPrec n e@(BinOp _ e1 op e2) = parensIf (n > prc) ps where prc = fromJust (lookup op bps) bps = [(Or,1),(And,2),(Plus,9),(Minus,9),(Mult,10),(Pow,12),(Div,10),(Mod,10), (EuDiv,10),(BOr,5),(BXor,6),(BAnd,7),(ShiftL,8),(ShiftR,8),(MMult,10)] ps | op == Pow = prettyPrec (prc+1) e1 <+> pretty op <+> prettyPrec prc e2 | otherwise = prettyPrec prc e1 <+> pretty op <+> prettyPrec (prc+1) e2 prettyPrec n (CompOp _ e ops) = parensIf (n > 4) $ pretty e <+> hsep (map pretty ops) prettyPrec n e1@(UnOp _ op e) = parensIf (n > 0) $ pretty op <> prettyPrec prc e where prc = if op == Not then 3 else 11 prettyPrec n (Cond _ e1 e e2) = parensIf (n > 1) $ pretty e1 <+> text "if" <+> pretty e <+> text "else" <+> pretty e2 prettyPrec _ e = pretty e prettyLambdaPar ps ks | annotP ps || annotK ks = parens (pretty (ps,ks)) | otherwise = pretty (ps,ks) where annotP (PosPar _ mba _ p) = mba /= Nothing || annotP p annotP (PosSTAR _ mba) = mba /= Nothing annotP PosNIL = False annotK (KwdPar _ mba _ k) = mba /= Nothing || annotK k annotK (KwdSTAR _ mba) = mba /= Nothing annotK KwdNIL = False instance Pretty OpArg where pretty (OpArg op e) = pretty op <+> pretty e prettyTuple [] = text "()" prettyTuple [e] = pretty e <> char ',' prettyTuple es = commaCat es instance Pretty Name where pretty nm | nm == nSelf = text "Self" | isIdent str = text str | otherwise = quotes (text str) where str = nstr nm instance Pretty ModName where pretty (ModName ns) = dotCat pretty ns instance Pretty QName where -- pretty (QName m n) = char '~' <> pretty m <> dot <> pretty n pretty (QName m n) = pretty m <> dot <> pretty n -- pretty (NoQ n) = char '~' <> pretty n pretty (NoQ n) = pretty n pretty (GName m n) | ModName [Name _ "$"] <- m = text ("$" ++ rawstr n) | otherwise = pretty m <> dot <> pretty n instance Pretty ModRef where pretty (ModRef (i,n)) = hcat (replicate i dot) <> pretty n instance Pretty Handler where pretty (Handler ex b) = pretty ex <> colon $+$ prettySuite b instance Pretty Except where pretty (ExceptAll _) = text "except" pretty (Except _ x) = text "except" <+> pretty x pretty (ExceptAs _ x n) = text "except" <+> pretty x <+> text "as" <+> pretty n prettyAnn Nothing = empty prettyAnn (Just a) = colon <+> pretty a instance Pretty Elem where pretty (Elem e) = pretty e pretty (Star e) = text "*" <> pretty e instance Pretty Assoc where pretty (Assoc k v) = pretty k <> colon <+> pretty v pretty (StarStar e) = text "**" <> pretty e instance Pretty WithItem where pretty (WithItem e p) = pretty e <+> nonEmpty (text "as" <+>) pretty p instance Pretty ModuleItem where pretty (ModuleItem n1 n2) = pretty n1 <+> nonEmpty (text "as" <+>) pretty n2 instance Pretty ImportItem where pretty (ImportItem n1 n2) = pretty n1 <+> nonEmpty (text "as" <+>) pretty n2 instance Pretty Sliz where pretty (Sliz _ a b c) = pretty a <> colon <> pretty b <> nonEmpty (colon <>) pretty c instance Pretty Comp where pretty (CompFor _ p e c) = text "for" <+> pretty p <+> text "in" <+> pretty e <+> pretty c pretty (CompIf _ e c) = text "if" <+> pretty e <+> pretty c pretty NoComp = empty instance Pretty PosPat where pretty (PosPat p PosPatNil) = pretty p pretty (PosPat p ps) = pretty p <> comma <+> pretty ps pretty (PosPatStar p) = text "*" <> pretty p pretty PosPatNil = empty instance Pretty KwdPat where pretty (KwdPat n p KwdPatNil) = pretty n <+> equals <+> pretty p pretty (KwdPat n p ps) = pretty n <+> equals <+> pretty p <> comma <+> pretty ps pretty (KwdPatStar p) = text "**" <> pretty p pretty KwdPatNil = empty instance Pretty (PosPat,KwdPat) where pretty (PosPatNil, ks) = pretty ks pretty (ps, KwdPatNil) = pretty ps pretty (ps, ks) = pretty ps <> comma <+> pretty ks instance Pretty Pattern where pretty (PWild _ a) = text "_" <> prettyAnn a pretty (PVar _ n a) = pretty n <> prettyAnn a pretty (PTuple _ ps KwdPatNil) | singlePosPat ps = pretty ps <> comma pretty (PTuple _ ps ks) = pretty (ps, ks) pretty (PList _ ps p) = brackets (prettyPats ps p) pretty (PParen _ p) = parens (pretty p) pretty (PData _ n ixs) = pretty n <> hcat (map (brackets . pretty) ixs) prettyPats [] Nothing = empty prettyPats ps Nothing = commaSep pretty ps prettyPats [] (Just p) = text "*" <> pretty p prettyPats ps (Just p) = commaSep pretty ps <> comma <+> text "*" <> pretty p prettyDec d = (pretty d $+$) instance Pretty Deco where pretty NoDec = empty pretty Static = text "@static" pretty Property = text "@property" instance Pretty Unary where pretty Not = text "not " pretty BNot = text "~" pretty UMinus = text "-" pretty UPlus = text "+" instance Pretty Binary where pretty Or = text "or" pretty And = text "and" pretty BOr = text "|" pretty BXor = text "^" pretty BAnd = text "&" pretty ShiftL = text "<<" pretty ShiftR = text ">>" pretty Plus = text "+" pretty Minus = text "-" pretty Mult = text "*" pretty MMult = text "@" pretty Div = text "/" pretty Mod = text "%" pretty EuDiv = text "//" pretty Pow = text "**" instance Pretty Comparison where pretty Lt = text "<" pretty Gt = text ">" pretty Eq = text "==" pretty GE = text ">=" pretty LE = text "<=" pretty NEq = text "!=" pretty In = text "in" pretty NotIn = text "not in" pretty Is = text "is" pretty IsNot = text "is not" instance Pretty Aug where pretty PlusA = text "+=" pretty MinusA = text "-=" pretty MultA = text "*=" pretty MMultA = text "@=" pretty DivA = text "/=" pretty ModA = text "%=" pretty PowA = text "**=" pretty BAndA = text "&=" pretty BOrA = text "|=" pretty BXorA = text "^=" pretty ShiftLA = text "<<=" pretty ShiftRA = text ">>=" pretty EuDivA = text "//=" instance Pretty TSchema where pretty (TSchema _ q t) = prettyQual q <+> pretty t prettyQual [] = empty prettyQual q = pretty q <+> text "=>" instance Pretty TVar where pretty (TV k n) = pretty n -- <> parens (colon <> pretty k) instance Pretty TUni where pretty (UV k l i) | i < 0 = text "T_" <> pretty (-i) <> text "w" <> prl | otherwise = text "T_" <> pretty i <> prk k <> prl where prk PRow = text "p" prk KRow = text "k" prk KFX = text "x" prk _ = empty -- prl = parens (pretty l) prl = empty instance Pretty TCon where pretty (TC n []) = pretty n -- pretty (TC n [t]) -- | n == qnSequence = brackets (pretty t) -- | n == qnSetP = braces (pretty t) -- pretty (TC n [kt,vt]) -- | n == qnMapping = braces (pretty kt <> colon <+> pretty vt) pretty (TC n ts) = pretty n <> brackets (commaList ts) instance Pretty QBinds where pretty q = brackets (commaList q) instance Pretty QBind where pretty (QBind v []) = pretty v pretty (QBind v cs) = pretty v <> parens (commaList cs) prettyPosRow (TRow _ PRow _ t (TNil _ PRow)) = pretty t prettyPosRow (TRow _ PRow _ t p) = pretty t <> comma <+> prettyPosRow p prettyPosRow (TStar _ PRow r) | TVar _ v <- r = text "*" <> pretty v | TUni _ u <- r = text "*" <> pretty u | TWild _ <- r = text "*" | otherwise = text "*" <> parens (prettyPosRow r) -- Print row as a tuple prettyPosRow (TVar _ v) = text "+" <> pretty v prettyPosRow (TUni _ u) = text "+" <> pretty u prettyPosRow (TWild _) = text "+" prettyPosRow (TNil _ PRow) = empty prettyPosRow t = text "??" <> pretty t prettyKwdRow (TRow _ KRow n t (TNil _ KRow)) = pretty n <> colon <+> pretty t prettyKwdRow (TRow _ KRow n t k) = pretty n <> colon <+> pretty t <> comma <+> prettyKwdRow k prettyKwdRow (TStar _ KRow r) | TVar _ v <- r = text "**" <> pretty v | TUni _ u <- r = text "**" <> pretty u | TWild _ <- r = text "**" | otherwise = text "**" <> parens (prettyKwdRow r) -- Print row as a tuple prettyKwdRow (TVar _ v) = text "++" <> pretty v prettyKwdRow (TUni _ u) = text "++" <> pretty u prettyKwdRow (TWild _) = text "++" prettyKwdRow (TNil _ KRow) = empty prettyKwdRow t = text "??" <> pretty t prettyFunRow (TNil _ PRow) k = prettyKwdRow k prettyFunRow p (TNil _ KRow) = prettyPosRow p prettyFunRow p k = prettyPosRow p <> comma <+> prettyKwdRow k instance Pretty Type where pretty (TVar _ v) = pretty v pretty (TUni _ u) = pretty u pretty (TCon _ c) = pretty c pretty (TFun _ fx p k t) = prettyFXnoPure fx <> parens (prettyFunRow p k) <+> text "->" <+> pretty t where spaceSep f = hsep . punctuate space . map f pretty (TTuple _ p k) | TVar{} <- p, TNil{} <- k = pretty p -- Print top row variable as a tyvar | TNil{} <- p, TVar{} <- k = pretty k -- Print top row variable as a tyvar | TUni{} <- p, TNil{} <- k = pretty p -- Print top row variable as a univar | TNil{} <- p, TUni{} <- k = pretty k -- Print top row variable as a univar | TRow _ _ _ t TNil{} <- p, TNil{} <- k = parens (pretty t <> comma) | otherwise = parens (prettyFunRow p k) pretty (TOpt _ t) = text "?" <> pretty t pretty (TNone _) = text "None" pretty (TWild _) = text "_" pretty (TRow _ PRow _ t TNil{}) = parens $ pretty t <> comma pretty r@TRow{rkind=PRow} = parens $ prettyPosRow r pretty r@TRow{rkind=KRow} = parens $ prettyKwdRow r pretty r@TStar{rkind=PRow} = parens $ prettyPosRow r pretty r@TStar{rkind=KRow} = parens $ prettyKwdRow r pretty r@TNil{rkind=PRow} = parens empty pretty r@TNil{rkind=KRow} = parens empty pretty (TFX _ fx) = pretty fx prettyFXnoPure (TFX _ FXPure) = empty prettyFXnoPure t = pretty t instance Pretty FX where pretty FXProc = text "proc" pretty FXMut = text "mut" pretty FXPure = text "pure" pretty FXAction = text "action" instance Pretty Kind where pretty KType = text "type" pretty KProto = text "protocol" pretty KFX = text "effect" pretty PRow = text "positional row" pretty KRow = text "keyword row" pretty (KFun ks k) = brackets (commaSep pretty ks) <+> text "=>" <+> pretty k pretty (KUni i) = text "K_" <> pretty i pretty KWild = text "_" ================================================ FILE: compiler/lib/src/Acton/QuickType.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- module Acton.QuickType where import Acton.Syntax import Acton.Names import Acton.Subst import Acton.Env import Acton.NameInfo import Acton.Builtin import Acton.Prim import Utils class QType a where qType :: EnvF x -> Checker -> a -> (Type, Type, a) qMatch :: Checker -> Type -> Type -> a -> a type Checker = Type -> Type -> Expr -> Expr accept :: Checker accept t t' e = e typecast :: Checker typecast t t' e | t == t' = e | otherwise = eCAST t t' e typeOf env x = t where (t, fx, x') = qType env accept x fxOf env x = fx where (t, fx, x') = qType env accept x typeInstOf env ts e = t where (t, fx, e') = qInst env accept ts e schemaOf env e = (sc, dec) where (sc, fx, dec, e') = qSchema env accept e closedType :: EnvF x -> Expr -> Bool closedType env (Var _ n) = isClosed $ findQName n env closedType env (Dot _ (Var _ x) n) | NClass q _ _ _ <- findQName x env = closedAttr env (TC x (map tVar $ qbound q)) n closedType env (Dot _ e n) = case typeOf env e of TCon _ c -> closedAttr env c n TVar _ v -> closedAttr env (findTVBound env v) n TTuple _ p k -> n `notElem` valueKWs t -> error ("t = "++prstr t) closedType env (TApp _ e _) = closedType env e closedType env (Async _ e) = closedType env e closedType env _ = True isUnboxedExpr (UnBox _ _) = True isUnboxedExpr (Var _ (NoQ (Internal BoxPass _ _))) = True isUnboxedExpr (BinOp _ l _ r) = isUnboxedExpr l || isUnboxedExpr r isUnboxedExpr _ = False qSchema :: EnvF x -> Checker -> Expr -> (TSchema, Type, Maybe Deco, Expr) qSchema env f e@(Var _ n) = case findQName n env of NVar t -> (monotype t, fxPure, Nothing, e) NSVar t -> (monotype t, fxPure, Nothing, e) NDef sc dec _ -> (sc, fxPure, Just dec, e) NSig sc dec _ -> (sc, fxPure, Just dec, e) NClass q _ _ _ -> let tc = TC (unalias env n) (map tVar $ qbound q) (TSchema _ q' t, _) = findAttr' env tc initKW t' = if restype t == tR then t else t{ restype = tSelf } in (tSchema (q++q') $ vsubst [(tvSelf,tCon tc)] t', fxPure, Just NoDec, e) NAct q p k _ _ -> (tSchema q (tFun fxProc p k (tCon0 n q)), fxPure, Just NoDec, e) i -> error ("### qSchema Var unexpected " ++ prstr (noq n,i)) qSchema env f e@(Dot _ (Var _ x) n) | NClass q _ _ _ <- info = let tc = TC x (map tVar $ qbound q) (TSchema _ q' t, mbdec) = findAttr' env tc n in (tSchema (q++q') $ vsubst [(tvSelf,tCon tc)] (addSelf t mbdec), fxPure, mbdec, e) where info = findQName x env qSchema env f e0@(Dot l e n) = case t of TCon _ c -> addE e' $ findAttr' env c n TTuple _ p k | n `elem` valueKWs -> addE e' $ findAttr' env cValue n | otherwise -> addE e' $ (monotype $ pick n k, Nothing) TVar _ v -> addE e' $ findAttr' env tc n where tc = findTVBound env v t -> error ("### qSchema Dot unexpected " ++ prstr e0 ++ " :: " ++ prstr t) where (t, fx, e') = qType env f e addE e1 (sc, dec) = (vsubst [(tvSelf,t)] sc, fx, dec, Dot l e1 n) pick n (TRow l k x t r) = if x == n then t else pick n r pick n (TStar l k r) | n == attrKW = tTupleK r pick n (TNil l k) | n == attrKW = tTupleK (tNil KRow) pick n _ = error ("### qSchema Dot " ++ prstr n ++ " on " ++ prstr e0 ++ " :: " ++ prstr t) qSchema env f e = (monotype t, fx, Nothing, e') where (t, fx, e') = qType env f e qInst :: EnvF x -> Checker -> [Type] -> Expr -> (Type, Type, Expr) qInst env f [] (TApp _ e ts) = qInst env f ts e qInst env f ts e = case qSchema env f e of (TSchema _ q t, fx, _, e') | length q == length ts -> (t', fx, tApp e' ts) where t' = vsubst (qbound q `zip` ts) t (sc, _, _, _) -> error ("###### qInst [" ++ prstrs ts ++ "] " ++ prstr e ++ " is " ++ prstr sc) instance QType Expr where qType env f e@Var{} = qInst env f [] e qType env f e@Dot{} = qInst env f [] e qType env f (TApp _ e ts) = qInst env f ts e qType env f e@(Int _ _ _) = (tInt, fxPure, e) qType env f e@(Float _ _ s) = (tFloat, fxPure, e) qType env f e@(Bool _ _) = (tBool, fxPure, e) qType env f e@(None _) = (tNone, fxPure, e) qType env f e@(Strings _ _) = (tStr, fxPure, e) qType env f e@(BStrings _ _) = (tBytes, fxPure, e) -- qType env f (Imaginary _ i s) = undefined -- qType env f (NotImplemented _) = undefined -- qType env f (Ellipsis _) = undefined qType env f e0@(Call l e ps ks) | TFun{} <- t = --trace ("## qType Call " ++ prstr e0 ++ ", t = " ++ prstr t) $ (restype t, fx', Call l e' (qMatch f p (posrow t) ps') (qMatch f k (kwdrow t) ks')) | otherwise = error ("###### qType Fun " ++ prstr e ++ " : " ++ prstr t) where (t, fx, e') = qType env f e (p, fxp, ps') = qType env f ps (k, fxk, ks') = qType env f ks fx' = upbound env [fx,fxp,fxk,effect t] qType env f (Let l ss e) = (t, fx, Let l ss e') where te = envOf ss (t,fx,e') = qType (define te env) f e qType env f (Async l e) = case t of TFun _ (TFX _ FXAction) p k t' -> (tFun fxProc p k (tMsg t'), fx, Async l e') where (t, fx, e') = qType env f e qType env f (Await l e) = case t of TCon _ (TC c [t]) | c == qnMsg -> (t, fxProc, Await l e') where (t, fx, e') = qType env f e qType env f e@(BinOp l e1 op e2) | isUnboxedExpr e = (t, fx, BinOp l e1' op e2') | otherwise = (t, fx, BinOp l (qMatch f t1 t e1') op (qMatch f t2 t e2')) where (t1, fx1, e1') = qType env f e1 (t2, fx2, e2') = qType env f e2 t = upbound env [t1,t2] fx = upbound env [fx1,fx2] qType env f (CompOp l e1 [OpArg op e2]) = (tBool, fx, CompOp l (qMatch f t1 t e1') [OpArg op (qMatch f t2 t e2')]) where (t1, fx1, e1') = qType env f e1 (t2, fx2, e2') = qType env f e2 t = upbound env [t1,t2] fx = upbound env [fx1,fx2] qType env f (UnOp l Not e) = (tBool, fx, UnOp l Not (qMatch f t tBool e')) where (t, fx, e') = qType env f e qType env f (Cond l e1 e e2) = (t', fx', Cond l (qMatch f t1 t' e1') (qMatch f t tBool e') (qMatch f t2 t' e2')) where (t1, fx1, e1') = qType env f e1 (t, fx, e') = qType env f e (t2, fx2, e2') = qType env f e2 t' = upbound env [t1,t2] fx' = upbound env [fx1,fx,fx2] qType env f (IsInstance l e c) = (tBool, fx, IsInstance l e' c) where (t, fx, e') = qType env f e qType env f (DotI l e i) = case t of TTuple _ p _ -> (pick i p, fx, DotI l e' i) where (t, fx, e') = qType env f e pick i (TRow _ _ _ t' p) = if i == 0 then t' else pick (i-1) p qType env f (RestI l e i) = case t of TTuple _ p _ -> (TTuple NoLoc (pick i p) kwdNil, fx, RestI l e' i) where (t, fx, e') = qType env f e pick i (TRow l k x t r) = if i == 0 then r else TRow l k x t (pick (i-1) r) pick i (TNil l k) = TNil l k qType env f (Rest l e n) = case t of TTuple _ p k -> (TTuple NoLoc posNil (pick n k), fx, Rest l e' n) where (t, fx, e') = qType env f e pick n (TRow l k x t r) = if x == n then r else TRow l k x t (pick n r) pick n (TNil l k) = TNil l k qType env f (Lambda l p k e fx) = (TFun NoLoc fx (prowOf p) (krowOf k) t, fxPure, Lambda l p k e' fx) where (t, _, e') = qType env1 f e env1 = define (envOf k) $ define (envOf p) env qType env f (Tuple l ps ks) = (TTuple NoLoc p k, fx, Tuple l ps' ks') where (p, fxp, ps') = qType env f ps (k, fxk, ks') = qType env f ks fx = upbound env [fxp,fxk] qType env f (List l es) = (tList (upbound env ts), upbound env fxs, List l es') where (ts, fxs, es') = unzip3 $ map (qType env f) es qType env f (ListComp l e c) = (tList t, upbound env [fxc,fx], ListComp l e' c') where (_, fxc, c') = qType env f c (t, fx, e') = qType env1 f e env1 = define (envOf c) env qType env f (SetComp l e c) = (tSet t, upbound env [fxc,fx], SetComp l e' c') where (_, fxc, c') = qType env f c (t, fx, e') = qType env1 f e env1 = define (envOf c) env qType env f (DictComp l a c) = (tDict tk tv, upbound env [fxc,fx], DictComp l a' c') where (_, fxc, c') = qType env f c (TTuple _ tk tv, fx, a') = qType env1 f a env1 = define (envOf c) env qType env f (Dict l as) = (tDict (upbound env ts1) (upbound env ts2), upbound env (fxk++fxv), Dict l (zipWith Assoc ks vs)) where (ts1, fxk, ks) = unzip3 $ [ qType env f k | Assoc k v <- as ] (ts2, fxv, vs) = unzip3 $ [ qType env f v | Assoc k v <- as ] qType env f (Set l es) = (tSet (upbound env ts), upbound env fxs, Set l es') where (ts, fxs, es') = unzip3 $ map (qType env f) es qType env f (Paren l e) = (t, fx, Paren l e') where (t, fx, e') = qType env f e qType env f (Box t e) = (t, fx, Box t e') where (_, fx, e') = qType env f e qType env f (UnBox t e) = (t, fx, UnBox t e') where (_, fx, e') = qType env f e qType env f e = error ("qType, e = " ++ show e) qMatch f t t' e = f t t' e instance QType Elem where qType env f (Elem e) = (t, fx, Elem e') where (t, fx, e') = qType env f e qMatch f t t' (Elem e) = Elem (qMatch f t t' e) instance QType Assoc where qType env f (Assoc ek ev) = (tTuple tk tv, upbound env [fxk,fxv], Assoc ek' ev') where (tk, fxk, ek') = qType env f ek (tv, fxv, ev') = qType env f ev qMatch f t t' a = a instance QType PosArg where qType env f (PosArg e p) = (posRow t r, upbound env [fx,fxp], PosArg e' p') where (t, fx, e') = qType env f e (r, fxp, p') = qType env f p qType env f (PosStar e) = case t of TTuple _ p _ -> (p, fx, PosStar e') where (t, fx, e') = qType env f e qType env f PosNil = (posNil, fxPure, PosNil) qMatch f TVar{} r p = p qMatch f r TVar{} p = p qMatch f r r' (PosArg e p) | TRow{} <- r, TRow{} <- r' = PosArg (qMatch f (rtype r) (rtype r') e) (qMatch f (rtail r) (rtail r') p) | otherwise = error ("#### rtail " ++ prstr r ++ " < " ++ prstr r' ++ " for " ++ prstr (PosArg e p)) qMatch f _ _ PosNil = PosNil instance QType KwdArg where qType env f (KwdArg n e k) = (kwdRow n t r, upbound env [fx,fxk], KwdArg n e' k') where (t, fx, e') = qType env f e (r, fxk, k') = qType env f k qType env f (KwdStar e) = case t of TTuple _ _ k -> (k, fx, KwdStar e') where (t, fx, e') = qType env f e qType env f KwdNil = (kwdNil, fxPure, KwdNil) qMatch f TVar{} r k = k qMatch f r TVar{} k = k qMatch f r r' (KwdArg n e k) | TRow{} <- r, TRow{} <- r' = KwdArg n (qMatch f (rtype r) (rtype r') e) (qMatch f (rtail r) (rtail r') k) | otherwise = error ("#### rtail " ++ prstr r ++ " < " ++ prstr r' ++ " for " ++ prstr (KwdArg n e k)) qMatch f _ _ KwdNil = KwdNil instance QType Pattern where qType env f (PWild l (Just t)) = (t, fxPure, PWild l (Just t)) qType env f (PVar l n (Just t)) = (t, fxPure, PVar l n (Just t)) qType env f (PVar l n Nothing) = (typeOf env (eVar n), fxPure, PVar l n Nothing) qType env f (PTuple l ps ks) = (tTuple (typeOf env ps) (typeOf env ks), fxPure, PTuple l ps ks) qType env f (PList l ps p) = (tList (typeOf env $ head ps), fxPure, PList l ps p) qType env f (PParen l p) = (typeOf env p, fxPure, PParen l p) qMatch f t t' p = p instance QType PosPat where qType env f (PosPat p ps) = (posRow (typeOf env p) (typeOf env ps), fxPure, PosPat p ps) qType env f (PosPatStar p) = (typeOf env p, fxPure, PosPatStar p) qType env f PosPatNil = (posNil, fxPure, PosPatNil) qMatch f r r' p = p instance QType KwdPat where qType env f (KwdPat n p ps) = (kwdRow n (typeOf env p) (typeOf env ps), fxPure, KwdPat n p ps) qType env f (KwdPatStar p) = (typeOf env p, fxPure, KwdPatStar p) qType env f KwdPatNil = (kwdNil, fxPure, KwdPatNil) qMatch f r r' p = p instance QType Comp where qType env f (CompFor l p e c) = (tNone, upbound env [fx,fxc], CompFor l p (qMatch f t (typeOf env p) e') c') where (t, fx, e') = qType env f e (_, fxc, c') = qType env1 f c env1 = define (envOf p) env qType env f (CompIf l e c) = (tNone, upbound env [fx,fxc], CompIf l e' c') where (t, fx, e') = qType env f e (_, fxc, c') = qType env f c qType env f NoComp = (tNone, fxPure, NoComp) qMatch f t t' c = c class EnvOf a where envOf :: a -> TEnv instance (EnvOf a) => EnvOf [a] where envOf = concat . map envOf instance (EnvOf a) => EnvOf (Maybe a) where envOf = maybe [] envOf instance EnvOf PosPar where envOf (PosPar n (Just t) _ p) = (n,NVar t) : envOf p envOf (PosSTAR n (Just t)) = [(n,NVar t)] envOf PosNIL = [] envOf p = error ("### BAD envOf " ++ prstr p) instance EnvOf KwdPar where envOf (KwdPar n (Just t) _ k) = (n,NVar t) : envOf k envOf (KwdSTAR n (Just t)) = [(n,NVar t)] envOf KwdNIL = [] instance EnvOf Comp where envOf (CompFor _ p e c) = envOf p ++ envOf c envOf (CompIf _ e c) = envOf c envOf NoComp = [] instance EnvOf Pattern where envOf (PWild _ (Just t)) = [] envOf (PVar _ n (Just t)) = [(n, NVar t)] envOf (PVar _ n Nothing) = [] envOf (PTuple _ ps ks) = envOf ps ++ envOf ks envOf (PList _ ps p) = envOf ps ++ envOf p envOf (PParen _ p) = envOf p instance EnvOf PosPat where envOf (PosPat p ps) = envOf p ++ envOf ps envOf (PosPatStar p) = envOf p envOf PosPatNil = [] instance EnvOf KwdPat where envOf (KwdPat n p ps) = envOf p ++ envOf ps envOf (KwdPatStar p) = envOf p envOf KwdPatNil = [] instance EnvOf Stmt where envOf (Assign _ ps e) = envOf ps envOf (VarAssign _ ps e) = envOf ps envOf (Decl _ ds) = envOf ds envOf (Signature _ ns sc dec) = [ (n, NSig sc dec Nothing) | n <- ns ] envOf (If _ [Branch e ss] fin) | isPUSHF e = envOf ss ++ envOf fin envOf (If _ bs els) = commonEnvOf ([ ss | Branch _ ss <- bs ] ++ [els]) envOf (Try _ b hs els fin) = commonEnvOf ([ ss | Handler _ ss <- hs ] ++ [b++els]) ++ envOf fin envOf (With _ items b) = envOf b `exclude` bound items envOf s = [] commonEnvOf suites | null liveSuites = [] | otherwise = foldl restrict (envOf $ head liveSuites) (map bound $ tail liveSuites) where liveSuites = filter fallsthru suites instance EnvOf Decl where envOf (Def _ n q p k (Just t) b dec fx doc) = [(n, NDef (TSchema NoLoc q $ TFun NoLoc fx (prowOf p) (krowOf k) t) dec doc)] envOf (Class _ n q as ss doc) = [(n, NClass q (leftpath as) (map dropDefSelf $ envOf ss) doc)] envOf (Actor _ n q p k ss doc) = [(n, NAct q (prowOf p) (krowOf k) (map wrap te) doc)] where te = filter (not . isHidden . fst) $ envOf ss `exclude` statevars ss wrap (n, NDef sc dec doc) = (n, NDef (wrapFX sc) dec doc) wrap (n, i) = (n, i) wrapFX (TSchema l q t) = TSchema l q (if effect t == fxProc then t{ effect = fxAction } else t) dropDefSelf (n, NDef (TSchema l q t) dec doc) = (n, NDef (TSchema l q (dropSelf t dec)) dec doc) dropDefSelf (n, i) = (n, i) -- The following constructs are translated away during type inference: -- envOf (Protocol _ n q as ss) = undefined -- envOf (Extension _ n q as ss) = undefined instance EnvOf Except where envOf (ExceptAll _) = [] envOf (Except _ x) = [] envOf (ExceptAs _ x n) = [(n, NVar $ tCon (TC x []))] instance EnvOf WithItem where envOf (WithItem e p) = envOf p instance EnvOf Branch where envOf _ = [] instance EnvOf Handler where envOf _ = [] instance EnvOf Sliz where envOf _ = [] instance EnvOf OpArg where envOf _ = [] instance EnvOf Elem where envOf _ = [] instance EnvOf Assoc where envOf _ = [] upbound env ts = case lubfold env ts of Just u -> u nvarsOf te = [ (n,t) | (n, NVar t) <- te ] updatesOf stmts = concatMap upd stmts where upd (Assign _ p _) = concatMap uvars p upd (If _ bs els) = concat [ updatesOf ss | Branch _ ss <- bs ] ++ updatesOf els upd (While _ _ ss els) = updatesOf ss ++ updatesOf els upd (Try _ ss hs els fin) = updatesOf ss ++ concat [ updatesOf ss | Handler _ ss <- hs ] ++ updatesOf els ++ updatesOf fin upd _ = [] uvars (PVar _ v Nothing) = [v] uvars (PParen _ p) = uvars p uvars (PTuple _ ps ks) = uvarsP ps ++ uvarsK ks uvars (PList _ ps mbp) = concatMap uvars ps ++ maybe [] uvars mbp uvars _ = [] uvarsP (PosPat p r) = uvars p ++ uvarsP r uvarsP (PosPatStar p) = uvars p uvarsP (PosPatNil) = [] uvarsK (KwdPat _ k r) = uvars k ++ uvarsK r uvarsK (KwdPatStar k) = uvars k uvarsK (KwdPatNil) = [] ================================================ FILE: compiler/lib/src/Acton/Solver.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} module Acton.Solver where import Control.Monad import Control.Monad.Except import qualified Data.Map.Strict as Map import Data.Map.Strict (Map) import qualified Control.Exception import Control.DeepSeq import Utils import Pretty import Acton.Syntax import Acton.Printer import Acton.Builtin import Acton.Names import Acton.Prim import Acton.NameInfo import Acton.Env import Acton.Subst import Acton.TypeEnv run_new_solver = False newSimplify env te cs = simplifyNew env cs oldSimplify env te cs = simplify env te cs noSimplify env te cs = return (cs, []) -- Reduce conservatively and remove entailed constraints simplifyNew :: Env -> Constraints -> TypeM (Constraints,Equations) simplifyNew env cs = do css <- groupCs env cs --traceM ("#### SIMPLIFY NEW " ++ prstr (length cs)) --sequence [ traceM ("## long:\n" ++ render (nest 4 $ vcat $ map pretty cs)) | cs <- css, length cs > 500 ] simplifyGroupsNew env css simplifyGroupsNew env [] = return ([], []) simplifyGroupsNew env (cs:css) = do --traceM ("\n\n######### simplifyNewGroup\n" ++ render (nest 4 $ vcat $ map pretty cs)) eq1 <- reduce [] cs `catchError` \err -> Control.Exception.throw err cs1 <- usubst =<< collectDeferred (cs2,eq2) <- simplifyGroupsNew env css return (cs1++cs2, eq1++eq2) -- Reduce conservatively and remove entailed constraints simplify :: Env -> TEnv -> Constraints -> TypeM (Constraints,Equations) simplify env te cs = do css <- groupCs env cs te <- usubst te --traceM ("#### SIMPLIFY " ++ prstr (length cs)) --sequence [ traceM ("## long:\n" ++ render (nest 4 $ vcat $ map pretty cs)) | cs <- css, length cs > 500 ] simplifyGroups env te css simplifyGroups env te [] = return ([], []) simplifyGroups env te (cs:css) = do --traceM ("\n\n######### simplifyGroup\n" ++ render (nest 4 $ vcat $ map pretty cs)) (cs1,eq1) <- simplify' env te [] cs `catchError` \err -> Control.Exception.throw err (cs2,eq2) <- simplifyGroups env te css return (cs1++cs2, eq1++eq2) simplify' :: Env -> TEnv -> Equations -> Constraints -> TypeM (Constraints,Equations) simplify' env te eq [] = return ([], eq) simplify' env te eq cs = do eq <- reduce eq cs cs <- usubst =<< collectDeferred let len = length cs --when (len > 0) $ traceM ("## Improving " ++ show len) --when (len > 0) $ traceM ("## Improving:\n" ++ render (nest 8 $ vcat $ map pretty cs)) env <- usubst env -- Remove.... te <- usubst te improve env te eq cs quicksimp env eq [] = return ([], eq) quicksimp env eq cs = do eq1 <- reduce eq cs cs1 <- usubst =<< collectDeferred return (cs1, eq1) groupCs env cs = do st <- currentState mark 1 cs m <- foldM group Map.empty cs rollbackState st let css = Map.elems m n = length (concat css) --traceM ("#### Grouped " ++ show n ++ " constraints into " ++ show (map length css) ++ " groups") return css where mark n [] = return n mark n (c : cs) = do tvs <- ufree <$> usubst c tvs' <- ufree <$> usubst (map tUni $ attrfree c) sequence [ unify (noinfo 1) (newUnivarToken n) (tUni tv) | tv <- nub (tvs++tvs') ] mark (n+1) cs group m c = do tvs <- ufree <$> usubst c let tv = case tvs of [] -> tv0; tv:_ -> tv return $ Map.insertWith (++) tv [c] m attrfree c@(Sel _ _ _ _ n _) = allConAttrUFree env n attrfree c@(Mut _ _ _ n _) = allConAttrUFree env n attrfree _ = [] TUni _ tv0 = newUnivarToken 0 ---------------------------------------------------------------------------------------------------------------------- -- solve ---------------------------------------------------------------------------------------------------------------------- -- ################################################################################################################### data Newrank = R_red | R_pos TUni [Type] | R_low TUni [Type] | R_neg TUni [Type] | R_amb TUni [Type] | R_var TUni TUni | R_ret deriving (Show) weight R_red{} = 0 weight R_pos{} = 1 weight R_low{} = 2 weight R_neg{} = 3 weight R_amb{} = 4 weight R_var{} = 5 weight R_ret{} = 6 instance Eq Newrank where a == b = weight a == weight b instance Ord Newrank where a <= b = weight a <= weight b info0 = noinfo 0 newrank pol (Sub info env _ t1 t2) = newrank pol (Cast info env t1 t2) newrank pol (Cast _ env (TUni _ v) (TUni _ v')) = R_var v v' newrank pol (Cast _ env t (TUni _ v)) | pos && not neg = R_pos v alts | otherwise = R_low v alts where (pos, neg) = (v `elem` fst pol, v `elem` snd pol) alts = reverse $ allAbove (limitQuant v env) t newrank pol (Cast _ env (TUni _ v) t) | TOpt _ (TUni _ v') <- t = R_var v v' | neg && pos = R_ret | neg = R_neg v alts | otherwise = R_amb v alts where (pos, neg) = (v `elem` fst pol, v `elem` snd pol) alts = allBelow (limitQuant v env) t newrank pol (Proto _ env _ (TUni _ v) p) -- Proto behaves as an upper type bound | neg && pos = R_ret -- | neg = R_neg v alts -- Later, when protos have become proper types | neg || pos = R_ret | otherwise = R_amb v alts where (pos, neg) = (v `elem` fst pol, v `elem` snd pol) alts = allBelowProto (limitQuant v env) p newrank pol (Sel _ env _ (TUni _ v) n _) -- Sel behaves as an upper type/proto bound | neg && pos = R_amb v alts | neg = R_neg v alts | otherwise = R_amb v alts where (pos, neg) = (v `elem` fst pol, v `elem` snd pol) alts = allClassAttr env_ n ++ allProtoAttr env_ n ++ [wildTuple] env_ = limitQuant v env newrank pol (Mut _ env (TUni _ v) n _) = R_amb v alts -- Mut behaves as an upper type bound where alts = allClassAttr (limitQuant v env) n newrank pol (Seal _ env (TUni _ v)) | uvkind v == KFX = R_amb v [fxAction, fxPure] newrank pol c = R_red newsolve :: Env -> TEnv -> Equations -> Constraints -> TypeM (Equations, Constraints) newsolve env te eq cs = do te <- usubst te cs <- usubst cs newsolve' env te eq cs newsolve' env te eq [] = return (eq, []) -- done newsolve' env te eq cs = do let pol = closePolVars (polvars te) cs st <- currentState case head $ sort $ map (newrank pol) cs of R_red -> do -- reducible eq <- reduce eq cs cs <- collectDeferred newsolve env te eq cs R_pos v ts -> -- positive lower con newtry env st te eq cs v ts R_low v ts -> -- must-solve lower con newtry env st te eq cs v ts R_neg v ts -> -- negative upper con newtry env st te eq cs v ts R_amb v ts -> -- must-solve upper con newtry env st te eq cs v ts R_var v v' -> do -- var-var unify info0 (tUni v) (tUni v') newsolve env te eq cs R_ret -> do -- acceptable upper con (eq,cs) <- validate env eq cs coalesce env eq cs newtry env st te eq cs v [] = noSolve0 env (Just $ tUni v) [] cs newtry env st te eq cs v (t:ts) = (unify info0 (tUni v) t >> newsolve env te eq cs) `catchError` const (rollbackState st >> newtry env st te eq cs v ts) validate env eq cs = do st <- currentState _ <- newsolve env [] eq cs -- check that a solution exists cs' <- usubst cs let us = nub $ concat [ ufree c | (c,c') <- cs `zip` cs', not $ null $ vfree c' ] ts <- usubst (map tUni us) -- collect scope dependent substitution let s = [ (u,t) | (u,t) <- us `zip` ts, t /= tUni u ] rollbackState st uextend s -- apply to old state eq <- reduce eq cs cs <- collectDeferred return (eq, cs) coalesce env eq cs = red env eq [] cs where red env eq cs [] = return (eq, cs) red env eq cs (Cast _ _ (TUni _ v) t : cs') | t' : _ <- hits = do eq' <- reduce eq [Cast info0 env t' t] red env eq' cs cs' where hits = [ t' | Cast _ env' (TUni _ v') t' <- cs++cs', v'==v, headcast env t' t ] red env eq cs (Sub _ _ w (TUni _ v) t : cs') | (w',t') : _ <- hits = do w2 <- newWitness let eq' = mkEqn env w (wFun (tUni v) t) (compWit (tUni v) w2 w') eq <- reduce (eq':eq) [Sub info0 env w2 t' t] red env eq cs cs' where hits = [ (w',t') | Sub _ _ w' (TUni _ v') t' <- cs++cs', v'==v, headcast env t' t ] red env eq cs (Proto _ _ w (TUni _ v) p : cs') | (w',p') : _ <- hits = do w2 <- newWitness let eq' = mkEqn env w (proto2type (tUni v) p) (compWit (tUni v) w2 w') eq <- reduce (eq':eq) [Sub info0 env w2 (tCon p') (tCon p)] red env eq cs cs' where hits = [ (w',p') | Proto _ _ w' (TUni _ v') p' <- cs++cs', v'==v, headcast env (tCon p') (tCon p) ] red env eq cs (c : cs') = red env eq (c:cs) cs' -- ################################################################################################################### data Rank = RRed { cstr :: Constraint } | RSealed { tgt :: TUni } | RTry { tgt :: TUni, alts :: [Type], rev :: Bool } | RVar { tgt :: TUni, alts :: [Type] } | RSkip deriving (Show) instance Eq Rank where RRed _ == RRed _ = True RSealed v1 == RSealed v2 = v1 == v2 RTry v1 _ _ == RTry v2 _ _ = v1 == v2 RVar v1 _ == RVar v2 _ = v1 == v2 RSkip == RSkip = True _ == _ = False instance Pretty Rank where pretty (RRed c) = text "" <+> pretty c pretty (RSealed v) = pretty v <+> text "sealed" pretty (RTry v ts rev) = pretty v <+> braces (commaSep pretty ts) Pretty.<> (if rev then char '\'' else empty) pretty (RVar v ts) = pretty v <+> char '~' <+> commaSep pretty ts pretty RSkip = text "" solve :: Env -> (Constraint -> Bool) -> TEnv -> Equations -> Constraints -> TypeM (Constraints,Equations) solve env select te eq cs = do css <- groupCs env cs te <- usubst te solveGroups env select te eq css solveGroups env select te eq [] = return ([], eq) solveGroups env select te eq (cs:css) = do --traceM ("\n\n######### solveGroup\n" ++ render (nest 4 $ vcat $ map pretty cs)) --traceM (" ### te:\n" ++ render (nest 4 $ vcat $ map pretty te)) (cs1,eq1) <- solve' env select [] te eq cs `catchError` \err -> Control.Exception.throw err (cs2,eq2) <- solveGroups env select te eq1 css return (cs1++cs2, eq2) solve' env select hist te eq cs | not $ null vargoals = do --traceM (unlines [ "### var goal " ++ prstr t ++ " ~ " ++ prstrs alts | RVar t alts <- vargoals ]) --traceM ("### var goals: " ++ show (sum [ length alts | RVar t alts <- vargoals ])) sequence [ unify (noinfo 2) (tUni v) t | RVar v alts <- vargoals, t <- alts ] proceed hist eq cs | any not keep_evidence = noSolve0 env Nothing [] keep_cs | null solve_cs || null goals = return (keep_cs, eq) | otherwise = do st <- currentState --traceM ("## keep:\n" ++ render (nest 8 $ vcat $ map pretty keep_cs)) --traceM ("## solve:\n" ++ render (nest 8 $ vcat $ map pretty solve_cs)) --traceM ("## ranks:\n" ++ render (nest 8 $ vcat $ map pretty rnks)) --traceM ("## optvs: " ++ prstrs optvs) --traceM ("## posvs: " ++ prstrs posvs) --traceM ("## negvs: " ++ prstrs negvs) case head goals of RRed c -> do --traceM ("### reduce " ++ prstr c) proceed hist eq cs RSealed v -> do --traceM ("### try goal " ++ prstr v ++ ", candidates: " ++ prstrs [fxAction, fxPure]) tryAlts st v [fxAction, fxPure] RTry v alts r -> do --traceM ("### try goal " ++ prstr v ++ ", candidates: " ++ prstrs alts ++ if r then " (rev)" else "") tryAlts st v alts RVar v alts -> do --traceM ("### var goal " ++ prstr v ++ ", unifying with " ++ prstrs alts) unifyM (noinfo 3) alts (repeat $ tUni v) >> proceed hist eq cs RSkip -> return (keep_cs, eq) where (solve_cs, keep_cs) = partition select cs keep_evidence = [ hasWitness env t p | Proto _ env _ t p <- keep_cs ] (vargoals, goals) = span isVar $ sortOn deco $ condense env rnks rnks = map (rank env) solve_cs tryAlts st tv [] = do --traceM ("### FAIL " ++ prstr tv ++ ":\n" ++ render (nest 4 $ vcat $ map pretty cs)) let ts = map (\n -> tCon (TC (noQ ('t':show n)) [])) [0..] vs = filter (\v -> length (filter (\c -> v `elem` ufree c) cs) > 1) (nub (ufree cs)) cs' = if length cs == 1 then cs else filter (not . useless vs) cs vs' = filter (\v -> length (filter (\c -> v `elem` ufree c) cs') > 1) (nub (ufree cs')) sequence [ usubstitute uv t | (uv,t) <- vs' `zip` ts ] cs' <- usubst cs' noSolve0 env (Just $ tUni tv) (take (length vs') ts) cs' tryAlts st tv (t:ts) = tryAlt tv t `catchError` const ( do --traceM ("=== ROLLBACK " ++ prstr tv) rollbackState st >> tryAlts st tv ts) tryAlt v (TCon _ c) | isProto env (tcname c) = do p <- instwildcon env c w <- newWitness --traceM (" # trying " ++ prstr v ++ " (" ++ prstr p ++ ")") proceed hist eq (Proto (noinfo 4) env w (tUni v) p : cs) tryAlt v (TTuple _ _ _) | not $ null attrs = do t <- instwild env KType (tTupleK $ foldr (\n -> kwdRow n tWild) tWild attrs) --traceM (" # trying tuple " ++ prstr v ++ " = " ++ prstr t) unify (noinfo 5) (tUni v) t proceed (t:hist) eq cs where selsOf cs = sortBy (\a b -> compare (nstr a) (nstr b)) $ nub [ n | Sel _ _ _ (TUni _ v') n _ <- cs, v' == v ] attrs = nub $ selsOf solve_cs \\ valueKWs tryAlt v t | uvkind v == KFX = do t <- instwild env (uvkind v) t --traceM (" # TRYING " ++ prstr v ++ " = " ++ prstr t) unify (noinfo 5) (tUni v) t (cs,eq) <- quicksimp env eq cs hist <- usubst hist te <- usubst te solve' env select hist te eq cs tryAlt v t = do t <- instwild env (uvkind v) t --traceM (" # trying " ++ prstr v ++ " = " ++ prstr t) unify (noinfo 5) (tUni v) t proceed (t:hist) eq cs proceed hist eq cs = do te <- usubst te (cs,eq) <- simplify' env te eq cs te <- usubst te hist <- usubst hist solve' env select hist te eq cs condense env rs = map cond (group rs) where cond (RRed c : rs) = RRed c cond (RSealed v : rs) = RSealed v cond (RTry v as r : rs) = RTry v (if rev' then subrev ts' else ts') rev' where ts = foldr intersect as $ map alts rs ts' = if v `elem` optvs then ts \\ [tOpt tWild] else ts -- rev' = (or $ r : map rev rs) || v `elem` posvs -- (new, matches new solver but picks bad order for lower None) rev' = (and $ r : map rev rs) || v `elem` posvs -- (old, incorrect in general, but avoids the None problem) cond (RVar v as : rs) = RVar v (foldr union as $ map alts rs) cond (RSkip : rs) = RSkip cond rs = error ("### condense " ++ show rs) subrev [] = [] subrev (t:ts) = subrev ts1 ++ t : subrev ts2 where (ts1,ts2) = partition (\t' -> castable' t' t) ts -- Interim: the env above is a simplification, it won't necessarily contain all TVars castable' t'@TVar{} t = True -- But a TVar is less than any of its bounds anyway castable' t' t@TVar{} = False -- And vice versa castable' t' t = castable env t' t group [] = [] group (r:rs) = (r : rs1) : group rs2 where (rs1,rs2) = partition (==r) rs optvs = optvars hist embvs = embvars cs univs = univars cs (posvs, negvs) = closePolVars (polvars te) cs isVar RVar{} = True isVar _ = False deco (RRed cs) = (0, 0, 0, 0) deco (RSealed v) = (2, 0, 0, 0) deco (RTry v as r) = (w, length as, length $ filter (==v) embvs, length $ filter (==v) univs) where w | uvkind v == KFX = 5 -- effect search, last to be explored | [TTuple{}] <- as = 4 -- default selection solution, deferred search | otherwise = 3 -- types and rows, normal search deco (RVar v as) = (6, length as, 0, 0) deco (RSkip) = (7, 0, 0, 0) -- subrev [int,Pt,float,CPt,C3Pt] = [] ++ int : subrev [Pt,float,CPt,C3Pt] -- = int : subrev [CPt,C3Pt] ++ Pt : subrev [float] -- = int : [C3Pt] ++ CPt ++ subrev [] ++ Pt : [] ++ float : subrev [] -- = int : C3Pt : CPt : Pt : float rank :: Env -> Constraint -> Rank rank _ (Sub info env _ t1 t2) = rank env (Cast info env t1 t2) rank _ (Cast _ env (TUni _ v) t2@TUni{}) = RVar v [t2] rank _ (Cast _ env (TUni _ v) t2) | TOpt _ t2@TUni{} <- t2 = RVar v [t2] | otherwise = RTry v (allBelow (limitQuant v env) t2) False rank _ (Cast _ env t1 (TUni _ v)) = RTry v (allAbove (limitQuant v env) t1) True rank _ (Proto _ env _ (TUni _ v) p) = RTry v ts False where ts = allBelowProto (limitQuant v env) p rank _ (Sel _ env _ (TUni _ v) n _) = RTry v (allClassAttr env_ n ++ allProtoAttr env_ n ++ [wildTuple]) False where env_ = limitQuant v env rank _ (Mut _ env (TUni _ v) n _) = RTry v (allClassAttr (limitQuant v env) n) False rank _ (Seal _ env (TUni _ v)) | uvkind v == KFX = RSealed v | otherwise = RSkip rank _ c = RRed c wildTuple = tTuple tWild tWild ------------------------------------------------------------------------------------------------------------------------- class OptVars a where optvars :: a -> [TUni] instance (OptVars a) => OptVars [a] where optvars = concat . map optvars instance OptVars Constraint where optvars (Cast _ _ t1 t2) = optvars [t1, t2] optvars (Sub _ w _ t1 t2) = optvars [t1, t2] optvars (Proto _ w _ t p) = optvars t ++ optvars p optvars (Sel _ w _ t1 n t2) = optvars [t1, t2] optvars (Mut _ _ t1 n t2) = optvars [t1, t2] optvars (Seal _ _ t) = optvars t instance OptVars Type where optvars (TOpt _ (TUni _ v)) = [v] optvars (TOpt _ t) = optvars t optvars (TCon _ c) = optvars c optvars (TFun _ fx p k t) = optvars [p, k, t] optvars (TTuple _ p k) = optvars [p, k] optvars (TRow _ _ _ t r) = optvars [t, r] optvars (TStar _ _ r) = optvars r optvars _ = [] instance OptVars TCon where optvars (TC n ts) = optvars ts embvars cs = concat $ map emb cs where emb (Cast _ _ (TUni _ v) (TUni _ v')) = [] emb (Cast _ _ (TUni _ v) t) = ufree t emb (Cast _ _ t (TUni _ v)) = ufree t emb (Sub _ _ _ (TUni _ v) (TUni _ v')) = [] emb (Sub _ _ _ (TUni _ v) t) = ufree t emb (Sub _ _ _ t (TUni _ v)) = ufree t emb (Proto _ _ _ (TUni _ v) p) = ufree p emb (Proto _ _ _ (TCon _ c) p) = ufree c ++ ufree p emb (Sel _ _ _ (TUni _ v) n t) = ufree t emb (Mut _ _ (TUni _ v) n t) = ufree t emb _ = [] univars cs = concat $ map uni cs where uni (Cast _ _ (TUni _ v) (TUni _ v')) = [v,v'] uni (Sub _ _ _ (TUni _ v) (TUni _ v')) = [v,v'] uni _ = [] allAbove env (TCon _ tc) = tOpt tWild : map tCon tcons where n = tcname tc tcons = allAncestors env tc ++ [schematic' tc] allAbove env (TVar _ tv) = allAbove env (tCon tc) ++ [tVar tv] where tc = findTVBound env tv allAbove env (TOpt _ t) = [tOpt tWild] allAbove env (TNone _) = [tOpt tWild, tNone] allAbove env (TFun _ _ _ _ _) = [tOpt tWild, tFun tWild tWild tWild tWild] allAbove env (TTuple _ _ _) = [tOpt tWild, tTuple tWild tWild] allAbove env (TFX _ FXProc) = [fxProc] allAbove env (TFX _ FXMut) = [fxProc, fxMut] allAbove env (TFX _ FXPure) = [fxProc, fxMut, fxPure] allAbove env (TFX _ FXAction) = [fxProc, fxAction] allBelow env (TCon _ tc) = map tCon tcons ++ map tVar tvars where tcons = schematic' tc : allDescendants env tc tvars = tvarDescendants env tcons allBelow env (TVar _ tv) = [tVar tv] allBelow env (TOpt _ t) = tOpt tWild : allBelow env t ++ [tNone] allBelow env (TNone _) = [tNone] allBelow env (TFun _ _ _ _ _) = [tFun tWild tWild tWild tWild] allBelow env (TTuple _ _ _) = [tTuple tWild tWild] allBelow env (TFX _ FXProc) = [fxProc, fxMut, fxPure, fxAction] allBelow env (TFX _ FXMut) = [fxMut, fxPure] allBelow env (TFX _ FXPure) = [fxPure] allBelow env (TFX _ FXAction) = [fxAction] allBelowProto env (TC n [t@TFX{},_]) | n == primWrappedP = reverse [ schematic (wtype w) | w <- witsByPName env n, t == (head $ tcargs $ proto w) ] allBelowProto env p | p == pIdentity = ts ++ [ schematic $ tCon tc | tc <- allActors env ] | p == pEq = ts ++ [tOpt tWild] | otherwise = ts where ts = reverse [ schematic (wtype w) | w <- witsByPName env (tcname p) ] -- includes tvars allClassAttr env n = map tCon tcons ++ map tVar tvars where tcons = allConAttr env n tvars = tvarDescendants env tcons allProtoAttr env n = map tCon pcons ++ concatMap (allBelowProto env) pcons where pcons = allPConAttr env n ---------------------------------------------------------------------------------------------------------------------- -- reduce ---------------------------------------------------------------------------------------------------------------------- reduce :: Equations -> Constraints -> TypeM Equations reduce eq [] = return eq reduce eq (c:cs) = do c <- usubst c --traceM (" reduce " ++ prstr c) eq1 <- reduce' eq c reduce eq1 cs reduce' :: Equations -> Constraint -> TypeM Equations reduce' eq c@(Cast i env t1 t2) = do cast' env i t1 t2 return eq reduce' eq c@(Sub i env w t1 t2) = sub' env i eq w t1 t2 reduce' eq c@(Proto _ env w TUni{} p) = do defer [c]; return eq reduce' eq c@(Proto _ env w t@(TVar _ tv) p) | [wit] <- witSearch = do (eq',cs) <- solveProto env wit w t p reduce (eq'++eq) cs | [wit] <- witSearch' = do (eq',cs) <- solveProto env wit w (tCon tc) p reduce (eq'++eq) cs where witSearch = findWitness env t p tc = findTVBound env tv witSearch' = findWitness env (tCon tc) p reduce' eq c@(Proto _ env w t@(TCon _ tc) p) | tcname p == qnIdentity, isActor env (tcname tc) = do let e = eCall (eQVar primIdentityActor) [] return (mkEqn env w (proto2type t p) e : eq) | [wit] <- witSearch = do (eq',cs) <- solveProto env wit w t p reduce (eq'++eq) cs where witSearch = findWitness env t p reduce' eq c@(Proto _ env w t@(TFX _ tc) p) | [wit] <- witSearch = do (eq',cs) <- solveProto env wit w t p reduce (eq'++eq) cs where witSearch = findWitness env t p reduce' eq c@(Proto info env w t@(TOpt _ t') p) | tcname p == qnEq = do w' <- newWitness let e = eCall (tApp (eQVar primEqOpt) [t']) [eVar w'] reduce (mkEqn env w (proto2type t p) e : eq) [Proto info env w' t' p] reduce' eq c@(Proto _ env w t@(TNone _) p) | tcname p == qnEq = return (mkEqn env w (proto2type t p) (eQVar primWEqNone) : eq) reduce' eq c@(Sel _ env w TUni{} n _) = do defer [c]; return eq reduce' eq c@(Sel _ env w (TVar _ tv) n _) | Just wsc <- attrSearch = do (eq',cs) <- solveSelAttr wsc c reduce (eq'++eq) cs | Just p <- protoSearch = do (eq',cs) <- solveSelProto p c reduce (eq'++eq) cs | otherwise = tyerr n "Attribute not found" where attrSearch = findTVAttr env tv n protoSearch = findProtoByAttr env (NoQ $ tvname tv) n reduce' eq c@(Sel _ env w (TCon _ tc) n _) | Just wsc <- attrSearch = do (eq',cs) <- solveSelAttr wsc c reduce (eq'++eq) cs | Just p <- protoSearch = do (eq',cs) <- solveSelProto p c reduce (eq'++eq) cs | otherwise = tyerr n "Attribute not found" where attrSearch = findAttr env tc n protoSearch = findProtoByAttr env (tcname tc) n reduce' eq c@(Sel info env w t1@(TTuple _ _ TUni{}) n t2) = do defer [c]; return eq reduce' eq c@(Sel info env w t1@(TTuple _ _ r) n t2) | n `elem` valueKWs = do let e = eLambda [(px0,t1)] (eDot (eVar px0) n) return (mkEqn env w (wFun t1 t2) e : eq) | otherwise = do --traceM ("### Sel " ++ prstr c) select r where select (TRow _ _ n' t r) | n == n' = do w' <- newWitness let e = eLambda [(px0,t1)] (eDot (eCallVar w' [eVar px0]) n) reduce (mkEqn env w (wFun t1 t2) e : eq) [Sub info env w' t t2] | otherwise = select r select (TStar _ _ r) = do w' <- newWitness let e = eLambda [(px0,t1)] (eCallVar w' [eDot (eVar px0) attrKW]) reduce (mkEqn env w (wFun t1 t2) e : eq) [Sel info env w' (tTupleK r) n t2] select (TNil _ _) = kwdNotFound0 env info n -- lambda (x:(a:int,b:int,**(c:int))): x.b ==> lambda x: (b=x.b, a=x.a, KW=x.KW).b ==> lambda x: x.b -- lambda (x:(a:int,b:int,**(c:int))): x.c ==> lambda x: (c=x.KW.x, a=x.a, b=x.b, KW=x.KW).c ==> lambda x: x.KW.c reduce' eq c@(Mut _ env TUni{} n _) = do defer [c]; return eq reduce' eq c@(Mut _ env (TVar _ tv) n _) | Just wsc <- attrSearch = do solveMutAttr wsc c return eq | otherwise = tyerr n "Attribute not found:" where attrSearch = findTVAttr env tv n reduce' eq c@(Mut _ env (TCon _ tc) n _) | Just wsc <- attrSearch = do solveMutAttr wsc c return eq | otherwise = tyerr n "Attribute not found:" where attrSearch = findAttr env tc n reduce' eq c@(Seal _ env TUni{}) = do defer [c]; return eq reduce' eq c@(Seal _ env t@(TVar _ tv)) = return eq reduce' eq (Seal info env t@(TCon _ tc)) -- | castable env t tObject = tyerr t "Leaking actor seal:" -- when we start prohibit sharing of mutable data | otherwise = reduce eq (map (Seal info env) $ tcargs tc) reduce' eq (Seal _ env t@(TFX _ fx)) -- | fx `elem` [FXMut,FXProc] = tyerr t "Leaking actor seal:" -- | fx `elem` [FXProc] = tyerr t "Leaking actor seal:" | otherwise = return eq reduce' eq (Seal info env t) = reduce eq (map (Seal info env) ts) where ts = leaves t reduce' eq c = noRed0 (scope c) c solveProto env wit w t p = do (cs,t',we) <- instWitness env p wit unify (noinfo 7) t t' return ([mkEqn env w (proto2type t p) we], cs) solveSelAttr (wf,sc,d) (Sel info env w t1 n t2) | d == Just Static = tyerr n "A static method cannot be selected by instance:" | otherwise = do (cs,tvs,t) <- instantiate env sc when (negself t) (tyerr n "A contravariant Self attribute cannot be selected by instance:") w' <- newWitness let e = eLambda [(px0,t1)] (eCallVar w' [app t (tApp (eDot (wf $ eVar px0) n) tvs) $ protoWitsOf cs]) c = Sub (locinfo info 8) env w' (vsubst [(tvSelf,t1)] t) t2 return ([mkEqn env w (wFun t1 t2) e], c:cs) -- e1.__setslice__(sl, e2) -- e1.__setslice__(w_Iterable, sl, e2) -- w_Sliceable.__setslice__(e1, w_Iterable, sl, e2) -- w(e1)(sl,e2) w = lambda x0: lambda p1,p2: w_Sliceable.__setslice__(x0, w1, p1, p2) -- (lambda p1,p2: w_Sliceable.__setslice__(x0, w1, p1, p2))(sl,e2) -- w_Sliceable.__setslice__(x0, w1, sl, e2) w1 = w_Iterable -- w_Sliceable.__setslice__(e1, w_Iterable, sl, e2) solveSelProto pn c@(Sel info env w t1 n t2) = do p <- instwildcon env pn w' <- newWitness (eq,cs) <- solveSelWit (p, eVar w') c return (eq, Proto info env w' t1 p : cs) solveSelWit (p,we) c0@(Sel info env w t1 n t2) = do let Just (wf,sc,d) = findAttr env p n (cs,tvs,t) <- instantiate env sc when (negself t) (tyerr n "A contravariant Self attribute cannot be selected by instance:") w' <- newWitness let e = eLambda [(px0,t1)] (eCallVar w' [app t (tApp (eDot (wf we) n) tvs) $ eVar px0 : protoWitsOf cs]) c = Sub (noinfo 9) env w' (vsubst [(tvSelf,t1)] t) t2 return ([mkEqn env w (wFun t1 t2) e], c:cs) solveMutAttr (wf,sc,dec) c@(Mut info env t1 n t2) = do when (dec /= Just Property) (noMut n) let TSchema _ [] t = sc cast env (locinfo c 10) t2 (vsubst [(tvSelf,t1)] t) ---------------------------------------------------------------------------------------------------------------------- -- witness lookup ---------------------------------------------------------------------------------------------------------------------- findWitness :: Env -> Type -> PCon -> [Witness] findWitness env t p = reverse $ filter (eqhead t . wtype) $ witsByPName env $ tcname p where eqhead (TCon _ c) (TCon _ c') = tcname c == tcname c' eqhead (TFX _ fx) (TFX _ fx') = fx == fx' eqhead (TVar _ v) (TVar _ v') = v == v' eqhead _ _ = False findProtoByAttr env cn n = case filter hasAttr $ witsByTName env cn of [] -> Nothing w:_ -> Just $ schematic' $ proto w where hasAttr w = n `elem` conAttrs env (tcname $ proto w) hasWitness :: Env -> Type -> PCon -> Bool hasWitness env TUni{} p = True hasWitness env (TCon _ c) p | isActor env (tcname c), tcname p == qnIdentity = True hasWitness env t p = not $ null $ findWitness env t p ---------------------------------------------------------------------------------------------------------------------- -- cast ---------------------------------------------------------------------------------------------------------------------- cast :: Env -> ErrInfo -> Type -> Type -> TypeM () cast env info t1 t2 = do t1' <- usubst t1 t2' <- usubst t2 info' <- usubst info --traceM (" cast " ++ prstr t1' ++ " < " ++ prstr t2') cast' env info' t1' t2' castM env info ts1 ts2 = mapM_ (uncurry $ cast env info) (ts1 `zip` ts2) cast' env _ (TWild _) t2 = return () cast' env _ t1 (TWild _) = return () cast' env info (TCon _ c1) (TCon _ c2) | Just (wf,c') <- search = if tcname c1 == tcname c2 && tcname c1 `elem` covariant then castM env info (tcargs c') (tcargs c2) else -- TODO: infer polarities in general! unifyM info (tcargs c') (tcargs c2) where search = findAncestor env c1 (tcname c2) -- as declared as called -- existing expected cast' env info t1@(TFun _ fx1 p1 k1 t1') t2@(TFun _ fx2 p2 k2 t2') | varTails [p1,p2] || varTails [k1,k2] = do --traceM ("## Unifying funs: " ++ prstr t1 ++ " ~ " ++ prstr t2) unify info t1 t2 return () | otherwise = do --traceM ("### Aligning fun " ++ prstr t1 ++ " < " ++ prstr t2) (cs1,ts) <- castpos env info p2 p1 cs2 <- castkwd0 env info ts k2 k1 t1 <- usubst t1 t2 <- usubst t2 let (TFun _ fx1 p1 k1 t1', TFun _ fx2 p2 k2 t2') = (t1, t2) reduce [] (Cast info env fx1 fx2 : Cast info env t1' t2' : cs1 ++ cs2) return () cast' env info t1@(TTuple _ p1 k1) t2@(TTuple _ p2 k2) | varTails [p1,p2] || varTails [k1,k2] = do --traceM ("### Unifying tuples: " ++ prstr t1 ++ " ~ " ++ prstr t2) unify info t1 t2 return () | otherwise = do --traceM ("### Aligning tuple " ++ prstr t1 ++ " < " ++ prstr t2) (cs1,ts) <- castpos env info p1 p2 cs2 <- castkwd0 env info ts k1 k2 t1 <- usubst t1 t2 <- usubst t2 let (TTuple _ p1 k1, TTuple _ p2 k2) = (t1, t2) reduce [] (cs1 ++ cs2) return () cast' env info (TOpt _ t1@TOpt{}) t2 = cast env info t1 t2 cast' env info t1 (TOpt _ t2@TOpt{}) = cast env info t1 t2 cast' env info (TOpt _ t1) (TOpt _ t2) = cast env info t1 t2 cast' env info (TUni _ tv) t2@TNone{} = do usubstitute tv tNone cast env info tNone t2 cast' env info t1@TOpt{} (TUni _ tv) = do t2 <- instwild env KType $ tOpt tWild -- What if tv is in t1??? usubstitute tv t2 cast env info t1 t2 cast' env info t1 (TOpt _ t2) | t1 == t2 = return () cast' env _ (TNone _) (TOpt _ t) = return () cast' env _ (TNone _) (TNone _) = return () cast' env info t1@(TFX _ fx1) t2@(TFX _ fx2) | castFX fx1 fx2 = return () where castFX FXPure FXPure = True castFX FXPure FXMut = True castFX FXPure FXProc = True castFX FXMut FXMut = True castFX FXMut FXProc = True castFX FXProc FXProc = True castFX FXAction FXAction = True castFX FXAction FXProc = True castFX _ _ = False cast' env info (TUni _ tv) t2@TFun{} | uvkind tv == KType = do t1 <- instwild env KType $ tFun tWild tWild tWild tWild usubstitute tv t1 cast env info t1 t2 cast' env info t1@TFun{} (TUni _ tv) -- Should remove this, rejects tv = TOpt... | KType == uvkind tv = do t2 <- instwild env KType $ tFun tWild tWild tWild tWild usubstitute tv t2 cast env info t1 t2 cast' env info (TUni _ tv) t2@TTuple{} | uvkind tv == KType = do t1 <- instwild env KType $ tTuple tWild tWild usubstitute tv t1 cast env info t1 t2 cast' env info (TVar _ tv1) (TVar _ tv2) | tv1 == tv2 = return () cast' env info (TUni _ tv1) (TUni _ tv2) | tv1 == tv2 = return () cast' env info t1@(TUni _ tv) t2 = defer [Cast info env t1 t2] cast' env info t1 t2@(TUni _ tv) = defer [Cast info env t1 t2] cast' env info t1@(TVar _ tv) t2 = cast' env info (tCon tc) t2 where tc = findTVBound env tv cast' env info t1 (TOpt _ t2) = cast env info t1 t2 -- Only matches when t1 is NOT a univar cast' env info t1 t2 = noRed0 env (Cast info env t1 t2) castpos :: Env -> ErrInfo -> PosRow -> PosRow -> TypeM (Constraints, [Type]) castpos env info TUni{} TUni{} = error "INTERNAL ERROR: castpos" castpos env info (TUni _ tv) r2 | tv `elem` ufree r2 = conflictingRow tv -- use rowTail? | otherwise = do r1 <- rowShape env r2 --traceM (" ## castpos L " ++ prstr tv ++ " ~ " ++ prstr r1) usubstitute tv r1 castpos env info r1 r2 castpos env info r1 (TUni _ tv) | tv `elem` ufree r1 = conflictingRow tv -- use rowTail? | otherwise = do r2 <- rowShape env r1 --traceM (" ## castpos R " ++ prstr r2 ++ " ~ " ++ prstr tv) usubstitute tv r2 castpos env info r1 r2 castpos env info (TRow _ _ _ t1 r1) (TRow _ _ _ t2 r2) = do --traceM (" ## castpos A " ++ prstr t1 ++ " < " ++ prstr t2) (cs,ts) <- castpos env info r1 r2 return (Cast info env t1 t2 : cs, ts) castpos env info (TStar _ _ r1) (TStar _ _ r2) = do --traceM (" ## castpos B " ++ prstr (tTupleP r1) ++ " < " ++ prstr (tTupleP r2)) return ([Cast info env (tTupleP r1) (tTupleP r2)], []) castpos env info TNil{} TNil{} = do --traceM (" ## castpos C ") return ([], []) castpos env info (TStar _ _ r1) r2 = do --traceM (" ## castpos D " ++ prstr r1 ++ " ~ " ++ prstr r2) castpos env info r1 r2 castpos env info r1 (TStar _ _ r2) = do --traceM (" ## castpos E " ++ prstr r1 ++ " ~ " ++ prstr r2) castpos env info r1 r2 castpos env info r1@TNil{} r@(TRow _ _ _ t2 r2) | TOpt{} <- t2 = do --traceM (" ## castpos F Opt ~ " ++ prstr t2) castpos env info r1 r2 | otherwise = do --traceM (" ## castpos G Nil ~ " ++ prstr r) posElemNotFound0 env True (Cast info env r1 r) nWild castpos env info (TRow _ _ _ t1 r1) r2@TNil{} = do --traceM (" ## castpos H " ++ prstr t1) (cs,ts) <- castpos env info r1 r2 return (cs, t1 : ts) castkwd0 :: Env -> ErrInfo -> [Type] -> KwdRow -> KwdRow -> TypeM Constraints castkwd0 env info [] r1 r2 = castkwd env info r1 r2 castkwd0 env info (t1:ts) r1 (TRow _ _ n t2 r2) = do --traceM (" ## castkwd0 extra pos for " ++ prstr n ++ ": " ++ prstr t1 ++ " < " ++ prstr t2) cs <- castkwd0 env info ts r1 r2 return (Cast info env t1 t2 : cs) castkwd0 env info ts r1 r2 = posElemNotFound0 env False (Cast info env r1 r2) nWild castkwd :: Env -> ErrInfo -> KwdRow -> KwdRow -> TypeM Constraints castkwd env info r1 (TUni _ tv) = do unif r1 r2 <- usubst (tUni tv) castkwd env info r1 r2 where unif TUni{} = error "INTERNAL ERROR: castkwd" unif (TRow _ _ n t r) | tv `elem` ufree r = conflictingRow tv -- use rowTail? | otherwise = do --traceM (" ## castkwd Row - Var: " ++ prstr (tRow KRow n t r) ++ " = " ++ prstr tv) t2 <- newUnivar env r2 <- tRow KRow n t2 <$> newUnivarOfKind KRow env unify info (tUni tv) r2 unif (TStar _ _ r) | tv `elem` ufree r = conflictingRow tv -- use rowTail? | otherwise = do --traceM (" ## castkwd Star - Var: " ++ prstr (tStar KRow r) ++ " = " ++ prstr tv) r2 <- tStar KRow <$> newUnivarOfKind KRow env unify info (tUni tv) r2 unif TNil{} = do --traceM (" ## castkwd Nil - Var: " ++ prstr (tNil KRow) ++ " = " ++ prstr tv) r2 <- pure $ tNil KRow unify info (tUni tv) r2 castkwd env info r1 (TRow _ _ n2 t2 r2) = do (t1,r1') <- pick r1 r2 <- usubst r2 cs <- castkwd env info r1' r2 return (Cast info env t1 t2 : cs) where pick (TUni _ tv) | tv `elem` ufree r2 = conflictingRow tv -- use rowTail? | otherwise = do --traceM (" ## castkwd Var - Row: " ++ prstr (tUni tv) ++ " = " ++ prstr (tRow KRow n2 t2 r2)) r1 <- tRow KRow n2 t2 <$> newUnivarOfKind KRow env unify info (tUni tv) r1 pick r1 pick (TRow _ _ n t r) | n == n2 = do --traceM (" ## castkwd Row - Row: " ++ prstr (tRow KRow n t r) ++ " = " ++ prstr (tRow KRow n2 t2 r2)) return (t, r) | otherwise = do --traceM (" ## castkwd Row - Row: " ++ prstr (tRow KRow n t r) ++ " ≠ " ++ prstr (tRow KRow n2 t2 r2)) kwdNotFound0 env info n2 pick (TStar _ _ r) = do --traceM (" ## castkwd Star - Row: " ++ prstr (tStar KRow r) ++ " ≠ " ++ prstr (tRow KRow n2 t2 r2)) kwdNotFound0 env info n2 pick TNil{} = do --traceM (" ## castkwd None - Row: " ++ prstr (tNil KRow) ++ " ≠ " ++ prstr (tRow KRow n2 t2 r2)) kwdNotFound0 env info n2 castkwd env info r1 (TStar _ _ r2) = match r1 where match (TUni _ tv) | tv `elem` ufree r2 = conflictingRow tv -- use rowTail? | otherwise = do --traceM (" ## castkwd Var - Star: " ++ prstr (tUni tv) ++ " = " ++ prstr (tStar KRow r2)) r1 <- tStar KRow <$> newUnivarOfKind KRow env unify info (tUni tv) r1 match r1 match (TRow _ _ n t r) = do --traceM (" ## castkwd Row - Star: " ++ prstr (tRow KRow n t r) ++ " ≠ " ++ prstr (tStar KRow r2)) kwdUnexpected info n match r1@(TStar _ _ r) | TUni _ v <- r, TUni _ v2 <- r2 = do --traceM (" ## castkwd StarVar - StarVar: " ++ prstr (tStar KRow r) ++ " = " ++ prstr (tStar KRow r2)) unify info r r2 return [] | TUni _ v <- r = do --traceM (" ## castkwd StarVar - Star: " ++ prstr (tStar KRow r) ++ " = " ++ prstr (tStar KRow r2)) castkwd env info r1 r2 | otherwise = do --traceM (" ## castkwd Star - Star: " ++ prstr (tStar KRow r) ++ " = " ++ prstr (tStar KRow r2)) castkwd env info r r2 match r1@TNil{} = do --traceM (" ## castkwd Nil - Star: " ++ prstr (tNil KRow) ++ " ≠ " ++ prstr (tStar KRow r2)) noRed0 env (Cast info env r1 r2) castkwd env info r1 r2@TNil{} = term r1 where term (TUni _ tv) = do --traceM (" ## castkwd Var - Nil: " ++ prstr (tUni tv) ++ " = " ++ prstr (tNil KRow)) r1 <- pure $ tNil KRow unify info (tUni tv) r1 term (tNil KRow) term (TNil _ _) = do --traceM (" ## castkwd Nil - Nil: " ++ prstr (tNil KRow) ++ " = " ++ prstr (tNil KRow)) return [] term (TRow _ _ n t r) = do --traceM (" ## castkwd Row - Nil: " ++ prstr (tRow KRow n t r) ++ " ≠ " ++ prstr (tNil KRow)) kwdUnexpected info n term (TStar _ _ r) = do --traceM (" ## castkwd Star - Nil: " ++ prstr (tStar KRow r) ++ " ≠ " ++ prstr (tNil KRow)) noRed0 env (Cast info env r1 r2) simpInfo env info = case info of DeclInfo l1 l2 n sc msg -> DeclInfo l1 l2 n (simp env sc) msg -- SelInfo l1 l2 n t msg -> SelInfo l1 l2 n (simp env t) msg _ -> info noRed0 env c = do c <- uwild <$> usubst c noRed (c{info = simpInfo env (info c)}) noSolve0 env mbt vs cs = do mbt <- uwild <$> usubst mbt cs <- uwild <$> usubst cs noSolve mbt vs $ map (\c -> c{info = simpInfo env (info c)}) cs posElemNotFound0 env b c n = do c <- uwild <$> usubst c posElemNotFound b (c{info = simpInfo env (info c)}) n kwdNotFound0 env info n = do i <- uwild <$> usubst info kwdNotFound (simpInfo env i) n ---------------------------------------------------------------------------------------------------------------------- -- sub ---------------------------------------------------------------------------------------------------------------------- sub :: Env -> ErrInfo -> Equations -> Name -> Type -> Type ->TypeM Equations sub env info eq w t1 t2 = do t1' <- usubst t1 t2' <- usubst t2 info' <- usubst info sub' env info' eq w t1' t2' sub' :: Env -> ErrInfo -> Equations -> Name -> Type -> Type ->TypeM Equations sub' env _ eq w t1@TWild{} t2 = return (idwit env w t1 t2 : eq) sub' env _ eq w t1 t2@TWild{} = return (idwit env w t1 t2 : eq) -- as declared as called -- existing expected sub' env info eq w t1@(TFun _ fx1 p1 k1 t1') t2@(TFun _ fx2 p2 k2 t2') | varTails [p1,p2] || varTails [k1,k2] = do --traceM ("## Unifying funs: " ++ prstr w ++ ": " ++ prstr t1 ++ " ~ " ++ prstr t2) unify info t1 t2 return (idwit env w t1 t2 : eq) | otherwise = do --traceM ("### Aligning fun " ++ prstr w ++ ": " ++ prstr t1 ++ " < " ++ prstr t2) (cs1,ap,es) <- subpos env info ((map eVar pNames)!!) 0 p2 p1 (cs2,ak) <- subkwd0 env info eVar es k2 k1 t1 <- usubst t1 t2 <- usubst t2 w' <- newWitness let (TFun _ fx1 p1 k1 t1', TFun _ fx2 p2 k2 t2') = (t1, t2) (pp,pk) = (pPar pNames p2, kPar attrKW k2) lambda = eLambda [(px0,t1)] $ Lambda l0 pp pk (eCallVar w' [Call l0 (eVar px0) ap ak]) fx1 reduce (mkEqn env w (wFun t1 t2) lambda : eq) (Cast info env fx1 fx2 : Sub info env w' t1' t2':cs1++cs2) -- existing expected sub' env info eq w t1@(TTuple _ p1 k1) t2@(TTuple _ p2 k2) | varTails [p1,p2] || varTails [k1,k2] = do --traceM ("### Unifying tuples: " ++ prstr w ++ ": " ++ prstr t1 ++ " ~ " ++ prstr t2) unify info t1 t2 return (idwit env w t1 t2 : eq) | otherwise = do --traceM ("### Aligning tuple " ++ prstr w ++ ": " ++ prstr t1 ++ " < " ++ prstr t2) (cs1,ap,es) <- subpos env info (eDotI (eVar px0) . toInteger) 0 p1 p2 (cs2,ak) <- subkwd0 env info (eDot (eVar px0)) es k1 k2 t1 <- usubst t1 t2 <- usubst t2 let (TTuple _ p1 k1, TTuple _ p2 k2) = (t1, t2) lambda = eLambda [(px0,t1)] (Paren l0 $ Tuple l0 ap ak) reduce (mkEqn env w (wFun t1 t2) lambda : eq) (cs1++cs2) sub' env info eq w (TUni _ tv) t2@TFun{} = do t1 <- instwild env KType $ tFun tWild tWild tWild tWild usubstitute tv t1 sub env info eq w t1 t2 sub' env info eq w t1@TFun{} (TUni _ tv) = do t2 <- instwild env KType $ tFun tWild tWild tWild tWild usubstitute tv t2 sub env info eq w t1 t2 sub' env info eq w (TUni _ tv) t2@TTuple{} = do t1 <- instwild env KType $ tTuple tWild tWild usubstitute tv t1 sub env info eq w t1 t2 sub' env info eq w t1@TTuple{} t2@(TUni _ tv) = do defer [Sub info env w t1 t2]; return eq -- Don't let cast solve this by idwit! sub' env info eq w t1@(TVar _ tv1) t2@(TVar _ tv2) | tv1 == tv2 = return (idwit env w t1 t2 : eq) sub' env info eq w t1@(TUni _ tv1) t2@(TUni _ tv2) | tv1 == tv2 = return (idwit env w t1 t2 : eq) | otherwise = do defer [Sub info env w t1 t2]; return eq sub' env info eq w t1@TUni{} t2@TCon{} = do defer [Sub info env w t1 t2]; return eq sub' env info eq w t1@TCon{} t2@TUni{} = do defer [Sub info env w t1 t2]; return eq sub' env info eq w t1 t2 = do cast env info t1 t2 return (idwit env w t1 t2 : eq) rowTail (TRow _ _ _ _ r) = rowTail r rowTail r = r varTails = all (isUnivar . rowTail) rowShape env (TRow _ k n t r) = do t' <- newUnivar env r' <- rowShape env r return (tRow k n t' r') rowShape env (TStar _ k r) = do r' <- rowShape env r return (tStar k r') rowShape env r = return r subpos :: Env -> ErrInfo -> (Int -> Expr) -> Int -> PosRow -> PosRow -> TypeM (Constraints, PosArg, [(Expr,Type)]) subpos env info f i TUni{} TUni{} = error "INTERNAL ERROR: subpos" subpos env info f i (TUni _ tv) r2 | tv `elem` ufree r2 = conflictingRow tv -- use rowTail? | otherwise = do r1 <- rowShape env r2 --traceM (" ## subpos L " ++ prstr tv ++ " ~ " ++ prstr r1) usubstitute tv r1 subpos env info f i r1 r2 subpos env info f i r1 (TUni _ tv) | tv `elem` ufree r1 = conflictingRow tv -- use rowTail? | otherwise = do r2 <- rowShape env r1 --traceM (" ## subpos R " ++ prstr r2 ++ " ~ " ++ prstr tv) usubstitute tv r2 subpos env info f i r1 r2 subpos env info f i (TRow _ _ _ t1 r1) (TRow _ _ _ t2 r2) = do --traceM (" ## subpos A " ++ prstr t1 ++ " < " ++ prstr t2) (cs,as,es) <- subpos env info f (i+1) r1 r2 w <- newWitness return (Sub info env w t1 t2 : cs, PosArg (eCallVar w [f i]) as, es) subpos env info f i (TStar _ _ r1) (TStar _ _ r2) = do --traceM (" ## subpos B " ++ prstr (tTupleP r1) ++ " < " ++ prstr (tTupleP r2)) w <- newWitness return ([Sub info env w (tTupleP r1) (tTupleP r2)], PosStar (eCallVar w [f i]), []) subpos env info f i TNil{} TNil{} = do --traceM (" ## subpos C ") return ([], PosNil, []) subpos env info f i (TStar _ _ r1) r2 = do --traceM (" ## subpos D " ++ prstr r1 ++ " ~ " ++ prstr r2) subpos env info (eDotI (f i) . toInteger) 0 r1 r2 subpos env info f i r1 (TStar _ _ r2) = do --traceM (" ## subpos E " ++ prstr r1 ++ " ~ " ++ prstr r2) (cs,as,es) <- subpos env info f i r1 r2 return (cs, PosStar (eTupleP as), es) subpos env info f i r1@TNil{} r@(TRow _ _ _ t2 r2) | TOpt{} <- t2 = do --traceM (" ## subpos F Opt ~ " ++ prstr t2) (cs,as,es) <- subpos env info f i r1 r2 return (cs, PosArg eNone as, es) | otherwise = do --traceM (" ## subpos G Nil ~ " ++ prstr r) posElemNotFound0 env True (Cast info env r1 r) nWild subpos env info f i (TRow _ _ _ t1 r1) r2@TNil{} = do --traceM (" ## subpos H " ++ prstr t1 ++ " = " ++ prstr (f i)) (cs,as,es) <- subpos env info f (i+1) r1 r2 return (cs, as, (f i, t1) : es) ----------------------- subkwd0 :: Env -> ErrInfo -> (Name -> Expr) -> [(Expr,Type)] -> KwdRow -> KwdRow -> TypeM (Constraints, KwdArg) subkwd0 env info f [] r1 r2 = subkwd env info f [] r1 r2 subkwd0 env info f ((e,t1):es) r1 (TRow _ _ n t2 r2) = do --traceM (" ## subkwd0 extra pos for " ++ prstr n ++ ": " ++ prstr t1 ++ " < " ++ prstr t2) (cs,as) <- subkwd0 env info f es r1 r2 w <- newWitness return (Sub info env w t1 t2 : cs, KwdArg n (eCallVar w [e]) as) subkwd0 env info f ((e,t1):es) r1 r2 = posElemNotFound0 env False (Cast info env r1 r2) nWild subkwd :: Env -> ErrInfo -> (Name -> Expr) -> [Name] -> KwdRow -> KwdRow -> TypeM (Constraints, KwdArg) subkwd env info f seen r1 (TUni _ tv) = do unif f seen r1 r2 <- usubst (tUni tv) subkwd env info f seen r1 r2 where unif f seen TUni{} = error "INTERNAL ERROR: subkwd" unif f seen (TRow _ _ n t r) | n `elem` seen = do --traceM (" ## subkwd (Row) - Var: " ++ prstr (tRow KRow n t r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr tv) unif f (seen\\[n]) r | tv `elem` ufree r = conflictingRow tv -- use rowTail? | otherwise = do --traceM (" ## subkwd Row - Var: " ++ prstr (tRow KRow n t r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr tv) t2 <- newUnivar env r2 <- tRow KRow n t2 <$> newUnivarOfKind KRow env unify info (tUni tv) r2 unif f seen (TStar _ _ r) | tv `elem` ufree r = conflictingRow tv -- use rowTail? | otherwise = do --traceM (" ## subkwd Star - Var: " ++ prstr (tStar KRow r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr tv) r2 <- tStar KRow <$> newUnivarOfKind KRow env unify info (tUni tv) r2 unif f seen TNil{} = do --traceM (" ## subkwd Nil - Var: " ++ prstr (tNil KRow) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr tv) r2 <- pure $ tNil KRow unify info (tUni tv) r2 subkwd env info f seen r1 (TRow _ _ n2 t2 r2) = do (cs1,e) <- pick f seen r1 r1 <- usubst r1 r2 <- usubst r2 (cs2,as) <- subkwd env info f (n2:seen) r1 r2 return (cs1++cs2, KwdArg n2 e as) where pick f seen (TUni _ tv) | tv `elem` ufree r2 = conflictingRow tv -- use rowTail? | otherwise = do --traceM (" ## subkwd Var - Row: " ++ prstr (tVar tv) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tRow KRow n2 t2 r2)) r1 <- tRow KRow n2 t2 <$> newUnivarOfKind KRow env unify info (tUni tv) r1 pick f seen r1 pick f seen (TRow _ _ n t r) | n `elem` seen = do --traceM (" ## subkwd (Row) - Row: " ++ prstr (tRow KRow n t r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tRow KRow n2 t2 r2)) pick f (seen\\[n]) r | n /= n2 = pick f seen r | otherwise = do --traceM (" ## subkwd Row! - Row: " ++ prstr (tRow KRow n t r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tRow KRow n2 t2 r2)) w <- newWitness return ([Sub info env w t t2], eCallVar w [f n]) pick f seen (TStar _ _ r) = do --traceM (" ## subkwd Star - Row: " ++ prstr (tStar KRow r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tRow KRow n2 t2 r2)) pick (eDot (f attrKW)) seen r pick f seen (TNil _ _) | TOpt{} <- t2 = do --traceM (" ## subkwd None - Row: " ++ prstr (tNil KRow) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tRow KRow n2 t2 r2)) return ([], eNone) | otherwise = kwdNotFound0 env info n2 subkwd env info f seen r1 (TStar _ _ r2) = do (cs,e) <- match f seen r1 return (cs, KwdStar e) where match f seen (TUni _ tv) | tv `elem` ufree r2 = conflictingRow tv -- use rowTail? | otherwise = do --traceM (" ## subkwd Var - Star: " ++ prstr (tVar tv) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tStar KRow r2)) r1 <- tStar KRow <$> newUnivarOfKind KRow env unify info (tUni tv) r1 match f seen r1 match f seen r1@(TRow _ _ n t r) | n `elem` seen = do --traceM (" ## subkwd (Row) - Star: " ++ prstr (tRow KRow n t r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tStar KRow r2)) match f (seen\\[n]) r | otherwise = do --traceM (" ## subkwd Row - Star: " ++ prstr (tRow KRow n t r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tStar KRow r2)) (cs,as) <- subkwd env info f seen r1 r2 return (cs, eTupleK as) match f seen r1@(TStar _ _ r) | TUni _ v <- r, TUni _ v2 <- r2 = do --traceM (" ## subkwd StarVar - StarVar: " ++ prstr (tStar KRow r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tStar KRow r2)) unify info r r2 return ([], f attrKW) | TUni _ v <- r = do --traceM (" ## subkwd StarVar - Star: " ++ prstr (tStar KRow r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tStar KRow r2)) (cs,as) <- subkwd env info f seen r1 r2 return (cs, eTupleK as) | otherwise = do --traceM (" ## subkwd Star - Star: " ++ prstr (tStar KRow r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tStar KRow r2)) match (eDot (f attrKW)) seen r match f seen r1@TNil{} = do --traceM (" ## subkwd Nil - Star: " ++ prstr (tNil KRow) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tStar KRow r2)) (cs,as) <- subkwd env info f seen r1 r2 return (cs, eTupleK as) subkwd env info f seen r1 TNil{} = term f seen r1 where term f seen (TUni _ tv) = do --traceM (" ## subkwd Var - Nil: " ++ prstr (tVar tv) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tNil KRow)) r1 <- pure $ tNil KRow unify info (tUni tv) r1 term f seen (tNil KRow) term f seen (TRow _ _ n t r) | n `elem` seen = do --traceM (" ## subkwd (Row) - Nil: " ++ prstr (tRow KRow n t r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tNil KRow)) term f (seen\\[n]) r | otherwise = do --traceM (" ## subkwd Row - Nil: " ++ prstr (tRow KRow n t r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tNil KRow)) kwdUnexpected info n term f seen (TStar _ _ r) = do --traceM (" ## subkwd Star - Nil: " ++ prstr (tStar KRow r) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tNil KRow)) term f seen r term f seen (TNil _ _) = do --traceM (" ## subkwd Nil - Nil: " ++ prstr (tNil KRow) ++ " [" ++ prstrs seen ++ "] ≈ " ++ prstr (tNil KRow)) return ([], KwdNil) {- ---- OK: x. c,a a,c a = x.a Row! Row x. c,a c a c = x.a Row! Row x. c,a . ac (Row) Nil x. . . . Nil Nil ---- OK: x. c,a*(b*A) a,b,c,e a = (x.)a, ... Row! Row x. c,a*(b*A) b,c,e a Star Row x.KW. b*A b,c,e a b = (x.KW.)b Row! Row x. c,a*(b*A) c,e ab c = (x.)c, ... Row! Row x. c,a*(b*A) e abc Star Row x.KW. b*A e abc StarVar Row x.KW.KW. A e abc A ~ e,B Var Row x.KW.KW. e,B e abc e = (x.KW.KW.)e, ... Row! Row x. c,a*(b*(e,B)) . abce (Row) Nil x. *(b*(e,B)) . be Star Nil x.KW. b*(e,B) . be (Row) Nil x.KW. *(e,B) . e Star Nil x.KW.KW e,B . e (Row) Nil x.KW.KW B . B ~ . Var Nil . . Nil Nil x = (c = 1, a = 2, KW = (b = 4, KW = (e = 5))) (a = x.a, b = x.KW.b, c = x.c, e = x.KW.KW.e) ---- OK: x. c*(b*A) c*X c = x.c Row! Row x. c*(b*A) *X c (Row) Star x. *(b*A) *X Star Star x.KW. b*A *X KW = (...) Row Star x.KW. b*A X X ~ b,Y Row Var x.KW. b*A b,Y b = x.KW.b Row! Row x.KW. b*A Y b (Row) Var x.KW. *A Y Y ~ *Z StarVar Var x.KW. *A *Z KW = x.KW.KW A ~ Z StarVar StarVar x = (c = 1, KW = (b = 4, KW = y)) (c = x.c, KW = (b = x.KW.b, KW = x.KW.KW)) ---- OK: x. c,a*(b*A) a,b,c*X a = (x.)a, ... Row! Row x. c,a*(b*A) b,c*X a Star Row x.KW. b*A b,c*X a b = (x.KW.)b, ... Row! Row x. c,a*(b*A) c*X ab c = (x.)c, ... Row! Row x. c,a*(b*A) *X abc (Row) Star x. *(b*A) *X b Star Star x.KW. b*A *X b (Row) Star x.KW. *A *X KW = (x.KW.)KW A ~ X StarVar StarVar x = (c = 1, a = 2, KW = (b = 4, KW = y)) (a = x.a, b = x.KW.b, c = x.c, KW = x.KW.KW) ---- OK: x. c,a*(b*A) a,b,c,e*X a = (x.)a, ... Row! Row x. c,a*(b*A) b,c,e*X a Star Row x.KW. b*A b,c,e*X b = (x.KW.)b, ... Row! Row x. c,a*(b*A) c,e*X ab c = (x.)c, ... Row! Row x. c,a*(b*A) e*X abc Star Row x.KW. b*A e*X b Star Row x.KW.KW. A e*X b A ~ e,B Var Row x.KW.KW. e,B e*X b e = (x.KW.KW.)e Row! Row x. c,a*(b*(e,B)) *X abce (Row) Star x. *(b*(e,B)) *X be Star Star x.KW. b*(e,B) *X be (Row) Star x.KW. *(e,B) *X e Star Star x.KW.KW. e,B *X e (Row) Star x.KW.KW. B *X B ~ *X Var Star x.KW.KW. *X *X KW = (x.KW.KW.)KW StarVar StarVar x = (c = 1, a = 2, KW = (b = 4, KW = (e = 5, KW = y))) (a = x.a, b = x.KW.b, c = x.c, e = x.KW.KW.e, KW = x.KW.KW.KW) ---- OK: x. c,a*A a,b,c,e*X a = (x.)a, ... Row! Row x. c,a*A b,c,e*X a StarVar Row x.KW. A b,c,e*X A ~ b,B Var Row x.KW. b,B b,c,e*X b = (x.KW.)b, ... Row! Row x. c,a*(b,B) c,e*X ab c = (x.)c, ... Row! Row x. c,a*(b,B) e*X abc Star Row x.KW. b,B e*X b B ~ e,C Var Row x.KW. b,e,C e*X b e = (x.KW.)e, ... Row! Row x. c,a*(b,e,C) *X abce (Row) Star x. *(b,e,C) *X be Star Star x.KW. b,e,C *X be (Row) Star x.KW. C *X C ~ *X Var Star x.KW. *X *X KW = (x.KW.)KW StarVar StarVar x = (c = 1, a = 2, KW = (b = 4, e = 5, KW = y)) (a = x.a, b = x.KW.b, c = x.c, e = x.KW.e, KW = x.KW.KW) ---- OK: x. c,a,d*A a,b,c,e*X a = (x.)a, ... Row! Row x. c,a,d*A b,c,e*X a StarVar Row x.KW. A b,c,e*X a A ~ b,B Var Row x.KW. b,B b,c,e*X a b = (x.KW.)b, ... Row! Row x. c,a,d*(b,B) c,e*X ab c = x.c, ... Row! Row x. c,a,d*(b,B) e*X abc Star Row x.KW. b,B e*X b B ~ e,C Var Row x.KW. b,e,C e*X b e = x.KW.e, ... Row! Row x. c,a,d*(b,e,C) *X abce (Row) Star x. d*(b,e,C) *X be KW = (...) Row Star x. d*(b,e,C) X be X ~ d,Y Row Var x. d*(b,e,C) d,Y be d = (x.)d, ... Row! Row x. d*(b,e,C) Y bed (Row) Var x. *(b,e,C) Y be Y ~ *Z Star Var x. *(b,e,C) *Z be Star Star x.KW. b,e,C *Z be (Row) Star x.KW. C *Z C ~ *Z Var Star x.KW. *Z *Z KW = (x.KW.)KW StarVar StarVar x = (c = 1, a = 2, d = 3, KW = (b = 4, e = 5, KW = y)) (a = x.a, b = x.KW.b, c = x.c, e = x.KW.e, KW = (d = x.d, KW = x.KW.KW)) ---- OK: x. c,a*A a,c*X a = (x.)a, ... Row! Row x. c,a*A c*X a c = (x.)c, ... Row! Row x. c,a*A *X ac (Row) Star x. *A *X KW = (x.)KW A ~ X StarVar StarVar x = (c = 1, a = 2, KW = y) (a = x.a, c = x.c, KW = x.KW) ---- OK: x. c,a,d*A a,c*X a = (x.)a, ... Row! Row x. c,a,d*A c*X a c = (x.)c, ... Row! Row x. c,a,d*A *X ac (Row) Star x. d*A *X KW = (...) Row Star x. d*A X X ~ d,Y Row Var x. d*A d,Y d = (x.)d, ... Row! Row x. d*A Y d (Row) Var x. *A Y Y ~ *A Star Var x. *A *A KW = (x.)KW StarVar StarVar x = (c = 1, a = 2, d = 3, KW = y) (a = x.a, c = x.c, KW = (d = x.d, KW = x.KW)) ---- OK: x. c,a,d*A a,c*(d*X) a = (x.)a, ... Row! Row x. c,a,d*A c*(d*X) a c = (x.)c, ... Row! Row x. c,a,d*A *(d*X) ac (Row) Star x. d*A *(d*X) KW = (...) Row Star x. d*A d*X d = x.d, ... Row! Row x. d*A *X d (Row) Star x. *A *X KW = (x.)KW A ~ X StarVar StarVar x = (c = 1, a = 2, d = 3, KW = y) (a = x.a, c = x.c, KW = (d = x.d, KW = x.KW)) ---- OK: x. c,a*A a,c*(d*X) a = (x.)a Row! Row x. c,a*A c*(d*X) a c = (x.)c Row! Row x. c,a*A *(d*X) ac (Row) Star x. *A *(d*X) KW = (...) StarVar Star x. *A d*X Star Row x.KW. A d*X A ~ d,B Var Row x.KW. d,B d*X d = x.KW.d Row! Row x. *(d,B) d*X d Star Star x.KW. d,B *X d (Row) Star x.KW. B *X B ~ *X Var Star x.KW. *X *X KW = x.KW.KW StarVar StarVar x = (c = 1, a = 2, KW = (d = 3, KW = y)) (a = x.a, c = x.c, KW = (d = x.KW.d, KW = x.KW.KW)) ---- OK: x. c,a,d a*X a = x.a Row! Row x. c,a,d *X a (Row) Star x. c,d *X KW = (...) Row Star x. c,d X X ~ c,Y Row Var x. c,d c,Y c = x.c Row! Row x. c,d Y c Y ~ d,Z Row Var x. c,d d,Z c d = x.d Row! Row x. c,d Z cd (Row) Var x. . Z Z ~ . Nil Var x = (c = 1, a = 2, d = 3) (a = x.a, KW = (c = x.c, d = x.d)) ---- OK: x. c,a,d*A a*X a = x.a Row! Row x. c,a,d*A *X a (Row) Star x. c,d*A *X KW = (...) Row Star x. c,d*A X X ~ c,Y (Row) Var x. c,d*A c,Y c = x.c Row! Row x. c,d*A Y c Y ~ d,Z (Row) Var x. c,d*A d,Z c d = x.d Row! Row x. c,d*A Z cd (Row) Var x. *A Z Z ~ *A Star Var x. *A *A KW = x.KW StarVar StarVar x = c = 1, a = 2, d = 3, KW = y) (a = x.a, KW = (c = x.c, d = x.d, KW = x.KW)) -} {- subpos 0 (A,B,*R) (A,B,C,D) = Arg x.0 $ subpos 1 (B,*R) (B,C,D) f = x. = Arg x.0 $ Arg x.1 $ subpos 2 (*R) (C,D) = Arg x.0 $ Arg x.1 $ subpos 0 R (C,D) f = x.2. R ~ (C,D) = Arg x.0 $ Arg x.1 $ subpos 0 (C,D) (C,D) = Arg x.0 $ Arg x.1 $ Arg x.2.0 $ subpos 1 (D) (D) = Arg x.0 $ Arg x.1 $ Arg x.2.0 $ Arg x.2.1 $ subpos 2 () () = Arg x.0 $ Arg x.1 $ Arg x.2.0 $ Arg x.2.1 $ Nil subpos 0 (A,B,C,D) (A,B,*S) = Arg x.0 $ subpos 1 (B,C,D) (B,*S) f = x. = Arg x.0 $ Arg x.1 $ subpos 2 (C,D) (*S) = Arg x.0 $ Arg x.1 $ Arg (subpos 2 (C,D) S) Nil = Arg x.0 $ Arg x.1 $ Arg (subpos 2 (C,D) (C,D)) Nil = Arg x.0 $ Arg x.1 $ Arg (Arg x.2 $ subpos 3 (D) (D)) Nil = Arg x.0 $ Arg x.1 $ Arg (Arg x.2 $ Arg x.3 $ subpos 4 () ()) Nil = Arg x.0 $ Arg x.1 $ Arg (Arg x.2 $ Arg x.3 $ Nil) Nil subpos 0 (A,*R) (A,B,*S) = Arg x.0 $ subpos 1 (*R) (B,*S) f = x. = Arg x.0 $ subpos 0 R (B,*S) f = x.1. R ~ (B,*S) = Arg x.0 $ subpos 0 (B,*S) (B,*S) = Arg x.0 $ Arg x.1.0 $ subpos 1 (*S) (*S) = Arg x.0 $ Arg x.1.0 $ Arg w(x.1.1) Nil -} ---------------------------------------------------------------------------------------------------------------------- -- Variable info ---------------------------------------------------------------------------------------------------------------------- data VInfo = VInfo { varvars :: [(TUni,TUni)], embedded :: [TUni], sealed :: [TUni], ubounds :: Map TUni [Type], lbounds :: Map TUni [Type], pbounds :: Map TUni [(Name,PCon)], mutattrs :: Map TUni [Name], selattrs :: Map TUni [Name] } varvar v1 v2 vi = vi{ varvars = (v1,v2) : varvars vi } embed vs vi = vi{ embedded = vs ++ embedded vi } seal v vi = vi{ sealed = v : sealed vi } ubound v t vi = vi{ ubounds = Map.insertWith (++) v [t] (ubounds vi) } lbound v t vi = vi{ lbounds = Map.insertWith (++) v [t] (lbounds vi) } pbound v w p vi = vi{ pbounds = Map.insertWith (++) v [(w,p)] (pbounds vi) } mutattr v n vi = vi{ mutattrs = Map.insertWith (++) v [n] (mutattrs vi) } selattr v n vi = vi{ selattrs = Map.insertWith (++) v [n] (selattrs vi) } lookup' v m = maybe [] id $ Map.lookup v m varinfo cs = f cs (VInfo [] [] [] Map.empty Map.empty Map.empty Map.empty Map.empty) where f (Cast _ _ (TUni _ v1) (TUni _ v2) : cs) | v1 == v2 = f cs | otherwise = f cs . varvar v1 v2 f (Cast _ _ (TUni _ v) t : cs) = f cs . ubound v t . embed (ufree t) f (Cast _ _ t (TUni _ v) : cs) = f cs . lbound v t . embed (ufree t) f (Sub _ _ _ (TUni _ v1) (TUni _ v2) : cs) | v1 == v2 = f cs | otherwise = f cs . varvar v1 v2 f (Sub _ _ _ (TUni _ v) t : cs) = f cs . ubound v t . embed (ufree t) f (Sub _ _ _ t (TUni _ v) : cs) = f cs . lbound v t . embed (ufree t) f (Proto _ _ w (TUni _ v) p : cs) = f cs . pbound v w p . embed (ufree p) f (Proto _ _ w t p : cs) | not $ null vs = f cs . embed (vs ++ ufree p) where vs = nub $ ufree t f (Mut _ _ (TUni _ v) n t : cs) = f cs . mutattr v n . embed (ufree t) f (Sel _ _ _ (TUni _ v) n t : cs) = f cs . selattr v n . embed (ufree t) f (Sel _ _ _ (TTuple _ _ TUni{}) _ _ : cs) = f cs f (Seal _ _ (TUni _ v) : cs) = f cs . seal v f [] = Just f (_ : cs) = \_ -> Nothing varclose xys = clos [] xys where clos cl [] = Right cl clos cl ((x,y):xys) | (x,y) `elem` cl = clos cl xys | not $ null common = Left (x,y:common) | otherwise = clos ((x,y):cl) (new_below++new_above++xys) where below_x = below x cl above_y = above y cl common = below_x `intersect` above_y new_below = [ (w,y) | w <- below_x ] new_above = [ (x,v) | v <- above_y ] below x cl = [ v | (v,w) <- cl, w==x ] above y cl = [ w | (v,w) <- cl, v==y ] gsimp vi cl obs [] = [] gsimp vi cl obs ((x,y):xys) | not subsumed = gsimp vi cl obs xys | x_obs && y_obs = gsimp vi cl obs xys | x_obs = (x,y) : gsimp vi cl (y:obs) xys | y_obs = (x,y) : gsimp vi cl (x:obs) xys | otherwise = (x,y) : gsimp vi cl obs xys where subsumed = (above x cl \\ [y]) `eq` above y cl && (below y cl \\ [x]) `eq` below x cl && lookup' x (ubounds vi) `subset` lookup' y (ubounds vi) && lookup' y (lbounds vi) `subset` lookup' x (lbounds vi) && rng (lookup' x (pbounds vi)) `eq` rng (lookup' y (pbounds vi)) a `eq` b = a `subset` b && b `subset` a a `subset` b = all (`elem` b) a x_obs = x `elem` obs y_obs = y `elem` obs instwild env k (TWild _) = newUnivarOfKind k env instwild env _ (TFun l e p k t) = TFun l <$> instwild env KFX e <*> instwild env PRow p <*> instwild env KRow k <*> instwild env KType t instwild env _ (TTuple l p k) = TTuple l <$> instwild env PRow p <*> instwild env KRow k instwild env _ (TOpt l t) = TOpt l <$> instwild env KType t instwild env _ (TCon l c) = TCon l <$> instwildcon env c instwild env _ (TRow l k n t r) = TRow l k n <$> instwild env KType t <*> instwild env k r instwild env _ (TStar l k r) = TStar l k <$> instwild env k r instwild env k t = return t instwildcon env c = case tconKind (tcname c) env of KFun ks _ -> TC (tcname c) <$> sequence [ instwild env k t | (k,t) <- ks `zip` tcargs c ] _ -> return $ TC (tcname c) [] mkGLB env (v,ts) | Just t <- glbfold env ts' = do t <- instwild env KType t --traceM (" glb " ++ prstrs ts ++ " = " ++ prstr t) return (v, t) | otherwise = tyerrs ts ("No common subtype:") where ts' = map schematic ts mkLUB env (v,ts) | Just t <- lubfold env ts' = do t <- instwild env KType t --traceM (" lub " ++ prstrs ts ++ " = " ++ prstr t) return (v, t) | otherwise = tyerrs ts ("No common supertype:") where ts' = map schematic ts ---------------------------------------------------------------------------------------------------------------------- -- Improvement ---------------------------------------------------------------------------------------------------------------------- -- Check if the deferred constraint set should be resubmitted -- Unify all var cycles -- Perform G-simplification on internal variables -- Check that there's at least one non-embedded variable -- For all non-embedded variables: replace multiple lower/upper con bounds with a LUB/GLB -- For non-embedded variables with a single lower/upper bound: replace with bound if not negative/positive -- For non-embedded variables with multiple protocol constraints: identify equal and subtype-related protocols -- After improvement: -- headvar is defined -- Cast/Sub bound is either TUni (upper), TCon, TNone (lower), TOpt (upper) or TFX -- acyclic -- G-minimal (constrained vars are observable) -- S-minimal (constrained vars are invariant) -- just single upper/lower bounds -- no closed upper/lower bounds -- no redundant Proto -- no Sel/Mut covered by Cast/Sub/Proto bounds instance Pretty (TUni, [Type]) where pretty (uv, ts) = pretty uv <+> text "<" <+> pretty ts instance Pretty [Type] where pretty ts = brackets (commaSep pretty ts) instance Pretty (TUni, Type) where pretty (uv, t) = pretty uv <+> text "~" <+> pretty t improve :: Env -> TEnv -> Equations -> Constraints -> TypeM (Constraints,Equations) improve env te eq [] = return ([], eq) improve env te eq cs | Nothing <- info = do --traceM (" *Resubmit " ++ show (length cs)) simplify' env te eq cs | Left (v,vs) <- closure = do --traceM (" *Unify cycle " ++ prstr v ++ " = " ++ prstrs vs) sequence [ unify (noinfo 12) (tUni v) (tUni v') | v' <- vs ] simplify' env te eq cs | not $ null gsimple = do --traceM (" *G-simplify " ++ prstrs [ (v,tUni v') | (v,v') <- gsimple ]) --traceM (" *obsvars: " ++ prstrs obsvars) --traceM (" *varvars: " ++ prstrs (varvars vi)) sequence [ unify (noinfo 13) (tUni v) (tUni v') | (v,v') <- gsimple ] simplify' env te eq cs | not $ null cyclic = tyerrs cyclic ("Cyclic subtyping:") | not $ null (multiUBnd++multiLBnd) = do ub <- mapM (mkGLB env) multiUBnd -- GLB of the upper bounds lb <- mapM (mkLUB env) multiLBnd -- LUB of the lower bounds --traceM (" *GLB " ++ prstrs ub) --traceM (" *LUB " ++ prstrs lb) simplify' env te eq (replace ub lb cs) | not $ null posLBnd = do --traceM (" *S-simplify (dn) " ++ prstrs posLBnd) --traceM (" posnames " ++ prstrs (posnames $ envX env)) sequence [ unify (noinfo 15) (tUni v) t | (v,t) <- posLBnd ] simplify' env te eq cs | not $ null negUBnd = do --traceM (" *S-simplify (up) " ++ prstrs negUBnd) --traceM (" posnames " ++ prstrs (posnames $ envX env)) sequence [ unify (noinfo 16) (tUni v) t | (v,t) <- negUBnd ] simplify' env te eq cs | not $ null closUBnd = do --traceM (" *Simplify upper closed bound " ++ prstrs closUBnd) sequence [ unify (noinfo 17) (tUni v) t | (v,t) <- closUBnd ] simplify' env te eq cs | not $ null closLBnd = do --traceM (" *Simplify lower closed bound " ++ prstrs closLBnd) sequence [ unify (noinfo 18) (tUni v) t | (v,t) <- closLBnd ] simplify' env te eq cs | not $ null redEq = do --traceM (" *(Context red) " ++ prstrs (bound redEq)) sequence [ unify (noinfo 19) t1 t2 | (t1,t2) <- redUni ] simplify' env te (redEq++eq) (remove (bound redEq) cs) | not $ null dots = do --traceM (" *Implied mutation/selection solutions " ++ prstrs dots) (eq',cs') <- solveDots mutC selC selP cs simplify' env te (eq'++eq) cs' | not $ null redSeal = do --traceM (" *removing redundant Seal constraints on: " ++ prstrs redSeal) return (filterOut redSeal cs, eq) | otherwise = do --traceM (" *improvement done " ++ show (length cs)) return (cs, eq) where info = varinfo cs Just vi = info closure = varclose (varvars vi) Right vclosed = closure (vvsL,vvsU) = unzip vclosed gsimple = gsimp vi vclosed obsvars (varvars vi) multiUBnd = [ (v,ts) | (v,ts) <- multiUBounds cs, noEmbed v, noLOpt v ] multiLBnd = [ (v,ts) | (v,ts) <- multiLBounds cs, noEmbed v ] lowerBnd = [ (v,t) | (v,[t]) <- Map.assocs (lbounds vi), noEmbed v ] upperBnd = [ (v,t) | (v,[t]) <- Map.assocs (ubounds vi), noEmbed v ] posLBnd = [ (v,t) | (v,t) <- lowerBnd, v `notElem` negvars, implAll env (lookup' v $ pbounds vi) t ] negUBnd = [ (v,t) | (v,t) <- upperBnd, v `notElem` posvars, implAll env (lookup' v $ pbounds vi) t, noDots vi v ] closLBnd = [ (v,t) | (v, [t]) <- Map.assocs (lbounds vi), upClosed env t, implAll env (lookup' v $ pbounds vi) t ] closUBnd = [ (v,t) | (v, [t]) <- Map.assocs (ubounds vi), dnClosed env t, implAll env (lookup' v $ pbounds vi) t, noDots vi v ] (redEq,redUni) = ctxtReduce env cs mutC = findBoundAttrs env (mutattrs vi) (ubounds vi) selC = findBoundAttrs env (selattrs vi) (ubounds vi) selP = findWitAttrs env (selattrs vi) (pbounds vi) dots = dom mutC ++ dom selC ++ dom selP pvars = Map.keys (pbounds vi) ++ ufree (Map.elems (pbounds vi)) dotvars = Map.keys (selattrs vi) ++ Map.keys (mutattrs vi) (posvars0,negvars0) = polvars te `polcat` polvars env (posvars,negvars) = (posvars0++vvsL, negvars0++vvsU) obsvars = posvars0 ++ negvars0 ++ pvars ++ dotvars ++ embedded vi ++ sealed vi boundvars = Map.keys (ubounds vi) ++ Map.keys (lbounds vi) boundprot = ufree (Map.elems $ ubounds vi) ++ ufree (Map.elems $ lbounds vi) cyclic = if null (boundvars\\boundprot) then [ c | c <- cs, headvar c `elem` boundvars ] else [] redSeal = sealed vi \\ (posvars ++ negvars ++ embedded vi ++ Map.keys (ubounds vi) ++ Map.keys (lbounds vi) ++ Map.keys (pbounds vi) ++ Map.keys (mutattrs vi) ++ Map.keys (selattrs vi)) noEmbed v = v `notElem` embedded vi noLOpt v = not $ any optCon $ lookup' v (lbounds vi) where optCon TNone{} = True optCon TOpt{} = True optCon _ = False multiUBounds cs = Map.assocs $ Map.map deOpt $ Map.filter ((>1) . length) $ bnds cs where bnds [] = Map.empty bnds (Cast _ _ TUni{} TUni{} : cs) = bnds cs bnds (Cast _ _ TUni{} (TOpt _ TUni{}) : cs) = bnds cs bnds (Cast _ env (TUni _ v) t : cs) = Map.insertWith (++) v [t] $ bnds cs bnds (Sub _ _ _ TUni{} TUni{} : cs) = bnds cs bnds (Sub _ _ env TUni{} (TOpt _ TUni{}) : cs) = bnds cs bnds (Sub _ _ _ (TUni _ v) t : cs) = Map.insertWith (++) v [t] $ bnds cs bnds (_ : cs) = bnds cs deOpt ts = if all isOpt ts then ts else map unOpt ts where isOpt TOpt{} = True isOpt _ = False unOpt (TOpt _ t) = t unOpt t = t multiLBounds cs = Map.assocs $ Map.map deEnv $ Map.filter ((>1) . length) $ bnds cs where bnds [] = Map.empty bnds (Cast _ _ TUni{} TUni{} : cs) = bnds cs bnds (Cast _ env t (TUni _ v) : cs) = Map.insertWith (++) v [(env,t)] $ bnds cs bnds (Sub _ _ _ TUni{} TUni{} : cs) = bnds cs bnds (Sub _ env _ t (TUni _ v) : cs)= Map.insertWith (++) v [(env,t)] $ bnds cs bnds (_ : cs) = bnds cs deEnv envts | length ts == 1 = ts | otherwise = map deVar envts where ts = nub [ t | (env,t) <- envts ] deVar (env,TVar _ v) = tCon (findTVBound env v) deVar (env,t) = t dnClosed env (TCon _ c) = isActor env (tcname c) dnClosed env (TFX _ FXPure) = True dnClosed env (TFX _ FXAction) = True dnClosed env (TNone _) = True dnClosed env (TNil _ _) = True dnClosed env _ = False upClosed env (TFX _ FXProc) = True upClosed env (TOpt _ _) = True upClosed env (TNil _ _) = True upClosed env _ = False findBoundAttrs env attrs bounds = [ ((v,n),wsc) | (v,ns) <- Map.assocs attrs, n <- ns, wsc <- bounds' v n ] where bounds' v n = [ wsc | TCon _ c <- lookup' v bounds, Just wsc <- [findAttr env c n] ] findWitAttrs env attrs bounds = [ ((v,n), (p, wexpr ws $ eVar w)) | (v,ns) <- Map.assocs attrs, n <- ns, (w,p,ws) <- bounds' v n ] where bounds' v n = [ (w,p,ws) | (w,p0) <- lookup' v bounds, (ws,p) <- findAncestry env p0, n `elem` conAttrs env (tcname p) ] implAll env [] t = True implAll env ps t@TCon{} = and [ hasWitness env t p | (w,p) <- ps ] implAll env ps t@TFX{} = and [ hasWitness env t p | (w,p) <- ps ] implAll env ps t@TOpt{} = all ((`elem` [qnIdentity,qnEq]) . tcname . snd) ps implAll env ps t = False noDots vi v = null (lookup' v $ selattrs vi) && null (lookup' v $ mutattrs vi) replace ub lb cs = ubs ++ lbs ++ cs' where (vss,cs') = unzip $ map repl cs vs = nubBy (\a b -> fst a == fst b) (concat vss) ubs = [ Cast info env (tUni v) t | (v,env) <- vs, Just t <- [lookup v ub] ] lbs = [ Cast info env t (tUni v) | (v,env) <- vs, Just t <- [lookup v lb] ] info = noinfo 14 repl c@(Cast _ _ TUni{} TUni{}) = ([], c) repl c@(Cast _ _ TUni{} (TOpt _ TUni{})) = ([], c) repl (Cast info env (TUni _ v) t) | Just t' <- lookup v ub = ([(v,env)], Cast info env t' t) repl (Cast info env t (TUni _ v)) | Just t' <- lookup v lb = ([(v,env)], Cast info env t t') repl c@(Sub _ _ _ TUni{} TUni{}) = ([], c) repl c@(Sub _ _ _ TUni{} (TOpt _ TUni{})) = ([], c) repl (Sub info env w (TUni _ v) t) | Just t' <- lookup v ub = ([(v,env)], Sub info env w t' t) repl (Sub info env w t (TUni _ v)) | Just t' <- lookup v lb = ([(v,env)], Sub info env w t t') repl c = ([], c) solveDots mutC selC selP cs = do (eqs,css) <- unzip <$> mapM solveDot cs return (concat eqs, concat css) where solveDot c@(Mut _ env (TUni _ v) n _) | Just w <- lookup (v,n) mutC = solveMutAttr w c >> return ([], []) solveDot c@(Sel _ _ env (TUni _ v) n _) | Just w <- lookup (v,n) selC = solveSelAttr w c | Just w <- lookup (v,n) selP = solveSelWit w c solveDot c = return ([], [c]) instance Pretty (TUni,Name) where pretty (v,n) = pretty v Pretty.<> text "." Pretty.<> pretty n ctxtReduce :: Env -> Constraints -> (Equations, [(Type,Type)]) ctxtReduce env cs = ctxtRed env (multiPBounds cs) multiPBounds cs = Map.assocs $ f cs Map.empty where f [] = Map.filter ((>1) . length) f (Proto _ env w (TUni _ v) p : cs) = f cs . Map.insertWith (++) v [(w, p, qlevel env)] f (_ : cs) = f cs ctxtRed :: Env -> [(TUni, [(Name, PCon, Int)])] -> (Equations, [(Type,Type)]) ctxtRed env multiPBnds = (concat eqs, concat unis) where (eqs,unis) = unzip $ map red multiPBnds red (v,wps) = imp v [] [] [] wps imp v eq uni wps ((w,p,i):wps') | (e,p',j):_ <- hits = --trace (" *" ++ prstr w ++ " (level " ++ show i ++ ") covered by " ++ prstr e ++ " (level " ++ show j ++ ")") $ imp v (Eqn (min i j) w (proto2type (tUni v) p) e : eq) ((tcargs p `zip` tcargs p') ++ uni) wps wps' | otherwise = --trace (" (Not covered: " ++ prstr p ++ " in context " ++ prstrs [ w | (w,_,_) <- wps++wps' ] ++ ")") $ imp v eq uni ((w,p,i):wps) wps' where hits = [ (wf $ eVar w', vsubst s p', j) | (w',p0,j) <- wps++wps', j <= i, Just (wf,p') <- [findAncestor env p0 (tcname p)] ] s = [(tvSelf,tUni v)] imp v eq uni wps [] = (reverse eq, uni) remove ws [] = [] remove ws (Proto _ _ w t p : cs) | w `elem` ws = remove ws cs remove ws (c : cs) = c : remove ws cs filterOut vs cs = filter preserve cs where preserve (Seal _ _ (TUni _ v)) = v `notElem` vs preserve _ = True ---------------------------------------------------------------------------------------------------------------------- -- Misc. ---------------------------------------------------------------------------------------------------------------------- px0:px1:px2:_ = xNames app tx e [] = e app (TFun _ fx p k _) e es = Lambda NoLoc p' k' (Call NoLoc e (exp2arg es (pArg p')) (kArg k')) fx where (p',k') = (pPar pNames p, kPar attrKW k) app tx e es = Call NoLoc e (exp2arg es PosNil) KwdNil app2nd (Just Static) tx e es = app tx e es app2nd (Just Property) tx e es = app tx e es app2nd Nothing tx e es = app tx e es app2nd _ tx e [] = e app2nd _ tx e es = Lambda NoLoc p' k' (Call NoLoc e (PosArg pSelf (exp2arg es pArgs)) (kArg k')) fx where TFun _ fx p k _ = tx -- If it already takes a first argument, it must be a function! (p',k') = (pPar pNames p, kPar attrKW k) PosArg pSelf pArgs = pArg p' idwit env w t1 t2 = mkEqn env w (wFun t1 t2) (eLambda [(px0,t1)] (eVar px0)) rowFun PRow r1 r2 = tFun fxPure (posRow (tTupleP r1) posNil) kwdNil (tTupleP r2) rowFun KRow r1 r2 = tFun fxPure (posRow (tTupleK r1) posNil) kwdNil (tTupleK r2) compWit t w1 w2 = eLambda [(px0,t)] (eCallVar w1 [eCallVar w2 [eVar px0]]) rowWit PRow n t r wt wr = eLambda [(px0,tTupleP $ posRow t r)] eTup where eTup = Paren l0 $ Tuple l0 (PosArg e1 (PosStar e2)) KwdNil e1 = eCall (eVar wt) [DotI l0 (eVar px0) 0] e2 = eCall (eVar wr) [RestI l0 (eVar px0) 0] rowWit KRow n t r wt wr = eLambda [(px0,tTupleK $ kwdRow n t r)] eTup where eTup = Paren l0 $ Tuple l0 PosNil (KwdArg n e1 (KwdStar e2)) e1 = eCall (eVar wt) [Dot l0 (eVar px0) n] e2 = eCall (eVar wr) [Rest l0 (eVar px0) n] wFun t1 t2 = tFun fxPure (posRow t1 posNil) kwdNil t2 ================================================ FILE: compiler/lib/src/Acton/SourceProvider.hs ================================================ -- | Source access abstraction used by the compiler and LSP. -- Provides an overlay-first view of files while still allowing disk fallback. -- This is needed because the LSP server must read on-disk files and also -- accept unsaved buffer contents from the editor as overlays. module Acton.SourceProvider ( SourceProvider(..) , SourceSnapshot(..) , diskSourceProvider , readSource ) where import qualified Data.ByteString as B import Data.Time.Clock (UTCTime) import System.Directory (getModificationTime) import System.IO (IOMode(ReadMode), hGetContents, hSetEncoding, openFile, utf8) -- | Snapshot of a file's contents. -- The same contents are available as decoded text and raw bytes. data SourceSnapshot = SourceSnapshot { ssText :: String -- ^ UTF-8 decoded text view. , ssBytes :: B.ByteString -- ^ Raw bytes for hashing or byte-precise work. , ssIsOverlay :: Bool -- ^ True when the snapshot comes from an overlay. } -- | Interface for reading sources with optional in-memory overlays. data SourceProvider = SourceProvider { spReadOverlay :: FilePath -> IO (Maybe SourceSnapshot) -- ^ Return overlay contents for a path, if any. , spReadFile :: FilePath -> IO SourceSnapshot -- ^ Read contents from disk. , spGetModTime :: FilePath -> IO UTCTime -- ^ Retrieve disk modification time. } -- | Read a path, preferring overlay contents when available. readSource :: SourceProvider -> FilePath -> IO SourceSnapshot readSource sp path = do mo <- spReadOverlay sp path case mo of Just snap -> return snap Nothing -> spReadFile sp path -- | Default provider that reads directly from disk with no overlays. diskSourceProvider :: SourceProvider diskSourceProvider = SourceProvider { spReadOverlay = \_ -> return Nothing , spReadFile = \path -> do txt <- readFileUtf8 path bytes <- B.readFile path return SourceSnapshot { ssText = txt , ssBytes = bytes , ssIsOverlay = False } , spGetModTime = getModificationTime } -- | Read a UTF-8 text file without altering newlines or encoding. readFileUtf8 :: FilePath -> IO String readFileUtf8 path = do h <- openFile path ReadMode hSetEncoding h utf8 hGetContents h ================================================ FILE: compiler/lib/src/Acton/Subst.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances #-} module Acton.Subst where import Control.Monad.State.Strict import Acton.Syntax import Acton.Builtin import Acton.Printer import Utils addSelf :: Type -> Maybe Deco -> Type addSelf (TFun l x p k t) (Just NoDec) = TFun l x (posRow tSelf p) k t addSelf t _ = t dropSelf :: Type -> Deco -> Type dropSelf (TFun l x p k t) NoDec | TRow _ _ _ _ p' <- p = TFun l x p' k t | TRow _ _ _ _ k' <- k = TFun l x p k' t dropSelf t _ = t selfType :: PosPar -> KwdPar -> Deco -> Type selfType p k NoDec | TRow _ _ _ t _ <- prowOf p = t | TRow _ _ _ t _ <- krowOf k = t selfType _ _ _ = tSelf qualbound q = [ v | QBind v ps <- q, not $ null ps ] -- VFree ---------------------------------------------------------------------------------------------- class VFree a where vfree :: a -> [TVar] instance VFree a => VFree [a] where vfree = concatMap vfree instance VFree a => VFree (Maybe a) where vfree = maybe [] vfree instance VFree a => VFree (Name,a) where vfree (n, t) = vfree t instance VFree Type where vfree (TVar _ v) = [v] vfree (TCon _ c) = vfree c vfree (TFun _ fx p k t) = vfree fx ++ vfree p ++ vfree k ++ vfree t vfree (TTuple _ p k) = vfree p ++ vfree k vfree (TOpt _ t) = vfree t vfree (TRow _ k n t r) = vfree t ++ vfree r vfree (TStar _ k r) = vfree r vfree _ = [] instance VFree TCon where vfree (TC n ts) = vfree ts instance VFree QBind where vfree (QBind v cs) = vfree cs instance VFree TSchema where vfree (TSchema _ q t) = (vfree q ++ vfree t) \\ qbound q instance VFree PosPar where vfree (PosPar n t e p) = vfree t ++ vfree p vfree (PosSTAR n t) = vfree t vfree PosNIL = [] instance VFree KwdPar where vfree (KwdPar n t e k) = vfree t ++ vfree k vfree (KwdSTAR n t) = vfree t vfree KwdNIL = [] instance VFree Decl where vfree (Def _ n q p k a ss de fx doc) = vfree q ++ vfree p ++ vfree k ++ vfree a ++ vfree ss ++ vfree fx vfree (Actor _ n q p k ss doc) = vfree q ++ vfree p ++ vfree k ++ vfree ss vfree (Class _ n q bs ss doc) = vfree q ++ vfree bs ++ vfree ss vfree (Protocol _ n q bs ss doc) = vfree q ++ vfree bs ++ vfree ss vfree (Extension _ q c bs ss doc) = vfree q ++ vfree c ++ vfree bs ++ vfree ss instance VFree Stmt where vfree (Expr _ e) = vfree e vfree (Assign _ ps e) = vfree ps ++ vfree e vfree (MutAssign _ t e) = vfree t ++ vfree e vfree (AugAssign _ t op e) = vfree t ++ vfree e vfree (Assert _ e mbe) = vfree e ++ vfree mbe vfree (Delete _ t) = vfree t vfree (Return _ mbe) = vfree mbe vfree (Raise _ e) = vfree e vfree (If _ bs els) = vfree bs ++ vfree els vfree (While _ e b els) = vfree e ++ vfree b ++ vfree els vfree (For _ p e b els) = vfree p ++ vfree e ++ vfree b ++ vfree els vfree (Try _ b hs els fin) = vfree b ++ vfree hs ++ vfree els ++ vfree fin vfree (With _ is b) = vfree is ++ vfree b vfree (VarAssign _ ps e) = vfree ps ++ vfree e vfree (After _ e e') = vfree e ++ vfree e' vfree (Decl _ ds) = vfree ds vfree (Signature _ ns tsc d) = vfree tsc vfree s = [] instance VFree Branch where vfree (Branch e b) = vfree e ++ vfree b instance VFree Handler where vfree (Handler ex b) = vfree b instance VFree WithItem where vfree (WithItem e p) = vfree e ++ vfree p instance VFree Expr where vfree (Call l e p k) = vfree e ++ vfree p ++ vfree k vfree (TApp l e ts) = vfree e ++ vfree ts vfree (Let l ss e) = vfree ss ++ vfree e vfree (Async l e) = vfree e vfree (Await l e) = vfree e vfree (Index l e ix) = vfree e ++ vfree ix vfree (Slice l e sl) = vfree e ++ vfree sl vfree (Cond l e1 cond e2) = vfree e1 ++ vfree cond ++ vfree e2 vfree (IsInstance l e c) = vfree e vfree (BinOp l e1 op e2) = vfree e1 ++ vfree e2 vfree (CompOp l e ops) = vfree e ++ vfree ops vfree (UnOp l op e) = vfree e vfree (Dot l e n) = vfree e vfree (Rest l e n) = vfree e vfree (DotI l e i) = vfree e vfree (RestI l e i) = vfree e vfree (Lambda l p k e fx) = vfree p ++ vfree k ++ vfree e ++ vfree fx vfree (Yield l e) = vfree e vfree (YieldFrom l e) = vfree e vfree (Tuple l p k) = vfree p ++ vfree k vfree (List l es) = vfree es vfree (ListComp l e c) = vfree e ++ vfree c vfree (Dict l as) = vfree as vfree (DictComp l a c) = vfree a ++ vfree c vfree (Set l es) = vfree es vfree (SetComp l e c) = vfree e ++ vfree c vfree (Paren l e) = vfree e vfree e = [] instance VFree Pattern where vfree (PWild _ t) = vfree t vfree (PVar _ n t) = vfree t vfree (PParen _ p) = vfree p vfree (PTuple _ p k) = vfree p ++ vfree k vfree (PList _ ps p) = vfree ps ++ vfree p instance VFree PosPat where vfree (PosPat p pp) = vfree p ++ vfree pp vfree (PosPatStar p) = vfree p vfree PosPatNil = [] instance VFree KwdPat where vfree (KwdPat n p kp) = vfree p ++ vfree kp vfree (KwdPatStar p) = vfree p vfree KwdPatNil = [] instance VFree PosArg where vfree (PosArg e p) = vfree e ++ vfree p vfree (PosStar e) = vfree e vfree PosNil = [] instance VFree KwdArg where vfree (KwdArg n e k) = vfree e ++ vfree k vfree (KwdStar e) = vfree e vfree KwdNil = [] instance VFree Elem where vfree (Elem e) = vfree e vfree (Star e) = vfree e instance VFree Assoc where vfree (Assoc k v) = vfree k ++ vfree v vfree (StarStar e) = vfree e instance VFree Comp where vfree (CompFor _ p e c) = vfree p ++ vfree e ++ vfree c vfree (CompIf _ e c) = vfree e ++ vfree c vfree NoComp = [] instance VFree Sliz where vfree (Sliz _ e1 e2 e3) = vfree e1 ++ vfree e2 ++ vfree e3 instance VFree OpArg where vfree (OpArg op e) = vfree e -- VSubst --------------------------------------------------------------------------------------------- class VSubst a where vsubst :: Substitution -> a -> a instance VSubst a => VSubst [a] where vsubst s = map $ vsubst s instance VSubst a => VSubst (Maybe a) where vsubst s = fmap $ vsubst s instance VSubst a => VSubst (Name,a) where vsubst s (n, t) = (n, vsubst s t) instance VSubst Type where vsubst s (TVar l v) = case lookup v s of Just t -> t Nothing -> TVar l v vsubst s (TUni l u) = TUni l u vsubst s (TCon l c) = TCon l (vsubst s c) vsubst s (TFun l fx p k t) = TFun l (vsubst s fx) (vsubst s p) (vsubst s k) (vsubst s t) vsubst s (TTuple l p k) = TTuple l (vsubst s p) (vsubst s k) vsubst s (TOpt l t) = case vsubst s t of t'@TOpt{} -> t' t' -> TOpt l t' vsubst s (TRow l k n t r) = TRow l k n (vsubst s t) (vsubst s r) vsubst s (TStar l k r) = TStar l k (vsubst s r) vsubst s (TNone l) = TNone l vsubst s (TWild l) = TWild l vsubst s (TNil l k) = TNil l k vsubst s (TFX l fx) = TFX l fx instance VSubst TCon where vsubst s (TC n ts) = TC n (vsubst s ts) instance VSubst TVar where vsubst s v = case lookup v s of Just (TVar _ v') -> v' _ -> v instance VSubst TSchema where vsubst s (TSchema l q t) = TSchema l (vsubst s' q) (vsubst s' t) where s' = quantsubst s q (vfree t) quantsubst s [] vs = s quantsubst s q vs = alpha ++ pruned where pruned = s `exclude` qbound q new = nub $ vfree (rng pruned) clash = new `intersect` qbound q alpha = clash `zip` map tVar (tvarSupply \\ avoid) avoid = new ++ vfree q ++ vs instance VSubst QBind where vsubst s (QBind v ts) = QBind (vsubst s v) (vsubst s ts) instance VSubst PosPar where vsubst s (PosPar n t e p) = PosPar n (vsubst s t) e (vsubst s p) vsubst s (PosSTAR n t) = PosSTAR n (vsubst s t) vsubst s PosNIL = PosNIL instance VSubst KwdPar where vsubst s (KwdPar n t e k) = KwdPar n (vsubst s t) e (vsubst s k) vsubst s (KwdSTAR n t) = KwdSTAR n (vsubst s t) vsubst s KwdNIL = KwdNIL instance VSubst Decl where vsubst s (Def l n q p k a ss de fx doc) = Def l n (vsubst r q) (vsubst r p) (vsubst r k) (vsubst r a) (vsubst r ss) de (vsubst r fx) doc where r = quantsubst s q (vfree p ++ vfree k ++ vfree a ++ vfree ss ++ vfree fx) vsubst s (Actor l n q p k ss doc) = Actor l n (vsubst r q) (vsubst r p) (vsubst r k) (vsubst r ss) doc where r = quantsubst s q (vfree p ++ vfree k ++ vfree ss) vsubst s (Class l n q bs ss doc) = Class l n (vsubst s q) (vsubst s bs) (vsubst s ss) doc where r = quantsubst s q (vfree bs ++ vfree ss) vsubst s (Protocol l n q bs ss doc) = Protocol l n (vsubst s q) (vsubst s bs) (vsubst s ss) doc where r = quantsubst s q (vfree bs ++ vfree ss) vsubst s (Extension l q c bs ss doc) = Extension l (vsubst s q) (vsubst s c) (vsubst s bs) (vsubst s ss) doc where r = quantsubst s q (vfree c ++ vfree bs ++ vfree ss) instance VSubst Stmt where vsubst s (Expr l e) = Expr l (vsubst s e) vsubst s (Assign l ps e) = Assign l (vsubst s ps) (vsubst s e) vsubst s (MutAssign l t e) = MutAssign l (vsubst s t) (vsubst s e) vsubst s (AugAssign l t op e) = AugAssign l (vsubst s t) op (vsubst s e) vsubst s (Assert l e mbe) = Assert l (vsubst s e) (vsubst s mbe) vsubst s (Delete l t) = Delete l (vsubst s t) vsubst s (Return l mbe) = Return l (vsubst s mbe) vsubst s (Raise l e) = Raise l (vsubst s e) vsubst s (If l bs els) = If l (vsubst s bs) (vsubst s els) vsubst s (While l e b els) = While l (vsubst s e) (vsubst s b) (vsubst s els) vsubst s (For l p e b els) = For l (vsubst s p) (vsubst s e) (vsubst s b) (vsubst s els) vsubst s (Try l b hs els fin) = Try l (vsubst s b) (vsubst s hs) (vsubst s els) (vsubst s fin) vsubst s (With l is b) = With l (vsubst s is) (vsubst s b) vsubst s (VarAssign l ps e) = VarAssign l (vsubst s ps) (vsubst s e) vsubst s (After l e e') = After l (vsubst s e) (vsubst s e') vsubst s (Decl l ds) = Decl l (vsubst s ds) vsubst s (Signature l ns tsc d) = Signature l ns (vsubst s tsc) d vsubst s stmt = stmt instance VSubst Expr where vsubst s (Call l e p k) = Call l (vsubst s e) (vsubst s p) (vsubst s k) vsubst s (TApp l e ts) = TApp l (vsubst s e) (vsubst s ts) vsubst s (Let l ss e) = Let l (vsubst s ss) (vsubst s e) vsubst s (Async l e) = Async l (vsubst s e) vsubst s (Await l e) = Await l (vsubst s e) vsubst s (Index l e ix) = Index l (vsubst s e) (vsubst s ix) vsubst s (Slice l e sl) = Slice l (vsubst s e) (vsubst s sl) vsubst s (Cond l e1 cond e2) = Cond l (vsubst s e1) (vsubst s cond) (vsubst s e2) vsubst s (IsInstance l e c) = IsInstance l (vsubst s e) c vsubst s (BinOp l e1 op e2) = BinOp l (vsubst s e1) op (vsubst s e2) vsubst s (CompOp l e ops) = CompOp l (vsubst s e) (vsubst s ops) vsubst s (UnOp l op e) = UnOp l op (vsubst s e) vsubst s (Dot l e n) = Dot l (vsubst s e) n vsubst s (Rest l e n) = Rest l (vsubst s e) n vsubst s (DotI l e i) = DotI l (vsubst s e) i vsubst s (RestI l e i) = RestI l (vsubst s e) i vsubst s (Lambda l p k e fx) = Lambda l (vsubst s p) (vsubst s k) (vsubst s e) (vsubst s fx) vsubst s (Yield l e) = Yield l (vsubst s e) vsubst s (YieldFrom l e) = YieldFrom l (vsubst s e) vsubst s (Tuple l p k) = Tuple l (vsubst s p) (vsubst s k) vsubst s (List l es) = List l (vsubst s es) vsubst s (ListComp l e c) = ListComp l (vsubst s e) (vsubst s c) vsubst s (Dict l as) = Dict l (vsubst s as) vsubst s (DictComp l a c) = DictComp l (vsubst s a) (vsubst s c) vsubst s (Set l es) = Set l (vsubst s es) vsubst s (SetComp l e c) = SetComp l (vsubst s e) (vsubst s c) vsubst s (Paren l e) = Paren l (vsubst s e) vsubst s e = e instance VSubst Branch where vsubst s (Branch e b) = Branch (vsubst s e) (vsubst s b) instance VSubst Pattern where vsubst s (PWild l t) = PWild l (vsubst s t) vsubst s (PVar l n t) = PVar l n (vsubst s t) vsubst s (PParen l p) = PParen l (vsubst s p) vsubst s (PTuple l p k) = PTuple l (vsubst s p) (vsubst s k) vsubst s (PList l ps p) = PList l (vsubst s ps) (vsubst s p) instance VSubst PosPat where vsubst s (PosPat p pp) = PosPat (vsubst s p) (vsubst s pp) vsubst s (PosPatStar p) = PosPatStar (vsubst s p) vsubst s PosPatNil = PosPatNil instance VSubst KwdPat where vsubst s (KwdPat n p kp) = KwdPat n (vsubst s p) (vsubst s kp) vsubst s (KwdPatStar p) = KwdPatStar (vsubst s p) vsubst s KwdPatNil = KwdPatNil instance VSubst Handler where vsubst s (Handler ex b) = Handler ex (vsubst s b) instance VSubst WithItem where vsubst s (WithItem e p) = WithItem (vsubst s e) (vsubst s p) instance VSubst PosArg where vsubst s (PosArg e p) = PosArg (vsubst s e) (vsubst s p) vsubst s (PosStar e) = PosStar (vsubst s e) vsubst s PosNil = PosNil instance VSubst KwdArg where vsubst s (KwdArg n e k) = KwdArg n (vsubst s e) (vsubst s k) vsubst s (KwdStar e) = KwdStar (vsubst s e) vsubst s KwdNil = KwdNil instance VSubst Assoc where vsubst s (Assoc k v) = Assoc (vsubst s k) (vsubst s v) vsubst s (StarStar e) = StarStar (vsubst s e) instance VSubst Elem where vsubst s (Elem e) = Elem (vsubst s e) vsubst s (Star e) = Star (vsubst s e) instance VSubst Comp where vsubst s (CompFor l p e c) = CompFor l (vsubst s p) (vsubst s e) (vsubst s c) vsubst s (CompIf l e c) = CompIf l (vsubst s e) (vsubst s c) vsubst s NoComp = NoComp instance VSubst Sliz where vsubst s (Sliz l e1 e2 e3) = Sliz l (vsubst s e1) (vsubst s e2) (vsubst s e3) instance VSubst OpArg where vsubst s (OpArg op e) = OpArg op (vsubst s e) -- UFree ---------------------------------------------------------------------------------------------- class UFree t where ufree :: t -> [TUni] instance UFree a => UFree (Name,a) where ufree (n, t) = ufree t instance (UFree a, UFree b) => UFree (QName,a,b) where ufree (n, t, u) = ufree t ++ ufree u instance UFree a => UFree [a] where ufree = concat . map ufree instance UFree a => UFree (Maybe a) where ufree = maybe [] ufree instance UFree TSchema where ufree (TSchema _ q t) = ufree q ++ ufree t instance UFree TVar where ufree v = [] instance UFree TCon where ufree (TC n ts) = ufree ts instance UFree QBind where ufree (QBind v cs) = ufree cs instance UFree Type where ufree (TUni _ u) = [u] ufree (TVar _ v) = [] ufree (TCon _ c) = ufree c ufree (TFun _ fx p k t) = ufree fx ++ ufree p ++ ufree k ++ ufree t ufree (TTuple _ p k) = ufree p ++ ufree k ufree (TOpt _ t) = ufree t ufree (TNone _) = [] ufree (TWild _) = [] ufree (TNil _ _) = [] ufree (TRow _ _ _ t r) = ufree t ++ ufree r ufree (TStar _ _ r) = ufree r ufree (TFX l fx) = [] instance UFree PosPar where ufree (PosPar n t e p) = ufree t ++ ufree p ufree (PosSTAR n t) = ufree t ufree PosNIL = [] instance UFree KwdPar where ufree (KwdPar n t e p) = ufree t ++ ufree p ufree (KwdSTAR n t) = ufree t ufree KwdNIL = [] instance UFree Decl where ufree (Def _ n q p k a ss de fx _) = ufree q ++ ufree p ++ ufree k ++ ufree a ++ ufree ss ++ ufree fx ufree (Actor _ n q p k ss _) = ufree q ++ ufree p ++ ufree k ++ ufree ss ufree (Class _ n q bs ss _) = ufree q ++ ufree bs ++ ufree ss ufree (Protocol _ n q bs ss _) = ufree q ++ ufree bs ++ ufree ss ufree (Extension _ q c bs ss _) = ufree q ++ ufree c ++ ufree bs ++ ufree ss instance UFree Stmt where ufree (Expr _ e) = ufree e ufree (Assign _ ps e) = ufree ps ++ ufree e ufree (MutAssign _ t e) = ufree t ++ ufree e ufree (AugAssign _ t op e) = ufree t ++ ufree e ufree (Assert _ e mbe) = ufree e ++ ufree mbe ufree (Delete _ t) = ufree t ufree (Return _ mbe) = ufree mbe ufree (Raise _ e) = ufree e ufree (If _ bs els) = ufree bs ++ ufree els ufree (While _ e b els) = ufree e ++ ufree b ++ ufree els ufree (For _ p e b els) = ufree p ++ ufree e ++ ufree b ++ ufree els ufree (Try _ b hs els fin) = ufree b ++ ufree hs ++ ufree els ++ ufree fin ufree (With _ is b) = ufree is ++ ufree b ufree (VarAssign _ ps e) = ufree ps ++ ufree e ufree (After _ e e') = ufree e ++ ufree e' ufree (Decl _ ds) = ufree ds ufree (Signature _ ns tsc d) = ufree tsc ufree s = [] instance UFree Expr where ufree (Call l e p k) = ufree e ++ ufree p ++ ufree k ufree (TApp l e ts) = ufree e ++ ufree ts ufree (Let l ss e) = ufree ss ++ ufree e ufree (Async l e) = ufree e ufree (Await l e) = ufree e ufree (Index l e ix) = ufree e ++ ufree ix ufree (Slice l e sl) = ufree e ++ ufree sl ufree (Cond l e1 cond e2) = ufree e1 ++ ufree cond ++ ufree e2 ufree (IsInstance l e c) = ufree e ufree (BinOp l e1 op e2) = ufree e1 ++ ufree e2 ufree (CompOp l e ops) = ufree e ++ ufree ops ufree (UnOp l op e) = ufree e ufree (Dot l e n) = ufree e ufree (Rest l e n) = ufree e ufree (DotI l e i) = ufree e ufree (RestI l e i) = ufree e ufree (Lambda l p k e fx) = ufree p ++ ufree k ++ ufree e ++ ufree fx ufree (Yield l e) = ufree e ufree (YieldFrom l e) = ufree e ufree (Tuple l p k) = ufree p ++ ufree k ufree (List l es) = ufree es ufree (ListComp l e c) = ufree e ++ ufree c ufree (Dict l as) = ufree as ufree (DictComp l a c) = ufree a ++ ufree c ufree (Set l es) = ufree es ufree (SetComp l e c) = ufree e ++ ufree c ufree (Paren l e) = ufree e ufree e = [] instance UFree Pattern where ufree (PWild _ t) = ufree t ufree (PVar _ n t) = ufree t ufree (PParen _ p) = ufree p ufree (PTuple _ p k) = ufree p ++ ufree k ufree (PList _ ps p) = ufree ps ++ ufree p instance UFree PosPat where ufree (PosPat p pp) = ufree p ++ ufree pp ufree (PosPatStar p) = ufree p ufree PosPatNil = [] instance UFree KwdPat where ufree (KwdPat n p kp) = ufree p ++ ufree kp ufree (KwdPatStar p) = ufree p ufree KwdPatNil = [] instance UFree Branch where ufree (Branch e b) = ufree e ++ ufree b instance UFree Handler where ufree (Handler ex b) = ufree b instance UFree WithItem where ufree (WithItem e p) = ufree e ++ ufree p instance UFree PosArg where ufree (PosArg e p) = ufree e ++ ufree p ufree (PosStar e) = ufree e ufree PosNil = [] instance UFree KwdArg where ufree (KwdArg n e k) = ufree e ++ ufree k ufree (KwdStar e) = ufree e ufree KwdNil = [] instance UFree Elem where ufree (Elem e) = ufree e ufree (Star e) = ufree e instance UFree Assoc where ufree (Assoc k v) = ufree k ++ ufree v ufree (StarStar e) = ufree e instance UFree Comp where ufree (CompFor _ p e c) = ufree p ++ ufree e ++ ufree c ufree (CompIf _ e c) = ufree e ++ ufree c ufree NoComp = [] instance UFree Sliz where ufree (Sliz _ e1 e2 e3) = ufree e1 ++ ufree e2 ++ ufree e3 instance UFree OpArg where ufree (OpArg op e) = ufree e -- Polarity ------------------------------------------------------------------------------------------- class UFree a => Polarity a where polvars :: a -> ([TUni],[TUni]) (p,n) `polcat` (p',n') = (p++p', n++n') polnil = ([], []) polnull (p,n) = null p && null n polneg (p,n) = (n,p) (p,n) `polminus` (p',n') = (p\\p', n\\n') instance Polarity Type where polvars (TUni _ u) = ([u],[]) polvars (TVar _ v) = polnil polvars (TCon _ c) = polvars c polvars (TFun _ fx p k t) = polvars fx `polcat` polvars t `polcat` polneg (polvars p `polcat` polvars k) polvars (TTuple _ p k) = polvars p `polcat` polvars k polvars (TOpt _ t) = polvars t polvars (TNone _) = polnil polvars (TWild _) = polnil polvars (TNil _ _) = polnil polvars (TRow _ _ _ t r) = polvars t `polcat` polvars r polvars (TStar _ _ r) = polvars r polvars (TFX l fx) = polnil invvars x = (vs, vs) where vs = ufree x covariant = [qnSetT,qnDict,qnList] -- Ignore mutation for now! instance Polarity TCon where polvars (TC c ts) | c `elem` covariant = (vs,[]) | otherwise = (vs,vs) where vs = ufree ts instance Polarity QBind where polvars (QBind v cs) = (vs,vs) where vs = ufree cs instance Polarity TSchema where polvars (TSchema _ q t) = polvars q `polcat` polvars t instance (Polarity a) => Polarity (Maybe a) where polvars = maybe polnil polvars instance (Polarity a) => Polarity [a] where polvars = foldr polcat polnil . map polvars -- Does Self occur positively? posself (TVar _ v) = v == tvSelf posself (TCon _ c) = any posself (tcargs c) posself (TFun _ fx p k t) = any posself [fx,t] || any negself [p,k] posself (TTuple _ p k) = any posself [p,k] posself (TOpt _ t) = posself t posself (TRow _ _ _ t r) = any posself [t,r] posself (TStar _ _ r) = posself r posself _ = False -- Does Self occur negatively? negself (TCon _ c) = any negself (tcargs c) negself (TFun _ fx p k t) = any negself [fx,t] || any posself [p,k] negself (TTuple _ p k) = any negself [p,k] negself (TOpt _ t) = negself t negself (TRow _ _ _ t r) = any negself [t,r] negself (TStar _ _ r) = negself r negself _ = False -- Tailvars ------------------------------------------------------------------------------------------- class (UFree a) => Tailvars a where -- Find free univars of kind PRow or KRow (for the purpose of defaulting them to TNil) tailvars :: a -> [TUni] instance Tailvars Type where tailvars (TCon _ c) = tailvars c tailvars (TFun _ fx p k t) = tailvars fx ++ tailvars' p ++ tailvars' k ++ tailvars t tailvars (TTuple _ p k) | TUni{} <- p, TNil{} <- k = [] -- Exclude open * tuples | TNil{} <- p, TUni{} <- k = [] -- Exclude open ** tuples | otherwise = tailvars' p ++ tailvars' k tailvars (TOpt _ t) = tailvars t tailvars _ = [] tailvars' (TRow _ _ _ t r) = tailvars t ++ tailvars' r tailvars' (TStar _ _ r) = tailvars r tailvars' (TNil _ _) = [] tailvars' (TUni _ u) = [u] instance Tailvars TCon where tailvars (TC c ts) = tailvars ts instance Tailvars QBind where tailvars (QBind v cs) = tailvars cs instance Tailvars TSchema where tailvars (TSchema _ q t) = tailvars q ++ tailvars t instance (Tailvars a) => Tailvars (Maybe a) where tailvars = maybe [] tailvars instance (Tailvars a) => Tailvars [a] where tailvars = concat . map tailvars schematic (TCon _ tc) = tCon (schematic' tc) schematic (TFun _ _ _ _ _) = tFun tWild tWild tWild tWild schematic (TTuple _ _ _) = tTuple tWild tWild schematic (TOpt _ _) = tOpt tWild schematic (TRow _ k n _ r) = tRow k n tWild (schematic r) schematic (TStar _ k _) = tStar k tWild schematic t = t schematic' (TC n ts) = TC n [ tWild | _ <- ts ] class UWild a where uwild :: a -> a instance UWild a => UWild [a] where uwild = map uwild instance UWild a => UWild (Maybe a) where uwild = fmap uwild instance UWild TCon where uwild (TC n ts) = TC n (uwild ts) instance UWild Type where uwild (TUni l u) = tWild uwild (TCon l c) = TCon l (uwild c) uwild (TFun l fx p k t) = TFun l fx (uwild p) (uwild k) (uwild t) uwild (TTuple l p k) = TTuple l (uwild p) (uwild k) uwild (TOpt l t) = TOpt l (uwild t) uwild (TRow l k n t r) = TRow l k n (uwild t) (uwild r) uwild (TStar l k r) = TStar l k (uwild r) uwild t = t instance UWild TSchema where uwild (TSchema l q t) = TSchema l (uwild q) (uwild t) instance UWild QBind where uwild (QBind v cs) = QBind v (uwild cs) instance (UWild a, UWild b) => UWild (QName,a,b) where uwild (n, t, u) = (n, uwild t, uwild u) ================================================ FILE: compiler/lib/src/Acton/Syntax.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, DeriveGeneric, DeriveAnyClass #-} module Acton.Syntax where import Utils import qualified Data.Binary import qualified Data.Set import qualified Data.HashMap.Strict as M import qualified Data.Hashable import Data.Char import GHC.Generics (Generic) import Control.DeepSeq import Prelude hiding((<>)) version :: [Int] version = [0,17] data Module = Module { modname::ModName, imps::[Import], mdoc::Maybe String, mbody::Suite } deriving (Eq,Show,Generic,NFData) data Import = Import { iloc::SrcLoc, moduls::[ModuleItem] } | FromImport { iloc::SrcLoc, modul::ModRef, items::[ImportItem] } | FromImportAll { iloc::SrcLoc, modul::ModRef } deriving (Show,Read,NFData,Generic) type Suite = [Stmt] data Stmt = Expr { sloc::SrcLoc, expr::Expr } | Assign { sloc::SrcLoc, patterns::[Pattern], expr::Expr } | MutAssign { sloc::SrcLoc, target::Target, expr::Expr } | AugAssign { sloc::SrcLoc, target::Target, aop::Aug, expr::Expr } | Assert { sloc::SrcLoc, expr::Expr, optExpr::Maybe Expr } | Pass { sloc::SrcLoc } | Delete { sloc::SrcLoc, target::Target } | Return { sloc::SrcLoc, optExpr::Maybe Expr } | Raise { sloc::SrcLoc, expr::Expr } | Break { sloc::SrcLoc } | Continue { sloc::SrcLoc } | If { sloc::SrcLoc, branches::[Branch], els::Suite } | While { sloc::SrcLoc, expr::Expr, body::Suite, els::Suite } | For { sloc::SrcLoc, pattern::Pattern, expr::Expr, body::Suite, els::Suite } | Try { sloc::SrcLoc, body::Suite, handlers::[Handler], els::Suite, finally::Suite } | With { sloc::SrcLoc, witems::[WithItem], body::Suite } | Data { sloc::SrcLoc, mbpat::Maybe Pattern, dsuite::Suite } | VarAssign { sloc::SrcLoc, patterns::[Pattern], expr::Expr } | After { sloc::SrcLoc, expr::Expr, expr2::Expr } | Signature { sloc::SrcLoc, vars::[Name], typ::TSchema, dec::Deco } | Decl { sloc::SrcLoc, decls::[Decl] } deriving (Show,Read,NFData,Generic) data Decl = Def { dloc::SrcLoc, dname:: Name, qbinds::QBinds, pos::PosPar, kwd::KwdPar, ann::Maybe Type, dbody::Suite, deco::Deco, dfx::TFX, ddoc::Maybe String } | Actor { dloc::SrcLoc, dname:: Name, qbinds::QBinds, pos::PosPar, kwd::KwdPar, dbody::Suite, ddoc::Maybe String } | Class { dloc::SrcLoc, dname:: Name, qbinds::QBinds, bounds::[TCon], dbody::Suite, ddoc::Maybe String } | Protocol { dloc::SrcLoc, dname:: Name, qbinds::QBinds, bounds::[PCon], dbody::Suite, ddoc::Maybe String } -- | Extension { dloc::SrcLoc, dqname::QName, qbinds::QBinds, bounds::[PCon], dbody::Suite } | Extension { dloc::SrcLoc, qbinds::QBinds, tycon::TCon, bounds::[PCon], dbody::Suite, ddoc::Maybe String } deriving (Show,Read,NFData,Generic) data Expr = Var { eloc::SrcLoc, var::QName } | Int { eloc::SrcLoc, ival::Integer, lexeme::String } | Float { eloc::SrcLoc, dval::Double, lexeme::String } | Imaginary { eloc::SrcLoc, dval::Double, lexeme::String } | Bool { eloc::SrcLoc, bval::Bool } | None { eloc::SrcLoc } | NotImplemented{ eloc::SrcLoc } | Ellipsis { eloc::SrcLoc } | Strings { eloc::SrcLoc, sval::[String] } | BStrings { eloc::SrcLoc, sval::[String] } | Call { eloc::SrcLoc, fun::Expr, pargs::PosArg, kargs::KwdArg } | Let { eloc::SrcLoc, suit::Suite, exp1::Expr } | TApp { eloc::SrcLoc, fun::Expr, targs::[Type] } | Async { eloc::SrcLoc, exp1::Expr } | Await { eloc::SrcLoc, exp1::Expr } | Index { eloc::SrcLoc, exp1::Expr, index::Expr } | Slice { eloc::SrcLoc, exp1::Expr, slice::Sliz } | Cond { eloc::SrcLoc, exp1::Expr, cond::Expr, exp2::Expr } | IsInstance { eloc::SrcLoc, exp1::Expr, classref::QName } | BinOp { eloc::SrcLoc, exp1::Expr, bop::Binary, exp2::Expr } | CompOp { eloc::SrcLoc, exp1::Expr, ops::[OpArg] } | UnOp { eloc::SrcLoc, uop::Unary, exp1::Expr } | Dot { eloc::SrcLoc, exp1::Expr, attr::Name } | Rest { eloc::SrcLoc, exp1::Expr, attr::Name } | DotI { eloc::SrcLoc, exp1::Expr, ival::Integer } | RestI { eloc::SrcLoc, exp1::Expr, ival::Integer } | Opt { eloc::SrcLoc, exp1::Expr, optVal::Bool } | OptChain { eloc::SrcLoc, exp1::Expr } | Lambda { eloc::SrcLoc, ppar::PosPar, kpar::KwdPar, exp1::Expr, efx::TFX } | Yield { eloc::SrcLoc, yexp1::Maybe Expr } | YieldFrom { eloc::SrcLoc, yfrom::Expr } | Tuple { eloc::SrcLoc, pargs::PosArg, kargs::KwdArg } | List { eloc::SrcLoc, elems::[Elem] } | ListComp { eloc::SrcLoc, elem1::Elem, comp::Comp } | Dict { eloc::SrcLoc, assocs::[Assoc] } | DictComp { eloc::SrcLoc, assoc1::Assoc, comp::Comp } | Set { eloc::SrcLoc, elems::[Elem] } | SetComp { eloc::SrcLoc, elem1::Elem, comp::Comp } | Paren { eloc::SrcLoc, exp1::Expr } | Box { tp :: Type, exp1 :: Expr } | UnBox { tp :: Type, exp1 :: Expr } deriving (Show,Read,NFData,Generic) data Pattern = PWild { ploc::SrcLoc, pann::Maybe Type } | PVar { ploc::SrcLoc, pn::Name, pann::Maybe Type } | PParen { ploc::SrcLoc, pat::Pattern } | PTuple { ploc::SrcLoc, ppat::PosPat, kpat::KwdPat} | PList { ploc::SrcLoc, pats::[Pattern], ptail::Maybe Pattern } | PData { ploc::SrcLoc, pn::Name, pixs::[Expr] } deriving (Show,Read,NFData,Generic) type Target = Expr data Prefix = Globvar | Xistvar | Tempvar | Witness | NormPass | CPSPass | LLiftPass | BoxPass deriving (Eq,Ord,Show,Read,Generic,NFData) data Name = Name SrcLoc String | Derived Name Name | Internal Prefix String Int deriving (Generic,Show,NFData) nloc (Name l _) = l nloc _ = NoLoc nstr (Name _ s) = esc s where esc (c:'_':s) | isUpper c = c : {- 'X' : -} '_' : esc s esc (c:s) = c : esc s esc "" = "" nstr (Derived n s) | Internal{} <- s = nstr n ++ nstr s | otherwise = nstr n ++ "D_" ++ nstr s nstr (Internal p s i) = prefix p ++ "_" ++ unique i ++ s where prefix Globvar = "G" prefix Xistvar = "E" prefix Tempvar = "V" prefix Witness = "W" prefix NormPass = "N" prefix CPSPass = "C" prefix LLiftPass = "L" prefix BoxPass = "U" unique 0 = "" unique i = show i rawstr (Name _ s) = s rawstr n = nstr n name = Name NoLoc nWild = name "_" globalName s = Internal Globvar s 0 globalNames s = map (Internal Globvar s) [1..] data ModName = ModName [Name] deriving (Show,Read,Eq,Generic,NFData) modName ss = ModName (map name ss) modPath (ModName ns) = map nstr ns modCat (ModName ns) n = ModName (ns++[n]) instance Ord ModName where compare a b = compare (modPath a) (modPath b) data QName = QName { mname::ModName, noq::Name } | NoQ { noq::Name } | GName { mname::ModName, noq::Name } deriving (Show,Read,Eq,Ord,Generic,NFData) qName ss s = QName (modName ss) (name s) noQ s = NoQ (name s) data ModuleItem = ModuleItem ModName (Maybe Name) deriving (Show,Eq,Read,NFData,Generic) data ModRef = ModRef (Int, Maybe ModName) deriving (Show,Eq,Read,NFData,Generic) data ImportItem = ImportItem Name (Maybe Name) deriving (Show,Eq,Read,NFData,Generic) data Branch = Branch Expr Suite deriving (Show,Eq,Read,NFData,Generic) data Handler = Handler Except Suite deriving (Show,Eq,Read,NFData,Generic) data Except = ExceptAll SrcLoc | Except SrcLoc QName | ExceptAs SrcLoc QName Name deriving (Show,Read,NFData,Generic) data Elem = Elem Expr | Star Expr deriving (Show,Eq,Read,NFData,Generic) data Assoc = Assoc Expr Expr | StarStar Expr deriving (Show,Eq,Read,NFData,Generic) data PosPar = PosPar Name (Maybe Type) (Maybe Expr) PosPar | PosSTAR Name (Maybe Type) | PosNIL deriving (Show,Eq,Read,NFData,Generic) data KwdPar = KwdPar Name (Maybe Type) (Maybe Expr) KwdPar | KwdSTAR Name (Maybe Type) | KwdNIL deriving (Show,Eq,Read,NFData,Generic) data PosArg = PosArg Expr PosArg | PosStar Expr | PosNil deriving (Show,NFData,Eq,Read,Generic) data KwdArg = KwdArg Name Expr KwdArg | KwdStar Expr | KwdNil deriving (Show,Eq,Read,NFData,Generic) data PosPat = PosPat Pattern PosPat | PosPatStar Pattern | PosPatNil deriving (Show,Eq,Read,NFData,Generic) data KwdPat = KwdPat Name Pattern KwdPat | KwdPatStar Pattern | KwdPatNil deriving (Show,Eq,Read,NFData,Generic) data OpArg = OpArg Comparison Expr deriving (Eq,Show,Read,NFData,Generic) data Sliz = Sliz SrcLoc (Maybe Expr) (Maybe Expr) (Maybe Expr) deriving (Show,Read,NFData,Generic) data Comp = CompFor SrcLoc Pattern Expr Comp | CompIf SrcLoc Expr Comp | NoComp deriving (Show,Read,NFData,Generic) data WithItem = WithItem Expr (Maybe Pattern) deriving (Show,Eq,Read,NFData,Generic) data Unary = Not|UPlus|UMinus|BNot deriving (Show,Eq,Read,NFData,Generic) data Binary = Or|And|Plus|Minus|Mult|Pow|Div|Mod|EuDiv|BOr|BXor|BAnd|ShiftL|ShiftR|MMult deriving (Show,Read,Eq,NFData,Generic) data Aug = PlusA|MinusA|MultA|PowA|DivA|ModA|EuDivA|BOrA|BXorA|BAndA|ShiftLA|ShiftRA|MMultA deriving (Show,Eq,Read,NFData,Generic) data Comparison = Eq|NEq|LtGt|Lt|Gt|GE|LE|In|NotIn|Is|IsNot deriving (Show,Eq,Read,NFData,Generic) data Deco = NoDec | Property | Static deriving (Eq,Show,Read,Generic,NFData) data Kind = KType | KProto | KFX | PRow | KRow | KFun [Kind] Kind | KUni Int | KWild deriving (Eq,Ord,Show,Read,Generic,NFData) data TSchema = TSchema { scloc::SrcLoc, scbind::QBinds, sctype::Type } deriving (Show,Read,Generic,NFData) data TVar = TV { tvkind::Kind, tvname::Name } -- the Name is an uppercase letter, optionally followed by digits. deriving (Show,Read,Generic,NFData) data TUni = UV { uvkind::Kind, uvlevel::Int, uvid::Int } deriving (Show,Read,Generic,NFData) univar k l i = UV k l i unitoken i = UV KWild 0 (-(i*2)) uniwild k l i = UV k l (-(i*2+1)) data TCon = TC { tcname::QName, tcargs::[Type] } deriving (Eq,Show,Read,Generic,NFData) data FX = FXPure | FXMut | FXProc | FXAction deriving (Eq,Show,Read,Generic,NFData) data QBind = QBind TVar [TCon] deriving (Eq,Show,Read,Generic,NFData) type QBinds = [QBind] type PCon = TCon type CCon = TCon type KUni = Int data Type = TUni { tloc::SrcLoc, uvar::TUni } | TVar { tloc::SrcLoc, tvar::TVar } | TCon { tloc::SrcLoc, tcon::TCon } | TFun { tloc::SrcLoc, effect::TFX, posrow::PosRow, kwdrow::KwdRow, restype::Type } | TTuple { tloc::SrcLoc, posrow::PosRow, kwdrow::KwdRow } | TOpt { tloc::SrcLoc, opttype::Type } | TNone { tloc::SrcLoc } | TWild { tloc::SrcLoc } | TNil { tloc::SrcLoc, rkind::Kind } | TRow { tloc::SrcLoc, rkind::Kind, label::Name, rtype::Type, rtail::TRow } | TStar { tloc::SrcLoc, rkind::Kind, rtail::TRow } | TFX { tloc::SrcLoc, tfx::FX } deriving (Show,Read,Generic,NFData) type TFX = Type type PosRow = Type type KwdRow = Type type TRow = Type leftpath tcs = [ (map Left ns, tc) | (ns,tc) <- nss `zip` tcs ] where nss = tail $ inits $ map tcname tcs mkBody [] = [Pass NoLoc] mkBody b = b sDef n p t b fx = sDecl [Def NoLoc n [] p KwdNIL (Just t) b NoDec fx Nothing] sReturn e = Return NoLoc (Just e) sAssign p e = Assign NoLoc [p] e sMutAssign t e = MutAssign NoLoc t e sRaise e = Raise NoLoc e sExpr e = Expr NoLoc e sDecl ds = Decl NoLoc ds sIf bs els = If NoLoc bs els sIf1 e b els = sIf [Branch e b] els sNotImpl = Expr NoLoc eNotImpl sPass = Pass NoLoc sBreak = Break NoLoc sContinue = Continue NoLoc handler qn b = Handler (Except NoLoc qn) b tApp e [] = e tApp e ts = TApp NoLoc e ts eCall e es = Call NoLoc e (posarg es) KwdNil eCallVar c es = eCall (eVar c) es eCallV c es = eCall (Var NoLoc c) es eCallP e as = Call NoLoc e as KwdNil eTuple es = Tuple NoLoc (posarg es) KwdNil eTupleP args = Tuple NoLoc args KwdNil eTupleK args = Tuple NoLoc PosNil args eQVar n = Var NoLoc n eVar n = Var NoLoc (NoQ n) eDot e n = Dot NoLoc e n eDotI e i = DotI NoLoc e i eNone = None NoLoc eCond e b e' = Cond NoLoc e b e' eInt n = Int NoLoc n (show n) eBool b = Bool NoLoc b eBinOp e o e' = BinOp NoLoc e o e' eLambda nts e = Lambda NoLoc (pospar nts) KwdNIL e fxPure eLambda' nts e = Lambda NoLoc (pospar nts) KwdNIL e fxProc eLet ss e = Let NoLoc ss e eAsync e = Async NoLoc e eAwait e = Await NoLoc e eNotImpl = NotImplemented NoLoc eIsInstance x n = IsInstance NoLoc (eVar x) n pospar nts = foldr (\(n,t) p -> PosPar n (Just t) Nothing p) PosNIL nts pospar' ns = foldr (\n p -> PosPar n Nothing Nothing p) PosNIL ns pospars' (PosPar n _ _ p) = n : pospars' p pospars' PosNIL = [] posarg es = foldr PosArg PosNil es posargs (PosArg e p) = e : posargs p posargs (PosStar e) = [e] posargs PosNil = [] selfPar Def{pos=PosPar x _ _ _} = Just x selfPar Def{kwd=KwdPar x _ _ _} = Just x selfPar _ = Nothing pVar n t = PVar NoLoc n (Just t) pVar' n = PVar NoLoc n Nothing monotype t = TSchema NoLoc [] t tSchema q t = TSchema NoLoc q t qbind v = QBind v [] qbound q = [ tv | QBind tv _ <- q ] tVar v = TVar NoLoc v tUni v = TUni NoLoc v tCon c = TCon NoLoc c tFun fx p k t = TFun NoLoc fx p k t tTuple p k = TTuple NoLoc p k tTupleP p = TTuple NoLoc p kwdNil tTupleK k = TTuple NoLoc posNil k tUnit = tTuple posNil kwdNil tOpt t@TOpt{} = t tOpt t = TOpt NoLoc t tNone = TNone NoLoc tWild = TWild NoLoc tNil k = TNil NoLoc k tRow k = TRow NoLoc k tStar k = TStar NoLoc k tTFX fx = TFX NoLoc fx tCon0 n q = tCon $ TC n [ tVar tv | QBind tv _ <- q ] tFun0 ps t = tFun fxPure (foldr posRow posNil ps) kwdNil t tSelf = TVar NoLoc tvSelf tvSelf = TV KType nSelf nSelf = Name NoLoc "Self" fxSelf = TV KFX nSelf fxPure = tTFX FXPure fxMut = tTFX FXMut fxProc = tTFX FXProc fxAction = tTFX FXAction fxWild = tWild fxFun fx1 fx2 = tFun fxPure (posRow (tF0 fx1) posNil) kwdNil (tF0 fx2) where tF0 fx = tFun fx posNil kwdNil tNone posNil = tNil PRow posRow = tRow PRow nWild posStar = tStar PRow posStar' = posStar . maybe tWild tVar kwdNil = tNil KRow kwdRow = tRow KRow kwdStar = tStar KRow kwdStar' = kwdStar . maybe tWild tVar prowOf (PosPar n a d p) = posRow (dflt d $ case a of Just t -> t; _ -> tWild) (prowOf p) where dflt Nothing = id dflt (Just e) = tOpt prowOf (PosSTAR n a) = posStar (case a of Just (TTuple _ r _) -> r; _ -> tWild) --prowOf (PosSTAR n a) = (case a of Just (TTuple _ r _) -> r; _ -> tWild) prowOf PosNIL = posNil krowOf (KwdPar n a d k) = kwdRow n (dflt d $ case a of Just t -> t; _ -> tWild) (krowOf k) where dflt Nothing = id dflt (Just e) = tOpt krowOf (KwdSTAR n a) = kwdStar (case a of Just (TTuple _ _ r) -> r; _ -> tWild) --krowOf (KwdSTAR n a) = (case a of Just (TTuple _ _ r) -> r; _ -> tWild) krowOf KwdNIL = kwdNil pArg (PosPar n a _ p) = PosArg (eVar n) (pArg p) pArg (PosSTAR n a) = PosStar (eVar n) pArg PosNIL = PosNil kArg (KwdPar n a _ p) = KwdArg n (eVar n) (kArg p) kArg (KwdSTAR n a) = KwdStar (eVar n) kArg KwdNIL = KwdNil chop 0 _ = PosNIL chop i (PosPar n a d p) = PosPar n a d (chop (i-1) p) chop _ p = p arity (TRow _ _ _ _ r) = 1 + arity r arity _ = 0 pPar ns (TRow _ PRow n t p) = PosPar (head ns) (Just t) Nothing (pPar (tail ns) p) pPar ns (TNil _ PRow) = PosNIL pPar ns (TStar _ PRow r)= PosSTAR (head ns) (Just $ tTupleP r) kPar kw (TRow _ KRow n t r) = KwdPar n (Just t) Nothing (kPar kw r) kPar kw (TNil _ KRow) = KwdNIL kPar kw (TStar _ KRow r)= KwdSTAR kw (Just $ tTupleK r) tRowLoc t@TRow{} = getLoc [tloc t, loc (rtype t)] tvarSupply = [ TV KType $ name (c:tl) | tl <- "" : map show [1..], c <- "ABCDEFGHIJKLMNOPQRSTUVW" ] fxSupply = [ TV KType $ name (c:tl) | tl <- "" : map show [1..], c <- "XYZ" ] tvarSupplyMap vs avoid = map setk (vs `zip` (tvarSupply \\ avoid)) where setk (v,v') = (v, tVar $ v'{ tvkind = tvkind v }) type Substitution = [(TVar,Type)] instance Data.Hashable.Hashable Name where hashWithSalt s (Name _ nstr) = Data.Hashable.hashWithSalt s nstr hashWithSalt s (Derived n1 n2) = Data.Hashable.hashWithSalt s (n1,n2) hashWithSalt s (Internal pre str n) = Data.Hashable.hashWithSalt s (show pre,str,n) -- Finding type leaves ----- class Leaves a where leaves :: a -> [Type] instance (Leaves a) => Leaves [a] where leaves = concatMap leaves instance (Leaves a) => Leaves (Name,a) where leaves (n,x) = leaves x instance Leaves QBind where leaves (QBind tv ps) = tVar tv : leaves ps instance Leaves TSchema where leaves (TSchema _ q t) = leaves q ++ leaves t instance Leaves Type where leaves t@TCon{} = [t] leaves t@TVar{} = [t] leaves t@TUni{} = [t] leaves t@TFX{} = [t] leaves (TFun _ x p k t) = leaves [x,p,k,t] leaves (TTuple _ p k) = leaves [p,k] leaves (TOpt _ t) = leaves t leaves (TRow _ _ _ t r) = leaves [t,r] leaves (TStar _ _ r) = leaves r leaves _ = [] instance Leaves TCon where leaves tc = [tCon tc] instance Leaves TVar where leaves tv = [tVar tv] instance Data.Binary.Binary Prefix instance Data.Binary.Binary Name instance Data.Binary.Binary ModName instance Data.Binary.Binary QName instance Data.Binary.Binary Deco instance Data.Binary.Binary TSchema instance Data.Binary.Binary TVar instance Data.Binary.Binary TUni instance Data.Binary.Binary TCon instance Data.Binary.Binary QBind instance Data.Binary.Binary Type instance Data.Binary.Binary Kind instance Data.Binary.Binary FX instance Data.Binary.Binary Expr instance Data.Binary.Binary Stmt instance Data.Binary.Binary Decl instance Data.Binary.Binary Branch instance Data.Binary.Binary Handler instance Data.Binary.Binary Except instance Data.Binary.Binary Elem instance Data.Binary.Binary Assoc instance Data.Binary.Binary Pattern instance Data.Binary.Binary PosPar instance Data.Binary.Binary KwdPar instance Data.Binary.Binary PosArg instance Data.Binary.Binary KwdArg instance Data.Binary.Binary PosPat instance Data.Binary.Binary KwdPat instance Data.Binary.Binary OpArg instance Data.Binary.Binary Sliz instance Data.Binary.Binary Comp instance Data.Binary.Binary WithItem instance Data.Binary.Binary Unary instance Data.Binary.Binary Binary instance Data.Binary.Binary Aug instance Data.Binary.Binary Comparison instance Data.Binary.Binary Module instance Data.Binary.Binary Import instance Data.Binary.Binary ModuleItem instance Data.Binary.Binary ImportItem instance Data.Binary.Binary ModRef -- Locations ---------------- instance HasLoc Import where loc = iloc instance HasLoc Stmt where loc = sloc instance HasLoc Decl where loc = dloc instance HasLoc Expr where loc = eloc instance HasLoc Name where loc = nloc instance HasLoc ModName where loc (ModName ns) = loc ns instance HasLoc QName where loc (QName m n) = loc m `upto` loc n loc (NoQ n) = loc n loc (GName m n) = loc m `upto` loc n instance HasLoc Elem where loc (Elem e) = loc e loc (Star e) = loc e instance HasLoc Assoc where loc (Assoc k v) = loc k `upto` loc v loc (StarStar e) = loc e instance HasLoc Pattern where loc = ploc instance HasLoc TSchema where loc (TSchema l _ _) = l instance HasLoc TVar where loc (TV _ v) = loc v instance HasLoc TUni where loc (UV _ _ v) = NoLoc instance HasLoc TCon where loc (TC c ts) = loc c `upto` loc ts instance HasLoc Type where loc = tloc instance HasLoc PosArg where loc (PosArg e p) = loc e `upto` loc p loc (PosStar e) = loc e loc PosNil = NoLoc instance HasLoc KwdArg where loc (KwdArg n e k) = loc n `upto` loc k loc (KwdStar e) = loc e loc KwdNil = NoLoc instance HasLoc PosPar where loc (PosPar n _ _ _) = loc n loc (PosSTAR n _) = loc n loc _ = NoLoc instance HasLoc KwdPar where loc (KwdPar n _ _ _) = loc n loc (KwdSTAR n _) = loc n loc _ = NoLoc -- Eq ------------------------- instance Eq Import where x@Import{} == y@Import{} = moduls x == moduls y x@FromImport{} == y@FromImport{} = modul x == modul y && items x == items y x@FromImportAll{} == y@FromImportAll{} = modul x == modul y _ == _ = False instance Eq Stmt where x@Expr{} == y@Expr{} = expr x == expr y x@Assign{} == y@Assign{} = patterns x == patterns y && expr x == expr y x@MutAssign{} == y@MutAssign{} = target x == target y && expr x == expr y x@AugAssign{} == y@AugAssign{} = target x == target y && aop x == aop y && expr x == expr y x@Assert{} == y@Assert{} = expr x == expr y && optExpr x == optExpr y x@Pass{} == y@Pass{} = True x@Delete{} == y@Delete{} = target x == target y x@Return{} == y@Return{} = optExpr x == optExpr y x@Raise{} == y@Raise{} = expr x == expr y x@Break{} == y@Break{} = True x@Continue{} == y@Continue{} = True x@If{} == y@If{} = branches x == branches y && els x == els y x@While{} == y@While{} = expr x == expr y && body x == body y && els x == els y x@For{} == y@For{} = pattern x == pattern y && expr x == expr y && body x == body y && els x == els y x@Try{} == y@Try{} = body x == body y && handlers x == handlers y && els x == els y && finally x == finally y x@With{} == y@With{} = witems x == witems y && body x == body y x@Data{} == y@Data{} = mbpat x == mbpat y && dsuite x == dsuite y x@VarAssign{} == y@VarAssign{} = patterns x == patterns y && expr x == expr y x@After{} == y@After{} = expr x == expr y && expr2 x == expr2 y x@Decl{} == y@Decl{} = decls x == decls y x@Signature{} == y@Signature{} = vars x == vars y && typ x == typ y && dec x == dec y _ == _ = False instance Eq Decl where Def _ n1 q1 p1 k1 a1 b1 m1 d1 doc1 == Def _ n2 q2 p2 k2 a2 b2 m2 d2 doc2 = n1==n2 && q1==q2 && p1==p2 && k1==k2 && a1==a2 && b1==b2 && d1==d2 && m1==m2 && doc1==doc2 Actor _ n1 q1 p1 k1 b1 doc1 == Actor _ n2 q2 p2 k2 b2 doc2 = n1 == n2 && q1 == q2 && p1 == p2 && k1 == k2 && b1 == b2 && doc1 == doc2 Class _ n1 q1 a1 b1 doc1 == Class _ n2 q2 a2 b2 doc2 = n1 == n2 && q1 == q2 && a1 == a2 && b1 == b2 && doc1 == doc2 Protocol _ n1 q1 a1 b1 doc1 == Protocol _ n2 q2 a2 b2 doc2 = n1 == n2 && q1 == q2 && a1 == a2 && b1 == b2 && doc1 == doc2 Extension _ q1 c1 a1 b1 doc1 == Extension _ q2 c2 a2 b2 doc2 = q1 == q2 && c1 == c2 && a1 == a2 && b1 == b2 && doc1 == doc2 _ == _ = False instance Eq Expr where x@Var{} == y@Var{} = var x == var y x@Int{} == y@Int{} = lexeme x == lexeme y x@Float{} == y@Float{} = lexeme x == lexeme y x@Imaginary{} == y@Imaginary{} = lexeme x == lexeme y x@Bool{} == y@Bool{} = bval x == bval y x@None{} == y@None{} = True x@NotImplemented{} == y@NotImplemented{} = True x@Ellipsis{} == y@Ellipsis{} = True x@Strings{} == y@Strings{} = sval x == sval y x@BStrings{} == y@BStrings{} = sval x == sval y x@Call{} == y@Call{} = fun x == fun y && pargs x == pargs y && kargs x == kargs y x@TApp{} == y@TApp{} = fun x == fun y && targs x == targs y x@Let{} == y@Let{} = suit x == suit y && exp1 x == exp1 y x@Async{} == y@Async{} = exp1 x == exp1 y x@Await{} == y@Await{} = exp1 x == exp1 y x@Index{} == y@Index{} = exp1 x == exp1 y && index x == index y x@Slice{} == y@Slice{} = exp1 x == exp1 y && slice x == slice y x@Cond{} == y@Cond{} = exp1 x == exp1 y && cond x == cond y && exp2 x == exp2 y x@IsInstance{} == y@IsInstance{} = exp1 x == exp1 y && classref x == classref y x@BinOp{} == y@BinOp{} = exp1 x == exp1 y && bop x == bop y && exp2 x == exp2 y x@CompOp{} == y@CompOp{} = exp1 x == exp1 y && ops x == ops y x@UnOp{} == y@UnOp{} = uop x == uop y && exp1 x == exp1 y x@Dot{} == y@Dot{} = exp1 x == exp1 y && attr x == attr y x@Rest{} == y@Rest{} = exp1 x == exp1 y && attr x == attr y x@DotI{} == y@DotI{} = exp1 x == exp1 y && ival x == ival y x@RestI{} == y@RestI{} = exp1 x == exp1 y && ival x == ival y x@Opt{} == y@Opt{} = exp1 x == exp1 y && optVal x == optVal y x@OptChain{} == y@OptChain{} = exp1 x == exp1 y x@Lambda{} == y@Lambda{} = ppar x == ppar y && kpar x == kpar y && exp1 x == exp1 y && efx x == efx y x@Yield{} == y@Yield{} = yexp1 x == yexp1 y x@YieldFrom{} == y@YieldFrom{} = yfrom x == yfrom y x@Tuple{} == y@Tuple{} = pargs x == pargs y && kargs x == kargs y x@List{} == y@List{} = elems x == elems y x@ListComp{} == y@ListComp{} = elem1 x == elem1 y && comp x == comp y x@Dict{} == y@Dict{} = assocs x == assocs y x@DictComp{} == y@DictComp{} = assoc1 x == assoc1 y && comp x == comp y x@Set{} == y@Set{} = elems x == elems y x@SetComp{} == y@SetComp{} = elem1 x == elem1 y && comp x == comp y x@Paren{} == y = exp1 x == y x == y@Paren{} = x == exp1 y _ == _ = False instance Eq Name where Name _ s1 == Name _ s2 = s1 == s2 Derived n1 s1 == Derived n2 s2 = n1 == n2 && s1 == s2 Internal p1 s1 i1 == Internal p2 s2 i2 = p1 == p2 && s1 == s2 && i1 == i2 _ == _ = False instance Ord Name where Name _ s1 <= Name _ s2 = s1 <= s2 Derived n1 s1 <= Derived n2 s2 = (n1,s1) <= (n2,s2) Internal p1 s1 i1 <= Internal p2 s2 i2 = (p1,s1,i1) <= (p2,s2,i2) Name{} <= Derived{} = True Name{} <= Internal{} = True Derived{} <= Internal{} = True _ <= _ = False instance Eq Except where ExceptAll _ == ExceptAll _ = True Except _ x1 == Except _ x2 = x1 == x2 ExceptAs _ x1 n1 == ExceptAs _ x2 n2 = x1 == x2 && n1 == n2 _ == _ = False instance Eq Sliz where Sliz _ a1 b1 c1 == Sliz _ a2 b2 c2 = a1 == a2 && b1 == b2 && c1 == c2 instance Eq Comp where CompFor _ p1 e1 c1 == CompFor _ p2 e2 c2 = p1 == p2 && e1 == e2 && c1 == c2 CompIf _ e1 c1 == CompIf _ e2 c2 = e1 == e2 && c1 == c2 NoComp == NoComp = True _ == _ = False instance Eq Pattern where PWild _ a1 == PWild _ a2 = a1 == a2 PVar _ n1 a1 == PVar _ n2 a2 = n1 == n2 && a1 == a2 PTuple _ p1 k1 == PTuple _ p2 k2 = p1 == p2 && k1 == k2 PList _ ps1 p1 == PList _ ps2 p2 = ps1 == ps2 && p1 == p2 PData _ n1 ix1 == PData _ n2 ix2 = n1 == n2 && ix1 == ix2 PParen _ p1 == p2 = p1 == p2 p1 == PParen _ p2 = p1 == p2 _ == _ = False instance Eq TSchema where TSchema _ q1 t1 == TSchema _ q2 t2 = q1 == q2 && t1 == t2 instance Eq TVar where TV k1 v1 == TV k2 v2 = v1 == v2 instance Eq TUni where UV _ _ i1 == UV _ _ i2 = i1 == i2 instance Ord TVar where TV _ v1 <= TV _ v2 = v1 <= v2 instance Ord TUni where UV _ _ i1 <= UV _ _ i2 = i1 <= i2 instance Eq Type where TUni _ u1 == TUni _ u2 = u1 == u2 TVar _ v1 == TVar _ v2 = v1 == v2 TCon _ c1 == TCon _ c2 = c1 == c2 TFun _ e1 p1 r1 t1 == TFun _ e2 p2 r2 t2 = e1 == e2 && p1 == p2 && r1 == r2 && t1 == t2 TTuple _ p1 r1 == TTuple _ p2 r2 = p1 == p2 && r1 == r2 TOpt _ t1 == TOpt _ t2 = t1 == t2 TNone _ == TNone _ = True TWild _ == TWild _ = True TNil _ k1 == TNil _ k2 = k1 == k2 TRow _ k1 n1 t1 r1 == TRow _ k2 n2 t2 r2 = k1 == k2 && n1 == n2 && t1 == t2 && r1 == r2 TStar _ k1 r1 == TStar _ k2 r2 = k1 == k2 && r1 == r2 TFX _ fx1 == TFX _ fx2 = fx1 == fx2 _ == _ = False -- Show & Read ---------------- --instance Show Name where -- show n = show (nstr n) instance Read Name where readsPrec p str = [ (Name NoLoc s, str') | (s,str') <- readsPrec p str ] -- Helpers ------------------ importsOf (Module _ imps _ _) = impsOf imps where impsOf [] = [] impsOf (Import _ mis : i) = map mName mis ++ impsOf i impsOf (FromImport _ mr _ : i) = mRef mr : impsOf i impsOf (FromImportAll _ mr : i) = mRef mr : impsOf i mName (ModuleItem qn _) = qn mRef (ModRef (0,Just qn)) = qn mRef _ = error "dot prefix in name of import modules not supported" unop op e = UnOp l0 op e binop e1 op e2 = BinOp l0 e1 op e2 cmp e1 op e2 = CompOp l0 e1 [OpArg op e2] mkStringLit s = Strings l0 ['\'' : s ++ "\'"] isIdent s@(c:cs) = isAlpha c && all isAlphaNum cs && not (isKeyword s) where isAlpha c = c `elem` ['a'..'z'] || c `elem` ['A'..'Z'] || c == '_' isAlphaNum c = isAlpha c || c `elem` ['0'..'9'] isKeyword x = x `Data.Set.member` rws where rws = Data.Set.fromDistinctAscList [ "False","None","NotImplemented","Self","True","action","actor","after","and","as", "assert","async","await","break","class","continue","def","del","elif","else", "except","extension","finally","for","from","if","import","in","is","isinstance", "lambda","mut","not","or","pass","proc","protocol","pure","raise","return","try", "var","while","with","yield","_" ] isSig Signature{} = True isSig _ = False isDecl Decl{} = True isDecl _ = False isQVar (Var _ n) = Just n isQVar (TApp _ e _) = isQVar e isQVar e = Nothing isVar e = case isQVar e of Just (NoQ n) -> Just n; _ -> Nothing hasNotImpl ss = any isNotImpl ss -- Check for __cleanup__ method on actor hasCleanup ss = any isCleanup ss isCleanup (Def _ n _ _ _ _ _ _ _ _) = n == Name NoLoc "__cleanup__" isNotImpl (Expr _ e) = e == eNotImpl isNotImpl (Assign _ _ e) = e == eNotImpl isNotImpl (Decl _ ds) = any (hasNotImpl . dbody) ds isNotImpl _ = False notImplBody b = not $ null $ notImpls b notImpls b = [ e | Expr _ e <- b, e == eNotImpl ] isUnivar TUni{} = True isUnivar _ = False singlePosArg (PosArg _ PosNil) = True singlePosArg _ = False singlePosPat (PosPat _ PosPatNil) = True singlePosPat _ = False posParHead (PosPar a b c _) = (a,b,c) posArgHead (PosArg a _) = a ================================================ FILE: compiler/lib/src/Acton/Testing.hs ================================================ module Acton.Testing ( TestResult(..) , TestRunContext(..) , TestCachedResult(..) , TestCacheEntry(..) , TestCache(..) , TestHashInfo(..) , testCacheVersion , cachedResultFromTest , testResultFromCache , testCachePath , readTestCache , writeTestCache , contextHashBytes , hashRun , hashDeps , formatTestCacheContext , formatTestCacheLog , buildTestHashInfos , classifyCachedTests , updateTestCacheEntry , mkTestKey , testNameCandidates , lookupTestInfo , readModuleNameHashes , readModuleNameHashesByModName , readModuleNameHashesCached , resolveDepImplHash , resolveTestImplDeps , buildTestHashInfo ) where import qualified Acton.Compile as Compile import qualified Acton.Env import qualified Acton.Hashing as Hashing import qualified Acton.Syntax as A import qualified InterfaceFiles import Utils (prstr) import Control.Exception (SomeException, try) import Control.Monad (forM) import Data.Binary (encode) import qualified Crypto.Hash.SHA256 as SHA256 import qualified Data.Aeson as Aeson import qualified Data.Aeson.Key as AesonKey import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Base16 as Base16 import qualified Data.ByteString.Lazy as BL import Data.Either (partitionEithers) import Data.IORef import Data.List (intercalate, isPrefixOf, isSuffixOf, nub) import qualified Data.List import Data.Maybe (catMaybes, fromMaybe, listToMaybe) import qualified Data.Map as M import System.Directory (createDirectoryIfMissing, doesFileExist, renameFile) import System.FilePath ((), takeDirectory) data TestResult = TestResult { trModule :: String , trName :: String , trComplete :: Bool , trSuccess :: Maybe Bool , trSkipped :: Bool , trSkipReason :: Maybe String , trException :: Maybe String , trOutput :: Maybe String , trStdOut :: Maybe String , trStdErr :: Maybe String , trFlaky :: Bool , trNumSkipped :: Int , trNumFailures :: Int , trNumErrors :: Int , trNumIterations :: Int , trTestDuration :: Double , trRaw :: Aeson.Value , trSnapshotUpdated :: Bool , trCached :: Bool } deriving (Show) testCacheVersion :: Int testCacheVersion = 2 data TestRunContext = TestRunContext { trcCompilerVersion :: String , trcTarget :: String , trcOptimize :: String , trcMode :: String , trcArgs :: [String] } deriving (Show, Eq) instance Aeson.ToJSON TestRunContext where toJSON ctx = Aeson.object [ AesonKey.fromString "compilerVersion" Aeson..= trcCompilerVersion ctx , AesonKey.fromString "target" Aeson..= trcTarget ctx , AesonKey.fromString "optimize" Aeson..= trcOptimize ctx , AesonKey.fromString "mode" Aeson..= trcMode ctx , AesonKey.fromString "args" Aeson..= trcArgs ctx ] instance Aeson.FromJSON TestRunContext where parseJSON = Aeson.withObject "TestRunContext" $ \o -> TestRunContext <$> o Aeson..: AesonKey.fromString "compilerVersion" <*> o Aeson..: AesonKey.fromString "target" <*> o Aeson..: AesonKey.fromString "optimize" <*> o Aeson..: AesonKey.fromString "mode" <*> o Aeson..: AesonKey.fromString "args" data TestCachedResult = TestCachedResult { tcrComplete :: Bool , tcrSuccess :: Maybe Bool , tcrSkipped :: Bool , tcrSkipReason :: Maybe String , tcrException :: Maybe String , tcrOutput :: Maybe String , tcrStdOut :: Maybe String , tcrStdErr :: Maybe String , tcrFlaky :: Bool , tcrNumSkipped :: Int , tcrNumFailures :: Int , tcrNumErrors :: Int , tcrNumIterations :: Int , tcrTestDuration :: Double } deriving (Show, Eq) instance Aeson.ToJSON TestCachedResult where toJSON res = Aeson.object [ AesonKey.fromString "complete" Aeson..= tcrComplete res , AesonKey.fromString "success" Aeson..= tcrSuccess res , AesonKey.fromString "skipped" Aeson..= tcrSkipped res , AesonKey.fromString "skip_reason" Aeson..= tcrSkipReason res , AesonKey.fromString "exception" Aeson..= tcrException res , AesonKey.fromString "output" Aeson..= tcrOutput res , AesonKey.fromString "std_out" Aeson..= tcrStdOut res , AesonKey.fromString "std_err" Aeson..= tcrStdErr res , AesonKey.fromString "flaky" Aeson..= tcrFlaky res , AesonKey.fromString "num_skipped" Aeson..= tcrNumSkipped res , AesonKey.fromString "num_failures" Aeson..= tcrNumFailures res , AesonKey.fromString "num_errors" Aeson..= tcrNumErrors res , AesonKey.fromString "num_iterations" Aeson..= tcrNumIterations res , AesonKey.fromString "test_duration" Aeson..= tcrTestDuration res ] instance Aeson.FromJSON TestCachedResult where parseJSON = Aeson.withObject "TestCachedResult" $ \o -> TestCachedResult <$> o Aeson..: AesonKey.fromString "complete" <*> o Aeson..:? AesonKey.fromString "success" <*> o Aeson..:? AesonKey.fromString "skipped" Aeson..!= False <*> o Aeson..:? AesonKey.fromString "skip_reason" <*> o Aeson..:? AesonKey.fromString "exception" <*> o Aeson..:? AesonKey.fromString "output" <*> o Aeson..:? AesonKey.fromString "std_out" <*> o Aeson..:? AesonKey.fromString "std_err" <*> o Aeson..:? AesonKey.fromString "flaky" Aeson..!= False <*> o Aeson..:? AesonKey.fromString "num_skipped" Aeson..!= 0 <*> o Aeson..:? AesonKey.fromString "num_failures" Aeson..!= 0 <*> o Aeson..:? AesonKey.fromString "num_errors" Aeson..!= 0 <*> o Aeson..:? AesonKey.fromString "num_iterations" Aeson..!= 0 <*> o Aeson..:? AesonKey.fromString "test_duration" Aeson..!= 0 data TestCacheEntry = TestCacheEntry { tceRunHash :: String , tceImplHash :: Maybe String , tceResult :: TestCachedResult } deriving (Show, Eq) instance Aeson.ToJSON TestCacheEntry where toJSON entry = Aeson.object [ AesonKey.fromString "runHash" Aeson..= tceRunHash entry , AesonKey.fromString "implHash" Aeson..= tceImplHash entry , AesonKey.fromString "result" Aeson..= tceResult entry ] instance Aeson.FromJSON TestCacheEntry where parseJSON = Aeson.withObject "TestCacheEntry" $ \o -> TestCacheEntry <$> o Aeson..: AesonKey.fromString "runHash" <*> o Aeson..:? AesonKey.fromString "implHash" <*> o Aeson..: AesonKey.fromString "result" data TestCache = TestCache { tcVersion :: Int , tcContext :: TestRunContext , tcTests :: M.Map String TestCacheEntry } deriving (Show, Eq) instance Aeson.ToJSON TestCache where toJSON tc = Aeson.object [ AesonKey.fromString "version" Aeson..= tcVersion tc , AesonKey.fromString "context" Aeson..= tcContext tc , AesonKey.fromString "tests" Aeson..= tcTests tc ] instance Aeson.FromJSON TestCache where parseJSON = Aeson.withObject "TestCache" $ \o -> TestCache <$> o Aeson..: AesonKey.fromString "version" <*> o Aeson..: AesonKey.fromString "context" <*> o Aeson..:? AesonKey.fromString "tests" Aeson..!= M.empty -- | Convert a live test result into a cacheable payload. cachedResultFromTest :: TestResult -> TestCachedResult cachedResultFromTest res = TestCachedResult { tcrComplete = trComplete res , tcrSuccess = trSuccess res , tcrSkipped = trSkipped res , tcrSkipReason = trSkipReason res , tcrException = trException res , tcrOutput = trOutput res , tcrStdOut = trStdOut res , tcrStdErr = trStdErr res , tcrFlaky = trFlaky res , tcrNumSkipped = trNumSkipped res , tcrNumFailures = trNumFailures res , tcrNumErrors = trNumErrors res , tcrNumIterations = trNumIterations res , tcrTestDuration = trTestDuration res } -- | Rehydrate a cached payload into a TestResult. testResultFromCache :: String -> String -> TestCachedResult -> TestResult testResultFromCache modName testName res = TestResult { trModule = modName , trName = testName , trComplete = tcrComplete res , trSuccess = tcrSuccess res , trSkipped = tcrSkipped res , trSkipReason = tcrSkipReason res , trException = tcrException res , trOutput = tcrOutput res , trStdOut = tcrStdOut res , trStdErr = tcrStdErr res , trFlaky = tcrFlaky res , trNumSkipped = tcrNumSkipped res , trNumFailures = tcrNumFailures res , trNumErrors = tcrNumErrors res , trNumIterations = tcrNumIterations res , trTestDuration = tcrTestDuration res , trRaw = Aeson.Null , trSnapshotUpdated = False , trCached = True } data TestHashInfo = TestHashInfo { thiImplHash :: Maybe B.ByteString , thiRunHash :: Maybe String , thiResolvedName :: Maybe String , thiImplDeps :: Maybe [(A.QName, B.ByteString)] } deriving (Show, Eq) -- | Build an empty cache with the current context. emptyTestCache :: TestRunContext -> TestCache emptyTestCache ctx = TestCache { tcVersion = testCacheVersion , tcContext = ctx , tcTests = M.empty } -- | Resolve the on-disk test cache path for a project. testCachePath :: Compile.Paths -> FilePath testCachePath paths = Compile.projPath paths "out" "test" "cache.json" -- | Read the cache file, returning an empty cache on error/mismatch. readTestCache :: FilePath -> TestRunContext -> IO TestCache readTestCache path ctx = do exists <- doesFileExist path if not exists then return (emptyTestCache ctx) else do res <- (try :: IO a -> IO (Either SomeException a)) $ BL.readFile path case res of Left _ -> return (emptyTestCache ctx) Right bs -> case Aeson.decode bs of Just tc | tcVersion tc == testCacheVersion -> return tc _ -> return (emptyTestCache ctx) -- | Write the cache file atomically. writeTestCache :: FilePath -> TestCache -> IO () writeTestCache path tc = do createDirectoryIfMissing True (takeDirectory path) let tmpPath = path ++ ".tmp" BL.writeFile tmpPath (Aeson.encode tc) renameFile tmpPath path -- | Hash the test run context to include in cache keys. contextHashBytes :: TestRunContext -> B.ByteString contextHashBytes ctx = SHA256.hash (BL.toStrict (Aeson.encode ctx)) -- | Hex-encode a hash. toHex :: B.ByteString -> String toHex = B.unpack . Base16.encode -- | Hash impl/deps/context into a cache run hash string. hashRun :: B.ByteString -> B.ByteString -> B.ByteString -> String hashRun implHash depsHash ctxHash = toHex (SHA256.hash (B.concat [implHash, depsHash, ctxHash])) -- | Hash a dependency list with a stable ordering. hashDeps :: [(A.QName, B.ByteString)] -> B.ByteString hashDeps deps = let sorted = Data.List.sortOn (Hashing.qnameKey . fst) deps in SHA256.hash (BL.toStrict (encode sorted)) -- | Shorten a hash to 8 hex characters. shortHash :: B.ByteString -> String shortHash bs = take 8 (toHex bs) -- | Shorten a hex hash string to 8 characters. shortHashStr :: String -> String shortHashStr s = take 8 s -- | Format the verbose test cache context header. formatTestCacheContext :: B.ByteString -> FilePath -> String formatTestCacheContext ctxHash cachePath = "[test-cache] context=" ++ shortHash ctxHash ++ " path=" ++ cachePath -- | Format a dependency list with shortened hashes. formatDepsShort :: [(A.QName, B.ByteString)] -> String formatDepsShort deps = let entries = [ prstr qn ++ ":" ++ shortHash h | (qn, h) <- deps ] shown = take 6 entries suffix = if length entries > 6 then " +" ++ show (length entries - 6) ++ " more" else "" in "[" ++ intercalate ", " shown ++ suffix ++ "]" -- | Format a verbose cache log line for a test. formatTestCacheLog :: String -> String -> TestHashInfo -> Maybe TestCacheEntry -> String formatTestCacheLog modName testName info entry = let testLabel = formatTestName modName testName candidates = intercalate ", " (testNameCandidates testName) cacheStatus = case (thiRunHash info, entry) of (Just runHash, Just e) | tceRunHash e == runHash -> "hit" (Just _, Just _) -> "miss (hash)" (Just _, Nothing) -> "miss (none)" (Nothing, _) -> "miss (no hash)" base = "[test-cache] " ++ testLabel implDeps = maybe "" (\deps -> " deps=" ++ formatDepsShort deps) (thiImplDeps info) in case info of TestHashInfo (Just implHash) (Just runHash) resolved _ -> base ++ " name=" ++ maybe "?" id resolved ++ " impl=" ++ shortHash implHash ++ " run=" ++ shortHashStr runHash ++ implDeps ++ " cache=" ++ cacheStatus _ -> base ++ " no impl hash" ++ " candidates=[" ++ candidates ++ "]" ++ " cache=" ++ cacheStatus -- | Build TestHashInfo records for a list of tests. buildTestHashInfos :: Compile.Paths -> B.ByteString -> [(String, [String])] -> IO (M.Map String TestHashInfo) buildTestHashInfos paths ctxHash testsByModule = do moduleHashes <- forM testsByModule $ \(modName, _) -> do nameHashes <- readModuleNameHashes paths modName return (modName, nameHashes) let nameHashesByModule = M.fromList moduleHashes seedCache = M.fromList [ (A.modName (splitOnDot modName), nameMap) | (modName, nameMap) <- M.toList nameHashesByModule ] allTests = concatMap (\(modName, names) -> map (\name -> (modName, name)) names) testsByModule depCacheRef <- newIORef seedCache M.fromList <$> forM allTests (\(modName, testName) -> do let nameMap = M.findWithDefault M.empty modName nameHashesByModule info <- buildTestHashInfo depCacheRef paths ctxHash nameMap testName return (mkTestKey modName testName, info)) -- | Split tests into cached results and ones to run. classifyCachedTests :: (String -> IO ()) -> M.Map String TestCacheEntry -> M.Map String TestHashInfo -> [(String, String)] -> IO ([TestResult], [(String, String)]) classifyCachedTests logLine cacheEntries testHashInfos allTests = do classified <- forM allTests $ \(modName, testName) -> do let key = mkTestKey modName testName info = M.findWithDefault (TestHashInfo Nothing Nothing Nothing Nothing) key testHashInfos entry = M.lookup key cacheEntries logLine (formatTestCacheLog modName testName info entry) case entry of Just cached | Just runHash <- thiRunHash info , tceRunHash cached == runHash -> return (Left (testResultFromCache modName testName (tceResult cached))) _ -> return (Right (modName, testName)) return (partitionEithers classified) -- | Build a cache key from module and test name. mkTestKey :: String -> String -> String mkTestKey modName testName = modName ++ ":" ++ testName -- | Drop a prefix once if present. stripPrefixOnce :: String -> String -> Maybe String stripPrefixOnce pref s | pref `isPrefixOf` s = Just (drop (length pref) s) | otherwise = Nothing -- | Drop a suffix once if present. stripSuffixOnce :: String -> String -> Maybe String stripSuffixOnce suff s | suff `isSuffixOf` s = Just (take (length s - length suff) s) | otherwise = Nothing -- | Generate alternate test names for wrapper/prefix variants. testNameCandidates :: String -> [String] testNameCandidates name = nub $ catMaybes [ Just name , stripSuffixOnce "_wrapper" name , stripPrefixOnce "_test_" name , stripPrefixOnce "_test_" =<< stripSuffixOnce "_wrapper" name , stripSuffixOnce "_wrapper" =<< stripPrefixOnce "_test_" name ] -- | Resolve a test name to the stored NameHashInfo, if any. lookupTestInfo :: M.Map String InterfaceFiles.NameHashInfo -> String -> Maybe (String, InterfaceFiles.NameHashInfo) lookupTestInfo nameMap testName = listToMaybe [ (cand, info) | cand <- testNameCandidates testName , Just info <- [M.lookup cand nameMap] ] -- | Read the name hash map for a module name string. readModuleNameHashes :: Compile.Paths -> String -> IO (M.Map String InterfaceFiles.NameHashInfo) readModuleNameHashes paths modName = readModuleNameHashesByModName paths (A.modName (splitOnDot modName)) -- | Split a module name string on dots. splitOnDot :: String -> [String] splitOnDot = splitOnChar '.' -- | Split a string on a single delimiter character. splitOnChar :: Char -> String -> [String] splitOnChar ch input = case break (== ch) input of (chunk, []) -> [chunk] (chunk, _ : rest) -> chunk : splitOnChar ch rest -- | Read the name hash map for a module name. readModuleNameHashesByModName :: Compile.Paths -> A.ModName -> IO (M.Map String InterfaceFiles.NameHashInfo) readModuleNameHashesByModName paths mn = do mty <- Acton.Env.findTyFile (Compile.searchPath paths) mn case mty of Nothing -> return M.empty Just tyFile -> do hdrE <- (try :: IO a -> IO (Either SomeException a)) $ InterfaceFiles.readHeader tyFile case hdrE of Left _ -> return M.empty Right (_sourceMeta, _srcH, _ih, _implH, _imps, nameHashes, _roots, _tests, _doc) -> return $ M.fromList [ (A.nstr (InterfaceFiles.nhName nh), nh) | nh <- nameHashes ] -- | Cache-aware wrapper for reading name hashes. readModuleNameHashesCached :: IORef (M.Map A.ModName (M.Map String InterfaceFiles.NameHashInfo)) -> Compile.Paths -> A.ModName -> IO (M.Map String InterfaceFiles.NameHashInfo) readModuleNameHashesCached cacheRef paths mn = do cache <- readIORef cacheRef case M.lookup mn cache of Just nameMap -> return nameMap Nothing -> do nameMap <- readModuleNameHashesByModName paths mn atomicModifyIORef' cacheRef (\m -> (M.insert mn nameMap m, ())) return nameMap -- | Resolve a dependency QName to its current impl hash, if any. resolveDepImplHash :: IORef (M.Map A.ModName (M.Map String InterfaceFiles.NameHashInfo)) -> Compile.Paths -> A.QName -> IO (Maybe (A.QName, B.ByteString)) resolveDepImplHash cacheRef paths qn = case qn of A.GName m n -> resolve m n (A.GName m n) A.QName m n -> resolve m n (A.GName m n) A.NoQ _ -> return Nothing where resolve m n qn' = do nameMap <- readModuleNameHashesCached cacheRef paths m return $ (\info -> (qn', InterfaceFiles.nhImplHash info)) <$> M.lookup (A.nstr n) nameMap -- | Resolve recorded impl deps to current hashes, preserving fallbacks. resolveTestImplDeps :: IORef (M.Map A.ModName (M.Map String InterfaceFiles.NameHashInfo)) -> Compile.Paths -> InterfaceFiles.NameHashInfo -> IO [(A.QName, B.ByteString)] resolveTestImplDeps cacheRef paths info = do let deps = InterfaceFiles.nhImplDeps info forM deps $ \(qn, recorded) -> do resolved <- resolveDepImplHash cacheRef paths qn return (fromMaybe (qn, recorded) resolved) -- | Build the hash info for a single test name. buildTestHashInfo :: IORef (M.Map A.ModName (M.Map String InterfaceFiles.NameHashInfo)) -> Compile.Paths -> B.ByteString -> M.Map String InterfaceFiles.NameHashInfo -> String -> IO TestHashInfo buildTestHashInfo cacheRef paths ctxHash nameMap testName = do case lookupTestInfo nameMap testName of Nothing -> return (TestHashInfo Nothing Nothing Nothing Nothing) Just (resolved, info) -> do let implHash = InterfaceFiles.nhImplHash info deps <- resolveTestImplDeps cacheRef paths info let depsHash = hashDeps deps runHash = hashRun implHash depsHash ctxHash return (TestHashInfo (Just implHash) (Just runHash) (Just resolved) (Just deps)) -- | Update the cache map with a new test result. updateTestCacheEntry :: M.Map String TestHashInfo -> M.Map String TestCacheEntry -> TestResult -> M.Map String TestCacheEntry updateTestCacheEntry testHashInfos acc res = let key = mkTestKey (trModule res) (trName res) info = M.lookup key testHashInfos runHash = maybe "" (\ti -> fromMaybe "" (thiRunHash ti)) info implHashHex = info >>= fmap toHex . thiImplHash entry = TestCacheEntry { tceRunHash = runHash , tceImplHash = implHashHex , tceResult = cachedResultFromTest res } in M.insert key entry acc -- | Format a module+test display name. formatTestName :: String -> String -> String formatTestName modName testName = modName ++ "." ++ testName ================================================ FILE: compiler/lib/src/Acton/Transform.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} module Acton.Transform where import qualified Data.HashMap.Strict as M import Utils import Acton.Syntax import Acton.Names import Acton.Builtin import Acton.Prim import Acton.Printer import Acton.TypeEnv termred :: Equations -> Stmt -> Stmt termred eq s = --trace ("### equations:\n" ++ render (nest 4 $ vcat $ map pretty eq)) $ --trace ("### termred:\n" ++ render (nest 4 $ pretty s)) $ trans env0{ eqns = eq } s termsubst :: (Transform a) => [(Name,Expr)] -> a -> a termsubst [] x = x termsubst s x = trans (finalize $ extsubst s env0) x class Transform a where trans :: TransEnv -> a -> a type TSubst = M.HashMap Name (Maybe Expr) data TransEnv = TransEnv { eqns :: Equations, -- Top-level constraint solutions trsubst :: TSubst, -- Inlineable assignments and scope blockers witscope :: [(Name,Type,Expr)], -- Preserved witness bindings in scope, for the purpose of duplicate removals final :: Bool } env0 = TransEnv{ eqns = [], trsubst = M.empty, witscope = [], final = False } blockscope ns env = env{ trsubst = foldr (`M.insert` Nothing) (trsubst env) ns } extsubst ns env = env{ trsubst = foldr (\(n,e) -> M.insert n (Just e)) (trsubst env) ns } limsubst ns env = env{ trsubst = foldr M.delete (trsubst env) ns } trfind n env = case M.lookup n (trsubst env) of Just (Just e) -> Just e _ -> Nothing trfinds ns env = [ e | n <- ns, Just e <- [trfind n env] ] extscope n t e env = env{ witscope = (n,t,e) : witscope env } equalwit env e t = listToMaybe [ eVar w | (w,t',e') <- witscope env, e' == e, t' == t ] finalize env = env{ final = True } instance Pretty (Name,Expr) where pretty (n,e) = pretty n <+> text "~" <+> pretty e wtrans env ss | final env = map (trans env) ss wtrans env (Signature _ ws (TSchema _ [] (TWild _)) NoDec : ss) = wtrans env (bindWits eq ++ ss) where eq = findeqns ws (eqns env) wtrans env (s@(Assign l p@[PVar _ w (Just t)] e) : ss) | not (isWitness w) = trans env s : wtrans env ss | Lambda{} <- e = wtrans (extsubst [(w,e1)] env) ss | TApp _ Var{} _ <- e = wtrans (extsubst [(w,e1)] env) ss | Var{} <- e = wtrans (extsubst [(w,e1)] env) ss | Dot _ Var{} _ <- e = wtrans (extsubst [(w,e1)] env) ss | Just e' <- equalwit env e t = wtrans (extsubst [(w,e')] env) ss | otherwise = Assign l p e1 : wtrans (extscope w t e1 env) ss where e1 = trans env e wtrans env (s:ss) = trans env s : wtrans env ss wtrans env [] = [] instance (Transform a) => Transform [a] where trans env = map (trans env) instance (Transform a) => Transform (Maybe a) where trans env = fmap (trans env) instance Transform Stmt where trans env (Assign l ps e) = Assign l ps (trans env e) trans env (Expr l e) = Expr l (trans env e) trans env (MutAssign l t e) = MutAssign l (trans env t) (trans env e) trans env (AugAssign l t op e) = AugAssign l (trans env t) op (trans env e) trans env (Assert l e mbe) = Assert l (trans env e) (trans env mbe) trans env (Delete l t) = Delete l (trans env t) trans env (Return l mbe) = Return l (trans env mbe) trans env (Raise l e) = Raise l (trans env e) trans env (If l bs els) = If l (trans env bs) (trans env els) trans env (While l e b els) = While l (trans env e) (trans env b) (trans env els) trans env (For l p e b els) = For l p (trans env e) (trans env1 b) (trans env els) where env1 = blockscope (bound p) env trans env (Try l b hs els fin) = Try l (trans env b) (trans env hs) (trans env els) (trans env fin) trans env (With l is b) = With l (trans env1 is) (wtrans env1 b) where env1 = blockscope (bound is) env trans env (Data l mbp ss) = Data l mbp (trans env ss) trans env (VarAssign l ps e) = VarAssign l ps (trans env e) trans env (After l e e') = After l (trans env e) (trans env e') trans env (Decl l ds) = Decl l (trans env ds) trans env s = s instance Transform Decl where trans env (Def l n q p k t b d fx doc) = Def l n q (trans env1 p) (trans env1 k) t (wtrans env1 b) d fx doc where env1 = blockscope (bound p ++ bound k) env trans env (Actor l n q p k b doc) = Actor l n q (trans env1 p) (trans env1 k) (wtrans env1 b) doc where env1 = blockscope (bound p ++ bound k) env trans env (Class l n q us b doc) = Class l n q us (wtrans env b) doc trans env (Protocol l n q us b doc) = Protocol l n q us (wtrans env b) doc trans env (Extension l n q us b doc)= Extension l n q us (wtrans env b) doc transCall (Dot _ (Var _ n) m) ts [e1,e2] | n == primWrapProc, m == attrWrap = Just e2 | n == primWrapAction,m == attrWrap = Just $ eCall (tApp (eQVar primWRAP) ts) [e1,e2] | n == primWrapMut, m == attrWrap = Just e2 | n == primWrapPure, m == attrWrap = Just e2 transCall (Dot _ (Var _ n) m) ts [e1] | n == primWrapProc, m == attrUnwrap = Just e1 | n == primWrapAction,m == attrUnwrap = Just e1 | n == primWrapMut, m == attrUnwrap = Just e1 | n == primWrapPure, m == attrUnwrap = Just e1 transCall _ _ _ = Nothing instance Transform Expr where trans env (Var l (NoQ n)) | Just e <- trfind n env = if final env then e else trans (blockscope [n] env) e trans env ee@(Call l e p k) | Lambda{} <- e', Just s1 <- pzip (ppar e') p', Just s2 <- kzip (kpar e') k' = termsubst (s1++s2) (exp1 e') -- TODO: check that e' is linear in all its parameters! | TApp _ e0 ts <- e', Just e1 <- transCall e0 ts es = e1 | otherwise = Call l e' p' k' where e' = trans env e p' = trans env p k' = trans env k es = posargs p' trans env (TApp l e ts) = TApp l (trans env e) ts trans env (Async l e) = Async l (trans env e) trans env (Await l e) = Await l (trans env e) trans env (Let l ss e) = Let l (trans env ss) (trans env e) trans env (Index l e is) = Index l (trans env e) (trans env is) trans env (Slice l e sl) = Slice l (trans env e) (trans env sl) trans env (Cond l e1 e2 e3) = Cond l (trans env e1) (trans env e2) (trans env e3) trans env (IsInstance l e c) = IsInstance l (trans env e) c trans env (BinOp l e1 op e2) = BinOp l (trans env e1) op (trans env e2) trans env (CompOp l e ops) = CompOp l (trans env e) (trans env ops) trans env (UnOp l op e) = UnOp l op (trans env e) trans env (Dot l e n) | n `elem` valueKWs = Dot l e' n | Tuple{} <- e' = kwditem n $ kargs e' -- TODO: outrule side-effects in e | otherwise = Dot l e' n where e' = trans env e trans env (OptChain l e) = OptChain l (trans env e) trans env (Rest l e n) | Tuple{} <- e' = Tuple NoLoc PosNil (kwdrest n $ kargs e') -- TODO: outrule side-effects in e | otherwise = Rest l e' n where e' = trans env e trans env (DotI l e i) | Tuple{} <- e' = positem i $ pargs e' -- TODO: outrule side-effects in e | otherwise = DotI l e' i where e' = trans env e trans env (RestI l e i) | Tuple{} <- e' = Tuple NoLoc (posrest i $ pargs e') KwdNil -- TODO: outrule side-effects in e | otherwise = RestI l e' i where e' = trans env e trans env e0@(Lambda l p k e fx) | null clash = eta $ Lambda l (trans env1 p) (trans env1 k) (trans env1 e) fx | otherwise = eta $ Lambda l (trans env1 $ prename s p) (trans env1 $ krename s k) (trans env1 $ erename s e) fx where fvs = free e bvs = bound p ++ bound k env1 = limsubst bvs env clash = bvs `intersect` free (trfinds fvs env1) s = clash `zip` (yNames \\ (fvs++bvs)) e1 = Lambda l (prename s p) (krename s k) (erename s e) fx trans env (Yield l e) = Yield l (trans env e) trans env (YieldFrom l e) = YieldFrom l (trans env e) trans env (Tuple l p k) = Tuple l (trans env p) (trans env k) trans env (List l es) = List l (trans env es) trans env (ListComp l e c) = ListComp l (trans env1 e) (trans env1 c) where env1 = blockscope (bound c) env trans env (Dict l as) = Dict l (trans env as) trans env (DictComp l a c) = DictComp l (trans env1 a) (trans env1 c) where env1 = blockscope (bound c) env trans env (Set l es) = Set l (trans env es) trans env (SetComp l e c) = SetComp l (trans env1 e) (trans env1 c) where env1 = blockscope (bound c) env -- trans env (Paren l e) = Paren l (trans env e) trans env (Paren l e) = trans env e trans env e = e eta (Lambda _ p k (Call _ e p' k') fx) | eq1 p p' && eq2 k k' = e where eq1 (PosPar n _ _ p) (PosArg e p') = eVar n == e && eq1 p p' eq1 (PosSTAR n _) (PosStar e) = eVar n == e eq1 PosNIL PosNil = True eq1 _ _ = False eq2 (KwdPar n _ _ k) (KwdArg _ e k')= eVar n == e && eq2 k k' -- Requires perfectly sorted args, which the type-checker produces eq2 (KwdSTAR n _) (KwdStar e) = eVar n == e eq2 KwdNIL KwdNil = True eq2 _ _ = False eta ee@(Lambda _ (PosPar n (Just t) Nothing PosNIL) KwdNIL (Tuple _ p k) (TFX _ FXPure)) | idtup t p k = eLambda [(n,t)] (eVar n) where idtup (TTuple _ prow krow) p k = ptup (eVar n) 0 prow p && ktup (eVar n) krow k ptup e0 i TNil{} PosNil = True ptup e0 i r@TRow{} (PosArg e p) = idot e0 i e && ptup e0 (i+1) (rtail r) p ptup e0 i r@TStar{} (PosStar e) | Tuple _ p KwdNil <- e = ptup (eDotI e0 i) 0 (rtail r) p | otherwise = idot e0 i e ptup e0 i _ _ = False idot e0 i (DotI _ e i') = e == e0 && i' == i idot e0 i _ = False ktup e0 TNil{} KwdNil = True ktup e0 r@TRow{} (KwdArg x e k) = x == label r && xdot e0 x e && ktup e0 (rtail r) k ktup e0 r@TStar{} (KwdStar e) | Tuple _ PosNil k <- e = ktup (eDot e0 attrKW) (rtail r) k | otherwise = xdot e0 attrKW e ktup e0 _ _ = False xdot e0 x (Dot _ e x') = e == e0 && x' == x xdot e0 x _ = False eta e = e pzip (PosPar n _ _ p) (PosArg e a) = do p' <- pzip p a; return $ (n, e) : p' pzip (PosSTAR n _) (PosStar e) = Just [(n, e)] pzip PosNIL _ = Just [] pzip _ _ = Nothing kzip (KwdPar n _ _ k) (KwdArg _ e a) = do k' <- kzip k a; return $ (n, e) : k' -- Requires perfectly sorted args, which the type-checker produces kzip (KwdSTAR n _) (KwdStar e) = Just [(n, e)] kzip KwdNIL _ = Just [] kzip _ _ = Nothing positem 0 (PosArg e _) = e positem i (PosArg _ p) = positem (i-1) p kwditem n (KwdArg n' e _) | n == n' = e kwditem n (KwdArg _ _ k) = kwditem n k kwditem n (KwdStar e) | n == attrKW = e kwditem n arg = error ("#### Bad kwditem " ++ prstr n ++ " in " ++ prstr arg) posrest 0 (PosArg _ p) = p posrest i (PosArg e p) = PosArg e (posrest (i-1) p) kwdrest n (KwdArg n' e k) | n == n' = k kwdrest n (KwdArg n' e k) = KwdArg n' e (kwdrest n k) prename s (PosPar n t e p) = PosPar (rename s n) t e (prename s p) prename s (PosSTAR n t) = PosSTAR (rename s n) t prename s p = p krename s (KwdPar n t e k) = KwdPar (rename s n) t e (krename s k) krename s (KwdSTAR n t) = KwdSTAR (rename s n) t krename s k = k rename s n = case lookup n s of Just n' -> n' _ -> n erename s e = termsubst [ (n, eVar n') | (n,n') <- s ] e instance Transform Branch where trans env (Branch e ss) = Branch (trans env e) (trans env ss) instance Transform Handler where trans env (Handler ex b) = Handler ex (trans env1 b) where env1 = blockscope (bound ex) env instance Transform PosPar where trans env (PosPar n t e p) = PosPar n t (trans env e) (trans env p) trans env p = p instance Transform KwdPar where trans env (KwdPar n t e k) = KwdPar n t (trans env e) (trans env k) trans env k = k instance Transform PosArg where trans env (PosArg e p) = PosArg (trans env e) (trans env p) trans env (PosStar e) = PosStar (trans env e) trans env PosNil = PosNil instance Transform KwdArg where trans env (KwdArg n e k) = KwdArg n (trans env e) (trans env k) trans env (KwdStar e) = KwdStar (trans env e) trans env KwdNil = KwdNil instance Transform OpArg where trans env (OpArg op e) = OpArg op (trans env e) instance Transform Comp where trans env (CompFor l p e c) = CompFor l p (trans env e) (trans env c) trans env (CompIf l e c) = CompIf l (trans env e) (trans env c) trans env NoComp = NoComp instance Transform WithItem where trans env (WithItem e p) = WithItem (trans env e) p instance Transform Elem where trans env (Elem e) = Elem (trans env e) trans env (Star e) = Star (trans env e) instance Transform Assoc where trans env (Assoc e1 e2) = Assoc (trans env e1) (trans env e2) trans env (StarStar e) = StarStar (trans env e) instance Transform Sliz where trans env (Sliz l e1 e2 e3) = Sliz l (trans env e1) (trans env e2) (trans env e3) ================================================ FILE: compiler/lib/src/Acton/TypeEnv.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE FlexibleInstances, FlexibleContexts, DeriveGeneric #-} module Acton.TypeEnv where import Control.Monad import qualified Control.Exception import Control.Monad.State.Strict import Control.Monad.Except import Data.Char import Error.Diagnose hiding ((<>), err) import Prelude hiding ((<>)) import qualified Data.Map.Strict as Map import Data.Map.Strict (Map) import qualified Data.Set as Set import Data.Set (Set) import qualified Data.IntMap.Strict as IntMap import Data.IntMap.Strict (IntMap) import qualified Data.IntSet as IntSet import Data.IntSet (IntSet) import Pretty import Utils import Acton.Syntax import Acton.Builtin import Acton.Prim import Acton.Printer import Acton.Names import Acton.NameInfo import Acton.Subst import Acton.Env data TypeX = TypeX { activeWits :: [Witness], closedWits :: [Witness], activeWitMap :: WitMap, closedWitMap :: WitMap, posnames :: [Name], indecl :: Bool, forced :: Bool, tyids :: Map QName Int, tyinfos :: IntMap TyInfo, typrotos :: IntSet, tyactors :: IntSet } data TyInfo = TyInfo { tywild :: Type, tyabove :: IntSet, tybelow :: IntSet, tyattrs :: Set Name } type Env = EnvF TypeX type WitMap = Map QName [Witness] initTypeEnv :: Env0 -> Env initTypeEnv env0 = setX env0 $ foldl' importInfo x0 imps where x0 = TypeX { activeWits = [], closedWits = primWits, activeWitMap = Map.empty, closedWitMap = witMap primWits, posnames = [], indecl = False, forced = False, tyids = Map.empty, tyinfos = tyinfos0, typrotos = IntSet.empty, tyactors = IntSet.empty } importInfo x (m,te) = setupCons f te $ setupWits addClosedWit f te x where f = GName m imps | inBuiltin env0 = [] | otherwise = [ (m, fromJust $ lookupMod m env0) | m <- mBuiltin : transitiveImports env0 ] tyinfos0 = IntMap.fromDistinctAscList pairs where pairs = [ (tyid t, TyInfo t (iset above) (iset below) Set.empty) | (t,above,below) <- graph ] tyid t = fromJust $ elemIndex t wtypes iset ts = IntSet.fromDistinctAscList $ map tyid ts wtypes = [ t | (t,_,_) <- graph ] graph = [ (wOpt, [wOpt], [wOpt,tNone]), -- Watch out for tNone here! (tNone, [wOpt,tNone], [tNone]), (wFun, [wOpt, wFun], [wFun]), (wTuple, [wOpt, wTuple], [wTuple]), (fxProc, [fxProc], [fxProc,fxMut,fxPure,fxAction]), (fxMut, [fxProc,fxMut], [fxMut,fxPure]), (fxPure, [fxProc,fxMut,fxPure], [fxPure]), (fxAction, [fxProc,fxAction], [fxAction]) ] wFun = tFun tWild tWild tWild tWild wTuple = tTuple tWild tWild wOpt = tOpt tWild instance Show TypeX where show _ = "" printX env = render (nest 4 $ vcat $ map (prinfo x) $ Map.assocs $ tyids x) where x = envX env instance Pretty TypeX where pretty x = text "--- witnesses:" $+$ vcat (map pretty (witnesses x)) prinfo x (n, tid) = pretty (noq n) <+> text "=" <+> pretty tid <> colon $+$ nest 4 (text "above" <> colon <+> commaSep pretty (IntSet.toAscList $ tyabove info) $+$ text "below" <> colon <+> commaSep pretty (IntSet.toAscList $ tybelow info) $+$ text "attrs" <> colon <+> commaSep pretty (Set.elems $ tyattrs info)) where info = tyinfos x IntMap.! tid instance USubst TypeX where usubst x = do we <- usubst (activeWits x) return x{ activeWits = we, activeWitMap = witMap we } instance UFree TypeX where ufree x = ufree (activeWits x) witnesses :: TypeX -> [Witness] witnesses x = activeWits x ++ closedWits x witMap :: [Witness] -> WitMap witMap = foldr addWit Map.empty nextid x = 1 + fst (IntMap.findMax $ tyinfos x) addconinfo :: (Name -> QName) -> TypeX -> (Name,NameInfo) -> TypeX addconinfo f x (n,i) | NClass q us te _ <- i = addcon n q us te x | NProto q us te _ <- i = addproto $ addcon n q us te x | NAct q _ _ te _ <- i = addactor $ addcon n q [] te x | otherwise = x where tid = nextid x addproto x = x{ typrotos = IntSet.insert tid (typrotos x) } addactor x = x{ tyactors = IntSet.insert tid (tyactors x) } addcon n q us te x = x{ tyids = Map.insert (f n) tid (tyids x), tyinfos = IntMap.insert tid info tyinfos' } where ui = [ tyids x Map.! tcname c | (_,c) <- us ] info = TyInfo { tywild = tCon $ TC (NoQ n) [ tWild | _ <- q ], tyabove = IntSet.fromList ui, tybelow = IntSet.singleton tid, tyattrs = foldr Set.union (Set.fromList $ dom te) [ tyattrs $ fromJust $ IntMap.lookup u $ tyinfos x | u <- ui ] } tyinfos' = foldr (IntMap.adjust addbelow) (tyinfos x) ui addbelow info = info{ tybelow = IntSet.insert tid (tybelow info) } tydefine :: TEnv -> Env -> Env tydefine te env = modX (define te env) (setupCons f te . setupWits addActiveWit NoQ te) where f = if inBuiltin env then GName mBuiltin else NoQ tydefineClosed :: TEnv -> Env -> Env tydefineClosed te env = modX (defineClosed te env) (setupCons f te . setupWits addClosedWit NoQ te) where f = if inBuiltin env then GName mBuiltin else NoQ setupCons :: (Name -> QName) -> TEnv -> TypeX -> TypeX setupCons f te x = foldl' (addconinfo f) x te setupWits :: (TypeX -> Witness -> TypeX) -> (Name -> QName) -> TEnv -> TypeX -> TypeX setupWits add f te x = foldl' add x wits where wits = [ WClass q (tCon c) p (f n) ws (length opts) | (n, NExt q c ps te' opts _) <- te, (ws,p) <- ps ] addvarinfo x (tv, c, _) = x{ tyids = Map.insert (NoQ $ tvname tv) tid (tyids x), tyinfos = IntMap.insert tid info tyinfos' } where tid = nextid x ci = tyinfos x IntMap.! (tyids x Map.! tcname c) info = TyInfo { tywild = tVar tv, tyabove = IntSet.insert tid $ tyabove ci, tybelow = IntSet.singleton tid, tyattrs = tyattrs ci } tyinfos' = IntSet.foldr' (IntMap.adjust addbelow) (tyinfos x) (tyabove ci) addbelow info = info{ tybelow = IntSet.insert tid (tybelow info) } tydefineVars :: QBinds -> Env -> Env tydefineVars q env = modX env1 (\x -> foldl' addvarinfo x tvs) where env1 = modX env0 (\x -> foldl' addActiveWit x wits) env0 = defineTVars q env tvs = [ (TV k v, c, us) | (v, NTVar k c us) <- take (length q) (activeNames env0), let tv = TV k v ] wits = [ WInst [] (tVar tv) p (NoQ $ tvarWit tv u) wchain | (tv, _, us) <- tvs, u <- us, (wchain,p) <- findAncestry env u ] tydefineInst :: TCon -> [WTCon] -> Name -> Env -> Env tydefineInst c ps w env = modX env (\x -> foldl' addActiveWit x wits) where wits = [ WInst [] (tCon c) p (NoQ w) ws | (ws,p) <- ps ] addActiveWit :: TypeX -> Witness -> TypeX addActiveWit x wit | null same = x{ activeWits = wit : activeWits x, activeWitMap = addWit wit (activeWitMap x) } | otherwise = x where same = [ w | w <- witsByPNameX x (tcname $ proto wit), wtype w == wtype wit ] addClosedWit :: TypeX -> Witness -> TypeX addClosedWit x wit | null same = x{ closedWits = wit : closedWits x, closedWitMap = addWit wit (closedWitMap x) } | otherwise = x where same = [ w | w <- witsByPNameX x (tcname $ proto wit), wtype w == wtype wit ] addWit :: Witness -> WitMap -> WitMap addWit w = Map.insertWith (++) (tcname $ proto w) [w] witsByPNameX x pn = Map.findWithDefault [] pn (activeWitMap x) ++ Map.findWithDefault [] pn (closedWitMap x) witsByPName :: Env -> QName -> [Witness] witsByPName env pn = witsByPNameX (envX env) pn witsByTName :: Env -> QName -> [Witness] witsByTName env tn = [ w | w <- activeWits x, eqname (wtype w) ] ++ [ w | w <- closedWits x, eqname (wtype w) ] where eqname (TCon _ c) = tcname c == tn eqname (TVar _ v) = NoQ (tvname v) == tn eqname _ = False x = envX env limitQuant :: TUni -> Env -> Env limitQuant (UV _ l _) env | n <= 0 = env | otherwise = modX env1 $ \x -> let we = dropw (activeWits x) in x{ activeWits = we, activeWitMap = witMap we } where env1 = setActiveNames (dropv n (activeNames env)) env{ qlevel = qlevel env - n } n = qlevel env - l vs = takev n (activeNames env) takev 0 te = [] takev n ((v,i):te) | NTVar{} <- i = v : takev (n-1) te | otherwise = takev n te dropv 0 te = te dropv n ((v,i):te) | NTVar{} <- i = dropv (n-1) te | otherwise = (v,i) : dropv n te dropw (WInst{wtype=TVar _ (TV _ v)} : we) | v `elem` vs = dropw we dropw we = we posdefine te env = modX (tydefine te env) $ \x -> x{ posnames = dom te ++ posnames x } setInDecl env = modX env $ \x -> x{ indecl = True } useForce env = modX env $ \x -> x{ forced = True } inDecl env = indecl $ envX env isForced env = forced $ envX env instance Polarity Env where polvars env = polvars pte `polcat` invvars ite where (pte, ite) = span ((`elem` pvs) . fst) (activeNames env) pvs = posnames $ envX env -- Constraints ------------------------------------------------------------------------------- data Constraint = Cast {info :: ErrInfo, scope :: Env, type1 :: Type, type2 :: Type} | Sub {info :: ErrInfo, scope :: Env, wit :: Name, type1 :: Type, type2 :: Type} | Proto {info :: ErrInfo, scope :: Env, wit :: Name, type1 :: Type, proto1 :: PCon} | Sel {info :: ErrInfo, scope :: Env, wit :: Name, type1 :: Type, name1 :: Name, type2 :: Type} | Mut {info :: ErrInfo, scope :: Env, type1 :: Type, name1 :: Name, type2 :: Type} | Seal {info :: ErrInfo, scope :: Env, type1 :: Type} deriving (Show) type Constraints = [Constraint] instance HasLoc Constraint where loc (Cast info env t1 t2) = getLoc [loc info, loc t1, loc t2] loc (Sub info env _ t1 t2) = getLoc [loc info, loc t1, loc t2] loc (Proto info _ env t1 _) = getLoc [loc info, loc t1] loc (Sel info _ env t1 n1 t2) = getLoc [loc info, loc t1, loc n1, loc t2] loc (Mut info env t1 n1 t2) = getLoc [loc info, loc t1, loc n1, loc t2] loc (Seal info env t1) = getLoc [loc info, loc t1] instance Pretty Constraint where pretty (Cast _ env t1 t2) = prettyQuant env <+> pretty t1 <+> text "<" <+> pretty t2 pretty (Sub _ env w t1 t2) = prettyQuant env <+> pretty w <+> colon <+> pretty t1 <+> text "<" <+> pretty t2 pretty (Proto _ env w t u) = prettyQuant env <+> pretty w <+> colon <+> pretty t <+> parens (pretty u) pretty (Sel _ env w t1 n t2) = prettyQuant env <+> pretty w <+> colon <+> pretty t1 <> text "." <> pretty n <+> text "<" <+> pretty t2 pretty (Mut _ env t1 n t2) = prettyQuant env <+> pretty t1 <+> text "." <> pretty n <+> text ">" <+> pretty t2 pretty (Seal _ env t) = prettyQuant env <+> text "$Seal" <+> pretty t prettyQuant env | qlevel env > 0 = brackets (commaSep pretty q) <+> text "=>" | otherwise = empty where q = [ QBind (TV k tv) (if c == cValue then ps else c:ps) | (tv, NTVar k c ps) <- activeNames env ] instance VFree Constraint where vfree (Cast info env t1 t2) = vfree t1 ++ vfree t2 vfree (Sub info env w t1 t2) = vfree t1 ++ vfree t2 vfree (Proto info env w t p) = vfree t ++ vfree p vfree (Sel info env w t1 n t2) = vfree t1 ++ vfree t2 vfree (Mut info env t1 n t2) = vfree t1 ++ vfree t2 vfree (Seal info env t) = vfree t instance UFree Constraint where ufree (Cast info env t1 t2) = ufree t1 ++ ufree t2 ufree (Sub info env w t1 t2) = ufree t1 ++ ufree t2 ufree (Proto info env w t p) = ufree t ++ ufree p ufree (Sel info env w t1 n t2) = ufree t1 ++ ufree t2 ufree (Mut info env t1 n t2) = ufree t1 ++ ufree t2 ufree (Seal info env t) = ufree t instance Tailvars Constraint where tailvars (Cast _ env t1 t2) = tailvars t1 ++ tailvars t2 tailvars (Sub _ env w t1 t2) = tailvars t1 ++ tailvars t2 tailvars (Proto _ env w t p) = tailvars t ++ tailvars p tailvars (Sel _ env w t1 n t2) = tailvars t1 ++ tailvars t2 tailvars (Mut _ env t1 n t2) = tailvars t1 ++ tailvars t2 tailvars (Seal _ env t) = tailvars t instance Vars Constraint where freeQ (Cast _ env t1 t2) = freeQ t1 ++ freeQ t2 freeQ (Sub _ env w t1 t2) = freeQ t1 ++ freeQ t2 freeQ (Proto _ env w t p) = freeQ t ++ freeQ p freeQ (Sel _ env w t1 n t2) = freeQ t1 ++ freeQ t2 freeQ (Mut _ env t1 n t2) = freeQ t1 ++ freeQ t2 freeQ (Seal _ env t) = freeQ t instance UWild Constraint where uwild (Cast info env t1 t2) = Cast info env (uwild t1) (uwild t2) uwild (Sub info env w t1 t2) = Sub info env w (uwild t1) (uwild t2) uwild (Proto info env w t p) = Proto info env w (uwild t) (uwild p) uwild (Sel info env w t1 n t2) = Sel info env w (uwild t1) n (uwild t2) uwild (Mut info env t1 n t2) = Mut info env (uwild t1) n (uwild t2) uwild (Seal info env t) = Seal info env (uwild t) instance VSubst Constraint where vsubst s (Cast i env t1 t2) = Cast i env (vsubst s t1) (vsubst s t2) vsubst s (Sub i env w t1 t2) = Sub i env w (vsubst s t1) (vsubst s t2) vsubst s (Proto i env w t p) = Proto i env w (vsubst s t) (vsubst s p) vsubst s (Sel i env w t1 n t2) = Sel i env w (vsubst s t1) n (vsubst s t2) vsubst s (Mut i env t1 n t2) = Mut i env (vsubst s t1) n (vsubst s t2) vsubst s (Seal i env t) = Seal i env (vsubst s t) requantize env cs = map requant cs where requant (Cast i _ t1 t2) = Cast i env t1 t2 requant (Sub i _ w t1 t2) = Sub i env w t1 t2 requant (Proto i _ w t p) = Proto i env w t p requant (Sel i _ w t1 n t2) = Sel i env w t1 n t2 requant (Mut i _ t1 n t2) = Mut i env t1 n t2 requant (Seal i _ t) = Seal i env t closeDepVars vs cs | null vs' = nub vs | otherwise = closeDepVars (vs'++vs) cs where vs' = concat [ deps c \\ vs | c <- cs, all (`elem` vs) (heads c) ] heads (Proto _ w _ t _) = ufree t heads (Cast _ _ t _) = ufree t heads (Sub _ w _ t _) = ufree t heads (Sel _ w _ t n _) = ufree t heads (Mut _ _ t n _) = ufree t heads (Seal _ _ t) = ufree t deps (Proto _ w _ _ p) = ufree p deps (Cast _ _ _ t) = typarams t deps (Sub _ w _ _ t) = typarams t deps (Sel _ w _ _ n t) = ufree t deps (Mut _ _ _ n t) = ufree t deps (Seal _ _ _) = [] typarams (TOpt _ t) = typarams t typarams (TCon _ c) = ufree c typarams _ = [] closePolVars :: ([TUni],[TUni]) -> Constraints -> ([TUni],[TUni]) closePolVars pvs cs | polnull (pvs' `polminus` pvs) = pvs' | otherwise = closePolVars pvs' cs' where (pvs',cs') = boundvs pvs cs boundvs pn [] = (pn, []) boundvs (p,n) (Cast _ _ (TUni _ v) (TUni _ u) : cs) = boundvs (if u `elem` p then v:p else p, if v `elem` n then u:n else n) cs boundvs (p,n) (Sub _ _ _ (TUni _ v) (TUni _ u) : cs) = boundvs (if u `elem` p then v:p else p, if v `elem` n then u:n else n) cs boundvs pn (Cast _ _ t (TUni _ v) : cs) | v `elem` fst pn = boundvs (polvars t `polcat` pn) cs boundvs pn (Sub _ _ _ t (TUni _ v) : cs) | v `elem` fst pn = boundvs (polvars t `polcat` pn) cs boundvs pn (Cast _ _ (TUni _ v) t : cs) | v `elem` snd pn = boundvs (polneg (polvars t) `polcat` pn) cs boundvs pn (Sub _ _ _ (TUni _ v) t : cs) | v `elem` snd pn = boundvs (polneg (polvars t) `polcat` pn) cs boundvs pn (Proto _ _ _ (TUni _ v) p : cs) | v `elem` snd pn = boundvs (polneg (polvars p) `polcat` pn) cs boundvs pn (Sel _ _ _ (TUni _ v) _ t : cs) | v `elem` snd pn = boundvs (polneg (polvars t) `polcat` pn) cs boundvs pn (Mut _ _ (TUni _ v) _ t : cs) | v `elem` (fst pn ++ snd pn) = boundvs (invvars t `polcat` pn) cs boundvs pn (c : cs) = let (pn',cs') = boundvs pn cs in (pn', c:cs') headvar (Proto _ w _ (TUni _ u) p) = u headvar (Cast _ _ TVar{} (TUni _ u)) = u headvar (Cast _ _ (TUni _ u) t) = u headvar (Cast _ _ t (TUni _ u)) = u -- ? headvar (Sub _ w _ TVar{} (TUni _ u)) = u headvar (Sub _ w _ (TUni _ u) t) = u headvar (Sub _ w _ t (TUni _ u)) = u -- ? headvar (Sel _ w _ (TUni _ u) n t) = u headvar (Mut _ _ (TUni _ u) n t) = u headvar (Seal _ _ (TUni _ u)) = u -- Type inference monad ------------------------------------------------------------------ data TypeState = TypeState { nextint :: Int, uniqprefix :: String, -- Prefix for generated names effectstack :: [(TFX,Type)], deferred :: Constraints, unisubst :: IntMap Type } initTypeState p = TypeState { nextint = 1, uniqprefix = p, effectstack = [], deferred = [], unisubst = IntMap.empty } type TypeM a = ExceptT TypeError (State TypeState) a runTypeMState :: String -> TypeM a -> Either TypeError (a, TypeState) runTypeMState p m = case runState (runExceptT m) (initTypeState p) of (Right x, st') -> Right (x, st') (Left err, _) -> Left err runTypeM :: TypeM a -> a runTypeM m = case runTypeMState "" m of Right (x,_) -> x Left err -> Control.Exception.throw err currentState :: TypeM TypeState currentState = lift $ state $ \st -> (st, st) rollbackState :: TypeState -> TypeM () rollbackState st = lift $ state $ \_ -> ((), st) newUnique :: TypeM Int newUnique = lift $ state $ \st -> (nextint st, st{ nextint = nextint st + 1 }) pushFX :: TFX -> Type -> TypeM () pushFX fx ret = lift $ state $ \st -> ((), st{ effectstack = (fx,ret) : effectstack st }) currFX :: TypeM TFX currFX = lift $ state $ \st -> (fst $ head $ effectstack st, st) currRet :: TypeM Type currRet = lift $ state $ \st -> (snd $ head $ effectstack st, st) popFX :: TypeM () popFX = lift $ state $ \st -> ((), st{ effectstack = tail (effectstack st) }) defer :: Constraints -> TypeM () defer cs = lift $ state $ \st -> ((), st{ deferred = cs ++ deferred st }) collectDeferred :: TypeM Constraints collectDeferred = lift $ state $ \st -> (deferred st, st{ deferred = [] }) usubstitute :: TUni -> Type -> TypeM () usubstitute uv t = lift $ --trace (" #usubstitute " ++ prstr uv ++ " ~ " ++ prstr t) $ state $ \st -> ((), st{ unisubst = IntMap.insert (uvid uv) t (unisubst st)}) usubstitution :: TypeM (IntMap Type) usubstitution = lift $ state $ \st -> (unisubst st, st) uextend :: [(TUni,Type)] -> TypeM () uextend s = lift $ state $ \st -> ((), st{ unisubst = IntMap.union (unisubst st) (IntMap.fromList [ (uvid u,t) | (u,t) <- s ])}) -- Name generation ------------------------------------------------------------------------------------------------------------------ newGenerated p = do i <- newUnique st <- currentState return $ Internal p (tag (uniqprefix st) i) 0 where tag "" i = show i tag s i = s ++ "_" ++ show i newWitness = newGenerated Witness newTmp = newGenerated Tempvar newUnivarOfKind k env = TUni NoLoc <$> univar k (qlevel env) <$> newUnique newUnivarToken n = TUni NoLoc $ unitoken n newUnivars env ks = mapM (\k -> newUnivarOfKind k env) ks newUnivar env = newUnivarOfKind KType env -- unification ---------------------------------------------------------------------------------------------------------------------- tryUnify info t1 t2 = unify info t1 t2 `catchError` \err -> Control.Exception.throw err unify :: ErrInfo -> Type -> Type -> TypeM () unify info t1 t2 = do t1' <- usubst t1 t2' <- usubst t2 --traceM (" #unify " ++ prstr t1' ++ " and " ++ prstr t2') unify' info t1' t2' unifyM info ts1 ts2 = mapM_ (uncurry $ unify info) (ts1 `zip` ts2) unify' _ (TWild _) t2 = return () unify' _ t1 (TWild _) = return () unify' info (TCon _ c1) (TCon _ c2) | tcname c1 == tcname c2 = unifyM info (tcargs c1) (tcargs c2) unify' info (TFun _ fx1 p1 k1 t1) (TFun _ fx2 p2 k2 t2) = do unify info fx1 fx2 unify info p2 p1 unify info k2 k1 unify info t1 t2 unify' info (TTuple _ p1 k1) (TTuple _ p2 k2) = do unify info p1 p2 unify info k1 k2 unify' info (TOpt _ t1) (TOpt _ t2) = unify info t1 t2 unify' _ (TNone _) (TNone _) = return () unify' _ (TFX _ fx1) (TFX _ fx2) | fx1 == fx2 = return () unify' _ (TNil _ k1) (TNil _ k2) | k1 == k2 = return () unify' info (TRow _ k1 n1 t1 r1) (TRow _ k2 n2 t2 r2) | k1 == k2 && n1 == n2 = do unify info t1 t2 unify info r1 r2 unify' info (TStar _ k1 r1) (TStar _ k2 r2) | k1 == k2 = unify info r1 r2 unify' info (TVar _ v1) (TVar _ v2) | v1 == v2 = return () unify' info t1@(TUni _ v1) t2@(TUni _ v2) | v1 == v2 = return () | uvlevel v1 < uvlevel v2 = usubstitute v2 t1 | otherwise = usubstitute v1 t2 -- Retain the var with the smallest ulevel (largest scope) unify' info (TUni _ v) t2 = do when (v `elem` ufree t2) (infiniteType v t2) usubstitute v t2 unify' info t1 (TUni _ v) = do when (v `elem` ufree t1) (infiniteType v t1) usubstitute v t1 unify' info t1 t2 = noUnify info t1 t2 -- Asymmetric matching -------------------------------------------------------------------------------- match vs (TWild _) t = Just [] match vs t (TWild _) = Just [] match vs (TUni _ _) t = Just [] match vs t (TUni _ _) = Just [] match vs (TCon _ c1) (TCon _ c2) | tcname c1 == tcname c2 = matches vs (tcargs c1) (tcargs c2) match vs (TFun _ fx1 p1 k1 t1) (TFun _ fx2 p2 k2 t2) = matches vs [fx1,p1,k1,t1] [fx2,p2,k2,t2] match vs (TTuple _ p1 k1) (TTuple _ p2 k2) = matches vs [p1,k1] [p2,k2] match vs (TOpt _ t1) (TOpt _ t2) = match vs t1 t2 match vs (TNone _) (TNone _) = Just [] match vs (TFX _ fx1) (TFX _ fx2) | fx1 == fx2 = Just [] match vs (TNil _ k1) (TNil _ k2) | k1 == k2 = Just [] match vs (TRow _ k1 n1 t1 r1) (TRow _ k2 n2 t2 r2) | k1 == k2 && n1 == n2 = matches vs [t1,r1] [t2,r2] match vs (TStar _ k1 r1) (TStar _ k2 r2) | k1 == k2 = match vs r1 r2 match vs (TVar _ tv1) (TVar _ tv2) | tv1 == tv2 = Just [] match vs t1 (TVar _ tv) | tv `elem` vs && tv `notElem` vfree t1 = Just [(tv, t1)] match vs t1 t2 = Nothing matches vs [] [] = Just [] matches vs (t:ts) (t':ts') = do s1 <- match vs t t' s2 <- matches vs ts ts' merge s1 s2 where merge s1 s2 | agree = Just $ s1 ++ s2 | otherwise = Nothing where agree = and [ vsubst s1 (tVar v) `wildeq` vsubst s2 (tVar v) | v <- dom s1 `intersect` dom s2 ] t `wildeq` t' = match [] t t' == Just [] -- USubst --------------------------------------------------------------------------------------------- class USubst t where usubst :: t -> TypeM t instance USubst a => USubst (Name,a) where usubst (n, t) = (,) <$> return n <*> usubst t instance (USubst a, USubst b) => USubst (QName,a,b) where usubst (n, t, u) = (,,) <$> return n <*> usubst t <*> usubst u instance USubst a => USubst [a] where usubst = mapM usubst instance USubst a => USubst (Maybe a) where usubst = maybe (return Nothing) (\x -> Just <$> usubst x) instance USubst Constraint where usubst (Cast info env t1 t2) = Cast <$> usubst info <*> return env <*> usubst t1 <*> usubst t2 usubst (Sub info env w t1 t2) = Sub <$> usubst info <*> return env <*> return w <*> usubst t1 <*> usubst t2 usubst (Proto info env w t p) = Proto <$> usubst info <*> return env <*> return w <*> usubst t <*> usubst p usubst (Sel info env w t1 n t2) = Sel <$> usubst info <*> return env <*> return w <*> usubst t1 <*> return n <*> usubst t2 usubst (Mut info env t1 n t2) = Mut <$> usubst info <*> return env <*> usubst t1 <*> return n <*> usubst t2 usubst (Seal info env t) = Seal <$> usubst info <*> return env <*> usubst t instance USubst ErrInfo where usubst (DfltInfo l n mbe ts) = DfltInfo l n <$> usubst mbe <*> usubst ts usubst (DeclInfo l1 l2 n t msg) = DeclInfo l1 l2 n <$> usubst t <*> return msg usubst info = return info instance USubst TSchema where usubst (TSchema l [] t) = TSchema l [] <$> usubst t usubst (TSchema l q t) = TSchema l <$> usubst q <*> usubst t instance USubst TVar where usubst v = do t <- usubst (TVar NoLoc v) case t of TVar _ v' -> return v' _ -> return v instance USubst TCon where usubst (TC n ts) = TC n <$> usubst ts instance USubst QBind where usubst (QBind v cs) = QBind <$> usubst v <*> usubst cs instance USubst WTCon where usubst (wpath, p) = do p <- usubst p; return (wpath, p) instance USubst Type where usubst (TUni l u) = do s <- usubstitution case IntMap.lookup (uvid u) s of Just t -> usubst t Nothing -> return (TUni l u) usubst (TVar l v) = return $ TVar l v usubst (TCon l c) = TCon l <$> usubst c usubst (TFun l fx p k t) = TFun l <$> usubst fx <*> usubst p <*> usubst k <*> usubst t usubst (TTuple l p k) = TTuple l <$> usubst p <*> usubst k usubst (TOpt l t) = do t' <- usubst t case t' of TOpt{} -> return t' _ -> return $ TOpt l t' usubst (TNone l) = return $ TNone l usubst (TWild l) = return $ TWild l usubst (TNil l s) = return $ TNil l s usubst (TRow l k n t r) = TRow l k n <$> usubst t <*> usubst r usubst (TStar l k r) = TStar l k <$> usubst r usubst (TFX l fx) = return $ TFX l fx instance USubst PosPar where usubst (PosPar n t e p) = PosPar n <$> usubst t <*> usubst e <*> usubst p usubst (PosSTAR n t) = PosSTAR n <$> usubst t usubst PosNIL = return PosNIL instance USubst KwdPar where usubst (KwdPar n t e p) = KwdPar n <$> usubst t <*> usubst e <*> usubst p usubst (KwdSTAR n t) = KwdSTAR n <$> usubst t usubst KwdNIL = return KwdNIL instance USubst Decl where usubst (Def l n q p k a ss de fx doc) = Def l n <$> usubst q <*> usubst p <*> usubst k <*> usubst a <*> usubst ss <*> return de <*> usubst fx <*> return doc usubst (Actor l n q p k ss doc) = Actor l n <$> usubst q <*> usubst p <*> usubst k <*> usubst ss <*> return doc usubst (Class l n q bs ss doc) = Class l n <$> usubst q <*> usubst bs <*> usubst ss <*> return doc usubst (Protocol l n q bs ss doc) = Protocol l n <$> usubst q <*> usubst bs <*> usubst ss <*> return doc usubst (Extension l q c bs ss doc) = Extension l <$> usubst q <*> usubst c <*> usubst bs <*> usubst ss <*> return doc instance USubst Stmt where usubst (Expr l e) = Expr l <$> usubst e usubst (Assign l ps e) = Assign l <$> usubst ps <*> usubst e usubst (MutAssign l t e) = MutAssign l <$> usubst t <*> usubst e usubst (AugAssign l t op e) = AugAssign l <$> usubst t <*> return op <*> usubst e usubst (Assert l e mbe) = Assert l <$> usubst e <*> usubst mbe usubst (Delete l t) = Delete l <$> usubst t usubst (Return l mbe) = Return l <$> usubst mbe usubst (Raise l e) = Raise l <$> usubst e usubst (If l bs els) = If l <$> usubst bs <*> usubst els usubst (While l e b els) = While l <$> usubst e <*> usubst b <*> usubst els usubst (For l p e b els) = For l <$> usubst p <*> usubst e <*> usubst b <*> usubst els usubst (Try l b hs els fin) = Try l <$> usubst b <*> usubst hs <*> usubst els <*> usubst fin usubst (With l is b) = With l <$> usubst is <*> usubst b usubst (VarAssign l ps e) = VarAssign l <$> usubst ps <*> usubst e usubst (After l e e') = After l <$> usubst e <*> usubst e' usubst (Decl l ds) = Decl l <$> usubst ds usubst (Signature l ns tsc d) = Signature l ns <$> usubst tsc <*> return d usubst s = return s instance USubst Expr where usubst (Call l e p k) = Call l <$> usubst e <*> usubst p <*> usubst k usubst (TApp l e ts) = TApp l <$> usubst e <*> usubst ts usubst (Let l ss e) = Let l <$> usubst ss <*> usubst e usubst (Async l e) = Async l <$> usubst e usubst (Await l e) = Await l <$> usubst e usubst (Index l e ix) = Index l <$> usubst e <*> usubst ix usubst (Slice l e sl) = Slice l <$> usubst e <*> usubst sl usubst (Cond l e1 cond e2) = Cond l <$> usubst e1 <*> usubst cond <*> usubst e2 usubst (IsInstance l e c) = IsInstance l <$> usubst e <*> return c usubst (BinOp l e1 op e2) = BinOp l <$> usubst e1 <*> return op <*> usubst e2 usubst (CompOp l e ops) = CompOp l <$> usubst e <*> usubst ops usubst (UnOp l op e) = UnOp l op <$> usubst e usubst (Dot l e n) = Dot l <$> usubst e <*> return n usubst (Rest l e n) = Rest l <$> usubst e <*> return n usubst (DotI l e i) = DotI l <$> usubst e <*> return i usubst (RestI l e i) = RestI l <$> usubst e <*> return i usubst (Lambda l p k e fx) = Lambda l <$> usubst p <*> usubst k <*> usubst e <*> usubst fx usubst (Yield l e) = Yield l <$> usubst e usubst (YieldFrom l e) = YieldFrom l <$> usubst e usubst (Tuple l p k) = Tuple l <$> usubst p <*> usubst k usubst (List l es) = List l <$> usubst es usubst (ListComp l e c) = ListComp l <$> usubst e <*> usubst c usubst (Dict l as) = Dict l <$> usubst as usubst (DictComp l a c) = DictComp l <$> usubst a <*> usubst c usubst (Set l es) = Set l <$> usubst es usubst (SetComp l e c) = SetComp l <$> usubst e <*> usubst c usubst (Paren l e) = Paren l <$> usubst e usubst e = return e instance USubst Pattern where usubst (PWild l t) = PWild l <$> usubst t usubst (PVar l n t) = PVar l n <$> usubst t usubst (PParen l p) = PParen l <$> usubst p usubst (PTuple l p k) = PTuple l <$> usubst p <*> usubst k usubst (PList l ps p) = PList l <$> usubst ps <*> usubst p instance USubst PosPat where usubst (PosPat p pp) = PosPat <$> usubst p <*> usubst pp usubst (PosPatStar p) = PosPatStar <$> usubst p usubst PosPatNil = return PosPatNil instance USubst KwdPat where usubst (KwdPat n p kp) = KwdPat n <$> usubst p <*> usubst kp usubst (KwdPatStar p) = KwdPatStar <$> usubst p usubst KwdPatNil = return KwdPatNil instance USubst Branch where usubst (Branch e b) = Branch <$> usubst e <*> usubst b instance USubst Handler where usubst (Handler ex b) = Handler ex <$> usubst b instance USubst WithItem where usubst (WithItem e p) = WithItem <$> usubst e <*> usubst p instance USubst PosArg where usubst (PosArg e p) = PosArg <$> usubst e <*> usubst p usubst (PosStar e) = PosStar <$> usubst e usubst PosNil = return PosNil instance USubst KwdArg where usubst (KwdArg n e k) = KwdArg n <$> usubst e <*> usubst k usubst (KwdStar e) = KwdStar <$> usubst e usubst KwdNil = return KwdNil instance USubst Assoc where usubst (Assoc k v) = Assoc <$> usubst k <*> usubst v usubst (StarStar e) = StarStar <$> usubst e instance USubst Elem where usubst (Elem e) = Elem <$> usubst e usubst (Star e) = Star <$> usubst e instance USubst Comp where usubst (CompFor l p e c) = CompFor l <$> usubst p <*> usubst e <*> usubst c usubst (CompIf l e c) = CompIf l <$> usubst e <*> usubst c usubst NoComp = return NoComp instance USubst Sliz where usubst (Sliz l e1 e2 e3) = Sliz l <$> usubst e1 <*> usubst e2 <*> usubst e3 instance USubst OpArg where usubst (OpArg op e) = OpArg op <$> usubst e instance USubst NameInfo where usubst (NVar t) = NVar <$> usubst t usubst (NSVar t) = NSVar <$> usubst t usubst (NDef t d doc) = NDef <$> usubst t <*> return d <*> return doc usubst (NSig t d doc) = NSig <$> usubst t <*> return d <*> return doc usubst (NAct q p k te doc) = NAct <$> usubst q <*> usubst p <*> usubst k <*> usubst te <*> return doc usubst (NClass q us te doc) = NClass <$> usubst q <*> usubst us <*> usubst te <*> return doc usubst (NProto q us te doc) = NProto <$> usubst q <*> usubst us <*> usubst te <*> return doc usubst (NExt q c ps te opts doc) = NExt <$> usubst q <*> usubst c <*> usubst ps <*> usubst te <*> return opts <*> return doc usubst (NTVar k c ps) = NTVar k <$> usubst c <*> usubst ps usubst (NAlias qn) = NAlias <$> return qn usubst (NMAlias m) = NMAlias <$> return m usubst (NModule ms te doc) = NModule ms <$> return te <*> return doc -- actually usubst te, but te has no free variables (top-level) usubst NReserved = return NReserved instance USubst Witness where usubst w@WClass{} = return w -- A WClass (i.e., an extension) can't have any free type variables usubst w@WInst{} = do t <- usubst (wtype w) p <- usubst (proto w) return w{ wtype = t, proto = p } instance USubst Env where usubst env = do ne <- usubst (activeNames env) ex <- usubst (envX env) return $ setActiveNames ne env{ envX = ex } instance UFree Env where ufree env = ufree (activeNames env) ++ ufree (envX env) -- Well-formed tycon applications ------------------------------------------------------------------------------------------------- class WellFormed a where wf :: Env -> a -> Constraints instance (WellFormed a) => WellFormed (Maybe a) where wf env = maybe [] (wf env) instance (WellFormed a) => WellFormed [a] where wf env = concatMap (wf env) instance WellFormed TCon where wf env (TC n ts) = wf env ts ++ [ constr (vsubst s u) (vsubst s $ tVar v) | QBind v us <- q, u <- us ] where q = case findQName n env of NAct q p k te _ -> q NClass q us te _ -> q NProto q us te _ -> q NReserved -> nameReserved n i -> err1 n ("wf: Class or protocol name expected, got " ++ show i) s = qbound q `zip` ts constr u t = if isProto env (tcname u) then Proto (noinfo 20) env nWild t u else Cast (noinfo 21) env t (tCon u) wfProto :: Env -> TCon -> TypeM (Constraints, Constraints) wfProto env (TC n ts) = do cs <- instQuals env q ts return (wf env ts, cs) where q = case findQName n env of NProto q us te _ -> q NReserved -> nameReserved n i -> err1 n ("wfProto: Protocol name expected, got " ++ show i) instance WellFormed Type where wf env (TCon _ tc) = wf env tc wf env (TFun _ x p k t) = wf env x ++ wf env p ++ wf env p ++ wf env k ++ wf env t wf env (TTuple _ p k) = wf env p ++ wf env k wf env (TOpt _ t) = wf env t wf env (TRow _ _ _ t r) = wf env t ++ wf env r wf env (TStar _ _ r) = wf env r wf env _ = [] instance WellFormed QBind where wf env (QBind v us) | not $ null ideps = err2 (head ideps) "Interdependent type variable bounds:" | otherwise = wf env us where (_,ps) = mro2 env us ideps = [ [tcname u, root $ head w] | u <- us, (w,p) <- ps, length w > 1, p == u ] root (Left n) = n root (Right n) = n -- Instantiation ------------------------------------------------------------------------------------------------------------------- instantiate :: Env -> TSchema -> TypeM (Constraints, [Type], Type) instantiate env (TSchema _ q t) = do (cs, tvs) <- instQBinds env q let s = qbound q `zip` tvs return (cs, tvs, vsubst s t) instQBinds :: Env -> QBinds -> TypeM (Constraints, [Type]) instQBinds env q = do ts <- newUnivars env [ tvkind v | QBind v _ <- q ] cs <- instQuals env q ts return (cs, ts) instWitness :: Env -> PCon -> Witness -> TypeM (Constraints,Type,Expr) instWitness env p0 wit = case wit of WClass q t p w ws opts -> do (cs,tvs) <- instQBinds env q let s = (tvSelf,t) : qbound q `zip` tvs unifyM (locinfo p0 22) (tcargs p0) (tcargs $ vsubst s p) t <- usubst (vsubst s t) cs <- usubst cs return (cs, t, wexpr ws (eCall (tApp (eQVar w) tvs) (wvars cs ++ replicate opts eNone))) WInst q t p w ws -> do (cs,tvs) <- instQBinds env q let s = (tvSelf,t) : qbound q `zip` tvs unifyM (locinfo p0 23) (tcargs p0) (tcargs $ vsubst s p) t <- usubst (vsubst s t) return (cs, t, wexpr ws (eQVar w)) instQuals :: Env -> QBinds -> [Type] -> TypeM Constraints instQuals env q ts = do let s = qbound q `zip` ts sequence [ constr (vsubst s (tVar v)) (vsubst s u) | QBind v us <- q, u <- us ] where constr t u@(TC n _) | isProto env n = do w <- newWitness; return $ Proto (noinfo 24) env w t u | otherwise = return $ Cast (noinfo 25) env t (tCon u) wvars :: Constraints -> [Expr] wvars cs = [ eVar v | Proto _ _ v _ _ <- cs ] -- Equations ----------------------------------------------------------------------------------------------------------------------- data Equation = Eqn Int Name Type Expr type Equations = [Equation] mkEqn env = Eqn (qlevel env) instance Pretty Equations where pretty eqs = vcat $ map pretty eqs instance Pretty Equation where pretty (Eqn i n t e) = pretty n <+> colon <+> pretty t <+> equals <+> pretty e <+> text ("# level " ++ show i) instance USubst Equation where usubst (Eqn i w t e) = Eqn i w <$> usubst t <*> usubst e instance UFree Equation where ufree (Eqn i w t e) = ufree t ++ ufree e instance Vars Equation where free (Eqn i w t e) = free e bound (Eqn i w t e) = [w] bindWits eqs | null sigws = binds | otherwise = Signature NoLoc sigws (monotype tWild) NoDec : binds where sigws = [ w | Eqn _ w _ (NotImplemented _) <- eqs ] binds = [ sAssign (pVar w t) e | Eqn _ w t e <- eqs, w `notElem` sigws ] scopedWits env0 q cs = scoped cs where level1 = qlevel env0 + length q scoped (Sub _ env w _ _ : cs) | qlevel env == level1 = w : scoped cs | qlevel env < level1 = trace ("### Bad constraint level for " ++ prstr w) $ scoped cs scoped (Proto _ env w _ _ : cs) | qlevel env == level1 = w : scoped cs | qlevel env < level1 = trace ("### Bad constraint level for " ++ prstr w) $ scoped cs scoped (Sel _ env w _ _ _ : cs) | qlevel env == level1 = w : scoped cs | qlevel env < level1 = trace ("### Bad constraint level for " ++ prstr w) $ scoped cs scoped (_ : cs) = scoped cs scoped [] = [] findeqns [] eqns = [] findeqns ws eqns = findeqns ws' eqns ++ match where match = [ eq | eq@(Eqn _ w t e) <- eqns, w `elem` ws ] ws' = filter isWitness $ free match spliteqns eqns = partition isTop eqns where isTop (Eqn 0 _ _ _) = True isTop _ = False -- Misc. --------------------------------------------------------------------------------------------------------------------------- proto2type t (TC n ts) = tCon $ TC n (t:ts) wit2row ws = \p -> foldr f p ws where f (w,t) = TRow NoLoc PRow nWild t wit2arg ws = \p -> foldr f p ws where f (w,t) = PosArg (eVar w) wit2par ws = \p -> foldr f p ws where f (w,t) = PosPar w (Just t) Nothing var2arg xs = \p -> foldr f p xs where f x = PosArg (eVar x) exp2arg es = \p -> foldr PosArg p es protoWitsOf cs = [ eVar w | Proto _ _ w t p <- cs ] qualWPar env q = wit2par (qualWits env q) qualWRow env q = wit2row (qualWits env q) qualWits env q = [ (tvarWit tv p, proto2type (tVar tv) p) | QBind tv ps <- q, p <- ps, isProto env (tcname p) ] witSubst env q cs = [ mkEqn env w0 t (eVar w) | ((w,t),w0) <- ws `zip` ws0 ] where ws = [ (w, proto2type t p) | Proto _ _ w t p <- cs ] ws0 = [ tvarWit tv p | QBind tv ps <- q, p <- ps, isProto env (tcname p) ] -- Type errors --------------------------------------------------------------------------------------------------------------------- data TypeError = TypeError SrcLoc String | RigidVariable TVar | InfiniteType TUni Type | ConflictingRow TUni | KwdNotFound ErrInfo Name | KwdUnexpected ErrInfo Name | PosElemNotFound ErrInfo String | IncompatError ErrInfo String | EscapingVar [TVar] TSchema | NoSelStatic Name TCon | NoSelInstByClass Name TCon | NoMut Name | LackSig Name | LackDef Name | SurplusRow PosRow | NoRed Constraint | NoSolve (Maybe Type) [Type] [Constraint] | NoUnify ErrInfo Type Type | UninitializedAttribute SrcLoc Name Bool SrcLoc SrcLoc Name (Maybe (Name, SrcLoc)) -- attr loc, attr name, is inferred, init loc, class loc, class name, parent class info deriving (Show) data ErrInfo = DfltInfo {errloc :: SrcLoc, errno :: Int, errexpr :: Maybe Expr, errinsts :: [(QName,TSchema,Type)]} | DeclInfo {errloc :: SrcLoc, errloc2 :: SrcLoc, errname :: Name, errschema :: TSchema, errmsg :: String} | Simple {errloc ::SrcLoc, errmsg :: String} deriving (Show) noinfo n = DfltInfo NoLoc n Nothing [] locinfo x n = DfltInfo (loc x) n Nothing [] locinfo' x n e = DfltInfo (loc x) n (Just e) [] locinfo2 n e = DfltInfo (loc e) n (Just e) [] instance Control.Exception.Exception TypeError instance HasLoc TypeError where loc (TypeError l str) = l loc (RigidVariable tv) = loc tv loc (InfiniteType tv t) = loc t loc (ConflictingRow tv) = loc tv loc (KwdNotFound _ n) = loc n loc (KwdUnexpected _ n) = loc n loc (PosElemNotFound info s) = loc info -- NoLoc -- TODO: supply position loc (EscapingVar tvs t) = loc tvs loc (NoSelStatic n u) = loc n loc (NoSelInstByClass n u) = loc n loc (NoMut n) = loc n loc (LackSig n) = loc n loc (LackDef n) = loc n loc (SurplusRow p) = NoLoc -- TODO: supply position loc (NoRed c) = loc c loc (NoSolve _ _ _) = NoLoc loc (NoUnify info t1 t2) = loc info loc (UninitializedAttribute l _ _ _ _ _ _) = l instance HasLoc ErrInfo where loc (Simple l _) = l loc (DfltInfo l _ _ _) = l loc (DeclInfo l _ _ _ _) = l instance UFree ErrInfo where ufree (DfltInfo l n mbe ts) = ufree mbe ++ ufree ts ufree (DeclInfo l1 l2 n t msg) = ufree t ufree _ = [] instance UWild ErrInfo where uwild (DfltInfo l n mbe ts) = DfltInfo l n mbe (uwild ts) uwild (DeclInfo l1 l2 n t msg) = DeclInfo l1 l2 n (uwild t) msg uwild info = info intro t mbe = case mbe of Nothing -> pretty t Just e -> text "The type of the indicated expression" <+> text "(" Pretty.<> (if isGen t then text "which we call" else text "inferred to be") <+> pretty t Pretty.<> text ")" where isGen (TCon _ (TC (NoQ (Name _ ('t' : ds))) [])) = all isDigit ds isGen _ = False explainRequirement c = case info c of Simple l s -> text s DfltInfo l n mbe ts -> (if ts /= [] then text (concatMap (\(n,s,t) -> Pretty.print n ++ " has had its polymorphic type " ++ Pretty.print s ++ " instantiated to " ++ Pretty.print t) ts++", so ") else empty) Pretty.<> (case c of Cast _ _ t1 t2 -> intro t1 mbe <+> text "must be a subclass of" <+> pretty t2 Sub i _ _ t1 t2 -> intro t1 mbe <+> text "must be a subtype of" <+> pretty t2 Proto _ _ _ t p -> intro t mbe <+> text "must implement" <+> pretty p Sel _ _ _ t n t0 -> intro t mbe <+> text "must have an attribute" <+> pretty n <+> text "with type" <+> pretty t0 Pretty.<> text "; no such type is known." _ -> pretty c <+> text "must hold") DeclInfo _ _ n sc msg -> text msg -- $+$ pretty n <+> text "is inferred to have type"<+> pretty sc useless vs c = case c of Cast _ _ t1 t2 -> f t1 || f t2 Sub _ _ _ t1 t2 -> f t1 || f t2 Proto _ _ _ t p -> f t Sel _ _ _ t n t0 -> f t || f t0 Mut _ _ t1 n t2 -> True -- TODO Seal _ _ _ -> True -- TODO where f (TUni _ v) = notElem v vs f _ = False --typeReport :: TypeError -> Report typeReport (TypeError l msg) filename src = Err Nothing msg [(locToPosition l filename src, This msg)] [] typeReport (RigidVariable tv) filename src = Err Nothing msg [(locToPosition (loc tv) filename src, This msg)] [] where msg = render (text "Type" <+> pretty tv <+> text "is rigid") typeReport (InfiniteType tv t) filename src = Err Nothing msg [(locToPosition (loc t) filename src, This msg)] [] where msg = render (text "Type" <+> pretty tv <+> text "~" <+> pretty t <+> text "is infinite") typeReport (ConflictingRow tv) filename src = Err Nothing msg [(locToPosition (loc tv) filename src, This msg)] [] where msg = render (text "Type" <+> pretty tv <+> text "has conflicting extensions") typeReport (KwdNotFound info n) filename src = Err Nothing "Keyword argument missing" [(locToPosition (loc n) filename src, This msg)] [] where msg = render (text "Keyword element" <+> quotes (pretty n) <+> text "is not found") typeReport (KwdUnexpected info n) filename src = Err Nothing "Unexpected keyword argument" [(locToPosition (loc n) filename src, This msg)] [] where msg = render (text "Unexpected keyword argument" <+> quotes (pretty n)) typeReport (PosElemNotFound info s) filename src = Err Nothing s [(locToPosition (loc info) filename src, This s)] [] typeReport (EscapingVar tvs t) filename src = Err Nothing msg [(locToPosition (loc tvs) filename src, This msg)] [] where msg = render (text "Type annotation" <+> pretty t <+> text "is too general, type variable" <+> pretty (head tvs) <+> text "escapes") typeReport (NoSelStatic n u) filename src = Err Nothing msg [(locToPosition (loc n) filename src, This msg)] [] where msg = render (text "Static method" <+> pretty n <+> text "cannot be selected from" <+> pretty u <+> text "instance") typeReport (NoSelInstByClass n u) filename src = Err Nothing msg [(locToPosition (loc n) filename src, This msg)] [] where msg = render (text "Instance attribute" <+> pretty n <+> text "cannot be selected from class" <+> pretty u) typeReport (NoMut n) filename src = Err Nothing msg [(locToPosition (loc n) filename src, This msg)] [] where msg = render (text "Non @property attribute" <+> pretty n <+> text "cannot be mutated") typeReport (LackSig n) filename src = Err Nothing msg [(locToPosition (loc n) filename src, This msg)] [] where msg = render (text "Declaration lacks accompanying signature") typeReport (LackDef n) filename src = Err Nothing msg [(locToPosition (loc n) filename src, This msg)] [] where msg = render (text "Signature lacks accompanying definition") typeReport (NoRed c) filename src | DeclInfo l1 l2 n _ _ <- info c = Err Nothing "Constraint violation" [ (locToPosition l1 filename src, This (render (explainRequirement c <+> parens (explainRequirement c{info = dummyInfo})))) , (locToPosition l2 filename src, Where (Pretty.print n ++ " is defined here")) ] [] | otherwise = Err Nothing "Constraint violation" [(locToPosition (loc c) filename src, This (render (explainRequirement c)))] [] typeReport (NoSolve mbt vs cs) filename src = let header = case length cs of 0 -> "Unable to give good error message: please report example" 1 -> "Cannot satisfy the following constraint:" _ -> "Cannot satisfy the following simultaneous constraints for the unknown " ++ (if length vs == 1 then "type " ++ case head vs of TCon _ tc -> nameStr (noq (tcname tc)) _ -> show (head vs) else "types") -- Each constraint gets its own complete error message with source line constraint_messages = concatMap (typeError . NoRed) cs -- Filter out empty positions and merge their messages into the first real position (noLocs, withLocs) = partition ((==NoLoc) . fst) constraint_messages withLocsMsgs = case (withLocs, noLocs) of ([], []) -> [(NoLoc, "Error: No location information")] ([], (l,m):_) -> [(l,m)] ((l,m):rest, extras) -> (l, m ++ "\n" ++ concatMap snd extras) : rest in Err Nothing header [(locToPosition l filename src, This m) | (l,m) <- withLocsMsgs] [] where nameStr (Name _ str) = str typeReport (NoUnify (Simple l msg) _ _) filename src = Err Nothing "Type unification error" [(locToPosition l filename src, This msg)] [] typeReport (NoUnify info t1 t2) filename src = case (loc t1, loc t2) of (l1@Loc{}, l2@Loc{}) -> Err Nothing "Type unification error" [ (locToPosition l1 filename src, This "First type appears here") , (locToPosition l2 filename src, This "Second type appears here") ] [] _ -> Err Nothing "Type unification error" [(locToPosition (getLoc[loc info, loc t1, loc t2]) filename src, This msg)] [] where msg = render (text "Incompatible types" <+> pretty t1 <+> text "and" <+> pretty t2) typeReport (IncompatError info msg) filename src = case info of DeclInfo l1 l2 n sc msg1 -> Err Nothing "Incompatible types" [ (locToPosition l1 filename src, This msg) , (locToPosition l2 filename src, Where (Pretty.print n ++ " is defined here")) ] [] _ -> Err Nothing "Incompatible types" [(locToPosition (loc info) filename src, This msg)] [] typeReport (SurplusRow p) filename src = Err Nothing "Too many arguments supplied" [(locToPosition NoLoc filename src, This (prstr (label p)))] [] typeReport (UninitializedAttribute attrLoc attrName isInferred initLoc classLoc className parentInfo) filename src = Err (Just "Type error") msg ([ (locToPosition initLoc filename src, This $ "Attribute '" ++ prstr attrName ++ "' is not initialized in __init__") , (locToPosition (makeLineOnlyLoc classLoc src) filename src, Where $ "In class " ++ prstr className) ] ++ (case parentInfo of Just (parentName, parentLoc) -> [(locToPosition (makeLineOnlyLoc parentLoc src) filename src, Where $ "Attribute inherited from " ++ prstr parentName)] Nothing -> []) ++ [ (locToPosition attrLoc filename src, Where $ "Attribute '" ++ prstr attrName ++ "' " ++ if isInferred then "inferred from use" else "is defined here") ]) [] where msg = "Attribute '" ++ prstr attrName ++ "' is not initialized in " ++ prstr className ++ ".__init__" typeError :: TypeError -> [(SrcLoc, String)] typeError (TypeError l str) = [(l, str)] typeError (RigidVariable tv) = [(loc tv, render (text "Type" <+> pretty tv <+> text "is rigid"))] typeError (InfiniteType tv t) = [(loc tv, render (text "Type" <+> pretty tv <+> text "~" <+> pretty t <+> text "is infinite"))] typeError (ConflictingRow tv) = [(loc tv, render (text "Type" <+> pretty tv <+> text "has conflicting extensions"))] typeError (KwdNotFound _ n) = [(loc n, render (text "Keyword element" <+> quotes (pretty n) <+> text "is not found"))] typeError (KwdUnexpected _ n) = [(loc n, render (text "Keyword element" <+> quotes (pretty n) <+> text "is not expected"))] typeError (PosElemNotFound info s) = [(loc info, s)] typeError (EscapingVar tvs t) = [(loc tvs, render (text "Type annotation" <+> pretty t <+> text "is too general, type variable" <+> pretty (head tvs) <+> text "escapes"))] typeError (NoSelStatic n u) = [(loc n, render (text "Static method" <+> pretty n <+> text "cannot be selected from" <+> pretty u <+> text "instance"))] typeError (NoSelInstByClass n u) = [(loc n, render (text "Instance attribute" <+> pretty n <+> text "cannot be selected from class" <+> pretty u))] typeError (NoMut n) = [(loc n, render (text "Non @property attribute" <+> pretty n <+> text "cannot be mutated"))] typeError (LackSig n) = [(loc n, render (text "Declaration lacks accompanying signature"))] typeError (LackDef n) = [(loc n, render (text "Signature lacks accompanying definition"))] typeError (UninitializedAttribute attrLoc attrName isInferred initLoc classLoc className parentInfo) = [(initLoc, "attribute '" ++ prstr attrName ++ "' is not initialized in __init__ of " ++ prstr className)] typeError (NoRed c) | DeclInfo l1 l2 _ _ _ <- info c = [(min l1 l2,""), (max l1 l2,render (explainRequirement c <+> parens (explainRequirement c{info = dummyInfo})))] -- | DfltInfo l n mbe is <- info c = [(loc c, render (explainRequirement c <+> parens (text ("errcode " ++ show n))))] | otherwise = [(loc c, render (explainRequirement c))] typeError (NoSolve mbt vs cs) = case length cs of 0 -> [(NoLoc, "Unable to give good error message: please report example")] 1 -> (NoLoc, "Cannot satisfy the following constraint:\n") : concatMap mkReq cs _ -> (NoLoc, "Cannot satisfy the following simultaneous constraints for the unknown " ++ (if length vs==1 then "type " else "types ") ++ render(commaList vs) ++":\n") : concatMap mkReq cs where mkReq = typeError . NoRed typeError (NoUnify info t1 t2) = case (loc t1, loc t2) of (l1@Loc{},l2@Loc{}) -> [(l1, ""),(l2,render(text "Incompatible types" <+> pretty t1 <+> text "and" <+> pretty t2))] _ -> [(getLoc[loc info, loc t1, loc t2],render(text "Incompatible types" <+> pretty t1 <+> text "and" <+> pretty t2))] typeError (IncompatError info msg) = case info of DeclInfo l1 l2 f sc _ -> [(min l1 l2,""),(max l1 l2,msg)] _ -> [(loc info, msg)] -- Error throwing functions: tyerr x s = throwError $ TypeError (loc x) (s ++ " " ++ prstr x) tyerrs xs s = throwError $ TypeError (loc $ head xs) (s ++ " " ++ prstrs xs) rigidVariable tv = throwError $ RigidVariable tv infiniteType tv t = throwError $ InfiniteType tv t conflictingRow tv = throwError $ ConflictingRow tv kwdNotFound info n = throwError $ incompatError info (render(text ("keyword " ++ elemSpec info) <+> quotes (pretty n) <+> text ("is missing" ++ elemSuffix info))) kwdUnexpected info n = throwError $ KwdUnexpected info n escapingVar tvs t = throwError $ EscapingVar tvs t noSelStatic n u = throwError $ NoSelStatic n u noSelInstByClass n u = throwError $ NoSelInstByClass n u noMut n = throwError $ NoMut n lackSig ns = throwError $ LackSig (head ns) lackDef ns = throwError $ LackDef (head ns) surplusRow p = throwError $ SurplusRow p noRed c = throwError $ NoRed c noSolve mbt vs cs = throwError $ NoSolve mbt vs cs noUnify info t1 t2 = throwError $ NoUnify info t1 t2 posElemNotFound b c n = throwError $ incompatError (info c) ("too " ++ (if b then "few " else "many positional ") ++ elemSpec (info c) ++ elemSuffix (info c)) incompatError info msg = case info of DeclInfo l1 l2 f sc msg1 -> IncompatError info (msg ++ Pretty.print f) _ -> IncompatError info msg elemSpec DeclInfo{} = "argument(s)" elemSpec _ = "component(s)" elemSuffix DeclInfo{} = " in call to " elemSuffix _ = " in tuple" -- elemHint DeclInfo{} = " Hint: The previous definition may have been implicit, using positional notation." -- elemHint _ = "" dummyInfo = noinfo 0 --mkErrorDiagnostic :: String -> String -> Report String -> Diagnostic String mkErrorDiagnostic filename src report = let diag = addFile mempty filename src in addReport (addFile diag filename src) report -- | Convert internal locations to Diagnose positions locToPosition :: SrcLoc -> String -> String -> Position locToPosition NoLoc _ _ = Position (0,0) (0,0) "" -- Empty position locToPosition (Loc start end) filename src = -- Convert byte offsets to line/col positions by counting in source let startPos = offsetToLineCol start src (endLine, endCol) = offsetToLineCol end src -- For multi-line spans, adjust end line to match original error format finalEndPos = if endLine > fst startPos then (endLine - 1, endCol) else (endLine, endCol) in Position startPos finalEndPos filename -- | Helper to convert byte offset to line/col tuple offsetToLineCol :: Int -> String -> (Int, Int) offsetToLineCol offset src = let beforeOffset = take offset src lines = splitLines beforeOffset lineNum = length lines colNum = if null lines then 1 else (length (last lines) + 1) in (lineNum, colNum) where splitLines [] = [""] splitLines s = let (first, rest) = break (=='\n') s in first : case rest of [] -> [] (_:rest') -> splitLines rest' -- | Make a location that only spans the first line -- Many of our locations, like for a class definition, span all the lines of the -- definition. For printing error messages it's commonly more useful to just -- point to where the definition starts rather than highlighting the whole. makeLineOnlyLoc :: SrcLoc -> String -> SrcLoc makeLineOnlyLoc NoLoc _ = NoLoc makeLineOnlyLoc (Loc start _) src = let endOfLine = findEndOfLine start src in Loc start endOfLine where findEndOfLine pos s = let remaining = drop pos s lineEnd = takeWhile (/= '\n') remaining in pos + length lineEnd ================================================ FILE: compiler/lib/src/Acton/Types.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} module Acton.Types(reconstruct, showTyFile, prettySigs, TypeError(..), TypeErrors(..), TypeProgressCallback, TypeInferredCallback) where import Control.Concurrent.Async import Control.Concurrent.Chan import Control.Concurrent.MVar import Control.Concurrent.QSem import Control.DeepSeq import Control.Monad import Control.Monad.Except (runExceptT) import Control.Monad.State.Strict (runState) import Data.Maybe (isJust) import Data.List (nub, intersect, sort) import Pretty import qualified Control.Exception import Debug.Trace import Utils import Acton.Syntax import Acton.Names import Acton.Builtin import Acton.Prim import Acton.NameInfo import Acton.Env import Acton.Solver import Acton.Subst import Acton.Transform import Acton.Converter import Acton.TypeEnv import Acton.WitKnots import qualified InterfaceFiles import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Base16 as Base16 import Data.List (foldl', intersperse, isPrefixOf, partition) import Data.Maybe (mapMaybe) import GHC.Conc (getNumCapabilities) type TypeProgressCallback = Int -> Int -> Maybe String -> [String] -> Int -> IO () type TypeInferredCallback = [String] -> String -> IO () emitTypeProgressIO :: Maybe TypeProgressCallback -> Int -> Int -> Maybe String -> [String] -> Int -> IO () emitTypeProgressIO Nothing _ _ _ _ _ = return () emitTypeProgressIO (Just cb) total completed current names weight = cb total completed current names weight emitTypeInferredIO :: Maybe TypeInferredCallback -> Env -> TEnv -> IO () emitTypeInferredIO Nothing _ _ = return () emitTypeInferredIO (Just cb) env te = cb (map nstr (dom te)) (render $ pretty (simp env [(n, stripDocsNI i) | (n,i) <- te])) data TypeErrors = TypeErrors [TypeError] deriving (Show) instance Control.Exception.Exception TypeErrors -- | Type-check a module and return its NameInfo, typed module, env, and discovered tests. reconstruct :: Maybe TypeProgressCallback -> Maybe TypeInferredCallback -> Env0 -> Module -> IO (NameInfo, Module, Env0, [String]) reconstruct progressCb inferredCb env0 (Module m i mdoc ss) = do --traceM ("#################### original env0 for " ++ prstr m ++ ":") --traceM (render (pretty env0)) (te,ss1) <- infTop progressCb inferredCb env1 ss let env2 = defineClosed te (setMod m env0) (teT,ssT,tests) = if hasTesting i then let (testSs, discovered) = testStmts env2 (modNameStr m) ss1 in (te ++ testEnv, ss1 ++ testSs, discovered) else (te, ss1, []) iface = unalias env2 teT nmod = NModule (getImports env2) iface mdoc --traceM ("#################### converted env0:") --traceM (render (pretty env0')) return (nmod, Module m i mdoc ssT, env0', tests) where env1 = reserveClosed (assigned ss) (initTypeEnv env0) env0' = convEnvProtos env0 hasTesting i = Import NoLoc [ModuleItem (ModName [name "testing"]) Nothing] `elem` i rmTests (Assign _ [PVar _ n _] _ : ss) | nstr n `elem` ["__unit_tests","__simple_sync_tests","__sync_tests","__async_tests","__env_tests"] = rmTests ss rmTests (Decl _ [Actor _ n _ _ _ _ _] : ss) | nstr n == "test_main" = rmTests ss rmTests (s : ss) = s : rmTests ss rmTests [] = [] -- Convert the module name (ModName) to a string, e.g. "foo.bar" modNameStr (ModName ns) = concat (intersperse "." (map nstr ns)) -- | Print a .ty file header and interface; include name hashes when verbose. showTyFile env0 m fname verbose = do (_,nmod,_,sourceMeta,srcH,pubH,implH,imps,nameHashes,roots,tests,mdocH) <- InterfaceFiles.readFile fname putStrLn ("\n############### Header ###############") putStrLn ("Imports: " ++ (show [ (prstr mn, take 16 (B.unpack $ Base16.encode h)) | (mn,h) <- imps ])) putStrLn ("Roots : " ++ (show (map prstr roots))) putStrLn ("Tests : " ++ (show tests)) case mdocH of Just ds -> putStrLn ("Doc : \"\"\"" ++ ds ++ "\"\"\"") Nothing -> return () putStrLn ("ModuleSrcBytesHash: 0x" ++ (B.unpack $ Base16.encode srcH)) putStrLn ("ModulePubHash : 0x" ++ (B.unpack $ Base16.encode pubH)) putStrLn ("ModuleImplHash : 0x" ++ (B.unpack $ Base16.encode implH)) when verbose $ do putStrLn ("\n############### Source Meta ############") case sourceMeta of Nothing -> putStrLn "None" Just meta -> do putStrLn ("mtimeNs: " ++ show (InterfaceFiles.sfmMTimeNs meta)) putStrLn ("ctimeNs: " ++ show (InterfaceFiles.sfmCTimeNs meta)) putStrLn ("size : " ++ show (InterfaceFiles.sfmSize meta)) putStrLn ("device : " ++ maybe "-" show (InterfaceFiles.sfmDevice meta)) putStrLn ("inode : " ++ maybe "-" show (InterfaceFiles.sfmInode meta)) putStrLn ("\n############### Name Hashes ############") forM_ nameHashes $ \nh -> do let formatHash h = if B.null h then "" else "0x" ++ B.unpack (Base16.encode h) srcHex = formatHash (InterfaceFiles.nhSrcHash nh) pubHex = formatHash (InterfaceFiles.nhPubHash nh) implHex = formatHash (InterfaceFiles.nhImplHash nh) showDep (qn,h) = (prstr qn, take 16 (B.unpack $ Base16.encode h)) putStrLn ("Name : " ++ prstr (InterfaceFiles.nhName nh)) putStrLn (" src : " ++ srcHex) putStrLn (" pub : " ++ pubHex) putStrLn (" impl : " ++ implHex) when (not (null (InterfaceFiles.nhPubDeps nh))) $ putStrLn (" pubDeps : " ++ show (map showDep (InterfaceFiles.nhPubDeps nh))) when (not (null (InterfaceFiles.nhImplDeps nh))) $ putStrLn (" implDeps: " ++ show (map showDep (InterfaceFiles.nhImplDeps nh))) putStrLn ("\n############### Interface ############") let NModule imps te mdoc = nmod forM_ mdoc $ \docstring -> putStrLn $ "\"\"\"" ++ docstring ++ "\"\"\"" putStrLn $ prettySigs env0 m imps te prettySigs env m imps te = render $ vcat [ text "import" <+> pretty m | m <- imps ] $++$ vpretty (simp env1 te) where env1 = defineClosed te $ setMod m env nodup x | not $ null vs = err2 vs "Duplicate names:" | otherwise = True where vs = duplicates (bound x) addTyping env n s t c = c {info = addT n (simp env s) t (info c){errloc = loc n}} where addT n s t (DfltInfo l m mbe ts) = DfltInfo l m mbe ((n,s,t):ts) addT _ _ _ info = info ------------------------------ -- | One source-level progress unit: the names in the top-level statement and -- its weight. A recursive group can bind several names, so the weight is kept -- separate from the label. type TopProgressItem = ([String], Int) -- | Progress events are sent from the scanner thread and from background -- checker workers to the single progress reporter thread. data TopProgressEvent = TopProgressStarted TopProgressItem | TopProgressFinished TopProgressItem | TopProgressStop -- Concurrent type checker infTop :: Maybe TypeProgressCallback -> Maybe TypeInferredCallback -> Env -> Suite -> IO (TEnv,Suite) infTop _ _ _ [] = return ([], []) infTop progressCb inferredCb env ss = do -- The scanner itself is sequential, but total statements, i.e. -- with a complete type signature can be independently type checked -- by a fixed worker queue in the background. ncap <- getNumCapabilities -- nworkers is the active checkTopStmt parallelism. window is bounded -- scanner lookahead, so generated modules cannot allocate one queued -- result and closure per total top-level statement. let nworkers = max 1 (min ncap (length ss)) window = max 1 (min (10 * nworkers) (length ss)) -- slots is acquired before enqueueing and released by the worker -- after that queued total statement has finished checking. slots <- newQSem window workQ <- newChan -- Progress reporting is serialized through one channel so concurrent -- workers do not call the UI callback directly. progressQ <- newChan workers <- replicateM nworkers (async $ worker slots workQ progressQ) -- The progress reporter is independent from scanning/checking; it -- consumes start/finish events until it receives TopProgressStop. progressA <- async $ topProgress progressCb total progressQ -- Stop the reporter after all work has been collected, and wait so -- the final progress update is emitted before infTop returns. let stopProgress = writeChan progressQ TopProgressStop >> wait progressA -- Workers exit on Nothing, written only after collect has consumed -- all real jobs. stopWorkers = replicateM_ nworkers (writeChan workQ Nothing) >> mapM_ wait workers -- run is the real top-level flow: scan left-to-right, collect -- all completed worker results, then validate signatures once -- the whole top-level environment is known. run = do (te,ss,errs) <- go slots workQ progressQ env [] [] ss stopWorkers stopProgress if null errs then do runType "" (checkSigs env te) return (te, ss) else throwTopErrors errs -- If scan/check throws before stopProgress runs, make sure the -- background threads do not stay blocked on readChan. run `Control.Exception.finally` (mapM_ cancel workers >> cancel progressA) where -- Total source progress is known syntactically before any type checking. total = sum (map stmtProgressWeight ss) -- Each worker runs total statements from workQ. Nothing is the stop -- marker; Just jobs must always publish their result MVar and release -- their scanner slot before the worker moves on. worker slots workQ progressQ = do job <- readChan workQ case job of Nothing -> return () Just (env,te,s,item,result) -> do writeChan progressQ (TopProgressStarted item) Control.Exception.finally (runWorker env te s result) (writeChan progressQ (TopProgressFinished item) >> signalQSem slots) worker slots workQ progressQ -- End of input: every statement has either produced an immediate -- result or a worker wait action, so now wait for them and assemble the -- final top-level environment and typed suite in source order. go slots workQ q env tes rs [] = collect tes rs -- Main scanner loop. This is deliberately sequential: every new scan -- sees a type environment containing all previous top-level declarations. go slots workQ q env tes rs (s:ss) = do let item = topProgressItem s -- scanOrCheck always scans in this thread. If the statement is not -- total, scanOrCheck also runs checkTopStmt here and blocks progress. r <- scanOrCheck env s item q case r of -- A scan error stops the source-order scan. -- Existing worker results are still collected so their errors can -- be reported together with this one. Left err -> collect tes (return (Left err) : rs) -- A total statement has a complete boundary after scanning. Its -- declarations can be put in env immediately, while full checking -- continues in the background. Right (True,te1,s1,_) -> do -- Acquire a queue slot before enqueueing so scanner lookahead -- is bounded, then let a fixed worker run checkTopStmt. waitQSem slots result <- newEmptyMVar writeChan workQ (Just (env,te1,s1,item,result)) -- Continue scanning with the scanned declarations visible. -- Store te1 and result wait on reversed accumulators to preserve -- source order cheaply when collect reverses them. go slots workQ q (tydefineClosed te1 env) (te1:tes) (readMVar result:rs) ss -- A non-total statement was already fully checked by scanOrCheck, -- so becomes complete / total before we get here and the scanner may -- continue. Right (_,te2,_,ss1) -> go slots workQ q (tydefineClosed te2 env) (te2:tes) (return (Right ss1):rs) ss -- Wait for all statement results in source order, concatenate the -- accumulated environments, keep typed statements whose checks -- succeeded, and keep every error for aggregate reporting. collect tes rs = do xs <- sequence (reverse rs) return (concat (reverse tes), [ s | Right ss1 <- xs, s <- ss1 ], [ e | Left e <- xs ]) -- Scanner/checker front door for one statement. Ordinary exceptions -- become Left values so infTop can collect multiple errors; async -- exceptions still escape through tryTop. scanOrCheck env s item q = tryTop $ do let p = nstr $ uniqPrefix s ((total,te1,s1),st) <- runTypeFromState p (initTypeState p) $ do pushFX fxPure tNone -- The scanner returns the syntactic totality bit, the scanned -- top-level env, and the rewritten statement. scanTopStmt env s if total -- Total means the signature boundary is complete, so the -- expensive check can be deferred to a worker. then do te1 <- Control.Exception.evaluate (force te1) return (True,te1,s1,[]) -- Non-total means inference/checking is needed now. This blocks -- the scanner because later statements need this completed env. else do writeChan q (TopProgressStarted item) Control.Exception.finally (do ((te2,ss1),_) <- runTypeFromState p st (checkTopStmt env te1 s1) (te2,ss1) <- forceChecked te2 ss1 emitTypeInferredIO inferredCb env te2 return (False,te2,s1,ss1)) (writeChan q (TopProgressFinished item)) -- Background worker body for a total statement. It receives exactly -- the scanned env and scanned statement returned by scanTopStmt. checkTotal env te s = tryTop $ do (te1,ss1) <- runType (nstr $ uniqPrefix s) $ do pushFX fxPure tNone checkTopStmt env te s forceSuite te1 ss1 -- Once a worker has taken a job, collect may wait on result. Mask the -- publish step so every claimed job fills the MVar; async exceptions are -- rethrown afterwards so cancellation still propagates normally. runWorker env te s result = Control.Exception.mask $ \restore -> do r <- Control.Exception.try (restore (checkTotal env te s)) case r of Left err -> do putMVar result (Left err) when (isAsyncException err) (Control.Exception.throwIO err) Right x -> putMVar result x -- Run a TypeM action and convert TypeM's Either error into the IO -- exception path used by tryTop. runType p m = do r <- Control.Exception.evaluate (runTypeMState p m) case r of Left err -> Control.Exception.throwIO err Right (x,_) -> return x runTypeFromState p st m = do r <- Control.Exception.evaluate (runState (runExceptT m) st) case r of (Left err, _) -> Control.Exception.throwIO err (Right x, st') -> return (x, st') -- checkTotal returns only the typed statements, but still forces the -- worker's type environment so any delayed failures surface in worker. forceSuite te ss = snd <$> forceChecked te ss forceChecked te ss = do te <- Control.Exception.evaluate (force te) ss <- Control.Exception.evaluate (force ss) return (te,ss) topProgress :: Maybe TypeProgressCallback -> Int -> Chan TopProgressEvent -> IO () topProgress progressCb total q = do when (total > 0) $ emit [] 0 loop [] 0 where loop active done = do event <- readChan q case event of TopProgressStarted item -> do let active' = active ++ [item] emit active' done loop active' done TopProgressFinished item -> do let active' = removeProgressItem item active done' = done + snd item emit active' done' loop active' done' TopProgressStop -> emit [] done emit active done = emitTypeProgressIO progressCb total done (activeProgressLabel active) (concatMap fst active) 0 topProgressItem :: Stmt -> TopProgressItem topProgressItem s = (stmtProgressNames s, stmtProgressWeight s) removeProgressItem :: TopProgressItem -> [TopProgressItem] -> [TopProgressItem] removeProgressItem item [] = [] removeProgressItem item (x:xs) | item == x = xs | otherwise = x : removeProgressItem item xs activeProgressLabel :: [TopProgressItem] -> Maybe String activeProgressLabel [] = Nothing activeProgressLabel active = Just (formatActive active) where formatActive active = show nstmt ++ " " ++ plural "stmt" nstmt ++ ", " ++ show nnames ++ " " ++ plural "name" nnames ++ ": " ++ formatNames names where nstmt = length active names = concatMap fst active nnames = length names plural s n = s ++ if n == 1 then "" else "s" formatNames [n] = n formatNames [n1,n2] = n1 ++ ", " ++ n2 formatNames (n1:n2:rest) = n1 ++ ", " ++ n2 ++ " (+" ++ show (length rest) ++ " others)" formatNames [] = "" tryTop :: IO a -> IO (Either Control.Exception.SomeException a) tryTop m = do r <- Control.Exception.try m case r of Left err | isAsyncException err -> Control.Exception.throwIO err _ -> return r isAsyncException :: Control.Exception.SomeException -> Bool isAsyncException err = isJust (Control.Exception.fromException err :: Maybe Control.Exception.SomeAsyncException) throwTopErrors :: [Control.Exception.SomeException] -> IO a throwTopErrors errs = case others of err:_ -> Control.Exception.throwIO err [] -> case typeErrs of [] -> error "Internal error: empty type error list" [err] -> Control.Exception.throwIO err _ -> Control.Exception.throwIO (TypeErrors typeErrs) where (typeErrs, others) = foldl' collect ([], []) errs collect (ts, os) err = case topTypeErrors err of Just ts' -> (ts ++ ts', os) Nothing -> (ts, os ++ [err]) topTypeErrors :: Control.Exception.SomeException -> Maybe [TypeError] topTypeErrors err = case Control.Exception.fromException err of Just (TypeErrors errs) -> Just errs Nothing -> case Control.Exception.fromException err of Just typeErr -> Just [typeErr] Nothing -> Nothing -- | Progress weight for one top-level statement, based on bound names. -- This makes large recursive groups count proportionally. stmtProgressWeight :: Stmt -> Int stmtProgressWeight s = length (stmtProgressNames s) -- | Top-level bound names used for progress reporting and weighting. stmtProgressNames :: Stmt -> [String] stmtProgressNames (Decl _ ds) = [ nstr (dname' d) | d <- ds ] stmtProgressNames s@Assign{} = map nstr (bound s) stmtProgressNames s@Signature{} = map nstr (bound s) stmtProgressNames s = error ("Unexpected top-level stmt: " ++ prstr s) uniqPrefix :: Stmt -> Name uniqPrefix (Decl _ (d : _)) = dname' d uniqPrefix s@Assign{} = head (bound s) uniqPrefix s@Signature{} = head (bound s) uniqPrefix s = error ("Unexpected top-level stmt: " ++ prstr s) infTopStmt :: Env -> Stmt -> TypeM (TEnv, [Stmt]) infTopStmt env s = do (total,te1,s) <- scanTopStmt env s -- NOTE: when total is True, te2 below is guaranteed to be identical to te1 --when total $ traceM ("## Scanned total env for " ++ prstrs (dom te1)) (te2,s) <- checkTopStmt env te1 s return (te2, s) scanTopStmt :: Env -> Stmt -> TypeM (Bool, TEnv, Stmt) scanTopStmt env (Decl l ds) = do (_,te,ds) <- infEnv (setInDecl env) ds return (null $ ufree te, te, Decl l ds) scanTopStmt env (Signature l ns sc d) = return (True, [ (n, NSig sc d Nothing) | n <- ns ], Signature l ns sc d) scanTopStmt env (Assign l pats e) = do (te,_,pats) <- infEnvT env pats return (null $ ufree te, te, Assign l pats e) checkTopStmt :: Env -> TEnv -> Stmt -> TypeM (TEnv, [Stmt]) checkTopStmt env te (Decl l ds) = do (cs,ds) <- checkEnv (tydefine te env) ds --traceM ("****************************************** infer (" ++ show (length cs) ++ ") " ++ prstrs (bound ds)) --traceM ("\n\n\n############\n" ++ render (nest 4 $ vcat $ map pretty te)) --traceM ("------------\n" ++ render (nest 4 $ vcat $ map pretty ds)) --traceM ("\\\\\\\\\\\\\n" ++ render (nest 4 $ vcat $ map pretty cs)) (te,eq,ds) <- genEnv env cs te ds --traceM ("============ push\n" ++ render (nest 4 $ vcat $ map pretty eq)) --traceM ("~~~~~~~~~~~~ i.e. top:\n" ++ render (nest 4 $ vcat $ map pretty eq0)) --traceM ("============ and scoped:\n" ++ render (nest 4 $ vcat $ map pretty eq1)) --traceM ("------------ onto\n" ++ render (nest 4 $ vcat $ map pretty ds)) finishToStmt env te eq (Decl l ds) checkTopStmt env te (Signature l ns sc d) = return ([ (n, NSig sc d Nothing) | n <- ns ], [Signature l ns sc d]) checkTopStmt env te (Assign l pats e) = do (_,t,pats) <- infEnvT env pats (cs,e) <- inferSub env t e eq <- solveAll env te cs finishToStmt env te eq (Assign l pats e) finishToStmt env te eq s = do te <- defaultX env te --traceM ("===========\n" ++ render (nest 4 $ vcat $ map pretty te)) --traceM (".........................................." ++ prstrs (bound s) ++ "\n") let (eq0, eq1) = spliteqns eq s <- defaultX env =<< termred eq1 <$> usubst (pushEqns env eq0 s) tieWitKnots te [fixupSelf s] defaultX :: (UFree a, USubst a) => Env -> a -> TypeM a defaultX env x = do defaultVars (ufree x) usubst x where defaultVars tvs = do tvs' <- ufree <$> usubst (map tUni tvs) sequence [ usubstitute tv (dflt (uvkind tv)) | tv <- tvs' ] dflt KType = tNone dflt KFX = fxPure dflt PRow = posNil dflt KRow = kwdNil pushEqns :: Env -> Equations -> Stmt -> Stmt pushEqns env [] s = s pushEqns env eqs s | null pre = inject env inj s | otherwise = withLocal (bindWits pre) $ inject env inj s where backward = free s `intersect` bound eqs (pre,inj) = split [] [] (bound s) eqs split pre inj bvs [] = (reverse pre, reverse inj) split pre inj bvs (eq:eqs) | null forward = split (eq:pre) inj bvs eqs | otherwise = split pre (eq:inj) (bound eq ++ bvs) eqs where forward = free eq `intersect` bvs inject env [] s = s inject env eqs (Decl l ds) = Decl l [ d{ dbody = prune [] (free d) reveqs ++ dbody d } | d <- ds ] where reveqs = reverse eqs prune inj fvs [] = --trace ("### Injecting " ++ prstrs (bound inj) ++ " into " ++ prstr n) $ bindWits inj prune inj fvs (eq:eqs) | null needed = prune inj fvs eqs | otherwise = prune (eq:inj) (free eq ++ fvs) eqs where needed = bound eq `intersect` fvs inject env eqs (With l [] ss) = With l [] (injlast eqs ss) where injlast eqs [s] = [inject env eqs s] injlast eqs (s:ss) = s : injlast eqs ss inject env eqs s = error ("# Internal error: cyclic witnesses " ++ prstrs eqs ++ "\n# and statement\n" ++ prstr s) genEnv :: Env -> Constraints -> TEnv -> [Decl] -> TypeM (TEnv,Equations,[Decl]) genEnv env cs te ds | any typeDecl te = do te <- usubst te --traceM ("## genEnv types 1\n" ++ render (nest 6 $ pretty te)) --traceM (" where\n" ++ render (nest 6 $ vcat $ map pretty cs)) eq <- solveAll (posdefine (filter typeDecl te) env) te cs te <- usubst te --traceM ("## genEnv types 2\n" ++ render (nest 6 $ pretty te)) --traceM (" where\n" ++ render (nest 6 $ vcat $ map pretty cs)) return (te, eq, ds) | otherwise = do te <- usubst te --traceM ("## genEnv defs 1\n" ++ render (nest 6 $ pretty te)) --traceM (" where\n" ++ render (nest 6 $ vcat $ map pretty cs)) (cs,eq) <- newSimplify env te cs te <- usubst te (gen_us, gen_cs, te, eq) <- refine env cs te eq let gen_vs = take (length gen_us) tvarSupply sequence [ usubstitute uv (tVar tv) | (uv,tv) <- gen_us `zip` gen_vs ] te <- usubst te gen_cs <- usubst gen_cs --traceM ("## genEnv defs 2 [" ++ prstrs gen_vs ++ "]\n" ++ render (nest 6 $ pretty te)) --traceM (" where\n" ++ render (nest 6 $ vcat $ map pretty gen_cs)) let (q,ws) = qualify gen_vs gen_cs te1 = map (generalize q) te (eq1,eq2) = splitEqs (dom ws) eq ds1 = map (abstract q ds ws eq1) ds --traceM ("## genEnv defs 3 [" ++ prstrs q ++ "]\n" ++ render (nest 6 $ pretty te1)) return (te1, eq2, ds1) where qualify vs cs = (q, concat wss) where (q,wss) = unzip $ map qbind vs qbind v = (QBind v bounds, wits) where bounds = [ p | Proto _ _ w (TVar _ v') p <- cs, v == v' ] wits = [ (w, proto2type t p) | Proto _ _ w t@(TVar _ v') p <- cs, v == v' ] generalize q (n, NDef (TSchema l [] t) d doc) = (n, NDef (TSchema l q t) d doc) generalize q (n, i) = (n, i) abstract q ds ws eq d@Def{} | null $ qbinds d = d{ qbinds = noqual env q, pos = wit2par ws (pos d), dbody = bindWits eq ++ wsubst ds q ws (dbody d) } | otherwise = d{ dbody = bindWits eq ++ wsubst ds q ws (dbody d) } wsubst ds [] [] = id wsubst ds q ws = termsubst s where s = [ (n, Lambda l0 p k (Call l0 (tApp (eVar n) tvs) (wit2arg ws (pArg p)) (kArg k)) fx) | Def _ n [] p k _ _ _ fx _ <- ds ] tvs = map tVar $ qbound q splitEqs ws eq | null eq1 = ([], eq) | otherwise = (eq1++eq1', eq2') where (eq1,eq2) = partition (any (`elem` ws) . free) eq (eq1',eq2') = splitEqs (bound eq1 ++ ws) eq2 newRefine env cs te eq = do (eq,cs) <- newsolve env te eq cs te <- usubst te eq <- usubst eq return (ufree te, cs, te, eq) refine env cs te eq | run_new_solver = newRefine env cs te eq | not $ null solve_cs = do --traceM (" #solving: " ++ prstrs solve_cs) (cs',eq') <- solve env noQual te eq cs refineAgain cs' eq' | not $ null ambig_vs = do --traceM (" #defaulting: " ++ prstrs ambig_vs) (cs',eq') <- solve env isAmbig te eq cs refineAgain cs' eq' | not $ null tail_vs = do sequence [ tryUnify (Simple NoLoc "internal") (tUni v) (tNil $ uvkind v) | v <- tail_vs ] refineAgain cs eq | otherwise = do eq <- usubst eq return (gen_vs, cs, te, eq) where ambig_vs = ufree cs \\ closeDepVars (safe_vs) cs tail_vs = gen_vs `intersect` (tailvars te ++ tailvars cs) safe_vs = if null def_vss then [] else nub $ foldr1 intersect def_vss def_vss = [ nub $ filter canGen $ ufree sc | (_, NDef sc _ _) <- te, null $ scbind sc ] gen_vs = nub (foldr union (ufree cs) def_vss) isAmbig c = any (`elem` ambig_vs) (ufree c) refineAgain cs eq = do (cs1,eq1) <- newSimplify env te cs te <- usubst te refine env cs1 te (eq1++eq) solve_cs = [ c | c <- cs, noQual c ] noQual (Proto _ _ _ (TUni _ u) p) = False noQual c = True canGen tv = uvkind tv /= KFX markScoped env n q te [] = return ([], []) -- Should remove this simplify call too, but doing so destroys performance of our current inferior constraint-solver (see module yang.schema in acton-yang). markScoped env n [] te cs = newSimplify env te cs -- Return the marks in terms of NotImplemented equations for now, so that we can coexist with the need to also run simplify (see above) markScoped env n q te cs = return (cs, eq) where eq = [ mkEqn env w tWild eNotImpl | w <- ws ] ws = scopedWits env q cs tempGoal t = [(nWild, NVar t)] newSolveAll env te cs = do (eq,cs) <- newsolve env te [] cs (eq,_) <- newsolve env [] eq cs return eq solveAll env te [] = return [] solveAll env te cs | run_new_solver = newSolveAll env te cs | otherwise = do --traceM ("\n\n### solveAll " ++ prstrs cs) (cs,eq) <- newSimplify env te cs (cs,eq) <- solve env (const True) te eq cs return eq -------------------------------------------------------------------------------------------------------------------------- class Infer a where infer :: Env -> a -> TypeM (Constraints,Type,a) class InfEnv a where infEnv :: Env -> a -> TypeM (Constraints,TEnv,a) class InfEnvT a where infEnvT :: Env -> a -> TypeM (TEnv,Type,a) -------------------------------------------------------------------------------------------------------------------------- commonTEnv :: Env -> [TEnv] -> TypeM (Constraints,TEnv) commonTEnv env [] = return ([], []) commonTEnv env (te:tes) = unifEnv tes (restrict te vs) where vs = foldr intersect (dom te) $ map dom tes l = length tes unifEnv tes [] = return ([], []) unifEnv tes ((n,i):te) = do t <- newUnivar env let (cs1,i') = unif n t i (cs2,te') <- unifEnv tes te return (cs1++cs2, (n,i'):te') unif n t0 (NVar t) | length ts == l = ([ Cast (locinfo t 26) env t1 t0 | t1 <- t:ts ], NVar t0) where ts = [ t | te <- tes, Just (NVar t) <- [lookup n te] ] unif n t0 (NSVar t) | length ts == l = ([ Cast (locinfo t 27) env t1 t0 | t1 <- t:ts ], NSVar t0) where ts = [ t | te <- tes, Just (NSVar t) <- [lookup n te] ] {- unif n t0 (NDef sc d) | null (scbind sc) && length ts == l = ([ Cast t t0 | t <- ts ], NDef (monotype t0) d) where ts = [ sctype sc | te <- tes, Just (NDef sc d') <- [lookup n te], null (scbind sc), d==d' ] unif n t0 (NDef _ _) | length scs == l = case findName n env of NReserved -> err1 n "Expected a common signature for" NSig sc d -> ([], NDef sc d) where scs = [ sc | te <- tes, Just (NDef sc d) <- [lookup n te] ] -} unif n _ _ = err1 n "Conflicting bindings for" infSuiteEnv env ss = do (cs,te,ss') <- infEnv env ss checkSigs env te return (cs, te, ss') checkSigs env te | null ns = return () | otherwise = err2 ns "Signature lacks subsequent binding" where (sigs,terms) = sigTerms te ns = dom sigs \\ dom terms infLiveEnv env x | fallsthru x = do (cs,te,x') <- infSuiteEnv env x return (cs, Just te, x') | otherwise = do (cs,te,x') <- infSuiteEnv env x return (cs, Nothing, x') liveCombine te Nothing = Nothing liveCombine Nothing te' = Nothing liveCombine (Just te) (Just te') = Just $ te++te' fxUnwrapSc env sc = sc{ sctype = fxUnwrap env $ sctype sc } fxUnwrap env (TFun l fx p k t) = TFun l (fxUnwrap env fx) p k t fxUnwrap env (TFX l FXAction) | inAct env = TFX l FXProc fxUnwrap env t = t wrap env t@TFun{} = do tvx <- newUnivarOfKind KFX env tvy <- newUnivarOfKind KFX env w <- newWitness return (Proto (locinfo t 28) env w tvx (pWrapped (effect t) tvy), t{ effect = tvx }) wrapped l kw env cs ts args = do tvx <- newUnivarOfKind KFX env tvy <- newUnivarOfKind KFX env let p = pWrapped tvx tvy Just (_, sc, Just Static) = findAttr env p kw (_,tvs,t0) <- instantiate env sc fx <- newUnivarOfKind KFX env t' <- newUnivar env let t1 = vsubst [(fxSelf,fx)] t0 t2 = tFun fxPure (foldr posRow posNil ts) kwdNil t' w <- newWitness unify (locinfo l 30) t1 t2 t' <- usubst t' cs' <- usubst (Proto (locinfo l 29) env w fx p : cs) return (cs', t', eCall (tApp (Dot l0 (eVar w) kw) tvs) args) -------------------------------------------------------------------------------------------------------------------------- instance (InfEnv a) => InfEnv [a] where infEnv env [] = return ([], [], []) infEnv env (s : ss) = do (cs1,te1,s1) <- infEnv env s let te1' = if inDecl env then noDefs te1 else te1 -- TODO: also stop class instantiation! env' = tydefine te1' env (cs2,te2,ss2) <- infEnv env' ss return (cs1++cs2, te1++te2, s1:ss2) instance InfEnv Stmt where infEnv env (Expr l e) | e == eNotImpl = return ([], [], Expr l e) | otherwise = do (cs,_,e') <- infer env e return (cs, [], Expr l e') infEnv env (Assign l pats e) | nodup pats, e == eNotImpl = do (te,t,pats') <- infEnvT env pats return ([], te, Assign l pats' e) | otherwise = do (te,t,pats') <- infEnvT env pats (cs,e') <- inferSub env t e return (cs, te, Assign l pats' e') infEnv env (Assert l e1 e2) = do (cs1,_,_,_,e1') <- inferTest env e1 (cs2,e2') <- inferSub env tStr e2 return (cs1++cs2, [], Assert l e1' e2') infEnv env s@(Pass l) = return ([], [], s) infEnv env s@(Return l Nothing) = do t <- currRet return ([Cast (locinfo l 31) env tNone t], [], Return l Nothing) infEnv env (Return l (Just e)) = do t <- currRet (cs,e') <- inferSub env t e return (cs, [], Return l (Just e')) infEnv env (Raise l e) = do (cs,t,e') <- infer env e return (Cast (locinfo2 32 e) env t tException : cs, [], Raise l e') infEnv env s@(Break _) = return ([], [], s) infEnv env s@(Continue _) = return ([], [], s) infEnv env (If l bs els) = do (css,tes,bs') <- fmap unzip3 $ mapM (infLiveEnv env) bs (cs0,te,els') <- infLiveEnv env els (cs1,te1) <- commonTEnv env $ catMaybes (te:tes) return (cs0++cs1++concat css, te1, If l bs' els') infEnv env (While l e b els) = do (cs1,env',s,_,e') <- inferTest env e (cs2,te1,b') <- infSuiteEnv env' b (cs3,te2,els') <- infSuiteEnv env els return (cs1++cs2++cs3, [], While l e' (termsubst s b') els') infEnv env (For l p e b els) | nodup p = do (te,t1,p') <- infEnvT env p t2 <- newUnivar env (cs2,e') <- inferSub env t2 e (cs3,te1,b') <- infSuiteEnv (define te env) b (cs4,te2,els') <- infSuiteEnv env els w <- newWitness return (Proto (locinfo2 33 e) env w t2 (pIterable t1) : cs2++cs3++cs4, [], For l p' (eCall (eDot (eVar w) iterKW) [e']) b' els') infEnv env (Try l b hs els fin) = do (cs1,te,b') <- infLiveEnv env b (cs2,te',els') <- infLiveEnv (maybe id define te $ env) els (css,tes,hs') <- fmap unzip3 $ mapM (infLiveEnv env) hs (cs3,te1) <- commonTEnv env $ catMaybes $ (liveCombine te te'):tes (cs4,te2,fin') <- infSuiteEnv env fin fx <- currFX return (--Cast fxProc fx : cs1++cs2++cs3++cs4++concat css, te1++te2, Try l b' hs' els' fin') infEnv env (With l items b) | nodup items = do (cs1,te,items') <- infEnv env items (cs2,te1,b') <- infSuiteEnv (define te env) b return $ (cs1++cs2, exclude te1 (dom te), With l items' b') infEnv env (VarAssign l pats e) | nodup pats = do (te,t,pats') <- infEnvT env pats (cs,e') <- inferSub env t e return (cs, [ (n,NSVar t) | (n,NVar t) <- te], VarAssign l pats' e') infEnv env (After l e1 e2) = do (cs1,e1') <- inferSub env tFloat e1 (cs2,t,e2') <- infer env e2 -- TODO: constrain t fx <- currFX return (Cast (locinfo l 34) env fxProc fx : cs1++cs2, [], After l e1' e2') infEnv env (Signature l ns sc@(TSchema _ q t) dec) | not $ null bad = illegalSigOverride (head bad) | otherwise = return ([], [(n, NSig sc dec' Nothing) | n <- ns], Signature l ns sc dec) where redefs = [ (n,i) | n <- ns, let i = findName n env, i /= NReserved ] bad = [ n | (n,i) <- redefs, not $ ok i ] ok (NSig (TSchema _ [] t') d _) = null q && castable env t t' && dec == d ok _ = False dec' = if inClass env && isProp dec sc then Property else dec infEnv env (Data l _ _) = notYet l "data syntax" infEnv env (Decl l ds) | inDecl env && nodup ds = do (cs1,te1,ds1) <- infEnv env ds return (cs1, te1, Decl l ds1) | nodup ds = do --traceM ("######## decls: " ++ prstrs (declnames ds)) (_,te1,ds1) <- infEnv (setInDecl env) ds (cs2,ds2) <- checkEnv (tydefine te1 env) ds1 --traceM ("-------- done: " ++ prstrs (declnames ds)) return (cs2, te1, Decl l ds2) infEnv env (Delete l targ) = do (cs0,t0,e0,tg) <- infTarg env targ (cs1,stmt) <- del t0 e0 tg return (cs0++cs1, [], stmt) where del t0 e0 (TgVar n) = do return ( Cast (locinfo l 35) env tNone t0 : [], sAssign (pVar' n) eNone) del t0 e0 (TgIndex ix) = do ti <- newUnivar env (cs,ix) <- inferSub env ti ix t <- newUnivar env w <- newWitness return ( Proto (locinfo l 36) env w t0 (pIndexed ti t) : cs, sExpr $ dotCall w delitemKW [e0, ix] ) del t0 e0 (TgSlice sl) = do (cs,sl) <- inferSlice env sl t <- newUnivar env w <- newWitness return ( Proto (locinfo l 37) env w t0 (pSliceable t) : cs, sExpr $ dotCall w delsliceKW [e0, sliz2exp sl] ) del t0 e0 (TgDot n) = do t <- newUnivar env return ( Mut (locinfo l 38) env t0 n t : Cast (locinfo l 39) env tNone t : [], sMutAssign (eDot e0 n) eNone ) infEnv env (MutAssign l targ e) = do (cs0,t0,e0,tg) <- infTarg env targ t <- newUnivar env (cs1,e) <- inferSub env t e (cs2,stmt) <- asgn t0 t e0 e tg return (cs0++cs1++cs2, [], stmt) where asgn t0 t e0 e (TgVar n) = do tryUnify (locinfo l 40) t0 t return ( [], sAssign (pVar' n) e ) asgn t0 t e0 e (TgIndex ix) = do ti <- newUnivar env (cs,ix) <- inferSub env ti ix w <- newWitness return ( Proto (locinfo l 41) env w t0 (pIndexed ti t) : cs, sExpr $ dotCall w setitemKW [e0, ix, e] ) asgn t0 t e0 e (TgSlice sl) = do (cs,sl) <- inferSlice env sl t' <- newUnivar env w <- newWitness w' <- newWitness return ( Proto (locinfo l 42) env w t0 (pSliceable t') : Proto (locinfo l 43) env w' t (pIterable t') : cs, sExpr $ eCall (tApp (eDot (eVar w) setsliceKW) [t]) [e0, eVar w', sliz2exp sl, e] ) asgn t0 t e0 e (TgDot n) = do return ( Mut (locinfo l 44) env t0 n t : [], sMutAssign (eDot e0 n) e ) infEnv env (AugAssign l targ o e) = do (cs0,t0,e0,tg) <- infTarg env targ t1 <- newUnivar env (cs1,e) <- inferSub env t1 e let (proto,kw) = oper t1 o t <- if o `elem` [MultA,DivA] then newUnivar env else pure t1 w <- newWitness (ss,x) <- mkvar t0 e0 (cs2,stmt) <- aug t0 t x (dotCall w kw) e tg return ( Proto (locinfo l 45) env w t proto : cs0++cs1++cs2, [], withLocal ss stmt ) where oper t MultA = (pTimes t, imulKW) oper t DivA = (pDiv t, itruedivKW) oper _ PlusA = (pPlus, iaddKW) oper _ MinusA = (pMinus, isubKW) oper _ PowA = (pNumber, ipowKW) oper _ ModA = (pIntegral, imodKW) oper _ EuDivA = (pIntegral, ifloordivKW) oper _ ShiftLA = (pIntegral, ilshiftKW) oper _ ShiftRA = (pIntegral, irshiftKW) oper _ BOrA = (pLogical, iorKW) oper _ BAndA = (pLogical, iandKW) oper _ MMultA = (pMatrix, imatmulKW) aug t0 t x f e (TgVar _) = do tryUnify (locinfo l 46) t0 t return ( [], sAssign (pVar' x) $ f [eVar x, e] ) aug t0 t x f e (TgIndex ix) = do ti <- newUnivar env (cs,ix) <- inferSub env ti ix w <- newWitness return ( Proto (locinfo l 47) env w t0 (pIndexed ti t) : cs, sExpr $ dotCall w setitemKW [eVar x, ix, f [dotCall w getitemKW [eVar x, ix], e]]) aug t0 t x f e (TgSlice sl) = do tryUnify (locinfo l 1115) t0 t (cs,sl) <- inferSlice env sl t' <- newUnivar env w <- newWitness w' <- newWitness let e1 = f [dotCall w getsliceKW [eVar x, sliz2exp sl], e] return ( Proto (locinfo l 48) env w t (pSliceable t') : Proto (locinfo l 49) env w' t (pIterable t') : cs, sExpr $ eCall (tApp (eDot (eVar w) setsliceKW) [t]) [eVar x, eVar w', sliz2exp sl, e1] ) aug t0 t x f e (TgDot n) = do return ( Mut (locinfo l 50) env t0 n t : [], sMutAssign (eDot (eVar x) n) $ f [eDot (eVar x) n, e]) dotCall w kw = eCall (eDot (eVar w) kw) mkvar t (Var _ (NoQ x)) = return ([], x) mkvar t e = do x <- newTmp return ([sAssign (pVar x t) e], x) data Tg = TgVar Name | TgIndex Expr | TgSlice Sliz | TgDot Name infTarg env e@(Var l (NoQ n)) = case findName n env of NReserved -> err1 n "Variable not yet assigned" NSig{} -> err1 n "Variable not yet assigned" NVar t -> return ([], t, e, TgVar n) NSVar t -> do fx <- currFX return ([Cast (locinfo l 51) env fxProc fx], t, e, TgVar n) _ -> err1 n "Variable not assignable:" infTarg env (Index l e ix) = do (cs,t,e) <- infer env e fx <- currFX return (Cast (locinfo l 52) env fxMut fx : Cast (locinfo' l 53 e) env t tObject : cs, t, e, TgIndex ix) infTarg env (Slice l e sl) = do (cs,t,e) <- infer env e fx <- currFX return (Cast (locinfo l 54) env fxMut fx : Cast (locinfo' l 55 e) env t tObject : cs, t, e, TgSlice sl) infTarg env (Dot l e n) = do (cs,t,e) <- infer env e fx <- currFX return (Cast (locinfo l 56) env fxMut fx : Cast (locinfo' l 57 e) env t tObject : cs, t, e, TgDot n) sliz2exp (Sliz _ e1 e2 e3) = eCall (eQVar qnSlice) $ map (maybe eNone id) [e1,e2,e3] withLocal [] s = s withLocal ss s = With l0 [] (ss ++ [s]) -------------------------------------------------------------------------------------------------------------------------- matchingDec n sc dec NoDec = True matchingDec n sc dec dec' | dec == dec' = True | otherwise = decorationMismatch n sc dec matchDefAssumption env cs1 def@Def{dname=n, qbinds=q1} | q0 == q1 = match cs1 [] def | null q1 = do let uvs = nub (ufree def ++ ufree cs1) \\ ufree env --traceM ("### matching " ++ prstr def) --traceM ("### with\n" ++ render (nest 4 $ vcat $ map pretty cs1)) --traceM ("### against " ++ prstr (n, findName n env) ++ "\n") sequence [ usubstitute uv =<< newUnivarOfKind (uvkind uv) env0 | uv <- uvs ] def <- usubst def cs1 <- usubst (requantize env0 cs1) match cs1 [] def | otherwise = do (cs, uvs) <- instQBinds env0 q1 let eq1 = witSubst env0 q1 cs s = qbound q1 `zip` uvs cs1' = vsubst s (requantize env0 cs1) def' = vsubst s def match (cs ++ cs1') eq1 def' where NDef (TSchema _ q0 t) dec _ = findName n env t0 | inClass env = addSelf t (Just dec) | otherwise = t env0 = tydefineVars q0 env fx | inAct env = dfx def | otherwise = effect t0 match cs eq def = do --traceM ("## matchDefAssumption " ++ prstr n ++ ": [" ++ prstrs q0 ++ "] => ") --traceM (render (nest 4 $ vcat $ map pretty $ Cast info env0 t1 t0 : cs)) (cs',eq') <- markScoped env n q0 (tempGoal t1) (Cast info env0 t1 t0 : cs) cs' <- usubst cs' return (cs', def{ qbinds = noqual env0 q0, pos = pos0, kwd = kwd0, dbody = bindWits (eq++eq') ++ dbody def, dfx = fx }) where t1 = tFun (dfx def) (prowOf $ pos def) (krowOf $ kwd def) (fromJust $ ann def) (pos0,kwd0) = qualDef env dec (pos def) (kwd def) (qualWPar env q0) sc1 = TSchema NoLoc q1 t1 mbl = findSigLoc n env msg = "Type incompatibility between signature for and definition of "++Pretty.print n info = maybe (locinfo def 58) (\l -> DeclInfo l (loc def) n sc1 msg) mbl qualDef env dec p k qf | not (inClass env) = (qf p, k) qualDef env Static p k qf = (qf p, k) qualDef env dec PosNIL (KwdPar n t e k) qf = (PosPar n t e (qf PosNIL), k) qualDef env dec (PosPar n t e p) k qf = (PosPar n t e (qf p), k) initComplement env n as body -- | True = body | inBuiltin env || null as = body | otherwise = defAltInit : body where defAltInit | baseHasAltInit = --trace ("### Connecting altInit chain to " ++ prstr base) $ mkInit (sExpr (eCall (eDot (eQVar basename) altInit) [eVar selfKW])) | otherwise = --trace ("### Stopping altInit chain before " ++ prstr base) $ mkInit sPass base = snd $ head as basename = tcname base baseHasAltInit = isJust $ findAttr env base altInit mkInit stmt = sDef altInit (pospar [(selfKW,tSelf)]) tNone [stmt] fxPure lockSelf l p k dec = tryUnify (Simple l "Type of first parameter of class method does not unify with Self") tSelf $ selfType p k dec -------------------------------------------------------------------------------------------------------------------------- instance InfEnv Decl where infEnv env d@(Def l n q p k a _ dec' fx ddoc) | nodup (p,k) = case findName n env of NSig sc dec _ | t@TFun{} <- sctype sc, matchingDec n sc dec dec' -> do --traceM ("\n## infEnv (sig) def " ++ prstr (n, NDef sc dec Nothing)) when (inClass env) $ lockSelf l p k dec return ([], [(n, NDef (fxUnwrapSc env sc) dec ddoc)], d{deco = dec}) NReserved -> do when (inClass env) $ lockSelf l p k dec' t <- tFun (fxUnwrap env fx) (prowOf p) (krowOf k) <$> maybe (newUnivar env) return a let sc = tSchema q (if inClass env then dropSelf t dec' else t) --traceM ("\n## infEnv def " ++ prstr (n, NDef sc dec' Nothing)) return ([], [(n, NDef sc dec' ddoc)], d) _ -> illegalRedef n infEnv env d@(Actor _ n q p k b ddoc) | nodup (p,k) = case findName n env of NReserved -> do te <- infActorEnv env b let prow = prowOf p krow = krowOf k --traceM ("\n## infEnv actor " ++ prstr (n, NAct q prow krow te ddoc)) return ([], [(n, NAct q prow krow te ddoc)], d) _ -> illegalRedef n infEnv env (Class l n q us b ddoc) | not $ null ps = notYet (loc n) "Classes with direct extensions" | otherwise = case findName n env of NReserved -> do --traceM ("\n## infEnv class " ++ prstr n) pushFX fxPure tNone te0 <- infProperties env1 as' b (cs,te,b1) <- infEnv env1 b0 popFX when (not $ null cs) $ err (loc n) "Deprecated class syntax" checkClassAttributesInitialized n l env as' b (nterms,asigs,_) <- checkAttributes [] te' te let (te2,b2) = if notImplBody b then let te1 = unSig asigs in (te++te1, addImpl te1 b1) else if null asigs && initKW `notElem` dom te then relayInit te b1 else (te,b1) return ([], [(n, NClass q as' (te0++te2) ddoc)], Class l n q us (props te0 ++ b2) ddoc) _ -> illegalRedef n where env1 = define (exclude (toSigs te') [initKW]) $ reserve (assigned b0) $ tydefineVars (stripQual q') $ setInClass env (as,ps) = mro2 env us as' = if null as && not (inBuiltin env && n == nValue) then leftpath [cValue] else as te' = parentTEnv env as' q' = selfQuant (NoQ n) q props te0 = [ Signature l0 [n] sc Property | (n,NSig sc Property _) <- te0 ] tc = TC (NoQ n) (map tVar $ qbound q) b0 = initComplement env n as' b relayInit te b = --trace ("####### Creating relayInit for class " ++ prstr n) $ case lookup initKW te' of Just ni@(NDef sc _ _) -> ((initKW,ni):te, sDecl [Def NoLoc initKW [] pp kp Nothing body NoDec fx Nothing]:b) where t = addSelf (sctype sc) (Just NoDec) pp = pPar pNames $ posrow t kp = kPar attrKW $ kwdrow t fx = effect t body = [sExpr $ Call NoLoc (eDot (eQVar $ tcname $ head us) initKW) (pArg pp) (kArg kp)] infEnv env (Protocol l n q us b ddoc) = case findName n env of NReserved -> do --traceM ("\n## infEnv protocol " ++ prstr n) pushFX fxPure tNone (cs,te,b') <- infEnv env1 b popFX when (not $ null cs) $ err (loc n) "Deprecated protocol syntax" (nterms,_,sigs) <- checkAttributes [] te' te let noself = [ n | (n, NSig sc Static _) <- te, tvSelf `notElem` vfree sc ] when (notImplBody b) $ err0 (notImpls b) "A protocol body cannot be NotImplemented" when (not $ null nterms) $ err2 (dom nterms) "Method/attribute lacks signature:" when (initKW `elem` sigs) $ err2 (filter (==initKW) sigs) "A protocol cannot define __init__" when (not $ null noself) $ err2 noself "A static protocol signature must mention Self" return ([], [(n, NProto q ps te ddoc)], Protocol l n q us b' ddoc) _ -> illegalRedef n where env1 = define (toSigs te') $ reserve (assigned b) $ tydefineVars (stripQual q') $ setInClass env ps = mro1 env us te' = parentTEnv env ps q' = selfQuant (NoQ n) q infEnv env (Extension l q c us b ddoc) | length us == 0 = err (loc n) "Extension lacks a protocol" -- | length us > 1 = notYet (loc n) "Extensions with multiple protocols" | not $ null witsearch = err (loc n) ("Extension already exists: " ++ prstr (head witsearch)) | otherwise = do --traceM ("\n## infEnv extension " ++ prstr (extensionName us c)) pushFX fxPure tNone (cs,te,b1) <- infEnv env1 b popFX when (not $ null cs) $ err (loc n) "Deprecated extension syntax" (nterms,asigs,sigs) <- checkAttributes final te' te when (not $ null nterms) $ err2 (dom nterms) "Method/attribute not in listed protocols:" when (not $ null sigs) $ err2 sigs "Extension with new methods/attributes not supported" when (not (null asigs || notImplBody b)) $ err3 l (dom asigs) "Protocol method/attribute lacks implementation:" let te1 = unSig $ selfSubst n q asigs te2 = te ++ te1 b2 = addImpl te1 b1 return ([], [(extensionName us c, NExt q c ps te2 [] ddoc)], Extension l q c us b2 ddoc) where TC n ts = c env1 = define (toSigs te') $ reserve (assigned b) $ tydefineVars (stripQual q') $ setInClass env witsearch = findWitness env (tCon c) u u = head us ps = selfSubst n q $ mro1 env us -- TODO: check that ps doesn't contradict any previous extension mro for c final = concat [ conAttrs env (tcname p) | (_,p) <- tail ps, hasWitness env (tCon c) p ] te' = parentTEnv env ps q' = selfQuant n q -------------------------------------------------------------------------------------------------------------------------- checkAttributes final te' te | not $ null dupsigs = err2 dupsigs "Duplicate signatures for" | not $ null props = err2 props "Property attributes cannot have class-level definitions:" | not $ null nodef = err2 nodef "Methods finalized in a previous extension cannot be overridden:" | otherwise = return (nterms, abssigs, dom sigs) where (sigs,terms) = sigTerms te (sigs',terms') = sigTerms te' (allsigs,allterms) = (sigs ++ sigs', terms ++ terms') dupsigs = duplicates (dom sigs) nterms = exclude terms (dom allsigs) abssigs = allsigs `exclude` (dom allterms ++ final) props = dom terms `intersect` dom (propSigs allsigs) nodef = dom terms `intersect` final addImpl [] ss = ss addImpl asigs (s : ss) | isNotImpl s = fromTEnv (unSig asigs) ++ s : ss | otherwise = s : addImpl asigs ss toSigs te = map makeSig te where makeSig (n, NDef sc dec doc) = (n, NSig sc dec doc) makeSig (n, NVar t) = (n, NSig (monotype t) Static Nothing) makeSig (n, i) = (n,i) -------------------------------------------------------------------------------------------------------------------------- checkClassAttributesInitialized :: Name -> SrcLoc -> Env -> [WTCon] -> Suite -> TypeM () checkClassAttributesInitialized className classLoc env ancestors b = do -- Only check if the class defines its own __init__. If it doesn't, it uses the parent's -- __init__ which already initialized everything (and we check the parent separately) case findInitMethod b of Nothing -> return () -- No __init__, uses parent's Just (self, initBody, initLoc) -> -- Check if __init__ is implemented in C (body is NotImplemented) if hasNotImpl initBody then return () -- Assume all is OK - we can't analyze C implementation else do let inherited = concatMap (getPropertiesFromClass env . tcname . snd) ancestors explicit = concat [ ns | Signature _ ns sc dec <- b, isProp dec sc ] inferred = inferClassAttributes self initBody expected = nub $ inherited ++ explicit ++ inferred initialized = scanSelfAssigns env self b initBody -- Track which parent __init__ methods are called calledParentInits = getCalledParentInits env initBody -- Get attributes initialized by called parent __init__ methods parentInitialized = nub $ concatMap (getInitializedByParent env) calledParentInits uninitialized = expected \\ (initialized ++ parentInitialized) forM_ uninitialized $ \prop -> let parentInfo = findAttributeParent prop isInferred = prop `elem` inferred && prop `notElem` explicit && prop `notElem` inherited in Control.Exception.throw $ UninitializedAttribute (loc prop) prop isInferred initLoc classLoc className parentInfo where getPropertiesFromClass env qn = let (_,_,te) = findConName qn env in [ n | (n, NSig _ Property _) <- te ] -- Helper to look up class location in environment getClassLoc env qname = case findClass (activeNames env) of Just l -> l Nothing -> maybe NoLoc id (findClass (closedNames env)) where findClass ((n, NClass{}):te) | n == noq qname = Just (loc n) findClass (_:te) = findClass te findClass [] = Nothing -- Find which parent class (if any) defines the given attribute findAttributeParent attrName = case [ n | Signature _ ns _ _ <- b, n <- ns, n == attrName ] of (_:_) -> Nothing -- Defined in current class [] -> -- Look for it in ancestors case mapMaybe (findInAncestor attrName) ancestors of (result:_) -> Just result [] -> Nothing -- Check if a specific ancestor defines the attribute findInAncestor attrName (_, anc)= let ancName = tcname anc in if attrName `elem` getPropertiesFromClass env ancName then Just (noq ancName, getClassLoc env ancName) else Nothing wellformed :: (WellFormed a) => Env -> a -> TypeM () wellformed env x = do _ <- solveAll env [] cs return () where cs = wf env x wellformedProtos :: Env -> [PCon] -> TypeM (Constraints, [(QName,[Expr])]) wellformedProtos env ps = do (css0, css1) <- unzip <$> mapM (wfProto env) ps _ <- solveAll env [] (concat css0) return (concat css1, [ (tcname p, protoWitsOf cs) | (p,cs) <- ps `zip` css1 ]) -------------------------------------------------------------------------------------------------------------------------- class Check a where checkEnv :: Env -> a -> TypeM (Constraints,a) checkEnv' :: Env -> a -> TypeM (Constraints,[a]) checkEnv env x = undefined checkEnv' env x = do (cs,x') <- checkEnv env x return (cs, [x']) instance (Check a) => Check [a] where checkEnv env [] = return ([], []) checkEnv env (d:ds) = do (cs1,d') <- checkEnv' env d (cs2,ds') <- checkEnv env ds return (cs1++cs2, d'++ds') ------------------ infActorEnv env ss = do dsigs <- mapM mkNDef dvars -- exposed defs without sigs bsigs <- mapM mkNVar pvars -- exposed assigns without sigs return (abssigs ++ unSig concsigs ++ dsigs ++ bsigs) -- abstract sigs ++ exposed sigs + the above where sigs = [ (n, NSig sc dec Nothing) | Signature _ ns sc dec <- ss, n <- ns, not $ isHidden n ] (concsigs, abssigs) = partition ((`elem`(dvars++pvars)) . fst) sigs dvars = notHidden $ methods ss \\ dom sigs mkNDef n = do t <- newUnivar env return (n, NDef (monotype $ t) NoDec Nothing) svars = statevars ss pvars = pvarsF ss \\ dom (sigs) \\ dvars pvarsF ss = nub $ concat $ map pvs ss where pvs (Assign _ pats _) = notHidden $ bound pats \\ svars -- svars only excluded until we move stateful actor cmds to __init__ pvs (If _ bs els) = foldr intersect (pvarsF els) [ pvarsF ss | Branch _ ss <- bs ] pvs _ = [] mkNVar n = do t <- newUnivar env return (n, NVar t) matchActorAssumption env n0 p k te = do --traceM ("## matchActorAssumption " ++ prstrs te) (css,eqs) <- unzip <$> mapM check1 te0 let cs = [Cast (locinfo p 60) env (tTuple p0 k0) (tTuple (prowOf p) (krowOf k)), Seal (locinfo p 112) env p0, Seal (locinfo k 113) env k0] (cs,eq) <- oldSimplify env obs (cs ++ concat css) return (cs, eq ++ concat eqs) where NAct q p0 k0 te0 _ = findName n0 env ns = dom te0 obs = te0 ++ te te1 = nTerms $ te `restrict` ns check1 (n, NSig _ _ _) = return ([], []) check1 (n, NVar t0) = do --traceM ("## matchActorAssumption for attribute " ++ prstr n) return ([Cast (locinfo n 62) env t t0, Seal (locinfo n 114) env t0],[]) where Just (NVar t) = lookup n te1 check1 (n, NDef sc0 _ _) = do (cs0,_,t) <- instantiate env sc (c0,t') <- wrap env t let c1 = Cast (locinfo n 63) env t' (sctype sc0) cs1 = map (Seal (locinfo n 115) env) (leaves sc0) q0 = scbind sc0 --traceM ("## matchActorAssumption for method " ++ prstr n ++ ": " ++ prstr c1) (cs2,eq) <- markScoped env n0 q0 obs (c0:c1:cs0++cs1) return (cs2, eq) where Just (NDef sc _ _) = lookup n te1 check1 (n, i) = return ([], []) -- Find __init__ method in class body, return self parameter, body and location findInitMethod :: Suite -> Maybe (Name, Suite, SrcLoc) findInitMethod b = listToMaybe [ (x, dbody d, loc d) | Decl _ ds <- b, d <- ds, dname d == initKW, Just x <- [selfPar d] ] -- Scan __init__ for "self.x = ..." to find which attributes are definitely -- assigned before any references to `self` escape externally. We allow most -- statements in the constructor as long as `self` does not escape although -- there are a few statements that will also be considered the end of the -- constructor (this isn't well documented). We are handling if/elif/else as -- well as some variations of exception handling and raising. Loops are allowed -- but any assignments in a loop does not count to the set of initialized -- attributes since we cannot statically determine if the loop executes. The -- loop is scanned to ensure `self` does not escape. scanSelfAssigns :: Env -> Name -> Suite -> Suite -> [Name] scanSelfAssigns env self classBody stmts = scanSuite [] stmts where -- Check if a method in the class has NotImplemented body isNotImplMethod :: Name -> Bool isNotImplMethod methodName = case [ d | Decl _ ds <- classBody, d@Def{dname=n} <- ds, n == methodName ] of (d:_) -> hasNotImpl (dbody d) [] -> False -- Check if a statement list ends with an early exit (only raise - not return!) -- Return would give back an uninitialized object, so it doesn't excuse initialization branchExitsEarly :: Suite -> Bool branchExitsEarly [] = False branchExitsEarly stmts = case last stmts of Raise _ _ -> True -- Only raise truly prevents object creation -- Recursively check nested if/else If _ branches elseBranch -> all (\(Branch _ body) -> branchExitsEarly body) branches && (not (null elseBranch) && branchExitsEarly elseBranch) -- Recursively check try/except Try _ tryBody handlers elseBranch finallyBlock -> -- If finally block raises, that's an early exit if not (null finallyBlock) && branchExitsEarly finallyBlock then True else -- Otherwise, check if all normal paths exit early branchExitsEarly tryBody && all (\(Handler _ hbody) -> branchExitsEarly hbody) handlers && (null elseBranch || branchExitsEarly elseBranch) _ -> False scanSuite seen [] = [] -- Handle assignments scanSuite seen (MutAssign _ (Dot _ (Var _ qn) n) e : rest) | noq qn == self = if checkNoSelfReference self seen e then n : scanSuite (n:seen) rest else [] -- Stop at self reference scanSuite seen (MutAssign _ _ _ : rest) = -- Continue: local assignment is OK scanSuite seen rest scanSuite seen (Assign _ _ e : rest) = -- Continue past local assignments, unless RHS contains self reference if checkNoSelfReference self seen e then scanSuite seen rest -- Continue past assignment else [] -- Stop at self reference scanSuite seen (AugAssign _ (Dot _ (Var _ qn) n) _ _ : rest) | noq qn == self && n `elem` seen -- OK: augmenting already-initialized attribute = scanSuite seen rest | noq qn == self = [] -- STOP: can't augment uninitialized attribute scanSuite seen (AugAssign _ _ _ _ : rest) = -- Continue: local augmented assignment is OK scanSuite seen rest -- Handle if/elif/else statements. Count assignments that happen in all -- branches as unconditional. Note how we must have an else branch in order -- to consider it exhaustive. Each branch either: -- 1. Completes normally and returns an object (must have initialized attributes), or -- 2. Exits early via raise (never returns an object, so doesn't constrain initialization) -- -- We need the intersection of assignments from all branches. Branches that exit early -- are "compatible" with any assignment set (they contribute the universal set to the -- intersection), so in practice we only intersect the branches that complete normally. -- -- Example: if cond: if cond: if cond: -- self.x = 1 self.x = 1 raise Error() -- else: else: else: -- self.x = 2 raise Error() self.x = 1 -- Result: {x} Result: {x} Result: {x} -- -- Without an else branch, the if/elif is non-exhaustive - we might skip all branches, -- so we can't guarantee any assignments. (Note: We don't attempt to analyze whether -- the predicates are exhaustive through logical analysis - that's undecidable in general -- and NP-complete even for boolean satisfiability. The else branch is our simple, -- syntactic criterion for exhaustiveness.) scanSuite seen (If _ branches elseBranch : rest) = -- Scan all branches for assignments let branchResults = map (\(Branch _ body) -> (scanSuite seen body, branchExitsEarly body)) branches elseResult = (scanSuite seen elseBranch, branchExitsEarly elseBranch) -- Branches that complete normally must be considered normalBranches = [assigns | (assigns, exits) <- branchResults, not exits] -- Else branch if it completes normally normalElse = case elseResult of (assigns, False) -> [assigns] -- Else completes normally (_, True) -> [] -- Else exits early -- All normal branches that do not exit early allNormalBranches = normalBranches ++ normalElse -- if we have else, it's exhaustive, otherwise it's not newAssigns = case not (null elseBranch) of False -> [] -- No else: not exhaustive, nothing counts True -> case allNormalBranches of [] -> [] -- All branches exit: no object returned branches -> foldl1 intersect branches -- Require intersection in newAssigns ++ scanSuite (newAssigns ++ seen) rest -- Only continue past simple statements scanSuite seen (Pass _ : rest) = scanSuite seen rest -- Parent init calls are special - they initialize parent attributes scanSuite seen (Expr _ (Call _ (Dot _ (Var _ c) n) _ _) : rest) | isClass env c, n == initKW = scanSuite seen rest -- Allow calling self methods that have NotImplemented body (C implementations) scanSuite seen (Expr _ (Call _ (Dot _ (Var _ (NoQ x)) methodName) _ _) : rest) | x == self && isNotImplMethod methodName = scanSuite seen rest -- Continue: NotImplemented method on self -- Stop at other self method calls scanSuite seen (Expr _ (Call _ (Dot _ _ _) _ _) : _) = [] -- STOP: method call -- Allow expressions without references to `self` scanSuite seen (Expr _ e : rest) | checkNoSelfReference self seen e = scanSuite seen rest -- Handle try/except/else/finally -- -- The possible execution paths are: -- 1. try → else (no exception raised) -- 2. handler (exception raised and caught) -- 3. exception propagates (not caught - early exit, no object returned) -- Finally always executes regardless of path taken. -- -- Since we don't know WHERE in try an exception might occur, we can't count ANY -- assignments from try when considering the exception path. But if try completes -- normally (no exception), we know ALL its assignments happened. -- -- Note: else is a CONTINUATION of try (only runs if try completes without exception), -- not an alternative branch like in if/else. -- -- Example: try: try: try: -- self.x = 1 self.x = 1 raise Error() -- self.y = 2 raise Error() except: -- except: except: self.x = 1 -- self.x = 1 self.x = 1 else: -- else: else: self.y = 2 -- self.z = 3 self.z = 3 -- -- Normal paths: Normal paths: Normal paths: -- - try+else: {x,y,z} - except: {x} - except: {x} -- - except: {x} (try+else exits) (try exits, else never runs) -- Result: {x} Result: {x} Result: {x} -- -- If try always exits (raises), we only consider handlers. If a handler exits, -- it doesn't contribute to the intersection (like if/else branches that exit). -- Finally assignments always count since finally always executes. scanSuite seen (Try _ tryBody handlers elseBranch finallyBlock : rest) = let -- Finally always executes finallyAssigns = scanSuite seen finallyBlock seenAfterFinally = finallyAssigns ++ seen -- Scan all code paths tryAssigns = scanSuite seenAfterFinally tryBody elseAssigns = scanSuite seenAfterFinally elseBranch handlerAssigns = map (\(Handler _ hbody) -> scanSuite seenAfterFinally hbody) handlers -- Check which paths exit early tryExits = branchExitsEarly tryBody elseExits = branchExitsEarly elseBranch handlerExits = map (\(Handler _ hbody) -> branchExitsEarly hbody) handlers -- Build list of paths that complete normally: -- 1. try+else path (if try doesn't exit) -- 2. each handler that doesn't exit tryElsePath = if not tryExits then [tryAssigns ++ if elseExits then [] else elseAssigns] else [] handlerPaths = [assigns | (assigns, exits) <- zip handlerAssigns handlerExits, not exits] normalPaths = tryElsePath ++ handlerPaths -- Intersect all normal paths (or empty if all exit) guaranteedFromPaths = case normalPaths of [] -> [] paths -> foldl1 intersect paths in finallyAssigns ++ guaranteedFromPaths ++ scanSuite (finallyAssigns ++ guaranteedFromPaths ++ seen) rest -- Handle loops - skip over them if they don't leak self references scanSuite seen (While _ cond body elseBranch : rest) | checkNoSelfReference self seen cond && checkNoSelfReferenceInSuite self seen body && checkNoSelfReferenceInSuite self seen elseBranch = scanSuite seen rest -- Continue past safe loop | otherwise = [] -- STOP: loop references self scanSuite seen (For _ pat expr body elseBranch : rest) | checkNoSelfReference self seen expr && checkNoSelfReferenceInSuite self seen body && checkNoSelfReferenceInSuite self seen elseBranch = scanSuite seen rest -- Continue past safe loop | otherwise = [] -- STOP: loop references self scanSuite _ (With _ _ _ : _) = [] -- STOP: with statements not supported -- Handle assert like if & raise - continue if test doesn't reference self scanSuite seen (Assert _ test msg : rest) | checkNoSelfReference self seen test && maybe True (checkNoSelfReference self seen) msg = scanSuite seen rest -- Continue: assert doesn't leak self | otherwise = [] -- STOP: assert references self scanSuite _ (Return _ _ : _) = [] -- STOP: early exit scanSuite _ (Raise _ _ : _) = [] -- STOP: raises exception -- Skip past break and continue - they are loop control flow, and we skip loops anyway scanSuite seen (Break _ : rest) = scanSuite seen rest scanSuite seen (Continue _ : rest) = scanSuite seen rest scanSuite seen (Delete _ _ : rest) = scanSuite seen rest scanSuite _ (After _ _ _ : _) = [] -- STOP: after statement (async) -- Check nested function declarations for self references scanSuite seen (Decl _ decls : rest) | all (checkDeclNoSelfReference self seen) decls = scanSuite seen rest -- Continue: nested functions don't capture self | otherwise = [] -- STOP: nested function captures self scanSuite _ (_ : _) = [] -- STOP: unhandled statement type (safe default) -- Check if a suite (list of statements) contains disallowed references to self checkNoSelfReferenceInSuite :: Name -> [Name] -> Suite -> Bool checkNoSelfReferenceInSuite self seen stmts = all checkStmt stmts where checkStmt (Expr _ e) = checkNoSelfReference self seen e checkStmt (Assign _ _ e) = checkNoSelfReference self seen e checkStmt (MutAssign _ target e) = checkNoSelfReference self seen e && checkNoSelfReference self seen target checkStmt (AugAssign _ target _ e) = checkNoSelfReference self seen e && checkNoSelfReference self seen target checkStmt (Return _ Nothing) = True checkStmt (Return _ (Just e)) = checkNoSelfReference self seen e checkStmt (If _ branches elseBranch) = all (\(Branch cond body) -> checkNoSelfReference self seen cond && checkNoSelfReferenceInSuite self seen body) branches && checkNoSelfReferenceInSuite self seen elseBranch checkStmt (While _ cond body elseBranch) = checkNoSelfReference self seen cond && checkNoSelfReferenceInSuite self seen body && checkNoSelfReferenceInSuite self seen elseBranch checkStmt (For _ _ expr body elseBranch) = checkNoSelfReference self seen expr && checkNoSelfReferenceInSuite self seen body && checkNoSelfReferenceInSuite self seen elseBranch checkStmt (Try _ tryBody handlers elseBranch finallyBlock) = checkNoSelfReferenceInSuite self seen tryBody && all (\(Handler _ hbody) -> checkNoSelfReferenceInSuite self seen hbody) handlers && checkNoSelfReferenceInSuite self seen elseBranch && checkNoSelfReferenceInSuite self seen finallyBlock checkStmt _ = True -- Conservative: allow other statements -- Check if an expression contains disallowed references to self -- We allow self.x since it can be seen as just a lone variable, which is valid -- as long as it has been previously assigned, but we cannot pass a reference to -- the whole `self` checkNoSelfReference :: Name -> [Name] -> Expr -> Bool checkNoSelfReference self seen expr = checkExpr expr where -- Check if an expression is allowed checkExpr :: Expr -> Bool checkExpr (Await _ _) = False -- Await is not allowed checkExpr (Var _ qn) | noq qn == self = False -- Direct reference to self not allowed checkExpr e@(Dot _ (Var _ qn) attr) | noq qn == self = attr `elem` seen -- self.attr is OK only if attr is initialized -- For other expressions, recursively check subexpressions checkExpr (Call _ func args kwds) = checkExpr func && checkPosArgs args && checkKwdArgs kwds checkExpr (BinOp _ e1 _ e2) = checkExpr e1 && checkExpr e2 checkExpr (CompOp _ e1 ops) = checkExpr e1 && all checkOpArg ops where checkOpArg (OpArg _ e) = checkExpr e checkExpr (UnOp _ _ e) = checkExpr e checkExpr (List _ elems) = all checkElem elems checkExpr (Tuple _ args kwds) = checkPosArgs args && checkKwdArgs kwds checkExpr (Paren _ e) = checkExpr e checkExpr (Cond _ cond thenE elseE) = checkExpr cond && checkExpr thenE && checkExpr elseE checkExpr (Index _ base idx) = checkExpr base && checkExpr idx checkExpr (Slice _ base (Sliz _ start stop step)) = checkExpr base && maybe True checkExpr start && maybe True checkExpr stop && maybe True checkExpr step checkExpr (Dict _ items) = all checkItem items checkExpr (Set _ elems) = all checkElem elems checkExpr (ListComp _ elem comp) = checkElem elem && checkComp comp checkExpr (DictComp _ (Assoc k v) comp) = checkExpr k && checkExpr v && checkComp comp checkExpr (SetComp _ elem comp) = checkElem elem && checkComp comp checkExpr (Lambda _ _ _ body _) = checkExpr body checkExpr (Yield _ e) = maybe True checkExpr e checkExpr (YieldFrom _ e) = checkExpr e checkExpr (Dot _ e _) = checkExpr e -- Check base expression checkExpr (Int _ _ _) = True -- Integer literals are OK checkExpr (Float _ _ _) = True -- Float literals are OK checkExpr (Strings _ _) = True -- String literals are OK checkExpr (BStrings _ _) = True -- Byte string literals are OK checkExpr (Bool _ _) = True -- Boolean literals are OK checkExpr None{} = True -- None is OK checkExpr _ = True -- Other expressions are OK (for now) checkPosArgs (PosArg e rest) = checkExpr e && checkPosArgs rest checkPosArgs (PosStar e) = checkExpr e checkPosArgs PosNil = True checkKwdArgs (KwdArg _ e rest) = checkExpr e && checkKwdArgs rest checkKwdArgs (KwdStar e) = checkExpr e checkKwdArgs KwdNil = True checkElem (Elem e) = checkExpr e checkElem (Star e) = checkExpr e checkItem (Assoc k v) = checkExpr k && checkExpr v checkComp (CompFor _ _ iter c) = checkExpr iter && checkComp c checkComp (CompIf _ test c) = checkExpr test && checkComp c checkComp NoComp = True -- Check if a declaration (nested function) references self -- We conservatively stop if ANY nested function references self at all, -- even if it only accesses already-initialized attributes checkDeclNoSelfReference :: Name -> [Name] -> Decl -> Bool checkDeclNoSelfReference self seen decl = case decl of Def _ _ _ _ _ _ body _ _ _ -> checkNoSelfReferenceInSuite self [] body -- Pass empty list to disallow ANY self reference Actor _ _ _ _ _ body _ -> checkNoSelfReferenceInSuite self [] body -- Pass empty list to disallow ANY self reference Class _ _ _ _ body _ -> True -- Nested classes don't capture self by default Protocol _ _ _ _ body _ -> True -- Nested protocols don't capture self Extension _ _ _ _ body _ -> True -- Extensions don't capture self -- Infer all class attributes by scanning the entire __init__ method for any -- self.x assignments, regardless of control flow. This is used for attribute -- discovery/inference, not for initialization checking. inferClassAttributes :: Name -> Suite -> [Name] inferClassAttributes self stmts = nub $ scanAll stmts where scanAll [] = [] -- Direct assignment to self.attribute scanAll (MutAssign _ (Dot _ (Var _ qn) n) _ : rest) | noq qn == self = n : scanAll rest -- Scan inside control structures scanAll (If _ branches elseBranch : rest) = concatMap (\(Branch _ body) -> scanAll body) branches ++ scanAll elseBranch ++ scanAll rest scanAll (While _ _ body elseBranch : rest) = scanAll body ++ scanAll elseBranch ++ scanAll rest scanAll (For _ _ _ body elseBranch : rest) = scanAll body ++ scanAll elseBranch ++ scanAll rest scanAll (Try _ tryBody handlers elseBranch finallyBlock : rest) = scanAll tryBody ++ concatMap (\(Handler _ hbody) -> scanAll hbody) handlers ++ scanAll elseBranch ++ scanAll finallyBlock ++ scanAll rest -- TODO: uh, do what with "with"?? scanAll (With _ witems body : rest) = scanAll body ++ scanAll rest scanAll (After _ _ _ : rest) = scanAll rest -- After has expressions, not suite -- Skip declarations - we don't scan nested function bodies scanAll (Decl _ _ : rest) = scanAll rest -- Continue past other statements scanAll (_ : rest) = scanAll rest -- Get all parent classes whose __init__ methods are called getCalledParentInits :: Env -> Suite -> [QName] getCalledParentInits _ [] = [] getCalledParentInits env (Expr _ (Call _ (Dot _ (Var _ c) n) _ _) : rest) | isClass env c, n == initKW = c : getCalledParentInits env rest getCalledParentInits env (_ : rest) = getCalledParentInits env rest -- Get attributes that would be initialized by calling a parent's __init__ -- This assumes the parent's __init__ properly initializes all attributes it's -- responsible for - we can rely on this since the parent's __init__ in turn -- will be checked getInitializedByParent :: Env -> QName -> [Name] getInitializedByParent env qn = -- When calling ParentClass.__init__(self), we assume it initializes: -- 1. All attributes declared in ParentClass -- 2. All attributes ParentClass inherited (since it should call its parent's __init__) let (_,ancestors,te) = findConName qn env inherited = concatMap (getPropertiesFromClass env . tcname . snd) ancestors declared = [ n | (n, NSig _ Property _) <- te ] in nub $ inherited ++ declared where getPropertiesFromClass env qn = let (_,_,te) = findConName qn env in [ n | (n, NSig _ Property _) <- te ] infProperties env as b | Just (self,ss) <- inits = forM newProps $ \n -> do t <- newUnivarOfKind KType env return (n, NSig (monotype t) Property Nothing) | otherwise = return [] where inherited = concat $ map (conAttrs env . tcname . snd) as explicit = concat [ ns | Signature _ ns sc dec <- b, isProp dec sc ] inits = case findInitMethod b of Just (self, body, _) -> Just (self, body) Nothing -> Nothing assigned = maybe [] (\(self,ss) -> inferClassAttributes self ss) inits newProps = assigned \\ (inherited ++ explicit) infDefBody env n (PosPar x _ _ _) k b | inClass env && n == initKW = infInitEnv (setInDef env) x b infDefBody env n p (KwdPar x _ _ _) b | inClass env && n == initKW = infInitEnv (setInDef env) x b infDefBody env _ _ _ b = infSuiteEnv (setInDef env) b infInitEnv env self (MutAssign l (Dot l' e1@(Var _ (NoQ x)) n) e2 : b) | x == self = do (cs1,t1,e1') <- infer env e1 t2 <- newUnivar env (cs2,e2') <- inferSub env t2 e2 (cs3,te,b') <- infInitEnv env self b return (Mut (locinfo l 64) env t1 n t2 : cs1++cs2++cs3, te, MutAssign l (Dot l' e1' n) e2' : b') infInitEnv env self (Expr l e : b) | Call{fun=Dot _ (Var _ c) n} <- e, isClass env c, n == initKW = do (cs1,_,e') <- infer env e (cs2,te,b') <- infInitEnv env self b return (cs1++cs2, te, Expr l e' : b') infInitEnv env self b = infSuiteEnv env b abstractDefs env q b = qsigs ++ map absDef b where qsigs = [ Signature NoLoc [n] (monotype $ proto2type (tVar v) p) Property | (v,p) <- quals env q, let n = tvarWit v p ] absDef (Decl l ds) = Decl l (map absDef' ds) absDef (If l bs els) = If l [ Branch e (map absDef ss) | Branch e ss <- bs ] (map absDef els) absDef stmt = stmt absDef' d@Def{} | deco d == Static = d{ pos = pos1 } | dname d == initKW = d{ pos = pos1, dbody = qcopies ++ dbody d } | otherwise = d{ dbody = bindWits qcopies' ++ dbody d } where nSelf = case pos d of PosPar nSelf _ _ _ -> nSelf pos1 = case pos d of PosPar nSelf t e p | deco d /= Static -> PosPar nSelf t e $ qualWPar env q p p -> qualWPar env q p qcopies = [ MutAssign NoLoc (eDot (eVar nSelf) n) (eVar n) | (v,p) <- quals env q, let n = tvarWit v p ] qcopies' = [ mkEqn env n (proto2type (tVar v) p) (eDot (eVar nSelf) n) | (v,p) <- quals env q, let n = tvarWit v p ] instance Check Decl where checkEnv env (Def l n q p k a b dec fx ddoc) = do --traceM ("## checkEnv def " ++ prstr n ++ " FX " ++ prstr fx') t <- maybe (newUnivar env) return a pushFX fx' t st <- newUnivar env wellformed env1 q wellformed env1 a when (inClass env) $ tryUnify (Simple l "Type of first parameter of class method does not unify with Self") tSelf $ selfType p k dec (csp,te0,p') <- infEnv env1 p (csk,te1,k') <- infEnv (define te0 env1) k (csb,_,b') <- infDefBody (define te1 (define te0 env1)) n p' k' b popFX let cst = if fallsthru b then [Cast (locinfo l 65) env1 tNone t] else [] t1 = tFun fx' (prowOf p') (krowOf k') t (cs0,eq1) <- oldSimplify env1 (tempGoal t1) (csp++csk++csb++cst) -- At this point, n has the type given by its def annotations. -- Now check that this type is no less general than its recursion assumption in env. let body = bindWits eq1 ++ defaultsP p' ++ defaultsK k' ++ b' (cs1,def) <- matchDefAssumption env cs0 (Def l n q p' k' (Just t) body dec fx' ddoc) return (cs1, def{ pos = noDefaultsP (pos def), kwd = noDefaultsK (kwd def) }) where env1 = reserve (bound (p,k) ++ assigned b \\ stateScope env) $ tydefineVars q env fx' = fxUnwrap env fx checkEnv env (Actor l n q p k b ddoc) = do --traceM ("## checkEnv actor " ++ prstr n) pushFX fxProc tNone wellformed env1 q (csp,te1,p') <- infEnv env1 p (csk,te2,k') <- infEnv (define te1 env1) k (csb,te,b') <- infSuiteEnv (define te2 $ define te1 env1) b -- At this point, each name defined in b has the type given by its annotations -- and possible type signatures. Now check that these types are no less general -- than the recursion assumption on actor n itself (which is distinct from any -- direct assumptions on its methods because actor interfaces are sealed). (cs0,eq0) <- matchActorAssumption env1 n p' k' te popFX (cs1,eq1) <- markScoped env n q te (csp++csk++csb++cs0) let body = bindWits (eq1++eq0) ++ defaultsP p' ++ defaultsK k' ++ b' act = Actor l n (noqual env q) (qualWPar env q p') k' body ddoc return (cs1, act{ pos = noDefaultsP (pos act), kwd = noDefaultsK (kwd act) }) where env1 = reserve (bound (p,k) ++ assigned b) $ setInAct $ define [(selfKW, NVar (tCon tc))] $ tydefineVars q env tc = TC (NoQ n) (map tVar $ qbound q) checkEnv' env (Class l n q us b ddoc) = do --traceM ("## checkEnv class " ++ prstr n) pushFX fxPure tNone wellformed env1 q wellformed env1 us (csb,b') <- checkEnv (define te' env1) b popFX (cs1,eq1) <- markScoped env n q' te csb return (cs1, [Class l n (noqual env q) (map snd as) (bindWits eq1 ++ abstractDefs env q b') ddoc]) where env1 = tydefineVars q' $ setInClass env NClass _ as te _ = findName n env te' = selfSubst n' q te q' = selfQuant n' q n' = NoQ n checkEnv' env (Protocol l n q us b ddoc) = do --traceM ("## checkEnv protocol " ++ prstr n) pushFX fxPure tNone wellformed env1 q (csu,wmap) <- wellformedProtos env1 us (csb,b') <- checkEnv (define te env1) b popFX (cs1,eq1) <- markScoped env n q' te (csu++csb) b' <- usubst b' return (cs1, convProtocol env n q ps eq1 wmap b') where env1 = tydefineVars q' $ setInClass env NProto _ ps te _ = findName n env te' = selfSubst n' q te q' = selfQuant n' q n' = NoQ n checkEnv' env (Extension l q c us b ddoc) | isActor env n = notYet (loc n) "Extension of an actor" | isProto env n = notYet (loc n) "Extension of a protocol" | otherwise = do --traceM ("## checkEnv extension " ++ prstr n ++ "(" ++ prstrs us ++ ")") pushFX fxPure tNone wellformed env1 q (csu,wmap) <- wellformedProtos env1 us (csb,b') <- checkEnv (define te' env1) b popFX (cs1,eq1) <- markScoped env n' q' te (csu++csb) b' <- usubst b' return (cs1, convExtension env n' c q ps eq1 wmap b' []) where env1 = tydefineInst c ps thisKW' $ tydefineVars q' $ setInClass env n = tcname c n' = extensionName us c NExt _ _ ps te _ _ = findName n' env te' = selfSubst n q te q' = selfQuant n q tc = TC n (map tVar $ qbound q) checkEnv' env x = do (cs,x') <- checkEnv env x return (cs, [x']) instance Check Stmt where checkEnv env (If l bs els) = do (cs1,bs') <- checkEnv env bs (cs2,els') <- checkEnv env els return (cs1++cs2, If l bs' els') checkEnv env (Decl l ds) = do (cs,ds') <- checkEnv env ds return (cs, Decl l ds') checkEnv env (Signature l ns sc dec) = do wellformed env1 q wellformed env1 t return ([], Signature l ns sc' dec') where TSchema l q t = sc sc' | null q = sc | otherwise = let TFun l' x p k t' = t in TSchema l (noqual env q) (TFun l' x (qualWRow env q p) k t') dec' = if inClass env && isProp dec sc then Property else dec env1 = tydefineVars q env checkEnv env s = return ([], s) instance Check Branch where checkEnv env (Branch e b) = do (cs,b') <- checkEnv env b return (cs, Branch e b') -------------------------------------------------------------------------------------------------------------------------- defaultsP (PosPar n (Just t) (Just e) p) | e /= eNone = set : defaultsP p where test = eCall (tApp (eQVar primISNONE) [t]) [eVar n] set = sAssign (pVar n t) (eCond e test (eVar n)) defaultsP (PosPar n _ _ p) = defaultsP p defaultsP _ = [] noDefaultsP (PosPar n (Just t) (Just e) p) = PosPar n (Just $ tOpt t) Nothing (noDefaultsP p) noDefaultsP (PosPar n t e p) = PosPar n t e (noDefaultsP p) noDefaultsP k = k defaultsK (KwdPar n (Just t) (Just e) k) | e /= eNone = set : defaultsK k where test = eCall (tApp (eQVar primISNONE) [t]) [eVar n] set = sAssign (pVar n t) (eCond e test (eVar n)) defaultsK (KwdPar n _ _ k) = defaultsK k defaultsK _ = [] noDefaultsK (KwdPar n (Just t) (Just e) k) = KwdPar n (Just $ tOpt t) Nothing (noDefaultsK k) noDefaultsK (KwdPar n t e k) = KwdPar n t e (noDefaultsK k) noDefaultsK k = k -------------------------------------------------------------------------------------------------------------------------- instance InfEnv Branch where infEnv env (Branch e b) = do (cs1,env',s,_,e') <- inferTest env e (cs2,te,b') <- infEnv env' b return (cs1++cs2, te, Branch e' (termsubst s b')) instance InfEnv WithItem where infEnv env (WithItem e Nothing) = do (cs,t,e') <- infer env e w <- newWitness return (Proto (locinfo2 66 e) env w t pContextManager : cs, [], WithItem e' Nothing) -- TODO: translate using w infEnv env (WithItem e (Just p)) = do (cs1,t1,e') <- infer env e (te,t2,p') <- infEnvT env p w <- newWitness return (Cast (locinfo2 67 e) env t1 t2 : Proto (locinfo2 68 e) env w t1 pContextManager : cs1, te, WithItem e' (Just p')) -- TODO: translate using w instance InfEnv Handler where infEnv env (Handler ex b) = do (cs1,te,ex') <- infEnv env ex (cs2,te1,b') <- infEnv (define te env) b return (cs1++cs2, exclude te1 (dom te), Handler ex' b') instance InfEnv Except where infEnv env (ExceptAll l) = return ([], [], ExceptAll l) infEnv env (Except l x) = return ([Cast (locinfo l 69) env t tException], [], Except l x) where t = tCon (TC (unalias env x) []) infEnv env (ExceptAs l x n) = return ([Cast (locinfo l 70) env t tException], [(n, NVar t)], ExceptAs l x n) where t = tCon (TC (unalias env x) []) instance Infer Expr where infer env x@(Var l n) = case findQName n env of NVar t -> return ([], t, x) NSVar t -> do fx <- currFX return ([Cast info env fxProc fx], t, x) where info = Simple l ("State variable may only be accessed in a proc") NDef sc d _ -> do (cs,tvs,t) <- instantiate env sc let e = app t (tApp x tvs) $ protoWitsOf cs cs1 = map (addTyping env n sc t) cs --traceM ("## type of " ++ prstr n ++ " = " ++ prstr t ++ ", cs = " ++ render(commaList cs)) if actorSelf env then wrapped l attrWrap env cs1 [tActor,t] [eVar selfKW,e] else return (cs1, t, e) NClass q _ _ _ -> do (cs0,ts) <- instQBinds env q --traceM ("## Instantiating " ++ prstr n) let ns = abstractAttrs env n when (not $ null ns) (err3 (loc n) ns "Abstract attributes prevent instantiation:") case findAttr env (TC n ts) initKW of Just (_,sc,_) -> do (cs1,tvs,t) <- instantiate env sc let t0 = tCon $ TC (unalias env n) ts t' = vsubst [(tvSelf,t0)] t{ restype = tSelf } return (cs0++cs1, t', app t' (tApp x (ts++tvs)) $ protoWitsOf (cs0++cs1)) NAct q p k _ _ -> do -- when (abstractActor env n) (err1 n "Abstract actor cannot be instantiated:") (cs,tvs,t) <- instantiate env (tSchema q (tFun fxProc p k (tCon0 (unalias env n) q))) return (cs, t, app t (tApp x tvs) $ protoWitsOf cs) NSig _ _ _ -> nameReserved n NReserved -> nameReserved n _ -> nameUnexpected n infer env e@(Int _ val s) | val < (-9223372036854775808) = return ([], tBigint, e) -- below i64 range ⇒ bigint | val > 18446744073709551615 = return ([], tBigint, e) -- above u64 range ⇒ bigint | val > 9223372036854775807 = return ([], tU64, e) -- between i64 max and u64 max ⇒ u64 | otherwise = do t <- newUnivar env w <- newWitness return ([Proto (locinfo2 72 e) env w t pNumber], t, eCall (eDot (eVar w) fromatomKW) [e]) infer env e@(Float _ val s) = do t <- newUnivar env w <- newWitness return ([Proto (locinfo2 73 e) env w t pRealFloat], t, eCall (eDot (eVar w) fromatomKW) [e]) infer env e@Imaginary{} = notYetExpr e infer env e@(Bool _ val) = return ([], tBool, e) infer env e@(None _) = return ([], tNone, e) infer env e@(NotImplemented _) = notYetExpr e infer env e@(Ellipsis _) = notYetExpr e infer env e@(Strings _ ss) = return ([], tStr, e) infer env e@(BStrings _ ss) = return ([], tBytes, e) infer env (Call l e ps ks) = inferCall env True l e ps ks infer env (TApp l e ts) = internal l "Unexpected TApp in infer" infer env (Let l ss e) = do (cs1, te, ss') <- infEnv env ss (cs2, t, e') <- infer (define te env) e return (cs1++cs2, t, Let l ss' e') infer env (Async l e) = do (cs,t,e) <- infer env e -- expect an action returning t' prow <- newUnivarOfKind PRow env krow <- newUnivarOfKind KRow env t' <- newUnivar env let tf fx = tFun fx prow krow return (Cast (locinfo2 74 e) env t (tf fxAction t') : cs, tf fxProc (tMsg t'), Async l e) -- produce a proc returning Msg[t'] infer env (Await l e) = do t0 <- newUnivar env (cs1,e') <- inferSub env (tMsg t0) e fx <- currFX return (Cast (locinfo2 75 e) env fxProc fx : cs1, t0, Await l e') infer env (Index l e ix) = do ti <- newUnivar env (cs1,ix') <- inferSub env ti ix t0 <- newUnivar env w <- newWitness (cs2,t,e') <- infer env e return (Proto (locinfo2 76 e) env w t (pIndexed ti t0) : cs1++cs2, t0, eCall (eDot (eVar w) getitemKW) [e', ix']) infer env (Slice l e sl) = do (cs1,sl') <- inferSlice env sl (cs2,t,e') <- infer env e t0 <- newUnivar env w <- newWitness return (Proto (locinfo2 77 e) env w t (pSliceable t0) : cs1++cs2, t, eCall (eDot (eVar w) getsliceKW) [e', sliz2exp sl']) infer env (Cond l e1 e e2) = do t0 <- newUnivar env (cs0,env',s,_,e') <- inferTest env e (cs1,e1') <- inferSub env' t0 e1 (cs2,e2') <- inferSub env t0 e2 return (cs0++cs1++cs2, t0, Cond l (termsubst s e1') e' e2') infer env (IsInstance l e c) = case findQName c env of NClass q _ _ _ -> do (cs,t,e') <- infer env e ts <- newUnivars env [ tvkind v | v <- qbound q ] return (cs, tBool, IsInstance l e' c) _ -> nameUnexpected c infer env (BinOp l s@Strings{} Mod e) | TRow _ _ _ t TNil{} <- prow = do (cs,e') <- inferSub env t e return (cs, tStr, eCall formatF [s,eTuple [e']]) | otherwise = do (cs,e') <- inferSub env tup e return (cs, tStr, eCall formatF [s,e']) where formatF = tApp (eQVar primFORMAT) [prow] tup = tTuple prow kwdNil prow = format $ concat $ sval s format [] = posNil format ('%':s) = nokey s format (c:s) = format s nokey ('(':s) = err l ("Mapping keys not supported in format strings") nokey s = flags s flags (f:s) | f `elem` "#0- +" = flags s flags s = width s width ('*':s) = posRow tInt (dot s) width (n:s) | n `elem` "123456789" = dot (dropWhile (`elem` "0123456789") s) width s = dot s dot ('.':s) = prec s dot s = len s prec ('*':s) = posRow tInt (len s) prec (n:s) | n `elem` "0123456789" = len (dropWhile (`elem` "0123456789") s) prec s = len s len (l:s) | l `elem` "hlL" = conv s len s = conv s conv (t:s) | t `elem` "diouxXc" = posRow tInt (format s) | t `elem` "eEfFgG" = posRow tFloat (format s) | t `elem` "rsa" = posRow tStr (format s) | t == '%' = format s conv (c:s) = err l ("Bad conversion character: " ++ [c]) conv [] = err l ("Bad conversion string") infer env e@(BinOp l e1 op e2) | op `elem` [Or,And] = do (cs,_,_,t,e') <- inferTest env e return (cs, t, e') | op == Mult = do t <- newUnivar env t' <- newUnivar env (cs1,e1') <- inferSub env t e1 (cs2,e2') <- inferSub env t' e2 w <- newWitness return (Proto (locinfo' l 79 e) env w t (pTimes t') : cs1++cs2, t, eCall (eDot (eVar w) mulKW) [e1',e2']) | op == Div = do t <- newUnivar env t' <- newUnivar env (cs1,e1') <- inferSub env t e1 (cs2,e2') <- inferSub env t e2 w <- newWitness return (Proto (locinfo' l 80 e) env w t (pDiv t') : cs1++cs2, t', eCall (eDot (eVar w) truedivKW) [e1',e2']) | otherwise = do t <- newUnivar env (cs1,e1') <- inferSub env t e1 (cs2,e2') <- inferSub env (rtype op t) e2 w <- newWitness return (Proto (locinfo2 81 e) env w t (protocol op) : cs1++cs2, t, eCall (eDot (eVar w) (method op)) [e1',e2']) where protocol Plus = pPlus protocol Minus = pMinus protocol Pow = pNumber protocol Mod = pIntegral protocol EuDiv = pIntegral protocol ShiftL = pIntegral protocol ShiftR = pIntegral protocol BOr = pLogical protocol BXor = pLogical protocol BAnd = pLogical protocol MMult = pMatrix method Plus = addKW method Minus = subKW method Pow = powKW method Mod = modKW method EuDiv = floordivKW method ShiftL = lshiftKW method ShiftR = rshiftKW method BOr = orKW method BXor = xorKW method BAnd = andKW method MMult = matmulKW rtype ShiftL t = tInt rtype ShiftR t = tInt rtype _ t = t infer env (UnOp l op e) | op == Not = do (cs,_,_,_,e') <- inferTest env e return (cs, tBool, UnOp l op e') | otherwise = do (cs,t,e') <- infer env e w <- newWitness return (Proto (locinfo2 82 e) env w t (protocol op) : cs, t, eCall (eDot (eVar w) (method op)) [e']) where protocol UPlus = pNumber protocol UMinus = pNumber protocol BNot = pIntegral method UPlus = posKW method UMinus = negKW method BNot = invertKW infer env e@(CompOp l e1 [OpArg op e2]) | op `elem` [In,NotIn] = do t1 <- newUnivar env (cs1,e1') <- inferSub env t1 e1 t2 <- newUnivar env (cs2,e2') <- inferSub env t2 e2 w <- newWitness return (Proto (locinfo2 83 e) env w t2 (pContainer t1) : cs1++cs2, tBool, eCall (eDot (eVar w) (method op)) [e2', e1']) | op `elem` [Is,IsNot], e2==eNone = do (cs,_,_,t,e') <- inferTest env e return (cs, t, e') | otherwise = do t <- newUnivar env (cs1,e1') <- inferSub env t e1 (cs2,e2') <- inferSub env t e2 w <- newWitness return (Proto (locinfo' l 84 e) env w t (protocol op) : cs1++cs2, tBool, eCall (eDot (eVar w) (method op)) [e1',e2']) -- TODO: This gives misleading error msg; it says that "e1 op e2 must implement protocol op" where protocol Eq = pEq protocol NEq = pEq protocol LtGt = pEq protocol Lt = pOrd protocol Gt = pOrd protocol LE = pOrd protocol GE = pOrd protocol Is = pIdentity protocol IsNot = pIdentity method Eq = eqKW method NEq = neKW method LtGt = neKW method Lt = ltKW method Gt = gtKW method LE = leKW method GE = geKW method Is = isKW method IsNot = isnotKW method In = containsKW method NotIn = containsnotKW infer env (CompOp l e1 ops) = notYet l "Comparison chaining" infer env (Dot l x@(Var _ c) n) | NClass q us te _ <- cinfo = do (cs0,ts) <- instQBinds env q let tc = TC c' ts case findAttr env tc n of Just (_,sc,dec) | dec == Just Property -> err l "Property attribute not selectable by class" | abstractAttr env tc n -> err l "Abstract attribute not selectable by class" | otherwise -> do (cs1,tvs,t) <- instantiate env sc let t' = vsubst [(tvSelf,tCon tc)] $ addSelf t dec csq = if dec == Just Static || n == initKW then cs0 else [] return (csq++cs1, t', app2nd dec t' (tApp (Dot l x n) (ts++tvs)) $ protoWitsOf (csq++cs1)) Nothing -> case findProtoByAttr env c' n of Just p -> do p <- instwildcon env p we <- eVar <$> newWitness let Just (wf,sc,dec) = findAttr env p n (cs2,tvs,t) <- instantiate env sc let t' = vsubst [(tvSelf,tCon tc)] $ addSelf t dec return (cs2, t', app t' (tApp (eDot (wf we) n) tvs) $ protoWitsOf cs2) Nothing -> err1 l "Attribute not found" | NProto q us te _ <- cinfo = do (_,ts) <- instQBinds env q let tc = TC c' ts case findAttr env tc n of Just (wf,sc,dec) -> do (cs1,tvs,t) <- instantiate env sc t0 <- newUnivar env let t' = vsubst [(tvSelf,t0)] $ addSelf t dec w <- newWitness return (Proto (locinfo l 85) env w t0 tc : cs1, t', app t' (tApp (Dot l (wf $ eVar w) n) tvs) $ protoWitsOf cs1) Nothing -> err1 l "Attribute not found" where c' = unalias env c cinfo = findQName c' env infer env (Dot l e n) | n == initKW = err1 n "__init__ cannot be selected by instance" | otherwise = do (cs,t,e') <- infer env e w <- newWitness t0 <- newUnivar env let con = case t of TOpt _ _ -> Sel info env w t n t0 _ -> Sel (locinfo' l 86 e) env w t n t0 info = Simple l (Pretty.print t ++ " does not have an attribute "++ Pretty.print n ++ "\nHint: you may need to test if " ++ Pretty.print e ++ " is not None") return (con : cs, t0, eCall (eVar w) [e']) -- The parser inserts Opt nodes only within OptChain nodes (which each contains exactly one Opt node). -- The Opt nodes are handled and eliminated by infer on an OptChain node. -- e is an atomic expression (atom_expr in the parser) which contains exactly one ? in its sequence of trailers infer env (OptChain l e) = do x <- newTmp -- Example: a s1 s2 ? t1 t2 let (b,e1,e2) = split x e -- e1 = a s1 s2, e2 = x t1 t2 te <- newUnivar env (cs1,e1') <- inferSub env (tOpt te) e1 let env1 = define [(x,NVar te)] env (cs2,t,e2') <- infer env1 e2 y <- newTmp (cs3,t',e3) <- alt t te b return (cs1++cs2++cs3, t', eLet [sAssign (pVar y (tOpt te)) e1'] (eCond (termsubst [(x,eCAST (tOpt te) te (eVar y))] e2') (eCall (tApp (eQVar primISNOTNONE) [te]) [eVar y]) e3)) where split x (Opt l e b) = (b, e, eVar x) split x (Dot l e n) = (b, e1,Dot l e2 n) where (b,e1,e2) = split x e split x (Call l f ps ks) = (b, e1,Call l e2 ps ks) where (b,e1,e2) = split x f split x (Index l e ix) = (b, e1,Index l e2 ix) where (b,e1,e2) = split x e split x (Slice l e sz) = (b, e1,Slice l e2 sz) where (b,e1,e2) = split x e alt t te True = do w <- newWitness w1 <- newWitness t1 <- newUnivar env return ([Sub (noinfo 444) env w tNone t1, Sub (noinfo 555) env w1 t t1],t1,eNone) alt t te False = return ([],t,eCall (tApp (eQVar primRaiseValueError) [te]) [Strings NoLoc ["Forced unwrapping applied to None"]] ) infer env e@(Rest _ _ _) = notYetExpr e -- infer env (Rest l e n) = do p <- newUnivarOfKind PRow env -- k <- newUnivarOfKind KRow env -- t0 <- newUnivar env -- (cs,e') <- inferSub env (tTuple p (kwdRow n t0 k)) e -- return (cs, tTuple p k, Rest l e' n) infer env (DotI l e i) = do (tup,ti,_) <- tupleTemplate env i (cs,e') <- inferSub env tup e return (cs, ti, DotI l e' i) infer env e@(RestI _ _ _) = notYetExpr e -- infer env (RestI l e i) = do (tup,_,rest) <- tupleTemplate env i -- (cs,e') <- inferSub env tup e -- return (cs, rest, RestI l e' i) infer env (Lambda l p k e fx) | nodup (p,k) = do pushFX fx tNone (cs0,te0,p') <- infEnv env1 p (cs1,te1,k') <- infEnv (define te0 env1) k let env2 = define te1 $ define te0 env1 (cs2,t,e') <- case e of Call l' e' ps ks -> inferCall env2 False l' e' ps ks _ -> infer env2 e popFX return (cs0++cs1++cs2, tFun fx (prowOf p') (krowOf k') t, Lambda l (noDefaultsP p') (noDefaultsK k') e' fx) -- TODO: replace defaulted params with Conds where env1 = reserve (bound (p,k)) env infer env e@Yield{} = notYetExpr e infer env e@YieldFrom{} = notYetExpr e infer env (Tuple l pargs kargs) = do (cs1,prow,pargs') <- infer env pargs (cs2,krow,kargs') <- infer env kargs return (cs1++cs2, TTuple l prow krow, Tuple l pargs' kargs') infer env (List l es) = do t0 <- newUnivar env (cs,es') <- infElems env es t0 return (cs, tList t0, List l es') infer env (ListComp l e co) | nodup co = do (cs1,env',s,co') <- infComp env co t0 <- newUnivar env (cs2,es) <- infElems env' [e] t0 let [e'] = es return (cs1++cs2, tList t0, ListComp l (termsubst s e') co') infer env (Set l es) = do t0 <- newUnivar env (cs,es') <- infElems env es t0 w <- newWitness return (Proto (locinfo l 87) env w t0 pHashable : cs, tSet t0, eCall (tApp (eQVar primMkSet) [t0]) [eVar w,Set l es']) infer env (SetComp l e co) | nodup co = do (cs1,env',s,co') <- infComp env co t0 <- newUnivar env (cs2,es) <- infElems env' [e] t0 w <- newWitness let Elem v = head es e' = Elem (annot (tHashableW t0) (eVar w) t0 v) return (Proto (locinfo l 89) env w t0 pHashable : cs1++cs2, tSet t0, SetComp l (termsubst s e') co') infer env (Dict l as) = do tk <- newUnivar env tv <- newUnivar env (cs,as') <- infAssocs env as tk tv w <- newWitness return (Proto (locinfo l 88) env w tk pHashable : cs, tDict tk tv, eCall (tApp (eQVar primMkDict) [tk, tv]) [eVar w,Dict l as']) infer env (DictComp l a co) | nodup co = do (cs1,env',s,co') <- infComp env co tk <- newUnivar env tv <- newUnivar env (cs2,as) <- infAssocs env' [a] tk tv w <- newWitness let Assoc k v = head as a' = Assoc (annot (tHashableW tk) (eVar w) tk k) v return (Proto (locinfo l 90) env w tk pHashable : cs1++cs2, tDict tk tv, DictComp l (termsubst s a') co') infer env (Paren l e) = do (cs,t,e') <- infer env e return (cs, t, Paren l e') inferCall env unwrap l e ps ks = do (cs1,t,e') <- infer env e{eloc = l} (cs1,t,e') <- if unwrap && actorSelf env then wrapped l attrUnwrap env cs1 [t] [e'] else pure (cs1,t,e') (cs2,prow,ps') <- infer env ps (cs3,krow,ks') <- infer env ks t0 <- newUnivar env fx <- currFX w <- newWitness let i = case e of Var _ n@(NoQ n') | NDef sc _ _ <- findQName n env, Just l2 <- findDefLoc n' env -> DeclInfo l l2 n' sc ("Type incompatibility between definition of and call of "++Pretty.print n') _ -> DfltInfo l 837 (Just (Call l e ps ks)) [] return (Sub i env w t (tFun fx prow krow t0) : -- return (Sub (DfltInfo l 837 (Just (Call l e ps ks)) []) w [] t (tFun fx prow krow t0) : cs1++cs2++cs3, t0, Call l (eCall (eVar w) [e']) ps' ks') tupleTemplate env i = do ts <- mapM (const $ newUnivar env) [0..i] -- Handle DotI or RestI... p <- newUnivarOfKind PRow env k <- newUnivarOfKind KRow env let p0 = foldl (flip posRow) p ts p1 = foldl (flip posRow) p (tail ts) return (TTuple NoLoc p0 k, head ts, TTuple NoLoc p1 k) infElems env [] t0 = return ([], []) infElems env (Elem e : es) t0 = do (cs1,e') <- inferSub env t0 e (cs2,es') <- infElems env es t0 return (cs1++cs2, Elem e' : es') infElems env (Star e : es) t0 = do t1 <- newUnivar env (cs1,e') <- inferSub env t1 e (cs2,es') <- infElems env es t0 w <- newWitness return (Proto (locinfo2 89 e) env w t1 (pIterable t0) : cs1++cs2, Star e' : es') infAssocs env [] tk tv = return ([], []) infAssocs env (Assoc k v : as) tk tv = do (cs1,k') <- inferSub env tk k (cs2,v') <- inferSub env tv v (cs3,as') <- infAssocs env as tk tv -- return (cs1++cs2++cs3, Elem (eTuple [k',v']) : as') return (cs1++cs2++cs3, Assoc k' v' : as') infAssocs env (StarStar e : as) tk tv = do t1 <- newUnivar env (cs1,e') <- inferSub env t1 e (cs2,as') <- infAssocs env as tk tv w <- newWitness return (Proto (locinfo2 90 e) env w t1 (pIterable $ tTupleP $ posRow tk $ posRow tv posNil) : -- cs1++cs2, Star e' : as') cs1++cs2, StarStar e' : as') inferTest env (BinOp l e1 And e2) = do (cs1,env1,s1,t1,e1') <- inferTest env e1 (cs2,env2,s2,t2,e2') <- inferTest env1 e2 t <- newUnivar env w1 <- newWitness w2 <- newWitness return (Sub (locinfo' l 91 e1) env w1 t1 t : Sub (locinfo' l 92 e2) env w2 t2 t : cs1++cs2, env2, s1++s2, t, BinOp l (eCall (eVar w1) [e1']) And (eCall (eVar w2) [termsubst s1 e2'])) inferTest env (BinOp l e1 Or e2) = do (cs1,_,_,t1,e1') <- inferTest env e1 (cs2,_,_,t2,e2') <- inferTest env e2 t <- newUnivar env w1 <- newWitness w2 <- newWitness return (Sub (locinfo2 93 e1) env w1 t1 (tOpt t) : Sub (locinfo2 94 e2) env w2 t2 t : cs1++cs2, env, [], t, BinOp l (eCall (eVar w1) [e1']) Or (eCall (eVar w2) [e2'])) inferTest env (UnOp l Not e) = do (cs,_,_,_,e') <- inferTest env e return (cs, env, [], tBool, UnOp l Not e') inferTest env (CompOp l e [OpArg IsNot None{}]) = do t <- newUnivar env (cs1,e1) <- inferSub env (tOpt t) e let e' = eCall (tApp (eQVar primISNOTNONE) [t]) [e1] case e of Var _ (NoQ n) -> return (cs1, define [(n,NVar t)] env, sCast n (tOpt t) t, tBool, e') _ -> return (cs1, env, [], tBool, e') inferTest env (CompOp l e [OpArg Is None{}]) = do t <- newUnivar env (cs1,e') <- inferSub env (tOpt t) e return (cs1, env, [], tBool, eCall (tApp (eQVar primISNONE) [t]) [e']) inferTest env (IsInstance l e@(Var _ (NoQ n)) c) = case findQName c env of NClass q _ _ _ -> do (cs,t,e') <- infer env e ts <- newUnivars env [ tvkind v | v <- qbound q ] let tc = tCon (TC c ts) return (cs, define [(n,NVar tc)] env, sCast n t tc, tBool, IsInstance l e' c) _ -> nameUnexpected c inferTest env (Paren l e) = do (cs,env',s,t,e') <- inferTest env e return (cs, env', s, t, Paren l e') inferTest env e = do (cs,t,e') <- infer env e return (cs, env, [], t, e') sCast n t t' = [(n, eCAST t t' (eVar n))] inferSlice env (Sliz l e1 e2 e3) = do (cs1,e1') <- inferSub env tInt e1 (cs2,e2') <- inferSub env tInt e2 (cs3,e3') <- inferSub env tInt e3 return (cs1++cs2++cs3, Sliz l e1' e2' e3') class InferSub a where inferSub :: Env -> Type -> a -> TypeM (Constraints,a) instance InferSub Expr where inferSub env t e = do (cs,t',e') <- infer env e w <- newWitness return (Sub (locinfo2 96 e) env w t' t : cs, eCall (eVar w) [e']) instance InferSub (Maybe Expr) where inferSub env t Nothing = return ([], Nothing) inferSub env t (Just e) = do (cs,e') <- inferSub env t e return (cs, Just e') instance (Infer a) => Infer (Maybe a) where infer env Nothing = do t <- newUnivar env return ([], t, Nothing) infer env (Just x) = do (cs,t,e') <- infer env x return (cs, t, Just e') instance InfEnv PosPar where infEnv env (PosPar n a Nothing p) = do t <- maybe (newUnivar env) return a wellformed env t let t' = t -- {tloc = loc n} (cs,te,p') <- infEnv (define [(n, NVar t')] env) p return (cs, (n, NVar t'):te, PosPar n (Just t') Nothing p') infEnv env (PosPar n a (Just e) p) = do t <- maybe (newUnivar env) return a wellformed env t (cs1,e') <- inferSub env t e (cs2,te,p') <- infEnv (define [(n, NVar t)] env) p return (cs1++cs2, (n, NVar t):te, PosPar n (Just t) (Just e') p') infEnv env (PosSTAR n a) = do t <- maybe (newUnivar env) return a wellformed env t r <- newUnivarOfKind PRow env return ([Cast (locinfo n 97) env t (tTupleP r)], [(n, NVar t)], PosSTAR n (Just $ tTupleP r)) infEnv env PosNIL = return ([], [], PosNIL) instance InfEnv KwdPar where infEnv env (KwdPar n a Nothing k) = do t <- maybe (newUnivar env) return a wellformed env t (cs,te,k') <- infEnv (define [(n, NVar t)] env) k return (cs, (n, NVar t):te, KwdPar n (Just t) Nothing k') infEnv env (KwdPar n a (Just e) k) = do t <- maybe (newUnivar env) return a wellformed env t (cs1,e') <- inferSub env t e (cs2,te,k') <- infEnv (define [(n, NVar t)] env) k return (cs1++cs2, (n, NVar t):te, KwdPar n (Just t) (Just e') k') infEnv env (KwdSTAR n a) = do t <- maybe (newUnivar env) return a wellformed env t r <- newUnivarOfKind KRow env return ([Cast (locinfo n 98) env t (tTupleK r)], [(n, NVar t)], KwdSTAR n (Just $ tTupleK r)) infEnv env KwdNIL = return ([], [], KwdNIL) --------- instance Infer PosArg where infer env (PosArg e p) = do (cs1,t,e') <- infer env e (cs2,prow,p') <- infer env p return (cs1++cs2, posRow t prow, PosArg e' p') infer env (PosStar e) = do prow <- newUnivarOfKind PRow env (cs,e') <- inferSub env (tTupleP prow) e return (cs, posStar prow, PosStar e') infer env PosNil = return ([], posNil, PosNil) instance Infer KwdArg where infer env (KwdArg n e k) = do (cs1,t,e') <- infer env e (cs2,krow,k') <- infer env k return (cs1++cs2, kwdRow n t krow, KwdArg n e' k') infer env (KwdStar e) = do krow <- newUnivarOfKind KRow env (cs,e') <- inferSub env (tTupleK krow) e return (cs, kwdStar krow, KwdStar e') infer env KwdNil = return ([], kwdNil, KwdNil) infComp env NoComp = return ([], env, [], NoComp) infComp env (CompIf l e c) = do (cs1,env1,s,_,e') <- inferTest env e (cs2,env2,s',c') <- infComp env1 c return (cs1++cs2, env2, s++s', CompIf l e' (termsubst s c')) infComp env (CompFor l p e c) = do (te1,t1,p') <- infEnvT (reserve (bound p) env) p t2 <- newUnivar env (cs2,e') <- inferSub env t2 e (cs3,env',s,c') <- infComp (define te1 env) c w <- newWitness return (Proto (locinfo2 101 e) env w t2 (pIterable t1) : cs2++cs3, env', s, CompFor l p' (eCall (eDot (eVar w) iterKW) [e']) c') instance InfEnvT PosPat where infEnvT env (PosPat p ps) = do (te1,t,p') <- infEnvT env p (te2,r,ps') <- infEnvT env ps return (te1++te2, posRow t r, PosPat p' ps') infEnvT env (PosPatStar p) = do (te,t,p') <- infEnvT env p r <- newUnivarOfKind PRow env tryUnify (locinfo p 102) t (tTupleP r) return (te, posStar r, PosPatStar p') infEnvT env PosPatNil = return ([], posNil, PosPatNil) instance InfEnvT KwdPat where infEnvT env (KwdPat n p ps) = do (te1,t,p') <- infEnvT env p (te2,r,ps') <- infEnvT env ps return (te1++te2, kwdRow n t r, KwdPat n p' ps') infEnvT env (KwdPatStar p) = do (te,t,p') <- infEnvT env p r <- newUnivarOfKind KRow env tryUnify (locinfo p 103) t (tTupleK r) return (te, kwdStar r, KwdPatStar p') infEnvT env KwdPatNil = return ([], kwdNil, KwdPatNil) instance InfEnvT Pattern where infEnvT env (PWild l a) = do t <- maybe (newUnivar env) return a wellformed env t return ([], t, PWild l (Just t)) infEnvT env (PVar l n a) = do t <- maybe (newUnivar env) return a wellformed env t case findName n env of NReserved -> do --traceM ("## infEnvT " ++ prstr n ++ " : " ++ prstr t) return ([(n, NVar t)], t, PVar l n (Just t)) NSig (TSchema _ [] t') _ _ | TFun{} <- t' -> notYet l "Pattern variable with previous function signature" | otherwise -> do --traceM ("## infEnvT (sig) " ++ prstr n ++ " : " ++ prstr t' ++ " < " ++ prstr t) let te = [(n, NVar t')] solveAll env te [Cast (locinfo l 104) env t' t] return (te, t', PVar l n (Just t')) NVar t' | isJust a -> do return ([], t, PVar l n (Just t)) | otherwise -> return ([], t', PVar l n Nothing) NSVar t' -> do fx <- currFX solveAll env [(n,NVar t)] [Cast (locinfo l 106) env fxProc fx, Cast (locinfo l 107) env t t'] return ([], t', PVar l n Nothing) _ -> err1 n "Variable not assignable:" infEnvT env (PTuple l ps ks) = do (te1,prow,ps') <- infEnvT env ps (te2,krow,ks') <- infEnvT env ks return (te1++te2, TTuple NoLoc prow krow, PTuple l ps' ks') infEnvT env (PList l ps p) = do (te1,t1,ps') <- infEnvT env ps (te2,t2,p') <- infEnvT (define te1 env) p tryUnify (locinfo l 108) t2 (tList t1) return (te1++te2, t2, PList l ps' p') infEnvT env (PParen l p) = do (te,t,p') <- infEnvT env p return (te, t, PParen l p') infEnvT env (PData l n es) = notYet l "data syntax" instance InfEnvT (Maybe Pattern) where infEnvT env Nothing = do t <- newUnivar env return ([], t, Nothing) infEnvT env (Just p) = do (te,t,p') <- infEnvT env p return (te, t, Just p') instance InfEnvT [Pattern] where infEnvT env [p] = do (te1,t1,p') <- infEnvT env p return (te1,t1,[p']) infEnvT env (p:ps) = do (te1,t1,p') <- infEnvT env p (te2,t2,ps') <- infEnvT env ps tryUnify (locinfo p 109) t1 t2 return (te1++te2, t1, p':ps') -- Test discovery -------------------------------------------------------------- tEnv = tCon (TC (gname [name "__builtin__"] (name "Env")) []) emptyDict = Dict NoLoc [] testDicts = [ ("__unit_tests", "UnitTest"), ("__simple_sync_tests", "SimpleSyncTest"), ("__sync_tests", "SyncTest"), ("__async_tests", "AsyncTest"), ("__env_tests", "EnvTest") ] testStmts env m ss = (stmts, tests) where assocs = testFuns (define te env) m (ss++ss') (te, ss') = genTestActorWrappers ss stmts = ss' ++ [ dictAssign n cl assoc | ((n,cl), assoc) <- testDicts `zip` assocs ] ++ [ testActor ] tests = sort (nub (concatMap assocNames assocs)) assocNames assocList = mapMaybe assocName assocList assocName (Assoc (Strings _ ssParts) _) = Just (concat ssParts) assocName _ = Nothing testEnv = [ (name n, NVar (tDict tStr (testing cl))) | (n,cl) <- testDicts ] ++ [ (name "test_main", NAct [] posNil (kwdRow (name "env") tEnv kwdNil) [] Nothing) ] gname ns n = GName (ModName ns) n dername a b = Derived (name a) (name b) dictAssign dictname cl dict = sAssign (pVar (name dictname) (tDict tStr (testing cl))) (mkDict cl dict) testing tstr = tCon (TC (gname [name "testing"] (name tstr)) []) mkDict cl as = eCall (tApp (eQVar primMkDict) [tStr, testing cl]) [w,Dict NoLoc as] where w = eCall (eQVar (gname [name "__builtin__"] (dername "Hashable" "str"))) [] testActor = sDecl [Actor NoLoc (name "test_main") [] PosNIL (KwdPar (name "env") (Just tEnv) Nothing KwdNIL) [sExpr (eCall (eQVar (gname [name "testing"] (name "test_runner"))) (map (eVar . name) ["env","__unit_tests","__simple_sync_tests","__sync_tests","__async_tests","__env_tests"]))] Nothing] row2list (TRow _ _ _ t r) = t : row2list r row2list (TNil _ _) = [] mkAssoc d testType modName = Assoc (Strings NoLoc [nstr (dname d)]) (eCall (eQVar (gname [name "testing"] testType)) [ eVar (dname d) , Strings NoLoc [nstr (dname d)] , comment (dbody d) , Strings NoLoc [modName] ]) where comment (Expr _ s@(Strings _ ss) : _) = s comment _ = Strings NoLoc [""] mkAssocActor (Actor _ n _ _ _ body _) testType modName = Assoc (Strings NoLoc [nstr n]) (eCall (eQVar (gname [name "testing"] testType)) [ eVar n , Strings NoLoc [nstr n] , comment body , Strings NoLoc [modName] ]) where comment (Expr _ s@(Strings _ ss) : _) = s comment _ = Strings NoLoc [""] testFuns :: Env0 -> String -> Suite -> [[Assoc]] testFuns env modName ss = tF ss [] [] [] [] [] where tF (With _ _ ss' : ss) uts ssts sts ats ets = tF (ss' ++ ss) uts ssts sts ats ets tF (Decl l (d@Def{}:ds) : ss) uts ssts sts ats ets | isTestName (dname d) = case testType (findQName (NoQ (dname d)) env) of Just UnitTest -> tF (Decl l ds : ss) (mkAssoc d (name "UnitTest") modName : uts) ssts sts ats ets Just SimpleSyncTest -> tF (Decl l ds : ss) uts (mkAssoc d (name "SimpleSyncTest") modName : ssts) sts ats ets Just SyncTest -> tF (Decl l ds : ss) uts ssts (mkAssoc d (name "SyncTest") modName : sts) ats ets Just AsyncTest -> tF (Decl l ds : ss) uts ssts sts (mkAssoc d (name "AsyncTest") modName : ats) ets Just EnvTest -> tF (Decl l ds : ss) uts ssts sts ats (mkAssoc d (name "EnvTest") modName : ets) Nothing -> tF (Decl l ds : ss) uts ssts sts ats ets -- Don't discover actors here - they're handled via wrapper generation tF (Decl l (_:ds) : ss) uts ssts sts ats ets = tF (Decl l ds : ss) uts ssts sts ats ets tF (Decl _ [] : ss) uts ssts sts ats ets = tF ss uts ssts sts ats ets tF (_ : ss) uts ssts sts ats ets = tF ss uts ssts sts ats ets tF [] uts ssts sts ats ets = [reverse uts, reverse ssts, reverse sts, reverse ats, reverse ets] isTestName n = take 6 (nstr n) == "_test_" -- Generate wrapper functions for test actors genTestActorWrappers :: Suite -> (TEnv, Suite) genTestActorWrappers ss = let testActors = findTestActors ss existingFunctions = collectFunctionNames ss wrappers = mapMaybe (genWrapper existingFunctions) testActors in unzip wrappers where -- Find actors that are test actors (either with testing params or _test_ prefix) findTestActors :: Suite -> [Decl] findTestActors = go [] where go actors [] = actors go actors (Decl _ ds : rest) = go (actors ++ filter isTestActor ds) rest go actors (With _ [] ss : rest) = go actors (ss ++ rest) go actors (_ : rest) = go actors rest isTestActor (Actor _ n _ ppar kpar _ _) = checkTestActorParams ppar kpar || (isTestName n && ppar == PosNIL && kpar == KwdNIL) isTestActor _ = False checkTestActorParams PosNIL (KwdPar _ (Just t) _ KwdNIL) = t == tCon (TC (gname [name "testing"] (name "SyncT")) []) || t == tCon (TC (gname [name "testing"] (name "AsyncT")) []) || t == tCon (TC (gname [name "testing"] (name "EnvT")) []) checkTestActorParams (PosPar _ (Just t) _ PosNIL) KwdNIL = t == tCon (TC (gname [name "testing"] (name "SyncT")) []) || t == tCon (TC (gname [name "testing"] (name "AsyncT")) []) || t == tCon (TC (gname [name "testing"] (name "EnvT")) []) checkTestActorParams _ _ = False -- Collect all function names to check for conflicts collectFunctionNames :: Suite -> [Name] collectFunctionNames = go [] where go names [] = names go names (Decl _ ds : rest) = go (names ++ mapMaybe getFuncName ds) rest go names (_ : rest) = go names rest getFuncName (Def _ n _ _ _ _ _ _ _ _) = Just n getFuncName _ = Nothing -- Generate a wrapper function for a test actor if needed genWrapper :: [Name] -> Decl -> Maybe ((Name,NameInfo), Stmt) genWrapper existingFuncs (Actor _ actorName _ ppar kpar _ _) = let tParam = name "t" paramType = getActorParamType ppar kpar -- actor Foo(t: testing.AsyncT) -> _test_Foo -- actor _test_Foo(t: testing.AsyncT) -> _test_Foo_wrapper wrapperName = if "_test_" `isPrefixOf` nstr actorName then name (nstr actorName ++ "_wrapper") else name ("_test_" ++ nstr actorName) checkName = case paramType of Nothing | isTestName actorName && ppar == PosNIL && kpar == KwdNIL -> name (nstr actorName ++ "_wrapper") _ -> wrapperName in if checkName `elem` existingFuncs then Nothing -- Wrapper / test function already exists, don't generate else case paramType of Just pType -> Just $ ((wrapperName, NDef (monotype $ tFun fxProc (posRow pType posNil) kwdNil tNone) NoDec Nothing), sDecl [Def NoLoc wrapperName [] -- Wrapper function with positional param (PosPar tParam (Just pType) Nothing PosNIL) KwdNIL (Just (TNone NoLoc)) [Expr NoLoc (eCall (eVar actorName) [eVar tParam])] -- Call original actor, passing parameters NoDec fxProc Nothing]) Nothing -> -- SimpleSyncTest actor - no parameters if isTestName actorName && ppar == PosNIL && kpar == KwdNIL then Just $ ((wrapperName, NDef (monotype $ tFun fxProc posNil kwdNil tNone) NoDec Nothing), sDecl [Def NoLoc wrapperName [] PosNIL KwdNIL (Just (TNone NoLoc)) [Expr NoLoc (eCall (eVar actorName) [])] -- Call original actor NoDec fxProc Nothing]) else Nothing genWrapper _ _ = Nothing -- Get the parameter type from actor parameters getActorParamType PosNIL (KwdPar _ (Just t) _ KwdNIL) = Just t getActorParamType (PosPar _ (Just t) _ PosNIL) KwdNIL = Just t getActorParamType _ _ = Nothing data TestType = UnitTest | SimpleSyncTest | SyncTest | AsyncTest | EnvTest deriving (Eq,Show,Read) -- Determine test type based on function signature testType (NDef (TSchema _ [] (TFun _ fx ppar kpar res)) _ _) = case (res, fx, row2list ppar, row2list kpar) of -- Functions with no parameters (r, fx', [], []) | validReturn r && (fx' == fxPure || fx' == fxMut) -> Just UnitTest (r, fx', [], []) | validReturn r && fx' == fxProc -> Just SimpleSyncTest -- Functions with positional test parameters (r, fx', [t], []) | t == syncT && validReturn r -> Just SyncTest (r, fx', [t], []) | t == asyncT && validReturn r -> Just AsyncTest (r, fx', [t], []) | t == envT && validReturn r -> Just EnvTest -- Functions with keyword test parameters (r, fx', [], [t]) | t == syncT && validReturn r -> Just SyncTest _ -> Nothing where validReturn r = r == tNone || r == TNone NoLoc || r == tStr syncT = tCon (TC (gname [name "testing"] (name "SyncT")) []) asyncT = tCon (TC (gname [name "testing"] (name "AsyncT")) []) envT = tCon (TC (gname [name "testing"] (name "EnvT")) []) testType _ = Nothing ================================================ FILE: compiler/lib/src/Acton/WitKnots.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} module Acton.WitKnots(tieWitKnots) where import Control.Monad import Data.List (nub, intersect,intersperse, isPrefixOf, partition) import Data.Maybe (isJust,mapMaybe) import Pretty import Debug.Trace import Utils import Acton.Syntax import Acton.Names import Acton.Builtin import Acton.Prim import Acton.NameInfo import Acton.Env import Acton.Subst import Acton.Transform import Acton.TypeEnv import Prelude hiding ((<>)) tieWitKnots te (Decl l ds : ss) = return (te', Decl l ds' : ss) where (te',ds') = tieDeclKnots te ds tieWitKnots te (With _ [] b : ss) = tieWitKnots te (b ++ ss) tieWitKnots te (s : ss) = do (te', ss') <- tieWitKnots te ss return (te', s:ss') tieWitKnots te [] = return (te, []) tieDeclKnots te ds | null ws = (te, ds) | null wdeps = (te, ds) | null cycles = (te, ds) | null cycledeps = (te, ds) | not $ null insts = error ("INTERNAL: #### Witness cycles with instantiations, not yet handled:\n" ++ render (nest 4 $ vcat $ map pretty insts)) | otherwise = do --trace ("#### Local witness deps:\n" ++ render (nest 4 $ vcat $ map pretty wdeps)) $ --trace ("#### Chains:\n" ++ render (nest 4 $ vcat $ map pretty wchains)) $ --trace ("#### Cycles:\n" ++ render (nest 4 $ vcat $ map pretty cycles)) $ --trace ("#### Cycle dependencies:\n" ++ render (nest 4 $ vcat $ map pretty cycledeps )) $ let ds' = map (tieknots cycledeps) ds te' = map (addopts cycledeps) te (te', ds') where ws = [ n | (n,NExt{}) <- te ] wexts = [ d | d <- ds, dname d `elem` ws ] wdeps = map (witDeps ws) wexts wchains = [ ch | dep <- wdeps, ch <- witChains wdeps (absToApp dep) ] (cycles, insts) = collect [] [] wchains cycledeps = analyze ws cycles data WAbs = WAbs [TVar] [Name] [WApp] deriving Eq data WApp = WApp Name [Type] [Expr] deriving Eq type WChain = [WApp] type Cut = (Name, [Name]) instance Pretty (Name, WAbs) where pretty (w, WAbs tvs ps as) = pretty w <> pretty_q <> parens (commaSep pretty ps) <+> text "-->" <+> commaSep pretty as where pretty_q = if null tvs then empty else text "@" <> brackets (commaSep pretty tvs) instance Pretty WApp where pretty (WApp n ts es) = pretty n <> pretty_ts <> parens (commaSep pretty es) where pretty_ts = if null ts then empty else text "@" <> brackets (commaSep pretty ts) instance Pretty WChain where pretty chain = pr chain where pr [wa] = pretty wa pr (wa : was) = pretty wa <+> text " - - > " <+> pr was instance Pretty Cut where pretty (hd, deps) = pretty hd <+> text "<--" <+> commaSep pretty deps initMeth d = head [ m | Decl _ ms <- dbody d, m <- ms, dname m == initKW ] witDeps ws d = (w, WAbs tvs ps as) where w = dname d as = nub $ [ wapp | Assign _ [PVar _ _ (Just t)] e <- dbody d, Just wapp <- [witCall ws t e] ] ps = tail $ bound $ pos $ initMeth d tvs = qbound $ qbinds d witCall ws t e@Call{} | Var _ (NoQ n) <- fun e, n `elem` ws = Just (WApp n [] $ arglist (pargs e)) | TApp _ f tvs <- fun e, Var _ (NoQ n) <- f, n `elem` ws = Just (WApp n tvs $ arglist (pargs e)) where arglist (PosArg e p) = e : arglist p arglist _ = [] witCall ws t _ = Nothing absToApp (w, (WAbs tvs ps _)) = WApp w (map tVar tvs) (map eVar ps) witChains deps a@(WApp w ts es) | null deps0 = [[a]] | otherwise = [ a : as' | a' <- as, as' <- witChains deps1 (apply a') ] where (deps0, deps1) = partition ((==w) . fst) deps WAbs vs ps as = snd $ head deps0 s0 = vs `zip` ts s1 = ps `zip` es apply (WApp n ts es) = WApp n (vsubst s0 ts) (termsubst s1 es) collect cycles insts [] = (reverse cycles, reverse insts) collect cycles insts (chain : chains) | length chain <= 1 = collect cycles insts chains | a_0 == a_n = collect (chain:cycles) insts chains -- New unique cycle | appname a_0 == appname a_n = collect cycles (chain:insts) chains -- Instantiated cycle | otherwise = collect cycles insts chains where a_0 = head chain a_n = last chain appname (WApp n _ _) = n analyze ws chains = [ (n, chainOrigins n) | n <- ws ] where bare = map (map appname) chains chainLinks n = nub [ ap | hd:tl <- bare, hd == n, ap <- init tl ] -- Intuitive... chainOrigins n = nub [ hd | hd:tl <- bare, hd /= n, n `elem` tl ] -- Works better as long as we're ignoring cyclic instantiations -- Now, for each declaration dec in ds: -- Let me = dname(dec) -- Let mydeps = depsof(me) -- For all d in mydeps: -- append W_d : ?d[Xs] to the parameters of __init__, where Xs are dec's generics -- For each top level assignment v : t = d@[ts](es) in dec: -- If d is me and me is in cyclic: -- Replace rhs with W_self -- Else: -- For each x in depsof(d), append to the rhs arguments: -- W_self if x is me -- W_x if x is in mydeps -- None otherwise -- if d is in mydeps: -- Prefix the rhs with W_d if W_d is not None else ... depsof w cycledeps = case lookup w cycledeps of Just deps -> deps _ -> [] addopts cycledeps (n, NExt q c us te _ doc) = --trace ("#### Extending " ++ prstr n ++ " with opts " ++ prstrs opts) $ (n, NExt q c us te opts doc) where opts = depsof n cycledeps addopts cycledeps ni = ni tieknots cycledeps dec = dec{ dbody = map tie (dbody dec) } where me = dname dec mydeps = depsof me cycledeps generics = qbound (qbinds dec) cyclic = (`elem` (dom cycledeps)) tie (Decl l ds) = Decl l (map tieI ds) tie s@Assign{} = s{ expr = tieE (expr s) } tie s = s tieI d@Def{} | dname d == initKW = d{ pos = ap (pos d) } where ap (PosPar n t e p) = PosPar n t e (ap p) ap (PosNIL) = foldr depParam PosNIL mydeps tieI d = d tieE e@Call{fun=Var _ (NoQ n)} = tieCall n e tieE e@Call{fun=TApp _ (Var _ (NoQ n)) _} = tieCall n e tieE e = e tieCall n e@Call{} | n == me && cyclic me = eVar selfKW' | n `elem` mydeps = depKnot n e' | otherwise = e' where e' = e{ pargs = ap (pargs e)} ap (PosArg e p) = PosArg e (ap p) ap (PosNil) = foldr extra PosNil (depsof n cycledeps) extra x | x == me = PosArg (eVar selfKW') | x `elem` mydeps = PosArg (eVar $ depVar x) | otherwise = PosArg eNone tieCall n e = e depVar n = witAttr (NoQ n) depType n = tCon (TC (NoQ n) (map tVar generics)) depParam n = PosPar n' (Just $ tOpt t) Nothing where t = depType n n' = depVar n depKnot n = eCond (eCAST (tOpt t) t $ eVar n') (eCall (tApp (eQVar primISNOTNONE) [t]) [eVar n']) where t = depType n n' = depVar n ================================================ FILE: compiler/lib/src/InterfaceFiles.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE DeriveGeneric #-} -- Acton Interface (.ty) Files -- -- Purpose -- - Cache compiled module information so later builds can avoid unnecessary -- work by reading a small header instead of decoding large structures. -- - If a .ty cannot be decoded or the version mismatches, the caller must -- treat the module as out-of-date and recompile from source. -- -- On-disk layout (Binary, in this exact order) -- 1) version :: [Int] -- Acton.Syntax.version -- 2) sourceMeta :: Maybe SourceFileMeta -- cached source stat metadata -- 3) moduleSrcBytesHash :: ByteString -- SHA-256 of raw source bytes -- 4) modulePubHash :: ByteString -- SHA-256 of public NameInfo (doc-free) -- -- augmented with imports' pub hashes -- 5) moduleImplHash :: ByteString -- SHA-256 of per-name impl hashes -- 6) imports :: [(A.ModName, ByteString)] -- imported module and pub hash used -- 7) nameHashes :: [NameHashInfo] -- per-name src/pub/impl hashes + deps -- 8) roots :: [A.Name] -- root actors (e.g., main or test_main) -- 9) tests :: [String] -- discovered test names -- 10) docstring :: Maybe String -- module docstring -- 11) nameInfo :: I.NameInfo -- type/name environment -- 12) typedModule :: A.Module -- typed module -- -- Rationale for ordering -- - Put cache validity fields first so callers can validate and reuse a cache -- entry without decoding the large NameInfo and typed Module sections. -- - Follow with the remaining module hashes used for dependency checks. -- - Follow with small variable fields (imports, roots, docstring). -- - Put heavy sections last (NameInfo, typed Module) to preserve laziness. module InterfaceFiles where import Prelude hiding (readFile, writeFile) import Data.Binary import qualified Control.Exception as E import qualified Data.Binary.Get as BinaryGet import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BL import qualified Acton.Syntax as A import qualified Acton.NameInfo as I import GHC.Generics (Generic) import System.Directory (renameFile) import System.IO (IOMode(ReadMode), hClose, hFileSize, openBinaryFile) import System.Posix.Process (getProcessID) data NameHashInfo = NameHashInfo { nhName :: A.Name , nhSrcHash :: BS.ByteString , nhPubHash :: BS.ByteString , nhImplHash :: BS.ByteString , nhPubDeps :: [(A.QName, BS.ByteString)] , nhImplDeps :: [(A.QName, BS.ByteString)] } deriving (Show, Eq, Generic) instance Binary NameHashInfo data SourceFileMeta = SourceFileMeta { sfmMTimeNs :: Integer , sfmCTimeNs :: Integer , sfmSize :: Integer , sfmDevice :: Maybe Integer , sfmInode :: Maybe Integer } deriving (Show, Eq, Generic) instance Binary SourceFileMeta type TyFile = ( [A.ModName] , I.NameInfo , A.Module , Maybe SourceFileMeta , BS.ByteString , BS.ByteString , BS.ByteString , [(A.ModName, BS.ByteString)] , [NameHashInfo] , [A.Name] , [String] , Maybe String ) type TyHeader = ( Maybe SourceFileMeta , BS.ByteString , BS.ByteString , BS.ByteString , [(A.ModName, BS.ByteString)] , [NameHashInfo] , [A.Name] , [String] , Maybe String ) -- Note: tests are stored in the header to support listing without compiling -- or executing test binaries. readTyBytes :: FilePath -> IO BL.ByteString readTyBytes f = do h <- openBinaryFile f ReadMode size <- hFileSize h bs <- BS.hGet h (fromIntegral size) hClose h return (BL.fromStrict bs) versionMismatch :: [Int] -> IO a versionMismatch vs = ioError (userError (".ty version mismatch: file has " ++ show vs ++ ", expected " ++ show A.version)) readTyVersion :: BL.ByteString -> IO BL.ByteString readTyVersion bsLazy = case BinaryGet.runGetOrFail (get :: BinaryGet.Get [Int]) bsLazy of Left _ -> ioError (userError "Failed to decode .ty version") Right (rest, _, vs) | vs == A.version -> return rest | otherwise -> versionMismatch vs decodeTyPrefix :: BL.ByteString -> IO (Maybe SourceFileMeta, BS.ByteString, BS.ByteString, BS.ByteString, BL.ByteString) decodeTyPrefix bsLazy = case BinaryGet.runGetOrFail getPrefix bsLazy of Left _ -> ioError (userError "Failed to decode .ty prefix") Right (rest, _, (sourceMeta, moduleSrcBytesHash, modulePubHash, moduleImplHash)) -> return (sourceMeta, moduleSrcBytesHash, modulePubHash, moduleImplHash, rest) where getPrefix = do sourceMeta <- get :: BinaryGet.Get (Maybe SourceFileMeta) moduleSrcBytesHash <- get :: BinaryGet.Get BS.ByteString modulePubHash <- get :: BinaryGet.Get BS.ByteString moduleImplHash <- get :: BinaryGet.Get BS.ByteString return (sourceMeta, moduleSrcBytesHash, modulePubHash, moduleImplHash) writeFile :: FilePath -> BS.ByteString -> BS.ByteString -> BS.ByteString -> Maybe SourceFileMeta -> [(A.ModName, BS.ByteString)] -> [NameHashInfo] -> [A.Name] -> [String] -> Maybe String -> I.NameInfo -> A.Module -> IO () writeFile f moduleSrcBytesHash modulePubHash moduleImplHash sourceMeta imps nameHashes roots tests mdoc nmod tchecked = do pid <- getProcessID let tmpFile = f ++ "." ++ show pid BL.writeFile tmpFile (encode ((A.version, sourceMeta, moduleSrcBytesHash, modulePubHash, moduleImplHash), imps, nameHashes, roots, tests, mdoc, nmod, tchecked)) renameFile tmpFile f readFile :: FilePath -> IO TyFile readFile f = do bsLazy <- readTyBytes f body0 <- readTyVersion bsLazy (sourceMeta, moduleSrcBytesHash, modulePubHash, moduleImplHash, body1) <- decodeTyPrefix body0 let getBody = do imps <- get :: BinaryGet.Get [(A.ModName, BS.ByteString)] nameHashes <- get :: BinaryGet.Get [NameHashInfo] roots <- get :: BinaryGet.Get [A.Name] tests <- get :: BinaryGet.Get [String] mdoc <- get :: BinaryGet.Get (Maybe String) nmod <- get :: BinaryGet.Get I.NameInfo tmod <- get :: BinaryGet.Get A.Module return (imps, nameHashes, roots, tests, mdoc, nmod, tmod) case BinaryGet.runGetOrFail getBody body1 of Left _ -> ioError (userError "Failed to decode .ty file") Right (_, _, (imps, nameHashes, roots, tests, mdoc, nmod, tmod)) -> return (map fst imps, nmod, tmod, sourceMeta, moduleSrcBytesHash, modulePubHash, moduleImplHash, imps, nameHashes, roots, tests, mdoc) -- Read only the cached header fields from .ty: source metadata, module hashes, -- imports, name hashes, roots, tests, and docstring. -- This avoids decoding the large NameInfo and typed Module sections and is -- much faster than readFile for freshness checks and dependency discovery. readHeader :: FilePath -> IO TyHeader readHeader f = do bsLazy <- readTyBytes f body0 <- readTyVersion bsLazy (sourceMeta, moduleSrcBytesHash, modulePubHash, moduleImplHash, body1) <- decodeTyPrefix body0 let getHdr = do imps <- get :: BinaryGet.Get [(A.ModName, BS.ByteString)] nameHashes <- get :: BinaryGet.Get [NameHashInfo] roots <- get :: BinaryGet.Get [A.Name] tests <- get :: BinaryGet.Get [String] doc <- get :: BinaryGet.Get (Maybe String) return (imps, nameHashes, roots, tests, doc) case BinaryGet.runGetOrFail getHdr body1 of Left _ -> ioError (userError "Failed to decode .ty header") Right (_, _, (imps, nameHashes, roots, tests, doc)) -> return (sourceMeta, moduleSrcBytesHash, modulePubHash, moduleImplHash, imps, nameHashes, roots, tests, doc) -- Interface files are caches for most callers. If a file is missing, -- unreadable, corrupt, or from a different compiler interface version, the -- cache entry is not usable. readFileMaybe :: FilePath -> IO (Maybe TyFile) readFileMaybe = readTyMaybe readFile readHeaderMaybe :: FilePath -> IO (Maybe TyHeader) readHeaderMaybe = readTyMaybe readHeader readTyMaybe :: (FilePath -> IO a) -> FilePath -> IO (Maybe a) readTyMaybe readTy f = (Just <$> readTy f) `E.catch` tyCacheMiss tyCacheMiss :: E.IOException -> IO (Maybe a) tyCacheMiss _ = return Nothing ================================================ FILE: compiler/lib/src/Pretty.hs ================================================ {-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} ----------------------------------------------------------------------------- -- | -- Module : Language.Python.Common.Pretty -- Copyright : (c) 2009 Bernie Pope -- License : BSD-style -- Maintainer : bjpop@csse.unimelb.edu.au -- Stability : experimental -- Portability : ghc -- -- Convenience class for pretty printing combinators. ----------------------------------------------------------------------------- module Pretty (module TextPP, module Pretty) where import Text.PrettyPrint as TextPP -------------------------------------------------------------------------------- infixl 5 $++$ a $++$ b = a $+$ blank $+$ b print x = render $ pretty x vprint x = render $ vpretty x vpretty x = vcat $ punctuate (text "\n") $ map pretty x -- | All types which can be transformed into a 'Doc'. class Pretty a where pretty :: a -> Doc -- | Transform values into strings. prettyText :: Pretty a => a -> String prettyText = render . pretty -- | Print just the prefix of something prettyPrefix :: Pretty a => Int -> a -> Doc prettyPrefix maxLen x | length fullText <= maxLen = pretty fullText | otherwise = pretty (take maxLen fullText) <+> text "..." where fullText = prettyText x instance Pretty String where pretty s = text s {- This is not used in Acton compiler, so we reuse the name for the following function, which we have use for. -- | Conditionally wrap parentheses around an item. parensIf :: Pretty a => (a -> Bool) -> a -> Doc parensIf test x = if test x then parens $ pretty x else pretty x -} parensIf :: Bool -> Doc -> Doc parensIf b e = if b then parens e else e perhaps :: Pretty a => Maybe a -> Doc -> Doc perhaps Nothing doc = empty perhaps (Just {}) doc = doc dot = char '.' blank = text "" -- | A list of things separated by dots (and no spaces). dotCat :: (a -> Doc) -> [a] -> Doc dotCat f = hcat . punctuate dot . map f -- | A list of things separated by commas. commaSep :: (a -> Doc) -> [a] -> Doc commaSep f = hsep . punctuate comma . map f commaCat :: Pretty a => [a] -> Doc commaCat = hcat . punctuate comma . map pretty commaList :: Pretty a => [a] -> Doc commaList = commaSep pretty commaIf :: [a] -> Doc commaIf [] = empty commaIf _ = comma -- | A list of things separated by equals signs. equalsList :: Pretty a => [a] -> Doc equalsList = hsep . punctuate (space TextPP.<> equals) . map pretty vmap :: (a -> Doc) -> [a] -> Doc vmap f = vcat . map f nonEmpty :: (Doc -> Doc) -> (t -> Doc) -> t -> Doc nonEmpty f g x | isEmpty doc = doc | otherwise = f doc where doc = g x prettyPair :: (Pretty a, Pretty b) => String -> (a, b) -> Doc prettyPair str (a, b) = pretty a <+> nonEmpty (text str <+>) pretty b instance Pretty Int where pretty = int instance Pretty Integer where pretty = integer instance Pretty Double where pretty = double instance Pretty Bool where pretty True = text "True" pretty False = text "False" instance Pretty a => Pretty (Maybe a) where pretty Nothing = empty pretty (Just x) = pretty x ================================================ FILE: compiler/lib/src/SrcLocation.hs ================================================ {-# LANGUAGE DeriveDataTypeable, DeriveGeneric #-} ----------------------------------------------------------------------------- -- | -- Module : Language.Python.Common.SrcLocation -- Copyright : (c) 2009 Bernie Pope -- License : BSD-style -- Maintainer : bjpop@csse.unimelb.edu.au -- Stability : experimental -- Portability : ghc -- -- Source location information for the Python lexer and parser. This module -- provides single-point locations and spans, and conversions between them. ----------------------------------------------------------------------------- module SrcLocation ( -- * Construction SrcLocation (..), SrcSpan (..), Span (..), spanning, (><), mkSrcSpan, combineSrcSpans, initialSrcLocation, spanStartPoint, -- * Modification incColumn, decColumn, incLine, incTab, -- * Projection of components of a span spanFile, endCol, endRow, startCol, startRow, showLine ) where import Pretty import Data.Data import Debug.Trace import qualified Data.Binary import GHC.Generics (Generic) import Prelude hiding((<>)) -- | A location for a syntactic entity from the source code. -- The location is specified by its filename, and starting row -- and column. data SrcLocation = Sloc { sloc_filename :: !String , sloc_row :: {-# UNPACK #-} !Int , sloc_column :: {-# UNPACK #-} !Int } | NoLocation deriving (Eq,Ord,Show,Typeable,Data) instance Pretty SrcLocation where pretty = pretty . getSpan -- | Types which have a span. class Span a where getSpan :: a -> SrcSpan getSpan x = SpanEmpty -- | Create a new span which encloses two spanned things. spanning :: (Span a, Span b) => a -> b -> SrcSpan spanning x y = combineSrcSpans (getSpan x) (getSpan y) infixr 7 >< (><) :: (Span a, Span b) => a -> b -> SrcSpan a >< b = spanning a b instance Span a => Span [a] where getSpan [] = SpanEmpty getSpan [x] = getSpan x getSpan list@(x:xs) = combineSrcSpans (getSpan x) (getSpan (last list)) instance Span a => Span (Maybe a) where getSpan Nothing = SpanEmpty getSpan (Just x) = getSpan x instance (Span a, Span b) => Span (Either a b) where getSpan (Left x) = getSpan x getSpan (Right x) = getSpan x instance (Span a, Span b) => Span (a, b) where getSpan (x,y) = spanning x y instance Span SrcSpan where getSpan = id -- | Construct the initial source location for a file. initialSrcLocation :: String -> SrcLocation initialSrcLocation filename = Sloc { sloc_filename = filename , sloc_row = 1 , sloc_column = 1 } -- | Decrement the column of a location, only if they are on the same row. decColumn :: Int -> SrcLocation -> SrcLocation decColumn n loc | n < col = loc { sloc_column = col - n } | otherwise = loc where col = sloc_column loc -- | Increment the column of a location. incColumn :: Int -> SrcLocation -> SrcLocation incColumn n loc@(Sloc { sloc_column = col }) = loc { sloc_column = col + n } -- | Increment the column of a location by one tab stop. incTab :: SrcLocation -> SrcLocation incTab loc@(Sloc { sloc_column = col }) = loc { sloc_column = newCol } where newCol = col + 8 - (col - 1) `mod` 8 -- | Increment the line number (row) of a location by one. incLine :: Int -> SrcLocation -> SrcLocation incLine n loc@(Sloc { sloc_row = row }) = loc { sloc_column = 1, sloc_row = row + n } {- Inspired heavily by compiler/basicTypes/SrcLoc.lhs A SrcSpan delimits a portion of a text file. -} -- | Source location spanning a contiguous section of a file. data SrcSpan -- | A span which starts and ends on the same line. = SpanCoLinear { span_filename :: !String , span_row :: {-# UNPACK #-} !Int , span_start_column :: {-# UNPACK #-} !Int , span_end_column :: {-# UNPACK #-} !Int } -- | A span which starts and ends on different lines. | SpanMultiLine { span_filename :: !String , span_start_row :: {-# UNPACK #-} !Int , span_start_column :: {-# UNPACK #-} !Int , span_end_row :: {-# UNPACK #-} !Int , span_end_column :: {-# UNPACK #-} !Int } -- | A span which is actually just one point in the file. | SpanPoint { span_filename :: !String , span_row :: {-# UNPACK #-} !Int , span_column :: {-# UNPACK #-} !Int } -- | No span information. | SpanNested { span_outer :: !SrcSpan , span_inner :: !SrcSpan } | SpanEmpty deriving (Eq,Ord,Typeable,Data,Read,Show,Generic) instance Data.Binary.Binary SrcSpan {- instance Show SrcSpan where show _ = "_" instance Read SrcSpan where readsPrec p (' ':s) = readsPrec p s readsPrec p ('\t':s) = readsPrec p s readsPrec p ('\n':s) = readsPrec p s readsPrec _ ('_':s) = [(SpanEmpty,s)] readsPrec _ s = [] -} instance Pretty SrcSpan where pretty span@(SpanCoLinear {}) = prettyMultiSpan span pretty span@(SpanMultiLine {}) = prettyMultiSpan span pretty span@(SpanPoint {}) = text (span_filename span) <> colon <+> parens (pretty (span_row span) <> comma <> pretty (span_column span)) pretty SpanNested{span_outer=o, span_inner=i} = pretty o <+> text "referencing" $$ pretty i pretty SpanEmpty = empty prettyMultiSpan :: SrcSpan -> Doc prettyMultiSpan span = text (spanFile span) <> colon <+> parens (pretty (startRow span) <> comma <> pretty (startCol span)) <> char '-' <> parens (pretty (endRow span) <> comma <> pretty (endCol span)) instance Span SrcLocation where getSpan loc@(Sloc {}) = SpanPoint { span_filename = sloc_filename loc , span_row = sloc_row loc , span_column = sloc_column loc } getSpan NoLocation = SpanEmpty -- | Make a point span from the start of a span spanStartPoint :: SrcSpan -> SrcSpan spanStartPoint SpanEmpty = SpanEmpty spanStartPoint span = SpanPoint { span_filename = spanFile span , span_row = startRow span , span_column = startCol span } -- | Make a span from two locations. Assumption: either the -- arguments are the same, or the left one preceeds the right one. mkSrcSpan :: SrcLocation -> SrcLocation -> SrcSpan mkSrcSpan NoLocation _ = SpanEmpty mkSrcSpan _ NoLocation = SpanEmpty mkSrcSpan loc1 loc2 | line1 == line2 = if col2 <= col1 then SpanPoint file line1 col1 else SpanCoLinear file line1 col1 col2 | otherwise = SpanMultiLine file line1 col1 line2 col2 where line1 = sloc_row loc1 line2 = sloc_row loc2 col1 = sloc_column loc1 col2 = sloc_column loc2 file = sloc_filename loc1 -- | Combines two 'SrcSpan' into one that spans at least all the characters -- within both spans. Assumes the "file" part is the same in both inputs combineSrcSpans :: SrcSpan -> SrcSpan -> SrcSpan combineSrcSpans SpanEmpty r = r -- this seems more useful combineSrcSpans l SpanEmpty = l combineSrcSpans (SpanNested o1 i1) (SpanNested o2 i2) | o1 == o2 = SpanNested o1 (combineSrcSpans i1 i2) combineSrcSpans (SpanNested o i) r = combineSrcSpans i r combineSrcSpans l (SpanNested o i) = combineSrcSpans l i combineSrcSpans start end = case row1 `compare` row2 of EQ -> case col1 `compare` col2 of EQ -> SpanPoint file row1 col1 LT -> SpanCoLinear file row1 col1 col2 GT -> SpanCoLinear file row1 col2 col1 LT -> SpanMultiLine file row1 col1 row2 col2 GT -> SpanMultiLine file row2 col2 row1 col1 where row1 = startRow start col1 = startCol start row2 = endRow end col2 = endCol end file = spanFile start spanFile :: SrcSpan -> String spanFile (SpanNested o i) = spanFile o spanFile SpanEmpty = error "spanFile called on empty span" spanFile sp = span_filename sp -- | Get the row of the start of a span. startRow :: SrcSpan -> Int startRow (SpanCoLinear { span_row = row }) = row startRow (SpanMultiLine { span_start_row = row }) = row startRow (SpanPoint { span_row = row }) = row startRow (SpanNested o i) = startRow o startRow SpanEmpty = error "startRow called on empty span" -- | Get the row of the end of a span. endRow :: SrcSpan -> Int endRow (SpanCoLinear { span_row = row }) = row endRow (SpanMultiLine { span_end_row = row }) = row endRow (SpanPoint { span_row = row }) = row endRow (SpanNested o i) = endRow o endRow SpanEmpty = error "endRow called on empty span" -- | Get the column of the start of a span. startCol :: SrcSpan -> Int startCol (SpanCoLinear { span_start_column = col }) = col startCol (SpanMultiLine { span_start_column = col }) = col startCol (SpanPoint { span_column = col }) = col startCol (SpanNested o i) = startCol o startCol SpanEmpty = error "startCol called on empty span" -- | Get the column of the end of a span. endCol :: SrcSpan -> Int endCol (SpanCoLinear { span_end_column = col }) = col endCol (SpanMultiLine { span_end_column = col }) = col endCol (SpanPoint { span_column = col }) = col endCol (SpanNested o i) = endCol o endCol SpanEmpty = error "endCol called on empty span" showLine :: SrcSpan -> String showLine (SpanNested o i) = showLine o ++ "->" ++ showLine i showLine l = show (startRow l) ================================================ FILE: compiler/lib/src/Text_Megaparsec_Expr.hs ================================================ -- | -- Module : Text.Megaparsec.Expr -- Copyright : © 2015–2017 Megaparsec contributors -- © 2007 Paolo Martini -- © 1999–2001 Daan Leijen -- License : FreeBSD -- -- Maintainer : Mark Karpov -- Stability : experimental -- Portability : non-portable -- -- A helper module to parse expressions. It can build a parser given a table -- of operators. module Text_Megaparsec_Expr ( Operator (..) , makeExprParser ) where import Text.Megaparsec -- | This data type specifies operators that work on values of type @a@. An -- operator is either binary infix or unary prefix or postfix. A binary -- operator has also an associated associativity. data Operator m a = InfixN (m (a -> a -> a)) -- ^ Non-associative infix | InfixL (m (a -> a -> a)) -- ^ Left-associative infix | InfixR (m (a -> a -> a)) -- ^ Right-associative infix | Prefix (m (a -> a)) -- ^ Prefix | Postfix (m (a -> a)) -- ^ Postfix -- | @'makeExprParser' term table@ builds an expression parser for terms -- @term@ with operators from @table@, taking the associativity and -- precedence specified in the @table@ into account. -- -- @table@ is a list of @[Operator m a]@ lists. The list is ordered in -- descending precedence. All operators in one list have the same precedence -- (but may have different associativity). -- -- Prefix and postfix operators of the same precedence associate to the left -- (i.e. if @++@ is postfix increment, than @-2++@ equals @-1@, not @-3@). -- -- Unary operators of the same precedence can only occur once (i.e. @--2@ is -- not allowed if @-@ is prefix negate). If you need to parse several prefix -- or postfix operators in a row, (like C pointers—@**i@) you can use this -- approach: -- -- > manyUnaryOp = foldr1 (.) <$> some singleUnaryOp -- -- This is not done by default because in some cases allowing repeating -- prefix or postfix operators is not desirable. -- -- If you want to have an operator that is a prefix of another operator in -- the table, use the following (or similar) wrapper instead of plain -- 'Text.Megaparsec.Char.Lexer.symbol': -- -- > op n = (lexeme . try) (string n <* notFollowedBy punctuationChar) -- -- 'makeExprParser' takes care of all the complexity involved in building an -- expression parser. Here is an example of an expression parser that -- handles prefix signs, postfix increment and basic arithmetic: -- -- > expr = makeExprParser term table "expression" -- > -- > term = parens expr <|> integer "term" -- > -- > table = [ [ prefix "-" negate -- > , prefix "+" id ] -- > , [ postfix "++" (+1) ] -- > , [ binary "*" (*) -- > , binary "/" div ] -- > , [ binary "+" (+) -- > , binary "-" (-) ] ] -- > -- > binary name f = InfixL (f <$ symbol name) -- > prefix name f = Prefix (f <$ symbol name) -- > postfix name f = Postfix (f <$ symbol name) makeExprParser :: MonadParsec e s m => m a -- ^ Term parser -> [[Operator m a]] -- ^ Operator table, see 'Operator' -> m a -- ^ Resulting expression parser makeExprParser = foldl addPrecLevel {-# INLINEABLE makeExprParser #-} -- | @addPrecLevel p ops@ adds the ability to parse operators in table @ops@ -- to parser @p@. addPrecLevel :: MonadParsec e s m => m a -> [Operator m a] -> m a addPrecLevel term ops = term' >>= \x -> choice [ras' x, las' x, nas' x, return x] "operator" where (ras, las, nas, prefix, postfix) = foldr splitOp ([],[],[],[],[]) ops term' = pTerm (choice prefix) term (choice postfix) ras' = pInfixR (choice ras) term' las' = pInfixL (choice las) term' nas' = pInfixN (choice nas) term' -- | @pTerm prefix term postfix@ parses a @term@ surrounded by optional -- prefix and postfix unary operators. Parsers @prefix@ and @postfix@ are -- allowed to fail, in this case 'id' is used. pTerm :: MonadParsec e s m => m (a -> a) -> m a -> m (a -> a) -> m a pTerm prefix term postfix = do pre <- option id (hidden prefix) x <- term post <- option id (hidden postfix) return . post . pre $ x -- | @pInfixN op p x@ parses non-associative infix operator @op@, then term -- with parser @p@, then returns result of the operator application on @x@ -- and the term. pInfixN :: MonadParsec e s m => m (a -> a -> a) -> m a -> a -> m a pInfixN op p x = do f <- op y <- p return $ f x y "operator" -- | @pInfixL op p x@ parses left-associative infix operator @op@, then term -- with parser @p@, then returns result of the operator application on @x@ -- and the term. pInfixL :: MonadParsec e s m => m (a -> a -> a) -> m a -> a -> m a pInfixL op p x = do f <- op y <- p let r = f x y pInfixL op p r <|> return r "operator" -- | @pInfixR op p x@ parses right-associative infix operator @op@, then -- term with parser @p@, then returns result of the operator application on -- @x@ and the term. pInfixR :: MonadParsec e s m => m (a -> a -> a) -> m a -> a -> m a pInfixR op p x = do f <- op y <- p >>= \r -> pInfixR op p r <|> return r return $ f x y "operator" type Batch m a = ( [m (a -> a -> a)] , [m (a -> a -> a)] , [m (a -> a -> a)] , [m (a -> a)] , [m (a -> a)] ) -- | A helper to separate various operators (binary, unary, and according to -- associativity) and return them in a tuple. splitOp :: Operator m a -> Batch m a -> Batch m a splitOp (InfixR op) (r, l, n, pre, post) = (op:r, l, n, pre, post) splitOp (InfixL op) (r, l, n, pre, post) = (r, op:l, n, pre, post) splitOp (InfixN op) (r, l, n, pre, post) = (r, l, op:n, pre, post) splitOp (Prefix op) (r, l, n, pre, post) = (r, l, n, op:pre, post) splitOp (Postfix op) (r, l, n, pre, post) = (r, l, n, pre, op:post) ================================================ FILE: compiler/lib/src/Utils.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE DeriveDataTypeable, DeriveGeneric, DeriveAnyClass #-} module Utils(module Utils, module SrcLocation, module Data.List, module Data.Maybe, module Debug.Trace) where import Debug.Trace import Data.List hiding ((\\)) import Data.Maybe import qualified Data.Binary import qualified Control.Exception import Data.Typeable import GHC.Generics (Generic) import SrcLocation import Pretty import Control.DeepSeq import Prelude hiding((<>)) import System.Directory (renameFile, removeFile) import System.FilePath (takeDirectory, takeFileName) import System.IO (openTempFile, hSetEncoding, utf8, hPutStr, hClose) import System.IO.Error (catchIOError) data SrcLoc = Loc Int Int | NoLoc deriving (Eq,Ord,Show,Read,Generic,NFData) instance Data.Binary.Binary SrcLoc where put NoLoc = Data.Binary.put False put (Loc l r) = Data.Binary.put True >> Data.Binary.put l >> Data.Binary.put r get = do hasLoc <- Data.Binary.get if hasLoc then Loc <$> Data.Binary.get <*> Data.Binary.get else return NoLoc instance Pretty SrcLoc where pretty (Loc l r) = pretty l <> text "-" <> pretty r pretty NoLoc = text "??" Loc i _ `upto` Loc _ j = Loc i j NoLoc `upto` l = l l `upto` NoLoc = l locAfter (Loc _ j) = Loc j j getLoc [] = NoLoc getLoc (NoLoc : ls) = getLoc ls getLoc (l : _) = l class HasLoc a where loc :: a -> SrcLoc instance HasLoc SrcLoc where loc = id instance HasLoc a => HasLoc [a] where loc = foldl (\l x -> l `upto` loc x) NoLoc instance HasLoc a => HasLoc (Maybe a) where loc = maybe NoLoc loc instance (HasLoc a, HasLoc b) => HasLoc (a,b) where loc (a,b) = loc a `upto` loc b xs \\ ys = [ x | x <- xs, x `notElem` ys ] -- remove *all* occurrences of xs elements from ys duplicates [] = [] duplicates (x:xs) = eqs ++ duplicates others where (eqs,others) = partition (==x) xs dom = map fst rng = map snd kvs `exclude` ks = filter ((`notElem` ks) . fst) kvs kvs `restrict` ks = filter ((`elem` ks) . fst) kvs mapFst f xs = [ (f a, b) | (a,b) <- xs ] mapSnd f xs = [ (a, f b) | (a,b) <- xs ] catLeft xs = [ x | Left x <- xs ] catRight xs = [ x | Right x <- xs ] l0 = NoLoc ignore t = return () prstr x = render (pretty x) prstrs xs = render (hsep $ punctuate comma (map pretty xs)) prcat xs = render (vcat $ (map pretty xs)) traceF f x = trace (f x) x tr s f x = trace (s ++ ": " ++ prstr x) $ f x ptrace doc = trace (render doc) ptraceM doc = traceM (render doc) ptraceF f = traceF (render . f) head_ tag [] = error ("Prelude.head: empty list (" ++ show tag ++ ")") head_ tag xs = head xs errSep = '\n' : concat (replicate 40 "- ") ++ "\n" errReport ((SpanCoLinear file row start end,msg) : ps) src = unlines ["",line2,line3,line4,msg] ++ errReport ps src where rowstr = show row --line1 = file ++ " "++show row++":"++show start++"-"++show end line2 = replicate (length rowstr+1) ' '++"|" line3 = rowstr ++ " |" ++ lines(src)!!!(row-1) line4 = replicate (length rowstr+1) ' '++"|"++replicate (start-1) ' '++replicate (end-start+1) '^' errReport ((SpanMultiLine file srow scol erow ecol,msg) : ps) src = unlines (line2:quote++(if erow-srow<=2 then [] else [replicate (length erowstr) ' ' ++ " | ..."])++[line2,msg]) ++ errReport ps src where erowstr = show erow --line1 = file ++ " "++show srow++":"++show scol++"-"++show erow++":"++show ecol line2 = replicate (length erowstr+1) ' '++"|" pad n = replicate (length erowstr - length nstr) ' ' ++ nstr where nstr = show n quote = map line [srow..minimum [srow+2,erow,length ls]] ls = lines src line n = pad n ++ " |" ++ ls!!!(n-1) errReport ((SpanPoint file row col,msg) : ps) src = unlines [line2,line3,line4,msg] ++ errReport ps src where rowstr = show row --line1 = file ++ " "++show row++":"++show col line2 = replicate (length rowstr+1) ' '++"|" line3 = rowstr ++ " |" ++ lines src!!!(row-1) line4 = replicate (length rowstr+1) ' '++"|"++replicate (col-1) ' '++"^" errReport ((SpanEmpty,msg) : ps) src = '\n' : msg ++ errReport ps src errReport [] _ = errSep lst !!! ix | ix >= length lst = lst !! 0 | otherwise = lst !! ix --------------------------------- data GeneralError = InternalErr SrcLoc Doc | NotYet SrcLoc Doc deriving (Eq,Show,Typeable) instance Control.Exception.Exception GeneralError instance HasLoc GeneralError where loc (InternalErr l doc) = l loc (NotYet l doc) = l internal loc x = Control.Exception.throw $ InternalErr loc (pretty x) notYet loc x = Control.Exception.throw $ NotYet loc (pretty x) generalError err = [(loc err,render (expl err))] where expl (InternalErr _ doc) = text "(internal)" <+> doc expl (NotYet _ doc) = text "Not yet supported:" <+> doc iff True m = m >> return () iff False _ = return () -- | Write a UTF-8 text file atomically (temp file + rename). -- Keeps readers from observing partial writes of generated artifacts. writeFileUtf8Atomic :: FilePath -> String -> IO () writeFileUtf8Atomic path contents = Control.Exception.bracketOnError (openTempFile dir template) (\(tmp, h) -> do catchIOError (hClose h) (\_ -> return ()) catchIOError (removeFile tmp) (\_ -> return ())) (\(tmp, h) -> do hSetEncoding h utf8 hPutStr h contents hClose h renameFile tmp path) where dir = takeDirectory path template = takeFileName path ++ ".tmp" ================================================ FILE: compiler/lib/test/1-parse/docstrings.input ================================================ """Test module for docstring functionality with {braces}.""" import math def test_function (x : int) -> int: """Test function with docstring.""" return x * 2 def no_docstring_function (x : int) -> int: return x * 3 # recursive group: class TestClass: """Test class with docstring.""" def method (self, x : int) -> int: return x + 1 actor TestActor (name : str): """Test actor with docstring.""" var name = name protocol TestProtocol: """Test protocol with docstring.""" test_method : (int) -> int extension TestClass (TestProtocol): """Extension with docstring.""" def test_method (self, x : int) -> int: return x * 10 # (recursive group) def function_with_non_first_string (x : int) -> int: y = x + 1 "Not a docstring" return y def function_with_multiple_strings (x : int) -> int: """First string is docstring.""" "Second string is not" return x def function_with_f_prefix_docstring () -> int: "Not a docstring %s" % str(1) return 1 def function_with_single_quotes (x : int) -> int: """Single quote docstring""" return x def function_with_triple_single_quotes (x : int) -> int: """Triple quote docstring""" return x def function_with_mixed_quotes (x : int) -> int: """Mixed 'quotes' in docstring""" return x def function_with_braces_docstring (): """Docstring with {braces} should not interpolate.""" pass def function_empty_docstring (): """""" pass def function_with_control_flow (): if True: "Not a docstring" return 42 def function_just_docstring (): """Just a docstring, no code.""" ================================================ FILE: compiler/lib/test/1-parse/docstrings.output ================================================ """Test module for docstring functionality with {braces}.""" import math def test_function (x : int) -> int: """Test function with docstring.""" return x * 2 def no_docstring_function (x : int) -> int: return x * 3 # recursive group: class TestClass: """Test class with docstring.""" def method (self, x : int) -> int: return x + 1 actor TestActor (name : str): """Test actor with docstring.""" var name = name protocol TestProtocol: """Test protocol with docstring.""" test_method : (int) -> int extension TestClass (TestProtocol): """Extension with docstring.""" def test_method (self, x : int) -> int: return x * 10 # (recursive group) def function_with_non_first_string (x : int) -> int: y = x + 1 "Not a docstring" return y def function_with_multiple_strings (x : int) -> int: """First string is docstring.""" "Second string is not" return x def function_with_f_prefix_docstring () -> int: "Not a docstring %s" % str(1) return 1 def function_with_single_quotes (x : int) -> int: """Single quote docstring""" return x def function_with_triple_single_quotes (x : int) -> int: """Triple quote docstring""" return x def function_with_mixed_quotes (x : int) -> int: """Mixed 'quotes' in docstring""" return x def function_with_braces_docstring (): """Docstring with {braces} should not interpolate.""" pass def function_empty_docstring (): """""" pass def function_with_control_flow (): if True: "Not a docstring" return 42 def function_just_docstring (): """Just a docstring, no code.""" ================================================ FILE: compiler/lib/test/1-parse/syntax1.input ================================================ """Module docstring for syntax1 test. This tests docstring support across all language constructs. """ import net def add (x : int, y : int) -> int: """Add two numbers together. This function takes two integers and returns their sum. """ def foo (): """A nested function that does nothing.""" pass return x + y # recursive group: class Calculator: """A calculator class with basic operations. This class provides methods for arithmetic operations. """ def multiply (self, x : int, y : int) -> int: """Multiply two numbers. Args: x: First number y: Second number Returns: The product of x and y """ return x * y def divide (self, x : int, y : int) -> float: """Divide x by y.""" return float(x) / float(y) actor Counter (name : str): """An actor that counts things. This actor maintains a count and can increment it. """ var count = 0 var name = name def increment (): """Increment the counter by one.""" count += 1 def get_count () -> int: """Get the current count value.""" return count protocol Drawable: """Protocol for objects that can be drawn. Any class implementing this protocol must provide a draw method. """ draw : () -> None get_color : () -> str extension Calculator (Drawable): """Extension to make Calculator drawable. This adds drawing capabilities to the Calculator class. """ def draw (self): """Draw the calculator.""" print("Drawing a calculator") def get_color (self) -> str: """Get the calculator's color.""" return "black" # (recursive group) def subtract (x : int, y : int) -> int: return x - y def outer_function (x : int) -> int: """Outer function with a nested function inside.""" def inner_function (y : int) -> int: """Inner function that adds to the outer parameter.""" return x + y return inner_function(10) ================================================ FILE: compiler/lib/test/1-parse/syntax1.output ================================================ """Module docstring for syntax1 test. This tests docstring support across all language constructs. """ import net def add (x : int, y : int) -> int: """Add two numbers together. This function takes two integers and returns their sum. """ def foo (): """A nested function that does nothing.""" pass return x + y # recursive group: class Calculator: """A calculator class with basic operations. This class provides methods for arithmetic operations. """ def multiply (self, x : int, y : int) -> int: """Multiply two numbers. Args: x: First number y: Second number Returns: The product of x and y """ return x * y def divide (self, x : int, y : int) -> float: """Divide x by y.""" return float(x) / float(y) actor Counter (name : str): """An actor that counts things. This actor maintains a count and can increment it. """ var count = 0 var name = name def increment (): """Increment the counter by one.""" count += 1 def get_count () -> int: """Get the current count value.""" return count protocol Drawable: """Protocol for objects that can be drawn. Any class implementing this protocol must provide a draw method. """ draw : () -> None get_color : () -> str extension Calculator (Drawable): """Extension to make Calculator drawable. This adds drawing capabilities to the Calculator class. """ def draw (self): """Draw the calculator.""" print("Drawing a calculator") def get_color (self) -> str: """Get the calculator's color.""" return "black" # (recursive group) def subtract (x : int, y : int) -> int: return x - y def outer_function (x : int) -> int: """Outer function with a nested function inside.""" def inner_function (y : int) -> int: """Inner function that adds to the outer parameter.""" return x + y return inner_function(10) ================================================ FILE: compiler/lib/test/2-kinds/deact.input ================================================ # recursive group: actor Apa (): def setup (cb): print("setup") cb(0) def compute (cb): print("compute") v = cb(1) m = (async cb)(2) return v * 10 def notice (i): print("notice") return i + 1 setup(notice) print("Apa") actor Bepa (): def callback (i): print("callback", i) return i + 1 print("Bepa") actor main (env): def myproc (i): print("myproc", i) if i == 2: env.exit(0) return i a = Apa() b = Bepa() print("-----") a.setup(a.notice) x = (async a.compute)(b.callback) r = await x print("r =", r) a.compute(myproc) print("main") # (recursive group) ================================================ FILE: compiler/lib/test/2-kinds/deact.output ================================================ # recursive group: actor Apa (): T_13w def setup (cb : T_5w) -> T_9w: print("setup") cb(0) T_25w def compute (cb : T_17w) -> T_21w: print("compute") v = cb(1) m = (async cb)(2) return v * 10 T_41w def notice (i : T_33w) -> T_37w: print("notice") return i + 1 setup(notice) print("Apa") actor Bepa (): T_53w def callback (i : T_45w) -> T_49w: print("callback", i) return i + 1 print("Bepa") actor main (env : T_57w): T_69w def myproc (i : T_61w) -> T_65w: print("myproc", i) if i == 2: env.exit(0) return i a = Apa() b = Bepa() print("-----") a.setup(a.notice) x = (async a.compute)(b.callback) r = await x print("r =", r) a.compute(myproc) print("main") # (recursive group) ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_assert_uninit_attr.golden ================================================ [error Type error]: Attribute 'result' is not initialized in TestClass.__init__ +--> uninit_assert_uninit_attr.act@6:5-14:1 | 2 | class TestClass(object): : ^----------------------- : `- In class TestClass : 4 | result: int : ^----- : `- Attribute 'result' is defined here : 6 | +> def __init__(self, x: int): 7 | | self.value = x 8 | | 9 | | # Assert that references uninitialized self.result - should fail! 10 | | assert self.result > 0, "result must be positive" 11 | | 12 | | # This should NOT be recognized as initialized 13 | | self.result = 42 14 | |> : | : `- Attribute 'result' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_augmented_assign.golden ================================================ [error Type error]: Attribute 'x' is not initialized in TestClass.__init__ +--> uninit_augmented_assign.act@4:5-5:1 | 1 | class TestClass(object): : ^----------------------- : `- In class TestClass 2 | x: int : ^ : `- Attribute 'x' is defined here : 4 | +> def __init__(self): 5 | |> self.x += 1 # Should fail - x not initialized before augmented assignment : | : `- Attribute 'x' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_basic.golden ================================================ [error Type error]: Attribute 'x' is not initialized in TestClass.__init__ +--> uninit_basic.act@3:5-5:1 | 1 | class TestClass(object): : ^----------------------- : `- In class TestClass 2 | x: int : ^ : `- Attribute 'x' is defined here 3 | +> def __init__(self): 4 | | pass 5 | |> : | : `- Attribute 'x' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_basic_inferred.golden ================================================ [error Type error]: Attribute 'x' is not initialized in TestClass.__init__ +--> uninit_basic_inferred.act@2:5-5:1 | 1 | class TestClass(object): : ^----------------------- : `- In class TestClass 2 | +> def __init__(self): 3 | | if False: 4 | | self.x = 1 # Should fail - x not initialized before use : | ^ : | `- Attribute 'x' inferred from use 5 | |> : | : `- Attribute 'x' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_elif_missing.golden ================================================ [error Type error]: Attribute 'x' is not initialized in TestClass.__init__ +--> uninit_elif_missing.act@5:5-11:1 | 2 | class TestClass(object): : ^----------------------- : `- In class TestClass 3 | x: int : ^ : `- Attribute 'x' is defined here : 5 | +> def __init__(self, mode: int): 6 | | if mode == 1: 7 | | self.x = 1 8 | | elif mode == 2: 9 | | self.x = 2 10 | | # No else - x not initialized for other values 11 | |> : | : `- Attribute 'x' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_for_loop.golden ================================================ [error Type error]: Attribute 'y' is not initialized in TestClass.__init__ +--> uninit_for_loop.act@6:5-12:1 | 2 | class TestClass(object): : ^----------------------- : `- In class TestClass : 4 | y: int : ^ : `- Attribute 'y' is defined here : 6 | +> def __init__(self, items: list[int]): 7 | | self.x = 1 8 | | for item in items: 9 | | if item == 0: 10 | | break 11 | | self.y = item # Might not execute if we break early or items is empty 12 | |> : | : `- Attribute 'y' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_grandparent.golden ================================================ [error Type error]: Attribute 'x' is not initialized in TestClass.__init__ +--> uninit_grandparent.act@8:5-10:1 | 1 | class BaseA: : ^----- : `- Attribute inherited from BaseA 2 | x: int : ^ : `- Attribute 'x' is defined here : 7 | class TestClass(BaseB): : ^---------------------- : `- In class TestClass 8 | +> def __init__(self): 9 | | self.y = 1 10 | |> : | : `- Attribute 'x' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_grandparent2.golden ================================================ [error Type error]: Attribute 'y' is not initialized in TestClass.__init__ +--> uninit_grandparent2.act@14:5-17:1 | 6 | class BaseB(BaseA): : ^------------ : `- Attribute inherited from BaseB 7 | y: int : ^ : `- Attribute 'y' is defined here : 13 | class TestClass(BaseB): : ^---------------------- : `- In class TestClass 14 | +> def __init__(self): 15 | | BaseA.__init__(self) 16 | | # Should get a failure since y is not initialized 17 | |> : | : `- Attribute 'y' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_inherited.golden ================================================ [error Type error]: Attribute 'x' is not initialized in TestClass.__init__ +--> uninit_inherited.act@5:5-7:1 | 1 | class Base: : ^---- : `- Attribute inherited from Base 2 | x: int : ^ : `- Attribute 'x' is defined here : 4 | class TestClass(Base): : ^--------------------- : `- In class TestClass 5 | +> def __init__(self): 6 | | pass 7 | |> : | : `- Attribute 'x' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_init_in_method.golden ================================================ [error Type error]: Attribute 'x' is not initialized in TestClass.__init__ +--> uninit_init_in_method.act@6:5-8:5 | 3 | class TestClass(object): : ^----------------------- : `- In class TestClass 4 | x: int : ^ : `- Attribute 'x' is defined here : 6 | +> def __init__(self): 7 | | self.setup() 8 | |> : | : `- Attribute 'x' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_loop_references_self.golden ================================================ [error Type error]: Attribute 'x' is not initialized in TestClass.__init__ +--> uninit_loop_references_self.act@6:5-14:1 | 2 | class TestClass(object): : ^----------------------- : `- In class TestClass 3 | x: int : ^ : `- Attribute 'x' is defined here : 6 | +> def __init__(self): 7 | | # Loop that references self - not safe to continue 8 | | for i in range(10): 9 | | process(self) # Leaks self reference! 10 | | # These assignments are after the loop but we can't reach them 11 | | # because the loop leaked self 12 | | self.x = 1 13 | | self.y = 2 14 | |> : | : `- Attribute 'x' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_method_call.golden ================================================ [error Type error]: Attribute 'y' is not initialized in TestClass.__init__ +--> uninit_method_call.act@10:5-15:5 | 5 | class TestClass(object): : ^----------------------- : `- In class TestClass : 7 | y: int : ^ : `- Attribute 'y' is defined here : 10 | +> def __init__(self): 11 | | self.counter = 0 12 | | self.x = 1 13 | | self.helper() # Method call on self - scanner should stop here 14 | | self.y = 2 # Not reached by scanner 15 | |> : | : `- Attribute 'y' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_method_call_assign.golden ================================================ [error Type error]: Attribute 'pi' is not initialized in TestClass.__init__ +--> uninit_method_call_assign.act@12:5-17:5 | 6 | class TestClass(object): : ^----------------------- : `- In class TestClass 7 | pi: int : ^- : `- Attribute 'pi' is defined here : 12 | +> def __init__(self): 13 | | self.counter = 0 14 | | self.x = 1 15 | | self.pi = self.pure_helper() 16 | | self.y = 2 # Not reached by scanner 17 | |> : | : `- Attribute 'pi' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_method_reference.golden ================================================ [error Type error]: Attribute 'handler' is not initialized in TestClass.__init__ +--> uninit_method_reference.act@12:5-17:5 | 8 | class TestClass(object): : ^----------------------- : `- In class TestClass 9 | handler: Callback : ^------ : `- Attribute 'handler' is defined here : 12 | +> def __init__(self): 13 | | # This should work - we're just passing a method reference 14 | | # But currently the compiler sees self._on_event as leaking self 15 | | self.handler = Callback(self._on_event) 16 | | self.value = 42 # This won't be seen as initialized 17 | |> : | : `- Attribute 'handler' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_nested_function_escape.golden ================================================ [error Type error]: Attribute 'result' is not initialized in TestClass.__init__ +--> uninit_nested_function_escape.act@6:5-18:1 | 2 | class TestClass(object): : ^----------------------- : `- In class TestClass : 4 | result: int : ^----- : `- Attribute 'result' is defined here : 6 | +> def __init__(self, x: int): 7 | | self.value = x 8 | | 9 | | # Nested function that captures self with uninitialized attribute 10 | | def get_result() -> int: 11 | | return self.result # References uninitialized self.result! 12 | | 13 | | # Pass the function externally (self escapes via closure) 14 | | register(get_result) 15 | | 16 | | # This won't be recognized as initialized (self escaped) 17 | | self.result = 42 18 | |> : | : `- Attribute 'result' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_nested_function_with_self.golden ================================================ [error Type error]: Attribute 'result' is not initialized in TestClass.__init__ +--> uninit_nested_function_with_self.act@6:5-16:1 | 2 | class TestClass(object): : ^----------------------- : `- In class TestClass : 4 | result: int : ^----- : `- Attribute 'result' is defined here : 6 | +> def __init__(self, x: int): 7 | | self.value = x 8 | | 9 | | # Nested function that captures self - stops scanning 10 | | def get_value() -> int: 11 | | return self.value # References self (even though value is initialized) 12 | | 13 | | # The nested function captured self, so we conservatively stop scanning 14 | | # This will NOT be seen as initialized 15 | | self.result = 42 16 | |> : | : `- Attribute 'result' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_nested_if.golden ================================================ [error Type error]: Attribute 'y' is not initialized in TestClass.__init__ +--> uninit_nested_if.act@6:5-17:1 | 2 | class TestClass(object): : ^----------------------- : `- In class TestClass : 4 | y: int : ^ : `- Attribute 'y' is defined here : 6 | +> def __init__(self, a: bool, b: bool): 7 | | if a: 8 | | if b: 9 | | self.x = 1 10 | | self.y = 1 11 | | else: 12 | | self.x = 2 13 | | # Missing y in this path 14 | | else: 15 | | self.x = 3 16 | | self.y = 3 17 | |> : | : `- Attribute 'y' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_no_parent_init.golden ================================================ [error Compilation error]: Abstract attribute not selectable by class +--> uninit_no_parent_init.act@6:9-6:28 | 6 | Base.__init__(self) : ^------------------ : `- Abstract attribute not selectable by class -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_notimpl_call_other.golden ================================================ [error Type error]: Attribute 'y' is not initialized in TestClass.__init__ +--> uninit_notimpl_call_other.act@8:5-15:5 | 4 | class TestClass(object): : ^----------------------- : `- In class TestClass : 6 | y: int : ^ : `- Attribute 'y' is defined here : 8 | +> def __init__(self): 9 | | # Calling a NotImplemented method on self should be allowed since it's 10 | | # implemented in C and thus trusted to do the right thing. 11 | | self.setup() 12 | | self.x = 1 13 | | self.setup2() 14 | | self.y = 2 15 | |> : | : `- Attribute 'y' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_partial.golden ================================================ [error Type error]: Attribute 'y' is not initialized in TestClass.__init__ +--> uninit_partial.act@4:5-6:1 | 1 | class TestClass(object): : ^----------------------- : `- In class TestClass : 3 | y: str : ^ : `- Attribute 'y' is defined here 4 | +> def __init__(self): 5 | | self.x = 1 6 | |> : | : `- Attribute 'y' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_return_early.golden ================================================ [error Type error]: Attribute 'y' is not initialized in TestClass.__init__ +--> uninit_return_early.act@6:5-13:1 | 2 | class TestClass(object): : ^----------------------- : `- In class TestClass : 4 | y: int : ^ : `- Attribute 'y' is defined here : 6 | +> def __init__(self, quick_exit: bool): 7 | | if quick_exit: 8 | | self.x = 0 9 | | return # Early return - but y is still uninitialized! 10 | | else: 11 | | self.x = 1 12 | | self.y = 2 13 | |> : | : `- Attribute 'y' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_self_attr_access.golden ================================================ [error Type error]: Attribute 'x' is not initialized in TestClass.__init__ +--> uninit_self_attr_access.act@6:5-9:1 | 2 | class TestClass(object): : ^----------------------- : `- In class TestClass 3 | x: int : ^ : `- Attribute 'x' is defined here : 6 | +> def __init__(self): 7 | | self.x = self.y * 2 # ERROR: y is not initialized yet! 8 | | self.y = 10 9 | |> : | : `- Attribute 'x' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_self_in_list.golden ================================================ [error Type error]: Attribute 'y' is not initialized in TestClass.__init__ +--> uninit_self_in_list.act@10:5-20:1 | 6 | class TestClass(object): : ^----------------------- : `- In class TestClass : 8 | y: int : ^ : `- Attribute 'y' is defined here : 10 | +> def __init__(self): 11 | | self.x = 1 12 | | 13 | | # Direct reference to self - stop scanning here 14 | | # We don't actually know if objects how objects is used or if it even is 15 | | # used, but that is untractable to analyze, so we stop analyzing at any 16 | | # point where self is referenced. 17 | | objects = [self, self] 18 | | # This won't be scanned, so y will be considered uninitialized 19 | | self.y = do_something(objects) 20 | |> : | : `- Attribute 'y' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_self_reference.golden ================================================ [error Type error]: Attribute 'y' is not initialized in TestClass.__init__ +--> uninit_self_reference.act@14:5-23:1 | 9 | class TestClass(object): : ^----------------------- : `- In class TestClass : 11 | y: int : ^ : `- Attribute 'y' is defined here : 14 | +> def __init__(self): 15 | | self.x = 1 16 | | 17 | | # This should stop scanning because we're passing self 18 | | result = external_func(self) 19 | | 20 | | # These won't be scanned, so z will be reported as uninitialized 21 | | self.y = result 22 | | self.z = 3 23 | |> : | : `- Attribute 'y' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/class_init_attrs/uninit_try_except.golden ================================================ [error Type error]: Attribute 'y' is not initialized in TestClass.__init__ +--> uninit_try_except.act@6:5-13:1 | 2 | class TestClass(object): : ^----------------------- : `- In class TestClass : 4 | y: int : ^ : `- Attribute 'y' is defined here : 6 | +> def __init__(self): 7 | | try: 8 | | self.x = risky_operation() 9 | | self.y = 1 10 | | except: 11 | | self.x = 0 12 | | # y not initialized in except block 13 | |> : | : `- Attribute 'y' is not initialized in __init__ -----+ ================================================ FILE: compiler/lib/test/3-types/deact.input ================================================ # recursive group: actor Apa (): T_13w def setup (cb : T_5w) -> T_9w: print("setup") cb(0) T_25w def compute (cb : T_17w) -> T_21w: print("compute") v = cb(1) m = (async cb)(2) return v * 10 T_41w def notice (i : T_33w) -> T_37w: print("notice") return i + 1 setup(notice) print("Apa") actor Bepa (): T_53w def callback (i : T_45w) -> T_49w: print("callback", i) return i + 1 print("Bepa") actor main (env : T_57w): T_69w def myproc (i : T_61w) -> T_65w: print("myproc", i) if i == 2: env.exit(0) return i a = Apa() b = Bepa() print("-----") a.setup(a.notice) x = (async a.compute)(b.callback) r = await x print("r =", r) a.compute(myproc) print("main") # (recursive group) ================================================ FILE: compiler/lib/test/3-types/deact.output ================================================ W_Apa_39: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_140: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_105: __builtin__.Times[__builtin__.int, __builtin__.int] = __builtin__.IntegralD_int() W_Apa_308: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() # recursive group: actor Apa (): proc def setup (cb : action(__builtin__.int) -> __builtin__.int) -> None: print@[(__builtin__.str,)](*("setup",), sep = None, end = None, err = None, flush = None) cb(W_Apa_39.__fromatom__(0)) proc def compute (cb : action(__builtin__.int) -> __builtin__.int) -> __builtin__.int: print@[(__builtin__.str,)](*("compute",), sep = None, end = None, err = None, flush = None) v: __builtin__.int = cb(W_Apa_39.__fromatom__(1)) m: __builtin__.Msg[__builtin__.int] = (async cb)(W_Apa_39.__fromatom__(2)) return W_Apa_105.__mul__(v, W_Apa_39.__fromatom__(10)) proc def notice (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str,)](*("notice",), sep = None, end = None, err = None, flush = None) return W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) setup(cb = action lambda (G_1y : __builtin__.int): $WRAP@[(), (i: __builtin__.int), __builtin__.int](self, notice)(i = G_1y)) print@[(__builtin__.str,)](*("Apa",), sep = None, end = None, err = None, flush = None) actor Bepa (): proc def callback (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str, __builtin__.int)](*("callback", i), sep = None, end = None, err = None, flush = None) return W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) print@[(__builtin__.str,)](*("Bepa",), sep = None, end = None, err = None, flush = None) actor main (env : __builtin__.Env): proc def myproc (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str, __builtin__.int)](*("myproc", i), sep = None, end = None, err = None, flush = None) if W_Apa_308.__eq__(i, W_Apa_39.__fromatom__(2)): env.exit(n = W_Apa_39.__fromatom__(0)) return i a: Apa = Apa() b: Bepa = Bepa() print@[(__builtin__.str,)](*("-----",), sep = None, end = None, err = None, flush = None) a.setup(cb = action lambda (G_1y : __builtin__.int): a.notice(i = G_1y)) x: __builtin__.Msg[__builtin__.int] = (async action lambda (G_1p : action(__builtin__.int) -> __builtin__.int): a.compute(cb = G_1p))(action lambda (G_1y : __builtin__.int): b.callback(i = G_1y)) r: __builtin__.int = await x print@[(__builtin__.str, __builtin__.int)](*("r =", r), sep = None, end = None, err = None, flush = None) a.compute(cb = action lambda (G_1y : __builtin__.int): $WRAP@[(), (i: __builtin__.int), __builtin__.int](self, myproc)(i = G_1y)) print@[(__builtin__.str,)](*("main",), sep = None, end = None, err = None, flush = None) # (recursive group) ================================================ FILE: compiler/lib/test/3-types/test_discovery.input ================================================ import logging import testing actor MathTester (): T_17w def add (a : T_5w, b : T_9w) -> T_13w: return a + b T_21w def _test_foo () -> None: pass # recursive group: actor _test_SimpleSyncTester (): m = MathTester() print("SimpleSyncTester.test()") testing.assertEqual(m.add(1, 2), 3, "1 + 2 = 3") actor _SyncTester (t : testing.SyncT): log = logging.Logger(t.log_handler) m = MathTester() log.info("SyncTester.test()") print("SyncTester.test()") testing.assertEqual(m.add(1, 2), 3, "1 + 2 = 3") actor _SyncTesterCore (): m = MathTester() print("SimpleSyncTester.test()") testing.assertEqual(m.add(1, 2), 3, "1 + 2 = 3") # (recursive group) T_37w def _test_simple_sync () -> T_33w: s = _SyncTesterCore() T_47w def _test_sync (t : testing.SyncT) -> T_43w: m = MathTester() return str(m.add(1, 2)) # recursive group: actor AsyncTester (t : testing.AsyncT): log = logging.Logger(t.log_handler) T_59w def test () -> T_55w: log.info("AsyncTester.test()", {"data": "test"}) t.success() after 0: test() actor EnvTester (t : testing.EnvT): log = logging.Logger(t.log_handler) T_69w def test () -> T_65w: log.info("EnvTester.test() wthreads:", {"nr_wthreads": t.env.nr_wthreads}) print("EnvTester.test() wthreads:", t.env.nr_wthreads) t.success() after 0: test() # (recursive group) ================================================ FILE: compiler/lib/test/3-types/test_discovery.output ================================================ import logging import testing W_MathTester_6: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() actor MathTester (): proc def add (a : __builtin__.int, b : __builtin__.int) -> __builtin__.int: return W_MathTester_6.__add__(a, b) pure def _test_foo () -> None: pass W__test_SimpleSyncTester_268: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W__test_SimpleSyncTester_234: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() # recursive group: actor _test_SimpleSyncTester (): m: MathTester = MathTester() print@[(__builtin__.str,)](*("SimpleSyncTester.test()",), sep = None, end = None, err = None, flush = None) testing.assertEqual@[__builtin__.int](W__test_SimpleSyncTester_234, a = m.add(a = W__test_SimpleSyncTester_268.__fromatom__(1), b = W__test_SimpleSyncTester_268.__fromatom__(2)), b = W__test_SimpleSyncTester_268.__fromatom__(3), msg = "1 + 2 = 3", print_vals = None, print_diff = None) actor _SyncTester (t : testing.SyncT): log: logging.Logger = logging.Logger(handler = t.log_handler) m: MathTester = MathTester() log.info(msg = "SyncTester.test()", data = None) print@[(__builtin__.str,)](*("SyncTester.test()",), sep = None, end = None, err = None, flush = None) testing.assertEqual@[__builtin__.int](W__test_SimpleSyncTester_234, a = m.add(a = W__test_SimpleSyncTester_268.__fromatom__(1), b = W__test_SimpleSyncTester_268.__fromatom__(2)), b = W__test_SimpleSyncTester_268.__fromatom__(3), msg = "1 + 2 = 3", print_vals = None, print_diff = None) actor _SyncTesterCore (): m: MathTester = MathTester() print@[(__builtin__.str,)](*("SimpleSyncTester.test()",), sep = None, end = None, err = None, flush = None) testing.assertEqual@[__builtin__.int](W__test_SimpleSyncTester_234, a = m.add(a = W__test_SimpleSyncTester_268.__fromatom__(1), b = W__test_SimpleSyncTester_268.__fromatom__(2)), b = W__test_SimpleSyncTester_268.__fromatom__(3), msg = "1 + 2 = 3", print_vals = None, print_diff = None) # (recursive group) proc def _test_simple_sync () -> None: s: _SyncTesterCore = _SyncTesterCore() proc def _test_sync (t : testing.SyncT) -> __builtin__.str: W__test_sync_11: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() m: MathTester = MathTester() return str(val = m.add(a = W__test_sync_11.__fromatom__(1), b = W__test_sync_11.__fromatom__(2))) W_AsyncTester_183: __builtin__.Number[__builtin__.float] = __builtin__.RealFloatD_float() W_AsyncTester_125: __builtin__.Hashable[__builtin__.str] = __builtin__.HashableD_str() # recursive group: actor AsyncTester (t : testing.AsyncT): log: logging.Logger = logging.Logger(handler = t.log_handler) proc def test () -> None: log.info(msg = "AsyncTester.test()", data = $mkDict@[__builtin__.str, __builtin__.str](W_AsyncTester_125, {"data": "test"})) t.success(output = None) after W_AsyncTester_183.__fromatom__(0): test() actor EnvTester (t : testing.EnvT): log: logging.Logger = logging.Logger(handler = t.log_handler) proc def test () -> None: log.info(msg = "EnvTester.test() wthreads:", data = $mkDict@[__builtin__.str, __builtin__.int](W_AsyncTester_125, {"nr_wthreads": t.env.nr_wthreads})) print@[(__builtin__.str, __builtin__.int)](*("EnvTester.test() wthreads:", t.env.nr_wthreads), sep = None, end = None, err = None, flush = None) t.success(output = None) after W_AsyncTester_183.__fromatom__(0): test() # (recursive group) proc def _test_SimpleSyncTester_wrapper () -> None: _test_SimpleSyncTester() proc def _test__SyncTester (t : testing.SyncT) -> None: _SyncTester(t) proc def _test_AsyncTester (t : testing.AsyncT) -> None: AsyncTester(t) proc def _test_EnvTester (t : testing.EnvT) -> None: EnvTester(t) __unit_tests: __builtin__.dict[__builtin__.str, testing.UnitTest] = $mkDict@[__builtin__.str, testing.UnitTest](__builtin__.HashableD_str(), {"_test_foo": testing.UnitTest(_test_foo, "_test_foo", "", "test_discovery")}) __simple_sync_tests: __builtin__.dict[__builtin__.str, testing.SimpleSyncTest] = $mkDict@[__builtin__.str, testing.SimpleSyncTest](__builtin__.HashableD_str(), {"_test_simple_sync": testing.SimpleSyncTest(_test_simple_sync, "_test_simple_sync", "", "test_discovery"), "_test_SimpleSyncTester_wrapper": testing.SimpleSyncTest(_test_SimpleSyncTester_wrapper, "_test_SimpleSyncTester_wrapper", "", "test_discovery")}) __sync_tests: __builtin__.dict[__builtin__.str, testing.SyncTest] = $mkDict@[__builtin__.str, testing.SyncTest](__builtin__.HashableD_str(), {"_test_sync": testing.SyncTest(_test_sync, "_test_sync", "", "test_discovery"), "_test__SyncTester": testing.SyncTest(_test__SyncTester, "_test__SyncTester", "", "test_discovery")}) __async_tests: __builtin__.dict[__builtin__.str, testing.AsyncTest] = $mkDict@[__builtin__.str, testing.AsyncTest](__builtin__.HashableD_str(), {"_test_AsyncTester": testing.AsyncTest(_test_AsyncTester, "_test_AsyncTester", "", "test_discovery")}) __env_tests: __builtin__.dict[__builtin__.str, testing.EnvTest] = $mkDict@[__builtin__.str, testing.EnvTest](__builtin__.HashableD_str(), {"_test_EnvTester": testing.EnvTest(_test_EnvTester, "_test_EnvTester", "", "test_discovery")}) actor test_main (env : __builtin__.Env): testing.test_runner(env, __unit_tests, __simple_sync_tests, __sync_tests, __async_tests, __env_tests) ================================================ FILE: compiler/lib/test/4-normalizer/deact.input ================================================ W_Apa_39: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_140: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_105: __builtin__.Times[__builtin__.int, __builtin__.int] = __builtin__.IntegralD_int() W_Apa_308: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() # recursive group: actor Apa (): proc def setup (cb : action(__builtin__.int) -> __builtin__.int) -> None: print@[(__builtin__.str,)](*("setup",), sep = None, end = None, err = None, flush = None) cb(W_Apa_39.__fromatom__(0)) proc def compute (cb : action(__builtin__.int) -> __builtin__.int) -> __builtin__.int: print@[(__builtin__.str,)](*("compute",), sep = None, end = None, err = None, flush = None) v: __builtin__.int = cb(W_Apa_39.__fromatom__(1)) m: __builtin__.Msg[__builtin__.int] = (async cb)(W_Apa_39.__fromatom__(2)) return W_Apa_105.__mul__(v, W_Apa_39.__fromatom__(10)) proc def notice (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str,)](*("notice",), sep = None, end = None, err = None, flush = None) return W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) setup(cb = action lambda (G_1y : __builtin__.int): $WRAP@[(), (i: __builtin__.int), __builtin__.int](self, notice)(i = G_1y)) print@[(__builtin__.str,)](*("Apa",), sep = None, end = None, err = None, flush = None) actor Bepa (): proc def callback (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str, __builtin__.int)](*("callback", i), sep = None, end = None, err = None, flush = None) return W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) print@[(__builtin__.str,)](*("Bepa",), sep = None, end = None, err = None, flush = None) actor main (env : __builtin__.Env): proc def myproc (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str, __builtin__.int)](*("myproc", i), sep = None, end = None, err = None, flush = None) if W_Apa_308.__eq__(i, W_Apa_39.__fromatom__(2)): env.exit(n = W_Apa_39.__fromatom__(0)) return i a: Apa = Apa() b: Bepa = Bepa() print@[(__builtin__.str,)](*("-----",), sep = None, end = None, err = None, flush = None) a.setup(cb = action lambda (G_1y : __builtin__.int): a.notice(i = G_1y)) x: __builtin__.Msg[__builtin__.int] = (async action lambda (G_1p : action(__builtin__.int) -> __builtin__.int): a.compute(cb = G_1p))(action lambda (G_1y : __builtin__.int): b.callback(i = G_1y)) r: __builtin__.int = await x print@[(__builtin__.str, __builtin__.int)](*("r =", r), sep = None, end = None, err = None, flush = None) a.compute(cb = action lambda (G_1y : __builtin__.int): $WRAP@[(), (i: __builtin__.int), __builtin__.int](self, myproc)(i = G_1y)) print@[(__builtin__.str,)](*("main",), sep = None, end = None, err = None, flush = None) # (recursive group) ================================================ FILE: compiler/lib/test/4-normalizer/deact.output ================================================ W_Apa_39: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_140: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_105: __builtin__.Times[__builtin__.int, __builtin__.int] = __builtin__.IntegralD_int() W_Apa_308: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() # recursive group: actor Apa (): proc def setup (cb : action(__builtin__.int) -> __builtin__.int) -> None: print@[(__builtin__.str,)](("\"setup\"",), None, None, None, None) cb(W_Apa_39.__fromatom__(0)) return None proc def compute (cb : action(__builtin__.int) -> __builtin__.int) -> __builtin__.int: print@[(__builtin__.str,)](("\"compute\"",), None, None, None, None) v: __builtin__.int = cb(W_Apa_39.__fromatom__(1)) m: __builtin__.Msg[__builtin__.int] = (async cb)(W_Apa_39.__fromatom__(2)) N_tmp: __builtin__.int = W_Apa_105.__mul__(v, W_Apa_39.__fromatom__(10)) return N_tmp proc def notice (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str,)](("\"notice\"",), None, None, None, None) N_1tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return N_1tmp setup($WRAP@[(), (__builtin__.int,), __builtin__.int](self, notice)) print@[(__builtin__.str,)](("\"Apa\"",), None, None, None, None) actor Bepa (): proc def callback (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str, __builtin__.int)](("\"callback\"", i), None, None, None, None) N_2tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return N_2tmp print@[(__builtin__.str,)](("\"Bepa\"",), None, None, None, None) actor main (env : __builtin__.Env): proc def myproc (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str, __builtin__.int)](("\"myproc\"", i), None, None, None, None) if W_Apa_308.__eq__(i, W_Apa_39.__fromatom__(2)): env.exit(W_Apa_39.__fromatom__(0)) return i a: Apa = Apa() b: Bepa = Bepa() print@[(__builtin__.str,)](("\"-----\"",), None, None, None, None) a.setup(a.notice) x: __builtin__.Msg[__builtin__.int] = (async a.compute)(b.callback) r: __builtin__.int = await x print@[(__builtin__.str, __builtin__.int)](("\"r =\"", r), None, None, None, None) a.compute($WRAP@[(), (__builtin__.int,), __builtin__.int](self, myproc)) print@[(__builtin__.str,)](("\"main\"",), None, None, None, None) # (recursive group) ================================================ FILE: compiler/lib/test/5-deactorizer/deact.input ================================================ W_Apa_39: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_140: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_105: __builtin__.Times[__builtin__.int, __builtin__.int] = __builtin__.IntegralD_int() W_Apa_308: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() # recursive group: actor Apa (): proc def setup (cb : action(__builtin__.int) -> __builtin__.int) -> None: print@[(__builtin__.str,)](("\"setup\"",), None, None, None, None) cb(W_Apa_39.__fromatom__(0)) return None proc def compute (cb : action(__builtin__.int) -> __builtin__.int) -> __builtin__.int: print@[(__builtin__.str,)](("\"compute\"",), None, None, None, None) v: __builtin__.int = cb(W_Apa_39.__fromatom__(1)) m: __builtin__.Msg[__builtin__.int] = (async cb)(W_Apa_39.__fromatom__(2)) N_tmp: __builtin__.int = W_Apa_105.__mul__(v, W_Apa_39.__fromatom__(10)) return N_tmp proc def notice (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str,)](("\"notice\"",), None, None, None, None) N_1tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return N_1tmp setup($WRAP@[(), (__builtin__.int,), __builtin__.int](self, notice)) print@[(__builtin__.str,)](("\"Apa\"",), None, None, None, None) actor Bepa (): proc def callback (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str, __builtin__.int)](("\"callback\"", i), None, None, None, None) N_2tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return N_2tmp print@[(__builtin__.str,)](("\"Bepa\"",), None, None, None, None) actor main (env : __builtin__.Env): proc def myproc (i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str, __builtin__.int)](("\"myproc\"", i), None, None, None, None) if W_Apa_308.__eq__(i, W_Apa_39.__fromatom__(2)): env.exit(W_Apa_39.__fromatom__(0)) return i a: Apa = Apa() b: Bepa = Bepa() print@[(__builtin__.str,)](("\"-----\"",), None, None, None, None) a.setup(a.notice) x: __builtin__.Msg[__builtin__.int] = (async a.compute)(b.callback) r: __builtin__.int = await x print@[(__builtin__.str, __builtin__.int)](("\"r =\"", r), None, None, None, None) a.compute($WRAP@[(), (__builtin__.int,), __builtin__.int](self, myproc)) print@[(__builtin__.str,)](("\"main\"",), None, None, None, None) # (recursive group) ================================================ FILE: compiler/lib/test/5-deactorizer/deact.output ================================================ W_Apa_39: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_140: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_105: __builtin__.Times[__builtin__.int, __builtin__.int] = __builtin__.IntegralD_int() W_Apa_308: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() # recursive group: class Apa ($Actor, __builtin__.value): proc def __init__ (self : Self) -> None: self.setupG_local(self.notice) print@[(__builtin__.str,)](("\"Apa\"",), None, None, None, None) proc def setupG_local (self : Self, cb : action(__builtin__.int) -> __builtin__.int) -> None: print@[(__builtin__.str,)](("\"setup\"",), None, None, None, None) (async cb)(W_Apa_39.__fromatom__(0)) return None proc def computeG_local (self : Self, cb : action(__builtin__.int) -> __builtin__.int) -> __builtin__.int: print@[(__builtin__.str,)](("\"compute\"",), None, None, None, None) v: __builtin__.int = $AWAITf@[__builtin__.int]((async cb)(W_Apa_39.__fromatom__(1))) m: __builtin__.Msg[__builtin__.int] = (async cb)(W_Apa_39.__fromatom__(2)) N_tmp: __builtin__.int = W_Apa_105.__mul__(v, W_Apa_39.__fromatom__(10)) return N_tmp proc def noticeG_local (self : Self, i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str,)](("\"notice\"",), None, None, None, None) N_1tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return N_1tmp action def setup (self : Self, cb : action(__builtin__.int) -> __builtin__.int) -> None: return $ASYNCf@[None](self, proc lambda: self.setupG_local(cb)) action def compute (self : Self, cb : action(__builtin__.int) -> __builtin__.int) -> __builtin__.int: return $ASYNCf@[__builtin__.int](self, proc lambda: self.computeG_local(cb)) action def notice (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNCf@[__builtin__.int](self, proc lambda: self.noticeG_local(i)) class Bepa ($Actor, __builtin__.value): proc def __init__ (self : Self) -> None: print@[(__builtin__.str,)](("\"Bepa\"",), None, None, None, None) proc def callbackG_local (self : Self, i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str, __builtin__.int)](("\"callback\"", i), None, None, None, None) N_2tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return N_2tmp action def callback (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNCf@[__builtin__.int](self, proc lambda: self.callbackG_local(i)) class main ($Actor, __builtin__.value): @property env : __builtin__.Env @property a : Apa @property b : Bepa @property x : __builtin__.Msg[__builtin__.int] @property r : __builtin__.int proc def __init__ (self : Self, env : __builtin__.Env) -> None: self.env = env self.a = ApaG_newact() self.b = BepaG_newact() print@[(__builtin__.str,)](("\"-----\"",), None, None, None, None) (async self.a.setup)(self.a.notice) self.x = (async self.a.compute)(self.b.callback) self.r = $AWAITf@[__builtin__.int](self.x) print@[(__builtin__.str, __builtin__.int)](("\"r =\"", self.r), None, None, None, None) (async self.a.compute)(self.myproc) print@[(__builtin__.str,)](("\"main\"",), None, None, None, None) proc def myprocG_local (self : Self, i : __builtin__.int) -> __builtin__.int: print@[(__builtin__.str, __builtin__.int)](("\"myproc\"", i), None, None, None, None) if W_Apa_308.__eq__(i, W_Apa_39.__fromatom__(2)): (async self.env.exit)(W_Apa_39.__fromatom__(0)) return i action def myproc (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNCf@[__builtin__.int](self, proc lambda: self.myprocG_local(i)) proc def ApaG_newact () -> Apa: G_act: Apa = $NEWACTOR@[Apa]() $InstallFinalizer@[Apa](G_act) $AWAITf@[None]($ASYNCf@[None](G_act, proc lambda: G_act.__init__())) return G_act proc def BepaG_newact () -> Bepa: G_act: Bepa = $NEWACTOR@[Bepa]() $InstallFinalizer@[Bepa](G_act) $AWAITf@[None]($ASYNCf@[None](G_act, proc lambda: G_act.__init__())) return G_act proc def mainG_newact (env : __builtin__.Env) -> main: G_act: main = $NEWACTOR@[main]() $InstallFinalizer@[main](G_act) $AWAITf@[None]($ASYNCf@[None](G_act, proc lambda: G_act.__init__(env))) return G_act # (recursive group) ================================================ FILE: compiler/lib/test/5-deactorizer/deact_from_import.input ================================================ from deact import Apa W_Manager_124: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() # recursive group: actor Manager (): proc def create_decoder () -> __builtin__.StringDecoder: decoder: __builtin__.StringDecoder = StringDecoder(self.decode_callback, None, None) return decoder proc def create_apa () -> deact.Apa: apa: deact.Apa = Apa() return apa proc def decode_callback (s : __builtin__.str) -> None: pass return None actor main (env : __builtin__.Env): mgr: Manager = Manager() decoder: __builtin__.StringDecoder = mgr.create_decoder() apa: deact.Apa = mgr.create_apa() env.exit(W_Manager_124.__fromatom__(0)) # (recursive group) ================================================ FILE: compiler/lib/test/5-deactorizer/deact_from_import.output ================================================ from deact import Apa W_Manager_124: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() # recursive group: class Manager ($Actor, __builtin__.value): proc def __init__ (self : Self) -> None: pass proc def create_decoderG_local (self : Self) -> __builtin__.StringDecoder: decoder: __builtin__.StringDecoder = __builtin__.StringDecoderG_newact(self.decode_callback, None, None) return decoder proc def create_apaG_local (self : Self) -> deact.Apa: apa: deact.Apa = deact.ApaG_newact() return apa proc def decode_callbackG_local (self : Self, s : __builtin__.str) -> None: pass return None action def create_decoder (self : Self) -> __builtin__.StringDecoder: return $ASYNCf@[__builtin__.StringDecoder](self, proc lambda: self.create_decoderG_local()) action def create_apa (self : Self) -> deact.Apa: return $ASYNCf@[deact.Apa](self, proc lambda: self.create_apaG_local()) action def decode_callback (self : Self, s : __builtin__.str) -> None: return $ASYNCf@[None](self, proc lambda: self.decode_callbackG_local(s)) class main ($Actor, __builtin__.value): @property mgr : Manager @property decoder : __builtin__.StringDecoder @property apa : deact.Apa proc def __init__ (self : Self, env : __builtin__.Env) -> None: self.mgr = ManagerG_newact() self.decoder = $AWAITf@[__builtin__.StringDecoder]((async self.mgr.create_decoder)()) self.apa = $AWAITf@[deact.Apa]((async self.mgr.create_apa)()) (async env.exit)(W_Manager_124.__fromatom__(0)) proc def ManagerG_newact () -> Manager: G_act: Manager = $NEWACTOR@[Manager]() $InstallFinalizer@[Manager](G_act) $AWAITf@[None]($ASYNCf@[None](G_act, proc lambda: G_act.__init__())) return G_act proc def mainG_newact (env : __builtin__.Env) -> main: G_act: main = $NEWACTOR@[main]() $InstallFinalizer@[main](G_act) $AWAITf@[None]($ASYNCf@[None](G_act, proc lambda: G_act.__init__(env))) return G_act # (recursive group) ================================================ FILE: compiler/lib/test/6-cps/cps_andor.input ================================================ proc def p () -> __builtin__.bool: return True proc def f (b : __builtin__.bool) -> __builtin__.bool: N_tmp: __builtin__.bool = b and p() return N_tmp proc def g (b : __builtin__.bool) -> __builtin__.bool: N_1tmp: __builtin__.bool = b or p() return N_1tmp ================================================ FILE: compiler/lib/test/6-cps/cps_andor.output ================================================ proc def p (C_cont : proc(__builtin__.bool) -> $R) -> $R: return $R_CONTc@[__builtin__.bool](C_cont, True) proc def f (C_cont : proc(__builtin__.bool) -> $R, b : __builtin__.bool) -> $R: C_2pre: __builtin__.bool = b proc def C_7cont (C_8res : None, C_3pre : __builtin__.bool) -> $R: N_tmp: __builtin__.bool = C_3pre return $R_CONTc@[__builtin__.bool](C_cont, N_tmp) if C_2pre: proc def C_9cont (C_10res : __builtin__.bool) -> $R: C_1pre: __builtin__.bool = C_10res C_3pre: __builtin__.bool = C_1pre return $R_CONTc@[None](proc lambda (G_skip : None): C_7cont(G_skip, C_3pre), None) return p(C_9cont) else: C_3pre: __builtin__.bool = C_2pre return $R_CONTc@[None](proc lambda (G_skip : None): C_7cont(G_skip, C_3pre), None) proc def g (C_cont : proc(__builtin__.bool) -> $R, b : __builtin__.bool) -> $R: C_5pre: __builtin__.bool = b proc def C_11cont (C_12res : None, C_6pre : __builtin__.bool) -> $R: N_1tmp: __builtin__.bool = C_6pre return $R_CONTc@[__builtin__.bool](C_cont, N_1tmp) if C_5pre: C_6pre: __builtin__.bool = C_5pre return $R_CONTc@[None](proc lambda (G_skip : None): C_11cont(G_skip, C_6pre), None) else: proc def C_13cont (C_14res : __builtin__.bool) -> $R: C_4pre: __builtin__.bool = C_14res C_6pre: __builtin__.bool = C_4pre return $R_CONTc@[None](proc lambda (G_skip : None): C_11cont(G_skip, C_6pre), None) return p(C_13cont) ================================================ FILE: compiler/lib/test/6-cps/cps_optchain.input ================================================ class Cls (__builtin__.value): pure def G_init (self : Self) -> None: pass return None proc def f (self : Self, msg : __builtin__.str) -> None: pass return None proc def maybe_log (c : ?Cls) -> None: let: V_maybe_log_9: ?Cls = c in $CAST@[?Cls, Cls](V_maybe_log_9).f("\"boom\"") if $ISNOTNONE@[Cls](V_maybe_log_9) else None return None ================================================ FILE: compiler/lib/test/6-cps/cps_optchain.output ================================================ class Cls (__builtin__.value): pure def G_init (self : Self) -> None: pass return None proc def f (self : Self, C_cont : proc(None) -> $R, msg : __builtin__.str) -> $R: pass return $R_CONTc@[None](C_cont, None) proc def maybe_log (C_cont : proc(None) -> $R, c : ?Cls) -> $R: V_maybe_log_9: ?Cls = c proc def C_3cont (C_4res : None, C_2pre : None) -> $R: C_2pre return $R_CONTc@[None](C_cont, None) if $ISNOTNONE@[Cls](V_maybe_log_9): proc def C_5cont (C_6res : None) -> $R: C_1pre: None = C_6res C_2pre: None = C_1pre return $R_CONTc@[None](proc lambda (G_skip : None): C_3cont(G_skip, C_2pre), None) return $CAST@[?Cls, Cls](V_maybe_log_9).f(C_5cont, "\"boom\"") else: C_2pre: None = None return $R_CONTc@[None](proc lambda (G_skip : None): C_3cont(G_skip, C_2pre), None) ================================================ FILE: compiler/lib/test/6-cps/cps_volatiles.input ================================================ proc def force_cps (arg : __builtin__.int) -> __builtin__.int: return arg proc def compute (aa : __builtin__.int) -> __builtin__.int: W_compute_19: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() W_compute_4: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() xx: __builtin__.int = W_compute_4.__fromatom__(1) if $PUSH(): xx = W_compute_19.__iadd__(xx, force_cps(W_compute_4.__fromatom__(1))) aa = W_compute_19.__iadd__(aa, force_cps(W_compute_4.__fromatom__(1))) $DROP() else: N_x: __builtin__.BaseException = $POP() if isinstance(N_x, ValueError): pass else: $RAISE(N_x) N_1tmp: __builtin__.int = W_compute_19.__add__(xx, aa) return N_1tmp W_main_74: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W_main_91: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() W_main_29: __builtin__.Eq[?__builtin__.int] = $EqOpt@[__builtin__.int](W_main_91) # recursive group: class main ($Actor, __builtin__.value): @property v : __builtin__.int proc def __init__ (self : Self, env : __builtin__.Env) -> None: self.v = compute(W_main_74.__fromatom__(10)) if W_main_29.__eq__(self.v, W_main_74.__fromatom__(13)): (async env.exit)(W_main_74.__fromatom__(0)) else: print@[(__builtin__.str, __builtin__.int)](("\"Excpected 13, got\"", self.v), None, None, None, None) (async env.exit)(W_main_74.__fromatom__(1)) proc def mainG_newact (env : __builtin__.Env) -> main: G_act: main = $NEWACTOR@[main]() $InstallFinalizer@[main](G_act) $AWAITf@[None]($ASYNCf@[None](G_act, proc lambda: G_act.__init__(env))) return G_act # (recursive group) ================================================ FILE: compiler/lib/test/6-cps/cps_volatiles.output ================================================ proc def force_cps (C_cont : proc(__builtin__.int) -> $R, arg : __builtin__.int) -> $R: return $R_CONTc@[__builtin__.int](C_cont, arg) proc def compute (C_cont : proc(__builtin__.int) -> $R, aa : __builtin__.int) -> $R: aa: $Box[__builtin__.int] = $Box@[__builtin__.int](aa) W_compute_19: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() W_compute_4: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() xx: $Box[__builtin__.int] = $Box@[__builtin__.int](W_compute_4.__fromatom__(1)) proc def C_3cont (C_4res : None) -> $R: N_1tmp: __builtin__.int = W_compute_19.__add__(xx.val, aa.val) return $R_CONTc@[__builtin__.int](C_cont, N_1tmp) proc def C_5try (C_6res : __builtin__.bool) -> $R: if C_6res: proc def C_7cont (C_8res : __builtin__.int) -> $R: C_1pre: __builtin__.int = C_8res xx.val = W_compute_19.__iadd__(xx.val, C_1pre) proc def C_9cont (C_10res : __builtin__.int) -> $R: C_2pre: __builtin__.int = C_10res aa.val = W_compute_19.__iadd__(aa.val, C_2pre) $DROP_C() return $R_CONTc@[None](C_3cont, None) return force_cps(C_9cont, W_compute_4.__fromatom__(1)) return force_cps(C_7cont, W_compute_4.__fromatom__(1)) else: N_x: __builtin__.BaseException = $POP_C() if isinstance(N_x, ValueError): pass else: $RAISE(N_x) return $R_CONTc@[None](C_3cont, None) return $PUSH_Cc(C_5try) W_main_74: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W_main_91: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() W_main_29: __builtin__.Eq[?__builtin__.int] = $EqOpt@[__builtin__.int](W_main_91) # recursive group: class main ($Actor, __builtin__.value): @property v : __builtin__.int proc def __init__ (self : Self, C_cont : proc(None) -> $R, env : __builtin__.Env) -> $R: proc def C_11cont (C_12res : __builtin__.int) -> $R: self.v = C_12res if W_main_29.__eq__(self.v, W_main_74.__fromatom__(13)): (async env.exit)(W_main_74.__fromatom__(0)) else: print@[(__builtin__.str, __builtin__.int)](("\"Excpected 13, got\"", self.v), None, None, None, None) (async env.exit)(W_main_74.__fromatom__(1)) return $R_CONTc@[None](C_cont, None) return compute(C_11cont, W_main_74.__fromatom__(10)) proc def mainG_newact (C_cont : proc(main) -> $R, env : __builtin__.Env) -> $R: G_act: main = $NEWACTOR@[main]() $InstallFinalizer@[main](G_act) proc def C_13cont (C_14res : None) -> $R: return $R_CONTc@[main](C_cont, G_act) return $AWAITc@[None](C_13cont, $ASYNCc@[None](G_act, proc lambda (C_cont : proc(None) -> $R): G_act.__init__(C_cont, env))) # (recursive group) ================================================ FILE: compiler/lib/test/7-lambdalifting/deact.input ================================================ W_Apa_39: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_140: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_105: __builtin__.Times[__builtin__.int, __builtin__.int] = __builtin__.IntegralD_int() W_Apa_308: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() # recursive group: class Apa ($Actor, __builtin__.value): proc def __init__ (self : Self, C_cont : proc(None) -> $R) -> $R: proc def C_1cont (C_2res : None) -> $R: print@[(__builtin__.str,)](("\"Apa\"",), None, None, None, None) return $R_CONTc@[None](C_cont, None) return self.setupG_local(C_1cont, self.notice) proc def setupG_local (self : Self, C_cont : proc(None) -> $R, cb : action(__builtin__.int) -> __builtin__.int) -> $R: print@[(__builtin__.str,)](("\"setup\"",), None, None, None, None) (async cb)(W_Apa_39.__fromatom__(0)) return $R_CONTc@[None](C_cont, None) proc def computeG_local (self : Self, C_cont : proc(__builtin__.int) -> $R, cb : action(__builtin__.int) -> __builtin__.int) -> $R: print@[(__builtin__.str,)](("\"compute\"",), None, None, None, None) proc def C_3cont (C_4res : __builtin__.int) -> $R: v: __builtin__.int = C_4res m: __builtin__.Msg[__builtin__.int] = (async cb)(W_Apa_39.__fromatom__(2)) N_tmp: __builtin__.int = W_Apa_105.__mul__(v, W_Apa_39.__fromatom__(10)) return $R_CONTc@[__builtin__.int](C_cont, N_tmp) return $AWAITc@[__builtin__.int](C_3cont, (async cb)(W_Apa_39.__fromatom__(1))) proc def noticeG_local (self : Self, C_cont : proc(__builtin__.int) -> $R, i : __builtin__.int) -> $R: print@[(__builtin__.str,)](("\"notice\"",), None, None, None, None) N_1tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return $R_CONTc@[__builtin__.int](C_cont, N_1tmp) action def setup (self : Self, cb : action(__builtin__.int) -> __builtin__.int) -> None: return $ASYNCc@[None](self, proc lambda (C_cont : proc(None) -> $R): self.setupG_local(C_cont, cb)) action def compute (self : Self, cb : action(__builtin__.int) -> __builtin__.int) -> __builtin__.int: return $ASYNCc@[__builtin__.int](self, proc lambda (C_cont : proc(__builtin__.int) -> $R): self.computeG_local(C_cont, cb)) action def notice (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNCc@[__builtin__.int](self, proc lambda (C_cont : proc(__builtin__.int) -> $R): self.noticeG_local(C_cont, i)) class Bepa ($Actor, __builtin__.value): proc def __init__ (self : Self, C_cont : proc(None) -> $R) -> $R: print@[(__builtin__.str,)](("\"Bepa\"",), None, None, None, None) return $R_CONTc@[None](C_cont, None) proc def callbackG_local (self : Self, C_cont : proc(__builtin__.int) -> $R, i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"callback\"", i), None, None, None, None) N_2tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return $R_CONTc@[__builtin__.int](C_cont, N_2tmp) action def callback (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNCc@[__builtin__.int](self, proc lambda (C_cont : proc(__builtin__.int) -> $R): self.callbackG_local(C_cont, i)) class main ($Actor, __builtin__.value): @property env : __builtin__.Env @property a : Apa @property b : Bepa @property x : __builtin__.Msg[__builtin__.int] @property r : __builtin__.int proc def __init__ (self : Self, C_cont : proc(None) -> $R, env : __builtin__.Env) -> $R: self.env = env proc def C_5cont (C_6res : Apa) -> $R: self.a = C_6res proc def C_7cont (C_8res : Bepa) -> $R: self.b = C_8res print@[(__builtin__.str,)](("\"-----\"",), None, None, None, None) (async self.a.setup)(self.a.notice) self.x = (async self.a.compute)(self.b.callback) proc def C_9cont (C_10res : __builtin__.int) -> $R: self.r = C_10res print@[(__builtin__.str, __builtin__.int)](("\"r =\"", self.r), None, None, None, None) (async self.a.compute)(self.myproc) print@[(__builtin__.str,)](("\"main\"",), None, None, None, None) return $R_CONTc@[None](C_cont, None) return $AWAITc@[__builtin__.int](C_9cont, self.x) return BepaG_newact(C_7cont) return ApaG_newact(C_5cont) proc def myprocG_local (self : Self, C_cont : proc(__builtin__.int) -> $R, i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"myproc\"", i), None, None, None, None) if W_Apa_308.__eq__(i, W_Apa_39.__fromatom__(2)): (async self.env.exit)(W_Apa_39.__fromatom__(0)) return $R_CONTc@[__builtin__.int](C_cont, i) action def myproc (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNCc@[__builtin__.int](self, proc lambda (C_cont : proc(__builtin__.int) -> $R): self.myprocG_local(C_cont, i)) proc def ApaG_newact (C_cont : proc(Apa) -> $R) -> $R: G_act: Apa = $NEWACTOR@[Apa]() $InstallFinalizer@[Apa](G_act) proc def C_11cont (C_12res : None) -> $R: return $R_CONTc@[Apa](C_cont, G_act) return $AWAITc@[None](C_11cont, $ASYNCc@[None](G_act, proc lambda (C_cont : proc(None) -> $R): G_act.__init__(C_cont))) proc def BepaG_newact (C_cont : proc(Bepa) -> $R) -> $R: G_act: Bepa = $NEWACTOR@[Bepa]() $InstallFinalizer@[Bepa](G_act) proc def C_13cont (C_14res : None) -> $R: return $R_CONTc@[Bepa](C_cont, G_act) return $AWAITc@[None](C_13cont, $ASYNCc@[None](G_act, proc lambda (C_cont : proc(None) -> $R): G_act.__init__(C_cont))) proc def mainG_newact (C_cont : proc(main) -> $R, env : __builtin__.Env) -> $R: G_act: main = $NEWACTOR@[main]() $InstallFinalizer@[main](G_act) proc def C_15cont (C_16res : None) -> $R: return $R_CONTc@[main](C_cont, G_act) return $AWAITc@[None](C_15cont, $ASYNCc@[None](G_act, proc lambda (C_cont : proc(None) -> $R): G_act.__init__(C_cont, env))) # (recursive group) ================================================ FILE: compiler/lib/test/7-lambdalifting/deact.output ================================================ W_Apa_39: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_140: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_105: __builtin__.Times[__builtin__.int, __builtin__.int] = __builtin__.IntegralD_int() W_Apa_308: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() # recursive group: proc def L_1C_1cont (C_cont : $Cont[None], C_2res : None) -> $R: print@[(__builtin__.str,)](("\"Apa\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) class L_2Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[None] pure def __init__ (L_self : Self, C_cont : $Cont[None]) -> None: L_self.C_cont = C_cont return None proc def __call__ (L_self : Self, G_1 : None) -> $R: C_cont: $Cont[None] = L_self.C_cont return L_1C_1cont(C_cont, G_1) class L_4action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_3obj : Apa pure def __init__ (L_self : Self, L_3obj : Apa) -> None: L_self.L_3obj = L_3obj return None # recursive group: proc def __call__ (L_self : Self, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : Self, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : Self, G_1 : __builtin__.int) -> __builtin__.int: L_3obj: Apa = L_self.L_3obj return L_3obj.notice(G_1) # (recursive group) proc def L_5C_3cont (cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int], C_4res : __builtin__.int) -> $R: v: __builtin__.int = C_4res m: __builtin__.Msg[__builtin__.int] = cb.__asyn__(W_Apa_39.__fromatom__(2)) N_tmp: __builtin__.int = W_Apa_105.__mul__(v, W_Apa_39.__fromatom__(10)) return $R_CONT@[__builtin__.int](C_cont, N_tmp) class L_6Cont ($Cont[__builtin__.int], __builtin__.value): @property cb : $action[(__builtin__.int,), __builtin__.int] @property C_cont : $Cont[__builtin__.int] pure def __init__ (L_self : Self, cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int]) -> None: L_self.cb = cb L_self.C_cont = C_cont return None proc def __call__ (L_self : Self, G_1 : __builtin__.int) -> $R: cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb C_cont: $Cont[__builtin__.int] = L_self.C_cont return L_5C_3cont(cb, C_cont, G_1) class L_7proc ($proc[(), None], __builtin__.value): @property self : Apa @property cb : $action[(__builtin__.int,), __builtin__.int] pure def __init__ (L_self : Self, self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: L_self.self = self L_self.cb = cb return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[None]) -> $R: self: Apa = L_self.self cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb return self.setupG_local(C_cont, cb) proc def __exec__ (L_self : Self, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_8proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Apa @property cb : $action[(__builtin__.int,), __builtin__.int] pure def __init__ (L_self : Self, self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: L_self.self = self L_self.cb = cb return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: self: Apa = L_self.self cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb return self.computeG_local(C_cont, cb) proc def __exec__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_9proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Apa @property i : __builtin__.int pure def __init__ (L_self : Self, self : Apa, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: self: Apa = L_self.self i: __builtin__.int = L_self.i return self.noticeG_local(C_cont, i) proc def __exec__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_10proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Bepa @property i : __builtin__.int pure def __init__ (L_self : Self, self : Bepa, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: self: Bepa = L_self.self i: __builtin__.int = L_self.i return self.callbackG_local(C_cont, i) proc def __exec__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_14action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_13obj : Apa pure def __init__ (L_self : Self, L_13obj : Apa) -> None: L_self.L_13obj = L_13obj return None # recursive group: proc def __call__ (L_self : Self, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : Self, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : Self, G_1 : __builtin__.int) -> __builtin__.int: L_13obj: Apa = L_self.L_13obj return L_13obj.notice(G_1) # (recursive group) class L_16action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_15obj : Bepa pure def __init__ (L_self : Self, L_15obj : Bepa) -> None: L_self.L_15obj = L_15obj return None # recursive group: proc def __call__ (L_self : Self, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : Self, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : Self, G_1 : __builtin__.int) -> __builtin__.int: L_15obj: Bepa = L_self.L_15obj return L_15obj.callback(G_1) # (recursive group) class L_19action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_18obj : main pure def __init__ (L_self : Self, L_18obj : main) -> None: L_self.L_18obj = L_18obj return None # recursive group: proc def __call__ (L_self : Self, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : Self, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : Self, G_1 : __builtin__.int) -> __builtin__.int: L_18obj: main = L_self.L_18obj return L_18obj.myproc(G_1) # (recursive group) proc def L_17C_9cont (self : main, C_cont : $Cont[None], C_10res : __builtin__.int) -> $R: self.r = C_10res print@[(__builtin__.str, __builtin__.int)](("\"r =\"", self.r), None, None, None, None) (async self.a.compute)(L_19action(self)) print@[(__builtin__.str,)](("\"main\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) class L_20Cont ($Cont[__builtin__.int], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : Self, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : Self, G_1 : __builtin__.int) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_17C_9cont(self, C_cont, G_1) proc def L_12C_7cont (self : main, C_cont : $Cont[None], C_8res : Bepa) -> $R: self.b = C_8res print@[(__builtin__.str,)](("\"-----\"",), None, None, None, None) (async self.a.setup)(L_14action(self.a)) self.x = (async self.a.compute)(L_16action(self.b)) return $AWAIT@[__builtin__.int](L_20Cont(self, C_cont), self.x) class L_21Cont ($Cont[Bepa], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : Self, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : Self, G_1 : Bepa) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_12C_7cont(self, C_cont, G_1) proc def L_11C_5cont (self : main, C_cont : $Cont[None], C_6res : Apa) -> $R: self.a = C_6res return BepaG_newact(L_21Cont(self, C_cont)) class L_22Cont ($Cont[Apa], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : Self, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : Self, G_1 : Apa) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_11C_5cont(self, C_cont, G_1) class L_23proc ($proc[(), __builtin__.int], __builtin__.value): @property self : main @property i : __builtin__.int pure def __init__ (L_self : Self, self : main, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: self: main = L_self.self i: __builtin__.int = L_self.i return self.myprocG_local(C_cont, i) proc def __exec__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_24C_11cont (C_cont : $Cont[Apa], G_act : Apa, C_12res : None) -> $R: return $R_CONT@[Apa](C_cont, G_act) class L_25Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[Apa] @property G_act : Apa pure def __init__ (L_self : Self, C_cont : $Cont[Apa], G_act : Apa) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : Self, G_1 : None) -> $R: C_cont: $Cont[Apa] = L_self.C_cont G_act: Apa = L_self.G_act return L_24C_11cont(C_cont, G_act, G_1) class L_26proc ($proc[(), None], __builtin__.value): @property G_act : Apa pure def __init__ (L_self : Self, G_act : Apa) -> None: L_self.G_act = G_act return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[None]) -> $R: G_act: Apa = L_self.G_act return G_act.__init__(C_cont) proc def __exec__ (L_self : Self, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_27C_13cont (C_cont : $Cont[Bepa], G_act : Bepa, C_14res : None) -> $R: return $R_CONT@[Bepa](C_cont, G_act) class L_28Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[Bepa] @property G_act : Bepa pure def __init__ (L_self : Self, C_cont : $Cont[Bepa], G_act : Bepa) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : Self, G_1 : None) -> $R: C_cont: $Cont[Bepa] = L_self.C_cont G_act: Bepa = L_self.G_act return L_27C_13cont(C_cont, G_act, G_1) class L_29proc ($proc[(), None], __builtin__.value): @property G_act : Bepa pure def __init__ (L_self : Self, G_act : Bepa) -> None: L_self.G_act = G_act return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[None]) -> $R: G_act: Bepa = L_self.G_act return G_act.__init__(C_cont) proc def __exec__ (L_self : Self, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_30C_15cont (C_cont : $Cont[main], G_act : main, C_16res : None) -> $R: return $R_CONT@[main](C_cont, G_act) class L_31Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[main] @property G_act : main pure def __init__ (L_self : Self, C_cont : $Cont[main], G_act : main) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : Self, G_1 : None) -> $R: C_cont: $Cont[main] = L_self.C_cont G_act: main = L_self.G_act return L_30C_15cont(C_cont, G_act, G_1) class L_32proc ($proc[(), None], __builtin__.value): @property G_act : main @property env : __builtin__.Env pure def __init__ (L_self : Self, G_act : main, env : __builtin__.Env) -> None: L_self.G_act = G_act L_self.env = env return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[None]) -> $R: G_act: main = L_self.G_act env: __builtin__.Env = L_self.env return G_act.__init__(C_cont, env) proc def __exec__ (L_self : Self, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) class Apa ($Actor, __builtin__.value): proc def __init__ (self : Self, C_cont : $Cont[None]) -> $R: return self.setupG_local(L_2Cont(C_cont), L_4action(self)) proc def setupG_local (self : Self, C_cont : $Cont[None], cb : $action[(__builtin__.int,), __builtin__.int]) -> $R: print@[(__builtin__.str,)](("\"setup\"",), None, None, None, None) cb.__asyn__(W_Apa_39.__fromatom__(0)) return $R_CONT@[None](C_cont, None) proc def computeG_local (self : Self, C_cont : $Cont[__builtin__.int], cb : $action[(__builtin__.int,), __builtin__.int]) -> $R: print@[(__builtin__.str,)](("\"compute\"",), None, None, None, None) return $AWAIT@[__builtin__.int](L_6Cont(cb, C_cont), cb.__asyn__(W_Apa_39.__fromatom__(1))) proc def noticeG_local (self : Self, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str,)](("\"notice\"",), None, None, None, None) N_1tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return $R_CONT@[__builtin__.int](C_cont, N_1tmp) action def setup (self : Self, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: return $ASYNC@[None](self, L_7proc(self, cb)) action def compute (self : Self, cb : $action[(__builtin__.int,), __builtin__.int]) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_8proc(self, cb)) action def notice (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_9proc(self, i)) class Bepa ($Actor, __builtin__.value): proc def __init__ (self : Self, C_cont : $Cont[None]) -> $R: print@[(__builtin__.str,)](("\"Bepa\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) proc def callbackG_local (self : Self, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"callback\"", i), None, None, None, None) N_2tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return $R_CONT@[__builtin__.int](C_cont, N_2tmp) action def callback (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_10proc(self, i)) class main ($Actor, __builtin__.value): @property env : __builtin__.Env @property a : Apa @property b : Bepa @property x : __builtin__.Msg[__builtin__.int] @property r : __builtin__.int proc def __init__ (self : Self, C_cont : $Cont[None], env : __builtin__.Env) -> $R: self.env = env return ApaG_newact(L_22Cont(self, C_cont)) proc def myprocG_local (self : Self, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"myproc\"", i), None, None, None, None) if W_Apa_308.__eq__(i, W_Apa_39.__fromatom__(2)): (async self.env.exit)(W_Apa_39.__fromatom__(0)) return $R_CONT@[__builtin__.int](C_cont, i) action def myproc (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_23proc(self, i)) proc def ApaG_newact (C_cont : $Cont[Apa]) -> $R: G_act: Apa = $NEWACTOR@[Apa]() $InstallFinalizer@[Apa](G_act) return $AWAIT@[None](L_25Cont(C_cont, G_act), $ASYNC@[None](G_act, L_26proc(G_act))) proc def BepaG_newact (C_cont : $Cont[Bepa]) -> $R: G_act: Bepa = $NEWACTOR@[Bepa]() $InstallFinalizer@[Bepa](G_act) return $AWAIT@[None](L_28Cont(C_cont, G_act), $ASYNC@[None](G_act, L_29proc(G_act))) proc def mainG_newact (C_cont : $Cont[main], env : __builtin__.Env) -> $R: G_act: main = $NEWACTOR@[main]() $InstallFinalizer@[main](G_act) return $AWAIT@[None](L_31Cont(C_cont, G_act), $ASYNC@[None](G_act, L_32proc(G_act, env))) # (recursive group) ================================================ FILE: compiler/lib/test/8-boxing/deact.input ================================================ W_Apa_39: __builtin__.Number[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_140: __builtin__.Plus[__builtin__.int] = __builtin__.IntegralD_int() W_Apa_105: __builtin__.Times[__builtin__.int, __builtin__.int] = __builtin__.IntegralD_int() W_Apa_308: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() # recursive group: proc def L_1C_1cont (C_cont : $Cont[None], C_2res : None) -> $R: print@[(__builtin__.str,)](("\"Apa\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) class L_2Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[None] pure def __init__ (L_self : Self, C_cont : $Cont[None]) -> None: L_self.C_cont = C_cont return None proc def __call__ (L_self : Self, G_1 : None) -> $R: C_cont: $Cont[None] = L_self.C_cont return L_1C_1cont(C_cont, G_1) class L_4action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_3obj : Apa pure def __init__ (L_self : Self, L_3obj : Apa) -> None: L_self.L_3obj = L_3obj return None # recursive group: proc def __call__ (L_self : Self, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : Self, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : Self, G_1 : __builtin__.int) -> __builtin__.int: L_3obj: Apa = L_self.L_3obj return L_3obj.notice(G_1) # (recursive group) proc def L_5C_3cont (cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int], C_4res : __builtin__.int) -> $R: v: __builtin__.int = C_4res m: __builtin__.Msg[__builtin__.int] = cb.__asyn__(W_Apa_39.__fromatom__(2)) N_tmp: __builtin__.int = W_Apa_105.__mul__(v, W_Apa_39.__fromatom__(10)) return $R_CONT@[__builtin__.int](C_cont, N_tmp) class L_6Cont ($Cont[__builtin__.int], __builtin__.value): @property cb : $action[(__builtin__.int,), __builtin__.int] @property C_cont : $Cont[__builtin__.int] pure def __init__ (L_self : Self, cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int]) -> None: L_self.cb = cb L_self.C_cont = C_cont return None proc def __call__ (L_self : Self, G_1 : __builtin__.int) -> $R: cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb C_cont: $Cont[__builtin__.int] = L_self.C_cont return L_5C_3cont(cb, C_cont, G_1) class L_7proc ($proc[(), None], __builtin__.value): @property self : Apa @property cb : $action[(__builtin__.int,), __builtin__.int] pure def __init__ (L_self : Self, self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: L_self.self = self L_self.cb = cb return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[None]) -> $R: self: Apa = L_self.self cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb return self.setupG_local(C_cont, cb) proc def __exec__ (L_self : Self, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_8proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Apa @property cb : $action[(__builtin__.int,), __builtin__.int] pure def __init__ (L_self : Self, self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: L_self.self = self L_self.cb = cb return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: self: Apa = L_self.self cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb return self.computeG_local(C_cont, cb) proc def __exec__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_9proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Apa @property i : __builtin__.int pure def __init__ (L_self : Self, self : Apa, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: self: Apa = L_self.self i: __builtin__.int = L_self.i return self.noticeG_local(C_cont, i) proc def __exec__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_10proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Bepa @property i : __builtin__.int pure def __init__ (L_self : Self, self : Bepa, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: self: Bepa = L_self.self i: __builtin__.int = L_self.i return self.callbackG_local(C_cont, i) proc def __exec__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_14action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_13obj : Apa pure def __init__ (L_self : Self, L_13obj : Apa) -> None: L_self.L_13obj = L_13obj return None # recursive group: proc def __call__ (L_self : Self, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : Self, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : Self, G_1 : __builtin__.int) -> __builtin__.int: L_13obj: Apa = L_self.L_13obj return L_13obj.notice(G_1) # (recursive group) class L_16action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_15obj : Bepa pure def __init__ (L_self : Self, L_15obj : Bepa) -> None: L_self.L_15obj = L_15obj return None # recursive group: proc def __call__ (L_self : Self, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : Self, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : Self, G_1 : __builtin__.int) -> __builtin__.int: L_15obj: Bepa = L_self.L_15obj return L_15obj.callback(G_1) # (recursive group) class L_19action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_18obj : main pure def __init__ (L_self : Self, L_18obj : main) -> None: L_self.L_18obj = L_18obj return None # recursive group: proc def __call__ (L_self : Self, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : Self, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : Self, G_1 : __builtin__.int) -> __builtin__.int: L_18obj: main = L_self.L_18obj return L_18obj.myproc(G_1) # (recursive group) proc def L_17C_9cont (self : main, C_cont : $Cont[None], C_10res : __builtin__.int) -> $R: self.r = C_10res print@[(__builtin__.str, __builtin__.int)](("\"r =\"", self.r), None, None, None, None) (async self.a.compute)(L_19action(self)) print@[(__builtin__.str,)](("\"main\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) class L_20Cont ($Cont[__builtin__.int], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : Self, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : Self, G_1 : __builtin__.int) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_17C_9cont(self, C_cont, G_1) proc def L_12C_7cont (self : main, C_cont : $Cont[None], C_8res : Bepa) -> $R: self.b = C_8res print@[(__builtin__.str,)](("\"-----\"",), None, None, None, None) (async self.a.setup)(L_14action(self.a)) self.x = (async self.a.compute)(L_16action(self.b)) return $AWAIT@[__builtin__.int](L_20Cont(self, C_cont), self.x) class L_21Cont ($Cont[Bepa], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : Self, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : Self, G_1 : Bepa) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_12C_7cont(self, C_cont, G_1) proc def L_11C_5cont (self : main, C_cont : $Cont[None], C_6res : Apa) -> $R: self.a = C_6res return BepaG_newact(L_21Cont(self, C_cont)) class L_22Cont ($Cont[Apa], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : Self, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : Self, G_1 : Apa) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_11C_5cont(self, C_cont, G_1) class L_23proc ($proc[(), __builtin__.int], __builtin__.value): @property self : main @property i : __builtin__.int pure def __init__ (L_self : Self, self : main, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: self: main = L_self.self i: __builtin__.int = L_self.i return self.myprocG_local(C_cont, i) proc def __exec__ (L_self : Self, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_24C_11cont (C_cont : $Cont[Apa], G_act : Apa, C_12res : None) -> $R: return $R_CONT@[Apa](C_cont, G_act) class L_25Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[Apa] @property G_act : Apa pure def __init__ (L_self : Self, C_cont : $Cont[Apa], G_act : Apa) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : Self, G_1 : None) -> $R: C_cont: $Cont[Apa] = L_self.C_cont G_act: Apa = L_self.G_act return L_24C_11cont(C_cont, G_act, G_1) class L_26proc ($proc[(), None], __builtin__.value): @property G_act : Apa pure def __init__ (L_self : Self, G_act : Apa) -> None: L_self.G_act = G_act return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[None]) -> $R: G_act: Apa = L_self.G_act return G_act.__init__(C_cont) proc def __exec__ (L_self : Self, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_27C_13cont (C_cont : $Cont[Bepa], G_act : Bepa, C_14res : None) -> $R: return $R_CONT@[Bepa](C_cont, G_act) class L_28Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[Bepa] @property G_act : Bepa pure def __init__ (L_self : Self, C_cont : $Cont[Bepa], G_act : Bepa) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : Self, G_1 : None) -> $R: C_cont: $Cont[Bepa] = L_self.C_cont G_act: Bepa = L_self.G_act return L_27C_13cont(C_cont, G_act, G_1) class L_29proc ($proc[(), None], __builtin__.value): @property G_act : Bepa pure def __init__ (L_self : Self, G_act : Bepa) -> None: L_self.G_act = G_act return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[None]) -> $R: G_act: Bepa = L_self.G_act return G_act.__init__(C_cont) proc def __exec__ (L_self : Self, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_30C_15cont (C_cont : $Cont[main], G_act : main, C_16res : None) -> $R: return $R_CONT@[main](C_cont, G_act) class L_31Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[main] @property G_act : main pure def __init__ (L_self : Self, C_cont : $Cont[main], G_act : main) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : Self, G_1 : None) -> $R: C_cont: $Cont[main] = L_self.C_cont G_act: main = L_self.G_act return L_30C_15cont(C_cont, G_act, G_1) class L_32proc ($proc[(), None], __builtin__.value): @property G_act : main @property env : __builtin__.Env pure def __init__ (L_self : Self, G_act : main, env : __builtin__.Env) -> None: L_self.G_act = G_act L_self.env = env return None # recursive group: proc def __call__ (L_self : Self, C_cont : $Cont[None]) -> $R: G_act: main = L_self.G_act env: __builtin__.Env = L_self.env return G_act.__init__(C_cont, env) proc def __exec__ (L_self : Self, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) class Apa ($Actor, __builtin__.value): proc def __init__ (self : Self, C_cont : $Cont[None]) -> $R: return self.setupG_local(L_2Cont(C_cont), L_4action(self)) proc def setupG_local (self : Self, C_cont : $Cont[None], cb : $action[(__builtin__.int,), __builtin__.int]) -> $R: print@[(__builtin__.str,)](("\"setup\"",), None, None, None, None) cb.__asyn__(W_Apa_39.__fromatom__(0)) return $R_CONT@[None](C_cont, None) proc def computeG_local (self : Self, C_cont : $Cont[__builtin__.int], cb : $action[(__builtin__.int,), __builtin__.int]) -> $R: print@[(__builtin__.str,)](("\"compute\"",), None, None, None, None) return $AWAIT@[__builtin__.int](L_6Cont(cb, C_cont), cb.__asyn__(W_Apa_39.__fromatom__(1))) proc def noticeG_local (self : Self, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str,)](("\"notice\"",), None, None, None, None) N_1tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return $R_CONT@[__builtin__.int](C_cont, N_1tmp) action def setup (self : Self, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: return $ASYNC@[None](self, L_7proc(self, cb)) action def compute (self : Self, cb : $action[(__builtin__.int,), __builtin__.int]) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_8proc(self, cb)) action def notice (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_9proc(self, i)) class Bepa ($Actor, __builtin__.value): proc def __init__ (self : Self, C_cont : $Cont[None]) -> $R: print@[(__builtin__.str,)](("\"Bepa\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) proc def callbackG_local (self : Self, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"callback\"", i), None, None, None, None) N_2tmp: __builtin__.int = W_Apa_140.__add__(i, W_Apa_39.__fromatom__(1)) return $R_CONT@[__builtin__.int](C_cont, N_2tmp) action def callback (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_10proc(self, i)) class main ($Actor, __builtin__.value): @property env : __builtin__.Env @property a : Apa @property b : Bepa @property x : __builtin__.Msg[__builtin__.int] @property r : __builtin__.int proc def __init__ (self : Self, C_cont : $Cont[None], env : __builtin__.Env) -> $R: self.env = env return ApaG_newact(L_22Cont(self, C_cont)) proc def myprocG_local (self : Self, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"myproc\"", i), None, None, None, None) if W_Apa_308.__eq__(i, W_Apa_39.__fromatom__(2)): (async self.env.exit)(W_Apa_39.__fromatom__(0)) return $R_CONT@[__builtin__.int](C_cont, i) action def myproc (self : Self, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_23proc(self, i)) proc def ApaG_newact (C_cont : $Cont[Apa]) -> $R: G_act: Apa = $NEWACTOR@[Apa]() $InstallFinalizer@[Apa](G_act) return $AWAIT@[None](L_25Cont(C_cont, G_act), $ASYNC@[None](G_act, L_26proc(G_act))) proc def BepaG_newact (C_cont : $Cont[Bepa]) -> $R: G_act: Bepa = $NEWACTOR@[Bepa]() $InstallFinalizer@[Bepa](G_act) return $AWAIT@[None](L_28Cont(C_cont, G_act), $ASYNC@[None](G_act, L_29proc(G_act))) proc def mainG_newact (C_cont : $Cont[main], env : __builtin__.Env) -> $R: G_act: main = $NEWACTOR@[main]() $InstallFinalizer@[main](G_act) return $AWAIT@[None](L_31Cont(C_cont, G_act), $ASYNC@[None](G_act, L_32proc(G_act, env))) # (recursive group) ================================================ FILE: compiler/lib/test/8-boxing/deact.output ================================================ # recursive group: proc def L_1C_1cont (C_cont : $Cont[None], C_2res : None) -> $R: print@[(__builtin__.str,)](("\"Apa\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) class L_2Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[None] pure def __init__ (L_self : L_2Cont, C_cont : $Cont[None]) -> None: L_self.C_cont = C_cont return None proc def __call__ (L_self : L_2Cont, G_1 : None) -> $R: C_cont: $Cont[None] = L_self.C_cont return L_1C_1cont(C_cont, G_1) class L_4action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_3obj : Apa pure def __init__ (L_self : L_4action, L_3obj : Apa) -> None: L_self.L_3obj = L_3obj return None # recursive group: proc def __call__ (L_self : L_4action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_4action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_4action, G_1 : __builtin__.int) -> __builtin__.int: L_3obj: Apa = L_self.L_3obj return L_3obj.notice(G_1) # (recursive group) proc def U_L_5C_3cont (cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int], U_2C_4res : __builtin__.int) -> $R: U_3v: __builtin__.int = U_2C_4res m: __builtin__.Msg[__builtin__.int] = cb.__asyn__((BOX __builtin__.int (UNBOX __builtin__.int 2))) U_4N_tmp: __builtin__.int = (U_3v * (UNBOX __builtin__.int 10)) return $R_CONT@[__builtin__.int](C_cont, (BOX __builtin__.int U_4N_tmp)) proc def L_5C_3cont (cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int], C_4res : __builtin__.int) -> $R: return U_L_5C_3cont(cb, C_cont, (UNBOX __builtin__.int C_4res)) class L_6Cont ($Cont[__builtin__.int], __builtin__.value): @property cb : $action[(__builtin__.int,), __builtin__.int] @property C_cont : $Cont[__builtin__.int] pure def __init__ (L_self : L_6Cont, cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int]) -> None: L_self.cb = cb L_self.C_cont = C_cont return None proc def __call__ (L_self : L_6Cont, G_1 : __builtin__.int) -> $R: cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb C_cont: $Cont[__builtin__.int] = L_self.C_cont return L_5C_3cont(cb, C_cont, G_1) class L_7proc ($proc[(), None], __builtin__.value): @property self : Apa @property cb : $action[(__builtin__.int,), __builtin__.int] pure def __init__ (L_self : L_7proc, self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: L_self.self = self L_self.cb = cb return None # recursive group: proc def __call__ (L_self : L_7proc, C_cont : $Cont[None]) -> $R: self: Apa = L_self.self cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb return self.setupG_local(C_cont, cb) proc def __exec__ (L_self : L_7proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_8proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Apa @property cb : $action[(__builtin__.int,), __builtin__.int] pure def __init__ (L_self : L_8proc, self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: L_self.self = self L_self.cb = cb return None # recursive group: proc def __call__ (L_self : L_8proc, C_cont : $Cont[__builtin__.int]) -> $R: self: Apa = L_self.self cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb return self.computeG_local(C_cont, cb) proc def __exec__ (L_self : L_8proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_9proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Apa @property i : __builtin__.int pure def __init__ (L_self : L_9proc, self : Apa, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : L_9proc, C_cont : $Cont[__builtin__.int]) -> $R: self: Apa = L_self.self U_5i: __builtin__.int = (UNBOX __builtin__.int L_self.i) return self.noticeG_local(C_cont, (BOX __builtin__.int U_5i)) proc def __exec__ (L_self : L_9proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_10proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Bepa @property i : __builtin__.int pure def __init__ (L_self : L_10proc, self : Bepa, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : L_10proc, C_cont : $Cont[__builtin__.int]) -> $R: self: Bepa = L_self.self U_6i: __builtin__.int = (UNBOX __builtin__.int L_self.i) return self.callbackG_local(C_cont, (BOX __builtin__.int U_6i)) proc def __exec__ (L_self : L_10proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_14action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_13obj : Apa pure def __init__ (L_self : L_14action, L_13obj : Apa) -> None: L_self.L_13obj = L_13obj return None # recursive group: proc def __call__ (L_self : L_14action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_14action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_14action, G_1 : __builtin__.int) -> __builtin__.int: L_13obj: Apa = L_self.L_13obj return L_13obj.notice(G_1) # (recursive group) class L_16action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_15obj : Bepa pure def __init__ (L_self : L_16action, L_15obj : Bepa) -> None: L_self.L_15obj = L_15obj return None # recursive group: proc def __call__ (L_self : L_16action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_16action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_16action, G_1 : __builtin__.int) -> __builtin__.int: L_15obj: Bepa = L_self.L_15obj return L_15obj.callback(G_1) # (recursive group) class L_19action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_18obj : main pure def __init__ (L_self : L_19action, L_18obj : main) -> None: L_self.L_18obj = L_18obj return None # recursive group: proc def __call__ (L_self : L_19action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_19action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_19action, G_1 : __builtin__.int) -> __builtin__.int: L_18obj: main = L_self.L_18obj return L_18obj.myproc(G_1) # (recursive group) proc def U_1L_17C_9cont (self : main, C_cont : $Cont[None], U_7C_10res : __builtin__.int) -> $R: self.r = (BOX __builtin__.int U_7C_10res) print@[(__builtin__.str, __builtin__.int)](("\"r =\"", self.r), None, None, None, None) (async self.a.compute)(L_19action(self)) print@[(__builtin__.str,)](("\"main\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) proc def L_17C_9cont (self : main, C_cont : $Cont[None], C_10res : __builtin__.int) -> $R: return U_1L_17C_9cont(self, C_cont, (UNBOX __builtin__.int C_10res)) class L_20Cont ($Cont[__builtin__.int], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : L_20Cont, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : L_20Cont, G_1 : __builtin__.int) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_17C_9cont(self, C_cont, G_1) proc def L_12C_7cont (self : main, C_cont : $Cont[None], C_8res : Bepa) -> $R: self.b = C_8res print@[(__builtin__.str,)](("\"-----\"",), None, None, None, None) (async self.a.setup)(L_14action(self.a)) self.x = (async self.a.compute)(L_16action(self.b)) return $AWAIT@[__builtin__.int](L_20Cont(self, C_cont), self.x) class L_21Cont ($Cont[Bepa], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : L_21Cont, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : L_21Cont, G_1 : Bepa) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_12C_7cont(self, C_cont, G_1) proc def L_11C_5cont (self : main, C_cont : $Cont[None], C_6res : Apa) -> $R: self.a = C_6res return BepaG_newact(L_21Cont(self, C_cont)) class L_22Cont ($Cont[Apa], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : L_22Cont, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : L_22Cont, G_1 : Apa) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_11C_5cont(self, C_cont, G_1) class L_23proc ($proc[(), __builtin__.int], __builtin__.value): @property self : main @property i : __builtin__.int pure def __init__ (L_self : L_23proc, self : main, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : L_23proc, C_cont : $Cont[__builtin__.int]) -> $R: self: main = L_self.self U_8i: __builtin__.int = (UNBOX __builtin__.int L_self.i) return self.myprocG_local(C_cont, (BOX __builtin__.int U_8i)) proc def __exec__ (L_self : L_23proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_24C_11cont (C_cont : $Cont[Apa], G_act : Apa, C_12res : None) -> $R: return $R_CONT@[Apa](C_cont, G_act) class L_25Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[Apa] @property G_act : Apa pure def __init__ (L_self : L_25Cont, C_cont : $Cont[Apa], G_act : Apa) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : L_25Cont, G_1 : None) -> $R: C_cont: $Cont[Apa] = L_self.C_cont G_act: Apa = L_self.G_act return L_24C_11cont(C_cont, G_act, G_1) class L_26proc ($proc[(), None], __builtin__.value): @property G_act : Apa pure def __init__ (L_self : L_26proc, G_act : Apa) -> None: L_self.G_act = G_act return None # recursive group: proc def __call__ (L_self : L_26proc, C_cont : $Cont[None]) -> $R: G_act: Apa = L_self.G_act return G_act.__init__(C_cont) proc def __exec__ (L_self : L_26proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_27C_13cont (C_cont : $Cont[Bepa], G_act : Bepa, C_14res : None) -> $R: return $R_CONT@[Bepa](C_cont, G_act) class L_28Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[Bepa] @property G_act : Bepa pure def __init__ (L_self : L_28Cont, C_cont : $Cont[Bepa], G_act : Bepa) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : L_28Cont, G_1 : None) -> $R: C_cont: $Cont[Bepa] = L_self.C_cont G_act: Bepa = L_self.G_act return L_27C_13cont(C_cont, G_act, G_1) class L_29proc ($proc[(), None], __builtin__.value): @property G_act : Bepa pure def __init__ (L_self : L_29proc, G_act : Bepa) -> None: L_self.G_act = G_act return None # recursive group: proc def __call__ (L_self : L_29proc, C_cont : $Cont[None]) -> $R: G_act: Bepa = L_self.G_act return G_act.__init__(C_cont) proc def __exec__ (L_self : L_29proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_30C_15cont (C_cont : $Cont[main], G_act : main, C_16res : None) -> $R: return $R_CONT@[main](C_cont, G_act) class L_31Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[main] @property G_act : main pure def __init__ (L_self : L_31Cont, C_cont : $Cont[main], G_act : main) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : L_31Cont, G_1 : None) -> $R: C_cont: $Cont[main] = L_self.C_cont G_act: main = L_self.G_act return L_30C_15cont(C_cont, G_act, G_1) class L_32proc ($proc[(), None], __builtin__.value): @property G_act : main @property env : __builtin__.Env pure def __init__ (L_self : L_32proc, G_act : main, env : __builtin__.Env) -> None: L_self.G_act = G_act L_self.env = env return None # recursive group: proc def __call__ (L_self : L_32proc, C_cont : $Cont[None]) -> $R: G_act: main = L_self.G_act env: __builtin__.Env = L_self.env return G_act.__init__(C_cont, env) proc def __exec__ (L_self : L_32proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) class Apa ($Actor, __builtin__.value): proc def __init__ (self : Apa, C_cont : $Cont[None]) -> $R: return self.setupG_local(L_2Cont(C_cont), L_4action(self)) proc def setupG_local (self : Apa, C_cont : $Cont[None], cb : $action[(__builtin__.int,), __builtin__.int]) -> $R: print@[(__builtin__.str,)](("\"setup\"",), None, None, None, None) cb.__asyn__((BOX __builtin__.int (UNBOX __builtin__.int 0))) return $R_CONT@[None](C_cont, None) proc def computeG_local (self : Apa, C_cont : $Cont[__builtin__.int], cb : $action[(__builtin__.int,), __builtin__.int]) -> $R: print@[(__builtin__.str,)](("\"compute\"",), None, None, None, None) return $AWAIT@[__builtin__.int](L_6Cont(cb, C_cont), cb.__asyn__((BOX __builtin__.int (UNBOX __builtin__.int 1)))) proc def noticeG_local (self : Apa, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str,)](("\"notice\"",), None, None, None, None) U_9N_1tmp: __builtin__.int = ((UNBOX __builtin__.int i) + (UNBOX __builtin__.int 1)) return $R_CONT@[__builtin__.int](C_cont, (BOX __builtin__.int U_9N_1tmp)) action def setup (self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: return $ASYNC@[None](self, L_7proc(self, cb)) action def compute (self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_8proc(self, cb)) action def notice (self : Apa, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_9proc(self, i)) class Bepa ($Actor, __builtin__.value): proc def __init__ (self : Bepa, C_cont : $Cont[None]) -> $R: print@[(__builtin__.str,)](("\"Bepa\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) proc def callbackG_local (self : Bepa, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"callback\"", i), None, None, None, None) U_10N_2tmp: __builtin__.int = ((UNBOX __builtin__.int i) + (UNBOX __builtin__.int 1)) return $R_CONT@[__builtin__.int](C_cont, (BOX __builtin__.int U_10N_2tmp)) action def callback (self : Bepa, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_10proc(self, i)) class main ($Actor, __builtin__.value): @property env : __builtin__.Env @property a : Apa @property b : Bepa @property x : __builtin__.Msg[__builtin__.int] @property r : __builtin__.int proc def __init__ (self : main, C_cont : $Cont[None], env : __builtin__.Env) -> $R: self.env = env return ApaG_newact(L_22Cont(self, C_cont)) proc def myprocG_local (self : main, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"myproc\"", i), None, None, None, None) if (BOX __builtin__.bool ((UNBOX __builtin__.int i) == (UNBOX __builtin__.int 2))): (async self.env.exit)((BOX __builtin__.int (UNBOX __builtin__.int 0))) return $R_CONT@[__builtin__.int](C_cont, i) action def myproc (self : main, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_23proc(self, i)) proc def ApaG_newact (C_cont : $Cont[Apa]) -> $R: G_act: Apa = $NEWACTOR@[Apa]() $InstallFinalizer@[Apa](G_act) return $AWAIT@[None](L_25Cont(C_cont, G_act), $ASYNC@[None](G_act, L_26proc(G_act))) proc def BepaG_newact (C_cont : $Cont[Bepa]) -> $R: G_act: Bepa = $NEWACTOR@[Bepa]() $InstallFinalizer@[Bepa](G_act) return $AWAIT@[None](L_28Cont(C_cont, G_act), $ASYNC@[None](G_act, L_29proc(G_act))) proc def mainG_newact (C_cont : $Cont[main], env : __builtin__.Env) -> $R: G_act: main = $NEWACTOR@[main]() $InstallFinalizer@[main](G_act) return $AWAIT@[None](L_31Cont(C_cont, G_act), $ASYNC@[None](G_act, L_32proc(G_act, env))) # (recursive group) ================================================ FILE: compiler/lib/test/9-codegen/deact.c ================================================ /* Acton impl hash: test-hash */ #include "rts/common.h" #include "out/types/deact.h" $R deactQ_L_1C_1cont ($Cont C_cont, B_NoneType C_2res) { #line 15 "test/src/deact.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("Apa")), B_None, B_None, B_None, B_None); return $R_CONT(C_cont, B_None); } B_NoneType deactQ_L_2ContD___init__ (deactQ_L_2Cont L_self, $Cont C_cont) { L_self->C_cont = C_cont; return B_None; } $R deactQ_L_2ContD___call__ (deactQ_L_2Cont L_self, B_NoneType G_1) { $Cont C_cont = L_self->C_cont; return deactQ_L_1C_1cont(C_cont, G_1); } void deactQ_L_2ContD___serialize__ (deactQ_L_2Cont self, $Serial$state state) { $step_serialize(self->C_cont, state); } deactQ_L_2Cont deactQ_L_2ContD___deserialize__ (deactQ_L_2Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_2Cont)); self->$class = &deactQ_L_2ContG_methods; return self; } self = $DNEW(deactQ_L_2Cont, state); } self->C_cont = $step_deserialize(state); return self; } deactQ_L_2Cont deactQ_L_2ContG_new($Cont G_1) { deactQ_L_2Cont $tmp = acton_malloc(sizeof(struct deactQ_L_2Cont)); $tmp->$class = &deactQ_L_2ContG_methods; deactQ_L_2ContG_methods.__init__($tmp, G_1); return $tmp; } struct deactQ_L_2ContG_class deactQ_L_2ContG_methods; B_NoneType deactQ_L_4actionD___init__ (deactQ_L_4action L_self, deactQ_Apa L_3obj) { L_self->L_3obj = L_3obj; return B_None; } $R deactQ_L_4actionD___call__ (deactQ_L_4action L_self, $Cont L_cont, B_int G_1) { return $AWAIT(L_cont, ((B_Msg)((B_Msg (*) (deactQ_L_4action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } $R deactQ_L_4actionD___exec__ (deactQ_L_4action L_self, $Cont L_cont, B_int G_1) { return $R_CONT(L_cont, ((B_value)((B_Msg (*) (deactQ_L_4action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } B_Msg deactQ_L_4actionD___asyn__ (deactQ_L_4action L_self, B_int G_1) { deactQ_Apa L_3obj = L_self->L_3obj; return ((B_Msg)((B_Msg (*) (deactQ_Apa, B_int))L_3obj->$class->notice)(L_3obj, G_1)); } void deactQ_L_4actionD___serialize__ (deactQ_L_4action self, $Serial$state state) { $step_serialize(self->L_3obj, state); } deactQ_L_4action deactQ_L_4actionD___deserialize__ (deactQ_L_4action self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_4action)); self->$class = &deactQ_L_4actionG_methods; return self; } self = $DNEW(deactQ_L_4action, state); } self->L_3obj = $step_deserialize(state); return self; } deactQ_L_4action deactQ_L_4actionG_new(deactQ_Apa G_1) { deactQ_L_4action $tmp = acton_malloc(sizeof(struct deactQ_L_4action)); $tmp->$class = &deactQ_L_4actionG_methods; deactQ_L_4actionG_methods.__init__($tmp, G_1); return $tmp; } struct deactQ_L_4actionG_class deactQ_L_4actionG_methods; $R deactQ_U_L_5C_3cont ($action cb, $Cont C_cont, int64_t U_2C_4res) { #line 7 "test/src/deact.act" int64_t U_3v = U_2C_4res; #line 8 "test/src/deact.act" B_Msg m = ((B_Msg)((B_Msg (*) ($action, B_int))cb->$class->__asyn__)(cb, toB_int(2LL))); int64_t U_4N_tmp = (U_3v * 10LL); return $R_CONT(C_cont, toB_int(U_4N_tmp)); } $R deactQ_L_5C_3cont ($action cb, $Cont C_cont, B_int C_4res) { return deactQ_U_L_5C_3cont(cb, C_cont, ((B_int)C_4res)->val); } B_NoneType deactQ_L_6ContD___init__ (deactQ_L_6Cont L_self, $action cb, $Cont C_cont) { L_self->cb = cb; L_self->C_cont = C_cont; return B_None; } $R deactQ_L_6ContD___call__ (deactQ_L_6Cont L_self, B_int G_1) { $action cb = L_self->cb; $Cont C_cont = L_self->C_cont; return deactQ_L_5C_3cont(cb, C_cont, G_1); } void deactQ_L_6ContD___serialize__ (deactQ_L_6Cont self, $Serial$state state) { $step_serialize(self->cb, state); $step_serialize(self->C_cont, state); } deactQ_L_6Cont deactQ_L_6ContD___deserialize__ (deactQ_L_6Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_6Cont)); self->$class = &deactQ_L_6ContG_methods; return self; } self = $DNEW(deactQ_L_6Cont, state); } self->cb = $step_deserialize(state); self->C_cont = $step_deserialize(state); return self; } deactQ_L_6Cont deactQ_L_6ContG_new($action G_1, $Cont G_2) { deactQ_L_6Cont $tmp = acton_malloc(sizeof(struct deactQ_L_6Cont)); $tmp->$class = &deactQ_L_6ContG_methods; deactQ_L_6ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_6ContG_class deactQ_L_6ContG_methods; B_NoneType deactQ_L_7procD___init__ (deactQ_L_7proc L_self, deactQ_Apa self, $action cb) { L_self->self = self; L_self->cb = cb; return B_None; } $R deactQ_L_7procD___call__ (deactQ_L_7proc L_self, $Cont C_cont) { deactQ_Apa self = L_self->self; $action cb = L_self->cb; return (($R (*) (deactQ_Apa, $Cont, $action))self->$class->setupG_local)(self, C_cont, cb); } $R deactQ_L_7procD___exec__ (deactQ_L_7proc L_self, $Cont C_cont) { return (($R (*) (deactQ_L_7proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void deactQ_L_7procD___serialize__ (deactQ_L_7proc self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->cb, state); } deactQ_L_7proc deactQ_L_7procD___deserialize__ (deactQ_L_7proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_7proc)); self->$class = &deactQ_L_7procG_methods; return self; } self = $DNEW(deactQ_L_7proc, state); } self->self = $step_deserialize(state); self->cb = $step_deserialize(state); return self; } deactQ_L_7proc deactQ_L_7procG_new(deactQ_Apa G_1, $action G_2) { deactQ_L_7proc $tmp = acton_malloc(sizeof(struct deactQ_L_7proc)); $tmp->$class = &deactQ_L_7procG_methods; deactQ_L_7procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_7procG_class deactQ_L_7procG_methods; B_NoneType deactQ_L_8procD___init__ (deactQ_L_8proc L_self, deactQ_Apa self, $action cb) { L_self->self = self; L_self->cb = cb; return B_None; } $R deactQ_L_8procD___call__ (deactQ_L_8proc L_self, $Cont C_cont) { deactQ_Apa self = L_self->self; $action cb = L_self->cb; return (($R (*) (deactQ_Apa, $Cont, $action))self->$class->computeG_local)(self, C_cont, cb); } $R deactQ_L_8procD___exec__ (deactQ_L_8proc L_self, $Cont C_cont) { return (($R (*) (deactQ_L_8proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void deactQ_L_8procD___serialize__ (deactQ_L_8proc self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->cb, state); } deactQ_L_8proc deactQ_L_8procD___deserialize__ (deactQ_L_8proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_8proc)); self->$class = &deactQ_L_8procG_methods; return self; } self = $DNEW(deactQ_L_8proc, state); } self->self = $step_deserialize(state); self->cb = $step_deserialize(state); return self; } deactQ_L_8proc deactQ_L_8procG_new(deactQ_Apa G_1, $action G_2) { deactQ_L_8proc $tmp = acton_malloc(sizeof(struct deactQ_L_8proc)); $tmp->$class = &deactQ_L_8procG_methods; deactQ_L_8procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_8procG_class deactQ_L_8procG_methods; B_NoneType deactQ_L_9procD___init__ (deactQ_L_9proc L_self, deactQ_Apa self, B_int i) { L_self->self = self; L_self->i = i; return B_None; } $R deactQ_L_9procD___call__ (deactQ_L_9proc L_self, $Cont C_cont) { deactQ_Apa self = L_self->self; int64_t U_5i = ((B_int)L_self->i)->val; return (($R (*) (deactQ_Apa, $Cont, B_int))self->$class->noticeG_local)(self, C_cont, toB_int(U_5i)); } $R deactQ_L_9procD___exec__ (deactQ_L_9proc L_self, $Cont C_cont) { return (($R (*) (deactQ_L_9proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void deactQ_L_9procD___serialize__ (deactQ_L_9proc self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->i, state); } deactQ_L_9proc deactQ_L_9procD___deserialize__ (deactQ_L_9proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_9proc)); self->$class = &deactQ_L_9procG_methods; return self; } self = $DNEW(deactQ_L_9proc, state); } self->self = $step_deserialize(state); self->i = $step_deserialize(state); return self; } deactQ_L_9proc deactQ_L_9procG_new(deactQ_Apa G_1, B_int G_2) { deactQ_L_9proc $tmp = acton_malloc(sizeof(struct deactQ_L_9proc)); $tmp->$class = &deactQ_L_9procG_methods; deactQ_L_9procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_9procG_class deactQ_L_9procG_methods; B_NoneType deactQ_L_10procD___init__ (deactQ_L_10proc L_self, deactQ_Bepa self, B_int i) { L_self->self = self; L_self->i = i; return B_None; } $R deactQ_L_10procD___call__ (deactQ_L_10proc L_self, $Cont C_cont) { deactQ_Bepa self = L_self->self; int64_t U_6i = ((B_int)L_self->i)->val; return (($R (*) (deactQ_Bepa, $Cont, B_int))self->$class->callbackG_local)(self, C_cont, toB_int(U_6i)); } $R deactQ_L_10procD___exec__ (deactQ_L_10proc L_self, $Cont C_cont) { return (($R (*) (deactQ_L_10proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void deactQ_L_10procD___serialize__ (deactQ_L_10proc self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->i, state); } deactQ_L_10proc deactQ_L_10procD___deserialize__ (deactQ_L_10proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_10proc)); self->$class = &deactQ_L_10procG_methods; return self; } self = $DNEW(deactQ_L_10proc, state); } self->self = $step_deserialize(state); self->i = $step_deserialize(state); return self; } deactQ_L_10proc deactQ_L_10procG_new(deactQ_Bepa G_1, B_int G_2) { deactQ_L_10proc $tmp = acton_malloc(sizeof(struct deactQ_L_10proc)); $tmp->$class = &deactQ_L_10procG_methods; deactQ_L_10procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_10procG_class deactQ_L_10procG_methods; B_NoneType deactQ_L_14actionD___init__ (deactQ_L_14action L_self, deactQ_Apa L_13obj) { L_self->L_13obj = L_13obj; return B_None; } $R deactQ_L_14actionD___call__ (deactQ_L_14action L_self, $Cont L_cont, B_int G_1) { return $AWAIT(L_cont, ((B_Msg)((B_Msg (*) (deactQ_L_14action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } $R deactQ_L_14actionD___exec__ (deactQ_L_14action L_self, $Cont L_cont, B_int G_1) { return $R_CONT(L_cont, ((B_value)((B_Msg (*) (deactQ_L_14action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } B_Msg deactQ_L_14actionD___asyn__ (deactQ_L_14action L_self, B_int G_1) { deactQ_Apa L_13obj = L_self->L_13obj; return ((B_Msg)((B_Msg (*) (deactQ_Apa, B_int))L_13obj->$class->notice)(L_13obj, G_1)); } void deactQ_L_14actionD___serialize__ (deactQ_L_14action self, $Serial$state state) { $step_serialize(self->L_13obj, state); } deactQ_L_14action deactQ_L_14actionD___deserialize__ (deactQ_L_14action self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_14action)); self->$class = &deactQ_L_14actionG_methods; return self; } self = $DNEW(deactQ_L_14action, state); } self->L_13obj = $step_deserialize(state); return self; } deactQ_L_14action deactQ_L_14actionG_new(deactQ_Apa G_1) { deactQ_L_14action $tmp = acton_malloc(sizeof(struct deactQ_L_14action)); $tmp->$class = &deactQ_L_14actionG_methods; deactQ_L_14actionG_methods.__init__($tmp, G_1); return $tmp; } struct deactQ_L_14actionG_class deactQ_L_14actionG_methods; B_NoneType deactQ_L_16actionD___init__ (deactQ_L_16action L_self, deactQ_Bepa L_15obj) { L_self->L_15obj = L_15obj; return B_None; } $R deactQ_L_16actionD___call__ (deactQ_L_16action L_self, $Cont L_cont, B_int G_1) { return $AWAIT(L_cont, ((B_Msg)((B_Msg (*) (deactQ_L_16action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } $R deactQ_L_16actionD___exec__ (deactQ_L_16action L_self, $Cont L_cont, B_int G_1) { return $R_CONT(L_cont, ((B_value)((B_Msg (*) (deactQ_L_16action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } B_Msg deactQ_L_16actionD___asyn__ (deactQ_L_16action L_self, B_int G_1) { deactQ_Bepa L_15obj = L_self->L_15obj; return ((B_Msg)((B_Msg (*) (deactQ_Bepa, B_int))L_15obj->$class->callback)(L_15obj, G_1)); } void deactQ_L_16actionD___serialize__ (deactQ_L_16action self, $Serial$state state) { $step_serialize(self->L_15obj, state); } deactQ_L_16action deactQ_L_16actionD___deserialize__ (deactQ_L_16action self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_16action)); self->$class = &deactQ_L_16actionG_methods; return self; } self = $DNEW(deactQ_L_16action, state); } self->L_15obj = $step_deserialize(state); return self; } deactQ_L_16action deactQ_L_16actionG_new(deactQ_Bepa G_1) { deactQ_L_16action $tmp = acton_malloc(sizeof(struct deactQ_L_16action)); $tmp->$class = &deactQ_L_16actionG_methods; deactQ_L_16actionG_methods.__init__($tmp, G_1); return $tmp; } struct deactQ_L_16actionG_class deactQ_L_16actionG_methods; B_NoneType deactQ_L_19actionD___init__ (deactQ_L_19action L_self, deactQ_main L_18obj) { L_self->L_18obj = L_18obj; return B_None; } $R deactQ_L_19actionD___call__ (deactQ_L_19action L_self, $Cont L_cont, B_int G_1) { return $AWAIT(L_cont, ((B_Msg)((B_Msg (*) (deactQ_L_19action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } $R deactQ_L_19actionD___exec__ (deactQ_L_19action L_self, $Cont L_cont, B_int G_1) { return $R_CONT(L_cont, ((B_value)((B_Msg (*) (deactQ_L_19action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } B_Msg deactQ_L_19actionD___asyn__ (deactQ_L_19action L_self, B_int G_1) { deactQ_main L_18obj = L_self->L_18obj; return ((B_Msg)((B_Msg (*) (deactQ_main, B_int))L_18obj->$class->myproc)(L_18obj, G_1)); } void deactQ_L_19actionD___serialize__ (deactQ_L_19action self, $Serial$state state) { $step_serialize(self->L_18obj, state); } deactQ_L_19action deactQ_L_19actionD___deserialize__ (deactQ_L_19action self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_19action)); self->$class = &deactQ_L_19actionG_methods; return self; } self = $DNEW(deactQ_L_19action, state); } self->L_18obj = $step_deserialize(state); return self; } deactQ_L_19action deactQ_L_19actionG_new(deactQ_main G_1) { deactQ_L_19action $tmp = acton_malloc(sizeof(struct deactQ_L_19action)); $tmp->$class = &deactQ_L_19actionG_methods; deactQ_L_19actionG_methods.__init__($tmp, G_1); return $tmp; } struct deactQ_L_19actionG_class deactQ_L_19actionG_methods; $R deactQ_U_1L_17C_9cont (deactQ_main self, $Cont C_cont, int64_t U_7C_10res) { #line 34 "test/src/deact.act" self->r = toB_int(U_7C_10res); #line 35 "test/src/deact.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(2, to$str("r ="), self->r), B_None, B_None, B_None, B_None); #line 36 "test/src/deact.act" ((B_Msg (*) (deactQ_Apa, $action))self->a->$class->compute)(self->a, (($action)deactQ_L_19actionG_new(self))); #line 37 "test/src/deact.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("main")), B_None, B_None, B_None, B_None); return $R_CONT(C_cont, B_None); } $R deactQ_L_17C_9cont (deactQ_main self, $Cont C_cont, B_int C_10res) { return deactQ_U_1L_17C_9cont(self, C_cont, ((B_int)C_10res)->val); } B_NoneType deactQ_L_20ContD___init__ (deactQ_L_20Cont L_self, deactQ_main self, $Cont C_cont) { L_self->self = self; L_self->C_cont = C_cont; return B_None; } $R deactQ_L_20ContD___call__ (deactQ_L_20Cont L_self, B_int G_1) { deactQ_main self = L_self->self; $Cont C_cont = L_self->C_cont; return deactQ_L_17C_9cont(self, C_cont, G_1); } void deactQ_L_20ContD___serialize__ (deactQ_L_20Cont self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->C_cont, state); } deactQ_L_20Cont deactQ_L_20ContD___deserialize__ (deactQ_L_20Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_20Cont)); self->$class = &deactQ_L_20ContG_methods; return self; } self = $DNEW(deactQ_L_20Cont, state); } self->self = $step_deserialize(state); self->C_cont = $step_deserialize(state); return self; } deactQ_L_20Cont deactQ_L_20ContG_new(deactQ_main G_1, $Cont G_2) { deactQ_L_20Cont $tmp = acton_malloc(sizeof(struct deactQ_L_20Cont)); $tmp->$class = &deactQ_L_20ContG_methods; deactQ_L_20ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_20ContG_class deactQ_L_20ContG_methods; $R deactQ_L_12C_7cont (deactQ_main self, $Cont C_cont, deactQ_Bepa C_8res) { #line 30 "test/src/deact.act" self->b = C_8res; #line 31 "test/src/deact.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("-----")), B_None, B_None, B_None, B_None); #line 32 "test/src/deact.act" ((B_Msg (*) (deactQ_Apa, $action))self->a->$class->setup)(self->a, (($action)deactQ_L_14actionG_new(self->a))); #line 33 "test/src/deact.act" self->x = ((B_Msg (*) (deactQ_Apa, $action))self->a->$class->compute)(self->a, (($action)deactQ_L_16actionG_new(self->b))); return $AWAIT((($Cont)deactQ_L_20ContG_new(self, C_cont)), self->x); } B_NoneType deactQ_L_21ContD___init__ (deactQ_L_21Cont L_self, deactQ_main self, $Cont C_cont) { L_self->self = self; L_self->C_cont = C_cont; return B_None; } $R deactQ_L_21ContD___call__ (deactQ_L_21Cont L_self, deactQ_Bepa G_1) { deactQ_main self = L_self->self; $Cont C_cont = L_self->C_cont; return deactQ_L_12C_7cont(self, C_cont, G_1); } void deactQ_L_21ContD___serialize__ (deactQ_L_21Cont self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->C_cont, state); } deactQ_L_21Cont deactQ_L_21ContD___deserialize__ (deactQ_L_21Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_21Cont)); self->$class = &deactQ_L_21ContG_methods; return self; } self = $DNEW(deactQ_L_21Cont, state); } self->self = $step_deserialize(state); self->C_cont = $step_deserialize(state); return self; } deactQ_L_21Cont deactQ_L_21ContG_new(deactQ_main G_1, $Cont G_2) { deactQ_L_21Cont $tmp = acton_malloc(sizeof(struct deactQ_L_21Cont)); $tmp->$class = &deactQ_L_21ContG_methods; deactQ_L_21ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_21ContG_class deactQ_L_21ContG_methods; $R deactQ_L_11C_5cont (deactQ_main self, $Cont C_cont, deactQ_Apa C_6res) { #line 29 "test/src/deact.act" self->a = C_6res; return deactQ_BepaG_newact((($Cont)deactQ_L_21ContG_new(self, C_cont))); } B_NoneType deactQ_L_22ContD___init__ (deactQ_L_22Cont L_self, deactQ_main self, $Cont C_cont) { L_self->self = self; L_self->C_cont = C_cont; return B_None; } $R deactQ_L_22ContD___call__ (deactQ_L_22Cont L_self, deactQ_Apa G_1) { deactQ_main self = L_self->self; $Cont C_cont = L_self->C_cont; return deactQ_L_11C_5cont(self, C_cont, G_1); } void deactQ_L_22ContD___serialize__ (deactQ_L_22Cont self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->C_cont, state); } deactQ_L_22Cont deactQ_L_22ContD___deserialize__ (deactQ_L_22Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_22Cont)); self->$class = &deactQ_L_22ContG_methods; return self; } self = $DNEW(deactQ_L_22Cont, state); } self->self = $step_deserialize(state); self->C_cont = $step_deserialize(state); return self; } deactQ_L_22Cont deactQ_L_22ContG_new(deactQ_main G_1, $Cont G_2) { deactQ_L_22Cont $tmp = acton_malloc(sizeof(struct deactQ_L_22Cont)); $tmp->$class = &deactQ_L_22ContG_methods; deactQ_L_22ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_22ContG_class deactQ_L_22ContG_methods; B_NoneType deactQ_L_23procD___init__ (deactQ_L_23proc L_self, deactQ_main self, B_int i) { L_self->self = self; L_self->i = i; return B_None; } $R deactQ_L_23procD___call__ (deactQ_L_23proc L_self, $Cont C_cont) { deactQ_main self = L_self->self; int64_t U_8i = ((B_int)L_self->i)->val; return (($R (*) (deactQ_main, $Cont, B_int))self->$class->myprocG_local)(self, C_cont, toB_int(U_8i)); } $R deactQ_L_23procD___exec__ (deactQ_L_23proc L_self, $Cont C_cont) { return (($R (*) (deactQ_L_23proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void deactQ_L_23procD___serialize__ (deactQ_L_23proc self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->i, state); } deactQ_L_23proc deactQ_L_23procD___deserialize__ (deactQ_L_23proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_23proc)); self->$class = &deactQ_L_23procG_methods; return self; } self = $DNEW(deactQ_L_23proc, state); } self->self = $step_deserialize(state); self->i = $step_deserialize(state); return self; } deactQ_L_23proc deactQ_L_23procG_new(deactQ_main G_1, B_int G_2) { deactQ_L_23proc $tmp = acton_malloc(sizeof(struct deactQ_L_23proc)); $tmp->$class = &deactQ_L_23procG_methods; deactQ_L_23procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_23procG_class deactQ_L_23procG_methods; $R deactQ_L_24C_11cont ($Cont C_cont, deactQ_Apa G_act, B_NoneType C_12res) { return $R_CONT(C_cont, G_act); } B_NoneType deactQ_L_25ContD___init__ (deactQ_L_25Cont L_self, $Cont C_cont, deactQ_Apa G_act) { L_self->C_cont = C_cont; L_self->G_act = G_act; return B_None; } $R deactQ_L_25ContD___call__ (deactQ_L_25Cont L_self, B_NoneType G_1) { $Cont C_cont = L_self->C_cont; deactQ_Apa G_act = L_self->G_act; return deactQ_L_24C_11cont(C_cont, G_act, G_1); } void deactQ_L_25ContD___serialize__ (deactQ_L_25Cont self, $Serial$state state) { $step_serialize(self->C_cont, state); $step_serialize(self->G_act, state); } deactQ_L_25Cont deactQ_L_25ContD___deserialize__ (deactQ_L_25Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_25Cont)); self->$class = &deactQ_L_25ContG_methods; return self; } self = $DNEW(deactQ_L_25Cont, state); } self->C_cont = $step_deserialize(state); self->G_act = $step_deserialize(state); return self; } deactQ_L_25Cont deactQ_L_25ContG_new($Cont G_1, deactQ_Apa G_2) { deactQ_L_25Cont $tmp = acton_malloc(sizeof(struct deactQ_L_25Cont)); $tmp->$class = &deactQ_L_25ContG_methods; deactQ_L_25ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_25ContG_class deactQ_L_25ContG_methods; B_NoneType deactQ_L_26procD___init__ (deactQ_L_26proc L_self, deactQ_Apa G_act) { L_self->G_act = G_act; return B_None; } $R deactQ_L_26procD___call__ (deactQ_L_26proc L_self, $Cont C_cont) { deactQ_Apa G_act = L_self->G_act; return (($R (*) (deactQ_Apa, $Cont))G_act->$class->__init__)(G_act, C_cont); } $R deactQ_L_26procD___exec__ (deactQ_L_26proc L_self, $Cont C_cont) { return (($R (*) (deactQ_L_26proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void deactQ_L_26procD___serialize__ (deactQ_L_26proc self, $Serial$state state) { $step_serialize(self->G_act, state); } deactQ_L_26proc deactQ_L_26procD___deserialize__ (deactQ_L_26proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_26proc)); self->$class = &deactQ_L_26procG_methods; return self; } self = $DNEW(deactQ_L_26proc, state); } self->G_act = $step_deserialize(state); return self; } deactQ_L_26proc deactQ_L_26procG_new(deactQ_Apa G_1) { deactQ_L_26proc $tmp = acton_malloc(sizeof(struct deactQ_L_26proc)); $tmp->$class = &deactQ_L_26procG_methods; deactQ_L_26procG_methods.__init__($tmp, G_1); return $tmp; } struct deactQ_L_26procG_class deactQ_L_26procG_methods; $R deactQ_L_27C_13cont ($Cont C_cont, deactQ_Bepa G_act, B_NoneType C_14res) { return $R_CONT(C_cont, G_act); } B_NoneType deactQ_L_28ContD___init__ (deactQ_L_28Cont L_self, $Cont C_cont, deactQ_Bepa G_act) { L_self->C_cont = C_cont; L_self->G_act = G_act; return B_None; } $R deactQ_L_28ContD___call__ (deactQ_L_28Cont L_self, B_NoneType G_1) { $Cont C_cont = L_self->C_cont; deactQ_Bepa G_act = L_self->G_act; return deactQ_L_27C_13cont(C_cont, G_act, G_1); } void deactQ_L_28ContD___serialize__ (deactQ_L_28Cont self, $Serial$state state) { $step_serialize(self->C_cont, state); $step_serialize(self->G_act, state); } deactQ_L_28Cont deactQ_L_28ContD___deserialize__ (deactQ_L_28Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_28Cont)); self->$class = &deactQ_L_28ContG_methods; return self; } self = $DNEW(deactQ_L_28Cont, state); } self->C_cont = $step_deserialize(state); self->G_act = $step_deserialize(state); return self; } deactQ_L_28Cont deactQ_L_28ContG_new($Cont G_1, deactQ_Bepa G_2) { deactQ_L_28Cont $tmp = acton_malloc(sizeof(struct deactQ_L_28Cont)); $tmp->$class = &deactQ_L_28ContG_methods; deactQ_L_28ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_28ContG_class deactQ_L_28ContG_methods; B_NoneType deactQ_L_29procD___init__ (deactQ_L_29proc L_self, deactQ_Bepa G_act) { L_self->G_act = G_act; return B_None; } $R deactQ_L_29procD___call__ (deactQ_L_29proc L_self, $Cont C_cont) { deactQ_Bepa G_act = L_self->G_act; return (($R (*) (deactQ_Bepa, $Cont))G_act->$class->__init__)(G_act, C_cont); } $R deactQ_L_29procD___exec__ (deactQ_L_29proc L_self, $Cont C_cont) { return (($R (*) (deactQ_L_29proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void deactQ_L_29procD___serialize__ (deactQ_L_29proc self, $Serial$state state) { $step_serialize(self->G_act, state); } deactQ_L_29proc deactQ_L_29procD___deserialize__ (deactQ_L_29proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_29proc)); self->$class = &deactQ_L_29procG_methods; return self; } self = $DNEW(deactQ_L_29proc, state); } self->G_act = $step_deserialize(state); return self; } deactQ_L_29proc deactQ_L_29procG_new(deactQ_Bepa G_1) { deactQ_L_29proc $tmp = acton_malloc(sizeof(struct deactQ_L_29proc)); $tmp->$class = &deactQ_L_29procG_methods; deactQ_L_29procG_methods.__init__($tmp, G_1); return $tmp; } struct deactQ_L_29procG_class deactQ_L_29procG_methods; $R deactQ_L_30C_15cont ($Cont C_cont, deactQ_main G_act, B_NoneType C_16res) { return $R_CONT(C_cont, G_act); } B_NoneType deactQ_L_31ContD___init__ (deactQ_L_31Cont L_self, $Cont C_cont, deactQ_main G_act) { L_self->C_cont = C_cont; L_self->G_act = G_act; return B_None; } $R deactQ_L_31ContD___call__ (deactQ_L_31Cont L_self, B_NoneType G_1) { $Cont C_cont = L_self->C_cont; deactQ_main G_act = L_self->G_act; return deactQ_L_30C_15cont(C_cont, G_act, G_1); } void deactQ_L_31ContD___serialize__ (deactQ_L_31Cont self, $Serial$state state) { $step_serialize(self->C_cont, state); $step_serialize(self->G_act, state); } deactQ_L_31Cont deactQ_L_31ContD___deserialize__ (deactQ_L_31Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_31Cont)); self->$class = &deactQ_L_31ContG_methods; return self; } self = $DNEW(deactQ_L_31Cont, state); } self->C_cont = $step_deserialize(state); self->G_act = $step_deserialize(state); return self; } deactQ_L_31Cont deactQ_L_31ContG_new($Cont G_1, deactQ_main G_2) { deactQ_L_31Cont $tmp = acton_malloc(sizeof(struct deactQ_L_31Cont)); $tmp->$class = &deactQ_L_31ContG_methods; deactQ_L_31ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_31ContG_class deactQ_L_31ContG_methods; B_NoneType deactQ_L_32procD___init__ (deactQ_L_32proc L_self, deactQ_main G_act, B_Env env) { L_self->G_act = G_act; L_self->env = env; return B_None; } $R deactQ_L_32procD___call__ (deactQ_L_32proc L_self, $Cont C_cont) { deactQ_main G_act = L_self->G_act; B_Env env = L_self->env; return (($R (*) (deactQ_main, $Cont, B_Env))G_act->$class->__init__)(G_act, C_cont, env); } $R deactQ_L_32procD___exec__ (deactQ_L_32proc L_self, $Cont C_cont) { return (($R (*) (deactQ_L_32proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void deactQ_L_32procD___serialize__ (deactQ_L_32proc self, $Serial$state state) { $step_serialize(self->G_act, state); $step_serialize(self->env, state); } deactQ_L_32proc deactQ_L_32procD___deserialize__ (deactQ_L_32proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_L_32proc)); self->$class = &deactQ_L_32procG_methods; return self; } self = $DNEW(deactQ_L_32proc, state); } self->G_act = $step_deserialize(state); self->env = $step_deserialize(state); return self; } deactQ_L_32proc deactQ_L_32procG_new(deactQ_main G_1, B_Env G_2) { deactQ_L_32proc $tmp = acton_malloc(sizeof(struct deactQ_L_32proc)); $tmp->$class = &deactQ_L_32procG_methods; deactQ_L_32procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct deactQ_L_32procG_class deactQ_L_32procG_methods; $R deactQ_ApaD___init__ (deactQ_Apa self, $Cont C_cont) { return (($R (*) (deactQ_Apa, $Cont, $action))self->$class->setupG_local)(self, (($Cont)deactQ_L_2ContG_new(C_cont)), (($action)deactQ_L_4actionG_new(self))); } #line 2 "test/src/deact.act" $R deactQ_ApaD_setupG_local (deactQ_Apa self, $Cont C_cont, $action cb) { #line 3 "test/src/deact.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("setup")), B_None, B_None, B_None, B_None); #line 4 "test/src/deact.act" ((B_Msg (*) ($action, B_int))cb->$class->__asyn__)(cb, toB_int(0LL)); return $R_CONT(C_cont, B_None); } #line 5 "test/src/deact.act" $R deactQ_ApaD_computeG_local (deactQ_Apa self, $Cont C_cont, $action cb) { #line 6 "test/src/deact.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("compute")), B_None, B_None, B_None, B_None); return $AWAIT((($Cont)deactQ_L_6ContG_new(cb, C_cont)), ((B_Msg)((B_Msg (*) ($action, B_int))cb->$class->__asyn__)(cb, toB_int(1LL)))); } #line 10 "test/src/deact.act" $R deactQ_ApaD_noticeG_local (deactQ_Apa self, $Cont C_cont, B_int i) { #line 11 "test/src/deact.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("notice")), B_None, B_None, B_None, B_None); int64_t U_9N_1tmp = (((B_int)i)->val + 1LL); return $R_CONT(C_cont, toB_int(U_9N_1tmp)); } B_Msg deactQ_ApaD_setup (deactQ_Apa self, $action cb) { return $ASYNC((($Actor)self), (($Cont)deactQ_L_7procG_new(self, cb))); } B_Msg deactQ_ApaD_compute (deactQ_Apa self, $action cb) { return ((B_Msg)$ASYNC((($Actor)self), (($Cont)deactQ_L_8procG_new(self, cb)))); } B_Msg deactQ_ApaD_notice (deactQ_Apa self, B_int i) { return ((B_Msg)$ASYNC((($Actor)self), (($Cont)deactQ_L_9procG_new(self, i)))); } void deactQ_ApaD___serialize__ (deactQ_Apa self, $Serial$state state) { $ActorG_methods.__serialize__(($Actor)self, state); } deactQ_Apa deactQ_ApaD___deserialize__ (deactQ_Apa self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_Apa)); self->$class = &deactQ_ApaG_methods; return self; } self = $DNEW(deactQ_Apa, state); } $ActorG_methods.__deserialize__(($Actor)self, state); return self; } void deactQ_ApaD_GCfinalizer (void *obj, void *cdata) { deactQ_Apa self = (deactQ_Apa)obj; self->$class->__cleanup__(self); } $R deactQ_ApaG_new($Cont G_1) { deactQ_Apa $tmp = acton_malloc(sizeof(struct deactQ_Apa)); $tmp->$class = &deactQ_ApaG_methods; return deactQ_ApaG_methods.__init__($tmp, $CONSTCONT($tmp, G_1)); } struct deactQ_ApaG_class deactQ_ApaG_methods; $R deactQ_BepaD___init__ (deactQ_Bepa self, $Cont C_cont) { #line 21 "test/src/deact.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("Bepa")), B_None, B_None, B_None, B_None); return $R_CONT(C_cont, B_None); } #line 18 "test/src/deact.act" $R deactQ_BepaD_callbackG_local (deactQ_Bepa self, $Cont C_cont, B_int i) { #line 19 "test/src/deact.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(2, to$str("callback"), i), B_None, B_None, B_None, B_None); int64_t U_10N_2tmp = (((B_int)i)->val + 1LL); return $R_CONT(C_cont, toB_int(U_10N_2tmp)); } B_Msg deactQ_BepaD_callback (deactQ_Bepa self, B_int i) { return ((B_Msg)$ASYNC((($Actor)self), (($Cont)deactQ_L_10procG_new(self, i)))); } void deactQ_BepaD___serialize__ (deactQ_Bepa self, $Serial$state state) { $ActorG_methods.__serialize__(($Actor)self, state); } deactQ_Bepa deactQ_BepaD___deserialize__ (deactQ_Bepa self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_Bepa)); self->$class = &deactQ_BepaG_methods; return self; } self = $DNEW(deactQ_Bepa, state); } $ActorG_methods.__deserialize__(($Actor)self, state); return self; } void deactQ_BepaD_GCfinalizer (void *obj, void *cdata) { deactQ_Bepa self = (deactQ_Bepa)obj; self->$class->__cleanup__(self); } $R deactQ_BepaG_new($Cont G_1) { deactQ_Bepa $tmp = acton_malloc(sizeof(struct deactQ_Bepa)); $tmp->$class = &deactQ_BepaG_methods; return deactQ_BepaG_methods.__init__($tmp, $CONSTCONT($tmp, G_1)); } struct deactQ_BepaG_class deactQ_BepaG_methods; $R deactQ_mainD___init__ (deactQ_main self, $Cont C_cont, B_Env env) { self->env = env; return deactQ_ApaG_newact((($Cont)deactQ_L_22ContG_new(self, C_cont))); } #line 24 "test/src/deact.act" $R deactQ_mainD_myprocG_local (deactQ_main self, $Cont C_cont, B_int i) { #line 25 "test/src/deact.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(2, to$str("myproc"), i), B_None, B_None, B_None, B_None); #line 26 "test/src/deact.act" if ((((B_int)i)->val == 2LL)) { #line 27 "test/src/deact.act" ((B_Msg (*) (B_Env, B_int))self->env->$class->exit)(self->env, toB_int(0LL)); } return $R_CONT(C_cont, i); } B_Msg deactQ_mainD_myproc (deactQ_main self, B_int i) { return ((B_Msg)$ASYNC((($Actor)self), (($Cont)deactQ_L_23procG_new(self, i)))); } void deactQ_mainD___serialize__ (deactQ_main self, $Serial$state state) { $ActorG_methods.__serialize__(($Actor)self, state); $step_serialize(self->env, state); $step_serialize(self->a, state); $step_serialize(self->b, state); $step_serialize(self->x, state); $step_serialize(self->r, state); } deactQ_main deactQ_mainD___deserialize__ (deactQ_main self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct deactQ_main)); self->$class = &deactQ_mainG_methods; return self; } self = $DNEW(deactQ_main, state); } $ActorG_methods.__deserialize__(($Actor)self, state); self->env = $step_deserialize(state); self->a = $step_deserialize(state); self->b = $step_deserialize(state); self->x = $step_deserialize(state); self->r = $step_deserialize(state); return self; } void deactQ_mainD_GCfinalizer (void *obj, void *cdata) { deactQ_main self = (deactQ_main)obj; self->$class->__cleanup__(self); } $R deactQ_mainG_new($Cont G_1, B_Env G_2) { deactQ_main $tmp = acton_malloc(sizeof(struct deactQ_main)); $tmp->$class = &deactQ_mainG_methods; return deactQ_mainG_methods.__init__($tmp, $CONSTCONT($tmp, G_1), G_2); } struct deactQ_mainG_class deactQ_mainG_methods; $R deactQ_ApaG_newact ($Cont C_cont) { deactQ_Apa G_act = $NEWACTOR(deactQ_Apa); if ((void*)G_act->$class->__cleanup__ != (void*)$ActorD___cleanup__) $InstallFinalizer(G_act, deactQ_ApaD_GCfinalizer); return $AWAIT((($Cont)deactQ_L_25ContG_new(C_cont, G_act)), $ASYNC((($Actor)G_act), (($Cont)deactQ_L_26procG_new(G_act)))); } $R deactQ_BepaG_newact ($Cont C_cont) { deactQ_Bepa G_act = $NEWACTOR(deactQ_Bepa); if ((void*)G_act->$class->__cleanup__ != (void*)$ActorD___cleanup__) $InstallFinalizer(G_act, deactQ_BepaD_GCfinalizer); return $AWAIT((($Cont)deactQ_L_28ContG_new(C_cont, G_act)), $ASYNC((($Actor)G_act), (($Cont)deactQ_L_29procG_new(G_act)))); } $R deactQ_mainG_newact ($Cont C_cont, B_Env env) { deactQ_main G_act = $NEWACTOR(deactQ_main); if ((void*)G_act->$class->__cleanup__ != (void*)$ActorD___cleanup__) $InstallFinalizer(G_act, deactQ_mainD_GCfinalizer); return $AWAIT((($Cont)deactQ_L_31ContG_new(C_cont, G_act)), $ASYNC((($Actor)G_act), (($Cont)deactQ_L_32procG_new(G_act, env)))); } int deactQ_done$ = 0; void deactQ___init__ () { if (deactQ_done$) return; deactQ_done$ = 1; { deactQ_L_2ContG_methods.$GCINFO = "deactQ_L_2Cont"; deactQ_L_2ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; deactQ_L_2ContG_methods.__bool__ = (B_bool (*) (deactQ_L_2Cont))B_valueG_methods.__bool__; deactQ_L_2ContG_methods.__str__ = (B_str (*) (deactQ_L_2Cont))B_valueG_methods.__str__; deactQ_L_2ContG_methods.__repr__ = (B_str (*) (deactQ_L_2Cont))B_valueG_methods.__repr__; deactQ_L_2ContG_methods.__init__ = deactQ_L_2ContD___init__; deactQ_L_2ContG_methods.__call__ = deactQ_L_2ContD___call__; deactQ_L_2ContG_methods.__serialize__ = deactQ_L_2ContD___serialize__; deactQ_L_2ContG_methods.__deserialize__ = deactQ_L_2ContD___deserialize__; $register(&deactQ_L_2ContG_methods); } { deactQ_L_4actionG_methods.$GCINFO = "deactQ_L_4action"; deactQ_L_4actionG_methods.$superclass = ($SuperG_class)&$actionG_methods; deactQ_L_4actionG_methods.__bool__ = (B_bool (*) (deactQ_L_4action))B_valueG_methods.__bool__; deactQ_L_4actionG_methods.__str__ = (B_str (*) (deactQ_L_4action))B_valueG_methods.__str__; deactQ_L_4actionG_methods.__repr__ = (B_str (*) (deactQ_L_4action))B_valueG_methods.__repr__; deactQ_L_4actionG_methods.__init__ = deactQ_L_4actionD___init__; deactQ_L_4actionG_methods.__call__ = deactQ_L_4actionD___call__; deactQ_L_4actionG_methods.__exec__ = deactQ_L_4actionD___exec__; deactQ_L_4actionG_methods.__asyn__ = deactQ_L_4actionD___asyn__; deactQ_L_4actionG_methods.__serialize__ = deactQ_L_4actionD___serialize__; deactQ_L_4actionG_methods.__deserialize__ = deactQ_L_4actionD___deserialize__; $register(&deactQ_L_4actionG_methods); } { deactQ_L_6ContG_methods.$GCINFO = "deactQ_L_6Cont"; deactQ_L_6ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; deactQ_L_6ContG_methods.__bool__ = (B_bool (*) (deactQ_L_6Cont))B_valueG_methods.__bool__; deactQ_L_6ContG_methods.__str__ = (B_str (*) (deactQ_L_6Cont))B_valueG_methods.__str__; deactQ_L_6ContG_methods.__repr__ = (B_str (*) (deactQ_L_6Cont))B_valueG_methods.__repr__; deactQ_L_6ContG_methods.__init__ = deactQ_L_6ContD___init__; deactQ_L_6ContG_methods.__call__ = deactQ_L_6ContD___call__; deactQ_L_6ContG_methods.__serialize__ = deactQ_L_6ContD___serialize__; deactQ_L_6ContG_methods.__deserialize__ = deactQ_L_6ContD___deserialize__; $register(&deactQ_L_6ContG_methods); } { deactQ_L_7procG_methods.$GCINFO = "deactQ_L_7proc"; deactQ_L_7procG_methods.$superclass = ($SuperG_class)&$procG_methods; deactQ_L_7procG_methods.__bool__ = (B_bool (*) (deactQ_L_7proc))B_valueG_methods.__bool__; deactQ_L_7procG_methods.__str__ = (B_str (*) (deactQ_L_7proc))B_valueG_methods.__str__; deactQ_L_7procG_methods.__repr__ = (B_str (*) (deactQ_L_7proc))B_valueG_methods.__repr__; deactQ_L_7procG_methods.__init__ = deactQ_L_7procD___init__; deactQ_L_7procG_methods.__call__ = deactQ_L_7procD___call__; deactQ_L_7procG_methods.__exec__ = deactQ_L_7procD___exec__; deactQ_L_7procG_methods.__serialize__ = deactQ_L_7procD___serialize__; deactQ_L_7procG_methods.__deserialize__ = deactQ_L_7procD___deserialize__; $register(&deactQ_L_7procG_methods); } { deactQ_L_8procG_methods.$GCINFO = "deactQ_L_8proc"; deactQ_L_8procG_methods.$superclass = ($SuperG_class)&$procG_methods; deactQ_L_8procG_methods.__bool__ = (B_bool (*) (deactQ_L_8proc))B_valueG_methods.__bool__; deactQ_L_8procG_methods.__str__ = (B_str (*) (deactQ_L_8proc))B_valueG_methods.__str__; deactQ_L_8procG_methods.__repr__ = (B_str (*) (deactQ_L_8proc))B_valueG_methods.__repr__; deactQ_L_8procG_methods.__init__ = deactQ_L_8procD___init__; deactQ_L_8procG_methods.__call__ = deactQ_L_8procD___call__; deactQ_L_8procG_methods.__exec__ = deactQ_L_8procD___exec__; deactQ_L_8procG_methods.__serialize__ = deactQ_L_8procD___serialize__; deactQ_L_8procG_methods.__deserialize__ = deactQ_L_8procD___deserialize__; $register(&deactQ_L_8procG_methods); } { deactQ_L_9procG_methods.$GCINFO = "deactQ_L_9proc"; deactQ_L_9procG_methods.$superclass = ($SuperG_class)&$procG_methods; deactQ_L_9procG_methods.__bool__ = (B_bool (*) (deactQ_L_9proc))B_valueG_methods.__bool__; deactQ_L_9procG_methods.__str__ = (B_str (*) (deactQ_L_9proc))B_valueG_methods.__str__; deactQ_L_9procG_methods.__repr__ = (B_str (*) (deactQ_L_9proc))B_valueG_methods.__repr__; deactQ_L_9procG_methods.__init__ = deactQ_L_9procD___init__; deactQ_L_9procG_methods.__call__ = deactQ_L_9procD___call__; deactQ_L_9procG_methods.__exec__ = deactQ_L_9procD___exec__; deactQ_L_9procG_methods.__serialize__ = deactQ_L_9procD___serialize__; deactQ_L_9procG_methods.__deserialize__ = deactQ_L_9procD___deserialize__; $register(&deactQ_L_9procG_methods); } { deactQ_L_10procG_methods.$GCINFO = "deactQ_L_10proc"; deactQ_L_10procG_methods.$superclass = ($SuperG_class)&$procG_methods; deactQ_L_10procG_methods.__bool__ = (B_bool (*) (deactQ_L_10proc))B_valueG_methods.__bool__; deactQ_L_10procG_methods.__str__ = (B_str (*) (deactQ_L_10proc))B_valueG_methods.__str__; deactQ_L_10procG_methods.__repr__ = (B_str (*) (deactQ_L_10proc))B_valueG_methods.__repr__; deactQ_L_10procG_methods.__init__ = deactQ_L_10procD___init__; deactQ_L_10procG_methods.__call__ = deactQ_L_10procD___call__; deactQ_L_10procG_methods.__exec__ = deactQ_L_10procD___exec__; deactQ_L_10procG_methods.__serialize__ = deactQ_L_10procD___serialize__; deactQ_L_10procG_methods.__deserialize__ = deactQ_L_10procD___deserialize__; $register(&deactQ_L_10procG_methods); } { deactQ_L_14actionG_methods.$GCINFO = "deactQ_L_14action"; deactQ_L_14actionG_methods.$superclass = ($SuperG_class)&$actionG_methods; deactQ_L_14actionG_methods.__bool__ = (B_bool (*) (deactQ_L_14action))B_valueG_methods.__bool__; deactQ_L_14actionG_methods.__str__ = (B_str (*) (deactQ_L_14action))B_valueG_methods.__str__; deactQ_L_14actionG_methods.__repr__ = (B_str (*) (deactQ_L_14action))B_valueG_methods.__repr__; deactQ_L_14actionG_methods.__init__ = deactQ_L_14actionD___init__; deactQ_L_14actionG_methods.__call__ = deactQ_L_14actionD___call__; deactQ_L_14actionG_methods.__exec__ = deactQ_L_14actionD___exec__; deactQ_L_14actionG_methods.__asyn__ = deactQ_L_14actionD___asyn__; deactQ_L_14actionG_methods.__serialize__ = deactQ_L_14actionD___serialize__; deactQ_L_14actionG_methods.__deserialize__ = deactQ_L_14actionD___deserialize__; $register(&deactQ_L_14actionG_methods); } { deactQ_L_16actionG_methods.$GCINFO = "deactQ_L_16action"; deactQ_L_16actionG_methods.$superclass = ($SuperG_class)&$actionG_methods; deactQ_L_16actionG_methods.__bool__ = (B_bool (*) (deactQ_L_16action))B_valueG_methods.__bool__; deactQ_L_16actionG_methods.__str__ = (B_str (*) (deactQ_L_16action))B_valueG_methods.__str__; deactQ_L_16actionG_methods.__repr__ = (B_str (*) (deactQ_L_16action))B_valueG_methods.__repr__; deactQ_L_16actionG_methods.__init__ = deactQ_L_16actionD___init__; deactQ_L_16actionG_methods.__call__ = deactQ_L_16actionD___call__; deactQ_L_16actionG_methods.__exec__ = deactQ_L_16actionD___exec__; deactQ_L_16actionG_methods.__asyn__ = deactQ_L_16actionD___asyn__; deactQ_L_16actionG_methods.__serialize__ = deactQ_L_16actionD___serialize__; deactQ_L_16actionG_methods.__deserialize__ = deactQ_L_16actionD___deserialize__; $register(&deactQ_L_16actionG_methods); } { deactQ_L_19actionG_methods.$GCINFO = "deactQ_L_19action"; deactQ_L_19actionG_methods.$superclass = ($SuperG_class)&$actionG_methods; deactQ_L_19actionG_methods.__bool__ = (B_bool (*) (deactQ_L_19action))B_valueG_methods.__bool__; deactQ_L_19actionG_methods.__str__ = (B_str (*) (deactQ_L_19action))B_valueG_methods.__str__; deactQ_L_19actionG_methods.__repr__ = (B_str (*) (deactQ_L_19action))B_valueG_methods.__repr__; deactQ_L_19actionG_methods.__init__ = deactQ_L_19actionD___init__; deactQ_L_19actionG_methods.__call__ = deactQ_L_19actionD___call__; deactQ_L_19actionG_methods.__exec__ = deactQ_L_19actionD___exec__; deactQ_L_19actionG_methods.__asyn__ = deactQ_L_19actionD___asyn__; deactQ_L_19actionG_methods.__serialize__ = deactQ_L_19actionD___serialize__; deactQ_L_19actionG_methods.__deserialize__ = deactQ_L_19actionD___deserialize__; $register(&deactQ_L_19actionG_methods); } { deactQ_L_20ContG_methods.$GCINFO = "deactQ_L_20Cont"; deactQ_L_20ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; deactQ_L_20ContG_methods.__bool__ = (B_bool (*) (deactQ_L_20Cont))B_valueG_methods.__bool__; deactQ_L_20ContG_methods.__str__ = (B_str (*) (deactQ_L_20Cont))B_valueG_methods.__str__; deactQ_L_20ContG_methods.__repr__ = (B_str (*) (deactQ_L_20Cont))B_valueG_methods.__repr__; deactQ_L_20ContG_methods.__init__ = deactQ_L_20ContD___init__; deactQ_L_20ContG_methods.__call__ = deactQ_L_20ContD___call__; deactQ_L_20ContG_methods.__serialize__ = deactQ_L_20ContD___serialize__; deactQ_L_20ContG_methods.__deserialize__ = deactQ_L_20ContD___deserialize__; $register(&deactQ_L_20ContG_methods); } { deactQ_L_21ContG_methods.$GCINFO = "deactQ_L_21Cont"; deactQ_L_21ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; deactQ_L_21ContG_methods.__bool__ = (B_bool (*) (deactQ_L_21Cont))B_valueG_methods.__bool__; deactQ_L_21ContG_methods.__str__ = (B_str (*) (deactQ_L_21Cont))B_valueG_methods.__str__; deactQ_L_21ContG_methods.__repr__ = (B_str (*) (deactQ_L_21Cont))B_valueG_methods.__repr__; deactQ_L_21ContG_methods.__init__ = deactQ_L_21ContD___init__; deactQ_L_21ContG_methods.__call__ = deactQ_L_21ContD___call__; deactQ_L_21ContG_methods.__serialize__ = deactQ_L_21ContD___serialize__; deactQ_L_21ContG_methods.__deserialize__ = deactQ_L_21ContD___deserialize__; $register(&deactQ_L_21ContG_methods); } { deactQ_L_22ContG_methods.$GCINFO = "deactQ_L_22Cont"; deactQ_L_22ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; deactQ_L_22ContG_methods.__bool__ = (B_bool (*) (deactQ_L_22Cont))B_valueG_methods.__bool__; deactQ_L_22ContG_methods.__str__ = (B_str (*) (deactQ_L_22Cont))B_valueG_methods.__str__; deactQ_L_22ContG_methods.__repr__ = (B_str (*) (deactQ_L_22Cont))B_valueG_methods.__repr__; deactQ_L_22ContG_methods.__init__ = deactQ_L_22ContD___init__; deactQ_L_22ContG_methods.__call__ = deactQ_L_22ContD___call__; deactQ_L_22ContG_methods.__serialize__ = deactQ_L_22ContD___serialize__; deactQ_L_22ContG_methods.__deserialize__ = deactQ_L_22ContD___deserialize__; $register(&deactQ_L_22ContG_methods); } { deactQ_L_23procG_methods.$GCINFO = "deactQ_L_23proc"; deactQ_L_23procG_methods.$superclass = ($SuperG_class)&$procG_methods; deactQ_L_23procG_methods.__bool__ = (B_bool (*) (deactQ_L_23proc))B_valueG_methods.__bool__; deactQ_L_23procG_methods.__str__ = (B_str (*) (deactQ_L_23proc))B_valueG_methods.__str__; deactQ_L_23procG_methods.__repr__ = (B_str (*) (deactQ_L_23proc))B_valueG_methods.__repr__; deactQ_L_23procG_methods.__init__ = deactQ_L_23procD___init__; deactQ_L_23procG_methods.__call__ = deactQ_L_23procD___call__; deactQ_L_23procG_methods.__exec__ = deactQ_L_23procD___exec__; deactQ_L_23procG_methods.__serialize__ = deactQ_L_23procD___serialize__; deactQ_L_23procG_methods.__deserialize__ = deactQ_L_23procD___deserialize__; $register(&deactQ_L_23procG_methods); } { deactQ_L_25ContG_methods.$GCINFO = "deactQ_L_25Cont"; deactQ_L_25ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; deactQ_L_25ContG_methods.__bool__ = (B_bool (*) (deactQ_L_25Cont))B_valueG_methods.__bool__; deactQ_L_25ContG_methods.__str__ = (B_str (*) (deactQ_L_25Cont))B_valueG_methods.__str__; deactQ_L_25ContG_methods.__repr__ = (B_str (*) (deactQ_L_25Cont))B_valueG_methods.__repr__; deactQ_L_25ContG_methods.__init__ = deactQ_L_25ContD___init__; deactQ_L_25ContG_methods.__call__ = deactQ_L_25ContD___call__; deactQ_L_25ContG_methods.__serialize__ = deactQ_L_25ContD___serialize__; deactQ_L_25ContG_methods.__deserialize__ = deactQ_L_25ContD___deserialize__; $register(&deactQ_L_25ContG_methods); } { deactQ_L_26procG_methods.$GCINFO = "deactQ_L_26proc"; deactQ_L_26procG_methods.$superclass = ($SuperG_class)&$procG_methods; deactQ_L_26procG_methods.__bool__ = (B_bool (*) (deactQ_L_26proc))B_valueG_methods.__bool__; deactQ_L_26procG_methods.__str__ = (B_str (*) (deactQ_L_26proc))B_valueG_methods.__str__; deactQ_L_26procG_methods.__repr__ = (B_str (*) (deactQ_L_26proc))B_valueG_methods.__repr__; deactQ_L_26procG_methods.__init__ = deactQ_L_26procD___init__; deactQ_L_26procG_methods.__call__ = deactQ_L_26procD___call__; deactQ_L_26procG_methods.__exec__ = deactQ_L_26procD___exec__; deactQ_L_26procG_methods.__serialize__ = deactQ_L_26procD___serialize__; deactQ_L_26procG_methods.__deserialize__ = deactQ_L_26procD___deserialize__; $register(&deactQ_L_26procG_methods); } { deactQ_L_28ContG_methods.$GCINFO = "deactQ_L_28Cont"; deactQ_L_28ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; deactQ_L_28ContG_methods.__bool__ = (B_bool (*) (deactQ_L_28Cont))B_valueG_methods.__bool__; deactQ_L_28ContG_methods.__str__ = (B_str (*) (deactQ_L_28Cont))B_valueG_methods.__str__; deactQ_L_28ContG_methods.__repr__ = (B_str (*) (deactQ_L_28Cont))B_valueG_methods.__repr__; deactQ_L_28ContG_methods.__init__ = deactQ_L_28ContD___init__; deactQ_L_28ContG_methods.__call__ = deactQ_L_28ContD___call__; deactQ_L_28ContG_methods.__serialize__ = deactQ_L_28ContD___serialize__; deactQ_L_28ContG_methods.__deserialize__ = deactQ_L_28ContD___deserialize__; $register(&deactQ_L_28ContG_methods); } { deactQ_L_29procG_methods.$GCINFO = "deactQ_L_29proc"; deactQ_L_29procG_methods.$superclass = ($SuperG_class)&$procG_methods; deactQ_L_29procG_methods.__bool__ = (B_bool (*) (deactQ_L_29proc))B_valueG_methods.__bool__; deactQ_L_29procG_methods.__str__ = (B_str (*) (deactQ_L_29proc))B_valueG_methods.__str__; deactQ_L_29procG_methods.__repr__ = (B_str (*) (deactQ_L_29proc))B_valueG_methods.__repr__; deactQ_L_29procG_methods.__init__ = deactQ_L_29procD___init__; deactQ_L_29procG_methods.__call__ = deactQ_L_29procD___call__; deactQ_L_29procG_methods.__exec__ = deactQ_L_29procD___exec__; deactQ_L_29procG_methods.__serialize__ = deactQ_L_29procD___serialize__; deactQ_L_29procG_methods.__deserialize__ = deactQ_L_29procD___deserialize__; $register(&deactQ_L_29procG_methods); } { deactQ_L_31ContG_methods.$GCINFO = "deactQ_L_31Cont"; deactQ_L_31ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; deactQ_L_31ContG_methods.__bool__ = (B_bool (*) (deactQ_L_31Cont))B_valueG_methods.__bool__; deactQ_L_31ContG_methods.__str__ = (B_str (*) (deactQ_L_31Cont))B_valueG_methods.__str__; deactQ_L_31ContG_methods.__repr__ = (B_str (*) (deactQ_L_31Cont))B_valueG_methods.__repr__; deactQ_L_31ContG_methods.__init__ = deactQ_L_31ContD___init__; deactQ_L_31ContG_methods.__call__ = deactQ_L_31ContD___call__; deactQ_L_31ContG_methods.__serialize__ = deactQ_L_31ContD___serialize__; deactQ_L_31ContG_methods.__deserialize__ = deactQ_L_31ContD___deserialize__; $register(&deactQ_L_31ContG_methods); } { deactQ_L_32procG_methods.$GCINFO = "deactQ_L_32proc"; deactQ_L_32procG_methods.$superclass = ($SuperG_class)&$procG_methods; deactQ_L_32procG_methods.__bool__ = (B_bool (*) (deactQ_L_32proc))B_valueG_methods.__bool__; deactQ_L_32procG_methods.__str__ = (B_str (*) (deactQ_L_32proc))B_valueG_methods.__str__; deactQ_L_32procG_methods.__repr__ = (B_str (*) (deactQ_L_32proc))B_valueG_methods.__repr__; deactQ_L_32procG_methods.__init__ = deactQ_L_32procD___init__; deactQ_L_32procG_methods.__call__ = deactQ_L_32procD___call__; deactQ_L_32procG_methods.__exec__ = deactQ_L_32procD___exec__; deactQ_L_32procG_methods.__serialize__ = deactQ_L_32procD___serialize__; deactQ_L_32procG_methods.__deserialize__ = deactQ_L_32procD___deserialize__; $register(&deactQ_L_32procG_methods); } { deactQ_ApaG_methods.$GCINFO = "deactQ_Apa"; deactQ_ApaG_methods.$superclass = ($SuperG_class)&$ActorG_methods; deactQ_ApaG_methods.__bool__ = (B_bool (*) (deactQ_Apa))$ActorG_methods.__bool__; deactQ_ApaG_methods.__str__ = (B_str (*) (deactQ_Apa))$ActorG_methods.__str__; deactQ_ApaG_methods.__repr__ = (B_str (*) (deactQ_Apa))$ActorG_methods.__repr__; deactQ_ApaG_methods.__resume__ = (B_NoneType (*) (deactQ_Apa))$ActorG_methods.__resume__; deactQ_ApaG_methods.__cleanup__ = (B_NoneType (*) (deactQ_Apa))$ActorG_methods.__cleanup__; deactQ_ApaG_methods.__init__ = deactQ_ApaD___init__; deactQ_ApaG_methods.setupG_local = deactQ_ApaD_setupG_local; deactQ_ApaG_methods.computeG_local = deactQ_ApaD_computeG_local; deactQ_ApaG_methods.noticeG_local = deactQ_ApaD_noticeG_local; deactQ_ApaG_methods.setup = deactQ_ApaD_setup; deactQ_ApaG_methods.compute = deactQ_ApaD_compute; deactQ_ApaG_methods.notice = deactQ_ApaD_notice; deactQ_ApaG_methods.__serialize__ = deactQ_ApaD___serialize__; deactQ_ApaG_methods.__deserialize__ = deactQ_ApaD___deserialize__; $register(&deactQ_ApaG_methods); } { deactQ_BepaG_methods.$GCINFO = "deactQ_Bepa"; deactQ_BepaG_methods.$superclass = ($SuperG_class)&$ActorG_methods; deactQ_BepaG_methods.__bool__ = (B_bool (*) (deactQ_Bepa))$ActorG_methods.__bool__; deactQ_BepaG_methods.__str__ = (B_str (*) (deactQ_Bepa))$ActorG_methods.__str__; deactQ_BepaG_methods.__repr__ = (B_str (*) (deactQ_Bepa))$ActorG_methods.__repr__; deactQ_BepaG_methods.__resume__ = (B_NoneType (*) (deactQ_Bepa))$ActorG_methods.__resume__; deactQ_BepaG_methods.__cleanup__ = (B_NoneType (*) (deactQ_Bepa))$ActorG_methods.__cleanup__; deactQ_BepaG_methods.__init__ = deactQ_BepaD___init__; deactQ_BepaG_methods.callbackG_local = deactQ_BepaD_callbackG_local; deactQ_BepaG_methods.callback = deactQ_BepaD_callback; deactQ_BepaG_methods.__serialize__ = deactQ_BepaD___serialize__; deactQ_BepaG_methods.__deserialize__ = deactQ_BepaD___deserialize__; $register(&deactQ_BepaG_methods); } { deactQ_mainG_methods.$GCINFO = "deactQ_main"; deactQ_mainG_methods.$superclass = ($SuperG_class)&$ActorG_methods; deactQ_mainG_methods.__bool__ = (B_bool (*) (deactQ_main))$ActorG_methods.__bool__; deactQ_mainG_methods.__str__ = (B_str (*) (deactQ_main))$ActorG_methods.__str__; deactQ_mainG_methods.__repr__ = (B_str (*) (deactQ_main))$ActorG_methods.__repr__; deactQ_mainG_methods.__resume__ = (B_NoneType (*) (deactQ_main))$ActorG_methods.__resume__; deactQ_mainG_methods.__cleanup__ = (B_NoneType (*) (deactQ_main))$ActorG_methods.__cleanup__; deactQ_mainG_methods.__init__ = deactQ_mainD___init__; deactQ_mainG_methods.myprocG_local = deactQ_mainD_myprocG_local; deactQ_mainG_methods.myproc = deactQ_mainD_myproc; deactQ_mainG_methods.__serialize__ = deactQ_mainD___serialize__; deactQ_mainG_methods.__deserialize__ = deactQ_mainD___deserialize__; $register(&deactQ_mainG_methods); } } ================================================ FILE: compiler/lib/test/9-codegen/deact.h ================================================ /* Acton impl hash: test-hash */ #pragma once #include "builtin/builtin.h" #include "rts/rts.h" struct deactQ_L_2Cont; struct deactQ_L_4action; struct deactQ_L_6Cont; struct deactQ_L_7proc; struct deactQ_L_8proc; struct deactQ_L_9proc; struct deactQ_L_10proc; struct deactQ_L_14action; struct deactQ_L_16action; struct deactQ_L_19action; struct deactQ_L_20Cont; struct deactQ_L_21Cont; struct deactQ_L_22Cont; struct deactQ_L_23proc; struct deactQ_L_25Cont; struct deactQ_L_26proc; struct deactQ_L_28Cont; struct deactQ_L_29proc; struct deactQ_L_31Cont; struct deactQ_L_32proc; struct deactQ_Apa; struct deactQ_Bepa; struct deactQ_main; typedef struct deactQ_L_2Cont *deactQ_L_2Cont; typedef struct deactQ_L_4action *deactQ_L_4action; typedef struct deactQ_L_6Cont *deactQ_L_6Cont; typedef struct deactQ_L_7proc *deactQ_L_7proc; typedef struct deactQ_L_8proc *deactQ_L_8proc; typedef struct deactQ_L_9proc *deactQ_L_9proc; typedef struct deactQ_L_10proc *deactQ_L_10proc; typedef struct deactQ_L_14action *deactQ_L_14action; typedef struct deactQ_L_16action *deactQ_L_16action; typedef struct deactQ_L_19action *deactQ_L_19action; typedef struct deactQ_L_20Cont *deactQ_L_20Cont; typedef struct deactQ_L_21Cont *deactQ_L_21Cont; typedef struct deactQ_L_22Cont *deactQ_L_22Cont; typedef struct deactQ_L_23proc *deactQ_L_23proc; typedef struct deactQ_L_25Cont *deactQ_L_25Cont; typedef struct deactQ_L_26proc *deactQ_L_26proc; typedef struct deactQ_L_28Cont *deactQ_L_28Cont; typedef struct deactQ_L_29proc *deactQ_L_29proc; typedef struct deactQ_L_31Cont *deactQ_L_31Cont; typedef struct deactQ_L_32proc *deactQ_L_32proc; typedef struct deactQ_Apa *deactQ_Apa; typedef struct deactQ_Bepa *deactQ_Bepa; typedef struct deactQ_main *deactQ_main; $R deactQ_L_1C_1cont ($Cont, B_NoneType); struct deactQ_L_2ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_2Cont, $Cont); void (*__serialize__) (deactQ_L_2Cont, $Serial$state); deactQ_L_2Cont (*__deserialize__) (deactQ_L_2Cont, $Serial$state); B_bool (*__bool__) (deactQ_L_2Cont); B_str (*__str__) (deactQ_L_2Cont); B_str (*__repr__) (deactQ_L_2Cont); $R (*__call__) (deactQ_L_2Cont, B_NoneType); }; struct deactQ_L_2Cont { struct deactQ_L_2ContG_class *$class; $Cont C_cont; }; struct deactQ_L_4actionG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_4action, deactQ_Apa); void (*__serialize__) (deactQ_L_4action, $Serial$state); deactQ_L_4action (*__deserialize__) (deactQ_L_4action, $Serial$state); B_bool (*__bool__) (deactQ_L_4action); B_str (*__str__) (deactQ_L_4action); B_str (*__repr__) (deactQ_L_4action); $R (*__call__) (deactQ_L_4action, $Cont, B_int); $R (*__exec__) (deactQ_L_4action, $Cont, B_int); B_Msg (*__asyn__) (deactQ_L_4action, B_int); }; struct deactQ_L_4action { struct deactQ_L_4actionG_class *$class; deactQ_Apa L_3obj; }; $R deactQ_U_L_5C_3cont ($action, $Cont, int64_t); $R deactQ_L_5C_3cont ($action, $Cont, B_int); struct deactQ_L_6ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_6Cont, $action, $Cont); void (*__serialize__) (deactQ_L_6Cont, $Serial$state); deactQ_L_6Cont (*__deserialize__) (deactQ_L_6Cont, $Serial$state); B_bool (*__bool__) (deactQ_L_6Cont); B_str (*__str__) (deactQ_L_6Cont); B_str (*__repr__) (deactQ_L_6Cont); $R (*__call__) (deactQ_L_6Cont, B_int); }; struct deactQ_L_6Cont { struct deactQ_L_6ContG_class *$class; $action cb; $Cont C_cont; }; struct deactQ_L_7procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_7proc, deactQ_Apa, $action); void (*__serialize__) (deactQ_L_7proc, $Serial$state); deactQ_L_7proc (*__deserialize__) (deactQ_L_7proc, $Serial$state); B_bool (*__bool__) (deactQ_L_7proc); B_str (*__str__) (deactQ_L_7proc); B_str (*__repr__) (deactQ_L_7proc); $R (*__call__) (deactQ_L_7proc, $Cont); $R (*__exec__) (deactQ_L_7proc, $Cont); }; struct deactQ_L_7proc { struct deactQ_L_7procG_class *$class; deactQ_Apa self; $action cb; }; struct deactQ_L_8procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_8proc, deactQ_Apa, $action); void (*__serialize__) (deactQ_L_8proc, $Serial$state); deactQ_L_8proc (*__deserialize__) (deactQ_L_8proc, $Serial$state); B_bool (*__bool__) (deactQ_L_8proc); B_str (*__str__) (deactQ_L_8proc); B_str (*__repr__) (deactQ_L_8proc); $R (*__call__) (deactQ_L_8proc, $Cont); $R (*__exec__) (deactQ_L_8proc, $Cont); }; struct deactQ_L_8proc { struct deactQ_L_8procG_class *$class; deactQ_Apa self; $action cb; }; struct deactQ_L_9procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_9proc, deactQ_Apa, B_int); void (*__serialize__) (deactQ_L_9proc, $Serial$state); deactQ_L_9proc (*__deserialize__) (deactQ_L_9proc, $Serial$state); B_bool (*__bool__) (deactQ_L_9proc); B_str (*__str__) (deactQ_L_9proc); B_str (*__repr__) (deactQ_L_9proc); $R (*__call__) (deactQ_L_9proc, $Cont); $R (*__exec__) (deactQ_L_9proc, $Cont); }; struct deactQ_L_9proc { struct deactQ_L_9procG_class *$class; deactQ_Apa self; B_int i; }; struct deactQ_L_10procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_10proc, deactQ_Bepa, B_int); void (*__serialize__) (deactQ_L_10proc, $Serial$state); deactQ_L_10proc (*__deserialize__) (deactQ_L_10proc, $Serial$state); B_bool (*__bool__) (deactQ_L_10proc); B_str (*__str__) (deactQ_L_10proc); B_str (*__repr__) (deactQ_L_10proc); $R (*__call__) (deactQ_L_10proc, $Cont); $R (*__exec__) (deactQ_L_10proc, $Cont); }; struct deactQ_L_10proc { struct deactQ_L_10procG_class *$class; deactQ_Bepa self; B_int i; }; struct deactQ_L_14actionG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_14action, deactQ_Apa); void (*__serialize__) (deactQ_L_14action, $Serial$state); deactQ_L_14action (*__deserialize__) (deactQ_L_14action, $Serial$state); B_bool (*__bool__) (deactQ_L_14action); B_str (*__str__) (deactQ_L_14action); B_str (*__repr__) (deactQ_L_14action); $R (*__call__) (deactQ_L_14action, $Cont, B_int); $R (*__exec__) (deactQ_L_14action, $Cont, B_int); B_Msg (*__asyn__) (deactQ_L_14action, B_int); }; struct deactQ_L_14action { struct deactQ_L_14actionG_class *$class; deactQ_Apa L_13obj; }; struct deactQ_L_16actionG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_16action, deactQ_Bepa); void (*__serialize__) (deactQ_L_16action, $Serial$state); deactQ_L_16action (*__deserialize__) (deactQ_L_16action, $Serial$state); B_bool (*__bool__) (deactQ_L_16action); B_str (*__str__) (deactQ_L_16action); B_str (*__repr__) (deactQ_L_16action); $R (*__call__) (deactQ_L_16action, $Cont, B_int); $R (*__exec__) (deactQ_L_16action, $Cont, B_int); B_Msg (*__asyn__) (deactQ_L_16action, B_int); }; struct deactQ_L_16action { struct deactQ_L_16actionG_class *$class; deactQ_Bepa L_15obj; }; struct deactQ_L_19actionG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_19action, deactQ_main); void (*__serialize__) (deactQ_L_19action, $Serial$state); deactQ_L_19action (*__deserialize__) (deactQ_L_19action, $Serial$state); B_bool (*__bool__) (deactQ_L_19action); B_str (*__str__) (deactQ_L_19action); B_str (*__repr__) (deactQ_L_19action); $R (*__call__) (deactQ_L_19action, $Cont, B_int); $R (*__exec__) (deactQ_L_19action, $Cont, B_int); B_Msg (*__asyn__) (deactQ_L_19action, B_int); }; struct deactQ_L_19action { struct deactQ_L_19actionG_class *$class; deactQ_main L_18obj; }; $R deactQ_U_1L_17C_9cont (deactQ_main, $Cont, int64_t); $R deactQ_L_17C_9cont (deactQ_main, $Cont, B_int); struct deactQ_L_20ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_20Cont, deactQ_main, $Cont); void (*__serialize__) (deactQ_L_20Cont, $Serial$state); deactQ_L_20Cont (*__deserialize__) (deactQ_L_20Cont, $Serial$state); B_bool (*__bool__) (deactQ_L_20Cont); B_str (*__str__) (deactQ_L_20Cont); B_str (*__repr__) (deactQ_L_20Cont); $R (*__call__) (deactQ_L_20Cont, B_int); }; struct deactQ_L_20Cont { struct deactQ_L_20ContG_class *$class; deactQ_main self; $Cont C_cont; }; $R deactQ_L_12C_7cont (deactQ_main, $Cont, deactQ_Bepa); struct deactQ_L_21ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_21Cont, deactQ_main, $Cont); void (*__serialize__) (deactQ_L_21Cont, $Serial$state); deactQ_L_21Cont (*__deserialize__) (deactQ_L_21Cont, $Serial$state); B_bool (*__bool__) (deactQ_L_21Cont); B_str (*__str__) (deactQ_L_21Cont); B_str (*__repr__) (deactQ_L_21Cont); $R (*__call__) (deactQ_L_21Cont, deactQ_Bepa); }; struct deactQ_L_21Cont { struct deactQ_L_21ContG_class *$class; deactQ_main self; $Cont C_cont; }; $R deactQ_L_11C_5cont (deactQ_main, $Cont, deactQ_Apa); struct deactQ_L_22ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_22Cont, deactQ_main, $Cont); void (*__serialize__) (deactQ_L_22Cont, $Serial$state); deactQ_L_22Cont (*__deserialize__) (deactQ_L_22Cont, $Serial$state); B_bool (*__bool__) (deactQ_L_22Cont); B_str (*__str__) (deactQ_L_22Cont); B_str (*__repr__) (deactQ_L_22Cont); $R (*__call__) (deactQ_L_22Cont, deactQ_Apa); }; struct deactQ_L_22Cont { struct deactQ_L_22ContG_class *$class; deactQ_main self; $Cont C_cont; }; struct deactQ_L_23procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_23proc, deactQ_main, B_int); void (*__serialize__) (deactQ_L_23proc, $Serial$state); deactQ_L_23proc (*__deserialize__) (deactQ_L_23proc, $Serial$state); B_bool (*__bool__) (deactQ_L_23proc); B_str (*__str__) (deactQ_L_23proc); B_str (*__repr__) (deactQ_L_23proc); $R (*__call__) (deactQ_L_23proc, $Cont); $R (*__exec__) (deactQ_L_23proc, $Cont); }; struct deactQ_L_23proc { struct deactQ_L_23procG_class *$class; deactQ_main self; B_int i; }; $R deactQ_L_24C_11cont ($Cont, deactQ_Apa, B_NoneType); struct deactQ_L_25ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_25Cont, $Cont, deactQ_Apa); void (*__serialize__) (deactQ_L_25Cont, $Serial$state); deactQ_L_25Cont (*__deserialize__) (deactQ_L_25Cont, $Serial$state); B_bool (*__bool__) (deactQ_L_25Cont); B_str (*__str__) (deactQ_L_25Cont); B_str (*__repr__) (deactQ_L_25Cont); $R (*__call__) (deactQ_L_25Cont, B_NoneType); }; struct deactQ_L_25Cont { struct deactQ_L_25ContG_class *$class; $Cont C_cont; deactQ_Apa G_act; }; struct deactQ_L_26procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_26proc, deactQ_Apa); void (*__serialize__) (deactQ_L_26proc, $Serial$state); deactQ_L_26proc (*__deserialize__) (deactQ_L_26proc, $Serial$state); B_bool (*__bool__) (deactQ_L_26proc); B_str (*__str__) (deactQ_L_26proc); B_str (*__repr__) (deactQ_L_26proc); $R (*__call__) (deactQ_L_26proc, $Cont); $R (*__exec__) (deactQ_L_26proc, $Cont); }; struct deactQ_L_26proc { struct deactQ_L_26procG_class *$class; deactQ_Apa G_act; }; $R deactQ_L_27C_13cont ($Cont, deactQ_Bepa, B_NoneType); struct deactQ_L_28ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_28Cont, $Cont, deactQ_Bepa); void (*__serialize__) (deactQ_L_28Cont, $Serial$state); deactQ_L_28Cont (*__deserialize__) (deactQ_L_28Cont, $Serial$state); B_bool (*__bool__) (deactQ_L_28Cont); B_str (*__str__) (deactQ_L_28Cont); B_str (*__repr__) (deactQ_L_28Cont); $R (*__call__) (deactQ_L_28Cont, B_NoneType); }; struct deactQ_L_28Cont { struct deactQ_L_28ContG_class *$class; $Cont C_cont; deactQ_Bepa G_act; }; struct deactQ_L_29procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_29proc, deactQ_Bepa); void (*__serialize__) (deactQ_L_29proc, $Serial$state); deactQ_L_29proc (*__deserialize__) (deactQ_L_29proc, $Serial$state); B_bool (*__bool__) (deactQ_L_29proc); B_str (*__str__) (deactQ_L_29proc); B_str (*__repr__) (deactQ_L_29proc); $R (*__call__) (deactQ_L_29proc, $Cont); $R (*__exec__) (deactQ_L_29proc, $Cont); }; struct deactQ_L_29proc { struct deactQ_L_29procG_class *$class; deactQ_Bepa G_act; }; $R deactQ_L_30C_15cont ($Cont, deactQ_main, B_NoneType); struct deactQ_L_31ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_31Cont, $Cont, deactQ_main); void (*__serialize__) (deactQ_L_31Cont, $Serial$state); deactQ_L_31Cont (*__deserialize__) (deactQ_L_31Cont, $Serial$state); B_bool (*__bool__) (deactQ_L_31Cont); B_str (*__str__) (deactQ_L_31Cont); B_str (*__repr__) (deactQ_L_31Cont); $R (*__call__) (deactQ_L_31Cont, B_NoneType); }; struct deactQ_L_31Cont { struct deactQ_L_31ContG_class *$class; $Cont C_cont; deactQ_main G_act; }; struct deactQ_L_32procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (deactQ_L_32proc, deactQ_main, B_Env); void (*__serialize__) (deactQ_L_32proc, $Serial$state); deactQ_L_32proc (*__deserialize__) (deactQ_L_32proc, $Serial$state); B_bool (*__bool__) (deactQ_L_32proc); B_str (*__str__) (deactQ_L_32proc); B_str (*__repr__) (deactQ_L_32proc); $R (*__call__) (deactQ_L_32proc, $Cont); $R (*__exec__) (deactQ_L_32proc, $Cont); }; struct deactQ_L_32proc { struct deactQ_L_32procG_class *$class; deactQ_main G_act; B_Env env; }; struct deactQ_ApaG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; $R (*__init__) (deactQ_Apa, $Cont); void (*__serialize__) (deactQ_Apa, $Serial$state); deactQ_Apa (*__deserialize__) (deactQ_Apa, $Serial$state); B_bool (*__bool__) (deactQ_Apa); B_str (*__str__) (deactQ_Apa); B_str (*__repr__) (deactQ_Apa); B_NoneType (*__resume__) (deactQ_Apa); B_NoneType (*__cleanup__) (deactQ_Apa); $R (*setupG_local) (deactQ_Apa, $Cont, $action); $R (*computeG_local) (deactQ_Apa, $Cont, $action); $R (*noticeG_local) (deactQ_Apa, $Cont, B_int); B_Msg (*setup) (deactQ_Apa, $action); B_Msg (*compute) (deactQ_Apa, $action); B_Msg (*notice) (deactQ_Apa, B_int); }; struct deactQ_Apa { struct deactQ_ApaG_class *$class; $Actor $next; B_Msg $msg; B_Msg $msg_tail; $Lock $msg_lock; $int64 $affinity; B_Msg $outgoing; B_Msg $waitsfor; $int64 $consume_hd; $Catcher $catcher; $long $globkey; }; struct deactQ_BepaG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; $R (*__init__) (deactQ_Bepa, $Cont); void (*__serialize__) (deactQ_Bepa, $Serial$state); deactQ_Bepa (*__deserialize__) (deactQ_Bepa, $Serial$state); B_bool (*__bool__) (deactQ_Bepa); B_str (*__str__) (deactQ_Bepa); B_str (*__repr__) (deactQ_Bepa); B_NoneType (*__resume__) (deactQ_Bepa); B_NoneType (*__cleanup__) (deactQ_Bepa); $R (*callbackG_local) (deactQ_Bepa, $Cont, B_int); B_Msg (*callback) (deactQ_Bepa, B_int); }; struct deactQ_Bepa { struct deactQ_BepaG_class *$class; $Actor $next; B_Msg $msg; B_Msg $msg_tail; $Lock $msg_lock; $int64 $affinity; B_Msg $outgoing; B_Msg $waitsfor; $int64 $consume_hd; $Catcher $catcher; $long $globkey; }; struct deactQ_mainG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; $R (*__init__) (deactQ_main, $Cont, B_Env); void (*__serialize__) (deactQ_main, $Serial$state); deactQ_main (*__deserialize__) (deactQ_main, $Serial$state); B_bool (*__bool__) (deactQ_main); B_str (*__str__) (deactQ_main); B_str (*__repr__) (deactQ_main); B_NoneType (*__resume__) (deactQ_main); B_NoneType (*__cleanup__) (deactQ_main); $R (*myprocG_local) (deactQ_main, $Cont, B_int); B_Msg (*myproc) (deactQ_main, B_int); }; struct deactQ_main { struct deactQ_mainG_class *$class; $Actor $next; B_Msg $msg; B_Msg $msg_tail; $Lock $msg_lock; $int64 $affinity; B_Msg $outgoing; B_Msg $waitsfor; $int64 $consume_hd; $Catcher $catcher; $long $globkey; B_Env env; deactQ_Apa a; deactQ_Bepa b; B_Msg x; B_int r; }; $R deactQ_ApaG_newact ($Cont); $R deactQ_BepaG_newact ($Cont); $R deactQ_mainG_newact ($Cont, B_Env); extern struct deactQ_L_2ContG_class deactQ_L_2ContG_methods; deactQ_L_2Cont deactQ_L_2ContG_new($Cont); extern struct deactQ_L_4actionG_class deactQ_L_4actionG_methods; deactQ_L_4action deactQ_L_4actionG_new(deactQ_Apa); extern struct deactQ_L_6ContG_class deactQ_L_6ContG_methods; deactQ_L_6Cont deactQ_L_6ContG_new($action, $Cont); extern struct deactQ_L_7procG_class deactQ_L_7procG_methods; deactQ_L_7proc deactQ_L_7procG_new(deactQ_Apa, $action); extern struct deactQ_L_8procG_class deactQ_L_8procG_methods; deactQ_L_8proc deactQ_L_8procG_new(deactQ_Apa, $action); extern struct deactQ_L_9procG_class deactQ_L_9procG_methods; deactQ_L_9proc deactQ_L_9procG_new(deactQ_Apa, B_int); extern struct deactQ_L_10procG_class deactQ_L_10procG_methods; deactQ_L_10proc deactQ_L_10procG_new(deactQ_Bepa, B_int); extern struct deactQ_L_14actionG_class deactQ_L_14actionG_methods; deactQ_L_14action deactQ_L_14actionG_new(deactQ_Apa); extern struct deactQ_L_16actionG_class deactQ_L_16actionG_methods; deactQ_L_16action deactQ_L_16actionG_new(deactQ_Bepa); extern struct deactQ_L_19actionG_class deactQ_L_19actionG_methods; deactQ_L_19action deactQ_L_19actionG_new(deactQ_main); extern struct deactQ_L_20ContG_class deactQ_L_20ContG_methods; deactQ_L_20Cont deactQ_L_20ContG_new(deactQ_main, $Cont); extern struct deactQ_L_21ContG_class deactQ_L_21ContG_methods; deactQ_L_21Cont deactQ_L_21ContG_new(deactQ_main, $Cont); extern struct deactQ_L_22ContG_class deactQ_L_22ContG_methods; deactQ_L_22Cont deactQ_L_22ContG_new(deactQ_main, $Cont); extern struct deactQ_L_23procG_class deactQ_L_23procG_methods; deactQ_L_23proc deactQ_L_23procG_new(deactQ_main, B_int); extern struct deactQ_L_25ContG_class deactQ_L_25ContG_methods; deactQ_L_25Cont deactQ_L_25ContG_new($Cont, deactQ_Apa); extern struct deactQ_L_26procG_class deactQ_L_26procG_methods; deactQ_L_26proc deactQ_L_26procG_new(deactQ_Apa); extern struct deactQ_L_28ContG_class deactQ_L_28ContG_methods; deactQ_L_28Cont deactQ_L_28ContG_new($Cont, deactQ_Bepa); extern struct deactQ_L_29procG_class deactQ_L_29procG_methods; deactQ_L_29proc deactQ_L_29procG_new(deactQ_Bepa); extern struct deactQ_L_31ContG_class deactQ_L_31ContG_methods; deactQ_L_31Cont deactQ_L_31ContG_new($Cont, deactQ_main); extern struct deactQ_L_32procG_class deactQ_L_32procG_methods; deactQ_L_32proc deactQ_L_32procG_new(deactQ_main, B_Env); extern struct deactQ_ApaG_class deactQ_ApaG_methods; $R deactQ_ApaG_new($Cont); extern struct deactQ_BepaG_class deactQ_BepaG_methods; $R deactQ_BepaG_new($Cont); extern struct deactQ_mainG_class deactQ_mainG_methods; $R deactQ_mainG_new($Cont, B_Env); void deactQ___init__ (); ================================================ FILE: compiler/lib/test/9-codegen/deact.input ================================================ # recursive group: proc def L_1C_1cont (C_cont : $Cont[None], C_2res : None) -> $R: print@[(__builtin__.str,)](("\"Apa\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) class L_2Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[None] pure def __init__ (L_self : L_2Cont, C_cont : $Cont[None]) -> None: L_self.C_cont = C_cont return None proc def __call__ (L_self : L_2Cont, G_1 : None) -> $R: C_cont: $Cont[None] = L_self.C_cont return L_1C_1cont(C_cont, G_1) class L_4action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_3obj : Apa pure def __init__ (L_self : L_4action, L_3obj : Apa) -> None: L_self.L_3obj = L_3obj return None # recursive group: proc def __call__ (L_self : L_4action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_4action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_4action, G_1 : __builtin__.int) -> __builtin__.int: L_3obj: Apa = L_self.L_3obj return L_3obj.notice(G_1) # (recursive group) proc def U_L_5C_3cont (cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int], U_2C_4res : __builtin__.int) -> $R: U_3v: __builtin__.int = U_2C_4res m: __builtin__.Msg[__builtin__.int] = cb.__asyn__((BOX __builtin__.int (UNBOX __builtin__.int 2))) U_4N_tmp: __builtin__.int = (U_3v * (UNBOX __builtin__.int 10)) return $R_CONT@[__builtin__.int](C_cont, (BOX __builtin__.int U_4N_tmp)) proc def L_5C_3cont (cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int], C_4res : __builtin__.int) -> $R: return U_L_5C_3cont(cb, C_cont, (UNBOX __builtin__.int C_4res)) class L_6Cont ($Cont[__builtin__.int], __builtin__.value): @property cb : $action[(__builtin__.int,), __builtin__.int] @property C_cont : $Cont[__builtin__.int] pure def __init__ (L_self : L_6Cont, cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int]) -> None: L_self.cb = cb L_self.C_cont = C_cont return None proc def __call__ (L_self : L_6Cont, G_1 : __builtin__.int) -> $R: cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb C_cont: $Cont[__builtin__.int] = L_self.C_cont return L_5C_3cont(cb, C_cont, G_1) class L_7proc ($proc[(), None], __builtin__.value): @property self : Apa @property cb : $action[(__builtin__.int,), __builtin__.int] pure def __init__ (L_self : L_7proc, self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: L_self.self = self L_self.cb = cb return None # recursive group: proc def __call__ (L_self : L_7proc, C_cont : $Cont[None]) -> $R: self: Apa = L_self.self cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb return self.setupG_local(C_cont, cb) proc def __exec__ (L_self : L_7proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_8proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Apa @property cb : $action[(__builtin__.int,), __builtin__.int] pure def __init__ (L_self : L_8proc, self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: L_self.self = self L_self.cb = cb return None # recursive group: proc def __call__ (L_self : L_8proc, C_cont : $Cont[__builtin__.int]) -> $R: self: Apa = L_self.self cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb return self.computeG_local(C_cont, cb) proc def __exec__ (L_self : L_8proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_9proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Apa @property i : __builtin__.int pure def __init__ (L_self : L_9proc, self : Apa, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : L_9proc, C_cont : $Cont[__builtin__.int]) -> $R: self: Apa = L_self.self U_5i: __builtin__.int = (UNBOX __builtin__.int L_self.i) return self.noticeG_local(C_cont, (BOX __builtin__.int U_5i)) proc def __exec__ (L_self : L_9proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_10proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Bepa @property i : __builtin__.int pure def __init__ (L_self : L_10proc, self : Bepa, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : L_10proc, C_cont : $Cont[__builtin__.int]) -> $R: self: Bepa = L_self.self U_6i: __builtin__.int = (UNBOX __builtin__.int L_self.i) return self.callbackG_local(C_cont, (BOX __builtin__.int U_6i)) proc def __exec__ (L_self : L_10proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_14action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_13obj : Apa pure def __init__ (L_self : L_14action, L_13obj : Apa) -> None: L_self.L_13obj = L_13obj return None # recursive group: proc def __call__ (L_self : L_14action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_14action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_14action, G_1 : __builtin__.int) -> __builtin__.int: L_13obj: Apa = L_self.L_13obj return L_13obj.notice(G_1) # (recursive group) class L_16action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_15obj : Bepa pure def __init__ (L_self : L_16action, L_15obj : Bepa) -> None: L_self.L_15obj = L_15obj return None # recursive group: proc def __call__ (L_self : L_16action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_16action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_16action, G_1 : __builtin__.int) -> __builtin__.int: L_15obj: Bepa = L_self.L_15obj return L_15obj.callback(G_1) # (recursive group) class L_19action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_18obj : main pure def __init__ (L_self : L_19action, L_18obj : main) -> None: L_self.L_18obj = L_18obj return None # recursive group: proc def __call__ (L_self : L_19action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_19action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_19action, G_1 : __builtin__.int) -> __builtin__.int: L_18obj: main = L_self.L_18obj return L_18obj.myproc(G_1) # (recursive group) proc def U_1L_17C_9cont (self : main, C_cont : $Cont[None], U_7C_10res : __builtin__.int) -> $R: self.r = (BOX __builtin__.int U_7C_10res) print@[(__builtin__.str, __builtin__.int)](("\"r =\"", self.r), None, None, None, None) (async self.a.compute)(L_19action(self)) print@[(__builtin__.str,)](("\"main\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) proc def L_17C_9cont (self : main, C_cont : $Cont[None], C_10res : __builtin__.int) -> $R: return U_1L_17C_9cont(self, C_cont, (UNBOX __builtin__.int C_10res)) class L_20Cont ($Cont[__builtin__.int], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : L_20Cont, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : L_20Cont, G_1 : __builtin__.int) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_17C_9cont(self, C_cont, G_1) proc def L_12C_7cont (self : main, C_cont : $Cont[None], C_8res : Bepa) -> $R: self.b = C_8res print@[(__builtin__.str,)](("\"-----\"",), None, None, None, None) (async self.a.setup)(L_14action(self.a)) self.x = (async self.a.compute)(L_16action(self.b)) return $AWAIT@[__builtin__.int](L_20Cont(self, C_cont), self.x) class L_21Cont ($Cont[Bepa], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : L_21Cont, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : L_21Cont, G_1 : Bepa) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_12C_7cont(self, C_cont, G_1) proc def L_11C_5cont (self : main, C_cont : $Cont[None], C_6res : Apa) -> $R: self.a = C_6res return BepaG_newact(L_21Cont(self, C_cont)) class L_22Cont ($Cont[Apa], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : L_22Cont, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : L_22Cont, G_1 : Apa) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_11C_5cont(self, C_cont, G_1) class L_23proc ($proc[(), __builtin__.int], __builtin__.value): @property self : main @property i : __builtin__.int pure def __init__ (L_self : L_23proc, self : main, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : L_23proc, C_cont : $Cont[__builtin__.int]) -> $R: self: main = L_self.self U_8i: __builtin__.int = (UNBOX __builtin__.int L_self.i) return self.myprocG_local(C_cont, (BOX __builtin__.int U_8i)) proc def __exec__ (L_self : L_23proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_24C_11cont (C_cont : $Cont[Apa], G_act : Apa, C_12res : None) -> $R: return $R_CONT@[Apa](C_cont, G_act) class L_25Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[Apa] @property G_act : Apa pure def __init__ (L_self : L_25Cont, C_cont : $Cont[Apa], G_act : Apa) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : L_25Cont, G_1 : None) -> $R: C_cont: $Cont[Apa] = L_self.C_cont G_act: Apa = L_self.G_act return L_24C_11cont(C_cont, G_act, G_1) class L_26proc ($proc[(), None], __builtin__.value): @property G_act : Apa pure def __init__ (L_self : L_26proc, G_act : Apa) -> None: L_self.G_act = G_act return None # recursive group: proc def __call__ (L_self : L_26proc, C_cont : $Cont[None]) -> $R: G_act: Apa = L_self.G_act return G_act.__init__(C_cont) proc def __exec__ (L_self : L_26proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_27C_13cont (C_cont : $Cont[Bepa], G_act : Bepa, C_14res : None) -> $R: return $R_CONT@[Bepa](C_cont, G_act) class L_28Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[Bepa] @property G_act : Bepa pure def __init__ (L_self : L_28Cont, C_cont : $Cont[Bepa], G_act : Bepa) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : L_28Cont, G_1 : None) -> $R: C_cont: $Cont[Bepa] = L_self.C_cont G_act: Bepa = L_self.G_act return L_27C_13cont(C_cont, G_act, G_1) class L_29proc ($proc[(), None], __builtin__.value): @property G_act : Bepa pure def __init__ (L_self : L_29proc, G_act : Bepa) -> None: L_self.G_act = G_act return None # recursive group: proc def __call__ (L_self : L_29proc, C_cont : $Cont[None]) -> $R: G_act: Bepa = L_self.G_act return G_act.__init__(C_cont) proc def __exec__ (L_self : L_29proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_30C_15cont (C_cont : $Cont[main], G_act : main, C_16res : None) -> $R: return $R_CONT@[main](C_cont, G_act) class L_31Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[main] @property G_act : main pure def __init__ (L_self : L_31Cont, C_cont : $Cont[main], G_act : main) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : L_31Cont, G_1 : None) -> $R: C_cont: $Cont[main] = L_self.C_cont G_act: main = L_self.G_act return L_30C_15cont(C_cont, G_act, G_1) class L_32proc ($proc[(), None], __builtin__.value): @property G_act : main @property env : __builtin__.Env pure def __init__ (L_self : L_32proc, G_act : main, env : __builtin__.Env) -> None: L_self.G_act = G_act L_self.env = env return None # recursive group: proc def __call__ (L_self : L_32proc, C_cont : $Cont[None]) -> $R: G_act: main = L_self.G_act env: __builtin__.Env = L_self.env return G_act.__init__(C_cont, env) proc def __exec__ (L_self : L_32proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) class Apa ($Actor, __builtin__.value): proc def __init__ (self : Apa, C_cont : $Cont[None]) -> $R: return self.setupG_local(L_2Cont(C_cont), L_4action(self)) proc def setupG_local (self : Apa, C_cont : $Cont[None], cb : $action[(__builtin__.int,), __builtin__.int]) -> $R: print@[(__builtin__.str,)](("\"setup\"",), None, None, None, None) cb.__asyn__((BOX __builtin__.int (UNBOX __builtin__.int 0))) return $R_CONT@[None](C_cont, None) proc def computeG_local (self : Apa, C_cont : $Cont[__builtin__.int], cb : $action[(__builtin__.int,), __builtin__.int]) -> $R: print@[(__builtin__.str,)](("\"compute\"",), None, None, None, None) return $AWAIT@[__builtin__.int](L_6Cont(cb, C_cont), cb.__asyn__((BOX __builtin__.int (UNBOX __builtin__.int 1)))) proc def noticeG_local (self : Apa, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str,)](("\"notice\"",), None, None, None, None) U_9N_1tmp: __builtin__.int = ((UNBOX __builtin__.int i) + (UNBOX __builtin__.int 1)) return $R_CONT@[__builtin__.int](C_cont, (BOX __builtin__.int U_9N_1tmp)) action def setup (self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: return $ASYNC@[None](self, L_7proc(self, cb)) action def compute (self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_8proc(self, cb)) action def notice (self : Apa, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_9proc(self, i)) class Bepa ($Actor, __builtin__.value): proc def __init__ (self : Bepa, C_cont : $Cont[None]) -> $R: print@[(__builtin__.str,)](("\"Bepa\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) proc def callbackG_local (self : Bepa, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"callback\"", i), None, None, None, None) U_10N_2tmp: __builtin__.int = ((UNBOX __builtin__.int i) + (UNBOX __builtin__.int 1)) return $R_CONT@[__builtin__.int](C_cont, (BOX __builtin__.int U_10N_2tmp)) action def callback (self : Bepa, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_10proc(self, i)) class main ($Actor, __builtin__.value): @property env : __builtin__.Env @property a : Apa @property b : Bepa @property x : __builtin__.Msg[__builtin__.int] @property r : __builtin__.int proc def __init__ (self : main, C_cont : $Cont[None], env : __builtin__.Env) -> $R: self.env = env return ApaG_newact(L_22Cont(self, C_cont)) proc def myprocG_local (self : main, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"myproc\"", i), None, None, None, None) if (BOX __builtin__.bool ((UNBOX __builtin__.int i) == (UNBOX __builtin__.int 2))): (async self.env.exit)((BOX __builtin__.int (UNBOX __builtin__.int 0))) return $R_CONT@[__builtin__.int](C_cont, i) action def myproc (self : main, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_23proc(self, i)) proc def ApaG_newact (C_cont : $Cont[Apa]) -> $R: G_act: Apa = $NEWACTOR@[Apa]() $InstallFinalizer@[Apa](G_act) return $AWAIT@[None](L_25Cont(C_cont, G_act), $ASYNC@[None](G_act, L_26proc(G_act))) proc def BepaG_newact (C_cont : $Cont[Bepa]) -> $R: G_act: Bepa = $NEWACTOR@[Bepa]() $InstallFinalizer@[Bepa](G_act) return $AWAIT@[None](L_28Cont(C_cont, G_act), $ASYNC@[None](G_act, L_29proc(G_act))) proc def mainG_newact (C_cont : $Cont[main], env : __builtin__.Env) -> $R: G_act: main = $NEWACTOR@[main]() $InstallFinalizer@[main](G_act) return $AWAIT@[None](L_31Cont(C_cont, G_act), $ASYNC@[None](G_act, L_32proc(G_act, env))) # (recursive group) ================================================ FILE: compiler/lib/test/9-codegen/ints.c ================================================ /* Acton impl hash: test-hash */ #include "rts/common.h" #include "out/types/ints.h" int64_t intsQ_U_int64_min; B_int intsQ_int64_min; int64_t intsQ_U_1int64_max; B_int intsQ_int64_max; int32_t intsQ_U_2int32_min; B_i32 intsQ_int32_min; int32_t intsQ_U_3int32_max; B_i32 intsQ_int32_max; int16_t intsQ_U_4int16_min; B_i16 intsQ_int16_min; int16_t intsQ_U_5int16_max; B_i16 intsQ_int16_max; B_Number intsQ_W_int8_min_2; B_i8 intsQ_int8_min; B_Number intsQ_W_int8_max_2; B_i8 intsQ_int8_max; uint64_t intsQ_U_6uint64_min; B_u64 intsQ_uint64_min; uint64_t intsQ_U_7uint64_max; B_u64 intsQ_uint64_max; uint32_t intsQ_U_8uint32_min; B_u32 intsQ_uint32_min; uint32_t intsQ_U_9uint32_max; B_u32 intsQ_uint32_max; uint16_t intsQ_U_10uint16_min; B_u16 intsQ_uint16_min; uint16_t intsQ_U_11uint16_max; B_u16 intsQ_uint16_max; B_Number intsQ_W_uint8_min_2; B_u8 intsQ_uint8_min; B_Number intsQ_W_uint8_max_2; B_u8 intsQ_uint8_max; B_bigint intsQ_bigint_small; B_bigint intsQ_bigint_neg_small; B_bigint intsQ_bigint_i64_max; B_bigint intsQ_bigint_i64_min; B_bigint intsQ_bigint_i64_underflow; B_bigint intsQ_bigint_u64_edge; B_bigint intsQ_bigint_u64_edge_minus1; B_bigint intsQ_bigint_u64_overflow; B_bigint intsQ_xint_i64_min_minus1; int intsQ_done$ = 0; void intsQ___init__ () { if (intsQ_done$) return; intsQ_done$ = 1; int64_t U_int64_min = -9223372036854775808LL; intsQ_U_int64_min = U_int64_min; B_int int64_min = toB_int(intsQ_U_int64_min); intsQ_int64_min = int64_min; int64_t U_1int64_max = 9223372036854775807LL; intsQ_U_1int64_max = U_1int64_max; B_int int64_max = toB_int(intsQ_U_1int64_max); intsQ_int64_max = int64_max; int32_t U_2int32_min = -2147483648; intsQ_U_2int32_min = U_2int32_min; B_i32 int32_min = toB_i32(intsQ_U_2int32_min); intsQ_int32_min = int32_min; int32_t U_3int32_max = 2147483647; intsQ_U_3int32_max = U_3int32_max; B_i32 int32_max = toB_i32(intsQ_U_3int32_max); intsQ_int32_max = int32_max; int16_t U_4int16_min = -32768; intsQ_U_4int16_min = U_4int16_min; B_i16 int16_min = toB_i16(intsQ_U_4int16_min); intsQ_int16_min = int16_min; int16_t U_5int16_max = 32767; intsQ_U_5int16_max = U_5int16_max; B_i16 int16_max = toB_i16(intsQ_U_5int16_max); intsQ_int16_max = int16_max; B_Number W_int8_min_2 = (B_Number)B_IntegralD_i8G_witness; intsQ_W_int8_min_2 = W_int8_min_2; B_i8 int8_min = ((B_i8 (*) (B_Number, B_atom))intsQ_W_int8_min_2->$class->__fromatom__)(intsQ_W_int8_min_2, ((B_atom)toB_bigint2("-128"))); intsQ_int8_min = int8_min; B_Number W_int8_max_2 = (B_Number)B_IntegralD_i8G_witness; intsQ_W_int8_max_2 = W_int8_max_2; B_i8 int8_max = ((B_i8 (*) (B_Number, B_atom))intsQ_W_int8_max_2->$class->__fromatom__)(intsQ_W_int8_max_2, ((B_atom)toB_bigint(127UL))); intsQ_int8_max = int8_max; uint64_t U_6uint64_min = 0UL; intsQ_U_6uint64_min = U_6uint64_min; B_u64 uint64_min = toB_u64(intsQ_U_6uint64_min); intsQ_uint64_min = uint64_min; uint64_t U_7uint64_max = 18446744073709551615UL; intsQ_U_7uint64_max = U_7uint64_max; B_u64 uint64_max = toB_u64(intsQ_U_7uint64_max); intsQ_uint64_max = uint64_max; uint32_t U_8uint32_min = 0; intsQ_U_8uint32_min = U_8uint32_min; B_u32 uint32_min = toB_u32(intsQ_U_8uint32_min); intsQ_uint32_min = uint32_min; uint32_t U_9uint32_max = 4294967295; intsQ_U_9uint32_max = U_9uint32_max; B_u32 uint32_max = toB_u32(intsQ_U_9uint32_max); intsQ_uint32_max = uint32_max; uint16_t U_10uint16_min = 0; intsQ_U_10uint16_min = U_10uint16_min; B_u16 uint16_min = toB_u16(intsQ_U_10uint16_min); intsQ_uint16_min = uint16_min; uint16_t U_11uint16_max = 65535; intsQ_U_11uint16_max = U_11uint16_max; B_u16 uint16_max = toB_u16(intsQ_U_11uint16_max); intsQ_uint16_max = uint16_max; B_Number W_uint8_min_2 = (B_Number)B_IntegralD_u8G_witness; intsQ_W_uint8_min_2 = W_uint8_min_2; B_u8 uint8_min = ((B_u8 (*) (B_Number, B_atom))intsQ_W_uint8_min_2->$class->__fromatom__)(intsQ_W_uint8_min_2, ((B_atom)toB_bigint(0UL))); intsQ_uint8_min = uint8_min; B_Number W_uint8_max_2 = (B_Number)B_IntegralD_u8G_witness; intsQ_W_uint8_max_2 = W_uint8_max_2; B_u8 uint8_max = ((B_u8 (*) (B_Number, B_atom))intsQ_W_uint8_max_2->$class->__fromatom__)(intsQ_W_uint8_max_2, ((B_atom)toB_bigint(255UL))); intsQ_uint8_max = uint8_max; B_bigint bigint_small = ((B_bigint)toB_bigint(42UL)); intsQ_bigint_small = bigint_small; B_bigint bigint_neg_small = ((B_bigint)toB_bigint2("-1")); intsQ_bigint_neg_small = bigint_neg_small; B_bigint bigint_i64_max = ((B_bigint)toB_bigint(9223372036854775807UL)); intsQ_bigint_i64_max = bigint_i64_max; B_bigint bigint_i64_min = ((B_bigint)toB_bigint2("-9223372036854775808")); intsQ_bigint_i64_min = bigint_i64_min; B_bigint bigint_i64_underflow = ((B_bigint)toB_bigint2("-9223372036854775809")); intsQ_bigint_i64_underflow = bigint_i64_underflow; B_bigint bigint_u64_edge = B_bigintG_new(((B_atom)toB_u64(18446744073709551615UL)), B_None); intsQ_bigint_u64_edge = bigint_u64_edge; B_bigint bigint_u64_edge_minus1 = B_bigintG_new(((B_atom)toB_u64(18446744073709551614UL)), B_None); intsQ_bigint_u64_edge_minus1 = bigint_u64_edge_minus1; B_bigint bigint_u64_overflow = ((B_bigint)toB_bigint2("18446744073709551616")); intsQ_bigint_u64_overflow = bigint_u64_overflow; B_bigint xint_i64_min_minus1 = ((B_bigint)toB_bigint2("-9223372036854775809")); intsQ_xint_i64_min_minus1 = xint_i64_min_minus1; } ================================================ FILE: compiler/lib/test/9-codegen/ints.h ================================================ /* Acton impl hash: test-hash */ #pragma once #include "builtin/builtin.h" #include "rts/rts.h" extern int64_t intsQ_U_int64_min; extern B_int intsQ_int64_min; extern int64_t intsQ_U_1int64_max; extern B_int intsQ_int64_max; extern int32_t intsQ_U_2int32_min; extern B_i32 intsQ_int32_min; extern int32_t intsQ_U_3int32_max; extern B_i32 intsQ_int32_max; extern int16_t intsQ_U_4int16_min; extern B_i16 intsQ_int16_min; extern int16_t intsQ_U_5int16_max; extern B_i16 intsQ_int16_max; extern B_Number intsQ_W_int8_min_2; extern B_i8 intsQ_int8_min; extern B_Number intsQ_W_int8_max_2; extern B_i8 intsQ_int8_max; extern uint64_t intsQ_U_6uint64_min; extern B_u64 intsQ_uint64_min; extern uint64_t intsQ_U_7uint64_max; extern B_u64 intsQ_uint64_max; extern uint32_t intsQ_U_8uint32_min; extern B_u32 intsQ_uint32_min; extern uint32_t intsQ_U_9uint32_max; extern B_u32 intsQ_uint32_max; extern uint16_t intsQ_U_10uint16_min; extern B_u16 intsQ_uint16_min; extern uint16_t intsQ_U_11uint16_max; extern B_u16 intsQ_uint16_max; extern B_Number intsQ_W_uint8_min_2; extern B_u8 intsQ_uint8_min; extern B_Number intsQ_W_uint8_max_2; extern B_u8 intsQ_uint8_max; extern B_bigint intsQ_bigint_small; extern B_bigint intsQ_bigint_neg_small; extern B_bigint intsQ_bigint_i64_max; extern B_bigint intsQ_bigint_i64_min; extern B_bigint intsQ_bigint_i64_underflow; extern B_bigint intsQ_bigint_u64_edge; extern B_bigint intsQ_bigint_u64_edge_minus1; extern B_bigint intsQ_bigint_u64_overflow; extern B_bigint intsQ_xint_i64_min_minus1; void intsQ___init__ (); ================================================ FILE: compiler/lib/test/9-codegen/ints.input ================================================ U_int64_min: __builtin__.int = (UNBOX __builtin__.int -9223372036854775808) int64_min: __builtin__.int = (BOX __builtin__.int U_int64_min) U_1int64_max: __builtin__.int = (UNBOX __builtin__.int 9223372036854775807) int64_max: __builtin__.int = (BOX __builtin__.int U_1int64_max) U_2int32_min: __builtin__.i32 = (UNBOX __builtin__.i32 -2147483648) int32_min: __builtin__.i32 = (BOX __builtin__.i32 U_2int32_min) U_3int32_max: __builtin__.i32 = (UNBOX __builtin__.i32 2147483647) int32_max: __builtin__.i32 = (BOX __builtin__.i32 U_3int32_max) U_4int16_min: __builtin__.i16 = (UNBOX __builtin__.i16 -32768) int16_min: __builtin__.i16 = (BOX __builtin__.i16 U_4int16_min) U_5int16_max: __builtin__.i16 = (UNBOX __builtin__.i16 32767) int16_max: __builtin__.i16 = (BOX __builtin__.i16 U_5int16_max) W_int8_min_2: __builtin__.Number[__builtin__.i8] = __builtin__.IntegralD_i8() int8_min: __builtin__.i8 = W_int8_min_2.__fromatom__(-128) W_int8_max_2: __builtin__.Number[__builtin__.i8] = __builtin__.IntegralD_i8() int8_max: __builtin__.i8 = W_int8_max_2.__fromatom__(127) U_6uint64_min: __builtin__.u64 = (UNBOX __builtin__.u64 0) uint64_min: __builtin__.u64 = (BOX __builtin__.u64 U_6uint64_min) U_7uint64_max: __builtin__.u64 = (UNBOX __builtin__.u64 18446744073709551615) uint64_max: __builtin__.u64 = (BOX __builtin__.u64 U_7uint64_max) U_8uint32_min: __builtin__.u32 = (UNBOX __builtin__.u32 0) uint32_min: __builtin__.u32 = (BOX __builtin__.u32 U_8uint32_min) U_9uint32_max: __builtin__.u32 = (UNBOX __builtin__.u32 4294967295) uint32_max: __builtin__.u32 = (BOX __builtin__.u32 U_9uint32_max) U_10uint16_min: __builtin__.u16 = (UNBOX __builtin__.u16 0) uint16_min: __builtin__.u16 = (BOX __builtin__.u16 U_10uint16_min) U_11uint16_max: __builtin__.u16 = (UNBOX __builtin__.u16 65535) uint16_max: __builtin__.u16 = (BOX __builtin__.u16 U_11uint16_max) W_uint8_min_2: __builtin__.Number[__builtin__.u8] = __builtin__.IntegralD_u8() uint8_min: __builtin__.u8 = W_uint8_min_2.__fromatom__(0) W_uint8_max_2: __builtin__.Number[__builtin__.u8] = __builtin__.IntegralD_u8() uint8_max: __builtin__.u8 = W_uint8_max_2.__fromatom__(255) bigint_small: __builtin__.bigint = 42 bigint_neg_small: __builtin__.bigint = -1 bigint_i64_max: __builtin__.bigint = 9223372036854775807 bigint_i64_min: __builtin__.bigint = -9223372036854775808 bigint_i64_underflow: __builtin__.bigint = -9223372036854775809 bigint_u64_edge: __builtin__.bigint = bigint(18446744073709551615, None) bigint_u64_edge_minus1: __builtin__.bigint = bigint(18446744073709551614, None) bigint_u64_overflow: __builtin__.bigint = 18446744073709551616 xint_i64_min_minus1: __builtin__.bigint = -9223372036854775809 ================================================ FILE: compiler/lib/test/9-codegen/lines.c ================================================ /* Acton impl hash: test-hash */ #include "rts/common.h" #include "out/types/lines.h" B_Eq linesQ_W_Apa_1097; B_Eq linesQ_W_Apa_759; B_Iterable linesQ_W_Apa_779; B_Eq linesQ_W_Apa_331; B_Eq linesQ_W_Apa_785; $R linesQ_L_1C_1cont (linesQ_Apa self, $Cont C_cont, B_NoneType C_2res) { #line 18 "test/src/lines.act" self->z = toB_int(1LL); #line 19 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("Apa")), B_None, B_None, B_None, B_None); return $R_CONT(C_cont, B_None); } B_NoneType linesQ_L_2ContD___init__ (linesQ_L_2Cont L_self, linesQ_Apa self, $Cont C_cont) { L_self->self = self; L_self->C_cont = C_cont; return B_None; } $R linesQ_L_2ContD___call__ (linesQ_L_2Cont L_self, B_NoneType G_1) { linesQ_Apa self = L_self->self; $Cont C_cont = L_self->C_cont; return linesQ_L_1C_1cont(self, C_cont, G_1); } void linesQ_L_2ContD___serialize__ (linesQ_L_2Cont self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->C_cont, state); } linesQ_L_2Cont linesQ_L_2ContD___deserialize__ (linesQ_L_2Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_2Cont)); self->$class = &linesQ_L_2ContG_methods; return self; } self = $DNEW(linesQ_L_2Cont, state); } self->self = $step_deserialize(state); self->C_cont = $step_deserialize(state); return self; } linesQ_L_2Cont linesQ_L_2ContG_new(linesQ_Apa G_1, $Cont G_2) { linesQ_L_2Cont $tmp = acton_malloc(sizeof(struct linesQ_L_2Cont)); $tmp->$class = &linesQ_L_2ContG_methods; linesQ_L_2ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_2ContG_class linesQ_L_2ContG_methods; B_NoneType linesQ_L_4actionD___init__ (linesQ_L_4action L_self, linesQ_Apa L_3obj) { L_self->L_3obj = L_3obj; return B_None; } $R linesQ_L_4actionD___call__ (linesQ_L_4action L_self, $Cont L_cont, B_int G_1) { return $AWAIT(L_cont, ((B_Msg)((B_Msg (*) (linesQ_L_4action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } $R linesQ_L_4actionD___exec__ (linesQ_L_4action L_self, $Cont L_cont, B_int G_1) { return $R_CONT(L_cont, ((B_value)((B_Msg (*) (linesQ_L_4action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } B_Msg linesQ_L_4actionD___asyn__ (linesQ_L_4action L_self, B_int G_1) { linesQ_Apa L_3obj = L_self->L_3obj; return ((B_Msg)((B_Msg (*) (linesQ_Apa, B_int))L_3obj->$class->notice)(L_3obj, G_1)); } void linesQ_L_4actionD___serialize__ (linesQ_L_4action self, $Serial$state state) { $step_serialize(self->L_3obj, state); } linesQ_L_4action linesQ_L_4actionD___deserialize__ (linesQ_L_4action self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_4action)); self->$class = &linesQ_L_4actionG_methods; return self; } self = $DNEW(linesQ_L_4action, state); } self->L_3obj = $step_deserialize(state); return self; } linesQ_L_4action linesQ_L_4actionG_new(linesQ_Apa G_1) { linesQ_L_4action $tmp = acton_malloc(sizeof(struct linesQ_L_4action)); $tmp->$class = &linesQ_L_4actionG_methods; linesQ_L_4actionG_methods.__init__($tmp, G_1); return $tmp; } struct linesQ_L_4actionG_class linesQ_L_4actionG_methods; $R linesQ_U_L_5C_3cont ($action cb, $Cont C_cont, int64_t U_2C_4res) { #line 9 "test/src/lines.act" int64_t U_3v = U_2C_4res; #line 10 "test/src/lines.act" B_Msg m = ((B_Msg)((B_Msg (*) ($action, B_int))cb->$class->__asyn__)(cb, toB_int(2LL))); int64_t U_4N_tmp = (U_3v * 10LL); return $R_CONT(C_cont, toB_int(U_4N_tmp)); } $R linesQ_L_5C_3cont ($action cb, $Cont C_cont, B_int C_4res) { return linesQ_U_L_5C_3cont(cb, C_cont, ((B_int)C_4res)->val); } B_NoneType linesQ_L_6ContD___init__ (linesQ_L_6Cont L_self, $action cb, $Cont C_cont) { L_self->cb = cb; L_self->C_cont = C_cont; return B_None; } $R linesQ_L_6ContD___call__ (linesQ_L_6Cont L_self, B_int G_1) { $action cb = L_self->cb; $Cont C_cont = L_self->C_cont; return linesQ_L_5C_3cont(cb, C_cont, G_1); } void linesQ_L_6ContD___serialize__ (linesQ_L_6Cont self, $Serial$state state) { $step_serialize(self->cb, state); $step_serialize(self->C_cont, state); } linesQ_L_6Cont linesQ_L_6ContD___deserialize__ (linesQ_L_6Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_6Cont)); self->$class = &linesQ_L_6ContG_methods; return self; } self = $DNEW(linesQ_L_6Cont, state); } self->cb = $step_deserialize(state); self->C_cont = $step_deserialize(state); return self; } linesQ_L_6Cont linesQ_L_6ContG_new($action G_1, $Cont G_2) { linesQ_L_6Cont $tmp = acton_malloc(sizeof(struct linesQ_L_6Cont)); $tmp->$class = &linesQ_L_6ContG_methods; linesQ_L_6ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_6ContG_class linesQ_L_6ContG_methods; B_NoneType linesQ_L_7procD___init__ (linesQ_L_7proc L_self, linesQ_Apa self, $action cb) { L_self->self = self; L_self->cb = cb; return B_None; } $R linesQ_L_7procD___call__ (linesQ_L_7proc L_self, $Cont C_cont) { linesQ_Apa self = L_self->self; $action cb = L_self->cb; return (($R (*) (linesQ_Apa, $Cont, $action))self->$class->setupG_local)(self, C_cont, cb); } $R linesQ_L_7procD___exec__ (linesQ_L_7proc L_self, $Cont C_cont) { return (($R (*) (linesQ_L_7proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void linesQ_L_7procD___serialize__ (linesQ_L_7proc self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->cb, state); } linesQ_L_7proc linesQ_L_7procD___deserialize__ (linesQ_L_7proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_7proc)); self->$class = &linesQ_L_7procG_methods; return self; } self = $DNEW(linesQ_L_7proc, state); } self->self = $step_deserialize(state); self->cb = $step_deserialize(state); return self; } linesQ_L_7proc linesQ_L_7procG_new(linesQ_Apa G_1, $action G_2) { linesQ_L_7proc $tmp = acton_malloc(sizeof(struct linesQ_L_7proc)); $tmp->$class = &linesQ_L_7procG_methods; linesQ_L_7procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_7procG_class linesQ_L_7procG_methods; B_NoneType linesQ_L_8procD___init__ (linesQ_L_8proc L_self, linesQ_Apa self, $action cb) { L_self->self = self; L_self->cb = cb; return B_None; } $R linesQ_L_8procD___call__ (linesQ_L_8proc L_self, $Cont C_cont) { linesQ_Apa self = L_self->self; $action cb = L_self->cb; return (($R (*) (linesQ_Apa, $Cont, $action))self->$class->computeG_local)(self, C_cont, cb); } $R linesQ_L_8procD___exec__ (linesQ_L_8proc L_self, $Cont C_cont) { return (($R (*) (linesQ_L_8proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void linesQ_L_8procD___serialize__ (linesQ_L_8proc self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->cb, state); } linesQ_L_8proc linesQ_L_8procD___deserialize__ (linesQ_L_8proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_8proc)); self->$class = &linesQ_L_8procG_methods; return self; } self = $DNEW(linesQ_L_8proc, state); } self->self = $step_deserialize(state); self->cb = $step_deserialize(state); return self; } linesQ_L_8proc linesQ_L_8procG_new(linesQ_Apa G_1, $action G_2) { linesQ_L_8proc $tmp = acton_malloc(sizeof(struct linesQ_L_8proc)); $tmp->$class = &linesQ_L_8procG_methods; linesQ_L_8procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_8procG_class linesQ_L_8procG_methods; B_NoneType linesQ_L_9procD___init__ (linesQ_L_9proc L_self, linesQ_Apa self, B_int i) { L_self->self = self; L_self->i = i; return B_None; } $R linesQ_L_9procD___call__ (linesQ_L_9proc L_self, $Cont C_cont) { linesQ_Apa self = L_self->self; int64_t U_5i = ((B_int)L_self->i)->val; return (($R (*) (linesQ_Apa, $Cont, B_int))self->$class->noticeG_local)(self, C_cont, toB_int(U_5i)); } $R linesQ_L_9procD___exec__ (linesQ_L_9proc L_self, $Cont C_cont) { return (($R (*) (linesQ_L_9proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void linesQ_L_9procD___serialize__ (linesQ_L_9proc self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->i, state); } linesQ_L_9proc linesQ_L_9procD___deserialize__ (linesQ_L_9proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_9proc)); self->$class = &linesQ_L_9procG_methods; return self; } self = $DNEW(linesQ_L_9proc, state); } self->self = $step_deserialize(state); self->i = $step_deserialize(state); return self; } linesQ_L_9proc linesQ_L_9procG_new(linesQ_Apa G_1, B_int G_2) { linesQ_L_9proc $tmp = acton_malloc(sizeof(struct linesQ_L_9proc)); $tmp->$class = &linesQ_L_9procG_methods; linesQ_L_9procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_9procG_class linesQ_L_9procG_methods; B_NoneType linesQ_L_10procD___init__ (linesQ_L_10proc L_self, linesQ_Bepa self, B_int i) { L_self->self = self; L_self->i = i; return B_None; } $R linesQ_L_10procD___call__ (linesQ_L_10proc L_self, $Cont C_cont) { linesQ_Bepa self = L_self->self; int64_t U_6i = ((B_int)L_self->i)->val; return (($R (*) (linesQ_Bepa, $Cont, B_int))self->$class->callbackG_local)(self, C_cont, toB_int(U_6i)); } $R linesQ_L_10procD___exec__ (linesQ_L_10proc L_self, $Cont C_cont) { return (($R (*) (linesQ_L_10proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void linesQ_L_10procD___serialize__ (linesQ_L_10proc self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->i, state); } linesQ_L_10proc linesQ_L_10procD___deserialize__ (linesQ_L_10proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_10proc)); self->$class = &linesQ_L_10procG_methods; return self; } self = $DNEW(linesQ_L_10proc, state); } self->self = $step_deserialize(state); self->i = $step_deserialize(state); return self; } linesQ_L_10proc linesQ_L_10procG_new(linesQ_Bepa G_1, B_int G_2) { linesQ_L_10proc $tmp = acton_malloc(sizeof(struct linesQ_L_10proc)); $tmp->$class = &linesQ_L_10procG_methods; linesQ_L_10procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_10procG_class linesQ_L_10procG_methods; B_NoneType linesQ_L_14actionD___init__ (linesQ_L_14action L_self, linesQ_Apa L_13obj) { L_self->L_13obj = L_13obj; return B_None; } $R linesQ_L_14actionD___call__ (linesQ_L_14action L_self, $Cont L_cont, B_int G_1) { return $AWAIT(L_cont, ((B_Msg)((B_Msg (*) (linesQ_L_14action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } $R linesQ_L_14actionD___exec__ (linesQ_L_14action L_self, $Cont L_cont, B_int G_1) { return $R_CONT(L_cont, ((B_value)((B_Msg (*) (linesQ_L_14action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } B_Msg linesQ_L_14actionD___asyn__ (linesQ_L_14action L_self, B_int G_1) { linesQ_Apa L_13obj = L_self->L_13obj; return ((B_Msg)((B_Msg (*) (linesQ_Apa, B_int))L_13obj->$class->notice)(L_13obj, G_1)); } void linesQ_L_14actionD___serialize__ (linesQ_L_14action self, $Serial$state state) { $step_serialize(self->L_13obj, state); } linesQ_L_14action linesQ_L_14actionD___deserialize__ (linesQ_L_14action self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_14action)); self->$class = &linesQ_L_14actionG_methods; return self; } self = $DNEW(linesQ_L_14action, state); } self->L_13obj = $step_deserialize(state); return self; } linesQ_L_14action linesQ_L_14actionG_new(linesQ_Apa G_1) { linesQ_L_14action $tmp = acton_malloc(sizeof(struct linesQ_L_14action)); $tmp->$class = &linesQ_L_14actionG_methods; linesQ_L_14actionG_methods.__init__($tmp, G_1); return $tmp; } struct linesQ_L_14actionG_class linesQ_L_14actionG_methods; B_NoneType linesQ_L_16actionD___init__ (linesQ_L_16action L_self, linesQ_Bepa L_15obj) { L_self->L_15obj = L_15obj; return B_None; } $R linesQ_L_16actionD___call__ (linesQ_L_16action L_self, $Cont L_cont, B_int G_1) { return $AWAIT(L_cont, ((B_Msg)((B_Msg (*) (linesQ_L_16action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } $R linesQ_L_16actionD___exec__ (linesQ_L_16action L_self, $Cont L_cont, B_int G_1) { return $R_CONT(L_cont, ((B_value)((B_Msg (*) (linesQ_L_16action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } B_Msg linesQ_L_16actionD___asyn__ (linesQ_L_16action L_self, B_int G_1) { linesQ_Bepa L_15obj = L_self->L_15obj; return ((B_Msg)((B_Msg (*) (linesQ_Bepa, B_int))L_15obj->$class->callback)(L_15obj, G_1)); } void linesQ_L_16actionD___serialize__ (linesQ_L_16action self, $Serial$state state) { $step_serialize(self->L_15obj, state); } linesQ_L_16action linesQ_L_16actionD___deserialize__ (linesQ_L_16action self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_16action)); self->$class = &linesQ_L_16actionG_methods; return self; } self = $DNEW(linesQ_L_16action, state); } self->L_15obj = $step_deserialize(state); return self; } linesQ_L_16action linesQ_L_16actionG_new(linesQ_Bepa G_1) { linesQ_L_16action $tmp = acton_malloc(sizeof(struct linesQ_L_16action)); $tmp->$class = &linesQ_L_16actionG_methods; linesQ_L_16actionG_methods.__init__($tmp, G_1); return $tmp; } struct linesQ_L_16actionG_class linesQ_L_16actionG_methods; B_NoneType linesQ_L_19actionD___init__ (linesQ_L_19action L_self, linesQ_main L_18obj) { L_self->L_18obj = L_18obj; return B_None; } $R linesQ_L_19actionD___call__ (linesQ_L_19action L_self, $Cont L_cont, B_int G_1) { return $AWAIT(L_cont, ((B_Msg)((B_Msg (*) (linesQ_L_19action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } $R linesQ_L_19actionD___exec__ (linesQ_L_19action L_self, $Cont L_cont, B_int G_1) { return $R_CONT(L_cont, ((B_value)((B_Msg (*) (linesQ_L_19action, B_int))L_self->$class->__asyn__)(L_self, G_1))); } B_Msg linesQ_L_19actionD___asyn__ (linesQ_L_19action L_self, B_int G_1) { linesQ_main L_18obj = L_self->L_18obj; return ((B_Msg)((B_Msg (*) (linesQ_main, B_int))L_18obj->$class->myproc)(L_18obj, G_1)); } void linesQ_L_19actionD___serialize__ (linesQ_L_19action self, $Serial$state state) { $step_serialize(self->L_18obj, state); } linesQ_L_19action linesQ_L_19actionD___deserialize__ (linesQ_L_19action self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_19action)); self->$class = &linesQ_L_19actionG_methods; return self; } self = $DNEW(linesQ_L_19action, state); } self->L_18obj = $step_deserialize(state); return self; } linesQ_L_19action linesQ_L_19actionG_new(linesQ_main G_1) { linesQ_L_19action $tmp = acton_malloc(sizeof(struct linesQ_L_19action)); $tmp->$class = &linesQ_L_19actionG_methods; linesQ_L_19actionG_methods.__init__($tmp, G_1); return $tmp; } struct linesQ_L_19actionG_class linesQ_L_19actionG_methods; B_NoneType linesQ_L_20procD___init__ (linesQ_L_20proc L_self, linesQ_main self) { L_self->self = self; return B_None; } $R linesQ_L_20procD___call__ (linesQ_L_20proc L_self, $Cont C_cont) { linesQ_main self = L_self->self; return (($R (*) (linesQ_main, $Cont, B_int))self->$class->myprocG_local)(self, C_cont, toB_int(0LL)); } $R linesQ_L_20procD___exec__ (linesQ_L_20proc L_self, $Cont C_cont) { return (($R (*) (linesQ_L_20proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void linesQ_L_20procD___serialize__ (linesQ_L_20proc self, $Serial$state state) { $step_serialize(self->self, state); } linesQ_L_20proc linesQ_L_20procD___deserialize__ (linesQ_L_20proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_20proc)); self->$class = &linesQ_L_20procG_methods; return self; } self = $DNEW(linesQ_L_20proc, state); } self->self = $step_deserialize(state); return self; } linesQ_L_20proc linesQ_L_20procG_new(linesQ_main G_1) { linesQ_L_20proc $tmp = acton_malloc(sizeof(struct linesQ_L_20proc)); $tmp->$class = &linesQ_L_20procG_methods; linesQ_L_20procG_methods.__init__($tmp, G_1); return $tmp; } struct linesQ_L_20procG_class linesQ_L_20procG_methods; $R linesQ_U_1L_17C_9cont (linesQ_main self, $Cont C_cont, int64_t U_7C_10res) { #line 38 "test/src/lines.act" self->r = toB_int(U_7C_10res); #line 39 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(2, to$str("r ="), self->r), B_None, B_None, B_None, B_None); #line 40 "test/src/lines.act" ((B_Msg (*) (linesQ_Apa, $action))self->a->$class->compute)(self->a, (($action)linesQ_L_19actionG_new(self))); #line 41 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("main")), B_None, B_None, B_None, B_None); #line 44 "test/src/lines.act" self->v = toB_int(0LL); #line 45 "test/src/lines.act" if ((((B_int)self->v)->val == 0LL)) { #line 46 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("if branch")), B_None, B_None, B_None, B_None); #line 47 "test/src/lines.act" if ((((B_int)self->v)->val < 1LL)) { #line 48 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("nested if")), B_None, B_None, B_None, B_None); } else if ((((B_int)self->v)->val == -1LL)) { #line 50 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("nested elif")), B_None, B_None, B_None, B_None); } else { #line 52 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("nested else")), B_None, B_None, B_None, B_None); } } else if ((((B_int)self->v)->val == 1LL)) { #line 54 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("outer elif")), B_None, B_None, B_None, B_None); } else { #line 56 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("outer else")), B_None, B_None, B_None, B_None); } #line 59 "test/src/lines.act" self->i = toB_int(0LL); #line 60 "test/src/lines.act" while (true) { if ((((B_int)self->i)->val < 3LL)) { } else { #line 70 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("while else")), B_None, B_None, B_None, B_None); break; } #line 61 "test/src/lines.act" self->i = toB_int((((B_int)self->i)->val + 1LL)); #line 62 "test/src/lines.act" if ((((B_int)self->i)->val == 1LL)) { #line 63 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("continue path")), B_None, B_None, B_None, B_None); #line 64 "test/src/lines.act" continue; } #line 65 "test/src/lines.act" if ((((B_int)self->i)->val == 2LL)) { #line 66 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("break path")), B_None, B_None, B_None, B_None); #line 67 "test/src/lines.act" break; } #line 68 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(2, to$str("loop body"), self->i), B_None, B_None, B_None, B_None); } B_Iterator N_3iter = ((B_Iterator (*) (B_Iterable, B_list))linesQ_W_Apa_779->$class->__iter__)(linesQ_W_Apa_779, B_mk_list(3, toB_int(1LL) , toB_int(2LL) , toB_int(3LL))); if ($PUSH()) { #line 73 "test/src/lines.act" while (true) { B_int j = ((B_int (*) (B_Iterator))N_3iter->$class->__next__)(N_3iter); #line 74 "test/src/lines.act" if (((B_bool)((B_bool (*) (B_Eq, B_int, B_int))linesQ_W_Apa_759->$class->__eq__)(linesQ_W_Apa_759, j, toB_int(2LL)))->val) { #line 75 "test/src/lines.act" continue; } #line 76 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(2, to$str("for j"), j), B_None, B_None, B_None, B_None); } $DROP(); } else { B_BaseException N_5x = $POP(); if ($ISINSTANCE0(N_5x, B_StopIteration)) { } else { $RAISE(N_5x); } } B_BaseException N_7xx; if ($PUSHF()) { if ($PUSH()) { #line 80 "test/src/lines.act" if (((B_bool)((B_bool (*) (B_Eq, B_int, B_int))linesQ_W_Apa_785->$class->__eq__)(linesQ_W_Apa_785, self->v, toB_int(0LL)))->val) { #line 81 "test/src/lines.act" $RAISE(((B_BaseException)B_ValueErrorG_new(to$str("boom")))); } #line 82 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("unreached")), B_None, B_None, B_None, B_None); $DROP(); } else { B_BaseException N_6x = $POP(); B_ValueError e; if ($ISINSTANCE0(N_6x, B_ValueError)) { e = ((B_ValueError)N_6x); #line 84 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(2, to$str("caught"), to$str("ValueError")), B_None, B_None, B_None, B_None); } else { $RAISE(N_6x); } } $RAISE(((B_BaseException)$SEQG_new())); } else { N_7xx = $POP(); #line 86 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("finally")), B_None, B_None, B_None, B_None); if ($ISINSTANCE0(N_7xx, $SEQ)) { } else { $RAISE(N_7xx); } } #line 89 "test/src/lines.act" $AFTER(toB_float(1), (($Cont)linesQ_L_20procG_new(self))); return (($R (*) (linesQ_main, $Cont))self->$class->nopG_local)(self, C_cont); } $R linesQ_L_17C_9cont (linesQ_main self, $Cont C_cont, B_int C_10res) { return linesQ_U_1L_17C_9cont(self, C_cont, ((B_int)C_10res)->val); } B_NoneType linesQ_L_21ContD___init__ (linesQ_L_21Cont L_self, linesQ_main self, $Cont C_cont) { L_self->self = self; L_self->C_cont = C_cont; return B_None; } $R linesQ_L_21ContD___call__ (linesQ_L_21Cont L_self, B_int G_1) { linesQ_main self = L_self->self; $Cont C_cont = L_self->C_cont; return linesQ_L_17C_9cont(self, C_cont, G_1); } void linesQ_L_21ContD___serialize__ (linesQ_L_21Cont self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->C_cont, state); } linesQ_L_21Cont linesQ_L_21ContD___deserialize__ (linesQ_L_21Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_21Cont)); self->$class = &linesQ_L_21ContG_methods; return self; } self = $DNEW(linesQ_L_21Cont, state); } self->self = $step_deserialize(state); self->C_cont = $step_deserialize(state); return self; } linesQ_L_21Cont linesQ_L_21ContG_new(linesQ_main G_1, $Cont G_2) { linesQ_L_21Cont $tmp = acton_malloc(sizeof(struct linesQ_L_21Cont)); $tmp->$class = &linesQ_L_21ContG_methods; linesQ_L_21ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_21ContG_class linesQ_L_21ContG_methods; $R linesQ_L_12C_7cont (linesQ_main self, $Cont C_cont, linesQ_Bepa C_8res) { #line 34 "test/src/lines.act" self->b = C_8res; #line 35 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("-----")), B_None, B_None, B_None, B_None); #line 36 "test/src/lines.act" ((B_Msg (*) (linesQ_Apa, $action))self->a->$class->setup)(self->a, (($action)linesQ_L_14actionG_new(self->a))); #line 37 "test/src/lines.act" self->x = ((B_Msg (*) (linesQ_Apa, $action))self->a->$class->compute)(self->a, (($action)linesQ_L_16actionG_new(self->b))); return $AWAIT((($Cont)linesQ_L_21ContG_new(self, C_cont)), self->x); } B_NoneType linesQ_L_22ContD___init__ (linesQ_L_22Cont L_self, linesQ_main self, $Cont C_cont) { L_self->self = self; L_self->C_cont = C_cont; return B_None; } $R linesQ_L_22ContD___call__ (linesQ_L_22Cont L_self, linesQ_Bepa G_1) { linesQ_main self = L_self->self; $Cont C_cont = L_self->C_cont; return linesQ_L_12C_7cont(self, C_cont, G_1); } void linesQ_L_22ContD___serialize__ (linesQ_L_22Cont self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->C_cont, state); } linesQ_L_22Cont linesQ_L_22ContD___deserialize__ (linesQ_L_22Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_22Cont)); self->$class = &linesQ_L_22ContG_methods; return self; } self = $DNEW(linesQ_L_22Cont, state); } self->self = $step_deserialize(state); self->C_cont = $step_deserialize(state); return self; } linesQ_L_22Cont linesQ_L_22ContG_new(linesQ_main G_1, $Cont G_2) { linesQ_L_22Cont $tmp = acton_malloc(sizeof(struct linesQ_L_22Cont)); $tmp->$class = &linesQ_L_22ContG_methods; linesQ_L_22ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_22ContG_class linesQ_L_22ContG_methods; $R linesQ_L_11C_5cont (linesQ_main self, $Cont C_cont, linesQ_Apa C_6res) { #line 33 "test/src/lines.act" self->a = C_6res; return linesQ_BepaG_newact((($Cont)linesQ_L_22ContG_new(self, C_cont))); } B_NoneType linesQ_L_23ContD___init__ (linesQ_L_23Cont L_self, linesQ_main self, $Cont C_cont) { L_self->self = self; L_self->C_cont = C_cont; return B_None; } $R linesQ_L_23ContD___call__ (linesQ_L_23Cont L_self, linesQ_Apa G_1) { linesQ_main self = L_self->self; $Cont C_cont = L_self->C_cont; return linesQ_L_11C_5cont(self, C_cont, G_1); } void linesQ_L_23ContD___serialize__ (linesQ_L_23Cont self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->C_cont, state); } linesQ_L_23Cont linesQ_L_23ContD___deserialize__ (linesQ_L_23Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_23Cont)); self->$class = &linesQ_L_23ContG_methods; return self; } self = $DNEW(linesQ_L_23Cont, state); } self->self = $step_deserialize(state); self->C_cont = $step_deserialize(state); return self; } linesQ_L_23Cont linesQ_L_23ContG_new(linesQ_main G_1, $Cont G_2) { linesQ_L_23Cont $tmp = acton_malloc(sizeof(struct linesQ_L_23Cont)); $tmp->$class = &linesQ_L_23ContG_methods; linesQ_L_23ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_23ContG_class linesQ_L_23ContG_methods; B_NoneType linesQ_L_24procD___init__ (linesQ_L_24proc L_self, linesQ_main self, B_int i) { L_self->self = self; L_self->i = i; return B_None; } $R linesQ_L_24procD___call__ (linesQ_L_24proc L_self, $Cont C_cont) { linesQ_main self = L_self->self; int64_t U_8i = ((B_int)L_self->i)->val; return (($R (*) (linesQ_main, $Cont, B_int))self->$class->myprocG_local)(self, C_cont, toB_int(U_8i)); } $R linesQ_L_24procD___exec__ (linesQ_L_24proc L_self, $Cont C_cont) { return (($R (*) (linesQ_L_24proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void linesQ_L_24procD___serialize__ (linesQ_L_24proc self, $Serial$state state) { $step_serialize(self->self, state); $step_serialize(self->i, state); } linesQ_L_24proc linesQ_L_24procD___deserialize__ (linesQ_L_24proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_24proc)); self->$class = &linesQ_L_24procG_methods; return self; } self = $DNEW(linesQ_L_24proc, state); } self->self = $step_deserialize(state); self->i = $step_deserialize(state); return self; } linesQ_L_24proc linesQ_L_24procG_new(linesQ_main G_1, B_int G_2) { linesQ_L_24proc $tmp = acton_malloc(sizeof(struct linesQ_L_24proc)); $tmp->$class = &linesQ_L_24procG_methods; linesQ_L_24procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_24procG_class linesQ_L_24procG_methods; B_NoneType linesQ_L_25procD___init__ (linesQ_L_25proc L_self, linesQ_main self) { L_self->self = self; return B_None; } $R linesQ_L_25procD___call__ (linesQ_L_25proc L_self, $Cont C_cont) { linesQ_main self = L_self->self; return (($R (*) (linesQ_main, $Cont))self->$class->nopG_local)(self, C_cont); } $R linesQ_L_25procD___exec__ (linesQ_L_25proc L_self, $Cont C_cont) { return (($R (*) (linesQ_L_25proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void linesQ_L_25procD___serialize__ (linesQ_L_25proc self, $Serial$state state) { $step_serialize(self->self, state); } linesQ_L_25proc linesQ_L_25procD___deserialize__ (linesQ_L_25proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_25proc)); self->$class = &linesQ_L_25procG_methods; return self; } self = $DNEW(linesQ_L_25proc, state); } self->self = $step_deserialize(state); return self; } linesQ_L_25proc linesQ_L_25procG_new(linesQ_main G_1) { linesQ_L_25proc $tmp = acton_malloc(sizeof(struct linesQ_L_25proc)); $tmp->$class = &linesQ_L_25procG_methods; linesQ_L_25procG_methods.__init__($tmp, G_1); return $tmp; } struct linesQ_L_25procG_class linesQ_L_25procG_methods; $R linesQ_L_26C_11cont ($Cont C_cont, linesQ_Apa G_act, B_NoneType C_12res) { return $R_CONT(C_cont, G_act); } B_NoneType linesQ_L_27ContD___init__ (linesQ_L_27Cont L_self, $Cont C_cont, linesQ_Apa G_act) { L_self->C_cont = C_cont; L_self->G_act = G_act; return B_None; } $R linesQ_L_27ContD___call__ (linesQ_L_27Cont L_self, B_NoneType G_1) { $Cont C_cont = L_self->C_cont; linesQ_Apa G_act = L_self->G_act; return linesQ_L_26C_11cont(C_cont, G_act, G_1); } void linesQ_L_27ContD___serialize__ (linesQ_L_27Cont self, $Serial$state state) { $step_serialize(self->C_cont, state); $step_serialize(self->G_act, state); } linesQ_L_27Cont linesQ_L_27ContD___deserialize__ (linesQ_L_27Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_27Cont)); self->$class = &linesQ_L_27ContG_methods; return self; } self = $DNEW(linesQ_L_27Cont, state); } self->C_cont = $step_deserialize(state); self->G_act = $step_deserialize(state); return self; } linesQ_L_27Cont linesQ_L_27ContG_new($Cont G_1, linesQ_Apa G_2) { linesQ_L_27Cont $tmp = acton_malloc(sizeof(struct linesQ_L_27Cont)); $tmp->$class = &linesQ_L_27ContG_methods; linesQ_L_27ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_27ContG_class linesQ_L_27ContG_methods; B_NoneType linesQ_L_28procD___init__ (linesQ_L_28proc L_self, linesQ_Apa G_act) { L_self->G_act = G_act; return B_None; } $R linesQ_L_28procD___call__ (linesQ_L_28proc L_self, $Cont C_cont) { linesQ_Apa G_act = L_self->G_act; return (($R (*) (linesQ_Apa, $Cont))G_act->$class->__init__)(G_act, C_cont); } $R linesQ_L_28procD___exec__ (linesQ_L_28proc L_self, $Cont C_cont) { return (($R (*) (linesQ_L_28proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void linesQ_L_28procD___serialize__ (linesQ_L_28proc self, $Serial$state state) { $step_serialize(self->G_act, state); } linesQ_L_28proc linesQ_L_28procD___deserialize__ (linesQ_L_28proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_28proc)); self->$class = &linesQ_L_28procG_methods; return self; } self = $DNEW(linesQ_L_28proc, state); } self->G_act = $step_deserialize(state); return self; } linesQ_L_28proc linesQ_L_28procG_new(linesQ_Apa G_1) { linesQ_L_28proc $tmp = acton_malloc(sizeof(struct linesQ_L_28proc)); $tmp->$class = &linesQ_L_28procG_methods; linesQ_L_28procG_methods.__init__($tmp, G_1); return $tmp; } struct linesQ_L_28procG_class linesQ_L_28procG_methods; $R linesQ_L_29C_13cont ($Cont C_cont, linesQ_Bepa G_act, B_NoneType C_14res) { return $R_CONT(C_cont, G_act); } B_NoneType linesQ_L_30ContD___init__ (linesQ_L_30Cont L_self, $Cont C_cont, linesQ_Bepa G_act) { L_self->C_cont = C_cont; L_self->G_act = G_act; return B_None; } $R linesQ_L_30ContD___call__ (linesQ_L_30Cont L_self, B_NoneType G_1) { $Cont C_cont = L_self->C_cont; linesQ_Bepa G_act = L_self->G_act; return linesQ_L_29C_13cont(C_cont, G_act, G_1); } void linesQ_L_30ContD___serialize__ (linesQ_L_30Cont self, $Serial$state state) { $step_serialize(self->C_cont, state); $step_serialize(self->G_act, state); } linesQ_L_30Cont linesQ_L_30ContD___deserialize__ (linesQ_L_30Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_30Cont)); self->$class = &linesQ_L_30ContG_methods; return self; } self = $DNEW(linesQ_L_30Cont, state); } self->C_cont = $step_deserialize(state); self->G_act = $step_deserialize(state); return self; } linesQ_L_30Cont linesQ_L_30ContG_new($Cont G_1, linesQ_Bepa G_2) { linesQ_L_30Cont $tmp = acton_malloc(sizeof(struct linesQ_L_30Cont)); $tmp->$class = &linesQ_L_30ContG_methods; linesQ_L_30ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_30ContG_class linesQ_L_30ContG_methods; B_NoneType linesQ_L_31procD___init__ (linesQ_L_31proc L_self, linesQ_Bepa G_act) { L_self->G_act = G_act; return B_None; } $R linesQ_L_31procD___call__ (linesQ_L_31proc L_self, $Cont C_cont) { linesQ_Bepa G_act = L_self->G_act; return (($R (*) (linesQ_Bepa, $Cont))G_act->$class->__init__)(G_act, C_cont); } $R linesQ_L_31procD___exec__ (linesQ_L_31proc L_self, $Cont C_cont) { return (($R (*) (linesQ_L_31proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void linesQ_L_31procD___serialize__ (linesQ_L_31proc self, $Serial$state state) { $step_serialize(self->G_act, state); } linesQ_L_31proc linesQ_L_31procD___deserialize__ (linesQ_L_31proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_31proc)); self->$class = &linesQ_L_31procG_methods; return self; } self = $DNEW(linesQ_L_31proc, state); } self->G_act = $step_deserialize(state); return self; } linesQ_L_31proc linesQ_L_31procG_new(linesQ_Bepa G_1) { linesQ_L_31proc $tmp = acton_malloc(sizeof(struct linesQ_L_31proc)); $tmp->$class = &linesQ_L_31procG_methods; linesQ_L_31procG_methods.__init__($tmp, G_1); return $tmp; } struct linesQ_L_31procG_class linesQ_L_31procG_methods; $R linesQ_L_32C_15cont ($Cont C_cont, linesQ_main G_act, B_NoneType C_16res) { return $R_CONT(C_cont, G_act); } B_NoneType linesQ_L_33ContD___init__ (linesQ_L_33Cont L_self, $Cont C_cont, linesQ_main G_act) { L_self->C_cont = C_cont; L_self->G_act = G_act; return B_None; } $R linesQ_L_33ContD___call__ (linesQ_L_33Cont L_self, B_NoneType G_1) { $Cont C_cont = L_self->C_cont; linesQ_main G_act = L_self->G_act; return linesQ_L_32C_15cont(C_cont, G_act, G_1); } void linesQ_L_33ContD___serialize__ (linesQ_L_33Cont self, $Serial$state state) { $step_serialize(self->C_cont, state); $step_serialize(self->G_act, state); } linesQ_L_33Cont linesQ_L_33ContD___deserialize__ (linesQ_L_33Cont self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_33Cont)); self->$class = &linesQ_L_33ContG_methods; return self; } self = $DNEW(linesQ_L_33Cont, state); } self->C_cont = $step_deserialize(state); self->G_act = $step_deserialize(state); return self; } linesQ_L_33Cont linesQ_L_33ContG_new($Cont G_1, linesQ_main G_2) { linesQ_L_33Cont $tmp = acton_malloc(sizeof(struct linesQ_L_33Cont)); $tmp->$class = &linesQ_L_33ContG_methods; linesQ_L_33ContG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_33ContG_class linesQ_L_33ContG_methods; B_NoneType linesQ_L_34procD___init__ (linesQ_L_34proc L_self, linesQ_main G_act, B_Env env) { L_self->G_act = G_act; L_self->env = env; return B_None; } $R linesQ_L_34procD___call__ (linesQ_L_34proc L_self, $Cont C_cont) { linesQ_main G_act = L_self->G_act; B_Env env = L_self->env; return (($R (*) (linesQ_main, $Cont, B_Env))G_act->$class->__init__)(G_act, C_cont, env); } $R linesQ_L_34procD___exec__ (linesQ_L_34proc L_self, $Cont C_cont) { return (($R (*) (linesQ_L_34proc, $Cont))L_self->$class->__call__)(L_self, C_cont); } void linesQ_L_34procD___serialize__ (linesQ_L_34proc self, $Serial$state state) { $step_serialize(self->G_act, state); $step_serialize(self->env, state); } linesQ_L_34proc linesQ_L_34procD___deserialize__ (linesQ_L_34proc self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_L_34proc)); self->$class = &linesQ_L_34procG_methods; return self; } self = $DNEW(linesQ_L_34proc, state); } self->G_act = $step_deserialize(state); self->env = $step_deserialize(state); return self; } linesQ_L_34proc linesQ_L_34procG_new(linesQ_main G_1, B_Env G_2) { linesQ_L_34proc $tmp = acton_malloc(sizeof(struct linesQ_L_34proc)); $tmp->$class = &linesQ_L_34procG_methods; linesQ_L_34procG_methods.__init__($tmp, G_1, G_2); return $tmp; } struct linesQ_L_34procG_class linesQ_L_34procG_methods; $R linesQ_ApaD___init__ (linesQ_Apa self, $Cont C_cont) { #line 2 "test/src/lines.act" self->apa = toB_int(2001LL); #line 6 "test/src/lines.act" self->apb = toB_int(2002LL); #line 16 "test/src/lines.act" self->y = toB_int(123LL); return (($R (*) (linesQ_Apa, $Cont, $action))self->$class->setupG_local)(self, (($Cont)linesQ_L_2ContG_new(self, C_cont)), (($action)linesQ_L_4actionG_new(self))); } #line 3 "test/src/lines.act" $R linesQ_ApaD_setupG_local (linesQ_Apa self, $Cont C_cont, $action cb) { #line 4 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("setup")), B_None, B_None, B_None, B_None); #line 5 "test/src/lines.act" ((B_Msg (*) ($action, B_int))cb->$class->__asyn__)(cb, toB_int(0LL)); return $R_CONT(C_cont, B_None); } #line 7 "test/src/lines.act" $R linesQ_ApaD_computeG_local (linesQ_Apa self, $Cont C_cont, $action cb) { #line 8 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("compute")), B_None, B_None, B_None, B_None); return $AWAIT((($Cont)linesQ_L_6ContG_new(cb, C_cont)), ((B_Msg)((B_Msg (*) ($action, B_int))cb->$class->__asyn__)(cb, toB_int(1LL)))); } #line 12 "test/src/lines.act" $R linesQ_ApaD_noticeG_local (linesQ_Apa self, $Cont C_cont, B_int i) { #line 13 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("notice")), B_None, B_None, B_None, B_None); int64_t U_9N_1tmp = (((B_int)i)->val + 1LL); return $R_CONT(C_cont, toB_int(U_9N_1tmp)); } B_Msg linesQ_ApaD_setup (linesQ_Apa self, $action cb) { return $ASYNC((($Actor)self), (($Cont)linesQ_L_7procG_new(self, cb))); } B_Msg linesQ_ApaD_compute (linesQ_Apa self, $action cb) { return ((B_Msg)$ASYNC((($Actor)self), (($Cont)linesQ_L_8procG_new(self, cb)))); } B_Msg linesQ_ApaD_notice (linesQ_Apa self, B_int i) { return ((B_Msg)$ASYNC((($Actor)self), (($Cont)linesQ_L_9procG_new(self, i)))); } void linesQ_ApaD___serialize__ (linesQ_Apa self, $Serial$state state) { $ActorG_methods.__serialize__(($Actor)self, state); $step_serialize(self->apa, state); $step_serialize(self->apb, state); $step_serialize(self->y, state); $step_serialize(self->z, state); } linesQ_Apa linesQ_ApaD___deserialize__ (linesQ_Apa self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_Apa)); self->$class = &linesQ_ApaG_methods; return self; } self = $DNEW(linesQ_Apa, state); } $ActorG_methods.__deserialize__(($Actor)self, state); self->apa = $step_deserialize(state); self->apb = $step_deserialize(state); self->y = $step_deserialize(state); self->z = $step_deserialize(state); return self; } void linesQ_ApaD_GCfinalizer (void *obj, void *cdata) { linesQ_Apa self = (linesQ_Apa)obj; self->$class->__cleanup__(self); } $R linesQ_ApaG_new($Cont G_1) { linesQ_Apa $tmp = acton_malloc(sizeof(struct linesQ_Apa)); $tmp->$class = &linesQ_ApaG_methods; return linesQ_ApaG_methods.__init__($tmp, $CONSTCONT($tmp, G_1)); } struct linesQ_ApaG_class linesQ_ApaG_methods; $R linesQ_BepaD___init__ (linesQ_Bepa self, $Cont C_cont) { #line 25 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(1, to$str("Bepa")), B_None, B_None, B_None, B_None); return $R_CONT(C_cont, B_None); } #line 22 "test/src/lines.act" $R linesQ_BepaD_callbackG_local (linesQ_Bepa self, $Cont C_cont, B_int i) { #line 23 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(2, to$str("callback"), i), B_None, B_None, B_None, B_None); int64_t U_10N_2tmp = (((B_int)i)->val + 1LL); return $R_CONT(C_cont, toB_int(U_10N_2tmp)); } B_Msg linesQ_BepaD_callback (linesQ_Bepa self, B_int i) { return ((B_Msg)$ASYNC((($Actor)self), (($Cont)linesQ_L_10procG_new(self, i)))); } void linesQ_BepaD___serialize__ (linesQ_Bepa self, $Serial$state state) { $ActorG_methods.__serialize__(($Actor)self, state); } linesQ_Bepa linesQ_BepaD___deserialize__ (linesQ_Bepa self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_Bepa)); self->$class = &linesQ_BepaG_methods; return self; } self = $DNEW(linesQ_Bepa, state); } $ActorG_methods.__deserialize__(($Actor)self, state); return self; } void linesQ_BepaD_GCfinalizer (void *obj, void *cdata) { linesQ_Bepa self = (linesQ_Bepa)obj; self->$class->__cleanup__(self); } $R linesQ_BepaG_new($Cont G_1) { linesQ_Bepa $tmp = acton_malloc(sizeof(struct linesQ_Bepa)); $tmp->$class = &linesQ_BepaG_methods; return linesQ_BepaG_methods.__init__($tmp, $CONSTCONT($tmp, G_1)); } struct linesQ_BepaG_class linesQ_BepaG_methods; $R linesQ_mainD___init__ (linesQ_main self, $Cont C_cont, B_Env env) { self->env = env; return linesQ_ApaG_newact((($Cont)linesQ_L_23ContG_new(self, C_cont))); } #line 28 "test/src/lines.act" $R linesQ_mainD_myprocG_local (linesQ_main self, $Cont C_cont, B_int i) { #line 29 "test/src/lines.act" ((B_NoneType (*) (B_tuple, B_str, B_str, B_bool, B_bool))B_print)($NEWTUPLE(2, to$str("myproc"), i), B_None, B_None, B_None, B_None); #line 30 "test/src/lines.act" if (((B_bool)((B_bool (*) (B_Eq, B_int, B_int))linesQ_W_Apa_331->$class->__eq__)(linesQ_W_Apa_331, i, toB_int(2LL)))->val) { #line 31 "test/src/lines.act" ((B_Msg (*) (B_Env, B_int))self->env->$class->exit)(self->env, toB_int(0LL)); } return $R_CONT(C_cont, i); } #line 92 "test/src/lines.act" $R linesQ_mainD_nopG_local (linesQ_main self, $Cont C_cont) { #line 93 "test/src/lines.act" return $R_CONT(C_cont, B_None); } B_Msg linesQ_mainD_myproc (linesQ_main self, B_int i) { return ((B_Msg)$ASYNC((($Actor)self), (($Cont)linesQ_L_24procG_new(self, i)))); } B_Msg linesQ_mainD_nop (linesQ_main self) { return $ASYNC((($Actor)self), (($Cont)linesQ_L_25procG_new(self))); } void linesQ_mainD___serialize__ (linesQ_main self, $Serial$state state) { $ActorG_methods.__serialize__(($Actor)self, state); $step_serialize(self->env, state); $step_serialize(self->a, state); $step_serialize(self->b, state); $step_serialize(self->x, state); $step_serialize(self->r, state); $step_serialize(self->v, state); $step_serialize(self->i, state); } linesQ_main linesQ_mainD___deserialize__ (linesQ_main self, $Serial$state state) { if (!self) { if (!state) { self = acton_malloc(sizeof(struct linesQ_main)); self->$class = &linesQ_mainG_methods; return self; } self = $DNEW(linesQ_main, state); } $ActorG_methods.__deserialize__(($Actor)self, state); self->env = $step_deserialize(state); self->a = $step_deserialize(state); self->b = $step_deserialize(state); self->x = $step_deserialize(state); self->r = $step_deserialize(state); self->v = $step_deserialize(state); self->i = $step_deserialize(state); return self; } void linesQ_mainD_GCfinalizer (void *obj, void *cdata) { linesQ_main self = (linesQ_main)obj; self->$class->__cleanup__(self); } $R linesQ_mainG_new($Cont G_1, B_Env G_2) { linesQ_main $tmp = acton_malloc(sizeof(struct linesQ_main)); $tmp->$class = &linesQ_mainG_methods; return linesQ_mainG_methods.__init__($tmp, $CONSTCONT($tmp, G_1), G_2); } struct linesQ_mainG_class linesQ_mainG_methods; $R linesQ_ApaG_newact ($Cont C_cont) { linesQ_Apa G_act = $NEWACTOR(linesQ_Apa); if ((void*)G_act->$class->__cleanup__ != (void*)$ActorD___cleanup__) $InstallFinalizer(G_act, linesQ_ApaD_GCfinalizer); return $AWAIT((($Cont)linesQ_L_27ContG_new(C_cont, G_act)), $ASYNC((($Actor)G_act), (($Cont)linesQ_L_28procG_new(G_act)))); } $R linesQ_BepaG_newact ($Cont C_cont) { linesQ_Bepa G_act = $NEWACTOR(linesQ_Bepa); if ((void*)G_act->$class->__cleanup__ != (void*)$ActorD___cleanup__) $InstallFinalizer(G_act, linesQ_BepaD_GCfinalizer); return $AWAIT((($Cont)linesQ_L_30ContG_new(C_cont, G_act)), $ASYNC((($Actor)G_act), (($Cont)linesQ_L_31procG_new(G_act)))); } $R linesQ_mainG_newact ($Cont C_cont, B_Env env) { linesQ_main G_act = $NEWACTOR(linesQ_main); if ((void*)G_act->$class->__cleanup__ != (void*)$ActorD___cleanup__) $InstallFinalizer(G_act, linesQ_mainD_GCfinalizer); return $AWAIT((($Cont)linesQ_L_33ContG_new(C_cont, G_act)), $ASYNC((($Actor)G_act), (($Cont)linesQ_L_34procG_new(G_act, env)))); } int linesQ_done$ = 0; void linesQ___init__ () { if (linesQ_done$) return; linesQ_done$ = 1; { linesQ_L_2ContG_methods.$GCINFO = "linesQ_L_2Cont"; linesQ_L_2ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; linesQ_L_2ContG_methods.__bool__ = (B_bool (*) (linesQ_L_2Cont))B_valueG_methods.__bool__; linesQ_L_2ContG_methods.__str__ = (B_str (*) (linesQ_L_2Cont))B_valueG_methods.__str__; linesQ_L_2ContG_methods.__repr__ = (B_str (*) (linesQ_L_2Cont))B_valueG_methods.__repr__; linesQ_L_2ContG_methods.__init__ = linesQ_L_2ContD___init__; linesQ_L_2ContG_methods.__call__ = linesQ_L_2ContD___call__; linesQ_L_2ContG_methods.__serialize__ = linesQ_L_2ContD___serialize__; linesQ_L_2ContG_methods.__deserialize__ = linesQ_L_2ContD___deserialize__; $register(&linesQ_L_2ContG_methods); } { linesQ_L_4actionG_methods.$GCINFO = "linesQ_L_4action"; linesQ_L_4actionG_methods.$superclass = ($SuperG_class)&$actionG_methods; linesQ_L_4actionG_methods.__bool__ = (B_bool (*) (linesQ_L_4action))B_valueG_methods.__bool__; linesQ_L_4actionG_methods.__str__ = (B_str (*) (linesQ_L_4action))B_valueG_methods.__str__; linesQ_L_4actionG_methods.__repr__ = (B_str (*) (linesQ_L_4action))B_valueG_methods.__repr__; linesQ_L_4actionG_methods.__init__ = linesQ_L_4actionD___init__; linesQ_L_4actionG_methods.__call__ = linesQ_L_4actionD___call__; linesQ_L_4actionG_methods.__exec__ = linesQ_L_4actionD___exec__; linesQ_L_4actionG_methods.__asyn__ = linesQ_L_4actionD___asyn__; linesQ_L_4actionG_methods.__serialize__ = linesQ_L_4actionD___serialize__; linesQ_L_4actionG_methods.__deserialize__ = linesQ_L_4actionD___deserialize__; $register(&linesQ_L_4actionG_methods); } { linesQ_L_6ContG_methods.$GCINFO = "linesQ_L_6Cont"; linesQ_L_6ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; linesQ_L_6ContG_methods.__bool__ = (B_bool (*) (linesQ_L_6Cont))B_valueG_methods.__bool__; linesQ_L_6ContG_methods.__str__ = (B_str (*) (linesQ_L_6Cont))B_valueG_methods.__str__; linesQ_L_6ContG_methods.__repr__ = (B_str (*) (linesQ_L_6Cont))B_valueG_methods.__repr__; linesQ_L_6ContG_methods.__init__ = linesQ_L_6ContD___init__; linesQ_L_6ContG_methods.__call__ = linesQ_L_6ContD___call__; linesQ_L_6ContG_methods.__serialize__ = linesQ_L_6ContD___serialize__; linesQ_L_6ContG_methods.__deserialize__ = linesQ_L_6ContD___deserialize__; $register(&linesQ_L_6ContG_methods); } { linesQ_L_7procG_methods.$GCINFO = "linesQ_L_7proc"; linesQ_L_7procG_methods.$superclass = ($SuperG_class)&$procG_methods; linesQ_L_7procG_methods.__bool__ = (B_bool (*) (linesQ_L_7proc))B_valueG_methods.__bool__; linesQ_L_7procG_methods.__str__ = (B_str (*) (linesQ_L_7proc))B_valueG_methods.__str__; linesQ_L_7procG_methods.__repr__ = (B_str (*) (linesQ_L_7proc))B_valueG_methods.__repr__; linesQ_L_7procG_methods.__init__ = linesQ_L_7procD___init__; linesQ_L_7procG_methods.__call__ = linesQ_L_7procD___call__; linesQ_L_7procG_methods.__exec__ = linesQ_L_7procD___exec__; linesQ_L_7procG_methods.__serialize__ = linesQ_L_7procD___serialize__; linesQ_L_7procG_methods.__deserialize__ = linesQ_L_7procD___deserialize__; $register(&linesQ_L_7procG_methods); } { linesQ_L_8procG_methods.$GCINFO = "linesQ_L_8proc"; linesQ_L_8procG_methods.$superclass = ($SuperG_class)&$procG_methods; linesQ_L_8procG_methods.__bool__ = (B_bool (*) (linesQ_L_8proc))B_valueG_methods.__bool__; linesQ_L_8procG_methods.__str__ = (B_str (*) (linesQ_L_8proc))B_valueG_methods.__str__; linesQ_L_8procG_methods.__repr__ = (B_str (*) (linesQ_L_8proc))B_valueG_methods.__repr__; linesQ_L_8procG_methods.__init__ = linesQ_L_8procD___init__; linesQ_L_8procG_methods.__call__ = linesQ_L_8procD___call__; linesQ_L_8procG_methods.__exec__ = linesQ_L_8procD___exec__; linesQ_L_8procG_methods.__serialize__ = linesQ_L_8procD___serialize__; linesQ_L_8procG_methods.__deserialize__ = linesQ_L_8procD___deserialize__; $register(&linesQ_L_8procG_methods); } { linesQ_L_9procG_methods.$GCINFO = "linesQ_L_9proc"; linesQ_L_9procG_methods.$superclass = ($SuperG_class)&$procG_methods; linesQ_L_9procG_methods.__bool__ = (B_bool (*) (linesQ_L_9proc))B_valueG_methods.__bool__; linesQ_L_9procG_methods.__str__ = (B_str (*) (linesQ_L_9proc))B_valueG_methods.__str__; linesQ_L_9procG_methods.__repr__ = (B_str (*) (linesQ_L_9proc))B_valueG_methods.__repr__; linesQ_L_9procG_methods.__init__ = linesQ_L_9procD___init__; linesQ_L_9procG_methods.__call__ = linesQ_L_9procD___call__; linesQ_L_9procG_methods.__exec__ = linesQ_L_9procD___exec__; linesQ_L_9procG_methods.__serialize__ = linesQ_L_9procD___serialize__; linesQ_L_9procG_methods.__deserialize__ = linesQ_L_9procD___deserialize__; $register(&linesQ_L_9procG_methods); } { linesQ_L_10procG_methods.$GCINFO = "linesQ_L_10proc"; linesQ_L_10procG_methods.$superclass = ($SuperG_class)&$procG_methods; linesQ_L_10procG_methods.__bool__ = (B_bool (*) (linesQ_L_10proc))B_valueG_methods.__bool__; linesQ_L_10procG_methods.__str__ = (B_str (*) (linesQ_L_10proc))B_valueG_methods.__str__; linesQ_L_10procG_methods.__repr__ = (B_str (*) (linesQ_L_10proc))B_valueG_methods.__repr__; linesQ_L_10procG_methods.__init__ = linesQ_L_10procD___init__; linesQ_L_10procG_methods.__call__ = linesQ_L_10procD___call__; linesQ_L_10procG_methods.__exec__ = linesQ_L_10procD___exec__; linesQ_L_10procG_methods.__serialize__ = linesQ_L_10procD___serialize__; linesQ_L_10procG_methods.__deserialize__ = linesQ_L_10procD___deserialize__; $register(&linesQ_L_10procG_methods); } { linesQ_L_14actionG_methods.$GCINFO = "linesQ_L_14action"; linesQ_L_14actionG_methods.$superclass = ($SuperG_class)&$actionG_methods; linesQ_L_14actionG_methods.__bool__ = (B_bool (*) (linesQ_L_14action))B_valueG_methods.__bool__; linesQ_L_14actionG_methods.__str__ = (B_str (*) (linesQ_L_14action))B_valueG_methods.__str__; linesQ_L_14actionG_methods.__repr__ = (B_str (*) (linesQ_L_14action))B_valueG_methods.__repr__; linesQ_L_14actionG_methods.__init__ = linesQ_L_14actionD___init__; linesQ_L_14actionG_methods.__call__ = linesQ_L_14actionD___call__; linesQ_L_14actionG_methods.__exec__ = linesQ_L_14actionD___exec__; linesQ_L_14actionG_methods.__asyn__ = linesQ_L_14actionD___asyn__; linesQ_L_14actionG_methods.__serialize__ = linesQ_L_14actionD___serialize__; linesQ_L_14actionG_methods.__deserialize__ = linesQ_L_14actionD___deserialize__; $register(&linesQ_L_14actionG_methods); } { linesQ_L_16actionG_methods.$GCINFO = "linesQ_L_16action"; linesQ_L_16actionG_methods.$superclass = ($SuperG_class)&$actionG_methods; linesQ_L_16actionG_methods.__bool__ = (B_bool (*) (linesQ_L_16action))B_valueG_methods.__bool__; linesQ_L_16actionG_methods.__str__ = (B_str (*) (linesQ_L_16action))B_valueG_methods.__str__; linesQ_L_16actionG_methods.__repr__ = (B_str (*) (linesQ_L_16action))B_valueG_methods.__repr__; linesQ_L_16actionG_methods.__init__ = linesQ_L_16actionD___init__; linesQ_L_16actionG_methods.__call__ = linesQ_L_16actionD___call__; linesQ_L_16actionG_methods.__exec__ = linesQ_L_16actionD___exec__; linesQ_L_16actionG_methods.__asyn__ = linesQ_L_16actionD___asyn__; linesQ_L_16actionG_methods.__serialize__ = linesQ_L_16actionD___serialize__; linesQ_L_16actionG_methods.__deserialize__ = linesQ_L_16actionD___deserialize__; $register(&linesQ_L_16actionG_methods); } { linesQ_L_19actionG_methods.$GCINFO = "linesQ_L_19action"; linesQ_L_19actionG_methods.$superclass = ($SuperG_class)&$actionG_methods; linesQ_L_19actionG_methods.__bool__ = (B_bool (*) (linesQ_L_19action))B_valueG_methods.__bool__; linesQ_L_19actionG_methods.__str__ = (B_str (*) (linesQ_L_19action))B_valueG_methods.__str__; linesQ_L_19actionG_methods.__repr__ = (B_str (*) (linesQ_L_19action))B_valueG_methods.__repr__; linesQ_L_19actionG_methods.__init__ = linesQ_L_19actionD___init__; linesQ_L_19actionG_methods.__call__ = linesQ_L_19actionD___call__; linesQ_L_19actionG_methods.__exec__ = linesQ_L_19actionD___exec__; linesQ_L_19actionG_methods.__asyn__ = linesQ_L_19actionD___asyn__; linesQ_L_19actionG_methods.__serialize__ = linesQ_L_19actionD___serialize__; linesQ_L_19actionG_methods.__deserialize__ = linesQ_L_19actionD___deserialize__; $register(&linesQ_L_19actionG_methods); } { linesQ_L_20procG_methods.$GCINFO = "linesQ_L_20proc"; linesQ_L_20procG_methods.$superclass = ($SuperG_class)&$procG_methods; linesQ_L_20procG_methods.__bool__ = (B_bool (*) (linesQ_L_20proc))B_valueG_methods.__bool__; linesQ_L_20procG_methods.__str__ = (B_str (*) (linesQ_L_20proc))B_valueG_methods.__str__; linesQ_L_20procG_methods.__repr__ = (B_str (*) (linesQ_L_20proc))B_valueG_methods.__repr__; linesQ_L_20procG_methods.__init__ = linesQ_L_20procD___init__; linesQ_L_20procG_methods.__call__ = linesQ_L_20procD___call__; linesQ_L_20procG_methods.__exec__ = linesQ_L_20procD___exec__; linesQ_L_20procG_methods.__serialize__ = linesQ_L_20procD___serialize__; linesQ_L_20procG_methods.__deserialize__ = linesQ_L_20procD___deserialize__; $register(&linesQ_L_20procG_methods); } { linesQ_L_21ContG_methods.$GCINFO = "linesQ_L_21Cont"; linesQ_L_21ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; linesQ_L_21ContG_methods.__bool__ = (B_bool (*) (linesQ_L_21Cont))B_valueG_methods.__bool__; linesQ_L_21ContG_methods.__str__ = (B_str (*) (linesQ_L_21Cont))B_valueG_methods.__str__; linesQ_L_21ContG_methods.__repr__ = (B_str (*) (linesQ_L_21Cont))B_valueG_methods.__repr__; linesQ_L_21ContG_methods.__init__ = linesQ_L_21ContD___init__; linesQ_L_21ContG_methods.__call__ = linesQ_L_21ContD___call__; linesQ_L_21ContG_methods.__serialize__ = linesQ_L_21ContD___serialize__; linesQ_L_21ContG_methods.__deserialize__ = linesQ_L_21ContD___deserialize__; $register(&linesQ_L_21ContG_methods); } { linesQ_L_22ContG_methods.$GCINFO = "linesQ_L_22Cont"; linesQ_L_22ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; linesQ_L_22ContG_methods.__bool__ = (B_bool (*) (linesQ_L_22Cont))B_valueG_methods.__bool__; linesQ_L_22ContG_methods.__str__ = (B_str (*) (linesQ_L_22Cont))B_valueG_methods.__str__; linesQ_L_22ContG_methods.__repr__ = (B_str (*) (linesQ_L_22Cont))B_valueG_methods.__repr__; linesQ_L_22ContG_methods.__init__ = linesQ_L_22ContD___init__; linesQ_L_22ContG_methods.__call__ = linesQ_L_22ContD___call__; linesQ_L_22ContG_methods.__serialize__ = linesQ_L_22ContD___serialize__; linesQ_L_22ContG_methods.__deserialize__ = linesQ_L_22ContD___deserialize__; $register(&linesQ_L_22ContG_methods); } { linesQ_L_23ContG_methods.$GCINFO = "linesQ_L_23Cont"; linesQ_L_23ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; linesQ_L_23ContG_methods.__bool__ = (B_bool (*) (linesQ_L_23Cont))B_valueG_methods.__bool__; linesQ_L_23ContG_methods.__str__ = (B_str (*) (linesQ_L_23Cont))B_valueG_methods.__str__; linesQ_L_23ContG_methods.__repr__ = (B_str (*) (linesQ_L_23Cont))B_valueG_methods.__repr__; linesQ_L_23ContG_methods.__init__ = linesQ_L_23ContD___init__; linesQ_L_23ContG_methods.__call__ = linesQ_L_23ContD___call__; linesQ_L_23ContG_methods.__serialize__ = linesQ_L_23ContD___serialize__; linesQ_L_23ContG_methods.__deserialize__ = linesQ_L_23ContD___deserialize__; $register(&linesQ_L_23ContG_methods); } { linesQ_L_24procG_methods.$GCINFO = "linesQ_L_24proc"; linesQ_L_24procG_methods.$superclass = ($SuperG_class)&$procG_methods; linesQ_L_24procG_methods.__bool__ = (B_bool (*) (linesQ_L_24proc))B_valueG_methods.__bool__; linesQ_L_24procG_methods.__str__ = (B_str (*) (linesQ_L_24proc))B_valueG_methods.__str__; linesQ_L_24procG_methods.__repr__ = (B_str (*) (linesQ_L_24proc))B_valueG_methods.__repr__; linesQ_L_24procG_methods.__init__ = linesQ_L_24procD___init__; linesQ_L_24procG_methods.__call__ = linesQ_L_24procD___call__; linesQ_L_24procG_methods.__exec__ = linesQ_L_24procD___exec__; linesQ_L_24procG_methods.__serialize__ = linesQ_L_24procD___serialize__; linesQ_L_24procG_methods.__deserialize__ = linesQ_L_24procD___deserialize__; $register(&linesQ_L_24procG_methods); } { linesQ_L_25procG_methods.$GCINFO = "linesQ_L_25proc"; linesQ_L_25procG_methods.$superclass = ($SuperG_class)&$procG_methods; linesQ_L_25procG_methods.__bool__ = (B_bool (*) (linesQ_L_25proc))B_valueG_methods.__bool__; linesQ_L_25procG_methods.__str__ = (B_str (*) (linesQ_L_25proc))B_valueG_methods.__str__; linesQ_L_25procG_methods.__repr__ = (B_str (*) (linesQ_L_25proc))B_valueG_methods.__repr__; linesQ_L_25procG_methods.__init__ = linesQ_L_25procD___init__; linesQ_L_25procG_methods.__call__ = linesQ_L_25procD___call__; linesQ_L_25procG_methods.__exec__ = linesQ_L_25procD___exec__; linesQ_L_25procG_methods.__serialize__ = linesQ_L_25procD___serialize__; linesQ_L_25procG_methods.__deserialize__ = linesQ_L_25procD___deserialize__; $register(&linesQ_L_25procG_methods); } { linesQ_L_27ContG_methods.$GCINFO = "linesQ_L_27Cont"; linesQ_L_27ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; linesQ_L_27ContG_methods.__bool__ = (B_bool (*) (linesQ_L_27Cont))B_valueG_methods.__bool__; linesQ_L_27ContG_methods.__str__ = (B_str (*) (linesQ_L_27Cont))B_valueG_methods.__str__; linesQ_L_27ContG_methods.__repr__ = (B_str (*) (linesQ_L_27Cont))B_valueG_methods.__repr__; linesQ_L_27ContG_methods.__init__ = linesQ_L_27ContD___init__; linesQ_L_27ContG_methods.__call__ = linesQ_L_27ContD___call__; linesQ_L_27ContG_methods.__serialize__ = linesQ_L_27ContD___serialize__; linesQ_L_27ContG_methods.__deserialize__ = linesQ_L_27ContD___deserialize__; $register(&linesQ_L_27ContG_methods); } { linesQ_L_28procG_methods.$GCINFO = "linesQ_L_28proc"; linesQ_L_28procG_methods.$superclass = ($SuperG_class)&$procG_methods; linesQ_L_28procG_methods.__bool__ = (B_bool (*) (linesQ_L_28proc))B_valueG_methods.__bool__; linesQ_L_28procG_methods.__str__ = (B_str (*) (linesQ_L_28proc))B_valueG_methods.__str__; linesQ_L_28procG_methods.__repr__ = (B_str (*) (linesQ_L_28proc))B_valueG_methods.__repr__; linesQ_L_28procG_methods.__init__ = linesQ_L_28procD___init__; linesQ_L_28procG_methods.__call__ = linesQ_L_28procD___call__; linesQ_L_28procG_methods.__exec__ = linesQ_L_28procD___exec__; linesQ_L_28procG_methods.__serialize__ = linesQ_L_28procD___serialize__; linesQ_L_28procG_methods.__deserialize__ = linesQ_L_28procD___deserialize__; $register(&linesQ_L_28procG_methods); } { linesQ_L_30ContG_methods.$GCINFO = "linesQ_L_30Cont"; linesQ_L_30ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; linesQ_L_30ContG_methods.__bool__ = (B_bool (*) (linesQ_L_30Cont))B_valueG_methods.__bool__; linesQ_L_30ContG_methods.__str__ = (B_str (*) (linesQ_L_30Cont))B_valueG_methods.__str__; linesQ_L_30ContG_methods.__repr__ = (B_str (*) (linesQ_L_30Cont))B_valueG_methods.__repr__; linesQ_L_30ContG_methods.__init__ = linesQ_L_30ContD___init__; linesQ_L_30ContG_methods.__call__ = linesQ_L_30ContD___call__; linesQ_L_30ContG_methods.__serialize__ = linesQ_L_30ContD___serialize__; linesQ_L_30ContG_methods.__deserialize__ = linesQ_L_30ContD___deserialize__; $register(&linesQ_L_30ContG_methods); } { linesQ_L_31procG_methods.$GCINFO = "linesQ_L_31proc"; linesQ_L_31procG_methods.$superclass = ($SuperG_class)&$procG_methods; linesQ_L_31procG_methods.__bool__ = (B_bool (*) (linesQ_L_31proc))B_valueG_methods.__bool__; linesQ_L_31procG_methods.__str__ = (B_str (*) (linesQ_L_31proc))B_valueG_methods.__str__; linesQ_L_31procG_methods.__repr__ = (B_str (*) (linesQ_L_31proc))B_valueG_methods.__repr__; linesQ_L_31procG_methods.__init__ = linesQ_L_31procD___init__; linesQ_L_31procG_methods.__call__ = linesQ_L_31procD___call__; linesQ_L_31procG_methods.__exec__ = linesQ_L_31procD___exec__; linesQ_L_31procG_methods.__serialize__ = linesQ_L_31procD___serialize__; linesQ_L_31procG_methods.__deserialize__ = linesQ_L_31procD___deserialize__; $register(&linesQ_L_31procG_methods); } { linesQ_L_33ContG_methods.$GCINFO = "linesQ_L_33Cont"; linesQ_L_33ContG_methods.$superclass = ($SuperG_class)&$ContG_methods; linesQ_L_33ContG_methods.__bool__ = (B_bool (*) (linesQ_L_33Cont))B_valueG_methods.__bool__; linesQ_L_33ContG_methods.__str__ = (B_str (*) (linesQ_L_33Cont))B_valueG_methods.__str__; linesQ_L_33ContG_methods.__repr__ = (B_str (*) (linesQ_L_33Cont))B_valueG_methods.__repr__; linesQ_L_33ContG_methods.__init__ = linesQ_L_33ContD___init__; linesQ_L_33ContG_methods.__call__ = linesQ_L_33ContD___call__; linesQ_L_33ContG_methods.__serialize__ = linesQ_L_33ContD___serialize__; linesQ_L_33ContG_methods.__deserialize__ = linesQ_L_33ContD___deserialize__; $register(&linesQ_L_33ContG_methods); } { linesQ_L_34procG_methods.$GCINFO = "linesQ_L_34proc"; linesQ_L_34procG_methods.$superclass = ($SuperG_class)&$procG_methods; linesQ_L_34procG_methods.__bool__ = (B_bool (*) (linesQ_L_34proc))B_valueG_methods.__bool__; linesQ_L_34procG_methods.__str__ = (B_str (*) (linesQ_L_34proc))B_valueG_methods.__str__; linesQ_L_34procG_methods.__repr__ = (B_str (*) (linesQ_L_34proc))B_valueG_methods.__repr__; linesQ_L_34procG_methods.__init__ = linesQ_L_34procD___init__; linesQ_L_34procG_methods.__call__ = linesQ_L_34procD___call__; linesQ_L_34procG_methods.__exec__ = linesQ_L_34procD___exec__; linesQ_L_34procG_methods.__serialize__ = linesQ_L_34procD___serialize__; linesQ_L_34procG_methods.__deserialize__ = linesQ_L_34procD___deserialize__; $register(&linesQ_L_34procG_methods); } { linesQ_ApaG_methods.$GCINFO = "linesQ_Apa"; linesQ_ApaG_methods.$superclass = ($SuperG_class)&$ActorG_methods; linesQ_ApaG_methods.__bool__ = (B_bool (*) (linesQ_Apa))$ActorG_methods.__bool__; linesQ_ApaG_methods.__str__ = (B_str (*) (linesQ_Apa))$ActorG_methods.__str__; linesQ_ApaG_methods.__repr__ = (B_str (*) (linesQ_Apa))$ActorG_methods.__repr__; linesQ_ApaG_methods.__resume__ = (B_NoneType (*) (linesQ_Apa))$ActorG_methods.__resume__; linesQ_ApaG_methods.__cleanup__ = (B_NoneType (*) (linesQ_Apa))$ActorG_methods.__cleanup__; linesQ_ApaG_methods.__init__ = linesQ_ApaD___init__; linesQ_ApaG_methods.setupG_local = linesQ_ApaD_setupG_local; linesQ_ApaG_methods.computeG_local = linesQ_ApaD_computeG_local; linesQ_ApaG_methods.noticeG_local = linesQ_ApaD_noticeG_local; linesQ_ApaG_methods.setup = linesQ_ApaD_setup; linesQ_ApaG_methods.compute = linesQ_ApaD_compute; linesQ_ApaG_methods.notice = linesQ_ApaD_notice; linesQ_ApaG_methods.__serialize__ = linesQ_ApaD___serialize__; linesQ_ApaG_methods.__deserialize__ = linesQ_ApaD___deserialize__; $register(&linesQ_ApaG_methods); } { linesQ_BepaG_methods.$GCINFO = "linesQ_Bepa"; linesQ_BepaG_methods.$superclass = ($SuperG_class)&$ActorG_methods; linesQ_BepaG_methods.__bool__ = (B_bool (*) (linesQ_Bepa))$ActorG_methods.__bool__; linesQ_BepaG_methods.__str__ = (B_str (*) (linesQ_Bepa))$ActorG_methods.__str__; linesQ_BepaG_methods.__repr__ = (B_str (*) (linesQ_Bepa))$ActorG_methods.__repr__; linesQ_BepaG_methods.__resume__ = (B_NoneType (*) (linesQ_Bepa))$ActorG_methods.__resume__; linesQ_BepaG_methods.__cleanup__ = (B_NoneType (*) (linesQ_Bepa))$ActorG_methods.__cleanup__; linesQ_BepaG_methods.__init__ = linesQ_BepaD___init__; linesQ_BepaG_methods.callbackG_local = linesQ_BepaD_callbackG_local; linesQ_BepaG_methods.callback = linesQ_BepaD_callback; linesQ_BepaG_methods.__serialize__ = linesQ_BepaD___serialize__; linesQ_BepaG_methods.__deserialize__ = linesQ_BepaD___deserialize__; $register(&linesQ_BepaG_methods); } { linesQ_mainG_methods.$GCINFO = "linesQ_main"; linesQ_mainG_methods.$superclass = ($SuperG_class)&$ActorG_methods; linesQ_mainG_methods.__bool__ = (B_bool (*) (linesQ_main))$ActorG_methods.__bool__; linesQ_mainG_methods.__str__ = (B_str (*) (linesQ_main))$ActorG_methods.__str__; linesQ_mainG_methods.__repr__ = (B_str (*) (linesQ_main))$ActorG_methods.__repr__; linesQ_mainG_methods.__resume__ = (B_NoneType (*) (linesQ_main))$ActorG_methods.__resume__; linesQ_mainG_methods.__cleanup__ = (B_NoneType (*) (linesQ_main))$ActorG_methods.__cleanup__; linesQ_mainG_methods.__init__ = linesQ_mainD___init__; linesQ_mainG_methods.myprocG_local = linesQ_mainD_myprocG_local; linesQ_mainG_methods.nopG_local = linesQ_mainD_nopG_local; linesQ_mainG_methods.myproc = linesQ_mainD_myproc; linesQ_mainG_methods.nop = linesQ_mainD_nop; linesQ_mainG_methods.__serialize__ = linesQ_mainD___serialize__; linesQ_mainG_methods.__deserialize__ = linesQ_mainD___deserialize__; $register(&linesQ_mainG_methods); } B_Eq W_Apa_1097 = (B_Eq)B_OrdD_intG_witness; linesQ_W_Apa_1097 = W_Apa_1097; B_Eq W_Apa_759 = ((B_Eq)$EqOptG_new(linesQ_W_Apa_1097)); linesQ_W_Apa_759 = W_Apa_759; B_Iterable W_Apa_779 = (B_Iterable)B_SequenceD_listG_witness->W_Collection; linesQ_W_Apa_779 = W_Apa_779; B_Eq W_Apa_331 = ((B_Eq)$EqOptG_new(linesQ_W_Apa_1097)); linesQ_W_Apa_331 = W_Apa_331; B_Eq W_Apa_785 = ((B_Eq)$EqOptG_new(linesQ_W_Apa_1097)); linesQ_W_Apa_785 = W_Apa_785; } ================================================ FILE: compiler/lib/test/9-codegen/lines.h ================================================ /* Acton impl hash: test-hash */ #pragma once #include "builtin/builtin.h" #include "rts/rts.h" struct linesQ_L_2Cont; struct linesQ_L_4action; struct linesQ_L_6Cont; struct linesQ_L_7proc; struct linesQ_L_8proc; struct linesQ_L_9proc; struct linesQ_L_10proc; struct linesQ_L_14action; struct linesQ_L_16action; struct linesQ_L_19action; struct linesQ_L_20proc; struct linesQ_L_21Cont; struct linesQ_L_22Cont; struct linesQ_L_23Cont; struct linesQ_L_24proc; struct linesQ_L_25proc; struct linesQ_L_27Cont; struct linesQ_L_28proc; struct linesQ_L_30Cont; struct linesQ_L_31proc; struct linesQ_L_33Cont; struct linesQ_L_34proc; struct linesQ_Apa; struct linesQ_Bepa; struct linesQ_main; typedef struct linesQ_L_2Cont *linesQ_L_2Cont; typedef struct linesQ_L_4action *linesQ_L_4action; typedef struct linesQ_L_6Cont *linesQ_L_6Cont; typedef struct linesQ_L_7proc *linesQ_L_7proc; typedef struct linesQ_L_8proc *linesQ_L_8proc; typedef struct linesQ_L_9proc *linesQ_L_9proc; typedef struct linesQ_L_10proc *linesQ_L_10proc; typedef struct linesQ_L_14action *linesQ_L_14action; typedef struct linesQ_L_16action *linesQ_L_16action; typedef struct linesQ_L_19action *linesQ_L_19action; typedef struct linesQ_L_20proc *linesQ_L_20proc; typedef struct linesQ_L_21Cont *linesQ_L_21Cont; typedef struct linesQ_L_22Cont *linesQ_L_22Cont; typedef struct linesQ_L_23Cont *linesQ_L_23Cont; typedef struct linesQ_L_24proc *linesQ_L_24proc; typedef struct linesQ_L_25proc *linesQ_L_25proc; typedef struct linesQ_L_27Cont *linesQ_L_27Cont; typedef struct linesQ_L_28proc *linesQ_L_28proc; typedef struct linesQ_L_30Cont *linesQ_L_30Cont; typedef struct linesQ_L_31proc *linesQ_L_31proc; typedef struct linesQ_L_33Cont *linesQ_L_33Cont; typedef struct linesQ_L_34proc *linesQ_L_34proc; typedef struct linesQ_Apa *linesQ_Apa; typedef struct linesQ_Bepa *linesQ_Bepa; typedef struct linesQ_main *linesQ_main; $R linesQ_L_1C_1cont (linesQ_Apa, $Cont, B_NoneType); struct linesQ_L_2ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_2Cont, linesQ_Apa, $Cont); void (*__serialize__) (linesQ_L_2Cont, $Serial$state); linesQ_L_2Cont (*__deserialize__) (linesQ_L_2Cont, $Serial$state); B_bool (*__bool__) (linesQ_L_2Cont); B_str (*__str__) (linesQ_L_2Cont); B_str (*__repr__) (linesQ_L_2Cont); $R (*__call__) (linesQ_L_2Cont, B_NoneType); }; struct linesQ_L_2Cont { struct linesQ_L_2ContG_class *$class; linesQ_Apa self; $Cont C_cont; }; struct linesQ_L_4actionG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_4action, linesQ_Apa); void (*__serialize__) (linesQ_L_4action, $Serial$state); linesQ_L_4action (*__deserialize__) (linesQ_L_4action, $Serial$state); B_bool (*__bool__) (linesQ_L_4action); B_str (*__str__) (linesQ_L_4action); B_str (*__repr__) (linesQ_L_4action); $R (*__call__) (linesQ_L_4action, $Cont, B_int); $R (*__exec__) (linesQ_L_4action, $Cont, B_int); B_Msg (*__asyn__) (linesQ_L_4action, B_int); }; struct linesQ_L_4action { struct linesQ_L_4actionG_class *$class; linesQ_Apa L_3obj; }; $R linesQ_U_L_5C_3cont ($action, $Cont, int64_t); $R linesQ_L_5C_3cont ($action, $Cont, B_int); struct linesQ_L_6ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_6Cont, $action, $Cont); void (*__serialize__) (linesQ_L_6Cont, $Serial$state); linesQ_L_6Cont (*__deserialize__) (linesQ_L_6Cont, $Serial$state); B_bool (*__bool__) (linesQ_L_6Cont); B_str (*__str__) (linesQ_L_6Cont); B_str (*__repr__) (linesQ_L_6Cont); $R (*__call__) (linesQ_L_6Cont, B_int); }; struct linesQ_L_6Cont { struct linesQ_L_6ContG_class *$class; $action cb; $Cont C_cont; }; struct linesQ_L_7procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_7proc, linesQ_Apa, $action); void (*__serialize__) (linesQ_L_7proc, $Serial$state); linesQ_L_7proc (*__deserialize__) (linesQ_L_7proc, $Serial$state); B_bool (*__bool__) (linesQ_L_7proc); B_str (*__str__) (linesQ_L_7proc); B_str (*__repr__) (linesQ_L_7proc); $R (*__call__) (linesQ_L_7proc, $Cont); $R (*__exec__) (linesQ_L_7proc, $Cont); }; struct linesQ_L_7proc { struct linesQ_L_7procG_class *$class; linesQ_Apa self; $action cb; }; struct linesQ_L_8procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_8proc, linesQ_Apa, $action); void (*__serialize__) (linesQ_L_8proc, $Serial$state); linesQ_L_8proc (*__deserialize__) (linesQ_L_8proc, $Serial$state); B_bool (*__bool__) (linesQ_L_8proc); B_str (*__str__) (linesQ_L_8proc); B_str (*__repr__) (linesQ_L_8proc); $R (*__call__) (linesQ_L_8proc, $Cont); $R (*__exec__) (linesQ_L_8proc, $Cont); }; struct linesQ_L_8proc { struct linesQ_L_8procG_class *$class; linesQ_Apa self; $action cb; }; struct linesQ_L_9procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_9proc, linesQ_Apa, B_int); void (*__serialize__) (linesQ_L_9proc, $Serial$state); linesQ_L_9proc (*__deserialize__) (linesQ_L_9proc, $Serial$state); B_bool (*__bool__) (linesQ_L_9proc); B_str (*__str__) (linesQ_L_9proc); B_str (*__repr__) (linesQ_L_9proc); $R (*__call__) (linesQ_L_9proc, $Cont); $R (*__exec__) (linesQ_L_9proc, $Cont); }; struct linesQ_L_9proc { struct linesQ_L_9procG_class *$class; linesQ_Apa self; B_int i; }; struct linesQ_L_10procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_10proc, linesQ_Bepa, B_int); void (*__serialize__) (linesQ_L_10proc, $Serial$state); linesQ_L_10proc (*__deserialize__) (linesQ_L_10proc, $Serial$state); B_bool (*__bool__) (linesQ_L_10proc); B_str (*__str__) (linesQ_L_10proc); B_str (*__repr__) (linesQ_L_10proc); $R (*__call__) (linesQ_L_10proc, $Cont); $R (*__exec__) (linesQ_L_10proc, $Cont); }; struct linesQ_L_10proc { struct linesQ_L_10procG_class *$class; linesQ_Bepa self; B_int i; }; struct linesQ_L_14actionG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_14action, linesQ_Apa); void (*__serialize__) (linesQ_L_14action, $Serial$state); linesQ_L_14action (*__deserialize__) (linesQ_L_14action, $Serial$state); B_bool (*__bool__) (linesQ_L_14action); B_str (*__str__) (linesQ_L_14action); B_str (*__repr__) (linesQ_L_14action); $R (*__call__) (linesQ_L_14action, $Cont, B_int); $R (*__exec__) (linesQ_L_14action, $Cont, B_int); B_Msg (*__asyn__) (linesQ_L_14action, B_int); }; struct linesQ_L_14action { struct linesQ_L_14actionG_class *$class; linesQ_Apa L_13obj; }; struct linesQ_L_16actionG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_16action, linesQ_Bepa); void (*__serialize__) (linesQ_L_16action, $Serial$state); linesQ_L_16action (*__deserialize__) (linesQ_L_16action, $Serial$state); B_bool (*__bool__) (linesQ_L_16action); B_str (*__str__) (linesQ_L_16action); B_str (*__repr__) (linesQ_L_16action); $R (*__call__) (linesQ_L_16action, $Cont, B_int); $R (*__exec__) (linesQ_L_16action, $Cont, B_int); B_Msg (*__asyn__) (linesQ_L_16action, B_int); }; struct linesQ_L_16action { struct linesQ_L_16actionG_class *$class; linesQ_Bepa L_15obj; }; struct linesQ_L_19actionG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_19action, linesQ_main); void (*__serialize__) (linesQ_L_19action, $Serial$state); linesQ_L_19action (*__deserialize__) (linesQ_L_19action, $Serial$state); B_bool (*__bool__) (linesQ_L_19action); B_str (*__str__) (linesQ_L_19action); B_str (*__repr__) (linesQ_L_19action); $R (*__call__) (linesQ_L_19action, $Cont, B_int); $R (*__exec__) (linesQ_L_19action, $Cont, B_int); B_Msg (*__asyn__) (linesQ_L_19action, B_int); }; struct linesQ_L_19action { struct linesQ_L_19actionG_class *$class; linesQ_main L_18obj; }; struct linesQ_L_20procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_20proc, linesQ_main); void (*__serialize__) (linesQ_L_20proc, $Serial$state); linesQ_L_20proc (*__deserialize__) (linesQ_L_20proc, $Serial$state); B_bool (*__bool__) (linesQ_L_20proc); B_str (*__str__) (linesQ_L_20proc); B_str (*__repr__) (linesQ_L_20proc); $R (*__call__) (linesQ_L_20proc, $Cont); $R (*__exec__) (linesQ_L_20proc, $Cont); }; struct linesQ_L_20proc { struct linesQ_L_20procG_class *$class; linesQ_main self; }; $R linesQ_U_1L_17C_9cont (linesQ_main, $Cont, int64_t); $R linesQ_L_17C_9cont (linesQ_main, $Cont, B_int); struct linesQ_L_21ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_21Cont, linesQ_main, $Cont); void (*__serialize__) (linesQ_L_21Cont, $Serial$state); linesQ_L_21Cont (*__deserialize__) (linesQ_L_21Cont, $Serial$state); B_bool (*__bool__) (linesQ_L_21Cont); B_str (*__str__) (linesQ_L_21Cont); B_str (*__repr__) (linesQ_L_21Cont); $R (*__call__) (linesQ_L_21Cont, B_int); }; struct linesQ_L_21Cont { struct linesQ_L_21ContG_class *$class; linesQ_main self; $Cont C_cont; }; $R linesQ_L_12C_7cont (linesQ_main, $Cont, linesQ_Bepa); struct linesQ_L_22ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_22Cont, linesQ_main, $Cont); void (*__serialize__) (linesQ_L_22Cont, $Serial$state); linesQ_L_22Cont (*__deserialize__) (linesQ_L_22Cont, $Serial$state); B_bool (*__bool__) (linesQ_L_22Cont); B_str (*__str__) (linesQ_L_22Cont); B_str (*__repr__) (linesQ_L_22Cont); $R (*__call__) (linesQ_L_22Cont, linesQ_Bepa); }; struct linesQ_L_22Cont { struct linesQ_L_22ContG_class *$class; linesQ_main self; $Cont C_cont; }; $R linesQ_L_11C_5cont (linesQ_main, $Cont, linesQ_Apa); struct linesQ_L_23ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_23Cont, linesQ_main, $Cont); void (*__serialize__) (linesQ_L_23Cont, $Serial$state); linesQ_L_23Cont (*__deserialize__) (linesQ_L_23Cont, $Serial$state); B_bool (*__bool__) (linesQ_L_23Cont); B_str (*__str__) (linesQ_L_23Cont); B_str (*__repr__) (linesQ_L_23Cont); $R (*__call__) (linesQ_L_23Cont, linesQ_Apa); }; struct linesQ_L_23Cont { struct linesQ_L_23ContG_class *$class; linesQ_main self; $Cont C_cont; }; struct linesQ_L_24procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_24proc, linesQ_main, B_int); void (*__serialize__) (linesQ_L_24proc, $Serial$state); linesQ_L_24proc (*__deserialize__) (linesQ_L_24proc, $Serial$state); B_bool (*__bool__) (linesQ_L_24proc); B_str (*__str__) (linesQ_L_24proc); B_str (*__repr__) (linesQ_L_24proc); $R (*__call__) (linesQ_L_24proc, $Cont); $R (*__exec__) (linesQ_L_24proc, $Cont); }; struct linesQ_L_24proc { struct linesQ_L_24procG_class *$class; linesQ_main self; B_int i; }; struct linesQ_L_25procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_25proc, linesQ_main); void (*__serialize__) (linesQ_L_25proc, $Serial$state); linesQ_L_25proc (*__deserialize__) (linesQ_L_25proc, $Serial$state); B_bool (*__bool__) (linesQ_L_25proc); B_str (*__str__) (linesQ_L_25proc); B_str (*__repr__) (linesQ_L_25proc); $R (*__call__) (linesQ_L_25proc, $Cont); $R (*__exec__) (linesQ_L_25proc, $Cont); }; struct linesQ_L_25proc { struct linesQ_L_25procG_class *$class; linesQ_main self; }; $R linesQ_L_26C_11cont ($Cont, linesQ_Apa, B_NoneType); struct linesQ_L_27ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_27Cont, $Cont, linesQ_Apa); void (*__serialize__) (linesQ_L_27Cont, $Serial$state); linesQ_L_27Cont (*__deserialize__) (linesQ_L_27Cont, $Serial$state); B_bool (*__bool__) (linesQ_L_27Cont); B_str (*__str__) (linesQ_L_27Cont); B_str (*__repr__) (linesQ_L_27Cont); $R (*__call__) (linesQ_L_27Cont, B_NoneType); }; struct linesQ_L_27Cont { struct linesQ_L_27ContG_class *$class; $Cont C_cont; linesQ_Apa G_act; }; struct linesQ_L_28procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_28proc, linesQ_Apa); void (*__serialize__) (linesQ_L_28proc, $Serial$state); linesQ_L_28proc (*__deserialize__) (linesQ_L_28proc, $Serial$state); B_bool (*__bool__) (linesQ_L_28proc); B_str (*__str__) (linesQ_L_28proc); B_str (*__repr__) (linesQ_L_28proc); $R (*__call__) (linesQ_L_28proc, $Cont); $R (*__exec__) (linesQ_L_28proc, $Cont); }; struct linesQ_L_28proc { struct linesQ_L_28procG_class *$class; linesQ_Apa G_act; }; $R linesQ_L_29C_13cont ($Cont, linesQ_Bepa, B_NoneType); struct linesQ_L_30ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_30Cont, $Cont, linesQ_Bepa); void (*__serialize__) (linesQ_L_30Cont, $Serial$state); linesQ_L_30Cont (*__deserialize__) (linesQ_L_30Cont, $Serial$state); B_bool (*__bool__) (linesQ_L_30Cont); B_str (*__str__) (linesQ_L_30Cont); B_str (*__repr__) (linesQ_L_30Cont); $R (*__call__) (linesQ_L_30Cont, B_NoneType); }; struct linesQ_L_30Cont { struct linesQ_L_30ContG_class *$class; $Cont C_cont; linesQ_Bepa G_act; }; struct linesQ_L_31procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_31proc, linesQ_Bepa); void (*__serialize__) (linesQ_L_31proc, $Serial$state); linesQ_L_31proc (*__deserialize__) (linesQ_L_31proc, $Serial$state); B_bool (*__bool__) (linesQ_L_31proc); B_str (*__str__) (linesQ_L_31proc); B_str (*__repr__) (linesQ_L_31proc); $R (*__call__) (linesQ_L_31proc, $Cont); $R (*__exec__) (linesQ_L_31proc, $Cont); }; struct linesQ_L_31proc { struct linesQ_L_31procG_class *$class; linesQ_Bepa G_act; }; $R linesQ_L_32C_15cont ($Cont, linesQ_main, B_NoneType); struct linesQ_L_33ContG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_33Cont, $Cont, linesQ_main); void (*__serialize__) (linesQ_L_33Cont, $Serial$state); linesQ_L_33Cont (*__deserialize__) (linesQ_L_33Cont, $Serial$state); B_bool (*__bool__) (linesQ_L_33Cont); B_str (*__str__) (linesQ_L_33Cont); B_str (*__repr__) (linesQ_L_33Cont); $R (*__call__) (linesQ_L_33Cont, B_NoneType); }; struct linesQ_L_33Cont { struct linesQ_L_33ContG_class *$class; $Cont C_cont; linesQ_main G_act; }; struct linesQ_L_34procG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; B_NoneType (*__init__) (linesQ_L_34proc, linesQ_main, B_Env); void (*__serialize__) (linesQ_L_34proc, $Serial$state); linesQ_L_34proc (*__deserialize__) (linesQ_L_34proc, $Serial$state); B_bool (*__bool__) (linesQ_L_34proc); B_str (*__str__) (linesQ_L_34proc); B_str (*__repr__) (linesQ_L_34proc); $R (*__call__) (linesQ_L_34proc, $Cont); $R (*__exec__) (linesQ_L_34proc, $Cont); }; struct linesQ_L_34proc { struct linesQ_L_34procG_class *$class; linesQ_main G_act; B_Env env; }; struct linesQ_ApaG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; $R (*__init__) (linesQ_Apa, $Cont); void (*__serialize__) (linesQ_Apa, $Serial$state); linesQ_Apa (*__deserialize__) (linesQ_Apa, $Serial$state); B_bool (*__bool__) (linesQ_Apa); B_str (*__str__) (linesQ_Apa); B_str (*__repr__) (linesQ_Apa); B_NoneType (*__resume__) (linesQ_Apa); B_NoneType (*__cleanup__) (linesQ_Apa); $R (*setupG_local) (linesQ_Apa, $Cont, $action); $R (*computeG_local) (linesQ_Apa, $Cont, $action); $R (*noticeG_local) (linesQ_Apa, $Cont, B_int); B_Msg (*setup) (linesQ_Apa, $action); B_Msg (*compute) (linesQ_Apa, $action); B_Msg (*notice) (linesQ_Apa, B_int); }; struct linesQ_Apa { struct linesQ_ApaG_class *$class; $Actor $next; B_Msg $msg; B_Msg $msg_tail; $Lock $msg_lock; $int64 $affinity; B_Msg $outgoing; B_Msg $waitsfor; $int64 $consume_hd; $Catcher $catcher; $long $globkey; B_int apa; B_int apb; B_int y; B_int z; }; struct linesQ_BepaG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; $R (*__init__) (linesQ_Bepa, $Cont); void (*__serialize__) (linesQ_Bepa, $Serial$state); linesQ_Bepa (*__deserialize__) (linesQ_Bepa, $Serial$state); B_bool (*__bool__) (linesQ_Bepa); B_str (*__str__) (linesQ_Bepa); B_str (*__repr__) (linesQ_Bepa); B_NoneType (*__resume__) (linesQ_Bepa); B_NoneType (*__cleanup__) (linesQ_Bepa); $R (*callbackG_local) (linesQ_Bepa, $Cont, B_int); B_Msg (*callback) (linesQ_Bepa, B_int); }; struct linesQ_Bepa { struct linesQ_BepaG_class *$class; $Actor $next; B_Msg $msg; B_Msg $msg_tail; $Lock $msg_lock; $int64 $affinity; B_Msg $outgoing; B_Msg $waitsfor; $int64 $consume_hd; $Catcher $catcher; $long $globkey; }; struct linesQ_mainG_class { char *$GCINFO; int $class_id; $SuperG_class $superclass; $R (*__init__) (linesQ_main, $Cont, B_Env); void (*__serialize__) (linesQ_main, $Serial$state); linesQ_main (*__deserialize__) (linesQ_main, $Serial$state); B_bool (*__bool__) (linesQ_main); B_str (*__str__) (linesQ_main); B_str (*__repr__) (linesQ_main); B_NoneType (*__resume__) (linesQ_main); B_NoneType (*__cleanup__) (linesQ_main); $R (*myprocG_local) (linesQ_main, $Cont, B_int); $R (*nopG_local) (linesQ_main, $Cont); B_Msg (*myproc) (linesQ_main, B_int); B_Msg (*nop) (linesQ_main); }; struct linesQ_main { struct linesQ_mainG_class *$class; $Actor $next; B_Msg $msg; B_Msg $msg_tail; $Lock $msg_lock; $int64 $affinity; B_Msg $outgoing; B_Msg $waitsfor; $int64 $consume_hd; $Catcher $catcher; $long $globkey; B_Env env; linesQ_Apa a; linesQ_Bepa b; B_Msg x; B_int r; B_int v; B_int i; }; $R linesQ_ApaG_newact ($Cont); $R linesQ_BepaG_newact ($Cont); $R linesQ_mainG_newact ($Cont, B_Env); extern struct linesQ_L_2ContG_class linesQ_L_2ContG_methods; linesQ_L_2Cont linesQ_L_2ContG_new(linesQ_Apa, $Cont); extern struct linesQ_L_4actionG_class linesQ_L_4actionG_methods; linesQ_L_4action linesQ_L_4actionG_new(linesQ_Apa); extern struct linesQ_L_6ContG_class linesQ_L_6ContG_methods; linesQ_L_6Cont linesQ_L_6ContG_new($action, $Cont); extern struct linesQ_L_7procG_class linesQ_L_7procG_methods; linesQ_L_7proc linesQ_L_7procG_new(linesQ_Apa, $action); extern struct linesQ_L_8procG_class linesQ_L_8procG_methods; linesQ_L_8proc linesQ_L_8procG_new(linesQ_Apa, $action); extern struct linesQ_L_9procG_class linesQ_L_9procG_methods; linesQ_L_9proc linesQ_L_9procG_new(linesQ_Apa, B_int); extern struct linesQ_L_10procG_class linesQ_L_10procG_methods; linesQ_L_10proc linesQ_L_10procG_new(linesQ_Bepa, B_int); extern struct linesQ_L_14actionG_class linesQ_L_14actionG_methods; linesQ_L_14action linesQ_L_14actionG_new(linesQ_Apa); extern struct linesQ_L_16actionG_class linesQ_L_16actionG_methods; linesQ_L_16action linesQ_L_16actionG_new(linesQ_Bepa); extern struct linesQ_L_19actionG_class linesQ_L_19actionG_methods; linesQ_L_19action linesQ_L_19actionG_new(linesQ_main); extern struct linesQ_L_20procG_class linesQ_L_20procG_methods; linesQ_L_20proc linesQ_L_20procG_new(linesQ_main); extern struct linesQ_L_21ContG_class linesQ_L_21ContG_methods; linesQ_L_21Cont linesQ_L_21ContG_new(linesQ_main, $Cont); extern struct linesQ_L_22ContG_class linesQ_L_22ContG_methods; linesQ_L_22Cont linesQ_L_22ContG_new(linesQ_main, $Cont); extern struct linesQ_L_23ContG_class linesQ_L_23ContG_methods; linesQ_L_23Cont linesQ_L_23ContG_new(linesQ_main, $Cont); extern struct linesQ_L_24procG_class linesQ_L_24procG_methods; linesQ_L_24proc linesQ_L_24procG_new(linesQ_main, B_int); extern struct linesQ_L_25procG_class linesQ_L_25procG_methods; linesQ_L_25proc linesQ_L_25procG_new(linesQ_main); extern struct linesQ_L_27ContG_class linesQ_L_27ContG_methods; linesQ_L_27Cont linesQ_L_27ContG_new($Cont, linesQ_Apa); extern struct linesQ_L_28procG_class linesQ_L_28procG_methods; linesQ_L_28proc linesQ_L_28procG_new(linesQ_Apa); extern struct linesQ_L_30ContG_class linesQ_L_30ContG_methods; linesQ_L_30Cont linesQ_L_30ContG_new($Cont, linesQ_Bepa); extern struct linesQ_L_31procG_class linesQ_L_31procG_methods; linesQ_L_31proc linesQ_L_31procG_new(linesQ_Bepa); extern struct linesQ_L_33ContG_class linesQ_L_33ContG_methods; linesQ_L_33Cont linesQ_L_33ContG_new($Cont, linesQ_main); extern struct linesQ_L_34procG_class linesQ_L_34procG_methods; linesQ_L_34proc linesQ_L_34procG_new(linesQ_main, B_Env); extern struct linesQ_ApaG_class linesQ_ApaG_methods; $R linesQ_ApaG_new($Cont); extern struct linesQ_BepaG_class linesQ_BepaG_methods; $R linesQ_BepaG_new($Cont); extern struct linesQ_mainG_class linesQ_mainG_methods; $R linesQ_mainG_new($Cont, B_Env); extern B_Eq linesQ_W_Apa_1097; extern B_Eq linesQ_W_Apa_759; extern B_Iterable linesQ_W_Apa_779; extern B_Eq linesQ_W_Apa_331; extern B_Eq linesQ_W_Apa_785; void linesQ___init__ (); ================================================ FILE: compiler/lib/test/9-codegen/lines.input ================================================ W_Apa_1097: __builtin__.Eq[__builtin__.int] = __builtin__.OrdD_int() W_Apa_759: __builtin__.Eq[?__builtin__.int] = $EqOpt@[__builtin__.int](W_Apa_1097) W_Apa_779: __builtin__.Iterable[__builtin__.list[?__builtin__.int], ?__builtin__.int] = __builtin__.SequenceD_list@[?__builtin__.int]().W_Collection W_Apa_331: __builtin__.Eq[?__builtin__.int] = $EqOpt@[__builtin__.int](W_Apa_1097) W_Apa_785: __builtin__.Eq[?__builtin__.int] = $EqOpt@[__builtin__.int](W_Apa_1097) # recursive group: proc def L_1C_1cont (self : Apa, C_cont : $Cont[None], C_2res : None) -> $R: self.z = (BOX __builtin__.int (UNBOX __builtin__.int 1)) print@[(__builtin__.str,)](("\"Apa\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) class L_2Cont ($Cont[None], __builtin__.value): @property self : Apa @property C_cont : $Cont[None] pure def __init__ (L_self : L_2Cont, self : Apa, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : L_2Cont, G_1 : None) -> $R: self: Apa = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_1C_1cont(self, C_cont, G_1) class L_4action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_3obj : Apa pure def __init__ (L_self : L_4action, L_3obj : Apa) -> None: L_self.L_3obj = L_3obj return None # recursive group: proc def __call__ (L_self : L_4action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_4action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_4action, G_1 : __builtin__.int) -> __builtin__.int: L_3obj: Apa = L_self.L_3obj return L_3obj.notice(G_1) # (recursive group) proc def U_L_5C_3cont (cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int], U_2C_4res : __builtin__.int) -> $R: U_3v: __builtin__.int = U_2C_4res m: __builtin__.Msg[__builtin__.int] = cb.__asyn__((BOX __builtin__.int (UNBOX __builtin__.int 2))) U_4N_tmp: __builtin__.int = (U_3v * (UNBOX __builtin__.int 10)) return $R_CONT@[__builtin__.int](C_cont, (BOX __builtin__.int U_4N_tmp)) proc def L_5C_3cont (cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int], C_4res : __builtin__.int) -> $R: return U_L_5C_3cont(cb, C_cont, (UNBOX __builtin__.int C_4res)) class L_6Cont ($Cont[__builtin__.int], __builtin__.value): @property cb : $action[(__builtin__.int,), __builtin__.int] @property C_cont : $Cont[__builtin__.int] pure def __init__ (L_self : L_6Cont, cb : $action[(__builtin__.int,), __builtin__.int], C_cont : $Cont[__builtin__.int]) -> None: L_self.cb = cb L_self.C_cont = C_cont return None proc def __call__ (L_self : L_6Cont, G_1 : __builtin__.int) -> $R: cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb C_cont: $Cont[__builtin__.int] = L_self.C_cont return L_5C_3cont(cb, C_cont, G_1) class L_7proc ($proc[(), None], __builtin__.value): @property self : Apa @property cb : $action[(__builtin__.int,), __builtin__.int] pure def __init__ (L_self : L_7proc, self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: L_self.self = self L_self.cb = cb return None # recursive group: proc def __call__ (L_self : L_7proc, C_cont : $Cont[None]) -> $R: self: Apa = L_self.self cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb return self.setupG_local(C_cont, cb) proc def __exec__ (L_self : L_7proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_8proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Apa @property cb : $action[(__builtin__.int,), __builtin__.int] pure def __init__ (L_self : L_8proc, self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: L_self.self = self L_self.cb = cb return None # recursive group: proc def __call__ (L_self : L_8proc, C_cont : $Cont[__builtin__.int]) -> $R: self: Apa = L_self.self cb: $action[(__builtin__.int,), __builtin__.int] = L_self.cb return self.computeG_local(C_cont, cb) proc def __exec__ (L_self : L_8proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_9proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Apa @property i : __builtin__.int pure def __init__ (L_self : L_9proc, self : Apa, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : L_9proc, C_cont : $Cont[__builtin__.int]) -> $R: self: Apa = L_self.self U_5i: __builtin__.int = (UNBOX __builtin__.int L_self.i) return self.noticeG_local(C_cont, (BOX __builtin__.int U_5i)) proc def __exec__ (L_self : L_9proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_10proc ($proc[(), __builtin__.int], __builtin__.value): @property self : Bepa @property i : __builtin__.int pure def __init__ (L_self : L_10proc, self : Bepa, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : L_10proc, C_cont : $Cont[__builtin__.int]) -> $R: self: Bepa = L_self.self U_6i: __builtin__.int = (UNBOX __builtin__.int L_self.i) return self.callbackG_local(C_cont, (BOX __builtin__.int U_6i)) proc def __exec__ (L_self : L_10proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_14action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_13obj : Apa pure def __init__ (L_self : L_14action, L_13obj : Apa) -> None: L_self.L_13obj = L_13obj return None # recursive group: proc def __call__ (L_self : L_14action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_14action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_14action, G_1 : __builtin__.int) -> __builtin__.int: L_13obj: Apa = L_self.L_13obj return L_13obj.notice(G_1) # (recursive group) class L_16action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_15obj : Bepa pure def __init__ (L_self : L_16action, L_15obj : Bepa) -> None: L_self.L_15obj = L_15obj return None # recursive group: proc def __call__ (L_self : L_16action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_16action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_16action, G_1 : __builtin__.int) -> __builtin__.int: L_15obj: Bepa = L_self.L_15obj return L_15obj.callback(G_1) # (recursive group) class L_19action ($action[(__builtin__.int,), __builtin__.int], $proc[(__builtin__.int,), __builtin__.int], __builtin__.value): @property L_18obj : main pure def __init__ (L_self : L_19action, L_18obj : main) -> None: L_self.L_18obj = L_18obj return None # recursive group: proc def __call__ (L_self : L_19action, L_cont : $Cont[__builtin__.int], G_1 : __builtin__.int) -> $R: return $AWAIT@[__builtin__.int](L_cont, L_self.__asyn__(G_1)) proc def __exec__ (L_self : L_19action, L_cont : $Cont[__builtin__.value], G_1 : __builtin__.int) -> $R: return $R_CONT@[__builtin__.value](L_cont, L_self.__asyn__(G_1)) action def __asyn__ (L_self : L_19action, G_1 : __builtin__.int) -> __builtin__.int: L_18obj: main = L_self.L_18obj return L_18obj.myproc(G_1) # (recursive group) class L_20proc ($proc[(), __builtin__.int], __builtin__.value): @property self : main pure def __init__ (L_self : L_20proc, self : main) -> None: L_self.self = self return None # recursive group: proc def __call__ (L_self : L_20proc, C_cont : $Cont[__builtin__.int]) -> $R: self: main = L_self.self return self.myprocG_local(C_cont, (BOX __builtin__.int (UNBOX __builtin__.int 0))) proc def __exec__ (L_self : L_20proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def U_1L_17C_9cont (self : main, C_cont : $Cont[None], U_7C_10res : __builtin__.int) -> $R: self.r = (BOX __builtin__.int U_7C_10res) print@[(__builtin__.str, __builtin__.int)](("\"r =\"", self.r), None, None, None, None) (async self.a.compute)(L_19action(self)) print@[(__builtin__.str,)](("\"main\"",), None, None, None, None) self.v = (BOX __builtin__.int (UNBOX __builtin__.int 0)) if (BOX __builtin__.bool ((UNBOX __builtin__.int self.v) == (UNBOX __builtin__.int 0))): print@[(__builtin__.str,)](("\"if branch\"",), None, None, None, None) if (BOX __builtin__.bool ((UNBOX __builtin__.int self.v) < (UNBOX __builtin__.int 1))): print@[(__builtin__.str,)](("\"nested if\"",), None, None, None, None) elif (BOX __builtin__.bool ((UNBOX __builtin__.int self.v) == (UNBOX __builtin__.int -1))): print@[(__builtin__.str,)](("\"nested elif\"",), None, None, None, None) else: print@[(__builtin__.str,)](("\"nested else\"",), None, None, None, None) elif (BOX __builtin__.bool ((UNBOX __builtin__.int self.v) == (UNBOX __builtin__.int 1))): print@[(__builtin__.str,)](("\"outer elif\"",), None, None, None, None) else: print@[(__builtin__.str,)](("\"outer else\"",), None, None, None, None) self.i = (BOX __builtin__.int (UNBOX __builtin__.int 0)) while True: if (BOX __builtin__.bool ((UNBOX __builtin__.int self.i) < (UNBOX __builtin__.int 3))): pass else: print@[(__builtin__.str,)](("\"while else\"",), None, None, None, None) break self.i = (BOX __builtin__.int ((UNBOX __builtin__.int self.i) + (UNBOX __builtin__.int 1))) if (BOX __builtin__.bool ((UNBOX __builtin__.int self.i) == (UNBOX __builtin__.int 1))): print@[(__builtin__.str,)](("\"continue path\"",), None, None, None, None) continue if (BOX __builtin__.bool ((UNBOX __builtin__.int self.i) == (UNBOX __builtin__.int 2))): print@[(__builtin__.str,)](("\"break path\"",), None, None, None, None) break print@[(__builtin__.str, __builtin__.int)](("\"loop body\"", self.i), None, None, None, None) N_3iter: __builtin__.Iterator[?__builtin__.int] = W_Apa_779.__iter__([(BOX __builtin__.int (UNBOX __builtin__.int 1)), (BOX __builtin__.int (UNBOX __builtin__.int 2)), (BOX __builtin__.int (UNBOX __builtin__.int 3))]) if $PUSH(): while True: if True: pass else: break j: ?__builtin__.int = N_3iter.__next__() if W_Apa_759.__eq__(j, (BOX __builtin__.int (UNBOX __builtin__.int 2))): continue print@[(__builtin__.str, ?__builtin__.int)](("\"for j\"", j), None, None, None, None) $DROP() else: N_5x: __builtin__.BaseException = $POP() if isinstance(N_5x, __builtin__.StopIteration): pass else: $RAISE(N_5x) if $PUSHF(): if $PUSH(): if W_Apa_785.__eq__(self.v, (BOX __builtin__.int (UNBOX __builtin__.int 0))): $RAISE(ValueError("\"boom\"")) print@[(__builtin__.str,)](("\"unreached\"",), None, None, None, None) $DROP() else: N_6x: __builtin__.BaseException = $POP() if isinstance(N_6x, ValueError): e: ValueError = N_6x print@[(__builtin__.str, __builtin__.str)](("\"caught\"", "\"ValueError\""), None, None, None, None) else: $RAISE(N_6x) $RAISE($SEQ()) else: N_7xx: __builtin__.BaseException = $POP() print@[(__builtin__.str,)](("\"finally\"",), None, None, None, None) if isinstance(N_7xx, $SEQ): pass else: $RAISE(N_7xx) $AFTER@[__builtin__.int]((BOX __builtin__.float (UNBOX __builtin__.float 1)), L_20proc(self)) return self.nopG_local(C_cont) proc def L_17C_9cont (self : main, C_cont : $Cont[None], C_10res : __builtin__.int) -> $R: return U_1L_17C_9cont(self, C_cont, (UNBOX __builtin__.int C_10res)) class L_21Cont ($Cont[__builtin__.int], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : L_21Cont, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : L_21Cont, G_1 : __builtin__.int) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_17C_9cont(self, C_cont, G_1) proc def L_12C_7cont (self : main, C_cont : $Cont[None], C_8res : Bepa) -> $R: self.b = C_8res print@[(__builtin__.str,)](("\"-----\"",), None, None, None, None) (async self.a.setup)(L_14action(self.a)) self.x = (async self.a.compute)(L_16action(self.b)) return $AWAIT@[__builtin__.int](L_21Cont(self, C_cont), self.x) class L_22Cont ($Cont[Bepa], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : L_22Cont, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : L_22Cont, G_1 : Bepa) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_12C_7cont(self, C_cont, G_1) proc def L_11C_5cont (self : main, C_cont : $Cont[None], C_6res : Apa) -> $R: self.a = C_6res return BepaG_newact(L_22Cont(self, C_cont)) class L_23Cont ($Cont[Apa], __builtin__.value): @property self : main @property C_cont : $Cont[None] pure def __init__ (L_self : L_23Cont, self : main, C_cont : $Cont[None]) -> None: L_self.self = self L_self.C_cont = C_cont return None proc def __call__ (L_self : L_23Cont, G_1 : Apa) -> $R: self: main = L_self.self C_cont: $Cont[None] = L_self.C_cont return L_11C_5cont(self, C_cont, G_1) class L_24proc ($proc[(), __builtin__.int], __builtin__.value): @property self : main @property i : __builtin__.int pure def __init__ (L_self : L_24proc, self : main, i : __builtin__.int) -> None: L_self.self = self L_self.i = i return None # recursive group: proc def __call__ (L_self : L_24proc, C_cont : $Cont[__builtin__.int]) -> $R: self: main = L_self.self U_8i: __builtin__.int = (UNBOX __builtin__.int L_self.i) return self.myprocG_local(C_cont, (BOX __builtin__.int U_8i)) proc def __exec__ (L_self : L_24proc, C_cont : $Cont[__builtin__.int]) -> $R: return L_self.__call__(C_cont) # (recursive group) class L_25proc ($proc[(), None], __builtin__.value): @property self : main pure def __init__ (L_self : L_25proc, self : main) -> None: L_self.self = self return None # recursive group: proc def __call__ (L_self : L_25proc, C_cont : $Cont[None]) -> $R: self: main = L_self.self return self.nopG_local(C_cont) proc def __exec__ (L_self : L_25proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_26C_11cont (C_cont : $Cont[Apa], G_act : Apa, C_12res : None) -> $R: return $R_CONT@[Apa](C_cont, G_act) class L_27Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[Apa] @property G_act : Apa pure def __init__ (L_self : L_27Cont, C_cont : $Cont[Apa], G_act : Apa) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : L_27Cont, G_1 : None) -> $R: C_cont: $Cont[Apa] = L_self.C_cont G_act: Apa = L_self.G_act return L_26C_11cont(C_cont, G_act, G_1) class L_28proc ($proc[(), None], __builtin__.value): @property G_act : Apa pure def __init__ (L_self : L_28proc, G_act : Apa) -> None: L_self.G_act = G_act return None # recursive group: proc def __call__ (L_self : L_28proc, C_cont : $Cont[None]) -> $R: G_act: Apa = L_self.G_act return G_act.__init__(C_cont) proc def __exec__ (L_self : L_28proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_29C_13cont (C_cont : $Cont[Bepa], G_act : Bepa, C_14res : None) -> $R: return $R_CONT@[Bepa](C_cont, G_act) class L_30Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[Bepa] @property G_act : Bepa pure def __init__ (L_self : L_30Cont, C_cont : $Cont[Bepa], G_act : Bepa) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : L_30Cont, G_1 : None) -> $R: C_cont: $Cont[Bepa] = L_self.C_cont G_act: Bepa = L_self.G_act return L_29C_13cont(C_cont, G_act, G_1) class L_31proc ($proc[(), None], __builtin__.value): @property G_act : Bepa pure def __init__ (L_self : L_31proc, G_act : Bepa) -> None: L_self.G_act = G_act return None # recursive group: proc def __call__ (L_self : L_31proc, C_cont : $Cont[None]) -> $R: G_act: Bepa = L_self.G_act return G_act.__init__(C_cont) proc def __exec__ (L_self : L_31proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) proc def L_32C_15cont (C_cont : $Cont[main], G_act : main, C_16res : None) -> $R: return $R_CONT@[main](C_cont, G_act) class L_33Cont ($Cont[None], __builtin__.value): @property C_cont : $Cont[main] @property G_act : main pure def __init__ (L_self : L_33Cont, C_cont : $Cont[main], G_act : main) -> None: L_self.C_cont = C_cont L_self.G_act = G_act return None proc def __call__ (L_self : L_33Cont, G_1 : None) -> $R: C_cont: $Cont[main] = L_self.C_cont G_act: main = L_self.G_act return L_32C_15cont(C_cont, G_act, G_1) class L_34proc ($proc[(), None], __builtin__.value): @property G_act : main @property env : __builtin__.Env pure def __init__ (L_self : L_34proc, G_act : main, env : __builtin__.Env) -> None: L_self.G_act = G_act L_self.env = env return None # recursive group: proc def __call__ (L_self : L_34proc, C_cont : $Cont[None]) -> $R: G_act: main = L_self.G_act env: __builtin__.Env = L_self.env return G_act.__init__(C_cont, env) proc def __exec__ (L_self : L_34proc, C_cont : $Cont[None]) -> $R: return L_self.__call__(C_cont) # (recursive group) class Apa ($Actor, __builtin__.value): @property apa : __builtin__.int @property apb : __builtin__.int @property y : __builtin__.int @property z : __builtin__.int proc def __init__ (self : Apa, C_cont : $Cont[None]) -> $R: self.apa = (BOX __builtin__.int (UNBOX __builtin__.int 2001)) self.apb = (BOX __builtin__.int (UNBOX __builtin__.int 2002)) self.y = (BOX __builtin__.int (UNBOX __builtin__.int 123)) return self.setupG_local(L_2Cont(self, C_cont), L_4action(self)) proc def setupG_local (self : Apa, C_cont : $Cont[None], cb : $action[(__builtin__.int,), __builtin__.int]) -> $R: print@[(__builtin__.str,)](("\"setup\"",), None, None, None, None) cb.__asyn__((BOX __builtin__.int (UNBOX __builtin__.int 0))) return $R_CONT@[None](C_cont, None) proc def computeG_local (self : Apa, C_cont : $Cont[__builtin__.int], cb : $action[(__builtin__.int,), __builtin__.int]) -> $R: print@[(__builtin__.str,)](("\"compute\"",), None, None, None, None) return $AWAIT@[__builtin__.int](L_6Cont(cb, C_cont), cb.__asyn__((BOX __builtin__.int (UNBOX __builtin__.int 1)))) proc def noticeG_local (self : Apa, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str,)](("\"notice\"",), None, None, None, None) U_9N_1tmp: __builtin__.int = ((UNBOX __builtin__.int i) + (UNBOX __builtin__.int 1)) return $R_CONT@[__builtin__.int](C_cont, (BOX __builtin__.int U_9N_1tmp)) action def setup (self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> None: return $ASYNC@[None](self, L_7proc(self, cb)) action def compute (self : Apa, cb : $action[(__builtin__.int,), __builtin__.int]) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_8proc(self, cb)) action def notice (self : Apa, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_9proc(self, i)) class Bepa ($Actor, __builtin__.value): proc def __init__ (self : Bepa, C_cont : $Cont[None]) -> $R: print@[(__builtin__.str,)](("\"Bepa\"",), None, None, None, None) return $R_CONT@[None](C_cont, None) proc def callbackG_local (self : Bepa, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"callback\"", i), None, None, None, None) U_10N_2tmp: __builtin__.int = ((UNBOX __builtin__.int i) + (UNBOX __builtin__.int 1)) return $R_CONT@[__builtin__.int](C_cont, (BOX __builtin__.int U_10N_2tmp)) action def callback (self : Bepa, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_10proc(self, i)) class main ($Actor, __builtin__.value): @property env : __builtin__.Env @property a : Apa @property b : Bepa @property x : __builtin__.Msg[__builtin__.int] @property r : __builtin__.int @property v : __builtin__.int @property i : __builtin__.int proc def __init__ (self : main, C_cont : $Cont[None], env : __builtin__.Env) -> $R: self.env = env return ApaG_newact(L_23Cont(self, C_cont)) proc def myprocG_local (self : main, C_cont : $Cont[__builtin__.int], i : __builtin__.int) -> $R: print@[(__builtin__.str, __builtin__.int)](("\"myproc\"", i), None, None, None, None) if W_Apa_331.__eq__(i, (BOX __builtin__.int (UNBOX __builtin__.int 2))): (async self.env.exit)((BOX __builtin__.int (UNBOX __builtin__.int 0))) return $R_CONT@[__builtin__.int](C_cont, i) proc def nopG_local (self : main, C_cont : $Cont[None]) -> $R: pass return $R_CONT@[None](C_cont, None) action def myproc (self : main, i : __builtin__.int) -> __builtin__.int: return $ASYNC@[__builtin__.int](self, L_24proc(self, i)) action def nop (self : main) -> None: return $ASYNC@[None](self, L_25proc(self)) proc def ApaG_newact (C_cont : $Cont[Apa]) -> $R: G_act: Apa = $NEWACTOR@[Apa]() $InstallFinalizer@[Apa](G_act) return $AWAIT@[None](L_27Cont(C_cont, G_act), $ASYNC@[None](G_act, L_28proc(G_act))) proc def BepaG_newact (C_cont : $Cont[Bepa]) -> $R: G_act: Bepa = $NEWACTOR@[Bepa]() $InstallFinalizer@[Bepa](G_act) return $AWAIT@[None](L_30Cont(C_cont, G_act), $ASYNC@[None](G_act, L_31proc(G_act))) proc def mainG_newact (C_cont : $Cont[main], env : __builtin__.Env) -> $R: G_act: main = $NEWACTOR@[main]() $InstallFinalizer@[main](G_act) return $AWAIT@[None](L_33Cont(C_cont, G_act), $ASYNC@[None](G_act, L_34proc(G_act, env))) # (recursive group) ================================================ FILE: compiler/lib/test/ActonSpec.hs ================================================ {-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-} module Main (main) where import Data.Char (toLower, isAlphaNum) import qualified Acton.Parser as P import qualified Acton.Syntax as S import qualified Acton.Builtin as Builtin import qualified Acton.NameInfo as I import qualified Acton.Printer as AP import qualified Acton.DocPrinter as DocP import qualified Acton.Env import Acton.Env (CompilationError(..)) import qualified Acton.Kinds import qualified Acton.Types import Acton.TypeEnv (TypeError(..),typeReport) import qualified Acton.Normalizer import qualified Acton.Deactorizer import qualified Acton.CPS import qualified Acton.LambdaLifter import qualified Acton.Boxing import qualified Acton.CodeGen import qualified Acton.Diagnostics as Diag import qualified Acton.Compile as Compile import qualified Acton.Fingerprint as Fingerprint import qualified Acton.Completion as Completion import qualified InterfaceFiles import Pretty (print, prettyText) import qualified Pretty import Test.Syd import Test.Syd.Def.Golden (goldenTextFile) import qualified Control.Monad.Trans.State.Strict as St import Text.Megaparsec (ParseErrorBundle, PosState(..), bundleErrors, bundlePosState, errorOffset, reachOffset, runParser, errorBundlePretty, ShowErrorComponent(..)) import Text.Megaparsec.Pos (sourceLine, unPos) import qualified Data.Text as T import Data.List (isInfixOf, isPrefixOf, nub, sort) import qualified Data.List.NonEmpty as NE import Data.IORef import Data.Bits (shiftL, (.|.)) import Error.Diagnose (printDiagnostic, prettyDiagnostic, WithUnicode(..), TabSize(..), defaultStyle, addReport, addFile) import Error.Diagnose.Report (Report(..)) import Prettyprinter (unAnnotate, layoutPretty, defaultLayoutOptions) import Prettyprinter.Render.Text (renderStrict) import System.FilePath ((), joinPath, takeFileName, takeBaseName, takeDirectory, splitDirectories, takeExtension) import System.Directory (createDirectoryIfMissing, getCurrentDirectory, setCurrentDirectory, listDirectory, doesDirectoryExist) import System.IO.Temp (withSystemTempDirectory) import Control.Monad (forM_, when, foldM) import qualified Control.Exception as E import Control.DeepSeq (rnf) import Utils (SrcLoc(..), loc, prstr) import qualified Acton.BuildSpec as BuildSpec import qualified Data.Binary as Binary import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Char8 as B8 import qualified Data.Aeson as Ae import qualified System.IO.Unsafe main :: IO () main = do let sysTypesPath = ".." ".." "dist" "base" "out" "types" env0 <- Acton.Env.initEnv sysTypesPath False sydTest $ do describe "Environment" $ do it "treats mismatched .ty headers for loaded modules as stale" $ do withSystemTempDirectory "acton-env" $ \dir -> do let directMod = S.modName ["direct"] directTy = dir "direct.ty" valueName = S.name "value" iface = [(valueName, I.NVar S.tWild)] directIface = I.NModule [] iface Nothing directModule = S.Module directMod [] Nothing [] env1 = Acton.Env.addMod directMod [] iface Nothing env0 InterfaceFiles.writeFile directTy B8.empty B8.empty B8.empty Nothing [] [] [] [] Nothing directIface directModule (_mods, nmod, tmod, sourceMeta, srcHash, pubHash, implHash, imps, nameHashes, roots, tests, mdoc) <- InterfaceFiles.readFile directTy BL.writeFile directTy $ Binary.encode ( (map (+ 1) S.version, sourceMeta, srcHash, pubHash, implHash) , imps, nameHashes, roots, tests, mdoc, nmod, tmod ) (_env2, te) <- Acton.Env.doImp [dir] env1 directMod map fst te `shouldBe` [valueName] describe "Pass 1: Parser" $ do it "reports rough parse progress by source offset" $ do progressRef <- newIORef [] _ <- P.parseModule (S.modName ["progress"]) "progress.act" "x = 1\n" (Just $ \completed total -> modifyIORef' progressRef (++ [(completed, total)])) progress <- readIORef progressRef let completed = map fst progress monotonic xs = and (zipWith (<=) xs (drop 1 xs)) progress `shouldSatisfy` (not . null) completed `shouldSatisfy` monotonic last progress `shouldBe` (6, 6) describe "Basic Syntax" $ do testParse env0 ["syntax1"] describe "Docstrings" $ do testParse env0 ["docstrings"] testDocstrings env0 "docstrings" describe "Module Structure" $ do describe "Module-level docstrings" $ do it "allows single-line docstring before import" $ do let input = "\"\"\"Module docstring\"\"\"\nimport math\n" case parseModuleTest input of Left err -> expectationFailure $ "Parse failed: " ++ err Right _ -> return () it "allows multi-line docstring before import" $ do let input = "\"\"\"Module docstring\nwith multiple lines\"\"\"\nimport math\n" case parseModuleTest input of Left err -> expectationFailure $ "Parse failed: " ++ err Right _ -> return () describe "Invalid module structure (before imports)" $ do testModuleParseError "module_var_before_import" "x = 42\nimport math\n" testModuleParseError "module_call_before_import" "print(\"hello\")\nimport math\n" testModuleParseError "module_number_before_import" "42\nimport math\n" testModuleParseError "module_list_before_import" "[1, 2, 3]\nimport math\n" testModuleParseError "module_dict_before_import" "{\"key\": \"value\"}\nimport math\n" testModuleParseError "module_if_before_import" "if True:\n pass\nimport math\n" testModuleParseError "module_for_before_import" "for i in range(10):\n pass\nimport math\n" testModuleParseError "module_class_before_import" "class Foo:\n pass\nimport math\n" testModuleParseError "module_func_before_import" "def foo():\n pass\nimport math\n" testModuleParseError "module_actor_before_import" "actor Foo():\n pass\nimport math\n" describe "Module-level constants" $ do it "allows top-level declarations, signatures, and assignments" $ do expectModuleParseSuccess $ unlines [ "value : int" , "def helper() -> int:" , " return 41" , "value = helper()" ] it "rejects top-level expression statements" $ do err <- expectModuleParseFailure $ unlines [ "value = 1" , "1 + 2" ] err `shouldContain` "Only declarations and assignments are allowed at the module top level" it "rejects top-level control flow" $ do err <- expectModuleParseFailure $ unlines [ "import math" , "if True:" , " value = 1" ] err `shouldContain` "Only declarations and assignments are allowed at the module top level" it "rejects top-level reassignment" $ do err <- expectModuleParseFailure $ unlines [ "value = 1" , "value = 2" ] err `shouldContain` "Module top-level name 'value' cannot be assigned more than once" it "allows top-level destructuring with at least one bound name" $ do expectModuleParseSuccess "left, _ = (1, 2)\n" it "rejects duplicate names within one top-level assignment" $ do err <- expectModuleParseFailure "left, left = (1, 2)\n" err `shouldContain` "Module top-level name 'left' cannot be assigned more than once" it "rejects top-level wildcard-only assignment" $ do _ <- expectModuleParseFailure "_ = 1\n" return () it "rejects top-level assignments with no bound names" $ do err <- expectModuleParseFailure "[] = []\n" err `shouldContain` "Module top-level assignments must bind at least one name" it "rejects top-level wildcard-only destructuring assignment" $ do err <- expectModuleParseFailure "[_, _] = [1, 2]\n" err `shouldContain` "Module top-level assignments must bind at least one name" describe "Chunked module parser" $ do it "matches the serial parser for mixed top-level forms" $ do expectChunkedParseMatchesSerial $ unlines [ "\"\"\"module docs\"\"\"" , "import math" , "answer: int" , "answer = (" , " 40 +" , " 2" , ")" , "class Box:" , " def get(self):" , " return answer" , "actor Worker(env):" , " def run(self):" , " env.exit(0)" ] it "does not split on column-zero text inside strings" $ do expectChunkedParseMatchesSerial $ unlines [ "text = \"\"\"" , "def not_a_chunk():" , " pass" , "\"\"\"" , "formatted = \"value {str('class also_not_a_chunk:')}\"" , "def real():" , " return text" ] it "matches triple-string quote run handling" $ do expectChunkedParseMatchesSerial $ unlines [ "quote_tail = \"\"\"foo\"\"\"\"" , "two_quote_tail = \"\"\"foo\"\"\"\"\"" , "formatted = \"\"\"value {str(\"class not_a_chunk:\")}\"\"\"\"" , "def real():" , " return formatted" ] it "preserves adjacent declaration grouping" $ do expectChunkedParseMatchesSerial $ unlines [ "def even(n):" , " if n == 0:" , " return True" , " return odd(n - 1)" , "def odd(n):" , " if n == 0:" , " return False" , " return even(n - 1)" , "value = even(2)" ] it "reports later chunk parse errors at original source lines" $ do let input = unlines [ "ok = 1" , "def broken():" , " if True" , " pass" ] moduleName = S.modName ["chunked"] result <- E.try (P.parseModule moduleName "chunked.act" input Nothing) case result of Left (bundle :: ParseErrorBundle String P.CustomParseError) -> parseBundleErrorLine bundle `shouldBe` 3 Right _ -> expectationFailure "Expected chunked parser to reject malformed input" it "returns diagnostics for chunk scanner failures" $ do let input = " pass\n" moduleName = S.modName ["chunked"] result <- Compile.parseActSource Compile.defaultCompileOptions moduleName "chunked.act" input Nothing case result of Left [diagnostic] -> renderDiagnosticText diagnostic `shouldContain` "non-top-level text before first chunk" Left diagnostics -> expectationFailure ("Expected one diagnostic, got " ++ show (length diagnostics)) Right _ -> expectationFailure "Expected scanner failure diagnostic" it "matches the serial parser for existing fixtures" $ do actFiles <- actFilesUnder ("test" "src") forM_ actFiles $ \actFile -> do input <- readFile actFile expectChunkedParseMatchesSerialFile actFile input describe "Numeric literals" $ do it "parses INT64_MIN as a single literal" $ do case parseStmtAst "a = -9223372036854775808" of Left err -> expectationFailure $ "Parse failed: " ++ err Right [S.Assign _ _ expr] -> case expr of S.Int _ ival lexeme -> do ival `shouldBe` (-9223372036854775808) lexeme `shouldBe` "-9223372036854775808" other -> expectationFailure $ "Expected Int literal, got " ++ show other Right other -> expectationFailure $ "Unexpected AST: " ++ show other it "keeps unary minus above exponentiation for -1**2" $ do case parseExprAst "-1**2" of Left err -> expectationFailure $ "Parse failed: " ++ err Right (S.UnOp _ S.UMinus inner) -> case inner of S.BinOp _ lhs op rhs -> do op `shouldBe` S.Pow case lhs of S.Int _ ival lexeme -> do ival `shouldBe` 1 lexeme `shouldBe` "1" other -> expectationFailure $ "Expected left int literal, got " ++ show other case rhs of S.Int _ ival lexeme -> do ival `shouldBe` 2 lexeme `shouldBe` "2" other -> expectationFailure $ "Expected right int literal, got " ++ show other other -> expectationFailure $ "Expected power expression, got " ++ show other Right other -> expectationFailure $ "Expected unary minus, got " ++ show other it "respects parentheses for (-1)**2" $ do case parseExprAst "(-1)**2" of Left err -> expectationFailure $ "Parse failed: " ++ err Right (S.BinOp _ lhs op rhs) -> do op `shouldBe` S.Pow case lhs of S.Paren _ (S.Int _ ival lexeme) -> do ival `shouldBe` (-1) lexeme `shouldBe` "-1" other -> expectationFailure $ "Expected parenthesized negative literal, got " ++ show other case rhs of S.Int _ ival lexeme -> do ival `shouldBe` 2 lexeme `shouldBe` "2" other -> expectationFailure $ "Expected right int literal, got " ++ show other Right other -> expectationFailure $ "Expected power expression, got " ++ show other describe "Optional chaining" $ do it "parses optional chaining expression statements without crashing" $ do case parseStmtAst "l?.append(1)" of Left err -> expectationFailure $ "Parse failed: " ++ err Right [S.Expr _ expr@S.OptChain{}] -> loc expr `shouldNotBe` NoLoc Right other -> expectationFailure $ "Unexpected AST: " ++ show other describe "Completion" $ do it "completes inherited transform input attributes" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "import mini.layers.y_1 as y1" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " i." ] items <- Completion.memberCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor let labels = map Completion.completionLabel items forM_ ["interface_name", "vpn_name", "ipv4_address"] $ \label -> labels `shouldSatisfy` elem label it "completes explicitly typed transform input attributes" $ do let env = completionFixtureEnv env0 inputTypeName = "y1.stratoweave_rfs__rfs__l3vpn_endpoint_entry" (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "import mini.layers.y_1 as y1" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i: " ++ inputTypeName ++ ", di):" , " i.v" ] items <- Completion.memberCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldBe` ["vpn_name"] it "completes annotated parameters inside generic functions" $ do let env = completionFixtureEnv env0 inputTypeName = "y1.stratoweave_rfs__rfs__l3vpn_endpoint_entry" (src, cursor) = cursorSource $ unlines [ "import mini.layers.y_1 as y1" , "" , "def helper [T](i: " ++ inputTypeName ++ "):" , " i.v" ] items <- Completion.memberCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldBe` ["vpn_name"] it "completes local values assigned from typed calls" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o." ] items <- Completion.memberCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldSatisfy` elem "netinfra" it "completes local values assigned from nested member calls" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o_router = o.netinfra.router.create(i.name, id=i.id)" , " o_router." ] items <- Completion.memberCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldSatisfy` elem "router_id" it "completes local values assigned from member paths" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o_router = o.netinfra.router.create(i.name, id=i.id)" , " bc = o_router.base_config" , " bc." ] items <- Completion.memberCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldSatisfy` elem "asn" [ Completion.completionDetail item | item <- items , Completion.completionLabel item == "asn" ] `shouldBe` [Just "int"] it "uses inherited parameter types inside generic classes" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint[T](base.L3vpnEndpoint):" , " def transform(self, i, di):" , " i." ] items <- Completion.memberCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldSatisfy` elem "interface_name" it "resolves inherited parameter types in the parent module" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class LocalEndpoint(base.LocalEndpoint):" , " def transform(self, i):" , " a = i." ] items <- Completion.memberCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldSatisfy` elem "local_field" it "uses direct imports when transitive interfaces are stale" $ do withSystemTempDirectory "acton-completion" $ \dir -> do let directMod = S.modName ["direct"] staleMod = S.modName ["stale"] directTy = dir "direct.ty" staleTy = dir "stale.ty" inputName = S.name "LocalInput" routerName = S.name "Router" inputType = S.tCon (S.TC (S.NoQ inputName) []) transformType = S.tFun S.fxMut (S.posRow inputType S.posNil) S.kwdNil S.tWild transformInfo = I.NSig (S.tSchema [] transformType) S.NoDec Nothing inputClass = I.NClass [] [] [(S.name "local_field", I.NVar S.tWild)] Nothing routerClass = I.NClass [] [] [(S.name "transform", transformInfo)] Nothing directIface = I.NModule [] [ (routerName, routerClass) , (inputName, inputClass) ] Nothing directModule = S.Module directMod [] Nothing [] (src, cursor) = cursorSource $ unlines [ "import direct as base" , "" , "class Router(base.Router):" , " def transform(self, i):" , " i." ] createDirectoryIfMissing True dir B8.writeFile staleTy "not a current ty file" InterfaceFiles.writeFile directTy B8.empty B8.empty B8.empty Nothing [(staleMod, B8.empty)] [] [] [] Nothing directIface directModule items <- Completion.memberCompletions env0 [dir] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldSatisfy` elem "local_field" it "shows signatures for nested member calls" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o.netinfra.router.create(\"r1\", )" ] sigs <- Completion.callSignatures env [] (S.modName ["rfs"]) "rfs.act" src cursor case sigs of [sig] -> do Completion.callSignatureLabel sig `shouldSatisfy` isPrefixOf "o.netinfra.router.create(" Completion.callSignatureLabel sig `shouldSatisfy` not . isInfixOf "__builtin__." Completion.callSignatureActiveParameter sig `shouldBe` 1 let params = map Completion.signatureParameterLabel (Completion.callSignatureParameters sig) params `shouldSatisfy` any (isPrefixOf "arg1:") params `shouldSatisfy` any (isPrefixOf "id:") params `shouldSatisfy` all (not . isInfixOf "__builtin__.") other -> expectationFailure $ "Unexpected signatures: " ++ show other it "ignores string parentheses when finding call signatures" $ do let env = completionFixtureEnv env0 forM_ ["\"(\"", "\"x)\""] $ \arg -> do let (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o.netinfra.router.create(" ++ arg ++ ", )" ] sigs <- Completion.callSignatures env [] (S.modName ["rfs"]) "rfs.act" src cursor case sigs of [sig] -> Completion.callSignatureActiveParameter sig `shouldBe` 1 other -> expectationFailure $ "Unexpected signatures: " ++ show other it "completes keyword arguments for nested member calls" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o.netinfra.router.create(\"r1\", )" ] items <- Completion.argumentCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldBe` ["id=", "role=", "mock="] map Completion.completionKind items `shouldBe` replicate 3 Completion.CompletionKeyword map Completion.completionDetail items `shouldBe` map Just ["int", "str", "bool"] it "filters supplied keyword argument completions" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o.netinfra.router.create(\"r1\", id=1, )" ] items <- Completion.argumentCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldBe` ["role=", "mock="] it "prefixes keyword argument completions" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o.netinfra.router.create(\"r1\", id=1, r)" ] items <- Completion.argumentCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldBe` ["role="] it "keeps escaped commas inside string arguments" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o.netinfra.router.create(\"r1\", id=1, role=\"a\\\",b\", m)" ] items <- Completion.argumentCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor map Completion.completionLabel items `shouldBe` ["mock="] it "does not complete keyword names inside argument values" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o.netinfra.router.create(\"r1\", id=)" ] items <- Completion.argumentCompletions env [] (S.modName ["rfs"]) "rfs.act" src cursor items `shouldBe` [] it "hovers local values assigned from member paths" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o_router = o.netinfra.router.create(i.name, id=i.id)" , " bc = o_router.base_config" , " bc.asn = 1" ] info <- Completion.hoverInfo env [] (S.modName ["rfs"]) "rfs.act" src cursor case info of Just hover -> do Completion.hoverDetail hover `shouldSatisfy` isInfixOf "BaseConfig" Completion.hoverDocumentation hover `shouldBe` Just "Base router configuration." Nothing -> expectationFailure "Expected hover info for bc" it "hovers nested member fields" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o_router = o.netinfra.router.create(i.name, id=i.id)" , " bc = o_router.base_config" , " bc.asn = 1" ] info <- Completion.hoverInfo env [] (S.modName ["rfs"]) "rfs.act" src cursor case info of Just hover -> do Completion.hoverDetail hover `shouldBe` "bc.asn: int" Completion.hoverDocumentation hover `shouldBe` Just "Autonomous system number." Nothing -> expectationFailure "Expected hover info for bc.asn" it "hovers methods resolved through local call results" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource $ unlines [ "import mini.layers.base_1 as base" , "" , "class L3vpnEndpoint(base.L3vpnEndpoint):" , " def transform(self, i, di):" , " o = base.o_root()" , " o.netinfra.router.create(\"r1\", id=1)" ] info <- Completion.hoverInfo env [] (S.modName ["rfs"]) "rfs.act" src cursor case info of Just hover -> do Completion.hoverDetail hover `shouldSatisfy` isPrefixOf "o.netinfra.router.create:" Completion.hoverDetail hover `shouldSatisfy` isInfixOf "RouterEntry" Completion.hoverDetail hover `shouldSatisfy` not . isInfixOf "__builtin__." Completion.hoverDocumentation hover `shouldBe` Just "Create a router entry." Nothing -> expectationFailure "Expected hover info for create" it "ignores imported module path hovers" $ do let env = completionFixtureEnv env0 (src, cursor) = cursorSource "import mini.layers.y_1\n" result <- E.try (E.evaluate (Completion.hoverInfoWithEnv env src cursor)) case result of Left (err :: E.SomeException) -> expectationFailure $ "Unexpected hover exception: " ++ E.displayException err Right info -> info `shouldBe` Nothing describe "String Interpolation" $ do -- Note: In these tests, we use Haskell string literals which require escaping. -- The test format is: testParseOutput -- -- Examples of what the Haskell escapes mean in actual Acton code: -- Haskell literal: "\"\"" → Acton code: "" -- Haskell literal: "\"hello\"" → Acton code: "hello" -- Haskell literal: "'world'" → Acton code: 'world' -- Haskell literal: "f\"x = {x}\"" → Acton code: f"x = {x}" -- Haskell literal: "\"x = {x}\"" → Acton code: "x = {x}" -- -- Interpolation is a core feature in standard Acton strings. -- Both "string {expr}" and f"string {expr}" support interpolation -- Basic functionality (simplest to more complex) describe "Basic string literals" $ do testParseOutput "\"\"" "\"\"" testParseOutput "\"plain text\"" "\"plain text\"" testParseOutput "'hello world'" "\"hello world\"" -- single quotes convert to double describe "Basic interpolation" $ do testParseOutput "\"hello {name}\"" "\"hello %s\" % str(name)" -- default interpolation testParseOutput "f\"hello {name}!\"" "\"hello %s!\" % str(name)" -- with f-prefix testParseOutput "'Value: {x}'" "\"Value: %s\" % str(x)" -- single quotes work too describe "Multiple interpolations" $ do testParseOutput "f\"Hello {name}, your score is {score}\"" "\"Hello %s, your score is %s\" % (str(name), str(score))" testParseOutput "\"First: {a}, Second: {b}, Third: {c}\"" "\"First: %s, Second: %s, Third: %s\" % (str(a), str(b), str(c))" describe "Expressions in interpolation" $ do testParseOutput "\"Sum: {a + b}\"" "\"Sum: %s\" % str(a + b)" -- simple expression testParseOutput "f\"Calculation: {a * b // 2}\"" "\"Calculation: %s\" % str(a * b // 2)" -- complex expression testParseOutput "f\"Result: {func({a: b})}\"" "\"Result: %s\" % str(func({a: b}))" -- nested braces describe "Formatting specifications" $ do -- Width testParseOutput "f\"{num:5}\"" "\"%5s\" % str(num)" testParseOutput "f\"{num:10}\"" "\"%10s\" % str(num)" -- Alignment testParseOutput "f\"{name:<9}\"" "\"%-9s\" % str(name)" -- left testParseOutput "f\"{name:>10}\"" "\"%10s\" % str(name)" -- right testParseOutput "f\"{name:^10}\"" "\"%s\" % str(name).center(10)" -- center -- Zero padding testParseOutput "f\"{num:05}\"" "\"%05d\" % num" testParseOutput "f\"{num:010}\"" "\"%010d\" % num" -- Floating point precision testParseOutput "f\"{pi:.2f}\"" "\"%.2f\" % pi" testParseOutput "f\"{pi:.4f}\"" "\"%.4f\" % pi" testParseOutput "f\"{pi:.0f}\"" "\"%.0f\" % pi" testParseOutput "f\"{pi:10.2f}\"" "\"%10.2f\" % pi" -- Combined formatting testParseOutput "f\"{a:>10}:{b:^10}:{c:<10}\"" "\"%10s:%s:%-10s\" % (str(a), str(b).center(10), str(c))" testParseOutput "f\"{num:+08.2f}\"" "\"%08.2f\" % num" -- Spaces in format spec (various positions allowed) testParseOutput "f\"{ num : 10 }\"" "\"%10s\" % str(num)" -- spaces everywhere describe "String quote variations" $ do -- Triple quotes support interpolation by default testParseOutput "\"\"\"hello {name}!\"\"\"" "\"hello %s!\" % str(name)" -- triple double quotes testParseOutput "'''multi-line\n{value}'''" "\"multi-line\\\\n%s\" % str(value)" -- triple single quotes testParseOutput "f\"\"\"Name: {name}\nAge: {age}\"\"\"" "\"Name: %s\\\\nAge: %s\" % (str(name), str(age))" -- f-prefix with multi-line testParseOutput "\"\"\"Plain text without interpolation\"\"\"" "\"Plain text without interpolation\"" -- no braces = no interpolation describe "Triple quotes with 4-5 quotes (ending with quotes)" $ do -- Triple double quotes with 4 quotes (string ends with single ") testParseOutput "\"\"\"\"foo\"\"\"" "\"\\\"foo\"" -- """"foo""" -> "foo (1 quote in content) testParseOutput "\"\"\"\"hello world\"\"\"\"" "\"\\\"hello world\\\"\"" -- """""hello world""""" -> ""hello world"" (2 quotes in content) testParseOutput "r\"\"\"\"raw quote\"\"\"" "\"\\\"raw quote\"" -- raw string with 4 quotes testParseOutput "r\"\"\"\"\"raw two quotes\"\"\"" "\"\\\"\\\"raw two quotes\"" -- raw string with 5 quotes -- Triple single quotes with 4 quotes (string ends with single ') testParseOutput "''''bar'''" "\"'bar\"" -- ''''bar''' -> 'bar (1 quote in content) testParseOutput "'''''test me'''''" "\"''test me''\"" -- '''''test me''''' -> ''test me'' (2 quotes in content) testParseOutput "r''''raw single'''" "\"'raw single\"" -- raw string with 4 quotes testParseOutput "r'''''raw two singles'''" "\"''raw two singles\"" -- raw string with 5 quotes -- Interpolation with trailing quotes testParseOutput "\"\"\"\"value: {x}\"\"\"" "\"\\\"value: %s\" % str(x)" -- interpolation with trailing quote testParseOutput "\"\"\"\"\"formatted {y}\"\"\"\"\"" "\"\\\"\\\"formatted %s\\\"\\\"\" % str(y)" -- 2 quotes before and after testParseOutput "f''''x = {x}'''" "\"'x = %s\" % str(x)" -- f-string with 4 single quotes testParseOutput "f'''''vals: {a}, {b}'''''" "\"''vals: %s, %s''\" % (str(a), str(b))" -- f-string with 5 single quotes describe "Triple quotes with 6+ quotes (error cases)" $ do -- Triple double quotes with 6+ quotes should fail testParseError "triple_double_6quotes" "\"\"\"foo\"\"\"\"\"\"" -- 3 opening, 6 closing testParseError "triple_double_7quotes" "\"\"\"bar\"\"\"\"\"\"\"" -- 3 opening, 7 closing testParseError "triple_double_8quotes" "\"\"\"test\"\"\"\"\"\"\"\"" -- 3 opening, 8 closing testParseError "triple_double_10quotes" "\"\"\"content\"\"\"\"\"\"\"\"\"\"" -- 3 opening, 10 closing -- Triple single quotes with 6+ quotes should fail testParseError "triple_single_6quotes" "'''foo''''''" -- 3 opening, 6 closing testParseError "triple_single_7quotes" "'''bar'''''''" -- 3 opening, 7 closing testParseError "triple_single_8quotes" "'''test''''''''" -- 3 opening, 8 closing testParseError "triple_single_10quotes" "'''content''''''''''" -- 3 opening, 10 closing -- Raw strings with 6+ quotes should fail testParseError "raw_triple_double_6quotes" "r\"\"\"raw\"\"\"\"\"\"" -- raw with 6 closing quotes testParseError "raw_triple_single_6quotes" "r'''raw''''''" -- raw with 6 closing quotes -- F-strings with 6+ quotes should fail testParseError "fstring_triple_double_6quotes" "f\"\"\"x={x}\"\"\"\"\"\"" -- f-string with 6 closing quotes testParseError "fstring_triple_single_6quotes" "f'''x={x}''''''" -- f-string with 6 closing quotes describe "Special characters and escaping" $ do -- Escaped braces testParseOutput "f\"something but {{{substituted}}}\"" "\"something but {%s}\" % str(substituted)" testParseOutput "\"{{a}}\"" "\"{a}\"" -- Escaped braces should not trigger interpolation testParseOutput "\"{{\"" "\"{\"" -- Just escaped opening brace testParseOutput "\"}}\"" "\"}\"" -- Just escaped closing brace testParseOutput "f\"{{hello}}\"" "\"{hello}\"" -- f-string with escaped braces testParseOutput "\"{{hello}} {world}\"" "\"{hello} %s\" % str(world)" -- Mix of escaped and interpolated -- Escaped quotes testParseOutput "f\"hello \\\"thing\\\"\"" "\"hello \\\"thing\\\"\"" testParseOutput "f'hello \\'thing\\''" "\"hello 'thing'\"" testParseOutput "f\"Value: {x} with \\\"quotes\\\"\"" "\"Value: %s with \\\"quotes\\\"\" % str(x)" -- Unicode testParseOutput "f\"Hello, {name}! 你好!\"" "\"Hello, %s! \\20320\\22909!\" % str(name)" describe "Slice expressions in interpolation" $ do -- Basic slice patterns testParseOutput "\"slice: {arr[1:3]}\"" "\"slice: %s\" % str(arr[1:3])" -- basic range testParseOutput "\"slice: {arr[:5]}\"" "\"slice: %s\" % str(arr[:5])" -- from start testParseOutput "\"slice: {arr[2:]}\"" "\"slice: %s\" % str(arr[2:])" -- to end -- Step parameter testParseOutput "\"step: {arr[1:10:2]}\"" "\"step: %s\" % str(arr[1:10:2])" -- with step testParseOutput "\"reverse: {arr[::-1]}\"" "\"reverse: %s\" % str(arr[::-1])" -- negative step -- Complex expressions testParseOutput "\"complex: {arr[i+1:j*2]}\"" "\"complex: %s\" % str(arr[i + 1:j * 2])" -- expressions in slice testParseOutput "\"nested: {matrix[i][j:k]}\"" "\"nested: %s\" % str(matrix[i][j:k])" -- nested indexing describe "Nested string interpolation" $ do testParseOutput "\"outer {\"inner {x}\"}\"" "\"outer %s\" % str(\"inner %s\" % str(x))" testParseOutput "\"outer {'inner {x}'}\"" "\"outer %s\" % str(\"inner %s\" % str(x))" testParseOutput "'outer {\"inner {x}\"}'" "\"outer %s\" % str(\"inner %s\" % str(x))" testParseOutput "\"level1 {\"level2 {\"level3 {x}\"}\"}\"" "\"level1 %s\" % str(\"level2 %s\" % str(\"level3 %s\" % str(x)))" testParseOutput "\"outer {{literal}} {\"inner {x}\"}\"" "\"outer {literal} %s\" % str(\"inner %s\" % str(x))" describe "Escape sequences" $ do -- Standard escapes (preserved during parsing) testParseOutput "\"\\n\\t\\r\"" "\"\\\\n\\\\t\\\\r\"" -- Hex escapes (note splitting behavior when followed by hex chars) testParseOutput "\"\\x48ello\"" "\"\\\\x48\" \"ello\"" -- splits to prevent C reading too many hex digits testParseOutput "\"\\x41BC\"" "\"\\\\x41\" \"BC\"" -- Unicode escapes testParseOutput "\"\\u0041\"" "\"\\\\u0041\"" -- 4-digit unicode testParseOutput "\"\\U00000041\"" "\"\\\\U00000041\"" -- 8-digit unicode -- Octal escapes testParseOutput "\"\\123\"" "\"\\\\123\"" -- 3-digit octal testParseOutput "\"\\7\"" "\"\\\\7\"" -- 1-digit octal -- Mixed with interpolation testParseOutput "f\"Hello \\n{name}\\t!\"" "\"Hello \\\\n%s\\\\t!\" % str(name)" -- ==== OTHER STRING LITERAL TESTS ==== describe "Other String Literals" $ do describe "Raw strings (no interpolation)" $ do testParseOutput "r\"hello {world}\"" "\"hello {world}\"" testParseOutput "r'test {x} value'" "\"test {x} value\"" testParseOutput "r\"\"\"multi\nline {no} interpolation\"\"\"" "\"multi\\\\nline {no} interpolation\"" testParseOutput "r\"path\\to\\file\"" "\"path\\\\\\\\to\\\\\\\\file\"" testParseOutput "r\"regex: \\x[0-9a-f]+\"" "\"regex: \\\\\\\\x[0-9a-f]+\"" testParseOutput "r\"test \\n \\t \\r\"" "\"test \\\\\\\\n \\\\\\\\t \\\\\\\\r\"" describe "Bytes literals" $ do -- Basic bytes testParseOutput "b\"hello\"" " bhello" testParseOutput "b\"\"\"multi\nline\"\"\"" " bmulti\\nline" -- Bytes with hex escapes (note splitting behavior) testParseOutput "b\"\\x48ello\"" " b\\x48 bello" -- splits hex from following text testParseOutput "b\"\\x48\\x65llo\"" " b\\x48\\x65llo" -- multiple hex escapes -- Other escapes in bytes testParseOutput "b\"Hello\\nWorld\"" " bHello\\nWorld" describe "Raw bytes literals" $ do testParseOutput "rb\"hello\"" " bhello" testParseOutput "rb'world'" " bworld" testParseOutput "rb\"\"\"multi\nline\"\"\"" " bmulti\\nline" describe "Legacy percent formatting (not interpolated)" $ do testParseOutput "\"hello %s\" % name" "\"hello %s\" % name" testParseOutput "\"Value: %d\" % count" "\"Value: %d\" % count" -- ==== ERROR HANDLING TESTS ==== describe "String Parsing Errors" $ do describe "Basic string errors" $ do testModuleParseError "unclosed_string" "a = \"hello" testModuleParseError "unclosed_string_triple" "z = 1\na = \"\"\"hello\nb = 3\ndef foo():\n pass" testModuleParseError "unclosed_raw_string" "a = r\"hello" testModuleParseError "unclosed_bytes_string" "a = b\"hello" testModuleParseError "unclosed_raw_bytes_string" "a = rb\"hello" testModuleParseError "unclosed_raw_string_single" "a = r'hello" testModuleParseError "unclosed_bytes_string_single" "a = b'hello" testModuleParseError "unclosed_raw_bytes_string_single" "a = rb'hello" describe "Triple quote errors (6+ quotes)" $ do testModuleParseError "six_double_quotes" "a = \"\"\"\"\"\"test\"\"\"\"\"\"" -- 6 quotes each side testModuleParseError "six_single_quotes" "a = ''''''test''''''" -- 6 quotes each side testModuleParseError "seven_double_quotes" "a = \"\"\"\"\"\"\"test\"\"\"\"\"\"\"" -- 7 quotes each side testModuleParseError "mixed_six_quotes_double" "a = \"\"\"\"\"\"mixed content with {interpolation}\"\"\"\"\"\"" testModuleParseError "raw_six_quotes" "a = r\"\"\"\"\"\"raw test\"\"\"\"\"\"" describe "Basic interpolation errors" $ do -- F-string errors testParseError "fstring_unclosed_brace" "f\"Unclosed brace: {name" testParseError "fstring_empty_expression" "f\"Empty expression {}\"" testParseError "fstring_missing_expression" "f\"Missing expression {:10}\"" testParseError "fstring_unbalanced_format" "f\"Unbalanced format {name:}:10}\"" -- String interpolation errors (without f-prefix) testParseError "string_unclosed_brace" "\"Unclosed brace: {name" testParseError "tristring_unclosed_brace" "\"\"\"Unclosed brace: {name" testParseError "string_empty_expression" "\"Empty expression {}\"" testParseError "string_missing_expression" "\"Missing expression {:10}\"" describe "Format specification errors" $ do testParseError "fstring_invalid_format" "f\"Invalid format specifier {name:@Z}\"" testParseError "fstring_invalid_alignment" "f\"{name:@10}\"" testParseError "string_invalid_format" "\"{name:@Z}\"" testParseError "fstring_empty_format_specifier" "f\"Empty format spec {x:}\"" testParseError "fstring_missing_precision_digits_error" "f\"Missing precision digits {value:10.}\"" testParseError "invalid_after_width" "\"value: {x:10@}\"" testParseError "invalid_after_align" "\"value: {x:>10@}\"" testParseError "invalid_after_precision" "\"value: {x:10.2@}\"" testParseError "invalid_in_type_spec" "\"value: {x:10.2@f}\"" describe "Nested interpolation errors" $ do testParseError "nested_unclosed_outer" "\"outer {\"inner" testParseError "nested_unclosed_inner" "\"outer {\"inner {x}\"" testParseError "nested_empty_inner" "\"outer {\"inner {}\"}\"" testParseError "nested_invalid_format" "\"outer {\"inner {x:@10}\"}\"" testParseError "triple_nested_unclosed" "\"level1 {\"level2 {\"level3 {x" testParseError "mixed_quotes_unclosed" "\"outer {'inner {x" testParseError "escaped_brace_error" "\"outer {{broken {x}\"" testParseError "nested_empty_format" "\"outer {\"inner {x:}\"}\"" testParseError "nested_invalid_align" "\"outer {\"inner {x:@5}\"}\"" testParseError "nested_bad_type_spec" "\"outer {\"inner {x:5@}\"}\"" testParseError "deep_nesting_error" "\"a {\"b {\"c {\"d {\"e {f:@}\"}\"}\"}\"}\"}\"" testParseError "alternating_quotes_error" "\"a {'b {\"c {'d {e'}\"}'}\"" describe "Position-specific errors" $ do testParseError "error_at_start" "{x} at start" testParseError "error_at_end" "\"at end {x" testParseError "error_in_middle" "\"start {x:@} end\"" testParseError "multiline_unclosed" "\"\"\"Line 1\nLine 2 {x\nLine 3\"\"\"" testParseError "multiline_nested_error" "\"\"\"First line\n{\"inner\n {broken}\n\"}\"\"\"" testParseError "multiline_format_error" "\"\"\"\nValue: {x:@invalid}\nMore text\"\"\"" testParseError "newline_in_expr" "\"value: {x\n}\"" testParseError "tab_in_format" "\"value: {x:\t10}\"" testParseError "unicode_format_error" "\"你好 {name:你}\"" describe "Slice expression errors" $ do testParseError "slice_unclosed_bracket" "\"slice: {arr[1:3\"" testParseError "slice_invalid_step" "\"slice: {arr[:::\"" testParseError "slice_missing_bracket" "\"slice: {arr 1:3]}\"" testParseError "slice_nested_error" "\"outer {arr[inner[}\"" testParseError "slice_format_error" "\"slice: {arr[1:3]:@10}\"" describe "Escape Sequence Errors" $ do describe "Hex escape errors" $ do testParseError "hex_incomplete_one_digit" "\"\\x4\"" testParseError "hex_incomplete_no_digits" "\"\\x\"" testParseError "hex_invalid_char" "\"\\xAG\"" testParseError "hex_incomplete_in_interpolation" "f\"value: {x} and \\x4\"" describe "Unicode escape errors" $ do testParseError "unicode_short_incomplete" "\"\\u123\"" testParseError "unicode_short_no_digits" "\"\\u\"" testParseError "unicode_short_invalid_char" "\"\\u123G\"" testParseError "unicode_short_in_fstring" "f\"Hello \\u123\"" testParseError "unicode_long_incomplete" "\"\\U1234567\"" testParseError "unicode_long_no_digits" "\"\\U\"" testParseError "unicode_long_invalid_char" "\"\\U1234567G\"" testParseError "unicode_long_in_fstring" "f\"Hello \\U1234567\"" describe "Octal escape errors" $ do testParseError "octal_out_of_range" "\"\\777\"" testParseError "octal_invalid_first_digit" "\"\\8\"" testParseError "octal_invalid_char" "\"\\12G\"" testParseError "octal_out_of_range_in_fstring" "f\"value: {x} \\777\"" describe "Unknown escape sequences" $ do testParseError "unknown_escape_p" "\"\\p\"" testParseError "unknown_escape_z" "\"\\z\"" testParseError "unknown_escape_in_fstring" "f\"unknown: \\q\"" testParseError "unknown_escape_with_interpolation" "f\"value: {x} \\k\"" describe "Documentation Generation" $ do testDocGen env0 ["bar", "foo"] describe "Pass 2: Kinds" $ do testKinds env0 ["deact"] describe "Pass 3: Types" $ do testTypes env0 ["deact"] testTypes env0 ["test_discovery"] testAttributesInitialization env0 it "keeps generated names stable within unchanged defs" $ do let fooSource = unlines [ "def foo(xs: list[int], y: int):" , " [xs][0][0] += y" ] warmSource = unlines [ "def warm(a):" , " return (a + 1) * 2" , "" ] namesA <- typedDefGeneratedNames env0 "stable_names_a" fooSource "foo" namesB <- typedDefGeneratedNames env0 "stable_names_b" (warmSource ++ fooSource) "foo" namesA `shouldSatisfy` any ("W_foo_" `isPrefixOf`) namesA `shouldSatisfy` any ("V_foo_" `isPrefixOf`) namesA `shouldBe` namesB it "accepts docstrings and extension decls at top level" $ do let src = unlines [ "\"\"\"Module docstring\"\"\"" , "" , "protocol Proto:" , " f: () -> int" , "" , "class Cls:" , " pass" , "" , "extension Cls(Proto):" , " def f(self) -> int:" , " return 0" ] tchecked <- typecheckSource env0 "tlname_doc_ext" src tchecked `shouldSatisfy` const True it "continues after a non-total top-level statement has been checked" $ do let src = unlines [ "value = 41" , "" , "def later() -> int:" , " return value + 1" ] tchecked <- typecheckSource env0 "top_non_total_then_total" src tchecked `shouldSatisfy` const True it "reports inferred signatures for non-total top-level statements" $ do sigsRef <- liftIO $ newIORef [] let src = "value = 41\n" moduleName = S.modName ["top_non_total_sig"] actFile = "" sysTypesPath = ".." ".." "dist" "base" "out" "types" onInferred names sig = modifyIORef' sigsRef ((names, sig) :) parsed <- liftIO $ P.parseModule moduleName actFile src Nothing env <- liftIO $ Acton.Env.mkEnv [sysTypesPath] env0 parsed kchecked <- liftIO $ Acton.Kinds.check env parsed _ <- liftIO $ Acton.Types.reconstruct Nothing (Just onInferred) env kchecked sigs <- liftIO $ reverse <$> readIORef sigsRef sigs `shouldSatisfy` any (\(names, sig) -> names == ["value"] && "value : int" `isInfixOf` sig) it "collects errors from independent total top-level statements" $ do let src = unlines [ "proc def first() -> int:" , " return \"one\"" , "" , "value = 1" , "" , "proc def second() -> int:" , " return \"two\"" ] result <- E.try (do tchecked <- typecheckSource env0 "top_total_errors" src E.evaluate (length (show tchecked)) return ()) :: IO (Either Acton.Types.TypeErrors ()) case result of Left (Acton.Types.TypeErrors errs) -> length errs `shouldBe` 2 Right _ -> expectationFailure "Expected multiple type errors but type checking succeeded" describe "Import Semantics" $ do it "omits private names from the public interface" $ do (envA, parsedA) <- parseAct env0 "import_private_a" kcheckedA <- liftIO $ Acton.Kinds.check envA parsedA (nmodA, _, _, _) <- liftIO $ Acton.Types.reconstruct Nothing Nothing envA kcheckedA let I.NModule impsA tenvA mdocA = nmodA env1 = Acton.Env.addMod (S.modname parsedA) impsA tenvA mdocA env0 (envB, _) <- parseAct env1 "import_private" case Acton.Env.lookupName (S.name "__foo") envB of Nothing -> pure () Just _ -> expectationFailure "from import * should skip __foo" case Acton.Env.lookupName (S.name "public_value") envB of Just (I.HNAlias _) -> pure () _ -> expectationFailure "from import * should include public_value" it "blocks qualified access to private names" $ do (envA, parsedA) <- parseAct env0 "import_private_a" kcheckedA <- liftIO $ Acton.Kinds.check envA parsedA (nmodA, _, _, _) <- liftIO $ Acton.Types.reconstruct Nothing Nothing envA kcheckedA let I.NModule impsA tenvA mdocA = nmodA publicTEnvA = Acton.Env.publicTEnv tenvA env1 = Acton.Env.addMod (S.modname parsedA) impsA publicTEnvA mdocA env0 (envB, parsedB) <- parseAct env1 "import_private_qualified" kcheckedB <- liftIO $ Acton.Kinds.check envB parsedB result <- liftIO $ (E.try (do (_, tcheckedB, _, _) <- Acton.Types.reconstruct Nothing Nothing envB kcheckedB _ <- E.evaluate (rnf tcheckedB) pure () ) :: IO (Either CompilationError ())) case result of Left NoItem{} -> pure () Left err -> expectationFailure $ "Expected NoItem error, got " ++ show err Right _ -> expectationFailure "Expected type check failure for private name access" describe "Pass 4: Normalizer" $ do testNorm env0 ["deact"] describe "Pass 5: Deactorizer" $ do testDeact env0 ["deact", "deact_from_import"] describe "Pass 6: CPS" $ do testCps env0 ["cps_andor"] testCps env0 ["cps_volatiles"] testCps env0 ["cps_optchain"] describe "Pass 7: Lambda Lifting" $ do testLL env0 ["deact"] describe "Pass 8: Boxing" $ do testBoxing env0 ["deact"] describe "Pass 9: CodeGen" $ do testCodeGen env0 ["ints"] testCodeGen env0 ["deact"] testCodeGen env0 ["lines"] -- BuildSpec: parsing and update-in-place of Build.act (canonical layout) describe "BuildSpec" $ do it "parses canonical Build.act and dumps JSON" $ do let buildAct = unlines [ "# Canonical Build.act file" , "name = \"demo\"" , "description = \"Demo project\"" , "fingerprint = 0x1234abcd5678ef00" , "" , "# Dependencies section" , "dependencies = {" , " \"a\": (path=\"deps/a\")" , "}" , "" , "# Zig dependencies section" , "zig_dependencies = {" , " \"z\": (" , " url=\"https://z\"," , " hash=\"abcd\"," , " artifacts=[\"z\"]" , " )" , "}" , "" , "# bla bla bla" , "actor main(env: Env):" , " pass" , "" ] case BuildSpec.parseBuildAct buildAct of Left err -> expectationFailure err Right (spec,_,_) -> do BuildSpec.fingerprint spec `shouldBe` "0x1234abcd5678ef00" let json = BuildSpec.encodeBuildSpecJSON spec case Ae.eitherDecode' json of Left err2 -> expectationFailure err2 Right spec2 -> spec2 `shouldBe` spec it "errors when fingerprint prefix does not match name" $ do withSystemTempDirectory "acton-fp" $ \dir -> do let buildAct = unlines [ "name = \"demo\"" , "fingerprint = 0x0000000000000000" , "" ] writeFile (dir "Build.act") buildAct res <- (E.try (Compile.loadBuildSpec dir) :: IO (Either Compile.ProjectError BuildSpec.BuildSpec)) case res of Left (Compile.ProjectError msg) -> msg `shouldSatisfy` (isInfixOf "Fingerprint mismatch") Right _ -> expectationFailure "Expected fingerprint mismatch error" it "accepts matching fingerprint for name" $ do withSystemTempDirectory "acton-fp" $ \dir -> do let prefix = Fingerprint.fingerprintPrefixForName "demo" fp = Fingerprint.formatFingerprint ((fromIntegral prefix `shiftL` 32) .|. 0x1) buildAct = unlines [ "name = \"demo\"" , "fingerprint = " ++ fp , "" ] writeFile (dir "Build.act") buildAct res <- (E.try (Compile.loadBuildSpec dir) :: IO (Either Compile.ProjectError BuildSpec.BuildSpec)) case res of Left (Compile.ProjectError msg) -> expectationFailure ("Unexpected fingerprint error: " ++ msg) Right spec -> BuildSpec.fingerprint spec `shouldBe` fp it "errors when fingerprint is malformed" $ do withSystemTempDirectory "acton-fp" $ \dir -> do let buildAct = unlines [ "name = \"demo\"" , "fingerprint = \"not-a-number\"" , "" ] writeFile (dir "Build.act") buildAct res <- (E.try (Compile.loadBuildSpec dir) :: IO (Either Compile.ProjectError BuildSpec.BuildSpec)) case res of Left (Compile.ProjectError msg) -> msg `shouldSatisfy` (isInfixOf "Invalid fingerprint") Right _ -> expectationFailure "Expected invalid fingerprint error" it "errors when fingerprint is quoted hex" $ do withSystemTempDirectory "acton-fp" $ \dir -> do let buildAct = unlines [ "name = \"demo\"" , "fingerprint = \"0x1234abcd5678ef00\"" , "" ] writeFile (dir "Build.act") buildAct res <- (E.try (Compile.loadBuildSpec dir) :: IO (Either Compile.ProjectError BuildSpec.BuildSpec)) case res of Left (Compile.ProjectError msg) -> msg `shouldSatisfy` (isInfixOf "Invalid fingerprint") Right _ -> expectationFailure "Expected invalid fingerprint error" it "errors when fingerprint is decimal" $ do withSystemTempDirectory "acton-fp" $ \dir -> do let buildAct = unlines [ "name = \"demo\"" , "fingerprint = 1234" , "" ] writeFile (dir "Build.act") buildAct res <- (E.try (Compile.loadBuildSpec dir) :: IO (Either Compile.ProjectError BuildSpec.BuildSpec)) case res of Left (Compile.ProjectError msg) -> msg `shouldSatisfy` (isInfixOf "Invalid fingerprint") Right _ -> expectationFailure "Expected invalid fingerprint error" it "errors when name is missing" $ do withSystemTempDirectory "acton-fp" $ \dir -> do let buildAct = unlines [ "fingerprint = 0x1234abcd5678ef00" , "" ] writeFile (dir "Build.act") buildAct res <- (E.try (Compile.loadBuildSpec dir) :: IO (Either Compile.ProjectError BuildSpec.BuildSpec)) case res of Left (Compile.ProjectError msg) -> msg `shouldSatisfy` (isInfixOf "Missing project name") Right _ -> expectationFailure "Expected missing project name error" it "errors when fingerprint is missing" $ do withSystemTempDirectory "acton-fp" $ \dir -> do let buildAct = unlines [ "name = \"demo\"" , "" ] writeFile (dir "Build.act") buildAct res <- (E.try (Compile.loadBuildSpec dir) :: IO (Either Compile.ProjectError BuildSpec.BuildSpec)) case res of Left (Compile.ProjectError msg) -> msg `shouldSatisfy` (isInfixOf "Missing fingerprint") Right _ -> expectationFailure "Expected missing fingerprint error" it "updates Build.act in-place, preserving comments and main actor" $ do let buildAct0 = unlines [ "# Canonical Build.act file" , "name = \"demo\"" , "description = \"Demo project\"" , "fingerprint = 0x1234abcd5678ef00" , "" , "# Dependencies section (keep my comments)" , "dependencies = {" , " \"a\": (path=\"deps/a\")" , "}" , "" , "# Zig dependencies section" , "zig_dependencies = {" , "}" , "" , "# bla bla bla" , "actor main(env: Env):" , " pass" , "" ] let prefix = Fingerprint.fingerprintPrefixForName "demo2" newFp = Fingerprint.formatFingerprint ((fromIntegral prefix `shiftL` 32) .|. 0x1) newJson = unlines [ "{" , " \"name\": \"demo2\"," , " \"description\": \"Demo project v2\"," , " \"fingerprint\": \"" ++ newFp ++ "\"," , " \"dependencies\": {" , " \"a\": {\"path\": \"deps/aa\"}," , " \"b\": {\"url\": \"u\", \"hash\": \"h\"}" , " }," , " \"zig_dependencies\": {" , " \"z\": {\"url\": \"zu\", \"hash\": \"zh\", \"artifacts\": [\"z\"]}" , " }" , "}" ] case BuildSpec.updateBuildActFromJSON buildAct0 (BL.fromStrict (B8.pack newJson)) of Left err -> expectationFailure err Right buildAct1 -> do let expected = unlines [ "# Canonical Build.act file" , "name = \"demo2\"" , "description = \"Demo project v2\"" , "fingerprint = " ++ newFp , "" , "# Dependencies section (keep my comments)" , "dependencies = {" , " \"a\": (" , " path=\"deps/aa\"" , " )," , " \"b\": (" , " url=\"u\"," , " hash=\"h\"" , " )" , "}" , "" , "# Zig dependencies section" , "zig_dependencies = {" , " \"z\": (" , " url=\"zu\"," , " hash=\"zh\"," , " artifacts=[\"z\"]" , " )" , "}" , "" , "# bla bla bla" , "actor main(env: Env):" , " pass" , "" ] buildAct1 `shouldBe` expected it "keeps hex fingerprints zero-padded when rewriting Build.act" $ do let buildAct0 = unlines [ "name = \"demo\"" , "fingerprint = 0x056275683c869ace" , "" , "dependencies = {}" , "" , "zig_dependencies = {}" , "" ] case BuildSpec.parseBuildAct buildAct0 of Left err -> expectationFailure err Right (spec, _, _) -> case BuildSpec.updateBuildActFromJSON buildAct0 (BuildSpec.encodeBuildSpecJSON spec) of Left err -> expectationFailure err Right buildAct1 -> do buildAct1 `shouldSatisfy` (isInfixOf "fingerprint = 0x056275683c869ace") buildAct1 `shouldSatisfy` (not . isInfixOf "fingerprint = 0x56275683c869ace") it "rejects non-hex fingerprints in Build.act updates" $ do let buildAct0 = unlines [ "name = \"demo\"" , "fingerprint = 0x1234abcd5678ef00" , "" , "dependencies = {}" , "" , "zig_dependencies = {}" , "" ] newJson = "{\"fingerprint\": \"1234\"}" case BuildSpec.updateBuildActFromJSON buildAct0 (BL.fromStrict (B8.pack newJson)) of Left err -> err `shouldSatisfy` (isInfixOf "64-bit hex literal") Right _ -> expectationFailure "Expected Build.act update to reject decimal fingerprint" it "parses Build.act with only dependencies (zig deps missing)" $ do let buildAct = unlines [ "# Only dependencies" , "name = \"demo\"" , "fingerprint = 0x1234abcd5678ef00" , "dependencies = {" , " \"a\": (path=\"deps/a\")" , "}" , "" , "actor main(env: Env):" , " pass" , "" ] case BuildSpec.parseBuildAct buildAct of Left err -> expectationFailure err Right (spec,_,_) -> do -- deps present, zig deps empty BuildSpec.dependencies spec `shouldSatisfy` (not . null) BuildSpec.zig_dependencies spec `shouldSatisfy` null it "parses Build.act with only zig_dependencies (deps missing)" $ do let buildAct = unlines [ "# Only zig deps" , "name = \"demo\"" , "fingerprint = 0x1234abcd5678ef00" , "zig_dependencies = {" , " \"z\": (" , " url=\"zu\"," , " hash=\"zh\"," , " artifacts=[\"z\"]" , " )" , "}" , "" , "actor main(env: Env):" , " pass" , "" ] case BuildSpec.parseBuildAct buildAct of Left err -> expectationFailure err Right (spec,_,_) -> do -- zig present, deps empty BuildSpec.zig_dependencies spec `shouldSatisfy` (not . null) BuildSpec.dependencies spec `shouldSatisfy` null it "parses Build.act with no dependency blocks" $ do let buildAct = unlines [ "# No deps here" , "name = \"demo\"" , "fingerprint = 0x1234abcd5678ef00" , "" , "actor main(env: Env):" , " pass" , "" ] case BuildSpec.parseBuildAct buildAct of Left err -> expectationFailure err Right (spec,_,_) -> do BuildSpec.dependencies spec `shouldSatisfy` null BuildSpec.zig_dependencies spec `shouldSatisfy` null it "appends missing zig_dependencies block when absent" $ do let buildAct0 = unlines [ "# Build with only dependencies" , "name = \"demo\"" , "fingerprint = 0x1234abcd5678ef00" , "dependencies = {" , " \"a\": (path=\"deps/a\")" , "}" , "" , "actor main(env: Env):" , " pass" , "" ] let newJson = "{\n \"zig_dependencies\": {\n \"z\": {\"url\": \"zu\", \"hash\": \"zh\", \"artifacts\": [\"z\"]}\n }\n}\n" case BuildSpec.updateBuildActFromJSON buildAct0 (BL.fromStrict (B8.pack newJson)) of Left err -> expectationFailure err Right buildAct1 -> do -- Original dependencies remain buildAct1 `shouldSatisfy` (isInfixOf $ unlines [ " \"a\": (" , " path=\"deps/a\"" , " )" ]) -- Missing zig_dependencies appended with expected formatting buildAct1 `shouldSatisfy` (isInfixOf $ unlines [ "zig_dependencies = {" , " \"z\": (" , " url=\"zu\"," , " hash=\"zh\"," , " artifacts=[\"z\"]" , " )" , "}" ]) it "appends missing dependencies block when absent" $ do let buildAct0 = unlines [ "# Build with only zig deps" , "name = \"demo\"" , "fingerprint = 0x1234abcd5678ef00" , "zig_dependencies = {" , " \"z\": (url=\"zu\", hash=\"zh\", artifacts=[\"z\"])" , "}" , "" , "actor main(env: Env):" , " pass" , "" ] let newJson = "{\n \"dependencies\": {\n \"a\": {\"path\": \"deps/a\"}\n }\n}\n" case BuildSpec.updateBuildActFromJSON buildAct0 (BL.fromStrict (B8.pack newJson)) of Left err -> expectationFailure err Right buildAct1 -> do -- Original zig deps remain buildAct1 `shouldSatisfy` (isInfixOf $ unlines [ " \"z\": (" , " url=\"zu\"," , " hash=\"zh\"," , " artifacts=[\"z\"]" , " )" ]) -- Missing dependencies appended with expected formatting buildAct1 `shouldSatisfy` (isInfixOf $ unlines [ "dependencies = {" , " \"a\": (" , " path=\"deps/a\"" , " )" , "}" ]) it "updates dependencies block with non-canonical whitespace, preserving outer line" $ do let buildAct0 = unlines [ "# Whitespace variant Build.act" , "name = \"demo\"" , "fingerprint = 0x1234abcd5678ef00" , "dependencies = {" , "" , " \"a\" : ( path = \"deps/a\" )" , "}" , "" , "actor main(env: Env):" , " pass" , "" ] let newJson = "{\n \"dependencies\": {\n \"a\": {\"path\": \"deps/aa\"}\n }\n}\n" case BuildSpec.updateBuildActFromJSON buildAct0 (BL.fromStrict (B8.pack newJson)) of Left err -> expectationFailure err Right buildAct1 -> do -- Outer label line (with extra spaces) is preserved buildAct1 `shouldSatisfy` (isInfixOf "dependencies = {") -- Inner body is canonicalised and updated buildAct1 `shouldSatisfy` (isInfixOf $ unlines [ " \"a\": (" , " path=\"deps/aa\"" , " )" ]) it "updates only the overlaid dependency entry, preserving others" $ do let buildAct0 = unlines [ "# Multiple dependencies" , "name = \"demo\"" , "fingerprint = 0x1234abcd5678ef00" , "dependencies = {" , " \"a\": (path=\"deps/a\")," , " \"b\": (path=\"deps/b\")" , "}" , "" , "actor main(env: Env):" , " pass" , "" ] let newJson = "{\n \"dependencies\": {\n \"b\": {\"path\": \"deps/bb\"}\n }\n}\n" case BuildSpec.updateBuildActFromJSON buildAct0 (BL.fromStrict (B8.pack newJson)) of Left err -> expectationFailure err Right buildAct1 -> do -- JSON dependencies is treated as full set: only "b" remains, with updated path. buildAct1 `shouldSatisfy` (not . isInfixOf " \"a\": (path=\"deps/a\"),") buildAct1 `shouldSatisfy` (isInfixOf $ unlines [ " \"b\": (" , " path=\"deps/bb\"" , " )" ]) it "removes all dependencies and zig deps when new spec objects are empty" $ do let buildAct0 = unlines [ "# Canonical Build.act file" , "name = \"demo\"" , "fingerprint = 0x1234abcd5678ef00" , "" , "# Dependencies section (keep my comments)" , "dependencies = {" , " \"a\": (path=\"deps/a\")" , "}" , "" , "# Zig dependencies section" , "zig_dependencies = {" , " \"z\": (" , " url=\"zu\"," , " hash=\"zh\"," , " artifacts=[\"z\"]" , " )" , "}" , "" , "# bla bla bla" , "actor main(env: Env):" , " pass" , "" ] let newJson = "{\n \"dependencies\": {},\n \"zig_dependencies\": {}\n}\n" case BuildSpec.updateBuildActFromJSON buildAct0 (BL.fromStrict (B8.pack newJson)) of Left err -> expectationFailure err Right buildAct1 -> do let expected = unlines [ "# Canonical Build.act file" , "name = \"demo\"" , "fingerprint = 0x1234abcd5678ef00" , "" , "# Dependencies section (keep my comments)" , "dependencies = {" , "}" , "" , "# Zig dependencies section" , "zig_dependencies = {" , "}" , "" , "# bla bla bla" , "actor main(env: Env):" , " pass" , "" ] buildAct1 `shouldBe` expected -- Helper function to format custom parse errors consistently formatCustomParseError :: String -> String -> SrcLoc -> P.CustomParseError -> String formatCustomParseError filename input loc err = let diagnostic = Diag.customParseErrorDiagnostic "Syntax error" filename input loc err doc = prettyDiagnostic WithUnicode (TabSize 4) diagnostic layout = layoutPretty defaultLayoutOptions (unAnnotate doc) in T.unpack $ renderStrict layout withTrailingNewline :: String -> String withTrailingNewline s | null s = s | last s == '\n' = s | otherwise = s ++ "\n" parseActon :: String -> Either String String parseActon input = System.IO.Unsafe.unsafePerformIO $ E.catch (E.evaluate $ case runParser (St.evalStateT P.stmt P.initState) "" inputWithNewline of Left err -> Left $ renderDiagnostic err Right result -> Right $ concatMap (Pretty.print) result) handleCustomParseException where inputWithNewline = withTrailingNewline input handleCustomParseException :: P.CustomParseException -> IO (Either String String) renderDiagnostic err = let diagnostic = Diag.parseDiagnosticFromBundle "test" inputWithNewline err doc = prettyDiagnostic WithUnicode (TabSize 4) diagnostic layout = layoutPretty defaultLayoutOptions (unAnnotate doc) in T.unpack $ renderStrict layout handleCustomParseException (P.CustomParseException loc err) = return $ Left $ formatCustomParseError "test" inputWithNewline loc err -- Helper function to parse a full module (for testing module-level constructs) parseModuleTest :: String -> Either String String parseModuleTest input = System.IO.Unsafe.unsafePerformIO $ E.catch (E.evaluate $ case runParser (St.evalStateT P.file_input P.initState) "test.act" inputWithNewline of Left err -> Left $ renderDiagnostic err Right (_imports, _mdoc, _suite) -> Right $ "Module parsed successfully") handleCustomParseException where inputWithNewline = withTrailingNewline input renderDiagnostic err = let diagnostic = Diag.parseDiagnosticFromBundle "test.act" inputWithNewline err doc = prettyDiagnostic WithUnicode (TabSize 4) diagnostic layout = layoutPretty defaultLayoutOptions (unAnnotate doc) in T.unpack $ renderStrict layout handleCustomParseException :: P.CustomParseException -> IO (Either String String) handleCustomParseException (P.CustomParseException loc err) = return $ Left $ formatCustomParseError "test.act" inputWithNewline loc err expectChunkedParseMatchesSerial :: String -> Expectation expectChunkedParseMatchesSerial input = do let actFile = "chunked.act" expectChunkedParseMatchesSerialFile actFile input expectChunkedParseMatchesSerialFile :: FilePath -> String -> Expectation expectChunkedParseMatchesSerialFile actFile input = do let moduleName = S.modName ["chunked"] serial <- P.parseModuleSerial moduleName actFile input Nothing chunked <- P.parseModule moduleName actFile input Nothing when (chunked /= serial) $ expectationFailure ("Chunked parser AST differs from serial parser for " ++ actFile) parseBundleErrorLine :: ParseErrorBundle String P.CustomParseError -> Int parseBundleErrorLine bundle = let firstError = NE.head (bundleErrors bundle) (_, posState) = reachOffset (errorOffset firstError) (bundlePosState bundle) in unPos (sourceLine (pstateSourcePos posState)) renderDiagnosticText diagnostic = let doc = prettyDiagnostic WithUnicode (TabSize 4) diagnostic layout = layoutPretty defaultLayoutOptions (unAnnotate doc) in T.unpack $ renderStrict layout actFilesUnder :: FilePath -> IO [FilePath] actFilesUnder root = do entries <- sort <$> listDirectory root fmap concat $ mapM (\entry -> do let path = root entry isDir <- doesDirectoryExist path if isDir then actFilesUnder path else return [path | takeExtension path == ".act"] ) entries expectModuleParseSuccess :: String -> IO () expectModuleParseSuccess input = case parseModuleTest input of Left err -> expectationFailure $ "Parse failed: " ++ err Right _ -> return () expectModuleParseFailure :: String -> IO String expectModuleParseFailure input = case parseModuleTest input of Left err -> return err Right result -> expectationFailure $ "Expected parse failure, got: " ++ result completionFixtureEnv :: Acton.Env.Env0 -> Acton.Env.Env0 completionFixtureEnv env0 = let y1Mod = S.modName ["mini", "layers", "y_1"] baseMod = S.modName ["mini", "layers", "base_1"] inputName = S.name "stratoweave_rfs__rfs__l3vpn_endpoint_entry" inputType = S.tCon (S.TC (S.GName y1Mod inputName) []) localInputName = S.name "LocalInput" localInputType = S.tCon (S.TC (S.NoQ localInputName) []) transformType = S.tFun S.fxMut (S.posRow inputType (S.posRow S.tWild S.posNil)) S.kwdNil S.tWild transformInfo = I.NSig (S.tSchema [] transformType) S.NoDec Nothing localTransformType = S.tFun S.fxMut (S.posRow localInputType S.posNil) S.kwdNil S.tWild localTransformInfo = I.NSig (S.tSchema [] localTransformType) S.NoDec Nothing outputRootName = S.name "OutputRoot" outputRootType = S.tCon (S.TC (S.GName baseMod outputRootName) []) netinfraName = S.name "Netinfra" netinfraType = S.tCon (S.TC (S.GName baseMod netinfraName) []) routerCollectionName = S.name "RouterCollection" routerCollectionType = S.tCon (S.TC (S.GName baseMod routerCollectionName) []) routerEntryName = S.name "RouterEntry" routerEntryType = S.tCon (S.TC (S.GName baseMod routerEntryName) []) baseConfigName = S.name "BaseConfig" baseConfigType = S.tCon (S.TC (S.GName baseMod baseConfigName) []) oRootType = S.tFun S.fxPure S.posNil S.kwdNil outputRootType oRootInfo = I.NDef (S.tSchema [] oRootType) S.NoDec Nothing createType = S.tFun S.fxMut (S.posRow Builtin.tStr S.posNil) (S.kwdRow (S.name "id") Builtin.tInt (S.kwdRow (S.name "role") Builtin.tStr (S.kwdRow (S.name "mock") Builtin.tBool S.kwdNil))) routerEntryType createInfo = I.NDef (S.tSchema [] createType) S.NoDec (Just "Create a router entry.") baseClass = I.NClass [] [] [(S.name "transform", transformInfo)] (Just "Base transform class.") localBaseClass = I.NClass [] [] [(S.name "transform", localTransformInfo)] Nothing outputRootClass = I.NClass [] [] [ fieldOf "netinfra" netinfraType , field "l3vpns" ] Nothing netinfraClass = I.NClass [] [] [ fieldOf "router" routerCollectionType ] Nothing routerCollectionClass = I.NClass [] [] [ (S.name "create", createInfo) ] Nothing routerEntryClass = I.NClass [] [] [ field "router_id" , field "hostname" , fieldOf "base_config" baseConfigType ] Nothing baseConfigClass = I.NClass [] [] [ docFieldOf "asn" Builtin.tInt "Autonomous system number." , fieldOf "ipv4_address" Builtin.tStr ] (Just "Base router configuration.") localInputClass = I.NClass [] [] [ field "local_field" ] Nothing inputClass = I.NClass [] [] [ field "interface_name" , field "vpn_name" , field "customer_name" , field "ipv4_address" ] (Just "L3VPN endpoint input.") field n = fieldOf n S.tWild fieldOf n typ = (S.name n, I.NVar typ) docFieldOf n typ doc = (S.name n, I.NSig (S.tSchema [] typ) S.NoDec (Just doc)) in Acton.Env.addMod baseMod [] [ (S.name "L3vpnEndpoint", baseClass) , (S.name "LocalEndpoint", localBaseClass) , (localInputName, localInputClass) , (outputRootName, outputRootClass) , (netinfraName, netinfraClass) , (routerCollectionName, routerCollectionClass) , (routerEntryName, routerEntryClass) , (baseConfigName, baseConfigClass) , (S.name "o_root", oRootInfo) ] Nothing $ Acton.Env.addMod y1Mod [] [(inputName, inputClass)] Nothing env0 cursorSource :: String -> (String, Int) cursorSource src = let marker = T.pack "" (before, after) = T.breakOn marker (T.pack src) in if T.null after then (src, length src) else (T.unpack before ++ T.unpack (T.drop (T.length marker) after), T.length before) parseStmtAst :: String -> Either String [S.Stmt] parseStmtAst input = System.IO.Unsafe.unsafePerformIO $ E.catch (E.evaluate $ case runParser (St.evalStateT P.stmt P.initState) "" inputWithNewline of Left err -> Left $ renderDiagnostic err Right result -> Right result) handleCustomParseException where inputWithNewline = withTrailingNewline input renderDiagnostic err = let diagnostic = Diag.parseDiagnosticFromBundle "test" inputWithNewline err doc = prettyDiagnostic WithUnicode (TabSize 4) diagnostic layout = layoutPretty defaultLayoutOptions (unAnnotate doc) in T.unpack $ renderStrict layout handleCustomParseException :: P.CustomParseException -> IO (Either String [S.Stmt]) handleCustomParseException (P.CustomParseException loc err) = return $ Left $ formatCustomParseError "test" inputWithNewline loc err parseExprAst :: String -> Either String S.Expr parseExprAst input = System.IO.Unsafe.unsafePerformIO $ E.catch (E.evaluate $ case runParser (St.evalStateT P.expr P.initState) "" inputWithNewline of Left err -> Left $ renderDiagnostic err Right result -> Right result) handleCustomParseException where inputWithNewline = withTrailingNewline input renderDiagnostic err = let diagnostic = Diag.parseDiagnosticFromBundle "test" inputWithNewline err doc = prettyDiagnostic WithUnicode (TabSize 4) diagnostic layout = layoutPretty defaultLayoutOptions (unAnnotate doc) in T.unpack $ renderStrict layout handleCustomParseException :: P.CustomParseException -> IO (Either String S.Expr) handleCustomParseException (P.CustomParseException loc err) = return $ Left $ formatCustomParseError "test" inputWithNewline loc err -- Helper function to test module-level parser errors with golden files testModuleParseError :: String -> String -> Spec testModuleParseError testName input = do it testName $ do case parseModuleTest input of Left err -> goldenTextFile ("test/parser_golden/" ++ testName ++ ".golden") $ return $ T.pack $ "ERROR: " ++ err Right result -> goldenTextFile ("test/parser_golden/" ++ testName ++ ".golden") $ return $ T.pack $ "PARSED: " ++ result -- Helper function to test parsing (just that it succeeds) testParse :: Acton.Env.Env0 -> [String] -> Spec testParse env0 modulePaths = do let dir = "test" "1-parse" modules <- runIO $ do let processModule (accEnv, accModules) modulePath = do (env, parsed) <- parseAct accEnv modulePath return (accEnv, accModules ++ [(takeFileName modulePath, parsed)]) (_, modules) <- foldM processModule (env0, []) modulePaths return modules forM_ modules $ \(modName, parsed) -> genTests "Parse Check" dir modName parsed parsed -- Helper function to test parsing with output validation testParseOutput :: String -> String -> Spec testParseOutput input expected = do it (show input) $ do case parseActon input of Left err -> expectationFailure $ "Parse failed: " ++ err Right output -> output `shouldBe` expected -- Helper function to test parser errors with golden files testParseError :: String -> String -> Spec testParseError testName input = do it testName $ do case parseActon input of Left err -> goldenTextFile ("test/parser_golden/" ++ testName ++ ".golden") $ return $ T.pack $ "ERROR: " ++ err Right result -> goldenTextFile ("test/parser_golden/" ++ testName ++ ".golden") $ return $ T.pack $ "PARSED: " ++ result -- Helper function for documentation golden tests -- Takes a list of module paths in dependency order -- Examples: ["bar", "foo"] or ["utils/math", "utils/strings", "app"] -- Generates golden files for all formats: .txt (ASCII), .md (Markdown), .html (HTML) testDocGen :: Acton.Env.Env0 -> [String] -> Spec testDocGen env0 modulePaths = do oldDir <- runIO getCurrentDirectory let goldenDir = oldDir "test" "doc-golden" modules <- runIO $ do let processModule (accEnv, accModules) modulePath = do (env, parsed) <- parseAct accEnv modulePath kchecked <- Acton.Kinds.check env parsed (nmod, _, _, _) <- Acton.Types.reconstruct Nothing Nothing env kchecked let I.NModule imps moduleTypeEnv moduleDoc = nmod let newAccEnv = Acton.Env.addMod (S.modname parsed) imps moduleTypeEnv moduleDoc accEnv return (newAccEnv, accModules ++ [((takeFileName modulePath), parsed, nmod)]) (finalEnv, modules) <- foldM processModule (env0, []) modulePaths return modules -- Generate documentation for each module forM_ modules $ \(modName, parsed, nmod) -> do describe modName $ do it "generates ASCII documentation (plain)" $ do let asciiDoc = DocP.printAsciiDoc False nmod parsed goldenTextFile (goldenDir modName ++ ".txt") $ return $ T.pack asciiDoc it "generates ASCII documentation (styled)" $ do let asciiDoc = DocP.printAsciiDoc True nmod parsed goldenTextFile (goldenDir modName ++ "-color.txt") $ return $ T.pack asciiDoc it "generates Markdown documentation" $ do let mdDoc = DocP.printMdDoc nmod parsed goldenTextFile (goldenDir modName ++ ".md") $ return $ T.pack mdDoc it "generates HTML documentation" $ do let htmlDoc = DocP.printHtmlDoc nmod parsed goldenTextFile (goldenDir modName ++ ".html") $ return $ T.pack htmlDoc -- Parse an Acton module by module path -- Examples: "foo" -> src/foo.act, module foo -- "foo/bar" -> src/foo/bar.act, module foo.bar parseAct env0 modulePath = do let moduleComponents = splitDirectories modulePath moduleName = S.modName moduleComponents act_file = "test" "src" modulePath ++ ".act" sysTypesPath = ".." ".." "dist" "base" "out" "types" src <- liftIO $ readFile act_file parsed <- liftIO $ P.parseModule moduleName act_file src Nothing env <- liftIO $ Acton.Env.mkEnv [sysTypesPath] env0 parsed return (env, parsed) typecheckSource env0 modName src = do let moduleName = S.modName [modName] actFile = "<" ++ modName ++ ">" sysTypesPath = ".." ".." "dist" "base" "out" "types" parsed <- liftIO $ P.parseModule moduleName actFile src Nothing env <- liftIO $ Acton.Env.mkEnv [sysTypesPath] env0 parsed kchecked <- liftIO $ Acton.Kinds.check env parsed (_, tchecked, _, _) <- liftIO $ Acton.Types.reconstruct Nothing Nothing env kchecked return tchecked typedDefGeneratedNames env0 modName src defName = do tchecked <- typecheckSource env0 modName src case findTypedDef defName tchecked of Just d -> pure $ generatedInternalNames (Pretty.print d) Nothing -> expectationFailure ("Definition not found: " ++ defName) >> pure [] findTypedDef defName (S.Module _ _ _ ss) = findInSuite ss where findInSuite [] = Nothing findInSuite (S.Decl _ ds : ss) = case [ d | d@(S.Def _ n _ _ _ _ _ _ _ _) <- ds, prstr n == defName ] of d : _ -> Just d [] -> findInSuite ss findInSuite (_ : ss) = findInSuite ss generatedInternalNames s = sort . nub . filter isGenerated $ words $ map keep s where keep c | isAlphaNum c || c == '_' = c | otherwise = ' ' isGenerated n = "W_" `isPrefixOf` n || "V_" `isPrefixOf` n genTests pass_name dir testname input_data output_data = do let input_golden = dir testname ++ ".input" output_golden = dir testname ++ ".output" describe testname $ do it ("Check " ++ pass_name ++ " input") $ do goldenTextFile input_golden $ return $ T.pack $ Pretty.print input_data it ("Check " ++ pass_name ++ " output") $ do goldenTextFile output_golden $ return $ T.pack $ Pretty.print output_data -- pass 2 Kinds check testKinds :: Acton.Env.Env0 -> [String] -> Spec testKinds env0 modulePaths = do let dir = "test" "2-kinds" modules <- runIO $ do let processModule (accEnv, accModules) modulePath = do (env, parsed) <- parseAct accEnv modulePath kchecked <- Acton.Kinds.check env parsed return (accEnv, accModules ++ [(takeFileName modulePath, parsed, kchecked)]) (_, modules) <- foldM processModule (env0, []) modulePaths return modules forM_ modules $ \(modName, parsed, kchecked) -> genTests "Kinds Check" dir modName parsed kchecked -- pass 3 Type check testTypes :: Acton.Env.Env0 -> [String] -> Spec testTypes env0 modulePaths = do let dir = "test" "3-types" modules <- runIO $ do let processModule (accEnv, accModules) modulePath = do (env, parsed) <- parseAct accEnv modulePath kchecked <- Acton.Kinds.check env parsed (nmod, tchecked, _, _) <- Acton.Types.reconstruct Nothing Nothing env kchecked let I.NModule imps tenv mdoc = nmod let newAccEnv = Acton.Env.addMod (S.modname parsed) imps tenv mdoc accEnv return (newAccEnv, accModules ++ [(takeFileName modulePath, kchecked, tchecked)]) (_, modules) <- foldM processModule (env0, []) modulePaths return modules forM_ modules $ \(modName, kchecked, tchecked) -> genTests "Type Check" dir modName kchecked tchecked -- pass 4 Normalizer testNorm :: Acton.Env.Env0 -> [String] -> Spec testNorm env0 modulePaths = do let dir = "test" "4-normalizer" modules <- runIO $ do let processModule (accEnv, accModules) modulePath = do (env, parsed) <- parseAct accEnv modulePath kchecked <- Acton.Kinds.check env parsed (nmod, tchecked, env0Typed, _) <- Acton.Types.reconstruct Nothing Nothing env kchecked let I.NModule imps tenv mdoc = nmod (normalized, normEnv) <- Acton.Normalizer.normalize env0Typed tchecked let newAccEnv = Acton.Env.addMod (S.modname parsed) imps tenv mdoc accEnv return (newAccEnv, accModules ++ [(takeFileName modulePath, tchecked, normalized)]) (_, modules) <- foldM processModule (env0, []) modulePaths return modules forM_ modules $ \(modName, tchecked, normalized) -> genTests "Normalizer" dir modName tchecked normalized -- pass 5 Deactorizer testDeact :: Acton.Env.Env0 -> [String] -> Spec testDeact env0 modulePaths = do let dir = "test" "5-deactorizer" modules <- runIO $ do let processModule (accEnv, accModules) modulePath = do (env, parsed) <- parseAct accEnv modulePath kchecked <- Acton.Kinds.check env parsed (nmod, tchecked, env0Typed, _) <- Acton.Types.reconstruct Nothing Nothing env kchecked let I.NModule imps tenv mdoc = nmod (normalized, normEnv) <- Acton.Normalizer.normalize env0Typed tchecked (deacted, deactEnv) <- Acton.Deactorizer.deactorize normEnv normalized let newAccEnv = Acton.Env.addMod (S.modname parsed) imps tenv mdoc accEnv return (newAccEnv, accModules ++ [(takeFileName modulePath, normalized, deacted)]) (_, modules) <- foldM processModule (env0, []) modulePaths return modules forM_ modules $ \(modName, normalized, deacted) -> genTests "Deactorizer" dir modName normalized deacted -- pass 6 CPS testCps :: Acton.Env.Env0 -> [String] -> Spec testCps env0 modulePaths = do let dir = "test" "6-cps" modules <- runIO $ do let processModule (accEnv, accModules) modulePath = do (env, parsed) <- parseAct accEnv modulePath kchecked <- Acton.Kinds.check env parsed (nmod, tchecked, env0Typed, _) <- Acton.Types.reconstruct Nothing Nothing env kchecked let I.NModule imps tenv mdoc = nmod (normalized, normEnv) <- Acton.Normalizer.normalize env0Typed tchecked (deacted, deactEnv) <- Acton.Deactorizer.deactorize normEnv normalized (cpstyled, _) <- Acton.CPS.convert deactEnv deacted let newAccEnv = Acton.Env.addMod (S.modname parsed) imps tenv mdoc accEnv return (newAccEnv, accModules ++ [(takeFileName modulePath, deacted, cpstyled)]) (_, modules) <- foldM processModule (env0, []) modulePaths return modules forM_ modules $ \(modName, deacted, cpstyled) -> genTests "CPS" dir modName deacted cpstyled -- pass 7 Lambda Lifting testLL :: Acton.Env.Env0 -> [String] -> Spec testLL env0 modulePaths = do let dir = "test" "7-lambdalifting" modules <- runIO $ do let processModule (accEnv, accModules) modulePath = do (env, parsed) <- parseAct accEnv modulePath kchecked <- Acton.Kinds.check env parsed (nmod, tchecked, env0Typed, _) <- Acton.Types.reconstruct Nothing Nothing env kchecked let I.NModule imps tenv mdoc = nmod (normalized, normEnv) <- Acton.Normalizer.normalize env0Typed tchecked (deacted, deactEnv) <- Acton.Deactorizer.deactorize normEnv normalized (cpstyled, cpsEnv) <- Acton.CPS.convert deactEnv deacted (lifted,liftEnv) <- Acton.LambdaLifter.liftModule cpsEnv cpstyled let newAccEnv = Acton.Env.addMod (S.modname parsed) imps tenv mdoc accEnv return (newAccEnv, accModules ++ [(takeFileName modulePath, cpstyled, lifted)]) (_, modules) <- foldM processModule (env0, []) modulePaths return modules forM_ modules $ \(modName, cpstyled, lifted) -> genTests "Lambda Lifting" dir modName cpstyled lifted -- pass 8 Boxing testBoxing :: Acton.Env.Env0 -> [String] -> Spec testBoxing env0 modulePaths = do let dir = "test" "8-boxing" modules <- runIO $ do let processModule (accEnv, accModules) modulePath = do (env, parsed) <- parseAct accEnv modulePath kchecked <- Acton.Kinds.check env parsed (nmod, tchecked, env0Typed, _) <- Acton.Types.reconstruct Nothing Nothing env kchecked let I.NModule imps tenv mdoc = nmod (normalized, normEnv) <- Acton.Normalizer.normalize env0Typed tchecked (deacted, deactEnv) <- Acton.Deactorizer.deactorize normEnv normalized (cpstyled, cpsEnv) <- Acton.CPS.convert deactEnv deacted (lifted,liftEnv) <- Acton.LambdaLifter.liftModule cpsEnv cpstyled boxed <- Acton.Boxing.doBoxing liftEnv lifted let newAccEnv = Acton.Env.addMod (S.modname parsed) imps tenv mdoc accEnv return (newAccEnv, accModules ++ [(takeFileName modulePath, lifted, boxed)]) (_, modules) <- foldM processModule (env0, []) modulePaths return modules forM_ modules $ \(modName, lifted, boxed) -> genTests "Boxing" dir modName lifted boxed -- pass 9 CodeGen testCodeGen :: Acton.Env.Env0 -> [String] -> Spec testCodeGen env0 modulePaths = do let dir = "test" "9-codegen" modules <- runIO $ do let processModule (accEnv, accModules) modulePath = do (env, parsed) <- parseAct accEnv modulePath kchecked <- Acton.Kinds.check env parsed (nmod, tchecked, env0Typed, _) <- Acton.Types.reconstruct Nothing Nothing env kchecked let I.NModule imps tenv mdoc = nmod (normalized, normEnv) <- Acton.Normalizer.normalize env0Typed tchecked (deacted, deactEnv) <- Acton.Deactorizer.deactorize normEnv normalized (cpstyled, cpsEnv) <- Acton.CPS.convert deactEnv deacted (lifted,liftEnv) <- Acton.LambdaLifter.liftModule cpsEnv cpstyled boxed <- Acton.Boxing.doBoxing liftEnv lifted let act_file = "test" "src" modulePath ++ ".act" srcText <- readFile act_file let srcbase = "test" "src" modulePath (n,h,c) <- Acton.CodeGen.generate liftEnv srcbase srcText True boxed "test-hash" let newAccEnv = Acton.Env.addMod (S.modname parsed) imps tenv mdoc accEnv return (newAccEnv, accModules ++ [(takeFileName modulePath, boxed, n, h, c)]) (_, modules) <- foldM processModule (env0, []) modulePaths return modules forM_ modules $ \(modName, boxed, n, h, c) -> do let pass_name = "CodeGen" let input_golden = dir modName ++ ".input" h_golden = dir modName ++ ".h" c_golden = dir modName ++ ".c" describe modName $ do it ("Check " ++ pass_name ++ " input") $ do goldenTextFile input_golden $ return $ T.pack $ Pretty.print boxed it ("Check " ++ pass_name ++ " .h output") $ do goldenTextFile h_golden $ return $ T.pack $ Pretty.print h it ("Check " ++ pass_name ++ " .c output") $ do goldenTextFile c_golden $ return $ T.pack $ Pretty.print c testDocstrings :: Acton.Env.Env0 -> String -> Spec testDocstrings env0 testname = do (env, parsed) <- parseAct env0 testname kchecked <- liftIO $ Acton.Kinds.check env parsed (nmod, _, _, _) <- liftIO $ Acton.Types.reconstruct Nothing Nothing env kchecked let I.NModule _ tenv mdoc = nmod -- Extract docstrings from the parsed AST let S.Module _ _ _ stmts = parsed extractDeclDocstrings (S.Decl _ decls) = concatMap extractDocFromDecl decls extractDeclDocstrings _ = [] extractDocFromDecl (S.Def _ n _ _ _ _ _ _ _ ddoc) = [(S.nstr n, ddoc)] extractDocFromDecl (S.Class _ n _ _ _ ddoc) = [(S.nstr n, ddoc)] extractDocFromDecl (S.Actor _ n _ _ _ _ ddoc) = [(S.nstr n, ddoc)] extractDocFromDecl (S.Protocol _ n _ _ _ ddoc) = [(S.nstr n, ddoc)] extractDocFromDecl (S.Extension _ _ _ _ _ ddoc) = [("extension", ddoc)] docstrings = concatMap extractDeclDocstrings stmts describe testname $ do -- Basic functionality tests it "extracts module docstrings" $ do case mdoc of Just doc -> do doc `shouldContain` "Test module" doc `shouldContain` "{braces}" Nothing -> expectationFailure "Module docstring not extracted" it "extracts function docstrings" $ do case lookup "test_function" docstrings of Just (Just doc) -> doc `shouldContain` "Test function" Just Nothing -> expectationFailure "Function should have docstring" Nothing -> expectationFailure "Function not found" it "handles functions without docstrings" $ do case lookup "no_docstring_function" docstrings of Just Nothing -> return () -- Expected: no docstring Just (Just _) -> expectationFailure "Function should not have docstring" Nothing -> expectationFailure "Function not found" it "extracts class docstrings" $ do case lookup "TestClass" docstrings of Just (Just doc) -> doc `shouldContain` "Test class" Just Nothing -> expectationFailure "Class should have docstring" Nothing -> expectationFailure "Class not found" it "extracts actor docstrings" $ do case lookup "TestActor" docstrings of Just (Just doc) -> doc `shouldContain` "Test actor" Just Nothing -> expectationFailure "Actor should have docstring" Nothing -> expectationFailure "Actor not found" it "extracts protocol docstrings" $ do case lookup "TestProtocol" docstrings of Just (Just doc) -> doc `shouldContain` "Test protocol" Just Nothing -> expectationFailure "Protocol should have docstring" Nothing -> expectationFailure "Protocol not found" it "extracts extension docstrings" $ do case lookup "extension" docstrings of Just (Just doc) -> doc `shouldContain` "Extension" Just Nothing -> expectationFailure "Extension should have docstring" Nothing -> expectationFailure "Extension not found" -- Edge case tests it "ignores non-first string statements" $ do case lookup "function_with_non_first_string" docstrings of Just Nothing -> return () -- Expected: no docstring Just (Just _) -> expectationFailure "Non-first string should not be docstring" Nothing -> expectationFailure "Function not found" it "extracts only first string as docstring" $ do case lookup "function_with_multiple_strings" docstrings of Just (Just doc) -> do doc `shouldContain` "First string is docstring" when ("Second string" `isInfixOf` doc) $ expectationFailure "Later strings should not be in docstring" Just Nothing -> expectationFailure "Function should have docstring" Nothing -> expectationFailure "Function not found" it "does not treat f-prefixed strings as docstrings" $ do case lookup "function_with_f_prefix_docstring" docstrings of Just Nothing -> return () Just (Just _) -> expectationFailure "f-prefixed string should not be docstring" Nothing -> expectationFailure "Function not found" it "handles single quote docstrings" $ do case lookup "function_with_single_quotes" docstrings of Just (Just doc) -> doc `shouldContain` "Single quote" Just Nothing -> expectationFailure "Function should have docstring" Nothing -> expectationFailure "Function not found" it "handles triple single quote docstrings" $ do case lookup "function_with_triple_single_quotes" docstrings of Just (Just doc) -> doc `shouldContain` "Triple quote" Just Nothing -> expectationFailure "Function should have docstring" Nothing -> expectationFailure "Function not found" it "handles mixed quotes in docstrings" $ do case lookup "function_with_mixed_quotes" docstrings of Just (Just doc) -> doc `shouldContain` "Mixed 'quotes'" Just Nothing -> expectationFailure "Function should have docstring" Nothing -> expectationFailure "Function not found" it "does not interpolate docstrings" $ do case lookup "function_with_braces_docstring" docstrings of Just (Just doc) -> doc `shouldContain` "{braces}" Just Nothing -> expectationFailure "Function should have docstring" Nothing -> expectationFailure "Function not found" it "handles empty docstrings" $ do case lookup "function_empty_docstring" docstrings of Just (Just doc) -> doc `shouldBe` "" Just Nothing -> expectationFailure "Function should have empty docstring" Nothing -> expectationFailure "Function not found" it "ignores strings in control flow" $ do case lookup "function_with_control_flow" docstrings of Just Nothing -> return () -- Expected: no docstring Just (Just _) -> expectationFailure "String in control flow should not be docstring" Nothing -> expectationFailure "Function not found" it "handles functions with just docstrings" $ do case lookup "function_just_docstring" docstrings of Just (Just doc) -> doc `shouldContain` "Just a docstring" Just Nothing -> expectationFailure "Function should have docstring" Nothing -> expectationFailure "Function not found" -- Tests for uninitialized class attribute checking testAttributesInitialization :: Acton.Env.Env0 -> Spec testAttributesInitialization env0 = do describe "Class Attribute Initialization Check" $ do testTypeSuccess env0 "class_init_attrs/init_basic" testTypeSuccess env0 "class_init_attrs/init_inferred_only" testTypeError env0 "class_init_attrs/uninit_basic" testTypeError env0 "class_init_attrs/uninit_basic_inferred" testTypeSuccess env0 "class_init_attrs/init_multiple" testTypeError env0 "class_init_attrs/uninit_partial" testTypeSuccess env0 "class_init_attrs/init_inherited" testTypeError env0 "class_init_attrs/uninit_inherited" testTypeSuccess env0 "class_init_attrs/init_parent_call" testTypeSuccess env0 "class_init_attrs/init_mixed_parent_self" testTypeSuccess env0 "class_init_attrs/init_grandparent_call" testTypeError env0 "class_init_attrs/uninit_no_parent_init" testTypeError env0 "class_init_attrs/uninit_grandparent" testTypeError env0 "class_init_attrs/uninit_grandparent2" testTypeSuccess env0 "class_init_attrs/init_no_init_uses_parent" testTypeSuccess env0 "class_init_attrs/init_conditional" testTypeSuccess env0 "class_init_attrs/init_nested_if" testTypeSuccess env0 "class_init_attrs/init_nested_if_raise" testTypeError env0 "class_init_attrs/uninit_nested_if" testTypeError env0 "class_init_attrs/uninit_elif_missing" testTypeSuccess env0 "class_init_attrs/init_try_except" testTypeSuccess env0 "class_init_attrs/init_try_finally" testTypeSuccess env0 "class_init_attrs/init_try_except_finally" testTypeError env0 "class_init_attrs/uninit_try_except" testTypeSuccess env0 "class_init_attrs/init_try_except_raise" testTypeSuccess env0 "class_init_attrs/init_try_else_combined" testTypeSuccess env0 "class_init_attrs/init_multiple_except_handlers" testTypeSuccess env0 "class_init_attrs/init_except_raise_after_assignment" testTypeSuccess env0 "class_init_attrs/init_try_inside_if" testTypeSuccess env0 "class_init_attrs/init_constant_condition" testTypeSuccess env0 "class_init_attrs/init_raise_after_assignment" testTypeSuccess env0 "class_init_attrs/init_both_branches_with_raise" testTypeSuccess env0 "class_init_attrs/init_elif_raise_after_assignment" testTypeSuccess env0 "class_init_attrs/init_after_statements" testTypeSuccess env0 "class_init_attrs/init_self_attr_access" testTypeSuccess env0 "class_init_attrs/init_self_attr_in_expr" testTypeError env0 "class_init_attrs/uninit_self_attr_access" testTypeSuccess env0 "class_init_attrs/init_self_attr_conditional" testTypeSuccess env0 "class_init_attrs/init_self_attr_in_loop" testTypeError env0 "class_init_attrs/uninit_method_reference" testTypeSuccess env0 "class_init_attrs/init_function_call" testTypeSuccess env0 "class_init_attrs/init_nested_function_call" testTypeError env0 "class_init_attrs/uninit_method_call" testTypeError env0 "class_init_attrs/uninit_method_call_assign" testTypeSuccess env0 "class_init_attrs/init_actor" testTypeSuccess env0 "class_init_attrs/init_actor_call" testTypeSuccess env0 "class_init_attrs/init_notimplemented" testTypeSuccess env0 "class_init_attrs/init_notimpl_call" testTypeError env0 "class_init_attrs/uninit_notimpl_call_other" testTypeError env0 "class_init_attrs/uninit_augmented_assign" testTypeError env0 "class_init_attrs/uninit_for_loop" testTypeSuccess env0 "class_init_attrs/init_after_loop" testTypeSuccess env0 "class_init_attrs/init_after_while" testTypeError env0 "class_init_attrs/uninit_loop_references_self" testTypeError env0 "class_init_attrs/uninit_init_in_method" testTypeError env0 "class_init_attrs/uninit_return_early" testTypeError env0 "class_init_attrs/uninit_self_reference" testTypeSuccess env0 "class_init_attrs/init_self_attr_reference" testTypeError env0 "class_init_attrs/uninit_self_in_list" testTypeSuccess env0 "class_init_attrs/init_loop_break" testTypeSuccess env0 "class_init_attrs/init_loop_continue" testTypeSuccess env0 "class_init_attrs/init_assert" testTypeSuccess env0 "class_init_attrs/init_assert_with_self" testTypeError env0 "class_init_attrs/uninit_assert_uninit_attr" testTypeSuccess env0 "class_init_attrs/init_delete" testTypeSuccess env0 "class_init_attrs/init_nested_function" testTypeError env0 "class_init_attrs/uninit_nested_function_with_self" testTypeError env0 "class_init_attrs/uninit_nested_function_escape" -- Test a file that should produce a type error -- Path can be "testname" or "subdir/testname" testTypeError :: Acton.Env.Env0 -> String -> Spec testTypeError env0 path = do let (subdir, testname) = case break (=='/') path of (name, "") -> ("", name) (dir, '/':name) -> (dir, name) _ -> error $ "Invalid test path: " ++ path act_file = "test" "src" path ++ ".act" golden_file = "test" "3-types" path ++ ".golden" -- For error display, use just the basename like acton does display_file = testname ++ ".act" it testname $ do goldenTextFile golden_file $ liftIO $ do -- Read the source file for error formatting srcContent <- readFile act_file result <- E.try $ do (env, parsed) <- parseAct env0 path kchecked <- Acton.Kinds.check env parsed (nmod, tchecked, _, _) <- Acton.Types.reconstruct Nothing Nothing env kchecked -- Force evaluation to trigger any lazy exceptions E.evaluate $ length (show tchecked) return () case result of Left (e :: E.SomeException) -> do -- Format the error like acton does let diagnostic = case E.fromException e :: Maybe TypeError of Just typeErr -> -- Use the typeReport function to format all TypeError variants with richer diagnostics let report = typeReport typeErr display_file srcContent diag = addReport mempty report in addFile diag display_file srcContent _ -> case E.fromException e :: Maybe CompilationError of Just (IllegalSigOverride n) -> Diag.actErrToDiagnostic "Compilation error" display_file srcContent (loc n) ("Illegal signature override: " ++ prettyText n) Just (OtherError loc msg) -> Diag.actErrToDiagnostic "Compilation error" display_file srcContent loc msg Just compErr -> -- For other compilation errors, use the default show instance Diag.actErrToDiagnostic "Compilation error" display_file srcContent (loc compErr) (show compErr) _ -> -- For now, just use the default formatting for other errors let diagnostic = addReport mempty $ Err (Just "error") (show e) [] [] in addFile diagnostic display_file srcContent -- Pretty print the diagnostic return $ T.pack $ show $ unAnnotate (prettyDiagnostic WithoutUnicode (TabSize 4) diagnostic) Right _ -> return $ T.pack "ERROR: Expected type error but compilation succeeded" -- Test a file that should type check successfully -- Path can be "testname" or "subdir/testname" testTypeSuccess :: Acton.Env.Env0 -> String -> Spec testTypeSuccess env0 path = do let testname = takeBaseName path act_file = "test" "src" path ++ ".act" it testname $ do result <- E.try $ do (env, parsed) <- parseAct env0 path kchecked <- Acton.Kinds.check env parsed (nmod, tchecked, _, _) <- Acton.Types.reconstruct Nothing Nothing env kchecked -- Force evaluation to trigger any lazy exceptions E.evaluate $ length (show tchecked) return () case result of Left (e :: E.SomeException) -> expectationFailure $ "Expected success but got error: " ++ show e Right _ -> return () ================================================ FILE: compiler/lib/test/doc-golden/bar-color.txt ================================================ bar - Bar module - defines shared types and utilities This module provides common data structures and utilities that are used across the application. class Data(object) A data container with metadata This class holds arbitrary data along with metadata about when it was created and last modified. Examples: >>> d = Data("hello", "test-data") >>> d.get_value() "hello" Attributes: value: str label: str count: int Methods: __init__(self, value: str, label: str) Initialize data with value and label Args: value: The data value label: A descriptive label get_value(self) -> str Get the stored value Returns: The data value update(self, new_value: str) Update the value Args: new_value: New value to store Note: This increments the access count get_info(self) -> str Get formatted information about this data Returns: A string with label, value, and count class Container[T](object) A generic container that can hold items of any type This container maintains a list of items with various operations for manipulation and querying. Type Args: T: The type of items stored in the container Attributes: items: list[T] name: str Methods: __init__(self, name: str) Create an empty container Args: name: Container name for identification add(self, item: T) Add an item to the container Args: item: Item to add Raises: ValueError: If container is full get_all(self) -> list[T] Get all items Returns: List of all items in the container filter[U](self, predicate: (T) -> bool, transform: (T) -> U) -> list[U] Filter and transform items Args: predicate: Function to test each item transform: Function to transform matching items Returns: List of transformed items that match predicate Examples: >>> c = Container[int]("numbers") >>> c.add(1) >>> c.add(2) >>> c.filter(lambda x: x > 1, lambda x: str(x)) ["2"] count(self) -> int Get number of items in container Returns: Number of items process_data(d: bar.Data) -> str Process a data object and return summary Args: d: Data object to process Returns: Processed summary string See Also: Data.get_info: For detailed information combine_data(d1: bar.Data, d2: bar.Data) -> bar.Data Combine two data objects Args: d1: First data object d2: Second data object Returns: New Data object with combined values actor DataProcessor() Actor that processes Data objects This actor maintains a queue of data objects and processes them asynchronously. sum_counts[T](items: list[T]) -> T Sum a list of items that support addition Args: items: List of summable items Returns: Sum of all items Raises: ValueError: If list is empty protocol Processable[T] Protocol for objects that can be processed This protocol defines the interface for objects that can be processed and transformed into a result of type T. Type Args: T: The type of the processing result Methods: process: T validate: bool get_metadata: dict[str,str] extension Data(Processable[str]) Makes Data implement the Processable protocol This extension allows Data objects to be processed according to the Processable protocol, returning string results. process_items[T](items: list[A]) -> list[T] Process a list of processable items Args: items: List of items implementing Processable protocol Returns: List of processed results Examples: >>> d1 = Data("hello", "test") >>> d2 = Data("world", "test2") >>> results = process_items([d1, d2]) >>> results ["HELLO", "WORLD"] gt(a: A, b: A, c: B, d: B) -> (A, A, B) Function that takes generic types ================================================ FILE: compiler/lib/test/doc-golden/bar.html ================================================ bar

    bar - Bar module - defines shared types and utilities

    This module provides common data structures and utilities
    that are used across the application.

    class Data(object)

    A data container with metadata

    This class holds arbitrary data along with metadata
    about when it was created and last modified.

    Examples:
    >>> d = Data("hello", "test-data")
    >>> d.get_value()
    "hello"

    Attributes

    value: str
    label: str
    count: int

    Methods

    __init__(self, value: str, label: str)
    Initialize data with value and label

    Args:
    value: The data value
    label: A descriptive label
    get_value(self) → str
    Get the stored value

    Returns:
    The data value
    update(self, new_value: str)
    Update the value

    Args:
    new_value: New value to store

    Note:
    This increments the access count
    get_info(self) → str
    Get formatted information about this data

    Returns:
    A string with label, value, and count

    class Container[T](object)

    A generic container that can hold items of any type

    This container maintains a list of items with various
    operations for manipulation and querying.

    Type Args:
    T: The type of items stored in the container

    Attributes

    items: list[T]
    name: str

    Methods

    __init__(self, name: str)
    Create an empty container

    Args:
    name: Container name for identification
    add(self, item: T)
    Add an item to the container

    Args:
    item: Item to add

    Raises:
    ValueError: If container is full
    get_all(self) → list[T]
    Get all items

    Returns:
    List of all items in the container
    filter[U](self, predicate: (T) -> bool, transform: (T) -> U) → list[U]
    Filter and transform items

    Args:
    predicate: Function to test each item
    transform: Function to transform matching items

    Returns:
    List of transformed items that match predicate

    Examples:
    >>> c = Container[int]("numbers")
    >>> c.add(1)
    >>> c.add(2)
    >>> c.filter(lambda x: x > 1, lambda x: str(x))
    ["2"]
    count(self) → int
    Get number of items in container

    Returns:
    Number of items

    process_data(d: bar.Data) → str

    Process a data object and return summary

    Args:
    d: Data object to process

    Returns:
    Processed summary string

    See Also:
    Data.get_info: For detailed information

    combine_data(d1: bar.Data, d2: bar.Data) → bar.Data

    Combine two data objects

    Args:
    d1: First data object
    d2: Second data object

    Returns:
    New Data object with combined values

    actor DataProcessor()

    Actor that processes Data objects

    This actor maintains a queue of data objects
    and processes them asynchronously.

    Internal Attributes

    queue: list[Data]
    processed_count: int

    Methods

    enqueue(d: Data)
    Add data to processing queue

    Args:
    d: Data object to process
    process_next() → ?Data
    Process next item in queue

    Returns:
    Processed data or None if queue empty
    get_stats() → dict[str, int]
    Get processing statistics

    Returns:
    Dict with queue size and processed count

    sum_counts[T(Plus)] => (items: [T]) → T

    Sum a list of items that support addition

    Args:
    items: List of summable items

    Returns:
    Sum of all items

    Raises:
    ValueError: If list is empty

    protocol Processable[T]

    Protocol for objects that can be processed

    This protocol defines the interface for objects that
    can be processed and transformed into a result of type T.

    Type Args:
    T: The type of the processing result

    Required Methods

    process() → T
    validate() → bool
    get_metadata() → dict[str, str]

    extension Data(Processable[str])

    Makes Data implement the Processable protocol

    This extension allows Data objects to be processed
    according to the Processable protocol, returning
    string results.

    Methods

    process(self) → str
    Process data by converting to uppercase

    Returns:
    Uppercase version of the data value
    validate(self) → bool
    Check if data is non-empty

    Returns:
    True if data has content, False if empty
    get_metadata(self) → dict[str, str]
    Get data metadata

    Returns:
    Metadata including label and access count

    process_items[T, A(bar.Processable)] => (items: [A]) → [T]

    Process a list of processable items

    Args:
    items: List of items implementing Processable protocol

    Returns:
    List of processed results

    Examples:
    >>> d1 = Data("hello", "test")
    >>> d2 = Data("world", "test2")
    >>> results = process_items([d1, d2])
    >>> results
    ["HELLO", "WORLD"]

    gt[A(Minus, Plus), B(Plus)] => (a: A, b: A, c: B, d: B) → (A, A, B)

    Function that takes generic types
    ================================================ FILE: compiler/lib/test/doc-golden/bar.md ================================================ # `bar`: Bar module - defines shared types and utilities This module provides common data structures and utilities that are used across the application. ## *class* `Data`(object) A data container with metadata This class holds arbitrary data along with metadata about when it was created and last modified. Examples: >>> d = Data("hello", "test-data") >>> d.get_value() "hello" **Attributes:** - `value`: *str* - `label`: *str* - `count`: *int* **Methods:** - `__init__`(self, value: *str*, label: *str*) Initialize data with value and label Args: value: The data value label: A descriptive label - `get_value`(self) → *str* Get the stored value Returns: The data value - `update`(self, new_value: *str*) Update the value Args: new_value: New value to store Note: This increments the access count - `get_info`(self) → *str* Get formatted information about this data Returns: A string with label, value, and count ## *class* `Container`[T](object) A generic container that can hold items of any type This container maintains a list of items with various operations for manipulation and querying. Type Args: T: The type of items stored in the container **Attributes:** - `items`: *list[T]* - `name`: *str* **Methods:** - `__init__`(self, name: *str*) Create an empty container Args: name: Container name for identification - `add`(self, item: *T*) Add an item to the container Args: item: Item to add Raises: ValueError: If container is full - `get_all`(self) → *list[T]* Get all items Returns: List of all items in the container - `filter`[U](self, predicate: *(T) -> bool*, transform: *(T) -> U*) → *list[U]* Filter and transform items Args: predicate: Function to test each item transform: Function to transform matching items Returns: List of transformed items that match predicate Examples: >>> c = Container[int]("numbers") >>> c.add(1) >>> c.add(2) >>> c.filter(lambda x: x > 1, lambda x: str(x)) ["2"] - `count`(self) → *int* Get number of items in container Returns: Number of items ## `process_data`(d: *bar.Data*) → *str* Process a data object and return summary Args: d: Data object to process Returns: Processed summary string See Also: Data.get_info: For detailed information ## `combine_data`(d1: *bar.Data*, d2: *bar.Data*) → *bar.Data* Combine two data objects Args: d1: First data object d2: Second data object Returns: New Data object with combined values ## *actor* `DataProcessor`() Actor that processes Data objects This actor maintains a queue of data objects and processes them asynchronously. ## `sum_counts`[T(Plus)](items: *list[T]*) → *T* Sum a list of items that support addition Args: items: List of summable items Returns: Sum of all items Raises: ValueError: If list is empty ## *protocol* `Processable`[T] Protocol for objects that can be processed This protocol defines the interface for objects that can be processed and transformed into a result of type T. Type Args: T: The type of the processing result **Methods:** - `process`: *T* - `validate`: *bool* - `get_metadata`: *dict[str,str]* ## *extension* `Data`(Processable[str]) Makes Data implement the Processable protocol This extension allows Data objects to be processed according to the Processable protocol, returning string results. ## `process_items`[T](items: *list[A]*) → *list[T]* Process a list of processable items Args: items: List of items implementing Processable protocol Returns: List of processed results Examples: >>> d1 = Data("hello", "test") >>> d2 = Data("world", "test2") >>> results = process_items([d1, d2]) >>> results ["HELLO", "WORLD"] ## `gt`[A(__builtin__.Minus,__builtin__.Plus),B(__builtin__.Plus)](a: *A*, b: *A*, c: *B*, d: *B*) → *(A, A, B)* Function that takes generic types ================================================ FILE: compiler/lib/test/doc-golden/bar.txt ================================================ bar - Bar module - defines shared types and utilities This module provides common data structures and utilities that are used across the application. class Data(object) A data container with metadata This class holds arbitrary data along with metadata about when it was created and last modified. Examples: >>> d = Data("hello", "test-data") >>> d.get_value() "hello" Attributes: value: str label: str count: int Methods: __init__(self, value: str, label: str) Initialize data with value and label Args: value: The data value label: A descriptive label get_value(self) -> str Get the stored value Returns: The data value update(self, new_value: str) Update the value Args: new_value: New value to store Note: This increments the access count get_info(self) -> str Get formatted information about this data Returns: A string with label, value, and count class Container[T](object) A generic container that can hold items of any type This container maintains a list of items with various operations for manipulation and querying. Type Args: T: The type of items stored in the container Attributes: items: list[T] name: str Methods: __init__(self, name: str) Create an empty container Args: name: Container name for identification add(self, item: T) Add an item to the container Args: item: Item to add Raises: ValueError: If container is full get_all(self) -> list[T] Get all items Returns: List of all items in the container filter[U](self, predicate: (T) -> bool, transform: (T) -> U) -> list[U] Filter and transform items Args: predicate: Function to test each item transform: Function to transform matching items Returns: List of transformed items that match predicate Examples: >>> c = Container[int]("numbers") >>> c.add(1) >>> c.add(2) >>> c.filter(lambda x: x > 1, lambda x: str(x)) ["2"] count(self) -> int Get number of items in container Returns: Number of items process_data(d: bar.Data) -> str Process a data object and return summary Args: d: Data object to process Returns: Processed summary string See Also: Data.get_info: For detailed information combine_data(d1: bar.Data, d2: bar.Data) -> bar.Data Combine two data objects Args: d1: First data object d2: Second data object Returns: New Data object with combined values actor DataProcessor() Actor that processes Data objects This actor maintains a queue of data objects and processes them asynchronously. sum_counts[T](items: list[T]) -> T Sum a list of items that support addition Args: items: List of summable items Returns: Sum of all items Raises: ValueError: If list is empty protocol Processable[T] Protocol for objects that can be processed This protocol defines the interface for objects that can be processed and transformed into a result of type T. Type Args: T: The type of the processing result Methods: process: T validate: bool get_metadata: dict[str,str] extension Data(Processable[str]) Makes Data implement the Processable protocol This extension allows Data objects to be processed according to the Processable protocol, returning string results. process_items[T](items: list[A]) -> list[T] Process a list of processable items Args: items: List of items implementing Processable protocol Returns: List of processed results Examples: >>> d1 = Data("hello", "test") >>> d2 = Data("world", "test2") >>> results = process_items([d1, d2]) >>> results ["HELLO", "WORLD"] gt(a: A, b: A, c: B, d: B) -> (A, A, B) Function that takes generic types ================================================ FILE: compiler/lib/test/doc-golden/foo-color.txt ================================================ foo - Foo module - demonstrates cross-module type usage This module extensively uses types from the bar module to demonstrate documentation of cross-module references. create_data(value: str) -> bar.Data Create a new Data instance Args: value: Value for the data Returns: A new bar.Data instance with auto-generated label Examples: >>> d = create_data("test") >>> d.get_value() "test" transform_data(d: bar.Data, f: (str) -> str) -> bar.Data Transform data by applying function to its value Args: d: Data object to transform f: Transformation function Returns: New bar.Data with transformed value See Also: bar.process_data: For simple processing bar.combine_data: For combining multiple data objects analyze_multiple(data_list: list[bar.Data]) -> dict[str, int] Analyze multiple data objects Args: data_list: List of bar.Data objects Returns: Statistics about the data Raises: ValueError: If list is empty class DataManager(object) Manages a collection of bar.Data objects This class provides high-level operations on collections of Data objects from the bar module. Attributes: storage: list[bar.Data] default: bar.Data name: str Methods: __init__(self, name: str) Initialize manager Args: name: Name for this manager add_data(self, d: bar.Data) Add a data object to storage Args: d: bar.Data object to add Raises: ValueError: If storage is full find_by_label(self, label: str) -> ?bar.Data Find first data with matching label Args: label: Label to search for Returns: Matching bar.Data or None if not found get_or_default(self, label: str) -> bar.Data Get data by label or return default Args: label: Label to search for Returns: Found bar.Data or the default instance transform_all(self, f: (bar.Data) -> bar.Data) -> list[bar.Data] Transform all stored data Args: f: Transformation function Returns: List of transformed bar.Data objects process_with_prefix(d: bar.Data, prefix: str) -> bar.Data Process data with a prefix Args: d: Data to process prefix: Prefix to add to data values Returns: New bar.Data with prefixed value actor DataHandler(initial: bar.Data) Actor that handles bar.Data objects Args: initial: Initial bar.Data to store apply_transformation(d: bar.Data, transform: (str) -> str) -> bar.Data Apply transformation to bar.Data value Args: d: Data to transform transform: Function to apply to value Returns: New bar.Data with transformed value apply_to_list(items: list[bar.Data], f: (bar.Data) -> str) -> list[str] Apply function to all items in list Args: items: List of bar.Data objects f: Function to apply Returns: List of results process_nested(data: list[(str, bar.Data)]) -> dict[str, list[bar.Data]] Process nested data structures Args: data: List of tuples containing keys and bar.Data Returns: Dictionary grouping bar.Data by key actor main(env: Env) Main actor demonstrating bar module usage ================================================ FILE: compiler/lib/test/doc-golden/foo.html ================================================ foo

    foo - Foo module - demonstrates cross-module type usage

    This module extensively uses types from the bar module
    to demonstrate documentation of cross-module references.

    create_data(value: str) → bar.Data

    Create a new Data instance

    Args:
    value: Value for the data

    Returns:
    A new bar.Data instance with auto-generated label

    Examples:
    >>> d = create_data("test")
    >>> d.get_value()
    "test"

    transform_data(d: bar.Data, f: (str) -> str) → bar.Data

    Transform data by applying function to its value

    Args:
    d: Data object to transform
    f: Transformation function

    Returns:
    New bar.Data with transformed value

    See Also:
    bar.process_data: For simple processing
    bar.combine_data: For combining multiple data objects

    analyze_multiple(data_list: [bar.Data]) → {str: int}

    Analyze multiple data objects

    Args:
    data_list: List of bar.Data objects

    Returns:
    Statistics about the data

    Raises:
    ValueError: If list is empty

    class DataManager(object)

    Manages a collection of bar.Data objects

    This class provides high-level operations on collections
    of Data objects from the bar module.

    Attributes

    storage: list[bar.Data]
    default: bar.Data
    name: str

    Methods

    __init__(self, name: str)
    Initialize manager

    Args:
    name: Name for this manager
    add_data(self, d: bar.Data)
    Add a data object to storage

    Args:
    d: bar.Data object to add

    Raises:
    ValueError: If storage is full
    find_by_label(self, label: str) → ?bar.Data
    Find first data with matching label

    Args:
    label: Label to search for

    Returns:
    Matching bar.Data or None if not found
    get_or_default(self, label: str) → bar.Data
    Get data by label or return default

    Args:
    label: Label to search for

    Returns:
    Found bar.Data or the default instance
    transform_all(self, f: (bar.Data) -> bar.Data) → list[bar.Data]
    Transform all stored data

    Args:
    f: Transformation function

    Returns:
    List of transformed bar.Data objects

    process_with_prefix(d: bar.Data, prefix: str) → bar.Data

    Process data with a prefix

    Args:
    d: Data to process
    prefix: Prefix to add to data values

    Returns:
    New bar.Data with prefixed value

    actor DataHandler(initial: bar.Data)

    Actor that handles bar.Data objects

    Args:
    initial: Initial bar.Data to store

    Internal Attributes

    current: bar.Data
    history: list[bar.Data]
    processor: ?bar.DataProcessor

    Methods

    update(new_data: bar.Data)
    Update current data

    Args:
    new_data: New bar.Data to set as current
    get_current() → bar.Data
    Get current data

    Returns:
    Current bar.Data instance
    transform_with(f: (bar.Data) -> bar.Data) → bar.Data
    Transform current data

    Args:
    f: Transformation function

    Returns:
    Transformed bar.Data
    combine_with(other: bar.Data) → bar.Data
    Combine current with another data

    Args:
    other: bar.Data to combine with

    Returns:
    Combined bar.Data using bar.combine_data
    send_to_processor(p: bar.DataProcessor)
    Send current data to a processor

    Args:
    p: bar.DataProcessor to send to
    get_history() → list[bar.Data]
    Get full history of data

    Returns:
    List of all bar.Data objects in history

    apply_transformation(d: bar.Data, transform: (str) -> str) → bar.Data

    Apply transformation to bar.Data value

    Args:
    d: Data to transform
    transform: Function to apply to value

    Returns:
    New bar.Data with transformed value

    apply_to_list(items: [bar.Data], f: (bar.Data) -> str) → [str]

    Apply function to all items in list

    Args:
    items: List of bar.Data objects
    f: Function to apply

    Returns:
    List of results

    process_nested(data: [(str, bar.Data)]) → {str: [bar.Data]}

    Process nested data structures

    Args:
    data: List of tuples containing keys and bar.Data

    Returns:
    Dictionary grouping bar.Data by key

    actor main(env: Env)

    Main actor demonstrating bar module usage

    Public Constants

    d1
    d2
    d3
    data_list
    long_values
    manager
    found
    handler
    processor
    processed
    transformed
    items
    grouped
    processed_results
    meta
    ================================================ FILE: compiler/lib/test/doc-golden/foo.md ================================================ # `foo`: Foo module - demonstrates cross-module type usage This module extensively uses types from the bar module to demonstrate documentation of cross-module references. ## `create_data`(value: *str*) → *bar.Data* Create a new Data instance Args: value: Value for the data Returns: A new bar.Data instance with auto-generated label Examples: >>> d = create_data("test") >>> d.get_value() "test" ## `transform_data`(d: *bar.Data*, f: *(str) -> str*) → *bar.Data* Transform data by applying function to its value Args: d: Data object to transform f: Transformation function Returns: New bar.Data with transformed value See Also: bar.process_data: For simple processing bar.combine_data: For combining multiple data objects ## `analyze_multiple`(data_list: *list[bar.Data]*) → *dict[str, int]* Analyze multiple data objects Args: data_list: List of bar.Data objects Returns: Statistics about the data Raises: ValueError: If list is empty ## *class* `DataManager`(object) Manages a collection of bar.Data objects This class provides high-level operations on collections of Data objects from the bar module. **Attributes:** - `storage`: *list[bar.Data]* - `default`: *bar.Data* - `name`: *str* **Methods:** - `__init__`(self, name: *str*) Initialize manager Args: name: Name for this manager - `add_data`(self, d: *bar.Data*) Add a data object to storage Args: d: bar.Data object to add Raises: ValueError: If storage is full - `find_by_label`(self, label: *str*) → *?bar.Data* Find first data with matching label Args: label: Label to search for Returns: Matching bar.Data or None if not found - `get_or_default`(self, label: *str*) → *bar.Data* Get data by label or return default Args: label: Label to search for Returns: Found bar.Data or the default instance - `transform_all`(self, f: *(bar.Data) -> bar.Data*) → *list[bar.Data]* Transform all stored data Args: f: Transformation function Returns: List of transformed bar.Data objects ## `process_with_prefix`(d: *bar.Data*, prefix: *str*) → *bar.Data* Process data with a prefix Args: d: Data to process prefix: Prefix to add to data values Returns: New bar.Data with prefixed value ## *actor* `DataHandler`(initial: *bar.Data*) Actor that handles bar.Data objects Args: initial: Initial bar.Data to store ## `apply_transformation`(d: *bar.Data*, transform: *(str) -> str*) → *bar.Data* Apply transformation to bar.Data value Args: d: Data to transform transform: Function to apply to value Returns: New bar.Data with transformed value ## `apply_to_list`(items: *list[bar.Data]*, f: *(bar.Data) -> str*) → *list[str]* Apply function to all items in list Args: items: List of bar.Data objects f: Function to apply Returns: List of results ## `process_nested`(data: *list[(str, bar.Data)]*) → *dict[str, list[bar.Data]]* Process nested data structures Args: data: List of tuples containing keys and bar.Data Returns: Dictionary grouping bar.Data by key ## *actor* `main`(env) Main actor demonstrating bar module usage ================================================ FILE: compiler/lib/test/doc-golden/foo.txt ================================================ foo - Foo module - demonstrates cross-module type usage This module extensively uses types from the bar module to demonstrate documentation of cross-module references. create_data(value: str) -> bar.Data Create a new Data instance Args: value: Value for the data Returns: A new bar.Data instance with auto-generated label Examples: >>> d = create_data("test") >>> d.get_value() "test" transform_data(d: bar.Data, f: (str) -> str) -> bar.Data Transform data by applying function to its value Args: d: Data object to transform f: Transformation function Returns: New bar.Data with transformed value See Also: bar.process_data: For simple processing bar.combine_data: For combining multiple data objects analyze_multiple(data_list: list[bar.Data]) -> dict[str, int] Analyze multiple data objects Args: data_list: List of bar.Data objects Returns: Statistics about the data Raises: ValueError: If list is empty class DataManager(object) Manages a collection of bar.Data objects This class provides high-level operations on collections of Data objects from the bar module. Attributes: storage: list[bar.Data] default: bar.Data name: str Methods: __init__(self, name: str) Initialize manager Args: name: Name for this manager add_data(self, d: bar.Data) Add a data object to storage Args: d: bar.Data object to add Raises: ValueError: If storage is full find_by_label(self, label: str) -> ?bar.Data Find first data with matching label Args: label: Label to search for Returns: Matching bar.Data or None if not found get_or_default(self, label: str) -> bar.Data Get data by label or return default Args: label: Label to search for Returns: Found bar.Data or the default instance transform_all(self, f: (bar.Data) -> bar.Data) -> list[bar.Data] Transform all stored data Args: f: Transformation function Returns: List of transformed bar.Data objects process_with_prefix(d: bar.Data, prefix: str) -> bar.Data Process data with a prefix Args: d: Data to process prefix: Prefix to add to data values Returns: New bar.Data with prefixed value actor DataHandler(initial: bar.Data) Actor that handles bar.Data objects Args: initial: Initial bar.Data to store apply_transformation(d: bar.Data, transform: (str) -> str) -> bar.Data Apply transformation to bar.Data value Args: d: Data to transform transform: Function to apply to value Returns: New bar.Data with transformed value apply_to_list(items: list[bar.Data], f: (bar.Data) -> str) -> list[str] Apply function to all items in list Args: items: List of bar.Data objects f: Function to apply Returns: List of results process_nested(data: list[(str, bar.Data)]) -> dict[str, list[bar.Data]] Process nested data structures Args: data: List of tuples containing keys and bar.Data Returns: Dictionary grouping bar.Data by key actor main(env: Env) Main actor demonstrating bar module usage ================================================ FILE: compiler/lib/test/parser_golden/alternating_quotes_error.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@1:17-1:18 │ 1 │ "a {'b {"c {'d {e'}"}'}" • ┬ • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/deep_nesting_error.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:23-1:24 │ 1 │ "a {"b {"c {"d {"e {f:@}"}"}"}"}"}" • ┬ • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/error_at_end.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@1:10-1:11 │ 1 │ "at end {x • ┬ • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/error_at_start.golden ================================================ ERROR: [error Parse error]: unexpected "at" expecting ';', call arguments, slice/index expression, comma, end of line, if clause, or operator ╭──▶ test@1:5-1:6 │ 1 │ {x} at start • ┬ • ╰╸ unexpected "at" • expecting ';', call arguments, slice/index expression, comma, end of line, if clause, or operator • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/error_in_middle.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:11-1:12 │ 1 │ "start {x:@} end" • ┬ • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/escaped_brace_error.golden ================================================ PARSED: "outer {broken %s" % str(x) ================================================ FILE: compiler/lib/test/parser_golden/fstring_empty_expression.golden ================================================ ERROR: [error Syntax error]: Empty expression in string interpolation ╭──▶ test@1:21-1:21 │ 1 │ f"Empty expression {}" • • ╰╸ Empty expression in string interpolation • │ Hint: Add an expression between the braces, e.g. {name} ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/fstring_empty_format_specifier.golden ================================================ ERROR: [error Syntax error]: Empty format specifier after ':' ╭──▶ test@1:24-1:24 │ 1 │ f"Empty format spec {x:}" • • ╰╸ Empty format specifier after ':' • │ Hint: Add a format specification or remove the colon ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/fstring_invalid_alignment.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:9-1:10 │ 1 │ f"{name:@10}" • ┬ • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/fstring_invalid_format.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:34-1:35 │ 1 │ f"Invalid format specifier {name:@Z}" • ┬ • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/fstring_missing_expression.golden ================================================ ERROR: [error Syntax error]: Missing expression before format specifier ╭──▶ test@1:23-1:23 │ 1 │ f"Missing expression {:10}" • • ╰╸ Missing expression before format specifier • │ Hint: Add an expression before the colon, e.g. {value:10} ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/fstring_missing_precision_digits_error.golden ================================================ ERROR: [error Syntax error]: Expected digits after '.' in format specifier ╭──▶ test@1:38-1:38 │ 1 │ f"Missing precision digits {value:10.}" • • ╰╸ Expected digits after '.' in format specifier • │ Hint: Add precision digits, e.g. .2f for 2 decimal places ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/fstring_triple_double_6quotes.golden ================================================ ERROR: [error Syntax error]: Too many quote characters ╭──▶ test@1:10-1:16 │ 1 │ f"""x={x}"""""" • ┬───── • ╰╸ Too many quote characters • │ Note: Triple-quoted strings accept 3-5 quotes at the end │ Hint: Using 4 quotes results in a string with 1 quote at the end, e.g. """text"""" -> text" │ Hint: Using 5 quotes results in a string with 2 quotes at the end, e.g. """text""""" -> text"" │ Hint: Use escape sequences for quotes inside strings, e.g. """text \"with quotes\""" -> text "with quotes" ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/fstring_triple_single_6quotes.golden ================================================ ERROR: [error Syntax error]: Too many quote characters ╭──▶ test@1:10-1:16 │ 1 │ f'''x={x}'''''' • ┬───── • ╰╸ Too many quote characters • │ Note: Triple-quoted strings accept 3-5 quotes at the end │ Hint: Using 4 quotes results in a string with 1 quote at the end, e.g. """text"""" -> text" │ Hint: Using 5 quotes results in a string with 2 quotes at the end, e.g. """text""""" -> text"" │ Hint: Use escape sequences for quotes inside strings, e.g. """text \"with quotes\""" -> text "with quotes" ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/fstring_unbalanced_format.golden ================================================ ERROR: [error Syntax error]: Empty format specifier after ':' ╭──▶ test@1:27-1:27 │ 1 │ f"Unbalanced format {name:}:10}" • • ╰╸ Empty format specifier after ':' • │ Hint: Add a format specification or remove the colon ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/fstring_unclosed_brace.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@1:20-1:24 │ 1 │ f"Unclosed brace: {name • ┬─── • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/hex_incomplete_in_interpolation.golden ================================================ ERROR: [error Syntax error]: Incomplete hex character ╭──▶ test@1:20-1:21 │ 1 │ f"value: {x} and \x4" • ┬ • ╰╸ Incomplete hex character • │ Note: Hex-escaped characters must be specified by two hexadecimal digits │ Hint: Use two characters, e.g. \x9a ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/hex_incomplete_no_digits.golden ================================================ ERROR: [error Syntax error]: Incomplete hex character ╭──▶ test@1:4-1:4 │ 1 │ "\x" • • ╰╸ Incomplete hex character • │ Note: Hex-escaped characters must be specified by two hexadecimal digits │ Hint: Use two characters, e.g. \x9a ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/hex_incomplete_one_digit.golden ================================================ ERROR: [error Syntax error]: Incomplete hex character ╭──▶ test@1:4-1:5 │ 1 │ "\x4" • ┬ • ╰╸ Incomplete hex character • │ Note: Hex-escaped characters must be specified by two hexadecimal digits │ Hint: Use two characters, e.g. \x9a ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/hex_invalid_char.golden ================================================ ERROR: [error Syntax error]: Incomplete hex character ╭──▶ test@1:4-1:5 │ 1 │ "\xAG" • ┬ • ╰╸ Incomplete hex character • │ Note: Hex-escaped characters must be specified by two hexadecimal digits │ Hint: Use two characters, e.g. \x9a ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/invalid_after_align.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:15-1:15 │ 1 │ "value: {x:>10@}" • • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/invalid_after_precision.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:16-1:16 │ 1 │ "value: {x:10.2@}" • • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/invalid_after_width.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:14-1:14 │ 1 │ "value: {x:10@}" • • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/invalid_in_type_spec.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:16-1:16 │ 1 │ "value: {x:10.2@f}" • • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/mixed_quotes_unclosed.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@1:17-1:18 │ 1 │ "outer {'inner {x • ┬ • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/mixed_six_quotes_double.golden ================================================ ERROR: [error Parse error]: unexpected "mi" expecting """"", "'''", '"', ''', ';', call arguments, slice/index expression, comma, end of line, if clause, or operator ╭──▶ test.act@1:11-1:12 │ 1 │ a = """"""mixed content with {interpolation}"""""" • ┬ • ╰╸ unexpected "mi" • expecting """"", "'''", '"', ''', ';', call arguments, slice/index expression, comma, end of line, if clause, or operator • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/module_actor_before_import.golden ================================================ ERROR: [error Parse error]: unexpected 'i' expecting "@static", "@staticmethod", "action", "actor", "class", "def", "extension", "mut", "proc", "protocol", "pure", '_', end of input, end of line, or statement ╭──▶ test.act@3:1-3:2 │ 3 │ import math • ┬ • ╰╸ unexpected 'i' • expecting "@static", "@staticmethod", "action", "actor", "class", "def", "extension", "mut", "proc", "protocol", "pure", '_', end of input, end of line, or statement • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/module_call_before_import.golden ================================================ ERROR: [error Syntax error]: Only declarations and assignments are allowed at the module top level ╭──▶ test.act@1:1-1:15 │ 1 │ print("hello") • ┬───────────── • ╰╸ Only declarations and assignments are allowed at the module top level • │ Hint: Assign the value to a name or move runtime work into an actor or function ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/module_class_before_import.golden ================================================ ERROR: [error Parse error]: unexpected 'i' expecting "@static", "@staticmethod", "action", "actor", "class", "def", "extension", "mut", "proc", "protocol", "pure", '_', end of input, end of line, or statement ╭──▶ test.act@3:1-3:2 │ 3 │ import math • ┬ • ╰╸ unexpected 'i' • expecting "@static", "@staticmethod", "action", "actor", "class", "def", "extension", "mut", "proc", "protocol", "pure", '_', end of input, end of line, or statement • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/module_dict_before_import.golden ================================================ ERROR: [error Syntax error]: Only declarations and assignments are allowed at the module top level ╭──▶ test.act@1:1-1:17 │ 1 │ {"key": "value"} • ┬─────────────── • ╰╸ Only declarations and assignments are allowed at the module top level • │ Hint: Assign the value to a name or move runtime work into an actor or function ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/module_for_before_import.golden ================================================ ERROR: [error Syntax error]: Only declarations and assignments are allowed at the module top level ╭──▶ test.act@1:1-1:1 │ 1 │ for i in range(10): • • ╰╸ Only declarations and assignments are allowed at the module top level • │ Hint: Assign the value to a name or move runtime work into an actor or function ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/module_func_before_import.golden ================================================ ERROR: [error Parse error]: unexpected 'i' expecting "@static", "@staticmethod", "action", "actor", "class", "def", "extension", "mut", "proc", "protocol", "pure", '_', end of input, end of line, or statement ╭──▶ test.act@3:1-3:2 │ 3 │ import math • ┬ • ╰╸ unexpected 'i' • expecting "@static", "@staticmethod", "action", "actor", "class", "def", "extension", "mut", "proc", "protocol", "pure", '_', end of input, end of line, or statement • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/module_if_before_import.golden ================================================ ERROR: [error Syntax error]: Only declarations and assignments are allowed at the module top level ╭──▶ test.act@1:1-1:1 │ 1 │ if True: • • ╰╸ Only declarations and assignments are allowed at the module top level • │ Hint: Assign the value to a name or move runtime work into an actor or function ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/module_list_before_import.golden ================================================ ERROR: [error Syntax error]: Only declarations and assignments are allowed at the module top level ╭──▶ test.act@1:1-1:10 │ 1 │ [1, 2, 3] • ┬──────── • ╰╸ Only declarations and assignments are allowed at the module top level • │ Hint: Assign the value to a name or move runtime work into an actor or function ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/module_number_before_import.golden ================================================ ERROR: [error Syntax error]: Only declarations and assignments are allowed at the module top level ╭──▶ test.act@1:1-1:3 │ 1 │ 42 • ┬─ • ╰╸ Only declarations and assignments are allowed at the module top level • │ Hint: Assign the value to a name or move runtime work into an actor or function ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/module_var_before_import.golden ================================================ ERROR: [error Parse error]: unexpected 'i' expecting end of input, end of line, or statement ╭──▶ test.act@2:1-2:2 │ 2 │ import math • ┬ • ╰╸ unexpected 'i' • expecting end of input, end of line, or statement • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/multiline_format_error.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@2:11-2:12 │ 2 │ Value: {x:@invalid} • ┬ • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/multiline_nested_error.golden ================================================ ERROR: [error Syntax error]: Missing closing " ╭──▶ test@2:2-2:8 │ 2 │ {"inner • ┬───── • ╰╸ Missing closing " • │ Hint: Add a closing quote (") to match the opening one ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/multiline_unclosed.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@2:9-2:10 │ 2 │ Line 2 {x • ┬ • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/nested_bad_type_spec.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:20-1:20 │ 1 │ "outer {"inner {x:5@}"}" • • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/nested_empty_format.golden ================================================ ERROR: [error Syntax error]: Empty format specifier after ':' ╭──▶ test@1:19-1:19 │ 1 │ "outer {"inner {x:}"}" • • ╰╸ Empty format specifier after ':' • │ Hint: Add a format specification or remove the colon ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/nested_empty_inner.golden ================================================ ERROR: [error Syntax error]: Empty expression in string interpolation ╭──▶ test@1:17-1:17 │ 1 │ "outer {"inner {}"}" • • ╰╸ Empty expression in string interpolation • │ Hint: Add an expression between the braces, e.g. {name} ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/nested_invalid_align.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:19-1:20 │ 1 │ "outer {"inner {x:@5}"}" • ┬ • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/nested_invalid_format.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:19-1:20 │ 1 │ "outer {"inner {x:@10}"}" • ┬ • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/nested_unclosed_inner.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@1:9-1:20 │ 1 │ "outer {"inner {x}" • ┬────────── • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/nested_unclosed_outer.golden ================================================ ERROR: [error Syntax error]: Missing closing " ╭──▶ test@1:9-1:15 │ 1 │ "outer {"inner • ┬───── • ╰╸ Missing closing " • │ Hint: Add a closing quote (") to match the opening one ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/newline_in_expr.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@1:10-1:11 │ 1 │ "value: {x • ┬ • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/octal_invalid_char.golden ================================================ PARSED: "\\12G" ================================================ FILE: compiler/lib/test/parser_golden/octal_invalid_first_digit.golden ================================================ ERROR: [error Syntax error]: Unknown escape sequence ╭──▶ test@1:4-1:4 │ 1 │ "\8" • • ╰╸ Unknown escape sequence • │ Note: Valid escape sequences: \\, \", \', \n, \r, \t, \a, \b, \f, \v, \xHH, \ooo, \uHHHH, \UHHHHHHHH ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/octal_out_of_range.golden ================================================ ERROR: [error Syntax error]: Octal escape sequence out of range ╭──▶ test@1:3-1:6 │ 1 │ "\777" • ┬── • ╰╸ Octal escape sequence out of range • │ Note: Octal values must be between \000 and \377 ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/octal_out_of_range_in_fstring.golden ================================================ ERROR: [error Syntax error]: Octal escape sequence out of range ╭──▶ test@1:15-1:18 │ 1 │ f"value: {x} \777" • ┬── • ╰╸ Octal escape sequence out of range • │ Note: Octal values must be between \000 and \377 ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/raw_six_quotes.golden ================================================ ERROR: [error Parse error]: unexpected "ra" expecting "r"", "r"""", "r'", "r'''", ';', call arguments, slice/index expression, comma, end of line, if clause, or operator ╭──▶ test.act@1:12-1:13 │ 1 │ a = r""""""raw test"""""" • ┬ • ╰╸ unexpected "ra" • expecting "r"", "r"""", "r'", "r'''", ';', call arguments, slice/index expression, comma, end of line, if clause, or operator • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/raw_triple_double_6quotes.golden ================================================ ERROR: [error Parse error]: unexpected """" expecting "r"", "r"""", "r'", "r'''", ';', call arguments, slice/index expression, comma, end of line, if clause, or operator ╭──▶ test@1:11-1:12 │ 1 │ r"""raw"""""" • ┬ • ╰╸ unexpected """" • expecting "r"", "r"""", "r'", "r'''", ';', call arguments, slice/index expression, comma, end of line, if clause, or operator • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/raw_triple_single_6quotes.golden ================================================ ERROR: [error Parse error]: unexpected "''" expecting "r"", "r"""", "r'", "r'''", ';', call arguments, slice/index expression, comma, end of line, if clause, or operator ╭──▶ test@1:11-1:12 │ 1 │ r'''raw'''''' • ┬ • ╰╸ unexpected "''" • expecting "r"", "r"""", "r'", "r'''", ';', call arguments, slice/index expression, comma, end of line, if clause, or operator • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/seven_double_quotes.golden ================================================ ERROR: [error Parse error]: unexpected "te" expecting """"", "'''", '"', ''', ';', call arguments, slice/index expression, comma, end of line, if clause, or operator ╭──▶ test.act@1:12-1:13 │ 1 │ a = """""""test""""""" • ┬ • ╰╸ unexpected "te" • expecting """"", "'''", '"', ''', ';', call arguments, slice/index expression, comma, end of line, if clause, or operator • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/six_double_quotes.golden ================================================ ERROR: [error Parse error]: unexpected "te" expecting """"", "'''", '"', ''', ';', call arguments, slice/index expression, comma, end of line, if clause, or operator ╭──▶ test.act@1:11-1:12 │ 1 │ a = """"""test"""""" • ┬ • ╰╸ unexpected "te" • expecting """"", "'''", '"', ''', ';', call arguments, slice/index expression, comma, end of line, if clause, or operator • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/six_single_quotes.golden ================================================ ERROR: [error Parse error]: unexpected "te" expecting """"", "'''", '"', ''', ';', call arguments, slice/index expression, comma, end of line, if clause, or operator ╭──▶ test.act@1:11-1:12 │ 1 │ a = ''''''test'''''' • ┬ • ╰╸ unexpected "te" • expecting """"", "'''", '"', ''', ';', call arguments, slice/index expression, comma, end of line, if clause, or operator • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/slice_format_error.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:19-1:20 │ 1 │ "slice: {arr[1:3]:@10}" • ┬ • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/slice_invalid_step.golden ================================================ ERROR: [error Parse error]: missing closing " ╭──▶ test@1:9-1:10 │ 1 │ "slice: {arr[:::" • ┬ • ╰╸ missing closing " • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/slice_missing_bracket.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@1:10-1:14 │ 1 │ "slice: {arr 1:3]}" • ┬─── • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/slice_nested_error.golden ================================================ ERROR: [error Parse error]: missing closing " ╭──▶ test@1:8-1:9 │ 1 │ "outer {arr[inner[}" • ┬ • ╰╸ missing closing " • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/slice_unclosed_bracket.golden ================================================ ERROR: [error Parse error]: missing closing " ╭──▶ test@1:9-1:10 │ 1 │ "slice: {arr[1:3" • ┬ • ╰╸ missing closing " • ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/string_empty_expression.golden ================================================ ERROR: [error Syntax error]: Empty expression in string interpolation ╭──▶ test@1:20-1:20 │ 1 │ "Empty expression {}" • • ╰╸ Empty expression in string interpolation • │ Hint: Add an expression between the braces, e.g. {name} ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/string_invalid_format.golden ================================================ ERROR: [error Syntax error]: Invalid character '@' in format specifier ╭──▶ test@1:8-1:9 │ 1 │ "{name:@Z}" • ┬ • ╰╸ Invalid character '@' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/string_missing_expression.golden ================================================ ERROR: [error Syntax error]: Missing expression before format specifier ╭──▶ test@1:22-1:22 │ 1 │ "Missing expression {:10}" • • ╰╸ Missing expression before format specifier • │ Hint: Add an expression before the colon, e.g. {value:10} ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/string_unclosed_brace.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@1:19-1:23 │ 1 │ "Unclosed brace: {name • ┬─── • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/tab_in_format.golden ================================================ ERROR: [error Syntax error]: Tab character not allowed in format specifier ╭──▶ test@1:12-1:17 │ 1 │ "value: {x: 10}" • ┬─────── • ╰╸ Tab character not allowed in format specifier ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/triple_double_10quotes.golden ================================================ ERROR: [error Syntax error]: Too many quote characters ╭──▶ test@1:11-1:21 │ 1 │ """content"""""""""" • ┬───────── • ╰╸ Too many quote characters • │ Note: Triple-quoted strings accept 3-5 quotes at the end │ Hint: Using 4 quotes results in a string with 1 quote at the end, e.g. """text"""" -> text" │ Hint: Using 5 quotes results in a string with 2 quotes at the end, e.g. """text""""" -> text"" │ Hint: Use escape sequences for quotes inside strings, e.g. """text \"with quotes\""" -> text "with quotes" ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/triple_double_6quotes.golden ================================================ ERROR: [error Syntax error]: Too many quote characters ╭──▶ test@1:7-1:13 │ 1 │ """foo"""""" • ┬───── • ╰╸ Too many quote characters • │ Note: Triple-quoted strings accept 3-5 quotes at the end │ Hint: Using 4 quotes results in a string with 1 quote at the end, e.g. """text"""" -> text" │ Hint: Using 5 quotes results in a string with 2 quotes at the end, e.g. """text""""" -> text"" │ Hint: Use escape sequences for quotes inside strings, e.g. """text \"with quotes\""" -> text "with quotes" ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/triple_double_7quotes.golden ================================================ ERROR: [error Syntax error]: Too many quote characters ╭──▶ test@1:7-1:14 │ 1 │ """bar""""""" • ┬────── • ╰╸ Too many quote characters • │ Note: Triple-quoted strings accept 3-5 quotes at the end │ Hint: Using 4 quotes results in a string with 1 quote at the end, e.g. """text"""" -> text" │ Hint: Using 5 quotes results in a string with 2 quotes at the end, e.g. """text""""" -> text"" │ Hint: Use escape sequences for quotes inside strings, e.g. """text \"with quotes\""" -> text "with quotes" ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/triple_double_8quotes.golden ================================================ ERROR: [error Syntax error]: Too many quote characters ╭──▶ test@1:8-1:16 │ 1 │ """test"""""""" • ┬─────── • ╰╸ Too many quote characters • │ Note: Triple-quoted strings accept 3-5 quotes at the end │ Hint: Using 4 quotes results in a string with 1 quote at the end, e.g. """text"""" -> text" │ Hint: Using 5 quotes results in a string with 2 quotes at the end, e.g. """text""""" -> text"" │ Hint: Use escape sequences for quotes inside strings, e.g. """text \"with quotes\""" -> text "with quotes" ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/triple_nested_unclosed.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@1:28-1:29 │ 1 │ "level1 {"level2 {"level3 {x • ┬ • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/triple_single_10quotes.golden ================================================ ERROR: [error Syntax error]: Too many quote characters ╭──▶ test@1:11-1:21 │ 1 │ '''content'''''''''' • ┬───────── • ╰╸ Too many quote characters • │ Note: Triple-quoted strings accept 3-5 quotes at the end │ Hint: Using 4 quotes results in a string with 1 quote at the end, e.g. """text"""" -> text" │ Hint: Using 5 quotes results in a string with 2 quotes at the end, e.g. """text""""" -> text"" │ Hint: Use escape sequences for quotes inside strings, e.g. """text \"with quotes\""" -> text "with quotes" ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/triple_single_6quotes.golden ================================================ ERROR: [error Syntax error]: Too many quote characters ╭──▶ test@1:7-1:13 │ 1 │ '''foo'''''' • ┬───── • ╰╸ Too many quote characters • │ Note: Triple-quoted strings accept 3-5 quotes at the end │ Hint: Using 4 quotes results in a string with 1 quote at the end, e.g. """text"""" -> text" │ Hint: Using 5 quotes results in a string with 2 quotes at the end, e.g. """text""""" -> text"" │ Hint: Use escape sequences for quotes inside strings, e.g. """text \"with quotes\""" -> text "with quotes" ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/triple_single_7quotes.golden ================================================ ERROR: [error Syntax error]: Too many quote characters ╭──▶ test@1:7-1:14 │ 1 │ '''bar''''''' • ┬────── • ╰╸ Too many quote characters • │ Note: Triple-quoted strings accept 3-5 quotes at the end │ Hint: Using 4 quotes results in a string with 1 quote at the end, e.g. """text"""" -> text" │ Hint: Using 5 quotes results in a string with 2 quotes at the end, e.g. """text""""" -> text"" │ Hint: Use escape sequences for quotes inside strings, e.g. """text \"with quotes\""" -> text "with quotes" ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/triple_single_8quotes.golden ================================================ ERROR: [error Syntax error]: Too many quote characters ╭──▶ test@1:8-1:16 │ 1 │ '''test'''''''' • ┬─────── • ╰╸ Too many quote characters • │ Note: Triple-quoted strings accept 3-5 quotes at the end │ Hint: Using 4 quotes results in a string with 1 quote at the end, e.g. """text"""" -> text" │ Hint: Using 5 quotes results in a string with 2 quotes at the end, e.g. """text""""" -> text"" │ Hint: Use escape sequences for quotes inside strings, e.g. """text \"with quotes\""" -> text "with quotes" ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/tristring_unclosed_brace.golden ================================================ ERROR: [error Syntax error]: Missing closing '}' for expression ╭──▶ test@1:21-1:25 │ 1 │ """Unclosed brace: {name • ┬─── • ╰╸ Missing closing '}' for expression • │ Hint: Add a closing brace to complete the interpolation ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unclosed_bytes_string.golden ================================================ ERROR: [error Syntax error]: Missing closing " ╭──▶ test.act@1:6-1:12 │ 1 │ a = b"hello • ┬───── • ╰╸ Missing closing " • │ Hint: Add a closing quote (") to match the opening one ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unclosed_bytes_string_single.golden ================================================ ERROR: [error Syntax error]: Missing closing ' ╭──▶ test.act@1:6-1:12 │ 1 │ a = b'hello • ┬───── • ╰╸ Missing closing ' • │ Hint: Add a closing quote (') to match the opening one ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unclosed_raw_bytes_string.golden ================================================ ERROR: [error Syntax error]: Missing closing " ╭──▶ test.act@1:7-1:13 │ 1 │ a = rb"hello • ┬───── • ╰╸ Missing closing " • │ Hint: Add a closing quote (") to match the opening one ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unclosed_raw_bytes_string_single.golden ================================================ ERROR: [error Syntax error]: Missing closing ' ╭──▶ test.act@1:7-1:13 │ 1 │ a = rb'hello • ┬───── • ╰╸ Missing closing ' • │ Hint: Add a closing quote (') to match the opening one ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unclosed_raw_string.golden ================================================ ERROR: [error Syntax error]: Missing closing " ╭──▶ test.act@1:6-1:12 │ 1 │ a = r"hello • ┬───── • ╰╸ Missing closing " • │ Hint: Add a closing quote (") to match the opening one ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unclosed_raw_string_single.golden ================================================ ERROR: [error Syntax error]: Missing closing ' ╭──▶ test.act@1:6-1:12 │ 1 │ a = r'hello • ┬───── • ╰╸ Missing closing ' • │ Hint: Add a closing quote (') to match the opening one ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unclosed_string.golden ================================================ ERROR: [error Syntax error]: Missing closing " ╭──▶ test.act@1:5-1:11 │ 1 │ a = "hello • ┬───── • ╰╸ Missing closing " • │ Hint: Add a closing quote (") to match the opening one ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unclosed_string_triple.golden ================================================ ERROR: [error Syntax error]: Missing closing """ ╭──▶ test.act@2:2-2:5 │ 2 │ a = """hello • ┬── • ╰╸ Missing closing """ • │ Hint: Add a closing quote (""") to match the opening one ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unicode_format_error.golden ================================================ ERROR: [error Syntax error]: Invalid character '你' in format specifier ╭──▶ test@1:11-1:12 │ 1 │ "你好 {name:你}" • ┬─ • ╰╸ Invalid character '你' in format specifier • │ Note: Valid format specifiers use <, >, ^, +, -, #, 0, width, .precision, and type characters │ Hint: Use a format specifier, e.g. '{name:<18}' ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unicode_long_in_fstring.golden ================================================ ERROR: [error Syntax error]: Incomplete universal character name ╭──▶ test@1:11-1:18 │ 1 │ f"Hello \U1234567" • ┬────── • ╰╸ Incomplete universal character name • │ Note: Expected 8 hex digits, found 7 ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unicode_long_incomplete.golden ================================================ ERROR: [error Syntax error]: Incomplete universal character name ╭──▶ test@1:4-1:11 │ 1 │ "\U1234567" • ┬────── • ╰╸ Incomplete universal character name • │ Note: Expected 8 hex digits, found 7 ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unicode_long_invalid_char.golden ================================================ ERROR: [error Syntax error]: Incomplete universal character name ╭──▶ test@1:4-1:11 │ 1 │ "\U1234567G" • ┬────── • ╰╸ Incomplete universal character name • │ Note: Expected 8 hex digits, found 7 ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unicode_long_no_digits.golden ================================================ ERROR: [error Syntax error]: Incomplete universal character name ╭──▶ test@1:4-1:4 │ 1 │ "\U" • • ╰╸ Incomplete universal character name • │ Note: Expected 8 hex digits, found 0 ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unicode_short_in_fstring.golden ================================================ ERROR: [error Syntax error]: Incomplete universal character name ╭──▶ test@1:11-1:14 │ 1 │ f"Hello \u123" • ┬── • ╰╸ Incomplete universal character name • │ Note: Expected 4 hex digits, found 3 ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unicode_short_incomplete.golden ================================================ ERROR: [error Syntax error]: Incomplete universal character name ╭──▶ test@1:4-1:7 │ 1 │ "\u123" • ┬── • ╰╸ Incomplete universal character name • │ Note: Expected 4 hex digits, found 3 ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unicode_short_invalid_char.golden ================================================ ERROR: [error Syntax error]: Incomplete universal character name ╭──▶ test@1:4-1:7 │ 1 │ "\u123G" • ┬── • ╰╸ Incomplete universal character name • │ Note: Expected 4 hex digits, found 3 ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unicode_short_no_digits.golden ================================================ ERROR: [error Syntax error]: Incomplete universal character name ╭──▶ test@1:4-1:4 │ 1 │ "\u" • • ╰╸ Incomplete universal character name • │ Note: Expected 4 hex digits, found 0 ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unknown_escape_in_fstring.golden ================================================ ERROR: [error Syntax error]: Unknown escape sequence ╭──▶ test@1:14-1:14 │ 1 │ f"unknown: \q" • • ╰╸ Unknown escape sequence • │ Note: Valid escape sequences: \\, \", \', \n, \r, \t, \a, \b, \f, \v, \xHH, \ooo, \uHHHH, \UHHHHHHHH ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unknown_escape_p.golden ================================================ ERROR: [error Syntax error]: Unknown escape sequence ╭──▶ test@1:4-1:4 │ 1 │ "\p" • • ╰╸ Unknown escape sequence • │ Note: Valid escape sequences: \\, \", \', \n, \r, \t, \a, \b, \f, \v, \xHH, \ooo, \uHHHH, \UHHHHHHHH ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unknown_escape_with_interpolation.golden ================================================ ERROR: [error Syntax error]: Unknown escape sequence ╭──▶ test@1:16-1:16 │ 1 │ f"value: {x} \k" • • ╰╸ Unknown escape sequence • │ Note: Valid escape sequences: \\, \", \', \n, \r, \t, \a, \b, \f, \v, \xHH, \ooo, \uHHHH, \UHHHHHHHH ─────╯ ================================================ FILE: compiler/lib/test/parser_golden/unknown_escape_z.golden ================================================ ERROR: [error Syntax error]: Unknown escape sequence ╭──▶ test@1:4-1:4 │ 1 │ "\z" • • ╰╸ Unknown escape sequence • │ Note: Valid escape sequences: \\, \", \', \n, \r, \t, \a, \b, \f, \v, \xHH, \ooo, \uHHHH, \UHHHHHHHH ─────╯ ================================================ FILE: compiler/lib/test/src/bar.act ================================================ """Bar module - defines shared types and utilities This module provides common data structures and utilities that are used across the application. """ # Module constants VERSION: str = "1.0.0" # Current version of the bar module MAX_ITEMS: int = 1000 # Maximum number of items allowed in a container # Basic data class class Data(object): """A data container with metadata This class holds arbitrary data along with metadata about when it was created and last modified. Examples: >>> d = Data("hello", "test-data") >>> d.get_value() "hello" """ value: str label: str count: int def __init__(self, value: str, label: str): """Initialize data with value and label Args: value: The data value label: A descriptive label """ self.value = value self.label = label self.count = 0 def get_value(self) -> str: """Get the stored value Returns: The data value """ self.count += 1 return self.value def update(self, new_value: str): """Update the value Args: new_value: New value to store Note: This increments the access count """ self.value = new_value self.count += 1 def get_info(self) -> str: """Get formatted information about this data Returns: A string with label, value, and count """ return f"{self.label}: {self.value} (accessed {self.count} times)" # Generic container class Container[T](object): """A generic container that can hold items of any type This container maintains a list of items with various operations for manipulation and querying. Type Args: T: The type of items stored in the container """ items: list[T] name: str def __init__(self, name: str): """Create an empty container Args: name: Container name for identification """ self.items = [] self.name = name def add(self, item: T): """Add an item to the container Args: item: Item to add Raises: ValueError: If container is full """ if len(self.items) >= MAX_ITEMS: raise ValueError("Container is full") self.items.append(item) def get_all(self) -> list[T]: """Get all items Returns: List of all items in the container """ return self.items def filter[U](self, predicate: (T) -> bool, transform: (T) -> U) -> list[U]: """Filter and transform items Args: predicate: Function to test each item transform: Function to transform matching items Returns: List of transformed items that match predicate Examples: >>> c = Container[int]("numbers") >>> c.add(1) >>> c.add(2) >>> c.filter(lambda x: x > 1, lambda x: str(x)) ["2"] """ result = [] for item in self.items: if predicate(item): result.append(transform(item)) return result def count(self) -> int: """Get number of items in container Returns: Number of items """ return len(self.items) # Utility functions def process_data(d: Data) -> str: """Process a data object and return summary Args: d: Data object to process Returns: Processed summary string See Also: Data.get_info: For detailed information """ return f"Processed: {d.get_value()}" def combine_data(d1: Data, d2: Data) -> Data: """Combine two data objects Args: d1: First data object d2: Second data object Returns: New Data object with combined values """ combined_value = d1.value + " + " + d2.value combined_label = f"{d1.label}/{d2.label}" return Data(combined_value, combined_label) # Actor that works with Data actor DataProcessor(): """Actor that processes Data objects This actor maintains a queue of data objects and processes them asynchronously. """ var queue: list[Data] = [] var processed_count: int = 0 def enqueue(d: Data): """Add data to processing queue Args: d: Data object to process """ queue.append(d) def process_next() -> ?Data: """Process next item in queue Returns: Processed data or None if queue empty """ if len(queue) > 0: d = queue[0] queue = queue[1:] processed_count += 1 # Simulate processing d.update(d.value.upper()) return d return None def get_stats() -> dict[str, int]: """Get processing statistics Returns: Dict with queue size and processed count """ return { "queued": len(queue), "processed": processed_count } # Type constraint for documentation def sum_counts[T(Plus)](items: list[T]) -> T: """Sum a list of items that support addition Args: items: List of summable items Returns: Sum of all items Raises: ValueError: If list is empty """ if len(items) == 0: raise ValueError("Cannot sum empty list") result = items[0] for i in range(1, len(items)): result = result + items[i] return result # Protocol definition protocol Processable[T]: """Protocol for objects that can be processed This protocol defines the interface for objects that can be processed and transformed into a result of type T. Type Args: T: The type of the processing result """ process : () -> T validate : () -> bool get_metadata : () -> dict[str, str] # Extension to make Data implement Processable extension Data(Processable[str]): """Makes Data implement the Processable protocol This extension allows Data objects to be processed according to the Processable protocol, returning string results. """ def process(self) -> str: """Process data by converting to uppercase Returns: Uppercase version of the data value """ return self.value.upper() def validate(self) -> bool: """Check if data is non-empty Returns: True if data has content, False if empty """ return len(self.value) > 0 def get_metadata(self) -> dict[str, str]: """Get data metadata Returns: Metadata including label and access count """ return { "label": self.label, "access_count": str(self.count), "length": str(len(self.value)) } # Function that uses the protocol def process_items[T](items: list[Processable[T]]) -> list[T]: """Process a list of processable items Args: items: List of items implementing Processable protocol Returns: List of processed results Examples: >>> d1 = Data("hello", "test") >>> d2 = Data("world", "test2") >>> results = process_items([d1, d2]) >>> results ["HELLO", "WORLD"] """ results = [] for item in items: if item.validate(): results.append(item.process()) return results def gt(a, b, c, d): """Function that takes generic types""" return (a + b, a - b, c + d) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_actor.act ================================================ actor Act(): def foo(): return 1 class TestClass(object): x: int y: int def __init__(self): self.x = 1 a = Act() self.y = a.foo() actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_actor_call.act ================================================ actor Act(): def foo(): return 1 class TestClass(object): x: int y: int def __init__(self, a): self.x = 1 self.y = a.foo() actor main(env): a = Act() t = TestClass(a) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_after_loop.act ================================================ # Test case: Assignments after a loop that doesn't reference self class TestClass(object): x: int y: int def __init__(self): # Loop that doesn't reference self - safe to continue past it for i in range(10): print(i) # These assignments happen after the loop self.x = 1 self.y = 2 def range(n: int) -> list[int]: return [] def print(x: int) -> None: pass actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_after_statements.act ================================================ class TestClass(object): x: int def __init__(self): print("hello") pass self.x = 1 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_after_while.act ================================================ # Test case: Assignments after a while loop that doesn't reference self class TestClass(object): x: int y: int def __init__(self): count = 0 # While loop that doesn't reference self while count < 5: count = count + 1 # These assignments happen after the loop self.x = 1 self.y = 2 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_assert.act ================================================ # Test case: assert statement shouldn't stop initialization scanning class TestClass(object): value: int result: int def __init__(self, x: int): self.value = x # Assert shouldn't stop scanning if it doesn't reference self assert x > 0, "x must be positive" # This should still be recognized as part of constructor self.result = self.value * 2 actor main(env): t = TestClass(5) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_assert_with_self.act ================================================ # Test case: assert that references self should stop initialization scanning class TestClass(object): value: int result: int def __init__(self, x: int): self.value = x # Assert that references self should stop scanning assert self.value > 0, "value must be positive" # This won't be recognized as initialized (self escaped in assert) self.result = 42 actor main(env): t = TestClass(5) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_basic.act ================================================ class TestClass(object): x: int def __init__(self): self.x = 1 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_both_branches_with_raise.act ================================================ # Test case: both branches initialize, but one raises after # This SHOULD be valid - if branch initializes and completes normally class TestClass(object): x: int def __init__(self): condition = True if condition: self.x = 1 else: self.x = 2 raise ValueError("After assignment") actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_conditional.act ================================================ class TestClass(object): x: int def __init__(self, cond: bool=True): self.x = 1 if cond else 0 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_constant_condition.act ================================================ # Test case: if/else with constant condition - both branches initialize class TestClass(object): x: int def __init__(self): if 1 == 1: # Always true, but compiler doesn't know self.x = 1 else: self.x = 2 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_delete.act ================================================ # Test case: delete statement shouldn't stop initialization scanning class TestClass(object): items: list[int] temp: dict[str, int] result: int def __init__(self): self.items = [1, 2, 3, 4, 5] self.temp = {"a": 1, "b": 2} del self.temp["a"] # Deleting dict item is OK # This should still be recognized as part of constructor self.result = len(self.items) def len(x: list[int]) -> int: NotImplemented actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_elif_raise_after_assignment.act ================================================ # Test case: elif branch assigns then raises - should succeed # The if and else branches complete normally with x initialized class TestClass(object): x: int def __init__(self, mode: int): if mode == 1: self.x = 1 elif mode == 2: raise ValueError("After assignment in elif") else: self.x = 3 # Paths: if={x}, elif exits, else={x} # Result: {x} actor main(env): t = TestClass(1) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_except_raise_after_assignment.act ================================================ # Test case: except handler assigns then raises - should succeed # The try path completes normally with x initialized class TestClass(object): x: int def __init__(self): try: self.x = 1 might_raise() except ValueError: self.x = 2 raise Exception("After assignment in except") # Paths: try={x}, except exits after assigning # Only try path returns object, and it initializes x def might_raise() -> None: pass actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_function_call.act ================================================ # Test case: function calls should be allowed in __init__ def compute_value(x: int) -> int: return x * 2 + 10 class TestClass(object): x: int y: int z: int def __init__(self, base: int): # Call to function should be allowed self.x = 3 + compute_value(compute_value(base)) result = compute_value(5) self.y = result # Multiple calls self.z = compute_value(self.x) + compute_value(self.y) actor main(env): t = TestClass(10) print(t.x) # Should be 30 print(t.y) # Should be 20 print(t.z) # Should be 80 env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_grandparent_call.act ================================================ class BaseA: x: int def __init__(self): self.x = 1 class BaseB(BaseA): y: int class TestClass(BaseB): def __init__(self): BaseA.__init__(self) self.y = 1 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_inferred_only.act ================================================ class TestClass(object): def __init__(self): self.x = 1 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_inherited.act ================================================ class Base(object): x: int class TestClass(Base): def __init__(self): self.x = 1 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_loop_break.act ================================================ # Test case: break statement in loop shouldn't stop initialization scanning class TestClass(object): values: list[int] result: int def __init__(self): self.values = [] # Loop with break shouldn't stop scanning for i in range(10): if i > 5: break # This should NOT stop constructor scanning self.values.append(i) # This should still be recognized as part of constructor self.result = len(self.values) def range(n: int) -> list[int]: NotImplemented def len(x: list[int]) -> int: NotImplemented actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_loop_continue.act ================================================ # Test case: continue statement in loop shouldn't stop initialization scanning class TestClass(object): skipped: list[int] processed: list[int] total: int def __init__(self): self.skipped = [] self.processed = [] # Loop with continue shouldn't stop scanning for i in range(10): if i % 2 == 0: self.skipped.append(i) continue # This should NOT stop constructor scanning self.processed.append(i) # This should still be recognized as part of constructor self.total = len(self.processed) + len(self.skipped) def range(n: int) -> list[int]: NotImplemented def len(x: list[int]) -> int: NotImplemented actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_mixed_parent_self.act ================================================ class Base: x: int def __init__(self): self.x = 1 class Derived(Base): y: int def __init__(self): Base.__init__(self) self.y = 2 d = Derived() ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_multiple.act ================================================ class TestClass(object): x: int y: str def __init__(self): self.x = 1 self.y = 'hello' actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_multiple_except_handlers.act ================================================ class TestClass(object): x: int def __init__(self): try: self.x = 1 might_raise() # Could raise ValueError or Exception except ValueError: self.x = 2 # Handler 1 initializes x except Exception: self.x = 3 # Handler 2 also initializes x # All paths (try, handler1, handler2) initialize x def might_raise() -> None: pass actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_nested_function.act ================================================ # Test case: nested function declarations shouldn't stop initialization class TestClass(object): value: int result: int def __init__(self, x: int): self.value = x # Nested function declaration shouldn't stop scanning def helper(n: int) -> int: return n * 2 # This should still be recognized as part of constructor self.result = helper(self.value) actor main(env): t = TestClass(5) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_nested_function_call.act ================================================ # Test case: function calls should be allowed in __init__ class TestClass(object): x: int y: int z: int def __init__(self, base: int): def compute_value(x: int) -> int: return x * 2 + 10 # Call to function should be allowed self.x = 3 + compute_value(compute_value(base)) # expressions are fine result = compute_value(5) self.y = result # Multiple calls self.z = compute_value(self.x) + compute_value(self.y) actor main(env): t = TestClass(10) print(t.x) # Should be 30 print(t.y) # Should be 20 print(t.z) # Should be 80 env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_nested_if.act ================================================ # Test case: Nested if statements with all branches initializing attributes class TestClass(object): x: int y: int z: int def __init__(self, mode: int, submode: int): # Complex nested if/elif/else where all paths initialize all attributes if mode == 1: if submode > 0: self.x = 10 self.y = 20 self.z = 30 else: self.x = 11 self.y = 21 self.z = 31 elif mode == 2: self.x = 100 if submode == 0: self.y = 200 self.z = 300 elif submode == 1: self.y = 201 self.z = 301 else: self.y = 202 self.z = 302 else: # Default case self.x = 0 self.y = 0 self.z = 0 actor main(env): t = TestClass(1, 5) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_nested_if_raise.act ================================================ class Rational(object): def __init__(self, num: int, denom: int): if denom == 0: raise ValueError("Denominator in rational is zero") else: if denom > 0: self.num = num self.denom = denom else: self.num = -num self.denom = -denom actor main(env): r = Rational(1, 2) print("Rational created:", r.num, "/", r.denom) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_no_init_uses_parent.act ================================================ class Base: x: int def __init__(self): self.x = 1 class TestClass(Base): pass actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_notimpl_call.act ================================================ # Test case: Calling self methods with NotImplemented body is allowed class TestClass(object): x: int y: int def __init__(self): # Calling a NotImplemented method on self should be allowed since it's # implemented in C and thus trusted to do the right thing. self.setup() self.x = 1 self.y = 2 def setup(self): NotImplemented actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_notimplemented.act ================================================ class TestClass(object): x: int def __init__(self): NotImplemented actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_parent_call.act ================================================ class Base: x: int def __init__(self): self.x = 1 class TestClass(Base): def __init__(self): Base.__init__(self) actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_raise_after_assignment.act ================================================ # Test case: if/else where else branch has assignment followed by raise # This should SUCCEED - the if branch completes normally with x initialized, # and the else branch exits early (so it doesn't constrain initialization) class TestClass(object): x: int def __init__(self): if 1 == 1: # Always true self.x = 1 else: self.x = 2 raise ValueError("This comes after assignment") actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_self_attr_access.act ================================================ # Test case: Accessing already-initialized attributes should be allowed class TestClass(object): x: int y: int z: int def __init__(self): self.x = 10 self.y = self.x * 2 # OK: x is already initialized self.z = self.x + self.y # OK: both x and y are initialized actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_self_attr_conditional.act ================================================ # Test case: Using initialized attributes in conditional branches class TestClass(object): base: int value: int doubled: int def __init__(self, mode: int): self.base = 10 if mode > 0: self.value = self.base * mode # OK: base is initialized else: self.value = self.base # OK: base is initialized # At this point, both base and value are guaranteed initialized self.doubled = self.value * 2 # OK: value is initialized from all paths actor main(env): t = TestClass(5) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_self_attr_in_expr.act ================================================ # Test case: Using initialized attributes in complex expressions class TestClass(object): items: list[int] total: int average: float description: str def __init__(self): self.items = [1, 2, 3, 4, 5] self.total = sum(self.items) # OK: items is initialized self.average = float(self.total) / float(len(self.items)) # OK: total and items initialized self.description = "Average is: " + str(self.average) # OK: average is initialized def sum(items: list[int]) -> int: total = 0 for i in items: total = total + i return total def float(x: int) -> float: NotImplemented def len(items: list[int]) -> int: NotImplemented actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_self_attr_in_loop.act ================================================ # Test case: Using initialized attribute in a loop class TestClass(object): multiplier: int values: list[int] def __init__(self): self.multiplier = 2 self.values = [] # Loop that uses initialized attribute for i in range(5): self.values.append(i * self.multiplier) # OK: multiplier is initialized def range(n: int) -> list[int]: NotImplemented actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_self_attr_reference.act ================================================ # Test case: References to self.attr should be allowed when attr is initialized def compute(x: int) -> int: return x * 2 + 10 class TestClass(object): x: int y: int z: int w: int def __init__(self): # Initialize x first self.x = 5 # This should be allowed - self.x is already initialized self.y = compute(self.x) # Multiple references to initialized attributes self.z = self.x + self.y # Even in complex expressions self.w = compute(self.x) + compute(self.y) + self.z actor main(env): t = TestClass() print(t.x) # 5 print(t.y) # 20 print(t.z) # 25 print(t.w) # 65 env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_try_else_combined.act ================================================ # Test case: try/else where all paths initialize everything class TestClass(object): x: int y: int def __init__(self): try: # This doesn't raise, so we continue to else self.x = safe_operation() except ValueError: # Exception path: initialize both self.x = 1 self.y = 2 else: # No exception path: continues from try # x is already set in try, now set y self.y = 3 # Both paths initialize x and y! # Path 1 (no exception): try sets x, else sets y # Path 2 (exception): except sets both x and y def safe_operation() -> int: return 42 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_try_except.act ================================================ class TestClass(object): x: int y: int def __init__(self): try: self.x = risky_operation() self.y = 2 except: self.x = 1 self.y = 2 def risky_operation() -> int: return 42 actor main(env): t = TestClass() print("x =", t.x, "y =", t.y) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_try_except_finally.act ================================================ # Test case: Complex try/except/finally with mixed initialization class TestClass(object): a: int b: int c: int d: int e: int def __init__(self, mode: int): # Initialize before try self.a = 1 try: if mode > 0: self.b = 10 self.c = risky_op(mode) else: self.b = 11 self.c = 12 except: # Exception handler must also init b and c self.b = 0 self.c = 0 finally: # Finally always runs self.d = 100 # After try/finally self.e = self.a + self.b + self.c + self.d def risky_op(x: int) -> int: if x > 100: raise ValueError("Too big!") return x * 2 actor main(env): t1 = TestClass(5) print("Normal:", t1.a, t1.b, t1.c, t1.d, t1.e) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_try_except_raise.act ================================================ # Test case: Try-except blocks class TestClass(object): x: int y: int def __init__(self): try: self.x = risky_operation() self.y = 1 except ValueError: # We're catching all errors and throwing our own. This will raise an # error, so y will not be initialized but that's OK since we are # terminating and not returning an object. raise ValueError("An error occurred") def risky_operation() -> int: return 42 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_try_finally.act ================================================ # Test case: Finally block always executes so assignments there count class TestClass(object): x: int y: int def __init__(self): try: self.x = risky_operation() self.y = 1 finally: self.x = 1 self.y = 2 def risky_operation() -> int: return 42 actor main(env): t = TestClass() print("x =", t.x, "y =", t.y) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/init_try_inside_if.act ================================================ # Test case: try/except nested inside if/else class TestClass(object): x: int def __init__(self, mode: int): if mode > 0: try: self.x = 1 might_raise() except: self.x = 2 else: self.x = 3 # All paths through if/else initialize x def might_raise() -> None: pass actor main(env): t = TestClass(1) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_assert_uninit_attr.act ================================================ # Test case: assert that references uninitialized attribute should fail class TestClass(object): value: int result: int def __init__(self, x: int): self.value = x # Assert that references uninitialized self.result - should fail! assert self.result > 0, "result must be positive" # This should NOT be recognized as initialized self.result = 42 actor main(env): t = TestClass(5) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_augmented_assign.act ================================================ class TestClass(object): x: int def __init__(self): self.x += 1 # Should fail - x not initialized before augmented assignment ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_basic.act ================================================ class TestClass(object): x: int def __init__(self): pass actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_basic_inferred.act ================================================ class TestClass(object): def __init__(self): if False: self.x = 1 # Should fail - x not initialized before use actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_elif_missing.act ================================================ # Test case: if-elif without else class TestClass(object): x: int def __init__(self, mode: int): if mode == 1: self.x = 1 elif mode == 2: self.x = 2 # No else - x not initialized for other values actor main(env): env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_for_loop.act ================================================ # Test case: Break/continue in loops affecting initialization class TestClass(object): x: int y: int def __init__(self, items: list[int]): self.x = 1 for item in items: if item == 0: break self.y = item # Might not execute if we break early or items is empty actor main(env): t = TestClass([1, 2, 0, 3]) # y will be set to 2 env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_grandparent.act ================================================ class BaseA: x: int class BaseB(BaseA): y: int class TestClass(BaseB): def __init__(self): self.y = 1 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_grandparent2.act ================================================ class BaseA: x: int def __init__(self): self.x = 1 class BaseB(BaseA): y: int def __init__(self): BaseA.__init__(self) self.y = 1 class TestClass(BaseB): def __init__(self): BaseA.__init__(self) # Should get a failure since y is not initialized actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_inherited.act ================================================ class Base: x: int class TestClass(Base): def __init__(self): pass actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_init_in_method.act ================================================ # Test case: Initialization in another method called from __init__ # Should fail because we don't allow calling any methods in init constructor class TestClass(object): x: int def __init__(self): self.setup() def setup(self): self.x = 1 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_loop_references_self.act ================================================ # Test case: Loop that references self - must stop scanning class TestClass(object): x: int y: int def __init__(self): # Loop that references self - not safe to continue for i in range(10): process(self) # Leaks self reference! # These assignments are after the loop but we can't reach them # because the loop leaked self self.x = 1 self.y = 2 def range(n: int) -> list[int]: return [] def process(obj: TestClass) -> None: pass actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_method_call.act ================================================ # Test case: Method calls on self should stop scanning. We are in the # constructor, so `self` is not initialized yet and we can't track down what the # method is doing exactly. class TestClass(object): x: int y: int counter: int def __init__(self): self.counter = 0 self.x = 1 self.helper() # Method call on self - scanner should stop here self.y = 2 # Not reached by scanner mut def helper(self): self.counter += 1 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_method_call_assign.act ================================================ # Test case: Method calls on self should stop scanning. We are in the # constructor, so `self` is not initialized yet, the method has access to self, # but we can't track what it is doing exactly. # We *could* potentially allow pure methods... class TestClass(object): pi: int x: int y: int counter: int def __init__(self): self.counter = 0 self.x = 1 self.pi = self.pure_helper() self.y = 2 # Not reached by scanner def pure_helper(self): return 3.14 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_method_reference.act ================================================ # Test case: Passing self.method as argument should stop initialization scanning # This should fails - self._on_event is a bound method that captures self, so # it's considered a leak of self class Callback(object): def __init__(self, callback): pass class TestClass(object): handler: Callback value: int def __init__(self): # This should work - we're just passing a method reference # But currently the compiler sees self._on_event as leaking self self.handler = Callback(self._on_event) self.value = 42 # This won't be seen as initialized def _on_event(self): pass actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_nested_function_escape.act ================================================ # Test case: nested function that captures uninitialized self attributes class TestClass(object): value: int result: int def __init__(self, x: int): self.value = x # Nested function that captures self with uninitialized attribute def get_result() -> int: return self.result # References uninitialized self.result! # Pass the function externally (self escapes via closure) register(get_result) # This won't be recognized as initialized (self escaped) self.result = 42 def register(f: () -> int): pass actor main(env): t = TestClass(5) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_nested_function_with_self.act ================================================ # Test case: nested function that captures self stops initialization scanning class TestClass(object): value: int result: int def __init__(self, x: int): self.value = x # Nested function that captures self - stops scanning def get_value() -> int: return self.value # References self (even though value is initialized) # The nested function captured self, so we conservatively stop scanning # This will NOT be seen as initialized self.result = 42 actor main(env): t = TestClass(5) env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_nested_if.act ================================================ # Test case: Nested if statements class TestClass(object): x: int y: int def __init__(self, a: bool, b: bool): if a: if b: self.x = 1 self.y = 1 else: self.x = 2 # Missing y in this path else: self.x = 3 self.y = 3 actor main(env): env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_no_parent_init.act ================================================ class Base: x: int class TestClass(Base): def __init__(self): Base.__init__(self) actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_notimpl_call_other.act ================================================ # Test case: Calling self methods with NotImplemented body is allowed but here # we also call .setup2() which is implemented here and it is NOT allowed, thus # we expect an error about self.y not being initialized. class TestClass(object): x: int y: int def __init__(self): # Calling a NotImplemented method on self should be allowed since it's # implemented in C and thus trusted to do the right thing. self.setup() self.x = 1 self.setup2() self.y = 2 def setup(self): NotImplemented def setup2(self): pass actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_partial.act ================================================ class TestClass(object): x: int y: str def __init__(self): self.x = 1 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_return_early.act ================================================ # Test case: Early return doesn't excuse initialization class TestClass(object): x: int y: int def __init__(self, quick_exit: bool): if quick_exit: self.x = 0 return # Early return - but y is still uninitialized! else: self.x = 1 self.y = 2 actor main(env): env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_self_attr_access.act ================================================ # Test case: Accessing uninitialized attribute should fail class TestClass(object): x: int y: int def __init__(self): self.x = self.y * 2 # ERROR: y is not initialized yet! self.y = 10 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_self_in_list.act ================================================ # Test case: Self references in data structures should stop scanning def do_something(l): return 1 class TestClass(object): x: int y: int def __init__(self): self.x = 1 # Direct reference to self - stop scanning here # We don't actually know if objects how objects is used or if it even is # used, but that is untractable to analyze, so we stop analyzing at any # point where self is referenced. objects = [self, self] # This won't be scanned, so y will be considered uninitialized self.y = do_something(objects) actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_self_reference.act ================================================ # Test case: Direct references to self should stop scanning # This ensures we don't pass incomplete objects around def external_func(obj): # This function might access obj which is not fully initialized when this # function is called return obj.x * 2 class TestClass(object): x: int y: int z: int def __init__(self): self.x = 1 # This should stop scanning because we're passing self result = external_func(self) # These won't be scanned, so z will be reported as uninitialized self.y = result self.z = 3 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/class_init_attrs/uninit_try_except.act ================================================ # Test case: Try-except blocks class TestClass(object): x: int y: int def __init__(self): try: self.x = risky_operation() self.y = 1 except: self.x = 0 # y not initialized in except block def risky_operation() -> int: return 42 actor main(env): t = TestClass() env.exit(0) ================================================ FILE: compiler/lib/test/src/cps_andor.act ================================================ proc def p() -> bool: return True def f(b: bool) -> bool: return b and p() def g(b: bool) -> bool: return b or p() ================================================ FILE: compiler/lib/test/src/cps_optchain.act ================================================ class Cls: proc def f(self, msg: str): pass def maybe_log(c: ?Cls): c?.f("boom") ================================================ FILE: compiler/lib/test/src/cps_volatiles.act ================================================ proc def force_cps(arg: int): return arg def compute(aa: int) -> int: xx = 1 try: xx += force_cps(1) aa += force_cps(1) except ValueError: pass return xx + aa actor main(env): v = compute(10) if v == 13: env.exit(0) else: print('Excpected 13, got', v) env.exit(1) ================================================ FILE: compiler/lib/test/src/deact.act ================================================ actor Apa(): def setup(cb): print("setup") cb(0) def compute(cb): print("compute") v = cb(1) m = async cb(2) return v*10 def notice(i): print("notice") return i+1 setup(notice) print("Apa") actor Bepa(): def callback(i): print("callback", i) return i+1 print("Bepa") actor main(env): def myproc(i): print("myproc", i) if i == 2: env.exit(0) return i a = Apa() b = Bepa() print("-----") a.setup(a.notice) x = async a.compute(b.callback) r = await x print("r =", r) a.compute(myproc) print("main") ================================================ FILE: compiler/lib/test/src/deact_from_import.act ================================================ from deact import Apa actor Manager(): def create_decoder() -> StringDecoder: decoder = StringDecoder(self.decode_callback) return decoder def create_apa() -> Apa: apa = Apa() return apa def decode_callback(s: str) -> None: pass actor main(env): mgr = Manager() decoder = mgr.create_decoder() apa = mgr.create_apa() env.exit(0) ================================================ FILE: compiler/lib/test/src/docstrings.act ================================================ """Test module for docstring functionality with {braces}.""" import math # Basic functionality tests def test_function(x: int) -> int: """Test function with docstring.""" return x * 2 def no_docstring_function(x: int) -> int: return x * 3 class TestClass: """Test class with docstring.""" def method(self, x: int) -> int: return x + 1 actor TestActor(name: str): """Test actor with docstring.""" var name = name protocol TestProtocol: """Test protocol with docstring.""" test_method: (int) -> int extension TestClass(TestProtocol): """Extension with docstring.""" def test_method(self, x: int) -> int: return x * 10 # Edge case tests def function_with_non_first_string(x: int) -> int: y = x + 1 "Not a docstring" return y def function_with_multiple_strings(x: int) -> int: """First string is docstring.""" "Second string is not" return x def function_with_f_prefix_docstring() -> int: f"Not a docstring {1}" return 1 def function_with_single_quotes(x: int) -> int: 'Single quote docstring' return x def function_with_triple_single_quotes(x: int) -> int: '''Triple quote docstring''' return x def function_with_mixed_quotes(x: int) -> int: """Mixed 'quotes' in docstring""" return x def function_with_braces_docstring(): """Docstring with {braces} should not interpolate.""" pass def function_empty_docstring(): """""" pass def function_with_control_flow(): if True: "Not a docstring" return 42 def function_just_docstring(): """Just a docstring, no code.""" ================================================ FILE: compiler/lib/test/src/foo.act ================================================ """Foo module - demonstrates cross-module type usage This module extensively uses types from the bar module to demonstrate documentation of cross-module references. """ import bar # Module constants DEFAULT_PREFIX: str = "AUTO_" # Default prefix for auto-generated labels # Functions using bar.Data def create_data(value: str) -> bar.Data: """Create a new Data instance Args: value: Value for the data Returns: A new bar.Data instance with auto-generated label Examples: >>> d = create_data("test") >>> d.get_value() "test" """ return bar.Data(value, DEFAULT_PREFIX + str(len(value))) def transform_data(d: bar.Data, f: (str) -> str) -> bar.Data: """Transform data by applying function to its value Args: d: Data object to transform f: Transformation function Returns: New bar.Data with transformed value See Also: bar.process_data: For simple processing bar.combine_data: For combining multiple data objects """ new_value = f(d.get_value()) return bar.Data(new_value, d.label + "_transformed") def analyze_multiple(data_list: list[bar.Data]) -> dict[str, int]: """Analyze multiple data objects Args: data_list: List of bar.Data objects Returns: Statistics about the data Raises: ValueError: If list is empty """ if len(data_list) == 0: raise ValueError("Cannot analyze empty list") total_length = 0 total_accesses = 0 for d in data_list: total_length += len(d.value) total_accesses += d.count return { "count": len(data_list), "total_length": total_length, "total_accesses": total_accesses } # Class that uses bar.Data class DataManager(object): """Manages a collection of bar.Data objects This class provides high-level operations on collections of Data objects from the bar module. """ storage: list[bar.Data] default: bar.Data name: str def __init__(self, name: str): """Initialize manager Args: name: Name for this manager """ self.storage = [] self.default = bar.Data("", "empty") self.name = name def add_data(self, d: bar.Data): """Add a data object to storage Args: d: bar.Data object to add Raises: ValueError: If storage is full """ if len(self.storage) >= bar.MAX_ITEMS: raise ValueError("Storage is full") self.storage.append(d) def find_by_label(self, label: str) -> ?bar.Data: """Find first data with matching label Args: label: Label to search for Returns: Matching bar.Data or None if not found """ for item in self.storage: if item.label == label: return item return None def get_or_default(self, label: str) -> bar.Data: """Get data by label or return default Args: label: Label to search for Returns: Found bar.Data or the default instance """ found = self.find_by_label(label) if found is not None: return found return self.default def transform_all(self, f: (bar.Data) -> bar.Data) -> list[bar.Data]: """Transform all stored data Args: f: Transformation function Returns: List of transformed bar.Data objects """ result = [] for d in self.storage: result.append(f(d)) return result # Function that works with bar types def process_with_prefix(d: bar.Data, prefix: str) -> bar.Data: """Process data with a prefix Args: d: Data to process prefix: Prefix to add to data values Returns: New bar.Data with prefixed value """ new_value = prefix + d.value return bar.Data(new_value, d.label + "_prefixed") # Actor using bar types actor DataHandler(initial: bar.Data): """Actor that handles bar.Data objects Args: initial: Initial bar.Data to store """ var current: bar.Data = initial var history: list[bar.Data] = [initial] var processor: ?bar.DataProcessor = None def update(new_data: bar.Data): """Update current data Args: new_data: New bar.Data to set as current """ current = new_data history.append(new_data) def get_current() -> bar.Data: """Get current data Returns: Current bar.Data instance """ return current def transform_with(f: (bar.Data) -> bar.Data) -> bar.Data: """Transform current data Args: f: Transformation function Returns: Transformed bar.Data """ new_data = f(current) update(new_data) return new_data def combine_with(other: bar.Data) -> bar.Data: """Combine current with another data Args: other: bar.Data to combine with Returns: Combined bar.Data using bar.combine_data """ combined = bar.combine_data(current, other) update(combined) return combined def send_to_processor(p: bar.DataProcessor): """Send current data to a processor Args: p: bar.DataProcessor to send to """ processor = p p.enqueue(current) def get_history() -> list[bar.Data]: """Get full history of data Returns: List of all bar.Data objects in history """ return history # Higher-order functions with bar types def apply_transformation(d: bar.Data, transform: (str) -> str) -> bar.Data: """Apply transformation to bar.Data value Args: d: Data to transform transform: Function to apply to value Returns: New bar.Data with transformed value """ new_value = transform(d.value) return bar.Data(new_value, d.label + "_transformed") def apply_to_list(items: list[bar.Data], f: (bar.Data) -> str) -> list[str]: """Apply function to all items in list Args: items: List of bar.Data objects f: Function to apply Returns: List of results """ result = [] for item in items: result.append(f(item)) return result # Complex type signatures def process_nested(data: list[(str, bar.Data)]) -> dict[str, list[bar.Data]]: """Process nested data structures Args: data: List of tuples containing keys and bar.Data Returns: Dictionary grouping bar.Data by key """ result: dict[str, list[bar.Data]] = {} for key, d in data: if key not in result: result[key] = [] result[key].append(d) return result # Main actor demonstrating usage actor main(env): """Main actor demonstrating bar module usage""" # Create and use bar.Data d1 = bar.Data("hello", "greeting") d2 = create_data("world") d3 = bar.combine_data(d1, d2) print("Data 1:", d1.get_info()) print("Data 2:", d2.get_info()) print("Combined:", d3.get_info()) # Use list instead of container for simplicity data_list = [d1, d2, d3] # Filter long values long_values = [] for d in data_list: if len(d.value) > 5: long_values.append(d.value) print("Long values:", long_values) # Use DataManager manager = DataManager("test_manager") manager.add_data(d1) manager.add_data(d2) found = manager.find_by_label("greeting") if found is not None: print("Found:", found.get_value()) # Use actors handler = DataHandler(d1) handler.update(d2) handler.combine_with(d3) processor = bar.DataProcessor() handler.send_to_processor(processor) # Process some data processor.enqueue(d1) processor.enqueue(d2) processed = processor.process_next() if processed is not None: print("Processed:", processed.get_info()) print("Processor stats:", processor.get_stats()) # Use transformation functions transformed = process_with_prefix(d1, "PREFIX_") print("Transformed:", transformed.get_info()) # Complex operations items = [("key1", d1), ("key2", d2), ("key1", d3)] grouped = process_nested(items) print("Grouped count:", len(grouped)) # Use protocol functionality processed_results = bar.process_items([d1, d2, d3]) print("Processed via protocol:", processed_results) # Check metadata meta = d1.get_metadata() print("Metadata:", meta) env.exit(0) ================================================ FILE: compiler/lib/test/src/import_private.act ================================================ from import_private_a import * actor main(env): print(__foo) print(public_value) env.exit(0) ================================================ FILE: compiler/lib/test/src/import_private_a.act ================================================ __foo: int = 1 public_value: int = 2 ================================================ FILE: compiler/lib/test/src/import_private_qualified.act ================================================ import import_private_a actor main(env): print(import_private_a.__foo) env.exit(0) ================================================ FILE: compiler/lib/test/src/ints.act ================================================ int64_min: int = -9223372036854775808 int64_max: int = 9223372036854775807 int32_min: i32 = -2147483648 int32_max: i32 = 2147483647 int16_min: i16 = -32768 int16_max: i16 = 32767 int8_min: i8 = -128 int8_max: i8 = 127 uint64_min: u64 = 0 uint64_max: u64 = 18446744073709551615 uint32_min: u32 = 0 uint32_max: u32 = 4294967295 uint16_min: u16 = 0 uint16_max: u16 = 65535 uint8_min: u8 = 0 uint8_max: u8 = 255 bigint_small: bigint = 42 bigint_neg_small: bigint = -1 bigint_i64_max: bigint = 9223372036854775807 bigint_i64_min: bigint = -9223372036854775808 bigint_i64_underflow: bigint = -9223372036854775809 bigint_u64_edge: bigint = bigint(18446744073709551615) bigint_u64_edge_minus1: bigint = bigint(18446744073709551614) bigint_u64_overflow: bigint = 18446744073709551616 xint_i64_min_minus1 = -9223372036854775809 ================================================ FILE: compiler/lib/test/src/lines.act ================================================ actor Apa(): apa = 2001 def setup(cb): print("setup") cb(0) apb = 2002 def compute(cb): print("compute") v = cb(1) m = async cb(2) return v*10 def notice(i): print("notice") return i+1 y = 123 setup(notice) z = 1 print("Apa") actor Bepa(): def callback(i): print("callback", i) return i+1 print("Bepa") actor main(env): def myproc(i): print("myproc", i) if i == 2: env.exit(0) return i a = Apa() b = Bepa() print("-----") a.setup(a.notice) x = async a.compute(b.callback) r = await x print("r =", r) a.compute(myproc) print("main") # If/elif/else nested blocks v = 0 if v == 0: print("if branch") if v < 1: print("nested if") elif v == -1: print("nested elif") else: print("nested else") elif v == 1: print("outer elif") else: print("outer else") # While with else, break/continue i = 0 while i < 3: i = i + 1 if i == 1: print("continue path") continue if i == 2: print("break path") break print("loop body", i) else: print("while else") # For loop over literal list for j in [1, 2, 3]: if j == 2: continue print("for j", j) # Try / except / finally try: if v == 0: raise ValueError("boom") print("unreached") except ValueError as e: print("caught", "ValueError") finally: print("finally") # After scheduling (not executed in tests, but exercises codegen) after 1: myproc(0) # pass statement and return None path in a local def nop(): pass return None nop() ================================================ FILE: compiler/lib/test/src/syntax1.act ================================================ """Module docstring for syntax1 test. This tests docstring support across all language constructs. """ import net # Test function definition with docstring (NDef) def add(x: int, y: int) -> int: """Add two numbers together. This function takes two integers and returns their sum. """ def foo(): """A nested function that does nothing.""" pass return x + y # Test function with just signature (NSig would be in a protocol/class) # We'll test NSig in the protocol below # Test class with docstring (NClass) class Calculator: """A calculator class with basic operations. This class provides methods for arithmetic operations. """ def multiply(self, x: int, y: int) -> int: """Multiply two numbers. Args: x: First number y: Second number Returns: The product of x and y """ return x * y def divide(self, x: int, y: int) -> float: """Divide x by y.""" return float(x) / float(y) # Test actor with docstring (NAct) actor Counter(name: str): """An actor that counts things. This actor maintains a count and can increment it. """ var count = 0 var name = name def increment(): """Increment the counter by one.""" count += 1 def get_count() -> int: """Get the current count value.""" return count # Test protocol with docstring (NProto) protocol Drawable: """Protocol for objects that can be drawn. Any class implementing this protocol must provide a draw method. """ # This creates NSig entries for protocol methods draw: () -> None get_color: () -> str # Test extension with docstring (NExt) extension Calculator (Drawable): """Extension to make Calculator drawable. This adds drawing capabilities to the Calculator class. """ def draw(self): """Draw the calculator.""" print("Drawing a calculator") def get_color(self) -> str: """Get the calculator's color.""" return "black" # Test top-level function without docstring def subtract(x: int, y: int) -> int: return x - y # Test nested functions with docstrings def outer_function(x: int) -> int: """Outer function with a nested function inside.""" def inner_function(y: int) -> int: """Inner function that adds to the outer parameter.""" return x + y return inner_function(10) ================================================ FILE: compiler/lib/test/src/test_discovery.act ================================================ import logging import testing actor MathTester(): def add(a, b): return a + b # Unit test def _test_foo() -> None: pass # Synchronous actor test actor _test_SimpleSyncTester(): m = MathTester() print("SimpleSyncTester.test()") testing.assertEqual(m.add(1, 2), 3, "1 + 2 = 3") actor _SyncTester(t: testing.SyncT): log = logging.Logger(t.log_handler) m = MathTester() log.info("SyncTester.test()") print("SyncTester.test()") testing.assertEqual(m.add(1, 2), 3, "1 + 2 = 3") actor _SyncTesterCore(): m = MathTester() print("SimpleSyncTester.test()") testing.assertEqual(m.add(1, 2), 3, "1 + 2 = 3") def _test_simple_sync(): s = _SyncTesterCore() def _test_sync(t: testing.SyncT): m = MathTester() return str(m.add(1, 2)) # Should return "3" actor AsyncTester(t: testing.AsyncT): log = logging.Logger(t.log_handler) def test(): log.info("AsyncTester.test()", {"data": "test"}) t.success() after 0: test() actor EnvTester(t: testing.EnvT): log = logging.Logger(t.log_handler) def test(): log.info("EnvTester.test() wthreads:", {"nr_wthreads": t.env.nr_wthreads}) print("EnvTester.test() wthreads:", t.env.nr_wthreads) t.success() after 0: test() ================================================ FILE: compiler/lsp-server/Main.hs ================================================ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} import Control.Exception (AsyncException, SomeException, displayException, evaluate, finally, fromException, throwIO, try) import Control.Concurrent (ThreadId, forkIO, killThread, threadDelay) import Control.Concurrent.MVar (MVar, newEmptyMVar, takeMVar, tryPutMVar) import Control.Monad (forM, forM_, forever, void, when) import Control.Monad.IO.Class import Data.Aeson (toJSON) import Data.Char (ord) import Data.List (find) import Data.IORef import qualified Data.HashMap.Strict as HM import qualified Data.Map.Strict as M import Data.Maybe (fromMaybe, listToMaybe) import Data.Sequence (Seq, ViewL(..), (|>)) import qualified Data.Sequence as Seq import qualified Data.Text as T import qualified Data.Text.Encoding as TE import GHC.Conc (getNumCapabilities) import System.Directory (doesDirectoryExist) import System.FilePath ((), takeExtension, takeFileName) import qualified System.FSNotify as FS import System.IO.Unsafe (unsafePerformIO) import Language.LSP.Protocol.Message import Language.LSP.Protocol.Types hiding (Diagnostic, Position) import qualified Language.LSP.Protocol.Types as LSP import Language.LSP.Server import qualified Acton.BuildSpec as BuildSpec import qualified Acton.Compile as Compile import qualified Acton.CommandLineParser as C import qualified Acton.Completion as Completion import qualified Acton.Env as Env import qualified Acton.SourceProvider as Source import qualified Acton.Syntax as S import Error.Diagnose (Diagnostic) import Error.Diagnose.Diagnostic (reportsOf) import Error.Diagnose.Report (Marker(..), Note(..), Report(Warn, Err)) import Error.Diagnose.Position (Position(..)) type OverlayMap = HM.HashMap FilePath Source.SourceSnapshot type UriMap = HM.HashMap FilePath Uri type BackgroundCompilerLockMap = HM.HashMap FilePath Compile.BackgroundCompilerLock type BackgroundCompilerWarned = HM.HashMap FilePath () type CompletionStateMap = HM.HashMap FilePath CompletionState type CompletionEnvCacheMap = HM.HashMap FilePath CompletionEnvCache type ProjectBuildCacheMap = HM.HashMap FilePath ProjectBuildCache type ProjectWatcherMap = HM.HashMap (FilePath, FilePath) ThreadId data CompletionState = CompletionState { completionEnv :: Env.Env0 , completionSearchPath :: [FilePath] , completionModuleName :: S.ModName , completionStateGen :: Int } data CompletionEnvCache = CompletionEnvCache { cachedCompletionStateGen :: Int , cachedCompletionImportKey :: String , cachedCompletionEnv :: Env.Env0 } data ProjectBuildCache = ProjectBuildCache { cachedCompileContext :: Compile.CompileContext , cachedProjectMap :: M.Map FilePath Compile.ProjCtx , cachedGlobalTasks :: [Compile.GlobalTask] , cachedRootPins :: M.Map String BuildSpec.PkgDep , cachedImportKeys :: HM.HashMap FilePath String } data PlanOrigin = PlanFromCache | PlanFromDiscovery deriving (Eq, Show) data LspProgress = LspProgress { lspProgressToken :: ProgressToken , lspProgressQueue :: IORef (Seq T.Text) , lspProgressSignal :: MVar () , lspProgressWorker :: ThreadId } -- | Debounce delay (microseconds) before recompiling on edits. debounceMicros :: Int debounceMicros = 200000 progressIntervalMicros :: Int progressIntervalMicros = 250000 progressQueueLimit :: Int progressQueueLimit = 100 {-# NOINLINE overlaysRef #-} -- | Global in-memory buffer map used as a source overlay. overlaysRef :: IORef OverlayMap overlaysRef = unsafePerformIO (newIORef HM.empty) {-# NOINLINE uriByPathRef #-} -- | Map canonical paths to the client-provided URIs for diagnostics. uriByPathRef :: IORef UriMap uriByPathRef = unsafePerformIO (newIORef HM.empty) {-# NOINLINE backgroundCompilerLocksRef #-} -- | Map project roots to held background-compiler locks. backgroundCompilerLocksRef :: IORef BackgroundCompilerLockMap backgroundCompilerLocksRef = unsafePerformIO (newIORef HM.empty) {-# NOINLINE backgroundCompilerWarnedRef #-} -- | Remember which projects have already warned about another background compiler. backgroundCompilerWarnedRef :: IORef BackgroundCompilerWarned backgroundCompilerWarnedRef = unsafePerformIO (newIORef HM.empty) {-# NOINLINE completionStatesRef #-} -- | Latest successful front-end environment for member completion. completionStatesRef :: IORef CompletionStateMap completionStatesRef = unsafePerformIO (newIORef HM.empty) {-# NOINLINE completionEnvCacheRef #-} completionEnvCacheRef :: IORef CompletionEnvCacheMap completionEnvCacheRef = unsafePerformIO (newIORef HM.empty) {-# NOINLINE projectBuildCachesRef #-} projectBuildCachesRef :: IORef ProjectBuildCacheMap projectBuildCachesRef = unsafePerformIO (newIORef HM.empty) {-# NOINLINE projectWatchersRef #-} projectWatchersRef :: IORef ProjectWatcherMap projectWatchersRef = unsafePerformIO (newIORef HM.empty) {-# NOINLINE compileScheduler #-} -- | Shared compile scheduler for LSP events and back jobs. compileScheduler :: Compile.CompileScheduler compileScheduler = unsafePerformIO $ do nCaps <- getNumCapabilities let maxParallel = max 1 (if C.jobs lspGlobalOpts > 0 then C.jobs lspGlobalOpts else nCaps) Compile.newCompileScheduler lspGlobalOpts maxParallel -- | Global compiler options for the LSP server (quiet, no color). lspGlobalOpts :: C.GlobalOptions lspGlobalOpts = C.GlobalOptions { color = C.Never , quiet = True , noProgress = True , timing = False , tty = False , verbose = False , verboseZig = False , jobs = 0 } -- | Compile options for LSP runs (front passes only, no final build). lspCompileOpts :: C.CompileOptions lspCompileOpts = Compile.defaultCompileOptions { C.skip_build = True , C.only_build = False , C.test = False } -- | SourceProvider that reads overlays first, then falls back to disk. overlaySourceProvider :: IORef OverlayMap -> Source.SourceProvider overlaySourceProvider ref = let disk = Source.diskSourceProvider in Source.SourceProvider { Source.spReadOverlay = \path -> HM.lookup path <$> readIORef ref , Source.spReadFile = Source.spReadFile disk , Source.spGetModTime = Source.spGetModTime disk } -- | Update the in-memory overlay for a document. updateOverlay :: FilePath -> T.Text -> IO () updateOverlay path txt = let snap = Source.SourceSnapshot { Source.ssText = T.unpack txt , Source.ssBytes = TE.encodeUtf8 txt , Source.ssIsOverlay = True } in atomicModifyIORef' overlaysRef $ \m -> (HM.insert path snap m, ()) -- | Remove a document overlay when it closes. removeOverlay :: FilePath -> IO () removeOverlay path = atomicModifyIORef' overlaysRef $ \m -> (HM.delete path m, ()) -- | Publish diagnostics for a file to the LSP client. publishDiagnosticsFor :: FilePath -> [LSP.Diagnostic] -> LspM () () publishDiagnosticsFor path diags = do uri <- liftIO $ lookupUri path sendNotification SMethod_TextDocumentPublishDiagnostics (PublishDiagnosticsParams uri Nothing diags) rememberUri :: FilePath -> Uri -> IO () rememberUri path uri = atomicModifyIORef' uriByPathRef $ \m -> (HM.insert path uri m, ()) forgetUri :: FilePath -> IO () forgetUri path = atomicModifyIORef' uriByPathRef $ \m -> (HM.delete path m, ()) lookupUri :: FilePath -> IO Uri lookupUri path = do m <- readIORef uriByPathRef return (fromMaybe (filePathToUri path) (HM.lookup path m)) ensureBackgroundCompilerLock :: FilePath -> IO Bool ensureBackgroundCompilerLock projRoot = do locks <- readIORef backgroundCompilerLocksRef case HM.lookup projRoot locks of Just _ -> return True Nothing -> do mlock <- Compile.tryBackgroundCompilerLock projRoot case mlock of Nothing -> return False Just lock -> do atomicModifyIORef' backgroundCompilerLocksRef $ \m -> (HM.insert projRoot lock m, ()) atomicModifyIORef' backgroundCompilerWarnedRef $ \m -> (HM.delete projRoot m, ()) return True releaseBackgroundCompilerLocks :: IO () releaseBackgroundCompilerLocks = do locks <- readIORef backgroundCompilerLocksRef forM_ (HM.elems locks) Compile.releaseBackgroundCompilerLock writeIORef backgroundCompilerLocksRef HM.empty rememberCompletionStates :: Int -> Compile.CompilePlan -> Env.Env0 -> IO () rememberCompletionStates gen plan env = do entries <- forM (Compile.cpGlobalTasks plan) $ \t -> do let key = Compile.gtKey t paths = Compile.gtPaths t mn = Compile.tkMod key path <- Compile.normalizePathSafe (Compile.srcFile paths mn) return (path, CompletionState env (Compile.searchPath paths) mn gen) atomicModifyIORef' completionStatesRef $ \m -> (foldr (uncurry HM.insert) m entries, ()) lookupCompletionState :: FilePath -> IO (Maybe CompletionState) lookupCompletionState path = HM.lookup path <$> readIORef completionStatesRef cacheCompletionState :: FilePath -> CompletionState -> IO () cacheCompletionState path state = atomicModifyIORef' completionStatesRef $ \m -> (HM.insert path state m, ()) loadDiskCompletionState :: FilePath -> IO CompletionState loadDiskCompletionState path = do paths <- Compile.findPaths path lspCompileOpts env <- Env.initEnv (Compile.sysTypes paths) False return CompletionState { completionEnv = env , completionSearchPath = Compile.searchPath paths , completionModuleName = Compile.modName paths , completionStateGen = 0 } loadCompletionStateFor :: FilePath -> IO (Maybe CompletionState) loadCompletionStateFor path = do mstate <- lookupCompletionState path case mstate of Just state -> return (Just state) Nothing -> do res <- (try (loadDiskCompletionState path) :: IO (Either SomeException CompletionState)) case res of Right state -> do cacheCompletionState path state return (Just state) Left _ -> return Nothing cacheCompilePlan :: Compile.CompilePlan -> IO () cacheCompilePlan plan = do importKeys <- globalTaskImportKeys (Compile.cpGlobalTasks plan) let ctx = Compile.cpContext plan rootProj = Compile.ccRootProj ctx cache = ProjectBuildCache { cachedCompileContext = ctx , cachedProjectMap = Compile.cpProjMap plan , cachedGlobalTasks = Compile.cpGlobalTasks plan , cachedRootPins = Compile.cpRootPins plan , cachedImportKeys = importKeys } atomicModifyIORef' projectBuildCachesRef $ \m -> (HM.insert rootProj cache m, ()) ensureProjectWatchers rootProj (M.keys (Compile.cpProjMap plan)) globalTaskImportKeys :: [Compile.GlobalTask] -> IO (HM.HashMap FilePath String) globalTaskImportKeys tasks = HM.fromList <$> mapM taskImportKeyEntry tasks taskImportKeyEntry :: Compile.GlobalTask -> IO (FilePath, String) taskImportKeyEntry task = do path <- Compile.normalizePathSafe $ Compile.srcFile (Compile.gtPaths task) (Compile.tkMod (Compile.gtKey task)) return (path, taskImportKey task) taskImportKey :: Compile.GlobalTask -> String taskImportKey task = show (Compile.importsOf (Compile.gtTask task)) invalidateProjectCache :: FilePath -> IO () invalidateProjectCache rootProj = do atomicModifyIORef' projectBuildCachesRef $ \m -> (HM.delete rootProj m, ()) invalidateCompletionEnvCache ensureProjectWatchers :: FilePath -> [FilePath] -> IO () ensureProjectWatchers rootProj roots = forM_ roots $ \watchedRoot -> do let key = (rootProj, watchedRoot) existing <- HM.lookup key <$> readIORef projectWatchersRef case existing of Just _ -> return () Nothing -> do tid <- forkIO (watchProjectShape rootProj watchedRoot) atomicModifyIORef' projectWatchersRef $ \m -> (HM.insert key tid m, ()) watchProjectShape :: FilePath -> FilePath -> IO () watchProjectShape rootProj watchedRoot = FS.withManager $ \mgr -> do let srcRoot = watchedRoot "src" invalidate _ = invalidateProjectCache rootProj isActEvent ev = takeExtension (FS.eventPath ev) == ".act" isBuildActEvent ev = takeFileName (FS.eventPath ev) == "Build.act" srcExists <- doesDirectoryExist srcRoot when srcExists $ void $ FS.watchTree mgr srcRoot isActEvent invalidate void $ FS.watchDir mgr watchedRoot isBuildActEvent invalidate forever $ threadDelay maxBound prepareLspCompilePlan :: Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> FilePath -> LspM () (Either String (PlanOrigin, Compile.CompilePlan)) prepareLspCompilePlan sp gopts opts path = do planE <- liftIO ((try $ do ctx <- Compile.prepareCompileContext opts [path] path' <- Compile.normalizePathSafe path mcache <- HM.lookup (Compile.ccRootProj ctx) <$> readIORef projectBuildCachesRef case mcache of Just cache | Compile.ccBuildStamp (cachedCompileContext cache) == Compile.ccBuildStamp ctx -> do mplan <- compilePlanFromCache ctx path' cache case mplan of Just plan -> return (PlanFromCache, plan) Nothing -> freshPlan _ -> freshPlan ) :: IO (Either SomeException (PlanOrigin, Compile.CompilePlan))) case planE of Left err -> case fromException err of Just (Compile.ProjectError msg) -> return (Left msg) Nothing -> return (Left (displayException err)) Right plan -> return (Right plan) where freshPlan = do plan <- Compile.prepareCompilePlan sp gopts compileScheduler opts [path] False (Just [path]) cacheCompilePlan plan return (PlanFromDiscovery, plan) compilePlanFromCache :: Compile.CompileContext -> FilePath -> ProjectBuildCache -> IO (Maybe Compile.CompilePlan) compilePlanFromCache ctx changedPath cache = do refreshed <- refreshChangedGlobalTask changedPath (Compile.ccOpts ctx) cache case refreshed of Nothing -> return Nothing Just (globalTasks, importKeys) -> do neededTasks <- Compile.selectAffectedTasks globalTasks [changedPath] let rootProj = Compile.ccRootProj ctx rootTasks = [ Compile.gtTask t | t <- neededTasks , Compile.tkProj (Compile.gtKey t) == rootProj ] cache' = cache { cachedCompileContext = ctx , cachedGlobalTasks = globalTasks , cachedImportKeys = importKeys } atomicModifyIORef' projectBuildCachesRef $ \m -> (HM.insert rootProj cache' m, ()) return $ Just Compile.CompilePlan { Compile.cpContext = ctx , Compile.cpProjMap = cachedProjectMap cache , Compile.cpGlobalTasks = globalTasks , Compile.cpNeededTasks = neededTasks , Compile.cpRootTasks = rootTasks , Compile.cpRootPins = cachedRootPins cache , Compile.cpIncremental = True , Compile.cpAllowPrune = False , Compile.cpChangedPaths = Just [changedPath] , Compile.cpSrcFiles = [changedPath] } refreshChangedGlobalTask :: FilePath -> C.CompileOptions -> ProjectBuildCache -> IO (Maybe ([Compile.GlobalTask], HM.HashMap FilePath String)) refreshChangedGlobalTask changedPath opts cache = case find isChanged (cachedGlobalTasks cache) of Nothing -> return Nothing Just old -> do newTask <- Compile.readModuleTask (overlaySourceProvider overlaysRef) lspGlobalOpts opts (Compile.gtPaths old) changedPath let new = old { Compile.gtTask = newTask } newKey = taskImportKey new case HM.lookup changedPath (cachedImportKeys cache) of Just oldKey | oldKey /= newKey -> return Nothing _ -> do let tasks' = [ if Compile.gtKey t == Compile.gtKey old then new else t | t <- cachedGlobalTasks cache ] importKeys' = HM.insert changedPath newKey (cachedImportKeys cache) return (Just (tasks', importKeys')) where isChanged t = Compile.srcFile (Compile.gtPaths t) (Compile.tkMod (Compile.gtKey t)) == changedPath progressToken :: Int -> FilePath -> ProgressToken progressToken gen path = ProgressToken (InR (T.pack ("acton-lsp-" ++ show gen ++ "-" ++ takeFileName path))) startLspProgress :: Int -> FilePath -> LspM () LspProgress startLspProgress gen path = do env <- getLspEnv queue <- liftIO $ newIORef Seq.empty signal <- liftIO newEmptyMVar let token = progressToken gen path title = T.pack ("Acton: " ++ takeFileName path) dequeue = atomicModifyIORef' queue $ \msgs -> case Seq.viewl msgs of EmptyL -> (msgs, Nothing) msg :< rest -> (rest, Just msg) drain = do mmsg <- dequeue case mmsg of Nothing -> return () Just msg -> do runLspT env $ progressReportToken token msg Nothing threadDelay progressIntervalMicros drain loop = forever $ takeMVar signal >> drain worker <- liftIO $ forkIO loop let progress = LspProgress token queue signal worker void $ sendRequest SMethod_WindowWorkDoneProgressCreate (WorkDoneProgressCreateParams token) (\_ -> pure ()) progressBegin progress title "Preparing diagnostics and completion" return progress progressBegin :: LspProgress -> T.Text -> T.Text -> LspM () () progressBegin progress title msg = sendNotification SMethod_Progress $ ProgressParams (lspProgressToken progress) $ toJSON (WorkDoneProgressBegin AString title (Just False) (Just msg) Nothing) progressReportToken :: ProgressToken -> T.Text -> Maybe Int -> LspM () () progressReportToken token msg pct = sendNotification SMethod_Progress $ ProgressParams token $ toJSON (WorkDoneProgressReport AString (Just False) (Just msg) (fromIntegral <$> pct)) progressReport :: LspProgress -> T.Text -> Maybe Int -> LspM () () progressReport progress = progressReportToken (lspProgressToken progress) clearProgressQueue :: LspProgress -> LspM () () clearProgressQueue progress = liftIO $ writeIORef (lspProgressQueue progress) Seq.empty progressReportImmediate :: LspProgress -> T.Text -> Maybe Int -> LspM () () progressReportImmediate progress msg pct = do clearProgressQueue progress progressReport progress msg pct progressReportQueued :: LspProgress -> T.Text -> LspM () () progressReportQueued progress msg = liftIO $ do atomicModifyIORef' (lspProgressQueue progress) $ \msgs -> let msgs' = msgs |> msg in (dropOldestProgress msgs', ()) void $ tryPutMVar (lspProgressSignal progress) () dropOldestProgress :: Seq T.Text -> Seq T.Text dropOldestProgress msgs = Seq.drop (max 0 (Seq.length msgs - progressQueueLimit)) msgs progressEnd :: LspProgress -> T.Text -> LspM () () progressEnd progress msg = sendNotification SMethod_Progress $ ProgressParams (lspProgressToken progress) $ toJSON (WorkDoneProgressEnd AString (Just msg)) finishProgressOnce :: IORef Bool -> LspProgress -> T.Text -> LspM () () finishProgressOnce finished progress msg = do alreadyFinished <- liftIO $ atomicModifyIORef' finished $ \done -> (True, done) when (not alreadyFinished) $ do clearProgressQueue progress liftIO $ killThread (lspProgressWorker progress) progressEnd progress msg moduleLabel :: Compile.GlobalTask -> String moduleLabel task = Compile.modNameToString (Compile.tkMod (Compile.gtKey task)) backJobLabel :: Compile.BackJob -> String backJobLabel job = Compile.modNameToString (S.modname (Compile.biTypedMod (Compile.bjInput job))) frontProgressMessage :: Compile.GlobalTask -> Compile.FrontPassProgress -> T.Text frontProgressMessage task p = T.pack $ passName (Compile.fppPass p) ++ " " ++ moduleLabel task ++ current where current = case Compile.fppCurrent p of Nothing -> "" Just label -> " (" ++ label ++ ")" passName Compile.FrontPassKinds = "Checking kinds for" passName Compile.FrontPassTypes = "Typechecking" backProgressMessage :: Compile.BackJob -> Compile.BackJobResult -> T.Text backProgressMessage job result = T.pack $ case result of Compile.BackJobOk{} -> "Generated " ++ backJobLabel job Compile.BackJobFailed{} -> "Codegen failed for " ++ backJobLabel job warnBackgroundCompilerLocked :: FilePath -> LspM () () warnBackgroundCompilerLocked projRoot = do first <- liftIO $ atomicModifyIORef' backgroundCompilerWarnedRef $ \m -> if HM.member projRoot m then (m, False) else (HM.insert projRoot () m, True) when first $ sendNotification SMethod_WindowShowMessage (ShowMessageParams MessageType_Warning (T.pack ("Another long-running Acton compiler is already running in " ++ projRoot ++ "; LSP compilation is disabled until it exits."))) -- | Run an action only if the compile generation is current. whenCurrentGen :: Int -> LspM () () -> LspM () () whenCurrentGen gen action = do current <- liftIO $ readIORef (Compile.csGenRef compileScheduler) when (current == gen) action -- | Notify the client of a compile error for the current generation. notifyCompileError :: Int -> String -> LspM () () notifyCompileError gen msg = whenCurrentGen gen $ sendNotification SMethod_WindowShowMessage (ShowMessageParams MessageType_Error (T.pack msg)) -- | Convert Acton positions to LSP ranges with zero-based offsets. reportRange :: Position -> Range reportRange (Position (bl, bc) (el, ec) _) = let l0 = max 0 (bl - 1) c0 = max 0 (bc - 1) l1 = max 0 (el - 1) c1 = max 0 (ec - 1) endC = max c1 (c0 + 1) in mkRange (fromIntegral l0) (fromIntegral c0) (fromIntegral l1) (fromIntegral endC) -- | Select a primary marker position for a diagnostic. pickPosition :: [(Position, Marker msg)] -> Maybe Position pickPosition markers = case [pos | (pos, This _) <- markers] of (p:_) -> Just p [] -> fmap fst (listToMaybe markers) -- | Render notes and hints into a diagnostic message. notesText :: [Note String] -> String notesText [] = "" notesText ns = "\n" ++ unlines (map noteLine ns) where noteLine (Hint h) = "Hint: " ++ h noteLine (Note n) = "Note: " ++ n -- | Translate an Acton report into an LSP diagnostic. reportToLsp :: Report String -> LSP.Diagnostic reportToLsp rep = let (sev, msg, markers, notes) = case rep of Err _ m ms ns -> (DiagnosticSeverity_Error, m, ms, ns) Warn _ m ms ns -> (DiagnosticSeverity_Warning, m, ms, ns) pos = pickPosition markers range = maybe (mkRange 0 0 0 0) reportRange pos fullMsg = T.pack (msg ++ notesText notes) in LSP.Diagnostic { _range = range , _severity = Just sev , _code = Nothing , _codeDescription = Nothing , _source = Just "acton" , _message = fullMsg , _tags = Nothing , _relatedInformation = Nothing , _data_ = Nothing } -- | Convert Diagnose diagnostics to LSP diagnostics. lspDiagnosticsFrom :: [Diagnostic String] -> [LSP.Diagnostic] lspDiagnosticsFrom diags = concatMap (map reportToLsp . reportsOf) diags -- | Prepare a compile plan for a file, run it, and publish diagnostics. runCompile :: Int -> FilePath -> LspM () () runCompile gen path = do env <- getLspEnv progress <- startLspProgress gen path finished <- liftIO $ newIORef False let finish = finishProgressOnce finished progress body = do let gopts = lspGlobalOpts opts = lspCompileOpts sp = overlaySourceProvider overlaysRef rootProj <- liftIO $ resolveCompileRoot path opts lockOk <- liftIO $ ensureBackgroundCompilerLock rootProj if lockOk then do progressReportImmediate progress "Running Acton front passes" Nothing ok <- runCompilePlanWithHooks gen rootProj path sp gopts opts progress if ok then finish "Acton ready" else finish "Acton failed" else do progressReportImmediate progress "Waiting for another Acton compiler for this project" Nothing whenCurrentGen gen $ warnBackgroundCompilerLocked rootProj finish "Acton blocked by another compiler" liftIO $ runLspT env body `finally` runLspT env (finish "Acton stopped") -- | Resolve the project root used for compile locking. resolveCompileRoot :: FilePath -> C.CompileOptions -> IO FilePath resolveCompileRoot path opts = do mproj <- Compile.findProjectDir path case mproj of Just proj -> Compile.normalizePathSafe proj Nothing -> do paths <- Compile.findPaths path opts Compile.normalizePathSafe (Compile.projPath paths) -- | Prepare and run a compile while holding the per-run project work lock. runCompilePlanWithHooks :: Int -> FilePath -> FilePath -> Source.SourceProvider -> C.GlobalOptions -> C.CompileOptions -> LspProgress -> LspM () Bool runCompilePlanWithHooks gen rootProj path sp gopts opts progress = do env <- getLspEnv let taskPath t = Compile.srcFile (Compile.gtPaths t) (Compile.tkMod (Compile.gtKey t)) publishFor t diags = runLspT env $ whenCurrentGen gen $ publishDiagnosticsFor (taskPath t) diags progressFor msg = runLspT env $ whenCurrentGen gen $ progressReportImmediate progress msg Nothing progressForQueued msg = runLspT env $ whenCurrentGen gen $ progressReportQueued progress msg hooks = Compile.defaultCompileHooks { Compile.chOnDiagnostics = \t _ diags -> publishFor t (lspDiagnosticsFrom diags) , Compile.chOnParseStart = \t -> progressForQueued (T.pack ("Parsing " ++ moduleLabel t)) , Compile.chOnParseDone = \t _ -> progressForQueued (T.pack ("Parsed " ++ moduleLabel t)) , Compile.chOnFrontStart = \t -> progressFor (T.pack ("Checking " ++ moduleLabel t)) , Compile.chOnFrontProgress = \t p -> progressForQueued (frontProgressMessage t p) , Compile.chOnFrontResult = \t _ -> publishFor t [] >> progressForQueued (T.pack ("Checked " ++ moduleLabel t)) , Compile.chOnBackStart = \job -> progressForQueued (T.pack ("Generating " ++ backJobLabel job)) , Compile.chOnBackDone = \job result -> progressForQueued (backProgressMessage job result) , Compile.chOnInfo = \_ -> return () } progressReportImmediate progress "Preparing Acton project" Nothing compileRes <- liftIO $ Compile.withProjectLock rootProj $ do planE <- runLspT env $ prepareLspCompilePlan sp gopts opts path case planE of Left msg -> return (Left msg) Right (origin, plan) -> do progressFor $ case origin of PlanFromCache -> "Acton cached project ready" PlanFromDiscovery -> "Acton compile plan ready" runRes <- Compile.runCompilePlan sp gopts plan compileScheduler gen hooks case runRes of Left err -> return (Left (Compile.compileFailureMessage err)) Right (envAcc, _) -> do rememberCompletionStates gen plan envAcc progressFor "Completion ready" let opts' = Compile.ccOpts (Compile.cpContext plan) backFailure <- if C.only_build opts' then return Nothing else Compile.backQueueWait (Compile.csBackQueue compileScheduler) gen case backFailure of Just failure -> return (Left (Compile.backPassFailureMessage failure)) Nothing -> return (Right ()) case compileRes of Left msg -> notifyCompileError gen msg >> return False Right () -> return True -- | Schedule a compile run with a debounce delay. scheduleCompile :: Int -> FilePath -> LspM () () scheduleCompile delay path = do env <- getLspEnv void $ liftIO $ Compile.startCompile compileScheduler delay $ \gen -> runLspT env (runCompile gen path) -- | Convert an LSP position to a source offset. LSP columns are UTF-16 code -- units; parser/source offsets are Haskell character offsets. positionToOffset :: String -> LSP.Position -> Int positionToOffset src (LSP.Position line character) = goLine (fromIntegral line) 0 src where targetCol = fromIntegral character goLine 0 off rest = off + columnOffset targetCol rest goLine _ off [] = off goLine n off (c:cs) | c == '\n' = goLine (n - 1) (off + 1) cs | otherwise = goLine n (off + 1) cs columnOffset 0 _ = 0 columnOffset _ [] = 0 columnOffset col (c:cs) | c == '\n' = 0 | units > col = 0 | otherwise = 1 + columnOffset (col - units) cs where units = if ord c > 0xffff then 2 else 1 completionKindToLsp :: Completion.CompletionKind -> CompletionItemKind completionKindToLsp kind = case kind of Completion.CompletionField -> CompletionItemKind_Field Completion.CompletionMethod -> CompletionItemKind_Method Completion.CompletionProperty -> CompletionItemKind_Property Completion.CompletionValue -> CompletionItemKind_Value Completion.CompletionKeyword -> CompletionItemKind_Keyword lspCompletionItem :: Completion.Completion -> CompletionItem lspCompletionItem item = CompletionItem { _label = T.pack (Completion.completionLabel item) , _labelDetails = Nothing , _kind = Just (completionKindToLsp (Completion.completionKind item)) , _tags = Nothing , _detail = T.pack <$> Completion.completionDetail item , _documentation = Nothing , _deprecated = Nothing , _preselect = Nothing , _sortText = Nothing , _filterText = Nothing , _insertText = completionInsertText item , _insertTextFormat = completionInsertTextFormat item , _insertTextMode = Nothing , _textEdit = Nothing , _textEditText = Nothing , _additionalTextEdits = Nothing , _commitCharacters = Nothing , _command = completionCommand item , _data_ = Nothing } completionInsertText :: Completion.Completion -> Maybe T.Text completionInsertText item = case Completion.completionKind item of Completion.CompletionMethod -> Just (T.pack (Completion.completionLabel item ++ "($0)")) Completion.CompletionKeyword -> Just (T.pack (Completion.completionLabel item ++ "$0")) _ -> Nothing completionInsertTextFormat :: Completion.Completion -> Maybe InsertTextFormat completionInsertTextFormat item = case Completion.completionKind item of Completion.CompletionMethod -> Just InsertTextFormat_Snippet Completion.CompletionKeyword -> Just InsertTextFormat_Snippet _ -> Nothing completionCommand :: Completion.Completion -> Maybe Command completionCommand item = case Completion.completionKind item of Completion.CompletionMethod -> Just Command { _title = "Trigger parameter hints" , _command = "editor.action.triggerParameterHints" , _arguments = Nothing } _ -> Nothing forceLspCompletions :: [Completion.Completion] -> [Completion.Completion] forceLspCompletions items = sum [ length (Completion.completionLabel item) + maybe 0 length (Completion.completionDetail item) + completionKindCode (Completion.completionKind item) | item <- items ] `seq` items forceLspSignatures :: [Completion.CallSignature] -> [Completion.CallSignature] forceLspSignatures sigs = sum [ length (Completion.callSignatureLabel sig) + Completion.callSignatureActiveParameter sig + sum (map (length . Completion.signatureParameterLabel) (Completion.callSignatureParameters sig)) | sig <- sigs ] `seq` sigs forceLspHover :: Maybe Completion.HoverInfo -> Maybe Completion.HoverInfo forceLspHover info = case info of Nothing -> Nothing Just hover -> length (Completion.hoverLabel hover) + length (Completion.hoverDetail hover) + maybe 0 length (Completion.hoverDocumentation hover) `seq` info completionKindCode :: Completion.CompletionKind -> Int completionKindCode kind = case kind of Completion.CompletionField -> 1 Completion.CompletionMethod -> 2 Completion.CompletionProperty -> 3 Completion.CompletionValue -> 4 Completion.CompletionKeyword -> 5 tryLspIO :: IO a -> IO (Maybe a) tryLspIO action = do res <- try action case res of Left err | Just (_ :: AsyncException) <- fromException err -> throwIO err | otherwise -> return Nothing Right value -> return (Just value) signatureHelpFor :: FilePath -> LSP.Position -> LspM () (SignatureHelp |? Null) signatureHelpFor path pos = do mstate <- liftIO $ loadCompletionStateFor path case mstate of Nothing -> return (InR Null) Just state -> do snapRes <- liftIO $ (try (Source.readSource (overlaySourceProvider overlaysRef) path) :: IO (Either IOError Source.SourceSnapshot)) case snapRes of Left _ -> return (InR Null) Right snap -> do let src = Source.ssText snap cursor = positionToOffset src pos msigs <- liftIO $ tryLspIO $ do env <- completionEnvFor state path src evaluate (forceLspSignatures (Completion.callSignaturesWithEnv env src cursor)) return $ case msigs of Just (sig:_) -> InL (lspSignatureHelp sig) _ -> InR Null hoverFor :: FilePath -> LSP.Position -> LspM () (Hover |? Null) hoverFor path pos = do mstate <- liftIO $ loadCompletionStateFor path case mstate of Nothing -> return (InR Null) Just state -> do snapRes <- liftIO $ (try (Source.readSource (overlaySourceProvider overlaysRef) path) :: IO (Either IOError Source.SourceSnapshot)) case snapRes of Left _ -> return (InR Null) Right snap -> do let src = Source.ssText snap cursor = positionToOffset src pos minfo <- liftIO $ tryLspIO $ do env <- completionEnvFor state path src evaluate (forceLspHover (Completion.hoverInfoWithEnv env src cursor)) return $ case minfo of Just (Just info) -> InL (lspHover info) _ -> InR Null lspHover :: Completion.HoverInfo -> Hover lspHover info = Hover { _contents = InL MarkupContent { _kind = MarkupKind_Markdown , _value = T.pack (hoverMarkdown info) } , _range = Nothing } where hoverMarkdown hover = "```acton\n" ++ Completion.hoverDetail hover ++ "\n```" ++ hoverDoc hover hoverDoc hover = case Completion.hoverDocumentation hover of Nothing -> "" Just doc -> "\n\n" ++ doc lspSignatureHelp :: Completion.CallSignature -> SignatureHelp lspSignatureHelp sig = SignatureHelp { _signatures = [lspSignatureInformation sig] , _activeSignature = Just 0 , _activeParameter = active } where params = Completion.callSignatureParameters sig active = if null params then Nothing else Just (InL (fromIntegral (Completion.callSignatureActiveParameter sig))) lspSignatureInformation :: Completion.CallSignature -> SignatureInformation lspSignatureInformation sig = SignatureInformation { _label = T.pack (Completion.callSignatureLabel sig) , _documentation = Nothing , _parameters = Just (map lspParameterInformation (Completion.callSignatureParameters sig)) , _activeParameter = active } where params = Completion.callSignatureParameters sig active = if null params then Nothing else Just (InL (fromIntegral (Completion.callSignatureActiveParameter sig))) lspParameterInformation :: Completion.SignatureParameter -> ParameterInformation lspParameterInformation param = ParameterInformation { _label = InL (T.pack (Completion.signatureParameterLabel param)) , _documentation = Nothing } completionEnvFor :: CompletionState -> FilePath -> String -> IO Env.Env0 completionEnvFor state path src = do importKey <- Completion.completionImportKey path src mcache <- HM.lookup path <$> readIORef completionEnvCacheRef case mcache of Just cache | cachedCompletionStateGen cache == completionStateGen state , cachedCompletionImportKey cache == importKey -> return (cachedCompletionEnv cache) _ -> do env <- Completion.prepareCompletionEnv (completionEnv state) (completionSearchPath state) (completionModuleName state) path src let cache = CompletionEnvCache { cachedCompletionStateGen = completionStateGen state , cachedCompletionImportKey = importKey , cachedCompletionEnv = env } atomicModifyIORef' completionEnvCacheRef $ \m -> (HM.insert path cache m, ()) return env invalidateCompletionEnvCache :: IO () invalidateCompletionEnvCache = writeIORef completionEnvCacheRef HM.empty completionItemsFor :: FilePath -> LSP.Position -> LspM () [CompletionItem] completionItemsFor path pos = do mstate <- liftIO $ loadCompletionStateFor path case mstate of Nothing -> return [] Just state -> do snapRes <- liftIO $ (try (Source.readSource (overlaySourceProvider overlaysRef) path) :: IO (Either IOError Source.SourceSnapshot)) case snapRes of Left _ -> return [] Right snap -> do let src = Source.ssText snap cursor = positionToOffset src pos mitems <- liftIO $ tryLspIO $ do env <- completionEnvFor state path src let items = Completion.memberCompletionsWithEnv env src cursor ++ Completion.argumentCompletionsWithEnv env src cursor evaluate (forceLspCompletions items) return (maybe [] (map lspCompletionItem) mitems) -- | Resolve and normalize a document URI to a file path. resolvePath :: Uri -> LspM () (Maybe FilePath) resolvePath uri = case uriToFilePath uri of Nothing -> return Nothing Just path -> liftIO $ do tryLspIO (Compile.normalizePathSafe path) -- | LSP notification handlers for open/change/close events. handlers :: Handlers (LspM ()) handlers = mconcat [ notificationHandler SMethod_Initialized $ \_ -> pure () , notificationHandler SMethod_WorkspaceDidChangeConfiguration $ \_ -> pure () , requestHandler SMethod_TextDocumentCompletion $ \(TRequestMessage _ _ _ params) respond -> do let CompletionParams (TextDocumentIdentifier uri) pos _ _ _ = params items <- resolvePath uri >>= \case Nothing -> return [] Just path -> completionItemsFor path pos respond (Right (InL items)) , requestHandler SMethod_TextDocumentSignatureHelp $ \(TRequestMessage _ _ _ params) respond -> do let SignatureHelpParams (TextDocumentIdentifier uri) pos _ _ = params help <- resolvePath uri >>= \case Nothing -> return (InR Null) Just path -> signatureHelpFor path pos respond (Right help) , requestHandler SMethod_TextDocumentHover $ \(TRequestMessage _ _ _ params) respond -> do let HoverParams (TextDocumentIdentifier uri) pos _ = params hover <- resolvePath uri >>= \case Nothing -> return (InR Null) Just path -> hoverFor path pos respond (Right hover) , notificationHandler SMethod_TextDocumentDidOpen $ \(TNotificationMessage _ _ (DidOpenTextDocumentParams doc)) -> do let TextDocumentItem{_uri=uri,_text=txt} = doc resolvePath uri >>= \case Nothing -> pure () Just path -> do liftIO $ rememberUri path uri liftIO $ updateOverlay path txt scheduleCompile 0 path , notificationHandler SMethod_TextDocumentDidChange $ \(TNotificationMessage _ _ (DidChangeTextDocumentParams vdoc changes)) -> do let VersionedTextDocumentIdentifier{_uri=uri} = vdoc resolvePath uri >>= \case Nothing -> pure () Just path -> case changes of [] -> pure () cs -> do let TextDocumentContentChangeEvent change = last cs txt = case change of InL TextDocumentContentChangePartial{_text=txt'} -> txt' InR TextDocumentContentChangeWholeDocument{_text=txt'} -> txt' liftIO $ rememberUri path uri liftIO $ updateOverlay path txt scheduleCompile debounceMicros path , notificationHandler SMethod_TextDocumentDidClose $ \(TNotificationMessage _ _ (DidCloseTextDocumentParams (TextDocumentIdentifier uri))) -> do resolvePath uri >>= \case Nothing -> pure () Just path -> do liftIO $ removeOverlay path publishDiagnosticsFor path [] liftIO $ forgetUri path ] -- | Start the Acton LSP server with the configured handlers. main :: IO Int main = runServer serverDef `finally` releaseBackgroundCompilerLocks where serverDef = ServerDefinition { parseConfig = const $ const $ Right () , onConfigChange = const $ pure () , defaultConfig = () , configSection = "acton" , doInitialize = \env _req -> pure $ Right env , staticHandlers = \_caps -> handlers , interpretHandler = \env -> Iso (runLspT env) liftIO , options = defaultOptions { optTextDocumentSync = Just syncOptions , optCompletionTriggerCharacters = Just ['.', '(', ','] , optSignatureHelpTriggerCharacters = Just ['(', ','] , optSignatureHelpRetriggerCharacters = Just [','] } } syncOptions = TextDocumentSyncOptions { _openClose = Just True , _change = Just TextDocumentSyncKind_Full , _willSave = Nothing , _willSaveWaitUntil = Nothing , _save = Nothing } ================================================ FILE: compiler/lsp-server/package.yaml.in ================================================ name: lsp-server-acton version: BUILD_VERSION # github: "/simple" license: BSD3 author: "Johan Nordlander, Björn von Sydow, Kristian Larsson" maintainer: "example@example.com" copyright: "Data Ductus, Deutsche Telekom" # Metadata used when publishing your package # synopsis: Short description of your package # category: Web # To avoid duplicated efforts in documentation and dealing with the # complications of embedding Haddock markup inside cabal files, it is # common to point users to the README.md file. description: Please see the README on Github at executables: lsp-server-acton: main: Main.hs source-dirs: . dependencies: - libacton - async - base >= 4.7 && < 5 - bytestring - containers - directory - filepath - fsnotify - mtl - megaparsec - aeson - unordered-containers - diagnose - lsp >= 2.7 - lsp-types - text - time ghc-options: - -threaded - -rtsopts - '"-with-rtsopts=-N -A64M"' when: - condition: os(linux) ghc-options: - -no-pie - -optl-no-pie - -pgml=../tools/ld-wrapper.sh ================================================ FILE: compiler/stack.yaml ================================================ # Resolver to choose a 'specific' stackage snapshot or a compiler version. # A snapshot resolver dictates the compiler version and the set of packages # to be used for project dependencies. # NOTE: do not forget to update homebrew/Formula/acton.rb with the version of # GHC that corresponds to the stack LTS release, like lts-18.28 -> ghc@8.10 snapshot: lts-22.34 # User packages to be built. # Various formats can be used as shown in the example below. # # packages: # - some-directory # - https://example.com/foo/bar/baz-0.0.2.tar.gz # - location: # git: https://github.com/commercialhaskell/stack.git # commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a # - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a # extra-dep: true # subdirs: # - auto-update # - wai # # A package marked 'extra-dep: true' will only be built if demanded by a # non-dependency (i.e. a user package), and its test suites and benchmarks # will not be run. This is useful for tweaking upstream packages. packages: - diagnose - lib - acton - lsp-server # Dependency packages to be pulled from upstream that are not in the resolver # (e.g., acme-missiles-0.3) # extra-deps: [] extra-deps: - Cabal-3.10.3.0 - Cabal-syntax-3.10.3.0 - dir-traverse-0.2.3.0 - directory-1.3.8.5 - filepath-1.4.300.1 - lsp-2.7.0.0 - lsp-types-2.3.0.0 - parsec-3.1.17.0@sha256:8407cbd428d7f640a0fff8891bd2f7aca13cebe70a5e654856f8abec9a648b56 - process-1.6.19.0 - tasty-1.5.3 - unix-2.8.2.1 # Override default flag values for local packages and extra-deps # flags: {} # Extra package databases containing global packages # extra-package-dbs: [] # Control whether we use the GHC we find on the path # NOTE: this is disabled so we can use a stack GHC in local dev environments but # we rewrite this in our Homebrew recipe to use the system GHC. Do NOT remove # this line, regexp replace matches on it! # system-ghc: true ghc-options: "$everything": -fPIC ================================================ FILE: compiler/test/.gitignore ================================================ **/out ================================================ FILE: compiler/tests/Acton.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE RankNTypes, MultiParamTypeClasses, FlexibleInstances #-} module Acton where import Control.Monad.Except data ST s a = ST a instance Functor (ST s) where fmap = undefined instance Applicative (ST s) where pure = undefined (<*>) = undefined instance Monad (ST s) where return = undefined (>>=) = undefined instance MonadError String (ST s) where throwError = undefined catchError = undefined data Msg t = Msg t data Var s t = Var t data Async a b = Async a b data Actor a = Actor a actor :: (forall s . ST s t) -> Actor t _new :: Actor a -> a -> ST s a _asyn :: (a -> ST s b) -> Async a b _snd :: Async a b -> a -> ST s (Msg b) await :: Msg a -> ST s a after :: Int -> ST s a -> ST s () var :: a -> ST s (Var s a) readv :: Var s a -> ST s a writev :: Var s a -> a -> ST s () prints :: String -> ST s () pass :: ST s () msg :: a -> ST s (Msg a) actor a = undefined await m = undefined after t p = undefined var e = undefined readv v = undefined writev v e = undefined prints s = undefined pass = undefined msg = undefined _asyn p = undefined _snd = undefined _new = undefined pingpong :: Int -> Actor (Async Int ()) pingpong i = actor $ do count <- var 0 let ping q = do c <- readv count writev count (c+1) prints ("Ping " ++ show (c*q)) after 1 (pong c (-q)) pong n q = do prints ("Pong " ++ show (n*q)) after 2 (ping (-q)) ping i return (_asyn ping) session :: Conn -> Async String () -> Actor (Async (String, Async Int ()) (), Async (String,String) (), Async () ()) session conn error_cb = actor $ do message_id <- var 1 responder <- var Nothing let get (path, reply_cb) = do m_id <- readv message_id _snd (deliver conn) (print_rpc m_id "get" (print_path path "")) writev responder $ Just $ \text -> _snd reply_cb (xml_parse $ strip_path path $ strip_reply m_id "data" text) edit_config (path, value) = do m_id <- readv message_id _snd (deliver conn) (print_rpc m_id "edit-config" (print_path path $ xml_print value)) writev responder $ Just $ \text -> msg $ xml_parse_empty (strip_reply m_id "ok" text) abort () = do _snd (close conn) () return () _receive text = do r <- readv responder case r of Just resp -> resp text `catchError` \ex -> _snd error_cb (show ex) _ -> undefined m_id <- readv message_id writev message_id (m_id + 1) _error what = do _snd error_cb what writev responder Nothing _snd (receive_on conn) (_asyn _receive, _asyn _error) return (_asyn get, _asyn edit_config, _asyn abort) data Conn = Conn deliver :: Conn -> Async String () close :: Conn -> Async () () receive_on :: Conn -> Async (Async String (), Async String ()) () deliver = undefined close = undefined receive_on = undefined print_rpc :: Int -> String -> String -> String print_path :: String -> String -> String strip_reply :: Int -> String -> String -> String strip_path :: String -> String -> String xml_print :: Show a => a -> String xml_parse :: Read a => String -> a xml_parse_empty :: String -> () print_rpc = undefined print_path = undefined strip_reply = undefined strip_path = undefined xml_print = undefined xml_parse = undefined xml_parse_empty = undefined ================================================ FILE: compiler/tests/ActonLevels.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE RankNTypes, MultiParamTypeClasses, FlexibleInstances #-} module ActonLevels where import Control.Monad.Except data ST s l a = ST a instance Functor (ST s l) where fmap = undefined instance Applicative (ST s l) where pure = undefined (<*>) = undefined instance Monad (ST s l) where return = undefined (>>=) = undefined instance MonadError String (ST s l) where throwError = undefined catchError = undefined data Msg l t = Msg t data Var s l t = Var t -- A Var mentions a level l simply to connect the type of methods sharing a state data Async l a b = Async a b data Actor a = Actor a class Less l l' where less :: l -> l' -> () actor :: (forall s . ST s l t) -> Actor t _new :: Actor a -> a -> ST s l a _asyn :: (a -> ST s l b) -> Async l a b _snd :: Async l' a b -> a -> ST s l (Msg l' b) await :: Less l l' => Msg l' a -> ST s l a after :: Int -> ST s l a -> ST s l () var :: a -> ST s l (Var s l a) readv :: Var s l a -> ST s l a writev :: Var s l a -> a -> ST s l () prints :: String -> ST s l () pass :: ST s l () msg :: a -> ST s l (Msg l' a) actor a = undefined await m = undefined after t p = undefined var e = undefined readv v = undefined writev v e = undefined prints s = undefined pass = undefined msg = undefined _asyn p = undefined _snd = undefined _new = undefined pingpong :: Int -> Actor (Async l Int ()) pingpong i = actor $ do count <- var 0 let ping q = do c <- readv count writev count (c+1) prints ("Ping " ++ show (c*q)) after 1 (pong c (-q)) pong n q = do prints ("Pong " ++ show (n*q)) after 2 (ping (-q)) ping i return (_asyn ping) session :: (Less l_conn l_me) => Conn l_conn -> Async l_cb String () -> Actor (Async l_me (String, Async l_cb Int ()) (), Async l_me (String,String) (), Async l_me () ()) session conn error_cb = actor $ do message_id <- var 1 responder <- var Nothing let get (path, reply_cb) = do m_id <- readv message_id _snd (deliver conn) (print_rpc m_id "get" (print_path path "")) writev responder $ Just $ \text -> _snd reply_cb (xml_parse $ strip_path path $ strip_reply m_id "data" text) edit_config (path, value) = do m_id <- readv message_id _snd (deliver conn) (print_rpc m_id "edit-config" (print_path path $ xml_print value)) writev responder $ Just $ \text -> msg $ xml_parse_empty (strip_reply m_id "ok" text) abort () = do _snd (close conn) () return () _receive text = do r <- readv responder case r of Just resp -> resp text `catchError` \ex -> _snd error_cb (show ex) _ -> undefined m_id <- readv message_id writev message_id (m_id + 1) _error what = do _snd error_cb what writev responder Nothing _snd (receive_on conn) (_asyn _receive, _asyn _error) return (_asyn get, _asyn edit_config, _asyn abort) data Conn l = Conn deliver :: Conn l -> Async l String () close :: Conn l -> Async l () () receive_on :: (Less l l1, Less l l2) => Conn l -> Async l (Async l1 String (), Async l2 String ()) () -- The Less constraints above make no obvious sense here, they are only added for testing purposes. deliver = undefined close = undefined receive_on = undefined print_rpc :: Int -> String -> String -> String print_path :: String -> String -> String strip_reply :: Int -> String -> String -> String strip_path :: String -> String -> String xml_print :: Show a => a -> String xml_parse :: Read a => String -> a xml_parse_empty :: String -> () print_rpc = undefined print_path = undefined strip_reply = undefined strip_path = undefined xml_print = undefined xml_parse = undefined xml_parse_empty = undefined ================================================ FILE: compiler/tests/CPretty.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- module Tests.CPretty where import Pretty import Acton.Syntax import Data.List import Data.Maybe import Acton.Printer import Utils import Prelude hiding ((<>)) cprint m@Module{} = cpretty (CEnv True) m data CEnv = CEnv {isglobal :: Bool} class CPretty a where cpretty :: CEnv -> a -> Doc instance CPretty a => CPretty [a] where cpretty env ss = vcat (map (cpretty env) ss) instance CPretty Module where cpretty env (Module _ _ ss) = text "#pragma once" $+$ blank $+$ text "#include \"common.h\"" $+$ blank $+$ vcat (map (structdecls . cpretty env . name) ["list","dict","set","str", "int","float","complex","bool","Iterator","Slice"] ++ concat (concatMap (structs env) ss) ++ map (cpretty env) ss ) structs env (Decl _ ds) = map strs ds where strs (Class _ nm qs bs ss) = [structdecls cnm, structdecls (cnm <> text "$class")] ++ case nm of Name{} -> [structdecls (cnm <> text "$opaque")] _ -> [] where cnm = cpretty env nm strs _ = [] structs _ _ = [] instance CPretty Stmt where cpretty env (Decl _ ds) = vcat (map (cpretty env) ds) cpretty env (Signature _ ns (TSchema _ _ (TFun _ f p _ r)) _) = if (isglobal env) then vcat (map (\n -> resultTuple env r <+> cpretty env n<>parens (cprettyPosRow env p) <>semi) ns) else vcat (map (\n -> resultTuple env{isglobal=True} r <+> parens (text "*"<> cpretty env n)<>parens (cprettyPosRow env{isglobal=True} p) <>semi) ns) cpretty env (Signature _ ns tsc _) = vcat (map (\n ->cpretty env{isglobal=True} tsc<+> cpretty env n<>semi) ns) cpretty env stmt = empty instance CPretty Decl where cpretty env (Class _ nm qs bs ss) = vcat (map ($+$ blank) [ text "//" <+> cnm <+> text (replicate 60 '/'), witness_struct env{isglobal=False} cnm is, class_struct env{isglobal=False} nm ms, case nm of Name{} -> opaque_struct cnm ms _ -> fun_prototypes env nm ms ]) where (ms,is) = partition isMeth ss cnm = cpretty env nm cpretty env d = error ("cpretty: unexpected Decl: "++show d) isMeth (Signature _ _ sc _) = isFunType (sctype sc) where isFunType (TFun {}) = True isFunType _ = False isMeth _ = False instance CPretty TBind where cpretty env (TBind tv bs) = vcat (map (\b -> cpretty env b<>pretty tv) bs) instance CPretty TCon where cpretty env (TC qn _) = cpretty env qn instance CPretty TSchema where cpretty env (TSchema _ _ t) = cpretty env t instance CPretty Name where cpretty env n@Internal{} = text (nstr n) cpretty env n | nstr n=="_Complex" = text "_Complx" | nstr n=="__complex__" = text "__complx__" | isglobal env = text ('$' : nstr n) | otherwise = text (nstr n) instance CPretty ModName where cpretty env (ModName ns) = hsep $ punctuate (text "$$") (map (cpretty env) ns) instance CPretty QName where cpretty env (QName mn n) = cpretty env mn<>text "$$"<>cpretty env n cpretty env (NoQ n) = cpretty env n instance CPretty Type where cpretty env (TVar _ v) = text "$WORD" cpretty env (TCon _ c) = cpretty env c cpretty env (TFun _ e p _ t) = cpretty env t <+> parens (cprettyPosRow env p) cpretty env (TTuple _ p _) = parens (cprettyPosRow env p) cpretty env (TUnion _ as) = parens (vbarSep pretty as) where vbarSep f = hsep . punctuate (space <> char '|') . map f cpretty env (TOpt _ t) = cpretty env t cpretty env (TNone _) = text "void" cpretty env (TWild _) = text "_" cpretty env row = prettyKwdRow row cprettyPosRow env (TRow _ _ _ t TNil{}) = cpretty env t cprettyPosRow env (TRow _ _ _ t p) = cpretty env t <> comma <+> cprettyPosRow env p cprettyPosRow env TNil{} = empty structdecls cnm = text "struct" <+> cnm <> semi $+$ text "typedef struct" <+> cnm <+> text "*" <> cnm <> semi $+$ blank witness_struct env cnm is = text "struct" <+> cnm <+> text "{" $+$ (nest 4 $ vcat ([--text "char *$GCINFO;", cnm <> text "$class" <+>text"$class"<>semi] ++ [vcat (map (cpretty env) is)])) $+$ text "};" class_struct :: CEnv -> Name -> [Stmt] -> Doc class_struct env nm ms = text "struct" <+> cpretty env{isglobal=True} nm<>text "$class" <+> text "{" $+$ (nest 4 $ text "char *$GCINFO;" $+$ vcat (map (cpretty env . addparSig nm) ms)) $+$ text "};" where addparSig nm (Signature l ns (TSchema l2 qs (TFun l3 f p k r)) d) = Signature l ns (TSchema l2 qs (TFun l3 f (addFstElem nm p) k r)) d addFstElem nm p = posRow (tCon (TC (NoQ nm) [])) p opaque_struct cnm ms = text "struct" <+> cnm<>text "$opaque" <+> text "{" $+$ (nest 4 $ text "char *$GCINFO;" $+$ vcat [cnm <+> text "proto"<>semi, text "$WORD impl"<>semi]) $+$ text "};" $+$ blank $+$ cnm<>text "$opaque" <+> cnm<>text "$pack"<>parens (cnm <+>text "proto, $WORD impl") <> semi $+$ blank fun_prototypes env nm ss = vcat (map proto ss) where proto (Signature _ ns (TSchema _ _ (TFun _ f p _ r)) _) = vcat (map (\n -> resultTuple env r <+> cpretty env nm<>cpretty env n<+>parens (cprettyPosRow env (addFstElem nm p)) <>semi) ns) resultTuple env (TTuple _ r _) = tup 0 r where tup n (TNil _ _) = text ("$tup"++show n++"_t") tup n (TRow _ _ _ _ r) = tup (n+1) r tup _ r = error ("cPrettyPosRow: unhandled tuple; row is "++render(pretty r)) resultTuple env t = cpretty env t ================================================ FILE: compiler/tests/ProtExtElim.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- module Tests.ProtExtElim where import Data.Maybe import Data.List import Acton.Env import Pretty import Utils import Acton.Syntax -- Transform a file containing protocol definitions, extensions and signatures. -- Intended use is to translate large parts of module __builtin__ to C. transform m@(Module nm is stmts) = Module nm is (map (Decl NoLoc . (:[])) (trans env ps) ++ map (Decl NoLoc . (:[])) (concatMap (transExt env) es) ++ trans env ss) where (ps,cs,es,ss) = splitStmts stmts -- ignore classes; builtin classes have handcrafted C code. -- for now, no defs or actors. env = newTransEnv (protocolsOf m) ----------------------------------------------------------------------------------------------------- data TransEnv = TransEnv {protocols :: [(Name,Decl)], decor :: Deco, fstpar :: Maybe Type, master :: Maybe TCon } newTransEnv ps = TransEnv ps NoDec Nothing Nothing splitStmts stmts = sp stmts [] [] [] [] -- protocols, classes, extensions, signatures where sp [] ps cs es ss = (reverse ps,reverse cs,reverse es,reverse ss) sp (Decl _ ds : stmts ) ps cs es ss = spdecl ds stmts ps cs es ss sp (s@Signature{} : stmts) ps cs es ss = sp stmts ps cs es (s : ss) spdecl [] stmts ps cs es ss = sp stmts ps cs es ss spdecl (p@Protocol{} : ds) stmts ps cs es ss = spdecl ds stmts (p : ps) cs es ss spdecl (c@Class{} : ds) stmts ps cs es ss = spdecl ds stmts ps (c : cs) es ss spdecl (e@Extension{} : ds) stmts ps cs es ss -- ignore defs = spdecl ds stmts ps cs (e : es) ss spdecl (d@Def{} : ds) stmts ps cs es ss = spdecl ds stmts ps cs es ss class Transform a where trans :: TransEnv -> a -> a instance Transform a => Transform [a] where trans env as = map (trans env) as instance Transform Module where trans env (Module nm is ss) = Module nm is $ trans env ss instance Transform Stmt where trans env (Decl loc ds) = Decl loc $ trans env ds trans env (Signature loc ns t d) = Signature loc ns (trans env{decor=d} t) (if d == Static then NoDec else d) trans env stmt = stmt instance Transform Decl where trans env (Protocol loc n qs bs ss) = case transParents tv bs of [] -> Class loc n (tBind v:qs1) [] ss2 b:_ -> Class loc n (tBind v:qs1) [trans env b] (addWitnesses env bs1 ss2) where v = head (drop 15 tvarSupply Utils.\\ tybound qs) -- we just prefer letters later in the alphabet for this type variable... tv = tVar v ss1 = trans env{fstpar = Just tv} (addSigs (protocols env) bs ++ ss) initSig = Signature NoLoc [name "__init__"] (monotype (tFun0 (map tCon (maybe [] (:[]) (master env) ++ws)) tNone)) Static (qs1,ws) = transParams qs ss2 = initSig : addWitnesses env ws ss1 cs = chains (protocols env) bs bs1 = transParents tv (if null cs then [] else map head (tail cs)) trans env d = d instance Transform TSchema where trans env (TSchema loc bs t) = TSchema loc (trans env bs) (trans env t) instance Transform Type where trans env (TVar loc (TV k (Name _ "Self"))) = fromJust (fstpar env) trans env v@TVar{} = v trans env (TTuple loc p k) = TTuple loc (trans env p) (trans env k) trans env (TFun loc fx p k r) = TFun loc fx p1 (trans env k) (trans env r) where p1 = if decor env == Static then trans env p else maybe (trans env p) (flip posRow (trans env p)) (fstpar env) trans env (TOpt loc t) = TOpt loc $ trans env t trans env (TRow loc k nm s r) = TRow loc k nm (trans env s) (trans env r) -- trans env (TCon loc tc) = maybe (TCon NoLoc (trans env tc)) (const (TExist NoLoc (trans env tc))) (lookup (noq (tcname tc)) (protocols env)) -- trans env (TExist _ tc) = TExist NoLoc (trans env tc) trans env t = t instance Transform TCon where trans env (TC qn ts) = TC (trans env qn) (trans env ts) instance Transform TBind where trans env (TBind tv tcs) = TBind tv (trans env tcs) instance Transform QName where trans env (QName _ nm) = NoQ nm trans env qn = qn instance Transform Name where trans env nm = nm -- adds witnesses to superprotocols other than the first mentioned. addWitnesses env ws ss = map mkSig ws ++ ss where mkSig tc = Signature NoLoc [name ('_' : nstr (noq (tcname tc)))] (monotype (tCon (trans env tc))) NoDec transParents tv bs = map addP bs where addP (TC qn ts) = TC qn (tv : ts) -- transforms [A(Eq), B, C(Hashable)] into ([A,B,C],[Eq[A],Hashable[C]]) transParams :: QBinds -> (QBinds,[TCon]) transParams qs = trP qs [] [] where trP [] ws qs1 = (reverse qs1,reverse ws) trP (TBind tv cs:qs) ws qs1 = trP qs ([TC nm [tVar tv] | TC nm _ <- cs]++ws) (tBind tv : qs1) --------------------------------------------------------------------------------------------------------- -- -- To transform an extension we assume for the moment that only one protocol is mentioned. -- We find all ancestor protocols and replace this tree with linear chains with only single -- inheritance. -- -- As an example, if the inheritance structure is -- -- Sequence-> Sliceable -> Indexed -- | -- -> Collection -> Iterable -- | -- -> Plus -- -- we form the three chains Sequence->Sliceable->Indexed , Collection->Iterable , Plus, -- each of which will be transformed to one class definition. -- -- transExt constructs the chains and calls transChain for each chain to build the class definition. --------------------------------------------------------------------------------------------------------- transExt :: TransEnv -> Decl -> [Decl] transExt env e@(Extension l nm qs bs ss) | length bs /= 1 = error "For now, an extension must implement exactly one protocol" | otherwise = transChain Nothing env (head bs) e cs where as = head bs : ancestors env (noq (tcname (head bs))) cs = chains (protocols env) as transChain :: Maybe Type -> TransEnv -> TCon -> Decl -> [[TCon]] -> [Decl] transChain _ _ _ _ [] = [] transChain mb env b e (c : cs) = c2{dname = c2nm, dbody = sigs} : transChain (Just witType) env{master = Just b} b e cs where cn = noq (tcname (head c)) prot = fromJust (lookup cn (protocols env)) c1 = trans env prot{qual = qual e ++ qual prot} ts = trans env (tCon (mkTC (dqname e) (qual e)) : tcargs (head (bounds e))) (_,ws) = transParams (qual e) c2 = substAll ts c1 tc = head (bounds c2) c2nm = Derived (dname c2) (noq (dqname e)) witType = maybe (tCon tc) id mb sigs = maybe [] (\(TCon _ (TC nm _))->[Signature NoLoc [name ('_':nstr (noq nm))] (monotype witType) NoDec]) mb ++ nub (dbody c2) -- nub (addWitnesses env ws (dbody c2)) substAll ts (Class l nm qs bs ss) = Class l nm (nub $ map tBind (ufree ts)) [tc] (subst2 s ss) where s = tVars qs `zip` ts tc = subst2 s (mkTC (NoQ nm) qs) addSigs :: [(Name,Decl)] -> [TCon] -> [Stmt] addSigs ps [] = [] addSigs ps (TC n qs : _) = addSigs ps (subst2 s (bounds p)) ++ subst2 s methodSigs where p = fromJust (lookup (noq n) ps) s = tVars (qual p) `zip` qs methodSigs = [sig | sig@(Signature _ _ sc _) <- dbody p, isFunSchema sc ] where isFunSchema sc = isFunType (sctype sc) isFunType (TFun {}) = True isFunType _ = False subst2 :: Subst a => Substitution -> a -> a subst2 s = subst s2 . subst s1 where (s1,s2) = partition (\p -> null (ufree(snd p) `intersect` (ufree (dom s)))) (red s) red [] = [] red ((tv,TVar _ tv') : ps) |tv == tv' = red ps red (p:ps) = p : red ps mkTC nm qs = TC nm $ map (\(TBind tv _) -> tVar tv) qs tVars qs = map (\(TBind tv _) -> tv) qs protocolsOf (Module _ _ ss) = [(dname p,p) | Decl _ ds <- ss, p@(Protocol{}) <- ds] parentsOf p = map (noq . tcname) (bounds p) ancestors :: TransEnv -> Name -> [TCon] ancestors env n = ps ++ concatMap (ancestors env) (map (noq . tcname) ps) where ps = bounds (fromJust (lookup n (protocols env))) chains :: [(Name,Decl)] -> [TCon] -> [[TCon]] chains ps [] = [] chains ps (b:bs) = cs : chains ps [ b | b@(TC qn ts) <- bs, qn `notElem` map tcname cs ] where cs = fstParents ps b fstParents ps b@(TC qn ts) = case lookup (noq qn) ps of Just (Protocol _ _ _ bs _) -> case bs of [] -> [b] p:_ -> b : fstParents ps p Nothing -> error ("cannot find protocol "++show qn) ================================================ FILE: compiler/tests/TestTransform.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- import qualified Acton.Parser as P import System.Environment import System.IO import Pretty import Acton.Printer import Acton.Syntax import Tests.ProtExtElim import Tests.CPretty import InterfaceFiles main = do src <- readFile "__builtin__.act" m <- P.parseModule (ModName [name "__builtin__"]) "__builtin__.act" src Nothing let m1 = transform m putStrLn (render(cprint m1)) ================================================ FILE: compiler/tests/actorring.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # no_actors = 5 total_msgs = 20 actor Act(i): var count = 0 var rcv_dict = {} var snd_dict = {} def work(src, table): if count < total_msgs: count += 1 dst = (i + 1) % no_actors rcv_dict[src] = rcv_dict.get(src,0) + 1 snd_dict[dst] = snd_dict.get(dst,0) + 1 print("Actor %d: count=%d, src=%d, dst=%d" % (i,count,src,dst)) table[dst].work(i, table) actor Root(_ignore:Env): table = [] for i in range(no_actors,None,None): table.append(Act(i)) table[0].work(no_actors, table) ================================================ FILE: compiler/tests/controller.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # import netconf actor Controller(env, address, port): var nc = None var state = 'IDLE' var setting = 0 def restart(what): if nc is not None: nc.abort() nc = None print('Controller', str(address) + ':' + str(port), what) netconf.connect(env, address, port, _established, _error) state = 'IDLE' def _established(sess): if sess is not None: nc = sess after 10: _tick() else: restart('connection failure') def _tick(): if state == 'IDLE': state = 'GET' after 10: _tick() nc.get('/oper/thevalue', _reply) else: restart('timeout') def _reply(newval): if state == 'GET': setting = compute(setting, newval) nc.edit_config('/config/settings/thesetting', setting) state = 'IDLE' else: restart('stray reply') def _error(what): restart('NETCONF error: ' + what) restart('initial') def compute(setting, newval): return (setting + newval) // 2 ================================================ FILE: compiler/tests/counter.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # actor Counter(): var count = 0 def inc(): count = count + 1 def get(): return count actor main(env: Env): c = Counter() def _step(): print('inc') c.inc() x = c.get() print('get = %d' % x) after 1: _step() _step() ================================================ FILE: compiler/tests/env.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # class Env (struct): open : action(str, int, action(?Connection)->None) -> None class Connection: deliver : action(data: str) -> None close : action() -> None receive_on : action(input: action(str)->None, error: action(str)->None) -> None actor _EnvActor (): def do_open(str, int, on_success): pass class _Env (Env): def __init__(self, actual): self.actual = actual def open(self, address: str, port: int, on_success): self.actual.do_open(address, port, on_success) # or, using a (tentative) notational shorthand: # open = self.actual.open # struct Env; # typedef struct Env *Env; # struct Env$__class__; # typedef struct Env$__class__ *Env$__class__; # # struct Connection; # typedef struct Connection *Connection; # struct Connection$__class__; # typedef struct Connection$__class__ *Connection$__class__; # # struct Env { # Env$__class__ __class__; # $WORD __impl__; # }; # struct Connection { # Connection$__class__ __class__; # $WORD __impl__; # }; # struct Env$__class__ { # char *$GCINFO; # $Msg (*open)(Env$__class__, $WORD, $str, $int, $Clos); # }; # struct Connection$__class__ { # char *$GCINFO; # $Msg (*deliver)(Connection$__class__, $WORD, $str); # $Msg (*close)(Connection$__class__, $WORD); # $Msg (*receive_on)(Connection$__class__, $WORD, $Clos, $Clos); # }; ================================================ FILE: compiler/tests/env.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "rts.h" // protocol Connection /////////////////////////////////////////////////////////////////////////////////// struct Connection; typedef struct Connection *Connection; struct ConnectionD___class__; typedef struct ConnectionD___class__ *ConnectionD___class__; struct Connection { ConnectionD___class__ __class__; $WORD __impl__; }; struct ConnectionD___class__ { char *$GCINFO; B_Msg (*deliver)(ConnectionD___class__, $WORD, B_str); B_Msg (*close)(ConnectionD___class__, $WORD); B_Msg (*receive_on)(ConnectionD___class__, $WORD, $function, $function); }; Connection ConnectionD___pack__(ConnectionD___class__ __class__, $WORD __impl__) { Connection conn = malloc(sizeof(struct Connection)); conn->__class__ = __class__; conn->__impl__ = __impl__; return conn; } // protocol Env ////////////////////////////////////////////////////////////////////////////////////////// struct Env; typedef struct Env *Env; struct EnvD___class__; typedef struct EnvD___class__ *EnvD___class__; struct Env { EnvD___class__ __class__; $WORD __impl__; }; struct EnvD___class__ { char *$GCINFO; B_Msg (*open)(EnvD___class__, $WORD, B_str, B_int, $function); }; Env EnvD___pack__(EnvD___class__ __class__, $WORD __impl__) { Env env = malloc(sizeof(struct Env)); env->__class__ = __class__; env->__impl__ = __impl__; return env; }; // class TrueConnection /////////////////////////////////////////////////////////////////////////////////// struct TrueConnection; typedef struct TrueConnection *TrueConnection; struct TrueConnection { int socket; $function input_callback; $function error_callback; // more... }; B_Msg TrueConnection$deliver (ConnectionD___class__ cls, $WORD __impl__, B_str data) { TrueConnection trueSelf = (TrueConnection)__impl__; return NULL; } B_Msg TrueConnection$close (ConnectionD___class__ cls, $WORD __impl__) { TrueConnection trueSelf = (TrueConnection)__impl__; return NULL; } B_Msg TrueConnection$receive_on (ConnectionD___class__ cls, $WORD __impl__, $function input, $function error) { TrueConnection trueSelf = (TrueConnection)__impl__; return NULL; } struct ConnectionD___class__ Connection___TrueConnection = { .$GCINFO = "Connection", .deliver = TrueConnection$deliver, .close = TrueConnection$close, .receive_on = TrueConnection$receive_on }; // class TrueEnv ///////////////////////////////////////////////////////////////////////////////////////// struct TrueEnv; typedef struct TrueEnv *TrueEnv; B_Msg TrueEnv$open(EnvD___class__ cls, $WORD __impl__, B_str address, B_int port, $function callback) { TrueEnv self = (TrueEnv)__impl__; TrueConnection trueConn = /* create socket, etc, ... */ NULL; Connection conn = ConnectionD___pack__(&Connection___TrueConnection, trueConn); B_Msg m = /* ASYNC... */ NULL; return m; } struct EnvD___class__ Env___TrueEnv = { .$GCINFO = "Env", .open = TrueEnv$open }; struct TrueEnv { // empty? Or selector_fd? }; // main ////////////////////////////////////////////////////////////////////////////////////////////////// int main() { // ... TrueEnv trueEnv = /* create whatever... */ NULL; Env env = EnvD___pack__(&Env___TrueEnv, trueEnv); // BOOTSTRAP($CONTINUATION(ROOT, 1, ($WORD)env)); // ... } ================================================ FILE: compiler/tests/netconf.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # import xml def connect(env, address, port, established_cb, error_cb): env.open(address, port, lambda conn: established_cb(session(conn, error_cb))) actor session(conn, error_cb): var message_id = 1 var responder = None def get(path, reply_cb): conn.deliver(print_rpc(message_id, 'get', print_path(path, ''))) responder = lambda text: reply_cb(xml.parse(strip_path(path, strip_reply(message_id, 'data', text)))) def edit_config(path, value): conn.deliver(print_rpc(message_id, 'edit-config', print_path(path, xml.print(value)))) responder = lambda text: xml.parse_empty(strip_reply(message_id, 'ok', text)) def abort(): conn.close() def _receive(text): try: if responder: responder(text) except xml.ParseError as ex: error_cb(str(ex)) except ValueError as ex: error_cb(str(ex)) message_id += 1 def _error(what): error_cb(what) responder = None conn.receive_on(_receive, _error) def print_rpc(message_id, second_tag, inner): strs = [] strs.append('') strs.append('<' + second_tag + '>') strs.append('') strs.append('') return ''.join(strs) def strip_reply(message_id, second_tag, text): prefix = '' suffix = '' text = text.strip() if text.startswith(prefix) and text.endswith(suffix): text = text[len(prefix):-len(suffix)].strip() prefix = '<' + second_tag + '>' suffix = '' if text.startswith(prefix) and text.endswith(suffix): return text[len(prefix):-len(suffix)] elif text == '<' + second_tag + '/>': return '' raise xml.ParseError def print_path(path, inner): elems = path.split('/') if elems[0] != '': raise ValueError if elems[-1] == '': elems.pop() strs = [] for elem in elems[1:]: strs.append('<' + elem + '>') strs.append(inner) for elem in elems[-1:0:-1]: strs.append('') return ''.join(strs) def strip_path(path, text): elems = path.split('/') if elems[0] != '': raise ValueError if elems[-1] == '': elems.pop() for elem in elems[1:]: text = text.strip() prefix = '<' + elem + '>' suffix = '' if text.startswith(prefix) and text.endswith(suffix): text = text[len(prefix):-len(suffix)] else: raise xml.ParseError return text ================================================ FILE: compiler/tests/newtuple.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # t1 = (3,5) t2 = (3) t3 = (3,) t4 = (3,x=5) t5 = (*e,x=5,) t6 = (x=5,) t7 = (x=5,**t) (y,a = x) = e ================================================ FILE: compiler/tests/pingpong.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # actor Pingpong(env: Env): var count = 0 i = int(env.argv[1]) def _ping(): count = count + i print('%d Ping %8d' % (i,count)) after 1: _pong(-count) def _pong(q): print('%d %8d Pong' % (i,q)) after 2: _ping() _ping() ================================================ FILE: compiler/tests/records.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # r1 = {x : int} r2 = {x:int,y:bool} r3 = {x:int,y:bool,} r4 = {x:int,y:bool,**f(a)} r5 = {x:int,y:bool,**f(a),} r6 = {**f(x,y)} r7 = {a:b for a,b in g(t)} r8 = {a:b for a,b, in g(t)} ================================================ FILE: compiler/tests/test.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # x0 : (x: int, y: int) # struct x1 : (x: int, y: A, **B) # open struct; two fileds of the same type x2 : (int | float) # union x3 : ('str1' | 'str2' | int) # union with string literals x4 : (int,bool) # tuple x5 : ?B12 # option type; type var x6 : Set[int] # Class with type argument x7 : [A(Hashable), B, S(Mapping[A,B])] => (S)->dict[A,B] # Qualified/constrained type x8 : ((int) -> int,(b : bool),(int,int)) # more complicated tuple x9 : act[X] (int,*A,b : bool,**B) -> set[int] # function with effects and all kinds of parameters x10: action(int, *A, b: bool) -> Msg[int] x11: X(f: X(A)->B, a: [A]) -> [B] #x12: st[Y](int, list[Y,str]) -> str #x13: st(int, dict[int]) -> None #x14: mut[Y](int, list[Y,str]) -> str #x15: mut(int, dict[int]) -> None #x16: !Y(int, list[Y,str]) -> str #x17: !(int, dict[int]) -> None a0 : (float,float) -> (float | 'division by zero') # function without effects; union result a1 : (str,*P,c : bool) -> None # function with * separation of pos and kwd parameters a2 : (int) -> (int) -> int # higher order function a3 : {int} # set of ints (protocol) a4 : [(float,bool)] # list of tuples (protocol) a5 : {{[int]}} # more complicated set (protcol) a6 : {[int]:(int) -> bool} # a dict (protocol) a7 : (set[int],list[float],dict[{int},bool]) # tuple of mutable data structures y1 : (x: float, y: A, **B) # open struct #y2 : (**) # open struct y3 : (**A) # open struct y4 : (int, bool, *A) # open tuple #y5 : (int, bool, *) # open tuple #y6 : (*) # open tuple y7 : (*A) # open tuple y8 : () # empty tuple (should count as empty struct as well?) f0 : () -> int f1 : (int) -> bool f2 : (int,) -> int f3 : (int,bool) -> int f4 : (int,bool,) -> int #f5 : (int,bool,*) -> int #f6 : (int,bool,*,) -> int f7 : (int,bool,*A) -> int f8 : (int,bool,*A,) -> int #f9 : (*) -> int #f10 : (*,) -> int f11 : (*A) -> int f12 : (*A,) -> int f12a : (**A) -> bool f12b : (**A,) -> bool f13 : (x : float) -> int f14 : (x : float,) -> int f15 : (x : float, y : str) -> int #f16 : (x : float, y : str, **) -> int f17 : (x : float, y : str, **A) -> int #f18 : (x : float, y : str,**,) -> int f19 : (x : float, y : str,**A,) -> int f20 : (int, x : float) -> int f21 : (int, *A,x:float, **B,) -> int f22 : (,) -> int # Should this really be allowed?? z0 : (int,bool,*A,) z1 : (x : float) z2 : (x : (y : float,z : bool),**A,) z3 : [A] # sequence that also could be the start of a qualified type def elem [A(Eq), B(Ord)] (x:A, xs:[A]) -> B: # function with explicit quant/qualifiers pass def f24(): pass def f25(a): pass def f26(a,): pass def f27(a,*b): # a.0 = (7) # a.*1 = (2,) return () def f28(a,*b,): apa = (1,2,x=3,y='hello') bepa = (1,2) (cepa) = 3 (c,) = (4,) (d,e) = a def f29(a,**b): pass def f30(a,**b,): pass def f31(a,*b,**c): pass def f32(a,*b,**c,): pass def f33(a,*b,c,**d): pass def f34(a,*b:(int,*P),c,**d,): pass def f35(*a): pass def f35b(*a,): pass def f36(*a,**b:(x:int,**K)): pass def f37(*a,**b,): pass def f38(*a,b,**c): pass def f39(*a,b,**c,): pass def f40(**c): pass def f40b(**c,): pass class Apa: @property x : int def __init__(self): self.x = 1 @staticmethod def f(x): pass if True: while False: pass protocol Bepa [A] (): x : int @staticmethod compare : (Self,Self) -> bool def compare(x:Self, y:Self) -> bool: if True: while False: pass return True actor Test[T](v0:T): def m(x): pass def f(z): pass protocol MyProto[A,B(Eq)] (Bepa[B]): pass extension __builtin__.int (Eq): pass protocol MyIndexed[A,B]: # just a protocol __getit__ : (A) -> B g : [A] => ((A)->A, int, str) -> (int,str) # explicit quantification h : [A] => ((A)->A, x:int, y:dict[int,str]) -> str # mixing positional and keyword arguments ff : (**A) -> bool ================================================ FILE: compiler/tests/test1.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # def f0(x : ?int): return x + 7 if x is not None else 0 def f1(x : ?(int)->int): return x(7) if x is not None else 0 def f2(x : ?int): return x is None def f3(x : ?int): return x == 7 def f4(x : ?int): return x + 7 if x is not None else 0 def f5(x : ?int): return x+1 if x is not None and x > 0 else 0 def f6(x : ?(?int)): return (x + 7 if x is not None else 1) if x is not None else 0 def f7a(x : ?int): return x == 7 #def f9(x : str): # return x == True # Cannot solve: atom < T, T(Eq) def f10(x : bool): return 'A' if x else 'B' def f11(): return 'A' 'B' def f12(x : Exception): return 1 if isinstance(x, NotImplementedError) else 2 def f13(x : atom): return x if isinstance(x, int) else -1 def f14(): a = (1, False, "hello" + "world") b0 = a.0 b1 = a.1 b2 = a.2 c0 = a.~0 c1 = a.~1 c2 = a.~2 x = (apa = 1, bepa = False, cepa = "hello" "world") y0 = x.apa y1 = x.bepa y2 = x.cepa z0 = x.~apa z1 = x.~bepa z2 = x.~cepa (p0,p1,p2) = a (apa=q0,bepa=q1,cepa=q2) = x def f15(x): return "%d %%" % x def f16(x,y,z): return "%*f %s" % (x,y,z) def f17(x): return "%s %f" % x ================================================ FILE: compiler/tests/test2.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # def fff (a, b, c): return len([a // c]) def abs(x : Number) -> Real: return x.__abs__() def all(it : Iterable[A]) -> bool: for x in it: if not x: return False return True def any(it : Iterable[A]) -> bool: for x in it: if x: return True return False def pow1 [A(Number)] (a: A, b: A) -> A: return Number.__pow__(a,b) pow2 : (int,int)->int def pow2 (a, b): return a**b def rev1(seq : Sequence[A]) -> Iterator[A]: return seq.__reversed__() def rev2(seq): return Sequence.__reversed__(seq) def rev3(seq): return seq.__reversed__() def fake [A(Real)] () -> A: raise ValueError("fake") def dflt(): x = fake() y = fake() return x/y > y def genrec(n): return genrec(n) + genrec(n-1) ================================================ FILE: compiler/tests/test3.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # actor Apa(): var v = 0 def m(): v = 0 b = Bepa() # b.meth() b.methods[0]() # b.bepa() return 23 actor Bepa(): var w = 0 # bepa : action() -> None def bepa(): w -= 1 methods : list[action()->None] methods = [] # meth : action() -> None meth = bepa def cepa(): a = Apa() x = await async a.m() ================================================ FILE: compiler/tests/test4.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # def m1(a): return a if a==a else a m2 : [A(Eq)] => (A) -> A def m2(a): return a x = m1(3) y = m2(4) actor Apa(): m3 : [A(Eq)] => (A) -> A pure def m3(a): return a def m4(a): return a class Bepa(): m5 : [A(Eq)] => (A) -> A def m5(self, a): return a def m6(self, a): return a+1 ================================================ FILE: compiler/tests/test5.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # protocol Apa (Eq, Plus): @staticmethod apa : [C(Ord)] => (Self,Self,C) -> bool @staticmethod bepa : (Self,Self) -> bool cepa : [C(Ord)] => (int,C) -> bool def apa(a,b,c): return a == b def __add__(a,b): return a extension bool (Apa): def bepa(a,b): return a == b def __add__(a,b): return b def __eq__(a,b): return False def __ne__(a,b): return not a==b def cepa(self,i,c): return False extension list[A(Eq)] (Apa): def bepa(a,b): return a == b def __eq__(a,b): if len(a) != len(b): return False for x,y in zip(a,b): if x != y: return False return True def __ne__(a,b): return not a==b def cepa(self,i,c): return False protocol What (Iterable[int], Real): pass protocol Who (Iterable[int], Ord): pass extension int (What): pass extension int (Who): pass ================================================ FILE: compiler/tests/test6.act ================================================ def f1(x): return x or "default" def f2(x): return x or 42 def f2b(x: int): return x or 42 def f3(x: ?int): return x or None def f4(x: int, y: ?int): return x or y def f5(x, y): return x or y def f6(x, y): return x and y/x def f7(x): return not x def f8(x): return x and True def f9(x: str): return x and True def f10(x): return x and 7 % x or 42 def g(x, y, z): if x: return 0 if not y: return 1 if x and y: return 2 if y or x: return 3 if x or y and z: return 4 return -1 ================================================ FILE: compiler/tests/tuples.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # t1 = (3,6,'a') t2 = (4,*f(y)) (a,x,*b) = (1,2,3,4,5) def f(): s = 0 for i in (k*k for k in range(1,5)) : s+=i return 7,4+5, for i in 3,4,*s: pass ================================================ FILE: compiler/tools/ld-wrapper.sh ================================================ #!/usr/bin/env bash set -euo pipefail real_linker="${ACTON_REAL_LD:-gcc}" state="static" arch="$(uname -m 2>/dev/null || true)" allow_dynamic_glibc=false case "$arch" in aarch64|arm64|x86_64|amd64) allow_dynamic_glibc=true ;; esac args=() args+=("-Wl,-Bstatic") gcc_lib_path() { local lib="$1" local lib_path lib_path="$(gcc -print-file-name="$lib" 2>/dev/null || true)" if [[ -n "$lib_path" && "$lib_path" != "$lib" ]]; then echo "$lib_path" return 0 fi return 1 } add_static_gcc_lib() { local archive="$1" local fallback="$2" local archive_path if archive_path="$(gcc_lib_path "$archive")"; then args+=("$archive_path") else args+=("-l:$fallback") fi } normalize_lib() { local lib="$1" if [[ "$lib" == :lib* ]]; then local name="${lib#:lib}" if [[ "$name" == *.so* ]]; then echo "${name%%.so*}" return fi if [[ "$name" == *.a ]]; then echo "${name%.a}" return fi fi echo "$lib" } handle_lib() { local lib="$1" local lib_key lib_key="$(normalize_lib "$lib")" if [[ "$lib_key" == "z" ]]; then if [[ "$state" != "static" ]]; then args+=("-Wl,-Bstatic") state="static" fi add_static_gcc_lib libz.a libz.a return fi if [[ "$lib_key" == "gmp" ]]; then if [[ "$state" != "static" ]]; then args+=("-Wl,-Bstatic") state="static" fi add_static_gcc_lib libgmp.a libgmp.a return fi if [[ "$lib_key" == "stdc++" ]]; then if [[ "$state" != "static" ]]; then args+=("-Wl,-Bstatic") state="static" fi add_static_gcc_lib libstdc++.a libstdc++.a add_static_gcc_lib libgcc_eh.a libgcc_eh.a return fi if [[ "$lib_key" == "tinfo" ]]; then if [[ "$state" != "static" ]]; then args+=("-Wl,-Bstatic") state="static" fi add_static_gcc_lib libtinfo.a libtinfo.a return fi if [[ "$allow_dynamic_glibc" == true ]]; then case "$lib_key" in c|m|dl|pthread|rt|util) if [[ "$state" != "dynamic" ]]; then args+=("-Wl,-Bdynamic") state="dynamic" fi args+=("-l${lib}") return ;; esac fi if [[ "$lib_key" == "gcc_s" ]]; then if [[ "$state" != "static" ]]; then args+=("-Wl,-Bstatic") state="static" fi add_static_gcc_lib libgcc_eh.a libgcc_eh.a return fi if [[ "$state" != "static" ]]; then args+=("-Wl,-Bstatic") state="static" fi args+=("-l${lib}") } process_arg() { local arg="$1" case "$arg" in @*) local rsp="${arg#@}" if [[ -f "$rsp" ]]; then while IFS= read -r line; do [[ -z "$line" ]] && continue if [[ "$line" == \"*\" && "$line" == *\" ]]; then line="${line:1:${#line}-2}" line="${line//\\\\/\\}" line="${line//\\\"/\"}" fi process_arg "$line" done < "$rsp" else args+=("$arg") fi ;; -Wl,*) IFS=',' read -r -a wl_opts <<< "${arg#-Wl,}" for opt in "${wl_opts[@]}"; do case "$opt" in -Bstatic|-Bdynamic) ;; -l*) handle_lib "${opt#-l}" ;; -u\ *) args+=("-Wl,-u" "-Wl,${opt#-u }") ;; *) if [[ "$opt" == *" "* ]]; then for part in $opt; do args+=("-Wl,$part") done else args+=("-Wl,$opt") fi ;; esac done ;; -l*) handle_lib "${arg#-l}" ;; -Wl,-Bstatic|-Wl,-Bdynamic) # Handled by this wrapper. ;; *) args+=("$arg") ;; esac } for arg in "$@"; do process_arg "$arg" done if [[ "$allow_dynamic_glibc" == true && "$state" != "dynamic" ]]; then args+=("-Wl,-Bdynamic") state="dynamic" fi exec "$real_linker" "${args[@]}" ================================================ FILE: compiler/tools/zig-cc.sh ================================================ #!/usr/bin/env bash set -euo pipefail ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)" ZIG="${ROOT}/dist/zig/zig" run_zig_with_lock() { if ! command -v flock >/dev/null 2>&1; then echo "flock is required for Linux Zig compiler wrapper serialization" >&2 return 1 fi local lock_root="${ZIG_GLOBAL_CACHE_DIR:-${TMPDIR:-/tmp}/acton-zig-global-cache}" mkdir -p "$lock_root" flock "$lock_root/acton-zig-cc.lock" "${ZIG}" "$@" } gcc_lib_path() { local lib="$1" local lib_path lib_path="$(gcc -print-file-name="$lib" 2>/dev/null || true)" if [[ -n "$lib_path" && "$lib_path" != "$lib" ]]; then echo "$lib_path" return 0 fi return 1 } add_system_include_dirs() { local multiarch args+=("-idirafter" "/usr/include") multiarch="$(gcc -print-multiarch 2>/dev/null || true)" if [[ -n "$multiarch" && -d "/usr/include/$multiarch" ]]; then args+=("-idirafter" "/usr/include/$multiarch") fi } add_arch_feature_args() { case "${ZIG_ARCH}" in x86_64) args+=("-Xclang" "-target-feature" "-Xclang" "+evex512") ;; esac } rewrite_lib_arg() { local arg="$1" local lib_path case "$arg" in -lgmp|-l:libgmp.a) if lib_path="$(gcc_lib_path libgmp.a)"; then echo "$lib_path" else echo "$arg" fi ;; -lz|-l:libz.a) if lib_path="$(gcc_lib_path libz.a)"; then echo "$lib_path" else echo "$arg" fi ;; -lstdc++|-l:libstdc++.a) if lib_path="$(gcc_lib_path libstdc++.a)"; then echo "$lib_path" else echo "$arg" fi ;; -ltinfo|-l:libtinfo.a) if lib_path="$(gcc_lib_path libtinfo.a)"; then echo "$lib_path" else echo "$arg" fi ;; *) echo "$arg" ;; esac } process_arg() { local arg="$1" case "$arg" in @*) local rsp="${arg#@}" if [[ -f "$rsp" ]]; then local line while IFS= read -r line || [[ -n "$line" ]]; do [[ -z "$line" ]] && continue if [[ "$line" == \"*\" && "$line" == *\" ]]; then line="${line:1:${#line}-2}" line="${line//\\\\/\\}" line="${line//\\\"/\"}" fi process_arg "$line" done < "$rsp" else args+=("$(rewrite_lib_arg "$arg")") fi ;; *) args+=("$(rewrite_lib_arg "$arg")") ;; esac } case "$(uname -s)" in Linux) ARCH="$(uname -m)" case "${ARCH}" in x86_64) ZIG_ARCH=x86_64 ;; aarch64|arm64) ZIG_ARCH=aarch64 ;; *) echo "Unsupported architecture for Linux: ${ARCH}" >&2; exit 1 ;; esac GLIBC_VERSION="${ACTON_ZIG_GLIBC_VERSION:-2.31}" args=() add_system_include_dirs add_arch_feature_args for arg in "$@"; do process_arg "$arg" done run_zig_with_lock cc -target "${ZIG_ARCH}-linux-gnu.${GLIBC_VERSION}" "${args[@]}" ;; *) exec "${ZIG}" cc "$@" ;; esac ================================================ FILE: compiler/tools/zig-cxx.sh ================================================ #!/usr/bin/env bash set -euo pipefail ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)" ZIG="${ROOT}/dist/zig/zig" run_zig_with_lock() { if ! command -v flock >/dev/null 2>&1; then echo "flock is required for Linux Zig compiler wrapper serialization" >&2 return 1 fi local lock_root="${ZIG_GLOBAL_CACHE_DIR:-${TMPDIR:-/tmp}/acton-zig-global-cache}" mkdir -p "$lock_root" flock "$lock_root/acton-zig-cc.lock" "${ZIG}" "$@" } gcc_lib_path() { local lib="$1" local lib_path lib_path="$(gcc -print-file-name="$lib" 2>/dev/null || true)" if [[ -n "$lib_path" && "$lib_path" != "$lib" ]]; then echo "$lib_path" return 0 fi return 1 } add_system_include_dirs() { local multiarch args+=("-idirafter" "/usr/include") multiarch="$(gcc -print-multiarch 2>/dev/null || true)" if [[ -n "$multiarch" && -d "/usr/include/$multiarch" ]]; then args+=("-idirafter" "/usr/include/$multiarch") fi } add_arch_feature_args() { case "${ZIG_ARCH}" in x86_64) args+=("-Xclang" "-target-feature" "-Xclang" "+evex512") ;; esac } rewrite_lib_arg() { local arg="$1" local lib_path case "$arg" in -lgmp|-l:libgmp.a) if lib_path="$(gcc_lib_path libgmp.a)"; then echo "$lib_path" else echo "$arg" fi ;; -lz|-l:libz.a) if lib_path="$(gcc_lib_path libz.a)"; then echo "$lib_path" else echo "$arg" fi ;; -lstdc++|-l:libstdc++.a) if lib_path="$(gcc_lib_path libstdc++.a)"; then echo "$lib_path" else echo "$arg" fi ;; -ltinfo|-l:libtinfo.a) if lib_path="$(gcc_lib_path libtinfo.a)"; then echo "$lib_path" else echo "$arg" fi ;; *) echo "$arg" ;; esac } process_arg() { local arg="$1" case "$arg" in @*) local rsp="${arg#@}" if [[ -f "$rsp" ]]; then local line while IFS= read -r line || [[ -n "$line" ]]; do [[ -z "$line" ]] && continue if [[ "$line" == \"*\" && "$line" == *\" ]]; then line="${line:1:${#line}-2}" line="${line//\\\\/\\}" line="${line//\\\"/\"}" fi process_arg "$line" done < "$rsp" else args+=("$(rewrite_lib_arg "$arg")") fi ;; *) args+=("$(rewrite_lib_arg "$arg")") ;; esac } case "$(uname -s)" in Linux) ARCH="$(uname -m)" case "${ARCH}" in x86_64) ZIG_ARCH=x86_64 ;; aarch64|arm64) ZIG_ARCH=aarch64 ;; *) echo "Unsupported architecture for Linux: ${ARCH}" >&2; exit 1 ;; esac GLIBC_VERSION="${ACTON_ZIG_GLIBC_VERSION:-2.31}" args=() add_system_include_dirs add_arch_feature_args for arg in "$@"; do process_arg "$arg" done run_zig_with_lock c++ -target "${ZIG_ARCH}-linux-gnu.${GLIBC_VERSION}" "${args[@]}" ;; *) exec "${ZIG}" c++ "$@" ;; esac ================================================ FILE: completion/acton.bash-completion ================================================ source <(acton --bash-completion-script `which acton`) ================================================ FILE: debian/acton.bash-completion ================================================ source <(acton --bash-completion-script `which acton`) ================================================ FILE: debian/changelog.in ================================================ acton (VERSION) DEB_DIST; urgency=medium * See CHANGELOG.md -- Kristian Larsson Mon, 13 Sep 2021 22:06:08 +0200 ================================================ FILE: debian/control ================================================ Source: acton Section: devel Priority: optional Maintainer: Kristian Larsson Build-Depends: bash-completion, debhelper-compat (= 13), g++, haskell-stack, libgmp-dev, libncurses-dev, make, zlib1g-dev Standards-Version: 4.6.0 Homepage: http://www.acton-lang.org Rules-Requires-Root: no Package: acton Architecture: any Depends: libc6 (>= 2.27), ${shlibs:Depends}, ${misc:Depends} Description: Acton Programming Language An awesome programming language. ================================================ FILE: debian/copyright ================================================ Package created by Kristian Larsson (kll) on Sun, 12 Sep 2021 08:23:00 +0200. Upstream Author: Johan Nordlander (nordlander) Andrei Agapi (aagapi) Kristian Larsson (kll) Files: * Copyright: 2019-2021 Data Ductus AB 2019-2021 Deutsche Telekom AG License: BSD-3-clause License: BSD-3-clause Copyright (C) 2019-2021 Data Ductus AB Copyright (C) 2019-2021 Deutsche Telekom AG Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: debian/rules ================================================ #!/usr/bin/make -f # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. export DH_VERBOSE = 1 # see FEATURE AREAS in dpkg-buildflags(1) #export DEB_BUILD_MAINT_OPTIONS = hardening=+all # see ENVIRONMENT in dpkg-buildflags(1) # package maintainers to append CFLAGS #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic # package maintainers to append LDFLAGS #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed %: dh $@ --parallel --with bash-completion override_dh_auto_test: @echo "Skipping tests" # Do not strip override_dh_strip: @echo "Skipping strip" # dwz in our CI package builder does not support DWARF v5 emitted by Zig 0.15. override_dh_dwz: @echo "Skipping dwz" # Force a legacy-compatible .deb compression format. # Newer dpkg defaults may emit control.tar.zst, which Debian 11 cannot unpack. override_dh_builddeb: dh_builddeb -- -Zxz --uniform-compression # dh_make generated override targets # This is example for Cmake (See https://bugs.debian.org/641051 ) #override_dh_auto_configure: # dh_auto_configure -- \ # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) ================================================ FILE: debian/watch ================================================ version=4 # GitHub hosted projects opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%-$1.tar.gz%" \ https://github.com/actonlang/acton/tags \ (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate ================================================ FILE: docs/acton-dev-guide/.gitignore ================================================ book ================================================ FILE: docs/acton-dev-guide/README.md ================================================ # Acton Developer Guide ## Writers Guide ```sh mdbook serve ``` ================================================ FILE: docs/acton-dev-guide/book.toml ================================================ [book] title = "Acton Developer Guide" authors = [] language = "en" multilingual = false preferred-dark-theme = "ayu" src = "src" site-url = "/learn/acton-dev-guide/" git-repository-url = "https://github.com/actonlang/acton" git-repository-icon = "fa-github" edit-url-template = "https://github.com/actonlang/acton/edit/master/docs/acton-dev-guide/{path}" [preprocessor.tabs] [preprocessor.svgbob] text_width = 8.0 text_height = 16.0 class = "bob" font_family = "arial" font_size = 14 stroke_width = 2.0 # there's using css-variables from theme: stroke_color = "var(--fg)" # see default theme / variables.css background_color = "transparent" # also useful `var(--bg)` [preprocessor.admonish] command = "mdbook-admonish" assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install` [output.html] additional-css = ["svgbob.css", "theme/tabs.css", "./mdbook-admonish.css", "theme/sbscode.css", "theme/skill-slider.css", "theme/content-width.css"] additional-js = ["theme/tabs.js", "theme/sbscode_copy.js", "theme/skill-slider.js"] [output.html.fold] enable = true ================================================ FILE: docs/acton-dev-guide/mdbook-admonish.css ================================================ @charset "UTF-8"; :is(.admonition) { display: flow-root; margin: 1.5625em 0; padding: 0 1.2rem; color: var(--fg); page-break-inside: avoid; background-color: var(--bg); border: 0 solid black; border-inline-start-width: 0.4rem; border-radius: 0.2rem; box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); } @media print { :is(.admonition) { box-shadow: none; } } :is(.admonition) > * { box-sizing: border-box; } :is(.admonition) :is(.admonition) { margin-top: 1em; margin-bottom: 1em; } :is(.admonition) > .tabbed-set:only-child { margin-top: 0; } html :is(.admonition) > :last-child { margin-bottom: 1.2rem; } a.admonition-anchor-link { display: none; position: absolute; left: -1.2rem; padding-right: 1rem; } a.admonition-anchor-link:link, a.admonition-anchor-link:visited { color: var(--fg); } a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { text-decoration: none; } a.admonition-anchor-link::before { content: "§"; } :is(.admonition-title, summary.admonition-title) { position: relative; min-height: 4rem; margin-block: 0; margin-inline: -1.6rem -1.2rem; padding-block: 0.8rem; padding-inline: 4.4rem 1.2rem; font-weight: 700; background-color: rgba(68, 138, 255, 0.1); print-color-adjust: exact; -webkit-print-color-adjust: exact; display: flex; } :is(.admonition-title, summary.admonition-title) p { margin: 0; } html :is(.admonition-title, summary.admonition-title):last-child { margin-bottom: 0; } :is(.admonition-title, summary.admonition-title)::before { position: absolute; top: 0.625em; inset-inline-start: 1.6rem; width: 2rem; height: 2rem; background-color: #448aff; print-color-adjust: exact; -webkit-print-color-adjust: exact; mask-image: url('data:image/svg+xml;charset=utf-8,'); -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-size: contain; content: ""; } :is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link { display: initial; } details.admonition > summary.admonition-title::after { position: absolute; top: 0.625em; inset-inline-end: 1.6rem; height: 2rem; width: 2rem; background-color: currentcolor; mask-image: var(--md-details-icon); -webkit-mask-image: var(--md-details-icon); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-size: contain; content: ""; transform: rotate(0deg); transition: transform 0.25s; } details[open].admonition > summary.admonition-title::after { transform: rotate(90deg); } :root { --md-details-icon: url("data:image/svg+xml;charset=utf-8,"); } :root { --md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,"); } :is(.admonition):is(.admonish-note) { border-color: #448aff; } :is(.admonish-note) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(68, 138, 255, 0.1); } :is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before { background-color: #448aff; mask-image: var(--md-admonition-icon--admonish-note); -webkit-mask-image: var(--md-admonition-icon--admonish-note); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) { border-color: #00b0ff; } :is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 176, 255, 0.1); } :is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00b0ff; mask-image: var(--md-admonition-icon--admonish-abstract); -webkit-mask-image: var(--md-admonition-icon--admonish-abstract); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-info, .admonish-todo) { border-color: #00b8d4; } :is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 184, 212, 0.1); } :is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00b8d4; mask-image: var(--md-admonition-icon--admonish-info); -webkit-mask-image: var(--md-admonition-icon--admonish-info); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) { border-color: #00bfa5; } :is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 191, 165, 0.1); } :is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00bfa5; mask-image: var(--md-admonition-icon--admonish-tip); -webkit-mask-image: var(--md-admonition-icon--admonish-tip); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) { border-color: #00c853; } :is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 200, 83, 0.1); } :is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00c853; mask-image: var(--md-admonition-icon--admonish-success); -webkit-mask-image: var(--md-admonition-icon--admonish-success); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) { border-color: #64dd17; } :is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(100, 221, 23, 0.1); } :is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before { background-color: #64dd17; mask-image: var(--md-admonition-icon--admonish-question); -webkit-mask-image: var(--md-admonition-icon--admonish-question); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) { border-color: #ff9100; } :is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(255, 145, 0, 0.1); } :is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before { background-color: #ff9100; mask-image: var(--md-admonition-icon--admonish-warning); -webkit-mask-image: var(--md-admonition-icon--admonish-warning); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) { border-color: #ff5252; } :is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(255, 82, 82, 0.1); } :is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before { background-color: #ff5252; mask-image: var(--md-admonition-icon--admonish-failure); -webkit-mask-image: var(--md-admonition-icon--admonish-failure); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-danger, .admonish-error) { border-color: #ff1744; } :is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(255, 23, 68, 0.1); } :is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before { background-color: #ff1744; mask-image: var(--md-admonition-icon--admonish-danger); -webkit-mask-image: var(--md-admonition-icon--admonish-danger); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-bug) { border-color: #f50057; } :is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(245, 0, 87, 0.1); } :is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before { background-color: #f50057; mask-image: var(--md-admonition-icon--admonish-bug); -webkit-mask-image: var(--md-admonition-icon--admonish-bug); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-example) { border-color: #7c4dff; } :is(.admonish-example) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(124, 77, 255, 0.1); } :is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before { background-color: #7c4dff; mask-image: var(--md-admonition-icon--admonish-example); -webkit-mask-image: var(--md-admonition-icon--admonish-example); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-quote, .admonish-cite) { border-color: #9e9e9e; } :is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(158, 158, 158, 0.1); } :is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before { background-color: #9e9e9e; mask-image: var(--md-admonition-icon--admonish-quote); -webkit-mask-image: var(--md-admonition-icon--admonish-quote); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } .navy :is(.admonition) { background-color: var(--sidebar-bg); } .ayu :is(.admonition), .coal :is(.admonition) { background-color: var(--theme-hover); } .rust :is(.admonition) { background-color: var(--sidebar-bg); color: var(--sidebar-fg); } .rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { color: var(--sidebar-fg); } ================================================ FILE: docs/acton-dev-guide/src/SUMMARY.md ================================================ # Summary - [Overview](index.md) - [Getting started](getting_started.md) - [Repository layout](getting_started/repo_layout.md) - [Build and run](getting_started/build.md) - [Tests](getting_started/tests.md) - [Debugging](getting_started/debugging.md) - [Compiler](compiler/index.md) - [Incremental compilation](compiler/incremental_compilation.md) - [Imports and environments](compiler/imports_and_envs.md) - [Project dependencies](compiler/project_dependencies.md) - [Test result cache](compiler/test_cache.md) - [Passes](compiler/passes/index.md) - [Parse](compiler/passes/parse.md) - [Kinds check](compiler/passes/kinds.md) - [Type check](compiler/passes/type_check.md) - [Normalize](compiler/passes/normalize.md) - [Deactorize](compiler/passes/deactorize.md) - [CPS](compiler/passes/cps.md) - [Lambda lift](compiler/passes/lambda_lift.md) - [Boxing](compiler/passes/boxing.md) - [Codegen](compiler/passes/codegen.md) - [Builtins](builtins/index.md) - [Builtin types](builtins/types.md) - [Builtin functions](builtins/functions.md) - [FFI hooks](builtins/ffi.md) - [Runtime](runtime/index.md) - [Scheduler](runtime/scheduler.md) - [Actors](runtime/actors.md) - [Memory and GC](runtime/memory.md) - [Tooling](tooling/index.md) - [Testing harness](tooling/testing.md) - [Design notes](design/index.md) - [Capabilities](design/capabilities.md) - [Concurrency model](design/concurrency.md) ================================================ FILE: docs/acton-dev-guide/src/builtins/ffi.md ================================================ # FFI hooks Explain the interfaces between builtins and external C/Zig code. Include the conventions for naming, memory ownership, and error handling. ================================================ FILE: docs/acton-dev-guide/src/builtins/functions.md ================================================ # Builtin functions Describe how builtin functions are declared and connected to runtime code. Call out any special casing in the compiler or optimizer. ================================================ FILE: docs/acton-dev-guide/src/builtins/index.md ================================================ # Builtins This section explains how builtins are modeled, where they live in the repository, and how they map to runtime implementations. ================================================ FILE: docs/acton-dev-guide/src/builtins/types.md ================================================ # Builtin types Document how core types are defined, their runtime layout, and any compiler hooks. Include guidance for adding or modifying a builtin type. ================================================ FILE: docs/acton-dev-guide/src/compiler/imports_and_envs.md ================================================ # Imports and Environments This note explains how imports move through the compiler today. The important distinction is that there are two related but different mechanisms: - graph discovery in `Acton.Compile`, which decides module ordering and cache reuse - environment materialization in `Acton.Env`, which makes imported modules available to kinds/type checking If those two are conflated, it becomes hard to reason about missing imports, stale `.ty` reuse, or why a module can be present in the scheduler but still need more imports loaded into the active environment. ## Environment layers There are three environment layers worth keeping separate when discussing the compiler. ### Base environment `Acton.Env.initEnv` constructs the base `Env0`. It always contains `prim`, and in normal compilation it also loads `__builtin__` from `__builtin__.ty`. This base environment is not tied to any one module. It is the starting point for later compilation work. ### Shared module cache During a compile run, the scheduler keeps an accumulated environment snapshot of finished modules. In `Acton.Compile.compileTasks`, each completed module extends that snapshot with: ```haskell Acton.Env.addMod (tkMod mnDone) (frIfaceTE fr) (frDoc fr) envAcc ``` This shared cache stores loaded module interfaces in `modules`. It does not store the current module's local names, and it should not be thought of as "the current type-checker env". It is a shared cache of interfaces that later tasks start from. ### Current-module import overlay When the compiler is about to kinds/type-check a module, it takes the shared snapshot and overlays the module's imports onto it with `Acton.Env.mkEnv`. `mkEnv` does not add the current module's own declarations. It only processes the module's `import` statements. Later, the type checker sets `thismod` and defines the module's own top-level names in a more specialized environment used within the pass. So the rough model is: 1. start from the shared module cache 2. load the imported modules needed for this module 3. type-check the module and derive its interface 4. add that interface back into the shared module cache ## Scheduler discovery versus import loading The scheduler in `Acton.Compile` does not eagerly materialize every imported module into the active environment. Instead it does header-first discovery: - `readModuleTask` reads the `.ty` header when possible and produces a cheap `TyTask` - otherwise it parses the source and produces an `ActonTask` - `buildGlobalTasks` uses the task's direct imports to build provider edges Those provider edges only cover imports that can be resolved to modules inside the discovered project graph. This is deliberate: they are scheduler edges, not the full transitive import closure of the final type-checker environment. This matters for standard library modules and any other imports that are not represented as in-graph provider tasks. Such modules still have to be made available later through `Acton.Env`. ## When `.ty` headers are read The compiler reads `.ty` data in two different modes. ### Header-only reads Header reads are used for cheap decisions: - module freshness - direct import names for graph construction - module public and implementation hashes - per-name dependency hash snapshots - roots, tests, and docstrings This is the path used by `readModuleTask` and the various cache lookups in `Acton.Compile`. ### Full `.ty` reads Full reads are used when the compiler needs actual interface contents or the typed module: - reusing an interface from a fresh cached module - implementation-hash refresh - codegen refresh Reading a full `.ty` does not by itself reconstruct the import closure in the active environment. It only gives the caller the stored interface and typed module payload. ## How transitive imports become available The transitive import closure is reconstructed through `Acton.Env.mkEnv`, `impModule`, `doImp`, and `subImp`. When a module imports another module: 1. `mkEnv` walks the AST import list 2. `impModule` delegates to `doImp` 3. `doImp` finds the imported module's `.ty` 4. `doImp` follows the imported module's recorded imports 5. only then does it return the imported module interface This is the mechanism that turns a direct import into a transitive environment closure suitable for kinds and type checking. An important invariant is that a cached direct module must still restore its own recorded imports. The shared scheduler env stores interfaces in `modules`, but that cache does not itself contain the imported module's import list. For that reason, `doImp` must still consult the cached module's `.ty` header and recurse through its recorded imports even when the direct module is already present in `modules`. Without that step, the compiler can end up in a state where: - the direct module is present in the shared module cache - the direct module's transitive imports are not - later type checking sees the direct module but fails when its public interface refers to a transitive dependency ## Practical debugging rules When debugging import failures, it helps to ask which layer is failing: - Is the module missing from graph discovery? Then look at `readModuleTask`, `.ty` headers, and `buildGlobalTasks`. - Is the module outside the project graph but still needed for type checking? Then look at `mkEnv` and `doImp`. - Is a cached module present but its transitives missing? Then the issue is in environment materialization, not scheduler ordering. - Is a full `.ty` being read but imports still not appearing? Then check whether the caller is only decoding interface payload rather than invoking the import loader. ## Related pages - [Compiler overview](index.md) - [Incremental compilation](incremental_compilation.md) - [Type check](passes/type_check.md) ================================================ FILE: docs/acton-dev-guide/src/compiler/incremental_compilation.md ================================================ # Incremental Compilation See also [Imports and environments](imports_and_envs.md) for the distinction between scheduler dependency discovery and the actual import closure loaded into the type-checker environment. Acton compiles a whole program by walking a dependency graph that spans the root project and all of its dependencies. The scheduler in `Acton.Compile` builds this total graph, runs the front passes (parse, kinds, types) in topological order, and queues back passes as soon as a module's front passes finish. Front work gates downstream modules, while back jobs overlap ongoing front work. The scheduler runs tasks concurrently with async jobs across worker threads. In watch/LSP mode, each change event bumps a generation id, cancels in-flight tasks, and drops stale diagnostics or back jobs that still carry the old generation, so we can react to new changes without waiting for obsolete work to finish. Interface files and content hashes tell the scheduler what work it can safely reuse. `.ty` interface headers store hashes and snapshots of dependencies and their hashes. It is cheap both to compute hashes and to read and compare them. If the hashes show no relevant change, the compiler can skip parsing, type checking, or back passes for large parts of the graph. At the module level we store **moduleSrcBytesHash**, **modulePubHash**, and **moduleImplHash**. The source-bytes hash (**moduleSrcBytesHash**) is the SHA-256 of the raw source bytes and is used to decide whether a cached `.ty` header is still valid; if it changes, we must re-parse the `.act` file and rerun front passes for that module. Reading the file is done at GB/s on modern NVMe hardware and hashing is typically running at roughly the same speed on modern CPUs. The public hash (**modulePubHash**) is derived from the module's public-name `pubHash` values (which already include any external signature dependencies). The implementation hash (**moduleImplHash**) is derived from per-name `implHash` values; it is stored in the `.ty` header and written into generated `.c`/`.h` files as an "Acton impl hash" tag. If the tag is missing or mismatched, we rerun back passes even if no other hashes changed. Hashing within a module is done per top-level name. A hashable unit is a `Def`, `Actor`, `Class`, `Protocol`, `Extension`, or any top-level value introduced by a binding statement such as `a = 123` or `b, c = f()`. Entries are keyed by the local `Name`; external references are stored as `QName` (canonicalized to `GName` with `unalias`), and extensions use the derived name from `extensionName`. For now class/actor implementation hashes are coarse and cover the entire body; per-method hashing can refine this later. Each unit has three hashes. **srcHash** is the hash of the kinds-checked AST for that name (pretty-printed), and is the earliest signal that a single declaration changed. We use the kinds-checked form because it is the first pass that normalizes type-level syntax (implicit type arguments, canonical kind structure) without paying the cost of full type inference. Hashing the raw parsed AST would make equivalent signatures hash differently and trigger needless rebuilds. **pubHash** is the hash of the unit's public interface (doc-free `NameInfo`) combined with the public hashes of external declarations referenced by its type signature. **implHash** is the hash of the unit's implementation combined with the implementation hashes of external declarations referenced from the body. Because we hash pretty-printed source, docstrings currently influence `implHash`; we can tighten the normalization later without changing the overall model. Name hashes depend on `NameInfo`. The type checker environment (`teAll`) is authoritative for user-facing declarations, but it does not include compiler- generated names (for example, protocol lowering emits classes such as `MinusD_Number`). The typed AST does include those generated names, so we derive their `NameInfo` with `QuickType.envOf`. Conversely, `envOf` omits `Protocol` and `Extension` entries because type inference translates them away. To cover both, hashing uses the union of `teAll` and `QuickType.envOf` as its name-info map, ensuring generated names appear in `.ty` and still keeping protocol and extension hashes intact. To detect changes without recompiling, each per-name entry in `.ty` stores dependency snapshots. **pubDeps** is a list of `(QName, pubHash)` for external declarations referenced from the unit's type signature and from value-level uses, which is what triggers re-typechecking when a provider's public interface changes. **implDeps** is a list of `(QName, implHash)` referenced from the body and is what triggers codegen and test invalidation. Only external dependencies are stored; local dependencies are folded into the computed hash during compilation. Mutually recursive groups are hashed as a unit to avoid fixed-point iteration. We compute `selfPubHash`/`selfImplHash` for each unit, compute a `groupHash` from the sorted self-hashes plus all external dependency hashes of the group, and then finalize each unit as `H(selfHash || groupHash || unitKey)`. The `.ty` header stays ordered for fast reads: ``` version moduleSrcBytesHash modulePubHash moduleImplHash imports nameHashInfo -- per-name src/pub/impl hash + dep snapshots roots docstring nameInfo typedModule ``` A source change always re-runs front passes for that module. Downstream modules compare recorded `pubDeps` against current provider hashes; any delta triggers re-typechecking. Separately, `implDeps` changes cause back passes and tests to rerun even when public hashes are stable. Missing or stale `.c`/`.h` outputs also force back passes so codegen can recover. To see the decisions, run `acton build --verbose`; it prints stale reasons and per-name hash deltas. The snippets below abbreviate hashes to 8 hex digits for readability. **Implementation-only change.** Before: ```acton # a.act def foo(x: int) -> int: return x + 1 # b.act import a def bar() -> int: return a.foo(1) ``` After changing only the body of `foo`: ```acton # a.act def foo(x: int) -> int: return x + 2 ``` `srcHash(foo)` and `implHash(foo)` change while `pubHash(foo)` does not. Downstream modules keep their public hashes stable, so they do not re-typecheck but they do rerun back passes: ```text $ acton build --verbose Building project in /path/proj Resolving dependencies (fetching if missing)... Stale a: source changed Hash deltas a: ~foo{src 12fa0b1c -> 3e3485be, impl 4bf97616 -> f736da16} Finished type check of /path/proj/a 0.004 s Stale b: impl changes in a.foo 4bf97616 -> f736da16 (used by bar) Finished compilation of /path/proj/a 0.002 s Finished compilation of /path/proj/b 0.003 s ``` **Public signature change.** Before: ```acton # a.act def foo(x: int) -> int: return x + 1 # b.act import a def bar() -> int: return a.foo(1) ``` After changing the signature of `foo`: ```acton # a.act def foo(x: int) -> float: return float(x) # b.act import a def bar() -> float: return a.foo(1) ``` Here `pubHash(foo)` changes, so `modulePubHash(a)` changes and any dependent that recorded `a.foo` in `pubDeps` must re-typecheck: ```text $ acton build --verbose Building project in /path/proj Resolving dependencies (fetching if missing)... Stale a: source changed Hash deltas a: ~foo{src 2f1a8c9b -> 3a7bb6e1, pub 91c2efb8 -> 5e7d9b02, impl 11c0aa34 -> 6b3e42f1} Finished type check of /path/proj/a 0.004 s Stale b: pub changes in a.foo 91c2efb8 -> 5e7d9b02 (used by bar) Finished type check of /path/proj/b 0.005 s Finished compilation of /path/proj/a 0.002 s Finished compilation of /path/proj/b 0.003 s ``` **Codegen-only staleness.** If generated output is missing or mismatched, we rerun back passes even when hashes are unchanged. For example, deleting the outputs forces codegen to refresh: ```text $ rm out/types/b.c out/types/b.h $ acton build --verbose Building project in /path/proj Resolving dependencies (fetching if missing)... Stale b: generated code out of date {impl c missing -> 7aa13f90, h missing -> 7aa13f90} Finished compilation of /path/proj/b 0.003 s ``` **Non-propagating change.** Adding an unused import changes the module source bytes, so the module itself re-runs front passes, but downstream modules do not re-typecheck because no public hashes changed: ```acton # before (b.act) import a def bar() -> int: return a.foo() # after (b.act) import a import testing # unused def bar() -> int: return a.foo() ``` Known limitations include the lack of incremental typechecking within a module, coarse class/actor impl hashes, and docstrings affecting `implHash`. ================================================ FILE: docs/acton-dev-guide/src/compiler/index.md ================================================ # Compiler The compiler runs a fixed sequence of AST-to-AST transforms before finally generating C. The main entry point is `compiler/acton/Main.hs`, which wires the stages together via the `compiler/lib` modules listed below. All the real logic are contained in these modules and are thus accessible and usable as a library. The same AST data type is used throughout all compiler passes, making it easy to read and understand what each transformation does. See [Imports and environments](imports_and_envs.md) for how the scheduler, `.ty` headers, and the active type-checker environment fit together. See [Project dependencies](project_dependencies.md) for how Acton package dependencies and zig dependencies are discovered, fetched, and emitted into the generated Zig build files. See [Passes](passes/index.md) for the stage-by-stage pipeline and how front and back passes split the work. ================================================ FILE: docs/acton-dev-guide/src/compiler/passes/boxing.md ================================================ # Boxing Implementation lives in `compiler/lib/src/Acton/Boxing.hs`. Values in Acton are mostly boxed. The boxing pass can unbox values in certain situations, which can greatly improve performance by avoiding unnecessary boxing operations. The more we can unbox, the better, but it is at odds with generics and polymorphism. - Inserts explicit `Box`/`UnBox` nodes to model conversions between boxed runtime objects and unboxed machine values. - Introduces unboxed temporaries for numeric primitives (ints/uints/floats) so codegen can emit efficient C operations. - Rewrites selected builtin operations (arithmetic/comparisons, math functions, and some builtin methods) to operate on unboxed values and then re-box results. The pass keeps a map from boxed names to their unboxed counterparts in its environment and generates internal names using the `BoxPass` prefix. It also preserves boxed values where needed so later stages still see the expected surface semantics. ## Debugging ```sh acton --box path/to/file.act ``` ## Thoughts - Push unboxing further without changing the type system by operating late, after type-checking and lowering, where the AST is simpler and richly typed. - Treat unboxable primitives (bounded ints, floats, bool) as unboxed in locals, params, returns, and class fields, and only box/unbox at polymorphic boundaries. - Keep polymorphic code boxed; allow monomorphic code to be unboxed, with boxing inserted at call sites when crossing module boundaries or calling polymorphic functions. - Extend the pass to cover classes and cross-module calls; current behavior is limited to function bodies and initializers. ================================================ FILE: docs/acton-dev-guide/src/compiler/passes/codegen.md ================================================ # Codegen Implementation lives in `compiler/lib/src/Acton/CodeGen.hs`. ================================================ FILE: docs/acton-dev-guide/src/compiler/passes/cps.md ================================================ # CPS Implementation lives in `compiler/lib/src/Acton/CPS.hs`. ================================================ FILE: docs/acton-dev-guide/src/compiler/passes/deactorize.md ================================================ # Deactorize Implementation lives in `compiler/lib/src/Acton/Deactorizer.hs`. ================================================ FILE: docs/acton-dev-guide/src/compiler/passes/index.md ================================================ # Passes The compiler runs a fixed sequence of AST-to-AST transforms before finally generating C. The main entry point is `compiler/acton/Main.hs`, which wires the stages together via the `compiler/lib` modules listed below. All the real logic is contained in these modules and is thus accessible and usable as a library. The same AST data type is used throughout all compiler passes, making it easy to read and understand what each transformation does. ## Stages (in order) | Stage | Module | Description | | --- | --- | --- | | [Parse](parse.md) | `compiler/lib/src/Acton/Parser.hs` | | | [Kinds check](kinds.md) | `compiler/lib/src/Acton/Kinds.hs` | | | [Type check](type_check.md) | `compiler/lib/src/Acton/Types.hs`, `compiler/lib/src/Acton/TypeEnv.hs` | | | [Normalize](normalize.md) | `compiler/lib/src/Acton/Normalizer.hs` | | | [Deactorize](deactorize.md) | `compiler/lib/src/Acton/Deactorizer.hs` | | | [CPS](cps.md) | `compiler/lib/src/Acton/CPS.hs` | | | [Lambda lift](lambda_lift.md) | `compiler/lib/src/Acton/LambdaLifter.hs` | | | [Boxing](boxing.md) | `compiler/lib/src/Acton/Boxing.hs` | | | [Codegen](codegen.md) | `compiler/lib/src/Acton/CodeGen.hs` | | The final C source is compiled and linked by the Zig build system. For how imports are loaded before these passes run, see [Imports and environments](../imports_and_envs.md). ## Front vs back passes The pipeline is split into a front end and a back end. The scheduler runs all front passes across the dependency graph first, then queues back-pass work once type checking succeeds for a module. Front passes (1–3) are: - Parse - Kinds check - Type check These passes produce all user-facing diagnostics, write the module interface header (`.ty`), and compute public hashes used for incremental rebuilds. They also define the cross-module dependency edges: a module can only start once its imports have completed the front passes. Back passes (4–9) are: - Normalize - Deactorize - CPS - Lambda lift - Boxing - Codegen The back end consumes the typed module from the front end and emits C and header files (`.c`, `.h`). It does not introduce new user errors, so it can run after front completion and even in the background. The CLI waits for all back jobs to finish before invoking Zig; the LSP enqueues back jobs in the background and does not wait for them or run Zig. The shared orchestration lives in `compiler/lib/src/Acton/Compile.hs` and is used by both `acton` and the LSP server. ================================================ FILE: docs/acton-dev-guide/src/compiler/passes/kinds.md ================================================ # Kinds check Implementation lives in `compiler/lib/src/Acton/Kinds.hs`. ================================================ FILE: docs/acton-dev-guide/src/compiler/passes/lambda_lift.md ================================================ # Lambda lift Implementation lives in `compiler/lib/src/Acton/LambdaLifter.hs`. ================================================ FILE: docs/acton-dev-guide/src/compiler/passes/normalize.md ================================================ # Normalize Implementation lives in `compiler/lib/src/Acton/Normalizer.hs`. ================================================ FILE: docs/acton-dev-guide/src/compiler/passes/parse.md ================================================ # Parse Implementation lives in `compiler/lib/src/Acton/Parser.hs`. - Parses `.act` source into the core AST (`Module`). - Uses the Haskell Megaparsec library - Tracks parse context (top-level, actor, loop, etc.) to enforce where statements are allowed. - Attaches source locations so later stages can produce precise errors. The entry point is `parseModule`, which takes a module name, filename, and file contents, then returns the parsed `Module`. It also appends a trailing newline if the file is missing one to keep the parser consistent. ## Debugging Use compiler flags to inspect the parser output: ```sh acton --parse path/to/file.act acton --parse-ast path/to/file.act ``` ## Tests There are unit tests for the parser in ActonSpec.hs, in particular the string interpolation support is fairly well tested. Please add more tests. ## Thoughts - It is hard to write a parser. It is even harder to write a parser with good error reporting... and once you do, it's probably not going to perform very well. - Our parser has some good error reporting, in particular around string interpolation. It can be improved in other areas. The aspiration as always is super friendly error messages. - TODO: When we encounter errors, the parser should be able to recover and continue parsing the rest of the file. We'd need to mark such nodes as Bad nodes (I think the Bad name is a good one) and also accumulate a list of errors instead of immediately reporting errors and exiting ================================================ FILE: docs/acton-dev-guide/src/compiler/passes/type_check.md ================================================ # Type check The type checker follows a Hindley-Milner style and borrows the protocol model from Swift. Implementation lives in `compiler/lib/src/Acton/Types.hs` and `compiler/lib/src/Acton/TypeEnv.hs`. The type checker runs on top of an import-augmented environment produced by `Acton.Env.mkEnv`, not directly on the scheduler's raw module graph. See [Imports and environments](../imports_and_envs.md) for the environment layers and how transitive imports are materialized from `.ty` files. ================================================ FILE: docs/acton-dev-guide/src/compiler/project_dependencies.md ================================================ # Project Dependencies Acton has two different dependency layers during a build: - Acton package dependencies from `Build.act` `dependencies` - Zig package dependencies from `Build.act` `zig_dependencies` They are related, but they do not participate in the build in the same way. ## Discovery and fetch Project discovery in `Acton.Compile` only follows Acton package dependencies. Those edges determine the project graph used for module ordering, cache reuse, import visibility, and type-check planning. Zig dependencies are not Acton project edges. They do not contribute modules to the import graph and they are not used for project discovery. Fetch still needs them, though. For each reachable Acton project, the fetch phase downloads or copies both that project's package dependencies and its zig dependencies before later compile planning uses them. ## Generated `build.zig` inputs `acton build` generates a `build.zig` and `build.zig.zon` for the current project in `compiler/acton/Main.hs`. At that point Acton combines: - direct package dependencies of the current project - transitive package dependencies reachable through package dependencies - direct zig dependencies of the current project - transitive zig dependencies from all reachable Acton projects Transitive zig dependencies are flattened into the consuming project's generated Zig manifest because the generated build may need to link their declared artifacts directly. ### Example: one wrapper package Conceptually, a root project might look like this: ```text root └── package dep "lmdb" -> acton-lmdb └── zig dep "lmdb" -> raw LMDB zig package ``` That means the root project imports an Acton package named `lmdb`, while that package in turn links against a zig package also declared as `lmdb`. The generated root `build.zig.zon` needs both of them as sibling entries, so Acton emits separate local names: ```zig .dependencies = .{ .lmdb = .{ ... }, // Acton package dep .acton_zig_lmdb = .{ ... }, // underlying zig dep }, ``` The Acton package keeps the user-facing name `lmdb`. The zig package gets a generated local alias because both entries live in the same Zig dependency table. ## Local Zig names Zig dependency names are only local aliases inside one generated `build.zig.zon`. They are not global identities across the whole dependency tree. Acton therefore keeps package dependency names unchanged and assigns internal names to zig dependencies when rendering build metadata: - package dependencies keep their declared names - zig dependencies get generated names with an `acton_zig_` prefix - if multiple distinct zig dependencies would reuse the same local name, Acton appends a numeric suffix This means an Acton package dependency named `lmdb` can coexist with a zig dependency also declared as `lmdb`, and two different transitive zig packages that both use the local name `shared` can still appear together in one generated manifest. ### Example: colliding transitive zig names Consider this project graph: ```text root ├── package dep "dep_a" │ └── zig dep "shared" -> zig_common ├── package dep "dep_b" │ └── zig dep "shared" -> zig_common └── package dep "dep_c" └── zig dep "shared" -> zig_other ``` All three zig dependencies are named `shared` in their own local `Build.act`, but once they are flattened into the root manifest they become siblings. The generated root `build.zig.zon` therefore looks conceptually like: ```zig .dependencies = .{ .dep_a = .{ ... }, .dep_b = .{ ... }, .dep_c = .{ ... }, .acton_zig_shared = .{ ... }, // zig_common .acton_zig_shared_2 = .{ ... }, // zig_other }, ``` There is no `.acton_zig_shared_3`, because `dep_a` and `dep_b` refer to the same zig package identity and are deduplicated before local names are assigned. ## Deduplication Before assigning local zig names, Acton deduplicates zig dependency references by resolved identity plus Zig build options. Today that identity is derived from whichever source locator is present: - rebased path plus options - content hash plus options - URL plus options When two references resolve to the same identity, Acton emits one local zig dependency entry and merges the requested artifact names. When the identities differ, both dependencies stay present and receive separate local aliases. So collisions only matter among sibling entries in one generated `build.zig.zon`, and only after deduplication has decided whether two references are really the same package instance. ### Example: same package, different options Options are part of the zig dependency identity. So this conceptual tree: ```text root ├── package dep "tls_a" │ └── zig dep "mbedtls" -> same package, options { .pic = true } └── package dep "tls_b" └── zig dep "mbedtls" -> same package, options { .pic = false } ``` still produces two sibling zig entries in the root `build.zig.zon`, because the Zig build instances are not interchangeable: ```zig .dependencies = .{ .tls_a = .{ ... }, .tls_b = .{ ... }, .acton_zig_mbedtls = .{ ... }, // options { .pic = true } .acton_zig_mbedtls_2 = .{ ... }, // options { .pic = false } }, ``` ## Practical debugging rules - Import or type-check failures are usually about Acton package discovery, not zig dependencies. - Linker or `b.dependency(...)` lookup failures are usually about generated `build.zig` and `build.zig.zon` contents. - Root dependency pinning and `--dep` overrides apply to Acton package dependencies, not zig dependencies. ================================================ FILE: docs/acton-dev-guide/src/compiler/test_cache.md ================================================ # Test result cache Acton caches test results using per-name implementation hashes to decide when a test must be rerun. The cache is stored in `out/test/cache.json` and is updated after each `acton test` run. ## Run context hash Each run computes a context hash that captures inputs that affect test behavior without changing source code: - compiler version (`acton` version string) - target triple - optimize mode - test mode (run/perf) - test runner arguments (iteration and timing limits) The context hash is SHA-256 over the JSON-encoded context record. ## Per-test hash Each test’s run hash is SHA-256 over: ``` implHash || depsHash || contextHash ``` Where `implHash` is the per-name implementation hash from the module’s `.ty` header. `depsHash` is a hash of the test’s current implementation dependencies (`implDeps`), resolved to their latest impl hashes via the `.ty` headers on the search path. Test name resolution uses the `.ty` name hash map, and applies simple fallbacks for generated actor wrappers: - try the test name as-is - if it ends in `_wrapper`, try the name without the suffix - if it begins with `_test_`, try the name without the prefix If no implementation hash can be resolved, the test is always rerun. ## Cache format The cache file is JSON: ``` { "version": 1, "context": { ... }, "tests": { "module:testName": { "runHash": "...", "implHash": "...", "result": { ... } } } } ``` The `result` payload mirrors the test runner’s result fields (success/exception, failures/errors, iterations, and duration). ## Behavior - If the cached run hash matches the newly computed run hash, the test is normally skipped and its cached result is used. - Snapshot tests add one more guard: a cached result is only reused when the `snapshots/output/...` file exists, the current expected snapshot file has the same size as that output file, and the expected snapshot has an older modification time. If the output file is missing, the expected file changed or disappeared, or the metadata does not prove it is older than the last produced output, the test is rerun. - With `--no-cache`, cached results are ignored and all selected tests are run. - Cached failures and errors still contribute to the overall test exit code. - By default, cached successes are hidden from output; cached failures/errors are still shown. Use `--show-cached` to include cached successes. - Snapshot expected updates are written only for tests executed in the current run. - Snapshot outputs are written for reported tests (cached results reuse cached output). ================================================ FILE: docs/acton-dev-guide/src/design/capabilities.md ================================================ # Capabilities Explain the capability model, how it is represented in the compiler, and the invariants that enforce safety. ================================================ FILE: docs/acton-dev-guide/src/design/concurrency.md ================================================ # Concurrency model Document the concurrency semantics the compiler assumes and the runtime enforces. Include how scheduling and async boundaries interact with the type system. ================================================ FILE: docs/acton-dev-guide/src/design/index.md ================================================ # Design notes This section captures rationale and tradeoffs behind major design choices. Use it for decisions that are not obvious from code alone. ================================================ FILE: docs/acton-dev-guide/src/getting_started/build.md ================================================ # Build and run This repo builds the compiler (Haskell), runtime, and bundled deps into `dist/`. ## Prereqs - `stack` for Haskell builds (compiler + LSP) - `make`, `curl`, `tar`, `xz` (used by the Makefile) - Zig is downloaded automatically into `dist/zig` (version pinned in `Makefile`) ## Common targets ```sh make # build full distribution (compiler, runtime, deps) make dist/bin/acton # compiler + lsp-server-acton only (fast for compiler work) make dist/bin/actonc # compatibility symlink to acton ``` ## Running local binaries ```sh dist/bin/acton path/to/file.act dist/bin/acton build dist/bin/acton test dist/bin/actonc path/to/file.act # compatibility alias ``` - Prefer `dist/bin/*` to avoid accidentally using a globally installed Acton. - `make clean` removes build outputs; `make clean-all` also removes the Zig cache. ## Caching and build knobs - `ZIG_LOCAL_CACHE_DIR` controls Zig's cache location (defaults to `~/.cache/acton/zig-local-cache` when `HOME` is set). - `BUILD_RELEASE=1 make` stamps release versions; default builds get a timestamped version suffix. - On Linux, the Makefile uses Zig for the Stack/GHC C compiler path and pins the default glibc target to 2.31 for compatibility. - `ACTON_ZIG_GLIBC_VERSION` overrides the glibc version used for Stack/GHC linking on Linux. - Linux release builds should run in a builder with system static libraries no newer than the requested glibc target. ================================================ FILE: docs/acton-dev-guide/src/getting_started/debugging.md ================================================ # Debugging Capture the preferred debugging workflow for compiler and runtime changes. Include tips for logging, tracing, and inspecting intermediate compiler artifacts. ================================================ FILE: docs/acton-dev-guide/src/getting_started/repo_layout.md ================================================ # Repository layout Top-level directories are grouped by subsystem and build outputs. | Path | Purpose | | --- | --- | | `compiler/` | Acton compiler & LSP (`acton`, `lsp-server-acton`). Written in Haskell. | | `base/` | Builtins, RTS, and standard library sources. | | `backend/` | Distributed RTS database backend. | | `builder/` | Zig build system helper definitions. | | `bin/` | Small helper binaries/scripts (e.g. `runacton`). | | `completion/` | Shell completion assets. | | `deps/` | Vendored third-party sources used by the build. | | `deps-download/` | Cached dependency tarballs (generated). | | `dist/` | Build output and bundled distribution (generated). | | `docs/` | Documentation, like this dev guide. | | `examples/` | Example programs and snippets. | | `test/` | Integration tests, runtime/db harness, stdlib tests. | | `utils/` | Misc tooling, scripts, and dev helpers. | | `ecolift/` | Lifting the Acton ecosystem for new language features. | | `debian/` | Debian packaging. | | `homebrew/` | Homebrew formulae. | | `slides/` | Presentation material. | | `workspace/` | Scratch notes and experiments (not part of build). | ================================================ FILE: docs/acton-dev-guide/src/getting_started/tests.md ================================================ # Tests The top-level Makefile drives test execution and wires together compiler, stdlib, backend, and runtime suites. ## Run everything ```sh make test ``` This runs: - `stack test` for the compiler packages - stdlib tests (`make test-stdlib`) - backend tests (`make -C backend test`) - runtime/db tests (`make -C test`) ## Targeted suites ```sh make test-compiler make test-builtins make test-stdlib make test-rts make test-backend ``` ## Snapshot / acceptance tests Some compiler suites have explicit accept targets that update expected output: ```sh make test-incremental make test-incremental-accept make test-syntaxerrors make test-syntaxerrors-accept make test-typeerrors make test-typeerrors-accept ``` `test-incremental*` requires `dist/bin/acton` (it is built automatically by the target). `test-rebuild*` remains as an alias for the incremental suite. ## Project tests with acton Run tests for the current Acton project (expects a `Build.act` in the cwd): ```sh acton test ``` Example output: ```text $ acton test Building project in /path/to/project Final compilation step Finished final compilation step in 0.462 s Test results: c.bar: OK: 445 runs in 50.160ms c.foo: OK: 444 runs in 50.188ms All 2 tests passed ( 0.528 s) ``` By default, `acton test` shows only tests that ran in the current invocation; cached successes are hidden (cached failures/errors are still shown). Use `--show-cached` to include cached successes in the output. Use `--no-cache` to force all selected tests to execute instead of reusing cached results. ## Tips - Prefer `make test-compiler` when iterating on Haskell changes. - Use `dist/bin/acton test` for Acton project-level tests in other repos. ================================================ FILE: docs/acton-dev-guide/src/getting_started.md ================================================ # Getting started This section collects practical instructions for setting up a development environment, building the compiler, and running tests locally. ================================================ FILE: docs/acton-dev-guide/src/index.md ================================================ # Overview This book is an internal reference for the Acton compiler, runtime, builtins and tooling. It focuses on architecture, key invariants, and how to extend or debug the system. ## Who this is for - Contributors working on language, compiler, runtime etc - Maintainers of builtins and standard library - Anyone needing to understand internal behavior ================================================ FILE: docs/acton-dev-guide/src/runtime/actors.md ================================================ # Actors Explain runtime actor lifecycle, mailbox behavior, and supervision semantics. Reference any integration points with the compiler. ================================================ FILE: docs/acton-dev-guide/src/runtime/index.md ================================================ # Runtime This section covers the runtime system, scheduling model, and core services that the compiler targets. ================================================ FILE: docs/acton-dev-guide/src/runtime/memory.md ================================================ # Memory and GC Describe allocation strategy, garbage collection, and ownership conventions. Include debugging tips for leaks or performance regressions. ================================================ FILE: docs/acton-dev-guide/src/runtime/scheduler.md ================================================ # Scheduler Document the actor scheduler, queues, and fairness guarantees. Include relevant configuration knobs and metrics. ================================================ FILE: docs/acton-dev-guide/src/tooling/index.md ================================================ # Tooling This section documents developer-facing tools, scripts, and workflows used to build, test, and release Acton. ================================================ FILE: docs/acton-dev-guide/src/tooling/testing.md ================================================ # Testing harness Document the internal test runner, fixtures, and any custom assertions. Include guidance for adding new compiler or runtime tests. ================================================ FILE: docs/acton-dev-guide/svgbob.css ================================================ /* Ensure text is legible in all themes. */ svg text { fill: var(--fg); } ================================================ FILE: docs/acton-dev-guide/theme/content-width.css ================================================ /* Wider content area for better side-by-side code display */ /* Increase main content width and center it */ .content main { max-width: 900px !important; margin: 0 auto !important; padding: 0 15px; } /* Wider content on larger screens */ @media (min-width: 1200px) { .content main { max-width: 950px !important; } } @media (min-width: 1400px) { .content main { max-width: 1000px !important; } } @media (min-width: 1600px) { .content main { max-width: 1050px !important; } } /* Make code blocks in side-by-side tables use available space better */ .side-by-side-code td:first-child { width: 35%; /* Explanations/comments column */ } .side-by-side-code td:last-child { width: 65%; /* Code column - more space for code */ } /* Adjust pre/code blocks to not add unnecessary padding in tables */ .side-by-side-code pre { margin: 0; padding: 10px; } .side-by-side-code td { padding: 12px; } /* For very wide screens, cap the side-by-side table width for readability */ @media (min-width: 1600px) { .side-by-side-code { max-width: 1400px; margin-left: auto; margin-right: auto; } } ================================================ FILE: docs/acton-dev-guide/theme/sbscode.css ================================================ /* Custom table styling for side-by-side documentation */ .content table.side-by-side-code { display: table; width: 100%; margin: 0; border-collapse: collapse; border: none; background: none; table-layout: fixed; } /* Dark theme support */ .rust.light-theme .content table.side-by-side-code td:last-child { background: var(--quote-bg); } .rust.dark-theme .content table.side-by-side-code td:last-child { background: var(--quote-bg); } /* Ensure button contrast in both themes */ .rust.light-theme .content table.side-by-side-code .buttons { background: var(--bg); color: var(--fg); } .rust.dark-theme .content table.side-by-side-code .buttons { background: var(--bg); color: var(--fg); } /* Remove default mdBook table styling */ .content table.side-by-side-code tbody tr { background: none !important; border: none; } .content table.side-by-side-code td { border: none; padding: 0.5rem; vertical-align: top; } /* Left column (prose) styling */ .content table.side-by-side-code td:first-child { width: 35%; padding-right: 1.5rem; color: var(--fg); } /* Right column (code) styling */ .content table.side-by-side-code td:last-child { width: 65%; background: var(--quote-bg); border-radius: 0; } /* Round only the top corners of the first row's code cell */ .content table.side-by-side-code tr:first-child td:last-child { border-top-left-radius: 4px; border-top-right-radius: 4px; } /* Round only the bottom corners of the last row's code cell */ .content table.side-by-side-code tr:last-child td:last-child { border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } /* Hide mdBook's default copy buttons in our special tables */ .content table.side-by-side-code pre > .buttons { display: none !important; } /* Code block styling */ .content table.side-by-side-code td pre { margin: 0; padding: 0.5rem; background: none; } .content table.side-by-side-code td code { background: none; padding: 0; } /* Ensure continuous code blocks */ .content table.side-by-side-code tr + tr td:last-child { padding-top: 0; } /* Hide empty prose cells */ .content table.side-by-side-code td:first-child:empty { padding: 0; border: none; } /* Position the buttons container */ .content table.side-by-side-code td:last-child { position: relative; } /* Keep original mdBook button styling for our custom button */ .content table.side-by-side-code .buttons { position: absolute; top: 0.5rem; right: 0.5rem; opacity: 0; transition: opacity 0.2s; } .content table.side-by-side-code:hover .buttons { opacity: 1; } ================================================ FILE: docs/acton-dev-guide/theme/sbscode_copy.js ================================================ document.addEventListener('DOMContentLoaded', () => { // Select all side-by-side-code tables const codeTables = document.querySelectorAll('table.side-by-side-code'); codeTables.forEach(table => { // Get all code cells in this table const codeCells = table.querySelectorAll('td:last-child'); if (codeCells.length === 0) return; // Create button container div const buttonDiv = document.createElement('div'); buttonDiv.className = 'buttons'; // Create copy button with mdBook's styling const copyButton = document.createElement('button'); copyButton.className = 'fa fa-copy clip-button'; copyButton.setAttribute('title', 'Copy to clipboard'); copyButton.setAttribute('aria-label', 'Copy to clipboard'); // Add tooltip span const tooltip = document.createElement('i'); tooltip.className = 'tooltiptext'; copyButton.appendChild(tooltip); // Get all code blocks from all cells in this table const getAllCode = () => { const allCodeBlocks = table.querySelectorAll('td:last-child pre code'); return Array.from(allCodeBlocks) .map(block => block.textContent) .join('\n'); }; // Add click handler copyButton.addEventListener('click', async () => { const code = getAllCode(); await navigator.clipboard.writeText(code); // Visual feedback using tooltip tooltip.textContent = 'Copied!'; setTimeout(() => { tooltip.textContent = ''; }, 2000); }); // Add the button to the container and container to the first code cell buttonDiv.appendChild(copyButton); codeCells[0].appendChild(buttonDiv); }); }); ================================================ FILE: docs/acton-dev-guide/theme/skill-slider.css ================================================ /* Skill Slider Styles for Acton Guide */ /* Skill control widget in menu bar */ .skill-control-menu { display: inline-flex; align-items: center; margin-right: 10px; } .skill-slider-wrapper { display: flex; align-items: center; gap: 8px; } .skill-control-menu .skill-slider { width: 60px; -webkit-appearance: none; height: 3px; border-radius: 2px; background: var(--scrollbar); outline: none; opacity: 0.7; transition: opacity 0.2s; cursor: pointer; } .skill-control-menu .skill-slider:hover { opacity: 1; } .skill-control-menu .skill-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 12px; height: 12px; border-radius: 50%; background: var(--icons); cursor: pointer; } .skill-control-menu .skill-slider::-moz-range-thumb { width: 12px; height: 12px; border-radius: 50%; background: var(--icons); cursor: pointer; border: none; } .skill-control-menu .skill-label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; opacity: 0.8; white-space: nowrap; color: var(--icons); } /* Hide on very small screens */ @media (max-width: 600px) { .skill-control-menu { display: none; } } /* Content visibility based on skill level */ .beginner-content, .advanced-content { max-height: 0; opacity: 0; overflow: hidden; transition: max-height 0.8s ease-out, opacity 0.6s ease-out, margin 0.6s ease-out; margin: 0; } /* Beginner: show beginner extras */ body[data-skill="1"] .beginner-content { max-height: 2000px; /* Large enough for most content */ opacity: 1; margin: 15px 0; } /* Standard: default, no extras */ /* Advanced: show advanced extras */ body[data-skill="3"] .advanced-content { max-height: 2000px; /* Large enough for most content */ opacity: 1; margin: 15px 0; } /* Inline skill content */ .beginner-inline, .advanced-inline { opacity: 0; font-size: 0; transition: opacity 0.5s ease-out, font-size 0.5s ease-out; } body[data-skill="1"] .beginner-inline { opacity: 1; font-size: inherit; } body[data-skill="3"] .advanced-inline { opacity: 1; font-size: inherit; } /* Visual indicators for skill content blocks */ .beginner-content { background: rgba(76, 175, 80, 0.1); border-left: 4px solid #4caf50; padding: 15px; margin: 15px 0; border-radius: 0 4px 4px 0; } .advanced-content { background: rgba(33, 150, 243, 0.1); border-left: 4px solid #2196f3; padding: 15px; margin: 15px 0; border-radius: 0 4px 4px 0; } /* Skill level indicators in content */ .beginner-content::before { content: "🌱 Beginner"; display: block; font-weight: bold; margin-bottom: 10px; color: #4caf50; } .advanced-content::before { content: "🚀 Advanced"; display: block; font-weight: bold; margin-bottom: 10px; color: #2196f3; } /* Enhanced side-by-side code table */ .side-by-side-code { width: 100%; border-collapse: collapse; margin: 25px 0; background: transparent; border-radius: 0; overflow: visible; box-shadow: none; } .side-by-side-code td { padding: 20px; vertical-align: top; border-bottom: 1px solid var(--table-border-color); } .side-by-side-code tr:last-child td { border-bottom: none; } .side-by-side-code td:first-child { width: 35%; background: var(--sidebar-bg); border-right: 1px solid var(--table-border-color); font-size: 0.95em; line-height: 1.7; color: var(--fg); } .side-by-side-code td:last-child { width: 65%; background: var(--code-bg); } /* Remove extra margins in code blocks inside tables */ .side-by-side-code pre { margin: 0; background: transparent; padding: 0; } .side-by-side-code code { font-size: 0.9em; } /* On smaller screens, stack the cells */ @media (max-width: 768px) { .side-by-side-code td { display: block; width: 100% !important; } .side-by-side-code td:first-child { border-right: none; border-bottom: 1px solid var(--table-border-color); } .side-by-side-code tr:last-child td:first-child { border-bottom: 1px solid var(--table-border-color); } } /* Dark theme adjustments */ .ayu .side-by-side-code td:first-child, .coal .side-by-side-code td:first-child, .navy .side-by-side-code td:first-child { background: rgba(0, 0, 0, 0.2); } ================================================ FILE: docs/acton-dev-guide/theme/skill-slider.js ================================================ // Skill Slider JavaScript for Acton Guide (function() { // Default skill level (1=beginner, 2=standard, 3=advanced) const DEFAULT_SKILL = 2; const STORAGE_KEY = 'acton-docs-skill-level'; // Get saved skill level or use default function getSavedSkillLevel() { const saved = localStorage.getItem(STORAGE_KEY); return saved ? parseInt(saved) : DEFAULT_SKILL; } // Save skill level function saveSkillLevel(level) { localStorage.setItem(STORAGE_KEY, level); } // Create skill slider widget for menu bar function createSkillSlider() { const widget = document.createElement('div'); widget.className = 'skill-control-menu'; widget.innerHTML = `
    `; return widget; } // Update skill level function updateSkillLevel(level) { document.body.setAttribute('data-skill', level); // Update label text const labels = ['', 'Beginner', 'Standard', 'Advanced']; const activeLabel = document.querySelector('.skill-control-menu .skill-label'); if (activeLabel) { activeLabel.textContent = labels[level]; activeLabel.setAttribute('data-level', level); } // Save preference saveSkillLevel(level); } // Initialize on page load function initialize() { // Set initial skill level const savedLevel = getSavedSkillLevel(); updateSkillLevel(savedLevel); // Check if slider already exists in menu bar if (document.querySelector('.skill-control-menu')) return; // Find menu bar const menuBar = document.querySelector('.menu-bar'); if (!menuBar) return; // Find the right section of menu bar (where theme picker is) const rightButtons = menuBar.querySelector('.right-buttons'); if (!rightButtons) return; // Add skill slider widget before the theme button const widget = createSkillSlider(); rightButtons.insertBefore(widget, rightButtons.firstChild); // Set up event listener const slider = document.getElementById('globalSkillSlider'); if (slider) { slider.addEventListener('input', (e) => { updateSkillLevel(parseInt(e.target.value)); }); } // Update labels to show current state updateSkillLevel(savedLevel); } // Handle page navigation in mdBook function handlePageChange() { // Small delay to ensure DOM is ready setTimeout(initialize, 100); } // Initialize on first load document.addEventListener('DOMContentLoaded', initialize); // Re-initialize on mdBook page changes // mdBook uses AJAX for navigation, so we need to watch for changes let lastUrl = location.href; new MutationObserver(() => { const url = location.href; if (url !== lastUrl) { lastUrl = url; handlePageChange(); } }).observe(document, {subtree: true, childList: true}); // Also listen for popstate events window.addEventListener('popstate', handlePageChange); })(); ================================================ FILE: docs/acton-dev-guide/theme/tabs.css ================================================ .mdbook-tabs { display: flex; } .mdbook-tab { background-color: var(--table-alternate-bg); padding: 0.5rem 1rem; cursor: pointer; border: none; font-size: 1.6rem; line-height: 1.45em; } .mdbook-tab.active { background-color: var(--table-header-bg); font-weight: bold; } .mdbook-tab-content { padding: 1rem 0rem; } .mdbook-tab-content table { margin: unset; } ================================================ FILE: docs/acton-dev-guide/theme/tabs.js ================================================ /** * Change active tab of tabs. * * @param {Element} container * @param {string} name */ const changeTab = (container, name) => { for (const child of container.children) { if (!(child instanceof HTMLElement)) { continue; } if (child.classList.contains('mdbook-tabs')) { for (const tab of child.children) { if (!(tab instanceof HTMLElement)) { continue; } if (tab.dataset.tabname === name) { tab.classList.add('active'); } else { tab.classList.remove('active'); } } } else if (child.classList.contains('mdbook-tab-content')) { if (child.dataset.tabname === name) { child.classList.remove('hidden'); } else { child.classList.add('hidden'); } } } }; document.addEventListener('DOMContentLoaded', () => { const tabs = document.querySelectorAll('.mdbook-tab'); for (const tab of tabs) { tab.addEventListener('click', () => { if (!(tab instanceof HTMLElement)) { return; } if (!tab.parentElement || !tab.parentElement.parentElement) { return; } const container = tab.parentElement.parentElement; const name = tab.dataset.tabname; const global = container.dataset.tabglobal; changeTab(container, name); if (global) { localStorage.setItem(`mdbook-tabs-${global}`, name); const globalContainers = document.querySelectorAll( `.mdbook-tabs-container[data-tabglobal="${global}"]` ); for (const globalContainer of globalContainers) { changeTab(globalContainer, name); } } }); } const containers = document.querySelectorAll('.mdbook-tabs-container[data-tabglobal]'); for (const container of containers) { const global = container.dataset.tabglobal; const name = localStorage.getItem(`mdbook-tabs-${global}`); if (name && document.querySelector(`.mdbook-tab[data-tabname=${name}]`)) { changeTab(container, name); } } }); ================================================ FILE: docs/acton-guide/.gitignore ================================================ book ================================================ FILE: docs/acton-guide/LANGUAGE_REVIEW.md ================================================ # Scope Review of the current `docs/acton-guide` working tree, with focus on `src/language.md`, the new `src/language/*` pages, nearby `types`, `actors`, `protocols`, and `stdlib` splits, `src/SUMMARY.md`, and `theme/detail-toggles.css` where the new skill-level behavior affects how the guide is read. # High-level Assessment The rewrite is moving the guide toward a clearer, task-first structure. The landing pages are more human-oriented than the old chapter stubs, and the beginner/advanced layering is a real improvement in several places. The main problems are in the seams: optional handling is split across two places without enough navigation context, the built-in vs standard library boundary is still fuzzy, and the new skill-level UI is not fully usable on narrow screens. # Findings 1. `docs/acton-guide/src/SUMMARY.md:32-35`, `docs/acton-guide/src/language/optionals_none.md`, and `docs/acton-guide/src/types/optionals.md` create a confusing split for optionals. Readers see both `Optionals and None` and `Optionals`, but only one of them is obviously the basic entry point. The two pages overlap enough that the hierarchy reads as duplication instead of a deliberate beginner-to-reference progression. 2. `docs/acton-guide/src/stdlib.md:5-16` overstates what the new built-in/reference split contains. It says this section covers built-in definitions such as core types and built-in protocols, but the navigation only exposes protocols and imported modules. Core types still live under `docs/acton-guide/src/primitives.md` in the Language chapter, so the new stdlib landing page does not actually own the whole built-in surface it describes. 3. `docs/acton-guide/theme/detail-toggles.css:60-65` makes the detail-level system inaccessible on mobile. The skill control is hidden below 600px, but beginner and advanced callouts are hidden by default and only revealed through that control. Because many of the rewritten language pages now put substantive explanation into those blocks, narrow-screen readers are locked to whatever skill level was last saved. 4. `docs/acton-guide/src/primitives/tuples.md:7-22` introduces named-field tuple syntax without enough setup. The page jumps from positional tuple access to `point = (x=3, y=4)` and `point.x` with no explanation of whether this is a named tuple, row, or some other Acton-specific shape. That makes the built-in types chapter feel less self-contained than the rest of the new Language structure. # Remediation Plan 1. Make the optionals path explicit in `SUMMARY.md` by distinguishing the beginner page from the type-system page, or collapse the overlap into one clearer sequence. 2. Either add a built-ins landing page for core types or reword `stdlib.md` so it only claims ownership of what the nav actually exposes. 3. Keep the skill selector reachable on narrow screens, or make the default page content sufficient without requiring the hidden control. 4. Add a short introduction to named tuple/row syntax before using named-field tuple examples, or switch the example to plain tuple syntax until that concept is covered. ================================================ FILE: docs/acton-guide/README.md ================================================ # Acton Guide ## Writers Guide ``` sh mdbook serve ``` Each page should contain a single example and try to explain as few concepts as possible. ================================================ FILE: docs/acton-guide/RUST_BOOK_COMPARISON.md ================================================ # Rust Book Comparison ## Scope This comparison reviews the current `docs/acton-guide` working tree against the Rust book's beginner-to-reference arc, but it judges the two guides by topic shape and teaching progression rather than by literal chapter order. The goal is to identify where the Acton guide already teaches the right idea, where it compresses several Rust-book ideas into one Acton-specific model, and where a learner would still need more scaffolding. ## High-Level Assessment The Acton guide is more task-oriented and runtime-model-first than the Rust book. It does a good job covering everyday syntax, collections, optionals, exceptions, classes, protocols, actors, testing, and package workflows. Its strongest trait is that it teaches the Acton model directly instead of forcing readers through a generic imperative primer. Compared with the Rust book, the weak point is continuity. Rust tends to build one mental model at a time and deepen it. The Acton guide often splits related ideas across several pages or introduces Acton-specific runtime concerns before the reader has a stable data-modeling baseline. The largest gaps are the lack of a dedicated simple-data-modeling path, the absence of a pattern-matching chapter, the fragmented modules and packages story, and a thinner learner-facing treatment of higher-order/iterator-style programming. ## Common Programming Concepts Acton covers the same baseline set as Rust's opening chapter: bindings and scope, built-in types, expressions, functions, comments, and control flow. This part of the guide is solid, and it makes a good beginner foundation. The key Acton difference is how mutability is framed. Rust introduces `mut` in a world of ownership and borrowing. Acton instead emphasizes constant module bindings, actor-local `var`, and the fact that mutable state belongs inside actors. That is the right Acton-specific move. The main weakness is sequencing. Several examples already use `actor main(env)` and other runtime ideas while the reader is still digesting ordinary programming concepts. The guide tells readers they do not need to understand actors yet, but the examples still make actors part of the early mental load. ## Structs and Data Modeling Rust uses structs early to give beginners a named composite value and a place to attach methods before moving into richer modeling. Acton does not have a direct struct chapter. The nearest pieces are tuples, named tuples, classes, and protocols. That covers the feature space, but not the teaching arc. Named tuples appear as a convenience in the primitives section, while classes are introduced later as the answer when a tuple becomes too anonymous. What is missing is a dedicated bridge from "small anonymous value" to "named data shape" to "behavior-bearing object". Without that bridge, the guide leaves a gap between the tuple examples and the class-based modeling chapter. ## Enums and Pattern Matching Rust's enums and `match` chapter has no direct Acton equivalent. Acton instead teaches optionals and exceptions as the two main ways to model absence and failure. That is good coverage for the features Acton actually has, but it is not a pattern-matching story. This should be treated as a language difference, not as a missing Rust chapter to recreate mechanically. The docs should be explicit that there is no Rust-style `match` arc here and that optionals, conditionals, and exceptions are the intended tools for the nearby problems. ## Packages, Crates, Modules, and Code Organization Acton does cover modules, project structure, package management, dependency fetching, and repository dependency handling. The material is practical and clear about `src/`, `import`, pinned hashes, local dependencies, and override workflows. The weakness is that the story is fragmented across `language`, `projects`, `modules`, `package_management`, and the `pkg/*` pages. Rust book presents packages, crates, and modules as one continuous mental model. Acton's guide is more operational: it explains what to type and what the build system does, but it does not yet tie the whole sequence together from single-file program to module tree to dependency graph. ## Common Collections Acton covers lists, dictionaries, and sets well. The guide is strong on choosing the right collection, showing the concrete APIs, and keeping the type-safety story visible. Comprehensions and iteration examples are also useful. The gap is not basic coverage but conceptual bridging. The shared protocol surface behind collections is mostly hidden in the reference material, so readers see the concrete APIs before they see the shared model. Rust spends more time building a single story around collection APIs; Acton would benefit from a stronger bridge from concrete collection use to the underlying iterable/indexable/mapping protocols. ## Error Handling Acton has a clean split between absence and failure: optionals model ordinary absence, and exceptions model real failures. That distinction is at least as clear as Rust's early `Option`/`Result` split. The guide also covers narrowing, optional chaining, and forced unwrapping, which gives the reader several levels of sophistication. The weak spot is that the decision rule is spread across multiple pages, so the reader sees the mechanics before the teaching story is fully settled. What is missing is a sharper "when do I return `?T`, when do I raise, and when do I force unwrap?" rule. That choice should be front-loaded more explicitly. ## Generics, Traits, and Lifetimes Acton has good coverage for generics and protocol constraints, and its built-in protocol reference covers much of the same ground Rust traits do. The guide also explains effects, which is a useful Acton-specific layer that Rust book does not need in the same form. Lifetimes are different. Rust needs a standalone lifetime story because ownership and borrowing are core to the language. Acton does not need that exact chapter, so this is not a missing feature in the same sense. What is missing is a beginner-facing explanation of the replacement model: actor ownership, explicit capability passing, and GC-backed object lifetime remove the need for a borrow-checker style arc. In other words, the guide has the pieces, but it does not yet connect them into a concise "why there is no Rust-style lifetime chapter here" explanation. ## Testing Acton's testing coverage is broader than the Rust book's. It goes beyond unit tests into actor tests, environment tests, snapshots, flaky tests, performance, and stress testing. That breadth is valuable for the language. The tradeoff is that the core lesson is less visible. Rust introduces testing as a straightforward habit. Acton should keep the unit-test path front and center and treat the specialized test kinds as extensions of that base model rather than as the first thing a newcomer has to sort through. ## Functional Features Rust's closures and iterators chapter has no direct Acton twin. Acton does have higher-order functions, comprehensions, and iteration over collections, but the guide does not yet teach a coherent "functional style" arc. The missing pedagogy is especially noticeable around closures, captured state, and iterator pipelines. Some of that may be less central to Acton than to Rust, but the current docs still leave the reader without a strong conceptual bridge from "a function is a value" to "here is how you build reusable pipelines over data." ## Concurrency This is where Acton diverges most from Rust book, and that difference is part of the language design. Rust treats concurrency as a systems topic layered on ownership and threads. Acton treats actors as the primary unit of mutable state and concurrency, so the guide naturally teaches async calls, delayed work, cleanup, and capability boundaries as core language ideas. The coverage is good, but the teaching load is heavy. The reader has to absorb state ownership, communication, and concurrency at the same time. A little more framing around "sequential inside an actor, concurrent between actors" would make the section easier to digest. ## OOP Comparison Rust uses its OOP comparison chapter to explain why objects, encapsulation, and inheritance are only part of the design space. Acton already covers classes, initialization, inheritance, and protocols, and it generally steers readers away from overusing inheritance. The gap is mostly rhetorical and structural. The guide explains the pieces, but it does not yet stage the tradeoff as a focused comparison between class-based design, protocol-based design, and actor-based state ownership. That would help readers coming from class-heavy languages understand why Acton's preferred abstractions differ. ## Concrete Gaps - No dedicated pattern-matching story, so readers never get a Rust-style `match` equivalent because the guide does not say whether one exists. - No single beginner path for "small anonymous value -> named tuple -> class", even though the docs use all three ideas. - Modules, projects, and package dependencies are split across several pages, which makes the code-organization story feel fragmented. - Higher-order functions are present, but closures and iterator-style composition are not taught as a first-class learning arc. - Lifetimes are not a real Acton chapter, but the docs do not yet explain clearly enough why actor ownership and capabilities replace the need for one. - Testing is broad and useful, but the basic unit-test workflow is partially buried under specialized test categories. ## Prioritized Remediation Plan 1. Add a short data-modeling bridge that explains tuples, named tuples, classes, and protocols as one progression. 2. Add or rewrite an overview page for modules and package management that links source layout, imports, and dependency resolution into one mental model. 3. Add a functional-programming overview that connects higher-order functions, comprehensions, and iteration protocols, and states plainly what Acton does not have compared with Rust closures and iterators. 4. Tighten the absence/failure story so the choice between optional values, exceptions, and forced unwrapping is stated up front. 5. Add a short note in the type or actor sections explaining that Rust-style lifetimes are not a direct Acton concept because actor ownership and capability passing solve a different problem. ================================================ FILE: docs/acton-guide/book.toml ================================================ [book] title = "Acton Guide" authors = [] language = "en" multilingual = false preferred-dark-theme = "ayu" src = "src" site-url = "/learn/acton-guide/" git-repository-url = "https://github.com/actonlang/acton" git-repository-icon = "fa-github" edit-url-template = "https://github.com/actonlang/acton/edit/master/docs/acton-guide/{path}" [preprocessor.tabs] [preprocessor.svgbob] text_width = 8.0 text_height = 16.0 class = "bob" font_family = "arial" font_size = 14 stroke_width = 2.0 # there's using css-variables from theme: stroke_color = "var(--fg)" # see default theme / variables.css background_color = "transparent" # also useful `var(--bg)` [preprocessor.admonish] command = "mdbook-admonish" assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install` [output.html] additional-css = ["svgbob.css", "theme/tabs.css", "./mdbook-admonish.css", "theme/acton-theme.css", "theme/sbscode.css", "theme/detail-toggles.css", "theme/guide-links.css", "theme/content-width.css"] additional-js = ["theme/tabs.js", "theme/sbscode_copy.js", "theme/acton-theme.js", "theme/detail-toggles.js", "theme/guide-links.js"] [output.html.fold] enable = true ================================================ FILE: docs/acton-guide/mdbook-admonish.css ================================================ @charset "UTF-8"; :is(.admonition) { display: flow-root; margin: 1.5625em 0; padding: 0 1.2rem; color: var(--fg); page-break-inside: avoid; background-color: var(--bg); border: 0 solid black; border-inline-start-width: 0.4rem; border-radius: 0.2rem; box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); } @media print { :is(.admonition) { box-shadow: none; } } :is(.admonition) > * { box-sizing: border-box; } :is(.admonition) :is(.admonition) { margin-top: 1em; margin-bottom: 1em; } :is(.admonition) > .tabbed-set:only-child { margin-top: 0; } html :is(.admonition) > :last-child { margin-bottom: 1.2rem; } a.admonition-anchor-link { display: none; position: absolute; left: -1.2rem; padding-right: 1rem; } a.admonition-anchor-link:link, a.admonition-anchor-link:visited { color: var(--fg); } a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { text-decoration: none; } a.admonition-anchor-link::before { content: "§"; } :is(.admonition-title, summary.admonition-title) { position: relative; min-height: 4rem; margin-block: 0; margin-inline: -1.6rem -1.2rem; padding-block: 0.8rem; padding-inline: 4.4rem 1.2rem; font-weight: 700; background-color: rgba(68, 138, 255, 0.1); print-color-adjust: exact; -webkit-print-color-adjust: exact; display: flex; } :is(.admonition-title, summary.admonition-title) p { margin: 0; } html :is(.admonition-title, summary.admonition-title):last-child { margin-bottom: 0; } :is(.admonition-title, summary.admonition-title)::before { position: absolute; top: 0.625em; inset-inline-start: 1.6rem; width: 2rem; height: 2rem; background-color: #448aff; print-color-adjust: exact; -webkit-print-color-adjust: exact; mask-image: url('data:image/svg+xml;charset=utf-8,'); -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-size: contain; content: ""; } :is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link { display: initial; } details.admonition > summary.admonition-title::after { position: absolute; top: 0.625em; inset-inline-end: 1.6rem; height: 2rem; width: 2rem; background-color: currentcolor; mask-image: var(--md-details-icon); -webkit-mask-image: var(--md-details-icon); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-size: contain; content: ""; transform: rotate(0deg); transition: transform 0.25s; } details[open].admonition > summary.admonition-title::after { transform: rotate(90deg); } :root { --md-details-icon: url("data:image/svg+xml;charset=utf-8,"); } :root { --md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,"); --md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,"); } :is(.admonition):is(.admonish-note) { border-color: #448aff; } :is(.admonish-note) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(68, 138, 255, 0.1); } :is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before { background-color: #448aff; mask-image: var(--md-admonition-icon--admonish-note); -webkit-mask-image: var(--md-admonition-icon--admonish-note); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) { border-color: #00b0ff; } :is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 176, 255, 0.1); } :is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00b0ff; mask-image: var(--md-admonition-icon--admonish-abstract); -webkit-mask-image: var(--md-admonition-icon--admonish-abstract); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-info, .admonish-todo) { border-color: #00b8d4; } :is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 184, 212, 0.1); } :is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00b8d4; mask-image: var(--md-admonition-icon--admonish-info); -webkit-mask-image: var(--md-admonition-icon--admonish-info); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) { border-color: #00bfa5; } :is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 191, 165, 0.1); } :is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00bfa5; mask-image: var(--md-admonition-icon--admonish-tip); -webkit-mask-image: var(--md-admonition-icon--admonish-tip); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) { border-color: #00c853; } :is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(0, 200, 83, 0.1); } :is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before { background-color: #00c853; mask-image: var(--md-admonition-icon--admonish-success); -webkit-mask-image: var(--md-admonition-icon--admonish-success); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) { border-color: #64dd17; } :is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(100, 221, 23, 0.1); } :is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before { background-color: #64dd17; mask-image: var(--md-admonition-icon--admonish-question); -webkit-mask-image: var(--md-admonition-icon--admonish-question); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) { border-color: #ff9100; } :is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(255, 145, 0, 0.1); } :is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before { background-color: #ff9100; mask-image: var(--md-admonition-icon--admonish-warning); -webkit-mask-image: var(--md-admonition-icon--admonish-warning); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) { border-color: #ff5252; } :is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(255, 82, 82, 0.1); } :is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before { background-color: #ff5252; mask-image: var(--md-admonition-icon--admonish-failure); -webkit-mask-image: var(--md-admonition-icon--admonish-failure); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-danger, .admonish-error) { border-color: #ff1744; } :is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(255, 23, 68, 0.1); } :is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before { background-color: #ff1744; mask-image: var(--md-admonition-icon--admonish-danger); -webkit-mask-image: var(--md-admonition-icon--admonish-danger); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-bug) { border-color: #f50057; } :is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(245, 0, 87, 0.1); } :is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before { background-color: #f50057; mask-image: var(--md-admonition-icon--admonish-bug); -webkit-mask-image: var(--md-admonition-icon--admonish-bug); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-example) { border-color: #7c4dff; } :is(.admonish-example) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(124, 77, 255, 0.1); } :is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before { background-color: #7c4dff; mask-image: var(--md-admonition-icon--admonish-example); -webkit-mask-image: var(--md-admonition-icon--admonish-example); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } :is(.admonition):is(.admonish-quote, .admonish-cite) { border-color: #9e9e9e; } :is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) { background-color: rgba(158, 158, 158, 0.1); } :is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before { background-color: #9e9e9e; mask-image: var(--md-admonition-icon--admonish-quote); -webkit-mask-image: var(--md-admonition-icon--admonish-quote); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; mask-size: contain; -webkit-mask-repeat: no-repeat; } .navy :is(.admonition) { background-color: var(--sidebar-bg); } .ayu :is(.admonition), .coal :is(.admonition) { background-color: var(--theme-hover); } .rust :is(.admonition) { background-color: var(--sidebar-bg); color: var(--sidebar-fg); } .rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { color: var(--sidebar-fg); } ================================================ FILE: docs/acton-guide/src/SUMMARY.md ================================================ # Summary - [Getting started](index.md) - [Hello World](hello.md) - [Installation](install.md) - [Tip / Nightly](install_tip.md) - [Acton scripts](hello/shebang.md) - [Acton Projects](projects.md) - [Running Tests](hello/running_tests.md) - [Language](language.md) - [Common programming concepts](language/common_programming_concepts.md) - [Variables, constants, and scope](language/bindings_scope.md) - [Built-in types and literals](primitives.md) - [Integers](primitives/integers.md) - [Floating-point numbers](primitives/float.md) - [Complex numbers](primitives/complex.md) - [Tuples](primitives/tuples.md) - [Expressions and operators](language/expressions_operators.md) - [Functions](functions.md) - [Higher order functions](functions/higher_order.md) - [Comments](language/comments.md) - [Control flow](control_flow.md) - [if / elif / else](control_flow/if_else.md) - [for](control_flow/for.md) - [while](control_flow/while.md) - [Collections and everyday data](collections.md) - [Lists](collections/lists.md) - [Dictionaries](collections/dicts.md) - [Sets](collections/sets.md) - [Missing values and failures](language/missing_values_failures.md) - [Optionals and `None`](language/optionals_none.md) - [Optionals](types/optionals.md) - [Errors and exceptions](language/errors_exceptions.md) - [Modeling data and interfaces](language/modeling_data_interfaces.md) - [Classes and objects](classes/intro.md) - [Initialization](classes/initialization.md) - [Inheritance](classes/inheritance.md) - [Protocols](protocols/intro.md) - [Method Dispatch](protocols/dispatch.md) - [Organizing code](language/organizing_code.md) - [Modules](modules.md) - [Naming](naming.md) - [Working with types](types/intro.md) - [Explicit types](types/explicit.md) - [Generics](types/generics.md) - [Effects (`pure`, `mut`, `proc`, `action`)](types/effects.md) - [Troubleshooting type errors](types/troubleshooting.md) - [Actors & concurrency](language/state_concurrency.md) - [Actors](actors.md) - [Root Actor](actors/root.md) - [Lifetime](actors/lifetime.md) - [Attributes](actors/attributes.md) - [`self` reference](actors/self.md) - [Actor methods](functions/actor_methods.md) - [Sync Method calls](actors/sync_method_call.md) - [Async Method calls](actors/async_method_call.md) - [Control flow in an async actor world](control_flow/actors.md) - [after / sleep](control_flow/after_sleep.md) - [Concurrency](actors/concurrency.md) - [Cleanup](actors/cleanup.md) - [Environment and capabilities](language/environment_capabilities.md) - [Security](security.md) - [Capabilities](security/capabilities.md) - [Environment](environment.md) - [Environment variables](environment/variables.md) - [Reading stdin input](environment/stdin.md) - [Interactive stdin input](environment/interactive_stdin.md) - [Built-in & Standard Library](stdlib.md) - [Built-in protocols](stdlib/builtin_protocols.md) - [General protocols](stdlib/builtin_protocols/general.md) - [Hashable](stdlib/builtin_protocols/hashable.md) - [Numeric protocols](stdlib/builtin_protocols/numeric.md) - [Collection protocols](stdlib/builtin_protocols/collection.md) - [Standard Library](stdlib/standard_library.md) - [math](stdlib/math.md) - [re](stdlib/re.md) - [Testing](testing.md) - [Unit tests](testing/unit_test.md) - [Sync actor tests](testing/sync_actor_test.md) - [Async actor tests](testing/async_actor_test.md) - [Env tests](testing/env_test.md) - [Snapshot testing](testing/snapshot.md) - [Failures vs errors](testing/failures_errors.md) - [Flaky tests](testing/flaky.md) - [Performance testing](testing/performance.md) - [Stress testing](testing/stress.md) - [Perf comparison](testing/perf_record.md) - [Build System](compilation.md) - [Incremental compilation](compilation/incremental.md) - [Package Management](package_management.md) - [Package Index](pkg/package_index.md) - [Fingerprint and Lineage](pkg/fingerprint.md) - [Add Dependency](pkg/add_dependency.md) - [Local Dependencies](pkg/local_dependencies.md) - [Override Dependency](pkg/override_dependency.md) - [Remove Dependency](pkg/remove_dependency.md) - [Fetch Deps (Airplane mode)](pkg/fetch_dependencies.md) - [Zig / C / C++ dependencies](zig_dependencies.md) - [Security and Trust](security/intro.md) - [Working with Zig / C / C++](working_with_zig.md) - [Integrating a C library (zlib)](ext/integrating_c_library.md) - [Run Time System](rts.md) ================================================ FILE: docs/acton-guide/src/actors/async_method_call.md ================================================ # Async Method calls Async calls let an actor tell another actor to do something without waiting for a return value. A method call is asynchronous when the caller does not use the return value.

    An async call is closer to "send this message" than "call this function and wait".

    ```python actor Worker(name): def say(msg): print(name, "received:", msg) actor main(env): w1 = Worker("one") w2 = Worker("two") w1.say("hello") w2.say("world") def stop(): env.exit(0) after 0.1: stop() ``` Here, `main` sends two messages and keeps going. It does not wait for either worker to return a value. ## When to use async calls - use them for fire-and-forget work - use them when another actor should react independently - use them to avoid blocking the current actor on a result ================================================ FILE: docs/acton-guide/src/actors/attributes.md ================================================ # Actor Attributes & Constants Actor attributes are used to store the state of an actor. The important distinctions are whether an attribute is mutable state or a constant, and whether it is private or public. An actor can define three kinds of top-level attributes: - `var foo = ...` defines private mutable actor state - `_foo = ...` defines a private constant - `foo = ...` defines a public constant

    The important boundary is not just "mutable or constant", but also "private or public". var stays private because mutable actor state must not be exposed directly across actor boundaries. Plain constant attributes can be read from other actors because they do not create shared mutable memory, and a leading _ keeps such a constant private to the actor.

    Actor constants are observed as constants. The top-level code in the actor body runs during actor creation, and a constant name may be assigned more than once while that final value is being established. Once initialization is complete, the final binding is the constant value seen by methods and, for public constants, by other actors.

    For example: ```python actor Act(): var something = 40 _step = 2 fixed = 0 fixed = 1234 def hello(): something += _step print("Hello, I'm Act & value of 'something' is: " + str(something)) actor main(env): actor1 = Act() await async actor1.hello() print("Externally visible constant: ", actor1.fixed) # print(actor1.something) # print(actor1._step) env.exit(0) ``` Here, `something` is private mutable state, `_step` is a private constant, and `fixed` is a public constant. The repeated assignment to `fixed` happens during actor creation. The final binding, `1234`, is the constant value methods and other actors observe after initialization has completed. Inside the actor, all three kinds of attributes can be used directly from methods without writing `self.`. Without `var`, an actor attribute is a constant. If the name starts with `_`, that constant stays private to the actor. Without the leading underscore, other actors can read the constant through an actor reference. In this example, `main` can read `actor1.fixed`, but it cannot read `actor1.something` or `actor1._step`. The first is private mutable state, and the second is a private constant. ================================================ FILE: docs/acton-guide/src/actors/cleanup.md ================================================ # Cleanup / Finalization It is possible to run special code when an actor is about to be garbage collected. This is mainly for actors that manage outside resources and need a best-effort final step when they become unreachable. Define an actor action called `__cleanup__` and the runtime will schedule it when garbage collection notices that the actor is no longer reachable. There is no hard guarantee when `__cleanup__` will run, and it can take more than one collection round before all finalizers are handled.

    Cleanup hooks are intentionally weakly timed. They are useful for best-effort resource cleanup at the boundary to the outside world, but they are not a substitute for explicit shutdown protocols when a system needs deterministic release or ordering.

    Source: ```python actor Foo(): action def __cleanup__(): print("Cleaning up after myself...") actor main(env): for i in range(20): Foo() a = 1 for i in range(99999): a += i def _stop(): env.exit(0) after 0.1: _stop() ``` Output: ```sh Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... Cleaning up after myself... ``` ================================================ FILE: docs/acton-guide/src/actors/concurrency.md ================================================ # Actor concurrency Multiple actors can make progress concurrently. In this example, Foo and Bar both keep ticking while the root actor schedules shutdown.

    Concurrency here means the actors can make progress independently, not that their outputs follow a fixed interleaving. The runtime may run them in parallel on multiple workers, but the semantic guarantee is still per-actor sequential execution rather than any global ordering between actors.

    Source: ```python actor Counter(name): var counter = 0 def periodic(): print("I am " + name + " and I have counted to " + str(counter)) counter += 1 after 1: periodic() periodic() actor main(env): foo = Counter("Foo") bar = Counter("Bar") def exit(): env.exit(0) after 10: exit() ``` Compile and run: ```sh acton concurrency.act ./concurrency ``` Output: ```sh I am Foo and I have counted to 0 I am Bar and I have counted to 0 I am Foo and I have counted to 1 I am Bar and I have counted to 1 I am Foo and I have counted to 2 I am Bar and I have counted to 2 I am Foo and I have counted to 3 I am Bar and I have counted to 3 I am Foo and I have counted to 4 I am Bar and I have counted to 4 I am Bar and I have counted to 5 I am Foo and I have counted to 5 I am Bar and I have counted to 6 I am Foo and I have counted to 6 I am Bar and I have counted to 7 I am Foo and I have counted to 7 I am Foo and I have counted to 8 I am Bar and I have counted to 8 I am Foo and I have counted to 9 I am Bar and I have counted to 9 ``` ================================================ FILE: docs/acton-guide/src/actors/lifetime.md ================================================ # Lifetime In many languages, reaching the end of `main` ends the program. Acton is different. Actors stay alive as long as another actor keeps a reference to them, and they sit idle until they receive more work. Actors without references can be garbage collected. The root actor stays alive until the program exits. That means a program like this will keep running even though the root actor body reaches its end. You must explicitly tell the runtime to stop the actor world with `env.exit()`.

    Actor lifetime is reference-based. Non-root actors disappear when no live actor keeps a reference to them, while the root actor persists until the program exits. This is why shutdown in Acton is explicit rather than an implicit fall-through from the end of main.

    Source: ```python actor main(env): print("Hello world!") ``` Compile and run: ```sh acton noexit.act ``` Output: ```sh $ ./noexit ``` ================================================ FILE: docs/acton-guide/src/actors/root.md ================================================ # Root Actor Every Acton program has a root actor. A binary executable must have one, and by default Acton uses an actor named `main` when it has a root-eligible signature. In ordinary programs that means a single environment parameter, usually written as `actor main(env):` or explicitly as `actor main(env: Env):`. You can choose a different root with `--root`. Given this Acton program: ```python actor main(env): print("Hello World!") env.exit(0) ``` The following acton commands will all produce the same output. ```sh acton hello.act acton hello.act --root main acton hello.act --root hello.main ``` The first invocation relies on the default rule of using an actor named `main`. The second explicitly selects `main` as the root actor. The third uses a qualified name that includes both the module name and the actor name. Qualified names are useful when a project contains several actors that could otherwise be mistaken for the entrypoint. The `env` parameter an actor reference to the builtin environment actor of type `Env`. The environment actor is constructed by the runtime system and passed to the root actor when the program starts. A normal Acton program consists of many actors arranged in a tree. The root actor is at the top of that tree and starts the rest of the program directly or indirectly. The Acton runtime bootstraps the root actor and passes it `Env`, which is the entrypoint for process arguments, capabilities, standard input, environment variables, and program exit.

    The root actor is the boundary where process-level capabilities enter the actor world. That is why main(env) keeps showing up throughout the guide: it is both the conventional entrypoint and the place where outside-world access begins.

    ```bob .────. ( root ) `----' / \ / \ V V .─. .─. ( A ) ( B )---+ `-' `-' \ / \ | \ \ / \ | \ \ V V | \ \ .─. .─. V V V ( 1 ) ( 2 ) .─. .─. .─. `─' `─' ( 3 ) ( 4 ) ( 5 ) `─' `─' `─' ``` Any executable Acton program must have a root actor. Acton libraries that are imported into another program do not. See [Environment](../environment.md) for the practical guide to `Env` and the operations it makes available. ================================================ FILE: docs/acton-guide/src/actors/self.md ================================================ # `self` `self` is implicitly bound inside an actor. Use it when you need to pass a reference to the current actor to another actor. Inside the actor, `self` is usually unnecessary.

    self inside an actor is about identity and communication, not ordinary attribute access. Passing self hands out a callback path to the current actor, which makes it central to request/reply and subscription-style protocols.

    Source: ```python actor Pinger(ponger: Ponger): def pong(message: str): print("Pinger: Got pong:", message) print("Pinger: Sending ping to Ponger...") ponger.ping(self) actor Ponger(): def ping(pinger: Pinger): print("Ponger: Got ping!") # Call back to the pinger pinger.pong("Hello from Ponger!") # Usage actor main(env): ponger = Ponger() pinger = Pinger(ponger) env.exit(0) ``` Output: ```console Pinger: Sending ping to Ponger... Ponger: Got ping! Pinger: Got pong: Hello from Ponger! ``` In this example, `Pinger` passes `self` to `Ponger` when pinging, allowing the ponger to send a pong back. ================================================ FILE: docs/acton-guide/src/actors/sequential.md ================================================ # Actors are sequential While many actors can run concurrently, each actor is a sequential process and will only do one thing at a time. There are no threads nor POSIX processes in Acton, only actors. In order to scale beyond a single In order to write Writing performant Acton programs This means an actor can only do one thing at a time and consequently, it is important not to block. All I/O in Acton is asynchronous. ================================================ FILE: docs/acton-guide/src/actors/sync_method_call.md ================================================ # Sync Method calls Acton lets one actor call another actor synchronously when it needs a result back immediately. A method call is synchronous when the caller uses the return value.

    A synchronous actor call feels like an ordinary function call: ask for a result, wait, then continue.

    ```python actor Calculator(): def square(n): return n * n actor main(env): calc = Calculator() answer = calc.square(7) print("The answer is", answer) env.exit(0) ``` Here, `main` waits for `calc.square(7)` to finish and then continues with the returned value.

    Sync calls suspend the current actor until the other actor replies. As systems grow, it is usually better to keep sync chains short and push longer work into asynchronous flows.

    ## When to use sync calls - use them when a result is needed right away - prefer them for small, direct requests - be careful with long chains of sync actor-to-actor calls ================================================ FILE: docs/acton-guide/src/actors.md ================================================ # Actors Actors are Acton's primary unit for state and concurrency. If you are looking for the Acton answer to Rust-style lifetime concerns, this is it: actors own mutable state, capabilities are passed explicitly, and the runtime handles ordinary object lifetime.

    If classes feel like objects that own data, actors are a useful way to think about objects that own state and participate in concurrent work. The actor body runs once when the actor starts; its methods run later in response to calls.

    An actor combines: - private state owned by one actor - sequential execution inside that actor - method-based communication with other actors - a place to put mutable program state ```python actor Greeter(name): print("starting", name) def hello(): print("hello from", name) actor main(env): greeter = Greeter("Acton") await async greeter.hello() env.exit(0) ``` Code in the actor body runs once when the actor is created. That body is where initialization happens, and it may define methods that operate on the actor's private state.

    Actors are also where several Acton-specific language pieces meet: var, await, async, after, capability passing, and effectful APIs. The main guarantee is actor-local sequentiality: state changes happen one handled message at a time inside that actor.

    ## What to read next - [Root Actor](actors/root.md) for the entrypoint pattern - [Lifetime](actors/lifetime.md) for how actors stay alive - [Attributes](actors/attributes.md) and [`self`](actors/self.md) for actor state - [Actor methods](functions/actor_methods.md), [Sync Method calls](actors/sync_method_call.md), and [Async Method calls](actors/async_method_call.md) for communication - [Concurrency](actors/concurrency.md), [Control flow in an async actor world](control_flow/actors.md), and [after / sleep](control_flow/after_sleep.md) for concurrent behavior - [Cleanup](actors/cleanup.md) for best-effort finalization ================================================ FILE: docs/acton-guide/src/classes/inheritance.md ================================================ # Class inheritance Inheritance lets one class specialize another. Use it when there is a real "is a" relationship between the two types. The derived class inherits behavior from the base class and can add or override methods of its own.

    Use inheritance sparingly. It couples representation, lifecycle, and method lookup, so a base class becomes part of the derived type's public contract. When the shared need is only behavior, a protocol is often a better fit. When the shared need is only state reuse, composition is often clearer.

    ```python class Shape(object): def area(self) -> float: raise NotImplementedError("subclasses must implement area()") class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): return 3.14 * self.radius ** 2 class Square(Shape): def __init__(self, side): self.side = side def area(self): return self.side ** 2 actor main(env): circle = Circle(3.14) square = Square(3.14) print(circle.area() + square.area()) env.exit(0) ``` In this example: - `Shape` defines a common interface - `Circle` and `Square` inherit from `Shape` - each subclass provides its own `area()` implementation - code written against `Shape` can still call `area()` on either value

    Read class Circle(Shape): as "Circle is a kind of Shape". If that sentence feels wrong, inheritance is usually the wrong tool.

    ================================================ FILE: docs/acton-guide/src/classes/initialization.md ================================================ # Class initialization Use `__init__` to leave the object valid. Before `self` escapes, every required attribute must already be set. Read the rule as two steps: 1. Build the object locally. 2. Let `self` out only after construction is complete.

    Think of __init__ as the boundary between "not ready" and "ready". If another function needs the object, wait until every required field is assigned.

    `self` escapes when you: - pass `self` to another function - call a method on `self` - capture a bound method such as `self.on_event` - return `self` - store `self` somewhere that outlives the constructor

    The important invariant is not "all assignments happen early" but "self must not escape before the object is fully initialized". Once you read the rules that way, the branch, loop, callback, and base-class cases all follow the same rule.

    ## Build the object first During construction, use local variables for intermediate values and assign to attributes once the values are ready. If you read from an attribute before assigning it, the initialization order is wrong. ```python class Config(object): def __init__(self, base_value: int): self.base = base_value self.doubled = self.base * 2 self.quadrupled = self.doubled * 2 ``` ## Let `self` out last Once the object is complete, you can call helper methods or register the instance with the rest of the system. ```python class BankAccount(object): def __init__(self, owner: str, initial_deposit: float): self.owner = owner self.balance = initial_deposit self.transaction_log = [] self.log_transaction("Account opened") register_account(self) if initial_deposit > 10000: flag_for_review(self) ``` ## Control flow Branches and loops are fine as long as every normal path leaves the object complete. ### Branches Conditional branches work when every branch that completes normally initializes the same required attributes. Branches that `raise` exceptions do not need to finish construction. ```python class Rational(object): num: int denom: int def __init__(self, num: int, denom: int): if denom == 0: raise ValueError("Denominator cannot be zero") if denom > 0: self.num = num self.denom = denom else: self.num = -num self.denom = -denom ``` ### Try/except `try`/`except` works the same way. The `else` branch is part of the normal path, so it must also leave the object initialized. ### Loops Loops are fine as long as they do not leak `self` before the object is ready. ```python class Example(object): def __init__(self, data: list[int]): total = 0 for item in data: total += item self.values = data self.computed = total for item in data: self.process(item) ``` ## Common mistake Passing a method reference like `self.method` also makes `self` escape, even if the method is not called immediately. ```python class Handler(object): callback: Callback data: int def __init__(self): self.callback = Callback(self.on_event) self.data = 42 def on_event(self): pass ``` ## Parent classes If a base class owns state, initialize that state before exposing the derived object. Call the parent `__init__` as part of your own construction. ```python class Account(object): account_id: str created_date: str def __init__(self, account_id: str): self.account_id = account_id self.created_date = current_date() class BankAccount(Account): owner: str balance: float def __init__(self, account_id: str, owner: str, initial_deposit: float): Account.__init__(self, account_id) self.owner = owner self.balance = initial_deposit ``` ================================================ FILE: docs/acton-guide/src/classes/intro.md ================================================ # Classes and objects Classes let you name a concept, keep its data together, and attach the behavior that belongs with that data. If a tuple or named tuple starts to feel too anonymous, a class is usually the next step. Use a class when a value should have: - a clear name instead of a bundle of positions - related pieces of data that travel together - methods that operate on that data - construction rules or invariants that matter to callers ```python class Circle(object): def __init__(self, radius): self.radius = radius def diameter(self): return self.radius * 2 actor main(env): circle = Circle(3.14) print(circle.diameter()) env.exit(0) ``` ## What a class gives you In the example above: - `radius` is an attribute stored on each `Circle` - `diameter()` is a method that uses that attribute - `self` refers to the object the method is running on

    If a tuple starts to feel anonymous or unclear, that is usually a sign that the value wants to become a class. Inside methods, self is the current object, so self.name means "this object's name".

    Attributes are often introduced by assignments in `__init__`, but you can also declare them explicitly in the class body when the shape should be obvious up front. ```python class Person(object): name: str def __init__(self, name, age): self.name = name self.age = age ``` ================================================ FILE: docs/acton-guide/src/collections/dicts.md ================================================ # Dictionaries Dictionaries map keys to values. They keep insertion order, so when you iterate over a dictionary you get keys back in the order they were first added.

    Use a dictionary when you want to look something up by name, id, or some other key. If you keep searching through a list for a matching value, a dictionary is often the better shape.

    ## Creating dictionaries ```python counts = {"apples": 2, "bananas": 4} empty_counts: dict[str, int] = {} ``` The key type and value type are fixed for a given dictionary. When a dictionary is empty, give it a type if the surrounding code does not make that obvious. ## Looking up values ```python counts = {"apples": 2, "bananas": 4} print(counts["apples"]) print(counts.get("pears")) print(counts.get_def("pears", 0)) print("apples" in counts) print(len(counts)) ``` Direct indexing says the key must already exist. `get()` returns `None` when a key is missing. `get_def()` lets you provide a default value instead of handling `None` later.

    `None` is a real value, so `get()` is best when missing keys are normal and uninteresting. If `None` means something in your data, `get_def()` or an explicit membership test is clearer.

    ## Updating entries ```python counts = {"apples": 2, "bananas": 4} counts["bananas"] = 5 counts["pears"] = 1 del counts["apples"] print(counts) ``` Assigning to a key adds it if it is new or replaces the old value if it already exists. ## Removing entries ```python counts = {"apples": 2, "bananas": 4, "pears": 1} print(counts.pop("bananas")) print(counts.pop_def("missing", 0)) print(counts.popitem()) ``` `pop()` removes a key and returns its value. `pop_def()` does the same thing with a fallback when the key is absent. `popitem()` removes and returns one key/value pair. ## Iterating over dictionaries ```python counts = {"apples": 2, "bananas": 4, "pears": 1} for key in counts: print(key) for key, value in counts.items(): print(key, value) print(list(counts.keys())) print(list(counts.values())) print(list(counts.items())) ``` Iterating over a dictionary yields keys. Use `items()` when you need both the key and the value. ## Updating from other data ```python counts = {"apples": 2} more_counts = {"bananas": 4, "pears": 1} counts.update(more_counts.items()) counts.setdefault("apples", 0) counts.setdefault("grapes", 3) ``` `update()` merges entries from another iterable of key/value pairs. `setdefault()` is useful when you want to add a missing key only once and keep the existing value otherwise. ## Dictionary comprehensions ```python words = ["hello", "world", "acton"] lengths = {word: len(word) for word in words} filtered = {word: len(word) for word in words if len(word) > 4} indexed = {i: word for (i, word) in enumerate(words)} ``` Dictionary comprehensions are the concise way to build a dictionary from an iterable. They are useful when the new keys and values come from the old data directly. ================================================ FILE: docs/acton-guide/src/collections/lists.md ================================================ # Lists Lists are ordered, mutable sequences. Use them when position matters or when you want to keep adding and removing items over time.

    Think of a list as a numbered row of slots. Slot 0 is the first item, slot 1 is the second, and so on. A list holds one element type, so a list[str] is for strings only.

    ## Creating lists ```python fruits = ["apple", "banana", "orange"] tasks: list[str] = [] numbers: list[int] = [1, 2, 3] ``` Use a literal when you already have values. Use an empty list when you plan to fill it later. If the compiler cannot infer the element type from context, add an annotation.

    Lists are dynamic arrays. Appending is cheap most of the time because storage grows in chunks, not one item at a time.

    ## Reading values ```python items = ["first", "second", "third", "fourth"] print(items[0]) print(items[-1]) print(items[1:3]) print(len(items)) print("second" in items) print(items.index("third")) ``` Indexing starts at `0`. Negative indexes count from the end. Slices use the familiar `start:stop` form and include the start but exclude the stop.

    If you are coming from a one-based indexing language, the first item is still at position 0 here.

    ## Updating lists ```python items = ["first", "second", "third"] items.append("fourth") items.insert(1, "new") items.extend(["fifth", "sixth"]) print(items) print(items.pop()) print(items.pop(0)) del items[1] ``` `append()` adds one item to the end. `insert()` places an item at a specific index. `extend()` adds several items from another iterable. `pop()` removes and returns an item, and `del items[i]` removes by index without returning anything.

    Appends are amortized O(1). Inserting or deleting near the front of a long list is O(n) because elements need to shift. `pop()` is O(1) at the end and O(n) at other positions.

    ## Common utilities ```python values = [9, 5, 123, 14, 1, 5] print(sorted(values)) values.reverse() print(values) print(values.count(5)) copy_of_values = values.copy() values.clear() print(copy_of_values) print(values) ``` `sorted()` returns a new list. `reverse()` changes the existing list in place. `count()` scans the whole list and counts matches. `copy()` makes a shallow copy, which is enough when the elements themselves are simple values.

    If the list contains mutable values, a shallow copy only duplicates the outer list. The items inside are still shared.

    ## Iterating over lists ```python names = ["Ada", "Bjarne", "Grace"] for name in names: print(name) for i, name in enumerate(names): print(i, name) ``` Iteration gives you each item in order. Use `enumerate()` when you also need the current index. ## List comprehensions ```python numbers = [1, 2, 3, 4, 5] squares = [n * n for n in numbers] evens = [n for n in numbers if n % 2 == 0] ``` List comprehensions are the compact way to build a new list from an existing iterable. Read them as "make a list of this expression for each item that matches the condition". ## Type safety All items in a list must be of the same type. Mixing types like `["foo", 1, True]` will not compile. ```python strings = ["foo", "bar", "baz"] numbers = [1, 2, 3, 4, 5] ``` When a list is empty, give it a type if the surrounding code does not make the element type obvious. ================================================ FILE: docs/acton-guide/src/collections/sets.md ================================================ # Sets Sets store unique values. Use them when you care about membership or deduplication more than order.

    A set is like a bag of distinct items. Adding the same value twice does not create a duplicate. If you only need to know whether something is present, a set usually fits better than a list.

    ## Creating sets ```python tags = {"docs", "guide", "acton"} empty_tags: set[str] = set() ``` Use `{...}` for a non-empty set. Use `set()` for an empty one, because `{}` means an empty dictionary. ## Checking and updating ```python tags = {"docs", "guide"} print("docs" in tags) print("api" not in tags) tags.add("api") tags.add("docs") tags.discard("guide") tags.update({"reference", "tutorial"}) print(tags) print(len(tags)) ``` `add()` inserts one value. `discard()` removes a value if it is present and does nothing if it is not. `update()` adds values from another set or any iterable of values. ## Removing values ```python tags = {"docs", "guide", "acton"} print(tags.pop()) print(tags) ``` `pop()` removes and returns one element. On an empty set it raises an exception, so check before calling it if the set may be empty. ## Iteration and order ```python tags = {"docs", "guide", "acton"} for tag in tags: print(tag) print(sorted(tags)) ``` Sets do not preserve order. Do not rely on the printed order when the exact sequence matters. If you need stable display order, sort the set first. ## Set comprehensions ```python words = ["hello", "world", "hello", "acton"] unique_words = {word for word in words} long_words = {word.upper() for word in words if len(word) > 4} remainder_classes = {n % 3 for n in range(10)} ``` Set comprehensions are a compact way to build a set while automatically removing duplicates. ================================================ FILE: docs/acton-guide/src/collections.md ================================================ # Collections and everyday data Acton has three built-in collection types for everyday data: - [Lists](collections/lists.md) keep values in order and allow duplicates. - [Dictionaries](collections/dicts.md) map keys to values. - [Sets](collections/sets.md) keep unique values and make membership checks direct.

    If you are unsure where to start, choose by the question you want to answer. Use a list when order matters, a dictionary when you need to look things up by key, and a set when you mainly care about uniqueness or membership.

    Use this section when you need to keep many values together and work with them as one logical value. Collections pair naturally with [higher order functions](functions/higher_order.md) and comprehensions. That is the common Acton path for turning one collection into another without spreading the transformation across several places. All collection types are statically typed. A list has one element type, a set has one element type, and a dictionary has one key type and one value type. ================================================ FILE: docs/acton-guide/src/compilation/incremental.md ================================================ # Content hash driven incremental compilation Acton tracks changes at a finer level than whole modules so builds stay fast as your project grows. The compiler keeps multiple different hashes and uses them to decide what and how to recompile. ## What gets hashed and tracked - **moduleSrcBytesHash**: hash of the raw bytes for a whole `.act` file. It is very cheap to read and hash a `.act` file from disk (GB/s). This is stored in the `.ty` file and is the authority for deciding whether a cached typed module still matches the source. Parsing is not incremental, it only supports re-parsing a complete module, which is also why a single hash for the entire `.act` module file makes sense. - **per-name srcHash**: hash of a name's source code. Since this is only the hash of the source code, it can be computed after the parser and before type checking in order to determine what functions we need to rerun through later passes, including type checking which is typically a relatively expensive pass. Note how the next pubHash and implHash are after type checking, so they cannot be used in order to determine if type-checking should be rerun for a function. - **per-name pubHash**: hash of a name's public interface (its type signature). Downstream modules only need to re-typecheck if a pubHash they depend on changes. The pubHash also contains the hashes of dependencies, and if those change, our pubHash will change, thus causing re-typecheck. - **per-name implHash**: hash of a name's implementation plus the impl hashes it depends on. If an implHash changes, we re-run back passes and tests. - **per-name pubDeps**: the public (type signature) hashes of other names that we depend on. If the hashes of any deps change, we must re-typecheck. - **per-name implsDeps**: the hashes of the implementation of other names that we depend on. If the hashes of any deps change, we must rerun back passes. Most names have both a pubHash and implHash. Some derived internal names only have implHash. ## How `.ty` cache validity is decided Each module gets a cached typed interface file in `out/types/.ty`. That cache stores: - the module source content hash (`moduleSrcBytesHash`) - fast-path source metadata such as modification time, change time, and file size - file identity metadata where available, such as inode/device on POSIX - the compiler/cache schema version The important rule is: - **content hash is the correctness authority** - **filesystem metadata is only a fast path** In practice, Acton decides reuse like this: 1. If the `.ty` file is missing, unreadable, or from an incompatible cache schema version, Acton reparses the `.act` file and rebuilds the `.ty`. 2. If the cached source metadata still matches the current source file and the source mtime is strictly older than the `.ty` mtime, Acton reuses the `.ty` header immediately without reading and hashing the source. 3. If the metadata differs, or the source and `.ty` mtimes are equal, Acton reads the `.act` file and compares its content hash to the stored `moduleSrcBytesHash`. 4. If the hash matches, the source content is unchanged, so Acton reuses the cached `.ty` and refreshes the stored source metadata. 5. If the hash differs, the source really changed, so Acton reparses and recompiles that module. This means harmless metadata drift, like a `touch`, checkout, restore, copy, or cross-machine sync, does not by itself force a front-end rebuild. It also means misleading timestamps cannot cause stale typed-module reuse, because Acton falls back to the source content hash before trusting the cache. The strict `source mtime < .ty mtime` check matters on filesystems with coarse mtime resolution. If a source edit and `.ty` write land in the same timestamp tick, equal mtimes are ambiguous: the source may already have changed even though the cached source metadata still looks identical. Acton therefore treats equal source and `.ty` mtimes as a signal to hash the current source instead of taking the metadata-only fast path. ## What changes cause what work **Change function body, same signature** ``` # a.act def apa() -> int: return 1 def a() -> int: return apa() ``` ``` # c.act import a import testing def _test_foo() -> None: testing.assertEqual(a.a(), 1) ``` If you change `apa()` to return `2`, only the impl hashes change since the return type and overall type signature remains the same. `c` does not re-typecheck, but back passes and tests are re-run. Example `acton build --verbose` output (trimmed): ``` Stale a: source changed Stale c: impl changes in a.a (used by _test_foo) ``` **Change a signature** If `a.a()` changes its return type, its pubHash changes. Any module that uses `a.a()` will re-run front passes. ``` Stale c: pub changes in a.a (used by _test_foo) ``` **Add or remove an unused import** If no name actually uses the import, per-name deps do not change, so nothing propagates. Changes are only computed and propagated for names that are actually in use, which also means that it is possible to create quite large and monolithic modules without paying a higher cost for longer compilation times of downstream dependents. ## Code generation staleness Generated C/H files embed the module impl hash. If the embedded hash differs from the current module impl hash, the compiler treats the generated code as out of date and regenerates it. ## Tests and hashes Test results are cached by the per-name implHash (plus impl deps). Cached failures are still shown by default. Use `--show-cached` to include cached successes, or `--no-cache` to force reruns. For more on tests, see the [Testing](testing.md) section. ================================================ FILE: docs/acton-guide/src/compilation.md ================================================ # Compilation Acton is a compiled language and as such, outputs binary executables. While compiled languages are often associated with long compilation times that slow down development, Acton goes to great lengths to offer a great developer experience. Content hashing is used extensively to carefully invalidate and recompile only necessary parts, see [incremental compilation](compilation/incremental.md) for more details. It is possible to influence the compilation process and the output in various ways. ## Optimization modes Acton defaults to `Debug` builds. Debug builds compile fast and include debug symbols, which makes them the right default during development. For release builds, use `acton build --release` to better optimize the final executable. For standalone files, use `acton --release foo.act`. `--release` and `--release=fast` select the fastest release mode. `--release=safe` enables release optimizations with safety checks. `--release=small` optimizes for a smaller binary size. ## Optimized for native CPU features The default target is somewhat conservative to ensure a reasonable amount of compatibility. On Linux, the default target is GNU Libc version 2.27 which makes it possible to run Acton programs on Ubuntu 18.04 and similar old operating systems. Similarly, a generic x86_64 CPU is assumed which means that newer extra CPU instruction sets are not used. To compile an executable optimized for the local computer, use `--target native`. In many cases it can lead to a significant faster program, often running 30% to 100% faster. ## Statically linked executables using musl for portability On Linux, executable programs can be statically linked using the Musl C library, which maximizes portability as there are no runtime dependencies at all. To compile an executable optimized for portability using musl on x86_64, use `--target x86_64-linux-musl`. A default compiled program is dynamically linked with GNU libc & friends ``` $ acton helloworld.act Building file helloworld.act Compiling helloworld.act for release Finished compilation in 0.013 s Final compilation step Finished final compilation step in 0.224 s $ ldd helloworld linux-vdso.so.1 (0x00007fff2975b000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f11f472a000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f11f4725000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f11f4544000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f11f453f000) /lib64/ld-linux-x86-64.so.2 (0x00007f11f4827000) $ ``` A program linked statically towards Musl has no run time dependencies: ``` $ acton helloworld.act --target x86_64-linux-musl Building file helloworld.act Compiling helloworld.act for release Finished compilation in 0.013 s Final compilation step Finished final compilation step in 0.224 s $ ldd helloworld not a dynamic executable $ ``` Although untested, static linking with musl should work on other CPU architectures. MacOS does not support static compilation. ## Cross-compilation Acton supports cross-compilation, which means that it is possible to run develop on one computer, say a Linux computer with an x86-64 CPU but build an executable binary that can run on a MacOS computer. Here's such an example. We can see how per default, the output is an ELF binary for x86-64. By setting the `--target` argument, `acton` will instead produce an executable for a Mac. ``` $ acton --quiet helloworld.act $ file helloworld helloworld: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.0.0, with debug_info, not stripped $ acton --quiet helloworld.act --target x86_64-macos-none $ file helloworld helloworld: Mach-O 64-bit x86_64 executable, flags: ``` It is not only possible to compile for other operating systems, but also for other CPU architectures. For example, use `--target aarch64-macos-any` to produce a binary executable for an Apple M1/M2 CPU. ## Prebuilt libraries Acton ships with prebuilt libraries for the local platforms default target, i.e. if you install Acton on a x86-64 Linux machine, it will have libraries prebuilt for x86_64-linux-gnu.2.27. The default target uses these prebuilt libraries which results in a fast build: ``` $ acton helloworld.act Building file helloworld.act Compiling helloworld.act for release Finished compilation in 0.013 s Final compilation step Finished final compilation step in 0.224 s $ ``` When targeting something that is not the default target, the entire Acton system, including builtins, the run time system, the standard library and external library dependencies is built from source and can take a significant amount of time. The build process is highly parallelized and cached. For example, on an AMD 5950X with 16 cores / 32 threads, it takes around 7 seconds to do a complete rebuild for a small Acton program as can be seen here: ``` $ acton helloworld.act --target aarch64-macos-none Building file helloworld.act Compiling helloworld.act for release Finished compilation in 0.012 s Final compilation step Finished final compilation step in 6.847 s $ ``` ## Build cache In an Acton project, there is a build cache, is is stored in a directory called `build-cache` in the project directory. The cache is always used for the project local files. If a non-default `--target` is being used, the built output of the Acton system is also stored in the cache, which means that it is only the first time around that it is slow. Any subsequent build is going to use the cache and run very fast. Like in this example, where the first invocation takes 6.120 seconds and the second one runs in 0.068 seconds. ``` $ acton new hello Created project hello Enter your new project directory with: cd hello Compile: acton build Run: ./out/bin/hello Initialized empty Git repository in /home/kll/hello/.git/ $ cd hello/ $ acton build --target native Building project in /home/kll/hello Compiling hello.act for release Finished compilation in 0.012 s Final compilation step Finished final compilation step in 6.120 s $ acton build --target native Building project in /home/kll/hello Compiling hello.act for release Already up to date, in 0.000 s Final compilation step Finished final compilation step in 0.068 s $ ``` When compiling standalone .act files, there is no project and thus no persistent cache, so using a custom `--target` will always incur a penalty. ================================================ FILE: docs/acton-guide/src/control_flow/actors.md ================================================ # Control flow in an async actor world Acton programs do not have only one simple top-to-bottom control flow. Once an actor exists, it keeps living and reacting to incoming method calls until it stops. That means control flow is closer to "react to messages over time" than to "run one main function and finish immediately".

    If you are new to this style, start with one actor and a few methods. Then add async calls and delayed work once the basic message flow makes sense. Inside one actor, each message still runs sequentially; the new part is thinking about what messages may arrive next.

    This reactive model means message order belongs to each actor's own mailbox and handling, not one global timeline for the whole program. That same boundary is why callbacks, async calls, and actor lifetime fit together in Acton.

    ## A mental model It helps to think in terms of actors reacting: - an actor receives a method call - it handles that work sequentially - it may call other actors - it may schedule more work with `after` - then it becomes idle again until the next message arrives This is why actor code often looks different from ordinary function code. The interesting question is usually not just "what happens next?", but also "what happens later, and in response to what message?" ================================================ FILE: docs/acton-guide/src/control_flow/after_sleep.md ================================================ # `after` and sleep Use `after` when work should happen later. `after 1: tick()` tells the runtime to schedule `tick()` to run about one second later. Meanwhile, the actor is free to handle other messages.

    If you would normally reach for sleep() in another language, first ask whether what you really want is "run this later". In Acton, that usually means after. Read after 1: tick() as "schedule this call for later", not "pause here for one second".

    ```python actor main(env): var count = 0 def tick(): print("tick", count) count += 1 if count >= 3: env.exit(0) else: after 1: tick() tick() ``` `after` is the normal tool for: - timeouts - retries - pacing repeated work - scheduling a follow-up action ## Why not `sleep`? Normal actor code should avoid blocking waits. A delayed callback with `after` lets the actor go idle and react to other messages in the meantime.

    There is a low-level sleep in the RTS for debugging and runtime work, but it is not the idiomatic control tool for actor programs. after keeps the actor schedulable, and the callback sees whatever state the actor has when that later message is handled.

    ================================================ FILE: docs/acton-guide/src/control_flow/for.md ================================================ # for Use `for ... in ...` to go through each value in something like a string, tuple, or `range(...)`. ```python actor main(env): names = ("Ada", "Grace", "Linus") for name in names: print("Hello", name) for n in range(3): print("n =", n) env.exit(0) ```

    A for loop is the usual choice when you want to go through each item in a collection or repeat something a known number of times. The loop variable is a new local name that takes on each value in turn.

    `range(stop)` counts from `0` up to, but not including, `stop`. ```python for n in range(5): print(n) ``` You can also use `range(start, stop, step)`. ```python for n in range(2, 10, 2): print(n) ``` The loop variable is local to the loop body. A common pattern is to use `for` with a collection when the values matter, and `range(...)` when the count matters.

    In Acton, for is usually the clearest way to consume an iterable because it avoids manual index state and keeps the element type front and center. When you need both the index and the value, prefer enumerate(...) over range(...). Use range(...) when the numbers themselves matter, not as a default substitute for iterating a collection.

    ```python for i, name in enumerate(names): print(i, name) ```
    ================================================ FILE: docs/acton-guide/src/control_flow/if_else.md ================================================ # if / elif / else Use `if` to run code only when a condition is true. Use `elif` for more cases and `else` for the fallback case. ```python def describe(n): if n < 0: return "negative" elif n > 0: return "positive" else: return "zero" actor main(env): print(describe(-7)) print(describe(0)) print(describe(5)) env.exit(0) ``` The conditions in `if`, `elif`, and `while` are expressions that evaluate to `True` or `False`. ```python n = 7 if n % 2 == 0: print("even") else: print("odd") ```

    Conditionals compose with Acton's expression model, so guards often mix comparisons, membership tests, and short-circuiting in one place. Once the branching logic starts encoding type or protocol decisions, helper functions or explicit narrowing usually read better than a long ladder.

    ================================================ FILE: docs/acton-guide/src/control_flow/while.md ================================================ # while Use `while` when you want to keep looping for as long as a condition stays true. ```python actor main(env): var remaining = 3 while remaining > 0: print("remaining:", remaining) remaining -= 1 print("done") env.exit(0) ```

    With while, make sure something in the loop body can eventually make the condition false. If that condition depends on a changing value in actor code, that value usually needs var.

    `while` is useful when the number of iterations is not the main point. What matters is the condition. ```python actor main(env): var retries = 5 while retries > 0: print("trying...") retries -= 1 env.exit(0) ``` If you already have a collection or a simple numeric range, a `for` loop is usually clearer than a `while` loop. Reach for `while` when the condition really is the center of the logic.

    A while loop makes state transitions explicit, which is useful for retries and actor-local state machines. The tradeoff is that you now own the loop invariant and termination condition, so it is more error-prone than for when the iteration boundary is already known.

    Typical uses include retry loops, waiting for a condition to change, and small state machines where each pass updates the state before checking again. ================================================ FILE: docs/acton-guide/src/control_flow.md ================================================ # Control flow Control flow decides which code runs, when it runs, and how often it runs. Acton does not have a Rust-style `match` expression. Use `if`/`elif`/`else` for branching, and combine that with optionals or exceptions when the question is about absence or failure. Start with these three everyday tools: - [`if` / `elif` / `else`](control_flow/if_else.md) for branching - [`for`](control_flow/for.md) for iterating over items - [`while`](control_flow/while.md) for repeating while a condition stays true Loops also support a few extra tools: - `break` to stop the loop early - `continue` to skip to the next iteration - `else` to run code after a loop finishes normally, without a `break`

    If you are new to programming, start with if, for, and while and treat loop else as optional. Most code uses the first three tools far more often.

    ```python for n in range(5): if n == 2: continue if n == 4: break print(n) else: print("finished without break") ```

    Loop else is tied to break, not to "zero iterations". It runs whenever the loop finishes normally, which makes it useful for search-style logic but easy to misread if used casually.

    Acton also has actor-specific control patterns such as [`after`](control_flow/after_sleep.md). Those matter once you start thinking about actors, timers, and concurrency. ================================================ FILE: docs/acton-guide/src/environment/interactive_stdin.md ================================================ # Interactive stdin Interactive programs do not usually want line-buffered input. A text editor, a terminal UI, or a game often needs individual key presses as they happen. By default, stdin is in canonical mode. That means the terminal buffers input and usually handles line editing before your program sees anything. If you want raw key presses, switch stdin to non-canonical mode. ```python actor main(env): def interact(input): print("Got some input:", input) # Set non-canonical mode so we get each key press directly. env.set_stdin(canonical=False) # Turn off terminal echo. env.set_stdin(echo=False) env.stdin_install(interact) ``` Canonical mode is the right default for ordinary command line tools. Non-canonical mode is for programs that need to manage the terminal themselves. The runtime copies the terminal settings on startup and restores them on exit, so you do not need to restore echo manually in the common case.

    Interactive stdin changes the terminal contract for the whole process, not just one helper function. That is why the runtime restores settings on exit for you, and why these programs should be careful and intentional about when they enter non-canonical mode.

    ## Common patterns Switch to non-canonical mode only when you need it, and keep that code close to the part that depends on raw input. That makes the terminal state easier to reason about. Disable echo when raw input should not be shown back to the user, such as when reading passwords or handling single-key commands. ================================================ FILE: docs/acton-guide/src/environment/stdin.md ================================================ # Reading stdin input Read from stdin by installing a handler with `env.stdin_install`. The handler receives data as it arrives. In the common text case, the data is decoded to `str`. ```python actor main(env): def interact(input): print("Got some input:", input) env.stdin_install(interact) ``` You can make the text decoding explicit by providing `on_stdin`, `encoding`, and `on_error`. When `encoding` is not set, Acton tries to discover the encoding from `LANG`. If nothing useful is found, it falls back to UTF-8. ```python actor main(env): def interact(input): print("Got some input:", input) def on_stdin_error(err, data): print("Some error with decoding the input data:", err) print("Raw bytes data:", data) env.stdin_install(on_stdin=interact, encoding="utf-8", on_error=on_stdin_error) ``` If the data is binary, or if you want to delay decoding, install a bytes handler instead. ```python actor main(env): def interact(bytes_input): # Decode only when this code is ready to decide how. print("Got some input:", bytes_input.decode()) env.stdin_install(on_stdin_bytes=interact) ```

    The important distinction is between a decoded text stream and a raw byte stream. If the input protocol is truly textual, the string path is usually right. If framing, binary payloads, or uncertain encodings matter, keep the data as bytes until your own code decides how to decode it.

    ## Common patterns Use the text callback for ordinary command line input, especially when the input is line-oriented or clearly textual. Use the bytes callback when the input may contain binary data, partial fragments of multibyte characters, or a protocol with its own framing rules. Treat decode errors as part of the interface. If the program expects text, decide what to do when the bytes do not decode cleanly instead of letting that decision hide inside a helper. ================================================ FILE: docs/acton-guide/src/environment/variables.md ================================================ # Environment variables Environment variables are a common way to pass configuration into a program. Acton lets you read, set, and unset them through `env`. The string-based helpers are the most convenient: - `env.getenv(name)` returns a `str` or `None` - `env.setenv(name, value)` stores a string value - `env.unsetenv(name)` removes a variable They assume UTF-8 text, which is practical for most programs. When you need exact byte-level control, use the byte-oriented variants instead: - `env.getenvb` - `env.setenvb` - `env.unsetenvb`

    The string helpers are deliberately opinionated. They make the common case easy, but they also make the text boundary explicit. If your code needs to preserve the original bytes, avoid round-tripping through str until you have chosen a decoding strategy yourself.

    ```python actor main(env): env_user = env.getenv("USER") if env_user is None: env_user = "unknown" print("User:", env_user) if env.getenv("FOO") is None: env.setenv("FOO", "bar") foo_env = env.getenv("FOO") if foo_env is not None: print("FOO:", foo_env) env.unsetenv("LANG") env.exit(0) ``` Output: ```sh User: myuser FOO: bar ``` ## Common patterns Read a variable once, check whether it is missing, and choose a safe default. Do not assume configuration is always present. Use environment variables for configuration values that are naturally textual, such as names, paths, flags, and addresses. If the value is binary or needs exact decoding rules, use the byte-oriented APIs and decode in your own code. When a program sets or unsets variables, it is changing process state, not just a local dictionary. Keep that in mind when passing `env` through helpers. ================================================ FILE: docs/acton-guide/src/environment.md ================================================ # Environment The environment is your program's practical link to the outside world. Most programs meet it first as the `env` argument passed to the root actor. The root actor receives the builtin environment actor `Env` as its `env` parameter. `Env` is the runtime-provided handle for outside-world access. ```python actor main(env): print("args:", env.argv) env.exit(0) ```

    You can think of env as the handle your program receives for talking to the world around it. It is passed into main; it is not a hidden global that every function can reach automatically. If a helper only needs one small piece of that power, pass the smaller piece instead of the whole environment.

    `Env` provides, among other things: - `env.argv` for command-line arguments - `env.cap` for the root `WorldCap` capability - `env.getenv`, `env.setenv`, and `env.unsetenv` for environment variables - `env.stdin_install`, `env.set_stdin`, `env.stdout_write`, and `env.is_tty` for terminal and stdin handling - `env.exit(n)` to terminate the program - [Environment variables](environment/variables.md) - [Reading stdin input](environment/stdin.md) - [Interactive stdin input](environment/interactive_stdin.md) Use `env` when code needs process arguments, environment variables, standard input, or terminal configuration. Pass it only to the code that actually needs that access.

    env is best understood as a bundle of process-level capabilities, not as one ordinary argument. It carries authority over things such as arguments, environment variables, standard input, and terminal configuration. If that whole bundle gets threaded through many layers, those layers quietly become coupled to process concerns even when they only need one small part of it.

    In larger programs, treat the root actor as the place where broad authority is received, then pass inward only the narrower capability or value a helper actually needs. That keeps APIs honest about what they depend on, makes tests easier to fake, and prevents a small utility from accidentally gaining much wider access to the outside world than its job requires.

    ================================================ FILE: docs/acton-guide/src/ext/integrating_c_library.md ================================================ # Integrating a C library (zlib) This is a guide to integrating C libraries in Acton code. We will use the zlib compression library, written in C, to build an Acton module that supports zlib compression and decompression. We will only focus on the `inflate` and `deflate` functions in zlib. They are pure functions (meaning they only take some input and return some output, they do not have any side effects like writing to some shared state), that makes them easier to integrate than anything that does I/O. While zlib does expose functions to interact with files, we don't want to reimplement file related functionality since we already have this supported by the Acton stdlib. ## Create new project Let's start by making a new Acton project, let's call it `acton-zlib`. New projects are created with an example "Hello world" app. Let's remove it and start from scratch. ```console acton new acton-zlib cd acton-zlib rm src/* ``` ## Acton's low level build system - the Zig build system The Acton compiler parses .act source code, runs through all its compilation passes with type checking, CPS conversion, lambda lifting etc and finally produces C code. Internally, Acton then uses the Zig build system to compile the generated C code to libraries and finally binary executables. To add a C library dependency, it first needs to be buildable using the Zig build system, which means that it needs a `build.zig` file, the config file for the Zig build, somewhat similar to the CMakeLists.txt of CMake. Some projects have already adopted a `build.zig` in the upstream repo, like PCRE2 and the Boehm-Demers-Weiser GC (both of which are used by Acton). In some cases, there are forks of projects with `build.zig` added. Otherwise you will need to write one for yourself, which is usually simpler than it might first seem. ## Add the zlib C library as a Zig dependency In the case of zlib, there is already [a repo available with a build.zig for zlib](https://github.com/allyourcodebase/zlib/). Navigate to the Tags page, find `1.3.1` and the link to the source files, i.e. `https://github.com/allyourcodebase/zlib/archive/refs/tags/1.3.1.tar.gz`. Add it to our `acton-zlib` project: ```console acton zig-pkg add https://github.com/allyourcodebase/zlib/archive/refs/tags/1.3.1.tar.gz zlib --artifact z ``` Note the `--artifact z` which is provided to instruct which library to link with. Headers from the zlib library, like `zlib.h`, will now become visible to C files in our project and the `z` library will be linked in with our executables. The easiest way to discover what the artifacts are called is by inspecting the `build.zig` file of the package. This particular zlib `build.zig` starts like this: ```zig const std = @import("std"); pub fn build(b: *std.Build) void { const upstream = b.dependency("zlib", .{}); const lib = b.addStaticLibrary(.{ .name = "z", .target = b.standardTargetOptions(.{}), .optimize = b.standardOptimizeOption(.{}), }); lib.linkLibC(); lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "adler32.c", "crc32.c", ... ``` It is the `.name` argument to `addStaticLibrary` that tells us the name of the artifact. Zig packages might expose multiple such artifacts, as is the case for [mbedtls](https://github.com/actonlang/mbedtls/blob/zig-build/build.zig). `acton zig-pkg add` will fetch the package from the provided URL and save the hash sum to `Build.act`, resulting in: ```python dependencies = {} zig_dependencies = { "zlib": ( url="https://github.com/allyourcodebase/zlib/archive/refs/tags/1.3.1.tar.gz", hash="122034ab2a12adf8016ffa76e48b4be3245ffd305193edba4d83058adbcfa749c107", artifacts=["z"] ), } ``` ## Create zlib.act Acton module Next up we need to create the Acton `zlib` module. Open `src/zlib.act` and add a compress and decompress function: ```python pure def compress(data: bytes) -> bytes: NotImplemented pure def decompress(data: bytes) -> bytes: NotImplemented ``` The `NotImplemented` statement tells the compiler that the implementation is not written in Acton but rather external. When there is a `.ext.c` file, the compiler expects it to contain the implementations for the `NotImplemented` functions. Also note the explicit types. Normally the Acton compiler can infer types, but since there is no Acton code here, only C code, there is nothing to infer from. Now create `src/zlib.ext.c` which is where we will do the actual implementation of these functions. We need to add a `__ext_init__` function, which runs on module load by the Acton RTS, which must always exist. There is nothing to do in particular for zlib so let's just create an empty function, like so: ```c void zlibQ___ext_init__() {} ``` Next, we need to fill in the C functions that map to the Acton functions `compress` and `decompress`. By invoking `acton build` we can get the compiler to generate a skeleton for these. We will also get a large error message, since there is no actual implementation: ```console user@host$ acton build ... some large error message ``` Ignore the error and instead check the content of `out/types/zlib.c` and we will find the C functions we need, commented out: ``` #include "rts/common.h" #include "out/types/zlib.h" #include "src/zlib.ext.c" B_bytes zlibQ_compress (B_bytes data); /* B_bytes zlibQ_compress (B_bytes data) { // NotImplemented } */ B_bytes zlibQ_decompress (B_bytes data); /* B_bytes zlibQ_decompress (B_bytes data) { // NotImplemented } */ int zlibQ_done$ = 0; void zlibQ___init__ () { if (zlibQ_done$) return; zlibQ_done$ = 1; zlibQ___ext_init__ (); } ``` Copy the commented-out skeleton into our own `src/zlib.ext.c`. Just in order to get something that compiles, let's just quickly let the functions return the input data. Since both input and output are `bytes`, this should now compile (and work at run time). ```c B_bytes zlibQ_compress (B_bytes data) { return data; } B_bytes zlibQ_decompress (B_bytes data) { return data; } ``` ```console user@host:~/acton-zlib$ acton build Building project in /Users/user/acton-zlib Compiling zlib.act for release Finished compilation in 0.005 s Compiling test_zlib.act for release Finished compilation in 0.019 s Final compilation step user@host:~/acton-zlib$ ``` ## Add a test module Before we implement the body of the compress and decompress functions, we can write a small test module which will tell us when we've succeeded. We use some pre-known test data (which we could get from another language implementation): ```python import testing import zlib def _test_roundtrip(): for x in range(100): i = "hello".encode() c = zlib.compress(i) d = zlib.decompress(c) testing.assertEqual(i, d) def _test_compress(): for x in range(100): i = "hello".encode() c = zlib.compress(i) testing.assertEqual(c, b'x\x9c\xcbH\xcd\xc9\xc9\x07') def _test_decompress(): for x in range(1000): c = b'x\x9c\xcbH\xcd\xc9\xc9\x07' d = zlib.decompress(c) testing.assertEqual(d, b'hello') ``` Note how we run a few test iterations to get slightly better timing measurements for performance testing. Run the test with `acton test`: ```console user@host:~/acton-zlib$ acton test Tests - module test_zlib: decompress: FAIL: 195 runs in 50.728ms testing.NotEqualError: Expected equal values but they are non-equal. A: b'x\x9c\xcbH\xcd\xc9\xc9\x07' B: b'hello' compress: FAIL: 197 runs in 50.886ms testing.NotEqualError: Expected equal values but they are non-equal. A: b'hello' B: b'x\x9c\xcbH\xcd\xc9\xc9\x07' roundtrip: OK: 226 runs in 50.890ms 2 out of 3 tests failed (26.354s) user@host:~/acton-zlib$ ``` As expected, the roundtrip test goes through, since we just return the input data while the compress and decompress tests fail. ## Implement the compress function Now let's fill in the rest of the owl. Below is the body of the `zlibQ_compress` function. The bulk of this code is not particularly interesting to this guide as it has more to do with standard C usage of zlib, but a few things are worth noting. ```c B_bytes zlibQ_compress(B_bytes data) { if (data->nbytes == 0) { return data; } // Prepare the zlib stream int ret; z_stream stream; memset(&stream, 0, sizeof(stream)); ret = deflateInit(&stream, Z_DEFAULT_COMPRESSION); if (ret != Z_OK) { $RAISE((B_BaseException)$NEW(B_ValueError, to$str("Unable to compress data, init error: %d", ret))); } // Set the input data stream.avail_in = data->nbytes; stream.next_in = (Bytef*)data->str; // Allocate the output buffer using Acton's malloc size_t output_size = deflateBound(&stream, data->nbytes); Bytef* output_buffer = (Bytef*)acton_malloc_atomic(output_size); stream.avail_out = output_size; stream.next_out = output_buffer; // Perform the deflate operation ret = deflate(&stream, Z_FINISH); if (ret != Z_STREAM_END) { $RAISE((B_BaseException)$NEW(B_ValueError, $FORMAT("Unable to compress data, error: %d", ret))); } // Clean up deflateEnd(&stream); return actBytesFromCStringNoCopy(output_buffer); } ``` Memory management is always top of mind when writing C, as it the case here. We can allocate memory via the Acton GC-heap malloc or just plain `malloc()` (the non-GC heap, to be explicit). Since `zlibQ_compress` is pure, we have no state leaking out of the function other than via its return value. All return values must be allocated on the Acton GC heap, so we know we must use `acton_malloc` for any value that we return. Any other local variables within the function can use classic malloc, as long as we make sure to explicitly free it up. For class or actor methods, any allocation for class or actor attributes must be performed using the Acton GC malloc, since there is no destructor or similar where a free can be inserted, so using classic malloc would be bound to leak. Also note that in this particular case, we know that the returned bytes value itself is not going to contain any pointers, so by using `acton_malloc_atomic` we can get a chunk of memory that will not be internally scanned by the GC, which saves a bit of time and thus improves GC performance. If we allocate structs that do carry pointers, they must use the normal `acton_malloc()`. `actBytesFromCStringNoCopy(output_buffer)` takes the `buffer` (already allocated via `acton_malloc_atomic()`) and wraps it up as a boxed value of the type `B_bytes` that we return. Also note how we convert Zlib errors to Acton exceptions where necessary. Running the test, the `compress` test now passes while roundtrip has stopped working (since decompress is not implemented yet): ```console user@host:~/acton-zlib$ acton test Tests - module test_zlib: decompress: FAIL: 158 runs in 50.175ms testing.NotEqualError: Expected equal values but they are non-equal. A: b'x\x9c\xcbH\xcd\xc9\xc9\x07' B: b'hello' compress: OK: 167 runs in 50.225ms roundtrip: FAIL: 147 runs in 50.266ms testing.NotEqualError: Expected equal values but they are non-equal. A: b'hello' B: b'x\x9c\xcbH\xcd\xc9\xc9\x07' 2 out of 3 tests failed (0.941s) user@host:~/acton-zlib$ ``` ## Implement the decompress function Much like the compress function, the decompress function mostly relates to how zlib itself and its interface works. We use the same wrappers and transform errors to exceptions. ```c B_bytes zlibQ_decompress(B_bytes data) { if (data->nbytes == 0) { return data; } // Prepare the zlib stream int ret; z_stream stream; memset(&stream, 0, sizeof(stream)); ret = inflateInit(&stream); if (ret != Z_OK) { $RAISE((B_BaseException)$NEW(B_ValueError, $FORMAT("Unable to decompress data, init error: %d", ret))); } // Set the input data stream.avail_in = data->nbytes; stream.next_in = (Bytef*)data->str; // Allocate the output buffer using Acton's malloc size_t output_size = 2 * data->nbytes; // Initial output buffer size Bytef* output_buffer = (Bytef*)acton_malloc_atomic(output_size); memset(output_buffer, 0, output_size); stream.avail_out = output_size; stream.next_out = output_buffer; // Perform the inflate operation, increasing the output buffer size if needed do { ret = inflate(&stream, Z_NO_FLUSH); if (ret == Z_BUF_ERROR) { // Increase the output buffer size and continue decompressing size_t new_output_size = output_size * 2; output_buffer = (Bytef*)acton_realloc(output_buffer, new_output_size); stream.avail_out = new_output_size - stream.total_out; stream.next_out = output_buffer + stream.total_out; } else if (ret != Z_OK) { $RAISE((B_BaseException)$NEW(B_ValueError, $FORMAT("Unable to decompress data, error: %d", ret))); } } while (ret == Z_BUF_ERROR); // Clean up inflateEnd(&stream); return actBytesFromCStringNoCopy(output_buffer); } ``` ## Final test ```console user@host:~/acton-zlib$ acton test Tests - module test_zlib: decompress: OK: 42 runs in 51.065ms compress: OK: 25 runs in 50.032ms roundtrip: OK: 24 runs in 50.053ms All 3 tests passed (0.738s) user@host:~/acton-zlib$ ``` And with that, we're done! A simple wrapper around zlib, which is also available [on GitHub](https://github.com/actonlang/acton-zlib) if you want to study it further. ================================================ FILE: docs/acton-guide/src/functions/actor_methods.md ================================================ # Actor methods Actor methods are declared inside an `actor` with `def`. An actor method runs in the context of that actor and can access its private state.

    An actor method is like a normal method with one extra idea: it runs inside an actor that owns its own state and message flow. That is why a method like compute can use secret without receiving it as an argument each time.

    Local actor methods can call each other by name. Methods on other actors are called through that actor's reference.

    Because actors are sequential, local function calls and local method calls run one step at a time inside that actor. Concurrency appears when actors call each other. Whether a remote call is sync or async changes ordering and waiting behavior, not just syntax.

    ```python def multiply(a, b): return a * b actor main(env): var secret = 42 def compute(a): return multiply(a, secret) result = compute(3) print("Result:", result) env.exit(0) ``` Actor methods are public by default. Calls to other actors can be [synchronous](../actors/sync_method_call.md) or [asynchronous](../actors/async_method_call.md). ================================================ FILE: docs/acton-guide/src/functions/higher_order.md ================================================ # Higher order functions Acton supports higher order functions, which means you can pass a function as an argument to another function and choose behavior at the call site. That is Acton's nearest equivalent to the reusable part of Rust's closure and iterator story. Acton does not have a Rust-style closure or iterator-adapter path to learn first; use higher-order functions, comprehensions, and explicit iteration instead.

    A function can be treated like any other value. That makes it easy to reuse one loop, one validation path, or one calculation with different behaviors plugged in.

    ```python def apply_twice(fun, value): return fun(fun(value)) def double(n): return 2 * n def square(n): return n * n actor main(env): print(apply_twice(double, 3)) print(apply_twice(square, 2)) env.exit(0) ``` This prints: ```sh 12 16 ``` Use this pattern when the operation is the thing that changes and the overall shape of the work stays the same.

    Higher order functions work best when the varying behavior is small, stateless, and easy to describe as "apply this operation here". That makes them a good fit for callbacks, adapters, validation hooks, and small reusable transformation steps. Once the behavior needs evolving state across calls, the design question changes: you are no longer just passing behavior, you are passing behavior plus state.

    At that point, an actor or a small object is often a better home than trying to simulate closure-heavy code by threading more and more helper arguments through every call. The same applies to collection work: if a transformation is local and easy to read, a comprehension or short loop usually expresses it more clearly than a stack of tiny callback-style helpers. Reach for higher order functions when they clarify the reusable variation, not just because the language allows them.

    ================================================ FILE: docs/acton-guide/src/functions.md ================================================ # Functions Functions package reusable logic behind a name. Declare a function with `def`. Functions are values too, so you can pass behavior into another function when the call site should choose the variation. See [Higher order functions](functions/higher_order.md) for that pattern. ```python def clamp(n, low, high): if n < low: return low if n > high: return high return n actor main(env): print(clamp(3, 0, 5)) print(clamp(-2, 0, 5)) print(clamp(9, 0, 5)) env.exit(0) ``` Function arguments are local names inside the function body.

    Type inference makes local helpers cheap to write, but it does not make their types unimportant. As soon as a function is used across a module boundary, callers depend on whatever the compiler inferred for its arguments, return value, effects, and generic constraints. Those facts are part of the callable contract even when no explicit signature appears in the source.

    That has a practical consequence: changing a function from pure to proc, tightening a generic bound, or making a result optional is not just an implementation tweak. It can force changes at call sites. That is why public functions deserve a higher bar than local helpers. It is often fine to let inference handle small local code, but API-facing functions should be read as typed interfaces whether the signature is written down or not.

    ## Arguments Arguments are available only inside the function where they are defined. That makes them useful for small, self-contained pieces of logic.

    Think of a function as a small named tool. You give it input values, it does some work, and it may give a result back. Calling a function is just another expression, so you can store or pass along its result.

    When the behavior itself should vary, pass a function instead of branching in every caller. That keeps the shared work in one place.

    ## Returning values Use `return` to send a value back to the caller. ```python def square(n): return n * n ``` If a function reaches the end without a `return`, the result is `None`.

    return ends the function immediately. Any code after it in the same block does not run.

    ```python def greet(name): print("Hello", name) ``` ## Practical guidance - Keep functions focused on one job. - Prefer returning values over printing inside helper functions. - Give functions names that describe what they compute or do. ================================================ FILE: docs/acton-guide/src/hello/args.md ================================================ # Program Arguments Program arguments are available as the attribute `argv` on the `env` actor. `env.argv` is a list where the first element contains the name of the shell command and the second element being the first proper argument. We can rewrite our program to print a user supplied name to greet rather than the world. Source: ```python actor main(env): print("Hello " + env.argv[1] + "!") env.exit(0) ``` Compile and run, with argument: ```sh acton hello.act ./hello Johan ``` Output: ```sh Hello Johan! ``` ================================================ FILE: docs/acton-guide/src/hello/running_tests.md ================================================ # Running Tests Writing tests is an integral part of writing software. In an Acton project, you can run all the tests by issuing `acton test`: ```console foo@bar:~hello$ acton test Tests - module hello: foo: OK: 278 runs in 50.238ms All 1 tests passed (23.491s) foo@bar:~hello$ ``` See the [Testing](/testing.md) section on how to write tests. ================================================ FILE: docs/acton-guide/src/hello/shebang.md ================================================ # Shebang While Acton is a compiled language and the `acton` compiler produces an executable binary, script style execution is also possible through the use of a shebang line. Source: ```python #!/usr/bin/env runacton actor main(env): print("Hello World!") env.exit(0) ``` Ensure the executable bit is set and run your .act file directly: ```console chmod a+x hello.act ./hello.act ``` Output: ```console Hello World! ``` ================================================ FILE: docs/acton-guide/src/hello.md ================================================ # Hello World We follow tradition and introduce Acton with the following minimal example Source: ```python # This is a comment, which is ignored by the compiler. # An actor named 'main' is automatically discovered and recognized as the root # actor. Any .act file with a main actor will be compiled into a binary # executable and the main actor becomes the starting point. actor main(env): print("Hello World!") env.exit(0) ``` Compile and run: ```console acton hello.act ./hello ``` Output: ```console Hello World! ``` ## Description When an Acton program runs, it really consits of a collection of actors that interact with each other. In the above example, we have just a single actor, which has been given the name `main` and that acts as the *root actor* of our system. The *root actor* of a system takes a parameter `env`, which represents the execution environment. `env` has methods for accessing command line arguments and carries a reference to the capabilities of the surrounding world, `WorldCap`, for accessing the environment, e.g. reading from and writing to keyboard/screen and files, working with sockets etc. ================================================ FILE: docs/acton-guide/src/index.md ================================================ ```bob A Guide to .---. .-. / \ | | / _ \ .----. .--' '--. .----. .-..-----. / / \ \ / .--._\ '--. .--' / .--. \ | / .---. \ / '---' \ / / | | / / \ \ | / | | / \ ( ( | | ( ( ) ) | | | | / .-------. \ \ \ __ | | __ \ \ / / | | | | / / \ \ \ '--' / \ '-' / \ '--' / | | | | '---' `---' '----' '---' '----' '-' '-' -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ``` Acton is a general-purpose programming language with a sharp focus on building robust reactive systems from many cooperating actors. It is especially well suited to distributed scale-out logic, where safety comes from combining actor-local state, explicit communication, and a static type system that checks the shape of the program before it runs. Actors are Acton's unit of state, concurrency, and communication: each actor runs sequentially, owns its state, and interacts with other actors through method calls, timers, callbacks, and async I/O. The actor model keeps mutation local and control flow direct while allowing many independent pieces of work to run concurrently. The language keeps familiar syntax while adding functional and object-oriented programming, type inference, capability-based security, and native compilation. It is practical for everyday scripts and services, but its center of gravity is actor-heavy systems where correctness, explicit authority, and efficient compiled code matter. ================================================ FILE: docs/acton-guide/src/install.md ================================================ # Installation {{#tabs }} {{#tab name="Debian / Ubuntu" }} For Debian derivative distributions that use .dpkg and the APT ecosystem. Add the Acton APT repo and install from there: ```console sudo install -m 0755 -d /etc/apt/keyrings sudo wget -q -O /etc/apt/keyrings/acton.asc https://apt.acton-lang.io/acton.gpg sudo chmod a+r /etc/apt/keyrings/acton.asc echo "deb [signed-by=/etc/apt/keyrings/acton.asc] http://apt.acton-lang.io/ stable main" | sudo tee -a /etc/apt/sources.list.d/acton.list sudo apt-get update sudo apt-get install -qy acton ``` {{#endtab }} {{#tab name="MacOS" }} ```console brew install actonlang/acton/acton ``` {{#endtab }} {{#endtabs }} ## Container image Acton also publishes a container image for trying Acton without installing it locally, running builds in CI, or pinning a reproducible toolchain for examples and tutorials. For day-to-day development, the native APT and Homebrew packages are usually more convenient. Check the installed Acton version in the image: ```console docker run --rm ghcr.io/actonlang/acton:latest version ``` Build the Acton project in the current directory: ```console docker run --rm -v "$PWD":/work -w /work ghcr.io/actonlang/acton:latest build ``` For CI and long-lived examples, pin a version tag instead of using `latest`. ================================================ FILE: docs/acton-guide/src/install_tip.md ================================================ # Installation Tip releases are built from the latest commit on the acton git repo main branch. They are built at least once a night, so can be thought of as nightlies but more up to date. {{#tabs }} {{#tab name="Debian / Ubuntu" }} For Debian derivative distributions that use .dpkg and the APT ecosystem. Add the Acton APT tip repo and install from there: ```console sudo install -m 0755 -d /etc/apt/keyrings sudo wget -q -O /etc/apt/keyrings/acton.asc https://apt.acton-lang.io/acton.gpg sudo chmod a+r /etc/apt/keyrings/acton.asc echo "deb [signed-by=/etc/apt/keyrings/acton.asc] http://aptip.acton-lang.io/ tip main" | sudo tee -a /etc/apt/sources.list.d/acton.list sudo apt-get update sudo apt-get install -qy acton ``` {{#endtab }} {{#tab name="Linux x86_64" }} Copy and extract the distribution tarball. Download from https://github.com/actonlang/acton/releases/download/tip/acton-linux-x86_64-tip.tar.xz ```console tar Jxf acton-linux-x86_64-tip.tar.xz ``` {{#endtab }} {{#tab name="Linux ARM64" }} Copy and extract the distribution tarball. Download from https://github.com/actonlang/acton/releases/download/tip/acton-linux-aarch64-tip.tar.xz ```console tar Jxf acton-linux-aarch64-tip.tar.xz ``` {{#endtab }} {{#tab name="MacOS x86_64" }} Copy and extract the distribution tarball. Download from https://github.com/actonlang/acton/releases/download/tip/acton-macos-x86_64-tip.tar.xz ```console tar Jxf acton-macos-x86_64-tip.tar.xz ``` {{#endtab }} {{#tab name="MacOS ARM64" }} Copy and extract the distribution tarball. Download from https://github.com/actonlang/acton/releases/download/tip/acton-macos-aarch64-tip.tar.xz ```console tar Jxf acton-macos-aarch64-tip.tar.xz ``` {{#endtab }} {{#endtabs }} ================================================ FILE: docs/acton-guide/src/language/bindings_scope.md ================================================ # Variables, constants, and scope Names let you store values and use them again later.

    Programmers often use variable to mean "a named place where a value is stored". In Acton, the more precise question is whether that name is a constant binding or a mutable one.

    A constant binding keeps the same value for its lifetime. A mutable binding is one whose value may be updated later. In everyday English, mutable just means "able to change".

    Where a name is defined determines where it can be used. This is called its *scope*.

    Scope means "the part of the program where a name is visible". A name defined inside a function or method is only available there. Module-level names live across the module. Actor bodies have their own rules, which are covered below.

    ```python greeting = "hello" # module-level constant def show_local(): greeting = "hi" # local name that shadows the module-level greeting print("local greeting:", greeting) def show_global(): print("global greeting:", greeting) actor main(env): show_local() show_global() env.exit(0) ``` In this example: - The module-level `greeting` is a constant. - The `greeting` inside `show_local` is a different local name. ## Module-level names Names defined at module level are constants. They are useful for helper functions, reusable values, and definitions that the rest of the module shares. ```python port = 9000 def address(): return "127.0.0.1:" + str(port) ```

    Here port is a constant: after it is defined, you use it, but you do not update it. That is a good default for names that describe configuration, helper values, and definitions shared across a module.

    ## Local names Names defined inside a function or method are local to that body. ```python def greet(name): message = "Hello " + name print(message) ``` Here, `message` only exists inside `greet`. ## Names in actors Acton treats names at the top level of an actor body differently from names inside a function or method. ```python actor Counter(): var remaining = 3 label = "counter" _unit = "items" def tick(): print(label, remaining, _unit) remaining -= 1 ``` In this example: - `remaining` is private mutable actor state. - `label` is a public constant attribute. - `_unit` is private to the actor because its name starts with `_`.

    Read var as "this actor-local name will change over time". If you plan to update a value in actor code, make that explicit up front.

    A plain name at the top level of an actor body is not an ordinary local variable. It becomes a constant actor attribute instead. If the name starts with _, it stays private to the actor. Without the leading underscore, other actors can read that constant through an actor reference.

    Acton keeps module-level bindings constant and pushes mutable shared state into actors. That changes how you structure larger programs: refactoring stateful logic usually means introducing an actor boundary, not another mutable top-level name.

    ## Shadowing Shadowing means introducing a new local name with the same spelling as an existing one. The outer name still exists, but the inner one is the one used in that scope. ```python name = "Acton" def show(): name = "local" print(name) show() print(name) ``` Here, `show` introduces a local `name` that shadows the module-level `name`. Inside `show`, `name` means `"local"`. Outside `show`, it still means `"Acton"`. Shadowing is sometimes useful, but overusing it makes code harder to read. Prefer distinct names when the two values mean different things. ================================================ FILE: docs/acton-guide/src/language/comments.md ================================================ # Comments Use `#` for comments. Comments are for readers of the code. Use them to explain intent, assumptions, or surprising choices. ```python def area(width, height): # Width and height are measured in meters. return width * height actor main(env): # Keep the greeting short because it is printed in a narrow terminal. message = "Hello" print(message) env.exit(0) ```

    A comment is ignored by the compiler. It is there only for people reading the source code. There is no separate block-comment syntax here; use # on each line you want to comment.

    ## What to comment Use comments for things the code does not make obvious: - why a check exists - units or external constraints - a temporary workaround - a non-obvious invariant ## Practical guidance - Prefer comments that explain why, not comments that only repeat what the code already says. - Keep comments close to the code they describe. - Update or remove comments when the code changes. ================================================ FILE: docs/acton-guide/src/language/common_programming_concepts.md ================================================ # Common programming concepts This section covers the pieces you use in almost every Acton program: names and scope, built-in types, expressions, functions, comments, and control flow. These pages are the foundation for the rest of the guide. Read them in order: 1. [Variables, constants, and scope](bindings_scope.md) 2. [Built-in types and literals](../primitives.md) 3. [Expressions and operators](expressions_operators.md) 4. [Functions](../functions.md) 5. [Comments](comments.md) 6. [Control flow](../control_flow.md) Most examples use `actor main(env):` as the entry point because Acton programs run from a root actor. You do not need to understand actors in depth yet to follow these pages, it will be explained later. ================================================ FILE: docs/acton-guide/src/language/environment_capabilities.md ================================================ # Environment and capabilities Programs that talk to the outside world need explicit access. In Acton, that access comes through the root `env` actor and through capability references that are passed around like any other value.

    Most small programs start with env and end with env.exit(0). That is normal. The important part is that env is passed in explicitly. When a function needs access to the outside world, give it the specific capability or environment reference it needs instead of assuming that access is always there.

    This chapter covers the practical side of that model: - [Security](../security.md) explains why access is explicit. - [Environment](../environment.md) covers `env`, arguments, variables, stdin, and terminal mode changes. Use this chapter when you need to: - read command line arguments - inspect or change environment variables - read from standard input - handle interactive terminal input - decide what authority a helper should receive

    Capability design is part of API design. When a helper takes a wide environment reference or a broad outside-world capability, that choice becomes part of the helper's contract: callers must now trust it with everything that capability can do, not just the one operation the current implementation happens to use.

    A narrower capability does more than look tidy. It limits authority, reduces the amount of code that must be audited when security matters, and makes substitution easier in tests or alternate runtimes. If a helper only needs to open a TCP connection, that is the capability it should receive. Anything wider increases coupling and makes accidental authority leaks more likely over time.

    ================================================ FILE: docs/acton-guide/src/language/errors_exceptions.md ================================================ # Errors and exceptions Use exceptions when something is wrong and the current path should stop. Raise an exception with `raise`, and handle it with `try` and `except`. ```python def parse_port(text: str) -> int: port = int(text) if port < 0 or port > 65535: raise ValueError("port must be between 0 and 65535") return port actor main(env): for text in ("8080", "70000"): try: port = parse_port(text) except ValueError as e: print("invalid input:", e) else: print("port:", port) env.exit(0) ```

    Use an exception for a real error. If "no result" is expected and normal, an optional value is often a better fit.

    ## `try` structure A `try` statement can contain these parts: - `try` for the code that may fail - `except` for handling specific exception types - `else` for code that should run only when nothing failed - `finally` for cleanup that should happen either way ```python try: value = parse_port("9000") except ValueError as e: print("bad input:", e) else: print("ready to use:", value) finally: print("done") ``` `except` runs only for matching exceptions. `else` runs only when the `try` block completed without raising. `finally` runs whether the `try` block succeeded or failed.

    Keep try blocks narrow so it stays obvious which operation can fail.

    Catch specific exceptions before broader ones, and keep exception handling close to boundaries such as input parsing, file access, network calls, and other integration points. Inside core logic, prefer domain values or optionals when the situation is expected rather than using exceptions as routine branching.

    ================================================ FILE: docs/acton-guide/src/language/expressions_operators.md ================================================ # Expressions and operators Acton evaluates expressions to values. Operators combine values into new expressions. ## Common operators - Arithmetic: `+`, `-`, `*`, `/`, `//`, `%`, `**` - Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=` - Boolean: `and`, `or`, `not` - Membership: `in`, `not in` ```python actor main(env): a = 10 b = 3 word = "Acton" point = (3, 4) print("sum:", a + b) print("product:", a * b) print("floor division:", a // b) print("remainder:", a % b) print("power:", b ** 3) print("comparison:", a > b) print("boolean:", a > 0 and b > 0) print("membership:", "ct" in word) print("indexing:", word[0], point[1]) print("slicing:", word[1:4]) env.exit(0) ``` Method calls, function calls, indexing, and slicing are expressions too. They all produce values. ```python name = "Acton" first = name[0] upper = name.upper() ``` ## Reading expressions Read an expression from the values upward. Start with the pieces that already have values, then apply the operator or call.

    When reading an expression, start with the smallest parts that already have values and then see how the operator or call combines them. If you have to stop and think about precedence, add parentheses.

    ## Precedence Acton follows standard operator precedence rules. When in doubt, use parentheses to make intent explicit. ```python x = 2 + 3 * 4 # 14 y = (2 + 3) * 4 # 20 ``` ## Boolean logic `and` and `or` are useful when the right-hand side only makes sense if the left-hand side has already passed a check. ```python if user_is_known and user_is_enabled: print("welcome") ```

    and and or short-circuit. That means Acton only evaluates the right-hand side when it is needed to determine the result. That matters not just for speed, but for semantics: you can use short-circuiting to guard operations that would otherwise fail or do unnecessary work. Calls, indexing, slicing, and later optional operations all participate in the same expression model.

    ```python a = 0 if a != 0 and 10 / a > 2: print("large enough") ```
    ================================================ FILE: docs/acton-guide/src/language/missing_values_failures.md ================================================ # Missing values and failures Programs usually need to represent two different cases: - a value is genuinely absent - an operation failed and execution should stop or recover Acton uses different tools for those cases. `None` and optional types model ordinary absence. Exceptions model failures.

    Use an optional when absence is part of the normal result. Use an exception when the operation could not finish as intended. A caller can branch on an optional; an exception means the current path should stop unless it is explicitly handled.

    There is no Rust-style `match` path for this in Acton. Use ordinary branching, optional checks, and exception handling instead. Start here when you need to decide whether a function should return `None`, raise an exception, or let an expression keep propagating an optional result.

    Optional chaining and forced unwrapping are expression-level tools. They do not replace the type system or exception handling; they make the common cases shorter. Keep absence in the type when it is expected, and reserve exceptions for broken assumptions, invalid input, and other failures that should not be treated as routine control flow.

    - [Optionals and `None`](optionals_none.md) covers the basic meaning of `None` and optional return values - [Optionals](../types/optionals.md) explains narrowing, optional chaining, and forced unwrapping - [Errors and exceptions](errors_exceptions.md) covers `raise`, `try`, `except`, `else`, and `finally` ================================================ FILE: docs/acton-guide/src/language/modeling_data_interfaces.md ================================================ # Modeling data and interfaces Once functions and collections stop expressing a problem clearly, you usually need a more explicit model. In Acton, that usually means moving through a simple progression: - tuples for small anonymous values - named tuples for small structured values with readable fields - classes for values with methods or invariants - protocols for shared behavior across unrelated types

    Start with a tuple when the value is small and anonymous. Move to a named tuple when the shape deserves field names but not behavior. Move to a class when the data needs methods, a constructor, or rules that should stay close to the value. Use a protocol when the real question is whether several different types can be used in the same place.

    Use this section when you need to decide how a domain concept should be represented, how an object becomes valid, and how different types can share the same behavior without sharing the same class.

    Classes and protocols solve different problems. Classes define the shape and lifecycle of a value. Protocols define an observed interface that multiple concrete types can satisfy. That choice affects API shape, initialization, dispatch, and type inference, not just code organization.

    - [Tuples](../primitives/tuples.md) - [Classes and objects](../classes/intro.md) - [Protocols](../protocols/intro.md) ================================================ FILE: docs/acton-guide/src/language/optionals_none.md ================================================ # Optionals and `None` `None` is the value Acton uses for "nothing here". An optional type `?T` means a value is either a `T` or `None`. Use an optional when absence is part of the normal result.

    `?str` means "a string or None". `?int` means "an integer or None". The `?` belongs to the type, not the value.

    ```python def lookup_name(users: dict[str, str], username: str) -> ?str: if username in users: return users[username] return None actor main(env): users = {"alice": "Alice Andersson"} name = lookup_name(users, "bob") if name is not None: print("Found:", name) print("Upper:", name.upper()) else: print("No match") env.exit(0) ``` Use `is None` and `is not None` to check whether an optional is present. When you want to use the value as non-optional, put that code inside the `is not None` branch.

    Write the check in the direction of the code that needs the value. Do not rely on an if name is None / else shape to make name non-optional in the else branch.

    Optional values are common in lookups, parsing, and APIs that may or may not find a result. `None` is not a general placeholder for every kind of empty value; use it when absence itself matters. ================================================ FILE: docs/acton-guide/src/language/organizing_code.md ================================================ # Organizing code As a program grows, you need more than a single file full of functions. The goal is not to create a deep tree of files. The goal is to make the code easier to read, change, and import.

    Start by grouping related code together, then split it when it begins to serve more than one purpose. A practical first cut is often one module for parsing, one for domain logic, and one for I/O or startup code. Keep local modules, project metadata, and external dependencies in one clear path rather than treating them as separate puzzles.

    You do not need a deep hierarchy early on. Small modules with clear names are usually easier to work with than a large set of thin files with vague responsibilities.

    This section connects the local source tree, the project file, and the package graph. Use it together with [Projects](../projects.md) and [Package Management](../package_management.md).

    In Acton, a module boundary is more than a foldering choice. Because module-level bindings are constant, a module behaves much more like a namespace and API surface than like an object with hidden mutable runtime state. That means a good split changes both how people read the program and how the compiler sees it.

    A coherent module split narrows imports, isolates reasons to change, and makes the public surface smaller. It also improves the mechanical side of the toolchain: discovery, type checking, caching, and API documentation all work in terms of modules. Once a file becomes a real boundary that other code imports on purpose, its top-level names and docstrings stop being decoration and start becoming part of the module's interface.

    This section is about the everyday structure around your code: - how to split code into modules - how to import names - how naming conventions make code easier to read Read next: - [Modules](../modules.md) - [Projects](../projects.md) - [Package Management](../package_management.md) - [Naming](../naming.md) ================================================ FILE: docs/acton-guide/src/language/state_concurrency.md ================================================ # Actors & concurrency Actors are the center of Acton's model for mutable state and concurrency. If you want to understand how Acton programs stay structured as they grow, start here.

    Start with the basic actor main(env) pattern. The core model is simple: an actor owns state, handles one message at a time, and communicates with other actors by calling their methods.

    This is also the closest Acton replacement for Rust-style lifetime thinking: actors own mutable state, capability references are passed explicitly, and the runtime manages ordinary object lifetime.

    The important guarantee is local seriality: within one actor, state changes are observed as if messages were handled one at a time. That is why var can hold mutable state without introducing the kind of shared-memory races that make threaded code hard to reason about. The actor boundary is doing real work here: mutation stays local, while concurrency appears only in the relationships between actors.

    Viewed that way, many Acton features are the same model in different forms. Sync and async calls, await, delayed callbacks with after, and lifecycle hooks all control when new work is placed into an actor's mailbox and when another actor is allowed to make progress. What Acton does not promise is one global timeline across the whole program. Ordering is local to each actor unless your own protocol establishes something stronger.

    This section covers: - how actors own state and methods - how the root actor starts a program - how actors talk to each other - how delayed work and cleanup fit into actor code - how concurrency works without shared mutable memory Read these pages next: - [Actors](../actors.md) - [Root Actor](../actors/root.md) - [Lifetime](../actors/lifetime.md) - [Attributes](../actors/attributes.md) - [`self`](../actors/self.md) - [Actor methods](../functions/actor_methods.md) - [Sync Method calls](../actors/sync_method_call.md) - [Async Method calls](../actors/async_method_call.md) - [Control flow in an async actor world](../control_flow/actors.md) - [after / sleep](../control_flow/after_sleep.md) - [Concurrency](../actors/concurrency.md) - [Cleanup](../actors/cleanup.md) Effect annotations such as `pure`, `mut`, `proc`, and `action` are documented under [Working with types](../types/effects.md). ================================================ FILE: docs/acton-guide/src/language.md ================================================ # Language This chapter is the core language guide and reference. It is organized around common programming tasks rather than around a taxonomy of language features. The early sections are the things most people need first. The later sections go deeper into Acton-specific parts of the language such as actors, concurrency, and capabilities. ## What to read first If you are new to Acton, read in this order: 1. [Common programming concepts](language/common_programming_concepts.md) 2. [Collections and everyday data](collections.md) 3. [Missing values and failures](language/missing_values_failures.md) 4. [Modeling data and interfaces](language/modeling_data_interfaces.md) 5. [Organizing code](language/organizing_code.md) 6. [Working with types](types/intro.md) 7. [Actors & concurrency](language/state_concurrency.md) 8. [Environment and capabilities](language/environment_capabilities.md) ## How to use this chapter as reference - Use the book's search when you want to find a specific feature, keyword, or builtin quickly. This chapter is organized for reading and programming tasks, not as a strict feature index. - Use section landing pages for overview. - Use subpages for details and examples. - Use the beginner and advanced callouts to choose the level of detail you need. - For runtime and tooling behavior, see the chapters after Language (Testing, Build System, Package Management, and RTS). ================================================ FILE: docs/acton-guide/src/modules.md ================================================ # Modules Modules let you split a program into smaller named units. In a project, modules live under `src/`, and subdirectories become part of the module name. For example, `src/a/b.act` is imported as `import a.b`. See [Projects](projects.md) for how `acton build` discovers those files and [Package Management](package_management.md) for external dependencies that live alongside local modules. Use modules to group code by responsibility. A good module has a clear job. For example: - parsing and validation - domain logic and shared types - I/O, network access, or other side effects - startup and orchestration

    Start with one module per clear topic. If a file starts mixing unrelated ideas, move one topic into its own module. Keep the project tree and the module tree aligned so the file layout stays easy to follow.

    ## Import forms Use `import` when you want the module name itself: - `import time` - `import time as timmy` Use `from ... import ...` when you want specific names directly: - `from time import now` - `from time import now as rightnow` ```python import time import time as timmy from time import now from time import now as rightnow actor main(env): print(time.now()) print(timmy.now()) print(now()) print(rightnow()) env.exit(0) ```

    Keep imports explicit, and use aliases only when they improve readability or avoid a name clash.

    ## Module-level code Module-level names are constants. Mutable program state belongs in actors, not in modules. That means: - helper functions and constants fit naturally at module level - mutable variables do not - program startup logic should live in actors such as `main` ```python default_timeout = 5 def timeout_seconds(): return default_timeout ```

    Modules can also carry docstrings. Because module-level bindings are constant, importing a module is closer to importing a namespace of definitions than shared mutable runtime state.

    That is why module boundaries work best when they are stable and purposeful. Prefer names that explain the boundary directly, and keep the module surface small unless the file is intentionally acting as a public API.

    ## How to split code Split a module when it starts doing too many different jobs. Good reasons to make a new module include: - a group of functions is reused from several places - a feature has a clear boundary, such as `parser`, `storage`, or `protocol` - one part of the code changes for different reasons than the rest - the file has grown enough that imports and names are hard to scan Avoid creating modules just to make a tree look deep. A short, direct module path is usually easier to work with than a very fine-grained one. ================================================ FILE: docs/acton-guide/src/naming.md ================================================ # Naming Acton has naming rules and conventions. Some are enforced by the compiler, and some are conventions that keep larger programs readable. ## Functions Use lower-case words with `_` between them. - `parse_user` - `load_config` - `send_report` Function names should describe what the function does. ## Actors and classes Use `PascalCase` with two or more alphanumeric characters. - `HttpServer` - `OrderBook` - `FileCache` Do not use a single upper-case letter for a class or actor name. Those names are reserved for type variables. ## Type variables Type variables use a single upper-case letter, optionally followed by digits. - `A` - `T1` Use them for generic code, not for ordinary domain concepts. If a name describes a real thing in the program, make it a normal type or actor name instead. ## Modules and files Module names come from file paths, so filename choice matters. Use short, lower-case names and let the import path reflect the structure of `src/`. For example, `src/a/b.act` is imported as `import a.b`. Naming is part of API design. In Acton, a module name, an imported symbol, and a type name often appear together, so keeping them short and predictable reduces noise in the code. This matters even more once a project has several modules and cross-module dependencies. ## Private names A leading `_` is the usual marker for implementation details that should not be treated as part of the public surface. Use it for names that are only meant to be used inside one module or actor. ## Practical guidance

    Good names make code easier to split into modules, and they make imports easier to read. If a name feels awkward at the call site, it is usually worth changing before the code grows.

    - Prefer names that describe what a thing is or does. - Use the same word for the same concept across modules. - Avoid abbreviations unless they are standard in your domain. - Make helper names specific enough that call sites read naturally. ================================================ FILE: docs/acton-guide/src/package_management.md ================================================ # Package Management `acton` offers integrated package management for adding library dependencies to a project and installing application packages as local tools. Dependencies are automatically fetched and validated at build time; applications are built from source before their binaries are installed. Acton pins dependencies by content, via a content hash, rather than by mutable package version labels. Therefore, builds are entirely deterministic so that the same compilation result can be reproduced on another machine. The guiding principle behind Acton's package management is to strive for determinism, robustness, and safety. Dependencies are resolved at design time by the package developer and written into `Build.act` as archive URLs plus content hashes. Later builds fetch those recorded archives and verify the hashes; they do not pick newer compatible versions or rely on a name to mean the same thing forever. Acton's public package index is a discovery index. Packages are hosted by their owners, and dependencies are recorded as URLs from which a specific package archive can be downloaded. This is typically a tar.gz or zip archive from GitHub, GitLab, or a similar source hosting site. The index helps find packages; `Build.act` records the exact archive and hash used by a project. The public index is decentralized in the sense that package authors opt in from their own GitHub repositories. The index collects repositories tagged with an `acton-library` or `acton-app` topic and records their metadata for search and resolution. `acton pkg` commands work with library packages only: `acton pkg search` shows libraries and `acton pkg add` resolves libraries as dependencies. App packages are installed with `acton install`, which builds the selected repository in release mode and copies its binaries into `~/.acton/bin`. Install manifests are kept under `~/.acton` so Acton can track which package owns each installed binary and remove those binaries again with `acton uninstall`. All dependencies are fetched and included, linked statically, at compile time, so there are no runtime dependencies. ## Project lineage fingerprint Each project must declare a **fingerprint** in `Build.act` to represent its lineage — the stable identity of the project across versions. This is separate from dependency content hashes: - Content hashes identify a specific version of a dependency. - Fingerprints identify the project itself and help Acton deduplicate dependencies and generate consistent build metadata. Example: ```python name = "myproject" fingerprint = 0x1234abcd5678ef00 ``` **How it behaves today** - `name` and `fingerprint` are required in every project. - Acton validates that the fingerprint matches the name’s lineage prefix. - If they don’t match or either is missing, the build fails with guidance on how to fix it. Renaming a project breaks lineage, so generate a new fingerprint for the new name. When you fork a project, also generate a new fingerprint so the fork has its own lineage. ================================================ FILE: docs/acton-guide/src/pkg/add_dependency.md ================================================ # Add Dependency Add a dependency to your project by using `acton pkg add`. The usual flow is to refresh the public package index first: ```console acton pkg update ``` Then add the dependency by package name: ```console acton pkg add foo ``` You can also provide a GitHub repository URL directly. The first argument is still the local dependency name: In this case we add the example `foo` package as a dependency. ```console acton pkg add foo --repo-url https://github.com/actonlang/foo --repo-ref main ``` This will fetch the dependency and add it to the `dependencies` block in `Build.act`, resulting in something like: ```python dependencies = { "foo": ( repo_url="https://github.com/actonlang/foo", repo_ref="main", url="https://github.com/actonlang/foo/archive/0123456789abcdef0123456789abcdef01234567.zip", hash="1220cd47344f8a1e7fe86741c7b0257a63567b4c17ad583bddf690eedd672032abdd", ), } zig_dependencies = {} ``` ```admonish It is possible to edit `Build.act` by hand, but adding dependencies requires filling in the `hash` field, which is somewhat tricky. ``` The `foo` package provides a single `foo` module with a `foo` function (that appropriately returns `foo`). We can now access it from our main actor: ```python import foo actor main(env): print(foo.foo()) env.exit(0) ``` ================================================ FILE: docs/acton-guide/src/pkg/fetch_dependencies.md ================================================ # Fetch Dependencies / Enable Airplane Mode You can fetch all the dependencies of a project by using `acton fetch`. It will download the dependencies specified in `Build.act` to the cache. `acton fetch` enables you to work offline (a.k.a **airplane mode**). ================================================ FILE: docs/acton-guide/src/pkg/fingerprint.md ================================================ # Fingerprint and lineage Each Acton project must declare a **fingerprint** in `Build.act`. The fingerprint represents the project’s **lineage** — a stable identity that stays the same across releases of the same project. ```python name = "myproject" fingerprint = 0x1234abcd5678ef00 ``` ## What the fingerprint is - A 64-bit hex value (`0x...`). - The upper 32 bits are derived from the project name. - The lower 32 bits are random. - Acton uses this lineage to deduplicate dependencies and to generate consistent build metadata. ## Rename vs fork Renaming a project breaks lineage, so generate a new fingerprint for the new name. Forking a project also creates a new lineage, so generate a fresh fingerprint. If Acton detects a mismatch, it will fail the build and tell you to generate a new fingerprint for the name. ## Current behavior - `name` and `fingerprint` are required in every project. - Acton validates the lineage prefix derived from the name. - Missing or mismatched values fail the build with guidance. ================================================ FILE: docs/acton-guide/src/pkg/local_dependencies.md ================================================ # Local Dependencies It is possible to use dependencies available via a local file system path by setting the `path` attribute. Edit `Build.act` and add or modify an existing dependency. Set the `path` attribute to a relative path, e.g.: ```python dependencies = { "foo": ( path="../foo" ), "local_lib": ( path="deps/local_lib" ), } zig_dependencies = {} ``` These are best used for dependencies located within the same git repository or similar. All users need to have the same relative path to the dependency so if the paths stretch over multiple repositories, the user needs to keep the paths aligned. ```admonish You can temporarily override the path to a dependency through the `--dep` argument, e.g. `acton build --dep foo=../foo`. This can be useful to fork a library and make local modifications to it before submitting them back upstream. ``` ================================================ FILE: docs/acton-guide/src/pkg/override_dependency.md ================================================ # Override the path to a dependency The configuration in `Build.act` sets the path or url that is normally used for a dependency. It is possible to temporarily override the path through the `--dep` argument to `acton build`. Let's say we have the following configuration: ```python dependencies = { "foo": ( url="https://github.com/actonlang/foo/archive/refs/tags/v1.0.zip", hash="1220cd47344f8a1e7fe86741c7b0257a63567b4c17ad583bddf690eedd672032abdd", ), } zig_dependencies = {} ``` Now we want to make some modifications to the `foo` library, so we clone it to a local path. We can now build our project using `acton build --dep foo=../foo` to temporarily override the `foo` dependency to use the path `../foo` instead of the url in the configuration. ================================================ FILE: docs/acton-guide/src/pkg/package_index.md ================================================ # Package Index The public package index is built from GitHub repository topics. A repository can opt in as a library, an app, or both. The generated index records this as a `kinds` list: - `acton-library` marks an importable library package. - `acton-app` marks an installable application package. Use `acton-library` for packages that other projects import and add as dependencies. These are the only packages used by `acton pkg add` and shown by `acton pkg search`. Use `acton-app` for projects that produce executable tools. App packages are installed with `acton install`, which builds the selected repository and copies its binaries into `~/.acton/bin`. Add both topics when a repository provides useful importable modules and also builds executable tools. `acton pkg` still uses only the library entry for dependency resolution. ## Add your package To have a package discovered by the public index: 1. Put `Build.act` at the root of the repository. 2. Declare the mandatory `name` and `fingerprint` fields in `Build.act`. 3. Publish the repository on GitHub. 4. Add the `acton-library` topic, the `acton-app` topic, or both. After the public index has refreshed, users can update their local copy: ```console acton pkg update ``` Libraries can then be found with: ```console acton pkg search PACKAGE ``` and added as dependencies with: ```console acton pkg add PACKAGE ``` Apps can be installed with: ```console acton install PACKAGE ``` and removed with: ```console acton uninstall PACKAGE ``` ================================================ FILE: docs/acton-guide/src/pkg/remove_dependency.md ================================================ # Remove Dependency You can remove a dependency from your project with `acton pkg remove`: ```console acton pkg remove foo ``` ================================================ FILE: docs/acton-guide/src/primitives/complex.md ================================================ # Complex numbers Complex numbers combine a real part and an imaginary part. Create them with `complex.from_real_imag(real, imag)`.

    If you have not used complex numbers before, think of them as two floating-point values with arithmetic rules built in. Most programs do not need them, but they are useful in math-heavy domains.

    ```python actor main(env): a = complex.from_real_imag(1.0, 2.0) b = complex.from_real_imag(3.0, 4.0) print("sum:", a + b) print("product:", a * b) print("real part:", a.real()) print("imag part:", a.imag()) print("conjugate:", a.conjugate()) print("magnitude:", abs(a)) env.exit(0) ``` ## Arithmetic Complex numbers support the usual arithmetic operations: - `+` and `-` - `*` - `/` - `**` They also support equality testing with `==` and `!=`. ```python a = complex.from_real_imag(1.0, 2.0) b = complex.from_real_imag(1.0, 2.0) print(a == b) ```

    Complex numbers are part of Acton's numeric world and work with the same floating-point realities as float: rounding and precision limits still matter. Any algorithm that wants a notion of ordering has to state it explicitly, such as by comparing magnitude, rather than relying on the usual ordered-number intuition.

    ## Errors Division by zero raises `ZeroDivisionError`. ```python zero = complex.from_real_imag(0.0, 0.0) # a / zero ``` ================================================ FILE: docs/acton-guide/src/primitives/float.md ================================================ # Floating-point numbers `float` is Acton's 64-bit floating-point type. Use it for values with a fractional part, such as measurements, ratios, and scientific calculations.

    A decimal point usually means a float literal. Use floats for measurements and ratios, and do not be surprised by small rounding artifacts in the last digits.

    ```python actor main(env): distance = 12.5 time = 4.0 speed = distance / time print("speed:", speed) print("rounded:", round(speed, 2)) print("formatted: %.2f" % speed) env.exit(0) ``` Floating-point arithmetic is approximate, not exact. ```python a = 0.1 b = 0.2 print(a + b) ```

    Floats trade exactness for range and speed. They are usually the right tool for physical measurements and approximate calculations, but not for values where exact decimal behavior is required. Equality on computed floats is often brittle, so treat exact comparison with care once values have gone through prior arithmetic.

    ================================================ FILE: docs/acton-guide/src/primitives/integers.md ================================================ # Integers Integers are whole numbers such as `0`, `42`, and `-7`. Acton has three groups of integer types: - `int` for the normal 64-bit signed integer type - `bigint` for integers that must grow beyond the `int` range - explicitly sized signed and unsigned integers such as `i32` and `u16` `bigint` lets values grow arbitrarily large ensuring correct program behavior when you are uncertain about the exact size needed. However, as `bigint` is significantly slower than the bounded integer types, do not default to `bigint` out of convenience. For the vast majority of normal use cases, `int` is large enough and considerably faster. Use exact-width integers when you specifically need their bit width.

    Bounded integer types can often be compiled in an unboxed form, which avoids boxing overhead and can make arithmetic much faster, several orders of magnitude, than bigint in tight code. That is another reason to prefer int or an exact-width integer when the bounded range is the right fit, and reserve bigint for values that truly need arbitrary precision.

    If you are not sure which integer type to use, start with int. Move to bigint when values may get very large, and use the exact-width types when you need to match a protocol, file format, or external API.

    Type Min Max
    i8
    -128 127
    i16
    -32768 32767
    i32
    -2147483648 2147483647
    u1
    0 1
    u8
    0 255
    u16
    0 65535
    u32
    0 4294967295
    u64
    0 18446744073709551615
    int
    -9223372036854775808 9223372036854775807
    bigint
    arbitrary arbitrary
    ## Basic use ```python actor main(env): count = 42 port = u16(5000) huge = bigint(123456789012345678901234567890) print("count:", count) print("port:", port) print("huge:", huge) print("widened:", int(port)) env.exit(0) ``` Use `int` for everyday counting and arithmetic. Use `bigint` when a value may exceed the normal machine-sized range. Use exact-width types when the bit pattern matters. ## Converting integers Convert by calling the target type as a constructor. ```python int(42) bigint(42) u16(255) ``` Widening to a larger type is straightforward: ```python small = u16(255) widened = int(small) ``` Converting to a narrower type checks that the value fits: ```python safe = u16(12345) # u16(70000) would raise ValueError ```

    Large integer literals are inferred by size. Values above the normal int range may infer as u64 or bigint. When you care about the exact type, annotate it or use an explicit constructor.

    ================================================ FILE: docs/acton-guide/src/primitives/scalars.md ================================================ # Scalars ================================================ FILE: docs/acton-guide/src/primitives/tuples.md ================================================ # Tuples Tuples group a fixed number of values into one value. The fields in a tuple can have different types. A tuple is a good first step for a small value with a fixed shape. When the shape needs names but still behaves like plain data, use a named tuple. When the value needs methods, invariants, or a lifecycle, move to a class.

    A tuple has a fixed shape. If you need a small value with exactly two or three fields, a tuple is often a good fit. If you keep forgetting what .0 and .1 mean, switch to a named tuple so the fields explain themselves. If the data starts needing methods or construction rules, switch to a class.

    ```python actor main(env): pair = ("Ada", 36) point = (x=3, y=4) print(pair.0) print(pair.1) print(point.x) print(point.y) env.exit(0) ``` Access positional tuple fields with `.0`, `.1`, and so on. Named tuples use field names such as `.x` and `.y`. ## Returning tuples from functions Tuples are handy when a function naturally returns a small fixed group of values. ```python def parse_result(): return (ok=True, code=200) ``` Acton can infer the tuple shape here from the returned value.

    Named tuples are the bridge between raw tuple positions and classes. They keep the value lightweight while making the shape self-documenting. Because the tuple shape is part of the type, changing field count or names is an API change.

    ================================================ FILE: docs/acton-guide/src/primitives.md ================================================ # Built-in types and literals Every value in Acton has a type. Many values can be written directly in source code. These are called *literals*.

    42, True, and "hello" are all literals: the value is written directly in the program instead of being computed somewhere else.

    ## Common built-in types | Type | Example | Notes | | --- | --- | --- | | `int` | `42` | 64-bit signed integer | | `bigint` | `123456789012345678901234567890` | arbitrary-precision integer | | `i8`, `i16`, `i32`, `u1`, `u8`, `u16`, `u32`, `u64` | `u16(42)` | explicitly sized integers | | `float` | `3.14` | 64-bit floating-point number | | `complex` | `complex.from_real_imag(1.0, 2.0)` | complex number | | `bool` | `True` | `True` or `False` | | `str` | `"hello"` | Unicode text | | tuple | `(1, "two")` | fixed-size group of values | ```python actor main(env): whole = 42 huge = bigint(123456789012345678901234567890) ratio = 3.5 truth = True name = "Acton" point = (x=3, y=4) z = complex.from_real_imag(2.0, 3.0) print(whole, huge, ratio, truth, name, point, z) env.exit(0) ```

    Integer literals are not all the same internally. Small whole-number literals usually fit in int, while very large literals may need u64 or bigint. If the exact type matters, write it explicitly.

    ## Choosing a type Use: - `int` for ordinary whole numbers - `bigint` when whole numbers may grow beyond the normal `int` range - `float` for fractional values - `bool` for yes/no conditions - `str` for text - tuples for small fixed-size groups of values Reach for fixed-size integers when width or sign matters, and for `complex` when you need real and imaginary parts together. Lists, dictionaries, and sets are covered in [Collections](collections.md). ## More detail - [Integers](primitives/integers.md) - [Floating-point numbers](primitives/float.md) - [Complex numbers](primitives/complex.md) - [Tuples](primitives/tuples.md) ================================================ FILE: docs/acton-guide/src/projects/directory_structure.md ================================================ # Project directory structure The directory layout of an Acton project follows a certain structure. ``` . ├── Build.act ├── out │   ├── bin │   │   └── foo │   └── types │   ├── foo.c │   ├── foo.h │   ├── foo.root.c │   └── foo.ty ├── README.md └── src └── foo.act ``` A `Build.act` file and the `src/` directory must be present in the project root, otherwise it is not considered a project. `src/` is used for all source files of the project. Use subdirectories to create hierarchies of modules, for example `src/a/b.act` is imported in an Acton program as `import a.b`. Output goes into `out/`, most importantly, executable binaries are placed in `out/bin`. The name of the binary is the name of the module which contains the specified root actor. In the example above, the root actor is `foo.main`, i.e. actor `main` in the module `foo` and consequently, the executable name is `foo`. `out/types` contains internal compiler output. In particular, `.ty` files are cached typed-module interfaces and `.c` / `.h` files are generated code derived from them. Acton validates and regenerates these files as needed, so they should be treated as internal build artifacts. Don't touch them. All other output files, like object files and archives, are placed out-of-tree in the cache directory (`~/.cache/acton/`). ================================================ FILE: docs/acton-guide/src/projects.md ================================================ # Acton Projects Besides compiling individual `.act` files, it is possible to organize Acton code into an **Acton Project**, which is suitable once you have more than one `.act` source code file. Use `acton` to create a new project called `foo`: ```console acton new foo ``` Output: ```console Created project foo Enter your new project directory with: cd foo Compile: acton build Run: ./out/bin/foo ``` ## Description Use `acton build` to build a project. The current working directory must be the project directory or a sub-directory to the project directory. `acton` will discover all source files and compile them according to dependency order. Add a `main` actor to any source file directly under `src/` to produce an executable binary. For example, if `src/hello.act` contains a `main` actor, it will produce `out/bin/hello` using `main` as the root actor. Projects and modules work together: `src/` defines the local module tree, while `Build.act` defines the project identity and its external dependencies. See [Modules](modules.md) for local source layout and [Package Management](package_management.md) for remote dependencies and override behavior. ## Build configuration and lineage Projects must include a `Build.act` file. Two common fields are `name` and `fingerprint`, where the fingerprint captures the project’s **lineage**: ```python name = "hello" fingerprint = 0x1234abcd5678ef00 ``` `name` and `fingerprint` are required for Acton projects. Acton validates that the fingerprint matches the name’s lineage prefix. A mismatch indicates a rename or a fork, so the build fails and tells you to generate a new fingerprint for the new name. If either field is missing, the build fails with guidance to add it. ================================================ FILE: docs/acton-guide/src/protocols/dispatch.md ================================================ # Protocol method dispatch Protocol dispatch is about choosing which protocol implementation to use. For ordinary class methods, the answer is usually the method on the actual class. For protocol methods, the result depends on the type the program is observing at that point. Here are two classes, the base class `Point` and the derived class `Point3D`. Both implement `Eq`. ```python class Point(object): def __init__(self, x: int, y: int): self.x = x self.y = y extension Point (Eq): def __eq__(self, other): return self.x == other.x and self.y == other.y class Point3D(Point): def __init__(self, x: int, y: int, z: int): self.x = x self.y = y self.z = z extension Point3D (Eq): def __eq__(self, other): return self.x == other.x and self.y == other.y and self.z == other.z def comparator(a: Point, b: Point) -> bool: return a == b actor main(env): p1 = Point3D(1, 2, 3) p2 = Point3D(1, 2, 4) print(p1 == p2) print(comparator(p1, p2)) env.exit(0) ``` The first comparison uses `Point3D` as the observed type, so it uses the `Eq` implementation for `Point3D`. The second comparison goes through `comparator(a: Point, b: Point)`, so the observed type has been forced to `Point`. That means protocol dispatch uses the `Eq` implementation for `Point`, which ignores `z`.

    If protocol dispatch feels surprising, first ask: what type is the program actually seeing here? If you annotate values as a base type too early, you can force dispatch to use the base-type implementation.

    In this case, the better API is usually a generic one that keeps the full type: ```python def generic_comparator[A(Eq)](a: A, b: A): return a == b ```

    This is one reason generic constraints such as [A(Eq)] often produce better behavior than prematurely forcing values into a base-class type. Protocol dispatch follows the observed type, so type annotations, container element types, and narrowing steps can all change behavior without changing the value itself.

    The same issue can appear when values are stored in a collection typed as the base class: ```python actor main(env): ref_point = Point3D(1, 2, 4) p1 = Point3D(1, 2, 3) p2 = Point3D(1, 2, 4) my_points: list[Point] = [p1, p2] for point in my_points: if point == ref_point: print("Found the reference (compared as Point)", point) if isinstance(point, Point3D) and point == ref_point: print("Found the reference (compared as Point3D)", point) ``` Here, `isinstance` narrows the observed type back to `Point3D`, so the more specific protocol implementation is used again. ## What to watch - If you annotate values as a base type too early, protocol dispatch can use the base-type implementation. - If you want behavior to follow the concrete value, keep the type generic for as long as possible. - If you need a more specific implementation after narrowing, use the narrower type again before the protocol method call. ================================================ FILE: docs/acton-guide/src/protocols/intro.md ================================================ # Protocols Protocols describe behavior that different types can share. Use a protocol when your main question is "what operations does this value support?" rather than "what class does it inherit from?" ```python protocol Processable[T]: process : () -> T class Message(object): def __init__(self, text): self.text = text extension Message(Processable[str]): def process(self): return self.text.upper() ``` In this example: - `Processable[T]` defines a capability - `Message` is an ordinary class - the `extension` says that `Message` implements that protocol

    Inheritance says one class is a kind of another class. A protocol says a type supports a certain behavior, whether or not there is any inheritance relationship. Read extension Message(Processable[str]) as "Message implements the Processable[str] protocol".

    Protocols are useful at API boundaries because they let you depend on a capability instead of a concrete class. Several unrelated types can offer the same behavior, and one type can offer several unrelated behaviors.

    Protocols matter both for programming style and for type inference. They let you describe the shape of an API without committing to a concrete hierarchy. In Acton, protocols can also be implemented by extensions after a class is defined, which makes them useful for retrofitting shared behavior onto existing types.

    ## Protocols in practice ```python protocol Printable: print : () -> None def render(item: Printable): item.print() ``` Here, `render` only cares that the value can be printed. It does not care which class the value comes from. ## Protocols and generic constraints Protocols also show up in generic type signatures. ```python def bigger[A(Ord)](a: A, b: A) -> A: if a > b: return a return b ``` Here, `A(Ord)` means the type `A` must implement the `Ord` protocol so that `>` is available. Built-in protocols such as `Ord`, `Hashable`, `Iterable`, and `Mapping` are documented in the reference section under [Built-in protocols](../stdlib/builtin_protocols.md). ================================================ FILE: docs/acton-guide/src/rts.md ================================================ # Run Time System The Acton Run Time System is what sets up the environment in which an Acton program runs. It performs bootstrapping of the root actor. The worker threads that carry out actual execution of actor continuations are part of the RTS. It is the RTS that handles scheduling of actors and the timer queue. All I/O is handled between modules in the standard library in conjunction with the RTS. # Arguments It is possible to configure the RTS through a number of arguments. All arguments to the RTS start with `--rts-`. Use `--rts-help` to see a list of all arguments: ```sh $ acton examples/helloworld.act Building file examples/helloworld.act Compiling helloworld.act for release Finished compilation in 0.012 s Final compilation step Finished final compilation step in 0.198 s $ examples/helloworld --rts-help The Acton RTS reads and consumes the following options and arguments. All other parameters are passed verbatim to the Acton application. Option arguments can be passed either with --rts-option=ARG or --rts-option ARG --rts-bt-dbg Interactively debug on SIGILL / SIGSEGV --rts-debug RTS debug, requires program to be compiled with --optimize Debug --rts-ddb-host=HOST DDB hostname --rts-ddb-port=PORT DDB port [32000] --rts-ddb-replication=FACTOR DDB replication factor [3] --rts-node-id=ID RTS node ID --rts-rack-id=RACK RTS rack ID --rts-dc-id=DATACENTER RTS datacenter ID --rts-host=RTSHOST RTS hostname --rts-help Show this help --rts-mon-log-path=PATH Path to RTS mon stats log --rts-mon-log-period=PERIOD Periodicity of writing RTS mon stats log entry --rts-mon-on-exit Print RTS mon stats to stdout on exit --rts-mon-socket-path=PATH Path to unix socket to expose RTS mon stats --rts-no-bt Disable automatic backtrace --rts-log-path=PATH Path to RTS log --rts-log-stderr Log to stderr in addition to log file --rts-verbose Enable verbose RTS output --rts-wthreads=COUNT Number of worker threads [#CPU cores] $ ``` # Worker threads Per default, the RTS starts as many worker threads as there are CPU threads available, although at least 4. This is optimized for server style workloads where it is presumed that the Acton program is the sole program consuming considerable resources. When there are 4 and more CPU threads available, the worker threads are pinned to each respective CPU thread. It is possible to specify the number of worker threads with `--rts-wthreads=COUNT`. Actor method continuations run to completion, which is why it is wise not to set this value too low. Per default a minimum of 4 threads are started even when there are fewer CPU threads available, which means the operating system will switch between the threads inducing context switching overhead. # Interactive debugging on crashes If an Acton program crashes, `--rts-bt-dbg` is a convenient option for launching an interactive debugger. It is triggered on `SIGILL` / `SIGSEGV` and launches an interactive GDB session that allows for debugging the running program. Acton programs do not normally crash with `SIGILL` / `SIGSEGV` but it possible either due to bugs in the compiler / RTS / builtins or more likely, for third party libraries that use C FFI, like for TLS, SSH, zlib or similar where a bug in the library triggers a crash on C level. ================================================ FILE: docs/acton-guide/src/security/capabilities.md ================================================ # Capabilities to access outside world Any useful program eventually needs to interact with the outside world. That can mean reading files, opening sockets, or sending data to a remote host. In many languages those operations are always available to any code. In Acton they are explicit. Things outside the actor world are represented by actors and accessed through capability references. A capability is a reference that grants permission for a specific kind of operation. Without the reference, the operation is not available. For example, `TCPConnection` needs a `TCPConnectCap` to connect to a remote host over TCP. The type system enforces that requirement. If the right capability is not available, the code does not compile. `TCPConnectCap` sits inside a capability hierarchy that starts at `WorldCap` and narrows from there: > WorldCap >> NetCap >> TCPCap >> TCPConnectCap The root actor, typically `main()`, takes an `Env` reference as its first argument. `env.cap` is the root `WorldCap` capability for accessing the outside world. ```python import net actor main(env): def on_connect(c): c.close() def on_receive(c, data): pass def on_error(c, msg): print("Client ERR", msg) connect_cap = net.TCPConnectCap(net.TCPCap(net.NetCap(env.cap))) client = net.TCPConnection(connect_cap, env.argv[1], int(env.argv[2]), on_connect, on_receive, on_error) ``` That structure matters because it lets the program choose how much authority to hand out. A deeply nested helper, or a dependency of a dependency, can only do what its received capability allows. ## Restrict and delegate When a function takes a capability argument, it should normally take the narrowest capability it actually needs. If the code only needs to open a TCP connection, pass `TCPConnectCap`. Do not pass `WorldCap` just because it is available. When you write a helper, ask what the helper really does. Give it only the capability needed for that work. If a library asks for a wider capability than the work requires, that is a design problem in the library.

    The deeper design point is capability attenuation: code should pass along narrower powers than it originally received whenever possible. That keeps authority local, makes APIs easier to audit, and prevents a convenient helper from quietly becoming a wide ambient escape hatch into the outside world.

    ## Capability-friendly interfaces Capability-friendly APIs are explicit about their authority boundaries. If one part of a library logs to files and another part talks to a remote host, split those responsibilities or make the narrower paths easy to select. The goal is not ceremony. The goal is to keep authority local and visible. A capability that is not passed in cannot be used, and a capability that is not passed on cannot escape further into the program. ================================================ FILE: docs/acton-guide/src/security/intro.md ================================================ # Security and Trust (or the lack thereof) ================================================ FILE: docs/acton-guide/src/security.md ================================================ # Security Acton's security model starts from a simple rule: code can only use what it has a reference to. Actors are isolated from each other. To call an actor, read from it, or otherwise interact with it, code must already hold a reference to that actor. There is no ambient authority hiding behind a module import or a global variable. That is close to the [object capability model](https://en.wikipedia.org/wiki/Object-capability_model).

    A useful mental model is: no ambient authority. If code can reach something, that access had to come from somewhere concrete. In practice, give each function or actor only the references it actually needs. That keeps the code easy to reason about and makes accidental access paths harder to create.

    Because there are no mutable globals, reachable state is either: - local to the current actor - reachable through references that were explicitly passed in ```python actor Vault(): def read(): print("secret") actor Reader(vault): def show(): await async vault.read() actor main(env): vault = Vault() reader = Reader(vault) await async reader.show() env.exit(0) ``` `Reader` can call `Vault` only because the reference was passed in explicitly. If the reference is not available, the access is not available.

    The key point is not only "there are no mutable globals". It is that authority itself becomes something code can pass, withhold, or narrow. If a function or actor never receives a filesystem, network, or process capability, it cannot perform those actions by accident or by hidden convention. That makes ordinary API boundaries double as security boundaries.

    This is why explicit capability passing matters so much in Acton. A reference is not just a way to reach a value; it is also the way authority enters a piece of code. That applies equally to actor references inside the program and to outside-world capabilities such as files, networking, environment access, and terminal control.

    ================================================ FILE: docs/acton-guide/src/stdlib/builtin_protocols/collection.md ================================================ # Collection protocols These protocols describe the shared APIs behind built-in collection types.

    These protocols describe behavior, not concrete storage. They let the language talk about "something indexable" or "something iterable" without naming one specific collection type.

    ## Core collection protocols - `Indexed[A(Eq), B]`: lookup, assignment, and deletion with `[]` - `Sliceable[A] (Indexed[int, A])`: slicing with `start:stop:step` - `Collection[A] (Iterable[A])`: construction from an iterable and `len` - `Container[A(Eq)] (Collection[A])`: membership with `in` and `not in` ## Specialized collection protocols - `Sequence[A] (Sliceable[A], Collection[A], Times[int])`: ordered, sliceable collections with repetition and mutating operations such as `append`, `insert`, and `reverse` - `Mapping[A(Eq), B] (Container[A], Indexed[A, B])`: key/value collections with `get`, `pop`, `keys`, `values`, and `items` - `Set[A(Eq)] (Container[A], Ord, Logical, Minus)`: set operations, ordering, membership, and mutating updates such as `add` and `discard` Built-in types make use of these protocols: - `list[A]` implements `Sequence[A]` - `dict[A(Hashable), B]` implements `Mapping[A, B]` - `set[A(Hashable)]` implements `Set[A]`

    The protocol surface is sometimes looser than a concrete type's full requirements. For example, Mapping[A, B] talks about key/value behavior in general, while dict specifically requires hashable keys.

    ================================================ FILE: docs/acton-guide/src/stdlib/builtin_protocols/general.md ================================================ # General protocols These protocols cover iteration, comparison, operators, and hashing. ## Iteration - `Iterable[A]`: values that can produce an iterator with `__iter__` and can therefore be used in `for` loops and other iteration-based APIs ## Identity and comparison - `Identity`: identity comparison with `is` and `is not` - `Eq`: equality comparison with `==` and `!=` - `Ord (Eq)`: ordering with `<`, `<=`, `>`, and `>=`

    If you see a constraint such as A(Ord) in a type signature, it means values of type A support ordering.

    ## Operator families - `Logical`: `&`, `|`, `^`, and their in-place forms - `Plus`: `+`, `+=`, and `__zero__` - `Minus`: `-` and `-=` - `Times[A] (Plus)`: `*` and `*=`, with right-hand operand type `A` - `Div[A]`: `/` and `/=`, with result type `A` ## Hashing - `Hashable (Eq)`: values that can feed data into a `hasher`; required for dictionary keys and set elements

    If you see a constraint such as A(Hashable), values of type A can be used where hashing is required.

    See [Hashable](hashable.md) for the full protocol reference and an implementation example. ================================================ FILE: docs/acton-guide/src/stdlib/builtin_protocols/hashable.md ================================================ # Hashable The `Hashable` protocol defines how values participate in hashing. It is required for dictionary keys and set elements.

    If a collection needs to look up a value by hash, the value's type must be hashable. That is why dictionary keys and set elements have this constraint.

    ## Protocol definition `Hashable` extends `Eq`, which means hashable values must also support equality: ```python protocol Hashable (Eq): hash : (hasher) -> None ``` The built-in helper functions are: ```python def hash(x: Hashable) -> u64 def seed_hash(seed: u64, x: Hashable) -> u64 ``` ## How hashing works Hashing uses a two-part design: 1. A `hasher` object accumulates hash input. 2. A value's `hash` method feeds its data into that `hasher`. When you call `hash(x)`, Acton creates a `hasher`, asks `x` to feed its state into it, and then finalizes the result as a `u64`. ```python p = Point(10, 20) h = hash(p) print("hash:", h) ``` ## Implementing `Hashable` To make a custom type hashable, define both equality and hashing so they describe the same identity. ```python class Point: x: int y: int def __init__(self, x: int, y: int): self.x = x self.y = y extension Point(Hashable): def __eq__(self, other): return self.x == other.x and self.y == other.y def hash(self, h): self.x.hash(h) self.y.hash(h) ``` The important rules are: 1. Hash all fields used by equality. 2. Hash them in a stable order. 3. Do not leave out part of the value's identity. If two values compare equal, they must feed the same data into the hasher.

    Hashable follows equality, not the other way around. If two values compare equal but feed different data into the hasher, sets and dictionaries can behave incorrectly in subtle ways even though the program still typechecks.

    ## Using hashable values in collections Once a type implements `Hashable`, values of that type can be used in sets and as dictionary keys: ```python def test_hashable_point(): p1 = Point(1, 2) p2 = Point(3, 4) p3 = Point(1, 2) points = {p1, p2, p3} point_names = {p1: "origin", p2: "destination"} print("unique points:", len(points)) print("point names:", point_names) ``` ## Built-in types Many built-in value types implement `Hashable`, including: - `bool` - `int`, `bigint`, and the fixed-width integer types - `float` - `complex` - `str` - `bytes` `dict` and `set` use `Hashable` for their key or element types, but are not themselves documented as `Hashable` here. ================================================ FILE: docs/acton-guide/src/stdlib/builtin_protocols/numeric.md ================================================ # Numeric protocols These protocols describe the operations available on built-in numeric types. ## Protocol hierarchy - `Number (Times[Self], Minus)`: core numeric behavior such as `+`, `-`, `*`, `**`, unary `+` and `-`, `abs`, `real`, `imag`, and `conjugate` - `Real (Number)`: float-style conversion and rounding operations such as `__float__`, `trunc`, `floor`, `ceil`, and `round` - `RealFloat (Real)`: floating-point real numbers - `Rational (Real)`: values with `numerator` and `denominator` - `Integral (Rational, Logical)`: integer-style operations such as `//`, `%`, shifts, bit operations, and indexing ## Built-in implementations - `int`, `bigint`, and the fixed-width signed and unsigned integer types implement `Integral` - `float` implements `RealFloat` - `complex` implements `Number` Use the narrowest constraint that matches the operations you need:

    Choose Number when you need ordinary arithmetic. Choose Integral when you need integer-only operations such as floor division, modulo, or bit shifts.

    ```python def square[A(Number)](x: A) -> A: return x * x def bucket[A(Integral)](x: A, size: A) -> A: return x // size ```

    Numeric constraints affect both operator availability and result types. For example, Div[A] separates the type of the result from the type of the operands, which is why integer division through / can return a different type than floor division through //.

    ================================================ FILE: docs/acton-guide/src/stdlib/builtin_protocols.md ================================================ # Built-in protocols Built-in protocols are defined in `__builtin__`. They show up in generic constraints, operator behavior, and the APIs of built-in collections. This section is reference material for the protocols that come with the language.

    Built-in protocol constraints are part of the type system, not just documentation. They affect which operators are available, which generic functions typecheck, and how protocol methods are resolved.

    The built-in protocols are grouped here as: - [General protocols](builtin_protocols/general.md) for iteration, comparison, operators, and hashing - [Numeric protocols](builtin_protocols/numeric.md) for number-like types - [Collection protocols](builtin_protocols/collection.md) for collection-shaped APIs

    Read a header such as protocol Ord (Eq) as "Ord extends Eq". A type that implements Ord must also satisfy the requirements of Eq.

    For how protocols work as a language feature, read [Protocols](../protocols/intro.md). ================================================ FILE: docs/acton-guide/src/stdlib/math.md ================================================ # math The `math` module provides the constant `pi` and common floating-point functions. Source: ```python import math actor main(env): angle = math.pi / 4.0 print(math.sin(angle)) print(math.sqrt(9.0)) env.exit(0) ```

    Import the module first with import math, then call its functions as math.sqrt(...), math.sin(...), and so on.

    The module currently exposes: - `pi` - `sqrt`, `exp`, `log` - `sin`, `cos`, `tan` - `asin`, `acos`, `atan` - `sinh`, `cosh`, `tanh` - `asinh`, `acosh`, `atanh` These functions take and return `float`.

    The module defines a RealFuns protocol and implements it for float. The exported module functions delegate through that protocol.

    ================================================ FILE: docs/acton-guide/src/stdlib/re.md ================================================ # re The `re` module provides regular expression matching. Source: ```python import re actor main(env): m = re.match(r"(foo[a-z]+)", "bla bla foobar abc123") if m is not None: print("Got a match:", m.group[1]) env.exit(0) ```

    Import the module with import re, then call functions such as re.match(...).

    `re.match` also accepts an optional `start_pos` to begin scanning at a specific index (defaults to 0). Output: ```sh Got a match: foobar ``` ================================================ FILE: docs/acton-guide/src/stdlib/standard_library.md ================================================ # Standard Library This section documents modules that you import explicitly.

    Use import to bring a standard library module into scope.

    Modules: - [math](math.md) - [re](re.md) ================================================ FILE: docs/acton-guide/src/stdlib.md ================================================ # Built-in & Standard Library This part of the guide is reference material. Acton has two closely related pieces here: - built-in definitions that are always available, such as core types and built-in protocols - standard library modules that you import explicitly, such as `math` and `re`

    Built-in names are part of the language environment. Standard library modules are brought into scope with import.

    Use [Built-in protocols](stdlib/builtin_protocols.md) for the protocols defined in `__builtin__`, including `Eq`, `Ord`, `Hashable`, `Iterable`, and `Mapping`.

    This split matches the implementation structure as well: built-in protocols and core types live in __builtin__, while module APIs such as math live in separate standard library modules.

    Use [Standard Library](stdlib/standard_library.md) for imported modules. ================================================ FILE: docs/acton-guide/src/testing/async_actor_test.md ================================================ # Async actor tests Source: ```python import logging import testing actor MathTester(): def add(a, b): return a + b actor _AsyncTester(t: testing.AsyncT): log = logging.Logger(t.log_handler) def test(): log.info("AsyncTester.test() doing its thing") t.success() # Provide output to .success to enable snapshot testing # t.success("some_output") # Or if things aren't going well, use .failure or .error # t.failure(ValueError("whopsy")) # t.error(ValueError("whopsy")) after 0: test() ``` Run: ```sh acton test ``` Output: ```sh Building project in /home/user/foo Compiling example.act for release Finished compilation in 0.028 s Final compilation step Finished final compilation step in 0.516 s Tests - module example: asyncact1: OK: 1171 runs in 56.181ms All 1 tests passed (0.695s) ``` If a particular module is written to be called asynchronously, you will need to use asynchronous tests to test it. `testing.AsyncT` also provides: - `t.require(tag)` to skip a test when a required capability is not enabled via `acton test --tag TAG` - `t.skip(reason)` to explicitly skip the current test The test discovery system finds asynchronous tests by looking for *actors* that take a `testing.AsyncT` parameter. *Snapshot testing* can be enabled by providing an output of type *str* to the `.success(output: ?str)` function. The Acton test framework will take care about recognizing the test as a snapshot test and comparing its output to the expected *snapshot value*. ================================================ FILE: docs/acton-guide/src/testing/env_test.md ================================================ # Env tests When you need to test functionality that accesses the environment, like files on disk or connect to something across the network, you need an env test. Do beware of errors related to test setup though, since you now depend on the external environment. TCP ports that you try to listen to might be already taken. Files that you assume exist might not be there. Source: ```python import logging import testing actor _TestWithEnv(t: testing.EnvT): log = logging.Logger(t.log_handler) def test(): log.info("EnvTester.test() running, going to check with the env", {"worker_threads": t.env.nr_wthreads}) t.success() # Provide output to .success to enable snapshot testing # t.success("some_output") # Or if things aren't going well, use .failure or .error # t.failure(ValueError("whopsy")) # t.error(ValueError("whopsy")) after 0: test() ``` Run: ```sh acton test ``` Output: ```sh Building project in /home/user/foo Compiling example.act for release Finished compilation in 0.023 s Final compilation step Finished final compilation step in 0.484 s Tests - module example: envtest1: OK: 1213 runs in 50.135ms All 1 tests passed (0.689s) ``` The test discovery system finds environment tests by looking for *actors* that take a `testing.EnvT` parameter. `testing.EnvT` also provides: - `t.require(tag)` to skip a test when a required capability is not enabled via `acton test --tag TAG` - `t.skip(reason)` to explicitly skip the current test *Snapshot testing* can be enabled by providing an output of type *str* to the `.success(output: ?str)` function. The Acton test framework will take care about recognizing the test as a snapshot test and comparing its output to the expected *snapshot value*. ================================================ FILE: docs/acton-guide/src/testing/failures_errors.md ================================================ # Failures vs errors Tests can have tree different outcomes; success, failure and error. **Success** and **failure** are the two common cases where success is when the test meets the expected assertions and a failure is when it fails to meet a test assertion like `testing.assertEqual(1, 2)`. We also distinguish a third case for test **errors** which is when a test does not run as expected, hitting an unexpected exception. This could indicate a design issue or that the test environment is not as expected. All test assertions raise exceptions inheriting from `AssertionError` which are considered **test failures**. Any other exception will be considered a **test error**. For example, if a test attempts to retrieve `https://dummyjson.com/products/1` and check that the returned JSON looks a certain way, it would be a test failure if the returned JSON does not match the expected value. If we try to connect with an invalid URL, like `htp://` we would get a different exception and that would be considered a **test error**. It's probably a bad idea to try to connect to something on the Internet in a test, so avoid that and other sources of non-determinism when possible. # Unit tests Source: ```python import random import testing def _test_failure(): testing.assertEqual(1, 2) def _test_flaky(): i = random.randint(0, 2) if i == 0: return elif i == 1: testing.assertEqual(1, 2) else: raise ValueError("Random failure") def _test_error() -> None: # Now we could never use a unit test to fetch things from the Internet # anyway, but it's just to show what the results look like raise ValueError() ``` Run: ```sh acton test ``` Output: ```sh Building project in /home/user/foo Compiling example.act for release Finished compilation in 0.020 s Final compilation step Finished final compilation step in 0.482 s Tests - module example: error: ERR: 454 errors out of 454 runs in 52.733ms ValueError: flaky: FLAKY FAIL: 231 failures out of 471 runs in 52.819ms testing.NotEqualError: Expected equal values but they are non-equal. A: 1 B: 2 failure: FAIL: 408 failures out of 408 runs in 52.837ms testing.NotEqualError: Expected equal values but they are non-equal. A: 1 B: 2 1 error and 2 failure out of 3 tests (0.691s) ``` Unit tests are a good starting point for testing small units of your program. Pure functions are deterministic and are thus preferable for tests over non-deterministic tests using actors. You are limited in what you can do though, since all called functions must be pure. ================================================ FILE: docs/acton-guide/src/testing/flaky.md ================================================ # Flaky tests Flaky tests are those that have different outcomes during different runs, i.e. they are not deterministic. To combat these, `acton test` will per default attempt to run tests multiple times to ensure that the result is the same. It runs as many test iterations as possible for at least 50ms. If a test is flaky, this will be displayed in the test output. Source: ```python import random import testing def _test_flaky(): i = random.randint(0, 2) if i == 0: return elif i == 1: testing.assertEqual(1, 2) else: raise ValueError("Random failure") ``` Run: ```sh acton test ``` Output: ```sh Building project in /home/user/foo Compiling example.act for release Finished compilation in 0.017 s Final compilation step Finished final compilation step in 0.453 s Tests - module example: flaky: FLAKY FAIL: 565 failures out of 1140 runs in 50.043ms testing.NotEqualError: Expected equal values but they are non-equal. A: 1 B: 2 1 out of 1 tests failed (0.625s) ``` ```admonish Note how this test case is only made possible because the random module has incorrect effects. The type says it is pure while in reality, it is not. There is an issue to improve this by applying a proper effect to the random module, see https://github.com/actonlang/acton/issues/1729, after which this example needs to be rewritten. ``` ================================================ FILE: docs/acton-guide/src/testing/perf_record.md ================================================ # Performance comparisons When running in `performance mode` you can record a snapshot of performance using `acton test perf --record`. A `perf_data` file is written to disk with the stored performance data. Subsequent test runs will read this file and show a comparison. The difference is displayed as a percentage increase or decrease in time. Source: ```python import testing def _test_simple(): a = 0 for i in range(99999): a += i ``` Run: ```sh acton test perf --record acton test perf ``` Output: ```sh Building project in /home/user/foo Compiling example.act for release Finished compilation in 0.017 s Final compilation step Finished final compilation step in 0.452 s Tests - module example: simple: OK: 3.25ms Avg: 4.16ms 7.38ms 122 runs in 1006.002ms All 1 tests passed (1.565s) Building project in /home/user/foo Compiling example.act for release Already up to date, in 0.000 s Final compilation step Finished final compilation step in 0.116 s Tests - module example: simple: OK: 3.23ms -0.50% Avg: 4.17ms +0.19% 6.35ms -13.91% 119 runs in 1001.375ms All 1 tests passed (1.215s) ``` (note that the output is rather wide, scroll horizontally to see the full output) ================================================ FILE: docs/acton-guide/src/testing/performance.md ================================================ # Performance testing It is also possible to run tests in a *performance mode*, which uses the same basic test definitions (so you can run your tests both as logic test and for performance purposes) but alters the way in which the tests are run. In performance mode, only a single test will be run at a time unlike the normal mode in which many tests are typically run concurrently. To get good numbers in performance mode, it's good if test functions run for at least a couple of milliseconds. With very short tests, very small differences lead to very large percentage differences. Source: ```python import testing def _test_simple(): a = 0 for i in range(99999): a += i ``` Run: ```sh acton test perf ``` Output: ```sh Building project in /home/user/foo Compiling example.act for release Finished compilation in 0.016 s Final compilation step Finished final compilation step in 0.451 s Tests - module example: simple: OK: 3.21ms Avg: 4.20ms 5.11ms 106 runs in 1005.261ms All 1 tests passed (1.571s) ``` (note that the output is rather wide, scroll horizontally to see the full output) See [Stress testing](stress.md) for concurrency-focused stress runs. ================================================ FILE: docs/acton-guide/src/testing/snapshot.md ================================================ # Snapshot testing Snapshot tests compare a produced string with a stored expected value. You can produce snapshot output from unit/sync test functions by returning `str`, or from async/env tests by calling `t.success("...")`. ```python import testing def _test_rendered_profile() -> str: return '{"name":"Alice","role":"admin"}' ``` Acton writes snapshot files in your project under `snapshots/output//` (latest produced value) and `snapshots/expected//` (expected value used for comparison). Test names in those paths use the display test name, so `_test_foo` becomes `foo`. When an expected snapshot differs (or is missing), running tests normally shows a mismatch: ```sh $ acton test Building project in /home/user/example ... Tests - module main: rendered_profile: FAIL : 254 runs in 50.045ms testing.NotEqualError: Test output does not match expected snapshot value. @@ -1,1 +1,1 @@ -{"name":"Alice","role":"user"} +{"name":"Alice","role":"admin"} 1 out of 1 tests failed (0.244s) ``` When the new output is correct, accept it as the new expected value with: ```sh $ acton test --accept Building project in /home/user/example ... Tests - module main: rendered_profile: UPDATED : 243 runs in 50.445ms All 1 tests passed (0.246s) ``` `--accept` is the idiomatic flag (aliases: `--snapshot-update`, `--golden-update`). For tests that produce snapshot output, `snapshots/output/...` is written on every run. That is intentional: it makes it easy to use external diff tools (`diff`, `vimdiff`, `meld`, etc.) against `snapshots/expected/...` without any extra export step. For example, to inspect the current snapshot difference for the test above: ```sh diff -u snapshots/expected/main/rendered_profile snapshots/output/main/rendered_profile ``` ## Common workflow 1. Run `acton test`. 2. If there is a snapshot mismatch, inspect it directly, for example: ```sh diff -u snapshots/expected/main/rendered_profile snapshots/output/main/rendered_profile ``` 3. Accept changes with `acton test --accept`. 4. Run `acton test` again to confirm everything passes. An alternative workflow is to accept first, then inspect version-controlled snapshot changes with Git: 1. Run `acton test --accept`. 2. Review what changed with `git diff -- snapshots/expected`. 3. Keep or revert changes before commit, then run `acton test`. ================================================ FILE: docs/acton-guide/src/testing/stress.md ================================================ # Stress testing Stress testing is meant for concurrency bugs, especially race conditions in FFI / C integrations. Run it with: ```sh acton test stress ``` ## How stress mode runs - Runs one test function/actor at a time. - For that test, starts multiple concurrent workers of the same test in one process. - Worker count defaults to roughly `1.5 * nr_wthreads` so workers must share RTS worker threads. - Override it with `--stress-workers N` when you want a specific level of oversubscription. - Stress runs are always fresh (no test-result cache reuse). - By default, stress runs for up to 5 seconds per test (`--max-time 5000`). - Continuous mode is available with `--max-time 0`. - In continuous mode, `--max-iter` is unbounded unless you set it. - The default stress `--min-time` is 1 second unless overridden (used for calibration; stress run length is controlled by `--max-time`). ## Worker scheduling Stress workers are split into: - A no-drift cohort (at least 2 workers, scaling to roughly 25% of workers) - A staggered-drift cohort (small per-iteration microsecond offsets) This combines synchronized overlap windows with evolving offsets over time. ## Per-worker live stats In an interactive terminal, stress mode shows one live status line per worker. - sync worker line: `wN sync RUN/DONE ... @ RATE/s cur=0us tot=0us` - drift worker line: `wN drift RUN/DONE ... @ RATE/s cur=DRIFTus tot=TOTALus` The main test line also carries a compact worker summary: - total: `... RUNS runs in DURATIONms @ RATE/s` - worker mix: `workers=N (sync=S drift=D)` - iteration estimate, granularity and observed coverage: `iter~...ms coarse~...ms sweep=... calib=... cov=SEEN/TOTAL(PCTpct)` - `iter~` is a moving estimate of one test iteration duration - `coarse~` is the current phase coarseness (lower is finer) - in continuous mode (`--max-time 0`), `coarse~` decreases stepwise over time as sweep depth increases - `cov` is observed occupied phase bins at current coarseness (resets when coarseness is refined) Example: ```txt racy_sum: RUN : 2400 runs in 1500.000ms @ 1600.0/s | workers=8 (sync=2 drift=6) iter~2.340ms coarse~0.037ms sweep=64 cov=37/64(57.8pct) ``` Use normal test flags to tune duration/iterations, for example: ```sh acton test stress --max-time 30000 --min-iter 100 ``` Pin a higher worker count explicitly: ```sh acton test stress --stress-workers 24 --max-time 30000 ``` Run continuously until interrupted: ```sh acton test stress --max-time 0 ``` Press `Ctrl-C` to stop and print the partial stress result collected so far. ================================================ FILE: docs/acton-guide/src/testing/sync_actor_test.md ================================================ # Sync actor tests Source: ```python import logging import testing actor MathTester(): def add(a, b): return a + b # It is possible to call actors in tests too, in which case the test is an # "actor test" (the function gets a 'proc' effect inferred when calling actors). def _test_syncact_simple(): m = MathTester() testing.assertEqual(m.add(1, 2), 3) # Actors named prefixed with _tests_ are also considered tests actor _test_SyncTester(): m = MathTester() testing.assertEqual(m.add(1, 2), 3) # Use any test actor name by taking a testing.SyncT as only parameter actor _SyncTester2(t: testing.SyncT): log = logging.Logger(t.log_handler) m = MathTester() log.info("Calculating numbers..") testing.assertEqual(m.add(1, 2), 3) # The traditional function-based approach can also take a testing.SyncT arg def _test_syncact(testing.SyncT): """A test using actors and synchronous control flow""" # We make use of an actor as the central point for running our test logic. s = _SyncTester(t) ``` Run: ```sh acton test ``` Output: ```sh Building project in /home/user/foo Compiling example.act for release Finished compilation in 0.027 s Final compilation step Finished final compilation step in 0.526 s Tests - module example: SyncTester: OK: 1029 runs in 50.015ms SyncTester2: OK: 1103 runs in 50.002ms syncact: OK: 1175 runs in 50.005ms syncact_simple: OK: 1231 runs in 50.014ms All 4 tests passed (0.655s) ``` Since the Acton RTS is multi-threaded and actors are scheduled concurrently on worker threads, using actors imply a degree of non-determinism and so unlike unit tests, which are completely deterministic, actors tests are fundamentally non-deterministic. You can still write deterministic tests as long as you pay attention to how you construct your test results. `testing.SyncT` also provides: - `t.require(tag)` to skip a test when a required capability is not enabled via `acton test --tag TAG` - `t.skip(reason)` to explicitly skip the current test For example, actor A might be scheduled before or after actor B so if the test relies on ordering of the output, it could fail or succeed intermittently. Interacting with the surrounding environment by reading files or communicating over the network introduces even more sources of non-determinism. Avoid it if you can. The test discovery system finds synchronous tests through: - **Functions**: with names starting with `_test_` and signatures `proc() -> None` or `proc(testing.SyncT) -> None` - **Actors**: that take a `testing.SyncT` parameter (the `_test_` prefix is optional) or actors with names starting with `_test_` and no parameters *Snapshot testing* can be enabled by returning a *str*. This only works for test *functions*, not test *actors*. Use a wrapping function if you want snapshot testing. The Acton test framework will take care about recognizing the test as a snapshot test and comparing its output to the expected *snapshot value*. ================================================ FILE: docs/acton-guide/src/testing/unit_test.md ================================================ # Unit tests Source: ```python import testing def _test_simple(): foo = 3+4 testing.assertEqual(7, foo) ``` Run: ```sh acton test ``` Output: ```sh Building project in /home/user/foo Compiling example.act for release Finished compilation in 0.016 s Final compilation step Finished final compilation step in 0.442 s Tests - module example: simple: OK: 1565 runs in 50.079ms All 1 tests passed (0.600s) ``` Unit tests are a good starting point for testing small units of your program. Pure functions are deterministic and are thus preferable for tests over non-deterministic tests using actors. You are limited in what you can do though, since all called functions must be pure. The test discovery finds unit tests based on the name starting with `_test_` and has a function signature of `mut() -> None` or `pure() -> None`. ```admonish Once effect analysis has been improved in the compiler to contain scope local effects, the test discovery will only consider `pure` functions to be unit tests. See https://github.com/actonlang/acton/issues/1632 ``` *Snapshot testing* can be enabled by returning a *str*. The Acton test framework will take care about recognizing the test as a snapshot test and comparing its output to the expected *snapshot value*. ================================================ FILE: docs/acton-guide/src/testing.md ================================================ # Testing Testing your code is a really good idea! While Acton's type system allows interfaces to be precisely defined, it is imperative that the behavior of a function or actor is tested! Test functions and test actors are automatically discovered by the compiler. Run tests with `acton test`. Import the testing module and name your test functions or actors starting with `_test_`. The type signature should match the test intended test category. Use the assertion functions available in the testing module. Here is a simple unit test: Source: ```python src/ut.act import testing def _test_simple(): testing.assertEqual(1, 1) ``` Run: ```sh acton test ``` Output: ```sh Building project in /home/user/foo Compiling example.act for release Finished compilation in 0.016 s Final compilation step Finished final compilation step in 0.437 s Tests - module example: simple: OK: 1523 runs in 50.001ms All 1 tests passed (0.604s) ``` There are 4 kinds of tests - **unit tests** - small simple tests of pure functions - **synchronous actor tests** - involving one or more actors, returning results synchronously - **asynchronous actor tests** - involving actors but use asynchronous callbacks for return values - **environment tests** - similar to async actor test in that a callback is used for the return value - these tests have access to the full environment via the `env` argument and can thus communicate with the outside world - this is a source of non-determinism so be mindful of this and try to avoid non-deterministic functions to the largest degree possible When possible, strive to use unit tests rather than actor based tests and strive to avoid env tests. For snapshot-based assertions, see [Snapshot testing](testing/snapshot.md). ## Cached test results The Acton test runner caches test results which means that repeated invokations of `acton test` might not actually (re)run tests. Cached failures and errors are still shown by default, so you never miss a failing test. Cached successes are hidden unless you pass `--show-cached`. Pass `--no-cache` to force all selected tests to run, even if cached results exist. This means that the developer experience for test driven development is great even for project with a very large amount of tests as the content hash driven test runner only recompiles and reruns tests that are actually affected by a change. Note that test input need to be contained within .act source code files in order for the compiler to consider them part of the content hash. You cannot use external .txt files or similar as input to test functions, since the compiler won't consider those parts of the implementation. Also see [incremental compilation](compilation/incremental.md) for more details on content hashing and how it applies to testing. Snapshot tests are the main exception: even when the test code hash matches the cache, `acton test` still checks the expected snapshot file on disk against the cached `snapshots/output/...` metadata. If the output snapshot is missing, the expected file changed, or Acton cannot cheaply prove the expected file is older than the last produced output, the test is rerun instead of trusting the cached result. ## Module Filtering You can run tests from specific modules using the `--module` flag: ```sh acton test --module foo --module bar ``` This will only run tests from the `foo` and `bar` modules, skipping all other test modules. ## Capability-gated tests Some tests depend on external capabilities (for example network services, hardware, or system setup). In tests that receive a test context argument (`t`), use `t.require(...)` and pass available capabilities with `--tag`: ```python import testing def _test_external_service(t): t.require("external-service") # test logic that depends on external-service being available ``` Run with capabilities: ```sh acton test --tag external-service ``` If the required capability is not enabled, the test is marked as skipped. Capabilities are runtime environment signals used by `t.require(...)`; they are not a pre-test selection/filter mechanism. This applies to test context objects like `SyncT`, `AsyncT`, and `EnvT`. You can also skip explicitly: ```python def _test_todo(t): t.skip("not implemented yet") ``` ================================================ FILE: docs/acton-guide/src/types/effects.md ================================================ # Effects (`pure`, `mut`, `proc`, `action`) Acton tracks effects as part of function and callable typing. An effect marker tells you what the callable is allowed to do, so it is part of the type information you read and design with. The four effect markers are: - `pure`: no side effects - `mut`: may update state - `proc`: functions that call actors - `action`: action or callback style code used heavily in actor APIs ```python pure def square(x: int) -> int: return x * x class Counter: value: int def __init__(self): self.value = 0 mut def next(self) -> int: self.value += 1 return self.value actor Greeter(): def hello(msg): print(msg) proc def show_square(g: Greeter, x: int) -> None: g.hello("square: " + str(square(x))) actor main(env): counter = Counter() greeter = Greeter() print("counter:", counter.next()) n = square(7) print("n:", n) show_square(greeter, 9) action def stop() -> None: env.exit(0) after 0.1: stop() ``` In this example: - `square` is `pure` - `Counter.next` is `mut` - `show_square` is `proc` because it calls an actor - `stop` is an `action` - the effect markers are part of the callable signatures, not notes ## Effect inference If you omit the effect marker, Acton infers it from the body. Use explicit annotations when you want an API to promise purity, make mutation clear, or document that a callback or actor-facing entrypoint has a particular effect. The effect is part of the contract just like its argument and return types.

    A useful first habit is to keep calculations pure and push printing, I/O, and actor orchestration into a smaller layer of effectful code. Read pure as "calculation only", mut as "may update state", proc as "calls actors", and action as "actor action or callback".

    That division makes code easier to reason about. If a helper is pure, you know it only depends on its inputs. If it is mut or proc, you know it may change state or interact with actors, which makes its API more specific.

    ## When the four effects show up - `pure` is common for ordinary calculations and helpers that should be easy to reuse anywhere - `mut` is common on methods that update state or work with local mutable data - `proc` is common for functions that orchestrate work by calling actors - `action` often appears in actor methods, timers, cleanup hooks, and callback types such as `action(str) -> None` Effects often explain why a signature looks the way it does. A function may have a simple data type and still be effectful, and the effect marker is what tells you whether it stays in pure computation or crosses into stateful or actor-driven work.

    Effects also appear in inferred signatures. As your code gets more generic or callback-heavy, those effect annotations become part of how you read and design APIs. In Acton, purity is a real constraint on what a function may call, so effect annotations are part of the contract, not just commentary.

    ## Practical guidance - Prefer `pure` for deterministic, test-friendly core logic. - Use `mut` when a callable really updates state. - Use `proc` for functions that orchestrate work by calling actors. - Expect `action` in actor APIs, timers, cleanup hooks, and callbacks. - Keep pure logic separated from actor-driven orchestration code. - Read the effect marker together with the argument and return types.

    A useful mental model is pure <= mut <= proc, with action <= proc on a separate branch. That is why pure code can be used where a mutating or procedural callable is accepted, and why actions participate in the broader effect system without being the same thing as ordinary sequential procedures. When you design higher order APIs, the effect on the callback is as important as its argument types.

    In practice, this means you should choose the weakest effect that describes the callable accurately. That keeps more code reusable and leaves the effect system useful as the codebase grows.

    ================================================ FILE: docs/acton-guide/src/types/explicit.md ================================================ # Explicit types Acton can infer many types, but explicit annotations are still useful. They are the way to say "this value must stay this shape" when the code would otherwise leave room for interpretation. ```python def repeat(text: str, count: int) -> str: return text * count describe_port : (int) -> str def describe_port(port): return "port " + str(port) actor main(env): port: int = 9000 print(repeat("ha", 3)) print(describe_port(port)) env.exit(0) ```

    Read name: Type as "name has type Type" and -> Type as "returns Type". A separate signature line can be easier to scan when the implementation is long or the signature is part of the public surface of a module.

    You can annotate: - function parameters - return values - local names - class and actor attributes - separate signature lines for named APIs - effect markers on callables ## When explicit types help Write annotations when: - you want an API to be clear to readers - inference becomes hard to understand - you want the compiler to reject the wrong shape earlier - a value could otherwise be inferred more loosely than you want - you are defining a reusable helper and want its contract visible

    A useful default is to annotate the things other people will read first: public functions, methods, actor fields, and data structures. Leave short local expressions inferred unless the type is surprising or important to the code around it.

    Explicit annotations also control generalization. If inference would make a helper more polymorphic than you want, a written signature can pin the API down and keep later changes from widening it by accident. That is especially useful for callback types, actor-facing entrypoints, and shared utility code where the signature is the real contract.

    ================================================ FILE: docs/acton-guide/src/types/generics.md ================================================ # Generics Generics let you write code that works for many types without throwing away type safety. They are how you describe a pattern once and reuse it for every concrete type that fits the pattern. ## A simple generic function ```python def first[A](items: list[A]) -> A: return items[0] actor main(env): print(first([1, 2, 3])) print(first(["a", "b", "c"])) env.exit(0) ``` `[A]` introduces a type variable named `A`. In this function: - `items` is a `list[A]` - the return value is also `A` - calling `first` on a `list[int]` returns an `int` - calling it on a `list[str]` returns a `str` - the compiler checks each call with the concrete type it sees there

    If the brackets feel abstract at first, read them as "for any type named A". Each call picks a concrete type for A, so first([1, 2, 3]) uses int while first(["a"]) uses str. That is how one definition stays reusable without giving up compile-time checking.

    ## Constrained generics Sometimes a generic function needs more than "any type". It may require that the type supports some operation or protocol. ```python def bigger[A(Ord)](a: A, b: A) -> A: if a > b: return a return b ``` Here, `A(Ord)` means `A` must implement the `Ord` protocol so the function can compare `a` and `b`. The constraint is part of the type information, not an implementation detail. Without it, the compiler would not know that `>` is valid for `A`.

    Acton can often infer generic parameters and protocol constraints for you. Using --sigs is a good way to see what the compiler understood before you decide whether to write the generic signature explicitly. That matters when a helper starts being reused widely, because the inferred constraints determine both flexibility and dispatch behavior.

    ## Generics on classes Built-in collection types use the same syntax. ```python class list[A] (object): ... ``` That means a `list[int]` and a `list[str]` have the same generic shape but different element types. The same idea applies to your own classes and records. If a container or wrapper stores values without caring which concrete type they are, make that type parameter explicit. ## When to add constraints Add a constraint when a type parameter must support a particular operation: - comparison, as in `Ord` - equality or hashing, if the code depends on it - a protocol, if the function calls methods from that protocol Do not add a constraint just because it looks formal. The compiler only needs the bounds that the body actually uses. ================================================ FILE: docs/acton-guide/src/types/intro.md ================================================ # Working with types Acton is statically typed. The compiler checks types when your program is compiled, but it can infer many of them for you. In practice, that means you usually write the shape of the code and let the compiler fill in the rest. This section explains how to work with that type system deliberately: how to read inferred signatures, when to write explicit annotations, and how generics, constraints, and effects show up in real code. Acton does not have Rust-style lifetimes. Mutable state lives inside actors, access to the outside world is passed explicitly as capabilities, and ordinary object lifetime is handled by the runtime. See [Actors](../actors.md), [Lifetime](../actors/lifetime.md), and [Environment and capabilities](../language/environment_capabilities.md) for the Acton model. Optional types are introduced earlier under [Missing values and failures](../language/missing_values_failures.md) because they come up quickly in everyday code, but they are also part of the broader type story. ```python def describe(value): if value > 0: return "positive" return "zero or negative" actor main(env): n = 3 text = describe(n) print(text) env.exit(0) ``` In this example, Acton can infer the types without any annotations. `n` is an `int`, `describe` returns `str`, and `text` is also a `str`. That is often the most pleasant way to write small programs: start with plain code, then add annotations only where they improve clarity.

    You do not need to annotate every value. A small helper, a local temporary, or a short private function can often stay inferred without hurting readability. Add types where they explain intent, not as decorations.

    ## Reading inferred signatures Use `--sigs` when you want the compiler to show the types it inferred. ```sh acton types.act --sigs ``` In a project, use `acton sig` when you want signatures by import path instead of by source file path: ```sh acton sig foo.bar ``` The target is resolved like an import path. Acton first looks for a module named `foo.bar`. If that module does not exist, it treats the target as the public name `bar` inside module `foo` and prints only that signature. This is useful when a type error mentions an imported module or name, especially one that comes from a dependency. `acton sig` uses the project's normal build resolution, so it reads `Build.act`, honors dependency overrides such as `--dep name=path`, fetches missing dependencies, and compiles the module interfaces it needs before printing the signatures. It does not perform the final executable build. For example: ```sh acton sig collections.list acton sig mylib.parser.parse ```

    Acton's inferred signatures include more than argument and return types. You will see generic binders, protocol constraints, optional types, tuple rows, and effect markers. Reading a signature means reading both the data shape and the callable behavior. The compiler's output is often the clearest summary of what an API actually promises, so acton sig and --sigs are useful first steps before deciding whether to make that promise explicit.

    This is especially useful when: - you want to understand what type a helper function ended up with - you are learning how generic constraints are written - you want to turn an inferred signature into an explicit API - you need to see effect markers or optionality in a callable type ## What this section covers - [Explicit types](explicit.md) when you want to state an API, narrow a local value, or make inference easier to follow - [Generics](generics.md) when one definition should work for many concrete types without losing safety - [Effects (`pure`, `mut`, `proc`, `action`)](effects.md) when you want to treat side effects as part of the type information - [Troubleshooting type errors](troubleshooting.md) when you want to inspect imported signatures and compare them with an error - [Optionals](optionals.md) when you want the deeper type-system view of values that may be absent ================================================ FILE: docs/acton-guide/src/types/optionals.md ================================================ # Optionals Before you can use an optional `?T` value as a plain `T` value, Acton must be able to see that the value is present. ## Narrowing `if x is not None` narrows `x` from `?T` to `T` inside that branch. Use this form when the following code needs the value itself, not a value that may still be `None`. ```python def upper_or_none(text: ?str) -> ?str: if text is not None: return text.upper() return None ``` Inside the `if` branch, `text` is treated as `str`, so ordinary string methods are available. `if isinstance(x, SomeClass)` can also narrow an optional value while refining the concrete class. Acton currently narrows variable names, not arbitrary attributes or expressions. When you need several guarded accesses, bind the intermediate value to a name and narrow that name explicitly. ```python class Residence(): def __init__(self, rooms: int, name: ?str = None): self.rooms = rooms self.name = name class Person(): def __init__(self, name: str, residence: ?Residence): self.name = name self.residence = residence def residence_name(person: ?Person) -> ?str: if person is not None: residence = person.residence if residence is not None: return residence.name return None ``` Each access is guarded by a test that rules out `None` before the next access. ## Optional chaining Optional chaining is a shorter way to keep `None` flowing through a single expression. ```python def residence_name(person: ?Person) -> ?str: return person?.residence?.name ``` The chain above is the compact form of the explicit checks from the previous section: ```python def residence_name(person: ?Person) -> ?str: if person is not None: residence = person.residence if residence is not None: return residence.name return None ``` If the value to the left of `?.` is `None`, the whole expression evaluates to `None`. If the value to the left of `?[...]` is `None`, indexing or slicing is skipped and the result is `None`. Use `?.` for attribute access and method calls, and `?[...]` for indexing and slicing. ```python def loud_residence_name(person: ?Person) -> ?str: return person?.residence?.name?.upper() def first_port(config: ?dict[str, list[int]]) -> ?int: return config?.get("ports")?[0] ``` The result of an optional chain is still optional. For example, `person?.residence?.rooms` has type `?int`, not `int`. Optional chaining only affects the current expression. It does not narrow the value for later statements, so use `is None` or `is not None` when you need to branch on the result.

    Optional chaining lifts each later access into optional context. Each step only runs if the previous step produced a real value; otherwise the whole expression settles to None immediately. That is why a chain is good for one-pass extraction of a nested value: it preserves absence without forcing you to invent a sentinel or write a stack of temporary checks just to carry None through the expression.

    That same property is also the limit of the feature. A chain tells you only the final result, not which step failed or what should happen next. Once you need branching, logging, recovery, or repeated use of an intermediate value, stop chaining and narrow explicitly with is None / is not None. Optional chaining is best for compact extraction, not for complex control flow.

    ## Forced unwrapping Use forced unwrapping when surrounding logic has already established that an optional value is present. If that assumption is wrong, Acton raises `ValueError` instead of continuing with `None`. Use `!` on an optional value to get the non-optional value inside it. If `b` has type `?str`, then `b!` has type `str`. ```python def required_name(name: ?str) -> str: return name! ``` You can think of forced unwrapping as this check: ```python def unwrap[T](value: ?T) -> T: if value is not None: return value raise ValueError("unexpected None value") ``` You do not normally write that helper yourself. The `!` syntax is the short form of "give me the value if it is present, otherwise raise `ValueError`". `!.` applies the same idea inside attribute access and method calls, and `![...]` applies it inside indexing and slicing chains. They follow the same shapes as `?.` and `?[...]`, but raise `ValueError` if the value to the left is `None` instead of returning `None`. ```python def required_residence_name(person: ?Person) -> str: return person!.residence!.name!.upper() ``` This returns `str`, not `?str`. If `person`, `residence`, or `name` is `None`, evaluation stops and raises `ValueError`. The final `!.upper()` is a guarded method call: it only calls `upper()` after `name` has been unwrapped. You can mix `?` and `!` in the same chain. Later steps still see the result of earlier ones, so a later `!` will raise if an earlier step produced `None`. ```python def first_port_required(config: ?dict[str, list[int]]) -> int: return config!.get("ports")![0] def first_port_or_none(config: ?dict[str, list[int]]) -> ?int: return config?.get("ports")?[0] ``` Use forced unwrapping when absence indicates a bug or broken invariant and execution should stop immediately.

    Forced unwrapping is for invariants: states that should already have been proven by surrounding logic. It is the right tool when a missing value means the program state is wrong, not when absence is still part of the normal control flow.

    ================================================ FILE: docs/acton-guide/src/types/troubleshooting.md ================================================ # Troubleshooting type errors with signatures When a type error mentions a value from another module, first check the interface that the compiler sees. `acton sig` prints inferred signatures by import path, so you can compare the error against the imported API instead of searching for generated files or guessing from memory. Use this workflow: 1. Read the type error and find the module or type name involved. 2. Run `acton sig` for the smallest exact module or public name. 3. Compare the available attributes and methods with the failing code. 4. Fix the source and rebuild. ## Example: singular vs plural attribute Suppose one module defines a contact value: ```python # src/directory.act class Contact(object): display_name: str email_addresses: list[str] def __init__(self, display_name: str, email_addresses: list[str]): self.display_name = display_name self.email_addresses = email_addresses ``` Another module imports the class and uses the right concept, but the wrong singular form of the attribute name: ```python # src/main.act from directory import Contact def email_count(contact: Contact) -> int: return len(contact.email_address) ``` Running `acton build` points at the attribute selection: ```text [error]: Attribute not found email_address +--> main.act@4:24-4:37 | 4 | return len(contact.email_address) : ^------------ : `- Attribute not found email_address -----+ ``` The error is in `main`, but the shape of `Contact` is defined in `directory`. Ask the compiler for the imported type: ```sh acton sig directory.Contact ``` `acton sig` first looks for a module named `directory.Contact`. If no such module exists, it treats the target as the public name `Contact` inside module `directory`. The output shows the public interface for the class: ```python class Contact (object, value): G_init : () -> None @property display_name : str @property email_addresses : list[str] __init__ : (display_name: str, email_addresses: list[str]) -> None ``` The `@property` entries are the readable part for this error. They say the class has `email_addresses`, not `email_address`. That is not obvious from the local `main.act` file, but it is clear from the compiler-visible interface. The fix is in the selecting code: ```python def email_count(contact: Contact) -> int: return len(contact.email_addresses) ``` This same approach works for dependencies. If `directory` comes from a package dependency, `acton sig directory.Contact` still uses the project's normal build resolution: it reads `Build.act`, fetches missing dependencies, compiles the interface files it needs, and skips the final executable build. If you are testing a local checkout of a dependency, pass the same override you would pass to `acton build`: ```sh acton sig --dep directory=../directory directory.Contact ``` ## Example: selecting attributes on the wrong value Some type errors mention an "unknown type" even when the value has a known expected type. This can happen when Acton checks a method body and collects constraints from dot selections before it has simplified the whole constraint set. The important part is not the unknown type name alone. Read the whole error and look for the known type that must satisfy those constraints. Suppose one module defines an item type, a context type, and a base class whose method takes both: ```python # pipeline.act class WorkItem(object): title: str tags: set[str] output_path: str def __init__(self, title: str, tags: set[str], output_path: str): self.title = title self.tags = tags self.output_path = output_path class RunContext(object): run_id: str user: str def __init__(self, run_id: str, user: str): self.run_id = run_id self.user = user class Step(object): def apply(self, item: WorkItem, ctx: RunContext): raise NotImplementedError() ``` A subclass can omit the local annotations because the inherited method shape already gives `item` and `ctx` their expected types: ```python # steps.act from pipeline import Step class DraftStep(Step): def apply(self, item, ctx): print("processing {ctx.title}") if "draft" in ctx.tags: return ctx.output_path raise ValueError("not a draft") ``` The method uses `ctx.title`, `ctx.tags`, and `ctx.output_path`, but the inherited signature says `ctx` is a `pipeline.RunContext`. The resulting error has a common "simultaneous constraints" shape: ```text [error]: Cannot satisfy the following simultaneous constraints for the unknown types +--> steps.act@4:5-10:1 | 4 | +> def apply(self, item, ctx): 5 | | print("processing {ctx.title}") : | ^-------- : | `- The type of the indicated expression (which we call t0) must have an attribute title with type t4; no such type is known. 6 | | 7 | | if "draft" in ctx.tags: : | ^----------^------- : | | |- The type of the indicated expression (which we call t0) must have an attribute tags with type t1; no such type is known. : | | `- The type of the indicated expression (which we call t1) must be a subtype of t2 : | |- The type of the indicated expression (inferred to be __builtin__.str) must be a subtype of t3 : | `- The type of the indicated expression (which we call t2) must implement __builtin__.Container[t3] 8 | | return ctx.output_path : | ^-------------- : | `- The type of the indicated expression (which we call t0) must have an attribute output_path with type None; no such type is known. : | The type of the indicated expression (which we call t4) must be a subclass of ?__builtin__.value 9 | | 10 | |> raise ValueError("not a draft") : | : `- pipeline.RunContext must be a subclass of t0 -----+ ``` Do not read this as "Acton cannot infer the type of `ctx`". In this example, the inherited method signature already gives `ctx` the expected type `pipeline.RunContext`. The unknown `t0` is the type variable that collected the requirements introduced by the dot selections on `ctx`. The final line says that `pipeline.RunContext` must satisfy those collected requirements. The next step is to inspect the exact known type named in the error: ```sh acton sig pipeline.RunContext ``` That is usually better than asking for the whole module, because a large module can produce a lot of unrelated output. The signature shows the compiler-visible fields: ```python class RunContext (object, value): @property run_id : str @property user : str __init__ : (run_id: str, user: str) -> None ``` Now compare the failing selections with the signature. The code asked for `title`, `tags`, and `output_path`, but `RunContext` has only `run_id` and `user`. When none of the selected attributes are present, the code may be selecting on the wrong value. In this example, those attributes belong to `WorkItem`, so inspect that type too: ```sh acton sig pipeline.WorkItem ``` The fix is not to add a redundant annotation to `ctx`. The fix is to use the value that actually has the fields: ```python class DraftStep(Step): def apply(self, item, ctx): print("processing {item.title}") if "draft" in item.tags: return item.output_path raise ValueError("not a draft") ``` This pattern also appears with dependency types. If the known type comes from a dependency, still run `acton sig` for the exact public name shown in the error: ```sh acton sig package.module.TypeName ``` If you are using a local dependency override, pass the same override to `acton sig` that you pass to `acton build`: ```sh acton sig --dep package=../package package.module.TypeName ``` The compiler already sees the dependency signatures when it reports the error. Running `acton sig` does not make those signatures visible to the compiler; it makes them visible to you, so you can compare the API Acton is checking against the attributes and methods your code selects. ================================================ FILE: docs/acton-guide/src/working_with_zig.md ================================================ # Working with Zig / C / C++ Acton has C ABI compatibility which makes it trivial to call C functions and fairly simply to call Zig and C++ using C wrapping functions. If you want to integrate a library written in one of these languages, this page is for you. Regardless of the foreign language used, we need to consider a few things: - memory allocation, it must play well with the Acton GC - You can allocate memory via classic `malloc` or via Acton GC malloc - `acton_malloc` - normal malloc - `acton_malloc_atomic` for allocations that are guaranteed to not contain pointers - Better safe than sorry, use the GC-malloc when in doubt - Always use Acton GC malloc for actor and class attributes and similar - object and actor instances are garbage collected by the GC and there is no destructor function, so if you would have used class `malloc` there is no good place for the `free` - Within pure functions, you can use class `malloc` - be sure to `free` the allocations before return of the function, even for error paths - thread safety, the Acton RTS is threaded and actors are concurrently executed by different threads - in general, we strive to only keep data per actor and since an actor executes sequentially, we do not need thread safety measures like locks - just make sure you don't try to share data between actors "under the hood" - libraries must not use global variables though - asynchronous I/O, the Acton RTS performs asynchronous I/O and any other library that performs I/O need to conform to this model ================================================ FILE: docs/acton-guide/src/zig_dependencies.md ================================================ # C / C++ / Zig dependencies Much like dependencies on other Acton packages, an Acton project can depend on a Zig package which could be a C / C++ or Zig library, as long as it has a `build.zig` file. - `acton zig-pkg add URL NAME --artifact X --artifact Y` - list the libraries you want to link with as artifacts - `acton zig-pkg remove NAME` ~~~admonish example ``` acton zig-pkg add https://github.com/allyourcodebase/zlib/archive/refs/tags/1.3.1.tar.gz zlib --artifacts z ``` ```json { "dependencies": {}, "zig_dependencies": { "zlib": { "url": "https://github.com/allyourcodebase/zlib/archive/refs/tags/1.3.1.tar.gz", "hash": "122034ab2a12adf8016ffa76e48b4be3245ffd305193edba4d83058adbcfa749c107", "artifacts": [ "z" ] } } } ``` ~~~ ================================================ FILE: docs/acton-guide/svgbob.css ================================================ /* Ensure text is legible in all themes. */ svg text { fill: var(--fg); } ================================================ FILE: docs/acton-guide/theme/acton-theme.css ================================================ /* Acton visual theme for mdBook */ :root { --acton-yellow: #ffd42a; --acton-yellow-soft: #fff3b4; --acton-yellow-strong: #9c7412; --acton-steel-950: #151617; --acton-steel-900: #202326; --acton-steel-800: #33373a; --acton-steel-700: #454b4f; --acton-steel-600: #5f666a; --acton-steel-300: #c8cdd0; --acton-steel-200: #dfe2e3; --acton-steel-100: #eef0ef; --acton-paper: #f7f8f6; } .light, .rust, html:not(.js) { --bg: var(--acton-steel-100); --fg: #191b1c; --sidebar-bg: var(--acton-steel-900); --sidebar-fg: var(--acton-steel-200); --sidebar-non-existant: #858d92; --sidebar-active: var(--acton-yellow); --sidebar-spacer: rgba(255, 255, 255, 0.12); --scrollbar: var(--acton-steel-600); --icons: #d7dcde; --icons-hover: #ffffff; --links: #785600; --inline-code-color: #5d4810; --theme-popup-bg: var(--acton-steel-900); --theme-popup-border: rgba(255, 255, 255, 0.16); --theme-hover: rgba(255, 212, 42, 0.14); --quote-bg: #fff7cf; --quote-border: var(--acton-yellow); --warning-border: var(--acton-yellow-strong); --table-border-color: rgba(35, 38, 40, 0.16); --table-header-bg: #dfe2e3; --table-alternate-bg: rgba(255, 255, 255, 0.42); --searchbar-border-color: rgba(255, 255, 255, 0.18); --searchbar-bg: var(--acton-steel-950); --searchbar-fg: var(--acton-paper); --searchbar-shadow-color: rgba(255, 212, 42, 0.34); --searchresults-header-fg: var(--acton-steel-600); --searchresults-border-color: rgba(35, 38, 40, 0.16); --searchresults-li-bg: #fff7cf; --search-mark-bg: var(--acton-yellow-soft); --color-scheme: light; --copy-button-filter: invert(87%) sepia(8%) saturate(126%) hue-rotate(164deg) brightness(102%) contrast(90%); --copy-button-filter-hover: invert(82%) sepia(80%) saturate(811%) hue-rotate(340deg) brightness(103%) contrast(102%); --footnote-highlight: var(--acton-yellow-soft); --overlay-bg: rgba(21, 22, 23, 0.34); --acton-chrome-bg: var(--acton-steel-900); --acton-chrome-fg: var(--acton-paper); --acton-chrome-muted: var(--acton-steel-300); --acton-panel-bg: rgba(247, 248, 246, 0.94); --acton-code-bg: #f4f4f1; } .ayu, .coal, .navy { --bg: var(--acton-steel-950); --fg: #f2f3ef; --sidebar-bg: #111213; --sidebar-fg: var(--acton-steel-200); --sidebar-non-existant: #727a80; --sidebar-active: var(--acton-yellow); --sidebar-spacer: rgba(255, 255, 255, 0.12); --scrollbar: #858d92; --icons: #d7dcde; --icons-hover: #ffffff; --links: var(--acton-yellow); --inline-code-color: var(--acton-yellow); --theme-popup-bg: #111213; --theme-popup-border: rgba(255, 255, 255, 0.16); --theme-hover: rgba(255, 212, 42, 0.14); --quote-bg: rgba(255, 212, 42, 0.1); --quote-border: rgba(255, 212, 42, 0.45); --warning-border: var(--acton-yellow); --table-border-color: rgba(255, 255, 255, 0.14); --table-header-bg: var(--acton-steel-800); --table-alternate-bg: rgba(255, 255, 255, 0.04); --searchbar-border-color: rgba(255, 255, 255, 0.18); --searchbar-bg: #111213; --searchbar-fg: var(--acton-paper); --searchbar-shadow-color: rgba(255, 212, 42, 0.34); --searchresults-header-fg: var(--acton-steel-300); --searchresults-border-color: rgba(255, 255, 255, 0.14); --searchresults-li-bg: var(--acton-steel-800); --search-mark-bg: #5d4810; --color-scheme: dark; --copy-button-filter: invert(87%) sepia(8%) saturate(126%) hue-rotate(164deg) brightness(102%) contrast(90%); --copy-button-filter-hover: invert(82%) sepia(80%) saturate(811%) hue-rotate(340deg) brightness(103%) contrast(102%); --footnote-highlight: #5d4810; --overlay-bg: rgba(0, 0, 0, 0.42); --acton-chrome-bg: #111213; --acton-chrome-fg: var(--acton-paper); --acton-chrome-muted: var(--acton-steel-300); --acton-panel-bg: rgba(32, 35, 38, 0.9); --acton-code-bg: #1a1c1d; } @media (prefers-color-scheme: dark) { html:not(.js) { --bg: var(--acton-steel-950); --fg: #f2f3ef; --sidebar-bg: #111213; --sidebar-fg: var(--acton-steel-200); --sidebar-active: var(--acton-yellow); --theme-popup-bg: #111213; --quote-bg: rgba(255, 212, 42, 0.1); --quote-border: rgba(255, 212, 42, 0.45); --table-border-color: rgba(255, 255, 255, 0.14); --table-header-bg: var(--acton-steel-800); --table-alternate-bg: rgba(255, 255, 255, 0.04); --color-scheme: dark; --acton-chrome-bg: #111213; --acton-chrome-fg: var(--acton-paper); --acton-chrome-muted: var(--acton-steel-300); --acton-panel-bg: rgba(32, 35, 38, 0.9); --acton-code-bg: #1a1c1d; } } html { background: var(--bg); } .page-wrapper { min-height: 100vh; background-color: var(--bg); background-image: linear-gradient(120deg, rgba(255, 212, 42, 0.08), transparent 28rem); background-repeat: no-repeat; background-size: 100% 100vh; } #menu-bar { align-items: center; background: var(--acton-chrome-bg); border-block-end-color: rgba(255, 255, 255, 0.12); color: var(--acton-chrome-muted); flex-wrap: nowrap; } #menu-bar.bordered { border-block-end-color: rgba(255, 255, 255, 0.18); } .menu-bar, .menu-bar:visited, .menu-bar .icon-button, .menu-bar a i { color: var(--acton-chrome-muted); } .menu-bar i:hover, .menu-bar .icon-button:hover { color: var(--acton-chrome-fg); } .menu-title { color: var(--acton-chrome-fg); min-width: 0; font-weight: 700; letter-spacing: -0.03em; } .left-buttons { align-self: stretch; align-items: center; } .right-buttons { display: flex; align-items: center; align-self: stretch; margin: 0 15px 0 0; } .sidebar { top: var(--menu-bar-height); border-inline-end: 1px solid rgba(255, 255, 255, 0.12); z-index: 100; } #sidebar-toggle-anchor:not(:checked) ~ .sidebar { z-index: 100; pointer-events: none; } #sidebar-toggle-anchor:checked ~ .page-wrapper { margin-inline-start: 0 !important; transform: none !important; } [dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper { margin-inline-end: 0 !important; transform: none !important; } @media only screen and (min-width: 620px) { #sidebar-toggle-anchor:checked ~ .page-wrapper .content { margin-inline-start: calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width)); } } @media only screen and (max-width: 980px) { .menu-title { text-align: start; } } @media only screen and (max-width: 760px) { .menu-title { display: none; } } .sidebar a:hover, .sidebar a.active { color: var(--acton-yellow); } .content main { padding-top: 1rem; } pre { background: var(--acton-code-bg); border: 1px solid var(--table-border-color); border-left: 4px solid var(--acton-yellow); border-radius: 8px; } pre > code, pre > code.hljs { background: transparent; } :not(pre):not(a) > .hljs { border-radius: 0.28em; padding: 0.1em 0.28em; background: rgba(255, 212, 42, 0.16); } .theme-popup { color: var(--acton-chrome-fg); box-shadow: 0 18px 45px rgba(0, 0, 0, 0.22); } .theme-popup .theme { min-width: 132px; } ================================================ FILE: docs/acton-guide/theme/acton-theme.js ================================================ // Keep mdBook's theme menu focused on the Acton visual themes. (function() { const THEME_LABELS = { default_theme: "Auto", light: "Acton Light", ayu: "Acton Dark" }; const LEGACY_THEME_MAP = { rust: "light", coal: "ayu", navy: "ayu" }; function migrateLegacyTheme() { const saved = localStorage.getItem("mdbook-theme"); const replacement = LEGACY_THEME_MAP[saved]; if (replacement) { localStorage.setItem("mdbook-theme", replacement); document.documentElement.classList.remove(saved); document.documentElement.classList.add(replacement); } } function movePrintControl() { const leftButtons = document.querySelector(".menu-bar .left-buttons"); const printButton = document.getElementById("print-button"); const printLink = printButton ? printButton.closest("a") : null; if (!leftButtons || !printLink || printLink.parentElement === leftButtons) { return; } printLink.classList.add("acton-print-control"); leftButtons.appendChild(printLink); } function pruneThemeMenu() { const themeList = document.getElementById("theme-list"); if (!themeList) { return; } for (const button of themeList.querySelectorAll("button.theme")) { const label = THEME_LABELS[button.id]; const item = button.closest("li"); if (!label) { if (item) { item.remove(); } continue; } button.textContent = label; } } function initialize() { migrateLegacyTheme(); movePrintControl(); pruneThemeMenu(); } initialize(); document.addEventListener("DOMContentLoaded", initialize); })(); ================================================ FILE: docs/acton-guide/theme/content-width.css ================================================ /* Wider content area for better side-by-side code display */ /* Increase main content width and center it */ .content main { max-width: 900px !important; margin: 0 auto !important; padding: 0 15px; } /* Wider content on larger screens */ @media (min-width: 1200px) { .content main { max-width: 950px !important; } } @media (min-width: 1400px) { .content main { max-width: 1000px !important; } } @media (min-width: 1600px) { .content main { max-width: 1050px !important; } } /* Make code blocks in side-by-side tables use available space better */ .side-by-side-code td:first-child { width: 35%; /* Explanations/comments column */ } .side-by-side-code td:last-child { width: 65%; /* Code column - more space for code */ } /* Adjust pre/code blocks to not add unnecessary padding in tables */ .side-by-side-code pre { margin: 0; padding: 10px; } .side-by-side-code td { padding: 12px; } /* For very wide screens, cap the side-by-side table width for readability */ @media (min-width: 1600px) { .side-by-side-code { max-width: 1400px; margin-left: auto; margin-right: auto; } } ================================================ FILE: docs/acton-guide/theme/detail-toggles.css ================================================ /* Detail-level controls for the Acton Guide */ .skill-control-menu { display: inline-flex; align-items: center; margin-left: 8px; } .detail-toggle-wrapper { display: inline-flex; align-items: center; gap: 8px; } .detail-toggle { display: inline-flex; align-items: center; justify-content: center; gap: 7px; min-height: 28px; padding: 0 12px; border-radius: 999px; border: 1px solid var(--table-border-color); background: var(--bg); color: var(--fg); cursor: pointer; user-select: none; white-space: nowrap; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, opacity 0.15s ease; } .detail-toggle:hover { opacity: 0.92; } .detail-toggle:focus-visible { outline: 2px solid var(--icons); outline-offset: 2px; } .detail-toggle-indicator { position: relative; display: inline-block; width: 15px; height: 15px; border-radius: 999px; border: 1px solid currentColor; flex: 0 0 15px; } .detail-toggle-indicator::before { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; font-weight: 700; } .detail-toggle[aria-pressed="false"] .detail-toggle-indicator::before { content: ""; width: 5px; height: 5px; inset: 50% auto auto 50%; border-radius: 999px; background: currentColor; opacity: 0.45; transform: translate(-50%, -50%); } .detail-toggle[aria-pressed="true"] .detail-toggle-indicator::before { content: "✓"; } .detail-toggle-beginner { background: rgba(76, 175, 80, 0.08); border-color: rgba(76, 175, 80, 0.55); color: #2e7d32; } .detail-toggle-advanced { background: rgba(33, 150, 243, 0.08); border-color: rgba(33, 150, 243, 0.55); color: #1565c0; } .detail-toggle-beginner.is-active, .detail-toggle-beginner[aria-pressed="true"] { background: rgba(76, 175, 80, 0.2); border-color: #4caf50; color: #2e7d32; box-shadow: inset 0 0 0 1px rgba(76, 175, 80, 0.12); } .detail-toggle-advanced.is-active, .detail-toggle-advanced[aria-pressed="true"] { background: rgba(33, 150, 243, 0.2); border-color: #2196f3; color: #1565c0; box-shadow: inset 0 0 0 1px rgba(33, 150, 243, 0.12); } .ayu .detail-toggle-beginner, .coal .detail-toggle-beginner, .navy .detail-toggle-beginner { color: #7bd67f; } .ayu .detail-toggle-advanced, .coal .detail-toggle-advanced, .navy .detail-toggle-advanced { color: #78c4ff; } .ayu .detail-toggle-beginner.is-active, .coal .detail-toggle-beginner.is-active, .navy .detail-toggle-beginner.is-active, .ayu .detail-toggle-beginner[aria-pressed="true"], .coal .detail-toggle-beginner[aria-pressed="true"], .navy .detail-toggle-beginner[aria-pressed="true"] { color: #7bd67f; } .ayu .detail-toggle-advanced.is-active, .coal .detail-toggle-advanced.is-active, .navy .detail-toggle-advanced.is-active, .ayu .detail-toggle-advanced[aria-pressed="true"], .coal .detail-toggle-advanced[aria-pressed="true"], .navy .detail-toggle-advanced[aria-pressed="true"] { color: #78c4ff; } @media (max-width: 700px) { .skill-control-menu { margin-right: 6px; } .detail-toggle-wrapper { gap: 6px; } .detail-toggle { gap: 6px; min-height: 24px; padding: 0 10px; font-size: 10px; letter-spacing: 0.35px; } .detail-toggle-indicator { width: 13px; height: 13px; flex-basis: 13px; font-size: 9px; } } /* Content visibility based on selected detail toggles */ .beginner-content, .advanced-content { display: none; margin: 0; padding: 0; border: 0; } body[data-show-beginner="true"] .beginner-content { display: block; margin: 15px 0; } body[data-show-advanced="true"] .advanced-content { display: block; margin: 15px 0; } .beginner-inline, .advanced-inline { display: none; } body[data-show-beginner="true"] .beginner-inline { display: inline; } body[data-show-advanced="true"] .advanced-inline { display: inline; } .beginner-content { background: rgba(76, 175, 80, 0.1); border-left: 4px solid #4caf50; padding: 15px; margin: 15px 0; border-radius: 0 4px 4px 0; } .advanced-content { background: rgba(33, 150, 243, 0.1); border-left: 4px solid #2196f3; padding: 15px; margin: 15px 0; border-radius: 0 4px 4px 0; } .beginner-content::before { content: "Beginner"; display: block; font-weight: bold; margin-bottom: 10px; color: #4caf50; } .advanced-content::before { content: "Advanced"; display: block; font-weight: bold; margin-bottom: 10px; color: #2196f3; } /* Enhanced side-by-side code table */ .side-by-side-code { width: 100%; border-collapse: collapse; margin: 25px 0; background: transparent; border-radius: 0; overflow: visible; box-shadow: none; } .side-by-side-code td { padding: 20px; vertical-align: top; border-bottom: 1px solid var(--table-border-color); } .side-by-side-code tr:last-child td { border-bottom: none; } .side-by-side-code td:first-child { width: 35%; background: var(--sidebar-bg); border-right: 1px solid var(--table-border-color); font-size: 0.95em; line-height: 1.7; color: var(--fg); } .side-by-side-code td:last-child { width: 65%; background: var(--code-bg); } .side-by-side-code pre { margin: 0; background: transparent; padding: 0; } .side-by-side-code code { font-size: 0.9em; } @media (max-width: 768px) { .side-by-side-code td { display: block; width: 100% !important; } .side-by-side-code td:first-child { border-right: none; border-bottom: 1px solid var(--table-border-color); } .side-by-side-code tr:last-child td:first-child { border-bottom: 1px solid var(--table-border-color); } } .ayu .side-by-side-code td:first-child, .coal .side-by-side-code td:first-child, .navy .side-by-side-code td:first-child { background: rgba(0, 0, 0, 0.2); } ================================================ FILE: docs/acton-guide/theme/detail-toggles.js ================================================ // Detail-level toggles for the Acton Guide (function() { const DEFAULT_PREFERENCES = { beginner: false, advanced: false }; const STORAGE_KEY = "acton-docs-detail-preferences"; const LEGACY_STORAGE_KEY = "acton-docs-skill-level"; function normalizePreferences(value) { return { beginner: Boolean(value && value.beginner), advanced: Boolean(value && value.advanced) }; } function migrateLegacyPreference() { const saved = localStorage.getItem(LEGACY_STORAGE_KEY); if (!saved) { return null; } const level = parseInt(saved, 10); if (level === 1) { return { beginner: true, advanced: false }; } if (level === 3) { return { beginner: false, advanced: true }; } return { beginner: false, advanced: false }; } function loadPreferences() { const saved = localStorage.getItem(STORAGE_KEY); if (saved) { try { return normalizePreferences(JSON.parse(saved)); } catch (_error) { // Fall through to defaults and legacy migration. } } const migrated = migrateLegacyPreference(); if (migrated) { savePreferences(migrated); return migrated; } return { ...DEFAULT_PREFERENCES }; } function savePreferences(preferences) { localStorage.setItem( STORAGE_KEY, JSON.stringify(normalizePreferences(preferences)) ); } function applyPreferences(preferences) { const normalized = normalizePreferences(preferences); document.body.setAttribute( "data-show-beginner", normalized.beginner ? "true" : "false" ); document.body.setAttribute( "data-show-advanced", normalized.advanced ? "true" : "false" ); } function syncControls(preferences) { const beginnerToggle = document.getElementById("toggleBeginnerDetails"); const advancedToggle = document.getElementById("toggleAdvancedDetails"); if (beginnerToggle) { beginnerToggle.setAttribute( "aria-pressed", preferences.beginner ? "true" : "false" ); beginnerToggle.classList.toggle("is-active", preferences.beginner); } if (advancedToggle) { advancedToggle.setAttribute( "aria-pressed", preferences.advanced ? "true" : "false" ); advancedToggle.classList.toggle("is-active", preferences.advanced); } } function currentPreferences() { return { beginner: document.body.getAttribute("data-show-beginner") === "true", advanced: document.body.getAttribute("data-show-advanced") === "true" }; } function updatePreferences(preferences) { const normalized = normalizePreferences(preferences); applyPreferences(normalized); syncControls(normalized); savePreferences(normalized); } function createDetailControls() { const widget = document.createElement("div"); widget.className = "skill-control-menu"; widget.setAttribute("aria-label", "Documentation detail toggles"); widget.innerHTML = `
    `; return widget; } function attachListeners() { const beginnerToggle = document.getElementById("toggleBeginnerDetails"); const advancedToggle = document.getElementById("toggleAdvancedDetails"); if (beginnerToggle && !beginnerToggle.dataset.bound) { beginnerToggle.addEventListener("click", () => { updatePreferences({ ...currentPreferences(), beginner: !currentPreferences().beginner }); }); beginnerToggle.dataset.bound = "true"; } if (advancedToggle && !advancedToggle.dataset.bound) { advancedToggle.addEventListener("click", () => { updatePreferences({ ...currentPreferences(), advanced: !currentPreferences().advanced }); }); advancedToggle.dataset.bound = "true"; } } function initialize() { const preferences = loadPreferences(); applyPreferences(preferences); const menuBar = document.querySelector(".menu-bar"); if (!menuBar) { return; } const leftButtons = menuBar.querySelector(".left-buttons"); if (!leftButtons) { return; } if (!document.querySelector(".skill-control-menu")) { const widget = createDetailControls(); leftButtons.appendChild(widget); } syncControls(preferences); attachListeners(); } function handlePageChange() { setTimeout(initialize, 100); } document.addEventListener("DOMContentLoaded", initialize); let lastUrl = location.href; new MutationObserver(() => { const url = location.href; if (url !== lastUrl) { lastUrl = url; handlePageChange(); } }).observe(document, { subtree: true, childList: true }); window.addEventListener("popstate", handlePageChange); })(); ================================================ FILE: docs/acton-guide/theme/guide-links.css ================================================ /* Cross-site navigation for the Acton Guide */ .acton-site-links { display: inline-flex; align-items: stretch; align-self: stretch; gap: 2px; } .acton-site-link { position: relative; display: inline-flex; align-items: center; min-height: var(--menu-bar-height); padding: 0 10px; color: var(--acton-yellow, var(--sidebar-active)); font-size: 12px; font-weight: 800; letter-spacing: 0.08em; text-decoration: none; text-transform: uppercase; white-space: nowrap; } .acton-site-link:hover { color: var(--acton-chrome-fg, var(--icons-hover)); text-decoration: none; } .acton-site-link::after { position: absolute; right: 10px; bottom: 0; left: 10px; height: 3px; border-radius: 999px 999px 0 0; background: transparent; content: ""; } .acton-site-link.is-active { color: var(--acton-chrome-fg, var(--fg)); } .acton-site-link.is-active::after { background: var(--acton-yellow, var(--sidebar-active)); } @media (max-width: 780px) { .acton-site-links { margin-left: 4px; margin-right: 8px; } .acton-site-link { padding: 0 7px; font-size: 11px; letter-spacing: 0.05em; } .acton-site-link::after { right: 7px; left: 7px; } } @media (max-width: 600px) { .acton-site-links { display: none; } } ================================================ FILE: docs/acton-guide/theme/guide-links.js ================================================ // Cross-site navigation for the Acton Guide. (function() { const SITES = [ { label: "Guide", href: "https://acton.guide/", active: true }, { label: "Play", href: "https://play.acton.guide/" }, { label: "Ask", href: "https://ask.acton.guide/" } ]; function createGuideLinks() { const nav = document.createElement("nav"); nav.className = "acton-site-links"; nav.setAttribute("aria-label", "Acton sites"); for (const site of SITES) { const link = document.createElement("a"); link.className = "acton-site-link"; link.href = site.href; link.textContent = site.label; if (site.active) { link.classList.add("is-active"); link.setAttribute("aria-current", "page"); } nav.appendChild(link); } return nav; } function initialize() { const menuBar = document.querySelector(".menu-bar"); const rightButtons = menuBar ? menuBar.querySelector(".right-buttons") : null; if (!menuBar || !rightButtons || document.querySelector(".acton-site-links")) { return; } const guideLinks = createGuideLinks(); rightButtons.appendChild(guideLinks); } function handlePageChange() { setTimeout(initialize, 100); } document.addEventListener("DOMContentLoaded", initialize); let lastUrl = location.href; new MutationObserver(() => { const url = location.href; if (url !== lastUrl) { lastUrl = url; handlePageChange(); } }).observe(document, { subtree: true, childList: true }); window.addEventListener("popstate", handlePageChange); })(); ================================================ FILE: docs/acton-guide/theme/sbscode.css ================================================ /* Custom table styling for side-by-side documentation */ .content table.side-by-side-code { display: table; width: 100%; margin: 0; border-collapse: collapse; border: none; background: none; table-layout: fixed; } /* Dark theme support */ .rust.light-theme .content table.side-by-side-code td:last-child { background: var(--quote-bg); } .rust.dark-theme .content table.side-by-side-code td:last-child { background: var(--quote-bg); } /* Ensure button contrast in both themes */ .rust.light-theme .content table.side-by-side-code .buttons { background: var(--bg); color: var(--fg); } .rust.dark-theme .content table.side-by-side-code .buttons { background: var(--bg); color: var(--fg); } /* Remove default mdBook table styling */ .content table.side-by-side-code tbody tr { background: none !important; border: none; } .content table.side-by-side-code td { border: none; padding: 0.5rem; vertical-align: top; } /* Left column (prose) styling */ .content table.side-by-side-code td:first-child { width: 35%; padding-right: 1.5rem; color: var(--fg); } /* Right column (code) styling */ .content table.side-by-side-code td:last-child { width: 65%; background: var(--quote-bg); border-radius: 0; } /* Round only the top corners of the first row's code cell */ .content table.side-by-side-code tr:first-child td:last-child { border-top-left-radius: 4px; border-top-right-radius: 4px; } /* Round only the bottom corners of the last row's code cell */ .content table.side-by-side-code tr:last-child td:last-child { border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } /* Hide mdBook's default copy buttons in our special tables */ .content table.side-by-side-code pre > .buttons { display: none !important; } /* Code block styling */ .content table.side-by-side-code td pre { margin: 0; padding: 0.5rem; background: none; } .content table.side-by-side-code td code { background: none; padding: 0; } /* Ensure continuous code blocks */ .content table.side-by-side-code tr + tr td:last-child { padding-top: 0; } /* Hide empty prose cells */ .content table.side-by-side-code td:first-child:empty { padding: 0; border: none; } /* Position the buttons container */ .content table.side-by-side-code td:last-child { position: relative; } /* Keep original mdBook button styling for our custom button */ .content table.side-by-side-code .buttons { position: absolute; top: 0.5rem; right: 0.5rem; opacity: 0; transition: opacity 0.2s; } .content table.side-by-side-code:hover .buttons { opacity: 1; } ================================================ FILE: docs/acton-guide/theme/sbscode_copy.js ================================================ document.addEventListener('DOMContentLoaded', () => { // Select all side-by-side-code tables const codeTables = document.querySelectorAll('table.side-by-side-code'); codeTables.forEach(table => { // Get all code cells in this table const codeCells = table.querySelectorAll('td:last-child'); if (codeCells.length === 0) return; // Create button container div const buttonDiv = document.createElement('div'); buttonDiv.className = 'buttons'; // Create copy button with mdBook's styling const copyButton = document.createElement('button'); copyButton.className = 'fa fa-copy clip-button'; copyButton.setAttribute('title', 'Copy to clipboard'); copyButton.setAttribute('aria-label', 'Copy to clipboard'); // Add tooltip span const tooltip = document.createElement('i'); tooltip.className = 'tooltiptext'; copyButton.appendChild(tooltip); // Get all code blocks from all cells in this table const getAllCode = () => { const allCodeBlocks = table.querySelectorAll('td:last-child pre code'); return Array.from(allCodeBlocks) .map(block => block.textContent) .join('\n'); }; // Add click handler copyButton.addEventListener('click', async () => { const code = getAllCode(); await navigator.clipboard.writeText(code); // Visual feedback using tooltip tooltip.textContent = 'Copied!'; setTimeout(() => { tooltip.textContent = ''; }, 2000); }); // Add the button to the container and container to the first code cell buttonDiv.appendChild(copyButton); codeCells[0].appendChild(buttonDiv); }); }); ================================================ FILE: docs/acton-guide/theme/tabs.css ================================================ .mdbook-tabs { display: flex; } .mdbook-tab { background-color: var(--table-alternate-bg); padding: 0.5rem 1rem; cursor: pointer; border: none; font-size: 1.6rem; line-height: 1.45em; } .mdbook-tab.active { background-color: var(--table-header-bg); font-weight: bold; } .mdbook-tab-content { padding: 1rem 0rem; } .mdbook-tab-content table { margin: unset; } ================================================ FILE: docs/acton-guide/theme/tabs.js ================================================ /** * Change active tab of tabs. * * @param {Element} container * @param {string} name */ const changeTab = (container, name) => { for (const child of container.children) { if (!(child instanceof HTMLElement)) { continue; } if (child.classList.contains('mdbook-tabs')) { for (const tab of child.children) { if (!(tab instanceof HTMLElement)) { continue; } if (tab.dataset.tabname === name) { tab.classList.add('active'); } else { tab.classList.remove('active'); } } } else if (child.classList.contains('mdbook-tab-content')) { if (child.dataset.tabname === name) { child.classList.remove('hidden'); } else { child.classList.add('hidden'); } } } }; document.addEventListener('DOMContentLoaded', () => { const tabs = document.querySelectorAll('.mdbook-tab'); for (const tab of tabs) { tab.addEventListener('click', () => { if (!(tab instanceof HTMLElement)) { return; } if (!tab.parentElement || !tab.parentElement.parentElement) { return; } const container = tab.parentElement.parentElement; const name = tab.dataset.tabname; const global = container.dataset.tabglobal; changeTab(container, name); if (global) { localStorage.setItem(`mdbook-tabs-${global}`, name); const globalContainers = document.querySelectorAll( `.mdbook-tabs-container[data-tabglobal="${global}"]` ); for (const globalContainer of globalContainers) { changeTab(globalContainer, name); } } }); } const containers = document.querySelectorAll('.mdbook-tabs-container[data-tabglobal]'); for (const container of containers) { const global = container.dataset.tabglobal; const name = localStorage.getItem(`mdbook-tabs-${global}`); if (name && document.querySelector(`.mdbook-tab[data-tabname=${name}]`)) { changeTab(container, name); } } }); ================================================ FILE: docs/dev.md ================================================ # Development Workflow n stuff ## Changelog We keep a `CHANGELOG.md`. It is good practice for PRs to contain a changelog entry for whatever they are updating. This is often forgotten and so in practice, we often update `CHANGELOG.md` in batches. When making a release, carefully inspect the git log and update `CHANGELOG.md` accordingly. Match the style and tone in `CHANGELOG.md`. For long descriptive git commit messages or whole branches with multiple commits, write a shorter summary. If the git commit messages are very brief, inspect the code and attempt to sum it up. ## Git workflow - authoritative git repository is https://github.com/actonlang/acton - git clone git@github.com:actonlang/acton.git - `main` is the main branch - the `main` branch is protected, meaning no one can directly push commits to it - commits should happen on a branch, from which a Pull Request (PR) is created - the PR can then be merged to `main` via GitHub - all PRs should contain a changelog entry in `CHANGELOG.md` under the `Unreleased` heading - this is later used as the body of the release ## Release workflow There are two types of releases, "version releases" and the `tip` release. ### Versioned release - this is like version `1.2.3` - create a new branch called `release-v` followed by the version number, like `release-v1.2.3` - prepare `CHANGELOG.md` by placing the content currently under the `Unreleased` heading under a version number, like version `1.2.3` instead - push branch to GitHub and open PR - once the PR is merged, a GitHub Action workflow will take over, create a tag and proceed to build the final release build and upload as an artifact - it will take the content from `CHANGELOG.md` and use as the GitHub Release notes - artifacts from the CI test jobs will be included in the Release as assets - the Release is published at https://github.com/actonlang/acton/releases ### `tip` release - this is the binary output from the last successful CI job on the `main` branch - somewhat like a nightly, just more frequent or less - depends on if there is new content on the `main` branch or not - `tip` will identify themselves with the base version number and the date and time when it was built - for example, if v0.4.0 was the last versioned release and a nightly is built, it would be called 0.4.0.2021.08.05.09.27.14, i.e. it was built at 09:27:14 on the 5th of August 2021 - this is automatically built for every merge on `main`, no extra action is required - the output is stored as a pre-release in Github called `tip` - new releases will overwrite older ones, i.e. only the latest build will be available - the release has a stable URL: https://github.com/actonlang/acton/releases/tag/tip ================================================ FILE: docs/git-develop-workflow.md ================================================ # Git Workflow for the `develop` branch The Acton repository primarily adheres to the triangular git workflow, where feature branches are used to introduce all changes and these are merged to the main branch through Pull Requests (PRs). The `develop` branch is an exception. It is not a feature branch, rather it is long lived. Development happens there for improvements to the compiler and other parts that might not be ready to merge in standalone and where it is still useful for others to be able to see (and test) these improvements. Long lived branches come with certain challenges, in particular how to keep it up to date with the `main` branch. Here's a quick cheat sheet: ## Merging things on `develop` branch to `main` - Before attempting to merge in the commits on `develop` into `main`, it is a good idea to ensure it is up to date with the `main` branch - We accomplish this through **rebasing**. - First we have to make sure the local `main` branch is up to date with the remote at GitHub. - After rebase, we need to force push (since we have rewritten the git log). - There might be conflicts during rebasing that need to be sorted out manually. ``` git checkout main git pull git checkout develop git rebase main # maybe sort out conflicts git push --force develop ``` - Open a Pull Request on GitHub to merge `develop` into `main` - GitHub CI tests will run for the `develop` branch on GitHub and if it passes, the PR can be merged - If tests do not pass, chances are there is a test that needs to be marked as not failing anymore or similar. Check CI test output or try running tests locally! - If GitHub says there are conflicts during merge, do NOT attempt to solve them in the web browser. Abort! - Instead, repeat the above procedure. Ensure that you pull the main branch so your local branch is up to date with the remove! - There is an option in the PR merge to remove the `develop` branch - deselect this option since we want the `develop` branch to remain. ## Updating local `develop` branch from GitHub remote If person #1 runs the above workflow of rebasing the `develop` branch on `main` in order to bring it up to date, then others who use the `develop` branch will need to update it as well. Since git history has been rewritten, some extra steps need to be taken. - Ensure git merge only accepts fast forward merges! - This ensures linear history on `develop` by avoiding merge commits - Do this by adding config to your `~/.gitconfig`: ``` [pull] ff = only ``` - To update your local `develop` branch with the remotes: ``` git checkout develop git pull --rebase --force ``` - Any local commits not yet pushed will be rebased upon the remote changes, after this you can push them to the remote with: `git push` ================================================ FILE: docs/git-feature-workflow.md ================================================ # Git Workflow for feature branches The Acton repository primarily adheres to the triangular git workflow, where feature branches are used to introduce all changes and these are merged to the main branch through Pull Requests (PRs). Feature branches are well suited to small fixes and well scoped out features where we know about the scope up front. ## Starting work on a new feature / bug fix - You should branch out your feature branch from the `main` branch - First ensure your local `main` branch is up to date with the remote - Give your branch a good name - If there is a GitHub issue for it, you can use the issue number as the prefix, like if you are fixing a bug described in issue #1337, the branch can be called `1337-fix-foobar-bug` - Don't sweat it too much, you can always rename the branch later - to rename, checkout the feature branch, then do `git branch -m 1337-fix-blargh-bug` to rename Branch out feature branch: ``` git checkout main git pull git checkout -b 1337-fix-foobar-bug # do some changes git commit ... git push -u origin 1337-fix-foobar-bug ``` - Open a Pull Request on GitHub to merge your feature branch into `main` - GitHub CI tests will run for the branch on GitHub and if it passes, the PR can be merged - If tests do not pass, chances are there is a test that needs to be marked as not failing anymore or similar. Check CI test output or try running tests locally! - If GitHub says there are conflicts during merge, do NOT attempt to solve them in the web browser. Abort! - Fix conflicts by rebasing your feature branch on main, see below. ## Rebasing your local feature branch - If the `main` branch has had updates since you branched out your feature branch, you might get a conflict when trying to merge your feature branch back into `main` - Fix this by rebasing your feature branch on the new main ``` git checkout main git pull git checkout 1337-fix-foobar-bug git rebase main # sort out potential conflicts git push --force origin 1337-fix-foobar-bug ``` The last step of pushing the branch is sort of optional, but if you have already opened a PR as per the above workflow, then you will need to use `--force` when pushing after a rebase, since you have rewritten git history. ## Cleaning up old local feature branches Once you have merged your feature branch(es) upstream, you can remove them locally. First we pull down the `main` branch to ensure we see if things are merged. We use `--prune` which also updates information about remote branches and in particular, will remove (prune!) them if they no longer exist. ``` git checkout main git pull --prune origin ``` Now you can go through your branches and remove them with `git branch -d 1337-fix-foobar-bug`. If the branch is fully merged to `main`, there won't be any output, like so: ``` kll@Boxy:~/terastream/acton$ git branch -d regression-actor-method-call-not-async Deleted branch regression-actor-method-call-not-async (was 1a34a28). kll@Boxy:~/terastream/acton$ ``` If the branch is not merged to `main` nor pushed to the remote, an error is raised: ``` kll@Boxy:~/terastream/acton$ git branch -d add-git-develop-workflow-cheat-sheet error: The branch 'add-git-develop-workflow-cheat-sheet' is not fully merged. If you are sure you want to delete it, run 'git branch -D add-git-develop-workflow-cheat-sheet'. kll@Boxy:~/terastream/acton$ ``` If the branch is pushed to the remote but not yet merged to main, a warning will be emitted: ``` kll@Boxy:~/terastream/acton$ git branch -d warnings-as-errors warning: deleting branch 'warnings-as-errors' that has been merged to 'refs/remotes/origin/warnings-as-errors', but not yet merged to HEAD. Deleted branch warnings-as-errors (was 60703e6). kll@Boxy:~/terastream/acton$ ``` You can then "undo" the branch removal by checking it out again, which will default to checking out what exists on the remote: ``` kll@Boxy:~/terastream/acton$ git checkout warnings-as-errors Branch 'warnings-as-errors' set up to track remote branch 'warnings-as-errors' from 'origin'. Switched to a new branch 'warnings-as-errors' kll@Boxy:~/terastream/acton$ ``` ================================================ FILE: docs/run-example.py ================================================ #!/usr/bin/env python3 """Script to run Acton examples embedded in Markdown and update output Will find first source code example, run it and insert the output back into the Markdown file. The document is expected to contain """ import argparse import os import re import subprocess import tempfile import time # TODO: This is the name of the language for the src block in the markdown file. # It should really be acton, but we don't get syntax hilighting with that # (nothing supports that), so using python for now SRCNAME='python' def run_cmd(workdir, cmd): current_dir = os.getcwd() acton = os.path.join(current_dir, "../dist/bin/acton") # Run acton in the specified working directory os.environ["PATH"] = os.path.join(current_dir, "../dist/bin") + ":" + os.getenv("PATH") cp = subprocess.run(cmd, shell=True, cwd=workdir, capture_output=True, text=True) # filter out color codes output = re.sub(r'\x1b\[[0-9;]*m', '', cp.stdout) output = re.sub(r'Building project in .*', 'Building project in /home/user/foo', output) return output def run(source, cmd=None): cmd = cmd or "acton build && out/bin/example" with tempfile.TemporaryDirectory() as tmpdirname: print(f"Got a temp dir: {tmpdirname}") try: run_cmd(tmpdirname, "acton new example") # stupid hack to get around some bug on macos where the newly # created directory (by acton) is not visible to us, how? time.sleep(0.1) source_file = open(tmpdirname + "/example/src/example.act", "w") source_file.write(source) source_file.close() output = run_cmd(os.path.join(tmpdirname, "example"), cmd) return output except Exception as exc: print(exc) print(f"ERROR, check {tmpdirname}") time.sleep(60) def get_source_from_md(content): """Extract Acton source code from Markdown document We just get the first source block and it should look like: Source: ```acton actor main.... ``` The starting "Source:" line is significant. The source block should immediately follow it. """ look_for = '^Source:$' source = "" filename = None for line in content: if look_for == '^Source:$' and re.search(look_for, line): look_for = f"^```{SRCNAME}" continue if look_for == f"^```{SRCNAME}": if not re.search(look_for, line): raise ValueError(f"Didn't find source block, ```{SRCNAME} should follow the Source: line") m = re.match(r"^```{SRCNAME} (.+)$", line) if m: filename = m.group(1) look_for = '^```$' continue if look_for == "^```$": if re.search(look_for, line): return source, filename source += line if look_for == '^Source:$': raise ValueError("Didn't find source block, missing 'Source:' line") def get_run_from_md(content): """Extract Acton source code from Markdown document We just get the first run block and it should look like: Run: ```sh acton test ``` """ look_for = '^Run:$' source = "" for line in content: if look_for == '^Run:$' and re.search(look_for, line): look_for = f"^```sh$" continue if look_for == f"^```sh$": if not re.search(look_for, line): raise ValueError(f"Didn't find source block, ```{SRCNAME} should follow the Source: line") look_for = '^```$' continue if look_for == "^```$": if re.search(look_for, line): return source source += line def write_output_to_md_content(output, md_content): new = "" look_for = '^Output:$' for line in md_content: if look_for == '^Output:$': new += line if re.search(look_for, line): look_for = "^```sh$" continue elif look_for == "^```sh$": new += line if not re.search(look_for, line): raise ValueError("Didn't find output block, ```sh should follow the Output: line") new += output look_for = '^```$' continue elif look_for == "^```$": if re.search(look_for, line): new += line look_for = None continue elif look_for is None: new += line if look_for == '^Output:$': raise ValueError("Didn't find output block, missing 'Output:' line") return new def write_md(fn, content): with open(fn, "w") as f: f.write(content) def process(md): f = open(md, "r") md_content = f.readlines() f.close() #print("MARKDOWN:") #print("----------------------------------------------------") #print("".join(md_content)) #print("----------------------------------------------------") source, src_file = get_source_from_md(md_content) cmd = get_run_from_md(md_content) #print("SOURCE:") #print(source) output = run(source, cmd) #print("OUTPUT:") #print(output) new_md = write_output_to_md_content(output, md_content) print("NEW MARKDOWN:") print("----------------------------------------------------") print("".join(new_md)) print("----------------------------------------------------") write_md(md, new_md) if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("md", nargs="+") args = parser.parse_args() for md in args.md: process(md) ================================================ FILE: docs/triage.md ================================================ # Bug triage and prioritization This isn't some hard line policy but rather a softer guideline on how to think with regards to triaging and prioritizing of bugs in Acton. - silent errors - we prioritize silent errors over those that emit explicit error messages - for example, there was a bug that cause integer subtraction to give the wrong results; 5-1 = 3 and stuff like that - debugging this program is harder than when presented an explicit error - seg faults - this causes a general feeling of brokenness and without a descriptive error message, it is rather difficult to work around - things without workarounds - with type errors it is often possible to work around by adding type signatures or explicit type conversions, thus they have lower priority compared to bugs that are not as simple to work around - other bugs ================================================ FILE: docs/tutorial/README.md ================================================ # Acton tutorial ## Introduction Acton is a general purpose programming language, designed to be useful for a wide range of applications, from desktop applications to embedded and distributed systems. In a first approximation Acton can be described as a seamless addition of a powerful new construct to an existing language: Acton adds ***actors*** to ***Python***. The aim of this document is to serve as a tutorial on Acton for a reader familiar with Python. The presentation is mainly through examples, chosen to illustrate both similarities and differences between the two languages. As befits a tutorial, the examples are short and simple, but we hope that they are chosen in a way that helps the reader to see how the concepts illustrated scale to more complex situations. We also try to explain the considerations that has led the Acton designers to deviate from Python, where this is the case. However, the document is not a comprehensive description of the Acton language. In fact, both the language definition and its implementation is currently under active development, so some minor aspects of what we present here may be subject to change. We recommend the reader to [download and install Acton](https://github.com/actonlang/acton#install-acton) and to play with the examples. ## Background: Actors and Python Before we turn to examples, we briefly discuss actors and Python and the reasons for basing Acton on this foundation. * The actor model for (concurrent) computation goes back to work by Carl Hewitt around 1970 and has been influential ever since, even though its direct impact on mainstream computation has been limited. However, recent developments, where multi-core processors have become ubiquitous and cloud computing is rapidly growing in importance, have put focus on the shortcomings of mainstream tools and methodologies for concurrent programming, based on shared memory and threads, requiring synchronization and coordination using locks and similar tools. Many observers have come to the conclusion that this methodology is inadequate in the current and future computing landscape. Actors offer a promising approach to addressing this bottleneck by providing a simpler programming model. The notion of actors provides a conceptual framework, and concrete, actor-based languages and libraries take different forms. For our purposes, we think of an actor as an entity, which interacts with other actors only through message-passing. An actor may encapsulate some private state, which can be accessed and modified only through messages in its ***interface***, a description of the message forms that the actor can handle. Each actor has a ***mailbox***, i.e. a queue where incoming messages are stored, waiting to be processed. In response to receipt of a message an actor can perform some computation, send messages to other actors, create new actors and update its state. Sending a message is an asynchronous operation, i.e. the sender asks the runtime system to supply the necessary service (delivering the message in the receiver's mailbox) and can immediately proceed with its processing of the current message. The runtime system guarantees that an actor only serves one message at a time, but of course several actors may be active in parallel. Therefore, actors can be used for synchronization and coordination of concurrent activities. It turns out that this simple and intuitive construct gives great power for concurrent and distributed programming, and suggests a programming style that naturally avoids common pitfalls. At the top level, an Acton program is an ensemble of actors. In-between processing messages, actors are idle, just maintaining their state. An intuitive view of an Acton system is therefore that it alternates between being idle and being engaged in a burst of activities in response to an incoming message. So, an Acton program is a ***reactive*** system. Also this notion has recently received a lot of attention, as witnessed by the [Reactive Manifesto](https://www.reactivemanifesto.org). In some respects actors can appear to be quite similar to class instances, which also maintain an internal state that can be manipulated through method calls. However, there are also major differences. We defer a fuller discussion of this to Example 3 below. * A major design decision in Acton is therefore to adopt the actor programming model as a base for the large-scale structure of programs. It remains to embed this model in a concrete programming language, either as a library or middleware package in an existing language, or to design a new programming language. For reasons to be discussed below, Acton is a new language, but is also very closely related to Python. Python has over many years acquired a large and enthousiastic user base. Programmers appreciate its light-weight syntax based on indentation and its native support for a variety of programming styles, including imperative, functional and object-oriented idioms. Acton capitalizes on this appeal by adopting Python syntax, making Acton immediately accessible to the Python programmer for programming in the small, i.e. defining functions and classes. Part of the appeal of Python lies also in the lack of variable and type declarations, accompanied by liberal polymorphism, dynamic typing and an interactive interpreter environment. All of this enables a quick development cycle, but it also implies that many errors in Python programs are caught only at runtime. Acton follows Python in the lack of declarations (it has the same syntax!), but adopts a much stricter discipline of static checks. In particular, Acton is statically typed with an expressive type language and type inference. Also, scope rules are modified to avoid runtime errors caused by uninitialized variables. See Examples 1 and 2 for more detail. At the syntax level, the addition of actors to the Python base just means a new keyword `actor` and a new form of compound statement, `actor Name(params): suite`, similar to class and function definitions. Thus, in spite of the fact that Acton is a new language, it is sufficiently close to Python that Python programmers will comfortably transition to Acton programming. We would even dare to conjecture that programming in Acton will come more natural than use of existing libraries for programming with actors in Python. Also, many Python library packages will also be valid Acton code. For the Acton programmer, there is no notion of threads to consider and no need of locks, semaphores or other low-level synchronisation primitives. Threads enter instead at the level of the runtime system, where a thread pool works on the collection of tasks formed by idle actors with non-empty mailboxes, each thread repeatedly picking an actor/message pair and executing the actor's message-processing code. This implementation permits efficient utilization of multi-core processors. Also distribution of tasks across machines can be done transparently. The execution environment of an Acton program is also modelled by an interface similar to that of an actor, i.e. we think of the external world as an actor with which the program interacts. The interface to this exterior world can vary greatly, depending on the type of application and the computing environment, and an Acton installation may offer one or more interfaces, with supporting runtime system. ## Examples The rest of this tutorial consists of a sequence of short examples. In connection with some of them we discuss Acton design decisions and differences between Python and Acton. As will become clear from the examples, Acton is a compiled language, as C or Java. Programs are written to files which are compiled to produce executable files, which can be run. There is currently no interactive environment, where programs can be developed and tested in a read/eval/print loop. * [Hello World](example-0.md) * [Harmonic Number](example-1.md) * [Prime numbers](example-2.md) * [Actors vs Classes](example-3.md) ================================================ FILE: docs/tutorial/example-0.md ================================================ # Example 0 - Hello World We follow tradition and introduce Acton programming with the following minimal example ```py actor main(env): print("Hello, World!") ``` We already mentioned that an executing Acton program consists of a collection of interacting actors. Here we have just a single actor, which has been given the name `main`. By convention, the ***root actor*** of a system takes a parameter `env` which represents the execution environment, i.e. `env` has fields and methods for accessing command line arguments, reading from and writing to keyboard/screen and files, working with sockets etc. When the program is executed, the runtime system creates the root actor, hands it an `env` object and runs its initialization code, which here is just a single command, to print a message on screen. The careful reader may ask why `print` is not a method of `env`. The answer is that we see `print` as a useful tool for tracing program execution, and this should be possible without having to thread an `env` parameter to all subunits. To compile the program, assuming that it is saved in `world.act`, the command is ``` shell $ acton world.act --root main ``` This creates an executable file `world` in the same directory, which can be run to see the familiar message. Finally, let's modify the program to greet not the world, but a name given on the command line: ```py actor main(env): print("Hello, " + env.argv[1] + "!") ``` The field `env.argv` is the list of command line arguments (with element 0 the name of the shell command, and element 1 the first proper argument). ================================================ FILE: docs/tutorial/example-1.md ================================================ # Example 1 - Harmonic numbers Even though the top level view of an Acton program is that of a community of interacting actors, function and method definitions play major roles in a program; typically the bulk of the program text is a collection of `def`'s. Here is a simple function definition, which is valid in both Python and Acton: ```py def harmonic(n): sum = 0 for i in range(1,n+1): sum += 1/float(i) return sum ``` For a given non-negative integer argument ***n***, `harmonic(n)` computes the ***n***'th harmonic number, i.e. 1+1/2+1/3+ ... +1/***n***. We can use this definition together with a simple actor that expects the integer argument to `harmonic` on the command line: ```py actor harmonicMain(env): print(harmonic(int(argv.env[1]))) ``` We used the name `harmonicMain` for this actor just to emphasize that there is no name convention for the root actor in Acton; instead its name is given to the compiler. So to compile and run this program (saved to `harmonic.act`) we do: ```shell $ acton harmonic.act --root harmonicMain $ ./harmonic 2 1.5 $ ./harmonic 10000 9.7876 ``` Let's make the program a bit more interesting by making it interactive, repeatedly inputting an integer from the user and outputting the corresponding harmonic number. We have to change the actor: ```py actor harmonicMain2(env): def response(input): print(harmonic(int(input))) env.stdin_install(response) ``` This actor definition has two parts: first we have the definition of a local method `response`, which describes how the actor should react to one line of user `input`. Then follows the actor initialization code, which simply installs `response` as a callback in the environment. Program execution starts by running the root actor's initialization code. After that, the program is idle, waiting for user input on `stdin`. When such input arrives, the callback is executed, i.e. the input string is converted to an integer, which is given as argument to `harmonic`, the result is printed and the program is again idle. This program has obvious shortcomings: there is no prompt to the user, no check that the input is actually a string that can be converted to an integer, and no way to terminate the program except by some interrupting signal. In spite of this, we leave the program as it is, with one final note. We have implicitly assumed that both the function declaration and the actor declaration are in the same file. Of course, we could have the function declaration in a separate library file, say `functions.act`, and the actor in `main.act`. In that case, we need to add a line at the beginning of the latter file, saying ```py import functions ``` Our main reason for using function `harmonic` as an early example is not the mathematics, but to use it to discuss the different type disciplines and scope rules of the two languages. Acton adopts many static checks in order to find programming errors at compile time rather than during execution. Some readers may prefer to proceed to the next example at a first reading and come back to the following discussion later. ## Typing in Python and Acton Both Python and Acton use types as a sanity check on computations, but in very different ways. Python uses ***dynamic*** typing, i.e. type-checking occurs at runtime. All values have their type attached, and before the interpreter attempts an operation, the types of operands are checked to be compatible with the operation. To roughly see how this works, consider the call ```py harmonic(3) ``` The definition above ***binds*** the name `harmonic` to an object of type `function`. This type means only that we may use the object in a function call. Thus, parameter `n` is bound to the integer 3, and the function body is executed. 3 will be added to 1, which is fine; integer values can be added. The result is used as the second argument to `range`, which also is type-correct since the builtin function `range` has known type and expects integer arguments. In similar style types are checked at each step until we arrive at the final value 1.8333333333333333. If we instead would try to compute ```py harmonic(7.5) ``` The interpreter will happily start the computation, but stop when it sees that the value 8.5 will be used as second argument to `range`. This does not make sense, so execution is interrupted and a `TypeError` exception is raised. Acton, on the other hand, uses ***static*** typing, i.e. all types are inferred at compile time, starting from known types of all builtin functions and objects. The type inference algorithm analyzes the function definition and sees for example that `n+1` is second argument to the builtin function `range`, which in Acton has the much more informative type `(int,int) -> int`. (This is a slight simplification; `range` actually takes ***three*** integer arguments, where the optional third argument has default value 1.) Thus `n+1` must be an `int`, and hence `n` must also have type `int`. In a similar way it can conclude that the function result will be a `float`, and hence that `harmonic` has type `(int) -> float`, i.e. it is a function that takes an integer argument and produces a floating point result. We note that in a static typing discipline types are assigned to variables, not to values; type inference is done at compile time and no values are yet computed. Acton also has a much more expressive type language than Python. The more detailed type of `harmonic` in Acton makes it easy to infer already at compile time that `harmonic(7.5)` is a type error. Thus a program containing that application is rejected and we avoid a later runtime error. Static typing also implies that there is no need for type-checking at runtime. This is a minor efficiency advantage, but in addition the extensive type information available at compile time gives a strong basis for proper compilation to machine code, a move that promises major gains in execution efficiency compared to Python's interpretation model. ## Scope rules in Python and Acton To discuss this, we consider a slight variant of this function. In fact, it is an inferior version, which we show only to be able to discuss the different scope rules. ```py def harmonic2(n): if n>=0: sum = 0 for i in range(1,n+1): sum += 1/float(i) return sum ``` This code could be the result of the following misguided thinking: harmonic numbers only make sense for non-negative ***n***, so we should check for that in the function body. However, the result is that ***if*** the function is called with a negative argument, the variable `sum` has not been assigned any value before it is returned. If we try to compute `harmonic2(-1)`, the interpreter will note, before returning `sum`, that the variable is unbound and raise an `UnboundLocalError`. So, this function definition is valid Python and works as intended for non-negative arguments, but using it with a negative argument results in an exception at runtime. The reader should not be surprised to learn that this function definition is rejected by the Acton compiler. In this case the problem is not with types; instead the ***scope rules*** of Acton rule out the definition. Scope rules define where in the program text names become bound (i.e. acquire meaning) and in which part of the program these bindings are valid. In Python, since `sum` does become bound in the body (the statement `sum = 0`), the variable is, surprisingly, in scope in the ***whole function body***, also after the `if` statement, in spite of the fact that execution of the binding statement may not have been executed (which is exactly what happens when ***n*** is negative). We defer a detailed discussion of scope rules to section 3.3 below. Here we just note that in Acton `sum` will not be in scope in the `return` statement, for exactly the reasons hinted at above. In general, Acton adopts scope rules that rule out runtime errors because of unassigned variables. The problem with `harmonic2` can be fixed by moving the initialisation of `sum` to before the `if` statement, by adding an `else` clause that also declares `sum` or, preferably, by sticking to our first definition. In summary, Example 1 shows two function definitions, which both are valid in Python, but which may result in runtime errors when applied. Acton avoids these problems, in one case by discovering type problems in an application of the function already at compile time, and in the other by rejecting the definition altogether, since it allows also type-correct use to give a runtime error. Of course, we cannot expect to avoid runtime errors completely. Programs execute in an environment where errors may be caused by external factors: faulty sensors, failing networks, corrupt files, etc. But Acton adopts the point of view that runtime errors which are caused not by the external world but by programming mistakes should be avoided as far as possible. Thus extensive static checks are performed at compile time. In Python, numeric code is often best written using the [NumPy](https://numpy.org/) package. Acton provides a package with some of the functionality of NumPy; to see how this is used to express function `harmonic`, see [WIP]. ================================================ FILE: docs/tutorial/example-2.md ================================================ # Example 2 - Prime numbers Here is another function definition, which is valid both in Python and Acton: ```py def primesTo(n): isPrime = [True] * n isPrime[0] = False; isPrime[1] = False for i in range(2,int(math.sqrt(float(n)))+1): if isPrime[i]: for k in range(i*i,n,i): isPrime[k] = False return [i for i in range(2,n) if isPrime[i]] ``` This function computes, for given ***n***, the list of all prime numbers smaller than ***n***, so `primesTo(20)` is `[2, 3, 5, 7, 11, 13, 17, 19]`. The function uses the ancient and remarkably efficient sieve algorithm discovered by the Greek mathematician Eratosthenes around 200 BC. On a typical laptop this function will compute the 78498 primes less than a million in a small fraction of a second. But again we are more interested in the data structures used and their types. In the function body, `isPrime` is bound to a list of $n$ Boolean values, i.e. the elements of the list are `True` or `False`. Like all lists in Python, `isPrime` will get the builtin type `list`. Also the function result is a `list`, but this time a list of integers. The type, however, cannot express this difference; this is also just a `list`. We have here an example of ***polymorphism***, i.e. a type of container which may contain elements of different types. In Python this polymorphism is unrestricted; even a single list can contain elements of many different types. As an example, we can form the list `[3,"hi",lambda n: n*n]`, consisting of one integer, one string and one function. Examples where this freedom is essential, or even useful, are relatively scarce. On the other hand, it is easy to see that it may cause trouble: when we traverse a list we do not know the types of the values we encounter and hence not which operations we may meaningfully perform on them. Acton does not allow full polymorphism, but adopts a more limited form which is both type-safe and has proven very useful in practice: ***parametric*** polymorphism. This means that we can have lists of integers, lists of strings, lists of lists of floats etc. but that in a given list, all elements have the same type. Thus we have not one all-encompassing type of lists, but a whole family of types `list[A]` where `A` is a ***type variable***, which can be ***instantiated*** to an arbitrary type. So `isPrime` has type `list[bool]` and the function `primesTo` has type `(int) -> list[int]`. The function `primesTo` itself may be inserted as an element in a list of type `list[(int) -> list[int]]`. Type safety means that whenever we encounter an element of such a list, we know that we can apply it to an integer and get a list of integers as result. To complete the example, here is an actor which accepts ***n*** on the command line and prints not all the primes but only the number of primes smaller than ***n***: ```py actor main(env): print(len(primesTo(int(env.argv[1])))) ``` To find the number of primes, we use the function `len`, which in Acton as in Python computes the length of its argument. So, it would seem that `len` har type `(list[A]) -> int`, i.e. it works independently of the type of elements of the list. This is indeed so, but it doesn't stop there. However, also in this case you may want to come back to the rest of this discussion in a future reading. You may recall that in Python, the function `len` can be applied not only to lists, but also to strings, sets and dictionaries (and other classes, which define the method `__len__`). This is also the case in Acton, and requires a new concept to ensure safe static typing. We need a general mechanism for ***overloading***, i.e. allowing several functions, with separate definitions, to be denoted by the same name. In fact, we have already seen overloading in previous examples: we have used + to denote addition both of `int`s and `float`s, quite different operations at the machine level. Many languages overload arithmetic operator symbols in ad hoc ways. What we look for is a general method to introduce new overloadings. The general type of `len` in Acton is `(Collection[A]) -> int`, where `Collection` is a builtin ***protocol***. A protocol is a collection of ***type signatures***. In order to ***implement*** the protocol a type must implement methods of the required signatures. The protocol `Collection` specifies two methods, `__len__` and `__fromiter__`. So, all the builtin types `list[A]`, `set[A]`, `dict[A, B]` and `str` implement this protocol and thus we can compute lengths of objects of these types. The type system, remarkably, allows overloading to be resolved at compile time, i.e. the compiled code invokes the correct instance of all overloaded functions at each occurrence. We cannot here discuss protocols in depth. We just note that the use of the word 'protocol' for this concept is taken from Swift. The concept is also closely related to the notion of ***type classes*** in Haskell. ================================================ FILE: docs/tutorial/example-3.md ================================================ # Example 3: Actors vs classes We now turn to classes and actors, which, as we have already mentioned, have some similarities, but also major differences. We consider a classical example of an object with state, the counter. ![Counter](images/counter.png) The counter allows three operations: its value can be `inc`reased by one (the ``button'' on top), `reset` to zero (the knob on the right) or `read` (the display). The use case for this particular variant of a counter is to keep track of the number of inc's performed since the counter was last reset. Below are two valid Acton definitions, modelling the counter. The left one is also a valid class definition in Python. We also show some simple, typical use of the definitions. ```py class CounterC(): actor CounterA(initval=0): def __init__(self,initval=0): var val = initval self._val = initval def inc(self): def inc(): self._val += 1 val += 1 def read(self): def read(): return self._val return val def reset(self): def reset(): self._val = 0 val = 0 actor main(env): actor main(env) c = CounterC(5) a = CounterA(5) c.inc() a.inc() c.inc() a.inc() v = c.read() v = a.read() print(v) # prints 7 print(v) # prints 7 ``` We see striking similarities and some minor differences between the two definitions: * Most strikingly, the definitions are used in exactly the same way: we create a class instance/an actor with initial value 5, we increase its value twice and finally read the counter value, which in both cases will be 7. * The definitions of methods are almost the same; the differences are the occurrences of `self` in the class (and our choice of having an underscore in the name of the instance variable). * There is no `__init__` method in the actor definition; instead the optional initial value is a parameter to the actor name. Thus parameters in an actor definition have another meaning than in a class definition (where they denote superclasses). * The state variable `val` is explicitly declared in the actor definition, introduced by the keyword `var`. Thus, we can use both class and actor definitions to create objects with state that can be manipulated and accessed through methods. But the syntax and the similaritites tend to downplay the fundamental difference between the two concepts: * The method call `c.inc()` is essentially an ordinary function call (with the receiving object as first parameter). A thread that executes this call will transfer control to the function body, execute the body, which will update the state variable, and continue. * The statement `a.inc()`, on the other hand, looks exactly the same but denotes the sending of the message `inc()` to the actor `a`. A thread executing the call will ask the runtime system for this service and proceed immediately with the next statement. The message will be queued and the actual increase of `a`'s state will be done at some later point in time, probably by some other thread. This difference means that the actor `a` can be used as a member of the community of actors comprising a program, providing the service of a shared counter. It keeps track of the number of `inc` messages received, for which it can be queried in a `read` message. The class instance, on the other hand, can ***not*** be safely used in this way. Imagine that we could create class instance `c` and place it as a top level member in a community of actors. Since the operation of increasing the value of an integer variable is not thread-safe, it is conceivable that two concurrent threads, doing message processing for actors using the class instance, will execute `c.inc()` in parallel, both read the same `_val` and increase it by 1 before writing back, with the net result that the two calls will only increase the counter by one. The conclusion is that classes and class instances do have a role to play in Acton: instances can be used as (part of) the internal state in actors, but not as replacement for actors. To illustrate this point in an exaggerated way, the following would be a legitimate and safe use of class `CounterC`: ```py actor CounterA(initval = 0): var c = CounterC(initval) def inc(): c.inc() def read(): return c.read() def reset(): c.reset() ``` Here, there is no risk of multiple threads causing problems, since the calls to `c`'s methods occur within the processing of an actor message. We certainly do not recommend this design, since the example is too trivial. The internal state of the actor is as easily modelled by an integer variable, so the use of a class instance here seems to offer no advantage. For an example where a class instance would be a natural choice as state we can think of a sorted container (set, list or dictionary or ...), i.e. a container which also supports an operation to retrieve its elements in sorted order. Here some form of binary search tree would be a natural candidate to represent the state. More generally, any data structure implemented as a class can be made thread-safe by wrapping it in an actor as indicated here. ## On templates, instances and message passing A class declaration is a template for objects. Every time we execute `c = CounterC()` we get a new ***instance*** of the class `CounterC` with its own copy of the state `_val`. The situation is the same for actors. Executing `a = CounterA()` creates a new actor instance of the "actor class" `CounterA` with its own copy of the state `val`. However, following established terminology but maybe a bit confusing at first, we refer also to the instance just as an actor. The syntax for sending a message to an actor `b`, where `b` is an instance of actor (class) `B`, is `b.m(args)`, where `m` must be a method declared in `B` and `args` are suitable arguments. Thus, actor `a` can only send a message to actor `b`, if `a` knows the name of `b`. This can be obtained in only two ways: * The name is obtained when `b` is created, as in `b = CounterA()`. The name is completely opaque; there are no operations that apply to it and it cannot be programmatically constructed. Thus, if `a` actually created `b`, then `a` knows the name of, and can send messages to, `b`. * The only other way that `a` may know the name is that it has received the name in a message, from an actor who already knows `b`. That actor could possibly be `b` itself, using the reserved word `self`. If `a` sends two asynchronous messages to `b`, the first message sent is guaranteed to be delivered before the second. But this is the only guarantee that Acton makes as to delivery order. If a third actor `c` also sends messages to `b`, nothing can be said about the arrival order between two messages with distinct senders. To be a bit more concrete, consider a community of worker actors that use a `CounterA` actor `a` to keep track how many times a certain task has been performed. To this end, all the workers call `a.inc()` each time they have completed the task. We consider two scenarios: * A method call `a.read()` which is done when the system is idle, will accurately report how many tasks have been completed. * Regardless of the state of the system, if one of the workers calls `a.read()`, the returned value will certainly include all tasks completed and reported by that worker. For task completions reported by other workers, we cannot say whether tasks completed ``recently'' will have been counted or whether the corresponding `a.inc()` messages remain in `a`'s mailbox, to be processed after the reading of the counter. ================================================ FILE: docs/wrapping_c_libraries.md ================================================ # Wrapping C libraries in Acton This document attempts to provide a brief introduction to using C for implementing functions and actors in Acton. The Acton stdlib is the only real use case where C is used. All other libraries and applications are implemented in pure Acton. Thus, this document is for those of you that intend to contribute to Acton's stdlib. Acton is a compiled language and C is used as an intermediate representation. Acton programs are turned into C which in turn are compiled to machine code using a standard C compiler. This makes it conceptually straightforward to integrate C libraries into Acton; we "just" need to write C code that looks the way that the Acton compiler would have written it! The simplest way to achieve this is to first have the compiler generate some C code for us, which we can go ahead and modify to our hearts content. C can be used to implement a whole module or individual functions and methods. Regardless to which extent C is used, the modules interface needs to be specified in Acton so that the Acton compiler has a view of the interface with types. While Acton has an advanced type inferencer, it is not able to inspect C code and reverse engineer the types used. It can infer the type based on how the module might be used, but it is much safer and thus recommended to write a type signature for all functions implemented in C. As an example, we will create our own `time.foo()` function, which will be a duplicate of the `time.time()` function. Start by writing the Acton declaration of the function in `stdlib/src/time.act`: ```Acton def foo() -> float: """Return the current real time """ return 3.14 ``` `foo()` does not take any arguments and returns a float. We provide a short description of the function and write a dummy return statement. This is so that we may generate some boilerplate code. Run `acton --cgen stdlib/src/time.act` to generate C code. The `foo()` function will be called `time$$foo` and should look something like (may change with compiler version): ```c $float time$$foo () { $RealFloat w$232 = (($RealFloat)$RealFloat$float$new()); return (($float (*) ($RealFloat, $atom))w$232->$class->__fromatom__)(w$232, (($atom)to$float(3.14))); } ``` Change the code in `stdlib/src/time.act` to replace the function body with `NotImplemented`: ```Acton def foo() -> float: """Return the current real time """ NotImplemented ``` This instructs the Acton compiler to not generate C code for this function if an external definition C file exists. Next, paste in the copied C code into the external C definition file `stdlib/src/time.ext.c`: ```c $float time$$foo () { $RealFloat w$232 = (($RealFloat)$RealFloat$float$new()); return (($float (*) ($RealFloat, $atom))w$232->$class->__fromatom__)(w$232, (($atom)to$float(3.14))); } ``` Recompile everything and write a test program that uses the new function: ```Acton import time actor main(env): print(time.foo()) exit(0) ``` And it should print `3.14`! We can now go ahead and modify `stdlib/src/time.ext.c` to implement the actual functionality we want, like so: ``` $float time$$foo () { struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { $RAISE((($BaseException)$RuntimeError$new(to$str("Unable to get time")))); } return to$float(ts.tv_sec + 0.000000001*ts.tv_nsec); } ``` Acton values are boxed and are available in C as `$float`, `$int`, `$str` etc. You will need to convert your machine native values into Acton values. ## Considerations - The Acton RTS runs multiple concurrent threads that run actors and as such it is of utmost importance that the C libraries used are thread safe. - All functions in Acton are run synchronously. Never ever ever perform I/O (which might never complete) or other similar operations, instead, model your C thing as an actor. Actor methods calls are always asynchronous and thus might never return. By design, there is no way to do blocking I/O in Acton, however, since you are writing things in C, there's enough rope to hang yourself (and your Acton system)... - Actors can be resumed if they die or are migrated from another compute node. If you keep state, make sure it survives a resumption (and implicitly the snapshotting of its state). There is a `__resume__` callback that can be used as a hook point to perform extra steps after an actor has been deserialized into memory. ================================================ FILE: ecolift/CLAUDE.md ================================================ # Acton Ecosystem Lift Process This document describes the process for lifting the entire Acton ecosystem when introducing new language features or breaking changes. ## Ecosystem Repositories builtin & stdlib are in this repo in the base/ directory. The following repositories contain syntax highlighting and similar for editors / IDE and should be updated when the language has been changed: - [ ] git@github.com:actonlang/Acton.tmbundle.git - [ ] git@github.com:actonlang/acton-mode.git - [ ] git@github.com:actonlang/sublime-acton.git - [ ] git@github.com:actonlang/vim-acton.git - [ ] git@github.com:actonlang/vscode-acton.git The following are Acton projects: - [ ] git@github.com:actonlang/acton-grpc.git - [ ] git@github.com:actonlang/acton-http2.git - [ ] git@github.com:actonlang/acton-snappy.git - [ ] git@github.com:actonlang/acton-zlib.git - [ ] git@github.com:orchestron-orchestrator/actmf.git - [ ] git@github.com:orchestron-orchestrator/acton-yang.git - [ ] git@github.com:orchestron-orchestrator/netcli.git - [ ] git@github.com:orchestron-orchestrator/netclics.git - [ ] git@github.com:orchestron-orchestrator/netconf.git - [ ] git@github.com:orchestron-orchestrator/orchestron.git - [ ] git@github.com:orchestron-orchestrator/sorespo.git - [ ] git@github.com:telemetrify-collector/telemetrify.git ## General Process We group together the remote git operations, so start by cloning all repositories, perform steps for each repository, then push all repositories at the end. The ecosystem lift process consists of the following steps for each repository: 1. **Clone the repository** (into the `repos/` directory) - done in batch ```bash cd ecolift/repos git clone cd ``` 2. **Create a new branch** ```bash git checkout -b ecolift/ ``` 3. **Apply the language changes** - Find .act files - Update the code for the particular feature 4. **Test the changes** ```bash acton build acton test ``` 5. **Commit** ```bash git add -u git commit -m "Adapt to in Acton" ``` the user can at this point review locally 6. **Push and create a pull request** ```bash git push -u origin ecolift/ gh pr create --title "Adapt to in Acton" --body "This PR updates the codebase to be compatible with in Acton" ``` ## Identifying Changes to Ecolift When performing an ecolift, the user requesting the ecolift should provide sufficient details about what changes need to be made. If the details are unclear, **prompt the user for more information** before proceeding. ### Required Information from User The user should provide one or more of the following: 1. **Specific commit IDs** from the main acton repository that introduced the changes: ``` Please provide the commit ID(s) that introduced this feature: abc123def ``` 2. **Examples of the transformation** showing old vs new syntax: ``` Old syntax: "Hello " + name + "!" New syntax: f"Hello {name}!" ``` 3. **Feature description** with concrete examples of what needs to change: ``` Added comprehensions: transform loops like `for x in items: result.append(x*2)` to `[x*2 for x in items]` ``` ### If Information is Unclear If the user's request lacks sufficient detail, ask clarifying questions: - "Can you provide the commit ID(s) from the main acton repo that introduced this feature?" - "Can you show an example of the old syntax vs new syntax transformation?" - "What specific language constructs or patterns need to be updated?" - "Are there test cases in the main repo that demonstrate this change?" ### Using Provided Information Once you have the necessary details: 1. **Examine the referenced commits** to understand the full scope of changes 2. **Study compiler test cases** that show transformation patterns 3. **Look for examples** in the main repo's test files (`test/compiler/`, `test/stdlib_tests/`) 4. **Extract transformation patterns** from the diffs and apply them systematically ## Generated Files to Skip During Refactoring When refactoring projects during ecolift, skip these generated files: ### General Rules - Skip any files that are generated by code generators (typically run via `make gen`) - Skip snapshot test files unless the expected output format itself changed - Focus refactoring efforts on handwritten source files ### acton-yang Project - `src/yang/schema.act` - `test/test_data_classes/src/yang_basics.act` - `test/test_data_classes/src/yang_foo.act` - `test/test_data_classes/src/yang_foo_loose.act` - `test/test_data_classes/src/yang_one.act` - `test/test_data_source_roundtrip/src/xml_full_adata.act` - `test/test_data_source_roundtrip/src/xml_full_gdata.act` - All files in `golden/` directories ## Feature-Specific Transformations A new Acton language feature wll almost certainly include tests in the actonlang/acton repository (the parent directory). When prompted to use a new feature, try to find test cases for the new feature to get a better idea of how it works. ### Example: F-strings When introducing f-strings to Acton, the transformation would involve: 1. Identifying string formatting patterns like: ```acton "Hello " + name + ", you have " + str(count) + " messages" ``` or ```acton "Hello %s" % name ``` 2. Converting to f-string syntax: ```acton f"Hello {name}, you have {count} messages" ``` ```acton f"Hello {name}" ``` ### Example: Comprehensions When adding comprehensions, look for patterns like: ```acton result = [] for x in items: if x > 0: result.append(x * 2) ``` And convert to: ```acton result = [x * 2 for x in items if x > 0] ``` ================================================ FILE: ecolift/repos/.gitignore ================================================ # Ignore all cloned repositories * # But keep this file !.gitignore ================================================ FILE: ecolift/string_interpolation.md ================================================ # New interpolated strings After the string parser rewrite, Acton now supports interpolation in normal strings plus many previous issues with f-strings have been fixed. The idiomatic Acton style is now to use regular strings with interpolation. ## basic concatenation replace ```acton "Hello " + name + ", you have " + str(count) + " messages" ``` with ```acton "Hello {name}, you have {count} messages" ``` ## % operator style replace: ```acton "Hello %s" % name ``` with: ```acton "Hello {name}" ``` ## f-strings Remove the f prefix since it is optional and the idiomatic Acton style is to NOT use f-prefix. replace: ```acton f"Hello {name}" ``` with: ```acton "Hello {name}" ``` ## Slice expressions There were previously issues with slice expressions inside f-strings. Those have been addressed with the new parser, so we should stick to string interplation, not concatenation. replace: ```acton "Hello " + name[:3] ``` with: ```acton "Hello {name[:3]}" ``` ## Escaped quotes There were previously issues with escaping quotes inside f-strings. Those issues have been addressed with the new parser, so we can use different quote chars: replace: ```acton f"""Hello \"world\"!""" ``` with: ```acton """Hello "world"!""" ``` ## Escape curly braces Since normal strings now offer interpolation, curly braces have changed semantically from literal braces to mean an expression that should be interpolated. Thus, for existing code, we need to convert the string to a raw string or escape the brace. replace: ```acton 'Some JSON {"a": 1}' ``` with: ```acton r'Some JSON {"a": 1}' ``` if interpolation or string concatenation is used, then escape replace: ```acton 'Name' + name + 'Some JSON {"a": 1}' ``` with: ```acton """Name {name} Some JSON {{"a": 1}}""" ``` ================================================ FILE: examples/.acton ================================================ ================================================ FILE: examples/StringsAndBytes.act ================================================ actor main(env): s = "\x48ello, world" print(s) env.exit(0) ================================================ FILE: examples/abs.act ================================================ actor main(env): x = -3 print(abs(x)) env.exit(0) ================================================ FILE: examples/average.act ================================================ def average(coll): sum = 0 for s in coll: sum += s return sum.__float__()/float(len(coll)) actor main(env): s = [3.2, 4.5, 3.2, 0.5] print(average(s)) t = [4, 6, 9, 14] print(average(t)) u = [3, 4.4] # u has type list[float] for i in map(int,u): print(i) for x in map(float,u): print(x) n : int n = 3 v = [n, 4.4] # v has type list[atom] for i in map(int,v): print(i) for x in map(float,v): print(x) # print(average(v)) env.exit(0) ================================================ FILE: examples/bsplit.act ================================================ import math def bsplit(a,b): if b-a == 1: return (1,b) else: m = a + (b-a)//2 p1,q = bsplit(a,m) p,q2 = bsplit(m,b) p1 *= q2 p += p1 q *= q2 return (p,q) def e(prec): fp = float(prec) n = int(3 * fp / math.log(fp) + 20) p,q = bsplit(0,n) p += q p *= 10**prec return p//q actor main(env): print(e(10000)) env.exit(0) ================================================ FILE: examples/client.act ================================================ import net actor main(env): def on_connect(c): print("Client established connection to", c.remote_address(), "from", c.local_address(), "using IP version", c.ip_version()) def conn_write(s): c.write(s.encode()) env.stdin_install(conn_write) def on_receive(c, data): env.stdout_write(data.decode()) def on_error(c, msg): print("Client ERR", msg) # Should do periodic back-off c.reconnect() if len(env.argv) != 3: print("usage: client [HOST] [PORT]") env.exit(-1) connect_cap = net.TCPConnectCap(net.TCPCap(net.NetCap(env.cap))) client = net.TCPConnection(connect_cap, env.argv[1], int(env.argv[2]), on_connect, on_receive, on_error) ================================================ FILE: examples/count.act ================================================ # This is a simple illustration for demoing how the Acton RTS can persist its # run time state in the Acton distributed database backend. First start the # database: # # ./server -p 32000 -m 34000 -s 127.0.0.1:34000 # ./server -p 32001 -m 34001 -s 127.0.0.1:34000 # ./server -p 32002 -m 34002 -s 127.0.0.1:34000 # # Then compile and run this program. Abort its current invocation with ^C, then # restart the program and note how it will resume its state from the database # before counting further. # # kll@Boxy:~/acton/examples$ ../acton --root main count.act # kll@Boxy:~/acton/examples$ ./count --rts-ddb-host localhost --rts-verbose # Acton RTS: using distributed database backend (DDB): localhost:32000 # Acton RTS: checking for previous actor state in DDB... done # 0 # 1 # 2 # 3 # 4 # ^C # kll@Boxy:~/acton/examples$ ./count --rts-ddb-host localhost --rts-verbose # Acton RTS: using distributed database backend (DDB): localhost:32000 # Acton RTS: checking for previous actor state in DDB... done # Acton RTS: restoring actor state from DDB... done # 5 # 6 # 7 # 8 # ^C # kll@Boxy:~/acton/examples$ ./count --rts-ddb-host localhost --rts-verbose # actor main(env): var i = 0; var count_to = 0 if len(env.argv) > 2: print("Usage: count COUNT") await async env.exit(1) if len(env.argv) > 1: count_to = int(env.argv[1]) def _work(): print(i) if count_to > 0 and i == count_to: env.exit(0) i += 1 after 1: _work() _work() ================================================ FILE: examples/counter.act ================================================ actor counter(initval): var val = initval def next(): val += 1 return val actor main(env): ctr = counter(0) n = ctr.next() print(n) env.exit(0) ================================================ FILE: examples/eq_list_dict.act ================================================ actor main(env): a = [1,2,3] if a == [1,2,3]: print("Equal, correct") else: print("Not equal, wrong") if a == [1,2]: print("Equal, wrong") else: print("Not equal, correct") if a == [1,5,2]: print("Equal, wrong") else: print("Not equal, correct") if [3.5,7.2] == [3.5, 7.2]: print("Equal, correct") else: print("Not equal, wrong") if [a,a] == [[1,2,3],[1,2,3]]: print("Equal, correct") else: print("Not equal, wrong") if [a,a] == [[1,2,3],[1,3]]: print("Equal, wrong") else: print("Not equal, correct") if ["hello", "world"]==["Hello","word"]: print("Equal, wrong") else: print("Not equal, correct") d1, d2 : dict[str,str] d1 = {} d1["Sweden"] = "Stockholm" d1["Norway"] ="Oslo" d1["Denmark"] = "Copenhagen" d2 = {} d2["Norway"] ="Oslo" d2["Denmark"] = "Copenhagen" d2["Sweden"] = "Stockholm" if d1==d2: print("Equal, correct") else: print("Not equal, wrong") d2["Finland"] = "Helsinki" if d1==d2: print("Equal, wrong") else: print("Not equal, correct") d3, d4 : dict[bool,dict[str,str]] d3 = {} d3[True] = d1 d3[False] = d2 d4 = {} d4[False] = d2 d4[True] = d1 if d3==d4: print("Equal, correct") else: print("Not equal, wrong") d2["Estonia"] = "Tallinn" if d3==d4: print("Equal, correct") else: print("Not equal, wrong") print("now to Ord") if ([3,4,5] < [3,4,5,8]): print("lt, correct") else: print("Not lt, wrong") if ([3,4,5] < [3,4,6,8]): print("lt, correct") else: print("Not lt, wrong") if ([3,4,5,6,7] < [3,4,6,1,2,3,4]): print("lt, correct") else: print("Not lt, wrong") if ([3,4,5,6,7] <= [3,4,6,1,2,3,4]): print("le, correct") else: print("Not le, wrong") if ([3,4,6,1,2,3,4] > [3,4,5,6,7]): print("gt, correct") else: print("Not gt, wrong") if d1 < d2: print("lt, correct") else: print("Not lt, wrong") if d3 <= d4: print("le, correct") else: print("Not le, wrong") env.exit(0) ================================================ FILE: examples/files.act ================================================ import file actor main(env): # Get a reference to capability to read a file, by refining from WorldCap f_cap = file.ReadFileCap(file.FileCap(env.cap)) f = file.ReadFile(f_cap, env.argv[1]) data = f.read() print(data.decode()) env.exit(0) ================================================ FILE: examples/helloworld.act ================================================ actor main(env): print("Hello, world!") env.exit(0) ================================================ FILE: examples/http_server.act ================================================ import net import http import logging # PolarSSL/mbedTLS self-signed test certificate CERT_PEM = """-----BEGIN CERTIFICATE----- MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN MTkwMjEwMTQ0NDA2WhcNMjkwMjEwMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQELBQADggEBAC465FJh Pqel7zJngHIHJrqj/wVAxGAFOTF396XKATGAp+HRCqJ81Ry60CNK1jDzk8dv6M6U HoS7RIFiM/9rXQCbJfiPD5xMTejZp5n5UYHAmxsxDaazfA5FuBhkfokKK6jD4Eq9 1C94xGKb6X4/VkaPF7cqoBBw/bHxawXc0UEPjqayiBpCYU/rJoVZgLqFVP7Px3sv a1nOrNx8rPPI1hJ+ZOg8maiPTxHZnBVLakSSLQy/sWeWyazO1RnrbxjrbgQtYKz0 e3nwGpu1w13vfckFmUSBhHXH7AAS/HpKC4IH7G2GAk3+n8iSSN71sZzpxonQwVbo pMZqLmbBm/7WPLc= -----END CERTIFICATE----- """ KEY_PEM = """-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2 2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABAoIBAQCXR0S8EIHFGORZ ++AtOg6eENxD+xVs0f1IeGz57Tjo3QnXX7VBZNdj+p1ECvhCE/G7XnkgU5hLZX+G Z0jkz/tqJOI0vRSdLBbipHnWouyBQ4e/A1yIJdlBtqXxJ1KE/ituHRbNc4j4kL8Z /r6pvwnTI0PSx2Eqs048YdS92LT6qAv4flbNDxMn2uY7s4ycS4Q8w1JXnCeaAnYm WYI5wxO+bvRELR2Mcz5DmVnL8jRyml6l6582bSv5oufReFIbyPZbQWlXgYnpu6He GTc7E1zKYQGG/9+DQUl/1vQuCPqQwny0tQoX2w5tdYpdMdVm+zkLtbajzdTviJJa TWzL6lt5AoGBAN86+SVeJDcmQJcv4Eq6UhtRr4QGMiQMz0Sod6ettYxYzMgxtw28 CIrgpozCc+UaZJLo7UxvC6an85r1b2nKPCLQFaggJ0H4Q0J/sZOhBIXaoBzWxveK nupceKdVxGsFi8CDy86DBfiyFivfBj+47BbaQzPBj7C4rK7UlLjab2rDAoGBAN2u AM2gchoFiu4v1HFL8D7lweEpi6ZnMJjnEu/dEgGQJFjwdpLnPbsj4c75odQ4Gz8g sw9lao9VVzbusoRE/JGI4aTdO0pATXyG7eG1Qu+5Yc1YGXcCrliA2xM9xx+d7f+s mPzN+WIEg5GJDYZDjAzHG5BNvi/FfM1C9dOtjv2dAoGAF0t5KmwbjWHBhcVqO4Ic BVvN3BIlc1ue2YRXEDlxY5b0r8N4XceMgKmW18OHApZxfl8uPDauWZLXOgl4uepv whZC3EuWrSyyICNhLY21Ah7hbIEBPF3L3ZsOwC+UErL+dXWLdB56Jgy3gZaBeW7b vDrEnocJbqCm7IukhXHOBK8CgYEAwqdHB0hqyNSzIOGY7v9abzB6pUdA3BZiQvEs 3LjHVd4HPJ2x0N8CgrBIWOE0q8+0hSMmeE96WW/7jD3fPWwCR5zlXknxBQsfv0gP 3BC5PR0Qdypz+d+9zfMf625kyit4T/hzwhDveZUzHnk1Cf+IG7Q+TOEnLnWAWBED ISOWmrUCgYAFEmRxgwAc/u+D6t0syCwAYh6POtscq9Y0i9GyWk89NzgC4NdwwbBH 4AgahOxIxXx2gxJnq3yfkJfIjwf0s2DyP0kY2y6Ua1OeomPeY9mrIS4tCuDQ6LrE TB6l9VGoxJL4fyHnZb8L5gGvnB1bbD8cL6YPaDiOhcRseC9vBiEuVg== -----END RSA PRIVATE KEY----- """ actor main(env): logh = logging.Handler() logh.add_sink(logging.ConsoleSink()) logh.set_output_level(logging.TRACE) listen_cap = net.TCPListenCap(net.TCPCap(net.NetCap(env.cap))) def on_accept(server): server.cb_install(on_request, on_error) def on_request(server, request, respond): respond(200, {"Content-Type": "text/plain"}, "Hello from the Acton HTTPS server") def on_error(server, error): print("HTTPS server error:", error) http.TLSListener( listen_cap, "127.0.0.1", 8443, CERT_PEM.encode(), KEY_PEM.encode(), on_accept, log_handler=logh ) print("HTTPS server listening on https://127.0.0.1:8443") ================================================ FILE: examples/inter.act ================================================ # An interacive terminal program that increments and decrements a counter based # on user input. The program will exit when the user types 'q'. There is also a # periodic incrementation of the counter every 5 seconds. # # The actor based asynchronous I/O model of Acton makes it very natural to # express event-driven reactive programs like this that can react to user input # while not blocking on I/O, thus allowing for other tasks to be performed, in # this case the periodic incrementation of the counter. actor main(env: Env): var count = 0 def interact(input): if input == "q": print("Quitting!") env.exit(0) elif input == "i": count += 1 print("Incrementing! Count is now:", count) elif input == "d": count -= 1 print("Decrementing! Count is now:", count) else: print("Unknown command:", input) # Set non-canonical mode, so we get each key stroke directly env.set_stdin(canonical=False) # Turn off terminal echo env.set_stdin(echo=False) env.stdin_install(interact) print("Type 'q' to quit, 'i' to increment a counter and 'd' to decrement it.") def periodic(): count += 1 print("Periodic +1 increment. Count is now:", count) after 5: periodic() after 1: periodic() ================================================ FILE: examples/print_time.act ================================================ import time actor main(env): def f(): print(time.time()) f() env.exit(0) ================================================ FILE: examples/reprtest.act ================================================ actor main(env): print(["abc","def"]) print([["abc","def"],["ghi"]]) print(repr("kalle")) s = {"abc"} s.add("def") print(s) d = {} for i in range(10): d[i] = str(i) print(d) env.exit(0) ================================================ FILE: examples/server.act ================================================ import net actor Server(conn): def on_receive(c, data): print("Server Received some data:", data, " from:", c) if data == b"PING": c.write(b"PONG") def on_error(c, error): print("There was an error:", error, " from:", c) actor Listener(listen_cap, port): def on_error(l, error): print("There was an error with the TCPListener socket:", error) def on_accept(c): s = Server(c) c.cb_install(s.on_receive, s.on_error) var server = net.TCPListener(listen_cap, "0.0.0.0", port, on_error, on_accept) actor main(env): port = 12345 # Set up capability for listening with TCP listen_cap = net.TCPListenCap(net.TCPCap(net.NetCap(env.cap))) l = Listener(listen_cap, port) ================================================ FILE: examples/sieve.act ================================================ import math def sieve(n): isPrime = [True] * n isPrime[0] = False; isPrime[1] = False for i in range(2, int(math.sqrt(float(n)))+1): if isPrime[i]: for k in range(i*i,n,i): isPrime[k] = False return isPrime count : (list[bool]) -> int def count(bs): res = 0 for b in bs: if b: res += 1 return res def primesTo(n): res = [] isPrime = sieve(n) for i in range(2, n): if isPrime[i]: res.append(i) return res actor main(env): if (len(env.argv) >= 2) and env.argv[1].isdecimal(): print(count(sieve(int(env.argv[1])))) else: print("Usage: sieve ") env.exit(0) ================================================ FILE: examples/sumto.act ================================================ def sumto(n): res = 0 for i in range(n): res += i return res actor main(env): if len(env.argv) >= 2: target = int(env.argv[1]) else: target = int(123) print(sumto(int(target))) env.exit(0) ================================================ FILE: examples/worker.act ================================================ actor worker(report): report() actor main(env): def report(): print('Done!') env.exit(0) worker(report) env.exit(0) ================================================ FILE: homebrew/Formula/acton.rb ================================================ class Acton < Formula desc "Delightful distributed programming language" homepage "https://www.acton-lang.org" url "https://github.com/actonlang/acton/archive/refs/tags/v0.0.0.tar.gz" sha256 "0000000000000000000000000000000000000000000000000000000000000000" license "BSD-3-Clause" head "https://github.com/actonlang/acton.git", branch: "main" depends_on "ghc@9.6" => :build depends_on "haskell-stack" => :build def install # Fix up stack config to not install project local GHC and use system GHC # which is idiomatic for Homebrew. Disable GHC version check as we want to # allow for minor version mismatches. inreplace "compiler/stack.yaml", "# system-ghc: true", <<~EOS system-ghc: true install-ghc: false allow-newer: true skip-ghc-check: true EOS ENV["BUILD_RELEASE"] = "1" system "make" bin.install "dist/bin/acton" bin.install_symlink "acton" => "actonc" bin.install "dist/bin/actondb" bin.install "dist/bin/runacton" prefix.install Dir["dist/*"] bash_completion.install "completion/acton.bash-completion" end test do testapp = (testpath/"hello.act") testapp.write <<~EOS #!/usr/bin/env runacton actor main(env): print("Hello World!") env.exit(0) EOS testapp.chmod 0755 assert_equal "Hello World!\n", shell_output(testapp) end end ================================================ FILE: test/.acton ================================================ test ================================================ FILE: test/Makefile ================================================ MK_PATH:=$(abspath $(CURDIR)/..) ACTON="../dist/bin/acton" --quiet DDB_SERVER=../dist/bin/actondb TESTS= \ $(DDB_TESTS) test: $(MAKE) $(TESTS) ddb-tests: $(MAKE) $(DDB_TESTS) DDB_TESTS=test_db_app test_db_resume_tcp_server test_db_resume_tcp_client .PHONY: $(DDB_TESTS) .PHONY: tls-test-server tls-test-server: ../dist/zig/zig cc -pthread -I../dist/deps/mbedtls/include -I../dist/deps/mbedtls/tests/include -I../dist/deps/mbedtls/library -Istdlib -DMBEDTLS_USER_CONFIG_FILE=\"tls_test_mbedtls_config.h\" -o stdlib/tls_test_server stdlib/tls_test_server.c ../dist/deps/mbedtls/tests/src/certs.c ../dist/deps/mbedtls/library/*.c # Starts up a database cluster, checks membership is ok before proceeding to run # a simple app. We do not really verify that the RTS uses the database - we # assume it does and would fail catastrohpically if it encounters an error. test_db_app: $(ACTON) --db rts_db/ddb_test_app.act $(ACTON) --db rts_db/test_db_app.act rts_db/test_db_app test_db_resume_tcp_server: $(ACTON) --db rts_db/ddb_test_server.act $(ACTON) --db rts_db/test_tcp_server.act rts_db/test_tcp_server test_db_resume_tcp_client: $(ACTON) --db rts_db/ddb_test_server.act $(ACTON) --db rts_db/ddb_test_client.act $(ACTON) --db rts_db/test_tcp_client.act rts_db/test_tcp_client # Expect 9 threads given 7 workers + main process + IO rts/wthreads1: $(ACTON) --root main $@.act ./$@ --rts-wthreads 7 & PID=$$! && ps -o thcount $${PID} | tail -n1 | awk '{ print $$1 }' | grep "^9$$" ================================================ FILE: test/count.act ================================================ actor main(env): var i = 0; var count_to = int(env.argv[1]) def _work(): print(i) if count_to and i == count_to: await async env.exit(0) i += 1 after 1: _work() _work() ================================================ FILE: utils/actonmon ================================================ #!/usr/bin/env python3 import argparse from functools import partial from http.server import HTTPServer, BaseHTTPRequestHandler import json import socket import time class MonSock: def __init__(self, address): self.address = address self.sock = None self.buf = b"" def connect(self): self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: self.sock.connect(self.address) except: pass def cmd(self, cmd, retries=5): if self.sock is None: self.connect() # Simple netstrings implementation, which also assumes that there is # only one response to our query try: self.sock.send(f"{len(cmd)}:{cmd},".encode('utf-8')) while True: try: colpos = self.buf.index(b':') except ValueError as exc: # Not enough data, read some and try again recv = self.sock.recv(1024) if len(recv) == 0: raise ConnectionError("RTS hung up") self.buf += recv continue length = int(self.buf[0:colpos]) start = colpos + 1 end = start + length if len(self.buf) < end: # Not enough data, read some and try again recv = self.sock.recv(1024) if len(recv) == 0: raise ConnectionError("RTS hung up") self.buf += recv continue res = self.buf[start:end] self.buf = self.buf[end+1:] # +1 to skip the , return json.loads(res.decode("utf-8")) except Exception as exc: self.connect() if retries > 0: return self.cmd(cmd, retries-1) else: raise ConnectionError("Unable to get data from acton rts") class PromHTTPRequestHandler(BaseHTTPRequestHandler): def __init__(self, sock_addr, *args, **kwargs): self.ms = MonSock(sock_addr) # BaseHTTPRequestHandler calls do_GET **inside** __init__ !!! # So we have to call super().__init__ after setting attributes. super().__init__(*args, **kwargs) def do_GET(self): try: data = self.ms.cmd("WTS") except ConnectionError: self.send_response(503) return self.send_response(200) self.end_headers() total = {k: 0 for k in data['wt']['0']} self.wfile.write(b'# HELP acton_rts_sleeps Number of times a thread went to sleep\n') self.wfile.write(b'# TYPE acton_rts_sleeps counter\n') for k,v in sorted(data['wt'].items(), key=lambda item: int(item[0])): self.wfile.write(f'acton_rts_sleeps{{thread="{k}"}} {v["sleeps"]}\n'.encode('utf-8')) self.wfile.write(b'# HELP acton_rts_conts Execution time of continuations\n') self.wfile.write(b'# TYPE acton_rts_conts histogram\n') for k,v in sorted(data['wt'].items(), key=lambda item: int(item[0])): total['conts_count'] += v['conts_count'] total['conts_sum'] += v['conts_sum'] total['conts_100ns'] += v['conts_100ns'] total['conts_1us'] += v['conts_1us'] total['conts_10us'] += v['conts_10us'] total['conts_100us'] += v['conts_100us'] total['conts_1ms'] += v['conts_1ms'] total['conts_10ms'] += v['conts_10ms'] total['conts_100ms'] += v['conts_100ms'] total['conts_1s'] += v['conts_1s'] total['conts_10s'] += v['conts_10s'] total['conts_100s'] += v['conts_100s'] total['conts_inf'] += v['conts_inf'] self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="0.0000001"}} {v["conts_100ns"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="0.000001"}} {v["conts_1us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="0.00001"}} {v["conts_10us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="0.0001"}} {v["conts_100us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="0.001"}} {v["conts_1ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="0.01"}} {v["conts_10ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="0.1"}} {v["conts_100ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="1"}} {v["conts_1s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="10"}} {v["conts_10s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="100"}} {v["conts_100s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="{k}",le="+Inf"}} {v["conts_inf"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_sum{{thread="{k}"}} {v["conts_sum"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_count{{thread="{k}"}} {v["conts_count"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="0.0000001"}} {total["conts_100ns"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="0.000001"}} {total["conts_1us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="0.00001"}} {total["conts_10us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="0.0001"}} {total["conts_100us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="0.001"}} {total["conts_1ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="0.01"}} {total["conts_10ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="0.1"}} {total["conts_100ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="1"}} {total["conts_1s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="10"}} {total["conts_10s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="100"}} {total["conts_100s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_bucket{{thread="sum",le="+Inf"}} {total["conts_inf"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_sum{{thread="sum"}} {total["conts_sum"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_conts_count{{thread="sum"}} {total["conts_count"]}\n'.encode('utf-8')) self.wfile.write(b'# HELP acton_rts_bkeep Bookkeeping\n') self.wfile.write(b'# TYPE acton_rts_bkeep histogram\n') for k,v in sorted(data['wt'].items(), key=lambda item: int(item[0])): total['bkeep_count'] += v['bkeep_count'] total['bkeep_sum'] += v['bkeep_sum'] total['bkeep_100ns'] += v['bkeep_100ns'] total['bkeep_1us'] += v['bkeep_1us'] total['bkeep_10us'] += v['bkeep_10us'] total['bkeep_100us'] += v['bkeep_100us'] total['bkeep_1ms'] += v['bkeep_1ms'] total['bkeep_10ms'] += v['bkeep_10ms'] total['bkeep_100ms'] += v['bkeep_100ms'] total['bkeep_1s'] += v['bkeep_1s'] total['bkeep_10s'] += v['bkeep_10s'] total['bkeep_100s'] += v['bkeep_100s'] total['bkeep_inf'] += v['bkeep_inf'] self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="0.0000001"}} {v["bkeep_100ns"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="0.000001"}} {v["bkeep_1us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="0.00001"}} {v["bkeep_10us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="0.0001"}} {v["bkeep_100us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="0.001"}} {v["bkeep_1ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="0.01"}} {v["bkeep_10ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="0.1"}} {v["bkeep_100ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="1"}} {v["bkeep_1s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="10"}} {v["bkeep_10s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="100"}} {v["bkeep_100s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="{k}",le="+Inf"}} {v["bkeep_inf"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_sum{{thread="{k}"}} {v["bkeep_sum"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_count{{thread="{k}"}} {v["bkeep_count"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="0.0000001"}} {total["bkeep_100ns"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="0.000001"}} {total["bkeep_1us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="0.00001"}} {total["bkeep_10us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="0.0001"}} {total["bkeep_100us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="0.001"}} {total["bkeep_1ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="0.01"}} {total["bkeep_10ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="0.1"}} {total["bkeep_100ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="1"}} {total["bkeep_1s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="10"}} {total["bkeep_10s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="100"}} {total["bkeep_100s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_bucket{{thread="sum",le="+Inf"}} {total["bkeep_inf"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_sum{{thread="sum"}} {total["bkeep_sum"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_bkeep_count{{thread="sum"}} {total["bkeep_count"]}\n'.encode('utf-8')) self.wfile.write(b'# HELP acton_rts_dbc_ops_called DB Client operation called\n') self.wfile.write(b'# TYPE acton_rts_dbc_ops_called counter\n') for k,v in data['db_client'].items(): self.wfile.write(f'acton_rts_dbc_ops_called{{type="{k}"}} {v["called"]}\n'.encode('utf-8')) self.wfile.write(b'# HELP acton_rts_dbc_ops_completed DB Client operation completed\n') self.wfile.write(b'# TYPE acton_rts_dbc_ops_completed counter\n') for k,v in data['db_client'].items(): self.wfile.write(f'acton_rts_dbc_ops_completed{{type="{k}"}} {v["completed"]}\n'.encode('utf-8')) self.wfile.write(b'# HELP acton_rts_dbc_ops_success DB Client operation success\n') self.wfile.write(b'# TYPE acton_rts_dbc_ops_success counter\n') for k,v in data['db_client'].items(): self.wfile.write(f'acton_rts_dbc_ops_success{{type="{k}"}} {v["success"]}\n'.encode('utf-8')) self.wfile.write(b'# HELP acton_rts_dbc_ops_error DB Client operation errors\n') self.wfile.write(b'# TYPE acton_rts_dbc_ops_error counter\n') for k,v in data['db_client'].items(): self.wfile.write(f'acton_rts_dbc_ops_error{{type="{k}"}} {v["error"]}\n'.encode('utf-8')) self.wfile.write(b'# HELP acton_rts_dbc_ops_no_quorum DB Client operation no_quorum\n') self.wfile.write(b'# TYPE acton_rts_dbc_ops_no_quorum counter\n') for k,v in data['db_client'].items(): self.wfile.write(f'acton_rts_dbc_ops_no_quorum{{type="{k}"}} {v["no_quorum"]}\n'.encode('utf-8')) self.wfile.write(b'# HELP acton_rts_dbc_ops DB client operations\n') self.wfile.write(b'# TYPE acton_rts_dbc_ops histogram\n') for k,v in data['db_client'].items(): self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="0.0000001"}} {v["time_100ns"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="0.000001"}} {v["time_1us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="0.00001"}} {v["time_10us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="0.0001"}} {v["time_100us"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="0.001"}} {v["time_1ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="0.01"}} {v["time_10ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="0.1"}} {v["time_100ms"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="1"}} {v["time_1s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="10"}} {v["time_10s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="100"}} {v["time_100s"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_bucket{{type="{k}",le="+Inf"}} {v["time_inf"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_sum{{type="{k}"}} {v["time_sum"]}\n'.encode('utf-8')) self.wfile.write(f'acton_rts_dbc_ops_count{{type="{k}"}} {v["success"]+v["error"]}\n'.encode('utf-8')) def prompom(sock_addr, listen_addr='0.0.0.0', listen_port=8000): ad = (listen_addr, listen_port) print(f"Serving stuff on {ad}") handler = partial(PromHTTPRequestHandler, sock_addr) httpd = HTTPServer(ad, handler) httpd.serve_forever() def mon(address, interval, once): ms = MonSock(address) while True: data = ms.cmd("WTS") print(f"Program: {data['name']} PID: {data['pid']}") print("WT# State Conts Sleeps") print("--------------------------------------------------------------------------------") for k,v in sorted(data['wt'].items(), key=lambda item: int(item[0])): print(f"{k:>3}: {v['state']:>6} {v['conts_count']:6} {v['sleeps']:7}") if once: break time.sleep(interval) def actors(address, interval, once): ms = MonSock(address) while True: data = ms.cmd("actors") print("Actor# RTS Local Status") print("--------------------------------------------------------------------------------") for k, v in data['actors'].items(): print(f"{k:>6}: {v['rts']:16} {v['local']:6} {v['status']}") if once: break time.sleep(interval) def rich_actors(address, interval, once): from rich.live import Live from rich.table import Table ms = MonSock(address) def generate_table() -> Table: table = Table(title="Actors") table.add_column("ID", style="cyan", no_wrap=True) table.add_column("RTS", style="magenta") table.add_column("Local", style="magenta") table.add_column("Status") while True: try: data = ms.cmd("actors") break except ConnectionError: time.sleep(0.5) status_to_color = { 'running': 'green', 'migrating': 'orange', 'stopped': 'yellow' } for k,v in data['actors'].items(): table.add_row(k, v['rts'], v['local'], f"[{status_to_color[v['status']]}]{v['status']}") return table with Live(generate_table(), refresh_per_second=(1.0/interval)) as live: while True: time.sleep(interval) live.update(generate_table()) if once: break def actdb_membership(address, interval, once): ms = MonSock(address) while True: data = ms.cmd("membership") print(json.dumps(data)) if once: break time.sleep(interval) def rich_actdb_membership(address, interval, once): from rich.live import Live from rich.table import Table ms = MonSock(address) def generate_table() -> Table: table = Table(title="Distributed Acton Members") table.add_column("Node", style="cyan", no_wrap=True) table.add_column("Type", style="magenta") table.add_column("Status") while True: try: data = ms.cmd("membership") break except ConnectionError: time.sleep(0.5) status_to_color = { 'live': 'green', 'dead': 'red', 'unknown': 'orange', 'prejoined': 'blue' } for k,v in data['nodes'].items(): table.add_row(k, v['type'], f"[{status_to_color[v['status']]}]{v['status']}") return table with Live(generate_table(), refresh_per_second=(1.0/interval)) as live: while True: time.sleep(interval) live.update(generate_table()) if once: break def richmon(address, interval, once): from rich.live import Live from rich.table import Table ms = MonSock(address) def generate_table() -> Table: table = Table(title="Acton RTS worker thread statistics") table.add_column("WT#", style="cyan", no_wrap=True) table.add_column("State", style="magenta") table.add_column("Sleeps", justify="right", style="green") table.add_column("Continuations", justify="right", style="green") table.add_column("Sum", justify="right", style="green") table.add_column("<100ns", justify="right", style="green") table.add_column("<1us", justify="right", style="green") table.add_column("<10us", justify="right", style="green") table.add_column("<100us", justify="right", style="green") table.add_column("<1ms", justify="right", style="green") table.add_column("<10ms", justify="right", style="green") table.add_column("<100ms", justify="right", style="green") table.add_column("<1s", justify="right", style="green") table.add_column("<10s", justify="right", style="green") table.add_column("<100s", justify="right", style="green") table.add_column("<+Inf", justify="right", style="green") table.add_column("bkeep", justify="right", style="green") table.add_column("Sum", justify="right", style="green") table.add_column("<100ns", justify="right", style="green") table.add_column("<1us", justify="right", style="green") table.add_column("<10us", justify="right", style="green") table.add_column("<100us", justify="right", style="green") table.add_column("<1ms", justify="right", style="green") table.add_column("<10ms", justify="right", style="green") table.add_column("<100ms", justify="right", style="green") table.add_column("<1s", justify="right", style="green") table.add_column("<10s", justify="right", style="green") table.add_column("<100s", justify="right", style="green") table.add_column("<+Inf", justify="right", style="green") while True: try: data = ms.cmd("WTS") break except ConnectionError: time.sleep(0.5) total = {k: 0 for k in data['wt']['0']} total = { 'sleeps': 0, 'conts_count': 0, 'conts_sum': 0, 'conts_100ns': 0, 'conts_1us': 0, 'conts_10us': 0, 'conts_100us': 0, 'conts_1ms': 0, 'conts_10ms': 0, 'conts_100ms': 0, 'conts_1s': 0, 'conts_10s': 0, 'conts_100s': 0, 'conts_inf': 0, 'bkeep_count': 0, 'bkeep_sum': 0, 'bkeep_100ns': 0, 'bkeep_1us': 0, 'bkeep_10us': 0, 'bkeep_100us': 0, 'bkeep_1ms': 0, 'bkeep_10ms': 0, 'bkeep_100ms': 0, 'bkeep_1s': 0, 'bkeep_10s': 0, 'bkeep_100s': 0, 'bkeep_inf': 0, } for k,v in sorted(data['wt'].items(), key=lambda item: int(item[0])): if k not in table.columns: total['sleeps'] += v['sleeps'] total['conts_count'] += v['conts_count'] total['conts_sum'] += v['conts_sum'] total['conts_100ns'] += v['conts_100ns'] total['conts_1us'] += v['conts_1us'] total['conts_10us'] += v['conts_10us'] total['conts_100us'] += v['conts_100us'] total['conts_1ms'] += v['conts_1ms'] total['conts_10ms'] += v['conts_10ms'] total['conts_100ms'] += v['conts_100ms'] total['conts_1s'] += v['conts_1s'] total['conts_10s'] += v['conts_10s'] total['conts_100s'] += v['conts_100s'] total['conts_inf'] += v['conts_inf'] total['bkeep_count'] += v['bkeep_count'] total['bkeep_sum'] += v['bkeep_sum'] total['bkeep_100ns'] += v['bkeep_100ns'] total['bkeep_1us'] += v['bkeep_1us'] total['bkeep_10us'] += v['bkeep_10us'] total['bkeep_100us'] += v['bkeep_100us'] total['bkeep_1ms'] += v['bkeep_1ms'] total['bkeep_10ms'] += v['bkeep_10ms'] total['bkeep_100ms'] += v['bkeep_100ms'] total['bkeep_1s'] += v['bkeep_1s'] total['bkeep_10s'] += v['bkeep_10s'] total['bkeep_100s'] += v['bkeep_100s'] total['bkeep_inf'] += v['bkeep_inf'] table.add_row(k, v['state'], str(v['sleeps']), str(v['conts_count']), str(v['conts_sum']), str(v['conts_100ns']), str(v['conts_1us']), str(v['conts_10us']), str(v['conts_100us']), str(v['conts_1ms']), str(v['conts_10ms']), str(v['conts_100ms']), str(v['conts_1s']), str(v['conts_10s']), str(v['conts_100s']), str(v['conts_inf']), str(v['bkeep_count']), str(v['bkeep_sum']), str(v['bkeep_100ns']), str(v['bkeep_1us']), str(v['bkeep_10us']), str(v['bkeep_100us']), str(v['bkeep_1ms']), str(v['bkeep_10ms']), str(v['bkeep_100ms']), str(v['bkeep_1s']), str(v['bkeep_10s']), str(v['bkeep_100s']), str(v['bkeep_inf']) ) table.add_row("SUM", '', str(total['sleeps']), str(total['conts_count']), str(total['conts_sum']), str(total['conts_100ns']), str(total['conts_1us']), str(total['conts_10us']), str(total['conts_100us']), str(total['conts_1ms']), str(total['conts_10ms']), str(total['conts_100ms']), str(total['conts_1s']), str(total['conts_10s']), str(total['conts_100s']), str(total['conts_inf']), str(total['bkeep_count']), str(total['bkeep_sum']), str(total['bkeep_100ns']), str(total['bkeep_1us']), str(total['bkeep_10us']), str(total['bkeep_100us']), str(total['bkeep_1ms']), str(total['bkeep_10ms']), str(total['bkeep_100ms']), str(total['bkeep_1s']), str(total['bkeep_10s']), str(total['bkeep_100s']), str(total['bkeep_inf']), ) return table with Live(generate_table(), refresh_per_second=(1.0/interval)) as live: while True: time.sleep(interval) live.update(generate_table()) if once: break if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("socket") parser.add_argument("--interval", type=float, default=0.5) parser.add_argument("--rich", action="store_true") parser.add_argument("--once", action="store_true", default=False) parser.add_argument("--prom", action="store_true") parser.add_argument("--actors", action="store_true") parser.add_argument("--actdb-membership", action="store_true") args = parser.parse_args() if args.actors: if args.rich: rich_actors(args.socket, args.interval, args.once) else: actors(args.socket, args.interval, args.once) elif args.actdb_membership: if args.rich: rich_actdb_membership(args.socket, args.interval, args.once) else: actdb_membership(args.socket, args.interval, args.once) elif args.prom: prompom(args.socket) elif args.rich: richmon(args.socket, args.interval, args.once) else: mon(args.socket, args.interval, args.once) ================================================ FILE: utils/changelog-find-missing-link-defs.py ================================================ #!/usr/bin/env python3 # Script to find short link refs, like '[#123]' in CHANGELOG.md which we use for # issue and pull request references. Maintaining the list of link definitions at # the end of the doc is a sort of PITA which this script helps with. # # Usage: # kll@Boxy ~/acton$ utils/changelog-find-missing-link-defs.py # Missing link definitions: # [#315]: https://github.com/actonlang/acton/pull/315 # [#431]: https://github.com/actonlang/acton/issues/431 # [#512]: https://github.com/actonlang/acton/pull/512 # [#514]: https://github.com/actonlang/acton/pull/514 # [#527]: https://github.com/actonlang/acton/issues/527 # ... # # Copy the output text and add to CHANGELOG.md # # Sort the output with: '<,'>!awk -F'[\#\\]]' '{ print $2 "\t" $0 }' | sort -n | cut -f 2 import re import requests def find_short_link_refs(lines): res = {} for line in lines: m = re.search(r"[^]](\[#[0-9]+\])[^:[\(]", line) if m: res[m.group(1)] = False return res def find_link_defs(lines): res = {} for line in lines: m = re.search(r"^(\[#[0-9]+\]): (.*)", line) if m: res[m.group(1)] = m.group(2) return res def get_url(tag): # We don't know if a particular number tag is a pull request or an issue. # Github will automatically redirect us though, so we just go pull/{num} and # then check the returned url if it says issue or pull. num = re.sub("[^0-9]", "", tag) r = requests.get(f"https://github.com/actonlang/acton/pull/{num}") return r.url f = open("CHANGELOG.md") lines = f.readlines() f.close() links = find_short_link_refs(lines) defs = find_link_defs(lines) missing = sorted(set(links) - set(defs)) print("Missing link definitions:") for num in missing: url = get_url(num) print(f"{num}: {url}") ================================================ FILE: utils/lldb/README.md ================================================ Acton LLDB Plugin (Prototype) Python plugin to improve debugging of Acton programs in LLDB on macOS. Provides filtered/demangled backtraces, readable locals, and Acton‑aware pretty printing. Commands - `acton bt` — Filtered backtrace with Acton demangling and argument values - Flags: - `-a, --all` include hidden frames (RTS, system) - `-f, --full` include all threads - `--no-demangle` turn off demangling - `--show-original` show original symbol next to demangled - `--hide-regex REGEX` add extra hide regex (repeatable) - `--clear-hides` clear previously added hide regexes - `--color/--no-color` toggle ANSI colors for file:line - `--no-arg-values` do not print argument values in bt - `acton locals` — In‑scope args/locals with demangled names and value summaries - Flags: - `--no-demangle` - `--all` include statics, out‑of‑scope and artificial - `--args-only` only show function arguments - `--no-hide-meta` include meta/runtime variables (by default hides `$`/`__` vars, method tables, `$class`, and `C_cont`) - `acton demangle [name]` — Demangle a single name; if omitted, uses the selected frame function - `acton break :` — Set a breakpoint by Acton source location. Alias: `acton-bp` Aliases - Hyphenated: `acton-bt`, `acton-locals`, `acton-demangle` - Dotted (if your LLDB accepts it): `acton.bt`, `acton.locals`, `acton.demangle` Loading 1) One‑off inside LLDB: - `(lldb) command script import /absolute/path/to/acton/utils/lldb/acton.py` - Reload after edits with `-r`: - `(lldb) command script import -r /absolute/path/to/acton/utils/lldb/acton.py` 2) Auto‑load on startup (`~/.lldbinit`): - `command script import /absolute/path/to/acton/utils/lldb/acton.py` Source breakpoints (Acton file:line) - Requires debug info that references `.act` files (build with `acton --debug`). - Examples: - `(lldb) breakpoint set -f stackdemo.act -l 7` - `(lldb) acton break stackdemo.act:7` - If no locations resolve, the helper prints source‑map hints based on compile units. You can map build paths to your checkout: - `(lldb) settings set target.source-map /old/build/root /Users/me/src/acton` Demangling and name rewrites - Heuristics to improve readability: - `Q_` → `.` (module separators) - `D___` → `.` and `D_` → `.` (method separators) - `G_` → `.` (generic/section) - `$` → `.` (C identifiers like `to$int` → `to.int`) - Drop `B_` prefix for builtins (e.g. `B_str` → `str`) - Drop `U_` prefix for unboxed C locals and trim leading numeric index: `U_5v3` → `v3` - Strip trailing `.local` synthesized from `G_local` Value summaries / pretty printing - Backtrace arguments and locals: - Boxed values are stringified via `B_value.__str__` and printed. This covers objects/actors/classes (e.g. ``), builtin numbers, etc. - Strings (`B_str`) are read directly and printed quoted (UTF‑8, with escaping). - Unboxed C types (e.g. `uint64_t`, `int64_t`) use LLDB’s native formatting. - The CPS continuation arg `C_cont` is hidden by default in `acton locals` and excluded from bt arg lists. - If stringification fails, we fall back to numeric conversions for simple builtins, then raw pointer. Colors - By default, `acton bt` prints file:line with colors (file in cyan, line in yellow). Use `--no-color` or set `ACTON_LLDB_NO_COLOR=1` to disable. Environment overrides - `ACTON_LLDB_HIDE_REGEX` — comma‑separated regexes to hide symbol names - `ACTON_LLDB_NO_DEMANGLE` — disable demangling - `ACTON_LLDB_SHOW_ORIGINAL` — print original symbol next to demangled - `ACTON_LLDB_NO_COLOR` / `ACTON_LLDB_COLOR` — control colors - `ACTON_LLDB_NO_ARG_VALUES` — disable argument value printing in bt Batch usage examples - Quick one‑liner: - `lldb examples/stackdemo -o 'command script import utils/lldb/acton.py' -o 'b stackdemo.act:7' -o 'run' -o 'acton locals' -o 'acton bt' --batch` - With module‑wide breakpoints: - `lldb -o 'command script import utils/lldb/acton.py' -o 'br s -r "stackdemoQ_.*"' -o run -- examples/stackdemo` Troubleshooting - Ensure your binary has debug info pointing at `.act` files (compile with `acton --debug`). - If bt/locals do not show Acton files, check source‑map settings. - If value printing is slow or too verbose in bt, pass `--no-arg-values`. Notes - This is a prototype; the demangler is heuristic. We can refine as needed and later move these capabilities to a native C++ plugin for deeper integration. ================================================ FILE: utils/lldb/acton.py ================================================ """ Acton LLDB plugin Features: - acton.bt: filtered backtrace with basic Acton demangling - acton.locals: print locals with Acton demangled names - acton.demangle: demangle a single symbol or the selected frame name Load in LLDB: (lldb) command script import /path/to/repo/utils/lldb/acton.py (lldb) acton.bt """ from __future__ import annotations import lldb # type: ignore import argparse import os import re from typing import List, Optional # ------------------------------ # Config and defaults # ------------------------------ DEFAULT_HIDE_FILE_SUBSTR = [ # "/base/rts/", # "/base/builtin/", "/deps/", ] DEFAULT_HIDE_SYMBOL_REGEX = [ r"^uv_", # libuv internals r"^pthread_", # r"^__.*", # many system trampolines, but could also conflict perhaps? TODO: figure this out r"^_sigtramp$", r"^start$", r"^start_wqthread$", ] DEFAULT_HIDE_MODULE_SUBSTR = [ "libsystem_", "libdispatch", "libdyld", "libobjc.A.dylib", "libc++.", ] class Config: def __init__(self) -> None: self.hide_file_substrings: List[str] = list(DEFAULT_HIDE_FILE_SUBSTR) self.hide_symbol_res: List[re.Pattern[str]] = [ re.compile(p) for p in DEFAULT_HIDE_SYMBOL_REGEX ] self.hide_module_substrings: List[str] = list(DEFAULT_HIDE_MODULE_SUBSTR) self.enable_demangle: bool = True self.show_original: bool = False self.enable_color: bool = True self.show_arg_values: bool = True CFG = Config() # ------------------------------ # Demangler (heuristic) # ------------------------------ _re_q_sep = re.compile(r"Q_") _re_d_magic = re.compile(r"D___") # e.g. $ActorD___init__ _re_d_sep = re.compile(r"D_") # general Derived separator, e.g. mainD_foo -> main.foo _re_g_sep = re.compile(r"G_") def demangle_acton(name: str) -> str: """Demangling of Acton/RTS symbol - Replace module separators: 'Q_' -> '.' (e.g. actonQ_rtsQ_X -> acton.rts.X) - Convert runtime method separators: 'D___' -> '.' (.__init__/__call__ etc.) - Convert generic/section separators: 'G_' -> '.' - Replace '$' with '.' to improve readability (e.g., to$int -> to.int) - Trim leading '$' or common C prefixes ("_" on Darwin) while preserving name content. """ if not name: return name # Darwin symbols may be prefixed with '_' if name.startswith("_"): name = name[1:] # Quick return for plain C names, but still allow builtin/unboxed prefix stripping. # Include 'U_' so we don't early-return for unboxed locals like U_5v3. if ("$" not in name) and ("Q_" not in name) and ("D___" not in name) and ("G_" not in name) and ("B_" not in name) and ("U_" not in name): return name s = name s = _re_q_sep.sub(".", s) s = _re_d_magic.sub(".", s) s = _re_d_sep.sub(".", s) s = _re_g_sep.sub(".", s) # Drop builtin prefix 'B_' (B_str -> str, B_dict -> dict, etc.) s = re.sub(r"\bB_", "", s) # Drop unboxed prefix 'U_' used by codegen for C locals (U_5v3, U_tmp) s = re.sub(r"\bU_", "", s) # After removing U_, drop any leading numeric index left by codegen: 5v3 -> v3, 6v4 -> v4 s = re.sub(r"^\d+([A-Za-z].*)$", r"\1", s) # Drop trailing ".local" produced from G_local (local method variant marker) if s.endswith(".local"): s = s[: -len(".local")] # Remove possible duplicate dots created by substitutions # s = re.sub(r"\.\.+", ".", s) # Trim leading dot if introduced s = s[1:] if s.startswith(".") else s return s def maybe_demangle(name: str) -> str: if not CFG.enable_demangle: return name try: d = demangle_acton(name) return d except Exception: return name # ------------------------------ # Utilities # ------------------------------ def _frame_is_hidden(frame: lldb.SBFrame) -> bool: # By file path le = frame.GetLineEntry() if le and le.IsValid(): fs = le.GetFileSpec() if fs and fs.IsValid(): path = os.path.join(fs.GetDirectory() or "", fs.GetFilename() or "") for part in CFG.hide_file_substrings: if part in path: return True # By module image mod = frame.GetModule() if mod and mod.IsValid(): mod_name = mod.GetFileSpec().GetFilename() or "" for part in CFG.hide_module_substrings: if part in mod_name: return True # By symbol name regex sym_name = frame.GetFunctionName() or frame.GetSymbol().GetName() or "" for rex in CFG.hide_symbol_res: try: if rex.search(sym_name or ""): return True except Exception: # Ignore miscompiled regex pass return False def _format_frame(idx: int, frame: lldb.SBFrame) -> str: pc = frame.GetPCAddress() load_addr = pc.GetLoadAddress(frame.GetThread().GetProcess().GetTarget()) fn = frame.GetDisplayFunctionName() or frame.GetFunctionName() or frame.GetSymbol().GetName() or "?" demangled = maybe_demangle(fn) args_str = _format_args(frame) if CFG.show_original and demangled != fn: name_part = f"{demangled}{args_str} [{fn}]" else: name_part = f"{demangled}{args_str}" le = frame.GetLineEntry() if le and le.IsValid(): fs = le.GetFileSpec() filename = fs.GetFilename() or "?" line_no = le.GetLine() # Colorize file and line to match LLDB feel loc = _fmt_file_line(filename, line_no) else: loc = "?" return f"#{idx:2d} 0x{load_addr:x} {name_part} at {loc}" def _iter_frames(only_visible: bool, thread: Optional[lldb.SBThread] = None): if thread is None: thread = lldb.debugger.GetSelectedTarget().process.GetSelectedThread() if not thread or not thread.IsValid(): return [] frames = [] for f in thread: if only_visible and _frame_is_hidden(f): continue frames.append(f) return frames # ------------------------------ # LLDB Commands # ------------------------------ def cmd_bt(debugger: lldb.SBDebugger, command: str, exe_ctx: lldb.SBExecutionContext, result: lldb.SBCommandReturnObject, _internal_dict=None) -> None: # noqa: D401 """acton.bt: Print a filtered backtrace with demangling. Usage: acton.bt [-a|--all] [-f|--full] [--no-demangle] [--show-original] [--hide-regex REGEX ...] [--clear-hides] -a/--all: include hidden frames -f/--full: include all threads (not just selected) --no-demangle: disable demangling --show-original: show original name alongside demangled --hide-regex: add extra hide regex for symbol names (repeatable) --clear-hides: clear all custom hide regexes """ try: parser = argparse.ArgumentParser(prog="acton.bt", add_help=False) parser.add_argument("-a", "--all", action="store_true") parser.add_argument("-f", "--full", action="store_true") parser.add_argument("--no-demangle", action="store_true") parser.add_argument("--show-original", action="store_true") parser.add_argument("--hide-regex", action="append", default=[]) parser.add_argument("--clear-hides", action="store_true") parser.add_argument("--color", dest="color", action="store_true") parser.add_argument("--no-color", dest="no_color", action="store_true") parser.add_argument("--no-arg-values", action="store_true", help="do not print argument values in bt") opts = parser.parse_args(shlex_split(command)) except SystemExit: # argparse error; show help result.PutCString(cmd_bt.__doc__ or "") result.SetStatus(lldb.eReturnStatusFailed) return CFG.enable_demangle = not opts.no_demangle CFG.show_original = bool(opts.show_original) if opts.color: CFG.enable_color = True if opts.no_color: CFG.enable_color = False if opts.no_arg_values: CFG.show_arg_values = False if opts.clear_hides: CFG.hide_symbol_res = [] for r in (opts.hide_regex or []): try: CFG.hide_symbol_res.append(re.compile(r)) except re.error as e: result.PutCString(f"Invalid regex '{r}': {e}") target = debugger.GetSelectedTarget() proc = target.process if not proc or not proc.IsValid(): result.PutCString("No process. Run or attach first.") result.SetStatus(lldb.eReturnStatusFailed) return threads = list(proc) printed_any = False def print_thread(th: lldb.SBThread): nonlocal printed_any header = f"thread #{th.GetIndexID()}" result.PutCString(header) frames = _iter_frames(not opts.all, th) for idx, fr in enumerate(frames): result.PutCString(_format_frame(idx, fr)) printed_any = True if opts.full: for th in threads: print_thread(th) else: print_thread(proc.GetSelectedThread()) if not printed_any: result.PutCString("No frames to display.") def cmd_locals(debugger: lldb.SBDebugger, command: str, exe_ctx: lldb.SBExecutionContext, result: lldb.SBCommandReturnObject, _internal_dict=None) -> None: # noqa: D401 """acton.locals: Print current frame locals with demangled names. Usage: acton.locals [--no-demangle] [--all] [--args-only] [--no-hide-meta] Defaults mimic `frame variable` more closely: - show only in-scope arguments + locals - exclude statics and artificial (compiler-generated) variables """ try: parser = argparse.ArgumentParser(prog="acton.locals", add_help=False) parser.add_argument("--no-demangle", action="store_true") parser.add_argument("--all", action="store_true", help="include statics, out-of-scope, artificial") parser.add_argument("--args-only", action="store_true", help="only show function arguments") parser.add_argument("--no-hide-meta", action="store_true", help="do not hide Acton meta vars (methods/class)") opts = parser.parse_args(shlex_split(command)) except SystemExit: result.PutCString(cmd_locals.__doc__ or "") result.SetStatus(lldb.eReturnStatusFailed) return frame = exe_ctx.GetFrame() if hasattr(exe_ctx, "GetFrame") else None if not frame or not frame.IsValid(): result.PutCString("No selected frame.") result.SetStatus(lldb.eReturnStatusFailed) return demangle_on = CFG.enable_demangle and not opts.no_demangle show_args = True show_locals = not opts.args_only show_statics = bool(opts.all) in_scope_only = not opts.all vals = frame.GetVariables(show_args, show_locals, show_statics, in_scope_only) def is_meta_var(val: lldb.SBValue, dname: str, type_name: str) -> bool: # Hide common Acton meta artifacts raw = val.GetName() or "" if hasattr(val, "IsArtificial") and val.IsArtificial(): return True # Names that look like vtable/method tables if dname.endswith(".methods") or dname.endswith(".$class") or dname.endswith(".class"): return True # Types that are class/method tables if "G_class" in type_name or type_name.endswith(".class"): return True # Heuristic: internal $-prefixed or double-underscore names if raw.startswith("$") or raw.startswith("__"): return True return False printed = 0 def _label_from_gcinfo(v: lldb.SBValue) -> Optional[str]: try: base = v.Dereference() if v.TypeIsPointerType() else v if not base or not base.IsValid(): return None cls = base.GetChildMemberWithName("$class") if not cls or not cls.IsValid(): return None cls_d = cls.Dereference() if cls.TypeIsPointerType() else cls gc = cls_d.GetChildMemberWithName("$GCINFO") if not gc or not gc.IsValid(): return None addr = gc.GetValueAsUnsigned() if not addr: return None proc = v.GetTarget().GetProcess() err = lldb.SBError() s = proc.ReadCStringFromMemory(addr, 256, err) if (err.Success() or not err.Fail()) and s: return maybe_demangle(s) return None except Exception: return None for v in vals: if not v or not v.IsValid(): continue name = v.GetName() or "?" # Hide CPS continuation argument in locals by default if name == "C_cont" and not opts.no_hide_meta: continue dname = demangle_acton(name) if demangle_on else name type_name = maybe_demangle(v.GetTypeName() or "") if not type_name or type_name in ("$WORD", "WORD"): lbl = _label_from_gcinfo(v) if lbl: type_name = lbl if not opts.no_hide_meta and is_meta_var(v, dname, type_name): continue try: # Prefer LLDB's summary providers (works in DAP), fallback to our eval-based summary summary = v.GetSummary() or _acton_value_summary(v, exe_ctx) or v.GetValue() or "" except Exception: summary = v.GetValue() or "" summary = (summary or "").strip() if type_name: line = f"{dname}: {type_name} = {summary}" else: line = f"{dname} = {summary}" result.PutCString(line) printed += 1 if printed == 0: result.PutCString("(no in-scope arguments/locals)") def cmd_demangle(debugger: lldb.SBDebugger, command: str, exe_ctx: lldb.SBExecutionContext, result: lldb.SBCommandReturnObject, _internal_dict=None) -> None: # noqa: D401 """acton.demangle: Demangle a raw Acton/RTS name or the current frame. Usage: acton.demangle [raw_name] If no name is provided, demangle the selected frame function. """ raw = command.strip() if not raw: frame = exe_ctx.GetFrame() if hasattr(exe_ctx, "GetFrame") else None if not frame or not frame.IsValid(): result.PutCString("No selected frame and no name provided.") result.SetStatus(lldb.eReturnStatusFailed) return raw = frame.GetDisplayFunctionName() or frame.GetFunctionName() or frame.GetSymbol().GetName() or "" if not raw: result.PutCString("No symbol name found.") result.SetStatus(lldb.eReturnStatusFailed) return result.PutCString(maybe_demangle(raw)) # ------------------------------ # Registration # ------------------------------ def __lldb_init_module(debugger: lldb.SBDebugger, _internal_dict) -> None: # Group commands under 'acton' # Register commands (multiple spellings for compatibility with LLDB parser) # Dotted form (may be ambiguous on some LLDB builds) _add_cmd(debugger, "acton.bt", cmd_bt, "Filtered backtrace with Acton demangling") _add_cmd(debugger, "acton.locals", cmd_locals, "Print locals with Acton demangled names") _add_cmd(debugger, "acton.demangle", cmd_demangle, "Demangle a symbol or current frame") # Hyphenated aliases _add_cmd(debugger, "acton-bt", cmd_bt, "Filtered backtrace with Acton demangling") _add_cmd(debugger, "acton-locals", cmd_locals, "Print locals with Acton demangled names") _add_cmd(debugger, "acton-demangle", cmd_demangle, "Demangle a symbol or current frame") # Group command with subcommands: `acton bt|locals|demangle` _add_cmd(debugger, "acton", cmd_root, "Acton command group: bt | locals | demangle") # Breakpoint helper _add_cmd(debugger, "acton.break", cmd_break, "Set breakpoint at Acton file:line") _add_cmd(debugger, "acton-bp", cmd_break, "Set breakpoint at Acton file:line") # Environment-driven config (optional) _apply_env_overrides() print("Acton LLDB plugin loaded. Commands: acton bt|locals|demangle; aliases: acton-bt, acton-locals, acton-demangle, acton.bt, acton.locals, acton.demangle") try: _register_formatters() except Exception: # Keep plugin usable even if formatters fail to register pass def _add_cmd(debugger: lldb.SBDebugger, name: str, func, help_text: str) -> None: # Register a Python function as an LLDB command. # Keep this compatible with stock LLDB on macOS (no SBCommandPluginInterface). # Use --overwrite so reloads work without manual settings tweaks. debugger.HandleCommand( f"command script add --overwrite -f {__name__}.{func.__name__} {name}" ) # Note: LLDB doesn't expose a stable API to set rich help text here. # The function's docstring is shown when you run `help {name}`. def _apply_env_overrides() -> None: # ACTON_LLDB_HIDE_REGEX: comma-separated regexes rx = os.getenv("ACTON_LLDB_HIDE_REGEX") if rx: for r in rx.split(","): r = r.strip() if not r: continue try: CFG.hide_symbol_res.append(re.compile(r)) except re.error: pass # ACTON_LLDB_NO_DEMANGLE: if set, disable demangling if os.getenv("ACTON_LLDB_NO_DEMANGLE"): CFG.enable_demangle = False # ACTON_LLDB_SHOW_ORIGINAL: if set, print original symbol alongside demangled if os.getenv("ACTON_LLDB_SHOW_ORIGINAL"): CFG.show_original = True if os.getenv("ACTON_LLDB_NO_COLOR"): CFG.enable_color = False if os.getenv("ACTON_LLDB_COLOR"): CFG.enable_color = True if os.getenv("ACTON_LLDB_NO_ARG_VALUES"): CFG.show_arg_values = False # ------------------------------ # Data formatters (type summaries) # ------------------------------ def _expr_opts() -> lldb.SBExpressionOptions: opts = lldb.SBExpressionOptions() opts.SetIgnoreBreakpoints(True) opts.SetUnwindOnError(True) opts.SetLanguage(lldb.eLanguageTypeC) return opts def _read_cstring(valobj: lldb.SBValue, char_ptr_val: lldb.SBValue, max_len: int = 2048) -> Optional[str]: try: if not char_ptr_val or not char_ptr_val.IsValid(): return None addr = char_ptr_val.GetValueAsUnsigned() if not addr: return None process = valobj.GetTarget().GetProcess() err = lldb.SBError() s = process.ReadCStringFromMemory(addr, max_len, err) if (err.Success() or not err.Fail()) and s is not None: return s return None except Exception: return None def sum_B_str(valobj: lldb.SBValue, _internal_dict) -> Optional[str]: """Summary for B_str values: print quoted UTF-8 string.""" try: ty = valobj.GetTypeName() or "" ptr = valobj.GetValue() or "" # Prefer calling fromB_str to get a C string pointer if ptr.startswith("0x"): expr = f"(char*)fromB_str(({ty}){ptr})" sev = valobj.EvaluateExpression(expr, _expr_opts()) s = _read_cstring(valobj, sev) if s is not None: s = s.replace('\\', r'\\').replace('"', r'\"') return f'"{s}"' # Fallback: read fields directly base = valobj.Dereference() if valobj.TypeIsPointerType() else valobj if not base or not base.IsValid(): return None nb = base.GetChildMemberWithName("nbytes") sp = base.GetChildMemberWithName("str") if nb and nb.IsValid() and sp and sp.IsValid(): nbytes = nb.GetValueAsUnsigned() addr = sp.GetValueAsUnsigned() if nbytes and addr: process = valobj.GetTarget().GetProcess() err = lldb.SBError() data = process.ReadMemory(addr, int(nbytes), err) if (err.Success() or not err.Fail()) and data is not None: try: s = data.decode('utf-8', errors='replace') s = s.replace('\\', r'\\').replace('"', r'\"') return f'"{s}"' except Exception: return None return None except Exception: return None def _summary_via___str__(valobj: lldb.SBValue) -> Optional[str]: try: ptr = valobj.GetValue() or "" if not ptr.startswith("0x"): return None # Dynamically dispatch via vtable: ((B_value)ptr)->$class->__str__((B_value)ptr) expr = f"(char*)fromB_str(((B_value){ptr})->$class->__str__(((B_value){ptr})))" sev = valobj.EvaluateExpression(expr, _expr_opts()) return _read_cstring(valobj, sev) except Exception: return None def _summary_via_gcinfo(valobj: lldb.SBValue) -> Optional[str]: try: base = valobj.Dereference() if valobj.TypeIsPointerType() else valobj if not base or not base.IsValid(): return None cls = base.GetChildMemberWithName("$class") if cls and cls.IsValid(): cls_d = cls.Dereference() if cls.TypeIsPointerType() else cls gc = cls_d.GetChildMemberWithName("$GCINFO") if gc and gc.IsValid(): gaddr = gc.GetValueAsUnsigned() if gaddr: process = valobj.GetTarget().GetProcess() err = lldb.SBError() gstr = process.ReadCStringFromMemory(gaddr, 256, err) if (err.Success() or not err.Fail()) and gstr: label = maybe_demangle(gstr) ptr = valobj.GetValue() or "?" return f"<{label} object at {ptr}>" return None except Exception: return None def sum_B_value(valobj: lldb.SBValue, _internal_dict) -> Optional[str]: """Generic summary for Acton boxed values: use __str__ → fromB_str.""" # Strings handled by sum_B_str; here we handle everything else try: ty = (valobj.GetTypeName() or "").strip() if "B_str" in ty: return None # Fast paths for common builtins via their specific __str__ ptr = valobj.GetValue() or "" if ptr.startswith("0x"): if "B_int" in ty: # Try to read small integers directly from limbs for speed/robustness try: base = valobj.Dereference() if valobj.TypeIsPointerType() else valobj vfield = base.GetChildMemberWithName("val") if vfield and vfield.IsValid(): sz = vfield.GetChildMemberWithName("size") nfield = vfield.GetChildMemberWithName("n") if sz and sz.IsValid() and nfield and nfield.IsValid(): size = sz.GetValueAsSigned() naddr = nfield.GetValueAsUnsigned() if size == 0: return "0" if abs(size) == 1 and naddr: process = valobj.GetTarget().GetProcess() limb_err = lldb.SBError() limb_bytes = process.ReadMemory(naddr, 8, limb_err) if (limb_err.Success() or not limb_err.Fail()) and limb_bytes is not None and len(limb_bytes) == 8: limb = int.from_bytes(limb_bytes, byteorder='little', signed=False) return f"{-limb if size < 0 else limb}" except Exception: pass # Fallback via __str__ helper expr = f"(char*)fromB_str(B_intD___str__((B_int){ptr}))" sev = valobj.EvaluateExpression(expr, _expr_opts()) s = _read_cstring(valobj, sev) if s is not None: return s elif "B_i64" in ty: expr = f"(char*)fromB_str(B_i64D___str__((B_i64){ptr}))" sev = valobj.EvaluateExpression(expr, _expr_opts()) s = _read_cstring(valobj, sev) if s is not None: return s elif "B_i32" in ty: expr = f"(char*)fromB_str(B_i32D___str__((B_i32){ptr}))" sev = valobj.EvaluateExpression(expr, _expr_opts()) s = _read_cstring(valobj, sev) if s is not None: return s elif "B_i16" in ty: expr = f"(char*)fromB_str(B_i16D___str__((B_i16){ptr}))" sev = valobj.EvaluateExpression(expr, _expr_opts()) s = _read_cstring(valobj, sev) if s is not None: return s elif "B_u64" in ty: expr = f"(char*)fromB_str(B_u64D___str__((B_u64){ptr}))" sev = valobj.EvaluateExpression(expr, _expr_opts()) s = _read_cstring(valobj, sev) if s is not None: return s elif "B_u32" in ty: expr = f"(char*)fromB_str(B_u32D___str__((B_u32){ptr}))" sev = valobj.EvaluateExpression(expr, _expr_opts()) s = _read_cstring(valobj, sev) if s is not None: return s elif "B_u16" in ty: expr = f"(char*)fromB_str(B_u16D___str__((B_u16){ptr}))" sev = valobj.EvaluateExpression(expr, _expr_opts()) s = _read_cstring(valobj, sev) if s is not None: return s elif "B_float" in ty: expr = f"(char*)fromB_str(B_floatD___str__((B_float){ptr}))" sev = valobj.EvaluateExpression(expr, _expr_opts()) s = _read_cstring(valobj, sev) if s is not None: return s elif "B_bool" in ty: # fromB_bool -> C int, but we keep unified path via __str__ to get "True"/"False" expr = f"(char*)fromB_str(B_boolD___str__((B_bool){ptr}))" sev = valobj.EvaluateExpression(expr, _expr_opts()) s = _read_cstring(valobj, sev) if s is not None: return s # Generic: try dynamic __str__ (may fail with unusual toolchains) s = _summary_via___str__(valobj) if s is not None: return s return _summary_via_gcinfo(valobj) except Exception: return None def sum_user_value(valobj: lldb.SBValue, _internal_dict) -> Optional[str]: """Summary for user objects (e.g., stackdemoQ_main): use __str__ fallback.""" try: s = _summary_via___str__(valobj) if s is not None: return s return _summary_via_gcinfo(valobj) except Exception: return None def _register_formatters() -> None: """Register LLDB Python type summaries so `frame variable` and DAP show Acton values.""" if os.getenv("ACTON_LLDB_NO_FORMATTERS"): return dbg = lldb.debugger # Define category (no enable yet to avoid 'empty category enabled' warning) dbg.HandleCommand("type category define Acton") # Add summaries into the Acton category dbg.HandleCommand(f"type summary add -w Acton -F {__name__}.sum_B_str B_str") dbg.HandleCommand(f"type summary add -w Acton -x -F {__name__}.sum_B_value '^B_.*$'") dbg.HandleCommand(f"type summary add -w Acton -x -F {__name__}.sum_user_value '^[A-Za-z_][A-Za-z0-9_]*Q_.*$'") # Many Acton locals show as $WORD/WORD (generic value). Provide a generic summary for those. dbg.HandleCommand(f"type summary add -w Acton -F {__name__}.sum_WORD '$WORD'") dbg.HandleCommand(f"type summary add -w Acton -F {__name__}.sum_WORD 'WORD'") dbg.HandleCommand("type category enable Acton") # Also install essential summaries in the default category so DAP shows them even if Acton is disabled dbg.HandleCommand(f"type summary add -F {__name__}.sum_B_str B_str") dbg.HandleCommand(f"type summary add -x -F {__name__}.sum_B_value '^B_.*$'") dbg.HandleCommand(f"type summary add -F {__name__}.sum_WORD '$WORD'") dbg.HandleCommand(f"type summary add -F {__name__}.sum_WORD 'WORD'") def sum_WORD(valobj: lldb.SBValue, _internal_dict) -> Optional[str]: """Summary for generic Acton value type ($WORD/WORD) — treat as B_value pointer.""" # TODO: we should be able to do better by following $class pointer and figuring out actual type try: s = _summary_via___str__(valobj) if s: return s return _summary_via_gcinfo(valobj) or "" except Exception: return "" # ------------------------------ # Small helpers # ------------------------------ def cmd_root(debugger: lldb.SBDebugger, command: str, exe_ctx: lldb.SBExecutionContext, result: lldb.SBCommandReturnObject, _internal_dict=None) -> None: """Acton command group. Usage: acton bt [options] acton locals [options] acton demangle [name] """ args = shlex_split(command) if not args: result.PutCString(cmd_root.__doc__ or "") return sub = args[0] rest = " ".join(args[1:]) if sub in ("bt",): return cmd_bt(debugger, rest, exe_ctx, result) if sub in ("locals",): return cmd_locals(debugger, rest, exe_ctx, result) if sub in ("demangle",): return cmd_demangle(debugger, rest, exe_ctx, result) if sub in ("bp", "break"): return cmd_break(debugger, rest, exe_ctx, result) result.PutCString(f"Unknown subcommand '{sub}'. Try: bt, locals, demangle") def shlex_split(s: str) -> List[str]: """A minimal shlex split that tolerates LLDB inputs without importing shlex eagerly.""" try: import shlex return shlex.split(s) except Exception: return s.split() # ------------------------------ # Color helpers # ------------------------------ def _c(code: str, s: str) -> str: if not CFG.enable_color: return s return f"\x1b[{code}m{s}\x1b[0m" def _fmt_file_line(filename: str, line: int) -> str: # Match LLDB bt-ish style: file in cyan/teal, line in yellow return f"{_c('36', filename)}:{_c('33', str(line))}" def _format_args(frame: lldb.SBFrame) -> str: try: args = frame.GetVariables(True, # arguments False, # locals False, # statics True) # in_scope_only except Exception: return "()" items: List[str] = [] for v in args: try: name = v.GetName() or "?" if name == "C_cont": continue dname = demangle_acton(name) if CFG.show_arg_values: pretty = _acton_value_summary(v, lldb.SBExecutionContext(frame)) if pretty is not None: val = pretty else: val = v.GetSummary() or v.GetValue() if val is None: items.append(dname) else: sval = str(val).strip() # keep brief; avoid long blobs/newlines if "\n" in sval: sval = sval.split("\n", 1)[0] + " …" if len(sval) > 120: sval = sval[:117] + "…" items.append(f"{dname}={sval}") else: items.append(dname) except Exception: continue return "(" + ", ".join(items) + ")" def _acton_value_summary(val: lldb.SBValue, exe_ctx: lldb.SBExecutionContext) -> Optional[str]: try: raw_name = val.GetName() or "" # Unboxed values start with 'U' — skip boxed pretty-print if raw_name.startswith("U"): return None # Need a pointer value to the boxed object ptr = val.GetValue() or "" if not ptr.startswith("0x"): return None frame = exe_ctx.GetFrame() if hasattr(exe_ctx, "GetFrame") else None if not frame or not frame.IsValid(): return None tyname = val.GetTypeName() or "" process = frame.GetThread().GetProcess() # Generic __str__ path early for non-strings: this covers actors/classes/self and # most builtins (ints, floats, bools) uniformly. We keep a dedicated fast path # for B_str below so strings still get quoted. if "B_str" not in tyname: try: opts0 = lldb.SBExpressionOptions() opts0.SetIgnoreBreakpoints(True) opts0.SetUnwindOnError(True) opts0.SetLanguage(lldb.eLanguageTypeC) sev0 = frame.EvaluateExpression(f"(B_str)B_valueD___str__((B_value){ptr})", opts0) if sev0 and sev0.IsValid() and (not sev0.GetError() or not sev0.GetError().Fail()): s_base0 = sev0.Dereference() if sev0.TypeIsPointerType() else sev0 nb0 = s_base0.GetChildMemberWithName("nbytes") sp0 = s_base0.GetChildMemberWithName("str") if nb0 and nb0.IsValid() and sp0 and sp0.IsValid(): nbytes0 = nb0.GetValueAsUnsigned() addr0 = sp0.GetValueAsUnsigned() if nbytes0 and addr0: err0 = lldb.SBError() data0 = process.ReadMemory(addr0, int(nbytes0), err0) if (err0.Success() or not err0.Fail()) and data0 is not None: try: return data0.decode('utf-8', errors='replace') except Exception: pass except Exception: pass # Integers (boxed) — extract underlying value via from$*/fromB_* int_expr = None if "B_int" in tyname: # Get B_str via B_int.__str__ and read bytes opts = lldb.SBExpressionOptions() opts.SetIgnoreBreakpoints(True) opts.SetUnwindOnError(True) opts.SetLanguage(lldb.eLanguageTypeC) sev = frame.EvaluateExpression(f"(B_str)B_intD___str__((B_int){ptr})", opts) if sev and sev.IsValid() and (not sev.GetError() or not sev.GetError().Fail()): s_base = sev.Dereference() if sev.TypeIsPointerType() else sev nb = s_base.GetChildMemberWithName("nbytes") sp = s_base.GetChildMemberWithName("str") if nb and nb.IsValid() and sp and sp.IsValid(): nbytes = nb.GetValueAsUnsigned() addr = sp.GetValueAsUnsigned() if nbytes and addr: errn = lldb.SBError() data = process.ReadMemory(addr, int(nbytes), errn) if (errn.Success() or not errn.Fail()) and data is not None: try: return data.decode('utf-8', errors='replace') except Exception: pass # Field-based quick path for small ints base = val.Dereference() if val.TypeIsPointerType() else val if base and base.IsValid(): vfield = base.GetChildMemberWithName("val") if vfield and vfield.IsValid(): sz = vfield.GetChildMemberWithName("size") nfield = vfield.GetChildMemberWithName("n") if sz and sz.IsValid() and nfield and nfield.IsValid(): size = sz.GetValueAsSigned() naddr = nfield.GetValueAsUnsigned() if size == 0: return "0" if abs(size) == 1 and naddr: limb_err = lldb.SBError() limb_bytes = process.ReadMemory(naddr, 8, limb_err) if (limb_err.Success() or not limb_err.Fail()) and limb_bytes is not None and len(limb_bytes) == 8: limb = int.from_bytes(limb_bytes, byteorder='little', signed=False) if size < 0: return f"-{limb}" else: return str(limb) # Fallback: try to get numeric value if available (may fail due to '$' in name) int_expr = f"from$int((B_int){ptr})" elif "B_i64" in tyname: int_expr = f"fromB_i64((B_i64){ptr})" elif "B_i32" in tyname: int_expr = f"fromB_i32((B_i32){ptr})" elif "B_i16" in tyname: int_expr = f"fromB_i16((B_i16){ptr})" elif "B_u64" in tyname: int_expr = f"fromB_u64((B_u64){ptr})" elif "B_u32" in tyname: int_expr = f"fromB_u32((B_u32){ptr})" elif "B_u16" in tyname: int_expr = f"fromB_u16((B_u16){ptr})" if int_expr is not None: opts = lldb.SBExpressionOptions() opts.SetIgnoreBreakpoints(True) opts.SetUnwindOnError(True) opts.SetLanguage(lldb.eLanguageTypeC) iev = frame.EvaluateExpression(int_expr, opts) if iev and iev.IsValid() and (not iev.GetError() or not iev.GetError().Fail()): ival = iev.GetValue() if ival is not None: return str(ival) # if failed, fall through # Booleans if "B_bool" in tyname: opts = lldb.SBExpressionOptions() opts.SetIgnoreBreakpoints(True) opts.SetUnwindOnError(True) opts.SetLanguage(lldb.eLanguageTypeC) bev = frame.EvaluateExpression(f"fromB_bool((B_bool){ptr})", opts) if bev and bev.IsValid() and (not bev.GetError() or not bev.GetError().Fail()): bval = bev.GetValueAsUnsigned() return "True" if bval else "False" # Floats if "B_float" in tyname: opts = lldb.SBExpressionOptions() opts.SetIgnoreBreakpoints(True) opts.SetUnwindOnError(True) opts.SetLanguage(lldb.eLanguageTypeC) fev = frame.EvaluateExpression(f"fromB_float((B_float){ptr})", opts) if fev and fev.IsValid() and (not fev.GetError() or not fev.GetError().Fail()): fval = fev.GetValue() if fval is not None: return str(fval) # Special-case B_str: read bytes directly to avoid null-termination issues if "B_str" in tyname: base = val.Dereference() if val.TypeIsPointerType() else val if not base or not base.IsValid(): return None nb = base.GetChildMemberWithName("nbytes") sp = base.GetChildMemberWithName("str") if nb and nb.IsValid() and sp and sp.IsValid(): nbytes = nb.GetValueAsUnsigned() addr = sp.GetValueAsUnsigned() if nbytes and addr: err = lldb.SBError() data = process.ReadMemory(addr, int(nbytes), err) if err.Success() and data is not None: try: s = data.decode('utf-8', errors='replace') # Quote string values for clarity s = s.replace('\\', r'\\').replace('"', r'\"') return f'"{s}"' except Exception: return None # Fall through to generic path if direct read fails # Generic path: get char* from __str__ quickly and read C-string cexpr = f"(char*)fromB_str(B_valueD___str__((B_value){ptr}))" opts = lldb.SBExpressionOptions() opts.SetIgnoreBreakpoints(True) opts.SetUnwindOnError(True) # C works, and the target is compiled as C; allow summary providers opts.SetLanguage(lldb.eLanguageTypeC) cev = frame.EvaluateExpression(cexpr, opts) if cev and cev.IsValid(): caddr = cev.GetValueAsUnsigned() if caddr: e3 = lldb.SBError() cstr = process.ReadCStringFromMemory(caddr, 512, e3) if (e3.Success() or not e3.Fail()) and cstr is not None: return cstr # Last-resort fallback for objects (actors/classes): use $class->$GCINFO try: base = val.Dereference() if val.TypeIsPointerType() else val if base and base.IsValid(): cls = base.GetChildMemberWithName("$class") if cls and cls.IsValid(): cls_d = cls.Dereference() if cls.TypeIsPointerType() else cls gc = cls_d.GetChildMemberWithName("$GCINFO") if gc and gc.IsValid(): gaddr = gc.GetValueAsUnsigned() if gaddr: gerr = lldb.SBError() gstr = process.ReadCStringFromMemory(gaddr, 256, gerr) if (gerr.Success() or not gerr.Fail()) and gstr: label = maybe_demangle(gstr) return f"<{label} object at {ptr}>" except Exception: pass return None except Exception: return None def cmd_break(debugger: lldb.SBDebugger, command: str, exe_ctx: lldb.SBExecutionContext, result: lldb.SBCommandReturnObject, _internal_dict=None) -> None: """acton.break: Set a breakpoint at Acton file:line Usage: acton break test.act:37 acton break test.act 37 Notes: - Requires DWARF with Acton file paths (acton --debug recommended) - If it resolves to 0 locations, you may need a source-map. """ s = command.strip() if not s: result.PutCString(cmd_break.__doc__ or "") result.SetStatus(lldb.eReturnStatusFailed) return file = None line = None if ":" in s and not s.startswith(":"): file, _, rest = s.partition(":") try: line = int(rest.strip()) except Exception: pass else: parts = shlex_split(s) if len(parts) == 2: file, line_s = parts try: line = int(line_s) except Exception: line = None if not file or not line: result.PutCString("Usage: acton break : or acton break ") result.SetStatus(lldb.eReturnStatusFailed) return target = debugger.GetSelectedTarget() if not target or not target.IsValid(): result.PutCString("No target. Create or run a target first.") result.SetStatus(lldb.eReturnStatusFailed) return # Try to set breakpoint by file:line fs = lldb.SBFileSpec() fs.SetFilename(os.path.basename(file)) # If a directory was included, set it as well dname = os.path.dirname(file) if dname: fs.SetDirectory(dname) bp = target.BreakpointCreateByLocation(fs, int(line)) if bp and bp.IsValid() and bp.GetNumLocations() > 0: result.PutCString(f"Breakpoint {bp.GetID()}: {bp.GetNumLocations()} locations at {file}:{line}") return # Fallback: try matching compile units with same basename to hint source-map hinted = False from_dirs = set() for mod in target.module_iter(): for i in range(mod.GetNumCompileUnits()): cu = mod.GetCompileUnitAtIndex(i) cu_fs = cu.GetFileSpec() if cu_fs and cu_fs.IsValid() and cu_fs.GetFilename() == os.path.basename(file): from_dirs.add(cu_fs.GetDirectory()) hinted = True if hinted and from_dirs: for src_dir in sorted(from_dirs): result.PutCString( f"Hint: DWARF references '{os.path.basename(file)}' under '{src_dir}'. If your sources live elsewhere, use:\n" f" settings set target.source-map {src_dir} " ) result.PutCString(f"No locations resolved for {file}:{line}. Ensure the binary has debug info (acton --debug) and source-map is correct.") result.SetStatus(lldb.eReturnStatusFailed) ================================================ FILE: utils/update-changelog.sh ================================================ #!/usr/bin/env bash claude --dangerously-skip-permissions 'Update CHANGELOG.md based on the git log. Review git commits from the latest versioned release git tag and make sure they are covered by an entry in the changelog. If it is not covered, check `git log -U` for the particular commit in order to understand what was done and why, then write an entry for CHANGELOG.md. Use the keepachangelog.com format. Keep the same tone and style already used in CHANGELOG.md - we want a brief, concice, technical no-nonsense tone. It is OK to intermingle examples - this is appreciated by users who can immediately understand the effects of a change' ================================================ FILE: version.mk ================================================ VERSION=0.27.0 ================================================ FILE: workspace/MRO.hs ================================================ -- Copyright (C) 2019-2021 Data Ductus AB -- -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- -- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -- -- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -- -- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- module MRO where type Name = String type Bases = [Name] type ClassDef = (Name,Bases) type Graph = [ClassDef] type WName = ([Maybe Name],Name) type WBases = [WName] type WClassDef = (Name,WBases) type WGraph = [WClassDef] -- With witnesses: mro :: Graph -> IO () mro graph = do mapM (putStrLn . uncurry showclass) graph putStrLn "----" mro' [] graph mro' :: WGraph -> Graph -> IO () mro' lins [] = return () mro' lins ((c,bases):graph) = case merge [] (map lin wbases ++ [wbases]) of Right cs -> do putStrLn (showlin c cs) mro' ((c,cs):lins) graph Left err -> putStrLn err where wbases = case bases of [] -> []; n:ns -> ([Nothing],n) : [ ([Just n],n) | n <- ns ] lin :: WName -> WBases lin (is,n) = case lookup n lins of Just la -> (is,n) : [ (is++w,x) | (w,x) <- la ] Nothing -> error ("Forward ref from " ++ c ++ " to " ++ n) merge :: WBases -> [WBases] -> Either String WBases merge out lists | null heads = Right $ reverse out | h:_ <- good = merge (h:out) [ if snd hd == snd h then tl else hd:tl | (hd,tl) <- zip heads tails ] | otherwise = Left (">>>>>> " ++ showlin c (reverse out) ++ " ++ merge(" ++ commasep id (map showlist lists) ++ ") <<<<<<<") where (heads,tails) = unzip [ (hd,tl) | hd:tl <- lists ] good = [ h | h <- heads, all (snd h `notElem`) (map (map snd) tails) ] showlin :: Name -> WBases -> String showlin c cs = "L(" ++ c ++ ") = " ++ showlist cs showlist cs = "[" ++ commasep wshow cs ++ "]" wshow (w,x) = wsh w ++ ": " ++ x where wsh [] = "" wsh [n] = wsh' n wsh (n:w) = wsh' n ++ "." ++ wsh w wsh' Nothing = "_" wsh' (Just n) = n commasep f [] = "" commasep f [x] = f x commasep f (x:xs) = f x ++ ", " ++ commasep f xs showclass c bases = c ++ "(" ++ commasep id bases ++ ")" -- Alternative formulation: type Env = [WClassDef] linearize :: Env -> ClassDef -> WClassDef linearize env (c,bases) = (c, merge [] $ map lin wbases ++ [wbases]) where wbases = case bases of [] -> []; n:ns -> ([Nothing],n) : [ ([Just n],n) | n <- ns ] lin :: WName -> [WName] lin (w,a) = (w,a) : [ (w++w',x) | (w',x) <- la ] where Just la = lookup a env merge :: [WName] -> [[WName]] -> [WName] merge out lists | null heads = reverse out | h:_ <- good = merge (h:out) [ if equal hd h then tl else hd:tl | (hd,tl) <- zip heads tails ] | otherwise = error (">>>>>> " ++ showlin c (reverse out) ++ " ++ merge(" ++ commasep id (map showlist lists) ++ ") <<<<<<<") where (heads,tails) = unzip [ (hd,tl) | hd:tl <- lists ] good = [ h | h <- heads, all (absent h) tails ] equal :: WName -> WName -> Bool equal (_,a) (_,b) = a == b absent :: WName -> [WName] -> Bool absent (_,h) tl = h `notElem` map snd tl mro2 :: Env -> Graph -> IO () mro2 env [] = mapM (putStrLn . uncurry showlin) (reverse env) >> return () mro2 env (g:graph) = mro2 (lmap:env) graph where lmap = linearize env g -- Examples from https://www.python.org/download/releases/2.3/mro/ ex0 = [("O",[]), ("X",["O"]), ("Y",["O"]), ("A",["X","Y"]), ("B",["Y","X"]), ("C",["A","B"])] -- fails ex1 = [("O",[]), ("F",["O"]), ("E",["O"]), ("D",["O"]), ("C",["D","F"]), ("B",["D","E"]), ("A",["B","C"])] -- ok ex2 = [("O",[]), ("F",["O"]), ("E",["O"]), ("D",["O"]), ("C",["D","F"]), ("B",["E","D"]), ("A",["B","C"])] -- ok ex3 = ex0 -- fails ex4 = [("O",[]), ("F",["O"]), ("E",["F"]), ("G",["F","E"])] -- fails ex5 = [("O",[]), ("F",["O"]), ("E",["F"]), ("G",["E","F"])] -- ok ex6 = [("O",[]), ("A",["O"]), ("C",["A","A"])] -- fails ex7 = [("O",[]), ("A",["O"]), ("B",["O"]), ("C",["O"]), ("D",["O"]), ("E",["O"]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z",["K1","K2","K3"])] -- ok ex8a = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("Z",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["Z","K1"]), ("Z2",["Z","K2"]), ("Z3",["Z","K3"]), ("Z_tot",["Z3","Z2","Z1"])] -- ok ex8b = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("Z",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["Z","K1","K2"]), ("Z2",["Z","K3"]), ("Z_tot",["Z2","Z1"])] -- fails ex8c = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("Z",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["Z","K1","K3"]), ("Z2",["Z","K2"]), ("Z_tot",["Z2","Z1"])] -- ok ex8d = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("Z",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["Z","K2","K3"]), ("Z2",["Z","K1"]), ("Z_tot",["Z1","Z2"])] -- fails ex8e = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("Z",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["Z","K1"]), ("Z2",["Z","K2","K3"]), ("Z_tot",["Z2","Z1"])] -- fails ex8f = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("Z",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["Z","K2"]), ("Z2",["Z","K1","K3"]), ("Z_tot",["Z2","Z1"])] -- ok ex8g = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("Z",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["Z","K3"]), ("Z2",["Z","K1","K2"]), ("Z_tot",["Z2","Z1"])] -- fails ex8h = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["K1"]), ("Z2",["Z1","K2"]), ("Z3",["Z2","K3"])] -- fails ex8i = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["K1"]), ("Z2",["Z1","K3"]), ("Z3",["Z2","K2"])] -- ok ex8j = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["K1"]), ("Z2",["Z1","K2","K3"])] -- ok ex8k = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["K3"]), ("Z2",["Z1","K2"]), ("Z3",["Z2","K1"])] -- ok ex8l = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["K2","K3"]), ("Z3",["Z1","K1"])] -- fails ex8m = [("A",[]), ("B",[]), ("C",[]), ("D",[]), ("E",[]), ("K1",["A","B","C"]), ("K2",["D","B","E"]), ("K3",["D","A"]), ("Z1",["K3"]), ("Z3",["Z1","K1","K2"])] -- ok ex9a = [("Eq",[]), ("Ord",["Eq"]), ("a",["Ord"])] -- ok ex9b = [("Eq",[]), ("Ord",["Eq"]), ("a",["Eq"]), ("a1",["Ord","a"])] -- ok ex9c = [("Eq",[]), ("Ord",["Eq"]), ("a",["Ord"]), ("a1",["Eq","a"])] -- fails ex10a = [("Rational",[]), ("Integer",["Rational"]), ("tt",["Integer","Rational"])] -- ok ex10b = [("Rational",[]), ("Integer",["Rational"]), ("tt",["Rational","Integer"])] -- fails ex10c = [("Rational",[]), ("Integer",["Rational"]), ("tt",[]), ("tt_IntRat",["tt","Integer","Rational"])] -- ok ex10d = [("Rational",[]), ("Integer",["Rational"]), ("tt",[]), ("tt_RatInt",["tt","Rational","Integer"])] -- fails ex10e = [("Rational",[]), ("Integer",["Rational"]), ("tt",[]), ("tt_Rational",["tt","Rational"]), ("tt_Integer",["tt_Rational","Integer"])] -- ok ex10f = [("Rational",[]), ("Integer",["Rational"]), ("tt",[]), ("tt_Integer",["tt","Integer"]), ("tt_Rational",["tt_Integer","Rational"])] -- ok! ex10x = [("Rational",[]), ("Integer",["Rational"]), ("tt",[]), ("tt_Integer",["tt","Integer"]), ("tt_Rational",["tt","Rational"]), ("tt_tot",["tt_Integer","tt_Rational"])] -- ok ex10y = [("Rational",[]), ("Integer",["Rational"]), ("tt",[]), ("tt_Integer",["tt","Integer"]), ("tt_Rational",["tt","Rational"]), ("tt_tot",["tt_Rational","tt_Integer"])] -- ok ex10g = [("Rational",[]), ("Integer",["Rational"]), ("tt",["Rational"]), ("tt_Integer",["tt","Integer"])] -- ok ex10h = [("Rational",[]), ("Integer",["Rational"]), ("tt",["Integer"]), ("tt_Rational",["tt","Rational"])] -- ok! ex11 = [("Rational",[]), ("Integer",["Rational"]), ("Eq",[]), ("Ord",["Eq"]), ("tt",[]), ("tt_1",["tt","Integer","Rational"]), ("tt_2",["tt","Ord"]), ("tt_tot",["tt_2","tt_1"])] -- ok ex12a = [("Eq",[]), ("Ord",["Eq"]), ("Apa",["Eq"]), ("Bepa",["Apa","Ord"])] -- Bepa,Apa,Ord,Eq ex12b = [("Eq",[]), ("Ord",["Eq"]), ("Apa",["Eq"]), ("Bepa",["Ord","Apa"])] -- Bepa,Ord,Apa,Eq ex13a = [("Eq",[]), ("Ord",["Eq"]), ("Hmm",["Eq"]), ("Apa",["Ord"]), ("Bepa",["Apa","Hmm"])] -- Bepa,Apa,Ord,Hmm,Eq ex13b = [("Eq",[]), ("Ord",["Eq"]), ("Hmm",["Eq"]), ("Apa",["Ord"]), ("Bepa",["Apa","Hmm","Ord"])] -- Bepa,Apa,Hmm,Ord,Eq ex14a = [("Apa",[]), ("Bepa",["Apa"]), ("Cepa",["Apa"]), ("Depa",["Cepa","Bepa"])] -- Depa,Cepa,Bepa,Apa ex14b = [("Apa",[]), ("Bepa",["Apa"]), ("Cepa",["Apa"]), ("Depa",["Cepa","Bepa"]), ("Xtra",["Bepa"]), ("Epa",["Depa","Xtra","Bepa"])] -- Epa,Depa,Cepa,Xtra,Bepa,Apa ex14c = [("Apa",[]), ("Bepa",["Apa"]), ("Cepa",["Apa"]), ("Depa",["Cepa","Bepa"]), ("Xtra",["Apa"]), ("Epa",["Depa","Xtra","Cepa"])] -- Epa,Depa,Xtra,Cepa,Bepa,Apa ex15 = [("G",[]), ("F",[]), ("E",[]), ("D",["G","F"]), ("C",["F"]), ("B",["E","F"]), ("A",["B","C","D"])] -- A,B,E,C,D,G,F ex16 = [("Eq",[]), ("Ord",["Eq"]), ("Hmm",["Eq","Ord"])] -- fails ------------------------------------------------------------------------------------------------------------------------------------------------ -- Desired extension semantics: ex17a = [("A",[]), -- A ("B",["A"]), -- B, A ("C",["A"]), -- C, A ("D",["C","B"]), -- D, C, B, A ("str_D",["D"])] -- str_D, D, C, B, A ex17b = [("A",[]), -- A ("B",["A"]), -- B, A ("C",["A"]), -- C, A ("str_CB",["C","B"])] -- str_CB, C, B, A ex17c = [("A",[]), -- A ("B",["A"]), -- B, A ("C",["A"]), -- C, A ("str_A",["A"]), -- str_A, A ("str_B",["str_A","B"]), -- str_B, str_A, B, A ("str_C",["str_B","str_A","C"])] -- str_C, str_B, str_A, B, C, A ex17d = [("A",[]), -- A ("B",["A"]), -- B, A ("C",["A"]), -- C, A ("str_B",["B"]), -- str_B, B, A <--- implicit A dep ("str_C",["str_B","C"])] -- str_C, str_B, B, C, A ex17e = [("A",[]), -- A ("B",["A"]), -- B, A ("C",["B","A"]), -- C, B, A ("str_A",["A"]), -- str_A, A ("str_B",["str_A","B"]), -- str_B, str_A, B, A ("str_C",["str_B","str_A","C"])] -- str_C, str_B, str_A, C, B, A ex17f = [("A",[]), -- A ("B",["A"]), -- B, A ("C",["B","A"]), -- C, B, A ("str_B",["B"]), -- str_B, B, A ("str_C",["str_B","C"])] -- str_C, str_B, C, B, A <--- implicit A dep -- Conclusion: a single multi-extension left->right corresponds to *accumulating* extensions top->down. -- That is, later extensions cover earlier ones, but protocol methods (the method defaults) only -- apply for methods implemented in neither of the extensions. ----------------------------------------------------------------------------------------------------------------------------------------------- ex18 = [("A",[]), ("B",["A"]), ("C",["A"]), ("str_A",["A"]), ("str_B",["B"]), ("str_C",["C"]), ("str_tot",["str_C","str_B","str_A"])] -- str_tot,str_C,C,str_B,B,str_A,A <--- bad, picks C before str_B... ex20a = [("A",[]), ("B",["A"]), ("C",["A"]), ("D",["B","C"])] ex20b = [("A",[]), ("B",["A"]), ("C",["A"]), ("D",["B","C"]), ("E",["D"])] ex20c = [("A",[]), ("B",["A"]), ("C",["A"]), ("D",["B","C"]), ("E",[]), ("F",["D","E"])] --------------- ex21a = [("Eq",[]), ("Ord",["Eq"]), ("Eq$set",["Eq"]), ("Ord$set",["Ord","Eq$set"])] ex21b = [("Eq",[]), ("Ord",["Eq"]), ("Eq$set",["Eq"]), ("Ord$set",["Eq$set","Ord"])] ex21c = [("Eq",[]), ("Ord",["Eq"]), ("Container",[]), ("Set",["Container","Ord"]), ("Eq$set",["Eq"]), ("Ord$set",["Ord","Eq$set"]), ("Set$set",["Set","Ord$set"])] ex21d = [("Eq",[]), ("Ord",["Eq"]), ("Container",[]), ("Set",["Container","Ord"]), ("Eq$set",["Eq"]), ("Ord$set",["Eq$set","Ord"]), ("Set$set",["Ord$set","Set"])] ex21e = [("Eq",[]), ("Ord",["Eq"]), ("Container",[]), ("Set",["Container","Ord"]), ("Ord$set",["Ord"]), ("Ord$set$2",["Ord$set","Ord"])] -- Succeeds... Acceptable? Or detect by a separate check? ex22 = [("Eq",[]), ("Ord",["Eq"]), ("Plus",[]), ("Minus",[]), ("Logical",[]), ("Complex",["Ord","Plus","Minus"]), ("Real",["Complex"]), ("Rational",["Real"]), ("Integral",["Rational","Logical"])] -- Rational,Real,Complex,Ord,Eq,Plus,Minus,Logical -- Indexed Iterable -- | | -- | | -- Sliceable Collection Plus -- | | | -- | | | -- Sequence <-------- <-------------- -- | -- | -- Sequence$list ex23 = [("Plus",[]), ("Indexed",[]), ("Iterable",[]), ("Sliceable",["Indexed"]), ("Collection",["Iterable"]), ("Sequence",["Sliceable","Collection","Plus"]), ("Sequence$list",["Sequence"])] -- Sequence,Sliceable,Indexed,Collection,Iterable,Plus -- (Indexed) Iterable Indexed -- | | | -- | | | -- (Sliceable) Collection Plus Sliceable -- | | | | -- | | | | -- Sequence <-------- <-------------- Sliceable$list -- | | -- | | -- Sequence$list <----------------------------------- ex24 = [("Plus",[]), ("Indexed",[]), ("Iterable",[]), ("Sliceable",["Indexed"]), ("Collection",["Iterable"]), ("Sequence",["Sliceable","Collection","Plus"]), ("Sliceable$list",["Sliceable"]), ("Sequence$list",["Sliceable$list","Sequence"])] -- Sliceable$list,Sequence,Sliceable,Indexed,Collection,Iterable,Plus -- (Indexed) Iterable -- | | -- | | -- Sliceable Collection Plus Indexed -- | | | | -- | | | | -- Sequence <-------- <-------------- Indexed$list -- | | -- | | -- Sequence$list <----------------------------------- ex25 = [("Plus",[]), ("Indexed",[]), ("Iterable",[]), ("Sliceable",["Indexed"]), ("Collection",["Iterable"]), ("Sequence",["Sliceable","Collection","Plus"]), ("Indexed$list",["Indexed"]), ("Sequence$list",["Indexed$list","Sequence"])] -- Indexed$list,Sequence,Sliceable,Indexed,Collection,Iterable,Plus -- Indexed Iterable -- | | -- | | -- (Iterable) Sliceable Collection Plus -- | | | | -- | | | | -- (Collection) Sequence <-------- <-------------- -- | | -- | | -- Container Sequence$list -- | | -- | | -- Container$list <-- ex26 = [("Plus",[]), ("Indexed",[]), ("Iterable",[]), ("Sliceable",["Indexed"]), ("Collection",["Iterable"]), ("Sequence",["Sliceable","Collection","Plus"]), ("Container",["Collection"]), ("Sequence$list",["Sequence"]), ("Container$list",["Sequence$list","Container"])] -- Sequence$list,Sequence,Sliceable,Indexed,Container,Collection,Iterable,Plus ================================================ FILE: workspace/Plan-scribble.txt ================================================ Acton II (scribble) ------------------- A. Language * Syntax of types. fun1 : (int) -> (float,float) -> str fun2 : (int,int,bool) -> bool fun3 : (int,int,bool) -> (int,int) fun4 : ((int,int),bool) -> (int,int) fun5 : ((int,int,bool)) -> (int,int) fun6 : (int,(int,),bool) -> str fun7 : () -> str dict1 : {str:(float,float)} dict2 : {(int,str):apa} fun8 : (A,B) -> bool \\ ElementOf(A,B) fun9 : (A,B) -> {A:B} \\ Hashable(A) fun9 : (A,B) -> {A:B} \ Hashable(A) fun9 : (A,B) -> {A:B} / Hashable(A) fun9 : apa(A) \\ Hashable(A) def fun9(a,b): return {a:b} x = fun9([1,2,3],"apa") def fun2(x:int, y:int, z:bool) -> bool: c = (a,b) = f(3) return z type apa(A) = (A,B) -> {A:B} f : (A) -> Apa(A) \\ Hashable(A) g : (int) -> Apa(int) fun13 : (Apa(int),(int)->str) -> Apa(str) fun14 : (Apa(A),(A)->B) -> Apa(B) fun15 : ((apa:[A],bepa:{int:A}), (A)->B) -> (apa:[A],bepa:{int:B}) [1,2,3] : [int] {'x':1,'y':2} : {str:int} {1,2,3} : {int} [1,2,3] : frozenlist(int) {'x':1,'y':2} : frozendict(str,int) {1,2,3} : frozenset(int) [1,2,3] : list(int) {'x':1,'y':2} : dict(str,int) {1,2,3} : set(int) [1,2,3] : A(int) \\ IsList(A) {'x':1,'y':2} : A(str,int) \\ IsDict(A) {1,2,3} : A(int) \\ IsSet(A) list([1,2,3]) : list(int) list(x) : list(int) list : (A(B)) -> list(B) \\ IsList(A) frozenlist : (A(B)) -> frozenlist(B) \\ IsList(A) frozenlist : A(B) -> frozenlist(B) \\ IsList(A) [1,2,3] : list(int) {'x':1,'y':2} : dict(str,int) {1,2,3} : set(int) [1,2,3] : list(int) {'x':1,'y':2} : dict(str,int) {1,2,3} : set(int) ![1,2,3] : list(int) !{'x':1,'y':2} : dict(str,int) !{1,2,3} : set(int) mut([1,2,3]) : list(int) mut({'x':1,'y':2}) : dict(str,int) mut({1,2,3}) : set(int) struct(A): f : (A,int) -> bool d : (A) -> bool d : sync new (int) -> bool e : sync () -> None f : (a,b) -> () g : (a,b) -> None kalle : sync () -> None def kalle(): pass class C(): def __init__(self, x, y): self.x = x self.y = y def sum(self): return self.x + self.y # instance Eq C: def __eq__(self:C,other:C): return self.x == other.x and self.y == other.y def __ne__(self,other): return self.x != None class D(C): def __init__(self, x,y,z): C.__init__(self,x,y) self.z = z def __eq__(self:D,other:D): return self.z == other.z and C.__eq__(self,other) c : C = C(1,2) d : D = D(1,2,3) c == c : bool ----> C.__eq__(c,c) c == d : bool ----> C.__eq__(c,d) d == d : bool ----> D.__eq__(d,d) d == c : bool ----> C.__eq__(d,c) --/--> D.__eq__(d,c) class Eq(): def __eq__(a,b): a.x == b.x and a.y == b.y class Ord(Eq): def __le__(a,b): a.x <= b.x and a.y <= b.y struct Apa(): x: int y: int kalle(*None) p : struct((int,str)) p.f((1,""),7) def f(x) : bool f((1,"",pi)) : bool h : (int,str,float) -> bool h(1,"",pi) : bool x : (int,str,float) h(*x) g : (int) -> bool g(7) : bool x : T = (1,"",pi) x,y = f(a,b,c) * Named interfaces / tagged unions struct Apa[]: pass struct Bepa[A](Apa[A]): b : A struct Cepa[A](Apa[A],Basetype): c1 : str = "" c2 : Apa[A] struct Depa[A]: pass # struct Epa[A] (Bepa[A],Cepa[A]): x : Apa[int] x = f(...) x = Bepa(2) x = Bepa(b=2) if isinstance(x,Bepa): b=x.b return b elif isinstance(x,Cepa): if x.c1 == "" and isinstance(x.c2,Fepa): return 0 else: s = x.c1 a = x.c2 return ... else: ... return x.b if isinstance(x,Bepa) else (0 if x.c1=="" and isinstance(x.c2,Fepa) else ...) if isinstance(x,Cepa) else ... lambda x: x.b : ((b:A,**R)) -> A ######### (c.f. Haskell) data Apa a = Bepa a | Cepa {c1::String, c2::Apa a} | Depa f (Bepa b) v | v > 0 = r+g where r = ... g = ... f (Cepa "" 0) 6 = ... f a x = ... f a x = case (a,x) of (Bepa b, _) -> ... (Cepa "" 0, 6) -> ... _ -> ... ########### Proposal: struct Apa[A]: case Bepa: b : A case Cepa: c1 : str c2 : Apa[A] case Depa: pass x : Apa[int] = Bepa(4) switch x: case Bepa(4): ... case Bepa(5): ... case Cepa(c1,c2): ... case Depa(): ... ############## (Selection from tuples) t = (1,"",false) t[0] t[1] t[2] def f(x,i): t = (1,"",false) return t.0 return t[0] return t[i] return x[i] ############## (Subtyping / type inheritance) struct Basetype (Embryo): base : str struct Apa[A]: case Bepa: x: A y: int z: A case Cepa (Basetype): c0: int c1: str c2: Apa[A] case Depa: b:int case Epa: s: str r: Apa[str] b: int case Fepa: pass struct Gepa[A] (Fepa[A]) f1: float f2: bool f3: A struct Hepa[A] (Fepa[A]): case Iepa: i1: int i2: (int),int)->int case Jepa: pass ############ (The diamond problem) module M: struct A: x: [int] module N: import M struct A: x: int struct B: y: str struct C: A B ma: M.A v: C = ... v.x v.b.x v.ma.x v.B.x v.A.x v.M.A.x f(v) g(v) f(v.ma) def f(p): print(p.x) def f(p): print(p.y) struct A(T): a: T struct B: A(int) struct C: A(str) struct D: B C d = D(a=3) b: B = d b.a c: C = d c.a == b.a == d.a * Pattern matching ##### Clumsy: def f(Bepa(b)): .... def f(Cepa("",Fepa)): ... ##### Nice: def f(a, x): switch a, x: case (Bepa(b),v) and v>b and fib(b) > 100000000 : ... case Cepa("",0), 6: ... case Cepa(c1,c2), i: ... case (Bepa(b),v): ... else: ... def f(u): var x : Apa(_) y : str z : Blaj({str}) x = Bepa(base="",b=u) x = Bepa(Fepa) x = Cepa("",Epa("huh",Fepa)) switch x: case Bepa: b = x.b x.base x.0.base case Bepa(b): return b+23 case Cepa(c2=Fepa,c1=""): return 0 case Cepa(s, a): return ... else: return b if x case Bepa(b) and b>0 else 0 return x if f(x) else None if f(x): return x else: return None * Comprehension syntax for x,y in zip("abcdefghij", range(10)): print(x,y) for x in "abcdefghij" and y in range(10): print(x,y) return [ for x in "abcdefghij" and y in range(10): (x,y) ] return [ for x in "abcdefghij": for y in range(10): (x,y) ] return [ for x in range(10): if x%3==0: for y in range(x): (x,y) ] for x in range(10): if x%3==0: for y in range(x): print(x,y) return [ (x,y) for x in range(10) if x%3==0 for y in range(x) ] some_struct = (a = 1, b = "world") fun_struct = (a = lambda x:x+1, b = lambda s:"hello "+s) ( for (v=k) in some_struct: v = fun_struct.v(k) ) == (a = 2, b = "hello world") ( v = fun_struct.v(k) for (v=k) in some_struct ) == (a = 2, b = "hello world") some_struct = {'a' : 1, 'b' : "world") fun_struct = {'a' : lambda x:x+1, 'b' : lambda s:"hello "+s) { for v,k in some_struct.items(): v: fun_struct.v(k) } == {'a' : 2, 'b' : "hello world"} { v: fun_struct.v(k) for v,k in some_struct.items() } == {'a' : 2, 'b' : "hello world"} #################### x : (a:int,b:bool) y : (k:str,l:str) x = (a=1,b=True) def f(y): return (v=4,**x, b=False, **y, k="") ================================================ FILE: workspace/Plan.txt ================================================ 2021-02-02: X Convert NameInfo envs to format of later passes X Make CPSEnv and LiftEnv instances of Env X Update CPS and Lifter passes to latest syntax X Convert NameInfo envs in Normalize X Convert NameInfo envs in CPS and Lifter as well 2h 8h X Make NormEnv an instance of Env 1h 1h X Make GenEnv an instance of Env 1h 1h X Let CPS make decisions based on true type 1d 2d X Ensure new vars in Normalize, CPS and Lifter are fully typed 2d 3d X Revisit Lifter on classes (now restricted to top level) 1d 2d X Generate custom $Clos subclasses in Lifter 1d 2d X Infer @property signatures based on __init__ assignments 2d 4d X Type-convert plain classes as well 3h 6h X Sample actor state ref'd within lambdas before closure conversion 1d 1d X Introduce special constructor GName for unaliased names 4h 8h X Fill out gaps in CodeGen 2d 5d X Apply typeinfo in CodeGen to insert correct casts 2d 4d X Print generated C code with precedences 2d 3d X Typecheck and convert formatted string literals 1d 2d X Fully defer ASYNC/AWAIT wrapping to the deactorizer pass 1d 2d X Integrate DB sources in build 1d 2d X Set up dedicated rts thread for DB protocol daemon 1d 2d X Add serialization calls to rts 3h 8h X Define Acton Environment type and implement IO loop in rts 1w 2w X Build demo app 2w 4w X Presentation slides 1w 1w - Documentation/tutorial 1w 1w 4w 6w - Sort out conversion from star params/args to tuples - Sort out the pos/kwd parameter parsing ambiguity - Implement pos/kwd and opt relaxation in Solver - Implement Rest/RestI in rts - Eliminate Star-elems in Normalizer - Fix cps translation of effect-polymorphic functions - Translate the root expression as a proper function - Make global __builtin__ witnesses available to Solver - Translate list comprehensions / Handle the with statements - Implement raise and try in the rts - Allow error exceptions to be thrown in from within lub & glb - Make NVar polymorphic but not qualified by inference (c.f. the monomorphism restriction) - Save the import list with each ty-file, fall back to ty-file if source not found when chasing imports Acton II -------- @. Terminology: world - A cluster consisting of 1-N nodes, on a non-partitioning network. in MMO server terms: "an instance" :) Multiple worlds might communicate, but only through a developer-defined interface using sockets. node - A single process contributing in a cluster. The same physical hardware might run multiple node processes (even non-virtualized). First release prio marked as [1] A. Language * Inheritance vs. delegation, examples and convenient syntax. The current Acton language makes use of a limited form of actor inheritance, which leaves several questions (such as access to overridden methods, or visibility of a parent's state variables) unresolved. Define a set of typical examples of inheritance and explore whether the same functionality can be obtained by replacing the super-actor with a local actor instance (a delegate), which is explicitly invoked via its regular interface. Ensure that large sets of the delegate's attributes can be conveniently reexported by the wrapping actor (perhaps using the **var pattern and expression syntax). Then generalize the examples to multiple delegates, and (if experiment is successful) remove actor inheritance from the language. * Import with version hashes/tags Choose a lexical syntax for version hashes/tags that "blends" well with Python's identifier syntax (so that version-completed ) * Syntax of types. Define a concrete syntax of type expressions, to replace the annotation terms in the current Acton grammar. Stay as close to the general Python expression syntax as possible. Some natural choices: (int,bool,str) for tuple types, (x=int,y=float) for anonymous struct types, (int,bool,x=str,y=float)->None for function types, 'tag' for singleton string constant types, int|'tag1'|'tag2' for union types, ?int for option types, single upper-case characters for type variables, any other name for user-defined type constructors, mycon(int,A) for type application, [int] for int lists, {str:int} for dicts, {str} for sets, etc. Things to resolve: distinction between mutable and immutable lists, dicts and sets (use list(A), dict(A,B) and set(B) for the mutable variants?), polymorphic rows (perhaps **R), qualified types (use at all in concrete syntax?), effect annotations on functions (idea: ro sync (A)->B). To recall: type constructors and variables constitute a namespace entirely distinct from the regular terms, even though some constructor names (int, str, list, ...) also exist as valid terms (mostly built-in conversion functions). Invent a syntax for type abbreviations (macros). * Named strutcs / tagged variants Propose a Pythonic construct for declaring immutable named structs (interfaces), that allows multiple super-types (extension), explicit polymorphic type arguments, and preferably also multiple sibling subtypes (tagged variants) to be expressed with little syntactic overhead. Make each name a valid term constructor as well (possily excluding the basetype of variants). Allow type recursion, and a mixture of positional and keyword (field name) arguments in the term constructors. Important to sort out the exact rules that govern field name clashes. * Pattern matching Extend the language with a switch statement, that allows nested patterns of (tagged) structs, tuples, lists, dicts, and atomic types. Allow variable binding, wildcard patterns and guard expressions. Make the syntax "pythonic" and compatible with the tagged variant type declarations. Also introduce an infix case expression that can match against a pattern and bind its variables in any if-branch taken as a direct consequence of a positive match. Define the semantics of pattern-matching in terms of a translation into a form that only uses tag tests (isinstance). * Comprehension syntax Try out an alternative syntax for list comprehensions: '[' COMP EXPR ']', where COMP is 'for' GEN ':' COMP | 'if' EXPR ':' COMP | /* empty */, and GEN is PAT 'in' EXPR. That is, a grammar that mimics the intuitive form of nested statements. Also experiment with the concept of "zip" comprehensions, where GEN can also be GEN 'and' GEN. * Semantics of classes Complete the formal semantics regarding classes and instances. Things to decide: support mutation of the classes themselves? (no...) Make method lookup in base classes explicit? How should the 'isinstance' operator be defined? Can classes inherit from lists/dicts/sets (yes...)? From primitive or immutable types (no...)? * Semantics of recursion Revisit the formal semantics of recursive definitions and see if an explicit notion of top-level bindings can be expressed, which would natively support recursion. If so, ensure that recursion on other levels can be defined in terms of simple lifting to the top level. * Semantics of break/continue Formalize the control flow of loops with break/continue in terms of encodings using exceptions, in order to firmly explain how these features interact. B. Type-system * Encoding of the union type using rows Define the meaning of union types, and the atomic types that can participate in a union, in terms of rows (pretty much analogous to the way effects are expressed as rows). Consequence: atomic types in positive (constructed) positions must become singleton rows with a polymorphic tail, whereas the same types in negative positions must stand for singleton rows with empty tails. Concrete atomic type names are thus mere short-hands for these singleton unions. Also investigate whether the opt type can be encoded in a similar manner (as a union between atomic type None and *any* other type), or whether sub-typing (back-tracking) must be deployed here. * Inference of overloaded constructs using back-tracking Define the set of overloaded constructs that Acton should support as a built-in set of Qualified Types predicates, so that overloading resolution can be implemented as a back- tracking constraint solver. Candidates: truth-value (of almost any type), conversion to/from strings, equality, inequality, identity, attribute selection, indexing, and the overloading required to allow positional function arguments to match named function parameters. Possibly: the subtyping relation between named structs and classes, and the opt type as subtyping. Also investigate which Python "abstractions" that are worth preserving (iterable, sequence, dict view, hashable, context mgr, ...). * Struct comprehensions Explore the theory required to support struct comprehensions, i.e., abstractions over unknown struct types in the form of a set of unknown types indexed by an unknown set of tags. Sort out the details of the struct comprehension expression, as well as any consequences to type inference. * Subtyping or row polymorphism for extended named structs? Evaluate the best way to encode nominal subtyping between user-defined structs and classes -- either using row-polymorphism as the internal representation (which is as fast as unification but requires the compiler to insert type coercion operators at select program places), or by direct subtype constraint solving (which requires weighted searching among the declared subtype axioms but enables subtyping coercions wherever they are required). * Deadlock avoidance analysis Explore the possibility of performing a safe deadlock avoidance analysis at compile-time. Idea: Extend the types of actor ids, actor methods and message handles with a (hidden) unique type variable denoting the *depth* of the receiving actor. Generate inequality constraints at inference time which guarantee that every synchronous call or await operation is directed to an actor of strictly greater depth than the sender. Perform unification and constraint solving as usual, ignoring the depth constraints. Since depth variables can only be unified with other depth variables, the resulting depth constraints must remain a partial order. Use topological sorting to determine whether this order is free of cycles, i.e., whether the synchronous call chain of the original program is deadlock-free. C. Compiler [1] * C back-end Define an abstract syntax of (suitably constrained) C programs and replace the current Acton- to-Python translator with a pass that generates C instead. Avoid the need to maintain type information by approximating every primitive value or pointer to WORD. Map values of primitive types to their C equivalents. Explore 64-bit words for tagging primitive values in unions. Translate class definitions to (linked) method tables. Avoid the idea of terminating each iteration by an exception. [1] * C representation of data Investigate what C representation to use for dicts, lists and sets. Check out what Python does internally. See if list concatenation/extension can be made cheaper at run-time by means of a concat constructor, hidden behind the iterator interface. Sync with the needs of (E). [1] * Reinstalled CPS pass Recover the abandoned CPS code and update it, especially regarding the formal semantics of exceptions and break/continue. Redress it to work on the Acton AST, not Python. Ensure that the decision points (to convert or not convert a function/call) are based solely on inferred effects (no remnants of syntax-based short-cuts). Also convert the lambda-lifter and closure-converter passes to use the proper Acton AST. * More refined effect inference Extend the current effect inference to capture mutation and sync/awaits calls at minimum, possibly also async calls, actor creation and exception-throwing. [1] * Unique name generation Make an overhaul of all compiler passes to ensure they all generate unique names using a global (monadic) name supply. (This means no more semi-clever use of source locations to establish uniqueness!) [1] * Binary interface files Merge in Björn's code to use new (fast!) binary interface files format. * New combinator parser Replace the old LR parser generated by Happy with Björn's alternative based on Megaparsec combinators. Linked to the unique name generation fix above, which will remove the need to retain the old (and heavy) representation of SrcLocations. * Retrofit the type-checker with witness translation to meet the demands of overloading (and possibly subtype coercions). * Complete the code that implements a redesigned tracking of type errors, where unification failures only print the parts of a type that actually differ (git branch 'better-errors'). D. Local RTS [1] Event-loop/reactor, 1 thread-per-logical-core IO via kqueue/epoll/..., files/sockets/devices/... Scheduler: 1. Timer queue Monotonic clock - (perf counter not steady) Via kqueue/(epoll timeout) 2. (Actor) ready queue 3. IO Basic memory management: Malloc wrapper (jemalloc?) No GC Investigate good-enough concurrent data structures (queues, task pool, hashtable, ...) libcuckoo, liblfds, spinlock, mutex Design of async Env Table mapping events/connections to actor context Env: Socket data - std read/write user allocated buffers (DNS lookup?) Exit Implementation of ACTOR MSG CLOSURE ASYNC Post message to target actor queue + ready? Return awaitable-handle SYNC/AWAIT Accepts awaitable-handle POSTPONE Add continuation to timer queue Return cancelable-handle CANCEL Accept cancelable-handle Exception handler stack (per message?) PUSH/POP? [2] Memory management, slab allocator, local garbage-collector Sharing message parameters across continuations? Region-inference for locally used results...? Investigate optimal lock-free shared data structures (queues, task pool, hashtable, ...) Argument and result conventions for various execution contexts Tagging and propagation of root events through method call chains Access to compiled code in the form of dynamic C libraries E. Distributed RTS Conversion from global ids to node id + local pointers (DHT + dynamic placement table?) Conversion from local pointer to global id (globale table or embedded in heap data?) Distributed garbage collection Control message protocol between nodes (multicast/broadcast?) CLI messages for inspection and control Gossip protocol for spreading cluster membership knowledge Dedicated thread for cluster protocol and persistence to disk? I/O? Check-pointing mechanism After an actor has completed a mutating message call, a (diff-)snapshot is made and distributed. Guidance to the snapshot content could probably be provided by the compiler. Track state updates using custom functions at each checkpoint, or use run-time book-keeping machinery Load-balancing based on actor connectivity graph and A * traffic load + B * cpu load + C * memory usage F. Code repository Summary of the global module system design: - All Acton code is conceptually part of a global module structure, that allows unambiguous identification of every Acton module in the world. - An Acton module definition has the following form, where a NAMEPATH is one or more module names connected by a dot (and the indentation of DEFINITIONS is voluntary): module NAMEPATH: DEFINITIONS - A compilation unit is a file containing a module definition. The name and location of such a file is irrelevant, it is the NAMEPATH of the contained module definition that determines the module's place in the Acton module hierarchy. - On the top level, the Acton module system is partitioned into a set of namespaces: * The Acton standard library namespace, identified as 'acton', visible to all Acton developers. * One namespace for every user on every computer where the Acton development system is installed. These namespaces are identified as 'localhost/USERNAME', and are only visible to the users on each particular computer. * A set of namespaces on every internet-connected computer on which an Acton code server runs. These namespaces are written 'DOMAIN.NAME/PATH' and are accessible by every Acton developer on the internet who owns appropriate access credentials. - To cater for evolving code, each Acton namespace exposes a set of versions. A version is identified by a human-friendly version tag, whose exact lexical structure is left unspecified for now. - An Acton development system maintains a local cache of namespace contents at different versions, managed via explicit tool commands. The contents of this cache can also be queried and the result listed as Acton source code. - A module is imported from a specific namespace and at an explicit version by prepending the import statement with a custom "decorator": @NAMESPACE!VERSION import NAMEPATH - A module defined in a specific namespace and at an explicit version is written an analogous way: @NAMESPACE!VERSION module NAMEPATH: DEFINITIONS However, such a definition is only accepted by the Acton compiler if VERSION is either unused in NAMESPACE, or VERSION exists and the new module definition is identical to the existing version. - When a set of modules are compiled at a new version, all other modules of the same namespace are automatically lifted to the new version as well, but with their contents unchanged. This feature can be disabled on the compiler command line for select modules, effectively deleting them from the new version of the namespace. - A module can also be defined with an empty VERSION field: @NAMESPACE module NAMEPATH: DEFINITIONS This results in code being placed in NAMESPACE under an internally generated version string, that is guaranteed to be unique. - Likewise, importing a module without specifying a version implicitly selects the latest version of the referenced namespace that is available in the local namespace cache: @NAMESPACE import NAMEPATH The compiled code is nevertheless stored with the selected namespace version spelled out, making it insensitive to future version upgrades to the local namespace cache. - For completely undecorated module definitions and imports, the following defaults are used: - A module definition without a namespace decoration is equivalent to specifying the namespace 'localhost/USERNAME'. - An un-decorated import statement is resolved in the namespace 'localhost/USERNAME', provided the imported module actually exists in the latest version of 'localhost/USERNAME'. Otherwise the 'acton' namespace is assumed. In both cases, however, the module being compiled is stored in the local module cache with the selected namespace explicitly written out. - It should be noted that the design above makes it fully possible to compile privately produced code into a namespace that legally belongs to some external organization. This is not a security flaw, as the important aspect is not what self-deceptions a developer chooses to believe, but to what extent such deceptions can remain undetected by others. The Acton system takes serious measures to prohibit the latter, although the details of how this is implemented will be deferred to a later discussion. A first implementation sketch: ... G. CLI Creating a running Acton "world" (bootstrap, references an actor def in the global module namespace) Monitor/inspect a running instance (meta info like cpu load, mem usage, traffic, downtimes, io, etc...) Commit new modules (compile and install into repo) Inspect repo (at specific version) Inspect and interact with live actors / run Acton code in sandbox Add/remove cluster nodes A new node is started in a "stand-by" mode, and then instructing the cluster to add the new node Removing a node similarly: instructing the cluster to remove a specific node, making the affected node to enter the same "stand-by" mode. H. Live code upgrade Replacing the living code pointers (atomically or via a message "wave"), using Should the "wave" perform it's update bottom-up? aggregate of conversion functions (lifted to full state converter) if state types don't match I. Security architecture Analysis... When a world is started it is given a private key/cert. This key acts as a CA when adding nodes to the cluster; they must pass a key exchange authentication. BUT: the key must be distributed among all nodes. Is this regarded as "safe"? A new node (to be added into a cluster) is started with a public key, matching the cluster's private key. J. Libraries Basic python: Primitive types: Now: int (bounded to machine word length (64) or overrideable default) bool float64 When needed: (u)int8/16/32/64/128 bigint/integer float32 Data structures: (frozen)list, (frozen)(sorted/ordered)set, (frozen)(sorted/ordered)dict, tuple, str (utf-8), bytes, bytearray, Decimal, BigFloat klib Representation of anonymous structs Built-ins: Now: Data constructors: bool, bytes, bytearray, dict, float, int, list, set, str, tuple Other: enumerate, format, hash, len, (print), range, round, sorted When needed: abs, all, any, ascii, bin, chr, divmod, filter, hex, isinstance, map, max, min, ord, pow, reversed, sum, zip Probably not: frozenset, complex, (.id), iter, next, object, oct, (property), (repr), slice, (super) Source of time duration (monotonic) as python float64 seconds Stopwatch -> float64 (s) String support functions: format, endswith, find, index, is(alnum/...), join, lower, partition, replace, split, startswith, strip, upper Type classes: ContextManager, Hashable, Ordered, Numeric, PrintParse(T1<->bytes/str) (Codec(T1<->T2)) Iterable > Sequence/Indexed Keyed/Dictionary TODO: Design standard typeclasses(-hierarchy) Exceptions - (Those already known to the compiler) [1] NETCONF client utf-8 <-> bytes (stub encode/decode) Struct/dict <-> XML string (parse/print-library) (convert existing python impl to acton) socket, connection interfaces (inspired or modeled after asyncio) IP address/port types Cryptography functionality ssh interface [2] NETCONF server NMDA RFC 8342 NETCONF push NETCONF call home tls interface (?) DateTime (time of day, calendar and such) Binary serialization of primitives etc (byte-order?) Tracker Multi-actor transactions Transactional Causal Consistency with CRDTs (Shapiro's "Cure") Sharding combinators Optimized time-series actors RESTconf server and client Data serialization Converted Python stdlibs REST API server Communication between two Acton worlds. Higher-level protocol services (built upon the async socket IO) http, sctp, etc. These APIs are of course also asynchronous in nature. Wrapped C libraries (ssl, ssh, ...) Akin to swig-wrapped code. K. Examples [1] The classic Demo1! OCP Kristian's core services DT's link provisioning (our demo2++) Time-series illustrative example L. Documentation Tutorial Language reference CLI manual (including sysadmin guide) M. GUI Blinkenlights Web Possibly started by using the CLI, e.g.: `acton web :8000` The same as, or subset of, the read-only operations possible in the CLI, but more "flashy" Live graphs possible Intended for administrators/executives; not a mega visitor-capable web site. N. YANG compiler Perform the two steps (yangc and actc) in one go. O. Installation Make target for building an installer Native MacOS, Ubuntu, RedHat & CentOS No external dependencies! P. Performance tests TBD Q. Open-source (verb!) the classic Acton code R. Automatic test environment How install basic tools? Yes. ================================================ FILE: workspace/Semantics.txt ================================================ ########################################### Abstract syntax ############################################ Variables: x,y Statevars: z Type constants: C Locations: l Actor refs: a,b Message tags: m Integers: i Floats: f Strings: s Expressions: E ::= x | z | V | (A) | lambda F: E | C | E(A) | E.n | E.x | E if E else E | E is E | await E | isinstance(E,C) | do S Actuals: A ::= E,A | *E,M | M | ***E Mappings actuals: M ::= x=E,M | **E | . Formals: F ::= x,F | x=E,F | *x,K | K | ***x Keyword formals: K ::= x,K | x=E,K | **x | . Values: V,W ::= True | False | None | (R) | ---- Only intangible constructs below CLOS(B;F):S | l | a | a.m | (C;B) | ACTOR(V) | ASYNC(a,V) | CLASS(C):B Value rows: R ::= O,B associative Orderings: O ::= O,V | . associative Bindings: B ::= B,x=V | B,C=V | . associative & commutative\duplicates, disjoint C Statements: S ::= E | x = E | (F) = E | D | return E | E.x = E | if E: S else S | while E: S | var z = E | z = E | after E: E' | raise E | try S Z else S finally S | pass | S; S associative, with unit 'pass' Declarations: D ::= def x(F): S | actor x(F): S | class C(C): M | D; D associative & commutative & disjoint Excepts: Z ::= except C as y: S Z | . ---- Only intangible constructs below Global states: G ::= a: | G,G associative, commutative & disjoint Local states: L ::= z=V, L | l=V, L | . associative, commutative & disjoint Queues: Q ::= m=E,Q | . associative & disjoint Histories: H ::= m=V,H | m=do raise V, H | . associative & disjoint E-in-E contexts: EE ::= _.x | _(A) | E if _ else E | V(O,_,A) | V(O,*_,M) | V(O,***_) | V(R,x=_,M) | V(R,**_) | (O,_,A) | (O,*_,M) | (O,***_) | (R,x=_,M) | (R,**_) | _ is E | V is _ | await _ | isinstance(_,C) E-in-S contexts: SE ::= _ | return _ | x = _ | (F) = _ | if _: S else S | _.x = E | var z = _ | z = _ | raise _ | after _: x(A) | after V: _ S-in-S contexts: SS ::= _; S | try _ Z else S finally S E-in-Q contexts: QE ::= H, m=_, Q ####################################### Expression evaluation ########################################## ***** B |- C(C') ******************** B |- C(C) B,C=CLASS(C'):B' |- C(C1) if B |- C'(C1) ***** B |- L | E --> L' | E' ******* B |- L | EE[E] --> L' | EE[E'] if B |- L | E --> L' | E' B |- L | do S --> L' | do S' if B |- L | S --> L' | S' B |- L | E --> L | E' if B |- E --> E' B |- L,z=V | z --> L,z=V | V B |- L,l=(C;B') | l.x --> L,l=(C;B') | V if B' |- x --> V B |- L,l=(C;B') | l.x --> L,l=(C;B') | CLOS(B2,y=l;F):S if x # B' and B |- C.x --> CLOS(B2;y,F):S and @classattr x B |- L,l=(C;B') | l.x --> L,l=(C;B') | V if x # B' and B |- C.x --> V otherwise B |- L | C(R) --> L,l=(C;.) | do l._init_(R); return l if B = B1,C=CLASS(C'):B2 and N |- C(object) B |- L,l=(C;B') | isinstance(l,C') --> L,l=(C;B') | True if B |- C(C') --> L,l=(C;B') | False if not B |- C(C') ***** B |- E --> E' **************** B |- E --> E' if E --> E' B,x=V |- x --> V B |- lambda F: E --> CLOS(B;F): return E B |- (C;B').x --> V if B' |- x --> V B |- (C;B').x --> CLOS(B2,y=(C;B');F):S if x # B' and B |- C.x --> CLOS(B2;y,F):S and @classattr x B |- (C;B').x --> V if x # B' and B |- C.x --> V otherwise B,C=CLASS(C'):B' |- C.x --> V if (B').x --> V B,C=CLASS(C'):B' |- C.x --> V if x # B' and B |- C'.x --> V B |- C(B') --> (C;B') if B = B1,C=CLASS(C'):B2 and N |- C(struct) B |- isinstance((C;B'),C')--> True if B |- C(C') --> False if not B |- C(C') ***** E --> E' ********************* E1 if True else E2 --> E1 E1 if False else E2 --> E2 do B; pass --> None do B; return V --> V if fc(V) # dc(B) do B; raise V --> do raise V if fc(V) # dc(B) EE[do raise V] --> do raise V (O,*(O'),M) --> (O,O',M) (O,B,**(B')) --> (O,B',B) (The binding order...!) V(R) --> do B; (F)=(R); S if V = CLOS(B;F):S (V0,..,Vn,R).n --> Vn (R,x=V).x --> V l is l --> True l is l' --> False if l != l' a is a --> True a is b --> False if a != b ######################################## Statement execution ########################################### ***** B |- L | S --> L' | S' ******* B |- L | SS[S] --> L' | SS[S'] if B |- L | S --> L' | S' B |- L | SE[E] --> L' | SE[E'] if B |- L | E --> L' | E' B |- L | S --> L' | S' if L | S --> L' | S' B |- L | S --> L | S' if B |- S --> S' ***** B |- S --> S' **************** B |- B'; S --> B'; S' if B,B' |- S --> S' B |- S --> S' if S --> S' B |- D --> B' if B,B' |- D ==> B' ***** S --> S' ********************* V; S --> S return V; S --> return V raise V; S --> raise V if True: S1 else S2 --> S1 if False: S1 else S2 --> S2 while E: S --> if E: S; while E: S else pass (x,F) = (V,O,B) --> x = V; (F) = (O,B) (x=E,F) = (None,O,B) --> x = E; (F) = (O,B) (x=E,F) = (V,O,B) --> x = V; (F) = (O,B) (*x,K) = (O,B) --> x = (O); (K) = (B) (***x) = (O,B) --> x = (O,B) (x,K) = (x=V,B) --> x = V; (K) = (B) (x=E,K) = (x=None,B) --> x = E; (K) = (B) (x=E,K) = (x=V,B) --> x = V; (K) = (B) (**x) = (B) --> x = (B) () = () --> pass SE[do raise V] --> raise V try B; S Z else S1 finally S2 --> B; try S Z else S1 finally S2 try return V Z else S1 finally S2 --> S2; return V try pass Z else pass finally S2 --> S2 try pass Z else S1 finally S2 --> try S1 . else pass finally S2 try raise V except C as y: S Z else S1 finally S2 --> try raise V Z else S1 finally S2 if V = (C';B) and C != C' try raise V except C as y: S Z else S1 finally S2 --> try y=V; S . else pass finally S2 if V = (C;B) try raise V . else S1 finally S2 --> S2; raise V ***** L | S --> L' | S' ************ L | B; S --> L' | B; S' if L | S --> L' | S' L | var z=V --> L,z=V | pass L,z=V | z = W --> L,z=W | pass L,l=(C;B) | l.x = V --> L,l=(C;B),x=V | pass if x # B L,l=(C;B),x=W | l.x = V --> L,l=(C;B),x=V | pass ***** B |- D ==> B ***************** B |- def x(F): S ==> x = CLOS(B;F): S B |- actor x(F): S ==> x = ACTOR(CLOS(B;_self_,F):S) B |- class C(C'): M ==> C = CLASS(C'): B' if B |- M ==> B' B |- D1; D2 ==> B1; B2 if B |- D1 ==> B1 and B |- D2 ==> B2 ***** B |- M ==> B ***************** B |- x=y,M ==> x=V,B' if B |- x --> V and B |- M ==> B' B |- . ==> . ######################################### Global reduction ############################################# ***** B |- G --> G' **************** B |- G1, G2 --> G1', G2 if B |- G1 --> G1' B |- a: --> a: if B |- L | E --> L' | E' B |- G --> G' if G --> G' ***** G --> G' ********************* a: --> a: a:, b: --> a:, b: a: --> a:, b:< . | m=V(b,R)> a:, b: --> a:, b: a:, b: --> a:, b: Recent decisions: - Mutable lists, dicts and sets are true class instances (although built-in) - Frozen lists, dicts and sets are true immutable class instances (although built-in) - Automatic coercion of mutable objects into immutable ones is abandoned for now (replaced by explicit conversion calls) - The 'protocol' and 'extension' declarations introduce static overloading, which gets translated into class declaration and explicit witness terms - Attribute selection can thus be overloaded, and supported on any type - Indexed selection and indexed update get translated to overloaded _getitem_ and _setitem_ calls, respectively - Built-in names int, float, str and bool are constructor/conversion functions, supporting multiple argument types via overloading - Class inheritance is single ancestor only (all other types of mix-ins are expressed as protocol adoption) - Classes are the only nominal types, and only these support the 'isinstance' primitive - Narrowing of the option type is done through ==None and !=None comparisons ========================================================================================================= Type inference: - Function arities always match - Short-hand positional arguments are preceeded by explicit keywords - Keyword arguments are in type order - Extra arguments are converted to explicit tupes/records - Missing arguments are replaced by explicit None values - Protocols and extensions are translated into classes - Overloaded names (global or attributes) are explicitly qualified by class - Binary and unary operators are replaced by their corresponding __op__ calls - Indexed and sliced expressions (Index/Slice) are replaced by __getitem__/__getslice__ calls - Assignments to indexed and sliced patterns (PIndex/PSlice) are replaced by __setitem__/__setslice__ calls Normalization: - All imported or built-in names are qualified by module, including those imported by 'from _ import' - All module aliases are replaced by their original module name X All parameters are positional X Parameter defaults are moved inside function definitions - Comprehensions are translated into loops X String literals are concatenated - Tuple (and list) patterns are replaced by a var pattern followed by explicit element assignments - For loops are replaced by while over iterators - With statemenmts are replaced by enter/exit prim calls + exception handling X The assert statement is replaced by a prim call ASSERT - The delete statement is replaced by (a sequence of) __delitem__ calls (for PIndex) or None assignments X Return without argument is replaced by return None - Incremental assignments are replaced by the corresponding __iop__ calls - The else branch of a while loop is replaced by an explicit if statement enclosing the loop Deactorization: - Every actor definition actor a(p): b is translated into class _a(): def __init__(__self__,p): b1 deactorized b \\ bound b4 b2 deactorized b && bound b4 class a(): def __init__(_this_,p): _this_.__self__ = _a(p) b3 bound(b) \\ decls \\ var b4 stored b where - b1 contains all non-def statements in b, where each "var z = e" is replaced by "__self__.z = e" and all local variables are referenced via __self__ - b2 contains one def m(__self__,p):c1 for each "async def m(p):c" in b, where c1 is c with all state and local names referenced via __self__ - b3 contains one assignment _this_.x = _this_.__self__.x for every constant variable "x" defined in b - b4 contains one def m(_this_,p): return ASYNC(_this_.__self__, lambda: _this_.__self__.m(p)) for each "async def m(p):c" in b - Every "await e" expression is translated into AWAIT(e) CPS transformation: - All potentially blocking functions receive continuations - All potentially blocking function calls are converted to tail calls that receive continuation arguments - All calls to continuation parameters are written as "return CONT(cont,value)" - Exception handlers are broken down into continuations and PUSH/POP calls - For loops are replaced by while over iterators Lambda-lifting: - All function definitions are moved either to the top level or to the closest class - Functions lifted to the top level are closed via additional parameters - Functions lifted to a class are closed via additional self attributes - Top-level and method functions in non-calling contexts are replaced by closure constructions UNDECIDED: - Where is self-application (x.m(ps) --> x.m(x,ps)) performed? ================================================ FILE: workspace/Type-hierarchy.act ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ######################################### Type and class hierarchy ############################################### protocol Eq: @static __eq__ : (Self,Self) -> bool @static __ne__ : (Self,Self) -> bool def __ne__(a,b): return not (a == b) ====> "typeclass" Eq[S]: __eq__ : (S,S) -> bool __ne__ : (S,S) -> bool def __ne__(a,b): return not (a == b) ====> class Eq[S](): __eq__ : (S,S) -> bool __ne__ : (S,S) -> bool def __ne__(w,a,b): return not w.__eq__(a,b) ----------------------------------------------------------------- class Fruit (Eq): def __eq__(a, b): return a.weight == b.weight class Apple (Fruit): def __eq__(a, b): return Fruit.__eq__(a,b) and a.appleness == b.appleness class Orange (Fruit): def __eq__(a, b): return Fruit.__eq__(a,b) and a.orangeness == b.orangeness a, b : Apple a == b Eq.__eq__(a,b) x, y : Orange x == y Eq.__eq__(x,y) f1 : Fruit = a f2 : Fruit = x f1 == f2 a == x Eq.__eq__(a,x) ====> class Fruit: ... "instance" Eq[Fruit]: def __eq__(a, b): return a.weight == b.weight class Apple (Fruit): ... "instance" Eq[Apple]: def __eq__(a, b): return Fruit.__eq__(a,b) and a.appleness == b.appleness class Orange (Fruit): ... "instance" Eq[Orange]: def __eq__(a, b): return Fruit.__eq__(a,b) and a.orangeness == b.orangeness ====> class Fruit: weight : int class Eq_Fruit[S(Fruit)] (Eq[S]): def __eq__(w, a:S, b:S): return Eq_int.__eq__(a.weight, b.weight) class Apple (Fruit): appleness : str class Eq_Apple[S(Apple)] (Eq_Fruit[S]): def __eq__(w, a:S, b:S): return Eq_Fruit.__eq__(a,b) and Eq_str(a.appleness, b.appleness) class Orange (Fruit): orangeness : str class Eq_Orange[S(Orange)] (Eq[S]): def __eq__(w, a:S, b:S): return Eq_Fruit.__eq__(a,b) and Eq_str(a.orangeness, b.orangeness) a, b : Apple Eq_Apple.__eq__(a,b) x, y : Orange Eq_Orange.__eq__(x,y) f1 : Fruit = a f2 : Fruit = x Eq_Fruit.__eq__(f1,f2) Eq_Fruit.__eq__(a,x) ----------------------------------------------------------------- protocol Hashable (Eq): __hash__ : () -> int ====> "typeclass" (Eq[S]) => Hashable[S]: __hash__ : (S) -> int ====> class Hashable[S] (Eq[S]): __hash__ : (S) -> int ----------------------------------------------------------------- class Apa(Hashable): x : int def apa(self, y): return self.hash() if y==0 else y def hash(self): return self.x + self.apa(1) ====> class Apa(): x : int def apa(self, w:Hashable[Apa], y): return w.hash(self) if y==0 else y class Hashable_Apa (Hashable[Apa]): def hash(w, self): return self.x + self.apa(w,1) ----------------------------------------------------------------- class MyClass (Hashable): attr1 : int def __eq__(a, b): return a.hash() == b.hash() def hash(self): return self.attr1 my_method: ()->int def my_method(self): return self.hash() class MySubClass (MyClass): attr2 : int def hash(self): return fancy_hash(self.attr2) x, y : MySubClass z : MyClass = y x == y --> Eq.__eq__(x,y) --> MySubClass.hash(x) == MySubClass.hash(y) --> fancy_hash(x.attr2) == fancy_hash(y.attr2) x == z --> Eq.__eq__(x,z) --> MyClass.hash(x) == MyClass.hash(z) --> x.attr1 == z.attr1 y.my_method() --> MySubClass.my_method(y) --> MySubClass.hash(y) --> fancy_hash(y.attr2) z.my_method() --> MySubClass.my_method(z) --> MyClass.hash(z) --> z.attr1 ====> class MyClass: def my_method(self): return hash(self) "instance" Hashable[MyClass]: def __hash__(self): return self.attr1 "instance" Eq[MyClass]: def __eq__(a, b): return hash(a) == hash(b) class MySubClass (MyClass): pass "instance" Hashable[MySubClass]: def __hash__(self): return fancy_hash(self.attr2) ====> class MyClass: attr1 : int my_method : (Hashable(Self))->int # Covariant in Self, since Hashable is a contravariant operator def my_method(self, w:Hashable[Self]): # Note: w:Hashable[MyClass] would render ny_method uninheritable in MySubClass return w.hash(self) class MySubClass (MyClass): attr2 : int class Hashable_MyClass[S(MyClass)] (Hashable[S]): def __eq__(w, a:S, b:S): return Eq_int.__eq__(w.hash(a), w.hash(b)) def hash(w, self:S): return self.attr1 class Hashable_MySubClass[S(MySubClass)] (Hashable_MyClass[S]): def hash(w, self:S): return fancy_hash(self.attr2) x, y : MySubClass z : MyClass = y w0 : Hashable_MyClass w1 : Hashable_MySubClass x == y --> w1.__eq__(x,y) --> Hashable_MySubClass.hash(w1,x) == Hashable_MySubClass.hash(w1,y) --> fancy_hash(x.attr2) == fancy_hash(y.attr2) x == z --> w0.__eq__(x,z) --> Hashable_MyClass.hash(w0,x) == Hashable_MyClass.hash(w0,z) --> x.attr1 == z.attr1 y.my_method() --> y.my_method(w1) --> MySubClass.my_method(y,w1) --> Hashable_MySubClass.hash(w1,y) --> fancy_hash(y.attr2) z.my_method() --> z.my_method(w2) --> MySubClass.my_method(z,w2) --> Hashable_MyClass.hash(w2,z) --> z.attr1 # P1 === Obj(Self) [hash:Int, mymeth:Int, a1:Int] # Class(P1) === [new:P1, hash:All(SelfInt, mymeth:All(SelfInt] # p1_class === [new = sigma(z:Class(P1)) obj(Self=P1) [hash = sigma(s:Self)z.hash(Self)(s), # mymeth = sigma(s:Self)z.mymeth(Self)(s), # a1 = sigma(s:Self)1], # hash = lambda(SelfInt, mymeth:All(SelfInt] # p2_class === [new = sigma(z:Class(P2)) obj(Self=P2) [hash = sigma(s:Self)z.hash(Self)(s), # mymeth = sigma(s:Self)z.mymeth(Self)(s), # a1 = sigma(s:Self)1, # a2 = sigma(s:Self)2], # hash = lambda(Self bool @static __le__ : (Self,Self) -> bool @static __gt__ : (Self,Self) -> bool @static __ge__ : (Self,Self) -> bool def __le__(a,b): return a < b or a == b # return Ord.__lt__(a,b) or Eq.__eq__(a,b) def __gt__(a,b): return b < a # return Ord.__lt__(b,a) def __ge__(a,b): return b <= a # return Ord.__le__(b,a) ====> "typeclass" (Eq[S]) => Ord[S]: __lt__ : (S,S) -> bool __le__ : (S,S) -> bool __gt__ : (S,S) -> bool __ge__ : (S,S) -> bool def __le__(a,b): return a < b or a == b def __gt__(a,b): return b < a def __ge__(a,b): return b <= a ====> class Ord[S] (Eq[S]): __lt__ : (S,S) -> bool __le__ : (S,S) -> bool __gt__ : (S,S) -> bool __ge__ : (S,S) -> bool def __le__(w,a,b): return w.__lt__(a,b) or w.__eq__(a,b) def __gt__(w,a,b): return w.__lt__(b,a) def __ge__(w,a,b): return w.__le__(b,a) ----------------------------------------------------------------- extension int (Eq): def __eq__(a:int, b:int) -> bool: return primeqint(a,b) extension int (Ord): def __lt__(a:int, b:int) -> bool: return primltint(a,b) def __eq__(a:int, b:int) -> bool: # Overrides int._eq_ return primeqint(a,b) ====> "instance" Eq[int]: def __eq__(a:int, b:int) -> bool: return primeqint(a,b) "instance" Ord[int]: def __lt__(a:int, b:int) -> bool: return primltint(a,b) def __eq__(a:int, b:int) -> bool: return primeqint(a,b) ====> class Eq_int (Eq[int]): def __eq__(w, a:int, b:int) -> bool: return primeqint(a,b) class Ord_int (Ord[int]): def __lt__(w, a:int, b:int) -> bool: return primltint(a,b) w1 : Eq[int] = Eq_int() w2 : Ord[int] = Ord_int() ----------------------------------------------------------------- extension int (Ord): # ALTERNATIVELY: A JOINT EXTENSION int (Ord) AND int (Eq) def __eq__(a:int, b:int) -> bool: return primeqint(a,b) def __lt__(a:int, b:int) -> bool: return primltint(a,b) ====> "instance" Ord[int]: def __eq__(a:int, b:int) -> bool: return primeqint(a,b) def __lt__(a:int, b:int) -> bool: return primeqint(a,b) ====> class Ord_int (Ord[int]): def __eq__(w, a:int, b:int) -> bool: return primeqint(a,b) def __lt__(w, a:int, b:int) -> bool: return primeqint(a,b) w2 : Ord[int] = Ord_int() w1 : Eq[int] = w2 ----------------------------------------------------------------- protocol SupportsInt: __int__ : () -> int ====> "typeclass" SupportsInt[S]: __int__ : (S) -> int ====> class SupportsInt[S](): __int__ : (S) -> int ----------------------------------------------------------------- extension int (SupportsInt): def __int__(self:int) -> int return self ====> "instance" SupportsInt[int]: def __int__(self:int) -> int return self ====> class SupportsInt_int (SupportsInt[int]): def __int__(w, self:int) -> int return self ----------------------------------------------------------------- protocol SupportsFloat: __float__ : () -> float ====> "typeclass" SupportsFloat[S]: __float__ : (S) -> float ====> class SupportsFloat[S](): __float__ : (S) -> float ----------------------------------------------------------------- protocol SupportsComplex: __complex__ : () -> complex ====> "typeclass" SupportsComplex[S]: __complex__ : (S) -> complex ====> class SupportsComplex[S](): __complex__ : (S) -> complex ----------------------------------------------------------------- protocol SupportsBytes: __bytes__ : () -> bytes ====> "typeclass" SupportsBytes[S]: __bytes__ : (S) -> bytes ====> class SupportsBytes[S](): __bytes__ : (S) -> bytes ----------------------------------------------------------------- protocol Logical: @static __and__ : (Self,Self) -> Self @static __or__ : (Self,Self) -> Self @static __xor__ : (Self,Self) -> Self ====> "typeclass" Logical[S]: __and__ : (S,S) -> S __or__ : (S,S) -> S __xor__ : (S,S) -> S ====> class Logical[S](): __and__ : (S,S) -> S __or__ : (S,S) -> S __xor__ : (S,S) -> S ----------------------------------------------------------------- protocol Plus: @static __add__ : (Self,Self) -> Self ====> "typeclass" Plus[S]: __add__ : (S,S) -> S ====> class Plus[S](): __add__ : (S,S) -> S ----------------------------------------------------------------- protocol Minus: @static __sub__ : (Self,Self) -> Self ====> "typeclass" Minus[S]: __sub__ : (S,S) -> S ====> class Minus[S](): __sub__ : (S,S) -> S ----------------------------------------------------------------- protocol Number (Ord, Plus, Minus): __pos__ : () -> Self __neg__ : () -> Self @static __mul__ : (Self,Self) -> Self @static __pow__ : (Self,Self) -> Self def __sub__(a,b): return a + (-b) ====> "typeclass" (Ord[S], Plus[S], Minus[S]) => Number[S]: __pos__ : (S) -> S __neg__ : (S) -> S __mul__ : (S,S) -> S __pow__ : (S,S) -> S def __sub__(a:S, b:S): return __add__(a, __neg__(b)) ====> class Plus_Number[S] (Plus[S]): _Number : Number[S] def __add__(w, a, b): return w._Number.__add__(a, b) class Minus_Number[S] (Minus[S]): _Number : Number[S] def __sub__(w, a:S, b:S): # if __sub__ is NOT inherited from Minus return w._Number.__sub__(a, b) class Number[S] (Ord[S]): _Plus : Plus[S] _Minus : Minus[S] __add__ : (S,S) -> S __sub__ : (S,S) -> S __pos__ : (S) -> S __neg__ : (S) -> S __mul__ : (S,S) -> S __pow__ : (S,S) -> S def __sub__(w, a, b): return w.__add__(a, w.__neg__(b)) ----------------------------------------------------------------- extension int (Number): def __pos__(self:int) -> int: return self def __neg__(self:int) -> int: return primnegint(self) def __add__(a:int, b:int) -> int: return primaddint(a,b) def __sub__(a:int, b:int) -> int: return primaddint(a,b) def __mul__(a:int, b:int) -> int: return primmulint(a,b) def __eq__(a:int, b:int) -> bool: return primeqint(a,b) def __lt__(a:int, b:int) -> bool: return primltint(a,b) ====> "instance" Number[int]: def __pos__(self:int) -> int: return self def __neg__(self:int) -> int: return primnegint(self) def __add__(a:int, b:int) -> int: return primaddint(a,b) def __sub__(a:int, b:int) -> int: return primaddint(a,b) def __mul__(a:int, b:int) -> int: return primmulint(a,b) def __eq__(a:int, b:int) -> bool: return primeqint(a,b) def __lt__(a:int, b:int) -> bool: return primltint(a,b) ====> class Plus_int (Plus_Number[int]): def __add__(w, a:int, b:int) -> int: return primaddint(a,b) class Minus_int (Minus_Number[int]): def __sub__(wit, a:int, b:int) -> int: return primsubint(a,b) # def __sub__(w, a:S, b:S): # if not overridden, inherited from Minus_Number # return w._Number._Plus.__add__(a, w._Number.__neg__(b)) class Number_int (Number[int]): def __init__(w): w._Plus = Plus_int(w) w._Minus = Minus_int(w) def __pos__(e, self:int) -> int: return self def __neg__(w, self:int) -> int: return primnegint(self) def __mul__(w, a:int, b:int) -> int: return primmulint(a,b) def __eq__(w, a:int, b:int) -> bool: return primeqint(a,b) def __lt__(w, a:int, b:int) -> bool: return primltint(a,b) ----------------------------------------------------------------- protocol SupportsAbs: __abs__ : () -> Self ====> "typeclass" SupportsAbs[S]: __abs__ : (S) -> S ====> class SupportsAbs[S](): __abs__ : (S) -> S ----------------------------------------------------------------- protocol Complex (Number, SupportsAbs, SupportsComplex): @static __fromcomplex__ : (complex) -> Self @static __div__ : (Self,Self) -> Self real : () -> Real imag : () -> Real conjugate : () -> Self ====> "typeclass" (Number[S],SupportsAbs[S],SupportsComplex[S]) => Complex[S]: __fromcomplex__ : (complex) -> S __div__ : (S,S) -> S real : (S) -> EXISTS[T,Real[T]] imag : (S) -> EXISTS[T,Real[T]] conjugate : (S) -> S ====> class SupportsAbs_Complex[S] (SupportsAbs[S]): _Complex : Complex[S] class SupportsComplex_Complex[S] (SupportsComplex[S]): _Complex : Complex[S] class Complex[S] (Number[S]): _SuppAbs : SupportsAbs[S] _SuppComplex : SupportsComplex[S] __fromcomplex__ : (complex) -> S __div__ : (S,S) -> S real : (S) -> EXISTS[T,Real[T]] imag : (S) -> EXISTS[T,Real[T]] conjugate : (S) -> S ----------------------------------------------------------------- protocol SupportsRound: __round__ : () -> int ====> "typeclass" SupportsRound[S]: __round__ : (S) -> int ====> class SupportsRound[S](): __round__ : (S) -> int ----------------------------------------------------------------- protocol Real (Complex, SupportsRound, SupportsFloat): @static __fromfloat__ : (float) -> Self __trunc__ : () -> Integral __floor__ : () -> Integral __ceil__ : () -> Integral @static __divmod__ : (Self,Self) -> (Self,Self) @static __floordiv__ : (Self,Self) -> Integral @static __mod__ : (Self,Self) -> Self def __complex__(a): return complex(float(a)) def real(a): return fromfloat(float(a)) def imag(a): return fromfloat(0.0) def conjugate(a): return a def divmod(a,b): return (a//b, a%b) ====> "typeclass" (Complex[S],SupportsRound[S],SupportsFloat[S]) => Real[S]: __fromfloat__ : (float) -> S __trunc__ : (S) -> EXISTS[T,Intergral[T]] __floor__ : (S) -> EXISTS[T,Intergral[T]] __ceil__ : (S) -> EXISTS[T,Intergral[T]] __divmod__ : (S,S) -> (S,S) __floordiv__ : (S,S) -> EXISTS[T,Intergral[T]] __mod__ : (S,S) -> S def __complex__(a): return complex(float(a)) def real(a): return a def imag(a): return 0 def conjugate(a): return a def divmod(a,b): return (a//b, a%b) ====> class Plus_Real[S] (Plus_Complex[S]): _Real : Real[S] class Minus_Real[S] (Minus_Complex[S]): _Real : Real[S] class SupportsAbs_Real[S] (SupportsAbs_Complex[S]): _Real : Real[S] class SupportsComplex_Real[S] (SupportsComplex_Complex[S]): _Real : Real[S] class SupportsRound_Real[S] (SupportsRound[S]): _Real : Real[S] class SupportsFloat_Real[S] (SupportsFloat[S]): _Real : Real[S] class Real[S] (Complex[S]): _SuppRound : SupportsRound[S] _SuppFloat : SupportsFloat[S] __fromfloat__ : (float) -> S __trunc__ : (S) -> EXISTS[T,Intergral[T]] __floor__ : (S) -> EXISTS[T,Intergral[T]] __ceil__ : (S) -> EXISTS[T,Intergral[T]] __divmod__ : (S,S) -> (S,S) __floordiv__ : (S,S) -> EXISTS[T,Intergral[T]] __mod__ : (S,S) -> S def __complex__(w,a): return w.__complex__(w.__float__(a)) def real(cls,_w,a): return _w.__fromfloat__(cls.__float__(a)) def imag(cls,_w,a): return _w.__fromfloat__(0.0) def conjugate(cls,a): return a def divmod(cls,a,b): return (cls.__floordiv__(a,b), cls.__mod__(a,b)) ----------------------------------------------------------------- protocol Rational (Real): numerator : () -> Integral denominator : () -> Integral def __float__(a): return numerator(a) / denominator(a) ====> "typeclass" (Real[S]) => Rational[S]: numerator : (Integral[T]) => (S) -> T denominator : (Integral[T]) => (S) -> T def __float__(a): return numerator(a) / denominator(a) ====> class Plus_Rational[S] (Plus_Real[S]): _Number = Rational class Minus_Rational[S] (Minus_Real[S]): _Number = Rational class SupportsAbs_Rational[S] (SupportsAbs_Real[S]): _Complex = Rational class SupportsComplex_Rational[S] (SupportsComplex_Real[S]): _Complex = Rational class SupportsRound_Rational[S] (SupportsRound_Real[S]): _Real = Rational class SupportsFLoat_Rational[S] (SupportsFLoat_Real[S]) _Real = Rational def __float__(cls,a): Int = Integral_int return Real_float.__div__(Int._SuppFloat.__float__(cls._Rational.numerator(Int,a)), Int._SuppFloat.__float__(cls._Rational.denominator(Int,a))) class Rational[S] (Real[S]): _Plus = Plus_Rational _Minus = Minus_Rational _SuppAbs = SupportsAbs_Rational _SuppComplex = SupportsComplex_Rational _SuppRound = SupportsRound_Rational _SuppFloat = SupportsFloat_Rational numerator : (@Integral[T], S) -> T denominator : (@Integral[T], S) -> T ----------------------------------------------------------------- protocol Integral (Rational,SupportsInt,Logical): @static __fromint__ : (int) -> Self __index__ : () -> Self @static __lshift__ : (Self,Self) -> Self @static __rshift__ : (Self,Self) -> Self __invert__ : () -> Self def __index__(a): return int(a) def __lshift__(a,b): return fromint(int(a) << int(b)) def __invert__(a): return fromint(~int(a)) def __float__(a): return float(int(a)) def numerator(a): return a def denominator(a): return 1 ====> "typeclass" (Rational[S],SupportsInt[S],Logical[S]) => Integral[S]: __fromint__ : (int) -> S __index__ : (S) -> S __lshift__ : (S,S) -> S __rshift__ : (S,S) -> S __invert__ : (S) -> S def __index__(a): return int(a) def __lshift__(a,b): return fromint(int(a) << int(b)) def __float__(a): return float(int(a)) def numerator(a): return a def denominator(a): return 1 ====> class Plus_Integral[S] (Plus_Rational[S]): _Number = Integral class Minus_Integral[S] (Minus_Rational[S]): _Number = Integral class SupportsAbs_Integral[S] (SupportsAbs_Rational[S]): _Complex = Integral class SupportsComplex_Integral[S] (SupportsComplex_Rational[S]): _Complex = Integral class SupportsRound_Integral[S] (SupportsRound_Rational[S]): _Real = Integral class SupportsFLoat_Integral[S] (SupportsFLoat_Rational[S]) _Real = Integral class SupportsInt_Integral[S] (SupportsInt[S]) _Integral = Integral class Logical_Integral[S] (Logical[S]) _Integral = Integral class Integral[S] (Rational[S]): _Plus = Plus_Integral _Minus = Minus_Integral _SuppAbs = SupportsAbs_Integral _SuppComplex = SupportsComplex_Integral _SuppRound = SupportsRound_Integral _SuppFloat = SupportsFloat_Integral _SuppInt = SupportsInt_Integral _Logical = Logical_Integral @static __fromint__ : (int) -> S __index__ : (S) -> S __lshift__ : (S,S) -> S __rshift__ : (S,S) -> S __invert__ : (S) -> S def __index__(cls,a): return cls._SuppInt.__int__(a) def __lshift__(cls,a,b): return cls.__fromint__(Integral_int.__lshift__(cls._SuppInt.__int__(a), cls._SuppInt.__int__(b))) def __invert__(cls,a): return cls.__fromint__(Integral_int.__invert__(cls._SuppInt.__int__(a))) def __float__(cls,a): return Integral_int._SuppFloat.__float__(cls._SuppInt.__int__(a)) def numerator(cls,_w,a): return _w.__fromint__(cls.__SuppInt.__int__(a)) def denominator(cls,_w,a): return _w.__fromint__(0) ----------------------------------------------------------------- extension int (Integral): def __fromint__(a): return a def __int__(self): return self def __and__(a,b): return prinandint(a,b) ====> "instance" Integral[int]: def __fromint__(a): return a def __int__(self): return self def __and__(a,b): return prinandint(a,b) ====> class Plus_Rational_int (Plus_Rational[int]): _Number = Integral_int class Minus_Rational_int (Minus_Rational[int]): _Number = Integral_int class SupportsAbs_Integral_int (SupportsAbs_Integral[int]): _Complex = Integral_int class SupportsComplex_Integral_int (SupportsComplex_Integral[int]): _Complex = Integral_int class SupportsRound_Integral_int (SupportsRound_Integral[int]): _Real = Integral_int class SupportsFloat_Integral_int (SupportsFloat_Integral[int]): _Real = Integral_int class SupportsInt_Integral_int (SupportsInt_Integral[int]): _Integral = Integral_int def __int__(cls,self): return self class Logical_Integral_int (Logical_Integral[int]): _Integral = Integral_int def __and__(cls,a,b): return prinandint(a,b) class Integral_int (Integral[int]): _Plus = Plus_Integral_int _Minus = Minus_Integral_int _SuppAbs = SupportsAbs_Integral_int _SuppComplex = SupportsComplex_Integral_int _SuppRound = SupportsRound_Integral_int _SuppFloat = SupportsFloat_Integral_int _SuppInt = SupportsInt_Integral_int _Logical = Logical_Integral_int def __fromint__(cls,a): return a ----------------------------------------------------------------- extension bool (Logical,Ord): def __and__(a,b): return b if a else False def __eq__(a,b): return primeqbool(a,b) def __lt__(a,b): return a == False and b == True ====> "instance" Ord[bool] def __eq__(a,b): return primeqbool(a,b) def __lt__(a,b): return a == True and b == False "instance" Logical[bool]: def __and__(a,b): return b if a else False ====> class Ord_bool (Ord[bool]): _Logical = Logical_bool def __eq__(cls,a,b): return primeqbool(a,b) def __lt__(cls,a,b): return cls.__eq__(a,True) and cls.__eq__(b,False) class Logical_bool (Logical[bool]): _Ord = Ord_bool def __and__(a,b): return b if a else False ----------------------------------------------------------------- extension bool (Logical): def __and__(a,b): return b if a else False extension bool (Ord): def __eq__(a,b): return primeqbool(a,b) def __lt__(a,b): return a == False and b == True ====> "instance" Ord[bool] def __eq__(a,b): return primeqbool(a,b) def __lt__(a,b): return a == True and b == False "instance" Logical[bool]: def __and__(a,b): return b if a else False ====> class Ord_bool (Ord[bool]): def __eq__(cls,a,b): return primeqbool(a,b) def __lt__(cls,a,b): return cls.__eq__(a,True) and cls.__eq__(b,False) class Logical_bool (Logical[bool]): def __and__(a,b): return b if a else False ----------------------------------------------------------------- protocol IncrementalLogical[A] (Logical): __iand__ : !(A) -> None __ior__ : !(A) -> None __ixor__ : !(A) -> None ====> "typeclass" (Logical[S]) => IncrementalLogical[S,A]: __iand__ : !(S,A) -> None __ior__ : !(S,A) -> None __ixor__ : !(S,A) -> None ====> class IncrementalLogical[S,A] (Logical[S]) __iand__ : !(S,A) -> None __ior__ : !(S,A) -> None __ixor__ : !(S,A) -> None ----------------------------------------------------------------- protocol IncrementalPlus[A] (Plus): __iadd__ : !(A) -> None ====> "typeclass" (Plus[S]) => IncrementalPlus[S,A]: __iadd__ : !(S,A) -> None ====> class IncrementalPlus[S,A] (Plus[S]): __iadd__ : !(S,A) -> None ----------------------------------------------------------------- protocol IncrementalMinus[A] (Minus): __isub__ : !(A) -> None ====> "typeclass" (Minus[S]) => IncrementalMinus[S,A]: __isub__ : !(S,A) -> None ====> class IncrementalMinus[S,A] (Minus[S]): __isub__ : !(S,A) -> None ----------------------------------------------------------------- protocol Foldable[A]: __fold__ : ((A,B)->B, B) -> B ====> "typeclass" Foldable[S,A]: __fold__ : (S, (A,B)->B, B) -> B ====> class Foldable[S,A](): __fold__ : (S, (A,B)->B, B) -> B ----------------------------------------------------------------- ### The collection hierarchy (from typing.py) protocol Iterable[A]: __iter__ : () -> Iterator[A] ====> "typeclass" Iterable[S,A]: __iter__ : (S) -> Iterator[A] ====> class Iterable[S,A](): __iter__ : (S) -> Iterator[A] ----------------------------------------------------------------- class Iterator[A] (Iterable[A]): # MUTUAL RECURSION BETWEEN TYPE AND PROTOCOL __next__ : !() -> A def __iter__(self): return self ====> class Iterator[A](): __next__ : !() -> A "instance" Iterable[Iterator[A],A]: def __iter__(self): return self ====> class Iterator[A](): __next__ : !() -> A class Iterable_Iterator (Iterable[Iterator[A],A]): def __iter__(cls,self): return self ----------------------------------------------------------------- protocol Reversible[A] (Iterable[A]): __reversed__ : () -> Self ====> "typeclass" (Iterable[S,A]) => Reversible[S,A]: __reversed__ : (S) -> S ====> class Reversible[S,A] (Iterable[S,A]): __reversed__ : (S) -> S ----------------------------------------------------------------- protocol Container[A]: __contains__ : (A) -> bool ====> "typeclass" Container[S,A]: __contains__ : (S,A) -> bool ====> class Container[S,A](): __contains__ : (S,A) -> bool ----------------------------------------------------------------- protocol Sized: __len__ : () -> int ====> "typeclass" Sized[S]: __len__ : (S) -> int ====> class Sized[S](): __len__ : (S) -> int ----------------------------------------------------------------- protocol Indexed[A,B]: __getitem__ : (A) -> B ====> "typeclass" Indexed[S,A,B]: __getitem__ : (S,A) -> B ====> class Indexed[S,A,B](): __getitem__ : (S,A) -> B ----------------------------------------------------------------- protocol Sliceable: __getslice__ : (int?,int?,int?) -> Self ====> "typeclass" Sliceable[S]: __getslice__ : (S,int?,int?,int?) -> S ====> class Sliceable[S,A](): __getslice__ : (S,int?,int?,int?) -> S ----------------------------------------------------------------- protocol Collection[A] (Container[A], Sized, Iterable[A]): __fromiter__ : (Iterable[A]) -> Self ====> "typeclass" (Container[S,A], Sized[S], Iterable[S,A]) => Collection[S,A]: __fromiter__ : (Iterable[T,A]) => (T) -> S ====> class Sized_Collection[S,A] (Sized[S]): _Collection : @Collection[A] class Iterable_Collection[S,A] (Iterable[S,A]): _Collection : @Collection[A] class Collection[S,A] (Container[S,A]): _Sized : @Sized_Collection[S,A] _Iterable : @Iterable_Collection[S,A] __fromiter__ : (@Iterable[A],T) -> S ----------------------------------------------------------------- protocol Set[A] (Collection[A], Ord, Logical, Minus): isdisjoint : (Set[A]) -> bool def __le__(a: Self, b: Self): if len(a) > len(b): return False for elem in a: if elem not in b: return False return True def __lt__(a: Self, b: Self): if len(a) >= len(b): return False for elem in a: if elem not in b: return False return True def __eq__(a: Self, b: Self): return len(a) == len(b) and a <= b def __or__(a: Self, b: Self): chain = [ e for s in [a,b] for e in s ] return fromiter(chain) def isdisjoint(self: Self, other: Set[A]): for value in b: if value in self: return False return True ====> "typeclass" (Collection[S,A], Ord[S], Logical[S], Minus[S]) => Set[S,A]: isdisjoint : (Set[T,A]) => (S,T) -> bool def __le__(a: S, b: S): if len(a) > len(b): return False for elem in a: if elem not in b: return False return True def __lt__(a: S, b: S): if len(a) >= len(b): return False for elem in a: if elem not in b: return False return True def __eq__(a: S, b: S): return len(a) == len(b) and a <= b def __or__(a: S, b: S): chain = [ e for s in [a,b] for e in s ] return fromiter(chain) def (Set[T,A]) => isdisjoint(self: S, other: T): for value in b: if value in self: return False return True ====> class Sized_Set[S,A] (Sized_Collection[S]): _Set : @Set[S,A] class Iterable_Set[S,A] (Iterable_Collection[S,A]): _Set : @Set[S,A] class Ord_Set[S,A] (Ord[S]): _Set : @Set[S,A] def __le__(cls, a:S, b:S): if Ord_int.__gt__(cls._Set._Sized.__len__(a), cls._Set._Sized.__len__(b)): return False for elem in cls._Set._Iterable.__iter__(a): if not cls._Set.__contains__(b,elem): return False return True def __lt__(cls, a:S, b:S): if Ord_int.__ge__(cls._Set._Sized.__len__(a), cls._Set._Sized.__len__(b)): return False for elem in cls._Set._Iterable.__iter__(a): if not cls._Set.__contains__(b,elem): return False return True def __eq__(cls, a: S, b: S): return Eq_int.__eq__(cls._Set._Sized.__len__(a), cls._Set._Sized.__len__(b)) and cls.__le__(a,b) class Logical_Set[S,A] (Logical[S]): _Set : @Set[S,A] def __or__(cls, a: S, b: S): chain = [ e for s in Iterable_list.__iter__([a,b]) for e in cls._Set._Iterable.__iter__(s) ] return cls.__fromiter__(Iterable_list,chain) class Minus_Set[S,A] (Minus[S]): _Set : @Set[S,A] class Set[S,A] (Collection[S,A]): _Sized : @Sized_Set[S,A] _Iterable : @Iterable_Set[S,A] _Ord : @Ord_Set[S,A] _Logical : @Logical_Set[S,A] _Minus : @Minus_Set[S,A] isdisjoint : (@Set[T,A],S,T) -> bool def isdisjoint(cls:@Self, _q:@Set[T,A]), self:S, other:T): for value in _q._Iterable.__iter__(other): if cls.__contains__(value): return False return True ----------------------------------------------------------------- extension Set[A (Hashable)] (Hashable): def __hash__(self): n = 12345 for k in self: n += hash(k) return n ====> "instance" (Hashable[A], Set[S,A]) => Hashable[S]: def __hash__(self): n = 12345 for k in self: n += hash(k) return n ====> def Hashable_Set[S,A] (_qual: @Hashable[A], _Set: @Set[S,A]) -> @Hashable[S]: class Hashable_Set[S,A] (Hashable[S]): def __hash__(cls: class Self, self:S): n = 12345 for k in _Set._Iterable.__iter__(self): n += _qual.__hash__(k) return n return Hashable_Set ----------------------------------------------------------------- class frozenset[A (Hashable)] (Set[A], Hashable): _val : frozendict[A,()] # HYPOTHETICAL! def __contains__(self, a): return a in self._val.keys() def __fromiter__(items: Iterable[A]): return frozenset(_val = { i:() for i in items }) def __len__(self): return len(self._val) def __iter__(self): return iter(self._val.keys()) ====> "qualified struct" (Hashable[A]) => frozenset[A]: _val : frozendict[A,()] "instance" (Hashable[A]) => Set[frozenset[A],A]: def __contains__(self, a): return a in self._val.keys() def (Iterable[T,A]) => __fromiter__(items: T): return frozenset(_val = { i:() for i in items }) def __len__(self): return len(self._val) def __iter__(self): return iter(self._val.keys()) "instance" (Hashable[A]) => Hashable[frozenset[A]]: def __hash__(self): ... n = 12345 for i in self._val.keys(): n += hash(i) return n ====> class frozenset[A](): _qual = Hashable _val : frozendict[A,()] def Set_frozenset[A](_qual: @Hashable[A]) -> @Set[frozenset[A],A]: class Sized_frozenset[A] (Sized_Set[frozenset[A],A]): _Collection = Set_frozenset _Set = Set_frozenset def __len__(cls,self): return len(self._val) class Iterable_frozenset[A] (Iterable_Set[frozenset[A],A]): _Collection = Set_frozenset _Set = Set_frozenset def __iter__(cls,self): return iter(self._val.keys()) class Ord_frozenset[A] (Ord_Set[frozenset[A],A]): _Set = Set_frozenset class Logical_frozenset[A] (Logical_Set[frozenset[A],A]): _Set = Set_frozenset class Minus_frozenset[A] (Minus_Set[frozenset[A],A]): _Set = Set_frozenset class Set_frozenset[A] (Set[frozenset[A],A]): _Sized = Sized_frozenset _Iterable = Iterable_frozenset _Ord = Ord_frozenset _Logical = Logical_frozenset _Minus = Minus_frozenset def __contains__(cls,self,a): return Mapping_frozendict.__contains__(self._val,a) def __fromiter__(_qual: @Iterable[T,A], items: T): return frozenset(_val = { i:() for i in _qual.__iter__(items) }) return Set_frozenset ####### Minus_frozenset[A] < Minus_Set[frozenset[A],A] < Minus[frozenset[A]] ## But assume frozensubset[A] < frozenset[A] ## and Minus_frozensubset[A] < Minus_frozenset[A] ## Can we inherit _sub_ from Minus_frozenset in Minus_frozensubset? ## Minus_frozenset._sub_ : (frozenset[A],frozenset[A])->frozenset[A] frozensubset[A] ## Answer is NO! ## But had we instead defined ####### Minus_frozenset[A,S(frozenset[A])] < Minus_Set[S,A] < Minus[S] ## and ####### Minus_frozensubset[A,S(frosensubset[A])] < Minus_frozenset[A,S] ## Then ## Minus_frozenset._sub_ : [S(frozenset[A])]=>(S,S)->S < Minus_frozensubset._sub_ : [S(frozensubset[A])]=>(S,S)->S ## I.e., Minus_frozenset._sub_ would be inheritable! ## But then the question is of course how to implement a generic Minus_frozenset._sub_ with type (S,S)->S that works for all S < frozenset... ## Conclusion: perhaps better stick to the non-inheritable version and ask all subclasses of frozenset for a reimplementation of _sub_ ## Can we direct the translation on basis of what the type of Minus_frozenset._sub_ is? ## That is, if the inferred type is indeed [S(frozenset)]=>(S,S)->S, then the translation ## Minus_frozenset[A,S(frozenset[A])] (Minus_Set[S,A]) is chosen and Minus_frozenset._sub_ is available to inherit ## Otherwise then translation defaults to Minus_frozenset[A] (Minus_Set[frozenset[A],A]) ## Hmm, isn't this just translating the extension frozenset (Minus) on basis of the most general method types inferred? ## Yes, it is! ## Conclusion: how to translate extension declarations will be based on inferred types. ## And whether a method can be inherited or not will also be determined entirely by the type-checker. def Hashable_frozenset[A](_qual: @Hashable[A]) -> @Hashable[frozenset[A]]: class Hashable_frozenset[A] (Hashable[frozenset[A]]): def __hash__(cls, self): ... n = 12345 for k in Mapping_frozendict._Iterable.__iter__(self._val): n += _qual.__hash__(k) return n return Hashable_frozenset --- Sized_frozenset_str = Sized_frozenset(Hashable_str) Hashable_frozenset_str = Hashable_Set(Hashable_str, Set_frozenset_str) --- x : frozenset[str] x = frozenset(["apa","bepa"]) y = hash(x) z = x.single() ====> x : frozenset[str] x = frozenset(["apa","bepa"]) y = __hash__(x) z = x.single() ====> x : frozenset[str] x = frozenset(["apa","bepa"]) y = Hashable_frozenset_str.__hash__(x) z = frozenset.single(x) --- class coloredset[A (Hashable)] (frozenset[A]): color : str def isblue(self): return self.color == "blue" ====> "qualified struct" (Hashable[A]) => coloredset[A] (frozenset[A]) color : str def isblue(self): return self.color == "blue" ====> class coloredset[A] (frozenset[A]) color : str def isblue : () -> bool def isblue(self:Self): return self.color == "blue" ----------------------------------------------------------------- protocol MutableIndexed[A,B] (Indexed[A,B]): __setitem__ : !(A,B) -> None __delitem__ : !(A) -> None ====> "typeclass" (Indexed[S,A,B]) => MutableIndexed[S,A,B]: __setitem__ : !(S,A,B) -> None __delitem__ : !(S,A) -> None ====> class MutableIndexed[S,A,B] (Indexed[S,A,B]): __setitem__ : !(S,A,B) -> None __delitem__ : !(S,A) -> None ----------------------------------------------------------------- protocol MutableSet[A] (Set[A], IncrementalLogical[Set[A]], IncrementalMinus[Set[A]]): add : !(A) -> None pop : !() -> A clear : !() -> None def clear(self: Self): try: while True: self.pop() except KeyError: pass def __ior__(self: Self, other: Set[A]): for value in other: self.add(value) ====> "typeclass" (Set[S,A], IncrementalLogical[S,EXISTS[T,Set[T,A]], IncrementalMinus[S,EXISTS[T,Set[T,A]]) => MutableSet[S,A]: add : !(A,A) -> None pop : !(S) -> A clear : !(S) -> None def clear(self: S): try: while True: self.pop() except KeyError: pass def __ior__(self: S, other: Set[A]): for value in other: self.add(value) ====> class Sized_MutableSet[S,A] (Sized_Set[S,A]): _MutableSet : MutableSet[S,A] class Iterable_MutableSet[S,A] (Iterable_Set[S,A]): _MutableSet : MutableSet[S,A] class Ord_MutableSet[S,A] (Ord_Set[S,A]): _MutableSet : MutableSet[S,A] class Logical_MutableSet[S,A] (Logical_Set[S,A]): _MutableSet : MutableSet[S,A] class Minus_MutableSet[S,A] (Minus_Set[S,A]): _MutableSet : MutableSet[S,A] class IncrementalLogical_MutableSet[S,A] (IncrementalLogical[S,EXISTS[T,Set[T,A]]): _MutableSet : MutableSet[S,A] def __ior__(cls,self: S, other: EXISTS[T,Set[T,A]): for value in other._protocol._Iterable.__iter__(other._element): cls._MutableSet.add(value) class IncrementalMinus_MutableSet[S,A] (IncrementalMinus[S,EXISTS[T,Set[T,A]]): _MutableSet : MutableSet[S,A] class MutableSet[S,A] (Set[S,A]): _Sized : Sized_MutableSet[S,A] _Iterable : Iterable_MutableSet[S,A] _Ord : Ord_MutableSet[S,A] _Logical : Logical_MutableSet[S,A] _Minus : Minus_MutableSet[S,A] _IncrementalLogical : IncrementalLogical_MutableSet[S,A] _IncrementalMinus : IncrementalMinus_MutableSet[S,A] add : !(S,A) -> None pop : !(S) -> A def clear(wit, self): try: while True: wit.pop(self) except KeyError: pass ----------------------------------------------------------------- # Type-based transformations: # # * Every protocol method not mentioning 'Self' is classified as an "instance" method # * A protocol method mentioning 'Self' is classified as a static method # * Every protocol "instance" method gets an extra first argument of type 'Self' # * Every protocol decl turns into a "typeclass" with an additional first type parameter 'Self' # * Every protocol base "class" turns into a "typeclass" ancestor (with 'Self' inserted first) # * In every type scheme: # * Every type expression that is a protocol application is replaced by a new universally # quantified variable and a corresponding protocol constraint in the schema constaint tuple # * Every type variable with an explicit protocol bound has its bound moved to the schema constraint tuple # * Nested types not occurring in type schemas of their own are treated as being part of the enclosing schema # * In every class or class: # * Protocol bases turn into separate "instance" declarations for each protocol, with the declared struct/class # inserted as the first protocol type argument # * Every struct/class parameter with an explicit protocol bound has its bound moved into a constraint on the # struct/class constructor function # * In every protocol extension: # * Every base protocol turns into an "instance" declaration for a fresh type variable, with the protocol constraint # on the new variable inserted as the first (last?) among the "instance" preconditions # * # * Protocols with overlapping method names are disallowed (loosen this?) # * Every selection expression mentioning a protocol "instance" method name generates the corresponding protocol constraint # * Every variable expression mentioning a static protocol method name generates the corresponding protocol constraint # * Constraint resolution and witness translation proceeds as in Haskell # Superclass constraint (C) => means # # * Additional function parameter (in a function/method type scheme) # * Additional constructor parameter (and field) (in a plain struct/class definition) # * Additional constructor parameter (and field) (in an "instance" (=struct) definition) # * Additional "instance" existence requirement (in a "typeclass" (=struct) definition) ----------------------------------------------------------------- class set[A (Hashable)] (object, MutableSet[A]): def __len__(self): ... def __contains__(self, a): ... def __iter__(self): ... def __eq__(self, other): ... def __lt__(self, other): ... def __or__(self, other): ... def add(self, a): ... def update(self, other): ... def __ior__(self, other): ... def copy(self): ... ====> "qualified class" (Hashable[A]) => set[A]: def __len__(self): ... def __contains__(self, a): ... def __iter__(self): ... def __eq__(self, other): ... def __lt__(self, other): ... def __or__(self, other): ... def add(self, a): ... def update(self, other): ... def __ior__(self, other): ... def copy(self): ... "instance" (Hashable[A]) => MutableSet[set[A],A]: ... ====> class set[A] (object): _qual : @Hashable[A] ... def MutableSet_set[A] (_qual: @Hashable[A]) -> @MutableSet[set[A],A]: class MutableSet_set[A] (MutableSet[A]): ... return MutableSet_set ----------------------------------------------------------------- ### More collections from typing.py protocol Mapping[A,B] (Collection[A], Indexed[A,B]): keys : () -> Iterator[A] values : () -> Iterator[B] items : () -> Iterator[(A,B)] ====> "typeclass" (Collection[S,A], Indexed[S,A,B]) => Mapping[S,A,B]: keys : (S) -> Iterator[A] values : (S) -> Iterator[B] items : (S) -> Iterator[(A,B)] ====> class Sized_Mapping[S,A,B] (Sized_Collection[S]): _Collection = Mapping _Mapping = Mapping class Iterable_Mapping[S,A,B] (Iterable_Collection[S,A]): _Collection = Mapping _Mapping = Mapping class Indexed_Mapping[S,A,B] (Indexed[S,A,B]): _Mapping = Mapping class Mapping[S,A,B] (Collection[S,A]): _Sized = Sized_Mapping _Iterable = Iterable_Mapping _Indexed = Indexed_Mapping keys : (S) -> Iterator[A] values : (S) -> Iterator[B] items : (S) -> Iterator[(A,B)] ----------------------------------------------------------------- extension frozendict[A(Hashable),B] (Mapping[A,B]): def keys(self): ... ... ====> "instance" (Hashable[A]) => Mapping[frozendict[A,B],A,B]: def keys(self): ... ... ====> def Mapping_frozendict[A,B] (_qual: @Hashable[A]) -> @Mapping[frozendict[A,B],A,B]: class Sized_Mapping_frozendict[A,B] (Sized_Mapping[frozendict[A,B],A,B]): _Collection = Mapping_frozendict _Mapping = Mapping_frozendict ... class Iterable_Mapping_frozendict[A,B] (Iterable_Mapping[frozendict[A,B],A,B]): _Collection = Mapping_frozendict _Mapping = Mapping_frozendict ... class Indexed_Mapping_frozendict[A,B] (Indexed_Mapping[frozendict[A,B],A,B]): _Mapping = Mapping_frozendict ... class Mapping_frozendict[A,B] (Mapping[frozendict[A,B],A,B]): _Sized = Sized_Mapping_frozendict _Iterable = Iterable_Mapping_frozendict _Indexed = Indexed_Mapping_frozendict def keys(cls, self): ... ... return Mapping_frozendict --- Mapping_frozendict_str = Mapping_frozendict(Hashable_str) ----------------------------------------------------------------- extension IO (VarMonad[MutableVar]) extension ST[S] (VarMonad[MutableVar]) extension State[S] (StateMonad[S]) extension Env[E] (ReaderMonad[E]) extension NetCircuit (Hard[NetSignal]) extension SimCircuit (Hard[SimSignal]) extension ListSet[A(Eq)] (Collection[A]) extension TreeSet[A(Ord)] (Collection[A]) extension A (Iso[A]) ......... extension Foo (HasFoo[int]) extension Sequence[A(Eq)] (Eq) extension tuple[A(Eq),B] (Foo) extension Sequence[A(MyShow)] (MyShow) extension Sequence[Char] (MyShow) extension A(Monad) (Functor) ......... extension StateT[S] (Monad) extension T(MonadT)[M(StateMonad[S])] (StateMonad[S]) extension tuple[A(Eq),B(Eq)] (Eq) extension [A(Eq),B(Eq)] => tuple[A,B] (Eq) extension Tree[int] (Foo) extension Tree[bool] (Foo) extension F(Liftable)[A(Num)] (Num) extension Ratio[A(Num)] (Num) extension tuple[float,float] (Movable) extension T[int,A] (D) extension T[bool,A] (D) extension tuple[A,A] (Foo) extension [Sequence[Sequence[A]](C)] => Sequence[A] (C) ......... extension T[M](Monad) (Foo) ......... extension [Sequence[Tree[A]](Eq)] => Tree[A(Eq)] (Eq) ......... extension [A,B(Eq)] => Mapping[A,B] (Eq) ----------------------------------------------------------------- extension Mapping[A, B(Eq)] (Eq): def __eq__(a: Self, b: Self): if len(a) != len(b): return False for i in a: if i not in b: return False if a[i] /= b[i]: return False return True ====> "instance" (Eq[B], Mapping[S,A,B]) => Eq[S] def __eq__(a: S, b: S): if len(a) != len(b): return False for i in a: if i not in b: return False if a[i] /= b[i]: return False return True ====> def Eq_Mapping[S,A,B] (_qual: @Eq[B], _Mapping: @Mapping[S,A,B]) -> @Eq[S]: class Eq_Mapping[S,A,B] (Eq[S]) def __eq__(cls, a: S, b: S): if Eq_int.__ne__(_Mapping._Sized.__len__(a), _Mapping._Sized.__len__(b)) return False for k in _Mapping._Iterable.__iter__(a): if not _Mapping.__contains__(b,k): return False if _qual.__ne__(_Mapping._Indexed.__getitem__(a,k), _Mapping._Indexed.__getitem__(b,k)): return False return True return Eq_Mapping --- def eqdict(a:frozendict[str,int], b:frozendict[str,int]) -> bool: return a == b ====> def eqdict(a:frozendict[str,int], b:frozendict[str,int]) -> bool: return a == b ====> def eqdict(a:frozendict[str,int], b:frozendict[str,int]) -> bool: Eq_Mapping_frozendict_str_int = Eq_Mapping(Eq_int, Mapping_frozendict(Hashable_str) return Eq_Mapping_frozendict_str_int.__eq__(a,b) ----------------------------------------------------------------- protocol MutableMapping[A,B] (Mapping[A,B], MutableIndexed[A,B]): update : !(Mapping[A,B]) -> None ====> "typeclass" (Mapping[S,A,B], MutableIndexed[S,A,B]) => MutableMapping[S,A,B]: update : (Mapping[T,A,B]) => !(S,T) -> None ====> class Sized_MutableMapping[S,A,B] (Sized_Mapping[S]): _MutableMapping = MutableMapping class Iterable_MutableMapping[S,A,B] (Iterable_Mapping[S,A]): _MutableMapping = MutableMapping class Indexed_MutableMapping[S,A,B] (Indexed_Mapping[S,A,B]): _MutableMapping = MutableMapping class MutableIndexed_MutableMapping[S,A,B] (MutableIndexed[S,A,B]): _MutableMapping = MutableMapping class MutableMapping[S,A,B] (Mapping[S,A,B]): _Sized = Sized_MutableMapping _Iterable = Iterable_MutableMapping _Indexed = Indexed_MutableMapping _MutableIndexed = MutableIndexed_MutableMapping update : !(@Mapping[T,A,B],S,T) -> None ----------------------------------------------------------------- protocol Sequence[A] (Collection[A], Indexed[int,A], Reversible[A], Plus): def __add__(self, other): ... def __contains__(self, key): ... def __iter__(self): ... def __reversed__(self): ... ====> "typeclass" (Collection[S,A], Indexed[S,int,A], Reversible[S,A], Plus[S]) => Sequence[S,A]: def __add__(self, other): ... def __contains__(self, key): ... def __iter__(self): ... def __reversed__(self): ... ====> class Sized_Sequence[S,A] (Sized_Collection[S]): _Collection = Sequence _Sequence = Sequence def __contains__(cls, self, key): ... class Iterable_Sequence[S,A] (Iterable_Collection[S,A]): _Collection = Sequence _Sequence = Sequence def __iter__(cls, self): ... class Indexed_Sequence[S,A] (Indexed[S,int,A]): _Sequence = Sequence class Reversible_Sequence[S,A] (Reversible[S,A]): _Sequence = Sequence def __reversed__(cls, self): ... class Plus_Sequence[S,A] (Plus[S]): _Sequence = Sequence def __add__(cls, self, other): ... class Sequence[S,A] (Collection[S,A]): _Sized = Sized_Sequence _Iterable = Iterable_Sequence _Indexed = Indexed_Sequence _Reversible = Reversible_Sequence _Plus = Plus_Sequence ----------------------------------------------------------------- extension Sequence[A (Eq)] (Eq): def __eq__(a: Self, b: Self): if len(a) != len(b): return False for i in range(0,len(a)): if a[i] != b[i]: return False return True ====> "instance" (Eq[A], Sequence[S,A]) => Eq[S]: def __eq__(a: S, b: S): if len(a) != len(b): return False for i in range(0,len(a)): if a[i] != b[i]: return False return True ====> def Eq_Sequence[S,A] (_qual: @Eq[A], _Sequence: @Sequence[S,A]) -> Eq[S]: class Eq_Sequence[S,A] (Eq[S]): def __eq__(cls, a: S, b: S): # OLD METHOD, SIGNATURE IS FIXED, CAN'T TAKE _qual AS A DIRECT ARGUMENT if Eq_int.__ne__(cls._Sequence._Sized.__len__(a), cls._Sequence._Sized.__len__(b)): return False for i in Iterable_range.__iter__(range(0,cls._Sequence._Sized.__len__(a))): if cls._qual.__ne__(cls._Sequence._Indexed.__getitem__(a,i), cls._Sequence._Indexed.__getitem__(b,i)): return False return True return Eq_Sequence ----------------------------------------------------------------- extension Sequence[A (Eq)]: # EXTENDED PROTOCOL WITH NEW METHODS AND TIGHTER PRE-CONDITION index : (A) -> int? count : (A) -> int def index(self, val): for i,x in enumerate(self): if x == val: return i return None def count(self, val): c = 0 for x in self: if x == val: c += 1 return c f : [A(Eq),S(Sequence[A])] => (S,A) -> int # INFERRED def f(s,a): return s.count(a) ====> "typeclass" (Eq[A], Sequence[S,A]) => Sequence_EXT[S,A]: index : (S,A) -> int? count : (S,A) -> int def index(self, val): for i,x in enumerate(self): if x == val: return i return None def count(self, val): c = 0 for x in self: if x == val: c += 1 return c f : (Eq[A],Sequence[S,A], Sequence_EXT[S,A]) => (S,A) -> int # INFERRED f : (Eq[A],Sequence[S,A]) => (S,A) -> int # CONTEXT-REDUCED (ALWAYS REDUCE AN EXTENDED PROTOCOL) def f(s,a): return s.count(a) ====> class Sequence_EXT[S,A](): _Eq : @Eq[A] _Sequence : @Sequence[S,A] index : (S,A) -> int? count : (S,A) -> int def index(cls, self, val): for i,x in enumerate(cls._Sequence._Iterable.__iter__(self)): if cls._Eq.__eq__(x,val): return i return None def count(cls, self, val): c = 0 for x in cls._Sequence._Iterable.__iter__(self): if cls._Eq.__eq__(x,val): c += 1 return c def f(_Sequence_EXT:@Sequence_EXT[S,A], s:S, a:A): return _Sequence_EXT.count(s,a) def f(_Eq:@Eq[A], _Sequence:@Sequence[S,A], s:S, a:A): class Sequence_EXT1[S,A] (Sequence_EXT[S,A]): _Eq = _Eq _Sequence = _Sequence return _Sequence_EXT1.count(s,a) ### OR #### class Sequence_EXT[S,A](): index : (@Eq[A], @Sequence[S,A], S, A) -> int? # NEW METHOD, SIGNATURE CAN BE ADAPTED count : (@Eq[A], @Sequence[S,A], S, A) -> int # NEW METHOD, SIGNATURE CAN BE ADAPTED def index(cls, _Eq: @Eq[A], _Sequence:@Sequence[S,A], self:S, val:A) -> int?: for i,x in enumerate(_Sequence._Iterable.__iter__(self)): if _Eq.__eq__(x,val): return i return None def count(cls, _Eq: @Eq[A], _Sequence:@Sequence[S,A], self:S, val:A) -> int: c = 0 for x in _Sequence._Iterable.__iter__(self): if _Eq.__eq__(x,val): c += 1 return c def f(_Eq:@Eq[A], _Sequence:@Sequence[S,A], s:S, a:A): return Sequence_EXT.count(_Eq,_Sequence,s,a) ### OR #### class Sequence_EXT[S,A](): index : (@Eq[A], @Sequence[S,A], S, A) -> int? count : (@Eq[A], @Sequence[S,A], S, A) -> int def Sequence_EXT_Eq_Sequence(_Eq: @Eq[A], _Sequence:@Sequence[S,A]): class Sequence_EXT[S,A](): def index(cls, self:S, val:A) -> int?: for i,x in enumerate(_Sequence._Iterable.__iter__(self)): if _Eq.__eq__(x,val): return i return None def count(cls, self:S, val:A) -> int: c = 0 for x in _Sequence._Iterable.__iter__(self): if _Eq.__eq__(x,val): c += 1 return c return Sequence_EXT_Eq_Sequence def f(_Eq:@Eq[A], _Sequence:@Sequence[S,A], s:S, a:A): Sequence_EXT = Sequence_EXT_Eq_Sequence(_Eq,_Sequence) return Sequence_EXT.count(s,a) ----------------------------------------------------------------- protocol MutableSequence[A] (Sequence[A], MutableIndexed[int,A], IncrementalPlus[Sequence[A]]): append : !(A) -> None __iadd__ : !(Sequence[A]) -> None def append(self, other): ... def __iadd__(self, other): self.append(other) ====> "typeclass" (Sequence[S,A], MutableIndexed[S,int,A], IncrementalPlus[S,Sequence[T,A]]) => MutableSequence[S,A]: append : !(S,A) -> None __iadd__ : !(S, Sequence[T,A]) -> None def append(self, other): ... def __iadd__(self, other): for v in other: self.append(v) ====> class Sized_MutableSequence[S,A] (Sized_Sequence[S]): _Collection = MutableSequence _Sequence = MutableSequence _MutableSequence = MutableSequence class Iterable_MutableSequence[S,A] (Iterable_Sequence[S,A]): _Collection = MutableSequence _Sequence = MutableSequence _MutableSequence = MutableSequence class Indexed_MutableSequence[S,A] (Indexed_Sequence[S,int,A]): _Sequence = MutableSequence _MutableSequence = MutableSequence class Reversible_MutableSequence[S,A] (Reversible_Sequence[S,A]): _Sequence = MutableSequence _MutableSequence = MutableSequence class Plus_MutableSequence[S,A] (Plus[S]): _Sequence = MutableSequence _MutableSequence = MutableSequence class MutableIndexed_MutableSequence[S,A] (MutableIndexed[S,int,A]): _MutableSequence = MutableSequence class IncrementalPlus_MutableSequence[S,A] (IncrementalPlus[S, Sequence[T,A] ]): ##################### _MutableSequence = MutableSequence __iadd__ : !(S, Sequence[T,A] ) -> None ##################### def __iadd__(self, other): other_val : TTTTT = some_other.val other_w : Sequence[TTTTT,A] = some_other.proto for v in other_w._Iterable.__iter__(other_val): self.append(v) class MutableSequence[S,A] (Sequence[S,A]): _Sized = Sized_MutableSequence _Iterable = Iterable_MutableSequence _Indexed = Indexed_MutableSequence _Reversible = Reversible_MutableSequence _Plus = Plus_MutableSequence _MutableIndexed = MutableIndexed_MutableSequence _IncrementalPlus = IncrementalPlus_MutableSequence[S,A]) append : !(S,A) -> None def append(cls, self, val): ... ----------------------------------------------------------------- protocol Apa: def apa1(self): return 1 def apa2(self): return 2 protocol Bepa (Apa): def apa1(self): return 3 def bepa(self): return 30 + self.apa2() protocol Cepa (Apa): def apa2(self): return 4 def cepa(self): return 40 + self.apa1() protocol Depa (Cepa, Bepa): # mro: Depa, Cepa, Bepa, Apa def depa(self): return (self.apa1(), self.apa2(), self.bepa(), self.cepa()) ====> class Apa[S] (): def apa1(wit,self): return 1 def apa2(wit,self): return 2 class Bepa[S] (Apa[S]): def apa1(wit,self): return 3 def bepa(wit,self): return 30 + wit.apa2(self) class Cepa[S] (Apa[S]): def apa2(wit,self): return 4 def cepa(wit,self): return 40 + wit.apa1(self) class Bepa_Depa[S] (Bepa[S]): _Depa : Depa[S] def apa2(wit,self): return wit._Depa.apa2(self) # DIAMOND PROBLEM RESOLUTION class Depa[S] (Cepa[S]): _Bepa : Bepa[S] def __init__(wit): wit._Bepa = Bepa_Depa(wit) def apa1(wit,self): # DIAMOND PROBLEM RESOLUTION return wit._Bepa.apa1(self) def depa(wit,self): return (wit.apa1(self), wit.apa2(self), wit._Bepa.bepa(self), wit.cepa(self)) --------------------- extension int (Depa): pass ====> "instance" Depa[int]: pass ====> wit : Depa[int] = Depa() witB : Bepa[int] = wit._Bepa 7.depa() ====> wit.depa(7) ====> Depa.depa(wit,7) ====> (wit.apa1(7), wit.apa2(7), wit._Bepa.bepa(7), wit.cepa(7)) ====> (Bepa.apa1(wit,7), Cepa.apa2(wit,7), Bepa.bepa(witB,7), Cepa.cepa(wit,7)) ====> (3, 4, 30 + witB.apa2(7), 40 + wit.apa1(7)) ====> (3, 4, 30 + witB._Depa.apa2(7), 40 + wit._Bepa.apa1(7)) ====> (3, 4, 30 + wit.apa2(7), 40 + witB.apa1(7)) ====> (3, 4, 30 + Cepa.apa2(wit,7), 40 + Bepa.apa1(witB,7)) ====> (3, 4, 30 + 4, 40 + 3) ====> (3, 4, 34, 43) ----------------------------------------------------------------- protocol Apa: def apa1(self): return 1 def apa2(self): return 2 protocol Bepa (Apa): def apa1(self): return 3 def bepa(self): return 30 + self.apa2() protocol Cepa (Apa): def apa2(self): return 4 def cepa(self): return 40 + self.apa1() protocol Depa (Cepa, Bepa): def depa(self): return (self.apa1(), self.apa2(), self.bepa(), self.cepa()) protocol Xtra (Apa): def apa1(self): return 5 def apa2(self): return 6 protocol Epa1 (Depa,Xtra,Bepa): # mro: Epa1,Depa,Cepa,Xtra,Bepa,Apa pass protocol Epa2 (Depa,Xtra,Cepa): # mro: Epa2,Depa,Xtra,Cepa,Bepa,Apa pass ====> class Apa[S] (): # apa1, apa2 def apa1(wit,self): return 1 def apa2(wit,self): return 2 class Bepa[S] (Apa[S]): # apa1, apa2, bepa def apa1(wit,self): return 3 # apa2 = Apa.apa2 def bepa(wit,self): return 30 + wit.apa2(self) class Cepa[S] (Apa[S]): # apa1, apa2, cepa # apa1 = Apa.apa1 def apa2(wit,self): return 4 def cepa(wit,self): return 40 + wit.apa1(self) class Bepa_Depa[S] (Bepa[S]): # apa1, apa2, bepa _Depa : Depa[S] # apa1 = Bepa.apa1 def apa2(wit,self): return wit._Depa.apa2(self) # DIAMOND PROBLEM RESOLUTION # bepa = Bepa.bepa class Depa[S] (Cepa[S]): # apa1, apa2, cepa, depa, bepa _Bepa : Bepa[S] def __init__(wit): wit._Bepa = Bepa_Depa(wit) def apa1(wit,self): # DIAMOND PROBLEM RESOLUTION return wit._Bepa.apa1(self) # apa2 = Cepa.apa2 # cepa = Cepa.cepa def depa(wit,self): return (wit.apa1(self), wit.apa2(self), wit.bepa(self), wit.cepa(self)) def bepa(wit,self): return wit._Bepa.bepa(self) # mro: Depa Cepa Bepa Apa # - - apa1 (apa1) # - apa2 *- (apa2) # - cepa # depa # -* bepa ---- class Xtra[S] (Apa[S]): # apa1, apa2 def apa1(wit,self): return 5 def apa2(wit,self): return 6 ---- class Xtra_Epa1[S] (Xtra[S]): # apa1, apa2 _Exp1 : Epa1[S] # apa1 = Xtra.apa1 def apa2(wit,self): return wit._Exp1.apa1(self) class Bepa_Epa1[S] (Bepa[S]): # apa1, apa2, bepa _Epa1 : Epa1[S] def apa1(wit,self): return wit._Epa1.apa1(self) def apa2(wit,self): return wit._Epa1.apa2(self) # bepa = Bepa.bepa class Epa1[S] (Depa[S]): # apa1, apa2, cepa, depa, bepa _Xtra : Xtra[S] def __init__(wit): wit._Bepa = Bepa_Epa1(wit) wit._Xtra = Xtra_Epa1(wit) def apa1(wit,self): return wit._Xtra.apa1(self) # apa2 = Cepa.apa2 # cepa = Depa.cepa # depa = Depa.depa # bepa = Depa.bepa # mro: Epa1 Depa Cepa Xtra Bepa Apa # -* - - apa1 *- (apa1) # - - apa2 *- *- (apa2) # - - cepa # - depa # - -* bepa ---- class Xtra_Epa2[S] (Xtra[S]): # apa1, apa2 _Exp1 : Epa1[S] # apa1 = Xtra.apa1 # apa2 = Xtra.apa2 class Bepa_Epa2[S] (Bepa[S]): # apa1, apa2, bepa _Epa1 : Epa1[S] def apa1(wit,self): return wit._Epa2.apa1(self) def apa2(wit,self): return wit._Epa2.apa2(self) # bepa = Bepa.bepa class Epa2[S] (Depa[S]): # apa1, apa2, cepa, depa, bepa _Xtra : Xtra[S] def __init__(wit): wit._Bepa = Bepa_Epa2(wit) wit._Xtra = Xtra_Epa2(wit) def apa1(wit,self): return wit._Xtra.apa1(self) def apa2(wit,self): return wit._Xtra.apa2(self) # cepa = Depa.cepa # depa = Depa.depa # bepa = Depa.bepa # mro: Epa2 Depa Xtra Cepa Bepa Apa # -* - apa1 - *- (apa1) # -* - apa2 - *- (apa2) # - - cepa # - depa # - -* bepa --------------------- extension int (Depa): pass ====> "instance" Depa[int]: pass ====> wit : Depa[int] = Depa() witB : Bepa[int] = wit._Bepa 7.depa() ====> wit.depa(7) ====> Depa.depa(wit,7) ====> (wit.apa1(7), wit.apa2(7), wit._Bepa.bepa(7), wit.cepa(7)) ====> (Bepa.apa1(wit,7), Cepa.apa2(wit,7), Bepa.bepa(witB,7), Cepa.cepa(wit,7)) ====> (3, 4, 30 + witB.apa2(7), 40 + wit.apa1(7)) ====> (3, 4, 30 + witB._Depa.apa2(7), 40 + wit._Bepa.apa1(7)) ====> (3, 4, 30 + wit.apa2(7), 40 + witB.apa1(7)) ====> (3, 4, 30 + Cepa.apa2(wit,7), 40 + Bepa.apa1(witB,7)) ====> (3, 4, 30 + 4, 40 + 3) ====> (3, 4, 34, 43) ------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------- protocol Apa: def apa1(self): return 1 def apa2(self): return 2 protocol Bepa (Apa): def apa1(self): return 10 def bepa(self): return self.apa2() protocol Cepa (Apa): def apa2(self): return 20 def cepa(self): return self.apa1() --- protocol Depa (Cepa,Bepa): def depa(self): return (self.cepa(), self.bepa()) extension int (Depa): # Extension by multi inheritance protocol def ipa(self): return depa(self) --- extension str (Cepa,Bepa): # Simultaneous multi extension def epa(self): return (self.cepa(), self.bepa()) --- extension str (Bepa): # First extension pass extension str (Cepa): # Second extension. Hmm... should this really affect the str (Bepa) extension behavior? Yes, on the def fepa(self): # grounds that it introduces a new behavior for str.apa2, on which str.bepa depends. return (self.cepa(), self.bepa()) --- extension list[A] (Bepa): # First extension pass extension list[A] (Cepa): def fepa(self): # Second extension return (self.cepa(), self.bepa()) # Witness translation goal: keep witnesses selection for Self and its type parameters open-ended in the OO way! # Achieve this via the "self" parameter of the translated protocol methods, here denoted "w" to distinguish it from the original "self" ====================================================> # Regular translation, avoiding class inheritance in translation of multiple base protocols class Apa[S] (): def apa1(w, self): return 1 def apa2(w, self): return 2 class Bepa[S] (): class Apa_wrapped[S] (Apa[S]): _main : Bepa[S] def apa1(w, self): return w._main.apa1(self) # Overriding apa1 (= redirection to Bepa, in case of Apa sibling use or Bepa promotion to Apa) # apa2 = Apa.apa1 # Inheriting apa2 _Apa : Apa[S] def __init__(w): w._Apa = Apa_wrapped(_main = w) def apa1(w, self): # Overriding apa1 return 10 def apa2(w, self): # "Inheriting" apa2 (= delegation to Apa, in case of either Bepa sibling use or official Bepa call) return w._Apa.apa2(self) def bepa(w, self): # Adding bepa return w.apa2(self) class Cepa[S] (): class Apa_wrapped[S] (Apa[S]): _main : Cepa[S] # apa1 = Apa.apa1 # Inheriting apa1 def apa2(w, self): return w._main.apa2(self) # Overriding apa2 (= redirection to Cepa, in case of Apa sibling use or Cepa promotion to Apa) _Apa : Apa[S] def __init__(w): w._Apa = Apa_wrapped(_main = w) def apa1(w, self): # "Inheriting" apa1 (= delegation to Apa, in case of Cepa sibling use or official Cepa call) return w._Apa.apa1(self) def apa2(w, self): # Overriding apa2 return 20 def cepa(w, self): # Adding cepa return w.apa1(self) --- extension int (Depa) class Depa[S] (): class Bepa_wrapped[S] (Bepa[S]): _main : Depa[S] # apa1 = Bepa.apa1 # Inheriting apa1 def apa2(w, self): # Overriding apa2 (= redirection to Depa, in case of Bepa sibling use or Depa promotion to Bepa) return w._main.apa2(self) # bepa = Bepa.bepa # Inheriting bepa class Cepa_wrapped[S] (Cepa[S]): _main : Depa[S] def apa1(w, self): # Overriding apa1 (= redirection to Depa, in case of Cepa sibling use or Depa promotion to Cepa) return w._main.apa1(self) # apa2 = Cepa.apa2 # Inheriting apa2 # cepa = Cepa.cepa # Inheriting cepa _Bepa : Bepa[S] _Cepa : Cepa[S] def __init__(w): w._Bepa = Bepa_wrapped(_main = w) w._Cepa = Cepa_wrapped(_main = w) def apa1(w, self): # "Inheriting" apa1 (= delegation to Bepa, in case of Depa sibling use or official Depa call) return w._Bepa.apa1(self) def bepa(w, self): # "Inheriting" bepa (= delegation to Bepa, in case of Depa sibling use or official Depa call) return w._Bepa.bepa(self) def apa2(w, self): # "Inheriting" apa2 (= delegation to Cepa, in case of Depa sibling use or official Depa call) return w._Cepa.apa2(self) def cepa(w, self): # "Inheriting" cepa (= delegation to Cepa, in case of Depa sibling use or official Depa call) return w._Cepa.bepa(self) def depa(w, self): # Adding depa return w.cepa(self) + w.bepa(self) class Depa_int (Depa[int]): # Extension by multi inheritance protocol def __init__(w): Depa.__init__(w) def ipa(w, self): return w.depa(self) --- extension str (Cepa,Bepa) class Cepa_Bepa_str (): # Simultaneous multi extension class Bepa_wrapped (Bepa[str]): _main : Cepa_Bepa_str # apa1 = Bepa.apa1 # Inheriting apa1 def apa2(w, self): # Overriding apa2 (= redirection to Cepa_Bepa_str, in case of Bepa sibling use or Cepa_Bepa_str promotion to Bepa) return w._main.apa2(self) # bepa = Bepa.bepa # Inheriting bepa class Cepa_wrapped (Cepa[str]): _main : Cepa_Bepa_str def apa1(w, self): # Overriding apa1 (= redirection to Cepa_Bepa_str, in case of Cepa sibling use or Cepa_Bepa_str promotion to Cepa) return w._main.apa1(self) # apa2 = Cepa.apa2 # Inheriting apa2 # cepa = Cepa.cepa # Inheriting cepa _Bepa : Bepa[str] _Cepa : Cepa[str] def __init__(w): w._Bepa = Bepa_wrapped(_main = w) w._Cepa = Cepa_wrapped(_main = w) def apa1(w, self): # "Inheriting" apa1 (= delegation to Bepa, in case of Cepa_Bepa_str sibling use or official Cepa_Bepa_str call) return w._Bepa.apa1(self) def bepa(w, self): # "Inheriting" bepa (= delegation to Bepa, in case of Cepa_Bepa_str sibling use or official Cepa_Bepa_str call) return w._Bepa.bepa(self) def apa2(w, self): # "Inheriting" apa2 (= delegation to Cepa, in case of Cepa_Bepa_str sibling use or official Cepa_Bepa_str call) return w._Cepa.apa2(self) def cepa(w, self): # "Inheriting" cepa (= delegation to Cepa, in case of Cepa_Bepa_str sibling use or official Cepa_Bepa_str call) return w._Cepa.bepa(self) def depa(w, self): # Adding depa return w.cepa(self) + w.bepa(self) def epa(w, self): return w.cepa(self) + w.bepa(self) --- extension str (Bepa); extension str (Cepa) class Bepa_str (): # First extension class Bepa_wrapped (Bepa[str]): _main : Bepa_str # apa1 = Bepa.apa1 # Inheriting apa1 # apa2 = Bepa.apa2 # Inheriting apa2 # bepa = Bepa.bepa # Inheriting bepa _Bepa : Bepa[str] # NOTE: real str(Bepa) witness! def __init__(w): w._Bepa = Bepa_wrapped(_main = w) def apa1(w, self): # "Inheriting" apa1 (= delegation to Bepa, in case of Bepa_str sibling use or official Bepa_str call) return w._Bepa.apa1(self) def apa2(w, self): # "Inheriting" apa2 (= delegation to Bepa, in case of Bepa_str sibling use or official Bepa_str call) return w._Bepa.apa2(self) def bepa(w, self): # "Inheriting" bepa (= delegation to Bepa, in case of Bepa_str sibling use or official Bepa_str call) return w._Bepa.bepa(self) class Cepa_Bepa_str (Bepa_str): # Second extension class Cepa_wrapped (Cepa[str]): _main : Cepa_Bepa_str def apa1(w, self): # Overriding apa1 (= redirection to Cepa_Bepa_str, in case of Cepa sibling use or Cepa_Bepa_str promotion to Cepa) return w._main.apa1(self) # apa2 = Cepa.apa2 # Inheriting apa2 # cepa = Cepa.cepa # Inheriting cepa _Cepa : Cepa[str] # NOTE: real str(Cepa) witness! def __init__(w): Bepa_str.__init__(w) w._Cepa = Cepa_wrapped(_main = w) # apa1 = Bepa_str.apa1 # Inheriting apa1 def apa2(w, self): # "Inheriting" apa2 (= delegation to Cepa, in case of Cepa_Bepa_str sibling use or official Cepa_Bepa_str call) return w._Cepa.apa2(self) # bepa = Bepa_str.bepa # Inheriting bepa def cepa(w, self): # "Inheriting" cepa (= delegation to Cepa, in case of Cepa_Bepa_str sibling use or official Cepa_Bepa_str call) return w._Cepa.bepa(self) def fepa(w, self): # Adding depa return w.cepa(self) + w.bepa(self) --- extension list[A] (Bepa); extension list[A] (Cepa) class Bepa_list[A] (): # First extension class Bepa_wrapped[A] (Bepa[list[A]]): _main : Bepa_list # apa1 = Bepa.apa1 # Inheriting apa1 # apa2 = Bepa.apa2 # Inheriting apa2 # bepa = Bepa.bepa # Inheriting bepa _Bepa : Bepa[list[A]] # NOTE: real list[A](Bepa) witness! def __init__(w): w._Bepa = Bepa_wrapped(_main = w) def apa1(w, self): # "Inheriting" apa1 (= delegation to Bepa, in case of Bepa_list sibling use or official Bepa_list call) return w._Bepa.apa1(self) def apa2(w, self): # "Inheriting" apa2 (= delegation to Bepa, in case of Bepa_list sibling use or official Bepa_list call) return w._Bepa.apa2(self) def bepa(w, self): # "Inheriting" bepa (= delegation to Bepa, in case of Bepa_list sibling use or official Bepa_list call) return w._Bepa.bepa(self) class Cepa_Bepa_list[A] (Bepa_list[A]): # Second extension class Cepa_wrapped[A] (Cepa[list[A]]): _main : Cepa_Bepa_list[A] def apa1(w, self): # Overriding apa1 (= redirection to Cepa_Bepa_list, in case of Cepa sibling use or Cepa_Bepa_list prom to Cepa) return w._main.apa1(self) # apa2 = Cepa.apa2 # Inheriting apa2 # cepa = Cepa.cepa # Inheriting cepa _Cepa : Cepa[list[A]] # NOTE: real str(Cepa) witness! def __init__(w): Bepa_list.__init__(w) w._Cepa = Cepa_wrapped(_main = w) # apa1 = Bepa_list.apa1 # Inheriting apa1 def apa2(w, self): # "Inheriting" apa2 (= delegation to Cepa, in case of Cepa_Bepa_list sibling use or official Cepa_Bepa_list call) return w._Cepa.apa2(self) # bepa = Bepa_list.bepa # Inheriting bepa def cepa(w, self): # "Inheriting" cepa (= delegation to Cepa, in case of Cepa_Bepa_list sibling use or official Cepa_Bepa_list call) return w._Cepa.bepa(self) def fepa(w, self): # Adding depa return w.cepa(self) + w.bepa(self) --- extension set[A(Eq)] (Bepa); extension set[A(Ord)] (Cepa) class Bepa_set[A] (): # First extension class Bepa_wrapped[A] (Bepa[set[A]]): _main : Bepa_set[A] _Eq_A : Eq[A] # apa1 = Bepa.apa1 # Inheriting apa1 # apa2 = Bepa.apa2 # Inheriting apa2 # bepa = Bepa.bepa # Inheriting bepa _Bepa : Bepa[set[A]] # NOTE: real set[A](Bepa) witness! def __init__(w, _Eq_A): w._Bepa = Bepa_wrapped(_main = w, _Eq_A = _Eq_A) def apa1(w, self): # "Inheriting" apa1 (= delegation to Bepa, in case of Bepa_set sibling use or official Bepa_set call) return w._Bepa.apa1(self) def apa2(w, self): # "Inheriting" apa2 (= delegation to Bepa, in case of Bepa_set sibling use or official Bepa_set call) return w._Bepa.apa2(self) def bepa(w, self): # "Inheriting" bepa (= delegation to Bepa, in case of Bepa_set sibling use or official Bepa_set call) return w._Bepa.bepa(self) class Cepa_Bepa_set[A] (Bepa_set[A]): # Second extension class Cepa_wrapped[A] (Cepa[set[A]]): _main : Cepa_Bepa_set[A] _Ord_A : Ord[A] def apa1(w, self): # Overriding apa1 (= redirection to Cepa_Bepa_set, in case of Cepa sibling use or Cepa_Bepa_set prom to Cepa) return w._main.apa1(self) # apa2 = Cepa.apa2 # Inheriting apa2 # cepa = Cepa.cepa # Inheriting cepa _Cepa : Cepa[set[A]] # NOTE: real str(Cepa) witness! def __init__(w, _Ord_A): Bepa_set.__init__(w, _Eq_A = _Ord_A) w._Cepa = Cepa_wrapped(_main = w, _Ord_A = _Ord_A) # apa1 = Bepa_set.apa1 # Inheriting apa1 def apa2(w, self): # "Inheriting" apa2 (= delegation to Cepa, in case of Cepa_Bepa_set sibling use or official Cepa_Bepa_set call) return w._Cepa.apa2(self) # bepa = Bepa_set.bepa # Inheriting bepa def cepa(w, self): # "Inheriting" cepa (= delegation to Cepa, in case of Cepa_Bepa_set sibling use or official Cepa_Bepa_set call) return w._Cepa.bepa(self) def fepa(w, self): # Adding depa return w.cepa(self) + w.bepa(self) ====================================================> # Utilizing single class inheritance.... class Apa[S] (): def apa1(w, self): return 1 def apa2(w, self): return 2 class Bepa[S] (Apa[S]): def apa1(w, self): return 10 def bepa(w, self): return w.apa2(self) class Cepa[S] (Apa[S]): # apa1 = Apa.apa1 def apa2(w, self): return 20 def cepa(w, self): return w.apa1(self) class Bepa_Depa[S] (Bepa[S]): _Depa : Depa[S] # apa1 = Bepa.apa1 def apa2(w, self): return w._Depa.apa2(self) # bepa = Bepa.bepa --- extension int (Depa) class Depa[S] (Cepa[S]): _Bepa : Bepa[S] def apa1(w, self): return w._Bepa.apa1(self) # apa2 = Cepa.apa2 # cepa = Cepa.cepa def bepa(w, self): return w._Bepa.bepa(self) def depa(w, self): return w.cepa(self) + w.bepa(self) class Depa_int (Depa[int]): def __init__(w): w._Bepa = Bepa_Depa(w) def ipa(w, self): return w.depa(self) --- extension str (Cepa,Bepa) class Cepa_Bepa_str (Cepa[str]): class Bepa_wrapped (Bepa[str]): _main : Cepa[str] # apa1 = Bepa.apa2 # Inheriting apa1 def apa2(w, self): # Overriding apa2 (= redirection to Cepa_Bepa_str, in case of Bepa sibling use or Cepa_Bepa_str promotion to Bepa) return w._main.apa2(self) # bepa = Bepa_str.bepa # Inheriting bepa _Bepa : Bepa[str] # NOTE: real str(Bepa) witness! def __init__(w): w._Bepa = Bepa_wrapped(_main = w) def apa1(w, self): retun w._Bepa.apa1(self) # apa2 = Cepa.apa2 # cepa = Cepa.cepa def bepa(w, self): return w._Bepa.bepa(self) def fepa(w, self): return w.cepa(self) + w.bepa(self) --- extension str (Bepa); extension str (Cepa) class Bepa_str (Bepa[str]): # apa1 = Bepa.apa1 # Inheriting apa1 # apa2 = Bepa.apa2 # Inheriting apa2 # bepa = Bepa.bepa # Inheriting bepa class Cepa_Bepa_str (Cepa[str]): # Encoding Cepa_Bepa_str (Cepa[str], Bepa[str]) class Bepa_wrapped (Bepa_str): # Forms inner baseclass (delegate), but comes before Cepa in the MRO _main : Cepa[str] # apa1 = Bepa.apa2 # Inheriting apa1 def apa2(w, self): # Overriding apa2 (= redirection to Cepa_Bepa_str, in case of Bepa_str sibling use or Cepa_Bepa_str promotion to Bepa) return w._main.apa2(self) # bepa = Bepa_str.bepa # Inheriting bepa _Bepa : Bepa[str] # NOTE: real str(Bepa) witness! def __init__(w): w._Bepa = Bepa_wrapped(_main = w) def apa1(w, self): # "Inheriting" apa1 (= delegation to Bepa, in case of Cepa_Bepa_str sibling use or official Cepa_Bepa_str call) retun w._Bepa.apa1(self) # apa2 = Cepa.apa2 # Inheriting apa2 # cepa = Cepa.cepa # Inheriting cepa def bepa(w, self): # "Inheriting" bepa (= delegation to Bepa, in case of Cepa_Bepa_str sibling use or official Cepa_Bepa_str call) return w._Bepa.bepa(self) def fepa(w, self): return w.cepa(self) + w.bepa(self) --- extension list[A] (Bepa); extension list[A] (Cepa) class Bepa_list[A] (Bepa[list[A]]): # apa1 = Bepa.apa1 # Inheriting apa1 # apa2 = Bepa.apa2 # Inheriting apa2 # bepa = Bepa.bepa # Inheriting bepa class Cepa_Bepa_list[A] (Cepa[list[A]]): # Encoding Cepa_Bepa_list[A] (Cepa[list[A]], Bepa[list[A]]) class Bepa_wrapped[A] (Bepa_list[A]): # Forms inner baseclass (delegate), but comes before Cepa in the MRO _main : Cepa[list[A]] # apa1 = Bepa.apa2 # Inheriting apa1 def apa2(w, self): # Overriding apa2 (= redirection to Cepa_Bepa_list, if Bepa_list sibling use or Cepa_Bepa_list prom to Bepa) return w._main.apa2(self) # bepa = Bepa_list.bepa # Inheriting bepa _Bepa : Bepa[list[A]] # NOTE: real list[A](Bepa) witness! def __init__(w): w._Bepa = Bepa_wrapped(_main = w) def apa1(w, self): # "Inheriting" apa1 (= delegation to Bepa, in case of Cepa_Bepa_list sibling use or official Cepa_Bepa_list call) retun w._Bepa.apa1(self) # apa2 = Cepa.apa2 # Inheriting apa2 # cepa = Cepa.cepa # Inheriting cepa def bepa(w, self): # "Inheriting" bepa (= delegation to Bepa, in case of Cepa_Bepa_list sibling use or official Cepa_Bepa_list call) return w._Bepa.bepa(self) def fepa(w, self): return w.cepa(self) + w.bepa(self) --- extension set[A(Eq)] (Bepa); extension set[A(Ord)] (Cepa) class Bepa_set[A] (Bepa[set[A]]): _Eq_A : Eq[A] def __init__(w, _Eq_A): w._Eq_A = _Eq_A # apa1 = Bepa.apa1 # Inheriting apa1 # apa2 = Bepa.apa2 # Inheriting apa2 # bepa = Bepa.bepa # Inheriting bepa class Cepa_Bepa_set[A] (Cepa[set[A]]): # Encoding Cepa_Bepa_set[A] (Cepa[set[A]], Bepa[set[A]]) class Bepa_wrapped[A] (Bepa_set[A]): # Forms inner baseclass (delegate), but comes before Cepa in the MRO _main : Cepa[set[A]] # apa1 = Bepa.apa2 # Inheriting apa1 def apa2(w, self): # Overriding apa2 (= redirection to Cepa_Bepa_set, if Bepa_set sibling use or Cepa_Bepa_set prom to Bepa) return w._main.apa2(self) # bepa = Bepa_set.bepa # Inheriting bepa _Bepa : Bepa[set[A]] # NOTE: real set[A](Bepa) witness! _Ord_A : Ord[A] def __init__(w, _Ord_A): w._Bepa = Bepa_wrapped(_main = w, _Eq_A = _Ord_A) # In general: _Eq_A = some_expr(_Ord_A) w._Ord_A = _Ord_A def apa1(w, self): # "Inheriting" apa1 (= delegation to Bepa, in case of Cepa_Bepa_set sibling use or official Cepa_Bepa_set call) retun w._Bepa.apa1(self) # apa2 = Cepa.apa2 # Inheriting apa2 # cepa = Cepa.cepa # Inheriting cepa def bepa(w, self): # "Inheriting" bepa (= delegation to Bepa, in case of Cepa_Bepa_set sibling use or official Cepa_Bepa_set call) return w._Bepa.bepa(self) def fepa(w, self): return w.cepa(self) + w.bepa(self) ================================================ FILE: workspace/Type-hierarchy.txt ================================================ Inheritance and overloading in Acton ==================================== This note aims to describe a proposal for how to integrate the notions of class inheritance and function/method overloading in Acton. By inheritance I mean the combination of the following ideas: - Classes (and other types) form a subtype hierarchy, and values of smaller types automatically count as values of their base types. - Classes defined by extension automatically include the code of their base classes, with the exception of overridden methods. - Methods invoked on 'self' reach code associated with the *actual* class of 'self', even when the calling method is an inherited one. By overloading I mean the feature that a certain method/function name can have many different implementations in a program, and that the selection of which implementation to invoke is directed by static type information available at the call site. Being dynamically typed, Python doesn't offer this particular feature, and instead often employs multiple inheritance (inheritance from more than one base class) as a form of compensation. However, this approach leads to its own set of problems that we want to avoid in Acton. The first problem is that generic operations get associated with individual objects, even when multiple objects are involved and the more correct view would be to associate the operation with the objects' common type. A typical example is the generic equality test ==, implemented in Python as a binary method __eq__ available on all objects. Ignoring for now the fact that higher-order types have no natural notion of equality, the primary problem of treating equality as a property of individual objects is that the relation becomes too localized. For example, x.__eq__(y) is in general a different test than y.__eq__(x), and the two forms may invoke entirely unrelated pieces of code in case x and y were instatiated from different classes. What is worse, the natural expectation that both operands of __eq__ exhibit the same set of attributes goes against well-known type-checking laws in the presence of inheritance, which renders static type safety problematic. The second problem with Python's reliance on inheritance is the fact that the ancestry of a class is fixed once the class is defined. That is, mixing in an extra base class as an afterthought is not possible. This isn't just a problem that can be avoided by careful planning, as all mix-in classes of useful functionality might not even be concieved when a datatype is defined. In a statically typed setting, the drawback is accentuated in the presence of generics (parametric polymorphism), where the appropriateness of mix-in inheritance also might depend on whether a yet unknown type parameter supports a certain operation or not. A type system where overloading is separate from the inheritance hierarchy would not suffer from this problem. Thirdly, there is no secret that multiple inheritance is tricky to implement, both in terms of the necessary static type analysis and the run-time machinery required. Many modern languages like Java, C#, Swift, Ruby and Scala abandon multiple inheritance in favor of a single inheritance hierarchy and the ability to overload classes using multiple interfaces/protocols/traits. Haskell has no notion of class inheritance, but provides an advanced system for overloading that is compatible with type inference and supports an efficient implementation. When I realized that Swift's protocol mechanism can be implemented like (and is probably based on) Haskell's overloading system, I felt the arguments tipping over in favor of abandoning multiple inheritance in Acton as well. If done right, the change would not even have to lead to much visible differences compared to existing Python programming practice. So the basic idea of the proposal is inspired by Swift, where one declares *protocols* in addition to classes. I'm not sure about the best way to syntactically introduce protocols in Acton, but let's for the moment assume something akin to (abstract) class declarations. Here's how we could write some simple protocols to express hashability and equality: protocol Hashable (Eq): __hash__ : () -> int protocol Eq: @staticmethod __eq__ : (Self,Self) -> bool @staticmethod __ne__ : (Self,Self) -> bool def __ne__(a,b): return not (a == b) The meaning is that a hashable type is a type with a method __hash__, and equality is supported by a type that offers the static methods __eq__ and __ne__. Hashable is furthermore defined as an extension of protocol Eq, which implies that any type wishing to implement protocol Hashable must also make sure it implements the Eq methods. Another detail is that protocols can offer default implementations of its methods, so that in this case, a type that wants to support protocol Eq doesn't have to implement method __ne__ unless it wishes to. We may say that such a type "inherits" the __ne__ method, although in this case the resolution of which method that gets called will be based on static type information rather than a dynamic class pointer. The special type Self stands for the actual type that implements a particular protocol, so declaring both method arguments to be of type Self effectively says the arguments must have the same (unknown) type. Self can also be used inside classes, where it stands for the type where an attribute or method eventually ends up after being inherited. Self is thus a place-holder that implicitly moves with the class and protocol hierarchies, and its presence in contravariant argument positions should therefore trigger some concern regarding type safety. Like in Swift, this proposal restricts the Self type by only allowing contravariant occurrences inside static methods. We will also impose the rule that (contravariant) static methods can only be selected directly from classes that implement them, they are not accessible as attributes of the instances of such classes. Combined with the ability of the Acton type-checker to automatically insert the appropriate class in front of overloaded method names, these restrictions are sufficient to guarantee type safety while retaining the original convenience of Python's binary methods. That is, an expression x==y will not translate into x.__eq__(y) in Acton but to w.__eq__(x,y), where w is a class name generated by the compiler on basis of static type information. Protocols can be listed instead of base classes when classes are defined, and the resulting behavior stays similar to that of class inheritance except for the statically resolved overloading. As an example, let's see how equality can be defined for a class of Fruit and some specialization classes Apple and Orange. class Fruit (Eq): ... def __eq__(a, b): return a.weight == b.weight class Apple (Fruit): ... def __eq__(a, b): return Fruit.__eq__(a,b) and a.appleness == b.appleness class Orange (Fruit): ... def __eq__(a, b): return Fruit.__eq__(a,b) and a.orangeness == b.orangeness The fact that __eq__ is a static method in all three classes is implied by the reference to protocol Eq. The specialized fruit attributes "appleness" and "orangeness" are left unspecified here, the important detail is that only apples possess appleness, and no fruit besides oranges exhibit the orangeness attribute. Assuming two variables x and y of type Apple, we can test for their apple-specific equality by writing x == y which gets translates to Apple.__eq__(x, y) on basis of the statically known types for x and y. Similarly, testing u == v, where both u and v are of type Orange, results in the following translated code: Orange.__eq__(u, v) However, should we promote any pair of these variables to type Fruit and then test for equality, we expect the comparison to only take the respective weights into account (as defined in class Fruit). That is, if we write i : Fruit = x j : Fruit = u i == j the last expression gets translated to Fruit.__eq__(i, j) by the compiler. In fact, the same effect is achieved if we compare Apple x directly to Orange u, since the closest common supertype of these types is Fruit: x == u ====> Fruit.__eq__(x, u) Any attempt to force the comparison of these variables using either the Apple.__eq__ or Orange.__eq__ methods will result in a static type error. That goes for the selection of __eq__ as an attribute of either a or x as well, since __eq__ is a contravariant static method which must therefore only be looked up by class. A more elaborate example looks as follows: class MyClass (Hashable): def __eq__(a, b): return hash(a) == hash(b) def hash(self): return cheap_hash(self) def my_method(self): return hash(self) class MySubClass (MyClass): def hash(self): return expensive_hash(self) Here MyClass implements the Hashable protocol, and MySubClass in turn extends MyClass in the plain old class inheritance fashion. Both __eq__ and my_method call the overloaded method __hash__ (via Python's syntactic sugar hash(v) ====> v.__hash__()), and __hash__ is redefined in MySubClass. But while __eq__ is itself a protocol method selected by type, my_method is dynamically bound. We should thus expect to see some differences in the way calls to these methods are resolved. First let's assume some objects x and y that are true MySubClass instances, and a variable z that is an alias to y but promoted to type MyClass: x = y = MySubClass() z : MyClass = y As in the Fruit example, the comparisons x == y x == z get translates on basis of static type information as before, and hence become MySubClass.__eq__(x,y) MyClass.__eq__(x,z) However, the calls y.my_method() z.my_method() are both dispatched dynamically on basis of the run-time class of y and z, and since this class is MySubClass in both cases, both calls behave the same at run-time: y.my_method() ====> MySubClass.my_method(y) z.my_method() ====> MySubClass.my_method(z) Now, inside both __eq__ and my_method, the calls to __hash__ (via hash) are resolved statically. But the static type in question is Self at these occurrences, and Self gets re-interpreted whenever a method is inherited in a subclass. Thus, the equality comparisons evolve as follows MySubClass.__eq__(x,y) ====> ... MySubClass.__hash__(b) ... ====> ... expensive_hash(b) ... (where b is y) MyClass.__eq__(x,z) ====> ... MyClass.__hash__(b) ... ====> ... cheap_hash(b) ... (where b is z) whereas the my_method calls become MySubClass.my_method(y) ====> ... MySubClass.__hash__(b) ... ====> ... expensive_hash(b) ... (where b is y) MySubClass.my_method(z) ====> ... MySubClass.__hash__(b) ... ====> ... expensive_hash(b) ... (where b is z) In essence, the statically known type of an object is irrelevant when one of its dynamically bound methods is called, but absolutely crucial when the called method belongs to a protocol. I expect these principles to coincide for most practical purposes, and I'll argue that the subtle cases one can construct are at least not harder to understand than the the corner cases of multiple inheritance in Python. The advantages of the proposal show up in the absence of a diamond problem (protocols can never be implemented twice), the ease by which contravariant binary methods can be handled (and explored at different types), and the straightforward implementation technique one gets for free when the protocol notion is understood in terms of Haskell's type classes (more on this below). Another distinct advantage of static overloading is that it also lends itself to incremental class adoptions. That is, all protocols a class can implement don't have to be listed when the class is defined; they can just as well be added later, in separate modules, and even without access to the original class implemenation. The key insight here is that type-based associations between a class and its various protocol implementations only exist within the compiler, there is no need to modify any existing class definition just because another such association is made. Again drawing inspiration from Swift (and Haskell), here's a tentative syntax illustrating what an incremental protocol adoption can look like. class SomeElaborateClass (SomeBaseClass, Eq, SomeBasicProtocol): ... # Much later, in a module far away: extension SomeElaborateClass (NewlyInventedProtocol): def protocol_method_A(self): ... def protocol_method_B(x, y, z): ... To investigate the design a bit further, I've made an experimental "implementation" of parts of Python's numeric tower and abstract collection libraries (modules numbers and collections.abc). I won't comment on every detail in it, but there are a few points worth mentioning: - Struct types and immutability - Abstract classes (where *some* unimplemented signatures remain) - Overloaded class constructors/converters (unresolved, but see __fromint__, etc) - Global status of protocol names - Type argument syntax: list[int] - Type parameter binding syntax, with protocol/baseclass constraints: Sequence[A] or Sequence[A(Eq)] - Recursion between protocol and type - Extension of a protocol itself - Uniqueness of extensions (see int(Eq) and int(Ord) alternatives) - Join protocols (see Collection[A]) - Protocols as types: either universal quant as in Haskell, or existential quant as in Swift (unresolved) - Inferring constrained types, or heavy defaulting? (unresolved) - Back to a nominal subtyping core, row polymorphism to handle tuple/record extensions only (and maybe unions) - The option type via subtyping - Associated types (future) - Mutability effects ignored when extending mutable to protocol (for example: iter() on a MutableSet should be monadic) - Notice Set, Mapping, Sequence extensions with additional constraint on type parameter - Appropriatness of SupportsX, Reversible, etc...? - Translation into plain classes... - Equivalent Haskell constructs... ############################################################ protocol Eq: @staticmethod __eq__ : (Self,Self) -> bool @staticmethod __ne__ : (Self,Self) -> bool def __ne__(a,b): return not (a == b) protocol Ord (Eq): @staticmethod __lt__ : (Self,Self) -> bool @staticmethod __le__ : (Self,Self) -> bool @staticmethod __gt__ : (Self,Self) -> bool @staticmethod __ge__ : (Self,Self) -> bool def __le__(a,b): return a < b or a == b def __gt__(a,b): return b < a def __ge__(a,b): return b <= a extension int (Eq): # ALTERNATIVE 1: SEPARATE EXTENSIONS def __eq__(a:int, b:int) -> bool: # return primeqint(a,b) # extension int (Ord): # def __lt__(a:int, b:int) -> bool: # return primltint(a,b) # extension int (Ord): # ALTERNATIVEL 2: A JOINT EXTENSION def __eq__(a:int, b:int) -> bool: # return primeqint(a,b) # def __lt__(a:int, b:int) -> bool: # return primltint(a,b) # protocol Hashable (Eq): __hash__ : () -> int protocol SupportsInt: __int__ : () -> int extension int (SupportsInt): def __int__(self): return self protocol SupportsFloat: __float__ : () -> float protocol SupportsComplex: __complex__ : () -> complex protocol SupportsAbs: __abs__ : () -> Self protocol SupportsRound: __round__ : () -> int protocol Logical: @staticmethod __and__ : (Self,Self) -> Self @staticmethod __or__ : (Self,Self) -> Self @staticmethod __xor__ : (Self,Self) -> Self protocol Plus: @staticmethod __add__ : (Self,Self) -> Self protocol Minus: @staticmethod __sub__ : (Self,Self) -> Self protocol Number (Ord, Plus, Minus): __pos__ : () -> Self __neg__ : () -> Self @staticmethod __mul__ : (Self,Self) -> Self @staticmethod __pow__ : (Self,Self) -> Self extension int (Number): def __pos__(self): return self def __neg__(self): return primnegint(self) def __add__(a, b) -> int: return primaddint(a,b) def __sub__(a, b) -> int: return primaddint(a,b) def __mul__(a, b) -> int: return primmulint(a,b) protocol Complex (Number, SupportsAbs, SupportsComplex): @staticmethod __fromcomplex__ : (complex) -> Self @staticmethod __div__ : (Self,Self) -> Self real : () -> Real imag : () -> Real conjugate : () -> Self protocol Real (Complex, SupportsRound, SupportsFloat): @staticmethod __fromfloat__ : (float) -> Self __trunc__ : () -> Integral __floor__ : () -> Integral __ceil__ : () -> Integral @staticmethod __divmod__ : (Self,Self) -> (Self,Self) @staticmethod __floordiv__ : (Self,Self) -> Integral @staticmethod __mod__ : (Self,Self) -> Self def __complex__(a): return complex(float(a)) def real(a): return fromfloat(float(a)) def imag(a): return fromfloat(0.0) def conjugate(a): return a def divmod(a,b): return (a//b, a%b) protocol Rational (Real): numerator : () -> Integral denominator : () -> Integral def __float__(a): return numerator(a) / denominator(a) protocol Integral (Rational,SupportsInt,Logical): @staticmethod __fromint__ : (int) -> Self __index__ : () -> Self @staticmethod __lshift__ : (Self,Self) -> Self @staticmethod __rshift__ : (Self,Self) -> Self __invert__ : () -> Self def __index__(a): return int(a) def __lshift__(a,b): return fromint(int(a) << int(b)) def __invert__(a): return fromint(~int(a)) def __float__(a): return float(int(a)) def numerator(a): return a def denominator(a): return 1 extension int (Integral): def __fromint__(a): return a def __int__(self): return self def __and__(a,b): return prinandint(a,b) extension bool (Logical,Ord): def __and__(a,b): return b if a else False def __eq__(a,b): return primeqbool(a,b) def __lt__(a,b): return a == False and b == True protocol IncrementalLogical[A] (Logical): __iand__ : !(A) -> None __ior__ : !(A) -> None __ixor__ : !(A) -> None protocol IncrementalPlus[A] (Plus): __iadd__ : !(A) -> None protocol IncrementalMinus[A] (Minus): __isub__ : !(A) -> None protocol Foldable[A]: __fold__ : ((A,B)->B, B) -> B protocol Iterable[A]: # MUTUAL RECURSION BETWEEN TYPE AND PROTOCOL __iter__ : () -> Iterator[A] # # struct Iterator[A] (Iterable[A]): # __next__ : !() -> A # # def __iter__(self): return self # protocol Reversible[A] (Iterable[A]): __reversed__ : () -> Self protocol Container[A]: __contains__ : (A) -> bool protocol Sized: __len__ : () -> int protocol Indexed[A,B]: __getitem__ : (A) -> B protocol Collection[A] (Container[A], Sized, Iterable[A]): @staticmethod __fromiter__ : (Iterable[A]) -> Self protocol Set[A] (Collection[A], Ord, Logical, Minus): isdisjoint : (Set[A]) -> bool def __le__(a: Self, b: Self): if len(a) > len(b): return False for elem in a: if elem not in b: return False return True def __lt__(a: Self, b: Self): if len(a) == len(b): return False return a <= b def __eq__(a: Self, b: Self): return len(a) == len(b) and a <= b def __or__(a: Self, b: Self): chain = [ e for s in [a,b] for e in s ] return fromiter(chain) def isdisjoint(self: Self, other: Set[A]): for value in b: if value in self: return False return True extension Set[A (Hashable)] (Hashable): def __hash__(self): n = 12345 for k in self: n += hash(k) return n struct frozenset[A (Hashable)] (Set[A], Hashable): # HYPOTHETICAL DEFINITION! _val : frozendict[A,()] def __contains__(self, a): return a in self._val.keys() def __fromiter__(items: Iterable[A]): return frozenset(_val = { i:() for i in items }) def __len__(self): return len(self._val) def __iter__(self): return iter(self._val.keys()) protocol MutableSet[A] (Set[A], IncrementalLogical[Set[A]], IncrementalMinus[Set[A]]): add : !(A) -> None pop : !() -> A clear : !() -> None update : !(Set[A]) -> None def clear(self: Self): try: while True: self.pop() except KeyError: pass def __ior__(self: Self, other: Set[A]): for value in other: self.add(value) class set[A (Hashable)] (MutableSet[A]): def __len__(self): ... def __contains__(self, a): ... def __iter__(self): ... def __eq__(self, other): ... def __lt__(self, other): ... def __or__(self, other): ... def add(self, a): ... def update(self, other): ... def __ior__(self, other): ... def copy(self): ... protocol MutableIndexed[A,B] (Indexed[A,B]): __setitem__ : !(A,B) -> None __delitem__ : !(A) -> None protocol Mapping[A,B] (Collection[A], Indexed[A,B]): keys : () -> Iterator[A] values : () -> Iterator[B] items : () -> Iterator[(A,B)] extension Mapping[A, B(Eq)] (Eq): def __eq__(a: Self, b: Self): if len(a) != len(b): return False for i in a: if i not in b: return False if a[i] /= b[i]: return False return True protocol MutableMapping[A,B] (Mapping[A,B], MutableIndexed[A,B]): update : !(Mapping[A,B]) -> None protocol Sequence[A] (Collection[A], Indexed[int,A], Reversible[A], Plus): def __add__(self, other): ... def __contains__(self, key): ... def __iter__(self): ... def __reversed__(self): ... extension Sequence[A(Eq)] (Eq): def __eq__(a: Self, b: Self): if len(a) != len(b): return False for i in range(0,len(a)): if a[i] != b[i]: return False return True extension Sequence[A (Eq)]: index : (A) -> int? count : (A) -> int def index(self, val): ... def count(self, val): ... protocol MutableSequence[A] (Sequence[A], MutableIndexed[int,A], IncrementalPlus[Sequence[A]]): append : !(A) -> None __iadd__ : !(Sequence[A]) -> None def append(self, other): ... def __iadd__(self, other): self.append(other) ================================================ FILE: workspace/Typesystem.txt ================================================ TODO: - Distinguishing required and available (defaulted) class/protocol attributes - Check subtyping (not equality) among overridden methods in classes - Witness translation - Automatic lifting of 's' to str (subtyping?) - Automatic lifting of int,... etc to (int|u) (subtyping?) - Static deadlock detection - Protocols as types, with existential quantification - Struct cases (and pattern-matching) - Type parameter variances - Higher-order polymorphism - Type macros / abstract types / associated types - Kind correctness - Read state effect (distinguish state effects per data structure?) - Clean up row order (l-to-r or r-to-l) - Read MPJ's Parametric Type Classes NOTES: - Named structs are gone! Their equivalents are obtained by classes inheriting from "struct". - Static methods in protocols must mention Self, or else they would be ambiguous (see translation into classes) - Methods that mention Self in a negative position *must* be static in order to preserve type soundness - Static methods (or just methods that mention Self negatively) must only be selected by class. - The [q] part in class, protocol and extension is required, but can be left out (and inferred) in actor and def(s). - Unambiguity in type schemes: for each [q]=>t it must hold that fv(q) <= fv(t) (not checked here) - Structs, classes and protocols have no ambiguity problems since q is always explicit there and the dom(q) are all in the resulting type. - Consistency requirement on extensions not checked here (from Haskell): if N |- t impl p and N |- p(p') then N |- t impl u' - Alternatively: if N |- t ~ extension(u) and N |- u < u' then N |- t ~ extension(u') - Concretely: if c:[q]=>extension(d[o]) and d[q']=>protocol(d'[o']) both exist in N then c:[q"]=>extension(d'[o"]) must also exist in N such that [o/dom(q')]o' = phi(o") and N,q,[o/dom(qd)]q' |- q" - Acyclic subtype/protocol hierarchy not checked here - Single subtype ancestry not checked here - Protocol attributes must be globally unique (not checked here) - Precondition to rule ImplExt: a unique (or best matching...) t(u) extension must exist in N (not checked here) - Termination requirements on q in extension c[q](o) not checked here (allow growing terms except in protocol cycles) - Self in the range of a substitution is forbidden but not checked here (maybe allow in covariant positions in the future) - Python's @classmethods are gone! Absorbed by protocols. - On class signatures: Attribute | stored in class: | stored in instance: | ----------------------------------------------------------------------- of function type: | (default) | @property | | @static | | ----------------------------------------------------------------------- of ground type: | @static | @property (default) | ----------------------------------------------------------------------- - Protocol signatures can only use @static - Unused meta variables: d,i,s,I,J,P,U,Y ***** Syntax *************************************************************************************************************************************************** Protocol names: P Class names: C including int,bool,str,string literals,Msg,Ref,super Type variables: X includes Self Types: t,u ::= X | c | EX(p) | e(r)->t | (r) | ?t | None var, con, existential, fun, tuple/record, opt, void Protocols: p ::= P[o] Classes: c ::= C[o] including int,bool,str,string literals,Msg,Ref,super Type orderings: o ::= t,o | . associative Rows: r ::= h,k associative Head rows: h ::= t,h | *X | . associative Keyword rows: k ::= x:t,k | **X | . associative, commutative\duplicates Effects: e ::= pure | mut[X] | act[X] | async | actor | X Function contexts: f ::= e[t] Type schemas: T ::= [q]=>t | t Qua(l|nt)ifiers: q ::= X(c,pi),q | . associative Goals: g ::= t(c,pi),g | . associative Environments: N ::= C:[q]=>(c;n) | P:[q]=>(pi;n) | w:[q]=>C(p) | w:q | x:T | z:t | x:# | z:# | N,N | . associative, commutative\duplicates Attribute envs: n ::= x:T | n,n | . associative, commutative\duplicates Witness variables: v Witness terms: w ::= (subset of E) ***** Judgments ************************************************************************************************************************************************ N |- D : N' Declaration D generates bindings N' in environment N N |- w : c ~ n Class type c exports attributes n, if instantiated with w N |- w : p ~ n Protocol p exports attributes n, if instantiated with w N |- w : g Goal (constraint) g holds, as witnessed by w N |- w : t < t' Type (schema) T is a subtype (schema) of T' in environment N, as witnessed by w N |- E : T | e Expression E has type (scheme) T and effect e in environment N N |- F : r | N' Formal F has type row r in environment N (if updated with N') N |- S : N' | f Statement S generates bindings N' in environment N and function context f N |- X : N' | f Except clause X generates bindings N' in environment N and function context f N |- S : t | e Statement S returns values of type t with effect e in environment N ***** N |- D : N' ********************************************************************************************************************************************** N,v:q |- _ : c1 ~ n1 n not in n1 N |- M : n' ~> M' n' in [q,Self(C[dom(q)]]=>(Self)->(n,n1) ------------------------------------------------------------------------------------------------------- (Class) N |- class C[q](c1):n,M : C:[q]=>(mro(c1);n,n1) ~> !class C[q](c):(n,M') N,v:q |- wi : pi ~ ni / all i n not in ni N,v:q |- M : n' ~> M' n' in [Self(P[dom(q)])]=>(Self)->(n,ni) ------------------------------------------------------------------------------------------------------------------------------------- (Proto) N |- protocol P[q](pi):n,M : P:[q]=>(mro(pi);n,ni) ~> !class P[Self,q]():(n,(v')->[v'.v/v]M',def _init_(v',v):v'.i=pi(wi);v'.v=v) N,v:q |- w : p1 ~ n1 N,v:q |- _ : C[dom(q)] ~ n N,v:q |- M : n' ~> M' n' in [Self(C[dom(q)])]=>(Self)->(n1) ----------------------------------------------------------------------------------------------------------------------------------------------- (Ext) N |- extension C[q](p1):M : P_C:[q]=>C(mro(p1)) ~> !class P_C[q](P[C[dom(q)],o]):((v')->[v'.v/v]M',def _init_(v',v):p1._init_(v',w);v'.v=v) N' = N,v:q,bv(F,S):#,bz(S):#,_self_:Ref[X] N' |- F : r | N1 N',N1 |- S : t | act[X] X not in fv(N,q,r,t) --------------------------------------------------------------------------------------------------------------------- (Actor) N |- actor x[q](F):S : (x : [q]=>actor(r)->t) ~> actor x[dom(q)](v:q,F'):S' N' = N,v:q,bv(F,S):# N' |- F : r | N1 | e N',N1 |- S : t | e ----------------------------------------------------------------------- (Def) N |- def x[q](F):S : (x : [q]=>e(r)->t) ~> def x[dom(q)](v:q,F'):S' N |- D1 : N1 N |- D2 : N2 ------------------------------ (Decls) N |- D1,D2 : N1,N2 ***** N |- w : c ~ n ******************************************************************************************************************************************* N,C:[q]=>(c;n) |- w : [o/q]q ----------------------------------- (SigC) N,C:[q]=>(c;n) |- w : C[o] ~ [o/q]n ***** N |- w : p ~ n ******************************************************************************************************************************************* N,P:[q]=>(pi;n) |- w : [o/q]q ------------------------------------ (SigP) N,P:[q]=>(pi;n) |- w : P[o] ~ [o/q]n ***** N |- w : g *********************************************************************************************************************************************** N,C:[q]=>(c;n) |- w : [o/q]q N,v:[q]=>C(p) |- w : [o/q]q -------------------------------------- (WitC) ------------------------------------- (WitP) N,C:[q]=>(c;n) |- \x:x : C[o] ([o/q]c) N,v:[q]=>C(p) |- v(w) : C[o] ([o/q]p) N,P:[q]=>(pi;n) |- w : t(P[o]) ------------------------------------------- (WitSub) N,P:[q]=>(pi;n) |- w.i : t([o/q]pi) / all i N |- w' : t < c N |- w : t(pi),g N |- wi : t(pi) / all i N |- w : g ----------------------------------- (ConsC) -------------------------------------- (ConsP) ----------- (Cons0) N |- w : t(c,pi),g N |- (wi,*w) : t(pi),g N |- () : . -------------- (WitHyp) N,v:q |- v : q N |- w : t(c,pi),g N |- w : t(c,pi),g N |- w : t(c,pi),g ------------------ (HypC) ------------------------ (HypP) --------------------- (Hyp1) N |- \x:x : t < c N |- w.i : t(pi) / all i N |- w.*i : g / max i ***** N |- w : t < t' ****************************************************************************************************************************************** N |- w : t < t' N |- w' : t' < t'' ----------------- (SubRefl) ------------------------------------- (SubTrans) N |- \x:x : t < t N |- \x.w'(w(x)) : t < t'' N |- w : t(p) N,p:[q]=>(pi;r) |- w : [o/q]q ------------------------- (SubPack) ---------------------------------------------------------------- (SubEX) N |- \x:(w,x) : t < EX(p) N,p:[q]=>(pi;r) |- \x:(x.0.i,x) : EX(P[o]) < EX([o/q]pi) / all i N |- w : (r') < (r) N |- w' : t < t' N |- e < e' N |- _self_ : Ref[X] ------------------------------------------------------- (SubFun) ---------------------------------------------------- (SubAsync) N |- \x:\***y:w'(x(***w(y))) : e(r)->t < e'(r')->t' N |- \x:ASYNC(_self_,x) : act[X](r)->t < async(r)->t ------------------ (SubPure) -------------------- (SubMut) N |- pure < mut[X] N |- mut[X] < act[X] ------------------------------------ (SubMsg) ------------------------------- (SubNew) N |- async(r)->t < act[X](r)->Msg[t] N |- actor(r)->t < act[X](r)->t N |- w : (k) < (r) N |- w : t < t' N |- w' : (r) < (r') ------------------------------------- (SubOptP) ------------------------------------------------------------ (SubRowP) N |- \v:(None,***w(v)) : (k) < (?t,r) N |- \v: (\x,***y: (w(x),***w'(y)) )(***v) : (t,r) < (t',r') N |- w : () < (k) N |- w : t < t' N |- w' : (k) < (k') --------------------------------------- (SubOptK) --------------------------------------------------------------- (SubRowK) N |- \v:(x=None,**w(v)) : () < (x:?t,k) N |- \v: (\x,**y: (x=w(x),**w'(y)) )(**v) : (x:t,k) < (x:t',k') N |- w : t < t' N |- w' : (r) < (k) ----------------------------------------------------------- (SubShift) ------------------- (SubStr) N |- \v:(\x,***y:(x=w(x),**w'(y)))(***v) : (t,r) < (x:t',k) N |- \x:x : s < str ------------------ (SubOpt) --------------------- (SubNone) N |- \x:x : t < ?t N |- \x:x : None < ?t ***** N |- E : T | e ******************************************************************************************************************************************* N |- E : t | e ~> E' N |- w : t < t' N |- e < e' N |- E : [q]=>t | e ~> E' N |- w : [o/q]q -------------------------------------------------------- (Sub) --------------------------------------------- (Inst) N |- E : T' | e' ~> w(E') N |- E : [o/q]t | e ~> app(E,w) N |- _self_ : Ref[X] ------------------------- (Var) ------------------------------------- (Read) N,x:t |- x : t | e ~> x N,z:t |- z : t | act[X] ~> _self_.z N |- E : (t,r) | e N |- E : (t,r) | e N |- E : (h,x:t,k) | e ------------------ (SelHead) ------------------- (SelTail) ---------------------- (SelKwd...) N |- E.0 : t | e N |- E.*1 : (r) | e N |- E.x : t | e N |- E : t | e ~> E' N |- t < c N |- w : c ~ (x:T,n) Self not in T- N |- w : C[o] ~ (x:T,n) --------------------------------------------------------------------------- (Sel) -------------------------------------------------------- (CSel) N |- E.x : [t/Self]T | e ~> app(E'.x, w) N |- C.x : [C[o]/Self]addself(T) | e ~> app2nd(C.x, w) N |- E : t | e ~> E' N |- w : t (p) N |- w : p ~ (x:T,n) N |- w : C[o] (p) N |- w : p ~ (x:T,n) -------------------------------------------------------------- (SelP) --------------------------------------------- (CSelP) N |- E.x : [t/Self]T | e ~> app(w.x, E') N |- C.x : [C[o]/Self]addself(T) | e ~> w.x N |- E : EX(p) | e ~> E' N |- _ : p ~ (x:T,n) Self not in T- N |- w : t (P[o]) N |- w : P[o] ~ (x:T,n) ------------------------------------------------------------------ (SelP') ------------------------------------------ (CSelP') N |- E.x : [EX(p)/Self]T | e ~> app(E'.0.x, E'.1) ... N |- P.x : [t/Self]addself(T) | e ~> w.x N' = N,bv(F):#,bz(N):# N' |- F : r | N1 N',N1 |- E : t | e N |- E : e(r)->t | e N |-> (A) : (r) | e ------------------------------------------------------------------ (Lam) -------------------------------------------- (App) N |- (lambda F: E) : e(r)->t | pure ~> lambda F: E' N |- E(A) : t | e N |- w : C[o] ~ (_init_:e(r)->None,n) ---------------------------------------- (Cons) N |- C : e(r)->C[o] | pure ~> app(C,w) N |- E : bool | e N |- E1 : t | e N |- E2 : t | e N |- S : t | e --------------------------------------------------------- (If1) ----------------- (Do) -------------------- (None) N |- E1 if E else E2 : t | e N |- do S : t | e N |- None : None | e N |- E : t | e N |- (A) : (r) | e N |- E : (h) | e N |- (M) : (k) | e ------------------------------------- (ETup) ---------------------------------------- (EStar1) N |- (E,A) : (t,r) | e N |- (*E,M) : (h,k) | e N |- E : t | e N |- (M) : (k) | e N |- E : (k) | e ------------------------------------- (ERec) -------------------- (EStar2) ------------------ (ENull) N |- (x=E,M) : (x:t,k) | e N |- (**E) : (k) | e N |- (.) : (.) | e N |- E : Msg[t] | act[X] ------------------------- (Await) N |- await E : t | act[X] ***** N |- F : r | N ******************************************************************************************************************************************* N |- x : t | N1 N,N1 |- F : r | N2 N |- x : (h) | N1 N,N1 |- K : k | N2 --------------------------------------- (PatTup) ------------------------------------------ (PatStar1) N |- x,F : t,r | N1,N2 N |- *x,K : h,k | N1,N2 N |- x : t | N1 N,N1 |- K : k | N2 N |- x : (k) | N1 --------------------------------------- (PatRec) ----------------- (PatStar2) N |- x,K : x:t,k | N1,N2 N |- **x : k | N1 N |- x : t | N1 N |- E : t | pure N,N1 |- F : r | N2 ------------------------------------------------------------ (PatOpt) -------------- (PatNull) N |- x=E,F : t,r | N1,N2 N |- . : . | . -------------------- (Bind) ------------------ (Rebind) N,x:# |- x : t | x:T N,x:t |- x : t | . ***** N |- S : N | f ******************************************************************************************************************************************* N |- E : t | e N |- x : t | N' N |- E : t | e N |- F : r | N' N |- E : (r) | e ------------------- (Run) ---------------------------------- (AssignVar) ------------------------------------ (AssignPat) N |- E : . | e[u] N |- x = E : N' | e[u] N |- (F) = E : N' | e[u] N,N' |- D : N' N |- E : t | e[t] ----------------- (Decl) -------------------------- (Return) ------------------- (Pass) N |- D : N' | f N |- return E : . | e[t] N |- pass : . | f N |- E1 : c | mut[X] N |- _ : c ~ (@prop x:t,r) N |- c < object[X] N |- E2 : t | mut[X] ------------------------------------------------------------------------------------------------- (Mut) N | E1.x = E2 : . | mut[X][u] N |- E : bool | e N |- S1 : N1 | f N |- S2 : N2 | f N |- E : bool | e N |- S : N' | f ----------------------------------------------------------- (If2) ------------------------------------- (While) N |- if E: S1 else S2 : N1&N2 | f N |- while E: S : . | f N,z:# |- E : t | mut[X] N |- _self_ : Ref[X] N,z:t |- E : t | mut[X] N |- _self_ : Ref[X] ------------------------------------------------ (State) ------------------------------------------------ (Write) N,z:# |- var z = E : z:t | mut[X] N,z:t |- z = E : . | mut[X] N |- E1 : int | act[X] N |- _self_ : Ref[X] N |- E2(A) : t | act[X] N |- S : N1 | f N,N1 |- S2 : N2 | f -------------------------------------------------------------------------- (After) --------------------------------------- (Seq) N |- after E1: E2(A) : . | act[X][u] N |- S1; S2 : N1,N2 | f N |- S : N1 | f N |- X : N2 | f N |- S1 : N1' | f N |- S2 : N2' | f N |- S : N' | e[t] N |- e < e' ----------------------------------------------------------------------------- (Try) ---------------------------------- (SubFX) N |- try S X else S1 finally S2 : ((N1,N1')&N2),N2' | f N |- S : N' | e'[t] ***** N |- X : N | f ******************************************************************************************************************************************* N,x:C[] |- S : N1 | f N |- X : N2 | f ---------------------------------------- (Except1) --------------- (Except0) N |- except C as x: S X : N1&N2 | f N |- . : N' | f ***** N |- S : t | e ******************************************************************************************************************************************* N |- S : N' | e[t] btc(N') # ftc(t,e) not thru(S) N |- S : N' | e[t] N |- None < t thru(S) --------------------------------------------------------- (Result) ----------------------------------------------- (Thru) N |- S : t | e N |- S : t | e thru(return E) = False thru(raise E) = False thru(while E: S) = thru(S) thru(if E: S1 else S2) = thru(S1) or thru(S2) thru(S1; S2) = thru(S1) and thru(S2) thru(try S X else S1 finally S2) = (thru(S;S1) or thru(X)) and thru(S2) thru(_) = True thru(except c as x: S X) = thru(S) or thru(X) thru(.) = False N |- S : t | mut[X] X not in fv(N,t) --------------------------------------- (RunST) N |- S : t | pure ################################################################################################################################################################ ################################################################################################################################################################ N,v:B(Ord) |- v._Eq_ : B(Eq) ------------------------------------------------- (SubInst) N,v:B(Ord) |- \y:y(v._Eq_) : [A(Eq)]=>t[A] < t[B] -------------------------------------------------------------- (SubGen) N |- \x:\v:(\y:y(v._Eq_))(x) : [A(Eq)]=>t[A] < [B(Ord)]=>t[B] N |- \x:\v: x(v._Eq_) : [A(Eq)]=>t[A] < [B(Ord)]=>t[B] N,v:A(Eq) |- \a,b: Eq._eq_(a,b) : (A,A)->bool ~> \a,b: v._eq_(a,b) ------------------------------------------------------------------------- (Gen) N |- \a,b: Eq._eq_(a,b) : [A(Eq)]=>(A,A)->bool ~> \v':\a,b: v'._eq_(a,b) N |- \x:\v:x(v._Eq_) : [A(Eq)]=(A,A)->bool[A] < [B(Ord)]=>(B,B)->bool[B] ----------------------------------------------------------------------------------------------------------------------------------------------------------- (Sub) N |- \a,b: Eq._eq_(a,b) : [B(Ord)]=>(B,B)->bool ~> (\x:\v:x(v._Eq_))(\v':\a,b: v'._eq_(a,b)) N |- \a,b: Eq._eq_(a,b) : [B(Ord)]=>(B,B)->bool ~> \v:(\v':\a,b: v'._eq_(a,b))(v._Eq_) N |- \a,b: Eq._eq_(a,b) : [B(Ord)]=>(B,B)->bool ~> \v:\a,b: v._Eq_._eq_(a,b) ################################################################################### class Apa [X(Eq)]: a : X def _init_(self,a:X): : [X(Eq), Self(Apa[X])] => (Self, X) -> None self.a = a def apa(self, y:X): : [X(Eq), Self(Apa[X])] => (Self, X) -> bool return Eq._eq_(self.a, y) class Bepa [X(Ord)] (Apa[X]): [X(Ord)]=>Bepa[X](Apa[X]) |- b : X def _init_(self, a:X, b:X): : [X(Ord), Self(Bepa[X])] => (Self, X, X) -> None Apa._init_(self,a) self.b = b def bepa(self, y:X): : [X(Ord), Self(Bepa[X])] => (Self, X) -> bool return self.apa(y) or Ord._lt_(self.b, y) =====> class Apa [X]: a : X def _init_(self, w:Eq[X], a:X): : [X, S(Apa[X])] => (S, Eq[X], X) -> None self.a = a def apa(self, w:Eq[X], y:X): : [X] => (Apa, Eq[X], X) -> bool return w._eq_(self.a, y) class Bepa [X] (Apa[X]): id:[X]=>(Ord[X],Apa[X])->Bepa[X] |- b : X def _init_(self, w:Ord[X], a:X, b:X): : [X] => (Bepa, Ord[X], X, X) -> None Apa._init_(self, _Ord_to_Eq(w), a) self.b = b def bepa(self, w:Ord[X], y:X): : [X] => (Bepa, Ord[X], X) -> bool return self.apa(_Ord_to_Eq(w), y) or w._lt_(self.b, y) ################################################################################### protocol Container[A(Eq)]: Container:[A(Eq)]=>(_contains_:(A)->bool) |- _contains_ : (A) -> bool def _contains_(self:Self, a:A): return False protocol Maximal[A(Ord)] (Container[A]): ..., Maximal:[A(Ord)]=>(max:()->A), [A(Ord)]=>Maximal[A](Container[A]) |- max : () -> A extension list[A(Ord)] (Maximal[A]): def _contains_(self:Self, a:A): for i in range(len(self)): if Eq._eq_(self[i], a): return True return False def max(self:Self): m = None for i in range(len(self)): if Ord._lt_(m, self[i]): m = self[i] return m =====> class Container[S,A]: Container:[S,A]=>(w1:Eq[A], _contains_:(S,A)->bool) |- w1 : Eq[A] _contains_ : (S, A) -> bool def _contains_(wit:Self, self:S, a:A): return False class Maximal[S,A] (Container[S,A]): ..., Maximal:[S,A]=>(w2:Ord[A], max:(S)->A), id:[S,A]=>(Container[S,A])->Maximal[S,A] |- w2 : Ord[A] max : (S, A) -> A class Maximal_list[A] (Maximal[list[A],A]): def _init_(wit:Self, w:Ord[A]): wit.w1 = w wit.w2 = w def _contains_(wit:Self, self:S, a:A): for i in range(len(self)): if wit.w1._eq_(self[i], a): return True return False def max(wit:Self, self:S): m = None for i in range(len(self)): if wit.w2._lt_(m, self[i]): m = self[i] return m ################################################################################### CONV(cs) = CONV(ds,cs) for ds in lbr(cs) CONV(d,cs) for d in rbr(cs) class nm(cs) tpar(cs) base(cs): d : d tpar(d) for d in newrbr(cs) + last(cs) def __init__(x,xs): where x,xs = par(cs) x.d = nm(d,ds,cs)(x,xs) for d,ds in lbr(cs) x.d = nm(d,cs)(x,xs) for d in rbr(cs) x.d = c for (d,c) in binds(cs) ... br(c) = { cs,c | cs in br(d) } U { d,c | d in ds } if c(d,ds) lbr(c..) = br(d) rbr(c..) = {ds} newrbr(c) = rbr(c) newrbr(cs) = {} br(c) = lbr(c..) = rbr(c..) = {} otherwise c << d = if c(d',ds) and d' = d or d' << d nm(c) = _c nm(cs,ds) = nm(cs)nm(ds) base(c) = (d[S,o]) if c[q](d[o],ds) = () otherwise base(cs,c) = (nm(cs)[dom(q)]) if tpar(c) = [q] last(c) = {} last(cs,c) = {c} binds(c,cs) = cs `zip` rh(cs) rh(cs,d,c) = rh(cs,c),c if c << d = rh(cs,d),c otherwise rh(cs) = cs tpar(cs,c) = [Self,q] if c[q](...) par(d,c,cs) = par(c,cs) if c << d = d,par(c,cs) otherwise par(xs) = cs ################################################################ A B C D E F G H \ . \ . \ . \ . \ . \ . \ . \ . I J K L \ . \ . \ . \ . \ . \ . M N \ . \ . \ . \ . \ . O A[X,Y]() B[Z]() C() D() E() F() G() H() I[X](A[X,int],B[str]) J[Z](C,D) K(E,F) L(G,H) M[X](I[bool],J[(X,X)]) N(K,L) O(M,N) ----------------------------------------------------------------- # CONV(A) lbr(A) = {} rbr(A) = {} class A[X,Y](): par(A) = A def __init__(A): rh(.) = . pass ... B - G similarly ... # CONV(I) lbr(I) = {} rbr(I) = {B} # CONV(B,I) lbr(B) = {} rbr(B) = {} class B_I[X](B[str]): par(B,I) = B,par(I) = B,I I : I def __init__(B,I): rh(I) = I B.I = I class I[X](A[X,int]): par(I) = I B : B[str] def __init__(I): rh(.) = . I.B = B_I(@X,I) # CONV(J) lbr(J) = {} rbr(J) = {D} # CONV(D,J) lbr(D) = {} rbr(D) = {} class D_J(D): par(D,J) = D,par(J) = D,J J : J def __init__(D,J): rh(J) = J D.J = J class J(C): par(J) = J D : D def __init__(J): rh(.) = . J.D = D_J(D) # CONV(K) lbr(K) = {} rbr(K) = {F} # CONV(F,K) lbr(F) = {} rbr(F) = {} class F_K(F): par(F,K) = F,par(K) = F,K K : K def __init__(F,K): rh(K) = K F.K = K class K(E): par(K) = K F : F def __init__(K): rh(.) = . K.F = F_K(K) # CONV(L) lbr(L) = {} rbr(L) = {H} # CONV(H,L) lbr(H) = {} rbr(H) = {} class H_L(H): par(H,L) = H,par(L) = L L : L def __init__(H,L): rh(L) = L H.L = L class L(G): par(L) = L H : H def __init__(L): rh(.) = . L.H = H_L(L) # CONV(M) lbr(M) = {B,I} rbr(M) = {J} # CONV(B,I,M) lbr(B) = {} rbr(B) = {} class B_I_M[X](B_I[bool]): par(B,I,M) = B,par(I,M) = B,par(M) = B,M M : M def __init__(B,M): rm(I,M) = rm(M),M = M,M B.I = M B.M = M # CONV(J,M) lbr(J) = {} rbr(J) = {D} # CONF(D,J,M) lbr(D) = {} rbr(D) = {} class D_J_M[X](D_J[(X,X)]): par(D,J,M) = D,par(J,M) = D,J,par(M) = D,J,M M : M def __init__(D,J,M): rh(J,M) = rh(J),M = J,M D.J = J D.M = M class J_M[X](J[(X,X)]): par(J,M) = J,par(M) = J,M M : M def __init__(J,M): rh(M) = M J.D = D_J_M(J,M) J.M = M class M[X](I[bool]): par(M) = M J : J def __init__(M): rh(.) = . M.B = B_I_M(@bool,M) M.J = J_M(M) # CONV(N) lbr(N) = {F,K} rbr(N) = {L} # CONV(F,K,N) lbr(F) = {} rbr(F) = {} class F_K_N(F_K): par(F,K,N) = F,par(K,N) = F,par(N) = F,N N : N def __init__(F,N): rh(K,N) = rn(N),N = N,N F.K = N F.N = N # CONV(L_N) lbr(L) = {} rbr(L) = {H} # CONV(H,L,N) lbr(H) = {} rbr(H) = {} class H_L_N(H_L): par(H,L,N) = H,par(L,N) = H,L,par(N) = H,L,N N : N def __init__(H,L,N): rh(L,N) = rn(L),N = L,N H.L = L H.N = N class L_N(L): par(L,N) = L,par(N) = L,N N : N def __init__(L,N): rh(N) = N L.H = H_L_N(L,N) L.N = N class N(K): par(N) = N L : L def __init__(N): rh(.) = . N.F = F_K_N(N) N.L = L_N(N) # CONV(O) lbr(O) = {B,I,M,O | J,M} rbr(O) = {N} # CONV(B,I,M,O) lbr(B) = {} rbr(B) = {} class B_I_M_O (B_I_M): par(B,I,M,O) = B,par(I,M,O) = B,par(M,O) = B,par(O) = B,O O : O def __init__(B,O): rh(I,M,O) = rh(I,O),O = rh(O),O,O = O,O,O B.I = O B.M = O B.O = O # CONV(J,M,O) lbr(J) = {} rbr(J) = {D} # CONV(D,J,M,O) lbf(D) = {} rbr(D) = {} class D_J_M_O(D_J_M): par(D,J,M,O) = D,par(J,M,O) = D,J,par(M,O) = D,J,par(O) = D,J,O O : O def __init__(D,J,O): rh(J,M,O) = rh(J,O),O = R(J),O,O = J,O,O D.J = J D.M = O D.O = O class J_M_O(J_M): par(J,M,O) = J,par(M,O) = J,par(O) = J,O O : O def __init__(J,O): rh(M,O) = rh(O),O = O,O J.D = D_J_M_O(J,O) J.M = O J.O = O # CONV(N,O) lbr(N) = {F,K} rbr(N) = {L} # CONV(F,K,N,O) lbr(F) = {} rbr(F) = {} class F_K_N_O(F_K_N): par(F,K,N,O) = F,par(K,N,O) = F,par(N,O) = F,N,par(O) = F,N,O O : O def __init__(F,N,O): rh(K,N,O) = rn(K,N),O = rn(N),N,O = N,N,O F.K = N F.N = N F.O = O # CONV(L,N,O) lbr(L) = {} rbr(L) = {H} # CONV(H,L,N,O) lbr(H) = {} rbr(H) = {} class H_L_N_O(H_L_N): par(H,L,N,O) = H,par(L,N,O) = H,L,par(N,O) = H,L,N,par(O) = H,L,N,O O : O def __init(H,L,N,O): rh(L,N,O) = rn(L,N),O = rn(L),N,O = L,N,O H.L = L H.N = N H.O = O class L_N_O(L_N): par(L,N,O) = L,par(N,O) = L,N,par(O) = L,N,O O : O def __init__(L,N,O): rh(N,O) = rh(N),O = N,O L.H = H_L_N_O(L,N,O) L.N = N L.O = O class N_O(N): par(N,O) = N,par(O) = N,O O : O def __init__(N,O): rh(O) = O N.F = F_K_N_O(N,O) N.L = L_N_O(N,O) N.O = O class O(M): par(O) = O N : N def __init__(O): rh(.) = . O.B = B_I_M_O(O) O.J = J_M_O(O) O.N = N_O(O) ################################################################ protocol Eq: @staticmethod _eq_ : (Self,Self) -> bool protocol Ord (Eq): @staticmethod _le_ : (Self,Self) -> bool def _eq_(x,y): return _le_(x,y) and _le_(y,x) protocol Hmm (Eq): def _eq_(x,y): return False class Apa (Ord) def _eq_(x,y): return x.apa == y.apa or super._eq_(x,y) def _le_(x,y): return x.apa <= y.apa class Bepa (Apa,Hmm,Ord): def _le_(x,y): return x.bepa <= y.bepa self,other : Bepa Eq._eq_(self,other) ==============> mro: Bepa, Apa, Hmm, Ord, Eq class Eq[S]: _eq_ : (S,S) -> bool class Ord[S] (Eq[S]): _le_ : (S,S) -> bool def _eq_(wit,x,y): return wit._le_(x,y) and wit._le_(y,x) class Hmm[S] (Eq[S]): def _eq_(wit,x,y): return False class Apa (): pass class Ord_Apa[S(Apa)] (Ord[S]): # NOT class Ord_Apa[] (Ord[Apa]), which would preclude inheritance (in Bepa) def _eq_(wit,x,y): return x.apa == y.apa or super._eq_(x,y) # super == super(Ord_Apa,cls), i.e., it passes on cls to Ord._eq_! def _le_(wit,x,y): return x.apa <= y.apa class Bepa (Apa): pass # NOTE: [S(Bepa)]=>Ord_Bepa[S] Ord_Apa[S] class Hmm_Bepa[S(Bepa)] (Hmm[S]): _Ord : Ord_Bepa def __init__(wit): wit._Ord = Ord_Bepa(wit) def _eq_(wit,a,b): return False class Ord_Bepa[S(Bepa)] (Ord[S]): _Hmm : Hmm_Bepa _eq_ = Ord_Apa._eq_ # [S(Apa)]=>(S,S)->bool < [S(Bepa)]=>(S,S)->bool ?????????????? def _le_(wit,x,y): return x.bepa <= y.bepa self,other : Bepa _eq_(self,other) ==> Ord_Bepa._eq_(Ord_Bepa,self,other) ==> Ord_Apa._eq_(Ord_Bepa,self,other) ==> ... Ord._eq_(Ord_Bepa,self,other) ==> ... Ord_Bepa._le_(Ord_Bepa,self_other) and ... ==> ... self.bepa <= y.bepa ... ==============> struct Eq_class; struct Ord_class; typedef struct Eq_class *Eq_class; typedef struct Ord_class *Ord_class; $bool Ord$_eq_(Ord_class, $WORD, $WORD); struct Eq_class { struct Ord_class { // extends Eq_class $bool(*_eq_)(Eq_class,$WORD,$WORD); $bool (*_eq_)(Ord_class,$WORD,$WORD); }; $bool (*_le_)(Ord_class,$WORD,$WORD); }; $bool Ord$_eq_(Ord_class cls, $WORD x, $WORD y) { return cls->_le_(cls,x,y) && cls->_le_(cls,y,x); } ///// struct Apa; struct Bepa; typedef struct Apa *Apa; typedef struct Bepa *Bepa; struct Apa { struct Bepa { // extends Apa Apa_class __class__; Bepa_class __class__; $int apa; $int apa; }; $int bepa; }; ///// struct Ord_Apa; struct Ord_Bepa; typedef struct Ord_Apa *Ord_Apa; typedef struct Ord_Bepa *Ord_Bepa; $bool Apa$_eq_(Ord_Apa, Apa, Apa); $bool Bepa$_le_(Ord_Bepa, Bepa, Bepa); $bool Apa$_le_(Ord_Apa, Apa, Apa); struct Ord_Apa { // extends Ord_class struct Ord_Bepa { // extends Ord_class $bool (*_eq_)(Ord_Apa,Apa,Apa); $bool (*_eq_)(Ord_Bepa,Bepa,Bepa); $bool (*_le_)(Ord_Apa,Apa,Apa); $bool (*_le_)(Ord_Bepa,Bepa,Bepa); $bool (*Ord_Apa$super$_eq_)(Ord_Apa,Apa,Apa); $bool (*Ord_Apa$super$_eq_)(Ord_Bepa,Bepa,Bepa); } Ord_Apa = { } Ord_Bepa = { Apa$_eq_, // _eq_ Apa$_eq_, // _eq_ Apa$_le_, // _le_ Bepa$_le_, // _le_ Ord$_eq_ // Ord_Apa$super$_eq_ Ord$_eq_ // Ord_Apa$super$_eq_ }; }; $bool Apa$_eq_(Ord_Apa cls, Apa x, Apa y) { return x->apa==y->apa || cls->Ord_Apa$super$_eq_(cls,x,y); } $bool Apa$_le_(Ord_Apa cls, Apa x, Apa y) { $bool Bepa$_le_(Ord_Bepa cls, Bepa x, Bepa x) { return x->apa <= y->apa; return x->bepa <= y->bepa; } } ///// Bepa self; Bepa other; w_Ord_Bepa = &Ord_Bepa; w_Ord_Bepa->_eq_(w_Ord_Bepa,self, other) ==> Apa$_eq_(w_Ord_Bepa, self, other) ==> ... w_Ord_Bepa->Ord_Apa$super$_eq_(w_Ord_Bepa, self, other) ... Ord$_eq_(w_Ord_Bepa, self, other) ==> ... w_Ord_Bepa->_le_(w_Ord_Bepa, self, other) and ... ==> ... Bepa$_le_(w_Ord_Bepa, self, other) and ... ==> ... self.bepa <= other.bepa ... ######################## protocol Eq () protocol Ord (Eq) protocol Rational () protocol Integer (Rational) class tt () extension tt (Integer,Rational) extension tt (Ord) --- MRO(Eq) = [Eq] MRO(Ord) = [Ord,Eq] MRO(Rational) = [Rational] MRO(Integer) = [Integer,Rational] MRO(tt) = [tt] MRO(tt_1) = [tt_1,tt,Integer,Rational] MRO(tt_2) = [tt_2,tt_1,tt,Integer,Rational,Ord,Eq] MRO(tt_1) = [tt,Integer,Rational] MRO(tt_2) = [tt,Ord,Eq] ######################## **************************************************************************************************************************************************************** **************************************************************************************************************************************************************** ================================================ FILE: workspace/anomaly_detector/acton_anomaly_detector2.py ================================================ ''' @author: aagapi ''' import numpy as np import pandas as pd from optparse import OptionParser do_plots = True if do_plots: import matplotlib.pyplot as plt from statsmodels.tsa.seasonal import DecomposeResult import sys sys.path.append('python_libs/stl/') from stl import decompose, forecast, naive, drift, mean, seasonal_naive import datetime TRAIN_RATIO=0.75 parser = OptionParser() parser.add_option("-x", "--input-file-x", type="str", dest="file_name_x", default=None, help="Path to input file name X") parser.add_option("-n", "--feature-name", type="str", dest="feature_name", default=None, help="Input feature name") parser.add_option("-o", "--output-dir", type="str", dest="output_dir", default=None, help="Path to output dir for plots") parser.add_option("-R", "--train-ratio", dest="train_ratio", type="float", default=0.75, help="Train ratio") options, args = parser.parse_args() file_name_x=options.file_name_x feature=options.feature_name output_dir=options.output_dir TRAIN_RATIO=options.train_ratio anomaly_examples = { 'level_change' : ['ambient_temperature_system_failure.csv', 'ec2_cpu_utilization_825cc2.csv', 'ec2_cpu_utilization_ac20cd.csv', 'grok_asg_anomaly.csv', 'rds_cpu_utilization_cc0c53.csv', 'rds_cpu_utilization_e47b3b.csv'], 'outliers' : ['ec2_cpu_utilization_fe7f93.csv', 'rogue_agent_key_hold.csv'], 'seasonal' : ['Twitter_volume_GOOG.csv', 'art_daily_jumpsdown.csv', 'art_daily_jumpsup.csv', 'art_daily_nojump.csv', 'exchange-2_cpc_results.csv', 'exchange-2_cpm_results.csv', 'exchange-3_cpm_results.csv', 'nyc_taxi.csv', 'occupancy_6005.csv', 'occupancy_t4013.csv'], 'trending' : ['ambient_temperature_system_failure.csv'], 'variance_change' : ['exchange-3_cpm_results.csv'] } def plot_feature(observed_idx, observed, col_name): fig, ax1 = plt.subplots(figsize=(12, 5)) plt.title('{} time plot'.format(col_name)) plt.plot(observed, color='b') ax1.set_xlabel('time') ax1.set_ylabel('{}'.format(col_name), color='k') plt.legend(['{}'.format(col_name)], loc=(0.01, 0.95)) plt.savefig('%s/feature_plot_%s.png' % (output_dir, col_name)) plt.show() def plot_decomp(trend, seasonal, resid, observed, period_averages, feature): decomp = DecomposeResult(seasonal=seasonal, trend=trend, resid=resid, observed=observed, period_averages=period_averages) decomp.plot() plt.savefig('%s/decomp_%s.png' % (output_dir, feature)) plt.show() def plot_forecast(observed, observed_short, observed_idx, observed_idx_short, trend, seasonal, resid, forecast_array, forecast_idx, feature): plt.title('Forecast plot') plt.plot(observed_idx, observed, label='truth') ## '-' plt.plot(observed_idx_short, observed_short, label='obs') ## '-' plt.plot(observed_idx_short, trend, label='decomp.trend') ## ':' plt.plot(forecast_idx, forecast_array, label='FCAST' ) ## '-' plt.legend(); plt.savefig('%s/forecast_%s.png' % (output_dir, feature)) plt.show() def plot_forecast_and_anomalies(observed, observed_short, trend, seasonal, resid, forecast_array, forecast_idx, feature, anomalies, tag): plt.title('Anomaly algorithm: %s'%(tag)) plt.plot(observed_idx, observed, label='truth') ## '-' plt.plot(observed_idx_short, observed_short, label='obs') ## '-' plt.plot(observed_idx_short, trend, label='decomp.trend') ## ':' plt.plot(forecast_idx, forecast_array, label='FCAST' ) ## '-' for (start, end) in anomalies: print(start - forecast_idx[0], end - forecast_idx[0]) plt.plot(start, 10, end, 10, marker = 'o') plt.legend(); plt.savefig('%s/forecast_%s_%s.png' % (output_dir, feature, tag)) plt.show() def arrays_to_dict(observed_idx, observed): return {observed_idx[i]: observed[i] for i in range(len(observed_idx))} df = pd.read_csv(file_name_x) if feature is None: feature = file_name_x[(file_name_x.rfind('/')+1):file_name_x.rfind('.')] ## print(feature) DEFAULT_EMA_SMOOTHING_FACTOR = 0.2 DEFAULT_EMA_WINDOW_SIZE_PCT = 0.2 # Percentage threshold on anomaly score below which is considered noises. DEFAULT_NOISE_PCT_THRESHOLD = 0.001 def denoise_scores(scores): if scores: maximal = max(scores.values()) if maximal: for key in scores: if scores[key] < DEFAULT_NOISE_PCT_THRESHOLD * maximal: scores[key] = 0 return scores def compute_ema(smoothing_factor, points): ema = [] if(len(points) > 0): ema.append(points[0]) for i in range(1, len(points)): ema.append(smoothing_factor * points[i] + (1 - smoothing_factor) * ema[i - 1]) return ema def compute_anom_score_ema(lag_window_points, point, smoothing_factor): ema = compute_ema(smoothing_factor, lag_window_points)[-1] return abs(point - ema) def ema_anomaly_detector(timestamps, values, smoothing_factor = DEFAULT_EMA_SMOOTHING_FACTOR, lag_window_size = None, use_lag_window = True): """ Compute anomaly scores based on an exponential moving average. """ lag_window_size = lag_window_size if lag_window_size is not None else int(len(timestamps) * DEFAULT_EMA_WINDOW_SIZE_PCT) anom_scores = {} if use_lag_window: stdev = np.std(values) for i in range(len(timestamps)): timestamp = timestamps[i] value = values[i] if i < lag_window_size: anom_score = compute_anom_score_ema(values[:i + 1], value, smoothing_factor) else: anom_score = compute_anom_score_ema(values[i - lag_window_size: i + 1], value, smoothing_factor) if stdev: anom_scores[timestamp] = anom_score / stdev else: anom_scores[timestamp] = anom_score else: ema = compute_ema(smoothing_factor, values) stdev = np.std(values) for i in range(len(timestamps)): timestamp = timestamps[i] value = values[i] anom_score = abs((value - ema[i]) / stdev) if stdev else value - ema[i] anom_scores[timestamp] = anom_score return denoise_scores(anom_scores) def np_sign(arr): """ Stand-in for numpy sign()""" signs = [] for i in range(len(arr)): signs.append(1 if arr[i] > 0 else -1) return np.array(signs) def np_ones(size): """ Stand-in for numpy ones()""" ones = [] for i in range(size): ones.append(1) return np.array(ones) def np_argwhere(arr): """ Stand-in for numpy argwhere()""" indices = [] for i in range(len(arr)): if arr[i] > 0: indices.append(i) return np.array(indices) def np_fmax_const(arr, const): """ Stand-in for numpy fmax with a constant """ values = [] for i in range(len(arr)): values.append(arr[i] if arr[i] > const else const) return np.array(values) def np_convolve_valid(arr1, arr2): """ Stand-in for numpy convolve with mode = valid (no extrapolation on edges) """ flipped_arr2 = [] for i in range(len(arr2)): flipped_arr2.append(arr2[len(arr2) - i - 1]) if len(arr2) > len(arr1): return np.array([]) convolution = [] for index in range(len(arr1) - len(arr2) + 1): sum = 0 for i in range(len(arr2)): sum += arr1[index + i] * flipped_arr2[i] convolution.append(sum) return np.array(convolution) def merge_ranges(ranges, max_gap): """ Merge ranges which are closer than max_gap """ merged_ranges = [] for range in ranges: if merged_ranges: curr_start, curr_end = range # compare against last interval in merged_ranges pre_start, pre_end = merged_ranges[-1] if curr_start - pre_end < max_gap: # merge current range with the last range in the list merged_ranges[-1] = (pre_start, max(curr_end, pre_end)) else: # append the new range to current one merged_ranges.append(range) else: # no merged ranges - just add this one merged_ranges.append(range) return merged_ranges def sign_test_anomaly_detector(x, y, k=24, alpha=0.05, offset=0.0, conf=0.01, gap=0): if len(x) != len(y) or len(x) < k: return list() # our filter to convolve with - just counts f = np_ones(k) # Threshold below calculated as quantile function for a binomial distribution with: # - probability of success=0.5 # - confidence level p=0.01 # - window size = 24 (2 hours at 5 minutes intervals) # == Smallest k such that Prob(X <= k) >= p # == scipy.stats.binom.ppf(1 - 0.01, 24, 0.5) - 1 qthresh = 17.0 alpha1 = 1. + alpha diff_array = x - offset diff_array = diff_array - (alpha1 * y) # this is 1 if bigger 0 otherwise d = np_fmax_const(np_sign(diff_array), 0) # d = np_fmax_const(np_sign(x - offset - (1. + alpha) * y), 0) # d = np.fmax(np.sign(x - offset - (1. + alpha) * y), 0) con = np_convolve_valid(d, f) # con = np.convolve(f, d, mode='valid') a = np_fmax_const(con - qthresh, 0) # a = np.fmax(con - qthresh, 0) ranges = [] for t in np_argwhere(a): ranges.append((t, t + k)) ranges = merge_ranges(ranges, gap) return ranges ## df['timestamp']=pd.to_datetime(df['timestamp']) ## df = df.set_index('timestamp') observed_idx = df['timestamp'].values observed = df['value'].values if do_plots: plot_feature(observed_idx, observed, feature) period=int(24 * 60 / 5) loess_window = 0.8 (trend, seasonal, resid, period_averages, phase) = decompose(observed, period=period, lo_window_frac=loess_window) if do_plots: plot_decomp(trend, seasonal, resid, observed, period_averages, feature) no_periods=int(len(observed)/period) observed_short = observed[:int(TRAIN_RATIO*no_periods)*period] observed_idx_short = observed_idx[:int(TRAIN_RATIO*no_periods)*period] observed_test = observed[int(TRAIN_RATIO*no_periods)*period:] observed_idx_test = observed_idx[int(TRAIN_RATIO*no_periods)*period:] (trend, seasonal, resid, period_averages, phase) = decompose(observed_short, period=period, lo_window_frac=loess_window) (forecast_array, forecast_idx) = forecast(observed_short, observed_idx_short, trend, seasonal, resid, period_averages, phase, steps=len(observed_test), fc_func=drift, forecast_seasonal=True, correlate_phase=False) if do_plots: plot_forecast(observed, observed_short, observed_idx, observed_idx_short, trend, seasonal, resid, forecast_array, forecast_idx, feature) df_observed_dict=arrays_to_dict(observed_idx_test, observed_test) fcast_dict=arrays_to_dict(forecast_idx, forecast_array) anomaly_windows = sign_test_anomaly_detector(observed_test, forecast_array, k=24, alpha=0.2, offset=0.0, conf=0.01, gap=0) anomaly_timestamps = [] for (start, end) in anomaly_windows: anomaly_timestamps.append((observed_idx_test[start], observed_idx_test[end])) print('Detected anomaly windows:', anomaly_timestamps) if do_plots: plot_forecast_and_anomalies(observed, observed_short, trend, seasonal, resid, forecast_array, forecast_idx, feature, anomaly_timestamps, 'anomaly_detector') ## anomaly_scores = ema_anomaly_detector(observed_idx, observed) ## print(anomaly_scores) if do_plots: plt.close('all') ================================================ FILE: workspace/anomaly_detector/acton_anomaly_detector3.py ================================================ ''' @author: aagapi ''' import numpy as np import pandas as pd from optparse import OptionParser do_plots = True if do_plots: import matplotlib.pyplot as plt from statsmodels.tsa.seasonal import DecomposeResult import sys sys.path.append('python_libs/stl/') from stl import decompose, forecast, naive, drift, mean, seasonal_naive import datetime TRAIN_RATIO=0.75 parser = OptionParser() parser.add_option("-x", "--input-file-x", type="str", dest="file_name_x", default=None, help="Path to input file name X") parser.add_option("-n", "--feature-name", type="str", dest="feature_name", default=None, help="Input feature name") parser.add_option("-o", "--output-dir", type="str", dest="output_dir", default=None, help="Path to output dir for plots") parser.add_option("-R", "--train-ratio", dest="train_ratio", type="float", default=0.75, help="Train ratio") options, args = parser.parse_args() file_name_x=options.file_name_x feature=options.feature_name output_dir=options.output_dir TRAIN_RATIO=options.train_ratio anomaly_examples = { 'level_change' : ['ambient_temperature_system_failure.csv', 'ec2_cpu_utilization_825cc2.csv', 'ec2_cpu_utilization_ac20cd.csv', 'grok_asg_anomaly.csv', 'rds_cpu_utilization_cc0c53.csv', 'rds_cpu_utilization_e47b3b.csv'], 'outliers' : ['ec2_cpu_utilization_fe7f93.csv', 'rogue_agent_key_hold.csv'], 'seasonal' : ['Twitter_volume_GOOG.csv', 'art_daily_jumpsdown.csv', 'art_daily_jumpsup.csv', 'art_daily_nojump.csv', 'exchange-2_cpc_results.csv', 'exchange-2_cpm_results.csv', 'exchange-3_cpm_results.csv', 'nyc_taxi.csv', 'occupancy_6005.csv', 'occupancy_t4013.csv'], 'trending' : ['ambient_temperature_system_failure.csv'], 'variance_change' : ['exchange-3_cpm_results.csv'] } def plot_feature(observed_idx, observed, col_name): fig, ax1 = plt.subplots(figsize=(12, 5)) plt.title('{} time plot'.format(col_name)) plt.plot(observed, color='b') ax1.set_xlabel('time') ax1.set_ylabel('{}'.format(col_name), color='k') plt.legend(['{}'.format(col_name)], loc=(0.01, 0.95)) plt.savefig('%s/feature_plot_%s.png' % (output_dir, col_name)) plt.show() def plot_decomp(trend, seasonal, resid, observed, period_averages, feature): decomp = DecomposeResult(seasonal=seasonal, trend=trend, resid=resid, observed=observed, period_averages=period_averages) decomp.plot() plt.savefig('%s/decomp_%s.png' % (output_dir, feature)) plt.show() def plot_forecast(observed, observed_short, observed_idx, observed_idx_short, trend, seasonal, resid, forecast_array, forecast_idx, feature): plt.title('Forecast plot') plt.plot(observed_idx, observed, label='truth') ## '-' plt.plot(observed_idx_short, observed_short, label='obs') ## '-' plt.plot(observed_idx_short, trend, label='decomp.trend') ## ':' plt.plot(forecast_idx, forecast_array, label='FCAST' ) ## '-' plt.legend(); plt.savefig('%s/forecast_%s.png' % (output_dir, feature)) plt.show() def plot_forecast_and_anomalies(observed, observed_short, trend, seasonal, resid, forecast_array, forecast_idx, feature, anomalies, tag): plt.title('Anomaly algorithm: %s'%(tag)) plt.plot(observed_idx, observed, label='truth') ## '-' plt.plot(observed_idx_short, observed_short, label='obs') ## '-' plt.plot(observed_idx_short, trend, label='decomp.trend') ## ':' plt.plot(forecast_idx, forecast_array, label='FCAST' ) ## '-' for (start, end) in anomalies: print(start - forecast_idx[0], end - forecast_idx[0]) plt.plot(start, 10, end, 10, marker = 'o') plt.legend(); plt.savefig('%s/forecast_%s_%s.png' % (output_dir, feature, tag)) plt.show() df = pd.read_csv(file_name_x) if feature is None: feature = file_name_x[(file_name_x.rfind('/')+1):file_name_x.rfind('.')] ## print(feature) def np_sign(arr): """ Stand-in for numpy sign()""" signs = [] for i in range(len(arr)): signs.append(1 if arr[i] > 0 else -1) return np.array(signs) def np_ones(size): """ Stand-in for numpy ones()""" ones = [] for i in range(size): ones.append(1) return np.array(ones) def np_argwhere(arr): """ Stand-in for numpy argwhere()""" indices = [] for i in range(len(arr)): if arr[i] > 0: indices.append(i) return np.array(indices) def np_fmax_const(arr, const): """ Stand-in for numpy fmax with a constant """ values = [] for i in range(len(arr)): values.append(arr[i] if arr[i] > const else const) return np.array(values) def np_convolve_valid(arr1, arr2): """ Stand-in for numpy convolve with mode = valid (no extrapolation on edges) """ flipped_arr2 = [] for i in range(len(arr2)): flipped_arr2.append(arr2[len(arr2) - i - 1]) if len(arr2) > len(arr1): return np.array([]) convolution = [] for index in range(len(arr1) - len(arr2) + 1): sum = 0 for i in range(len(arr2)): sum += arr1[index + i] * flipped_arr2[i] convolution.append(sum) return np.array(convolution) def merge_ranges(ranges, max_gap): """ Merge ranges which are closer than max_gap """ merged_ranges = [] for range in ranges: if merged_ranges: curr_start, curr_end = range # compare against last interval in merged_ranges pre_start, pre_end = merged_ranges[-1] if curr_start - pre_end < max_gap: # merge current range with the last range in the list merged_ranges[-1] = (pre_start, max(curr_end, pre_end)) else: # append the new range to current one merged_ranges.append(range) else: # no merged ranges - just add this one merged_ranges.append(range) return merged_ranges def sign_test_anomaly_detector(x, y, k=24, alpha=0.05, offset=0.0, conf=0.01, gap=0): if len(x) != len(y) or len(x) < k: return list() # our filter to convolve with - just counts f = np_ones(k) # Threshold below calculated as quantile function for a binomial distribution with: # - probability of success=0.5 # - confidence level p=0.01 # - window size = 24 (2 hours at 5 minutes intervals) # == Smallest k such that Prob(X <= k) >= p # == scipy.stats.binom.ppf(1 - 0.01, 24, 0.5) - 1 qthresh = 17.0 alpha1 = 1. + alpha diff_array = x - offset diff_array = diff_array - (alpha1 * y) # this is 1 if bigger 0 otherwise d = np_fmax_const(np_sign(diff_array), 0) # d = np_fmax_const(np_sign(x - offset - (1. + alpha) * y), 0) # d = np.fmax(np.sign(x - offset - (1. + alpha) * y), 0) con = np_convolve_valid(d, f) # con = np.convolve(f, d, mode='valid') a = np_fmax_const(con - qthresh, 0) # a = np.fmax(con - qthresh, 0) ranges = [] for t in np_argwhere(a): ranges.append((t, t + k)) ranges = merge_ranges(ranges, gap) return ranges ## df['timestamp']=pd.to_datetime(df['timestamp']) ## df = df.set_index('timestamp') observed_idx = df['timestamp'].values observed = df['value'].values if do_plots: plot_feature(observed_idx, observed, feature) period=int(24 * 60 / 5) loess_window = 0.8 (trend, seasonal, resid, period_averages, phase) = decompose(observed, period=period, lo_window_frac=loess_window) if do_plots: plot_decomp(trend, seasonal, resid, observed, period_averages, feature) no_periods=int(len(observed)/period) observed_short = observed[:int(TRAIN_RATIO*no_periods)*period] observed_idx_short = observed_idx[:int(TRAIN_RATIO*no_periods)*period] observed_test = observed[int(TRAIN_RATIO*no_periods)*period:] observed_idx_test = observed_idx[int(TRAIN_RATIO*no_periods)*period:] print('AnomalyDetector: Forecasting on window of size', len(observed_idx), ', [', observed_idx[0], ', ' , observed_idx[-1], ']') (trend, seasonal, resid, period_averages, phase) = decompose(observed_short, period=period, lo_window_frac=loess_window) (forecast_array, forecast_idx) = forecast(observed_short, observed_idx_short, trend, seasonal, resid, period_averages, phase, steps=len(observed_test), fc_func=drift, forecast_seasonal=True, correlate_phase=False) if do_plots: plot_forecast(observed, observed_short, observed_idx, observed_idx_short, trend, seasonal, resid, forecast_array, forecast_idx, feature) anomaly_windows = sign_test_anomaly_detector(observed_test, forecast_array, k=24, alpha=0.2, offset=0.0, conf=0.01, gap=0) anomaly_timestamps = [] for (start, end) in anomaly_windows: anomaly_timestamps.append((observed_idx_test[start], observed_idx_test[end])) print('DETECTED ANOMALY WINDOWS:', anomaly_timestamps) if do_plots: plot_forecast_and_anomalies(observed, observed_short, trend, seasonal, resid, forecast_array, forecast_idx, feature, anomaly_timestamps, 'anomaly_detector') if do_plots: plt.close('all') ================================================ FILE: workspace/anomaly_detector/acton_anomaly_detector_demo.py ================================================ ''' @author: aagapi ''' import numpy as np import pandas as pd from optparse import OptionParser import sys sys.path.append('python_libs/stl/') from stl import decompose, forecast, naive, drift, mean, seasonal_naive TRAIN_RATIO=0.75 DEFAULT_EMA_SMOOTHING_FACTOR = 0.2 DEFAULT_EMA_WINDOW_SIZE_PCT = 0.2 # Percentage threshold on anomaly score below which is considered noises. DEFAULT_NOISE_PCT_THRESHOLD = 0.001 parser = OptionParser() parser.add_option("-x", "--input-file-x", type="str", dest="file_name_x", default=None, help="Path to input file name X") parser.add_option("-n", "--feature-name", type="str", dest="feature_name", default=None, help="Input feature name") parser.add_option("-o", "--output-dir", type="str", dest="output_dir", default=None, help="Path to output dir for plots") parser.add_option("-R", "--train-ratio", dest="train_ratio", type="float", default=0.75, help="Train ratio") options, args = parser.parse_args() file_name_x=options.file_name_x feature=options.feature_name output_dir=options.output_dir TRAIN_RATIO=options.train_ratio def arrays_to_dict(observed_idx, observed): return {observed_idx[i]: observed[i] for i in range(len(observed_idx))} if feature is None: feature = file_name_x[(file_name_x.rfind('/')+1):file_name_x.rfind('.')] ## print(feature) def denoise_scores(scores): if scores: maximal = max(scores.values()) if maximal: for key in scores: if scores[key] < DEFAULT_NOISE_PCT_THRESHOLD * maximal: scores[key] = 0 return scores def compute_ema(smoothing_factor, points): ema = [] if(len(points) > 0): ema.append(points[0]) for i in range(1, len(points)): ema.append(smoothing_factor * points[i] + (1 - smoothing_factor) * ema[i - 1]) return ema def compute_anom_score_ema(lag_window_points, point, smoothing_factor): ema = compute_ema(smoothing_factor, lag_window_points)[-1] return abs(point - ema) def ema_anomaly_detector(timestamps, values, smoothing_factor = DEFAULT_EMA_SMOOTHING_FACTOR, lag_window_size = None, use_lag_window = True): """ Compute anomaly scores based on an exponential moving average. """ lag_window_size = lag_window_size if lag_window_size is not None else int(len(timestamps) * DEFAULT_EMA_WINDOW_SIZE_PCT) anom_scores = {} if use_lag_window: stdev = np.std(values) for i in range(len(timestamps)): timestamp = timestamps[i] value = values[i] if i < lag_window_size: anom_score = compute_anom_score_ema(values[:i + 1], value, smoothing_factor) else: anom_score = compute_anom_score_ema(values[i - lag_window_size: i + 1], value, smoothing_factor) if stdev: anom_scores[timestamp] = anom_score / stdev else: anom_scores[timestamp] = anom_score else: ema = compute_ema(smoothing_factor, values) stdev = np.std(values) for i in range(len(timestamps)): timestamp = timestamps[i] value = values[i] anom_score = abs((value - ema[i]) / stdev) if stdev else value - ema[i] anom_scores[timestamp] = anom_score return denoise_scores(anom_scores) class Sensor(object): def __init__(self, file_name_x, feature, anomaly_detector, read_window_size = 100, repeats=100, trend=0.0): self.repeats = repeats self.trend = trend self.read_window_size = read_window_size self.anomaly_detector = anomaly_detector df = pd.read_csv(file_name_x) self.observed_idx = df['timestamp'].values self.observed = df['value'].values self.first_ts = self.observed_idx[0] self.last_ts = self.observed_idx[-1] self.timestep = self.observed_idx[1] - self.observed_idx[0] def fix_timestamps(self, observed_idx, add_lag): return (observed_idx + add_lag) def fix_trend(self, observed, repeat_count, trend): fixed_observed = np.zeros(len(observed)) for i in range(len(observed)): fixed_observed[i] = observed[i] + (repeat_count*len(observed)+i)*trend return fixed_observed def run(self): for i in range(self.repeats): observed_idx = self.fix_timestamps(self.observed_idx, i*(self.last_ts - self.first_ts + self.timestep)) if self.trend > 0: self.observed = self.fix_trend(self.observed, i, self.trend) num_windows = len(observed_idx) // self.read_window_size + (len(observed_idx) % self.read_window_size) for j in range(num_windows): observed_idx_w = observed_idx[j*self.read_window_size:(j+1)*self.read_window_size] observed_w = self.observed[j*self.read_window_size:(j+1)*self.read_window_size] print('Sensor: Sending window ', j, ' of repeat ', i, ', length=', len(observed_idx_w), len(observed_w)) self.anomaly_detector.update(observed_idx_w, observed_w) class AnomalyDetector(object): def __init__(self, period, loess_window, min_train_window_size=3000): self.observed_idx = None self.observed = None self.min_train_window_size = min_train_window_size self.period = period self.loess_window = loess_window def update(self, observed_idx_w, observed_w): # Append received window: if self.observed is None: assert self.observed_idx is None self.observed_idx = observed_idx_w self.observed = observed_w else: assert self.observed_idx is not None self.observed_idx = np.append(self.observed_idx, observed_idx_w) self.observed = np.append(self.observed, observed_w) # Truncate training window to last min_train_window_size entries: if len(self.observed_idx) > self.min_train_window_size: self.observed_idx = self.observed_idx[-self.min_train_window_size:] self.observed = self.observed[-self.min_train_window_size:] print('AnomalyDetector: Forecasting on window of size', len(self.observed_idx), ', [', self.observed_idx[0], ', ' , self.observed_idx[-1], ']') self.detect_anomalies(self.observed_idx, self.observed) def detect_anomalies(self, observed_idx, observed): no_periods=int(len(observed)/self.period) observed_short = observed[:int(TRAIN_RATIO*no_periods)*self.period] observed_idx_short = observed_idx[:int(TRAIN_RATIO*no_periods)*self.period] (trend, seasonal, resid, period_averages, phase) = decompose(observed_short, period=self.period, lo_window_frac=self.loess_window) (forecast_array, forecast_idx) = forecast(observed_short, observed_idx_short, trend, seasonal, resid, period_averages, phase, steps=(len(observed)-len(observed_short)), fc_func=drift, forecast_seasonal=True, correlate_phase=False) df_observed_dict=arrays_to_dict(observed_idx, observed) fcast_dict=arrays_to_dict(forecast_idx, forecast_array) anomaly_scores = ema_anomaly_detector(observed_idx, observed) print(anomaly_scores) anomaly_detector = AnomalyDetector(period=int(24 * 60 / 5), loess_window = 0.8, min_train_window_size=3000) sensor = Sensor(file_name_x, feature, anomaly_detector, read_window_size = 100, repeats=2, trend=0.0) sensor.run() ================================================ FILE: workspace/anomaly_detector/acton_anomaly_detector_demo2.py ================================================ ''' @author: aagapi ''' import numpy as np import pandas as pd from optparse import OptionParser import sys sys.path.append('python_libs/stl/') from stl import decompose, forecast, naive, drift, mean, seasonal_naive TRAIN_RATIO=0.75 DEFAULT_EMA_SMOOTHING_FACTOR = 0.2 DEFAULT_EMA_WINDOW_SIZE_PCT = 0.2 # Percentage threshold on anomaly score below which is considered noises. DEFAULT_NOISE_PCT_THRESHOLD = 0.001 parser = OptionParser() parser.add_option("-x", "--input-file-x", type="str", dest="file_name_x", default=None, help="Path to input file name X") parser.add_option("-n", "--feature-name", type="str", dest="feature_name", default=None, help="Input feature name") parser.add_option("-o", "--output-dir", type="str", dest="output_dir", default=None, help="Path to output dir for plots") parser.add_option("-R", "--train-ratio", dest="train_ratio", type="float", default=0.75, help="Train ratio") options, args = parser.parse_args() file_name_x=options.file_name_x feature=options.feature_name output_dir=options.output_dir TRAIN_RATIO=options.train_ratio if feature is None: feature = file_name_x[(file_name_x.rfind('/')+1):file_name_x.rfind('.')] ## print(feature) def np_sign(arr): """ Stand-in for numpy sign()""" signs = [] for i in range(len(arr)): signs.append(1 if arr[i] > 0 else -1) return np.array(signs) def np_ones(size): """ Stand-in for numpy ones()""" ones = [] for i in range(size): ones.append(1) return np.array(ones) def np_argwhere(arr): """ Stand-in for numpy argwhere()""" indices = [] for i in range(len(arr)): if arr[i] > 0: indices.append(i) return np.array(indices) def np_fmax_const(arr, const): """ Stand-in for numpy fmax with a constant """ values = [] for i in range(len(arr)): values.append(arr[i] if arr[i] > const else const) return np.array(values) def np_convolve_valid(arr1, arr2): """ Stand-in for numpy convolve with mode = valid (no extrapolation on edges) """ flipped_arr2 = [] for i in range(len(arr2)): flipped_arr2.append(arr2[len(arr2) - i - 1]) if len(arr2) > len(arr1): return np.array([]) convolution = [] for index in range(len(arr1) - len(arr2) + 1): sum = 0 for i in range(len(arr2)): sum += arr1[index + i] * flipped_arr2[i] convolution.append(sum) return np.array(convolution) def merge_ranges(ranges, max_gap): """ Merge ranges which are closer than max_gap """ merged_ranges = [] for range in ranges: if merged_ranges: curr_start, curr_end = range # compare against last interval in merged_ranges pre_start, pre_end = merged_ranges[-1] if curr_start - pre_end < max_gap: # merge current range with the last range in the list merged_ranges[-1] = (pre_start, max(curr_end, pre_end)) else: # append the new range to current one merged_ranges.append(range) else: # no merged ranges - just add this one merged_ranges.append(range) return merged_ranges def sign_test_anomaly_detector(x, y, k, alpha, offset, conf, gap): if len(x) != len(y) or len(x) < k: return list() # our filter to convolve with - just counts f = np_ones(k) # Threshold below calculated as quantile function for a binomial distribution with: # - probability of success=0.5 # - confidence level p=0.01 # - window size = 24 (2 hours at 5 minutes intervals) # == Smallest k such that Prob(X <= k) >= p # == scipy.stats.binom.ppf(1 - 0.01, 24, 0.5) - 1 qthresh = 17.0 alpha1 = 1. + alpha diff_array = x - offset diff_array = diff_array - (alpha1 * y) # this is 1 if bigger 0 otherwise d = np_fmax_const(np_sign(diff_array), 0) # d = np_fmax_const(np_sign(x - offset - (1. + alpha) * y), 0) # d = np.fmax(np.sign(x - offset - (1. + alpha) * y), 0) con = np_convolve_valid(d, f) # con = np.convolve(f, d, mode='valid') a = np_fmax_const(con - qthresh, 0) # a = np.fmax(con - qthresh, 0) ranges = [] for t in np_argwhere(a): ranges.append((t, t + k)) ranges = merge_ranges(ranges, gap) return ranges class Sensor(object): def __init__(self, file_name_x, feature, anomaly_detector, read_window_size, repeats, trend): self.repeats = repeats self.trend = trend self.read_window_size = read_window_size self.anomaly_detector = anomaly_detector df = pd.read_csv(file_name_x) self.observed_idx = df['timestamp'].values self.observed = df['value'].values print(len(self.observed)) self.first_ts = self.observed_idx[0] self.last_ts = self.observed_idx[-1] self.timestep = self.observed_idx[1] - self.observed_idx[0] def fix_timestamps(self, observed_idx, add_lag): return (observed_idx + add_lag) def fix_trend(self, observed, repeat_count, trend): fixed_observed = np.zeros(len(observed)) for i in range(len(observed)): fixed_observed[i] = observed[i] + (repeat_count*len(observed)+i)*trend return fixed_observed def run(self): for i in range(self.repeats): observed_idx = self.fix_timestamps(self.observed_idx, i*(self.last_ts - self.first_ts + self.timestep)) if self.trend > 0: self.observed = self.fix_trend(self.observed, i, self.trend) num_windows = len(observed_idx) // self.read_window_size + (len(observed_idx) % self.read_window_size) for j in range(num_windows): observed_idx_w = observed_idx[j*self.read_window_size:(j+1)*self.read_window_size] observed_w = self.observed[j*self.read_window_size:(j+1)*self.read_window_size] print('Sensor: Sending window ', j, ' of repeat ', i, ', length=', len(observed_idx_w), len(observed_w)) self.anomaly_detector.update(observed_idx_w, observed_w) class AnomalyDetector(object): def __init__(self, period, loess_window, min_train_window_size): self.observed_idx = None self.observed = None self.min_train_window_size = min_train_window_size self.period = period self.loess_window = loess_window def update(self, observed_idx_w, observed_w): # Append received window: if self.observed is None: assert self.observed_idx is None self.observed_idx = observed_idx_w self.observed = observed_w else: assert self.observed_idx is not None self.observed_idx = np.append(self.observed_idx, observed_idx_w) self.observed = np.append(self.observed, observed_w) # Truncate training window to last min_train_window_size entries: if len(self.observed_idx) > self.min_train_window_size: self.observed_idx = self.observed_idx[-self.min_train_window_size:] self.observed = self.observed[-self.min_train_window_size:] print('AnomalyDetector: Forecasting on window of size', len(self.observed_idx), ', [', self.observed_idx[0], ', ' , self.observed_idx[-1], ']') self.detect_anomalies(self.observed_idx, self.observed) def detect_anomalies(self, observed_idx, observed): no_periods=int(len(observed)/self.period) observed_short = observed[:int(TRAIN_RATIO*no_periods)*self.period] observed_idx_short = observed_idx[:int(TRAIN_RATIO*no_periods)*self.period] observed_test = observed[int(TRAIN_RATIO*no_periods)*self.period:] observed_idx_test = observed_idx[int(TRAIN_RATIO*no_periods)*self.period:] (trend, seasonal, resid, period_averages, phase) = decompose(observed_short, period=self.period, lo_window_frac=self.loess_window) (forecast_array, forecast_idx) = forecast(observed_short, observed_idx_short, trend, seasonal, resid, period_averages, phase, steps=len(observed_test), fc_func=drift, forecast_seasonal=True, correlate_phase=False) anomaly_windows = sign_test_anomaly_detector(observed_test, forecast_array, k=24, alpha=0.2, offset=0.0, conf=0.01, gap=0) anomaly_timestamps = [] for (start, end) in anomaly_windows: if end >= len(observed_idx_test): end = len(observed_idx_test) - 1 anomaly_timestamps.append((observed_idx_test[start], observed_idx_test[end])) print('DETECTED ANOMALY WINDOWS:', anomaly_timestamps) anomaly_detector = AnomalyDetector(period=int(24 * 60 / 5), loess_window = 0.8, min_train_window_size=4032) sensor = Sensor(file_name_x, feature, anomaly_detector, read_window_size = 126, repeats=2, trend=0.0) sensor.run() ================================================ FILE: workspace/anomaly_detector/datasets/selected/level_change/ambient_temperature_system_failure.csv ================================================ timestamp,value 2013-07-04 00:00:00,69.88083514 2013-07-04 01:00:00,71.22022706 2013-07-04 02:00:00,70.87780496 2013-07-04 03:00:00,68.95939994 2013-07-04 04:00:00,69.28355102 2013-07-04 05:00:00,70.06096581 2013-07-04 06:00:00,69.27976479 2013-07-04 07:00:00,69.36960846 2013-07-04 08:00:00,69.16671394 2013-07-04 09:00:00,68.98608257 2013-07-04 10:00:00,69.96506224 2013-07-04 11:00:00,70.55619466 2013-07-04 12:00:00,70.30750511 2013-07-04 13:00:00,70.24625215 2013-07-04 14:00:00,69.85490839 2013-07-04 15:00:00,71.64329118 2013-07-04 16:00:00,71.24565942 2013-07-04 17:00:00,70.74509976 2013-07-04 18:00:00,71.37329829 2013-07-04 19:00:00,71.7957509 2013-07-04 20:00:00,72.09160609999998 2013-07-04 21:00:00,71.55307612 2013-07-04 22:00:00,72.18769545 2013-07-04 23:00:00,70.64995744 2013-07-05 00:00:00,71.34274211 2013-07-05 01:00:00,71.5867281 2013-07-05 02:00:00,70.97700116 2013-07-05 03:00:00,70.24388209 2013-07-05 04:00:00,70.43282627 2013-07-05 05:00:00,69.74896285 2013-07-05 06:00:00,68.74938222 2013-07-05 07:00:00,69.35162661 2013-07-05 08:00:00,68.85314844 2013-07-05 09:00:00,70.31790951 2013-07-05 10:00:00,70.30055692 2013-07-05 11:00:00,72.53056283 2013-07-05 12:00:00,71.64320692 2013-07-05 13:00:00,72.92223804 2013-07-05 14:00:00,72.63758833 2013-07-05 15:00:00,72.95903086 2013-07-05 16:00:00,72.15222081 2013-07-05 17:00:00,72.16607562 2013-07-05 18:00:00,72.30558574 2013-07-05 19:00:00,72.3823022 2013-07-05 20:00:00,72.61234869 2013-07-05 21:00:00,72.77599570000002 2013-07-05 22:00:00,71.91696888 2013-07-05 23:00:00,71.55368851 2013-07-06 00:00:00,71.63096403 2013-07-06 01:00:00,70.59673521 2013-07-06 02:00:00,70.85248247 2013-07-06 03:00:00,71.08476824 2013-07-06 04:00:00,70.84723252 2013-07-06 05:00:00,70.23242259999999 2013-07-06 06:00:00,70.12823808 2013-07-06 07:00:00,69.92923136 2013-07-06 08:00:00,69.28574982 2013-07-06 09:00:00,69.72638712 2013-07-06 10:00:00,68.19010253 2013-07-06 11:00:00,68.91679541 2013-07-06 12:00:00,67.26820458 2013-07-06 13:00:00,66.9649601 2013-07-06 14:00:00,67.76538379 2013-07-06 15:00:00,66.91858576 2013-07-06 16:00:00,67.60522282 2013-07-06 17:00:00,67.17661097 2013-07-06 18:00:00,67.99254044 2013-07-06 19:00:00,67.25818019 2013-07-06 20:00:00,66.59407898 2013-07-06 21:00:00,67.86855757 2013-07-06 22:00:00,67.2922007 2013-07-06 23:00:00,67.16337656 2013-07-07 00:00:00,66.27568448 2013-07-07 01:00:00,65.96858705 2013-07-07 02:00:00,65.31642297 2013-07-07 03:00:00,65.42912751 2013-07-07 04:00:00,66.75098393 2013-07-07 05:00:00,64.68391715 2013-07-07 06:00:00,64.56520692 2013-07-07 07:00:00,66.12965686 2013-07-07 08:00:00,66.09613054 2013-07-07 09:00:00,64.9748123 2013-07-07 10:00:00,64.33478963 2013-07-07 11:00:00,65.54142516 2013-07-07 12:00:00,63.9130944 2013-07-07 13:00:00,65.00924432 2013-07-07 14:00:00,64.04781966 2013-07-07 15:00:00,64.25831852 2013-07-07 16:00:00,63.89332373 2013-07-07 17:00:00,64.14310465 2013-07-07 18:00:00,64.17594209 2013-07-07 19:00:00,63.1570819 2013-07-07 20:00:00,63.38689893 2013-07-07 21:00:00,63.99038726 2013-07-07 22:00:00,62.67478854 2013-07-07 23:00:00,64.24663357 2013-07-08 00:00:00,62.48078508 2013-07-08 01:00:00,62.03055446 2013-07-08 02:00:00,63.41156044 2013-07-08 03:00:00,61.70510991 2013-07-08 04:00:00,62.77513946 2013-07-08 05:00:00,61.36447611 2013-07-08 06:00:00,61.68984072 2013-07-08 07:00:00,62.20048874 2013-07-08 08:00:00,62.98280722 2013-07-08 09:00:00,64.44813096 2013-07-08 10:00:00,65.33294727 2013-07-08 11:00:00,66.51294379 2013-07-08 12:00:00,67.88554227 2013-07-08 13:00:00,67.22250712 2013-07-08 14:00:00,68.08885127 2013-07-08 15:00:00,68.55257476 2013-07-08 16:00:00,70.32033392 2013-07-08 17:00:00,70.48553783 2013-07-08 18:00:00,72.33830154 2013-07-08 19:00:00,71.1908248 2013-07-08 20:00:00,70.75989770000002 2013-07-08 21:00:00,70.57075487 2013-07-08 22:00:00,68.88572309999999 2013-07-08 23:00:00,68.36836764 2013-07-09 00:00:00,68.42198714 2013-07-09 01:00:00,67.55824354 2013-07-09 02:00:00,66.4884322 2013-07-09 03:00:00,66.00939653 2013-07-09 04:00:00,64.88258671 2013-07-09 05:00:00,65.79409771 2013-07-09 06:00:00,65.69617694 2013-07-09 07:00:00,66.14773729 2013-07-09 08:00:00,67.47861967 2013-07-09 09:00:00,67.43966413 2013-07-09 10:00:00,68.50079012 2013-07-09 11:00:00,69.93367814 2013-07-09 12:00:00,70.66856782 2013-07-09 13:00:00,69.43364009999999 2013-07-09 14:00:00,70.20645921 2013-07-09 15:00:00,70.23002897 2013-07-09 16:00:00,71.58361231 2013-07-09 17:00:00,71.56436778 2013-07-09 18:00:00,71.02917453 2013-07-09 19:00:00,72.831066 2013-07-09 20:00:00,71.13716811 2013-07-09 21:00:00,69.72083178 2013-07-09 22:00:00,69.17560647 2013-07-09 23:00:00,69.31959282 2013-07-10 00:00:00,68.81260454 2013-07-10 01:00:00,68.55716829 2013-07-10 02:00:00,67.73062887 2013-07-10 03:00:00,67.80815335 2013-07-10 04:00:00,66.93277621 2013-07-10 05:00:00,65.84066557 2013-07-10 06:00:00,66.15467548 2013-07-10 07:00:00,65.78125301 2013-07-10 08:00:00,67.33388757 2013-07-10 09:00:00,67.3485843 2013-07-10 10:00:00,69.75301970000001 2013-07-10 11:00:00,69.90438916 2013-07-10 12:00:00,70.59424483 2013-07-10 13:00:00,70.05946788 2013-07-10 14:00:00,71.02625542 2013-07-10 15:00:00,71.56116588 2013-07-10 16:00:00,70.98303947 2013-07-10 17:00:00,71.78059711 2013-07-10 18:00:00,73.40419990000002 2013-07-10 19:00:00,71.60391994 2013-07-10 20:00:00,70.48045714 2013-07-10 21:00:00,69.48780075 2013-07-10 22:00:00,69.37470081 2013-07-10 23:00:00,68.66754682 2013-07-11 00:00:00,69.05640228 2013-07-11 01:00:00,69.28118591 2013-07-11 02:00:00,68.00921159 2013-07-11 03:00:00,68.57902651 2013-07-11 04:00:00,66.49549932 2013-07-11 05:00:00,66.7500451 2013-07-11 06:00:00,66.42304923 2013-07-11 07:00:00,67.52779448 2013-07-11 08:00:00,67.89346899 2013-07-11 09:00:00,69.1011507 2013-07-11 10:00:00,70.51575503 2013-07-11 11:00:00,71.51359764 2013-07-11 12:00:00,70.78913828 2013-07-11 13:00:00,70.92408975 2013-07-11 14:00:00,71.43667911 2013-07-11 15:00:00,72.77048744 2013-07-11 16:00:00,72.18360109 2013-07-11 17:00:00,72.2317116 2013-07-11 18:00:00,72.14511125 2013-07-11 19:00:00,72.66568122 2013-07-11 20:00:00,71.74663208 2013-07-11 21:00:00,71.47523835 2013-07-11 22:00:00,70.17998073 2013-07-11 23:00:00,70.01828427 2013-07-12 00:00:00,69.63409091 2013-07-12 01:00:00,69.24166979 2013-07-12 02:00:00,69.44746561 2013-07-12 03:00:00,69.56135461 2013-07-12 04:00:00,67.43148423 2013-07-12 05:00:00,67.27588501 2013-07-12 06:00:00,67.64302314 2013-07-12 07:00:00,67.11633221 2013-07-12 08:00:00,68.58615434 2013-07-12 09:00:00,68.54878335 2013-07-12 10:00:00,69.78361434 2013-07-12 11:00:00,70.13666468 2013-07-12 12:00:00,71.79856679999997 2013-07-12 13:00:00,72.95326709 2013-07-12 14:00:00,73.38358272 2013-07-12 15:00:00,72.72556855 2013-07-12 16:00:00,74.27730941 2013-07-12 17:00:00,73.58946213 2013-07-12 18:00:00,73.07774519 2013-07-12 19:00:00,74.52428051 2013-07-12 20:00:00,72.52552383 2013-07-12 21:00:00,72.64264374 2013-07-12 22:00:00,73.47727338 2013-07-12 23:00:00,72.37521094 2013-07-13 00:00:00,71.20816904 2013-07-13 01:00:00,72.23586399 2013-07-13 02:00:00,71.09992340000002 2013-07-13 03:00:00,70.95986451 2013-07-13 04:00:00,70.25370091 2013-07-13 05:00:00,71.29442554 2013-07-13 06:00:00,70.37620145 2013-07-13 07:00:00,70.33534302 2013-07-13 08:00:00,68.96127518 2013-07-13 09:00:00,68.67478951 2013-07-13 10:00:00,68.68142551 2013-07-13 11:00:00,70.09922792 2013-07-13 12:00:00,69.29115996 2013-07-13 13:00:00,69.14944184 2013-07-13 14:00:00,69.38045679999999 2013-07-13 15:00:00,68.32729437 2013-07-13 16:00:00,68.71167009999999 2013-07-13 17:00:00,69.43031387 2013-07-13 18:00:00,69.12568539 2013-07-13 19:00:00,69.40509502 2013-07-13 20:00:00,68.64876516 2013-07-13 21:00:00,67.68106913 2013-07-13 22:00:00,69.16363194 2013-07-13 23:00:00,68.19982138 2013-07-14 00:00:00,68.1347302 2013-07-14 01:00:00,67.28588699 2013-07-14 02:00:00,67.77737459 2013-07-14 03:00:00,68.40400085 2013-07-14 04:00:00,68.12434843 2013-07-14 05:00:00,66.62975642 2013-07-14 06:00:00,67.75402118 2013-07-14 07:00:00,67.19706687 2013-07-14 08:00:00,66.19511529 2013-07-14 09:00:00,67.03467174 2013-07-14 10:00:00,66.39229109 2013-07-14 11:00:00,66.98910128 2013-07-14 12:00:00,66.70652022 2013-07-14 13:00:00,65.89533219 2013-07-14 14:00:00,66.15310629999999 2013-07-14 15:00:00,65.94826687 2013-07-14 16:00:00,66.18545065 2013-07-14 17:00:00,65.956704 2013-07-14 18:00:00,66.58099932 2013-07-14 19:00:00,67.19124175 2013-07-14 20:00:00,66.74457508 2013-07-14 21:00:00,65.89869767 2013-07-14 22:00:00,65.51804828 2013-07-14 23:00:00,65.98471013 2013-07-15 00:00:00,66.62908319 2013-07-15 01:00:00,64.90780861 2013-07-15 02:00:00,64.9498236 2013-07-15 03:00:00,65.64024470000001 2013-07-15 04:00:00,64.33322178 2013-07-15 05:00:00,65.81400458 2013-07-15 06:00:00,64.19811908 2013-07-15 07:00:00,65.79277627 2013-07-15 08:00:00,66.47022878 2013-07-15 09:00:00,66.21114689 2013-07-15 10:00:00,68.4034625 2013-07-15 11:00:00,69.51708004 2013-07-15 12:00:00,69.39746721 2013-07-15 13:00:00,70.91288645 2013-07-15 14:00:00,70.88878119 2013-07-15 15:00:00,71.10972093 2013-07-15 16:00:00,72.96756108 2013-07-15 17:00:00,72.02770961 2013-07-15 18:00:00,73.95202783 2013-07-15 19:00:00,73.37599022 2013-07-15 20:00:00,73.50769737 2013-07-15 21:00:00,72.71914771 2013-07-15 22:00:00,72.47419791 2013-07-15 23:00:00,72.0845572 2013-07-16 00:00:00,70.36089703 2013-07-16 01:00:00,71.0505306 2013-07-16 02:00:00,71.07182369 2013-07-16 03:00:00,70.51372607 2013-07-16 04:00:00,70.18259029999999 2013-07-16 05:00:00,69.85543379 2013-07-16 06:00:00,67.99007603 2013-07-16 07:00:00,68.45766038 2013-07-16 08:00:00,68.27103298 2013-07-16 09:00:00,68.96138225 2013-07-16 10:00:00,69.74436809 2013-07-16 11:00:00,70.61571518 2013-07-16 12:00:00,71.17846267 2013-07-16 13:00:00,72.386747 2013-07-16 14:00:00,72.41193764 2013-07-16 15:00:00,73.68813485 2013-07-16 16:00:00,73.74326223 2013-07-16 17:00:00,73.75611822 2013-07-16 18:00:00,74.32401543 2013-07-16 19:00:00,73.86398591 2013-07-16 20:00:00,73.78849309 2013-07-16 21:00:00,73.00264849 2013-07-16 22:00:00,72.04541547 2013-07-16 23:00:00,71.08743709 2013-07-17 00:00:00,71.9849653 2013-07-17 01:00:00,71.11160009999998 2013-07-17 02:00:00,70.99668759999999 2013-07-17 03:00:00,69.26084472 2013-07-17 04:00:00,69.52490512 2013-07-17 05:00:00,68.65398309 2013-07-17 06:00:00,68.44222186 2013-07-17 07:00:00,68.98691712 2013-07-17 08:00:00,68.12116394 2013-07-17 09:00:00,70.27706087 2013-07-17 10:00:00,69.46657012 2013-07-17 11:00:00,70.32267213 2013-07-17 12:00:00,71.8078395 2013-07-17 13:00:00,72.06436516 2013-07-17 14:00:00,72.48594731 2013-07-17 15:00:00,72.35822858 2013-07-17 16:00:00,74.73026071 2013-07-17 17:00:00,74.45593333 2013-07-17 18:00:00,75.42083051 2013-07-17 19:00:00,74.93021109 2013-07-17 20:00:00,73.46169520000002 2013-07-17 21:00:00,73.44264061 2013-07-17 22:00:00,73.59425862 2013-07-17 23:00:00,72.56355591 2013-07-18 00:00:00,71.67826483 2013-07-18 01:00:00,72.61615717 2013-07-18 02:00:00,70.46155106 2013-07-18 03:00:00,70.68690223 2013-07-18 04:00:00,71.27823432 2013-07-18 05:00:00,70.31179231 2013-07-18 06:00:00,69.53791299 2013-07-18 07:00:00,70.39827926 2013-07-18 08:00:00,69.63338286 2013-07-18 09:00:00,69.47214598 2013-07-18 10:00:00,71.46398548 2013-07-18 11:00:00,72.41314268 2013-07-18 12:00:00,70.9737679 2013-07-18 13:00:00,72.40852176 2013-07-18 14:00:00,73.89859399 2013-07-18 15:00:00,73.99496326 2013-07-18 16:00:00,74.54050584 2013-07-18 17:00:00,74.01063854 2013-07-18 18:00:00,76.39001911 2013-07-18 19:00:00,75.69719107 2013-07-18 20:00:00,75.38408868 2013-07-18 21:00:00,74.12498598 2013-07-18 22:00:00,75.41434918 2013-07-18 23:00:00,74.69411987 2013-07-19 00:00:00,73.07657971 2013-07-19 01:00:00,73.16384917 2013-07-19 02:00:00,73.505794 2013-07-19 03:00:00,74.12699807 2013-07-19 04:00:00,73.71152259 2013-07-19 05:00:00,71.98042488 2013-07-19 06:00:00,71.25116014 2013-07-19 07:00:00,72.16027157 2013-07-19 08:00:00,71.37306717 2013-07-19 09:00:00,71.51790632 2013-07-19 10:00:00,72.2737793 2013-07-19 11:00:00,71.8167371 2013-07-19 12:00:00,73.80696593 2013-07-19 13:00:00,72.94734057 2013-07-19 14:00:00,75.32774091 2013-07-19 15:00:00,75.75888894 2013-07-19 16:00:00,75.61622646 2013-07-19 17:00:00,74.80626301 2013-07-19 18:00:00,75.95162112 2013-07-19 19:00:00,75.00414728 2013-07-19 20:00:00,75.7922298 2013-07-19 21:00:00,75.93662081 2013-07-19 22:00:00,74.08191979 2013-07-19 23:00:00,74.0239745 2013-07-20 00:00:00,73.62518064 2013-07-20 01:00:00,73.55238749 2013-07-20 02:00:00,74.17438898 2013-07-20 03:00:00,72.87160933 2013-07-20 04:00:00,72.28482269 2013-07-20 05:00:00,73.51122601 2013-07-20 06:00:00,72.89366827 2013-07-20 07:00:00,72.14791650000002 2013-07-20 08:00:00,72.9557522 2013-07-20 09:00:00,72.42186823 2013-07-20 10:00:00,70.665252 2013-07-20 11:00:00,71.61263958 2013-07-20 12:00:00,69.74580737 2013-07-20 13:00:00,71.39185449 2013-07-20 14:00:00,70.82733191 2013-07-20 15:00:00,69.32886638 2013-07-20 16:00:00,70.65200484 2013-07-20 17:00:00,70.26620516 2013-07-20 18:00:00,69.04063432 2013-07-20 19:00:00,68.41965745 2013-07-20 20:00:00,68.8585241 2013-07-20 21:00:00,68.36710746 2013-07-20 22:00:00,68.83774585 2013-07-20 23:00:00,68.30402817 2013-07-21 00:00:00,69.3689329 2013-07-21 01:00:00,68.08187826 2013-07-21 02:00:00,67.60392999 2013-07-21 03:00:00,67.44621031 2013-07-21 04:00:00,67.54039145 2013-07-21 05:00:00,67.80852224 2013-07-21 06:00:00,66.38552342 2013-07-21 07:00:00,66.67172095 2013-07-21 08:00:00,65.91622406 2013-07-21 09:00:00,65.67154675 2013-07-21 10:00:00,65.72519189 2013-07-21 11:00:00,66.79848157 2013-07-21 12:00:00,65.43107747 2013-07-21 13:00:00,66.88734467 2013-07-21 14:00:00,65.94946794 2013-07-21 15:00:00,65.28216492 2013-07-21 16:00:00,66.6497085 2013-07-21 17:00:00,66.3990687 2013-07-21 18:00:00,65.00919878 2013-07-21 19:00:00,65.06137224 2013-07-21 20:00:00,65.62911927 2013-07-21 21:00:00,66.37157503 2013-07-21 22:00:00,64.5293161 2013-07-21 23:00:00,66.33871216 2013-07-22 00:00:00,65.29158087 2013-07-22 01:00:00,65.17119986 2013-07-22 02:00:00,65.36758419 2013-07-22 03:00:00,64.55987145 2013-07-22 04:00:00,64.65845259 2013-07-22 05:00:00,64.86762829999999 2013-07-22 06:00:00,63.6094313 2013-07-22 07:00:00,64.96073316 2013-07-22 08:00:00,65.43995404 2013-07-22 09:00:00,67.07099988 2013-07-22 10:00:00,66.67125763 2013-07-22 11:00:00,67.64060287 2013-07-22 12:00:00,68.62797459999999 2013-07-22 13:00:00,70.2454449 2013-07-22 14:00:00,69.70567339 2013-07-22 15:00:00,70.36650487 2013-07-22 16:00:00,72.27945276 2013-07-22 17:00:00,72.71664316 2013-07-22 18:00:00,71.84306091 2013-07-22 19:00:00,71.53844637 2013-07-22 20:00:00,71.55812139 2013-07-22 21:00:00,70.76534571 2013-07-22 22:00:00,71.14242657 2013-07-22 23:00:00,70.71393712 2013-07-23 00:00:00,69.58966371 2013-07-23 01:00:00,69.02299462 2013-07-23 02:00:00,68.95729279 2013-07-23 03:00:00,68.14795876 2013-07-23 04:00:00,67.48635522 2013-07-23 05:00:00,66.52278589 2013-07-23 06:00:00,66.81771127 2013-07-23 07:00:00,66.25215878 2013-07-23 08:00:00,68.14487953 2013-07-23 09:00:00,68.75540328 2013-07-23 10:00:00,68.54546326 2013-07-23 11:00:00,68.65504344 2013-07-23 12:00:00,69.96525521 2013-07-23 13:00:00,70.93097625 2013-07-23 14:00:00,70.67200225 2013-07-23 15:00:00,72.45541594 2013-07-23 16:00:00,72.75267236 2013-07-23 17:00:00,72.98703117 2013-07-23 18:00:00,73.15160594 2013-07-23 19:00:00,73.18754221 2013-07-23 20:00:00,71.04274096 2013-07-23 21:00:00,71.54354038 2013-07-23 22:00:00,71.74520109 2013-07-23 23:00:00,70.94274876 2013-07-24 00:00:00,69.74530422 2013-07-24 01:00:00,69.52726729 2013-07-24 02:00:00,70.32903161 2013-07-24 03:00:00,70.03017299 2013-07-24 04:00:00,68.87043296 2013-07-24 05:00:00,68.92349639 2013-07-24 06:00:00,68.10636443 2013-07-24 07:00:00,68.55988567 2013-07-24 08:00:00,67.85392905 2013-07-24 09:00:00,68.35577512 2013-07-24 10:00:00,69.70795831 2013-07-24 11:00:00,70.53390858 2013-07-24 12:00:00,69.78024465 2013-07-24 13:00:00,71.51678733 2013-07-24 14:00:00,72.03103759999998 2013-07-24 15:00:00,73.40007449 2013-07-24 16:00:00,73.8675255 2013-07-24 17:00:00,72.66779455 2013-07-24 18:00:00,72.85222389 2013-07-24 19:00:00,73.11323349999998 2013-07-24 20:00:00,72.2813031 2013-07-24 21:00:00,72.61561106 2013-07-24 22:00:00,71.61517817 2013-07-24 23:00:00,72.75668787 2013-07-25 00:00:00,71.14354005 2013-07-25 01:00:00,70.8585056 2013-07-25 02:00:00,70.89259768 2013-07-25 03:00:00,70.85000882 2013-07-25 04:00:00,71.4091997 2013-07-25 05:00:00,70.257825 2013-07-25 06:00:00,69.82174319 2013-07-25 07:00:00,69.39311984 2013-07-25 08:00:00,69.94923869 2013-07-25 09:00:00,70.35977277 2013-07-25 10:00:00,71.59751048 2013-07-25 11:00:00,71.15990415 2013-07-25 12:00:00,72.51273013 2013-07-25 13:00:00,73.02999473 2013-07-25 14:00:00,72.09791824 2013-07-25 15:00:00,72.92583014 2013-07-25 16:00:00,73.86938351 2013-07-25 17:00:00,73.91377788 2013-07-25 18:00:00,74.46991144 2013-07-25 19:00:00,73.21314175 2013-07-25 20:00:00,74.51203141 2013-07-25 21:00:00,72.84294254 2013-07-25 22:00:00,73.43276491 2013-07-25 23:00:00,73.30466379999999 2013-07-26 00:00:00,72.81092703 2013-07-26 01:00:00,72.86473466 2013-07-26 02:00:00,71.38222869 2013-07-26 03:00:00,71.19623896 2013-07-26 04:00:00,71.03955791 2013-07-26 05:00:00,72.27910059999998 2013-07-26 06:00:00,70.21785723 2013-07-26 07:00:00,70.31733297 2013-07-26 08:00:00,69.78868463 2013-07-26 09:00:00,70.88145123 2013-07-26 10:00:00,71.61930479 2013-07-26 11:00:00,72.28509323 2013-07-26 12:00:00,72.77202114 2013-07-26 13:00:00,73.24703993 2013-07-26 14:00:00,72.80712104 2013-07-26 15:00:00,72.58748947 2013-07-26 16:00:00,74.68417583 2013-07-26 17:00:00,73.09200323 2013-07-26 18:00:00,74.09006089 2013-07-26 19:00:00,74.61862587 2013-07-26 20:00:00,73.81911639 2013-07-26 21:00:00,74.57014385 2013-07-26 22:00:00,72.69101123 2013-07-26 23:00:00,73.56142292 2013-07-27 00:00:00,73.77909916 2013-07-27 01:00:00,72.91239911 2013-07-27 02:00:00,73.48633826 2013-07-27 03:00:00,72.73447053 2013-07-27 04:00:00,71.62959719 2013-07-27 05:00:00,72.41051865 2013-07-27 06:00:00,71.64829313 2013-07-27 07:00:00,71.34815297 2013-07-27 08:00:00,70.69776199 2013-07-27 09:00:00,70.47033288 2013-07-27 10:00:00,71.02517791 2013-07-27 11:00:00,69.83488902 2013-07-27 12:00:00,71.50090936 2013-07-27 13:00:00,70.40361959 2013-07-27 14:00:00,70.54399168 2013-07-27 15:00:00,71.85746328 2013-07-27 16:00:00,71.15225757 2013-07-27 17:00:00,72.78516393 2013-07-27 18:00:00,73.36070500000002 2013-07-27 19:00:00,72.86473047 2013-07-27 20:00:00,72.70608578 2013-07-27 21:00:00,73.85915886 2013-07-27 22:00:00,73.50507967 2013-07-27 23:00:00,72.19240313 2013-07-28 00:00:00,72.13995763 2013-07-28 01:00:00,72.76124036 2013-07-28 03:00:00,72.78238947 2013-07-28 04:00:00,71.89290086 2013-07-29 12:00:00,73.24344321 2013-07-29 13:00:00,73.25408094 2013-07-29 14:00:00,72.61221201 2013-07-29 15:00:00,73.02852459 2013-07-29 16:00:00,73.29062043 2013-07-29 17:00:00,74.12192813 2013-07-29 18:00:00,75.04218319 2013-07-29 19:00:00,75.01049779 2013-07-29 20:00:00,74.14262591 2013-07-29 21:00:00,73.92443272 2013-07-29 22:00:00,74.65910397 2013-07-29 23:00:00,74.79811406 2013-07-30 00:00:00,74.46700925 2013-07-30 01:00:00,73.29755441 2013-07-30 02:00:00,73.68345172 2013-07-30 03:00:00,72.34692708 2013-07-30 04:00:00,73.24426001 2013-07-30 05:00:00,72.14957625 2013-07-30 06:00:00,72.41976913 2013-07-30 07:00:00,71.31132501 2013-07-30 08:00:00,71.70322328 2013-07-30 09:00:00,72.25103685 2013-07-30 10:00:00,71.97716389 2013-07-30 11:00:00,71.39886276 2013-07-30 12:00:00,71.59695286 2013-07-30 13:00:00,72.63410157 2013-07-30 14:00:00,73.23961797 2013-07-30 15:00:00,72.52081721 2013-07-30 16:00:00,74.01598050000003 2013-07-30 17:00:00,73.67468353 2013-07-30 18:00:00,75.75032693 2013-07-30 19:00:00,74.3638755 2013-07-30 20:00:00,74.41574553 2013-07-30 21:00:00,74.22077381 2013-07-30 22:00:00,75.24461638 2013-07-30 23:00:00,75.76683279 2013-07-31 00:00:00,75.2599283 2013-07-31 01:00:00,75.00430133 2013-07-31 02:00:00,72.99868724 2013-07-31 03:00:00,74.22813959 2013-07-31 04:00:00,73.86242657 2013-07-31 05:00:00,73.64995716 2013-07-31 06:00:00,72.4157443 2013-07-31 07:00:00,72.33008672 2013-07-31 08:00:00,72.6550647 2013-07-31 09:00:00,72.28311126 2013-07-31 10:00:00,73.03449417 2013-07-31 11:00:00,72.28032012 2013-07-31 12:00:00,71.87820491 2013-07-31 13:00:00,73.40155661 2013-07-31 14:00:00,74.44122979 2013-07-31 15:00:00,73.87635966 2013-07-31 16:00:00,73.90784081 2013-07-31 17:00:00,75.16955484 2013-07-31 18:00:00,75.15953611 2013-07-31 19:00:00,74.80214938 2013-07-31 20:00:00,76.28002237 2013-07-31 21:00:00,74.85748264 2013-07-31 22:00:00,75.92805235 2013-07-31 23:00:00,75.91643042 2013-08-01 00:00:00,74.39653829999997 2013-08-01 01:00:00,75.10901277 2013-08-01 02:00:00,74.09065784 2013-08-01 03:00:00,74.99478559 2013-08-01 04:00:00,74.49008385 2013-08-01 05:00:00,74.15968431 2013-08-01 06:00:00,73.77074883 2013-08-01 07:00:00,73.761944 2013-08-01 08:00:00,72.39267309 2013-08-01 09:00:00,72.65461782 2013-08-01 10:00:00,71.85842391 2013-08-01 11:00:00,72.90726702 2013-08-01 12:00:00,72.74347127 2013-08-01 13:00:00,73.80882616 2013-08-01 14:00:00,74.02068569 2013-08-01 15:00:00,74.93830342 2013-08-01 16:00:00,73.482711 2013-08-01 17:00:00,74.16997946 2013-08-01 18:00:00,74.01751843 2013-08-01 19:00:00,74.49814040000003 2013-08-01 20:00:00,76.3120219 2013-08-01 21:00:00,75.08484325 2013-08-01 22:00:00,74.65943066 2013-08-01 23:00:00,75.82212698 2013-08-02 00:00:00,74.8569766 2013-08-02 01:00:00,73.98785798 2013-08-02 02:00:00,74.22412386 2013-08-02 03:00:00,74.51575386 2013-08-02 04:00:00,74.45778211 2013-08-02 05:00:00,74.12643606 2013-08-02 06:00:00,73.99954302 2013-08-02 07:00:00,72.26824527 2013-08-02 08:00:00,73.7764128 2013-08-02 09:00:00,72.90101937 2013-08-02 10:00:00,72.11776996 2013-08-02 11:00:00,72.92499217 2013-08-02 12:00:00,72.05187563 2013-08-02 13:00:00,72.38437545 2013-08-02 14:00:00,74.07630529 2013-08-02 15:00:00,74.61920753 2013-08-02 16:00:00,75.08524938 2013-08-02 17:00:00,75.82866138 2013-08-02 18:00:00,75.42713311 2013-08-02 19:00:00,76.56950166 2013-08-02 20:00:00,76.17963379 2013-08-02 21:00:00,74.94074803 2013-08-02 22:00:00,74.76418837 2013-08-02 23:00:00,74.12540695 2013-08-03 00:00:00,74.84051371 2013-08-03 01:00:00,73.79928772 2013-08-03 02:00:00,74.780247 2013-08-03 03:00:00,72.82864301 2013-08-03 04:00:00,72.48177255 2013-08-03 05:00:00,73.27429509999997 2013-08-03 06:00:00,73.26715622 2013-08-03 07:00:00,72.74611472 2013-08-03 08:00:00,71.30564248 2013-08-03 09:00:00,70.79796992 2013-08-03 10:00:00,70.8324548 2013-08-03 11:00:00,71.36899796 2013-08-03 12:00:00,71.30600481 2013-08-03 13:00:00,69.95127986 2013-08-03 14:00:00,71.11183674 2013-08-03 15:00:00,71.24355108 2013-08-03 16:00:00,71.16602046 2013-08-03 17:00:00,69.5362003 2013-08-03 18:00:00,71.21599291 2013-08-03 19:00:00,70.94704371 2013-08-03 20:00:00,71.14172451 2013-08-03 21:00:00,70.94719413 2013-08-03 22:00:00,70.28093351 2013-08-03 23:00:00,69.95038298 2013-08-04 00:00:00,70.06016939 2013-08-04 01:00:00,68.72937535 2013-08-04 02:00:00,68.31124754 2013-08-04 03:00:00,67.59938455 2013-08-04 04:00:00,69.23919313 2013-08-04 05:00:00,68.70527934 2013-08-04 06:00:00,67.30881248 2013-08-04 07:00:00,67.29093890000001 2013-08-04 08:00:00,67.01058194 2013-08-04 09:00:00,67.11700116 2013-08-04 10:00:00,67.17114622 2013-08-04 11:00:00,64.8612751 2013-08-04 12:00:00,66.1031092 2013-08-04 13:00:00,64.70015253 2013-08-04 14:00:00,65.97732586 2013-08-04 15:00:00,64.83488246 2013-08-04 16:00:00,65.16140029 2013-08-04 17:00:00,65.86503497 2013-08-04 18:00:00,67.73521012 2013-08-04 19:00:00,68.12101336 2013-08-04 20:00:00,68.68838431 2013-08-04 21:00:00,67.73402197 2013-08-04 22:00:00,68.42818207 2013-08-04 23:00:00,68.16946111 2013-08-05 00:00:00,67.49229937 2013-08-05 01:00:00,66.98395449 2013-08-05 02:00:00,68.04064964 2013-08-05 03:00:00,66.62055167 2013-08-05 04:00:00,66.64744323 2013-08-05 05:00:00,66.08743294 2013-08-05 06:00:00,67.22510503 2013-08-05 07:00:00,66.43247979 2013-08-05 08:00:00,66.57052361 2013-08-05 09:00:00,68.05327519 2013-08-05 10:00:00,67.67038945 2013-08-05 11:00:00,69.17031869 2013-08-05 12:00:00,68.89948983 2013-08-05 13:00:00,70.00978672 2013-08-05 14:00:00,69.82913552 2013-08-05 15:00:00,70.9242198 2013-08-05 16:00:00,71.27814633 2013-08-05 17:00:00,72.15965785 2013-08-05 18:00:00,72.97618331 2013-08-05 19:00:00,72.66683797 2013-08-05 20:00:00,73.69117746 2013-08-05 21:00:00,72.80151077 2013-08-05 22:00:00,71.85931396 2013-08-05 23:00:00,72.23815016 2013-08-06 00:00:00,70.95862334 2013-08-06 01:00:00,72.4688891 2013-08-06 02:00:00,71.66219799 2013-08-06 03:00:00,71.86755979 2013-08-06 04:00:00,70.7802684 2013-08-06 05:00:00,70.99083764 2013-08-06 06:00:00,69.15653193 2013-08-06 07:00:00,69.08522976 2013-08-06 08:00:00,69.75214256 2013-08-06 09:00:00,69.46942493 2013-08-06 10:00:00,68.77679875 2013-08-06 11:00:00,70.22714587 2013-08-06 12:00:00,71.01598435 2013-08-06 13:00:00,72.44743344 2013-08-06 14:00:00,72.06658701 2013-08-06 15:00:00,72.98693668 2013-08-06 16:00:00,73.69835469 2013-08-06 17:00:00,73.75209157 2013-08-06 18:00:00,74.55800629 2013-08-06 19:00:00,72.35247916 2013-08-06 20:00:00,65.26017655 2013-08-06 21:00:00,74.76223447 2013-08-06 22:00:00,73.49525372 2013-08-06 23:00:00,73.36538505 2013-08-07 00:00:00,72.5976732 2013-08-07 01:00:00,72.99425699999998 2013-08-07 02:00:00,72.85282429 2013-08-07 03:00:00,72.74890938 2013-08-07 04:00:00,72.12765994 2013-08-07 05:00:00,71.09856805 2013-08-07 06:00:00,71.23849804 2013-08-07 07:00:00,70.27255592 2013-08-07 08:00:00,70.88395870000002 2013-08-07 09:00:00,71.39022061 2013-08-07 10:00:00,70.52089931 2013-08-07 11:00:00,71.25419744 2013-08-07 12:00:00,72.68993228 2013-08-07 13:00:00,72.61074543 2013-08-07 14:00:00,72.43902889 2013-08-07 15:00:00,73.58512146 2013-08-07 16:00:00,73.89459624 2013-08-07 17:00:00,72.95170937 2013-08-07 18:00:00,74.07563886 2013-08-07 19:00:00,73.6806514 2013-08-07 20:00:00,72.89217355 2013-08-07 21:00:00,73.32218412 2013-08-07 22:00:00,73.24266369 2013-08-07 23:00:00,72.14171440000001 2013-08-08 00:00:00,72.30380183 2013-08-08 01:00:00,72.89276841 2013-08-08 02:00:00,71.56299973 2013-08-08 03:00:00,72.39705979 2013-08-08 04:00:00,72.00657008 2013-08-08 05:00:00,71.32736169 2013-08-08 06:00:00,70.82135373 2013-08-08 07:00:00,70.1336473 2013-08-08 08:00:00,70.0467162 2013-08-08 09:00:00,70.06918582 2013-08-08 10:00:00,70.79634920000002 2013-08-08 11:00:00,70.91540196 2013-08-08 12:00:00,71.67451047 2013-08-08 13:00:00,72.18760774 2013-08-08 14:00:00,72.1207947 2013-08-08 15:00:00,72.51156743 2013-08-08 16:00:00,72.23695024 2013-08-08 17:00:00,71.87503532 2013-08-08 18:00:00,72.49582348 2013-08-08 19:00:00,72.35768598 2013-08-08 20:00:00,73.93378927 2013-08-08 21:00:00,73.98233814 2013-08-08 22:00:00,73.59560241 2013-08-08 23:00:00,71.98821679 2013-08-09 00:00:00,72.32396967 2013-08-09 01:00:00,71.6259057 2013-08-09 02:00:00,71.72859842 2013-08-09 03:00:00,70.70127666 2013-08-09 04:00:00,71.00161546 2013-08-09 05:00:00,70.81636614 2013-08-09 06:00:00,70.72324263 2013-08-09 07:00:00,70.3860912 2013-08-09 08:00:00,68.77908287 2013-08-09 09:00:00,70.22778904 2013-08-09 10:00:00,69.87258414 2013-08-09 11:00:00,70.44715736 2013-08-09 12:00:00,71.08361107 2013-08-09 13:00:00,71.23292042 2013-08-09 14:00:00,72.16067996 2013-08-09 15:00:00,71.86722192 2013-08-09 16:00:00,72.16014273 2013-08-09 17:00:00,72.99568483 2013-08-09 18:00:00,73.27572883 2013-08-09 19:00:00,73.49417662 2013-08-09 20:00:00,74.21107376 2013-08-09 21:00:00,72.54083404 2013-08-09 22:00:00,73.21324868 2013-08-09 23:00:00,72.58771726 2013-08-10 00:00:00,73.50120424 2013-08-10 01:00:00,72.09154651 2013-08-10 02:00:00,71.09042019 2013-08-10 03:00:00,71.23416619 2013-08-10 04:00:00,70.63012271 2013-08-10 05:00:00,69.77541726 2013-08-10 06:00:00,69.28687677 2013-08-10 07:00:00,70.44057715 2013-08-10 08:00:00,69.28731334 2013-08-10 09:00:00,69.93728934 2013-08-10 10:00:00,69.3391448 2013-08-10 11:00:00,69.13334157 2013-08-10 12:00:00,68.65929831 2013-08-10 13:00:00,68.18197506 2013-08-10 14:00:00,67.84812498 2013-08-10 15:00:00,69.37597782 2013-08-10 16:00:00,69.10036669 2013-08-10 17:00:00,68.8546449 2013-08-10 18:00:00,67.85837277 2013-08-10 19:00:00,68.46916703 2013-08-10 20:00:00,68.17855534 2013-08-10 21:00:00,69.21501077 2013-08-10 22:00:00,68.96464737 2013-08-10 23:00:00,67.87377682 2013-08-11 00:00:00,67.72178625 2013-08-11 01:00:00,68.58499733 2013-08-11 02:00:00,68.44962111 2013-08-11 03:00:00,67.14273776 2013-08-11 04:00:00,67.07599947 2013-08-11 05:00:00,68.29349922 2013-08-11 06:00:00,66.78969926 2013-08-11 07:00:00,65.82622549 2013-08-11 08:00:00,66.59954318 2013-08-11 09:00:00,65.01332031 2013-08-11 10:00:00,65.90620917 2013-08-11 11:00:00,65.84496837 2013-08-11 12:00:00,64.92189809 2013-08-11 13:00:00,65.58278655 2013-08-11 14:00:00,65.55748205 2013-08-11 15:00:00,65.59894884 2013-08-11 16:00:00,64.94337424 2013-08-11 17:00:00,64.74950254 2013-08-11 18:00:00,64.84844096 2013-08-11 19:00:00,65.83625843 2013-08-11 20:00:00,66.03749482 2013-08-11 21:00:00,65.38311565 2013-08-11 22:00:00,65.99967447 2013-08-11 23:00:00,64.36458794 2013-08-12 00:00:00,65.07952767 2013-08-12 01:00:00,65.29604166 2013-08-12 02:00:00,65.20610988 2013-08-12 03:00:00,63.96596281 2013-08-12 04:00:00,64.72425165 2013-08-12 05:00:00,65.40331196 2013-08-12 06:00:00,65.42865101 2013-08-12 07:00:00,64.09801612 2013-08-12 08:00:00,63.80900879 2013-08-12 09:00:00,64.54585931 2013-08-12 10:00:00,66.95784817 2013-08-12 11:00:00,66.61279611 2013-08-12 12:00:00,67.94979306 2013-08-12 13:00:00,66.39778915 2013-08-12 14:00:00,66.77796074 2013-08-12 15:00:00,67.1940435 2013-08-12 16:00:00,68.38187061 2013-08-12 17:00:00,67.12861534 2013-08-12 18:00:00,67.17067346 2013-08-12 19:00:00,68.43923628 2013-08-12 20:00:00,66.57086417 2013-08-12 21:00:00,67.78803691 2013-08-12 22:00:00,67.2787936 2013-08-12 23:00:00,67.87219243 2013-08-13 00:00:00,67.50915846 2013-08-13 01:00:00,67.66070149 2013-08-13 02:00:00,65.93597991 2013-08-13 03:00:00,65.72336823 2013-08-13 04:00:00,65.72245666 2013-08-13 05:00:00,66.11658266 2013-08-13 06:00:00,65.32184413 2013-08-13 07:00:00,65.71791971 2013-08-13 08:00:00,65.47364884 2013-08-13 09:00:00,66.64929047 2013-08-13 10:00:00,66.55123544 2013-08-13 11:00:00,67.79521779999999 2013-08-13 12:00:00,68.14077842 2013-08-13 13:00:00,69.79685244 2013-08-13 14:00:00,70.34622184 2013-08-13 15:00:00,69.32175382 2013-08-13 16:00:00,69.89015017 2013-08-13 17:00:00,71.58845383 2013-08-13 18:00:00,71.86175982 2013-08-13 19:00:00,72.7410679 2013-08-13 20:00:00,71.90458946 2013-08-13 21:00:00,71.28351048 2013-08-13 22:00:00,70.09728390000001 2013-08-13 23:00:00,69.27726512 2013-08-14 00:00:00,68.92546699 2013-08-14 01:00:00,68.55186335 2013-08-14 02:00:00,67.65673848 2013-08-14 03:00:00,68.32131351 2013-08-14 04:00:00,68.12150858 2013-08-14 05:00:00,66.5554972 2013-08-14 06:00:00,66.38718242 2013-08-14 07:00:00,66.99569939 2013-08-14 08:00:00,65.87173899 2013-08-14 09:00:00,67.22433388 2013-08-14 10:00:00,68.40446699 2013-08-14 11:00:00,68.74846629999999 2013-08-14 12:00:00,69.32469028 2013-08-14 13:00:00,71.15467576 2013-08-14 14:00:00,71.05227306 2013-08-14 15:00:00,70.83181931 2013-08-14 16:00:00,70.91625104 2013-08-14 17:00:00,72.39488293 2013-08-14 18:00:00,71.98328520000003 2013-08-14 19:00:00,72.37378341 2013-08-14 20:00:00,71.80748327 2013-08-14 21:00:00,72.54903002 2013-08-14 22:00:00,71.18557043 2013-08-14 23:00:00,70.6560059 2013-08-15 00:00:00,71.42334777 2013-08-15 01:00:00,69.34699767 2013-08-15 02:00:00,70.73289851 2013-08-15 03:00:00,68.5593425 2013-08-15 04:00:00,69.75429868 2013-08-15 05:00:00,69.42528082 2013-08-15 06:00:00,68.78050479 2013-08-15 07:00:00,67.57592345 2013-08-15 08:00:00,67.31292692 2013-08-15 09:00:00,68.61465054 2013-08-15 10:00:00,68.93048832 2013-08-15 11:00:00,70.42238762 2013-08-15 12:00:00,70.84558646 2013-08-15 13:00:00,71.06424324 2013-08-15 14:00:00,72.69610401 2013-08-15 15:00:00,72.32617126 2013-08-15 16:00:00,72.22167626 2013-08-15 17:00:00,73.21437055 2013-08-15 18:00:00,73.15708957 2013-08-15 19:00:00,73.49412607 2013-08-15 20:00:00,72.3006671 2013-08-15 21:00:00,73.86668101 2013-08-15 22:00:00,72.6701852 2013-08-15 23:00:00,72.7624445 2013-08-16 00:00:00,72.76328752 2013-08-16 01:00:00,71.3147316 2013-08-16 02:00:00,71.43288687 2013-08-16 03:00:00,70.82264418 2013-08-16 04:00:00,70.66687081 2013-08-16 05:00:00,70.43909465 2013-08-16 06:00:00,69.81296825 2013-08-16 07:00:00,69.69858982 2013-08-16 08:00:00,68.34291749 2013-08-16 09:00:00,69.78913221 2013-08-16 10:00:00,69.04301127 2013-08-16 11:00:00,71.2618595 2013-08-16 12:00:00,71.53303086 2013-08-16 13:00:00,71.2414772 2013-08-16 14:00:00,73.36763803 2013-08-16 15:00:00,73.57415941 2013-08-16 16:00:00,72.24425435 2013-08-16 17:00:00,74.26516471 2013-08-16 18:00:00,72.92651196 2013-08-16 19:00:00,74.39635211 2013-08-16 20:00:00,74.11889706 2013-08-16 21:00:00,72.19232832 2013-08-16 22:00:00,73.73903840000001 2013-08-16 23:00:00,72.2079627 2013-08-17 00:00:00,72.96446399 2013-08-17 01:00:00,72.47851039 2013-08-17 02:00:00,71.26534459 2013-08-17 03:00:00,70.53066333 2013-08-17 04:00:00,71.25037104 2013-08-17 05:00:00,70.43519581 2013-08-17 06:00:00,70.42341332 2013-08-17 07:00:00,70.79164337 2013-08-17 08:00:00,68.95439433 2013-08-17 09:00:00,70.34051981 2013-08-17 10:00:00,69.80542162 2013-08-17 11:00:00,68.64316206 2013-08-17 12:00:00,69.38668045 2013-08-17 13:00:00,68.78927469999999 2013-08-17 14:00:00,68.83952616 2013-08-17 15:00:00,67.63291116 2013-08-17 16:00:00,68.40694416 2013-08-17 17:00:00,69.14007715 2013-08-17 18:00:00,69.11590587 2013-08-17 19:00:00,68.03579823 2013-08-17 20:00:00,69.27272007 2013-08-17 21:00:00,68.75322294 2013-08-17 22:00:00,69.56566049 2013-08-17 23:00:00,68.17712131 2013-08-18 00:00:00,67.79477436 2013-08-18 01:00:00,67.49347171 2013-08-18 02:00:00,67.79427593 2013-08-18 03:00:00,67.70107774 2013-08-18 04:00:00,67.26294021 2013-08-18 05:00:00,66.86984441 2013-08-18 06:00:00,66.14932783 2013-08-18 07:00:00,66.42313039 2013-08-18 08:00:00,67.0524877 2013-08-18 09:00:00,65.34818634 2013-08-18 10:00:00,65.89940057 2013-08-18 11:00:00,66.64739688 2013-08-18 12:00:00,66.64122284 2013-08-18 13:00:00,64.79138473 2013-08-18 14:00:00,65.90167301 2013-08-18 15:00:00,65.74127604 2013-08-18 16:00:00,65.45031794 2013-08-18 17:00:00,66.16094532 2013-08-18 18:00:00,65.7044379 2013-08-18 19:00:00,64.77549911 2013-08-18 20:00:00,66.10922106 2013-08-18 21:00:00,64.65138267 2013-08-18 22:00:00,64.63763005 2013-08-18 23:00:00,64.86524307 2013-08-19 00:00:00,64.67189696 2013-08-19 01:00:00,64.46795885 2013-08-19 02:00:00,65.91187512 2013-08-19 03:00:00,64.34806529 2013-08-19 04:00:00,63.99581812 2013-08-19 05:00:00,65.39461929 2013-08-19 06:00:00,64.65292546 2013-08-19 07:00:00,63.25807837 2013-08-19 08:00:00,63.73827199 2013-08-19 09:00:00,64.48038308 2013-08-19 10:00:00,65.99746656 2013-08-19 11:00:00,66.25822123 2013-08-19 12:00:00,68.10328147 2013-08-19 13:00:00,67.8042515 2013-08-19 14:00:00,69.4870625 2013-08-19 15:00:00,70.03024494 2013-08-19 16:00:00,70.29600481 2013-08-19 17:00:00,71.04468694 2013-08-19 18:00:00,72.07494806 2013-08-19 19:00:00,71.92135771 2013-08-19 20:00:00,72.83067187 2013-08-19 21:00:00,71.98101498 2013-08-19 22:00:00,69.32089454 2013-08-19 23:00:00,70.13159511 2013-08-20 00:00:00,70.00507257 2013-08-20 01:00:00,69.43663186 2013-08-20 02:00:00,68.94680541 2013-08-20 03:00:00,67.39526388 2013-08-20 04:00:00,66.86451228 2013-08-20 05:00:00,67.61515255 2013-08-20 06:00:00,67.50015115 2013-08-20 07:00:00,67.06492539999999 2013-08-20 08:00:00,66.18109356 2013-08-20 09:00:00,67.67862944 2013-08-20 10:00:00,67.28780716 2013-08-20 11:00:00,68.64887048 2013-08-20 12:00:00,68.03818943 2013-08-20 13:00:00,69.43733797 2013-08-20 14:00:00,69.42521625 2013-08-20 15:00:00,70.34561943 2013-08-20 16:00:00,70.30816394 2013-08-20 17:00:00,70.8360583 2013-08-20 18:00:00,71.1470857 2013-08-20 19:00:00,71.57781772 2013-08-20 20:00:00,72.19406331 2013-08-20 21:00:00,72.28995087 2013-08-20 22:00:00,71.14766239 2013-08-20 23:00:00,69.76492572 2013-08-21 00:00:00,69.91788048 2013-08-21 01:00:00,69.25384854 2013-08-21 02:00:00,67.70300258 2013-08-21 03:00:00,67.34860655 2013-08-21 04:00:00,67.03007179 2013-08-21 05:00:00,67.02774425 2013-08-21 06:00:00,66.79530391 2013-08-21 07:00:00,65.29474687 2013-08-21 08:00:00,66.61324069 2013-08-21 09:00:00,66.79489002 2013-08-21 10:00:00,66.72432203 2013-08-21 11:00:00,66.81536983 2013-08-21 12:00:00,67.17358633 2013-08-21 13:00:00,67.63012369 2013-08-21 14:00:00,67.48754605 2013-08-21 15:00:00,67.33171806 2013-08-21 16:00:00,69.7284424 2013-08-21 17:00:00,69.89615603 2013-08-21 18:00:00,68.99214926 2013-08-21 19:00:00,70.03999165 2013-08-21 20:00:00,70.55714223 2013-08-21 21:00:00,70.17848707 2013-08-21 22:00:00,68.21913112 2013-08-21 23:00:00,68.40833713 2013-08-22 00:00:00,68.94808523 2013-08-22 01:00:00,67.38899521 2013-08-22 02:00:00,68.05245103 2013-08-22 03:00:00,67.21188517 2013-08-22 04:00:00,65.70328183 2013-08-22 05:00:00,67.16985267 2013-08-22 06:00:00,66.55460769 2013-08-22 07:00:00,65.72798535 2013-08-22 08:00:00,65.75716876 2013-08-22 09:00:00,67.16913702 2013-08-22 10:00:00,67.21744752 2013-08-22 11:00:00,68.42865711 2013-08-22 12:00:00,67.939555 2013-08-22 13:00:00,68.21272047 2013-08-22 14:00:00,68.59771355 2013-08-22 15:00:00,69.8746694 2013-08-22 16:00:00,69.78932095 2013-08-22 17:00:00,71.20599841 2013-08-22 18:00:00,71.58253869 2013-08-22 19:00:00,71.88959565 2013-08-22 20:00:00,71.86056438 2013-08-22 21:00:00,72.04256027 2013-08-22 22:00:00,71.39573223 2013-08-22 23:00:00,69.55668318 2013-08-23 00:00:00,68.93024269 2013-08-23 01:00:00,69.66341833 2013-08-23 02:00:00,69.04101322 2013-08-23 03:00:00,67.96747227 2013-08-23 04:00:00,69.31576272 2013-08-23 05:00:00,68.15040455 2013-08-23 06:00:00,68.35613984 2013-08-23 07:00:00,67.76316051 2013-08-23 08:00:00,67.03590822 2013-08-23 09:00:00,67.39406286 2013-08-23 10:00:00,68.68188132 2013-08-23 11:00:00,70.23539114 2013-08-23 12:00:00,70.72213492 2013-08-23 13:00:00,70.58200639 2013-08-23 14:00:00,71.80797978 2013-08-23 15:00:00,70.57872691 2013-08-23 16:00:00,72.0077339 2013-08-23 17:00:00,71.71571281 2013-08-23 18:00:00,72.11695816 2013-08-23 19:00:00,72.64909676 2013-08-23 20:00:00,71.43282886 2013-08-23 21:00:00,71.71418699 2013-08-23 22:00:00,72.28243141 2013-08-23 23:00:00,72.25217338 2013-08-24 00:00:00,71.74318478 2013-08-24 01:00:00,69.68874182 2013-08-24 02:00:00,70.11075437 2013-08-24 03:00:00,68.69315914 2013-08-24 04:00:00,68.49395196 2013-08-24 05:00:00,69.05769349 2013-08-24 06:00:00,67.38563023 2013-08-24 07:00:00,68.51017483 2013-08-24 08:00:00,68.046038 2013-08-24 09:00:00,66.69591868 2013-08-24 10:00:00,67.0893911 2013-08-24 11:00:00,66.22561571 2013-08-24 12:00:00,66.50296546 2013-08-24 13:00:00,65.29980537 2013-08-24 14:00:00,65.44279328 2013-08-24 15:00:00,65.87726412 2013-08-24 16:00:00,65.57372439 2013-08-24 17:00:00,65.68296557 2013-08-24 18:00:00,66.93568163 2013-08-24 19:00:00,66.69982543 2013-08-24 20:00:00,65.99025408 2013-08-24 21:00:00,65.93769573 2013-08-24 22:00:00,67.04970768 2013-08-24 23:00:00,66.73555970000001 2013-08-25 00:00:00,66.23665366 2013-08-25 01:00:00,66.23546935 2013-08-25 02:00:00,66.85525388 2013-08-25 03:00:00,65.44418785 2013-08-25 04:00:00,66.70939032 2013-08-25 05:00:00,64.88554717 2013-08-25 06:00:00,64.35080723 2013-08-25 07:00:00,64.38802527 2013-08-25 08:00:00,64.40835278 2013-08-25 09:00:00,64.42226129 2013-08-25 10:00:00,64.05518099 2013-08-25 11:00:00,64.71716427 2013-08-25 12:00:00,64.45389357 2013-08-25 13:00:00,64.50166125 2013-08-25 14:00:00,64.01651861 2013-08-25 15:00:00,62.85522295 2013-08-25 16:00:00,64.23986264 2013-08-25 17:00:00,63.38848875 2013-08-25 18:00:00,63.39183252 2013-08-25 19:00:00,65.20905227 2013-08-25 20:00:00,64.94516739 2013-08-25 21:00:00,64.25107982 2013-08-25 22:00:00,64.17982393 2013-08-25 23:00:00,64.38921578 2013-08-26 00:00:00,64.49909975 2013-08-26 01:00:00,65.09660852 2013-08-26 02:00:00,63.40543705 2013-08-26 03:00:00,63.83826011 2013-08-26 04:00:00,63.68217925 2013-08-26 05:00:00,63.32128642 2013-08-26 06:00:00,63.45009249 2013-08-26 07:00:00,63.58602877 2013-08-26 08:00:00,62.73132759 2013-08-26 09:00:00,64.6219447 2013-08-26 10:00:00,65.04527027 2013-08-26 11:00:00,65.66669249 2013-08-26 12:00:00,66.04597893 2013-08-26 13:00:00,66.92945334 2013-08-26 14:00:00,68.27335848 2013-08-26 15:00:00,68.03643251 2013-08-26 16:00:00,68.32526303 2013-08-26 17:00:00,69.45241625 2013-08-26 18:00:00,69.292876 2013-08-26 19:00:00,69.61637759 2013-08-26 20:00:00,69.09830136 2013-08-26 21:00:00,68.9295352 2013-08-26 22:00:00,68.38166541 2013-08-26 23:00:00,66.69776707 2013-08-27 00:00:00,66.55923923 2013-08-27 01:00:00,65.50421593 2013-08-27 02:00:00,65.36283826 2013-08-27 03:00:00,65.03631072 2013-08-27 04:00:00,64.28289583 2013-08-27 05:00:00,64.70837708 2013-08-27 06:00:00,65.19959422 2013-08-27 07:00:00,64.37599177 2013-08-27 08:00:00,65.80010808 2013-08-27 09:00:00,66.90052411 2013-08-27 10:00:00,65.97556180000001 2013-08-27 11:00:00,67.21755426 2013-08-29 11:00:00,67.61970814 2013-08-29 12:00:00,68.68919867 2013-08-29 13:00:00,68.99230755 2013-08-29 14:00:00,69.01270334 2013-08-29 15:00:00,69.60076165 2013-08-29 16:00:00,70.62180453 2013-08-29 17:00:00,70.80389723 2013-08-29 18:00:00,71.95049453 2013-08-29 19:00:00,71.45525932 2013-08-29 20:00:00,70.69089941 2013-08-29 21:00:00,70.84845568 2013-08-29 22:00:00,71.14711094 2013-08-29 23:00:00,70.19670613 2013-08-30 00:00:00,70.26757380000001 2013-08-30 01:00:00,70.3477134 2013-08-30 02:00:00,68.94715476 2013-08-30 03:00:00,68.19452413 2013-08-30 04:00:00,67.41217981 2013-08-30 05:00:00,67.6915133 2013-08-30 06:00:00,68.1326941 2013-08-30 07:00:00,67.72304464 2013-08-30 08:00:00,67.00024303 2013-08-30 09:00:00,68.33122058 2013-08-30 10:00:00,68.77081792 2013-08-30 11:00:00,67.89464946 2013-08-30 12:00:00,70.32897545 2013-08-30 13:00:00,69.94984745 2013-08-30 14:00:00,69.04940045 2013-08-30 15:00:00,70.48680148 2013-08-30 16:00:00,70.73164318 2013-08-30 17:00:00,70.27130965 2013-08-30 18:00:00,70.56771532 2013-08-30 19:00:00,70.52348927 2013-08-30 20:00:00,70.94288585 2013-08-30 21:00:00,70.09622236 2013-08-30 22:00:00,70.92253659999999 2013-08-30 23:00:00,69.73699276 2013-08-31 00:00:00,69.50362657 2013-08-31 01:00:00,68.74107885 2013-08-31 02:00:00,67.98350404 2013-08-31 03:00:00,68.65775842 2013-08-31 04:00:00,69.01901831 2013-08-31 05:00:00,68.7557281 2013-08-31 06:00:00,67.6440132 2013-08-31 07:00:00,67.09824802 2013-08-31 08:00:00,68.86076740000001 2013-08-31 09:00:00,68.54857064 2013-08-31 10:00:00,68.10020545 2013-08-31 11:00:00,67.3162411 2013-08-31 12:00:00,67.37946307 2013-08-31 13:00:00,68.16976322 2013-08-31 14:00:00,68.33976301 2013-08-31 15:00:00,68.55040093 2013-08-31 16:00:00,67.16532869 2013-08-31 17:00:00,67.30479343 2013-08-31 18:00:00,66.79372649 2013-08-31 19:00:00,66.97126902 2013-08-31 20:00:00,66.36018507 2013-08-31 21:00:00,67.20420628 2013-08-31 22:00:00,68.07608732 2013-08-31 23:00:00,67.23191893 2013-09-01 00:00:00,67.78175194 2013-09-01 01:00:00,66.07614673 2013-09-01 02:00:00,66.11011254 2013-09-01 03:00:00,67.10977933 2013-09-01 04:00:00,67.52951352 2013-09-01 05:00:00,67.37827727 2013-09-01 06:00:00,67.10470918 2013-09-01 07:00:00,66.9472606 2013-09-01 08:00:00,67.13996477 2013-09-01 09:00:00,66.67085420000001 2013-09-01 10:00:00,65.9378113 2013-09-01 11:00:00,66.5151767 2013-09-01 12:00:00,66.072041 2013-09-01 13:00:00,66.3918316 2013-09-01 14:00:00,65.43023923 2013-09-01 15:00:00,65.6508534 2013-09-01 16:00:00,66.13170688 2013-09-01 17:00:00,65.63831743 2013-09-01 18:00:00,65.95578224 2013-09-01 19:00:00,67.36956957 2013-09-01 20:00:00,67.02516809 2013-09-01 21:00:00,66.72385597 2013-09-01 22:00:00,67.25433659 2013-09-01 23:00:00,68.06762583 2013-09-02 00:00:00,68.2229547 2013-09-02 01:00:00,66.04236184 2013-09-02 02:00:00,66.95310877 2013-09-02 03:00:00,66.30459021 2013-09-02 04:00:00,66.61170465 2013-09-02 05:00:00,64.69937871 2013-09-02 06:00:00,66.21768604 2013-09-02 07:00:00,65.95636186 2013-09-02 08:00:00,65.97202741 2013-09-02 09:00:00,67.53287993 2013-09-02 10:00:00,67.49599206 2013-09-02 11:00:00,67.72868098 2013-09-02 12:00:00,68.32218023 2013-09-02 13:00:00,68.08308598 2013-09-02 14:00:00,68.607251 2013-09-02 15:00:00,68.77487445 2013-09-02 16:00:00,68.7696785 2013-09-02 17:00:00,68.64186817 2013-09-02 18:00:00,70.62377265 2013-09-02 19:00:00,69.50433389 2013-09-02 20:00:00,68.92231254 2013-09-02 21:00:00,70.48760069 2013-09-02 22:00:00,68.22783476 2013-09-02 23:00:00,69.04882691 2013-09-03 00:00:00,67.74723934 2013-09-03 01:00:00,68.09114575 2013-09-03 02:00:00,68.65891435 2013-09-03 03:00:00,69.63167183 2013-09-03 04:00:00,69.57087107 2013-09-03 05:00:00,68.92351224 2013-09-03 06:00:00,67.53393503 2013-09-03 07:00:00,68.2712078 2013-09-03 08:00:00,68.65631055 2013-09-03 09:00:00,67.39411119 2013-09-03 10:00:00,68.37006622 2013-09-03 11:00:00,68.23821811 2013-09-03 12:00:00,68.24746423 2013-09-03 13:00:00,67.42129150000001 2013-09-03 14:00:00,67.17151006 2013-09-03 15:00:00,68.84601436 2013-09-03 16:00:00,68.98532397 2013-09-03 17:00:00,68.6852691 2013-09-03 18:00:00,70.38096941 2013-09-03 19:00:00,70.63271507 2013-09-03 20:00:00,70.71181053 2013-09-03 21:00:00,71.77605259 2013-09-03 22:00:00,71.9902121 2013-09-03 23:00:00,70.50334409 2013-09-04 00:00:00,70.02106963 2013-09-04 01:00:00,71.10226832 2013-09-04 02:00:00,71.07281481 2013-09-04 03:00:00,71.00298194 2013-09-04 04:00:00,69.64750524 2013-09-04 05:00:00,69.29922688 2013-09-04 06:00:00,70.19295937 2013-09-04 07:00:00,69.59298326 2013-09-04 08:00:00,69.94483099 2013-09-04 09:00:00,68.38753638 2013-09-04 10:00:00,70.12778664 2013-09-04 11:00:00,69.75996879 2013-09-04 12:00:00,70.57663801 2013-09-04 13:00:00,70.11459489 2013-09-04 14:00:00,71.54936878 2013-09-04 15:00:00,71.04470664 2013-09-04 16:00:00,71.67149466 2013-09-04 17:00:00,73.23762503 2013-09-04 18:00:00,72.25962147 2013-09-04 19:00:00,72.93900293 2013-09-04 20:00:00,71.27122808 2013-09-04 21:00:00,72.55002116 2013-09-04 22:00:00,71.25225098 2013-09-04 23:00:00,71.97747232 2013-09-05 00:00:00,70.23719215 2013-09-05 01:00:00,69.94606111 2013-09-05 02:00:00,69.450805 2013-09-05 03:00:00,69.93479403 2013-09-05 04:00:00,69.0965309 2013-09-05 05:00:00,68.97376954 2013-09-05 06:00:00,70.04102824 2013-09-05 07:00:00,69.54259642 2013-09-05 08:00:00,69.85107284 2013-09-05 09:00:00,69.61953454 2013-09-05 10:00:00,69.99920276 2013-09-05 11:00:00,70.41283415 2013-09-05 12:00:00,72.11046261 2013-09-05 13:00:00,72.80678003 2013-09-05 14:00:00,72.51801434 2013-09-05 15:00:00,72.69228723 2013-09-05 16:00:00,72.16597707 2013-09-05 17:00:00,73.99614903 2013-09-05 18:00:00,72.82582702 2013-09-05 19:00:00,74.24818259 2013-09-05 20:00:00,74.69982523 2013-09-05 21:00:00,75.16462698 2013-09-05 22:00:00,74.48402123 2013-09-05 23:00:00,72.97264305 2013-09-06 00:00:00,72.49176792 2013-09-06 01:00:00,73.77290611 2013-09-06 02:00:00,73.53132409999998 2013-09-06 03:00:00,72.73837497 2013-09-06 04:00:00,71.88548201 2013-09-06 05:00:00,71.52278755 2013-09-06 06:00:00,71.76144938 2013-09-06 07:00:00,72.45670094 2013-09-06 08:00:00,71.89475031 2013-09-06 09:00:00,70.52341229 2013-09-06 10:00:00,71.2629687 2013-09-06 11:00:00,72.8074479 2013-09-06 12:00:00,73.80156306 2013-09-06 13:00:00,73.52862948 2013-09-06 14:00:00,72.90089441 2013-09-06 15:00:00,73.17178042 2013-09-06 16:00:00,73.42038306 2013-09-06 17:00:00,73.47819457 2013-09-06 18:00:00,73.96854139 2013-09-06 19:00:00,74.39984284 2013-09-06 20:00:00,74.13263209 2013-09-06 21:00:00,73.66106497 2013-09-06 22:00:00,74.42455034 2013-09-06 23:00:00,73.88125989 2013-09-07 00:00:00,72.88416225 2013-09-07 01:00:00,72.53366149 2013-09-07 02:00:00,72.28026919 2013-09-07 03:00:00,73.5383584 2013-09-07 04:00:00,72.97417623 2013-09-07 05:00:00,72.80378043 2013-09-07 06:00:00,71.11640175 2013-09-07 07:00:00,71.8028968 2013-09-07 08:00:00,71.74339169 2013-09-07 09:00:00,71.89946776 2013-09-07 10:00:00,71.37667995 2013-09-07 11:00:00,70.97398196 2013-09-07 12:00:00,71.3123657 2013-09-07 13:00:00,71.86460893 2013-09-07 14:00:00,71.16599578 2013-09-07 15:00:00,71.37723976 2013-09-07 16:00:00,71.36848881 2013-09-07 17:00:00,70.78637361 2013-09-07 18:00:00,71.11015784 2013-09-07 19:00:00,71.85983966 2013-09-07 20:00:00,70.95035881 2013-09-07 21:00:00,72.65891354 2013-09-07 22:00:00,72.33779272 2013-09-07 23:00:00,70.61711298 2013-09-08 00:00:00,71.01930095 2013-09-08 01:00:00,71.63639202 2013-09-08 02:00:00,71.32415634 2013-09-08 03:00:00,70.5466809 2013-09-08 04:00:00,70.97726886 2013-09-08 05:00:00,69.7019157 2013-09-08 06:00:00,70.36501785 2013-09-08 07:00:00,69.28265658 2013-09-08 08:00:00,68.52513155 2013-09-08 09:00:00,68.91671905 2013-09-08 10:00:00,68.90391361 2013-09-08 11:00:00,69.25304945 2013-09-08 12:00:00,69.20694068 2013-09-08 13:00:00,68.4344154 2013-09-08 14:00:00,69.13783219 2013-09-08 15:00:00,67.78567323 2013-09-08 16:00:00,68.87397161 2013-09-08 17:00:00,68.04502775 2013-09-08 18:00:00,67.81055256 2013-09-08 19:00:00,68.99773267 2013-09-08 20:00:00,68.99448259 2013-09-08 21:00:00,67.84551049 2013-09-08 22:00:00,68.86458993 2013-09-08 23:00:00,67.97043986 2013-09-09 00:00:00,66.92321439 2013-09-09 01:00:00,68.59393936 2013-09-09 02:00:00,66.62695158 2013-09-09 03:00:00,67.75427493 2013-09-09 04:00:00,66.66782263 2013-09-09 05:00:00,67.46664892 2013-09-09 06:00:00,67.60322003 2013-09-09 07:00:00,67.66040956 2013-09-09 08:00:00,66.65714613 2013-09-09 09:00:00,68.75283581 2013-09-09 10:00:00,69.19079475 2013-09-09 11:00:00,70.45646119 2013-09-09 12:00:00,70.93982761 2013-09-09 13:00:00,69.63003292 2013-09-09 14:00:00,71.41526516 2013-09-09 15:00:00,71.55056424 2013-09-09 16:00:00,71.90106522 2013-09-09 17:00:00,71.69673606 2013-09-09 18:00:00,71.04065657 2013-09-09 19:00:00,71.73045012 2013-09-09 20:00:00,72.76664681 2013-09-16 12:00:00,72.69643979 2013-09-16 13:00:00,72.80547371 2013-09-16 14:00:00,72.91975931 2013-09-16 15:00:00,72.26792976 2013-09-16 16:00:00,72.85550390000002 2013-09-16 17:00:00,72.96351653 2013-09-16 18:00:00,72.77608689 2013-09-16 19:00:00,74.71764725 2013-09-16 20:00:00,75.18175232 2013-09-16 21:00:00,74.68157666 2013-09-16 22:00:00,75.03251294 2013-09-16 23:00:00,74.89547613 2013-09-17 00:00:00,72.88724781 2013-09-17 01:00:00,74.04983548 2013-09-17 02:00:00,73.82712414 2013-09-17 03:00:00,72.79875638 2013-09-17 04:00:00,71.99918837 2013-09-17 05:00:00,72.17190677 2013-09-17 06:00:00,71.25158302 2013-09-17 07:00:00,71.28680525 2013-09-17 08:00:00,71.38988043 2013-09-17 09:00:00,72.24634579 2013-09-17 10:00:00,71.59644925 2013-09-17 11:00:00,72.90837738 2013-09-17 12:00:00,73.24145352 2013-09-17 13:00:00,73.06605307 2013-09-17 14:00:00,72.64709801 2013-09-17 15:00:00,73.15343178 2013-09-17 16:00:00,72.96232879 2013-09-17 17:00:00,72.52813486 2013-09-17 18:00:00,73.81719904 2013-09-17 19:00:00,74.02874448 2013-09-17 20:00:00,73.79102864 2013-09-17 21:00:00,73.25605739 2013-09-17 22:00:00,73.05358423 2013-09-17 23:00:00,73.77224906 2013-09-18 00:00:00,72.8998969 2013-09-18 01:00:00,72.24385814 2013-09-18 02:00:00,71.33933531 2013-09-18 03:00:00,72.29793377 2013-09-18 04:00:00,70.34516442 2013-09-18 05:00:00,71.13949198 2013-09-18 06:00:00,70.16453648 2013-09-18 07:00:00,71.11202658 2013-09-18 08:00:00,70.4874724 2013-09-18 09:00:00,70.71749668 2013-09-18 10:00:00,69.89570423 2013-09-18 11:00:00,71.68790348 2013-09-18 12:00:00,71.37615947 2013-09-18 13:00:00,71.74150703 2013-09-18 14:00:00,73.20729802 2013-09-18 15:00:00,72.89029189 2013-09-18 16:00:00,72.30341978 2013-09-18 17:00:00,72.6912123 2013-09-18 18:00:00,72.34201351 2013-09-18 19:00:00,74.49429294 2013-09-18 20:00:00,73.25501422 2013-09-18 21:00:00,74.13004256 2013-09-18 22:00:00,73.68325892 2013-09-18 23:00:00,72.11340117 2013-09-19 00:00:00,72.31138231 2013-09-19 01:00:00,71.29385993 2013-09-19 02:00:00,71.93404046 2013-09-19 03:00:00,71.67908598 2013-09-19 04:00:00,71.48141177 2013-09-19 05:00:00,70.85357689 2013-09-19 06:00:00,69.45647733 2013-09-19 07:00:00,70.12965246 2013-09-19 08:00:00,69.02484940000001 2013-09-19 09:00:00,69.00810205 2013-09-19 10:00:00,67.59898139 2013-09-19 11:00:00,67.55493576 2013-09-19 12:00:00,67.40273072 2013-09-19 13:00:00,67.39032649 2013-09-19 14:00:00,68.09580201 2013-09-19 15:00:00,67.39266673 2013-09-19 16:00:00,68.36226835 2013-09-19 17:00:00,68.40469903 2013-09-19 18:00:00,67.83621597 2013-09-19 19:00:00,69.19489788 2013-09-19 20:00:00,68.49088179 2013-09-19 21:00:00,68.33740959999999 2013-09-19 22:00:00,68.76983220000001 2013-09-19 23:00:00,68.4357686 2013-09-20 00:00:00,68.74846768 2013-09-20 01:00:00,68.95527404 2013-09-20 02:00:00,68.2181708 2013-09-20 03:00:00,69.12993292 2013-09-20 04:00:00,68.4385586 2013-09-20 05:00:00,69.06796416 2013-09-20 06:00:00,68.30227174 2013-09-20 07:00:00,68.64631402 2013-09-20 08:00:00,68.88148079 2013-09-20 09:00:00,68.90088305 2013-09-20 10:00:00,69.65328565 2013-09-20 11:00:00,68.86754593 2013-09-20 12:00:00,68.42564703 2013-09-20 13:00:00,69.09581068 2013-09-20 14:00:00,69.44780599 2013-09-20 15:00:00,68.42082002 2013-09-20 16:00:00,68.83199074 2013-09-20 17:00:00,69.55729317 2013-09-20 18:00:00,68.83137434 2013-09-20 19:00:00,70.02835926 2013-09-20 20:00:00,71.07058978 2013-09-20 21:00:00,71.28937940000002 2013-09-20 22:00:00,70.10090101 2013-09-20 23:00:00,71.68557803 2013-09-21 00:00:00,69.88814945 2013-09-21 01:00:00,70.42523491 2013-09-21 02:00:00,69.44404702 2013-09-21 03:00:00,70.1451179 2013-09-21 04:00:00,69.48543471 2013-09-21 05:00:00,69.63115874 2013-09-21 06:00:00,70.00727727 2013-09-21 07:00:00,69.16183248 2013-09-21 08:00:00,68.43812628 2013-09-21 09:00:00,68.65276698 2013-09-21 10:00:00,68.15293671 2013-09-21 11:00:00,69.64474901 2013-09-21 12:00:00,69.0369617 2013-09-21 13:00:00,68.59565354 2013-09-21 14:00:00,69.91779386 2013-09-21 15:00:00,68.59944984 2013-09-21 16:00:00,68.66763575 2013-09-21 17:00:00,68.79732688 2013-09-21 18:00:00,69.52728032 2013-09-21 19:00:00,69.14499021 2013-09-21 20:00:00,69.36640493 2013-09-21 21:00:00,69.32436477 2013-09-21 22:00:00,70.04079998 2013-09-21 23:00:00,70.32088532 2013-09-22 00:00:00,70.68643574 2013-09-22 01:00:00,69.41778612 2013-09-22 02:00:00,69.52225613 2013-09-22 03:00:00,69.97825566 2013-09-22 04:00:00,69.84686459999999 2013-09-22 05:00:00,69.94587165 2013-09-22 06:00:00,68.70555692 2013-09-22 07:00:00,68.59229114 2013-09-22 08:00:00,69.9367965 2013-09-22 09:00:00,69.07467717 2013-09-22 10:00:00,68.77459707 2013-09-22 11:00:00,68.96774462 2013-09-22 12:00:00,69.51423059 2013-09-22 13:00:00,69.60984678 2013-09-22 14:00:00,68.45901476 2013-09-22 15:00:00,68.66205887 2013-09-22 16:00:00,69.07470807 2013-09-22 17:00:00,68.98798244 2013-09-22 18:00:00,70.4512398 2013-09-22 19:00:00,69.1587948 2013-09-22 20:00:00,70.02852311 2013-09-22 21:00:00,70.30112967 2013-09-22 22:00:00,71.02701721 2013-09-22 23:00:00,70.44438138 2013-09-23 00:00:00,71.21079549 2013-09-23 01:00:00,70.08097943 2013-09-23 02:00:00,70.01900785 2013-09-23 03:00:00,71.31684052 2013-09-23 04:00:00,69.49194049 2013-09-23 05:00:00,70.71476009 2013-09-23 06:00:00,70.30901685 2013-09-23 07:00:00,69.92749715 2013-09-23 08:00:00,69.28252505 2013-09-23 09:00:00,70.51499697 2013-09-23 10:00:00,69.17037572 2013-09-23 11:00:00,69.67300935 2013-09-23 12:00:00,70.98686733 2013-09-23 13:00:00,72.71037561 2013-09-23 14:00:00,72.84618043 2013-09-23 15:00:00,71.49931817 2013-09-23 16:00:00,71.82884072 2013-09-23 17:00:00,71.96846019 2013-09-23 18:00:00,72.38205511 2013-09-23 19:00:00,73.10852105 2013-09-23 20:00:00,72.50710177 2013-09-23 21:00:00,71.36822279 2013-09-23 22:00:00,71.73373415 2013-09-23 23:00:00,70.39800507 2013-09-24 00:00:00,71.02329854 2013-09-24 01:00:00,70.42861121 2013-09-24 02:00:00,71.29850242 2013-09-24 03:00:00,70.41391036 2013-09-24 04:00:00,69.83300525 2013-09-24 05:00:00,70.04073494 2013-09-24 06:00:00,69.2952676 2013-09-24 07:00:00,69.80497056 2013-09-24 08:00:00,70.47845996 2013-09-24 09:00:00,68.87983862 2013-09-24 10:00:00,70.82988977 2013-09-24 11:00:00,71.7612628 2013-09-24 12:00:00,71.23686153 2013-09-24 13:00:00,72.17708088 2013-09-24 14:00:00,73.52407232 2013-09-24 15:00:00,73.43257426 2013-09-24 16:00:00,71.96142812 2013-09-24 17:00:00,72.06857704 2013-09-24 18:00:00,72.80742737 2013-09-24 19:00:00,74.18072649 2013-09-24 20:00:00,72.6407991 2013-09-24 21:00:00,72.49329287 2013-09-24 22:00:00,73.37279171 2013-09-24 23:00:00,72.84631814 2013-09-25 00:00:00,73.74634464 2013-09-25 01:00:00,73.08950487 2013-09-25 02:00:00,73.12797789 2013-09-25 03:00:00,72.85145065 2013-09-25 04:00:00,71.78459362 2013-09-25 05:00:00,71.96428662 2013-09-25 06:00:00,70.98315976 2013-09-25 07:00:00,72.09370496 2013-09-25 08:00:00,70.47875896 2013-09-25 09:00:00,71.15613714 2013-09-25 10:00:00,71.79613981 2013-09-25 11:00:00,70.53267958 2013-09-25 12:00:00,70.92408688 2013-09-25 13:00:00,71.07714472 2013-09-25 14:00:00,72.12801602 2013-09-25 15:00:00,73.76239725 2013-09-25 16:00:00,73.50455944 2013-09-25 17:00:00,74.06381073 2013-09-25 18:00:00,75.84971566 2013-09-25 19:00:00,74.917338 2013-09-25 20:00:00,74.48204982 2013-09-25 21:00:00,75.4754704 2013-09-25 22:00:00,75.86633429 2013-09-25 23:00:00,75.82692618 2013-09-26 00:00:00,74.83518922 2013-09-26 01:00:00,75.84170562 2013-09-26 02:00:00,74.56152098 2013-09-26 03:00:00,74.74597341 2013-09-26 04:00:00,73.95196621 2013-09-26 05:00:00,74.73785827 2013-09-26 06:00:00,73.40944252 2013-09-26 07:00:00,74.09665445 2013-09-26 08:00:00,74.24341181 2013-09-26 09:00:00,72.4241878 2013-09-26 10:00:00,73.53577955 2013-09-26 11:00:00,72.89263790000003 2013-09-26 12:00:00,74.20179708 2013-09-26 13:00:00,73.82891751 2013-09-26 14:00:00,75.00384972 2013-09-26 15:00:00,75.06654759999998 2013-09-26 16:00:00,76.10375919 2013-09-26 17:00:00,75.0111683 2013-09-26 18:00:00,76.19220719 2013-09-26 19:00:00,75.75430219 2013-09-26 20:00:00,76.55201347 2013-09-26 21:00:00,76.3420965 2013-09-26 22:00:00,77.36149124 2013-09-26 23:00:00,76.62602951 2013-09-27 00:00:00,77.08086395 2013-09-27 01:00:00,77.09614267 2013-09-27 02:00:00,76.94079244 2013-09-27 03:00:00,76.9216273 2013-09-27 04:00:00,76.41395592 2013-09-27 05:00:00,76.76728419 2013-09-27 06:00:00,75.56516500000002 2013-09-27 07:00:00,75.00316640000001 2013-09-27 08:00:00,74.96022554 2013-09-27 09:00:00,76.25958507 2013-09-27 10:00:00,75.03195475 2013-09-27 11:00:00,75.97741221 2013-09-27 12:00:00,74.70847211 2013-10-01 12:00:00,75.66428844 2013-10-01 13:00:00,76.15183593 2013-10-01 14:00:00,74.94798282 2013-10-01 15:00:00,76.11749514 2013-10-01 16:00:00,76.35342739 2013-10-01 17:00:00,78.18999866 2013-10-01 18:00:00,78.34183958 2013-10-01 19:00:00,77.44052693 2013-10-01 20:00:00,76.20708541 2013-10-01 21:00:00,78.08998122 2013-10-01 22:00:00,78.05491504 2013-10-01 23:00:00,78.98542499 2013-10-02 00:00:00,78.23875807 2013-10-02 01:00:00,78.65871078 2013-10-02 02:00:00,78.53164898 2013-10-02 03:00:00,78.14277259999999 2013-10-02 04:00:00,76.73686252 2013-10-02 05:00:00,76.53612798 2013-10-02 06:00:00,77.21543335 2013-10-02 07:00:00,76.92976821 2013-10-02 08:00:00,77.61334761 2013-10-02 09:00:00,75.94869317 2013-10-02 10:00:00,76.80988678 2013-10-02 11:00:00,76.35617474 2013-10-02 12:00:00,75.51487417 2013-10-02 13:00:00,76.75914485 2013-10-02 14:00:00,77.18231352 2013-10-02 15:00:00,76.72424559 2013-10-02 16:00:00,77.02058259 2013-10-02 17:00:00,77.59412726 2013-10-02 18:00:00,76.57737238 2013-10-02 19:00:00,78.14370344 2013-10-02 20:00:00,76.44863817 2013-10-02 21:00:00,77.11808435 2013-10-02 22:00:00,76.66444143 2013-10-02 23:00:00,77.60066939 2013-10-03 00:00:00,76.44893235 2013-10-03 01:00:00,77.72893525 2013-10-03 02:00:00,76.61186772 2013-10-03 03:00:00,77.04302364 2013-10-03 04:00:00,75.7689679 2013-10-03 05:00:00,76.38938955 2013-10-03 06:00:00,76.10096966 2013-10-03 07:00:00,76.62421773 2013-10-03 08:00:00,75.41072897 2013-10-03 09:00:00,76.32543548 2013-10-03 10:00:00,75.26776154 2013-10-03 11:00:00,75.11220118 2013-10-03 12:00:00,76.37061231 2013-10-03 13:00:00,75.17527773 2013-10-03 14:00:00,76.48020188 2013-10-03 15:00:00,75.40371872 2013-10-03 16:00:00,76.08145149 2013-10-03 17:00:00,74.83978917 2013-10-03 18:00:00,74.700469 2013-10-03 19:00:00,75.46720555 2013-10-03 20:00:00,74.52571486 2013-10-03 21:00:00,75.50447062 2013-10-03 22:00:00,76.68142877 2013-10-03 23:00:00,77.07422539 2013-10-04 00:00:00,76.62848003 2013-10-04 01:00:00,75.65887074 2013-10-04 02:00:00,76.78498097 2013-10-04 03:00:00,76.97398833 2013-10-04 04:00:00,76.81809786 2013-10-04 05:00:00,76.18810762 2013-10-04 06:00:00,75.14738658 2013-10-04 07:00:00,74.60880026 2013-10-04 08:00:00,74.71020506 2013-10-04 09:00:00,74.33666665 2013-10-04 10:00:00,75.89063588 2013-10-04 11:00:00,74.92352501 2013-10-04 12:00:00,76.25032166 2013-10-04 13:00:00,76.76285447 2013-10-04 14:00:00,76.43795622 2013-10-04 15:00:00,75.84095165 2013-10-04 16:00:00,76.30759992 2013-10-04 17:00:00,76.37889288 2013-10-04 18:00:00,74.50037961 2013-10-04 19:00:00,75.46855478 2013-10-04 20:00:00,76.23977529 2013-10-04 21:00:00,75.60803745 2013-10-04 22:00:00,75.53609477 2013-10-04 23:00:00,76.15092858 2013-10-05 00:00:00,77.04357167 2013-10-05 01:00:00,76.83958927 2013-10-05 02:00:00,75.35704476 2013-10-05 03:00:00,75.26244693 2013-10-05 04:00:00,75.67256245 2013-10-05 05:00:00,74.97423465 2013-10-05 06:00:00,74.68662683 2013-10-05 07:00:00,74.67127682 2013-10-05 08:00:00,75.30039984 2013-10-05 09:00:00,75.41442640000002 2013-10-05 10:00:00,75.77834261 2013-10-05 11:00:00,76.30250549 2013-10-05 12:00:00,76.08729308 2013-10-05 13:00:00,76.17387791 2013-10-05 14:00:00,74.59539903 2013-10-05 15:00:00,74.8586202 2013-10-05 16:00:00,76.15473545 2013-10-05 17:00:00,76.73544665 2013-10-05 18:00:00,76.81207028 2013-10-05 19:00:00,76.76942959 2013-10-05 20:00:00,76.0742703 2013-10-05 21:00:00,77.67624752 2013-10-05 22:00:00,77.20513301 2013-10-05 23:00:00,78.30547509 2013-10-06 00:00:00,76.57887568 2013-10-06 01:00:00,76.88289528 2013-10-06 02:00:00,77.48251447 2013-10-06 03:00:00,76.38323965 2013-10-06 04:00:00,76.26112886 2013-10-06 05:00:00,77.83782089 2013-10-06 06:00:00,77.81793736 2013-10-06 07:00:00,76.88455309 2013-10-06 08:00:00,77.29695705 2013-10-06 09:00:00,75.7818161 2013-10-06 10:00:00,77.23681223 2013-10-06 11:00:00,77.65970467 2013-10-06 12:00:00,76.47686703 2013-10-06 13:00:00,76.45250409 2013-10-06 14:00:00,76.44446488 2013-10-06 15:00:00,75.338712 2013-10-06 16:00:00,75.43988813 2013-10-06 17:00:00,76.11375195 2013-10-06 18:00:00,75.44361839 2013-10-06 19:00:00,74.85664993 2013-10-06 20:00:00,75.89981187 2013-10-06 21:00:00,75.52638288 2013-10-06 22:00:00,76.70454118 2013-10-06 23:00:00,76.91841747 2013-10-07 00:00:00,76.77395886 2013-10-07 01:00:00,76.24255849 2013-10-07 02:00:00,75.93339717 2013-10-07 03:00:00,75.02163716 2013-10-07 04:00:00,75.85554729 2013-10-07 05:00:00,75.36964545 2013-10-07 06:00:00,74.66467269 2013-10-07 07:00:00,73.75869737 2013-10-07 08:00:00,74.69866385 2013-10-07 09:00:00,74.63334088 2013-10-07 10:00:00,74.24988343 2013-10-07 11:00:00,75.38338771 2013-10-07 12:00:00,74.12097863 2013-10-07 13:00:00,75.46608714 2013-10-07 14:00:00,74.99673301 2013-10-07 15:00:00,75.84411143 2013-10-07 16:00:00,76.15467811 2013-10-07 17:00:00,75.38180222 2013-10-07 18:00:00,74.98612428 2013-10-07 19:00:00,74.83290714 2013-10-07 20:00:00,75.33838706 2013-10-07 21:00:00,75.99301951 2013-10-07 22:00:00,75.44383011 2013-10-07 23:00:00,74.71510278 2013-10-08 00:00:00,75.16393256 2013-10-08 01:00:00,73.98772604 2013-10-08 02:00:00,72.99713921 2013-10-08 03:00:00,72.73963377 2013-10-08 04:00:00,72.56210332 2013-10-08 05:00:00,71.95415339 2013-10-08 06:00:00,71.53772099 2013-10-08 07:00:00,73.3846364 2013-10-08 08:00:00,73.02911198 2013-10-08 09:00:00,73.32056873 2013-10-08 10:00:00,72.65757445 2013-10-08 11:00:00,72.91058794 2013-10-08 12:00:00,72.00144343 2013-10-08 13:00:00,72.17948397 2013-10-08 14:00:00,73.13684959999998 2013-10-08 15:00:00,72.74243972 2013-10-08 16:00:00,74.04314141 2013-10-08 17:00:00,74.9362334 2013-10-08 18:00:00,73.60819261 2013-10-08 19:00:00,74.85510654 2013-10-08 20:00:00,75.18349971 2013-10-08 21:00:00,74.64847435 2013-10-08 22:00:00,74.30749947 2013-10-08 23:00:00,74.22020409 2013-10-09 00:00:00,73.93927621 2013-10-09 01:00:00,73.62134422 2013-10-09 02:00:00,73.81914203 2013-10-09 03:00:00,72.9684546 2013-10-09 04:00:00,73.01285776 2013-10-09 05:00:00,72.80505299 2013-10-09 06:00:00,72.66330867 2013-10-09 07:00:00,72.77940061 2013-10-09 08:00:00,72.45267623 2013-10-09 09:00:00,72.41013365 2013-10-09 10:00:00,72.97620201 2013-10-09 11:00:00,72.70599693 2013-10-09 12:00:00,72.67329612 2013-10-09 13:00:00,73.25471351 2013-10-09 14:00:00,74.21758249 2013-10-09 15:00:00,73.41679227 2013-10-09 16:00:00,73.26801845 2013-10-09 17:00:00,74.21654701 2013-10-09 18:00:00,74.49963991 2013-10-09 19:00:00,74.93839694 2013-10-09 20:00:00,74.48590659999998 2013-10-09 21:00:00,74.5249187 2013-10-09 22:00:00,74.94497354 2013-10-09 23:00:00,75.11312816 2013-10-10 00:00:00,73.45479839 2013-10-10 01:00:00,73.62753539 2013-10-10 02:00:00,74.65356252 2013-10-10 03:00:00,73.65569667 2013-10-10 04:00:00,74.30833238 2013-10-10 05:00:00,72.36883324 2013-10-10 06:00:00,72.63029089 2013-10-10 07:00:00,72.92216679 2013-10-10 08:00:00,73.50841047 2013-10-10 09:00:00,73.8940062 2013-10-10 10:00:00,72.75520825 2013-10-10 11:00:00,72.77342691 2013-10-10 12:00:00,74.0173653 2013-10-10 13:00:00,74.07999403 2013-10-10 14:00:00,74.98348749 2013-10-10 15:00:00,74.93166228 2013-10-10 16:00:00,75.00032977 2013-10-10 17:00:00,74.79545142 2013-10-10 18:00:00,74.22649476 2013-10-10 19:00:00,74.89181277 2013-10-10 20:00:00,76.03381278 2013-10-10 21:00:00,75.75160616 2013-10-10 22:00:00,75.35499490000002 2013-10-10 23:00:00,75.3520882 2013-10-11 00:00:00,75.59122877 2013-10-11 01:00:00,74.60615095 2013-10-11 02:00:00,73.66657269 2013-10-11 03:00:00,75.29576071 2013-10-11 04:00:00,73.07467638 2013-10-11 05:00:00,73.54096289 2013-10-11 06:00:00,73.56748044 2013-10-11 07:00:00,72.23943668 2013-10-11 08:00:00,72.98971633 2013-10-11 09:00:00,71.8624757 2013-10-11 10:00:00,72.15907086 2013-10-11 11:00:00,73.28710779 2013-10-11 12:00:00,73.23267068 2013-10-11 13:00:00,72.91831075 2013-10-11 14:00:00,74.13951981 2013-10-11 15:00:00,73.91840559 2013-10-11 16:00:00,74.05658495 2013-10-11 17:00:00,74.4819446 2013-10-11 18:00:00,75.13591435 2013-10-11 19:00:00,75.68312614 2013-10-11 20:00:00,74.4794284 2013-10-14 19:00:00,72.98303434 2013-10-14 20:00:00,73.97904439 2013-10-14 21:00:00,72.80960896 2013-10-14 22:00:00,74.45908003 2013-10-14 23:00:00,73.22449615 2013-10-15 00:00:00,74.08849517 2013-10-15 01:00:00,72.09427723 2013-10-15 02:00:00,73.30412261 2013-10-15 03:00:00,72.49226170000001 2013-10-15 04:00:00,71.55592659 2013-10-15 05:00:00,71.92880201 2013-10-15 06:00:00,72.20455302 2013-10-15 07:00:00,71.5729309 2013-10-15 08:00:00,71.38455809 2013-10-15 09:00:00,71.57838797 2013-10-15 10:00:00,72.33092601 2013-10-15 11:00:00,72.5020361 2013-10-15 12:00:00,72.16890223 2013-10-15 13:00:00,71.80124576 2013-10-15 14:00:00,71.98653741 2013-10-15 15:00:00,73.57829998 2013-10-15 16:00:00,73.76993449 2013-10-15 17:00:00,73.90520817 2013-10-15 18:00:00,73.88052554 2013-10-15 19:00:00,72.72460722 2013-10-15 20:00:00,73.87825084 2013-10-15 21:00:00,73.1538236 2013-10-15 22:00:00,74.25507299 2013-10-15 23:00:00,72.78303586 2013-10-16 00:00:00,72.70043711 2013-10-16 01:00:00,72.55484862 2013-10-16 02:00:00,72.52805707 2013-10-16 03:00:00,73.14618943 2013-10-16 04:00:00,71.23182363 2013-10-16 05:00:00,72.41740232 2013-10-16 06:00:00,71.66301343 2013-10-16 07:00:00,71.06682037 2013-10-16 08:00:00,72.17174017 2013-10-16 09:00:00,71.98736373 2013-10-16 10:00:00,71.53260775 2013-10-16 11:00:00,72.36545699 2013-10-16 12:00:00,72.78437383 2013-10-16 13:00:00,71.97296390000002 2013-10-16 14:00:00,72.4644608 2013-10-16 15:00:00,72.62455626 2013-10-16 16:00:00,73.55532127 2013-10-16 17:00:00,72.89143683 2013-10-16 18:00:00,74.21730356 2013-10-16 19:00:00,75.25147517 2013-10-16 20:00:00,75.28003046 2013-10-16 21:00:00,73.45611639 2013-10-16 22:00:00,67.59220788 2013-10-16 23:00:00,74.3959065 2013-10-17 00:00:00,72.76152535 2013-10-17 01:00:00,72.84667905 2013-10-17 02:00:00,74.06782481 2013-10-17 03:00:00,73.40328569 2013-10-17 04:00:00,72.4928657 2013-10-17 05:00:00,72.36963864 2013-10-17 06:00:00,70.63012656 2013-10-17 07:00:00,70.32611117 2013-10-17 08:00:00,71.46025104 2013-10-17 09:00:00,71.14590855 2013-10-17 10:00:00,71.46817075 2013-10-17 11:00:00,71.41876211 2013-10-17 12:00:00,72.99363734 2013-10-17 13:00:00,72.24666709 2013-10-17 14:00:00,73.45167119 2013-10-17 15:00:00,74.39956072 2013-10-17 16:00:00,72.81416628 2013-10-17 17:00:00,73.03240204 2013-10-17 18:00:00,75.04333658 2013-10-17 19:00:00,73.92938757 2013-10-17 20:00:00,73.81507515 2013-10-17 21:00:00,74.08455767 2013-10-17 22:00:00,73.38180602 2013-10-17 23:00:00,73.23701247 2013-10-18 00:00:00,72.99037413 2013-10-18 01:00:00,72.99012950000002 2013-10-18 02:00:00,72.66562134 2013-10-18 03:00:00,72.51950292 2013-10-18 04:00:00,72.45390193 2013-10-18 05:00:00,72.03998157 2013-10-18 06:00:00,72.47195408 2013-10-18 07:00:00,72.34968064 2013-10-18 08:00:00,71.45220535 2013-10-18 09:00:00,71.55743829999999 2013-10-18 10:00:00,72.63790855 2013-10-18 11:00:00,71.85849263 2013-10-18 12:00:00,72.93395917 2013-10-18 13:00:00,72.38591831 2013-10-18 14:00:00,73.80702055 2013-10-18 15:00:00,73.52710171 2013-10-18 16:00:00,74.83471181 2013-10-18 17:00:00,74.21326248 2013-10-18 18:00:00,73.25223693 2013-10-18 19:00:00,73.93628199999998 2013-10-18 20:00:00,73.04669143 2013-10-18 21:00:00,73.08417829999998 2013-10-18 22:00:00,74.19287354 2013-10-18 23:00:00,73.41808921 2013-10-19 00:00:00,74.12963911 2013-10-19 01:00:00,73.46278565 2013-10-19 02:00:00,73.62789649 2013-10-19 03:00:00,71.92833946 2013-10-19 04:00:00,72.26119661 2013-10-19 05:00:00,71.47946165 2013-10-19 06:00:00,72.63321496 2013-10-19 07:00:00,72.24354039 2013-10-19 08:00:00,71.57056509 2013-10-19 09:00:00,72.2797028 2013-10-19 10:00:00,73.01911793 2013-10-19 11:00:00,71.61445258 2013-10-19 12:00:00,71.26409105 2013-10-19 13:00:00,71.75373049 2013-10-19 14:00:00,72.57075359 2013-10-19 15:00:00,71.7959401 2013-10-19 16:00:00,71.53861613 2013-10-19 17:00:00,70.90022339 2013-10-19 18:00:00,71.73254786 2013-10-19 19:00:00,71.71309029999998 2013-10-19 20:00:00,72.76010528 2013-10-19 21:00:00,72.84417558 2013-10-19 22:00:00,71.99223058 2013-10-19 23:00:00,71.70725001 2013-10-20 00:00:00,71.71438532 2013-10-20 01:00:00,72.55191183 2013-10-20 02:00:00,71.03928043 2013-10-20 03:00:00,71.46046414 2013-10-20 04:00:00,71.99130446 2013-10-20 05:00:00,71.45046564 2013-10-20 06:00:00,71.51504432 2013-10-20 07:00:00,70.99280008 2013-10-20 08:00:00,71.34776909 2013-10-20 09:00:00,70.72845843 2013-10-20 10:00:00,70.27507626 2013-10-20 11:00:00,70.27111929 2013-10-20 12:00:00,70.85408914 2013-10-20 13:00:00,69.94855497 2013-10-20 14:00:00,69.53492069 2013-10-20 15:00:00,70.92058525 2013-10-20 16:00:00,70.99850582 2013-10-20 17:00:00,71.05686947 2013-10-20 18:00:00,72.14843798 2013-10-20 19:00:00,71.45617637 2013-10-20 20:00:00,73.27200083 2013-10-20 21:00:00,71.80063059 2013-10-20 22:00:00,73.01762667 2013-10-20 23:00:00,72.12768954 2013-10-21 00:00:00,73.33199587 2013-10-21 01:00:00,73.21702132 2013-10-21 02:00:00,72.41071376 2013-10-21 03:00:00,72.12548765 2013-10-21 04:00:00,73.03066312 2013-10-21 05:00:00,71.54792939 2013-10-21 06:00:00,72.74034991 2013-10-21 07:00:00,71.35108732 2013-10-21 08:00:00,71.40181091 2013-10-21 09:00:00,72.12977881 2013-10-21 10:00:00,72.31327617 2013-10-21 11:00:00,71.50759292 2013-10-21 12:00:00,73.42790189 2013-10-21 13:00:00,74.33787739 2013-10-21 14:00:00,73.42943331 2013-10-21 15:00:00,72.64800749999998 2013-10-21 16:00:00,74.48313565 2013-10-21 17:00:00,73.37484563 2013-10-21 18:00:00,74.54468294 2013-10-21 19:00:00,74.91468608 2013-10-21 20:00:00,74.48188759 2013-10-21 21:00:00,73.21984661 2013-10-21 22:00:00,73.46717767 2013-10-21 23:00:00,73.43538257 2013-10-22 00:00:00,74.11014418 2013-10-22 01:00:00,74.0856674 2013-10-22 02:00:00,74.43241463 2013-10-22 03:00:00,74.304057 2013-10-22 04:00:00,73.43146696 2013-10-22 05:00:00,72.49383421 2013-10-22 06:00:00,73.03216682 2013-10-22 07:00:00,71.83335039 2013-10-22 08:00:00,71.01856015 2013-10-22 09:00:00,72.21563105 2013-10-22 10:00:00,72.48771792 2013-10-22 11:00:00,72.7382649 2013-10-22 12:00:00,73.60978997 2013-10-22 13:00:00,73.74620023 2013-10-22 14:00:00,73.23713965 2013-10-22 15:00:00,73.4530571 2013-10-22 16:00:00,73.92328043 2013-10-22 17:00:00,75.18250744 2013-10-22 18:00:00,74.02490252 2013-10-22 19:00:00,75.3285915 2013-10-22 20:00:00,74.66865644 2013-10-22 21:00:00,74.14984749 2013-10-22 22:00:00,74.89985381 2013-10-22 23:00:00,75.30346611 2013-10-23 00:00:00,73.91031296 2013-10-23 01:00:00,73.93275037 2013-10-23 02:00:00,73.16148058 2013-10-23 03:00:00,73.52562326 2013-10-23 04:00:00,72.47484370000002 2013-10-23 05:00:00,72.49504420000002 2013-10-23 06:00:00,71.61991048 2013-10-23 07:00:00,73.22943968 2013-10-23 08:00:00,71.58909683 2013-10-23 09:00:00,71.81584418 2013-10-23 10:00:00,71.34809224 2013-10-23 11:00:00,72.96869218 2013-10-23 12:00:00,72.55053234 2013-10-23 13:00:00,72.57797464 2013-10-23 14:00:00,74.69536550000002 2013-10-23 15:00:00,74.1296061 2013-10-23 16:00:00,73.94533205 2013-10-23 17:00:00,74.07901132 2013-10-23 18:00:00,75.05479911 2013-10-23 19:00:00,74.85789892 2013-10-23 20:00:00,76.0974356 2013-10-23 21:00:00,75.60625767 2013-10-23 22:00:00,76.460003 2013-10-23 23:00:00,75.95853846 2013-10-24 00:00:00,75.66920488 2013-10-24 01:00:00,76.19819465 2013-10-24 02:00:00,74.83838032 2013-10-24 03:00:00,75.34256101 2013-10-24 04:00:00,75.63691814 2013-10-24 05:00:00,76.00126612 2013-10-24 06:00:00,74.28973725 2013-10-24 07:00:00,74.80605955 2013-10-24 08:00:00,75.30172567 2013-10-24 09:00:00,74.34735395 2013-10-24 10:00:00,75.12651355 2013-10-24 11:00:00,73.75813908 2013-10-24 12:00:00,75.04085467 2013-10-24 13:00:00,74.7295084 2013-10-24 14:00:00,75.23496324 2013-10-24 15:00:00,74.09558127 2013-10-24 16:00:00,75.40924951 2013-10-24 17:00:00,75.05840643 2013-10-24 18:00:00,75.20790637 2013-10-24 19:00:00,73.69135931 2013-10-24 20:00:00,73.54196014 2013-10-24 21:00:00,75.19082042 2013-10-24 22:00:00,74.60746814 2013-10-24 23:00:00,74.53993625 2013-10-25 00:00:00,73.4168865 2013-10-25 01:00:00,73.95852383 2013-10-25 02:00:00,73.75006416 2013-10-25 03:00:00,74.14389026 2013-10-25 04:00:00,72.51791753 2013-10-25 05:00:00,73.6608867 2013-10-25 06:00:00,71.99874820000002 2013-10-25 07:00:00,72.38400327 2013-10-25 08:00:00,72.51858237 2013-10-25 09:00:00,71.55343537 2013-10-25 10:00:00,72.55778642 2013-10-25 11:00:00,71.96670972 2013-10-25 12:00:00,72.36781957 2013-10-25 13:00:00,72.69666807 2013-10-25 14:00:00,72.75559541 2013-10-25 15:00:00,73.59062056 2013-10-25 16:00:00,73.17199341 2013-10-25 17:00:00,74.06972966 2013-10-25 18:00:00,74.49830916 2013-10-25 19:00:00,73.95696452 2013-10-25 20:00:00,73.63058672 2013-10-25 21:00:00,73.49661513 2013-10-25 22:00:00,75.0238628 2013-10-25 23:00:00,73.41067783 2013-10-26 00:00:00,74.43789627 2013-10-26 01:00:00,73.69728217 2013-10-26 02:00:00,72.79073013 2013-10-26 03:00:00,74.02303394 2013-10-26 04:00:00,73.99547327 2013-10-26 05:00:00,72.63698998 2013-10-26 06:00:00,72.65022647 2013-10-26 07:00:00,71.45778273 2013-10-26 08:00:00,73.30880143 2013-10-26 09:00:00,71.88486246 2013-10-26 10:00:00,72.3666265 2013-10-26 11:00:00,71.51972021 2013-10-26 12:00:00,71.73511359 2013-10-26 13:00:00,72.78641155 2013-10-26 14:00:00,71.38856419 2013-10-26 15:00:00,72.18526942 2013-10-26 16:00:00,73.51448987 2013-10-26 17:00:00,73.57199426 2013-10-26 18:00:00,72.91075318 2013-10-26 19:00:00,73.81514959 2013-10-26 20:00:00,72.68504592 2013-10-26 21:00:00,74.08911438 2013-10-26 22:00:00,72.9589277 2013-10-26 23:00:00,73.14610095 2013-10-27 00:00:00,73.78917147 2013-10-27 01:00:00,72.79764335 2013-10-27 02:00:00,73.85796513 2013-10-27 03:00:00,73.14750042 2013-10-27 04:00:00,73.68655845 2013-10-27 05:00:00,71.99772202 2013-10-27 06:00:00,71.98066434 2013-10-27 07:00:00,72.34138543 2013-10-27 08:00:00,72.73493389 2013-10-27 09:00:00,71.65669486 2013-10-27 10:00:00,71.49563964 2013-10-27 11:00:00,72.5480017 2013-10-27 12:00:00,71.57221259 2013-10-27 13:00:00,72.7741422 2013-10-27 14:00:00,72.50897204 2013-10-27 15:00:00,72.37165679 2013-10-27 16:00:00,71.76151786 2013-10-27 17:00:00,71.14297184 2013-10-27 18:00:00,71.17422664 2013-10-27 19:00:00,72.7253094 2013-10-27 20:00:00,71.85317981 2013-10-27 21:00:00,72.85663059 2013-10-27 22:00:00,71.76247182 2013-10-27 23:00:00,71.69635699999998 2013-10-28 00:00:00,70.92483713 2013-10-28 01:00:00,71.43725419 2013-10-28 02:00:00,72.13600699999998 2013-10-28 03:00:00,70.64687742 2013-10-28 04:00:00,70.22032111 2013-10-28 05:00:00,69.75235982 2013-10-28 06:00:00,71.33829611 2013-10-28 07:00:00,69.61769321 2013-10-28 08:00:00,70.75591875 2013-10-28 09:00:00,71.47646234 2013-10-28 10:00:00,71.59381864 2013-10-28 11:00:00,70.66816135 2013-10-28 12:00:00,73.12430398 2013-10-28 13:00:00,72.97024298 2013-10-28 14:00:00,73.74160859999998 2013-10-28 15:00:00,73.95406465 2013-10-28 16:00:00,73.45808119 2013-10-28 17:00:00,73.14484568 2013-10-28 18:00:00,74.48764885 2013-10-28 19:00:00,73.40434954 2013-10-28 20:00:00,73.32924842 2013-10-28 21:00:00,74.46460516 2013-10-28 22:00:00,74.68612326 2013-10-28 23:00:00,73.64400862 2013-10-29 00:00:00,73.05155138 2013-10-29 01:00:00,73.20917824 2013-10-29 02:00:00,72.9686264 2013-10-29 03:00:00,73.44971023 2013-10-29 04:00:00,73.55495921 2013-10-29 05:00:00,71.69592455 2013-10-29 06:00:00,73.53646843 2013-10-29 07:00:00,72.02971426 2013-10-29 08:00:00,73.42081575 2013-10-29 09:00:00,72.58490985 2013-10-29 10:00:00,73.0300541 2013-10-29 11:00:00,73.33546169 2013-10-29 12:00:00,73.69525708 2013-10-29 13:00:00,74.44248772 2013-10-29 14:00:00,73.36288859 2013-10-29 15:00:00,74.23441848 2013-10-29 16:00:00,73.53614618 2013-10-29 17:00:00,73.55358243 2013-10-29 18:00:00,73.31606619 2013-10-29 19:00:00,74.07121348 2013-10-29 20:00:00,73.84322808 2013-10-29 21:00:00,74.31880636 2013-10-29 22:00:00,75.37365059999998 2013-10-29 23:00:00,74.6158649 2013-10-30 00:00:00,74.22361987 2013-10-30 01:00:00,74.90183652 2013-10-30 02:00:00,74.60288205 2013-10-30 03:00:00,73.60468314 2013-10-30 04:00:00,74.41600686 2013-10-30 05:00:00,74.16088548 2013-10-30 06:00:00,72.84884222 2013-10-30 07:00:00,72.92107082 2013-10-30 08:00:00,73.01604281 2013-10-30 09:00:00,74.13143498 2013-10-30 10:00:00,72.57848043 2013-10-30 11:00:00,72.87188536 2013-10-30 12:00:00,73.61682058 2013-10-30 13:00:00,73.37016715 2013-10-30 14:00:00,74.04450691 2013-10-30 15:00:00,74.12361236 2013-10-30 16:00:00,74.66328477 2013-10-30 17:00:00,75.70737338 2013-10-30 18:00:00,75.3545802 2013-10-30 19:00:00,75.25614118 2013-10-30 20:00:00,74.87355721 2013-10-30 21:00:00,76.29745203 2013-10-30 22:00:00,75.32289320000002 2013-10-30 23:00:00,75.85634859999998 2013-10-31 00:00:00,75.14595644 2013-10-31 01:00:00,75.88962012 2013-10-31 02:00:00,76.4180307 2013-10-31 03:00:00,76.56197890000001 2013-10-31 04:00:00,76.10597378 2013-10-31 05:00:00,75.25141922 2013-10-31 06:00:00,75.72435817 2013-10-31 07:00:00,74.49878947 2013-10-31 08:00:00,75.84183322 2013-10-31 09:00:00,75.2866983 2013-10-31 10:00:00,74.87398102 2013-10-31 11:00:00,74.94194615 2013-10-31 12:00:00,75.98035652 2013-10-31 13:00:00,74.95842691 2013-10-31 14:00:00,75.24512346 2013-10-31 15:00:00,75.35692048 2013-10-31 16:00:00,76.88500697 2013-10-31 17:00:00,76.12766594 2013-10-31 18:00:00,75.86319296 2013-10-31 19:00:00,76.41346624 2013-10-31 20:00:00,75.5347714 2013-10-31 21:00:00,75.84580103 2013-10-31 22:00:00,76.34558396 2013-10-31 23:00:00,77.39292354 2013-11-01 00:00:00,76.30796353 2013-11-01 01:00:00,77.25259793 2013-11-01 02:00:00,76.43178992 2013-11-01 03:00:00,77.69772574 2013-11-01 04:00:00,76.53784364 2013-11-01 05:00:00,76.38649065 2013-11-01 06:00:00,77.20675318 2013-11-01 07:00:00,77.18738382 2013-11-01 08:00:00,75.67736243 2013-11-01 09:00:00,74.81300493 2013-11-01 10:00:00,75.83696911 2013-11-01 11:00:00,75.02326067 2013-11-01 12:00:00,75.05073943 2013-11-01 13:00:00,75.28745236 2013-11-01 14:00:00,75.20319345 2013-11-01 15:00:00,75.12528566 2013-11-01 16:00:00,75.19924971 2013-11-01 17:00:00,75.73098218 2013-11-01 18:00:00,75.93704108 2013-11-01 19:00:00,74.89355303 2013-11-01 20:00:00,75.07774926 2013-11-01 21:00:00,75.25618705 2013-11-01 22:00:00,75.71797654 2013-11-01 23:00:00,75.63395379 2013-11-02 00:00:00,75.48381386 2013-11-02 01:00:00,75.66762937 2013-11-02 02:00:00,76.51474357 2013-11-02 03:00:00,75.08953119 2013-11-02 04:00:00,75.81216694 2013-11-02 05:00:00,75.60610346 2013-11-02 06:00:00,74.96367140000002 2013-11-02 07:00:00,74.98121493 2013-11-02 08:00:00,74.45643905 2013-11-02 09:00:00,75.51516542 2013-11-02 10:00:00,74.73560812 2013-11-02 11:00:00,74.69915087 2013-11-02 12:00:00,74.54298971 2013-11-02 13:00:00,73.35219351 2013-11-02 14:00:00,74.12383795 2013-11-02 15:00:00,74.22554631 2013-11-02 16:00:00,73.99079534 2013-11-02 17:00:00,74.79507379 2013-11-02 18:00:00,76.11205116 2013-11-02 19:00:00,75.22593768 2013-11-02 20:00:00,75.27953666 2013-11-02 21:00:00,77.15937503 2013-11-02 22:00:00,76.19111223 2013-11-02 23:00:00,76.31079818 2013-11-03 00:00:00,76.38206634 2013-11-03 01:00:00,75.57825005 2013-11-03 02:00:00,76.13455079999999 2013-11-03 03:00:00,75.23603382 2013-11-03 04:00:00,76.23782807 2013-11-03 05:00:00,75.336605 2013-11-03 06:00:00,74.36531352 2013-11-03 07:00:00,73.71769524 2013-11-03 08:00:00,74.074138 2013-11-03 09:00:00,74.84189513 2013-11-03 10:00:00,73.95914727 2013-11-03 11:00:00,74.04130502 2013-11-03 12:00:00,74.56437617 2013-11-03 13:00:00,73.29808803 2013-11-03 14:00:00,73.53188681 2013-11-03 15:00:00,73.87759563 2013-11-03 16:00:00,74.87971926 2013-11-03 17:00:00,74.1892936 2013-11-03 18:00:00,75.41399344 2013-11-03 19:00:00,75.86744504 2013-11-03 20:00:00,75.6150603 2013-11-03 21:00:00,76.97153329 2013-11-03 22:00:00,77.0894334 2013-11-03 23:00:00,76.17299187 2013-11-04 00:00:00,75.60827582 2013-11-04 01:00:00,76.66746590000002 2013-11-04 02:00:00,76.59056219 2013-11-04 03:00:00,75.05998404 2013-11-04 04:00:00,75.88379996 2013-11-04 05:00:00,75.47865146 2013-11-04 06:00:00,74.4588194 2013-11-04 07:00:00,73.60738959 2013-11-04 08:00:00,74.41420743 2013-11-04 09:00:00,74.765766 2013-11-04 10:00:00,74.16291232 2013-11-04 11:00:00,74.19468656 2013-11-04 12:00:00,74.43225537 2013-11-04 13:00:00,74.24359177 2013-11-04 14:00:00,74.55720475 2013-11-04 15:00:00,75.76889616 2013-11-04 16:00:00,75.5197806 2013-11-04 17:00:00,74.72805694 2013-11-04 18:00:00,75.06364679 2013-11-04 19:00:00,75.92542961 2013-11-04 20:00:00,75.03438753 2013-11-04 21:00:00,75.53025670000002 2013-11-04 22:00:00,76.20838186 2013-11-04 23:00:00,75.88011467 2013-11-05 00:00:00,75.25305005 2013-11-05 01:00:00,76.16092035 2013-11-05 02:00:00,74.87732367 2013-11-05 03:00:00,75.70725229 2013-11-05 04:00:00,74.62446294 2013-11-05 05:00:00,73.93894725 2013-11-05 06:00:00,75.39833336 2013-11-05 07:00:00,73.67042395 2013-11-05 08:00:00,74.78394113 2013-11-05 09:00:00,75.36637593 2013-11-05 10:00:00,75.62678541 2013-11-05 11:00:00,75.54245470000002 2013-11-05 12:00:00,75.56486359 2013-11-05 13:00:00,75.40045594 2013-11-05 14:00:00,75.72241656 2013-11-05 15:00:00,75.38360735 2013-11-05 16:00:00,74.96366192 2013-11-05 17:00:00,75.15506847 2013-11-05 18:00:00,76.44462418 2013-11-05 19:00:00,76.14152676 2013-11-05 20:00:00,77.7365963 2013-11-05 21:00:00,75.94504175 2013-11-05 22:00:00,77.66560315 2013-11-05 23:00:00,77.14421695 2013-11-06 00:00:00,77.14840943 2013-11-06 01:00:00,76.57972961 2013-11-06 02:00:00,75.67263157 2013-11-06 03:00:00,75.55554775 2013-11-06 04:00:00,76.02875358 2013-11-06 05:00:00,75.83856917 2013-11-06 06:00:00,76.72809013 2013-11-06 07:00:00,76.8067863 2013-11-06 08:00:00,76.14957763 2013-11-06 09:00:00,74.72851186 2013-11-06 10:00:00,76.79427945 2013-11-06 11:00:00,75.54402995 2013-11-06 12:00:00,75.62375922 2013-11-06 13:00:00,75.66503039 2013-11-06 14:00:00,76.1298699 2013-11-06 15:00:00,75.2965713 2013-11-06 16:00:00,75.65848549 2013-11-06 17:00:00,75.77541647 2013-11-06 18:00:00,75.7226112 2013-11-06 19:00:00,75.17457270000001 2013-11-06 20:00:00,76.75484571 2013-11-06 21:00:00,76.17423765 2013-11-06 22:00:00,76.11021976 2013-11-06 23:00:00,77.62413958 2013-11-07 00:00:00,76.47954412 2013-11-07 01:00:00,77.95666612 2013-11-07 02:00:00,77.26824525 2013-11-07 03:00:00,76.93680905 2013-11-07 04:00:00,77.33274264 2013-11-07 05:00:00,75.89490524 2013-11-07 06:00:00,76.97245983 2013-11-07 07:00:00,76.44928327 2013-11-07 08:00:00,76.38799696 2013-11-07 09:00:00,76.09948105 2013-11-07 10:00:00,76.81359962 2013-11-07 11:00:00,75.10202225 2013-11-07 12:00:00,75.6896651 2013-11-07 13:00:00,76.31908661 2013-11-07 14:00:00,76.23526528 2013-11-07 15:00:00,75.71330856 2013-11-07 16:00:00,75.27910715 2013-11-07 17:00:00,75.6502543 2013-11-07 18:00:00,76.21250234 2013-11-07 19:00:00,77.10759799 2013-11-07 20:00:00,76.93375995 2013-11-07 21:00:00,75.77571222 2013-11-07 22:00:00,75.93642846 2013-11-07 23:00:00,75.42451794 2013-11-08 00:00:00,75.74984119 2013-11-08 01:00:00,75.72379288 2013-11-08 02:00:00,76.19812769 2013-11-08 03:00:00,76.40959723 2013-11-08 04:00:00,76.17249971 2013-11-08 05:00:00,74.18157735 2013-11-08 06:00:00,75.54911204 2013-11-08 07:00:00,74.92685622 2013-11-08 08:00:00,74.06821774 2013-11-08 09:00:00,74.6063132 2013-11-08 10:00:00,74.59934737 2013-11-08 11:00:00,74.57257027 2013-11-08 12:00:00,75.80192985 2013-11-08 13:00:00,75.58576634 2013-11-08 14:00:00,75.80339835 2013-11-08 15:00:00,74.95083817 2013-11-08 16:00:00,74.30202352 2013-11-08 17:00:00,74.30126215 2013-11-08 18:00:00,74.56143904 2013-11-08 19:00:00,74.80702056 2013-11-08 20:00:00,73.81540339 2013-11-08 21:00:00,74.46177933 2013-11-08 22:00:00,73.33340389 2013-11-08 23:00:00,73.13844142 2013-11-09 00:00:00,74.43327812 2013-11-09 01:00:00,73.55423309999998 2013-11-09 02:00:00,74.72110603 2013-11-09 03:00:00,73.50877487 2013-11-09 04:00:00,74.83946496 2013-11-09 05:00:00,73.55614636 2013-11-09 06:00:00,73.07126074 2013-11-09 07:00:00,72.82584529 2013-11-09 08:00:00,72.95550534 2013-11-09 09:00:00,73.64826422 2013-11-09 10:00:00,73.4784976 2013-11-09 11:00:00,73.16790935 2013-11-09 12:00:00,72.25990891 2013-11-09 13:00:00,73.22695232 2013-11-09 14:00:00,73.36574509999998 2013-11-09 15:00:00,72.78698119 2013-11-09 16:00:00,73.23132790000003 2013-11-09 17:00:00,73.06305918 2013-11-09 18:00:00,73.23528333 2013-11-09 19:00:00,73.95548531 2013-11-09 20:00:00,73.98859537 2013-11-09 21:00:00,73.18927798 2013-11-09 22:00:00,73.48796428 2013-11-09 23:00:00,73.23741435 2013-11-10 00:00:00,74.54367695 2013-11-10 01:00:00,73.43081550000002 2013-11-10 02:00:00,74.74891586 2013-11-10 03:00:00,74.75362909 2013-11-10 04:00:00,72.86175442 2013-11-10 05:00:00,72.73720269 2013-11-10 06:00:00,73.3559507 2013-11-10 07:00:00,73.39759537 2013-11-10 08:00:00,73.14595598 2013-11-10 09:00:00,73.76092178 2013-11-10 10:00:00,72.25168702 2013-11-10 11:00:00,73.13205651 2013-11-10 12:00:00,72.08360267 2013-11-10 13:00:00,72.07368375 2013-11-10 14:00:00,72.61268471 2013-11-10 15:00:00,73.72321874 2013-11-10 16:00:00,73.72849169 2013-11-10 17:00:00,73.13296089 2013-11-10 18:00:00,72.65494358 2013-11-10 19:00:00,72.32299088 2013-11-10 20:00:00,73.55015881 2013-11-10 21:00:00,73.72223486 2013-11-10 22:00:00,72.25297108 2013-11-10 23:00:00,72.31541006 2013-11-11 00:00:00,72.76195068 2013-11-11 01:00:00,73.76142519 2013-11-11 02:00:00,73.10583663 2013-11-11 03:00:00,73.50193935 2013-11-11 04:00:00,73.49132918 2013-11-11 05:00:00,72.41669997 2013-11-11 06:00:00,73.04263579 2013-11-11 07:00:00,72.31388627 2013-11-11 08:00:00,71.53125555 2013-11-11 09:00:00,72.51297974 2013-11-11 10:00:00,73.05072318 2013-11-11 11:00:00,72.93039079 2013-11-11 12:00:00,72.68112696 2013-11-11 13:00:00,74.10651227 2013-11-11 14:00:00,73.20678582 2013-11-11 15:00:00,73.97883407 2013-11-11 16:00:00,74.29101178 2013-11-11 17:00:00,75.92300396 2013-11-11 18:00:00,75.09551863 2013-11-11 19:00:00,74.50642676 2013-11-11 20:00:00,75.29868809 2013-11-11 21:00:00,74.81087057 2013-11-11 22:00:00,75.04623283 2013-11-11 23:00:00,75.27267490000001 2013-11-12 00:00:00,74.35723061 2013-11-12 01:00:00,75.59912555 2013-11-12 02:00:00,75.38508019 2013-11-12 03:00:00,74.01849770000003 2013-11-12 04:00:00,74.67643353 2013-11-12 05:00:00,74.23187951 2013-11-12 06:00:00,73.23464912 2013-11-12 07:00:00,72.9246375 2013-11-12 08:00:00,73.50042577 2013-11-12 09:00:00,73.9103724 2013-11-12 10:00:00,73.36473041 2013-11-12 11:00:00,74.56847369 2013-11-12 12:00:00,73.01626683 2013-11-12 13:00:00,74.58986064 2013-11-12 14:00:00,74.79361415 2013-11-12 15:00:00,74.62816075 2013-11-12 16:00:00,73.48499084 2013-11-12 17:00:00,74.83572629999998 2013-11-12 18:00:00,75.71863379 2013-11-12 19:00:00,74.10748463 2013-11-12 20:00:00,76.18679389 2013-11-12 21:00:00,75.68515368 2013-11-12 22:00:00,75.95116314 2013-11-12 23:00:00,75.27091748 2013-11-13 00:00:00,75.10698746 2013-11-13 01:00:00,75.50230648 2013-11-13 02:00:00,74.96947424 2013-11-13 03:00:00,74.66135819 2013-11-13 04:00:00,74.16500932 2013-11-13 05:00:00,73.61945248 2013-11-13 06:00:00,73.04705436 2013-11-13 07:00:00,73.10898413 2013-11-13 08:00:00,73.14571961 2013-11-13 09:00:00,73.13454489 2013-11-13 10:00:00,73.63776206 2013-11-13 11:00:00,72.51683568 2013-11-13 12:00:00,74.15631949 2013-11-13 13:00:00,73.16933890000001 2013-11-13 14:00:00,74.42966035 2013-11-13 15:00:00,73.93593742 2013-11-13 16:00:00,74.0165059 2013-11-13 17:00:00,75.64136409999998 2013-11-13 18:00:00,75.49191161 2013-11-13 19:00:00,74.71810201 2013-11-13 20:00:00,75.30978555 2013-11-13 21:00:00,75.66631972 2013-11-13 22:00:00,76.3113897 2013-11-13 23:00:00,75.93818590000002 2013-11-14 00:00:00,75.28806128 2013-11-14 01:00:00,74.04154576 2013-11-14 02:00:00,75.03847755 2013-11-14 03:00:00,74.23765297 2013-11-14 04:00:00,74.41627738 2013-11-14 05:00:00,72.52116762 2013-11-14 06:00:00,72.25396537 2013-11-14 07:00:00,73.35919816 2013-11-14 08:00:00,73.3005709 2013-11-14 09:00:00,71.94989116 2013-11-14 10:00:00,72.70754191 2013-11-14 11:00:00,73.57919806 2013-11-14 12:00:00,73.71447163 2013-11-14 13:00:00,73.20962568 2013-11-14 14:00:00,73.60901764 2013-11-14 15:00:00,73.39056823 2013-11-14 16:00:00,74.84991329 2013-11-14 17:00:00,75.29117938 2013-11-14 18:00:00,75.05266772 2013-11-14 19:00:00,73.87313966 2013-11-14 20:00:00,73.88685052 2013-11-14 21:00:00,75.32457686 2013-11-14 22:00:00,74.52795985 2013-11-14 23:00:00,74.50517038 2013-11-15 00:00:00,75.28019509999999 2013-11-15 01:00:00,73.39054569 2013-11-15 02:00:00,73.61502322 2013-11-15 03:00:00,73.40129594 2013-11-15 04:00:00,72.71904624 2013-11-15 05:00:00,73.04163914 2013-11-15 06:00:00,71.66850691 2013-11-15 07:00:00,72.44293549 2013-11-15 08:00:00,72.77424531 2013-11-15 09:00:00,71.02651442 2013-11-15 10:00:00,72.46122501 2013-11-15 11:00:00,72.053069 2013-11-15 12:00:00,71.43164940000003 2013-11-15 13:00:00,73.5399011 2013-11-15 14:00:00,73.32159625 2013-11-15 15:00:00,74.17128378 2013-11-15 16:00:00,73.44249817 2013-11-15 17:00:00,73.84389329999998 2013-11-15 18:00:00,74.32478195 2013-11-15 19:00:00,74.33059913 2013-11-15 20:00:00,74.50938842 2013-11-15 21:00:00,74.18876225 2013-11-15 22:00:00,73.26010958 2013-11-15 23:00:00,72.71542581 2013-11-16 00:00:00,72.91699629 2013-11-16 01:00:00,72.72921375 2013-11-16 02:00:00,72.00496338 2013-11-16 03:00:00,72.91473652 2013-11-16 04:00:00,72.22070042 2013-11-16 05:00:00,72.19057869 2013-11-16 06:00:00,72.75354149 2013-11-16 07:00:00,70.85140062 2013-11-16 08:00:00,72.60434778 2013-11-16 09:00:00,72.2513124 2013-11-16 10:00:00,72.44304869 2013-11-16 11:00:00,71.82902242 2013-11-16 12:00:00,72.13432831 2013-11-16 13:00:00,72.28302117 2013-11-16 14:00:00,70.87841589 2013-11-16 15:00:00,70.5596423 2013-11-16 16:00:00,71.49929374 2013-11-16 17:00:00,70.91004612 2013-11-16 18:00:00,71.52840484 2013-11-16 19:00:00,71.62859496 2013-11-16 20:00:00,72.74468133 2013-11-16 21:00:00,71.59071961 2013-11-16 22:00:00,72.53877392 2013-11-16 23:00:00,72.67710054 2013-11-17 00:00:00,72.51924339 2013-11-17 01:00:00,72.53149628 2013-11-17 02:00:00,71.57898299 2013-11-17 03:00:00,72.42367877 2013-11-17 04:00:00,71.48775583 2013-11-17 05:00:00,71.06116079 2013-11-17 06:00:00,70.32136308 2013-11-17 07:00:00,71.8799218 2013-11-17 08:00:00,72.01945706 2013-11-17 09:00:00,71.02801335 2013-11-17 10:00:00,70.32011267 2013-11-17 11:00:00,70.43736052 2013-11-17 12:00:00,70.71326074 2013-11-17 13:00:00,71.29496969 2013-11-17 14:00:00,71.19238211 2013-11-17 15:00:00,70.76197992 2013-11-17 16:00:00,71.97783594 2013-11-17 17:00:00,71.93428932 2013-11-17 18:00:00,70.92727189 2013-11-17 19:00:00,70.69309796 2013-11-17 20:00:00,72.26337995 2013-11-17 21:00:00,71.59257385 2013-11-17 22:00:00,72.78595446 2013-11-17 23:00:00,72.51893435 2013-11-18 00:00:00,71.86984301 2013-11-18 01:00:00,72.26094927 2013-11-18 02:00:00,71.49387364 2013-11-18 03:00:00,71.34440084 2013-11-18 04:00:00,71.45222531 2013-11-18 05:00:00,71.07687116 2013-11-18 06:00:00,70.85817442 2013-11-18 07:00:00,70.94781553 2013-11-18 08:00:00,70.27853073 2013-11-18 09:00:00,69.32489169 2013-11-18 10:00:00,70.20579203 2013-11-18 11:00:00,70.38921093 2013-11-18 12:00:00,71.97995521 2013-11-18 13:00:00,71.09700465 2013-11-18 14:00:00,73.01321007 2013-11-18 15:00:00,72.74733169 2013-11-18 16:00:00,72.53910037 2013-11-18 17:00:00,73.35960207 2013-11-18 18:00:00,72.84142418 2013-11-18 19:00:00,74.43420638 2013-11-18 20:00:00,74.6164561 2013-11-18 21:00:00,74.22528903 2013-11-18 22:00:00,74.42442215 2013-11-18 23:00:00,73.14775012 2013-11-19 00:00:00,73.69107041 2013-11-19 01:00:00,74.03109935 2013-11-19 02:00:00,73.46135999 2013-11-19 03:00:00,72.49412233 2013-11-19 04:00:00,73.09658152 2013-11-19 05:00:00,73.46536527 2013-11-19 06:00:00,72.80605916 2013-11-19 07:00:00,71.59932742 2013-11-19 08:00:00,72.73375635 2013-11-19 09:00:00,73.27079545 2013-11-19 10:00:00,72.32538482 2013-11-19 11:00:00,71.96557762 2013-11-19 12:00:00,72.50861543 2013-11-19 13:00:00,72.20848244 2013-11-19 14:00:00,73.98532747 2013-11-19 15:00:00,73.77910642 2013-11-19 16:00:00,73.74309124 2013-11-19 17:00:00,75.62033656 2013-11-19 18:00:00,75.92989871 2013-11-19 19:00:00,76.14345589 2013-11-19 20:00:00,75.62712477 2013-11-19 21:00:00,76.09385992 2013-11-19 22:00:00,76.71081637 2013-11-19 23:00:00,76.04933698 2013-11-20 00:00:00,75.72755913 2013-11-20 01:00:00,75.51638547 2013-11-20 02:00:00,74.52746945 2013-11-20 03:00:00,74.48053719 2013-11-20 04:00:00,75.44810401 2013-11-20 05:00:00,73.87105555 2013-11-20 06:00:00,75.52376743 2013-11-20 07:00:00,73.59258353 2013-11-20 08:00:00,73.54086694 2013-11-20 09:00:00,74.60328237 2013-11-20 10:00:00,73.53405054 2013-11-20 11:00:00,73.18585771 2013-11-20 12:00:00,74.73396876 2013-11-20 13:00:00,74.00301199 2013-11-20 14:00:00,74.25992091 2013-11-20 15:00:00,75.3819048 2013-11-20 16:00:00,74.89925956 2013-11-20 17:00:00,74.95695549 2013-11-20 18:00:00,74.99328121 2013-11-20 19:00:00,76.8861063 2013-11-20 20:00:00,75.74120031 2013-11-20 21:00:00,77.29515004 2013-11-20 22:00:00,77.42615583 2013-11-20 23:00:00,77.57042544 2013-11-21 00:00:00,76.97148499 2013-11-21 01:00:00,76.55304852 2013-11-21 02:00:00,76.83218408 2013-11-21 03:00:00,76.76691174 2013-11-21 04:00:00,75.03003109 2013-11-21 05:00:00,76.13262453 2013-11-21 06:00:00,74.88298612 2013-11-21 07:00:00,74.75528879999997 2013-11-21 08:00:00,74.96824419 2013-11-21 09:00:00,74.38032373 2013-11-21 10:00:00,74.51502775 2013-11-21 11:00:00,75.03807231 2013-11-21 12:00:00,75.47315484 2013-11-21 13:00:00,74.28147702 2013-11-21 14:00:00,74.9158214 2013-11-21 15:00:00,74.73332116 2013-11-21 16:00:00,74.57659907 2013-11-21 17:00:00,75.13741621 2013-11-21 18:00:00,76.09123393 2013-11-21 19:00:00,75.48996689 2013-11-21 20:00:00,75.37277558 2013-11-21 21:00:00,74.86375645 2013-11-21 22:00:00,74.72416427 2013-11-21 23:00:00,75.88303251 2013-11-22 00:00:00,76.26881945 2013-11-22 01:00:00,74.40797403 2013-11-22 02:00:00,75.07100534 2013-11-22 03:00:00,75.22936273 2013-11-22 04:00:00,75.3850351 2013-11-22 05:00:00,74.12951939 2013-11-22 06:00:00,74.33830078 2013-11-22 07:00:00,73.13110340000001 2013-11-22 08:00:00,73.72892540000002 2013-11-22 09:00:00,73.47971521 2013-11-22 10:00:00,73.55503441 2013-11-22 11:00:00,73.21770574 2013-11-22 12:00:00,74.8002409 2013-11-22 13:00:00,75.10424352 2013-11-22 14:00:00,74.02504086 2013-11-22 15:00:00,75.99705923 2013-11-22 16:00:00,76.14728499 2013-11-22 17:00:00,75.97342391 2013-11-22 18:00:00,74.55135899 2013-11-22 19:00:00,75.52513628 2013-11-22 20:00:00,74.83841776 2013-11-22 21:00:00,75.86804316 2013-11-22 22:00:00,74.78322701 2013-11-22 23:00:00,74.93730171 2013-11-23 00:00:00,75.99533878 2013-11-23 01:00:00,74.9811996 2013-11-23 02:00:00,74.90004537 2013-11-23 03:00:00,74.45881512 2013-11-23 04:00:00,74.98859321 2013-11-23 05:00:00,74.80551896 2013-11-23 06:00:00,74.37725744 2013-11-23 07:00:00,73.23877045 2013-11-23 08:00:00,74.57228705 2013-11-23 09:00:00,73.61937989 2013-11-23 10:00:00,73.62510552 2013-11-23 11:00:00,73.89538449 2013-11-23 12:00:00,73.97705688 2013-11-23 13:00:00,73.49598319 2013-11-23 14:00:00,74.480482 2013-11-23 15:00:00,74.05324671 2013-11-23 16:00:00,72.99508362 2013-11-23 17:00:00,74.06252472 2013-11-23 18:00:00,74.31310832 2013-11-23 19:00:00,73.86600895 2013-11-23 20:00:00,74.72618679 2013-11-23 21:00:00,74.87409105 2013-11-23 22:00:00,75.16150552 2013-11-23 23:00:00,75.24524494 2013-11-24 00:00:00,76.06110472 2013-11-24 01:00:00,76.04876445 2013-11-24 02:00:00,75.92643826 2013-11-24 03:00:00,75.30896496 2013-11-24 04:00:00,73.85862031 2013-11-24 05:00:00,74.35243191 2013-11-24 06:00:00,73.22576335 2013-11-24 07:00:00,73.89709736 2013-11-24 08:00:00,73.45107827 2013-11-24 09:00:00,74.28662864 2013-11-24 10:00:00,73.11935916 2013-11-24 11:00:00,73.61847392 2013-11-24 12:00:00,73.95085216 2013-11-24 13:00:00,73.81302278 2013-11-24 14:00:00,74.47090026 2013-11-24 15:00:00,73.99949512 2013-11-24 16:00:00,74.01073568 2013-11-24 17:00:00,74.48269327 2013-11-24 18:00:00,74.99975789 2013-11-24 19:00:00,75.51838405 2013-11-24 20:00:00,74.91884001 2013-11-24 21:00:00,76.19947972 2013-11-24 22:00:00,76.37182291 2013-11-24 23:00:00,75.88886956 2013-11-25 00:00:00,75.8200126 2013-11-25 01:00:00,75.09124497 2013-11-25 02:00:00,76.15627384 2013-11-25 03:00:00,74.91899343 2013-11-25 04:00:00,74.96455081 2013-11-25 05:00:00,73.92706103 2013-11-25 06:00:00,74.79903613 2013-11-25 07:00:00,73.3751018 2013-11-25 08:00:00,73.59611961 2013-11-25 09:00:00,73.62927662 2013-11-25 10:00:00,74.00708949 2013-11-25 11:00:00,73.65766251 2013-11-25 12:00:00,75.03306974 2013-11-25 13:00:00,75.04645886 2013-11-25 14:00:00,75.24681613 2013-11-25 15:00:00,75.70692895 2013-11-25 16:00:00,74.67360854 2013-11-25 17:00:00,74.61358909 2013-11-25 18:00:00,74.491203 2013-11-25 19:00:00,76.12426881 2013-11-25 20:00:00,76.37678862 2013-11-25 21:00:00,76.92387133 2013-11-25 22:00:00,75.33838879 2013-11-25 23:00:00,75.99550579 2013-11-26 00:00:00,76.69138228 2013-11-26 01:00:00,75.88567453 2013-11-26 02:00:00,75.76685516 2013-11-26 03:00:00,75.37412724 2013-11-26 04:00:00,76.68765753 2013-11-26 05:00:00,74.51443263 2013-11-26 06:00:00,74.81803517 2013-11-26 07:00:00,75.98462212 2013-11-26 08:00:00,75.47773677 2013-11-26 09:00:00,73.83422894 2013-11-26 10:00:00,74.80800635 2013-11-26 11:00:00,74.2813275 2013-11-26 12:00:00,75.90857214 2013-11-26 13:00:00,75.58094376 2013-11-26 14:00:00,75.38129562 2013-11-26 15:00:00,75.16651189 2013-11-26 16:00:00,75.93238329 2013-11-26 17:00:00,74.27644123 2013-11-26 18:00:00,74.14545793 2013-11-26 19:00:00,74.83272443 2013-11-26 20:00:00,75.96087554 2013-11-26 21:00:00,76.77265319 2013-11-26 22:00:00,77.00068715 2013-11-26 23:00:00,77.15745947 2013-11-27 00:00:00,77.15974376 2013-11-27 01:00:00,76.69033706 2013-11-27 02:00:00,76.17756923 2013-11-27 03:00:00,77.24837065 2013-11-27 04:00:00,77.35430618 2013-11-27 05:00:00,77.55637201 2013-11-27 06:00:00,77.11772453 2013-11-27 07:00:00,76.16169102 2013-11-27 08:00:00,76.13252582 2013-11-27 09:00:00,76.22151059999999 2013-11-27 10:00:00,74.98788383 2013-11-27 11:00:00,75.70819313 2013-11-27 12:00:00,75.28208686 2013-11-27 13:00:00,75.58863441 2013-11-27 14:00:00,76.04015957 2013-11-27 15:00:00,76.30194796 2013-11-27 16:00:00,76.25516001 2013-11-27 17:00:00,74.8667481 2013-11-27 18:00:00,75.62370485 2013-11-27 19:00:00,74.98800103 2013-11-27 20:00:00,76.56855175 2013-11-27 21:00:00,76.20402117 2013-11-27 22:00:00,76.04503464 2013-11-27 23:00:00,78.00863821 2013-11-28 00:00:00,77.16791565 2013-11-28 01:00:00,77.47286351 2013-11-28 02:00:00,78.34299712 2013-11-28 03:00:00,77.23397943 2013-11-28 04:00:00,78.33064076 2013-11-28 05:00:00,77.74235688 2013-11-28 06:00:00,76.90841346 2013-11-28 07:00:00,78.19122395 2013-11-28 08:00:00,77.11531177 2013-11-28 09:00:00,76.19078959 2013-11-28 10:00:00,75.89108336 2013-11-28 11:00:00,74.91135143 2013-11-28 12:00:00,76.05428041 2013-11-28 13:00:00,74.98413324 2013-11-28 14:00:00,76.71790748 2013-11-28 15:00:00,76.87780803 2013-11-28 16:00:00,75.59376618 2013-11-28 17:00:00,75.42355277 2013-11-28 18:00:00,76.12701487 2013-11-28 19:00:00,76.85731503 2013-11-28 20:00:00,76.36303141 2013-11-28 21:00:00,75.84007067 2013-11-28 22:00:00,76.46922703 2013-11-28 23:00:00,76.80884417 2013-11-29 00:00:00,79.02591263 2013-11-29 01:00:00,78.20757005 2013-11-29 02:00:00,78.47792298 2013-11-29 03:00:00,79.23633448 2013-11-29 04:00:00,78.88770756 2013-11-29 05:00:00,78.8953397 2013-11-29 06:00:00,78.876609 2013-11-29 07:00:00,77.56230513 2013-11-29 08:00:00,76.59404839 2013-11-29 09:00:00,76.94499489 2013-11-29 10:00:00,78.49555784 2013-11-29 11:00:00,76.94027286 2013-11-29 12:00:00,77.88769599 2013-11-29 13:00:00,77.17967275 2013-11-29 14:00:00,77.53951629 2013-11-29 15:00:00,76.83583058 2013-11-29 16:00:00,77.38018752 2013-11-29 17:00:00,78.10468211 2013-11-29 18:00:00,77.14646568 2013-11-29 19:00:00,76.97117206 2013-11-29 20:00:00,77.84318487 2013-11-29 21:00:00,76.66135240000001 2013-11-29 22:00:00,78.15703794 2013-11-29 23:00:00,77.46965922 2013-11-30 00:00:00,77.88460537 2013-11-30 01:00:00,77.65864458 2013-11-30 02:00:00,78.70593097 2013-11-30 03:00:00,78.50094859 2013-11-30 04:00:00,77.02001536 2013-11-30 05:00:00,78.09143757 2013-11-30 06:00:00,76.72362831 2013-11-30 07:00:00,76.45580209 2013-11-30 08:00:00,77.02544955 2013-11-30 09:00:00,78.11045131 2013-11-30 10:00:00,76.35997079 2013-11-30 11:00:00,76.89472925 2013-11-30 12:00:00,77.04274751 2013-11-30 13:00:00,77.94149348 2013-11-30 14:00:00,77.75067472 2013-11-30 15:00:00,77.55710197 2013-11-30 16:00:00,76.86340194 2013-11-30 17:00:00,78.53850778 2013-11-30 18:00:00,78.37908378 2013-11-30 19:00:00,78.81008775 2013-11-30 20:00:00,77.73485863 2013-11-30 21:00:00,77.83555944 2013-11-30 22:00:00,78.56664962 2013-11-30 23:00:00,78.4432628 2013-12-01 00:00:00,78.58726082 2013-12-01 01:00:00,77.53521019 2013-12-01 02:00:00,77.63065448 2013-12-01 03:00:00,78.12865125 2013-12-01 04:00:00,77.86603288 2013-12-01 05:00:00,77.44856207 2013-12-01 06:00:00,76.98370721 2013-12-01 07:00:00,75.4790699 2013-12-01 08:00:00,75.33305301 2013-12-01 09:00:00,75.89776898 2013-12-01 10:00:00,76.60147615 2013-12-01 11:00:00,74.71098020000002 2013-12-01 12:00:00,75.3552543 2013-12-01 13:00:00,74.87224431 2013-12-01 14:00:00,75.9791723 2013-12-01 15:00:00,75.47730656 2013-12-01 16:00:00,75.2003445 2013-12-01 17:00:00,76.27953207 2013-12-01 18:00:00,76.45168292 2013-12-01 19:00:00,76.07015052 2013-12-01 20:00:00,75.73563349999998 2013-12-01 21:00:00,77.0986277 2013-12-01 22:00:00,76.35243379 2013-12-01 23:00:00,76.91635076 2013-12-02 00:00:00,75.41786731 2013-12-02 01:00:00,76.54536726 2013-12-02 02:00:00,75.59756303 2013-12-02 03:00:00,74.89586951 2013-12-02 04:00:00,75.43229909 2013-12-02 05:00:00,74.50186087 2013-12-02 06:00:00,74.80732462 2013-12-02 07:00:00,73.08595318 2013-12-02 08:00:00,73.80861958 2013-12-02 09:00:00,73.38120847 2013-12-02 10:00:00,74.42042248 2013-12-02 11:00:00,75.53513849 2013-12-02 12:00:00,75.09092686 2013-12-02 13:00:00,75.56936508 2013-12-02 14:00:00,74.90652388 2013-12-02 15:00:00,74.082068 2013-12-02 16:00:00,75.77601988 2013-12-02 17:00:00,74.20052806 2013-12-02 18:00:00,75.23398924 2013-12-02 19:00:00,74.67382574 2013-12-02 20:00:00,74.65542741 2013-12-02 21:00:00,74.67489567 2013-12-02 22:00:00,74.8350368 2013-12-02 23:00:00,76.08893067 2013-12-03 00:00:00,75.15278013 2013-12-03 01:00:00,75.02923911 2013-12-03 02:00:00,75.85895688 2013-12-03 03:00:00,74.36103377 2013-12-03 04:00:00,75.5156958 2013-12-03 05:00:00,74.70868339 2013-12-03 06:00:00,73.83262026 2013-12-03 07:00:00,73.70124329 2013-12-03 08:00:00,73.63678504 2013-12-03 09:00:00,73.41637369 2013-12-03 10:00:00,73.80197277 2013-12-03 11:00:00,73.97767514 2013-12-03 12:00:00,74.83469243 2013-12-03 13:00:00,74.97139121 2013-12-03 14:00:00,73.77486044 2013-12-03 15:00:00,75.13503163 2013-12-03 16:00:00,73.87999867 2013-12-03 17:00:00,75.77548486 2013-12-03 18:00:00,75.01213492 2013-12-03 19:00:00,75.50478063 2013-12-03 20:00:00,76.25258396 2013-12-03 21:00:00,75.71050611 2013-12-03 22:00:00,77.20657998 2013-12-03 23:00:00,77.30399661 2013-12-04 00:00:00,75.91202374 2013-12-04 01:00:00,76.66853953 2013-12-04 02:00:00,75.74567822 2013-12-04 03:00:00,75.19938463 2013-12-04 04:00:00,76.19384417 2013-12-04 05:00:00,76.09302338 2013-12-04 06:00:00,76.04003915 2013-12-04 07:00:00,75.29326815 2013-12-04 08:00:00,74.21052551 2013-12-04 09:00:00,75.1991017 2013-12-04 10:00:00,74.06782191 2013-12-04 11:00:00,75.64687089 2013-12-04 12:00:00,74.70819726 2013-12-04 13:00:00,75.45305517 2013-12-04 14:00:00,74.00072839 2013-12-04 15:00:00,74.0555797 2013-12-04 16:00:00,74.61075053 2013-12-04 17:00:00,75.33297088 2013-12-04 18:00:00,75.94712761 2013-12-04 19:00:00,75.58518275 2013-12-04 20:00:00,76.02023976 2013-12-04 21:00:00,76.59701799 2013-12-04 22:00:00,76.96921944 2013-12-04 23:00:00,77.22393149 2013-12-05 00:00:00,75.97207085 2013-12-05 01:00:00,77.39107002 2013-12-05 02:00:00,76.84450656 2013-12-05 03:00:00,77.41677019 2013-12-05 04:00:00,75.98938319 2013-12-05 05:00:00,76.6635247 2013-12-05 06:00:00,75.44756559999998 2013-12-05 07:00:00,76.21819272 2013-12-05 08:00:00,76.32008979 2013-12-05 09:00:00,74.9409507 2013-12-05 10:00:00,75.4784256 2013-12-05 11:00:00,75.17090954 2013-12-05 12:00:00,74.29941509 2013-12-05 13:00:00,74.3062439 2013-12-05 14:00:00,75.90126283 2013-12-05 15:00:00,75.04716769 2013-12-05 16:00:00,75.58599677 2013-12-05 17:00:00,74.87807236 2013-12-05 18:00:00,75.27313151 2013-12-05 19:00:00,76.48370315 2013-12-05 20:00:00,75.50998007 2013-12-05 21:00:00,76.75086745 2013-12-05 22:00:00,76.68483447 2013-12-05 23:00:00,77.38495142 2013-12-06 00:00:00,75.87360168 2013-12-06 01:00:00,77.6556306 2013-12-06 02:00:00,76.42670507 2013-12-06 03:00:00,75.71056203 2013-12-06 04:00:00,75.06068153 2013-12-06 05:00:00,76.10503754 2013-12-06 06:00:00,75.62420413 2013-12-06 07:00:00,76.08456044 2013-12-06 08:00:00,75.29375586 2013-12-06 09:00:00,74.80440567 2013-12-06 10:00:00,75.19512835 2013-12-06 11:00:00,76.00205619 2013-12-06 12:00:00,74.52998721 2013-12-06 13:00:00,74.90420227 2013-12-06 14:00:00,74.16669948 2013-12-06 15:00:00,73.80445232 2013-12-06 16:00:00,74.47552074 2013-12-06 17:00:00,75.30827578 2013-12-06 18:00:00,75.03218705 2013-12-06 19:00:00,76.23218309999999 2013-12-06 20:00:00,75.6839157 2013-12-06 21:00:00,74.92143663 2013-12-06 22:00:00,76.87342138 2013-12-06 23:00:00,76.59855258 2013-12-07 00:00:00,75.33861432 2013-12-07 01:00:00,75.45218311 2013-12-07 02:00:00,76.06290495 2013-12-07 03:00:00,74.9575668 2013-12-07 04:00:00,76.00917564 2013-12-07 05:00:00,75.8543825 2013-12-07 06:00:00,75.27205469 2013-12-07 07:00:00,75.31174871 2013-12-07 08:00:00,74.68013979999998 2013-12-07 09:00:00,74.82785613 2013-12-07 10:00:00,74.52306854 2013-12-07 11:00:00,74.15590675 2013-12-07 12:00:00,75.10514663 2013-12-07 13:00:00,74.7545796 2013-12-07 14:00:00,74.52277912 2013-12-07 15:00:00,75.82423762 2013-12-07 16:00:00,74.22414092 2013-12-07 17:00:00,75.46409745 2013-12-07 18:00:00,76.33578873 2013-12-07 19:00:00,76.79710999 2013-12-07 20:00:00,75.93536531 2013-12-07 21:00:00,75.56283028 2013-12-07 22:00:00,77.20560211 2013-12-07 23:00:00,76.87039405 2013-12-08 00:00:00,75.44604893 2013-12-08 01:00:00,76.57429989 2013-12-08 02:00:00,76.06483199 2013-12-08 03:00:00,76.00964555 2013-12-08 04:00:00,74.80675596 2013-12-08 05:00:00,75.1980522 2013-12-08 06:00:00,76.07994366 2013-12-08 07:00:00,74.76370837 2013-12-08 08:00:00,74.52201927 2013-12-08 09:00:00,74.64224735 2013-12-08 10:00:00,75.14042076 2013-12-08 11:00:00,74.36953798 2013-12-08 12:00:00,75.37965099 2013-12-08 13:00:00,74.93759126 2013-12-08 14:00:00,74.37191177 2013-12-08 15:00:00,74.73159262 2013-12-08 16:00:00,75.61318422 2013-12-08 17:00:00,74.40147509 2013-12-08 18:00:00,76.13732359999999 2013-12-08 19:00:00,74.9962055 2013-12-08 20:00:00,75.54659614 2013-12-08 21:00:00,75.26882561 2013-12-08 22:00:00,74.39856404 2013-12-08 23:00:00,74.28786598 2013-12-09 00:00:00,75.1690554 2013-12-09 01:00:00,75.28609538 2013-12-09 02:00:00,75.1906637 2013-12-09 03:00:00,73.93566312 2013-12-09 04:00:00,74.13405397 2013-12-09 05:00:00,74.18672976 2013-12-09 06:00:00,74.17864554 2013-12-09 07:00:00,72.37641122 2013-12-09 08:00:00,73.10689581 2013-12-09 09:00:00,73.18092841 2013-12-09 10:00:00,72.4431114 2013-12-09 11:00:00,73.61399348 2013-12-09 12:00:00,73.50101128 2013-12-09 13:00:00,72.3008609 2013-12-09 14:00:00,72.34904296 2013-12-09 15:00:00,72.21993949 2013-12-09 16:00:00,73.2791445 2013-12-09 17:00:00,73.29098671 2013-12-09 18:00:00,73.02860249 2013-12-09 19:00:00,73.73807814 2013-12-09 20:00:00,73.96940648 2013-12-09 21:00:00,73.87529271 2013-12-09 22:00:00,74.12690095 2013-12-09 23:00:00,74.54068596 2013-12-10 00:00:00,74.58730262 2013-12-10 01:00:00,73.27195908 2013-12-10 02:00:00,73.90958789 2013-12-10 03:00:00,74.12705890000002 2013-12-10 04:00:00,73.64989009 2013-12-10 05:00:00,73.12019765 2013-12-10 06:00:00,72.94981371 2013-12-10 07:00:00,72.63017091 2013-12-10 08:00:00,72.71613838 2013-12-10 09:00:00,72.71722481 2013-12-10 10:00:00,73.73304064 2013-12-10 11:00:00,72.67712283 2013-12-10 12:00:00,73.64547544 2013-12-10 13:00:00,72.30699831 2013-12-10 14:00:00,72.64327782 2013-12-10 15:00:00,72.70649962 2013-12-10 16:00:00,74.00551 2013-12-10 17:00:00,73.59150747 2013-12-10 18:00:00,74.36327747 2013-12-10 19:00:00,73.43398151 2013-12-10 20:00:00,73.34037954 2013-12-10 21:00:00,72.49370372 2013-12-10 22:00:00,73.36328308 2013-12-10 23:00:00,73.75270216 2013-12-11 00:00:00,74.07760056 2013-12-11 01:00:00,74.13267133 2013-12-11 02:00:00,73.55944399 2013-12-11 03:00:00,72.82256754 2013-12-11 04:00:00,72.55823579 2013-12-11 05:00:00,72.94645319 2013-12-11 06:00:00,73.85665686 2013-12-11 07:00:00,72.43060965 2013-12-11 08:00:00,73.64939159 2013-12-11 09:00:00,72.18117166 2013-12-11 10:00:00,72.68621701 2013-12-11 11:00:00,73.38138872 2013-12-11 12:00:00,72.59355339 2013-12-11 13:00:00,73.08965494 2013-12-11 14:00:00,72.15235240000001 2013-12-11 15:00:00,74.58666641 2013-12-11 16:00:00,75.02738785 2013-12-11 17:00:00,74.62411392 2013-12-11 18:00:00,75.34149751 2013-12-11 19:00:00,75.31820223 2013-12-11 20:00:00,74.99496694 2013-12-11 21:00:00,75.14356488 2013-12-11 22:00:00,75.35414616 2013-12-11 23:00:00,75.60743795 2013-12-12 00:00:00,75.11999997 2013-12-12 01:00:00,74.84177433 2013-12-12 02:00:00,75.34780841 2013-12-12 03:00:00,74.96166134 2013-12-12 04:00:00,76.02028875 2013-12-12 05:00:00,74.99070572 2013-12-12 06:00:00,74.54696679 2013-12-12 07:00:00,75.24551555 2013-12-12 08:00:00,74.58234736 2013-12-12 09:00:00,73.27790479 2013-12-12 10:00:00,73.75848662 2013-12-12 11:00:00,73.72426779 2013-12-12 12:00:00,73.40027014 2013-12-12 13:00:00,74.42141665 2013-12-12 14:00:00,74.09206973 2013-12-12 15:00:00,76.13283725 2013-12-12 16:00:00,76.27032048 2013-12-12 17:00:00,76.22574288 2013-12-12 18:00:00,76.19386187 2013-12-12 19:00:00,75.38155998 2013-12-12 20:00:00,75.54108786 2013-12-12 21:00:00,75.44093455 2013-12-12 22:00:00,75.98674438 2013-12-12 23:00:00,76.37852170000002 2013-12-13 00:00:00,76.24170509 2013-12-13 01:00:00,76.07005174 2013-12-13 02:00:00,76.18773069 2013-12-13 03:00:00,74.54095745 2013-12-13 04:00:00,75.9857027 2013-12-13 05:00:00,75.70301054 2013-12-13 06:00:00,75.97637738 2013-12-13 07:00:00,73.99051999 2013-12-13 08:00:00,74.25959878 2013-12-13 09:00:00,74.06537538 2013-12-13 10:00:00,73.497738 2013-12-13 11:00:00,74.40930673 2013-12-13 12:00:00,73.53465219 2013-12-13 13:00:00,74.01325297 2013-12-13 14:00:00,74.65517361 2013-12-13 15:00:00,73.80252519999998 2013-12-13 16:00:00,73.47288405 2013-12-13 17:00:00,74.39571525 2013-12-13 18:00:00,75.54122752 2013-12-13 19:00:00,75.61996717 2013-12-13 20:00:00,74.29673142 2013-12-13 21:00:00,75.83949955 2013-12-13 22:00:00,76.92758894 2013-12-13 23:00:00,75.89869489 2013-12-14 00:00:00,75.17568757 2013-12-14 01:00:00,75.81093193 2013-12-14 02:00:00,75.69196428 2013-12-14 03:00:00,74.5128894 2013-12-14 04:00:00,74.98113099 2013-12-14 05:00:00,76.17734177 2013-12-14 06:00:00,74.42758116 2013-12-14 07:00:00,74.07682949 2013-12-14 08:00:00,75.69932551 2013-12-14 09:00:00,74.84695927 2013-12-14 10:00:00,74.35760136 2013-12-14 11:00:00,74.39803827 2013-12-14 12:00:00,75.02743496 2013-12-14 13:00:00,74.02252097 2013-12-14 14:00:00,74.56358368 2013-12-14 15:00:00,74.69963645 2013-12-14 16:00:00,75.09767236 2013-12-14 17:00:00,76.44727912 2013-12-14 18:00:00,76.95586845 2013-12-14 19:00:00,76.87810004 2013-12-14 20:00:00,78.17639551 2013-12-14 21:00:00,78.63037082 2013-12-14 22:00:00,77.38397999 2013-12-14 23:00:00,78.19047845 2013-12-15 00:00:00,78.61378004 2013-12-15 01:00:00,77.03252890000002 2013-12-15 02:00:00,78.6107109 2013-12-15 03:00:00,76.68094652 2013-12-15 04:00:00,77.05003701 2013-12-15 05:00:00,76.33040884 2013-12-15 06:00:00,77.55881425 2013-12-15 07:00:00,77.29425879 2013-12-15 08:00:00,75.96598011 2013-12-15 09:00:00,76.44504229 2013-12-15 10:00:00,77.37936193 2013-12-15 11:00:00,76.39378285 2013-12-15 12:00:00,76.18731941 2013-12-15 13:00:00,75.55839334 2013-12-15 14:00:00,77.31227539 2013-12-15 15:00:00,77.63696989 2013-12-15 16:00:00,76.61057145 2013-12-15 17:00:00,78.01573292 2013-12-15 18:00:00,78.11484883 2013-12-15 19:00:00,77.7134697 2013-12-15 20:00:00,78.35903267 2013-12-15 21:00:00,77.54037213 2013-12-15 22:00:00,77.50429946 2013-12-15 23:00:00,78.54151818 2013-12-16 00:00:00,78.51850373 2013-12-16 01:00:00,79.21046638 2013-12-16 02:00:00,79.13826897 2013-12-16 03:00:00,78.40306640000001 2013-12-16 04:00:00,78.62008697 2013-12-16 05:00:00,77.13148416 2013-12-16 06:00:00,78.02477786 2013-12-16 07:00:00,77.86136184 2013-12-16 08:00:00,77.78773632 2013-12-16 09:00:00,76.85925072 2013-12-16 10:00:00,76.69516519 2013-12-16 11:00:00,77.00482738 2013-12-16 12:00:00,76.44663657 2013-12-16 13:00:00,76.83346215 2013-12-16 14:00:00,76.46349867 2013-12-16 15:00:00,75.94666293 2013-12-16 16:00:00,75.43675043 2013-12-16 17:00:00,76.31010809 2013-12-16 18:00:00,75.95438461 2013-12-16 19:00:00,76.15312638 2013-12-16 20:00:00,76.12036689 2013-12-16 21:00:00,75.94597297 2013-12-16 22:00:00,76.55225442 2013-12-16 23:00:00,76.79808015 2013-12-17 00:00:00,76.48918773 2013-12-17 01:00:00,76.33896896 2013-12-17 02:00:00,77.05310437 2013-12-17 03:00:00,76.54734976 2013-12-17 04:00:00,75.9568436 2013-12-17 05:00:00,76.51240415 2013-12-17 06:00:00,76.18995103 2013-12-17 07:00:00,76.90449174 2013-12-17 08:00:00,76.17663538 2013-12-17 09:00:00,75.63774692 2013-12-17 10:00:00,74.76111351 2013-12-17 11:00:00,75.90421071 2013-12-17 12:00:00,76.50791927 2013-12-17 13:00:00,75.03569534 2013-12-17 14:00:00,76.44788554 2013-12-17 15:00:00,75.69349585 2013-12-17 16:00:00,74.67369137 2013-12-17 17:00:00,75.53230267 2013-12-17 18:00:00,75.69028376 2013-12-17 19:00:00,75.61612508 2013-12-17 20:00:00,75.38417556 2013-12-17 21:00:00,76.53118614 2013-12-17 22:00:00,76.0893708 2013-12-17 23:00:00,76.67098365 2013-12-18 00:00:00,77.51409604 2013-12-18 01:00:00,77.71518301 2013-12-18 02:00:00,77.49253948 2013-12-18 03:00:00,76.1495223 2013-12-18 04:00:00,77.69271299 2013-12-18 05:00:00,77.3078518 2013-12-18 06:00:00,76.58823094 2013-12-18 07:00:00,77.01356606 2013-12-18 08:00:00,76.29867262 2013-12-18 09:00:00,76.6226516 2013-12-18 10:00:00,76.44608657 2013-12-18 11:00:00,75.00817082 2013-12-18 12:00:00,74.40000215 2013-12-18 13:00:00,75.95158419 2013-12-18 14:00:00,74.806774 2013-12-18 15:00:00,76.18399877 2013-12-18 16:00:00,75.65218318 2013-12-18 17:00:00,75.92126892 2013-12-18 18:00:00,74.56981993 2013-12-18 19:00:00,74.55990289 2013-12-18 20:00:00,74.70972542 2013-12-18 21:00:00,75.87615507 2013-12-18 22:00:00,75.79608847 2013-12-18 23:00:00,74.99922907 2013-12-19 00:00:00,75.24370674 2013-12-19 01:00:00,76.28685920000002 2013-12-19 02:00:00,76.86505572 2013-12-19 03:00:00,75.77297344 2013-12-19 04:00:00,75.97494123 2013-12-19 05:00:00,74.90139316 2013-12-19 06:00:00,74.02325849 2013-12-19 07:00:00,75.06232298 2013-12-19 08:00:00,74.98321538 2013-12-19 09:00:00,75.28863521 2013-12-19 10:00:00,74.94672097 2013-12-19 11:00:00,73.86675878 2013-12-19 12:00:00,73.71014444 2013-12-19 13:00:00,74.90952525 2013-12-19 14:00:00,74.84580286 2013-12-19 15:00:00,75.602222 2013-12-19 16:00:00,74.74889536 2013-12-19 17:00:00,75.01816634 2013-12-19 18:00:00,75.72022589 2013-12-19 19:00:00,76.30473901 2013-12-19 20:00:00,76.01042931 2013-12-19 21:00:00,77.21635808 2013-12-19 22:00:00,76.50729669 2013-12-19 23:00:00,76.88382451 2013-12-20 00:00:00,76.77573772 2013-12-20 01:00:00,76.28321772 2013-12-20 02:00:00,76.24950337 2013-12-20 03:00:00,76.06611132 2013-12-20 04:00:00,75.81287763 2013-12-20 05:00:00,75.70166172 2013-12-20 06:00:00,77.39653919999998 2013-12-20 07:00:00,76.21575455 2013-12-20 08:00:00,76.42174243 2013-12-20 09:00:00,76.12429859999997 2013-12-20 10:00:00,75.95841843 2013-12-20 11:00:00,74.24349947 2013-12-20 12:00:00,76.0751302 2013-12-20 13:00:00,75.84588787 2013-12-20 14:00:00,74.92850291 2013-12-20 15:00:00,76.3109073 2013-12-20 16:00:00,75.13722516 2013-12-20 17:00:00,75.66403255 2013-12-20 18:00:00,77.34278041 2013-12-20 19:00:00,76.93423637 2013-12-20 20:00:00,76.61857052 2013-12-20 21:00:00,77.03286984 2013-12-20 22:00:00,77.55962287 2013-12-20 23:00:00,79.09188313 2013-12-21 00:00:00,78.52068112 2013-12-21 01:00:00,78.98608769 2013-12-21 02:00:00,79.4198418 2013-12-21 03:00:00,79.04463822 2013-12-21 04:00:00,78.08950603 2013-12-21 05:00:00,77.60666850000001 2013-12-21 06:00:00,77.94600233 2013-12-21 07:00:00,77.89349375 2013-12-21 08:00:00,78.60456446 2013-12-21 09:00:00,77.06658421 2013-12-21 10:00:00,78.3217143 2013-12-21 11:00:00,77.70983715 2013-12-21 12:00:00,78.84426107 2013-12-21 13:00:00,77.1455334 2013-12-21 14:00:00,78.76918765 2013-12-21 15:00:00,77.91774797 2013-12-21 16:00:00,78.34500813 2013-12-21 17:00:00,79.86106375 2013-12-21 18:00:00,80.52026302 2013-12-21 19:00:00,79.89687488 2013-12-21 20:00:00,82.28923988 2013-12-21 21:00:00,82.98986906 2013-12-21 22:00:00,83.24788623 2013-12-21 23:00:00,82.51965884 2013-12-22 00:00:00,82.73680192 2013-12-22 01:00:00,83.78099481 2013-12-22 02:00:00,83.00863385 2013-12-22 03:00:00,82.8156272 2013-12-22 04:00:00,81.77474405 2013-12-22 05:00:00,82.45427776 2013-12-22 06:00:00,82.09190101 2013-12-22 07:00:00,80.96998612 2013-12-22 08:00:00,81.84802474 2013-12-22 09:00:00,82.11075802 2013-12-22 10:00:00,80.90724311 2013-12-22 11:00:00,81.79664979 2013-12-22 12:00:00,80.13996622 2013-12-22 13:00:00,80.56010402 2013-12-22 14:00:00,81.53097122 2013-12-22 15:00:00,81.83006626 2013-12-22 16:00:00,83.51163000000003 2013-12-22 17:00:00,84.39093203 2013-12-22 18:00:00,85.22768546 2013-12-22 19:00:00,86.09488844 2013-12-22 20:00:00,86.20418922 2013-12-22 21:00:00,86.22321261 2013-12-22 22:00:00,85.64943737 2013-12-22 23:00:00,86.07470988 2013-12-23 00:00:00,85.32616543 2013-12-23 01:00:00,85.70599036 2013-12-23 02:00:00,84.08697057 2013-12-23 03:00:00,85.22227695 2013-12-23 04:00:00,83.65396808 2013-12-23 05:00:00,84.32899995 2013-12-23 06:00:00,83.11824067 2013-12-23 07:00:00,82.62728762 2013-12-23 08:00:00,82.6222981 2013-12-23 09:00:00,82.37343675 2013-12-23 10:00:00,81.32311924 2013-12-23 11:00:00,80.15369446 2013-12-23 12:00:00,80.29698997 2013-12-23 13:00:00,81.14245049 2013-12-23 14:00:00,79.87450895 2013-12-23 15:00:00,78.72789303 2013-12-23 16:00:00,80.46954892 2013-12-23 17:00:00,79.03221423 2013-12-23 18:00:00,79.87953093 2013-12-23 19:00:00,78.55827641 2013-12-23 20:00:00,79.53990963 2013-12-23 21:00:00,78.25863964 2013-12-23 22:00:00,79.65429515 2013-12-23 23:00:00,80.24362459999998 2013-12-24 00:00:00,80.69153985 2013-12-24 01:00:00,80.39914328 2013-12-24 02:00:00,81.39129706 2013-12-24 03:00:00,81.17088406 2013-12-24 04:00:00,79.61617311 2013-12-24 05:00:00,81.12807513 2013-12-24 06:00:00,80.430862 2013-12-24 07:00:00,80.02182976 2013-12-24 08:00:00,79.86815899999998 2013-12-24 09:00:00,80.57302099 2013-12-24 10:00:00,78.64657966 2013-12-24 11:00:00,77.52978652 2013-12-24 12:00:00,77.83306033 2013-12-24 13:00:00,77.05832672 2013-12-24 14:00:00,77.19065966 2013-12-24 15:00:00,78.12445799999998 2013-12-24 16:00:00,78.72794247 2013-12-24 17:00:00,78.00471004 2013-12-24 18:00:00,77.76657966 2013-12-24 19:00:00,77.67753604 2013-12-24 20:00:00,78.95358338 2013-12-24 21:00:00,78.36725003 2013-12-24 22:00:00,78.6347335 2013-12-24 23:00:00,79.85459920000002 2013-12-25 00:00:00,78.54898156 2013-12-25 01:00:00,79.24333333 2013-12-25 02:00:00,80.04303671 2013-12-25 03:00:00,78.27609712 2013-12-25 04:00:00,79.68598902 2013-12-25 05:00:00,77.91620784 2013-12-25 06:00:00,79.18453247 2013-12-25 07:00:00,77.94191184 2013-12-25 08:00:00,77.08242193 2013-12-25 09:00:00,77.14715291 2013-12-25 10:00:00,77.62220228 2013-12-25 11:00:00,78.39516049 2013-12-25 12:00:00,76.84592783 2013-12-25 13:00:00,78.29719758 2013-12-25 14:00:00,77.61888521 2013-12-25 15:00:00,77.00744034 2013-12-25 16:00:00,77.76062769 2013-12-25 17:00:00,77.05181008 2013-12-25 18:00:00,77.0723302 2013-12-25 19:00:00,78.46417804 2013-12-25 20:00:00,77.42081363 2013-12-25 21:00:00,77.808112 2013-12-25 22:00:00,77.61400932 2013-12-25 23:00:00,78.09598691 2013-12-26 00:00:00,77.77116624 2013-12-26 01:00:00,77.12786457 2013-12-26 02:00:00,77.0909157 2013-12-26 03:00:00,78.23972837 2013-12-26 04:00:00,77.93250468 2013-12-26 05:00:00,77.65365613 2013-12-26 06:00:00,76.34552706 2013-12-26 07:00:00,77.17220436 2013-12-26 08:00:00,76.85489779 2013-12-26 09:00:00,77.10917493 2013-12-26 10:00:00,76.08132018 2013-12-26 11:00:00,75.97126016 2013-12-26 12:00:00,75.31930024 2013-12-26 13:00:00,76.16500538 2013-12-26 14:00:00,76.33505989 2013-12-26 15:00:00,74.71455759 2013-12-26 16:00:00,75.16889103 2013-12-26 17:00:00,76.88840520000002 2013-12-26 18:00:00,75.877899 2013-12-26 19:00:00,76.41369568 2013-12-26 20:00:00,76.51985988 2013-12-26 21:00:00,76.32626701 2013-12-26 22:00:00,76.75690732 2013-12-26 23:00:00,77.20223204 2013-12-27 00:00:00,76.54350997 2013-12-27 01:00:00,77.01021977 2013-12-27 02:00:00,77.28761998 2013-12-27 03:00:00,77.13929934 2013-12-27 04:00:00,75.83918057 2013-12-27 05:00:00,77.4130038 2013-12-27 06:00:00,75.63631529 2013-12-27 07:00:00,76.80939855 2013-12-27 08:00:00,77.20317007 2013-12-27 09:00:00,75.9880975 2013-12-27 10:00:00,75.60517409 2013-12-27 11:00:00,76.4823878 2013-12-27 12:00:00,76.08486147 2013-12-27 13:00:00,75.05631746 2013-12-27 14:00:00,75.71939344 2013-12-27 15:00:00,75.49636047 2013-12-27 16:00:00,75.55847428 2013-12-27 17:00:00,75.78702171 2013-12-27 18:00:00,75.42590876 2013-12-27 19:00:00,76.5985245 2013-12-27 20:00:00,75.35253788 2013-12-27 21:00:00,75.52461588 2013-12-27 22:00:00,75.27324876 2013-12-27 23:00:00,76.24473974 2013-12-28 00:00:00,76.39365772 2013-12-28 01:00:00,76.14188495 2013-12-28 02:00:00,76.01404616 2013-12-28 03:00:00,76.24766604 2013-12-28 04:00:00,74.60550738 2013-12-28 05:00:00,75.27305911 2013-12-28 06:00:00,75.76095709 2013-12-28 07:00:00,75.18391571 2013-12-28 08:00:00,74.39944531 2013-12-28 09:00:00,74.93700505 2013-12-28 10:00:00,74.62630625 2013-12-28 11:00:00,74.52466577 2013-12-28 12:00:00,75.20171861 2013-12-28 13:00:00,75.59031954 2013-12-28 14:00:00,74.99300208 2013-12-28 15:00:00,75.12205049 2013-12-28 16:00:00,74.8451182 2013-12-28 17:00:00,75.5004353 2013-12-28 18:00:00,75.78745907 2013-12-28 19:00:00,76.80171084 2013-12-28 20:00:00,76.89224059 2013-12-28 21:00:00,76.57189936 2013-12-28 22:00:00,76.05772001 2013-12-28 23:00:00,76.30518585 2013-12-29 00:00:00,75.67921558 2013-12-29 01:00:00,75.65697105 2013-12-29 02:00:00,76.36312409 2013-12-29 03:00:00,76.36912771 2013-12-29 04:00:00,75.98000468 2013-12-29 05:00:00,74.95772326 2013-12-29 06:00:00,75.4259806 2013-12-29 07:00:00,75.84298448 2013-12-29 08:00:00,74.33460196 2013-12-29 09:00:00,75.25125208 2013-12-29 10:00:00,75.28419137 2013-12-29 11:00:00,73.97549299 2013-12-29 12:00:00,73.77993441 2013-12-29 13:00:00,74.11605842 2013-12-29 14:00:00,75.41199782 2013-12-29 15:00:00,75.88781183 2013-12-29 16:00:00,75.34116597 2013-12-29 17:00:00,74.87521094 2013-12-29 18:00:00,76.97509822 2013-12-29 19:00:00,76.83889695 2013-12-29 20:00:00,76.92440774 2013-12-29 21:00:00,77.32019076 2013-12-29 22:00:00,77.67837913 2013-12-29 23:00:00,76.02861347 2013-12-30 00:00:00,75.57417604 2013-12-30 01:00:00,75.79405442 2013-12-30 02:00:00,76.64253253 2013-12-30 03:00:00,76.35495023 2013-12-30 04:00:00,76.05391238 2013-12-30 05:00:00,75.76492651 2013-12-30 06:00:00,75.53227413 2013-12-30 07:00:00,75.96286731 2013-12-30 08:00:00,76.43916795 2013-12-30 09:00:00,75.79904062 2013-12-30 10:00:00,75.53723344 2013-12-30 11:00:00,74.76067835 2013-12-30 12:00:00,74.8480328 2013-12-30 13:00:00,76.23999342 2013-12-30 14:00:00,75.11179225 2013-12-30 15:00:00,74.94556814 2013-12-30 16:00:00,75.55307362 2013-12-30 17:00:00,76.83833799 2013-12-30 18:00:00,75.59523206 2013-12-30 19:00:00,76.31503423 2013-12-30 20:00:00,77.53459374 2013-12-30 21:00:00,76.0050383 2013-12-30 22:00:00,77.68454433 2013-12-30 23:00:00,77.72108111 2013-12-31 00:00:00,77.51558001 2013-12-31 01:00:00,78.44437589 2013-12-31 02:00:00,77.97499028 2013-12-31 03:00:00,76.46430922 2013-12-31 04:00:00,77.99078395 2013-12-31 05:00:00,76.65166801 2013-12-31 06:00:00,76.38382148 2013-12-31 07:00:00,77.98764166 2013-12-31 08:00:00,76.02353562 2013-12-31 09:00:00,76.85941302 2013-12-31 10:00:00,77.02694156 2013-12-31 11:00:00,77.4351667 2013-12-31 12:00:00,75.742419 2013-12-31 13:00:00,76.75512501 2013-12-31 14:00:00,76.1618611 2013-12-31 15:00:00,76.68101761 2013-12-31 16:00:00,76.57323145 2013-12-31 17:00:00,77.42705796 2013-12-31 18:00:00,78.04219444 2013-12-31 19:00:00,77.03500259 2013-12-31 20:00:00,77.59435294 2013-12-31 21:00:00,76.86767814 2013-12-31 22:00:00,77.59032761 2013-12-31 23:00:00,77.68816859 2014-01-01 00:00:00,77.17536982 2014-01-01 01:00:00,76.88160145 2014-01-01 02:00:00,77.64735761 2014-01-01 03:00:00,76.6094964 2014-01-01 04:00:00,76.88619653 2014-01-01 05:00:00,76.25204932 2014-01-01 06:00:00,75.93757409 2014-01-01 07:00:00,77.0866129 2014-01-01 08:00:00,76.89226412 2014-01-01 09:00:00,77.15228638 2014-01-01 10:00:00,76.16837159999999 2014-01-01 11:00:00,76.0309472 2014-01-01 12:00:00,76.36542467 2014-01-01 13:00:00,76.21666009999998 2014-01-01 14:00:00,77.344746 2014-01-01 15:00:00,77.17413937 2014-01-01 16:00:00,77.7444573 2014-01-01 17:00:00,77.80851622 2014-01-01 18:00:00,76.95110006 2014-01-01 19:00:00,77.37914862 2014-01-01 20:00:00,77.64861189 2014-01-01 21:00:00,77.57337175 2014-01-01 22:00:00,77.64969323 2014-01-01 23:00:00,77.28681311 2014-01-02 00:00:00,77.62789588 2014-01-02 01:00:00,76.37452465 2014-01-02 02:00:00,76.89324349 2014-01-02 03:00:00,75.84159632 2014-01-02 04:00:00,76.54495496 2014-01-02 05:00:00,75.54568718 2014-01-02 06:00:00,75.61285500000002 2014-01-02 07:00:00,75.77509947 2014-01-02 08:00:00,76.86025712 2014-01-02 09:00:00,76.75063266 2014-01-02 10:00:00,76.65430247 2014-01-02 11:00:00,76.07822982 2014-01-02 12:00:00,75.64525857 2014-01-02 13:00:00,75.6153839 2014-01-02 14:00:00,75.63346999 2014-01-02 15:00:00,75.45555433 2014-01-02 16:00:00,75.36337466 2014-01-02 17:00:00,76.62929369 2014-01-02 18:00:00,76.02807317 2014-01-02 19:00:00,76.95841456 2014-01-02 20:00:00,77.16409297 2014-01-02 21:00:00,77.50435808 2014-01-02 22:00:00,76.45265121 2014-01-02 23:00:00,76.48343837 2014-01-03 00:00:00,75.53864608 2014-01-03 01:00:00,75.63032548 2014-01-03 02:00:00,75.41759869 2014-01-03 03:00:00,75.98132744 2014-01-03 04:00:00,73.93952186 2014-01-03 05:00:00,74.72379503 2014-01-03 06:00:00,74.41912965 2014-01-03 07:00:00,73.57769606 2014-01-03 08:00:00,73.39289962 2014-01-03 09:00:00,73.40029958 2014-01-03 10:00:00,73.15702733 2014-01-03 11:00:00,73.14839463 2014-01-03 12:00:00,73.56870109 2014-01-03 13:00:00,74.24132001 2014-01-03 14:00:00,73.74719451 2014-01-03 15:00:00,75.18506859 2014-01-03 16:00:00,75.62687166 2014-01-03 17:00:00,75.05191762 2014-01-03 18:00:00,75.03447509 2014-01-03 19:00:00,76.67924387 2014-01-03 20:00:00,75.85058042 2014-01-03 21:00:00,76.26521877 2014-01-03 22:00:00,76.40487485 2014-01-03 23:00:00,76.20869095 2014-01-04 00:00:00,75.78848542 2014-01-04 01:00:00,75.78491462 2014-01-04 02:00:00,74.35316083 2014-01-04 03:00:00,73.2440553 2014-01-04 04:00:00,74.52607513 2014-01-04 05:00:00,72.70071992 2014-01-04 06:00:00,72.55197957 2014-01-04 07:00:00,72.76263888 2014-01-04 08:00:00,74.03023695 2014-01-04 09:00:00,72.1040175 2014-01-04 10:00:00,72.46775852 2014-01-04 11:00:00,72.42871912 2014-01-04 12:00:00,72.52468151 2014-01-04 13:00:00,73.11919307 2014-01-04 14:00:00,72.88771617 2014-01-04 15:00:00,73.79287601 2014-01-04 16:00:00,72.8959554 2014-01-04 17:00:00,73.45337227 2014-01-04 18:00:00,74.06806234 2014-01-04 19:00:00,75.77846693 2014-01-04 20:00:00,75.23072963 2014-01-04 21:00:00,75.61607375 2014-01-04 22:00:00,74.98886104 2014-01-04 23:00:00,75.7975775 2014-01-05 00:00:00,74.59213146 2014-01-05 01:00:00,74.133984 2014-01-05 02:00:00,75.68401665 2014-01-05 03:00:00,74.63891988 2014-01-05 04:00:00,74.84522321 2014-01-05 05:00:00,74.99541401 2014-01-05 06:00:00,73.95833504 2014-01-05 07:00:00,73.91074857 2014-01-05 08:00:00,73.56416169 2014-01-05 09:00:00,73.94257293 2014-01-05 10:00:00,73.32290889 2014-01-05 11:00:00,73.93627585 2014-01-05 12:00:00,74.19905101 2014-01-05 13:00:00,72.79990441 2014-01-05 14:00:00,74.06666139 2014-01-05 15:00:00,74.44944008 2014-01-05 16:00:00,74.62982839 2014-01-05 17:00:00,73.89403209 2014-01-05 18:00:00,75.44283941 2014-01-05 19:00:00,74.9532114 2014-01-05 20:00:00,75.48287312 2014-01-05 21:00:00,74.85663000000002 2014-01-05 22:00:00,75.91564308 2014-01-05 23:00:00,74.31605939 2014-01-06 00:00:00,75.58963791 2014-01-06 01:00:00,73.80836459 2014-01-06 02:00:00,74.64795190000002 2014-01-06 03:00:00,75.13418494 2014-01-06 04:00:00,73.66916292 2014-01-06 05:00:00,73.35199946 2014-01-06 06:00:00,73.97781018 2014-01-06 07:00:00,74.35526471 2014-01-06 08:00:00,73.95431726 2014-01-06 09:00:00,73.80845391 2014-01-06 10:00:00,73.97871909 2014-01-06 11:00:00,72.86942158 2014-01-06 12:00:00,74.94885797 2014-01-06 13:00:00,75.39944679999998 2014-01-06 14:00:00,74.74238142 2014-01-06 15:00:00,74.66350681 2014-01-06 16:00:00,74.41156835 2014-01-06 17:00:00,75.13358423 2014-01-06 18:00:00,75.11834143 2014-01-06 19:00:00,75.43622284 2014-01-06 20:00:00,76.21395639 2014-01-06 21:00:00,74.73751944 2014-01-06 22:00:00,74.54551289 2014-01-06 23:00:00,75.71630602 2014-01-07 00:00:00,73.71800848 2014-01-07 01:00:00,73.64882122 2014-01-07 02:00:00,74.84681716 2014-01-07 03:00:00,73.4509252 2014-01-07 04:00:00,74.87858197 2014-01-07 05:00:00,74.74808979 2014-01-07 06:00:00,74.36531581 2014-01-07 07:00:00,74.17844994 2014-01-07 08:00:00,74.32707278 2014-01-07 09:00:00,73.04205499 2014-01-07 10:00:00,73.88036889 2014-01-07 11:00:00,74.06747359999999 2014-01-07 12:00:00,73.85181753 2014-01-07 13:00:00,73.52105745 2014-01-07 14:00:00,75.89900009 2014-01-07 15:00:00,75.83602568 2014-01-07 16:00:00,75.7488075 2014-01-07 17:00:00,77.03472136 2014-01-07 18:00:00,75.75358374 2014-01-07 19:00:00,76.37330245 2014-01-07 20:00:00,76.41021209 2014-01-07 21:00:00,76.86214074 2014-01-07 22:00:00,76.37969889 2014-01-07 23:00:00,75.8606675 2014-01-08 00:00:00,75.98763517 2014-01-08 01:00:00,75.23598479 2014-01-08 02:00:00,75.71067527 2014-01-08 03:00:00,75.16753331 2014-01-08 04:00:00,74.70772724 2014-01-08 05:00:00,76.07797055 2014-01-08 06:00:00,74.98527003 2014-01-08 07:00:00,74.9606503 2014-01-08 08:00:00,75.33628459999998 2014-01-08 09:00:00,73.55344265 2014-01-08 10:00:00,73.99107759 2014-01-08 11:00:00,74.84672677 2014-01-08 12:00:00,75.07497205 2014-01-08 13:00:00,74.36771562 2014-01-08 14:00:00,75.74259037 2014-01-08 15:00:00,74.87882442 2014-01-08 16:00:00,76.24095087 2014-01-08 17:00:00,75.95860682 2014-01-08 18:00:00,76.37186909 2014-01-08 19:00:00,75.9443031 2014-01-08 20:00:00,75.11146533 2014-01-08 21:00:00,75.15274793 2014-01-08 22:00:00,75.06549983 2014-01-08 23:00:00,74.69714713 2014-01-09 00:00:00,76.19664042 2014-01-09 01:00:00,74.10948331 2014-01-09 02:00:00,74.63482711 2014-01-09 03:00:00,73.51138733 2014-01-09 04:00:00,73.12606794 2014-01-09 05:00:00,74.01271456 2014-01-09 06:00:00,73.86542453 2014-01-09 07:00:00,73.89712719 2014-01-09 08:00:00,74.03537465 2014-01-09 09:00:00,73.72201999 2014-01-09 10:00:00,72.66948077 2014-01-09 11:00:00,72.50391252 2014-01-09 12:00:00,73.95811461 2014-01-09 13:00:00,74.01521745 2014-01-09 14:00:00,74.01596603 2014-01-09 15:00:00,75.4479466 2014-01-09 16:00:00,76.13073887 2014-01-09 17:00:00,75.25463596 2014-01-09 18:00:00,75.93286118 2014-01-09 19:00:00,75.59193841 2014-01-09 20:00:00,76.30709504 2014-01-09 21:00:00,77.18425747 2014-01-09 22:00:00,75.64246944 2014-01-09 23:00:00,76.37537373 2014-01-10 00:00:00,74.68720578 2014-01-10 01:00:00,75.18990319 2014-01-10 02:00:00,75.849666 2014-01-10 03:00:00,75.14636897 2014-01-10 04:00:00,73.90081676 2014-01-10 05:00:00,74.73933733 2014-01-10 06:00:00,73.74171083 2014-01-10 07:00:00,74.46143239 2014-01-10 08:00:00,73.4840964 2014-01-10 09:00:00,73.03863545 2014-01-10 10:00:00,74.07519737 2014-01-10 11:00:00,72.93006063 2014-01-10 12:00:00,73.18888994 2014-01-10 13:00:00,73.95558633 2014-01-10 14:00:00,75.22775409 2014-01-10 15:00:00,75.05332699 2014-01-10 16:00:00,75.36510048 2014-01-10 17:00:00,76.11231412 2014-01-10 18:00:00,75.58706498 2014-01-10 19:00:00,76.06972961 2014-01-10 20:00:00,75.32744105 2014-01-10 21:00:00,76.06533695 2014-01-10 22:00:00,75.66969997 2014-01-10 23:00:00,76.2727697 2014-01-11 00:00:00,75.50606319 2014-01-11 01:00:00,75.37971925 2014-01-11 02:00:00,74.86435121 2014-01-11 03:00:00,75.92346681 2014-01-11 04:00:00,75.81348126 2014-01-11 05:00:00,75.53701836 2014-01-11 06:00:00,74.23671001 2014-01-11 07:00:00,75.16424971 2014-01-11 08:00:00,74.30239478 2014-01-11 09:00:00,74.59790374 2014-01-11 10:00:00,73.58871356 2014-01-11 11:00:00,73.01315859 2014-01-11 12:00:00,72.58458265 2014-01-11 13:00:00,73.95143473 2014-01-11 14:00:00,73.97461465 2014-01-11 15:00:00,74.56884896 2014-01-11 16:00:00,75.03613111 2014-01-11 17:00:00,75.56055848 2014-01-11 18:00:00,75.62240148 2014-01-11 19:00:00,77.67158003 2014-01-11 20:00:00,77.56623639 2014-01-11 21:00:00,77.61657097 2014-01-11 22:00:00,77.69091215 2014-01-11 23:00:00,77.65642064 2014-01-12 00:00:00,76.58082694 2014-01-12 01:00:00,76.82821008 2014-01-12 02:00:00,77.44683206 2014-01-12 03:00:00,77.63174648 2014-01-12 04:00:00,76.76049719 2014-01-12 05:00:00,76.10329035 2014-01-12 06:00:00,75.93474711 2014-01-12 07:00:00,76.39983542 2014-01-12 08:00:00,75.07645543 2014-01-12 09:00:00,76.25156678 2014-01-12 10:00:00,75.59060727 2014-01-12 11:00:00,75.83963106 2014-01-12 12:00:00,75.22056579999997 2014-01-12 13:00:00,74.85866283 2014-01-12 14:00:00,75.53354519 2014-01-12 15:00:00,75.71749619 2014-01-12 16:00:00,77.69659197 2014-01-12 17:00:00,78.08214012 2014-01-12 18:00:00,78.95522712 2014-01-12 19:00:00,79.64623758 2014-01-12 20:00:00,81.37618811 2014-01-12 21:00:00,80.96947535 2014-01-12 22:00:00,80.30864114 2014-01-12 23:00:00,80.18657579 2014-01-13 00:00:00,78.47491514 2014-01-13 01:00:00,78.96162765 2014-01-13 02:00:00,79.1300713 2014-01-13 03:00:00,78.39635208 2014-01-13 04:00:00,79.85480600000002 2014-01-13 05:00:00,77.98583629 2014-01-13 06:00:00,78.35432954 2014-01-13 07:00:00,78.66812563 2014-01-13 08:00:00,79.03360146 2014-01-13 09:00:00,77.31328955 2014-01-13 10:00:00,77.73451371 2014-01-13 11:00:00,77.69436304 2014-01-13 12:00:00,77.79754628 2014-01-13 13:00:00,77.22909454 2014-01-13 14:00:00,78.35433755 2014-01-13 15:00:00,78.03170789 2014-01-13 16:00:00,76.63660126 2014-01-13 17:00:00,76.57220626 2014-01-13 18:00:00,77.76546817 2014-01-13 19:00:00,77.38246298 2014-01-13 20:00:00,76.69839827 2014-01-13 21:00:00,76.3966038 2014-01-13 22:00:00,78.2430965 2014-01-13 23:00:00,77.18014447 2014-01-14 00:00:00,76.98731733 2014-01-14 01:00:00,76.802564 2014-01-14 02:00:00,78.04845667 2014-01-14 03:00:00,78.30808931 2014-01-14 04:00:00,78.56024461 2014-01-14 05:00:00,78.00986597 2014-01-14 06:00:00,77.74735738 2014-01-14 07:00:00,76.56851354 2014-01-14 08:00:00,76.57631974 2014-01-14 09:00:00,76.29506325 2014-01-14 10:00:00,76.91856774 2014-01-14 11:00:00,77.35300179999999 2014-01-14 12:00:00,76.69395845 2014-01-14 13:00:00,76.79314078 2014-01-14 14:00:00,76.78184988 2014-01-14 15:00:00,76.58378687 2014-01-14 16:00:00,75.29365403 2014-01-14 17:00:00,77.08526779 2014-01-14 18:00:00,77.16331386 2014-01-14 19:00:00,76.08578513 2014-01-14 20:00:00,76.26928873 2014-01-14 21:00:00,76.76325951 2014-01-14 22:00:00,75.47553688 2014-01-14 23:00:00,75.0534243 2014-01-15 00:00:00,75.69341909 2014-01-15 01:00:00,74.84655904 2014-01-15 02:00:00,74.60828148 2014-01-15 03:00:00,75.23334924 2014-01-15 04:00:00,74.76757914 2014-01-15 05:00:00,74.32699919 2014-01-15 06:00:00,72.97529237 2014-01-15 07:00:00,73.30416843 2014-01-15 08:00:00,73.38232286 2014-01-15 09:00:00,74.58791578 2014-01-15 10:00:00,72.9067279 2014-01-15 11:00:00,74.15335692 2014-01-15 12:00:00,74.15977548 2014-01-15 13:00:00,75.48000267 2014-01-15 14:00:00,74.94602944 2014-01-15 15:00:00,74.36597865 2014-01-15 16:00:00,75.40107507 2014-01-15 17:00:00,76.43324294 2014-01-15 18:00:00,76.76879953 2014-01-15 19:00:00,75.42099851 2014-01-15 20:00:00,75.04376408 2014-01-15 21:00:00,75.14537633 2014-01-15 22:00:00,75.26255156 2014-01-15 23:00:00,75.35976422 2014-01-16 00:00:00,75.45234139 2014-01-16 01:00:00,73.94180609 2014-01-16 02:00:00,75.00647379 2014-01-16 03:00:00,74.33106778 2014-01-16 04:00:00,74.87396446 2014-01-16 05:00:00,73.3379579 2014-01-16 06:00:00,72.80256039 2014-01-16 07:00:00,73.66597073 2014-01-16 08:00:00,73.87172516 2014-01-16 09:00:00,73.27324959 2014-01-16 10:00:00,72.72014324 2014-01-16 11:00:00,74.17992104 2014-01-16 12:00:00,74.15880306 2014-01-16 13:00:00,75.59329179999997 2014-01-16 14:00:00,75.41968933 2014-01-16 15:00:00,74.53134496 2014-01-16 16:00:00,74.44982256 2014-01-16 17:00:00,75.434016 2014-01-16 18:00:00,75.62950104 2014-01-16 19:00:00,75.34933235 2014-01-16 20:00:00,75.201389 2014-01-16 21:00:00,75.40868152 2014-01-16 22:00:00,75.11984946 2014-01-16 23:00:00,74.38931293 2014-01-17 00:00:00,74.69809723 2014-01-17 01:00:00,75.18846342 2014-01-17 02:00:00,74.45343886 2014-01-17 03:00:00,74.67691315 2014-01-17 04:00:00,73.41217429 2014-01-17 05:00:00,72.83454005 2014-01-17 06:00:00,73.5939262 2014-01-17 07:00:00,72.76406621 2014-01-17 08:00:00,72.68778157 2014-01-17 09:00:00,73.37875182 2014-01-17 10:00:00,72.06183623 2014-01-17 11:00:00,72.86400869 2014-01-17 12:00:00,74.31198445 2014-01-17 13:00:00,73.92421104 2014-01-17 14:00:00,73.6834725 2014-01-17 15:00:00,73.71034271 2014-01-17 16:00:00,73.515123 2014-01-17 17:00:00,74.65384045 2014-01-17 18:00:00,74.59773769 2014-01-17 19:00:00,74.96277198 2014-01-17 20:00:00,74.62437982 2014-01-17 21:00:00,73.58807814 2014-01-17 22:00:00,74.27463197 2014-01-17 23:00:00,73.46593712 2014-01-18 00:00:00,73.37697331 2014-01-18 01:00:00,74.28679774 2014-01-18 02:00:00,74.60507656 2014-01-18 03:00:00,73.56215036 2014-01-18 04:00:00,74.11232577 2014-01-18 05:00:00,73.97053959 2014-01-18 06:00:00,72.77785049 2014-01-18 07:00:00,72.57867332 2014-01-18 08:00:00,73.50341351 2014-01-18 09:00:00,73.17997554 2014-01-18 10:00:00,73.07969608 2014-01-18 11:00:00,72.86778282 2014-01-18 12:00:00,72.97978227 2014-01-18 13:00:00,72.06864306 2014-01-18 14:00:00,73.46915696 2014-01-18 15:00:00,72.73501198 2014-01-18 16:00:00,73.06122541 2014-01-18 17:00:00,73.9831845 2014-01-18 18:00:00,74.44162889 2014-01-18 19:00:00,74.04541228 2014-01-18 20:00:00,74.99423532 2014-01-18 21:00:00,76.25032982 2014-01-18 22:00:00,75.29434003 2014-01-18 23:00:00,74.45046834 2014-01-19 00:00:00,75.03906858 2014-01-19 01:00:00,75.11973678 2014-01-19 02:00:00,73.60403299 2014-01-19 03:00:00,73.44321638 2014-01-19 04:00:00,73.43418914 2014-01-19 05:00:00,73.23859587 2014-01-19 06:00:00,73.7150373 2014-01-19 07:00:00,73.89335646 2014-01-19 08:00:00,73.87424506 2014-01-19 09:00:00,72.96073809 2014-01-19 10:00:00,72.61113449999998 2014-01-19 11:00:00,71.38831163 2014-01-19 12:00:00,72.09667227 2014-01-19 13:00:00,72.43175322 2014-01-19 14:00:00,73.43453663 2014-01-19 15:00:00,71.85172628 2014-01-19 16:00:00,73.33181218 2014-01-19 17:00:00,73.98179005 2014-01-19 18:00:00,75.60339242 2014-01-19 19:00:00,74.84669634 2014-01-19 20:00:00,75.66432669 2014-01-19 21:00:00,75.41398766 2014-01-19 22:00:00,75.62691835 2014-01-19 23:00:00,76.12839652 2014-01-20 00:00:00,75.24374402 2014-01-20 01:00:00,74.25000295 2014-01-20 02:00:00,74.76520353 2014-01-20 03:00:00,74.88412726 2014-01-20 04:00:00,74.70121296 2014-01-20 05:00:00,73.93681762 2014-01-20 06:00:00,74.25651103 2014-01-20 07:00:00,73.57337828 2014-01-20 08:00:00,72.94924405 2014-01-20 09:00:00,73.73581362 2014-01-20 10:00:00,73.57616849 2014-01-20 11:00:00,73.09497078 2014-01-20 12:00:00,74.97348441 2014-01-20 13:00:00,74.48410538 2014-01-20 14:00:00,74.37005879 2014-01-20 15:00:00,74.89437525 2014-01-20 16:00:00,75.36858942 2014-01-20 17:00:00,75.51543606 2014-01-20 18:00:00,75.93149966 2014-01-20 19:00:00,76.80408083 2014-01-20 20:00:00,76.08022555 2014-01-20 21:00:00,74.81338988 2014-01-20 22:00:00,75.92940133 2014-01-20 23:00:00,75.50636120000001 2014-01-21 00:00:00,74.14574816 2014-01-21 01:00:00,74.86999088 2014-01-21 02:00:00,75.32625215 2014-01-21 03:00:00,73.74854939 2014-01-21 04:00:00,74.07036021 2014-01-21 05:00:00,74.04524108 2014-01-21 06:00:00,74.05595233 2014-01-21 07:00:00,74.2393244 2014-01-21 08:00:00,73.90532239 2014-01-21 09:00:00,73.53187021 2014-01-21 10:00:00,73.96226531 2014-01-21 11:00:00,73.20525326 2014-01-21 12:00:00,74.60467618 2014-01-21 13:00:00,74.24149076 2014-01-21 14:00:00,75.28123022 2014-01-21 15:00:00,74.40222479 2014-01-21 16:00:00,74.19210633 2014-01-21 17:00:00,75.87886303 2014-01-21 18:00:00,75.23863029 2014-01-21 19:00:00,74.96873237 2014-01-21 20:00:00,76.10793148 2014-01-21 21:00:00,75.36131634 2014-01-21 22:00:00,75.90263465 2014-01-21 23:00:00,75.50472037 2014-01-22 00:00:00,74.28022956 2014-01-22 01:00:00,72.97203667 2014-01-22 02:00:00,72.67511800000003 2014-01-22 03:00:00,73.47639463 2014-01-22 04:00:00,73.39614473 2014-01-22 05:00:00,72.10091024 2014-01-22 06:00:00,71.8777649 2014-01-22 07:00:00,72.55737568 2014-01-22 08:00:00,72.98505223 2014-01-22 09:00:00,73.73262672 2014-01-22 10:00:00,72.69930722 2014-01-22 11:00:00,73.01882828 2014-01-22 12:00:00,72.80921712 2014-01-22 13:00:00,73.65716599 2014-01-22 14:00:00,74.68008894 2014-01-22 15:00:00,74.65383035 2014-01-22 16:00:00,73.90375633 2014-01-22 17:00:00,74.95962081 2014-01-22 18:00:00,74.72151271 2014-01-22 19:00:00,76.1127814 2014-01-22 20:00:00,76.27976034 2014-01-22 21:00:00,75.43044158 2014-01-22 22:00:00,74.81221712 2014-01-22 23:00:00,75.29112173 2014-01-23 00:00:00,74.11805047 2014-01-23 01:00:00,73.08506057 2014-01-23 02:00:00,73.71635914 2014-01-23 03:00:00,72.75477351 2014-01-23 04:00:00,73.06979399999999 2014-01-23 05:00:00,73.43277483 2014-01-23 06:00:00,72.12848145 2014-01-23 07:00:00,72.30633866 2014-01-23 08:00:00,72.55350882 2014-01-23 09:00:00,72.43365278 2014-01-23 10:00:00,72.16028829999998 2014-01-23 11:00:00,71.87997676 2014-01-23 12:00:00,72.30469043 2014-01-23 13:00:00,72.90140272 2014-01-23 14:00:00,73.52178365 2014-01-23 15:00:00,74.33549357 2014-01-23 16:00:00,75.39468245 2014-01-23 17:00:00,74.07597525 2014-01-23 18:00:00,75.35896953 2014-01-23 19:00:00,76.20885954 2014-01-23 20:00:00,75.47638239 2014-01-23 21:00:00,74.560063 2014-01-23 22:00:00,74.52753611 2014-01-23 23:00:00,73.71689559999999 2014-01-24 00:00:00,73.90866358 2014-01-24 01:00:00,74.09748437 2014-01-24 02:00:00,73.87374575 2014-01-24 03:00:00,73.74883976 2014-01-24 04:00:00,72.9320447 2014-01-24 05:00:00,73.49330934 2014-01-24 06:00:00,73.66155176 2014-01-24 07:00:00,73.62855627 2014-01-24 08:00:00,73.16522286 2014-01-24 09:00:00,72.7479508 2014-01-24 10:00:00,73.56592026 2014-01-24 11:00:00,71.75263157 2014-01-24 12:00:00,73.18039611 2014-01-24 13:00:00,73.92384 2014-01-24 14:00:00,73.80439905 2014-01-24 15:00:00,73.73073979 2014-01-24 16:00:00,73.80911621 2014-01-24 17:00:00,73.53212237 2014-01-24 18:00:00,75.18577049 2014-01-24 19:00:00,75.01261659 2014-01-24 20:00:00,75.04608932 2014-01-24 21:00:00,73.33607329 2014-01-24 22:00:00,73.1043253 2014-01-24 23:00:00,74.10360046 2014-01-25 00:00:00,73.78519774 2014-01-25 01:00:00,71.71663594 2014-01-25 02:00:00,72.13397159 2014-01-25 03:00:00,71.51253422 2014-01-25 04:00:00,72.46607477 2014-01-25 05:00:00,70.94402108 2014-01-25 06:00:00,72.61890668 2014-01-25 07:00:00,70.73076574 2014-01-25 08:00:00,72.48740311 2014-01-25 09:00:00,70.83079397 2014-01-25 10:00:00,71.04843529 2014-01-25 11:00:00,70.71591042 2014-01-25 12:00:00,70.79152507 2014-01-25 13:00:00,70.65705161 2014-01-25 14:00:00,71.61997893 2014-01-25 15:00:00,71.01293809 2014-01-25 16:00:00,71.73672317 2014-01-25 17:00:00,72.73172553 2014-01-25 18:00:00,71.46886416 2014-01-25 19:00:00,71.86085423 2014-01-25 20:00:00,73.11208905 2014-01-25 21:00:00,72.20025328 2014-01-25 22:00:00,72.23507842 2014-01-25 23:00:00,72.0287567 2014-01-26 00:00:00,71.82552414 2014-01-26 01:00:00,72.33922968 2014-01-26 02:00:00,71.85635252 2014-01-26 03:00:00,70.5453744 2014-01-26 04:00:00,70.37989579 2014-01-26 05:00:00,70.37604173 2014-01-26 06:00:00,70.77914323 2014-01-26 07:00:00,70.19317971 2014-01-26 08:00:00,70.24674398 2014-01-26 09:00:00,71.35010374 2014-01-26 10:00:00,69.99332028 2014-01-26 11:00:00,71.14020035 2014-01-26 12:00:00,69.67929351 2014-01-26 13:00:00,69.35287097 2014-01-26 14:00:00,70.07391138 2014-01-26 15:00:00,70.16723295 2014-01-26 16:00:00,70.29923518 2014-01-26 17:00:00,70.53565511 2014-01-26 18:00:00,71.79430755 2014-01-26 19:00:00,71.82889986 2014-01-26 20:00:00,72.54095975 2014-01-26 21:00:00,71.58480523 2014-01-26 22:00:00,73.13032124 2014-01-26 23:00:00,72.19137711 2014-01-27 00:00:00,72.69299224 2014-01-27 01:00:00,72.52594748 2014-01-27 02:00:00,72.1202739 2014-01-27 03:00:00,71.63100933 2014-01-27 04:00:00,72.32810907 2014-01-27 05:00:00,71.35093709 2014-01-27 06:00:00,72.35543488 2014-01-27 07:00:00,72.9372165 2014-01-27 08:00:00,71.70966262 2014-01-27 09:00:00,72.032484 2014-01-27 10:00:00,72.49053701 2014-01-27 11:00:00,71.89054985 2014-01-27 12:00:00,71.26701803 2014-01-27 13:00:00,74.46663598 2014-01-27 14:00:00,72.22220945 2014-01-27 15:00:00,73.72378953 2014-01-27 16:00:00,73.22172217 2014-01-27 17:00:00,73.98717586 2014-01-27 18:00:00,73.03814208 2014-01-27 19:00:00,73.32673418 2014-01-27 20:00:00,74.66952758 2014-01-27 21:00:00,74.79814747 2014-01-27 22:00:00,73.00862053 2014-01-27 23:00:00,72.03939489 2014-01-28 00:00:00,72.84926503 2014-01-28 01:00:00,72.21653075 2014-01-28 02:00:00,72.82207234 2014-01-28 03:00:00,72.13937972 2014-01-28 04:00:00,71.41855654 2014-01-28 05:00:00,72.13106037 2014-01-28 06:00:00,70.30742259 2014-01-28 07:00:00,71.29753092 2014-01-28 08:00:00,70.73465105 2014-01-28 09:00:00,70.97773483 2014-01-28 10:00:00,71.29569485 2014-01-28 11:00:00,70.86865163 2014-01-28 12:00:00,71.13147563 2014-01-28 13:00:00,71.26149539 2014-01-28 14:00:00,71.94856019 2014-01-28 15:00:00,73.39954311 2014-01-28 16:00:00,72.71250801 2014-01-28 17:00:00,72.77672232 2014-01-28 18:00:00,72.35599271 2014-01-28 19:00:00,73.15618385 2014-01-28 20:00:00,73.63572063 2014-01-28 21:00:00,72.21822025 2014-01-28 22:00:00,73.09245779 2014-01-28 23:00:00,72.11831496 2014-01-29 00:00:00,71.42071144 2014-01-29 01:00:00,70.56138073 2014-01-29 02:00:00,71.67378573 2014-01-29 03:00:00,70.69482748 2014-01-29 04:00:00,71.05763613 2014-01-29 05:00:00,69.64124933 2014-01-29 06:00:00,69.98065226 2014-01-29 07:00:00,69.64774646 2014-01-29 08:00:00,68.90916513 2014-01-29 09:00:00,68.87238795 2014-01-29 10:00:00,69.78818855 2014-01-29 11:00:00,71.12277947 2014-01-29 12:00:00,69.26547487 2014-01-29 13:00:00,69.4026087 2014-01-29 14:00:00,70.83920046 2014-01-29 15:00:00,69.3426551 2014-01-29 16:00:00,70.48650218 2014-01-29 17:00:00,71.05859214 2014-01-29 18:00:00,72.61395853 2014-01-29 19:00:00,72.86434604 2014-01-29 20:00:00,72.37767629 2014-01-29 21:00:00,71.96930019 2014-01-29 22:00:00,70.34552908 2014-01-29 23:00:00,70.14337141 2014-01-30 00:00:00,69.65669593 2014-01-30 01:00:00,70.78838358 2014-01-30 02:00:00,69.51059999 2014-01-30 03:00:00,70.31048879 2014-01-30 04:00:00,68.33312277 2014-01-30 05:00:00,69.11285507 2014-01-30 06:00:00,68.36206502 2014-01-30 07:00:00,70.00255638 2014-01-30 08:00:00,69.84002555 2014-01-30 09:00:00,70.8745921 2014-01-30 10:00:00,69.71342166 2014-01-30 11:00:00,70.57222326 2014-01-30 12:00:00,71.52531104 2014-01-30 13:00:00,72.153684 2014-01-30 14:00:00,71.81595951 2014-01-30 15:00:00,72.36544447 2014-01-30 16:00:00,72.4569589 2014-01-30 17:00:00,74.33983452 2014-01-30 18:00:00,72.53925557 2014-01-30 19:00:00,73.62854553 2014-01-30 20:00:00,74.16754767 2014-01-30 21:00:00,72.13192721 2014-01-30 22:00:00,72.59170057 2014-01-30 23:00:00,73.23535767 2014-01-31 00:00:00,71.19719727 2014-01-31 01:00:00,72.61891747 2014-01-31 02:00:00,70.88976393 2014-01-31 03:00:00,71.45727319 2014-01-31 04:00:00,70.03927892 2014-01-31 05:00:00,71.28071130000002 2014-01-31 06:00:00,70.26626228 2014-01-31 07:00:00,70.99283914 2014-01-31 08:00:00,72.32981714 2014-01-31 09:00:00,73.11036920000002 2014-01-31 10:00:00,71.65932377 2014-01-31 11:00:00,71.69114293 2014-01-31 12:00:00,73.06636241 2014-01-31 13:00:00,72.80727072 2014-01-31 14:00:00,73.03538763 2014-01-31 15:00:00,74.79646198 2014-01-31 16:00:00,74.73596869 2014-01-31 17:00:00,74.52413086 2014-01-31 18:00:00,75.13725636 2014-01-31 19:00:00,75.51339861 2014-01-31 20:00:00,74.97912619 2014-01-31 21:00:00,75.16085571 2014-01-31 22:00:00,73.94071425 2014-01-31 23:00:00,74.6188033 2014-02-01 00:00:00,74.59156686 2014-02-01 01:00:00,73.28286835 2014-02-01 02:00:00,74.00350054 2014-02-01 03:00:00,72.69543879 2014-02-01 04:00:00,71.81722439 2014-02-01 05:00:00,71.22178031 2014-02-01 06:00:00,70.71015231 2014-02-01 07:00:00,71.85774564 2014-02-01 08:00:00,72.71240816 2014-02-01 09:00:00,70.8336897 2014-02-01 10:00:00,70.79616568 2014-02-01 11:00:00,71.21849014 2014-02-01 12:00:00,70.71605474 2014-02-01 13:00:00,70.86097936 2014-02-01 14:00:00,70.84299733 2014-02-01 15:00:00,71.92974532 2014-02-01 16:00:00,71.79294961 2014-02-01 17:00:00,71.10245254 2014-02-01 18:00:00,71.47578673 2014-02-01 19:00:00,73.06019458 2014-02-01 20:00:00,71.57960823 2014-02-01 21:00:00,72.00120605 2014-02-01 22:00:00,71.53750218 2014-02-01 23:00:00,71.07065184 2014-02-02 00:00:00,70.44906285 2014-02-02 01:00:00,71.26135473 2014-02-02 02:00:00,71.33996454 2014-02-02 03:00:00,71.30097322 2014-02-02 04:00:00,69.9892031 2014-02-02 05:00:00,70.48431814 2014-02-02 06:00:00,70.00301726 2014-02-02 07:00:00,70.80399895 2014-02-02 08:00:00,69.16903154 2014-02-02 09:00:00,70.23674187 2014-02-02 10:00:00,70.13354079 2014-02-02 11:00:00,70.15141027 2014-02-02 12:00:00,69.00452108 2014-02-02 13:00:00,69.71760276 2014-02-02 14:00:00,70.12305221 2014-02-02 15:00:00,69.76208503 2014-02-02 16:00:00,69.90676189 2014-02-02 17:00:00,70.43625119 2014-02-02 18:00:00,71.23295217 2014-02-02 19:00:00,71.99986698 2014-02-02 20:00:00,72.88904636 2014-02-02 21:00:00,72.65424564 2014-02-02 22:00:00,71.64446397 2014-02-02 23:00:00,72.49652262 2014-02-03 00:00:00,72.19594917 2014-02-03 01:00:00,71.27499667 2014-02-03 02:00:00,71.54927665 2014-02-03 03:00:00,71.37741336 2014-02-03 04:00:00,70.96126394 2014-02-03 05:00:00,70.86526769 2014-02-03 06:00:00,69.51742692 2014-02-03 07:00:00,70.23699729 2014-02-03 08:00:00,70.25478592 2014-02-03 09:00:00,69.54660274 2014-02-03 10:00:00,71.28535022 2014-02-03 11:00:00,71.76620383 2014-02-03 12:00:00,73.1581291 2014-02-03 13:00:00,72.81950243 2014-02-03 14:00:00,73.94357122 2014-02-03 15:00:00,73.31051239 2014-02-03 16:00:00,75.01779737 2014-02-03 17:00:00,73.79603192 2014-02-03 18:00:00,74.03478298 2014-02-03 19:00:00,74.89001392 2014-02-03 20:00:00,74.20342727 2014-02-03 21:00:00,75.47335894 2014-02-03 22:00:00,74.35480145 2014-02-03 23:00:00,73.90516246 2014-02-04 00:00:00,74.27115536 2014-02-04 01:00:00,72.83977840000001 2014-02-04 02:00:00,72.75240643 2014-02-04 03:00:00,72.32492459999997 2014-02-04 04:00:00,73.52854801 2014-02-04 05:00:00,72.4911934 2014-02-04 06:00:00,72.27198579 2014-02-04 07:00:00,71.4871934 2014-02-04 08:00:00,72.12293771 2014-02-04 09:00:00,72.29360612 2014-02-04 10:00:00,72.86539996 2014-02-04 11:00:00,71.36774996 2014-02-04 12:00:00,73.26391824 2014-02-04 13:00:00,73.68072512 2014-02-04 14:00:00,72.61150204 2014-02-04 15:00:00,73.07639687 2014-02-04 16:00:00,74.24530254 2014-02-04 17:00:00,74.49700643 2014-02-04 18:00:00,75.69456912 2014-02-04 19:00:00,74.47440675 2014-02-04 20:00:00,74.34991774 2014-02-04 21:00:00,73.98990175 2014-02-04 22:00:00,73.49337021 2014-02-04 23:00:00,74.69248458 2014-02-05 00:00:00,72.92171344 2014-02-05 01:00:00,73.9381704 2014-02-05 02:00:00,73.26932063 2014-02-05 03:00:00,72.89486303 2014-02-05 04:00:00,71.82789886 2014-02-05 05:00:00,71.50326635 2014-02-05 06:00:00,72.43797863 2014-02-05 07:00:00,71.49212101 2014-02-05 08:00:00,71.97523749 2014-02-05 09:00:00,72.25395073 2014-02-05 10:00:00,72.56517449 2014-02-05 11:00:00,71.83775883 2014-02-05 12:00:00,73.44242506 2014-02-05 13:00:00,74.27947284 2014-02-05 14:00:00,72.99596329 2014-02-05 15:00:00,74.10552743 2014-02-05 16:00:00,73.61788608 2014-02-05 17:00:00,73.31701516 2014-02-05 18:00:00,73.01174645 2014-02-05 19:00:00,74.31390131 2014-02-05 20:00:00,73.22819982 2014-02-05 21:00:00,73.72890646 2014-02-05 22:00:00,72.94723977 2014-02-05 23:00:00,73.8378393 2014-02-06 00:00:00,72.12373833 2014-02-06 01:00:00,72.04284098 2014-02-06 02:00:00,72.25186859 2014-02-06 03:00:00,73.09282493 2014-02-06 04:00:00,71.36865067 2014-02-06 05:00:00,71.49960342 2014-02-06 06:00:00,70.32354612 2014-02-06 07:00:00,70.39520632 2014-02-06 08:00:00,71.16626768 2014-02-06 09:00:00,70.02861579 2014-02-06 10:00:00,71.96241743 2014-02-06 11:00:00,72.38074162 2014-02-06 12:00:00,71.76366871 2014-02-06 13:00:00,71.43442294 2014-02-06 14:00:00,72.96389766 2014-02-06 15:00:00,72.40563890000001 2014-02-06 16:00:00,73.24319119 2014-02-06 17:00:00,74.49209885 2014-02-06 18:00:00,75.67593984 2014-02-06 19:00:00,76.29491541 2014-02-06 20:00:00,74.47855616 2014-02-06 21:00:00,73.97881601 2014-02-06 22:00:00,74.2503925 2014-02-06 23:00:00,73.65281821 2014-02-07 00:00:00,73.5566298 2014-02-07 01:00:00,74.55125277 2014-02-07 02:00:00,73.17815807 2014-02-07 03:00:00,73.99622426 2014-02-07 04:00:00,72.16705646 2014-02-07 05:00:00,72.45023357 2014-02-07 06:00:00,73.06302806 2014-02-07 07:00:00,72.0095 2014-02-07 08:00:00,71.80741665 2014-02-07 09:00:00,71.04467432 2014-02-07 10:00:00,71.97005629 2014-02-07 11:00:00,72.90941163 2014-02-07 12:00:00,72.17063774 2014-02-07 13:00:00,73.06947938 2014-02-07 14:00:00,73.0341092 2014-02-07 15:00:00,73.80953945 2014-02-07 16:00:00,74.31038278 2014-02-07 17:00:00,73.68024234 2014-02-07 18:00:00,74.41363078 2014-02-07 19:00:00,74.41119626 2014-02-07 20:00:00,75.30582101 2014-02-07 21:00:00,73.72231831 2014-02-07 22:00:00,73.956886 2014-02-07 23:00:00,74.57015739 2014-02-08 00:00:00,74.38656607 2014-02-08 01:00:00,73.40422925 2014-02-08 02:00:00,74.70798308 2014-02-08 03:00:00,74.45851269 2014-02-08 04:00:00,73.61811087 2014-02-08 05:00:00,72.61189448 2014-02-08 06:00:00,72.51799386 2014-02-08 07:00:00,72.23863682 2014-02-08 08:00:00,72.24960786 2014-02-08 09:00:00,72.36965218 2014-02-08 10:00:00,73.01194094 2014-02-08 11:00:00,71.62813647 2014-02-08 12:00:00,73.08187593 2014-02-08 13:00:00,72.56747177 2014-02-08 14:00:00,72.40514197 2014-02-08 15:00:00,71.49508201 2014-02-08 16:00:00,72.94715866 2014-02-08 17:00:00,72.921265 2014-02-08 18:00:00,73.01400553 2014-02-08 19:00:00,72.79306485 2014-02-08 20:00:00,72.85442183 2014-02-08 21:00:00,71.65525912 2014-02-08 22:00:00,72.67823919 2014-02-08 23:00:00,71.24393979999998 2014-02-09 00:00:00,72.55938056 2014-02-09 01:00:00,72.05872252 2014-02-09 02:00:00,70.76837988 2014-02-09 03:00:00,72.2572247 2014-02-09 04:00:00,70.78523809 2014-02-09 05:00:00,70.62316491 2014-02-09 06:00:00,69.95124246 2014-02-09 07:00:00,69.93090011 2014-02-09 08:00:00,70.59418428 2014-02-09 09:00:00,70.22278152 2014-02-09 10:00:00,70.96283441 2014-02-09 11:00:00,69.80899995 2014-02-09 12:00:00,70.54885559 2014-02-09 13:00:00,69.93109781 2014-02-09 14:00:00,69.51149457 2014-02-09 15:00:00,69.65236836 2014-02-09 16:00:00,70.29518506 2014-02-09 17:00:00,71.62899935 2014-02-09 18:00:00,70.19075454 2014-02-09 19:00:00,70.75169665 2014-02-09 20:00:00,70.81184472 2014-02-09 21:00:00,72.25826358 2014-02-09 22:00:00,71.2385615 2014-02-09 23:00:00,71.58482682 2014-02-10 00:00:00,72.05545689 2014-02-10 01:00:00,70.68437859 2014-02-10 02:00:00,71.74562272 2014-02-10 03:00:00,70.63016123 2014-02-10 04:00:00,70.10605477 2014-02-10 05:00:00,69.15085681 2014-02-10 06:00:00,70.53897933 2014-02-10 07:00:00,69.75848063 2014-02-10 08:00:00,69.0311664 2014-02-10 09:00:00,69.97462923 2014-02-10 10:00:00,70.99730927 2014-02-10 11:00:00,71.81090729 2014-02-10 12:00:00,71.22813976 2014-02-10 13:00:00,73.54807891 2014-02-10 14:00:00,73.1994691 2014-02-10 15:00:00,72.48376476 2014-02-10 16:00:00,73.27048296 2014-02-10 17:00:00,72.63291885 2014-02-10 18:00:00,73.04230204 2014-02-10 19:00:00,73.59851179 2014-02-10 20:00:00,73.94426246 2014-02-10 21:00:00,72.24379429999998 2014-02-10 22:00:00,72.89933674 2014-02-10 23:00:00,73.3069622 2014-02-11 00:00:00,73.94052267 2014-02-11 01:00:00,72.92628635 2014-02-11 02:00:00,72.67838417 2014-02-11 03:00:00,73.30959938 2014-02-11 04:00:00,73.02655382 2014-02-11 05:00:00,72.29872004 2014-02-11 06:00:00,71.88552448 2014-02-11 07:00:00,72.40495323 2014-02-11 08:00:00,72.02464429 2014-02-11 09:00:00,72.19614083 2014-02-11 10:00:00,72.60597358 2014-02-11 11:00:00,72.39294669 2014-02-11 12:00:00,71.43716569 2014-02-11 13:00:00,73.99604465 2014-02-11 14:00:00,73.50943035 2014-02-11 15:00:00,73.45291204 2014-02-11 16:00:00,72.83513404 2014-02-11 17:00:00,73.94819798 2014-02-11 18:00:00,72.4788448 2014-02-11 19:00:00,72.83570362 2014-02-11 20:00:00,73.99025826 2014-02-11 21:00:00,72.88226906 2014-02-11 22:00:00,73.27645109 2014-02-11 23:00:00,74.02768967 2014-02-12 00:00:00,73.89558413 2014-02-12 01:00:00,72.59262336 2014-02-12 02:00:00,71.72471476 2014-02-12 03:00:00,72.13704935 2014-02-12 04:00:00,71.67420314 2014-02-12 05:00:00,70.80216066 2014-02-12 06:00:00,71.79116991 2014-02-12 07:00:00,70.14151030000001 2014-02-12 08:00:00,71.38580367 2014-02-12 09:00:00,70.1927803 2014-02-12 10:00:00,71.53122540000003 2014-02-12 11:00:00,70.74462709 2014-02-12 12:00:00,71.60956249 2014-02-12 13:00:00,72.63429747 2014-02-12 14:00:00,72.72337319 2014-02-12 15:00:00,73.61530291 2014-02-12 16:00:00,73.79199341 2014-02-12 17:00:00,74.02452744 2014-02-12 18:00:00,73.33443313 2014-02-12 19:00:00,73.77239947 2014-02-12 20:00:00,74.18795723 2014-02-12 21:00:00,72.73057539 2014-02-12 22:00:00,73.0460628 2014-02-12 23:00:00,72.61851266 2014-02-13 00:00:00,73.63047725 2014-02-13 01:00:00,71.86090259999997 2014-02-13 02:00:00,73.39534945 2014-02-13 03:00:00,72.5265888 2014-02-13 04:00:00,72.50012423 2014-02-13 05:00:00,70.9921352 2014-02-13 06:00:00,70.68379403 2014-02-13 07:00:00,70.92225816 2014-02-13 08:00:00,71.06859469 2014-02-13 09:00:00,70.50557416 2014-02-13 10:00:00,72.40911188 2014-02-13 11:00:00,71.18403064 2014-02-13 12:00:00,72.27270943 2014-02-13 13:00:00,72.11898377 2014-02-13 14:00:00,74.22012096 2014-02-13 15:00:00,74.14513886 2014-02-13 16:00:00,72.57257271 2014-02-13 17:00:00,73.9980464 2014-02-13 18:00:00,73.63505079999999 2014-02-13 19:00:00,74.18442393 2014-02-13 20:00:00,74.01379528 2014-02-13 21:00:00,73.31100848 2014-02-13 22:00:00,73.2449359 2014-02-13 23:00:00,73.63799953 2014-02-14 00:00:00,74.22768593 2014-02-14 01:00:00,73.25438431 2014-02-14 02:00:00,73.33046811 2014-02-14 03:00:00,73.61255907 2014-02-14 04:00:00,72.97745167 2014-02-14 05:00:00,71.89748993 2014-02-14 06:00:00,72.9483533 2014-02-14 07:00:00,70.81534967 2014-02-14 08:00:00,72.54651585 2014-02-14 09:00:00,71.6016416 2014-02-14 10:00:00,71.38492873 2014-02-14 11:00:00,72.63654073 2014-02-14 12:00:00,72.26304553 2014-02-14 13:00:00,73.08441684 2014-02-14 14:00:00,72.98119162 2014-02-14 15:00:00,73.44090643 2014-02-14 16:00:00,73.67536027 2014-02-14 17:00:00,73.57106999 2014-02-14 18:00:00,75.09120703 2014-02-14 19:00:00,74.01718788 2014-02-14 20:00:00,74.75368514 2014-02-14 21:00:00,74.06098855 2014-02-14 22:00:00,73.64913399 2014-02-14 23:00:00,72.97725908 2014-02-15 00:00:00,74.31242165 2014-02-15 01:00:00,73.36846791 2014-02-15 02:00:00,73.40601581 2014-02-15 03:00:00,71.88177019 2014-02-15 04:00:00,72.16843891 2014-02-15 05:00:00,72.02037785 2014-02-15 06:00:00,71.46429845 2014-02-15 07:00:00,70.13150262 2014-02-15 08:00:00,71.3592175 2014-02-15 09:00:00,71.52512352 2014-02-15 10:00:00,71.20384956 2014-02-15 11:00:00,70.74443864 2014-02-15 12:00:00,70.44676548 2014-02-15 13:00:00,69.73276669 2014-02-15 14:00:00,69.16754481 2014-02-15 15:00:00,68.61762076 2014-02-15 16:00:00,68.2700207 2014-02-15 17:00:00,68.32512358 2014-02-15 18:00:00,68.00591358 2014-02-15 19:00:00,67.69518570000001 2014-02-15 20:00:00,67.66314846 2014-02-15 21:00:00,68.83888277 2014-02-15 22:00:00,67.71317938 2014-02-15 23:00:00,68.16526105 2014-02-16 00:00:00,67.74392032 2014-02-16 01:00:00,66.91077531 2014-02-16 02:00:00,67.67449688 2014-02-16 03:00:00,67.30731382 2014-02-16 04:00:00,67.90404578 2014-02-16 05:00:00,66.9816318 2014-02-16 06:00:00,67.36349977 2014-02-16 07:00:00,66.85608572 2014-02-16 08:00:00,66.82867178 2014-02-16 09:00:00,65.9175334 2014-02-16 10:00:00,65.85412004 2014-02-16 11:00:00,66.57327898 2014-02-16 12:00:00,66.93439295 2014-02-16 13:00:00,65.95981552 2014-02-16 14:00:00,65.52567020000001 2014-02-16 15:00:00,65.00654684 2014-02-16 16:00:00,65.86116824 2014-02-16 17:00:00,66.24895835 2014-02-16 18:00:00,64.84240685 2014-02-16 19:00:00,65.69994977 2014-02-16 20:00:00,65.11922166 2014-02-16 21:00:00,65.06927583 2014-02-16 22:00:00,65.16381523 2014-02-16 23:00:00,64.32817118 2014-02-17 00:00:00,66.17891449 2014-02-17 01:00:00,65.64161252 2014-02-17 02:00:00,64.79075623 2014-02-17 03:00:00,64.67428457 2014-02-17 04:00:00,64.36980786 2014-02-17 05:00:00,63.50098479 2014-02-17 06:00:00,63.81534068 2014-02-17 07:00:00,64.24808886 2014-02-17 08:00:00,63.39175042 2014-02-17 09:00:00,65.78667951 2014-02-17 10:00:00,65.26018668 2014-02-17 11:00:00,66.52420616 2014-02-17 12:00:00,68.3216973 2014-02-17 13:00:00,69.51920746 2014-02-17 14:00:00,70.41798643 2014-02-17 15:00:00,69.85636686 2014-02-17 16:00:00,70.50368788 2014-02-17 17:00:00,71.55722128 2014-02-17 18:00:00,72.21400820000002 2014-02-17 19:00:00,72.23486752 2014-02-17 20:00:00,72.30190595 2014-02-17 21:00:00,71.38697638 2014-02-17 22:00:00,71.71658422 2014-02-17 23:00:00,70.60328489 2014-02-18 00:00:00,70.70527374 2014-02-18 01:00:00,69.37279327 2014-02-18 02:00:00,69.26929995 2014-02-18 03:00:00,68.33325827 2014-02-18 04:00:00,68.26287644 2014-02-18 05:00:00,68.58490764 2014-02-18 06:00:00,67.91159536 2014-02-18 07:00:00,67.02506652 2014-02-18 08:00:00,66.65870493 2014-02-18 09:00:00,68.35154455 2014-02-18 10:00:00,67.47621403 2014-02-18 11:00:00,69.77932913 2014-02-18 12:00:00,69.15476006 2014-02-18 13:00:00,71.2527348 2014-02-18 14:00:00,70.75971585 2014-02-18 15:00:00,72.72805852 2014-02-18 16:00:00,71.57641906 2014-02-18 17:00:00,71.53146856 2014-02-18 18:00:00,72.43892738 2014-02-18 19:00:00,72.51358476 2014-02-18 20:00:00,73.04307154 2014-02-18 21:00:00,72.01489481 2014-02-18 22:00:00,72.03402933 2014-02-18 23:00:00,71.36277817 2014-02-19 00:00:00,70.22442557 2014-02-19 01:00:00,71.04606096 2014-02-19 02:00:00,70.29642466 2014-02-19 03:00:00,69.67691329 2014-02-19 04:00:00,68.59571214 2014-02-19 05:00:00,69.32304528 2014-02-19 06:00:00,69.67748164 2014-02-19 07:00:00,68.7353527 2014-02-19 08:00:00,68.35921937 2014-02-19 09:00:00,68.72795161 2014-02-19 10:00:00,68.99210194 2014-02-19 11:00:00,70.19905465 2014-02-19 12:00:00,69.97929042 2014-02-19 13:00:00,71.22263248 2014-02-19 14:00:00,71.68970302 2014-02-19 15:00:00,71.30018987 2014-02-19 16:00:00,71.27840683 2014-02-19 17:00:00,71.89062285 2014-02-19 18:00:00,70.7418569 2014-02-19 19:00:00,72.45036867 2014-02-19 20:00:00,71.32687587 2014-02-19 21:00:00,71.41737459999997 2014-02-19 22:00:00,72.27479477 2014-02-19 23:00:00,70.60398854 2014-02-20 00:00:00,71.26949942 2014-02-20 01:00:00,70.11901901 2014-02-20 02:00:00,70.71862637 2014-02-20 03:00:00,70.01345997 2014-02-20 04:00:00,70.36792895 2014-02-20 05:00:00,70.25181505 2014-02-20 06:00:00,70.06343925 2014-02-20 07:00:00,69.51877722 2014-02-20 08:00:00,69.51143689 2014-02-20 09:00:00,69.28431029 2014-02-20 10:00:00,70.02917117 2014-02-20 11:00:00,69.77788948 2014-02-20 12:00:00,70.64429563 2014-02-20 13:00:00,72.09907213 2014-02-20 14:00:00,72.55900491 2014-02-20 15:00:00,72.48953325 2014-02-20 16:00:00,72.02762569 2014-02-20 17:00:00,72.56107268 2014-02-20 18:00:00,72.29252772 2014-02-20 19:00:00,72.14536417 2014-02-20 20:00:00,73.17633192 2014-02-20 21:00:00,72.09881309 2014-02-20 22:00:00,73.03183616 2014-02-20 23:00:00,73.4095494 2014-02-21 00:00:00,73.61055026 2014-02-21 01:00:00,73.22469023 2014-02-21 02:00:00,72.77238923 2014-02-21 03:00:00,71.77678685 2014-02-21 04:00:00,71.39870017 2014-02-21 05:00:00,72.01672718 2014-02-21 06:00:00,71.71709105 2014-02-21 07:00:00,71.89082404 2014-02-21 08:00:00,71.79162775 2014-02-21 09:00:00,71.73870688 2014-02-21 10:00:00,70.86190335 2014-02-21 11:00:00,71.69377098 2014-02-21 12:00:00,72.24965305 2014-02-21 13:00:00,71.86440398 2014-02-21 14:00:00,71.71570293 2014-02-21 15:00:00,73.11333987 2014-02-21 16:00:00,73.11595078 2014-02-21 17:00:00,71.98594655 2014-02-21 18:00:00,71.77056727 2014-02-21 19:00:00,72.69503008 2014-02-21 20:00:00,72.97101070000002 2014-02-21 21:00:00,72.4740122 2014-02-21 22:00:00,73.52059659 2014-02-21 23:00:00,72.43691661 2014-02-22 00:00:00,72.18066282 2014-02-22 01:00:00,71.32459195 2014-02-22 02:00:00,71.85583639 2014-02-22 03:00:00,71.88074888 2014-02-22 04:00:00,72.15361442 2014-02-22 05:00:00,71.17776846 2014-02-22 06:00:00,71.41359324 2014-02-22 07:00:00,71.75202769 2014-02-22 08:00:00,72.29547661 2014-02-22 09:00:00,72.06697006 2014-02-22 10:00:00,70.50858274 2014-02-22 11:00:00,70.18441596 2014-02-22 12:00:00,71.29025253 2014-02-22 13:00:00,70.23647890000001 2014-02-22 14:00:00,70.42527414 2014-02-22 15:00:00,70.62841849 2014-02-22 16:00:00,71.29022977 2014-02-22 17:00:00,70.83192557 2014-02-22 18:00:00,71.13549561 2014-02-22 19:00:00,70.83738869 2014-02-22 20:00:00,70.83849743 2014-02-22 21:00:00,70.93245308 2014-02-22 22:00:00,70.27290872 2014-02-22 23:00:00,70.58817206 2014-02-23 00:00:00,70.24057965 2014-02-23 01:00:00,70.80419 2014-02-23 02:00:00,69.80143685 2014-02-23 03:00:00,69.31283198 2014-02-23 04:00:00,69.35668517 2014-02-23 05:00:00,69.13396209999999 2014-02-23 06:00:00,70.44526682 2014-02-23 07:00:00,70.20928733 2014-02-23 08:00:00,69.93524085 2014-02-23 09:00:00,69.29629038 2014-02-23 10:00:00,68.45718549 2014-02-23 11:00:00,69.36682524 2014-02-23 12:00:00,69.78440146 2014-02-23 13:00:00,70.05047118 2014-02-23 14:00:00,69.94616047 2014-02-23 15:00:00,69.58663804 2014-02-23 16:00:00,69.26826291 2014-02-23 17:00:00,70.67206672 2014-02-23 18:00:00,69.77136750000001 2014-02-23 19:00:00,70.36000475 2014-02-23 20:00:00,71.22900600000001 2014-02-23 21:00:00,71.01855228 2014-02-23 22:00:00,71.67436488 2014-02-23 23:00:00,71.98920306 2014-02-24 00:00:00,71.41241783 2014-02-24 01:00:00,70.21304108 2014-02-24 02:00:00,70.46941197 2014-02-24 03:00:00,71.81875355 2014-02-24 04:00:00,70.75726396 2014-02-24 05:00:00,70.35054453 2014-02-24 06:00:00,71.46188706 2014-02-24 07:00:00,70.98973616 2014-02-24 08:00:00,69.85618346 2014-02-24 09:00:00,70.33833311 2014-02-24 10:00:00,70.64534116 2014-02-24 11:00:00,71.59340431 2014-02-24 12:00:00,72.81269719 2014-02-24 13:00:00,71.4608208 2014-02-24 14:00:00,72.85545543 2014-02-24 15:00:00,73.05311023 2014-02-24 16:00:00,73.92592685 2014-02-24 17:00:00,74.95996905 2014-02-24 18:00:00,75.94820959999998 2014-02-24 19:00:00,75.75487779999997 2014-02-24 20:00:00,74.81028192 2014-02-24 21:00:00,73.54824379 2014-02-24 22:00:00,75.07458015 2014-02-24 23:00:00,73.30253287 2014-02-25 00:00:00,74.89976587 2014-02-25 01:00:00,74.93152766 2014-02-25 02:00:00,73.08132323 2014-02-25 03:00:00,74.38609616 2014-02-25 04:00:00,73.555717 2014-02-25 05:00:00,72.43144467 2014-02-25 06:00:00,73.01942581 2014-02-25 07:00:00,72.1483262 2014-02-25 08:00:00,72.8103996 2014-02-25 09:00:00,72.69220185 2014-02-25 10:00:00,72.93948367 2014-02-25 11:00:00,72.10962389 2014-02-25 12:00:00,73.58615695 2014-02-25 13:00:00,72.55872059 2014-02-25 14:00:00,73.58393306 2014-02-25 15:00:00,72.67472192 2014-02-25 16:00:00,73.6832062 2014-02-25 17:00:00,74.65712512 2014-02-25 18:00:00,74.81826612 2014-02-25 19:00:00,75.30493537 2014-02-25 20:00:00,74.75955931 2014-02-25 21:00:00,74.82300241 2014-02-25 22:00:00,75.2020531 2014-02-25 23:00:00,73.73854426 2014-02-26 00:00:00,74.52699276 2014-02-26 01:00:00,74.22793271 2014-02-26 02:00:00,73.43795586 2014-02-26 03:00:00,73.07056291 2014-02-26 04:00:00,72.27324959999999 2014-02-26 05:00:00,71.51947436 2014-02-26 06:00:00,71.63920884 2014-02-26 07:00:00,72.10054496 2014-02-26 08:00:00,72.35798657 2014-02-26 09:00:00,71.52260473 2014-02-26 10:00:00,70.96393378 2014-02-26 11:00:00,72.58154764 2014-02-26 12:00:00,72.58419551 2014-02-26 13:00:00,72.36171361 2014-02-26 14:00:00,72.42998458 2014-02-26 15:00:00,71.75716944 2014-02-26 16:00:00,73.07326185 2014-02-26 17:00:00,72.75507065 2014-02-26 18:00:00,72.5752305 2014-02-26 19:00:00,73.48040164 2014-02-26 20:00:00,72.81148014 2014-02-26 21:00:00,72.55668889 2014-02-26 22:00:00,72.85158523 2014-02-26 23:00:00,73.26970533 2014-02-27 00:00:00,71.19146991 2014-02-27 01:00:00,72.08289113 2014-02-27 02:00:00,71.96350659 2014-02-27 03:00:00,71.82605361 2014-02-27 04:00:00,70.82030946 2014-02-27 05:00:00,69.42550165 2014-02-27 06:00:00,69.92242421 2014-02-27 07:00:00,69.31438143 2014-02-27 08:00:00,70.76033757 2014-02-27 09:00:00,70.97100633 2014-02-27 10:00:00,70.17113554 2014-02-27 11:00:00,70.71432592 2014-02-27 12:00:00,71.921708 2014-02-27 13:00:00,72.00375809999998 2014-02-27 14:00:00,71.78458459 2014-02-27 15:00:00,72.65555112 2014-02-27 16:00:00,72.58009757 2014-02-27 17:00:00,73.05064890000001 2014-02-27 18:00:00,74.54039587 2014-02-27 19:00:00,75.18858469 2014-02-27 20:00:00,74.27894519 2014-02-27 21:00:00,74.26208079 2014-02-27 22:00:00,73.23807909 2014-02-27 23:00:00,73.87025742 2014-02-28 00:00:00,73.43235603 2014-02-28 01:00:00,72.37198523 2014-02-28 02:00:00,73.92808884 2014-02-28 03:00:00,73.25719839 2014-02-28 04:00:00,72.53001535 2014-02-28 05:00:00,71.63872957 2014-02-28 06:00:00,72.28002048 2014-02-28 07:00:00,71.72196102 2014-02-28 08:00:00,70.39334093 2014-02-28 09:00:00,70.10964532 2014-02-28 10:00:00,70.65823648 2014-02-28 11:00:00,71.51087208 2014-02-28 12:00:00,72.44637778 2014-02-28 13:00:00,71.51568524 2014-02-28 14:00:00,72.7279092 2014-02-28 15:00:00,72.29771123 2014-02-28 16:00:00,71.52876516 2014-02-28 17:00:00,72.59605592 2014-02-28 18:00:00,72.01554663 2014-02-28 19:00:00,72.97598217 2014-02-28 20:00:00,71.20551 2014-02-28 21:00:00,72.52524715 2014-02-28 22:00:00,72.49802968 2014-02-28 23:00:00,72.6226827 2014-03-01 00:00:00,71.39694912 2014-03-01 01:00:00,70.29320788 2014-03-01 02:00:00,70.10398202 2014-03-01 03:00:00,70.02121361 2014-03-01 04:00:00,70.27777940000001 2014-03-01 05:00:00,68.76433592 2014-03-01 06:00:00,69.37923216 2014-03-01 07:00:00,67.78520256 2014-03-01 08:00:00,68.49976639 2014-03-01 09:00:00,66.66557183 2014-03-01 10:00:00,66.92889456 2014-03-01 11:00:00,65.80440933 2014-03-01 12:00:00,66.89565828 2014-03-01 13:00:00,66.20627379 2014-03-01 14:00:00,65.62264979 2014-03-01 15:00:00,66.38603358 2014-03-01 16:00:00,66.57722161 2014-03-01 17:00:00,67.22633566 2014-03-01 18:00:00,66.59760208 2014-03-01 19:00:00,67.12154486 2014-03-01 20:00:00,65.97349626 2014-03-01 21:00:00,66.84503091 2014-03-01 22:00:00,66.34569414 2014-03-01 23:00:00,65.04830890000001 2014-03-02 00:00:00,65.36668131 2014-03-02 01:00:00,64.60285133 2014-03-02 02:00:00,65.00628144 2014-03-02 03:00:00,65.10276279 2014-03-03 09:00:00,64.73752596 2014-03-03 10:00:00,66.44422198 2014-03-03 11:00:00,66.67119237 2014-03-03 12:00:00,68.20387067 2014-03-03 13:00:00,67.99377700000001 2014-03-03 14:00:00,68.82246666 2014-03-03 15:00:00,69.83201105 2014-03-03 16:00:00,70.41675915 2014-03-03 17:00:00,69.67662317 2014-03-03 18:00:00,69.75960523 2014-03-03 19:00:00,70.63902199 2014-03-03 20:00:00,71.26261117 2014-03-03 21:00:00,70.37991099999998 2014-03-03 22:00:00,68.99746538 2014-03-03 23:00:00,67.80571471 2014-03-04 00:00:00,68.65145086 2014-03-04 01:00:00,67.3954395 2014-03-04 02:00:00,67.04867326 2014-03-04 03:00:00,66.58482439 2014-03-04 04:00:00,65.50344586 2014-03-04 05:00:00,65.72809278 2014-03-04 06:00:00,65.71347736 2014-03-04 07:00:00,66.21746488 2014-03-04 08:00:00,67.3270938 2014-03-04 09:00:00,67.62303328 2014-03-04 10:00:00,68.08086803 2014-03-04 11:00:00,68.72680885 2014-03-04 12:00:00,70.45355378 2014-03-04 13:00:00,70.06613398 2014-03-04 14:00:00,69.97752106 2014-03-04 15:00:00,70.4927163 2014-03-04 16:00:00,71.61681198 2014-03-04 17:00:00,70.29198332 2014-03-04 18:00:00,71.67066391 2014-03-04 19:00:00,70.70533885 2014-03-04 20:00:00,70.4300817 2014-03-04 21:00:00,69.29157767 2014-03-04 22:00:00,69.34063822 2014-03-04 23:00:00,70.38420092 2014-03-05 00:00:00,69.63034413 2014-03-05 01:00:00,69.0398113 2014-03-05 02:00:00,67.76196134 2014-03-05 03:00:00,67.67675741 2014-03-05 04:00:00,68.86005963 2014-03-05 05:00:00,67.57048842 2014-03-05 06:00:00,68.46335363 2014-03-05 07:00:00,69.29349205 2014-03-05 08:00:00,68.01547296 2014-03-05 09:00:00,68.10090635 2014-03-05 10:00:00,68.12754514 2014-03-05 11:00:00,70.01662351 2014-03-05 12:00:00,70.25863434 2014-03-05 13:00:00,71.09608996 2014-03-05 14:00:00,71.50280303 2014-03-05 15:00:00,71.42488612 2014-03-05 16:00:00,72.71167276 2014-03-05 17:00:00,71.59459113 2014-03-05 18:00:00,72.43328872 2014-03-05 19:00:00,71.48709146 2014-03-05 20:00:00,71.99469951 2014-03-05 21:00:00,71.35471229 2014-03-05 22:00:00,70.39110149 2014-03-05 23:00:00,69.43812495 2014-03-06 00:00:00,70.2584932 2014-03-06 01:00:00,69.67190229 2014-03-06 02:00:00,68.22337002 2014-03-06 03:00:00,68.80799396 2014-03-06 04:00:00,68.03247815 2014-03-06 05:00:00,67.80972606 2014-03-06 06:00:00,66.40552502 2014-03-06 07:00:00,67.83509944 2014-03-06 08:00:00,65.97248106 2014-03-06 09:00:00,66.31911328 2014-03-06 10:00:00,66.29172592 2014-03-06 11:00:00,66.46979301 2014-03-06 12:00:00,67.19727082 2014-03-06 13:00:00,67.26610171 2014-03-06 14:00:00,66.58963271 2014-03-06 15:00:00,66.13565431 2014-03-06 16:00:00,67.45824979 2014-03-06 17:00:00,67.08281943 2014-03-06 18:00:00,66.60154522 2014-03-06 19:00:00,66.14435074 2014-03-06 20:00:00,65.70970149 2014-03-06 21:00:00,65.72663154 2014-03-06 22:00:00,65.58931781 2014-03-06 23:00:00,65.82957452 2014-03-07 00:00:00,65.66945407 2014-03-07 01:00:00,64.47296805 2014-03-07 02:00:00,64.33275758 2014-03-07 03:00:00,64.30729548 2014-03-07 04:00:00,63.27916803 2014-03-07 05:00:00,63.28661915 2014-03-07 06:00:00,62.71784797 2014-03-07 07:00:00,62.10356599 2014-03-07 08:00:00,62.35873434 2014-03-07 09:00:00,62.26844161 2014-03-07 10:00:00,64.14762913 2014-03-07 11:00:00,66.74519744 2014-03-07 12:00:00,66.88478620000001 2014-03-07 13:00:00,67.39191825 2014-03-07 14:00:00,66.3784179 2014-03-07 15:00:00,67.24728902 2014-03-07 16:00:00,68.80478948 2014-03-07 17:00:00,67.78706753 2014-03-07 18:00:00,67.6234333 2014-03-07 19:00:00,68.13243751 2014-03-07 20:00:00,68.35249809 2014-03-07 21:00:00,68.76098726 2014-03-07 22:00:00,68.27847874 2014-03-07 23:00:00,67.18038204 2014-03-08 00:00:00,66.54164375 2014-03-08 01:00:00,67.01120528 2014-03-08 02:00:00,66.64272086 2014-03-08 03:00:00,65.06151932 2014-03-08 04:00:00,65.17996189 2014-03-08 05:00:00,64.67925087 2014-03-08 06:00:00,65.55120828 2014-03-08 07:00:00,64.59678509 2014-03-08 08:00:00,65.27563058 2014-03-08 09:00:00,64.88539882 2014-03-08 10:00:00,65.15421592 2014-03-08 11:00:00,64.26521212 2014-03-08 12:00:00,64.07879166 2014-03-08 13:00:00,63.99581719 2014-03-08 14:00:00,63.37198838 2014-03-08 15:00:00,63.85857426 2014-03-08 16:00:00,65.7786958 2014-03-08 17:00:00,66.00473119 2014-03-08 18:00:00,65.12337382 2014-03-08 19:00:00,66.57607623 2014-03-08 20:00:00,65.02660446 2014-03-08 21:00:00,64.95266133 2014-03-08 22:00:00,64.97658136 2014-03-08 23:00:00,65.67719536 2014-03-09 00:00:00,65.24741305 2014-03-09 01:00:00,65.41542891 2014-03-09 02:00:00,64.98877478 2014-03-09 03:00:00,64.96988162 2014-03-09 04:00:00,63.30792665 2014-03-09 05:00:00,64.40463119 2014-03-09 06:00:00,63.87984768 2014-03-09 07:00:00,62.65054877 2014-03-09 08:00:00,63.64803912 2014-03-09 09:00:00,63.06377998 2014-03-09 10:00:00,63.08252395 2014-03-09 11:00:00,62.42757669 2014-03-09 12:00:00,62.08987607 2014-03-09 13:00:00,61.82403302 2014-03-09 14:00:00,61.80836032 2014-03-09 15:00:00,63.57034584 2014-03-09 16:00:00,63.14298573 2014-03-09 17:00:00,65.21301797 2014-03-09 18:00:00,63.94421349 2014-03-09 19:00:00,64.45766756 2014-03-09 20:00:00,63.5914373 2014-03-09 21:00:00,62.89815719 2014-03-09 22:00:00,64.45257404 2014-03-09 23:00:00,64.12681763 2014-03-10 00:00:00,63.49055243 2014-03-10 01:00:00,63.42430336 2014-03-10 02:00:00,62.15728246 2014-03-10 03:00:00,62.18439593 2014-03-10 04:00:00,62.23825287 2014-03-10 05:00:00,61.28489989 2014-03-10 06:00:00,62.43160143 2014-03-10 07:00:00,62.64010591 2014-03-10 08:00:00,62.75477551 2014-03-10 09:00:00,63.07107014 2014-03-10 10:00:00,65.36263572 2014-03-10 11:00:00,67.68834829 2014-03-10 12:00:00,66.78938507 2014-03-10 13:00:00,67.4030453 2014-03-10 14:00:00,69.22223465 2014-03-10 15:00:00,68.72906724 2014-03-10 16:00:00,69.43623743 2014-03-10 17:00:00,70.25809179999999 2014-03-10 18:00:00,70.25948981 2014-03-10 19:00:00,70.60726748 2014-03-10 20:00:00,70.2063059 2014-03-10 21:00:00,69.81033474 2014-03-10 22:00:00,68.24486669 2014-03-10 23:00:00,68.10978258 2014-03-11 00:00:00,67.63116079 2014-03-11 01:00:00,68.12898944 2014-03-11 02:00:00,66.93579537 2014-03-11 03:00:00,67.28183681 2014-03-11 04:00:00,67.12842156 2014-03-11 05:00:00,65.79175844 2014-03-11 06:00:00,65.13144669 2014-03-11 07:00:00,66.1775294 2014-03-11 08:00:00,66.51384686 2014-03-11 09:00:00,66.52764863 2014-03-11 10:00:00,67.78500622 2014-03-11 11:00:00,69.36668186 2014-03-11 12:00:00,71.10686192 2014-03-11 13:00:00,71.34507296 2014-03-11 14:00:00,71.63930695 2014-03-11 15:00:00,70.36000942 2014-03-11 16:00:00,71.98604698 2014-03-11 17:00:00,71.66471114 2014-03-11 18:00:00,72.72998288 2014-03-11 19:00:00,72.17540433 2014-03-11 20:00:00,71.92709502 2014-03-11 21:00:00,70.85195269 2014-03-11 22:00:00,69.01463509 2014-03-11 23:00:00,68.49462169 2014-03-12 00:00:00,67.48580392 2014-03-12 01:00:00,68.07698894 2014-03-12 02:00:00,68.23106386 2014-03-12 03:00:00,67.01328165 2014-03-12 04:00:00,67.18611750000001 2014-03-12 05:00:00,65.92239173 2014-03-12 06:00:00,66.38206209 2014-03-12 07:00:00,66.46286064 2014-03-12 08:00:00,68.24047875 2014-03-12 09:00:00,68.02786863 2014-03-12 10:00:00,70.1038357 2014-03-12 11:00:00,70.22659164 2014-03-12 12:00:00,71.37680632 2014-03-12 13:00:00,70.67512681 2014-03-12 14:00:00,70.46297529 2014-03-12 15:00:00,71.28157524 2014-03-12 16:00:00,71.05593879999998 2014-03-12 17:00:00,71.70627229 2014-03-12 18:00:00,72.17357465 2014-03-12 19:00:00,71.84544009 2014-03-12 20:00:00,71.17415427 2014-03-12 21:00:00,71.43730024 2014-03-12 22:00:00,71.00435876 2014-03-12 23:00:00,71.1510194 2014-03-13 00:00:00,69.55935905 2014-03-13 01:00:00,69.6460687 2014-03-13 02:00:00,69.7364644 2014-03-13 03:00:00,68.79399824 2014-03-13 04:00:00,69.72507825 2014-03-13 05:00:00,69.23149065 2014-03-13 06:00:00,67.21438079 2014-03-13 07:00:00,68.75934959 2014-03-13 08:00:00,69.27054515 2014-03-13 09:00:00,69.90997802 2014-03-13 10:00:00,69.07299661 2014-03-13 11:00:00,70.97799327 2014-03-13 12:00:00,70.81341304 2014-03-13 13:00:00,69.80737543 2014-03-13 14:00:00,70.50417147 2014-03-13 15:00:00,71.00976364 2014-03-13 16:00:00,71.64484062 2014-03-13 17:00:00,71.60940441 2014-03-13 18:00:00,71.17635266 2014-03-13 19:00:00,70.46962717 2014-03-13 20:00:00,70.50548628 2014-03-13 21:00:00,70.62289581 2014-03-13 22:00:00,71.69910104 2014-03-13 23:00:00,70.73907743 2014-03-14 00:00:00,69.02175496 2014-03-14 01:00:00,68.78503059 2014-03-14 02:00:00,69.22496356 2014-03-14 03:00:00,67.87748709 2014-03-14 04:00:00,67.29471566 2014-03-14 05:00:00,67.28621294 2014-03-14 06:00:00,66.7890731 2014-03-14 07:00:00,67.50432318 2014-03-14 08:00:00,67.79009858 2014-03-14 09:00:00,69.87567 2014-03-14 10:00:00,70.21520038 2014-03-14 11:00:00,71.18656942 2014-03-14 12:00:00,71.67624154 2014-03-14 13:00:00,71.22363341 2014-03-14 14:00:00,70.43924193 2014-03-14 15:00:00,70.36288978 2014-03-14 16:00:00,70.79729744 2014-03-14 17:00:00,70.23646361 2014-03-14 18:00:00,71.73164608 2014-03-14 19:00:00,70.94221602 2014-03-14 20:00:00,70.53918108 2014-03-14 21:00:00,70.54767727 2014-03-14 22:00:00,70.90770815 2014-03-14 23:00:00,69.78682182 2014-03-15 00:00:00,70.91189536 2014-03-15 01:00:00,70.07406754 2014-03-15 02:00:00,69.59586543 2014-03-15 03:00:00,69.60260984 2014-03-15 04:00:00,68.27877452 2014-03-15 05:00:00,69.45619825 2014-03-15 06:00:00,68.44995951 2014-03-15 07:00:00,69.73862286 2014-03-15 08:00:00,68.94209701 2014-03-15 09:00:00,68.18149599 2014-03-15 10:00:00,68.76664235 2014-03-15 11:00:00,67.45815017 2014-03-15 12:00:00,67.66257636 2014-03-15 13:00:00,67.77115437 2014-03-15 14:00:00,67.69510921 2014-03-15 15:00:00,68.11376092 2014-03-15 16:00:00,68.40917826 2014-03-15 17:00:00,68.68576669 2014-03-15 18:00:00,68.70780771 2014-03-15 19:00:00,68.52816028 2014-03-15 20:00:00,67.29328776 2014-03-15 21:00:00,67.71998071 2014-03-15 22:00:00,66.43501296 2014-03-15 23:00:00,67.6421382 2014-03-16 00:00:00,67.50558169 2014-03-16 01:00:00,66.63507662 2014-03-16 02:00:00,66.03094617 2014-03-16 03:00:00,66.85659507 2014-03-16 04:00:00,65.17315838 2014-03-16 05:00:00,65.21746396 2014-03-16 06:00:00,66.28285507 2014-03-16 07:00:00,65.42152866 2014-03-16 08:00:00,64.94362409 2014-03-16 09:00:00,64.89450895 2014-03-16 10:00:00,64.55896017 2014-03-16 11:00:00,63.75135279 2014-03-16 12:00:00,64.59758157 2014-03-16 13:00:00,64.12270321 2014-03-16 14:00:00,63.49946799 2014-03-16 15:00:00,64.70090581 2014-03-16 16:00:00,63.79618368 2014-03-16 17:00:00,64.00797024 2014-03-16 18:00:00,64.72220608 2014-03-16 19:00:00,62.87773689 2014-03-16 20:00:00,63.82235957 2014-03-16 21:00:00,63.75804636 2014-03-16 22:00:00,63.15739889 2014-03-16 23:00:00,63.44294756 2014-03-17 00:00:00,62.12890913 2014-03-17 01:00:00,61.82512301 2014-03-17 02:00:00,61.83080286 2014-03-17 03:00:00,63.16291422 2014-03-17 04:00:00,61.25053172 2014-03-17 05:00:00,61.01365104 2014-03-17 06:00:00,61.21543911 2014-03-17 07:00:00,62.37751935 2014-03-17 08:00:00,62.92591945 2014-03-17 09:00:00,64.87107009 2014-03-17 10:00:00,64.86490926 2014-03-17 11:00:00,66.04123541 2014-03-17 12:00:00,67.6714638 2014-03-17 13:00:00,68.92351552 2014-03-17 14:00:00,67.95417072 2014-03-17 15:00:00,69.769521 2014-03-17 16:00:00,70.24593681 2014-03-17 17:00:00,69.82130302 2014-03-17 18:00:00,70.83974955 2014-03-17 19:00:00,70.51174374 2014-03-17 20:00:00,71.02364643 2014-03-17 21:00:00,68.7052537 2014-03-17 22:00:00,68.11165389 2014-03-17 23:00:00,68.1166531 2014-03-18 00:00:00,67.21496653 2014-03-18 01:00:00,67.06224246 2014-03-18 02:00:00,67.30972126 2014-03-18 05:00:00,66.69399198 2014-03-18 06:00:00,65.70506463 2014-03-18 07:00:00,64.62101714 2014-03-18 08:00:00,65.77618074 2014-03-18 09:00:00,67.40523118 2014-03-18 10:00:00,68.71941661 2014-03-18 11:00:00,69.61966828 2014-03-18 12:00:00,70.27366665 2014-03-18 13:00:00,70.56337429 2014-03-18 14:00:00,70.67077922 2014-03-18 15:00:00,72.26734255 2014-03-18 16:00:00,70.62328355 2014-03-18 17:00:00,71.06334712 2014-03-18 18:00:00,71.65028164 2014-03-18 19:00:00,71.77769312 2014-03-18 20:00:00,70.059985 2014-03-18 21:00:00,70.75799228 2014-03-18 22:00:00,69.98433493 2014-03-18 23:00:00,68.84969949 2014-03-19 00:00:00,69.74606796 2014-03-19 01:00:00,69.53952356 2014-03-19 02:00:00,67.523201 2014-03-19 03:00:00,67.37990329 2014-03-19 04:00:00,67.41747840000001 2014-03-19 05:00:00,65.93843117 2014-03-19 06:00:00,66.82475179 2014-03-19 07:00:00,67.27135893 2014-03-19 08:00:00,67.13357776 2014-03-19 09:00:00,68.52772342 2014-03-19 10:00:00,68.55982584 2014-03-19 11:00:00,68.81377025 2014-03-19 12:00:00,70.36173769 2014-03-19 13:00:00,71.70237934 2014-03-19 14:00:00,72.13491131 2014-03-19 15:00:00,72.18835193 2014-03-19 16:00:00,71.92595429 2014-03-19 17:00:00,71.92725603 2014-03-19 18:00:00,71.54807344 2014-03-19 19:00:00,70.49187639 2014-03-19 20:00:00,71.48653484 2014-03-19 21:00:00,70.20635388 2014-03-19 22:00:00,69.49279694 2014-03-19 23:00:00,68.9205068 2014-03-20 00:00:00,68.33056564 2014-03-20 01:00:00,68.82533073 2014-03-20 02:00:00,68.84005375 2014-03-20 03:00:00,68.31437625 2014-03-20 04:00:00,66.64807821 2014-03-20 05:00:00,66.34454369 2014-03-20 06:00:00,66.17310237 2014-03-20 07:00:00,66.74208658 2014-03-20 08:00:00,68.01627433 2014-03-20 09:00:00,68.92086970000001 2014-03-20 10:00:00,70.1290524 2014-03-20 11:00:00,70.85226597 2014-03-20 12:00:00,70.66374179 2014-03-20 13:00:00,70.4602105 2014-03-20 14:00:00,70.72339624 2014-03-20 15:00:00,71.44960721 2014-03-20 16:00:00,72.70811888 2014-03-20 17:00:00,72.77820708 2014-03-20 18:00:00,71.29761709 2014-03-20 19:00:00,71.33906347 2014-03-20 20:00:00,72.43172383 2014-03-20 21:00:00,70.68626447 2014-03-20 22:00:00,70.90794649 2014-03-20 23:00:00,69.22547767 2014-03-21 00:00:00,69.59225848 2014-03-21 01:00:00,69.23210541 2014-03-21 02:00:00,68.15528042 2014-03-21 03:00:00,66.91203197 2014-03-21 04:00:00,67.71558241 2014-03-21 05:00:00,66.33452731 2014-03-21 06:00:00,66.34030271 2014-03-21 07:00:00,66.1824594 2014-03-21 08:00:00,66.26386 2014-03-21 09:00:00,68.22384891 2014-03-21 10:00:00,69.16427797 2014-03-21 11:00:00,69.10930036 2014-03-21 12:00:00,70.81803261 2014-03-21 13:00:00,70.01676069 2014-03-21 14:00:00,70.90161589 2014-03-21 15:00:00,71.64555322 2014-03-21 16:00:00,71.70339358 2014-03-21 17:00:00,71.27680445 2014-03-21 18:00:00,70.63130618 2014-03-21 19:00:00,70.97130269 2014-03-21 20:00:00,71.71353903 2014-03-21 21:00:00,69.9054085 2014-03-21 22:00:00,69.66400387 2014-03-21 23:00:00,69.16838511 2014-03-22 00:00:00,69.69722981 2014-03-22 01:00:00,69.15682991 2014-03-22 02:00:00,68.72517924 2014-03-22 03:00:00,68.35990386 2014-03-22 04:00:00,67.18127785 2014-03-22 05:00:00,67.94571484 2014-03-22 06:00:00,66.71803036 2014-03-22 07:00:00,65.66712074 2014-03-22 08:00:00,66.84586991 2014-03-22 09:00:00,66.29208118 2014-03-22 10:00:00,66.88373267 2014-03-22 11:00:00,65.19948254 2014-03-22 12:00:00,65.58210550000001 2014-03-22 13:00:00,64.70394655 2014-03-22 14:00:00,66.22315748 2014-03-22 15:00:00,64.88013387 2014-03-22 16:00:00,65.55529857 2014-03-22 17:00:00,64.64947474 2014-03-22 18:00:00,64.68176215 2014-03-22 19:00:00,64.80958215 2014-03-22 20:00:00,65.33285671 2014-03-22 21:00:00,64.36267745 2014-03-22 22:00:00,64.11222793 2014-03-22 23:00:00,65.11150875 2014-03-23 00:00:00,65.33899224 2014-03-23 01:00:00,65.61427437 2014-03-23 02:00:00,63.77836909 2014-03-23 03:00:00,63.70443845 2014-03-23 04:00:00,63.46343576 2014-03-23 05:00:00,63.6445251 2014-03-23 06:00:00,65.44047774 2014-03-23 07:00:00,63.66470663 2014-03-23 08:00:00,64.32136806 2014-03-23 09:00:00,64.17341 2014-03-23 10:00:00,64.86387244 2014-03-23 11:00:00,62.98320455 2014-03-23 12:00:00,63.83170364 2014-03-23 13:00:00,62.81085999 2014-03-23 14:00:00,62.84699795 2014-03-23 15:00:00,63.166335499999995 2014-03-23 16:00:00,63.23431085 2014-03-23 17:00:00,63.01982143 2014-03-23 18:00:00,63.70769083 2014-03-23 19:00:00,62.51382762 2014-03-23 20:00:00,63.21955192 2014-03-23 21:00:00,62.20602098 2014-03-23 22:00:00,62.15285065 2014-03-23 23:00:00,63.05547087 2014-03-24 00:00:00,62.10293066 2014-03-24 01:00:00,62.540844799999995 2014-03-24 02:00:00,62.5503174 2014-03-24 03:00:00,63.20486663 2014-03-24 04:00:00,62.9317748 2014-03-24 19:00:00,71.94336325 2014-03-24 20:00:00,70.71564295 2014-03-24 21:00:00,69.28811871 2014-03-24 22:00:00,68.43786337 2014-03-24 23:00:00,68.24934959 2014-03-25 00:00:00,68.47135744 2014-03-25 01:00:00,67.01776467 2014-03-25 02:00:00,68.08328348 2014-03-25 03:00:00,67.68747842 2014-03-25 04:00:00,67.39799093 2014-03-25 05:00:00,66.2691171 2014-03-25 06:00:00,65.34304105 2014-03-25 07:00:00,64.77433465 2014-03-25 08:00:00,66.44792487 2014-03-25 09:00:00,67.26279954 2014-03-25 10:00:00,67.60152815 2014-03-25 11:00:00,69.90530838 2014-03-25 12:00:00,70.73996852 2014-03-25 13:00:00,70.49826866 2014-03-25 14:00:00,70.2611678 2014-03-25 15:00:00,71.53832084 2014-03-25 16:00:00,71.27033912 2014-03-25 17:00:00,70.90025791 2014-03-25 18:00:00,71.52148116 2014-03-25 19:00:00,70.28414588 2014-03-25 20:00:00,71.60015916 2014-03-25 21:00:00,70.28728127 2014-03-25 22:00:00,68.83984168 2014-03-25 23:00:00,68.49777461 2014-03-26 00:00:00,69.31375581 2014-03-26 01:00:00,67.72785184 2014-03-26 02:00:00,68.09933961 2014-03-26 03:00:00,67.25783658 2014-03-26 04:00:00,66.86402700000001 2014-03-26 05:00:00,66.59775853 2014-03-26 06:00:00,65.53304117 2014-03-26 07:00:00,66.86270078 2014-03-26 08:00:00,67.50801513 2014-03-26 09:00:00,67.77407736 2014-03-26 10:00:00,68.52400365 2014-03-26 11:00:00,69.56611683 2014-03-26 12:00:00,71.28961034 2014-03-26 13:00:00,70.14062086 2014-03-26 14:00:00,71.034825 2014-03-26 15:00:00,71.44418165 2014-03-26 16:00:00,70.78327368 2014-03-26 17:00:00,70.66347191 2014-03-26 18:00:00,69.90711596 2014-03-26 19:00:00,70.24754496 2014-03-26 20:00:00,71.0175816 2014-03-26 21:00:00,71.11791992 2014-03-26 22:00:00,69.28691532 2014-03-26 23:00:00,69.27422586 2014-03-27 00:00:00,70.19449054 2014-03-27 01:00:00,68.77820054 2014-03-27 02:00:00,68.18678053 2014-03-27 03:00:00,68.85984403 2014-03-27 04:00:00,67.73755512 2014-03-27 05:00:00,67.49811369 2014-03-27 06:00:00,66.73351538 2014-03-27 07:00:00,65.96544261 2014-03-27 08:00:00,66.93124294 2014-03-27 09:00:00,69.07779412 2014-03-27 10:00:00,69.22374151 2014-03-27 11:00:00,69.4535237 2014-03-27 12:00:00,72.22574727 2014-03-27 13:00:00,72.32609476 2014-03-27 14:00:00,72.0268521 2014-03-27 15:00:00,71.58630641 2014-03-27 16:00:00,70.57044597 2014-03-27 17:00:00,71.2768215 2014-03-27 18:00:00,71.55483881 2014-03-27 19:00:00,72.03927682 2014-03-27 20:00:00,71.48654663 2014-03-27 21:00:00,70.86464227 2014-03-27 22:00:00,69.35637651 2014-03-27 23:00:00,69.61239792 2014-03-28 00:00:00,68.43977756 2014-03-28 01:00:00,68.1853957 2014-03-28 02:00:00,67.29170594 2014-03-28 03:00:00,68.42970414 2014-03-28 04:00:00,67.05828335 2014-03-28 05:00:00,66.50295007 2014-03-28 06:00:00,67.00732027 2014-03-28 07:00:00,65.42638245 2014-03-28 08:00:00,67.67939638 2014-03-28 09:00:00,67.02204681 2014-03-28 10:00:00,68.54764706 2014-03-28 11:00:00,69.4655308 2014-03-28 12:00:00,70.43402561 2014-03-28 13:00:00,71.9389561 2014-03-28 14:00:00,70.81297494 2014-03-28 15:00:00,70.81249572 2014-03-28 16:00:00,70.15898776 2014-03-28 17:00:00,71.64451052 2014-03-28 18:00:00,70.19782359 2014-03-28 19:00:00,70.58227035 2014-03-28 20:00:00,71.2087204 2014-03-28 21:00:00,70.20658031 2014-03-28 22:00:00,71.01175909999998 2014-03-28 23:00:00,68.85446017 2014-03-29 00:00:00,69.98331416 2014-03-29 01:00:00,68.46446529 2014-03-29 02:00:00,68.73818002 2014-03-29 03:00:00,69.062706 2014-03-29 04:00:00,68.38697286 2014-03-29 05:00:00,67.58387429 2014-03-29 06:00:00,67.83077241 2014-03-29 07:00:00,68.81423687 2014-03-29 08:00:00,66.69042351 2014-03-29 09:00:00,66.36840797 2014-03-29 10:00:00,66.61346754 2014-03-29 11:00:00,67.33922911 2014-03-29 12:00:00,66.9322944 2014-03-29 13:00:00,66.76955124 2014-03-29 14:00:00,66.00830414 2014-03-29 15:00:00,66.7799832 2014-03-29 16:00:00,66.58172048 2014-03-29 17:00:00,67.11698683 2014-03-29 18:00:00,66.15598172 2014-03-29 19:00:00,66.69489329 2014-03-29 20:00:00,64.82380273 2014-03-29 21:00:00,65.2430426 2014-03-29 22:00:00,65.21164883 2014-03-29 23:00:00,64.54188892 2014-03-30 00:00:00,64.8747141 2014-03-30 01:00:00,65.4966696 2014-03-30 02:00:00,65.38109608 2014-03-30 03:00:00,65.02897391 2014-03-30 04:00:00,64.67595377 2014-03-30 05:00:00,64.44424833 2014-03-30 06:00:00,64.25219739 2014-03-30 07:00:00,65.40018788 2014-03-30 08:00:00,63.73067948 2014-03-30 09:00:00,64.20889648 2014-03-30 10:00:00,63.45681538 2014-03-30 11:00:00,64.48807692 2014-03-30 12:00:00,63.79730874 2014-03-30 13:00:00,64.36082107 2014-03-30 14:00:00,63.84830762 2014-03-30 15:00:00,65.51296869 2014-03-30 16:00:00,65.48389278 2014-03-30 17:00:00,65.75005021 2014-03-30 18:00:00,64.65810145 2014-03-30 19:00:00,64.36282383 2014-03-30 20:00:00,64.99007209 2014-03-30 21:00:00,65.34666001 2014-03-30 22:00:00,65.39531562 2014-03-30 23:00:00,64.45329069 2014-03-31 00:00:00,64.61712504 2014-03-31 01:00:00,63.75428142 2014-03-31 02:00:00,63.49502357 2014-03-31 03:00:00,64.12967698 2014-03-31 04:00:00,63.69871435 2014-03-31 05:00:00,62.31748849 2014-03-31 06:00:00,62.56249792 2014-03-31 07:00:00,62.083133 2014-03-31 08:00:00,64.28414943 2014-03-31 09:00:00,63.94397227 2014-03-31 10:00:00,65.76317725 2014-03-31 11:00:00,67.38934556 2014-03-31 12:00:00,66.79761934 2014-03-31 13:00:00,67.51730856 2014-03-31 14:00:00,69.42271076 2014-03-31 15:00:00,69.86566479 2014-03-31 16:00:00,69.47338876 2014-03-31 17:00:00,70.95110588 2014-03-31 18:00:00,71.56889705 2014-03-31 19:00:00,70.99062865 2014-03-31 20:00:00,70.60246289 2014-03-31 21:00:00,68.00017618 2014-03-31 22:00:00,68.25783759999999 2014-03-31 23:00:00,68.63980318 2014-04-01 00:00:00,68.32316289 2014-04-01 01:00:00,66.43383631 2014-04-01 02:00:00,67.18821052 2014-04-01 03:00:00,67.27079193 2014-04-01 04:00:00,65.27791142 2014-04-01 05:00:00,64.67375005 2014-04-01 06:00:00,63.96850495 2014-04-01 07:00:00,64.60849643 2014-04-01 08:00:00,65.56452156 2014-04-01 09:00:00,66.5334125 2014-04-01 10:00:00,68.23406291 2014-04-01 11:00:00,68.56959033 2014-04-01 12:00:00,69.70420104 2014-04-01 13:00:00,69.63981849 2014-04-01 14:00:00,70.22222824 2014-04-01 15:00:00,70.31535411 2014-04-01 16:00:00,71.95951248 2014-04-01 17:00:00,71.24637137 2014-04-01 18:00:00,71.58768312 2014-04-01 19:00:00,70.42108950000002 2014-04-01 20:00:00,71.20646965 2014-04-01 21:00:00,70.61530009 2014-04-01 22:00:00,70.06998582 2014-04-01 23:00:00,69.29171113 2014-04-02 00:00:00,67.85447566 2014-04-02 01:00:00,68.24887826 2014-04-02 02:00:00,68.76715290000001 2014-04-02 03:00:00,68.21590455 2014-04-02 04:00:00,66.42226253 2014-04-02 05:00:00,67.39517591 2014-04-02 06:00:00,65.36892099 2014-04-02 07:00:00,66.25362724 2014-04-02 08:00:00,66.59754547 2014-04-02 09:00:00,67.72967658 2014-04-02 10:00:00,68.48225745 2014-04-02 11:00:00,69.92320652 2014-04-02 12:00:00,70.58513885 2014-04-02 13:00:00,71.41308851 2014-04-02 14:00:00,70.3227835 2014-04-02 15:00:00,71.11789389 2014-04-02 16:00:00,69.47243025 2014-04-02 17:00:00,70.89176392 2014-04-02 18:00:00,71.46215140000002 2014-04-02 19:00:00,71.40483009 2014-04-02 20:00:00,72.2868221 2014-04-02 21:00:00,69.7696442 2014-04-02 22:00:00,69.85857394 2014-04-02 23:00:00,70.29044092 2014-04-03 00:00:00,69.18897735 2014-04-03 01:00:00,68.25903615 2014-04-03 02:00:00,69.48405619 2014-04-03 03:00:00,69.03729828 2014-04-03 04:00:00,68.99054634 2014-04-03 05:00:00,66.96693467 2014-04-03 06:00:00,67.79585605 2014-04-03 07:00:00,67.30111228 2014-04-03 08:00:00,68.06321777 2014-04-03 09:00:00,68.92309559 2014-04-10 15:00:00,69.95467957 2014-04-10 16:00:00,69.99969109999999 2014-04-10 17:00:00,70.46057561 2014-04-10 18:00:00,69.69177635 2014-04-10 19:00:00,71.01239837 2014-04-10 20:00:00,69.3636139 2014-04-10 21:00:00,69.23956202 2014-04-10 22:00:00,69.02602271 2014-04-10 23:00:00,67.66881974 2014-04-11 00:00:00,66.9784945 2014-04-11 01:00:00,66.1376634 2014-04-11 02:00:00,65.64125076 2014-04-11 03:00:00,64.99436157 2014-04-11 04:00:00,64.15511608 2014-04-11 05:00:00,62.70299143 2014-04-11 06:00:00,63.83944116 2014-04-11 07:00:00,62.44194873 2014-04-11 08:00:00,62.37114409 2014-04-11 09:00:00,65.37565585 2014-04-11 10:00:00,65.96957647 2014-04-11 11:00:00,66.59359265 2014-04-11 12:00:00,68.33141592 2014-04-11 13:00:00,68.92824643 2014-04-11 14:00:00,69.4470812 2014-04-11 15:00:00,70.69379188 2014-04-11 16:00:00,68.80751333 2014-04-11 17:00:00,69.77099451 2014-04-11 18:00:00,69.4302069 2014-04-11 19:00:00,69.69943799 2014-04-11 20:00:00,68.39255358 2014-04-11 21:00:00,69.67023519 2014-04-11 22:00:00,68.57844056 2014-04-11 23:00:00,67.05017892 2014-04-12 00:00:00,68.53844670000001 2014-04-12 01:00:00,66.58977222 2014-04-12 02:00:00,66.4437355 2014-04-12 03:00:00,66.63975574 2014-04-12 04:00:00,65.35200151 2014-04-12 05:00:00,66.56495507 2014-04-12 06:00:00,64.62244069 2014-04-12 07:00:00,64.9923665 2014-04-12 08:00:00,63.97746263 2014-04-12 09:00:00,64.18268808 2014-04-12 10:00:00,64.55629521 2014-04-12 11:00:00,63.96192594 2014-04-12 12:00:00,63.56770877 2014-04-12 13:00:00,63.45102885 2014-04-12 14:00:00,62.75664373 2014-04-12 15:00:00,61.88488434 2014-04-12 16:00:00,61.97105163 2014-04-12 17:00:00,62.03644725 2014-04-12 18:00:00,62.85879831 2014-04-12 19:00:00,61.75532146 2014-04-12 20:00:00,60.33080311 2014-04-12 21:00:00,61.31862007 2014-04-12 22:00:00,61.26515428 2014-04-12 23:00:00,59.564727100000006 2014-04-13 00:00:00,59.92144785 2014-04-13 01:00:00,60.09354127 2014-04-13 02:00:00,59.92218636 2014-04-13 03:00:00,58.86227492 2014-04-13 04:00:00,58.77714115 2014-04-13 05:00:00,59.41074654 2014-04-13 06:00:00,57.84457312 2014-04-13 07:00:00,58.38952164 2014-04-13 08:00:00,59.12502309 2014-04-13 09:00:00,57.45840559 2014-04-13 10:00:00,58.23364994 2014-04-13 11:00:00,58.73348655 2014-04-13 12:00:00,58.97261213 2014-04-13 13:00:00,60.25792529 2014-04-13 14:00:00,59.15943501 2014-04-13 15:00:00,60.26702164 2014-04-13 16:00:00,59.20056905 2014-04-13 17:00:00,59.42050888 2014-04-13 18:00:00,59.61076035 2014-04-13 19:00:00,59.375844799999996 2014-04-13 20:00:00,60.45036956 2014-04-13 21:00:00,60.38321276 2014-04-13 22:00:00,59.91094693 2014-04-13 23:00:00,60.28396361 2014-04-14 00:00:00,58.83249363 2014-04-14 01:00:00,60.184197 2014-04-14 02:00:00,60.57384958 2014-04-14 03:00:00,60.58416247 2014-04-14 04:00:00,59.54132737 2014-04-14 05:00:00,60.578911899999994 2014-04-14 06:00:00,59.20245134 2014-04-14 07:00:00,59.53629772 2014-04-14 08:00:00,61.42760267 2014-04-14 09:00:00,62.35052077 2014-04-14 10:00:00,63.87302969 2014-04-14 11:00:00,63.95474106 2014-04-14 12:00:00,64.33255339 2014-04-14 13:00:00,66.89048639 2014-04-14 14:00:00,66.76290578 2014-04-14 15:00:00,68.22765033 2014-04-14 16:00:00,68.66217484 2014-04-14 17:00:00,68.77584664 2014-04-14 18:00:00,69.85149804 2014-04-14 19:00:00,69.64134024 2014-04-14 20:00:00,68.67883235 2014-04-14 21:00:00,66.53906385 2014-04-14 22:00:00,66.75587974 2014-04-14 23:00:00,66.67419463 2014-04-15 00:00:00,65.2054392 2014-04-15 01:00:00,65.2363275 2014-04-15 02:00:00,63.50605093 2014-04-15 03:00:00,64.46464095 2014-04-15 04:00:00,63.51738461 2014-04-15 05:00:00,63.61950823 2014-04-15 06:00:00,62.96296552 2014-04-15 07:00:00,61.77349005 2014-04-15 08:00:00,63.95443765 2014-04-15 09:00:00,63.98985647 2014-04-15 10:00:00,66.04334863 2014-04-15 11:00:00,68.14218819999999 2014-04-15 12:00:00,68.61566659 2014-04-15 13:00:00,68.80427879999999 2014-04-15 14:00:00,70.24867959 2014-04-15 15:00:00,68.84215496 2014-04-15 16:00:00,71.07422118 2014-04-15 17:00:00,70.7975171 2014-04-15 18:00:00,70.00379538 2014-04-15 19:00:00,69.63818207 2014-04-15 20:00:00,71.11138859 2014-04-15 21:00:00,68.9745537 2014-04-15 22:00:00,68.41451411 2014-04-15 23:00:00,67.63084599 2014-04-16 00:00:00,65.73481705 2014-04-16 01:00:00,65.50434383 2014-04-16 02:00:00,64.79166617 2014-04-16 03:00:00,63.918387100000004 2014-04-16 04:00:00,64.49704161 2014-04-16 05:00:00,63.67515316 2014-04-16 06:00:00,62.46829544 2014-04-16 07:00:00,63.58707467 2014-04-16 08:00:00,64.98478124 2014-04-16 09:00:00,64.79823783 2014-04-16 10:00:00,67.37766731 2014-04-16 11:00:00,67.53637026 2014-04-16 12:00:00,68.93675906 2014-04-16 13:00:00,69.01582856 2014-04-16 14:00:00,70.01135347 2014-04-16 15:00:00,70.54341131 2014-04-16 16:00:00,70.35620490000001 2014-04-16 17:00:00,72.05054652 2014-04-16 18:00:00,70.83587447 2014-04-16 19:00:00,71.22103625 2014-04-16 20:00:00,70.22217235 2014-04-16 21:00:00,69.83271805 2014-04-16 22:00:00,67.95233259 2014-04-16 23:00:00,67.65108997 2014-04-17 00:00:00,67.466994 2014-04-17 01:00:00,65.22016644 2014-04-17 02:00:00,65.24342103 2014-04-17 03:00:00,64.62596906 2014-04-17 04:00:00,63.67041499 2014-04-17 05:00:00,64.21771116 2014-04-17 06:00:00,62.40771234 2014-04-17 07:00:00,64.25745568 2014-04-17 08:00:00,63.78224775 2014-04-17 09:00:00,65.71063960000001 2014-04-17 10:00:00,66.77957199 2014-04-17 11:00:00,68.38229729 2014-04-17 12:00:00,68.29797018 2014-04-17 13:00:00,70.41445853 2014-04-17 14:00:00,68.73075749 2014-04-17 15:00:00,70.53796369999998 2014-04-17 16:00:00,69.84495909999998 2014-04-17 17:00:00,69.92419335 2014-04-17 18:00:00,70.06645502 2014-04-17 19:00:00,70.01194478 2014-04-17 20:00:00,70.75213902 2014-04-17 21:00:00,70.23146023 2014-04-17 22:00:00,68.89087654 2014-04-17 23:00:00,68.74794199 2014-04-18 00:00:00,68.6134614 2014-04-18 01:00:00,67.80409959999999 2014-04-18 02:00:00,66.81999556 2014-04-18 03:00:00,66.76963018 2014-04-18 04:00:00,65.69553058 2014-04-18 05:00:00,65.73002042 2014-04-18 06:00:00,65.04376513 2014-04-18 07:00:00,64.66042336 2014-04-18 08:00:00,66.66369506 2014-04-18 09:00:00,66.91478029 2014-04-18 10:00:00,68.35124962 2014-04-18 11:00:00,68.53892428 2014-04-18 12:00:00,69.18079834 2014-04-18 13:00:00,70.04821235 2014-04-18 14:00:00,69.09186246 2014-04-18 15:00:00,70.13679966 2014-04-18 16:00:00,68.64486802 2014-04-18 17:00:00,69.10913357 2014-04-18 18:00:00,69.34877115 2014-04-18 19:00:00,70.06810868 2014-04-18 20:00:00,69.68681363 2014-04-18 21:00:00,69.28946496 2014-04-18 22:00:00,68.10328878 2014-04-18 23:00:00,68.52704977 2014-04-19 00:00:00,67.80210719 2014-04-19 01:00:00,66.29263566 2014-04-19 02:00:00,66.15580573 2014-04-19 03:00:00,65.50262029 2014-04-19 04:00:00,65.67858252 2014-04-19 05:00:00,66.76499604 2014-04-19 06:00:00,65.38745208 2014-04-19 07:00:00,64.95897072 2014-04-19 08:00:00,64.77271857 2014-04-19 09:00:00,64.36173315 2014-04-19 10:00:00,65.1175339 2014-04-19 11:00:00,64.06584001 2014-04-19 12:00:00,63.84447255 2014-04-19 13:00:00,63.69995847 2014-04-19 14:00:00,64.95980589 2014-04-19 15:00:00,64.54564962 2014-04-19 16:00:00,64.92641544 2014-04-19 17:00:00,64.05690668 2014-04-19 18:00:00,65.14093075 2014-04-19 19:00:00,65.37596399 2014-04-19 20:00:00,64.49955643 2014-04-19 21:00:00,64.61511022 2014-04-19 22:00:00,64.38633566 2014-04-19 23:00:00,64.6986036 2014-04-20 00:00:00,63.69621365 2014-04-20 01:00:00,63.46227468 2014-04-20 02:00:00,61.73732749 2014-04-20 03:00:00,62.88858987 2014-04-20 04:00:00,62.02517391 2014-04-20 05:00:00,61.32938908 2014-04-20 06:00:00,61.58004254 2014-04-20 07:00:00,60.95237553 2014-04-20 08:00:00,60.85101193 2014-04-20 09:00:00,59.91009200000001 2014-04-20 10:00:00,60.32414667 2014-04-20 11:00:00,61.24486641 2014-04-20 12:00:00,59.66938197 2014-04-20 13:00:00,61.12053222 2014-04-20 14:00:00,61.88004071 2014-04-20 15:00:00,60.49012871 2014-04-20 16:00:00,61.00233827 2014-04-20 17:00:00,61.765906799999996 2014-04-20 18:00:00,60.26541206 2014-04-20 19:00:00,60.71115886 2014-04-20 20:00:00,60.52159375 2014-04-20 21:00:00,61.72193037 2014-04-20 22:00:00,60.84591691 2014-04-20 23:00:00,60.77650542 2014-04-21 00:00:00,60.2969507 2014-04-21 01:00:00,60.50295653 2014-04-21 02:00:00,60.86537483 2014-04-21 03:00:00,60.31204125 2014-04-21 04:00:00,59.84361371 2014-04-21 05:00:00,60.93695396 2014-04-21 06:00:00,61.29175138 2014-04-21 07:00:00,61.35624139 2014-04-21 08:00:00,62.51476508 2014-04-21 09:00:00,62.43283694 2014-04-21 10:00:00,64.91681271 2014-04-21 11:00:00,65.39698618 2014-04-21 12:00:00,65.915587 2014-04-21 13:00:00,67.29050932 2014-04-21 14:00:00,68.45738752 2014-04-21 15:00:00,70.07377229 2014-04-21 16:00:00,69.70332453 2014-04-21 17:00:00,69.7202728 2014-04-21 18:00:00,69.40144364 2014-04-21 19:00:00,68.60855551 2014-04-21 20:00:00,68.59433384 2014-04-21 21:00:00,67.36680577 2014-04-21 22:00:00,67.03274551 2014-04-21 23:00:00,67.24095409 2014-04-22 00:00:00,65.7964252 2014-04-22 01:00:00,64.99226274 2014-04-22 02:00:00,64.49559793 2014-04-22 03:00:00,65.11700189 2014-04-22 04:00:00,64.3213603 2014-04-22 05:00:00,63.60761024 2014-04-22 06:00:00,64.31240029 2014-04-22 07:00:00,63.6046907 2014-04-22 08:00:00,64.44609818 2014-04-22 09:00:00,65.51557705 2014-04-22 10:00:00,66.98431814 2014-04-22 11:00:00,67.61193771 2014-04-22 12:00:00,69.98132266 2014-04-22 13:00:00,70.67558021 2014-04-22 14:00:00,69.62883752 2014-04-22 15:00:00,69.69713146 2014-04-22 16:00:00,69.91198782 2014-04-22 17:00:00,70.55887454 2014-04-22 18:00:00,70.51507392 2014-04-22 19:00:00,69.61686927 2014-04-22 20:00:00,69.95093901 2014-04-22 21:00:00,68.91740485 2014-04-22 22:00:00,67.98366316 2014-04-22 23:00:00,69.21152689 2014-04-23 00:00:00,68.4994454 2014-04-23 01:00:00,68.2065762 2014-04-23 02:00:00,67.17531475 2014-04-23 03:00:00,66.98745597 2014-04-23 04:00:00,66.01118571 2014-04-23 05:00:00,66.26108706 2014-04-23 06:00:00,66.03229855 2014-04-23 07:00:00,66.26457169 2014-04-23 08:00:00,66.5901253 2014-04-23 09:00:00,67.33860469 2014-04-23 10:00:00,67.71813475 2014-04-23 11:00:00,68.74407883 2014-04-23 12:00:00,70.07146655 2014-04-23 13:00:00,69.09664385 2014-04-23 14:00:00,68.54085218 2014-04-23 15:00:00,68.74793879 2014-04-23 16:00:00,70.2110304 2014-04-23 17:00:00,69.08812898 2014-04-23 18:00:00,71.14090948 2014-04-23 19:00:00,71.35406032 2014-04-23 20:00:00,70.40898557 2014-04-23 21:00:00,70.11680124 2014-04-23 22:00:00,68.45657214 2014-04-23 23:00:00,68.04369977 2014-04-24 00:00:00,67.86825922 2014-04-24 01:00:00,68.25265298 2014-04-24 02:00:00,67.93389846 2014-04-24 03:00:00,67.41557857 2014-04-24 04:00:00,66.82858317 2014-04-24 05:00:00,66.46827942 2014-04-24 06:00:00,66.70529771 2014-04-24 07:00:00,65.99333339 2014-04-24 08:00:00,66.39954920000001 2014-04-24 09:00:00,68.68937881 2014-04-24 10:00:00,68.86981543 2014-04-24 11:00:00,69.28930829 2014-04-24 12:00:00,70.13701442 2014-04-24 13:00:00,70.87920902 2014-04-24 14:00:00,69.73387857 2014-04-24 15:00:00,71.07672883 2014-04-24 16:00:00,70.8997397 2014-04-24 17:00:00,70.81721973 2014-04-24 18:00:00,70.08894813 2014-04-24 19:00:00,71.49812440000002 2014-04-24 20:00:00,70.33872212 2014-04-24 21:00:00,69.97998584 2014-04-24 22:00:00,69.11046806 2014-04-24 23:00:00,68.18636306 2014-04-25 00:00:00,67.39351909 2014-04-25 01:00:00,66.57525861 2014-04-25 02:00:00,67.73318644 2014-04-25 03:00:00,66.68982673 2014-04-25 04:00:00,65.83218116 2014-04-25 05:00:00,65.95237266 2014-04-25 06:00:00,67.28099527 2014-04-25 07:00:00,66.90419491 2014-04-25 08:00:00,67.80676658 2014-04-25 09:00:00,68.71115712 2014-04-25 10:00:00,70.02939458 2014-04-25 11:00:00,69.32625844 2014-04-25 12:00:00,70.95509984 2014-04-25 13:00:00,70.33649459 2014-04-25 14:00:00,70.46790053 2014-04-25 15:00:00,71.4753647 2014-04-25 16:00:00,71.6850702 2014-04-25 17:00:00,70.43496647 2014-04-25 18:00:00,70.80912379 2014-04-25 19:00:00,70.67649218 2014-04-25 20:00:00,70.53630655 2014-04-25 21:00:00,70.9107218 2014-04-25 22:00:00,69.72934336 2014-04-25 23:00:00,69.6017667 2014-04-26 00:00:00,69.48880205 2014-04-26 01:00:00,67.24793666 2014-04-26 02:00:00,67.33153476 2014-04-26 03:00:00,66.89338891 2014-04-26 04:00:00,66.56130689 2014-04-26 05:00:00,66.53741504 2014-04-26 06:00:00,67.13725522 2014-04-26 07:00:00,66.5594858 2014-04-26 08:00:00,65.90565072 2014-04-26 09:00:00,65.53921771 2014-04-26 10:00:00,65.83948867 2014-04-26 11:00:00,64.57393058 2014-04-26 12:00:00,65.47092598 2014-04-26 13:00:00,64.06228730000001 2014-04-26 14:00:00,65.61321875 2014-04-26 15:00:00,65.0033148 2014-04-26 16:00:00,65.06987305 2014-04-26 17:00:00,65.49571691 2014-04-26 18:00:00,64.89058829999999 2014-04-26 19:00:00,63.93327257 2014-04-26 20:00:00,65.74230017 2014-04-26 21:00:00,64.87334743 2014-04-26 22:00:00,64.59101491 2014-04-26 23:00:00,64.52446439 2014-04-27 00:00:00,65.86073905 2014-04-27 01:00:00,65.70163338 2014-04-27 02:00:00,65.48002454 2014-04-27 03:00:00,65.01981817 2014-04-27 04:00:00,64.07651163 2014-04-27 05:00:00,64.19020524 2014-04-27 06:00:00,64.54513799 2014-04-27 07:00:00,64.16276662 2014-04-27 08:00:00,64.68808942 2014-04-27 09:00:00,65.0067767 2014-04-27 10:00:00,64.86726485 2014-04-27 11:00:00,65.27562701 2014-04-27 12:00:00,64.76188253 2014-04-27 13:00:00,64.21479337 2014-04-27 14:00:00,64.22497124 2014-04-27 15:00:00,63.48983416 2014-04-27 16:00:00,64.02881119 2014-04-27 17:00:00,65.14115001 2014-04-27 18:00:00,64.16580322 2014-04-27 19:00:00,63.82552427 2014-04-27 20:00:00,64.51645768 2014-04-27 21:00:00,64.81548712 2014-04-27 22:00:00,63.65811355 2014-04-27 23:00:00,63.04274263 2014-04-28 00:00:00,63.66900707 2014-04-28 01:00:00,62.84663436 2014-04-28 02:00:00,64.00274294 2014-04-28 03:00:00,64.17028398 2014-04-28 04:00:00,64.29074432 2014-04-28 05:00:00,62.8534311 2014-04-28 06:00:00,64.27748755 2014-04-28 07:00:00,63.93818963 2014-04-28 08:00:00,64.19242071 2014-04-28 09:00:00,66.39555183 2014-04-28 10:00:00,66.35592434 2014-04-28 11:00:00,66.93708398 2014-04-28 12:00:00,67.94603672 2014-04-28 13:00:00,67.83616225 2014-04-28 14:00:00,68.02972643 2014-04-28 15:00:00,67.63528784 2014-04-28 16:00:00,67.95345262 2014-04-28 17:00:00,67.94164899 2014-04-28 18:00:00,66.31355879 2014-04-28 19:00:00,66.90239851 2014-04-28 20:00:00,67.92545865 2014-04-28 21:00:00,66.24886617 2014-04-28 22:00:00,66.61769712 2014-04-28 23:00:00,66.45853965 2014-04-29 00:00:00,65.70015178 2014-04-29 01:00:00,66.15509081 2014-04-29 02:00:00,64.37093221 2014-04-29 03:00:00,64.73766535 2014-04-29 04:00:00,63.71676928 2014-04-29 05:00:00,65.12909065 2014-04-29 06:00:00,64.59083625 2014-04-29 07:00:00,65.39479955 2014-04-29 08:00:00,64.99259943 2014-04-29 09:00:00,63.55132406 2014-04-29 10:00:00,63.86318351 2014-04-29 11:00:00,63.4598629 2014-04-29 12:00:00,63.08150923 2014-04-29 13:00:00,63.48047822 2014-04-29 14:00:00,64.82342973 2014-04-29 15:00:00,64.45813978 2014-04-29 16:00:00,63.80209508 2014-04-29 17:00:00,65.04887616 2014-04-29 18:00:00,65.88072103 2014-04-29 19:00:00,65.4814587 2014-04-29 20:00:00,64.19984122 2014-04-29 21:00:00,65.87838087 2014-04-29 22:00:00,64.72572253 2014-04-29 23:00:00,65.00936847 2014-04-30 00:00:00,64.37972197 2014-04-30 01:00:00,64.81705324 2014-04-30 02:00:00,64.01853731 2014-04-30 03:00:00,62.59835239 2014-04-30 04:00:00,62.15358748 2014-04-30 05:00:00,63.65464859 2014-04-30 06:00:00,62.66869499 2014-04-30 07:00:00,63.19330523 2014-04-30 08:00:00,64.24502053 2014-04-30 09:00:00,65.1453243 2014-04-30 10:00:00,64.9329398 2014-04-30 11:00:00,66.64151484 2014-04-30 12:00:00,66.82120203 2014-04-30 13:00:00,67.1960497 2014-04-30 14:00:00,66.13772358 2014-04-30 15:00:00,66.37318638 2014-04-30 16:00:00,67.38361772 2014-04-30 17:00:00,67.98871109999999 2014-04-30 18:00:00,66.25593843 2014-04-30 19:00:00,65.92849928 2014-04-30 20:00:00,67.21492219 2014-04-30 21:00:00,66.24671438 2014-04-30 22:00:00,66.61478769 2014-04-30 23:00:00,64.84814958 2014-05-01 00:00:00,64.94889814 2014-05-01 01:00:00,64.45625398 2014-05-01 02:00:00,63.9798679 2014-05-01 03:00:00,64.26732464 2014-05-01 04:00:00,64.59177699 2014-05-01 05:00:00,65.37702424 2014-05-01 06:00:00,65.19211401 2014-05-01 07:00:00,65.37953893 2014-05-01 08:00:00,65.05709023 2014-05-01 09:00:00,65.87109317 2014-05-01 10:00:00,66.54947805 2014-05-01 11:00:00,66.4332683 2014-05-01 12:00:00,67.94196795 2014-05-01 13:00:00,67.73779434 2014-05-01 14:00:00,67.94409258 2014-05-01 15:00:00,68.59569962 2014-05-01 16:00:00,67.76281833 2014-05-01 17:00:00,66.3713461 2014-05-01 18:00:00,66.45491031 2014-05-01 19:00:00,67.7664687 2014-05-01 20:00:00,66.30486725 2014-05-01 21:00:00,66.77500592 2014-05-01 22:00:00,66.08791142 2014-05-01 23:00:00,66.23633214 2014-05-02 00:00:00,66.08952394 2014-05-02 01:00:00,65.49363114 2014-05-02 02:00:00,65.20911118 2014-05-02 03:00:00,64.65270388 2014-05-02 04:00:00,65.68346791 2014-05-02 05:00:00,64.53848669 2014-05-02 06:00:00,64.87436222 2014-05-02 07:00:00,65.83693065 2014-05-02 08:00:00,66.45562134 2014-05-02 09:00:00,66.22132242 2014-05-02 10:00:00,67.40617703 2014-05-02 11:00:00,66.82972449 2014-05-02 12:00:00,66.3484439 2014-05-02 13:00:00,66.56058031 2014-05-02 14:00:00,67.87466603 2014-05-02 15:00:00,68.36875479999999 2014-05-02 16:00:00,68.32191349 2014-05-02 17:00:00,68.61482576 2014-05-02 18:00:00,67.74306346 2014-05-02 19:00:00,67.08645996 2014-05-02 20:00:00,68.34330065 2014-05-02 21:00:00,68.30007946 2014-05-02 22:00:00,68.22785404 2014-05-02 23:00:00,66.69875824 2014-05-03 00:00:00,66.4911086 2014-05-03 01:00:00,66.35595511 2014-05-03 02:00:00,66.81821492 2014-05-03 03:00:00,65.56948969 2014-05-03 04:00:00,66.61559763 2014-05-03 05:00:00,65.6976645 2014-05-03 06:00:00,64.59377619 2014-05-03 07:00:00,64.74378706 2014-05-03 08:00:00,65.25902071 2014-05-03 09:00:00,64.47503572 2014-05-03 10:00:00,64.61145531 2014-05-03 11:00:00,63.68596001 2014-05-03 12:00:00,65.43821188 2014-05-03 13:00:00,64.12205423 2014-05-03 14:00:00,65.42301205 2014-05-03 15:00:00,65.95634267 2014-05-03 16:00:00,65.81969209 2014-05-03 17:00:00,64.85601416 2014-05-03 18:00:00,65.00620928 2014-05-03 19:00:00,63.94392708 2014-05-03 20:00:00,65.20208745 2014-05-03 21:00:00,63.84740672 2014-05-03 22:00:00,63.75022634 2014-05-03 23:00:00,64.87600042 2014-05-04 00:00:00,64.18060217 2014-05-04 01:00:00,64.07250966 2014-05-04 02:00:00,62.43332813 2014-05-04 03:00:00,62.52641171 2014-05-04 04:00:00,62.30957888 2014-05-04 05:00:00,62.35436891 2014-05-04 06:00:00,63.42459056 2014-05-04 07:00:00,63.09408094 2014-05-04 08:00:00,62.58243369 2014-05-04 09:00:00,63.37961637 2014-05-04 10:00:00,62.86781634 2014-05-04 11:00:00,62.88417215 2014-05-04 12:00:00,62.11991599 2014-05-04 13:00:00,62.70773678 2014-05-04 14:00:00,63.59298753 2014-05-04 15:00:00,62.71663598 2014-05-04 16:00:00,63.60890306 2014-05-04 17:00:00,62.82802932 2014-05-04 18:00:00,63.79858076 2014-05-04 19:00:00,63.11692463 2014-05-04 20:00:00,62.12890815 2014-05-04 21:00:00,61.59769629 2014-05-04 22:00:00,62.8583145 2014-05-04 23:00:00,61.41615236 2014-05-05 00:00:00,61.49160445 2014-05-05 01:00:00,61.82814205 2014-05-05 02:00:00,61.69737845 2014-05-05 03:00:00,61.65254063 2014-05-05 04:00:00,60.606883700000004 2014-05-05 05:00:00,60.47320097 2014-05-05 06:00:00,61.5530172 2014-05-05 07:00:00,62.01910222 2014-05-05 08:00:00,61.23608102 2014-05-05 09:00:00,63.67999575 2014-05-05 10:00:00,63.36326181 2014-05-05 11:00:00,64.13721032 2014-05-05 12:00:00,64.5332446 2014-05-05 13:00:00,64.19481423 2014-05-05 14:00:00,65.1361502 2014-05-05 15:00:00,65.97596267 2014-05-05 16:00:00,65.85552001 2014-05-05 17:00:00,66.32755106 2014-05-05 18:00:00,66.92969566 2014-05-05 19:00:00,67.2613918 2014-05-05 20:00:00,65.80789035 2014-05-05 21:00:00,66.20385124 2014-05-05 22:00:00,66.51044071 2014-05-05 23:00:00,64.8207324 2014-05-06 00:00:00,63.59220664 2014-05-06 01:00:00,63.23531713 2014-05-06 02:00:00,62.49046863 2014-05-06 03:00:00,62.28369414 2014-05-06 04:00:00,63.30749881 2014-05-06 05:00:00,62.80276256 2014-05-06 06:00:00,62.34187092 2014-05-06 07:00:00,64.17473372 2014-05-06 08:00:00,63.97093501 2014-05-06 09:00:00,65.0523434 2014-05-06 10:00:00,64.75464232 2014-05-06 11:00:00,65.04876411 2014-05-06 12:00:00,65.74920338 2014-05-06 13:00:00,66.40186825 2014-05-06 14:00:00,66.18664212 2014-05-06 15:00:00,67.31747692 2014-05-06 16:00:00,66.95425995 2014-05-06 17:00:00,66.93790428 2014-05-06 18:00:00,67.73969822 2014-05-06 19:00:00,66.72610529 2014-05-06 20:00:00,66.08638956 2014-05-06 21:00:00,66.71634147 2014-05-06 22:00:00,65.14686479999999 2014-05-06 23:00:00,64.64265197 2014-05-07 00:00:00,65.62693199 2014-05-07 01:00:00,64.08219838 2014-05-07 02:00:00,64.54200752 2014-05-07 03:00:00,65.09258433 2014-05-07 04:00:00,64.43853993 2014-05-07 05:00:00,64.62081306 2014-05-07 06:00:00,63.29588419 2014-05-07 07:00:00,64.71917156 2014-05-07 08:00:00,63.73179147 2014-05-07 09:00:00,66.29709464 2014-05-07 10:00:00,67.19427577 2014-05-07 11:00:00,67.06897531 2014-05-07 12:00:00,68.72099133 2014-05-07 13:00:00,69.96068224 2014-05-07 14:00:00,70.56685636 2014-05-07 15:00:00,69.75004488 2014-05-07 16:00:00,69.17335133 2014-05-07 17:00:00,70.50844769 2014-05-07 18:00:00,70.24540175 2014-05-07 19:00:00,70.81293524 2014-05-07 20:00:00,69.94704581 2014-05-07 21:00:00,68.86682809 2014-05-07 22:00:00,68.39329009 2014-05-07 23:00:00,66.6067577 2014-05-08 00:00:00,66.76001378 2014-05-08 01:00:00,66.27637613 2014-05-08 02:00:00,65.75512541 2014-05-08 03:00:00,65.81007339 2014-05-08 04:00:00,65.37270606 2014-05-08 05:00:00,66.28889617 2014-05-08 06:00:00,66.23410255 2014-05-08 07:00:00,64.91234651 2014-05-08 08:00:00,67.05133706 2014-05-08 09:00:00,67.83863065 2014-05-08 10:00:00,68.10943196 2014-05-08 11:00:00,69.65642273 2014-05-08 12:00:00,70.60573585 2014-05-08 13:00:00,70.62927012 2014-05-08 14:00:00,70.21115072 2014-05-08 15:00:00,70.29113189 2014-05-08 16:00:00,70.64550484 2014-05-08 17:00:00,71.27645212 2014-05-08 18:00:00,71.83727293 2014-05-08 19:00:00,71.46726041 2014-05-08 20:00:00,69.75939304 2014-05-08 21:00:00,70.11417736 2014-05-08 22:00:00,70.05504972 2014-05-08 23:00:00,69.37027812 2014-05-09 00:00:00,67.98228281 2014-05-09 01:00:00,67.7865791 2014-05-09 02:00:00,68.43446290000001 2014-05-09 03:00:00,68.07785549 2014-05-09 04:00:00,67.81285784 2014-05-09 05:00:00,67.56774369 2014-05-09 06:00:00,66.24760777 2014-05-09 07:00:00,67.65004294 2014-05-09 08:00:00,67.05143804 2014-05-09 09:00:00,69.05576366 2014-05-09 10:00:00,70.10149255 2014-05-09 11:00:00,70.63274013 2014-05-09 12:00:00,71.06084806 2014-05-09 13:00:00,71.07378866 2014-05-09 14:00:00,69.87334432 2014-05-09 15:00:00,70.92486991 2014-05-09 16:00:00,71.2245648 2014-05-09 17:00:00,70.78867373 2014-05-09 18:00:00,71.99197043 2014-05-09 19:00:00,70.89590208 2014-05-09 20:00:00,72.38733933 2014-05-09 21:00:00,70.14675317 2014-05-09 22:00:00,69.74583888 2014-05-09 23:00:00,69.43160284 2014-05-10 00:00:00,68.23254059 2014-05-10 01:00:00,69.47792142 2014-05-10 02:00:00,68.91530719 2014-05-10 03:00:00,68.35492212 2014-05-10 04:00:00,68.39336374 2014-05-10 05:00:00,68.42272702 2014-05-10 06:00:00,67.0775277 2014-05-10 07:00:00,66.90356792 2014-05-10 08:00:00,66.37013021 2014-05-10 09:00:00,68.21760218 2014-05-10 10:00:00,67.53453251 2014-05-10 11:00:00,67.42839785 2014-05-10 12:00:00,66.96098515 2014-05-10 13:00:00,67.33616722 2014-05-10 14:00:00,66.84359334 2014-05-10 15:00:00,65.89084398 2014-05-10 16:00:00,66.81261725 2014-05-10 17:00:00,65.32919958 2014-05-10 18:00:00,65.92892671 2014-05-10 19:00:00,66.58894429 2014-05-10 20:00:00,65.10538195 2014-05-10 21:00:00,65.63011787 2014-05-10 22:00:00,65.81492917 2014-05-10 23:00:00,65.57018764 2014-05-11 00:00:00,63.91974669 2014-05-11 01:00:00,64.51176296 2014-05-11 02:00:00,64.43387227 2014-05-11 03:00:00,64.33383818 2014-05-11 04:00:00,64.57554395 2014-05-11 05:00:00,65.03499427 2014-05-11 06:00:00,63.11467108 2014-05-11 07:00:00,63.87061555 2014-05-11 08:00:00,64.64784774 2014-05-11 09:00:00,63.64523071 2014-05-11 10:00:00,64.05141919 2014-05-11 11:00:00,62.7828001 2014-05-11 12:00:00,63.82347474 2014-05-11 13:00:00,63.58691465 2014-05-11 14:00:00,62.08829654 2014-05-11 15:00:00,63.01928506 2014-05-11 16:00:00,63.90711168 2014-05-11 17:00:00,63.07839314 2014-05-11 18:00:00,62.69840054 2014-05-11 19:00:00,61.72789308 2014-05-11 20:00:00,62.289274 2014-05-11 21:00:00,63.08826676 2014-05-11 22:00:00,61.55557216 2014-05-11 23:00:00,63.00932675 2014-05-12 00:00:00,62.18412627 2014-05-12 01:00:00,62.39660826 2014-05-12 02:00:00,61.14767562 2014-05-12 03:00:00,61.13299926 2014-05-12 04:00:00,62.20171526 2014-05-12 05:00:00,61.03856972 2014-05-12 06:00:00,62.82075925 2014-05-12 07:00:00,62.287278799999996 2014-05-12 08:00:00,61.74042901 2014-05-12 09:00:00,64.34959977 2014-05-12 10:00:00,66.00850439 2014-05-12 11:00:00,65.98530817 2014-05-12 12:00:00,67.03067426 2014-05-12 13:00:00,68.11149661 2014-05-12 14:00:00,68.18592974 2014-05-12 15:00:00,69.09194409999999 2014-05-12 16:00:00,70.46158593 2014-05-12 17:00:00,68.55542525 2014-05-12 18:00:00,68.18348692 2014-05-12 19:00:00,68.79946301 2014-05-12 20:00:00,68.94392853 2014-05-12 21:00:00,68.37912217 2014-05-12 22:00:00,68.03272736 2014-05-12 23:00:00,66.7522962 2014-05-13 00:00:00,65.70093962 2014-05-13 01:00:00,65.23145055 2014-05-13 02:00:00,65.58334605 2014-05-13 03:00:00,64.43826513 2014-05-13 04:00:00,64.76745107 2014-05-13 05:00:00,63.63936741 2014-05-13 06:00:00,64.99365642 2014-05-13 07:00:00,65.42791053 2014-05-13 08:00:00,64.54368408 2014-05-13 09:00:00,65.7424681 2014-05-13 10:00:00,68.2490268 2014-05-13 11:00:00,68.81523729 2014-05-13 12:00:00,69.61897566 2014-05-13 13:00:00,69.27540087 2014-05-13 14:00:00,69.46898521 2014-05-13 15:00:00,70.39851654 2014-05-13 16:00:00,70.72748205 2014-05-13 17:00:00,70.07376172 2014-05-13 18:00:00,70.43111508 2014-05-13 19:00:00,69.18648323 2014-05-13 20:00:00,69.33720712 2014-05-13 21:00:00,68.52452572 2014-05-13 22:00:00,68.66320083 2014-05-13 23:00:00,67.39728285 2014-05-14 00:00:00,68.3111207 2014-05-14 01:00:00,67.1601394 2014-05-14 02:00:00,66.97372975 2014-05-14 03:00:00,66.48481188 2014-05-14 04:00:00,64.8808456 2014-05-14 05:00:00,64.70801495 2014-05-14 06:00:00,64.5459563 2014-05-14 07:00:00,65.67840491 2014-05-14 08:00:00,65.05875661 2014-05-14 09:00:00,67.03858825 2014-05-14 10:00:00,69.05639384 2014-05-14 11:00:00,68.99189609999999 2014-05-14 12:00:00,69.97788528 2014-05-14 13:00:00,70.175432 2014-05-14 14:00:00,68.16664370000001 2014-05-14 15:00:00,68.57300267 2014-05-14 16:00:00,69.83526008 2014-05-14 17:00:00,70.27480031 2014-05-14 18:00:00,70.20609040000001 2014-05-14 19:00:00,69.40921677 2014-05-14 20:00:00,70.27798951 2014-05-14 21:00:00,68.30333556 2014-05-14 22:00:00,68.09324242 2014-05-14 23:00:00,68.36429597 2014-05-15 00:00:00,67.72416061 2014-05-15 01:00:00,67.8085136 2014-05-15 02:00:00,68.26962214 2014-05-15 03:00:00,66.64600393 2014-05-15 04:00:00,67.56801604 2014-05-15 05:00:00,67.36462946 2014-05-15 06:00:00,64.81152604 2014-05-15 07:00:00,66.53328753 2014-05-15 08:00:00,67.08670333 2014-05-15 09:00:00,66.85800575 2014-05-15 10:00:00,69.47031702 2014-05-15 11:00:00,70.77703377 2014-05-15 12:00:00,71.07003789 2014-05-15 13:00:00,70.78202725 2014-05-15 14:00:00,70.7083186 2014-05-15 15:00:00,70.96353620000002 2014-05-15 16:00:00,70.2180453 2014-05-15 17:00:00,71.14732103 2014-05-15 18:00:00,71.78243404 2014-05-15 19:00:00,70.94431125 2014-05-15 20:00:00,70.25408586 2014-05-15 21:00:00,69.97385592 2014-05-15 22:00:00,71.20814017 2014-05-15 23:00:00,70.28109027 2014-05-16 00:00:00,68.42534022 2014-05-16 01:00:00,68.14026632 2014-05-16 02:00:00,68.31516842 2014-05-16 03:00:00,68.80554576 2014-05-16 04:00:00,68.70805438 2014-05-16 05:00:00,68.21126844 2014-05-16 06:00:00,67.02311979 2014-05-16 07:00:00,68.13634615 2014-05-16 08:00:00,68.50810021 2014-05-16 09:00:00,68.78472332 2014-05-16 10:00:00,70.26313322 2014-05-16 11:00:00,69.48894493 2014-05-16 12:00:00,69.78809126 2014-05-16 13:00:00,69.96723012 2014-05-16 14:00:00,69.74249505 2014-05-16 15:00:00,70.69057352 2014-05-16 16:00:00,70.63243838 2014-05-16 17:00:00,70.67548445 2014-05-16 18:00:00,71.48839758 2014-05-16 19:00:00,70.21791457 2014-05-16 20:00:00,69.93428517 2014-05-16 21:00:00,70.22321349 2014-05-16 22:00:00,70.68873242 2014-05-16 23:00:00,68.72204475 2014-05-17 00:00:00,69.45225691 2014-05-17 01:00:00,68.41224787 2014-05-17 02:00:00,68.36748732 2014-05-17 03:00:00,67.63648402 2014-05-17 04:00:00,67.66201157 2014-05-17 05:00:00,65.90307781 2014-05-17 06:00:00,66.21437481 2014-05-17 07:00:00,65.82644339 2014-05-17 08:00:00,65.50506941 2014-05-17 09:00:00,65.74501564 2014-05-17 10:00:00,65.36640537 2014-05-17 11:00:00,65.90704699 2014-05-17 12:00:00,63.77248723 2014-05-17 13:00:00,64.55949992 2014-05-17 14:00:00,64.5256338 2014-05-17 15:00:00,64.67400160000001 2014-05-17 16:00:00,62.79405286 2014-05-17 17:00:00,64.31443601 2014-05-17 18:00:00,62.55982025 2014-05-17 19:00:00,62.74968304 2014-05-17 20:00:00,62.73063243 2014-05-17 21:00:00,63.65406403 2014-05-17 22:00:00,63.42070867 2014-05-17 23:00:00,61.94114934 2014-05-18 00:00:00,62.89319989 2014-05-18 01:00:00,61.96136235 2014-05-18 02:00:00,61.33631343 2014-05-18 03:00:00,61.95426535 2014-05-18 04:00:00,61.38195858 2014-05-18 05:00:00,62.38443786 2014-05-18 06:00:00,61.0947659 2014-05-18 07:00:00,61.36331427 2014-05-18 08:00:00,60.59300743 2014-05-18 09:00:00,60.43062383 2014-05-18 10:00:00,60.58242408 2014-05-18 11:00:00,60.31117133 2014-05-18 12:00:00,59.76775547 2014-05-18 13:00:00,59.86404445 2014-05-18 14:00:00,60.24787212 2014-05-18 15:00:00,60.87471092 2014-05-18 16:00:00,60.28561460000001 2014-05-18 17:00:00,59.52889185 2014-05-18 18:00:00,59.31666076 2014-05-18 19:00:00,59.14006513 2014-05-18 20:00:00,59.33578729 2014-05-18 21:00:00,58.5039748 2014-05-18 22:00:00,59.10760819 2014-05-18 23:00:00,58.16034228 2014-05-19 00:00:00,58.42363855 2014-05-19 01:00:00,57.8619057 2014-05-19 02:00:00,58.63929497 2014-05-19 03:00:00,59.07469099 2014-05-19 04:00:00,60.49092523 2014-05-19 05:00:00,59.71185823 2014-05-19 06:00:00,60.37589367 2014-05-19 07:00:00,60.17109245 2014-05-19 08:00:00,60.29668226 2014-05-19 09:00:00,62.032778 2014-05-19 10:00:00,63.30565358 2014-05-19 11:00:00,66.46108503 2014-05-19 12:00:00,68.26175947 2014-05-19 13:00:00,70.71157984 2014-05-19 14:00:00,71.27550282 2014-05-19 15:00:00,72.16832368 2014-05-19 16:00:00,71.18424703 2014-05-19 17:00:00,72.14062818 2014-05-19 18:00:00,71.21197512 2014-05-19 19:00:00,69.21714746 2014-05-19 20:00:00,68.35285951 2014-05-19 21:00:00,65.94373646 2014-05-19 22:00:00,63.16581259 2014-05-19 23:00:00,63.4757356 2014-05-20 00:00:00,63.46895245 2014-05-20 01:00:00,61.42920712 2014-05-20 02:00:00,61.67708270000001 2014-05-20 03:00:00,61.78693595 2014-05-20 04:00:00,60.88555024 2014-05-20 05:00:00,61.49993807 2014-05-20 06:00:00,61.05565421 2014-05-20 07:00:00,61.47083928 2014-05-20 08:00:00,62.30626718 2014-05-20 09:00:00,62.87057976 2014-05-20 10:00:00,63.400864500000004 2014-05-20 11:00:00,67.54217170000001 2014-05-20 12:00:00,69.71421777 2014-05-20 13:00:00,69.51084605 2014-05-20 14:00:00,71.30924261 2014-05-20 15:00:00,71.54100964 2014-05-20 16:00:00,72.16153754 2014-05-20 17:00:00,70.88654096 2014-05-20 18:00:00,70.91172121 2014-05-20 19:00:00,72.16415303 2014-05-20 20:00:00,70.52750726 2014-05-20 21:00:00,67.87157133 2014-05-20 22:00:00,68.33303676 2014-05-20 23:00:00,66.90035458 2014-05-21 00:00:00,66.99561858 2014-05-21 01:00:00,65.40626786 2014-05-21 02:00:00,64.32359927 2014-05-21 03:00:00,63.56365044 2014-05-21 04:00:00,64.11854793 2014-05-21 05:00:00,62.70245453 2014-05-21 06:00:00,62.74071071 2014-05-21 07:00:00,64.71093807 2014-05-21 08:00:00,65.83512160000001 2014-05-21 09:00:00,66.70320421 2014-05-21 10:00:00,68.58472225 2014-05-21 11:00:00,71.45729537 2014-05-21 12:00:00,71.66573622 2014-05-21 13:00:00,72.395749 2014-05-21 14:00:00,73.90430952 2014-05-21 15:00:00,74.74593843 2014-05-21 16:00:00,74.30063758 2014-05-21 17:00:00,72.59432304 2014-05-21 18:00:00,72.22398046 2014-05-21 19:00:00,72.32603021 2014-05-21 20:00:00,73.63394052 2014-05-21 21:00:00,71.85085806 2014-05-21 22:00:00,70.92319988 2014-05-21 23:00:00,69.67101298 2014-05-22 00:00:00,69.59055937 2014-05-22 01:00:00,68.10096848 2014-05-22 02:00:00,67.59063877 2014-05-22 03:00:00,67.28802796 2014-05-22 04:00:00,65.50415242 2014-05-22 05:00:00,64.98749725 2014-05-22 06:00:00,63.84289079999999 2014-05-22 07:00:00,65.27590436 2014-05-22 08:00:00,65.24654655 2014-05-22 09:00:00,69.10167387 2014-05-22 10:00:00,70.78848187 2014-05-22 11:00:00,71.86870384 2014-05-22 12:00:00,71.94794239 2014-05-22 13:00:00,73.677598 2014-05-22 14:00:00,72.98770276 2014-05-22 15:00:00,74.42875737 2014-05-22 16:00:00,72.64701052 2014-05-22 17:00:00,73.13696747 2014-05-22 18:00:00,72.89262523 2014-05-22 19:00:00,71.9456771 2014-05-22 20:00:00,72.75306445 2014-05-22 21:00:00,72.16946467 2014-05-22 22:00:00,70.85768581 2014-05-22 23:00:00,68.89846747 2014-05-23 00:00:00,69.76426088 2014-05-23 01:00:00,67.22274865 2014-05-23 02:00:00,66.84469742 2014-05-23 03:00:00,65.7499409 2014-05-23 04:00:00,65.72828867 2014-05-23 05:00:00,64.56403526 2014-05-23 06:00:00,64.82619471 2014-05-23 07:00:00,65.55274567 2014-05-23 08:00:00,66.27026002 2014-05-23 09:00:00,68.11559824 2014-05-23 10:00:00,69.89230339 2014-05-23 11:00:00,70.85563315 2014-05-23 12:00:00,72.70590985 2014-05-23 13:00:00,73.19388671 2014-05-23 14:00:00,71.69026293 2014-05-23 15:00:00,71.85985178 2014-05-23 16:00:00,73.21648743 2014-05-23 17:00:00,72.87018134 2014-05-23 18:00:00,72.78601953 2014-05-23 19:00:00,72.3176002 2014-05-23 20:00:00,72.96734992 2014-05-23 21:00:00,72.9728198 2014-05-23 22:00:00,71.42381462 2014-05-23 23:00:00,71.5294155 2014-05-24 00:00:00,70.53019592 2014-05-24 01:00:00,67.44737298 2014-05-24 02:00:00,68.10673337 2014-05-24 03:00:00,66.54488604 2014-05-24 04:00:00,65.99044378 2014-05-24 05:00:00,65.57383653 2014-05-24 06:00:00,63.7342402 2014-05-24 07:00:00,64.60030306 2014-05-24 08:00:00,63.81887969 2014-05-24 09:00:00,62.53317986 2014-05-24 10:00:00,62.63998719 2014-05-24 11:00:00,63.36766655 2014-05-24 12:00:00,62.24567585 2014-05-24 13:00:00,62.11892222 2014-05-24 14:00:00,60.93392081 2014-05-24 15:00:00,60.93279727 2014-05-24 16:00:00,61.2825587 2014-05-24 17:00:00,61.86767484 2014-05-24 18:00:00,61.09664628 2014-05-24 19:00:00,62.27844332 2014-05-24 20:00:00,61.90070789 2014-05-24 21:00:00,62.39310154 2014-05-24 22:00:00,62.30137458 2014-05-24 23:00:00,62.56461867 2014-05-25 00:00:00,62.72498472 2014-05-25 01:00:00,61.83288929 2014-05-25 02:00:00,61.81999904 2014-05-25 03:00:00,61.63311346 2014-05-25 04:00:00,62.64551718 2014-05-25 05:00:00,62.36561658 2014-05-25 06:00:00,60.95432355 2014-05-25 07:00:00,62.2887861 2014-05-25 08:00:00,61.79099234 2014-05-25 09:00:00,61.2350892 2014-05-25 10:00:00,61.70115537 2014-05-25 11:00:00,62.50943034 2014-05-25 12:00:00,61.01775642 2014-05-25 13:00:00,62.17679039 2014-05-25 14:00:00,62.78656524 2014-05-25 15:00:00,61.01764809 2014-05-25 16:00:00,62.19066364 2014-05-25 17:00:00,62.3200289 2014-05-25 18:00:00,61.24446489 2014-05-25 19:00:00,61.04660004 2014-05-25 20:00:00,62.45615333 2014-05-25 21:00:00,60.84765432 2014-05-25 22:00:00,62.16201772 2014-05-25 23:00:00,61.47244327 2014-05-26 00:00:00,62.07873026 2014-05-26 01:00:00,61.76786 2014-05-26 02:00:00,61.14309718 2014-05-26 03:00:00,61.00938428 2014-05-26 04:00:00,61.95202076 2014-05-26 05:00:00,62.03764829 2014-05-26 06:00:00,61.473338899999995 2014-05-26 07:00:00,61.51732548 2014-05-26 08:00:00,63.77163674 2014-05-26 09:00:00,66.16135606 2014-05-26 10:00:00,68.07227638 2014-05-26 11:00:00,69.81799259 2014-05-26 12:00:00,72.0269253 2014-05-26 13:00:00,71.77669121 2014-05-26 14:00:00,72.19859519 2014-05-26 15:00:00,72.23311654 2014-05-26 16:00:00,72.51360720000002 2014-05-26 17:00:00,73.97990891 2014-05-26 18:00:00,72.13547844 2014-05-26 19:00:00,73.53223604 2014-05-26 20:00:00,71.63600005 2014-05-26 21:00:00,70.98695943 2014-05-26 22:00:00,69.02377801 2014-05-26 23:00:00,68.51109537 2014-05-27 00:00:00,67.10193816 2014-05-27 01:00:00,66.822098 2014-05-27 02:00:00,65.9294706 2014-05-27 03:00:00,67.12169762 2014-05-27 04:00:00,65.4066128 2014-05-27 05:00:00,64.94669438 2014-05-27 06:00:00,64.01596424 2014-05-27 07:00:00,63.637964399999994 2014-05-27 08:00:00,64.58194931 2014-05-27 09:00:00,66.86987932 2014-05-27 10:00:00,70.10010407 2014-05-27 11:00:00,71.53161261 2014-05-27 12:00:00,72.17782106 2014-05-27 13:00:00,72.68078037 2014-05-27 14:00:00,71.96861391 2014-05-27 15:00:00,72.11443201 2014-05-27 16:00:00,73.00783047 2014-05-27 17:00:00,73.08768457 2014-05-27 18:00:00,71.32243816 2014-05-27 19:00:00,71.49022791 2014-05-27 20:00:00,71.8134752 2014-05-27 21:00:00,69.75022022 2014-05-27 22:00:00,69.68719735 2014-05-27 23:00:00,68.98695874 2014-05-28 00:00:00,68.63483818 2014-05-28 01:00:00,67.0000815 2014-05-28 02:00:00,66.52891628 2014-05-28 03:00:00,67.65632279 2014-05-28 04:00:00,65.74329837 2014-05-28 05:00:00,66.24037883 2014-05-28 06:00:00,64.78402266 2014-05-28 07:00:00,65.6458741 2014-05-28 08:00:00,67.47256826 2014-05-28 09:00:00,68.03307954 2014-05-28 10:00:00,70.45571697 2014-05-28 11:00:00,72.37020644 2014-05-28 12:00:00,72.17295622 2014-05-28 13:00:00,72.04656545 2014-05-28 14:00:00,71.82522648 2014-05-28 15:00:00,72.58408858 ================================================ FILE: workspace/anomaly_detector/datasets/selected/level_change/ec2_cpu_utilization_825cc2.csv ================================================ timestamp,value 2014-04-10 00:04:00,91.958 2014-04-10 00:09:00,94.79799999999999 2014-04-10 00:14:00,92.208 2014-04-10 00:19:00,93.72200000000001 2014-04-10 00:24:00,93.042 2014-04-10 00:29:00,92.958 2014-04-10 00:34:00,95.708 2014-04-10 00:39:00,95.25 2014-04-10 00:44:00,94.458 2014-04-10 00:49:00,92.75 2014-04-10 00:54:00,94.208 2014-04-10 00:59:00,92.75 2014-04-10 01:04:00,94.376 2014-04-10 01:09:00,92.792 2014-04-10 01:14:00,91.666 2014-04-10 01:19:00,87.542 2014-04-10 01:24:00,90.75 2014-04-10 01:29:00,91.65 2014-04-10 01:34:00,90.06200000000004 2014-04-10 01:39:00,93.416 2014-04-10 01:44:00,89.904 2014-04-10 01:49:00,90.542 2014-04-10 01:54:00,90.62799999999999 2014-04-10 01:59:00,91.166 2014-04-10 02:04:00,90.5 2014-04-10 02:09:00,89.166 2014-04-10 02:14:00,90.292 2014-04-10 02:19:00,90.208 2014-04-10 02:24:00,93.626 2014-04-10 02:29:00,93.624 2014-04-10 02:34:00,93.756 2014-04-10 02:39:00,93.542 2014-04-10 02:44:00,92.042 2014-04-10 02:49:00,90.93799999999999 2014-04-10 02:54:00,91.376 2014-04-10 02:59:00,92.666 2014-04-10 03:04:00,94.42 2014-04-10 03:09:00,95.584 2014-04-10 03:19:00,90.62 2014-04-10 03:24:00,93.478 2014-04-10 03:29:00,94.126 2014-04-10 03:34:00,93.338 2014-04-10 03:39:00,93.458 2014-04-10 03:44:00,92.166 2014-04-10 03:49:00,91.584 2014-04-10 03:54:00,94.33 2014-04-10 03:59:00,95.084 2014-04-10 04:04:00,93.958 2014-04-10 04:09:00,94.714 2014-04-10 04:14:00,92.23200000000001 2014-04-10 04:19:00,95.2 2014-04-10 04:24:00,92.458 2014-04-10 04:29:00,94.444 2014-04-10 04:34:00,86.736 2014-04-10 04:39:00,93.072 2014-04-10 04:44:00,95.876 2014-04-10 04:49:00,93.994 2014-04-10 04:54:00,94.104 2014-04-10 04:59:00,93.75 2014-04-10 05:04:00,90.852 2014-04-10 05:09:00,89.584 2014-04-10 05:14:00,94.542 2014-04-10 05:19:00,91.97399999999999 2014-04-10 05:24:00,93.0 2014-04-10 05:29:00,92.262 2014-04-10 05:34:00,93.25 2014-04-10 05:39:00,93.624 2014-04-10 05:44:00,93.436 2014-04-10 05:49:00,92.774 2014-04-10 05:54:00,91.624 2014-04-10 05:59:00,93.042 2014-04-10 06:04:00,91.542 2014-04-10 06:09:00,93.74799999999999 2014-04-10 06:14:00,93.042 2014-04-10 06:19:00,92.8 2014-04-10 06:24:00,90.11 2014-04-10 06:29:00,94.64399999999999 2014-04-10 06:34:00,90.542 2014-04-10 06:39:00,93.292 2014-04-10 06:44:00,91.14 2014-04-10 06:49:00,91.126 2014-04-10 06:54:00,91.5 2014-04-10 06:59:00,95.042 2014-04-10 07:04:00,95.712 2014-04-10 07:09:00,91.506 2014-04-10 07:14:00,94.9625 2014-04-10 07:19:00,91.848 2014-04-10 07:24:00,92.416 2014-04-10 07:29:00,95.126 2014-04-10 07:34:00,93.584 2014-04-10 07:39:00,93.834 2014-04-10 07:44:00,94.708 2014-04-10 07:49:00,94.5 2014-04-10 07:54:00,93.45200000000001 2014-04-10 07:59:00,88.086 2014-04-10 08:04:00,91.08 2014-04-10 08:09:00,89.584 2014-04-10 08:14:00,91.238 2014-04-10 08:19:00,91.932 2014-04-10 08:24:00,89.458 2014-04-10 08:29:00,87.75 2014-04-10 08:34:00,92.666 2014-04-10 08:39:00,94.5 2014-04-10 08:44:00,92.162 2014-04-10 08:49:00,92.648 2014-04-10 08:54:00,94.352 2014-04-10 08:59:00,92.916 2014-04-10 09:04:00,90.874 2014-04-10 09:09:00,92.334 2014-04-10 09:14:00,93.75 2014-04-10 09:19:00,93.77 2014-04-10 09:24:00,93.48 2014-04-10 09:29:00,94.22 2014-04-10 09:34:00,94.014 2014-04-10 09:39:00,94.666 2014-04-10 09:44:00,94.516 2014-04-10 09:49:00,96.75 2014-04-10 09:54:00,93.834 2014-04-10 09:59:00,91.666 2014-04-10 10:04:00,90.8 2014-04-10 10:09:00,96.042 2014-04-10 10:14:00,85.42200000000003 2014-04-10 10:19:00,91.73 2014-04-10 10:24:00,90.61 2014-04-10 10:29:00,90.25 2014-04-10 10:34:00,90.03399999999998 2014-04-10 10:39:00,89.33200000000002 2014-04-10 10:44:00,91.766 2014-04-10 10:49:00,94.084 2014-04-10 10:54:00,91.6525 2014-04-10 10:59:00,93.75 2014-04-10 11:04:00,93.71799999999999 2014-04-10 11:09:00,94.11200000000001 2014-04-10 11:14:00,93.46600000000001 2014-04-10 11:19:00,95.416 2014-04-10 11:24:00,94.5 2014-04-10 11:29:00,96.67399999999999 2014-04-10 11:34:00,93.212 2014-04-10 11:39:00,91.166 2014-04-10 11:44:00,93.678 2014-04-10 11:49:00,93.55 2014-04-10 11:54:00,93.374 2014-04-10 11:59:00,95.554 2014-04-10 12:04:00,94.292 2014-04-10 12:09:00,90.164 2014-04-10 12:14:00,88.75 2014-04-10 12:19:00,92.458 2014-04-10 12:24:00,96.21 2014-04-10 12:29:00,91.646 2014-04-10 12:34:00,94.792 2014-04-10 12:39:00,92.53399999999999 2014-04-10 12:44:00,89.084 2014-04-10 12:49:00,91.75 2014-04-10 12:54:00,92.75 2014-04-10 12:59:00,89.568 2014-04-10 13:04:00,90.65799999999999 2014-04-10 13:09:00,88.024 2014-04-10 13:14:00,91.542 2014-04-10 13:19:00,94.25 2014-04-10 13:24:00,94.124 2014-04-10 13:29:00,91.708 2014-04-10 13:34:00,92.584 2014-04-10 13:39:00,92.63799999999999 2014-04-10 13:44:00,93.794 2014-04-10 13:49:00,96.514 2014-04-10 13:54:00,95.20200000000001 2014-04-10 13:59:00,96.18799999999999 2014-04-10 14:04:00,89.3 2014-04-10 14:09:00,90.74600000000001 2014-04-10 14:14:00,88.25 2014-04-10 14:19:00,88.834 2014-04-10 14:24:00,89.834 2014-04-10 14:29:00,93.5 2014-04-10 14:34:00,95.5 2014-04-10 14:39:00,89.542 2014-04-10 14:44:00,89.052 2014-04-10 14:49:00,87.454 2014-04-10 14:54:00,86.876 2014-04-10 14:59:00,86.958 2014-04-10 15:04:00,89.928 2014-04-10 15:09:00,90.5 2014-04-10 15:14:00,90.124 2014-04-10 15:19:00,90.58 2014-04-10 15:24:00,92.0 2014-04-10 15:29:00,88.708 2014-04-10 15:34:00,89.962 2014-04-10 15:39:00,92.50200000000001 2014-04-10 15:44:00,94.0 2014-04-10 15:49:00,94.804 2014-04-10 15:54:00,89.542 2014-04-10 15:59:00,94.0 2014-04-10 16:04:00,94.292 2014-04-10 16:09:00,93.916 2014-04-10 16:14:00,91.458 2014-04-10 16:19:00,92.14 2014-04-10 16:24:00,93.208 2014-04-10 16:29:00,96.292 2014-04-10 16:34:00,90.666 2014-04-10 16:39:00,89.458 2014-04-10 16:44:00,95.292 2014-04-10 16:49:00,95.626 2014-04-10 16:54:00,93.0 2014-04-10 16:59:00,93.75 2014-04-10 17:04:00,95.292 2014-04-10 17:09:00,95.208 2014-04-10 17:14:00,95.542 2014-04-10 17:19:00,93.0 2014-04-10 17:24:00,92.236 2014-04-10 17:29:00,94.25 2014-04-10 17:34:00,92.28200000000001 2014-04-10 17:39:00,94.714 2014-04-10 17:44:00,94.126 2014-04-10 17:49:00,96.25 2014-04-10 17:54:00,93.834 2014-04-10 17:59:00,94.46 2014-04-10 18:04:00,95.542 2014-04-10 18:09:00,98.042 2014-04-10 18:14:00,95.766 2014-04-10 18:19:00,93.458 2014-04-10 18:24:00,92.85799999999999 2014-04-10 18:29:00,95.584 2014-04-10 18:34:00,93.12799999999999 2014-04-10 18:39:00,91.88799999999999 2014-04-10 18:44:00,92.984 2014-04-10 18:49:00,94.32600000000001 2014-04-10 18:54:00,95.876 2014-04-10 18:59:00,93.584 2014-04-10 19:04:00,95.15799999999999 2014-04-10 19:09:00,95.416 2014-04-10 19:14:00,93.166 2014-04-10 19:19:00,96.25 2014-04-10 19:24:00,93.376 2014-04-10 19:29:00,93.084 2014-04-10 19:34:00,93.146 2014-04-10 19:39:00,95.596 2014-04-10 19:44:00,94.336 2014-04-10 19:49:00,91.458 2014-04-10 19:54:00,93.292 2014-04-10 19:59:00,95.126 2014-04-10 20:04:00,92.976 2014-04-10 20:09:00,94.32600000000001 2014-04-10 20:14:00,89.538 2014-04-10 20:19:00,92.12799999999999 2014-04-10 20:24:00,94.14399999999999 2014-04-10 20:29:00,89.488 2014-04-10 20:34:00,90.314 2014-04-10 20:39:00,95.0 2014-04-10 20:44:00,93.208 2014-04-10 20:49:00,94.042 2014-04-10 20:54:00,92.626 2014-04-10 20:59:00,95.398 2014-04-10 21:04:00,93.52799999999999 2014-04-10 21:09:00,93.5 2014-04-10 21:14:00,95.63 2014-04-10 21:19:00,93.292 2014-04-10 21:24:00,95.292 2014-04-10 21:29:00,95.01 2014-04-10 21:34:00,92.384 2014-04-10 21:39:00,93.75 2014-04-10 21:44:00,96.124 2014-04-10 21:49:00,93.42 2014-04-10 21:54:00,91.854 2014-04-10 21:59:00,90.5 2014-04-10 22:04:00,92.666 2014-04-10 22:09:00,93.956 2014-04-10 22:14:00,91.792 2014-04-10 22:19:00,95.0 2014-04-10 22:24:00,95.626 2014-04-10 22:29:00,95.084 2014-04-10 22:34:00,94.834 2014-04-10 22:39:00,95.566 2014-04-10 22:44:00,94.454 2014-04-10 22:49:00,95.0 2014-04-10 22:54:00,93.334 2014-04-10 22:59:00,94.10799999999999 2014-04-10 23:04:00,93.596 2014-04-10 23:09:00,92.92200000000001 2014-04-10 23:14:00,92.414 2014-04-10 23:19:00,92.478 2014-04-10 23:24:00,92.22 2014-04-10 23:29:00,93.876 2014-04-10 23:34:00,95.58 2014-04-10 23:39:00,95.166 2014-04-10 23:44:00,94.5 2014-04-10 23:49:00,95.04799999999999 2014-04-10 23:54:00,93.42399999999999 2014-04-10 23:59:00,93.01 2014-04-11 00:04:00,93.774 2014-04-11 00:09:00,95.704 2014-04-11 00:14:00,95.21600000000001 2014-04-11 00:19:00,93.572 2014-04-11 00:24:00,92.056 2014-04-11 00:29:00,93.904 2014-04-11 00:34:00,95.792 2014-04-11 00:39:00,93.374 2014-04-11 00:44:00,91.666 2014-04-11 00:49:00,95.708 2014-04-11 00:54:00,93.042 2014-04-11 00:59:00,96.0 2014-04-11 01:04:00,95.10799999999999 2014-04-11 01:09:00,93.77799999999999 2014-04-11 01:14:00,91.71600000000001 2014-04-11 01:19:00,91.666 2014-04-11 01:24:00,95.75 2014-04-11 01:29:00,97.042 2014-04-11 01:34:00,93.624 2014-04-11 01:39:00,93.4 2014-04-11 01:44:00,89.75399999999998 2014-04-11 01:49:00,94.334 2014-04-11 01:54:00,96.522 2014-04-11 01:59:00,93.516 2014-04-11 02:04:00,95.25 2014-04-11 02:09:00,95.914 2014-04-11 02:14:00,97.084 2014-04-11 02:19:00,94.91799999999999 2014-04-11 02:24:00,93.766 2014-04-11 02:29:00,96.056 2014-04-11 02:34:00,96.376 2014-04-11 02:39:00,96.166 2014-04-11 02:44:00,94.166 2014-04-11 02:49:00,96.49600000000001 2014-04-11 02:54:00,95.042 2014-04-11 02:59:00,95.584 2014-04-11 03:04:00,96.726 2014-04-11 03:09:00,96.056 2014-04-11 03:14:00,95.17200000000001 2014-04-11 03:19:00,93.876 2014-04-11 03:24:00,95.958 2014-04-11 03:29:00,95.708 2014-04-11 03:34:00,94.008 2014-04-11 03:39:00,92.084 2014-04-11 03:44:00,96.932 2014-04-11 03:49:00,92.79 2014-04-11 03:54:00,94.006 2014-04-11 03:59:00,94.874 2014-04-11 04:04:00,93.126 2014-04-11 04:09:00,95.834 2014-04-11 04:14:00,93.624 2014-04-11 04:19:00,95.554 2014-04-11 04:24:00,95.758 2014-04-11 04:29:00,95.402 2014-04-11 04:34:00,93.916 2014-04-11 04:39:00,98.042 2014-04-11 04:44:00,93.29 2014-04-11 04:49:00,92.792 2014-04-11 04:54:00,97.374 2014-04-11 04:59:00,97.374 2014-04-11 05:04:00,96.38600000000001 2014-04-11 05:09:00,95.584 2014-04-11 05:14:00,96.618 2014-04-11 05:19:00,94.5 2014-04-11 05:24:00,93.792 2014-04-11 05:29:00,96.084 2014-04-11 05:34:00,97.584 2014-04-11 05:39:00,97.21600000000001 2014-04-11 05:44:00,92.916 2014-04-11 05:49:00,97.042 2014-04-11 05:54:00,97.166 2014-04-11 05:59:00,94.852 2014-04-11 06:04:00,92.626 2014-04-11 06:09:00,96.916 2014-04-11 06:14:00,95.416 2014-04-11 06:19:00,92.77 2014-04-11 06:24:00,93.626 2014-04-11 06:29:00,95.708 2014-04-11 06:34:00,94.52799999999999 2014-04-11 06:39:00,93.56200000000001 2014-04-11 06:44:00,94.102 2014-04-11 06:49:00,93.986 2014-04-11 06:54:00,94.584 2014-04-11 06:59:00,92.22399999999999 2014-04-11 07:04:00,92.958 2014-04-11 07:09:00,93.042 2014-04-11 07:14:00,88.542 2014-04-11 07:19:00,92.042 2014-04-11 07:24:00,94.542 2014-04-11 07:29:00,95.958 2014-04-11 07:34:00,96.876 2014-04-11 07:39:00,94.708 2014-04-11 07:44:00,94.0 2014-04-11 07:49:00,93.958 2014-04-11 07:54:00,95.34200000000001 2014-04-11 07:59:00,91.304 2014-04-11 08:04:00,92.352 2014-04-11 08:09:00,90.41 2014-04-11 08:14:00,92.476 2014-04-11 08:19:00,94.71600000000001 2014-04-11 08:24:00,94.542 2014-04-11 08:29:00,93.042 2014-04-11 08:34:00,91.292 2014-04-11 08:39:00,95.604 2014-04-11 08:44:00,96.78200000000001 2014-04-11 08:49:00,96.458 2014-04-11 08:54:00,94.916 2014-04-11 08:59:00,92.916 2014-04-11 09:04:00,92.416 2014-04-11 09:09:00,96.428 2014-04-11 09:14:00,95.374 2014-04-11 09:19:00,93.10600000000001 2014-04-11 09:24:00,91.39 2014-04-11 09:29:00,93.374 2014-04-11 09:34:00,92.744 2014-04-11 09:39:00,96.12 2014-04-11 09:44:00,95.542 2014-04-11 09:49:00,96.4 2014-04-11 09:54:00,94.24600000000001 2014-04-11 09:59:00,93.13 2014-04-11 10:04:00,92.404 2014-04-11 10:09:00,96.166 2014-04-11 10:14:00,93.594 2014-04-11 10:19:00,89.416 2014-04-11 10:24:00,94.084 2014-04-11 10:29:00,94.524 2014-04-11 10:34:00,94.492 2014-04-11 10:39:00,93.584 2014-04-11 10:44:00,92.958 2014-04-11 10:49:00,92.75 2014-04-11 10:54:00,93.416 2014-04-11 10:59:00,94.75 2014-04-11 11:04:00,93.67200000000001 2014-04-11 11:09:00,93.374 2014-04-11 11:14:00,95.12200000000001 2014-04-11 11:19:00,92.666 2014-04-11 11:24:00,95.666 2014-04-11 11:29:00,96.834 2014-04-11 11:34:00,94.256 2014-04-11 11:39:00,93.39399999999999 2014-04-11 11:44:00,94.126 2014-04-11 11:49:00,96.17200000000001 2014-04-11 11:54:00,93.7 2014-04-11 11:59:00,93.064 2014-04-11 12:04:00,96.0 2014-04-11 12:09:00,95.436 2014-04-11 12:14:00,95.98 2014-04-11 12:19:00,94.53399999999999 2014-04-11 12:24:00,87.5 2014-04-11 12:29:00,91.208 2014-04-11 12:34:00,93.39200000000001 2014-04-11 12:39:00,91.524 2014-04-11 12:44:00,93.83200000000001 2014-04-11 12:49:00,90.66799999999999 2014-04-11 12:54:00,92.25 2014-04-11 12:59:00,93.99600000000001 2014-04-11 13:04:00,91.5 2014-04-11 13:09:00,92.816 2014-04-11 13:14:00,91.148 2014-04-11 13:19:00,89.06200000000004 2014-04-11 13:24:00,91.1 2014-04-11 13:29:00,93.0 2014-04-11 13:34:00,87.834 2014-04-11 13:39:00,90.584 2014-04-11 13:44:00,92.624 2014-04-11 13:49:00,89.292 2014-04-11 13:54:00,91.416 2014-04-11 13:59:00,91.624 2014-04-11 14:04:00,88.5 2014-04-11 14:09:00,91.5 2014-04-11 14:14:00,93.126 2014-04-11 14:19:00,91.536 2014-04-11 14:24:00,92.89200000000001 2014-04-11 14:29:00,89.35 2014-04-11 14:34:00,88.584 2014-04-11 14:39:00,89.52799999999998 2014-04-11 14:44:00,89.042 2014-04-11 14:49:00,92.55 2014-04-11 14:54:00,90.712 2014-04-11 14:59:00,92.208 2014-04-11 15:04:00,93.084 2014-04-11 15:09:00,90.82 2014-04-11 15:14:00,88.542 2014-04-11 15:19:00,89.75 2014-04-11 15:24:00,96.708 2014-04-11 15:29:00,93.75 2014-04-11 15:34:00,92.458 2014-04-11 15:39:00,94.53399999999999 2014-04-11 15:44:00,95.454 2014-04-11 15:49:00,92.084 2014-04-11 15:54:00,92.584 2014-04-11 15:59:00,90.124 2014-04-11 16:04:00,88.48200000000001 2014-04-11 16:09:00,89.376 2014-04-11 16:14:00,90.626 2014-04-11 16:19:00,86.064 2014-04-11 16:24:00,89.012 2014-04-11 16:29:00,87.656 2014-04-11 16:34:00,91.634 2014-04-11 16:39:00,87.08 2014-04-11 16:44:00,88.958 2014-04-11 16:49:00,90.084 2014-04-11 16:54:00,92.126 2014-04-11 16:59:00,93.624 2014-04-11 17:04:00,88.416 2014-04-11 17:09:00,90.75 2014-04-11 17:14:00,90.104 2014-04-11 17:19:00,90.5 2014-04-11 17:24:00,88.916 2014-04-11 17:29:00,88.666 2014-04-11 17:34:00,90.39399999999999 2014-04-11 17:39:00,92.666 2014-04-11 17:44:00,92.75 2014-04-11 17:49:00,90.334 2014-04-11 17:54:00,92.25 2014-04-11 17:59:00,97.084 2014-04-11 18:04:00,93.012 2014-04-11 18:09:00,94.212 2014-04-11 18:14:00,95.61200000000001 2014-04-11 18:19:00,95.834 2014-04-11 18:24:00,96.084 2014-04-11 18:29:00,93.75399999999999 2014-04-11 18:34:00,95.042 2014-04-11 18:39:00,95.75 2014-04-11 18:44:00,95.834 2014-04-11 18:49:00,96.292 2014-04-11 18:54:00,95.91799999999999 2014-04-11 18:59:00,95.334 2014-04-11 19:04:00,93.292 2014-04-11 19:09:00,95.376 2014-04-11 19:14:00,95.626 2014-04-11 19:19:00,96.67399999999999 2014-04-11 19:24:00,92.43 2014-04-11 19:29:00,93.542 2014-04-11 19:34:00,94.958 2014-04-11 19:39:00,96.416 2014-04-11 19:44:00,96.818 2014-04-11 19:49:00,94.074 2014-04-11 19:54:00,94.98 2014-04-11 19:59:00,97.25 2014-04-11 20:04:00,94.96 2014-04-11 20:09:00,96.708 2014-04-11 20:14:00,95.374 2014-04-11 20:19:00,94.376 2014-04-11 20:24:00,93.086 2014-04-11 20:29:00,93.458 2014-04-11 20:34:00,94.958 2014-04-11 20:39:00,95.71799999999999 2014-04-11 20:44:00,95.14200000000001 2014-04-11 20:49:00,95.494 2014-04-11 20:54:00,93.792 2014-04-11 20:59:00,95.376 2014-04-11 21:04:00,92.14399999999999 2014-04-11 21:09:00,93.46600000000001 2014-04-11 21:14:00,94.64200000000001 2014-04-11 21:19:00,93.89399999999999 2014-04-11 21:24:00,93.542 2014-04-11 21:29:00,94.208 2014-04-11 21:34:00,91.166 2014-04-11 21:39:00,90.126 2014-04-11 21:44:00,95.618 2014-04-11 21:49:00,91.71 2014-04-11 21:54:00,94.014 2014-04-11 21:59:00,93.958 2014-04-11 22:04:00,90.75 2014-04-11 22:09:00,93.708 2014-04-11 22:14:00,89.78399999999998 2014-04-11 22:19:00,92.874 2014-04-11 22:24:00,91.184 2014-04-11 22:29:00,94.916 2014-04-11 22:34:00,89.666 2014-04-11 22:39:00,90.458 2014-04-11 22:44:00,90.084 2014-04-11 22:49:00,91.04799999999999 2014-04-11 22:54:00,90.792 2014-04-11 22:59:00,90.626 2014-04-11 23:04:00,88.708 2014-04-11 23:09:00,92.33 2014-04-11 23:14:00,91.292 2014-04-11 23:19:00,93.416 2014-04-11 23:24:00,90.5 2014-04-11 23:29:00,89.874 2014-04-11 23:34:00,91.124 2014-04-11 23:39:00,91.584 2014-04-11 23:44:00,94.708 2014-04-11 23:49:00,91.5 2014-04-11 23:54:00,91.446 2014-04-11 23:59:00,90.708 2014-04-12 00:04:00,93.32799999999999 2014-04-12 00:09:00,90.86399999999999 2014-04-12 00:14:00,96.836 2014-04-12 00:19:00,94.402 2014-04-12 00:24:00,95.47 2014-04-12 00:29:00,94.416 2014-04-12 00:34:00,96.176 2014-04-12 00:39:00,95.792 2014-04-12 00:44:00,92.2 2014-04-12 00:49:00,95.962 2014-04-12 00:54:00,96.79799999999999 2014-04-12 00:59:00,91.95200000000001 2014-04-12 01:04:00,91.148 2014-04-12 01:09:00,96.458 2014-04-12 01:14:00,95.042 2014-04-12 01:19:00,95.458 2014-04-12 01:24:00,95.162 2014-04-12 01:29:00,92.084 2014-04-12 01:34:00,96.97 2014-04-12 01:39:00,97.042 2014-04-12 01:44:00,94.25 2014-04-12 01:49:00,97.042 2014-04-12 01:54:00,94.916 2014-04-12 01:59:00,95.126 2014-04-12 02:04:00,95.21 2014-04-12 02:09:00,96.666 2014-04-12 02:14:00,95.63 2014-04-12 02:19:00,95.18799999999999 2014-04-12 02:24:00,94.416 2014-04-12 02:29:00,95.78 2014-04-12 02:34:00,96.958 2014-04-12 02:39:00,94.07600000000001 2014-04-12 02:44:00,96.334 2014-04-12 02:49:00,96.074 2014-04-12 02:54:00,95.708 2014-04-12 02:59:00,95.3 2014-04-12 03:04:00,92.126 2014-04-12 03:09:00,94.57600000000001 2014-04-12 03:14:00,94.67399999999999 2014-04-12 03:19:00,94.084 2014-04-12 03:24:00,94.834 2014-04-12 03:29:00,97.126 2014-04-12 03:34:00,97.792 2014-04-12 03:39:00,97.458 2014-04-12 03:44:00,96.208 2014-04-12 03:49:00,96.916 2014-04-12 03:54:00,96.792 2014-04-12 03:59:00,95.212 2014-04-12 04:04:00,97.42 2014-04-12 04:09:00,95.094 2014-04-12 04:14:00,95.306 2014-04-12 04:19:00,96.24600000000001 2014-04-12 04:24:00,94.57600000000001 2014-04-12 04:29:00,94.5 2014-04-12 04:34:00,95.916 2014-04-12 04:39:00,96.25 2014-04-12 04:44:00,96.376 2014-04-12 04:49:00,95.61399999999999 2014-04-12 04:54:00,93.96799999999999 2014-04-12 04:59:00,96.88 2014-04-12 05:04:00,96.132 2014-04-12 05:09:00,96.166 2014-04-12 05:14:00,95.846 2014-04-12 05:19:00,95.54799999999999 2014-04-12 05:24:00,94.0 2014-04-12 05:29:00,93.584 2014-04-12 05:34:00,97.676 2014-04-12 05:39:00,95.75 2014-04-12 05:44:00,95.416 2014-04-12 05:49:00,92.626 2014-04-12 05:54:00,97.626 2014-04-12 05:59:00,95.166 2014-04-12 06:04:00,93.292 2014-04-12 06:09:00,92.052 2014-04-12 06:14:00,92.39200000000001 2014-04-12 06:19:00,93.24799999999999 2014-04-12 06:24:00,90.458 2014-04-12 06:29:00,93.022 2014-04-12 06:34:00,93.084 2014-04-12 06:39:00,93.334 2014-04-12 06:44:00,94.208 2014-04-12 06:49:00,89.666 2014-04-12 06:54:00,94.708 2014-04-12 06:59:00,92.772 2014-04-12 07:04:00,94.774 2014-04-12 07:09:00,96.5 2014-04-12 07:14:00,95.042 2014-04-12 07:19:00,92.584 2014-04-12 07:24:00,93.33 2014-04-12 07:29:00,96.042 2014-04-12 07:34:00,93.5 2014-04-12 07:39:00,95.708 2014-04-12 07:44:00,95.126 2014-04-12 07:49:00,96.0 2014-04-12 07:54:00,93.916 2014-04-12 07:59:00,94.708 2014-04-12 08:04:00,95.334 2014-04-12 08:09:00,97.17 2014-04-12 08:14:00,95.604 2014-04-12 08:19:00,95.64399999999999 2014-04-12 08:24:00,93.238 2014-04-12 08:29:00,95.72 2014-04-12 08:34:00,95.708 2014-04-12 08:39:00,96.416 2014-04-12 08:44:00,95.708 2014-04-12 08:49:00,95.584 2014-04-12 08:54:00,96.726 2014-04-12 08:59:00,96.714 2014-04-12 09:04:00,95.23200000000001 2014-04-12 09:09:00,94.426 2014-04-12 09:14:00,93.626 2014-04-12 09:19:00,95.958 2014-04-12 09:24:00,94.666 2014-04-12 09:29:00,93.596 2014-04-12 09:34:00,93.334 2014-04-12 09:39:00,94.292 2014-04-12 09:44:00,95.208 2014-04-12 09:49:00,96.416 2014-04-12 09:54:00,94.17200000000001 2014-04-12 09:59:00,94.87 2014-04-12 10:04:00,93.5 2014-04-12 10:09:00,91.458 2014-04-12 10:14:00,91.292 2014-04-12 10:19:00,92.916 2014-04-12 10:24:00,95.334 2014-04-12 10:29:00,94.208 2014-04-12 10:34:00,96.292 2014-04-12 10:39:00,94.416 2014-04-12 10:44:00,92.97399999999999 2014-04-12 10:49:00,94.25 2014-04-12 10:54:00,97.708 2014-04-12 10:59:00,95.096 2014-04-12 11:04:00,95.406 2014-04-12 11:09:00,94.572 2014-04-12 11:14:00,95.494 2014-04-12 11:19:00,94.208 2014-04-12 11:24:00,94.124 2014-04-12 11:29:00,95.046 2014-04-12 11:34:00,96.584 2014-04-12 11:39:00,94.432 2014-04-12 11:44:00,96.43 2014-04-12 11:49:00,97.042 2014-04-12 11:54:00,96.31200000000001 2014-04-12 11:59:00,95.292 2014-04-12 12:04:00,94.042 2014-04-12 12:09:00,96.78 2014-04-12 12:14:00,95.666 2014-04-12 12:19:00,95.0 2014-04-12 12:24:00,94.67200000000001 2014-04-12 12:29:00,95.75 2014-04-12 12:34:00,96.834 2014-04-12 12:39:00,95.876 2014-04-12 12:44:00,95.834 2014-04-12 12:49:00,95.958 2014-04-12 12:54:00,93.03 2014-04-12 12:59:00,93.042 2014-04-12 13:04:00,96.166 2014-04-12 13:09:00,96.0 2014-04-12 13:14:00,96.334 2014-04-12 13:19:00,95.126 2014-04-12 13:24:00,94.25 2014-04-12 13:29:00,93.334 2014-04-12 13:34:00,95.124 2014-04-12 13:39:00,95.626 2014-04-12 13:44:00,95.542 2014-04-12 13:49:00,96.126 2014-04-12 13:54:00,92.71799999999999 2014-04-12 13:59:00,96.292 2014-04-12 14:04:00,94.916 2014-04-12 14:09:00,96.416 2014-04-12 14:14:00,92.166 2014-04-12 14:19:00,93.666 2014-04-12 14:24:00,95.292 2014-04-12 14:29:00,95.25 2014-04-12 14:34:00,94.334 2014-04-12 14:39:00,93.126 2014-04-12 14:44:00,96.876 2014-04-12 14:49:00,94.458 2014-04-12 14:54:00,93.958 2014-04-12 14:59:00,96.376 2014-04-12 15:04:00,92.766 2014-04-12 15:09:00,95.49 2014-04-12 15:14:00,92.45200000000001 2014-04-12 15:19:00,92.126 2014-04-12 15:24:00,95.06200000000001 2014-04-12 15:29:00,95.064 2014-04-12 15:34:00,92.75 2014-04-12 15:39:00,94.854 2014-04-12 15:44:00,96.81200000000001 2014-04-12 15:49:00,93.456 2014-04-12 15:54:00,94.49600000000001 2014-04-12 15:59:00,94.63799999999999 2014-04-12 16:04:00,94.874 2014-04-12 16:09:00,94.876 2014-04-12 16:14:00,93.084 2014-04-12 16:19:00,94.666 2014-04-12 16:24:00,94.868 2014-04-12 16:29:00,95.126 2014-04-12 16:34:00,91.542 2014-04-12 16:39:00,88.97200000000002 2014-04-12 16:44:00,91.788 2014-04-12 16:49:00,93.126 2014-04-12 16:54:00,93.956 2014-04-12 16:59:00,94.334 2014-04-12 17:04:00,93.238 2014-04-12 17:09:00,94.042 2014-04-12 17:14:00,97.25 2014-04-12 17:19:00,93.876 2014-04-12 17:24:00,97.382 2014-04-12 17:29:00,96.664 2014-04-12 17:34:00,97.00399999999999 2014-04-12 17:39:00,96.876 2014-04-12 17:44:00,95.042 2014-04-12 17:49:00,95.458 2014-04-12 17:54:00,96.792 2014-04-12 17:59:00,93.042 2014-04-12 18:04:00,96.64200000000001 2014-04-12 18:09:00,95.436 2014-04-12 18:14:00,95.31200000000001 2014-04-12 18:19:00,94.5 2014-04-12 18:24:00,94.78200000000001 2014-04-12 18:29:00,94.65 2014-04-12 18:34:00,89.28399999999998 2014-04-12 18:39:00,90.51 2014-04-12 18:44:00,91.334 2014-04-12 18:49:00,95.166 2014-04-12 18:54:00,94.292 2014-04-12 18:59:00,93.834 2014-04-12 19:04:00,95.542 2014-04-12 19:09:00,94.794 2014-04-12 19:14:00,95.01799999999999 2014-04-12 19:19:00,94.876 2014-04-12 19:24:00,96.084 2014-04-12 19:29:00,95.042 2014-04-12 19:34:00,93.584 2014-04-12 19:39:00,95.66799999999999 2014-04-12 19:44:00,95.666 2014-04-12 19:49:00,95.042 2014-04-12 19:54:00,95.70200000000001 2014-04-12 19:59:00,94.912 2014-04-12 20:04:00,94.512 2014-04-12 20:09:00,94.542 2014-04-12 20:14:00,93.204 2014-04-12 20:19:00,96.506 2014-04-12 20:24:00,93.88 2014-04-12 20:29:00,95.70200000000001 2014-04-12 20:34:00,93.666 2014-04-12 20:39:00,91.834 2014-04-12 20:44:00,95.572 2014-04-12 20:49:00,94.334 2014-04-12 20:54:00,95.542 2014-04-12 20:59:00,96.084 2014-04-12 21:04:00,95.334 2014-04-12 21:09:00,94.376 2014-04-12 21:14:00,92.24799999999999 2014-04-12 21:19:00,95.626 2014-04-12 21:24:00,93.624 2014-04-12 21:29:00,92.38 2014-04-12 21:34:00,92.374 2014-04-12 21:39:00,95.708 2014-04-12 21:44:00,94.586 2014-04-12 21:49:00,92.586 2014-04-12 21:54:00,91.458 2014-04-12 21:59:00,95.292 2014-04-12 22:04:00,96.0 2014-04-12 22:09:00,96.708 2014-04-12 22:14:00,91.708 2014-04-12 22:19:00,93.772 2014-04-12 22:24:00,96.734 2014-04-12 22:29:00,94.416 2014-04-12 22:34:00,94.0 2014-04-12 22:39:00,95.54 2014-04-12 22:44:00,95.166 2014-04-12 22:49:00,95.58 2014-04-12 22:54:00,96.41799999999999 2014-04-12 22:59:00,92.85600000000001 2014-04-12 23:04:00,94.604 2014-04-12 23:09:00,91.876 2014-04-12 23:14:00,92.708 2014-04-12 23:19:00,94.416 2014-04-12 23:24:00,92.402 2014-04-12 23:29:00,96.624 2014-04-12 23:34:00,96.584 2014-04-12 23:39:00,94.666 2014-04-12 23:44:00,96.042 2014-04-12 23:49:00,93.97200000000001 2014-04-12 23:54:00,99.118 2014-04-12 23:59:00,95.042 2014-04-13 00:04:00,95.318 2014-04-13 00:09:00,96.126 2014-04-13 00:14:00,94.34 2014-04-13 00:19:00,95.85 2014-04-13 00:24:00,94.042 2014-04-13 00:29:00,94.0 2014-04-13 00:34:00,93.542 2014-04-13 00:39:00,96.666 2014-04-13 00:44:00,97.292 2014-04-13 00:49:00,95.75 2014-04-13 00:54:00,96.416 2014-04-13 00:59:00,95.52799999999999 2014-04-13 01:04:00,96.13600000000001 2014-04-13 01:09:00,95.148 2014-04-13 01:14:00,93.51799999999999 2014-04-13 01:19:00,94.458 2014-04-13 01:24:00,96.042 2014-04-13 01:29:00,95.874 2014-04-13 01:34:00,95.598 2014-04-13 01:39:00,96.042 2014-04-13 01:44:00,95.75 2014-04-13 01:49:00,93.166 2014-04-13 01:54:00,97.176 2014-04-13 01:59:00,93.874 2014-04-13 02:04:00,93.666 2014-04-13 02:09:00,96.39 2014-04-13 02:14:00,94.124 2014-04-13 02:19:00,93.736 2014-04-13 02:24:00,95.708 2014-04-13 02:29:00,96.166 2014-04-13 02:34:00,95.708 2014-04-13 02:39:00,95.666 2014-04-13 02:44:00,96.208 2014-04-13 02:49:00,95.166 2014-04-13 02:54:00,96.64200000000001 2014-04-13 02:59:00,96.666 2014-04-13 03:04:00,93.624 2014-04-13 03:09:00,94.5 2014-04-13 03:14:00,95.396 2014-04-13 03:19:00,92.774 2014-04-13 03:24:00,94.958 2014-04-13 03:29:00,94.916 2014-04-13 03:34:00,94.334 2014-04-13 03:39:00,95.94 2014-04-13 03:44:00,92.35600000000001 2014-04-13 03:49:00,96.75 2014-04-13 03:54:00,95.542 2014-04-13 03:59:00,95.126 2014-04-13 04:04:00,95.21 2014-04-13 04:09:00,93.88799999999999 2014-04-13 04:14:00,93.012 2014-04-13 04:19:00,95.292 2014-04-13 04:24:00,94.0 2014-04-13 04:29:00,95.042 2014-04-13 04:34:00,94.124 2014-04-13 04:39:00,89.916 2014-04-13 04:44:00,94.13799999999999 2014-04-13 04:49:00,95.084 2014-04-13 04:54:00,94.816 2014-04-13 04:59:00,95.814 2014-04-13 05:04:00,93.794 2014-04-13 05:09:00,92.14200000000001 2014-04-13 05:14:00,92.348 2014-04-13 05:19:00,96.01 2014-04-13 05:24:00,94.708 2014-04-13 05:29:00,94.75 2014-04-13 05:34:00,93.834 2014-04-13 05:39:00,97.042 2014-04-13 05:44:00,94.874 2014-04-13 05:49:00,93.65 2014-04-13 05:54:00,93.94 2014-04-13 05:59:00,95.46600000000001 2014-04-13 06:04:00,96.538 2014-04-13 06:09:00,94.542 2014-04-13 06:14:00,92.19200000000001 2014-04-13 06:19:00,95.37200000000001 2014-04-13 06:24:00,94.584 2014-04-13 06:29:00,97.036 2014-04-13 06:34:00,93.084 2014-04-13 06:39:00,94.4 2014-04-13 06:44:00,92.402 2014-04-13 06:49:00,94.82 2014-04-13 06:54:00,92.354 2014-04-13 06:59:00,91.814 2014-04-13 07:04:00,87.958 2014-04-13 07:09:00,93.206 2014-04-13 07:14:00,94.902 2014-04-13 07:19:00,88.834 2014-04-13 07:24:00,90.666 2014-04-13 07:29:00,90.584 2014-04-13 07:34:00,92.374 2014-04-13 07:39:00,93.5 2014-04-13 07:44:00,92.376 2014-04-13 07:49:00,85.818 2014-04-13 07:54:00,91.72 2014-04-13 07:59:00,89.25 2014-04-13 08:04:00,91.166 2014-04-13 08:09:00,90.5 2014-04-13 08:14:00,90.916 2014-04-13 08:19:00,90.584 2014-04-13 08:24:00,93.292 2014-04-13 08:29:00,93.876 2014-04-13 08:34:00,92.126 2014-04-13 08:39:00,90.292 2014-04-13 08:44:00,91.63600000000001 2014-04-13 08:49:00,91.21 2014-04-13 08:54:00,93.156 2014-04-13 08:59:00,90.084 2014-04-13 09:04:00,88.416 2014-04-13 09:09:00,90.042 2014-04-13 09:14:00,90.126 2014-04-13 09:19:00,88.584 2014-04-13 09:24:00,90.626 2014-04-13 09:29:00,89.834 2014-04-13 09:34:00,92.334 2014-04-13 09:39:00,88.084 2014-04-13 09:44:00,94.964 2014-04-13 09:49:00,94.416 2014-04-13 09:54:00,89.666 2014-04-13 09:59:00,90.084 2014-04-13 10:04:00,87.292 2014-04-13 10:09:00,93.834 2014-04-13 10:14:00,92.0 2014-04-13 10:19:00,91.11 2014-04-13 10:24:00,88.07 2014-04-13 10:29:00,90.542 2014-04-13 10:34:00,93.834 2014-04-13 10:39:00,92.542 2014-04-13 10:44:00,90.126 2014-04-13 10:49:00,90.708 2014-04-13 10:54:00,91.084 2014-04-13 10:59:00,91.708 2014-04-13 11:04:00,92.124 2014-04-13 11:09:00,90.958 2014-04-13 11:14:00,90.626 2014-04-13 11:19:00,90.5 2014-04-13 11:24:00,92.75 2014-04-13 11:29:00,93.44 2014-04-13 11:34:00,95.262 2014-04-13 11:39:00,92.208 2014-04-13 11:44:00,93.338 2014-04-13 11:49:00,94.292 2014-04-13 11:54:00,94.836 2014-04-13 11:59:00,94.624 2014-04-13 12:04:00,93.166 2014-04-13 12:09:00,96.376 2014-04-13 12:14:00,93.824 2014-04-13 12:19:00,95.542 2014-04-13 12:24:00,94.584 2014-04-13 12:29:00,93.24 2014-04-13 12:34:00,93.094 2014-04-13 12:39:00,94.458 2014-04-13 12:44:00,92.416 2014-04-13 12:49:00,92.97 2014-04-13 12:54:00,98.07799999999999 2014-04-13 12:59:00,94.17200000000001 2014-04-13 13:04:00,93.006 2014-04-13 13:09:00,93.956 2014-04-13 13:14:00,95.126 2014-04-13 13:19:00,93.36 2014-04-13 13:24:00,91.708 2014-04-13 13:29:00,94.542 2014-04-13 13:34:00,93.11 2014-04-13 13:39:00,93.916 2014-04-13 13:44:00,93.792 2014-04-13 13:49:00,94.82 2014-04-13 13:54:00,95.654 2014-04-13 13:59:00,94.47 2014-04-13 14:04:00,93.772 2014-04-13 14:09:00,95.458 2014-04-13 14:14:00,94.416 2014-04-13 14:19:00,94.29799999999999 2014-04-13 14:24:00,91.84200000000001 2014-04-13 14:29:00,94.79799999999999 2014-04-13 14:34:00,96.28 2014-04-13 14:39:00,95.042 2014-04-13 14:44:00,95.25 2014-04-13 14:49:00,96.376 2014-04-13 14:54:00,95.208 2014-04-13 14:59:00,93.478 2014-04-13 15:04:00,94.586 2014-04-13 15:09:00,93.62200000000001 2014-04-13 15:14:00,93.834 2014-04-13 15:19:00,94.834 2014-04-13 15:24:00,93.652 2014-04-13 15:29:00,93.762 2014-04-13 15:34:00,92.762 2014-04-13 15:39:00,94.584 2014-04-13 15:44:00,92.792 2014-04-13 15:49:00,94.084 2014-04-13 15:54:00,92.766 2014-04-13 15:59:00,94.916 2014-04-13 16:04:00,93.8 2014-04-13 16:09:00,93.124 2014-04-13 16:14:00,93.208 2014-04-13 16:19:00,94.624 2014-04-13 16:24:00,97.166 2014-04-13 16:29:00,96.208 2014-04-13 16:34:00,93.56200000000001 2014-04-13 16:39:00,93.34 2014-04-13 16:44:00,94.19200000000001 2014-04-13 16:49:00,95.042 2014-04-13 16:54:00,93.834 2014-04-13 16:59:00,95.374 2014-04-13 17:04:00,95.87200000000001 2014-04-13 17:09:00,97.166 2014-04-13 17:14:00,93.822 2014-04-13 17:19:00,94.992 2014-04-13 17:24:00,93.542 2014-04-13 17:29:00,96.48 2014-04-13 17:34:00,94.542 2014-04-13 17:39:00,94.462 2014-04-13 17:44:00,94.82799999999999 2014-04-13 17:49:00,94.958 2014-04-13 17:54:00,95.834 2014-04-13 17:59:00,96.626 2014-04-13 18:04:00,95.334 2014-04-13 18:09:00,94.584 2014-04-13 18:14:00,92.63 2014-04-13 18:19:00,97.55799999999999 2014-04-13 18:24:00,96.294 2014-04-13 18:29:00,94.916 2014-04-13 18:34:00,94.458 2014-04-13 18:39:00,93.936 2014-04-13 18:44:00,95.126 2014-04-13 18:49:00,95.5 2014-04-13 18:54:00,94.69200000000001 2014-04-13 18:59:00,95.086 2014-04-13 19:04:00,94.542 2014-04-13 19:09:00,95.626 2014-04-13 19:14:00,94.084 2014-04-13 19:19:00,97.584 2014-04-13 19:24:00,94.30799999999999 2014-04-13 19:29:00,93.92 2014-04-13 19:34:00,94.134 2014-04-13 19:39:00,93.67200000000001 2014-04-13 19:44:00,95.27799999999999 2014-04-13 19:49:00,95.102 2014-04-13 19:54:00,93.916 2014-04-13 19:59:00,94.60600000000001 2014-04-13 20:04:00,94.16799999999999 2014-04-13 20:09:00,95.75 2014-04-13 20:14:00,94.678 2014-04-13 20:19:00,95.166 2014-04-13 20:24:00,95.18 2014-04-13 20:29:00,94.376 2014-04-13 20:34:00,92.958 2014-04-13 20:39:00,95.084 2014-04-13 20:44:00,95.126 2014-04-13 20:49:00,93.96 2014-04-13 20:54:00,93.584 2014-04-13 20:59:00,94.156 2014-04-13 21:09:00,93.99 2014-04-13 21:14:00,93.274 2014-04-13 21:19:00,94.162 2014-04-13 21:24:00,94.0 2014-04-13 21:29:00,95.0 2014-04-13 21:34:00,96.584 2014-04-13 21:39:00,92.75 2014-04-13 21:44:00,94.458 2014-04-13 21:49:00,97.29 2014-04-13 21:54:00,93.75 2014-04-13 21:59:00,94.666 2014-04-13 22:04:00,95.08200000000001 2014-04-13 22:09:00,93.714 2014-04-13 22:14:00,93.89399999999999 2014-04-13 22:19:00,93.96600000000001 2014-04-13 22:24:00,96.238 2014-04-13 22:29:00,94.006 2014-04-13 22:34:00,94.99600000000001 2014-04-13 22:39:00,96.0 2014-04-13 22:44:00,93.416 2014-04-13 22:49:00,94.19 2014-04-13 22:54:00,97.694 2014-04-13 22:59:00,95.834 2014-04-13 23:04:00,92.50200000000001 2014-04-13 23:09:00,94.86200000000001 2014-04-13 23:14:00,95.62799999999999 2014-04-13 23:19:00,95.15 2014-04-13 23:24:00,93.75 2014-04-13 23:29:00,94.166 2014-04-13 23:34:00,94.374 2014-04-13 23:39:00,96.508 2014-04-13 23:44:00,94.92399999999999 2014-04-13 23:49:00,95.584 2014-04-13 23:54:00,93.054 2014-04-13 23:59:00,93.666 2014-04-14 00:04:00,93.126 2014-04-14 00:09:00,92.958 2014-04-14 00:14:00,91.542 2014-04-14 00:19:00,92.00399999999999 2014-04-14 00:24:00,95.166 2014-04-14 00:29:00,93.666 2014-04-14 00:34:00,92.804 2014-04-14 00:39:00,93.75 2014-04-14 00:44:00,94.596 2014-04-14 00:49:00,95.208 2014-04-14 00:54:00,93.916 2014-04-14 00:59:00,93.334 2014-04-14 01:04:00,93.708 2014-04-14 01:09:00,93.292 2014-04-14 01:14:00,93.162 2014-04-14 01:19:00,96.00399999999999 2014-04-14 01:24:00,95.85799999999999 2014-04-14 01:29:00,93.708 2014-04-14 01:34:00,94.928 2014-04-14 01:39:00,95.566 2014-04-14 01:44:00,95.374 2014-04-14 01:49:00,96.396 2014-04-14 01:54:00,97.084 2014-04-14 01:59:00,95.042 2014-04-14 02:04:00,94.584 2014-04-14 02:09:00,97.374 2014-04-14 02:14:00,96.124 2014-04-14 02:19:00,93.708 2014-04-14 02:24:00,94.5 2014-04-14 02:29:00,95.32 2014-04-14 02:34:00,94.292 2014-04-14 02:39:00,94.758 2014-04-14 02:44:00,93.708 2014-04-14 02:49:00,94.5 2014-04-14 02:54:00,94.792 2014-04-14 02:59:00,92.542 2014-04-14 03:04:00,93.97 2014-04-14 03:09:00,96.626 2014-04-14 03:14:00,96.792 2014-04-14 03:19:00,92.274 2014-04-14 03:24:00,93.666 2014-04-14 03:29:00,96.834 2014-04-14 03:34:00,94.82799999999999 2014-04-14 03:39:00,96.914 2014-04-14 03:44:00,92.916 2014-04-14 03:49:00,93.292 2014-04-14 03:54:00,95.76799999999999 2014-04-14 03:59:00,95.646 2014-04-14 04:04:00,94.148 2014-04-14 04:09:00,93.648 2014-04-14 04:14:00,96.098 2014-04-14 04:19:00,94.792 2014-04-14 04:24:00,93.916 2014-04-14 04:29:00,93.292 2014-04-14 04:34:00,94.334 2014-04-14 04:39:00,95.28200000000001 2014-04-14 04:44:00,94.874 2014-04-14 04:49:00,95.834 2014-04-14 04:54:00,94.792 2014-04-14 04:59:00,95.626 2014-04-14 05:04:00,96.666 2014-04-14 05:09:00,96.0 2014-04-14 05:14:00,95.708 2014-04-14 05:19:00,94.46799999999999 2014-04-14 05:24:00,94.208 2014-04-14 05:29:00,94.292 2014-04-14 05:34:00,97.77 2014-04-14 05:39:00,97.24799999999999 2014-04-14 05:44:00,96.87200000000001 2014-04-14 05:49:00,92.90799999999999 2014-04-14 05:54:00,94.38600000000001 2014-04-14 05:59:00,95.822 2014-04-14 06:04:00,93.708 2014-04-14 06:09:00,93.73200000000001 2014-04-14 06:14:00,93.978 2014-04-14 06:19:00,95.376 2014-04-14 06:24:00,93.12799999999999 2014-04-14 06:29:00,94.166 2014-04-14 06:34:00,97.24799999999999 2014-04-14 06:39:00,94.626 2014-04-14 06:44:00,97.26 2014-04-14 06:49:00,95.376 2014-04-14 06:54:00,94.542 2014-04-14 06:59:00,97.874 2014-04-14 07:04:00,93.456 2014-04-14 07:09:00,94.5 2014-04-14 07:14:00,96.708 2014-04-14 07:19:00,94.304 2014-04-14 07:24:00,93.932 2014-04-14 07:29:00,93.16799999999999 2014-04-14 07:34:00,96.42399999999999 2014-04-14 07:39:00,95.6 2014-04-14 07:44:00,95.084 2014-04-14 07:49:00,96.13600000000001 2014-04-14 07:54:00,95.416 2014-04-14 07:59:00,93.42399999999999 2014-04-14 08:04:00,94.63600000000001 2014-04-14 08:09:00,95.084 2014-04-14 08:14:00,94.958 2014-04-14 08:19:00,94.292 2014-04-14 08:24:00,94.708 2014-04-14 08:29:00,96.46799999999999 2014-04-14 08:34:00,95.958 2014-04-14 08:39:00,94.416 2014-04-14 08:44:00,93.25 2014-04-14 08:49:00,94.416 2014-04-14 08:54:00,94.626 2014-04-14 08:59:00,94.85 2014-04-14 09:04:00,92.294 2014-04-14 09:09:00,95.5 2014-04-14 09:14:00,94.042 2014-04-14 09:19:00,93.508 2014-04-14 09:24:00,92.77 2014-04-14 09:29:00,92.63 2014-04-14 09:34:00,94.86200000000001 2014-04-14 09:39:00,93.666 2014-04-14 09:44:00,94.53399999999999 2014-04-14 09:49:00,94.25 2014-04-14 09:54:00,96.124 2014-04-14 09:59:00,93.334 2014-04-14 10:04:00,96.53 2014-04-14 10:09:00,91.958 2014-04-14 10:14:00,93.708 2014-04-14 10:19:00,95.958 2014-04-14 10:24:00,94.5 2014-04-14 10:29:00,95.708 2014-04-14 10:34:00,93.166 2014-04-14 10:39:00,91.458 2014-04-14 10:44:00,96.32799999999999 2014-04-14 10:49:00,94.184 2014-04-14 10:54:00,96.182 2014-04-14 10:59:00,91.9 2014-04-14 11:04:00,92.542 2014-04-14 11:09:00,94.22 2014-04-14 11:14:00,94.416 2014-04-14 11:19:00,98.212 2014-04-14 11:24:00,94.546 2014-04-14 11:29:00,93.334 2014-04-14 11:34:00,93.88 2014-04-14 11:39:00,92.868 2014-04-14 11:44:00,95.306 2014-04-14 11:49:00,93.876 2014-04-14 11:54:00,94.712 2014-04-14 11:59:00,93.876 2014-04-14 12:04:00,95.876 2014-04-14 12:09:00,96.708 2014-04-14 12:14:00,95.334 2014-04-14 12:19:00,93.57600000000001 2014-04-14 12:24:00,94.292 2014-04-14 12:29:00,94.25 2014-04-14 12:34:00,93.26 2014-04-14 12:39:00,94.072 2014-04-14 12:44:00,94.0 2014-04-14 12:49:00,94.334 2014-04-14 12:54:00,94.662 2014-04-14 12:59:00,96.96600000000001 2014-04-14 13:04:00,93.626 2014-04-14 13:09:00,93.874 2014-04-14 13:14:00,95.5 2014-04-14 13:19:00,94.874 2014-04-14 13:24:00,95.416 2014-04-14 13:29:00,93.75 2014-04-14 13:34:00,93.126 2014-04-14 13:39:00,94.0 2014-04-14 13:44:00,91.708 2014-04-14 13:49:00,92.46799999999999 2014-04-14 13:54:00,96.376 2014-04-14 13:59:00,93.12 2014-04-14 14:04:00,90.60600000000001 2014-04-14 14:09:00,94.958 2014-04-14 14:14:00,94.916 2014-04-14 14:19:00,98.208 2014-04-14 14:24:00,94.50399999999999 2014-04-14 14:29:00,93.126 2014-04-14 14:34:00,95.542 2014-04-14 14:39:00,94.166 2014-04-14 14:44:00,94.25 2014-04-14 14:49:00,95.292 2014-04-14 14:54:00,96.916 2014-04-14 14:59:00,93.5 2014-04-14 15:04:00,96.25 2014-04-14 15:09:00,96.0 2014-04-14 15:14:00,94.384 2014-04-14 15:19:00,96.084 2014-04-14 15:24:00,94.384 2014-04-14 15:29:00,95.042 2014-04-14 15:34:00,95.436 2014-04-14 15:39:00,96.25 2014-04-14 15:44:00,96.416 2014-04-14 15:49:00,96.876 2014-04-14 15:54:00,94.0 2014-04-14 15:59:00,93.47 2014-04-14 16:04:00,95.22399999999999 2014-04-14 16:09:00,94.084 2014-04-14 16:14:00,93.792 2014-04-14 16:19:00,95.5 2014-04-14 16:24:00,93.792 2014-04-14 16:29:00,92.47399999999999 2014-04-14 16:34:00,93.834 2014-04-14 16:39:00,92.37200000000001 2014-04-14 16:44:00,94.958 2014-04-14 16:49:00,94.542 2014-04-14 16:54:00,93.208 2014-04-14 16:59:00,94.48200000000001 2014-04-14 17:04:00,93.19200000000001 2014-04-14 17:09:00,93.64200000000001 2014-04-14 17:14:00,92.964 2014-04-14 17:19:00,94.814 2014-04-14 17:24:00,95.178 2014-04-14 17:29:00,94.5 2014-04-14 17:34:00,95.58200000000001 2014-04-14 17:39:00,96.204 2014-04-14 17:44:00,95.834 2014-04-14 17:49:00,93.208 2014-04-14 17:54:00,93.00200000000001 2014-04-14 17:59:00,92.958 2014-04-14 18:04:00,96.272 2014-04-14 18:09:00,95.404 2014-04-14 18:14:00,93.792 2014-04-14 18:19:00,95.042 2014-04-14 18:24:00,96.334 2014-04-14 18:29:00,97.874 2014-04-14 18:34:00,95.75 2014-04-14 18:39:00,93.522 2014-04-14 18:44:00,93.198 2014-04-14 18:49:00,95.208 2014-04-14 18:54:00,92.5 2014-04-14 18:59:00,93.24799999999999 2014-04-14 19:04:00,93.584 2014-04-14 19:09:00,94.36399999999999 2014-04-14 19:14:00,93.36200000000001 2014-04-14 19:19:00,94.21600000000001 2014-04-14 19:24:00,93.96 2014-04-14 19:29:00,94.57 2014-04-14 19:34:00,93.446 2014-04-14 19:39:00,93.27 2014-04-14 19:44:00,93.23200000000001 2014-04-14 19:49:00,95.5 2014-04-14 19:54:00,94.374 2014-04-14 19:59:00,93.116 2014-04-14 20:04:00,93.402 2014-04-14 20:09:00,92.44 2014-04-14 20:14:00,93.75200000000001 2014-04-14 20:19:00,91.792 2014-04-14 20:24:00,95.0 2014-04-14 20:29:00,94.166 2014-04-14 20:34:00,94.208 2014-04-14 20:39:00,92.75 2014-04-14 20:44:00,94.5 2014-04-14 20:49:00,92.86399999999999 2014-04-14 20:54:00,95.916 2014-04-14 20:59:00,90.27600000000001 2014-04-14 21:04:00,93.22 2014-04-14 21:09:00,97.042 2014-04-14 21:14:00,95.4 2014-04-14 21:19:00,92.542 2014-04-14 21:24:00,93.12200000000001 2014-04-14 21:29:00,94.59200000000001 2014-04-14 21:34:00,93.882 2014-04-14 21:39:00,94.0 2014-04-14 21:44:00,93.084 2014-04-14 21:49:00,95.292 2014-04-14 21:54:00,98.46600000000001 2014-04-14 21:59:00,94.99600000000001 2014-04-14 22:04:00,95.632 2014-04-14 22:09:00,96.78200000000001 2014-04-14 22:14:00,95.57799999999999 2014-04-14 22:19:00,92.87 2014-04-14 22:24:00,96.208 2014-04-14 22:29:00,91.792 2014-04-14 22:34:00,95.166 2014-04-14 22:39:00,95.584 2014-04-14 22:44:00,94.874 2014-04-14 22:49:00,95.876 2014-04-14 22:54:00,96.334 2014-04-14 22:59:00,92.916 2014-04-14 23:04:00,95.542 2014-04-14 23:09:00,94.416 2014-04-14 23:14:00,92.834 2014-04-14 23:19:00,93.958 2014-04-14 23:24:00,93.266 2014-04-14 23:29:00,95.25 2014-04-14 23:34:00,95.14200000000001 2014-04-14 23:39:00,94.306 2014-04-14 23:44:00,95.792 2014-04-14 23:49:00,94.916 2014-04-14 23:54:00,93.198 2014-04-14 23:59:00,94.376 2014-04-15 00:04:00,95.46 2014-04-15 00:09:00,95.956 2014-04-15 00:14:00,95.682 2014-04-15 00:19:00,93.21799999999999 2014-04-15 00:24:00,94.584 2014-04-15 00:29:00,96.584 2014-04-15 00:34:00,96.458 2014-04-15 00:39:00,93.792 2014-04-15 00:44:00,93.084 2014-04-15 00:49:00,93.792 2014-04-15 00:54:00,94.75 2014-04-15 00:59:00,91.94200000000001 2014-04-15 01:04:00,94.334 2014-04-15 01:09:00,92.92 2014-04-15 01:14:00,93.958 2014-04-15 01:19:00,91.478 2014-04-15 01:24:00,94.708 2014-04-15 01:29:00,93.62799999999999 2014-04-15 01:34:00,91.75 2014-04-15 01:39:00,93.834 2014-04-15 01:44:00,94.39399999999999 2014-04-15 01:49:00,92.834 2014-04-15 01:54:00,95.852 2014-04-15 01:59:00,94.406 2014-04-15 02:04:00,93.584 2014-04-15 02:09:00,92.25 2014-04-15 02:14:00,96.764 2014-04-15 02:19:00,96.772 2014-04-15 02:24:00,93.584 2014-04-15 02:29:00,93.5 2014-04-15 02:34:00,93.792 2014-04-15 02:39:00,95.964 2014-04-15 02:44:00,93.81 2014-04-15 02:49:00,95.556 2014-04-15 02:54:00,92.96600000000001 2014-04-15 02:59:00,93.85799999999999 2014-04-15 03:04:00,95.354 2014-04-15 03:09:00,92.40799999999999 2014-04-15 03:14:00,93.084 2014-04-15 03:19:00,95.124 2014-04-15 03:24:00,97.042 2014-04-15 03:29:00,93.762 2014-04-15 03:34:00,94.458 2014-04-15 03:39:00,95.792 2014-04-15 03:44:00,93.792 2014-04-15 03:49:00,95.81200000000001 2014-04-15 03:54:00,94.126 2014-04-15 03:59:00,93.75 2014-04-15 04:04:00,90.25 2014-04-15 04:09:00,97.708 2014-04-15 04:14:00,95.21799999999999 2014-04-15 04:19:00,95.48 2014-04-15 04:24:00,92.916 2014-04-15 04:29:00,94.874 2014-04-15 04:34:00,93.376 2014-04-15 04:39:00,92.084 2014-04-15 04:44:00,95.456 2014-04-15 04:49:00,95.542 2014-04-15 04:54:00,93.75 2014-04-15 04:59:00,92.32799999999999 2014-04-15 05:04:00,95.042 2014-04-15 05:09:00,95.74600000000001 2014-04-15 05:14:00,94.92200000000001 2014-04-15 05:19:00,94.53200000000001 2014-04-15 05:24:00,96.336 2014-04-15 05:29:00,93.584 2014-04-15 05:34:00,94.176 2014-04-15 05:39:00,94.25 2014-04-15 05:44:00,96.512 2014-04-15 05:49:00,92.708 2014-04-15 05:54:00,94.666 2014-04-15 05:59:00,92.458 2014-04-15 06:04:00,95.03399999999999 2014-04-15 06:09:00,93.5 2014-04-15 06:14:00,92.346 2014-04-15 06:19:00,91.454 2014-04-15 06:24:00,92.0 2014-04-15 06:29:00,92.0 2014-04-15 06:34:00,93.698 2014-04-15 06:39:00,94.208 2014-04-15 06:44:00,93.824 2014-04-15 06:49:00,88.376 2014-04-15 06:54:00,94.0 2014-04-15 06:59:00,91.166 2014-04-15 07:04:00,91.514 2014-04-15 07:09:00,90.02799999999998 2014-04-15 07:14:00,88.97399999999998 2014-04-15 07:19:00,95.29799999999999 2014-04-15 07:24:00,93.726 2014-04-15 07:29:00,91.542 2014-04-15 07:34:00,92.416 2014-04-15 07:39:00,95.47 2014-04-15 07:44:00,97.542 2014-04-15 07:49:00,92.552 2014-04-15 07:54:00,93.416 2014-04-15 07:59:00,89.87 2014-04-15 08:04:00,92.41 2014-04-15 08:09:00,91.73 2014-04-15 08:14:00,93.624 2014-04-15 08:19:00,93.134 2014-04-15 08:24:00,92.334 2014-04-15 08:29:00,94.376 2014-04-15 08:34:00,94.07799999999999 2014-04-15 08:39:00,93.042 2014-04-15 08:44:00,93.958 2014-04-15 08:49:00,94.124 2014-04-15 08:54:00,91.458 2014-04-15 08:59:00,93.376 2014-04-15 09:04:00,94.25 2014-04-15 09:09:00,95.834 2014-04-15 09:14:00,94.564 2014-04-15 09:19:00,93.25 2014-04-15 09:24:00,94.348 2014-04-15 09:29:00,97.18799999999999 2014-04-15 09:34:00,95.11399999999999 2014-04-15 09:39:00,95.958 2014-04-15 09:44:00,95.708 2014-04-15 09:49:00,91.83 2014-04-15 09:54:00,93.584 2014-04-15 09:59:00,93.166 2014-04-15 10:04:00,92.708 2014-04-15 10:09:00,93.042 2014-04-15 10:14:00,95.084 2014-04-15 10:19:00,97.042 2014-04-15 10:24:00,93.958 2014-04-15 10:29:00,94.124 2014-04-15 10:34:00,92.416 2014-04-15 10:39:00,95.166 2014-04-15 10:44:00,93.084 2014-04-15 10:49:00,95.43 2014-04-15 10:54:00,93.904 2014-04-15 10:59:00,94.054 2014-04-15 11:04:00,93.334 2014-04-15 11:09:00,93.05799999999999 2014-04-15 11:14:00,93.92 2014-04-15 11:19:00,94.208 2014-04-15 11:24:00,95.806 2014-04-15 11:29:00,90.75 2014-04-15 11:34:00,93.584 2014-04-15 11:39:00,93.334 2014-04-15 11:44:00,94.292 2014-04-15 11:49:00,95.272 2014-04-15 11:54:00,93.958 2014-04-15 11:59:00,90.75 2014-04-15 12:04:00,95.446 2014-04-15 12:09:00,93.73200000000001 2014-04-15 12:14:00,91.162 2014-04-15 12:19:00,92.19 2014-04-15 12:24:00,93.87 2014-04-15 12:29:00,92.91799999999999 2014-04-15 12:34:00,93.208 2014-04-15 12:39:00,92.792 2014-04-15 12:44:00,96.75 2014-04-15 12:49:00,93.374 2014-04-15 12:54:00,94.35799999999999 2014-04-15 12:59:00,93.27 2014-04-15 13:04:00,93.54 2014-04-15 13:09:00,93.024 2014-04-15 13:14:00,95.166 2014-04-15 13:19:00,95.04 2014-04-15 13:24:00,93.904 2014-04-15 13:29:00,93.834 2014-04-15 13:34:00,94.406 2014-04-15 13:39:00,94.376 2014-04-15 13:44:00,95.334 2014-04-15 13:49:00,95.084 2014-04-15 13:54:00,89.958 2014-04-15 13:59:00,91.1 2014-04-15 14:04:00,93.822 2014-04-15 14:09:00,93.60799999999999 2014-04-15 14:14:00,90.50399999999999 2014-04-15 14:19:00,88.384 2014-04-15 14:24:00,91.124 2014-04-15 14:29:00,93.542 2014-04-15 14:34:00,86.728 2014-04-15 14:39:00,91.44 2014-04-15 14:44:00,93.17200000000001 2014-04-15 14:49:00,92.634 2014-04-15 14:54:00,95.804 2014-04-15 14:59:00,92.916 2014-04-15 15:04:00,89.948 2014-04-15 15:09:00,92.834 2014-04-15 15:14:00,91.666 2014-04-15 15:19:00,92.0 2014-04-15 15:24:00,89.92 2014-04-15 15:29:00,94.024 2014-04-15 15:34:00,91.876 2014-04-15 15:39:00,92.042 2014-04-15 15:44:00,76.874 2014-04-15 15:49:00,86.124 2014-04-15 15:54:00,84.626 2014-04-15 15:59:00,82.374 2014-04-15 16:04:00,85.52799999999998 2014-04-15 16:09:00,90.23 2014-04-15 16:14:00,90.458 2014-04-15 16:19:00,90.584 2014-04-15 16:24:00,91.626 2014-04-15 16:29:00,90.0 2014-04-15 16:34:00,93.404 2014-04-15 16:39:00,95.766 2014-04-15 16:44:00,93.76799999999999 2014-04-15 16:49:00,89.292 2014-04-15 16:54:00,54.958 2014-04-15 16:59:00,54.7775 2014-04-15 17:04:00,90.03200000000002 2014-04-15 17:09:00,93.18 2014-04-15 17:14:00,88.178 2014-04-15 17:19:00,87.99799999999998 2014-04-15 17:24:00,87.986 2014-04-15 17:29:00,87.542 2014-04-15 17:34:00,89.084 2014-04-15 17:39:00,89.876 2014-04-15 17:44:00,87.044 2014-04-15 17:49:00,88.0 2014-04-15 17:54:00,88.49799999999998 2014-04-15 17:59:00,89.322 2014-04-15 18:04:00,88.166 2014-04-15 18:09:00,92.916 2014-04-15 18:14:00,87.626 2014-04-15 18:19:00,89.072 2014-04-15 18:24:00,85.238 2014-04-15 18:29:00,89.756 2014-04-15 18:34:00,87.666 2014-04-15 18:39:00,89.626 2014-04-15 18:44:00,90.292 2014-04-15 18:49:00,87.74600000000002 2014-04-15 18:54:00,85.458 2014-04-15 18:59:00,88.0 2014-04-15 19:04:00,88.958 2014-04-15 19:09:00,92.60600000000001 2014-04-15 19:14:00,76.982 2014-04-15 19:19:00,92.262 2014-04-15 19:24:00,86.552 2014-04-15 19:29:00,88.042 2014-04-15 19:34:00,88.334 2014-04-15 19:39:00,90.696 2014-04-15 19:44:00,87.89399999999998 2014-04-15 19:49:00,93.85 2014-04-15 19:54:00,91.348 2014-04-15 19:59:00,91.626 2014-04-15 20:04:00,89.084 2014-04-15 20:09:00,90.98200000000001 2014-04-15 20:14:00,90.98200000000001 2014-04-15 20:19:00,92.18799999999999 2014-04-15 20:24:00,90.25 2014-04-15 20:29:00,93.166 2014-04-15 20:34:00,93.75 2014-04-15 20:39:00,89.584 2014-04-15 20:44:00,91.708 2014-04-15 20:49:00,89.12 2014-04-15 20:54:00,91.618 2014-04-15 20:59:00,91.266 2014-04-15 21:04:00,94.084 2014-04-15 21:09:00,94.5 2014-04-15 21:14:00,93.708 2014-04-15 21:19:00,92.708 2014-04-15 21:24:00,93.662 2014-04-15 21:29:00,91.652 2014-04-15 21:34:00,93.75200000000001 2014-04-15 21:39:00,91.07600000000001 2014-04-15 21:44:00,92.508 2014-04-15 21:49:00,93.64 2014-04-15 21:54:00,93.584 2014-04-15 21:59:00,92.124 2014-04-15 22:04:00,90.166 2014-04-15 22:09:00,94.484 2014-04-15 22:14:00,92.148 2014-04-15 22:19:00,93.486 2014-04-15 22:24:00,94.56 2014-04-15 22:29:00,91.458 2014-04-15 22:34:00,91.0 2014-04-15 22:39:00,91.876 2014-04-15 22:44:00,90.042 2014-04-15 22:49:00,93.626 2014-04-15 22:54:00,93.666 2014-04-15 22:59:00,95.166 2014-04-15 23:04:00,92.59 2014-04-15 23:09:00,94.042 2014-04-15 23:14:00,87.708 2014-04-15 23:19:00,92.78200000000001 2014-04-15 23:24:00,91.514 2014-04-15 23:29:00,88.834 2014-04-15 23:34:00,90.964 2014-04-15 23:39:00,91.084 2014-04-15 23:44:00,90.15799999999999 2014-04-15 23:49:00,88.958 2014-04-15 23:54:00,91.896 2014-04-15 23:59:00,92.916 2014-04-16 00:04:00,91.348 2014-04-16 00:09:00,92.75 2014-04-16 00:14:00,93.704 2014-04-16 00:19:00,93.292 2014-04-16 00:24:00,93.916 2014-04-16 00:29:00,92.126 2014-04-16 00:34:00,93.084 2014-04-16 00:39:00,93.454 2014-04-16 00:44:00,91.292 2014-04-16 00:49:00,94.25 2014-04-16 00:54:00,91.542 2014-04-16 00:59:00,93.292 2014-04-16 01:04:00,92.63 2014-04-16 01:09:00,94.39200000000001 2014-04-16 01:14:00,90.292 2014-04-16 01:19:00,94.292 2014-04-16 01:24:00,93.57 2014-04-16 01:29:00,91.876 2014-04-16 01:34:00,91.376 2014-04-16 01:39:00,92.65799999999999 2014-04-16 01:44:00,90.666 2014-04-16 01:49:00,92.5 2014-04-16 01:54:00,92.042 2014-04-16 01:59:00,92.5 2014-04-16 02:04:00,93.208 2014-04-16 02:09:00,95.34 2014-04-16 02:14:00,93.962 2014-04-16 02:19:00,93.55799999999999 2014-04-16 02:24:00,90.08200000000001 2014-04-16 02:29:00,90.344 2014-04-16 02:34:00,92.506 2014-04-16 02:39:00,90.89399999999999 2014-04-16 02:44:00,91.416 2014-04-16 02:49:00,90.374 2014-04-16 02:54:00,92.166 2014-04-16 02:59:00,91.632 2014-04-16 03:04:00,92.416 2014-04-16 03:09:00,98.292 2014-04-16 03:14:00,92.124 2014-04-16 03:19:00,91.416 2014-04-16 03:24:00,91.458 2014-04-16 03:29:00,58.461999999999996 2014-04-16 03:34:00,24.432 2014-04-16 03:39:00,24.624000000000002 2014-04-16 03:44:00,23.994 2014-04-16 03:49:00,24.291999999999998 2014-04-16 03:54:00,25.208000000000002 2014-04-16 03:59:00,24.541999999999998 2014-04-16 04:04:00,18.7225 2014-04-16 04:09:00,35.93199999999999 2014-04-16 04:14:00,24.638 2014-04-16 04:19:00,23.59 2014-04-16 04:24:00,24.608 2014-04-16 04:29:00,24.204 2014-04-16 04:34:00,24.294 2014-04-16 04:39:00,24.82 2014-04-16 04:44:00,24.584 2014-04-16 04:49:00,24.584 2014-04-16 04:54:00,25.375999999999998 2014-04-16 04:59:00,25.124000000000002 2014-04-16 05:04:00,24.951999999999998 2014-04-16 05:09:00,36.461999999999996 2014-04-16 05:14:00,24.651999999999997 2014-04-16 05:19:00,25.048000000000002 2014-04-16 05:24:00,25.32 2014-04-16 05:29:00,25.166 2014-04-16 05:34:00,24.791999999999998 2014-04-16 05:39:00,25.334 2014-04-16 05:44:00,24.875999999999998 2014-04-16 05:49:00,24.708000000000002 2014-04-16 05:54:00,25.75 2014-04-16 05:59:00,25.5 2014-04-16 06:04:00,25.416 2014-04-16 06:09:00,36.334 2014-04-16 06:14:00,25.334 2014-04-16 06:19:00,25.108 2014-04-16 06:24:00,25.32 2014-04-16 06:29:00,25.401999999999997 2014-04-16 06:34:00,24.666 2014-04-16 06:39:00,25.208000000000002 2014-04-16 06:44:00,25.122 2014-04-16 06:49:00,25.25 2014-04-16 06:54:00,25.541999999999998 2014-04-16 06:59:00,25.584 2014-04-16 07:04:00,25.334 2014-04-16 07:09:00,36.67 2014-04-16 07:14:00,25.108 2014-04-16 07:19:00,24.976 2014-04-16 07:24:00,25.274 2014-04-16 07:29:00,24.842 2014-04-16 07:34:00,24.541999999999998 2014-04-16 07:39:00,25.0 2014-04-16 07:44:00,24.916 2014-04-16 07:49:00,24.516 2014-04-16 07:54:00,25.25 2014-04-16 07:59:00,25.204 2014-04-16 08:04:00,24.8 2014-04-16 08:09:00,36.0 2014-04-16 08:14:00,25.291999999999998 2014-04-16 08:19:00,25.166 2014-04-16 08:24:00,25.375999999999998 2014-04-16 08:29:00,24.874000000000002 2014-04-16 08:34:00,24.541999999999998 2014-04-16 08:39:00,25.041999999999998 2014-04-16 08:44:00,24.666 2014-04-16 08:49:00,24.791999999999998 2014-04-16 08:54:00,25.45 2014-04-16 08:59:00,25.214000000000002 2014-04-16 09:04:00,24.916 2014-04-16 09:09:00,36.166 2014-04-16 09:14:00,24.958000000000002 2014-04-16 09:19:00,24.666 2014-04-16 09:24:00,24.624000000000002 2014-04-16 09:29:00,25.125999999999998 2014-04-16 09:34:00,25.125999999999998 2014-04-16 09:39:00,24.916 2014-04-16 09:44:00,25.25 2014-04-16 09:49:00,24.834 2014-04-16 09:54:00,25.666 2014-04-16 09:59:00,25.364 2014-04-16 10:04:00,24.791999999999998 2014-04-16 10:09:00,36.626 2014-04-16 10:14:00,24.484 2014-04-16 10:19:00,24.94 2014-04-16 10:24:00,24.726 2014-04-16 10:29:00,26.458000000000002 2014-04-16 10:34:00,24.916 2014-04-16 10:39:00,25.272 2014-04-16 10:44:00,25.166 2014-04-16 10:49:00,24.75 2014-04-16 10:54:00,25.334 2014-04-16 10:59:00,25.625999999999998 2014-04-16 11:04:00,25.081999999999997 2014-04-16 11:09:00,35.876 2014-04-16 11:14:00,24.916 2014-04-16 11:19:00,24.991999999999997 2014-04-16 11:24:00,25.484 2014-04-16 11:29:00,25.084 2014-04-16 11:34:00,24.791999999999998 2014-04-16 11:39:00,25.084 2014-04-16 11:44:00,25.374000000000002 2014-04-16 11:49:00,24.75 2014-04-16 11:54:00,25.416 2014-04-16 11:59:00,25.334 2014-04-16 12:04:00,25.041999999999998 2014-04-16 12:09:00,35.854 2014-04-16 12:14:00,24.625999999999998 2014-04-16 12:19:00,25.11 2014-04-16 12:24:00,24.97 2014-04-16 12:29:00,24.94 2014-04-16 12:34:00,24.666 2014-04-16 12:39:00,24.708000000000002 2014-04-16 12:44:00,25.125999999999998 2014-04-16 12:49:00,25.25 2014-04-16 12:54:00,25.416 2014-04-16 12:59:00,25.691999999999997 2014-04-16 13:04:00,26.0425 2014-04-16 13:09:00,36.385999999999996 2014-04-16 13:14:00,24.726 2014-04-16 13:19:00,24.706 2014-04-16 13:24:00,24.76 2014-04-16 13:29:00,23.756 2014-04-16 13:34:00,24.334 2014-04-16 13:39:00,24.416 2014-04-16 13:44:00,24.916 2014-04-16 13:49:00,24.291999999999998 2014-04-16 13:54:00,25.026 2014-04-16 13:59:00,24.334 2014-04-16 14:04:00,24.284000000000002 2014-04-16 14:09:00,36.166 2014-04-16 14:14:00,24.081999999999997 2014-04-16 14:19:00,85.266 2014-04-16 14:24:00,94.834 2014-04-16 14:29:00,92.162 2014-04-16 14:34:00,94.4 2014-04-16 14:39:00,94.334 2014-04-16 14:44:00,93.882 2014-04-16 14:49:00,91.75 2014-04-16 14:54:00,92.208 2014-04-16 14:59:00,93.374 2014-04-16 15:04:00,88.626 2014-04-16 15:09:00,90.874 2014-04-16 15:14:00,91.25 2014-04-16 15:19:00,92.374 2014-04-16 15:24:00,85.958 2014-04-16 15:29:00,86.75 2014-04-16 15:34:00,85.584 2014-04-16 15:39:00,84.958 2014-04-16 15:44:00,85.25 2014-04-16 15:49:00,87.25 2014-04-16 15:54:00,87.132 2014-04-16 15:59:00,94.1 2014-04-16 16:04:00,89.208 2014-04-16 16:09:00,93.584 2014-04-16 16:14:00,92.292 2014-04-16 16:19:00,89.196 2014-04-16 16:24:00,90.25 2014-04-16 16:29:00,90.95200000000001 2014-04-16 16:34:00,91.4 2014-04-16 16:39:00,93.182 2014-04-16 16:44:00,89.512 2014-04-16 16:49:00,88.648 2014-04-16 16:54:00,88.87799999999999 2014-04-16 16:59:00,87.006 2014-04-16 17:04:00,93.53200000000001 2014-04-16 17:09:00,93.072 2014-04-16 17:14:00,80.63 2014-04-16 17:19:00,91.72200000000001 2014-04-16 17:24:00,92.194 2014-04-16 17:29:00,90.94 2014-04-16 17:34:00,89.666 2014-04-16 17:39:00,94.292 2014-04-16 17:44:00,92.626 2014-04-16 17:49:00,93.376 2014-04-16 17:54:00,91.87200000000001 2014-04-16 17:59:00,90.48200000000001 2014-04-16 18:04:00,92.91 2014-04-16 18:09:00,92.124 2014-04-16 18:14:00,91.208 2014-04-16 18:19:00,91.292 2014-04-16 18:24:00,92.902 2014-04-16 18:29:00,93.042 2014-04-16 18:34:00,90.5 2014-04-16 18:39:00,91.036 2014-04-16 18:44:00,89.208 2014-04-16 18:49:00,89.376 2014-04-16 18:54:00,89.98200000000001 2014-04-16 18:59:00,90.042 2014-04-16 19:04:00,88.5 2014-04-16 19:09:00,90.176 2014-04-16 19:14:00,87.396 2014-04-16 19:19:00,84.584 2014-04-16 19:24:00,92.166 2014-04-16 19:29:00,92.5 2014-04-16 19:34:00,89.874 2014-04-16 19:39:00,89.416 2014-04-16 19:44:00,91.51 2014-04-16 19:49:00,93.5 2014-04-16 19:54:00,91.876 2014-04-16 19:59:00,92.676 2014-04-16 20:04:00,89.044 2014-04-16 20:09:00,94.208 2014-04-16 20:14:00,91.70200000000001 2014-04-16 20:19:00,90.556 2014-04-16 20:24:00,85.61200000000002 2014-04-16 20:29:00,89.02 2014-04-16 20:34:00,84.78 2014-04-16 20:39:00,87.806 2014-04-16 20:44:00,89.874 2014-04-16 20:49:00,87.792 2014-04-16 20:54:00,90.666 2014-04-16 20:59:00,88.67399999999998 2014-04-16 21:04:00,87.124 2014-04-16 21:09:00,88.958 2014-04-16 21:14:00,90.374 2014-04-16 21:19:00,90.916 2014-04-16 21:24:00,87.75 2014-04-16 21:29:00,90.792 2014-04-16 21:34:00,82.0 2014-04-16 21:39:00,92.806 2014-04-16 21:44:00,85.82799999999997 2014-04-16 21:49:00,90.632 2014-04-16 21:54:00,92.44 2014-04-16 21:59:00,87.626 2014-04-16 22:04:00,87.75 2014-04-16 22:09:00,95.22399999999999 2014-04-16 22:14:00,91.182 2014-04-16 22:19:00,89.52600000000002 2014-04-16 22:24:00,84.686 2014-04-16 22:29:00,89.01799999999999 2014-04-16 22:34:00,83.664 2014-04-16 22:39:00,93.134 2014-04-16 22:44:00,90.25 2014-04-16 22:49:00,86.584 2014-04-16 22:54:00,87.792 2014-04-16 22:59:00,85.292 2014-04-16 23:04:00,88.95200000000001 2014-04-16 23:09:00,89.542 2014-04-16 23:14:00,93.084 2014-04-16 23:19:00,88.958 2014-04-16 23:24:00,92.542 2014-04-16 23:29:00,88.458 2014-04-16 23:34:00,87.166 2014-04-16 23:39:00,86.876 2014-04-16 23:44:00,86.166 2014-04-16 23:49:00,88.376 2014-04-16 23:54:00,85.25200000000002 2014-04-16 23:59:00,88.846 2014-04-17 00:04:00,90.416 2014-04-17 00:09:00,95.0 2014-04-17 00:14:00,90.75 2014-04-17 00:19:00,91.626 2014-04-17 00:24:00,88.792 2014-04-17 00:29:00,85.75 2014-04-17 00:34:00,88.96799999999998 2014-04-17 00:39:00,86.792 2014-04-17 00:44:00,85.584 2014-04-17 00:49:00,88.624 2014-04-17 00:54:00,87.916 2014-04-17 00:59:00,89.28399999999998 2014-04-17 01:04:00,87.52799999999998 2014-04-17 01:09:00,93.796 2014-04-17 01:14:00,91.766 2014-04-17 01:19:00,83.63 2014-04-17 01:24:00,93.132 2014-04-17 01:29:00,86.456 2014-04-17 01:34:00,83.584 2014-04-17 01:39:00,92.26799999999999 2014-04-17 01:44:00,87.958 2014-04-17 01:49:00,86.25 2014-04-17 01:54:00,88.274 2014-04-17 01:59:00,87.42 2014-04-17 02:04:00,86.542 2014-04-17 02:09:00,88.126 2014-04-17 02:14:00,92.958 2014-04-17 02:19:00,92.17200000000001 2014-04-17 02:24:00,91.166 2014-04-17 02:29:00,92.416 2014-04-17 02:34:00,87.564 2014-04-17 02:39:00,91.34200000000001 2014-04-17 02:44:00,83.626 2014-04-17 02:49:00,86.124 2014-04-17 02:54:00,89.742 2014-04-17 02:59:00,87.292 2014-04-17 03:04:00,85.79 2014-04-17 03:09:00,88.786 2014-04-17 03:14:00,94.08 2014-04-17 03:19:00,91.492 2014-04-17 03:24:00,84.56 2014-04-17 03:29:00,88.836 2014-04-17 03:34:00,89.124 2014-04-17 03:39:00,85.686 2014-04-17 03:44:00,85.584 2014-04-17 03:49:00,84.96 2014-04-17 03:54:00,86.94 2014-04-17 03:59:00,86.708 2014-04-17 04:04:00,86.626 2014-04-17 04:09:00,88.434 2014-04-17 04:14:00,88.08 2014-04-17 04:19:00,88.756 2014-04-17 04:24:00,90.166 2014-04-17 04:29:00,88.0 2014-04-17 04:34:00,90.708 2014-04-17 04:39:00,88.708 2014-04-17 04:44:00,84.792 2014-04-17 04:49:00,87.374 2014-04-17 04:54:00,85.208 2014-04-17 04:59:00,88.292 2014-04-17 05:04:00,88.208 2014-04-17 05:09:00,95.416 2014-04-17 05:14:00,92.5 2014-04-17 05:19:00,91.916 2014-04-17 05:24:00,88.10600000000002 2014-04-17 05:29:00,87.698 2014-04-17 05:34:00,86.56200000000004 2014-04-17 05:39:00,87.11200000000002 2014-04-17 05:44:00,87.256 2014-04-17 05:49:00,85.916 2014-04-17 05:54:00,93.63799999999999 2014-04-17 05:59:00,89.58 2014-04-17 06:04:00,88.05 2014-04-17 06:09:00,86.068 2014-04-17 06:14:00,93.22399999999999 2014-04-17 06:19:00,93.416 2014-04-17 06:24:00,89.25 2014-04-17 06:29:00,85.39200000000002 2014-04-17 06:34:00,88.458 2014-04-17 06:39:00,90.25 2014-04-17 06:44:00,86.63600000000002 2014-04-17 06:49:00,87.16799999999998 2014-04-17 06:54:00,82.292 2014-04-17 06:59:00,88.824 2014-04-17 07:04:00,89.162 2014-04-17 07:09:00,91.45 2014-04-17 07:14:00,88.514 2014-04-17 07:19:00,85.104 2014-04-17 07:24:00,89.17200000000004 2014-04-17 07:29:00,92.484 2014-04-17 07:34:00,88.25 2014-04-17 07:39:00,85.876 2014-04-17 07:44:00,88.24600000000002 2014-04-17 07:49:00,87.244 2014-04-17 07:54:00,88.738 2014-04-17 07:59:00,90.46600000000001 2014-04-17 08:04:00,91.37 2014-04-17 08:09:00,93.042 2014-04-17 08:14:00,92.72399999999999 2014-04-17 08:19:00,88.834 2014-04-17 08:24:00,87.198 2014-04-17 08:29:00,86.5 2014-04-17 08:34:00,86.75 2014-04-17 08:39:00,84.208 2014-04-17 08:44:00,85.0 2014-04-17 08:49:00,87.838 2014-04-17 08:54:00,90.834 2014-04-17 08:59:00,86.374 2014-04-17 09:04:00,87.126 2014-04-17 09:09:00,88.208 2014-04-17 09:14:00,88.39 2014-04-17 09:19:00,90.444 2014-04-17 09:24:00,88.80799999999998 2014-04-17 09:29:00,89.5 2014-04-17 09:34:00,90.126 2014-04-17 09:39:00,91.25 2014-04-17 09:44:00,87.708 2014-04-17 09:49:00,89.584 2014-04-17 09:54:00,86.324 2014-04-17 09:59:00,88.626 2014-04-17 10:04:00,86.28 2014-04-17 10:09:00,90.542 2014-04-17 10:14:00,87.874 2014-04-17 10:19:00,85.874 2014-04-17 10:24:00,91.818 2014-04-17 10:29:00,91.542 2014-04-17 10:34:00,92.47200000000001 2014-04-17 10:39:00,86.72399999999998 2014-04-17 10:44:00,90.044 2014-04-17 10:49:00,91.666 2014-04-17 10:54:00,85.25 2014-04-17 10:59:00,87.02799999999998 2014-04-17 11:04:00,89.708 2014-04-17 11:09:00,89.666 2014-04-17 11:14:00,89.708 2014-04-17 11:19:00,89.734 2014-04-17 11:24:00,89.75 2014-04-17 11:29:00,87.712 2014-04-17 11:34:00,88.25 2014-04-17 11:39:00,91.166 2014-04-17 11:44:00,88.084 2014-04-17 11:49:00,89.834 2014-04-17 11:54:00,85.542 2014-04-17 11:59:00,88.208 2014-04-17 12:04:00,91.25 2014-04-17 12:09:00,90.416 2014-04-17 12:14:00,89.834 2014-04-17 12:19:00,89.586 2014-04-17 12:24:00,88.958 2014-04-17 12:29:00,90.626 2014-04-17 12:34:00,90.634 2014-04-17 12:39:00,88.79 2014-04-17 12:44:00,88.042 2014-04-17 12:49:00,86.666 2014-04-17 12:54:00,83.792 2014-04-17 12:59:00,86.542 2014-04-17 13:04:00,89.82799999999996 2014-04-17 13:09:00,87.62200000000001 2014-04-17 13:14:00,89.166 2014-04-17 13:19:00,90.0 2014-04-17 13:24:00,88.374 2014-04-17 13:29:00,92.334 2014-04-17 13:34:00,93.208 2014-04-17 13:39:00,88.0 2014-04-17 13:44:00,87.012 2014-04-17 13:49:00,89.0 2014-04-17 13:54:00,86.626 2014-04-17 13:59:00,87.584 2014-04-17 14:04:00,84.292 2014-04-17 14:09:00,90.916 2014-04-17 14:14:00,89.458 2014-04-17 14:19:00,91.5 2014-04-17 14:24:00,91.89200000000001 2014-04-17 14:29:00,89.598 2014-04-17 14:34:00,91.792 2014-04-17 14:39:00,86.084 2014-04-17 14:44:00,83.33200000000002 2014-04-17 14:49:00,87.458 2014-04-17 14:54:00,85.75 2014-04-17 14:59:00,89.708 2014-04-17 15:04:00,87.416 2014-04-17 15:09:00,95.346 2014-04-17 15:14:00,92.426 2014-04-17 15:19:00,88.416 2014-04-17 15:24:00,87.334 2014-04-17 15:29:00,87.01799999999999 2014-04-17 15:34:00,90.67200000000001 2014-04-17 15:39:00,88.33 2014-04-17 15:44:00,86.75 2014-04-17 15:49:00,86.124 2014-04-17 15:54:00,92.916 2014-04-17 15:59:00,93.182 2014-04-17 16:04:00,95.0 2014-04-17 16:09:00,95.584 2014-04-17 16:14:00,93.834 2014-04-17 16:19:00,93.374 2014-04-17 16:24:00,93.042 2014-04-17 16:29:00,91.792 2014-04-17 16:34:00,87.626 2014-04-17 16:39:00,91.75 2014-04-17 16:44:00,85.69 2014-04-17 16:49:00,89.26 2014-04-17 16:54:00,86.164 2014-04-17 16:59:00,89.334 2014-04-17 17:04:00,91.84 2014-04-17 17:09:00,94.0 2014-04-17 17:14:00,91.25 2014-04-17 17:19:00,93.0 2014-04-17 17:24:00,92.25 2014-04-17 17:29:00,92.914 2014-04-17 17:34:00,92.5 2014-04-17 17:39:00,92.958 2014-04-17 17:44:00,92.958 2014-04-17 17:49:00,88.43799999999996 2014-04-17 17:54:00,88.22399999999998 2014-04-17 17:59:00,92.166 2014-04-17 18:04:00,93.958 2014-04-17 18:09:00,92.916 2014-04-17 18:14:00,93.74 2014-04-17 18:19:00,92.042 2014-04-17 18:24:00,92.208 2014-04-17 18:29:00,94.738 2014-04-17 18:34:00,94.6 2014-04-17 18:39:00,91.708 2014-04-17 18:44:00,92.22399999999999 2014-04-17 18:49:00,92.542 2014-04-17 18:54:00,93.32600000000001 2014-04-17 18:59:00,92.77600000000001 2014-04-17 19:04:00,88.484 2014-04-17 19:09:00,93.40799999999999 2014-04-17 19:14:00,95.12799999999999 2014-04-17 19:19:00,92.46 2014-04-17 19:24:00,90.958 2014-04-17 19:29:00,89.824 2014-04-17 19:34:00,89.92200000000004 2014-04-17 19:39:00,89.00399999999998 2014-04-17 19:44:00,89.25 2014-04-17 19:49:00,88.626 2014-04-17 19:54:00,94.51799999999999 2014-04-17 19:59:00,93.898 2014-04-17 20:04:00,91.764 2014-04-17 20:09:00,93.16799999999999 2014-04-17 20:14:00,89.11399999999998 2014-04-17 20:19:00,93.07600000000001 2014-04-17 20:24:00,91.014 2014-04-17 20:29:00,91.07799999999999 2014-04-17 20:34:00,94.792 2014-04-17 20:39:00,93.33200000000001 2014-04-17 20:44:00,93.88 2014-04-17 20:49:00,94.124 2014-04-17 20:54:00,94.542 2014-04-17 20:59:00,92.126 2014-04-17 21:04:00,92.166 2014-04-17 21:09:00,94.458 2014-04-17 21:14:00,92.25 2014-04-17 21:19:00,92.834 2014-04-17 21:24:00,91.428 2014-04-17 21:29:00,93.292 2014-04-17 21:34:00,91.792 2014-04-17 21:39:00,92.666 2014-04-17 21:44:00,95.042 2014-04-17 21:49:00,92.25 2014-04-17 21:54:00,90.916 2014-04-17 21:59:00,93.88 2014-04-17 22:04:00,92.124 2014-04-17 22:09:00,95.042 2014-04-17 22:14:00,92.542 2014-04-17 22:19:00,91.042 2014-04-17 22:24:00,92.75 2014-04-17 22:29:00,90.416 2014-04-17 22:34:00,94.084 2014-04-17 22:39:00,92.166 2014-04-17 22:44:00,91.208 2014-04-17 22:49:00,91.916 2014-04-17 22:54:00,90.916 2014-04-17 22:59:00,93.43 2014-04-17 23:04:00,92.874 2014-04-17 23:09:00,96.262 2014-04-17 23:14:00,93.37799999999999 2014-04-17 23:19:00,92.45 2014-04-17 23:24:00,93.19 2014-04-17 23:29:00,93.98200000000001 2014-04-17 23:34:00,93.26 2014-04-17 23:39:00,90.75 2014-04-17 23:44:00,92.064 2014-04-17 23:49:00,94.866 2014-04-17 23:54:00,93.162 2014-04-17 23:59:00,93.34 2014-04-18 00:04:00,92.64200000000001 2014-04-18 00:09:00,94.834 2014-04-18 00:14:00,91.666 2014-04-18 00:19:00,91.584 2014-04-18 00:24:00,92.666 2014-04-18 00:29:00,93.618 2014-04-18 00:34:00,94.568 2014-04-18 00:39:00,93.334 2014-04-18 00:44:00,94.166 2014-04-18 00:49:00,92.584 2014-04-18 00:54:00,94.95 2014-04-18 00:59:00,91.64399999999999 2014-04-18 01:04:00,87.874 2014-04-18 01:09:00,92.494 2014-04-18 01:14:00,90.96799999999999 2014-04-18 01:19:00,92.374 2014-04-18 01:24:00,93.042 2014-04-18 01:29:00,92.542 2014-04-18 01:34:00,93.624 2014-04-18 01:39:00,92.458 2014-04-18 01:44:00,94.21 2014-04-18 01:49:00,89.834 2014-04-18 01:54:00,89.656 2014-04-18 01:59:00,94.116 2014-04-18 02:04:00,90.084 2014-04-18 02:09:00,94.772 2014-04-18 02:14:00,91.376 2014-04-18 02:19:00,93.126 2014-04-18 02:24:00,92.90799999999999 2014-04-18 02:29:00,91.684 2014-04-18 02:34:00,90.708 2014-04-18 02:39:00,92.94 2014-04-18 02:44:00,88.042 2014-04-18 02:49:00,89.666 2014-04-18 02:54:00,89.208 2014-04-18 02:59:00,94.03399999999999 2014-04-18 03:04:00,90.432 2014-04-18 03:09:00,94.0 2014-04-18 03:14:00,92.61200000000001 2014-04-18 03:19:00,94.19 2014-04-18 03:24:00,92.766 2014-04-18 03:29:00,95.134 2014-04-18 03:34:00,89.98 2014-04-18 03:39:00,88.916 2014-04-18 03:44:00,88.792 2014-04-18 03:49:00,89.448 2014-04-18 03:54:00,90.042 2014-04-18 03:59:00,90.334 2014-04-18 04:04:00,87.662 2014-04-18 04:09:00,91.42200000000001 2014-04-18 04:14:00,91.848 2014-04-18 04:19:00,94.458 2014-04-18 04:24:00,91.876 2014-04-18 04:29:00,93.698 2014-04-18 04:34:00,93.07 2014-04-18 04:39:00,91.574 2014-04-18 04:44:00,90.738 2014-04-18 04:49:00,90.544 2014-04-18 04:54:00,90.428 2014-04-18 04:59:00,92.626 2014-04-18 05:04:00,88.0 2014-04-18 05:09:00,93.292 2014-04-18 05:14:00,92.916 2014-04-18 05:19:00,92.374 2014-04-18 05:24:00,92.958 2014-04-18 05:29:00,90.542 2014-04-18 05:34:00,93.5 2014-04-18 05:39:00,91.916 2014-04-18 05:44:00,90.60799999999999 2014-04-18 05:49:00,92.208 2014-04-18 05:54:00,90.208 2014-04-18 05:59:00,91.85600000000001 2014-04-18 06:04:00,90.334 2014-04-18 06:09:00,94.71600000000001 2014-04-18 06:14:00,91.376 2014-04-18 06:19:00,90.458 2014-04-18 06:24:00,93.352 2014-04-18 06:29:00,88.428 2014-04-18 06:34:00,92.084 2014-04-18 06:39:00,92.75 2014-04-18 06:44:00,91.708 2014-04-18 06:49:00,92.124 2014-04-18 06:54:00,93.084 2014-04-18 06:59:00,95.542 2014-04-18 07:04:00,86.208 2014-04-18 07:09:00,95.416 2014-04-18 07:14:00,91.916 2014-04-18 07:19:00,87.084 2014-04-18 07:24:00,84.488 2014-04-18 07:29:00,89.416 2014-04-18 07:34:00,85.208 2014-04-18 07:39:00,90.0 2014-04-18 07:44:00,83.29 2014-04-18 07:49:00,89.366 2014-04-18 07:54:00,88.454 2014-04-18 07:59:00,89.682 2014-04-18 08:04:00,89.258 2014-04-18 08:09:00,94.708 2014-04-18 08:14:00,92.458 2014-04-18 08:19:00,86.988 2014-04-18 08:24:00,87.64200000000002 2014-04-18 08:29:00,89.75 2014-04-18 08:34:00,88.426 2014-04-18 08:39:00,85.208 2014-04-18 08:44:00,88.916 2014-04-18 08:49:00,83.75 2014-04-18 08:54:00,89.986 2014-04-18 08:59:00,89.78 2014-04-18 09:04:00,90.572 2014-04-18 09:09:00,95.63600000000001 2014-04-18 09:14:00,91.97399999999999 2014-04-18 09:19:00,87.876 2014-04-18 09:24:00,84.584 2014-04-18 09:29:00,89.0 2014-04-18 09:34:00,86.626 2014-04-18 09:39:00,85.334 2014-04-18 09:44:00,88.666 2014-04-18 09:49:00,89.772 2014-04-18 09:54:00,87.516 2014-04-18 09:59:00,90.374 2014-04-18 10:04:00,87.458 2014-04-18 10:09:00,93.876 2014-04-18 10:14:00,92.208 2014-04-18 10:19:00,86.52600000000002 2014-04-18 10:24:00,92.604 2014-04-18 10:29:00,92.0 2014-04-18 10:34:00,89.584 2014-04-18 10:39:00,88.53 2014-04-18 10:44:00,89.23 2014-04-18 10:49:00,87.042 2014-04-18 10:54:00,87.454 2014-04-18 10:59:00,87.126 2014-04-18 11:04:00,87.646 2014-04-18 11:09:00,88.666 2014-04-18 11:14:00,92.84 2014-04-18 11:19:00,89.208 2014-04-18 11:24:00,89.084 2014-04-18 11:29:00,94.292 2014-04-18 11:34:00,92.376 2014-04-18 11:39:00,88.874 2014-04-18 11:44:00,87.416 2014-04-18 11:49:00,87.24 2014-04-18 11:54:00,86.17200000000004 2014-04-18 11:59:00,85.626 2014-04-18 12:04:00,87.416 2014-04-18 12:09:00,91.084 2014-04-18 12:14:00,90.664 2014-04-18 12:19:00,92.376 2014-04-18 12:24:00,93.02 2014-04-18 12:29:00,89.23 2014-04-18 12:34:00,86.876 2014-04-18 12:39:00,87.042 2014-04-18 12:44:00,86.48 2014-04-18 12:49:00,87.126 2014-04-18 12:54:00,84.792 2014-04-18 12:59:00,87.416 2014-04-18 13:04:00,85.75 2014-04-18 13:09:00,92.75 2014-04-18 13:14:00,89.834 2014-04-18 13:19:00,90.33 2014-04-18 13:24:00,91.35 2014-04-18 13:29:00,91.774 2014-04-18 13:34:00,86.626 2014-04-18 13:39:00,90.0 2014-04-18 13:44:00,88.134 2014-04-18 13:49:00,90.96799999999999 2014-04-18 13:54:00,88.042 2014-04-18 13:59:00,85.626 2014-04-18 14:04:00,84.042 2014-04-18 14:09:00,94.874 2014-04-18 14:14:00,90.75 2014-04-18 14:19:00,92.792 2014-04-18 14:24:00,86.288 2014-04-18 14:29:00,88.75 2014-04-18 14:34:00,87.416 2014-04-18 14:39:00,90.51 2014-04-18 14:44:00,90.876 2014-04-18 14:49:00,89.756 2014-04-18 14:54:00,88.09200000000001 2014-04-18 14:59:00,87.916 2014-04-18 15:04:00,87.124 2014-04-18 15:09:00,92.5 2014-04-18 15:14:00,93.458 2014-04-18 15:19:00,87.792 2014-04-18 15:24:00,87.0 2014-04-18 15:29:00,85.334 2014-04-18 15:34:00,88.458 2014-04-18 15:39:00,90.374 2014-04-18 15:44:00,85.594 2014-04-18 15:49:00,88.916 2014-04-18 15:54:00,85.166 2014-04-18 15:59:00,90.292 2014-04-18 16:04:00,88.042 2014-04-18 16:09:00,87.292 2014-04-18 16:14:00,89.49600000000002 2014-04-18 16:19:00,93.042 2014-04-18 16:24:00,91.25 2014-04-18 16:29:00,92.334 2014-04-18 16:34:00,87.75 2014-04-18 16:39:00,88.098 2014-04-18 16:44:00,86.876 2014-04-18 16:49:00,87.416 2014-04-18 16:54:00,88.01 2014-04-18 16:59:00,86.75 2014-04-18 17:04:00,87.792 2014-04-18 17:09:00,87.374 2014-04-18 17:14:00,91.75 2014-04-18 17:19:00,92.416 2014-04-18 17:24:00,90.042 2014-04-18 17:29:00,86.75 2014-04-18 17:34:00,89.682 2014-04-18 17:39:00,86.934 2014-04-18 17:44:00,87.834 2014-04-18 17:49:00,86.5 2014-04-18 17:54:00,88.0 2014-04-18 17:59:00,86.62799999999999 2014-04-18 18:04:00,87.794 2014-04-18 18:09:00,91.15799999999999 2014-04-18 18:14:00,90.73 2014-04-18 18:19:00,92.874 2014-04-18 18:24:00,86.916 2014-04-18 18:29:00,85.626 2014-04-18 18:34:00,90.742 2014-04-18 18:39:00,90.67399999999999 2014-04-18 18:44:00,86.936 2014-04-18 18:49:00,84.958 2014-04-18 18:54:00,89.792 2014-04-18 18:59:00,87.25 2014-04-18 19:04:00,88.594 2014-04-18 19:09:00,92.186 2014-04-18 19:14:00,91.042 2014-04-18 19:19:00,90.118 2014-04-18 19:24:00,92.1 2014-04-18 19:29:00,91.458 2014-04-18 19:34:00,92.792 2014-04-18 19:39:00,90.516 2014-04-18 19:44:00,89.564 2014-04-18 19:49:00,89.488 2014-04-18 19:54:00,92.23 2014-04-18 19:59:00,91.876 2014-04-18 20:04:00,86.744 2014-04-18 20:09:00,94.124 2014-04-18 20:14:00,93.334 2014-04-18 20:19:00,91.376 2014-04-18 20:24:00,87.626 2014-04-18 20:29:00,86.5 2014-04-18 20:34:00,87.60799999999998 2014-04-18 20:39:00,87.708 2014-04-18 20:44:00,86.542 2014-04-18 20:49:00,87.3 2014-04-18 20:54:00,87.914 2014-04-18 20:59:00,87.626 2014-04-18 21:04:00,87.416 2014-04-18 21:09:00,90.376 2014-04-18 21:14:00,90.69200000000001 2014-04-18 21:19:00,93.042 2014-04-18 21:24:00,87.446 2014-04-18 21:29:00,89.792 2014-04-18 21:34:00,87.874 2014-04-18 21:39:00,86.416 2014-04-18 21:44:00,86.876 2014-04-18 21:49:00,87.126 2014-04-18 21:54:00,87.898 2014-04-18 21:59:00,88.084 2014-04-18 22:04:00,92.584 2014-04-18 22:09:00,92.944 2014-04-18 22:14:00,95.014 2014-04-18 22:19:00,88.42 2014-04-18 22:24:00,88.042 2014-04-18 22:29:00,87.666 2014-04-18 22:34:00,87.542 2014-04-18 22:39:00,86.084 2014-04-18 22:44:00,87.708 2014-04-18 22:49:00,88.292 2014-04-18 22:54:00,85.256 2014-04-18 22:59:00,87.708 2014-04-18 23:04:00,90.75 2014-04-18 23:09:00,92.88 2014-04-18 23:14:00,92.258 2014-04-18 23:19:00,93.286 2014-04-18 23:24:00,92.584 2014-04-18 23:29:00,90.48200000000001 2014-04-18 23:34:00,87.584 2014-04-18 23:39:00,86.75399999999998 2014-04-18 23:44:00,87.042 2014-04-18 23:49:00,86.916 2014-04-18 23:54:00,86.542 2014-04-18 23:59:00,89.334 2014-04-19 00:04:00,86.67399999999998 2014-04-19 00:09:00,93.624 2014-04-19 00:14:00,92.25 2014-04-19 00:19:00,91.124 2014-04-19 00:24:00,88.666 2014-04-19 00:29:00,85.5 2014-04-19 00:34:00,91.152 2014-04-19 00:39:00,87.458 2014-04-19 00:44:00,84.458 2014-04-19 00:49:00,91.916 2014-04-19 00:54:00,89.166 2014-04-19 00:59:00,87.708 2014-04-19 01:04:00,87.876 2014-04-19 01:09:00,89.458 2014-04-19 01:14:00,92.47 2014-04-19 01:19:00,91.126 2014-04-19 01:24:00,89.584 2014-04-19 01:29:00,87.0 2014-04-19 01:34:00,88.25 2014-04-19 01:39:00,86.958 2014-04-19 01:44:00,87.25 2014-04-19 01:49:00,87.584 2014-04-19 01:54:00,86.584 2014-04-19 01:59:00,90.75 2014-04-19 02:04:00,89.042 2014-04-19 02:09:00,94.124 2014-04-19 02:14:00,91.208 2014-04-19 02:19:00,91.084 2014-04-19 02:24:00,89.166 2014-04-19 02:29:00,87.916 2014-04-19 02:34:00,88.05799999999998 2014-04-19 02:39:00,85.626 2014-04-19 02:44:00,86.708 2014-04-19 02:49:00,86.416 2014-04-19 02:54:00,88.758 2014-04-19 02:59:00,87.916 2014-04-19 03:04:00,88.25 2014-04-19 03:09:00,86.82799999999996 2014-04-19 03:14:00,93.042 2014-04-19 03:19:00,92.79799999999999 2014-04-19 03:24:00,85.958 2014-04-19 03:29:00,86.292 2014-04-19 03:34:00,88.088 2014-04-19 03:39:00,85.788 2014-04-19 03:44:00,90.084 2014-04-19 03:49:00,86.834 2014-04-19 03:54:00,86.834 2014-04-19 03:59:00,86.25200000000002 2014-04-19 04:04:00,87.126 2014-04-19 04:09:00,94.0 2014-04-19 04:14:00,92.792 2014-04-19 04:19:00,86.708 2014-04-19 04:24:00,87.296 2014-04-19 04:29:00,85.708 2014-04-19 04:34:00,86.166 2014-04-19 04:39:00,87.584 2014-04-19 04:44:00,88.126 2014-04-19 04:49:00,84.32600000000002 2014-04-19 04:54:00,90.354 2014-04-19 04:59:00,87.572 2014-04-19 05:04:00,88.166 2014-04-19 05:09:00,93.834 2014-04-19 05:14:00,90.708 2014-04-19 05:19:00,91.708 2014-04-19 05:24:00,89.458 2014-04-19 05:29:00,86.874 2014-04-19 05:34:00,86.764 2014-04-19 05:39:00,84.834 2014-04-19 05:44:00,88.458 2014-04-19 05:49:00,85.876 2014-04-19 05:54:00,88.584 2014-04-19 05:59:00,90.542 2014-04-19 06:04:00,88.666 2014-04-19 06:09:00,89.376 2014-04-19 06:14:00,93.916 2014-04-19 06:19:00,91.428 2014-04-19 06:24:00,86.666 2014-04-19 06:29:00,86.916 2014-04-19 06:34:00,87.334 2014-04-19 06:39:00,90.76799999999999 2014-04-19 06:44:00,86.376 2014-04-19 06:49:00,87.542 2014-04-19 06:54:00,87.25 2014-04-19 06:59:00,87.584 2014-04-19 07:04:00,87.084 2014-04-19 07:09:00,87.57600000000002 2014-04-19 07:14:00,90.458 2014-04-19 07:19:00,93.838 2014-04-19 07:24:00,89.458 2014-04-19 07:29:00,89.834 2014-04-19 07:34:00,87.75 2014-04-19 07:39:00,86.334 2014-04-19 07:44:00,88.334 2014-04-19 07:49:00,85.984 2014-04-19 07:54:00,88.18 2014-04-19 07:59:00,87.556 2014-04-19 08:04:00,87.72200000000002 2014-04-19 08:09:00,88.75 2014-04-19 08:14:00,92.916 2014-04-19 08:19:00,93.126 2014-04-19 08:24:00,87.666 2014-04-19 08:29:00,89.542 2014-04-19 08:34:00,87.584 2014-04-19 08:39:00,87.542 2014-04-19 08:44:00,86.376 2014-04-19 08:49:00,87.458 2014-04-19 08:54:00,87.916 2014-04-19 08:59:00,88.126 2014-04-19 09:04:00,87.25 2014-04-19 09:09:00,88.792 2014-04-19 09:14:00,93.416 2014-04-19 09:19:00,92.334 2014-04-19 09:24:00,84.584 2014-04-19 09:29:00,89.094 2014-04-19 09:34:00,89.35799999999998 2014-04-19 09:39:00,87.792 2014-04-19 09:44:00,90.792 2014-04-19 09:49:00,87.75 2014-04-19 09:54:00,87.958 2014-04-19 09:59:00,87.792 2014-04-19 10:04:00,88.834 2014-04-19 10:09:00,92.75 2014-04-19 10:14:00,92.834 2014-04-19 10:19:00,88.126 2014-04-19 10:24:00,87.166 2014-04-19 10:29:00,87.834 2014-04-19 10:34:00,85.758 2014-04-19 10:39:00,88.876 2014-04-19 10:44:00,86.666 2014-04-19 10:49:00,87.25 2014-04-19 10:54:00,86.758 2014-04-19 10:59:00,87.1 2014-04-19 11:04:00,87.322 2014-04-19 11:09:00,95.876 2014-04-19 11:14:00,90.126 2014-04-19 11:19:00,88.126 2014-04-19 11:24:00,87.458 2014-04-19 11:29:00,86.834 2014-04-19 11:34:00,87.88600000000002 2014-04-19 11:39:00,84.79799999999999 2014-04-19 11:44:00,85.208 2014-04-19 11:49:00,89.958 2014-04-19 11:54:00,84.376 2014-04-19 11:59:00,92.916 2014-04-19 12:04:00,91.75 2014-04-19 12:09:00,93.334 2014-04-19 12:14:00,93.166 2014-04-19 12:19:00,86.416 2014-04-19 12:24:00,86.708 2014-04-19 12:29:00,89.834 2014-04-19 12:34:00,83.874 2014-04-19 12:39:00,90.334 2014-04-19 12:44:00,85.81 2014-04-19 12:49:00,89.514 2014-04-19 12:54:00,88.21799999999998 2014-04-19 12:59:00,87.584 2014-04-19 13:04:00,88.0 2014-04-19 13:09:00,93.056 2014-04-19 13:14:00,91.24600000000001 2014-04-19 13:19:00,89.376 2014-04-19 13:24:00,85.834 2014-04-19 13:29:00,89.0 2014-04-19 13:34:00,86.9 2014-04-19 13:39:00,87.37 2014-04-19 13:44:00,86.0 2014-04-19 13:49:00,86.04799999999999 2014-04-19 13:54:00,90.81200000000001 2014-04-19 13:59:00,86.292 2014-04-19 14:04:00,87.0 2014-04-19 14:09:00,91.08 2014-04-19 14:14:00,92.126 2014-04-19 14:19:00,92.54 2014-04-19 14:24:00,86.734 2014-04-19 14:29:00,88.52 2014-04-19 14:34:00,90.916 2014-04-19 14:39:00,86.416 2014-04-19 14:44:00,86.91799999999998 2014-04-19 14:49:00,88.376 2014-04-19 14:54:00,89.61 2014-04-19 14:59:00,87.35600000000002 2014-04-19 15:04:00,87.166 2014-04-19 15:09:00,89.292 2014-04-19 15:14:00,93.084 2014-04-19 15:19:00,92.75 2014-04-19 15:24:00,85.992 2014-04-19 15:29:00,87.75 2014-04-19 15:34:00,86.02799999999998 2014-04-19 15:39:00,90.542 2014-04-19 15:44:00,87.25 2014-04-19 15:49:00,87.708 2014-04-19 15:54:00,87.958 2014-04-19 15:59:00,88.084 2014-04-19 16:04:00,88.37200000000001 2014-04-19 16:09:00,90.292 2014-04-19 16:14:00,93.084 2014-04-19 16:19:00,94.416 2014-04-19 16:24:00,88.126 2014-04-19 16:29:00,85.666 2014-04-19 16:34:00,89.542 2014-04-19 16:39:00,87.302 2014-04-19 16:44:00,86.708 2014-04-19 16:49:00,87.208 2014-04-19 16:54:00,87.876 2014-04-19 16:59:00,87.83 2014-04-19 17:04:00,87.626 2014-04-19 17:09:00,87.916 2014-04-19 17:14:00,93.458 2014-04-19 17:19:00,90.624 2014-04-19 17:24:00,85.33 2014-04-19 17:29:00,89.042 2014-04-19 17:34:00,89.072 2014-04-19 17:39:00,87.542 2014-04-19 17:44:00,86.874 2014-04-19 17:49:00,87.792 2014-04-19 17:54:00,85.762 2014-04-19 17:59:00,87.52600000000002 2014-04-19 18:04:00,86.17200000000004 2014-04-19 18:09:00,93.0 2014-04-19 18:14:00,90.542 2014-04-19 18:19:00,92.99799999999999 2014-04-19 18:24:00,88.45 2014-04-19 18:29:00,91.146 2014-04-19 18:34:00,85.07600000000002 2014-04-19 18:39:00,84.75 2014-04-19 18:44:00,91.416 2014-04-19 18:49:00,91.59 2014-04-19 18:54:00,87.916 2014-04-19 18:59:00,87.208 2014-04-19 19:04:00,87.196 2014-04-19 19:09:00,95.124 2014-04-19 19:14:00,94.042 2014-04-19 19:19:00,89.458 2014-04-19 19:24:00,85.75 2014-04-19 19:29:00,91.124 2014-04-19 19:34:00,87.834 2014-04-19 19:39:00,87.792 2014-04-19 19:44:00,87.374 2014-04-19 19:49:00,87.064 2014-04-19 19:54:00,87.846 2014-04-19 19:59:00,88.416 2014-04-19 20:04:00,88.834 2014-04-19 20:09:00,90.39 2014-04-19 20:14:00,92.584 2014-04-19 20:19:00,92.288 2014-04-19 20:24:00,86.5 2014-04-19 20:29:00,83.5 2014-04-19 20:34:00,88.10600000000002 2014-04-19 20:39:00,89.916 2014-04-19 20:44:00,89.834 2014-04-19 20:49:00,86.88600000000002 2014-04-19 20:54:00,88.166 2014-04-19 20:59:00,85.916 2014-04-19 21:04:00,88.44 2014-04-19 21:09:00,91.542 2014-04-19 21:14:00,90.416 2014-04-19 21:19:00,92.708 2014-04-19 21:24:00,88.166 2014-04-19 21:29:00,92.292 2014-04-19 21:34:00,87.0 2014-04-19 21:39:00,91.584 2014-04-19 21:44:00,86.834 2014-04-19 21:49:00,87.07 2014-04-19 21:54:00,84.792 2014-04-19 21:59:00,91.91799999999999 2014-04-19 22:04:00,88.208 2014-04-19 22:09:00,89.5 2014-04-19 22:14:00,91.802 2014-04-19 22:19:00,94.67399999999999 2014-04-19 22:24:00,87.958 2014-04-19 22:29:00,90.542 2014-04-19 22:34:00,88.042 2014-04-19 22:39:00,87.166 2014-04-19 22:44:00,86.916 2014-04-19 22:49:00,86.708 2014-04-19 22:54:00,85.792 2014-04-19 22:59:00,87.708 2014-04-19 23:04:00,88.876 2014-04-19 23:09:00,91.0 2014-04-19 23:14:00,92.34200000000001 2014-04-19 23:19:00,93.82799999999999 2014-04-19 23:24:00,90.084 2014-04-19 23:29:00,87.73 2014-04-19 23:34:00,88.302 2014-04-19 23:39:00,89.834 2014-04-19 23:44:00,86.084 2014-04-19 23:49:00,87.88799999999998 2014-04-19 23:54:00,87.34200000000001 2014-04-19 23:59:00,88.708 2014-04-20 00:04:00,84.874 2014-04-20 00:09:00,93.458 2014-04-20 00:14:00,92.834 2014-04-20 00:19:00,93.166 2014-04-20 00:24:00,92.292 2014-04-20 00:29:00,88.624 2014-04-20 00:34:00,87.384 2014-04-20 00:39:00,87.542 2014-04-20 00:44:00,86.834 2014-04-20 00:49:00,87.208 2014-04-20 00:54:00,87.458 2014-04-20 00:59:00,85.458 2014-04-20 01:04:00,87.79 2014-04-20 01:09:00,89.374 2014-04-20 01:14:00,88.5 2014-04-20 01:19:00,91.124 2014-04-20 01:24:00,90.5 2014-04-20 01:29:00,87.958 2014-04-20 01:34:00,90.584 2014-04-20 01:39:00,90.27 2014-04-20 01:44:00,87.834 2014-04-20 01:49:00,87.374 2014-04-20 01:54:00,84.708 2014-04-20 01:59:00,89.584 2014-04-20 02:04:00,88.208 2014-04-20 02:09:00,90.834 2014-04-20 02:14:00,91.042 2014-04-20 02:19:00,92.25 2014-04-20 02:24:00,88.416 2014-04-20 02:29:00,88.374 2014-04-20 02:34:00,88.126 2014-04-20 02:39:00,89.384 2014-04-20 02:44:00,86.916 2014-04-20 02:49:00,87.584 2014-04-20 02:54:00,87.25 2014-04-20 02:59:00,89.25 2014-04-20 03:04:00,87.708 2014-04-20 03:09:00,92.792 2014-04-20 03:14:00,90.512 2014-04-20 03:19:00,92.084 2014-04-20 03:24:00,89.88600000000002 2014-04-20 03:29:00,88.0 2014-04-20 03:34:00,88.24799999999998 2014-04-20 03:39:00,86.876 2014-04-20 03:44:00,86.88600000000002 2014-04-20 03:49:00,86.542 2014-04-20 03:54:00,85.042 2014-04-20 03:59:00,91.626 2014-04-20 04:04:00,87.066 2014-04-20 04:09:00,90.152 2014-04-20 04:14:00,92.89399999999999 2014-04-20 04:19:00,94.432 2014-04-20 04:24:00,90.626 2014-04-20 04:29:00,85.5 2014-04-20 04:34:00,87.376 2014-04-20 04:39:00,88.37 2014-04-20 04:44:00,87.624 2014-04-20 04:49:00,88.286 2014-04-20 04:54:00,90.75 2014-04-20 04:59:00,86.0 2014-04-20 05:04:00,88.208 2014-04-20 05:09:00,89.334 2014-04-20 05:14:00,95.084 2014-04-20 05:19:00,93.85 2014-04-20 05:24:00,89.712 2014-04-20 05:29:00,88.126 2014-04-20 05:34:00,86.506 2014-04-20 05:39:00,87.416 2014-04-20 05:44:00,87.084 2014-04-20 05:49:00,86.958 2014-04-20 05:54:00,89.084 2014-04-20 05:59:00,88.154 2014-04-20 06:04:00,87.666 2014-04-20 06:09:00,95.932 2014-04-20 06:14:00,94.624 2014-04-20 06:19:00,92.166 2014-04-20 06:24:00,90.09 2014-04-20 06:29:00,87.62 2014-04-20 06:34:00,87.584 2014-04-20 06:39:00,87.876 2014-04-20 06:44:00,87.25 2014-04-20 06:49:00,86.85799999999998 2014-04-20 06:54:00,85.374 2014-04-20 06:59:00,91.542 2014-04-20 07:04:00,87.74799999999998 2014-04-20 07:09:00,90.166 2014-04-20 07:14:00,92.916 2014-04-20 07:19:00,88.876 2014-04-20 07:24:00,87.588 2014-04-20 07:29:00,90.834 2014-04-20 07:34:00,89.166 2014-04-20 07:39:00,88.042 2014-04-20 07:44:00,87.874 2014-04-20 07:49:00,87.38 2014-04-20 07:54:00,88.792 2014-04-20 07:59:00,88.166 2014-04-20 08:04:00,88.0 2014-04-20 08:09:00,93.834 2014-04-20 08:14:00,92.334 2014-04-20 08:19:00,91.084 2014-04-20 08:24:00,87.792 2014-04-20 08:29:00,87.67399999999998 2014-04-20 08:34:00,87.624 2014-04-20 08:39:00,88.084 2014-04-20 08:44:00,87.042 2014-04-20 08:49:00,86.52799999999998 2014-04-20 08:54:00,86.116 2014-04-20 08:59:00,87.958 2014-04-20 09:04:00,89.416 2014-04-20 09:09:00,90.964 2014-04-20 09:14:00,93.258 2014-04-20 09:19:00,90.096 2014-04-20 09:24:00,88.584 2014-04-20 09:29:00,87.75 2014-04-20 09:34:00,86.584 2014-04-20 09:39:00,87.25 2014-04-20 09:44:00,87.32799999999996 2014-04-20 09:49:00,86.96 2014-04-20 09:54:00,88.6 2014-04-20 09:59:00,88.39200000000002 2014-04-20 10:04:00,87.76 2014-04-20 10:09:00,93.084 2014-04-20 10:14:00,93.584 2014-04-20 10:19:00,90.708 2014-04-20 10:24:00,87.25 2014-04-20 10:29:00,87.208 2014-04-20 10:34:00,87.666 2014-04-20 10:39:00,88.042 2014-04-20 10:44:00,87.416 2014-04-20 10:49:00,86.87799999999999 2014-04-20 10:54:00,87.666 2014-04-20 10:59:00,86.208 2014-04-20 11:04:00,88.292 2014-04-20 11:09:00,89.666 2014-04-20 11:14:00,92.334 2014-04-20 11:19:00,93.166 2014-04-20 11:24:00,87.596 2014-04-20 11:29:00,87.834 2014-04-20 11:34:00,86.834 2014-04-20 11:39:00,87.462 2014-04-20 11:44:00,87.126 2014-04-20 11:49:00,86.916 2014-04-20 11:54:00,88.25 2014-04-20 11:59:00,88.5 2014-04-20 12:04:00,87.916 2014-04-20 12:09:00,92.25 2014-04-20 12:14:00,94.2 2014-04-20 12:19:00,90.208 2014-04-20 12:24:00,88.792 2014-04-20 12:29:00,85.792 2014-04-20 12:34:00,87.0 2014-04-20 12:39:00,88.0 2014-04-20 12:44:00,86.75399999999998 2014-04-20 12:49:00,90.916 2014-04-20 12:54:00,88.542 2014-04-20 12:59:00,87.414 2014-04-20 13:04:00,87.708 2014-04-20 13:09:00,88.584 2014-04-20 13:14:00,93.5 2014-04-20 13:19:00,92.624 2014-04-20 13:24:00,85.786 2014-04-20 13:29:00,88.824 2014-04-20 13:34:00,87.334 2014-04-20 13:39:00,87.042 2014-04-20 13:44:00,89.456 2014-04-20 13:49:00,86.916 2014-04-20 13:54:00,88.374 2014-04-20 13:59:00,88.206 2014-04-20 14:04:00,87.958 2014-04-20 14:09:00,90.67200000000001 2014-04-20 14:14:00,91.624 2014-04-20 14:19:00,92.0 2014-04-20 14:24:00,89.414 2014-04-20 14:29:00,92.0 2014-04-20 14:34:00,89.916 2014-04-20 14:39:00,87.626 2014-04-20 14:44:00,87.03200000000002 2014-04-20 14:49:00,86.852 2014-04-20 14:54:00,87.198 2014-04-20 14:59:00,86.792 2014-04-20 15:04:00,89.792 2014-04-20 15:09:00,90.124 2014-04-20 15:14:00,91.792 2014-04-20 15:19:00,92.25 2014-04-20 15:24:00,85.916 2014-04-20 15:29:00,88.126 2014-04-20 15:34:00,87.916 2014-04-20 15:39:00,86.334 2014-04-20 15:44:00,87.792 2014-04-20 15:49:00,89.084 2014-04-20 15:54:00,87.824 2014-04-20 15:59:00,88.75 2014-04-20 16:04:00,87.458 2014-04-20 16:09:00,90.042 2014-04-20 16:14:00,89.214 2014-04-20 16:19:00,90.75 2014-04-20 16:24:00,89.458 2014-04-20 16:29:00,89.0 2014-04-20 16:34:00,87.126 2014-04-20 16:39:00,90.43 2014-04-20 16:44:00,87.458 2014-04-20 16:49:00,87.334 2014-04-20 16:54:00,85.834 2014-04-20 16:59:00,90.916 2014-04-20 17:04:00,88.25 2014-04-20 17:09:00,95.416 2014-04-20 17:14:00,93.97 2014-04-20 17:19:00,88.5 2014-04-20 17:24:00,87.846 2014-04-20 17:29:00,86.21799999999998 2014-04-20 17:34:00,89.66 2014-04-20 17:39:00,87.244 2014-04-20 17:44:00,88.868 2014-04-20 17:49:00,87.564 2014-04-20 17:54:00,87.006 2014-04-20 17:59:00,93.902 2014-04-20 18:04:00,87.944 2014-04-20 18:09:00,94.986 2014-04-20 18:14:00,93.072 2014-04-20 18:19:00,91.36399999999999 2014-04-20 18:24:00,87.792 2014-04-20 18:29:00,92.458 2014-04-20 18:34:00,86.75399999999998 2014-04-20 18:39:00,88.0 2014-04-20 18:44:00,87.49600000000002 2014-04-20 18:49:00,87.294 2014-04-20 18:54:00,88.354 2014-04-20 18:59:00,87.876 2014-04-20 19:04:00,86.876 2014-04-20 19:09:00,92.374 2014-04-20 19:14:00,92.042 2014-04-20 19:19:00,91.5 2014-04-20 19:24:00,87.834 2014-04-20 19:29:00,88.084 2014-04-20 19:34:00,90.75 2014-04-20 19:39:00,87.916 2014-04-20 19:44:00,87.626 2014-04-20 19:49:00,87.36 2014-04-20 19:54:00,89.22 2014-04-20 19:59:00,88.96 2014-04-20 20:04:00,88.166 2014-04-20 20:09:00,88.958 2014-04-20 20:14:00,95.5 2014-04-20 20:19:00,91.792 2014-04-20 20:24:00,88.584 2014-04-20 20:29:00,87.83 2014-04-20 20:34:00,88.25 2014-04-20 20:39:00,88.958 2014-04-20 20:44:00,86.874 2014-04-20 20:49:00,87.208 2014-04-20 20:54:00,89.126 2014-04-20 20:59:00,87.792 2014-04-20 21:04:00,86.5 2014-04-20 21:09:00,88.084 2014-04-20 21:14:00,93.132 2014-04-20 21:19:00,93.588 2014-04-20 21:24:00,92.916 2014-04-20 21:29:00,90.056 2014-04-20 21:34:00,87.014 2014-04-20 21:39:00,88.166 2014-04-20 21:44:00,88.43 2014-04-20 21:49:00,87.334 2014-04-20 21:54:00,88.542 2014-04-20 21:59:00,88.834 2014-04-20 22:04:00,89.124 2014-04-20 22:09:00,93.354 2014-04-20 22:14:00,92.792 2014-04-20 22:19:00,89.208 2014-04-20 22:24:00,88.25 2014-04-20 22:29:00,87.958 2014-04-20 22:34:00,87.834 2014-04-20 22:39:00,89.044 2014-04-20 22:44:00,87.11399999999998 2014-04-20 22:49:00,87.208 2014-04-20 22:54:00,89.042 2014-04-20 22:59:00,87.584 2014-04-20 23:04:00,86.75 2014-04-20 23:09:00,89.958 2014-04-20 23:14:00,94.44200000000001 2014-04-20 23:19:00,93.084 2014-04-20 23:24:00,92.75 2014-04-20 23:29:00,89.116 2014-04-20 23:34:00,87.42 2014-04-20 23:39:00,87.25 2014-04-20 23:44:00,87.74 2014-04-20 23:49:00,87.46600000000002 2014-04-20 23:54:00,89.37799999999999 2014-04-20 23:59:00,88.126 2014-04-21 00:04:00,88.208 2014-04-21 00:09:00,94.124 2014-04-21 00:14:00,93.006 2014-04-21 00:19:00,91.666 2014-04-21 00:24:00,87.916 2014-04-21 00:29:00,87.458 2014-04-21 00:34:00,87.584 2014-04-21 00:39:00,88.412 2014-04-21 00:44:00,85.62 2014-04-21 00:49:00,88.396 2014-04-21 00:54:00,84.584 2014-04-21 00:59:00,90.042 2014-04-21 01:04:00,89.17399999999998 2014-04-21 01:09:00,91.572 2014-04-21 01:14:00,91.334 2014-04-21 01:19:00,94.63799999999999 2014-04-21 01:24:00,87.398 2014-04-21 01:29:00,87.74600000000002 2014-04-21 01:34:00,91.334 2014-04-21 01:39:00,87.834 2014-04-21 01:44:00,87.958 2014-04-21 01:49:00,87.75399999999998 2014-04-21 01:54:00,89.042 2014-04-21 01:59:00,88.124 2014-04-21 02:04:00,88.626 2014-04-21 02:09:00,90.834 2014-04-21 02:14:00,92.208 2014-04-21 02:19:00,91.916 2014-04-21 02:24:00,88.876 2014-04-21 02:29:00,88.708 2014-04-21 02:34:00,91.916 2014-04-21 02:39:00,88.87799999999999 2014-04-21 02:44:00,87.54 2014-04-21 02:49:00,87.084 2014-04-21 02:54:00,88.334 2014-04-21 02:59:00,88.0 2014-04-21 03:04:00,88.166 2014-04-21 03:09:00,90.54799999999999 2014-04-21 03:14:00,92.792 2014-04-21 03:19:00,94.376 2014-04-21 03:24:00,90.124 2014-04-21 03:29:00,88.042 2014-04-21 03:34:00,86.834 2014-04-21 03:39:00,86.75 2014-04-21 03:44:00,86.69200000000002 2014-04-21 03:49:00,87.25 2014-04-21 03:54:00,87.792 2014-04-21 03:59:00,87.416 2014-04-21 04:04:00,90.84200000000001 2014-04-21 04:09:00,87.95 2014-04-21 04:14:00,91.906 2014-04-21 04:19:00,91.5 2014-04-21 04:24:00,91.834 2014-04-21 04:29:00,89.708 2014-04-21 04:34:00,90.368 2014-04-21 04:39:00,92.654 2014-04-21 04:44:00,87.292 2014-04-21 04:49:00,87.126 2014-04-21 04:54:00,85.196 2014-04-21 04:59:00,90.96799999999999 2014-04-21 05:04:00,86.876 2014-04-21 05:09:00,90.042 2014-04-21 05:14:00,90.874 2014-04-21 05:19:00,92.396 2014-04-21 05:24:00,94.212 2014-04-21 05:29:00,89.82799999999996 2014-04-21 05:34:00,88.166 2014-04-21 05:39:00,87.834 2014-04-21 05:44:00,87.626 2014-04-21 05:49:00,87.958 2014-04-21 05:54:00,89.704 2014-04-21 05:59:00,88.84200000000001 2014-04-21 06:04:00,88.962 2014-04-21 06:09:00,91.5 2014-04-21 06:14:00,89.626 2014-04-21 06:19:00,91.792 2014-04-21 06:24:00,93.376 2014-04-21 06:29:00,90.458 2014-04-21 06:34:00,90.322 2014-04-21 06:39:00,89.804 2014-04-21 06:44:00,87.374 2014-04-21 06:49:00,87.876 2014-04-21 06:54:00,89.712 2014-04-21 06:59:00,88.916 2014-04-21 07:04:00,87.958 2014-04-21 07:09:00,89.626 2014-04-21 07:14:00,91.376 2014-04-21 07:19:00,88.0 2014-04-21 07:24:00,88.588 2014-04-21 07:29:00,91.586 2014-04-21 07:34:00,89.708 2014-04-21 07:39:00,87.876 2014-04-21 07:44:00,87.25 2014-04-21 07:49:00,88.91 2014-04-21 07:54:00,86.86 2014-04-21 07:59:00,91.904 2014-04-21 08:04:00,88.62200000000001 2014-04-21 08:09:00,91.25 2014-04-21 08:14:00,92.27 2014-04-21 08:19:00,94.666 2014-04-21 08:24:00,91.124 2014-04-21 08:29:00,89.124 2014-04-21 08:34:00,88.542 2014-04-21 08:39:00,86.88799999999998 2014-04-21 08:44:00,86.584 2014-04-21 08:49:00,89.334 2014-04-21 08:54:00,90.05 2014-04-21 08:59:00,88.73 2014-04-21 09:04:00,87.334 2014-04-21 09:09:00,92.208 2014-04-21 09:14:00,94.416 2014-04-21 09:19:00,89.0 2014-04-21 09:24:00,88.126 2014-04-21 09:29:00,87.458 2014-04-21 09:34:00,87.11200000000002 2014-04-21 09:39:00,88.876 2014-04-21 09:44:00,87.25 2014-04-21 09:49:00,87.666 2014-04-21 09:54:00,88.686 2014-04-21 09:59:00,84.89200000000002 2014-04-21 10:04:00,89.634 2014-04-21 10:09:00,95.666 2014-04-21 10:14:00,93.25 2014-04-21 10:19:00,93.916 2014-04-21 10:24:00,94.55799999999999 2014-04-21 10:29:00,90.86 2014-04-21 10:34:00,94.568 2014-04-21 10:39:00,96.34 2014-04-21 10:44:00,93.584 2014-04-21 10:49:00,91.876 2014-04-21 10:54:00,93.584 2014-04-21 10:59:00,92.57600000000001 2014-04-21 11:04:00,92.022 2014-04-21 11:09:00,92.458 2014-04-21 11:14:00,91.428 2014-04-21 11:19:00,91.208 2014-04-21 11:24:00,91.334 2014-04-21 11:29:00,90.874 2014-04-21 11:34:00,94.12799999999999 2014-04-21 11:39:00,93.334 2014-04-21 11:44:00,93.792 2014-04-21 11:49:00,91.95200000000001 2014-04-21 11:54:00,94.208 2014-04-21 11:59:00,94.126 2014-04-21 12:04:00,92.916 2014-04-21 12:09:00,94.166 2014-04-21 12:14:00,93.292 2014-04-21 12:19:00,93.624 2014-04-21 12:24:00,93.75 2014-04-21 12:29:00,92.666 2014-04-21 12:34:00,91.75 2014-04-21 12:39:00,93.04799999999999 2014-04-21 12:44:00,93.374 2014-04-21 12:49:00,94.0 2014-04-21 12:54:00,94.542 2014-04-21 12:59:00,92.0 2014-04-21 13:04:00,94.0 2014-04-21 13:09:00,94.916 2014-04-21 13:14:00,92.9 2014-04-21 13:19:00,94.124 2014-04-21 13:24:00,92.60600000000001 2014-04-21 13:29:00,92.958 2014-04-21 13:34:00,94.042 2014-04-21 13:39:00,93.334 2014-04-21 13:44:00,92.124 2014-04-21 13:49:00,92.5 2014-04-21 13:54:00,94.25 2014-04-21 13:59:00,90.208 2014-04-21 14:04:00,92.448 2014-04-21 14:09:00,91.936 2014-04-21 14:14:00,92.124 2014-04-21 14:19:00,91.0 2014-04-21 14:24:00,90.834 2014-04-21 14:29:00,90.834 2014-04-21 14:34:00,91.5 2014-04-21 14:39:00,88.166 2014-04-21 14:44:00,91.876 2014-04-21 14:49:00,91.416 2014-04-21 14:54:00,92.708 2014-04-21 14:59:00,92.584 2014-04-21 15:04:00,92.916 2014-04-21 15:09:00,95.0 2014-04-21 15:14:00,93.584 2014-04-21 15:19:00,94.084 2014-04-21 15:24:00,92.458 2014-04-21 15:29:00,91.76 2014-04-21 15:34:00,92.5 2014-04-21 15:39:00,91.176 2014-04-21 15:44:00,93.334 2014-04-21 15:49:00,91.166 2014-04-21 15:54:00,92.75 2014-04-21 15:59:00,89.584 2014-04-21 16:04:00,91.0 2014-04-21 16:09:00,95.64200000000001 2014-04-21 16:14:00,90.416 2014-04-21 16:19:00,92.084 2014-04-21 16:24:00,93.084 2014-04-21 16:29:00,90.334 2014-04-21 16:34:00,88.056 2014-04-21 16:39:00,93.834 2014-04-21 16:44:00,92.376 2014-04-21 16:49:00,92.916 2014-04-21 16:54:00,91.10600000000001 2014-04-21 16:59:00,92.458 2014-04-21 17:04:00,92.958 2014-04-21 17:09:00,93.834 2014-04-21 17:14:00,93.084 2014-04-21 17:19:00,91.916 2014-04-21 17:24:00,92.208 2014-04-21 17:29:00,93.666 2014-04-21 17:34:00,93.416 2014-04-21 17:39:00,93.75 2014-04-21 17:44:00,93.32799999999999 2014-04-21 17:49:00,92.126 2014-04-21 17:54:00,93.584 2014-04-21 17:59:00,91.05 2014-04-21 18:04:00,92.166 2014-04-21 18:09:00,94.666 2014-04-21 18:14:00,92.416 2014-04-21 18:19:00,92.25 2014-04-21 18:24:00,88.666 2014-04-21 18:29:00,89.124 2014-04-21 18:34:00,90.584 2014-04-21 18:39:00,93.624 2014-04-21 18:44:00,91.25 2014-04-21 18:49:00,93.624 2014-04-21 18:54:00,95.57799999999999 2014-04-21 18:59:00,92.958 2014-04-21 19:04:00,92.792 2014-04-21 19:09:00,94.542 2014-04-21 19:14:00,91.584 2014-04-21 19:19:00,92.792 2014-04-21 19:24:00,94.124 2014-04-21 19:29:00,87.958 2014-04-21 19:34:00,92.0 2014-04-21 19:39:00,94.5 2014-04-21 19:44:00,93.334 2014-04-21 19:49:00,92.208 2014-04-21 19:54:00,92.22200000000001 2014-04-21 19:59:00,93.208 2014-04-21 20:04:00,94.958 2014-04-21 20:09:00,93.78 2014-04-21 20:14:00,92.916 2014-04-21 20:19:00,93.1 2014-04-21 20:24:00,94.584 2014-04-21 20:29:00,91.916 2014-04-21 20:34:00,93.0 2014-04-21 20:39:00,92.708 2014-04-21 20:44:00,91.4 2014-04-21 20:49:00,91.70200000000001 2014-04-21 20:54:00,93.0 2014-04-21 20:59:00,92.338 2014-04-21 21:04:00,91.876 2014-04-21 21:09:00,95.084 2014-04-21 21:14:00,93.916 2014-04-21 21:19:00,88.958 2014-04-21 21:24:00,90.3 2014-04-21 21:29:00,93.416 2014-04-21 21:34:00,91.126 2014-04-21 21:39:00,92.874 2014-04-21 21:44:00,92.28 2014-04-21 21:49:00,92.542 2014-04-21 21:54:00,93.416 2014-04-21 21:59:00,90.86200000000001 2014-04-21 22:04:00,82.75 2014-04-21 22:09:00,91.124 2014-04-21 22:14:00,90.25 2014-04-21 22:19:00,91.042 2014-04-21 22:24:00,90.046 2014-04-21 22:29:00,86.51 2014-04-21 22:34:00,86.484 2014-04-21 22:39:00,89.208 2014-04-21 22:44:00,89.084 2014-04-21 22:49:00,87.93 2014-04-21 22:54:00,86.666 2014-04-21 22:59:00,91.084 2014-04-21 23:04:00,90.448 2014-04-21 23:09:00,94.334 2014-04-21 23:14:00,89.708 2014-04-21 23:19:00,87.958 2014-04-21 23:24:00,92.458 2014-04-21 23:29:00,91.292 2014-04-21 23:34:00,90.334 2014-04-21 23:39:00,88.166 2014-04-21 23:44:00,89.41 2014-04-21 23:49:00,90.554 2014-04-21 23:54:00,89.83200000000002 2014-04-21 23:59:00,88.458 2014-04-22 00:04:00,87.374 2014-04-22 00:09:00,93.834 2014-04-22 00:14:00,91.124 2014-04-22 00:19:00,90.15799999999999 2014-04-22 00:24:00,89.17 2014-04-22 00:29:00,88.05 2014-04-22 00:34:00,87.81200000000004 2014-04-22 00:39:00,89.46 2014-04-22 00:44:00,87.602 2014-04-22 00:49:00,87.46 2014-04-22 00:54:00,88.916 2014-04-22 00:59:00,87.084 2014-04-22 01:04:00,88.152 2014-04-22 01:09:00,93.696 2014-04-22 01:14:00,85.08 2014-04-22 01:19:00,85.958 2014-04-22 01:24:00,88.624 2014-04-22 01:29:00,88.084 2014-04-22 01:34:00,87.208 2014-04-22 01:39:00,88.376 2014-04-22 01:44:00,90.292 2014-04-22 01:49:00,89.792 2014-04-22 01:54:00,91.896 2014-04-22 01:59:00,90.5 2014-04-22 02:04:00,87.292 2014-04-22 02:09:00,92.05 2014-04-22 02:14:00,90.662 2014-04-22 02:19:00,89.764 2014-04-22 02:24:00,89.0 2014-04-22 02:29:00,84.666 2014-04-22 02:34:00,88.5 2014-04-22 02:39:00,86.75 2014-04-22 02:44:00,86.458 2014-04-22 02:49:00,88.208 2014-04-22 02:54:00,86.25 2014-04-22 02:59:00,87.346 2014-04-22 03:04:00,87.584 2014-04-22 03:09:00,89.208 2014-04-22 03:14:00,84.376 2014-04-22 03:19:00,79.166 2014-04-22 03:24:00,88.416 2014-04-22 03:29:00,91.954 2014-04-22 03:34:00,94.75 2014-04-22 03:39:00,95.458 2014-04-22 03:44:00,93.958 2014-04-22 03:49:00,92.708 2014-04-22 03:54:00,94.37 2014-04-22 03:59:00,94.428 2014-04-22 04:04:00,96.166 2014-04-22 04:09:00,93.042 2014-04-22 04:14:00,89.042 2014-04-22 04:19:00,89.626 2014-04-22 04:24:00,89.542 2014-04-22 04:29:00,89.5 2014-04-22 04:34:00,83.166 2014-04-22 04:39:00,94.542 2014-04-22 04:44:00,95.208 2014-04-22 04:49:00,93.75 2014-04-22 04:54:00,92.542 2014-04-22 04:59:00,94.75 2014-04-22 05:04:00,95.0 2014-04-22 05:09:00,95.75 2014-04-22 05:14:00,92.238 2014-04-22 05:19:00,95.0 2014-04-22 05:24:00,96.586 2014-04-22 05:29:00,93.376 2014-04-22 05:34:00,94.416 2014-04-22 05:39:00,96.042 2014-04-22 05:44:00,90.916 2014-04-22 05:49:00,88.834 2014-04-22 05:54:00,88.084 2014-04-22 05:59:00,86.28399999999998 2014-04-22 06:04:00,89.916 2014-04-22 06:09:00,92.208 2014-04-22 06:14:00,92.0 2014-04-22 06:19:00,92.042 2014-04-22 06:24:00,88.682 2014-04-22 06:29:00,95.126 2014-04-22 06:34:00,92.458 2014-04-22 06:39:00,94.084 2014-04-22 06:44:00,94.75 2014-04-22 06:49:00,93.374 2014-04-22 06:54:00,95.958 2014-04-22 06:59:00,95.37799999999999 2014-04-22 07:04:00,94.624 2014-04-22 07:09:00,93.916 2014-04-22 07:14:00,95.72 2014-04-22 07:19:00,94.014 2014-04-22 07:24:00,95.458 2014-04-22 07:29:00,93.91 2014-04-22 07:34:00,95.53399999999999 2014-04-22 07:39:00,94.208 2014-04-22 07:44:00,92.64 2014-04-22 07:49:00,95.458 2014-04-22 07:54:00,91.458 2014-04-22 07:59:00,95.876 2014-04-22 08:04:00,94.542 2014-04-22 08:09:00,92.084 2014-04-22 08:14:00,93.69 2014-04-22 08:19:00,93.834 2014-04-22 08:24:00,94.5 2014-04-22 08:29:00,92.292 2014-04-22 08:34:00,95.916 2014-04-22 08:39:00,96.042 2014-04-22 08:44:00,95.584 2014-04-22 08:49:00,96.5 2014-04-22 08:54:00,94.708 2014-04-22 08:59:00,94.166 2014-04-22 09:04:00,88.376 2014-04-22 09:09:00,92.624 2014-04-22 09:14:00,93.0 2014-04-22 09:19:00,94.334 2014-04-22 09:24:00,91.584 2014-04-22 09:29:00,92.584 2014-04-22 09:34:00,93.242 2014-04-22 09:39:00,93.834 2014-04-22 09:44:00,93.666 2014-04-22 09:49:00,93.126 2014-04-22 09:54:00,94.708 2014-04-22 09:59:00,92.37 2014-04-22 10:04:00,91.542 2014-04-22 10:09:00,96.792 2014-04-22 10:14:00,91.794 2014-04-22 10:19:00,93.584 2014-04-22 10:24:00,94.61 2014-04-22 10:29:00,94.27799999999999 2014-04-22 10:34:00,91.25 2014-04-22 10:39:00,93.75 2014-04-22 10:44:00,92.916 2014-04-22 10:49:00,94.542 2014-04-22 10:54:00,90.626 2014-04-22 10:59:00,91.292 2014-04-22 11:04:00,94.958 2014-04-22 11:09:00,97.874 2014-04-22 11:14:00,95.914 2014-04-22 11:19:00,94.47200000000001 2014-04-22 11:24:00,96.124 2014-04-22 11:29:00,96.416 2014-04-22 11:34:00,95.88799999999999 2014-04-22 11:39:00,96.666 2014-04-22 11:44:00,96.292 2014-04-22 11:49:00,91.414 2014-04-22 11:54:00,91.486 2014-04-22 11:59:00,96.664 2014-04-22 12:04:00,95.0 2014-04-22 12:09:00,97.0 2014-04-22 12:14:00,96.624 2014-04-22 12:19:00,96.166 2014-04-22 12:24:00,95.286 2014-04-22 12:29:00,96.376 2014-04-22 12:34:00,93.666 2014-04-22 12:39:00,92.806 2014-04-22 12:44:00,95.36 2014-04-22 12:49:00,95.186 2014-04-22 12:54:00,95.25 2014-04-22 12:59:00,89.75 2014-04-22 13:04:00,95.96600000000001 2014-04-22 13:09:00,96.99 2014-04-22 13:14:00,97.084 2014-04-22 13:19:00,95.58200000000001 2014-04-22 13:24:00,95.792 2014-04-22 13:29:00,95.166 2014-04-22 13:34:00,94.334 2014-04-22 13:39:00,91.84200000000001 2014-04-22 13:44:00,96.166 2014-04-22 13:49:00,95.64 2014-04-22 13:54:00,95.956 2014-04-22 13:59:00,95.542 2014-04-22 14:04:00,92.458 2014-04-22 14:09:00,97.708 2014-04-22 14:14:00,94.416 2014-04-22 14:19:00,93.334 2014-04-22 14:24:00,91.792 2014-04-22 14:29:00,89.916 2014-04-22 14:34:00,88.916 2014-04-22 14:39:00,93.458 2014-04-22 14:44:00,92.11 2014-04-22 14:49:00,90.27799999999999 2014-04-22 14:54:00,92.5 2014-04-22 14:59:00,91.166 2014-04-22 15:04:00,92.052 2014-04-22 15:09:00,93.42 2014-04-22 15:14:00,89.084 2014-04-22 15:19:00,93.0 2014-04-22 15:24:00,91.666 2014-04-22 15:29:00,89.5 2014-04-22 15:34:00,89.546 2014-04-22 15:39:00,91.666 2014-04-22 15:44:00,93.27799999999999 2014-04-22 15:49:00,95.97200000000001 2014-04-22 15:54:00,93.946 2014-04-22 15:59:00,95.376 2014-04-22 16:04:00,92.62 2014-04-22 16:09:00,94.464 2014-04-22 16:14:00,95.566 2014-04-22 16:19:00,94.714 2014-04-22 16:24:00,95.626 2014-04-22 16:29:00,93.508 2014-04-22 16:34:00,92.56200000000001 2014-04-22 16:39:00,92.876 2014-04-22 16:44:00,94.15799999999999 2014-04-22 16:49:00,93.02 2014-04-22 16:54:00,92.292 2014-04-22 16:59:00,87.874 2014-04-22 17:04:00,90.166 2014-04-22 17:09:00,91.834 2014-04-22 17:14:00,89.126 2014-04-22 17:19:00,84.124 2014-04-22 17:24:00,85.958 2014-04-22 17:29:00,84.624 2014-04-22 17:34:00,89.792 2014-04-22 17:39:00,91.936 2014-04-22 17:44:00,88.834 2014-04-22 17:49:00,91.292 2014-04-22 17:54:00,91.876 2014-04-22 17:59:00,91.666 2014-04-22 18:04:00,92.666 2014-04-22 18:09:00,96.292 2014-04-22 18:14:00,88.458 2014-04-22 18:19:00,90.292 2014-04-22 18:24:00,92.042 2014-04-22 18:29:00,93.5 2014-04-22 18:34:00,92.042 2014-04-22 18:39:00,91.54 2014-04-22 18:44:00,91.822 2014-04-22 18:49:00,92.48 2014-04-22 18:54:00,92.57600000000001 2014-04-22 18:59:00,90.334 2014-04-22 19:04:00,89.874 2014-04-22 19:09:00,92.948 2014-04-22 19:14:00,92.274 2014-04-22 19:19:00,91.44200000000001 2014-04-22 19:24:00,92.25 2014-04-22 19:29:00,91.792 2014-04-22 19:34:00,90.616 2014-04-22 19:39:00,92.946 2014-04-22 19:44:00,89.166 2014-04-22 19:49:00,90.374 2014-04-22 19:54:00,93.126 2014-04-22 19:59:00,89.266 2014-04-22 20:04:00,90.542 2014-04-22 20:09:00,93.5 2014-04-22 20:14:00,92.166 2014-04-22 20:19:00,92.53 2014-04-22 20:24:00,91.198 2014-04-22 20:29:00,91.17 2014-04-22 20:34:00,91.834 2014-04-22 20:39:00,87.334 2014-04-22 20:44:00,91.584 2014-04-22 20:49:00,91.57 2014-04-22 20:54:00,89.458 2014-04-22 20:59:00,93.876 2014-04-22 21:04:00,90.0 2014-04-22 21:09:00,94.958 2014-04-22 21:14:00,90.08200000000001 2014-04-22 21:19:00,91.77799999999999 2014-04-22 21:24:00,91.84200000000001 2014-04-22 21:29:00,83.13 2014-04-22 21:34:00,88.5 2014-04-22 21:39:00,91.542 2014-04-22 21:44:00,91.292 2014-04-22 21:49:00,92.374 2014-04-22 21:54:00,91.208 2014-04-22 21:59:00,87.916 2014-04-22 22:04:00,91.708 2014-04-22 22:09:00,94.874 2014-04-22 22:14:00,89.834 2014-04-22 22:19:00,91.25 2014-04-22 22:24:00,92.25 2014-04-22 22:29:00,91.708 2014-04-22 22:34:00,90.416 2014-04-22 22:39:00,93.126 2014-04-22 22:44:00,90.166 2014-04-22 22:49:00,90.084 2014-04-22 22:54:00,92.876 2014-04-22 22:59:00,91.042 2014-04-22 23:04:00,92.316 2014-04-22 23:09:00,95.954 2014-04-22 23:14:00,93.126 2014-04-22 23:19:00,92.05 2014-04-22 23:24:00,90.876 2014-04-22 23:29:00,91.416 2014-04-22 23:34:00,90.79 2014-04-22 23:39:00,93.416 2014-04-22 23:44:00,91.00200000000001 2014-04-22 23:49:00,94.958 2014-04-22 23:54:00,93.208 2014-04-22 23:59:00,91.458 2014-04-23 00:04:00,93.37799999999999 2014-04-23 00:09:00,94.042 2014-04-23 00:14:00,91.416 2014-04-23 00:19:00,89.88799999999998 2014-04-23 00:24:00,91.084 2014-04-23 00:29:00,90.084 2014-04-23 00:34:00,88.876 2014-04-23 00:39:00,88.876 2014-04-23 00:44:00,92.374 2014-04-23 00:49:00,88.584 2014-04-23 00:54:00,89.666 2014-04-23 00:59:00,94.5 2014-04-23 01:04:00,92.042 2014-04-23 01:09:00,95.084 2014-04-23 01:14:00,93.458 2014-04-23 01:19:00,95.084 2014-04-23 01:24:00,93.166 2014-04-23 01:29:00,94.084 2014-04-23 01:34:00,92.792 2014-04-23 01:39:00,91.5 2014-04-23 01:44:00,95.042 2014-04-23 01:49:00,95.916 2014-04-23 01:54:00,93.042 2014-04-23 01:59:00,92.75 2014-04-23 02:04:00,92.62799999999999 2014-04-23 02:09:00,95.25 2014-04-23 02:14:00,95.12200000000001 2014-04-23 02:19:00,93.116 2014-04-23 02:24:00,89.072 2014-04-23 02:29:00,90.0 2014-04-23 02:34:00,93.25 2014-04-23 02:39:00,90.666 2014-04-23 02:44:00,91.334 2014-04-23 02:49:00,88.958 2014-04-23 02:54:00,89.75 2014-04-23 02:59:00,90.334 2014-04-23 03:04:00,91.624 2014-04-23 03:09:00,94.626 2014-04-23 03:14:00,89.458 2014-04-23 03:19:00,89.92 2014-04-23 03:24:00,90.546 2014-04-23 03:29:00,92.084 2014-04-23 03:34:00,90.416 2014-04-23 03:39:00,92.834 2014-04-23 03:44:00,88.25 2014-04-23 03:49:00,89.376 2014-04-23 03:54:00,92.042 2014-04-23 03:59:00,91.042 2014-04-23 04:04:00,93.344 2014-04-23 04:09:00,93.0 2014-04-23 04:14:00,90.666 2014-04-23 04:19:00,92.584 2014-04-23 04:24:00,90.5 2014-04-23 04:29:00,88.5 2014-04-23 04:34:00,92.794 2014-04-23 04:39:00,87.65799999999999 2014-04-23 04:44:00,85.99600000000002 2014-04-23 04:49:00,90.678 2014-04-23 04:54:00,90.166 2014-04-23 04:59:00,91.5 2014-04-23 05:04:00,89.00200000000002 2014-04-23 05:09:00,93.584 2014-04-23 05:14:00,89.0 2014-04-23 05:19:00,89.416 2014-04-23 05:24:00,88.334 2014-04-23 05:29:00,90.09200000000001 2014-04-23 05:34:00,92.0 2014-04-23 05:39:00,89.436 2014-04-23 05:44:00,87.084 2014-04-23 05:49:00,91.61 2014-04-23 05:54:00,90.068 2014-04-23 05:59:00,87.80799999999998 2014-04-23 06:04:00,90.75 2014-04-23 06:09:00,90.416 2014-04-23 06:14:00,89.042 2014-04-23 06:19:00,87.0 2014-04-23 06:24:00,89.584 2014-04-23 06:29:00,90.584 2014-04-23 06:34:00,90.458 2014-04-23 06:39:00,90.66799999999999 2014-04-23 06:44:00,88.042 2014-04-23 06:49:00,90.0 2014-04-23 06:54:00,88.084 2014-04-23 06:59:00,89.708 2014-04-23 07:04:00,89.792 2014-04-23 07:09:00,92.376 2014-04-23 07:14:00,89.584 2014-04-23 07:19:00,89.834 2014-04-23 07:24:00,86.71799999999998 2014-04-23 07:29:00,86.166 2014-04-23 07:34:00,85.446 2014-04-23 07:39:00,88.25 2014-04-23 07:44:00,87.344 2014-04-23 07:49:00,91.124 2014-04-23 07:54:00,90.334 2014-04-23 07:59:00,81.0 2014-04-23 08:04:00,82.0 2014-04-23 08:09:00,92.708 2014-04-23 08:14:00,93.042 2014-04-23 08:19:00,94.626 2014-04-23 08:24:00,93.084 2014-04-23 08:29:00,94.334 2014-04-23 08:34:00,92.584 2014-04-23 08:39:00,92.584 2014-04-23 08:44:00,93.916 2014-04-23 08:49:00,92.7 2014-04-23 08:54:00,94.0 2014-04-23 08:59:00,93.184 2014-04-23 09:04:00,93.514 2014-04-23 09:09:00,96.666 2014-04-23 09:14:00,92.5 2014-04-23 09:19:00,93.09200000000001 2014-04-23 09:24:00,94.55799999999999 2014-04-23 09:29:00,92.416 2014-04-23 09:34:00,93.874 2014-04-23 09:39:00,92.542 2014-04-23 09:44:00,94.208 2014-04-23 09:49:00,94.334 2014-04-23 09:54:00,92.084 2014-04-23 09:59:00,92.666 2014-04-23 10:04:00,93.876 2014-04-23 10:09:00,95.126 2014-04-23 10:14:00,94.666 2014-04-23 10:19:00,93.208 2014-04-23 10:24:00,91.802 2014-04-23 10:29:00,91.742 2014-04-23 10:34:00,93.9 2014-04-23 10:39:00,92.604 2014-04-23 10:44:00,93.126 2014-04-23 10:49:00,95.208 2014-04-23 10:54:00,93.084 2014-04-23 10:59:00,92.666 2014-04-23 11:04:00,93.236 2014-04-23 11:09:00,94.088 2014-04-23 11:14:00,93.666 2014-04-23 11:19:00,95.29 2014-04-23 11:24:00,93.102 2014-04-23 11:29:00,93.666 2014-04-23 11:34:00,95.208 2014-04-23 11:39:00,94.416 2014-04-23 11:44:00,95.166 2014-04-23 11:49:00,92.834 2014-04-23 11:54:00,94.792 2014-04-23 11:59:00,92.854 2014-04-23 12:04:00,95.03200000000001 2014-04-23 12:09:00,96.75 2014-04-23 12:14:00,95.68 2014-04-23 12:19:00,95.584 2014-04-23 12:24:00,95.0 2014-04-23 12:29:00,94.584 2014-04-23 12:34:00,93.042 2014-04-23 12:39:00,92.584 2014-04-23 12:44:00,95.208 2014-04-23 12:49:00,93.78 2014-04-23 12:54:00,96.512 2014-04-23 12:59:00,95.1 2014-04-23 13:04:00,94.626 2014-04-23 13:09:00,95.72200000000001 2014-04-23 13:14:00,95.334 2014-04-23 13:19:00,97.042 2014-04-23 13:24:00,95.876 2014-04-23 13:29:00,94.376 2014-04-23 13:34:00,92.126 2014-04-23 13:39:00,94.124 2014-04-23 13:44:00,94.618 2014-04-23 13:49:00,93.604 2014-04-23 13:54:00,94.61 2014-04-23 13:59:00,93.09 2014-04-23 14:04:00,92.292 2014-04-23 14:09:00,95.916 2014-04-23 14:14:00,93.0 2014-04-23 14:19:00,93.75 2014-04-23 14:24:00,95.124 2014-04-23 14:29:00,91.264 2014-04-23 14:34:00,93.75 2014-04-23 14:39:00,94.334 2014-04-23 14:44:00,93.75 2014-04-23 14:49:00,93.792 2014-04-23 14:54:00,94.626 2014-04-23 14:59:00,94.292 2014-04-23 15:04:00,94.75 2014-04-23 15:09:00,94.75 2014-04-23 15:14:00,94.876 2014-04-23 15:19:00,93.23200000000001 2014-04-23 15:24:00,94.58 2014-04-23 15:29:00,94.834 2014-04-23 15:34:00,94.31200000000001 2014-04-23 15:39:00,95.708 2014-04-23 15:44:00,95.08 2014-04-23 15:49:00,95.666 2014-04-23 15:54:00,95.084 2014-04-23 15:59:00,93.542 2014-04-23 16:04:00,97.038 2014-04-23 16:09:00,96.462 2014-04-23 16:14:00,93.68799999999999 2014-04-23 16:19:00,94.816 2014-04-23 16:24:00,95.834 2014-04-23 16:29:00,92.916 2014-04-23 16:34:00,94.584 2014-04-23 16:39:00,93.208 2014-04-23 16:44:00,94.042 2014-04-23 16:49:00,93.75 2014-04-23 16:54:00,96.584 2014-04-23 16:59:00,94.626 2014-04-23 17:04:00,95.916 2014-04-23 17:09:00,95.084 2014-04-23 17:14:00,94.916 2014-04-23 17:19:00,94.124 2014-04-23 17:24:00,93.792 2014-04-23 17:29:00,95.006 2014-04-23 17:34:00,94.458 2014-04-23 17:39:00,93.126 2014-04-23 17:44:00,95.25 2014-04-23 17:49:00,94.25 2014-04-23 17:54:00,94.624 2014-04-23 17:59:00,93.904 2014-04-23 18:04:00,94.18799999999999 2014-04-23 18:09:00,95.208 2014-04-23 18:14:00,93.666 2014-04-23 18:19:00,96.292 2014-04-23 18:24:00,96.012 2014-04-23 18:29:00,94.006 2014-04-23 18:34:00,94.63 2014-04-23 18:39:00,94.0 2014-04-23 18:44:00,94.792 2014-04-23 18:49:00,94.416 2014-04-23 18:54:00,93.166 2014-04-23 18:59:00,95.792 2014-04-23 19:04:00,94.536 2014-04-23 19:09:00,94.416 2014-04-23 19:14:00,94.208 2014-04-23 19:19:00,95.292 2014-04-23 19:24:00,93.542 2014-04-23 19:29:00,92.84200000000001 2014-04-23 19:34:00,93.584 2014-04-23 19:39:00,93.084 2014-04-23 19:44:00,93.792 2014-04-23 19:49:00,93.624 2014-04-23 19:54:00,92.17399999999999 2014-04-23 19:59:00,95.626 2014-04-23 20:04:00,92.834 2014-04-23 20:09:00,97.416 2014-04-23 20:14:00,94.32799999999999 2014-04-23 20:19:00,93.958 2014-04-23 20:24:00,94.814 2014-04-23 20:29:00,94.95 2014-04-23 20:34:00,92.404 2014-04-23 20:39:00,94.552 2014-04-23 20:44:00,94.19 2014-04-23 20:49:00,94.458 2014-04-23 20:54:00,93.126 2014-04-23 20:59:00,95.126 2014-04-23 21:04:00,93.208 2014-04-23 21:09:00,97.0 2014-04-23 21:14:00,95.166 2014-04-23 21:19:00,94.334 2014-04-23 21:24:00,95.5 2014-04-23 21:29:00,95.708 2014-04-23 21:34:00,94.376 2014-04-23 21:39:00,93.374 2014-04-23 21:44:00,94.376 2014-04-23 21:49:00,95.024 2014-04-23 21:54:00,96.33 2014-04-23 21:59:00,94.0 2014-04-23 22:04:00,93.61 2014-04-23 22:09:00,97.084 2014-04-23 22:14:00,95.24600000000001 2014-04-23 22:19:00,95.584 2014-04-23 22:24:00,94.75 2014-04-23 22:29:00,96.338 2014-04-23 22:34:00,95.626 2014-04-23 22:39:00,93.75 2014-04-23 22:44:00,95.876 2014-04-23 22:49:00,94.49 2014-04-23 22:54:00,95.182 2014-04-23 22:59:00,92.27600000000001 2014-04-23 23:04:00,93.07600000000001 2014-04-23 23:09:00,99.04 2014-04-23 23:14:00,93.666 2014-04-23 23:19:00,94.49799999999999 2014-04-23 23:24:00,93.682 2014-04-23 23:29:00,94.666 2014-04-23 23:34:00,96.334 2014-04-23 23:39:00,94.59200000000001 2014-04-23 23:44:00,92.666 2014-04-23 23:49:00,95.084 2014-04-23 23:54:00,95.236 2014-04-23 23:59:00,96.374 2014-04-24 00:04:00,95.042 2014-04-24 00:09:00,96.584 ================================================ FILE: workspace/anomaly_detector/datasets/selected/level_change/ec2_cpu_utilization_ac20cd.csv ================================================ timestamp,value 2014-04-02 14:29:00,42.652 2014-04-02 14:34:00,41.361999999999995 2014-04-02 14:39:00,43.408 2014-04-02 14:44:00,40.262 2014-04-02 14:49:00,40.328 2014-04-02 14:54:00,42.652 2014-04-02 14:59:00,39.836 2014-04-02 15:04:00,42.57 2014-04-02 15:09:00,45.211999999999996 2014-04-02 15:14:00,41.15 2014-04-02 15:19:00,42.91 2014-04-02 15:24:00,43.756 2014-04-02 15:29:00,38.522 2014-04-02 15:34:00,42.488 2014-04-02 15:39:00,41.268 2014-04-02 15:44:00,42.136 2014-04-02 15:49:00,42.066 2014-04-02 15:54:00,43.544 2014-04-02 15:59:00,38.404 2014-04-02 16:04:00,42.018 2014-04-02 16:09:00,44.872 2014-04-02 16:14:00,40.658 2014-04-02 16:19:00,42.276 2014-04-02 16:24:00,43.052 2014-04-02 16:29:00,43.56800000000001 2014-04-02 16:34:00,38.356 2014-04-02 16:39:00,39.788000000000004 2014-04-02 16:44:00,41.83 2014-04-02 16:49:00,39.038000000000004 2014-04-02 16:54:00,42.184 2014-04-02 16:59:00,41.76 2014-04-02 17:04:00,43.99 2014-04-02 17:09:00,41.476000000000006 2014-04-02 17:14:00,39.236 2014-04-02 17:19:00,41.798 2014-04-02 17:24:00,39.722 2014-04-02 17:29:00,40.61 2014-04-02 17:34:00,44.413999999999994 2014-04-02 17:39:00,38.404 2014-04-02 17:44:00,41.982 2014-04-02 17:49:00,42.066 2014-04-02 17:54:00,42.33600000000001 2014-04-02 17:59:00,41.01 2014-04-02 18:04:00,43.122 2014-04-02 18:09:00,39.954 2014-04-02 18:14:00,40.516 2014-04-02 18:19:00,45.396 2014-04-02 18:24:00,38.188 2014-04-02 18:29:00,42.536 2014-04-02 18:34:00,38.882 2014-04-02 18:39:00,40.766 2014-04-02 18:44:00,40.4 2014-04-02 18:49:00,41.808 2014-04-02 18:54:00,42.324 2014-04-02 18:59:00,44.152 2014-04-02 19:04:00,40.234 2014-04-02 19:09:00,40.891999999999996 2014-04-02 19:14:00,41.494 2014-04-02 19:19:00,40.61 2014-04-02 19:24:00,42.483999999999995 2014-04-02 19:29:00,38.774 2014-04-02 19:34:00,45.14 2014-04-02 19:39:00,40.122 2014-04-02 19:44:00,41.01 2014-04-02 19:49:00,43.708 2014-04-02 19:54:00,40.61 2014-04-02 19:59:00,43.49800000000001 2014-04-02 20:04:00,42.606 2014-04-02 20:09:00,46.361999999999995 2014-04-02 20:14:00,40.306 2014-04-02 20:19:00,46.478 2014-04-02 20:24:00,38.808 2014-04-02 20:29:00,41.878 2014-04-02 20:34:00,44.254 2014-04-02 20:39:00,41.57 2014-04-02 20:44:00,39.205999999999996 2014-04-02 20:49:00,40.482 2014-04-02 20:54:00,43.593999999999994 2014-04-02 20:59:00,41.808 2014-04-02 21:04:00,40.751999999999995 2014-04-02 21:09:00,46.31399999999999 2014-04-02 21:14:00,38.99 2014-04-02 21:19:00,41.666000000000004 2014-04-02 21:24:00,39.39 2014-04-02 21:29:00,40.812 2014-04-02 21:34:00,42.20399999999999 2014-04-02 21:39:00,44.95399999999999 2014-04-02 21:44:00,41.55 2014-04-02 21:49:00,42.09 2014-04-02 21:54:00,42.178000000000004 2014-04-02 21:59:00,43.24 2014-04-02 22:04:00,38.27 2014-04-02 22:09:00,42.206 2014-04-02 22:14:00,44.15600000000001 2014-04-02 22:19:00,41.332 2014-04-02 22:24:00,42.276 2014-04-02 22:29:00,41.15 2014-04-02 22:34:00,41.648 2014-04-02 22:39:00,41.298 2014-04-02 22:44:00,38.616 2014-04-02 22:49:00,41.15 2014-04-02 22:54:00,44.718 2014-04-02 22:59:00,41.924 2014-04-02 23:04:00,42.042 2014-04-02 23:09:00,42.536 2014-04-02 23:14:00,45.163999999999994 2014-04-02 23:19:00,39.141999999999996 2014-04-02 23:24:00,41.0 2014-04-02 23:29:00,40.576 2014-04-02 23:34:00,44.233999999999995 2014-04-02 23:39:00,42.816 2014-04-02 23:44:00,41.31399999999999 2014-04-02 23:49:00,40.156 2014-04-02 23:54:00,45.684 2014-04-02 23:59:00,39.508 2014-04-03 00:04:00,42.36 2014-04-03 00:09:00,46.882 2014-04-03 00:14:00,40.188 2014-04-03 00:19:00,40.576 2014-04-03 00:24:00,41.924 2014-04-03 00:29:00,40.68 2014-04-03 00:34:00,39.152 2014-04-03 00:39:00,45.0 2014-04-03 00:44:00,38.898 2014-04-03 00:49:00,41.69 2014-04-03 00:54:00,43.56800000000001 2014-04-03 00:59:00,42.23 2014-04-03 01:04:00,42.3 2014-04-03 01:09:00,44.328 2014-04-03 01:14:00,40.172 2014-04-03 01:19:00,41.292 2014-04-03 01:24:00,44.812 2014-04-03 01:29:00,43.17 2014-04-03 01:34:00,42.7 2014-04-03 01:39:00,45.716 2014-04-03 01:44:00,39.202 2014-04-03 01:49:00,41.571999999999996 2014-04-03 01:54:00,44.163999999999994 2014-04-03 01:59:00,40.798 2014-04-03 02:04:00,42.066 2014-04-03 02:09:00,43.708 2014-04-03 02:14:00,41.22 2014-04-03 02:19:00,41.394 2014-04-03 02:24:00,41.996 2014-04-03 02:29:00,40.102 2014-04-03 02:34:00,42.37 2014-04-03 02:39:00,38.858000000000004 2014-04-03 02:44:00,42.16 2014-04-03 02:49:00,41.422 2014-04-03 02:54:00,43.146 2014-04-03 02:59:00,40.54 2014-04-03 03:04:00,43.988 2014-04-03 03:09:00,41.12600000000001 2014-04-03 03:14:00,40.868 2014-04-03 03:19:00,46.478 2014-04-03 03:24:00,41.76 2014-04-03 03:29:00,43.538000000000004 2014-04-03 03:34:00,44.013999999999996 2014-04-03 03:39:00,44.40600000000001 2014-04-03 03:44:00,38.25 2014-04-03 03:49:00,41.022 2014-04-03 03:54:00,43.926 2014-04-03 03:59:00,39.578 2014-04-03 04:04:00,43.63800000000001 2014-04-03 04:09:00,44.578 2014-04-03 04:14:00,38.92 2014-04-03 04:19:00,40.538000000000004 2014-04-03 04:24:00,43.49800000000001 2014-04-03 04:29:00,39.468 2014-04-03 04:34:00,39.366 2014-04-03 04:39:00,42.49800000000001 2014-04-03 04:44:00,38.826 2014-04-03 04:49:00,41.181999999999995 2014-04-03 04:54:00,42.86600000000001 2014-04-03 04:59:00,40.931999999999995 2014-04-03 05:04:00,42.538000000000004 2014-04-03 05:09:00,47.37 2014-04-03 05:14:00,38.81 2014-04-03 05:19:00,45.114 2014-04-03 05:24:00,45.438 2014-04-03 05:29:00,42.864 2014-04-03 05:34:00,44.738 2014-04-03 05:39:00,46.43 2014-04-03 05:44:00,41.028 2014-04-03 05:49:00,40.361999999999995 2014-04-03 05:54:00,46.26600000000001 2014-04-03 05:59:00,39.342 2014-04-03 06:04:00,44.24800000000001 2014-04-03 06:09:00,42.63 2014-04-03 06:14:00,42.77 2014-04-03 06:19:00,43.943999999999996 2014-04-03 06:24:00,40.774 2014-04-03 06:29:00,43.728 2014-04-03 06:34:00,48.756 2014-04-03 06:39:00,41.29 2014-04-03 06:44:00,41.571999999999996 2014-04-03 06:49:00,42.262 2014-04-03 06:54:00,45.6 2014-04-03 06:59:00,41.15 2014-04-03 07:04:00,44.302 2014-04-03 07:09:00,41.972 2014-04-03 07:14:00,42.324 2014-04-03 07:19:00,43.028 2014-04-03 07:24:00,44.648 2014-04-03 07:29:00,43.403999999999996 2014-04-03 07:34:00,38.052 2014-04-03 07:39:00,41.338 2014-04-03 07:44:00,40.602 2014-04-03 07:49:00,40.61 2014-04-03 07:54:00,42.18 2014-04-03 07:59:00,40.446 2014-04-03 08:04:00,45.188 2014-04-03 08:09:00,44.132 2014-04-03 08:14:00,41.644 2014-04-03 08:19:00,39.24800000000001 2014-04-03 08:24:00,42.042 2014-04-03 08:29:00,40.364000000000004 2014-04-03 08:34:00,42.181999999999995 2014-04-03 08:39:00,38.79 2014-04-03 08:44:00,42.04 2014-04-03 08:49:00,43.38 2014-04-03 08:54:00,41.08 2014-04-03 08:59:00,40.68 2014-04-03 09:04:00,41.878 2014-04-03 09:09:00,46.488 2014-04-03 09:14:00,38.028 2014-04-03 09:19:00,40.916 2014-04-03 09:24:00,40.821999999999996 2014-04-03 09:29:00,41.864 2014-04-03 09:34:00,41.456 2014-04-03 09:39:00,44.803999999999995 2014-04-03 09:44:00,38.99 2014-04-03 09:49:00,40.57 2014-04-03 09:54:00,45.163999999999994 2014-04-03 09:59:00,38.316 2014-04-03 10:04:00,42.111999999999995 2014-04-03 10:09:00,42.488 2014-04-03 10:14:00,38.592 2014-04-03 10:19:00,40.492 2014-04-03 10:24:00,41.74800000000001 2014-04-03 10:29:00,43.286 2014-04-03 10:34:00,41.69 2014-04-03 10:39:00,45.702 2014-04-03 10:44:00,38.85 2014-04-03 10:49:00,38.592 2014-04-03 10:54:00,42.066 2014-04-03 10:59:00,43.093999999999994 2014-04-03 11:04:00,40.442 2014-04-03 11:09:00,45.282 2014-04-03 11:14:00,38.826 2014-04-03 11:19:00,41.948 2014-04-03 11:24:00,37.746 2014-04-03 11:29:00,40.282 2014-04-03 11:34:00,43.98 2014-04-03 11:39:00,43.176 2014-04-03 11:44:00,38.99800000000001 2014-04-03 11:49:00,43.146 2014-04-03 11:54:00,42.816 2014-04-03 11:59:00,40.47 2014-04-03 12:04:00,43.192 2014-04-03 12:09:00,41.666000000000004 2014-04-03 12:14:00,38.756 2014-04-03 12:19:00,40.22 2014-04-03 12:24:00,40.564 2014-04-03 12:29:00,41.62 2014-04-03 12:34:00,39.108000000000004 2014-04-03 12:39:00,42.018 2014-04-03 12:44:00,38.49800000000001 2014-04-03 12:49:00,43.04600000000001 2014-04-03 12:54:00,39.954 2014-04-03 12:59:00,43.226000000000006 2014-04-03 13:04:00,42.348 2014-04-03 13:09:00,41.456 2014-04-03 13:14:00,39.508 2014-04-03 13:19:00,41.032 2014-04-03 13:24:00,40.634 2014-04-03 13:29:00,41.994 2014-04-03 13:34:00,45.798 2014-04-03 13:39:00,39.624 2014-04-03 13:44:00,42.37600000000001 2014-04-03 13:49:00,40.634 2014-04-03 13:54:00,41.31399999999999 2014-04-03 13:59:00,40.634 2014-04-03 14:04:00,42.84 2014-04-03 14:09:00,40.306 2014-04-03 14:14:00,40.564 2014-04-03 14:19:00,40.704 2014-04-03 14:24:00,42.16 2014-04-03 14:29:00,39.264 2014-04-03 14:34:00,44.178000000000004 2014-04-03 14:39:00,38.494 2014-04-03 14:44:00,41.961999999999996 2014-04-03 14:49:00,40.586 2014-04-03 14:54:00,43.732 2014-04-03 14:59:00,39.32 2014-04-03 15:04:00,42.556000000000004 2014-04-03 15:09:00,40.821999999999996 2014-04-03 15:14:00,43.403999999999996 2014-04-03 15:19:00,43.333999999999996 2014-04-03 15:24:00,42.02 2014-04-03 15:29:00,39.414 2014-04-03 15:34:00,42.736000000000004 2014-04-03 15:39:00,42.19600000000001 2014-04-03 15:44:00,38.99 2014-04-03 15:49:00,40.821999999999996 2014-04-03 15:54:00,42.324 2014-04-03 15:59:00,40.592 2014-04-03 16:04:00,42.846000000000004 2014-04-03 16:09:00,46.784 2014-04-03 16:14:00,36.784 2014-04-03 16:19:00,40.936 2014-04-03 16:24:00,41.832 2014-04-03 16:29:00,43.672 2014-04-03 16:34:00,39.08 2014-04-03 16:39:00,41.582 2014-04-03 16:44:00,39.442 2014-04-03 16:49:00,42.018 2014-04-03 16:54:00,40.736 2014-04-03 16:59:00,42.394 2014-04-03 17:04:00,40.04 2014-04-03 17:09:00,44.373999999999995 2014-04-03 17:14:00,41.803999999999995 2014-04-03 17:19:00,39.236 2014-04-03 17:24:00,40.446 2014-04-03 17:29:00,42.442 2014-04-03 17:34:00,40.452 2014-04-03 17:39:00,45.418 2014-04-03 17:44:00,38.076 2014-04-03 17:49:00,40.798 2014-04-03 17:54:00,43.602 2014-04-03 17:59:00,39.574 2014-04-03 18:04:00,40.69 2014-04-03 18:09:00,43.968 2014-04-03 18:14:00,41.198 2014-04-03 18:19:00,43.15 2014-04-03 18:24:00,42.23 2014-04-03 18:29:00,44.56 2014-04-03 18:34:00,40.422 2014-04-03 18:39:00,41.01 2014-04-03 18:44:00,38.544000000000004 2014-04-03 18:49:00,40.438 2014-04-03 18:54:00,42.29 2014-04-03 18:59:00,40.576 2014-04-03 19:04:00,41.262 2014-04-03 19:09:00,44.15600000000001 2014-04-03 19:14:00,42.724 2014-04-03 19:19:00,36.73 2014-04-03 19:24:00,45.47 2014-04-03 19:29:00,38.56800000000001 2014-04-03 19:34:00,44.062 2014-04-03 19:39:00,41.552 2014-04-03 19:44:00,41.256 2014-04-03 19:49:00,43.544 2014-04-03 19:54:00,42.816 2014-04-03 19:59:00,42.91 2014-04-03 20:04:00,41.15 2014-04-03 20:09:00,40.846 2014-04-03 20:14:00,42.211999999999996 2014-04-03 20:19:00,41.808 2014-04-03 20:24:00,43.192 2014-04-03 20:29:00,41.738 2014-04-03 20:34:00,38.934 2014-04-03 20:39:00,40.816 2014-04-03 20:44:00,40.542 2014-04-03 20:49:00,43.48 2014-04-03 20:54:00,42.02 2014-04-03 20:59:00,43.33600000000001 2014-04-03 21:04:00,37.5 2014-04-03 21:09:00,42.456 2014-04-03 21:14:00,40.64 2014-04-03 21:19:00,42.418 2014-04-03 21:24:00,42.20399999999999 2014-04-03 21:29:00,42.35 2014-04-03 21:34:00,42.136 2014-04-03 21:39:00,40.14 2014-04-03 21:44:00,39.742 2014-04-03 21:49:00,40.63800000000001 2014-04-03 21:54:00,42.488 2014-04-03 21:59:00,39.28 2014-04-03 22:04:00,31.381999999999998 2014-04-03 22:09:00,34.85 2014-04-03 22:14:00,34.594 2014-04-03 22:19:00,38.286 2014-04-03 22:24:00,32.794000000000004 2014-04-03 22:29:00,31.408 2014-04-03 22:34:00,33.251999999999995 2014-04-03 22:39:00,33.364000000000004 2014-04-03 22:44:00,33.268 2014-04-03 22:49:00,34.226 2014-04-03 22:54:00,36.666 2014-04-03 22:59:00,36.566 2014-04-03 23:04:00,30.634 2014-04-03 23:09:00,35.728 2014-04-03 23:14:00,35.025999999999996 2014-04-03 23:19:00,36.292 2014-04-03 23:24:00,30.09800000000001 2014-04-03 23:29:00,33.346 2014-04-03 23:34:00,33.334 2014-04-03 23:39:00,33.874 2014-04-03 23:44:00,37.982 2014-04-03 23:49:00,28.616 2014-04-03 23:54:00,36.198 2014-04-03 23:59:00,32.296 2014-04-04 00:04:00,36.266 2014-04-04 00:09:00,34.742 2014-04-04 00:14:00,35.516 2014-04-04 00:19:00,31.41 2014-04-04 00:24:00,35.868 2014-04-04 00:29:00,32.888000000000005 2014-04-04 00:34:00,33.45 2014-04-04 00:39:00,33.122 2014-04-04 00:44:00,33.356 2014-04-04 00:49:00,35.0 2014-04-04 00:54:00,32.888000000000005 2014-04-04 00:59:00,33.258 2014-04-04 01:04:00,34.87 2014-04-04 01:09:00,37.536 2014-04-04 01:14:00,32.534 2014-04-04 01:19:00,33.216 2014-04-04 01:24:00,37.834 2014-04-04 01:29:00,25.25800000000001 2014-04-04 01:34:00,2.7 2014-04-04 01:39:00,2.6060000000000003 2014-04-04 01:44:00,2.77 2014-04-04 01:49:00,2.5980000000000003 2014-04-04 01:54:00,4.352 2014-04-04 01:59:00,2.77 2014-04-04 02:04:00,2.722 2014-04-04 02:09:00,4.132 2014-04-04 02:14:00,2.7 2014-04-04 02:19:00,2.676 2014-04-04 02:24:00,2.7939999999999996 2014-04-04 02:29:00,2.582 2014-04-04 02:34:00,2.676 2014-04-04 02:39:00,2.512 2014-04-04 02:44:00,2.7239999999999998 2014-04-04 02:49:00,2.676 2014-04-04 02:54:00,4.414 2014-04-04 02:59:00,2.84 2014-04-04 03:04:00,2.912 2014-04-04 03:09:00,6.22 2014-04-04 03:14:00,2.7239999999999998 2014-04-04 03:19:00,2.8160000000000003 2014-04-04 03:24:00,2.6060000000000003 2014-04-04 03:29:00,2.7239999999999998 2014-04-04 03:34:00,2.6060000000000003 2014-04-04 03:39:00,2.7 2014-04-04 03:44:00,2.7239999999999998 2014-04-04 03:49:00,2.596 2014-04-04 03:54:00,4.352 2014-04-04 03:59:00,2.77 2014-04-04 04:04:00,2.8160000000000003 2014-04-04 04:09:00,4.038 2014-04-04 04:14:00,2.7939999999999996 2014-04-04 04:19:00,2.7239999999999998 2014-04-04 04:24:00,2.722 2014-04-04 04:29:00,2.7680000000000002 2014-04-04 04:34:00,2.77 2014-04-04 04:39:00,2.6060000000000003 2014-04-04 04:44:00,2.668 2014-04-04 04:49:00,2.662 2014-04-04 04:54:00,4.4 2014-04-04 04:59:00,2.7560000000000002 2014-04-04 05:04:00,2.84 2014-04-04 05:09:00,4.342 2014-04-04 05:14:00,2.7460000000000004 2014-04-04 05:19:00,2.6060000000000003 2014-04-04 05:24:00,2.63 2014-04-04 05:29:00,2.8160000000000003 2014-04-04 05:34:00,2.6439999999999997 2014-04-04 05:39:00,2.734 2014-04-04 05:44:00,2.7 2014-04-04 05:49:00,2.7 2014-04-04 05:54:00,4.414 2014-04-04 05:59:00,2.6519999999999997 2014-04-04 06:04:00,2.888 2014-04-04 06:09:00,4.084 2014-04-04 06:14:00,2.7460000000000004 2014-04-04 06:19:00,2.6519999999999997 2014-04-04 06:24:00,2.63 2014-04-04 06:29:00,2.6519999999999997 2014-04-04 06:34:00,2.5580000000000003 2014-04-04 06:39:00,2.7 2014-04-04 06:44:00,2.7939999999999996 2014-04-04 06:49:00,2.464 2014-04-04 06:54:00,4.188 2014-04-04 06:59:00,2.71 2014-04-04 07:04:00,2.792 2014-04-04 07:09:00,4.388 2014-04-04 07:14:00,2.77 2014-04-04 07:19:00,2.852 2014-04-04 07:24:00,2.7 2014-04-04 07:29:00,2.888 2014-04-04 07:34:00,2.7460000000000004 2014-04-04 07:39:00,2.676 2014-04-04 07:44:00,2.84 2014-04-04 07:49:00,2.77 2014-04-04 07:54:00,4.46 2014-04-04 07:59:00,2.958 2014-04-04 08:04:00,2.9819999999999998 2014-04-04 08:09:00,4.32 2014-04-04 08:14:00,3.1260000000000003 2014-04-04 08:19:00,2.7239999999999998 2014-04-04 08:24:00,2.7939999999999996 2014-04-04 08:29:00,2.6060000000000003 2014-04-04 08:34:00,2.55 2014-04-04 08:39:00,2.568 2014-04-04 08:44:00,2.84 2014-04-04 08:49:00,2.6060000000000003 2014-04-04 08:54:00,4.32 2014-04-04 08:59:00,2.77 2014-04-04 09:04:00,2.9819999999999998 2014-04-04 09:09:00,4.39 2014-04-04 09:14:00,3.556 2014-04-04 09:19:00,3.3819999999999997 2014-04-04 09:24:00,3.486 2014-04-04 09:29:00,3.568 2014-04-04 09:34:00,3.38 2014-04-04 09:39:00,3.122 2014-04-04 09:44:00,3.3560000000000003 2014-04-04 09:49:00,3.5439999999999996 2014-04-04 09:54:00,5.234 2014-04-04 09:59:00,3.51 2014-04-04 10:04:00,3.512 2014-04-04 10:09:00,5.046 2014-04-04 10:14:00,3.6860000000000004 2014-04-04 10:19:00,3.522 2014-04-04 10:24:00,3.804 2014-04-04 10:29:00,3.802 2014-04-04 10:34:00,3.946 2014-04-04 10:39:00,3.78 2014-04-04 10:44:00,3.968 2014-04-04 10:49:00,3.742 2014-04-04 10:54:00,5.916 2014-04-04 10:59:00,3.6860000000000004 2014-04-04 11:04:00,3.568 2014-04-04 11:09:00,5.2120000000000015 2014-04-04 11:14:00,3.498 2014-04-04 11:19:00,3.262 2014-04-04 11:24:00,3.286 2014-04-04 11:29:00,3.85 2014-04-04 11:34:00,3.92 2014-04-04 11:39:00,3.592 2014-04-04 11:44:00,3.404 2014-04-04 11:49:00,3.1919999999999997 2014-04-04 11:54:00,5.093999999999999 2014-04-04 11:59:00,3.3339999999999996 2014-04-04 12:04:00,3.616 2014-04-04 12:09:00,5.376 2014-04-04 12:14:00,3.5439999999999996 2014-04-04 12:19:00,3.592 2014-04-04 12:24:00,3.24 2014-04-04 12:29:00,3.38 2014-04-04 12:34:00,2.7239999999999998 2014-04-04 12:39:00,2.7460000000000004 2014-04-04 12:44:00,2.676 2014-04-04 12:49:00,2.582 2014-04-04 12:54:00,4.954 2014-04-04 12:59:00,3.332 2014-04-04 13:04:00,3.428 2014-04-04 13:09:00,4.954 2014-04-04 13:14:00,3.38 2014-04-04 13:19:00,3.45 2014-04-04 13:24:00,3.1919999999999997 2014-04-04 13:29:00,3.3339999999999996 2014-04-04 13:34:00,3.122 2014-04-04 13:39:00,3.1460000000000004 2014-04-04 13:44:00,3.404 2014-04-04 13:49:00,2.9339999999999997 2014-04-04 13:54:00,5.188 2014-04-04 13:59:00,3.45 2014-04-04 14:04:00,2.7239999999999998 2014-04-04 14:09:00,4.32 2014-04-04 14:14:00,3.5439999999999996 2014-04-04 14:19:00,3.1919999999999997 2014-04-04 14:24:00,3.216 2014-04-04 14:29:00,3.522 2014-04-04 14:34:00,2.7 2014-04-04 14:39:00,3.498 2014-04-04 14:44:00,3.522 2014-04-04 14:49:00,3.216 2014-04-04 14:54:00,4.812 2014-04-04 14:59:00,2.7939999999999996 2014-04-04 15:04:00,2.958 2014-04-04 15:09:00,4.132 2014-04-04 15:14:00,2.7680000000000002 2014-04-04 15:19:00,2.63 2014-04-04 15:24:00,2.6060000000000003 2014-04-04 15:29:00,2.536 2014-04-04 15:34:00,2.6060000000000003 2014-04-04 15:39:00,2.6919999999999997 2014-04-04 15:44:00,2.568 2014-04-04 15:49:00,56.854 2014-04-04 15:54:00,38.874 2014-04-04 15:59:00,34.202 2014-04-04 16:04:00,35.961999999999996 2014-04-04 16:09:00,34.46 2014-04-04 16:14:00,32.726 2014-04-04 16:19:00,35.0 2014-04-04 16:24:00,31.08 2014-04-04 16:29:00,34.32 2014-04-04 16:34:00,34.084 2014-04-04 16:39:00,31.268 2014-04-04 16:44:00,33.18 2014-04-04 16:49:00,35.046 2014-04-04 16:54:00,32.91 2014-04-04 16:59:00,32.808 2014-04-04 17:04:00,34.366 2014-04-04 17:09:00,36.476 2014-04-04 17:14:00,34.084 2014-04-04 17:19:00,33.004 2014-04-04 17:24:00,35.211999999999996 2014-04-04 17:29:00,30.58 2014-04-04 17:34:00,33.498000000000005 2014-04-04 17:39:00,35.62 2014-04-04 17:44:00,32.84 2014-04-04 17:49:00,32.37 2014-04-04 17:54:00,35.192 2014-04-04 17:59:00,34.632 2014-04-04 18:04:00,35.938 2014-04-04 18:09:00,36.738 2014-04-04 18:14:00,34.062 2014-04-04 18:19:00,31.971999999999998 2014-04-04 18:24:00,32.018 2014-04-04 18:29:00,33.146 2014-04-04 18:34:00,35.821999999999996 2014-04-04 18:39:00,35.376 2014-04-04 18:44:00,31.644000000000002 2014-04-04 18:49:00,33.122 2014-04-04 18:54:00,35.262 2014-04-04 18:59:00,38.31 2014-04-04 19:04:00,31.15 2014-04-04 19:09:00,36.672 2014-04-04 19:14:00,31.524 2014-04-04 19:19:00,33.356 2014-04-04 19:24:00,33.474000000000004 2014-04-04 19:29:00,33.344 2014-04-04 19:34:00,36.032 2014-04-04 19:39:00,36.086 2014-04-04 19:44:00,34.59 2014-04-04 19:49:00,30.564 2014-04-04 19:54:00,36.244 2014-04-04 19:59:00,34.972 2014-04-04 20:04:00,33.192 2014-04-04 20:09:00,37.864000000000004 2014-04-04 20:14:00,30.218000000000004 2014-04-04 20:19:00,33.216 2014-04-04 20:24:00,33.098 2014-04-04 20:29:00,35.732 2014-04-04 20:34:00,32.442 2014-04-04 20:39:00,32.512 2014-04-04 20:44:00,32.016 2014-04-04 20:49:00,33.554 2014-04-04 20:54:00,35.4 2014-04-04 20:59:00,33.13 2014-04-04 21:04:00,33.38 2014-04-04 21:09:00,36.554 2014-04-04 21:14:00,35.211999999999996 2014-04-04 21:19:00,32.218 2014-04-04 21:24:00,34.596 2014-04-04 21:29:00,31.984 2014-04-04 21:34:00,33.722 2014-04-04 21:39:00,35.54 2014-04-04 21:44:00,31.448 2014-04-04 21:49:00,33.284 2014-04-04 21:54:00,34.882 2014-04-04 21:59:00,33.522 2014-04-04 22:04:00,33.198 2014-04-04 22:09:00,36.268 2014-04-04 22:14:00,36.431999999999995 2014-04-04 22:19:00,31.268 2014-04-04 22:24:00,33.052 2014-04-04 22:29:00,33.082 2014-04-04 22:34:00,32.91 2014-04-04 22:39:00,35.22 2014-04-04 22:44:00,32.65 2014-04-04 22:49:00,33.802 2014-04-04 22:54:00,32.746 2014-04-04 22:59:00,33.24 2014-04-04 23:04:00,33.262 2014-04-04 23:09:00,36.62 2014-04-04 23:14:00,34.01 2014-04-04 23:19:00,34.766 2014-04-04 23:24:00,34.976 2014-04-04 23:29:00,33.498000000000005 2014-04-04 23:34:00,35.774 2014-04-04 23:39:00,34.906 2014-04-04 23:44:00,30.986 2014-04-04 23:49:00,36.15 2014-04-04 23:54:00,35.42800000000001 2014-04-04 23:59:00,37.394 2014-04-05 00:04:00,35.046 2014-04-05 00:09:00,39.644 2014-04-05 00:14:00,31.738000000000003 2014-04-05 00:19:00,33.472 2014-04-05 00:24:00,33.356 2014-04-05 00:29:00,35.798 2014-04-05 00:34:00,30.564 2014-04-05 00:39:00,37.394 2014-04-05 00:44:00,34.014 2014-04-05 00:49:00,31.314 2014-04-05 00:54:00,34.882 2014-04-05 00:59:00,33.404 2014-04-05 01:04:00,35.306 2014-04-05 01:09:00,35.492 2014-04-05 01:14:00,36.361999999999995 2014-04-05 01:19:00,30.506 2014-04-05 01:24:00,33.216 2014-04-05 01:29:00,35.986 2014-04-05 01:34:00,36.784 2014-04-05 01:39:00,31.186 2014-04-05 01:44:00,33.952 2014-04-05 01:49:00,33.85 2014-04-05 01:54:00,35.61 2014-04-05 01:59:00,34.16 2014-04-05 02:04:00,38.896 2014-04-05 02:09:00,32.418 2014-04-05 02:14:00,35.211999999999996 2014-04-05 02:19:00,32.746 2014-04-05 02:24:00,32.16 2014-04-05 02:29:00,33.616 2014-04-05 02:34:00,33.474000000000004 2014-04-05 02:39:00,35.54400000000001 2014-04-05 02:44:00,31.62 2014-04-05 02:49:00,36.384 2014-04-05 02:54:00,34.484 2014-04-05 02:59:00,36.22 2014-04-05 03:04:00,33.428000000000004 2014-04-05 03:09:00,39.132 2014-04-05 03:14:00,31.526 2014-04-05 03:19:00,33.262 2014-04-05 03:24:00,33.45 2014-04-05 03:29:00,33.65 2014-04-05 03:34:00,39.554 2014-04-05 03:39:00,30.055999999999997 2014-04-05 03:44:00,35.938 2014-04-05 03:49:00,31.502 2014-04-05 03:54:00,35.525999999999996 2014-04-05 03:59:00,33.616 2014-04-05 04:04:00,33.826 2014-04-05 04:09:00,38.31 2014-04-05 04:14:00,38.278 2014-04-05 04:19:00,35.868 2014-04-05 04:24:00,31.268 2014-04-05 04:29:00,33.968 2014-04-05 04:34:00,33.68 2014-04-05 04:39:00,33.356 2014-04-05 04:44:00,35.066 2014-04-05 04:49:00,31.342 2014-04-05 04:54:00,36.268 2014-04-05 04:59:00,32.536 2014-04-05 05:04:00,33.028 2014-04-05 05:09:00,38.616 2014-04-05 05:14:00,32.404 2014-04-05 05:19:00,35.164 2014-04-05 05:24:00,31.408 2014-04-05 05:29:00,34.624 2014-04-05 05:34:00,32.3 2014-04-05 05:39:00,34.988 2014-04-05 05:44:00,35.284 2014-04-05 05:49:00,33.356 2014-04-05 05:54:00,36.878 2014-04-05 05:59:00,31.41 2014-04-05 06:04:00,36.596 2014-04-05 06:09:00,31.714000000000002 2014-04-05 06:14:00,33.234 2014-04-05 06:19:00,33.098 2014-04-05 06:24:00,36.644 2014-04-05 06:29:00,32.464 2014-04-05 06:34:00,33.24 2014-04-05 06:39:00,34.414 2014-04-05 06:44:00,32.348 2014-04-05 06:49:00,35.68 2014-04-05 06:54:00,35.44 2014-04-05 06:59:00,34.062 2014-04-05 07:04:00,33.216 2014-04-05 07:09:00,34.972 2014-04-05 07:14:00,34.672 2014-04-05 07:19:00,31.83 2014-04-05 07:24:00,35.17 2014-04-05 07:29:00,31.478 2014-04-05 07:34:00,36.21 2014-04-05 07:39:00,36.854 2014-04-05 07:44:00,31.15 2014-04-05 07:49:00,34.436 2014-04-05 07:54:00,33.874 2014-04-05 07:59:00,35.07 2014-04-05 08:04:00,34.006 2014-04-05 08:09:00,36.566 2014-04-05 08:14:00,34.882 2014-04-05 08:19:00,33.254 2014-04-05 08:24:00,38.896 2014-04-05 08:29:00,27.676 2014-04-05 08:34:00,33.344 2014-04-05 08:39:00,33.286 2014-04-05 08:44:00,33.424 2014-04-05 08:49:00,33.24 2014-04-05 08:54:00,36.948 2014-04-05 08:59:00,36.582 2014-04-05 09:04:00,33.604 2014-04-05 09:09:00,37.652 2014-04-05 09:14:00,31.031999999999996 2014-04-05 09:19:00,33.31 2014-04-05 09:24:00,35.188 2014-04-05 09:29:00,31.456 2014-04-05 09:34:00,34.906 2014-04-05 09:39:00,32.442 2014-04-05 09:44:00,33.732 2014-04-05 09:49:00,35.916 2014-04-05 09:54:00,39.578 2014-04-05 09:59:00,31.61 2014-04-05 10:04:00,33.312 2014-04-05 10:09:00,34.93 2014-04-05 10:14:00,35.891999999999996 2014-04-05 10:19:00,34.972 2014-04-05 10:24:00,37.864000000000004 2014-04-05 10:29:00,31.302 2014-04-05 10:34:00,33.482 2014-04-05 10:39:00,35.938 2014-04-05 10:44:00,30.634 2014-04-05 10:49:00,33.111999999999995 2014-04-05 10:54:00,36.461999999999996 2014-04-05 10:59:00,33.686 2014-04-05 11:04:00,31.338 2014-04-05 11:09:00,37.816 2014-04-05 11:14:00,33.358000000000004 2014-04-05 11:19:00,33.076 2014-04-05 11:24:00,34.226 2014-04-05 11:29:00,35.352 2014-04-05 11:34:00,30.421999999999997 2014-04-05 11:39:00,33.896 2014-04-05 11:44:00,33.616 2014-04-05 11:49:00,33.356 2014-04-05 11:54:00,34.976 2014-04-05 11:59:00,33.262 2014-04-05 12:04:00,35.238 2014-04-05 12:09:00,33.506 2014-04-05 12:14:00,36.08 2014-04-05 12:19:00,30.164 2014-04-05 12:24:00,35.961999999999996 2014-04-05 12:29:00,33.31 2014-04-05 12:34:00,35.14 2014-04-05 12:39:00,31.644000000000002 2014-04-05 12:44:00,33.592 2014-04-05 12:49:00,34.224000000000004 2014-04-05 12:54:00,33.732 2014-04-05 12:59:00,35.0 2014-04-05 13:04:00,33.912 2014-04-05 13:09:00,33.376 2014-04-05 13:14:00,33.404 2014-04-05 13:19:00,34.53 2014-04-05 13:24:00,37.148 2014-04-05 13:29:00,33.568000000000005 2014-04-05 13:34:00,35.564 2014-04-05 13:39:00,32.078 2014-04-05 13:44:00,35.14 2014-04-05 13:49:00,32.218 2014-04-05 13:54:00,35.164 2014-04-05 13:59:00,36.455999999999996 2014-04-05 14:04:00,30.25800000000001 2014-04-05 14:09:00,34.554 2014-04-05 14:14:00,33.251999999999995 2014-04-05 14:19:00,37.196 2014-04-05 14:24:00,33.146 2014-04-05 14:29:00,35.168 2014-04-05 14:34:00,34.068000000000005 2014-04-05 14:39:00,30.491999999999997 2014-04-05 14:44:00,33.474000000000004 2014-04-05 14:49:00,35.83 2014-04-05 14:54:00,36.41 2014-04-05 14:59:00,36.174 2014-04-05 15:04:00,38.028 2014-04-05 15:09:00,35.914 2014-04-05 15:14:00,32.205999999999996 2014-04-05 15:19:00,35.868 2014-04-05 15:24:00,30.68 2014-04-05 15:29:00,33.65 2014-04-05 15:34:00,35.59 2014-04-05 15:39:00,34.672 2014-04-05 15:44:00,35.094 2014-04-05 15:49:00,32.238 2014-04-05 15:54:00,35.124 2014-04-05 15:59:00,33.374 2014-04-05 16:04:00,36.83 2014-04-05 16:09:00,31.244 2014-04-05 16:14:00,36.192 2014-04-05 16:19:00,34.63 2014-04-05 16:24:00,31.971999999999998 2014-04-05 16:29:00,35.14 2014-04-05 16:34:00,31.78 2014-04-05 16:39:00,33.004 2014-04-05 16:44:00,33.522 2014-04-05 16:49:00,35.806 2014-04-05 16:54:00,33.814 2014-04-05 16:59:00,34.226 2014-04-05 17:04:00,31.502 2014-04-05 17:09:00,34.86 2014-04-05 17:14:00,34.93 2014-04-05 17:19:00,35.89 2014-04-05 17:24:00,33.464 2014-04-05 17:29:00,36.244 2014-04-05 17:34:00,30.464000000000002 2014-04-05 17:39:00,34.202 2014-04-05 17:44:00,33.78 2014-04-05 17:49:00,33.334 2014-04-05 17:54:00,35.046 2014-04-05 17:59:00,35.4 2014-04-05 18:04:00,33.076 2014-04-05 18:09:00,35.13 2014-04-05 18:14:00,34.896 2014-04-05 18:19:00,35.774 2014-04-05 18:24:00,33.826 2014-04-05 18:29:00,36.384 2014-04-05 18:34:00,32.794000000000004 2014-04-05 18:39:00,34.436 2014-04-05 18:44:00,31.974 2014-04-05 18:49:00,33.146 2014-04-05 18:54:00,36.056 2014-04-05 18:59:00,36.808 2014-04-05 19:04:00,33.99 2014-04-05 19:09:00,32.152 2014-04-05 19:14:00,34.742 2014-04-05 19:19:00,32.111999999999995 2014-04-05 19:24:00,33.292 2014-04-05 19:29:00,38.028 2014-04-05 19:34:00,33.146 2014-04-05 19:39:00,33.874 2014-04-05 19:44:00,34.132 2014-04-05 19:49:00,33.732 2014-04-05 19:54:00,35.844 2014-04-05 19:59:00,32.205999999999996 2014-04-05 20:04:00,35.306 2014-04-05 20:09:00,33.286 2014-04-05 20:14:00,33.286 2014-04-05 20:19:00,33.448 2014-04-05 20:24:00,33.286 2014-04-05 20:29:00,34.366 2014-04-05 20:34:00,35.306 2014-04-05 20:39:00,32.536 2014-04-05 20:44:00,33.568000000000005 2014-04-05 20:49:00,33.404 2014-04-05 20:54:00,35.0 2014-04-05 20:59:00,33.474000000000004 2014-04-05 21:04:00,36.338 2014-04-05 21:09:00,31.784000000000002 2014-04-05 21:14:00,33.64 2014-04-05 21:19:00,35.391999999999996 2014-04-05 21:24:00,31.198 2014-04-05 21:29:00,33.522 2014-04-05 21:34:00,33.498000000000005 2014-04-05 21:39:00,35.774 2014-04-05 21:44:00,33.262 2014-04-05 21:49:00,31.892 2014-04-05 21:54:00,35.234 2014-04-05 21:59:00,33.356 2014-04-05 22:04:00,33.568000000000005 2014-04-05 22:09:00,37.452 2014-04-05 22:14:00,33.498000000000005 2014-04-05 22:19:00,31.338 2014-04-05 22:24:00,37.176 2014-04-05 22:29:00,32.218 2014-04-05 22:34:00,33.334 2014-04-05 22:39:00,33.38 2014-04-05 22:44:00,35.54 2014-04-05 22:49:00,32.512 2014-04-05 22:54:00,36.972 2014-04-05 22:59:00,34.53 2014-04-05 23:04:00,32.388000000000005 2014-04-05 23:09:00,35.024 2014-04-05 23:14:00,35.42800000000001 2014-04-05 23:19:00,31.174 2014-04-05 23:24:00,34.812 2014-04-05 23:29:00,35.99800000000001 2014-04-05 23:34:00,33.878 2014-04-05 23:39:00,35.352 2014-04-05 23:44:00,34.554 2014-04-05 23:49:00,34.132 2014-04-05 23:54:00,32.63 2014-04-05 23:59:00,33.498000000000005 2014-04-06 00:04:00,33.45 2014-04-06 00:09:00,34.718 2014-04-06 00:14:00,35.282 2014-04-06 00:19:00,32.442 2014-04-06 00:24:00,32.348 2014-04-06 00:29:00,33.38 2014-04-06 00:34:00,35.891999999999996 2014-04-06 00:39:00,33.592 2014-04-06 00:44:00,35.306 2014-04-06 00:49:00,31.362 2014-04-06 00:54:00,36.361999999999995 2014-04-06 00:59:00,31.886 2014-04-06 01:04:00,34.635999999999996 2014-04-06 01:09:00,39.688 2014-04-06 01:14:00,32.244 2014-04-06 01:19:00,34.508 2014-04-06 01:24:00,34.016 2014-04-06 01:29:00,32.5 2014-04-06 01:34:00,34.108000000000004 2014-04-06 01:39:00,36.714 2014-04-06 01:44:00,32.3 2014-04-06 01:49:00,33.756 2014-04-06 01:54:00,35.564 2014-04-06 01:59:00,33.802 2014-04-06 02:04:00,36.86 2014-04-06 02:09:00,36.476 2014-04-06 02:14:00,31.572 2014-04-06 02:19:00,33.428000000000004 2014-04-06 02:24:00,33.461999999999996 2014-04-06 02:29:00,33.326 2014-04-06 02:34:00,33.146 2014-04-06 02:39:00,36.294000000000004 2014-04-06 02:44:00,29.976 2014-04-06 02:49:00,35.54 2014-04-06 02:54:00,34.444 2014-04-06 02:59:00,34.788000000000004 2014-04-06 03:04:00,34.718 2014-04-06 03:09:00,38.094 2014-04-06 03:14:00,32.84 2014-04-06 03:19:00,36.571999999999996 2014-04-06 03:24:00,32.288000000000004 2014-04-06 03:29:00,33.592 2014-04-06 03:34:00,35.646 2014-04-06 03:39:00,36.796 2014-04-06 03:44:00,33.31 2014-04-06 03:49:00,31.59 2014-04-06 03:54:00,36.596 2014-04-06 03:59:00,37.368 2014-04-06 04:04:00,33.821999999999996 2014-04-06 04:09:00,35.07 2014-04-06 04:14:00,35.422 2014-04-06 04:19:00,31.16 2014-04-06 04:24:00,33.288000000000004 2014-04-06 04:29:00,35.188 2014-04-06 04:34:00,32.488 2014-04-06 04:39:00,32.042 2014-04-06 04:44:00,35.352 2014-04-06 04:49:00,31.3 2014-04-06 04:54:00,34.976 2014-04-06 04:59:00,36.056 2014-04-06 05:04:00,33.638000000000005 2014-04-06 05:09:00,39.39 2014-04-06 05:14:00,31.866 2014-04-06 05:19:00,35.21 2014-04-06 05:24:00,31.612 2014-04-06 05:29:00,33.544000000000004 2014-04-06 05:34:00,33.628 2014-04-06 05:39:00,36.008 2014-04-06 05:44:00,33.076 2014-04-06 05:49:00,31.962 2014-04-06 05:54:00,36.361999999999995 2014-04-06 05:59:00,34.554 2014-04-06 06:04:00,33.522 2014-04-06 06:09:00,38.33 2014-04-06 06:14:00,36.08 2014-04-06 06:19:00,33.92 2014-04-06 06:24:00,31.996 2014-04-06 06:29:00,34.624 2014-04-06 06:34:00,34.272 2014-04-06 06:39:00,33.85 2014-04-06 06:44:00,35.894 2014-04-06 06:49:00,33.262 2014-04-06 06:54:00,39.062 2014-04-06 06:59:00,32.146 2014-04-06 07:04:00,31.91 2014-04-06 07:09:00,34.928000000000004 2014-04-06 07:14:00,37.63 2014-04-06 07:19:00,32.816 2014-04-06 07:24:00,33.544000000000004 2014-04-06 07:29:00,33.58 2014-04-06 07:34:00,35.53 2014-04-06 07:39:00,32.9 2014-04-06 07:44:00,36.69 2014-04-06 07:49:00,34.27 2014-04-06 07:54:00,36.15 2014-04-06 07:59:00,35.376 2014-04-06 08:04:00,33.99 2014-04-06 08:09:00,35.164 2014-04-06 08:14:00,35.118 2014-04-06 08:19:00,32.394 2014-04-06 08:24:00,35.47 2014-04-06 08:29:00,31.924 2014-04-06 08:34:00,36.338 2014-04-06 08:39:00,30.854 2014-04-06 08:44:00,35.25 2014-04-06 08:49:00,36.384 2014-04-06 08:54:00,35.891999999999996 2014-04-06 08:59:00,33.344 2014-04-06 09:04:00,35.958 2014-04-06 09:09:00,36.216 2014-04-06 09:14:00,34.048 2014-04-06 09:19:00,36.144 2014-04-06 09:24:00,32.652 2014-04-06 09:29:00,32.582 2014-04-06 09:34:00,33.944 2014-04-06 09:39:00,34.332 2014-04-06 09:44:00,35.542 2014-04-06 09:49:00,37.018 2014-04-06 09:54:00,33.474000000000004 2014-04-06 09:59:00,34.05 2014-04-06 10:04:00,37.676 2014-04-06 10:09:00,36.4 2014-04-06 10:14:00,33.896 2014-04-06 10:19:00,35.376 2014-04-06 10:24:00,31.264 2014-04-06 10:29:00,33.428000000000004 2014-04-06 10:34:00,33.19 2014-04-06 10:39:00,34.578 2014-04-06 10:44:00,34.854 2014-04-06 10:49:00,37.63 2014-04-06 10:54:00,30.445999999999998 2014-04-06 10:59:00,36.054 2014-04-06 11:04:00,34.672 2014-04-06 11:09:00,36.455999999999996 2014-04-06 11:14:00,34.73 2014-04-06 11:19:00,34.084 2014-04-06 11:24:00,31.471999999999998 2014-04-06 11:29:00,33.498000000000005 2014-04-06 11:34:00,36.314 2014-04-06 11:39:00,32.558 2014-04-06 11:44:00,35.188 2014-04-06 11:49:00,36.571999999999996 2014-04-06 11:54:00,31.971999999999998 2014-04-06 11:59:00,33.38 2014-04-06 12:04:00,33.638000000000005 2014-04-06 12:09:00,34.948 2014-04-06 12:14:00,33.262 2014-04-06 12:19:00,35.146 2014-04-06 12:24:00,35.258 2014-04-06 12:29:00,29.741999999999997 2014-04-06 12:34:00,33.498000000000005 2014-04-06 12:39:00,33.321999999999996 2014-04-06 12:44:00,36.384 2014-04-06 12:49:00,33.028 2014-04-06 12:54:00,37.042 2014-04-06 12:59:00,32.63 2014-04-06 13:04:00,32.09 2014-04-06 13:09:00,37.672 2014-04-06 13:14:00,30.938000000000002 2014-04-06 13:19:00,33.192 2014-04-06 13:24:00,33.286 2014-04-06 13:29:00,35.586 2014-04-06 13:34:00,35.634 2014-04-06 13:39:00,35.14 2014-04-06 13:44:00,33.756 2014-04-06 13:49:00,33.156 2014-04-06 13:54:00,35.118 2014-04-06 13:59:00,36.93 2014-04-06 14:04:00,30.0 2014-04-06 14:09:00,35.036 2014-04-06 14:14:00,34.718 2014-04-06 14:19:00,32.184 2014-04-06 14:24:00,35.821999999999996 2014-04-06 14:29:00,37.958 2014-04-06 14:34:00,31.464000000000002 2014-04-06 14:39:00,33.522 2014-04-06 14:44:00,33.39 2014-04-06 14:49:00,35.774 2014-04-06 14:54:00,33.718 2014-04-06 14:59:00,32.042 2014-04-06 15:04:00,35.306 2014-04-06 15:09:00,32.726 2014-04-06 15:14:00,33.544000000000004 2014-04-06 15:19:00,33.24 2014-04-06 15:24:00,35.961999999999996 2014-04-06 15:29:00,33.428000000000004 2014-04-06 15:34:00,36.571999999999996 2014-04-06 15:39:00,33.474000000000004 2014-04-06 15:44:00,31.031999999999996 2014-04-06 15:49:00,33.204 2014-04-06 15:54:00,36.314 2014-04-06 15:59:00,34.89 2014-04-06 16:04:00,35.62 2014-04-06 16:09:00,33.004 2014-04-06 16:14:00,34.694 2014-04-06 16:19:00,31.712 2014-04-06 16:24:00,33.122 2014-04-06 16:29:00,36.198 2014-04-06 16:34:00,32.436 2014-04-06 16:39:00,31.362 2014-04-06 16:44:00,33.428000000000004 2014-04-06 16:49:00,33.216 2014-04-06 16:54:00,36.15 2014-04-06 16:59:00,32.184 2014-04-06 17:04:00,33.58 2014-04-06 17:09:00,36.972 2014-04-06 17:14:00,31.596 2014-04-06 17:19:00,37.286 2014-04-06 17:24:00,31.901999999999997 2014-04-06 17:29:00,34.648 2014-04-06 17:34:00,32.418 2014-04-06 17:39:00,35.854 2014-04-06 17:44:00,31.854 2014-04-06 17:49:00,33.428000000000004 2014-04-06 17:54:00,35.146 2014-04-06 17:59:00,33.404 2014-04-06 18:04:00,34.906 2014-04-06 18:09:00,38.396 2014-04-06 18:14:00,28.92 2014-04-06 18:19:00,33.46 2014-04-06 18:24:00,33.686 2014-04-06 18:29:00,33.498000000000005 2014-04-06 18:34:00,35.75199999999999 2014-04-06 18:39:00,36.571999999999996 2014-04-06 18:44:00,30.206 2014-04-06 18:49:00,33.474000000000004 2014-04-06 18:54:00,37.632 2014-04-06 18:59:00,30.728 2014-04-06 19:04:00,33.568000000000005 2014-04-06 19:09:00,35.122 2014-04-06 19:14:00,35.211999999999996 2014-04-06 19:19:00,32.582 2014-04-06 19:24:00,32.184 2014-04-06 19:29:00,33.498000000000005 2014-04-06 19:34:00,36.501999999999995 2014-04-06 19:39:00,33.96 2014-04-06 19:44:00,36.244 2014-04-06 19:49:00,32.888000000000005 2014-04-06 19:54:00,32.536 2014-04-06 19:59:00,34.836 2014-04-06 20:04:00,32.076 2014-04-06 20:09:00,35.118 2014-04-06 20:14:00,34.806 2014-04-06 20:19:00,37.84 2014-04-06 20:24:00,31.388 2014-04-06 20:29:00,33.391999999999996 2014-04-06 20:34:00,34.86 2014-04-06 20:39:00,31.634 2014-04-06 20:44:00,33.708 2014-04-06 20:49:00,33.286 2014-04-06 20:54:00,36.784 2014-04-06 20:59:00,31.76 2014-04-06 21:04:00,33.568000000000005 2014-04-06 21:09:00,36.55 2014-04-06 21:14:00,32.3 2014-04-06 21:19:00,35.868 2014-04-06 21:24:00,32.7 2014-04-06 21:29:00,32.724000000000004 2014-04-06 21:34:00,35.058 2014-04-06 21:39:00,37.944 2014-04-06 21:44:00,32.558 2014-04-06 21:49:00,33.484 2014-04-06 21:54:00,37.16 2014-04-06 21:59:00,34.084 2014-04-06 22:04:00,31.01 2014-04-06 22:09:00,35.188 2014-04-06 22:14:00,33.65 2014-04-06 22:19:00,34.514 2014-04-06 22:24:00,33.896 2014-04-06 22:29:00,31.552 2014-04-06 22:34:00,33.404 2014-04-06 22:39:00,33.24 2014-04-06 22:44:00,35.896 2014-04-06 22:49:00,30.68 2014-04-06 22:54:00,36.275999999999996 2014-04-06 22:59:00,34.02 2014-04-06 23:04:00,31.604 2014-04-06 23:09:00,34.93 2014-04-06 23:14:00,33.474000000000004 2014-04-06 23:19:00,33.498000000000005 2014-04-06 23:24:00,33.24 2014-04-06 23:29:00,36.816 2014-04-06 23:34:00,33.356 2014-04-06 23:39:00,31.408 2014-04-06 23:44:00,33.708 2014-04-06 23:49:00,33.31 2014-04-06 23:54:00,34.958 2014-04-06 23:59:00,36.244 2014-04-07 00:04:00,35.282 2014-04-07 00:09:00,34.272 2014-04-07 00:14:00,32.275999999999996 2014-04-07 00:19:00,38.42 2014-04-07 00:24:00,30.658 2014-04-07 00:29:00,33.31 2014-04-07 00:34:00,34.954 2014-04-07 00:39:00,35.282 2014-04-07 00:44:00,32.676 2014-04-07 00:49:00,33.17 2014-04-07 00:54:00,34.87 2014-04-07 00:59:00,33.662 2014-04-07 01:04:00,37.794000000000004 2014-04-07 01:09:00,30.73 2014-04-07 01:14:00,33.662 2014-04-07 01:19:00,36.948 2014-04-07 01:24:00,32.205999999999996 2014-04-07 01:29:00,33.286 2014-04-07 01:34:00,35.492 2014-04-07 01:39:00,31.924 2014-04-07 01:44:00,33.78 2014-04-07 01:49:00,33.38 2014-04-07 01:54:00,35.274 2014-04-07 01:59:00,35.254 2014-04-07 02:04:00,33.896 2014-04-07 02:09:00,33.004 2014-04-07 02:14:00,33.256 2014-04-07 02:19:00,33.368 2014-04-07 02:24:00,36.052 2014-04-07 02:29:00,34.624 2014-04-07 02:34:00,33.71 2014-04-07 02:39:00,34.154 2014-04-07 02:44:00,30.892 2014-04-07 02:49:00,33.17 2014-04-07 02:54:00,35.078 2014-04-07 02:59:00,33.53 2014-04-07 03:04:00,36.996 2014-04-07 03:09:00,31.54 2014-04-07 03:14:00,33.544000000000004 2014-04-07 03:19:00,34.624 2014-04-07 03:24:00,36.472 2014-04-07 03:29:00,35.961999999999996 2014-04-07 03:34:00,32.762 2014-04-07 03:39:00,33.424 2014-04-07 03:44:00,32.512 2014-04-07 03:49:00,33.404 2014-04-07 03:54:00,35.118 2014-04-07 03:59:00,33.641999999999996 2014-04-07 04:04:00,35.61 2014-04-07 04:09:00,35.674 2014-04-07 04:14:00,33.726 2014-04-07 04:19:00,34.812 2014-04-07 04:24:00,34.955999999999996 2014-04-07 04:29:00,33.568000000000005 2014-04-07 04:34:00,35.046 2014-04-07 04:39:00,31.654 2014-04-07 04:44:00,33.848 2014-04-07 04:49:00,37.09 2014-04-07 04:54:00,30.938000000000002 2014-04-07 04:59:00,33.428000000000004 2014-04-07 05:04:00,35.306 2014-04-07 05:09:00,32.846 2014-04-07 05:14:00,33.732 2014-04-07 05:19:00,33.1 2014-04-07 05:24:00,35.824 2014-04-07 05:29:00,33.78 2014-04-07 05:34:00,39.356 2014-04-07 05:39:00,31.174 2014-04-07 05:44:00,34.312 2014-04-07 05:49:00,33.616 2014-04-07 05:54:00,36.01 2014-04-07 05:59:00,37.111999999999995 2014-04-07 06:04:00,30.68 2014-04-07 06:09:00,35.376 2014-04-07 06:14:00,36.442 2014-04-07 06:19:00,31.314 2014-04-07 06:24:00,35.868 2014-04-07 06:29:00,33.408 2014-04-07 06:34:00,33.742 2014-04-07 06:39:00,35.024 2014-04-07 06:44:00,34.038000000000004 2014-04-07 06:49:00,35.564 2014-04-07 06:54:00,33.498000000000005 2014-04-07 06:59:00,33.99 2014-04-07 07:04:00,35.868 2014-04-07 07:09:00,32.86 2014-04-07 07:14:00,35.746 2014-04-07 07:19:00,35.41 2014-04-07 07:24:00,35.024 2014-04-07 07:29:00,33.686 2014-04-07 07:34:00,33.99 2014-04-07 07:39:00,34.108000000000004 2014-04-07 07:44:00,35.188 2014-04-07 07:49:00,33.931999999999995 2014-04-07 07:54:00,35.891999999999996 2014-04-07 07:59:00,31.125999999999998 2014-04-07 08:04:00,35.622 2014-04-07 08:09:00,35.704 2014-04-07 08:14:00,33.492 2014-04-07 08:19:00,33.24 2014-04-07 08:24:00,36.494 2014-04-07 08:29:00,30.342 2014-04-07 08:34:00,33.262 2014-04-07 08:39:00,33.474000000000004 2014-04-07 08:44:00,36.338 2014-04-07 08:49:00,31.174 2014-04-07 08:54:00,38.78 2014-04-07 08:59:00,34.34 2014-04-07 09:04:00,36.501999999999995 2014-04-07 09:09:00,36.268 2014-04-07 09:14:00,34.788000000000004 2014-04-07 09:19:00,36.742 2014-04-07 09:24:00,32.646 2014-04-07 09:29:00,36.292 2014-04-07 09:34:00,34.508 2014-04-07 09:39:00,34.062 2014-04-07 09:44:00,35.282 2014-04-07 09:49:00,34.68 2014-04-07 09:54:00,39.104 2014-04-07 09:59:00,34.154 2014-04-07 10:04:00,36.292 2014-04-07 10:09:00,37.88800000000001 2014-04-07 10:14:00,33.796 2014-04-07 10:19:00,36.338 2014-04-07 10:24:00,34.32 2014-04-07 10:29:00,35.658 2014-04-07 10:34:00,34.694 2014-04-07 10:39:00,36.162 2014-04-07 10:44:00,34.508 2014-04-07 10:49:00,31.456 2014-04-07 10:54:00,35.3 2014-04-07 10:59:00,33.45 2014-04-07 11:04:00,33.28 2014-04-07 11:09:00,35.328 2014-04-07 11:14:00,37.275999999999996 2014-04-07 11:19:00,34.672 2014-04-07 11:24:00,31.76 2014-04-07 11:29:00,33.356 2014-04-07 11:34:00,33.686 2014-04-07 11:39:00,33.972 2014-04-07 11:44:00,33.874 2014-04-07 11:49:00,36.326 2014-04-07 11:54:00,32.324 2014-04-07 11:59:00,34.078 2014-04-07 12:04:00,33.428000000000004 2014-04-07 12:09:00,35.046 2014-04-07 12:14:00,33.358000000000004 2014-04-07 12:19:00,35.14 2014-04-07 12:24:00,33.708 2014-04-07 12:29:00,33.944 2014-04-07 12:34:00,33.92 2014-04-07 12:39:00,33.38 2014-04-07 12:44:00,37.652 2014-04-07 12:49:00,29.378 2014-04-07 12:54:00,35.33 2014-04-07 12:59:00,34.906 2014-04-07 13:04:00,32.356 2014-04-07 13:09:00,34.988 2014-04-07 13:14:00,35.328 2014-04-07 13:19:00,31.392 2014-04-07 13:24:00,34.455999999999996 2014-04-07 13:29:00,38.208 2014-04-07 13:34:00,35.61 2014-04-07 13:49:00,28.225 2014-04-07 13:54:00,35.78800000000001 2014-04-07 13:59:00,33.498000000000005 2014-04-07 14:04:00,34.32 2014-04-07 14:09:00,38.262 2014-04-07 14:14:00,33.004 2014-04-07 14:19:00,30.872 2014-04-07 14:24:00,34.014 2014-04-07 14:29:00,34.906 2014-04-07 14:34:00,35.164 2014-04-07 14:39:00,36.111999999999995 2014-04-07 14:44:00,32.958 2014-04-07 14:49:00,32.3 2014-04-07 14:54:00,35.422 2014-04-07 14:59:00,33.732 2014-04-07 15:04:00,33.494 2014-04-07 15:09:00,39.814 2014-04-07 15:14:00,30.118000000000002 2014-04-07 15:19:00,34.296 2014-04-07 15:24:00,34.414 2014-04-07 15:29:00,35.47400000000001 2014-04-07 15:34:00,35.14 2014-04-07 15:39:00,37.324 2014-04-07 15:44:00,32.934 2014-04-07 15:49:00,34.586 2014-04-07 15:54:00,36.578 2014-04-07 15:59:00,37.632 2014-04-07 16:04:00,31.59800000000001 2014-04-07 16:09:00,38.63800000000001 2014-04-07 16:14:00,34.014 2014-04-07 16:19:00,34.062 2014-04-07 16:24:00,33.896 2014-04-07 16:29:00,35.774 2014-04-07 16:34:00,32.51 2014-04-07 16:39:00,38.756 2014-04-07 16:44:00,29.43 2014-04-07 16:49:00,33.978 2014-04-07 16:54:00,35.796 2014-04-07 16:59:00,35.282 2014-04-07 17:04:00,34.6 2014-04-07 17:09:00,32.922 2014-04-07 17:14:00,33.616 2014-04-07 17:19:00,33.38 2014-04-07 17:24:00,34.32 2014-04-07 17:29:00,32.63 2014-04-07 17:34:00,37.501999999999995 2014-04-07 17:39:00,31.15 2014-04-07 17:44:00,33.826 2014-04-07 17:49:00,33.568000000000005 2014-04-07 17:54:00,35.054 2014-04-07 17:59:00,32.228 2014-04-07 18:04:00,34.9 2014-04-07 18:09:00,33.662 2014-04-07 18:14:00,33.24 2014-04-07 18:19:00,30.605999999999998 2014-04-07 18:24:00,32.135999999999996 2014-04-07 18:29:00,32.254 2014-04-07 18:34:00,34.202 2014-04-07 18:39:00,30.278000000000002 2014-04-07 18:44:00,32.558 2014-04-07 18:49:00,32.184 2014-04-07 18:54:00,34.32 2014-04-07 18:59:00,38.324 2014-04-07 19:04:00,29.624000000000002 2014-04-07 19:09:00,34.038000000000004 2014-04-07 19:14:00,34.251999999999995 2014-04-07 19:19:00,30.406 2014-04-07 19:24:00,32.066 2014-04-07 19:29:00,31.971999999999998 2014-04-07 19:34:00,32.778 2014-04-07 19:39:00,36.01 2014-04-07 19:44:00,29.248 2014-04-07 19:49:00,33.896 2014-04-07 19:54:00,32.37 2014-04-07 19:59:00,32.16 2014-04-07 20:04:00,32.7 2014-04-07 20:09:00,36.738 2014-04-07 20:14:00,33.356 2014-04-07 20:19:00,32.17 2014-04-07 20:24:00,33.008 2014-04-07 20:29:00,34.144 2014-04-07 20:34:00,34.21 2014-04-07 20:39:00,28.261999999999997 2014-04-07 20:44:00,32.234 2014-04-07 20:49:00,32.418 2014-04-07 20:54:00,33.944 2014-04-07 20:59:00,34.118 2014-04-07 21:04:00,30.756 2014-04-07 21:09:00,35.024 2014-04-07 21:14:00,30.846 2014-04-07 21:19:00,34.578 2014-04-07 21:24:00,29.414 2014-04-07 21:29:00,33.99 2014-04-07 21:34:00,30.336 2014-04-07 21:39:00,32.676 2014-04-07 21:44:00,33.708 2014-04-07 21:49:00,31.01 2014-04-07 21:54:00,33.826 2014-04-07 21:59:00,34.436 2014-04-07 22:04:00,32.512 2014-04-07 22:09:00,32.135999999999996 2014-04-07 22:14:00,34.812 2014-04-07 22:19:00,33.544000000000004 2014-04-07 22:24:00,36.22 2014-04-07 22:29:00,32.848 2014-04-07 22:34:00,33.146 2014-04-07 22:39:00,32.275999999999996 2014-04-07 22:44:00,32.205999999999996 2014-04-07 22:49:00,32.536 2014-04-07 22:54:00,34.508 2014-04-07 22:59:00,36.361999999999995 2014-04-07 23:04:00,29.201999999999998 2014-04-07 23:09:00,34.578 2014-04-07 23:14:00,34.93 2014-04-07 23:19:00,33.662 2014-04-07 23:24:00,33.592 2014-04-07 23:29:00,34.226 2014-04-07 23:34:00,30.81 2014-04-07 23:39:00,36.99800000000001 2014-04-07 23:44:00,28.464000000000002 2014-04-07 23:49:00,33.082 2014-04-07 23:54:00,36.104 2014-04-07 23:59:00,31.314 2014-04-08 00:04:00,32.906 2014-04-08 00:09:00,33.99 2014-04-08 00:14:00,35.492 2014-04-08 00:19:00,33.968 2014-04-08 00:24:00,34.326 2014-04-08 00:29:00,29.32800000000001 2014-04-08 00:34:00,32.676 2014-04-08 00:39:00,32.816 2014-04-08 00:44:00,32.982 2014-04-08 00:49:00,32.77 2014-04-08 00:54:00,36.198 2014-04-08 00:59:00,31.901999999999997 2014-04-08 01:04:00,31.15 2014-04-08 01:09:00,34.525999999999996 2014-04-08 01:14:00,36.314 2014-04-08 01:19:00,34.578 2014-04-08 01:24:00,34.226 2014-04-08 01:29:00,33.384 2014-04-08 01:34:00,32.838 2014-04-08 01:39:00,33.896 2014-04-08 01:44:00,31.596 2014-04-08 01:49:00,32.512 2014-04-08 01:54:00,38.514 2014-04-08 01:59:00,33.036 2014-04-08 02:04:00,30.491999999999997 2014-04-08 02:09:00,37.77 2014-04-08 02:14:00,31.15 2014-04-08 02:19:00,32.275999999999996 2014-04-08 02:24:00,34.132 2014-04-08 02:29:00,33.028 2014-04-08 02:34:00,32.23 2014-04-08 02:39:00,32.272 2014-04-08 02:44:00,35.75199999999999 2014-04-08 02:49:00,28.57800000000001 2014-04-08 02:54:00,36.08 2014-04-08 02:59:00,30.564 2014-04-08 03:04:00,32.275999999999996 2014-04-08 03:09:00,33.568000000000005 2014-04-08 03:14:00,32.122 2014-04-08 03:19:00,33.24 2014-04-08 03:24:00,32.348 2014-04-08 03:29:00,37.864000000000004 2014-04-08 03:34:00,28.215999999999998 2014-04-08 03:39:00,32.482 2014-04-08 03:44:00,32.808 2014-04-08 03:49:00,31.968000000000004 2014-04-08 03:54:00,33.874 2014-04-08 03:59:00,34.648 2014-04-08 04:04:00,33.616 2014-04-08 04:09:00,32.966 2014-04-08 04:14:00,33.758 2014-04-08 04:19:00,34.108000000000004 2014-04-08 04:24:00,32.111999999999995 2014-04-08 04:29:00,34.554 2014-04-08 04:34:00,30.42 2014-04-08 04:39:00,32.3 2014-04-08 04:44:00,33.896 2014-04-08 04:49:00,31.174 2014-04-08 04:54:00,36.178000000000004 2014-04-08 04:59:00,33.146 2014-04-08 05:04:00,34.954 2014-04-08 05:09:00,31.198 2014-04-08 05:14:00,32.244 2014-04-08 05:19:00,36.762 2014-04-08 05:24:00,33.146 2014-04-08 05:29:00,30.491999999999997 2014-04-08 05:34:00,32.888000000000005 2014-04-08 05:39:00,32.888000000000005 2014-04-08 05:44:00,32.84 2014-04-08 05:49:00,35.094 2014-04-08 05:54:00,33.45 2014-04-08 05:59:00,31.714000000000002 2014-04-08 06:04:00,31.494 2014-04-08 06:09:00,33.92 2014-04-08 06:14:00,32.324 2014-04-08 06:19:00,33.906 2014-04-08 06:24:00,31.691999999999997 2014-04-08 06:29:00,33.955999999999996 2014-04-08 06:34:00,35.054 2014-04-08 06:39:00,30.866 2014-04-08 06:44:00,31.362 2014-04-08 06:49:00,33.99 2014-04-08 06:54:00,31.83 2014-04-08 06:59:00,32.348 2014-04-08 07:04:00,32.394 2014-04-08 07:09:00,33.896 2014-04-08 07:14:00,33.662 2014-04-08 07:19:00,35.422 2014-04-08 07:24:00,27.712 2014-04-08 07:29:00,32.52 2014-04-08 07:34:00,33.926 2014-04-08 07:39:00,34.32 2014-04-08 07:44:00,34.46 2014-04-08 07:49:00,31.362 2014-04-08 07:54:00,32.396 2014-04-08 07:59:00,32.51 2014-04-08 08:04:00,32.558 2014-04-08 08:09:00,33.592 2014-04-08 08:14:00,34.318000000000005 2014-04-08 08:19:00,30.281999999999996 2014-04-08 08:24:00,32.09 2014-04-08 08:29:00,33.16 2014-04-08 08:34:00,31.154 2014-04-08 08:39:00,34.038000000000004 2014-04-08 08:44:00,30.25800000000001 2014-04-08 08:49:00,31.984 2014-04-08 08:54:00,36.704 2014-04-08 08:59:00,30.752 2014-04-08 09:04:00,31.031999999999996 2014-04-08 09:09:00,37.018 2014-04-08 09:14:00,33.99 2014-04-08 09:19:00,34.39 2014-04-08 09:24:00,34.436 2014-04-08 09:29:00,34.628 2014-04-08 09:34:00,38.076 2014-04-08 09:39:00,32.476 2014-04-08 09:44:00,34.52 2014-04-08 09:49:00,34.672 2014-04-08 09:54:00,36.784 2014-04-08 09:59:00,34.272 2014-04-08 10:04:00,36.455999999999996 2014-04-08 10:09:00,38.304 2014-04-08 10:14:00,32.418 2014-04-08 10:19:00,33.638000000000005 2014-04-08 10:24:00,34.138000000000005 2014-04-08 10:29:00,33.662 2014-04-08 10:34:00,39.296 2014-04-08 10:39:00,32.394 2014-04-08 10:44:00,36.052 2014-04-08 10:49:00,33.38 2014-04-08 10:54:00,35.774 2014-04-08 10:59:00,36.59 2014-04-08 11:04:00,32.512 2014-04-08 11:09:00,37.004 2014-04-08 11:14:00,34.302 2014-04-08 11:19:00,34.954 2014-04-08 11:24:00,35.024 2014-04-08 11:29:00,33.732 2014-04-08 11:34:00,34.53 2014-04-08 11:39:00,30.962 2014-04-08 11:44:00,33.85 2014-04-08 11:49:00,31.104 2014-04-08 11:54:00,36.431999999999995 2014-04-08 11:59:00,29.904 2014-04-08 12:04:00,34.666 2014-04-08 12:09:00,32.032 2014-04-08 12:14:00,32.418 2014-04-08 12:19:00,35.908 2014-04-08 12:24:00,31.00800000000001 2014-04-08 12:29:00,32.394 2014-04-08 12:34:00,34.014 2014-04-08 12:39:00,32.746 2014-04-08 12:44:00,29.75800000000001 2014-04-08 12:49:00,32.036 2014-04-08 12:54:00,33.944 2014-04-08 12:59:00,33.24 2014-04-08 13:04:00,33.004 2014-04-08 13:09:00,31.644000000000002 2014-04-08 13:14:00,32.524 2014-04-08 13:19:00,32.122 2014-04-08 13:24:00,33.638000000000005 2014-04-08 13:29:00,38.544000000000004 2014-04-08 13:34:00,29.484 2014-04-08 13:39:00,32.724000000000004 2014-04-08 13:44:00,34.266 2014-04-08 13:49:00,32.102 2014-04-08 13:54:00,34.154 2014-04-08 13:59:00,32.418 2014-04-08 14:04:00,34.788000000000004 2014-04-08 14:09:00,33.334 2014-04-08 14:14:00,31.291999999999998 2014-04-08 14:19:00,36.864000000000004 2014-04-08 14:24:00,33.16 2014-04-08 14:29:00,32.248000000000005 2014-04-08 14:34:00,34.178000000000004 2014-04-08 14:39:00,32.794000000000004 2014-04-08 14:44:00,33.732 2014-04-08 14:49:00,31.234 2014-04-08 14:54:00,34.374 2014-04-08 14:59:00,32.318000000000005 2014-04-08 15:04:00,34.39 2014-04-08 15:09:00,37.3 2014-04-08 15:14:00,29.691999999999997 2014-04-08 15:19:00,32.135999999999996 2014-04-08 15:24:00,36.032 2014-04-08 15:29:00,30.892 2014-04-08 15:34:00,34.508 2014-04-08 15:39:00,30.798000000000002 2014-04-08 15:44:00,32.606 2014-04-08 15:49:00,32.37 2014-04-08 15:54:00,36.972 2014-04-08 15:59:00,32.135999999999996 2014-04-08 16:04:00,36.431999999999995 2014-04-08 16:09:00,34.554 2014-04-08 16:14:00,31.572 2014-04-08 16:19:00,33.85 2014-04-08 16:24:00,32.042 2014-04-08 16:29:00,31.878 2014-04-08 16:34:00,32.205999999999996 2014-04-08 16:39:00,34.812 2014-04-08 16:44:00,34.53 2014-04-08 16:49:00,33.248000000000005 2014-04-08 16:54:00,32.275999999999996 2014-04-08 16:59:00,32.348 2014-04-08 17:04:00,32.342 2014-04-08 17:09:00,33.896 2014-04-08 17:14:00,32.63 2014-04-08 17:19:00,32.418 2014-04-08 17:24:00,36.738 2014-04-08 17:29:00,34.474000000000004 2014-04-08 17:34:00,31.72 2014-04-08 17:39:00,32.958 2014-04-08 17:44:00,32.652 2014-04-08 17:49:00,32.3 2014-04-08 17:54:00,35.898 2014-04-08 17:59:00,32.21 2014-04-08 18:04:00,32.562 2014-04-08 18:09:00,35.455999999999996 2014-04-08 18:14:00,33.99 2014-04-08 18:19:00,39.484 2014-04-08 18:24:00,28.592 2014-04-08 18:29:00,36.292 2014-04-08 18:34:00,35.496 2014-04-08 18:39:00,31.031999999999996 2014-04-08 18:44:00,34.598 2014-04-08 18:49:00,30.305999999999997 2014-04-08 18:54:00,33.83 2014-04-08 18:59:00,34.754 2014-04-08 19:04:00,29.851999999999997 2014-04-08 19:09:00,37.018 2014-04-08 19:14:00,28.99 2014-04-08 19:19:00,32.032 2014-04-08 19:24:00,32.692 2014-04-08 19:29:00,32.23 2014-04-08 19:34:00,32.824 2014-04-08 19:39:00,37.95 2014-04-08 19:44:00,29.178 2014-04-08 19:49:00,31.104 2014-04-08 19:54:00,33.708 2014-04-08 19:59:00,32.23 2014-04-08 20:04:00,34.798 2014-04-08 20:09:00,32.382 2014-04-08 20:14:00,33.912 2014-04-08 20:19:00,33.714 2014-04-08 20:24:00,29.53 2014-04-08 20:29:00,32.278 2014-04-08 20:34:00,34.63 2014-04-08 20:39:00,30.046 2014-04-08 20:44:00,33.568000000000005 2014-04-08 20:49:00,32.066 2014-04-08 20:54:00,35.728 2014-04-08 20:59:00,32.536 2014-04-08 21:04:00,35.14 2014-04-08 21:09:00,35.044000000000004 2014-04-08 21:14:00,31.378 2014-04-08 21:19:00,35.07 2014-04-08 21:24:00,34.014 2014-04-08 21:29:00,38.885999999999996 2014-04-08 21:34:00,34.046 2014-04-08 21:39:00,34.635999999999996 2014-04-08 21:44:00,34.668 2014-04-08 21:49:00,35.4 2014-04-08 21:54:00,36.784 2014-04-08 21:59:00,32.788000000000004 2014-04-08 22:04:00,34.216 2014-04-08 22:09:00,36.071999999999996 2014-04-08 22:14:00,34.054 2014-04-08 22:19:00,36.628 2014-04-08 22:24:00,37.51 2014-04-08 22:29:00,30.752 2014-04-08 22:34:00,33.638000000000005 2014-04-08 22:39:00,33.356 2014-04-08 22:44:00,33.474000000000004 2014-04-08 22:49:00,33.474000000000004 2014-04-08 22:54:00,38.656 2014-04-08 22:59:00,32.644 2014-04-08 23:04:00,32.91 2014-04-08 23:09:00,35.838 2014-04-08 23:14:00,34.288000000000004 2014-04-08 23:19:00,35.68 2014-04-08 23:24:00,37.794000000000004 2014-04-08 23:29:00,32.614000000000004 2014-04-08 23:34:00,34.718 2014-04-08 23:39:00,34.718 2014-04-08 23:44:00,35.868 2014-04-08 23:49:00,32.724000000000004 2014-04-08 23:54:00,38.11 2014-04-08 23:59:00,32.512 2014-04-09 00:04:00,34.272 2014-04-09 00:09:00,35.65 2014-04-09 00:14:00,34.148 2014-04-09 00:19:00,35.246 2014-04-09 00:24:00,33.036 2014-04-09 00:29:00,36.32 2014-04-09 00:34:00,34.742 2014-04-09 00:39:00,35.282 2014-04-09 00:44:00,32.178000000000004 2014-04-09 00:49:00,33.826 2014-04-09 00:54:00,35.916 2014-04-09 00:59:00,36.361999999999995 2014-04-09 01:04:00,36.174 2014-04-09 01:09:00,33.568000000000005 2014-04-09 01:14:00,33.94 2014-04-09 01:19:00,33.756 2014-04-09 01:24:00,34.014 2014-04-09 01:29:00,34.3 2014-04-09 01:34:00,35.894 2014-04-09 01:39:00,39.374 2014-04-09 01:44:00,31.27 2014-04-09 01:49:00,34.202 2014-04-09 01:54:00,35.938 2014-04-09 01:59:00,34.196 2014-04-09 02:04:00,36.431999999999995 2014-04-09 02:09:00,34.976 2014-04-09 02:14:00,35.72 2014-04-09 02:19:00,38.262 2014-04-09 02:24:00,30.854 2014-04-09 02:29:00,33.508 2014-04-09 02:34:00,33.576 2014-04-09 02:39:00,36.134 2014-04-09 02:44:00,31.842 2014-04-09 02:49:00,33.57 2014-04-09 02:54:00,35.076 2014-04-09 02:59:00,33.61 2014-04-09 03:04:00,33.874 2014-04-09 03:09:00,36.52 2014-04-09 03:14:00,32.724000000000004 2014-04-09 03:19:00,40.868 2014-04-09 03:24:00,33.028 2014-04-09 03:29:00,32.205999999999996 2014-04-09 03:34:00,34.836 2014-04-09 03:39:00,34.584 2014-04-09 03:44:00,34.848 2014-04-09 03:49:00,35.36400000000001 2014-04-09 03:54:00,35.0 2014-04-09 03:59:00,35.616 2014-04-09 04:04:00,32.09 2014-04-09 04:09:00,36.01 2014-04-09 04:14:00,37.264 2014-04-09 04:19:00,34.396 2014-04-09 04:24:00,35.774 2014-04-09 04:29:00,36.666 2014-04-09 04:34:00,32.135999999999996 2014-04-09 04:39:00,34.524 2014-04-09 04:44:00,32.001999999999995 2014-04-09 04:49:00,33.906 2014-04-09 04:54:00,35.634 2014-04-09 04:59:00,35.32 2014-04-09 05:04:00,36.668 2014-04-09 05:09:00,35.656 2014-04-09 05:14:00,34.044000000000004 2014-04-09 05:19:00,35.798 2014-04-09 05:24:00,31.901999999999997 2014-04-09 05:29:00,35.188 2014-04-09 05:34:00,33.24 2014-04-09 05:39:00,33.944 2014-04-09 05:44:00,36.208 2014-04-09 05:49:00,34.32 2014-04-09 05:54:00,34.042 2014-04-09 05:59:00,33.802 2014-04-09 06:04:00,34.446 2014-04-09 06:09:00,37.13800000000001 2014-04-09 06:14:00,33.186 2014-04-09 06:19:00,34.976 2014-04-09 06:24:00,37.354 2014-04-09 06:29:00,33.78 2014-04-09 06:34:00,36.15 2014-04-09 06:39:00,33.732 2014-04-09 06:44:00,32.246 2014-04-09 06:49:00,33.874 2014-04-09 06:54:00,35.704 2014-04-09 06:59:00,35.282 2014-04-09 07:04:00,35.61 2014-04-09 07:09:00,35.846 2014-04-09 07:14:00,34.226 2014-04-09 07:19:00,35.438 2014-04-09 07:24:00,35.186 2014-04-09 07:29:00,32.0 2014-04-09 07:34:00,34.17 2014-04-09 07:39:00,34.544000000000004 2014-04-09 07:44:00,34.29 2014-04-09 07:49:00,36.738 2014-04-09 07:54:00,34.504 2014-04-09 07:59:00,34.882 2014-04-09 08:04:00,32.582 2014-04-09 08:09:00,35.81800000000001 2014-04-09 08:14:00,34.364000000000004 2014-04-09 08:19:00,34.178000000000004 2014-04-09 08:24:00,35.564 2014-04-09 08:29:00,35.564 2014-04-09 08:34:00,34.062 2014-04-09 08:39:00,35.99800000000001 2014-04-09 08:44:00,33.498000000000005 2014-04-09 08:49:00,33.24 2014-04-09 08:54:00,36.902 2014-04-09 08:59:00,33.45 2014-04-09 09:04:00,34.39 2014-04-09 09:09:00,36.062 2014-04-09 09:14:00,35.705999999999996 2014-04-09 09:19:00,38.85 2014-04-09 09:24:00,32.184 2014-04-09 09:29:00,34.296 2014-04-09 09:34:00,36.048 2014-04-09 09:39:00,33.624 2014-04-09 09:44:00,34.702 2014-04-09 09:49:00,37.596 2014-04-09 09:54:00,33.098 2014-04-09 09:59:00,34.624 2014-04-09 10:04:00,36.048 2014-04-09 10:09:00,38.968 2014-04-09 10:14:00,33.216 2014-04-09 10:19:00,36.478 2014-04-09 10:24:00,32.071999999999996 2014-04-09 10:29:00,34.36 2014-04-09 10:34:00,33.96 2014-04-09 10:39:00,34.09 2014-04-09 10:44:00,36.668 2014-04-09 10:49:00,32.222 2014-04-09 10:54:00,39.536 2014-04-09 10:59:00,31.022 2014-04-09 11:04:00,34.251999999999995 2014-04-09 11:09:00,38.92 2014-04-09 11:14:00,34.558 2014-04-09 11:19:00,33.796 2014-04-09 11:24:00,38.944 2014-04-09 11:29:00,29.57800000000001 2014-04-09 11:34:00,36.174 2014-04-09 11:39:00,33.45 2014-04-09 11:44:00,35.211999999999996 2014-04-09 11:49:00,34.648 2014-04-09 11:54:00,38.194 2014-04-09 11:59:00,32.111999999999995 2014-04-09 12:04:00,34.742 2014-04-09 12:09:00,38.38 2014-04-09 12:14:00,32.348 2014-04-09 12:19:00,38.262 2014-04-09 12:24:00,32.816 2014-04-09 12:29:00,36.431999999999995 2014-04-09 12:34:00,32.066 2014-04-09 12:39:00,34.138000000000005 2014-04-09 12:44:00,34.46 2014-04-09 12:49:00,34.53 2014-04-09 12:54:00,35.394 2014-04-09 12:59:00,38.99 2014-04-09 13:04:00,27.041999999999998 2014-04-09 13:09:00,34.882 2014-04-09 13:14:00,33.052 2014-04-09 13:19:00,37.37 2014-04-09 13:24:00,35.08 2014-04-09 13:29:00,34.698 2014-04-09 13:34:00,32.821999999999996 2014-04-09 13:39:00,32.135999999999996 2014-04-09 13:44:00,35.85800000000001 2014-04-09 13:49:00,30.204 2014-04-09 13:54:00,35.042 2014-04-09 13:59:00,32.71 2014-04-09 14:04:00,35.178000000000004 2014-04-09 14:09:00,32.816 2014-04-09 14:14:00,34.272 2014-04-09 14:19:00,31.526 2014-04-09 14:24:00,35.846 2014-04-09 14:29:00,33.31 2014-04-09 14:34:00,36.832 2014-04-09 14:39:00,29.718000000000004 2014-04-09 14:44:00,34.508 2014-04-09 14:49:00,35.47 2014-04-09 14:54:00,37.722 2014-04-09 14:59:00,34.36 2014-04-09 15:04:00,35.916 2014-04-09 15:09:00,34.108000000000004 2014-04-09 15:14:00,34.372 2014-04-09 15:19:00,37.14 2014-04-09 15:24:00,36.714 2014-04-09 15:29:00,32.786 2014-04-09 15:34:00,35.694 2014-04-09 15:39:00,32.254 2014-04-09 15:44:00,34.436 2014-04-09 15:49:00,34.108000000000004 2014-04-09 15:54:00,35.938 2014-04-09 15:59:00,36.501999999999995 2014-04-09 16:04:00,36.114000000000004 2014-04-09 16:09:00,37.738 2014-04-09 16:14:00,34.742 2014-04-09 16:19:00,31.66800000000001 2014-04-09 16:24:00,35.242 2014-04-09 16:29:00,34.054 2014-04-09 16:34:00,35.64 2014-04-09 16:39:00,34.658 2014-04-09 16:44:00,34.194 2014-04-09 16:49:00,35.188 2014-04-09 16:54:00,35.846 2014-04-09 16:59:00,35.54 2014-04-09 17:04:00,38.152 2014-04-09 17:09:00,32.91 2014-04-09 17:14:00,34.668 2014-04-09 17:19:00,36.15 2014-04-09 17:24:00,35.798 2014-04-09 17:29:00,38.708 2014-04-09 17:34:00,33.836 2014-04-09 17:39:00,37.444 2014-04-09 17:44:00,33.122 2014-04-09 17:49:00,34.508 2014-04-09 17:54:00,39.178000000000004 2014-04-09 17:59:00,32.126 2014-04-09 18:04:00,34.664 2014-04-09 18:09:00,39.508 2014-04-09 18:14:00,31.478 2014-04-09 18:19:00,36.09 2014-04-09 18:24:00,36.232 2014-04-09 18:29:00,34.6 2014-04-09 18:34:00,37.135999999999996 2014-04-09 18:39:00,34.264 2014-04-09 18:44:00,33.802 2014-04-09 18:49:00,33.186 2014-04-09 18:54:00,37.356 2014-04-09 18:59:00,35.37 2014-04-09 19:04:00,33.826 2014-04-09 19:09:00,35.704 2014-04-09 19:14:00,36.032 2014-04-09 19:19:00,32.111999999999995 2014-04-09 19:24:00,38.192 2014-04-09 19:29:00,32.464 2014-04-09 19:34:00,34.178000000000004 2014-04-09 19:39:00,34.414 2014-04-09 19:44:00,36.272 2014-04-09 19:49:00,32.361999999999995 2014-04-09 19:54:00,35.588 2014-04-09 19:59:00,35.492 2014-04-09 20:04:00,32.652 2014-04-09 20:09:00,37.762 2014-04-09 20:14:00,31.052 2014-04-09 20:19:00,35.891999999999996 2014-04-09 20:24:00,31.69 2014-04-09 20:29:00,33.602 2014-04-09 20:34:00,37.49 2014-04-09 20:39:00,33.616 2014-04-09 20:44:00,33.674 2014-04-09 20:49:00,33.806 2014-04-09 20:54:00,38.92 2014-04-09 20:59:00,32.018 2014-04-09 21:04:00,34.836 2014-04-09 21:09:00,35.14 2014-04-09 21:14:00,34.38 2014-04-09 21:19:00,35.54 2014-04-09 21:24:00,31.362 2014-04-09 21:29:00,35.328 2014-04-09 21:34:00,33.052 2014-04-09 21:39:00,35.34 2014-04-09 21:44:00,32.95 2014-04-09 21:49:00,35.961999999999996 2014-04-09 21:54:00,34.172 2014-04-09 21:59:00,34.826 2014-04-09 22:04:00,35.4 2014-04-09 22:09:00,34.608000000000004 2014-04-09 22:14:00,35.16 2014-04-09 22:19:00,37.348 2014-04-09 22:24:00,34.436 2014-04-09 22:29:00,31.268 2014-04-09 22:34:00,34.036 2014-04-09 22:39:00,34.826 2014-04-09 22:44:00,33.708 2014-04-09 22:49:00,35.046 2014-04-09 22:54:00,37.794000000000004 2014-04-09 22:59:00,31.644000000000002 2014-04-09 23:04:00,34.236 2014-04-09 23:09:00,39.624 2014-04-09 23:14:00,34.178000000000004 2014-04-09 23:19:00,36.8 2014-04-09 23:24:00,34.976 2014-04-09 23:29:00,32.184 2014-04-09 23:34:00,34.226 2014-04-09 23:39:00,34.014 2014-04-09 23:44:00,33.99 2014-04-09 23:49:00,33.896 2014-04-09 23:54:00,37.512 2014-04-09 23:59:00,35.54 2014-04-10 00:04:00,29.976 2014-04-10 00:09:00,35.47 2014-04-10 00:14:00,37.864000000000004 2014-04-10 00:19:00,37.284 2014-04-10 00:24:00,31.901999999999997 2014-04-10 00:29:00,35.478 2014-04-10 00:34:00,35.934 2014-04-10 00:39:00,36.032 2014-04-10 00:44:00,33.334 2014-04-10 00:49:00,38.732 2014-04-10 00:54:00,31.644000000000002 2014-04-10 00:59:00,34.6 2014-04-10 01:04:00,36.854 2014-04-10 01:09:00,35.821999999999996 2014-04-10 01:14:00,34.226 2014-04-10 01:19:00,39.906 2014-04-10 01:24:00,30.83 2014-04-10 01:29:00,34.418 2014-04-10 01:34:00,37.135999999999996 2014-04-10 01:39:00,32.134 2014-04-10 01:44:00,34.836 2014-04-10 01:49:00,36.455999999999996 2014-04-10 01:54:00,37.746 2014-04-10 01:59:00,31.421999999999997 2014-04-10 02:04:00,34.32 2014-04-10 02:09:00,35.891999999999996 2014-04-10 02:14:00,34.11 2014-04-10 02:19:00,40.728 2014-04-10 02:24:00,32.652 2014-04-10 02:29:00,35.564 2014-04-10 02:34:00,33.968 2014-04-10 02:39:00,33.802 2014-04-10 02:44:00,36.374 2014-04-10 02:49:00,36.154 2014-04-10 02:54:00,33.73 2014-04-10 02:59:00,33.474000000000004 2014-04-10 03:04:00,36.08 2014-04-10 03:09:00,35.628 2014-04-10 03:14:00,35.61 2014-04-10 03:19:00,35.516 2014-04-10 03:24:00,35.094 2014-04-10 03:29:00,34.622 2014-04-10 03:34:00,34.512 2014-04-10 03:39:00,34.79 2014-04-10 03:44:00,36.644 2014-04-10 03:49:00,34.484 2014-04-10 03:54:00,32.91 2014-04-10 03:59:00,35.61 2014-04-10 04:04:00,33.404 2014-04-10 04:09:00,35.374 2014-04-10 04:14:00,35.458 2014-04-10 04:19:00,31.784000000000002 2014-04-10 04:24:00,33.532 2014-04-10 04:29:00,35.066 2014-04-10 04:34:00,38.49800000000001 2014-04-10 04:39:00,31.44 2014-04-10 04:44:00,35.28800000000001 2014-04-10 04:49:00,32.324 2014-04-10 04:54:00,35.455999999999996 2014-04-10 04:59:00,37.141999999999996 2014-04-10 05:04:00,34.794000000000004 2014-04-10 05:09:00,36.76 2014-04-10 05:14:00,34.178000000000004 2014-04-10 05:19:00,33.436 2014-04-10 05:24:00,36.114000000000004 2014-04-10 05:29:00,34.302 2014-04-10 05:34:00,38.968 2014-04-10 05:39:00,33.098 2014-04-10 05:44:00,34.226 2014-04-10 05:49:00,33.812 2014-04-10 05:54:00,35.7 2014-04-10 05:59:00,34.058 2014-04-10 06:04:00,35.586 2014-04-10 06:09:00,36.338 2014-04-10 06:14:00,33.192 2014-04-10 06:19:00,35.14 2014-04-10 06:24:00,36.666 2014-04-10 06:29:00,33.31 2014-04-10 06:34:00,35.164 2014-04-10 06:39:00,34.624 2014-04-10 06:44:00,32.12 2014-04-10 06:49:00,33.638000000000005 2014-04-10 06:54:00,35.4 2014-04-10 06:59:00,33.232 2014-04-10 07:04:00,33.766 2014-04-10 07:09:00,40.188 2014-04-10 07:14:00,29.201999999999998 2014-04-10 07:19:00,33.328 2014-04-10 07:24:00,33.122 2014-04-10 07:29:00,37.864000000000004 2014-04-10 07:34:00,37.77 2014-04-10 07:39:00,33.275999999999996 2014-04-10 07:44:00,32.77 2014-04-10 07:49:00,33.78 2014-04-10 07:54:00,38.0 2014-04-10 07:59:00,31.596 2014-04-10 08:04:00,33.78 2014-04-10 08:09:00,36.698 2014-04-10 08:14:00,32.85 2014-04-10 08:19:00,39.135999999999996 2014-04-10 08:24:00,34.202 2014-04-10 08:29:00,34.014 2014-04-10 08:34:00,33.332 2014-04-10 08:39:00,33.436 2014-04-10 08:44:00,35.434 2014-04-10 08:49:00,31.941999999999997 2014-04-10 08:54:00,37.936 2014-04-10 08:59:00,33.99 2014-04-10 09:04:00,36.83 2014-04-10 09:09:00,34.422 2014-04-10 09:14:00,33.812 2014-04-10 09:19:00,35.328 2014-04-10 09:24:00,31.996 2014-04-10 09:29:00,33.802 2014-04-10 09:34:00,34.394 2014-04-10 09:39:00,34.586 2014-04-10 09:44:00,34.402 2014-04-10 09:49:00,37.3 2014-04-10 09:54:00,34.474000000000004 2014-04-10 09:59:00,33.098 2014-04-10 10:04:00,35.47 2014-04-10 10:09:00,39.342 2014-04-10 10:14:00,34.86 2014-04-10 10:19:00,34.546 2014-04-10 10:24:00,33.321999999999996 2014-04-10 10:29:00,33.05 2014-04-10 10:34:00,32.09 2014-04-10 10:39:00,33.344 2014-04-10 10:44:00,34.088 2014-04-10 10:49:00,34.062 2014-04-10 10:54:00,38.216 2014-04-10 10:59:00,30.54 2014-04-10 11:04:00,33.356 2014-04-10 11:09:00,39.154 2014-04-10 11:14:00,33.356 2014-04-10 11:19:00,34.158 2014-04-10 11:24:00,34.604 2014-04-10 11:29:00,33.064 2014-04-10 11:34:00,33.135999999999996 2014-04-10 11:39:00,34.226 2014-04-10 11:44:00,34.718 2014-04-10 11:49:00,28.572 2014-04-10 11:54:00,37.464 2014-04-10 11:59:00,31.822 2014-04-10 12:04:00,34.24 2014-04-10 12:09:00,37.718 2014-04-10 12:14:00,34.6 2014-04-10 12:19:00,33.616 2014-04-10 12:24:00,33.544000000000004 2014-04-10 12:29:00,35.424 2014-04-10 12:34:00,32.032 2014-04-10 12:39:00,33.756 2014-04-10 12:44:00,33.31 2014-04-10 12:49:00,33.492 2014-04-10 12:54:00,36.361999999999995 2014-04-10 12:59:00,32.205999999999996 2014-04-10 13:04:00,36.62 2014-04-10 13:09:00,32.132 2014-04-10 13:14:00,34.226 2014-04-10 13:19:00,33.968 2014-04-10 13:24:00,36.62 2014-04-10 13:29:00,36.564 2014-04-10 13:34:00,35.022 2014-04-10 13:39:00,32.248000000000005 2014-04-10 13:44:00,34.148 2014-04-10 13:49:00,33.17 2014-04-10 13:54:00,35.986 2014-04-10 13:59:00,33.38 2014-04-10 14:04:00,35.144 2014-04-10 14:09:00,36.714 2014-04-10 14:14:00,31.784000000000002 2014-04-10 14:19:00,33.686 2014-04-10 14:24:00,33.122 2014-04-10 14:29:00,34.578 2014-04-10 14:34:00,34.894 2014-04-10 14:39:00,36.218 2014-04-10 14:44:00,36.77 2014-04-10 14:49:00,31.22 2014-04-10 14:54:00,35.086 2014-04-10 14:59:00,35.576 2014-04-10 15:04:00,33.666 2014-04-10 15:09:00,37.88800000000001 2014-04-10 15:14:00,36.398 2014-04-10 15:19:00,33.0 2014-04-10 15:24:00,32.698 2014-04-10 15:29:00,33.662 2014-04-10 15:34:00,34.108000000000004 2014-04-10 15:39:00,37.522 2014-04-10 15:44:00,33.802 2014-04-10 15:49:00,32.018 2014-04-10 15:54:00,36.056 2014-04-10 15:59:00,33.286 2014-04-10 16:04:00,36.04 2014-04-10 16:09:00,38.342 2014-04-10 16:14:00,36.571999999999996 2014-04-10 16:19:00,32.518 2014-04-10 16:24:00,34.32 2014-04-10 16:29:00,36.808 2014-04-10 16:34:00,31.808000000000003 2014-04-10 16:39:00,37.16 2014-04-10 16:44:00,37.135999999999996 2014-04-10 16:49:00,33.99 2014-04-10 16:54:00,38.052 2014-04-10 16:59:00,34.46 2014-04-10 17:04:00,34.53 2014-04-10 17:09:00,35.961999999999996 2014-04-10 17:14:00,41.01 2014-04-10 17:19:00,28.794 2014-04-10 17:24:00,34.624 2014-04-10 17:29:00,35.622 2014-04-10 17:34:00,37.824 2014-04-10 17:39:00,37.42 2014-04-10 17:44:00,34.226 2014-04-10 17:49:00,36.571999999999996 2014-04-10 17:54:00,38.92 2014-04-10 17:59:00,32.076 2014-04-10 18:04:00,36.902 2014-04-10 18:09:00,34.202 2014-04-10 18:14:00,34.681999999999995 2014-04-10 18:19:00,36.036 2014-04-10 18:24:00,33.192 2014-04-10 18:29:00,34.976 2014-04-10 18:34:00,35.798 2014-04-10 18:39:00,37.214 2014-04-10 18:44:00,38.512 2014-04-10 18:49:00,32.614000000000004 2014-04-10 18:54:00,39.63800000000001 2014-04-10 18:59:00,34.122 2014-04-10 19:04:00,33.452 2014-04-10 19:09:00,36.571999999999996 2014-04-10 19:14:00,39.32 2014-04-10 19:19:00,32.046 2014-04-10 19:24:00,34.436 2014-04-10 19:29:00,34.718 2014-04-10 19:34:00,34.635999999999996 2014-04-10 19:39:00,36.455999999999996 2014-04-10 19:44:00,38.45 2014-04-10 19:49:00,29.962 2014-04-10 19:54:00,37.522 2014-04-10 19:59:00,35.234 2014-04-10 20:04:00,34.882 2014-04-10 20:09:00,36.525999999999996 2014-04-10 20:14:00,36.596 2014-04-10 20:19:00,40.436 2014-04-10 20:24:00,31.118000000000002 2014-04-10 20:29:00,34.178000000000004 2014-04-10 20:34:00,36.49 2014-04-10 20:39:00,32.442 2014-04-10 20:44:00,34.508 2014-04-10 20:49:00,36.286 2014-04-10 20:54:00,35.916 2014-04-10 20:59:00,33.63 2014-04-10 21:04:00,34.47 2014-04-10 21:09:00,35.986 2014-04-10 21:14:00,34.474000000000004 2014-04-10 21:19:00,35.982 2014-04-10 21:24:00,37.978 2014-04-10 21:29:00,28.968000000000004 2014-04-10 21:34:00,35.188 2014-04-10 21:39:00,32.53 2014-04-10 21:44:00,33.498000000000005 2014-04-10 21:49:00,35.326 2014-04-10 21:54:00,32.7 2014-04-10 21:59:00,33.262 2014-04-10 22:04:00,36.501999999999995 2014-04-10 22:09:00,35.234 2014-04-10 22:14:00,38.24 2014-04-10 22:19:00,31.125999999999998 2014-04-10 22:24:00,36.178000000000004 2014-04-10 22:29:00,32.042 2014-04-10 22:34:00,33.732 2014-04-10 22:39:00,33.17 2014-04-10 22:44:00,33.826 2014-04-10 22:49:00,33.498000000000005 2014-04-10 22:54:00,35.211999999999996 2014-04-10 22:59:00,40.492 2014-04-10 23:04:00,30.47 2014-04-10 23:09:00,37.324 2014-04-10 23:14:00,33.052 2014-04-10 23:19:00,33.262 2014-04-10 23:24:00,33.376 2014-04-10 23:29:00,36.338 2014-04-10 23:34:00,34.132 2014-04-10 23:39:00,32.864000000000004 2014-04-10 23:44:00,34.202 2014-04-10 23:49:00,34.39 2014-04-10 23:54:00,36.238 2014-04-10 23:59:00,38.63800000000001 2014-04-11 00:04:00,30.44 2014-04-11 00:09:00,39.718 2014-04-11 00:14:00,34.0 2014-04-11 00:19:00,33.34 2014-04-11 00:24:00,35.658 2014-04-11 00:29:00,31.8 2014-04-11 00:34:00,33.876 2014-04-11 00:39:00,37.488 2014-04-11 00:44:00,29.94 2014-04-11 00:49:00,35.961999999999996 2014-04-11 00:54:00,33.336 2014-04-11 00:59:00,33.802 2014-04-11 01:04:00,35.938 2014-04-11 01:09:00,34.836 2014-04-11 01:14:00,35.564 2014-04-11 01:19:00,39.904 2014-04-11 01:24:00,29.372 2014-04-11 01:29:00,33.92 2014-04-11 01:34:00,33.99 2014-04-11 01:39:00,36.808 2014-04-11 01:44:00,33.908 2014-04-11 01:49:00,33.514 2014-04-11 01:54:00,35.296 2014-04-11 01:59:00,40.54 2014-04-11 02:04:00,33.298 2014-04-11 02:09:00,35.516 2014-04-11 02:14:00,36.282 2014-04-11 02:19:00,31.362 2014-04-11 02:24:00,33.946 2014-04-11 02:29:00,33.78 2014-04-11 02:34:00,35.634 2014-04-11 02:39:00,32.694 2014-04-11 02:44:00,32.954 2014-04-11 02:49:00,33.85 2014-04-11 02:54:00,36.198 2014-04-11 02:59:00,38.63800000000001 2014-04-11 03:04:00,31.746 2014-04-11 03:09:00,37.135999999999996 2014-04-11 03:14:00,35.68 2014-04-11 03:19:00,34.508 2014-04-11 03:24:00,34.442 2014-04-11 03:29:00,33.764 2014-04-11 03:34:00,34.384 2014-04-11 03:39:00,34.496 2014-04-11 03:44:00,35.708 2014-04-11 03:49:00,32.824 2014-04-11 03:54:00,38.874 2014-04-11 03:59:00,31.08 2014-04-11 04:04:00,33.722 2014-04-11 04:09:00,35.328 2014-04-11 04:14:00,36.69 2014-04-11 04:19:00,37.16 2014-04-11 04:24:00,34.554 2014-04-11 04:29:00,36.62 2014-04-11 04:34:00,35.0 2014-04-11 04:39:00,30.938000000000002 2014-04-11 04:44:00,33.472 2014-04-11 04:49:00,35.95 2014-04-11 04:54:00,34.214 2014-04-11 04:59:00,33.662 2014-04-11 05:04:00,34.694 2014-04-11 05:09:00,37.816 2014-04-11 05:14:00,34.624 2014-04-11 05:19:00,35.634 2014-04-11 05:24:00,34.3 2014-04-11 05:29:00,33.874 2014-04-11 05:34:00,36.478 2014-04-11 05:39:00,32.16 2014-04-11 05:44:00,33.81 2014-04-11 05:49:00,34.028 2014-04-11 05:54:00,35.516 2014-04-11 05:59:00,34.296 2014-04-11 06:04:00,32.464 2014-04-11 06:09:00,34.718 2014-04-11 06:14:00,37.07 2014-04-11 06:19:00,35.4 2014-04-11 06:24:00,31.646 2014-04-11 06:29:00,33.404 2014-04-11 06:34:00,33.711999999999996 2014-04-11 06:39:00,35.07 2014-04-11 06:44:00,34.824 2014-04-11 06:49:00,31.971999999999998 2014-04-11 06:54:00,35.098 2014-04-11 06:59:00,33.944 2014-04-11 07:04:00,35.586 2014-04-11 07:09:00,33.28 2014-04-11 07:14:00,34.718 2014-04-11 07:19:00,34.648 2014-04-11 07:24:00,34.836 2014-04-11 07:29:00,33.376 2014-04-11 07:34:00,34.624 2014-04-11 07:39:00,34.07 2014-04-11 07:44:00,33.616 2014-04-11 07:49:00,37.352 2014-04-11 07:54:00,30.63 2014-04-11 07:59:00,32.698 2014-04-11 08:04:00,35.504 2014-04-11 08:09:00,36.996 2014-04-11 08:14:00,33.738 2014-04-11 08:19:00,35.54 2014-04-11 08:24:00,32.536 2014-04-11 08:29:00,32.254 2014-04-11 08:34:00,34.186 2014-04-11 08:39:00,33.052 2014-04-11 08:44:00,36.15 2014-04-11 08:49:00,32.228 2014-04-11 08:54:00,38.492 2014-04-11 08:59:00,34.694 2014-04-11 09:04:00,34.154 2014-04-11 09:09:00,38.242 2014-04-11 09:14:00,36.202 2014-04-11 09:19:00,34.238 2014-04-11 09:24:00,30.916 2014-04-11 09:29:00,33.24 2014-04-11 09:34:00,35.492 2014-04-11 09:39:00,35.024 2014-04-11 09:44:00,32.066 2014-04-11 09:49:00,33.802 2014-04-11 09:54:00,36.69 2014-04-11 09:59:00,36.032 2014-04-11 10:04:00,36.254 2014-04-11 10:09:00,40.188 2014-04-11 10:14:00,28.94400000000001 2014-04-11 10:19:00,33.85 2014-04-11 10:24:00,33.732 2014-04-11 10:29:00,33.278 2014-04-11 10:34:00,33.53 2014-04-11 10:39:00,36.046 2014-04-11 10:44:00,33.18 2014-04-11 10:49:00,32.644 2014-04-11 10:54:00,37.244 2014-04-11 10:59:00,30.76 2014-04-11 11:04:00,33.772 2014-04-11 11:09:00,39.424 2014-04-11 11:14:00,33.028 2014-04-11 11:19:00,35.164 2014-04-11 11:24:00,31.76 2014-04-11 11:29:00,33.278 2014-04-11 11:34:00,33.756 2014-04-11 11:39:00,35.798 2014-04-11 11:44:00,33.404 2014-04-11 11:49:00,35.446 2014-04-11 11:54:00,35.602 2014-04-11 11:59:00,34.66 2014-04-11 12:04:00,34.874 2014-04-11 12:09:00,33.568000000000005 2014-04-11 12:14:00,33.474000000000004 2014-04-11 12:19:00,35.258 2014-04-11 12:24:00,35.4 2014-04-11 12:29:00,34.65 2014-04-11 12:34:00,35.4 2014-04-11 12:39:00,36.736 2014-04-11 12:44:00,33.202 2014-04-11 12:49:00,34.135999999999996 2014-04-11 12:54:00,35.868 2014-04-11 12:59:00,33.568000000000005 2014-04-11 13:04:00,33.638000000000005 2014-04-11 13:09:00,37.418 2014-04-11 13:14:00,32.934 2014-04-11 13:19:00,33.052 2014-04-11 13:24:00,33.262 2014-04-11 13:29:00,33.654 2014-04-11 13:34:00,33.874 2014-04-11 13:39:00,34.108000000000004 2014-04-11 13:44:00,33.78 2014-04-11 13:49:00,34.436 2014-04-11 13:54:00,37.184 2014-04-11 13:59:00,32.464 2014-04-11 14:04:00,35.634 2014-04-11 14:09:00,34.6 2014-04-11 14:14:00,33.616 2014-04-11 14:19:00,33.99 2014-04-11 14:24:00,33.756 2014-04-11 14:29:00,36.59 2014-04-11 14:34:00,35.406 2014-04-11 14:39:00,31.291999999999998 2014-04-11 14:44:00,33.348 2014-04-11 14:49:00,34.12 2014-04-11 14:54:00,37.111999999999995 2014-04-11 14:59:00,31.471999999999998 2014-04-11 15:04:00,34.014 2014-04-11 15:09:00,38.052 2014-04-11 15:14:00,32.042 2014-04-11 15:19:00,34.718 2014-04-11 15:24:00,35.152 2014-04-11 15:29:00,33.85 2014-04-11 15:34:00,33.498000000000005 2014-04-11 15:39:00,34.53 2014-04-11 15:44:00,34.414 2014-04-11 15:49:00,36.15 2014-04-11 15:54:00,34.176 2014-04-11 15:59:00,34.05 2014-04-11 16:04:00,34.558 2014-04-11 16:09:00,40.184 2014-04-11 16:14:00,31.996 2014-04-11 16:19:00,33.31 2014-04-11 16:24:00,35.856 2014-04-11 16:29:00,35.461999999999996 2014-04-11 16:34:00,33.818000000000005 2014-04-11 16:39:00,33.568000000000005 2014-04-11 16:44:00,34.976 2014-04-11 16:49:00,32.652 2014-04-11 16:54:00,38.24 2014-04-11 16:59:00,33.78 2014-04-11 17:04:00,32.86 2014-04-11 17:09:00,35.564 2014-04-11 17:14:00,34.226 2014-04-11 17:19:00,35.548 2014-04-11 17:24:00,37.324 2014-04-11 17:29:00,34.484 2014-04-11 17:34:00,35.046 2014-04-11 17:39:00,34.472 2014-04-11 17:44:00,34.648 2014-04-11 17:49:00,35.466 2014-04-11 17:54:00,36.384 2014-04-11 17:59:00,34.952 2014-04-11 18:04:00,32.898 2014-04-11 18:09:00,37.464 2014-04-11 18:14:00,36.104 2014-04-11 18:19:00,34.726 2014-04-11 18:24:00,34.088 2014-04-11 18:29:00,37.418 2014-04-11 18:34:00,32.09 2014-04-11 18:39:00,33.216 2014-04-11 18:44:00,34.588 2014-04-11 18:49:00,34.568000000000005 2014-04-11 18:54:00,38.076 2014-04-11 18:59:00,37.696 2014-04-11 19:04:00,34.288000000000004 2014-04-11 19:09:00,34.211999999999996 2014-04-11 19:14:00,36.598 2014-04-11 19:19:00,31.502 2014-04-11 19:24:00,34.025999999999996 2014-04-11 19:29:00,37.63 2014-04-11 19:34:00,34.248000000000005 2014-04-11 19:39:00,34.976 2014-04-11 19:44:00,34.672 2014-04-11 19:49:00,35.658 2014-04-11 19:54:00,35.086 2014-04-11 19:59:00,34.064 2014-04-11 20:04:00,36.878 2014-04-11 20:09:00,35.634 2014-04-11 20:14:00,32.174 2014-04-11 20:19:00,34.178000000000004 2014-04-11 20:24:00,34.092 2014-04-11 20:29:00,37.866 2014-04-11 20:34:00,34.366 2014-04-11 20:39:00,34.414 2014-04-11 20:44:00,34.446 2014-04-11 20:49:00,34.308 2014-04-11 20:54:00,36.314 2014-04-11 20:59:00,41.948 2014-04-11 21:04:00,29.788 2014-04-11 21:09:00,38.522 2014-04-11 21:14:00,34.33 2014-04-11 21:19:00,34.37 2014-04-11 21:24:00,34.226 2014-04-11 21:29:00,36.82 2014-04-11 21:34:00,32.536 2014-04-11 21:39:00,34.788000000000004 2014-04-11 21:44:00,37.018 2014-04-11 21:49:00,33.356 2014-04-11 21:54:00,34.882 2014-04-11 21:59:00,38.592 2014-04-11 22:04:00,35.188 2014-04-11 22:09:00,38.404 2014-04-11 22:14:00,36.738 2014-04-11 22:19:00,37.03 2014-04-11 22:24:00,35.48 2014-04-11 22:29:00,32.782 2014-04-11 22:34:00,39.39 2014-04-11 22:39:00,31.976 2014-04-11 22:44:00,34.35 2014-04-11 22:49:00,34.742 2014-04-11 22:54:00,36.08 2014-04-11 22:59:00,35.338 2014-04-11 23:04:00,35.508 2014-04-11 23:09:00,34.278 2014-04-11 23:14:00,33.178000000000004 2014-04-11 23:19:00,34.836 2014-04-11 23:24:00,35.47 2014-04-11 23:29:00,36.86 2014-04-11 23:34:00,34.998000000000005 2014-04-11 23:39:00,35.24800000000001 2014-04-11 23:44:00,34.69 2014-04-11 23:49:00,34.614000000000004 2014-04-11 23:54:00,38.202 2014-04-11 23:59:00,31.674 2014-04-12 00:04:00,35.696 2014-04-12 00:09:00,37.184 2014-04-12 00:14:00,31.514 2014-04-12 00:19:00,36.01 2014-04-12 00:24:00,33.498000000000005 2014-04-12 00:29:00,37.536 2014-04-12 00:34:00,36.1 2014-04-12 00:39:00,34.38 2014-04-12 00:44:00,35.586 2014-04-12 00:49:00,33.732 2014-04-12 00:54:00,38.756 2014-04-12 00:59:00,33.708 2014-04-12 01:04:00,32.455999999999996 2014-04-12 01:09:00,36.338 2014-04-12 01:14:00,33.906 2014-04-12 01:19:00,35.098 2014-04-12 01:24:00,33.122 2014-04-12 01:29:00,33.86 2014-04-12 01:34:00,39.296 2014-04-12 01:39:00,30.118000000000002 2014-04-12 01:44:00,34.566 2014-04-12 01:49:00,34.484 2014-04-12 01:54:00,37.746 2014-04-12 01:59:00,35.24800000000001 2014-04-12 02:04:00,32.816 2014-04-12 02:09:00,36.08 2014-04-12 02:14:00,34.414 2014-04-12 02:19:00,36.294000000000004 2014-04-12 02:24:00,32.622 2014-04-12 02:29:00,38.99 2014-04-12 02:34:00,33.816 2014-04-12 02:39:00,37.042 2014-04-12 02:44:00,36.174 2014-04-12 02:49:00,34.562 2014-04-12 02:54:00,36.22 2014-04-12 02:59:00,37.23 2014-04-12 03:04:00,35.912 2014-04-12 03:09:00,35.128 2014-04-12 03:14:00,34.286 2014-04-12 03:19:00,34.224000000000004 2014-04-12 03:24:00,33.748000000000005 2014-04-12 03:29:00,35.916 2014-04-12 03:34:00,32.63 2014-04-12 03:39:00,34.196 2014-04-12 03:44:00,35.422 2014-04-12 03:49:00,32.652 2014-04-12 03:54:00,37.876 2014-04-12 03:59:00,33.404 2014-04-12 04:04:00,32.32 2014-04-12 04:09:00,36.104 2014-04-12 04:14:00,35.106 2014-04-12 04:19:00,35.216 2014-04-12 04:24:00,35.204 2014-04-12 04:29:00,34.836 2014-04-12 04:34:00,32.152 2014-04-12 04:39:00,34.084 2014-04-12 04:44:00,36.174 2014-04-12 04:49:00,32.536 2014-04-12 04:54:00,36.034 2014-04-12 04:59:00,36.644 2014-04-12 05:04:00,30.088 2014-04-12 05:09:00,35.314 2014-04-12 05:14:00,33.942 2014-04-12 05:19:00,33.58 2014-04-12 05:24:00,33.262 2014-04-12 05:29:00,38.43 2014-04-12 05:34:00,31.314 2014-04-12 05:39:00,33.24 2014-04-12 05:44:00,34.211999999999996 2014-04-12 05:49:00,33.79 2014-04-12 05:54:00,34.992 2014-04-12 05:59:00,33.262 2014-04-12 06:04:00,36.478 2014-04-12 06:09:00,34.27 2014-04-12 06:14:00,35.306 2014-04-12 06:19:00,31.561999999999998 2014-04-12 06:24:00,33.874 2014-04-12 06:29:00,35.516 2014-04-12 06:34:00,34.272 2014-04-12 06:39:00,37.652 2014-04-12 06:44:00,32.384 2014-04-12 06:49:00,33.568000000000005 2014-04-12 06:54:00,36.714 2014-04-12 06:59:00,33.826 2014-04-12 07:04:00,32.226 2014-04-12 07:09:00,36.275999999999996 2014-04-12 07:14:00,34.85 2014-04-12 07:19:00,35.282 2014-04-12 07:24:00,32.09 2014-04-12 07:29:00,34.062 2014-04-12 07:34:00,34.836 2014-04-12 07:39:00,34.508 2014-04-12 07:44:00,36.268 2014-04-12 07:49:00,34.016 2014-04-12 07:54:00,35.3 2014-04-12 07:59:00,32.606 2014-04-12 08:04:00,33.85 2014-04-12 08:09:00,36.234 2014-04-12 08:14:00,35.068000000000005 2014-04-12 08:19:00,31.791999999999998 2014-04-12 08:24:00,33.961999999999996 2014-04-12 08:29:00,34.812 2014-04-12 08:34:00,35.118 2014-04-12 08:39:00,33.15 2014-04-12 08:44:00,32.184 2014-04-12 08:49:00,34.194 2014-04-12 08:54:00,35.61 2014-04-12 08:59:00,33.098 2014-04-12 09:04:00,33.57 2014-04-12 09:09:00,36.204 2014-04-12 09:14:00,32.056 2014-04-12 09:19:00,31.666 2014-04-12 09:24:00,36.62 2014-04-12 09:29:00,31.596 2014-04-12 09:34:00,33.498000000000005 2014-04-12 09:39:00,35.938 2014-04-12 09:44:00,31.62 2014-04-12 09:49:00,34.53 2014-04-12 09:54:00,34.312 2014-04-12 09:59:00,33.302 2014-04-12 10:04:00,33.78 2014-04-12 10:09:00,38.99 2014-04-12 10:14:00,29.754 2014-04-12 10:19:00,33.616 2014-04-12 10:24:00,34.672 2014-04-12 10:29:00,33.802 2014-04-12 10:34:00,35.564 2014-04-12 10:39:00,33.874 2014-04-12 10:44:00,35.99800000000001 2014-04-12 10:49:00,31.988000000000003 2014-04-12 10:54:00,35.211999999999996 2014-04-12 10:59:00,33.522 2014-04-12 11:04:00,37.324 2014-04-12 11:09:00,32.606 2014-04-12 11:14:00,35.891999999999996 2014-04-12 11:19:00,31.76 2014-04-12 11:24:00,33.556 2014-04-12 11:29:00,33.426 2014-04-12 11:34:00,33.522 2014-04-12 11:39:00,34.648 2014-04-12 11:44:00,31.886 2014-04-12 11:49:00,37.016 2014-04-12 11:54:00,30.554000000000002 2014-04-12 11:59:00,32.88 2014-04-12 12:04:00,33.326 2014-04-12 12:09:00,34.718 2014-04-12 12:14:00,36.032 2014-04-12 12:19:00,29.624000000000002 2014-04-12 12:24:00,33.17 2014-04-12 12:29:00,34.202 2014-04-12 12:34:00,37.24800000000001 2014-04-12 12:39:00,30.61 2014-04-12 12:44:00,35.571999999999996 2014-04-12 12:49:00,31.666 2014-04-12 12:54:00,36.292 2014-04-12 12:59:00,31.76 2014-04-12 13:04:00,33.356 2014-04-12 13:09:00,36.004 2014-04-12 13:14:00,36.464 2014-04-12 13:19:00,32.728 2014-04-12 13:24:00,31.448 2014-04-12 13:29:00,33.896 2014-04-12 13:34:00,32.3 2014-04-12 13:39:00,34.248000000000005 2014-04-12 13:44:00,33.656 2014-04-12 13:49:00,34.906 2014-04-12 13:54:00,32.536 2014-04-12 13:59:00,32.424 2014-04-12 14:04:00,33.03 2014-04-12 14:09:00,38.238 2014-04-12 14:14:00,29.108 2014-04-12 14:19:00,35.086 2014-04-12 14:24:00,30.778000000000002 2014-04-12 14:29:00,32.676 2014-04-12 14:34:00,35.774 2014-04-12 14:39:00,34.342 2014-04-12 14:44:00,32.108000000000004 2014-04-12 14:49:00,37.496 2014-04-12 14:54:00,30.351999999999997 2014-04-12 14:59:00,33.27 2014-04-12 15:04:00,34.766 2014-04-12 15:09:00,35.846 2014-04-12 15:14:00,34.718 2014-04-12 15:19:00,32.066 2014-04-12 15:24:00,35.108000000000004 2014-04-12 15:29:00,30.978 2014-04-12 15:34:00,33.818000000000005 2014-04-12 15:39:00,36.152 2014-04-12 15:44:00,31.55 2014-04-12 15:49:00,36.838 2014-04-12 15:54:00,31.22 2014-04-12 15:59:00,32.558 2014-04-12 16:04:00,33.24 2014-04-12 16:09:00,34.08 2014-04-12 16:14:00,32.934 2014-04-12 16:19:00,33.122 2014-04-12 16:24:00,35.74800000000001 2014-04-12 16:29:00,34.154 2014-04-12 16:34:00,31.45 2014-04-12 16:39:00,32.488 2014-04-12 16:44:00,32.794000000000004 2014-04-12 16:49:00,32.864000000000004 2014-04-12 16:54:00,34.884 2014-04-12 16:59:00,33.146 2014-04-12 17:04:00,37.275999999999996 2014-04-12 17:09:00,33.616 2014-04-12 17:14:00,30.32800000000001 2014-04-12 17:19:00,32.864000000000004 2014-04-12 17:24:00,33.076 2014-04-12 17:29:00,32.84 2014-04-12 17:34:00,35.292 2014-04-12 17:39:00,32.606 2014-04-12 17:44:00,31.912 2014-04-12 17:49:00,35.141999999999996 2014-04-12 17:54:00,32.738 2014-04-12 17:59:00,32.84 2014-04-12 18:04:00,36.032 2014-04-12 18:09:00,33.78 2014-04-12 18:14:00,33.544000000000004 2014-04-12 18:19:00,33.37 2014-04-12 18:24:00,34.32 2014-04-12 18:29:00,32.394 2014-04-12 18:34:00,37.816 2014-04-12 18:39:00,38.522 2014-04-12 18:44:00,33.404 2014-04-12 18:49:00,36.268 2014-04-12 18:54:00,32.84 2014-04-12 18:59:00,35.282 2014-04-12 19:04:00,34.038000000000004 2014-04-12 19:09:00,37.132 2014-04-12 19:14:00,35.774 2014-04-12 19:19:00,31.305999999999997 2014-04-12 19:24:00,33.251999999999995 2014-04-12 19:29:00,33.54 2014-04-12 19:34:00,34.062 2014-04-12 19:39:00,35.492 2014-04-12 19:44:00,36.972 2014-04-12 19:49:00,30.212 2014-04-12 19:54:00,35.821999999999996 2014-04-12 19:59:00,33.868 2014-04-12 20:04:00,34.282 2014-04-12 20:09:00,38.75 2014-04-12 20:14:00,37.18 2014-04-12 20:19:00,30.704 2014-04-12 20:24:00,33.92 2014-04-12 20:29:00,36.431999999999995 2014-04-12 20:34:00,31.314 2014-04-12 20:39:00,34.384 2014-04-12 20:44:00,36.361999999999995 2014-04-12 20:49:00,33.662 2014-04-12 20:54:00,34.436 2014-04-12 20:59:00,33.662 2014-04-12 21:04:00,33.568000000000005 2014-04-12 21:09:00,39.111999999999995 2014-04-12 21:14:00,32.934 2014-04-12 21:19:00,31.666 2014-04-12 21:24:00,35.33 2014-04-12 21:29:00,32.404 2014-04-12 21:34:00,33.944 2014-04-12 21:39:00,34.578 2014-04-12 21:44:00,36.104 2014-04-12 21:49:00,31.574 2014-04-12 21:54:00,34.654 2014-04-12 21:59:00,33.846 2014-04-12 22:04:00,34.2 2014-04-12 22:09:00,34.272 2014-04-12 22:14:00,34.02 2014-04-12 22:19:00,35.838 2014-04-12 22:24:00,31.834 2014-04-12 22:29:00,34.014 2014-04-12 22:34:00,33.874 2014-04-12 22:39:00,33.04 2014-04-12 22:44:00,34.316 2014-04-12 22:49:00,37.7 2014-04-12 22:54:00,33.916 2014-04-12 22:59:00,31.901999999999997 2014-04-12 23:04:00,34.726 2014-04-12 23:09:00,35.306 2014-04-12 23:14:00,33.826 2014-04-12 23:19:00,34.32 2014-04-12 23:24:00,38.662 2014-04-12 23:29:00,33.334 2014-04-12 23:34:00,38.286 2014-04-12 23:39:00,31.526 2014-04-12 23:44:00,34.624 2014-04-12 23:49:00,33.976 2014-04-12 23:54:00,35.662 2014-04-12 23:59:00,35.916 2014-04-13 00:04:00,33.334 2014-04-13 00:09:00,36.431999999999995 2014-04-13 00:14:00,33.544000000000004 2014-04-13 00:19:00,35.61199999999999 2014-04-13 00:24:00,37.746 2014-04-13 00:29:00,33.24 2014-04-13 00:34:00,31.706 2014-04-13 00:39:00,34.772 2014-04-13 00:44:00,32.92 2014-04-13 00:49:00,34.014 2014-04-13 00:54:00,37.864000000000004 2014-04-13 00:59:00,31.526 2014-04-13 01:04:00,34.108000000000004 2014-04-13 01:09:00,36.244 2014-04-13 01:14:00,38.431999999999995 2014-04-13 01:19:00,33.156 2014-04-13 01:24:00,36.37 2014-04-13 01:29:00,31.268 2014-04-13 01:34:00,34.954 2014-04-13 01:39:00,34.288000000000004 2014-04-13 01:44:00,33.498000000000005 2014-04-13 01:49:00,34.718 2014-04-13 01:54:00,34.428000000000004 2014-04-13 01:59:00,38.705999999999996 2014-04-13 02:04:00,31.08 2014-04-13 02:09:00,36.738 2014-04-13 02:14:00,33.704 2014-04-13 02:19:00,34.058 2014-04-13 02:24:00,33.534 2014-04-13 02:29:00,33.522 2014-04-13 02:34:00,34.484 2014-04-13 02:39:00,34.391999999999996 2014-04-13 02:44:00,31.924 2014-04-13 02:49:00,33.775999999999996 2014-04-13 02:54:00,37.586 2014-04-13 02:59:00,30.97 2014-04-13 03:04:00,33.672 2014-04-13 03:09:00,41.034 2014-04-13 03:14:00,34.17 2014-04-13 03:19:00,33.474000000000004 2014-04-13 03:24:00,34.73 2014-04-13 03:29:00,35.164 2014-04-13 03:34:00,36.62 2014-04-13 03:39:00,36.654 2014-04-13 03:44:00,29.95 2014-04-13 03:49:00,33.46 2014-04-13 03:54:00,35.304 2014-04-13 03:59:00,34.672 2014-04-13 04:04:00,37.442 2014-04-13 04:09:00,34.6 2014-04-13 04:14:00,36.256 2014-04-13 04:19:00,32.536 2014-04-13 04:24:00,36.22 2014-04-13 04:29:00,33.44 2014-04-13 04:34:00,31.666 2014-04-13 04:39:00,33.17 2014-04-13 04:44:00,33.756 2014-04-13 04:49:00,35.0 2014-04-13 04:54:00,33.638000000000005 2014-04-13 04:59:00,34.86 2014-04-13 05:04:00,34.308 2014-04-13 05:09:00,33.146 2014-04-13 05:14:00,36.174 2014-04-13 05:19:00,35.198 2014-04-13 05:24:00,34.866 2014-04-13 05:29:00,31.738000000000003 2014-04-13 05:34:00,35.33 2014-04-13 05:39:00,31.802 2014-04-13 05:44:00,33.262 2014-04-13 05:49:00,33.146 2014-04-13 05:54:00,34.976 2014-04-13 05:59:00,33.592 2014-04-13 06:04:00,35.082 2014-04-13 06:09:00,36.455999999999996 2014-04-13 06:14:00,32.092 2014-04-13 06:19:00,34.366 2014-04-13 06:24:00,35.586 2014-04-13 06:29:00,32.828 2014-04-13 06:34:00,34.984 2014-04-13 06:39:00,32.096 2014-04-13 06:44:00,31.526 2014-04-13 06:49:00,35.516 2014-04-13 06:54:00,31.996 2014-04-13 06:59:00,34.46 2014-04-13 07:04:00,30.774 2014-04-13 07:09:00,34.788000000000004 2014-04-13 07:14:00,34.04 2014-04-13 07:19:00,34.722 2014-04-13 07:24:00,35.798 2014-04-13 07:29:00,34.6 2014-04-13 07:34:00,30.798000000000002 2014-04-13 07:39:00,33.326 2014-04-13 07:44:00,34.46 2014-04-13 07:49:00,36.232 2014-04-13 07:54:00,36.478 2014-04-13 07:59:00,33.556 2014-04-13 08:04:00,33.216 2014-04-13 08:09:00,34.46 2014-04-13 08:14:00,35.376 2014-04-13 08:19:00,30.212 2014-04-13 08:24:00,36.056 2014-04-13 08:29:00,29.27 2014-04-13 08:34:00,32.814 2014-04-13 08:39:00,32.652 2014-04-13 08:44:00,32.942 2014-04-13 08:49:00,33.416 2014-04-13 08:54:00,37.56 2014-04-13 08:59:00,36.158 2014-04-13 09:04:00,30.658 2014-04-13 09:09:00,35.891999999999996 2014-04-13 09:14:00,34.226 2014-04-13 09:19:00,33.122 2014-04-13 09:24:00,34.84 2014-04-13 09:29:00,30.822 2014-04-13 09:34:00,34.968 2014-04-13 09:39:00,32.275999999999996 2014-04-13 09:44:00,35.774 2014-04-13 09:49:00,30.54 2014-04-13 09:54:00,34.75 2014-04-13 09:59:00,35.188 2014-04-13 10:04:00,31.338 2014-04-13 10:09:00,37.254 2014-04-13 10:14:00,35.468 2014-04-13 10:19:00,31.49 2014-04-13 10:24:00,32.978 2014-04-13 10:29:00,37.635999999999996 2014-04-13 10:34:00,28.204 2014-04-13 10:39:00,32.676 2014-04-13 10:44:00,32.934 2014-04-13 10:49:00,33.82 2014-04-13 10:54:00,33.382 2014-04-13 10:59:00,35.0 2014-04-13 11:04:00,31.201999999999998 2014-04-13 11:09:00,34.702 2014-04-13 11:14:00,37.412 2014-04-13 11:19:00,33.544000000000004 2014-04-13 11:24:00,34.014 2014-04-13 11:29:00,33.8 2014-04-13 11:34:00,32.111999999999995 2014-04-13 11:39:00,33.99 2014-04-13 11:44:00,34.824 2014-04-13 11:49:00,33.708 2014-04-13 11:54:00,34.624 2014-04-13 11:59:00,33.888000000000005 2014-04-13 12:04:00,39.994 2014-04-13 12:09:00,33.498000000000005 2014-04-13 12:14:00,31.54 2014-04-13 12:19:00,32.79 2014-04-13 12:24:00,32.982 2014-04-13 12:29:00,32.652 2014-04-13 12:34:00,35.282 2014-04-13 12:39:00,32.418 2014-04-13 12:44:00,31.76 2014-04-13 12:49:00,34.624 2014-04-13 12:54:00,33.428000000000004 2014-04-13 12:59:00,33.334 2014-04-13 13:04:00,32.764 2014-04-13 13:09:00,37.374 2014-04-13 13:14:00,31.921999999999997 2014-04-13 13:19:00,31.76 2014-04-13 13:24:00,35.492 2014-04-13 13:29:00,35.516 2014-04-13 13:34:00,34.578 2014-04-13 13:39:00,34.62 2014-04-13 13:44:00,32.096 2014-04-13 13:49:00,32.018 2014-04-13 13:54:00,36.314 2014-04-13 13:59:00,31.478 2014-04-13 14:04:00,35.586 2014-04-13 14:09:00,32.8 2014-04-13 14:14:00,33.95 2014-04-13 14:19:00,35.824 2014-04-13 14:24:00,38.874 2014-04-13 14:29:00,36.054 2014-04-13 14:34:00,33.262 2014-04-13 14:39:00,33.544000000000004 2014-04-13 14:44:00,33.568000000000005 2014-04-13 14:49:00,33.45 2014-04-13 14:54:00,34.882 2014-04-13 14:59:00,33.474000000000004 2014-04-13 15:04:00,36.596 2014-04-13 15:09:00,33.001999999999995 2014-04-13 15:14:00,32.582 2014-04-13 15:19:00,37.6 2014-04-13 15:24:00,33.438 2014-04-13 15:29:00,33.292 2014-04-13 15:34:00,35.942 2014-04-13 15:39:00,33.484 2014-04-13 15:44:00,33.004 2014-04-13 15:49:00,33.514 2014-04-13 15:54:00,35.306 2014-04-13 15:59:00,34.32 2014-04-13 16:04:00,34.766 2014-04-13 16:09:00,33.076 2014-04-13 16:14:00,34.282 2014-04-13 16:19:00,33.592 2014-04-13 16:24:00,32.275999999999996 2014-04-13 16:29:00,38.852 2014-04-13 16:34:00,32.882 2014-04-13 16:39:00,33.216 2014-04-13 16:44:00,34.234 2014-04-13 16:49:00,32.582 2014-04-13 16:54:00,35.282 2014-04-13 16:59:00,36.948 2014-04-13 17:04:00,31.471999999999998 2014-04-13 17:09:00,33.614000000000004 2014-04-13 17:14:00,34.4 2014-04-13 17:19:00,35.008 2014-04-13 17:24:00,33.07 2014-04-13 17:29:00,35.116 2014-04-13 17:34:00,34.452 2014-04-13 17:39:00,31.39 2014-04-13 17:44:00,33.512 2014-04-13 17:49:00,33.47 2014-04-13 17:54:00,37.746 2014-04-13 17:59:00,31.69 2014-04-13 18:04:00,33.67 2014-04-13 18:09:00,36.208 2014-04-13 18:14:00,32.042 2014-04-13 18:19:00,37.298 2014-04-13 18:24:00,30.32800000000001 2014-04-13 18:29:00,35.846 2014-04-13 18:34:00,37.566 2014-04-13 18:39:00,33.04 2014-04-13 18:44:00,34.641999999999996 2014-04-13 18:49:00,32.124 2014-04-13 18:54:00,35.352 2014-04-13 18:59:00,34.536 2014-04-13 19:04:00,32.464 2014-04-13 19:09:00,37.348 2014-04-13 19:14:00,31.384 2014-04-13 19:19:00,34.718 2014-04-13 19:24:00,34.342 2014-04-13 19:29:00,35.164 2014-04-13 19:34:00,35.328 2014-04-13 19:39:00,34.86 2014-04-13 19:44:00,37.288000000000004 2014-04-13 19:49:00,31.072 2014-04-13 19:54:00,36.032 2014-04-13 19:59:00,33.394 2014-04-13 20:04:00,33.004 2014-04-13 20:09:00,35.418 2014-04-13 20:14:00,35.47 2014-04-13 20:19:00,31.055999999999997 2014-04-13 20:24:00,33.098 2014-04-13 20:29:00,33.31 2014-04-13 20:34:00,33.248000000000005 2014-04-13 20:39:00,35.961999999999996 2014-04-13 20:44:00,32.744 2014-04-13 20:49:00,31.528000000000002 2014-04-13 20:54:00,34.624 2014-04-13 20:59:00,34.788000000000004 2014-04-13 21:04:00,32.568000000000005 2014-04-13 21:09:00,35.004 2014-04-13 21:14:00,34.52 2014-04-13 21:19:00,34.014 2014-04-13 21:24:00,32.464 2014-04-13 21:29:00,32.042 2014-04-13 21:34:00,34.038000000000004 2014-04-13 21:39:00,34.566 2014-04-13 21:44:00,35.282 2014-04-13 21:49:00,34.664 2014-04-13 21:54:00,39.236 2014-04-13 21:59:00,28.338 2014-04-13 22:04:00,33.494 2014-04-13 22:09:00,34.766 2014-04-13 22:14:00,34.648 2014-04-13 22:19:00,31.738000000000003 2014-04-13 22:24:00,35.282 2014-04-13 22:29:00,32.394 2014-04-13 22:34:00,32.536 2014-04-13 22:39:00,34.766 2014-04-13 22:44:00,32.57 2014-04-13 22:49:00,33.424 2014-04-13 22:54:00,37.184 2014-04-13 22:59:00,32.864000000000004 2014-04-13 23:04:00,33.944 2014-04-13 23:09:00,33.954 2014-04-13 23:14:00,33.884 2014-04-13 23:19:00,33.18 2014-04-13 23:24:00,33.17 2014-04-13 23:29:00,35.282 2014-04-13 23:34:00,32.344 2014-04-13 23:39:00,33.406 2014-04-13 23:44:00,34.906 2014-04-13 23:49:00,31.94400000000001 2014-04-13 23:54:00,36.078 2014-04-13 23:59:00,33.814 2014-04-14 00:04:00,34.396 2014-04-14 00:09:00,35.0 2014-04-14 00:14:00,33.38 2014-04-14 00:19:00,37.126 2014-04-14 00:24:00,33.391999999999996 2014-04-14 00:29:00,36.666 2014-04-14 00:34:00,31.726 2014-04-14 00:39:00,34.406 2014-04-14 00:44:00,32.794000000000004 2014-04-14 00:49:00,34.006 2014-04-14 00:54:00,36.666 2014-04-14 00:59:00,32.36 2014-04-14 01:04:00,33.635999999999996 2014-04-14 01:09:00,37.135999999999996 2014-04-14 01:14:00,31.932 2014-04-14 01:19:00,34.648 2014-04-14 01:24:00,32.242 2014-04-14 01:29:00,33.404 2014-04-14 01:34:00,36.211999999999996 2014-04-14 01:39:00,39.306 2014-04-14 01:44:00,34.828 2014-04-14 01:49:00,31.314 2014-04-14 01:54:00,35.308 2014-04-14 01:59:00,33.498000000000005 2014-04-14 02:04:00,34.788000000000004 2014-04-14 02:09:00,33.72 2014-04-14 02:14:00,36.996 2014-04-14 02:19:00,30.938000000000002 2014-04-14 02:24:00,32.746 2014-04-14 02:29:00,34.46 2014-04-14 02:34:00,33.984 2014-04-14 02:39:00,35.656 2014-04-14 02:44:00,34.436 2014-04-14 02:49:00,31.15 2014-04-14 02:54:00,35.586 2014-04-14 02:59:00,33.608000000000004 2014-04-14 03:04:00,34.694 2014-04-14 03:09:00,34.906 2014-04-14 03:14:00,38.356 2014-04-14 03:19:00,32.652 2014-04-14 03:24:00,33.076 2014-04-14 03:29:00,37.606 2014-04-14 03:34:00,32.711999999999996 2014-04-14 03:39:00,34.705999999999996 2014-04-14 03:44:00,37.12 2014-04-14 03:49:00,31.714000000000002 2014-04-14 03:54:00,36.784 2014-04-14 03:59:00,33.708 2014-04-14 04:04:00,38.24 2014-04-14 04:09:00,33.92 2014-04-14 04:14:00,35.452 2014-04-14 04:19:00,31.62 2014-04-14 04:24:00,33.592 2014-04-14 04:29:00,34.812 2014-04-14 04:34:00,33.838 2014-04-14 04:39:00,35.236 2014-04-14 04:44:00,29.978 2014-04-14 04:49:00,33.094 2014-04-14 04:54:00,35.946 2014-04-14 04:59:00,33.522 2014-04-14 05:04:00,33.304 2014-04-14 05:09:00,35.082 2014-04-14 05:14:00,33.562 2014-04-14 05:19:00,34.484 2014-04-14 05:24:00,38.286 2014-04-14 05:29:00,32.102 2014-04-14 05:34:00,32.37 2014-04-14 05:39:00,33.896 2014-04-14 05:44:00,34.244 2014-04-14 05:49:00,33.78 2014-04-14 05:54:00,35.078 2014-04-14 05:59:00,35.35 2014-04-14 06:04:00,31.808000000000003 2014-04-14 06:09:00,35.258 2014-04-14 06:14:00,34.806 2014-04-14 06:19:00,32.264 2014-04-14 06:24:00,37.184 2014-04-14 06:29:00,32.43 2014-04-14 06:34:00,35.504 2014-04-14 06:39:00,31.244 2014-04-14 06:44:00,33.896 2014-04-14 06:49:00,34.788000000000004 2014-04-14 06:54:00,34.098 2014-04-14 06:59:00,34.132 2014-04-14 07:04:00,35.821999999999996 2014-04-14 07:09:00,35.692 2014-04-14 07:14:00,36.354 2014-04-14 07:19:00,35.094 2014-04-14 07:24:00,33.6 2014-04-14 07:29:00,34.718 2014-04-14 07:34:00,32.496 2014-04-14 07:39:00,35.798 2014-04-14 07:44:00,32.135999999999996 2014-04-14 07:49:00,33.31 2014-04-14 07:54:00,37.536 2014-04-14 07:59:00,31.031999999999996 2014-04-14 08:04:00,33.802 2014-04-14 08:09:00,37.63 2014-04-14 08:14:00,37.254 2014-04-14 08:19:00,31.13 2014-04-14 08:24:00,33.286 2014-04-14 08:29:00,33.046 2014-04-14 08:34:00,33.122 2014-04-14 08:39:00,38.391999999999996 2014-04-14 08:44:00,30.281999999999996 2014-04-14 08:49:00,32.205999999999996 2014-04-14 08:54:00,35.14 2014-04-14 08:59:00,36.22 2014-04-14 09:04:00,33.592 2014-04-14 09:09:00,35.762 2014-04-14 09:14:00,36.858000000000004 2014-04-14 09:19:00,32.111999999999995 2014-04-14 09:24:00,37.69 2014-04-14 09:29:00,29.79 2014-04-14 09:34:00,33.916 2014-04-14 09:39:00,33.998000000000005 2014-04-14 09:44:00,36.164 2014-04-14 09:49:00,32.128 2014-04-14 09:54:00,35.872 2014-04-14 09:59:00,33.782 2014-04-14 10:04:00,37.418 2014-04-14 10:09:00,34.93 2014-04-14 10:14:00,33.644 2014-04-14 10:19:00,32.464 2014-04-14 10:24:00,35.66 2014-04-14 10:29:00,31.162 2014-04-14 10:34:00,33.338 2014-04-14 10:39:00,35.472 2014-04-14 10:44:00,32.676 2014-04-14 10:49:00,32.794000000000004 2014-04-14 10:54:00,34.882 2014-04-14 10:59:00,35.354 2014-04-14 11:04:00,32.14 2014-04-14 11:09:00,34.882 2014-04-14 11:14:00,35.738 2014-04-14 11:19:00,34.558 2014-04-14 11:24:00,33.896 2014-04-14 11:29:00,30.938000000000002 2014-04-14 11:34:00,33.256 2014-04-14 11:39:00,33.594 2014-04-14 11:44:00,33.628 2014-04-14 11:49:00,34.406 2014-04-14 11:54:00,41.056000000000004 2014-04-14 11:59:00,32.618 2014-04-14 12:04:00,32.008 2014-04-14 12:09:00,35.39 2014-04-14 12:14:00,33.094 2014-04-14 12:19:00,37.488 2014-04-14 12:24:00,31.98 2014-04-14 12:29:00,34.882 2014-04-14 12:34:00,35.846 2014-04-14 12:39:00,31.614 2014-04-14 12:44:00,31.901999999999997 2014-04-14 12:49:00,36.15 2014-04-14 12:54:00,34.554 2014-04-14 12:59:00,33.262 2014-04-14 13:04:00,33.21 2014-04-14 13:09:00,34.578 2014-04-14 13:14:00,36.292 2014-04-14 13:19:00,32.724000000000004 2014-04-14 13:24:00,32.408 2014-04-14 13:29:00,33.034 2014-04-14 13:34:00,34.354 2014-04-14 13:39:00,33.638000000000005 2014-04-14 13:44:00,33.428000000000004 2014-04-14 13:49:00,33.192 2014-04-14 13:54:00,38.204 2014-04-14 13:59:00,29.682 2014-04-14 14:04:00,33.662 2014-04-14 14:09:00,36.76 2014-04-14 14:14:00,33.616 2014-04-14 14:19:00,35.088 2014-04-14 14:24:00,32.821999999999996 2014-04-14 14:29:00,33.654 2014-04-14 14:34:00,33.052 2014-04-14 14:39:00,35.566 2014-04-14 14:44:00,32.961999999999996 2014-04-14 14:49:00,31.744 2014-04-14 14:54:00,35.208 2014-04-14 14:59:00,33.216 2014-04-14 15:04:00,33.548 2014-04-14 15:09:00,40.058 2014-04-14 15:14:00,30.07 2014-04-14 15:19:00,35.6 2014-04-14 15:24:00,35.868 2014-04-14 15:29:00,31.754 2014-04-14 15:34:00,33.722 2014-04-14 15:39:00,34.062 2014-04-14 15:44:00,35.47 2014-04-14 15:49:00,31.244 2014-04-14 15:54:00,35.728 2014-04-14 15:59:00,34.46 2014-04-14 16:04:00,34.342 2014-04-14 16:09:00,33.052 2014-04-14 16:14:00,32.982 2014-04-14 16:19:00,32.57 2014-04-14 16:24:00,34.742 2014-04-14 16:29:00,30.986 2014-04-14 16:34:00,32.806 2014-04-14 16:39:00,33.156 2014-04-14 16:44:00,33.004 2014-04-14 16:49:00,32.408 2014-04-14 16:54:00,35.61 2014-04-14 16:59:00,33.544000000000004 2014-04-14 17:04:00,31.01 2014-04-14 17:09:00,34.146 2014-04-14 17:14:00,35.422 2014-04-14 17:19:00,30.234 2014-04-14 17:24:00,36.22 2014-04-14 17:29:00,32.7 2014-04-14 17:34:00,35.211999999999996 2014-04-14 17:39:00,31.362 2014-04-14 17:44:00,34.32 2014-04-14 17:49:00,31.502 2014-04-14 17:54:00,34.508 2014-04-14 17:59:00,32.63 2014-04-14 18:04:00,32.94 2014-04-14 18:09:00,35.728 2014-04-14 18:14:00,39.954 2014-04-14 18:19:00,30.488000000000003 2014-04-14 18:24:00,32.63 2014-04-14 18:29:00,32.738 2014-04-14 18:34:00,33.78 2014-04-14 18:39:00,32.924 2014-04-14 18:44:00,35.188 2014-04-14 18:49:00,34.902 2014-04-14 18:54:00,32.418 2014-04-14 18:59:00,32.794000000000004 2014-04-14 19:04:00,34.248000000000005 2014-04-14 19:09:00,33.028 2014-04-14 19:14:00,35.352 2014-04-14 19:19:00,32.602 2014-04-14 19:24:00,34.812 2014-04-14 19:29:00,30.564 2014-04-14 19:34:00,33.274 2014-04-14 19:39:00,33.461999999999996 2014-04-14 19:44:00,33.028 2014-04-14 19:49:00,32.668 2014-04-14 19:54:00,34.316 2014-04-14 19:59:00,33.004 2014-04-14 20:04:00,36.902 2014-04-14 20:09:00,32.544000000000004 2014-04-14 20:14:00,30.658 2014-04-14 20:19:00,32.84 2014-04-14 20:24:00,35.352 2014-04-14 20:29:00,34.436 2014-04-14 20:34:00,32.934 2014-04-14 20:39:00,33.076 2014-04-14 20:44:00,32.622 2014-04-14 20:49:00,35.986 2014-04-14 20:54:00,31.198 2014-04-14 20:59:00,35.164 2014-04-14 21:04:00,30.372 2014-04-14 21:09:00,37.018 2014-04-14 21:14:00,32.91 2014-04-14 21:19:00,32.606 2014-04-14 21:24:00,34.554 2014-04-14 21:29:00,32.016 2014-04-14 21:34:00,31.854 2014-04-14 21:39:00,33.944 2014-04-14 21:44:00,33.132 2014-04-14 21:49:00,32.746 2014-04-14 21:54:00,34.466 2014-04-14 21:59:00,32.806 2014-04-14 22:04:00,33.076 2014-04-14 22:09:00,34.436 2014-04-14 22:14:00,35.306 2014-04-14 22:19:00,32.088 2014-04-14 22:24:00,33.5 2014-04-14 22:29:00,32.814 2014-04-14 22:34:00,33.244 2014-04-14 22:39:00,32.746 2014-04-14 22:44:00,32.802 2014-04-14 22:49:00,32.724000000000004 2014-04-14 22:54:00,34.308 2014-04-14 22:59:00,34.562 2014-04-14 23:04:00,32.376 2014-04-14 23:09:00,35.916 2014-04-14 23:14:00,31.62 2014-04-14 23:19:00,35.262 2014-04-14 23:24:00,34.571999999999996 2014-04-14 23:29:00,33.334 2014-04-14 23:34:00,35.492 2014-04-14 23:39:00,31.76 2014-04-14 23:44:00,52.6125 2014-04-15 00:04:00,55.394 2014-04-15 00:09:00,34.154 2014-04-15 00:14:00,32.254 2014-04-15 00:19:00,33.602 2014-04-15 00:24:00,34.692 2014-04-15 00:29:00,32.09 2014-04-15 00:34:00,31.886 2014-04-15 00:39:00,37.742 2014-04-15 00:44:00,30.908 2014-04-15 00:49:00,88.20200000000001 2014-04-15 00:54:00,99.552 2014-04-15 00:59:00,98.944 2014-04-15 01:04:00,98.816 2014-04-15 01:09:00,98.42399999999999 2014-04-15 01:14:00,98.73 2014-04-15 01:19:00,98.544 2014-04-15 01:24:00,98.49799999999999 2014-04-15 01:29:00,98.238 2014-04-15 01:34:00,98.92 2014-04-15 01:39:00,99.62 2014-04-15 01:44:00,99.39 2014-04-15 01:49:00,99.014 2014-04-15 01:54:00,98.49799999999999 2014-04-15 01:59:00,99.06200000000001 2014-04-15 02:04:00,99.25 2014-04-15 02:09:00,99.52799999999999 2014-04-15 02:14:00,99.226 2014-04-15 02:19:00,99.272 2014-04-15 02:24:00,98.72399999999999 2014-04-15 02:29:00,99.554 2014-04-15 02:34:00,98.706 2014-04-15 02:39:00,99.414 2014-04-15 02:44:00,99.53 2014-04-15 02:49:00,99.20200000000001 2014-04-15 02:54:00,98.91799999999999 2014-04-15 02:59:00,99.436 2014-04-15 03:04:00,99.414 2014-04-15 03:09:00,98.73200000000001 2014-04-15 03:14:00,99.46 2014-04-15 03:19:00,99.52799999999999 2014-04-15 03:24:00,99.57799999999999 2014-04-15 03:29:00,99.434 2014-04-15 03:34:00,98.904 2014-04-15 03:39:00,98.756 2014-04-15 03:44:00,99.088 2014-04-15 03:49:00,99.226 2014-04-15 03:54:00,99.318 2014-04-15 03:59:00,98.99 2014-04-15 04:04:00,99.24799999999999 2014-04-15 04:09:00,99.27 2014-04-15 04:14:00,99.414 2014-04-15 04:19:00,98.49799999999999 2014-04-15 04:24:00,98.896 2014-04-15 04:29:00,99.20200000000001 2014-04-15 04:34:00,99.436 2014-04-15 04:39:00,98.616 2014-04-15 04:44:00,98.63799999999999 2014-04-15 04:49:00,99.38799999999999 2014-04-15 04:54:00,98.428 2014-04-15 04:59:00,99.32 2014-04-15 05:04:00,99.296 2014-04-15 05:09:00,99.366 2014-04-15 05:14:00,99.038 2014-04-15 05:19:00,99.484 2014-04-15 05:24:00,99.67 2014-04-15 05:29:00,99.296 2014-04-15 05:34:00,99.20200000000001 2014-04-15 05:39:00,99.436 2014-04-15 05:44:00,98.896 2014-04-15 05:49:00,99.53399999999999 2014-04-15 05:54:00,99.46 2014-04-15 05:59:00,99.038 2014-04-15 06:04:00,99.038 2014-04-15 06:09:00,99.39200000000001 2014-04-15 06:14:00,99.178 2014-04-15 06:19:00,99.20200000000001 2014-04-15 06:24:00,98.904 2014-04-15 06:29:00,98.85 2014-04-15 06:34:00,99.06200000000001 2014-04-15 06:39:00,98.756 2014-04-15 06:44:00,99.3 2014-04-15 06:49:00,99.25 2014-04-15 06:54:00,99.044 2014-04-15 06:59:00,98.522 2014-04-15 07:04:00,98.706 2014-04-15 07:09:00,99.508 2014-04-15 07:14:00,99.39 2014-04-15 07:19:00,99.414 2014-04-15 07:24:00,99.53 2014-04-15 07:29:00,99.36399999999999 2014-04-15 07:34:00,99.042 2014-04-15 07:39:00,99.27 2014-04-15 07:44:00,99.436 2014-04-15 07:49:00,99.132 2014-04-15 07:54:00,99.32 2014-04-15 07:59:00,99.24799999999999 2014-04-15 08:04:00,99.038 2014-04-15 08:09:00,98.9 2014-04-15 08:14:00,99.508 2014-04-15 08:19:00,99.436 2014-04-15 08:24:00,99.412 2014-04-15 08:29:00,98.522 2014-04-15 08:34:00,99.46 2014-04-15 08:39:00,99.014 2014-04-15 08:44:00,98.45 2014-04-15 08:49:00,99.414 2014-04-15 08:54:00,99.458 2014-04-15 08:59:00,98.806 2014-04-15 09:04:00,98.182 2014-04-15 09:09:00,99.08200000000001 2014-04-15 09:14:00,98.82600000000001 2014-04-15 09:19:00,99.34200000000001 2014-04-15 09:24:00,99.574 2014-04-15 09:29:00,99.18 2014-04-15 09:34:00,99.508 2014-04-15 09:39:00,99.436 2014-04-15 09:44:00,99.67200000000001 2014-04-15 09:49:00,99.316 2014-04-15 09:54:00,98.89399999999999 2014-04-15 09:59:00,99.32 2014-04-15 10:04:00,99.67200000000001 2014-04-15 10:09:00,99.366 2014-04-15 10:14:00,99.27 2014-04-15 10:19:00,99.3 2014-04-15 10:24:00,98.49799999999999 2014-04-15 10:29:00,98.89399999999999 2014-04-15 10:34:00,99.53 2014-04-15 10:39:00,99.39 2014-04-15 10:44:00,98.96799999999999 2014-04-15 10:49:00,99.742 2014-04-15 10:54:00,99.318 2014-04-15 10:59:00,99.508 2014-04-15 11:04:00,98.63799999999999 2014-04-15 11:09:00,99.272 2014-04-15 11:14:00,99.484 2014-04-15 11:19:00,99.57799999999999 2014-04-15 11:24:00,98.82600000000001 2014-04-15 11:29:00,98.426 2014-04-15 11:34:00,98.47399999999999 2014-04-15 11:39:00,99.34200000000001 2014-04-15 11:44:00,99.67200000000001 2014-04-15 11:49:00,99.436 2014-04-15 11:54:00,98.556 2014-04-15 11:59:00,98.38 2014-04-15 12:04:00,99.414 2014-04-15 12:09:00,98.756 2014-04-15 12:14:00,99.46 2014-04-15 12:19:00,99.484 2014-04-15 12:24:00,99.046 2014-04-15 12:29:00,99.272 2014-04-15 12:34:00,98.288 2014-04-15 12:39:00,99.414 2014-04-15 12:44:00,99.554 2014-04-15 12:49:00,99.226 2014-04-15 12:54:00,99.67200000000001 2014-04-15 12:59:00,99.178 2014-04-15 13:04:00,98.97200000000001 2014-04-15 13:09:00,99.598 2014-04-15 13:14:00,98.66799999999999 2014-04-15 13:19:00,99.338 2014-04-15 13:24:00,99.27 2014-04-15 13:29:00,98.92 2014-04-15 13:34:00,99.06200000000001 2014-04-15 13:39:00,99.132 2014-04-15 13:44:00,99.506 2014-04-15 13:49:00,99.414 2014-04-15 13:54:00,99.32 2014-04-15 13:59:00,99.624 2014-04-15 14:04:00,98.802 2014-04-15 14:09:00,99.554 2014-04-15 14:14:00,98.82600000000001 2014-04-15 14:19:00,98.78 2014-04-15 14:24:00,98.964 2014-04-15 14:29:00,99.20200000000001 2014-04-15 14:34:00,98.714 2014-04-15 14:39:00,99.458 2014-04-15 14:44:00,99.104 2014-04-15 14:49:00,98.92 2014-04-15 14:54:00,98.68799999999999 2014-04-15 14:59:00,99.32 2014-04-15 15:04:00,99.11 2014-04-15 15:09:00,98.756 2014-04-15 15:14:00,98.708 2014-04-15 15:19:00,98.92 2014-04-15 15:24:00,99.036 2014-04-15 15:29:00,99.412 2014-04-15 15:34:00,98.874 2014-04-15 15:39:00,99.05799999999999 2014-04-15 15:44:00,99.53 2014-04-15 15:49:00,99.25200000000001 2014-04-15 15:54:00,99.272 2014-04-15 15:59:00,99.154 2014-04-15 16:04:00,99.274 2014-04-15 16:09:00,98.944 2014-04-15 16:14:00,98.522 2014-04-15 16:19:00,99.39 2014-04-15 16:24:00,99.508 2014-04-15 16:29:00,98.96799999999999 2014-04-15 16:34:00,99.71799999999999 2014-04-15 16:39:00,99.20200000000001 2014-04-15 16:44:00,99.39 2014-04-15 16:49:00,98.686 2014-04-15 16:54:00,98.63799999999999 2014-04-15 16:59:00,98.64 2014-04-15 17:04:00,99.24799999999999 2014-04-15 17:09:00,99.226 2014-04-15 17:14:00,99.24799999999999 2014-04-15 17:19:00,99.366 2014-04-15 17:24:00,99.484 2014-04-15 17:29:00,99.39 2014-04-15 17:34:00,99.32 2014-04-15 17:39:00,99.436 2014-04-15 17:44:00,99.27600000000001 2014-04-15 17:49:00,98.99 2014-04-15 17:54:00,98.92200000000001 2014-04-15 17:59:00,99.24799999999999 2014-04-15 18:04:00,99.226 2014-04-15 18:09:00,98.874 2014-04-15 18:14:00,99.624 2014-04-15 18:19:00,98.75399999999999 2014-04-15 18:24:00,99.29799999999999 2014-04-15 18:29:00,99.20200000000001 2014-04-15 18:34:00,99.414 2014-04-15 18:39:00,99.20200000000001 2014-04-15 18:44:00,99.39 2014-04-15 18:49:00,98.82600000000001 2014-04-15 18:54:00,99.04 2014-04-15 18:59:00,98.99 2014-04-15 19:04:00,99.366 2014-04-15 19:09:00,99.38600000000001 2014-04-15 19:14:00,98.38 2014-04-15 19:19:00,99.038 2014-04-15 19:24:00,99.34200000000001 2014-04-15 19:29:00,99.436 2014-04-15 19:34:00,99.366 2014-04-15 19:39:00,99.154 2014-04-15 19:44:00,99.10799999999999 2014-04-15 19:49:00,99.084 2014-04-15 19:54:00,99.154 2014-04-15 19:59:00,98.92 2014-04-15 20:04:00,98.78 2014-04-15 20:09:00,98.802 2014-04-15 20:14:00,99.39 2014-04-15 20:19:00,99.272 2014-04-15 20:24:00,99.46 2014-04-15 20:29:00,99.178 2014-04-15 20:34:00,98.662 2014-04-15 20:39:00,99.272 2014-04-15 20:44:00,99.20200000000001 2014-04-15 20:49:00,99.39 2014-04-15 20:54:00,98.706 2014-04-15 20:59:00,99.24600000000001 2014-04-15 21:04:00,99.132 2014-04-15 21:09:00,98.944 2014-04-15 21:14:00,99.436 2014-04-15 21:19:00,98.648 2014-04-15 21:24:00,98.756 2014-04-15 21:29:00,99.204 2014-04-15 21:34:00,99.132 2014-04-15 21:39:00,99.296 2014-04-15 21:44:00,99.178 2014-04-15 21:49:00,99.508 2014-04-15 21:54:00,98.874 2014-04-15 21:59:00,98.99 2014-04-15 22:04:00,99.10799999999999 2014-04-15 22:09:00,99.152 2014-04-15 22:14:00,99.13 2014-04-15 22:19:00,99.13 2014-04-15 22:24:00,99.554 2014-04-15 22:29:00,98.286 2014-04-15 22:34:00,98.286 2014-04-15 22:39:00,99.624 2014-04-15 22:44:00,98.848 2014-04-15 22:49:00,98.88600000000001 2014-04-15 22:54:00,98.626 2014-04-15 22:59:00,98.82600000000001 2014-04-15 23:04:00,98.334 2014-04-15 23:09:00,99.038 2014-04-15 23:14:00,99.226 2014-04-15 23:19:00,99.436 2014-04-15 23:24:00,99.32 2014-04-15 23:29:00,99.50399999999999 2014-04-15 23:34:00,99.624 2014-04-15 23:39:00,98.756 2014-04-15 23:44:00,99.32 2014-04-15 23:49:00,99.414 2014-04-15 23:54:00,98.544 2014-04-15 23:59:00,99.67200000000001 2014-04-16 00:04:00,99.11200000000001 2014-04-16 00:09:00,97.98200000000001 2014-04-16 00:14:00,98.522 2014-04-16 00:19:00,98.31 2014-04-16 00:24:00,98.334 2014-04-16 00:29:00,99.53 2014-04-16 00:34:00,99.43799999999999 2014-04-16 00:39:00,99.20200000000001 2014-04-16 00:44:00,98.59200000000001 2014-04-16 00:49:00,99.088 2014-04-16 00:54:00,99.32 2014-04-16 00:59:00,99.156 2014-04-16 01:04:00,99.24799999999999 2014-04-16 01:09:00,99.57799999999999 2014-04-16 01:14:00,98.616 2014-04-16 01:19:00,97.72399999999999 2014-04-16 01:24:00,98.78 2014-04-16 01:29:00,98.404 2014-04-16 01:34:00,99.6 2014-04-16 01:39:00,99.036 2014-04-16 01:44:00,99.67200000000001 2014-04-16 01:49:00,99.624 2014-04-16 01:54:00,99.39 2014-04-16 01:59:00,99.014 2014-04-16 02:04:00,99.178 2014-04-16 02:09:00,99.176 2014-04-16 02:14:00,99.038 2014-04-16 02:19:00,98.73200000000001 2014-04-16 02:24:00,98.6 2014-04-16 02:29:00,99.084 2014-04-16 02:34:00,99.36399999999999 2014-04-16 02:39:00,99.24799999999999 2014-04-16 02:44:00,99.32 2014-04-16 02:49:00,99.486 2014-04-16 02:54:00,98.756 2014-04-16 02:59:00,98.99 2014-04-16 03:04:00,99.552 2014-04-16 03:09:00,99.014 2014-04-16 03:14:00,98.544 2014-04-16 03:19:00,99.53 2014-04-16 03:24:00,99.296 2014-04-16 03:29:00,98.92 2014-04-16 03:34:00,99.206 2014-04-16 03:39:00,98.896 2014-04-16 03:44:00,98.772 2014-04-16 03:49:00,99.41 2014-04-16 03:54:00,99.39 2014-04-16 03:59:00,98.896 2014-04-16 04:04:00,99.014 2014-04-16 04:09:00,99.34200000000001 2014-04-16 04:14:00,99.10600000000001 2014-04-16 04:19:00,99.162 2014-04-16 04:24:00,99.10799999999999 2014-04-16 04:29:00,99.132 2014-04-16 04:34:00,98.85 2014-04-16 04:39:00,98.73200000000001 2014-04-16 04:44:00,99.014 2014-04-16 04:49:00,98.92399999999999 2014-04-16 04:54:00,99.038 2014-04-16 04:59:00,99.038 2014-04-16 05:04:00,98.82600000000001 2014-04-16 05:09:00,99.274 2014-04-16 05:14:00,98.944 2014-04-16 05:19:00,98.992 2014-04-16 05:24:00,99.346 2014-04-16 05:29:00,98.726 2014-04-16 05:34:00,99.34200000000001 2014-04-16 05:39:00,98.286 2014-04-16 05:44:00,98.96799999999999 2014-04-16 05:49:00,98.35600000000001 2014-04-16 05:54:00,99.228 2014-04-16 05:59:00,99.436 2014-04-16 06:04:00,99.36 2014-04-16 06:09:00,99.39 2014-04-16 06:14:00,98.588 2014-04-16 06:19:00,99.06200000000001 2014-04-16 06:24:00,99.414 2014-04-16 06:29:00,99.226 2014-04-16 06:34:00,98.81 2014-04-16 06:39:00,99.20200000000001 2014-04-16 06:44:00,99.20200000000001 2014-04-16 06:49:00,99.24799999999999 2014-04-16 06:54:00,98.896 2014-04-16 06:59:00,98.662 2014-04-16 07:04:00,99.038 2014-04-16 07:09:00,99.24799999999999 2014-04-16 07:14:00,98.758 2014-04-16 07:19:00,98.334 2014-04-16 07:24:00,98.20200000000001 2014-04-16 07:29:00,99.01799999999999 2014-04-16 07:34:00,99.084 2014-04-16 07:39:00,99.39 2014-04-16 07:44:00,98.546 2014-04-16 07:49:00,99.03399999999999 2014-04-16 07:54:00,99.304 2014-04-16 07:59:00,98.662 2014-04-16 08:04:00,99.038 2014-04-16 08:09:00,99.296 2014-04-16 08:14:00,98.59200000000001 2014-04-16 08:19:00,98.31 2014-04-16 08:24:00,98.896 2014-04-16 08:29:00,98.63799999999999 2014-04-16 08:34:00,99.316 2014-04-16 08:39:00,99.22399999999999 2014-04-16 08:44:00,98.896 2014-04-16 08:49:00,99.366 2014-04-16 08:54:00,99.226 2014-04-16 08:59:00,99.24799999999999 2014-04-16 09:04:00,97.8 2014-04-16 09:09:00,99.06200000000001 2014-04-16 09:14:00,99.344 2014-04-16 09:19:00,98.85 2014-04-16 09:24:00,99.132 2014-04-16 09:29:00,99.20200000000001 2014-04-16 09:34:00,99.412 2014-04-16 09:39:00,99.2 2014-04-16 09:44:00,99.694 2014-04-16 09:49:00,99.06200000000001 2014-04-16 09:54:00,99.436 2014-04-16 09:59:00,98.47399999999999 2014-04-16 10:04:00,98.764 2014-04-16 10:09:00,99.014 2014-04-16 10:14:00,98.96799999999999 2014-04-16 10:19:00,99.04 2014-04-16 10:24:00,98.052 2014-04-16 10:29:00,99.05799999999999 2014-04-16 10:34:00,98.802 2014-04-16 10:39:00,98.59200000000001 2014-04-16 10:44:00,97.27600000000001 2014-04-16 10:49:00,98.286 2014-04-16 10:54:00,99.27 2014-04-16 10:59:00,98.788 2014-04-16 11:04:00,97.98200000000001 2014-04-16 11:09:00,98.83 2014-04-16 11:14:00,98.49600000000001 2014-04-16 11:19:00,98.712 2014-04-16 11:24:00,99.46 2014-04-16 11:29:00,98.686 2014-04-16 11:34:00,98.664 2014-04-16 11:39:00,99.296 2014-04-16 11:44:00,98.428 2014-04-16 11:49:00,99.296 2014-04-16 11:54:00,99.154 2014-04-16 11:59:00,99.038 2014-04-16 12:04:00,99.34200000000001 2014-04-16 12:09:00,99.084 2014-04-16 12:14:00,99.014 2014-04-16 12:19:00,99.366 2014-04-16 12:24:00,98.82600000000001 2014-04-16 12:29:00,98.42399999999999 2014-04-16 12:34:00,98.69 2014-04-16 12:39:00,99.132 2014-04-16 12:44:00,98.96799999999999 2014-04-16 12:49:00,98.944 2014-04-16 12:54:00,98.92 2014-04-16 12:59:00,99.484 2014-04-16 13:04:00,99.366 2014-04-16 13:09:00,98.756 2014-04-16 13:14:00,98.756 2014-04-16 13:19:00,99.04 2014-04-16 13:24:00,98.38 2014-04-16 13:29:00,99.226 2014-04-16 13:34:00,98.78 2014-04-16 13:39:00,98.89399999999999 2014-04-16 13:44:00,98.74 2014-04-16 13:49:00,98.47399999999999 2014-04-16 13:54:00,98.572 2014-04-16 13:59:00,99.084 2014-04-16 14:04:00,97.488 2014-04-16 14:09:00,99.226 2014-04-16 14:14:00,98.99 2014-04-16 14:19:00,99.296 2014-04-16 14:24:00,99.06200000000001 2014-04-16 14:29:00,99.434 2014-04-16 14:34:00,99.132 2014-04-16 14:39:00,99.24799999999999 2014-04-16 14:44:00,98.552 2014-04-16 14:49:00,99.22200000000001 ================================================ FILE: workspace/anomaly_detector/datasets/selected/level_change/grok_asg_anomaly.csv ================================================ timestamp,value 2014-01-16 00:00:00,33.5573 2014-01-16 00:05:00,33.446 2014-01-16 00:10:00,33.4447 2014-01-16 00:15:00,33.3333 2014-01-16 00:20:00,33.4447 2014-01-16 00:25:00,33.4447 2014-01-16 00:30:00,33.446 2014-01-16 00:35:00,33.4427 2014-01-16 00:40:00,33.3333 2014-01-16 00:45:00,33.554 2014-01-16 00:50:00,33.3333 2014-01-16 00:55:00,33.4427 2014-01-16 01:00:00,33.4427 2014-01-16 01:05:00,33.5573 2014-01-16 01:10:00,33.3333 2014-01-16 01:15:00,33.4447 2014-01-16 01:20:00,33.446 2014-01-16 01:25:00,33.3333 2014-01-16 01:30:00,33.5553 2014-01-16 01:35:00,33.3333 2014-01-16 01:40:00,33.6647 2014-01-16 01:45:00,33.3333 2014-01-16 01:50:00,33.3333 2014-01-16 01:55:00,33.5587 2014-01-16 02:00:00,33.5587 2014-01-16 02:05:00,33.3333 2014-01-16 02:10:00,33.4447 2014-01-16 02:15:00,33.4427 2014-01-16 02:20:00,33.3333 2014-01-16 02:25:00,33.554 2014-01-16 02:30:00,33.3333 2014-01-16 02:35:00,33.4447 2014-01-16 02:40:00,33.4447 2014-01-16 02:45:00,33.446 2014-01-16 02:50:00,33.4427 2014-01-16 02:55:00,33.3333 2014-01-16 03:00:00,33.5587 2014-01-16 03:05:00,35.222 2014-01-16 03:10:00,33.3333 2014-01-16 03:15:00,33.3333 2014-01-16 03:20:00,33.5553 2014-01-16 03:25:00,33.3333 2014-01-16 03:30:00,35.2507 2014-01-16 03:35:00,33.3333 2014-01-16 03:40:00,33.4447 2014-01-16 03:45:00,33.4447 2014-01-16 03:50:00,33.4447 2014-01-16 03:55:00,33.4447 2014-01-16 04:00:00,33.554 2014-01-16 04:05:00,33.3333 2014-01-16 04:10:00,33.4427 2014-01-16 04:15:00,33.4447 2014-01-16 04:20:00,33.5573 2014-01-16 04:25:00,33.3333 2014-01-16 04:30:00,33.4427 2014-01-16 04:35:00,33.4447 2014-01-16 04:40:00,33.4427 2014-01-16 04:45:00,33.446 2014-01-16 04:50:00,33.3333 2014-01-16 04:55:00,33.4427 2014-01-16 05:00:00,33.4427 2014-01-16 05:05:00,33.5573 2014-01-16 05:10:00,33.3333 2014-01-16 05:15:00,33.446 2014-01-16 05:20:00,33.446 2014-01-16 05:25:00,33.4447 2014-01-16 05:30:00,33.446 2014-01-16 05:35:00,33.3333 2014-01-16 05:40:00,33.554 2014-01-16 05:45:00,33.3333 2014-01-16 05:50:00,33.5553 2014-01-16 05:55:00,33.3333 2014-01-16 06:00:00,33.554 2014-01-16 06:05:00,33.3333 2014-01-16 06:10:00,33.5553 2014-01-16 06:15:00,33.3333 2014-01-16 06:20:00,33.3333 2014-01-16 06:25:00,33.5553 2014-01-16 06:30:00,33.3333 2014-01-16 06:35:00,33.4447 2014-01-16 06:40:00,33.4427 2014-01-16 06:45:00,33.4447 2014-01-16 06:50:00,33.446 2014-01-16 06:55:00,33.3333 2014-01-16 07:00:00,33.556 2014-01-16 07:05:00,33.446 2014-01-16 07:10:00,33.4447 2014-01-16 07:15:00,33.3333 2014-01-16 07:20:00,33.446 2014-01-16 07:25:00,33.4427 2014-01-16 07:30:00,33.4447 2014-01-16 07:35:00,33.446 2014-01-16 07:40:00,33.446 2014-01-16 07:45:00,33.3333 2014-01-16 07:50:00,33.554 2014-01-16 07:55:00,33.3333 2014-01-16 08:00:00,33.5553 2014-01-16 08:05:00,33.4447 2014-01-16 08:10:00,33.5573 2014-01-16 08:15:00,33.3333 2014-01-16 08:20:00,33.4447 2014-01-16 08:25:00,33.4427 2014-01-16 08:30:00,33.3333 2014-01-16 08:35:00,33.556 2014-01-16 08:40:00,33.3333 2014-01-16 08:45:00,33.446 2014-01-16 08:50:00,33.446 2014-01-16 08:55:00,33.3333 2014-01-16 09:00:00,33.5573 2014-01-16 09:05:00,33.446 2014-01-16 09:10:00,33.4427 2014-01-16 09:15:00,33.3333 2014-01-16 09:20:00,33.5587 2014-01-16 09:25:00,33.3333 2014-01-16 09:30:00,33.556 2014-01-16 09:35:00,33.3333 2014-01-16 09:40:00,33.3333 2014-01-16 09:45:00,33.5573 2014-01-16 09:50:00,33.3333 2014-01-16 09:55:00,33.554 2014-01-16 10:00:00,33.3333 2014-01-16 10:05:00,33.556 2014-01-16 10:10:00,33.3333 2014-01-16 10:15:00,33.554 2014-01-16 10:20:00,33.3333 2014-01-16 10:25:00,33.3333 2014-01-16 10:30:00,33.5587 2014-01-16 10:35:00,33.3333 2014-01-16 10:40:00,33.556 2014-01-16 10:45:00,33.3333 2014-01-16 10:50:00,33.3333 2014-01-16 10:55:00,33.672 2014-01-16 11:00:00,33.554 2014-01-16 11:05:00,33.3333 2014-01-16 11:10:00,33.4427 2014-01-16 11:15:00,34.7767 2014-01-16 11:20:00,34.452 2014-01-16 11:25:00,34.2133 2014-01-16 11:30:00,33.4427 2014-01-16 11:35:00,33.4427 2014-01-16 11:40:00,33.3333 2014-01-16 11:45:00,33.4447 2014-01-16 11:50:00,33.4427 2014-01-16 11:55:00,33.4447 2014-01-16 12:00:00,33.552 2014-01-16 12:05:00,33.4447 2014-01-16 12:10:00,33.3333 2014-01-16 12:15:00,33.552 2014-01-16 12:20:00,33.3333 2014-01-16 12:25:00,33.5573 2014-01-16 12:30:00,33.3333 2014-01-16 12:35:00,33.3333 2014-01-16 12:40:00,33.554 2014-01-16 12:45:00,33.3333 2014-01-16 12:50:00,33.554 2014-01-16 12:55:00,33.3333 2014-01-16 13:00:00,33.552 2014-01-16 13:05:00,33.3333 2014-01-16 13:10:00,33.552 2014-01-16 13:15:00,33.3333 2014-01-16 13:20:00,33.4427 2014-01-16 13:25:00,33.4447 2014-01-16 13:30:00,33.446 2014-01-16 13:35:00,33.4427 2014-01-16 13:40:00,33.3333 2014-01-16 13:45:00,33.4447 2014-01-16 13:50:00,33.446 2014-01-16 13:55:00,33.4427 2014-01-16 14:00:00,33.4447 2014-01-16 14:05:00,33.4447 2014-01-16 14:10:00,33.4427 2014-01-16 14:15:00,33.8887 2014-01-16 14:20:00,33.8833 2014-01-16 14:25:00,33.3333 2014-01-16 14:30:00,33.5573 2014-01-16 14:35:00,33.3333 2014-01-16 14:40:00,33.4447 2014-01-16 14:45:00,33.446 2014-01-16 14:50:00,33.446 2014-01-16 14:55:00,33.446 2014-01-16 15:00:00,33.4427 2014-01-16 15:05:00,33.4427 2014-01-16 15:10:00,33.446 2014-01-16 15:15:00,33.3333 2014-01-16 15:20:00,33.4447 2014-01-16 15:25:00,33.4427 2014-01-16 15:30:00,33.446 2014-01-16 15:35:00,33.446 2014-01-16 15:40:00,33.3333 2014-01-16 15:45:00,33.5573 2014-01-16 15:50:00,33.3333 2014-01-16 15:55:00,33.446 2014-01-16 16:00:00,33.446 2014-01-16 16:05:00,33.446 2014-01-16 16:10:00,33.4427 2014-01-16 16:15:00,33.446 2014-01-16 16:20:00,33.4447 2014-01-16 16:25:00,33.3333 2014-01-16 16:30:00,33.5587 2014-01-16 16:35:00,33.3333 2014-01-16 16:40:00,33.4447 2014-01-16 16:45:00,33.4427 2014-01-16 16:50:00,33.3333 2014-01-16 16:55:00,33.552 2014-01-16 17:00:00,33.4447 2014-01-16 17:05:00,33.4427 2014-01-16 17:10:00,33.3333 2014-01-16 17:15:00,33.5573 2014-01-16 17:20:00,33.3333 2014-01-16 17:25:00,33.556 2014-01-16 17:30:00,33.3333 2014-01-16 17:35:00,33.3333 2014-01-16 17:40:00,33.668 2014-01-16 17:45:00,33.3333 2014-01-16 17:50:00,33.5553 2014-01-16 17:55:00,33.3333 2014-01-16 18:00:00,33.552 2014-01-16 18:05:00,33.3333 2014-01-16 18:10:00,33.556 2014-01-16 18:15:00,33.3333 2014-01-16 18:20:00,33.556 2014-01-16 18:25:00,33.3333 2014-01-16 18:30:00,33.4447 2014-01-16 18:35:00,33.4427 2014-01-16 18:40:00,9.090910000000001 2014-01-16 18:45:00,28.8093 2014-01-16 18:50:00,33.3333 2014-01-16 18:55:00,33.4427 2014-01-16 19:00:00,35.3187 2014-01-16 19:05:00,34.3413 2014-01-16 19:10:00,35.1113 2014-01-16 19:15:00,33.446 2014-01-16 19:20:00,33.446 2014-01-16 19:25:00,33.3333 2014-01-16 19:30:00,33.5553 2014-01-16 19:35:00,33.3333 2014-01-16 19:40:00,33.4427 2014-01-16 19:45:00,33.4447 2014-01-16 19:50:00,33.4427 2014-01-16 19:55:00,33.4447 2014-01-16 20:00:00,33.552 2014-01-16 20:05:00,33.3333 2014-01-16 20:10:00,33.4447 2014-01-16 20:15:00,33.4447 2014-01-16 20:20:00,33.446 2014-01-16 20:25:00,34.2313 2014-01-16 20:30:00,33.5553 2014-01-16 20:35:00,33.3333 2014-01-16 20:40:00,33.4447 2014-01-16 20:45:00,33.4427 2014-01-16 20:50:00,33.4447 2014-01-16 20:55:00,33.4447 2014-01-16 21:00:00,33.4447 2014-01-16 21:05:00,33.4447 2014-01-16 21:10:00,33.4427 2014-01-16 21:15:00,33.4427 2014-01-16 21:20:00,33.3333 2014-01-16 21:25:00,33.4427 2014-01-16 21:30:00,33.4427 2014-01-16 21:35:00,33.4427 2014-01-16 21:40:00,33.4447 2014-01-16 21:45:00,33.3333 2014-01-16 21:50:00,33.554 2014-01-16 21:55:00,33.3333 2014-01-16 22:00:00,33.5573 2014-01-16 22:05:00,33.3333 2014-01-16 22:10:00,33.5553 2014-01-16 22:15:00,33.3333 2014-01-16 22:20:00,33.4427 2014-01-16 22:25:00,33.4427 2014-01-16 22:30:00,33.3333 2014-01-16 22:35:00,33.5573 2014-01-16 22:40:00,33.446 2014-01-16 22:45:00,33.4447 2014-01-16 22:50:00,33.446 2014-01-16 22:55:00,33.3333 2014-01-16 23:00:00,33.5587 2014-01-16 23:05:00,33.4447 2014-01-16 23:10:00,33.4447 2014-01-16 23:15:00,33.4427 2014-01-16 23:20:00,33.446 2014-01-16 23:25:00,33.3333 2014-01-16 23:30:00,33.554 2014-01-16 23:35:00,33.3333 2014-01-16 23:40:00,35.6707 2014-01-16 23:45:00,33.4427 2014-01-16 23:50:00,33.4447 2014-01-16 23:55:00,33.446 2014-01-17 00:00:00,33.552 2014-01-17 00:05:00,33.3333 2014-01-17 00:10:00,33.554 2014-01-17 00:15:00,33.3333 2014-01-17 00:20:00,33.4447 2014-01-17 00:25:00,33.446 2014-01-17 00:30:00,33.3333 2014-01-17 00:35:00,33.556 2014-01-17 00:40:00,33.3333 2014-01-17 00:45:00,33.5573 2014-01-17 00:50:00,33.3333 2014-01-17 00:55:00,33.3333 2014-01-17 01:00:00,33.5573 2014-01-17 01:05:00,33.554 2014-01-17 01:10:00,33.3333 2014-01-17 01:15:00,33.5553 2014-01-17 01:20:00,33.3333 2014-01-17 01:25:00,33.3333 2014-01-17 01:30:00,33.554 2014-01-17 01:35:00,33.3333 2014-01-17 01:40:00,34.124 2014-01-17 01:45:00,37.664 2014-01-17 01:50:00,37.8887 2014-01-17 01:55:00,37.6533 2014-01-17 02:00:00,34.3427 2014-01-17 02:05:00,33.3333 2014-01-17 02:10:00,33.556 2014-01-17 02:15:00,33.3333 2014-01-17 02:20:00,37.6687 2014-01-17 02:25:00,38.5593 2014-01-17 02:30:00,38.328 2014-01-17 02:35:00,33.6647 2014-01-17 02:40:00,33.3333 2014-01-17 02:45:00,33.4427 2014-01-17 02:50:00,33.446 2014-01-17 02:55:00,33.4447 2014-01-17 03:00:00,33.4447 2014-01-17 03:05:00,35.588 2014-01-17 03:10:00,33.3333 2014-01-17 03:15:00,33.554 2014-01-17 03:20:00,33.3333 2014-01-17 03:25:00,35.3333 2014-01-17 03:30:00,33.5553 2014-01-17 03:35:00,33.3333 2014-01-17 03:40:00,33.554 2014-01-17 03:45:00,33.3333 2014-01-17 03:50:00,33.556 2014-01-17 03:55:00,33.4447 2014-01-17 04:00:00,33.5573 2014-01-17 04:05:00,33.3333 2014-01-17 04:10:00,33.446 2014-01-17 04:15:00,33.446 2014-01-17 04:20:00,33.3333 2014-01-17 04:25:00,33.4447 2014-01-17 04:30:00,33.446 2014-01-17 04:35:00,33.4447 2014-01-17 04:40:00,33.4447 2014-01-17 04:45:00,33.446 2014-01-17 04:50:00,33.3333 2014-01-17 04:55:00,33.4447 2014-01-17 05:00:00,33.554 2014-01-17 05:05:00,33.446 2014-01-17 05:10:00,33.3333 2014-01-17 05:15:00,33.446 2014-01-17 05:20:00,33.4427 2014-01-17 05:25:00,33.4447 2014-01-17 05:30:00,33.446 2014-01-17 05:35:00,33.3333 2014-01-17 05:40:00,33.554 2014-01-17 05:45:00,33.3333 2014-01-17 05:50:00,33.4427 2014-01-17 05:55:00,33.4447 2014-01-17 06:00:00,33.5573 2014-01-17 06:05:00,33.3333 2014-01-17 06:10:00,33.4427 2014-01-17 06:15:00,33.4447 2014-01-17 06:20:00,33.3333 2014-01-17 06:25:00,33.556 2014-01-17 06:30:00,33.3333 2014-01-17 06:35:00,33.4447 2014-01-17 06:40:00,33.4447 2014-01-17 06:45:00,33.3333 2014-01-17 06:50:00,33.556 2014-01-17 06:55:00,33.3333 2014-01-17 07:00:00,33.554 2014-01-17 07:05:00,33.3333 2014-01-17 07:10:00,33.554 2014-01-17 07:15:00,33.3333 2014-01-17 07:20:00,33.4427 2014-01-17 07:25:00,33.446 2014-01-17 07:30:00,33.3333 2014-01-17 07:35:00,33.5573 2014-01-17 07:40:00,33.4427 2014-01-17 07:45:00,33.556 2014-01-17 07:50:00,33.3333 2014-01-17 07:55:00,33.3333 2014-01-17 08:00:00,33.5573 2014-01-17 08:05:00,33.556 2014-01-17 08:10:00,33.3333 2014-01-17 08:15:00,33.554 2014-01-17 08:20:00,33.3333 2014-01-17 08:25:00,33.3333 2014-01-17 08:30:00,33.554 2014-01-17 08:35:00,33.3333 2014-01-17 08:40:00,33.5553 2014-01-17 08:45:00,33.3333 2014-01-17 08:50:00,33.4427 2014-01-17 08:55:00,33.4427 2014-01-17 09:00:00,33.4447 2014-01-17 09:05:00,33.446 2014-01-17 09:10:00,33.4447 2014-01-17 09:15:00,33.446 2014-01-17 09:20:00,33.446 2014-01-17 09:25:00,33.3333 2014-01-17 09:30:00,33.446 2014-01-17 09:35:00,33.4427 2014-01-17 09:40:00,33.4447 2014-01-17 09:45:00,33.4447 2014-01-17 09:50:00,33.4447 2014-01-17 09:55:00,33.4427 2014-01-17 10:00:00,33.4447 2014-01-17 10:05:00,33.4427 2014-01-17 10:10:00,33.4447 2014-01-17 10:15:00,33.4427 2014-01-17 10:20:00,33.3333 2014-01-17 10:25:00,33.4427 2014-01-17 10:30:00,33.4447 2014-01-17 10:35:00,33.4447 2014-01-17 10:40:00,33.4447 2014-01-17 10:45:00,33.4447 2014-01-17 10:50:00,33.4427 2014-01-17 10:55:00,33.3333 2014-01-17 11:00:00,33.5573 2014-01-17 11:05:00,33.4447 2014-01-17 11:10:00,33.446 2014-01-17 11:15:00,33.3333 2014-01-17 11:20:00,33.4447 2014-01-17 11:25:00,33.4447 2014-01-17 11:30:00,33.4427 2014-01-17 11:35:00,33.446 2014-01-17 11:40:00,33.3333 2014-01-17 11:45:00,33.556 2014-01-17 11:50:00,33.3333 2014-01-17 11:55:00,33.556 2014-01-17 12:00:00,33.4447 2014-01-17 12:05:00,33.4447 2014-01-17 12:10:00,33.446 2014-01-17 12:15:00,33.4427 2014-01-17 12:20:00,33.3333 2014-01-17 12:25:00,33.4427 2014-01-17 12:30:00,33.4427 2014-01-17 12:35:00,33.4427 2014-01-17 12:40:00,33.4427 2014-01-17 12:45:00,33.3333 2014-01-17 12:50:00,33.552 2014-01-17 12:55:00,33.3333 2014-01-17 13:00:00,33.5553 2014-01-17 13:05:00,33.4427 2014-01-17 13:10:00,33.3333 2014-01-17 13:15:00,33.5553 2014-01-17 13:20:00,33.3333 2014-01-17 13:25:00,35.6633 2014-01-17 13:30:00,33.4447 2014-01-17 13:35:00,33.4427 2014-01-17 13:40:00,33.446 2014-01-17 13:45:00,33.4447 2014-01-17 13:50:00,33.3333 2014-01-17 13:55:00,33.4447 2014-01-17 14:00:00,33.556 2014-01-17 14:05:00,33.446 2014-01-17 14:10:00,33.3333 2014-01-17 14:15:00,33.4447 2014-01-17 14:20:00,33.4447 2014-01-17 14:25:00,33.446 2014-01-17 14:30:00,33.4447 2014-01-17 14:35:00,33.3333 2014-01-17 14:40:00,33.5573 2014-01-17 14:45:00,33.3333 2014-01-17 14:50:00,33.4447 2014-01-17 14:55:00,33.4447 2014-01-17 15:00:00,33.554 2014-01-17 15:05:00,33.3333 2014-01-17 15:10:00,33.4427 2014-01-17 15:15:00,33.4427 2014-01-17 15:20:00,33.4427 2014-01-17 15:25:00,33.4427 2014-01-17 15:30:00,33.4447 2014-01-17 15:35:00,33.5553 2014-01-17 15:40:00,33.3333 2014-01-17 15:45:00,33.4447 2014-01-17 15:50:00,33.4447 2014-01-17 15:55:00,33.446 2014-01-17 16:00:00,33.4427 2014-01-17 16:05:00,33.556 2014-01-17 16:10:00,33.3333 2014-01-17 16:15:00,33.556 2014-01-17 16:20:00,33.3333 2014-01-17 16:25:00,33.3333 2014-01-17 16:30:00,33.5573 2014-01-17 16:35:00,33.3333 2014-01-17 16:40:00,33.5573 2014-01-17 16:45:00,33.3333 2014-01-17 16:50:00,33.4427 2014-01-17 16:55:00,33.4447 2014-01-17 17:00:00,33.5573 2014-01-17 17:05:00,33.3333 2014-01-17 17:10:00,33.4427 2014-01-17 17:15:00,33.4447 2014-01-17 17:20:00,33.4447 2014-01-17 17:25:00,33.4447 2014-01-17 17:30:00,33.4447 2014-01-17 17:35:00,33.3333 2014-01-17 17:40:00,33.446 2014-01-17 17:45:00,33.4427 2014-01-17 17:50:00,33.4447 2014-01-17 17:55:00,33.446 2014-01-17 18:00:00,33.4447 2014-01-17 18:05:00,33.4447 2014-01-17 18:10:00,33.446 2014-01-17 18:15:00,33.5573 2014-01-17 18:20:00,33.4427 2014-01-17 18:25:00,33.3333 2014-01-17 18:30:00,33.446 2014-01-17 18:35:00,33.4447 2014-01-17 18:40:00,33.4447 2014-01-17 18:45:00,33.3333 2014-01-17 18:50:00,33.5553 2014-01-17 18:55:00,33.3333 2014-01-17 19:00:00,33.556 2014-01-17 19:05:00,33.3333 2014-01-17 19:10:00,33.554 2014-01-17 19:15:00,36.6713 2014-01-17 19:20:00,34.778 2014-01-17 19:25:00,33.3333 2014-01-17 19:30:00,33.5553 2014-01-17 19:35:00,33.3333 2014-01-17 19:40:00,33.5587 2014-01-17 19:45:00,33.3333 2014-01-17 19:50:00,33.4427 2014-01-17 19:55:00,33.4447 2014-01-17 20:00:00,33.5553 2014-01-17 20:05:00,33.3333 2014-01-17 20:10:00,33.3333 2014-01-17 20:15:00,33.556 2014-01-17 20:20:00,33.3333 2014-01-17 20:25:00,33.556 2014-01-17 20:30:00,33.3333 2014-01-17 20:35:00,33.4447 2014-01-17 20:40:00,33.446 2014-01-17 20:45:00,33.4447 2014-01-17 20:50:00,33.446 2014-01-17 20:55:00,33.3333 2014-01-17 21:00:00,33.5553 2014-01-17 21:05:00,33.446 2014-01-17 21:10:00,33.4427 2014-01-17 21:15:00,33.3333 2014-01-17 21:20:00,33.446 2014-01-17 21:25:00,33.446 2014-01-17 21:30:00,33.446 2014-01-17 21:35:00,33.4447 2014-01-17 21:40:00,33.446 2014-01-17 21:45:00,33.3333 2014-01-17 21:50:00,33.4427 2014-01-17 21:55:00,33.4447 2014-01-17 22:00:00,33.556 2014-01-17 22:05:00,33.3333 2014-01-17 22:10:00,33.4447 2014-01-17 22:15:00,33.446 2014-01-17 22:20:00,33.4427 2014-01-17 22:25:00,33.4447 2014-01-17 22:30:00,33.3333 2014-01-17 22:35:00,34.8907 2014-01-17 22:40:00,35.5727 2014-01-17 22:45:00,33.446 2014-01-17 22:50:00,33.3333 2014-01-17 22:55:00,33.4447 2014-01-17 23:00:00,33.5573 2014-01-17 23:05:00,33.4447 2014-01-17 23:10:00,33.4447 2014-01-17 23:15:00,33.3333 2014-01-17 23:20:00,33.4447 2014-01-17 23:25:00,33.4447 2014-01-17 23:30:00,33.4447 2014-01-17 23:35:00,33.446 2014-01-17 23:40:00,33.4447 2014-01-17 23:45:00,33.3333 2014-01-17 23:50:00,33.4447 2014-01-17 23:55:00,33.4427 2014-01-18 00:00:00,33.556 2014-01-18 00:05:00,33.3333 2014-01-18 00:10:00,33.556 2014-01-18 00:15:00,33.3333 2014-01-18 00:20:00,33.446 2014-01-18 00:25:00,33.446 2014-01-18 00:30:00,33.3333 2014-01-18 00:35:00,33.5573 2014-01-18 00:40:00,33.3333 2014-01-18 00:45:00,33.554 2014-01-18 00:50:00,33.3333 2014-01-18 00:55:00,33.3333 2014-01-18 01:00:00,33.554 2014-01-18 01:05:00,33.5573 2014-01-18 01:10:00,33.3333 2014-01-18 01:15:00,33.4447 2014-01-18 01:20:00,33.4447 2014-01-18 01:25:00,33.4447 2014-01-18 01:30:00,33.7833 2014-01-18 01:35:00,33.5587 2014-01-18 01:40:00,33.3333 2014-01-18 01:45:00,33.4447 2014-01-18 01:50:00,33.4447 2014-01-18 01:55:00,33.3333 2014-01-18 02:00:00,33.5573 2014-01-18 02:05:00,33.5573 2014-01-18 02:10:00,33.3333 2014-01-18 02:15:00,33.3333 2014-01-18 02:20:00,33.554 2014-01-18 02:25:00,33.3333 2014-01-18 02:30:00,33.5587 2014-01-18 02:35:00,33.3333 2014-01-18 02:40:00,33.446 2014-01-18 02:45:00,33.4447 2014-01-18 02:50:00,33.4427 2014-01-18 02:55:00,33.554 2014-01-18 03:00:00,33.554 2014-01-18 03:05:00,35.1113 2014-01-18 03:10:00,33.4447 2014-01-18 03:15:00,33.4447 2014-01-18 03:20:00,33.3333 2014-01-18 03:25:00,35.1947 2014-01-18 03:30:00,33.4427 2014-01-18 03:35:00,33.4427 2014-01-18 03:40:00,33.3333 2014-01-18 03:45:00,33.4427 2014-01-18 03:50:00,33.4427 2014-01-18 03:55:00,33.4447 2014-01-18 04:00:00,33.5573 2014-01-18 04:05:00,34.5553 2014-01-18 04:10:00,35.328 2014-01-18 04:15:00,34.774 2014-01-18 04:20:00,34.6613 2014-01-18 04:25:00,33.556 2014-01-18 04:30:00,33.3333 2014-01-18 04:35:00,33.3333 2014-01-18 04:40:00,33.67 2014-01-18 04:45:00,33.3333 2014-01-18 04:50:00,33.4447 2014-01-18 04:55:00,33.4447 2014-01-18 05:00:00,33.554 2014-01-18 05:05:00,33.3333 2014-01-18 05:10:00,33.4447 2014-01-18 05:15:00,33.4447 2014-01-18 05:20:00,33.3333 2014-01-18 05:25:00,33.554 2014-01-18 05:30:00,33.3333 2014-01-18 05:35:00,33.446 2014-01-18 05:40:00,33.446 2014-01-18 05:45:00,33.4447 2014-01-18 05:50:00,33.4447 2014-01-18 05:55:00,33.3333 2014-01-18 06:00:00,33.552 2014-01-18 06:05:00,33.4427 2014-01-18 06:10:00,33.446 2014-01-18 06:15:00,33.3333 2014-01-18 06:20:00,33.4447 2014-01-18 06:25:00,33.4447 2014-01-18 06:30:00,33.4447 2014-01-18 06:35:00,33.446 2014-01-18 06:40:00,33.446 2014-01-18 06:45:00,33.3333 2014-01-18 06:50:00,33.446 2014-01-18 06:55:00,33.4447 2014-01-18 07:00:00,33.5573 2014-01-18 07:05:00,33.4427 2014-01-18 07:10:00,33.3333 2014-01-18 07:15:00,33.4427 2014-01-18 07:20:00,33.4447 2014-01-18 07:25:00,33.446 2014-01-18 07:30:00,33.3333 2014-01-18 07:35:00,33.5573 2014-01-18 07:40:00,33.3333 2014-01-18 07:45:00,33.4447 2014-01-18 07:50:00,33.4447 2014-01-18 07:55:00,33.3333 2014-01-18 08:00:00,33.5553 2014-01-18 08:05:00,33.4447 2014-01-18 08:10:00,33.446 2014-01-18 08:15:00,33.4447 2014-01-18 08:20:00,33.4447 2014-01-18 08:25:00,33.3333 2014-01-18 08:30:00,33.554 2014-01-18 08:35:00,33.3333 2014-01-18 08:40:00,33.446 2014-01-18 08:45:00,33.4427 2014-01-18 08:50:00,33.3333 2014-01-18 08:55:00,33.5573 2014-01-18 09:00:00,33.4447 2014-01-18 09:05:00,33.4447 2014-01-18 09:10:00,33.3333 2014-01-18 09:15:00,33.552 2014-01-18 09:20:00,33.3333 2014-01-18 09:25:00,33.4427 2014-01-18 09:30:00,33.4427 2014-01-18 09:35:00,33.3333 2014-01-18 09:40:00,33.5553 2014-01-18 09:45:00,33.3333 2014-01-18 09:50:00,33.6647 2014-01-18 09:55:00,33.4427 2014-01-18 10:00:00,33.554 2014-01-18 10:05:00,33.3333 2014-01-18 10:10:00,33.446 2014-01-18 10:15:00,33.4427 2014-01-18 10:20:00,33.3333 2014-01-18 10:25:00,33.552 2014-01-18 10:30:00,33.3333 2014-01-18 10:35:00,33.4447 2014-01-18 10:40:00,33.446 2014-01-18 10:45:00,33.3333 2014-01-18 10:50:00,33.554 2014-01-18 10:55:00,33.3333 2014-01-18 11:00:00,33.5573 2014-01-18 11:05:00,33.3333 2014-01-18 11:10:00,33.5587 2014-01-18 11:15:00,33.3333 2014-01-18 11:20:00,33.4427 2014-01-18 11:25:00,33.4427 2014-01-18 11:30:00,33.4447 2014-01-18 11:35:00,33.4427 2014-01-18 11:40:00,33.3333 2014-01-18 11:45:00,33.4447 2014-01-18 11:50:00,33.4447 2014-01-18 11:55:00,33.4427 2014-01-18 12:00:00,33.4427 2014-01-18 12:05:00,33.4447 2014-01-18 12:10:00,33.4427 2014-01-18 12:15:00,33.4447 2014-01-18 12:20:00,33.4427 2014-01-18 12:25:00,33.3333 2014-01-18 12:30:00,33.552 2014-01-18 12:35:00,33.3333 2014-01-18 12:40:00,33.446 2014-01-18 12:45:00,33.446 2014-01-18 12:50:00,33.446 2014-01-18 12:55:00,33.446 2014-01-18 13:00:00,33.4427 2014-01-18 13:05:00,33.4447 2014-01-18 13:10:00,33.4447 2014-01-18 13:15:00,33.4447 2014-01-18 13:20:00,33.446 2014-01-18 13:25:00,33.3333 2014-01-18 13:30:00,33.4427 2014-01-18 13:35:00,33.4447 2014-01-18 13:40:00,33.4427 2014-01-18 13:45:00,33.4447 2014-01-18 13:50:00,33.3333 2014-01-18 13:55:00,33.4427 2014-01-18 14:00:00,33.5573 2014-01-18 14:05:00,33.4447 2014-01-18 14:10:00,33.4447 2014-01-18 14:15:00,33.4427 2014-01-18 14:20:00,33.4447 2014-01-18 14:25:00,33.446 2014-01-18 14:30:00,33.446 2014-01-18 14:35:00,33.4447 2014-01-18 14:40:00,33.446 2014-01-18 14:45:00,33.3333 2014-01-18 14:50:00,33.556 2014-01-18 14:55:00,33.446 2014-01-18 15:00:00,33.5573 2014-01-18 15:05:00,33.4447 2014-01-18 15:10:00,33.3333 2014-01-18 15:15:00,33.554 2014-01-18 15:20:00,33.3333 2014-01-18 15:25:00,33.4427 2014-01-18 15:30:00,33.4447 2014-01-18 15:35:00,33.446 2014-01-18 15:40:00,33.4447 2014-01-18 15:45:00,33.3333 2014-01-18 15:50:00,33.4447 2014-01-18 15:55:00,33.446 2014-01-18 16:00:00,33.5553 2014-01-18 16:05:00,33.3333 2014-01-18 16:10:00,33.4427 2014-01-18 16:15:00,33.4447 2014-01-18 16:20:00,37.214 2014-01-18 16:25:00,33.446 2014-01-18 16:30:00,33.4447 2014-01-18 16:35:00,33.4447 2014-01-18 16:40:00,33.3333 2014-01-18 16:45:00,33.5553 2014-01-18 16:50:00,33.3333 2014-01-18 16:55:00,33.4447 2014-01-18 17:00:00,33.446 2014-01-18 17:05:00,33.554 2014-01-18 17:10:00,33.3333 2014-01-18 17:15:00,33.4447 2014-01-18 17:20:00,33.4447 2014-01-18 17:25:00,33.4427 2014-01-18 17:30:00,33.4447 2014-01-18 17:35:00,33.4447 2014-01-18 17:40:00,33.3333 2014-01-18 17:45:00,33.446 2014-01-18 17:50:00,33.4447 2014-01-18 17:55:00,33.4447 2014-01-18 18:00:00,33.5553 2014-01-18 18:05:00,33.3333 2014-01-18 18:10:00,33.446 2014-01-18 18:15:00,33.4447 2014-01-18 18:20:00,33.4447 2014-01-18 18:25:00,33.4447 2014-01-18 18:30:00,33.446 2014-01-18 18:35:00,33.3333 2014-01-18 18:40:00,33.4447 2014-01-18 18:45:00,33.4427 2014-01-18 18:50:00,33.4427 2014-01-18 18:55:00,33.446 2014-01-18 19:00:00,33.4447 2014-01-18 19:05:00,33.4427 2014-01-18 19:10:00,33.4447 2014-01-18 19:15:00,33.4447 2014-01-18 19:20:00,33.4447 2014-01-18 19:25:00,33.4447 2014-01-18 19:30:00,33.3333 2014-01-18 19:35:00,33.4447 2014-01-18 19:40:00,33.4447 2014-01-18 19:45:00,33.4447 2014-01-18 19:50:00,33.4447 2014-01-18 19:55:00,33.3333 2014-01-18 20:00:00,33.5573 2014-01-18 20:05:00,33.4447 2014-01-18 20:10:00,33.4447 2014-01-18 20:15:00,33.3333 2014-01-18 20:20:00,33.5573 2014-01-18 20:25:00,33.3333 2014-01-18 20:30:00,33.4427 2014-01-18 20:35:00,33.446 2014-01-18 20:40:00,33.4447 2014-01-18 20:45:00,33.4447 2014-01-18 20:50:00,33.3333 2014-01-18 20:55:00,33.4447 2014-01-18 21:00:00,33.4447 2014-01-18 21:05:00,33.554 2014-01-18 21:10:00,28.5714 2014-01-18 21:15:00,33.4447 2014-01-18 21:20:00,33.4447 2014-01-18 21:25:00,33.3333 2014-01-18 21:30:00,33.5587 2014-01-18 21:35:00,33.3333 2014-01-18 21:40:00,33.556 2014-01-18 21:45:00,33.3333 2014-01-18 21:50:00,33.3333 2014-01-18 21:55:00,33.5573 2014-01-18 22:00:00,33.556 2014-01-18 22:05:00,33.3333 2014-01-18 22:10:00,33.3333 2014-01-18 22:15:00,33.5553 2014-01-18 22:20:00,33.3333 2014-01-18 22:25:00,33.554 2014-01-18 22:30:00,33.3333 2014-01-18 22:35:00,33.446 2014-01-18 22:40:00,33.4447 2014-01-18 22:45:00,33.3333 2014-01-18 22:50:00,33.5573 2014-01-18 22:55:00,33.3333 2014-01-18 23:00:00,33.556 2014-01-18 23:05:00,33.3333 2014-01-18 23:10:00,34.344 2014-01-18 23:15:00,36.2207 2014-01-18 23:20:00,36.1113 2014-01-18 23:25:00,33.4447 2014-01-18 23:30:00,33.4447 2014-01-18 23:35:00,33.6633 2014-01-18 23:40:00,38.1267 2014-01-18 23:45:00,33.9913 2014-01-18 23:50:00,33.3333 2014-01-18 23:55:00,33.4447 2014-01-19 00:00:00,33.556 2014-01-19 00:05:00,33.4447 2014-01-19 00:10:00,33.3333 2014-01-19 00:15:00,33.4447 2014-01-19 00:20:00,33.556 2014-01-19 00:25:00,33.5573 2014-01-19 00:30:00,33.4447 2014-01-19 00:35:00,33.3333 2014-01-19 00:40:00,33.5553 2014-01-19 00:45:00,35.756 2014-01-19 00:50:00,39.91 2014-01-19 00:55:00,35.5487 2014-01-19 01:00:00,33.6667 2014-01-19 01:05:00,33.554 2014-01-19 01:10:00,33.3333 2014-01-19 01:15:00,33.3333 2014-01-19 01:20:00,33.554 2014-01-19 01:25:00,33.3333 2014-01-19 01:30:00,33.4427 2014-01-19 01:35:00,33.4427 2014-01-19 01:40:00,33.4427 2014-01-19 01:45:00,33.4447 2014-01-19 01:50:00,33.3333 2014-01-19 01:55:00,33.4427 2014-01-19 02:00:00,33.5573 2014-01-19 02:05:00,33.4447 2014-01-19 02:10:00,33.3333 2014-01-19 02:15:00,33.4427 2014-01-19 02:20:00,33.4447 2014-01-19 02:25:00,33.4447 2014-01-19 02:30:00,33.4447 2014-01-19 02:35:00,33.446 2014-01-19 02:40:00,33.3333 2014-01-19 02:45:00,33.4447 2014-01-19 02:50:00,33.4427 2014-01-19 02:55:00,33.4447 2014-01-19 03:00:00,33.446 2014-01-19 03:05:00,35.1113 2014-01-19 03:10:00,33.446 2014-01-19 03:15:00,33.4447 2014-01-19 03:20:00,33.4447 2014-01-19 03:25:00,35.2227 2014-01-19 03:30:00,33.4447 2014-01-19 03:35:00,33.4447 2014-01-19 03:40:00,33.4447 2014-01-19 03:45:00,33.3333 2014-01-19 03:50:00,33.4447 2014-01-19 03:55:00,33.4447 2014-01-19 04:00:00,33.554 2014-01-19 04:05:00,33.3333 2014-01-19 04:10:00,33.4447 2014-01-19 04:15:00,33.446 2014-01-19 04:20:00,33.3333 2014-01-19 04:25:00,33.556 2014-01-19 04:30:00,33.3333 2014-01-19 04:35:00,33.5573 2014-01-19 04:40:00,33.3333 2014-01-19 04:45:00,33.3333 2014-01-19 04:50:00,33.5573 2014-01-19 04:55:00,33.3333 2014-01-19 05:00:00,33.554 2014-01-19 05:05:00,33.446 2014-01-19 05:10:00,33.4447 2014-01-19 05:15:00,33.3333 2014-01-19 05:20:00,33.554 2014-01-19 05:25:00,33.3333 2014-01-19 05:30:00,33.4427 2014-01-19 05:35:00,33.446 2014-01-19 05:40:00,33.3333 2014-01-19 05:45:00,33.5573 2014-01-19 05:50:00,33.3333 2014-01-19 05:55:00,33.4427 2014-01-19 06:00:00,33.4447 2014-01-19 06:05:00,33.5573 2014-01-19 06:10:00,33.3333 2014-01-19 06:15:00,33.4447 2014-01-19 06:20:00,33.446 2014-01-19 06:25:00,33.3333 2014-01-19 06:30:00,33.5573 2014-01-19 06:35:00,33.3333 2014-01-19 06:40:00,33.554 2014-01-19 06:45:00,33.3333 2014-01-19 06:50:00,33.3333 2014-01-19 06:55:00,33.5573 2014-01-19 07:00:00,33.554 2014-01-19 07:05:00,33.3333 2014-01-19 07:10:00,33.4427 2014-01-19 07:15:00,33.4447 2014-01-19 07:20:00,33.3333 2014-01-19 07:25:00,35.1113 2014-01-19 07:30:00,36.9867 2014-01-19 07:35:00,37.114000000000004 2014-01-19 07:40:00,33.556 2014-01-19 07:45:00,33.3333 2014-01-19 07:50:00,33.4427 2014-01-19 07:55:00,33.4447 2014-01-19 08:00:00,33.554 2014-01-19 08:05:00,33.3333 2014-01-19 08:10:00,33.446 2014-01-19 08:15:00,33.446 2014-01-19 08:20:00,33.3333 2014-01-19 08:25:00,33.556 2014-01-19 08:30:00,23.0769 2014-01-19 08:35:00,33.556 2014-01-19 08:40:00,33.3333 2014-01-19 08:45:00,33.4447 2014-01-19 08:50:00,33.4447 2014-01-19 08:55:00,33.3333 2014-01-19 09:00:00,33.5573 2014-01-19 09:05:00,33.4427 2014-01-19 09:10:00,33.446 2014-01-19 09:15:00,33.3333 2014-01-19 09:20:00,33.5573 2014-01-19 09:25:00,33.3333 2014-01-19 09:30:00,33.446 2014-01-19 09:35:00,33.4447 2014-01-19 09:40:00,33.3333 2014-01-19 09:45:00,33.554 2014-01-19 09:50:00,33.3333 2014-01-19 09:55:00,33.4447 2014-01-19 10:00:00,33.554 2014-01-19 10:05:00,33.554 2014-01-19 10:10:00,33.3333 2014-01-19 10:15:00,33.4427 2014-01-19 10:20:00,33.4447 2014-01-19 10:25:00,33.446 2014-01-19 10:30:00,33.446 2014-01-19 10:35:00,33.3333 2014-01-19 10:40:00,33.4447 2014-01-19 10:45:00,33.446 2014-01-19 10:50:00,33.4427 2014-01-19 10:55:00,33.5553 2014-01-19 11:00:00,33.5587 2014-01-19 11:05:00,33.3333 2014-01-19 11:10:00,33.4427 2014-01-19 11:15:00,33.4447 2014-01-19 11:20:00,33.3333 2014-01-19 11:25:00,33.5553 2014-01-19 11:30:00,28.5714 2014-01-19 11:35:00,33.4427 2014-01-19 11:40:00,33.4447 2014-01-19 11:45:00,33.5573 2014-01-19 11:50:00,33.3333 2014-01-19 11:55:00,33.3333 2014-01-19 12:00:00,33.556 2014-01-19 12:05:00,33.554 2014-01-19 12:10:00,34.0033 2014-01-19 12:15:00,33.446 2014-01-19 12:20:00,33.4427 2014-01-19 12:25:00,33.3333 2014-01-19 12:30:00,33.5573 2014-01-19 12:35:00,33.3333 2014-01-19 12:40:00,33.4427 2014-01-19 12:45:00,33.4447 2014-01-19 12:50:00,33.4427 2014-01-19 12:55:00,33.4447 2014-01-19 13:00:00,33.4447 2014-01-19 13:05:00,33.4447 2014-01-19 13:10:00,33.4447 2014-01-19 13:15:00,33.446 2014-01-19 13:20:00,33.3333 2014-01-19 13:25:00,33.5573 2014-01-19 13:30:00,38.0187 2014-01-19 13:35:00,37.3347 2014-01-19 13:40:00,37.222 2014-01-19 13:45:00,38.1107 2014-01-19 13:50:00,37.8893 2014-01-19 13:55:00,38.222 2014-01-19 14:00:00,34.1093 2014-01-19 14:05:00,37.444 2014-01-19 14:10:00,33.8893 2014-01-19 14:15:00,33.4447 2014-01-19 14:20:00,33.4447 2014-01-19 14:25:00,33.3333 2014-01-19 14:30:00,36.5713 2014-01-19 14:35:00,37.116 2014-01-19 14:40:00,36.1007 2014-01-19 14:45:00,35.8967 2014-01-19 14:50:00,36.5493 2014-01-19 14:55:00,36.3373 2014-01-19 15:00:00,35.6673 2014-01-19 15:05:00,35.7787 2014-01-19 15:10:00,36.1113 2014-01-19 15:15:00,35.44 2014-01-19 15:20:00,33.5573 2014-01-19 15:25:00,33.3333 2014-01-19 15:30:00,33.5553 2014-01-19 15:35:00,33.3333 2014-01-19 15:40:00,33.446 2014-01-19 15:45:00,33.4447 2014-01-19 15:50:00,33.3333 2014-01-19 15:55:00,33.554 2014-01-19 16:00:00,33.4427 2014-01-19 16:05:00,33.4447 2014-01-19 16:10:00,33.3333 2014-01-19 16:15:00,33.5553 2014-01-19 16:20:00,33.3333 2014-01-19 16:25:00,33.5573 2014-01-19 16:30:00,33.3333 2014-01-19 16:35:00,33.4447 2014-01-19 16:40:00,33.4447 2014-01-19 16:45:00,33.3333 2014-01-19 16:50:00,33.5573 2014-01-19 16:55:00,33.3333 2014-01-19 17:00:00,33.5573 2014-01-19 17:05:00,33.3333 2014-01-19 17:10:00,33.554 2014-01-19 17:15:00,33.3333 2014-01-19 17:20:00,33.4427 2014-01-19 17:25:00,33.4427 2014-01-19 17:30:00,33.446 2014-01-19 17:35:00,33.4447 2014-01-19 17:40:00,33.3333 2014-01-19 17:45:00,33.4427 2014-01-19 17:50:00,33.446 2014-01-19 17:55:00,33.446 2014-01-19 18:00:00,33.4447 2014-01-19 18:05:00,33.554 2014-01-19 18:10:00,33.3333 2014-01-19 18:15:00,33.4447 2014-01-19 18:20:00,33.4447 2014-01-19 18:25:00,33.4447 2014-01-19 18:30:00,33.4427 2014-01-19 18:35:00,33.3333 2014-01-19 18:40:00,33.4447 2014-01-19 18:45:00,37.7947 2014-01-19 18:50:00,38.556 2014-01-19 18:55:00,36.9907 2014-01-19 19:00:00,33.5573 2014-01-19 19:05:00,33.3333 2014-01-19 19:10:00,36.2333 2014-01-19 19:15:00,38.8913 2014-01-19 19:20:00,38.1007 2014-01-19 19:25:00,33.446 2014-01-19 19:30:00,33.4447 2014-01-19 19:35:00,33.4447 2014-01-19 19:40:00,33.4447 2014-01-19 19:45:00,33.3333 2014-01-19 19:50:00,33.4447 2014-01-19 19:55:00,33.446 2014-01-19 20:00:00,33.6653 2014-01-19 20:05:00,33.3333 2014-01-19 20:10:00,33.4427 2014-01-19 20:15:00,33.4447 2014-01-19 20:20:00,33.4447 2014-01-19 20:25:00,33.446 2014-01-19 20:30:00,33.3333 2014-01-19 20:35:00,33.4427 2014-01-19 20:40:00,33.4427 2014-01-19 20:45:00,33.4447 2014-01-19 20:50:00,33.4447 2014-01-19 20:55:00,33.3333 2014-01-19 21:00:00,33.5573 2014-01-19 21:05:00,33.4427 2014-01-19 21:10:00,33.5587 2014-01-19 21:15:00,33.3333 2014-01-19 21:20:00,33.5553 2014-01-19 21:25:00,33.3333 2014-01-19 21:30:00,33.4447 2014-01-19 21:35:00,33.446 2014-01-19 21:40:00,33.3333 2014-01-19 21:45:00,33.5573 2014-01-19 21:50:00,33.3333 2014-01-19 21:55:00,33.554 2014-01-19 22:00:00,33.3333 2014-01-19 22:05:00,33.5573 2014-01-19 22:10:00,33.3333 2014-01-19 22:15:00,33.5553 2014-01-19 22:20:00,33.3333 2014-01-19 22:25:00,33.3333 2014-01-19 22:30:00,23.3354 2014-01-19 22:35:00,33.3333 2014-01-19 22:40:00,33.554 2014-01-19 22:45:00,33.3333 2014-01-19 22:50:00,33.4427 2014-01-19 22:55:00,33.4447 2014-01-19 23:00:00,33.5587 2014-01-19 23:05:00,33.3333 2014-01-19 23:10:00,33.446 2014-01-19 23:15:00,33.4447 2014-01-19 23:20:00,33.3333 2014-01-19 23:25:00,33.5573 2014-01-19 23:30:00,33.3333 2014-01-19 23:35:00,33.446 2014-01-19 23:40:00,33.4447 2014-01-19 23:45:00,33.4447 2014-01-19 23:50:00,33.3333 2014-01-19 23:55:00,33.446 2014-01-20 00:00:00,33.5573 2014-01-20 00:05:00,33.4427 2014-01-20 00:10:00,33.5553 2014-01-20 00:15:00,33.5573 2014-01-20 00:20:00,33.3333 2014-01-20 00:25:00,33.4447 2014-01-20 00:30:00,33.4447 2014-01-20 00:35:00,33.3333 2014-01-20 00:40:00,33.556 2014-01-20 00:45:00,33.3333 2014-01-20 00:50:00,33.446 2014-01-20 00:55:00,33.4427 2014-01-20 01:00:00,33.556 2014-01-20 01:05:00,33.3333 2014-01-20 01:10:00,33.552 2014-01-20 01:15:00,33.3333 2014-01-20 01:20:00,33.3333 2014-01-20 01:25:00,33.552 2014-01-20 01:30:00,33.3333 2014-01-20 01:35:00,33.552 2014-01-20 01:40:00,33.3333 2014-01-20 01:45:00,33.4447 2014-01-20 01:50:00,33.4447 2014-01-20 01:55:00,33.3333 2014-01-20 02:00:00,33.556 2014-01-20 02:05:00,33.4447 2014-01-20 02:10:00,33.446 2014-01-20 02:15:00,33.446 2014-01-20 02:20:00,33.4427 2014-01-20 02:25:00,33.4427 2014-01-20 02:30:00,33.4447 2014-01-20 02:35:00,33.3333 2014-01-20 02:40:00,33.4427 2014-01-20 02:45:00,33.4447 2014-01-20 02:50:00,33.4447 2014-01-20 02:55:00,33.4447 2014-01-20 03:00:00,33.554 2014-01-20 03:05:00,33.3333 2014-01-20 03:10:00,33.556 2014-01-20 03:15:00,33.3333 2014-01-20 03:20:00,35.2227 2014-01-20 03:25:00,33.3333 2014-01-20 03:30:00,33.4427 2014-01-20 03:35:00,33.4447 2014-01-20 03:40:00,35.2207 2014-01-20 03:45:00,33.3333 2014-01-20 03:50:00,33.5587 2014-01-20 03:55:00,33.3333 2014-01-20 04:00:00,23.3315 2014-01-20 04:05:00,37.5 2014-01-20 04:10:00,33.5573 2014-01-20 04:15:00,33.3333 2014-01-20 04:20:00,33.4447 2014-01-20 04:25:00,33.4427 2014-01-20 04:30:00,33.3333 2014-01-20 04:35:00,33.554 2014-01-20 04:40:00,33.3333 2014-01-20 04:45:00,33.5553 2014-01-20 04:50:00,33.3333 2014-01-20 04:55:00,33.3333 2014-01-20 05:00:00,28.81 2014-01-20 05:05:00,33.556 2014-01-20 05:10:00,33.3333 2014-01-20 05:15:00,33.3333 2014-01-20 05:20:00,33.5553 2014-01-20 05:25:00,33.4447 2014-01-20 05:30:00,33.4427 2014-01-20 05:35:00,33.3333 2014-01-20 05:40:00,33.5573 2014-01-20 05:45:00,33.3333 2014-01-20 05:50:00,33.4447 2014-01-20 05:55:00,33.4447 2014-01-20 06:00:00,33.6667 2014-01-20 06:05:00,33.4447 2014-01-20 06:10:00,33.4447 2014-01-20 06:15:00,33.4447 2014-01-20 06:20:00,33.3333 2014-01-20 06:25:00,33.446 2014-01-20 06:30:00,35.8336 2014-01-20 06:35:00,33.4447 2014-01-20 06:40:00,33.446 2014-01-20 06:45:00,35.7143 2014-01-20 06:50:00,33.4447 2014-01-20 06:55:00,33.4447 2014-01-20 07:00:00,35.9521 2014-01-20 07:05:00,30.7692 2014-01-20 07:10:00,33.4447 2014-01-20 07:15:00,33.4427 2014-01-20 07:20:00,35.8336 2014-01-20 07:25:00,33.4447 2014-01-20 07:30:00,33.3333 2014-01-20 07:35:00,35.9543 2014-01-20 07:40:00,30.7692 2014-01-20 07:45:00,33.4447 2014-01-20 07:50:00,33.4427 2014-01-20 07:55:00,33.6667 2014-01-20 08:00:00,33.554 2014-01-20 08:05:00,35.7143 2014-01-20 08:10:00,30.7692 2014-01-20 08:15:00,33.4427 2014-01-20 08:20:00,33.3333 2014-01-20 08:25:00,35.9557 2014-01-20 08:30:00,30.7692 2014-01-20 08:35:00,33.556 2014-01-20 08:40:00,33.3333 2014-01-20 08:45:00,35.7143 2014-01-20 08:50:00,35.9507 2014-01-20 08:55:00,33.3333 2014-01-20 09:00:00,33.5553 2014-01-20 09:05:00,35.8336 2014-01-20 09:10:00,31.0262 2014-01-20 09:15:00,33.3333 2014-01-20 09:20:00,33.446 2014-01-20 09:25:00,33.4447 2014-01-20 09:30:00,35.7143 2014-01-20 09:35:00,33.615 2014-01-20 09:40:00,33.3333 2014-01-20 09:45:00,33.4447 2014-01-20 09:50:00,35.835 2014-01-20 09:55:00,33.3333 2014-01-20 10:00:00,33.446 2014-01-20 10:05:00,33.446 2014-01-20 10:10:00,35.8336 2014-01-20 10:15:00,30.8954 2014-01-20 10:20:00,33.4447 2014-01-20 10:25:00,33.3333 2014-01-20 10:30:00,35.835 2014-01-20 10:35:00,33.4742 2014-01-20 10:40:00,33.446 2014-01-20 10:45:00,33.4447 2014-01-20 10:50:00,35.835 2014-01-20 10:55:00,30.7692 2014-01-20 11:00:00,33.4427 2014-01-20 11:05:00,33.4427 2014-01-20 11:10:00,35.8336 2014-01-20 11:15:00,30.7692 2014-01-20 11:20:00,33.4447 2014-01-20 11:25:00,33.3333 2014-01-20 11:30:00,35.8336 2014-01-20 11:35:00,30.8954 2014-01-20 11:40:00,33.4447 2014-01-20 11:45:00,33.4447 2014-01-20 11:50:00,35.7143 2014-01-20 11:55:00,30.8977 2014-01-20 12:00:00,33.554 2014-01-20 12:05:00,33.446 2014-01-20 12:10:00,35.9543 2014-01-20 12:15:00,30.7692 2014-01-20 12:20:00,33.4447 2014-01-20 12:25:00,33.4447 2014-01-20 12:30:00,35.7143 2014-01-20 12:35:00,31.0277 2014-01-20 12:40:00,33.3333 2014-01-20 12:45:00,33.552 2014-01-20 12:50:00,35.7143 2014-01-20 12:55:00,30.7692 2014-01-20 13:00:00,33.556 2014-01-20 13:05:00,33.554 2014-01-20 13:10:00,35.7143 2014-01-20 13:15:00,30.7692 2014-01-20 13:20:00,33.5573 2014-01-20 13:25:00,33.3333 2014-01-20 13:30:00,35.8336 2014-01-20 13:35:00,30.7692 2014-01-20 13:40:00,33.4427 2014-01-20 13:45:00,33.4447 2014-01-20 13:50:00,35.7143 2014-01-20 13:55:00,35.9507 2014-01-20 14:00:00,33.4725 2014-01-20 14:05:00,33.4447 2014-01-20 14:10:00,35.7143 2014-01-20 14:15:00,35.9507 2014-01-20 14:20:00,33.3333 2014-01-20 14:25:00,33.446 2014-01-20 14:30:00,35.8336 2014-01-20 14:35:00,35.8314 2014-01-20 14:40:00,33.4447 2014-01-20 14:45:00,33.3333 2014-01-20 14:50:00,35.835 2014-01-20 14:55:00,35.8336 2014-01-20 15:00:00,33.6092 2014-01-20 15:05:00,33.3333 2014-01-20 15:10:00,33.554 2014-01-20 15:15:00,35.7143 2014-01-20 15:20:00,33.4742 2014-01-20 15:25:00,33.4447 2014-01-20 15:30:00,33.4447 2014-01-20 15:35:00,35.8314 2014-01-20 15:40:00,33.3333 2014-01-20 15:45:00,33.446 2014-01-20 15:50:00,33.4427 2014-01-20 15:55:00,35.835 2014-01-20 16:00:00,33.4725 2014-01-20 16:05:00,33.554 2014-01-20 16:10:00,33.3333 2014-01-20 16:15:00,35.8314 2014-01-20 16:20:00,30.8977 2014-01-20 16:25:00,33.3333 2014-01-20 16:30:00,33.556 2014-01-20 16:35:00,33.3333 2014-01-20 16:40:00,35.8314 2014-01-20 16:45:00,33.4725 2014-01-20 16:50:00,33.446 2014-01-20 16:55:00,33.4427 2014-01-20 17:00:00,35.8336 2014-01-20 17:05:00,30.8992 2014-01-20 17:10:00,33.4427 2014-01-20 17:15:00,33.4447 2014-01-20 17:20:00,35.8314 2014-01-20 17:25:00,30.7692 2014-01-20 17:30:00,33.4447 2014-01-20 17:35:00,33.4447 2014-01-20 17:40:00,35.9486 2014-01-20 17:45:00,30.7692 2014-01-20 17:50:00,33.4447 2014-01-20 17:55:00,33.446 2014-01-20 18:00:00,35.9529 2014-01-20 18:05:00,30.7692 2014-01-20 18:10:00,33.446 2014-01-20 18:15:00,33.446 2014-01-20 18:20:00,35.7143 2014-01-20 18:25:00,35.8336 2014-01-20 18:30:00,33.3333 2014-01-20 18:35:00,33.5587 2014-01-20 18:40:00,35.7143 2014-01-20 18:45:00,35.7143 2014-01-20 18:50:00,33.554 2014-01-20 18:55:00,33.3333 2014-01-20 19:00:00,35.9529 2014-01-20 19:05:00,30.8977 2014-01-20 19:10:00,36.5487 2014-01-20 19:15:00,35.7893 2014-01-20 19:20:00,33.446 2014-01-20 19:25:00,35.8336 2014-01-20 19:30:00,33.3333 2014-01-20 19:35:00,35.6667 2014-01-20 19:40:00,33.3333 2014-01-20 19:45:00,35.8336 2014-01-20 19:50:00,33.75 2014-01-20 19:55:00,36.4447 2014-01-20 20:00:00,33.554 2014-01-20 20:05:00,35.7143 2014-01-20 20:10:00,30.8977 2014-01-20 20:15:00,33.3333 2014-01-20 20:20:00,33.5553 2014-01-20 20:25:00,35.7143 2014-01-20 20:30:00,30.7692 2014-01-20 20:35:00,33.4427 2014-01-20 20:40:00,33.3333 2014-01-20 20:45:00,35.9507 2014-01-20 20:50:00,30.7692 2014-01-20 20:55:00,33.4427 2014-01-20 21:00:00,33.4447 2014-01-20 21:05:00,35.9557 2014-01-20 21:10:00,30.7692 2014-01-20 21:15:00,33.5573 2014-01-20 21:20:00,33.3333 2014-01-20 21:25:00,35.7143 2014-01-20 21:30:00,31.0254 2014-01-20 21:35:00,33.3333 2014-01-20 21:40:00,33.4447 2014-01-20 21:45:00,35.8314 2014-01-20 21:50:00,31.5338 2014-01-20 21:55:00,33.4427 2014-01-20 22:00:00,33.4447 2014-01-20 22:05:00,35.8336 2014-01-20 22:10:00,30.8954 2014-01-20 22:15:00,33.4427 2014-01-20 22:20:00,33.3333 2014-01-20 22:25:00,35.835 2014-01-20 22:30:00,30.8954 2014-01-20 22:35:00,33.446 2014-01-20 22:40:00,33.4447 2014-01-20 22:45:00,35.8314 2014-01-20 22:50:00,30.7692 2014-01-20 22:55:00,33.4447 2014-01-20 23:00:00,33.554 2014-01-20 23:05:00,35.8314 2014-01-20 23:10:00,30.7692 2014-01-20 23:15:00,33.446 2014-01-20 23:20:00,33.446 2014-01-20 23:25:00,35.8336 2014-01-20 23:30:00,30.8992 2014-01-20 23:35:00,33.3333 2014-01-20 23:40:00,33.556 2014-01-20 23:45:00,35.7143 2014-01-20 23:50:00,34.0167 2014-01-20 23:55:00,33.8873 2014-01-21 00:00:00,33.554 2014-01-21 00:05:00,35.7143 2014-01-21 00:10:00,31.0238 2014-01-21 00:15:00,33.3333 2014-01-21 00:20:00,33.446 2014-01-21 00:25:00,35.835 2014-01-21 00:30:00,33.3333 2014-01-21 00:35:00,33.554 2014-01-21 00:40:00,33.3333 2014-01-21 00:45:00,35.8314 2014-01-21 00:50:00,33.3333 2014-01-21 00:55:00,33.3333 2014-01-21 01:00:00,33.552 2014-01-21 01:05:00,35.9486 2014-01-21 01:10:00,35.7143 2014-01-21 01:15:00,33.3333 2014-01-21 01:20:00,33.5573 2014-01-21 01:25:00,35.7143 2014-01-21 01:30:00,31.0277 2014-01-21 01:35:00,33.3333 2014-01-21 01:40:00,33.4427 2014-01-21 01:45:00,33.446 2014-01-21 01:50:00,33.3333 2014-01-21 01:55:00,35.9521 2014-01-21 02:00:00,35.835 2014-01-21 02:05:00,35.835 2014-01-21 02:10:00,30.7692 2014-01-21 02:15:00,33.6092 2014-01-21 02:20:00,33.3333 2014-01-21 02:25:00,33.4427 2014-01-21 02:30:00,33.446 2014-01-21 02:35:00,33.4447 2014-01-21 02:40:00,33.446 2014-01-21 02:45:00,35.7143 2014-01-21 02:50:00,35.835 2014-01-21 02:55:00,30.8977 2014-01-21 03:00:00,33.6133 2014-01-21 03:05:00,36.9153 2014-01-21 03:10:00,33.3333 2014-01-21 03:15:00,33.446 2014-01-21 03:20:00,33.446 2014-01-21 03:25:00,35.7143 2014-01-21 03:30:00,35.9486 2014-01-21 03:35:00,30.7692 2014-01-21 03:40:00,33.47 2014-01-21 03:45:00,33.4447 2014-01-21 03:50:00,33.4427 2014-01-21 03:55:00,35.8314 2014-01-21 04:00:00,33.5587 2014-01-21 04:05:00,35.8314 2014-01-21 04:10:00,35.8314 2014-01-21 04:15:00,30.7692 2014-01-21 04:20:00,33.554 2014-01-21 04:25:00,33.3333 2014-01-21 04:30:00,33.446 2014-01-21 04:35:00,35.8336 2014-01-21 04:40:00,35.835 2014-01-21 04:45:00,35.835 2014-01-21 04:50:00,30.8954 2014-01-21 04:55:00,33.4447 2014-01-21 05:00:00,33.4447 2014-01-21 05:05:00,33.4427 2014-01-21 05:10:00,35.8336 2014-01-21 05:15:00,35.8336 2014-01-21 05:20:00,35.7143 2014-01-21 05:25:00,30.8992 2014-01-21 05:30:00,33.4427 2014-01-21 05:35:00,33.446 2014-01-21 05:40:00,33.4447 2014-01-21 05:45:00,33.4447 2014-01-21 05:50:00,35.7143 2014-01-21 05:55:00,35.9507 2014-01-21 06:00:00,30.8977 2014-01-21 06:05:00,30.8992 2014-01-21 06:10:00,33.3333 2014-01-21 06:15:00,33.554 2014-01-21 06:20:00,33.3333 2014-01-21 06:25:00,33.4427 2014-01-21 06:30:00,33.4427 2014-01-21 06:35:00,35.7143 2014-01-21 06:40:00,36.07 2014-01-21 06:45:00,30.7692 2014-01-21 06:50:00,33.4725 2014-01-21 06:55:00,33.3333 2014-01-21 07:00:00,33.554 2014-01-21 07:05:00,33.4447 2014-01-21 07:10:00,35.835 2014-01-21 07:15:00,35.7143 2014-01-21 07:20:00,35.9529 2014-01-21 07:25:00,33.47 2014-01-21 07:30:00,33.3333 2014-01-21 07:35:00,33.556 2014-01-21 07:40:00,33.3333 2014-01-21 07:45:00,35.9543 2014-01-21 07:50:00,35.7143 2014-01-21 07:55:00,35.7143 2014-01-21 08:00:00,31.0262 2014-01-21 08:05:00,33.3333 2014-01-21 08:10:00,33.4725 2014-01-21 08:15:00,33.3333 2014-01-21 08:20:00,33.4427 2014-01-21 08:25:00,33.4427 2014-01-21 08:30:00,33.4427 2014-01-21 08:35:00,35.835 2014-01-21 08:40:00,35.7143 2014-01-21 08:45:00,30.8992 2014-01-21 08:50:00,33.4725 2014-01-21 08:55:00,33.4427 2014-01-21 09:00:00,33.4447 2014-01-21 09:05:00,33.4427 2014-01-21 09:10:00,33.4447 2014-01-21 09:15:00,35.8336 2014-01-21 09:20:00,35.7143 2014-01-21 09:25:00,35.7143 2014-01-21 09:30:00,30.8977 2014-01-21 09:35:00,33.4447 2014-01-21 09:40:00,33.4427 2014-01-21 09:45:00,33.3333 2014-01-21 09:50:00,33.554 2014-01-21 09:55:00,35.7143 2014-01-21 10:00:00,35.9557 2014-01-21 10:05:00,30.7692 2014-01-21 10:10:00,33.4725 2014-01-21 10:15:00,33.3333 2014-01-21 10:20:00,33.4427 2014-01-21 10:25:00,33.4447 2014-01-21 10:30:00,33.3333 2014-01-21 10:35:00,35.9529 2014-01-21 10:40:00,37.3814 2014-01-21 10:45:00,45.6229 2014-01-21 10:50:00,35.8685 2014-01-21 10:55:00,33.4447 2014-01-21 11:00:00,33.556 2014-01-21 11:05:00,33.3333 2014-01-21 11:10:00,33.554 2014-01-21 11:15:00,35.7143 2014-01-21 11:20:00,35.7143 2014-01-21 11:25:00,35.8314 2014-01-21 11:30:00,30.7692 2014-01-21 11:35:00,33.556 2014-01-21 11:40:00,33.4427 2014-01-21 11:45:00,33.5573 2014-01-21 11:50:00,33.446 2014-01-21 11:55:00,35.7143 2014-01-21 12:00:00,35.9543 2014-01-21 12:05:00,35.835 2014-01-21 12:10:00,30.7692 2014-01-21 12:15:00,33.3333 2014-01-21 12:20:00,33.5573 2014-01-21 12:25:00,33.3333 2014-01-21 12:30:00,33.4427 2014-01-21 12:35:00,35.8336 2014-01-21 12:40:00,35.8336 2014-01-21 12:45:00,35.7143 2014-01-21 12:50:00,30.7692 2014-01-21 12:55:00,33.4742 2014-01-21 13:00:00,33.5553 2014-01-21 13:05:00,33.3333 2014-01-21 13:10:00,33.4447 2014-01-21 13:15:00,33.4427 2014-01-21 13:20:00,35.8336 2014-01-21 13:25:00,35.835 2014-01-21 13:30:00,30.7692 2014-01-21 13:35:00,33.47 2014-01-21 13:40:00,33.3333 2014-01-21 13:45:00,33.4447 2014-01-21 13:50:00,33.446 2014-01-21 13:55:00,35.7143 2014-01-21 14:00:00,35.9507 2014-01-21 14:05:00,35.7143 2014-01-21 14:10:00,30.8992 2014-01-21 14:15:00,33.3333 2014-01-21 14:20:00,33.5573 2014-01-21 14:25:00,33.3333 2014-01-21 14:30:00,33.4427 2014-01-21 14:35:00,35.835 2014-01-21 14:40:00,35.7143 2014-01-21 14:45:00,31.0254 2014-01-21 14:50:00,33.3333 2014-01-21 14:55:00,33.446 2014-01-21 15:00:00,33.4447 2014-01-21 15:05:00,33.554 2014-01-21 15:10:00,33.3333 2014-01-21 15:15:00,35.8314 2014-01-21 15:20:00,35.8314 2014-01-21 15:25:00,35.7143 2014-01-21 15:30:00,31.0238 2014-01-21 15:35:00,34.2153 2014-01-21 15:40:00,33.5573 2014-01-21 15:45:00,33.3333 2014-01-21 15:50:00,35.7143 2014-01-21 15:55:00,36.0721 2014-01-21 16:00:00,35.9557 2014-01-21 16:05:00,30.7692 2014-01-21 16:10:00,33.3333 2014-01-21 16:15:00,33.4427 2014-01-21 16:20:00,33.3333 2014-01-21 16:25:00,33.554 2014-01-21 16:30:00,33.3333 2014-01-21 16:35:00,35.8314 2014-01-21 16:40:00,35.8336 2014-01-21 16:45:00,30.7692 2014-01-21 16:50:00,33.556 2014-01-21 16:55:00,33.3333 2014-01-21 17:00:00,33.556 2014-01-21 17:05:00,33.3333 2014-01-21 17:10:00,35.8336 2014-01-21 17:15:00,35.7143 2014-01-21 17:20:00,35.8336 2014-01-21 17:25:00,33.4725 2014-01-21 17:30:00,33.446 2014-01-21 17:35:00,35.4613 2014-01-21 17:40:00,38.2036 2014-01-21 17:45:00,33.5593 2014-01-21 17:50:00,35.8336 2014-01-21 17:55:00,35.8314 2014-01-21 18:00:00,35.8336 2014-01-21 18:05:00,33.4725 2014-01-21 18:10:00,33.446 2014-01-21 18:15:00,33.554 2014-01-21 18:20:00,33.3333 2014-01-21 18:25:00,33.5573 2014-01-21 18:30:00,35.7143 2014-01-21 18:35:00,35.835 2014-01-21 18:40:00,30.8977 2014-01-21 18:45:00,33.3333 2014-01-21 18:50:00,33.556 2014-01-21 18:55:00,33.3333 2014-01-21 19:00:00,33.556 2014-01-21 19:05:00,36.3193 2014-01-21 19:10:00,35.8336 2014-01-21 19:15:00,30.8977 2014-01-21 19:20:00,33.4725 2014-01-21 19:25:00,33.4427 2014-01-21 19:30:00,35.7143 2014-01-21 19:35:00,33.554 2014-01-21 19:40:00,33.3333 2014-01-21 19:45:00,35.7143 2014-01-21 19:50:00,35.8314 2014-01-21 19:55:00,35.7143 2014-01-21 20:00:00,31.0277 2014-01-21 20:05:00,33.3333 2014-01-21 20:10:00,33.4427 2014-01-21 20:15:00,33.3333 2014-01-21 20:20:00,33.552 2014-01-21 20:25:00,33.3333 2014-01-21 20:30:00,33.4427 2014-01-21 20:35:00,35.8336 2014-01-21 20:40:00,35.7143 2014-01-21 20:45:00,31.0254 2014-01-21 20:50:00,33.3333 2014-01-21 20:55:00,33.4447 2014-01-21 21:00:00,35.9543 2014-01-21 21:05:00,33.3333 2014-01-21 21:10:00,33.3333 2014-01-21 21:15:00,33.554 2014-01-21 21:20:00,35.7143 2014-01-21 21:25:00,35.9507 2014-01-21 21:30:00,35.7143 2014-01-21 21:35:00,33.4742 2014-01-21 21:40:00,33.4427 2014-01-21 21:45:00,33.3333 2014-01-21 21:50:00,33.4447 2014-01-21 21:55:00,33.4447 2014-01-21 22:00:00,35.9507 2014-01-21 22:05:00,35.7143 2014-01-21 22:10:00,35.8336 2014-01-21 22:15:00,30.7692 2014-01-21 22:20:00,33.4447 2014-01-21 22:25:00,33.4447 2014-01-21 22:30:00,33.4447 2014-01-21 22:35:00,33.4447 2014-01-21 22:40:00,35.7143 2014-01-21 22:45:00,35.835 2014-01-21 22:50:00,35.7143 2014-01-21 22:55:00,35.8336 2014-01-21 23:00:00,30.8992 2014-01-21 23:05:00,33.6117 2014-01-21 23:10:00,35.7143 2014-01-21 23:15:00,33.4447 2014-01-21 23:20:00,33.4427 2014-01-21 23:25:00,33.4447 2014-01-21 23:30:00,35.8336 2014-01-21 23:35:00,35.7143 2014-01-21 23:40:00,30.8954 2014-01-21 23:45:00,33.4447 2014-01-21 23:50:00,33.446 2014-01-21 23:55:00,33.4427 2014-01-22 00:00:00,33.775999999999996 2014-01-22 00:05:00,39.0314 2014-01-22 00:10:00,37.145 2014-01-22 00:15:00,35.7143 2014-01-22 00:20:00,30.8977 2014-01-22 00:25:00,33.47 2014-01-22 00:30:00,33.4447 2014-01-22 00:35:00,33.4447 2014-01-22 00:40:00,33.3333 2014-01-22 00:45:00,35.835 2014-01-22 00:50:00,35.8336 2014-01-22 00:55:00,35.8314 2014-01-22 01:00:00,35.9543 2014-01-22 01:05:00,30.7692 2014-01-22 01:10:00,33.4725 2014-01-22 01:15:00,33.446 2014-01-22 01:20:00,33.4447 2014-01-22 01:25:00,33.446 2014-01-22 01:30:00,35.7143 2014-01-22 01:35:00,35.9529 2014-01-22 01:40:00,35.7143 2014-01-22 01:45:00,30.8977 2014-01-22 01:50:00,33.4447 2014-01-22 01:55:00,30.7692 2014-01-22 02:00:00,33.554 2014-01-22 02:05:00,33.4447 2014-01-22 02:10:00,35.8336 2014-01-22 02:15:00,35.7143 2014-01-22 02:20:00,37.51 2014-01-22 02:25:00,30.7692 2014-01-22 02:30:00,33.556 2014-01-22 02:35:00,33.3333 2014-01-22 02:40:00,33.4447 2014-01-22 02:45:00,33.446 2014-01-22 02:50:00,35.7143 2014-01-22 02:55:00,31.0238 2014-01-22 03:00:00,30.7692 2014-01-22 03:05:00,33.6667 2014-01-22 03:10:00,33.3333 2014-01-22 03:15:00,33.554 2014-01-22 03:20:00,34.9727 2014-01-22 03:25:00,33.554 2014-01-22 03:30:00,35.7143 2014-01-22 03:35:00,35.8336 2014-01-22 03:40:00,34.6169 2014-01-22 03:45:00,35.2227 2014-01-22 03:50:00,33.3333 2014-01-22 03:55:00,33.3333 2014-01-22 04:00:00,33.5573 2014-01-22 04:05:00,35.9529 2014-01-22 04:10:00,35.7143 2014-01-22 04:15:00,35.835 2014-01-22 04:20:00,33.4725 2014-01-22 04:25:00,33.3333 2014-01-22 04:30:00,33.554 2014-01-22 04:35:00,35.104 2014-01-22 04:40:00,35.1187 2014-01-22 04:45:00,37.7307 2014-01-22 04:50:00,37.4943 2014-01-22 04:55:00,32.7008 2014-01-22 05:00:00,34.1625 2014-01-22 05:05:00,33.4447 2014-01-22 05:10:00,33.3333 2014-01-22 05:15:00,33.4447 2014-01-22 05:20:00,35.8314 2014-01-22 05:25:00,35.8314 2014-01-22 05:30:00,35.7143 2014-01-22 05:35:00,30.7692 2014-01-22 05:40:00,33.47 2014-01-22 05:45:00,33.446 2014-01-22 05:50:00,33.5593 2014-01-22 05:55:00,33.3333 2014-01-22 06:00:00,33.5553 2014-01-22 06:05:00,33.4447 2014-01-22 06:10:00,35.8336 2014-01-22 06:15:00,35.7143 2014-01-22 06:20:00,30.8977 2014-01-22 06:25:00,33.47 2014-01-22 06:30:00,33.4447 2014-01-22 06:35:00,33.446 2014-01-22 06:40:00,33.3333 2014-01-22 06:45:00,33.556 2014-01-22 06:50:00,35.7143 2014-01-22 06:55:00,35.7143 2014-01-22 07:00:00,30.8977 2014-01-22 07:05:00,33.5587 2014-01-22 07:10:00,33.3333 2014-01-22 07:15:00,33.3333 2014-01-22 07:20:00,33.556 2014-01-22 07:25:00,33.3333 2014-01-22 07:30:00,35.9507 2014-01-22 07:35:00,35.7143 2014-01-22 07:40:00,33.4742 2014-01-22 07:45:00,33.4447 2014-01-22 07:50:00,33.3333 2014-01-22 07:55:00,33.5573 2014-01-22 08:00:00,33.4447 2014-01-22 08:05:00,35.835 2014-01-22 08:10:00,35.7143 2014-01-22 08:15:00,31.0277 2014-01-22 08:20:00,33.3333 2014-01-22 08:25:00,33.446 2014-01-22 08:30:00,33.4447 2014-01-22 08:35:00,33.446 2014-01-22 08:40:00,35.7143 2014-01-22 08:45:00,35.8336 2014-01-22 08:50:00,35.835 2014-01-22 08:55:00,33.4725 2014-01-22 09:00:00,33.4447 2014-01-22 09:05:00,33.556 2014-01-22 09:10:00,33.3333 2014-01-22 09:15:00,33.4447 2014-01-22 09:20:00,35.8336 2014-01-22 09:25:00,35.7143 2014-01-22 09:30:00,35.9486 2014-01-22 09:35:00,33.3333 2014-01-22 09:40:00,33.554 2014-01-22 09:45:00,33.3333 2014-01-22 09:50:00,33.3333 2014-01-22 09:55:00,33.556 2014-01-22 10:00:00,35.9507 2014-01-22 10:05:00,35.7143 2014-01-22 10:10:00,30.7692 2014-01-22 10:15:00,33.4725 2014-01-22 10:20:00,33.3333 2014-01-22 10:25:00,31.0238 2014-01-22 10:30:00,33.3333 2014-01-22 10:35:00,33.3333 2014-01-22 10:40:00,35.9521 2014-01-22 10:45:00,35.7143 2014-01-22 10:50:00,35.8336 2014-01-22 10:55:00,33.3333 2014-01-22 11:00:00,33.5587 2014-01-22 11:05:00,33.4427 2014-01-22 11:10:00,33.4447 2014-01-22 11:15:00,33.3333 2014-01-22 11:20:00,35.835 2014-01-22 11:25:00,35.8314 2014-01-22 11:30:00,35.835 2014-01-22 11:35:00,33.3333 2014-01-22 11:40:00,33.4427 2014-01-22 11:45:00,33.3333 2014-01-22 11:50:00,33.4447 2014-01-22 11:55:00,35.835 2014-01-22 12:00:00,35.9529 2014-01-22 12:05:00,30.7692 2014-01-22 12:10:00,30.8992 2014-01-22 12:15:00,33.4427 2014-01-22 12:20:00,33.4427 2014-01-22 12:25:00,33.3333 2014-01-22 12:30:00,33.3333 2014-01-22 12:35:00,33.6633 2014-01-22 12:40:00,35.835 2014-01-22 12:45:00,35.8336 2014-01-22 12:50:00,35.8336 2014-01-22 12:55:00,30.7692 2014-01-22 13:00:00,33.554 2014-01-22 13:05:00,33.4447 2014-01-22 13:10:00,33.4427 2014-01-22 13:15:00,33.3333 2014-01-22 13:20:00,33.4447 2014-01-22 13:25:00,35.8336 2014-01-22 13:30:00,35.8336 2014-01-22 13:35:00,33.4725 2014-01-22 13:40:00,33.3333 2014-01-22 13:45:00,33.4447 2014-01-22 13:50:00,33.4427 2014-01-22 13:55:00,33.446 2014-01-22 14:00:00,36.3114 2014-01-22 14:05:00,35.7143 2014-01-22 14:10:00,30.8992 2014-01-22 14:15:00,33.4725 2014-01-22 14:20:00,34.8987 2014-01-22 14:25:00,33.3333 2014-01-22 14:30:00,37.2679 2014-01-22 14:35:00,35.8314 2014-01-22 14:40:00,35.7143 2014-01-22 14:45:00,35.8314 2014-01-22 14:50:00,30.7692 2014-01-22 14:55:00,33.4725 2014-01-22 15:00:00,33.556 2014-01-22 15:05:00,30.8992 2014-01-22 15:10:00,33.3333 2014-01-22 15:15:00,33.4447 2014-01-22 15:20:00,35.8336 2014-01-22 15:25:00,35.7143 2014-01-22 15:30:00,33.6092 2014-01-22 15:35:00,41.3333 2014-01-22 15:40:00,33.554 2014-01-22 15:45:00,33.3333 2014-01-22 15:50:00,33.3333 2014-01-22 15:55:00,35.9507 2014-01-22 16:00:00,35.9507 2014-01-22 16:05:00,30.7692 2014-01-22 16:10:00,33.3333 2014-01-22 16:15:00,33.554 2014-01-22 16:20:00,33.3333 2014-01-22 16:25:00,33.5553 2014-01-22 16:30:00,35.7143 2014-01-22 16:35:00,35.8314 2014-01-22 16:40:00,31.0262 2014-01-22 16:45:00,33.3333 2014-01-22 16:50:00,33.4447 2014-01-22 16:55:00,33.3333 2014-01-22 17:00:00,33.556 2014-01-22 17:05:00,33.3333 2014-01-22 17:10:00,35.9543 2014-01-22 17:15:00,35.7143 2014-01-22 17:20:00,36.0693 2014-01-22 17:25:00,30.7692 2014-01-22 17:30:00,33.4742 2014-01-22 17:35:00,34.5633 2014-01-22 17:40:00,35.104 2014-01-22 17:45:00,31.0254 2014-01-22 17:50:00,35.7143 2014-01-22 17:55:00,35.8336 2014-01-22 18:00:00,35.7143 2014-01-22 18:05:00,35.9521 2014-01-22 18:10:00,30.7692 2014-01-22 18:15:00,33.6108 2014-01-22 18:20:00,33.3333 2014-01-22 18:25:00,33.3333 2014-01-22 18:30:00,33.5553 2014-01-22 18:35:00,33.3333 2014-01-22 18:40:00,35.8314 2014-01-22 18:45:00,35.7143 2014-01-22 18:50:00,30.8954 2014-01-22 18:55:00,33.4447 2014-01-22 19:00:00,33.5573 2014-01-22 19:05:00,33.3333 2014-01-22 19:10:00,33.4742 2014-01-22 19:15:00,35.8336 2014-01-22 19:20:00,35.7143 2014-01-22 19:25:00,35.8314 2014-01-22 19:30:00,30.7692 2014-01-22 19:35:00,33.4725 2014-01-22 19:40:00,35.8336 2014-01-22 19:45:00,33.4427 2014-01-22 19:50:00,33.3333 2014-01-22 19:55:00,33.4447 2014-01-22 20:00:00,33.5573 2014-01-22 20:05:00,35.8336 2014-01-22 20:10:00,35.7143 2014-01-22 20:15:00,35.835 2014-01-22 20:20:00,33.4742 2014-01-22 20:25:00,35.8336 2014-01-22 20:30:00,33.4447 2014-01-22 20:35:00,33.3333 2014-01-22 20:40:00,33.5553 2014-01-22 20:45:00,35.7143 2014-01-22 20:50:00,35.7143 2014-01-22 20:55:00,30.8954 2014-01-22 21:00:00,33.4742 2014-01-22 21:05:00,33.446 2014-01-22 21:10:00,33.4427 2014-01-22 21:15:00,33.4447 2014-01-22 21:20:00,35.7143 2014-01-22 21:25:00,35.9521 2014-01-22 21:30:00,35.7143 2014-01-22 21:35:00,30.7692 2014-01-22 21:40:00,33.47 2014-01-22 21:45:00,33.3333 2014-01-22 21:50:00,33.5573 2014-01-22 21:55:00,33.3333 2014-01-22 22:00:00,35.9521 2014-01-22 22:05:00,35.7143 2014-01-22 22:10:00,35.9543 2014-01-22 22:15:00,35.7143 2014-01-22 22:20:00,30.7692 2014-01-22 22:25:00,33.5553 2014-01-22 22:30:00,33.3333 2014-01-22 22:35:00,33.5587 2014-01-22 22:40:00,33.3333 2014-01-22 22:45:00,33.3333 2014-01-22 22:50:00,35.835 2014-01-22 22:55:00,35.7143 2014-01-22 23:00:00,35.9507 2014-01-22 23:05:00,30.8992 2014-01-22 23:10:00,33.47 2014-01-22 23:15:00,33.3333 2014-01-22 23:20:00,33.5573 2014-01-22 23:25:00,35.7143 2014-01-22 23:30:00,33.446 2014-01-22 23:35:00,35.8336 2014-01-22 23:40:00,35.7143 2014-01-22 23:45:00,30.8954 2014-01-22 23:50:00,33.3333 2014-01-22 23:55:00,33.446 2014-01-23 00:00:00,33.554 2014-01-23 00:05:00,33.446 2014-01-23 00:10:00,33.4447 2014-01-23 00:15:00,35.8314 2014-01-23 00:20:00,35.8314 2014-01-23 00:25:00,30.8992 2014-01-23 00:30:00,33.3333 2014-01-23 00:35:00,33.5573 2014-01-23 00:40:00,33.3333 2014-01-23 00:45:00,33.4447 2014-01-23 00:50:00,35.835 2014-01-23 00:55:00,35.7143 2014-01-23 01:00:00,35.9507 2014-01-23 01:05:00,33.4742 2014-01-23 01:10:00,33.4427 2014-01-23 01:15:00,33.3333 2014-01-23 01:20:00,33.5573 2014-01-23 01:25:00,33.3333 2014-01-23 01:30:00,35.9507 2014-01-23 01:35:00,35.7143 2014-01-23 01:40:00,31.0254 2014-01-23 01:45:00,33.446 2014-01-23 01:50:00,33.4447 2014-01-23 01:55:00,33.446 2014-01-23 02:00:00,33.6092 2014-01-23 02:05:00,33.3333 2014-01-23 02:10:00,35.8336 2014-01-23 02:15:00,35.835 2014-01-23 02:20:00,35.8336 2014-01-23 02:25:00,33.47 2014-01-23 02:30:00,33.3333 2014-01-23 02:35:00,33.556 2014-01-23 02:40:00,33.3333 2014-01-23 02:45:00,35.7143 2014-01-23 02:50:00,35.835 2014-01-23 02:55:00,35.7143 2014-01-23 03:00:00,31.0262 2014-01-23 03:05:00,35.5933 2014-01-23 03:10:00,35.835 2014-01-23 03:15:00,33.4427 2014-01-23 03:20:00,35.2207 2014-01-23 03:25:00,33.4447 2014-01-23 03:30:00,35.835 2014-01-23 03:35:00,35.7143 2014-01-23 03:40:00,30.7692 2014-01-23 03:45:00,33.4742 2014-01-23 03:50:00,30.8954 2014-01-23 03:55:00,33.446 2014-01-23 04:00:00,35.54 2014-01-23 04:05:00,33.446 2014-01-23 04:10:00,35.9507 2014-01-23 04:15:00,35.7143 2014-01-23 04:20:00,30.8992 2014-01-23 04:25:00,33.4427 2014-01-23 04:30:00,33.554 2014-01-23 04:35:00,33.446 2014-01-23 04:40:00,33.3333 2014-01-23 04:45:00,35.835 2014-01-23 04:50:00,35.8336 2014-01-23 04:55:00,35.835 2014-01-23 05:00:00,33.47 2014-01-23 05:05:00,33.446 2014-01-23 05:10:00,34.6667 2014-01-23 05:15:00,33.4447 2014-01-23 05:20:00,34.786 2014-01-23 05:25:00,35.7143 2014-01-23 05:30:00,35.835 2014-01-23 05:35:00,30.8954 2014-01-23 05:40:00,33.4725 2014-01-23 05:45:00,33.4427 2014-01-23 05:50:00,33.3333 2014-01-23 05:55:00,33.4447 2014-01-23 06:00:00,35.9507 2014-01-23 06:05:00,35.8336 2014-01-23 06:10:00,35.7143 2014-01-23 06:15:00,30.8977 2014-01-23 06:20:00,33.4725 2014-01-23 06:25:00,33.4447 2014-01-23 06:30:00,33.4447 2014-01-23 06:35:00,33.3333 2014-01-23 06:40:00,33.5573 2014-01-23 06:45:00,35.7143 2014-01-23 06:50:00,35.7143 2014-01-23 06:55:00,35.8336 2014-01-23 07:00:00,30.8977 2014-01-23 07:05:00,33.4427 2014-01-23 07:10:00,33.4447 2014-01-23 07:15:00,33.446 2014-01-23 07:20:00,33.3333 2014-01-23 07:25:00,35.9507 2014-01-23 07:30:00,35.7143 2014-01-23 07:35:00,35.7143 2014-01-23 07:40:00,33.4742 2014-01-23 07:45:00,33.3333 2014-01-23 07:50:00,33.5573 2014-01-23 07:55:00,33.3333 2014-01-23 08:00:00,33.554 2014-01-23 08:05:00,35.7143 2014-01-23 08:10:00,36.1864 2014-01-23 08:15:00,32.0477 2014-01-23 08:20:00,33.4725 2014-01-23 08:25:00,35.8314 2014-01-23 08:30:00,33.3333 2014-01-23 08:35:00,33.4447 2014-01-23 08:40:00,33.4427 2014-01-23 08:45:00,35.7143 2014-01-23 08:50:00,35.9543 2014-01-23 08:55:00,35.7143 2014-01-23 09:00:00,35.9543 2014-01-23 09:05:00,35.0 2014-01-23 09:10:00,37.8727 2014-01-23 09:15:00,38.1107 2014-01-23 09:20:00,35.2353 2014-01-23 09:25:00,33.4447 2014-01-23 09:30:00,35.8336 2014-01-23 09:35:00,40.5943 2014-01-23 09:40:00,41.8871 2014-01-23 09:45:00,34.1054 2014-01-23 09:50:00,33.3333 2014-01-23 09:55:00,33.4447 2014-01-23 10:00:00,35.8336 2014-01-23 10:05:00,33.552 2014-01-23 10:10:00,35.7143 2014-01-23 10:15:00,35.835 2014-01-23 10:20:00,35.835 2014-01-23 10:25:00,30.7692 2014-01-23 10:30:00,33.446 2014-01-23 10:35:00,33.3333 2014-01-23 10:40:00,30.8977 2014-01-23 10:45:00,33.446 2014-01-23 10:50:00,35.7143 2014-01-23 10:55:00,35.9529 2014-01-23 11:00:00,31.0238 2014-01-23 11:05:00,33.3333 2014-01-23 11:10:00,33.4447 2014-01-23 11:15:00,33.446 2014-01-23 11:20:00,33.3333 2014-01-23 11:25:00,33.47 2014-01-23 11:30:00,35.7143 2014-01-23 11:35:00,30.7692 2014-01-23 11:40:00,33.6092 2014-01-23 11:45:00,33.3333 2014-01-23 11:50:00,33.554 2014-01-23 11:55:00,33.3333 2014-01-23 12:00:00,33.554 2014-01-23 12:05:00,35.7143 2014-01-23 12:10:00,35.8314 2014-01-23 12:15:00,33.3333 2014-01-23 12:20:00,33.3333 2014-01-23 12:25:00,35.9507 2014-01-23 12:30:00,33.3333 2014-01-23 12:35:00,33.446 2014-01-23 12:40:00,33.4447 2014-01-23 12:45:00,35.8314 2014-01-23 12:50:00,35.7143 2014-01-23 12:55:00,30.7692 2014-01-23 13:00:00,33.6092 2014-01-23 13:05:00,33.4427 2014-01-23 13:10:00,33.4447 2014-01-23 13:15:00,33.3333 2014-01-23 13:20:00,35.8314 2014-01-23 13:25:00,35.8336 2014-01-23 13:30:00,35.9543 2014-01-23 13:35:00,33.3333 2014-01-23 13:40:00,33.446 2014-01-23 13:45:00,33.3333 2014-01-23 13:50:00,33.4447 2014-01-23 13:55:00,35.835 2014-01-23 14:00:00,35.8336 2014-01-23 14:05:00,35.835 2014-01-23 14:10:00,30.8977 2014-01-23 14:15:00,33.4725 2014-01-23 14:20:00,33.3333 2014-01-23 14:25:00,33.5573 2014-01-23 14:30:00,33.3333 2014-01-23 14:35:00,33.4447 2014-01-23 14:40:00,35.835 2014-01-23 14:45:00,35.7143 2014-01-23 14:50:00,35.9529 2014-01-23 14:55:00,30.7692 2014-01-23 15:00:00,33.554 2014-01-23 15:05:00,33.3333 2014-01-23 15:10:00,33.552 2014-01-23 15:15:00,33.3333 2014-01-23 15:20:00,35.8314 2014-01-23 15:25:00,35.8336 2014-01-23 15:30:00,35.7143 2014-01-23 15:35:00,30.8954 2014-01-23 15:40:00,33.3333 2014-01-23 15:45:00,33.556 2014-01-23 15:50:00,33.3333 2014-01-23 15:55:00,33.446 2014-01-23 16:00:00,33.4447 2014-01-23 16:05:00,35.9543 2014-01-23 16:10:00,35.7143 2014-01-23 16:15:00,30.8992 2014-01-23 16:20:00,33.4725 2014-01-23 16:25:00,33.3333 2014-01-23 16:30:00,33.5553 2014-01-23 16:35:00,33.3333 2014-01-23 16:40:00,33.554 2014-01-23 16:45:00,35.7143 2014-01-23 16:50:00,35.9529 2014-01-23 16:55:00,30.7692 2014-01-23 17:00:00,33.6117 2014-01-23 17:05:00,33.3333 2014-01-23 17:10:00,33.5573 2014-01-23 17:15:00,33.3333 2014-01-23 17:20:00,33.446 2014-01-23 17:25:00,35.8336 2014-01-23 17:30:00,35.8336 2014-01-23 17:35:00,30.7692 2014-01-23 17:40:00,33.3333 2014-01-23 17:45:00,33.446 2014-01-23 17:50:00,33.4447 2014-01-23 17:55:00,33.4447 2014-01-23 18:00:00,35.8314 2014-01-23 18:05:00,35.835 2014-01-23 18:10:00,35.8336 2014-01-23 18:15:00,30.8992 2014-01-23 18:20:00,33.3333 2014-01-23 18:25:00,33.4447 2014-01-23 18:30:00,33.4447 2014-01-23 18:35:00,33.4427 2014-01-23 18:40:00,33.446 2014-01-23 18:45:00,35.7143 2014-01-23 18:50:00,35.8336 2014-01-23 18:55:00,35.8336 2014-01-23 19:00:00,33.6117 2014-01-23 19:05:00,33.3333 2014-01-23 19:10:00,33.446 2014-01-23 19:15:00,33.446 2014-01-23 19:20:00,33.446 2014-01-23 19:25:00,35.8314 2014-01-23 19:30:00,35.7143 2014-01-23 19:35:00,35.9521 2014-01-23 19:40:00,30.7692 2014-01-23 19:45:00,33.4447 2014-01-23 19:50:00,33.5573 2014-01-23 19:55:00,33.3333 2014-01-23 20:00:00,33.5573 2014-01-23 20:05:00,33.3333 2014-01-23 20:10:00,44.4864 2014-01-23 20:15:00,35.835 2014-01-23 20:20:00,30.8977 2014-01-23 20:25:00,33.3333 2014-01-23 20:30:00,33.446 2014-01-23 20:35:00,33.4447 2014-01-23 20:40:00,33.446 2014-01-23 20:45:00,35.7143 2014-01-23 20:50:00,35.8336 2014-01-23 20:55:00,35.8336 2014-01-23 21:00:00,33.6092 2014-01-23 21:05:00,33.4427 2014-01-23 21:10:00,33.3333 2014-01-23 21:15:00,33.4427 2014-01-23 21:20:00,33.4447 2014-01-23 21:25:00,33.446 2014-01-23 21:30:00,35.7143 2014-01-23 21:35:00,35.8336 2014-01-23 21:40:00,35.8336 2014-01-23 21:45:00,33.3333 2014-01-23 21:50:00,33.4427 2014-01-23 21:55:00,33.3333 2014-01-23 22:00:00,33.554 2014-01-23 22:05:00,35.7143 2014-01-23 22:10:00,33.446 2014-01-23 22:15:00,33.3333 2014-01-23 22:20:00,35.9543 2014-01-23 22:25:00,35.7143 2014-01-23 22:30:00,35.7143 2014-01-23 22:35:00,33.615 2014-01-23 22:40:00,33.3333 2014-01-23 22:45:00,33.554 2014-01-23 22:50:00,33.3333 2014-01-23 22:55:00,33.4427 2014-01-23 23:00:00,33.5573 2014-01-23 23:05:00,33.446 2014-01-23 23:10:00,35.8314 2014-01-23 23:15:00,35.835 2014-01-23 23:20:00,35.8336 2014-01-23 23:25:00,30.7692 2014-01-23 23:30:00,33.4725 2014-01-23 23:35:00,33.4725 2014-01-23 23:40:00,33.4447 2014-01-23 23:45:00,33.4447 2014-01-23 23:50:00,33.3333 2014-01-23 23:55:00,33.446 2014-01-24 00:00:00,33.5553 2014-01-24 00:05:00,35.8336 2014-01-24 00:10:00,35.7143 2014-01-24 00:15:00,35.8336 2014-01-24 00:20:00,30.8977 2014-01-24 00:25:00,33.4725 2014-01-24 00:30:00,33.4447 2014-01-24 00:35:00,33.4427 2014-01-24 00:40:00,33.3333 2014-01-24 00:45:00,33.5587 2014-01-24 00:50:00,33.3333 2014-01-24 00:55:00,33.3333 2014-01-24 01:00:00,35.9557 2014-01-24 01:05:00,35.9543 2014-01-24 01:10:00,35.7143 2014-01-24 01:15:00,30.7692 2014-01-24 01:20:00,33.554 2014-01-24 01:25:00,33.3333 2014-01-24 01:30:00,33.552 2014-01-24 01:35:00,33.3333 2014-01-24 01:40:00,33.5573 2014-01-24 01:45:00,33.3333 2014-01-24 01:50:00,35.552 2014-01-24 01:55:00,38.3343 2014-01-24 02:00:00,38.575 2014-01-24 02:05:00,37.85 2014-01-24 02:10:00,36.7843 2014-01-24 02:15:00,30.8977 2014-01-24 02:20:00,33.3333 2014-01-24 02:25:00,33.554 2014-01-24 02:30:00,33.3333 2014-01-24 02:35:00,33.554 2014-01-24 02:40:00,33.3333 2014-01-24 02:45:00,33.3333 2014-01-24 02:50:00,35.9543 2014-01-24 02:55:00,35.7143 2014-01-24 03:00:00,35.9557 2014-01-24 03:05:00,32.0408 2014-01-24 03:10:00,33.3333 2014-01-24 03:15:00,33.446 2014-01-24 03:20:00,33.4447 2014-01-24 03:25:00,33.3333 2014-01-24 03:30:00,33.554 2014-01-24 03:35:00,33.3333 2014-01-24 03:40:00,35.9543 2014-01-24 03:45:00,35.7143 2014-01-24 03:50:00,35.8336 2014-01-24 03:55:00,35.835 2014-01-24 04:00:00,35.9543 2014-01-24 04:05:00,33.3333 2014-01-24 04:10:00,33.4447 2014-01-24 04:15:00,33.446 2014-01-24 04:20:00,33.4447 2014-01-24 04:25:00,33.446 2014-01-24 04:30:00,33.3333 2014-01-24 04:35:00,35.8336 2014-01-24 04:40:00,35.835 2014-01-24 04:45:00,35.8314 2014-01-24 04:50:00,30.8977 2014-01-24 04:55:00,33.3333 2014-01-24 05:00:00,33.6067 2014-01-24 05:05:00,33.4447 2014-01-24 05:10:00,33.446 2014-01-24 05:15:00,33.3333 2014-01-24 05:20:00,33.554 2014-01-24 05:25:00,33.3333 2014-01-24 05:30:00,33.4447 2014-01-24 05:35:00,33.4427 2014-01-24 05:40:00,33.3333 2014-01-24 05:45:00,33.554 2014-01-24 05:50:00,35.7143 2014-01-24 05:55:00,35.7143 2014-01-24 06:00:00,35.9507 2014-01-24 06:05:00,35.9543 2014-01-24 06:10:00,35.7143 2014-01-24 06:15:00,35.7143 2014-01-24 06:20:00,35.9521 2014-01-24 06:25:00,35.7143 2014-01-24 06:30:00,35.8314 2014-01-24 06:35:00,35.7143 2014-01-24 06:40:00,35.7143 2014-01-24 06:45:00,31.1523 2014-01-24 06:50:00,35.7143 2014-01-24 06:55:00,30.8954 2014-01-24 07:00:00,30.7692 2014-01-24 07:05:00,33.6108 2014-01-24 07:10:00,30.7692 2014-01-24 07:15:00,33.446 2014-01-24 07:20:00,33.4447 2014-01-24 07:25:00,33.3333 2014-01-24 07:30:00,33.552 2014-01-24 07:35:00,33.3333 2014-01-24 07:40:00,33.446 2014-01-24 07:45:00,33.4447 2014-01-24 07:50:00,33.4427 2014-01-24 07:55:00,33.4447 2014-01-24 08:00:00,35.8336 2014-01-24 08:05:00,35.8336 2014-01-24 08:10:00,35.8336 2014-01-24 08:15:00,35.835 2014-01-24 08:20:00,35.8336 2014-01-24 08:25:00,30.7692 2014-01-24 08:30:00,35.8336 2014-01-24 08:35:00,35.8314 2014-01-24 08:40:00,35.7143 2014-01-24 08:45:00,35.835 2014-01-24 08:50:00,30.7692 2014-01-24 08:55:00,31.0262 2014-01-24 09:00:00,33.4725 2014-01-24 09:05:00,33.4447 2014-01-24 09:10:00,33.3333 2014-01-24 09:15:00,35.8314 2014-01-24 09:20:00,33.3333 2014-01-24 09:25:00,33.556 2014-01-24 09:30:00,33.3333 2014-01-24 09:35:00,33.6653 2014-01-24 09:40:00,33.3333 2014-01-24 09:45:00,33.3333 2014-01-24 09:50:00,33.554 2014-01-24 09:55:00,33.3333 2014-01-24 10:00:00,33.5573 2014-01-24 10:05:00,33.3333 2014-01-24 10:10:00,33.554 2014-01-24 10:15:00,33.3333 2014-01-24 10:20:00,33.554 2014-01-24 10:25:00,33.3333 2014-01-24 10:30:00,30.7692 2014-01-24 10:35:00,35.9507 2014-01-24 10:40:00,35.7143 2014-01-24 10:45:00,35.835 2014-01-24 10:50:00,35.8336 2014-01-24 10:55:00,35.8336 2014-01-24 11:00:00,35.8314 2014-01-24 11:05:00,35.8314 2014-01-24 11:10:00,35.8336 2014-01-24 11:15:00,35.835 2014-01-24 11:20:00,35.8336 2014-01-24 11:25:00,35.7143 2014-01-24 11:30:00,35.8314 2014-01-24 11:35:00,35.8336 2014-01-24 11:40:00,35.8336 2014-01-24 11:45:00,35.8314 2014-01-24 11:50:00,35.835 2014-01-24 11:55:00,35.7143 2014-01-24 12:00:00,35.9543 2014-01-24 12:05:00,35.8336 2014-01-24 12:10:00,35.835 2014-01-24 12:15:00,35.7143 2014-01-24 12:20:00,35.835 2014-01-24 12:25:00,35.835 2014-01-24 12:30:00,35.7143 2014-01-24 12:35:00,35.9543 2014-01-24 12:40:00,35.8336 2014-01-24 12:45:00,35.8314 2014-01-24 12:50:00,35.7143 2014-01-24 12:55:00,30.7692 2014-01-24 13:00:00,31.0238 2014-01-24 13:05:00,33.3333 2014-01-24 13:10:00,34.4407 2014-01-24 13:15:00,33.4447 2014-01-24 13:20:00,33.4447 2014-01-24 13:25:00,33.4447 2014-01-24 13:30:00,33.4427 2014-01-24 13:35:00,33.3333 2014-01-24 13:40:00,33.4447 2014-01-24 13:45:00,33.446 2014-01-24 13:50:00,33.3333 2014-01-24 13:55:00,35.9521 2014-01-24 14:00:00,35.8336 2014-01-24 14:05:00,35.835 2014-01-24 14:10:00,35.7143 2014-01-24 14:15:00,35.9507 2014-01-24 14:20:00,35.7143 2014-01-24 14:25:00,35.8336 2014-01-24 14:30:00,35.8314 2014-01-24 14:35:00,35.7143 2014-01-24 14:40:00,35.9543 2014-01-24 14:45:00,35.7143 2014-01-24 14:50:00,30.7692 2014-01-24 14:55:00,30.8992 2014-01-24 15:00:00,33.4725 2014-01-24 15:05:00,33.3333 2014-01-24 15:10:00,33.4725 2014-01-24 15:15:00,33.4427 2014-01-24 15:20:00,33.3333 2014-01-24 15:25:00,33.5587 2014-01-24 15:30:00,33.3333 2014-01-24 15:35:00,33.9987 2014-01-24 15:40:00,33.3333 2014-01-24 15:45:00,33.3333 2014-01-24 15:50:00,33.556 2014-01-24 15:55:00,33.3333 2014-01-24 16:00:00,33.5587 2014-01-24 16:05:00,33.3333 2014-01-24 16:10:00,33.556 2014-01-24 16:15:00,33.3333 2014-01-24 16:20:00,35.9486 2014-01-24 16:25:00,35.7143 2014-01-24 16:30:00,35.7143 2014-01-24 16:35:00,35.9543 2014-01-24 16:40:00,35.7143 2014-01-24 16:45:00,36.07 2014-01-24 16:50:00,35.7143 2014-01-24 16:55:00,30.8992 2014-01-24 17:00:00,35.8314 2014-01-24 17:05:00,30.8992 2014-01-24 17:10:00,30.7692 2014-01-24 17:15:00,33.3333 2014-01-24 17:20:00,33.4725 2014-01-24 17:25:00,33.3333 2014-01-24 17:30:00,34.4353 2014-01-24 17:35:00,33.5553 2014-01-24 17:40:00,33.3333 2014-01-24 17:45:00,33.446 2014-01-24 17:50:00,33.4447 2014-01-24 17:55:00,33.3333 2014-01-24 18:00:00,33.6092 2014-01-24 18:05:00,33.4427 2014-01-24 18:10:00,30.8992 2014-01-24 18:15:00,35.7143 2014-01-24 18:20:00,35.835 2014-01-24 18:25:00,37.1507 2014-01-24 18:30:00,35.8336 2014-01-24 18:35:00,35.8336 2014-01-24 18:40:00,35.7143 2014-01-24 18:45:00,31.0254 2014-01-24 18:50:00,30.7692 2014-01-24 18:55:00,33.47 2014-01-24 19:00:00,33.446 2014-01-24 19:05:00,33.4447 2014-01-24 19:10:00,33.3333 2014-01-24 19:15:00,33.4447 2014-01-24 19:20:00,33.4447 2014-01-24 19:25:00,33.4447 2014-01-24 19:30:00,33.4447 2014-01-24 19:35:00,33.3333 2014-01-24 19:40:00,33.446 2014-01-24 19:45:00,33.446 2014-01-24 19:50:00,33.446 2014-01-24 19:55:00,35.7143 2014-01-24 20:00:00,33.6667 2014-01-24 20:05:00,35.8336 2014-01-24 20:10:00,35.8336 2014-01-24 20:15:00,35.7143 2014-01-24 20:20:00,35.9543 2014-01-24 20:25:00,35.7143 2014-01-24 20:30:00,35.8314 2014-01-24 20:35:00,35.7143 2014-01-24 20:40:00,35.7143 2014-01-24 20:45:00,31.0238 2014-01-24 20:50:00,30.7692 2014-01-24 20:55:00,30.8992 2014-01-24 21:00:00,30.8977 2014-01-24 21:05:00,31.0254 2014-01-24 21:10:00,33.3333 2014-01-24 21:15:00,33.4427 2014-01-24 21:20:00,33.4427 2014-01-24 21:25:00,33.3333 2014-01-24 21:30:00,33.446 2014-01-24 21:35:00,33.4447 2014-01-24 21:40:00,33.4447 2014-01-24 21:45:00,33.4447 2014-01-24 21:50:00,33.4447 2014-01-24 21:55:00,33.3333 2014-01-24 22:00:00,33.5573 2014-01-24 22:05:00,33.4447 2014-01-24 22:10:00,33.446 2014-01-24 22:15:00,33.3333 2014-01-24 22:20:00,33.4447 2014-01-24 22:25:00,33.4427 2014-01-24 22:30:00,33.3333 2014-01-24 22:35:00,35.9529 2014-01-24 22:40:00,35.7143 2014-01-24 22:45:00,35.8314 2014-01-24 22:50:00,35.8314 2014-01-24 22:55:00,35.7143 2014-01-24 23:00:00,35.9486 2014-01-24 23:05:00,33.47 2014-01-24 23:10:00,35.8336 2014-01-24 23:15:00,30.7692 2014-01-24 23:20:00,31.0254 2014-01-24 23:25:00,30.7692 2014-01-24 23:30:00,33.4725 2014-01-24 23:35:00,33.4447 2014-01-24 23:40:00,33.3333 2014-01-24 23:45:00,33.5573 2014-01-24 23:50:00,33.3333 2014-01-24 23:55:00,33.4427 2014-01-25 00:00:00,33.4447 2014-01-25 00:05:00,33.5553 2014-01-25 00:10:00,33.3333 2014-01-25 00:15:00,35.8336 2014-01-25 00:20:00,33.4447 2014-01-25 00:25:00,35.835 2014-01-25 00:30:00,35.8336 2014-01-25 00:35:00,35.7143 2014-01-25 00:40:00,33.47 2014-01-25 00:45:00,33.4725 2014-01-25 00:50:00,36.8014 2014-01-25 00:55:00,35.7143 2014-01-25 01:00:00,35.9557 2014-01-25 01:05:00,30.7692 2014-01-25 01:10:00,31.0262 2014-01-25 01:15:00,33.3333 2014-01-25 01:20:00,33.47 2014-01-25 01:25:00,33.4447 2014-01-25 01:30:00,33.3333 2014-01-25 01:35:00,33.4427 2014-01-25 01:40:00,33.4447 2014-01-25 01:45:00,33.4427 2014-01-25 01:50:00,33.4447 2014-01-25 01:55:00,33.3333 2014-01-25 02:00:00,33.554 2014-01-25 02:05:00,35.835 2014-01-25 02:10:00,35.8314 2014-01-25 02:15:00,35.8314 2014-01-25 02:20:00,35.7143 2014-01-25 02:25:00,35.835 2014-01-25 02:30:00,33.47 2014-01-25 02:35:00,35.8336 2014-01-25 02:40:00,30.8992 2014-01-25 02:45:00,30.7692 2014-01-25 02:50:00,33.4725 2014-01-25 02:55:00,33.47 2014-01-25 03:00:00,33.6092 2014-01-25 03:05:00,33.3333 2014-01-25 03:10:00,33.446 2014-01-25 03:15:00,35.222 2014-01-25 03:20:00,33.556 2014-01-25 03:25:00,33.3333 2014-01-25 03:30:00,35.8336 2014-01-25 03:35:00,33.3333 2014-01-25 03:40:00,35.082 2014-01-25 03:45:00,35.8314 2014-01-25 03:50:00,35.7143 2014-01-25 03:55:00,35.9543 2014-01-25 04:00:00,35.835 2014-01-25 04:05:00,35.8336 2014-01-25 04:10:00,35.7143 2014-01-25 04:15:00,35.9543 2014-01-25 04:20:00,30.7692 2014-01-25 04:25:00,30.8977 2014-01-25 04:30:00,33.4725 2014-01-25 04:35:00,33.3333 2014-01-25 04:40:00,33.6673 2014-01-25 04:45:00,33.3333 2014-01-25 04:50:00,33.3333 2014-01-25 04:55:00,33.5587 2014-01-25 05:00:00,33.5573 2014-01-25 05:05:00,33.3333 2014-01-25 05:10:00,30.7692 2014-01-25 05:15:00,33.552 2014-01-25 05:20:00,33.3333 2014-01-25 05:25:00,33.556 2014-01-25 05:30:00,35.7143 2014-01-25 05:35:00,35.7143 2014-01-25 05:40:00,35.9557 2014-01-25 05:45:00,35.7143 2014-01-25 05:50:00,35.9529 2014-01-25 05:55:00,35.8314 2014-01-25 06:00:00,35.9521 2014-01-25 06:05:00,30.7692 2014-01-25 06:10:00,30.8992 2014-01-25 06:15:00,30.8977 2014-01-25 06:20:00,33.3333 2014-01-25 06:25:00,35.8336 2014-01-25 06:30:00,33.3333 2014-01-25 06:35:00,33.446 2014-01-25 06:40:00,33.446 2014-01-25 06:45:00,33.446 2014-01-25 06:50:00,33.3333 2014-01-25 06:55:00,33.4447 2014-01-25 07:00:00,35.9529 2014-01-25 07:05:00,35.8314 2014-01-25 07:10:00,35.7143 2014-01-25 07:15:00,35.8336 2014-01-25 07:20:00,35.8314 2014-01-25 07:25:00,35.8314 2014-01-25 07:30:00,35.8314 2014-01-25 07:35:00,35.7143 2014-01-25 07:40:00,35.8336 2014-01-25 07:45:00,30.8954 2014-01-25 07:50:00,30.7692 2014-01-25 07:55:00,31.0262 2014-01-25 08:00:00,33.4725 2014-01-25 08:05:00,33.4742 2014-01-25 08:10:00,33.4447 2014-01-25 08:15:00,33.446 2014-01-25 08:20:00,33.4447 2014-01-25 08:25:00,33.4427 2014-01-25 08:30:00,33.3333 2014-01-25 08:35:00,31.0238 2014-01-25 08:40:00,33.3333 2014-01-25 08:45:00,33.3333 2014-01-25 08:50:00,35.9543 2014-01-25 08:55:00,35.7143 2014-01-25 09:00:00,35.9543 2014-01-25 09:05:00,35.7143 2014-01-25 09:10:00,35.9507 2014-01-25 09:15:00,35.7143 2014-01-25 09:20:00,35.835 2014-01-25 09:25:00,30.7692 2014-01-25 09:30:00,30.7692 2014-01-25 09:35:00,31.0215 2014-01-25 09:40:00,33.3333 2014-01-25 09:45:00,33.446 2014-01-25 09:50:00,33.446 2014-01-25 09:55:00,33.3333 2014-01-25 10:00:00,33.556 2014-01-25 10:05:00,33.446 2014-01-25 10:10:00,33.4447 2014-01-25 10:15:00,33.3333 2014-01-25 10:20:00,33.4427 2014-01-25 10:25:00,33.4447 2014-01-25 10:30:00,33.4427 2014-01-25 10:35:00,33.4447 2014-01-25 10:40:00,33.4427 2014-01-25 10:45:00,35.7143 2014-01-25 10:50:00,35.8314 2014-01-25 10:55:00,35.835 2014-01-25 11:00:00,35.9543 2014-01-25 11:05:00,35.7143 2014-01-25 11:10:00,35.8314 2014-01-25 11:15:00,30.8977 2014-01-25 11:20:00,33.3333 2014-01-25 11:25:00,33.4725 2014-01-25 11:30:00,33.3333 2014-01-25 11:35:00,33.3333 2014-01-25 11:40:00,33.5573 2014-01-25 11:45:00,33.3333 2014-01-25 11:50:00,33.5553 2014-01-25 11:55:00,33.3333 2014-01-25 12:00:00,34.4433 2014-01-25 12:05:00,35.7143 2014-01-25 12:10:00,35.9529 2014-01-25 12:15:00,35.7143 2014-01-25 12:20:00,35.9507 2014-01-25 12:25:00,35.7143 2014-01-25 12:30:00,35.9507 2014-01-25 12:35:00,35.7143 2014-01-25 12:40:00,30.7692 2014-01-25 12:45:00,33.6117 2014-01-25 12:50:00,33.3333 2014-01-25 12:55:00,33.446 2014-01-25 13:00:00,33.4447 2014-01-25 13:05:00,33.556 2014-01-25 13:10:00,33.7813 2014-01-25 13:15:00,33.4447 2014-01-25 13:20:00,33.4447 2014-01-25 13:25:00,33.3333 2014-01-25 13:30:00,33.5573 2014-01-25 13:35:00,33.3333 2014-01-25 13:40:00,35.8314 2014-01-25 13:45:00,35.8336 2014-01-25 13:50:00,35.835 2014-01-25 13:55:00,35.8336 2014-01-25 14:00:00,35.835 2014-01-25 14:05:00,35.8336 2014-01-25 14:10:00,30.8954 2014-01-25 14:15:00,30.7692 2014-01-25 14:20:00,33.3333 2014-01-25 14:25:00,33.4742 2014-01-25 14:30:00,33.4742 2014-01-25 14:35:00,33.4447 2014-01-25 14:40:00,33.3333 2014-01-25 14:45:00,33.4447 2014-01-25 14:50:00,33.4447 2014-01-25 14:55:00,33.556 2014-01-25 15:00:00,33.4427 2014-01-25 15:05:00,33.6647 2014-01-25 15:10:00,33.3333 2014-01-25 15:15:00,33.4447 2014-01-25 15:20:00,33.446 2014-01-25 15:25:00,35.7143 2014-01-25 15:30:00,35.9529 2014-01-25 15:35:00,38.5714 2014-01-25 15:40:00,39.0357 2014-01-25 15:45:00,35.8336 2014-01-25 15:50:00,35.8336 2014-01-25 15:55:00,35.8336 2014-01-25 16:00:00,35.8314 2014-01-25 16:05:00,35.8314 2014-01-25 16:10:00,30.8992 2014-01-25 16:15:00,30.8977 2014-01-25 16:20:00,33.4742 2014-01-25 16:25:00,33.4447 2014-01-25 16:30:00,35.8314 2014-01-25 16:35:00,33.3333 2014-01-25 16:40:00,33.4427 2014-01-25 16:45:00,33.4427 2014-01-25 16:50:00,33.446 2014-01-25 16:55:00,33.446 2014-01-25 17:00:00,33.4447 2014-01-25 17:05:00,33.446 2014-01-25 17:10:00,35.7143 2014-01-25 17:15:00,33.5587 2014-01-25 17:20:00,35.7143 2014-01-25 17:25:00,35.8336 2014-01-25 17:30:00,35.835 2014-01-25 17:35:00,39.5043 2014-01-25 17:40:00,31.0215 2014-01-25 17:45:00,35.7143 2014-01-25 17:50:00,35.835 2014-01-25 17:55:00,35.7143 2014-01-25 18:00:00,35.9543 2014-01-25 18:05:00,30.7692 2014-01-25 18:10:00,33.6092 2014-01-25 18:15:00,33.3333 2014-01-25 18:20:00,33.446 2014-01-25 18:25:00,33.4447 2014-01-25 18:30:00,33.3333 2014-01-25 18:35:00,34.3313 2014-01-25 18:40:00,34.3333 2014-01-25 18:45:00,33.5573 2014-01-25 18:50:00,34.7813 2014-01-25 18:55:00,36.1864 2014-01-25 19:00:00,35.8314 2014-01-25 19:05:00,31.0277 2014-01-25 19:10:00,35.7143 2014-01-25 19:15:00,35.835 2014-01-25 19:20:00,40.3379 2014-01-25 19:25:00,30.7692 2014-01-25 19:30:00,30.8954 2014-01-25 19:35:00,33.3333 2014-01-25 19:40:00,33.4427 2014-01-25 19:45:00,35.8314 2014-01-25 19:50:00,33.4447 2014-01-25 19:55:00,33.3333 2014-01-25 20:00:00,33.554 2014-01-25 20:05:00,33.4447 2014-01-25 20:10:00,33.446 2014-01-25 20:15:00,33.3333 2014-01-25 20:20:00,33.47 2014-01-25 20:25:00,33.4742 2014-01-25 20:30:00,35.7143 2014-01-25 20:35:00,35.9557 2014-01-25 20:40:00,38.9414 2014-01-25 20:45:00,35.8314 2014-01-25 20:50:00,35.8336 2014-01-25 20:55:00,30.7692 2014-01-25 21:00:00,31.0238 2014-01-25 21:05:00,30.7692 2014-01-25 21:10:00,33.47 2014-01-25 21:15:00,33.3333 2014-01-25 21:20:00,33.4427 2014-01-25 21:25:00,33.4447 2014-01-25 21:30:00,33.446 2014-01-25 21:35:00,33.3333 2014-01-25 21:40:00,33.4427 2014-01-25 21:45:00,33.446 2014-01-25 21:50:00,33.4447 2014-01-25 21:55:00,33.446 2014-01-25 22:00:00,33.4447 2014-01-25 22:05:00,35.835 2014-01-25 22:10:00,39.405 2014-01-25 22:15:00,35.835 2014-01-25 22:20:00,35.7143 2014-01-25 22:25:00,35.8336 2014-01-25 22:30:00,35.835 2014-01-25 22:35:00,35.7143 2014-01-25 22:40:00,31.0238 2014-01-25 22:45:00,30.7692 2014-01-25 22:50:00,33.4725 2014-01-25 22:55:00,33.4742 2014-01-25 23:00:00,33.5573 2014-01-25 23:05:00,33.3333 2014-01-25 23:10:00,33.4447 2014-01-25 23:15:00,33.4447 2014-01-25 23:20:00,33.3333 2014-01-25 23:25:00,35.9529 2014-01-25 23:30:00,33.3333 2014-01-25 23:35:00,33.5587 2014-01-25 23:40:00,35.7143 2014-01-25 23:45:00,35.835 2014-01-25 23:50:00,39.8614 2014-01-25 23:55:00,35.8336 2014-01-26 00:00:00,35.9521 2014-01-26 00:05:00,35.8314 2014-01-26 00:10:00,35.7143 2014-01-26 00:15:00,35.9543 2014-01-26 00:20:00,30.7692 2014-01-26 00:25:00,30.8977 2014-01-26 00:30:00,30.8954 2014-01-26 00:35:00,33.3333 2014-01-26 00:40:00,33.5553 2014-01-26 00:45:00,33.3333 2014-01-26 00:50:00,30.7692 2014-01-26 00:55:00,35.9529 2014-01-26 01:00:00,33.5573 2014-01-26 01:05:00,33.3333 2014-01-26 01:10:00,33.5587 2014-01-26 01:15:00,33.3333 2014-01-26 01:20:00,33.3333 2014-01-26 01:25:00,33.6067 2014-01-26 01:30:00,36.13 2014-01-26 01:35:00,37.1429 2014-01-26 01:40:00,35.7143 2014-01-26 01:45:00,35.9507 2014-01-26 01:50:00,35.7143 2014-01-26 01:55:00,35.7143 2014-01-26 02:00:00,35.9543 2014-01-26 02:05:00,35.9507 2014-01-26 02:10:00,30.7692 2014-01-26 02:15:00,31.0254 2014-01-26 02:20:00,33.3333 2014-01-26 02:25:00,33.4427 2014-01-26 02:30:00,33.5573 2014-01-26 02:35:00,33.3333 2014-01-26 02:40:00,33.5573 2014-01-26 02:45:00,33.3333 2014-01-26 02:50:00,33.3333 2014-01-26 02:55:00,33.6687 2014-01-26 03:00:00,33.5573 2014-01-26 03:05:00,33.3333 2014-01-26 03:10:00,37.5879 2014-01-26 03:15:00,39.7621 2014-01-26 03:20:00,37.705 2014-01-26 03:25:00,30.7692 2014-01-26 03:30:00,35.835 2014-01-26 03:35:00,35.8314 2014-01-26 03:40:00,30.7692 2014-01-26 03:45:00,30.8992 2014-01-26 03:50:00,30.7692 2014-01-26 03:55:00,33.615 2014-01-26 04:00:00,33.3333 2014-01-26 04:05:00,33.4447 2014-01-26 04:10:00,33.3333 2014-01-26 04:15:00,33.5553 2014-01-26 04:20:00,35.7143 2014-01-26 04:25:00,33.3333 2014-01-26 04:30:00,35.9543 2014-01-26 04:35:00,33.3333 2014-01-26 04:40:00,33.5553 2014-01-26 04:45:00,33.3333 2014-01-26 04:50:00,33.3333 2014-01-26 04:55:00,38.9314 2014-01-26 05:00:00,34.1127 2014-01-26 05:05:00,33.3333 2014-01-26 05:10:00,35.8336 2014-01-26 05:15:00,35.835 2014-01-26 05:20:00,35.835 2014-01-26 05:25:00,35.835 2014-01-26 05:30:00,30.7692 2014-01-26 05:35:00,35.9529 2014-01-26 05:40:00,35.7143 2014-01-26 05:45:00,30.7692 2014-01-26 05:50:00,33.6108 2014-01-26 05:55:00,33.3333 2014-01-26 06:00:00,33.556 2014-01-26 06:05:00,33.3333 2014-01-26 06:10:00,33.556 2014-01-26 06:15:00,33.3333 2014-01-26 06:20:00,33.3333 2014-01-26 06:25:00,33.5553 2014-01-26 06:30:00,33.3333 2014-01-26 06:35:00,35.872 2014-01-26 06:40:00,35.556 2014-01-26 06:45:00,33.446 2014-01-26 06:50:00,33.4447 2014-01-26 06:55:00,33.3333 2014-01-26 07:00:00,35.9557 2014-01-26 07:05:00,35.9521 2014-01-26 07:10:00,35.7143 2014-01-26 07:15:00,35.7143 2014-01-26 07:20:00,35.9543 2014-01-26 07:25:00,30.7692 2014-01-26 07:30:00,35.835 2014-01-26 07:35:00,33.3333 2014-01-26 07:40:00,30.7692 2014-01-26 07:45:00,31.0238 2014-01-26 07:50:00,33.3333 2014-01-26 07:55:00,33.4427 2014-01-26 08:00:00,30.8977 2014-01-26 08:05:00,33.552 2014-01-26 08:10:00,33.3333 2014-01-26 08:15:00,35.22400000000001 2014-01-26 08:20:00,36.1093 2014-01-26 08:25:00,33.4447 2014-01-26 08:30:00,33.446 2014-01-26 08:35:00,35.7143 2014-01-26 08:40:00,35.835 2014-01-26 08:45:00,36.3114 2014-01-26 08:50:00,36.3079 2014-01-26 08:55:00,35.8314 2014-01-26 09:00:00,35.835 2014-01-26 09:05:00,35.835 2014-01-26 09:10:00,35.8314 2014-01-26 09:15:00,30.8977 2014-01-26 09:20:00,35.8336 2014-01-26 09:25:00,35.7143 2014-01-26 09:30:00,30.8992 2014-01-26 09:35:00,33.4742 2014-01-26 09:40:00,33.4725 2014-01-26 09:45:00,33.446 2014-01-26 09:50:00,33.4447 2014-01-26 09:55:00,33.8887 2014-01-26 10:00:00,38.46 2014-01-26 10:05:00,33.556 2014-01-26 10:10:00,33.3333 2014-01-26 10:15:00,33.3333 2014-01-26 10:20:00,33.5573 2014-01-26 10:25:00,33.3333 2014-01-26 10:30:00,35.8336 2014-01-26 10:35:00,35.7143 2014-01-26 10:40:00,35.8314 2014-01-26 10:45:00,35.8336 2014-01-26 10:50:00,35.7143 2014-01-26 10:55:00,35.835 2014-01-26 11:00:00,35.9521 2014-01-26 11:05:00,35.7143 2014-01-26 11:10:00,30.7692 2014-01-26 11:15:00,33.4725 2014-01-26 11:20:00,33.4447 2014-01-26 11:25:00,33.4427 2014-01-26 11:30:00,33.3333 2014-01-26 11:35:00,33.4447 2014-01-26 11:40:00,37.8707 2014-01-26 11:45:00,33.446 2014-01-26 11:50:00,33.446 2014-01-26 11:55:00,33.4447 2014-01-26 12:00:00,33.5553 2014-01-26 12:05:00,35.7143 2014-01-26 12:10:00,35.835 2014-01-26 12:15:00,35.8336 2014-01-26 12:20:00,35.8314 2014-01-26 12:25:00,35.7143 2014-01-26 12:30:00,35.835 2014-01-26 12:35:00,31.0238 2014-01-26 12:40:00,33.4725 2014-01-26 12:45:00,33.4427 2014-01-26 12:50:00,33.3333 2014-01-26 12:55:00,33.552 2014-01-26 13:00:00,33.446 2014-01-26 13:05:00,33.4427 2014-01-26 13:10:00,33.3333 2014-01-26 13:15:00,33.5573 2014-01-26 13:20:00,36.3313 2014-01-26 13:25:00,34.8893 2014-01-26 13:30:00,33.47 2014-01-26 13:35:00,33.446 2014-01-26 13:40:00,35.9507 2014-01-26 13:45:00,35.7143 2014-01-26 13:50:00,35.8336 2014-01-26 13:55:00,35.7143 2014-01-26 14:00:00,35.9543 2014-01-26 14:05:00,35.7143 2014-01-26 14:10:00,35.9543 2014-01-26 14:15:00,30.7692 2014-01-26 14:20:00,33.3333 2014-01-26 14:25:00,33.556 2014-01-26 14:30:00,33.3333 2014-01-26 14:35:00,33.5553 2014-01-26 14:40:00,33.3333 2014-01-26 14:45:00,33.446 2014-01-26 14:50:00,33.4447 2014-01-26 14:55:00,33.3333 2014-01-26 15:00:00,35.455999999999996 2014-01-26 15:05:00,36.11 2014-01-26 15:10:00,33.3333 2014-01-26 15:15:00,33.3333 2014-01-26 15:20:00,35.9529 2014-01-26 15:25:00,35.8314 2014-01-26 15:30:00,35.8336 2014-01-26 15:35:00,37.8621 2014-01-26 15:40:00,38.2136 2014-01-26 15:45:00,30.8954 2014-01-26 15:50:00,36.8986 2014-01-26 15:55:00,30.7692 2014-01-26 16:00:00,33.6133 2014-01-26 16:05:00,33.6133 2014-01-26 16:10:00,33.3333 2014-01-26 16:15:00,33.3333 2014-01-26 16:20:00,33.5553 2014-01-26 16:25:00,33.3333 2014-01-26 16:30:00,33.5553 2014-01-26 16:35:00,33.3333 2014-01-26 16:40:00,34.3347 2014-01-26 16:45:00,36.984 2014-01-26 16:50:00,33.3333 2014-01-26 16:55:00,35.9507 2014-01-26 17:00:00,33.4427 2014-01-26 17:05:00,35.8336 2014-01-26 17:10:00,35.7143 2014-01-26 17:15:00,35.9521 2014-01-26 17:20:00,35.7143 2014-01-26 17:25:00,35.835 2014-01-26 17:30:00,35.835 2014-01-26 17:35:00,35.7143 2014-01-26 17:40:00,35.835 2014-01-26 17:45:00,35.7143 2014-01-26 17:50:00,30.8977 2014-01-26 17:55:00,33.4725 2014-01-26 18:00:00,33.446 2014-01-26 18:05:00,33.4427 2014-01-26 18:10:00,33.446 2014-01-26 18:15:00,33.4447 2014-01-26 18:20:00,33.4447 2014-01-26 18:25:00,37.906 2014-01-26 18:30:00,33.556 2014-01-26 18:35:00,33.3333 2014-01-26 18:40:00,35.7143 2014-01-26 18:45:00,35.9543 2014-01-26 18:50:00,35.7143 2014-01-26 18:55:00,35.835 2014-01-26 19:00:00,35.835 2014-01-26 19:05:00,35.9543 2014-01-26 19:10:00,35.7143 2014-01-26 19:15:00,35.835 2014-01-26 19:20:00,35.8336 2014-01-26 19:25:00,30.8954 2014-01-26 19:30:00,33.4742 2014-01-26 19:35:00,33.3333 2014-01-26 19:40:00,33.446 2014-01-26 19:45:00,33.4447 2014-01-26 19:50:00,33.4447 2014-01-26 19:55:00,33.4447 2014-01-26 20:00:00,33.4447 2014-01-26 20:05:00,38.111999999999995 2014-01-26 20:10:00,33.5553 2014-01-26 20:15:00,33.3333 2014-01-26 20:20:00,33.5573 2014-01-26 20:25:00,33.3333 2014-01-26 20:30:00,33.4427 2014-01-26 20:35:00,35.8336 2014-01-26 20:40:00,35.7143 2014-01-26 20:45:00,35.8314 2014-01-26 20:50:00,35.835 2014-01-26 20:55:00,35.8336 2014-01-26 21:00:00,35.8314 2014-01-26 21:05:00,35.8314 2014-01-26 21:10:00,35.8336 2014-01-26 21:15:00,30.8977 2014-01-26 21:20:00,30.7692 2014-01-26 21:25:00,31.0277 2014-01-26 21:30:00,33.3333 2014-01-26 21:35:00,33.4725 2014-01-26 21:40:00,33.4742 2014-01-26 21:45:00,37.908 2014-01-26 21:50:00,33.5573 2014-01-26 21:55:00,33.3333 2014-01-26 22:00:00,33.7525 2014-01-26 22:05:00,33.3333 2014-01-26 22:10:00,33.4427 2014-01-26 22:15:00,33.4447 2014-01-26 22:20:00,33.4447 2014-01-26 22:25:00,33.4447 2014-01-26 22:30:00,33.3333 2014-01-26 22:35:00,35.8336 2014-01-26 22:40:00,35.8314 2014-01-26 22:45:00,35.8314 2014-01-26 22:50:00,35.7143 2014-01-26 22:55:00,35.7143 2014-01-26 23:00:00,35.9507 2014-01-26 23:05:00,39.5279 2014-01-26 23:10:00,30.7692 2014-01-26 23:15:00,30.8992 2014-01-26 23:20:00,33.3333 2014-01-26 23:25:00,33.4447 2014-01-26 23:30:00,33.5593 2014-01-26 23:35:00,33.3333 2014-01-26 23:40:00,33.6092 2014-01-26 23:45:00,33.3333 2014-01-26 23:50:00,30.7692 2014-01-26 23:55:00,33.446 2014-01-27 00:00:00,33.556 2014-01-27 00:05:00,33.3333 2014-01-27 00:10:00,33.5587 2014-01-27 00:15:00,35.7143 2014-01-27 00:20:00,35.7143 2014-01-27 00:25:00,35.9507 2014-01-27 00:30:00,35.7143 2014-01-27 00:35:00,35.8314 2014-01-27 00:40:00,35.8336 2014-01-27 00:45:00,38.465 2014-01-27 00:50:00,36.7871 2014-01-27 00:55:00,30.7692 2014-01-27 01:00:00,31.0215 2014-01-27 01:05:00,30.7692 2014-01-27 01:10:00,33.4742 2014-01-27 01:15:00,30.7692 2014-01-27 01:20:00,33.554 2014-01-27 01:25:00,33.3333 2014-01-27 01:30:00,33.4447 2014-01-27 01:35:00,33.4447 2014-01-27 01:40:00,33.3333 2014-01-27 01:45:00,33.5573 2014-01-27 01:50:00,33.3333 2014-01-27 01:55:00,33.4427 2014-01-27 02:00:00,33.5587 2014-01-27 02:05:00,33.4447 2014-01-27 02:10:00,35.7143 2014-01-27 02:15:00,35.8314 2014-01-27 02:20:00,35.8336 2014-01-27 02:25:00,38.465 2014-01-27 02:30:00,36.7679 2014-01-27 02:35:00,35.7143 2014-01-27 02:40:00,35.8336 2014-01-27 02:45:00,35.7143 2014-01-27 02:50:00,35.9543 2014-01-27 02:55:00,30.7692 2014-01-27 03:00:00,33.6133 2014-01-27 03:05:00,33.3333 2014-01-27 03:10:00,33.5573 2014-01-27 03:15:00,33.3333 2014-01-27 03:20:00,33.4447 2014-01-27 03:25:00,33.4447 2014-01-27 03:30:00,33.3333 2014-01-27 03:35:00,35.1953 2014-01-27 03:40:00,35.2207 2014-01-27 03:45:00,33.3333 2014-01-27 03:50:00,33.446 2014-01-27 03:55:00,35.835 2014-01-27 04:00:00,35.9543 2014-01-27 04:05:00,38.5921 2014-01-27 04:10:00,36.5479 2014-01-27 04:15:00,35.9529 2014-01-27 04:20:00,35.7143 2014-01-27 04:25:00,35.9529 2014-01-27 04:30:00,35.7143 2014-01-27 04:35:00,30.7692 2014-01-27 04:40:00,31.0238 2014-01-27 04:45:00,30.7692 2014-01-27 04:50:00,33.6133 2014-01-27 04:55:00,33.3333 2014-01-27 05:00:00,33.5553 2014-01-27 05:05:00,33.3333 2014-01-27 05:10:00,33.552 2014-01-27 05:15:00,33.3333 2014-01-27 05:20:00,33.446 2014-01-27 05:25:00,33.4427 2014-01-27 05:30:00,33.3333 2014-01-27 05:35:00,33.554 2014-01-27 05:40:00,36.0714 2014-01-27 05:45:00,39.3814 2014-01-27 05:50:00,36.3093 2014-01-27 05:55:00,35.7143 2014-01-27 06:00:00,35.9507 2014-01-27 06:05:00,35.7143 2014-01-27 06:10:00,35.9529 2014-01-27 06:15:00,35.7143 2014-01-27 06:20:00,30.8954 2014-01-27 06:25:00,33.4725 2014-01-27 06:30:00,33.3333 2014-01-27 06:35:00,33.3333 2014-01-27 06:40:00,33.4447 2014-01-27 06:45:00,33.4427 2014-01-27 06:50:00,33.4447 2014-01-27 06:55:00,33.446 2014-01-27 07:00:00,33.4427 2014-01-27 07:05:00,33.4427 2014-01-27 07:10:00,33.4447 2014-01-27 07:15:00,33.4427 2014-01-27 07:20:00,33.3333 2014-01-27 07:25:00,40.005 2014-01-27 07:30:00,36.7879 2014-01-27 07:35:00,35.9507 2014-01-27 07:40:00,35.7143 2014-01-27 07:45:00,35.9543 2014-01-27 07:50:00,35.7143 2014-01-27 07:55:00,35.7143 2014-01-27 08:00:00,35.9529 2014-01-27 08:05:00,35.9486 2014-01-27 08:10:00,35.7143 2014-01-27 08:15:00,35.7143 2014-01-27 08:20:00,35.9507 2014-01-27 08:25:00,30.7692 2014-01-27 08:30:00,33.47 2014-01-27 08:35:00,33.4725 2014-01-27 08:40:00,33.4447 2014-01-27 08:45:00,33.4447 2014-01-27 08:50:00,33.4447 2014-01-27 08:55:00,33.4427 2014-01-27 09:00:00,34.0007 2014-01-27 09:05:00,37.4633 2014-01-27 09:10:00,33.4427 2014-01-27 09:15:00,33.4447 2014-01-27 09:20:00,35.7143 2014-01-27 09:25:00,35.9529 2014-01-27 09:30:00,35.7143 2014-01-27 09:35:00,35.8314 2014-01-27 09:40:00,30.8977 2014-01-27 09:45:00,35.8314 2014-01-27 09:50:00,30.7692 2014-01-27 09:55:00,33.3333 2014-01-27 10:00:00,33.6133 2014-01-27 10:05:00,33.4447 2014-01-27 10:10:00,33.4427 2014-01-27 10:15:00,33.4447 2014-01-27 10:20:00,33.446 2014-01-27 10:25:00,33.4447 2014-01-27 10:30:00,33.4447 2014-01-27 10:35:00,33.3333 2014-01-27 10:40:00,35.0167 2014-01-27 10:45:00,38.9286 2014-01-27 10:50:00,35.8336 2014-01-27 10:55:00,35.835 2014-01-27 11:00:00,35.9543 2014-01-27 11:05:00,35.7143 2014-01-27 11:10:00,35.8336 2014-01-27 11:15:00,30.8954 2014-01-27 11:20:00,30.8977 2014-01-27 11:25:00,33.4742 2014-01-27 11:30:00,33.3333 2014-01-27 11:35:00,33.4427 2014-01-27 11:40:00,33.4427 2014-01-27 11:45:00,33.4447 2014-01-27 11:50:00,33.4447 2014-01-27 11:55:00,33.3333 2014-01-27 12:00:00,33.5573 2014-01-27 12:05:00,33.5553 2014-01-27 12:10:00,33.3333 2014-01-27 12:15:00,33.4447 2014-01-27 12:20:00,37.28 2014-01-27 12:25:00,37.9586 2014-01-27 12:30:00,35.835 2014-01-27 12:35:00,35.7143 2014-01-27 12:40:00,30.8954 2014-01-27 12:45:00,30.7692 2014-01-27 12:50:00,33.4725 2014-01-27 12:55:00,33.446 2014-01-27 13:00:00,33.554 2014-01-27 13:05:00,33.3333 2014-01-27 13:10:00,33.4447 2014-01-27 13:15:00,33.4427 2014-01-27 13:20:00,35.7143 2014-01-27 13:25:00,35.9507 2014-01-27 13:30:00,35.7143 2014-01-27 13:35:00,35.835 2014-01-27 13:40:00,35.7143 2014-01-27 13:45:00,35.7143 2014-01-27 13:50:00,35.9543 2014-01-27 13:55:00,30.7692 2014-01-27 14:00:00,33.4385 2014-01-27 14:05:00,35.0233 2014-01-27 14:10:00,33.47 2014-01-27 14:15:00,33.4427 2014-01-27 14:20:00,33.4427 2014-01-27 14:25:00,33.4427 2014-01-27 14:30:00,33.4447 2014-01-27 14:35:00,33.3333 2014-01-27 14:40:00,33.4447 2014-01-27 14:45:00,33.446 2014-01-27 14:50:00,33.3333 2014-01-27 14:55:00,35.9507 2014-01-27 15:00:00,35.8314 2014-01-27 15:05:00,35.835 2014-01-27 15:10:00,35.7143 2014-01-27 15:15:00,35.9543 2014-01-27 15:20:00,35.7143 2014-01-27 15:25:00,35.835 2014-01-27 15:30:00,35.8314 2014-01-27 15:35:00,30.7692 2014-01-27 15:40:00,34.3631 2014-01-27 15:45:00,34.0167 2014-01-27 15:50:00,33.4742 2014-01-27 15:55:00,33.3333 2014-01-27 16:00:00,33.554 2014-01-27 16:05:00,33.3333 2014-01-27 16:10:00,33.554 2014-01-27 16:15:00,33.3333 2014-01-27 16:20:00,33.4447 2014-01-27 16:25:00,33.4447 2014-01-27 16:30:00,33.3333 2014-01-27 16:35:00,33.556 2014-01-27 16:40:00,33.3333 2014-01-27 16:45:00,35.7143 2014-01-27 16:50:00,35.9486 2014-01-27 16:55:00,35.7143 2014-01-27 17:00:00,35.9507 2014-01-27 17:05:00,35.7143 2014-01-27 17:10:00,35.9543 2014-01-27 17:15:00,35.7143 2014-01-27 17:20:00,39.3857 2014-01-27 17:25:00,35.8336 2014-01-27 17:30:00,31.0238 2014-01-27 17:35:00,30.7692 2014-01-27 17:40:00,33.3333 2014-01-27 17:45:00,33.6133 2014-01-27 17:50:00,33.3333 2014-01-27 17:55:00,33.554 2014-01-27 18:00:00,33.4725 2014-01-27 18:05:00,33.5587 2014-01-27 18:10:00,33.3333 2014-01-27 18:15:00,33.446 2014-01-27 18:20:00,33.4447 2014-01-27 18:25:00,33.3333 2014-01-27 18:30:00,33.5553 2014-01-27 18:35:00,33.3333 2014-01-27 18:40:00,33.4427 2014-01-27 18:45:00,33.4447 2014-01-27 18:50:00,33.4447 2014-01-27 18:55:00,33.4427 2014-01-27 19:00:00,38.0007 2014-01-27 19:05:00,33.4447 2014-01-27 19:10:00,33.446 2014-01-27 19:15:00,35.7143 2014-01-27 19:20:00,35.8336 2014-01-27 19:25:00,35.835 2014-01-27 19:30:00,35.7143 2014-01-27 19:35:00,35.9507 2014-01-27 19:40:00,35.7143 2014-01-27 19:45:00,35.9529 2014-01-27 19:50:00,35.7143 2014-01-27 19:55:00,30.7692 2014-01-27 20:00:00,31.0215 2014-01-27 20:05:00,30.7692 2014-01-27 20:10:00,33.4742 2014-01-27 20:15:00,33.3333 2014-01-27 20:20:00,33.554 2014-01-27 20:25:00,33.3333 2014-01-27 20:30:00,33.556 2014-01-27 20:35:00,34.0 2014-01-27 20:40:00,37.2153 2014-01-27 20:45:00,33.4427 2014-01-27 20:50:00,33.3333 2014-01-27 20:55:00,33.6633 2014-01-27 21:00:00,33.4427 2014-01-27 21:05:00,35.835 2014-01-27 21:10:00,35.9486 2014-01-27 21:15:00,35.835 2014-01-27 21:20:00,35.8336 2014-01-27 21:25:00,35.835 2014-01-27 21:30:00,38.0771 2014-01-27 21:35:00,38.2229 2014-01-27 21:40:00,35.8336 2014-01-27 21:45:00,35.7143 2014-01-27 21:50:00,35.8336 2014-01-27 21:55:00,33.4725 2014-01-27 22:00:00,31.0238 2014-01-27 22:05:00,30.7692 2014-01-27 22:10:00,33.4725 2014-01-27 22:15:00,34.8633 2014-01-27 22:20:00,38.4343 2014-01-27 22:25:00,33.4447 2014-01-27 22:30:00,33.4427 2014-01-27 22:35:00,33.446 2014-01-27 22:40:00,33.3333 2014-01-27 22:45:00,33.5573 2014-01-27 22:50:00,33.3333 2014-01-27 22:55:00,33.4447 2014-01-27 23:00:00,35.8336 2014-01-27 23:05:00,35.835 2014-01-27 23:10:00,35.7143 2014-01-27 23:15:00,35.8314 2014-01-27 23:20:00,35.8336 2014-01-27 23:25:00,35.8336 2014-01-27 23:30:00,35.7143 2014-01-27 23:35:00,35.8336 2014-01-27 23:40:00,30.7692 2014-01-27 23:45:00,30.8977 2014-01-27 23:50:00,33.4742 2014-01-27 23:55:00,37.326 2014-01-28 00:00:00,33.556 2014-01-28 00:05:00,33.4447 2014-01-28 00:10:00,33.4447 2014-01-28 00:15:00,33.3333 2014-01-28 00:20:00,33.4427 2014-01-28 00:25:00,33.4447 2014-01-28 00:30:00,33.4427 2014-01-28 00:35:00,33.4447 2014-01-28 00:40:00,33.4447 2014-01-28 00:45:00,33.3333 2014-01-28 00:50:00,33.446 2014-01-28 00:55:00,35.3427 2014-01-28 01:00:00,35.9543 2014-01-28 01:05:00,35.7143 2014-01-28 01:10:00,35.835 2014-01-28 01:15:00,35.8336 2014-01-28 01:20:00,35.7143 2014-01-28 01:25:00,35.9529 2014-01-28 01:30:00,35.7143 2014-01-28 01:35:00,35.8314 2014-01-28 01:40:00,35.8314 2014-01-28 01:45:00,30.7692 2014-01-28 01:50:00,33.47 2014-01-28 01:55:00,33.4725 2014-01-28 02:00:00,36.332 2014-01-28 02:05:00,35.2167 2014-01-28 02:10:00,33.3333 2014-01-28 02:15:00,33.4447 2014-01-28 02:20:00,33.4447 2014-01-28 02:25:00,33.4427 2014-01-28 02:30:00,33.4427 2014-01-28 02:35:00,33.3333 2014-01-28 02:40:00,33.4427 2014-01-28 02:45:00,33.4447 2014-01-28 02:50:00,33.4447 2014-01-28 02:55:00,33.446 2014-01-28 03:00:00,35.8336 2014-01-28 03:05:00,35.8336 2014-01-28 03:10:00,37.7386 2014-01-28 03:15:00,35.8336 2014-01-28 03:20:00,37.5914 2014-01-28 03:25:00,35.8314 2014-01-28 03:30:00,35.7143 2014-01-28 03:35:00,35.835 2014-01-28 03:40:00,30.7692 2014-01-28 03:45:00,30.8977 2014-01-28 03:50:00,33.4725 2014-01-28 03:55:00,33.3333 2014-01-28 04:00:00,33.5553 2014-01-28 04:05:00,33.446 2014-01-28 04:10:00,33.4427 2014-01-28 04:15:00,35.3333 2014-01-28 04:20:00,35.9893 2014-01-28 04:25:00,33.4427 2014-01-28 04:30:00,33.4447 2014-01-28 04:35:00,33.4447 2014-01-28 04:40:00,33.4427 2014-01-28 04:45:00,33.4447 2014-01-28 04:50:00,35.8336 2014-01-28 04:55:00,35.835 2014-01-28 05:00:00,35.9543 2014-01-28 05:05:00,35.7143 2014-01-28 05:10:00,35.8314 2014-01-28 05:15:00,35.8314 2014-01-28 05:20:00,35.7143 2014-01-28 05:25:00,35.8314 2014-01-28 05:30:00,30.7692 2014-01-28 05:35:00,31.0262 2014-01-28 05:40:00,30.7692 2014-01-28 05:45:00,30.8977 2014-01-28 05:50:00,30.8977 2014-01-28 05:55:00,33.3333 2014-01-28 06:00:00,33.6108 2014-01-28 06:05:00,33.4427 2014-01-28 06:10:00,33.4447 2014-01-28 06:15:00,34.7613 2014-01-28 06:20:00,35.1227 2014-01-28 06:25:00,33.3333 2014-01-28 06:30:00,33.5573 2014-01-28 06:35:00,33.3333 2014-01-28 06:40:00,35.835 2014-01-28 06:45:00,35.8336 2014-01-28 06:50:00,35.7143 2014-01-28 06:55:00,35.9529 2014-01-28 07:00:00,35.8336 2014-01-28 07:05:00,35.8336 2014-01-28 07:10:00,35.8336 2014-01-28 07:15:00,30.8992 2014-01-28 07:20:00,30.7692 2014-01-28 07:25:00,33.6067 2014-01-28 07:30:00,33.3333 2014-01-28 07:35:00,33.4742 2014-01-28 07:40:00,33.3333 2014-01-28 07:45:00,33.3333 2014-01-28 07:50:00,37.4447 2014-01-28 07:55:00,34.0 2014-01-28 08:00:00,33.5553 2014-01-28 08:05:00,33.4447 2014-01-28 08:10:00,33.4447 2014-01-28 08:15:00,33.4447 2014-01-28 08:20:00,33.3333 2014-01-28 08:25:00,33.552 2014-01-28 08:30:00,35.8314 2014-01-28 08:35:00,35.8336 2014-01-28 08:40:00,35.8336 2014-01-28 08:45:00,35.7143 2014-01-28 08:50:00,35.9521 2014-01-28 08:55:00,30.7692 2014-01-28 09:00:00,31.0277 2014-01-28 09:05:00,30.8954 2014-01-28 09:10:00,33.4725 2014-01-28 09:15:00,33.3333 2014-01-28 09:20:00,33.446 2014-01-28 09:25:00,33.3333 2014-01-28 09:30:00,33.4447 2014-01-28 09:35:00,33.4447 2014-01-28 09:40:00,33.4447 2014-01-28 09:45:00,33.4427 2014-01-28 09:50:00,33.3333 2014-01-28 09:55:00,38.004 2014-01-28 10:00:00,35.9557 2014-01-28 10:05:00,35.7143 2014-01-28 10:10:00,35.9507 2014-01-28 10:15:00,35.7143 2014-01-28 10:20:00,35.9529 2014-01-28 10:25:00,35.7143 2014-01-28 10:30:00,35.7143 2014-01-28 10:35:00,31.0254 2014-01-28 10:40:00,30.7692 2014-01-28 10:45:00,33.4725 2014-01-28 10:50:00,33.4447 2014-01-28 10:55:00,33.446 2014-01-28 11:00:00,35.0007 2014-01-28 11:05:00,34.8893 2014-01-28 11:10:00,33.4427 2014-01-28 11:15:00,33.4447 2014-01-28 11:20:00,33.446 2014-01-28 11:25:00,33.3333 2014-01-28 11:30:00,33.4447 2014-01-28 11:35:00,35.8314 2014-01-28 11:40:00,36.0714 2014-01-28 11:45:00,36.5493 2014-01-28 11:50:00,38.4457 2014-01-28 11:55:00,39.1786 2014-01-28 12:00:00,42.1307 2014-01-28 12:05:00,35.7143 2014-01-28 12:10:00,35.9543 2014-01-28 12:15:00,30.7692 2014-01-28 12:20:00,30.8954 2014-01-28 12:25:00,33.3333 2014-01-28 12:30:00,33.3333 2014-01-28 12:35:00,33.554 2014-01-28 12:40:00,33.3333 2014-01-28 12:45:00,33.4447 2014-01-28 12:50:00,33.4447 2014-01-28 12:55:00,33.4427 2014-01-28 13:00:00,33.4447 2014-01-28 13:05:00,33.446 2014-01-28 13:10:00,33.4427 2014-01-28 13:15:00,33.4427 2014-01-28 13:20:00,33.446 2014-01-28 13:25:00,33.3333 2014-01-28 13:30:00,35.8314 2014-01-28 13:35:00,35.835 2014-01-28 13:40:00,35.835 2014-01-28 13:45:00,37.1507 2014-01-28 13:50:00,37.0143 2014-01-28 13:55:00,37.985 2014-01-28 14:00:00,39.0207 2014-01-28 14:05:00,41.7907 2014-01-28 14:10:00,37.9671 2014-01-28 14:15:00,36.1964 2014-01-28 14:20:00,35.8336 2014-01-28 14:25:00,35.7143 2014-01-28 14:30:00,35.9543 2014-01-28 14:35:00,35.7143 2014-01-28 14:40:00,35.835 2014-01-28 14:45:00,30.8977 2014-01-28 14:50:00,30.8954 2014-01-28 14:55:00,33.3333 2014-01-28 15:00:00,33.6108 2014-01-28 15:05:00,33.4447 2014-01-28 15:10:00,33.4427 2014-01-28 15:15:00,33.3333 2014-01-28 15:20:00,33.446 2014-01-28 15:25:00,33.4447 2014-01-28 15:30:00,33.3333 2014-01-28 15:35:00,33.5573 2014-01-28 15:40:00,33.3333 2014-01-28 15:45:00,33.5553 2014-01-28 15:50:00,33.3333 2014-01-28 15:55:00,33.3333 2014-01-28 16:00:00,33.554 2014-01-28 16:05:00,34.554 2014-01-28 16:10:00,36.78 2014-01-28 16:15:00,35.8336 2014-01-28 16:20:00,35.8336 2014-01-28 16:25:00,35.8314 2014-01-28 16:30:00,35.7143 2014-01-28 16:35:00,35.8314 2014-01-28 16:40:00,35.7143 2014-01-28 16:45:00,35.8336 2014-01-28 16:50:00,35.8314 2014-01-28 16:55:00,35.7143 2014-01-28 17:00:00,35.9486 2014-01-28 17:05:00,35.8314 2014-01-28 17:10:00,30.8992 2014-01-28 17:15:00,30.7692 2014-01-28 17:20:00,33.6092 2014-01-28 17:25:00,33.3333 2014-01-28 17:30:00,33.5573 2014-01-28 17:35:00,33.3333 2014-01-28 17:40:00,33.3333 2014-01-28 17:45:00,33.5553 2014-01-28 17:50:00,33.3333 2014-01-28 17:55:00,33.4447 2014-01-28 18:00:00,33.446 2014-01-28 18:05:00,33.5553 2014-01-28 18:10:00,33.8887 2014-01-28 18:15:00,37.33 2014-01-28 18:20:00,35.9507 2014-01-28 18:25:00,35.7143 2014-01-28 18:30:00,35.9543 2014-01-28 18:35:00,37.9764 2014-01-28 18:40:00,38.0957 2014-01-28 18:45:00,35.8314 2014-01-28 18:50:00,35.8314 2014-01-28 18:55:00,35.8314 2014-01-28 19:00:00,30.8977 2014-01-28 19:05:00,30.8954 2014-01-28 19:10:00,33.47 2014-01-28 19:15:00,33.4725 2014-01-28 19:20:00,33.3333 2014-01-28 19:25:00,33.446 2014-01-28 19:30:00,33.446 2014-01-28 19:35:00,33.4447 2014-01-28 19:40:00,33.4447 2014-01-28 19:45:00,33.3333 2014-01-28 19:50:00,33.5573 2014-01-28 19:55:00,33.446 2014-01-28 20:00:00,33.554 2014-01-28 20:05:00,33.3333 2014-01-28 20:10:00,33.5587 2014-01-28 20:15:00,33.5553 2014-01-28 20:20:00,40.5943 2014-01-28 20:25:00,35.9521 2014-01-28 20:30:00,35.7143 2014-01-28 20:35:00,35.9507 2014-01-28 20:40:00,35.7143 2014-01-28 20:45:00,35.835 2014-01-28 20:50:00,35.8336 2014-01-28 20:55:00,35.8314 2014-01-28 21:00:00,30.8977 2014-01-28 21:05:00,35.835 2014-01-28 21:10:00,30.7692 2014-01-28 21:15:00,30.8977 2014-01-28 21:20:00,33.4742 2014-01-28 21:25:00,33.3333 2014-01-28 21:30:00,33.4427 2014-01-28 21:35:00,33.4427 2014-01-28 21:40:00,33.4447 2014-01-28 21:45:00,33.4427 2014-01-28 21:50:00,33.3333 2014-01-28 21:55:00,33.446 2014-01-28 22:00:00,34.001999999999995 2014-01-28 22:05:00,33.8873 2014-01-28 22:10:00,33.6687 2014-01-28 22:15:00,33.4447 2014-01-28 22:20:00,33.8887 2014-01-28 22:25:00,39.9893 2014-01-28 22:30:00,36.0679 2014-01-28 22:35:00,36.675 2014-01-28 22:40:00,35.8336 2014-01-28 22:45:00,35.8336 2014-01-28 22:50:00,35.8336 2014-01-28 22:55:00,35.8336 2014-01-28 23:00:00,35.8336 2014-01-28 23:05:00,35.7143 2014-01-28 23:10:00,35.835 2014-01-28 23:15:00,35.8336 2014-01-28 23:20:00,30.7692 2014-01-28 23:25:00,33.4742 2014-01-28 23:30:00,33.47 2014-01-28 23:35:00,33.4447 2014-01-28 23:40:00,33.4447 2014-01-28 23:45:00,33.4427 2014-01-28 23:50:00,33.3333 2014-01-28 23:55:00,33.4447 2014-01-29 00:00:00,33.5573 2014-01-29 00:05:00,33.446 2014-01-29 00:10:00,33.3333 2014-01-29 00:15:00,33.556 2014-01-29 00:20:00,33.3333 2014-01-29 00:25:00,37.1229 2014-01-29 00:30:00,39.3043 2014-01-29 00:35:00,39.6579 2014-01-29 00:40:00,32.6018 2014-01-29 00:45:00,1.334 2014-01-29 00:50:00,0.996 2014-01-29 00:55:00,1.006 2014-01-29 01:00:00,0.6659999999999999 2014-01-29 01:05:00,0.0 2014-01-29 01:10:00,0.33399999999999996 2014-01-29 01:15:00,0.0 2014-01-29 01:20:00,0.33399999999999996 2014-01-29 01:25:00,0.0 2014-01-29 01:30:00,0.0 2014-01-29 01:35:00,0.32799999999999996 2014-01-29 01:40:00,0.0 2014-01-29 01:45:00,0.33399999999999996 2014-01-29 01:50:00,0.0 2014-01-29 01:55:00,0.0 2014-01-29 02:00:00,0.32799999999999996 2014-01-29 02:05:00,0.33799999999999997 2014-01-29 02:10:00,0.0 2014-01-29 02:15:00,0.32799999999999996 2014-01-29 02:20:00,0.0 2014-01-29 02:25:00,0.0 2014-01-29 02:30:00,10.008 2014-01-29 02:35:00,3.9619999999999997 2014-01-29 02:40:00,0.0 2014-01-29 02:45:00,0.0 2014-01-29 02:50:00,0.32799999999999996 2014-01-29 02:55:00,0.0 2014-01-29 03:00:00,0.33399999999999996 2014-01-29 03:05:00,0.0 2014-01-29 03:10:00,0.33399999999999996 2014-01-29 03:15:00,0.0 2014-01-29 03:20:00,0.33799999999999997 2014-01-29 03:25:00,0.0 2014-01-29 03:30:00,0.33399999999999996 2014-01-29 03:35:00,5.084 2014-01-29 03:40:00,0.33399999999999996 2014-01-29 03:45:00,0.0 2014-01-29 03:50:00,0.33399999999999996 2014-01-29 03:55:00,0.0 2014-01-29 04:00:00,0.32799999999999996 2014-01-29 04:05:00,0.0 2014-01-29 04:10:00,0.33799999999999997 2014-01-29 04:15:00,0.6559999999999999 2014-01-29 04:20:00,3.034 2014-01-29 04:25:00,0.0 2014-01-29 04:30:00,14.014000000000001 2014-01-29 04:35:00,0.0 2014-01-29 04:40:00,0.0 2014-01-29 04:45:00,0.33799999999999997 2014-01-29 04:50:00,0.0 2014-01-29 04:55:00,0.33799999999999997 2014-01-29 05:00:00,0.0 2014-01-29 05:05:00,0.33399999999999996 2014-01-29 05:10:00,0.0 2014-01-29 05:15:00,0.33399999999999996 2014-01-29 05:20:00,0.0 2014-01-29 05:25:00,0.0 2014-01-29 05:30:00,0.32799999999999996 2014-01-29 05:35:00,0.0 2014-01-29 05:40:00,0.32799999999999996 2014-01-29 05:45:00,0.0 2014-01-29 05:50:00,0.0 2014-01-29 05:55:00,0.6659999999999999 2014-01-29 06:00:00,0.33399999999999996 2014-01-29 06:05:00,0.0 2014-01-29 06:10:00,0.0 2014-01-29 06:15:00,0.32799999999999996 2014-01-29 06:20:00,0.0 2014-01-29 06:25:00,2.63 2014-01-29 06:30:00,11.03 2014-01-29 06:35:00,0.32799999999999996 2014-01-29 06:40:00,0.0 2014-01-29 06:45:00,0.33399999999999996 2014-01-29 06:50:00,0.0 2014-01-29 06:55:00,0.0 2014-01-29 07:00:00,0.33799999999999997 2014-01-29 07:05:00,0.33399999999999996 2014-01-29 07:10:00,0.0 2014-01-29 07:15:00,0.0 2014-01-29 07:20:00,0.33399999999999996 2014-01-29 07:25:00,0.0 2014-01-29 07:30:00,0.33799999999999997 2014-01-29 07:35:00,0.0 2014-01-29 07:40:00,0.33399999999999996 2014-01-29 07:45:00,0.0 2014-01-29 07:50:00,0.0 2014-01-29 07:55:00,0.33399999999999996 2014-01-29 08:00:00,0.0 2014-01-29 08:05:00,0.33399999999999996 2014-01-29 08:10:00,0.0 2014-01-29 08:15:00,0.33399999999999996 2014-01-29 08:20:00,0.0 2014-01-29 08:25:00,12.014000000000001 2014-01-29 08:30:00,1.64 2014-01-29 08:35:00,0.0 2014-01-29 08:40:00,0.4225 2014-01-29 08:45:00,0.0 2014-01-29 08:50:00,0.32799999999999996 2014-01-29 08:55:00,0.0 2014-01-29 09:00:00,0.33399999999999996 2014-01-29 09:05:00,0.0 2014-01-29 09:10:00,0.33399999999999996 2014-01-29 09:15:00,0.0 2014-01-29 09:20:00,0.33799999999999997 2014-01-29 09:25:00,0.0 2014-01-29 09:30:00,0.0 2014-01-29 09:35:00,0.33399999999999996 2014-01-29 09:40:00,0.0 2014-01-29 09:45:00,0.33799999999999997 2014-01-29 09:50:00,0.0 2014-01-29 09:55:00,0.32799999999999996 2014-01-29 10:00:00,0.0 2014-01-29 10:05:00,0.32799999999999996 2014-01-29 10:10:00,0.0 2014-01-29 10:15:00,0.33799999999999997 2014-01-29 10:20:00,2.0340000000000003 2014-01-29 10:25:00,11.652000000000001 2014-01-29 10:30:00,0.0 2014-01-29 10:35:00,0.32799999999999996 2014-01-29 10:40:00,0.0 2014-01-29 10:45:00,0.32799999999999996 2014-01-29 10:50:00,0.0 2014-01-29 10:55:00,0.0 2014-01-29 11:00:00,0.33399999999999996 2014-01-29 11:05:00,0.33399999999999996 2014-01-29 11:10:00,0.0 2014-01-29 11:15:00,0.0 2014-01-29 11:20:00,0.33799999999999997 2014-01-29 11:25:00,0.0 2014-01-29 11:30:00,0.32799999999999996 2014-01-29 11:35:00,0.0 2014-01-29 11:40:00,0.33399999999999996 2014-01-29 11:45:00,0.0 2014-01-29 11:50:00,0.0 2014-01-29 11:55:00,0.33399999999999996 2014-01-29 12:00:00,0.33799999999999997 2014-01-29 12:05:00,0.0 2014-01-29 12:10:00,0.0 2014-01-29 12:15:00,0.33399999999999996 2014-01-29 12:20:00,10.39 2014-01-29 12:25:00,3.3339999999999996 2014-01-29 12:30:00,0.33399999999999996 2014-01-29 12:35:00,0.0 2014-01-29 12:40:00,0.0 2014-01-29 12:45:00,0.33399999999999996 2014-01-29 12:50:00,0.0 2014-01-29 12:55:00,0.33399999999999996 2014-01-29 13:00:00,0.0 2014-01-29 13:05:00,0.4175 2014-01-29 13:10:00,0.0 2014-01-29 13:15:00,0.33399999999999996 2014-01-29 13:20:00,0.0 2014-01-29 13:25:00,0.0 2014-01-29 13:30:00,0.33799999999999997 2014-01-29 13:35:00,0.0 2014-01-29 13:40:00,0.33399999999999996 2014-01-29 13:45:00,0.0 2014-01-29 13:50:00,0.0 2014-01-29 13:55:00,0.32799999999999996 2014-01-29 14:00:00,0.33399999999999996 2014-01-29 14:05:00,0.0 2014-01-29 14:10:00,0.0 2014-01-29 14:15:00,1.69 2014-01-29 14:20:00,12.328 2014-01-29 14:25:00,0.33799999999999997 2014-01-29 14:30:00,0.0 2014-01-29 14:35:00,0.33399999999999996 2014-01-29 14:40:00,0.0 2014-01-29 14:45:00,0.33399999999999996 2014-01-29 14:50:00,0.0 2014-01-29 14:55:00,0.0 2014-01-29 15:00:00,0.33399999999999996 2014-01-29 15:05:00,0.32799999999999996 2014-01-29 15:10:00,0.0 2014-01-29 15:15:00,0.32799999999999996 2014-01-29 15:20:00,0.33399999999999996 2014-01-29 15:25:00,0.0 2014-01-29 15:30:00,0.33399999999999996 2014-01-29 15:35:00,0.0 2014-01-29 15:40:00,0.33399999999999996 2014-01-29 15:45:00,2.34 2014-01-29 15:50:00,0.32799999999999996 2014-01-29 15:55:00,0.0 2014-01-29 16:00:00,0.33799999999999997 2014-01-29 16:05:00,0.0 2014-01-29 16:10:00,0.32799999999999996 2014-01-29 16:15:00,6.662000000000001 2014-01-29 16:20:00,6.95 2014-01-29 16:25:00,0.0 2014-01-29 16:30:00,0.33799999999999997 2014-01-29 16:35:00,0.0 2014-01-29 16:40:00,0.32799999999999996 2014-01-29 16:45:00,0.0 2014-01-29 16:50:00,0.33399999999999996 2014-01-29 16:55:00,0.0 2014-01-29 17:00:00,0.33399999999999996 2014-01-29 17:05:00,0.0 2014-01-29 17:10:00,0.33799999999999997 2014-01-29 17:15:00,0.0 2014-01-29 17:20:00,0.0 2014-01-29 17:25:00,0.32799999999999996 2014-01-29 17:30:00,0.0 2014-01-29 17:35:00,0.32799999999999996 2014-01-29 17:40:00,0.0 2014-01-29 17:45:00,0.33799999999999997 2014-01-29 17:50:00,0.0 2014-01-29 17:55:00,0.0 2014-01-29 18:00:00,0.33399999999999996 2014-01-29 18:05:00,0.33399999999999996 2014-01-29 18:10:00,0.0 2014-01-29 18:15:00,1.64 2014-01-29 18:20:00,11.995999999999999 2014-01-29 18:25:00,0.33399999999999996 2014-01-29 18:30:00,0.0 2014-01-29 18:35:00,0.33399999999999996 2014-01-29 18:40:00,0.0 2014-01-29 18:45:00,0.0 2014-01-29 18:50:00,0.33399999999999996 2014-01-29 18:55:00,0.0 2014-01-29 19:00:00,0.33399999999999996 2014-01-29 19:05:00,0.0 2014-01-29 19:10:00,0.33399999999999996 2014-01-29 19:15:00,0.0 2014-01-29 19:20:00,0.33799999999999997 2014-01-29 19:25:00,0.0 2014-01-29 19:30:00,0.0 2014-01-29 19:35:00,0.33799999999999997 2014-01-29 19:40:00,0.0 2014-01-29 19:45:00,0.33399999999999996 2014-01-29 19:50:00,0.0 2014-01-29 19:55:00,0.33399999999999996 2014-01-29 20:00:00,0.0 2014-01-29 20:05:00,0.33399999999999996 2014-01-29 20:10:00,0.0 2014-01-29 20:15:00,0.33399999999999996 2014-01-29 20:20:00,13.34 2014-01-29 20:25:00,0.32799999999999996 2014-01-29 20:30:00,0.0 2014-01-29 20:35:00,0.33399999999999996 2014-01-29 20:40:00,0.0 2014-01-29 20:45:00,0.0 2014-01-29 20:50:00,0.33399999999999996 2014-01-29 20:55:00,0.0 2014-01-29 21:00:00,0.32799999999999996 2014-01-29 21:05:00,0.0 2014-01-29 21:10:00,0.33799999999999997 2014-01-29 21:15:00,0.0 2014-01-29 21:20:00,0.33399999999999996 2014-01-29 21:25:00,0.0 2014-01-29 21:30:00,0.33399999999999996 2014-01-29 21:35:00,0.0 2014-01-29 21:40:00,0.33399999999999996 2014-01-29 21:45:00,0.0 2014-01-29 21:50:00,0.33799999999999997 2014-01-29 21:55:00,0.0 2014-01-29 22:00:00,0.41 2014-01-29 22:05:00,0.0 2014-01-29 22:10:00,0.4225 2014-01-29 22:15:00,2.0 2014-01-29 22:20:00,11.662 2014-01-29 22:25:00,0.0 2014-01-29 22:30:00,0.32799999999999996 2014-01-29 22:35:00,0.0 2014-01-29 22:40:00,0.33799999999999997 2014-01-29 22:45:00,0.0 2014-01-29 22:50:00,0.0 2014-01-29 22:55:00,0.33399999999999996 2014-01-29 23:00:00,0.32799999999999996 2014-01-29 23:05:00,0.0 2014-01-29 23:10:00,0.0 2014-01-29 23:15:00,0.33799999999999997 2014-01-29 23:20:00,0.0 2014-01-29 23:25:00,0.32799999999999996 2014-01-29 23:30:00,0.0 2014-01-29 23:35:00,0.33399999999999996 2014-01-29 23:40:00,0.0 2014-01-29 23:45:00,0.0 2014-01-29 23:50:00,0.33399999999999996 2014-01-29 23:55:00,0.0 2014-01-30 00:00:00,0.33399999999999996 2014-01-30 00:05:00,0.0 2014-01-30 00:10:00,0.32799999999999996 2014-01-30 00:15:00,0.0 2014-01-30 00:20:00,13.68 2014-01-30 00:25:00,0.33399999999999996 2014-01-30 00:30:00,0.0 2014-01-30 00:35:00,0.6679999999999999 2014-01-30 00:40:00,0.0 2014-01-30 00:45:00,0.32799999999999996 2014-01-30 00:50:00,0.0 2014-01-30 00:55:00,0.0 2014-01-30 01:00:00,0.4225 2014-01-30 01:05:00,0.0 2014-01-30 01:10:00,0.0 2014-01-30 01:15:00,0.0 2014-01-30 01:20:00,0.33399999999999996 2014-01-30 01:25:00,0.0 2014-01-30 01:30:00,0.32799999999999996 2014-01-30 01:35:00,0.0 2014-01-30 01:40:00,0.0 2014-01-30 01:45:00,0.33399999999999996 2014-01-30 01:50:00,0.33399999999999996 2014-01-30 01:55:00,0.0 2014-01-30 02:00:00,0.32799999999999996 2014-01-30 02:05:00,0.0 2014-01-30 02:10:00,0.32799999999999996 2014-01-30 02:15:00,5.612 2014-01-30 02:20:00,8.056000000000001 2014-01-30 02:25:00,0.0 2014-01-30 02:30:00,0.32799999999999996 2014-01-30 02:35:00,0.0 2014-01-30 02:40:00,0.0 2014-01-30 02:45:00,0.33399999999999996 2014-01-30 02:50:00,0.0 2014-01-30 02:55:00,0.33399999999999996 2014-01-30 03:00:00,0.32799999999999996 2014-01-30 03:05:00,4.918 2014-01-30 03:10:00,0.32799999999999996 2014-01-30 03:15:00,0.0 2014-01-30 03:20:00,0.0 2014-01-30 03:25:00,0.33399999999999996 2014-01-30 03:30:00,0.0 2014-01-30 03:35:00,0.32799999999999996 2014-01-30 03:40:00,0.0 2014-01-30 03:45:00,0.33399999999999996 2014-01-30 03:50:00,0.0 2014-01-30 03:55:00,0.0 2014-01-30 04:00:00,0.33799999999999997 2014-01-30 04:05:00,0.0 2014-01-30 04:10:00,0.32799999999999996 2014-01-30 04:15:00,13.652000000000001 2014-01-30 04:20:00,0.0 2014-01-30 04:25:00,0.33399999999999996 2014-01-30 04:30:00,0.0 2014-01-30 04:35:00,0.32799999999999996 2014-01-30 04:40:00,0.0 2014-01-30 04:45:00,0.0 2014-01-30 04:50:00,0.32799999999999996 2014-01-30 04:55:00,0.0 2014-01-30 05:00:00,0.33799999999999997 2014-01-30 05:05:00,0.0 2014-01-30 05:10:00,0.33799999999999997 2014-01-30 05:15:00,0.0 2014-01-30 05:20:00,0.33799999999999997 2014-01-30 05:25:00,0.0 2014-01-30 05:30:00,0.0 2014-01-30 05:35:00,0.32799999999999996 2014-01-30 05:40:00,0.0 2014-01-30 05:45:00,0.33799999999999997 2014-01-30 05:50:00,0.0 2014-01-30 05:55:00,0.0 2014-01-30 06:00:00,0.32799999999999996 2014-01-30 06:05:00,0.32799999999999996 2014-01-30 06:10:00,11.612 2014-01-30 06:15:00,2.0 2014-01-30 06:20:00,0.0 2014-01-30 06:25:00,0.33399999999999996 2014-01-30 06:30:00,0.0 2014-01-30 06:35:00,0.33799999999999997 2014-01-30 06:40:00,0.0 2014-01-30 06:45:00,0.0 2014-01-30 06:50:00,0.33399999999999996 2014-01-30 06:55:00,0.0 2014-01-30 07:00:00,0.33799999999999997 2014-01-30 07:05:00,0.0 2014-01-30 07:10:00,0.33799999999999997 2014-01-30 07:15:00,0.0 2014-01-30 07:20:00,0.33399999999999996 2014-01-30 07:25:00,0.0 2014-01-30 07:30:00,0.33399999999999996 2014-01-30 07:35:00,0.0 2014-01-30 07:40:00,0.0 2014-01-30 07:45:00,0.33399999999999996 2014-01-30 07:50:00,0.0 2014-01-30 07:55:00,0.33399999999999996 2014-01-30 08:00:00,0.0 2014-01-30 08:05:00,13.968 2014-01-30 08:10:00,0.0 2014-01-30 08:15:00,0.0 2014-01-30 08:20:00,0.32799999999999996 2014-01-30 08:25:00,0.0 2014-01-30 08:30:00,0.33799999999999997 2014-01-30 08:35:00,0.0 2014-01-30 08:40:00,0.33399999999999996 2014-01-30 08:45:00,0.0 2014-01-30 08:50:00,0.0 2014-01-30 08:55:00,0.33399999999999996 2014-01-30 09:00:00,0.33799999999999997 2014-01-30 09:05:00,0.0 2014-01-30 09:10:00,0.0 2014-01-30 09:15:00,0.32799999999999996 2014-01-30 09:20:00,0.0 2014-01-30 09:25:00,0.33399999999999996 2014-01-30 09:30:00,0.0 2014-01-30 09:35:00,0.0 2014-01-30 09:40:00,0.32799999999999996 2014-01-30 09:45:00,0.0 2014-01-30 09:50:00,0.33799999999999997 2014-01-30 09:55:00,6.95 2014-01-30 10:00:00,6.666 2014-01-30 10:05:00,0.33399999999999996 2014-01-30 10:10:00,0.0 2014-01-30 10:15:00,0.32799999999999996 2014-01-30 10:20:00,0.0 2014-01-30 10:25:00,0.0 2014-01-30 10:30:00,0.32799999999999996 2014-01-30 10:35:00,0.0 2014-01-30 10:40:00,0.32799999999999996 2014-01-30 10:45:00,0.0 2014-01-30 10:50:00,0.33399999999999996 2014-01-30 10:55:00,0.0 2014-01-30 11:00:00,0.33799999999999997 2014-01-30 11:05:00,0.0 2014-01-30 11:10:00,0.0 2014-01-30 11:15:00,0.33799999999999997 2014-01-30 11:20:00,0.0 2014-01-30 11:25:00,0.33799999999999997 2014-01-30 11:30:00,0.0 2014-01-30 11:35:00,0.32799999999999996 2014-01-30 11:40:00,0.0 2014-01-30 11:45:00,0.0 2014-01-30 11:50:00,14.036 2014-01-30 11:55:00,0.0 2014-01-30 12:00:00,0.33799999999999997 2014-01-30 12:05:00,0.0 2014-01-30 12:10:00,0.33799999999999997 2014-01-30 12:15:00,0.0 2014-01-30 12:20:00,2.372 2014-01-30 12:25:00,0.33799999999999997 2014-01-30 12:30:00,0.0 2014-01-30 12:35:00,0.672 2014-01-30 12:40:00,0.0 2014-01-30 12:45:00,0.32799999999999996 2014-01-30 12:50:00,0.0 2014-01-30 12:55:00,0.0 2014-01-30 13:00:00,0.32799999999999996 2014-01-30 13:05:00,0.33799999999999997 2014-01-30 13:10:00,0.0 2014-01-30 13:15:00,0.0 2014-01-30 13:20:00,0.33799999999999997 2014-01-30 13:25:00,0.0 2014-01-30 13:30:00,0.33799999999999997 2014-01-30 13:35:00,0.0 2014-01-30 13:40:00,3.7239999999999998 2014-01-30 13:45:00,10.328 2014-01-30 13:50:00,0.0 2014-01-30 13:55:00,0.33799999999999997 2014-01-30 14:00:00,0.0 2014-01-30 14:05:00,0.33799999999999997 2014-01-30 14:10:00,0.32799999999999996 2014-01-30 14:15:00,0.0 2014-01-30 14:20:00,0.33799999999999997 2014-01-30 14:25:00,0.0 2014-01-30 14:30:00,5.296 2014-01-30 14:35:00,1.016 2014-01-30 14:40:00,0.0 2014-01-30 14:45:00,0.0 2014-01-30 14:50:00,0.32799999999999996 2014-01-30 14:55:00,0.0 2014-01-30 15:00:00,0.32799999999999996 2014-01-30 15:05:00,0.0 2014-01-30 15:10:00,0.41 2014-01-30 15:15:00,0.0 2014-01-30 15:20:00,0.33399999999999996 2014-01-30 15:25:00,0.0 2014-01-30 15:30:00,0.33399999999999996 2014-01-30 15:35:00,10.334000000000001 2014-01-30 15:40:00,3.2880000000000003 2014-01-30 15:45:00,0.0 2014-01-30 15:50:00,0.32799999999999996 2014-01-30 15:55:00,0.0 2014-01-30 16:00:00,0.33799999999999997 2014-01-30 16:05:00,0.0 2014-01-30 16:10:00,0.33799999999999997 2014-01-30 16:15:00,0.0 2014-01-30 16:20:00,0.0 2014-01-30 16:25:00,0.672 2014-01-30 16:30:00,0.0 2014-01-30 16:35:00,0.0 2014-01-30 16:40:00,0.33399999999999996 2014-01-30 16:45:00,0.0 2014-01-30 16:50:00,0.33399999999999996 2014-01-30 16:55:00,0.0 2014-01-30 17:00:00,0.32799999999999996 2014-01-30 17:05:00,0.0 2014-01-30 17:10:00,0.33799999999999997 2014-01-30 17:15:00,0.0 2014-01-30 17:20:00,0.32799999999999996 2014-01-30 17:25:00,0.0 2014-01-30 17:30:00,0.0 2014-01-30 17:35:00,0.33399999999999996 2014-01-30 17:40:00,7.34 2014-01-30 17:45:00,6.284 2014-01-30 17:50:00,0.32799999999999996 2014-01-30 17:55:00,0.0 2014-01-30 18:00:00,0.33399999999999996 2014-01-30 18:05:00,0.0 2014-01-30 18:10:00,0.41 2014-01-30 18:15:00,0.0 2014-01-30 18:20:00,0.33799999999999997 2014-01-30 18:25:00,0.0 2014-01-30 18:30:00,0.33399999999999996 2014-01-30 18:35:00,0.0 2014-01-30 18:40:00,0.0 2014-01-30 18:45:00,0.33399999999999996 2014-01-30 18:50:00,0.0 2014-01-30 18:55:00,0.32799999999999996 2014-01-30 19:00:00,0.0 2014-01-30 19:05:00,0.33399999999999996 2014-01-30 19:10:00,0.0 2014-01-30 19:15:00,0.33399999999999996 2014-01-30 19:20:00,5.716 2014-01-30 19:25:00,0.0 2014-01-30 19:30:00,0.33399999999999996 2014-01-30 19:35:00,0.0 2014-01-30 19:40:00,0.32799999999999996 2014-01-30 19:45:00,0.0 2014-01-30 19:50:00,0.0 2014-01-30 19:55:00,0.32799999999999996 2014-01-30 20:00:00,0.33799999999999997 2014-01-30 20:05:00,0.0 2014-01-30 20:10:00,0.0 2014-01-30 20:15:00,0.33799999999999997 2014-01-30 20:20:00,0.0 2014-01-30 20:25:00,0.33799999999999997 2014-01-30 20:30:00,0.0 2014-01-30 20:35:00,0.33399999999999996 2014-01-30 20:40:00,3.2880000000000003 2014-01-30 20:45:00,0.0 2014-01-30 20:50:00,0.33799999999999997 2014-01-30 20:55:00,0.0 2014-01-30 21:00:00,0.33399999999999996 2014-01-30 21:05:00,0.0 2014-01-30 21:10:00,0.32799999999999996 2014-01-30 21:15:00,0.0 2014-01-30 21:20:00,0.4175 2014-01-30 21:25:00,8.322000000000001 2014-01-30 21:30:00,0.0 2014-01-30 21:35:00,0.41 2014-01-30 21:40:00,0.0 2014-01-30 21:45:00,0.33799999999999997 2014-01-30 21:50:00,0.0 2014-01-30 21:55:00,0.0 2014-01-30 22:00:00,0.4175 2014-01-30 22:05:00,0.33399999999999996 2014-01-30 22:10:00,0.0 2014-01-30 22:15:00,0.0 2014-01-30 22:20:00,0.33799999999999997 2014-01-30 22:25:00,0.0 2014-01-30 22:30:00,0.33799999999999997 2014-01-30 22:35:00,0.0 2014-01-30 22:40:00,0.0 2014-01-30 22:45:00,0.0 2014-01-30 22:50:00,0.0 2014-01-30 22:55:00,0.32799999999999996 2014-01-30 23:00:00,0.33399999999999996 2014-01-30 23:05:00,0.0 2014-01-30 23:10:00,0.0 2014-01-30 23:15:00,0.33399999999999996 2014-01-30 23:20:00,0.0 2014-01-30 23:25:00,0.32799999999999996 2014-01-30 23:30:00,0.0 2014-01-30 23:35:00,0.0 2014-01-30 23:40:00,0.33399999999999996 2014-01-30 23:45:00,0.0 2014-01-30 23:50:00,0.33399999999999996 2014-01-30 23:55:00,0.0 2014-01-31 00:00:00,0.33799999999999997 2014-01-31 00:05:00,0.0 2014-01-31 00:10:00,0.32799999999999996 2014-01-31 00:15:00,0.0 2014-01-31 00:20:00,0.6659999999999999 2014-01-31 00:25:00,0.0 2014-01-31 00:30:00,0.0 2014-01-31 00:35:00,0.33799999999999997 2014-01-31 00:40:00,0.0 2014-01-31 00:45:00,0.33399999999999996 2014-01-31 00:50:00,0.0 2014-01-31 00:55:00,0.0 2014-01-31 01:00:00,0.33799999999999997 2014-01-31 01:05:00,0.32799999999999996 2014-01-31 01:10:00,0.0 2014-01-31 01:15:00,0.32799999999999996 2014-01-31 01:20:00,0.0 2014-01-31 01:25:00,0.0 2014-01-31 01:30:00,0.33399999999999996 2014-01-31 01:35:00,0.0 2014-01-31 01:40:00,0.4175 2014-01-31 01:45:00,0.0 2014-01-31 01:50:00,0.0 2014-01-31 01:55:00,0.32799999999999996 2014-01-31 02:00:00,0.33399999999999996 2014-01-31 02:05:00,0.0 2014-01-31 02:10:00,0.0 2014-01-31 02:15:00,0.33399999999999996 2014-01-31 02:20:00,0.0 2014-01-31 02:25:00,0.33399999999999996 2014-01-31 02:30:00,0.0 2014-01-31 02:35:00,0.33399999999999996 2014-01-31 02:40:00,0.0 2014-01-31 02:45:00,0.0 2014-01-31 02:50:00,0.33799999999999997 2014-01-31 02:55:00,0.0 2014-01-31 03:00:00,0.32799999999999996 2014-01-31 03:05:00,0.0 2014-01-31 03:10:00,0.33799999999999997 2014-01-31 03:15:00,0.0 2014-01-31 03:20:00,0.33799999999999997 2014-01-31 03:25:00,0.0 2014-01-31 03:30:00,0.33799999999999997 2014-01-31 03:35:00,0.0 2014-01-31 03:40:00,5.246 2014-01-31 03:45:00,0.0 2014-01-31 03:50:00,0.4175 2014-01-31 03:55:00,0.0 2014-01-31 04:00:00,0.33399999999999996 2014-01-31 04:05:00,0.0 2014-01-31 04:10:00,0.33399999999999996 2014-01-31 04:15:00,0.0 2014-01-31 04:20:00,0.32799999999999996 2014-01-31 04:25:00,0.0 2014-01-31 04:30:00,0.0 2014-01-31 04:35:00,0.33399999999999996 2014-01-31 04:40:00,0.0 2014-01-31 04:45:00,0.32799999999999996 2014-01-31 04:50:00,0.0 2014-01-31 04:55:00,0.33399999999999996 2014-01-31 05:00:00,0.33799999999999997 2014-01-31 05:05:00,0.0 2014-01-31 05:10:00,0.0 2014-01-31 05:15:00,0.33399999999999996 2014-01-31 05:20:00,0.0 2014-01-31 05:25:00,0.33399999999999996 2014-01-31 05:30:00,0.0 2014-01-31 05:35:00,0.32799999999999996 2014-01-31 05:40:00,0.0 2014-01-31 05:45:00,0.0 2014-01-31 05:50:00,0.33799999999999997 2014-01-31 05:55:00,0.0 2014-01-31 06:00:00,0.4175 2014-01-31 06:05:00,0.0 2014-01-31 06:10:00,0.33399999999999996 2014-01-31 06:15:00,0.0 2014-01-31 06:20:00,0.33799999999999997 2014-01-31 06:25:00,0.0 2014-01-31 06:30:00,0.33799999999999997 2014-01-31 06:35:00,0.0 2014-01-31 06:40:00,0.33799999999999997 2014-01-31 06:45:00,0.0 2014-01-31 06:50:00,0.0 2014-01-31 06:55:00,0.32799999999999996 2014-01-31 07:00:00,0.33399999999999996 2014-01-31 07:05:00,0.0 2014-01-31 07:10:00,0.0 2014-01-31 07:15:00,0.33799999999999997 2014-01-31 07:20:00,0.0 2014-01-31 07:25:00,0.33399999999999996 2014-01-31 07:30:00,0.0 2014-01-31 07:35:00,0.32799999999999996 2014-01-31 07:40:00,1.334 2014-01-31 07:45:00,0.0 2014-01-31 07:50:00,0.33799999999999997 2014-01-31 07:55:00,0.0 2014-01-31 08:00:00,0.33799999999999997 2014-01-31 08:05:00,0.0 2014-01-31 08:10:00,0.0 2014-01-31 08:15:00,0.0 2014-01-31 08:20:00,0.0 2014-01-31 08:25:00,0.32799999999999996 2014-01-31 08:30:00,0.0 2014-01-31 08:35:00,0.4225 2014-01-31 08:40:00,11.62 2014-01-31 08:45:00,11.718 2014-01-31 08:50:00,5.318 2014-01-31 08:55:00,0.33399999999999996 2014-01-31 09:00:00,0.32799999999999996 2014-01-31 09:05:00,0.0 2014-01-31 09:10:00,0.0 2014-01-31 09:15:00,0.4175 2014-01-31 09:20:00,0.0 2014-01-31 09:25:00,0.32799999999999996 2014-01-31 09:30:00,0.0 2014-01-31 09:35:00,0.33399999999999996 2014-01-31 09:40:00,0.0 2014-01-31 09:45:00,0.0 2014-01-31 09:50:00,0.33399999999999996 2014-01-31 09:55:00,0.0 2014-01-31 10:00:00,0.33399999999999996 2014-01-31 10:05:00,0.0 2014-01-31 10:10:00,0.33399999999999996 2014-01-31 10:15:00,0.0 2014-01-31 10:20:00,0.0 2014-01-31 10:25:00,0.32799999999999996 2014-01-31 10:30:00,4.215 2014-01-31 10:35:00,0.0 2014-01-31 10:40:00,0.32799999999999996 2014-01-31 10:45:00,0.0 2014-01-31 10:50:00,0.33399999999999996 2014-01-31 10:55:00,0.0 2014-01-31 11:00:00,0.33399999999999996 2014-01-31 11:05:00,0.0 2014-01-31 11:10:00,0.0 2014-01-31 11:15:00,0.0 2014-01-31 11:20:00,0.0 2014-01-31 11:25:00,0.6679999999999999 2014-01-31 11:30:00,0.0 2014-01-31 11:35:00,0.4175 2014-01-31 11:40:00,0.0 2014-01-31 11:45:00,0.32799999999999996 2014-01-31 11:50:00,0.0 2014-01-31 11:55:00,0.0 2014-01-31 12:00:00,0.32799999999999996 2014-01-31 12:05:00,0.33399999999999996 2014-01-31 12:10:00,0.0 2014-01-31 12:15:00,0.0 2014-01-31 12:20:00,0.32799999999999996 2014-01-31 12:25:00,0.0 2014-01-31 12:30:00,0.33399999999999996 2014-01-31 12:35:00,0.0 2014-01-31 12:40:00,0.0 2014-01-31 12:45:00,0.33799999999999997 2014-01-31 12:50:00,0.0 2014-01-31 12:55:00,0.4175 2014-01-31 13:00:00,0.0 2014-01-31 13:05:00,0.33399999999999996 2014-01-31 13:10:00,0.0 2014-01-31 13:15:00,0.33399999999999996 2014-01-31 13:20:00,0.0 2014-01-31 13:25:00,0.0 2014-01-31 13:30:00,0.33399999999999996 2014-01-31 13:35:00,0.0 2014-01-31 13:40:00,0.33399999999999996 2014-01-31 13:45:00,0.0 2014-01-31 13:50:00,0.0 2014-01-31 13:55:00,0.33799999999999997 2014-01-31 14:00:00,0.41 2014-01-31 14:05:00,0.0 2014-01-31 14:10:00,0.33399999999999996 2014-01-31 14:15:00,0.0 2014-01-31 14:20:00,0.0 2014-01-31 14:25:00,0.32799999999999996 2014-01-31 14:30:00,0.0 2014-01-31 14:35:00,0.33399999999999996 2014-01-31 14:40:00,0.0 2014-01-31 14:45:00,0.0 2014-01-31 14:50:00,0.33399999999999996 2014-01-31 14:55:00,0.0 2014-01-31 15:00:00,0.33799999999999997 2014-01-31 15:05:00,0.0 2014-01-31 15:10:00,0.33799999999999997 2014-01-31 15:15:00,0.0 2014-01-31 15:20:00,0.4225 2014-01-31 15:25:00,0.0 2014-01-31 15:30:00,0.32799999999999996 2014-01-31 15:35:00,0.0 2014-01-31 15:40:00,0.0 2014-01-31 15:45:00,0.33399999999999996 2014-01-31 15:50:00,0.0 2014-01-31 15:55:00,0.33799999999999997 2014-01-31 16:00:00,0.0 2014-01-31 16:05:00,0.33799999999999997 2014-01-31 16:10:00,0.0 2014-01-31 16:15:00,0.32799999999999996 2014-01-31 16:20:00,0.0 2014-01-31 16:25:00,0.33399999999999996 2014-01-31 16:30:00,0.0 2014-01-31 16:35:00,0.0 2014-01-31 16:40:00,0.33399999999999996 2014-01-31 16:45:00,0.0 2014-01-31 16:50:00,0.41 2014-01-31 16:55:00,0.0 2014-01-31 17:00:00,0.33399999999999996 2014-01-31 17:05:00,0.0 2014-01-31 17:10:00,0.33399999999999996 2014-01-31 17:15:00,0.0 2014-01-31 17:20:00,0.33799999999999997 2014-01-31 17:25:00,0.0 2014-01-31 17:30:00,0.0 2014-01-31 17:35:00,0.33399999999999996 2014-01-31 17:40:00,0.0 2014-01-31 17:45:00,0.33799999999999997 2014-01-31 17:50:00,0.0 2014-01-31 17:55:00,2.7060000000000004 2014-01-31 18:00:00,0.33799999999999997 2014-01-31 18:05:00,0.0 2014-01-31 18:10:00,0.33799999999999997 2014-01-31 18:15:00,0.0 2014-01-31 18:20:00,0.0 2014-01-31 18:25:00,0.32799999999999996 2014-01-31 18:30:00,0.0 2014-01-31 18:35:00,0.33799999999999997 2014-01-31 18:40:00,0.0 2014-01-31 18:45:00,0.0 2014-01-31 18:50:00,0.33799999999999997 2014-01-31 18:55:00,0.0 2014-01-31 19:00:00,0.33799999999999997 2014-01-31 19:05:00,0.0 2014-01-31 19:10:00,0.33399999999999996 2014-01-31 19:15:00,0.0 2014-01-31 19:20:00,0.33799999999999997 2014-01-31 19:25:00,0.0 2014-01-31 19:30:00,0.0 2014-01-31 19:35:00,0.32799999999999996 2014-01-31 19:40:00,0.0 2014-01-31 19:45:00,0.0 2014-01-31 19:50:00,0.41 2014-01-31 19:55:00,0.0 2014-01-31 20:00:00,0.33799999999999997 2014-01-31 20:05:00,0.0 2014-01-31 20:10:00,0.33399999999999996 2014-01-31 20:15:00,0.0 2014-01-31 20:20:00,0.33799999999999997 2014-01-31 20:25:00,0.0 2014-01-31 20:30:00,0.0 2014-01-31 20:35:00,0.0 2014-01-31 20:40:00,0.0 2014-01-31 20:45:00,0.33399999999999996 2014-01-31 20:50:00,0.0 2014-01-31 20:55:00,0.33799999999999997 2014-01-31 21:00:00,0.0 2014-01-31 21:05:00,1.646 2014-01-31 21:10:00,0.0 2014-01-31 21:15:00,0.0 2014-01-31 21:20:00,0.672 2014-01-31 21:25:00,0.0 2014-01-31 21:30:00,0.33399999999999996 2014-01-31 21:35:00,0.0 2014-01-31 21:40:00,0.33399999999999996 2014-01-31 21:45:00,0.0 2014-01-31 21:50:00,0.0 2014-01-31 21:55:00,0.33799999999999997 2014-01-31 22:00:00,0.33799999999999997 2014-01-31 22:05:00,0.0 2014-01-31 22:10:00,0.0 2014-01-31 22:15:00,0.32799999999999996 2014-01-31 22:20:00,0.0 2014-01-31 22:25:00,0.0 2014-01-31 22:30:00,0.0 2014-01-31 22:35:00,0.0 2014-01-31 22:40:00,0.33399999999999996 2014-01-31 22:45:00,0.0 2014-01-31 22:50:00,0.33399999999999996 2014-01-31 22:55:00,0.0 2014-01-31 23:00:00,0.33399999999999996 2014-01-31 23:05:00,0.0 2014-01-31 23:10:00,0.32799999999999996 2014-01-31 23:15:00,0.0 2014-01-31 23:20:00,0.32799999999999996 2014-01-31 23:25:00,0.0 2014-01-31 23:30:00,0.33399999999999996 2014-01-31 23:35:00,0.0 2014-01-31 23:40:00,0.0 2014-01-31 23:45:00,0.32799999999999996 2014-01-31 23:50:00,0.0 2014-01-31 23:55:00,0.33799999999999997 2014-02-01 00:00:00,0.0 2014-02-01 00:05:00,0.33399999999999996 2014-02-01 00:10:00,0.0 2014-02-01 00:15:00,0.33399999999999996 2014-02-01 00:20:00,0.0 2014-02-01 00:25:00,0.32799999999999996 2014-02-01 00:30:00,0.0 2014-02-01 00:35:00,0.0 2014-02-01 00:40:00,0.33799999999999997 2014-02-01 00:45:00,0.0 2014-02-01 00:50:00,0.0 2014-02-01 00:55:00,0.0 2014-02-01 01:00:00,0.33399999999999996 ================================================ FILE: workspace/anomaly_detector/datasets/selected/level_change/rds_cpu_utilization_cc0c53.csv ================================================ timestamp,value 2014-02-14 14:30:00,6.456 2014-02-14 14:35:00,5.816 2014-02-14 14:40:00,6.268 2014-02-14 14:45:00,5.816 2014-02-14 14:50:00,5.862 2014-02-14 14:55:00,6.246 2014-02-14 15:00:00,6.648 2014-02-14 15:05:00,6.4479999999999995 2014-02-14 15:10:00,6.46 2014-02-14 15:15:00,5.834 2014-02-14 15:20:00,6.232 2014-02-14 15:25:00,6.064 2014-02-14 15:30:00,6.0520000000000005 2014-02-14 15:35:00,5.834 2014-02-14 15:40:00,6.4639999999999995 2014-02-14 15:45:00,5.622000000000001 2014-02-14 15:50:00,6.2379999999999995 2014-02-14 15:55:00,6.06 2014-02-14 16:00:00,6.04 2014-02-14 16:05:00,5.837999999999999 2014-02-14 16:10:00,6.024 2014-02-14 16:15:00,5.86 2014-02-14 16:20:00,6.432 2014-02-14 16:25:00,6.6720000000000015 2014-02-14 16:30:00,6.0520000000000005 2014-02-14 16:35:00,5.63 2014-02-14 16:40:00,6.226 2014-02-14 16:45:00,6.06 2014-02-14 16:50:00,5.85 2014-02-14 16:55:00,6.022 2014-02-14 17:00:00,6.058 2014-02-14 17:05:00,5.622000000000001 2014-02-14 17:10:00,6.268 2014-02-14 17:15:00,6.454 2014-02-14 17:20:00,7.066 2014-02-14 17:25:00,5.856 2014-02-14 17:30:00,6.254 2014-02-14 17:35:00,6.024 2014-02-14 17:40:00,6.278 2014-02-14 17:45:00,5.834 2014-02-14 17:50:00,5.843999999999999 2014-02-14 17:55:00,5.834 2014-02-14 18:00:00,6.053999999999999 2014-02-14 18:05:00,6.226 2014-02-14 18:10:00,5.6160000000000005 2014-02-14 18:15:00,5.64 2014-02-14 18:20:00,6.03 2014-02-14 18:25:00,5.864 2014-02-14 18:30:00,7.27 2014-02-14 18:35:00,6.018 2014-02-14 18:40:00,6.2620000000000005 2014-02-14 18:45:00,5.8420000000000005 2014-02-14 18:50:00,5.85 2014-02-14 18:55:00,6.046 2014-02-14 19:00:00,6.044 2014-02-14 19:05:00,5.827999999999999 2014-02-14 19:10:00,6.476 2014-02-14 19:15:00,6.046 2014-02-14 19:20:00,6.04 2014-02-14 19:25:00,6.0420000000000025 2014-02-14 19:30:00,7.104 2014-02-14 19:35:00,6.246 2014-02-14 19:40:00,6.2379999999999995 2014-02-14 19:45:00,5.8660000000000005 2014-02-14 19:50:00,6.044 2014-02-14 19:55:00,5.834 2014-02-14 20:00:00,6.25 2014-02-14 20:05:00,5.834 2014-02-14 20:10:00,6.2139999999999995 2014-02-14 20:15:00,5.8420000000000005 2014-02-14 20:20:00,6.474 2014-02-14 20:25:00,6.642 2014-02-14 20:30:00,6.058 2014-02-14 20:35:00,5.814 2014-02-14 20:40:00,6.058 2014-02-14 20:45:00,5.824 2014-02-14 20:50:00,6.04 2014-02-14 20:55:00,6.022 2014-02-14 21:00:00,5.85 2014-02-14 21:05:00,6.0360000000000005 2014-02-14 21:10:00,6.056 2014-02-14 21:15:00,5.622000000000001 2014-02-14 21:20:00,7.266 2014-02-14 21:25:00,6.074 2014-02-14 21:30:00,6.024 2014-02-14 21:35:00,5.862 2014-02-14 21:40:00,6.44 2014-02-14 21:45:00,6.0520000000000005 2014-02-14 21:50:00,6.246 2014-02-14 21:55:00,6.2860000000000005 2014-02-14 22:00:00,6.0520000000000005 2014-02-14 22:05:00,6.013999999999999 2014-02-14 22:10:00,6.257999999999999 2014-02-14 22:15:00,5.837999999999999 2014-02-14 22:20:00,6.2379999999999995 2014-02-14 22:25:00,6.072 2014-02-14 22:30:00,6.85 2014-02-14 22:35:00,6.476 2014-02-14 22:40:00,6.257999999999999 2014-02-14 22:45:00,6.48 2014-02-14 22:50:00,5.398 2014-02-14 22:55:00,6.044 2014-02-14 23:00:00,6.0820000000000025 2014-02-14 23:05:00,5.834 2014-02-14 23:10:00,6.63 2014-02-14 23:15:00,6.6979999999999995 2014-02-14 23:20:00,6.004 2014-02-14 23:25:00,5.654 2014-02-14 23:30:00,6.266 2014-02-14 23:35:00,5.62 2014-02-14 23:40:00,6.2479999999999976 2014-02-14 23:45:00,5.62 2014-02-14 23:50:00,6.028 2014-02-14 23:55:00,5.9460000000000015 2014-02-15 00:00:00,6.232 2014-02-15 00:05:00,5.81 2014-02-15 00:10:00,6.297999999999999 2014-02-15 00:15:00,7.09 2014-02-15 00:20:00,6.666 2014-02-15 00:25:00,6.046 2014-02-15 00:30:00,6.226 2014-02-15 00:35:00,5.862 2014-02-15 00:40:00,6.263999999999999 2014-02-15 00:45:00,5.816 2014-02-15 00:50:00,6.062 2014-02-15 00:55:00,6.068 2014-02-15 01:00:00,6.044 2014-02-15 01:05:00,5.827999999999999 2014-02-15 01:10:00,7.883999999999999 2014-02-15 01:15:00,6.077999999999999 2014-02-15 01:20:00,6.2520000000000024 2014-02-15 01:25:00,5.834 2014-02-15 01:30:00,5.8320000000000025 2014-02-15 01:35:00,6.03 2014-02-15 01:40:00,6.224 2014-02-15 01:45:00,5.862 2014-02-15 01:50:00,6.232 2014-02-15 01:55:00,6.2479999999999976 2014-02-15 02:00:00,6.266 2014-02-15 02:05:00,7.334 2014-02-15 02:10:00,6.6739999999999995 2014-02-15 02:15:00,6.0360000000000005 2014-02-15 02:20:00,6.2379999999999995 2014-02-15 02:25:00,6.047999999999999 2014-02-15 02:30:00,6.09 2014-02-15 02:35:00,5.816 2014-02-15 02:40:00,6.2860000000000005 2014-02-15 02:45:00,5.834 2014-02-15 02:50:00,6.04 2014-02-15 02:55:00,6.0360000000000005 2014-02-15 03:00:00,6.2360000000000015 2014-02-15 03:05:00,5.834 2014-02-15 03:10:00,6.03 2014-02-15 03:15:00,5.848 2014-02-15 03:20:00,6.037999999999999 2014-02-15 03:25:00,7.114 2014-02-15 03:30:00,6.86 2014-02-15 03:35:00,5.8420000000000005 2014-02-15 03:40:00,6.2620000000000005 2014-02-15 03:45:00,6.06 2014-02-15 03:50:00,6.2360000000000015 2014-02-15 03:55:00,6.282 2014-02-15 04:00:00,6.438 2014-02-15 04:05:00,6.04 2014-02-15 04:10:00,6.2 2014-02-15 04:15:00,6.07 2014-02-15 04:20:00,6.044 2014-02-15 04:25:00,6.046 2014-02-15 04:30:00,6.024 2014-02-15 04:35:00,5.862 2014-02-15 04:40:00,6.044 2014-02-15 04:45:00,6.05 2014-02-15 04:50:00,6.044 2014-02-15 04:55:00,6.018 2014-02-15 05:00:00,5.867999999999999 2014-02-15 05:05:00,6.04 2014-02-15 05:10:00,6.257999999999999 2014-02-15 05:15:00,5.837999999999999 2014-02-15 05:20:00,5.827999999999999 2014-02-15 05:25:00,6.022 2014-02-15 05:30:00,6.087999999999999 2014-02-15 05:35:00,5.834 2014-02-15 05:40:00,5.837999999999999 2014-02-15 05:45:00,6.046 2014-02-15 05:50:00,6.6679999999999975 2014-02-15 05:55:00,6.234 2014-02-15 06:00:00,5.87 2014-02-15 06:05:00,6.028 2014-02-15 06:10:00,6.058 2014-02-15 06:15:00,6.0420000000000025 2014-02-15 06:20:00,6.26 2014-02-15 06:25:00,6.024 2014-02-15 06:30:00,6.266 2014-02-15 06:35:00,6.224 2014-02-15 06:40:00,6.074 2014-02-15 06:45:00,6.04 2014-02-15 06:50:00,6.2520000000000024 2014-02-15 06:55:00,6.25 2014-02-15 07:00:00,6.04 2014-02-15 07:05:00,6.04 2014-02-15 07:10:00,6.25 2014-02-15 07:15:00,6.04 2014-02-15 07:20:00,6.257999999999999 2014-02-15 07:25:00,6.0420000000000025 2014-02-15 07:30:00,6.044 2014-02-15 07:35:00,5.816 2014-02-15 07:40:00,6.284 2014-02-15 07:45:00,5.602 2014-02-15 07:50:00,6.266 2014-02-15 07:55:00,6.86 2014-02-15 08:00:00,5.803999999999999 2014-02-15 08:05:00,6.436 2014-02-15 08:10:00,6.65 2014-02-15 08:15:00,5.228 2014-02-15 08:20:00,5.846 2014-02-15 08:25:00,6.0420000000000025 2014-02-15 08:30:00,6.047999999999999 2014-02-15 08:35:00,5.63 2014-02-15 08:40:00,6.4460000000000015 2014-02-15 08:45:00,5.86 2014-02-15 08:50:00,6.2520000000000024 2014-02-15 08:55:00,6.23 2014-02-15 09:00:00,6.077999999999999 2014-02-15 09:05:00,6.2520000000000024 2014-02-15 09:10:00,6.232 2014-02-15 09:15:00,6.44 2014-02-15 09:20:00,6.058 2014-02-15 09:25:00,6.2479999999999976 2014-02-15 09:30:00,6.047999999999999 2014-02-15 09:35:00,6.046 2014-02-15 09:40:00,6.228 2014-02-15 09:45:00,6.068 2014-02-15 09:50:00,6.058 2014-02-15 09:55:00,6.0420000000000025 2014-02-15 10:00:00,6.2379999999999995 2014-02-15 10:05:00,5.648 2014-02-15 10:10:00,6.85 2014-02-15 10:15:00,5.81 2014-02-15 10:20:00,6.058 2014-02-15 10:25:00,6.06 2014-02-15 10:30:00,6.047999999999999 2014-02-15 10:35:00,5.827999999999999 2014-02-15 10:40:00,5.8420000000000005 2014-02-15 10:45:00,6.222 2014-02-15 10:50:00,6.053999999999999 2014-02-15 10:55:00,6.46 2014-02-15 11:00:00,6.228 2014-02-15 11:05:00,6.046 2014-02-15 11:10:00,7.106 2014-02-15 11:15:00,6.068 2014-02-15 11:20:00,6.644 2014-02-15 11:25:00,6.454 2014-02-15 11:30:00,6.478 2014-02-15 11:35:00,6.25 2014-02-15 11:40:00,6.644 2014-02-15 11:45:00,6.2520000000000024 2014-02-15 11:50:00,6.482 2014-02-15 11:55:00,6.2620000000000005 2014-02-15 12:00:00,6.416 2014-02-15 12:05:00,6.064 2014-02-15 12:10:00,6.44 2014-02-15 12:15:00,6.2520000000000024 2014-02-15 12:20:00,6.444 2014-02-15 12:25:00,6.4579999999999975 2014-02-15 12:30:00,7.062 2014-02-15 12:35:00,6.224 2014-02-15 12:40:00,6.666 2014-02-15 12:45:00,6.282 2014-02-15 12:50:00,6.416 2014-02-15 12:55:00,6.478 2014-02-15 13:00:00,6.644 2014-02-15 13:05:00,6.25 2014-02-15 13:10:00,6.45 2014-02-15 13:15:00,6.263999999999999 2014-02-15 13:20:00,7.27 2014-02-15 13:25:00,6.04 2014-02-15 13:30:00,6.46 2014-02-15 13:35:00,6.454 2014-02-15 13:40:00,6.452000000000001 2014-02-15 13:45:00,6.222 2014-02-15 13:50:00,6.26 2014-02-15 13:55:00,6.49 2014-02-15 14:00:00,6.472 2014-02-15 14:05:00,6.4620000000000015 2014-02-15 14:10:00,6.888 2014-02-15 14:15:00,6.23 2014-02-15 14:20:00,6.912000000000001 2014-02-15 14:25:00,5.8320000000000025 2014-02-15 14:30:00,6.0420000000000025 2014-02-15 14:35:00,6.432 2014-02-15 14:40:00,6.478 2014-02-15 14:45:00,6.272 2014-02-15 14:50:00,6.232 2014-02-15 14:55:00,6.688 2014-02-15 15:00:00,6.4460000000000015 2014-02-15 15:05:00,6.468 2014-02-15 15:10:00,6.48 2014-02-15 15:15:00,6.0420000000000025 2014-02-15 15:20:00,7.056 2014-02-15 15:25:00,6.47 2014-02-15 15:30:00,6.2860000000000005 2014-02-15 15:35:00,6.034 2014-02-15 15:40:00,6.472 2014-02-15 15:45:00,6.0420000000000025 2014-02-15 15:50:00,6.2479999999999976 2014-02-15 15:55:00,6.254 2014-02-15 16:00:00,6.426 2014-02-15 16:05:00,5.834 2014-02-15 16:10:00,6.472 2014-02-15 16:15:00,5.816 2014-02-15 16:20:00,6.27 2014-02-15 16:25:00,6.256 2014-02-15 16:30:00,6.85 2014-02-15 16:35:00,6.282 2014-02-15 16:40:00,6.2479999999999976 2014-02-15 16:45:00,6.0360000000000005 2014-02-15 16:50:00,6.016 2014-02-15 16:55:00,6.07 2014-02-15 17:00:00,6.25 2014-02-15 17:05:00,6.0420000000000025 2014-02-15 17:10:00,6.442 2014-02-15 17:15:00,6.706 2014-02-15 17:20:00,6.01 2014-02-15 17:25:00,6.074 2014-02-15 17:30:00,6.2520000000000024 2014-02-15 17:35:00,5.834 2014-02-15 17:40:00,6.228 2014-02-15 17:45:00,5.648 2014-02-15 17:50:00,6.2520000000000024 2014-02-15 17:55:00,6.0420000000000025 2014-02-15 18:00:00,7.5 2014-02-15 18:05:00,5.822 2014-02-15 18:10:00,6.44 2014-02-15 18:15:00,6.0420000000000025 2014-02-15 18:20:00,6.218 2014-02-15 18:25:00,6.244 2014-02-15 18:30:00,6.2479999999999976 2014-02-15 18:35:00,6.0420000000000025 2014-02-15 18:40:00,6.256 2014-02-15 18:45:00,6.86 2014-02-15 18:50:00,6.4220000000000015 2014-02-15 18:55:00,6.0520000000000005 2014-02-15 19:00:00,6.274 2014-02-15 19:05:00,5.83 2014-02-15 19:10:00,6.46 2014-02-15 19:15:00,6.226 2014-02-15 19:20:00,6.926 2014-02-15 19:25:00,5.617999999999999 2014-02-15 19:30:00,6.266 2014-02-15 19:35:00,5.81 2014-02-15 19:40:00,6.077999999999999 2014-02-15 19:45:00,5.834 2014-02-15 19:50:00,5.814 2014-02-15 19:55:00,6.044 2014-02-15 20:00:00,5.843999999999999 2014-02-15 20:05:00,5.8320000000000025 2014-02-15 20:10:00,6.2520000000000024 2014-02-15 20:15:00,7.08 2014-02-15 20:20:00,5.8320000000000025 2014-02-15 20:25:00,5.814 2014-02-15 20:30:00,5.846 2014-02-15 20:35:00,5.834 2014-02-15 20:40:00,6.642 2014-02-15 20:45:00,5.86 2014-02-15 20:50:00,6.03 2014-02-15 20:55:00,6.276 2014-02-15 21:00:00,6.028 2014-02-15 21:05:00,6.046 2014-02-15 21:10:00,6.276 2014-02-15 21:15:00,6.904 2014-02-15 21:20:00,6.648 2014-02-15 21:25:00,5.654 2014-02-15 21:30:00,6.44 2014-02-15 21:35:00,5.8660000000000005 2014-02-15 21:40:00,6.246 2014-02-15 21:45:00,5.837999999999999 2014-02-15 21:50:00,5.9979999999999976 2014-02-15 21:55:00,5.862 2014-02-15 22:00:00,6.6720000000000015 2014-02-15 22:05:00,7.63667 2014-02-15 22:10:00,6.034 2014-02-15 22:15:00,5.648 2014-02-15 22:20:00,6.0120000000000005 2014-02-15 22:25:00,5.8320000000000025 2014-02-15 22:30:00,6.024 2014-02-15 22:35:00,5.862 2014-02-15 22:40:00,6.044 2014-02-15 22:45:00,6.0420000000000025 2014-02-15 22:50:00,6.266 2014-02-15 22:55:00,6.022 2014-02-15 23:00:00,6.086 2014-02-15 23:05:00,6.034 2014-02-15 23:10:00,6.2479999999999976 2014-02-15 23:15:00,7.5020000000000024 2014-02-15 23:20:00,6.2520000000000024 2014-02-15 23:25:00,6.026 2014-02-15 23:30:00,6.07 2014-02-15 23:35:00,5.834 2014-02-15 23:40:00,6.05 2014-02-15 23:45:00,6.0420000000000025 2014-02-15 23:50:00,6.024 2014-02-15 23:55:00,5.756 2014-02-16 00:00:00,7.43 2014-02-16 00:05:00,6.686 2014-02-16 00:10:00,6.228 2014-02-16 00:15:00,6.28 2014-02-16 00:20:00,6.044 2014-02-16 00:25:00,6.246 2014-02-16 00:30:00,6.2479999999999976 2014-02-16 00:35:00,6.0420000000000025 2014-02-16 00:40:00,6.472 2014-02-16 00:45:00,6.04 2014-02-16 00:50:00,6.028 2014-02-16 00:55:00,6.2520000000000024 2014-02-16 01:00:00,6.224 2014-02-16 01:05:00,5.837999999999999 2014-02-16 01:10:00,6.63 2014-02-16 01:15:00,6.0420000000000025 2014-02-16 01:20:00,6.228 2014-02-16 01:25:00,6.05 2014-02-16 01:30:00,6.506 2014-02-16 01:35:00,7.268 2014-02-16 01:40:00,6.072 2014-02-16 01:45:00,5.834 2014-02-16 01:50:00,6.0520000000000005 2014-02-16 01:55:00,6.046 2014-02-16 02:00:00,6.028 2014-02-16 02:05:00,5.852 2014-02-16 02:10:00,6.016 2014-02-16 02:15:00,6.874 2014-02-16 02:20:00,6.864 2014-02-16 02:25:00,6.047999999999999 2014-02-16 02:30:00,5.837999999999999 2014-02-16 02:35:00,5.8660000000000005 2014-02-16 02:40:00,6.044 2014-02-16 02:45:00,5.624 2014-02-16 02:50:00,6.044 2014-02-16 02:55:00,6.0420000000000025 2014-02-16 03:00:00,6.2520000000000024 2014-02-16 03:05:00,7.058 2014-02-16 03:10:00,6.9179999999999975 2014-02-16 03:15:00,6.032 2014-02-16 03:20:00,5.816 2014-02-16 03:25:00,6.066 2014-02-16 03:30:00,5.843999999999999 2014-02-16 03:35:00,5.816 2014-02-16 03:40:00,6.682 2014-02-16 03:45:00,5.19 2014-02-16 03:50:00,5.86 2014-02-16 03:55:00,6.046 2014-02-16 04:00:00,6.0520000000000005 2014-02-16 04:05:00,5.6320000000000014 2014-02-16 04:10:00,6.018 2014-02-16 04:15:00,5.63 2014-02-16 04:20:00,6.066 2014-02-16 04:25:00,6.25 2014-02-16 04:30:00,6.024 2014-02-16 04:35:00,6.0420000000000025 2014-02-16 04:40:00,6.228 2014-02-16 04:45:00,5.6579999999999995 2014-02-16 04:50:00,6.24 2014-02-16 04:55:00,5.856 2014-02-16 05:00:00,6.228 2014-02-16 05:05:00,5.626 2014-02-16 05:10:00,6.016 2014-02-16 05:15:00,5.834 2014-02-16 05:20:00,6.2520000000000024 2014-02-16 05:25:00,5.612 2014-02-16 05:30:00,5.877999999999999 2014-02-16 05:35:00,5.834 2014-02-16 05:40:00,6.0520000000000005 2014-02-16 05:45:00,5.83 2014-02-16 05:50:00,5.843999999999999 2014-02-16 05:55:00,6.0420000000000025 2014-02-16 06:00:00,6.044 2014-02-16 06:05:00,5.827999999999999 2014-02-16 06:10:00,6.044 2014-02-16 06:15:00,5.626 2014-02-16 06:20:00,6.046 2014-02-16 06:25:00,5.8320000000000025 2014-02-16 06:30:00,6.04 2014-02-16 06:35:00,5.816 2014-02-16 06:40:00,6.058 2014-02-16 06:45:00,5.834 2014-02-16 06:50:00,6.024 2014-02-16 06:55:00,6.0420000000000025 2014-02-16 07:00:00,6.256 2014-02-16 07:05:00,5.626 2014-02-16 07:10:00,6.2520000000000024 2014-02-16 07:15:00,6.232 2014-02-16 07:20:00,7.09 2014-02-16 07:25:00,5.398 2014-02-16 07:30:00,5.864 2014-02-16 07:35:00,5.803999999999999 2014-02-16 07:40:00,6.2860000000000005 2014-02-16 07:45:00,5.834 2014-02-16 07:50:00,6.03 2014-02-16 07:55:00,7.122000000000001 2014-02-16 08:00:00,6.436 2014-02-16 08:05:00,6.046 2014-02-16 08:10:00,6.004 2014-02-16 08:15:00,5.837999999999999 2014-02-16 08:20:00,6.278 2014-02-16 08:25:00,5.834 2014-02-16 08:30:00,6.876 2014-02-16 08:35:00,5.1960000000000015 2014-02-16 08:40:00,6.268 2014-02-16 08:45:00,5.81 2014-02-16 08:50:00,6.268 2014-02-16 08:55:00,6.0360000000000005 2014-02-16 09:00:00,6.2860000000000005 2014-02-16 09:05:00,5.834 2014-02-16 09:10:00,6.82 2014-02-16 09:15:00,6.0520000000000005 2014-02-16 09:20:00,6.266 2014-02-16 09:25:00,6.0420000000000025 2014-02-16 09:30:00,6.2479999999999976 2014-02-16 09:35:00,6.23 2014-02-16 09:40:00,6.4879999999999995 2014-02-16 09:45:00,5.608 2014-02-16 09:50:00,6.266 2014-02-16 09:55:00,6.456 2014-02-16 10:00:00,6.05 2014-02-16 10:05:00,5.862 2014-02-16 10:10:00,6.263999999999999 2014-02-16 10:15:00,5.816 2014-02-16 10:20:00,7.104 2014-02-16 10:25:00,5.44 2014-02-16 10:30:00,5.808 2014-02-16 10:35:00,6.034 2014-02-16 10:40:00,6.6720000000000015 2014-02-16 10:45:00,5.822 2014-02-16 10:50:00,6.412000000000001 2014-02-16 10:55:00,6.4860000000000015 2014-02-16 11:00:00,6.436 2014-02-16 11:05:00,6.877999999999999 2014-02-16 11:10:00,6.256 2014-02-16 11:15:00,6.438 2014-02-16 11:20:00,6.077999999999999 2014-02-16 11:25:00,6.256 2014-02-16 11:30:00,6.662000000000001 2014-02-16 11:35:00,6.0420000000000025 2014-02-16 11:40:00,6.6679999999999975 2014-02-16 11:45:00,6.23 2014-02-16 11:50:00,6.2479999999999976 2014-02-16 11:55:00,6.278 2014-02-16 12:00:00,6.4460000000000015 2014-02-16 12:05:00,6.2620000000000005 2014-02-16 12:10:00,6.722 2014-02-16 12:15:00,6.858 2014-02-16 12:20:00,6.294 2014-02-16 12:25:00,6.23 2014-02-16 12:30:00,6.274 2014-02-16 12:35:00,6.257999999999999 2014-02-16 12:40:00,6.688 2014-02-16 12:45:00,6.257999999999999 2014-02-16 12:50:00,6.706 2014-02-16 12:55:00,6.4579999999999975 2014-02-16 13:00:00,6.4639999999999995 2014-02-16 13:05:00,6.874 2014-02-16 13:10:00,6.872000000000001 2014-02-16 13:15:00,6.0420000000000025 2014-02-16 13:20:00,6.6679999999999975 2014-02-16 13:25:00,6.25 2014-02-16 13:30:00,6.2520000000000024 2014-02-16 13:35:00,6.0420000000000025 2014-02-16 13:40:00,6.228 2014-02-16 13:45:00,6.064 2014-02-16 13:50:00,6.2360000000000015 2014-02-16 13:55:00,6.47 2014-02-16 14:00:00,6.436 2014-02-16 14:05:00,6.064 2014-02-16 14:10:00,6.436 2014-02-16 14:15:00,6.072 2014-02-16 14:20:00,7.29 2014-02-16 14:25:00,6.0420000000000025 2014-02-16 14:30:00,6.6720000000000015 2014-02-16 14:35:00,6.024 2014-02-16 14:40:00,6.5020000000000024 2014-02-16 14:45:00,6.46 2014-02-16 14:50:00,6.2479999999999976 2014-02-16 14:55:00,6.436 2014-02-16 15:00:00,6.4979999999999976 2014-02-16 15:05:00,6.232 2014-02-16 15:10:00,7.5120000000000005 2014-02-16 15:15:00,6.2620000000000005 2014-02-16 15:20:00,6.2860000000000005 2014-02-16 15:25:00,6.23 2014-02-16 15:30:00,6.266 2014-02-16 15:35:00,6.06 2014-02-16 15:40:00,6.476 2014-02-16 15:45:00,6.25 2014-02-16 15:50:00,6.644 2014-02-16 15:55:00,6.4639999999999995 2014-02-16 16:00:00,6.706 2014-02-16 16:05:00,6.874 2014-02-16 16:10:00,6.03 2014-02-16 16:15:00,6.234 2014-02-16 16:20:00,6.6720000000000015 2014-02-16 16:25:00,7.077999999999999 2014-02-16 16:30:00,6.468 2014-02-16 16:35:00,6.25 2014-02-16 16:40:00,6.444 2014-02-16 16:45:00,6.25 2014-02-16 16:50:00,6.46 2014-02-16 16:55:00,6.666 2014-02-16 17:00:00,6.2120000000000015 2014-02-16 17:05:00,6.278 2014-02-16 17:10:00,6.4220000000000015 2014-02-16 17:15:00,5.862 2014-02-16 17:20:00,6.04 2014-02-16 17:25:00,6.222 2014-02-16 17:30:00,7.1339999999999995 2014-02-16 17:35:00,5.827999999999999 2014-02-16 17:40:00,6.044 2014-02-16 17:45:00,6.022 2014-02-16 17:50:00,5.867999999999999 2014-02-16 17:55:00,6.037999999999999 2014-02-16 18:00:00,6.2520000000000024 2014-02-16 18:05:00,5.834 2014-02-16 18:10:00,7.6560000000000015 2014-02-16 18:15:00,5.228 2014-02-16 18:20:00,6.232 2014-02-16 18:25:00,6.074 2014-02-16 18:30:00,6.436 2014-02-16 18:35:00,6.0360000000000005 2014-02-16 18:40:00,6.228 2014-02-16 18:45:00,6.068 2014-02-16 18:50:00,6.04 2014-02-16 18:55:00,6.224 2014-02-16 19:00:00,6.254 2014-02-16 19:05:00,6.482 2014-02-16 19:10:00,5.602 2014-02-16 19:15:00,7.114 2014-02-16 19:20:00,6.244 2014-02-16 19:25:00,6.022 2014-02-16 19:30:00,6.086 2014-02-16 19:35:00,5.81 2014-02-16 19:40:00,6.257999999999999 2014-02-16 19:45:00,5.834 2014-02-16 19:50:00,6.044 2014-02-16 19:55:00,6.0420000000000025 2014-02-16 20:00:00,6.047999999999999 2014-02-16 20:05:00,5.834 2014-02-16 20:10:00,6.228 2014-02-16 20:15:00,6.86 2014-02-16 20:20:00,5.816 2014-02-16 20:25:00,6.4579999999999975 2014-02-16 20:30:00,7.126 2014-02-16 20:35:00,5.626 2014-02-16 20:40:00,6.006 2014-02-16 20:45:00,5.862 2014-02-16 20:50:00,6.05 2014-02-16 20:55:00,5.834 2014-02-16 21:00:00,6.056 2014-02-16 21:05:00,6.02 2014-02-16 21:10:00,6.062 2014-02-16 21:15:00,6.064 2014-02-16 21:20:00,6.0420000000000025 2014-02-16 21:25:00,6.68 2014-02-16 21:30:00,7.08 2014-02-16 21:35:00,5.814 2014-02-16 21:40:00,6.077999999999999 2014-02-16 21:45:00,6.006 2014-02-16 21:50:00,5.864 2014-02-16 21:55:00,5.834 2014-02-16 22:00:00,6.4579999999999975 2014-02-16 22:05:00,5.82 2014-02-16 22:10:00,6.91 2014-02-16 22:15:00,6.44 2014-02-16 22:20:00,6.086 2014-02-16 22:25:00,6.037999999999999 2014-02-16 22:30:00,6.053999999999999 2014-02-16 22:35:00,6.0420000000000025 2014-02-16 22:40:00,6.03 2014-02-16 22:45:00,6.064 2014-02-16 22:50:00,6.044 2014-02-16 22:55:00,6.0420000000000025 2014-02-16 23:00:00,6.2520000000000024 2014-02-16 23:05:00,6.0420000000000025 2014-02-16 23:10:00,6.2479999999999976 2014-02-16 23:15:00,6.024 2014-02-16 23:20:00,6.272 2014-02-16 23:25:00,7.51 2014-02-16 23:30:00,6.278 2014-02-16 23:35:00,6.064 2014-02-16 23:40:00,6.2520000000000024 2014-02-16 23:45:00,5.816 2014-02-16 23:50:00,6.256 2014-02-16 23:55:00,6.166 2014-02-17 00:00:00,6.354 2014-02-17 00:05:00,7.318 2014-02-17 00:10:00,6.43 2014-02-17 00:15:00,6.0420000000000025 2014-02-17 00:20:00,6.256 2014-02-17 00:25:00,6.0420000000000025 2014-02-17 00:30:00,6.2520000000000024 2014-02-17 00:35:00,5.837999999999999 2014-02-17 00:40:00,6.2379999999999995 2014-02-17 00:45:00,5.862 2014-02-17 00:50:00,6.044 2014-02-17 00:55:00,6.25 2014-02-17 01:00:00,6.047999999999999 2014-02-17 01:05:00,5.837999999999999 2014-02-17 01:10:00,6.438 2014-02-17 01:15:00,5.8320000000000025 2014-02-17 01:20:00,6.03 2014-02-17 01:25:00,6.053999999999999 2014-02-17 01:30:00,7.528 2014-02-17 01:35:00,5.8420000000000005 2014-02-17 01:40:00,6.056 2014-02-17 01:45:00,5.8420000000000005 2014-02-17 01:50:00,6.016 2014-02-17 01:55:00,5.8660000000000005 2014-02-17 02:00:00,6.0520000000000005 2014-02-17 02:05:00,6.01 2014-02-17 02:10:00,6.0520000000000005 2014-02-17 02:15:00,5.63 2014-02-17 02:20:00,7.7 2014-02-17 02:25:00,6.244 2014-02-17 02:30:00,6.246 2014-02-17 02:35:00,5.638 2014-02-17 02:40:00,6.297999999999999 2014-02-17 02:45:00,6.032 2014-02-17 02:50:00,6.2520000000000024 2014-02-17 02:55:00,6.022 2014-02-17 03:00:00,6.482 2014-02-17 03:05:00,6.06 2014-02-17 03:10:00,6.2520000000000024 2014-02-17 03:15:00,7.077999999999999 2014-02-17 03:20:00,6.654 2014-02-17 03:25:00,6.068 2014-02-17 03:30:00,6.044 2014-02-17 03:35:00,5.834 2014-02-17 03:40:00,6.25 2014-02-17 03:45:00,6.452000000000001 2014-02-17 03:50:00,5.626 2014-02-17 03:55:00,6.018 2014-02-17 04:00:00,6.0820000000000025 2014-02-17 04:05:00,6.024 2014-02-17 04:10:00,6.096 2014-02-17 04:15:00,5.837999999999999 2014-02-17 04:20:00,6.263999999999999 2014-02-17 04:25:00,5.814 2014-02-17 04:30:00,6.086 2014-02-17 04:35:00,5.8420000000000005 2014-02-17 04:40:00,6.028 2014-02-17 04:45:00,5.816 2014-02-17 04:50:00,5.8839999999999995 2014-02-17 04:55:00,6.246 2014-02-17 05:00:00,6.204 2014-02-17 05:05:00,5.86 2014-02-17 05:10:00,6.016 2014-02-17 05:15:00,6.028 2014-02-17 05:20:00,6.7120000000000015 2014-02-17 05:25:00,5.837999999999999 2014-02-17 05:30:00,6.478 2014-02-17 05:35:00,5.814 2014-02-17 05:40:00,6.297999999999999 2014-02-17 05:45:00,6.0420000000000025 2014-02-17 05:50:00,6.2479999999999976 2014-02-17 05:55:00,6.034 2014-02-17 06:00:00,6.228 2014-02-17 06:05:00,6.05 2014-02-17 06:10:00,6.494 2014-02-17 06:15:00,5.816 2014-02-17 06:20:00,6.077999999999999 2014-02-17 06:25:00,6.04 2014-02-17 06:30:00,6.228 2014-02-17 06:35:00,5.856 2014-02-17 06:40:00,6.04 2014-02-17 06:45:00,6.034 2014-02-17 06:50:00,6.046 2014-02-17 06:55:00,5.834 2014-02-17 07:00:00,6.2479999999999976 2014-02-17 07:05:00,6.046 2014-02-17 07:10:00,6.0360000000000005 2014-02-17 07:15:00,6.05 2014-02-17 07:20:00,5.85 2014-02-17 07:25:00,6.044 2014-02-17 07:30:00,6.016 2014-02-17 07:35:00,5.834 2014-02-17 07:40:00,6.044 2014-02-17 07:45:00,6.04 2014-02-17 07:50:00,6.228 2014-02-17 07:55:00,7.29 2014-02-17 08:00:00,6.412000000000001 2014-02-17 08:05:00,6.064 2014-02-17 08:10:00,6.23 2014-02-17 08:15:00,6.234 2014-02-17 08:20:00,6.087999999999999 2014-02-17 08:25:00,6.047999999999999 2014-02-17 08:30:00,6.228 2014-02-17 08:35:00,6.022 2014-02-17 08:40:00,6.282 2014-02-17 08:45:00,6.228 2014-02-17 08:50:00,6.2620000000000005 2014-02-17 08:55:00,6.0420000000000025 2014-02-17 09:00:00,6.022 2014-02-17 09:05:00,6.064 2014-02-17 09:10:00,6.452000000000001 2014-02-17 09:15:00,5.814 2014-02-17 09:20:00,5.867999999999999 2014-02-17 09:25:00,6.0420000000000025 2014-02-17 09:30:00,6.0120000000000005 2014-02-17 09:35:00,5.64 2014-02-17 09:40:00,6.03 2014-02-17 09:45:00,5.852 2014-02-17 09:50:00,5.9979999999999976 2014-02-17 09:55:00,6.074 2014-02-17 10:00:00,5.824 2014-02-17 10:05:00,5.836 2014-02-17 10:10:00,6.246 2014-02-17 10:15:00,5.8320000000000025 2014-02-17 10:20:00,6.2520000000000024 2014-02-17 10:25:00,6.664 2014-02-17 10:30:00,6.04 2014-02-17 10:35:00,6.046 2014-02-17 10:40:00,6.2620000000000005 2014-02-17 10:45:00,6.0420000000000025 2014-02-17 10:50:00,6.044 2014-02-17 10:55:00,6.026 2014-02-17 11:00:00,6.26 2014-02-17 11:05:00,6.25 2014-02-17 11:10:00,6.684 2014-02-17 11:15:00,5.8420000000000005 2014-02-17 11:20:00,5.834 2014-02-17 11:25:00,6.242000000000001 2014-02-17 11:30:00,6.024 2014-02-17 11:35:00,5.648 2014-02-17 11:40:00,6.4639999999999995 2014-02-17 11:45:00,5.816 2014-02-17 11:50:00,6.053999999999999 2014-02-17 11:55:00,5.862 2014-02-17 12:00:00,6.05 2014-02-17 12:05:00,5.812 2014-02-17 12:10:00,6.468 2014-02-17 12:15:00,6.2620000000000005 2014-02-17 12:20:00,5.87 2014-02-17 12:25:00,5.834 2014-02-17 12:30:00,6.044 2014-02-17 12:35:00,5.827999999999999 2014-02-17 12:40:00,6.0360000000000005 2014-02-17 12:45:00,5.856 2014-02-17 12:50:00,6.2520000000000024 2014-02-17 12:55:00,6.2520000000000024 2014-02-17 13:00:00,6.43 2014-02-17 13:05:00,6.6679999999999975 2014-02-17 13:10:00,6.2479999999999976 2014-02-17 13:15:00,6.0420000000000025 2014-02-17 13:20:00,6.26 2014-02-17 13:25:00,6.03 2014-02-17 13:30:00,6.028 2014-02-17 13:35:00,6.064 2014-02-17 13:40:00,6.04 2014-02-17 13:45:00,6.0420000000000025 2014-02-17 13:50:00,6.02 2014-02-17 13:55:00,6.07 2014-02-17 14:00:00,6.044 2014-02-17 14:05:00,6.0420000000000025 2014-02-17 14:10:00,6.468 2014-02-17 14:15:00,6.46 2014-02-17 14:20:00,6.004 2014-02-17 14:25:00,6.074 2014-02-17 14:30:00,6.03 2014-02-17 14:35:00,6.05 2014-02-17 14:40:00,6.07 2014-02-17 14:45:00,5.822 2014-02-17 14:50:00,6.03 2014-02-17 14:55:00,6.07 2014-02-17 15:00:00,6.4460000000000015 2014-02-17 15:05:00,6.482 2014-02-17 15:10:00,6.2360000000000015 2014-02-17 15:15:00,5.834 2014-02-17 15:20:00,6.228 2014-02-17 15:25:00,6.234 2014-02-17 15:30:00,6.257999999999999 2014-02-17 15:35:00,5.816 2014-02-17 15:40:00,6.66 2014-02-17 15:45:00,5.856 2014-02-17 15:50:00,6.26 2014-02-17 15:55:00,6.2139999999999995 2014-02-17 16:00:00,6.0820000000000025 2014-02-17 16:05:00,6.046 2014-02-17 16:10:00,6.6679999999999975 2014-02-17 16:15:00,6.4479999999999995 2014-02-17 16:20:00,6.047999999999999 2014-02-17 16:25:00,5.816 2014-02-17 16:30:00,6.086 2014-02-17 16:35:00,5.8260000000000005 2014-02-17 16:40:00,6.04 2014-02-17 16:45:00,5.83 2014-02-17 16:50:00,6.056 2014-02-17 16:55:00,6.047999999999999 2014-02-17 17:00:00,5.846 2014-02-17 17:05:00,5.834 2014-02-17 17:10:00,6.876 2014-02-17 17:15:00,6.442 2014-02-17 17:20:00,6.053999999999999 2014-02-17 17:25:00,5.63 2014-02-17 17:30:00,6.2520000000000024 2014-02-17 17:35:00,5.824 2014-02-17 17:40:00,6.024 2014-02-17 17:45:00,6.022 2014-02-17 17:50:00,6.053999999999999 2014-02-17 17:55:00,6.046 2014-02-17 18:00:00,6.412000000000001 2014-02-17 18:05:00,6.692 2014-02-17 18:10:00,6.68 2014-02-17 18:15:00,5.827999999999999 2014-02-17 18:20:00,6.2520000000000024 2014-02-17 18:25:00,5.82 2014-02-17 18:30:00,6.278 2014-02-17 18:35:00,5.834 2014-02-17 18:40:00,6.263999999999999 2014-02-17 18:45:00,5.836 2014-02-17 18:50:00,6.058 2014-02-17 18:55:00,5.84 2014-02-17 19:00:00,5.992000000000001 2014-02-17 19:05:00,5.848 2014-02-17 19:10:00,7.532 2014-02-17 19:15:00,5.827999999999999 2014-02-17 19:20:00,6.044 2014-02-17 19:25:00,5.8320000000000025 2014-02-17 19:30:00,6.044 2014-02-17 19:35:00,5.626 2014-02-17 19:40:00,6.234 2014-02-17 19:45:00,5.862 2014-02-17 19:50:00,5.8420000000000005 2014-02-17 19:55:00,5.827999999999999 2014-02-17 20:00:00,5.8420000000000005 2014-02-17 20:05:00,6.034 2014-02-17 20:10:00,5.81 2014-02-17 20:15:00,5.837999999999999 2014-02-17 20:20:00,5.85 2014-02-17 20:25:00,6.242000000000001 2014-02-17 20:30:00,6.0 2014-02-17 20:35:00,6.892 2014-02-17 20:40:00,6.4460000000000015 2014-02-17 20:45:00,6.074 2014-02-17 20:50:00,5.82 2014-02-17 20:55:00,5.837999999999999 2014-02-17 21:00:00,6.877999999999999 2014-02-17 21:05:00,6.452000000000001 2014-02-17 21:10:00,6.024 2014-02-17 21:15:00,6.0360000000000005 2014-02-17 21:20:00,6.024 2014-02-17 21:25:00,6.2860000000000005 2014-02-17 21:30:00,7.104 2014-02-17 21:35:00,6.016 2014-02-17 21:40:00,6.077999999999999 2014-02-17 21:45:00,6.034 2014-02-17 21:50:00,6.25 2014-02-17 21:55:00,6.0420000000000025 2014-02-17 22:00:00,6.1979999999999995 2014-02-17 22:05:00,6.068 2014-02-17 22:10:00,6.056 2014-02-17 22:15:00,5.83 2014-02-17 22:20:00,6.018 2014-02-17 22:25:00,5.862 2014-02-17 22:30:00,6.0520000000000005 2014-02-17 22:35:00,5.83 2014-02-17 22:40:00,7.084 2014-02-17 22:45:00,6.25 2014-02-17 22:50:00,6.0520000000000005 2014-02-17 22:55:00,5.834 2014-02-17 23:00:00,6.024 2014-02-17 23:05:00,5.626 2014-02-17 23:10:00,6.22 2014-02-17 23:15:00,5.62 2014-02-17 23:20:00,6.0120000000000005 2014-02-17 23:25:00,5.837999999999999 2014-02-17 23:30:00,7.084 2014-02-17 23:35:00,6.25 2014-02-17 23:40:00,6.256 2014-02-17 23:45:00,5.827999999999999 2014-02-17 23:50:00,6.2520000000000024 2014-02-17 23:55:00,6.176 2014-02-18 00:00:00,6.1 2014-02-18 00:05:00,6.69 2014-02-18 00:10:00,7.06 2014-02-18 00:15:00,6.07 2014-02-18 00:20:00,6.024 2014-02-18 00:25:00,5.843999999999999 2014-02-18 00:30:00,6.287999999999999 2014-02-18 00:35:00,5.827999999999999 2014-02-18 00:40:00,6.062 2014-02-18 00:45:00,5.816 2014-02-18 00:50:00,6.0760000000000005 2014-02-18 00:55:00,6.04 2014-02-18 01:00:00,6.044 2014-02-18 01:05:00,6.04 2014-02-18 01:10:00,7.88 2014-02-18 01:15:00,5.854 2014-02-18 01:20:00,6.026 2014-02-18 01:25:00,6.4860000000000015 2014-02-18 01:30:00,5.4220000000000015 2014-02-18 01:35:00,6.04 2014-02-18 01:40:00,6.03 2014-02-18 01:45:00,5.862 2014-02-18 01:50:00,5.824 2014-02-18 01:55:00,5.834 2014-02-18 02:00:00,6.206 2014-02-18 02:05:00,5.852 2014-02-18 02:10:00,6.2520000000000024 2014-02-18 02:15:00,6.016 2014-02-18 02:20:00,7.76 2014-02-18 02:25:00,6.44 2014-02-18 02:30:00,6.297999999999999 2014-02-18 02:35:00,5.814 2014-02-18 02:40:00,6.278 2014-02-18 02:45:00,6.04 2014-02-18 02:50:00,6.04 2014-02-18 02:55:00,6.028 2014-02-18 03:00:00,7.3279999999999985 2014-02-18 03:05:00,6.6679999999999975 2014-02-18 03:10:00,6.0520000000000005 2014-02-18 03:15:00,6.0420000000000025 2014-02-18 03:20:00,6.0420000000000025 2014-02-18 03:25:00,6.044 2014-02-18 03:30:00,6.056 2014-02-18 03:35:00,5.834 2014-02-18 03:40:00,6.047999999999999 2014-02-18 03:45:00,5.812 2014-02-18 03:50:00,6.09 2014-02-18 03:55:00,6.026 2014-02-18 04:00:00,5.85 2014-02-18 04:05:00,6.034 2014-02-18 04:10:00,6.024 2014-02-18 04:15:00,5.862 2014-02-18 04:20:00,6.02 2014-02-18 04:25:00,5.862 2014-02-18 04:30:00,6.037999999999999 2014-02-18 04:35:00,5.827999999999999 2014-02-18 04:40:00,6.044 2014-02-18 04:45:00,6.024 2014-02-18 04:50:00,6.08 2014-02-18 04:55:00,6.022 2014-02-18 05:00:00,6.077999999999999 2014-02-18 05:05:00,5.8320000000000025 2014-02-18 05:10:00,6.436 2014-02-18 05:15:00,6.064 2014-02-18 05:20:00,6.04 2014-02-18 05:25:00,7.0520000000000005 2014-02-18 05:30:00,5.606 2014-02-18 05:35:00,6.064 2014-02-18 05:40:00,6.2360000000000015 2014-02-18 05:45:00,6.496 2014-02-18 05:50:00,5.426 2014-02-18 05:55:00,6.438 2014-02-18 06:00:00,6.074 2014-02-18 06:05:00,6.04 2014-02-18 06:10:00,6.218 2014-02-18 06:15:00,5.862 2014-02-18 06:20:00,6.04 2014-02-18 06:25:00,6.218 2014-02-18 06:30:00,6.058 2014-02-18 06:35:00,5.837999999999999 2014-02-18 06:40:00,6.0820000000000025 2014-02-18 06:45:00,5.8320000000000025 2014-02-18 06:50:00,6.044 2014-02-18 06:55:00,6.254 2014-02-18 07:00:00,6.0120000000000005 2014-02-18 07:05:00,5.83 2014-02-18 07:10:00,6.4639999999999995 2014-02-18 07:15:00,5.816 2014-02-18 07:20:00,6.08 2014-02-18 07:25:00,5.827999999999999 2014-02-18 07:30:00,6.044 2014-02-18 07:35:00,5.8020000000000005 2014-02-18 07:40:00,6.4460000000000015 2014-02-18 07:45:00,6.068 2014-02-18 07:50:00,6.024 2014-02-18 07:55:00,6.9079999999999995 2014-02-18 08:00:00,6.652 2014-02-18 08:05:00,6.077999999999999 2014-02-18 08:10:00,6.2520000000000024 2014-02-18 08:15:00,6.4620000000000015 2014-02-18 08:20:00,6.037999999999999 2014-02-18 08:25:00,5.827999999999999 2014-02-18 08:30:00,6.276 2014-02-18 08:35:00,5.834 2014-02-18 08:40:00,6.007999999999999 2014-02-18 08:45:00,6.074 2014-02-18 08:50:00,6.022 2014-02-18 08:55:00,6.07 2014-02-18 09:00:00,6.044 2014-02-18 09:05:00,5.63 2014-02-18 09:10:00,6.2520000000000024 2014-02-18 09:15:00,5.82 2014-02-18 09:20:00,6.044 2014-02-18 09:25:00,6.46 2014-02-18 09:30:00,6.044 2014-02-18 09:35:00,5.622000000000001 2014-02-18 09:40:00,6.056 2014-02-18 09:45:00,5.816 2014-02-18 09:50:00,6.062 2014-02-18 09:55:00,6.046 2014-02-18 10:00:00,5.85 2014-02-18 10:05:00,6.4579999999999975 2014-02-18 10:10:00,6.6679999999999975 2014-02-18 10:15:00,5.81 2014-02-18 10:20:00,6.08 2014-02-18 10:25:00,5.834 2014-02-18 10:30:00,5.843999999999999 2014-02-18 10:35:00,5.834 2014-02-18 10:40:00,5.834 2014-02-18 10:45:00,5.626 2014-02-18 10:50:00,6.024 2014-02-18 10:55:00,6.032 2014-02-18 11:00:00,6.266 2014-02-18 11:05:00,5.836 2014-02-18 11:10:00,5.836 2014-02-18 11:15:00,5.827999999999999 2014-02-18 11:20:00,6.468 2014-02-18 11:25:00,5.62 2014-02-18 11:30:00,6.2379999999999995 2014-02-18 11:35:00,6.06 2014-02-18 11:40:00,6.232 2014-02-18 11:45:00,6.064 2014-02-18 11:50:00,6.2520000000000024 2014-02-18 11:55:00,6.25 2014-02-18 12:00:00,6.2079999999999975 2014-02-18 12:05:00,5.862 2014-02-18 12:10:00,6.682 2014-02-18 12:15:00,6.244 2014-02-18 12:20:00,6.0120000000000005 2014-02-18 12:25:00,6.25 2014-02-18 12:30:00,6.024 2014-02-18 12:35:00,5.81 2014-02-18 12:40:00,6.297999999999999 2014-02-18 12:45:00,5.836 2014-02-18 12:50:00,5.836 2014-02-18 12:55:00,6.246 2014-02-18 13:00:00,6.642 2014-02-18 13:05:00,6.037999999999999 2014-02-18 13:10:00,6.266 2014-02-18 13:15:00,5.816 2014-02-18 13:20:00,6.053999999999999 2014-02-18 13:25:00,5.824 2014-02-18 13:30:00,6.058 2014-02-18 13:35:00,5.63 2014-02-18 13:40:00,6.02 2014-02-18 13:45:00,6.044 2014-02-18 13:50:00,6.0420000000000025 2014-02-18 13:55:00,5.834 2014-02-18 14:00:00,6.46 2014-02-18 14:05:00,6.026 2014-02-18 14:10:00,6.432 2014-02-18 14:15:00,5.856 2014-02-18 14:20:00,6.2520000000000024 2014-02-18 14:25:00,6.0420000000000025 2014-02-18 14:30:00,6.228 2014-02-18 14:35:00,6.05 2014-02-18 14:40:00,6.297999999999999 2014-02-18 14:45:00,6.0360000000000005 2014-02-18 14:50:00,6.263999999999999 2014-02-18 14:55:00,6.4579999999999975 2014-02-18 15:00:00,5.59 2014-02-18 15:05:00,5.86 2014-02-18 15:10:00,6.228 2014-02-18 15:15:00,5.834 2014-02-18 15:20:00,6.856 2014-02-18 15:25:00,6.064 2014-02-18 15:30:00,6.024 2014-02-18 15:35:00,5.848 2014-02-18 15:40:00,6.037999999999999 2014-02-18 15:45:00,6.07 2014-02-18 15:50:00,5.8420000000000005 2014-02-18 15:55:00,6.0420000000000025 2014-02-18 16:00:00,6.0520000000000005 2014-02-18 16:05:00,5.827999999999999 2014-02-18 16:10:00,6.044 2014-02-18 16:15:00,5.834 2014-02-18 16:20:00,6.876 2014-02-18 16:25:00,5.62 2014-02-18 16:30:00,6.4639999999999995 2014-02-18 16:35:00,6.016 2014-02-18 16:40:00,6.3020000000000005 2014-02-18 16:45:00,6.4579999999999975 2014-02-18 16:50:00,5.626 2014-02-18 16:55:00,6.0360000000000005 2014-02-18 17:00:00,6.044 2014-02-18 17:05:00,6.25 2014-02-18 17:10:00,6.0420000000000025 2014-02-18 17:15:00,6.244 2014-02-18 17:20:00,6.676 2014-02-18 17:25:00,6.046 2014-02-18 17:30:00,5.84 2014-02-18 17:35:00,6.0360000000000005 2014-02-18 17:40:00,6.46 2014-02-18 17:45:00,6.04 2014-02-18 17:50:00,6.2520000000000024 2014-02-18 17:55:00,6.222 2014-02-18 18:00:00,6.29 2014-02-18 18:05:00,6.254 2014-02-18 18:10:00,7.084 2014-02-18 18:15:00,6.0420000000000025 2014-02-18 18:20:00,6.2479999999999976 2014-02-18 18:25:00,6.037999999999999 2014-02-18 18:30:00,6.26 2014-02-18 18:35:00,6.046 2014-02-18 18:40:00,6.228 2014-02-18 18:45:00,5.856 2014-02-18 18:50:00,6.0520000000000005 2014-02-18 18:55:00,5.834 2014-02-18 19:00:00,6.46 2014-02-18 19:05:00,6.016 2014-02-18 19:10:00,7.54 2014-02-18 19:15:00,5.816 2014-02-18 19:20:00,6.09 2014-02-18 19:25:00,5.834 2014-02-18 19:30:00,6.0 2014-02-18 19:35:00,5.837999999999999 2014-02-18 19:40:00,6.058 2014-02-18 19:45:00,5.822 2014-02-18 19:50:00,6.022 2014-02-18 19:55:00,6.064 2014-02-18 20:00:00,6.022 2014-02-18 20:05:00,5.856 2014-02-18 20:10:00,6.436 2014-02-18 20:15:00,5.862 2014-02-18 20:20:00,6.0520000000000005 2014-02-18 20:25:00,6.876 2014-02-18 20:30:00,6.414 2014-02-18 20:35:00,6.07 2014-02-18 20:40:00,6.016 2014-02-18 20:45:00,5.837999999999999 2014-02-18 20:50:00,6.07 2014-02-18 20:55:00,5.808 2014-02-18 21:00:00,6.086 2014-02-18 21:05:00,5.816 2014-02-18 21:10:00,6.276 2014-02-18 21:15:00,6.044 2014-02-18 21:20:00,6.053999999999999 2014-02-18 21:25:00,7.266 2014-02-18 21:30:00,6.2920000000000025 2014-02-18 21:35:00,6.03 2014-02-18 21:40:00,5.814 2014-02-18 21:45:00,5.862 2014-02-18 21:50:00,5.827999999999999 2014-02-18 21:55:00,6.037999999999999 2014-02-18 22:00:00,6.04 2014-02-18 22:05:00,5.834 2014-02-18 22:10:00,6.876 2014-02-18 22:15:00,6.642 2014-02-18 22:20:00,6.053999999999999 2014-02-18 22:25:00,6.05 2014-02-18 22:30:00,6.044 2014-02-18 22:35:00,5.834 2014-02-18 22:40:00,6.228 2014-02-18 22:45:00,5.837999999999999 2014-02-18 22:50:00,6.01 2014-02-18 22:55:00,6.69 2014-02-18 23:00:00,6.0420000000000025 2014-02-18 23:05:00,6.877999999999999 2014-02-18 23:10:00,6.6679999999999975 2014-02-18 23:15:00,5.837999999999999 2014-02-18 23:20:00,6.22 2014-02-18 23:25:00,6.4579999999999975 2014-02-18 23:30:00,6.026 2014-02-18 23:35:00,5.8660000000000005 2014-02-18 23:40:00,6.256 2014-02-18 23:45:00,5.837999999999999 2014-02-18 23:50:00,6.0520000000000005 2014-02-18 23:55:00,5.978 2014-02-19 00:00:00,6.1560000000000015 2014-02-19 00:05:00,5.834 2014-02-19 00:10:00,6.228 2014-02-19 00:15:00,7.114 2014-02-19 00:20:00,6.644 2014-02-19 00:25:00,6.064 2014-02-19 00:30:00,6.2520000000000024 2014-02-19 00:35:00,6.0420000000000025 2014-02-19 00:40:00,6.2520000000000024 2014-02-19 00:45:00,6.024 2014-02-19 00:50:00,6.29 2014-02-19 00:55:00,6.022 2014-02-19 01:00:00,6.888 2014-02-19 01:05:00,5.232 2014-02-19 01:10:00,6.6679999999999975 2014-02-19 01:15:00,5.834 2014-02-19 01:20:00,6.68 2014-02-19 01:25:00,7.272 2014-02-19 01:30:00,6.077999999999999 2014-02-19 01:35:00,5.816 2014-02-19 01:40:00,6.3 2014-02-19 01:45:00,5.82 2014-02-19 01:50:00,5.872000000000001 2014-02-19 01:55:00,6.224 2014-02-19 02:00:00,6.068 2014-02-19 02:05:00,5.862 2014-02-19 02:10:00,6.206 2014-02-19 02:15:00,6.902 2014-02-19 02:20:00,6.646 2014-02-19 02:25:00,5.816 2014-02-19 02:30:00,6.062 2014-02-19 02:35:00,5.837999999999999 2014-02-19 02:40:00,6.053999999999999 2014-02-19 02:45:00,5.84 2014-02-19 02:50:00,6.056 2014-02-19 02:55:00,6.25 2014-02-19 03:00:00,6.2520000000000024 2014-02-19 03:05:00,6.0420000000000025 2014-02-19 03:10:00,6.228 2014-02-19 03:15:00,6.046 2014-02-19 03:20:00,6.02 2014-02-19 03:25:00,6.068 2014-02-19 03:30:00,6.6579999999999995 2014-02-19 03:35:00,7.296 2014-02-19 03:40:00,6.228 2014-02-19 03:45:00,5.856 2014-02-19 03:50:00,6.2520000000000024 2014-02-19 03:55:00,5.834 2014-02-19 04:00:00,6.41 2014-02-19 04:05:00,5.848 2014-02-19 04:10:00,6.228 2014-02-19 04:15:00,5.8660000000000005 2014-02-19 04:20:00,6.044 2014-02-19 04:25:00,6.034 2014-02-19 04:30:00,6.022 2014-02-19 04:35:00,5.862 2014-02-19 04:40:00,6.254 2014-02-19 04:45:00,5.8420000000000005 2014-02-19 04:50:00,5.816 2014-02-19 04:55:00,6.07 2014-02-19 05:00:00,6.03 2014-02-19 05:05:00,6.48 2014-02-19 05:10:00,5.402 2014-02-19 05:15:00,5.856 2014-02-19 05:20:00,6.044 2014-02-19 05:25:00,6.2520000000000024 2014-02-19 05:30:00,6.2520000000000024 2014-02-19 05:35:00,5.83 2014-02-19 05:40:00,6.232 2014-02-19 05:45:00,6.0420000000000025 2014-02-19 05:50:00,6.024 2014-02-19 05:55:00,6.25 2014-02-19 06:00:00,6.04 2014-02-19 06:05:00,6.25 2014-02-19 06:10:00,6.0360000000000005 2014-02-19 06:15:00,6.24 2014-02-19 06:20:00,6.6679999999999975 2014-02-19 06:25:00,5.624 2014-02-19 06:30:00,6.044 2014-02-19 06:35:00,5.836 2014-02-19 06:40:00,6.0420000000000025 2014-02-19 06:45:00,5.834 2014-02-19 06:50:00,6.0420000000000025 2014-02-19 06:55:00,6.0420000000000025 2014-02-19 07:00:00,6.664 2014-02-19 07:05:00,5.837999999999999 2014-02-19 07:10:00,6.6339999999999995 2014-02-19 07:15:00,5.222 2014-02-19 07:20:00,6.05 2014-02-19 07:25:00,5.827999999999999 2014-02-19 07:30:00,6.047999999999999 2014-02-19 07:35:00,5.83 2014-02-19 07:40:00,5.836 2014-02-19 07:45:00,6.018 2014-02-19 07:50:00,6.077999999999999 2014-02-19 07:55:00,7.0820000000000025 2014-02-19 08:00:00,7.2520000000000024 2014-02-19 08:05:00,5.42 2014-02-19 08:10:00,6.266 2014-02-19 08:15:00,5.816 2014-02-19 08:20:00,6.257999999999999 2014-02-19 08:25:00,5.8420000000000005 2014-02-19 08:30:00,6.266 2014-02-19 08:35:00,6.037999999999999 2014-02-19 08:40:00,6.244 2014-02-19 08:45:00,5.834 2014-02-19 08:50:00,6.044 2014-02-19 08:55:00,6.256 2014-02-19 09:00:00,6.044 2014-02-19 09:05:00,6.4579999999999975 2014-02-19 09:10:00,6.0360000000000005 2014-02-19 09:15:00,6.0420000000000025 2014-02-19 09:20:00,6.25 2014-02-19 09:25:00,5.834 2014-02-19 09:30:00,6.047999999999999 2014-02-19 09:35:00,5.62 2014-02-19 09:40:00,6.256 2014-02-19 09:45:00,5.626 2014-02-19 09:50:00,6.2360000000000015 2014-02-19 09:55:00,6.4639999999999995 2014-02-19 10:00:00,5.6339999999999995 2014-02-19 10:05:00,6.49 2014-02-19 10:10:00,6.026 2014-02-19 10:15:00,5.64 2014-02-19 10:20:00,6.077999999999999 2014-02-19 10:25:00,5.83 2014-02-19 10:30:00,6.254 2014-02-19 10:35:00,6.032 2014-02-19 10:40:00,6.228 2014-02-19 10:45:00,6.05 2014-02-19 10:50:00,6.037999999999999 2014-02-19 10:55:00,6.2860000000000005 2014-02-19 11:00:00,6.044 2014-02-19 11:05:00,6.25 2014-02-19 11:10:00,6.0520000000000005 2014-02-19 11:15:00,5.816 2014-02-19 11:20:00,6.058 2014-02-19 11:25:00,6.0420000000000025 2014-02-19 11:30:00,7.254 2014-02-19 11:35:00,5.834 2014-02-19 11:40:00,6.2520000000000024 2014-02-19 11:45:00,6.032 2014-02-19 11:50:00,5.834 2014-02-19 11:55:00,6.244 2014-02-19 12:00:00,6.648 2014-02-19 12:05:00,6.07 2014-02-19 12:10:00,6.062 2014-02-19 12:15:00,5.834 2014-02-19 12:20:00,6.2520000000000024 2014-02-19 12:25:00,5.82 2014-02-19 12:30:00,6.4479999999999995 2014-02-19 12:35:00,5.44 2014-02-19 12:40:00,6.016 2014-02-19 12:45:00,5.856 2014-02-19 12:50:00,6.024 2014-02-19 12:55:00,6.492000000000001 2014-02-19 13:00:00,5.85 2014-02-19 13:05:00,5.834 2014-02-19 13:10:00,6.44 2014-02-19 13:15:00,5.836 2014-02-19 13:20:00,5.876 2014-02-19 13:25:00,5.836 2014-02-19 13:30:00,6.02 2014-02-19 13:35:00,6.49 2014-02-19 13:40:00,5.992000000000001 2014-02-19 13:45:00,6.282 2014-02-19 13:50:00,6.228 2014-02-19 13:55:00,6.25 2014-02-19 14:00:00,6.066 2014-02-19 14:05:00,6.022 2014-02-19 14:10:00,6.888 2014-02-19 14:15:00,5.827999999999999 2014-02-19 14:20:00,6.26 2014-02-19 14:25:00,6.0420000000000025 2014-02-19 14:30:00,6.046 2014-02-19 14:35:00,5.827999999999999 2014-02-19 14:40:00,6.226 2014-02-19 14:45:00,5.837999999999999 2014-02-19 14:50:00,6.066 2014-02-19 14:55:00,6.0420000000000025 2014-02-19 15:00:00,6.4620000000000015 2014-02-19 15:05:00,5.626 2014-02-19 15:10:00,6.46 2014-02-19 15:15:00,6.224 2014-02-19 15:20:00,5.4460000000000015 2014-02-19 15:25:00,6.867999999999999 2014-02-19 15:30:00,6.04 2014-02-19 15:35:00,5.8420000000000005 2014-02-19 15:40:00,6.016 2014-02-19 15:45:00,5.86 2014-02-19 15:50:00,6.02 2014-02-19 15:55:00,6.072 2014-02-19 16:00:00,6.256 2014-02-19 16:05:00,5.82 2014-02-19 16:10:00,6.91 2014-02-19 16:15:00,5.834 2014-02-19 16:20:00,6.256 2014-02-19 16:25:00,6.032 2014-02-19 16:30:00,6.02 2014-02-19 16:35:00,5.8660000000000005 2014-02-19 16:40:00,6.0520000000000005 2014-02-19 16:45:00,5.626 2014-02-19 16:50:00,6.232 2014-02-19 16:55:00,5.827999999999999 2014-02-19 17:00:00,5.996 2014-02-19 17:05:00,6.074 2014-02-19 17:10:00,7.098 2014-02-19 17:15:00,5.834 2014-02-19 17:20:00,6.2479999999999976 2014-02-19 17:25:00,5.81 2014-02-19 17:30:00,5.85 2014-02-19 17:35:00,5.836 2014-02-19 17:40:00,6.032 2014-02-19 17:45:00,5.598 2014-02-19 17:50:00,6.474 2014-02-19 17:55:00,6.694 2014-02-19 18:00:00,5.602 2014-02-19 18:05:00,5.862 2014-02-19 18:10:00,6.2520000000000024 2014-02-19 18:15:00,6.0420000000000025 2014-02-19 18:20:00,6.8839999999999995 2014-02-19 18:25:00,6.627999999999999 2014-02-19 18:30:00,5.428 2014-02-19 18:35:00,6.046 2014-02-19 18:40:00,5.8260000000000005 2014-02-19 18:45:00,6.04 2014-02-19 18:50:00,6.456 2014-02-19 18:55:00,6.228 2014-02-19 19:00:00,6.058 2014-02-19 19:05:00,6.0420000000000025 2014-02-19 19:10:00,6.224 2014-02-19 19:15:00,6.077999999999999 2014-02-19 19:20:00,7.272 2014-02-19 19:25:00,6.07 2014-02-19 19:30:00,6.05 2014-02-19 19:35:00,6.0420000000000025 2014-02-19 19:40:00,6.2520000000000024 2014-02-19 19:45:00,5.8420000000000005 2014-02-19 19:50:00,6.018 2014-02-19 19:55:00,6.07 2014-02-19 20:00:00,6.0420000000000025 2014-02-19 20:05:00,6.452000000000001 2014-02-19 20:10:00,6.867999999999999 2014-02-19 20:15:00,5.63 2014-02-19 20:20:00,6.474 2014-02-19 20:25:00,5.82 2014-02-19 20:30:00,6.062 2014-02-19 20:35:00,5.843999999999999 2014-02-19 20:40:00,6.3020000000000005 2014-02-19 20:45:00,5.834 2014-02-19 20:50:00,5.843999999999999 2014-02-19 20:55:00,6.0420000000000025 2014-02-19 21:00:00,6.032 2014-02-19 21:05:00,5.816 2014-02-19 21:10:00,6.7 2014-02-19 21:15:00,6.644 2014-02-19 21:20:00,6.2379999999999995 2014-02-19 21:25:00,6.06 2014-02-19 21:30:00,6.2520000000000024 2014-02-19 21:35:00,6.034 2014-02-19 21:40:00,6.2479999999999976 2014-02-19 21:45:00,6.24 2014-02-19 21:50:00,6.228 2014-02-19 21:55:00,6.072 2014-02-19 22:00:00,6.2520000000000024 2014-02-19 22:05:00,6.0420000000000025 2014-02-19 22:10:00,6.256 2014-02-19 22:15:00,5.827999999999999 2014-02-19 22:20:00,7.5020000000000024 2014-02-19 22:25:00,6.0420000000000025 2014-02-19 22:30:00,5.816 2014-02-19 22:35:00,6.24 2014-02-19 22:40:00,6.024 2014-02-19 22:45:00,6.282 2014-02-19 22:50:00,5.848 2014-02-19 22:55:00,6.0360000000000005 2014-02-19 23:00:00,6.02 2014-02-19 23:05:00,7.086 2014-02-19 23:10:00,6.428 2014-02-19 23:15:00,5.856 2014-02-19 23:20:00,5.836 2014-02-19 23:25:00,6.222 2014-02-19 23:30:00,6.074 2014-02-19 23:35:00,5.834 2014-02-19 23:40:00,5.846 2014-02-19 23:45:00,6.046 2014-02-19 23:50:00,6.032 2014-02-19 23:55:00,6.416 2014-02-20 00:00:00,6.96 2014-02-20 00:05:00,6.627999999999999 2014-02-20 00:10:00,6.2860000000000005 2014-02-20 00:15:00,6.0420000000000025 2014-02-20 00:20:00,6.047999999999999 2014-02-20 00:25:00,6.0420000000000025 2014-02-20 00:30:00,6.2360000000000015 2014-02-20 00:35:00,7.3020000000000005 2014-02-20 00:40:00,6.5020000000000024 2014-02-20 00:45:00,5.82 2014-02-20 00:50:00,6.058 2014-02-20 00:55:00,6.234 2014-02-20 01:00:00,6.032 2014-02-20 01:05:00,5.8320000000000025 2014-02-20 01:10:00,6.224 2014-02-20 01:15:00,7.492000000000001 2014-02-20 01:20:00,6.46 2014-02-20 01:25:00,5.834 2014-02-20 01:30:00,6.0420000000000025 2014-02-20 01:35:00,5.604 2014-02-20 01:40:00,6.05 2014-02-20 01:45:00,5.8320000000000025 2014-02-20 01:50:00,6.056 2014-02-20 01:55:00,5.81 2014-02-20 02:00:00,6.074 2014-02-20 02:05:00,6.25 2014-02-20 02:10:00,7.274 2014-02-20 02:15:00,6.046 2014-02-20 02:20:00,6.04 2014-02-20 02:25:00,6.0420000000000025 2014-02-20 02:30:00,6.46 2014-02-20 02:35:00,5.827999999999999 2014-02-20 02:40:00,6.016 2014-02-20 02:45:00,6.244 2014-02-20 02:50:00,6.03 2014-02-20 02:55:00,6.254 2014-02-20 03:00:00,6.246 2014-02-20 03:05:00,7.3279999999999985 2014-02-20 03:10:00,6.846 2014-02-20 03:15:00,5.834 2014-02-20 03:20:00,5.8320000000000025 2014-02-20 03:25:00,6.018 2014-02-20 03:30:00,6.086 2014-02-20 03:35:00,5.827999999999999 2014-02-20 03:40:00,6.257999999999999 2014-02-20 03:45:00,5.837999999999999 2014-02-20 03:50:00,6.0 2014-02-20 03:55:00,6.066 2014-02-20 04:00:00,6.2479999999999976 2014-02-20 04:05:00,5.814 2014-02-20 04:10:00,6.058 2014-02-20 04:15:00,5.834 2014-02-20 04:20:00,6.0120000000000005 2014-02-20 04:25:00,5.864 2014-02-20 04:30:00,5.843999999999999 2014-02-20 04:35:00,5.81 2014-02-20 04:40:00,5.854 2014-02-20 04:45:00,6.0420000000000025 2014-02-20 04:50:00,6.04 2014-02-20 04:55:00,6.254 2014-02-20 05:00:00,6.0420000000000025 2014-02-20 05:05:00,6.0520000000000005 2014-02-20 05:10:00,6.044 2014-02-20 05:15:00,6.0420000000000025 2014-02-20 05:20:00,6.204 2014-02-20 05:25:00,5.862 2014-02-20 05:30:00,6.044 2014-02-20 05:35:00,5.834 2014-02-20 05:40:00,6.0360000000000005 2014-02-20 05:45:00,5.626 2014-02-20 05:50:00,6.024 2014-02-20 05:55:00,6.022 2014-02-20 06:00:00,6.08 2014-02-20 06:05:00,5.837999999999999 2014-02-20 06:10:00,6.022 2014-02-20 06:15:00,5.856 2014-02-20 06:20:00,6.0520000000000005 2014-02-20 06:25:00,5.83 2014-02-20 06:30:00,6.04 2014-02-20 06:35:00,5.81 2014-02-20 06:40:00,6.0520000000000005 2014-02-20 06:45:00,5.862 2014-02-20 06:50:00,6.024 2014-02-20 06:55:00,6.022 2014-02-20 07:00:00,6.064 2014-02-20 07:05:00,6.07 2014-02-20 07:10:00,6.2520000000000024 2014-02-20 07:15:00,6.016 2014-02-20 07:20:00,6.27 2014-02-20 07:25:00,6.2860000000000005 2014-02-20 07:30:00,6.016 2014-02-20 07:35:00,5.848 2014-02-20 07:40:00,6.263999999999999 2014-02-20 07:45:00,5.8320000000000025 2014-02-20 07:50:00,6.032 2014-02-20 07:55:00,7.077999999999999 2014-02-20 08:00:00,6.2479999999999976 2014-02-20 08:05:00,6.024 2014-02-20 08:10:00,6.284 2014-02-20 08:15:00,5.83 2014-02-20 08:20:00,6.6679999999999975 2014-02-20 08:25:00,6.04 2014-02-20 08:30:00,6.044 2014-02-20 08:35:00,6.0420000000000025 2014-02-20 08:40:00,6.232 2014-02-20 08:45:00,6.0420000000000025 2014-02-20 08:50:00,6.044 2014-02-20 08:55:00,6.254 2014-02-20 09:00:00,6.224 2014-02-20 09:05:00,6.064 2014-02-20 09:10:00,6.26 2014-02-20 09:15:00,6.018 2014-02-20 09:20:00,6.474 2014-02-20 09:25:00,6.246 2014-02-20 09:30:00,6.024 2014-02-20 09:35:00,5.837999999999999 2014-02-20 09:40:00,6.0820000000000025 2014-02-20 09:45:00,6.016 2014-02-20 09:50:00,6.27 2014-02-20 09:55:00,6.068 2014-02-20 10:00:00,6.642 2014-02-20 10:05:00,5.856 2014-02-20 10:10:00,6.263999999999999 2014-02-20 10:15:00,5.814 2014-02-20 10:20:00,6.0820000000000025 2014-02-20 10:25:00,5.8260000000000005 2014-02-20 10:30:00,6.232 2014-02-20 10:35:00,5.836 2014-02-20 10:40:00,6.096 2014-02-20 10:45:00,5.814 2014-02-20 10:50:00,6.05 2014-02-20 10:55:00,6.0420000000000025 2014-02-20 11:00:00,5.992000000000001 2014-02-20 11:05:00,6.478 2014-02-20 11:10:00,6.266 2014-02-20 11:15:00,5.834 2014-02-20 11:20:00,6.23 2014-02-20 11:25:00,6.05 2014-02-20 11:30:00,6.29 2014-02-20 11:35:00,5.834 2014-02-20 11:40:00,6.4639999999999995 2014-02-20 11:45:00,6.02 2014-02-20 11:50:00,6.034 2014-02-20 11:55:00,6.064 2014-02-20 12:00:00,6.2479999999999976 2014-02-20 12:05:00,5.837999999999999 2014-02-20 12:10:00,6.846 2014-02-20 12:15:00,5.856 2014-02-20 12:20:00,6.016 2014-02-20 12:25:00,6.04 2014-02-20 12:30:00,6.046 2014-02-20 12:35:00,6.044 2014-02-20 12:40:00,6.047999999999999 2014-02-20 12:45:00,6.0420000000000025 2014-02-20 12:50:00,6.6720000000000015 2014-02-20 12:55:00,6.0360000000000005 2014-02-20 13:00:00,5.6339999999999995 2014-02-20 13:05:00,6.046 2014-02-20 13:10:00,6.2520000000000024 2014-02-20 13:15:00,5.834 2014-02-20 13:20:00,6.044 2014-02-20 13:25:00,5.834 2014-02-20 13:30:00,6.852 2014-02-20 13:35:00,5.8260000000000005 2014-02-20 13:40:00,6.44 2014-02-20 13:45:00,5.636 2014-02-20 13:50:00,6.058 2014-02-20 13:55:00,6.246 2014-02-20 14:00:00,7.27 2014-02-20 14:05:00,5.83 2014-02-20 14:10:00,6.228 2014-02-20 14:15:00,6.0360000000000005 2014-02-20 14:20:00,6.256 2014-02-20 14:25:00,6.04 2014-02-20 14:30:00,6.452000000000001 2014-02-20 14:35:00,6.04 2014-02-20 14:40:00,6.04 2014-02-20 14:45:00,6.04 2014-02-20 14:50:00,6.0420000000000025 2014-02-20 14:55:00,6.03 2014-02-20 15:00:00,6.2479999999999976 2014-02-20 15:05:00,6.67 2014-02-20 15:10:00,6.016 2014-02-20 15:15:00,5.862 2014-02-20 15:20:00,6.044 2014-02-20 15:25:00,5.814 2014-02-20 15:30:00,6.0820000000000025 2014-02-20 15:35:00,6.05 2014-02-20 15:40:00,6.02 2014-02-20 15:45:00,5.848 2014-02-20 15:50:00,5.827999999999999 2014-02-20 15:55:00,6.0420000000000025 2014-02-20 16:00:00,6.86 2014-02-20 16:05:00,5.626 2014-02-20 16:10:00,6.263999999999999 2014-02-20 16:15:00,5.608 2014-02-20 16:20:00,6.242000000000001 2014-02-20 16:25:00,6.068 2014-02-20 16:30:00,6.25 2014-02-20 16:35:00,6.016 2014-02-20 16:40:00,6.266 2014-02-20 16:45:00,6.02 2014-02-20 16:50:00,6.058 2014-02-20 16:55:00,6.2479999999999976 2014-02-20 17:00:00,6.044 2014-02-20 17:05:00,6.874 2014-02-20 17:10:00,6.232 2014-02-20 17:15:00,5.827999999999999 2014-02-20 17:20:00,6.256 2014-02-20 17:25:00,6.0360000000000005 2014-02-20 17:30:00,6.226 2014-02-20 17:35:00,5.843999999999999 2014-02-20 17:40:00,6.29 2014-02-20 17:45:00,6.03 2014-02-20 17:50:00,6.266 2014-02-20 17:55:00,6.25 2014-02-20 18:00:00,6.228 2014-02-20 18:05:00,6.064 2014-02-20 18:10:00,6.642 2014-02-20 18:15:00,7.117999999999999 2014-02-20 18:20:00,6.2520000000000024 2014-02-20 18:25:00,6.046 2014-02-20 18:30:00,6.232 2014-02-20 18:35:00,6.074 2014-02-20 18:40:00,6.232 2014-02-20 18:45:00,6.077999999999999 2014-02-20 18:50:00,6.228 2014-02-20 18:55:00,6.046 2014-02-20 19:00:00,6.614 2014-02-20 19:05:00,6.694 2014-02-20 19:10:00,6.266 2014-02-20 19:15:00,5.837999999999999 2014-02-20 19:20:00,6.25 2014-02-20 19:25:00,5.816 2014-02-20 19:30:00,6.303999999999999 2014-02-20 19:35:00,5.834 2014-02-20 19:40:00,6.024 2014-02-20 19:45:00,6.06 2014-02-20 19:50:00,5.843999999999999 2014-02-20 19:55:00,5.827999999999999 2014-02-20 20:00:00,6.436 2014-02-20 20:05:00,5.837999999999999 2014-02-20 20:10:00,6.077999999999999 2014-02-20 20:15:00,5.834 2014-02-20 20:20:00,7.066 2014-02-20 20:25:00,5.856 2014-02-20 20:30:00,6.228 2014-02-20 20:35:00,5.636 2014-02-20 20:40:00,6.058 2014-02-20 20:45:00,5.834 2014-02-20 20:50:00,5.626 2014-02-20 20:55:00,6.034 2014-02-20 21:00:00,6.02 2014-02-20 21:05:00,6.046 2014-02-20 21:10:00,7.2920000000000025 2014-02-20 21:15:00,6.24 2014-02-20 21:20:00,6.257999999999999 2014-02-20 21:25:00,6.0360000000000005 2014-02-20 21:30:00,6.02 2014-02-20 21:35:00,6.0420000000000025 2014-02-20 21:40:00,6.22 2014-02-20 21:45:00,5.843999999999999 2014-02-20 21:50:00,6.256 2014-02-20 21:55:00,6.0420000000000025 2014-02-20 22:00:00,7.084 2014-02-20 22:05:00,6.257999999999999 2014-02-20 22:10:00,6.268 2014-02-20 22:15:00,6.026 2014-02-20 22:20:00,5.836 2014-02-20 22:25:00,6.0420000000000025 2014-02-20 22:30:00,6.024 2014-02-20 22:35:00,5.848 2014-02-20 22:40:00,6.024 2014-02-20 22:45:00,6.0420000000000025 2014-02-20 22:50:00,5.836 2014-02-20 22:55:00,6.0420000000000025 2014-02-20 23:00:00,6.2360000000000015 2014-02-20 23:05:00,5.856 2014-02-20 23:10:00,7.2920000000000025 2014-02-20 23:15:00,6.046 2014-02-20 23:20:00,6.024 2014-02-20 23:25:00,5.837999999999999 2014-02-20 23:30:00,6.034 2014-02-20 23:35:00,5.856 2014-02-20 23:40:00,6.028 2014-02-20 23:45:00,6.0420000000000025 2014-02-20 23:50:00,6.024 2014-02-20 23:55:00,6.19 2014-02-21 00:00:00,6.152 2014-02-21 00:05:00,5.816 2014-02-21 00:10:00,6.077999999999999 2014-02-21 00:15:00,7.0760000000000005 2014-02-21 00:20:00,6.44 2014-02-21 00:25:00,5.843999999999999 2014-02-21 00:30:00,6.064 2014-02-21 00:35:00,5.848 2014-02-21 00:40:00,6.287999999999999 2014-02-21 00:45:00,5.626 2014-02-21 00:50:00,6.0520000000000005 2014-02-21 00:55:00,5.8320000000000025 2014-02-21 01:00:00,6.874 2014-02-21 01:05:00,6.6720000000000015 2014-02-21 01:10:00,6.4639999999999995 2014-02-21 01:15:00,5.834 2014-02-21 01:20:00,5.796 2014-02-21 01:25:00,6.056 2014-02-21 01:30:00,5.85 2014-02-21 01:35:00,5.834 2014-02-21 01:40:00,7.098 2014-02-21 01:45:00,6.86 2014-02-21 01:50:00,6.2520000000000024 2014-02-21 01:55:00,5.8420000000000005 2014-02-21 02:00:00,6.024 2014-02-21 02:05:00,5.856 2014-02-21 02:10:00,6.232 2014-02-21 02:15:00,6.037999999999999 2014-02-21 02:20:00,6.024 2014-02-21 02:25:00,6.23 2014-02-21 02:30:00,6.29 2014-02-21 02:35:00,7.2620000000000005 2014-02-21 02:40:00,6.246 2014-02-21 02:45:00,5.862 2014-02-21 02:50:00,6.0360000000000005 2014-02-21 02:55:00,6.0420000000000025 2014-02-21 03:00:00,6.05 2014-02-21 03:05:00,5.83 2014-02-21 03:10:00,7.5020000000000024 2014-02-21 03:15:00,6.024 2014-02-21 03:20:00,5.87 2014-02-21 03:25:00,5.83 2014-02-21 03:30:00,6.0420000000000025 2014-02-21 03:35:00,5.822 2014-02-21 03:40:00,5.7920000000000025 2014-02-21 03:45:00,5.6579999999999995 2014-02-21 03:50:00,6.02 2014-02-21 03:55:00,5.824 2014-02-21 04:00:00,5.82 2014-02-21 04:05:00,5.83 2014-02-21 04:10:00,6.044 2014-02-21 04:15:00,5.608 2014-02-21 04:20:00,6.2860000000000005 2014-02-21 04:25:00,5.626 2014-02-21 04:30:00,5.816 2014-02-21 04:35:00,5.626 2014-02-21 04:40:00,6.228 2014-02-21 04:45:00,5.86 2014-02-21 04:50:00,6.0 2014-02-21 04:55:00,5.862 2014-02-21 05:00:00,6.037999999999999 2014-02-21 05:05:00,5.622000000000001 2014-02-21 05:10:00,6.0420000000000025 2014-02-21 05:15:00,5.626 2014-02-21 05:20:00,5.834 2014-02-21 05:25:00,6.046 2014-02-21 05:30:00,5.822 2014-02-21 05:35:00,5.8260000000000005 2014-02-21 05:40:00,6.0120000000000005 2014-02-21 05:45:00,5.654 2014-02-21 05:50:00,6.004 2014-02-21 05:55:00,5.862 2014-02-21 06:00:00,6.028 2014-02-21 06:05:00,5.834 2014-02-21 06:10:00,6.2520000000000024 2014-02-21 06:15:00,6.0420000000000025 2014-02-21 06:20:00,6.044 2014-02-21 06:25:00,6.037999999999999 2014-02-21 06:30:00,6.03 2014-02-21 06:35:00,5.856 2014-02-21 06:40:00,6.028 2014-02-21 06:45:00,5.843999999999999 2014-02-21 06:50:00,6.058 2014-02-21 06:55:00,5.834 2014-02-21 07:00:00,6.2520000000000024 2014-02-21 07:05:00,6.04 2014-02-21 07:10:00,6.044 2014-02-21 07:15:00,5.83 2014-02-21 07:20:00,6.044 2014-02-21 07:25:00,5.834 2014-02-21 07:30:00,6.044 2014-02-21 07:35:00,5.608 2014-02-21 07:40:00,6.077999999999999 2014-02-21 07:45:00,5.808 2014-02-21 07:50:00,5.6579999999999995 2014-02-21 07:55:00,6.874 2014-02-21 08:00:00,6.202000000000001 2014-02-21 08:05:00,5.86 2014-02-21 08:10:00,6.0420000000000025 2014-02-21 08:15:00,5.626 2014-02-21 08:20:00,5.6320000000000014 2014-02-21 08:25:00,6.46 2014-02-21 08:30:00,6.0420000000000025 2014-02-21 08:35:00,6.026 2014-02-21 08:40:00,6.2 2014-02-21 08:45:00,5.6579999999999995 2014-02-21 08:50:00,5.84 2014-02-21 08:55:00,6.044 2014-02-21 09:00:00,6.044 2014-02-21 09:05:00,5.622000000000001 2014-02-21 09:10:00,6.46 2014-02-21 09:15:00,5.624 2014-02-21 09:20:00,6.2479999999999976 2014-02-21 09:25:00,6.0420000000000025 2014-02-21 09:30:00,6.26 2014-02-21 09:35:00,6.032 2014-02-21 09:40:00,6.04 2014-02-21 09:45:00,5.822 2014-02-21 09:50:00,6.2520000000000024 2014-02-21 09:55:00,5.827999999999999 2014-02-21 10:00:00,6.222 2014-02-21 10:05:00,5.816 2014-02-21 10:10:00,6.494 2014-02-21 10:15:00,6.0420000000000025 2014-02-21 10:20:00,6.0360000000000005 2014-02-21 10:25:00,6.037999999999999 2014-02-21 10:30:00,6.0 2014-02-21 10:35:00,5.87 2014-02-21 10:40:00,6.2520000000000024 2014-02-21 10:45:00,5.837999999999999 2014-02-21 10:50:00,6.044 2014-02-21 10:55:00,5.837999999999999 2014-02-21 11:00:00,6.257999999999999 2014-02-21 11:05:00,6.4460000000000015 2014-02-21 11:10:00,6.0420000000000025 2014-02-21 11:15:00,5.834 2014-02-21 11:20:00,6.044 2014-02-21 11:25:00,5.834 2014-02-21 11:30:00,6.044 2014-02-21 11:35:00,5.822 2014-02-21 11:40:00,6.04 2014-02-21 11:45:00,5.834 2014-02-21 11:50:00,6.05 2014-02-21 11:55:00,6.03 2014-02-21 12:00:00,6.0520000000000005 2014-02-21 12:05:00,5.827999999999999 2014-02-21 12:10:00,6.25 2014-02-21 12:15:00,5.834 2014-02-21 12:20:00,6.2379999999999995 2014-02-21 12:25:00,6.07 2014-02-21 12:30:00,6.436 2014-02-21 12:35:00,6.2860000000000005 2014-02-21 12:40:00,6.256 2014-02-21 12:45:00,6.046 2014-02-21 12:50:00,6.24 2014-02-21 12:55:00,6.2520000000000024 2014-02-21 13:00:00,6.02 2014-02-21 13:05:00,5.8660000000000005 2014-02-21 13:10:00,6.02 2014-02-21 13:15:00,6.44 2014-02-21 13:20:00,6.077999999999999 2014-02-21 13:25:00,6.0420000000000025 2014-02-21 13:30:00,6.26 2014-02-21 13:35:00,6.46 2014-02-21 13:40:00,6.228 2014-02-21 13:45:00,5.862 2014-02-21 13:50:00,6.016 2014-02-21 13:55:00,6.04 2014-02-21 14:00:00,6.6679999999999975 2014-02-21 14:05:00,5.21 2014-02-21 14:10:00,5.84 2014-02-21 14:15:00,6.2520000000000024 2014-02-21 14:20:00,5.836 2014-02-21 14:25:00,5.814 2014-02-21 14:30:00,5.88 2014-02-21 14:35:00,6.666 2014-02-21 14:40:00,5.834 2014-02-21 14:45:00,5.606 2014-02-21 14:50:00,6.244 2014-02-21 14:55:00,5.622000000000001 2014-02-21 15:00:00,6.228 2014-02-21 15:05:00,6.46 2014-02-21 15:10:00,6.442 2014-02-21 15:15:00,5.626 2014-02-21 15:20:00,6.047999999999999 2014-02-21 15:25:00,6.0420000000000025 2014-02-21 15:30:00,6.0420000000000025 2014-02-21 15:35:00,5.822 2014-02-21 15:40:00,6.2520000000000024 2014-02-21 15:45:00,6.0420000000000025 2014-02-21 15:50:00,6.024 2014-02-21 15:55:00,6.04 2014-02-21 16:00:00,6.0520000000000005 2014-02-21 16:05:00,6.0420000000000025 2014-02-21 16:10:00,6.6679999999999975 2014-02-21 16:15:00,5.834 2014-02-21 16:20:00,5.846 2014-02-21 16:25:00,5.837999999999999 2014-02-21 16:30:00,6.044 2014-02-21 16:35:00,5.8320000000000025 2014-02-21 16:40:00,6.044 2014-02-21 16:45:00,5.608 2014-02-21 16:50:00,6.062 2014-02-21 16:55:00,5.862 2014-02-21 17:00:00,5.834 2014-02-21 17:05:00,5.834 2014-02-21 17:10:00,6.0 2014-02-21 17:15:00,5.652 2014-02-21 17:20:00,6.852 2014-02-21 17:25:00,6.05 2014-02-21 17:30:00,5.87 2014-02-21 17:35:00,5.814 2014-02-21 17:40:00,5.87 2014-02-21 17:45:00,5.803999999999999 2014-02-21 17:50:00,6.074 2014-02-21 17:55:00,5.8420000000000005 2014-02-21 18:00:00,6.05 2014-02-21 18:05:00,5.822 2014-02-21 18:10:00,6.02 2014-02-21 18:15:00,5.652 2014-02-21 18:20:00,6.032 2014-02-21 18:25:00,5.86 2014-02-21 18:30:00,7.087999999999999 2014-02-21 18:35:00,5.626 2014-02-21 18:40:00,6.044 2014-02-21 18:45:00,5.834 2014-02-21 18:50:00,6.228 2014-02-21 18:55:00,5.834 2014-02-21 19:00:00,6.0420000000000025 2014-02-21 19:05:00,6.45 2014-02-21 19:10:00,6.876 2014-02-21 19:15:00,6.0420000000000025 2014-02-21 19:20:00,6.46 2014-02-21 19:25:00,5.606 2014-02-21 19:30:00,6.074 2014-02-21 19:35:00,6.0420000000000025 2014-02-21 19:40:00,6.232 2014-02-21 19:45:00,6.028 2014-02-21 19:50:00,6.077999999999999 2014-02-21 19:55:00,6.037999999999999 2014-02-21 20:00:00,7.268 2014-02-21 20:05:00,5.8660000000000005 2014-02-21 20:10:00,6.2520000000000024 2014-02-21 20:15:00,5.834 2014-02-21 20:20:00,6.04 2014-02-21 20:25:00,6.0420000000000025 2014-02-21 20:30:00,7.087999999999999 2014-02-21 20:35:00,5.834 2014-02-21 20:40:00,6.044 2014-02-21 20:45:00,5.626 2014-02-21 20:50:00,6.044 2014-02-21 20:55:00,6.04 2014-02-21 21:00:00,5.836 2014-02-21 21:05:00,5.626 2014-02-21 21:10:00,6.858 2014-02-21 21:15:00,6.25 2014-02-21 21:20:00,5.836 2014-02-21 21:25:00,6.047999999999999 2014-02-21 21:30:00,5.6 2014-02-21 21:35:00,5.834 2014-02-21 21:40:00,5.836 2014-02-21 21:45:00,5.822 2014-02-21 21:50:00,5.806 2014-02-21 21:55:00,6.022 2014-02-21 22:00:00,5.874 2014-02-21 22:05:00,6.466 2014-02-21 22:10:00,6.854 2014-02-21 22:15:00,5.834 2014-02-21 22:20:00,6.228 2014-02-21 22:25:00,6.07 2014-02-21 22:30:00,6.044 2014-02-21 22:35:00,5.822 2014-02-21 22:40:00,6.226 2014-02-21 22:45:00,5.862 2014-02-21 22:50:00,6.004 2014-02-21 22:55:00,6.282 2014-02-21 23:00:00,5.822 2014-02-21 23:05:00,5.843999999999999 2014-02-21 23:10:00,6.287999999999999 2014-02-21 23:15:00,6.876 2014-02-21 23:20:00,6.25 2014-02-21 23:25:00,5.816 2014-02-21 23:30:00,5.864 2014-02-21 23:35:00,5.624 2014-02-21 23:40:00,6.044 2014-02-21 23:45:00,5.6160000000000005 2014-02-21 23:50:00,6.05 2014-02-21 23:55:00,5.77 2014-02-22 00:00:00,6.356 2014-02-22 00:05:00,6.876 2014-02-22 00:10:00,6.047999999999999 2014-02-22 00:15:00,5.816 2014-02-22 00:20:00,5.877999999999999 2014-02-22 00:25:00,5.622000000000001 2014-02-22 00:30:00,6.02 2014-02-22 00:35:00,5.626 2014-02-22 00:40:00,6.044 2014-02-22 00:45:00,5.808 2014-02-22 00:50:00,6.077999999999999 2014-02-22 00:55:00,6.026 2014-02-22 01:00:00,6.8820000000000014 2014-02-22 01:05:00,6.6679999999999975 2014-02-22 01:10:00,6.21 2014-02-22 01:15:00,6.476 2014-02-22 01:20:00,5.87 2014-02-22 01:25:00,6.02 2014-02-22 01:30:00,6.29 2014-02-22 01:35:00,5.624 2014-02-22 01:40:00,6.224 2014-02-22 01:45:00,5.834 2014-02-22 01:50:00,6.044 2014-02-22 01:55:00,5.837999999999999 2014-02-22 02:00:00,6.232 2014-02-22 02:05:00,5.604 2014-02-22 02:10:00,6.068 2014-02-22 02:15:00,6.278 2014-02-22 02:20:00,6.876 2014-02-22 02:25:00,5.8420000000000005 2014-02-22 02:30:00,5.816 2014-02-22 02:35:00,5.654 2014-02-22 02:40:00,6.0520000000000005 2014-02-22 02:45:00,5.82 2014-02-22 02:50:00,5.867999999999999 2014-02-22 02:55:00,6.0420000000000025 2014-02-22 03:00:00,6.682 2014-02-22 03:05:00,6.6579999999999995 2014-02-22 03:10:00,6.02 2014-02-22 03:15:00,5.86 2014-02-22 03:20:00,6.04 2014-02-22 03:25:00,6.0360000000000005 2014-02-22 03:30:00,6.256 2014-02-22 03:35:00,5.834 2014-02-22 03:40:00,6.256 2014-02-22 03:45:00,5.837999999999999 2014-02-22 03:50:00,6.2479999999999976 2014-02-22 03:55:00,6.04 2014-02-22 04:00:00,6.426 2014-02-22 04:05:00,5.827999999999999 2014-02-22 04:10:00,6.257999999999999 2014-02-22 04:15:00,6.018 2014-02-22 04:20:00,6.086 2014-02-22 04:25:00,6.04 2014-02-22 04:30:00,6.2520000000000024 2014-02-22 04:35:00,5.834 2014-02-22 04:40:00,6.047999999999999 2014-02-22 04:45:00,6.0360000000000005 2014-02-22 04:50:00,6.047999999999999 2014-02-22 04:55:00,6.0420000000000025 2014-02-22 05:00:00,5.84 2014-02-22 05:05:00,5.6160000000000005 2014-02-22 05:10:00,6.44 2014-02-22 05:15:00,5.862 2014-02-22 05:20:00,6.044 2014-02-22 05:25:00,5.814 2014-02-22 05:30:00,6.077999999999999 2014-02-22 05:35:00,5.614 2014-02-22 05:40:00,6.024 2014-02-22 05:45:00,6.07 2014-02-22 05:50:00,5.82 2014-02-22 05:55:00,5.8660000000000005 2014-02-22 06:00:00,5.836 2014-02-22 06:05:00,6.026 2014-02-22 06:10:00,6.077999999999999 2014-02-22 06:15:00,5.834 2014-02-22 06:20:00,6.044 2014-02-22 06:25:00,6.0360000000000005 2014-02-22 06:30:00,6.8839999999999995 2014-02-22 06:35:00,6.0420000000000025 2014-02-22 06:40:00,6.434 2014-02-22 06:45:00,6.074 2014-02-22 06:50:00,6.2520000000000024 2014-02-22 06:55:00,6.02 2014-02-22 07:00:00,6.29 2014-02-22 07:05:00,6.037999999999999 2014-02-22 07:10:00,6.228 2014-02-22 07:15:00,5.834 2014-02-22 07:20:00,6.2479999999999976 2014-02-22 07:25:00,6.232 2014-02-22 07:30:00,6.058 2014-02-22 07:35:00,5.862 2014-02-22 07:40:00,6.04 2014-02-22 07:45:00,5.827999999999999 2014-02-22 07:50:00,6.044 2014-02-22 07:55:00,6.854 2014-02-22 08:00:00,6.287999999999999 2014-02-22 08:05:00,6.032 2014-02-22 08:10:00,5.604 2014-02-22 08:15:00,6.0420000000000025 2014-02-22 08:20:00,5.83 2014-02-22 08:25:00,5.814 2014-02-22 08:30:00,6.08 2014-02-22 08:35:00,5.626 2014-02-22 08:40:00,6.0420000000000025 2014-02-22 08:45:00,5.624 2014-02-22 08:50:00,6.05 2014-02-22 08:55:00,5.837999999999999 2014-02-22 09:00:00,6.2520000000000024 2014-02-22 09:05:00,6.037999999999999 2014-02-22 09:10:00,6.46 2014-02-22 09:15:00,5.8320000000000025 2014-02-22 09:20:00,6.2520000000000024 2014-02-22 09:25:00,6.0420000000000025 2014-02-22 09:30:00,6.2379999999999995 2014-02-22 09:35:00,5.862 2014-02-22 09:40:00,6.047999999999999 2014-02-22 09:45:00,6.0420000000000025 2014-02-22 09:50:00,6.044 2014-02-22 09:55:00,5.83 2014-02-22 10:00:00,6.232 2014-02-22 10:05:00,5.862 2014-02-22 10:10:00,6.652 2014-02-22 10:15:00,5.626 2014-02-22 10:20:00,6.05 2014-02-22 10:25:00,5.834 2014-02-22 10:30:00,6.02 2014-02-22 10:35:00,5.626 2014-02-22 10:40:00,6.09 2014-02-22 10:45:00,5.614 2014-02-22 10:50:00,6.044 2014-02-22 10:55:00,6.0420000000000025 2014-02-22 11:00:00,5.836 2014-02-22 11:05:00,6.428 2014-02-22 11:10:00,6.077999999999999 2014-02-22 11:15:00,5.834 2014-02-22 11:20:00,5.836 2014-02-22 11:25:00,6.022 2014-02-22 11:30:00,6.29 2014-02-22 11:35:00,5.834 2014-02-22 11:40:00,6.4639999999999995 2014-02-22 11:45:00,5.837999999999999 2014-02-22 11:50:00,6.0420000000000025 2014-02-22 11:55:00,6.0420000000000025 2014-02-22 12:00:00,6.044 2014-02-22 12:05:00,6.226 2014-02-22 12:10:00,6.474 2014-02-22 12:15:00,5.83 2014-02-22 12:20:00,6.022 2014-02-22 12:25:00,5.816 2014-02-22 12:30:00,6.0820000000000025 2014-02-22 12:35:00,5.816 2014-02-22 12:40:00,6.2860000000000005 2014-02-22 12:45:00,5.827999999999999 2014-02-22 12:50:00,5.824 2014-02-22 12:55:00,5.862 2014-02-22 13:00:00,6.044 2014-02-22 13:05:00,6.254 2014-02-22 13:10:00,6.204 2014-02-22 13:15:00,5.654 2014-02-22 13:20:00,5.84 2014-02-22 13:25:00,6.018 2014-02-22 13:30:00,6.29 2014-02-22 13:35:00,5.834 2014-02-22 13:40:00,6.46 2014-02-22 13:45:00,5.834 2014-02-22 13:50:00,6.877999999999999 2014-02-22 13:55:00,6.037999999999999 2014-02-22 14:00:00,5.824 2014-02-22 14:05:00,5.83 2014-02-22 14:10:00,6.0520000000000005 2014-02-22 14:15:00,5.8320000000000025 2014-02-22 14:20:00,6.8839999999999995 2014-02-22 14:25:00,5.834 2014-02-22 14:30:00,6.044 2014-02-22 14:35:00,5.6 2014-02-22 14:40:00,6.284 2014-02-22 14:45:00,5.83 2014-02-22 14:50:00,5.836 2014-02-22 14:55:00,6.0420000000000025 2014-02-22 15:00:00,5.834 2014-02-22 15:05:00,5.822 2014-02-22 15:10:00,6.024 2014-02-22 15:15:00,6.694 2014-02-22 15:20:00,6.044 2014-02-22 15:25:00,5.827999999999999 2014-02-22 15:30:00,6.024 2014-02-22 15:35:00,5.4179999999999975 2014-02-22 15:40:00,6.2520000000000024 2014-02-22 15:45:00,6.03 2014-02-22 15:50:00,5.834 2014-02-22 15:55:00,5.834 2014-02-22 16:00:00,6.044 2014-02-22 16:05:00,6.034 2014-02-22 16:10:00,6.864 2014-02-22 16:15:00,6.0420000000000025 2014-02-22 16:20:00,6.044 2014-02-22 16:25:00,5.824 2014-02-22 16:30:00,5.834 2014-02-22 16:35:00,5.834 2014-02-22 16:40:00,6.436 2014-02-22 16:45:00,5.834 2014-02-22 16:50:00,6.016 2014-02-22 16:55:00,6.0420000000000025 2014-02-22 17:00:00,6.2479999999999976 2014-02-22 17:05:00,5.8320000000000025 2014-02-22 17:10:00,6.228 2014-02-22 17:15:00,5.834 2014-02-22 17:20:00,6.648 2014-02-22 17:25:00,6.02 2014-02-22 17:30:00,6.062 2014-02-22 17:35:00,5.8420000000000005 2014-02-22 17:40:00,6.0820000000000025 2014-02-22 17:45:00,6.026 2014-02-22 17:50:00,5.87 2014-02-22 17:55:00,6.25 2014-02-22 18:00:00,6.028 2014-02-22 18:05:00,5.626 2014-02-22 18:10:00,6.25 2014-02-22 18:15:00,5.83 2014-02-22 18:20:00,5.796 2014-02-22 18:25:00,6.494 2014-02-22 18:30:00,6.44 2014-02-22 18:35:00,5.654 2014-02-22 18:40:00,6.044 2014-02-22 18:45:00,5.834 2014-02-22 18:50:00,5.822 2014-02-22 18:55:00,5.862 2014-02-22 19:00:00,6.85 2014-02-22 19:05:00,6.024 2014-02-22 19:10:00,6.282 2014-02-22 19:15:00,6.0420000000000025 2014-02-22 19:20:00,6.222 2014-02-22 19:25:00,6.0420000000000025 2014-02-22 19:30:00,6.044 2014-02-22 19:35:00,6.0420000000000025 2014-02-22 19:40:00,6.044 2014-02-22 19:45:00,6.028 2014-02-22 19:50:00,6.0360000000000005 2014-02-22 19:55:00,6.037999999999999 2014-02-22 20:00:00,6.024 2014-02-22 20:05:00,5.862 2014-02-22 20:10:00,6.044 2014-02-22 20:15:00,5.834 2014-02-22 20:20:00,6.022 2014-02-22 20:25:00,5.806 2014-02-22 20:30:00,6.062 2014-02-22 20:35:00,6.0360000000000005 2014-02-22 20:40:00,6.894 2014-02-22 20:45:00,6.0420000000000025 2014-02-22 20:50:00,6.028 2014-02-22 20:55:00,5.8420000000000005 2014-02-22 21:00:00,6.087999999999999 2014-02-22 21:05:00,6.876 2014-02-22 21:10:00,6.654 2014-02-22 21:15:00,5.652 2014-02-22 21:20:00,5.834 2014-02-22 21:25:00,5.822 2014-02-22 21:30:00,5.816 2014-02-22 21:35:00,6.024 2014-02-22 21:40:00,6.296 2014-02-22 21:45:00,6.028 2014-02-22 21:50:00,6.074 2014-02-22 21:55:00,6.0360000000000005 2014-02-22 22:00:00,6.256 2014-02-22 22:05:00,5.827999999999999 2014-02-22 22:10:00,6.648 2014-02-22 22:15:00,6.6960000000000015 2014-02-22 22:20:00,6.232 2014-02-22 22:25:00,5.834 2014-02-22 22:30:00,6.024 2014-02-22 22:35:00,5.827999999999999 2014-02-22 22:40:00,6.25 2014-02-22 22:45:00,5.626 2014-02-22 22:50:00,6.03 2014-02-22 22:55:00,6.064 2014-02-22 23:00:00,5.816 2014-02-22 23:05:00,5.872000000000001 2014-02-22 23:10:00,6.016 2014-02-22 23:15:00,5.834 2014-02-22 23:20:00,6.47 2014-02-22 23:25:00,6.6679999999999975 2014-02-22 23:30:00,5.836 2014-02-22 23:35:00,5.834 2014-02-22 23:40:00,5.803999999999999 2014-02-22 23:45:00,5.843999999999999 2014-02-22 23:50:00,6.077999999999999 2014-02-22 23:55:00,5.774 2014-02-23 00:00:00,6.162000000000001 2014-02-23 00:05:00,5.83 2014-02-23 00:10:00,6.256 2014-02-23 00:15:00,6.0360000000000005 2014-02-23 00:20:00,6.644 2014-02-23 00:25:00,6.904 2014-02-23 00:30:00,6.018 2014-02-23 00:35:00,5.822 2014-02-23 00:40:00,7.916 2014-02-23 00:45:00,5.83 2014-02-23 00:50:00,6.044 2014-02-23 00:55:00,5.834 2014-02-23 01:00:00,5.836 2014-02-23 01:05:00,5.834 2014-02-23 01:10:00,6.46 2014-02-23 01:15:00,5.612 2014-02-23 01:20:00,5.88 2014-02-23 01:25:00,6.0360000000000005 2014-02-23 01:30:00,6.2520000000000024 2014-02-23 01:35:00,6.642 2014-02-23 01:40:00,7.102 2014-02-23 01:45:00,5.862 2014-02-23 01:50:00,6.004 2014-02-23 01:55:00,6.05 2014-02-23 02:00:00,6.2620000000000005 2014-02-23 02:05:00,5.827999999999999 2014-02-23 02:10:00,6.263999999999999 2014-02-23 02:15:00,7.0820000000000025 2014-02-23 02:20:00,6.25 2014-02-23 02:25:00,5.834 2014-02-23 02:30:00,6.0420000000000025 2014-02-23 02:35:00,5.822 2014-02-23 02:40:00,6.024 2014-02-23 02:45:00,5.626 2014-02-23 02:50:00,6.0020000000000024 2014-02-23 02:55:00,5.862 2014-02-23 03:00:00,5.62 2014-02-23 03:05:00,5.6320000000000014 2014-02-23 03:10:00,7.087999999999999 2014-02-23 03:15:00,6.442 2014-02-23 03:20:00,5.87 2014-02-23 03:25:00,5.827999999999999 2014-02-23 03:30:00,5.836 2014-02-23 03:35:00,5.626 2014-02-23 03:40:00,6.2520000000000024 2014-02-23 03:45:00,5.626 2014-02-23 03:50:00,5.836 2014-02-23 03:55:00,5.822 2014-02-23 04:00:00,6.64 2014-02-23 04:05:00,5.606 2014-02-23 04:10:00,6.294 2014-02-23 04:15:00,6.0360000000000005 2014-02-23 04:20:00,6.228 2014-02-23 04:25:00,6.0420000000000025 2014-02-23 04:30:00,6.2520000000000024 2014-02-23 04:35:00,5.834 2014-02-23 04:40:00,6.2520000000000024 2014-02-23 04:45:00,5.82 2014-02-23 04:50:00,6.058 2014-02-23 04:55:00,6.066 2014-02-23 05:00:00,6.232 2014-02-23 05:05:00,5.862 2014-02-23 05:10:00,6.028 2014-02-23 05:15:00,5.862 2014-02-23 05:20:00,6.024 2014-02-23 05:25:00,5.6579999999999995 2014-02-23 05:30:00,6.232 2014-02-23 05:35:00,5.204 2014-02-23 05:40:00,6.4579999999999975 2014-02-23 05:45:00,5.834 2014-02-23 05:50:00,5.836 2014-02-23 05:55:00,6.0420000000000025 2014-02-23 06:00:00,6.024 2014-02-23 06:05:00,5.862 2014-02-23 06:10:00,6.0420000000000025 2014-02-23 06:15:00,5.626 2014-02-23 06:20:00,5.794 2014-02-23 06:25:00,5.8660000000000005 2014-02-23 06:30:00,6.2520000000000024 2014-02-23 06:35:00,6.026 2014-02-23 06:40:00,6.2860000000000005 2014-02-23 06:45:00,5.834 2014-02-23 06:50:00,6.044 2014-02-23 06:55:00,6.05 2014-02-23 07:00:00,6.204 2014-02-23 07:05:00,5.848 2014-02-23 07:10:00,5.867999999999999 2014-02-23 07:15:00,6.0360000000000005 2014-02-23 07:20:00,6.046 2014-02-23 07:25:00,5.808 2014-02-23 07:30:00,6.046 2014-02-23 07:35:00,5.65 2014-02-23 07:40:00,6.25 2014-02-23 07:45:00,6.016 2014-02-23 07:50:00,6.077999999999999 2014-02-23 07:55:00,7.074 2014-02-23 08:00:00,6.2520000000000024 2014-02-23 08:05:00,5.614 2014-02-23 08:10:00,6.44 2014-02-23 08:15:00,5.862 2014-02-23 08:20:00,6.044 2014-02-23 08:25:00,6.024 2014-02-23 08:30:00,6.058 2014-02-23 08:35:00,5.834 2014-02-23 08:40:00,6.0520000000000005 2014-02-23 08:45:00,5.834 2014-02-23 08:50:00,6.03 2014-02-23 08:55:00,6.0420000000000025 2014-02-23 09:00:00,6.2520000000000024 2014-02-23 09:05:00,5.827999999999999 2014-02-23 09:10:00,6.044 2014-02-23 09:15:00,5.61 2014-02-23 09:20:00,6.02 2014-02-23 09:25:00,5.614 2014-02-23 09:30:00,5.836 2014-02-23 09:35:00,5.827999999999999 2014-02-23 09:40:00,6.044 2014-02-23 09:45:00,5.414 2014-02-23 09:50:00,6.25 2014-02-23 09:55:00,6.0420000000000025 2014-02-23 10:00:00,6.044 2014-02-23 10:05:00,5.626 2014-02-23 10:10:00,6.256 2014-02-23 10:15:00,6.034 2014-02-23 10:20:00,6.044 2014-02-23 10:25:00,6.44 2014-02-23 10:30:00,6.062 2014-02-23 10:35:00,6.074 2014-02-23 10:40:00,6.062 2014-02-23 10:45:00,5.62 2014-02-23 10:50:00,6.044 2014-02-23 10:55:00,6.032 2014-02-23 11:00:00,5.834 2014-02-23 11:05:00,6.0420000000000025 2014-02-23 11:10:00,6.6679999999999975 2014-02-23 11:15:00,5.83 2014-02-23 11:20:00,5.846 2014-02-23 11:25:00,6.022 2014-02-23 11:30:00,5.867999999999999 2014-02-23 11:35:00,5.82 2014-02-23 11:40:00,5.867999999999999 2014-02-23 11:45:00,5.8260000000000005 2014-02-23 11:50:00,6.044 2014-02-23 11:55:00,5.834 2014-02-23 12:00:00,6.044 2014-02-23 12:05:00,5.834 2014-02-23 12:10:00,6.026 2014-02-23 12:15:00,6.25 2014-02-23 12:20:00,5.843999999999999 2014-02-23 12:25:00,5.82 2014-02-23 12:30:00,6.0520000000000005 2014-02-23 12:35:00,5.6320000000000014 2014-02-23 12:40:00,6.0760000000000005 2014-02-23 12:45:00,5.83 2014-02-23 12:50:00,6.05 2014-02-23 12:55:00,6.0420000000000025 2014-02-23 13:00:00,5.816 2014-02-23 13:05:00,6.037999999999999 2014-02-23 13:10:00,6.87 2014-02-23 13:15:00,5.2120000000000015 2014-02-23 13:20:00,6.05 2014-02-23 13:25:00,5.83 2014-02-23 13:30:00,6.0360000000000005 2014-02-23 13:35:00,5.834 2014-02-23 13:40:00,6.25 2014-02-23 13:45:00,5.837999999999999 2014-02-23 13:50:00,6.2520000000000024 2014-02-23 13:55:00,6.016 2014-02-23 14:00:00,6.0820000000000025 2014-02-23 14:05:00,5.834 2014-02-23 14:10:00,6.044 2014-02-23 14:15:00,6.2520000000000024 2014-02-23 14:20:00,6.0520000000000005 2014-02-23 14:25:00,6.662000000000001 2014-02-23 14:30:00,6.2479999999999976 2014-02-23 14:35:00,6.0360000000000005 2014-02-23 14:40:00,6.6579999999999995 2014-02-23 14:45:00,5.228 2014-02-23 14:50:00,5.796 2014-02-23 14:55:00,6.05 2014-02-23 15:00:00,6.266 2014-02-23 15:05:00,6.274 2014-02-23 15:10:00,6.256 2014-02-23 15:15:00,5.816 2014-02-23 15:20:00,6.058 2014-02-23 15:25:00,5.654 2014-02-23 15:30:00,6.226 2014-02-23 15:35:00,5.624 2014-02-23 15:40:00,6.022 2014-02-23 15:45:00,5.8660000000000005 2014-02-23 15:50:00,5.814 2014-02-23 15:55:00,5.62 2014-02-23 16:00:00,6.2479999999999976 2014-02-23 16:05:00,5.816 2014-02-23 16:10:00,6.3020000000000005 2014-02-23 16:15:00,5.834 2014-02-23 16:20:00,6.0420000000000025 2014-02-23 16:25:00,6.664 2014-02-23 16:30:00,6.056 2014-02-23 16:35:00,5.626 2014-02-23 16:40:00,5.824 2014-02-23 16:45:00,6.024 2014-02-23 16:50:00,6.062 2014-02-23 16:55:00,6.07 2014-02-23 17:00:00,6.2520000000000024 2014-02-23 17:05:00,6.44 2014-02-23 17:10:00,5.6160000000000005 2014-02-23 17:15:00,6.053999999999999 2014-02-23 17:20:00,7.102 2014-02-23 17:25:00,6.046 2014-02-23 17:30:00,6.044 2014-02-23 17:35:00,5.834 2014-02-23 17:40:00,6.23 2014-02-23 17:45:00,5.827999999999999 2014-02-23 17:50:00,6.2520000000000024 2014-02-23 17:55:00,6.0420000000000025 2014-02-23 18:00:00,6.2360000000000015 2014-02-23 18:05:00,6.912000000000001 2014-02-23 18:10:00,6.46 2014-02-23 18:15:00,5.834 2014-02-23 18:20:00,6.23 2014-02-23 18:25:00,6.0420000000000025 2014-02-23 18:30:00,6.0420000000000025 2014-02-23 18:35:00,5.8260000000000005 2014-02-23 18:40:00,6.644 2014-02-23 18:45:00,5.862 2014-02-23 18:50:00,6.8420000000000005 2014-02-23 18:55:00,5.834 2014-02-23 19:00:00,6.46 2014-02-23 19:05:00,5.8260000000000005 2014-02-23 19:10:00,6.23 2014-02-23 19:15:00,6.05 2014-02-23 19:20:00,7.3420000000000005 2014-02-23 19:25:00,5.626 2014-02-23 19:30:00,6.024 2014-02-23 19:35:00,5.822 2014-02-23 19:40:00,6.03 2014-02-23 19:45:00,5.83 2014-02-23 19:50:00,6.242000000000001 2014-02-23 19:55:00,6.064 2014-02-23 20:00:00,6.053999999999999 2014-02-23 20:05:00,5.834 2014-02-23 20:10:00,6.232 2014-02-23 20:15:00,5.6160000000000005 2014-02-23 20:20:00,5.836 2014-02-23 20:25:00,7.087999999999999 2014-02-23 20:30:00,5.836 2014-02-23 20:35:00,5.803999999999999 2014-02-23 20:40:00,6.077999999999999 2014-02-23 20:45:00,5.606 2014-02-23 20:50:00,6.074 2014-02-23 20:55:00,5.624 2014-02-23 21:00:00,6.25 2014-02-23 21:05:00,5.816 2014-02-23 21:10:00,5.864 2014-02-23 21:15:00,5.82 2014-02-23 21:20:00,5.6560000000000015 2014-02-23 21:25:00,5.827999999999999 2014-02-23 21:30:00,6.0020000000000024 2014-02-23 21:35:00,6.282 2014-02-23 21:40:00,7.07 2014-02-23 21:45:00,6.074 2014-02-23 21:50:00,6.024 2014-02-23 21:55:00,6.07 2014-02-23 22:00:00,6.2520000000000024 2014-02-23 22:05:00,6.454 2014-02-23 22:10:00,5.626 2014-02-23 22:15:00,5.834 2014-02-23 22:20:00,6.676 2014-02-23 22:25:00,6.46 2014-02-23 22:30:00,6.044 2014-02-23 22:35:00,5.834 2014-02-23 22:40:00,6.257999999999999 2014-02-23 22:45:00,5.834 2014-02-23 22:50:00,5.836 2014-02-23 22:55:00,6.0120000000000005 2014-02-23 23:00:00,6.468 2014-02-23 23:05:00,6.902 2014-02-23 23:10:00,6.0420000000000025 2014-02-23 23:15:00,5.822 2014-02-23 23:20:00,5.824 2014-02-23 23:25:00,5.8660000000000005 2014-02-23 23:30:00,6.024 2014-02-23 23:35:00,6.25 2014-02-23 23:40:00,5.617999999999999 2014-02-23 23:45:00,5.626 2014-02-23 23:50:00,6.256 2014-02-23 23:55:00,5.774 2014-02-24 00:00:00,6.1560000000000015 2014-02-24 00:05:00,6.037999999999999 2014-02-24 00:10:00,6.047999999999999 2014-02-24 00:15:00,5.834 2014-02-24 00:20:00,6.886 2014-02-24 00:25:00,6.65 2014-02-24 00:30:00,6.2520000000000024 2014-02-24 00:35:00,5.803999999999999 2014-02-24 00:40:00,6.263999999999999 2014-02-24 00:45:00,5.827999999999999 2014-02-24 00:50:00,6.2520000000000024 2014-02-24 00:55:00,6.25 2014-02-24 01:00:00,6.02 2014-02-24 01:05:00,5.827999999999999 2014-02-24 01:10:00,6.6679999999999975 2014-02-24 01:15:00,5.834 2014-02-24 01:20:00,6.2520000000000024 2014-02-24 01:25:00,6.87 2014-02-24 01:30:00,6.4639999999999995 2014-02-24 01:35:00,5.622000000000001 2014-02-24 01:40:00,6.2520000000000024 2014-02-24 01:45:00,5.818 2014-02-24 01:50:00,6.058 2014-02-24 01:55:00,6.0420000000000025 2014-02-24 02:00:00,6.044 2014-02-24 02:05:00,5.827999999999999 2014-02-24 02:10:00,6.02 2014-02-24 02:15:00,6.466 2014-02-24 02:20:00,6.706 2014-02-24 02:25:00,6.0420000000000025 2014-02-24 02:30:00,5.836 2014-02-24 02:35:00,5.814 2014-02-24 02:40:00,5.87 2014-02-24 02:45:00,5.827999999999999 2014-02-24 02:50:00,5.836 2014-02-24 02:55:00,5.837999999999999 2014-02-24 03:00:00,6.89 2014-02-24 03:05:00,6.877999999999999 2014-02-24 03:10:00,6.25 2014-02-24 03:15:00,6.0420000000000025 2014-02-24 03:20:00,5.836 2014-02-24 03:25:00,5.827999999999999 2014-02-24 03:30:00,5.836 2014-02-24 03:35:00,5.834 2014-02-24 03:40:00,5.787999999999999 2014-02-24 03:45:00,5.654 2014-02-24 03:50:00,6.01 2014-02-24 03:55:00,5.862 2014-02-24 04:00:00,5.834 2014-02-24 04:05:00,5.806 2014-02-24 04:10:00,5.87 2014-02-24 04:15:00,5.614 2014-02-24 04:20:00,6.044 2014-02-24 04:25:00,5.626 2014-02-24 04:30:00,5.84 2014-02-24 04:35:00,5.837999999999999 2014-02-24 04:40:00,6.044 2014-02-24 04:45:00,5.596 2014-02-24 04:50:00,5.867999999999999 2014-02-24 04:55:00,6.0420000000000025 2014-02-24 05:00:00,5.808 2014-02-24 05:05:00,5.617999999999999 2014-02-24 05:10:00,5.843999999999999 2014-02-24 05:15:00,5.606 2014-02-24 05:20:00,6.694 2014-02-24 05:25:00,5.843999999999999 2014-02-24 05:30:00,6.0820000000000025 2014-02-24 05:35:00,5.834 2014-02-24 05:40:00,6.03 2014-02-24 05:45:00,5.834 2014-02-24 05:50:00,5.8320000000000025 2014-02-24 05:55:00,5.816 2014-02-24 06:00:00,5.862 2014-02-24 06:05:00,5.834 2014-02-24 06:10:00,6.047999999999999 2014-02-24 06:15:00,5.816 2014-02-24 06:20:00,5.87 2014-02-24 06:25:00,5.834 2014-02-24 06:30:00,6.0520000000000005 2014-02-24 06:35:00,5.622000000000001 2014-02-24 06:40:00,6.256 2014-02-24 06:45:00,5.626 2014-02-24 06:50:00,6.2520000000000024 2014-02-24 06:55:00,6.034 2014-02-24 07:00:00,6.024 2014-02-24 07:05:00,5.862 2014-02-24 07:10:00,6.4579999999999975 2014-02-24 07:15:00,5.827999999999999 2014-02-24 07:20:00,6.0420000000000025 2014-02-24 07:25:00,5.834 2014-02-24 07:30:00,6.438 2014-02-24 07:35:00,6.0420000000000025 2014-02-24 07:40:00,6.047999999999999 2014-02-24 07:45:00,6.034 2014-02-24 07:50:00,6.2520000000000024 2014-02-24 07:55:00,7.29 2014-02-24 08:00:00,6.226 2014-02-24 08:05:00,5.862 2014-02-24 08:10:00,6.4479999999999995 2014-02-24 08:15:00,6.074 2014-02-24 08:20:00,6.028 2014-02-24 08:25:00,6.01 2014-02-24 08:30:00,5.864 2014-02-24 08:35:00,5.837999999999999 2014-02-24 08:40:00,6.047999999999999 2014-02-24 08:45:00,5.816 2014-02-24 08:50:00,5.874 2014-02-24 08:55:00,6.0420000000000025 2014-02-24 09:00:00,6.02 2014-02-24 09:05:00,5.816 2014-02-24 09:10:00,6.077999999999999 2014-02-24 09:15:00,6.0420000000000025 2014-02-24 09:20:00,6.028 2014-02-24 09:25:00,5.626 2014-02-24 09:30:00,6.244 2014-02-24 09:35:00,5.62 2014-02-24 09:40:00,6.044 2014-02-24 09:45:00,5.834 2014-02-24 09:50:00,5.808 2014-02-24 09:55:00,6.07 2014-02-24 10:00:00,5.836 2014-02-24 10:05:00,5.834 2014-02-24 10:10:00,6.024 2014-02-24 10:15:00,6.226 2014-02-24 10:20:00,5.85 2014-02-24 10:25:00,5.843999999999999 2014-02-24 10:30:00,6.287999999999999 2014-02-24 10:35:00,5.837999999999999 2014-02-24 10:40:00,6.056 2014-02-24 10:45:00,5.624 2014-02-24 10:50:00,6.024 2014-02-24 10:55:00,5.86 2014-02-24 11:00:00,6.044 2014-02-24 11:05:00,5.624 2014-02-24 11:10:00,6.02 2014-02-24 11:15:00,6.056 2014-02-24 11:20:00,6.2860000000000005 2014-02-24 11:25:00,6.0420000000000025 2014-02-24 11:30:00,6.6339999999999995 2014-02-24 11:35:00,6.074 2014-02-24 11:40:00,6.024 2014-02-24 11:45:00,5.65 2014-02-24 11:50:00,6.226 2014-02-24 11:55:00,6.0420000000000025 2014-02-24 12:00:00,6.0420000000000025 2014-02-24 12:05:00,6.874 2014-02-24 12:10:00,5.602 2014-02-24 12:15:00,5.862 2014-02-24 12:20:00,6.044 2014-02-24 12:25:00,5.83 2014-02-24 12:30:00,6.0360000000000005 2014-02-24 12:35:00,5.834 2014-02-24 12:40:00,6.226 2014-02-24 12:45:00,6.474 2014-02-24 12:50:00,6.018 2014-02-24 12:55:00,5.862 2014-02-24 13:00:00,6.04 2014-02-24 13:05:00,6.454 2014-02-24 13:10:00,5.394 2014-02-24 13:15:00,5.862 2014-02-24 13:20:00,5.836 2014-02-24 13:25:00,6.6679999999999975 2014-02-24 13:30:00,6.0420000000000025 2014-02-24 13:35:00,5.622000000000001 2014-02-24 13:40:00,6.2520000000000024 2014-02-24 13:45:00,5.614 2014-02-24 13:50:00,6.2120000000000015 2014-02-24 13:55:00,6.06 2014-02-24 14:00:00,6.2520000000000024 2014-02-24 14:05:00,5.816 2014-02-24 14:10:00,6.702000000000001 2014-02-24 14:15:00,6.47 2014-02-24 14:20:00,5.837999999999999 2014-02-24 14:25:00,6.0420000000000025 2014-02-24 14:30:00,6.23 2014-02-24 14:35:00,5.83 2014-02-24 14:40:00,6.2520000000000024 2014-02-24 14:45:00,5.834 2014-02-24 14:50:00,6.224 2014-02-24 14:55:00,5.816 2014-02-24 15:00:00,6.2379999999999995 2014-02-24 15:05:00,5.648 2014-02-24 15:10:00,6.234 2014-02-24 15:15:00,5.856 2014-02-24 15:20:00,5.836 2014-02-24 15:25:00,5.61 2014-02-24 15:30:00,6.232 2014-02-24 15:35:00,5.848 2014-02-24 15:40:00,6.92 2014-02-24 15:45:00,5.6 2014-02-24 15:50:00,5.87 2014-02-24 15:55:00,5.626 2014-02-24 16:00:00,6.044 2014-02-24 16:05:00,5.834 2014-02-24 16:10:00,6.88 2014-02-24 16:15:00,5.81 2014-02-24 16:20:00,5.872000000000001 2014-02-24 16:25:00,5.837999999999999 2014-02-24 16:30:00,6.016 2014-02-24 16:35:00,5.814 2014-02-24 16:40:00,6.074 2014-02-24 16:45:00,5.414 2014-02-24 16:50:00,6.232 2014-02-24 16:55:00,6.074 2014-02-24 17:00:00,6.0420000000000025 2014-02-24 17:05:00,6.876 2014-02-24 17:10:00,6.436 2014-02-24 17:15:00,5.803999999999999 2014-02-24 17:20:00,6.037999999999999 2014-02-24 17:25:00,5.6579999999999995 2014-02-24 17:30:00,6.2520000000000024 2014-02-24 17:35:00,5.4179999999999975 2014-02-24 17:40:00,6.2479999999999976 2014-02-24 17:45:00,5.834 2014-02-24 17:50:00,6.026 2014-02-24 17:55:00,6.0420000000000025 2014-02-24 18:00:00,6.044 2014-02-24 18:05:00,6.032 2014-02-24 18:10:00,7.044 2014-02-24 18:15:00,5.8660000000000005 2014-02-24 18:20:00,6.864 2014-02-24 18:25:00,5.218 2014-02-24 18:30:00,5.796 2014-02-24 18:35:00,5.843999999999999 2014-02-24 18:40:00,6.29 2014-02-24 18:45:00,5.834 2014-02-24 18:50:00,5.8420000000000005 2014-02-24 18:55:00,6.0420000000000025 2014-02-24 19:00:00,5.836 2014-02-24 19:05:00,5.816 2014-02-24 19:10:00,6.07 2014-02-24 19:15:00,5.626 2014-02-24 19:20:00,6.053999999999999 2014-02-24 19:25:00,5.808 2014-02-24 19:30:00,6.91 2014-02-24 19:35:00,6.0420000000000025 2014-02-24 19:40:00,6.047999999999999 2014-02-24 19:45:00,5.822 2014-02-24 19:50:00,5.816 2014-02-24 19:55:00,5.4179999999999975 2014-02-24 20:00:00,6.666 2014-02-24 20:05:00,6.872000000000001 2014-02-24 20:10:00,6.047999999999999 2014-02-24 20:15:00,5.818 2014-02-24 20:20:00,6.2860000000000005 2014-02-24 20:25:00,6.022 2014-02-24 20:30:00,6.08 2014-02-24 20:35:00,5.816 2014-02-24 20:40:00,6.294 2014-02-24 20:45:00,5.822 2014-02-24 20:50:00,6.05 2014-02-24 20:55:00,6.0360000000000005 2014-02-24 21:00:00,6.46 2014-02-24 21:05:00,6.454 2014-02-24 21:10:00,6.037999999999999 2014-02-24 21:15:00,5.816 2014-02-24 21:20:00,6.09 2014-02-24 21:25:00,6.0420000000000025 2014-02-24 21:30:00,5.812 2014-02-24 21:35:00,6.044 2014-02-24 21:40:00,6.2479999999999976 2014-02-24 21:45:00,6.016 2014-02-24 21:50:00,6.257999999999999 2014-02-24 21:55:00,6.068 2014-02-24 22:00:00,5.836 2014-02-24 22:05:00,7.3 2014-02-24 22:10:00,6.228 2014-02-24 22:15:00,5.836 2014-02-24 22:20:00,6.024 2014-02-24 22:25:00,5.8660000000000005 2014-02-24 22:30:00,6.228 2014-02-24 22:35:00,5.66 2014-02-24 22:40:00,5.996 2014-02-24 22:45:00,5.862 2014-02-24 22:50:00,6.024 2014-02-24 22:55:00,5.848 2014-02-24 23:00:00,6.2920000000000025 2014-02-24 23:05:00,6.88 2014-02-24 23:10:00,6.046 2014-02-24 23:15:00,5.626 2014-02-24 23:20:00,5.8420000000000005 2014-02-24 23:25:00,6.0360000000000005 2014-02-24 23:30:00,5.836 2014-02-24 23:35:00,5.614 2014-02-24 23:40:00,6.876 2014-02-24 23:45:00,6.46 2014-02-24 23:50:00,5.836 2014-02-24 23:55:00,5.756 2014-02-25 00:00:00,6.192 2014-02-25 00:05:00,6.0420000000000025 2014-02-25 00:10:00,7.474 2014-02-25 00:15:00,5.834 2014-02-25 00:20:00,6.006 2014-02-25 00:25:00,6.0520000000000005 2014-02-25 00:30:00,6.077999999999999 2014-02-25 00:35:00,5.834 2014-02-25 00:40:00,5.818 2014-02-25 00:45:00,6.022 2014-02-25 00:50:00,6.053999999999999 2014-02-25 00:55:00,5.444 2014-02-25 01:00:00,6.2520000000000024 2014-02-25 01:05:00,5.604 2014-02-25 01:10:00,6.914 2014-02-25 01:15:00,6.867999999999999 2014-02-25 01:20:00,5.812 2014-02-25 01:25:00,5.824 2014-02-25 01:30:00,6.224 2014-02-25 01:35:00,5.83 2014-02-25 01:40:00,6.2520000000000024 2014-02-25 01:45:00,6.022 2014-02-25 01:50:00,6.077999999999999 2014-02-25 01:55:00,5.837999999999999 2014-02-25 02:00:00,6.226 2014-02-25 02:05:00,5.8320000000000025 2014-02-25 02:10:00,6.612 2014-02-25 02:15:00,7.108 2014-02-25 02:20:00,6.018 2014-02-25 02:25:00,6.0360000000000005 2014-02-25 02:30:00,6.024 2014-02-25 02:35:00,5.608 2014-02-25 02:40:00,6.062 2014-02-25 02:45:00,5.834 2014-02-25 02:50:00,5.8320000000000025 2014-02-25 02:55:00,6.0360000000000005 2014-02-25 03:00:00,6.028 2014-02-25 03:05:00,5.8420000000000005 2014-02-25 03:10:00,7.2860000000000005 2014-02-25 03:15:00,5.834 2014-02-25 03:20:00,6.016 2014-02-25 03:25:00,5.4179999999999975 2014-02-25 03:30:00,6.256 2014-02-25 03:35:00,5.827999999999999 2014-02-25 03:40:00,5.834 2014-02-25 03:45:00,5.827999999999999 2014-02-25 03:50:00,5.822 2014-02-25 03:55:00,6.034 2014-02-25 04:00:00,6.26 2014-02-25 04:05:00,5.834 2014-02-25 04:10:00,6.044 2014-02-25 04:15:00,6.0360000000000005 2014-02-25 04:20:00,6.022 2014-02-25 04:25:00,6.077999999999999 2014-02-25 04:30:00,5.836 2014-02-25 04:35:00,6.0420000000000025 2014-02-25 04:40:00,6.024 2014-02-25 04:45:00,5.816 2014-02-25 04:50:00,6.087999999999999 2014-02-25 04:55:00,5.63 2014-02-25 05:00:00,6.018 2014-02-25 05:05:00,5.8260000000000005 2014-02-25 05:10:00,5.814 2014-02-25 05:15:00,6.2379999999999995 2014-02-25 05:20:00,5.627999999999999 2014-02-25 05:25:00,6.026 2014-02-25 05:30:00,6.044 2014-02-25 05:35:00,5.626 2014-02-25 05:40:00,6.046 2014-02-25 05:45:00,5.827999999999999 2014-02-25 05:50:00,5.816 2014-02-25 05:55:00,6.07 2014-02-25 06:00:00,5.836 2014-02-25 06:05:00,5.834 2014-02-25 06:10:00,6.0420000000000025 2014-02-25 06:15:00,5.626 2014-02-25 06:20:00,6.044 2014-02-25 06:25:00,6.0420000000000025 2014-02-25 06:30:00,6.044 2014-02-25 06:35:00,5.626 2014-02-25 06:40:00,6.016 2014-02-25 06:45:00,5.626 2014-02-25 06:50:00,5.87 2014-02-25 06:55:00,6.0420000000000025 2014-02-25 07:00:00,6.4639999999999995 2014-02-25 07:05:00,6.0360000000000005 2014-02-25 07:15:00,25.1033 2014-02-25 07:20:00,17.186 2014-02-25 07:25:00,14.452 2014-02-25 07:30:00,13.968 2014-02-25 07:35:00,13.352 2014-02-25 07:40:00,15.6433 2014-02-25 07:45:00,14.4533 2014-02-25 07:50:00,15.42 2014-02-25 07:55:00,18.3333 2014-02-25 08:00:00,16.19 2014-02-25 08:05:00,15.0 2014-02-25 08:10:00,15.07 2014-02-25 08:15:00,15.0 2014-02-25 08:20:00,15.0867 2014-02-25 08:25:00,13.9333 2014-02-25 08:30:00,15.0033 2014-02-25 08:35:00,14.4533 2014-02-25 08:40:00,15.0 2014-02-25 08:45:00,13.9067 2014-02-25 08:50:00,15.1433 2014-02-25 08:55:00,14.4433 2014-02-25 09:00:00,15.5567 2014-02-25 09:05:00,14.4433 2014-02-25 09:10:00,15.55 2014-02-25 09:15:00,14.4733 2014-02-25 09:20:00,14.8833 2014-02-25 09:25:00,13.9333 2014-02-25 09:30:00,16.1133 2014-02-25 09:35:00,13.8867 2014-02-25 09:40:00,15.0 2014-02-25 09:45:00,13.27 2014-02-25 09:50:00,15.5567 2014-02-25 09:55:00,14.4433 2014-02-25 10:00:00,15.0 2014-02-25 10:05:00,13.8867 2014-02-25 10:10:00,15.0 2014-02-25 10:15:00,14.4733 2014-02-25 10:20:00,15.5567 2014-02-25 10:25:00,14.4433 2014-02-25 10:30:00,15.0 2014-02-25 10:35:00,14.3567 2014-02-25 10:40:00,15.5567 2014-02-25 10:45:00,14.4433 2014-02-25 10:50:00,15.5567 2014-02-25 10:55:00,14.5 2014-02-25 11:00:00,15.0 2014-02-25 11:05:00,14.4733 2014-02-25 11:10:00,16.11 2014-02-25 11:15:00,14.4833 2014-02-25 11:20:00,12.925 2014-02-25 11:25:00,13.9267 2014-02-25 11:30:00,15.5567 2014-02-25 11:35:00,14.4433 2014-02-25 11:40:00,15.0867 2014-02-25 11:45:00,13.8867 2014-02-25 11:50:00,14.4433 2014-02-25 11:55:00,14.3333 2014-02-25 12:00:00,15.0 2014-02-25 12:05:00,14.4567 2014-02-25 12:10:00,15.5567 2014-02-25 12:15:00,13.9533 2014-02-25 12:20:00,15.0 2014-02-25 12:25:00,13.8867 2014-02-25 12:30:00,15.0 2014-02-25 12:35:00,13.89 2014-02-25 12:40:00,14.8733 2014-02-25 12:45:00,14.4433 2014-02-25 12:50:00,15.6433 2014-02-25 12:55:00,13.97 2014-02-25 13:00:00,15.0567 2014-02-25 13:05:00,13.8867 2014-02-25 13:10:00,15.0 2014-02-25 13:15:00,13.9333 2014-02-25 13:20:00,15.5567 2014-02-25 13:25:00,13.9333 2014-02-25 13:30:00,15.0 2014-02-25 13:35:00,13.9333 2014-02-25 13:40:00,15.6133 2014-02-25 13:45:00,11.6467 2014-02-25 13:50:00,15.0867 2014-02-25 13:55:00,13.8867 2014-02-25 14:00:00,15.0 2014-02-25 14:05:00,14.4433 2014-02-25 14:10:00,15.0 2014-02-25 14:15:00,13.8867 2014-02-25 14:20:00,14.9933 2014-02-25 14:25:00,13.8867 2014-02-25 14:30:00,15.5567 2014-02-25 14:35:00,14.4433 2014-02-25 14:40:00,15.0 2014-02-25 14:45:00,13.8867 2014-02-25 14:50:00,15.0567 2014-02-25 14:55:00,13.8267 2014-02-25 15:00:00,15.1267 2014-02-25 15:05:00,13.9067 2014-02-25 15:10:00,14.8733 2014-02-25 15:15:00,12.22 2014-02-25 15:20:00,13.2333 2014-02-25 15:25:00,14.4733 2014-02-25 15:30:00,15.0 2014-02-25 15:35:00,13.9333 2014-02-25 15:40:00,14.4433 2014-02-25 15:45:00,14.3733 2014-02-25 15:50:00,15.0 2014-02-25 15:55:00,14.4433 2014-02-25 16:00:00,15.0033 2014-02-25 16:05:00,13.8267 2014-02-25 16:10:00,13.3367 2014-02-25 16:15:00,13.9267 2014-02-25 16:20:00,15.6333 2014-02-25 16:25:00,14.4833 2014-02-25 16:30:00,14.93 2014-02-25 16:35:00,14.4833 2014-02-25 16:40:00,15.0 2014-02-25 16:45:00,13.9067 2014-02-25 16:50:00,15.5567 2014-02-25 16:55:00,14.4433 2014-02-25 17:00:00,15.0567 2014-02-25 17:05:00,14.4433 2014-02-25 17:10:00,15.5567 2014-02-25 17:15:00,12.22 2014-02-25 17:20:00,15.1433 2014-02-25 17:25:00,14.5133 2014-02-25 17:30:00,15.5567 2014-02-25 17:35:00,14.4 2014-02-25 17:40:00,15.0 2014-02-25 17:45:00,14.5 2014-02-25 17:50:00,15.0 2014-02-25 17:55:00,14.4433 2014-02-25 18:00:00,15.5567 2014-02-25 18:05:00,14.4433 2014-02-25 18:10:00,13.89 2014-02-25 18:15:00,13.8867 2014-02-25 18:20:00,15.1967 2014-02-25 18:25:00,13.8867 2014-02-25 18:30:00,15.0 2014-02-25 18:35:00,14.4433 2014-02-25 18:40:00,15.0567 2014-02-25 18:45:00,14.3967 2014-02-25 18:50:00,15.5567 2014-02-25 18:55:00,14.4433 2014-02-25 19:00:00,15.0 2014-02-25 19:05:00,13.9067 2014-02-25 19:10:00,15.5567 2014-02-25 19:15:00,13.7767 2014-02-25 19:20:00,15.07 2014-02-25 19:25:00,14.3333 2014-02-25 19:30:00,14.4433 2014-02-25 19:35:00,13.8867 2014-02-25 19:40:00,13.3333 2014-02-25 19:45:00,14.4433 2014-02-25 19:50:00,15.42 2014-02-25 19:55:00,13.9067 2014-02-25 20:00:00,15.55 2014-02-25 20:05:00,14.4433 2014-02-25 20:10:00,16.1067 2014-02-25 20:15:00,14.4433 2014-02-25 20:20:00,13.75 2014-02-25 20:25:00,14.4433 2014-02-25 20:30:00,15.0 2014-02-25 20:35:00,14.4433 2014-02-25 20:40:00,15.6433 2014-02-25 20:45:00,13.8867 2014-02-25 20:50:00,14.9367 2014-02-25 20:55:00,13.8867 2014-02-25 21:00:00,15.0567 2014-02-25 21:05:00,13.9333 2014-02-25 21:10:00,15.55 2014-02-25 21:15:00,13.8867 2014-02-25 21:20:00,15.1433 2014-02-25 21:25:00,14.4433 2014-02-25 21:30:00,15.42 2014-02-25 21:35:00,15.0 2014-02-25 21:40:00,14.4433 2014-02-25 21:45:00,13.9267 2014-02-25 21:50:00,15.0867 2014-02-25 21:55:00,14.4433 2014-02-25 22:00:00,15.5567 2014-02-25 22:05:00,15.0 2014-02-25 22:10:00,15.0 2014-02-25 22:15:00,13.9333 2014-02-25 22:20:00,15.0 2014-02-25 22:25:00,14.3433 2014-02-25 22:30:00,15.0 2014-02-25 22:35:00,13.8867 2014-02-25 22:40:00,15.08 2014-02-25 22:45:00,14.4733 2014-02-25 22:50:00,13.94 2014-02-25 22:55:00,13.8867 2014-02-25 23:00:00,14.9467 2014-02-25 23:05:00,13.92 2014-02-25 23:10:00,15.0 2014-02-25 23:15:00,14.4433 2014-02-25 23:20:00,15.5567 2014-02-25 23:25:00,13.9167 2014-02-25 23:30:00,14.3267 2014-02-25 23:35:00,13.8867 2014-02-25 23:40:00,15.0867 2014-02-25 23:45:00,13.8867 2014-02-25 23:50:00,15.0 2014-02-25 23:55:00,13.39 2014-02-26 00:00:00,15.15 2014-02-26 00:05:00,14.4433 2014-02-26 00:10:00,15.5567 2014-02-26 00:15:00,14.4433 2014-02-26 00:20:00,14.9933 2014-02-26 00:25:00,13.9333 2014-02-26 00:30:00,14.4433 2014-02-26 00:35:00,13.9067 2014-02-26 00:40:00,15.0633 2014-02-26 00:45:00,14.3333 2014-02-26 00:50:00,15.0 2014-02-26 00:55:00,13.8867 2014-02-26 01:00:00,15.5567 2014-02-26 01:05:00,12.2233 2014-02-26 01:10:00,15.0 2014-02-26 01:15:00,16.15 2014-02-26 01:20:00,15.0 2014-02-26 01:25:00,13.9333 2014-02-26 01:30:00,15.0567 2014-02-26 01:35:00,13.9067 2014-02-26 01:40:00,15.08 2014-02-26 01:45:00,13.9067 2014-02-26 01:50:00,14.8633 2014-02-26 01:55:00,14.4433 2014-02-26 02:00:00,12.105 2014-02-26 02:05:00,13.8867 2014-02-26 02:10:00,15.1433 2014-02-26 02:15:00,14.4433 2014-02-26 02:20:00,15.9767 2014-02-26 02:25:00,14.4433 2014-02-26 02:30:00,14.9367 2014-02-26 02:35:00,14.5267 2014-02-26 02:40:00,15.07 2014-02-26 02:45:00,13.9067 2014-02-26 02:50:00,15.0 2014-02-26 02:55:00,13.94 2014-02-26 03:00:00,15.0 2014-02-26 03:05:00,13.3333 2014-02-26 03:10:00,15.0 2014-02-26 03:15:00,11.7067 2014-02-26 03:20:00,15.0 2014-02-26 03:25:00,14.3433 2014-02-26 03:30:00,15.42 2014-02-26 03:35:00,13.8867 2014-02-26 03:40:00,14.5 2014-02-26 03:45:00,14.4433 2014-02-26 03:50:00,15.0 2014-02-26 03:55:00,13.8867 2014-02-26 04:00:00,15.0 2014-02-26 04:05:00,13.8867 2014-02-26 04:10:00,15.01 2014-02-26 04:15:00,14.4433 2014-02-26 04:20:00,16.1133 2014-02-26 04:25:00,14.4433 2014-02-26 04:30:00,15.0867 2014-02-26 04:35:00,14.49 2014-02-26 04:40:00,15.0 2014-02-26 04:45:00,14.4433 2014-02-26 04:50:00,15.0 2014-02-26 04:55:00,13.33 2014-02-26 05:00:00,15.0 2014-02-26 05:05:00,14.3433 2014-02-26 05:10:00,15.0 2014-02-26 05:15:00,14.4533 2014-02-26 05:20:00,15.0033 2014-02-26 05:25:00,14.4433 2014-02-26 05:30:00,15.0 2014-02-26 05:35:00,13.89 2014-02-26 05:40:00,14.39 2014-02-26 05:45:00,13.3333 2014-02-26 05:50:00,15.42 2014-02-26 05:55:00,14.4933 2014-02-26 06:00:00,15.08 2014-02-26 06:05:00,14.3433 2014-02-26 06:10:00,14.9467 2014-02-26 06:15:00,13.9567 2014-02-26 06:20:00,14.8667 2014-02-26 06:25:00,15.0 2014-02-26 06:30:00,14.4433 2014-02-26 06:35:00,13.8867 2014-02-26 06:40:00,15.0 2014-02-26 06:45:00,13.3333 2014-02-26 06:50:00,15.0 2014-02-26 06:55:00,14.4433 2014-02-26 07:00:00,15.0 2014-02-26 07:05:00,13.36 2014-02-26 07:10:00,13.3675 2014-02-26 07:15:00,13.85 2014-02-26 07:20:00,15.0 2014-02-26 07:25:00,15.0 2014-02-26 07:30:00,15.62 2014-02-26 07:35:00,14.49 2014-02-26 07:40:00,15.0 2014-02-26 07:45:00,13.8867 2014-02-26 07:50:00,15.0 2014-02-26 07:55:00,16.6667 2014-02-26 08:00:00,14.9467 2014-02-26 08:05:00,13.8867 2014-02-26 08:10:00,14.4433 2014-02-26 08:15:00,14.4433 2014-02-26 08:20:00,15.5567 2014-02-26 08:25:00,14.5 2014-02-26 08:30:00,15.5567 2014-02-26 08:35:00,13.8333 2014-02-26 08:40:00,13.3425 2014-02-26 08:45:00,13.8867 2014-02-26 08:50:00,14.8633 2014-02-26 08:55:00,13.9633 2014-02-26 09:00:00,14.4433 2014-02-26 09:05:00,13.7867 2014-02-26 09:10:00,15.0 2014-02-26 09:15:00,13.9367 2014-02-26 09:20:00,15.01 2014-02-26 09:25:00,14.37 2014-02-26 09:30:00,15.07 2014-02-26 09:35:00,14.49 2014-02-26 09:40:00,15.0 2014-02-26 09:45:00,13.8033 2014-02-26 09:50:00,13.2925 2014-02-26 09:55:00,13.8267 2014-02-26 10:00:00,15.0 2014-02-26 10:05:00,12.9025 2014-02-26 10:10:00,15.0 2014-02-26 10:15:00,14.5267 2014-02-26 10:20:00,14.5 2014-02-26 10:25:00,13.8867 2014-02-26 10:30:00,13.4275 2014-02-26 10:35:00,14.36 2014-02-26 10:40:00,15.0 2014-02-26 10:45:00,12.9525 2014-02-26 10:50:00,14.8733 2014-02-26 10:55:00,13.3633 2014-02-26 11:00:00,14.3167 2014-02-26 11:05:00,13.8867 2014-02-26 11:10:00,15.0033 2014-02-26 11:15:00,12.915 2014-02-26 11:20:00,15.62 2014-02-26 11:25:00,13.8867 2014-02-26 11:30:00,17.22 2014-02-26 11:35:00,13.8867 2014-02-26 11:40:00,15.4833 2014-02-26 11:45:00,13.9333 2014-02-26 11:50:00,14.9467 2014-02-26 11:55:00,13.8867 2014-02-26 12:00:00,15.0 2014-02-26 12:05:00,14.4433 2014-02-26 12:10:00,15.5567 2014-02-26 12:15:00,14.4433 2014-02-26 12:20:00,15.6433 2014-02-26 12:25:00,13.9267 2014-02-26 12:30:00,12.9175 2014-02-26 12:35:00,14.4433 2014-02-26 12:40:00,14.4433 2014-02-26 12:45:00,13.4167 2014-02-26 12:50:00,14.49 2014-02-26 12:55:00,13.8867 2014-02-26 13:00:00,15.0 2014-02-26 13:05:00,14.4433 2014-02-26 13:10:00,15.0 2014-02-26 13:15:00,13.8867 2014-02-26 13:20:00,12.975 2014-02-26 13:25:00,13.9267 2014-02-26 13:30:00,15.0 2014-02-26 13:35:00,13.9333 2014-02-26 13:40:00,15.42 2014-02-26 13:45:00,12.22 2014-02-26 13:50:00,15.5567 2014-02-26 13:55:00,15.0 2014-02-26 14:00:00,16.19 2014-02-26 14:05:00,14.4733 2014-02-26 14:10:00,15.5567 2014-02-26 14:15:00,13.8867 2014-02-26 14:20:00,15.6333 2014-02-26 14:25:00,14.3333 2014-02-26 14:30:00,15.08 2014-02-26 14:35:00,13.9267 2014-02-26 14:40:00,14.4433 2014-02-26 14:45:00,13.7767 2014-02-26 14:50:00,15.0567 2014-02-26 14:55:00,13.9067 2014-02-26 15:00:00,15.0 2014-02-26 15:05:00,11.6667 2014-02-26 15:10:00,15.08 2014-02-26 15:15:00,14.4433 2014-02-26 15:20:00,15.42 2014-02-26 15:25:00,15.0 2014-02-26 15:30:00,15.5567 2014-02-26 15:35:00,12.7767 2014-02-26 15:40:00,15.5567 2014-02-26 15:45:00,14.4433 2014-02-26 15:50:00,15.5567 2014-02-26 15:55:00,13.8867 2014-02-26 16:00:00,15.0 2014-02-26 16:05:00,13.9267 2014-02-26 16:10:00,15.0 2014-02-26 16:15:00,13.8867 2014-02-26 16:20:00,15.0633 2014-02-26 16:25:00,15.0 2014-02-26 16:30:00,15.0567 2014-02-26 16:35:00,14.4433 2014-02-26 16:40:00,15.5567 2014-02-26 16:45:00,14.4433 2014-02-26 16:50:00,14.4433 2014-02-26 16:55:00,13.8867 2014-02-26 17:00:00,14.5233 2014-02-26 17:05:00,14.3333 2014-02-26 17:10:00,15.5567 2014-02-26 17:15:00,14.4433 2014-02-26 17:20:00,15.5667 2014-02-26 17:25:00,14.4433 2014-02-26 17:30:00,15.0 2014-02-26 17:35:00,14.3333 2014-02-26 17:40:00,15.43 2014-02-26 17:45:00,13.4367 2014-02-26 17:50:00,14.8733 2014-02-26 17:55:00,13.25 2014-02-26 18:00:00,15.5667 2014-02-26 18:05:00,13.9333 2014-02-26 18:10:00,15.5567 2014-02-26 18:15:00,13.8867 2014-02-26 18:20:00,15.0 2014-02-26 18:25:00,15.0 2014-02-26 18:30:00,16.11 2014-02-26 18:35:00,13.8867 2014-02-26 18:40:00,14.4433 2014-02-26 18:45:00,13.3333 2014-02-26 18:50:00,15.0033 2014-02-26 18:55:00,13.8867 2014-02-26 19:00:00,15.08 2014-02-26 19:05:00,13.8867 2014-02-26 19:10:00,14.8733 2014-02-26 19:15:00,12.7033 2014-02-26 19:20:00,16.1133 2014-02-26 19:25:00,12.22 2014-02-26 19:30:00,15.5567 2014-02-26 19:35:00,14.4433 2014-02-26 19:40:00,15.42 2014-02-26 19:45:00,12.915 2014-02-26 19:50:00,15.0 2014-02-26 19:55:00,13.9267 2014-02-26 20:00:00,15.0 2014-02-26 20:05:00,12.22 2014-02-26 20:10:00,15.5567 2014-02-26 20:15:00,13.8867 2014-02-26 20:20:00,15.06 2014-02-26 20:25:00,14.4433 2014-02-26 20:30:00,16.1133 2014-02-26 20:35:00,14.4633 2014-02-26 20:40:00,15.5567 2014-02-26 20:45:00,14.4433 2014-02-26 20:50:00,15.0 2014-02-26 20:55:00,14.4433 2014-02-26 21:00:00,14.88 2014-02-26 21:05:00,13.8867 2014-02-26 21:10:00,15.5567 2014-02-26 21:15:00,14.5 2014-02-26 21:20:00,16.1767 2014-02-26 21:25:00,14.89 2014-02-26 21:30:00,16.1133 2014-02-26 21:35:00,14.4433 2014-02-26 21:40:00,15.6133 2014-02-26 21:45:00,13.89 2014-02-26 21:50:00,15.0 2014-02-26 21:55:00,14.4833 2014-02-26 22:00:00,15.08 2014-02-26 22:05:00,13.8867 2014-02-26 22:10:00,15.55 2014-02-26 22:15:00,15.0767 2014-02-26 22:20:00,16.1133 2014-02-26 22:25:00,14.4433 2014-02-26 22:30:00,15.01 2014-02-26 22:35:00,14.4833 2014-02-26 22:40:00,15.6533 2014-02-26 22:45:00,14.4433 2014-02-26 22:50:00,15.6433 2014-02-26 22:55:00,13.9467 2014-02-26 23:00:00,15.0 2014-02-26 23:05:00,13.9267 2014-02-26 23:10:00,15.43 2014-02-26 23:15:00,14.4433 2014-02-26 23:20:00,15.5567 2014-02-26 23:25:00,14.49 2014-02-26 23:30:00,15.6333 2014-02-26 23:35:00,13.75 2014-02-26 23:40:00,14.1675 2014-02-26 23:45:00,13.9267 2014-02-26 23:50:00,15.0 2014-02-26 23:55:00,14.4433 2014-02-27 00:00:00,16.1533 2014-02-27 00:05:00,15.0 2014-02-27 00:10:00,15.5567 2014-02-27 00:15:00,14.4433 2014-02-27 00:20:00,14.9933 2014-02-27 00:25:00,14.4433 2014-02-27 00:30:00,15.5567 2014-02-27 00:35:00,14.3433 2014-02-27 00:40:00,14.3733 2014-02-27 00:45:00,16.695 2014-02-27 00:50:00,19.165 2014-02-27 00:55:00,12.1367 2014-02-27 01:00:00,14.8733 2014-02-27 01:05:00,14.4433 2014-02-27 01:10:00,14.9367 2014-02-27 01:15:00,14.4433 2014-02-27 01:20:00,16.1067 2014-02-27 01:25:00,15.0567 2014-02-27 01:30:00,15.5567 2014-02-27 01:35:00,14.4467 2014-02-27 01:40:00,15.5567 2014-02-27 01:45:00,15.0 2014-02-27 01:50:00,15.0033 2014-02-27 01:55:00,13.8867 2014-02-27 02:00:00,15.01 2014-02-27 02:05:00,14.3433 2014-02-27 02:10:00,15.01 2014-02-27 02:15:00,14.4833 2014-02-27 02:20:00,15.5567 2014-02-27 02:25:00,15.0 2014-02-27 02:30:00,15.5567 2014-02-27 02:35:00,14.4433 2014-02-27 02:40:00,15.0 2014-02-27 02:45:00,14.4433 2014-02-27 02:50:00,13.76 2014-02-27 02:55:00,14.3433 2014-02-27 03:00:00,15.55 2014-02-27 03:05:00,14.4833 2014-02-27 03:10:00,15.62 2014-02-27 03:15:00,14.4433 2014-02-27 03:20:00,14.8733 2014-02-27 03:25:00,13.91 2014-02-27 03:30:00,13.75 2014-02-27 03:35:00,14.4433 2014-02-27 03:40:00,15.62 2014-02-27 03:45:00,15.0 2014-02-27 03:50:00,15.6333 2014-02-27 03:55:00,13.7867 2014-02-27 04:00:00,15.0567 2014-02-27 04:05:00,13.9267 2014-02-27 04:10:00,15.07 2014-02-27 04:15:00,14.49 2014-02-27 04:20:00,16.1133 2014-02-27 04:25:00,14.4433 2014-02-27 04:30:00,14.9467 2014-02-27 04:35:00,13.8867 2014-02-27 04:40:00,15.5567 2014-02-27 04:45:00,14.39 2014-02-27 04:50:00,15.0 2014-02-27 04:55:00,14.89 2014-02-27 05:00:00,15.01 2014-02-27 05:05:00,13.9333 2014-02-27 05:10:00,15.0 2014-02-27 05:15:00,14.49 2014-02-27 05:20:00,15.0 2014-02-27 05:25:00,13.24 2014-02-27 05:30:00,15.0 2014-02-27 05:35:00,14.3333 2014-02-27 05:40:00,14.9467 2014-02-27 05:45:00,13.9267 2014-02-27 05:50:00,15.0567 2014-02-27 05:55:00,13.8867 2014-02-27 06:00:00,15.0633 2014-02-27 06:05:00,14.49 2014-02-27 06:10:00,15.5667 2014-02-27 06:15:00,13.8867 2014-02-27 06:20:00,13.75 2014-02-27 06:25:00,13.37 2014-02-27 06:30:00,15.0 2014-02-27 06:35:00,13.8867 2014-02-27 06:40:00,15.0867 2014-02-27 06:45:00,13.2633 2014-02-27 06:50:00,14.4433 2014-02-27 06:55:00,13.4167 2014-02-27 07:00:00,15.0033 2014-02-27 07:05:00,13.8867 2014-02-27 07:10:00,15.55 2014-02-27 07:15:00,13.8867 2014-02-27 07:20:00,15.0 2014-02-27 07:25:00,13.9067 2014-02-27 07:30:00,15.0867 2014-02-27 07:35:00,13.9067 2014-02-27 07:40:00,14.8667 2014-02-27 07:45:00,12.9125 2014-02-27 07:50:00,14.9367 2014-02-27 07:55:00,16.64 2014-02-27 08:00:00,15.5533 2014-02-27 08:05:00,15.02 2014-02-27 08:10:00,15.0567 2014-02-27 08:15:00,11.1233 2014-02-27 08:20:00,14.5 2014-02-27 08:25:00,13.78 2014-02-27 08:30:00,14.4433 2014-02-27 08:35:00,11.6467 2014-02-27 08:40:00,12.78 2014-02-27 08:45:00,13.9 2014-02-27 08:50:00,14.9933 2014-02-27 08:55:00,14.4833 2014-02-27 09:00:00,14.88 2014-02-27 09:05:00,13.8867 2014-02-27 09:10:00,14.8633 2014-02-27 09:15:00,13.27 2014-02-27 09:20:00,12.2233 2014-02-27 09:25:00,13.89 2014-02-27 09:30:00,15.5567 2014-02-27 09:35:00,13.7867 2014-02-27 09:40:00,14.5 2014-02-27 09:45:00,12.22 2014-02-27 09:50:00,15.0 2014-02-27 09:55:00,14.4433 2014-02-27 10:00:00,15.0567 2014-02-27 10:05:00,13.8867 2014-02-27 10:10:00,14.9933 2014-02-27 10:15:00,13.3333 2014-02-27 10:20:00,15.0567 2014-02-27 10:25:00,14.4433 2014-02-27 10:30:00,15.0967 2014-02-27 10:35:00,14.5 2014-02-27 10:40:00,15.0 2014-02-27 10:45:00,13.8867 2014-02-27 10:50:00,14.8633 2014-02-27 10:55:00,14.4733 2014-02-27 11:00:00,14.4433 2014-02-27 11:05:00,13.8867 2014-02-27 11:10:00,15.0 2014-02-27 11:15:00,13.7867 2014-02-27 11:20:00,12.81 2014-02-27 11:25:00,14.4433 2014-02-27 11:30:00,15.0567 2014-02-27 11:35:00,13.38 2014-02-27 11:40:00,12.8333 2014-02-27 11:45:00,12.2967 2014-02-27 11:50:00,15.6267 2014-02-27 11:55:00,13.38 2014-02-27 12:00:00,15.07 2014-02-27 12:05:00,13.9467 2014-02-27 12:10:00,14.8733 2014-02-27 12:15:00,13.27 2014-02-27 12:20:00,14.4433 2014-02-27 12:25:00,14.3333 2014-02-27 12:30:00,12.28 2014-02-27 12:35:00,13.9267 2014-02-27 12:40:00,14.4433 2014-02-27 12:45:00,13.9333 2014-02-27 12:50:00,15.01 2014-02-27 12:55:00,13.9333 2014-02-27 13:00:00,14.3167 2014-02-27 13:05:00,13.9267 2014-02-27 13:10:00,15.0 2014-02-27 13:15:00,14.4433 2014-02-27 13:20:00,15.5567 2014-02-27 13:25:00,13.3333 2014-02-27 13:30:00,14.8633 2014-02-27 13:35:00,13.8867 2014-02-27 13:40:00,12.8267 2014-02-27 13:45:00,13.8267 2014-02-27 13:50:00,14.4467 2014-02-27 13:55:00,13.8867 2014-02-27 14:00:00,14.4433 2014-02-27 14:05:00,13.9533 2014-02-27 14:10:00,15.0567 2014-02-27 14:15:00,13.8867 2014-02-27 14:20:00,15.5567 2014-02-27 14:25:00,14.49 2014-02-27 14:30:00,13.385 2014-02-27 14:35:00,14.3733 2014-02-27 14:40:00,15.08 2014-02-27 14:45:00,14.3733 2014-02-27 14:50:00,15.0 2014-02-27 14:55:00,14.3733 2014-02-27 15:00:00,15.0567 2014-02-27 15:05:00,14.4733 2014-02-27 15:10:00,15.0 2014-02-27 15:15:00,13.8867 2014-02-27 15:20:00,14.4433 2014-02-27 15:25:00,13.9067 2014-02-27 15:30:00,15.42 2014-02-27 15:35:00,13.7967 2014-02-27 15:40:00,15.5567 2014-02-27 15:45:00,14.3333 2014-02-27 15:50:00,15.5567 2014-02-27 15:55:00,14.4433 2014-02-27 16:00:00,15.4133 2014-02-27 16:05:00,14.35 2014-02-27 16:10:00,12.78 2014-02-27 16:15:00,13.9333 2014-02-27 16:20:00,15.0 2014-02-27 16:25:00,14.4433 2014-02-27 16:30:00,15.5567 2014-02-27 16:35:00,15.03 2014-02-27 16:40:00,15.4133 2014-02-27 16:45:00,14.4533 2014-02-27 16:50:00,15.5567 2014-02-27 16:55:00,15.0 2014-02-27 17:00:00,14.88 2014-02-27 17:05:00,14.4433 2014-02-27 17:10:00,16.1233 2014-02-27 17:15:00,14.4433 2014-02-27 17:20:00,16.05 2014-02-27 17:25:00,16.1133 2014-02-27 17:30:00,16.6633 2014-02-27 17:35:00,14.4633 2014-02-27 17:40:00,15.0 2014-02-27 17:45:00,14.4433 2014-02-27 17:50:00,15.5567 2014-02-27 17:55:00,15.0 2014-02-27 18:00:00,16.1133 2014-02-27 18:05:00,14.49 2014-02-27 18:10:00,14.5767 2014-02-27 18:15:00,14.4833 2014-02-27 18:20:00,14.8733 2014-02-27 18:25:00,13.7867 2014-02-27 18:30:00,15.0 2014-02-27 18:35:00,13.8867 2014-02-27 18:40:00,14.92 2014-02-27 18:45:00,13.8333 2014-02-27 18:50:00,15.08 2014-02-27 18:55:00,13.97 2014-02-27 19:00:00,15.0 2014-02-27 19:05:00,13.8867 2014-02-27 19:10:00,16.1133 2014-02-27 19:15:00,14.3433 2014-02-27 19:20:00,15.6133 2014-02-27 19:25:00,14.4733 2014-02-27 19:30:00,15.0 2014-02-27 19:35:00,13.9333 2014-02-27 19:40:00,14.93 2014-02-27 19:45:00,14.4433 2014-02-27 19:50:00,15.6967 2014-02-27 19:55:00,13.85 2014-02-27 20:00:00,15.5567 2014-02-27 20:05:00,14.4433 2014-02-27 20:10:00,15.5567 2014-02-27 20:15:00,14.5 2014-02-27 20:20:00,15.42 2014-02-27 20:25:00,13.8333 2014-02-27 20:30:00,15.5567 2014-02-27 20:35:00,14.49 2014-02-27 20:40:00,15.5567 2014-02-27 20:45:00,15.0 2014-02-27 20:50:00,15.0 2014-02-27 20:55:00,13.9267 2014-02-27 21:00:00,15.5567 2014-02-27 21:05:00,14.4633 2014-02-27 21:10:00,15.0 2014-02-27 21:15:00,13.7867 2014-02-27 21:20:00,15.0 2014-02-27 21:25:00,15.5567 2014-02-27 21:30:00,16.1133 2014-02-27 21:35:00,14.4433 2014-02-27 21:40:00,15.1433 2014-02-27 21:45:00,13.9067 2014-02-27 21:50:00,15.56 2014-02-27 21:55:00,13.8867 2014-02-27 22:00:00,15.0 2014-02-27 22:05:00,13.9333 2014-02-27 22:10:00,15.5567 2014-02-27 22:15:00,14.89 2014-02-27 22:20:00,15.6333 2014-02-27 22:25:00,14.5267 2014-02-27 22:30:00,14.4433 2014-02-27 22:35:00,13.8867 2014-02-27 22:40:00,15.0 2014-02-27 22:45:00,13.9267 2014-02-27 22:50:00,12.9575 2014-02-27 22:55:00,13.8033 2014-02-27 23:00:00,15.0 2014-02-27 23:05:00,13.9333 2014-02-27 23:10:00,15.0 2014-02-27 23:15:00,14.4433 2014-02-27 23:20:00,16.11 2014-02-27 23:25:00,15.02 2014-02-27 23:30:00,15.5567 2014-02-27 23:35:00,14.4733 2014-02-27 23:40:00,15.6133 2014-02-27 23:45:00,14.49 2014-02-27 23:50:00,13.6475 2014-02-27 23:55:00,14.38 2014-02-28 00:00:00,16.1467 2014-02-28 00:05:00,14.4433 2014-02-28 00:10:00,16.1133 2014-02-28 00:15:00,14.94 2014-02-28 00:20:00,15.6433 2014-02-28 00:25:00,15.0667 2014-02-28 00:30:00,15.55 2014-02-28 00:35:00,14.4433 2014-02-28 00:40:00,15.0 2014-02-28 00:45:00,14.4433 2014-02-28 00:50:00,15.5567 2014-02-28 00:55:00,15.0 2014-02-28 01:00:00,15.0 2014-02-28 01:05:00,15.0 2014-02-28 01:10:00,15.5567 2014-02-28 01:15:00,15.0 2014-02-28 01:20:00,15.5567 2014-02-28 01:25:00,13.8867 2014-02-28 01:30:00,15.5667 2014-02-28 01:35:00,13.9333 2014-02-28 01:40:00,15.55 2014-02-28 01:45:00,13.8867 2014-02-28 01:50:00,15.0 2014-02-28 01:55:00,13.8867 2014-02-28 02:00:00,15.0633 2014-02-28 02:05:00,13.8333 2014-02-28 02:10:00,15.42 2014-02-28 02:15:00,14.4733 2014-02-28 02:20:00,15.5567 2014-02-28 02:25:00,13.9467 2014-02-28 02:30:00,14.8733 2014-02-28 02:35:00,12.1933 2014-02-28 02:40:00,14.3733 2014-02-28 02:45:00,13.8867 2014-02-28 02:50:00,15.0 2014-02-28 02:55:00,13.87 2014-02-28 03:00:00,12.7767 2014-02-28 03:05:00,13.9333 2014-02-28 03:10:00,15.0 2014-02-28 03:15:00,14.52 2014-02-28 03:20:00,14.4467 2014-02-28 03:25:00,14.4433 2014-02-28 03:30:00,15.5567 2014-02-28 03:35:00,12.26 2014-02-28 03:40:00,15.1333 2014-02-28 03:45:00,15.0 2014-02-28 03:50:00,15.5567 2014-02-28 03:55:00,13.36 2014-02-28 04:00:00,14.4433 2014-02-28 04:05:00,13.9333 2014-02-28 04:10:00,15.0 2014-02-28 04:15:00,13.4125 2014-02-28 04:20:00,14.8733 2014-02-28 04:25:00,13.3333 2014-02-28 04:30:00,14.32 2014-02-28 04:35:00,14.4733 2014-02-28 04:40:00,15.4133 2014-02-28 04:45:00,13.9067 2014-02-28 04:50:00,15.55 2014-02-28 04:55:00,13.9267 2014-02-28 05:00:00,15.0 2014-02-28 05:05:00,13.9267 2014-02-28 05:10:00,15.0 2014-02-28 05:15:00,13.3333 2014-02-28 05:20:00,15.0033 2014-02-28 05:25:00,13.8867 2014-02-28 05:30:00,15.0 2014-02-28 05:35:00,13.3333 2014-02-28 05:40:00,14.8733 2014-02-28 05:45:00,14.4433 2014-02-28 05:50:00,15.0567 2014-02-28 05:55:00,13.8867 2014-02-28 06:00:00,15.0467 2014-02-28 06:05:00,13.9067 2014-02-28 06:10:00,15.0567 2014-02-28 06:15:00,14.4433 2014-02-28 06:20:00,15.0 2014-02-28 06:25:00,13.9533 2014-02-28 06:30:00,13.785 2014-02-28 06:35:00,14.49 2014-02-28 06:40:00,15.4833 2014-02-28 06:45:00,12.1467 2014-02-28 06:50:00,15.1333 2014-02-28 06:55:00,14.4433 2014-02-28 07:00:00,15.5567 2014-02-28 07:05:00,14.3433 2014-02-28 07:10:00,15.5567 2014-02-28 07:15:00,13.9067 2014-02-28 07:20:00,15.0033 2014-02-28 07:25:00,13.9733 2014-02-28 07:30:00,14.8667 2014-02-28 07:35:00,13.8867 2014-02-28 07:40:00,15.07 2014-02-28 07:45:00,13.3333 2014-02-28 07:50:00,15.5567 2014-02-28 07:55:00,17.2667 2014-02-28 08:00:00,15.5567 2014-02-28 08:05:00,13.9267 2014-02-28 08:10:00,15.5567 2014-02-28 08:15:00,13.9333 2014-02-28 08:20:00,15.4833 2014-02-28 08:25:00,14.4433 2014-02-28 08:30:00,15.6433 2014-02-28 08:35:00,13.7867 2014-02-28 08:40:00,15.6967 2014-02-28 08:45:00,14.3933 2014-02-28 08:50:00,15.08 2014-02-28 08:55:00,13.8867 2014-02-28 09:00:00,15.62 2014-02-28 09:05:00,15.0 2014-02-28 09:10:00,15.5567 2014-02-28 09:15:00,15.0 2014-02-28 09:20:00,15.0 2014-02-28 09:25:00,14.3333 2014-02-28 09:30:00,12.78 2014-02-28 09:35:00,13.8867 2014-02-28 09:40:00,15.0567 2014-02-28 09:45:00,14.3433 2014-02-28 09:50:00,15.0 2014-02-28 09:55:00,14.4433 2014-02-28 10:00:00,15.42 2014-02-28 10:05:00,13.8867 2014-02-28 10:10:00,15.5567 2014-02-28 10:15:00,15.0467 2014-02-28 10:20:00,15.42 2014-02-28 10:25:00,13.9333 2014-02-28 10:30:00,14.5 2014-02-28 10:35:00,14.3333 2014-02-28 10:40:00,16.1133 2014-02-28 10:45:00,14.4633 2014-02-28 10:50:00,14.92 2014-02-28 10:55:00,13.97 2014-02-28 11:00:00,15.5567 2014-02-28 11:05:00,15.0 2014-02-28 11:10:00,14.9933 2014-02-28 11:15:00,14.3333 2014-02-28 11:20:00,12.78 2014-02-28 11:25:00,13.9333 2014-02-28 11:30:00,15.6433 2014-02-28 11:35:00,14.4433 2014-02-28 11:40:00,14.8733 2014-02-28 11:45:00,13.8867 2014-02-28 11:50:00,15.4667 2014-02-28 11:55:00,13.8867 2014-02-28 12:00:00,15.5567 2014-02-28 12:05:00,13.9333 2014-02-28 12:10:00,15.1033 2014-02-28 12:15:00,14.4433 2014-02-28 12:20:00,16.11 2014-02-28 12:25:00,14.3333 2014-02-28 12:30:00,15.0567 2014-02-28 12:35:00,13.8867 2014-02-28 12:40:00,15.6533 2014-02-28 12:45:00,14.9667 2014-02-28 12:50:00,15.5567 2014-02-28 12:55:00,13.9733 2014-02-28 13:00:00,15.07 2014-02-28 13:05:00,15.02 2014-02-28 13:10:00,16.17 2014-02-28 13:15:00,14.5267 2014-02-28 13:20:00,15.0867 2014-02-28 13:25:00,14.4433 2014-02-28 13:30:00,15.4133 2014-02-28 13:35:00,14.4433 2014-02-28 13:40:00,15.5667 2014-02-28 13:45:00,12.2133 2014-02-28 13:50:00,12.0825 2014-02-28 13:55:00,14.3333 2014-02-28 14:00:00,15.0 2014-02-28 14:05:00,14.4633 2014-02-28 14:10:00,15.5567 2014-02-28 14:15:00,14.4833 2014-02-28 14:20:00,15.4767 2014-02-28 14:25:00,13.9433 2014-02-28 14:30:00,15.5567 ================================================ FILE: workspace/anomaly_detector/datasets/selected/level_change/rds_cpu_utilization_e47b3b.csv ================================================ timestamp,value 2014-04-10 00:02:00,14.012 2014-04-10 00:07:00,13.334000000000001 2014-04-10 00:12:00,15.0 2014-04-10 00:17:00,13.998 2014-04-10 00:22:00,14.332 2014-04-10 00:27:00,15.002 2014-04-10 00:32:00,13.984000000000002 2014-04-10 00:37:00,14.674000000000001 2014-04-10 00:42:00,14.668 2014-04-10 00:47:00,13.665999999999999 2014-04-10 00:52:00,13.334000000000001 2014-04-10 00:57:00,15.046 2014-04-10 01:02:00,13.332 2014-04-10 01:07:00,15.0 2014-04-10 01:12:00,15.0 2014-04-10 01:17:00,14.368 2014-04-10 01:22:00,13.665999999999999 2014-04-10 01:27:00,15.332 2014-04-10 01:32:00,14.334000000000001 2014-04-10 01:37:00,14.335999999999999 2014-04-10 01:42:00,14.0 2014-04-10 01:47:00,14.332 2014-04-10 01:52:00,13.332 2014-04-10 01:57:00,14.998 2014-04-10 02:02:00,13.665999999999999 2014-04-10 02:07:00,13.67 2014-04-10 02:12:00,14.668 2014-04-10 02:17:00,14.334000000000001 2014-04-10 02:22:00,14.304 2014-04-10 02:27:00,15.038 2014-04-10 02:32:00,13.665999999999999 2014-04-10 02:37:00,14.334000000000001 2014-04-10 02:42:00,14.0 2014-04-10 02:47:00,14.665999999999999 2014-04-10 02:52:00,13.0 2014-04-10 02:57:00,14.334000000000001 2014-04-10 03:02:00,14.658 2014-04-10 03:07:00,14.0 2014-04-10 03:12:00,14.318 2014-04-10 03:17:00,14.277999999999999 2014-04-10 03:22:00,14.706 2014-04-10 03:27:00,14.334000000000001 2014-04-10 03:32:00,14.0 2014-04-10 03:37:00,14.694 2014-04-10 03:42:00,14.334000000000001 2014-04-10 03:47:00,14.002 2014-04-10 03:52:00,13.716 2014-04-10 03:57:00,13.962 2014-04-10 04:02:00,13.998 2014-04-10 04:07:00,14.002 2014-04-10 04:12:00,14.0 2014-04-10 04:17:00,13.332 2014-04-10 04:22:00,14.335999999999999 2014-04-10 04:27:00,13.708 2014-04-10 04:32:00,13.998 2014-04-10 04:37:00,13.664000000000001 2014-04-10 04:42:00,13.665999999999999 2014-04-10 04:47:00,13.958 2014-04-10 04:52:00,13.716 2014-04-10 04:57:00,14.306 2014-04-10 05:02:00,13.332 2014-04-10 05:07:00,13.618 2014-04-10 05:12:00,13.665999999999999 2014-04-10 05:17:00,14.0 2014-04-10 05:22:00,14.0 2014-04-10 05:27:00,13.334000000000001 2014-04-10 05:32:00,13.998 2014-04-10 05:37:00,14.0 2014-04-10 05:42:00,14.668 2014-04-10 05:47:00,13.665999999999999 2014-04-10 05:52:00,13.668 2014-04-10 05:57:00,14.332 2014-04-10 06:02:00,14.334000000000001 2014-04-10 06:07:00,13.335999999999999 2014-04-10 06:12:00,13.665999999999999 2014-04-10 06:17:00,13.994000000000002 2014-04-10 06:22:00,14.056 2014-04-10 06:27:00,14.636 2014-04-10 06:32:00,14.384 2014-04-10 06:37:00,13.308 2014-04-10 06:42:00,14.334000000000001 2014-04-10 06:47:00,13.334000000000001 2014-04-10 06:52:00,14.366 2014-04-10 06:57:00,14.0 2014-04-10 07:02:00,14.0 2014-04-10 07:07:00,13.668 2014-04-10 07:12:00,14.0 2014-04-10 07:17:00,13.74 2014-04-10 07:22:00,13.968 2014-04-10 07:27:00,13.665999999999999 2014-04-10 07:32:00,14.0 2014-04-10 07:37:00,13.33 2014-04-10 07:42:00,14.0 2014-04-10 07:47:00,13.952 2014-04-10 07:52:00,16.0 2014-04-10 07:57:00,14.0 2014-04-10 08:02:00,13.344000000000001 2014-04-10 08:07:00,13.668 2014-04-10 08:12:00,14.0 2014-04-10 08:17:00,13.334000000000001 2014-04-10 08:22:00,14.668 2014-04-10 08:27:00,14.084000000000001 2014-04-10 08:32:00,13.645999999999999 2014-04-10 08:37:00,13.334000000000001 2014-04-10 08:42:00,14.0 2014-04-10 08:47:00,13.0 2014-04-10 08:52:00,13.665999999999999 2014-04-10 08:57:00,14.334000000000001 2014-04-10 09:02:00,13.665999999999999 2014-04-10 09:07:00,14.29 2014-04-10 09:12:00,14.0 2014-04-10 09:17:00,13.386 2014-04-10 09:22:00,14.0 2014-04-10 09:27:00,13.658 2014-04-10 09:32:00,13.318 2014-04-10 09:37:00,13.665999999999999 2014-04-10 09:42:00,13.34 2014-04-10 09:47:00,13.334000000000001 2014-04-10 09:52:00,13.665999999999999 2014-04-10 09:57:00,12.998 2014-04-10 10:02:00,14.332 2014-04-10 10:07:00,13.668 2014-04-10 10:12:00,13.665999999999999 2014-04-10 10:17:00,13.332 2014-04-10 10:22:00,13.322000000000001 2014-04-10 10:27:00,13.668 2014-04-10 10:32:00,14.0 2014-04-10 10:37:00,13.332 2014-04-10 10:42:00,14.0 2014-04-10 10:47:00,13.286 2014-04-10 10:52:00,12.998 2014-04-10 10:57:00,13.665999999999999 2014-04-10 11:02:00,13.665999999999999 2014-04-10 11:07:00,13.334000000000001 2014-04-10 11:12:00,13.69 2014-04-10 11:17:00,13.286 2014-04-10 11:22:00,14.334000000000001 2014-04-10 11:27:00,12.99 2014-04-10 11:32:00,13.722000000000001 2014-04-10 11:37:00,13.308 2014-04-10 11:42:00,13.332 2014-04-10 11:47:00,13.665999999999999 2014-04-10 11:52:00,13.022 2014-04-10 11:57:00,13.952 2014-04-10 12:02:00,12.992 2014-04-10 12:07:00,13.704 2014-04-10 12:12:00,13.665999999999999 2014-04-10 12:17:00,13.38 2014-04-10 12:22:00,14.315999999999999 2014-04-10 12:27:00,14.0 2014-04-10 12:32:00,14.0 2014-04-10 12:37:00,14.332 2014-04-10 12:42:00,13.332 2014-04-10 12:47:00,13.99 2014-04-10 12:52:00,13.714 2014-04-10 12:57:00,13.962 2014-04-10 13:02:00,13.334000000000001 2014-04-10 13:07:00,14.0 2014-04-10 13:12:00,13.024000000000001 2014-04-10 13:17:00,14.306 2014-04-10 13:22:00,13.34 2014-04-10 13:27:00,13.974 2014-04-10 13:32:00,14.04 2014-04-10 13:37:00,14.0 2014-04-10 13:42:00,13.962 2014-04-10 13:47:00,14.0 2014-04-10 13:52:00,13.332 2014-04-10 13:57:00,14.364 2014-04-10 14:02:00,12.65 2014-04-10 14:07:00,13.33 2014-04-10 14:12:00,13.35 2014-04-10 14:17:00,13.998 2014-04-10 14:22:00,13.332 2014-04-10 14:27:00,14.665999999999999 2014-04-10 14:32:00,14.0 2014-04-10 14:37:00,14.002 2014-04-10 14:42:00,12.655999999999999 2014-04-10 14:47:00,14.335999999999999 2014-04-10 14:52:00,13.06 2014-04-10 14:57:00,14.324000000000002 2014-04-10 15:02:00,12.984000000000002 2014-04-10 15:07:00,13.335999999999999 2014-04-10 15:12:00,13.332 2014-04-10 15:17:00,13.988 2014-04-10 15:22:00,13.332 2014-04-10 15:27:00,14.334000000000001 2014-04-10 15:32:00,13.31 2014-04-10 15:37:00,14.332 2014-04-10 15:42:00,13.998 2014-04-10 15:47:00,13.668 2014-04-10 15:52:00,13.332 2014-04-10 15:57:00,14.368 2014-04-10 16:02:00,13.332 2014-04-10 16:07:00,15.33 2014-04-10 16:12:00,13.332 2014-04-10 16:17:00,13.668 2014-04-10 16:22:00,14.0 2014-04-10 16:27:00,14.63 2014-04-10 16:32:00,13.706 2014-04-10 16:37:00,13.0 2014-04-10 16:42:00,14.0 2014-04-10 16:47:00,13.334000000000001 2014-04-10 16:52:00,13.33 2014-04-10 16:57:00,13.332 2014-04-10 17:02:00,13.665999999999999 2014-04-10 17:07:00,13.665999999999999 2014-04-10 17:12:00,13.332 2014-04-10 17:17:00,12.962 2014-04-10 17:22:00,14.674000000000001 2014-04-10 17:27:00,14.0 2014-04-10 17:32:00,14.0 2014-04-10 17:37:00,14.002 2014-04-10 17:42:00,14.0 2014-04-10 17:47:00,13.046 2014-04-10 17:52:00,13.672 2014-04-10 17:57:00,14.0 2014-04-10 18:02:00,13.322000000000001 2014-04-10 18:07:00,13.332 2014-04-10 18:12:00,13.332 2014-04-10 18:17:00,13.334000000000001 2014-04-10 18:22:00,14.0 2014-04-10 18:27:00,14.034 2014-04-10 18:32:00,13.665999999999999 2014-04-10 18:37:00,13.964 2014-04-10 18:42:00,13.332 2014-04-10 18:47:00,13.334000000000001 2014-04-10 18:52:00,13.332 2014-04-10 18:57:00,13.655999999999999 2014-04-10 19:02:00,13.665999999999999 2014-04-10 19:07:00,13.0 2014-04-10 19:12:00,14.345999999999998 2014-04-10 19:17:00,12.668 2014-04-10 19:22:00,13.665999999999999 2014-04-10 19:27:00,13.325999999999999 2014-04-10 19:32:00,13.978 2014-04-10 19:37:00,13.668 2014-04-10 19:42:00,14.334000000000001 2014-04-10 19:47:00,13.964 2014-04-10 19:52:00,13.704 2014-04-10 19:57:00,14.0 2014-04-10 20:02:00,13.665999999999999 2014-04-10 20:07:00,13.345999999999998 2014-04-10 20:12:00,13.69 2014-04-10 20:17:00,12.645999999999999 2014-04-10 20:22:00,13.668 2014-04-10 20:27:00,13.0 2014-04-10 20:32:00,13.332 2014-04-10 20:37:00,13.964 2014-04-10 20:42:00,14.334000000000001 2014-04-10 20:47:00,13.29 2014-04-10 20:52:00,13.332 2014-04-10 20:57:00,14.334000000000001 2014-04-10 21:02:00,12.998 2014-04-10 21:07:00,13.334000000000001 2014-04-10 21:12:00,14.334000000000001 2014-04-10 21:17:00,14.102 2014-04-10 21:22:00,14.017999999999999 2014-04-10 21:27:00,14.28 2014-04-10 21:32:00,13.95 2014-04-10 21:37:00,13.67 2014-04-10 21:42:00,14.0 2014-04-10 21:47:00,12.665999999999999 2014-04-10 21:52:00,14.0 2014-04-10 21:57:00,13.665999999999999 2014-04-10 22:02:00,13.332 2014-04-10 22:07:00,13.665999999999999 2014-04-10 22:12:00,13.044 2014-04-10 22:17:00,13.308 2014-04-10 22:22:00,13.665999999999999 2014-04-10 22:27:00,14.0 2014-04-10 22:32:00,13.665999999999999 2014-04-10 22:37:00,14.014000000000001 2014-04-10 22:42:00,14.668 2014-04-10 22:47:00,13.665999999999999 2014-04-10 22:52:00,13.332 2014-04-10 22:57:00,15.334000000000001 2014-04-10 23:02:00,13.332 2014-04-10 23:07:00,14.334000000000001 2014-04-10 23:12:00,14.0 2014-04-10 23:17:00,13.668 2014-04-10 23:22:00,14.0 2014-04-10 23:27:00,14.0 2014-04-10 23:32:00,12.998 2014-04-10 23:37:00,14.0 2014-04-10 23:42:00,12.998 2014-04-10 23:47:00,14.017999999999999 2014-04-10 23:52:00,12.998 2014-04-10 23:57:00,14.165999999999999 2014-04-11 00:02:00,13.0 2014-04-11 00:07:00,14.335999999999999 2014-04-11 00:12:00,13.665999999999999 2014-04-11 00:17:00,13.668 2014-04-11 00:22:00,13.998 2014-04-11 00:27:00,14.332 2014-04-11 00:32:00,12.998 2014-04-11 00:37:00,13.334000000000001 2014-04-11 00:42:00,13.665999999999999 2014-04-11 00:47:00,13.335999999999999 2014-04-11 00:52:00,13.665999999999999 2014-04-11 00:57:00,14.302 2014-04-11 01:02:00,12.998 2014-04-11 01:07:00,14.332 2014-04-11 01:12:00,13.665999999999999 2014-04-11 01:17:00,13.335999999999999 2014-04-11 01:22:00,13.332 2014-04-11 01:27:00,13.642000000000001 2014-04-11 01:32:00,13.665999999999999 2014-04-11 01:37:00,13.612 2014-04-11 01:42:00,13.966 2014-04-11 01:47:00,13.664000000000001 2014-04-11 01:52:00,14.334000000000001 2014-04-11 01:57:00,14.668 2014-04-11 02:02:00,14.012 2014-04-11 02:07:00,13.665999999999999 2014-04-11 02:12:00,14.312000000000001 2014-04-11 02:17:00,13.334000000000001 2014-04-11 02:22:00,14.0 2014-04-11 02:27:00,13.634 2014-04-11 02:32:00,13.665999999999999 2014-04-11 02:37:00,14.347999999999999 2014-04-11 02:42:00,14.318 2014-04-11 02:47:00,13.708 2014-04-11 02:52:00,14.334000000000001 2014-04-11 02:57:00,13.652000000000001 2014-04-11 03:02:00,14.0 2014-04-11 03:07:00,13.0 2014-04-11 03:12:00,13.665999999999999 2014-04-11 03:17:00,12.665999999999999 2014-04-11 03:22:00,13.665999999999999 2014-04-11 03:27:00,14.334000000000001 2014-04-11 03:32:00,14.0 2014-04-11 03:37:00,14.334000000000001 2014-04-11 03:42:00,14.0 2014-04-11 03:47:00,13.668 2014-04-11 03:52:00,14.0 2014-04-11 03:57:00,13.665999999999999 2014-04-11 04:02:00,13.665999999999999 2014-04-11 04:07:00,13.334000000000001 2014-04-11 04:12:00,13.665999999999999 2014-04-11 04:17:00,13.626 2014-04-11 04:22:00,13.665999999999999 2014-04-11 04:27:00,13.665999999999999 2014-04-11 04:32:00,13.665999999999999 2014-04-11 04:37:00,13.0 2014-04-11 04:42:00,14.0 2014-04-11 04:47:00,13.334000000000001 2014-04-11 04:52:00,14.655999999999999 2014-04-11 04:57:00,13.665999999999999 2014-04-11 05:02:00,13.332 2014-04-11 05:07:00,13.662 2014-04-11 05:12:00,13.345999999999998 2014-04-11 05:17:00,13.392000000000001 2014-04-11 05:22:00,13.65 2014-04-11 05:27:00,13.665999999999999 2014-04-11 05:32:00,12.998 2014-04-11 05:37:00,13.334000000000001 2014-04-11 05:42:00,13.665999999999999 2014-04-11 05:47:00,13.334000000000001 2014-04-11 05:52:00,13.332 2014-04-11 05:57:00,13.665999999999999 2014-04-11 06:02:00,13.644 2014-04-11 06:07:00,13.0 2014-04-11 06:12:00,13.332 2014-04-11 06:17:00,13.655999999999999 2014-04-11 06:22:00,13.332 2014-04-11 06:27:00,13.665999999999999 2014-04-11 06:32:00,14.048 2014-04-11 06:37:00,13.974 2014-04-11 06:42:00,13.665999999999999 2014-04-11 06:47:00,14.0 2014-04-11 06:52:00,14.0 2014-04-11 06:57:00,13.328 2014-04-11 07:02:00,13.332 2014-04-11 07:07:00,12.662 2014-04-11 07:12:00,13.716 2014-04-11 07:17:00,13.64 2014-04-11 07:22:00,13.332 2014-04-11 07:27:00,13.665999999999999 2014-04-11 07:32:00,13.332 2014-04-11 07:37:00,13.324000000000002 2014-04-11 07:42:00,13.972000000000001 2014-04-11 07:47:00,13.042 2014-04-11 07:52:00,15.31 2014-04-11 07:57:00,14.332 2014-04-11 08:02:00,13.665999999999999 2014-04-11 08:07:00,13.334000000000001 2014-04-11 08:12:00,14.0 2014-04-11 08:17:00,13.0 2014-04-11 08:22:00,14.334000000000001 2014-04-11 08:27:00,13.628 2014-04-11 08:32:00,13.704 2014-04-11 08:37:00,13.668 2014-04-11 08:42:00,13.332 2014-04-11 08:47:00,13.668 2014-04-11 08:52:00,14.0 2014-04-11 08:57:00,13.332 2014-04-11 09:02:00,13.686 2014-04-11 09:07:00,13.302 2014-04-11 09:12:00,13.665999999999999 2014-04-11 09:17:00,13.334000000000001 2014-04-11 09:22:00,13.665999999999999 2014-04-11 09:27:00,14.0 2014-04-11 09:32:00,13.332 2014-04-11 09:37:00,13.364 2014-04-11 09:42:00,13.968 2014-04-11 09:47:00,12.668 2014-04-11 09:52:00,13.332 2014-04-11 09:57:00,14.052 2014-04-11 10:02:00,13.366 2014-04-11 10:07:00,12.968 2014-04-11 10:12:00,13.672 2014-04-11 10:17:00,13.334000000000001 2014-04-11 10:22:00,14.0 2014-04-11 10:27:00,13.0 2014-04-11 10:32:00,14.027999999999999 2014-04-11 10:37:00,13.296 2014-04-11 10:42:00,14.022 2014-04-11 10:47:00,12.972000000000001 2014-04-11 10:52:00,13.35 2014-04-11 10:57:00,14.0 2014-04-11 11:02:00,13.0 2014-04-11 11:07:00,14.29 2014-04-11 11:12:00,13.366 2014-04-11 11:17:00,14.0 2014-04-11 11:22:00,13.665999999999999 2014-04-11 11:27:00,14.325999999999999 2014-04-11 11:32:00,13.01 2014-04-11 11:37:00,13.994000000000002 2014-04-11 11:42:00,13.332 2014-04-11 11:47:00,13.67 2014-04-11 11:52:00,13.334000000000001 2014-04-11 11:57:00,13.668 2014-04-11 12:02:00,13.332 2014-04-11 12:07:00,14.0 2014-04-11 12:12:00,13.315999999999999 2014-04-11 12:17:00,14.304 2014-04-11 12:22:00,13.332 2014-04-11 12:27:00,14.0 2014-04-11 12:32:00,13.0 2014-04-11 12:37:00,14.332 2014-04-11 12:42:00,13.322000000000001 2014-04-11 12:47:00,13.668 2014-04-11 12:52:00,13.677999999999999 2014-04-11 12:57:00,14.0 2014-04-11 13:02:00,13.015999999999998 2014-04-11 13:07:00,14.002 2014-04-11 13:12:00,13.665999999999999 2014-04-11 13:17:00,14.0 2014-04-11 13:22:00,13.665999999999999 2014-04-11 13:27:00,14.315999999999999 2014-04-11 13:32:00,12.668 2014-04-11 13:37:00,13.668 2014-04-11 13:42:00,13.332 2014-04-11 13:47:00,13.334000000000001 2014-04-11 13:52:00,13.35 2014-04-11 13:57:00,13.665999999999999 2014-04-11 14:02:00,12.982000000000001 2014-04-11 14:07:00,13.668 2014-04-11 14:12:00,14.0 2014-04-11 14:17:00,13.335999999999999 2014-04-11 14:22:00,13.015999999999998 2014-04-11 14:27:00,13.655999999999999 2014-04-11 14:32:00,13.334000000000001 2014-04-11 14:37:00,14.334000000000001 2014-04-11 14:42:00,13.65 2014-04-11 14:47:00,13.0 2014-04-11 14:52:00,13.665999999999999 2014-04-11 14:57:00,13.665999999999999 2014-04-11 15:02:00,13.332 2014-04-11 15:07:00,13.63 2014-04-11 15:12:00,14.368 2014-04-11 15:17:00,12.665999999999999 2014-04-11 15:22:00,13.332 2014-04-11 15:27:00,13.665999999999999 2014-04-11 15:32:00,13.665999999999999 2014-04-11 15:37:00,13.334000000000001 2014-04-11 15:42:00,13.332 2014-04-11 15:47:00,13.415999999999999 2014-04-11 15:52:00,13.3 2014-04-11 15:57:00,13.332 2014-04-11 16:02:00,13.984000000000002 2014-04-11 16:07:00,13.0 2014-04-11 16:12:00,14.334000000000001 2014-04-11 16:17:00,13.665999999999999 2014-04-11 16:22:00,14.0 2014-04-11 16:27:00,13.328 2014-04-11 16:32:00,13.668 2014-04-11 16:37:00,13.0 2014-04-11 16:42:00,14.0 2014-04-11 16:47:00,13.0 2014-04-11 16:52:00,13.702 2014-04-11 16:57:00,13.974 2014-04-11 17:02:00,13.332 2014-04-11 17:07:00,14.002 2014-04-11 17:12:00,13.332 2014-04-11 17:17:00,12.628 2014-04-11 17:22:00,13.665999999999999 2014-04-11 17:27:00,13.992 2014-04-11 17:32:00,13.665999999999999 2014-04-11 17:37:00,13.665999999999999 2014-04-11 17:42:00,13.665999999999999 2014-04-11 17:47:00,12.962 2014-04-11 17:52:00,13.332 2014-04-11 17:57:00,14.0 2014-04-11 18:02:00,14.664000000000001 2014-04-11 18:07:00,14.334000000000001 2014-04-11 18:12:00,13.665999999999999 2014-04-11 18:17:00,13.335999999999999 2014-04-11 18:22:00,13.0 2014-04-11 18:27:00,14.0 2014-04-11 18:32:00,12.988 2014-04-11 18:37:00,13.334000000000001 2014-04-11 18:42:00,13.644 2014-04-11 18:47:00,13.634 2014-04-11 18:52:00,12.664000000000001 2014-04-11 18:57:00,14.29 2014-04-11 19:02:00,12.998 2014-04-11 19:07:00,13.67 2014-04-11 19:12:00,13.378 2014-04-11 19:17:00,13.626 2014-04-11 19:22:00,13.332 2014-04-11 19:27:00,14.334000000000001 2014-04-11 19:32:00,13.044 2014-04-11 19:37:00,13.636 2014-04-11 19:42:00,13.334000000000001 2014-04-11 19:47:00,13.702 2014-04-11 19:52:00,12.677999999999999 2014-04-11 19:57:00,13.998 2014-04-11 20:02:00,12.998 2014-04-11 20:07:00,13.334000000000001 2014-04-11 20:12:00,13.664000000000001 2014-04-11 20:17:00,14.388 2014-04-11 20:22:00,14.05 2014-04-11 20:27:00,13.634 2014-04-11 20:32:00,13.332 2014-04-11 20:37:00,12.958 2014-04-11 20:42:00,13.334000000000001 2014-04-11 20:47:00,14.0 2014-04-11 20:52:00,14.0 2014-04-11 20:57:00,13.677999999999999 2014-04-11 21:02:00,14.0 2014-04-11 21:07:00,13.0 2014-04-11 21:12:00,14.0 2014-04-11 21:17:00,13.332 2014-04-11 21:22:00,14.334000000000001 2014-04-11 21:27:00,13.68 2014-04-11 21:32:00,13.998 2014-04-11 21:37:00,13.334000000000001 2014-04-11 21:42:00,14.0 2014-04-11 21:47:00,13.0 2014-04-11 21:52:00,13.718 2014-04-11 21:57:00,13.674000000000001 2014-04-11 22:02:00,13.634 2014-04-11 22:07:00,13.334000000000001 2014-04-11 22:12:00,14.668 2014-04-11 22:17:00,13.665999999999999 2014-04-11 22:22:00,13.39 2014-04-11 22:27:00,13.306 2014-04-11 22:32:00,14.0 2014-04-11 22:37:00,13.354000000000001 2014-04-11 22:42:00,14.372 2014-04-11 22:47:00,13.334000000000001 2014-04-11 22:52:00,13.645999999999999 2014-04-11 22:57:00,13.332 2014-04-11 23:02:00,14.005999999999998 2014-04-11 23:07:00,13.334000000000001 2014-04-11 23:12:00,14.664000000000001 2014-04-11 23:17:00,13.334000000000001 2014-04-11 23:22:00,14.0 2014-04-11 23:27:00,13.665999999999999 2014-04-11 23:32:00,13.332 2014-04-11 23:37:00,13.668 2014-04-11 23:42:00,13.35 2014-04-11 23:47:00,13.0 2014-04-11 23:52:00,14.0 2014-04-11 23:57:00,13.526 2014-04-12 00:02:00,13.332 2014-04-12 00:07:00,13.0 2014-04-12 00:12:00,13.665999999999999 2014-04-12 00:17:00,13.0 2014-04-12 00:22:00,13.998 2014-04-12 00:27:00,13.372 2014-04-12 00:32:00,14.0 2014-04-12 00:37:00,13.0 2014-04-12 00:42:00,13.332 2014-04-12 00:47:00,13.665999999999999 2014-04-12 00:52:00,13.674000000000001 2014-04-12 00:57:00,13.332 2014-04-12 01:02:00,13.0 2014-04-12 01:07:00,13.665999999999999 2014-04-12 01:12:00,14.334000000000001 2014-04-12 01:17:00,13.0 2014-04-12 01:22:00,13.665999999999999 2014-04-12 01:27:00,13.322000000000001 2014-04-12 01:32:00,13.665999999999999 2014-04-12 01:37:00,13.0 2014-04-12 01:42:00,14.334000000000001 2014-04-12 01:47:00,13.0 2014-04-12 01:52:00,14.334000000000001 2014-04-12 01:57:00,14.0 2014-04-12 02:02:00,13.34 2014-04-12 02:07:00,13.332 2014-04-12 02:12:00,13.0 2014-04-12 02:17:00,13.334000000000001 2014-04-12 02:22:00,14.0 2014-04-12 02:27:00,14.668 2014-04-12 02:32:00,13.665999999999999 2014-04-12 02:37:00,14.334000000000001 2014-04-12 02:42:00,13.655999999999999 2014-04-12 02:47:00,13.0 2014-04-12 02:52:00,13.998 2014-04-12 02:57:00,14.332 2014-04-12 03:02:00,12.665999999999999 2014-04-12 03:07:00,13.594000000000001 2014-04-12 03:12:00,13.665999999999999 2014-04-12 03:17:00,13.665999999999999 2014-04-12 03:22:00,12.998 2014-04-12 03:27:00,14.668 2014-04-12 03:32:00,13.015999999999998 2014-04-12 03:37:00,14.002 2014-04-12 03:42:00,12.985999999999999 2014-04-12 03:47:00,14.334000000000001 2014-04-12 03:52:00,13.0 2014-04-12 03:57:00,14.335999999999999 2014-04-12 04:02:00,12.998 2014-04-12 04:07:00,13.708 2014-04-12 04:12:00,13.296 2014-04-12 04:17:00,14.332 2014-04-12 04:22:00,12.998 2014-04-12 04:27:00,13.668 2014-04-12 04:32:00,13.665999999999999 2014-04-12 04:37:00,13.64 2014-04-12 04:42:00,13.332 2014-04-12 04:47:00,14.034 2014-04-12 04:52:00,12.665999999999999 2014-04-12 04:57:00,14.334000000000001 2014-04-12 05:02:00,13.332 2014-04-12 05:07:00,13.335999999999999 2014-04-12 05:12:00,13.668 2014-04-12 05:17:00,13.335999999999999 2014-04-12 05:22:00,13.716 2014-04-12 05:27:00,13.274000000000001 2014-04-12 05:32:00,13.032 2014-04-12 05:37:00,13.332 2014-04-12 05:42:00,13.665999999999999 2014-04-12 05:47:00,13.0 2014-04-12 05:52:00,13.665999999999999 2014-04-12 05:57:00,13.332 2014-04-12 06:02:00,13.332 2014-04-12 06:07:00,13.332 2014-04-12 06:12:00,14.318 2014-04-12 06:17:00,13.29 2014-04-12 06:22:00,12.998 2014-04-12 06:27:00,14.0 2014-04-12 06:32:00,13.332 2014-04-12 06:37:00,13.334000000000001 2014-04-12 06:42:00,14.0 2014-04-12 06:47:00,14.332 2014-04-12 06:52:00,14.0 2014-04-12 06:57:00,13.634 2014-04-12 07:02:00,13.37 2014-04-12 07:07:00,13.38 2014-04-12 07:12:00,13.665999999999999 2014-04-12 07:17:00,13.0 2014-04-12 07:22:00,14.05 2014-04-12 07:27:00,12.972000000000001 2014-04-12 07:32:00,12.998 2014-04-12 07:37:00,13.655999999999999 2014-04-12 07:42:00,13.332 2014-04-12 07:47:00,13.665999999999999 2014-04-12 07:52:00,14.0 2014-04-12 07:57:00,16.0 2014-04-12 08:02:00,13.665999999999999 2014-04-12 08:07:00,13.334000000000001 2014-04-12 08:12:00,13.734000000000002 2014-04-12 08:17:00,13.308 2014-04-12 08:22:00,13.332 2014-04-12 08:27:00,13.665999999999999 2014-04-12 08:32:00,13.332 2014-04-12 08:37:00,13.668 2014-04-12 08:42:00,13.665999999999999 2014-04-12 08:47:00,13.334000000000001 2014-04-12 08:52:00,13.65 2014-04-12 08:57:00,13.724 2014-04-12 09:02:00,14.334000000000001 2014-04-12 09:07:00,13.052 2014-04-12 09:12:00,14.0 2014-04-12 09:17:00,13.0 2014-04-12 09:22:00,14.33 2014-04-12 09:27:00,13.332 2014-04-12 09:32:00,13.332 2014-04-12 09:37:00,14.014000000000001 2014-04-12 09:42:00,13.665999999999999 2014-04-12 09:47:00,13.0 2014-04-12 09:52:00,12.998 2014-04-12 09:57:00,13.665999999999999 2014-04-12 10:02:00,14.0 2014-04-12 10:07:00,13.334000000000001 2014-04-12 10:12:00,13.668 2014-04-12 10:17:00,13.334000000000001 2014-04-12 10:22:00,13.332 2014-04-12 10:27:00,13.718 2014-04-12 10:32:00,13.665999999999999 2014-04-12 10:37:00,13.334000000000001 2014-04-12 10:42:00,14.002 2014-04-12 10:47:00,13.0 2014-04-12 10:52:00,13.995999999999999 2014-04-12 10:57:00,13.998 2014-04-12 11:02:00,13.655999999999999 2014-04-12 11:07:00,14.328 2014-04-12 11:12:00,13.332 2014-04-12 11:17:00,13.334000000000001 2014-04-12 11:22:00,12.998 2014-04-12 11:27:00,13.334000000000001 2014-04-12 11:32:00,13.332 2014-04-12 11:37:00,13.665999999999999 2014-04-12 11:42:00,13.332 2014-04-12 11:47:00,13.334000000000001 2014-04-12 11:52:00,13.332 2014-04-12 11:57:00,13.665999999999999 2014-04-12 12:02:00,12.665999999999999 2014-04-12 12:07:00,13.334000000000001 2014-04-12 12:12:00,13.712 2014-04-12 12:17:00,14.3 2014-04-12 12:22:00,13.06 2014-04-12 12:27:00,13.597999999999999 2014-04-12 12:32:00,13.668 2014-04-12 12:37:00,13.716 2014-04-12 12:42:00,13.332 2014-04-12 12:47:00,13.335999999999999 2014-04-12 12:52:00,13.315999999999999 2014-04-12 12:57:00,14.0 2014-04-12 13:02:00,12.998 2014-04-12 13:07:00,13.37 2014-04-12 13:12:00,13.315999999999999 2014-04-12 13:17:00,14.0 2014-04-12 13:22:00,12.664000000000001 2014-04-12 13:27:00,13.658 2014-04-12 13:32:00,13.315999999999999 2014-04-12 13:37:00,13.002 2014-04-12 13:42:00,13.665999999999999 2014-04-12 13:47:00,13.334000000000001 2014-04-12 13:52:00,14.046 2014-04-12 13:57:00,13.008 2014-04-12 14:02:00,13.665999999999999 2014-04-12 14:07:00,13.67 2014-04-12 14:12:00,13.38 2014-04-12 14:17:00,13.64 2014-04-12 14:22:00,12.994000000000002 2014-04-12 14:27:00,12.995999999999999 2014-04-12 14:32:00,14.017999999999999 2014-04-12 14:37:00,14.002 2014-04-12 14:42:00,13.338 2014-04-12 14:47:00,13.0 2014-04-12 14:52:00,13.332 2014-04-12 14:57:00,13.665999999999999 2014-04-12 15:02:00,13.015999999999998 2014-04-12 15:07:00,13.334000000000001 2014-04-12 15:12:00,14.0 2014-04-12 15:17:00,14.0 2014-04-12 15:22:00,13.332 2014-04-12 15:27:00,13.29 2014-04-12 15:32:00,13.368 2014-04-12 15:37:00,13.668 2014-04-12 15:42:00,13.344000000000001 2014-04-12 15:47:00,13.668 2014-04-12 15:52:00,13.665999999999999 2014-04-12 15:57:00,13.332 2014-04-12 16:02:00,14.334000000000001 2014-04-12 16:07:00,13.665999999999999 2014-04-12 16:12:00,14.0 2014-04-12 16:17:00,13.332 2014-04-12 16:22:00,12.975999999999999 2014-04-12 16:27:00,14.0 2014-04-12 16:32:00,13.665999999999999 2014-04-12 16:37:00,13.0 2014-04-12 16:42:00,14.0 2014-04-12 16:47:00,13.332 2014-04-12 16:52:00,13.344000000000001 2014-04-12 16:57:00,13.665999999999999 2014-04-12 17:02:00,12.984000000000002 2014-04-12 17:07:00,14.002 2014-04-12 17:12:00,14.0 2014-04-12 17:17:00,13.334000000000001 2014-04-12 17:22:00,13.0 2014-04-12 17:27:00,14.0 2014-04-12 17:32:00,12.984000000000002 2014-04-12 17:37:00,12.662 2014-04-12 17:42:00,13.665999999999999 2014-04-12 17:47:00,13.664000000000001 2014-04-12 17:52:00,12.998 2014-04-12 17:57:00,14.0 2014-04-12 18:02:00,13.665999999999999 2014-04-12 18:07:00,13.335999999999999 2014-04-12 18:12:00,13.665999999999999 2014-04-12 18:17:00,13.0 2014-04-12 18:22:00,13.332 2014-04-12 18:27:00,14.368 2014-04-12 18:32:00,14.0 2014-04-12 18:37:00,13.334000000000001 2014-04-12 18:42:00,13.31 2014-04-12 18:47:00,13.668 2014-04-12 18:52:00,13.332 2014-04-12 18:57:00,13.662 2014-04-12 19:02:00,14.0 2014-04-12 19:07:00,13.334000000000001 2014-04-12 19:12:00,14.334000000000001 2014-04-12 19:17:00,13.0 2014-04-12 19:22:00,13.665999999999999 2014-04-12 19:27:00,13.334000000000001 2014-04-12 19:32:00,12.998 2014-04-12 19:37:00,13.668 2014-04-12 19:42:00,13.335999999999999 2014-04-12 19:47:00,13.668 2014-04-12 19:52:00,12.665999999999999 2014-04-12 19:57:00,15.334000000000001 2014-04-12 20:02:00,13.665999999999999 2014-04-12 20:07:00,13.334000000000001 2014-04-12 20:12:00,13.332 2014-04-12 20:17:00,14.0 2014-04-12 20:22:00,13.372 2014-04-12 20:27:00,13.968 2014-04-12 20:32:00,12.998 2014-04-12 20:37:00,13.668 2014-04-12 20:42:00,13.665999999999999 2014-04-12 20:47:00,13.68 2014-04-12 20:52:00,13.332 2014-04-12 20:57:00,14.665999999999999 2014-04-12 21:02:00,12.968 2014-04-12 21:07:00,14.0 2014-04-12 21:12:00,12.966 2014-04-12 21:17:00,14.0 2014-04-12 21:22:00,13.665999999999999 2014-04-12 21:27:00,14.334000000000001 2014-04-12 21:32:00,12.998 2014-04-12 21:37:00,13.67 2014-04-12 21:42:00,13.665999999999999 2014-04-12 21:47:00,13.37 2014-04-12 21:52:00,13.665999999999999 2014-04-12 21:57:00,14.332 2014-04-12 22:02:00,13.0 2014-04-12 22:07:00,14.342 2014-04-12 22:12:00,13.665999999999999 2014-04-12 22:17:00,14.046 2014-04-12 22:22:00,13.294 2014-04-12 22:27:00,14.0 2014-04-12 22:32:00,12.664000000000001 2014-04-12 22:37:00,13.002 2014-04-12 22:42:00,13.652000000000001 2014-04-12 22:47:00,13.668 2014-04-12 22:52:00,13.332 2014-04-12 22:57:00,14.322000000000001 2014-04-12 23:02:00,13.332 2014-04-12 23:07:00,13.334000000000001 2014-04-12 23:12:00,13.665999999999999 2014-04-12 23:17:00,13.668 2014-04-12 23:22:00,13.334000000000001 2014-04-12 23:27:00,13.665999999999999 2014-04-12 23:32:00,14.0 2014-04-12 23:37:00,13.334000000000001 2014-04-12 23:42:00,14.71 2014-04-12 23:47:00,12.665999999999999 2014-04-12 23:52:00,13.06 2014-04-12 23:57:00,13.834000000000001 2014-04-13 00:02:00,12.998 2014-04-13 00:07:00,13.38 2014-04-13 00:12:00,13.312000000000001 2014-04-13 00:17:00,12.99 2014-04-13 00:22:00,13.665999999999999 2014-04-13 00:27:00,14.0 2014-04-13 00:32:00,14.334000000000001 2014-04-13 00:37:00,13.334000000000001 2014-04-13 00:42:00,13.012 2014-04-13 00:47:00,13.334000000000001 2014-04-13 00:52:00,13.665999999999999 2014-04-13 00:57:00,13.665999999999999 2014-04-13 01:02:00,13.665999999999999 2014-04-13 01:07:00,13.334000000000001 2014-04-13 01:12:00,14.35 2014-04-13 01:17:00,14.0 2014-04-13 01:22:00,13.722000000000001 2014-04-13 01:27:00,13.968 2014-04-13 01:32:00,13.332 2014-04-13 01:37:00,13.332 2014-04-13 01:42:00,13.334000000000001 2014-04-13 01:47:00,13.334000000000001 2014-04-13 01:52:00,13.665999999999999 2014-04-13 01:57:00,13.626 2014-04-13 02:02:00,13.665999999999999 2014-04-13 02:07:00,13.702 2014-04-13 02:12:00,13.665999999999999 2014-04-13 02:17:00,14.334000000000001 2014-04-13 02:22:00,13.665999999999999 2014-04-13 02:27:00,13.332 2014-04-13 02:32:00,14.0 2014-04-13 02:37:00,12.665999999999999 2014-04-13 02:42:00,14.0 2014-04-13 02:47:00,13.334000000000001 2014-04-13 02:52:00,13.334000000000001 2014-04-13 02:57:00,14.0 2014-04-13 03:02:00,13.382 2014-04-13 03:07:00,13.026 2014-04-13 03:12:00,14.665999999999999 2014-04-13 03:17:00,14.0 2014-04-13 03:22:00,13.332 2014-04-13 03:27:00,13.968 2014-04-13 03:32:00,13.665999999999999 2014-04-13 03:37:00,13.0 2014-04-13 03:42:00,14.0 2014-04-13 03:47:00,13.372 2014-04-13 03:52:00,13.294 2014-04-13 03:57:00,14.302 2014-04-13 04:02:00,12.984000000000002 2014-04-13 04:07:00,13.668 2014-04-13 04:12:00,13.655999999999999 2014-04-13 04:17:00,12.962 2014-04-13 04:22:00,14.0 2014-04-13 04:27:00,13.362 2014-04-13 04:32:00,13.294 2014-04-13 04:37:00,13.334000000000001 2014-04-13 04:42:00,13.668 2014-04-13 04:47:00,13.0 2014-04-13 04:52:00,13.332 2014-04-13 04:57:00,13.706 2014-04-13 05:02:00,13.294 2014-04-13 05:07:00,13.665999999999999 2014-04-13 05:12:00,13.0 2014-04-13 05:17:00,14.0 2014-04-13 05:22:00,12.665999999999999 2014-04-13 05:27:00,13.334000000000001 2014-04-13 05:32:00,12.664000000000001 2014-04-13 05:37:00,13.67 2014-04-13 05:42:00,13.665999999999999 2014-04-13 05:47:00,13.37 2014-04-13 05:52:00,12.665999999999999 2014-04-13 05:57:00,14.002 2014-04-13 06:02:00,13.665999999999999 2014-04-13 06:07:00,13.335999999999999 2014-04-13 06:12:00,13.665999999999999 2014-04-13 06:17:00,13.002 2014-04-13 06:22:00,13.665999999999999 2014-04-13 06:27:00,13.665999999999999 2014-04-13 06:32:00,12.998 2014-04-13 06:37:00,14.374 2014-04-13 06:42:00,13.665999999999999 2014-04-13 06:47:00,13.706 2014-04-13 06:52:00,76.23 2014-04-13 06:57:00,65.835 2014-04-13 07:02:00,21.666 2014-04-13 07:07:00,17.668 2014-04-13 07:12:00,16.668 2014-04-13 07:17:00,16.666 2014-04-13 07:22:00,15.668 2014-04-13 07:27:00,17.0 2014-04-13 07:32:00,15.665999999999999 2014-04-13 07:37:00,16.296 2014-04-13 07:42:00,16.336 2014-04-13 07:47:00,16.668 2014-04-13 07:52:00,17.334 2014-04-13 07:57:00,18.334 2014-04-13 08:02:00,16.652 2014-04-13 08:07:00,16.0 2014-04-13 08:12:00,16.738 2014-04-13 08:17:00,16.62 2014-04-13 08:22:00,16.336 2014-04-13 08:27:00,16.668 2014-04-13 08:32:00,16.012 2014-04-13 08:37:00,16.0 2014-04-13 08:42:00,17.018 2014-04-13 08:47:00,16.334 2014-04-13 08:52:00,16.392 2014-04-13 08:57:00,15.958 2014-04-13 09:02:00,17.0 2014-04-13 09:07:00,16.334 2014-04-13 09:12:00,17.0 2014-04-13 09:17:00,17.0 2014-04-13 09:22:00,16.334 2014-04-13 09:27:00,16.334 2014-04-13 09:32:00,17.012 2014-04-13 09:37:00,16.334 2014-04-13 09:42:00,16.32 2014-04-13 09:47:00,16.334 2014-04-13 09:52:00,16.668 2014-04-13 09:57:00,16.666 2014-04-13 10:02:00,16.392 2014-04-13 10:07:00,16.298 2014-04-13 10:12:00,16.334 2014-04-13 10:17:00,16.666 2014-04-13 10:22:00,16.67 2014-04-13 10:27:00,16.334 2014-04-13 10:32:00,16.336 2014-04-13 10:37:00,16.666 2014-04-13 10:42:00,16.666 2014-04-13 10:47:00,16.042 2014-04-13 10:52:00,16.334 2014-04-13 10:57:00,16.334 2014-04-13 11:02:00,16.336 2014-04-13 11:07:00,16.988 2014-04-13 11:12:00,16.666 2014-04-13 11:17:00,16.0 2014-04-13 11:22:00,16.668 2014-04-13 11:27:00,16.656 2014-04-13 11:32:00,16.352 2014-04-13 11:37:00,16.002 2014-04-13 11:42:00,16.668 2014-04-13 11:47:00,16.0 2014-04-13 11:52:00,16.002 2014-04-13 11:57:00,17.0 2014-04-13 12:02:00,16.336 2014-04-13 12:07:00,16.666 2014-04-13 12:12:00,16.0 2014-04-13 12:17:00,15.998 2014-04-13 12:22:00,16.334 2014-04-13 12:27:00,16.0 2014-04-13 12:32:00,16.666 2014-04-13 12:37:00,15.63 2014-04-13 12:42:00,17.392 2014-04-13 12:47:00,17.33 2014-04-13 12:52:00,16.0 2014-04-13 12:57:00,16.668 2014-04-13 13:02:00,16.605999999999998 2014-04-13 13:07:00,16.38 2014-04-13 13:12:00,17.668 2014-04-13 13:17:00,15.668 2014-04-13 13:22:00,16.668 2014-04-13 13:27:00,15.655999999999999 2014-04-13 13:32:00,16.65 2014-04-13 13:37:00,16.332 2014-04-13 13:42:00,16.666 2014-04-13 13:47:00,15.998 2014-04-13 13:52:00,16.67 2014-04-13 13:57:00,17.002 2014-04-13 14:02:00,16.317999999999998 2014-04-13 14:07:00,16.332 2014-04-13 14:12:00,16.334 2014-04-13 14:17:00,17.0 2014-04-13 14:22:00,15.668 2014-04-13 14:27:00,17.334 2014-04-13 14:32:00,16.668 2014-04-13 14:37:00,16.666 2014-04-13 14:42:00,16.002 2014-04-13 14:47:00,17.0 2014-04-13 14:52:00,15.684000000000001 2014-04-13 14:57:00,17.0 2014-04-13 15:02:00,16.018 2014-04-13 15:07:00,16.666 2014-04-13 15:12:00,16.0 2014-04-13 15:17:00,17.046 2014-04-13 15:22:00,15.958 2014-04-13 15:27:00,16.31 2014-04-13 15:32:00,17.0 2014-04-13 15:37:00,17.0 2014-04-13 15:42:00,16.0 2014-04-13 15:47:00,17.384 2014-04-13 15:52:00,16.288 2014-04-13 15:57:00,16.666 2014-04-13 16:02:00,16.334 2014-04-13 16:07:00,17.0 2014-04-13 16:12:00,16.002 2014-04-13 16:17:00,17.0 2014-04-13 16:22:00,16.334 2014-04-13 16:27:00,17.668 2014-04-13 16:32:00,16.724 2014-04-13 16:37:00,15.954 2014-04-13 16:42:00,17.0 2014-04-13 16:47:00,16.666 2014-04-13 16:52:00,15.665999999999999 2014-04-13 16:57:00,17.332 2014-04-13 17:02:00,16.668 2014-04-13 17:07:00,16.7 2014-04-13 17:12:00,17.332 2014-04-13 17:17:00,16.0 2014-04-13 17:22:00,17.334 2014-04-13 17:27:00,17.044 2014-04-13 17:32:00,16.724 2014-04-13 17:37:00,16.29 2014-04-13 17:42:00,17.0 2014-04-13 17:47:00,16.052 2014-04-13 17:52:00,17.0 2014-04-13 17:57:00,17.0 2014-04-13 18:02:00,16.317999999999998 2014-04-13 18:07:00,16.998 2014-04-13 18:12:00,16.998 2014-04-13 18:17:00,17.002 2014-04-13 18:22:00,16.0 2014-04-13 18:27:00,16.378 2014-04-13 18:32:00,16.622 2014-04-13 18:37:00,15.634 2014-04-13 18:42:00,16.684 2014-04-13 18:47:00,16.0 2014-04-13 18:52:00,15.984000000000002 2014-04-13 18:57:00,17.038 2014-04-13 19:02:00,16.332 2014-04-13 19:07:00,15.668 2014-04-13 19:12:00,17.002 2014-04-13 19:17:00,15.668 2014-04-13 19:22:00,16.334 2014-04-13 19:27:00,16.332 2014-04-13 19:32:00,16.334 2014-04-13 19:37:00,16.977999999999998 2014-04-13 19:42:00,16.666 2014-04-13 19:47:00,16.0 2014-04-13 19:52:00,16.055999999999994 2014-04-13 19:57:00,16.29 2014-04-13 20:02:00,16.666 2014-04-13 20:07:00,15.334000000000001 2014-04-13 20:12:00,16.68 2014-04-13 20:17:00,16.336 2014-04-13 20:22:00,17.352 2014-04-13 20:27:00,16.666 2014-04-13 20:32:00,16.334 2014-04-13 20:37:00,15.99 2014-04-13 20:42:00,16.334 2014-04-13 20:47:00,15.998 2014-04-13 20:52:00,16.674 2014-04-13 20:57:00,16.285999999999998 2014-04-13 21:02:00,16.674 2014-04-13 21:07:00,16.0 2014-04-13 21:12:00,16.334 2014-04-13 21:17:00,16.666 2014-04-13 21:22:00,17.0 2014-04-13 21:27:00,16.706 2014-04-13 21:32:00,16.302 2014-04-13 21:37:00,16.0 2014-04-13 21:42:00,16.666 2014-04-13 21:47:00,16.332 2014-04-13 21:52:00,16.668 2014-04-13 21:57:00,17.002 2014-04-13 22:02:00,16.064 2014-04-13 22:07:00,16.95 2014-04-13 22:12:00,15.665999999999999 2014-04-13 22:17:00,16.666 2014-04-13 22:22:00,16.355999999999998 2014-04-13 22:27:00,17.328 2014-04-13 22:32:00,16.68 2014-04-13 22:37:00,16.666 2014-04-13 22:42:00,16.998 2014-04-13 22:47:00,16.666 2014-04-13 22:52:00,16.006 2014-04-13 22:57:00,16.715999999999998 2014-04-13 23:02:00,15.63 2014-04-13 23:07:00,16.666 2014-04-13 23:12:00,18.334 2014-04-13 23:17:00,16.666 2014-04-13 23:22:00,16.666 2014-04-13 23:27:00,16.046 2014-04-13 23:32:00,16.285999999999998 2014-04-13 23:37:00,16.332 2014-04-13 23:42:00,16.0 2014-04-13 23:47:00,17.0 2014-04-13 23:52:00,16.0 2014-04-13 23:57:00,16.436 2014-04-14 00:02:00,15.668 2014-04-14 00:07:00,17.0 2014-04-14 00:12:00,16.334 2014-04-14 00:17:00,17.0 2014-04-14 00:22:00,16.336 2014-04-14 00:27:00,16.666 2014-04-14 00:32:00,16.332 2014-04-14 00:37:00,16.332 2014-04-14 00:42:00,16.355999999999998 2014-04-14 00:47:00,17.0 2014-04-14 00:52:00,16.002 2014-04-14 00:57:00,17.01 2014-04-14 01:02:00,15.38 2014-04-14 01:07:00,16.282 2014-04-14 01:12:00,17.334 2014-04-14 01:17:00,17.0 2014-04-14 01:22:00,16.002 2014-04-14 01:27:00,16.666 2014-04-14 01:32:00,17.016 2014-04-14 01:37:00,17.0 2014-04-14 01:42:00,16.334 2014-04-14 01:47:00,16.372 2014-04-14 01:52:00,16.332 2014-04-14 01:57:00,16.666 2014-04-14 02:02:00,16.334 2014-04-14 02:07:00,16.998 2014-04-14 02:12:00,17.0 2014-04-14 02:17:00,16.334 2014-04-14 02:22:00,16.97 2014-04-14 02:27:00,16.666 2014-04-14 02:32:00,16.336 2014-04-14 02:37:00,17.0 2014-04-14 02:42:00,16.334 2014-04-14 02:47:00,15.664000000000001 2014-04-14 02:52:00,16.668 2014-04-14 02:57:00,16.334 2014-04-14 03:02:00,16.0 2014-04-14 03:07:00,16.044 2014-04-14 03:12:00,17.294 2014-04-14 03:17:00,16.0 2014-04-14 03:22:00,17.0 2014-04-14 03:27:00,16.334 2014-04-14 03:32:00,17.332 2014-04-14 03:37:00,15.72 2014-04-14 03:42:00,16.666 2014-04-14 03:47:00,15.668 2014-04-14 03:52:00,16.336 2014-04-14 03:57:00,16.334 2014-04-14 04:02:00,16.33 2014-04-14 04:07:00,16.334 2014-04-14 04:12:00,16.317999999999998 2014-04-14 04:17:00,16.372 2014-04-14 04:22:00,16.666 2014-04-14 04:27:00,16.666 2014-04-14 04:32:00,16.668 2014-04-14 04:37:00,15.334000000000001 2014-04-14 04:42:00,17.0 2014-04-14 04:47:00,16.042 2014-04-14 04:52:00,16.652 2014-04-14 04:57:00,16.002 2014-04-14 05:02:00,16.002 2014-04-14 05:07:00,16.334 2014-04-14 05:12:00,16.664 2014-04-14 05:17:00,16.334 2014-04-14 05:22:00,16.334 2014-04-14 05:27:00,16.336 2014-04-14 05:32:00,16.666 2014-04-14 05:37:00,15.968 2014-04-14 05:42:00,16.99 2014-04-14 05:47:00,16.332 2014-04-14 05:52:00,15.668 2014-04-14 05:57:00,16.332 2014-04-14 06:02:00,16.378 2014-04-14 06:07:00,16.95 2014-04-14 06:12:00,16.652 2014-04-14 06:17:00,16.666 2014-04-14 06:22:00,16.336 2014-04-14 06:27:00,16.666 2014-04-14 06:32:00,16.715999999999998 2014-04-14 06:37:00,16.288 2014-04-14 06:42:00,16.666 2014-04-14 06:47:00,16.666 2014-04-14 06:52:00,16.334 2014-04-14 06:57:00,17.3 2014-04-14 07:02:00,16.336 2014-04-14 07:07:00,16.666 2014-04-14 07:12:00,16.666 2014-04-14 07:17:00,16.044 2014-04-14 07:22:00,16.284000000000002 2014-04-14 07:27:00,16.666 2014-04-14 07:32:00,16.332 2014-04-14 07:37:00,17.0 2014-04-14 07:42:00,16.342 2014-04-14 07:47:00,16.332 2014-04-14 07:52:00,16.334 2014-04-14 07:57:00,19.0 2014-04-14 08:02:00,15.668 2014-04-14 08:07:00,17.0 2014-04-14 08:12:00,16.052 2014-04-14 08:17:00,16.316 2014-04-14 08:22:00,16.334 2014-04-14 08:27:00,16.666 2014-04-14 08:32:00,16.666 2014-04-14 08:37:00,16.666 2014-04-14 08:42:00,16.656 2014-04-14 08:47:00,16.666 2014-04-14 08:52:00,16.0 2014-04-14 08:57:00,16.666 2014-04-14 09:02:00,16.668 2014-04-14 09:07:00,16.666 2014-04-14 09:12:00,16.334 2014-04-14 09:17:00,16.332 2014-04-14 09:22:00,16.664 2014-04-14 09:27:00,17.334 2014-04-14 09:32:00,16.002 2014-04-14 09:37:00,16.666 2014-04-14 09:42:00,17.04 2014-04-14 09:47:00,16.288 2014-04-14 09:52:00,16.682000000000002 2014-04-14 09:57:00,16.334 2014-04-14 10:02:00,16.648 2014-04-14 10:07:00,16.002 2014-04-14 10:12:00,17.35 2014-04-14 10:17:00,16.0 2014-04-14 10:22:00,16.666 2014-04-14 10:27:00,18.332 2014-04-14 10:32:00,16.336 2014-04-14 10:37:00,16.0 2014-04-14 10:42:00,16.998 2014-04-14 10:47:00,16.0 2014-04-14 10:52:00,16.334 2014-04-14 10:57:00,16.998 2014-04-14 11:02:00,16.336 2014-04-14 11:07:00,16.668 2014-04-14 11:12:00,16.666 2014-04-14 11:17:00,16.666 2014-04-14 11:22:00,17.0 2014-04-14 11:27:00,16.622 2014-04-14 11:32:00,16.714000000000002 2014-04-14 11:37:00,16.332 2014-04-14 11:42:00,16.358 2014-04-14 11:47:00,15.964 2014-04-14 11:52:00,16.64 2014-04-14 11:57:00,16.002 2014-04-14 12:02:00,17.0 2014-04-14 12:07:00,16.332 2014-04-14 12:12:00,16.336 2014-04-14 12:17:00,16.324 2014-04-14 12:22:00,16.692 2014-04-14 12:27:00,16.372 2014-04-14 12:32:00,16.928 2014-04-14 12:37:00,15.665999999999999 2014-04-14 12:42:00,17.0 2014-04-14 12:47:00,16.002 2014-04-14 12:52:00,16.658 2014-04-14 12:57:00,16.668 2014-04-14 13:02:00,17.0 2014-04-14 13:07:00,16.334 2014-04-14 13:12:00,16.668 2014-04-14 13:17:00,15.668 2014-04-14 13:22:00,16.998 2014-04-14 13:27:00,16.352 2014-04-14 13:32:00,16.284000000000002 2014-04-14 13:37:00,16.334 2014-04-14 13:42:00,17.062 2014-04-14 13:47:00,15.964 2014-04-14 13:52:00,15.962 2014-04-14 13:57:00,17.33 2014-04-14 14:02:00,16.002 2014-04-14 14:07:00,16.334 2014-04-14 14:12:00,16.336 2014-04-14 14:17:00,16.33 2014-04-14 14:22:00,17.332 2014-04-14 14:27:00,16.052 2014-04-14 14:32:00,16.336 2014-04-14 14:37:00,16.334 2014-04-14 14:42:00,16.674 2014-04-14 14:47:00,16.0 2014-04-14 14:52:00,16.668 2014-04-14 14:57:00,16.372 2014-04-14 15:02:00,16.332 2014-04-14 15:07:00,16.332 2014-04-14 15:12:00,16.336 2014-04-14 15:17:00,16.668 2014-04-14 15:22:00,16.66 2014-04-14 15:27:00,16.666 2014-04-14 15:32:00,17.334 2014-04-14 15:37:00,15.668 2014-04-14 15:42:00,17.014 2014-04-14 15:47:00,16.334 2014-04-14 15:52:00,16.336 2014-04-14 15:57:00,16.668 2014-04-14 16:02:00,16.668 2014-04-14 16:07:00,16.368 2014-04-14 16:12:00,17.69 2014-04-14 16:17:00,16.028 2014-04-14 16:22:00,16.285999999999998 2014-04-14 16:27:00,16.336 2014-04-14 16:32:00,16.656 2014-04-14 16:37:00,15.998 2014-04-14 16:42:00,16.666 2014-04-14 16:47:00,16.332 2014-04-14 16:52:00,17.334 2014-04-14 16:57:00,17.044 2014-04-14 17:02:00,15.616 2014-04-14 17:07:00,16.666 2014-04-14 17:12:00,16.334 2014-04-14 17:17:00,16.7 2014-04-14 17:22:00,16.334 2014-04-14 17:27:00,16.666 2014-04-14 17:32:00,16.332 2014-04-14 17:37:00,16.332 2014-04-14 17:42:00,16.317999999999998 2014-04-14 17:47:00,16.666 2014-04-14 17:52:00,15.68 2014-04-14 17:57:00,17.0 2014-04-14 18:02:00,16.296 2014-04-14 18:07:00,16.666 2014-04-14 18:12:00,16.0 2014-04-14 18:17:00,17.006 2014-04-14 18:22:00,16.034000000000002 2014-04-14 18:27:00,16.662 2014-04-14 18:32:00,16.0 2014-04-14 18:37:00,16.666 2014-04-14 18:42:00,16.668 2014-04-14 18:47:00,16.328 2014-04-14 18:52:00,16.332 2014-04-14 18:57:00,16.962 2014-04-14 19:02:00,15.668 2014-04-14 19:07:00,17.0 2014-04-14 19:12:00,16.666 2014-04-14 19:17:00,17.334 2014-04-14 19:22:00,15.668 2014-04-14 19:27:00,17.332 2014-04-14 19:32:00,16.332 2014-04-14 19:37:00,16.332 2014-04-14 19:42:00,17.332 2014-04-14 19:47:00,15.674000000000001 2014-04-14 19:52:00,16.668 2014-04-14 19:57:00,16.666 2014-04-14 20:02:00,16.342 2014-04-14 20:07:00,16.99 2014-04-14 20:12:00,16.666 2014-04-14 20:17:00,17.0 2014-04-14 20:22:00,16.336 2014-04-14 20:27:00,16.656 2014-04-14 20:32:00,16.018 2014-04-14 20:37:00,16.332 2014-04-14 20:42:00,16.334 2014-04-14 20:47:00,16.334 2014-04-14 20:52:00,15.668 2014-04-14 20:57:00,16.334 2014-04-14 21:02:00,16.704 2014-04-14 21:07:00,16.0 2014-04-14 21:12:00,16.65 2014-04-14 21:17:00,16.65 2014-04-14 21:22:00,17.0 2014-04-14 21:27:00,16.668 2014-04-14 21:32:00,17.332 2014-04-14 21:37:00,15.665999999999999 2014-04-14 21:42:00,17.0 2014-04-14 21:47:00,15.334000000000001 2014-04-14 21:52:00,16.002 2014-04-14 21:57:00,16.002 2014-04-14 22:02:00,16.32 2014-04-14 22:07:00,16.334 2014-04-14 22:12:00,17.0 2014-04-14 22:17:00,16.666 2014-04-14 22:22:00,16.686 2014-04-14 22:27:00,16.0 2014-04-14 22:32:00,16.0 2014-04-14 22:37:00,16.0 2014-04-14 22:42:00,16.322 2014-04-14 22:47:00,16.664 2014-04-14 22:52:00,16.336 2014-04-14 22:57:00,16.0 2014-04-14 23:02:00,16.666 2014-04-14 23:07:00,16.0 2014-04-14 23:12:00,16.65 2014-04-14 23:17:00,16.002 2014-04-14 23:22:00,16.334 2014-04-14 23:27:00,16.332 2014-04-14 23:32:00,17.0 2014-04-14 23:37:00,16.332 2014-04-14 23:42:00,16.668 2014-04-14 23:47:00,16.708 2014-04-14 23:52:00,16.666 2014-04-14 23:57:00,16.03 2014-04-15 00:02:00,15.952 2014-04-15 00:07:00,16.666 2014-04-15 00:12:00,17.0 2014-04-15 00:17:00,16.64 2014-04-15 00:22:00,16.65 2014-04-15 00:27:00,17.384 2014-04-15 00:32:00,16.002 2014-04-15 00:37:00,16.334 2014-04-15 00:42:00,16.332 2014-04-15 00:47:00,16.002 2014-04-15 00:52:00,16.305999999999994 2014-04-15 00:57:00,16.715999999999998 2014-04-15 01:02:00,15.956 2014-04-15 01:07:00,17.668 2014-04-15 01:12:00,17.334 2014-04-15 01:17:00,16.666 2014-04-15 01:22:00,15.668 2014-04-15 01:27:00,16.666 2014-04-15 01:32:00,16.668 2014-04-15 01:37:00,15.998 2014-04-15 01:42:00,16.666 2014-04-15 01:47:00,16.332 2014-04-15 01:52:00,16.334 2014-04-15 01:57:00,17.317999999999998 2014-04-15 02:02:00,16.334 2014-04-15 02:07:00,17.334 2014-04-15 02:12:00,16.666 2014-04-15 02:17:00,17.374000000000002 2014-04-15 02:22:00,16.666 2014-04-15 02:27:00,16.998 2014-04-15 02:32:00,15.718 2014-04-15 02:37:00,16.996 2014-04-15 02:42:00,16.954 2014-04-15 02:47:00,16.382 2014-04-15 02:52:00,16.328 2014-04-15 02:57:00,17.308 2014-04-15 03:02:00,16.002 2014-04-15 03:07:00,17.334 2014-04-15 03:12:00,16.668 2014-04-15 03:17:00,16.63 2014-04-15 03:22:00,18.668 2014-04-15 03:27:00,17.332 2014-04-15 03:32:00,15.665999999999999 2014-04-15 03:37:00,17.002 2014-04-15 03:42:00,16.334 2014-04-15 03:47:00,16.334 2014-04-15 03:52:00,15.99 2014-04-15 03:57:00,16.708 2014-04-15 04:02:00,16.29 2014-04-15 04:07:00,15.33 2014-04-15 04:12:00,16.336 2014-04-15 04:17:00,16.002 2014-04-15 04:22:00,16.334 2014-04-15 04:27:00,16.668 2014-04-15 04:32:00,16.666 2014-04-15 04:37:00,15.998 2014-04-15 04:42:00,16.334 2014-04-15 04:47:00,16.0 2014-04-15 04:52:00,16.34 2014-04-15 04:57:00,17.046 2014-04-15 05:02:00,16.602 2014-04-15 05:07:00,16.332 2014-04-15 05:12:00,17.332 2014-04-15 05:17:00,15.668 2014-04-15 05:22:00,17.0 2014-04-15 05:27:00,16.334 2014-04-15 05:32:00,16.334 2014-04-15 05:37:00,16.664 2014-04-15 05:42:00,16.68 2014-04-15 05:47:00,16.332 2014-04-15 05:52:00,17.018 2014-04-15 05:57:00,16.666 2014-04-15 06:02:00,16.998 2014-04-15 06:07:00,16.046 2014-04-15 06:12:00,16.616 2014-04-15 06:17:00,17.0 2014-04-15 06:22:00,16.668 2014-04-15 06:27:00,16.668 2014-04-15 06:32:00,17.0 2014-04-15 06:37:00,16.0 2014-04-15 06:42:00,17.0 2014-04-15 06:47:00,16.334 2014-04-15 06:52:00,16.334 2014-04-15 06:57:00,16.666 2014-04-15 07:02:00,16.668 2014-04-15 07:07:00,16.656 2014-04-15 07:12:00,16.666 2014-04-15 07:17:00,16.334 2014-04-15 07:22:00,16.668 2014-04-15 07:27:00,16.298 2014-04-15 07:32:00,15.984000000000002 2014-04-15 07:37:00,16.666 2014-04-15 07:42:00,16.656 2014-04-15 07:47:00,16.038 2014-04-15 07:52:00,16.622 2014-04-15 07:57:00,18.668 2014-04-15 08:02:00,16.334 2014-04-15 08:07:00,16.666 2014-04-15 08:12:00,16.334 2014-04-15 08:17:00,16.372 2014-04-15 08:22:00,16.618 2014-04-15 08:27:00,16.666 2014-04-15 08:32:00,16.336 2014-04-15 08:37:00,16.378 2014-04-15 08:42:00,16.622 2014-04-15 08:47:00,16.328 2014-04-15 08:52:00,15.668 2014-04-15 08:57:00,16.332 2014-04-15 09:02:00,16.002 2014-04-15 09:07:00,17.332 2014-04-15 09:12:00,16.05 2014-04-15 09:17:00,16.282 2014-04-15 09:22:00,15.984000000000002 2014-04-15 09:27:00,17.334 2014-04-15 09:32:00,15.716 2014-04-15 09:37:00,16.652 2014-04-15 09:42:00,16.666 2014-04-15 09:47:00,16.338 2014-04-15 09:52:00,16.666 2014-04-15 09:57:00,16.666 2014-04-15 10:02:00,16.022000000000002 2014-04-15 10:07:00,16.332 2014-04-15 10:12:00,16.656 2014-04-15 10:17:00,16.362000000000002 2014-04-15 10:22:00,16.332 2014-04-15 10:27:00,17.668 2014-04-15 10:32:00,15.674000000000001 2014-04-15 10:37:00,17.0 2014-04-15 10:42:00,16.334 2014-04-15 10:47:00,16.372 2014-04-15 10:52:00,16.0 2014-04-15 10:57:00,17.334 2014-04-15 11:02:00,16.336 2014-04-15 11:07:00,16.968 2014-04-15 11:12:00,17.0 2014-04-15 11:17:00,16.666 2014-04-15 11:22:00,16.652 2014-04-15 11:27:00,17.424 2014-04-15 11:32:00,16.285999999999998 2014-04-15 11:37:00,16.668 2014-04-15 11:42:00,16.666 2014-04-15 11:47:00,16.334 2014-04-15 11:52:00,16.668 2014-04-15 11:57:00,16.668 2014-04-15 12:02:00,16.666 2014-04-15 12:07:00,15.995999999999999 2014-04-15 12:12:00,16.336 2014-04-15 12:17:00,16.334 2014-04-15 12:22:00,16.662 2014-04-15 12:27:00,17.0 2014-04-15 12:32:00,16.002 2014-04-15 12:37:00,16.386 2014-04-15 12:42:00,16.668 2014-04-15 12:47:00,16.0 2014-04-15 12:52:00,16.666 2014-04-15 12:57:00,16.334 2014-04-15 13:02:00,17.002 2014-04-15 13:07:00,16.988 2014-04-15 13:12:00,17.018 2014-04-15 13:17:00,16.296 2014-04-15 13:22:00,17.0 2014-04-15 13:27:00,16.002 2014-04-15 13:32:00,16.666 2014-04-15 13:37:00,16.044 2014-04-15 13:42:00,16.284000000000002 2014-04-15 13:47:00,16.666 2014-04-15 13:52:00,16.666 2014-04-15 13:57:00,16.666 2014-04-15 14:02:00,17.022000000000002 2014-04-15 14:07:00,16.334 2014-04-15 14:12:00,17.334 2014-04-15 14:17:00,16.332 2014-04-15 14:22:00,16.334 2014-04-15 14:27:00,16.0 2014-04-15 14:32:00,16.002 2014-04-15 14:37:00,16.0 2014-04-15 14:42:00,17.012 2014-04-15 14:47:00,16.352 2014-04-15 14:52:00,16.668 2014-04-15 14:57:00,16.998 2014-04-15 15:02:00,15.99 2014-04-15 15:07:00,16.334 2014-04-15 15:12:00,16.332 2014-04-15 15:17:00,16.666 2014-04-15 15:22:00,16.334 2014-04-15 15:27:00,16.38 2014-04-15 15:32:00,16.666 2014-04-15 15:37:00,17.042 2014-04-15 15:42:00,17.375999999999998 2014-04-15 15:47:00,16.038 2014-04-15 15:52:00,16.285999999999998 2014-04-15 15:57:00,16.704 2014-04-15 16:02:00,17.282 2014-04-15 16:07:00,16.332 2014-04-15 16:12:00,17.002 2014-04-15 16:17:00,16.666 2014-04-15 16:22:00,17.328 2014-04-15 16:27:00,16.334 2014-04-15 16:32:00,16.336 2014-04-15 16:37:00,16.334 2014-04-15 16:42:00,16.334 2014-04-15 16:47:00,15.968 2014-04-15 16:52:00,18.0 2014-04-15 16:57:00,16.002 2014-04-15 17:02:00,16.666 2014-04-15 17:07:00,16.04 2014-04-15 17:12:00,16.336 2014-04-15 17:17:00,15.706 2014-04-15 17:22:00,16.288 2014-04-15 17:27:00,16.334 2014-04-15 17:32:00,17.334 2014-04-15 17:37:00,16.332 2014-04-15 17:42:00,16.998 2014-04-15 17:47:00,16.0 2014-04-15 17:52:00,16.336 2014-04-15 17:57:00,17.322 2014-04-15 18:02:00,16.0 2014-04-15 18:07:00,16.666 2014-04-15 18:12:00,16.308 2014-04-15 18:17:00,17.666 2014-04-15 18:22:00,16.334 2014-04-15 18:27:00,16.66 2014-04-15 18:32:00,16.334 2014-04-15 18:37:00,16.666 2014-04-15 18:42:00,16.722 2014-04-15 18:47:00,16.282 2014-04-15 18:52:00,16.656 2014-04-15 18:57:00,17.0 2014-04-15 19:02:00,16.724 2014-04-15 19:07:00,17.29 2014-04-15 19:12:00,16.334 2014-04-15 19:17:00,16.712 2014-04-15 19:22:00,16.634 2014-04-15 19:27:00,17.044 2014-04-15 19:32:00,15.952 2014-04-15 19:37:00,17.0 2014-04-15 19:42:00,15.668 2014-04-15 19:47:00,16.666 2014-04-15 19:52:00,16.0 2014-04-15 19:57:00,17.328 2014-04-15 20:02:00,16.048 2014-04-15 20:07:00,16.61 2014-04-15 20:12:00,17.332 2014-04-15 20:17:00,17.0 2014-04-15 20:22:00,16.977999999999998 2014-04-15 20:27:00,16.666 2014-04-15 20:32:00,16.0 2014-04-15 20:37:00,16.662 2014-04-15 20:42:00,16.715999999999998 2014-04-15 20:47:00,16.282 2014-04-15 20:52:00,16.002 2014-04-15 20:57:00,17.364 2014-04-15 21:02:00,16.35 2014-04-15 21:07:00,17.328 2014-04-15 21:12:00,17.02 2014-04-15 21:17:00,16.666 2014-04-15 21:22:00,16.334 2014-04-15 21:27:00,16.334 2014-04-15 21:32:00,16.348 2014-04-15 21:37:00,17.0 2014-04-15 21:42:00,17.0 2014-04-15 21:47:00,16.666 2014-04-15 21:52:00,15.985999999999999 2014-04-15 21:57:00,16.664 2014-04-15 22:02:00,16.308 2014-04-15 22:07:00,16.712 2014-04-15 22:12:00,16.998 2014-04-15 22:17:00,16.954 2014-04-15 22:22:00,16.718 2014-04-15 22:27:00,16.666 2014-04-15 22:32:00,16.336 2014-04-15 22:37:00,15.7 2014-04-15 22:42:00,17.0 2014-04-15 22:47:00,16.332 2014-04-15 22:52:00,16.666 2014-04-15 22:57:00,16.332 2014-04-15 23:02:00,16.998 2014-04-15 23:07:00,16.0 2014-04-15 23:12:00,17.0 2014-04-15 23:17:00,16.334 2014-04-15 23:22:00,17.317999999999998 2014-04-15 23:27:00,16.998 2014-04-15 23:32:00,16.668 2014-04-15 23:37:00,16.666 2014-04-15 23:42:00,16.334 2014-04-15 23:47:00,16.284000000000002 2014-04-15 23:52:00,17.0 2014-04-15 23:57:00,16.894000000000002 2014-04-16 00:02:00,17.332 2014-04-16 00:07:00,16.372 2014-04-16 00:12:00,17.278 2014-04-16 00:17:00,16.372 2014-04-16 00:22:00,16.284000000000002 2014-04-16 00:27:00,16.372 2014-04-16 00:32:00,16.668 2014-04-16 00:37:00,16.666 2014-04-16 00:42:00,15.99 2014-04-16 00:47:00,16.706 2014-04-16 00:52:00,16.622 2014-04-16 00:57:00,16.666 2014-04-16 01:02:00,16.998 2014-04-16 01:07:00,16.0 2014-04-16 01:12:00,17.668 2014-04-16 01:17:00,16.72 2014-04-16 01:22:00,16.668 2014-04-16 01:27:00,16.668 2014-04-16 01:32:00,17.332 2014-04-16 01:37:00,16.666 2014-04-16 01:42:00,16.99 2014-04-16 01:47:00,16.332 2014-04-16 01:52:00,16.336 2014-04-16 01:57:00,16.38 2014-04-16 02:02:00,16.95 2014-04-16 02:07:00,16.334 2014-04-16 02:12:00,16.684 2014-04-16 02:17:00,17.332 2014-04-16 02:22:00,16.666 2014-04-16 02:27:00,17.0 2014-04-16 02:32:00,16.944000000000006 2014-04-16 02:37:00,16.378 2014-04-16 02:42:00,16.652 2014-04-16 02:47:00,17.0 2014-04-16 02:52:00,15.668 2014-04-16 02:57:00,17.0 2014-04-16 03:02:00,16.334 2014-04-16 03:07:00,17.33 2014-04-16 03:12:00,16.666 2014-04-16 03:17:00,17.334 2014-04-16 03:22:00,16.324 2014-04-16 03:27:00,17.05 2014-04-16 03:32:00,16.284000000000002 2014-04-16 03:37:00,16.666 2014-04-16 03:42:00,16.0 2014-04-16 03:47:00,16.332 2014-04-16 03:52:00,16.317999999999998 2014-04-16 03:57:00,17.666 2014-04-16 04:02:00,15.664000000000001 2014-04-16 04:07:00,16.332 2014-04-16 04:12:00,16.334 2014-04-16 04:17:00,15.998 2014-04-16 04:22:00,15.672 2014-04-16 04:27:00,16.666 2014-04-16 04:32:00,16.0 2014-04-16 04:37:00,16.668 2014-04-16 04:42:00,15.684000000000001 2014-04-16 04:47:00,16.666 2014-04-16 04:52:00,17.648 2014-04-16 04:57:00,16.666 2014-04-16 05:02:00,16.332 2014-04-16 05:07:00,16.666 2014-04-16 05:12:00,16.0 2014-04-16 05:17:00,15.998 2014-04-16 05:22:00,16.332 2014-04-16 05:27:00,16.666 2014-04-16 05:32:00,16.334 2014-04-16 05:37:00,16.994 2014-04-16 05:42:00,16.03 2014-04-16 05:47:00,16.712 2014-04-16 05:52:00,15.934000000000001 2014-04-16 05:57:00,16.702 2014-04-16 06:02:00,16.0 2014-04-16 06:07:00,16.296 2014-04-16 06:12:00,16.998 2014-04-16 06:17:00,15.668 2014-04-16 06:22:00,16.666 2014-04-16 06:27:00,16.002 2014-04-16 06:32:00,16.666 2014-04-16 06:37:00,16.038 2014-04-16 06:42:00,16.95 2014-04-16 06:47:00,16.332 2014-04-16 06:52:00,16.666 2014-04-16 06:57:00,16.718 2014-04-16 07:02:00,16.668 2014-04-16 07:07:00,16.334 2014-04-16 07:12:00,16.334 2014-04-16 07:17:00,15.958 2014-04-16 07:22:00,16.39 2014-04-16 07:27:00,16.622 2014-04-16 07:32:00,16.668 2014-04-16 07:37:00,15.668 2014-04-16 07:42:00,17.002 2014-04-16 07:47:00,16.38 2014-04-16 07:52:00,15.952 2014-04-16 07:57:00,18.668 2014-04-16 08:02:00,16.317999999999998 2014-04-16 08:07:00,16.386 2014-04-16 08:12:00,16.668 2014-04-16 08:17:00,16.332 2014-04-16 08:22:00,16.336 2014-04-16 08:27:00,16.668 2014-04-16 08:32:00,16.312 2014-04-16 08:37:00,16.006 2014-04-16 08:42:00,17.0 2014-04-16 08:47:00,16.332 2014-04-16 08:52:00,16.39 2014-04-16 08:57:00,16.962 2014-04-16 09:02:00,16.002 2014-04-16 09:07:00,16.332 2014-04-16 09:12:00,17.33 2014-04-16 09:17:00,15.665999999999999 2014-04-16 09:22:00,16.668 2014-04-16 09:27:00,16.998 2014-04-16 09:32:00,16.002 2014-04-16 09:37:00,16.666 2014-04-16 09:42:00,16.652 2014-04-16 09:47:00,16.372 2014-04-16 09:52:00,16.002 2014-04-16 09:57:00,16.666 2014-04-16 10:02:00,16.998 2014-04-16 10:07:00,16.332 2014-04-16 10:12:00,16.332 2014-04-16 10:17:00,17.0 2014-04-16 10:22:00,16.014 2014-04-16 10:27:00,17.0 2014-04-16 10:32:00,16.666 2014-04-16 10:37:00,15.998 2014-04-16 10:42:00,16.0 2014-04-16 10:47:00,16.666 2014-04-16 10:52:00,16.332 2014-04-16 10:57:00,17.0 2014-04-16 11:02:00,16.332 2014-04-16 11:07:00,17.0 2014-04-16 11:12:00,17.334 2014-04-16 11:17:00,17.0 2014-04-16 11:22:00,16.32 2014-04-16 11:27:00,17.334 2014-04-16 11:32:00,16.002 2014-04-16 11:37:00,17.0 2014-04-16 11:42:00,17.028 2014-04-16 11:47:00,16.63 2014-04-16 11:52:00,16.668 2014-04-16 11:57:00,17.04 2014-04-16 12:02:00,15.665999999999999 2014-04-16 12:07:00,16.332 2014-04-16 12:12:00,17.0 2014-04-16 12:17:00,16.334 2014-04-16 12:22:00,17.666 2014-04-16 12:27:00,17.0 2014-04-16 12:32:00,16.336 2014-04-16 12:37:00,16.72 2014-04-16 12:42:00,16.998 2014-04-16 12:47:00,16.628 2014-04-16 12:52:00,17.0 2014-04-16 12:57:00,16.998 2014-04-16 13:02:00,16.684 2014-04-16 13:07:00,16.998 2014-04-16 13:12:00,16.312 2014-04-16 13:17:00,17.0 2014-04-16 13:22:00,17.686 2014-04-16 13:27:00,16.38 2014-04-16 13:32:00,16.285999999999998 2014-04-16 13:37:00,16.724 2014-04-16 13:42:00,17.0 2014-04-16 13:47:00,16.332 2014-04-16 13:52:00,17.0 2014-04-16 13:57:00,17.002 2014-04-16 14:02:00,17.0 2014-04-16 14:07:00,16.998 2014-04-16 14:12:00,16.668 2014-04-16 14:17:00,16.334 2014-04-16 14:22:00,16.6675 2014-04-16 14:27:00,17.5 2014-04-16 14:32:00,15.8325 2014-04-16 14:37:00,16.6625 2014-04-16 14:42:00,17.0825 2014-04-16 14:47:00,17.0825 2014-04-16 14:52:00,16.32 2014-04-16 14:57:00,17.915 2014-04-16 15:02:00,16.6675 2014-04-16 15:07:00,17.0825 2014-04-16 15:12:00,17.515 2014-04-16 15:17:00,17.5 2014-04-16 15:22:00,17.5025 2014-04-16 15:27:00,17.8 2014-04-16 15:32:00,16.25 2014-04-16 15:37:00,17.4875 2014-04-16 15:42:00,16.195 2014-04-16 15:47:00,17.5 2014-04-16 15:52:00,17.0825 2014-04-16 15:57:00,17.5 2014-04-16 16:02:00,15.8325 2014-04-16 16:07:00,17.085 2014-04-16 16:12:00,17.0825 2014-04-16 16:17:00,17.9175 2014-04-16 16:22:00,16.6675 2014-04-16 16:27:00,17.5 2014-04-16 16:32:00,17.5 2014-04-16 16:37:00,17.0775 2014-04-16 16:42:00,16.605 2014-04-16 16:47:00,17.55 2014-04-16 16:52:00,17.4975 2014-04-16 16:57:00,18.245 2014-04-16 17:02:00,17.4875 2014-04-16 17:07:00,17.9175 2014-04-16 17:12:00,16.6675 2014-04-16 17:17:00,17.5 2014-04-16 17:22:00,16.2525 2014-04-16 17:27:00,17.02 2014-04-16 17:32:00,17.435 2014-04-16 17:37:00,16.665 2014-04-16 17:42:00,17.085 2014-04-16 17:47:00,19.085 2014-04-16 17:52:00,17.0825 2014-04-16 17:57:00,17.0825 2014-04-16 18:02:00,16.6675 2014-04-16 18:07:00,17.5 2014-04-16 18:12:00,16.6675 2014-04-16 18:17:00,17.0825 2014-04-16 18:22:00,16.27 2014-04-16 18:27:00,18.2625 2014-04-16 18:32:00,15.925 2014-04-16 18:37:00,17.605 2014-04-16 18:42:00,17.0975 2014-04-16 18:47:00,17.02 2014-04-16 18:52:00,17.0825 2014-04-16 18:57:00,17.5 2014-04-16 19:02:00,16.2525 2014-04-16 19:07:00,17.5 2014-04-16 19:12:00,17.5475 2014-04-16 19:17:00,17.495 2014-04-16 19:22:00,16.2525 2014-04-16 19:27:00,17.96 2014-04-16 19:32:00,16.225 2014-04-16 19:37:00,16.765 2014-04-16 19:42:00,16.6525 2014-04-16 19:47:00,16.665 2014-04-16 19:52:00,16.2525 2014-04-16 19:57:00,18.3325 2014-04-16 20:02:00,16.2525 2014-04-16 20:07:00,17.5 2014-04-16 20:12:00,17.08 2014-04-16 20:17:00,17.5 2014-04-16 20:22:00,17.5 2014-04-16 20:27:00,17.915 2014-04-16 20:32:00,16.2525 2014-04-16 20:37:00,17.085 2014-04-16 20:42:00,17.0825 2014-04-16 20:47:00,17.195 2014-04-16 20:52:00,16.25 2014-04-16 20:57:00,17.5 2014-04-16 21:02:00,15.8325 2014-04-16 21:07:00,17.0825 2014-04-16 21:12:00,17.91 2014-04-16 21:17:00,17.5 2014-04-16 21:22:00,16.25 2014-04-16 21:27:00,17.9175 2014-04-16 21:32:00,16.25 2014-04-16 21:37:00,16.7725 2014-04-16 21:42:00,17.0825 2014-04-16 21:47:00,17.0375 2014-04-16 21:52:00,16.6675 2014-04-16 21:57:00,17.9175 2014-04-16 22:02:00,15.835 2014-04-16 22:07:00,17.8 2014-04-16 22:12:00,17.9375 2014-04-16 22:17:00,17.5 2014-04-16 22:22:00,17.905 2014-04-16 22:27:00,17.4975 2014-04-16 22:32:00,16.6675 2014-04-16 22:37:00,17.5025 2014-04-16 22:42:00,16.25 2014-04-16 22:47:00,17.0825 2014-04-16 22:52:00,16.67 2014-04-16 22:57:00,18.3325 2014-04-16 23:02:00,16.25 2014-04-16 23:07:00,16.6275 2014-04-16 23:12:00,17.0825 2014-04-16 23:17:00,17.5 2014-04-16 23:22:00,16.25 2014-04-16 23:27:00,17.5 2014-04-16 23:32:00,16.6675 2014-04-16 23:37:00,17.5 2014-04-16 23:42:00,17.9225 2014-04-16 23:47:00,16.71 2014-04-16 23:52:00,16.67 2014-04-16 23:57:00,17.8275 2014-04-17 00:02:00,16.665 2014-04-17 00:07:00,18.335 2014-04-17 00:12:00,17.0825 2014-04-17 00:17:00,18.385 2014-04-17 00:22:00,16.23 2014-04-17 00:27:00,17.4975 2014-04-17 00:32:00,16.655 2014-04-17 00:37:00,17.4975 2014-04-17 00:42:00,16.6675 2014-04-17 00:47:00,16.6675 2014-04-17 00:52:00,16.665 2014-04-17 00:57:00,17.5025 2014-04-17 01:02:00,16.2525 2014-04-17 01:07:00,17.085 2014-04-17 01:12:00,17.5025 2014-04-17 01:17:00,17.5025 2014-04-17 01:22:00,16.6675 2014-04-17 01:27:00,18.3325 2014-04-17 01:32:00,16.665 2014-04-17 01:37:00,17.4975 2014-04-17 01:42:00,17.59 2014-04-17 01:47:00,17.0825 2014-04-17 01:52:00,16.6675 2014-04-17 01:57:00,18.3325 2014-04-17 02:02:00,16.34 2014-04-17 02:07:00,17.085 2014-04-17 02:12:00,16.6675 2014-04-17 02:17:00,17.5 2014-04-17 02:22:00,16.6675 2014-04-17 02:27:00,18.335 2014-04-17 02:32:00,17.0825 2014-04-17 02:37:00,17.5 2014-04-17 02:42:00,17.0825 2014-04-17 02:47:00,17.0275 2014-04-17 02:52:00,16.6675 2014-04-17 02:57:00,18.33 2014-04-17 03:02:00,16.2675 2014-04-17 03:07:00,17.0375 2014-04-17 03:12:00,17.5 2014-04-17 03:17:00,16.3825 2014-04-17 03:22:00,15.835 2014-04-17 03:27:00,17.085 2014-04-17 03:32:00,17.4575 2014-04-17 03:37:00,17.5 2014-04-17 03:42:00,17.05 2014-04-17 03:47:00,18.335 2014-04-17 03:52:00,15.8075 2014-04-17 03:57:00,17.4875 2014-04-17 04:02:00,16.35 2014-04-17 04:07:00,16.665 2014-04-17 04:12:00,16.665 2014-04-17 04:17:00,17.02 2014-04-17 04:22:00,16.6675 2014-04-17 04:27:00,17.89 2014-04-17 04:32:00,16.2675 2014-04-17 04:37:00,17.5 2014-04-17 04:42:00,16.2525 2014-04-17 04:47:00,16.66 2014-04-17 04:52:00,16.19 2014-04-17 04:57:00,17.515 2014-04-17 05:02:00,16.9925 2014-04-17 05:07:00,17.1875 2014-04-17 05:12:00,16.665 2014-04-17 05:17:00,17.5 2014-04-17 05:22:00,16.25 2014-04-17 05:27:00,16.61 2014-04-17 05:32:00,17.085 2014-04-17 05:37:00,17.5 2014-04-17 05:42:00,16.6675 2014-04-17 05:47:00,17.8775 2014-04-17 05:52:00,15.7775 2014-04-17 05:57:00,17.5 2014-04-17 06:02:00,17.9175 2014-04-17 06:07:00,17.5075 2014-04-17 06:12:00,17.5 2014-04-17 06:17:00,17.03 2014-04-17 06:22:00,16.6875 2014-04-17 06:27:00,17.5025 2014-04-17 06:32:00,16.25 2014-04-17 06:37:00,17.48 2014-04-17 06:42:00,16.25 2014-04-17 06:47:00,17.0825 2014-04-17 06:52:00,17.5225 2014-04-17 06:57:00,17.5 2014-04-17 07:02:00,17.0925 2014-04-17 07:07:00,16.6675 2014-04-17 07:12:00,17.0825 2014-04-17 07:17:00,17.555 2014-04-17 07:22:00,17.0825 2014-04-17 07:27:00,17.915 2014-04-17 07:32:00,16.275 2014-04-17 07:37:00,17.9175 2014-04-17 07:42:00,16.7575 2014-04-17 07:47:00,17.0275 2014-04-17 07:52:00,16.665 2014-04-17 07:57:00,19.16 2014-04-17 08:02:00,16.675 2014-04-17 08:07:00,17.5 2014-04-17 08:12:00,17.175 2014-04-17 08:17:00,17.085 2014-04-17 08:22:00,15.8275 2014-04-17 08:27:00,18.335 2014-04-17 08:32:00,16.6675 2014-04-17 08:37:00,16.6675 2014-04-17 08:42:00,17.1725 2014-04-17 08:47:00,17.0825 2014-04-17 08:52:00,16.6675 2014-04-17 08:57:00,17.5 2014-04-17 09:02:00,17.0275 2014-04-17 09:07:00,17.0825 2014-04-17 09:12:00,16.6675 2014-04-17 09:17:00,17.4925 2014-04-17 09:22:00,15.7925 2014-04-17 09:27:00,17.5 2014-04-17 09:32:00,16.25 2014-04-17 09:37:00,17.5 2014-04-17 09:42:00,16.25 2014-04-17 09:47:00,17.0825 2014-04-17 09:52:00,16.2675 2014-04-17 09:57:00,17.9175 2014-04-17 10:02:00,16.25 2014-04-17 10:07:00,17.0825 2014-04-17 10:12:00,17.4975 2014-04-17 10:17:00,17.085 2014-04-17 10:22:00,16.6675 2014-04-17 10:27:00,17.4375 2014-04-17 10:32:00,16.6675 2014-04-17 10:37:00,17.9175 2014-04-17 10:42:00,16.25 2014-04-17 10:47:00,16.6675 2014-04-17 10:52:00,16.665 2014-04-17 10:57:00,17.915 2014-04-17 11:02:00,16.6675 2014-04-17 11:07:00,18.3325 2014-04-17 11:12:00,16.665 2014-04-17 11:17:00,17.0275 2014-04-17 11:22:00,16.6675 2014-04-17 11:27:00,17.1875 2014-04-17 11:32:00,16.665 2014-04-17 11:37:00,17.445 2014-04-17 11:42:00,17.0825 2014-04-17 11:47:00,17.9175 2014-04-17 11:52:00,16.665 2014-04-17 11:57:00,17.915 2014-04-17 12:02:00,16.6675 2014-04-17 12:07:00,17.5 2014-04-17 12:12:00,18.3325 2014-04-17 12:17:00,17.0375 2014-04-17 12:22:00,16.6675 2014-04-17 12:27:00,17.4975 2014-04-17 12:32:00,16.6675 2014-04-17 12:37:00,17.5 2014-04-17 12:42:00,16.2525 2014-04-17 12:47:00,16.665 2014-04-17 12:52:00,15.835 2014-04-17 12:57:00,18.335 2014-04-17 13:02:00,16.6675 2014-04-17 13:07:00,17.0825 2014-04-17 13:12:00,16.64 2014-04-17 13:17:00,18.335 2014-04-17 13:22:00,16.6675 2014-04-17 13:27:00,17.5 2014-04-17 13:32:00,16.6675 2014-04-17 13:37:00,17.085 2014-04-17 13:42:00,16.2375 2014-04-17 13:47:00,17.0425 2014-04-17 13:52:00,16.6675 2014-04-17 13:57:00,17.5 2014-04-17 14:02:00,17.0825 2014-04-17 14:07:00,17.9175 2014-04-17 14:12:00,16.25 2014-04-17 14:17:00,17.0825 2014-04-17 14:22:00,17.0825 2014-04-17 14:27:00,17.5 2014-04-17 14:32:00,17.0825 2014-04-17 14:37:00,17.0825 2014-04-17 14:42:00,16.2525 2014-04-17 14:47:00,17.0825 2014-04-17 14:52:00,16.2525 2014-04-17 14:57:00,17.5 2014-04-17 15:02:00,16.665 2014-04-17 15:07:00,17.0775 2014-04-17 15:12:00,17.0825 2014-04-17 15:17:00,18.335 2014-04-17 15:22:00,16.6675 2014-04-17 15:27:00,18.03 2014-04-17 15:32:00,17.0825 2014-04-17 15:37:00,16.665 2014-04-17 15:42:00,17.0825 2014-04-17 15:47:00,17.5 2014-04-17 15:52:00,15.835 2014-04-17 15:57:00,18.3325 2014-04-17 16:02:00,16.6675 2014-04-17 16:07:00,17.085 2014-04-17 16:12:00,17.085 2014-04-17 16:17:00,17.085 2014-04-17 16:22:00,16.665 2014-04-17 16:27:00,17.87 2014-04-17 16:32:00,16.6675 2014-04-17 16:37:00,16.6675 2014-04-17 16:42:00,17.0825 2014-04-17 16:47:00,16.66 2014-04-17 16:52:00,16.5975 2014-04-17 16:57:00,17.91 2014-04-17 17:02:00,16.665 2014-04-17 17:07:00,18.0075 2014-04-17 17:12:00,17.0825 2014-04-17 17:17:00,16.6625 2014-04-17 17:22:00,16.6675 2014-04-17 17:27:00,18.3325 2014-04-17 17:32:00,16.25 2014-04-17 17:37:00,17.0825 2014-04-17 17:42:00,16.25 2014-04-17 17:47:00,17.9175 2014-04-17 17:52:00,16.2675 2014-04-17 17:57:00,18.3325 2014-04-17 18:02:00,17.065 2014-04-17 18:07:00,17.0825 2014-04-17 18:12:00,17.915 2014-04-17 18:17:00,17.5 2014-04-17 18:22:00,17.1825 2014-04-17 18:27:00,17.5 2014-04-17 18:32:00,17.0825 2014-04-17 18:37:00,16.57 2014-04-17 18:42:00,16.6825 2014-04-17 18:47:00,18.7475 2014-04-17 18:52:00,16.25 2014-04-17 18:57:00,17.9175 2014-04-17 19:02:00,16.665 2014-04-17 19:07:00,17.235 2014-04-17 19:12:00,17.915 2014-04-17 19:17:00,17.9175 2014-04-17 19:22:00,16.6675 2014-04-17 19:27:00,17.5 2014-04-17 19:32:00,17.0825 2014-04-17 19:37:00,16.665 2014-04-17 19:42:00,16.6675 2014-04-17 19:47:00,17.0425 2014-04-17 19:52:00,17.08 2014-04-17 19:57:00,17.4975 2014-04-17 20:02:00,17.0825 2014-04-17 20:07:00,18.34 2014-04-17 20:12:00,17.0825 2014-04-17 20:17:00,17.0825 2014-04-17 20:22:00,16.3425 2014-04-17 20:27:00,17.5025 2014-04-17 20:32:00,16.6525 2014-04-17 20:37:00,17.495 2014-04-17 20:42:00,17.0825 2014-04-17 20:47:00,16.6275 2014-04-17 20:52:00,16.6675 2014-04-17 20:57:00,18.275 2014-04-17 21:02:00,16.665 2014-04-17 21:07:00,18.75 2014-04-17 21:12:00,17.4975 2014-04-17 21:17:00,18.3325 2014-04-17 21:22:00,17.0825 2014-04-17 21:27:00,18.335 2014-04-17 21:32:00,16.6825 2014-04-17 21:37:00,17.5 2014-04-17 21:42:00,17.4375 2014-04-17 21:47:00,17.5 2014-04-17 21:52:00,16.25 2014-04-17 21:57:00,18.3325 2014-04-17 22:02:00,16.6675 2014-04-17 22:07:00,17.0825 2014-04-17 22:12:00,16.6675 2014-04-17 22:17:00,16.6675 2014-04-17 22:22:00,17.175 2014-04-17 22:27:00,17.0825 2014-04-17 22:32:00,17.0825 2014-04-17 22:37:00,17.9225 2014-04-17 22:42:00,17.56 2014-04-17 22:47:00,17.925 2014-04-17 22:52:00,17.5 2014-04-17 22:57:00,17.5025 2014-04-17 23:02:00,16.6675 2014-04-17 23:07:00,18.015 2014-04-17 23:12:00,17.085 2014-04-17 23:17:00,18.2175 2014-04-17 23:22:00,16.6675 2014-04-17 23:27:00,17.915 2014-04-17 23:32:00,17.0825 2014-04-17 23:37:00,17.085 2014-04-17 23:42:00,17.0825 2014-04-17 23:47:00,16.6675 2014-04-17 23:52:00,16.26 2014-04-17 23:57:00,18.06 2014-04-18 00:02:00,16.25 2014-04-18 00:07:00,18.3325 2014-04-18 00:12:00,17.0825 2014-04-18 00:17:00,17.5 2014-04-18 00:22:00,16.6675 2014-04-18 00:27:00,17.915 2014-04-18 00:32:00,16.2525 2014-04-18 00:37:00,17.5 2014-04-18 00:42:00,16.25 2014-04-18 00:47:00,17.0825 2014-04-18 00:52:00,17.0825 2014-04-18 00:57:00,17.5025 2014-04-18 01:02:00,17.0825 2014-04-18 01:07:00,18.335 2014-04-18 01:12:00,18.2875 2014-04-18 01:17:00,17.5 2014-04-18 01:22:00,16.6675 2014-04-18 01:27:00,17.4875 2014-04-18 01:32:00,16.6675 2014-04-18 01:37:00,17.0825 2014-04-18 01:42:00,17.4975 2014-04-18 01:47:00,16.665 2014-04-18 01:52:00,16.25 2014-04-18 01:57:00,18.295 2014-04-18 02:02:00,16.665 2014-04-18 02:07:00,17.0825 2014-04-18 02:12:00,17.0825 2014-04-18 02:17:00,17.5 2014-04-18 02:22:00,17.5075 2014-04-18 02:27:00,17.915 2014-04-18 02:32:00,16.665 2014-04-18 02:37:00,17.9175 2014-04-18 02:42:00,16.6675 2014-04-18 02:47:00,17.5 2014-04-18 02:52:00,17.0475 2014-04-18 02:57:00,17.4975 2014-04-18 03:02:00,17.0825 2014-04-18 03:07:00,17.535 2014-04-18 03:12:00,17.9175 2014-04-18 03:17:00,17.5 2014-04-18 03:22:00,17.515 2014-04-18 03:27:00,17.5 2014-04-18 03:32:00,16.2525 2014-04-18 03:37:00,17.9175 2014-04-18 03:42:00,17.0825 2014-04-18 03:47:00,17.0825 2014-04-18 03:52:00,17.4975 2014-04-18 03:57:00,17.0775 2014-04-18 04:02:00,16.6675 2014-04-18 04:07:00,17.3975 2014-04-18 04:12:00,16.665 2014-04-18 04:17:00,17.5 2014-04-18 04:22:00,16.2525 2014-04-18 04:27:00,17.96 2014-04-18 04:32:00,16.25 2014-04-18 04:37:00,17.9175 2014-04-18 04:42:00,16.665 2014-04-18 04:47:00,17.0825 2014-04-18 04:52:00,17.0825 2014-04-18 04:57:00,17.5 2014-04-18 05:02:00,16.25 2014-04-18 05:07:00,17.0825 2014-04-18 05:12:00,17.0825 2014-04-18 05:17:00,17.5025 2014-04-18 05:22:00,16.665 2014-04-18 05:27:00,17.915 2014-04-18 05:32:00,16.675 2014-04-18 05:37:00,17.5 2014-04-18 05:42:00,16.665 2014-04-18 05:47:00,17.5 2014-04-18 05:52:00,16.6675 2014-04-18 05:57:00,17.5025 2014-04-18 06:02:00,17.09 2014-04-18 06:07:00,17.485 2014-04-18 06:12:00,17.0825 2014-04-18 06:17:00,17.915 2014-04-18 06:22:00,16.2525 2014-04-18 06:27:00,17.5 2014-04-18 06:32:00,17.0625 2014-04-18 06:37:00,17.085 2014-04-18 06:42:00,17.0975 2014-04-18 06:47:00,16.665 2014-04-18 06:52:00,16.2525 2014-04-18 06:57:00,17.915 2014-04-18 07:02:00,16.25 2014-04-18 07:07:00,17.5 2014-04-18 07:12:00,17.4825 2014-04-18 07:17:00,17.035 2014-04-18 07:22:00,15.835 2014-04-18 07:27:00,17.4875 2014-04-18 07:32:00,17.0825 2014-04-18 07:37:00,16.6675 2014-04-18 07:42:00,17.6 2014-04-18 07:47:00,16.71 2014-04-18 07:52:00,17.0825 2014-04-18 07:57:00,20.0 2014-04-18 08:02:00,17.085 2014-04-18 08:07:00,17.915 2014-04-18 08:12:00,16.6675 2014-04-18 08:17:00,17.8625 2014-04-18 08:22:00,16.6675 2014-04-18 08:27:00,17.5 2014-04-18 08:32:00,17.08 2014-04-18 08:37:00,16.665 2014-04-18 08:42:00,17.085 2014-04-18 08:47:00,17.5 2014-04-18 08:52:00,16.19 2014-04-18 08:57:00,17.4625 2014-04-18 09:02:00,16.6675 2014-04-18 09:07:00,17.085 2014-04-18 09:12:00,16.6675 2014-04-18 09:17:00,17.5 2014-04-18 09:22:00,16.26 2014-04-18 09:27:00,17.9175 2014-04-18 09:32:00,16.25 2014-04-18 09:37:00,17.32 2014-04-18 09:42:00,17.0975 2014-04-18 09:47:00,17.5025 2014-04-18 09:52:00,16.6825 2014-04-18 09:57:00,17.9175 2014-04-18 10:02:00,16.655 2014-04-18 10:07:00,17.0375 2014-04-18 10:12:00,17.915 2014-04-18 10:17:00,17.5 2014-04-18 10:22:00,16.6825 2014-04-18 10:27:00,17.5025 2014-04-18 10:32:00,17.0825 2014-04-18 10:37:00,17.915 2014-04-18 10:42:00,17.62 2014-04-18 10:47:00,17.085 2014-04-18 10:52:00,16.6675 2014-04-18 10:57:00,17.9175 2014-04-18 11:02:00,16.2525 2014-04-18 11:07:00,18.3325 2014-04-18 11:12:00,16.6675 2014-04-18 11:17:00,17.0825 2014-04-18 11:22:00,16.6675 2014-04-18 11:27:00,17.5025 2014-04-18 11:32:00,16.6675 2014-04-18 11:37:00,17.9175 2014-04-18 11:42:00,16.7575 2014-04-18 11:47:00,17.5 2014-04-18 11:52:00,16.34 2014-04-18 11:57:00,18.33 2014-04-18 12:02:00,16.19 2014-04-18 12:07:00,17.8025 2014-04-18 12:12:00,17.08 2014-04-18 12:17:00,17.1825 2014-04-18 12:22:00,16.25 2014-04-18 12:27:00,18.3325 2014-04-18 12:32:00,16.2525 2014-04-18 12:37:00,17.085 2014-04-18 12:42:00,16.665 2014-04-18 12:47:00,16.625 2014-04-18 12:52:00,17.0825 2014-04-18 12:57:00,17.5 2014-04-18 13:02:00,15.835 2014-04-18 13:07:00,17.5 2014-04-18 13:12:00,16.2525 2014-04-18 13:17:00,17.5575 2014-04-18 13:22:00,17.0825 2014-04-18 13:27:00,17.8525 2014-04-18 13:32:00,15.8325 2014-04-18 13:37:00,17.145 2014-04-18 13:42:00,17.0825 2014-04-18 13:47:00,16.665 2014-04-18 13:52:00,17.0825 2014-04-18 13:57:00,17.9175 2014-04-18 14:02:00,16.2525 2014-04-18 14:07:00,17.5 2014-04-18 14:12:00,17.0825 2014-04-18 14:17:00,17.5 2014-04-18 14:22:00,17.085 2014-04-18 14:27:00,17.91 2014-04-18 14:32:00,16.25 2014-04-18 14:37:00,17.5 2014-04-18 14:42:00,16.665 2014-04-18 14:47:00,17.0825 2014-04-18 14:52:00,16.665 2014-04-18 14:57:00,17.915 2014-04-18 15:02:00,16.25 2014-04-18 15:07:00,16.665 2014-04-18 15:12:00,16.6675 2014-04-18 15:17:00,17.915 2014-04-18 15:22:00,17.0825 2014-04-18 15:27:00,17.445 2014-04-18 15:32:00,16.2325 2014-04-18 15:37:00,17.5925 2014-04-18 15:42:00,16.25 2014-04-18 15:47:00,17.0825 2014-04-18 15:52:00,17.0825 2014-04-18 15:57:00,17.1975 2014-04-18 16:02:00,16.665 2014-04-18 16:07:00,16.6675 2014-04-18 16:12:00,17.08 2014-04-18 16:17:00,16.25 2014-04-18 16:22:00,17.5 2014-04-18 16:27:00,17.5 2014-04-18 16:32:00,16.2525 2014-04-18 16:37:00,17.085 2014-04-18 16:42:00,16.61 2014-04-18 16:47:00,17.0825 2014-04-18 16:52:00,16.665 2014-04-18 16:57:00,17.5 2014-04-18 17:02:00,17.5 2014-04-18 17:07:00,17.915 2014-04-18 17:12:00,17.0825 2014-04-18 17:17:00,17.9175 2014-04-18 17:22:00,16.2475 2014-04-18 17:27:00,17.085 2014-04-18 17:32:00,16.25 2014-04-18 17:37:00,17.5 2014-04-18 17:42:00,17.1875 2014-04-18 17:47:00,17.0825 2014-04-18 17:52:00,17.5 2014-04-18 17:57:00,17.19 2014-04-18 18:02:00,17.5225 2014-04-18 18:07:00,18.3325 2014-04-18 18:12:00,16.6675 2014-04-18 18:17:00,16.25 2014-04-18 18:22:00,16.25 2014-04-18 18:27:00,18.035 2014-04-18 18:32:00,16.6675 2014-04-18 18:37:00,17.4525 2014-04-18 18:42:00,16.2525 2014-04-18 18:47:00,17.0825 2014-04-18 18:52:00,16.2525 2014-04-18 18:57:00,17.0725 2014-04-18 19:02:00,17.0275 2014-04-18 19:07:00,16.6675 2014-04-18 19:12:00,16.64 2014-04-18 19:17:00,17.5 2014-04-18 19:22:00,17.0975 2014-04-18 19:27:00,17.855 2014-04-18 19:32:00,16.25 2014-04-18 19:37:00,16.665 2014-04-18 19:42:00,16.6675 2014-04-18 19:47:00,17.0825 2014-04-18 19:52:00,16.23 2014-04-18 19:57:00,19.2575 2014-04-18 20:02:00,16.2525 2014-04-18 20:07:00,17.9175 2014-04-18 20:12:00,17.085 2014-04-18 20:17:00,17.145 2014-04-18 20:22:00,17.085 2014-04-18 20:27:00,17.9175 2014-04-18 20:32:00,16.34 2014-04-18 20:37:00,17.5 2014-04-18 20:42:00,17.0825 2014-04-18 20:47:00,17.0825 2014-04-18 20:52:00,17.0825 2014-04-18 20:57:00,17.5 2014-04-18 21:02:00,16.6825 2014-04-18 21:07:00,17.5 2014-04-18 21:12:00,16.665 2014-04-18 21:17:00,17.5 2014-04-18 21:22:00,16.2325 2014-04-18 21:27:00,18.335 2014-04-18 21:32:00,16.665 2014-04-18 21:37:00,17.09 2014-04-18 21:42:00,17.4375 2014-04-18 21:47:00,17.0825 2014-04-18 21:52:00,16.7575 2014-04-18 21:57:00,17.4375 2014-04-18 22:02:00,15.845 2014-04-18 22:07:00,17.925 2014-04-18 22:12:00,16.25 2014-04-18 22:17:00,17.5 2014-04-18 22:22:00,17.045 2014-04-18 22:27:00,18.3325 2014-04-18 22:32:00,17.0825 2014-04-18 22:37:00,17.5 2014-04-18 22:42:00,16.6125 2014-04-18 22:47:00,17.085 2014-04-18 22:52:00,15.835 2014-04-18 22:57:00,17.5025 2014-04-18 23:02:00,17.0825 2014-04-18 23:07:00,17.915 2014-04-18 23:12:00,17.085 2014-04-18 23:17:00,18.33 2014-04-18 23:22:00,16.25 2014-04-18 23:27:00,25.11 2014-04-18 23:32:00,26.665 2014-04-18 23:37:00,27.405 2014-04-18 23:42:00,28.475 2014-04-18 23:47:00,27.9175 2014-04-18 23:52:00,27.085 2014-04-18 23:57:00,29.73 2014-04-19 00:02:00,27.5 2014-04-19 00:07:00,28.75 2014-04-19 00:12:00,28.75 2014-04-19 00:17:00,29.165 2014-04-19 00:22:00,26.665 2014-04-19 00:27:00,27.4975 2014-04-19 00:32:00,28.3325 2014-04-19 00:37:00,27.0825 2014-04-19 00:42:00,27.635 2014-04-19 00:47:00,27.6525 2014-04-19 00:52:00,27.4975 2014-04-19 00:57:00,27.5 2014-04-19 01:02:00,27.9175 2014-04-19 01:07:00,27.92 2014-04-19 01:12:00,29.225 2014-04-19 01:17:00,28.75 2014-04-19 01:22:00,29.1675 2014-04-19 01:27:00,28.3325 2014-04-19 01:32:00,28.3325 2014-04-19 01:37:00,27.9175 2014-04-19 01:42:00,27.0825 2014-04-19 01:47:00,27.045 2014-04-19 01:52:00,27.5 2014-04-19 01:57:00,27.4975 2014-04-19 02:02:00,27.0475 2014-04-19 02:07:00,27.9175 2014-04-19 02:12:00,26.6675 2014-04-19 02:17:00,29.5875 2014-04-19 02:22:00,27.5 2014-04-19 02:27:00,28.75 2014-04-19 02:32:00,28.875 2014-04-19 02:37:00,27.0825 2014-04-19 02:42:00,27.915 2014-04-19 02:47:00,28.32 2014-04-19 02:52:00,26.25 2014-04-19 02:57:00,28.335 2014-04-19 03:02:00,26.64 2014-04-19 03:07:00,27.085 2014-04-19 03:12:00,26.225 2014-04-19 03:17:00,28.7475 2014-04-19 03:22:00,27.88 2014-04-19 03:27:00,28.7525 2014-04-19 03:32:00,28.75 2014-04-19 03:37:00,28.75 2014-04-19 03:42:00,28.3325 2014-04-19 03:47:00,28.3325 2014-04-19 03:52:00,26.39 2014-04-19 03:57:00,29.1225 2014-04-19 04:02:00,27.5 2014-04-19 04:07:00,25.9725 2014-04-19 04:12:00,27.085 2014-04-19 04:17:00,27.24 2014-04-19 04:22:00,27.085 2014-04-19 04:27:00,27.5 2014-04-19 04:32:00,27.5 2014-04-19 04:37:00,26.6425 2014-04-19 04:42:00,26.2475 2014-04-19 04:47:00,27.0825 2014-04-19 04:52:00,26.25 2014-04-19 04:57:00,28.75 2014-04-19 05:02:00,27.3975 2014-04-19 05:07:00,27.9175 2014-04-19 05:12:00,28.3325 2014-04-19 05:17:00,27.9175 2014-04-19 05:22:00,28.05 2014-04-19 05:27:00,28.33 2014-04-19 05:32:00,26.6675 2014-04-19 05:37:00,27.9125 2014-04-19 05:42:00,26.665 2014-04-19 05:47:00,27.9175 2014-04-19 05:52:00,27.0925 2014-04-19 05:57:00,29.585 2014-04-19 06:02:00,27.225 2014-04-19 06:07:00,28.335 2014-04-19 06:12:00,26.6675 2014-04-19 06:17:00,29.5825 2014-04-19 06:22:00,27.6425 2014-04-19 06:27:00,29.585 2014-04-19 06:32:00,26.665 2014-04-19 06:37:00,28.33 2014-04-19 06:42:00,28.2325 2014-04-19 06:47:00,27.0825 2014-04-19 06:52:00,27.0825 2014-04-19 06:57:00,27.8675 2014-04-19 07:02:00,26.2525 2014-04-19 07:07:00,27.5 2014-04-19 07:12:00,28.3325 2014-04-19 07:17:00,27.4425 2014-04-19 07:22:00,26.6475 2014-04-19 07:27:00,27.9175 2014-04-19 07:32:00,26.2475 2014-04-19 07:37:00,28.3325 2014-04-19 07:42:00,27.4975 2014-04-19 07:47:00,27.5 2014-04-19 07:52:00,28.335 2014-04-19 07:57:00,28.7525 2014-04-19 08:02:00,27.0825 2014-04-19 08:07:00,26.6675 2014-04-19 08:12:00,28.75 2014-04-19 08:17:00,30.0025 2014-04-19 08:22:00,28.335 2014-04-19 08:27:00,29.22 2014-04-19 08:32:00,27.4975 2014-04-19 08:37:00,29.165 2014-04-19 08:42:00,27.065 2014-04-19 08:47:00,28.75 2014-04-19 08:52:00,28.3325 2014-04-19 08:57:00,28.3275 2014-04-19 09:02:00,27.605 2014-04-19 09:07:00,27.9175 2014-04-19 09:12:00,28.75 2014-04-19 09:17:00,28.6475 2014-04-19 09:22:00,26.6675 2014-04-19 09:27:00,27.5025 2014-04-19 09:32:00,28.3325 2014-04-19 09:37:00,28.8475 2014-04-19 09:42:00,26.7725 2014-04-19 09:47:00,29.5825 2014-04-19 09:52:00,26.6675 2014-04-19 09:57:00,27.8925 2014-04-19 10:02:00,27.0825 2014-04-19 10:07:00,29.165 2014-04-19 10:12:00,27.915 2014-04-19 10:17:00,27.915 2014-04-19 10:22:00,28.3325 2014-04-19 10:27:00,28.3325 2014-04-19 10:32:00,27.915 2014-04-19 10:37:00,27.0825 2014-04-19 10:42:00,28.3325 2014-04-19 10:47:00,28.3325 2014-04-19 10:52:00,27.0825 2014-04-19 10:57:00,28.335 2014-04-19 11:02:00,27.5 2014-04-19 11:07:00,28.7475 2014-04-19 11:12:00,28.8625 2014-04-19 11:17:00,29.27 2014-04-19 11:22:00,27.0825 2014-04-19 11:27:00,28.7475 2014-04-19 11:32:00,28.75 2014-04-19 11:37:00,28.3325 2014-04-19 11:42:00,27.9175 2014-04-19 11:47:00,28.75 2014-04-19 11:52:00,27.085 2014-04-19 11:57:00,28.75 2014-04-19 12:02:00,27.915 2014-04-19 12:07:00,27.96 2014-04-19 12:12:00,28.335 2014-04-19 12:17:00,27.915 2014-04-19 12:22:00,27.915 2014-04-19 12:27:00,30.0 2014-04-19 12:32:00,25.835 2014-04-19 12:37:00,27.4975 2014-04-19 12:42:00,28.7275 2014-04-19 12:47:00,27.0825 2014-04-19 12:52:00,27.0825 2014-04-19 12:57:00,29.165 2014-04-19 13:02:00,26.665 2014-04-19 13:07:00,28.75 2014-04-19 13:12:00,26.7975 2014-04-19 13:17:00,28.335 2014-04-19 13:22:00,27.085 2014-04-19 13:27:00,27.47 2014-04-19 13:32:00,28.3325 2014-04-19 13:37:00,28.335 2014-04-19 13:42:00,27.5025 2014-04-19 13:47:00,28.335 2014-04-19 13:52:00,26.2525 2014-04-19 13:57:00,29.1675 2014-04-19 14:02:00,27.0825 2014-04-19 14:07:00,27.9175 2014-04-19 14:12:00,29.1675 2014-04-19 14:17:00,28.7525 2014-04-19 14:22:00,27.5025 2014-04-19 14:27:00,27.915 2014-04-19 14:32:00,26.565 2014-04-19 14:37:00,28.7525 2014-04-19 14:42:00,27.435 2014-04-19 14:47:00,28.3325 2014-04-19 14:52:00,28.3325 2014-04-19 14:57:00,27.5025 2014-04-19 15:02:00,28.7475 2014-04-19 15:07:00,28.75 2014-04-19 15:12:00,27.915 2014-04-19 15:17:00,29.9975 2014-04-19 15:22:00,27.0825 2014-04-19 15:27:00,27.915 2014-04-19 15:32:00,27.915 2014-04-19 15:37:00,27.9175 2014-04-19 15:42:00,27.5 2014-04-19 15:47:00,27.4975 2014-04-19 15:52:00,27.4975 2014-04-19 15:57:00,27.085 2014-04-19 16:02:00,27.915 2014-04-19 16:07:00,27.655 2014-04-19 16:12:00,28.3325 2014-04-19 16:17:00,29.5825 2014-04-19 16:22:00,27.915 2014-04-19 16:27:00,28.91 2014-04-19 16:32:00,26.6675 2014-04-19 16:37:00,28.75 2014-04-19 16:42:00,27.88 2014-04-19 16:47:00,27.5 2014-04-19 16:52:00,27.5 2014-04-19 16:57:00,28.75 2014-04-19 17:02:00,26.6775 2014-04-19 17:07:00,27.455 2014-04-19 17:12:00,28.75 2014-04-19 17:17:00,28.335 2014-04-19 17:22:00,27.4975 2014-04-19 17:27:00,29.5725 2014-04-19 17:32:00,25.8325 2014-04-19 17:37:00,27.0725 2014-04-19 17:42:00,27.4975 2014-04-19 17:47:00,28.65 2014-04-19 17:52:00,27.9175 2014-04-19 17:57:00,27.88 2014-04-19 18:02:00,28.23 2014-04-19 18:07:00,27.9175 2014-04-19 18:12:00,27.6425 2014-04-19 18:17:00,29.585 2014-04-19 18:22:00,27.6575 2014-04-19 18:27:00,30.1025 2014-04-19 18:32:00,27.6475 2014-04-19 18:37:00,27.5 2014-04-19 18:42:00,28.76 2014-04-19 18:47:00,28.495 2014-04-19 18:52:00,26.225 2014-04-19 18:57:00,29.1675 2014-04-19 19:02:00,27.9 2014-04-19 19:07:00,28.2975 2014-04-19 19:12:00,29.4825 2014-04-19 19:17:00,28.38 2014-04-19 19:22:00,29.165 2014-04-19 19:27:00,28.3225 2014-04-19 19:32:00,26.6675 2014-04-19 19:37:00,28.76 2014-04-19 19:42:00,26.6675 2014-04-19 19:47:00,27.905 2014-04-19 19:52:00,26.25 2014-04-19 19:57:00,28.75 2014-04-19 20:02:00,26.5625 2014-04-19 20:07:00,28.75 2014-04-19 20:12:00,27.915 2014-04-19 20:17:00,27.6425 2014-04-19 20:22:00,27.5 2014-04-19 20:27:00,28.335 2014-04-19 20:32:00,26.98 2014-04-19 20:37:00,28.225 2014-04-19 20:42:00,27.0825 2014-04-19 20:47:00,27.9175 2014-04-19 20:52:00,27.4975 2014-04-19 20:57:00,28.3325 2014-04-19 21:02:00,27.5 2014-04-19 21:07:00,31.5225 2014-04-19 21:12:00,28.4375 2014-04-19 21:17:00,29.1675 2014-04-19 21:22:00,27.915 2014-04-19 21:27:00,29.3225 2014-04-19 21:32:00,28.335 2014-04-19 21:37:00,27.0825 2014-04-19 21:42:00,28.3325 2014-04-19 21:47:00,27.9175 2014-04-19 21:52:00,26.25 2014-04-19 21:57:00,27.5 2014-04-19 22:02:00,27.38 2014-04-19 22:07:00,29.1675 2014-04-19 22:12:00,27.915 2014-04-19 22:17:00,29.89 2014-04-19 22:22:00,27.0825 2014-04-19 22:27:00,27.5 2014-04-19 22:32:00,27.64 2014-04-19 22:37:00,27.915 2014-04-19 22:42:00,27.5 2014-04-19 22:47:00,28.7525 2014-04-19 22:52:00,27.4575 2014-04-19 22:57:00,27.4975 2014-04-19 23:02:00,28.0575 2014-04-19 23:07:00,29.585 2014-04-19 23:12:00,29.1675 2014-04-19 23:17:00,27.92 2014-04-19 23:22:00,27.9175 2014-04-19 23:27:00,27.5025 2014-04-19 23:32:00,27.0825 2014-04-19 23:37:00,27.9175 2014-04-19 23:42:00,27.215 2014-04-19 23:47:00,27.9175 2014-04-19 23:52:00,27.9175 2014-04-19 23:57:00,28.685 2014-04-20 00:02:00,27.0675 2014-04-20 00:07:00,28.335 2014-04-20 00:12:00,27.915 2014-04-20 00:17:00,28.75 2014-04-20 00:22:00,27.5 2014-04-20 00:27:00,29.5825 2014-04-20 00:32:00,27.085 2014-04-20 00:37:00,28.485 2014-04-20 00:42:00,27.8125 2014-04-20 00:47:00,27.9125 2014-04-20 00:52:00,28.75 2014-04-20 00:57:00,28.3325 2014-04-20 01:02:00,26.665 2014-04-20 01:07:00,28.7525 2014-04-20 01:12:00,29.1675 2014-04-20 01:17:00,28.69 2014-04-20 01:22:00,28.3325 2014-04-20 01:27:00,28.49 2014-04-20 01:32:00,27.5 2014-04-20 01:37:00,27.8225 2014-04-20 01:42:00,28.315 2014-04-20 01:47:00,27.9175 2014-04-20 01:52:00,27.085 2014-04-20 01:57:00,29.3225 2014-04-20 02:02:00,27.5 2014-04-20 02:07:00,28.7525 2014-04-20 02:12:00,27.3975 2014-04-20 02:17:00,29.1675 2014-04-20 02:22:00,27.915 2014-04-20 02:27:00,28.4875 2014-04-20 02:32:00,29.1675 2014-04-20 02:37:00,28.3325 2014-04-20 02:42:00,27.0825 2014-04-20 02:47:00,27.49 2014-04-20 02:52:00,28.0575 2014-04-20 02:57:00,27.92 2014-04-20 03:02:00,27.0675 2014-04-20 03:07:00,30.7625 2014-04-20 03:12:00,28.7675 2014-04-20 03:17:00,28.74 2014-04-20 03:22:00,28.365 2014-04-20 03:27:00,28.75 2014-04-20 03:32:00,29.1775 2014-04-20 03:37:00,27.82 2014-04-20 03:42:00,30.12 2014-04-20 03:47:00,30.0675 2014-04-20 03:52:00,28.3325 2014-04-20 03:57:00,30.0 2014-04-20 04:02:00,26.6575 2014-04-20 04:07:00,30.0 2014-04-20 04:12:00,27.5 2014-04-20 04:17:00,28.75 2014-04-20 04:22:00,27.915 2014-04-20 04:27:00,28.75 2014-04-20 04:32:00,27.915 2014-04-20 04:37:00,29.1675 2014-04-20 04:42:00,27.9075 2014-04-20 04:47:00,28.75 2014-04-20 04:52:00,27.4975 2014-04-20 04:57:00,28.75 2014-04-20 05:02:00,28.75 2014-04-20 05:07:00,27.5 2014-04-20 05:12:00,27.4975 2014-04-20 05:17:00,28.7525 2014-04-20 05:22:00,26.6675 2014-04-20 05:27:00,29.1225 2014-04-20 05:32:00,27.4975 2014-04-20 05:37:00,27.5 2014-04-20 05:42:00,28.75 2014-04-20 05:47:00,28.335 2014-04-20 05:52:00,27.4975 2014-04-20 05:57:00,29.1675 2014-04-20 06:02:00,26.98 2014-04-20 06:07:00,28.7525 2014-04-20 06:12:00,28.75 2014-04-20 06:17:00,28.49 2014-04-20 06:22:00,27.085 2014-04-20 06:27:00,29.4675 2014-04-20 06:32:00,27.0825 2014-04-20 06:37:00,28.445 2014-04-20 06:42:00,28.365 2014-04-20 06:47:00,27.9175 2014-04-20 06:52:00,27.895 2014-04-20 06:57:00,29.6225 2014-04-20 07:02:00,27.9 2014-04-20 07:07:00,28.335 2014-04-20 07:12:00,27.0925 2014-04-20 07:17:00,27.2325 2014-04-20 07:22:00,27.915 2014-04-20 07:27:00,27.5 2014-04-20 07:32:00,28.3325 2014-04-20 07:37:00,27.5 2014-04-20 07:42:00,27.925 2014-04-20 07:47:00,27.9175 2014-04-20 07:52:00,27.0675 2014-04-20 07:57:00,32.5 2014-04-20 08:02:00,27.5 2014-04-20 08:07:00,27.9175 2014-04-20 08:12:00,28.75 2014-04-20 08:17:00,28.38 2014-04-20 08:22:00,27.915 2014-04-20 08:27:00,28.4875 2014-04-20 08:32:00,27.365 2014-04-20 08:37:00,28.335 2014-04-20 08:42:00,29.1675 2014-04-20 08:47:00,28.175 2014-04-20 08:52:00,27.9175 2014-04-20 08:57:00,28.8325 2014-04-20 09:02:00,27.375 2014-04-20 09:07:00,27.9175 2014-04-20 09:12:00,28.645 2014-04-20 09:17:00,27.5025 2014-04-20 09:22:00,27.5 2014-04-20 09:27:00,29.165 2014-04-20 09:32:00,27.9175 2014-04-20 09:37:00,28.335 2014-04-20 09:42:00,27.4975 2014-04-20 09:47:00,27.9175 2014-04-20 09:52:00,27.9175 2014-04-20 09:57:00,27.915 2014-04-20 10:02:00,28.365 2014-04-20 10:07:00,26.63 2014-04-20 10:12:00,28.75 2014-04-20 10:17:00,27.9175 2014-04-20 10:22:00,27.4975 2014-04-20 10:27:00,27.9625 2014-04-20 10:32:00,28.475 2014-04-20 10:37:00,28.335 2014-04-20 10:42:00,27.915 2014-04-20 10:47:00,28.7475 2014-04-20 10:52:00,27.5 2014-04-20 10:57:00,28.7475 2014-04-20 11:02:00,27.53 2014-04-20 11:07:00,28.3325 2014-04-20 11:12:00,28.3325 2014-04-20 11:17:00,29.1675 2014-04-20 11:22:00,27.0575 2014-04-20 11:27:00,29.1675 2014-04-20 11:32:00,28.005 2014-04-20 11:37:00,27.45 2014-04-20 11:42:00,28.2375 2014-04-20 11:47:00,27.5025 2014-04-20 11:52:00,27.5025 2014-04-20 11:57:00,29.1625 2014-04-20 12:02:00,27.915 2014-04-20 12:07:00,27.5025 2014-04-20 12:12:00,27.2225 2014-04-20 12:17:00,28.7525 2014-04-20 12:22:00,27.08 2014-04-20 12:27:00,27.5 2014-04-20 12:32:00,27.5 2014-04-20 12:37:00,28.75 2014-04-20 12:42:00,27.5075 2014-04-20 12:47:00,28.75 2014-04-20 12:52:00,27.5075 2014-04-20 12:57:00,28.75 2014-04-20 13:02:00,27.0825 2014-04-20 13:07:00,27.645 2014-04-20 13:12:00,28.3325 2014-04-20 13:17:00,27.9175 2014-04-20 13:22:00,28.05 2014-04-20 13:27:00,27.915 2014-04-20 13:32:00,26.6675 2014-04-20 13:37:00,28.7525 2014-04-20 13:42:00,27.5 2014-04-20 13:47:00,27.5 2014-04-20 13:52:00,27.9175 2014-04-20 13:57:00,27.915 2014-04-20 14:02:00,28.475 2014-04-20 14:07:00,29.155 2014-04-20 14:12:00,27.0825 2014-04-20 14:17:00,28.335 2014-04-20 14:22:00,28.335 2014-04-20 14:27:00,27.5 2014-04-20 14:32:00,27.915 2014-04-20 14:37:00,27.9175 2014-04-20 14:42:00,27.915 2014-04-20 14:47:00,27.5 2014-04-20 14:52:00,27.5 2014-04-20 14:57:00,29.1675 2014-04-20 15:02:00,26.665 2014-04-20 15:07:00,29.1675 2014-04-20 15:12:00,28.295 2014-04-20 15:17:00,27.9175 2014-04-20 15:22:00,27.5 2014-04-20 15:27:00,30.4175 2014-04-20 15:32:00,27.5 2014-04-20 15:37:00,28.7525 2014-04-20 15:42:00,29.1675 2014-04-20 15:47:00,28.75 2014-04-20 15:52:00,28.2 2014-04-20 15:57:00,28.715 2014-04-20 16:02:00,28.75 2014-04-20 16:07:00,27.9125 2014-04-20 16:12:00,28.7525 2014-04-20 16:17:00,29.1625 2014-04-20 16:22:00,27.5 2014-04-20 16:27:00,29.1675 2014-04-20 16:32:00,27.915 2014-04-20 16:37:00,29.33 2014-04-20 16:42:00,27.6425 2014-04-20 16:47:00,28.3375 2014-04-20 16:52:00,27.5025 2014-04-20 16:57:00,29.165 2014-04-20 17:02:00,28.1925 2014-04-20 17:07:00,29.58 2014-04-20 17:12:00,28.3325 2014-04-20 17:17:00,27.9175 2014-04-20 17:22:00,27.08 2014-04-20 17:27:00,28.7475 2014-04-20 17:32:00,28.3325 2014-04-20 17:37:00,27.59 2014-04-20 17:42:00,28.3325 2014-04-20 17:47:00,27.445 2014-04-20 17:52:00,27.5 2014-04-20 17:57:00,28.3325 2014-04-20 18:02:00,28.75 2014-04-20 18:07:00,29.1675 2014-04-20 18:12:00,29.1675 2014-04-20 18:17:00,27.9175 2014-04-20 18:22:00,27.0825 2014-04-20 18:27:00,29.215 2014-04-20 18:32:00,26.8 2014-04-20 18:37:00,28.4275 2014-04-20 18:42:00,28.3325 2014-04-20 18:47:00,28.3225 2014-04-20 18:52:00,27.5025 2014-04-20 18:57:00,29.165 2014-04-20 19:02:00,27.4825 2014-04-20 19:07:00,29.9975 2014-04-20 19:12:00,27.5 2014-04-20 19:17:00,27.915 2014-04-20 19:22:00,28.3325 2014-04-20 19:27:00,27.815 2014-04-20 19:32:00,27.5 2014-04-20 19:37:00,27.5 2014-04-20 19:42:00,28.3325 2014-04-20 19:47:00,27.5 2014-04-20 19:52:00,27.085 2014-04-20 19:57:00,29.165 2014-04-20 20:02:00,27.915 2014-04-20 20:07:00,29.89 2014-04-20 20:12:00,27.4975 2014-04-20 20:17:00,28.335 2014-04-20 20:22:00,27.4825 2014-04-20 20:27:00,27.47 2014-04-20 20:32:00,27.94 2014-04-20 20:37:00,28.335 2014-04-20 20:42:00,27.5 2014-04-20 20:47:00,27.815 2014-04-20 20:52:00,28.8975 2014-04-20 20:57:00,29.165 2014-04-20 21:02:00,26.6675 2014-04-20 21:07:00,29.5825 2014-04-20 21:12:00,27.4975 2014-04-20 21:17:00,27.9175 2014-04-20 21:22:00,27.915 2014-04-20 21:27:00,29.42 2014-04-20 21:32:00,28.36 2014-04-20 21:37:00,28.335 2014-04-20 21:42:00,28.75 2014-04-20 21:47:00,27.6425 2014-04-20 21:52:00,27.5025 2014-04-20 21:57:00,28.75 2014-04-20 22:02:00,27.0825 2014-04-20 22:07:00,29.5825 2014-04-20 22:12:00,28.755 2014-04-20 22:17:00,28.7525 2014-04-20 22:22:00,29.165 2014-04-20 22:27:00,29.745 2014-04-20 22:32:00,27.4975 2014-04-20 22:37:00,29.1675 2014-04-20 22:42:00,27.4975 2014-04-20 22:47:00,27.9175 2014-04-20 22:52:00,28.3325 2014-04-20 22:57:00,28.49 2014-04-20 23:02:00,27.9175 2014-04-20 23:07:00,26.6675 2014-04-20 23:12:00,27.4975 2014-04-20 23:17:00,28.3325 2014-04-20 23:22:00,28.3225 2014-04-20 23:27:00,28.7525 2014-04-20 23:32:00,27.0825 2014-04-20 23:37:00,27.0825 2014-04-20 23:42:00,28.3325 2014-04-20 23:47:00,27.5 2014-04-20 23:52:00,28.3325 2014-04-20 23:57:00,29.045 2014-04-21 00:02:00,26.565 2014-04-21 00:07:00,29.8325 2014-04-21 00:12:00,28.3325 2014-04-21 00:17:00,28.3325 2014-04-21 00:22:00,27.5 2014-04-21 00:27:00,27.9175 2014-04-21 00:32:00,27.925 2014-04-21 00:37:00,27.5 2014-04-21 00:42:00,28.725 2014-04-21 00:47:00,28.7475 2014-04-21 00:52:00,26.67 2014-04-21 00:57:00,29.5825 2014-04-21 01:02:00,27.0825 2014-04-21 01:07:00,27.9175 2014-04-21 01:12:00,29.5825 2014-04-21 01:17:00,27.915 2014-04-21 01:22:00,26.635 2014-04-21 01:27:00,29.5825 2014-04-21 01:32:00,30.0025 2014-04-21 01:37:00,27.915 2014-04-21 01:42:00,28.3325 2014-04-21 01:47:00,27.915 2014-04-21 01:52:00,27.5 2014-04-21 01:57:00,28.7475 2014-04-21 02:02:00,26.7725 2014-04-21 02:07:00,27.6475 2014-04-21 02:12:00,28.3325 2014-04-21 02:17:00,27.5 2014-04-21 02:22:00,28.75 2014-04-21 02:27:00,29.3225 2014-04-21 02:32:00,29.585 2014-04-21 02:37:00,28.335 2014-04-21 02:42:00,28.06 2014-04-21 02:47:00,28.3325 2014-04-21 02:52:00,27.085 2014-04-21 02:57:00,29.155 2014-04-21 03:02:00,27.4825 2014-04-21 03:07:00,27.9175 2014-04-21 03:12:00,28.3325 2014-04-21 03:17:00,27.8075 2014-04-21 03:22:00,28.3325 2014-04-21 03:27:00,28.7675 2014-04-21 03:32:00,27.915 2014-04-21 03:37:00,28.8575 2014-04-21 03:42:00,27.5 2014-04-21 03:47:00,27.9175 2014-04-21 03:52:00,28.75 2014-04-21 03:57:00,28.75 2014-04-21 04:02:00,28.335 2014-04-21 04:07:00,28.75 2014-04-21 04:12:00,27.4975 2014-04-21 04:17:00,28.335 2014-04-21 04:22:00,27.485 2014-04-21 04:27:00,30.0525 2014-04-21 04:32:00,27.4975 2014-04-21 04:37:00,29.1675 2014-04-21 04:42:00,27.885 2014-04-21 04:47:00,27.9175 2014-04-21 04:52:00,28.3325 2014-04-21 04:57:00,28.3325 2014-04-21 05:02:00,27.4775 2014-04-21 05:07:00,29.165 2014-04-21 05:12:00,27.4975 2014-04-21 05:17:00,29.1675 2014-04-21 05:22:00,27.645 2014-04-21 05:27:00,27.5 2014-04-21 05:32:00,27.5 2014-04-21 05:37:00,29.07 2014-04-21 05:42:00,28.3325 2014-04-21 05:47:00,29.17 2014-04-21 05:52:00,27.5 2014-04-21 05:57:00,28.3325 2014-04-21 06:02:00,27.08 2014-04-21 06:07:00,27.6425 2014-04-21 06:12:00,27.4975 2014-04-21 06:17:00,28.3325 2014-04-21 06:22:00,27.49 2014-04-21 06:27:00,28.07 2014-04-21 06:32:00,27.9175 2014-04-21 06:37:00,27.9175 2014-04-21 06:42:00,27.5175 2014-04-21 06:47:00,29.165 2014-04-21 06:52:00,27.0925 2014-04-21 06:57:00,29.0575 2014-04-21 07:02:00,28.3325 2014-04-21 07:07:00,27.5 2014-04-21 07:12:00,28.75 2014-04-21 07:17:00,27.5 2014-04-21 07:22:00,27.1975 2014-04-21 07:27:00,28.75 2014-04-21 07:32:00,27.5 2014-04-21 07:37:00,27.915 2014-04-21 07:42:00,28.7475 2014-04-21 07:47:00,27.9175 2014-04-21 07:52:00,28.295 2014-04-21 07:57:00,28.75 2014-04-21 08:02:00,26.8 2014-04-21 08:07:00,28.3325 2014-04-21 08:12:00,28.475 2014-04-21 08:17:00,27.0825 2014-04-21 08:22:00,27.915 2014-04-21 08:27:00,29.065 2014-04-21 08:32:00,27.2175 2014-04-21 08:37:00,28.2875 2014-04-21 08:42:00,28.64 2014-04-21 08:47:00,27.9175 2014-04-21 08:52:00,28.3325 2014-04-21 08:57:00,27.915 2014-04-21 09:02:00,26.6675 2014-04-21 09:07:00,27.0425 2014-04-21 09:12:00,27.4875 2014-04-21 09:17:00,27.0875 2014-04-21 09:22:00,27.0825 2014-04-21 09:27:00,29.99 2014-04-21 09:32:00,26.6675 2014-04-21 09:37:00,28.275 2014-04-21 09:42:00,28.335 2014-04-21 09:47:00,27.085 2014-04-21 09:52:00,27.1875 2014-04-21 09:57:00,29.5825 2014-04-21 10:02:00,28.3575 2014-04-21 10:07:00,28.7225 2014-04-21 10:12:00,29.585 2014-04-21 10:17:00,27.9175 2014-04-21 10:22:00,27.485 2014-04-21 10:27:00,29.585 2014-04-21 10:32:00,27.8075 2014-04-21 10:37:00,27.0825 2014-04-21 10:42:00,28.7525 2014-04-21 10:47:00,27.5 2014-04-21 10:52:00,27.5 2014-04-21 10:57:00,28.335 2014-04-21 11:02:00,26.25 2014-04-21 11:07:00,27.495 2014-04-21 11:12:00,27.64 2014-04-21 11:17:00,29.1675 2014-04-21 11:22:00,28.19 2014-04-21 11:27:00,28.7525 2014-04-21 11:32:00,27.915 2014-04-21 11:37:00,28.75 2014-04-21 11:42:00,27.5 2014-04-21 11:47:00,28.6475 2014-04-21 11:52:00,27.5 2014-04-21 11:57:00,29.1675 2014-04-21 12:02:00,27.47 2014-04-21 12:07:00,28.345 2014-04-21 12:12:00,29.165 2014-04-21 12:17:00,27.0825 2014-04-21 12:22:00,27.9125 2014-04-21 12:27:00,28.3325 2014-04-21 12:32:00,27.0825 2014-04-21 12:37:00,29.575 2014-04-21 12:42:00,28.0575 2014-04-21 12:47:00,27.9175 2014-04-21 12:52:00,25.8325 2014-04-21 12:57:00,28.72 2014-04-21 13:02:00,28.3325 2014-04-21 13:07:00,27.9175 2014-04-21 13:12:00,28.75 2014-04-21 13:17:00,27.5 2014-04-21 13:22:00,27.4975 2014-04-21 13:27:00,29.1625 2014-04-21 13:32:00,27.0825 2014-04-21 13:37:00,28.8975 2014-04-21 13:42:00,27.5 2014-04-21 13:47:00,27.5 2014-04-21 13:52:00,28.335 2014-04-21 13:57:00,29.5825 2014-04-21 14:02:00,27.1 2014-04-21 14:07:00,29.615 2014-04-21 14:12:00,28.3325 2014-04-21 14:17:00,27.9075 2014-04-21 14:22:00,27.915 2014-04-21 14:27:00,28.75 2014-04-21 14:32:00,27.915 2014-04-21 14:37:00,30.0 2014-04-21 14:42:00,27.085 2014-04-21 14:47:00,28.3325 2014-04-21 14:52:00,27.39 2014-04-21 14:57:00,28.3325 2014-04-21 15:02:00,27.0825 2014-04-21 15:07:00,29.5925 2014-04-21 15:12:00,27.5 2014-04-21 15:17:00,28.7475 2014-04-21 15:22:00,27.47 2014-04-21 15:27:00,28.335 2014-04-21 15:32:00,27.4975 2014-04-21 15:37:00,27.9175 2014-04-21 15:42:00,28.335 2014-04-21 15:47:00,28.75 2014-04-21 15:52:00,27.085 2014-04-21 15:57:00,29.1675 2014-04-21 16:02:00,27.0825 2014-04-21 16:07:00,28.75 2014-04-21 16:12:00,28.335 2014-04-21 16:17:00,27.5 2014-04-21 16:22:00,27.5025 2014-04-21 16:27:00,28.75 2014-04-21 16:32:00,27.94 2014-04-21 16:37:00,28.75 2014-04-21 16:42:00,29.1675 2014-04-21 16:47:00,27.5 2014-04-21 16:52:00,27.5 2014-04-21 16:57:00,29.5825 2014-04-21 17:02:00,27.4975 2014-04-21 17:07:00,28.7525 2014-04-21 17:12:00,27.4975 2014-04-21 17:17:00,27.4975 2014-04-21 17:22:00,27.4975 2014-04-21 17:27:00,28.3325 2014-04-21 17:32:00,28.75 2014-04-21 17:37:00,28.01 2014-04-21 17:42:00,27.5 2014-04-21 17:47:00,26.6575 2014-04-21 17:52:00,28.0475 2014-04-21 17:57:00,29.07 2014-04-21 18:02:00,27.0675 2014-04-21 18:07:00,28.71 2014-04-21 18:12:00,28.6 2014-04-21 18:17:00,29.1675 2014-04-21 18:22:00,28.75 2014-04-21 18:27:00,28.49 2014-04-21 18:32:00,27.9175 2014-04-21 18:37:00,27.455 2014-04-21 18:42:00,27.5025 2014-04-21 18:47:00,28.7475 2014-04-21 18:52:00,26.6425 2014-04-21 18:57:00,28.365 2014-04-21 19:02:00,27.9175 2014-04-21 19:07:00,28.335 2014-04-21 19:12:00,29.1675 2014-04-21 19:17:00,27.4975 2014-04-21 19:22:00,27.055 2014-04-21 19:27:00,29.165 2014-04-21 19:32:00,27.08 2014-04-21 19:37:00,27.4975 2014-04-21 19:42:00,27.5 2014-04-21 19:47:00,28.3325 2014-04-21 19:52:00,27.0825 2014-04-21 19:57:00,28.75 2014-04-21 20:02:00,27.5 2014-04-21 20:07:00,27.0825 2014-04-21 20:12:00,27.5 2014-04-21 20:17:00,29.1625 2014-04-21 20:22:00,27.065 2014-04-21 20:27:00,30.12 2014-04-21 20:32:00,28.3575 2014-04-21 20:37:00,28.345 2014-04-21 20:42:00,28.3325 2014-04-21 20:47:00,28.75 2014-04-21 20:52:00,26.25 2014-04-21 20:57:00,29.1675 2014-04-21 21:02:00,27.5 2014-04-21 21:07:00,27.9275 2014-04-21 21:12:00,28.3325 2014-04-21 21:17:00,28.335 2014-04-21 21:22:00,27.9175 2014-04-21 21:27:00,28.33 2014-04-21 21:32:00,26.67 2014-04-21 21:37:00,27.9175 2014-04-21 21:42:00,27.4175 2014-04-21 21:47:00,28.3325 2014-04-21 21:52:00,26.665 2014-04-21 21:57:00,29.74 2014-04-21 22:02:00,27.0825 2014-04-21 22:07:00,27.8875 2014-04-21 22:12:00,27.2175 2014-04-21 22:17:00,28.7475 2014-04-21 22:22:00,27.9175 2014-04-21 22:27:00,29.9975 2014-04-21 22:32:00,28.79 2014-04-21 22:37:00,28.3325 2014-04-21 22:42:00,28.75 2014-04-21 22:47:00,27.5025 2014-04-21 22:52:00,27.915 2014-04-21 22:57:00,28.7475 2014-04-21 23:02:00,26.6675 2014-04-21 23:07:00,29.17 2014-04-21 23:12:00,31.7125 2014-04-21 23:17:00,28.335 2014-04-21 23:22:00,28.75 2014-04-21 23:27:00,27.5 2014-04-21 23:32:00,27.085 2014-04-21 23:37:00,28.75 2014-04-21 23:42:00,27.5 2014-04-21 23:47:00,28.3325 2014-04-21 23:52:00,28.75 2014-04-21 23:57:00,28.4875 2014-04-22 00:02:00,27.9075 2014-04-22 00:07:00,28.75 2014-04-22 00:12:00,27.5 2014-04-22 00:17:00,28.3325 2014-04-22 00:22:00,27.4825 2014-04-22 00:27:00,28.7475 2014-04-22 00:32:00,28.3325 2014-04-22 00:37:00,27.5 2014-04-22 00:42:00,27.0825 2014-04-22 00:47:00,26.6675 2014-04-22 00:52:00,27.8125 2014-04-22 00:57:00,29.1275 2014-04-22 01:02:00,29.165 2014-04-22 01:07:00,28.3325 2014-04-22 01:12:00,29.635 2014-04-22 01:17:00,29.165 2014-04-22 01:22:00,27.0825 2014-04-22 01:27:00,28.705 2014-04-22 01:32:00,27.9175 2014-04-22 01:37:00,27.5 2014-04-22 01:42:00,27.9 2014-04-22 01:47:00,28.75 2014-04-22 01:52:00,26.6675 2014-04-22 01:57:00,28.75 2014-04-22 02:02:00,25.4175 2014-04-22 02:07:00,27.5 2014-04-22 02:12:00,28.3325 2014-04-22 02:17:00,27.9175 2014-04-22 02:22:00,28.4725 2014-04-22 02:27:00,28.3325 2014-04-22 02:32:00,27.48 2014-04-22 02:37:00,29.17 2014-04-22 02:42:00,29.1675 2014-04-22 02:47:00,27.5 2014-04-22 02:52:00,26.6675 2014-04-22 02:57:00,27.9175 2014-04-22 03:02:00,27.0825 2014-04-22 03:07:00,28.75 2014-04-22 03:12:00,29.1675 2014-04-22 03:17:00,29.165 2014-04-22 03:22:00,27.9175 2014-04-22 03:27:00,27.915 2014-04-22 03:32:00,27.4975 2014-04-22 03:37:00,28.7525 2014-04-22 03:42:00,27.4975 2014-04-22 03:47:00,30.4175 2014-04-22 03:52:00,26.675 2014-04-22 03:57:00,29.9975 2014-04-22 04:02:00,27.5 2014-04-22 04:07:00,27.9175 2014-04-22 04:12:00,29.3475 2014-04-22 04:17:00,28.29 2014-04-22 04:22:00,29.1675 2014-04-22 04:27:00,28.335 2014-04-22 04:32:00,28.0575 2014-04-22 04:37:00,28.235 2014-04-22 04:42:00,26.6675 2014-04-22 04:47:00,28.745 2014-04-22 04:52:00,28.4675 2014-04-22 04:57:00,28.3325 2014-04-22 05:02:00,26.635 2014-04-22 05:07:00,28.905 2014-04-22 05:12:00,27.5075 2014-04-22 05:17:00,27.085 2014-04-22 05:22:00,28.3325 2014-04-22 05:27:00,27.915 2014-04-22 05:32:00,27.0825 2014-04-22 05:37:00,28.7475 2014-04-22 05:42:00,27.0825 2014-04-22 05:47:00,27.5 2014-04-22 05:52:00,28.335 2014-04-22 05:57:00,27.915 2014-04-22 06:02:00,27.5975 2014-04-22 06:07:00,29.165 2014-04-22 06:12:00,26.9875 2014-04-22 06:17:00,27.5 2014-04-22 06:22:00,28.345 2014-04-22 06:27:00,28.7475 2014-04-22 06:32:00,27.895 2014-04-22 06:37:00,28.3375 2014-04-22 06:42:00,27.5 2014-04-22 06:47:00,27.6475 2014-04-22 06:52:00,27.5 2014-04-22 06:57:00,28.3325 2014-04-22 07:02:00,27.085 2014-04-22 07:07:00,29.1675 2014-04-22 07:12:00,27.0925 2014-04-22 07:17:00,27.5 2014-04-22 07:22:00,27.1 2014-04-22 07:27:00,28.75 2014-04-22 07:32:00,27.0575 2014-04-22 07:37:00,27.1425 2014-04-22 07:42:00,28.3325 2014-04-22 07:47:00,27.5 2014-04-22 07:52:00,26.6675 2014-04-22 07:57:00,30.8325 2014-04-22 08:02:00,27.0725 2014-04-22 08:07:00,29.1675 2014-04-22 08:12:00,28.3175 2014-04-22 08:17:00,27.0825 2014-04-22 08:22:00,27.9175 2014-04-22 08:27:00,28.33 2014-04-22 08:32:00,25.835 2014-04-22 08:37:00,28.7525 2014-04-22 08:42:00,26.25 2014-04-22 08:47:00,27.44 2014-04-22 08:52:00,27.5 2014-04-22 08:57:00,28.75 2014-04-22 09:02:00,27.085 2014-04-22 09:07:00,28.335 2014-04-22 09:12:00,28.2325 2014-04-22 09:17:00,27.6475 2014-04-22 09:22:00,26.2475 2014-04-22 09:27:00,28.75 2014-04-22 09:32:00,27.085 2014-04-22 09:37:00,27.815 2014-04-22 09:42:00,28.335 2014-04-22 09:47:00,27.49 2014-04-22 09:52:00,28.3325 2014-04-22 09:57:00,27.9175 2014-04-22 10:02:00,28.3325 2014-04-22 10:07:00,27.9175 2014-04-22 10:12:00,28.3325 2014-04-22 10:17:00,27.5 2014-04-22 10:22:00,26.2525 2014-04-22 10:27:00,29.5825 2014-04-22 10:32:00,27.0825 2014-04-22 10:37:00,29.2725 2014-04-22 10:42:00,28.75 2014-04-22 10:47:00,27.5 2014-04-22 10:52:00,27.4575 2014-04-22 10:57:00,28.4925 2014-04-22 11:02:00,27.9175 2014-04-22 11:07:00,28.7475 2014-04-22 11:12:00,30.0 2014-04-22 11:17:00,28.335 2014-04-22 11:22:00,28.75 2014-04-22 11:27:00,21.245 2014-04-22 11:32:00,18.3325 2014-04-22 11:37:00,17.5 2014-04-22 11:42:00,17.5 2014-04-22 11:47:00,17.9175 2014-04-22 11:52:00,16.25 2014-04-22 11:57:00,18.4375 2014-04-22 12:02:00,16.6675 2014-04-22 12:07:00,16.66 2014-04-22 12:12:00,16.25 2014-04-22 12:17:00,17.5 2014-04-22 12:22:00,17.5 2014-04-22 12:27:00,17.5 2014-04-22 12:32:00,15.835 2014-04-22 12:37:00,17.0825 2014-04-22 12:42:00,16.7725 2014-04-22 12:47:00,16.665 2014-04-22 12:52:00,16.6525 2014-04-22 12:57:00,17.5 2014-04-22 13:02:00,16.25 2014-04-22 13:07:00,17.5 2014-04-22 13:12:00,16.6675 2014-04-22 13:17:00,18.335 2014-04-22 13:22:00,16.665 2014-04-22 13:27:00,17.5 2014-04-22 13:32:00,17.0825 2014-04-22 13:37:00,17.0825 2014-04-22 13:42:00,16.6675 2014-04-22 13:47:00,17.0825 2014-04-22 13:52:00,16.6675 2014-04-22 13:57:00,18.3325 2014-04-22 14:02:00,16.2525 2014-04-22 14:07:00,17.9525 2014-04-22 14:12:00,17.4975 2014-04-22 14:17:00,17.0825 2014-04-22 14:22:00,17.0825 2014-04-22 14:27:00,17.915 2014-04-22 14:32:00,16.2525 2014-04-22 14:37:00,17.55 2014-04-22 14:42:00,17.0825 2014-04-22 14:47:00,17.0825 2014-04-22 14:52:00,15.84 2014-04-22 14:57:00,17.9025 2014-04-22 15:02:00,17.0825 2014-04-22 15:07:00,17.975 2014-04-22 15:12:00,17.0825 2014-04-22 15:17:00,17.0825 2014-04-22 15:22:00,17.0825 2014-04-22 15:27:00,17.085 2014-04-22 15:32:00,16.25 2014-04-22 15:37:00,17.9175 2014-04-22 15:42:00,16.5775 2014-04-22 15:47:00,17.035 2014-04-22 15:52:00,17.09 2014-04-22 15:57:00,17.085 2014-04-22 16:02:00,16.6675 2014-04-22 16:07:00,17.92 2014-04-22 16:12:00,17.0275 2014-04-22 16:17:00,17.8075 2014-04-22 16:22:00,16.6675 2014-04-22 16:27:00,17.5025 2014-04-22 16:32:00,16.665 2014-04-22 16:37:00,17.0825 2014-04-22 16:42:00,16.6675 2014-04-22 16:47:00,17.9175 2014-04-22 16:52:00,15.835 2014-04-22 16:57:00,17.9025 2014-04-22 17:02:00,17.065 2014-04-22 17:07:00,17.085 2014-04-22 17:12:00,16.6675 2014-04-22 17:17:00,17.0825 2014-04-22 17:22:00,16.6875 2014-04-22 17:27:00,17.9725 2014-04-22 17:32:00,17.0825 2014-04-22 17:37:00,18.39 2014-04-22 17:42:00,16.5775 2014-04-22 17:47:00,17.0825 2014-04-22 17:52:00,16.6875 2014-04-22 17:57:00,17.3925 2014-04-22 18:02:00,17.085 2014-04-22 18:07:00,16.6675 2014-04-22 18:12:00,16.6675 2014-04-22 18:17:00,17.5 2014-04-22 18:22:00,17.5 2014-04-22 18:27:00,18.33 2014-04-22 18:32:00,17.085 2014-04-22 18:37:00,18.3225 2014-04-22 18:42:00,17.0825 2014-04-22 18:47:00,17.135 2014-04-22 18:52:00,16.68 2014-04-22 18:57:00,17.5 2014-04-22 19:02:00,16.6675 2014-04-22 19:07:00,17.5 2014-04-22 19:12:00,17.0825 2014-04-22 19:17:00,17.9175 2014-04-22 19:22:00,16.665 2014-04-22 19:27:00,17.5 2014-04-22 19:32:00,17.0825 2014-04-22 19:37:00,17.9725 2014-04-22 19:42:00,17.0825 2014-04-22 19:47:00,17.9175 2014-04-22 19:52:00,16.2525 2014-04-22 19:57:00,17.915 2014-04-22 20:02:00,16.665 2014-04-22 20:07:00,17.1825 2014-04-22 20:12:00,16.25 2014-04-22 20:17:00,18.335 2014-04-22 20:22:00,16.9925 2014-04-22 20:27:00,18.335 2014-04-22 20:32:00,15.835 2014-04-22 20:37:00,17.5 2014-04-22 20:42:00,16.665 2014-04-22 20:47:00,17.5 2014-04-22 20:52:00,16.665 2014-04-22 20:57:00,17.5 2014-04-22 21:02:00,17.0825 2014-04-22 21:07:00,17.915 2014-04-22 21:12:00,17.0825 2014-04-22 21:17:00,17.9175 2014-04-22 21:22:00,16.26 2014-04-22 21:27:00,17.0825 2014-04-22 21:32:00,17.0825 2014-04-22 21:37:00,17.0825 2014-04-22 21:42:00,17.4975 2014-04-22 21:47:00,17.0825 2014-04-22 21:52:00,16.25 2014-04-22 21:57:00,18.3325 2014-04-22 22:02:00,16.2525 2014-04-22 22:07:00,17.9525 2014-04-22 22:12:00,17.0825 2014-04-22 22:17:00,17.98 2014-04-22 22:22:00,17.085 2014-04-22 22:27:00,17.915 2014-04-22 22:32:00,16.2525 2014-04-22 22:37:00,17.9175 2014-04-22 22:42:00,16.665 2014-04-22 22:47:00,17.0825 2014-04-22 22:52:00,16.25 2014-04-22 22:57:00,18.3325 2014-04-22 23:02:00,17.0825 2014-04-22 23:07:00,17.9175 2014-04-22 23:12:00,17.5 2014-04-22 23:17:00,17.9175 2014-04-22 23:22:00,15.835 2014-04-22 23:27:00,17.085 2014-04-22 23:32:00,16.6675 2014-04-22 23:37:00,17.0825 2014-04-22 23:42:00,16.665 2014-04-22 23:47:00,17.5 2014-04-22 23:52:00,16.2675 2014-04-22 23:57:00,17.91 2014-04-23 00:02:00,19.5825 2014-04-23 00:07:00,17.14 2014-04-23 00:12:00,17.915 2014-04-23 00:17:00,17.915 2014-04-23 00:22:00,15.835 2014-04-23 00:27:00,17.085 2014-04-23 00:32:00,17.0825 2014-04-23 00:37:00,17.0825 2014-04-23 00:42:00,16.25 2014-04-23 00:47:00,17.9125 2014-04-23 00:52:00,16.2525 2014-04-23 00:57:00,17.9175 2014-04-23 01:02:00,17.5 2014-04-23 01:07:00,17.0825 2014-04-23 01:12:00,18.7475 2014-04-23 01:17:00,17.5 2014-04-23 01:22:00,16.2525 2014-04-23 01:27:00,17.9175 2014-04-23 01:32:00,16.23 2014-04-23 01:37:00,17.0825 2014-04-23 01:42:00,17.0825 2014-04-23 01:47:00,16.665 2014-04-23 01:52:00,17.085 2014-04-23 01:57:00,17.085 2014-04-23 02:02:00,16.6825 2014-04-23 02:07:00,18.3325 2014-04-23 02:12:00,16.665 2014-04-23 02:17:00,17.915 2014-04-23 02:22:00,17.0825 2014-04-23 02:27:00,17.96 2014-04-23 02:32:00,16.6675 2014-04-23 02:37:00,16.665 2014-04-23 02:42:00,16.605 2014-04-23 02:47:00,17.0275 2014-04-23 02:52:00,17.08 2014-04-23 02:57:00,17.0825 2014-04-23 03:02:00,15.835 2014-04-23 03:07:00,17.5 2014-04-23 03:12:00,17.0825 2014-04-23 03:17:00,16.665 2014-04-23 03:22:00,17.0825 2014-04-23 03:27:00,17.5 2014-04-23 03:32:00,17.0825 2014-04-23 03:37:00,17.5 2014-04-23 03:42:00,17.0275 2014-04-23 03:47:00,17.9175 2014-04-23 03:52:00,16.2525 2014-04-23 03:57:00,17.915 2014-04-23 04:02:00,16.6675 2014-04-23 04:07:00,17.0825 2014-04-23 04:12:00,17.1825 2014-04-23 04:17:00,16.665 2014-04-23 04:22:00,16.25 2014-04-23 04:27:00,17.5 2014-04-23 04:32:00,15.8325 2014-04-23 04:37:00,17.0825 2014-04-23 04:42:00,16.25 2014-04-23 04:47:00,17.9175 2014-04-23 04:52:00,16.2525 2014-04-23 04:57:00,18.01 2014-04-23 05:02:00,17.105 2014-04-23 05:07:00,16.25 2014-04-23 05:12:00,17.085 2014-04-23 05:17:00,16.665 2014-04-23 05:22:00,16.69 2014-04-23 05:27:00,17.0825 2014-04-23 05:32:00,16.755 2014-04-23 05:37:00,17.0825 2014-04-23 05:42:00,16.6675 2014-04-23 05:47:00,17.5 2014-04-23 05:52:00,16.6975 2014-04-23 05:57:00,17.9175 2014-04-23 06:02:00,16.6675 2014-04-23 06:07:00,16.665 2014-04-23 06:12:00,16.6675 2014-04-23 06:17:00,17.5 2014-04-23 06:22:00,16.6675 2014-04-23 06:27:00,18.34 2014-04-23 06:32:00,16.25 2014-04-23 06:37:00,17.0825 2014-04-23 06:42:00,17.4975 2014-04-23 06:47:00,16.6675 2014-04-23 06:52:00,16.6675 2014-04-23 06:57:00,17.915 2014-04-23 07:02:00,16.6675 2014-04-23 07:07:00,17.5 2014-04-23 07:12:00,16.6675 2014-04-23 07:17:00,17.5 2014-04-23 07:22:00,16.2525 2014-04-23 07:27:00,17.945 2014-04-23 07:32:00,16.1825 2014-04-23 07:37:00,16.6675 2014-04-23 07:42:00,17.065 2014-04-23 07:47:00,17.5 2014-04-23 07:52:00,16.2525 2014-04-23 07:57:00,20.835 2014-04-23 08:02:00,16.6675 2014-04-23 08:07:00,17.085 2014-04-23 08:12:00,16.6675 2014-04-23 08:17:00,17.5025 2014-04-23 08:22:00,16.6825 2014-04-23 08:27:00,17.98 2014-04-23 08:32:00,16.665 2014-04-23 08:37:00,16.6675 2014-04-23 08:42:00,17.0825 2014-04-23 08:47:00,17.0825 2014-04-23 08:52:00,16.6975 2014-04-23 08:57:00,17.9175 2014-04-23 09:02:00,16.6675 2014-04-23 09:07:00,17.0825 2014-04-23 09:12:00,16.665 2014-04-23 09:17:00,17.1875 2014-04-23 09:22:00,16.2525 2014-04-23 09:27:00,17.0825 2014-04-23 09:32:00,16.25 2014-04-23 09:37:00,17.5 2014-04-23 09:42:00,16.265 2014-04-23 09:47:00,17.5 2014-04-23 09:52:00,16.2525 2014-04-23 09:57:00,17.9175 2014-04-23 10:02:00,16.2525 2014-04-23 10:07:00,17.9175 2014-04-23 10:12:00,16.34 2014-04-23 10:17:00,17.5 2014-04-23 10:22:00,16.6675 2014-04-23 10:27:00,17.5 2014-04-23 10:32:00,16.64 2014-04-23 10:37:00,17.0775 2014-04-23 10:42:00,16.6375 2014-04-23 10:47:00,17.9175 2014-04-23 10:52:00,16.25 2014-04-23 10:57:00,17.5025 2014-04-23 11:02:00,16.6675 2014-04-23 11:07:00,18.3325 2014-04-23 11:12:00,17.0825 2014-04-23 11:17:00,17.4975 2014-04-23 11:22:00,17.5 2014-04-23 11:27:00,17.925 2014-04-23 11:32:00,16.705 2014-04-23 11:37:00,17.5075 2014-04-23 11:42:00,17.0825 2014-04-23 11:47:00,17.8825 2014-04-23 11:52:00,16.25 2014-04-23 11:57:00,17.9175 2014-04-23 12:02:00,17.0825 2014-04-23 12:07:00,17.0825 2014-04-23 12:12:00,17.0825 2014-04-23 12:17:00,17.015 2014-04-23 12:22:00,16.6675 2014-04-23 12:27:00,17.445 2014-04-23 12:32:00,16.25 2014-04-23 12:37:00,17.9175 2014-04-23 12:42:00,18.3325 2014-04-23 12:47:00,17.5 2014-04-23 12:52:00,16.2525 2014-04-23 12:57:00,18.335 2014-04-23 13:02:00,16.6675 2014-04-23 13:07:00,17.9175 2014-04-23 13:12:00,16.26 2014-04-23 13:17:00,17.4975 2014-04-23 13:22:00,16.6675 2014-04-23 13:27:00,17.085 2014-04-23 13:32:00,16.6675 2014-04-23 13:37:00,17.0825 2014-04-23 13:42:00,16.655 2014-04-23 13:47:00,17.5875 2014-04-23 13:52:00,16.26 2014-04-23 13:57:00,17.9175 2014-04-23 14:02:00,16.605 2014-04-23 14:07:00,17.5025 2014-04-23 14:12:00,17.915 2014-04-23 14:17:00,17.5 2014-04-23 14:22:00,17.0775 2014-04-23 14:27:00,17.915 2014-04-23 14:32:00,16.2525 2014-04-23 14:37:00,17.915 2014-04-23 14:42:00,16.6825 2014-04-23 14:47:00,17.6125 2014-04-23 14:52:00,16.2525 2014-04-23 14:57:00,17.9175 2014-04-23 15:02:00,16.28 2014-04-23 15:07:00,18.335 2014-04-23 15:12:00,16.25 2014-04-23 15:17:00,17.0825 2014-04-23 15:22:00,16.23 2014-04-23 15:27:00,17.0375 2014-04-23 15:32:00,16.67 2014-04-23 15:37:00,17.4625 2014-04-23 15:42:00,16.25 2014-04-23 15:47:00,17.6125 2014-04-23 15:52:00,16.665 2014-04-23 15:57:00,17.085 2014-04-23 16:02:00,16.9925 2014-04-23 16:07:00,18.3325 2014-04-23 16:12:00,17.075 2014-04-23 16:17:00,17.9175 2014-04-23 16:22:00,16.68 2014-04-23 16:27:00,17.9175 2014-04-23 16:32:00,16.6475 2014-04-23 16:37:00,17.0825 2014-04-23 16:42:00,17.0825 2014-04-23 16:47:00,17.0825 2014-04-23 16:52:00,15.835 2014-04-23 16:57:00,17.9925 2014-04-23 17:02:00,16.6675 2014-04-23 17:07:00,17.0825 2014-04-23 17:12:00,16.25 2014-04-23 17:17:00,17.5 2014-04-23 17:22:00,15.8325 2014-04-23 17:27:00,17.9175 2014-04-23 17:32:00,16.6675 2014-04-23 17:37:00,17.0825 2014-04-23 17:42:00,16.25 2014-04-23 17:47:00,17.5 2014-04-23 17:52:00,16.2525 2014-04-23 17:57:00,17.5 2014-04-23 18:02:00,16.665 2014-04-23 18:07:00,17.0825 2014-04-23 18:12:00,17.0825 2014-04-23 18:17:00,17.8075 2014-04-23 18:22:00,16.6675 2014-04-23 18:27:00,18.3325 2014-04-23 18:32:00,16.765 2014-04-23 18:37:00,16.665 2014-04-23 18:42:00,17.0825 2014-04-23 18:47:00,17.0825 2014-04-23 18:52:00,17.085 2014-04-23 18:57:00,18.3325 2014-04-23 19:02:00,16.25 2014-04-23 19:07:00,17.5 2014-04-23 19:12:00,17.5 2014-04-23 19:17:00,17.5 2014-04-23 19:22:00,17.4975 2014-04-23 19:27:00,17.5 2014-04-23 19:32:00,16.6675 2014-04-23 19:37:00,17.6675 2014-04-23 19:42:00,16.6675 2014-04-23 19:47:00,17.5 2014-04-23 19:52:00,17.0825 2014-04-23 19:57:00,17.5 2014-04-23 20:02:00,17.07 2014-04-23 20:07:00,17.0375 2014-04-23 20:12:00,16.6675 2014-04-23 20:17:00,17.615 2014-04-23 20:22:00,16.665 2014-04-23 20:27:00,17.9175 2014-04-23 20:32:00,17.4975 2014-04-23 20:37:00,17.085 2014-04-23 20:42:00,17.0825 2014-04-23 20:47:00,17.445 2014-04-23 20:52:00,16.2525 2014-04-23 20:57:00,17.0375 2014-04-23 21:02:00,15.9225 2014-04-23 21:07:00,18.22 2014-04-23 21:12:00,16.575 2014-04-23 21:17:00,17.0825 2014-04-23 21:22:00,16.6675 2014-04-23 21:27:00,17.87 2014-04-23 21:32:00,16.25 2014-04-23 21:37:00,17.4925 2014-04-23 21:42:00,17.0825 2014-04-23 21:47:00,16.6675 2014-04-23 21:52:00,16.25 2014-04-23 21:57:00,17.085 2014-04-23 22:02:00,17.1825 2014-04-23 22:07:00,17.135 2014-04-23 22:12:00,17.5 2014-04-23 22:17:00,18.34 2014-04-23 22:22:00,16.2525 2014-04-23 22:27:00,17.9175 2014-04-23 22:32:00,16.2525 2014-04-23 22:37:00,16.665 2014-04-23 22:42:00,17.08 2014-04-23 22:47:00,17.0825 2014-04-23 22:52:00,15.8325 2014-04-23 22:57:00,17.9175 2014-04-23 23:02:00,16.6475 2014-04-23 23:07:00,17.9175 2014-04-23 23:12:00,17.08 2014-04-23 23:17:00,17.9175 2014-04-23 23:22:00,16.665 2014-04-23 23:27:00,17.605 2014-04-23 23:32:00,15.835 2014-04-23 23:37:00,17.09 2014-04-23 23:42:00,17.08 2014-04-23 23:47:00,17.0825 2014-04-23 23:52:00,16.2525 2014-04-23 23:57:00,18.005 ================================================ FILE: workspace/anomaly_detector/datasets/selected/outliers/ec2_cpu_utilization_fe7f93.csv ================================================ timestamp,value 2014-02-14 14:27:00,2.296 2014-02-14 14:32:00,2.144 2014-02-14 14:37:00,2.274 2014-02-14 14:42:00,2.066 2014-02-14 14:47:00,2.35 2014-02-14 14:52:00,2.136 2014-02-14 14:57:00,2.366 2014-02-14 15:02:00,2.252 2014-02-14 15:07:00,2.4 2014-02-14 15:12:00,2.18 2014-02-14 15:17:00,2.352 2014-02-14 15:22:00,3.4339999999999997 2014-02-14 15:27:00,2.43 2014-02-14 15:32:00,2.0340000000000003 2014-02-14 15:37:00,2.296 2014-02-14 15:42:00,2.052 2014-02-14 15:47:00,2.314 2014-02-14 15:52:00,2.07 2014-02-14 15:57:00,2.4 2014-02-14 16:02:00,2.07 2014-02-14 16:07:00,3.588 2014-02-14 16:12:00,2.1919999999999997 2014-02-14 16:17:00,2.3 2014-02-14 16:22:00,2.134 2014-02-14 16:27:00,2.2840000000000003 2014-02-14 16:32:00,2.12 2014-02-14 16:37:00,2.35 2014-02-14 16:42:00,2.166 2014-02-14 16:47:00,2.314 2014-02-14 16:52:00,2.186 2014-02-14 16:57:00,2.33 2014-02-14 17:02:00,2.108 2014-02-14 17:07:00,2.3280000000000003 2014-02-14 17:12:00,3.4339999999999997 2014-02-14 17:17:00,2.424 2014-02-14 17:22:00,2.158 2014-02-14 17:27:00,2.342 2014-02-14 17:32:00,2.056 2014-02-14 17:37:00,2.376 2014-02-14 17:42:00,2.106 2014-02-14 17:47:00,2.408 2014-02-14 17:52:00,2.156 2014-02-14 17:57:00,2.464 2014-02-14 18:02:00,2.224 2014-02-14 18:07:00,2.428 2014-02-14 18:12:00,2.234 2014-02-14 18:17:00,2.408 2014-02-14 18:22:00,3.372 2014-02-14 18:27:00,2.318 2014-02-14 18:32:00,2.166 2014-02-14 18:37:00,2.386 2014-02-14 18:42:00,2.138 2014-02-14 18:47:00,2.336 2014-02-14 18:52:00,2.23 2014-02-14 18:57:00,2.452 2014-02-14 19:02:00,2.15 2014-02-14 19:07:00,2.386 2014-02-14 19:12:00,2.234 2014-02-14 19:17:00,2.7319999999999998 2014-02-14 19:22:00,2.9160000000000004 2014-02-14 19:27:00,2.246 2014-02-14 19:32:00,2.084 2014-02-14 19:37:00,2.248 2014-02-14 19:42:00,2.096 2014-02-14 19:47:00,2.266 2014-02-14 19:52:00,2.504 2014-02-14 19:57:00,52.26600000000001 2014-02-14 20:02:00,54.806000000000004 2014-02-14 20:07:00,55.736000000000004 2014-02-14 20:12:00,11.058 2014-02-14 20:17:00,20.215999999999998 2014-02-14 20:22:00,71.306 2014-02-14 20:27:00,55.49800000000001 2014-02-14 20:32:00,25.366 2014-02-14 20:37:00,6.994 2014-02-14 20:42:00,5.034 2014-02-14 20:47:00,5.45 2014-02-14 20:52:00,5.4 2014-02-14 20:57:00,5.65 2014-02-14 21:02:00,7.992000000000001 2014-02-14 21:07:00,5.42 2014-02-14 21:12:00,7.8020000000000005 2014-02-14 21:17:00,5.666 2014-02-14 21:22:00,5.164 2014-02-14 21:27:00,7.2 2014-02-14 21:32:00,5.082 2014-02-14 21:37:00,5.546 2014-02-14 21:42:00,5.282 2014-02-14 21:47:00,5.566 2014-02-14 21:52:00,4.002 2014-02-14 21:57:00,3.512 2014-02-14 22:02:00,1.98 2014-02-14 22:07:00,2.278 2014-02-14 22:12:00,2.016 2014-02-14 22:17:00,3.5239999999999996 2014-02-14 22:22:00,2.0340000000000003 2014-02-14 22:27:00,2.25 2014-02-14 22:32:00,2.068 2014-02-14 22:37:00,2.3040000000000003 2014-02-14 22:42:00,2.092 2014-02-14 22:47:00,2.332 2014-02-14 22:52:00,2.124 2014-02-14 22:57:00,53.692 2014-02-14 23:02:00,51.466 2014-02-14 23:07:00,51.85 2014-02-14 23:12:00,5.372000000000001 2014-02-14 23:17:00,3.002 2014-02-14 23:22:00,3.984 2014-02-14 23:27:00,3.2460000000000004 2014-02-14 23:32:00,4.7 2014-02-14 23:37:00,2.864 2014-02-14 23:42:00,2.426 2014-02-14 23:47:00,3.112 2014-02-14 23:52:00,2.84 2014-02-14 23:57:00,3.0839999999999996 2014-02-15 00:02:00,3.556 2014-02-15 00:07:00,2.0340000000000003 2014-02-15 00:12:00,2.064 2014-02-15 00:17:00,3.534 2014-02-15 00:22:00,2.27 2014-02-15 00:27:00,2.292 2014-02-15 00:32:00,2.09 2014-02-15 00:37:00,2.234 2014-02-15 00:42:00,4.73 2014-02-15 00:47:00,2.634 2014-02-15 00:52:00,2.766 2014-02-15 00:57:00,2.7 2014-02-15 01:02:00,2.728 2014-02-15 01:07:00,2.616 2014-02-15 01:12:00,2.474 2014-02-15 01:17:00,3.79 2014-02-15 01:22:00,2.458 2014-02-15 01:27:00,2.4219999999999997 2014-02-15 01:32:00,2.434 2014-02-15 01:37:00,2.452 2014-02-15 01:42:00,2.2880000000000003 2014-02-15 01:47:00,2.5780000000000003 2014-02-15 01:52:00,2.396 2014-02-15 01:57:00,2.7680000000000002 2014-02-15 02:02:00,2.346 2014-02-15 02:07:00,2.464 2014-02-15 02:12:00,3.5580000000000003 2014-02-15 02:17:00,2.36 2014-02-15 02:22:00,2.2159999999999997 2014-02-15 02:27:00,2.292 2014-02-15 02:32:00,2.1519999999999997 2014-02-15 02:37:00,2.334 2014-02-15 02:42:00,2.166 2014-02-15 02:47:00,2.3680000000000003 2014-02-15 02:52:00,2.052 2014-02-15 02:57:00,2.342 2014-02-15 03:02:00,2.386 2014-02-15 03:07:00,2.318 2014-02-15 03:12:00,2.08 2014-02-15 03:17:00,2.766 2014-02-15 03:22:00,2.898 2014-02-15 03:27:00,2.2 2014-02-15 03:32:00,2.086 2014-02-15 03:37:00,2.25 2014-02-15 03:42:00,2.066 2014-02-15 03:47:00,2.168 2014-02-15 03:52:00,2.08 2014-02-15 03:57:00,2.266 2014-02-15 04:02:00,2.084 2014-02-15 04:07:00,2.218 2014-02-15 04:12:00,2.148 2014-02-15 04:17:00,3.5060000000000002 2014-02-15 04:22:00,2.182 2014-02-15 04:27:00,2.2359999999999998 2014-02-15 04:32:00,2.1319999999999997 2014-02-15 04:37:00,2.3 2014-02-15 04:42:00,2.086 2014-02-15 04:47:00,2.202 2014-02-15 04:52:00,2.064 2014-02-15 04:57:00,2.296 2014-02-15 05:02:00,2.08 2014-02-15 05:07:00,2.2640000000000002 2014-02-15 05:12:00,3.352 2014-02-15 05:17:00,2.334 2014-02-15 05:22:00,1.9980000000000002 2014-02-15 05:27:00,2.26 2014-02-15 05:32:00,1.9880000000000002 2014-02-15 05:37:00,2.184 2014-02-15 05:42:00,1.996 2014-02-15 05:47:00,2.2159999999999997 2014-02-15 05:52:00,2.0 2014-02-15 05:57:00,2.198 2014-02-15 06:02:00,1.966 2014-02-15 06:07:00,2.164 2014-02-15 06:12:00,3.298 2014-02-15 06:17:00,2.18 2014-02-15 06:22:00,1.984 2014-02-15 06:27:00,2.258 2014-02-15 06:32:00,1.952 2014-02-15 06:37:00,2.184 2014-02-15 06:42:00,1.984 2014-02-15 06:47:00,2.22 2014-02-15 06:52:00,1.9580000000000002 2014-02-15 06:57:00,2.234 2014-02-15 07:02:00,2.1319999999999997 2014-02-15 07:07:00,2.2640000000000002 2014-02-15 07:12:00,2.0 2014-02-15 07:17:00,2.218 2014-02-15 07:22:00,3.378 2014-02-15 07:27:00,2.292 2014-02-15 07:32:00,2.0780000000000003 2014-02-15 07:37:00,2.542 2014-02-15 07:42:00,2.0180000000000002 2014-02-15 07:47:00,2.144 2014-02-15 07:52:00,2.048 2014-02-15 07:57:00,2.296 2014-02-15 08:02:00,2.164 2014-02-15 08:07:00,2.366 2014-02-15 08:12:00,2.114 2014-02-15 08:17:00,3.61 2014-02-15 08:22:00,2.05 2014-02-15 08:27:00,2.376 2014-02-15 08:32:00,2.066 2014-02-15 08:37:00,2.18 2014-02-15 08:42:00,2.068 2014-02-15 08:47:00,2.214 2014-02-15 08:52:00,2.048 2014-02-15 08:57:00,2.356 2014-02-15 09:02:00,2.108 2014-02-15 09:07:00,2.3 2014-02-15 09:12:00,2.044 2014-02-15 09:17:00,2.312 2014-02-15 09:22:00,3.318 2014-02-15 09:27:00,2.258 2014-02-15 09:32:00,2.002 2014-02-15 09:37:00,2.2119999999999997 2014-02-15 09:42:00,2.044 2014-02-15 09:47:00,2.244 2014-02-15 09:52:00,2.062 2014-02-15 09:57:00,2.332 2014-02-15 10:02:00,2.05 2014-02-15 10:07:00,2.298 2014-02-15 10:12:00,3.3 2014-02-15 10:17:00,2.302 2014-02-15 10:22:00,2.036 2014-02-15 10:27:00,2.2840000000000003 2014-02-15 10:32:00,2.1519999999999997 2014-02-15 10:37:00,2.2840000000000003 2014-02-15 10:42:00,2.164 2014-02-15 10:47:00,2.25 2014-02-15 10:52:00,2.126 2014-02-15 10:57:00,2.326 2014-02-15 11:02:00,2.134 2014-02-15 11:07:00,2.316 2014-02-15 11:12:00,2.114 2014-02-15 11:17:00,3.5660000000000003 2014-02-15 11:22:00,2.11 2014-02-15 11:27:00,2.17 2014-02-15 11:32:00,1.9240000000000002 2014-02-15 11:37:00,2.1180000000000003 2014-02-15 11:42:00,2.042 2014-02-15 11:47:00,2.1719999999999997 2014-02-15 11:52:00,1.944 2014-02-15 11:57:00,2.292 2014-02-15 12:02:00,2.0 2014-02-15 12:07:00,2.17 2014-02-15 12:12:00,3.218 2014-02-15 12:17:00,2.146 2014-02-15 12:22:00,1.946 2014-02-15 12:27:00,2.158 2014-02-15 12:32:00,1.94 2014-02-15 12:37:00,2.202 2014-02-15 12:42:00,1.98 2014-02-15 12:47:00,2.194 2014-02-15 12:52:00,1.95 2014-02-15 12:57:00,2.246 2014-02-15 13:02:00,2.052 2014-02-15 13:07:00,2.266 2014-02-15 13:12:00,1.984 2014-02-15 13:17:00,3.528 2014-02-15 13:22:00,1.996 2014-02-15 13:27:00,2.214 2014-02-15 13:32:00,2.03 2014-02-15 13:37:00,2.2159999999999997 2014-02-15 13:42:00,2.0140000000000002 2014-02-15 13:47:00,2.1959999999999997 2014-02-15 13:52:00,2.064 2014-02-15 13:57:00,2.262 2014-02-15 14:02:00,2.06 2014-02-15 14:07:00,2.306 2014-02-15 14:12:00,1.982 2014-02-15 14:17:00,3.4339999999999997 2014-02-15 14:22:00,1.946 2014-02-15 14:27:00,2.1519999999999997 2014-02-15 14:32:00,1.886 2014-02-15 14:37:00,2.102 2014-02-15 14:42:00,1.93 2014-02-15 14:47:00,2.244 2014-02-15 14:52:00,1.956 2014-02-15 14:57:00,2.234 2014-02-15 15:02:00,1.994 2014-02-15 15:07:00,2.158 2014-02-15 15:12:00,1.98 2014-02-15 15:17:00,3.446 2014-02-15 15:22:00,2.0 2014-02-15 15:27:00,2.23 2014-02-15 15:32:00,1.952 2014-02-15 15:37:00,2.222 2014-02-15 15:42:00,1.974 2014-02-15 15:47:00,2.242 2014-02-15 15:52:00,1.974 2014-02-15 15:57:00,2.258 2014-02-15 16:02:00,1.9880000000000002 2014-02-15 16:07:00,2.202 2014-02-15 16:12:00,2.046 2014-02-15 16:17:00,2.244 2014-02-15 16:22:00,3.302 2014-02-15 16:27:00,2.2359999999999998 2014-02-15 16:32:00,1.942 2014-02-15 16:37:00,2.15 2014-02-15 16:42:00,2.07 2014-02-15 16:47:00,2.334 2014-02-15 16:52:00,2.01 2014-02-15 16:57:00,2.242 2014-02-15 17:02:00,1.996 2014-02-15 17:07:00,2.186 2014-02-15 17:12:00,2.002 2014-02-15 17:17:00,3.4560000000000004 2014-02-15 17:22:00,2.03 2014-02-15 17:27:00,2.2159999999999997 2014-02-15 17:32:00,2.052 2014-02-15 17:37:00,2.15 2014-02-15 17:42:00,2.048 2014-02-15 17:47:00,2.234 2014-02-15 17:52:00,2.062 2014-02-15 17:57:00,2.276 2014-02-15 18:02:00,2.0340000000000003 2014-02-15 18:07:00,2.226 2014-02-15 18:12:00,3.29 2014-02-15 18:17:00,2.218 2014-02-15 18:22:00,2.06 2014-02-15 18:27:00,2.226 2014-02-15 18:32:00,2.062 2014-02-15 18:37:00,2.3080000000000003 2014-02-15 18:42:00,2.052 2014-02-15 18:47:00,2.23 2014-02-15 18:52:00,2.066 2014-02-15 18:57:00,2.238 2014-02-15 19:02:00,2.04 2014-02-15 19:07:00,2.2 2014-02-15 19:12:00,2.064 2014-02-15 19:17:00,2.3 2014-02-15 19:22:00,3.322 2014-02-15 19:27:00,2.208 2014-02-15 19:32:00,1.922 2014-02-15 19:37:00,2.134 2014-02-15 19:42:00,1.9780000000000002 2014-02-15 19:47:00,2.158 2014-02-15 19:52:00,2.0140000000000002 2014-02-15 19:57:00,2.266 2014-02-15 20:02:00,2.18 2014-02-15 20:07:00,2.2640000000000002 2014-02-15 20:12:00,2.082 2014-02-15 20:17:00,3.64 2014-02-15 20:22:00,2.072 2014-02-15 20:27:00,2.2359999999999998 2014-02-15 20:32:00,2.1180000000000003 2014-02-15 20:37:00,2.326 2014-02-15 20:42:00,2.056 2014-02-15 20:47:00,2.2680000000000002 2014-02-15 20:52:00,2.164 2014-02-15 20:57:00,2.346 2014-02-15 21:02:00,37.134 2014-02-15 21:07:00,61.11600000000001 2014-02-15 21:12:00,52.378 2014-02-15 21:17:00,12.267999999999999 2014-02-15 21:22:00,2.802 2014-02-15 21:27:00,4.034 2014-02-15 21:32:00,3.0660000000000003 2014-02-15 21:37:00,4.794 2014-02-15 21:42:00,2.96 2014-02-15 21:47:00,2.722 2014-02-15 21:52:00,2.912 2014-02-15 21:57:00,4.3 2014-02-15 22:02:00,3.7460000000000004 2014-02-15 22:07:00,2.4459999999999997 2014-02-15 22:12:00,2.05 2014-02-15 22:17:00,3.5839999999999996 2014-02-15 22:22:00,2.116 2014-02-15 22:27:00,2.33 2014-02-15 22:32:00,2.136 2014-02-15 22:37:00,2.35 2014-02-15 22:42:00,2.2159999999999997 2014-02-15 22:47:00,2.366 2014-02-15 22:52:00,2.182 2014-02-15 22:57:00,2.362 2014-02-15 23:02:00,2.226 2014-02-15 23:07:00,3.656 2014-02-15 23:12:00,2.252 2014-02-15 23:17:00,2.3819999999999997 2014-02-15 23:22:00,2.2 2014-02-15 23:27:00,2.3819999999999997 2014-02-15 23:32:00,2.206 2014-02-15 23:37:00,2.392 2014-02-15 23:42:00,2.334 2014-02-15 23:47:00,2.316 2014-02-15 23:52:00,2.134 2014-02-15 23:57:00,2.334 2014-02-16 00:02:00,2.1180000000000003 2014-02-16 00:07:00,2.35 2014-02-16 00:12:00,2.234 2014-02-16 00:17:00,2.334 2014-02-16 00:22:00,3.5660000000000003 2014-02-16 00:27:00,2.31 2014-02-16 00:32:00,2.14 2014-02-16 00:37:00,2.36 2014-02-16 00:42:00,2.106 2014-02-16 00:47:00,2.272 2014-02-16 00:52:00,2.162 2014-02-16 00:57:00,2.412 2014-02-16 01:02:00,2.116 2014-02-16 01:07:00,2.318 2014-02-16 01:12:00,3.5260000000000002 2014-02-16 01:17:00,2.414 2014-02-16 01:22:00,2.22 2014-02-16 01:27:00,2.412 2014-02-16 01:32:00,2.12 2014-02-16 01:37:00,2.376 2014-02-16 01:42:00,2.124 2014-02-16 01:47:00,2.426 2014-02-16 01:52:00,2.2880000000000003 2014-02-16 01:57:00,2.318 2014-02-16 02:02:00,2.116 2014-02-16 02:07:00,2.3 2014-02-16 02:12:00,3.3760000000000003 2014-02-16 02:17:00,2.334 2014-02-16 02:22:00,2.05 2014-02-16 02:27:00,2.3280000000000003 2014-02-16 02:32:00,2.1 2014-02-16 02:37:00,2.366 2014-02-16 02:42:00,2.164 2014-02-16 02:47:00,2.334 2014-02-16 02:52:00,2.114 2014-02-16 02:57:00,2.396 2014-02-16 03:02:00,2.12 2014-02-16 03:07:00,2.336 2014-02-16 03:12:00,2.2 2014-02-16 03:17:00,2.266 2014-02-16 03:22:00,3.742 2014-02-16 03:27:00,2.396 2014-02-16 03:32:00,2.084 2014-02-16 03:37:00,2.338 2014-02-16 03:42:00,2.122 2014-02-16 03:47:00,2.334 2014-02-16 03:52:00,2.33 2014-02-16 03:57:00,2.404 2014-02-16 04:02:00,2.052 2014-02-16 04:07:00,2.2840000000000003 2014-02-16 04:12:00,2.1180000000000003 2014-02-16 04:17:00,2.2640000000000002 2014-02-16 04:22:00,3.43 2014-02-16 04:27:00,2.3 2014-02-16 04:32:00,2.096 2014-02-16 04:37:00,2.336 2014-02-16 04:42:00,2.072 2014-02-16 04:47:00,2.234 2014-02-16 04:52:00,2.17 2014-02-16 04:57:00,2.3680000000000003 2014-02-16 05:02:00,2.05 2014-02-16 05:07:00,2.342 2014-02-16 05:12:00,3.38 2014-02-16 05:17:00,2.3280000000000003 2014-02-16 05:22:00,2.102 2014-02-16 05:27:00,2.334 2014-02-16 05:32:00,2.066 2014-02-16 05:37:00,2.2 2014-02-16 05:42:00,2.094 2014-02-16 05:47:00,2.424 2014-02-16 05:52:00,2.08 2014-02-16 05:57:00,2.28 2014-02-16 06:02:00,2.096 2014-02-16 06:07:00,3.634 2014-02-16 06:12:00,2.05 2014-02-16 06:17:00,2.184 2014-02-16 06:22:00,2.0980000000000003 2014-02-16 06:27:00,2.2840000000000003 2014-02-16 06:32:00,2.12 2014-02-16 06:37:00,2.336 2014-02-16 06:42:00,2.102 2014-02-16 06:47:00,2.302 2014-02-16 06:52:00,2.146 2014-02-16 06:57:00,2.378 2014-02-16 07:02:00,2.15 2014-02-16 07:07:00,2.352 2014-02-16 07:12:00,3.46 2014-02-16 07:17:00,2.292 2014-02-16 07:22:00,2.08 2014-02-16 07:27:00,2.252 2014-02-16 07:32:00,2.144 2014-02-16 07:37:00,2.6439999999999997 2014-02-16 07:42:00,2.062 2014-02-16 07:47:00,2.162 2014-02-16 07:52:00,1.936 2014-02-16 07:57:00,2.1959999999999997 2014-02-16 08:02:00,1.996 2014-02-16 08:07:00,2.254 2014-02-16 08:12:00,1.932 2014-02-16 08:17:00,2.1719999999999997 2014-02-16 08:22:00,3.2260000000000004 2014-02-16 08:27:00,2.116 2014-02-16 08:32:00,1.98 2014-02-16 08:37:00,2.1959999999999997 2014-02-16 08:42:00,1.95 2014-02-16 08:47:00,2.208 2014-02-16 08:52:00,1.9340000000000002 2014-02-16 08:57:00,2.296 2014-02-16 09:02:00,2.002 2014-02-16 09:07:00,2.162 2014-02-16 09:12:00,3.2680000000000002 2014-02-16 09:17:00,2.26 2014-02-16 09:22:00,2.006 2014-02-16 09:27:00,2.168 2014-02-16 09:32:00,2.234 2014-02-16 09:37:00,2.166 2014-02-16 09:42:00,2.016 2014-02-16 09:47:00,2.066 2014-02-16 09:52:00,1.9980000000000002 2014-02-16 09:57:00,2.2159999999999997 2014-02-16 10:02:00,1.962 2014-02-16 10:07:00,2.146 2014-02-16 10:12:00,1.966 2014-02-16 10:17:00,3.44 2014-02-16 10:22:00,1.946 2014-02-16 10:27:00,2.138 2014-02-16 10:32:00,1.994 2014-02-16 10:37:00,2.156 2014-02-16 10:42:00,1.944 2014-02-16 10:47:00,2.26 2014-02-16 10:52:00,1.984 2014-02-16 10:57:00,2.25 2014-02-16 11:02:00,2.02 2014-02-16 11:07:00,2.234 2014-02-16 11:12:00,2.066 2014-02-16 11:17:00,3.67 2014-02-16 11:22:00,2.016 2014-02-16 11:27:00,2.202 2014-02-16 11:32:00,2.01 2014-02-16 11:37:00,2.126 2014-02-16 11:42:00,1.916 2014-02-16 11:47:00,2.116 2014-02-16 11:52:00,1.936 2014-02-16 11:57:00,2.1519999999999997 2014-02-16 12:02:00,2.05 2014-02-16 12:07:00,2.1519999999999997 2014-02-16 12:12:00,2.012 2014-02-16 12:17:00,2.116 2014-02-16 12:22:00,3.298 2014-02-16 12:27:00,2.116 2014-02-16 12:32:00,2.01 2014-02-16 12:37:00,2.252 2014-02-16 12:42:00,1.936 2014-02-16 12:47:00,2.182 2014-02-16 12:52:00,2.016 2014-02-16 12:57:00,2.346 2014-02-16 13:02:00,1.984 2014-02-16 13:07:00,2.202 2014-02-16 13:12:00,3.3339999999999996 2014-02-16 13:17:00,2.23 2014-02-16 13:22:00,2.0180000000000002 2014-02-16 13:27:00,2.102 2014-02-16 13:32:00,1.966 2014-02-16 13:37:00,2.168 2014-02-16 13:42:00,1.9340000000000002 2014-02-16 13:47:00,2.116 2014-02-16 13:52:00,1.9340000000000002 2014-02-16 13:57:00,2.2 2014-02-16 14:02:00,2.032 2014-02-16 14:07:00,2.18 2014-02-16 14:12:00,3.266 2014-02-16 14:17:00,2.248 2014-02-16 14:22:00,2.046 2014-02-16 14:27:00,2.396 2014-02-16 14:32:00,1.9180000000000001 2014-02-16 14:37:00,2.136 2014-02-16 14:42:00,2.032 2014-02-16 14:47:00,2.166 2014-02-16 14:52:00,1.996 2014-02-16 14:57:00,2.1519999999999997 2014-02-16 15:02:00,1.996 2014-02-16 15:07:00,2.1 2014-02-16 15:12:00,1.98 2014-02-16 15:17:00,3.4739999999999998 2014-02-16 15:22:00,1.99 2014-02-16 15:27:00,2.116 2014-02-16 15:32:00,1.944 2014-02-16 15:37:00,2.1919999999999997 2014-02-16 15:42:00,1.996 2014-02-16 15:47:00,2.1959999999999997 2014-02-16 15:52:00,1.956 2014-02-16 15:57:00,2.214 2014-02-16 16:02:00,2.022 2014-02-16 16:07:00,2.142 2014-02-16 16:12:00,1.9240000000000002 2014-02-16 16:17:00,3.45 2014-02-16 16:22:00,1.886 2014-02-16 16:27:00,2.124 2014-02-16 16:32:00,1.956 2014-02-16 16:37:00,2.1919999999999997 2014-02-16 16:42:00,1.9380000000000002 2014-02-16 16:47:00,2.154 2014-02-16 16:52:00,1.906 2014-02-16 16:57:00,2.15 2014-02-16 17:02:00,2.0 2014-02-16 17:07:00,3.4 2014-02-16 17:12:00,2.036 2014-02-16 17:17:00,2.182 2014-02-16 17:22:00,1.868 2014-02-16 17:27:00,2.242 2014-02-16 17:32:00,2.04 2014-02-16 17:37:00,2.136 2014-02-16 17:42:00,2.0340000000000003 2014-02-16 17:47:00,2.244 2014-02-16 17:52:00,1.956 2014-02-16 17:57:00,2.112 2014-02-16 18:02:00,1.966 2014-02-16 18:07:00,2.084 2014-02-16 18:12:00,1.9180000000000001 2014-02-16 18:17:00,2.062 2014-02-16 18:22:00,3.236 2014-02-16 18:27:00,2.112 2014-02-16 18:32:00,2.016 2014-02-16 18:37:00,2.13 2014-02-16 18:42:00,1.962 2014-02-16 18:47:00,2.148 2014-02-16 18:52:00,1.95 2014-02-16 18:57:00,2.334 2014-02-16 19:02:00,1.9340000000000002 2014-02-16 19:07:00,2.096 2014-02-16 19:12:00,2.02 2014-02-16 19:17:00,2.1 2014-02-16 19:22:00,3.1919999999999997 2014-02-16 19:27:00,2.062 2014-02-16 19:32:00,1.8940000000000001 2014-02-16 19:37:00,2.088 2014-02-16 19:42:00,1.966 2014-02-16 19:47:00,2.134 2014-02-16 19:52:00,1.9680000000000002 2014-02-16 19:57:00,2.2159999999999997 2014-02-16 20:02:00,1.94 2014-02-16 20:07:00,2.142 2014-02-16 20:12:00,1.9980000000000002 2014-02-16 20:17:00,3.35 2014-02-16 20:22:00,2.064 2014-02-16 20:27:00,2.042 2014-02-16 20:32:00,1.916 2014-02-16 20:37:00,2.124 2014-02-16 20:42:00,1.854 2014-02-16 20:47:00,2.046 2014-02-16 20:52:00,1.8940000000000001 2014-02-16 20:57:00,2.11 2014-02-16 21:02:00,1.8840000000000001 2014-02-16 21:07:00,2.114 2014-02-16 21:12:00,1.9240000000000002 2014-02-16 21:17:00,2.074 2014-02-16 21:22:00,3.218 2014-02-16 21:27:00,2.086 2014-02-16 21:32:00,1.8840000000000001 2014-02-16 21:37:00,2.108 2014-02-16 21:42:00,1.9880000000000002 2014-02-16 21:47:00,2.0340000000000003 2014-02-16 21:52:00,1.896 2014-02-16 21:57:00,3.4160000000000004 2014-02-16 22:02:00,1.9180000000000001 2014-02-16 22:07:00,2.11 2014-02-16 22:12:00,1.854 2014-02-16 22:17:00,2.036 2014-02-16 22:22:00,3.162 2014-02-16 22:27:00,2.03 2014-02-16 22:32:00,1.8980000000000001 2014-02-16 22:37:00,2.0 2014-02-16 22:42:00,1.864 2014-02-16 22:47:00,2.046 2014-02-16 22:52:00,1.93 2014-02-16 22:57:00,2.106 2014-02-16 23:02:00,2.02 2014-02-16 23:07:00,2.016 2014-02-16 23:12:00,3.1460000000000004 2014-02-16 23:17:00,2.05 2014-02-16 23:22:00,1.8159999999999998 2014-02-16 23:27:00,2.046 2014-02-16 23:32:00,1.834 2014-02-16 23:37:00,2.096 2014-02-16 23:42:00,1.8619999999999999 2014-02-16 23:47:00,2.0540000000000003 2014-02-16 23:52:00,1.91 2014-02-16 23:57:00,2.1719999999999997 2014-02-17 00:02:00,1.986 2014-02-17 00:07:00,2.1519999999999997 2014-02-17 00:12:00,1.986 2014-02-17 00:17:00,3.532 2014-02-17 00:22:00,1.854 2014-02-17 00:27:00,2.144 2014-02-17 00:32:00,1.8719999999999999 2014-02-17 00:37:00,2.036 2014-02-17 00:42:00,1.864 2014-02-17 00:47:00,2.042 2014-02-17 00:52:00,1.8459999999999999 2014-02-17 00:57:00,2.142 2014-02-17 01:02:00,1.84 2014-02-17 01:07:00,3.338 2014-02-17 01:12:00,1.806 2014-02-17 01:17:00,2.032 2014-02-17 01:22:00,1.8159999999999998 2014-02-17 01:27:00,2.116 2014-02-17 01:32:00,2.0340000000000003 2014-02-17 01:37:00,2.0340000000000003 2014-02-17 01:42:00,1.8659999999999999 2014-02-17 01:47:00,1.996 2014-02-17 01:52:00,1.886 2014-02-17 01:57:00,2.1519999999999997 2014-02-17 02:02:00,1.902 2014-02-17 02:07:00,2.16 2014-02-17 02:12:00,1.906 2014-02-17 02:17:00,3.352 2014-02-17 02:22:00,2.002 2014-02-17 02:27:00,2.186 2014-02-17 02:32:00,1.974 2014-02-17 02:37:00,2.1919999999999997 2014-02-17 02:42:00,2.11 2014-02-17 02:47:00,2.092 2014-02-17 02:52:00,1.916 2014-02-17 02:57:00,2.2 2014-02-17 03:02:00,4.534 2014-02-17 03:07:00,2.716 2014-02-17 03:12:00,3.9739999999999998 2014-02-17 03:17:00,2.576 2014-02-17 03:22:00,2.366 2014-02-17 03:27:00,2.398 2014-02-17 03:32:00,2.166 2014-02-17 03:37:00,2.332 2014-02-17 03:42:00,2.07 2014-02-17 03:47:00,2.346 2014-02-17 03:52:00,2.17 2014-02-17 03:57:00,2.324 2014-02-17 04:02:00,2.106 2014-02-17 04:07:00,2.2840000000000003 2014-02-17 04:12:00,3.49 2014-02-17 04:17:00,2.29 2014-02-17 04:22:00,2.224 2014-02-17 04:27:00,2.674 2014-02-17 04:32:00,2.134 2014-02-17 04:37:00,4.624 2014-02-17 04:42:00,2.424 2014-02-17 04:47:00,2.358 2014-02-17 04:52:00,2.204 2014-02-17 04:57:00,2.464 2014-02-17 05:02:00,2.2319999999999998 2014-02-17 05:07:00,2.374 2014-02-17 05:12:00,6.09 2014-02-17 05:17:00,2.872 2014-02-17 05:22:00,2.62 2014-02-17 05:27:00,2.7 2014-02-17 05:32:00,2.6660000000000004 2014-02-17 05:37:00,2.8339999999999996 2014-02-17 05:42:00,6.412000000000001 2014-02-17 05:47:00,60.19 2014-02-17 05:52:00,54.0 2014-02-17 05:57:00,48.916000000000004 2014-02-17 06:02:00,8.41 2014-02-17 06:07:00,67.94800000000001 2014-02-17 06:12:00,53.922 2014-02-17 06:17:00,63.722 2014-02-17 06:22:00,61.076 2014-02-17 06:27:00,53.794 2014-02-17 06:32:00,44.36600000000001 2014-02-17 06:37:00,61.794 2014-02-17 06:42:00,56.262 2014-02-17 06:47:00,55.512 2014-02-17 06:52:00,57.26600000000001 2014-02-17 06:57:00,54.302 2014-02-17 07:02:00,35.436 2014-02-17 07:07:00,66.044 2014-02-17 07:12:00,55.62600000000001 2014-02-17 07:17:00,20.18 2014-02-17 07:22:00,19.206 2014-02-17 07:27:00,72.376 2014-02-17 07:32:00,53.284 2014-02-17 07:37:00,25.74 2014-02-17 07:42:00,8.932 2014-02-17 07:47:00,67.426 2014-02-17 07:52:00,53.762 2014-02-17 07:57:00,43.284 2014-02-17 08:02:00,8.716000000000001 2014-02-17 08:07:00,3.446 2014-02-17 08:12:00,3.3339999999999996 2014-02-17 08:17:00,4.598 2014-02-17 08:22:00,3.298 2014-02-17 08:27:00,3.1839999999999997 2014-02-17 08:32:00,3.33 2014-02-17 08:37:00,3.1660000000000004 2014-02-17 08:42:00,3.33 2014-02-17 08:47:00,3.1319999999999997 2014-02-17 08:52:00,3.284 2014-02-17 08:57:00,6.55 2014-02-17 09:02:00,8.916 2014-02-17 09:07:00,3.068 2014-02-17 09:12:00,3.0639999999999996 2014-02-17 09:17:00,4.364 2014-02-17 09:22:00,3.0460000000000003 2014-02-17 09:27:00,3.092 2014-02-17 09:32:00,3.05 2014-02-17 09:37:00,2.984 2014-02-17 09:42:00,3.13 2014-02-17 09:47:00,2.998 2014-02-17 09:52:00,3.054 2014-02-17 09:57:00,3.168 2014-02-17 10:02:00,3.176 2014-02-17 10:07:00,3.1839999999999997 2014-02-17 10:12:00,4.314 2014-02-17 10:17:00,3.048 2014-02-17 10:22:00,3.0660000000000003 2014-02-17 10:27:00,3.234 2014-02-17 10:32:00,3.142 2014-02-17 10:37:00,3.08 2014-02-17 10:42:00,3.0639999999999996 2014-02-17 10:47:00,3.016 2014-02-17 10:52:00,3.2 2014-02-17 10:57:00,3.0839999999999996 2014-02-17 11:02:00,3.2319999999999998 2014-02-17 11:07:00,3.2 2014-02-17 11:12:00,3.1660000000000004 2014-02-17 11:17:00,5.9 2014-02-17 11:22:00,8.872 2014-02-17 11:27:00,10.222000000000001 2014-02-17 11:32:00,11.1 2014-02-17 11:37:00,12.0 2014-02-17 11:42:00,72.78399999999998 2014-02-17 11:47:00,55.62 2014-02-17 11:52:00,28.182 2014-02-17 11:57:00,3.15 2014-02-17 12:02:00,3.1639999999999997 2014-02-17 12:07:00,3.016 2014-02-17 12:12:00,3.218 2014-02-17 12:17:00,4.436 2014-02-17 12:22:00,3.148 2014-02-17 12:27:00,3.0660000000000003 2014-02-17 12:32:00,3.1660000000000004 2014-02-17 12:37:00,3.1839999999999997 2014-02-17 12:42:00,3.214 2014-02-17 12:47:00,3.182 2014-02-17 12:52:00,3.2319999999999998 2014-02-17 12:57:00,3.13 2014-02-17 13:02:00,3.3139999999999996 2014-02-17 13:07:00,3.182 2014-02-17 13:12:00,3.1660000000000004 2014-02-17 13:17:00,4.346 2014-02-17 13:22:00,3.284 2014-02-17 13:27:00,3.2319999999999998 2014-02-17 13:32:00,3.116 2014-02-17 13:37:00,3.05 2014-02-17 13:42:00,3.234 2014-02-17 13:47:00,3.1660000000000004 2014-02-17 13:52:00,3.18 2014-02-17 13:57:00,3.1839999999999997 2014-02-17 14:02:00,3.182 2014-02-17 14:07:00,3.95 2014-02-17 14:12:00,68.16199999999999 2014-02-17 14:17:00,56.242 2014-02-17 14:22:00,45.324 2014-02-17 14:27:00,4.0 2014-02-17 14:32:00,4.806 2014-02-17 14:37:00,5.966 2014-02-17 14:42:00,5.85 2014-02-17 14:47:00,4.416 2014-02-17 14:52:00,4.096 2014-02-17 14:57:00,3.968 2014-02-17 15:02:00,3.98 2014-02-17 15:07:00,3.9339999999999997 2014-02-17 15:12:00,5.834 2014-02-17 15:17:00,5.2139999999999995 2014-02-17 15:22:00,3.06 2014-02-17 15:27:00,3.216 2014-02-17 15:32:00,3.3339999999999996 2014-02-17 15:37:00,3.234 2014-02-17 15:42:00,3.466 2014-02-17 15:47:00,3.25 2014-02-17 15:52:00,3.45 2014-02-17 15:57:00,3.522 2014-02-17 16:02:00,3.31 2014-02-17 16:07:00,4.518 2014-02-17 16:12:00,3.614 2014-02-17 16:17:00,3.1239999999999997 2014-02-17 16:22:00,3.0980000000000003 2014-02-17 16:27:00,3.08 2014-02-17 16:32:00,3.238 2014-02-17 16:37:00,3.196 2014-02-17 16:42:00,3.25 2014-02-17 16:47:00,3.2 2014-02-17 16:52:00,3.134 2014-02-17 16:57:00,3.128 2014-02-17 17:02:00,3.286 2014-02-17 17:07:00,3.266 2014-02-17 17:12:00,3.228 2014-02-17 17:17:00,4.216 2014-02-17 17:22:00,3.4160000000000004 2014-02-17 17:27:00,3.034 2014-02-17 17:32:00,3.25 2014-02-17 17:37:00,3.3819999999999997 2014-02-17 17:42:00,3.322 2014-02-17 17:47:00,3.1260000000000003 2014-02-17 17:52:00,4.362 2014-02-17 17:57:00,4.082 2014-02-17 18:02:00,4.332 2014-02-17 18:07:00,4.2360000000000015 2014-02-17 18:12:00,8.783999999999999 2014-02-17 18:17:00,5.504 2014-02-17 18:22:00,3.952 2014-02-17 18:27:00,4.244 2014-02-17 18:32:00,4.184 2014-02-17 18:37:00,4.3660000000000005 2014-02-17 18:42:00,4.314 2014-02-17 18:47:00,4.296 2014-02-17 18:52:00,5.68 2014-02-17 18:57:00,3.19 2014-02-17 19:02:00,3.0660000000000003 2014-02-17 19:07:00,2.984 2014-02-17 19:12:00,4.442 2014-02-17 19:17:00,3.114 2014-02-17 19:22:00,3.0839999999999996 2014-02-17 19:27:00,3.016 2014-02-17 19:32:00,3.198 2014-02-17 19:37:00,3.0980000000000003 2014-02-17 19:42:00,3.182 2014-02-17 19:47:00,3.116 2014-02-17 19:52:00,3.2319999999999998 2014-02-17 19:57:00,3.1519999999999997 2014-02-17 20:02:00,3.3160000000000003 2014-02-17 20:07:00,4.412 2014-02-17 20:12:00,3.252 2014-02-17 20:17:00,3.242 2014-02-17 20:22:00,3.1839999999999997 2014-02-17 20:27:00,3.15 2014-02-17 20:32:00,3.4360000000000004 2014-02-17 20:37:00,3.2939999999999996 2014-02-17 20:42:00,3.282 2014-02-17 20:47:00,3.45 2014-02-17 20:52:00,3.298 2014-02-17 20:57:00,3.2319999999999998 2014-02-17 21:02:00,3.266 2014-02-17 21:07:00,3.2880000000000003 2014-02-17 21:12:00,4.426 2014-02-17 21:17:00,3.116 2014-02-17 21:22:00,3.3139999999999996 2014-02-17 21:27:00,3.1519999999999997 2014-02-17 21:32:00,3.25 2014-02-17 21:37:00,3.196 2014-02-17 21:42:00,3.25 2014-02-17 21:47:00,3.198 2014-02-17 21:52:00,3.1660000000000004 2014-02-17 21:57:00,4.632 2014-02-17 22:02:00,3.214 2014-02-17 22:07:00,3.2680000000000002 2014-02-17 22:12:00,3.11 2014-02-17 22:17:00,4.396 2014-02-17 22:22:00,3.366 2014-02-17 22:27:00,3.29 2014-02-17 22:32:00,3.074 2014-02-17 22:37:00,3.216 2014-02-17 22:42:00,3.048 2014-02-17 22:47:00,3.1839999999999997 2014-02-17 22:52:00,3.05 2014-02-17 22:57:00,3.218 2014-02-17 23:02:00,3.0660000000000003 2014-02-17 23:07:00,3.05 2014-02-17 23:12:00,3.28 2014-02-17 23:17:00,4.59 2014-02-17 23:22:00,64.638 2014-02-17 23:27:00,52.118 2014-02-17 23:32:00,44.85 2014-02-17 23:37:00,3.734 2014-02-17 23:42:00,4.184 2014-02-17 23:47:00,5.0 2014-02-17 23:52:00,9.294 2014-02-17 23:57:00,7.38 2014-02-18 00:02:00,37.984 2014-02-18 00:07:00,62.838 2014-02-18 00:12:00,53.72 2014-02-18 00:17:00,15.466 2014-02-18 00:22:00,4.25 2014-02-18 00:27:00,5.6160000000000005 2014-02-18 00:32:00,2.766 2014-02-18 00:37:00,8.582 2014-02-18 00:42:00,4.3 2014-02-18 00:47:00,4.532 2014-02-18 00:52:00,19.874000000000002 2014-02-18 00:57:00,68.75399999999999 2014-02-18 01:02:00,53.20399999999999 2014-02-18 01:07:00,23.215999999999998 2014-02-18 01:12:00,2.698 2014-02-18 01:17:00,2.5340000000000003 2014-02-18 01:22:00,3.7960000000000003 2014-02-18 01:27:00,2.45 2014-02-18 01:32:00,2.6180000000000003 2014-02-18 01:37:00,2.5580000000000003 2014-02-18 01:42:00,2.34 2014-02-18 01:47:00,8.766 2014-02-18 01:52:00,6.1339999999999995 2014-02-18 01:57:00,4.566 2014-02-18 02:02:00,10.948 2014-02-18 02:07:00,6.916 2014-02-18 02:12:00,11.527999999999999 2014-02-18 02:17:00,5.372000000000001 2014-02-18 02:22:00,3.076 2014-02-18 02:27:00,3.072 2014-02-18 02:32:00,6.2479999999999976 2014-02-18 02:37:00,3.2880000000000003 2014-02-18 02:42:00,3.076 2014-02-18 02:47:00,2.912 2014-02-18 02:52:00,4.9319999999999995 2014-02-18 02:57:00,11.84 2014-02-18 03:02:00,6.9879999999999995 2014-02-18 03:07:00,9.3 2014-02-18 03:12:00,4.598 2014-02-18 03:17:00,5.85 2014-02-18 03:22:00,4.1819999999999995 2014-02-18 03:27:00,2.7 2014-02-18 03:32:00,2.8280000000000003 2014-02-18 03:37:00,2.5839999999999996 2014-02-18 03:42:00,2.6060000000000003 2014-02-18 03:47:00,2.54 2014-02-18 03:52:00,2.522 2014-02-18 03:57:00,2.592 2014-02-18 04:02:00,2.516 2014-02-18 04:07:00,2.634 2014-02-18 04:12:00,6.66 2014-02-18 04:17:00,4.516 2014-02-18 04:22:00,7.182 2014-02-18 04:27:00,3.734 2014-02-18 04:32:00,4.81 2014-02-18 04:37:00,3.716 2014-02-18 04:42:00,5.73 2014-02-18 04:47:00,3.55 2014-02-18 04:52:00,3.766 2014-02-18 04:57:00,3.628 2014-02-18 05:02:00,3.75 2014-02-18 05:07:00,5.1160000000000005 2014-02-18 05:12:00,5.4220000000000015 2014-02-18 05:17:00,3.1260000000000003 2014-02-18 05:22:00,4.404 2014-02-18 05:27:00,2.9139999999999997 2014-02-18 05:32:00,2.9219999999999997 2014-02-18 05:37:00,3.826 2014-02-18 05:42:00,6.932 2014-02-18 05:47:00,6.95 2014-02-18 05:52:00,5.184 2014-02-18 05:57:00,15.56 2014-02-18 06:02:00,72.22 2014-02-18 06:07:00,54.06399999999999 2014-02-18 06:12:00,34.296 2014-02-18 06:17:00,6.54 2014-02-18 06:22:00,55.95 2014-02-18 06:27:00,51.332 2014-02-18 06:32:00,56.05 2014-02-18 06:37:00,8.068 2014-02-18 06:42:00,3.83 2014-02-18 06:47:00,6.4460000000000015 2014-02-18 06:52:00,4.086 2014-02-18 06:57:00,15.548 2014-02-18 07:02:00,3.716 2014-02-18 07:07:00,6.376 2014-02-18 07:12:00,3.466 2014-02-18 07:17:00,3.142 2014-02-18 07:22:00,3.42 2014-02-18 07:27:00,3.122 2014-02-18 07:32:00,3.342 2014-02-18 07:37:00,2.8 2014-02-18 07:42:00,3.208 2014-02-18 07:47:00,2.85 2014-02-18 07:52:00,3.17 2014-02-18 07:57:00,2.766 2014-02-18 08:02:00,3.014 2014-02-18 08:07:00,2.54 2014-02-18 08:12:00,4.1339999999999995 2014-02-18 08:17:00,2.392 2014-02-18 08:22:00,2.8760000000000003 2014-02-18 08:27:00,2.9339999999999997 2014-02-18 08:32:00,2.734 2014-02-18 08:37:00,2.324 2014-02-18 08:42:00,2.6719999999999997 2014-02-18 08:47:00,2.238 2014-02-18 08:52:00,2.64 2014-02-18 08:57:00,2.3680000000000003 2014-02-18 09:02:00,2.56 2014-02-18 09:07:00,14.752 2014-02-18 09:12:00,4.5360000000000005 2014-02-18 09:17:00,3.472 2014-02-18 09:22:00,3.2760000000000002 2014-02-18 09:27:00,2.6180000000000003 2014-02-18 09:32:00,3.13 2014-02-18 09:37:00,4.484 2014-02-18 09:42:00,4.1080000000000005 2014-02-18 09:47:00,14.654000000000002 2014-02-18 09:52:00,13.984000000000002 2014-02-18 09:57:00,11.2 2014-02-18 10:02:00,14.372 2014-02-18 10:07:00,19.977999999999998 2014-02-18 10:12:00,8.656 2014-02-18 10:17:00,9.716000000000001 2014-02-18 10:22:00,29.114 2014-02-18 10:27:00,23.831999999999997 2014-02-18 10:32:00,3.5839999999999996 2014-02-18 10:37:00,3.04 2014-02-18 10:42:00,3.45 2014-02-18 10:47:00,3.04 2014-02-18 10:52:00,3.4760000000000004 2014-02-18 10:57:00,3.034 2014-02-18 11:02:00,3.5 2014-02-18 11:07:00,3.0239999999999996 2014-02-18 11:12:00,4.788 2014-02-18 11:17:00,2.972 2014-02-18 11:22:00,3.444 2014-02-18 11:27:00,2.966 2014-02-18 11:32:00,3.318 2014-02-18 11:37:00,2.83 2014-02-18 11:42:00,3.36 2014-02-18 11:47:00,2.766 2014-02-18 11:52:00,3.2939999999999996 2014-02-18 11:57:00,2.8339999999999996 2014-02-18 12:02:00,3.29 2014-02-18 12:07:00,2.988 2014-02-18 12:12:00,3.234 2014-02-18 12:17:00,4.084 2014-02-18 12:22:00,3.258 2014-02-18 12:27:00,2.7939999999999996 2014-02-18 12:32:00,3.326 2014-02-18 12:37:00,2.75 2014-02-18 12:42:00,3.2680000000000002 2014-02-18 12:47:00,2.7939999999999996 2014-02-18 12:52:00,3.2760000000000002 2014-02-18 12:57:00,2.79 2014-02-18 13:02:00,3.29 2014-02-18 13:07:00,4.19 2014-02-18 13:12:00,3.29 2014-02-18 13:17:00,2.8280000000000003 2014-02-18 13:22:00,3.49 2014-02-18 13:27:00,2.7880000000000003 2014-02-18 13:32:00,3.3 2014-02-18 13:37:00,2.782 2014-02-18 13:42:00,3.2939999999999996 2014-02-18 13:47:00,2.79 2014-02-18 13:52:00,3.3 2014-02-18 13:57:00,2.862 2014-02-18 14:02:00,3.3160000000000003 2014-02-18 14:07:00,2.86 2014-02-18 14:12:00,4.56 2014-02-18 14:17:00,2.806 2014-02-18 14:22:00,3.25 2014-02-18 14:27:00,2.852 2014-02-18 14:32:00,3.266 2014-02-18 14:37:00,2.772 2014-02-18 14:42:00,3.2560000000000002 2014-02-18 14:47:00,2.762 2014-02-18 14:52:00,3.306 2014-02-18 14:57:00,2.8480000000000003 2014-02-18 15:02:00,3.3160000000000003 2014-02-18 15:07:00,3.154 2014-02-18 15:12:00,5.587999999999999 2014-02-18 15:17:00,8.876 2014-02-18 15:22:00,3.45 2014-02-18 15:27:00,2.708 2014-02-18 15:32:00,3.012 2014-02-18 15:37:00,2.622 2014-02-18 15:42:00,2.992 2014-02-18 15:47:00,2.5660000000000003 2014-02-18 15:52:00,2.958 2014-02-18 15:57:00,2.574 2014-02-18 16:02:00,2.908 2014-02-18 16:07:00,2.5580000000000003 2014-02-18 16:12:00,2.958 2014-02-18 16:17:00,3.912 2014-02-18 16:22:00,2.9419999999999997 2014-02-18 16:27:00,2.5660000000000003 2014-02-18 16:32:00,2.9339999999999997 2014-02-18 16:37:00,2.576 2014-02-18 16:42:00,2.9339999999999997 2014-02-18 16:47:00,2.576 2014-02-18 16:52:00,2.9419999999999997 2014-02-18 16:57:00,2.6239999999999997 2014-02-18 17:02:00,2.938 2014-02-18 17:07:00,2.596 2014-02-18 17:12:00,2.924 2014-02-18 17:17:00,2.526 2014-02-18 17:22:00,4.266 2014-02-18 17:27:00,2.536 2014-02-18 17:32:00,2.88 2014-02-18 17:37:00,2.492 2014-02-18 17:42:00,2.9419999999999997 2014-02-18 17:47:00,2.5580000000000003 2014-02-18 17:52:00,2.904 2014-02-18 17:57:00,2.6060000000000003 2014-02-18 18:02:00,2.86 2014-02-18 18:07:00,2.542 2014-02-18 18:12:00,4.188 2014-02-18 18:17:00,2.556 2014-02-18 18:22:00,2.9760000000000004 2014-02-18 18:27:00,2.636 2014-02-18 18:32:00,2.9539999999999997 2014-02-18 18:37:00,2.6 2014-02-18 18:42:00,3.008 2014-02-18 18:47:00,9.908 2014-02-18 18:52:00,70.77199999999998 2014-02-18 18:57:00,50.81399999999999 2014-02-18 19:02:00,32.36 2014-02-18 19:07:00,4.206 2014-02-18 19:12:00,5.284 2014-02-18 19:17:00,4.45 2014-02-18 19:22:00,3.89 2014-02-18 19:27:00,5.2 2014-02-18 19:32:00,3.508 2014-02-18 19:37:00,3.194 2014-02-18 19:42:00,3.6239999999999997 2014-02-18 19:47:00,3.25 2014-02-18 19:52:00,3.6919999999999997 2014-02-18 19:57:00,4.3 2014-02-18 20:02:00,2.978 2014-02-18 20:07:00,2.648 2014-02-18 20:12:00,4.263999999999999 2014-02-18 20:17:00,2.6260000000000003 2014-02-18 20:22:00,2.984 2014-02-18 20:27:00,2.6260000000000003 2014-02-18 20:32:00,2.938 2014-02-18 20:37:00,2.53 2014-02-18 20:42:00,2.94 2014-02-18 20:47:00,2.5580000000000003 2014-02-18 20:52:00,2.95 2014-02-18 20:57:00,2.642 2014-02-18 21:02:00,2.9419999999999997 2014-02-18 21:07:00,2.608 2014-02-18 21:12:00,2.8539999999999996 2014-02-18 21:17:00,3.7880000000000003 2014-02-18 21:22:00,2.884 2014-02-18 21:27:00,2.504 2014-02-18 21:32:00,2.94 2014-02-18 21:37:00,2.576 2014-02-18 21:42:00,2.95 2014-02-18 21:47:00,2.55 2014-02-18 21:52:00,2.9339999999999997 2014-02-18 21:57:00,4.26 2014-02-18 22:02:00,2.9419999999999997 2014-02-18 22:07:00,3.9160000000000004 2014-02-18 22:12:00,3.0 2014-02-18 22:17:00,2.658 2014-02-18 22:22:00,2.984 2014-02-18 22:27:00,2.5839999999999996 2014-02-18 22:32:00,3.0 2014-02-18 22:37:00,2.6260000000000003 2014-02-18 22:42:00,2.966 2014-02-18 22:47:00,2.642 2014-02-18 22:52:00,2.9960000000000004 2014-02-18 22:57:00,43.42 2014-02-18 23:02:00,57.066 2014-02-18 23:07:00,55.431999999999995 2014-02-18 23:12:00,14.45 2014-02-18 23:17:00,5.202000000000001 2014-02-18 23:22:00,5.36 2014-02-18 23:27:00,3.99 2014-02-18 23:32:00,5.65 2014-02-18 23:37:00,3.65 2014-02-18 23:42:00,3.9619999999999997 2014-02-18 23:47:00,3.674 2014-02-18 23:52:00,4.018 2014-02-18 23:57:00,4.73 2014-02-19 00:02:00,24.5 2014-02-19 00:07:00,65.648 2014-02-19 00:12:00,52.961999999999996 2014-02-19 00:17:00,20.7 2014-02-19 00:22:00,59.458 2014-02-19 00:27:00,55.826 2014-02-19 00:32:00,54.9 2014-02-19 00:37:00,5.59 2014-02-19 00:42:00,9.64 2014-02-19 00:47:00,2.932 2014-02-19 00:52:00,3.6839999999999997 2014-02-19 00:57:00,3.366 2014-02-19 01:02:00,9.038 2014-02-19 01:07:00,6.584 2014-02-19 01:12:00,5.098 2014-02-19 01:17:00,3.4819999999999998 2014-02-19 01:22:00,4.684 2014-02-19 01:27:00,3.576 2014-02-19 01:32:00,6.858 2014-02-19 01:37:00,2.9760000000000004 2014-02-19 01:42:00,2.938 2014-02-19 01:47:00,7.6720000000000015 2014-02-19 01:52:00,6.1160000000000005 2014-02-19 01:57:00,4.94 2014-02-19 02:02:00,6.034 2014-02-19 02:07:00,5.688 2014-02-19 02:12:00,4.368 2014-02-19 02:17:00,3.266 2014-02-19 02:22:00,5.058 2014-02-19 02:27:00,3.5 2014-02-19 02:32:00,3.826 2014-02-19 02:37:00,4.598 2014-02-19 02:42:00,2.9419999999999997 2014-02-19 02:47:00,2.592 2014-02-19 02:52:00,3.034 2014-02-19 02:57:00,2.678 2014-02-19 03:02:00,3.0380000000000003 2014-02-19 03:07:00,2.6239999999999997 2014-02-19 03:12:00,3.05 2014-02-19 03:17:00,2.678 2014-02-19 03:22:00,5.846 2014-02-19 03:27:00,2.6919999999999997 2014-02-19 03:32:00,12.204 2014-02-19 03:37:00,2.642 2014-02-19 03:42:00,3.138 2014-02-19 03:47:00,2.76 2014-02-19 03:52:00,3.4 2014-02-19 03:57:00,4.65 2014-02-19 04:02:00,3.2260000000000004 2014-02-19 04:07:00,2.71 2014-02-19 04:12:00,3.11 2014-02-19 04:17:00,2.734 2014-02-19 04:22:00,4.434 2014-02-19 04:27:00,2.6919999999999997 2014-02-19 04:32:00,3.0860000000000003 2014-02-19 04:37:00,2.7 2014-02-19 04:42:00,3.1060000000000003 2014-02-19 04:47:00,2.65 2014-02-19 04:52:00,3.028 2014-02-19 04:57:00,2.722 2014-02-19 05:02:00,5.127999999999999 2014-02-19 05:07:00,3.28 2014-02-19 05:12:00,4.053999999999999 2014-02-19 05:17:00,10.356 2014-02-19 05:22:00,71.154 2014-02-19 05:27:00,52.05 2014-02-19 05:32:00,31.184 2014-02-19 05:37:00,3.408 2014-02-19 05:42:00,5.416 2014-02-19 05:47:00,3.4619999999999997 2014-02-19 05:52:00,3.718 2014-02-19 05:57:00,5.0760000000000005 2014-02-19 06:02:00,3.3360000000000003 2014-02-19 06:07:00,4.774 2014-02-19 06:12:00,3.742 2014-02-19 06:17:00,4.76 2014-02-19 06:22:00,5.356 2014-02-19 06:27:00,2.736 2014-02-19 06:32:00,3.156 2014-02-19 06:37:00,2.69 2014-02-19 06:42:00,3.0839999999999996 2014-02-19 06:47:00,2.6239999999999997 2014-02-19 06:52:00,3.034 2014-02-19 06:57:00,2.658 2014-02-19 07:02:00,5.504 2014-02-19 07:07:00,43.20399999999999 2014-02-19 07:12:00,66.858 2014-02-19 07:17:00,51.542 2014-02-19 07:22:00,16.36 2014-02-19 07:27:00,3.492 2014-02-19 07:32:00,4.766 2014-02-19 07:37:00,3.424 2014-02-19 07:42:00,3.6839999999999997 2014-02-19 07:47:00,5.042 2014-02-19 07:52:00,3.358 2014-02-19 07:57:00,3.202 2014-02-19 08:02:00,3.6260000000000003 2014-02-19 08:07:00,3.342 2014-02-19 08:12:00,5.084 2014-02-19 08:17:00,3.1839999999999997 2014-02-19 08:22:00,3.6260000000000003 2014-02-19 08:27:00,3.234 2014-02-19 08:32:00,3.66 2014-02-19 08:37:00,3.25 2014-02-19 08:42:00,4.462 2014-02-19 08:47:00,2.546 2014-02-19 08:52:00,2.9160000000000004 2014-02-19 08:57:00,2.6 2014-02-19 09:02:00,2.926 2014-02-19 09:07:00,2.5340000000000003 2014-02-19 09:12:00,2.966 2014-02-19 09:17:00,3.234 2014-02-19 09:22:00,4.298 2014-02-19 09:27:00,4.95 2014-02-19 09:32:00,3.076 2014-02-19 09:37:00,2.608 2014-02-19 09:42:00,3.008 2014-02-19 09:47:00,8.094 2014-02-19 09:52:00,3.0260000000000002 2014-02-19 09:57:00,2.642 2014-02-19 10:02:00,2.978 2014-02-19 10:07:00,3.8760000000000003 2014-02-19 10:12:00,2.928 2014-02-19 10:17:00,2.572 2014-02-19 10:22:00,2.95 2014-02-19 10:27:00,2.5180000000000002 2014-02-19 10:32:00,2.9339999999999997 2014-02-19 10:37:00,2.526 2014-02-19 10:42:00,2.8760000000000003 2014-02-19 10:47:00,2.542 2014-02-19 10:52:00,2.9 2014-02-19 10:57:00,2.576 2014-02-19 11:02:00,2.8939999999999997 2014-02-19 11:07:00,2.6 2014-02-19 11:12:00,2.966 2014-02-19 11:17:00,2.5839999999999996 2014-02-19 11:22:00,4.216 2014-02-19 11:27:00,2.5839999999999996 2014-02-19 11:32:00,2.968 2014-02-19 11:37:00,2.55 2014-02-19 11:42:00,2.924 2014-02-19 11:47:00,2.55 2014-02-19 11:52:00,2.9160000000000004 2014-02-19 11:57:00,2.594 2014-02-19 12:02:00,2.93 2014-02-19 12:07:00,2.5660000000000003 2014-02-19 12:12:00,3.008 2014-02-19 12:17:00,3.928 2014-02-19 12:22:00,3.0 2014-02-19 12:27:00,2.5660000000000003 2014-02-19 12:32:00,2.9739999999999998 2014-02-19 12:37:00,2.5780000000000003 2014-02-19 12:42:00,2.968 2014-02-19 12:47:00,2.582 2014-02-19 12:52:00,2.992 2014-02-19 12:57:00,2.65 2014-02-19 13:02:00,2.97 2014-02-19 13:07:00,2.6060000000000003 2014-02-19 13:12:00,2.9939999999999998 2014-02-19 13:17:00,2.58 2014-02-19 13:22:00,4.3 2014-02-19 13:27:00,2.61 2014-02-19 13:32:00,2.9760000000000004 2014-02-19 13:37:00,2.5839999999999996 2014-02-19 13:42:00,2.9339999999999997 2014-02-19 13:47:00,2.57 2014-02-19 13:52:00,2.988 2014-02-19 13:57:00,2.76 2014-02-19 14:02:00,3.008 2014-02-19 14:07:00,2.5660000000000003 2014-02-19 14:12:00,2.92 2014-02-19 14:17:00,2.556 2014-02-19 14:22:00,4.32 2014-02-19 14:27:00,2.48 2014-02-19 14:32:00,2.8539999999999996 2014-02-19 14:37:00,4.716 2014-02-19 14:42:00,9.85 2014-02-19 14:47:00,3.7439999999999998 2014-02-19 14:52:00,5.41 2014-02-19 14:57:00,4.158 2014-02-19 15:02:00,6.0420000000000025 2014-02-19 15:07:00,3.7960000000000003 2014-02-19 15:12:00,4.0680000000000005 2014-02-19 15:17:00,7.7079999999999975 2014-02-19 15:22:00,4.226 2014-02-19 15:27:00,5.184 2014-02-19 15:32:00,3.1 2014-02-19 15:37:00,2.66 2014-02-19 15:42:00,3.16 2014-02-19 15:47:00,2.642 2014-02-19 15:52:00,3.1260000000000003 2014-02-19 15:57:00,2.6860000000000004 2014-02-19 16:02:00,3.108 2014-02-19 16:07:00,2.674 2014-02-19 16:12:00,4.3919999999999995 2014-02-19 16:17:00,2.64 2014-02-19 16:22:00,3.068 2014-02-19 16:27:00,2.6519999999999997 2014-02-19 16:32:00,3.1 2014-02-19 16:37:00,2.698 2014-02-19 16:42:00,3.092 2014-02-19 16:47:00,2.716 2014-02-19 16:52:00,3.1039999999999996 2014-02-19 16:57:00,2.688 2014-02-19 17:02:00,3.0660000000000003 2014-02-19 17:07:00,2.67 2014-02-19 17:12:00,3.108 2014-02-19 17:17:00,3.966 2014-02-19 17:22:00,3.0839999999999996 2014-02-19 17:27:00,2.674 2014-02-19 17:32:00,3.112 2014-02-19 17:37:00,2.698 2014-02-19 17:42:00,3.108 2014-02-19 17:47:00,42.76600000000001 2014-02-19 17:52:00,57.81 2014-02-19 17:57:00,53.39 2014-02-19 18:02:00,11.304 2014-02-19 18:07:00,3.42 2014-02-19 18:12:00,4.916 2014-02-19 18:17:00,5.2 2014-02-19 18:22:00,7.963999999999999 2014-02-19 18:27:00,3.7 2014-02-19 18:32:00,4.26 2014-02-19 18:37:00,3.6660000000000004 2014-02-19 18:42:00,4.3660000000000005 2014-02-19 18:47:00,3.95 2014-02-19 18:52:00,27.95 2014-02-19 18:57:00,66.324 2014-02-19 19:02:00,53.57 2014-02-19 19:07:00,23.281999999999996 2014-02-19 19:12:00,5.648 2014-02-19 19:17:00,6.257999999999999 2014-02-19 19:22:00,4.752 2014-02-19 19:27:00,5.608 2014-02-19 19:32:00,4.598 2014-02-19 19:37:00,3.8339999999999996 2014-02-19 19:42:00,4.54 2014-02-19 19:47:00,4.1 2014-02-19 19:52:00,4.374 2014-02-19 19:57:00,4.4060000000000015 2014-02-19 20:02:00,3.66 2014-02-19 20:07:00,2.826 2014-02-19 20:12:00,3.176 2014-02-19 20:17:00,2.722 2014-02-19 20:22:00,4.484 2014-02-19 20:27:00,2.7260000000000004 2014-02-19 20:32:00,3.174 2014-02-19 20:37:00,2.708 2014-02-19 20:42:00,3.1839999999999997 2014-02-19 20:47:00,5.242000000000001 2014-02-19 20:52:00,3.3760000000000003 2014-02-19 20:57:00,3.06 2014-02-19 21:02:00,3.4 2014-02-19 21:07:00,8.73 2014-02-19 21:12:00,5.936 2014-02-19 21:17:00,3.97 2014-02-19 21:22:00,4.846 2014-02-19 21:27:00,3.466 2014-02-19 21:32:00,5.886 2014-02-19 21:37:00,3.4019999999999997 2014-02-19 21:42:00,3.96 2014-02-19 21:47:00,3.634 2014-02-19 21:52:00,4.408 2014-02-19 21:57:00,6.476 2014-02-19 22:02:00,3.0839999999999996 2014-02-19 22:07:00,2.734 2014-02-19 22:12:00,4.434 2014-02-19 22:17:00,2.77 2014-02-19 22:22:00,3.108 2014-02-19 22:27:00,2.676 2014-02-19 22:32:00,3.158 2014-02-19 22:37:00,2.7260000000000004 2014-02-19 22:42:00,3.142 2014-02-19 22:47:00,2.708 2014-02-19 22:52:00,3.234 2014-02-19 22:57:00,4.7360000000000015 2014-02-19 23:02:00,59.083999999999996 2014-02-19 23:07:00,52.916000000000004 2014-02-19 23:12:00,52.61600000000001 2014-02-19 23:17:00,6.6160000000000005 2014-02-19 23:22:00,4.592 2014-02-19 23:27:00,5.066 2014-02-19 23:32:00,4.71 2014-02-19 23:37:00,5.88 2014-02-19 23:42:00,4.302 2014-02-19 23:47:00,4.013999999999999 2014-02-19 23:52:00,6.4639999999999995 2014-02-19 23:57:00,4.238 2014-02-20 00:02:00,4.6339999999999995 2014-02-20 00:07:00,5.507999999999999 2014-02-20 00:12:00,3.216 2014-02-20 00:17:00,4.4860000000000015 2014-02-20 00:22:00,3.1839999999999997 2014-02-20 00:27:00,2.728 2014-02-20 00:32:00,3.21 2014-02-20 00:37:00,2.742 2014-02-20 00:42:00,3.21 2014-02-20 00:47:00,3.3160000000000003 2014-02-20 00:52:00,27.965999999999998 2014-02-20 00:57:00,65.554 2014-02-20 01:02:00,53.722 2014-02-20 01:07:00,20.334 2014-02-20 01:12:00,5.896 2014-02-20 01:17:00,6.976 2014-02-20 01:22:00,3.15 2014-02-20 01:27:00,7.058 2014-02-20 01:32:00,4.078 2014-02-20 01:37:00,4.3839999999999995 2014-02-20 01:42:00,58.62600000000001 2014-02-20 01:47:00,55.31399999999999 2014-02-20 01:52:00,49.668 2014-02-20 01:57:00,3.324 2014-02-20 02:02:00,3.81 2014-02-20 02:07:00,4.0360000000000005 2014-02-20 02:12:00,4.3180000000000005 2014-02-20 02:17:00,14.5 2014-02-20 02:22:00,6.1160000000000005 2014-02-20 02:27:00,6.742000000000001 2014-02-20 02:32:00,4.434 2014-02-20 02:37:00,5.756 2014-02-20 02:42:00,4.11 2014-02-20 02:47:00,3.68 2014-02-20 02:52:00,4.042 2014-02-20 02:57:00,3.7260000000000004 2014-02-20 03:02:00,5.216 2014-02-20 03:07:00,2.5340000000000003 2014-02-20 03:12:00,2.908 2014-02-20 03:17:00,3.68 2014-02-20 03:22:00,2.8080000000000003 2014-02-20 03:27:00,2.342 2014-02-20 03:32:00,2.8080000000000003 2014-02-20 03:37:00,2.314 2014-02-20 03:42:00,2.73 2014-02-20 03:47:00,2.2359999999999998 2014-02-20 03:52:00,2.6460000000000004 2014-02-20 03:57:00,2.26 2014-02-20 04:02:00,2.676 2014-02-20 04:07:00,2.24 2014-02-20 04:12:00,3.904 2014-02-20 04:17:00,2.178 2014-02-20 04:22:00,2.5839999999999996 2014-02-20 04:27:00,2.492 2014-02-20 04:32:00,2.7 2014-02-20 04:37:00,2.242 2014-02-20 04:42:00,2.696 2014-02-20 04:47:00,2.184 2014-02-20 04:52:00,2.6180000000000003 2014-02-20 04:57:00,2.2880000000000003 2014-02-20 05:02:00,2.734 2014-02-20 05:07:00,4.9 2014-02-20 05:12:00,4.524 2014-02-20 05:17:00,2.7760000000000002 2014-02-20 05:22:00,3.1839999999999997 2014-02-20 05:27:00,2.786 2014-02-20 05:32:00,3.158 2014-02-20 05:37:00,4.628 2014-02-20 05:42:00,3.21 2014-02-20 05:47:00,2.762 2014-02-20 05:52:00,3.19 2014-02-20 05:57:00,2.72 2014-02-20 06:02:00,3.11 2014-02-20 06:07:00,2.616 2014-02-20 06:12:00,25.566 2014-02-20 06:17:00,68.38600000000001 2014-02-20 06:22:00,56.542 2014-02-20 06:27:00,23.2 2014-02-20 06:32:00,4.418 2014-02-20 06:37:00,5.13 2014-02-20 06:42:00,4.762 2014-02-20 06:47:00,5.654 2014-02-20 06:52:00,8.7 2014-02-20 06:57:00,3.918 2014-02-20 07:02:00,4.55 2014-02-20 07:07:00,5.26 2014-02-20 07:12:00,6.234 2014-02-20 07:17:00,4.592 2014-02-20 07:22:00,3.176 2014-02-20 07:27:00,2.674 2014-02-20 07:32:00,3.108 2014-02-20 07:37:00,2.6180000000000003 2014-02-20 07:42:00,2.99 2014-02-20 07:47:00,2.8080000000000003 2014-02-20 07:52:00,2.8339999999999996 2014-02-20 07:57:00,2.42 2014-02-20 08:02:00,2.738 2014-02-20 08:07:00,2.292 2014-02-20 08:12:00,2.6719999999999997 2014-02-20 08:17:00,3.5460000000000003 2014-02-20 08:22:00,2.6260000000000003 2014-02-20 08:27:00,2.184 2014-02-20 08:32:00,2.6 2014-02-20 08:37:00,2.2 2014-02-20 08:42:00,2.572 2014-02-20 08:47:00,2.2 2014-02-20 08:52:00,2.596 2014-02-20 08:57:00,2.27 2014-02-20 09:02:00,2.608 2014-02-20 09:07:00,2.2159999999999997 2014-02-20 09:12:00,3.85 2014-02-20 09:17:00,2.634 2014-02-20 09:22:00,2.694 2014-02-20 09:27:00,2.32 2014-02-20 09:32:00,2.488 2014-02-20 09:37:00,2.066 2014-02-20 09:42:00,2.44 2014-02-20 09:47:00,2.06 2014-02-20 09:52:00,2.384 2014-02-20 09:57:00,2.1 2014-02-20 10:02:00,5.1339999999999995 2014-02-20 10:07:00,2.734 2014-02-20 10:12:00,3.156 2014-02-20 10:17:00,2.71 2014-02-20 10:22:00,4.376 2014-02-20 10:27:00,2.608 2014-02-20 10:32:00,2.958 2014-02-20 10:37:00,2.4659999999999997 2014-02-20 10:42:00,2.8739999999999997 2014-02-20 10:47:00,2.576 2014-02-20 10:52:00,2.9160000000000004 2014-02-20 10:57:00,2.4659999999999997 2014-02-20 11:02:00,2.7760000000000002 2014-02-20 11:07:00,2.342 2014-02-20 11:12:00,2.722 2014-02-20 11:17:00,3.55 2014-02-20 11:22:00,2.722 2014-02-20 11:27:00,2.302 2014-02-20 11:32:00,2.758 2014-02-20 11:37:00,2.324 2014-02-20 11:42:00,2.766 2014-02-20 11:47:00,2.266 2014-02-20 11:52:00,8.866 2014-02-20 11:57:00,2.7239999999999998 2014-02-20 12:02:00,3.1180000000000003 2014-02-20 12:07:00,2.6660000000000004 2014-02-20 12:12:00,3.05 2014-02-20 12:17:00,3.9139999999999997 2014-02-20 12:22:00,2.878 2014-02-20 12:27:00,2.4219999999999997 2014-02-20 12:32:00,2.7260000000000004 2014-02-20 12:37:00,2.352 2014-02-20 12:42:00,2.742 2014-02-20 12:47:00,6.7620000000000005 2014-02-20 12:52:00,7.28 2014-02-20 12:57:00,2.97 2014-02-20 13:02:00,3.216 2014-02-20 13:07:00,2.786 2014-02-20 13:12:00,4.322 2014-02-20 13:17:00,2.524 2014-02-20 13:22:00,2.842 2014-02-20 13:27:00,2.45 2014-02-20 13:32:00,2.764 2014-02-20 13:37:00,2.35 2014-02-20 13:42:00,2.7039999999999997 2014-02-20 13:47:00,2.292 2014-02-20 13:52:00,2.708 2014-02-20 13:57:00,2.2840000000000003 2014-02-20 14:02:00,2.674 2014-02-20 14:07:00,3.534 2014-02-20 14:12:00,2.592 2014-02-20 14:17:00,2.166 2014-02-20 14:22:00,2.658 2014-02-20 14:27:00,2.25 2014-02-20 14:32:00,2.634 2014-02-20 14:37:00,2.2840000000000003 2014-02-20 14:42:00,2.5839999999999996 2014-02-20 14:47:00,2.33 2014-02-20 14:52:00,7.284 2014-02-20 14:57:00,2.8339999999999996 2014-02-20 15:02:00,3.1719999999999997 2014-02-20 15:07:00,2.6839999999999997 2014-02-20 15:12:00,4.32 2014-02-20 15:17:00,2.548 2014-02-20 15:22:00,2.9 2014-02-20 15:27:00,2.458 2014-02-20 15:32:00,2.8080000000000003 2014-02-20 15:37:00,2.376 2014-02-20 15:42:00,2.7760000000000002 2014-02-20 15:47:00,2.3040000000000003 2014-02-20 15:52:00,2.7539999999999996 2014-02-20 15:57:00,2.324 2014-02-20 16:02:00,25.3 2014-02-20 16:07:00,64.79 2014-02-20 16:12:00,52.52 2014-02-20 16:17:00,20.168 2014-02-20 16:22:00,4.73 2014-02-20 16:27:00,4.1339999999999995 2014-02-20 16:32:00,3.634 2014-02-20 16:37:00,4.772 2014-02-20 16:42:00,3.338 2014-02-20 16:47:00,2.636 2014-02-20 16:52:00,3.44 2014-02-20 16:57:00,3.01 2014-02-20 17:02:00,3.2939999999999996 2014-02-20 17:07:00,3.764 2014-02-20 17:12:00,3.716 2014-02-20 17:17:00,2.016 2014-02-20 17:22:00,2.424 2014-02-20 17:27:00,2.026 2014-02-20 17:32:00,2.35 2014-02-20 17:37:00,2.026 2014-02-20 17:42:00,2.366 2014-02-20 17:47:00,1.99 2014-02-20 17:52:00,2.384 2014-02-20 17:57:00,2.146 2014-02-20 18:02:00,2.394 2014-02-20 18:07:00,2.0340000000000003 2014-02-20 18:12:00,3.612 2014-02-20 18:17:00,2.0780000000000003 2014-02-20 18:22:00,2.418 2014-02-20 18:27:00,2.094 2014-02-20 18:32:00,2.484 2014-02-20 18:37:00,2.184 2014-02-20 18:42:00,2.5580000000000003 2014-02-20 18:47:00,2.178 2014-02-20 18:52:00,2.4659999999999997 2014-02-20 18:57:00,2.184 2014-02-20 19:02:00,2.46 2014-02-20 19:07:00,2.106 2014-02-20 19:12:00,3.594 2014-02-20 19:17:00,41.716 2014-02-20 19:22:00,57.114 2014-02-20 19:27:00,53.19600000000001 2014-02-20 19:32:00,9.984 2014-02-20 19:37:00,2.716 2014-02-20 19:42:00,4.144 2014-02-20 19:47:00,2.9160000000000004 2014-02-20 19:52:00,5.034 2014-02-20 19:57:00,2.6060000000000003 2014-02-20 20:02:00,2.762 2014-02-20 20:07:00,2.658 2014-02-20 20:12:00,4.35 2014-02-20 20:17:00,2.7939999999999996 2014-02-20 20:22:00,3.05 2014-02-20 20:27:00,3.8939999999999997 2014-02-20 20:32:00,2.256 2014-02-20 20:37:00,1.922 2014-02-20 20:42:00,2.25 2014-02-20 20:47:00,1.91 2014-02-20 20:52:00,2.224 2014-02-20 20:57:00,2.654 2014-02-20 21:02:00,2.978 2014-02-20 21:07:00,4.334 2014-02-20 21:12:00,2.972 2014-02-20 21:17:00,2.59 2014-02-20 21:22:00,3.156 2014-02-20 21:27:00,2.884 2014-02-20 21:32:00,3.522 2014-02-20 21:37:00,3.134 2014-02-20 21:42:00,3.016 2014-02-20 21:47:00,3.096 2014-02-20 21:52:00,3.4939999999999998 2014-02-20 21:57:00,4.64 2014-02-20 22:02:00,4.2780000000000005 2014-02-20 22:07:00,1.9240000000000002 2014-02-20 22:12:00,2.234 2014-02-20 22:17:00,1.9680000000000002 2014-02-20 22:22:00,58.508 2014-02-20 22:27:00,51.88399999999999 2014-02-20 22:32:00,47.733999999999995 2014-02-20 22:37:00,3.7319999999999998 2014-02-20 22:42:00,2.434 2014-02-20 22:47:00,2.104 2014-02-20 22:52:00,2.438 2014-02-20 22:57:00,2.134 2014-02-20 23:02:00,2.356 2014-02-20 23:07:00,3.3160000000000003 2014-02-20 23:12:00,2.36 2014-02-20 23:17:00,2.01 2014-02-20 23:22:00,2.39 2014-02-20 23:27:00,2.076 2014-02-20 23:32:00,2.356 2014-02-20 23:37:00,2.0380000000000003 2014-02-20 23:42:00,2.4219999999999997 2014-02-20 23:47:00,2.2159999999999997 2014-02-20 23:52:00,2.364 2014-02-20 23:57:00,38.08 2014-02-21 00:02:00,60.402 2014-02-21 00:07:00,52.478 2014-02-21 00:12:00,13.094000000000001 2014-02-21 00:17:00,2.388 2014-02-21 00:22:00,3.716 2014-02-21 00:27:00,1.9680000000000002 2014-02-21 00:32:00,2.316 2014-02-21 00:37:00,1.916 2014-02-21 00:42:00,2.256 2014-02-21 00:47:00,2.01 2014-02-21 00:52:00,3.9339999999999997 2014-02-21 00:57:00,64.882 2014-02-21 01:02:00,52.378 2014-02-21 01:07:00,59.606 2014-02-21 01:12:00,63.968 2014-02-21 01:17:00,53.13 2014-02-21 01:22:00,18.994 2014-02-21 01:27:00,2.694 2014-02-21 01:32:00,4.816 2014-02-21 01:37:00,2.546 2014-02-21 01:42:00,3.042 2014-02-21 01:47:00,2.846 2014-02-21 01:52:00,3.094 2014-02-21 01:57:00,6.25 2014-02-21 02:02:00,3.216 2014-02-21 02:07:00,3.9339999999999997 2014-02-21 02:12:00,3.24 2014-02-21 02:17:00,5.846 2014-02-21 02:22:00,3.0060000000000002 2014-02-21 02:27:00,2.484 2014-02-21 02:32:00,3.156 2014-02-21 02:37:00,2.9 2014-02-21 02:42:00,3.216 2014-02-21 02:47:00,4.716 2014-02-21 02:52:00,2.2840000000000003 2014-02-21 02:57:00,1.992 2014-02-21 03:02:00,2.24 2014-02-21 03:07:00,2.654 2014-02-21 03:12:00,27.636 2014-02-21 03:17:00,64.304 2014-02-21 03:22:00,52.55 2014-02-21 03:27:00,18.668 2014-02-21 03:32:00,2.988 2014-02-21 03:37:00,3.74 2014-02-21 03:42:00,3.138 2014-02-21 03:47:00,4.474 2014-02-21 03:52:00,3.0439999999999996 2014-02-21 03:57:00,2.41 2014-02-21 04:02:00,3.0239999999999996 2014-02-21 04:07:00,2.7060000000000004 2014-02-21 04:12:00,4.303999999999999 2014-02-21 04:17:00,3.87 2014-02-21 04:22:00,2.21 2014-02-21 04:27:00,1.9340000000000002 2014-02-21 04:32:00,2.266 2014-02-21 04:37:00,1.944 2014-02-21 04:42:00,2.266 2014-02-21 04:47:00,1.944 2014-02-21 04:52:00,2.24 2014-02-21 04:57:00,2.056 2014-02-21 05:02:00,2.326 2014-02-21 05:07:00,2.022 2014-02-21 05:12:00,3.556 2014-02-21 05:17:00,1.996 2014-02-21 05:22:00,2.326 2014-02-21 05:27:00,2.046 2014-02-21 05:32:00,2.366 2014-02-21 05:37:00,4.71 2014-02-21 05:42:00,2.908 2014-02-21 05:47:00,2.62 2014-02-21 05:52:00,3.068 2014-02-21 05:57:00,2.6460000000000004 2014-02-21 06:02:00,3.0039999999999996 2014-02-21 06:07:00,2.55 2014-02-21 06:12:00,2.85 2014-02-21 06:17:00,58.95399999999999 2014-02-21 06:22:00,52.166000000000004 2014-02-21 06:27:00,53.15 2014-02-21 06:32:00,2.676 2014-02-21 06:37:00,2.23 2014-02-21 06:42:00,2.596 2014-02-21 06:47:00,2.158 2014-02-21 06:52:00,2.55 2014-02-21 06:57:00,2.234 2014-02-21 07:02:00,2.5839999999999996 2014-02-21 07:07:00,2.21 2014-02-21 07:12:00,2.758 2014-02-21 07:17:00,3.3160000000000003 2014-02-21 07:22:00,2.6239999999999997 2014-02-21 07:27:00,2.254 2014-02-21 07:32:00,3.5460000000000003 2014-02-21 07:37:00,66.858 2014-02-21 07:42:00,53.03 2014-02-21 07:47:00,37.994 2014-02-21 07:52:00,3.208 2014-02-21 07:57:00,3.846 2014-02-21 08:02:00,3.7239999999999998 2014-02-21 08:07:00,2.8160000000000003 2014-02-21 08:12:00,4.8839999999999995 2014-02-21 08:17:00,2.6 2014-02-21 08:22:00,9.154 2014-02-21 08:27:00,3.2939999999999996 2014-02-21 08:32:00,3.758 2014-02-21 08:37:00,6.5360000000000005 2014-02-21 08:42:00,3.092 2014-02-21 08:47:00,2.6919999999999997 2014-02-21 08:52:00,6.8839999999999995 2014-02-21 08:57:00,2.722 2014-02-21 09:02:00,3.02 2014-02-21 09:07:00,3.838 2014-02-21 09:12:00,5.516 2014-02-21 09:17:00,3.042 2014-02-21 09:22:00,2.9760000000000004 2014-02-21 09:27:00,4.466 2014-02-21 09:32:00,3.136 2014-02-21 09:37:00,2.638 2014-02-21 09:42:00,2.9760000000000004 2014-02-21 09:47:00,2.4859999999999998 2014-02-21 09:52:00,2.842 2014-02-21 09:57:00,2.45 2014-02-21 10:02:00,2.772 2014-02-21 10:07:00,2.366 2014-02-21 10:12:00,3.9960000000000004 2014-02-21 10:17:00,2.32 2014-02-21 10:22:00,2.654 2014-02-21 10:27:00,2.1919999999999997 2014-02-21 10:32:00,2.658 2014-02-21 10:37:00,2.25 2014-02-21 10:42:00,2.658 2014-02-21 10:47:00,2.2159999999999997 2014-02-21 10:52:00,2.6260000000000003 2014-02-21 10:57:00,2.258 2014-02-21 11:02:00,2.61 2014-02-21 11:07:00,2.1959999999999997 2014-02-21 11:12:00,2.562 2014-02-21 11:17:00,3.534 2014-02-21 11:22:00,2.66 2014-02-21 11:27:00,2.292 2014-02-21 11:32:00,2.55 2014-02-21 11:37:00,2.1919999999999997 2014-02-21 11:42:00,2.5340000000000003 2014-02-21 11:47:00,2.184 2014-02-21 11:52:00,2.476 2014-02-21 11:57:00,2.202 2014-02-21 12:02:00,2.556 2014-02-21 12:07:00,2.228 2014-02-21 12:12:00,6.666 2014-02-21 12:17:00,2.694 2014-02-21 12:22:00,3.09 2014-02-21 12:27:00,2.634 2014-02-21 12:32:00,2.86 2014-02-21 12:37:00,2.492 2014-02-21 12:42:00,2.78 2014-02-21 12:47:00,2.354 2014-02-21 12:52:00,2.694 2014-02-21 12:57:00,2.342 2014-02-21 13:02:00,2.576 2014-02-21 13:07:00,2.158 2014-02-21 13:12:00,3.838 2014-02-21 13:17:00,2.1959999999999997 2014-02-21 13:22:00,2.59 2014-02-21 13:27:00,2.184 2014-02-21 13:32:00,2.524 2014-02-21 13:37:00,2.19 2014-02-21 13:42:00,5.0760000000000005 2014-02-21 13:47:00,2.742 2014-02-21 13:52:00,3.1919999999999997 2014-02-21 13:57:00,2.758 2014-02-21 14:02:00,3.016 2014-02-21 14:07:00,2.5580000000000003 2014-02-21 14:12:00,2.924 2014-02-21 14:17:00,5.28 2014-02-21 14:22:00,4.508 2014-02-21 14:27:00,2.7260000000000004 2014-02-21 14:32:00,9.226 2014-02-21 14:37:00,4.808 2014-02-21 14:42:00,3.134 2014-02-21 14:47:00,2.65 2014-02-21 14:52:00,3.008 2014-02-21 14:57:00,2.582 2014-02-21 15:02:00,2.842 2014-02-21 15:07:00,2.384 2014-02-21 15:12:00,2.784 2014-02-21 15:17:00,3.634 2014-02-21 15:22:00,2.73 2014-02-21 15:27:00,2.312 2014-02-21 15:32:00,2.576 2014-02-21 15:37:00,2.146 2014-02-21 15:42:00,2.5780000000000003 2014-02-21 15:47:00,2.16 2014-02-21 15:52:00,2.5580000000000003 2014-02-21 15:57:00,2.226 2014-02-21 16:02:00,2.592 2014-02-21 16:07:00,2.242 2014-02-21 16:12:00,2.622 2014-02-21 16:17:00,3.67 2014-02-21 16:22:00,2.634 2014-02-21 16:27:00,2.258 2014-02-21 16:32:00,2.594 2014-02-21 16:37:00,38.366 2014-02-21 16:42:00,60.4 2014-02-21 16:47:00,52.62600000000001 2014-02-21 16:52:00,13.936 2014-02-21 16:57:00,2.964 2014-02-21 17:02:00,4.226 2014-02-21 17:07:00,4.33 2014-02-21 17:12:00,3.24 2014-02-21 17:17:00,4.676 2014-02-21 17:22:00,2.838 2014-02-21 17:27:00,2.938 2014-02-21 17:32:00,3.122 2014-02-21 17:37:00,2.8139999999999996 2014-02-21 17:42:00,4.328 2014-02-21 17:47:00,2.056 2014-02-21 17:52:00,2.39 2014-02-21 17:57:00,2.23 2014-02-21 18:02:00,2.456 2014-02-21 18:07:00,2.0780000000000003 2014-02-21 18:12:00,2.6 2014-02-21 18:17:00,3.194 2014-02-21 18:22:00,2.412 2014-02-21 18:27:00,2.106 2014-02-21 18:32:00,2.412 2014-02-21 18:37:00,2.1519999999999997 2014-02-21 18:42:00,2.494 2014-02-21 18:47:00,2.22 2014-02-21 18:52:00,2.484 2014-02-21 18:57:00,2.206 2014-02-21 19:02:00,2.484 2014-02-21 19:07:00,2.266 2014-02-21 19:12:00,3.9160000000000004 2014-02-21 19:17:00,2.128 2014-02-21 19:22:00,2.516 2014-02-21 19:27:00,2.14 2014-02-21 19:32:00,2.428 2014-02-21 19:37:00,2.162 2014-02-21 19:42:00,2.444 2014-02-21 19:47:00,2.156 2014-02-21 19:52:00,2.494 2014-02-21 19:57:00,2.234 2014-02-21 20:02:00,2.444 2014-02-21 20:07:00,2.256 2014-02-21 20:12:00,3.734 2014-02-21 20:17:00,2.106 2014-02-21 20:22:00,2.384 2014-02-21 20:27:00,2.088 2014-02-21 20:32:00,2.388 2014-02-21 20:37:00,2.112 2014-02-21 20:42:00,2.406 2014-02-21 20:47:00,2.14 2014-02-21 20:52:00,2.412 2014-02-21 20:57:00,2.166 2014-02-21 21:02:00,2.418 2014-02-21 21:07:00,2.134 2014-02-21 21:12:00,3.766 2014-02-21 21:17:00,2.084 2014-02-21 21:22:00,3.15 2014-02-21 21:27:00,3.55 2014-02-21 21:32:00,2.34 2014-02-21 21:37:00,2.026 2014-02-21 21:42:00,2.344 2014-02-21 21:47:00,2.09 2014-02-21 21:52:00,2.362 2014-02-21 21:57:00,3.762 2014-02-21 22:02:00,2.294 2014-02-21 22:07:00,2.0340000000000003 2014-02-21 22:12:00,2.29 2014-02-21 22:17:00,2.022 2014-02-21 22:22:00,4.276 2014-02-21 22:27:00,2.028 2014-02-21 22:32:00,2.3 2014-02-21 22:37:00,2.056 2014-02-21 22:42:00,25.524 2014-02-21 22:47:00,64.19800000000001 2014-02-21 22:52:00,52.666000000000004 2014-02-21 22:57:00,25.48 2014-02-21 23:02:00,70.672 2014-02-21 23:07:00,53.742 2014-02-21 23:12:00,28.498 2014-02-21 23:17:00,5.766 2014-02-21 23:22:00,3.05 2014-02-21 23:27:00,2.4619999999999997 2014-02-21 23:32:00,4.024 2014-02-21 23:37:00,67.204 2014-02-21 23:42:00,53.141999999999996 2014-02-21 23:47:00,42.571999999999996 2014-02-21 23:52:00,57.86 2014-02-21 23:57:00,75.24600000000002 2014-02-22 00:02:00,99.66799999999999 2014-02-22 00:07:00,70.582 2014-02-22 00:12:00,28.51 2014-02-22 00:17:00,2.45 2014-02-22 00:22:00,2.884 2014-02-22 00:27:00,38.874 2014-02-22 00:32:00,61.258 2014-02-22 00:37:00,53.483999999999995 2014-02-22 00:42:00,29.218000000000004 2014-02-22 00:47:00,4.508 2014-02-22 00:52:00,3.8960000000000004 2014-02-22 00:57:00,3.266 2014-02-22 01:02:00,5.343999999999999 2014-02-22 01:07:00,2.8760000000000003 2014-02-22 01:12:00,3.322 2014-02-22 01:17:00,3.134 2014-02-22 01:22:00,4.7 2014-02-22 01:27:00,14.384 2014-02-22 01:32:00,8.658 2014-02-22 01:37:00,4.75 2014-02-22 01:42:00,4.684 2014-02-22 01:47:00,5.374 2014-02-22 01:52:00,4.708 2014-02-22 01:57:00,5.7620000000000005 2014-02-22 02:02:00,4.334 2014-02-22 02:07:00,3.784 2014-02-22 02:12:00,4.34 2014-02-22 02:17:00,5.27 2014-02-22 02:22:00,4.092 2014-02-22 02:27:00,5.148 2014-02-22 02:32:00,3.55 2014-02-22 02:37:00,3.15 2014-02-22 02:42:00,4.684 2014-02-22 02:47:00,2.242 2014-02-22 02:52:00,2.596 2014-02-22 02:57:00,2.344 2014-02-22 03:02:00,2.64 2014-02-22 03:07:00,2.384 2014-02-22 03:12:00,2.616 2014-02-22 03:17:00,2.5 2014-02-22 03:22:00,3.81 2014-02-22 03:27:00,2.244 2014-02-22 03:32:00,2.522 2014-02-22 03:37:00,2.206 2014-02-22 03:42:00,2.478 2014-02-22 03:47:00,2.184 2014-02-22 03:52:00,2.49 2014-02-22 03:57:00,2.278 2014-02-22 04:02:00,2.512 2014-02-22 04:07:00,3.4960000000000004 2014-02-22 04:12:00,2.516 2014-02-22 04:17:00,2.2840000000000003 2014-02-22 04:22:00,2.572 2014-02-22 04:27:00,2.3 2014-02-22 04:32:00,2.59 2014-02-22 04:37:00,2.21 2014-02-22 04:42:00,2.45 2014-02-22 04:47:00,2.006 2014-02-22 04:52:00,2.306 2014-02-22 04:57:00,2.044 2014-02-22 05:02:00,2.34 2014-02-22 05:07:00,2.1 2014-02-22 05:12:00,2.374 2014-02-22 05:17:00,2.126 2014-02-22 05:22:00,3.642 2014-02-22 05:27:00,2.09 2014-02-22 05:32:00,2.372 2014-02-22 05:37:00,2.134 2014-02-22 05:42:00,2.356 2014-02-22 05:47:00,2.026 2014-02-22 05:52:00,2.35 2014-02-22 05:57:00,2.056 2014-02-22 06:02:00,2.258 2014-02-22 06:07:00,3.3819999999999997 2014-02-22 06:12:00,2.29 2014-02-22 06:17:00,2.004 2014-02-22 06:22:00,2.306 2014-02-22 06:27:00,2.04 2014-02-22 06:32:00,2.334 2014-02-22 06:37:00,2.072 2014-02-22 06:42:00,2.322 2014-02-22 06:47:00,2.056 2014-02-22 06:52:00,2.334 2014-02-22 06:57:00,2.154 2014-02-22 07:02:00,2.366 2014-02-22 07:07:00,2.09 2014-02-22 07:12:00,2.31 2014-02-22 07:17:00,3.312 2014-02-22 07:22:00,2.326 2014-02-22 07:27:00,2.05 2014-02-22 07:32:00,2.384 2014-02-22 07:37:00,2.094 2014-02-22 07:42:00,2.406 2014-02-22 07:47:00,2.094 2014-02-22 07:52:00,2.39 2014-02-22 07:57:00,2.158 2014-02-22 08:02:00,2.412 2014-02-22 08:07:00,3.1439999999999997 2014-02-22 08:12:00,2.7439999999999998 2014-02-22 08:17:00,2.112 2014-02-22 08:22:00,2.4 2014-02-22 08:27:00,2.138 2014-02-22 08:32:00,2.44 2014-02-22 08:37:00,2.134 2014-02-22 08:42:00,2.434 2014-02-22 08:47:00,2.14 2014-02-22 08:52:00,2.4659999999999997 2014-02-22 08:57:00,2.278 2014-02-22 09:02:00,2.456 2014-02-22 09:07:00,2.366 2014-02-22 09:12:00,3.528 2014-02-22 09:17:00,2.488 2014-02-22 09:22:00,2.36 2014-02-22 09:27:00,2.046 2014-02-22 09:32:00,2.36 2014-02-22 09:37:00,2.05 2014-02-22 09:42:00,2.366 2014-02-22 09:47:00,2.06 2014-02-22 09:52:00,2.362 2014-02-22 09:57:00,2.066 2014-02-22 10:02:00,2.34 2014-02-22 10:07:00,2.072 2014-02-22 10:12:00,2.34 2014-02-22 10:17:00,2.5380000000000003 2014-02-22 10:22:00,3.18 2014-02-22 10:27:00,2.076 2014-02-22 10:32:00,2.296 2014-02-22 10:37:00,2.026 2014-02-22 10:42:00,2.35 2014-02-22 10:47:00,2.056 2014-02-22 10:52:00,2.5340000000000003 2014-02-22 10:57:00,2.05 2014-02-22 11:02:00,2.338 2014-02-22 11:07:00,2.006 2014-02-22 11:12:00,3.5439999999999996 2014-02-22 11:17:00,2.006 2014-02-22 11:22:00,2.326 2014-02-22 11:27:00,2.084 2014-02-22 11:32:00,2.378 2014-02-22 11:37:00,2.122 2014-02-22 11:42:00,2.39 2014-02-22 11:47:00,2.094 2014-02-22 11:52:00,2.388 2014-02-22 11:57:00,2.166 2014-02-22 12:02:00,2.4 2014-02-22 12:07:00,2.156 2014-02-22 12:12:00,3.698 2014-02-22 12:17:00,2.11 2014-02-22 12:22:00,2.4 2014-02-22 12:27:00,2.128 2014-02-22 12:32:00,2.412 2014-02-22 12:37:00,2.116 2014-02-22 12:42:00,2.394 2014-02-22 12:47:00,2.122 2014-02-22 12:52:00,2.444 2014-02-22 12:57:00,2.194 2014-02-22 13:02:00,2.428 2014-02-22 13:07:00,2.128 2014-02-22 13:12:00,2.378 2014-02-22 13:17:00,2.0780000000000003 2014-02-22 13:22:00,3.716 2014-02-22 13:27:00,2.096 2014-02-22 13:32:00,2.428 2014-02-22 13:37:00,2.102 2014-02-22 13:42:00,2.388 2014-02-22 13:47:00,2.074 2014-02-22 13:52:00,2.34 2014-02-22 13:57:00,2.1180000000000003 2014-02-22 14:02:00,2.39 2014-02-22 14:07:00,2.102 2014-02-22 14:12:00,2.384 2014-02-22 14:17:00,3.388 2014-02-22 14:22:00,2.4 2014-02-22 14:27:00,2.05 2014-02-22 14:32:00,2.356 2014-02-22 14:37:00,2.056 2014-02-22 14:42:00,2.356 2014-02-22 14:47:00,2.09 2014-02-22 14:52:00,2.35 2014-02-22 14:57:00,2.166 2014-02-22 15:02:00,2.434 2014-02-22 15:07:00,2.16 2014-02-22 15:12:00,2.412 2014-02-22 15:17:00,2.138 2014-02-22 15:22:00,3.728 2014-02-22 15:27:00,2.122 2014-02-22 15:32:00,2.384 2014-02-22 15:37:00,2.11 2014-02-22 15:42:00,2.418 2014-02-22 15:47:00,2.116 2014-02-22 15:52:00,2.4 2014-02-22 15:57:00,2.166 2014-02-22 16:02:00,2.338 2014-02-22 16:07:00,2.088 2014-02-22 16:12:00,2.266 2014-02-22 16:17:00,3.3160000000000003 2014-02-22 16:22:00,2.444 2014-02-22 16:27:00,1.91 2014-02-22 16:32:00,2.208 2014-02-22 16:37:00,1.942 2014-02-22 16:42:00,2.2119999999999997 2014-02-22 16:47:00,1.9380000000000002 2014-02-22 16:52:00,2.2159999999999997 2014-02-22 16:57:00,1.976 2014-02-22 17:02:00,2.256 2014-02-22 17:07:00,1.984 2014-02-22 17:12:00,2.272 2014-02-22 17:17:00,1.966 2014-02-22 17:22:00,3.6239999999999997 2014-02-22 17:27:00,2.032 2014-02-22 17:32:00,2.266 2014-02-22 17:37:00,1.96 2014-02-22 17:42:00,2.25 2014-02-22 17:47:00,1.956 2014-02-22 17:52:00,2.272 2014-02-22 17:57:00,2.028 2014-02-22 18:02:00,2.276 2014-02-22 18:07:00,2.01 2014-02-22 18:12:00,2.2880000000000003 2014-02-22 18:17:00,3.2239999999999998 2014-02-22 18:22:00,2.306 2014-02-22 18:27:00,2.056 2014-02-22 18:32:00,2.246 2014-02-22 18:37:00,2.004 2014-02-22 18:42:00,2.306 2014-02-22 18:47:00,2.044 2014-02-22 18:52:00,2.356 2014-02-22 18:57:00,2.134 2014-02-22 19:02:00,2.366 2014-02-22 19:07:00,2.116 2014-02-22 19:12:00,2.3680000000000003 2014-02-22 19:17:00,3.35 2014-02-22 19:22:00,2.366 2014-02-22 19:27:00,2.096 2014-02-22 19:32:00,2.326 2014-02-22 19:37:00,2.0340000000000003 2014-02-22 19:42:00,2.316 2014-02-22 19:47:00,2.022 2014-02-22 19:52:00,2.356 2014-02-22 19:57:00,2.084 2014-02-22 20:02:00,2.3 2014-02-22 20:07:00,2.084 2014-02-22 20:12:00,2.35 2014-02-22 20:17:00,2.31 2014-02-22 20:22:00,2.25 2014-02-22 20:27:00,1.984 2014-02-22 20:32:00,2.2640000000000002 2014-02-22 20:37:00,2.044 2014-02-22 20:42:00,2.356 2014-02-22 20:47:00,2.062 2014-02-22 20:52:00,2.344 2014-02-22 20:57:00,2.0780000000000003 2014-02-22 21:02:00,2.29 2014-02-22 21:07:00,2.04 2014-02-22 21:12:00,2.508 2014-02-22 21:17:00,1.966 2014-02-22 21:22:00,2.256 2014-02-22 21:27:00,2.006 2014-02-22 21:32:00,2.266 2014-02-22 21:37:00,1.984 2014-02-22 21:42:00,2.316 2014-02-22 21:47:00,2.05 2014-02-22 21:52:00,2.408 2014-02-22 21:57:00,3.5 2014-02-22 22:02:00,2.2159999999999997 2014-02-22 22:07:00,1.956 2014-02-22 22:12:00,2.228 2014-02-22 22:17:00,1.952 2014-02-22 22:22:00,3.572 2014-02-22 22:27:00,1.8940000000000001 2014-02-22 22:32:00,2.2119999999999997 2014-02-22 22:37:00,1.96 2014-02-22 22:42:00,2.2 2014-02-22 22:47:00,1.972 2014-02-22 22:52:00,2.2119999999999997 2014-02-22 22:57:00,2.028 2014-02-22 23:02:00,2.234 2014-02-22 23:07:00,1.9680000000000002 2014-02-22 23:12:00,3.6 2014-02-22 23:17:00,2.006 2014-02-22 23:22:00,2.286 2014-02-22 23:27:00,2.0380000000000003 2014-02-22 23:32:00,2.3 2014-02-22 23:37:00,1.9880000000000002 2014-02-22 23:42:00,2.262 2014-02-22 23:47:00,2.012 2014-02-22 23:52:00,2.322 2014-02-22 23:57:00,2.106 2014-02-23 00:02:00,2.332 2014-02-23 00:07:00,2.022 2014-02-23 00:12:00,2.278 2014-02-23 00:17:00,3.33 2014-02-23 00:22:00,2.262 2014-02-23 00:27:00,2.0380000000000003 2014-02-23 00:32:00,2.28 2014-02-23 00:37:00,2.026 2014-02-23 00:42:00,2.3 2014-02-23 00:47:00,2.05 2014-02-23 00:52:00,2.334 2014-02-23 00:57:00,2.126 2014-02-23 01:02:00,2.394 2014-02-23 01:07:00,2.144 2014-02-23 01:12:00,3.64 2014-02-23 01:17:00,2.05 2014-02-23 01:22:00,2.312 2014-02-23 01:27:00,2.052 2014-02-23 01:32:00,2.312 2014-02-23 01:37:00,2.06 2014-02-23 01:42:00,2.29 2014-02-23 01:47:00,1.956 2014-02-23 01:52:00,2.2880000000000003 2014-02-23 01:57:00,2.108 2014-02-23 02:02:00,2.338 2014-02-23 02:07:00,2.066 2014-02-23 02:12:00,2.378 2014-02-23 02:17:00,2.106 2014-02-23 02:22:00,3.6660000000000004 2014-02-23 02:27:00,2.112 2014-02-23 02:32:00,2.406 2014-02-23 02:37:00,2.15 2014-02-23 02:42:00,2.378 2014-02-23 02:47:00,2.062 2014-02-23 02:52:00,2.3 2014-02-23 02:57:00,2.182 2014-02-23 03:02:00,2.4659999999999997 2014-02-23 03:07:00,3.3160000000000003 2014-02-23 03:12:00,2.266 2014-02-23 03:17:00,1.9880000000000002 2014-02-23 03:22:00,2.2 2014-02-23 03:27:00,1.93 2014-02-23 03:32:00,2.238 2014-02-23 03:37:00,1.9340000000000002 2014-02-23 03:42:00,2.2 2014-02-23 03:47:00,1.966 2014-02-23 03:52:00,2.224 2014-02-23 03:57:00,2.088 2014-02-23 04:02:00,2.3 2014-02-23 04:07:00,2.0340000000000003 2014-02-23 04:12:00,2.2840000000000003 2014-02-23 04:17:00,3.27 2014-02-23 04:22:00,2.244 2014-02-23 04:27:00,1.9780000000000002 2014-02-23 04:32:00,2.2119999999999997 2014-02-23 04:37:00,2.052 2014-02-23 04:42:00,2.2880000000000003 2014-02-23 04:47:00,2.022 2014-02-23 04:52:00,2.2840000000000003 2014-02-23 04:57:00,2.05 2014-02-23 05:02:00,2.258 2014-02-23 05:07:00,2.01 2014-02-23 05:12:00,3.58 2014-02-23 05:17:00,1.994 2014-02-23 05:22:00,2.246 2014-02-23 05:27:00,1.996 2014-02-23 05:32:00,2.294 2014-02-23 05:37:00,2.0180000000000002 2014-02-23 05:42:00,2.3040000000000003 2014-02-23 05:47:00,2.002 2014-02-23 05:52:00,2.296 2014-02-23 05:57:00,2.088 2014-02-23 06:02:00,2.344 2014-02-23 06:07:00,2.174 2014-02-23 06:12:00,3.55 2014-02-23 06:17:00,2.0 2014-02-23 06:22:00,2.234 2014-02-23 06:27:00,1.994 2014-02-23 06:32:00,2.2880000000000003 2014-02-23 06:37:00,2.024 2014-02-23 06:42:00,2.274 2014-02-23 06:47:00,2.0380000000000003 2014-02-23 06:52:00,2.2880000000000003 2014-02-23 06:57:00,2.122 2014-02-23 07:02:00,2.3 2014-02-23 07:07:00,2.094 2014-02-23 07:12:00,2.338 2014-02-23 07:17:00,3.384 2014-02-23 07:22:00,2.366 2014-02-23 07:27:00,2.084 2014-02-23 07:32:00,2.316 2014-02-23 07:37:00,2.028 2014-02-23 07:42:00,2.388 2014-02-23 07:47:00,1.9340000000000002 2014-02-23 07:52:00,2.228 2014-02-23 07:57:00,1.994 2014-02-23 08:02:00,2.194 2014-02-23 08:07:00,1.9340000000000002 2014-02-23 08:12:00,2.156 2014-02-23 08:17:00,3.1660000000000004 2014-02-23 08:22:00,2.162 2014-02-23 08:27:00,1.916 2014-02-23 08:32:00,2.2119999999999997 2014-02-23 08:37:00,1.944 2014-02-23 08:42:00,2.246 2014-02-23 08:47:00,1.976 2014-02-23 08:52:00,2.266 2014-02-23 08:57:00,2.0 2014-02-23 09:02:00,2.184 2014-02-23 09:07:00,1.9240000000000002 2014-02-23 09:12:00,2.176 2014-02-23 09:17:00,3.582 2014-02-23 09:22:00,2.2840000000000003 2014-02-23 09:27:00,1.906 2014-02-23 09:32:00,2.184 2014-02-23 09:37:00,1.9 2014-02-23 09:42:00,2.178 2014-02-23 09:47:00,1.95 2014-02-23 09:52:00,2.2159999999999997 2014-02-23 09:57:00,2.0 2014-02-23 10:02:00,2.194 2014-02-23 10:07:00,1.966 2014-02-23 10:12:00,2.2 2014-02-23 10:17:00,3.272 2014-02-23 10:22:00,2.234 2014-02-23 10:27:00,2.0380000000000003 2014-02-23 10:32:00,2.296 2014-02-23 10:37:00,2.016 2014-02-23 10:42:00,2.228 2014-02-23 10:47:00,2.0 2014-02-23 10:52:00,2.316 2014-02-23 10:57:00,2.072 2014-02-23 11:02:00,2.2840000000000003 2014-02-23 11:07:00,2.04 2014-02-23 11:12:00,2.326 2014-02-23 11:17:00,2.088 2014-02-23 11:22:00,3.65 2014-02-23 11:27:00,1.972 2014-02-23 11:32:00,2.2159999999999997 2014-02-23 11:37:00,1.966 2014-02-23 11:42:00,2.2159999999999997 2014-02-23 11:47:00,1.9680000000000002 2014-02-23 11:52:00,2.246 2014-02-23 11:57:00,2.05 2014-02-23 12:02:00,2.2840000000000003 2014-02-23 12:07:00,2.002 2014-02-23 12:12:00,3.5660000000000003 2014-02-23 12:17:00,1.962 2014-02-23 12:22:00,2.258 2014-02-23 12:27:00,2.0180000000000002 2014-02-23 12:32:00,1.92 2014-02-23 12:37:00,1.9380000000000002 2014-02-23 12:42:00,2.184 2014-02-23 12:47:00,1.838 2014-02-23 12:52:00,2.242 2014-02-23 12:57:00,1.9880000000000002 2014-02-23 13:02:00,2.2 2014-02-23 13:07:00,1.984 2014-02-23 13:12:00,2.208 2014-02-23 13:17:00,1.854 2014-02-23 13:22:00,3.56 2014-02-23 13:27:00,1.984 2014-02-23 13:32:00,2.278 2014-02-23 13:37:00,1.952 2014-02-23 13:42:00,2.384 2014-02-23 13:47:00,1.9780000000000002 2014-02-23 13:52:00,2.164 2014-02-23 13:57:00,2.184 2014-02-23 14:02:00,2.294 2014-02-23 14:07:00,2.026 2014-02-23 14:12:00,2.258 2014-02-23 14:17:00,3.3080000000000003 2014-02-23 14:22:00,2.25 2014-02-23 14:27:00,1.8459999999999999 2014-02-23 14:32:00,2.068 2014-02-23 14:37:00,2.144 2014-02-23 14:42:00,2.27 2014-02-23 14:47:00,1.944 2014-02-23 14:52:00,2.234 2014-02-23 14:57:00,2.05 2014-02-23 15:02:00,2.266 2014-02-23 15:07:00,1.9 2014-02-23 15:12:00,2.366 2014-02-23 15:17:00,3.3 2014-02-23 15:22:00,2.234 2014-02-23 15:27:00,1.984 2014-02-23 15:32:00,2.244 2014-02-23 15:37:00,1.962 2014-02-23 15:42:00,2.234 2014-02-23 15:47:00,1.9340000000000002 2014-02-23 15:52:00,2.19 2014-02-23 15:57:00,2.088 2014-02-23 16:02:00,2.306 2014-02-23 16:07:00,2.0340000000000003 2014-02-23 16:12:00,2.2119999999999997 2014-02-23 16:17:00,3.2880000000000003 2014-02-23 16:22:00,2.184 2014-02-23 16:27:00,1.9280000000000002 2014-02-23 16:32:00,2.2 2014-02-23 16:37:00,1.946 2014-02-23 16:42:00,2.238 2014-02-23 16:47:00,1.93 2014-02-23 16:52:00,2.3080000000000003 2014-02-23 16:57:00,1.966 2014-02-23 17:02:00,2.146 2014-02-23 17:07:00,1.9140000000000001 2014-02-23 17:12:00,3.486 2014-02-23 17:17:00,1.8780000000000001 2014-02-23 17:22:00,2.15 2014-02-23 17:27:00,1.9 2014-02-23 17:32:00,2.166 2014-02-23 17:37:00,1.912 2014-02-23 17:42:00,2.1919999999999997 2014-02-23 17:47:00,1.8619999999999999 2014-02-23 17:52:00,2.3080000000000003 2014-02-23 17:57:00,2.0 2014-02-23 18:02:00,2.238 2014-02-23 18:07:00,3.304 2014-02-23 18:12:00,2.184 2014-02-23 18:17:00,2.094 2014-02-23 18:22:00,2.194 2014-02-23 18:27:00,1.9380000000000002 2014-02-23 18:32:00,2.15 2014-02-23 18:37:00,2.062 2014-02-23 18:42:00,2.2840000000000003 2014-02-23 18:47:00,2.0340000000000003 2014-02-23 18:52:00,2.3040000000000003 2014-02-23 18:57:00,2.0780000000000003 2014-02-23 19:02:00,2.2159999999999997 2014-02-23 19:07:00,2.0 2014-02-23 19:12:00,2.234 2014-02-23 19:17:00,3.2560000000000002 2014-02-23 19:22:00,2.2640000000000002 2014-02-23 19:27:00,1.984 2014-02-23 19:32:00,2.224 2014-02-23 19:37:00,1.994 2014-02-23 19:42:00,2.296 2014-02-23 19:47:00,1.954 2014-02-23 19:52:00,2.234 2014-02-23 19:57:00,2.036 2014-02-23 20:02:00,2.246 2014-02-23 20:07:00,2.022 2014-02-23 20:12:00,2.28 2014-02-23 20:17:00,2.084 2014-02-23 20:22:00,3.6660000000000004 2014-02-23 20:27:00,2.084 2014-02-23 20:32:00,2.366 2014-02-23 20:37:00,2.134 2014-02-23 20:42:00,2.472 2014-02-23 20:47:00,2.028 2014-02-23 20:52:00,2.166 2014-02-23 20:57:00,1.92 2014-02-23 21:02:00,2.154 2014-02-23 21:07:00,1.972 2014-02-23 21:12:00,3.5 2014-02-23 21:17:00,1.966 2014-02-23 21:22:00,2.206 2014-02-23 21:27:00,1.956 2014-02-23 21:32:00,2.204 2014-02-23 21:37:00,1.996 2014-02-23 21:42:00,2.242 2014-02-23 21:47:00,1.96 2014-02-23 21:52:00,2.228 2014-02-23 21:57:00,3.4960000000000004 2014-02-23 22:02:00,2.176 2014-02-23 22:07:00,1.94 2014-02-23 22:12:00,3.552 2014-02-23 22:17:00,1.94 2014-02-23 22:22:00,2.248 2014-02-23 22:27:00,1.996 2014-02-23 22:32:00,2.276 2014-02-23 22:37:00,2.046 2014-02-23 22:42:00,2.262 2014-02-23 22:47:00,2.022 2014-02-23 22:52:00,2.254 2014-02-23 22:57:00,2.0540000000000003 2014-02-23 23:02:00,2.234 2014-02-23 23:07:00,1.962 2014-02-23 23:12:00,3.53 2014-02-23 23:17:00,1.946 2014-02-23 23:22:00,2.222 2014-02-23 23:27:00,1.984 2014-02-23 23:32:00,2.2680000000000002 2014-02-23 23:37:00,1.9780000000000002 2014-02-23 23:42:00,2.3 2014-02-23 23:47:00,2.084 2014-02-23 23:52:00,2.356 2014-02-23 23:57:00,2.1319999999999997 2014-02-24 00:02:00,2.2840000000000003 2014-02-24 00:07:00,2.084 2014-02-24 00:12:00,3.5660000000000003 2014-02-24 00:17:00,2.066 2014-02-24 00:22:00,2.266 2014-02-24 00:27:00,2.128 2014-02-24 00:32:00,2.444 2014-02-24 00:37:00,2.0780000000000003 2014-02-24 00:42:00,2.46 2014-02-24 00:47:00,1.966 2014-02-24 00:52:00,2.238 2014-02-24 00:57:00,2.002 2014-02-24 01:02:00,2.222 2014-02-24 01:07:00,1.972 2014-02-24 01:12:00,3.478 2014-02-24 01:17:00,1.95 2014-02-24 01:22:00,2.2 2014-02-24 01:27:00,2.012 2014-02-24 01:32:00,2.204 2014-02-24 01:37:00,1.966 2014-02-24 01:42:00,2.204 2014-02-24 01:47:00,1.9780000000000002 2014-02-24 01:52:00,2.238 2014-02-24 01:57:00,1.972 2014-02-24 02:02:00,2.21 2014-02-24 02:07:00,2.022 2014-02-24 02:12:00,3.536 2014-02-24 02:17:00,1.966 2014-02-24 02:22:00,2.23 2014-02-24 02:27:00,2.0340000000000003 2014-02-24 02:32:00,2.3040000000000003 2014-02-24 02:37:00,2.04 2014-02-24 02:42:00,2.326 2014-02-24 02:47:00,2.05 2014-02-24 02:52:00,2.318 2014-02-24 02:57:00,2.122 2014-02-24 03:02:00,2.374 2014-02-24 03:07:00,2.122 2014-02-24 03:12:00,2.362 2014-02-24 03:17:00,3.616 2014-02-24 03:22:00,2.346 2014-02-24 03:27:00,2.1 2014-02-24 03:32:00,2.362 2014-02-24 03:37:00,2.126 2014-02-24 03:42:00,2.35 2014-02-24 03:47:00,2.084 2014-02-24 03:52:00,2.334 2014-02-24 03:57:00,2.136 2014-02-24 04:02:00,2.366 2014-02-24 04:07:00,2.1 2014-02-24 04:12:00,2.362 2014-02-24 04:17:00,3.3160000000000003 2014-02-24 04:22:00,2.434 2014-02-24 04:27:00,2.016 2014-02-24 04:32:00,2.234 2014-02-24 04:37:00,1.9880000000000002 2014-02-24 04:42:00,2.31 2014-02-24 04:47:00,2.046 2014-02-24 04:52:00,2.2880000000000003 2014-02-24 04:57:00,2.106 2014-02-24 05:02:00,2.338 2014-02-24 05:07:00,2.094 2014-02-24 05:12:00,5.3660000000000005 2014-02-24 05:17:00,3.884 2014-02-24 05:22:00,3.0 2014-02-24 05:27:00,2.5839999999999996 2014-02-24 05:32:00,2.8280000000000003 2014-02-24 05:37:00,2.346 2014-02-24 05:42:00,2.6660000000000004 2014-02-24 05:47:00,2.166 2014-02-24 05:52:00,2.472 2014-02-24 05:57:00,2.246 2014-02-24 06:02:00,2.526 2014-02-24 06:07:00,2.134 2014-02-24 06:12:00,2.45 2014-02-24 06:17:00,3.424 2014-02-24 06:22:00,3.116 2014-02-24 06:27:00,6.108 2014-02-24 06:32:00,3.718 2014-02-24 06:37:00,3.2 2014-02-24 06:42:00,3.486 2014-02-24 06:47:00,3.114 2014-02-24 06:52:00,3.3339999999999996 2014-02-24 06:57:00,2.99 2014-02-24 07:02:00,3.3339999999999996 2014-02-24 07:07:00,4.364 2014-02-24 07:12:00,2.488 2014-02-24 07:17:00,3.4 2014-02-24 07:22:00,2.44 2014-02-24 07:27:00,2.112 2014-02-24 07:32:00,2.484 2014-02-24 07:37:00,2.122 2014-02-24 07:42:00,2.4619999999999997 2014-02-24 07:47:00,2.188 2014-02-24 07:52:00,2.728 2014-02-24 07:57:00,3.0839999999999996 2014-02-24 08:02:00,4.934 2014-02-24 08:07:00,2.0380000000000003 2014-02-24 08:12:00,3.6660000000000004 2014-02-24 08:17:00,2.0180000000000002 2014-02-24 08:22:00,2.366 2014-02-24 08:27:00,2.074 2014-02-24 08:32:00,2.434 2014-02-24 08:37:00,2.09 2014-02-24 08:42:00,2.41 2014-02-24 08:47:00,2.072 2014-02-24 08:52:00,2.372 2014-02-24 08:57:00,2.136 2014-02-24 09:02:00,2.316 2014-02-24 09:07:00,2.0340000000000003 2014-02-24 09:12:00,3.3 2014-02-24 09:17:00,2.35 2014-02-24 09:22:00,2.158 2014-02-24 09:27:00,1.8880000000000001 2014-02-24 09:32:00,2.234 2014-02-24 09:37:00,1.972 2014-02-24 09:42:00,2.294 2014-02-24 09:47:00,2.046 2014-02-24 09:52:00,2.254 2014-02-24 09:57:00,2.066 2014-02-24 10:02:00,2.224 2014-02-24 10:07:00,2.044 2014-02-24 10:12:00,3.5460000000000003 2014-02-24 10:17:00,2.1180000000000003 2014-02-24 10:22:00,2.2 2014-02-24 10:27:00,2.022 2014-02-24 10:32:00,2.278 2014-02-24 10:37:00,1.954 2014-02-24 10:42:00,2.166 2014-02-24 10:47:00,1.9080000000000001 2014-02-24 10:52:00,2.16 2014-02-24 10:57:00,1.986 2014-02-24 11:02:00,2.208 2014-02-24 11:07:00,1.966 2014-02-24 11:12:00,2.2119999999999997 2014-02-24 11:17:00,3.2680000000000002 2014-02-24 11:22:00,2.238 2014-02-24 11:27:00,1.99 2014-02-24 11:32:00,2.276 2014-02-24 11:37:00,2.024 2014-02-24 11:42:00,2.282 2014-02-24 11:47:00,1.9780000000000002 2014-02-24 11:52:00,2.2119999999999997 2014-02-24 11:57:00,2.012 2014-02-24 12:02:00,3.182 2014-02-24 12:07:00,1.8940000000000001 2014-02-24 12:12:00,2.112 2014-02-24 12:17:00,3.2060000000000004 2014-02-24 12:22:00,2.136 2014-02-24 12:27:00,1.9340000000000002 2014-02-24 12:32:00,2.1959999999999997 2014-02-24 12:37:00,1.99 2014-02-24 12:42:00,2.31 2014-02-24 12:47:00,2.022 2014-02-24 12:52:00,2.222 2014-02-24 12:57:00,2.016 2014-02-24 13:02:00,2.19 2014-02-24 13:07:00,2.01 2014-02-24 13:12:00,2.2880000000000003 2014-02-24 13:17:00,3.266 2014-02-24 13:22:00,2.222 2014-02-24 13:27:00,1.95 2014-02-24 13:32:00,2.228 2014-02-24 13:37:00,1.9780000000000002 2014-02-24 13:42:00,2.1959999999999997 2014-02-24 13:47:00,1.966 2014-02-24 13:52:00,2.204 2014-02-24 13:57:00,2.05 2014-02-24 14:02:00,2.28 2014-02-24 14:07:00,2.0380000000000003 2014-02-24 14:12:00,2.246 2014-02-24 14:17:00,3.34 2014-02-24 14:22:00,2.26 2014-02-24 14:27:00,2.012 2014-02-24 14:32:00,2.262 2014-02-24 14:37:00,2.022 2014-02-24 14:42:00,2.266 2014-02-24 14:47:00,2.0180000000000002 2014-02-24 14:52:00,5.016 2014-02-24 14:57:00,4.518 2014-02-24 15:02:00,2.938 2014-02-24 15:07:00,2.542 2014-02-24 15:12:00,3.616 2014-02-24 15:17:00,2.926 2014-02-24 15:22:00,2.674 2014-02-24 15:27:00,2.244 2014-02-24 15:32:00,2.588 2014-02-24 15:37:00,2.188 2014-02-24 15:42:00,2.522 2014-02-24 15:47:00,2.146 2014-02-24 15:52:00,2.542 2014-02-24 15:57:00,2.226 2014-02-24 16:02:00,2.54 2014-02-24 16:07:00,2.202 2014-02-24 16:12:00,2.5340000000000003 2014-02-24 16:17:00,3.536 2014-02-24 16:22:00,2.65 2014-02-24 16:27:00,2.31 2014-02-24 16:32:00,2.61 2014-02-24 16:37:00,2.226 2014-02-24 16:42:00,2.4819999999999998 2014-02-24 16:47:00,2.138 2014-02-24 16:52:00,2.434 2014-02-24 16:57:00,2.166 2014-02-24 17:02:00,2.44 2014-02-24 17:07:00,2.128 2014-02-24 17:12:00,2.384 2014-02-24 17:17:00,3.412 2014-02-24 17:22:00,2.384 2014-02-24 17:27:00,2.062 2014-02-24 17:32:00,2.322 2014-02-24 17:37:00,2.012 2014-02-24 17:42:00,2.2840000000000003 2014-02-24 17:47:00,1.974 2014-02-24 17:52:00,2.21 2014-02-24 17:57:00,2.006 2014-02-24 18:02:00,2.238 2014-02-24 18:07:00,1.99 2014-02-24 18:12:00,3.6 2014-02-24 18:17:00,42.896 2014-02-24 18:22:00,57.976000000000006 2014-02-24 18:27:00,52.316 2014-02-24 18:32:00,38.57 2014-02-24 18:37:00,65.18 2014-02-24 18:42:00,53.65 2014-02-24 18:47:00,21.678 2014-02-24 18:52:00,6.65 2014-02-24 18:57:00,6.9620000000000015 2014-02-24 19:02:00,3.926 2014-02-24 19:07:00,4.3660000000000005 2014-02-24 19:12:00,3.8139999999999996 2014-02-24 19:17:00,6.1320000000000014 2014-02-24 19:22:00,3.176 2014-02-24 19:27:00,39.684 2014-02-24 19:32:00,60.812 2014-02-24 19:37:00,53.176 2014-02-24 19:42:00,17.308 2014-02-24 19:47:00,2.806 2014-02-24 19:52:00,3.2739999999999996 2014-02-24 19:57:00,4.008 2014-02-24 20:02:00,3.2260000000000004 2014-02-24 20:07:00,4.646 2014-02-24 20:12:00,2.972 2014-02-24 20:17:00,11.07 2014-02-24 20:22:00,70.866 2014-02-24 20:27:00,55.216 2014-02-24 20:32:00,37.156 2014-02-24 20:37:00,3.884 2014-02-24 20:42:00,5.278 2014-02-24 20:47:00,3.9 2014-02-24 20:52:00,4.1 2014-02-24 20:57:00,5.182 2014-02-24 21:02:00,3.516 2014-02-24 21:07:00,3.5060000000000002 2014-02-24 21:12:00,5.034 2014-02-24 21:17:00,3.3819999999999997 2014-02-24 21:22:00,11.67 2014-02-24 21:27:00,3.35 2014-02-24 21:32:00,3.582 2014-02-24 21:37:00,2.9339999999999997 2014-02-24 21:42:00,3.266 2014-02-24 21:47:00,2.984 2014-02-24 21:52:00,3.284 2014-02-24 21:57:00,4.6419999999999995 2014-02-24 22:02:00,3.0060000000000002 2014-02-24 22:07:00,3.5239999999999996 2014-02-24 22:12:00,4.202 2014-02-24 22:17:00,3.136 2014-02-24 22:22:00,3.842 2014-02-24 22:27:00,5.16 2014-02-24 22:32:00,2.274 2014-02-24 22:37:00,1.8659999999999999 2014-02-24 22:42:00,2.144 2014-02-24 22:47:00,1.8780000000000001 2014-02-24 22:52:00,2.164 2014-02-24 22:57:00,1.916 2014-02-24 23:02:00,2.2159999999999997 2014-02-24 23:07:00,39.134 2014-02-24 23:12:00,59.983999999999995 2014-02-24 23:17:00,52.19 2014-02-24 23:22:00,14.19 2014-02-24 23:27:00,2.512 2014-02-24 23:32:00,3.938 2014-02-24 23:37:00,2.8 2014-02-24 23:42:00,4.466 2014-02-24 23:47:00,2.63 2014-02-24 23:52:00,2.556 2014-02-24 23:57:00,2.762 2014-02-25 00:02:00,2.806 2014-02-25 00:07:00,3.5580000000000003 2014-02-25 00:12:00,2.7939999999999996 2014-02-25 00:17:00,2.344 2014-02-25 00:22:00,3.7119999999999997 2014-02-25 00:27:00,66.52199999999999 2014-02-25 00:32:00,53.16 2014-02-25 00:37:00,37.916 2014-02-25 00:42:00,25.234 2014-02-25 00:47:00,65.58800000000001 2014-02-25 00:52:00,53.49 2014-02-25 00:57:00,19.35 2014-02-25 01:02:00,4.584 2014-02-25 01:07:00,2.35 2014-02-25 01:12:00,4.15 2014-02-25 01:17:00,2.568 2014-02-25 01:22:00,2.822 2014-02-25 01:27:00,5.358 2014-02-25 01:32:00,57.931999999999995 2014-02-25 01:37:00,54.013999999999996 2014-02-25 01:42:00,49.032 2014-02-25 01:47:00,4.734 2014-02-25 01:52:00,2.6060000000000003 2014-02-25 01:57:00,2.404 2014-02-25 02:02:00,2.95 2014-02-25 02:07:00,2.6060000000000003 2014-02-25 02:12:00,6.872000000000001 2014-02-25 02:17:00,2.55 2014-02-25 02:22:00,3.742 2014-02-25 02:27:00,2.966 2014-02-25 02:32:00,2.924 2014-02-25 02:37:00,41.288000000000004 2014-02-25 02:42:00,63.56 2014-02-25 02:47:00,55.118 2014-02-25 02:52:00,14.95 2014-02-25 02:57:00,3.326 2014-02-25 03:02:00,8.72 2014-02-25 03:07:00,5.864 2014-02-25 03:12:00,4.534 2014-02-25 03:17:00,5.0360000000000005 2014-02-25 03:22:00,5.6 2014-02-25 03:27:00,5.416 2014-02-25 03:32:00,3.89 2014-02-25 03:37:00,3.532 2014-02-25 03:42:00,4.316 2014-02-25 03:47:00,3.668 2014-02-25 03:52:00,4.216 2014-02-25 03:57:00,4.81 2014-02-25 04:02:00,3.1639999999999997 2014-02-25 04:07:00,4.1419999999999995 2014-02-25 04:12:00,2.33 2014-02-25 04:17:00,3.2880000000000003 2014-02-25 04:22:00,2.266 2014-02-25 04:27:00,1.9240000000000002 2014-02-25 04:32:00,2.26 2014-02-25 04:37:00,1.972 2014-02-25 04:42:00,2.4659999999999997 2014-02-25 04:47:00,2.01 2014-02-25 04:52:00,2.306 2014-02-25 04:57:00,2.1 2014-02-25 05:02:00,2.35 2014-02-25 05:07:00,2.01 2014-02-25 05:12:00,2.266 2014-02-25 05:17:00,3.216 2014-02-25 05:22:00,2.162 2014-02-25 05:27:00,1.9180000000000001 2014-02-25 05:32:00,2.1959999999999997 2014-02-25 05:37:00,1.954 2014-02-25 05:42:00,2.166 2014-02-25 05:47:00,1.9880000000000002 2014-02-25 05:52:00,2.204 2014-02-25 05:57:00,2.016 2014-02-25 06:02:00,2.188 2014-02-25 06:07:00,1.9340000000000002 2014-02-25 06:12:00,2.2 2014-02-25 06:17:00,1.912 2014-02-25 06:22:00,6.596 2014-02-25 06:27:00,2.55 2014-02-25 06:32:00,3.2260000000000004 2014-02-25 06:37:00,2.51 2014-02-25 06:42:00,2.766 2014-02-25 06:47:00,2.334 2014-02-25 06:52:00,2.8080000000000003 2014-02-25 06:57:00,4.808 2014-02-25 07:02:00,5.438 2014-02-25 07:07:00,3.4219999999999997 2014-02-25 07:12:00,3.262 2014-02-25 07:17:00,2.416 2014-02-25 07:22:00,2.68 2014-02-25 07:27:00,2.262 2014-02-25 07:32:00,2.61 2014-02-25 07:37:00,2.108 2014-02-25 07:42:00,2.4659999999999997 2014-02-25 07:47:00,2.102 2014-02-25 07:52:00,2.414 2014-02-25 07:57:00,2.12 2014-02-25 08:02:00,2.434 2014-02-25 08:07:00,2.116 2014-02-25 08:12:00,2.508 2014-02-25 08:17:00,2.2159999999999997 2014-02-25 08:22:00,3.762 2014-02-25 08:27:00,2.134 2014-02-25 08:32:00,2.378 2014-02-25 08:37:00,2.094 2014-02-25 08:42:00,2.44 2014-02-25 08:47:00,2.134 2014-02-25 08:52:00,2.362 2014-02-25 08:57:00,2.072 2014-02-25 09:02:00,2.35 2014-02-25 09:07:00,2.0 2014-02-25 09:12:00,2.258 2014-02-25 09:17:00,2.344 2014-02-25 09:22:00,3.484 2014-02-25 09:27:00,2.072 2014-02-25 09:32:00,2.184 2014-02-25 09:37:00,1.8519999999999999 2014-02-25 09:42:00,2.2159999999999997 2014-02-25 09:47:00,5.478 2014-02-25 09:52:00,3.054 2014-02-25 09:57:00,2.65 2014-02-25 10:02:00,2.866 2014-02-25 10:07:00,2.384 2014-02-25 10:12:00,3.9339999999999997 2014-02-25 10:17:00,2.184 2014-02-25 10:22:00,2.456 2014-02-25 10:27:00,2.0340000000000003 2014-02-25 10:32:00,2.366 2014-02-25 10:37:00,1.954 2014-02-25 10:42:00,2.34 2014-02-25 10:47:00,2.0 2014-02-25 10:52:00,2.356 2014-02-25 10:57:00,2.096 2014-02-25 11:02:00,2.378 2014-02-25 11:07:00,2.022 2014-02-25 11:12:00,3.688 2014-02-25 11:17:00,2.106 2014-02-25 11:22:00,2.3280000000000003 2014-02-25 11:27:00,2.016 2014-02-25 11:32:00,2.266 2014-02-25 11:37:00,1.9780000000000002 2014-02-25 11:42:00,2.226 2014-02-25 11:47:00,2.006 2014-02-25 11:52:00,2.294 2014-02-25 11:57:00,1.954 2014-02-25 12:02:00,2.166 2014-02-25 12:07:00,1.9340000000000002 2014-02-25 12:12:00,2.21 2014-02-25 12:17:00,3.266 2014-02-25 12:22:00,2.178 2014-02-25 12:27:00,1.94 2014-02-25 12:32:00,2.16 2014-02-25 12:37:00,1.922 2014-02-25 12:42:00,2.178 2014-02-25 12:47:00,1.93 2014-02-25 12:52:00,2.164 2014-02-25 12:57:00,1.994 2014-02-25 13:02:00,2.246 2014-02-25 13:07:00,1.854 2014-02-25 13:12:00,3.438 2014-02-25 13:17:00,2.084 2014-02-25 13:22:00,2.198 2014-02-25 13:27:00,1.834 2014-02-25 13:32:00,2.096 2014-02-25 13:37:00,1.874 2014-02-25 13:42:00,2.148 2014-02-25 13:47:00,1.95 2014-02-25 13:52:00,2.184 2014-02-25 13:57:00,2.004 2014-02-25 14:02:00,2.222 2014-02-25 14:07:00,1.9780000000000002 2014-02-25 14:12:00,3.592 2014-02-25 14:17:00,1.984 2014-02-25 14:22:00,5.666 2014-02-25 14:27:00,2.568 2014-02-25 14:32:00,2.9339999999999997 2014-02-25 14:37:00,2.542 2014-02-25 14:42:00,2.7539999999999996 2014-02-25 14:47:00,2.346 2014-02-25 14:52:00,2.61 2014-02-25 14:57:00,2.2840000000000003 2014-02-25 15:02:00,2.5340000000000003 2014-02-25 15:07:00,2.094 2014-02-25 15:12:00,2.44 2014-02-25 15:17:00,3.42 2014-02-25 15:22:00,2.456 2014-02-25 15:27:00,2.184 2014-02-25 15:32:00,2.5839999999999996 2014-02-25 15:37:00,2.134 2014-02-25 15:42:00,2.494 2014-02-25 15:47:00,2.156 2014-02-25 15:52:00,2.438 2014-02-25 15:57:00,2.1519999999999997 2014-02-25 16:02:00,2.36 2014-02-25 16:07:00,1.99 2014-02-25 16:12:00,2.278 2014-02-25 16:17:00,2.04 2014-02-25 16:22:00,3.614 2014-02-25 16:27:00,2.072 2014-02-25 16:32:00,2.378 2014-02-25 16:37:00,2.06 2014-02-25 16:42:00,2.238 2014-02-25 16:47:00,2.1 2014-02-25 16:52:00,2.1180000000000003 2014-02-25 16:57:00,1.95 2014-02-25 17:02:00,2.062 2014-02-25 17:07:00,3.154 2014-02-25 17:12:00,2.066 2014-02-25 17:17:00,1.824 2014-02-25 17:22:00,2.07 2014-02-25 17:27:00,1.8459999999999999 2014-02-25 17:32:00,2.092 2014-02-25 17:37:00,1.838 2014-02-25 17:42:00,2.1 2014-02-25 17:47:00,1.95 2014-02-25 17:52:00,2.15 2014-02-25 17:57:00,2.0340000000000003 2014-02-25 18:02:00,2.204 2014-02-25 18:07:00,1.896 2014-02-25 18:12:00,2.146 2014-02-25 18:17:00,3.196 2014-02-25 18:22:00,2.176 2014-02-25 18:27:00,1.9080000000000001 2014-02-25 18:32:00,2.188 2014-02-25 18:37:00,7.58 2014-02-25 18:42:00,2.89 2014-02-25 18:47:00,2.484 2014-02-25 18:52:00,2.7239999999999998 2014-02-25 18:57:00,2.338 2014-02-25 19:02:00,2.572 2014-02-25 19:07:00,2.178 2014-02-25 19:12:00,3.79 2014-02-25 19:17:00,2.146 2014-02-25 19:22:00,2.3680000000000003 2014-02-25 19:27:00,1.962 2014-02-25 19:32:00,2.318 2014-02-25 19:37:00,2.0 2014-02-25 19:42:00,2.334 2014-02-25 19:47:00,2.06 2014-02-25 19:52:00,2.334 2014-02-25 19:57:00,2.076 2014-02-25 20:02:00,2.3 2014-02-25 20:07:00,2.056 2014-02-25 20:12:00,3.574 2014-02-25 20:17:00,1.972 2014-02-25 20:22:00,2.174 2014-02-25 20:27:00,1.95 2014-02-25 20:32:00,2.178 2014-02-25 20:37:00,1.95 2014-02-25 20:42:00,2.2159999999999997 2014-02-25 20:47:00,2.044 2014-02-25 20:52:00,2.088 2014-02-25 20:57:00,1.922 2014-02-25 21:02:00,2.15 2014-02-25 21:07:00,1.8459999999999999 2014-02-25 21:12:00,2.092 2014-02-25 21:17:00,1.868 2014-02-25 21:22:00,3.346 2014-02-25 21:27:00,1.8780000000000001 2014-02-25 21:32:00,2.154 2014-02-25 21:37:00,2.006 2014-02-25 21:42:00,2.2640000000000002 2014-02-25 21:47:00,1.9780000000000002 2014-02-25 21:52:00,2.184 2014-02-25 21:57:00,3.5 2014-02-25 22:02:00,2.222 2014-02-25 22:07:00,1.946 2014-02-25 22:12:00,3.514 2014-02-25 22:17:00,1.99 2014-02-25 22:22:00,2.226 2014-02-25 22:27:00,1.94 2014-02-25 22:32:00,2.23 2014-02-25 22:37:00,1.9780000000000002 2014-02-25 22:42:00,2.25 2014-02-25 22:47:00,2.0 2014-02-25 22:52:00,2.218 2014-02-25 22:57:00,2.5839999999999996 2014-02-25 23:02:00,2.1719999999999997 2014-02-25 23:07:00,1.966 2014-02-25 23:12:00,2.366 2014-02-25 23:17:00,1.944 2014-02-25 23:22:00,3.458 2014-02-25 23:27:00,1.942 2014-02-25 23:32:00,24.912 2014-02-25 23:37:00,64.252 2014-02-25 23:42:00,52.263999999999996 2014-02-25 23:47:00,19.456 2014-02-25 23:52:00,2.878 2014-02-25 23:57:00,6.037999999999999 2014-02-26 00:02:00,3.1239999999999997 2014-02-26 00:07:00,4.34 2014-02-26 00:12:00,2.984 2014-02-26 00:17:00,4.24 2014-02-26 00:22:00,2.562 2014-02-26 00:27:00,2.61 2014-02-26 00:32:00,3.054 2014-02-26 00:37:00,2.762 2014-02-26 00:42:00,4.168 2014-02-26 00:47:00,1.84 2014-02-26 00:52:00,2.11 2014-02-26 00:57:00,1.984 2014-02-26 01:02:00,2.1719999999999997 2014-02-26 01:07:00,1.95 2014-02-26 01:12:00,2.188 2014-02-26 01:17:00,1.9340000000000002 2014-02-26 01:22:00,3.542 2014-02-26 01:27:00,9.542 2014-02-26 01:32:00,70.018 2014-02-26 01:37:00,52.104 2014-02-26 01:42:00,29.064 2014-02-26 01:47:00,2.6180000000000003 2014-02-26 01:52:00,3.9160000000000004 2014-02-26 01:57:00,2.866 2014-02-26 02:02:00,4.666 2014-02-26 02:07:00,3.984 2014-02-26 02:12:00,2.52 2014-02-26 02:17:00,2.912 2014-02-26 02:22:00,2.9160000000000004 2014-02-26 02:27:00,2.772 2014-02-26 02:32:00,5.03 2014-02-26 02:37:00,1.8159999999999998 2014-02-26 02:42:00,2.164 2014-02-26 02:47:00,1.834 2014-02-26 02:52:00,2.112 2014-02-26 02:57:00,1.96 2014-02-26 03:02:00,2.136 2014-02-26 03:07:00,2.026 2014-02-26 03:12:00,6.14 2014-02-26 03:17:00,2.516 2014-02-26 03:22:00,4.666 2014-02-26 03:27:00,2.376 2014-02-26 03:32:00,4.284 2014-02-26 03:37:00,2.5340000000000003 2014-02-26 03:42:00,6.1160000000000005 2014-02-26 03:47:00,2.9160000000000004 2014-02-26 03:52:00,2.384 2014-02-26 03:57:00,2.064 2014-02-26 04:02:00,2.394 2014-02-26 04:07:00,2.0380000000000003 2014-02-26 04:12:00,58.33600000000001 2014-02-26 04:17:00,52.784 2014-02-26 04:22:00,51.782 2014-02-26 04:27:00,27.965999999999998 2014-02-26 04:32:00,52.083999999999996 2014-02-26 04:37:00,16.528 2014-02-26 04:42:00,3.384 2014-02-26 04:47:00,4.532 2014-02-26 04:52:00,2.864 2014-02-26 04:57:00,2.5839999999999996 2014-02-26 05:02:00,3.196 2014-02-26 05:07:00,2.738 2014-02-26 05:12:00,6.316 2014-02-26 05:17:00,2.8360000000000003 2014-02-26 05:22:00,4.706 2014-02-26 05:27:00,2.75 2014-02-26 05:32:00,3.094 2014-02-26 05:37:00,2.516 2014-02-26 05:42:00,2.75 2014-02-26 05:47:00,2.37 2014-02-26 05:52:00,2.8080000000000003 2014-02-26 05:57:00,9.357999999999999 2014-02-26 06:02:00,2.9760000000000004 2014-02-26 06:07:00,42.943999999999996 2014-02-26 06:12:00,57.251999999999995 2014-02-26 06:17:00,55.483999999999995 2014-02-26 06:22:00,10.908 2014-02-26 06:27:00,2.7239999999999998 2014-02-26 06:32:00,59.86600000000001 2014-02-26 06:37:00,53.63800000000001 2014-02-26 06:42:00,49.391999999999996 2014-02-26 06:47:00,2.54 2014-02-26 06:52:00,2.806 2014-02-26 06:57:00,2.736 2014-02-26 07:02:00,2.984 2014-02-26 07:07:00,6.056 2014-02-26 07:12:00,3.1 2014-02-26 07:17:00,5.3820000000000014 2014-02-26 07:22:00,3.134 2014-02-26 07:27:00,4.508 2014-02-26 07:32:00,2.7560000000000002 2014-02-26 07:37:00,2.334 2014-02-26 07:42:00,3.0780000000000003 2014-02-26 07:47:00,2.844 2014-02-26 07:52:00,4.584 2014-02-26 07:57:00,1.8659999999999999 2014-02-26 08:02:00,2.096 2014-02-26 08:07:00,1.896 2014-02-26 08:12:00,2.08 2014-02-26 08:17:00,2.7539999999999996 2014-02-26 08:22:00,2.504 2014-02-26 08:27:00,1.8219999999999998 2014-02-26 08:32:00,2.012 2014-02-26 08:37:00,1.808 2014-02-26 08:42:00,2.0540000000000003 2014-02-26 08:47:00,1.8659999999999999 2014-02-26 08:52:00,2.084 2014-02-26 08:57:00,1.946 2014-02-26 09:02:00,2.11 2014-02-26 09:07:00,1.896 2014-02-26 09:12:00,2.126 2014-02-26 09:17:00,3.556 2014-02-26 09:22:00,2.48 2014-02-26 09:27:00,2.0380000000000003 2014-02-26 09:32:00,2.166 2014-02-26 09:37:00,1.95 2014-02-26 09:42:00,2.2 2014-02-26 09:47:00,2.8339999999999996 2014-02-26 09:52:00,2.378 2014-02-26 09:57:00,2.106 2014-02-26 10:02:00,2.016 2014-02-26 10:07:00,1.85 2014-02-26 10:12:00,2.13 2014-02-26 10:17:00,3.1660000000000004 2014-02-26 10:22:00,2.182 2014-02-26 10:27:00,1.808 2014-02-26 10:32:00,2.092 2014-02-26 10:37:00,1.9080000000000001 2014-02-26 10:42:00,2.154 2014-02-26 10:47:00,1.916 2014-02-26 10:52:00,2.13 2014-02-26 10:57:00,1.962 2014-02-26 11:02:00,2.188 2014-02-26 11:07:00,1.972 2014-02-26 11:12:00,3.484 2014-02-26 11:17:00,1.9080000000000001 2014-02-26 11:22:00,2.146 2014-02-26 11:27:00,1.946 2014-02-26 11:32:00,2.2 2014-02-26 11:37:00,1.9 2014-02-26 11:42:00,2.23 2014-02-26 11:47:00,1.9780000000000002 2014-02-26 11:52:00,2.26 2014-02-26 11:57:00,2.062 2014-02-26 12:02:00,2.2840000000000003 2014-02-26 12:07:00,2.0540000000000003 2014-02-26 12:12:00,2.246 2014-02-26 12:17:00,3.18 2014-02-26 12:22:00,2.096 2014-02-26 12:27:00,7.716 2014-02-26 12:32:00,2.988 2014-02-26 12:37:00,2.556 2014-02-26 12:42:00,2.69 2014-02-26 12:47:00,2.2840000000000003 2014-02-26 12:52:00,2.428 2014-02-26 12:57:00,2.108 2014-02-26 13:02:00,2.29 2014-02-26 13:07:00,1.956 2014-02-26 13:12:00,3.514 2014-02-26 13:17:00,1.944 2014-02-26 13:22:00,2.272 2014-02-26 13:27:00,2.056 2014-02-26 13:32:00,2.238 2014-02-26 13:37:00,1.9280000000000002 2014-02-26 13:42:00,2.2119999999999997 2014-02-26 13:47:00,1.906 2014-02-26 13:52:00,2.146 2014-02-26 13:57:00,2.0340000000000003 2014-02-26 14:02:00,2.226 2014-02-26 14:07:00,2.028 2014-02-26 14:12:00,2.272 2014-02-26 14:17:00,3.2880000000000003 2014-02-26 14:22:00,2.234 2014-02-26 14:27:00,2.062 2014-02-26 14:32:00,2.326 2014-02-26 14:37:00,2.022 2014-02-26 14:42:00,2.2119999999999997 2014-02-26 14:47:00,2.004 2014-02-26 14:52:00,2.274 2014-02-26 14:57:00,2.094 2014-02-26 15:02:00,2.2880000000000003 2014-02-26 15:07:00,2.0780000000000003 2014-02-26 15:12:00,2.322 2014-02-26 15:17:00,3.372 2014-02-26 15:22:00,2.246 2014-02-26 15:27:00,2.012 2014-02-26 15:32:00,2.298 2014-02-26 15:37:00,2.138 2014-02-26 15:42:00,2.096 2014-02-26 15:47:00,1.8780000000000001 2014-02-26 15:52:00,2.106 2014-02-26 15:57:00,1.944 2014-02-26 16:02:00,2.108 2014-02-26 16:07:00,1.926 2014-02-26 16:12:00,2.13 2014-02-26 16:17:00,3.2039999999999997 2014-02-26 16:22:00,2.122 2014-02-26 16:27:00,1.9 2014-02-26 16:32:00,2.154 2014-02-26 16:37:00,2.7880000000000003 2014-02-26 16:42:00,2.0540000000000003 2014-02-26 16:47:00,1.8 2014-02-26 16:52:00,2.062 2014-02-26 16:57:00,1.98 2014-02-26 17:02:00,2.154 2014-02-26 17:07:00,1.912 2014-02-26 17:12:00,3.484 2014-02-26 17:17:00,1.9280000000000002 2014-02-26 17:22:00,2.142 2014-02-26 17:27:00,2.01 2014-02-26 17:32:00,2.2159999999999997 2014-02-26 17:37:00,47.066 2014-02-26 17:42:00,60.746 2014-02-26 17:47:00,52.141999999999996 2014-02-26 17:52:00,12.93 2014-02-26 17:57:00,3.168 2014-02-26 18:02:00,4.466 2014-02-26 18:07:00,3.24 2014-02-26 18:12:00,4.984 2014-02-26 18:17:00,3.9960000000000004 2014-02-26 18:22:00,3.068 2014-02-26 18:27:00,2.772 2014-02-26 18:32:00,3.1660000000000004 2014-02-26 18:37:00,4.102 2014-02-26 18:42:00,2.324 2014-02-26 18:47:00,2.006 2014-02-26 18:52:00,2.306 2014-02-26 18:57:00,2.094 2014-02-26 19:02:00,2.362 2014-02-26 19:07:00,44.396 2014-02-26 19:12:00,56.25 2014-02-26 19:17:00,56.333999999999996 2014-02-26 19:22:00,9.376 2014-02-26 19:27:00,3.202 2014-02-26 19:32:00,4.724 2014-02-26 19:37:00,3.366 2014-02-26 19:42:00,5.2860000000000005 2014-02-26 19:47:00,2.806 2014-02-26 19:52:00,2.984 2014-02-26 19:57:00,3.0580000000000003 2014-02-26 20:02:00,3.234 2014-02-26 20:07:00,2.8739999999999997 2014-02-26 20:12:00,3.99 2014-02-26 20:17:00,3.388 2014-02-26 20:22:00,2.524 2014-02-26 20:27:00,2.15 2014-02-26 20:32:00,2.5 2014-02-26 20:37:00,2.24 2014-02-26 20:42:00,2.49 2014-02-26 20:47:00,2.194 2014-02-26 20:52:00,2.4659999999999997 2014-02-26 20:57:00,2.134 2014-02-26 21:02:00,2.41 2014-02-26 21:07:00,3.34 2014-02-26 21:12:00,2.356 2014-02-26 21:17:00,2.116 2014-02-26 21:22:00,2.38 2014-02-26 21:27:00,2.072 2014-02-26 21:32:00,2.316 2014-02-26 21:37:00,1.9280000000000002 2014-02-26 21:42:00,2.198 2014-02-26 21:47:00,1.99 2014-02-26 21:52:00,2.226 2014-02-26 21:57:00,3.464 2014-02-26 22:02:00,2.2119999999999997 2014-02-26 22:07:00,1.8880000000000001 2014-02-26 22:12:00,3.4160000000000004 2014-02-26 22:17:00,1.922 2014-02-26 22:22:00,2.134 2014-02-26 22:27:00,1.906 2014-02-26 22:32:00,2.9 2014-02-26 22:37:00,66.906 2014-02-26 22:42:00,52.794 2014-02-26 22:47:00,37.718 2014-02-26 22:52:00,2.8280000000000003 2014-02-26 22:57:00,3.216 2014-02-26 23:02:00,3.728 2014-02-26 23:07:00,2.6260000000000003 2014-02-26 23:12:00,4.688 2014-02-26 23:17:00,3.7 2014-02-26 23:22:00,2.908 2014-02-26 23:27:00,2.7060000000000004 2014-02-26 23:32:00,2.9160000000000004 2014-02-26 23:37:00,5.086 2014-02-26 23:42:00,5.066 2014-02-26 23:47:00,2.6660000000000004 2014-02-26 23:52:00,3.866 2014-02-26 23:57:00,66.266 2014-02-27 00:02:00,52.61600000000001 2014-02-27 00:07:00,40.452 2014-02-27 00:12:00,4.644 2014-02-27 00:17:00,3.674 2014-02-27 00:22:00,3.948 2014-02-27 00:27:00,4.04 2014-02-27 00:32:00,9.638 2014-02-27 00:37:00,3.292 2014-02-27 00:42:00,3.35 2014-02-27 00:47:00,2.72 2014-02-27 00:52:00,3.49 2014-02-27 00:57:00,2.99 2014-02-27 01:02:00,3.27 2014-02-27 01:07:00,4.306 2014-02-27 01:12:00,3.7319999999999998 2014-02-27 01:17:00,42.461999999999996 2014-02-27 01:22:00,56.483999999999995 2014-02-27 01:27:00,52.342 2014-02-27 01:32:00,8.79 2014-02-27 01:37:00,4.206 2014-02-27 01:42:00,25.656 2014-02-27 01:47:00,65.598 2014-02-27 01:52:00,52.583999999999996 2014-02-27 01:57:00,21.136 2014-02-27 02:02:00,3.4619999999999997 2014-02-27 02:07:00,5.4239999999999995 2014-02-27 02:12:00,3.48 2014-02-27 02:17:00,4.758 2014-02-27 02:22:00,3.136 2014-02-27 02:27:00,2.7239999999999998 2014-02-27 02:32:00,3.574 2014-02-27 02:37:00,3.134 2014-02-27 02:42:00,4.71 2014-02-27 02:47:00,2.4 2014-02-27 02:52:00,2.628 2014-02-27 02:57:00,2.376 2014-02-27 03:02:00,2.728 2014-02-27 03:07:00,2.376 2014-02-27 03:12:00,2.8760000000000003 2014-02-27 03:17:00,3.6039999999999996 2014-02-27 03:22:00,2.572 2014-02-27 03:27:00,2.2680000000000002 2014-02-27 03:32:00,2.596 2014-02-27 03:37:00,2.3040000000000003 2014-02-27 03:42:00,2.7060000000000004 2014-02-27 03:47:00,2.4 2014-02-27 03:52:00,2.688 2014-02-27 03:57:00,2.4219999999999997 2014-02-27 04:02:00,2.7060000000000004 2014-02-27 04:07:00,2.39 2014-02-27 04:12:00,2.676 2014-02-27 04:17:00,3.634 2014-02-27 04:22:00,7.612 2014-02-27 04:27:00,2.6719999999999997 2014-02-27 04:32:00,3.028 2014-02-27 04:37:00,2.622 2014-02-27 04:42:00,3.48 2014-02-27 04:47:00,2.96 2014-02-27 04:52:00,3.234 2014-02-27 04:57:00,2.74 2014-02-27 05:02:00,3.1660000000000004 2014-02-27 05:07:00,4.684 2014-02-27 05:12:00,3.292 2014-02-27 05:17:00,2.886 2014-02-27 05:22:00,3.24 2014-02-27 05:27:00,5.052 2014-02-27 05:32:00,3.792 2014-02-27 05:37:00,2.7119999999999997 2014-02-27 05:42:00,3.08 2014-02-27 05:47:00,2.592 2014-02-27 05:52:00,2.7560000000000002 2014-02-27 05:57:00,11.998 2014-02-27 06:02:00,3.088 2014-02-27 06:07:00,5.1339999999999995 2014-02-27 06:12:00,2.984 2014-02-27 06:17:00,4.374 2014-02-27 06:22:00,2.716 2014-02-27 06:27:00,2.322 2014-02-27 06:32:00,2.572 2014-02-27 06:37:00,2.194 2014-02-27 06:42:00,2.4 2014-02-27 06:47:00,1.974 2014-02-27 06:52:00,2.316 2014-02-27 06:57:00,2.106 2014-02-27 07:02:00,2.41 2014-02-27 07:07:00,3.326 2014-02-27 07:12:00,2.366 2014-02-27 07:17:00,2.06 2014-02-27 07:22:00,2.256 2014-02-27 07:27:00,1.944 2014-02-27 07:32:00,2.228 2014-02-27 07:37:00,2.006 2014-02-27 07:42:00,2.21 2014-02-27 07:47:00,1.9880000000000002 2014-02-27 07:52:00,2.23 2014-02-27 07:57:00,1.9780000000000002 2014-02-27 08:02:00,2.1719999999999997 2014-02-27 08:07:00,2.004 2014-02-27 08:12:00,2.204 2014-02-27 08:17:00,3.222 2014-02-27 08:22:00,2.2159999999999997 2014-02-27 08:27:00,2.006 2014-02-27 08:32:00,2.2159999999999997 2014-02-27 08:37:00,1.946 2014-02-27 08:42:00,2.15 2014-02-27 08:47:00,1.922 2014-02-27 08:52:00,2.178 2014-02-27 08:57:00,1.962 2014-02-27 09:02:00,2.226 2014-02-27 09:07:00,1.984 2014-02-27 09:12:00,2.166 2014-02-27 09:17:00,2.306 2014-02-27 09:22:00,3.4339999999999997 2014-02-27 09:27:00,1.8940000000000001 2014-02-27 09:32:00,2.146 2014-02-27 09:37:00,1.9380000000000002 2014-02-27 09:42:00,2.146 2014-02-27 09:47:00,1.886 2014-02-27 09:52:00,2.188 2014-02-27 09:57:00,1.944 2014-02-27 10:02:00,2.15 2014-02-27 10:07:00,5.584 2014-02-27 10:12:00,3.1260000000000003 2014-02-27 10:17:00,4.064 2014-02-27 10:22:00,3.1639999999999997 2014-02-27 10:27:00,2.72 2014-02-27 10:32:00,2.98 2014-02-27 10:37:00,2.526 2014-02-27 10:42:00,2.842 2014-02-27 10:47:00,2.424 2014-02-27 10:52:00,2.8280000000000003 2014-02-27 10:57:00,2.33 2014-02-27 11:02:00,2.65 2014-02-27 11:07:00,2.36 2014-02-27 11:12:00,2.616 2014-02-27 11:17:00,2.434 2014-02-27 11:22:00,3.6519999999999997 2014-02-27 11:27:00,2.166 2014-02-27 11:32:00,2.484 2014-02-27 11:37:00,2.116 2014-02-27 11:42:00,2.38 2014-02-27 11:47:00,2.11 2014-02-27 11:52:00,2.358 2014-02-27 11:57:00,2.022 2014-02-27 12:02:00,3.452 2014-02-27 12:07:00,3.15 2014-02-27 12:12:00,3.302 2014-02-27 12:17:00,4.2219999999999995 2014-02-27 12:22:00,3.342 2014-02-27 12:27:00,3.114 2014-02-27 12:32:00,3.312 2014-02-27 12:37:00,3.096 2014-02-27 12:42:00,3.134 2014-02-27 12:47:00,3.088 2014-02-27 12:52:00,3.322 2014-02-27 12:57:00,3.1460000000000004 2014-02-27 13:02:00,4.216 2014-02-27 13:07:00,1.854 2014-02-27 13:12:00,8.15 2014-02-27 13:17:00,9.666 2014-02-27 13:22:00,4.1 2014-02-27 13:27:00,3.6660000000000004 2014-02-27 13:32:00,6.084 2014-02-27 13:37:00,3.6860000000000004 2014-02-27 13:42:00,4.058 2014-02-27 13:47:00,3.6319999999999997 2014-02-27 13:52:00,3.8360000000000003 2014-02-27 13:57:00,3.4939999999999998 2014-02-27 14:02:00,3.4939999999999998 2014-02-27 14:07:00,3.342 2014-02-27 14:12:00,3.6439999999999997 2014-02-27 14:17:00,3.234 2014-02-27 14:22:00,6.2479999999999976 2014-02-27 14:27:00,2.076 2014-02-27 14:32:00,3.55 2014-02-27 14:37:00,2.67 2014-02-27 14:42:00,2.884 2014-02-27 14:47:00,2.694 2014-02-27 14:52:00,5.8 2014-02-27 14:57:00,3.4419999999999997 2014-02-27 15:02:00,3.892 2014-02-27 15:07:00,6.376 2014-02-27 15:12:00,3.4760000000000004 2014-02-27 15:17:00,3.34 2014-02-27 15:22:00,3.784 2014-02-27 15:27:00,3.06 2014-02-27 15:32:00,4.46 2014-02-27 15:37:00,2.126 2014-02-27 15:42:00,2.49 2014-02-27 15:47:00,2.16 2014-02-27 15:52:00,3.6860000000000004 2014-02-27 15:57:00,2.306 2014-02-27 16:02:00,2.716 2014-02-27 16:07:00,46.01600000000001 2014-02-27 16:12:00,78.81 2014-02-27 16:17:00,42.742 2014-02-27 16:22:00,11.05 2014-02-27 16:27:00,4.102 2014-02-27 16:32:00,5.224 2014-02-27 16:37:00,4.0760000000000005 2014-02-27 16:42:00,6.428 2014-02-27 16:47:00,3.342 2014-02-27 16:52:00,4.662 2014-02-27 16:57:00,7.4 2014-02-27 17:02:00,5.816 2014-02-27 17:07:00,9.17 2014-02-27 17:12:00,8.634 2014-02-27 17:17:00,2.634 2014-02-27 17:22:00,3.034 2014-02-27 17:27:00,2.612 2014-02-27 17:32:00,3.022 2014-02-27 17:37:00,4.816 2014-02-27 17:42:00,3.326 2014-02-27 17:47:00,2.892 2014-02-27 17:52:00,3.4739999999999998 2014-02-27 17:57:00,2.892 2014-02-27 18:02:00,3.3 2014-02-27 18:07:00,2.85 2014-02-27 18:12:00,4.408 2014-02-27 18:17:00,2.592 2014-02-27 18:22:00,2.9760000000000004 2014-02-27 18:27:00,2.568 2014-02-27 18:32:00,3.008 2014-02-27 18:37:00,2.6460000000000004 2014-02-27 18:42:00,3.1719999999999997 2014-02-27 18:47:00,2.734 2014-02-27 18:52:00,3.108 2014-02-27 18:57:00,2.7439999999999998 2014-02-27 19:02:00,3.0980000000000003 2014-02-27 19:07:00,2.716 2014-02-27 19:12:00,4.336 2014-02-27 19:17:00,48.676 2014-02-27 19:22:00,76.5 2014-02-27 19:27:00,38.446 2014-02-27 19:32:00,3.7739999999999996 2014-02-27 19:37:00,4.334 2014-02-27 19:42:00,3.918 2014-02-27 19:47:00,5.4079999999999995 2014-02-27 19:52:00,3.818 2014-02-27 19:57:00,3.15 2014-02-27 20:02:00,3.702 2014-02-27 20:07:00,3.46 2014-02-27 20:12:00,3.8739999999999997 2014-02-27 20:17:00,6.484 2014-02-27 20:22:00,3.062 2014-02-27 20:27:00,2.656 2014-02-27 20:32:00,3.034 2014-02-27 20:37:00,2.6439999999999997 2014-02-27 20:42:00,3.056 2014-02-27 20:47:00,5.31 2014-02-27 20:52:00,3.0180000000000002 2014-02-27 20:57:00,2.742 2014-02-27 21:02:00,3.016 2014-02-27 21:07:00,2.592 2014-02-27 21:12:00,2.9760000000000004 2014-02-27 21:17:00,44.63 2014-02-27 21:22:00,79.72399999999998 2014-02-27 21:27:00,41.583999999999996 2014-02-27 21:32:00,3.8 2014-02-27 21:37:00,4.3660000000000005 2014-02-27 21:42:00,3.884 2014-02-27 21:47:00,5.4 2014-02-27 21:52:00,3.7439999999999998 2014-02-27 21:57:00,4.566 2014-02-27 22:02:00,3.516 2014-02-27 22:07:00,3.1439999999999997 2014-02-27 22:12:00,3.6 2014-02-27 22:17:00,3.216 2014-02-27 22:22:00,5.843999999999999 2014-02-27 22:27:00,2.592 2014-02-27 22:32:00,3.0260000000000002 2014-02-27 22:37:00,2.5860000000000003 2014-02-27 22:42:00,2.9960000000000004 2014-02-27 22:47:00,2.5660000000000003 2014-02-27 22:52:00,31.938000000000002 2014-02-27 22:57:00,82.89 2014-02-27 23:02:00,45.174 2014-02-27 23:07:00,3.952 2014-02-27 23:12:00,6.138 2014-02-27 23:17:00,3.516 2014-02-27 23:22:00,3.742 2014-02-27 23:27:00,5.377999999999999 2014-02-27 23:32:00,3.4 2014-02-27 23:37:00,3.188 2014-02-27 23:42:00,3.6660000000000004 2014-02-27 23:47:00,3.234 2014-02-27 23:52:00,4.882 2014-02-27 23:57:00,2.592 2014-02-28 00:02:00,2.958 2014-02-28 00:07:00,3.87 2014-02-28 00:12:00,3.114 2014-02-28 00:17:00,2.6919999999999997 2014-02-28 00:22:00,3.05 2014-02-28 00:27:00,2.642 2014-02-28 00:32:00,3.042 2014-02-28 00:37:00,2.67 2014-02-28 00:42:00,3.122 2014-02-28 00:47:00,2.634 2014-02-28 00:52:00,3.076 2014-02-28 00:57:00,2.722 2014-02-28 01:02:00,3.096 2014-02-28 01:07:00,2.736 2014-02-28 01:12:00,4.478 2014-02-28 01:17:00,2.8 2014-02-28 01:22:00,3.1839999999999997 2014-02-28 01:27:00,43.1 2014-02-28 01:32:00,79.084 2014-02-28 01:37:00,42.141999999999996 2014-02-28 01:42:00,3.89 2014-02-28 01:47:00,4.466 2014-02-28 01:52:00,4.008 2014-02-28 01:57:00,3.508 2014-02-28 02:02:00,5.85 2014-02-28 02:07:00,3.052 2014-02-28 02:12:00,3.6260000000000003 2014-02-28 02:17:00,7.3439999999999985 2014-02-28 02:22:00,5.562 2014-02-28 02:27:00,5.726 2014-02-28 02:32:00,3.542 2014-02-28 02:37:00,2.9 2014-02-28 02:42:00,9.866 2014-02-28 02:47:00,4.342 2014-02-28 02:52:00,5.584 2014-02-28 02:57:00,4.46 2014-02-28 03:02:00,6.757999999999999 2014-02-28 03:07:00,4.342 2014-02-28 03:12:00,4.15 2014-02-28 03:17:00,5.142 2014-02-28 03:22:00,4.558 2014-02-28 03:27:00,3.966 2014-02-28 03:32:00,5.532 2014-02-28 03:37:00,2.9019999999999997 2014-02-28 03:42:00,3.35 2014-02-28 03:47:00,2.926 2014-02-28 03:52:00,3.3080000000000003 2014-02-28 03:57:00,2.95 2014-02-28 04:02:00,3.4419999999999997 2014-02-28 04:07:00,2.9339999999999997 2014-02-28 04:12:00,4.7 2014-02-28 04:17:00,3.016 2014-02-28 04:22:00,3.3939999999999997 2014-02-28 04:27:00,3.1180000000000003 2014-02-28 04:32:00,16.6 2014-02-28 04:37:00,2.9760000000000004 2014-02-28 04:42:00,3.358 2014-02-28 04:47:00,2.95 2014-02-28 04:52:00,3.4419999999999997 2014-02-28 04:57:00,3.05 2014-02-28 05:02:00,3.408 2014-02-28 05:07:00,13.734000000000002 2014-02-28 05:12:00,91.00200000000001 2014-02-28 05:17:00,56.193999999999996 2014-02-28 05:22:00,12.765999999999998 2014-02-28 05:27:00,4.606 2014-02-28 05:32:00,8.766 2014-02-28 05:37:00,3.502 2014-02-28 05:42:00,6.1 2014-02-28 05:47:00,3.25 2014-02-28 05:52:00,3.846 2014-02-28 05:57:00,3.742 2014-02-28 06:02:00,3.984 2014-02-28 06:07:00,4.684 2014-02-28 06:12:00,3.21 2014-02-28 06:17:00,4.024 2014-02-28 06:22:00,3.252 2014-02-28 06:27:00,2.778 2014-02-28 06:32:00,3.2060000000000004 2014-02-28 06:37:00,2.752 2014-02-28 06:42:00,3.168 2014-02-28 06:47:00,2.784 2014-02-28 06:52:00,3.19 2014-02-28 06:57:00,2.734 2014-02-28 07:02:00,3.116 2014-02-28 07:07:00,2.7 2014-02-28 07:12:00,4.513999999999999 2014-02-28 07:17:00,2.676 2014-02-28 07:22:00,3.134 2014-02-28 07:27:00,2.658 2014-02-28 07:32:00,3.092 2014-02-28 07:37:00,2.688 2014-02-28 07:42:00,3.14 2014-02-28 07:47:00,2.76 2014-02-28 07:52:00,3.1839999999999997 2014-02-28 07:57:00,2.766 2014-02-28 08:02:00,3.17 2014-02-28 08:07:00,2.9160000000000004 2014-02-28 08:12:00,6.734 2014-02-28 08:17:00,2.742 2014-02-28 08:22:00,6.166 2014-02-28 08:27:00,2.95 2014-02-28 08:32:00,3.3339999999999996 2014-02-28 08:37:00,2.784 2014-02-28 08:42:00,3.266 2014-02-28 08:47:00,2.7739999999999996 2014-02-28 08:52:00,3.242 2014-02-28 08:57:00,2.7939999999999996 2014-02-28 09:02:00,3.1919999999999997 2014-02-28 09:07:00,4.624 2014-02-28 09:12:00,3.1660000000000004 2014-02-28 09:17:00,3.1239999999999997 2014-02-28 09:22:00,3.1239999999999997 2014-02-28 09:27:00,2.6919999999999997 2014-02-28 09:32:00,3.158 2014-02-28 09:37:00,2.694 2014-02-28 09:42:00,3.1260000000000003 2014-02-28 09:47:00,5.058 2014-02-28 09:52:00,3.076 2014-02-28 09:57:00,2.708 2014-02-28 10:02:00,3.1239999999999997 2014-02-28 10:07:00,2.728 2014-02-28 10:12:00,3.134 2014-02-28 10:17:00,3.9939999999999998 2014-02-28 10:22:00,3.0839999999999996 2014-02-28 10:27:00,2.65 2014-02-28 10:32:00,3.0780000000000003 2014-02-28 10:37:00,2.71 2014-02-28 10:42:00,3.1 2014-02-28 10:47:00,5.332000000000002 2014-02-28 10:52:00,3.142 2014-02-28 10:57:00,2.734 2014-02-28 11:02:00,3.142 2014-02-28 11:07:00,2.738 2014-02-28 11:12:00,3.13 2014-02-28 11:17:00,3.858 2014-02-28 11:22:00,2.77 2014-02-28 11:27:00,2.344 2014-02-28 11:32:00,2.594 2014-02-28 11:37:00,2.208 2014-02-28 11:42:00,2.516 2014-02-28 11:47:00,2.1 2014-02-28 11:52:00,2.46 2014-02-28 11:57:00,2.13 2014-02-28 12:02:00,2.536 2014-02-28 12:07:00,2.094 2014-02-28 12:12:00,2.426 2014-02-28 12:17:00,3.3160000000000003 2014-02-28 12:22:00,2.384 2014-02-28 12:27:00,2.04 2014-02-28 12:32:00,2.444 2014-02-28 12:37:00,2.116 2014-02-28 12:42:00,2.418 2014-02-28 12:47:00,2.08 2014-02-28 12:52:00,2.412 2014-02-28 12:57:00,2.096 2014-02-28 13:02:00,2.42 2014-02-28 13:07:00,3.366 2014-02-28 13:12:00,2.39 2014-02-28 13:17:00,4.94 2014-02-28 13:22:00,5.766 2014-02-28 13:27:00,2.6660000000000004 2014-02-28 13:32:00,3.014 2014-02-28 13:37:00,2.548 2014-02-28 13:42:00,2.75 2014-02-28 13:47:00,2.354 2014-02-28 13:52:00,2.6 2014-02-28 13:57:00,2.262 2014-02-28 14:02:00,2.456 2014-02-28 14:07:00,2.0980000000000003 2014-02-28 14:12:00,2.376 2014-02-28 14:17:00,2.426 2014-02-28 14:22:00,3.252 ================================================ FILE: workspace/anomaly_detector/datasets/selected/outliers/rogue_agent_key_hold.csv ================================================ timestamp,value 2014-07-06 20:10:00,0.06453452400000001 2014-07-06 20:15:00,0.064295318 2014-07-06 20:20:00,0.063879838 2014-07-06 20:25:00,0.065691833 2014-07-06 20:35:00,0.056301242 2014-07-06 20:40:00,0.067750636 2014-07-06 20:45:00,0.0 2014-07-06 20:55:00,0.06528790799999999 2014-07-06 21:00:00,0.063178539 2014-07-06 21:05:00,0.0 2014-07-06 21:10:00,0.0 2014-07-06 21:15:00,0.0 2014-07-07 16:15:00,0.06593207599999999 2014-07-07 16:20:00,0.068277308 2014-07-07 16:25:00,0.0 2014-07-07 16:35:00,0.062787234 2014-07-07 16:40:00,0.06657756599999999 2014-07-07 16:45:00,0.077044715 2014-07-07 16:50:00,0.075116301 2014-07-07 16:55:00,0.07199654 2014-07-07 17:00:00,0.0 2014-07-07 17:05:00,0.0 2014-07-07 17:25:00,0.061142873 2014-07-07 17:30:00,0.0 2014-07-07 17:35:00,0.04943192 2014-07-07 17:45:00,0.071269501 2014-07-07 17:50:00,0.064887449 2014-07-07 17:55:00,0.079126387 2014-07-07 18:00:00,0.079692364 2014-07-07 18:05:00,0.064561804 2014-07-07 18:10:00,0.076985488 2014-07-07 18:15:00,0.07198525900000001 2014-07-07 18:20:00,0.066090552 2014-07-07 18:25:00,0.06469324900000001 2014-07-07 18:30:00,0.064608783 2014-07-07 18:35:00,0.067478103 2014-07-07 18:40:00,0.069862932 2014-07-07 18:45:00,0.06589513 2014-07-07 18:50:00,0.06522446700000001 2014-07-07 18:55:00,0.058982897 2014-07-07 19:00:00,0.0 2014-07-07 19:30:00,0.0 2014-07-07 20:10:00,0.0 2014-07-07 20:15:00,0.07537598200000001 2014-07-07 20:20:00,0.06833768700000001 2014-07-07 20:25:00,0.077055882 2014-07-07 20:30:00,0.08510286800000001 2014-07-07 20:35:00,0.074617078 2014-07-07 20:40:00,0.073783769 2014-07-07 20:45:00,0.067219689 2014-07-07 20:50:00,0.082650582 2014-07-07 20:55:00,0.071369655 2014-07-07 21:00:00,0.074396641 2014-07-07 21:05:00,0.11970953 2014-07-07 21:10:00,0.06731445700000001 2014-07-07 21:15:00,0.072558182 2014-07-07 21:20:00,0.06728508700000001 2014-07-07 21:25:00,0.070712037 2014-07-07 21:30:00,0.064641756 2014-07-07 21:35:00,0.073068096 2014-07-07 21:40:00,0.07057474799999999 2014-07-07 21:45:00,0.066541138 2014-07-07 21:50:00,0.07096640900000001 2014-07-07 21:55:00,0.072068935 2014-07-07 22:00:00,0.068014095 2014-07-07 22:05:00,0.069069546 2014-07-07 22:10:00,0.066306158 2014-07-07 22:15:00,0.071656362 2014-07-07 22:20:00,0.070537682 2014-07-07 22:25:00,0.069981819 2014-07-07 22:30:00,0.063712692 2014-07-07 22:35:00,0.07592906599999999 2014-07-07 22:40:00,0.068992963 2014-07-07 22:45:00,0.073445647 2014-07-07 22:50:00,0.07052242 2014-07-07 22:55:00,0.226947951 2014-07-07 23:00:00,0.0770232 2014-07-07 23:05:00,0.072146928 2014-07-07 23:10:00,0.070184442 2014-07-07 23:15:00,0.071785589 2014-07-07 23:20:00,0.07143490799999999 2014-07-07 23:25:00,0.065622919 2014-07-07 23:30:00,0.081242128 2014-07-07 23:35:00,0.093692864 2014-07-07 23:40:00,0.090847328 2014-07-07 23:45:00,0.086801539 2014-07-07 23:50:00,0.072789827 2014-07-07 23:55:00,0.07527392299999999 2014-07-08 00:00:00,0.0 2014-07-08 00:05:00,0.074694667 2014-07-08 00:10:00,0.070129173 2014-07-08 00:20:00,0.080410458 2014-07-08 00:25:00,0.067807492 2014-07-08 00:30:00,0.08191316400000001 2014-07-08 00:35:00,0.0 2014-07-08 00:40:00,0.112033203 2014-07-08 00:45:00,0.089263947 2014-07-08 00:50:00,0.07131035200000001 2014-07-08 00:55:00,0.073491377 2014-07-08 01:00:00,0.062912334 2014-07-08 01:05:00,0.060903851 2014-07-08 01:10:00,0.055824222 2014-07-08 01:15:00,0.062922219 2014-07-08 01:20:00,0.07722562599999999 2014-07-08 01:25:00,0.083142297 2014-07-08 01:30:00,0.07844424900000001 2014-07-08 01:35:00,0.07028794299999999 2014-07-08 01:40:00,0.067850363 2014-07-08 16:20:00,0.066507083 2014-07-08 16:25:00,0.072771192 2014-07-08 16:30:00,0.058495297 2014-07-08 16:35:00,0.057057806 2014-07-08 16:40:00,0.058605791 2014-07-08 16:45:00,0.058052596 2014-07-08 16:50:00,0.051507674 2014-07-08 17:00:00,0.0 2014-07-08 17:05:00,0.0 2014-07-08 17:20:00,0.069990465 2014-07-08 17:25:00,0.081846427 2014-07-08 17:30:00,0.06884088599999999 2014-07-08 17:35:00,0.065170985 2014-07-08 17:40:00,0.0 2014-07-08 17:50:00,0.07462521400000001 2014-07-08 17:55:00,0.068300284 2014-07-08 18:00:00,0.065351057 2014-07-08 18:05:00,0.068766445 2014-07-08 18:10:00,0.06544404200000001 2014-07-08 18:15:00,0.073886382 2014-07-08 18:20:00,0.072648136 2014-07-08 18:25:00,0.070162658 2014-07-08 18:30:00,0.078440291 2014-07-08 18:35:00,0.080437172 2014-07-08 18:40:00,0.074335158 2014-07-08 18:45:00,0.070396356 2014-07-08 18:50:00,0.068971142 2014-07-08 18:55:00,0.06825881 2014-07-08 19:00:00,0.07241175400000001 2014-07-08 19:05:00,0.0 2014-07-08 19:10:00,0.083314965 2014-07-08 19:15:00,0.0 2014-07-08 19:25:00,0.0 2014-07-08 19:35:00,0.07265456099999999 2014-07-08 19:40:00,0.070770578 2014-07-08 19:45:00,0.06535992 2014-07-08 19:50:00,0.06516216700000001 2014-07-08 19:55:00,0.072056066 2014-07-08 20:00:00,0.085815709 2014-07-08 20:05:00,0.101067175 2014-07-08 20:10:00,0.102269133 2014-07-08 20:20:00,0.07337235 2014-07-08 20:25:00,0.086461415 2014-07-08 20:40:00,0.122939428 2014-07-08 21:05:00,0.648676709 2014-07-08 21:10:00,0.085586475 2014-07-08 21:15:00,0.070694787 2014-07-08 21:20:00,0.095611246 2014-07-08 21:55:00,0.0 2014-07-08 22:00:00,0.06963178099999999 2014-07-08 22:05:00,0.0 2014-07-08 22:15:00,0.065337805 2014-07-08 22:20:00,0.069423449 2014-07-08 22:25:00,0.089264929 2014-07-08 22:30:00,0.066457554 2014-07-08 22:35:00,0.0 2014-07-08 22:40:00,0.0 2014-07-08 22:50:00,0.07276004400000001 2014-07-08 22:55:00,0.077930063 2014-07-08 23:00:00,0.08089861599999999 2014-07-08 23:05:00,0.0901801 2014-07-08 23:10:00,0.096584395 2014-07-08 23:15:00,0.0 2014-07-08 23:20:00,0.0 2014-07-08 23:25:00,0.073069589 2014-07-08 23:30:00,0.07526831099999999 2014-07-08 23:35:00,0.080200333 2014-07-08 23:40:00,0.081870055 2014-07-08 23:45:00,0.066538187 2014-07-08 23:50:00,0.06486616 2014-07-09 16:20:00,0.078202243 2014-07-09 16:25:00,0.08467332 2014-07-09 16:30:00,0.077211048 2014-07-09 16:35:00,0.072798011 2014-07-09 16:40:00,0.061893388 2014-07-09 16:45:00,0.084999126 2014-07-09 16:50:00,0.06060981400000001 2014-07-09 16:55:00,0.05830139700000001 2014-07-09 17:00:00,0.068059045 2014-07-09 17:05:00,0.0 2014-07-09 17:15:00,0.06533578799999999 2014-07-09 17:20:00,0.06522328299999999 2014-07-09 17:25:00,0.06660350400000001 2014-07-09 17:30:00,0.064493822 2014-07-09 17:35:00,0.063759473 2014-07-09 17:40:00,0.0 2014-07-09 17:45:00,0.078130967 2014-07-09 17:50:00,0.065035345 2014-07-09 17:55:00,0.07328794799999999 2014-07-09 18:00:00,0.078835874 2014-07-09 18:05:00,0.061821222 2014-07-09 18:10:00,0.058587455 2014-07-09 18:15:00,0.072103732 2014-07-09 18:20:00,0.06053375 2014-07-09 18:25:00,0.07560126 2014-07-09 18:30:00,0.06640715900000001 2014-07-09 18:35:00,0.066940445 2014-07-09 18:40:00,0.067622642 2014-07-09 18:45:00,0.06494316 2014-07-09 18:50:00,0.07410472 2014-07-09 18:55:00,0.0 2014-07-09 19:25:00,0.0 2014-07-09 19:45:00,0.076853483 2014-07-09 19:50:00,0.075200748 2014-07-09 19:55:00,0.07226239599999999 2014-07-09 20:00:00,0.07267715599999999 2014-07-09 20:05:00,0.0 2014-07-09 20:10:00,0.074125749 2014-07-09 20:15:00,0.071203032 2014-07-09 20:20:00,0.076607068 2014-07-09 20:25:00,0.0 2014-07-09 20:30:00,0.0 2014-07-09 20:40:00,0.072540702 2014-07-09 20:45:00,0.0 2014-07-09 20:50:00,0.0 2014-07-09 21:00:00,0.072589764 2014-07-09 21:05:00,0.073043263 2014-07-09 21:10:00,0.071478658 2014-07-09 21:15:00,0.06925759 2014-07-09 21:20:00,0.074117643 2014-07-09 21:25:00,0.083657749 2014-07-09 21:30:00,0.100010991 2014-07-09 21:35:00,0.08167639900000001 2014-07-09 21:40:00,0.06905876 2014-07-09 21:45:00,0.076641826 2014-07-09 21:50:00,0.065264078 2014-07-09 21:55:00,0.06151601900000001 2014-07-09 22:00:00,0.064245564 2014-07-09 22:05:00,0.067416084 2014-07-09 22:10:00,0.065174883 2014-07-09 22:15:00,0.063981892 2014-07-09 22:20:00,0.070781631 2014-07-09 22:25:00,0.07091886 2014-07-09 22:30:00,0.072767741 2014-07-09 22:35:00,0.06628128400000001 2014-07-09 22:40:00,0.068282272 2014-07-09 22:45:00,0.072731916 2014-07-09 22:50:00,0.531583598 2014-07-09 22:55:00,0.0 2014-07-10 20:05:00,0.06758560000000001 2014-07-10 20:10:00,0.069346799 2014-07-10 20:15:00,0.069808377 2014-07-10 20:20:00,0.064024417 2014-07-10 20:25:00,0.059894006 2014-07-10 20:30:00,0.0 2014-07-10 20:35:00,0.052889268 2014-07-10 20:40:00,0.069996505 2014-07-10 20:45:00,0.090819702 2014-07-10 20:50:00,0.092357278 2014-07-10 20:55:00,0.073224392 2014-07-10 21:00:00,0.074288471 2014-07-10 21:05:00,0.08014450599999999 2014-07-10 21:10:00,0.096451795 2014-07-10 21:15:00,0.08249667299999999 2014-07-10 21:20:00,0.06315431 2014-07-10 21:25:00,0.062846261 2014-07-10 21:30:00,0.067098234 2014-07-10 21:35:00,0.070040669 2014-07-10 21:40:00,0.151596686 2014-07-10 21:45:00,0.075223056 2014-07-10 21:50:00,0.07014687 2014-07-10 21:55:00,0.06984607 2014-07-10 22:00:00,0.0 2014-07-10 22:05:00,0.067074281 2014-07-10 22:10:00,0.069360377 2014-07-10 22:15:00,0.06914248 2014-07-10 22:20:00,0.070213866 2014-07-10 22:25:00,0.076050628 2014-07-10 22:30:00,0.086771271 2014-07-10 22:35:00,0.072209089 2014-07-10 22:45:00,0.063050624 2014-07-10 22:50:00,0.07327640099999999 2014-07-10 22:55:00,0.07553544 2014-07-10 23:00:00,0.071689969 2014-07-10 23:05:00,0.070439837 2014-07-10 23:10:00,0.063566086 2014-07-10 23:15:00,0.059849366 2014-07-10 23:20:00,0.061594495 2014-07-10 23:25:00,0.066851831 2014-07-10 23:30:00,0.062975055 2014-07-10 23:35:00,0.06460803700000001 2014-07-10 23:40:00,0.061033292 2014-07-10 23:45:00,0.06339773900000001 2014-07-10 23:50:00,0.059772211 2014-07-10 23:55:00,0.068874465 2014-07-11 00:00:00,0.082920038 2014-07-11 00:05:00,0.08584952400000001 2014-07-11 00:10:00,0.0 2014-07-11 00:15:00,0.0 2014-07-11 00:35:00,0.117173433 2014-07-11 00:40:00,0.05802717 2014-07-11 00:45:00,0.0 2014-07-11 01:20:00,0.0 2014-07-11 01:30:00,0.110067689 2014-07-11 01:35:00,0.113982558 2014-07-11 01:40:00,0.0 2014-07-11 01:45:00,0.0 2014-07-11 01:50:00,0.0 2014-07-11 01:55:00,0.0 2014-07-11 02:00:00,0.0 2014-07-11 02:05:00,0.0 2014-07-11 02:10:00,0.0 2014-07-11 02:15:00,0.0 2014-07-11 02:20:00,0.0 2014-07-11 02:25:00,0.0 2014-07-11 02:30:00,0.0 2014-07-11 02:35:00,0.0 2014-07-11 02:40:00,0.0 2014-07-11 02:45:00,0.0 2014-07-11 02:50:00,0.0 2014-07-11 02:55:00,0.0 2014-07-11 03:00:00,0.0 2014-07-11 03:05:00,0.0 2014-07-11 03:10:00,0.0 2014-07-11 03:15:00,0.0 2014-07-11 03:20:00,0.0 2014-07-11 03:25:00,0.0 2014-07-11 03:35:00,0.0 2014-07-11 03:40:00,0.0 2014-07-11 03:45:00,0.0 2014-07-11 03:50:00,0.0 2014-07-11 07:30:00,0.03192997 2014-07-11 07:35:00,0.0 2014-07-11 07:40:00,0.0 2014-07-11 07:45:00,0.0 2014-07-11 07:50:00,0.0 2014-07-11 07:55:00,0.0 2014-07-11 08:00:00,0.0 2014-07-11 08:05:00,0.0 2014-07-11 08:10:00,0.0 2014-07-11 08:15:00,0.0 2014-07-11 08:20:00,0.0 2014-07-11 08:25:00,0.0 2014-07-11 08:35:00,0.0 2014-07-11 08:40:00,0.0 2014-07-11 08:45:00,0.0 2014-07-11 08:50:00,0.0 2014-07-11 08:55:00,0.0 2014-07-11 09:00:00,0.0 2014-07-11 09:05:00,0.0 2014-07-11 09:10:00,0.0 2014-07-11 09:15:00,0.0 2014-07-11 09:20:00,0.0 2014-07-11 09:25:00,0.0 2014-07-11 09:30:00,0.0 2014-07-11 09:35:00,0.0 2014-07-11 09:40:00,0.0 2014-07-11 09:45:00,0.0 2014-07-11 09:50:00,0.0 2014-07-11 09:55:00,0.0 2014-07-11 10:00:00,0.0 2014-07-11 10:05:00,0.0 2014-07-11 10:10:00,0.0 2014-07-11 10:15:00,0.0 2014-07-11 10:20:00,0.0 2014-07-11 10:30:00,0.0 2014-07-11 10:35:00,0.0 2014-07-11 10:40:00,0.0 2014-07-11 10:45:00,0.0 2014-07-11 10:50:00,0.0 2014-07-11 10:55:00,0.0 2014-07-11 11:00:00,0.0 2014-07-11 11:05:00,0.0 2014-07-11 11:10:00,0.0 2014-07-11 11:15:00,0.0 2014-07-11 11:20:00,0.0 2014-07-11 11:25:00,0.0 2014-07-11 11:30:00,0.0 2014-07-11 11:35:00,0.0 2014-07-11 11:40:00,0.0 2014-07-11 11:45:00,0.0 2014-07-11 11:50:00,0.0 2014-07-11 11:55:00,0.0 2014-07-11 12:00:00,0.0 2014-07-11 12:05:00,0.0 2014-07-11 12:10:00,0.0 2014-07-11 12:15:00,0.0 2014-07-11 12:20:00,0.0 2014-07-11 12:25:00,0.0 2014-07-11 12:30:00,0.0 2014-07-11 12:35:00,0.0 2014-07-11 12:45:00,0.0 2014-07-11 12:50:00,0.0 2014-07-11 12:55:00,0.0 2014-07-11 13:00:00,0.0 2014-07-11 13:05:00,0.0 2014-07-11 13:10:00,0.0 2014-07-11 13:15:00,0.0 2014-07-11 13:20:00,0.0 2014-07-11 13:25:00,0.0 2014-07-11 13:30:00,0.0 2014-07-11 13:35:00,0.0 2014-07-11 13:40:00,0.0 2014-07-11 13:45:00,0.0 2014-07-11 13:50:00,0.0 2014-07-11 13:55:00,0.0 2014-07-11 14:00:00,0.0 2014-07-11 14:05:00,0.0 2014-07-11 14:10:00,0.0 2014-07-11 14:15:00,0.0 2014-07-11 14:20:00,0.0 2014-07-11 14:25:00,0.0 2014-07-11 14:30:00,0.0 2014-07-11 14:35:00,0.0 2014-07-11 14:45:00,0.0 2014-07-11 14:50:00,0.0 2014-07-11 14:55:00,0.0 2014-07-11 15:00:00,0.0 2014-07-11 15:05:00,0.0 2014-07-11 15:10:00,0.0 2014-07-11 15:15:00,0.0 2014-07-11 15:20:00,0.0 2014-07-11 16:10:00,0.09863162 2014-07-11 16:15:00,0.08272386 2014-07-11 16:20:00,0.085230736 2014-07-11 16:25:00,0.06826363 2014-07-11 16:30:00,0.082736923 2014-07-11 16:35:00,0.073087134 2014-07-11 16:40:00,0.06398754 2014-07-11 16:45:00,0.07573959200000001 2014-07-11 16:50:00,0.06987537 2014-07-11 16:55:00,0.069682799 2014-07-11 17:00:00,0.073080403 2014-07-11 17:05:00,0.0 2014-07-11 17:15:00,0.894877604 2014-07-11 17:20:00,0.08934301300000001 2014-07-11 17:25:00,0.065345519 2014-07-11 17:30:00,0.067827237 2014-07-11 17:35:00,0.0 2014-07-11 18:10:00,0.07592336599999999 2014-07-11 18:15:00,0.063932613 2014-07-11 18:20:00,0.08958878199999999 2014-07-11 18:25:00,0.085891063 2014-07-11 18:30:00,0.067534644 2014-07-11 18:35:00,0.07018377599999999 2014-07-11 18:40:00,0.069429169 2014-07-11 18:45:00,0.073223894 2014-07-11 18:50:00,0.066217605 2014-07-11 18:55:00,0.062421981 2014-07-11 19:00:00,0.07063684 2014-07-11 19:05:00,0.068916717 2014-07-11 19:10:00,0.064045422 2014-07-11 19:15:00,0.06963963 2014-07-11 19:20:00,0.070939419 2014-07-11 19:25:00,0.06970957900000001 2014-07-11 19:30:00,0.068598365 2014-07-11 19:35:00,0.0 2014-07-11 20:10:00,0.0 2014-07-11 20:20:00,0.063635359 2014-07-11 20:25:00,0.06422909 2014-07-11 20:30:00,0.070774645 2014-07-11 20:35:00,0.068035847 2014-07-11 20:40:00,0.071887277 2014-07-11 20:45:00,0.066371174 2014-07-11 20:50:00,0.073693152 2014-07-11 20:55:00,0.074337182 2014-07-11 21:00:00,0.081452785 2014-07-11 21:05:00,0.080226873 2014-07-11 21:10:00,0.075866301 2014-07-11 21:15:00,0.082649088 2014-07-11 21:20:00,0.067151591 2014-07-11 21:25:00,0.071230778 2014-07-11 21:30:00,0.064547304 2014-07-11 21:35:00,0.058622577 2014-07-11 21:40:00,0.061547310999999987 2014-07-11 21:45:00,0.062709794 2014-07-11 21:50:00,0.076483583 2014-07-11 21:55:00,0.066729108 2014-07-11 22:00:00,0.070420094 2014-07-11 22:05:00,0.087912241 2014-07-11 22:10:00,0.0 2014-07-11 22:15:00,0.065736168 2014-07-11 22:20:00,0.070528229 2014-07-11 22:25:00,0.07141012599999999 2014-07-11 22:30:00,0.0 2014-07-11 22:35:00,0.071144378 2014-07-11 22:40:00,0.07158130900000001 2014-07-11 22:45:00,0.081845461 2014-07-11 22:50:00,0.077930015 2014-07-11 22:55:00,0.077977317 2014-07-11 23:00:00,0.086169364 2014-07-11 23:05:00,0.083144763 2014-07-11 23:10:00,0.058807518 2014-07-11 23:15:00,0.082003931 2014-07-11 23:20:00,0.07838690799999999 2014-07-11 23:25:00,0.072364739 2014-07-11 23:30:00,0.075285607 2014-07-11 23:35:00,0.076338906 2014-07-11 23:40:00,0.069559493 2014-07-11 23:45:00,0.079055729 2014-07-11 23:50:00,0.064776535 2014-07-11 23:55:00,0.0 2014-07-12 00:00:00,0.06512030099999999 2014-07-12 00:05:00,0.081144121 2014-07-12 00:10:00,0.069493738 2014-07-12 00:15:00,0.07132172 2014-07-12 00:20:00,0.08174910099999999 2014-07-12 00:25:00,0.08094678200000001 2014-07-12 00:30:00,0.043550134 2014-07-12 00:35:00,0.071189478 2014-07-12 00:40:00,0.07651633299999999 2014-07-12 00:45:00,0.07223233700000001 2014-07-12 00:50:00,0.07577371299999999 2014-07-12 00:55:00,0.072497933 2014-07-12 01:00:00,0.078945033 2014-07-12 01:05:00,0.066033045 2014-07-12 01:10:00,0.071879928 2014-07-12 01:15:00,0.064920046 2014-07-12 01:20:00,0.07239877900000001 2014-07-12 01:25:00,0.061562998 2014-07-12 01:30:00,0.075128839 2014-07-12 18:10:00,0.07235504799999999 2014-07-12 18:15:00,0.07390092 2014-07-12 18:20:00,0.064606555 2014-07-12 18:25:00,0.063249826 2014-07-12 18:30:00,0.079823196 2014-07-12 18:35:00,0.0 2014-07-14 16:10:00,0.066142584 2014-07-14 16:15:00,0.082683495 2014-07-14 16:20:00,0.121088107 2014-07-14 16:25:00,0.078241639 2014-07-14 16:30:00,0.11917909 2014-07-14 16:35:00,0.082868306 2014-07-14 16:40:00,0.077474031 2014-07-14 16:45:00,0.076853245 2014-07-14 16:50:00,0.06721400200000001 2014-07-14 16:55:00,0.0 2014-07-14 17:00:00,0.0 2014-07-14 17:05:00,0.06624467099999999 2014-07-14 17:10:00,0.076446056 2014-07-14 17:15:00,0.0832685 2014-07-14 17:20:00,0.084635518 2014-07-14 17:25:00,0.070059102 2014-07-14 17:30:00,0.0 2014-07-14 17:35:00,0.0843253 2014-07-14 17:40:00,0.090023782 2014-07-14 17:45:00,0.086879535 2014-07-14 17:50:00,0.096119506 2014-07-14 17:55:00,0.087577124 2014-07-14 18:15:00,0.0 2014-07-14 18:20:00,0.0 2014-07-14 18:25:00,0.0 2014-07-14 18:30:00,0.0 2014-07-14 18:35:00,0.0 2014-07-14 18:40:00,0.0 2014-07-14 18:45:00,0.0 2014-07-14 18:50:00,0.0 2014-07-14 18:55:00,0.0 2014-07-14 19:00:00,0.0 2014-07-14 19:05:00,0.0 2014-07-14 19:10:00,0.0 2014-07-14 19:15:00,0.0 2014-07-14 19:20:00,0.0 2014-07-14 19:25:00,0.0 2014-07-14 19:30:00,0.0 2014-07-14 19:40:00,0.0 2014-07-14 19:45:00,0.099778858 2014-07-14 19:50:00,0.0 2014-07-14 19:55:00,0.0 2014-07-14 20:00:00,0.0 2014-07-14 20:05:00,0.0 2014-07-14 20:10:00,0.109809041 2014-07-14 20:15:00,0.0 2014-07-14 20:20:00,0.0 2014-07-14 20:30:00,0.08800430599999999 2014-07-14 20:35:00,0.0 2014-07-14 20:40:00,0.0 2014-07-14 20:45:00,0.0 2014-07-14 20:50:00,0.0 2014-07-14 20:55:00,0.0 2014-07-14 21:00:00,0.0 2014-07-14 21:05:00,0.085474809 2014-07-14 21:10:00,0.0 2014-07-14 21:15:00,0.0 2014-07-14 21:20:00,0.0 2014-07-14 21:25:00,0.0 2014-07-14 21:30:00,0.0 2014-07-14 21:35:00,0.0 2014-07-14 21:40:00,0.0 2014-07-14 21:45:00,0.0 2014-07-14 21:50:00,0.0 2014-07-14 21:55:00,0.0 2014-07-14 22:00:00,0.0 2014-07-14 22:05:00,0.0 2014-07-14 22:10:00,0.0 2014-07-14 22:15:00,0.0 2014-07-14 22:20:00,0.0 2014-07-14 22:25:00,0.0 2014-07-14 22:30:00,0.0 2014-07-14 22:35:00,0.0 2014-07-14 22:40:00,0.0 2014-07-14 22:45:00,0.0 2014-07-14 22:50:00,0.0 2014-07-14 22:55:00,0.0 2014-07-14 23:00:00,0.0 2014-07-14 23:05:00,0.0 2014-07-14 23:10:00,0.0 2014-07-14 23:15:00,0.0 2014-07-14 23:20:00,0.0 2014-07-14 23:25:00,0.0 2014-07-14 23:30:00,0.0 2014-07-14 23:35:00,0.0 2014-07-14 23:40:00,0.0 2014-07-14 23:45:00,0.0 2014-07-14 23:50:00,0.0 2014-07-14 23:55:00,0.0 2014-07-15 00:00:00,0.0 2014-07-15 00:05:00,0.113392589 2014-07-15 00:10:00,0.153085695 2014-07-15 00:15:00,0.0 2014-07-15 00:20:00,0.0 2014-07-15 00:25:00,0.0 2014-07-15 00:30:00,0.08191084900000001 2014-07-15 00:35:00,0.0 2014-07-15 00:40:00,0.0 2014-07-15 00:45:00,0.0 2014-07-15 00:50:00,0.0 2014-07-15 00:55:00,0.0 2014-07-15 01:00:00,0.0 2014-07-15 01:05:00,0.0 2014-07-15 01:10:00,0.0 2014-07-15 01:15:00,0.0 2014-07-15 01:20:00,0.0 2014-07-15 01:25:00,0.0 2014-07-15 01:30:00,0.0 2014-07-15 01:35:00,0.0 2014-07-15 01:40:00,0.0 2014-07-15 01:45:00,0.0 2014-07-15 01:50:00,0.0 2014-07-15 01:55:00,0.0 2014-07-15 02:00:00,0.0 2014-07-15 02:05:00,0.0 2014-07-15 02:10:00,0.0 2014-07-15 02:15:00,0.0 2014-07-15 02:20:00,0.0 2014-07-15 02:25:00,0.0 2014-07-15 02:30:00,0.0 2014-07-15 02:35:00,0.0 2014-07-15 02:40:00,0.0 2014-07-15 02:45:00,0.0 2014-07-15 02:50:00,0.0 2014-07-15 02:55:00,0.0 2014-07-15 03:00:00,0.0 2014-07-15 03:05:00,0.0 2014-07-15 03:10:00,0.0 2014-07-15 03:15:00,0.0 2014-07-15 03:20:00,0.0 2014-07-15 03:25:00,0.0 2014-07-15 03:30:00,0.0 2014-07-15 03:35:00,0.0 2014-07-15 03:40:00,0.0 2014-07-15 03:45:00,0.0 2014-07-15 03:50:00,0.0 2014-07-15 03:55:00,0.0 2014-07-15 04:00:00,0.0 2014-07-15 04:05:00,0.0 2014-07-15 04:10:00,0.0 2014-07-15 04:15:00,0.0 2014-07-15 04:20:00,0.0 2014-07-15 04:25:00,0.0 2014-07-15 04:30:00,0.0 2014-07-15 04:35:00,0.0 2014-07-15 04:40:00,0.0 2014-07-15 04:45:00,0.0 2014-07-15 04:50:00,0.0 2014-07-15 04:55:00,0.0 2014-07-15 05:00:00,0.0 2014-07-15 05:05:00,0.0 2014-07-15 05:10:00,0.0 2014-07-15 05:15:00,0.0 2014-07-15 05:20:00,0.0 2014-07-15 05:25:00,0.0 2014-07-15 05:30:00,0.0 2014-07-15 05:35:00,0.0 2014-07-15 05:40:00,0.0 2014-07-15 05:45:00,0.0 2014-07-15 05:50:00,0.0 2014-07-15 05:55:00,0.0 2014-07-15 06:00:00,0.0 2014-07-15 06:05:00,0.0 2014-07-15 06:10:00,0.0 2014-07-15 06:15:00,0.0 2014-07-15 06:20:00,0.0 2014-07-15 06:25:00,0.0 2014-07-15 06:30:00,0.0 2014-07-15 06:35:00,0.0 2014-07-15 06:40:00,0.0 2014-07-15 06:45:00,0.0 2014-07-15 06:50:00,0.0 2014-07-15 06:55:00,0.0 2014-07-15 07:00:00,0.0 2014-07-15 07:05:00,0.0 2014-07-15 07:10:00,0.0 2014-07-15 07:15:00,0.0 2014-07-15 07:20:00,0.0 2014-07-15 07:25:00,0.0 2014-07-15 07:30:00,0.0 2014-07-15 07:35:00,0.0 2014-07-15 07:40:00,0.0 2014-07-15 07:45:00,0.0 2014-07-15 07:50:00,0.0 2014-07-15 07:55:00,0.0 2014-07-15 08:00:00,0.0 2014-07-15 08:05:00,0.0 2014-07-15 08:10:00,0.0 2014-07-15 08:15:00,0.0 2014-07-15 08:20:00,0.0 2014-07-15 08:25:00,0.0 2014-07-15 08:30:00,0.0 2014-07-15 08:35:00,0.0 2014-07-15 08:40:00,0.0 2014-07-15 08:45:00,0.0 2014-07-15 08:50:00,0.0 2014-07-15 08:55:00,0.0 2014-07-15 09:00:00,0.0 2014-07-15 09:05:00,0.0 2014-07-15 09:10:00,0.0 2014-07-15 09:15:00,0.0 2014-07-15 09:20:00,0.0 2014-07-15 09:25:00,0.0 2014-07-15 09:30:00,0.0 2014-07-15 09:35:00,0.0 2014-07-15 09:40:00,0.0 2014-07-15 09:45:00,0.0 2014-07-15 09:50:00,0.0 2014-07-15 09:55:00,0.0 2014-07-15 10:05:00,0.074724019 2014-07-15 10:40:00,0.081010018 2014-07-15 10:45:00,0.072983488 2014-07-15 10:50:00,0.08618763900000001 2014-07-15 10:55:00,0.081845165 2014-07-15 11:20:00,0.087103692 2014-07-15 11:25:00,0.084364615 2014-07-15 11:30:00,0.095506993 2014-07-15 11:35:00,0.065466642 2014-07-15 11:40:00,0.089246559 2014-07-15 11:45:00,0.067008018 2014-07-15 11:55:00,0.091611182 2014-07-15 12:00:00,0.078721786 2014-07-15 12:05:00,0.0 2014-07-15 12:10:00,0.082381546 2014-07-15 12:15:00,0.116034985 2014-07-15 12:20:00,0.0 2014-07-15 12:25:00,0.084316413 2014-07-15 12:30:00,0.08645440900000001 2014-07-15 12:35:00,0.085921212 2014-07-15 12:40:00,0.0 2014-07-15 12:45:00,0.078981244 2014-07-15 12:50:00,0.071727986 2014-07-15 12:55:00,0.08374694 2014-07-15 13:00:00,0.127655029 2014-07-15 13:05:00,0.07211113799999999 2014-07-15 13:10:00,0.070604499 2014-07-15 13:15:00,0.070273212 2014-07-15 13:20:00,0.068471751 2014-07-15 13:25:00,0.086299364 2014-07-15 13:30:00,0.0 2014-07-15 13:35:00,0.0 2014-07-15 13:40:00,0.077449515 2014-07-15 13:45:00,0.067616585 2014-07-15 13:50:00,0.078807843 2014-07-15 13:55:00,0.07274336299999999 2014-07-15 14:00:00,0.0 2014-07-15 14:05:00,0.0 2014-07-15 14:10:00,0.0 2014-07-15 14:15:00,0.0 2014-07-15 14:25:00,0.080492813 2014-07-15 14:30:00,0.07925586700000001 2014-07-15 14:35:00,0.099784017 2014-07-15 14:40:00,0.094524997 2014-07-15 14:45:00,0.0 2014-07-15 14:50:00,0.0 2014-07-15 14:55:00,0.0 2014-07-15 15:00:00,0.148122787 2014-07-15 15:05:00,0.089310208 2014-07-15 15:10:00,0.072272571 2014-07-15 15:15:00,0.076298205 2014-07-15 15:20:00,0.072686692 2014-07-15 15:25:00,0.08762771800000001 2014-07-15 15:30:00,0.09528804 2014-07-15 15:35:00,0.08145366400000001 2014-07-15 15:40:00,0.079814911 2014-07-15 15:45:00,0.094125643 2014-07-15 15:50:00,0.083192171 2014-07-15 15:55:00,0.08591253300000001 2014-07-15 16:00:00,0.084625536 2014-07-15 16:05:00,0.082236197 2014-07-15 16:10:00,0.08890311199999999 2014-07-15 16:15:00,0.085081768 2014-07-15 16:20:00,0.079566366 2014-07-15 16:25:00,0.073478292 2014-07-15 16:30:00,0.072119777 2014-07-15 16:35:00,0.08529961 2014-07-15 16:45:00,0.0 2014-07-15 16:50:00,0.0 2014-07-15 16:55:00,0.0 2014-07-15 17:00:00,0.0 2014-07-15 17:05:00,0.0 2014-07-15 17:10:00,0.0 2014-07-15 17:15:00,0.0 2014-07-15 17:20:00,0.0 2014-07-15 17:25:00,0.078008972 2014-07-15 17:30:00,0.111104952 2014-07-15 17:35:00,0.087882042 2014-07-15 17:40:00,0.068434081 2014-07-15 17:45:00,0.0 2014-07-15 17:50:00,0.0 2014-07-15 17:55:00,0.114406149 2014-07-15 18:00:00,0.063544533 2014-07-15 18:05:00,0.0 2014-07-15 18:10:00,0.0 2014-07-15 18:15:00,0.06955913 2014-07-15 18:20:00,0.069773555 2014-07-15 18:25:00,0.068620113 2014-07-15 18:30:00,0.07671086099999999 2014-07-15 18:35:00,0.07475174400000001 2014-07-15 18:40:00,0.07469165900000001 2014-07-15 18:45:00,0.080636783 2014-07-15 18:50:00,0.073058015 2014-07-15 18:55:00,0.069489793 2014-07-15 19:00:00,0.072557135 2014-07-15 19:05:00,0.073479031 2014-07-15 19:10:00,0.071080778 2014-07-15 19:15:00,0.071638993 2014-07-15 19:20:00,0.07121422 2014-07-15 19:25:00,0.075122619 2014-07-15 19:30:00,0.08179059 2014-07-15 19:35:00,0.071841574 2014-07-15 19:40:00,0.137128337 2014-07-15 19:45:00,0.0 2014-07-15 19:50:00,0.0 2014-07-15 19:55:00,0.0 2014-07-15 20:05:00,0.06297117299999999 2014-07-15 20:10:00,0.0 2014-07-15 20:15:00,0.0 2014-07-15 20:25:00,0.0 2014-07-15 20:30:00,0.0 2014-07-15 20:35:00,0.0 2014-07-15 20:40:00,0.0 2014-07-15 20:45:00,0.0 2014-07-15 20:50:00,0.0 2014-07-15 20:55:00,0.0 2014-07-15 21:00:00,0.0 2014-07-15 21:05:00,0.0 2014-07-15 21:10:00,0.0 2014-07-15 21:15:00,0.0 2014-07-15 21:20:00,0.0 2014-07-15 21:25:00,0.0 2014-07-15 21:30:00,0.0 2014-07-15 21:35:00,0.0 2014-07-15 21:40:00,0.0 2014-07-15 21:45:00,0.0 2014-07-15 21:50:00,0.0 2014-07-15 21:55:00,0.0 2014-07-15 22:00:00,0.0 2014-07-15 22:05:00,0.0 2014-07-15 22:10:00,0.0 2014-07-15 22:15:00,0.0 2014-07-15 22:20:00,0.0 2014-07-15 22:25:00,0.0 2014-07-15 22:30:00,0.0 2014-07-15 22:35:00,0.0 2014-07-15 22:40:00,0.0 2014-07-15 22:45:00,0.0 2014-07-15 22:50:00,0.0 2014-07-15 22:55:00,0.0 2014-07-15 23:00:00,0.0 2014-07-15 23:05:00,0.0 2014-07-15 23:10:00,0.0 2014-07-15 23:15:00,0.0 2014-07-15 23:20:00,0.0 2014-07-15 23:25:00,0.0 2014-07-15 23:30:00,0.08347703 2014-07-15 23:35:00,0.0 2014-07-15 23:40:00,0.0 2014-07-15 23:45:00,0.0 2014-07-15 23:50:00,0.0 2014-07-15 23:55:00,0.0 2014-07-16 00:00:00,0.0 2014-07-16 00:05:00,0.0 2014-07-16 00:10:00,0.0 2014-07-16 00:15:00,0.0 2014-07-16 00:20:00,0.0 2014-07-16 00:25:00,0.0 2014-07-16 00:30:00,0.0 2014-07-16 00:35:00,0.0 2014-07-16 00:40:00,0.0 2014-07-16 00:45:00,0.0 2014-07-16 00:50:00,0.0 2014-07-16 00:55:00,0.0 2014-07-16 01:00:00,0.0 2014-07-16 01:05:00,0.0 2014-07-16 01:10:00,0.0 2014-07-16 01:15:00,0.0 2014-07-16 01:20:00,0.0 2014-07-16 01:25:00,0.0 2014-07-16 01:30:00,0.0 2014-07-16 01:35:00,0.0 2014-07-16 01:40:00,0.0 2014-07-16 01:45:00,0.0 2014-07-16 01:50:00,0.0 2014-07-16 01:55:00,0.0 2014-07-16 02:00:00,0.0 2014-07-16 02:05:00,0.0 2014-07-16 02:10:00,0.0 2014-07-16 02:15:00,0.0 2014-07-16 02:20:00,0.0 2014-07-16 02:25:00,0.0 2014-07-16 02:30:00,0.0 2014-07-16 02:35:00,0.0 2014-07-16 02:40:00,0.0 2014-07-16 02:45:00,0.0 2014-07-16 02:50:00,0.0 2014-07-16 02:55:00,0.0 2014-07-16 03:00:00,0.0 2014-07-16 03:05:00,0.0 2014-07-16 03:10:00,0.0 2014-07-16 03:15:00,0.0 2014-07-16 03:20:00,0.0 2014-07-16 03:25:00,0.0 2014-07-16 03:30:00,0.0 2014-07-16 03:35:00,0.0 2014-07-16 03:40:00,0.0 2014-07-16 03:45:00,0.0 2014-07-16 03:50:00,0.0 2014-07-16 03:55:00,0.0 2014-07-16 04:00:00,0.0 2014-07-16 04:05:00,0.0 2014-07-16 04:10:00,0.0 2014-07-16 04:15:00,0.0 2014-07-16 04:20:00,0.0 2014-07-16 04:25:00,0.0 2014-07-16 04:30:00,0.0 2014-07-16 04:35:00,0.0 2014-07-16 04:40:00,0.0 2014-07-16 04:45:00,0.0 2014-07-16 04:50:00,0.0 2014-07-16 04:55:00,0.0 2014-07-16 05:00:00,0.0 2014-07-16 05:05:00,0.0 2014-07-16 05:10:00,0.0 2014-07-16 05:15:00,0.0 2014-07-16 05:20:00,0.0 2014-07-16 05:25:00,0.0 2014-07-16 05:30:00,0.0 2014-07-16 05:35:00,0.0 2014-07-16 05:40:00,0.0 2014-07-16 05:45:00,0.0 2014-07-16 05:50:00,0.0 2014-07-16 05:55:00,0.0 2014-07-16 06:00:00,0.0 2014-07-16 06:05:00,0.0 2014-07-16 06:10:00,0.0 2014-07-16 06:15:00,0.0 2014-07-16 06:20:00,0.0 2014-07-16 06:25:00,0.0 2014-07-16 06:30:00,0.0 2014-07-16 06:35:00,0.0 2014-07-16 06:40:00,0.0 2014-07-16 06:45:00,0.0 2014-07-16 06:50:00,0.0 2014-07-16 06:55:00,0.0 2014-07-16 07:00:00,0.0 2014-07-16 07:05:00,0.0 2014-07-16 07:10:00,0.0 2014-07-16 07:15:00,0.0 2014-07-16 07:20:00,0.0 2014-07-16 07:25:00,0.0 2014-07-16 07:30:00,0.0 2014-07-16 07:35:00,0.0 2014-07-16 07:40:00,0.0 2014-07-16 07:45:00,0.0 2014-07-16 07:50:00,0.0 2014-07-16 07:55:00,0.0 2014-07-16 08:00:00,0.0 2014-07-16 08:05:00,0.0 2014-07-16 08:10:00,0.0 2014-07-16 08:15:00,0.0 2014-07-16 08:20:00,0.0 2014-07-16 08:25:00,0.0 2014-07-16 08:30:00,0.0 2014-07-16 08:35:00,0.0 2014-07-16 08:40:00,0.0 2014-07-16 08:45:00,0.0 2014-07-16 08:50:00,0.0 2014-07-16 08:55:00,0.0 2014-07-16 09:00:00,0.0 2014-07-16 09:05:00,0.0 2014-07-16 09:10:00,0.0 2014-07-16 09:15:00,0.0 2014-07-16 09:20:00,0.0 2014-07-16 09:25:00,0.0 2014-07-16 09:30:00,0.0 2014-07-16 09:35:00,0.0 2014-07-16 09:40:00,0.0 2014-07-16 09:45:00,0.0 2014-07-16 09:50:00,0.0 2014-07-16 09:55:00,0.0 2014-07-16 10:00:00,0.0 2014-07-16 10:05:00,0.0 2014-07-16 10:10:00,0.0 2014-07-16 10:15:00,0.0 2014-07-16 10:20:00,0.076638222 2014-07-16 10:25:00,0.0 2014-07-16 10:30:00,0.0 2014-07-16 10:35:00,0.0 2014-07-16 10:40:00,0.0 2014-07-16 10:45:00,0.0 2014-07-16 10:50:00,0.0 2014-07-16 10:55:00,0.0 2014-07-16 11:00:00,0.0 2014-07-16 11:05:00,0.0 2014-07-16 11:10:00,0.0 2014-07-16 11:15:00,0.0 2014-07-16 11:20:00,0.0 2014-07-16 11:25:00,0.0 2014-07-16 11:30:00,0.0 2014-07-16 11:35:00,0.0 2014-07-16 11:40:00,0.0 2014-07-16 11:45:00,0.0 2014-07-16 11:50:00,0.0 2014-07-16 11:55:00,0.0 2014-07-16 12:00:00,0.0 2014-07-16 12:05:00,0.0 2014-07-16 12:10:00,0.0 2014-07-16 12:15:00,0.0 2014-07-16 12:20:00,0.0 2014-07-16 12:25:00,0.0 2014-07-16 12:30:00,0.0 2014-07-16 12:35:00,0.0 2014-07-16 12:40:00,0.0 2014-07-16 12:45:00,0.0 2014-07-16 12:50:00,0.0 2014-07-16 12:55:00,0.0 2014-07-16 13:00:00,0.0 2014-07-16 13:05:00,0.0 2014-07-16 13:10:00,0.0 2014-07-16 13:15:00,0.0 2014-07-16 13:20:00,0.0 2014-07-16 13:25:00,0.0 2014-07-16 13:30:00,0.0 2014-07-16 13:35:00,0.0 2014-07-16 13:40:00,0.0 2014-07-16 13:45:00,0.0 2014-07-16 13:50:00,0.0 2014-07-16 13:55:00,0.0 2014-07-16 14:00:00,0.0 2014-07-16 14:05:00,0.0 2014-07-16 14:10:00,0.0 2014-07-16 14:15:00,0.0 2014-07-16 14:20:00,0.0 2014-07-16 14:25:00,0.0 2014-07-16 14:30:00,0.0 2014-07-16 14:35:00,0.0 2014-07-16 14:40:00,0.0 2014-07-16 14:45:00,0.0 2014-07-16 14:50:00,0.0 2014-07-16 14:55:00,0.0 2014-07-16 15:00:00,0.0 2014-07-16 15:05:00,0.0 2014-07-16 15:10:00,0.0 2014-07-16 15:15:00,0.0 2014-07-16 15:20:00,0.0 2014-07-16 15:25:00,0.0 2014-07-16 15:30:00,0.0 2014-07-16 15:35:00,0.0 2014-07-16 15:40:00,0.0 2014-07-16 15:45:00,0.0 2014-07-16 15:50:00,0.0 2014-07-16 15:55:00,0.0 2014-07-16 16:00:00,0.0 2014-07-16 16:05:00,0.0 2014-07-16 16:10:00,0.0 2014-07-16 16:15:00,0.0 2014-07-16 16:20:00,0.0 2014-07-16 16:25:00,0.0 2014-07-16 16:30:00,0.0 2014-07-16 16:35:00,0.0 2014-07-16 16:40:00,0.0 2014-07-16 16:45:00,0.0 2014-07-16 16:50:00,0.0 2014-07-16 16:55:00,0.0 2014-07-16 17:00:00,0.0 2014-07-16 17:05:00,0.0 2014-07-16 17:10:00,0.0 2014-07-16 17:15:00,0.0 2014-07-16 17:20:00,0.0 2014-07-16 17:25:00,0.0 2014-07-16 17:30:00,0.0 2014-07-16 17:35:00,0.0 2014-07-16 17:40:00,0.0 2014-07-16 17:45:00,0.0 2014-07-16 17:50:00,0.0 2014-07-16 17:55:00,0.0 2014-07-16 18:00:00,0.0 2014-07-16 18:05:00,0.0 2014-07-16 18:10:00,0.0 2014-07-16 18:15:00,0.0 2014-07-16 18:20:00,0.0 2014-07-16 18:25:00,0.0 2014-07-16 18:30:00,0.0 2014-07-16 18:35:00,0.0 2014-07-16 18:40:00,0.117964904 2014-07-16 18:45:00,0.0 2014-07-16 18:55:00,0.103039529 2014-07-16 19:05:00,0.06518697700000001 2014-07-16 19:10:00,0.0 2014-07-16 19:20:00,0.0 2014-07-16 19:25:00,0.0 2014-07-16 19:30:00,0.0 2014-07-16 19:35:00,0.0 2014-07-16 19:40:00,0.0 2014-07-16 19:45:00,0.0 2014-07-16 19:50:00,0.0 2014-07-16 19:55:00,0.0 2014-07-16 20:00:00,0.0 2014-07-16 20:05:00,0.0 2014-07-16 20:10:00,0.0 2014-07-16 20:15:00,0.0 2014-07-16 20:20:00,0.0 2014-07-16 20:25:00,0.0 2014-07-16 20:30:00,0.0 2014-07-16 20:35:00,0.0 2014-07-16 20:40:00,0.0 2014-07-16 20:45:00,0.0 2014-07-16 20:50:00,0.0 2014-07-16 20:55:00,0.0 2014-07-16 21:00:00,0.0 2014-07-16 21:05:00,0.0 2014-07-16 21:10:00,0.0 2014-07-16 21:15:00,0.0 2014-07-16 21:20:00,0.0 2014-07-16 21:25:00,0.0 2014-07-16 21:30:00,0.0 2014-07-16 21:35:00,0.0 2014-07-16 21:40:00,0.0 2014-07-16 21:45:00,0.0 2014-07-16 21:50:00,0.0 2014-07-16 21:55:00,0.0 2014-07-16 22:00:00,0.0 2014-07-16 22:05:00,0.0 2014-07-16 22:10:00,0.0 2014-07-16 22:15:00,0.0 2014-07-16 22:20:00,0.0 2014-07-16 22:25:00,0.0 2014-07-16 22:30:00,0.0 2014-07-16 22:35:00,0.0 2014-07-16 22:40:00,0.0 2014-07-16 22:45:00,0.0 2014-07-16 22:50:00,0.0 2014-07-16 22:55:00,0.0 2014-07-16 23:00:00,0.0 2014-07-16 23:05:00,0.0 2014-07-16 23:10:00,0.0 2014-07-16 23:15:00,0.0 2014-07-16 23:20:00,0.0 2014-07-16 23:25:00,0.0 2014-07-16 23:30:00,0.0 2014-07-16 23:35:00,0.0 2014-07-16 23:40:00,0.0 2014-07-16 23:45:00,0.0 2014-07-16 23:50:00,0.0 2014-07-16 23:55:00,0.0 2014-07-17 00:00:00,0.0 2014-07-17 00:05:00,0.0 2014-07-17 00:10:00,0.0 2014-07-17 00:15:00,0.0 2014-07-17 00:20:00,0.0 2014-07-17 00:25:00,0.0 2014-07-17 00:30:00,0.0 2014-07-17 00:35:00,0.0 2014-07-17 00:40:00,0.0 2014-07-17 00:45:00,0.0 2014-07-17 00:50:00,0.0 2014-07-17 00:55:00,0.0 2014-07-17 01:00:00,0.0 2014-07-17 01:05:00,0.0 2014-07-17 01:15:00,0.0 2014-07-17 01:20:00,0.0 2014-07-17 01:25:00,0.0 2014-07-17 01:30:00,0.0 2014-07-17 01:35:00,0.0 2014-07-17 01:40:00,0.0 2014-07-17 01:45:00,0.0 2014-07-17 01:50:00,0.0 2014-07-17 01:55:00,0.0 2014-07-17 02:00:00,0.0 2014-07-17 02:05:00,0.0 2014-07-17 02:10:00,0.0 2014-07-17 02:15:00,0.0 2014-07-17 02:20:00,0.0 2014-07-17 02:25:00,0.0 2014-07-17 02:30:00,0.0 2014-07-17 02:35:00,0.0 2014-07-17 02:40:00,0.0 2014-07-17 02:45:00,0.0 2014-07-17 02:50:00,0.0 2014-07-17 02:55:00,0.0 2014-07-17 03:00:00,0.0 2014-07-17 03:05:00,0.0 2014-07-17 03:10:00,0.0 2014-07-17 03:15:00,0.0 2014-07-17 03:20:00,0.0 2014-07-17 03:25:00,0.0 2014-07-17 03:30:00,0.0 2014-07-17 03:35:00,0.0 2014-07-17 03:40:00,0.0 2014-07-17 03:45:00,0.0 2014-07-17 03:50:00,0.0 2014-07-17 03:55:00,0.0 2014-07-17 04:00:00,0.0 2014-07-17 04:05:00,0.0 2014-07-17 04:10:00,0.0 2014-07-17 04:15:00,0.0 2014-07-17 04:20:00,0.0 2014-07-17 04:25:00,0.0 2014-07-17 04:30:00,0.0 2014-07-17 04:35:00,0.0 2014-07-17 04:40:00,0.0 2014-07-17 04:45:00,0.0 2014-07-17 04:50:00,0.0 2014-07-17 04:55:00,0.0 2014-07-17 05:00:00,0.0 2014-07-17 05:05:00,0.0 2014-07-17 05:10:00,0.0 2014-07-17 05:15:00,0.0 2014-07-17 05:20:00,0.0 2014-07-17 05:25:00,0.0 2014-07-17 05:30:00,0.0 2014-07-17 05:35:00,0.0 2014-07-17 05:40:00,0.0 2014-07-17 05:45:00,0.0 2014-07-17 05:50:00,0.0 2014-07-17 05:55:00,0.0 2014-07-17 06:00:00,0.0 2014-07-17 06:05:00,0.0 2014-07-17 06:10:00,0.0 2014-07-17 06:15:00,0.0 2014-07-17 06:20:00,0.0 2014-07-17 06:25:00,0.0 2014-07-17 06:30:00,0.0 2014-07-17 06:35:00,0.0 2014-07-17 06:40:00,0.0 2014-07-17 06:45:00,0.0 2014-07-17 06:50:00,0.0 2014-07-17 06:55:00,0.0 2014-07-17 07:00:00,0.0 2014-07-17 07:05:00,0.0 2014-07-17 07:10:00,0.0 2014-07-17 07:15:00,0.0 2014-07-17 07:20:00,0.0 2014-07-17 07:25:00,0.0 2014-07-17 07:30:00,0.0 2014-07-17 07:35:00,0.0 2014-07-17 07:40:00,0.0 2014-07-17 07:45:00,0.0 2014-07-17 07:50:00,0.0 2014-07-17 07:55:00,0.0 2014-07-17 08:00:00,0.0 2014-07-17 08:05:00,0.0 2014-07-17 08:10:00,0.0 2014-07-17 08:15:00,0.0 2014-07-17 08:20:00,0.0 2014-07-17 08:25:00,0.0 2014-07-17 08:30:00,0.077423356 2014-07-17 08:35:00,0.098985658 2014-07-17 08:40:00,0.0 2014-07-17 08:50:00,0.0 2014-07-17 08:55:00,0.0 2014-07-17 09:00:00,0.0 2014-07-17 09:05:00,0.0 2014-07-17 09:10:00,0.0 2014-07-17 09:15:00,0.0 2014-07-17 09:20:00,0.0 2014-07-17 09:25:00,0.0 2014-07-17 09:30:00,0.0 2014-07-17 09:35:00,0.0 2014-07-17 09:40:00,0.0 2014-07-17 09:45:00,0.0 2014-07-17 09:50:00,0.0 2014-07-17 09:55:00,0.0 2014-07-17 10:00:00,0.0 2014-07-17 10:05:00,0.0 2014-07-17 10:10:00,0.0 2014-07-17 10:15:00,0.0 2014-07-17 10:20:00,0.0 2014-07-17 10:25:00,0.0 2014-07-17 10:30:00,0.0 2014-07-17 10:35:00,0.0 2014-07-17 10:40:00,0.0 2014-07-17 10:45:00,0.0 2014-07-17 10:50:00,0.0 2014-07-17 10:55:00,0.0 2014-07-17 11:00:00,0.0 2014-07-17 11:05:00,0.0 2014-07-17 11:10:00,0.075698766 2014-07-17 11:15:00,0.0 2014-07-17 11:20:00,0.0 2014-07-17 11:25:00,0.0 2014-07-17 11:30:00,0.0 2014-07-17 11:35:00,0.0 2014-07-17 11:45:00,0.0 2014-07-17 11:50:00,0.0 2014-07-17 12:00:00,0.0 2014-07-17 12:05:00,0.0 2014-07-17 12:10:00,0.099804997 2014-07-17 12:15:00,0.154392838 2014-07-17 12:20:00,0.0 2014-07-17 12:25:00,0.0 2014-07-17 12:30:00,0.100179557 2014-07-17 12:35:00,0.096398302 2014-07-17 12:40:00,0.080038962 2014-07-17 12:45:00,0.145575047 2014-07-17 12:50:00,0.079540943 2014-07-17 12:55:00,0.122484446 2014-07-17 13:00:00,0.092316898 2014-07-17 13:05:00,0.181797504 2014-07-17 13:10:00,0.181043005 2014-07-17 13:15:00,0.167886972 2014-07-17 13:20:00,0.185409403 2014-07-17 13:25:00,0.16096556199999998 2014-07-17 13:30:00,0.213152885 2014-07-17 16:30:00,0.256532192 2014-07-17 21:30:00,0.0 2014-07-18 03:30:00,0.0 2014-07-18 06:40:00,0.0 2014-07-18 06:45:00,0.0 2014-07-18 06:50:00,0.0 2014-07-18 06:55:00,0.075918346 2014-07-18 07:00:00,0.088902824 2014-07-18 07:05:00,0.0 2014-07-18 07:10:00,0.0 2014-07-18 07:15:00,0.0 2014-07-18 07:20:00,0.0 2014-07-18 07:25:00,0.0 2014-07-18 08:35:00,0.07629801900000001 2014-07-18 08:40:00,0.078025562 2014-07-18 08:45:00,0.129002392 2014-07-18 08:50:00,0.0 2014-07-18 08:55:00,0.0 2014-07-18 09:00:00,0.0 2014-07-18 09:05:00,0.0 2014-07-18 09:10:00,0.0 2014-07-18 09:15:00,0.0 2014-07-18 09:20:00,0.0 2014-07-18 09:25:00,0.0 2014-07-18 09:30:00,0.0 2014-07-18 09:35:00,0.0 2014-07-18 09:40:00,0.0 2014-07-18 09:45:00,0.0 2014-07-18 09:50:00,0.0 2014-07-18 09:55:00,0.0 2014-07-18 10:00:00,0.0 2014-07-18 10:55:00,0.0 2014-07-18 11:00:00,0.0 2014-07-18 11:05:00,0.0 2014-07-18 11:10:00,0.0 2014-07-18 11:15:00,0.0 2014-07-18 11:20:00,0.0 2014-07-18 11:25:00,0.0 2014-07-18 11:30:00,0.0 2014-07-18 11:50:00,0.0 2014-07-18 11:55:00,0.0 2014-07-18 12:00:00,0.0 2014-07-18 12:05:00,0.0 2014-07-18 12:10:00,0.0 2014-07-18 12:15:00,0.0 2014-07-18 12:20:00,0.0 2014-07-18 12:25:00,0.0 2014-07-18 12:30:00,0.0 2014-07-18 12:35:00,0.0 2014-07-18 12:40:00,0.0 2014-07-18 12:50:00,0.0 2014-07-18 12:55:00,0.0 2014-07-18 13:00:00,0.0 2014-07-18 13:05:00,0.0 2014-07-18 13:10:00,0.0 2014-07-18 13:30:00,0.0 2014-07-20 05:35:00,0.08837019900000001 2014-07-20 05:40:00,0.078759973 2014-07-20 05:45:00,0.083010178 2014-07-20 05:50:00,0.08861694699999999 2014-07-20 05:55:00,0.085390379 2014-07-20 06:00:00,0.083756364 2014-07-20 06:05:00,0.125853002 2014-07-20 06:10:00,0.086653279 2014-07-20 06:15:00,0.064589664 2014-07-20 06:20:00,0.081922395 2014-07-20 06:25:00,0.081532863 2014-07-20 06:30:00,0.079646328 2014-07-20 06:35:00,0.090795596 2014-07-20 06:40:00,0.075009891 2014-07-20 06:45:00,0.083280383 2014-07-20 06:50:00,0.067865371 2014-07-20 06:55:00,0.071016709 2014-07-20 07:00:00,0.065320139 2014-07-20 07:05:00,0.081546221 2014-07-20 07:10:00,0.08385719400000001 2014-07-20 07:15:00,0.08925564300000001 2014-07-20 07:20:00,0.06688303 2014-07-20 07:25:00,0.064959883 2014-07-20 07:30:00,0.06097663 2014-07-20 07:35:00,0.059792013 2014-07-20 07:40:00,0.078348523 2014-07-20 07:45:00,0.077374113 2014-07-20 07:50:00,0.07966400900000001 2014-07-20 07:55:00,0.08777109300000001 2014-07-20 08:00:00,0.076440345 2014-07-20 08:05:00,0.08259113400000001 2014-07-20 08:10:00,0.07116006 2014-07-20 08:15:00,0.091661677 2014-07-20 08:20:00,0.084915466 2014-07-20 08:25:00,0.081899181 2014-07-20 08:30:00,0.082369635 2014-07-20 08:35:00,0.087235705 2014-07-21 11:20:00,0.071238098 2014-07-21 11:25:00,0.08691614800000001 2014-07-21 11:30:00,0.073151928 2014-07-21 11:35:00,0.075275989 2014-07-21 11:40:00,0.079913506 2014-07-21 11:45:00,0.079200711 2014-07-21 11:50:00,0.102046473 2014-07-21 11:55:00,0.072009265 2014-07-21 12:00:00,0.0 2014-07-21 12:05:00,0.093747727 2014-07-21 12:10:00,0.07192952700000001 2014-07-21 12:15:00,0.092240284 2014-07-21 12:20:00,0.08607551699999999 2014-07-21 12:25:00,0.103967011 2014-07-21 12:30:00,0.0 2014-07-21 12:35:00,0.0 2014-07-21 12:40:00,0.0 2014-07-21 12:45:00,0.086884194 2014-07-21 12:50:00,0.117275238 2014-07-21 12:55:00,0.0 2014-07-21 13:00:00,0.0 2014-07-21 13:20:00,0.081546437 2014-07-21 13:25:00,0.0 2014-07-21 13:30:00,0.0 2014-07-21 13:35:00,0.0 2014-07-21 13:40:00,0.0 2014-07-22 02:00:00,0.082676935 2014-07-22 02:05:00,0.07217667700000001 2014-07-22 02:10:00,0.1026359 2014-07-22 02:15:00,0.068788141 2014-07-22 02:20:00,0.076415445 2014-07-22 02:25:00,0.069610348 2014-07-22 02:30:00,0.074864876 2014-07-22 02:35:00,0.063544522 2014-07-22 02:40:00,0.099381566 2014-07-22 02:45:00,0.0 2014-07-22 02:50:00,0.066098839 2014-07-22 02:55:00,0.077184598 2014-07-22 03:00:00,0.067246207 2014-07-22 03:05:00,0.0 2014-07-22 03:10:00,0.07331007 2014-07-22 03:15:00,0.07823991799999999 2014-07-22 03:20:00,0.074598854 2014-07-22 03:25:00,0.074727423 2014-07-22 03:30:00,0.106285294 2014-07-22 03:35:00,0.071302036 2014-07-22 03:40:00,0.069261506 2014-07-22 03:45:00,0.071043954 2014-07-22 03:50:00,0.07251629 2014-07-22 03:55:00,0.081079956 2014-07-22 04:00:00,0.072769252 2014-07-22 04:35:00,0.086065877 2014-07-22 04:40:00,0.08397303099999999 2014-07-22 04:45:00,0.080356677 2014-07-22 04:50:00,0.087925255 2014-07-22 04:55:00,0.07977986299999999 2014-07-22 05:00:00,0.0 2014-07-22 05:05:00,0.0 2014-07-22 05:10:00,0.087990178 2014-07-22 05:15:00,0.08447536900000001 2014-07-22 05:20:00,0.105537585 2014-07-22 05:25:00,0.083881527 2014-07-22 05:30:00,0.087496805 2014-07-22 05:35:00,0.073710733 2014-07-22 05:40:00,0.066292941 2014-07-22 05:45:00,0.06467717 2014-07-22 05:50:00,0.07062594700000001 2014-07-22 05:55:00,0.069643898 2014-07-22 06:00:00,0.066808108 2014-07-22 06:05:00,0.074006823 2014-07-22 06:10:00,0.09600998 2014-07-22 06:15:00,0.070130505 2014-07-22 06:20:00,0.08710951800000001 2014-07-22 06:25:00,0.067063945 2014-07-22 06:30:00,0.089206405 2014-07-22 06:35:00,0.062315247 2014-07-22 06:40:00,0.071898393 2014-07-22 06:45:00,0.081883682 2014-07-22 06:50:00,0.077740383 2014-07-22 06:55:00,0.101794004 2014-07-22 07:00:00,0.075867248 2014-07-22 07:05:00,0.078512921 2014-07-22 07:10:00,0.087242691 2014-07-22 07:15:00,0.068022267 2014-07-22 07:20:00,0.065473058 2014-07-22 07:25:00,0.07113723200000001 2014-07-22 07:30:00,0.091192008 2014-07-22 07:35:00,0.08384286099999999 2014-07-22 07:40:00,0.084881976 2014-07-22 07:45:00,0.069177867 2014-07-22 07:50:00,0.065212768 2014-07-22 07:55:00,0.06537169 2014-07-22 08:00:00,0.0 2014-07-22 08:05:00,0.0 2014-07-22 08:15:00,0.066673024 2014-07-22 08:20:00,0.081489706 2014-07-22 08:25:00,0.087758636 2014-07-22 08:30:00,0.07695827200000001 2014-07-22 08:35:00,0.081872515 2014-07-22 08:40:00,0.06749843400000001 2014-07-22 08:45:00,0.077520247 2014-07-22 08:50:00,0.07340019 2014-07-22 08:55:00,0.077518924 2014-07-22 09:00:00,0.077860681 2014-07-22 09:05:00,0.081376882 2014-07-22 09:10:00,0.078736668 2014-07-22 09:15:00,0.081914268 2014-07-22 09:20:00,0.084949445 2014-07-22 09:25:00,0.085251038 2014-07-22 09:30:00,0.08794400000000001 2014-07-22 09:35:00,0.087185803 2014-07-22 09:40:00,0.08670235 2014-07-22 09:45:00,0.079396967 2014-07-22 09:50:00,0.064100263 2014-07-22 09:55:00,0.0 2014-07-22 10:00:00,0.0 2014-07-22 10:05:00,0.0 2014-07-22 10:10:00,0.0 2014-07-22 10:15:00,0.075937231 2014-07-22 10:20:00,0.063441813 2014-07-22 10:25:00,0.08886477699999999 2014-07-22 10:30:00,0.0 2014-07-22 10:35:00,0.0 2014-07-22 10:40:00,0.0 2014-07-22 10:45:00,0.0 2014-07-22 10:50:00,0.0 2014-07-22 10:55:00,0.0 2014-07-22 11:00:00,0.066337222 2014-07-22 11:05:00,0.08218078599999999 2014-07-22 11:10:00,0.0 2014-07-22 11:20:00,0.082968481 2014-07-22 11:25:00,0.094356045 2014-07-22 11:30:00,0.08977174800000001 2014-07-22 11:35:00,0.095347788 2014-07-22 11:40:00,0.08870353199999999 2014-07-22 11:45:00,0.079930566 2014-07-22 11:50:00,0.099499519 2014-07-22 11:55:00,0.093424884 2014-07-22 12:00:00,0.078719417 2014-07-22 12:05:00,0.074829279 2014-07-22 12:10:00,0.075621686 2014-07-22 12:15:00,0.081784352 2014-07-22 12:20:00,0.080311402 2014-07-22 12:25:00,0.094215231 2014-07-22 12:30:00,0.098539943 2014-07-22 12:35:00,0.063090687 2014-07-22 12:40:00,0.349751279 2014-07-23 07:20:00,0.078692155 2014-07-23 07:25:00,0.0 2014-07-23 07:30:00,0.097602643 2014-07-23 07:35:00,0.079580865 2014-07-23 07:40:00,0.076324244 2014-07-23 07:45:00,0.08432425699999999 2014-07-23 07:50:00,0.065346726 2014-07-23 07:55:00,0.064352295 2014-07-23 08:00:00,0.061049436 2014-07-23 08:05:00,0.06098353400000001 2014-07-23 08:10:00,0.062208184000000014 2014-07-23 08:15:00,0.065034564 2014-07-23 08:20:00,0.072705949 2014-07-23 08:25:00,0.066192 2014-07-23 08:30:00,0.06410224099999999 2014-07-23 08:35:00,0.06770680400000001 2014-07-23 08:40:00,0.061213848 2014-07-23 08:45:00,0.0636799 2014-07-23 08:50:00,0.06978205400000001 2014-07-23 08:55:00,0.066042146 2014-07-23 09:05:00,0.083272074 2014-07-23 09:10:00,0.06986912599999999 2014-07-23 09:15:00,0.089911461 2014-07-23 09:20:00,0.0 2014-07-23 09:25:00,0.0 2014-07-23 09:30:00,0.0 2014-07-23 09:35:00,0.0 2014-07-23 09:40:00,0.0 2014-07-23 09:45:00,0.0 2014-07-23 09:50:00,0.0 2014-07-23 09:55:00,0.0 2014-07-23 10:05:00,0.0 2014-07-23 10:10:00,0.070423741 2014-07-23 10:15:00,0.073670626 2014-07-23 10:20:00,0.0 2014-07-23 10:25:00,0.066148576 2014-07-23 10:30:00,0.067378998 2014-07-23 10:35:00,0.059605674 2014-07-23 10:40:00,0.064556568 2014-07-23 10:45:00,0.064033921 2014-07-23 10:50:00,0.076436295 2014-07-23 10:55:00,0.068352964 2014-07-23 11:00:00,0.087604841 2014-07-23 11:05:00,0.065447872 2014-07-23 11:10:00,0.068623924 2014-07-23 11:15:00,0.073543434 2014-07-23 11:20:00,0.078354799 2014-07-23 11:25:00,0.073093331 2014-07-23 11:30:00,0.061083667 2014-07-23 11:35:00,0.076646452 2014-07-23 11:40:00,0.068090503 2014-07-23 11:45:00,0.081139378 2014-07-23 11:50:00,0.8950121529999999 2014-07-23 11:55:00,0.084473344 2014-07-23 12:00:00,0.069972732 2014-07-23 12:05:00,0.07644509099999999 2014-07-23 12:10:00,0.08279169900000001 2014-07-23 12:15:00,0.096352205 2014-07-23 12:20:00,0.07790807599999999 2014-07-23 12:25:00,0.075705942 2014-07-23 12:30:00,0.07219347599999999 2014-07-23 12:35:00,0.064731841 2014-07-23 12:40:00,0.076889346 2014-07-23 12:45:00,0.06270653 2014-07-23 12:50:00,0.06578236400000001 2014-07-23 12:55:00,0.070512584 2014-07-23 13:00:00,0.065273208 2014-07-23 13:05:00,0.06391691099999999 2014-07-23 13:10:00,0.062644989 2014-07-23 13:15:00,0.066731398 2014-07-23 13:20:00,0.063483177 2014-07-23 13:25:00,0.073762227 2014-07-23 13:30:00,0.09574565 2014-07-23 13:35:00,0.063987507 2014-07-23 13:40:00,0.0 2014-07-23 13:45:00,0.061681696 2014-07-23 13:50:00,0.067545557 2014-07-23 13:55:00,0.36199113 2014-07-23 14:00:00,0.06789997099999999 2014-07-23 14:05:00,0.06809734099999999 2014-07-23 14:10:00,0.06805268099999999 2014-07-23 14:15:00,0.067784277 2014-07-23 14:20:00,0.07164703900000001 2014-07-23 14:25:00,0.072229549 2014-07-23 14:30:00,0.071906585 2014-07-23 14:35:00,0.067114268 2014-07-23 14:40:00,0.099018082 2014-07-23 14:45:00,0.610788546 2014-07-23 14:50:00,0.073930318 2014-07-23 14:55:00,0.0 2014-07-23 15:00:00,0.07169031599999999 2014-07-23 15:05:00,0.077011813 2014-07-23 15:10:00,0.067765429 2014-07-23 15:15:00,0.07217746400000001 2014-07-23 15:20:00,0.067513486 2014-07-23 15:25:00,0.064085774 2014-07-23 15:30:00,0.06260954099999999 2014-07-23 15:35:00,0.061791321 2014-07-23 16:50:00,0.072957139 2014-07-23 16:55:00,0.07063700099999999 2014-07-23 17:00:00,0.075139932 2014-07-23 17:05:00,0.088852105 2014-07-23 17:10:00,0.082308069 2014-07-23 17:15:00,0.074726225 2014-07-23 17:20:00,0.079228689 2014-07-23 17:25:00,0.067461448 2014-07-23 17:30:00,0.07496677 2014-07-23 17:35:00,0.076553275 2014-07-23 17:40:00,0.064552832 2014-07-23 17:45:00,0.068947534 2014-07-23 17:50:00,0.067166564 2014-07-23 17:55:00,0.07933624 2014-07-23 18:00:00,0.074044645 2014-07-23 18:05:00,0.0 2014-07-23 18:10:00,0.0 2014-07-23 18:15:00,0.065402345 2014-07-23 18:20:00,0.092749881 2014-07-23 18:25:00,0.096656305 2014-07-23 18:30:00,0.098988258 2014-07-23 18:35:00,0.101811358 2014-07-23 18:40:00,0.093130313 2014-07-23 18:45:00,0.092407793 2014-07-23 18:50:00,0.0 2014-07-23 18:55:00,0.061650065 2014-07-23 19:15:00,0.0 2014-07-23 19:20:00,0.092823676 2014-07-23 19:25:00,0.074424922 2014-07-23 19:30:00,0.0 2014-07-23 19:35:00,0.07226751599999999 2014-07-23 19:40:00,0.0 2014-07-23 19:45:00,0.0 2014-07-23 19:50:00,0.0 2014-07-23 19:55:00,0.08830370900000001 2014-07-23 20:00:00,0.063548088 2014-07-23 20:05:00,0.0 2014-07-23 20:10:00,0.0 2014-07-23 20:15:00,0.0 2014-07-23 20:20:00,0.0 2014-07-24 05:55:00,0.06313646099999999 2014-07-24 06:00:00,0.072994453 2014-07-24 06:05:00,0.07012359 2014-07-24 06:10:00,0.108550088 2014-07-24 06:15:00,0.0 2014-07-24 06:25:00,0.069650797 2014-07-24 06:30:00,0.094860491 2014-07-24 06:35:00,0.065317447 2014-07-24 06:40:00,0.09187328 2014-07-24 06:45:00,0.101925869 2014-07-24 06:50:00,0.104564421 2014-07-24 06:55:00,0.080665497 2014-07-24 07:00:00,0.101051966 2014-07-24 07:05:00,0.0 2014-07-24 07:10:00,0.0 2014-07-24 07:15:00,0.07473769400000001 2014-07-24 07:20:00,0.069878197 2014-07-24 08:45:00,0.0 2014-07-24 08:50:00,0.0 2014-07-24 08:55:00,0.0 2014-07-24 09:00:00,0.0 2014-07-24 09:05:00,0.0 2014-07-24 09:10:00,0.0 2014-07-24 09:15:00,0.0 2014-07-24 09:20:00,0.0 2014-07-24 09:25:00,0.0 2014-07-24 09:30:00,0.0 2014-07-24 09:35:00,0.0 2014-07-24 09:40:00,0.0 2014-07-24 09:45:00,0.062455331 2014-07-24 09:50:00,0.070857845 2014-07-24 09:55:00,0.068090968 2014-07-24 10:00:00,0.079217003 2014-07-24 10:05:00,0.057993155 2014-07-24 10:10:00,0.06279552 2014-07-24 10:15:00,0.063083849 2014-07-24 10:20:00,0.064707347 2014-07-24 10:25:00,0.061793969 2014-07-24 10:30:00,0.057134586 2014-07-24 10:35:00,0.066382056 2014-07-24 10:40:00,0.06570248599999999 2014-07-24 10:45:00,0.07583788400000001 2014-07-24 10:50:00,0.07132485200000001 2014-07-24 10:55:00,0.072924837 2014-07-24 11:00:00,0.068822214 2014-07-24 11:05:00,0.067517329 2014-07-24 11:10:00,0.072035726 2014-07-24 11:15:00,0.069037403 2014-07-24 11:20:00,0.064108242 2014-07-24 11:25:00,0.060951365 2014-07-24 11:30:00,0.067261475 2014-07-24 11:35:00,0.06399500000000001 2014-07-24 11:40:00,0.114735047 2014-07-24 11:45:00,0.0 2014-07-24 11:50:00,0.062882542 2014-07-24 11:55:00,0.077318974 2014-07-24 12:00:00,0.069855268 2014-07-24 12:05:00,0.055725676 2014-07-24 12:10:00,0.093738198 2014-07-24 12:20:00,0.068159761 2014-07-24 12:25:00,0.076422071 2014-07-24 12:30:00,0.07587888200000001 2014-07-24 12:35:00,0.071253913 2014-07-24 12:40:00,0.077756844 2014-07-24 12:45:00,0.06360170700000001 2014-07-24 12:50:00,0.10324349 2014-07-24 12:55:00,0.059044135 2014-07-24 13:00:00,0.065392214 2014-07-24 13:05:00,0.074960282 2014-07-24 13:10:00,0.085893458 2014-07-24 13:15:00,0.084598799 2014-07-24 13:20:00,0.063798883 2014-07-24 13:25:00,0.068831275 2014-07-24 13:30:00,0.524246935 2014-07-24 13:35:00,0.087101771 2014-07-24 13:40:00,0.065787391 2014-07-24 13:45:00,0.06919821 2014-07-24 13:50:00,0.07065954299999999 2014-07-24 13:55:00,0.06117666 2014-07-24 14:00:00,0.078157515 2014-07-24 14:05:00,0.067612386 2014-07-24 14:10:00,0.089919632 2014-07-24 14:15:00,0.097439289 2014-07-24 14:20:00,0.066014404 2014-07-24 14:25:00,0.08573717300000001 2014-07-24 14:30:00,0.06489059900000001 2014-07-24 14:35:00,0.06850619 2014-07-24 14:40:00,0.06691381 2014-07-24 14:45:00,0.062846575 2014-07-24 14:50:00,0.074442913 2014-07-24 14:55:00,0.085791861 2014-07-24 15:00:00,0.066712354 2014-07-24 15:05:00,0.071112197 2014-07-24 15:10:00,0.060056244 2014-07-24 15:15:00,0.070031968 2014-07-24 15:20:00,0.095845057 2014-07-24 15:25:00,0.06619569900000001 2014-07-24 15:30:00,0.081358772 2014-07-24 15:35:00,0.068662967 2014-07-24 15:40:00,0.108670118 2014-07-24 15:45:00,0.091656786 2014-07-24 15:50:00,0.099634248 2014-07-24 15:55:00,0.11856300000000003 2014-07-24 16:00:00,0.058717608 2014-07-24 16:05:00,0.0 2014-07-24 16:10:00,0.0 2014-07-24 16:15:00,0.0 2014-07-24 18:45:00,0.0 2014-07-24 18:50:00,0.0 2014-07-24 18:55:00,0.060939679 2014-07-24 19:00:00,0.073384077 2014-07-24 19:05:00,0.0 2014-07-24 19:10:00,0.0 2014-07-24 19:15:00,0.0 2014-07-24 19:20:00,0.066576387 2014-07-24 19:25:00,0.06964247 2014-07-24 19:30:00,0.063509709 2014-07-24 19:35:00,0.06448430599999999 2014-07-24 19:40:00,0.061242839 2014-07-24 19:45:00,0.064032585 2014-07-25 04:25:00,0.067142889 2014-07-25 04:35:00,0.068054505 2014-07-25 04:40:00,0.066956947 2014-07-25 04:45:00,0.06847438900000001 2014-07-25 04:50:00,0.092548565 2014-07-25 04:55:00,0.06987181099999999 2014-07-25 05:00:00,0.072714345 2014-07-25 05:05:00,0.07117198 2014-07-25 05:10:00,0.07489518099999999 2014-07-25 05:15:00,0.08371131400000001 2014-07-25 05:20:00,0.07240345299999999 2014-07-25 05:25:00,0.080385259 2014-07-25 05:30:00,0.078046892 2014-07-25 05:35:00,0.078197638 2014-07-25 05:40:00,0.07752671900000001 2014-07-25 05:45:00,0.075176188 2014-07-25 05:50:00,0.077734212 2014-07-25 05:55:00,0.066790509 2014-07-25 06:00:00,0.073448632 2014-07-25 06:05:00,0.078631616 2014-07-25 06:10:00,0.078642825 2014-07-25 06:15:00,0.071975314 2014-07-25 06:20:00,0.068929185 2014-07-25 06:25:00,0.06820836400000001 2014-07-25 06:30:00,0.06526570400000001 2014-07-25 06:35:00,0.065391185 2014-07-25 06:40:00,0.321492891 2014-07-25 06:45:00,0.093553322 2014-07-25 06:50:00,0.08904257199999999 2014-07-25 06:55:00,0.075370373 2014-07-25 07:00:00,0.080041643 2014-07-25 07:05:00,0.073008225 2014-07-25 07:10:00,0.080206812 2014-07-25 07:15:00,0.0 2014-07-25 07:20:00,0.0 2014-07-25 07:25:00,0.0 2014-07-25 07:30:00,0.0 2014-07-25 07:35:00,0.0 2014-07-25 07:40:00,0.0 2014-07-25 07:45:00,0.0 2014-07-25 07:50:00,0.0 2014-07-25 07:55:00,0.078838386 2014-07-25 08:00:00,0.099511194 2014-07-25 08:05:00,0.09507214 2014-07-25 08:10:00,0.07767202 2014-07-25 08:15:00,0.074637525 2014-07-25 08:20:00,0.070592141 2014-07-25 08:25:00,0.06513331900000001 2014-07-25 08:30:00,0.069692447 2014-07-25 08:35:00,0.094646682 2014-07-25 08:40:00,0.0 2014-07-25 08:45:00,0.08524335 2014-07-25 08:50:00,0.077485182 2014-07-25 08:55:00,0.0 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/Twitter_volume_GOOG.csv ================================================ timestamp,value 2015-02-26 21:42:53,35 2015-02-26 21:47:53,41 2015-02-26 21:52:53,32 2015-02-26 21:57:53,36 2015-02-26 22:02:53,32 2015-02-26 22:07:53,25 2015-02-26 22:12:53,33 2015-02-26 22:17:53,20 2015-02-26 22:22:53,38 2015-02-26 22:27:53,28 2015-02-26 22:32:53,28 2015-02-26 22:37:53,27 2015-02-26 22:42:53,30 2015-02-26 22:47:53,31 2015-02-26 22:52:53,38 2015-02-26 22:57:53,35 2015-02-26 23:02:53,33 2015-02-26 23:07:53,24 2015-02-26 23:12:53,28 2015-02-26 23:17:53,20 2015-02-26 23:22:53,35 2015-02-26 23:27:53,29 2015-02-26 23:32:53,24 2015-02-26 23:37:53,24 2015-02-26 23:42:53,33 2015-02-26 23:47:53,36 2015-02-26 23:52:53,18 2015-02-26 23:57:53,28 2015-02-27 00:02:53,20 2015-02-27 00:07:53,59 2015-02-27 00:12:53,41 2015-02-27 00:17:53,97 2015-02-27 00:22:53,61 2015-02-27 00:27:53,105 2015-02-27 00:32:53,52 2015-02-27 00:37:53,30 2015-02-27 00:42:53,23 2015-02-27 00:47:53,26 2015-02-27 00:52:53,43 2015-02-27 00:57:53,24 2015-02-27 01:02:53,41 2015-02-27 01:07:53,24 2015-02-27 01:12:53,33 2015-02-27 01:17:53,20 2015-02-27 01:22:53,21 2015-02-27 01:27:53,34 2015-02-27 01:32:53,39 2015-02-27 01:37:53,41 2015-02-27 01:42:53,48 2015-02-27 01:47:53,28 2015-02-27 01:52:53,32 2015-02-27 01:57:53,26 2015-02-27 02:02:53,18 2015-02-27 02:07:53,17 2015-02-27 02:12:53,25 2015-02-27 02:17:53,25 2015-02-27 02:22:53,32 2015-02-27 02:27:53,94 2015-02-27 02:32:53,39 2015-02-27 02:37:53,23 2015-02-27 02:42:53,73 2015-02-27 02:47:53,31 2015-02-27 02:52:53,30 2015-02-27 02:57:53,35 2015-02-27 03:02:53,23 2015-02-27 03:07:53,49 2015-02-27 03:12:53,187 2015-02-27 03:17:53,203 2015-02-27 03:22:53,175 2015-02-27 03:27:53,112 2015-02-27 03:32:53,22 2015-02-27 03:37:53,24 2015-02-27 03:42:53,12 2015-02-27 03:47:53,26 2015-02-27 03:52:53,16 2015-02-27 03:57:53,14 2015-02-27 04:02:53,19 2015-02-27 04:07:53,21 2015-02-27 04:12:53,18 2015-02-27 04:17:53,12 2015-02-27 04:22:53,25 2015-02-27 04:27:53,17 2015-02-27 04:32:53,21 2015-02-27 04:37:53,18 2015-02-27 04:42:53,22 2015-02-27 04:47:53,23 2015-02-27 04:52:53,26 2015-02-27 04:57:53,33 2015-02-27 05:02:53,26 2015-02-27 05:07:53,16 2015-02-27 05:12:53,15 2015-02-27 05:17:53,7 2015-02-27 05:22:53,14 2015-02-27 05:27:53,11 2015-02-27 05:32:53,31 2015-02-27 05:37:53,15 2015-02-27 05:42:53,15 2015-02-27 05:47:53,15 2015-02-27 05:52:53,25 2015-02-27 05:57:53,34 2015-02-27 06:02:53,20 2015-02-27 06:07:53,15 2015-02-27 06:12:53,16 2015-02-27 06:17:53,18 2015-02-27 06:22:53,6 2015-02-27 06:27:53,10 2015-02-27 06:32:53,20 2015-02-27 06:37:53,14 2015-02-27 06:42:53,11 2015-02-27 06:47:53,27 2015-02-27 06:52:53,7 2015-02-27 06:57:53,21 2015-02-27 07:02:53,16 2015-02-27 07:07:53,20 2015-02-27 07:12:53,11 2015-02-27 07:17:53,11 2015-02-27 07:22:53,21 2015-02-27 07:27:53,16 2015-02-27 07:32:53,16 2015-02-27 07:37:53,16 2015-02-27 07:42:53,18 2015-02-27 07:47:53,10 2015-02-27 07:52:53,13 2015-02-27 07:57:53,21 2015-02-27 08:02:53,18 2015-02-27 08:07:53,11 2015-02-27 08:12:53,17 2015-02-27 08:17:53,19 2015-02-27 08:22:53,8 2015-02-27 08:27:53,14 2015-02-27 08:32:53,18 2015-02-27 08:37:53,13 2015-02-27 08:42:53,16 2015-02-27 08:47:53,18 2015-02-27 08:52:53,8 2015-02-27 08:57:53,17 2015-02-27 09:02:53,28 2015-02-27 09:07:53,14 2015-02-27 09:12:53,14 2015-02-27 09:17:53,16 2015-02-27 09:22:53,9 2015-02-27 09:27:53,20 2015-02-27 09:32:53,17 2015-02-27 09:37:53,13 2015-02-27 09:42:53,22 2015-02-27 09:47:53,19 2015-02-27 09:52:53,19 2015-02-27 09:57:53,30 2015-02-27 10:02:53,12 2015-02-27 10:07:53,13 2015-02-27 10:12:53,13 2015-02-27 10:17:53,12 2015-02-27 10:22:53,13 2015-02-27 10:27:53,61 2015-02-27 10:32:53,12 2015-02-27 10:37:53,19 2015-02-27 10:42:53,34 2015-02-27 10:47:53,25 2015-02-27 10:52:53,19 2015-02-27 10:57:53,14 2015-02-27 11:02:53,17 2015-02-27 11:07:53,33 2015-02-27 11:12:53,19 2015-02-27 11:17:53,11 2015-02-27 11:22:53,9 2015-02-27 11:27:53,14 2015-02-27 11:32:53,22 2015-02-27 11:37:53,9 2015-02-27 11:42:53,21 2015-02-27 11:47:53,24 2015-02-27 11:52:53,10 2015-02-27 11:57:53,15 2015-02-27 12:02:53,19 2015-02-27 12:07:53,30 2015-02-27 12:12:53,36 2015-02-27 12:17:53,21 2015-02-27 12:22:53,24 2015-02-27 12:27:53,24 2015-02-27 12:32:53,21 2015-02-27 12:37:53,14 2015-02-27 12:42:53,22 2015-02-27 12:47:53,24 2015-02-27 12:52:53,20 2015-02-27 12:57:53,20 2015-02-27 13:02:53,20 2015-02-27 13:07:53,14 2015-02-27 13:12:53,19 2015-02-27 13:17:53,11 2015-02-27 13:22:53,12 2015-02-27 13:27:53,25 2015-02-27 13:32:53,15 2015-02-27 13:37:53,17 2015-02-27 13:42:53,10 2015-02-27 13:47:53,20 2015-02-27 13:52:53,14 2015-02-27 13:57:53,20 2015-02-27 14:02:53,14 2015-02-27 14:07:53,21 2015-02-27 14:12:53,15 2015-02-27 14:17:53,31 2015-02-27 14:22:53,29 2015-02-27 14:27:53,34 2015-02-27 14:32:53,30 2015-02-27 14:37:53,26 2015-02-27 14:42:53,21 2015-02-27 14:47:53,30 2015-02-27 14:52:53,24 2015-02-27 14:57:53,47 2015-02-27 15:02:53,21 2015-02-27 15:07:53,30 2015-02-27 15:12:53,27 2015-02-27 15:17:53,18 2015-02-27 15:22:53,40 2015-02-27 15:27:53,18 2015-02-27 15:32:53,20 2015-02-27 15:37:53,23 2015-02-27 15:42:53,14 2015-02-27 15:47:53,20 2015-02-27 15:52:53,22 2015-02-27 15:57:53,28 2015-02-27 16:02:53,18 2015-02-27 16:07:53,19 2015-02-27 16:12:53,27 2015-02-27 16:17:53,30 2015-02-27 16:22:53,23 2015-02-27 16:27:53,17 2015-02-27 16:32:53,24 2015-02-27 16:37:53,18 2015-02-27 16:42:53,27 2015-02-27 16:47:53,42 2015-02-27 16:52:53,22 2015-02-27 16:57:53,100 2015-02-27 17:02:53,67 2015-02-27 17:07:53,43 2015-02-27 17:12:53,43 2015-02-27 17:17:53,24 2015-02-27 17:22:53,22 2015-02-27 17:27:53,43 2015-02-27 17:32:53,39 2015-02-27 17:37:53,37 2015-02-27 17:42:53,41 2015-02-27 17:47:53,25 2015-02-27 17:52:53,24 2015-02-27 17:57:53,63 2015-02-27 18:02:53,80 2015-02-27 18:07:53,48 2015-02-27 18:12:53,58 2015-02-27 18:17:53,52 2015-02-27 18:22:53,44 2015-02-27 18:27:53,68 2015-02-27 18:32:53,58 2015-02-27 18:37:53,112 2015-02-27 18:42:53,77 2015-02-27 18:47:53,46 2015-02-27 18:52:53,202 2015-02-27 18:57:53,105 2015-02-27 19:02:53,60 2015-02-27 19:07:53,61 2015-02-27 19:12:53,55 2015-02-27 19:17:53,34 2015-02-27 19:22:53,35 2015-02-27 19:27:53,61 2015-02-27 19:32:53,47 2015-02-27 19:37:53,30 2015-02-27 19:42:53,37 2015-02-27 19:47:53,41 2015-02-27 19:52:53,54 2015-02-27 19:57:53,35 2015-02-27 20:02:53,39 2015-02-27 20:07:53,54 2015-02-27 20:12:53,116 2015-02-27 20:17:53,77 2015-02-27 20:22:53,75 2015-02-27 20:27:53,90 2015-02-27 20:32:53,70 2015-02-27 20:37:53,41 2015-02-27 20:42:53,24 2015-02-27 20:47:53,40 2015-02-27 20:52:53,26 2015-02-27 20:57:53,36 2015-02-27 21:02:53,36 2015-02-27 21:07:53,31 2015-02-27 21:12:53,34 2015-02-27 21:17:53,40 2015-02-27 21:22:53,30 2015-02-27 21:27:53,70 2015-02-27 21:32:53,40 2015-02-27 21:37:53,36 2015-02-27 21:42:53,31 2015-02-27 21:47:53,42 2015-02-27 21:52:53,31 2015-02-27 21:57:53,32 2015-02-27 22:02:53,24 2015-02-27 22:07:53,32 2015-02-27 22:12:53,32 2015-02-27 22:17:53,33 2015-02-27 22:22:53,27 2015-02-27 22:27:53,31 2015-02-27 22:32:53,25 2015-02-27 22:37:53,24 2015-02-27 22:42:53,21 2015-02-27 22:47:53,25 2015-02-27 22:52:53,13 2015-02-27 22:57:53,27 2015-02-27 23:02:53,37 2015-02-27 23:07:53,20 2015-02-27 23:12:53,17 2015-02-27 23:17:53,18 2015-02-27 23:22:53,20 2015-02-27 23:27:53,24 2015-02-27 23:32:53,27 2015-02-27 23:37:53,58 2015-02-27 23:42:53,80 2015-02-27 23:47:53,51 2015-02-27 23:52:53,42 2015-02-27 23:57:53,39 2015-02-28 00:02:53,28 2015-02-28 00:07:53,27 2015-02-28 00:12:53,22 2015-02-28 00:17:53,21 2015-02-28 00:22:53,20 2015-02-28 00:27:53,35 2015-02-28 00:32:53,25 2015-02-28 00:37:53,16 2015-02-28 00:42:53,15 2015-02-28 00:47:53,22 2015-02-28 00:52:53,104 2015-02-28 00:57:53,18 2015-02-28 01:02:53,13 2015-02-28 01:07:53,16 2015-02-28 01:12:53,14 2015-02-28 01:17:53,20 2015-02-28 01:22:53,17 2015-02-28 01:27:53,25 2015-02-28 01:32:53,16 2015-02-28 01:37:53,13 2015-02-28 01:42:53,12 2015-02-28 01:47:53,12 2015-02-28 01:52:53,21 2015-02-28 01:57:53,13 2015-02-28 02:02:53,24 2015-02-28 02:07:53,20 2015-02-28 02:12:53,12 2015-02-28 02:17:53,12 2015-02-28 02:22:53,13 2015-02-28 02:27:53,15 2015-02-28 02:32:53,12 2015-02-28 02:37:53,16 2015-02-28 02:42:53,13 2015-02-28 02:47:53,15 2015-02-28 02:52:53,10 2015-02-28 02:57:53,16 2015-02-28 03:02:53,14 2015-02-28 03:07:53,12 2015-02-28 03:12:53,7 2015-02-28 03:17:53,15 2015-02-28 03:22:53,13 2015-02-28 03:27:53,11 2015-02-28 03:32:53,8 2015-02-28 03:37:53,6 2015-02-28 03:42:53,15 2015-02-28 03:47:53,9 2015-02-28 03:52:53,7 2015-02-28 03:57:53,11 2015-02-28 04:02:53,9 2015-02-28 04:07:53,12 2015-02-28 04:12:53,6 2015-02-28 04:17:53,8 2015-02-28 04:22:53,4 2015-02-28 04:27:53,10 2015-02-28 04:32:53,14 2015-02-28 04:37:53,12 2015-02-28 04:42:53,25 2015-02-28 04:47:53,14 2015-02-28 04:52:53,8 2015-02-28 04:57:53,14 2015-02-28 05:02:53,7 2015-02-28 05:07:53,22 2015-02-28 05:12:53,23 2015-02-28 05:17:53,9 2015-02-28 05:22:53,27 2015-02-28 05:27:53,11 2015-02-28 05:32:53,8 2015-02-28 05:37:53,19 2015-02-28 05:42:53,20 2015-02-28 05:47:53,7 2015-02-28 05:52:53,16 2015-02-28 05:57:53,9 2015-02-28 06:02:53,15 2015-02-28 06:07:53,10 2015-02-28 06:12:53,20 2015-02-28 06:17:53,9 2015-02-28 06:22:53,11 2015-02-28 06:27:53,8 2015-02-28 06:32:53,17 2015-02-28 06:37:53,32 2015-02-28 06:42:53,4 2015-02-28 06:47:53,7 2015-02-28 06:52:53,9 2015-02-28 06:57:53,12 2015-02-28 07:02:53,5 2015-02-28 07:07:53,5 2015-02-28 07:12:53,7 2015-02-28 07:17:53,10 2015-02-28 07:22:53,10 2015-02-28 07:27:53,12 2015-02-28 07:32:53,11 2015-02-28 07:37:53,6 2015-02-28 07:42:53,6 2015-02-28 07:47:53,10 2015-02-28 07:52:53,15 2015-02-28 07:57:53,13 2015-02-28 08:02:53,8 2015-02-28 08:07:53,10 2015-02-28 08:12:53,12 2015-02-28 08:17:53,6 2015-02-28 08:22:53,10 2015-02-28 08:27:53,8 2015-02-28 08:32:53,9 2015-02-28 08:37:53,12 2015-02-28 08:42:53,5 2015-02-28 08:47:53,6 2015-02-28 08:52:53,7 2015-02-28 08:57:53,14 2015-02-28 09:02:53,4 2015-02-28 09:07:53,15 2015-02-28 09:12:53,21 2015-02-28 09:17:53,17 2015-02-28 09:22:53,6 2015-02-28 09:27:53,11 2015-02-28 09:32:53,5 2015-02-28 09:37:53,3 2015-02-28 09:42:53,7 2015-02-28 09:47:53,7 2015-02-28 09:52:53,3 2015-02-28 09:57:53,15 2015-02-28 10:02:53,8 2015-02-28 10:07:53,8 2015-02-28 10:12:53,7 2015-02-28 10:17:53,4 2015-02-28 10:22:53,22 2015-02-28 10:27:53,8 2015-02-28 10:32:53,10 2015-02-28 10:37:53,14 2015-02-28 10:42:53,17 2015-02-28 10:47:53,13 2015-02-28 10:52:53,9 2015-02-28 10:57:53,13 2015-02-28 11:02:53,33 2015-02-28 11:07:53,25 2015-02-28 11:12:53,15 2015-02-28 11:17:53,8 2015-02-28 11:22:53,9 2015-02-28 11:27:53,11 2015-02-28 11:32:53,8 2015-02-28 11:37:53,4 2015-02-28 11:42:53,6 2015-02-28 11:47:53,7 2015-02-28 11:52:53,6 2015-02-28 11:57:53,22 2015-02-28 12:02:53,17 2015-02-28 12:07:53,13 2015-02-28 12:12:53,13 2015-02-28 12:17:53,19 2015-02-28 12:22:53,31 2015-02-28 12:27:53,23 2015-02-28 12:32:53,13 2015-02-28 12:37:53,21 2015-02-28 12:42:53,12 2015-02-28 12:47:53,11 2015-02-28 12:52:53,15 2015-02-28 12:57:53,13 2015-02-28 13:02:53,10 2015-02-28 13:07:53,12 2015-02-28 13:12:53,16 2015-02-28 13:17:53,14 2015-02-28 13:22:53,18 2015-02-28 13:27:53,17 2015-02-28 13:32:53,8 2015-02-28 13:37:53,8 2015-02-28 13:42:53,13 2015-02-28 13:47:53,9 2015-02-28 13:52:53,12 2015-02-28 13:57:53,25 2015-02-28 14:02:53,17 2015-02-28 14:07:53,15 2015-02-28 14:12:53,24 2015-02-28 14:17:53,17 2015-02-28 14:22:53,17 2015-02-28 14:27:53,23 2015-02-28 14:32:53,17 2015-02-28 14:37:53,15 2015-02-28 14:42:53,18 2015-02-28 14:47:53,14 2015-02-28 14:52:53,22 2015-02-28 14:57:53,22 2015-02-28 15:02:53,26 2015-02-28 15:07:53,18 2015-02-28 15:12:53,36 2015-02-28 15:17:53,15 2015-02-28 15:22:53,19 2015-02-28 15:27:53,24 2015-02-28 15:32:53,12 2015-02-28 15:37:53,13 2015-02-28 15:42:53,17 2015-02-28 15:47:53,14 2015-02-28 15:52:53,20 2015-02-28 15:57:53,16 2015-02-28 16:02:53,20 2015-02-28 16:07:53,7 2015-02-28 16:12:53,32 2015-02-28 16:17:53,16 2015-02-28 16:22:53,15 2015-02-28 16:27:53,28 2015-02-28 16:32:53,19 2015-02-28 16:37:53,10 2015-02-28 16:42:53,21 2015-02-28 16:47:53,21 2015-02-28 16:52:53,20 2015-02-28 16:57:53,25 2015-02-28 17:02:53,16 2015-02-28 17:07:53,18 2015-02-28 17:12:53,10 2015-02-28 17:17:53,11 2015-02-28 17:22:53,46 2015-02-28 17:27:53,8 2015-02-28 17:32:53,31 2015-02-28 17:37:53,22 2015-02-28 17:42:53,11 2015-02-28 17:47:53,14 2015-02-28 17:52:53,8 2015-02-28 17:57:53,23 2015-02-28 18:02:53,19 2015-02-28 18:07:53,20 2015-02-28 18:12:53,17 2015-02-28 18:17:53,19 2015-02-28 18:22:53,11 2015-02-28 18:27:53,16 2015-02-28 18:32:53,16 2015-02-28 18:37:53,9 2015-02-28 18:42:53,14 2015-02-28 18:47:53,16 2015-02-28 18:52:53,6 2015-02-28 18:57:53,32 2015-02-28 19:02:53,30 2015-02-28 19:07:53,39 2015-02-28 19:12:53,30 2015-02-28 19:17:53,27 2015-02-28 19:22:53,16 2015-02-28 19:27:53,17 2015-02-28 19:32:53,20 2015-02-28 19:37:53,27 2015-02-28 19:42:53,20 2015-02-28 19:47:53,21 2015-02-28 19:52:53,22 2015-02-28 19:57:53,25 2015-02-28 20:02:53,19 2015-02-28 20:07:53,21 2015-02-28 20:12:53,20 2015-02-28 20:17:53,13 2015-02-28 20:22:53,14 2015-02-28 20:27:53,13 2015-02-28 20:32:53,19 2015-02-28 20:37:53,16 2015-02-28 20:42:53,13 2015-02-28 20:47:53,14 2015-02-28 20:52:53,23 2015-02-28 20:57:53,21 2015-02-28 21:02:53,11 2015-02-28 21:07:53,25 2015-02-28 21:12:53,8 2015-02-28 21:17:53,11 2015-02-28 21:22:53,13 2015-02-28 21:27:53,21 2015-02-28 21:32:53,10 2015-02-28 21:37:53,12 2015-02-28 21:42:53,14 2015-02-28 21:47:53,17 2015-02-28 21:52:53,19 2015-02-28 21:57:53,23 2015-02-28 22:02:53,13 2015-02-28 22:07:53,14 2015-02-28 22:12:53,19 2015-02-28 22:17:53,10 2015-02-28 22:22:53,12 2015-02-28 22:27:53,7 2015-02-28 22:32:53,11 2015-02-28 22:37:53,10 2015-02-28 22:42:53,9 2015-02-28 22:47:53,14 2015-02-28 22:52:53,13 2015-02-28 22:57:53,17 2015-02-28 23:02:53,24 2015-02-28 23:07:53,5 2015-02-28 23:12:53,9 2015-02-28 23:17:53,20 2015-02-28 23:22:53,11 2015-02-28 23:27:53,16 2015-02-28 23:32:53,7 2015-02-28 23:37:53,18 2015-02-28 23:42:53,7 2015-02-28 23:47:53,3 2015-02-28 23:52:53,12 2015-02-28 23:57:53,10 2015-03-01 00:02:53,13 2015-03-01 00:07:53,16 2015-03-01 00:12:53,9 2015-03-01 00:17:53,5 2015-03-01 00:22:53,10 2015-03-01 00:27:53,7 2015-03-01 00:32:53,5 2015-03-01 00:37:53,9 2015-03-01 00:42:53,13 2015-03-01 00:47:53,14 2015-03-01 00:52:53,9 2015-03-01 00:57:53,8 2015-03-01 01:02:53,12 2015-03-01 01:07:53,4 2015-03-01 01:12:53,11 2015-03-01 01:17:53,11 2015-03-01 01:22:53,11 2015-03-01 01:27:53,18 2015-03-01 01:32:53,6 2015-03-01 01:37:53,5 2015-03-01 01:42:53,8 2015-03-01 01:47:53,9 2015-03-01 01:52:53,5 2015-03-01 01:57:53,15 2015-03-01 02:02:53,13 2015-03-01 02:07:53,6 2015-03-01 02:12:53,14 2015-03-01 02:17:53,7 2015-03-01 02:22:53,1 2015-03-01 02:27:53,8 2015-03-01 02:32:53,9 2015-03-01 02:37:53,5 2015-03-01 02:42:53,6 2015-03-01 02:47:53,10 2015-03-01 02:52:53,6 2015-03-01 02:57:53,6 2015-03-01 03:02:53,10 2015-03-01 03:07:53,16 2015-03-01 03:12:53,8 2015-03-01 03:17:53,9 2015-03-01 03:22:53,5 2015-03-01 03:27:53,16 2015-03-01 03:32:53,6 2015-03-01 03:37:53,10 2015-03-01 03:42:53,11 2015-03-01 03:47:53,6 2015-03-01 03:52:53,16 2015-03-01 03:57:53,14 2015-03-01 04:02:53,7 2015-03-01 04:07:53,7 2015-03-01 04:12:53,7 2015-03-01 04:17:53,11 2015-03-01 04:22:53,4 2015-03-01 04:27:53,7 2015-03-01 04:32:53,9 2015-03-01 04:37:53,5 2015-03-01 04:42:53,12 2015-03-01 04:47:53,6 2015-03-01 04:52:53,11 2015-03-01 04:57:53,12 2015-03-01 05:02:53,6 2015-03-01 05:07:53,4 2015-03-01 05:12:53,5 2015-03-01 05:17:53,4 2015-03-01 05:22:53,7 2015-03-01 05:27:53,22 2015-03-01 05:32:53,4 2015-03-01 05:37:53,6 2015-03-01 05:42:53,6 2015-03-01 05:47:53,9 2015-03-01 05:52:53,3 2015-03-01 05:57:53,3 2015-03-01 06:02:53,7 2015-03-01 06:07:53,12 2015-03-01 06:12:53,6 2015-03-01 06:17:53,5 2015-03-01 06:22:53,2 2015-03-01 06:27:53,13 2015-03-01 06:32:53,7 2015-03-01 06:37:53,14 2015-03-01 06:42:53,15 2015-03-01 06:47:53,4 2015-03-01 06:52:53,10 2015-03-01 06:57:53,8 2015-03-01 07:02:53,8 2015-03-01 07:07:53,4 2015-03-01 07:12:53,16 2015-03-01 07:17:53,5 2015-03-01 07:22:53,5 2015-03-01 07:27:53,5 2015-03-01 07:32:53,9 2015-03-01 07:37:53,13 2015-03-01 07:42:53,0 2015-03-01 07:47:53,2 2015-03-01 07:52:53,5 2015-03-01 07:57:53,7 2015-03-01 08:02:53,11 2015-03-01 08:07:53,9 2015-03-01 08:12:53,6 2015-03-01 08:17:53,15 2015-03-01 08:22:53,11 2015-03-01 08:27:53,3 2015-03-01 08:32:53,8 2015-03-01 08:37:53,7 2015-03-01 08:42:53,3 2015-03-01 08:47:53,5 2015-03-01 08:52:53,7 2015-03-01 08:57:53,14 2015-03-01 09:02:53,5 2015-03-01 09:07:53,5 2015-03-01 09:12:53,9 2015-03-01 09:17:53,3 2015-03-01 09:22:53,6 2015-03-01 09:27:53,6 2015-03-01 09:32:53,8 2015-03-01 09:37:53,10 2015-03-01 09:42:53,12 2015-03-01 09:47:53,9 2015-03-01 09:52:53,16 2015-03-01 09:57:53,17 2015-03-01 10:02:53,7 2015-03-01 10:07:53,11 2015-03-01 10:12:53,14 2015-03-01 10:17:53,11 2015-03-01 10:22:53,5 2015-03-01 10:27:53,12 2015-03-01 10:32:53,10 2015-03-01 10:37:53,14 2015-03-01 10:42:53,13 2015-03-01 10:47:53,22 2015-03-01 10:52:53,16 2015-03-01 10:57:53,13 2015-03-01 11:02:53,4 2015-03-01 11:07:53,13 2015-03-01 11:12:53,12 2015-03-01 11:17:53,6 2015-03-01 11:22:53,16 2015-03-01 11:27:53,10 2015-03-01 11:32:53,4 2015-03-01 11:37:53,11 2015-03-01 11:42:53,7 2015-03-01 11:47:53,7 2015-03-01 11:52:53,81 2015-03-01 11:57:53,41 2015-03-01 12:02:53,27 2015-03-01 12:07:53,12 2015-03-01 12:12:53,15 2015-03-01 12:17:53,7 2015-03-01 12:22:53,9 2015-03-01 12:27:53,9 2015-03-01 12:32:53,21 2015-03-01 12:37:53,4 2015-03-01 12:42:53,11 2015-03-01 12:47:53,14 2015-03-01 12:52:53,18 2015-03-01 12:57:53,12 2015-03-01 13:02:53,8 2015-03-01 13:07:53,6 2015-03-01 13:12:53,7 2015-03-01 13:17:53,13 2015-03-01 13:22:53,7 2015-03-01 13:27:53,8 2015-03-01 13:32:53,8 2015-03-01 13:37:53,12 2015-03-01 13:42:53,18 2015-03-01 13:47:53,24 2015-03-01 13:52:53,12 2015-03-01 13:57:53,12 2015-03-01 14:02:53,6 2015-03-01 14:07:53,17 2015-03-01 14:12:53,19 2015-03-01 14:17:53,14 2015-03-01 14:22:53,17 2015-03-01 14:27:53,12 2015-03-01 14:32:53,17 2015-03-01 14:37:53,12 2015-03-01 14:42:53,13 2015-03-01 14:47:53,15 2015-03-01 14:52:53,11 2015-03-01 14:57:53,19 2015-03-01 15:02:53,10 2015-03-01 15:07:53,10 2015-03-01 15:12:53,12 2015-03-01 15:17:53,10 2015-03-01 15:22:53,20 2015-03-01 15:27:53,13 2015-03-01 15:32:53,11 2015-03-01 15:37:53,14 2015-03-01 15:42:53,15 2015-03-01 15:47:53,9 2015-03-01 15:52:53,17 2015-03-01 15:57:53,14 2015-03-01 16:02:53,16 2015-03-01 16:07:53,23 2015-03-01 16:12:53,11 2015-03-01 16:17:53,8 2015-03-01 16:22:53,20 2015-03-01 16:27:53,12 2015-03-01 16:32:53,13 2015-03-01 16:37:53,26 2015-03-01 16:42:53,18 2015-03-01 16:47:53,16 2015-03-01 16:52:53,10 2015-03-01 16:57:53,8 2015-03-01 17:02:53,11 2015-03-01 17:07:53,16 2015-03-01 17:12:53,18 2015-03-01 17:17:53,12 2015-03-01 17:22:53,20 2015-03-01 17:27:53,17 2015-03-01 17:32:53,17 2015-03-01 17:37:53,21 2015-03-01 17:42:53,14 2015-03-01 17:47:53,20 2015-03-01 17:52:53,12 2015-03-01 17:57:53,26 2015-03-01 18:02:53,8 2015-03-01 18:07:53,16 2015-03-01 18:12:53,8 2015-03-01 18:17:53,11 2015-03-01 18:22:53,13 2015-03-01 18:27:53,21 2015-03-01 18:32:53,14 2015-03-01 18:37:53,11 2015-03-01 18:42:53,11 2015-03-01 18:47:53,17 2015-03-01 18:52:53,10 2015-03-01 18:57:53,11 2015-03-01 19:02:53,18 2015-03-01 19:07:53,17 2015-03-01 19:12:53,18 2015-03-01 19:17:53,14 2015-03-01 19:22:53,9 2015-03-01 19:27:53,10 2015-03-01 19:32:53,7 2015-03-01 19:37:53,6 2015-03-01 19:42:53,5 2015-03-01 19:47:53,11 2015-03-01 19:52:53,5 2015-03-01 19:57:53,14 2015-03-01 20:02:53,13 2015-03-01 20:07:53,13 2015-03-01 20:12:53,15 2015-03-01 20:17:53,12 2015-03-01 20:22:53,8 2015-03-01 20:27:53,8 2015-03-01 20:32:53,16 2015-03-01 20:37:53,15 2015-03-01 20:42:53,10 2015-03-01 20:47:53,7 2015-03-01 20:52:53,5 2015-03-01 20:57:53,16 2015-03-01 21:02:53,17 2015-03-01 21:07:53,10 2015-03-01 21:12:53,26 2015-03-01 21:17:53,6 2015-03-01 21:22:53,11 2015-03-01 21:27:53,20 2015-03-01 21:32:53,24 2015-03-01 21:37:53,7 2015-03-01 21:42:53,13 2015-03-01 21:47:53,7 2015-03-01 21:52:53,10 2015-03-01 21:57:53,8 2015-03-01 22:02:53,8 2015-03-01 22:07:53,9 2015-03-01 22:12:53,8 2015-03-01 22:17:53,9 2015-03-01 22:22:53,15 2015-03-01 22:27:53,8 2015-03-01 22:32:53,10 2015-03-01 22:37:53,15 2015-03-01 22:42:53,7 2015-03-01 22:47:53,12 2015-03-01 22:52:53,5 2015-03-01 22:57:53,11 2015-03-01 23:02:53,7 2015-03-01 23:07:53,8 2015-03-01 23:12:53,11 2015-03-01 23:17:53,14 2015-03-01 23:22:53,14 2015-03-01 23:27:53,20 2015-03-01 23:32:53,16 2015-03-01 23:37:53,16 2015-03-01 23:42:53,10 2015-03-01 23:47:53,9 2015-03-01 23:52:53,9 2015-03-01 23:57:53,7 2015-03-02 00:02:53,14 2015-03-02 00:07:53,14 2015-03-02 00:12:53,9 2015-03-02 00:17:53,13 2015-03-02 00:22:53,7 2015-03-02 00:27:53,7 2015-03-02 00:32:53,5 2015-03-02 00:37:53,13 2015-03-02 00:42:53,11 2015-03-02 00:47:53,7 2015-03-02 00:52:53,9 2015-03-02 00:57:53,9 2015-03-02 01:02:53,15 2015-03-02 01:07:53,6 2015-03-02 01:12:53,9 2015-03-02 01:17:53,5 2015-03-02 01:22:53,12 2015-03-02 01:27:53,10 2015-03-02 01:32:53,10 2015-03-02 01:37:53,10 2015-03-02 01:42:53,15 2015-03-02 01:47:53,12 2015-03-02 01:52:53,17 2015-03-02 01:57:53,14 2015-03-02 02:02:53,9 2015-03-02 02:07:53,9 2015-03-02 02:12:53,7 2015-03-02 02:17:53,11 2015-03-02 02:22:53,11 2015-03-02 02:27:53,7 2015-03-02 02:32:53,7 2015-03-02 02:37:53,12 2015-03-02 02:42:53,6 2015-03-02 02:47:53,12 2015-03-02 02:52:53,6 2015-03-02 02:57:53,12 2015-03-02 03:02:53,10 2015-03-02 03:07:53,6 2015-03-02 03:12:53,12 2015-03-02 03:17:53,11 2015-03-02 03:22:53,8 2015-03-02 03:27:53,8 2015-03-02 03:32:53,10 2015-03-02 03:37:53,11 2015-03-02 03:42:53,5 2015-03-02 03:47:53,3 2015-03-02 03:52:53,8 2015-03-02 03:57:53,7 2015-03-02 04:02:53,13 2015-03-02 04:07:53,5 2015-03-02 04:12:53,10 2015-03-02 04:17:53,6 2015-03-02 04:22:53,32 2015-03-02 04:27:53,17 2015-03-02 04:32:53,19 2015-03-02 04:37:53,16 2015-03-02 04:42:53,14 2015-03-02 04:47:53,9 2015-03-02 04:52:53,5 2015-03-02 04:57:53,7 2015-03-02 05:02:53,9 2015-03-02 05:07:53,9 2015-03-02 05:12:53,17 2015-03-02 05:17:53,12 2015-03-02 05:22:53,8 2015-03-02 05:27:53,15 2015-03-02 05:32:53,15 2015-03-02 05:37:53,1 2015-03-02 05:42:53,11 2015-03-02 05:47:53,5 2015-03-02 05:52:53,8 2015-03-02 05:57:53,13 2015-03-02 06:02:53,7 2015-03-02 06:07:53,8 2015-03-02 06:12:53,1 2015-03-02 06:17:53,8 2015-03-02 06:22:53,12 2015-03-02 06:27:53,8 2015-03-02 06:32:53,5 2015-03-02 06:37:53,15 2015-03-02 06:42:53,6 2015-03-02 06:47:53,9 2015-03-02 06:52:53,10 2015-03-02 06:57:53,20 2015-03-02 07:02:53,9 2015-03-02 07:07:53,7 2015-03-02 07:12:53,19 2015-03-02 07:17:53,17 2015-03-02 07:22:53,7 2015-03-02 07:27:53,24 2015-03-02 07:32:53,5 2015-03-02 07:37:53,10 2015-03-02 07:42:53,11 2015-03-02 07:47:53,9 2015-03-02 07:52:53,14 2015-03-02 07:57:53,6 2015-03-02 08:02:53,10 2015-03-02 08:07:53,20 2015-03-02 08:12:53,8 2015-03-02 08:17:53,4 2015-03-02 08:22:53,7 2015-03-02 08:27:53,10 2015-03-02 08:32:53,6 2015-03-02 08:37:53,7 2015-03-02 08:42:53,18 2015-03-02 08:47:53,21 2015-03-02 08:52:53,21 2015-03-02 08:57:53,70 2015-03-02 09:02:53,6 2015-03-02 09:07:53,9 2015-03-02 09:12:53,9 2015-03-02 09:17:53,21 2015-03-02 09:22:53,13 2015-03-02 09:27:53,11 2015-03-02 09:32:53,13 2015-03-02 09:37:53,11 2015-03-02 09:42:53,5 2015-03-02 09:47:53,6 2015-03-02 09:52:53,10 2015-03-02 09:57:53,14 2015-03-02 10:02:53,13 2015-03-02 10:07:53,21 2015-03-02 10:12:53,10 2015-03-02 10:17:53,13 2015-03-02 10:22:53,11 2015-03-02 10:27:53,6 2015-03-02 10:32:53,14 2015-03-02 10:37:53,10 2015-03-02 10:42:53,15 2015-03-02 10:47:53,9 2015-03-02 10:52:53,11 2015-03-02 10:57:53,22 2015-03-02 11:02:53,21 2015-03-02 11:07:53,10 2015-03-02 11:12:53,11 2015-03-02 11:17:53,22 2015-03-02 11:22:53,9 2015-03-02 11:27:53,13 2015-03-02 11:32:53,11 2015-03-02 11:37:53,12 2015-03-02 11:42:53,8 2015-03-02 11:47:53,12 2015-03-02 11:52:53,17 2015-03-02 11:57:53,22 2015-03-02 12:02:53,24 2015-03-02 12:07:53,14 2015-03-02 12:12:53,30 2015-03-02 12:17:53,19 2015-03-02 12:22:53,13 2015-03-02 12:27:53,15 2015-03-02 12:32:53,18 2015-03-02 12:37:53,31 2015-03-02 12:42:53,25 2015-03-02 12:47:53,29 2015-03-02 12:52:53,29 2015-03-02 12:57:53,35 2015-03-02 13:02:53,40 2015-03-02 13:07:53,28 2015-03-02 13:12:53,22 2015-03-02 13:17:53,19 2015-03-02 13:22:53,23 2015-03-02 13:27:53,16 2015-03-02 13:32:53,17 2015-03-02 13:37:53,18 2015-03-02 13:42:53,40 2015-03-02 13:47:53,28 2015-03-02 13:52:53,29 2015-03-02 13:57:53,35 2015-03-02 14:02:53,27 2015-03-02 14:07:53,15 2015-03-02 14:12:53,29 2015-03-02 14:17:53,23 2015-03-02 14:22:53,19 2015-03-02 14:27:53,13 2015-03-02 14:32:53,17 2015-03-02 14:37:53,19 2015-03-02 14:42:53,23 2015-03-02 14:47:53,20 2015-03-02 14:52:53,25 2015-03-02 14:57:53,35 2015-03-02 15:02:53,46 2015-03-02 15:07:53,66 2015-03-02 15:12:53,72 2015-03-02 15:17:53,52 2015-03-02 15:22:53,40 2015-03-02 15:27:53,42 2015-03-02 15:32:53,39 2015-03-02 15:37:53,32 2015-03-02 15:42:53,28 2015-03-02 15:47:53,36 2015-03-02 15:52:53,37 2015-03-02 15:57:53,30 2015-03-02 16:02:53,19 2015-03-02 16:07:53,31 2015-03-02 16:12:53,28 2015-03-02 16:17:53,59 2015-03-02 16:22:53,50 2015-03-02 16:27:53,35 2015-03-02 16:32:53,33 2015-03-02 16:37:53,31 2015-03-02 16:42:53,47 2015-03-02 16:47:53,36 2015-03-02 16:52:53,31 2015-03-02 16:57:53,39 2015-03-02 17:02:53,48 2015-03-02 17:07:53,42 2015-03-02 17:12:53,33 2015-03-02 17:17:53,25 2015-03-02 17:22:53,28 2015-03-02 17:27:53,24 2015-03-02 17:32:53,54 2015-03-02 17:37:53,32 2015-03-02 17:42:53,25 2015-03-02 17:47:53,17 2015-03-02 17:52:53,21 2015-03-02 17:57:53,46 2015-03-02 18:02:53,42 2015-03-02 18:07:53,21 2015-03-02 18:12:53,28 2015-03-02 18:17:53,53 2015-03-02 18:22:53,26 2015-03-02 18:27:53,31 2015-03-02 18:32:53,28 2015-03-02 18:37:53,39 2015-03-02 18:42:53,25 2015-03-02 18:47:53,20 2015-03-02 18:52:53,40 2015-03-02 18:57:53,37 2015-03-02 19:02:53,61 2015-03-02 19:07:53,53 2015-03-02 19:12:53,33 2015-03-02 19:17:53,40 2015-03-02 19:22:53,61 2015-03-02 19:27:53,49 2015-03-02 19:32:53,51 2015-03-02 19:37:53,43 2015-03-02 19:42:53,41 2015-03-02 19:47:53,27 2015-03-02 19:52:53,47 2015-03-02 19:57:53,47 2015-03-02 20:02:53,72 2015-03-02 20:07:53,40 2015-03-02 20:12:53,37 2015-03-02 20:17:53,33 2015-03-02 20:22:53,51 2015-03-02 20:27:53,49 2015-03-02 20:32:53,32 2015-03-02 20:37:53,42 2015-03-02 20:42:53,30 2015-03-02 20:47:53,33 2015-03-02 20:52:53,29 2015-03-02 20:57:53,35 2015-03-02 21:02:53,30 2015-03-02 21:07:53,20 2015-03-02 21:12:53,32 2015-03-02 21:17:53,25 2015-03-02 21:22:53,52 2015-03-02 21:27:53,55 2015-03-02 21:32:53,32 2015-03-02 21:37:53,17 2015-03-02 21:42:53,25 2015-03-02 21:47:53,33 2015-03-02 21:52:53,22 2015-03-02 21:57:53,19 2015-03-02 22:02:53,28 2015-03-02 22:07:53,30 2015-03-02 22:12:53,26 2015-03-02 22:17:53,20 2015-03-02 22:22:53,21 2015-03-02 22:27:53,20 2015-03-02 22:32:53,15 2015-03-02 22:37:53,26 2015-03-02 22:42:53,38 2015-03-02 22:47:53,26 2015-03-02 22:52:53,22 2015-03-02 22:57:53,26 2015-03-02 23:02:53,18 2015-03-02 23:07:53,16 2015-03-02 23:12:53,10 2015-03-02 23:17:53,33 2015-03-02 23:22:53,21 2015-03-02 23:27:53,20 2015-03-02 23:32:53,11 2015-03-02 23:37:53,15 2015-03-02 23:42:53,11 2015-03-02 23:47:53,21 2015-03-02 23:52:53,22 2015-03-02 23:57:53,24 2015-03-03 00:02:53,27 2015-03-03 00:07:53,18 2015-03-03 00:12:53,14 2015-03-03 00:17:53,47 2015-03-03 00:22:53,21 2015-03-03 00:27:53,30 2015-03-03 00:32:53,22 2015-03-03 00:37:53,17 2015-03-03 00:42:53,18 2015-03-03 00:47:53,28 2015-03-03 00:52:53,26 2015-03-03 00:57:53,22 2015-03-03 01:02:53,19 2015-03-03 01:07:53,47 2015-03-03 01:12:53,21 2015-03-03 01:17:53,18 2015-03-03 01:22:53,18 2015-03-03 01:27:53,26 2015-03-03 01:32:53,14 2015-03-03 01:37:53,12 2015-03-03 01:42:53,13 2015-03-03 01:47:53,16 2015-03-03 01:52:53,33 2015-03-03 01:57:53,21 2015-03-03 02:02:53,12 2015-03-03 02:07:53,15 2015-03-03 02:12:53,10 2015-03-03 02:17:53,22 2015-03-03 02:22:53,10 2015-03-03 02:27:53,24 2015-03-03 02:32:53,33 2015-03-03 02:37:53,25 2015-03-03 02:42:53,16 2015-03-03 02:47:53,23 2015-03-03 02:52:53,22 2015-03-03 02:57:53,14 2015-03-03 03:02:53,14 2015-03-03 03:07:53,15 2015-03-03 03:12:53,23 2015-03-03 03:17:53,13 2015-03-03 03:22:53,14 2015-03-03 03:27:53,20 2015-03-03 03:32:53,15 2015-03-03 03:37:53,20 2015-03-03 03:42:53,9 2015-03-03 03:47:53,15 2015-03-03 03:52:53,16 2015-03-03 03:57:53,22 2015-03-03 04:02:53,16 2015-03-03 04:07:53,21 2015-03-03 04:12:53,23 2015-03-03 04:17:53,18 2015-03-03 04:22:53,14 2015-03-03 04:27:53,9 2015-03-03 04:32:53,9 2015-03-03 04:37:53,8 2015-03-03 04:42:53,6 2015-03-03 04:47:53,12 2015-03-03 04:52:53,16 2015-03-03 04:57:53,14 2015-03-03 05:02:53,12 2015-03-03 05:07:53,8 2015-03-03 05:12:53,6 2015-03-03 05:17:53,5 2015-03-03 05:22:53,8 2015-03-03 05:27:53,15 2015-03-03 05:32:53,12 2015-03-03 05:37:53,15 2015-03-03 05:42:53,8 2015-03-03 05:47:53,11 2015-03-03 05:52:53,8 2015-03-03 05:57:53,14 2015-03-03 06:02:53,8 2015-03-03 06:07:53,13 2015-03-03 06:12:53,7 2015-03-03 06:17:53,13 2015-03-03 06:22:53,16 2015-03-03 06:27:53,10 2015-03-03 06:32:53,8 2015-03-03 06:37:53,6 2015-03-03 06:42:53,18 2015-03-03 06:47:53,13 2015-03-03 06:52:53,9 2015-03-03 06:57:53,21 2015-03-03 07:02:53,9 2015-03-03 07:07:53,5 2015-03-03 07:12:53,18 2015-03-03 07:17:53,12 2015-03-03 07:22:53,5 2015-03-03 07:27:53,12 2015-03-03 07:32:53,15 2015-03-03 07:37:53,6 2015-03-03 07:42:53,20 2015-03-03 07:47:53,16 2015-03-03 07:52:53,14 2015-03-03 07:57:53,8 2015-03-03 08:02:53,9 2015-03-03 08:07:53,13 2015-03-03 08:12:53,7 2015-03-03 08:17:53,11 2015-03-03 08:22:53,7 2015-03-03 08:27:53,12 2015-03-03 08:32:53,18 2015-03-03 08:37:53,15 2015-03-03 08:42:53,17 2015-03-03 08:47:53,15 2015-03-03 08:52:53,15 2015-03-03 08:57:53,19 2015-03-03 09:02:53,14 2015-03-03 09:07:53,13 2015-03-03 09:12:53,10 2015-03-03 09:17:53,11 2015-03-03 09:22:53,12 2015-03-03 09:27:53,21 2015-03-03 09:32:53,9 2015-03-03 09:37:53,8 2015-03-03 09:42:53,10 2015-03-03 09:47:53,15 2015-03-03 09:52:53,14 2015-03-03 09:57:53,23 2015-03-03 10:02:53,14 2015-03-03 10:07:53,7 2015-03-03 10:12:53,10 2015-03-03 10:17:53,15 2015-03-03 10:22:53,9 2015-03-03 10:27:53,20 2015-03-03 10:32:53,14 2015-03-03 10:37:53,14 2015-03-03 10:42:53,15 2015-03-03 10:47:53,6 2015-03-03 10:52:53,7 2015-03-03 10:57:53,29 2015-03-03 11:02:53,11 2015-03-03 11:07:53,19 2015-03-03 11:12:53,18 2015-03-03 11:17:53,12 2015-03-03 11:22:53,11 2015-03-03 11:27:53,13 2015-03-03 11:32:53,12 2015-03-03 11:37:53,13 2015-03-03 11:42:53,25 2015-03-03 11:47:53,18 2015-03-03 11:52:53,22 2015-03-03 11:57:53,18 2015-03-03 12:02:53,14 2015-03-03 12:07:53,19 2015-03-03 12:12:53,17 2015-03-03 12:17:53,11 2015-03-03 12:22:53,24 2015-03-03 12:27:53,20 2015-03-03 12:32:53,17 2015-03-03 12:37:53,18 2015-03-03 12:42:53,18 2015-03-03 12:47:53,24 2015-03-03 12:52:53,22 2015-03-03 12:57:53,38 2015-03-03 13:02:53,14 2015-03-03 13:07:53,20 2015-03-03 13:12:53,12 2015-03-03 13:17:53,22 2015-03-03 13:22:53,26 2015-03-03 13:27:53,30 2015-03-03 13:32:53,18 2015-03-03 13:37:53,30 2015-03-03 13:42:53,23 2015-03-03 13:47:53,29 2015-03-03 13:52:53,20 2015-03-03 13:57:53,25 2015-03-03 14:02:53,29 2015-03-03 14:07:53,42 2015-03-03 14:12:53,36 2015-03-03 14:17:53,43 2015-03-03 14:22:53,28 2015-03-03 14:27:53,29 2015-03-03 14:32:53,28 2015-03-03 14:37:53,38 2015-03-03 14:42:53,34 2015-03-03 14:47:53,30 2015-03-03 14:52:53,29 2015-03-03 14:57:53,25 2015-03-03 15:02:53,20 2015-03-03 15:07:53,30 2015-03-03 15:12:53,30 2015-03-03 15:17:53,18 2015-03-03 15:22:53,20 2015-03-03 15:27:53,25 2015-03-03 15:32:53,28 2015-03-03 15:37:53,19 2015-03-03 15:42:53,23 2015-03-03 15:47:53,20 2015-03-03 15:52:53,11 2015-03-03 15:57:53,25 2015-03-03 16:02:53,42 2015-03-03 16:07:53,28 2015-03-03 16:12:53,26 2015-03-03 16:17:53,23 2015-03-03 16:22:53,23 2015-03-03 16:27:53,34 2015-03-03 16:32:53,26 2015-03-03 16:37:53,25 2015-03-03 16:42:53,20 2015-03-03 16:47:53,21 2015-03-03 16:52:53,34 2015-03-03 16:57:53,31 2015-03-03 17:02:53,59 2015-03-03 17:07:53,35 2015-03-03 17:12:53,45 2015-03-03 17:17:53,34 2015-03-03 17:22:53,28 2015-03-03 17:27:53,26 2015-03-03 17:32:53,24 2015-03-03 17:37:53,21 2015-03-03 17:42:53,26 2015-03-03 17:47:53,17 2015-03-03 17:52:53,19 2015-03-03 17:57:53,27 2015-03-03 18:02:53,23 2015-03-03 18:07:53,23 2015-03-03 18:12:53,35 2015-03-03 18:17:53,18 2015-03-03 18:22:53,33 2015-03-03 18:27:53,25 2015-03-03 18:32:53,26 2015-03-03 18:37:53,32 2015-03-03 18:42:53,39 2015-03-03 18:47:53,22 2015-03-03 18:52:53,28 2015-03-03 18:57:53,71 2015-03-03 19:02:53,41 2015-03-03 19:07:53,37 2015-03-03 19:12:53,27 2015-03-03 19:17:53,30 2015-03-03 19:22:53,21 2015-03-03 19:27:53,25 2015-03-03 19:32:53,30 2015-03-03 19:37:53,32 2015-03-03 19:42:53,31 2015-03-03 19:47:53,30 2015-03-03 19:52:53,26 2015-03-03 19:57:53,35 2015-03-03 20:02:53,27 2015-03-03 20:07:53,21 2015-03-03 20:12:53,13 2015-03-03 20:17:53,16 2015-03-03 20:22:53,23 2015-03-03 20:27:53,16 2015-03-03 20:32:53,15 2015-03-03 20:37:53,24 2015-03-03 20:42:53,43 2015-03-03 20:47:53,42 2015-03-03 20:52:53,38 2015-03-03 20:57:53,55 2015-03-03 21:02:53,44 2015-03-03 21:07:53,21 2015-03-03 21:12:53,23 2015-03-03 21:17:53,19 2015-03-03 21:22:53,41 2015-03-03 21:27:53,53 2015-03-03 21:32:53,46 2015-03-03 21:37:53,31 2015-03-03 21:42:53,38 2015-03-03 21:47:53,22 2015-03-03 21:52:53,22 2015-03-03 21:57:53,22 2015-03-03 22:02:53,23 2015-03-03 22:07:53,26 2015-03-03 22:12:53,23 2015-03-03 22:17:53,30 2015-03-03 22:22:53,22 2015-03-03 22:27:53,19 2015-03-03 22:32:53,26 2015-03-03 22:37:53,17 2015-03-03 22:42:53,34 2015-03-03 22:47:53,18 2015-03-03 22:52:53,27 2015-03-03 22:57:53,35 2015-03-03 23:02:53,17 2015-03-03 23:07:53,13 2015-03-03 23:12:53,19 2015-03-03 23:17:53,22 2015-03-03 23:22:53,24 2015-03-03 23:27:53,22 2015-03-03 23:32:53,21 2015-03-03 23:37:53,31 2015-03-03 23:42:53,39 2015-03-03 23:47:53,21 2015-03-03 23:52:53,17 2015-03-03 23:57:53,22 2015-03-04 00:02:53,20 2015-03-04 00:07:53,21 2015-03-04 00:12:53,17 2015-03-04 00:17:53,15 2015-03-04 00:22:53,13 2015-03-04 00:27:53,15 2015-03-04 00:32:53,18 2015-03-04 00:37:53,14 2015-03-04 00:42:53,8 2015-03-04 00:47:53,7 2015-03-04 00:52:53,14 2015-03-04 00:57:53,26 2015-03-04 01:02:53,11 2015-03-04 01:07:53,15 2015-03-04 01:12:53,11 2015-03-04 01:17:53,13 2015-03-04 01:22:53,20 2015-03-04 01:27:53,20 2015-03-04 01:32:53,13 2015-03-04 01:37:53,15 2015-03-04 01:42:53,7 2015-03-04 01:47:53,7 2015-03-04 01:52:53,16 2015-03-04 01:57:53,10 2015-03-04 02:02:53,20 2015-03-04 02:07:53,13 2015-03-04 02:12:53,15 2015-03-04 02:17:53,7 2015-03-04 02:22:53,12 2015-03-04 02:27:53,26 2015-03-04 02:32:53,25 2015-03-04 02:37:53,20 2015-03-04 02:42:53,6 2015-03-04 02:47:53,6 2015-03-04 02:52:53,7 2015-03-04 02:57:53,18 2015-03-04 03:02:53,8 2015-03-04 03:07:53,25 2015-03-04 03:12:53,23 2015-03-04 03:17:53,13 2015-03-04 03:22:53,10 2015-03-04 03:27:53,23 2015-03-04 03:32:53,6 2015-03-04 03:37:53,11 2015-03-04 03:42:53,2 2015-03-04 03:47:53,8 2015-03-04 03:52:53,8 2015-03-04 03:57:53,25 2015-03-04 04:02:53,13 2015-03-04 04:07:53,15 2015-03-04 04:12:53,15 2015-03-04 04:17:53,10 2015-03-04 04:22:53,10 2015-03-04 04:27:53,22 2015-03-04 04:32:53,17 2015-03-04 04:37:53,11 2015-03-04 04:42:53,16 2015-03-04 04:47:53,20 2015-03-04 04:52:53,23 2015-03-04 04:57:53,25 2015-03-04 05:02:53,14 2015-03-04 05:07:53,6 2015-03-04 05:12:53,12 2015-03-04 05:17:53,14 2015-03-04 05:22:53,8 2015-03-04 05:27:53,7 2015-03-04 05:32:53,17 2015-03-04 05:37:53,12 2015-03-04 05:42:53,7 2015-03-04 05:47:53,14 2015-03-04 05:52:53,16 2015-03-04 05:57:53,18 2015-03-04 06:02:53,22 2015-03-04 06:07:53,6 2015-03-04 06:12:53,4 2015-03-04 06:17:53,7 2015-03-04 06:22:53,9 2015-03-04 06:27:53,14 2015-03-04 06:32:53,9 2015-03-04 06:37:53,10 2015-03-04 06:42:53,16 2015-03-04 06:47:53,6 2015-03-04 06:52:53,7 2015-03-04 06:57:53,19 2015-03-04 07:02:53,9 2015-03-04 07:07:53,10 2015-03-04 07:12:53,24 2015-03-04 07:17:53,8 2015-03-04 07:22:53,12 2015-03-04 07:27:53,15 2015-03-04 07:32:53,6 2015-03-04 07:37:53,16 2015-03-04 07:42:53,12 2015-03-04 07:47:53,9 2015-03-04 07:52:53,11 2015-03-04 07:57:53,8 2015-03-04 08:02:53,12 2015-03-04 08:07:53,4 2015-03-04 08:12:53,7 2015-03-04 08:17:53,17 2015-03-04 08:22:53,10 2015-03-04 08:27:53,34 2015-03-04 08:32:53,18 2015-03-04 08:37:53,12 2015-03-04 08:42:53,11 2015-03-04 08:47:53,15 2015-03-04 08:52:53,31 2015-03-04 08:57:53,46 2015-03-04 09:02:53,82 2015-03-04 09:07:53,45 2015-03-04 09:12:53,20 2015-03-04 09:17:53,21 2015-03-04 09:22:53,15 2015-03-04 09:27:53,20 2015-03-04 09:32:53,21 2015-03-04 09:37:53,24 2015-03-04 09:42:53,18 2015-03-04 09:47:53,30 2015-03-04 09:52:53,20 2015-03-04 09:57:53,31 2015-03-04 10:02:53,27 2015-03-04 10:07:53,25 2015-03-04 10:12:53,55 2015-03-04 10:17:53,47 2015-03-04 10:22:53,29 2015-03-04 10:27:53,30 2015-03-04 10:32:53,24 2015-03-04 10:37:53,30 2015-03-04 10:42:53,32 2015-03-04 10:47:53,11 2015-03-04 10:52:53,30 2015-03-04 10:57:53,35 2015-03-04 11:02:53,31 2015-03-04 11:07:53,17 2015-03-04 11:12:53,16 2015-03-04 11:17:53,16 2015-03-04 11:22:53,19 2015-03-04 11:27:53,22 2015-03-04 11:32:53,33 2015-03-04 11:37:53,23 2015-03-04 11:42:53,18 2015-03-04 11:47:53,31 2015-03-04 11:52:53,22 2015-03-04 11:57:53,19 2015-03-04 12:02:53,12 2015-03-04 12:07:53,14 2015-03-04 12:12:53,27 2015-03-04 12:17:53,21 2015-03-04 12:22:53,22 2015-03-04 12:27:53,20 2015-03-04 12:32:53,26 2015-03-04 12:37:53,14 2015-03-04 12:42:53,18 2015-03-04 12:47:53,36 2015-03-04 12:52:53,15 2015-03-04 12:57:53,27 2015-03-04 13:02:53,19 2015-03-04 13:07:53,16 2015-03-04 13:12:53,26 2015-03-04 13:17:53,16 2015-03-04 13:22:53,20 2015-03-04 13:27:53,23 2015-03-04 13:32:53,24 2015-03-04 13:37:53,27 2015-03-04 13:42:53,33 2015-03-04 13:47:53,30 2015-03-04 13:52:53,11 2015-03-04 13:57:53,30 2015-03-04 14:02:53,28 2015-03-04 14:07:53,19 2015-03-04 14:12:53,21 2015-03-04 14:17:53,26 2015-03-04 14:22:53,184 2015-03-04 14:27:53,144 2015-03-04 14:32:53,89 2015-03-04 14:37:53,59 2015-03-04 14:42:53,56 2015-03-04 14:47:53,45 2015-03-04 14:52:53,56 2015-03-04 14:57:53,71 2015-03-04 15:02:53,44 2015-03-04 15:07:53,67 2015-03-04 15:12:53,58 2015-03-04 15:17:53,58 2015-03-04 15:22:53,49 2015-03-04 15:27:53,40 2015-03-04 15:32:53,46 2015-03-04 15:37:53,46 2015-03-04 15:42:53,36 2015-03-04 15:47:53,42 2015-03-04 15:52:53,39 2015-03-04 15:57:53,33 2015-03-04 16:02:53,48 2015-03-04 16:07:53,70 2015-03-04 16:12:53,56 2015-03-04 16:17:53,41 2015-03-04 16:22:53,38 2015-03-04 16:27:53,54 2015-03-04 16:32:53,31 2015-03-04 16:37:53,32 2015-03-04 16:42:53,38 2015-03-04 16:47:53,36 2015-03-04 16:52:53,37 2015-03-04 16:57:53,33 2015-03-04 17:02:53,29 2015-03-04 17:07:53,42 2015-03-04 17:12:53,38 2015-03-04 17:17:53,31 2015-03-04 17:22:53,20 2015-03-04 17:27:53,32 2015-03-04 17:32:53,29 2015-03-04 17:37:53,35 2015-03-04 17:42:53,36 2015-03-04 17:47:53,29 2015-03-04 17:52:53,31 2015-03-04 17:57:53,50 2015-03-04 18:02:53,19 2015-03-04 18:07:53,36 2015-03-04 18:12:53,25 2015-03-04 18:17:53,19 2015-03-04 18:22:53,21 2015-03-04 18:27:53,26 2015-03-04 18:32:53,19 2015-03-04 18:37:53,28 2015-03-04 18:42:53,21 2015-03-04 18:47:53,35 2015-03-04 18:52:53,33 2015-03-04 18:57:53,51 2015-03-04 19:02:53,36 2015-03-04 19:07:53,21 2015-03-04 19:12:53,33 2015-03-04 19:17:53,29 2015-03-04 19:22:53,29 2015-03-04 19:27:53,48 2015-03-04 19:32:53,30 2015-03-04 19:37:53,42 2015-03-04 19:42:53,21 2015-03-04 19:47:53,28 2015-03-04 19:52:53,37 2015-03-04 19:57:53,43 2015-03-04 20:02:53,31 2015-03-04 20:07:53,24 2015-03-04 20:12:53,24 2015-03-04 20:17:53,31 2015-03-04 20:22:53,19 2015-03-04 20:27:53,29 2015-03-04 20:32:53,36 2015-03-04 20:37:53,29 2015-03-04 20:42:53,27 2015-03-04 20:47:53,21 2015-03-04 20:52:53,22 2015-03-04 20:57:53,37 2015-03-04 21:02:53,28 2015-03-04 21:07:53,16 2015-03-04 21:12:53,21 2015-03-04 21:17:53,28 2015-03-04 21:22:53,25 2015-03-04 21:27:53,28 2015-03-04 21:32:53,21 2015-03-04 21:37:53,8 2015-03-04 21:42:53,26 2015-03-04 21:47:53,21 2015-03-04 21:52:53,26 2015-03-04 21:57:53,20 2015-03-04 22:02:53,17 2015-03-04 22:07:53,19 2015-03-04 22:12:53,16 2015-03-04 22:17:53,14 2015-03-04 22:22:53,16 2015-03-04 22:27:53,23 2015-03-04 22:32:53,16 2015-03-04 22:37:53,12 2015-03-04 22:42:53,14 2015-03-04 22:47:53,12 2015-03-04 22:52:53,17 2015-03-04 22:57:53,17 2015-03-04 23:02:53,26 2015-03-04 23:07:53,19 2015-03-04 23:12:53,14 2015-03-04 23:17:53,27 2015-03-04 23:22:53,16 2015-03-04 23:27:53,35 2015-03-04 23:32:53,21 2015-03-04 23:37:53,24 2015-03-04 23:42:53,12 2015-03-04 23:47:53,15 2015-03-04 23:52:53,12 2015-03-04 23:57:53,22 2015-03-05 00:02:53,17 2015-03-05 00:07:53,17 2015-03-05 00:12:53,20 2015-03-05 00:17:53,11 2015-03-05 00:22:53,9 2015-03-05 00:27:53,24 2015-03-05 00:32:53,21 2015-03-05 00:37:53,18 2015-03-05 00:42:53,16 2015-03-05 00:47:53,17 2015-03-05 00:52:53,22 2015-03-05 00:57:53,23 2015-03-05 01:02:53,15 2015-03-05 01:07:53,19 2015-03-05 01:12:53,16 2015-03-05 01:17:53,24 2015-03-05 01:22:53,19 2015-03-05 01:27:53,14 2015-03-05 01:32:53,7 2015-03-05 01:37:53,12 2015-03-05 01:42:53,19 2015-03-05 01:47:53,14 2015-03-05 01:52:53,22 2015-03-05 01:57:53,15 2015-03-05 02:02:53,17 2015-03-05 02:07:53,19 2015-03-05 02:12:53,18 2015-03-05 02:17:53,16 2015-03-05 02:22:53,14 2015-03-05 02:27:53,21 2015-03-05 02:32:53,27 2015-03-05 02:37:53,20 2015-03-05 02:42:53,15 2015-03-05 02:47:53,18 2015-03-05 02:52:53,17 2015-03-05 02:57:53,14 2015-03-05 03:02:53,10 2015-03-05 03:07:53,19 2015-03-05 03:12:53,24 2015-03-05 03:17:53,11 2015-03-05 03:22:53,9 2015-03-05 03:27:53,27 2015-03-05 03:32:53,14 2015-03-05 03:37:53,6 2015-03-05 03:42:53,17 2015-03-05 03:47:53,11 2015-03-05 03:52:53,10 2015-03-05 03:57:53,18 2015-03-05 04:02:53,34 2015-03-05 04:07:53,18 2015-03-05 04:12:53,24 2015-03-05 04:17:53,22 2015-03-05 04:22:53,18 2015-03-05 04:27:53,7 2015-03-05 04:32:53,24 2015-03-05 04:37:53,17 2015-03-05 04:42:53,20 2015-03-05 04:47:53,26 2015-03-05 04:52:53,21 2015-03-05 04:57:53,21 2015-03-05 05:02:53,21 2015-03-05 05:07:53,22 2015-03-05 05:12:53,27 2015-03-05 05:17:53,14 2015-03-05 05:22:53,15 2015-03-05 05:27:53,18 2015-03-05 05:32:53,4 2015-03-05 05:37:53,25 2015-03-05 05:42:53,21 2015-03-05 05:47:53,21 2015-03-05 05:52:53,17 2015-03-05 05:57:53,12 2015-03-05 06:02:53,15 2015-03-05 06:07:53,9 2015-03-05 06:12:53,10 2015-03-05 06:17:53,9 2015-03-05 06:22:53,17 2015-03-05 06:27:53,9 2015-03-05 06:32:53,15 2015-03-05 06:37:53,13 2015-03-05 06:42:53,14 2015-03-05 06:47:53,10 2015-03-05 06:52:53,19 2015-03-05 06:57:53,8 2015-03-05 07:02:53,15 2015-03-05 07:07:53,15 2015-03-05 07:12:53,14 2015-03-05 07:17:53,20 2015-03-05 07:22:53,25 2015-03-05 07:27:53,23 2015-03-05 07:32:53,19 2015-03-05 07:37:53,13 2015-03-05 07:42:53,16 2015-03-05 07:47:53,12 2015-03-05 07:52:53,12 2015-03-05 07:57:53,23 2015-03-05 08:02:53,15 2015-03-05 08:07:53,22 2015-03-05 08:12:53,18 2015-03-05 08:17:53,21 2015-03-05 08:22:53,16 2015-03-05 08:27:53,13 2015-03-05 08:32:53,19 2015-03-05 08:37:53,22 2015-03-05 08:42:53,18 2015-03-05 08:47:53,11 2015-03-05 08:52:53,7 2015-03-05 08:57:53,27 2015-03-05 09:02:53,12 2015-03-05 09:07:53,11 2015-03-05 09:12:53,16 2015-03-05 09:17:53,22 2015-03-05 09:22:53,16 2015-03-05 09:27:53,35 2015-03-05 09:32:53,26 2015-03-05 09:37:53,10 2015-03-05 09:42:53,25 2015-03-05 09:47:53,20 2015-03-05 09:52:53,24 2015-03-05 09:57:53,26 2015-03-05 10:02:53,16 2015-03-05 10:07:53,22 2015-03-05 10:12:53,15 2015-03-05 10:17:53,15 2015-03-05 10:22:53,15 2015-03-05 10:27:53,14 2015-03-05 10:32:53,14 2015-03-05 10:37:53,16 2015-03-05 10:42:53,14 2015-03-05 10:47:53,14 2015-03-05 10:52:53,5 2015-03-05 10:57:53,27 2015-03-05 11:02:53,19 2015-03-05 11:07:53,19 2015-03-05 11:12:53,17 2015-03-05 11:17:53,33 2015-03-05 11:22:53,30 2015-03-05 11:27:53,16 2015-03-05 11:32:53,21 2015-03-05 11:37:53,13 2015-03-05 11:42:53,15 2015-03-05 11:47:53,18 2015-03-05 11:52:53,13 2015-03-05 11:57:53,13 2015-03-05 12:02:53,16 2015-03-05 12:07:53,12 2015-03-05 12:12:53,12 2015-03-05 12:17:53,23 2015-03-05 12:22:53,34 2015-03-05 12:27:53,14 2015-03-05 12:32:53,25 2015-03-05 12:37:53,20 2015-03-05 12:42:53,15 2015-03-05 12:47:53,24 2015-03-05 12:52:53,52 2015-03-05 12:57:53,82 2015-03-05 13:02:53,92 2015-03-05 13:07:53,106 2015-03-05 13:12:53,103 2015-03-05 13:17:53,86 2015-03-05 13:22:53,88 2015-03-05 13:27:53,75 2015-03-05 13:32:53,41 2015-03-05 13:37:53,20 2015-03-05 13:42:53,67 2015-03-05 13:47:53,26 2015-03-05 13:52:53,30 2015-03-05 13:57:53,33 2015-03-05 14:02:53,16 2015-03-05 14:07:53,16 2015-03-05 14:12:53,21 2015-03-05 14:17:53,18 2015-03-05 14:22:53,21 2015-03-05 14:27:53,18 2015-03-05 14:32:53,16 2015-03-05 14:37:53,20 2015-03-05 14:42:53,28 2015-03-05 14:47:53,24 2015-03-05 14:52:53,24 2015-03-05 14:57:53,76 2015-03-05 15:02:53,52 2015-03-05 15:07:53,54 2015-03-05 15:12:53,56 2015-03-05 15:17:53,41 2015-03-05 15:22:53,43 2015-03-05 15:27:53,38 2015-03-05 15:32:53,42 2015-03-05 15:37:53,33 2015-03-05 15:42:53,27 2015-03-05 15:47:53,31 2015-03-05 15:52:53,32 2015-03-05 15:57:53,46 2015-03-05 16:02:53,36 2015-03-05 16:07:53,26 2015-03-05 16:12:53,36 2015-03-05 16:17:53,40 2015-03-05 16:22:53,39 2015-03-05 16:27:53,50 2015-03-05 16:32:53,51 2015-03-05 16:37:53,35 2015-03-05 16:42:53,29 2015-03-05 16:47:53,35 2015-03-05 16:52:53,28 2015-03-05 16:57:53,23 2015-03-05 17:02:53,31 2015-03-05 17:07:53,33 2015-03-05 17:12:53,32 2015-03-05 17:17:53,39 2015-03-05 17:22:53,24 2015-03-05 17:27:53,27 2015-03-05 17:32:53,40 2015-03-05 17:37:53,24 2015-03-05 17:42:53,27 2015-03-05 17:47:53,44 2015-03-05 17:52:53,40 2015-03-05 17:57:53,29 2015-03-05 18:02:53,26 2015-03-05 18:07:53,25 2015-03-05 18:12:53,24 2015-03-05 18:17:53,12 2015-03-05 18:22:53,21 2015-03-05 18:27:53,27 2015-03-05 18:32:53,31 2015-03-05 18:37:53,22 2015-03-05 18:42:53,24 2015-03-05 18:47:53,28 2015-03-05 18:52:53,20 2015-03-05 18:57:53,29 2015-03-05 19:02:53,25 2015-03-05 19:07:53,15 2015-03-05 19:12:53,28 2015-03-05 19:17:53,29 2015-03-05 19:22:53,28 2015-03-05 19:27:53,30 2015-03-05 19:32:53,21 2015-03-05 19:37:53,16 2015-03-05 19:42:53,26 2015-03-05 19:47:53,37 2015-03-05 19:52:53,39 2015-03-05 19:57:53,24 2015-03-05 20:02:53,28 2015-03-05 20:07:53,23 2015-03-05 20:12:53,43 2015-03-05 20:17:53,52 2015-03-05 20:22:53,90 2015-03-05 20:27:53,49 2015-03-05 20:32:53,45 2015-03-05 20:37:53,78 2015-03-05 20:42:53,53 2015-03-05 20:47:53,49 2015-03-05 20:52:53,35 2015-03-05 20:57:53,51 2015-03-05 21:02:53,34 2015-03-05 21:07:53,33 2015-03-05 21:12:53,29 2015-03-05 21:17:53,32 2015-03-05 21:22:53,40 2015-03-05 21:27:53,40 2015-03-05 21:32:53,27 2015-03-05 21:37:53,20 2015-03-05 21:42:53,32 2015-03-05 21:47:53,40 2015-03-05 21:52:53,35 2015-03-05 21:57:53,75 2015-03-05 22:02:53,31 2015-03-05 22:07:53,24 2015-03-05 22:12:53,21 2015-03-05 22:17:53,24 2015-03-05 22:22:53,26 2015-03-05 22:27:53,19 2015-03-05 22:32:53,15 2015-03-05 22:37:53,23 2015-03-05 22:42:53,29 2015-03-05 22:47:53,20 2015-03-05 22:52:53,34 2015-03-05 22:57:53,26 2015-03-05 23:02:53,17 2015-03-05 23:07:53,14 2015-03-05 23:12:53,27 2015-03-05 23:17:53,21 2015-03-05 23:22:53,32 2015-03-05 23:27:53,40 2015-03-05 23:32:53,53 2015-03-05 23:37:53,28 2015-03-05 23:42:53,23 2015-03-05 23:47:53,23 2015-03-05 23:52:53,29 2015-03-05 23:57:53,30 2015-03-06 00:02:53,38 2015-03-06 00:07:53,34 2015-03-06 00:12:53,28 2015-03-06 00:17:53,21 2015-03-06 00:22:53,19 2015-03-06 00:27:53,18 2015-03-06 00:32:53,25 2015-03-06 00:37:53,20 2015-03-06 00:42:53,28 2015-03-06 00:47:53,20 2015-03-06 00:52:53,30 2015-03-06 00:57:53,33 2015-03-06 01:02:53,17 2015-03-06 01:07:53,9 2015-03-06 01:12:53,28 2015-03-06 01:17:53,8 2015-03-06 01:22:53,21 2015-03-06 01:27:53,18 2015-03-06 01:32:53,25 2015-03-06 01:37:53,22 2015-03-06 01:42:53,17 2015-03-06 01:47:53,60 2015-03-06 01:52:53,40 2015-03-06 01:57:53,36 2015-03-06 02:02:53,13 2015-03-06 02:07:53,19 2015-03-06 02:12:53,20 2015-03-06 02:17:53,21 2015-03-06 02:22:53,30 2015-03-06 02:27:53,30 2015-03-06 02:32:53,29 2015-03-06 02:37:53,17 2015-03-06 02:42:53,24 2015-03-06 02:47:53,14 2015-03-06 02:52:53,21 2015-03-06 02:57:53,18 2015-03-06 03:02:53,21 2015-03-06 03:07:53,15 2015-03-06 03:12:53,31 2015-03-06 03:17:53,22 2015-03-06 03:22:53,13 2015-03-06 03:27:53,21 2015-03-06 03:32:53,19 2015-03-06 03:37:53,9 2015-03-06 03:42:53,25 2015-03-06 03:47:53,19 2015-03-06 03:52:53,13 2015-03-06 03:57:53,51 2015-03-06 04:02:53,13 2015-03-06 04:07:53,16 2015-03-06 04:12:53,31 2015-03-06 04:17:53,7 2015-03-06 04:22:53,15 2015-03-06 04:27:53,15 2015-03-06 04:32:53,15 2015-03-06 04:37:53,16 2015-03-06 04:42:53,11 2015-03-06 04:47:53,8 2015-03-06 04:52:53,15 2015-03-06 04:57:53,31 2015-03-06 05:02:53,9 2015-03-06 05:07:53,8 2015-03-06 05:12:53,12 2015-03-06 05:17:53,9 2015-03-06 05:22:53,18 2015-03-06 05:27:53,14 2015-03-06 05:32:53,12 2015-03-06 05:37:53,12 2015-03-06 05:42:53,13 2015-03-06 05:47:53,6 2015-03-06 05:52:53,9 2015-03-06 05:57:53,20 2015-03-06 06:02:53,13 2015-03-06 06:07:53,10 2015-03-06 06:12:53,12 2015-03-06 06:17:53,14 2015-03-06 06:22:53,12 2015-03-06 06:27:53,13 2015-03-06 06:32:53,15 2015-03-06 06:37:53,10 2015-03-06 06:42:53,20 2015-03-06 06:47:53,8 2015-03-06 06:52:53,15 2015-03-06 06:57:53,23 2015-03-06 07:02:53,12 2015-03-06 07:07:53,10 2015-03-06 07:12:53,26 2015-03-06 07:17:53,7 2015-03-06 07:22:53,5 2015-03-06 07:27:53,18 2015-03-06 07:32:53,3 2015-03-06 07:37:53,12 2015-03-06 07:42:53,9 2015-03-06 07:47:53,7 2015-03-06 07:52:53,9 2015-03-06 07:57:53,21 2015-03-06 08:02:53,11 2015-03-06 08:07:53,35 2015-03-06 08:12:53,15 2015-03-06 08:17:53,11 2015-03-06 08:22:53,11 2015-03-06 08:27:53,17 2015-03-06 08:32:53,8 2015-03-06 08:37:53,10 2015-03-06 08:42:53,7 2015-03-06 08:47:53,12 2015-03-06 08:52:53,15 2015-03-06 08:57:53,22 2015-03-06 09:02:53,12 2015-03-06 09:07:53,17 2015-03-06 09:12:53,11 2015-03-06 09:17:53,17 2015-03-06 09:22:53,13 2015-03-06 09:27:53,15 2015-03-06 09:32:53,10 2015-03-06 09:37:53,9 2015-03-06 09:42:53,13 2015-03-06 09:47:53,5 2015-03-06 09:52:53,12 2015-03-06 09:57:53,13 2015-03-06 10:02:53,10 2015-03-06 10:07:53,15 2015-03-06 10:12:53,11 2015-03-06 10:17:53,12 2015-03-06 10:22:53,15 2015-03-06 10:27:53,9 2015-03-06 10:32:53,16 2015-03-06 10:37:53,9 2015-03-06 10:42:53,15 2015-03-06 10:47:53,13 2015-03-06 10:52:53,22 2015-03-06 10:57:53,17 2015-03-06 11:02:53,20 2015-03-06 11:07:53,13 2015-03-06 11:12:53,12 2015-03-06 11:17:53,17 2015-03-06 11:22:53,17 2015-03-06 11:27:53,18 2015-03-06 11:32:53,5 2015-03-06 11:37:53,5 2015-03-06 11:42:53,13 2015-03-06 11:47:53,18 2015-03-06 11:52:53,22 2015-03-06 11:57:53,19 2015-03-06 12:02:53,8 2015-03-06 12:07:53,16 2015-03-06 12:12:53,28 2015-03-06 12:17:53,13 2015-03-06 12:22:53,29 2015-03-06 12:27:53,22 2015-03-06 12:32:53,13 2015-03-06 12:37:53,22 2015-03-06 12:42:53,24 2015-03-06 12:47:53,19 2015-03-06 12:52:53,17 2015-03-06 12:57:53,26 2015-03-06 13:02:53,22 2015-03-06 13:07:53,25 2015-03-06 13:12:53,14 2015-03-06 13:17:53,18 2015-03-06 13:22:53,13 2015-03-06 13:27:53,29 2015-03-06 13:32:53,16 2015-03-06 13:37:53,36 2015-03-06 13:42:53,49 2015-03-06 13:47:53,27 2015-03-06 13:52:53,36 2015-03-06 13:57:53,34 2015-03-06 14:02:53,25 2015-03-06 14:07:53,29 2015-03-06 14:12:53,31 2015-03-06 14:17:53,21 2015-03-06 14:22:53,38 2015-03-06 14:27:53,18 2015-03-06 14:32:53,23 2015-03-06 14:37:53,27 2015-03-06 14:42:53,15 2015-03-06 14:47:53,14 2015-03-06 14:52:53,17 2015-03-06 14:57:53,20 2015-03-06 15:02:53,18 2015-03-06 15:07:53,35 2015-03-06 15:12:53,27 2015-03-06 15:17:53,31 2015-03-06 15:22:53,25 2015-03-06 15:27:53,37 2015-03-06 15:32:53,21 2015-03-06 15:37:53,18 2015-03-06 15:42:53,24 2015-03-06 15:47:53,28 2015-03-06 15:52:53,21 2015-03-06 15:57:53,27 2015-03-06 16:02:53,23 2015-03-06 16:07:53,17 2015-03-06 16:12:53,17 2015-03-06 16:17:53,24 2015-03-06 16:22:53,20 2015-03-06 16:27:53,46 2015-03-06 16:32:53,25 2015-03-06 16:37:53,44 2015-03-06 16:42:53,22 2015-03-06 16:47:53,17 2015-03-06 16:52:53,23 2015-03-06 16:57:53,28 2015-03-06 17:02:53,20 2015-03-06 17:07:53,25 2015-03-06 17:12:53,21 2015-03-06 17:17:53,19 2015-03-06 17:22:53,24 2015-03-06 17:27:53,32 2015-03-06 17:32:53,20 2015-03-06 17:37:53,15 2015-03-06 17:42:53,22 2015-03-06 17:47:53,34 2015-03-06 17:52:53,16 2015-03-06 17:57:53,18 2015-03-06 18:02:53,24 2015-03-06 18:07:53,16 2015-03-06 18:12:53,9 2015-03-06 18:17:53,16 2015-03-06 18:22:53,23 2015-03-06 18:27:53,27 2015-03-06 18:32:53,29 2015-03-06 18:37:53,16 2015-03-06 18:42:53,19 2015-03-06 18:47:53,20 2015-03-06 18:52:53,57 2015-03-06 18:57:53,63 2015-03-06 19:02:53,41 2015-03-06 19:07:53,37 2015-03-06 19:12:53,16 2015-03-06 19:17:53,15 2015-03-06 19:22:53,13 2015-03-06 19:27:53,19 2015-03-06 19:32:53,18 2015-03-06 19:37:53,31 2015-03-06 19:42:53,24 2015-03-06 19:47:53,20 2015-03-06 19:52:53,20 2015-03-06 19:57:53,30 2015-03-06 20:02:53,23 2015-03-06 20:07:53,12 2015-03-06 20:12:53,22 2015-03-06 20:17:53,14 2015-03-06 20:22:53,23 2015-03-06 20:27:53,20 2015-03-06 20:32:53,56 2015-03-06 20:37:53,112 2015-03-06 20:42:53,69 2015-03-06 20:47:53,51 2015-03-06 20:52:53,61 2015-03-06 20:57:53,65 2015-03-06 21:02:53,29 2015-03-06 21:07:53,36 2015-03-06 21:12:53,29 2015-03-06 21:17:53,49 2015-03-06 21:22:53,47 2015-03-06 21:27:53,42 2015-03-06 21:32:53,41 2015-03-06 21:37:53,27 2015-03-06 21:42:53,28 2015-03-06 21:47:53,21 2015-03-06 21:52:53,30 2015-03-06 21:57:53,27 2015-03-06 22:02:53,18 2015-03-06 22:07:53,22 2015-03-06 22:12:53,18 2015-03-06 22:17:53,34 2015-03-06 22:22:53,28 2015-03-06 22:27:53,37 2015-03-06 22:32:53,20 2015-03-06 22:37:53,26 2015-03-06 22:42:53,26 2015-03-06 22:47:53,60 2015-03-06 22:52:53,37 2015-03-06 22:57:53,34 2015-03-06 23:02:53,25 2015-03-06 23:07:53,22 2015-03-06 23:12:53,21 2015-03-06 23:17:53,25 2015-03-06 23:22:53,14 2015-03-06 23:27:53,17 2015-03-06 23:32:53,24 2015-03-06 23:37:53,38 2015-03-06 23:42:53,25 2015-03-06 23:47:53,29 2015-03-06 23:52:53,32 2015-03-06 23:57:53,36 2015-03-07 00:02:53,18 2015-03-07 00:07:53,17 2015-03-07 00:12:53,20 2015-03-07 00:17:53,18 2015-03-07 00:22:53,14 2015-03-07 00:27:53,34 2015-03-07 00:32:53,25 2015-03-07 00:37:53,9 2015-03-07 00:42:53,15 2015-03-07 00:47:53,9 2015-03-07 00:52:53,6 2015-03-07 00:57:53,9 2015-03-07 01:02:53,24 2015-03-07 01:07:53,9 2015-03-07 01:12:53,13 2015-03-07 01:17:53,10 2015-03-07 01:22:53,22 2015-03-07 01:27:53,9 2015-03-07 01:32:53,9 2015-03-07 01:37:53,20 2015-03-07 01:42:53,20 2015-03-07 01:47:53,13 2015-03-07 01:52:53,13 2015-03-07 01:57:53,22 2015-03-07 02:02:53,15 2015-03-07 02:07:53,8 2015-03-07 02:12:53,11 2015-03-07 02:17:53,21 2015-03-07 02:22:53,11 2015-03-07 02:27:53,16 2015-03-07 02:32:53,17 2015-03-07 02:37:53,21 2015-03-07 02:42:53,22 2015-03-07 02:47:53,11 2015-03-07 02:52:53,14 2015-03-07 02:57:53,12 2015-03-07 03:02:53,11 2015-03-07 03:07:53,7 2015-03-07 03:12:53,15 2015-03-07 03:17:53,12 2015-03-07 03:22:53,10 2015-03-07 03:27:53,9 2015-03-07 03:32:53,5 2015-03-07 03:37:53,4 2015-03-07 03:42:53,9 2015-03-07 03:47:53,12 2015-03-07 03:52:53,13 2015-03-07 03:57:53,13 2015-03-07 04:02:53,6 2015-03-07 04:07:53,25 2015-03-07 04:12:53,3 2015-03-07 04:17:53,13 2015-03-07 04:22:53,7 2015-03-07 04:27:53,8 2015-03-07 04:32:53,7 2015-03-07 04:37:53,12 2015-03-07 04:42:53,6 2015-03-07 04:47:53,5 2015-03-07 04:52:53,6 2015-03-07 04:57:53,15 2015-03-07 05:02:53,22 2015-03-07 05:07:53,16 2015-03-07 05:12:53,12 2015-03-07 05:17:53,6 2015-03-07 05:22:53,14 2015-03-07 05:27:53,7 2015-03-07 05:32:53,13 2015-03-07 05:37:53,17 2015-03-07 05:42:53,5 2015-03-07 05:47:53,13 2015-03-07 05:52:53,15 2015-03-07 05:57:53,12 2015-03-07 06:02:53,16 2015-03-07 06:07:53,7 2015-03-07 06:12:53,11 2015-03-07 06:17:53,8 2015-03-07 06:22:53,15 2015-03-07 06:27:53,11 2015-03-07 06:32:53,10 2015-03-07 06:37:53,10 2015-03-07 06:42:53,6 2015-03-07 06:47:53,8 2015-03-07 06:52:53,11 2015-03-07 06:57:53,13 2015-03-07 07:02:53,15 2015-03-07 07:07:53,11 2015-03-07 07:12:53,9 2015-03-07 07:17:53,10 2015-03-07 07:22:53,10 2015-03-07 07:27:53,11 2015-03-07 07:32:53,15 2015-03-07 07:37:53,13 2015-03-07 07:42:53,16 2015-03-07 07:47:53,9 2015-03-07 07:52:53,8 2015-03-07 07:57:53,11 2015-03-07 08:02:53,4 2015-03-07 08:07:53,18 2015-03-07 08:12:53,2 2015-03-07 08:17:53,9 2015-03-07 08:22:53,11 2015-03-07 08:27:53,9 2015-03-07 08:32:53,12 2015-03-07 08:37:53,12 2015-03-07 08:42:53,16 2015-03-07 08:47:53,14 2015-03-07 08:52:53,5 2015-03-07 08:57:53,21 2015-03-07 09:02:53,11 2015-03-07 09:07:53,12 2015-03-07 09:12:53,9 2015-03-07 09:17:53,9 2015-03-07 09:22:53,6 2015-03-07 09:27:53,4 2015-03-07 09:32:53,8 2015-03-07 09:37:53,11 2015-03-07 09:42:53,9 2015-03-07 09:47:53,16 2015-03-07 09:52:53,11 2015-03-07 09:57:53,10 2015-03-07 10:02:53,14 2015-03-07 10:07:53,10 2015-03-07 10:12:53,9 2015-03-07 10:17:53,6 2015-03-07 10:22:53,6 2015-03-07 10:27:53,6 2015-03-07 10:32:53,5 2015-03-07 10:37:53,10 2015-03-07 10:42:53,4 2015-03-07 10:47:53,11 2015-03-07 10:52:53,3 2015-03-07 10:57:53,8 2015-03-07 11:02:53,8 2015-03-07 11:07:53,8 2015-03-07 11:12:53,4 2015-03-07 11:17:53,9 2015-03-07 11:22:53,15 2015-03-07 11:27:53,9 2015-03-07 11:32:53,17 2015-03-07 11:37:53,34 2015-03-07 11:42:53,13 2015-03-07 11:47:53,8 2015-03-07 11:52:53,5 2015-03-07 11:57:53,12 2015-03-07 12:02:53,14 2015-03-07 12:07:53,8 2015-03-07 12:12:53,13 2015-03-07 12:17:53,13 2015-03-07 12:22:53,7 2015-03-07 12:27:53,7 2015-03-07 12:32:53,13 2015-03-07 12:37:53,19 2015-03-07 12:42:53,29 2015-03-07 12:47:53,9 2015-03-07 12:52:53,13 2015-03-07 12:57:53,11 2015-03-07 13:02:53,9 2015-03-07 13:07:53,13 2015-03-07 13:12:53,9 2015-03-07 13:17:53,8 2015-03-07 13:22:53,15 2015-03-07 13:27:53,12 2015-03-07 13:32:53,12 2015-03-07 13:37:53,7 2015-03-07 13:42:53,9 2015-03-07 13:47:53,12 2015-03-07 13:52:53,14 2015-03-07 13:57:53,17 2015-03-07 14:02:53,6 2015-03-07 14:07:53,13 2015-03-07 14:12:53,15 2015-03-07 14:17:53,1 2015-03-07 14:22:53,9 2015-03-07 14:27:53,26 2015-03-07 14:32:53,8 2015-03-07 14:37:53,13 2015-03-07 14:42:53,12 2015-03-07 14:47:53,18 2015-03-07 14:52:53,6 2015-03-07 14:57:53,11 2015-03-07 15:02:53,7 2015-03-07 15:07:53,9 2015-03-07 15:12:53,5 2015-03-07 15:17:53,11 2015-03-07 15:22:53,11 2015-03-07 15:27:53,16 2015-03-07 15:32:53,7 2015-03-07 15:37:53,12 2015-03-07 15:42:53,13 2015-03-07 15:47:53,15 2015-03-07 15:52:53,26 2015-03-07 15:57:53,22 2015-03-07 16:02:53,14 2015-03-07 16:07:53,11 2015-03-07 16:12:53,12 2015-03-07 16:17:53,16 2015-03-07 16:22:53,18 2015-03-07 16:27:53,10 2015-03-07 16:32:53,12 2015-03-07 16:37:53,13 2015-03-07 16:42:53,14 2015-03-07 16:47:53,14 2015-03-07 16:52:53,8 2015-03-07 16:57:53,18 2015-03-07 17:02:53,14 2015-03-07 17:07:53,10 2015-03-07 17:12:53,14 2015-03-07 17:17:53,7 2015-03-07 17:22:53,23 2015-03-07 17:27:53,12 2015-03-07 17:32:53,13 2015-03-07 17:37:53,18 2015-03-07 17:42:53,18 2015-03-07 17:47:53,12 2015-03-07 17:52:53,18 2015-03-07 17:57:53,19 2015-03-07 18:02:53,18 2015-03-07 18:07:53,21 2015-03-07 18:12:53,10 2015-03-07 18:17:53,13 2015-03-07 18:22:53,6 2015-03-07 18:27:53,17 2015-03-07 18:32:53,13 2015-03-07 18:37:53,6 2015-03-07 18:42:53,12 2015-03-07 18:47:53,13 2015-03-07 18:52:53,25 2015-03-07 18:57:53,16 2015-03-07 19:02:53,9 2015-03-07 19:07:53,6 2015-03-07 19:12:53,12 2015-03-07 19:17:53,7 2015-03-07 19:22:53,11 2015-03-07 19:27:53,22 2015-03-07 19:32:53,9 2015-03-07 19:37:53,15 2015-03-07 19:42:53,7 2015-03-07 19:47:53,10 2015-03-07 19:52:53,16 2015-03-07 19:57:53,24 2015-03-07 20:02:53,15 2015-03-07 20:07:53,18 2015-03-07 20:12:53,16 2015-03-07 20:17:53,9 2015-03-07 20:22:53,19 2015-03-07 20:27:53,10 2015-03-07 20:32:53,13 2015-03-07 20:37:53,8 2015-03-07 20:42:53,16 2015-03-07 20:47:53,10 2015-03-07 20:52:53,11 2015-03-07 20:57:53,30 2015-03-07 21:02:53,24 2015-03-07 21:07:53,25 2015-03-07 21:12:53,39 2015-03-07 21:17:53,16 2015-03-07 21:22:53,15 2015-03-07 21:27:53,11 2015-03-07 21:32:53,13 2015-03-07 21:37:53,20 2015-03-07 21:42:53,11 2015-03-07 21:47:53,15 2015-03-07 21:52:53,15 2015-03-07 21:57:53,16 2015-03-07 22:02:53,19 2015-03-07 22:07:53,12 2015-03-07 22:12:53,9 2015-03-07 22:17:53,10 2015-03-07 22:22:53,16 2015-03-07 22:27:53,11 2015-03-07 22:32:53,11 2015-03-07 22:37:53,5 2015-03-07 22:42:53,6 2015-03-07 22:47:53,12 2015-03-07 22:52:53,13 2015-03-07 22:57:53,25 2015-03-07 23:02:53,6 2015-03-07 23:07:53,11 2015-03-07 23:12:53,16 2015-03-07 23:17:53,9 2015-03-07 23:22:53,16 2015-03-07 23:27:53,23 2015-03-07 23:32:53,14 2015-03-07 23:37:53,8 2015-03-07 23:42:53,9 2015-03-07 23:47:53,14 2015-03-07 23:52:53,18 2015-03-07 23:57:53,12 2015-03-08 00:02:53,8 2015-03-08 00:07:53,18 2015-03-08 00:12:53,9 2015-03-08 00:17:53,15 2015-03-08 00:22:53,12 2015-03-08 00:27:53,8 2015-03-08 00:32:53,12 2015-03-08 00:37:53,4 2015-03-08 00:42:53,15 2015-03-08 00:47:53,10 2015-03-08 00:52:53,16 2015-03-08 00:57:53,9 2015-03-08 01:02:53,12 2015-03-08 01:07:53,13 2015-03-08 01:12:53,7 2015-03-08 01:17:53,17 2015-03-08 01:22:53,5 2015-03-08 01:27:53,7 2015-03-08 01:32:53,7 2015-03-08 01:37:53,7 2015-03-08 01:42:53,10 2015-03-08 01:47:53,17 2015-03-08 01:52:53,9 2015-03-08 01:57:53,10 2015-03-08 02:02:53,4 2015-03-08 02:07:53,4 2015-03-08 02:12:53,9 2015-03-08 02:17:53,14 2015-03-08 02:22:53,5 2015-03-08 02:27:53,21 2015-03-08 02:32:53,18 2015-03-08 02:37:53,16 2015-03-08 02:42:53,8 2015-03-08 02:47:53,14 2015-03-08 02:52:53,6 2015-03-08 02:57:53,12 2015-03-08 03:02:53,8 2015-03-08 03:07:53,11 2015-03-08 03:12:53,13 2015-03-08 03:17:53,7 2015-03-08 03:22:53,16 2015-03-08 03:27:53,2 2015-03-08 03:32:53,8 2015-03-08 03:37:53,8 2015-03-08 03:42:53,8 2015-03-08 03:47:53,6 2015-03-08 03:52:53,12 2015-03-08 03:57:53,9 2015-03-08 04:02:53,6 2015-03-08 04:07:53,7 2015-03-08 04:12:53,6 2015-03-08 04:17:53,7 2015-03-08 04:22:53,10 2015-03-08 04:27:53,15 2015-03-08 04:32:53,27 2015-03-08 04:37:53,7 2015-03-08 04:42:53,2 2015-03-08 04:47:53,20 2015-03-08 04:52:53,4 2015-03-08 04:57:53,11 2015-03-08 05:02:53,3 2015-03-08 05:07:53,6 2015-03-08 05:12:53,4 2015-03-08 05:17:53,2 2015-03-08 05:22:53,20 2015-03-08 05:27:53,10 2015-03-08 05:32:53,9 2015-03-08 05:37:53,4 2015-03-08 05:42:53,10 2015-03-08 05:47:53,7 2015-03-08 05:52:53,4 2015-03-08 05:57:53,13 2015-03-08 06:02:53,10 2015-03-08 06:07:53,6 2015-03-08 06:12:53,14 2015-03-08 06:17:53,18 2015-03-08 06:22:53,9 2015-03-08 06:27:53,13 2015-03-08 06:32:53,3 2015-03-08 06:37:53,3 2015-03-08 06:42:53,5 2015-03-08 06:47:53,7 2015-03-08 06:52:53,5 2015-03-08 06:57:53,10 2015-03-08 07:02:53,4 2015-03-08 07:07:53,5 2015-03-08 07:12:53,7 2015-03-08 07:17:53,9 2015-03-08 07:22:53,11 2015-03-08 07:27:53,7 2015-03-08 07:32:53,7 2015-03-08 07:37:53,16 2015-03-08 07:42:53,5 2015-03-08 07:47:53,2 2015-03-08 07:52:53,8 2015-03-08 07:57:53,10 2015-03-08 08:02:53,7 2015-03-08 08:07:53,10 2015-03-08 08:12:53,10 2015-03-08 08:17:53,7 2015-03-08 08:22:53,14 2015-03-08 08:27:53,19 2015-03-08 08:32:53,6 2015-03-08 08:37:53,12 2015-03-08 08:42:53,9 2015-03-08 08:47:53,4 2015-03-08 08:52:53,5 2015-03-08 08:57:53,14 2015-03-08 09:02:53,9 2015-03-08 09:07:53,18 2015-03-08 09:12:53,8 2015-03-08 09:17:53,6 2015-03-08 09:22:53,11 2015-03-08 09:27:53,13 2015-03-08 09:32:53,7 2015-03-08 09:37:53,21 2015-03-08 09:42:53,8 2015-03-08 09:47:53,15 2015-03-08 09:52:53,11 2015-03-08 09:57:53,9 2015-03-08 10:02:53,11 2015-03-08 10:07:53,1 2015-03-08 10:12:53,7 2015-03-08 10:17:53,15 2015-03-08 10:22:53,8 2015-03-08 10:27:53,9 2015-03-08 10:32:53,4 2015-03-08 10:37:53,11 2015-03-08 10:42:53,8 2015-03-08 10:47:53,3 2015-03-08 10:52:53,11 2015-03-08 10:57:53,13 2015-03-08 11:02:53,4 2015-03-08 11:07:53,19 2015-03-08 11:12:53,6 2015-03-08 11:17:53,7 2015-03-08 11:22:53,8 2015-03-08 11:27:53,5 2015-03-08 11:32:53,11 2015-03-08 11:37:53,3 2015-03-08 11:42:53,8 2015-03-08 11:47:53,16 2015-03-08 11:52:53,13 2015-03-08 11:57:53,27 2015-03-08 12:02:53,13 2015-03-08 12:07:53,12 2015-03-08 12:12:53,10 2015-03-08 12:17:53,15 2015-03-08 12:22:53,14 2015-03-08 12:27:53,16 2015-03-08 12:32:53,9 2015-03-08 12:37:53,10 2015-03-08 12:42:53,21 2015-03-08 12:47:53,12 2015-03-08 12:52:53,18 2015-03-08 12:57:53,21 2015-03-08 13:02:53,20 2015-03-08 13:07:53,13 2015-03-08 13:12:53,10 2015-03-08 13:17:53,10 2015-03-08 13:22:53,9 2015-03-08 13:27:53,14 2015-03-08 13:32:53,17 2015-03-08 13:37:53,18 2015-03-08 13:42:53,19 2015-03-08 13:47:53,17 2015-03-08 13:52:53,14 2015-03-08 13:57:53,12 2015-03-08 14:02:53,15 2015-03-08 14:07:53,16 2015-03-08 14:12:53,15 2015-03-08 14:17:53,24 2015-03-08 14:22:53,12 2015-03-08 14:27:53,13 2015-03-08 14:32:53,14 2015-03-08 14:37:53,16 2015-03-08 14:42:53,22 2015-03-08 14:47:53,11 2015-03-08 14:52:53,11 2015-03-08 14:57:53,14 2015-03-08 15:02:53,29 2015-03-08 15:07:53,31 2015-03-08 15:12:53,32 2015-03-08 15:17:53,15 2015-03-08 15:22:53,19 2015-03-08 15:27:53,22 2015-03-08 15:32:53,20 2015-03-08 15:37:53,26 2015-03-08 15:42:53,21 2015-03-08 15:47:53,28 2015-03-08 15:52:53,34 2015-03-08 15:57:53,30 2015-03-08 16:02:53,27 2015-03-08 16:07:53,28 2015-03-08 16:12:53,36 2015-03-08 16:17:53,15 2015-03-08 16:22:53,7 2015-03-08 16:27:53,20 2015-03-08 16:32:53,19 2015-03-08 16:37:53,9 2015-03-08 16:42:53,19 2015-03-08 16:47:53,13 2015-03-08 16:52:53,13 2015-03-08 16:57:53,21 2015-03-08 17:02:53,35 2015-03-08 17:07:53,152 2015-03-08 17:12:53,57 2015-03-08 17:17:53,57 2015-03-08 17:22:53,56 2015-03-08 17:27:53,49 2015-03-08 17:32:53,43 2015-03-08 17:37:53,34 2015-03-08 17:42:53,25 2015-03-08 17:47:53,32 2015-03-08 17:52:53,46 2015-03-08 17:57:53,35 2015-03-08 18:02:53,38 2015-03-08 18:07:53,42 2015-03-08 18:12:53,55 2015-03-08 18:17:53,49 2015-03-08 18:22:53,38 2015-03-08 18:27:53,32 2015-03-08 18:32:53,33 2015-03-08 18:37:53,32 2015-03-08 18:42:53,15 2015-03-08 18:47:53,27 2015-03-08 18:52:53,23 2015-03-08 18:57:53,25 2015-03-08 19:02:53,22 2015-03-08 19:07:53,21 2015-03-08 19:12:53,35 2015-03-08 19:17:53,49 2015-03-08 19:22:53,25 2015-03-08 19:27:53,27 2015-03-08 19:32:53,14 2015-03-08 19:37:53,18 2015-03-08 19:42:53,18 2015-03-08 19:47:53,12 2015-03-08 19:52:53,35 2015-03-08 19:57:53,42 2015-03-08 20:02:53,37 2015-03-08 20:07:53,20 2015-03-08 20:12:53,48 2015-03-08 20:17:53,73 2015-03-08 20:22:53,53 2015-03-08 20:27:53,31 2015-03-08 20:32:53,37 2015-03-08 20:37:53,28 2015-03-08 20:42:53,39 2015-03-08 20:47:53,26 2015-03-08 20:52:53,22 2015-03-08 20:57:53,23 2015-03-08 21:02:53,20 2015-03-08 21:07:53,23 2015-03-08 21:12:53,26 2015-03-08 21:17:53,28 2015-03-08 21:22:53,25 2015-03-08 21:27:53,23 2015-03-08 21:32:53,20 2015-03-08 21:37:53,17 2015-03-08 21:42:53,19 2015-03-08 21:47:53,23 2015-03-08 21:52:53,11 2015-03-08 21:57:53,14 2015-03-08 22:02:53,25 2015-03-08 22:07:53,14 2015-03-08 22:12:53,18 2015-03-08 22:17:53,16 2015-03-08 22:22:53,18 2015-03-08 22:27:53,12 2015-03-08 22:32:53,14 2015-03-08 22:37:53,13 2015-03-08 22:42:53,14 2015-03-08 22:47:53,13 2015-03-08 22:52:53,12 2015-03-08 22:57:53,12 2015-03-08 23:02:53,10 2015-03-08 23:07:53,7 2015-03-08 23:12:53,19 2015-03-08 23:17:53,14 2015-03-08 23:22:53,12 2015-03-08 23:27:53,6 2015-03-08 23:32:53,10 2015-03-08 23:37:53,7 2015-03-08 23:42:53,10 2015-03-08 23:47:53,12 2015-03-08 23:52:53,17 2015-03-08 23:57:53,13 2015-03-09 00:02:53,15 2015-03-09 00:07:53,9 2015-03-09 00:12:53,5 2015-03-09 00:17:53,4 2015-03-09 00:22:53,23 2015-03-09 00:27:53,7 2015-03-09 00:32:53,15 2015-03-09 00:37:53,11 2015-03-09 00:42:53,8 2015-03-09 00:47:53,8 2015-03-09 00:52:53,13 2015-03-09 00:57:53,13 2015-03-09 01:02:53,2 2015-03-09 01:07:53,12 2015-03-09 01:12:53,11 2015-03-09 01:17:53,8 2015-03-09 01:22:53,12 2015-03-09 01:27:53,11 2015-03-09 01:32:53,12 2015-03-09 01:37:53,79 2015-03-09 01:42:53,42 2015-03-09 01:47:53,31 2015-03-09 01:52:53,31 2015-03-09 01:57:53,25 2015-03-09 02:02:53,20 2015-03-09 02:07:53,17 2015-03-09 02:12:53,17 2015-03-09 02:17:53,13 2015-03-09 02:22:53,11 2015-03-09 02:27:53,15 2015-03-09 02:32:53,24 2015-03-09 02:37:53,22 2015-03-09 02:42:53,23 2015-03-09 02:47:53,26 2015-03-09 02:52:53,11 2015-03-09 02:57:53,16 2015-03-09 03:02:53,22 2015-03-09 03:07:53,13 2015-03-09 03:12:53,12 2015-03-09 03:17:53,14 2015-03-09 03:22:53,17 2015-03-09 03:27:53,8 2015-03-09 03:32:53,8 2015-03-09 03:37:53,11 2015-03-09 03:42:53,14 2015-03-09 03:47:53,13 2015-03-09 03:52:53,15 2015-03-09 03:57:53,10 2015-03-09 04:02:53,23 2015-03-09 04:07:53,21 2015-03-09 04:12:53,5 2015-03-09 04:17:53,15 2015-03-09 04:22:53,18 2015-03-09 04:27:53,15 2015-03-09 04:32:53,9 2015-03-09 04:37:53,10 2015-03-09 04:42:53,8 2015-03-09 04:47:53,9 2015-03-09 04:52:53,14 2015-03-09 04:57:53,17 2015-03-09 05:02:53,6 2015-03-09 05:07:53,13 2015-03-09 05:12:53,17 2015-03-09 05:17:53,14 2015-03-09 05:22:53,12 2015-03-09 05:27:53,7 2015-03-09 05:32:53,4 2015-03-09 05:37:53,12 2015-03-09 05:42:53,9 2015-03-09 05:47:53,9 2015-03-09 05:52:53,5 2015-03-09 05:57:53,10 2015-03-09 06:02:53,8 2015-03-09 06:07:53,12 2015-03-09 06:12:53,22 2015-03-09 06:17:53,4 2015-03-09 06:22:53,18 2015-03-09 06:27:53,28 2015-03-09 06:32:53,57 2015-03-09 06:37:53,14 2015-03-09 06:42:53,16 2015-03-09 06:47:53,10 2015-03-09 06:52:53,15 2015-03-09 06:57:53,15 2015-03-09 07:02:53,20 2015-03-09 07:07:53,14 2015-03-09 07:12:53,17 2015-03-09 07:17:53,16 2015-03-09 07:22:53,6 2015-03-09 07:27:53,8 2015-03-09 07:32:53,11 2015-03-09 07:37:53,11 2015-03-09 07:42:53,14 2015-03-09 07:47:53,19 2015-03-09 07:52:53,6 2015-03-09 07:57:53,9 2015-03-09 08:02:53,12 2015-03-09 08:07:53,13 2015-03-09 08:12:53,11 2015-03-09 08:17:53,10 2015-03-09 08:22:53,10 2015-03-09 08:27:53,9 2015-03-09 08:32:53,4 2015-03-09 08:37:53,7 2015-03-09 08:42:53,13 2015-03-09 08:47:53,15 2015-03-09 08:52:53,8 2015-03-09 08:57:53,15 2015-03-09 09:02:53,14 2015-03-09 09:07:53,13 2015-03-09 09:12:53,7 2015-03-09 09:17:53,5 2015-03-09 09:22:53,14 2015-03-09 09:27:53,9 2015-03-09 09:32:53,9 2015-03-09 09:37:53,12 2015-03-09 09:42:53,7 2015-03-09 09:47:53,12 2015-03-09 09:52:53,12 2015-03-09 09:57:53,10 2015-03-09 10:02:53,4 2015-03-09 10:07:53,13 2015-03-09 10:12:53,19 2015-03-09 10:17:53,13 2015-03-09 10:22:53,10 2015-03-09 10:27:53,12 2015-03-09 10:32:53,10 2015-03-09 10:37:53,18 2015-03-09 10:42:53,18 2015-03-09 10:47:53,17 2015-03-09 10:52:53,13 2015-03-09 10:57:53,82 2015-03-09 11:02:53,11 2015-03-09 11:07:53,6 2015-03-09 11:12:53,10 2015-03-09 11:17:53,13 2015-03-09 11:22:53,10 2015-03-09 11:27:53,11 2015-03-09 11:32:53,13 2015-03-09 11:37:53,16 2015-03-09 11:42:53,19 2015-03-09 11:47:53,18 2015-03-09 11:52:53,36 2015-03-09 11:57:53,19 2015-03-09 12:02:53,15 2015-03-09 12:07:53,9 2015-03-09 12:12:53,22 2015-03-09 12:17:53,16 2015-03-09 12:22:53,16 2015-03-09 12:27:53,11 2015-03-09 12:32:53,13 2015-03-09 12:37:53,10 2015-03-09 12:42:53,19 2015-03-09 12:47:53,22 2015-03-09 12:52:53,15 2015-03-09 12:57:53,24 2015-03-09 13:02:53,17 2015-03-09 13:07:53,33 2015-03-09 13:12:53,20 2015-03-09 13:17:53,17 2015-03-09 13:22:53,15 2015-03-09 13:27:53,28 2015-03-09 13:32:53,20 2015-03-09 13:37:53,33 2015-03-09 13:42:53,18 2015-03-09 13:47:53,29 2015-03-09 13:52:53,20 2015-03-09 13:57:53,27 2015-03-09 14:02:53,21 2015-03-09 14:07:53,17 2015-03-09 14:12:53,20 2015-03-09 14:17:53,14 2015-03-09 14:22:53,14 2015-03-09 14:27:53,23 2015-03-09 14:32:53,21 2015-03-09 14:37:53,39 2015-03-09 14:42:53,40 2015-03-09 14:47:53,19 2015-03-09 14:52:53,21 2015-03-09 14:57:53,14 2015-03-09 15:02:53,20 2015-03-09 15:07:53,23 2015-03-09 15:12:53,32 2015-03-09 15:17:53,26 2015-03-09 15:22:53,21 2015-03-09 15:27:53,14 2015-03-09 15:32:53,26 2015-03-09 15:37:53,25 2015-03-09 15:42:53,30 2015-03-09 15:47:53,15 2015-03-09 15:52:53,20 2015-03-09 15:57:53,21 2015-03-09 16:02:53,24 2015-03-09 16:07:53,26 2015-03-09 16:12:53,28 2015-03-09 16:17:53,33 2015-03-09 16:22:53,33 2015-03-09 16:27:53,44 2015-03-09 16:32:53,39 2015-03-09 16:37:53,33 2015-03-09 16:42:53,39 2015-03-09 16:47:53,35 2015-03-09 16:52:53,20 2015-03-09 16:57:53,21 2015-03-09 17:02:53,18 2015-03-09 17:07:53,29 2015-03-09 17:12:53,30 2015-03-09 17:17:53,18 2015-03-09 17:22:53,27 2015-03-09 17:27:53,33 2015-03-09 17:32:53,25 2015-03-09 17:37:53,27 2015-03-09 17:42:53,26 2015-03-09 17:47:53,23 2015-03-09 17:52:53,32 2015-03-09 17:57:53,38 2015-03-09 18:02:53,22 2015-03-09 18:07:53,19 2015-03-09 18:12:53,20 2015-03-09 18:17:53,24 2015-03-09 18:22:53,31 2015-03-09 18:27:53,25 2015-03-09 18:32:53,27 2015-03-09 18:37:53,25 2015-03-09 18:42:53,35 2015-03-09 18:47:53,21 2015-03-09 18:52:53,24 2015-03-09 18:57:53,26 2015-03-09 19:02:53,22 2015-03-09 19:07:53,18 2015-03-09 19:12:53,26 2015-03-09 19:17:53,22 2015-03-09 19:22:53,20 2015-03-09 19:27:53,28 2015-03-09 19:32:53,30 2015-03-09 19:37:53,35 2015-03-09 19:42:53,39 2015-03-09 19:47:53,16 2015-03-09 19:52:53,12 2015-03-09 19:57:53,29 2015-03-09 20:02:53,20 2015-03-09 20:07:53,19 2015-03-09 20:12:53,26 2015-03-09 20:17:53,21 2015-03-09 20:22:53,29 2015-03-09 20:27:53,23 2015-03-09 20:32:53,19 2015-03-09 20:37:53,23 2015-03-09 20:42:53,25 2015-03-09 20:47:53,24 2015-03-09 20:52:53,11 2015-03-09 20:57:53,34 2015-03-09 21:02:53,26 2015-03-09 21:07:53,23 2015-03-09 21:12:53,12 2015-03-09 21:17:53,20 2015-03-09 21:22:53,22 2015-03-09 21:27:53,14 2015-03-09 21:32:53,9 2015-03-09 21:37:53,7 2015-03-09 21:42:53,20 2015-03-09 21:47:53,19 2015-03-09 21:52:53,19 2015-03-09 21:57:53,19 2015-03-09 22:02:53,18 2015-03-09 22:07:53,18 2015-03-09 22:12:53,13 2015-03-09 22:17:53,20 2015-03-09 22:22:53,16 2015-03-09 22:27:53,23 2015-03-09 22:32:53,14 2015-03-09 22:37:53,13 2015-03-09 22:42:53,17 2015-03-09 22:47:53,29 2015-03-09 22:52:53,37 2015-03-09 22:57:53,17 2015-03-09 23:02:53,22 2015-03-09 23:07:53,30 2015-03-09 23:12:53,20 2015-03-09 23:17:53,47 2015-03-09 23:22:53,23 2015-03-09 23:27:53,23 2015-03-09 23:32:53,18 2015-03-09 23:37:53,24 2015-03-09 23:42:53,20 2015-03-09 23:47:53,10 2015-03-09 23:52:53,15 2015-03-09 23:57:53,22 2015-03-10 00:02:53,14 2015-03-10 00:07:53,14 2015-03-10 00:12:53,7 2015-03-10 00:17:53,25 2015-03-10 00:22:53,18 2015-03-10 00:27:53,11 2015-03-10 00:32:53,11 2015-03-10 00:37:53,18 2015-03-10 00:42:53,14 2015-03-10 00:47:53,16 2015-03-10 00:52:53,21 2015-03-10 00:57:53,13 2015-03-10 01:02:53,11 2015-03-10 01:07:53,10 2015-03-10 01:12:53,11 2015-03-10 01:17:53,19 2015-03-10 01:22:53,9 2015-03-10 01:27:53,16 2015-03-10 01:32:53,7 2015-03-10 01:37:53,17 2015-03-10 01:42:53,29 2015-03-10 01:47:53,11 2015-03-10 01:52:53,15 2015-03-10 01:57:53,9 2015-03-10 02:02:53,15 2015-03-10 02:07:53,11 2015-03-10 02:12:53,25 2015-03-10 02:17:53,25 2015-03-10 02:22:53,23 2015-03-10 02:27:53,21 2015-03-10 02:32:53,20 2015-03-10 02:37:53,21 2015-03-10 02:42:53,14 2015-03-10 02:47:53,11 2015-03-10 02:52:53,11 2015-03-10 02:57:53,11 2015-03-10 03:02:53,17 2015-03-10 03:07:53,13 2015-03-10 03:12:53,13 2015-03-10 03:17:53,13 2015-03-10 03:22:53,20 2015-03-10 03:27:53,8 2015-03-10 03:32:53,10 2015-03-10 03:37:53,13 2015-03-10 03:42:53,9 2015-03-10 03:47:53,10 2015-03-10 03:52:53,15 2015-03-10 03:57:53,5 2015-03-10 04:02:53,5 2015-03-10 04:07:53,5 2015-03-10 04:12:53,9 2015-03-10 04:17:53,14 2015-03-10 04:22:53,18 2015-03-10 04:27:53,15 2015-03-10 04:32:53,10 2015-03-10 04:37:53,9 2015-03-10 04:42:53,32 2015-03-10 04:47:53,34 2015-03-10 04:52:53,25 2015-03-10 04:57:53,20 2015-03-10 05:02:53,13 2015-03-10 05:07:53,15 2015-03-10 05:12:53,7 2015-03-10 05:17:53,7 2015-03-10 05:22:53,12 2015-03-10 05:27:53,16 2015-03-10 05:32:53,10 2015-03-10 05:37:53,28 2015-03-10 05:42:53,12 2015-03-10 05:47:53,7 2015-03-10 05:52:53,5 2015-03-10 05:57:53,18 2015-03-10 06:02:53,15 2015-03-10 06:07:53,13 2015-03-10 06:12:53,15 2015-03-10 06:17:53,8 2015-03-10 06:22:53,13 2015-03-10 06:27:53,12 2015-03-10 06:32:53,9 2015-03-10 06:37:53,8 2015-03-10 06:42:53,14 2015-03-10 06:47:53,20 2015-03-10 06:52:53,12 2015-03-10 06:57:53,12 2015-03-10 07:02:53,12 2015-03-10 07:07:53,3 2015-03-10 07:12:53,21 2015-03-10 07:17:53,11 2015-03-10 07:22:53,15 2015-03-10 07:27:53,7 2015-03-10 07:32:53,9 2015-03-10 07:37:53,15 2015-03-10 07:42:53,14 2015-03-10 07:47:53,11 2015-03-10 07:52:53,10 2015-03-10 07:57:53,15 2015-03-10 08:02:53,9 2015-03-10 08:07:53,17 2015-03-10 08:12:53,10 2015-03-10 08:17:53,9 2015-03-10 08:22:53,12 2015-03-10 08:27:53,8 2015-03-10 08:32:53,17 2015-03-10 08:37:53,13 2015-03-10 08:42:53,11 2015-03-10 08:47:53,10 2015-03-10 08:52:53,10 2015-03-10 08:57:53,19 2015-03-10 09:02:53,29 2015-03-10 09:07:53,13 2015-03-10 09:12:53,28 2015-03-10 09:17:53,19 2015-03-10 09:22:53,15 2015-03-10 09:27:53,6 2015-03-10 09:32:53,15 2015-03-10 09:37:53,17 2015-03-10 09:42:53,13 2015-03-10 09:47:53,5 2015-03-10 09:52:53,10 2015-03-10 09:57:53,17 2015-03-10 10:02:53,16 2015-03-10 10:07:53,18 2015-03-10 10:12:53,9 2015-03-10 10:17:53,13 2015-03-10 10:22:53,10 2015-03-10 10:27:53,11 2015-03-10 10:32:53,11 2015-03-10 10:37:53,16 2015-03-10 10:42:53,11 2015-03-10 10:47:53,2 2015-03-10 10:52:53,11 2015-03-10 10:57:53,13 2015-03-10 11:02:53,13 2015-03-10 11:07:53,8 2015-03-10 11:12:53,22 2015-03-10 11:17:53,14 2015-03-10 11:22:53,15 2015-03-10 11:27:53,20 2015-03-10 11:32:53,16 2015-03-10 11:37:53,14 2015-03-10 11:42:53,22 2015-03-10 11:47:53,10 2015-03-10 11:52:53,12 2015-03-10 11:57:53,23 2015-03-10 12:02:53,14 2015-03-10 12:07:53,9 2015-03-10 12:12:53,17 2015-03-10 12:17:53,10 2015-03-10 12:22:53,22 2015-03-10 12:27:53,14 2015-03-10 12:32:53,17 2015-03-10 12:37:53,10 2015-03-10 12:42:53,16 2015-03-10 12:47:53,32 2015-03-10 12:52:53,18 2015-03-10 12:57:53,20 2015-03-10 13:02:53,21 2015-03-10 13:07:53,23 2015-03-10 13:12:53,22 2015-03-10 13:17:53,11 2015-03-10 13:22:53,26 2015-03-10 13:27:53,23 2015-03-10 13:32:53,17 2015-03-10 13:37:53,11 2015-03-10 13:42:53,10 2015-03-10 13:47:53,9 2015-03-10 13:52:53,21 2015-03-10 13:57:53,28 2015-03-10 14:02:53,24 2015-03-10 14:07:53,21 2015-03-10 14:12:53,26 2015-03-10 14:17:53,24 2015-03-10 14:22:53,34 2015-03-10 14:27:53,20 2015-03-10 14:32:53,17 2015-03-10 14:37:53,20 2015-03-10 14:42:53,22 2015-03-10 14:47:53,36 2015-03-10 14:52:53,22 2015-03-10 14:57:53,28 2015-03-10 15:02:53,27 2015-03-10 15:07:53,16 2015-03-10 15:12:53,17 2015-03-10 15:17:53,19 2015-03-10 15:22:53,15 2015-03-10 15:27:53,17 2015-03-10 15:32:53,21 2015-03-10 15:37:53,27 2015-03-10 15:42:53,37 2015-03-10 15:47:53,23 2015-03-10 15:52:53,22 2015-03-10 15:57:53,21 2015-03-10 16:02:53,33 2015-03-10 16:07:53,24 2015-03-10 16:12:53,25 2015-03-10 16:17:53,15 2015-03-10 16:22:53,23 2015-03-10 16:27:53,28 2015-03-10 16:32:53,29 2015-03-10 16:37:53,33 2015-03-10 16:42:53,19 2015-03-10 16:47:53,22 2015-03-10 16:52:53,12 2015-03-10 16:57:53,25 2015-03-10 17:02:53,25 2015-03-10 17:07:53,41 2015-03-10 17:12:53,27 2015-03-10 17:17:53,23 2015-03-10 17:22:53,14 2015-03-10 17:27:53,35 2015-03-10 17:32:53,38 2015-03-10 17:37:53,26 2015-03-10 17:42:53,36 2015-03-10 17:47:53,30 2015-03-10 17:52:53,15 2015-03-10 17:57:53,20 2015-03-10 18:02:53,23 2015-03-10 18:07:53,29 2015-03-10 18:12:53,26 2015-03-10 18:17:53,23 2015-03-10 18:22:53,29 2015-03-10 18:27:53,31 2015-03-10 18:32:53,36 2015-03-10 18:37:53,13 2015-03-10 18:42:53,20 2015-03-10 18:47:53,29 2015-03-10 18:52:53,27 2015-03-10 18:57:53,38 2015-03-10 19:02:53,16 2015-03-10 19:07:53,30 2015-03-10 19:12:53,32 2015-03-10 19:17:53,22 2015-03-10 19:22:53,17 2015-03-10 19:27:53,16 2015-03-10 19:32:53,20 2015-03-10 19:37:53,19 2015-03-10 19:42:53,17 2015-03-10 19:47:53,46 2015-03-10 19:52:53,17 2015-03-10 19:57:53,32 2015-03-10 20:02:53,18 2015-03-10 20:07:53,17 2015-03-10 20:12:53,18 2015-03-10 20:17:53,17 2015-03-10 20:22:53,17 2015-03-10 20:27:53,29 2015-03-10 20:32:53,29 2015-03-10 20:37:53,38 2015-03-10 20:42:53,30 2015-03-10 20:47:53,26 2015-03-10 20:52:53,19 2015-03-10 20:57:53,27 2015-03-10 21:02:53,20 2015-03-10 21:07:53,23 2015-03-10 21:12:53,14 2015-03-10 21:17:53,23 2015-03-10 21:22:53,29 2015-03-10 21:27:53,38 2015-03-10 21:32:53,24 2015-03-10 21:37:53,33 2015-03-10 21:42:53,48 2015-03-10 21:47:53,18 2015-03-10 21:52:53,23 2015-03-10 21:57:53,27 2015-03-10 22:02:53,28 2015-03-10 22:07:53,25 2015-03-10 22:12:53,20 2015-03-10 22:17:53,40 2015-03-10 22:22:53,26 2015-03-10 22:27:53,17 2015-03-10 22:32:53,23 2015-03-10 22:37:53,15 2015-03-10 22:42:53,23 2015-03-10 22:47:53,21 2015-03-10 22:52:53,16 2015-03-10 22:57:53,18 2015-03-10 23:02:53,22 2015-03-10 23:07:53,15 2015-03-10 23:12:53,17 2015-03-10 23:17:53,19 2015-03-10 23:22:53,29 2015-03-10 23:27:53,21 2015-03-10 23:32:53,18 2015-03-10 23:37:53,15 2015-03-10 23:42:53,12 2015-03-10 23:47:53,15 2015-03-10 23:52:53,15 2015-03-10 23:57:53,22 2015-03-11 00:02:53,14 2015-03-11 00:07:53,10 2015-03-11 00:12:53,21 2015-03-11 00:17:53,19 2015-03-11 00:22:53,9 2015-03-11 00:27:53,16 2015-03-11 00:32:53,17 2015-03-11 00:37:53,15 2015-03-11 00:42:53,19 2015-03-11 00:47:53,12 2015-03-11 00:52:53,13 2015-03-11 00:57:53,10 2015-03-11 01:02:53,19 2015-03-11 01:07:53,10 2015-03-11 01:12:53,16 2015-03-11 01:17:53,17 2015-03-11 01:22:53,13 2015-03-11 01:27:53,23 2015-03-11 01:32:53,7 2015-03-11 01:37:53,14 2015-03-11 01:42:53,16 2015-03-11 01:47:53,15 2015-03-11 01:52:53,18 2015-03-11 01:57:53,17 2015-03-11 02:02:53,16 2015-03-11 02:07:53,5 2015-03-11 02:12:53,11 2015-03-11 02:17:53,17 2015-03-11 02:22:53,5 2015-03-11 02:27:53,16 2015-03-11 02:32:53,13 2015-03-11 02:37:53,17 2015-03-11 02:42:53,23 2015-03-11 02:47:53,11 2015-03-11 02:52:53,12 2015-03-11 02:57:53,22 2015-03-11 03:02:53,18 2015-03-11 03:07:53,8 2015-03-11 03:12:53,9 2015-03-11 03:17:53,12 2015-03-11 03:22:53,12 2015-03-11 03:27:53,10 2015-03-11 03:32:53,22 2015-03-11 03:37:53,21 2015-03-11 03:42:53,22 2015-03-11 03:47:53,17 2015-03-11 03:52:53,14 2015-03-11 03:57:53,9 2015-03-11 04:02:53,4 2015-03-11 04:07:53,9 2015-03-11 04:12:53,9 2015-03-11 04:17:53,14 2015-03-11 04:22:53,17 2015-03-11 04:27:53,8 2015-03-11 04:32:53,13 2015-03-11 04:37:53,11 2015-03-11 04:42:53,11 2015-03-11 04:47:53,12 2015-03-11 04:52:53,6 2015-03-11 04:57:53,18 2015-03-11 05:02:53,8 2015-03-11 05:07:53,12 2015-03-11 05:12:53,13 2015-03-11 05:17:53,24 2015-03-11 05:22:53,5 2015-03-11 05:27:53,5 2015-03-11 05:32:53,8 2015-03-11 05:37:53,12 2015-03-11 05:42:53,14 2015-03-11 05:47:53,6 2015-03-11 05:52:53,5 2015-03-11 05:57:53,13 2015-03-11 06:02:53,13 2015-03-11 06:07:53,5 2015-03-11 06:12:53,5 2015-03-11 06:17:53,7 2015-03-11 06:22:53,12 2015-03-11 06:27:53,3 2015-03-11 06:32:53,10 2015-03-11 06:37:53,21 2015-03-11 06:42:53,13 2015-03-11 06:47:53,10 2015-03-11 06:52:53,4 2015-03-11 06:57:53,4 2015-03-11 07:02:53,0 2015-03-11 07:07:53,0 2015-03-11 07:12:53,0 2015-03-11 07:17:53,0 2015-03-11 07:22:53,0 2015-03-11 07:27:53,0 2015-03-11 07:32:53,0 2015-03-11 07:37:53,0 2015-03-11 07:42:53,0 2015-03-11 07:47:53,0 2015-03-11 07:52:53,0 2015-03-11 07:57:53,0 2015-03-11 08:02:53,0 2015-03-11 08:07:53,0 2015-03-11 08:12:53,0 2015-03-11 08:17:53,0 2015-03-11 08:22:53,0 2015-03-11 08:27:53,0 2015-03-11 08:32:53,0 2015-03-11 08:37:53,0 2015-03-11 08:42:53,0 2015-03-11 08:47:53,0 2015-03-11 08:52:53,0 2015-03-11 08:57:53,0 2015-03-11 09:02:53,0 2015-03-11 09:07:53,0 2015-03-11 09:12:53,10 2015-03-11 09:17:53,13 2015-03-11 09:22:53,16 2015-03-11 09:27:53,11 2015-03-11 09:32:53,9 2015-03-11 09:37:53,15 2015-03-11 09:42:53,10 2015-03-11 09:47:53,11 2015-03-11 09:52:53,15 2015-03-11 09:57:53,10 2015-03-11 10:02:53,18 2015-03-11 10:07:53,13 2015-03-11 10:12:53,20 2015-03-11 10:17:53,23 2015-03-11 10:22:53,15 2015-03-11 10:27:53,24 2015-03-11 10:32:53,21 2015-03-11 10:37:53,20 2015-03-11 10:42:53,26 2015-03-11 10:47:53,12 2015-03-11 10:52:53,17 2015-03-11 10:57:53,18 2015-03-11 11:02:53,30 2015-03-11 11:07:53,29 2015-03-11 11:12:53,17 2015-03-11 11:17:53,17 2015-03-11 11:22:53,25 2015-03-11 11:27:53,33 2015-03-11 11:32:53,18 2015-03-11 11:37:53,28 2015-03-11 11:42:53,18 2015-03-11 11:47:53,19 2015-03-11 11:52:53,16 2015-03-11 11:57:53,27 2015-03-11 12:02:53,19 2015-03-11 12:07:53,22 2015-03-11 12:12:53,23 2015-03-11 12:17:53,22 2015-03-11 12:22:53,14 2015-03-11 12:27:53,35 2015-03-11 12:32:53,21 2015-03-11 12:37:53,22 2015-03-11 12:42:53,23 2015-03-11 12:47:53,19 2015-03-11 12:52:53,24 2015-03-11 12:57:53,24 2015-03-11 13:02:53,27 2015-03-11 13:07:53,27 2015-03-11 13:12:53,31 2015-03-11 13:17:53,18 2015-03-11 13:22:53,15 2015-03-11 13:27:53,122 2015-03-11 13:32:53,74 2015-03-11 13:37:53,59 2015-03-11 13:42:53,41 2015-03-11 13:47:53,42 2015-03-11 13:52:53,40 2015-03-11 13:57:53,44 2015-03-11 14:02:53,44 2015-03-11 14:07:53,29 2015-03-11 14:12:53,47 2015-03-11 14:17:53,32 2015-03-11 14:22:53,35 2015-03-11 14:27:53,36 2015-03-11 14:32:53,30 2015-03-11 14:37:53,28 2015-03-11 14:42:53,20 2015-03-11 14:47:53,18 2015-03-11 14:52:53,27 2015-03-11 14:57:53,25 2015-03-11 15:02:53,33 2015-03-11 15:07:53,24 2015-03-11 15:12:53,32 2015-03-11 15:17:53,30 2015-03-11 15:22:53,16 2015-03-11 15:27:53,28 2015-03-11 15:32:53,23 2015-03-11 15:37:53,28 2015-03-11 15:42:53,29 2015-03-11 15:47:53,35 2015-03-11 15:52:53,29 2015-03-11 15:57:53,38 2015-03-11 16:02:53,37 2015-03-11 16:07:53,31 2015-03-11 16:12:53,29 2015-03-11 16:17:53,17 2015-03-11 16:22:53,31 2015-03-11 16:27:53,30 2015-03-11 16:32:53,34 2015-03-11 16:37:53,34 2015-03-11 16:42:53,23 2015-03-11 16:47:53,23 2015-03-11 16:52:53,39 2015-03-11 16:57:53,29 2015-03-11 17:02:53,29 2015-03-11 17:07:53,27 2015-03-11 17:12:53,31 2015-03-11 17:17:53,28 2015-03-11 17:22:53,12 2015-03-11 17:27:53,37 2015-03-11 17:32:53,27 2015-03-11 17:37:53,40 2015-03-11 17:42:53,30 2015-03-11 17:47:53,50 2015-03-11 17:52:53,56 2015-03-11 17:57:53,64 2015-03-11 18:02:53,49 2015-03-11 18:07:53,59 2015-03-11 18:12:53,48 2015-03-11 18:17:53,34 2015-03-11 18:22:53,29 2015-03-11 18:27:53,30 2015-03-11 18:32:53,39 2015-03-11 18:37:53,89 2015-03-11 18:42:53,56 2015-03-11 18:47:53,42 2015-03-11 18:52:53,46 2015-03-11 18:57:53,47 2015-03-11 19:02:53,36 2015-03-11 19:07:53,35 2015-03-11 19:12:53,20 2015-03-11 19:17:53,19 2015-03-11 19:22:53,29 2015-03-11 19:27:53,29 2015-03-11 19:32:53,36 2015-03-11 19:37:53,22 2015-03-11 19:42:53,54 2015-03-11 19:47:53,41 2015-03-11 19:52:53,30 2015-03-11 19:57:53,36 2015-03-11 20:02:53,40 2015-03-11 20:07:53,43 2015-03-11 20:12:53,28 2015-03-11 20:17:53,43 2015-03-11 20:22:53,24 2015-03-11 20:27:53,27 2015-03-11 20:32:53,28 2015-03-11 20:37:53,19 2015-03-11 20:42:53,39 2015-03-11 20:47:53,56 2015-03-11 20:52:53,36 2015-03-11 20:57:53,36 2015-03-11 21:02:53,28 2015-03-11 21:07:53,33 2015-03-11 21:12:53,34 2015-03-11 21:17:53,23 2015-03-11 21:22:53,16 2015-03-11 21:27:53,27 2015-03-11 21:32:53,24 2015-03-11 21:37:53,27 2015-03-11 21:42:53,23 2015-03-11 21:47:53,24 2015-03-11 21:52:53,18 2015-03-11 21:57:53,39 2015-03-11 22:02:53,18 2015-03-11 22:07:53,12 2015-03-11 22:12:53,24 2015-03-11 22:17:53,39 2015-03-11 22:22:53,34 2015-03-11 22:27:53,32 2015-03-11 22:32:53,32 2015-03-11 22:37:53,18 2015-03-11 22:42:53,22 2015-03-11 22:47:53,17 2015-03-11 22:52:53,21 2015-03-11 22:57:53,27 2015-03-11 23:02:53,21 2015-03-11 23:07:53,22 2015-03-11 23:12:53,12 2015-03-11 23:17:53,22 2015-03-11 23:22:53,11 2015-03-11 23:27:53,17 2015-03-11 23:32:53,20 2015-03-11 23:37:53,16 2015-03-11 23:42:53,17 2015-03-11 23:47:53,13 2015-03-11 23:52:53,16 2015-03-11 23:57:53,50 2015-03-12 00:02:53,21 2015-03-12 00:07:53,29 2015-03-12 00:12:53,31 2015-03-12 00:17:53,25 2015-03-12 00:22:53,19 2015-03-12 00:27:53,17 2015-03-12 00:32:53,15 2015-03-12 00:37:53,22 2015-03-12 00:42:53,15 2015-03-12 00:47:53,9 2015-03-12 00:52:53,15 2015-03-12 00:57:53,21 2015-03-12 01:02:53,22 2015-03-12 01:07:53,7 2015-03-12 01:12:53,21 2015-03-12 01:17:53,18 2015-03-12 01:22:53,17 2015-03-12 01:27:53,15 2015-03-12 01:32:53,14 2015-03-12 01:37:53,15 2015-03-12 01:42:53,13 2015-03-12 01:47:53,12 2015-03-12 01:52:53,28 2015-03-12 01:57:53,24 2015-03-12 02:02:53,8 2015-03-12 02:07:53,15 2015-03-12 02:12:53,12 2015-03-12 02:17:53,16 2015-03-12 02:22:53,18 2015-03-12 02:27:53,18 2015-03-12 02:32:53,9 2015-03-12 02:37:53,10 2015-03-12 02:42:53,23 2015-03-12 02:47:53,14 2015-03-12 02:52:53,19 2015-03-12 02:57:53,14 2015-03-12 03:02:53,17 2015-03-12 03:07:53,13 2015-03-12 03:12:53,3 2015-03-12 03:17:53,6 2015-03-12 03:22:53,19 2015-03-12 03:27:53,9 2015-03-12 03:32:53,6 2015-03-12 03:37:53,11 2015-03-12 03:42:53,14 2015-03-12 03:47:53,14 2015-03-12 03:52:53,11 2015-03-12 03:57:53,16 2015-03-12 04:02:53,14 2015-03-12 04:07:53,14 2015-03-12 04:12:53,22 2015-03-12 04:17:53,7 2015-03-12 04:22:53,21 2015-03-12 04:27:53,17 2015-03-12 04:32:53,7 2015-03-12 04:37:53,7 2015-03-12 04:42:53,9 2015-03-12 04:47:53,15 2015-03-12 04:52:53,10 2015-03-12 04:57:53,21 2015-03-12 05:02:53,11 2015-03-12 05:07:53,7 2015-03-12 05:12:53,6 2015-03-12 05:17:53,15 2015-03-12 05:22:53,8 2015-03-12 05:27:53,1 2015-03-12 05:32:53,0 2015-03-12 05:37:53,2 2015-03-12 05:42:53,13 2015-03-12 05:47:53,7 2015-03-12 05:52:53,6 2015-03-12 05:57:53,16 2015-03-12 06:02:53,9 2015-03-12 06:07:53,21 2015-03-12 06:12:53,12 2015-03-12 06:17:53,13 2015-03-12 06:22:53,4 2015-03-12 06:27:53,12 2015-03-12 06:32:53,9 2015-03-12 06:37:53,15 2015-03-12 06:42:53,8 2015-03-12 06:47:53,15 2015-03-12 06:52:53,13 2015-03-12 06:57:53,14 2015-03-12 07:02:53,9 2015-03-12 07:07:53,15 2015-03-12 07:12:53,10 2015-03-12 07:17:53,8 2015-03-12 07:22:53,8 2015-03-12 07:27:53,20 2015-03-12 07:32:53,21 2015-03-12 07:37:53,20 2015-03-12 07:42:53,11 2015-03-12 07:47:53,9 2015-03-12 07:52:53,11 2015-03-12 07:57:53,18 2015-03-12 08:02:53,20 2015-03-12 08:07:53,13 2015-03-12 08:12:53,10 2015-03-12 08:17:53,11 2015-03-12 08:22:53,13 2015-03-12 08:27:53,12 2015-03-12 08:32:53,11 2015-03-12 08:37:53,19 2015-03-12 08:42:53,15 2015-03-12 08:47:53,18 2015-03-12 08:52:53,10 2015-03-12 08:57:53,14 2015-03-12 09:02:53,27 2015-03-12 09:07:53,50 2015-03-12 09:12:53,24 2015-03-12 09:17:53,11 2015-03-12 09:22:53,2 2015-03-12 09:27:53,4 2015-03-12 09:32:53,9 2015-03-12 09:37:53,9 2015-03-12 09:42:53,15 2015-03-12 09:47:53,11 2015-03-12 09:52:53,9 2015-03-12 09:57:53,19 2015-03-12 10:02:53,22 2015-03-12 10:07:53,23 2015-03-12 10:12:53,11 2015-03-12 10:17:53,25 2015-03-12 10:22:53,25 2015-03-12 10:27:53,19 2015-03-12 10:32:53,20 2015-03-12 10:37:53,23 2015-03-12 10:42:53,23 2015-03-12 10:47:53,16 2015-03-12 10:52:53,17 2015-03-12 10:57:53,21 2015-03-12 11:02:53,22 2015-03-12 11:07:53,14 2015-03-12 11:12:53,18 2015-03-12 11:17:53,17 2015-03-12 11:22:53,23 2015-03-12 11:27:53,16 2015-03-12 11:32:53,25 2015-03-12 11:37:53,20 2015-03-12 11:42:53,23 2015-03-12 11:47:53,14 2015-03-12 11:52:53,25 2015-03-12 11:57:53,19 2015-03-12 12:02:53,21 2015-03-12 12:07:53,18 2015-03-12 12:12:53,14 2015-03-12 12:17:53,11 2015-03-12 12:22:53,17 2015-03-12 12:27:53,26 2015-03-12 12:32:53,35 2015-03-12 12:37:53,25 2015-03-12 12:42:53,19 2015-03-12 12:47:53,14 2015-03-12 12:52:53,23 2015-03-12 12:57:53,30 2015-03-12 13:02:53,38 2015-03-12 13:07:53,21 2015-03-12 13:12:53,12 2015-03-12 13:17:53,29 2015-03-12 13:22:53,20 2015-03-12 13:27:53,29 2015-03-12 13:32:53,27 2015-03-12 13:37:53,13 2015-03-12 13:42:53,14 2015-03-12 13:47:53,23 2015-03-12 13:52:53,19 2015-03-12 13:57:53,20 2015-03-12 14:02:53,37 2015-03-12 14:07:53,27 2015-03-12 14:12:53,29 2015-03-12 14:17:53,29 2015-03-12 14:22:53,33 2015-03-12 14:27:53,30 2015-03-12 14:32:53,35 2015-03-12 14:37:53,29 2015-03-12 14:42:53,26 2015-03-12 14:47:53,29 2015-03-12 14:52:53,27 2015-03-12 14:57:53,37 2015-03-12 15:02:53,30 2015-03-12 15:07:53,25 2015-03-12 15:12:53,29 2015-03-12 15:17:53,24 2015-03-12 15:22:53,24 2015-03-12 15:27:53,27 2015-03-12 15:32:53,34 2015-03-12 15:37:53,17 2015-03-12 15:42:53,25 2015-03-12 15:47:53,17 2015-03-12 15:52:53,30 2015-03-12 15:57:53,34 2015-03-12 16:02:53,23 2015-03-12 16:07:53,26 2015-03-12 16:12:53,29 2015-03-12 16:17:53,32 2015-03-12 16:22:53,33 2015-03-12 16:27:53,28 2015-03-12 16:32:53,30 2015-03-12 16:37:53,37 2015-03-12 16:42:53,27 2015-03-12 16:47:53,18 2015-03-12 16:52:53,33 2015-03-12 16:57:53,20 2015-03-12 17:02:53,31 2015-03-12 17:07:53,40 2015-03-12 17:12:53,67 2015-03-12 17:17:53,44 2015-03-12 17:22:53,44 2015-03-12 17:27:53,35 2015-03-12 17:32:53,27 2015-03-12 17:37:53,28 2015-03-12 17:42:53,36 2015-03-12 17:47:53,23 2015-03-12 17:52:53,18 2015-03-12 17:57:53,29 2015-03-12 18:02:53,21 2015-03-12 18:07:53,16 2015-03-12 18:12:53,29 2015-03-12 18:17:53,20 2015-03-12 18:22:53,27 2015-03-12 18:27:53,33 2015-03-12 18:32:53,26 2015-03-12 18:37:53,32 2015-03-12 18:42:53,27 2015-03-12 18:47:53,24 2015-03-12 18:52:53,25 2015-03-12 18:57:53,30 2015-03-12 19:02:53,34 2015-03-12 19:07:53,20 2015-03-12 19:12:53,25 2015-03-12 19:17:53,23 2015-03-12 19:22:53,15 2015-03-12 19:27:53,30 2015-03-12 19:32:53,21 2015-03-12 19:37:53,21 2015-03-12 19:42:53,26 2015-03-12 19:47:53,26 2015-03-12 19:52:53,29 2015-03-12 19:57:53,39 2015-03-12 20:02:53,34 2015-03-12 20:07:53,28 2015-03-12 20:12:53,21 2015-03-12 20:17:53,16 2015-03-12 20:22:53,36 2015-03-12 20:27:53,25 2015-03-12 20:32:53,19 2015-03-12 20:37:53,24 2015-03-12 20:42:53,14 2015-03-12 20:47:53,16 2015-03-12 20:52:53,27 2015-03-12 20:57:53,17 2015-03-12 21:02:53,24 2015-03-12 21:07:53,15 2015-03-12 21:12:53,12 2015-03-12 21:17:53,17 2015-03-12 21:22:53,21 2015-03-12 21:27:53,22 2015-03-12 21:32:53,14 2015-03-12 21:37:53,12 2015-03-12 21:42:53,33 2015-03-12 21:47:53,18 2015-03-12 21:52:53,24 2015-03-12 21:57:53,20 2015-03-12 22:02:53,27 2015-03-12 22:07:53,21 2015-03-12 22:12:53,26 2015-03-12 22:17:53,21 2015-03-12 22:22:53,32 2015-03-12 22:27:53,26 2015-03-12 22:32:53,18 2015-03-12 22:37:53,14 2015-03-12 22:42:53,18 2015-03-12 22:47:53,16 2015-03-12 22:52:53,17 2015-03-12 22:57:53,13 2015-03-12 23:02:53,13 2015-03-12 23:07:53,10 2015-03-12 23:12:53,17 2015-03-12 23:17:53,11 2015-03-12 23:22:53,7 2015-03-12 23:27:53,17 2015-03-12 23:32:53,14 2015-03-12 23:37:53,24 2015-03-12 23:42:53,15 2015-03-12 23:47:53,15 2015-03-12 23:52:53,9 2015-03-12 23:57:53,14 2015-03-13 00:02:53,8 2015-03-13 00:07:53,15 2015-03-13 00:12:53,11 2015-03-13 00:17:53,11 2015-03-13 00:22:53,8 2015-03-13 00:27:53,15 2015-03-13 00:32:53,15 2015-03-13 00:37:53,12 2015-03-13 00:42:53,6 2015-03-13 00:47:53,8 2015-03-13 00:52:53,10 2015-03-13 00:57:53,20 2015-03-13 01:02:53,15 2015-03-13 01:07:53,16 2015-03-13 01:12:53,33 2015-03-13 01:17:53,11 2015-03-13 01:22:53,24 2015-03-13 01:27:53,12 2015-03-13 01:32:53,10 2015-03-13 01:37:53,12 2015-03-13 01:42:53,12 2015-03-13 01:47:53,15 2015-03-13 01:52:53,16 2015-03-13 01:57:53,5 2015-03-13 02:02:53,29 2015-03-13 02:07:53,12 2015-03-13 02:12:53,7 2015-03-13 02:17:53,54 2015-03-13 02:22:53,56 2015-03-13 02:27:53,31 2015-03-13 02:32:53,25 2015-03-13 02:37:53,22 2015-03-13 02:42:53,22 2015-03-13 02:47:53,19 2015-03-13 02:52:53,10 2015-03-13 02:57:53,30 2015-03-13 03:02:53,10 2015-03-13 03:07:53,20 2015-03-13 03:12:53,31 2015-03-13 03:17:53,6 2015-03-13 03:22:53,12 2015-03-13 03:27:53,20 2015-03-13 03:32:53,18 2015-03-13 03:37:53,15 2015-03-13 03:42:53,15 2015-03-13 03:47:53,12 2015-03-13 03:52:53,19 2015-03-13 03:57:53,13 2015-03-13 04:02:53,5 2015-03-13 04:07:53,13 2015-03-13 04:12:53,12 2015-03-13 04:17:53,14 2015-03-13 04:22:53,8 2015-03-13 04:27:53,21 2015-03-13 04:32:53,19 2015-03-13 04:37:53,9 2015-03-13 04:42:53,13 2015-03-13 04:47:53,13 2015-03-13 04:52:53,11 2015-03-13 04:57:53,12 2015-03-13 05:02:53,9 2015-03-13 05:07:53,20 2015-03-13 05:12:53,17 2015-03-13 05:17:53,15 2015-03-13 05:22:53,2 2015-03-13 05:27:53,14 2015-03-13 05:32:53,4 2015-03-13 05:37:53,18 2015-03-13 05:42:53,9 2015-03-13 05:47:53,7 2015-03-13 05:52:53,18 2015-03-13 05:57:53,12 2015-03-13 06:02:53,18 2015-03-13 06:07:53,7 2015-03-13 06:12:53,10 2015-03-13 06:17:53,10 2015-03-13 06:22:53,16 2015-03-13 06:27:53,10 2015-03-13 06:32:53,4 2015-03-13 06:37:53,11 2015-03-13 06:42:53,11 2015-03-13 06:47:53,16 2015-03-13 06:52:53,21 2015-03-13 06:57:53,11 2015-03-13 07:02:53,6 2015-03-13 07:07:53,12 2015-03-13 07:12:53,15 2015-03-13 07:17:53,4 2015-03-13 07:22:53,12 2015-03-13 07:27:53,8 2015-03-13 07:32:53,7 2015-03-13 07:37:53,18 2015-03-13 07:42:53,7 2015-03-13 07:47:53,15 2015-03-13 07:52:53,18 2015-03-13 07:57:53,10 2015-03-13 08:02:53,14 2015-03-13 08:07:53,9 2015-03-13 08:12:53,14 2015-03-13 08:17:53,17 2015-03-13 08:22:53,13 2015-03-13 08:27:53,13 2015-03-13 08:32:53,14 2015-03-13 08:37:53,16 2015-03-13 08:42:53,9 2015-03-13 08:47:53,15 2015-03-13 08:52:53,13 2015-03-13 08:57:53,11 2015-03-13 09:02:53,10 2015-03-13 09:07:53,16 2015-03-13 09:12:53,12 2015-03-13 09:17:53,15 2015-03-13 09:22:53,11 2015-03-13 09:27:53,15 2015-03-13 09:32:53,13 2015-03-13 09:37:53,5 2015-03-13 09:42:53,21 2015-03-13 09:47:53,19 2015-03-13 09:52:53,16 2015-03-13 09:57:53,19 2015-03-13 10:02:53,7 2015-03-13 10:07:53,6 2015-03-13 10:12:53,25 2015-03-13 10:17:53,12 2015-03-13 10:22:53,13 2015-03-13 10:27:53,15 2015-03-13 10:32:53,11 2015-03-13 10:37:53,8 2015-03-13 10:42:53,25 2015-03-13 10:47:53,20 2015-03-13 10:52:53,21 2015-03-13 10:57:53,10 2015-03-13 11:02:53,14 2015-03-13 11:07:53,12 2015-03-13 11:12:53,24 2015-03-13 11:17:53,11 2015-03-13 11:22:53,32 2015-03-13 11:27:53,16 2015-03-13 11:32:53,17 2015-03-13 11:37:53,15 2015-03-13 11:42:53,16 2015-03-13 11:47:53,21 2015-03-13 11:52:53,15 2015-03-13 11:57:53,19 2015-03-13 12:02:53,15 2015-03-13 12:07:53,12 2015-03-13 12:12:53,20 2015-03-13 12:17:53,26 2015-03-13 12:22:53,26 2015-03-13 12:27:53,17 2015-03-13 12:32:53,31 2015-03-13 12:37:53,24 2015-03-13 12:42:53,24 2015-03-13 12:47:53,25 2015-03-13 12:52:53,23 2015-03-13 12:57:53,26 2015-03-13 13:02:53,24 2015-03-13 13:07:53,25 2015-03-13 13:12:53,30 2015-03-13 13:17:53,25 2015-03-13 13:22:53,18 2015-03-13 13:27:53,32 2015-03-13 13:32:53,21 2015-03-13 13:37:53,23 2015-03-13 13:42:53,19 2015-03-13 13:47:53,30 2015-03-13 13:52:53,31 2015-03-13 13:57:53,30 2015-03-13 14:02:53,28 2015-03-13 14:07:53,19 2015-03-13 14:12:53,18 2015-03-13 14:17:53,33 2015-03-13 14:22:53,34 2015-03-13 14:27:53,37 2015-03-13 14:32:53,38 2015-03-13 14:37:53,41 2015-03-13 14:42:53,36 2015-03-13 14:47:53,28 2015-03-13 14:52:53,27 2015-03-13 14:57:53,31 2015-03-13 15:02:53,23 2015-03-13 15:07:53,27 2015-03-13 15:12:53,18 2015-03-13 15:17:53,19 2015-03-13 15:22:53,25 2015-03-13 15:27:53,29 2015-03-13 15:32:53,23 2015-03-13 15:37:53,23 2015-03-13 15:42:53,38 2015-03-13 15:47:53,32 2015-03-13 15:52:53,24 2015-03-13 15:57:53,33 2015-03-13 16:02:53,47 2015-03-13 16:07:53,28 2015-03-13 16:12:53,44 2015-03-13 16:17:53,30 2015-03-13 16:22:53,31 2015-03-13 16:27:53,36 2015-03-13 16:32:53,23 2015-03-13 16:37:53,22 2015-03-13 16:42:53,23 2015-03-13 16:47:53,21 2015-03-13 16:52:53,23 2015-03-13 16:57:53,37 2015-03-13 17:02:53,21 2015-03-13 17:07:53,25 2015-03-13 17:12:53,36 2015-03-13 17:17:53,20 2015-03-13 17:22:53,31 2015-03-13 17:27:53,18 2015-03-13 17:32:53,20 2015-03-13 17:37:53,22 2015-03-13 17:42:53,21 2015-03-13 17:47:53,17 2015-03-13 17:52:53,73 2015-03-13 17:57:53,25 2015-03-13 18:02:53,42 2015-03-13 18:07:53,31 2015-03-13 18:12:53,34 2015-03-13 18:17:53,40 2015-03-13 18:22:53,13 2015-03-13 18:27:53,24 2015-03-13 18:32:53,30 2015-03-13 18:37:53,32 2015-03-13 18:42:53,26 2015-03-13 18:47:53,27 2015-03-13 18:52:53,32 2015-03-13 18:57:53,23 2015-03-13 19:02:53,40 2015-03-13 19:07:53,50 2015-03-13 19:12:53,75 2015-03-13 19:17:53,61 2015-03-13 19:22:53,43 2015-03-13 19:27:53,52 2015-03-13 19:32:53,55 2015-03-13 19:37:53,56 2015-03-13 19:42:53,43 2015-03-13 19:47:53,38 2015-03-13 19:52:53,49 2015-03-13 19:57:53,134 2015-03-13 20:02:53,54 2015-03-13 20:07:53,68 2015-03-13 20:12:53,276 2015-03-13 20:17:53,157 2015-03-13 20:22:53,452 2015-03-13 20:27:53,295 2015-03-13 20:32:53,94 2015-03-13 20:37:53,224 2015-03-13 20:42:53,94 2015-03-13 20:47:53,227 2015-03-13 20:52:53,78 2015-03-13 20:57:53,411 2015-03-13 21:02:53,327 2015-03-13 21:07:53,210 2015-03-13 21:12:53,141 2015-03-13 21:17:53,73 2015-03-13 21:22:53,128 2015-03-13 21:27:53,268 2015-03-13 21:32:53,29 2015-03-13 21:37:53,14 2015-03-13 21:42:53,17 2015-03-13 21:47:53,18 2015-03-13 21:52:53,16 2015-03-13 21:57:53,26 2015-03-13 22:02:53,27 2015-03-13 22:07:53,15 2015-03-13 22:12:53,21 2015-03-13 22:17:53,16 2015-03-13 22:22:53,16 2015-03-13 22:27:53,33 2015-03-13 22:32:53,27 2015-03-13 22:37:53,14 2015-03-13 22:42:53,13 2015-03-13 22:47:53,34 2015-03-13 22:52:53,21 2015-03-13 22:57:53,31 2015-03-13 23:02:53,14 2015-03-13 23:07:53,20 2015-03-13 23:12:53,27 2015-03-13 23:17:53,31 2015-03-13 23:22:53,22 2015-03-13 23:27:53,21 2015-03-13 23:32:53,9 2015-03-13 23:37:53,23 2015-03-13 23:42:53,22 2015-03-13 23:47:53,9 2015-03-13 23:52:53,23 2015-03-13 23:57:53,11 2015-03-14 00:02:53,22 2015-03-14 00:07:53,13 2015-03-14 00:12:53,15 2015-03-14 00:17:53,11 2015-03-14 00:22:53,11 2015-03-14 00:27:53,11 2015-03-14 00:32:53,14 2015-03-14 00:37:53,21 2015-03-14 00:42:53,9 2015-03-14 00:47:53,15 2015-03-14 00:52:53,12 2015-03-14 00:57:53,10 2015-03-14 01:02:53,12 2015-03-14 01:07:53,19 2015-03-14 01:12:53,15 2015-03-14 01:17:53,12 2015-03-14 01:22:53,12 2015-03-14 01:27:53,12 2015-03-14 01:32:53,7 2015-03-14 01:37:53,9 2015-03-14 01:42:53,10 2015-03-14 01:47:53,12 2015-03-14 01:52:53,21 2015-03-14 01:57:53,12 2015-03-14 02:02:53,16 2015-03-14 02:07:53,13 2015-03-14 02:12:53,7 2015-03-14 02:17:53,12 2015-03-14 02:22:53,24 2015-03-14 02:27:53,11 2015-03-14 02:32:53,15 2015-03-14 02:37:53,10 2015-03-14 02:42:53,8 2015-03-14 02:47:53,7 2015-03-14 02:52:53,8 2015-03-14 02:57:53,20 2015-03-14 03:02:53,12 2015-03-14 03:07:53,12 2015-03-14 03:12:53,7 2015-03-14 03:17:53,4 2015-03-14 03:22:53,5 2015-03-14 03:27:53,5 2015-03-14 03:32:53,20 2015-03-14 03:37:53,17 2015-03-14 03:42:53,15 2015-03-14 03:47:53,12 2015-03-14 03:52:53,8 2015-03-14 03:57:53,12 2015-03-14 04:02:53,11 2015-03-14 04:07:53,7 2015-03-14 04:12:53,10 2015-03-14 04:17:53,10 2015-03-14 04:22:53,13 2015-03-14 04:27:53,8 2015-03-14 04:32:53,10 2015-03-14 04:37:53,3 2015-03-14 04:42:53,14 2015-03-14 04:47:53,11 2015-03-14 04:52:53,8 2015-03-14 04:57:53,14 2015-03-14 05:02:53,12 2015-03-14 05:07:53,6 2015-03-14 05:12:53,6 2015-03-14 05:17:53,1 2015-03-14 05:22:53,10 2015-03-14 05:27:53,7 2015-03-14 05:32:53,15 2015-03-14 05:37:53,8 2015-03-14 05:42:53,7 2015-03-14 05:47:53,14 2015-03-14 05:52:53,8 2015-03-14 05:57:53,5 2015-03-14 06:02:53,17 2015-03-14 06:07:53,8 2015-03-14 06:12:53,7 2015-03-14 06:17:53,4 2015-03-14 06:22:53,8 2015-03-14 06:27:53,5 2015-03-14 06:32:53,6 2015-03-14 06:37:53,3 2015-03-14 06:42:53,10 2015-03-14 06:47:53,8 2015-03-14 06:52:53,10 2015-03-14 06:57:53,13 2015-03-14 07:02:53,9 2015-03-14 07:07:53,7 2015-03-14 07:12:53,6 2015-03-14 07:17:53,10 2015-03-14 07:22:53,3 2015-03-14 07:27:53,7 2015-03-14 07:32:53,8 2015-03-14 07:37:53,5 2015-03-14 07:42:53,5 2015-03-14 07:47:53,7 2015-03-14 07:52:53,9 2015-03-14 07:57:53,7 2015-03-14 08:02:53,9 2015-03-14 08:07:53,11 2015-03-14 08:12:53,4 2015-03-14 08:17:53,4 2015-03-14 08:22:53,5 2015-03-14 08:27:53,6 2015-03-14 08:32:53,4 2015-03-14 08:37:53,4 2015-03-14 08:42:53,10 2015-03-14 08:47:53,3 2015-03-14 08:52:53,9 2015-03-14 08:57:53,6 2015-03-14 09:02:53,8 2015-03-14 09:07:53,4 2015-03-14 09:12:53,10 2015-03-14 09:17:53,6 2015-03-14 09:22:53,10 2015-03-14 09:27:53,6 2015-03-14 09:32:53,5 2015-03-14 09:37:53,8 2015-03-14 09:42:53,6 2015-03-14 09:47:53,4 2015-03-14 09:52:53,11 2015-03-14 09:57:53,7 2015-03-14 10:02:53,8 2015-03-14 10:07:53,9 2015-03-14 10:12:53,7 2015-03-14 10:17:53,3 2015-03-14 10:22:53,2 2015-03-14 10:27:53,8 2015-03-14 10:32:53,10 2015-03-14 10:37:53,14 2015-03-14 10:42:53,10 2015-03-14 10:47:53,4 2015-03-14 10:52:53,4 2015-03-14 10:57:53,6 2015-03-14 11:02:53,4 2015-03-14 11:07:53,6 2015-03-14 11:12:53,6 2015-03-14 11:17:53,7 2015-03-14 11:22:53,18 2015-03-14 11:27:53,14 2015-03-14 11:32:53,19 2015-03-14 11:37:53,6 2015-03-14 11:42:53,5 2015-03-14 11:47:53,9 2015-03-14 11:52:53,9 2015-03-14 11:57:53,9 2015-03-14 12:02:53,14 2015-03-14 12:07:53,7 2015-03-14 12:12:53,4 2015-03-14 12:17:53,9 2015-03-14 12:22:53,10 2015-03-14 12:27:53,5 2015-03-14 12:32:53,7 2015-03-14 12:37:53,8 2015-03-14 12:42:53,7 2015-03-14 12:47:53,9 2015-03-14 12:52:53,11 2015-03-14 12:57:53,18 2015-03-14 13:02:53,26 2015-03-14 13:07:53,14 2015-03-14 13:12:53,10 2015-03-14 13:17:53,18 2015-03-14 13:22:53,16 2015-03-14 13:27:53,18 2015-03-14 13:32:53,31 2015-03-14 13:37:53,13 2015-03-14 13:42:53,17 2015-03-14 13:47:53,16 2015-03-14 13:52:53,10 2015-03-14 13:57:53,12 2015-03-14 14:02:53,10 2015-03-14 14:07:53,10 2015-03-14 14:12:53,8 2015-03-14 14:17:53,21 2015-03-14 14:22:53,10 2015-03-14 14:27:53,9 2015-03-14 14:32:53,10 2015-03-14 14:37:53,19 2015-03-14 14:42:53,9 2015-03-14 14:47:53,17 2015-03-14 14:52:53,11 2015-03-14 14:57:53,10 2015-03-14 15:02:53,10 2015-03-14 15:07:53,13 2015-03-14 15:12:53,9 2015-03-14 15:17:53,11 2015-03-14 15:22:53,11 2015-03-14 15:27:53,9 2015-03-14 15:32:53,7 2015-03-14 15:37:53,10 2015-03-14 15:42:53,11 2015-03-14 15:47:53,6 2015-03-14 15:52:53,23 2015-03-14 15:57:53,12 2015-03-14 16:02:53,16 2015-03-14 16:07:53,22 2015-03-14 16:12:53,25 2015-03-14 16:17:53,24 2015-03-14 16:22:53,178 2015-03-14 16:27:53,287 2015-03-14 16:32:53,164 2015-03-14 16:37:53,135 2015-03-14 16:42:53,111 2015-03-14 16:47:53,78 2015-03-14 16:52:53,68 2015-03-14 16:57:53,65 2015-03-14 17:02:53,66 2015-03-14 17:07:53,50 2015-03-14 17:12:53,52 2015-03-14 17:17:53,57 2015-03-14 17:22:53,47 2015-03-14 17:27:53,34 2015-03-14 17:32:53,47 2015-03-14 17:37:53,30 2015-03-14 17:42:53,30 2015-03-14 17:47:53,35 2015-03-14 17:52:53,39 2015-03-14 17:57:53,165 2015-03-14 18:02:53,264 2015-03-14 18:07:53,28 2015-03-14 18:12:53,36 2015-03-14 18:17:53,41 2015-03-14 18:22:53,35 2015-03-14 18:27:53,28 2015-03-14 18:32:53,16 2015-03-14 18:37:53,23 2015-03-14 18:42:53,23 2015-03-14 18:47:53,20 2015-03-14 18:52:53,20 2015-03-14 18:57:53,21 2015-03-14 19:02:53,32 2015-03-14 19:07:53,21 2015-03-14 19:12:53,23 2015-03-14 19:17:53,14 2015-03-14 19:22:53,26 2015-03-14 19:27:53,11 2015-03-14 19:32:53,24 2015-03-14 19:37:53,19 2015-03-14 19:42:53,14 2015-03-14 19:47:53,240 2015-03-14 19:52:53,92 2015-03-14 19:57:53,29 2015-03-14 20:02:53,34 2015-03-14 20:07:53,16 2015-03-14 20:12:53,14 2015-03-14 20:17:53,20 2015-03-14 20:22:53,14 2015-03-14 20:27:53,13 2015-03-14 20:32:53,18 2015-03-14 20:37:53,22 2015-03-14 20:42:53,12 2015-03-14 20:47:53,25 2015-03-14 20:52:53,10 2015-03-14 20:57:53,13 2015-03-14 21:02:53,20 2015-03-14 21:07:53,19 2015-03-14 21:12:53,12 2015-03-14 21:17:53,18 2015-03-14 21:22:53,16 2015-03-14 21:27:53,30 2015-03-14 21:32:53,17 2015-03-14 21:37:53,11 2015-03-14 21:42:53,36 2015-03-14 21:47:53,14 2015-03-14 21:52:53,19 2015-03-14 21:57:53,13 2015-03-14 22:02:53,19 2015-03-14 22:07:53,22 2015-03-14 22:12:53,21 2015-03-14 22:17:53,19 2015-03-14 22:22:53,16 2015-03-14 22:27:53,12 2015-03-14 22:32:53,15 2015-03-14 22:37:53,20 2015-03-14 22:42:53,16 2015-03-14 22:47:53,12 2015-03-14 22:52:53,13 2015-03-14 22:57:53,17 2015-03-14 23:02:53,13 2015-03-14 23:07:53,7 2015-03-14 23:12:53,12 2015-03-14 23:17:53,19 2015-03-14 23:22:53,6 2015-03-14 23:27:53,11 2015-03-14 23:32:53,12 2015-03-14 23:37:53,18 2015-03-14 23:42:53,15 2015-03-14 23:47:53,9 2015-03-14 23:52:53,14 2015-03-14 23:57:53,10 2015-03-15 00:02:53,13 2015-03-15 00:07:53,12 2015-03-15 00:12:53,14 2015-03-15 00:17:53,12 2015-03-15 00:22:53,4 2015-03-15 00:27:53,7 2015-03-15 00:32:53,5 2015-03-15 00:37:53,14 2015-03-15 00:42:53,4 2015-03-15 00:47:53,13 2015-03-15 00:52:53,13 2015-03-15 00:57:53,11 2015-03-15 01:02:53,10 2015-03-15 01:07:53,15 2015-03-15 01:12:53,13 2015-03-15 01:17:53,7 2015-03-15 01:22:53,4 2015-03-15 01:27:53,6 2015-03-15 01:32:53,10 2015-03-15 01:37:53,11 2015-03-15 01:42:53,8 2015-03-15 01:47:53,11 2015-03-15 01:52:53,4 2015-03-15 01:57:53,14 2015-03-15 02:02:53,10 2015-03-15 02:07:53,8 2015-03-15 02:12:53,10 2015-03-15 02:17:53,11 2015-03-15 02:22:53,8 2015-03-15 02:27:53,8 2015-03-15 02:32:53,7 2015-03-15 02:37:53,8 2015-03-15 02:42:53,4 2015-03-15 02:47:53,12 2015-03-15 02:52:53,13 2015-03-15 02:57:53,13 2015-03-15 03:02:53,10 2015-03-15 03:07:53,12 2015-03-15 03:12:53,9 2015-03-15 03:17:53,12 2015-03-15 03:22:53,7 2015-03-15 03:27:53,8 2015-03-15 03:32:53,20 2015-03-15 03:37:53,5 2015-03-15 03:42:53,16 2015-03-15 03:47:53,12 2015-03-15 03:52:53,7 2015-03-15 03:57:53,8 2015-03-15 04:02:53,10 2015-03-15 04:07:53,16 2015-03-15 04:12:53,7 2015-03-15 04:17:53,7 2015-03-15 04:22:53,13 2015-03-15 04:27:53,10 2015-03-15 04:32:53,5 2015-03-15 04:37:53,6 2015-03-15 04:42:53,10 2015-03-15 04:47:53,7 2015-03-15 04:52:53,14 2015-03-15 04:57:53,5 2015-03-15 05:02:53,7 2015-03-15 05:07:53,3 2015-03-15 05:12:53,8 2015-03-15 05:17:53,6 2015-03-15 05:22:53,9 2015-03-15 05:27:53,11 2015-03-15 05:32:53,11 2015-03-15 05:37:53,5 2015-03-15 05:42:53,3 2015-03-15 05:47:53,5 2015-03-15 05:52:53,4 2015-03-15 05:57:53,15 2015-03-15 06:02:53,7 2015-03-15 06:07:53,8 2015-03-15 06:12:53,5 2015-03-15 06:17:53,4 2015-03-15 06:22:53,8 2015-03-15 06:27:53,5 2015-03-15 06:32:53,11 2015-03-15 06:37:53,14 2015-03-15 06:42:53,5 2015-03-15 06:47:53,5 2015-03-15 06:52:53,11 2015-03-15 06:57:53,12 2015-03-15 07:02:53,4 2015-03-15 07:07:53,12 2015-03-15 07:12:53,9 2015-03-15 07:17:53,2 2015-03-15 07:22:53,10 2015-03-15 07:27:53,6 2015-03-15 07:32:53,2 2015-03-15 07:37:53,8 2015-03-15 07:42:53,11 2015-03-15 07:47:53,7 2015-03-15 07:52:53,6 2015-03-15 07:57:53,11 2015-03-15 08:02:53,2 2015-03-15 08:07:53,8 2015-03-15 08:12:53,7 2015-03-15 08:17:53,6 2015-03-15 08:22:53,9 2015-03-15 08:27:53,7 2015-03-15 08:32:53,2 2015-03-15 08:37:53,8 2015-03-15 08:42:53,7 2015-03-15 08:47:53,15 2015-03-15 08:52:53,5 2015-03-15 08:57:53,32 2015-03-15 09:02:53,29 2015-03-15 09:07:53,29 2015-03-15 09:12:53,15 2015-03-15 09:17:53,14 2015-03-15 09:22:53,21 2015-03-15 09:27:53,26 2015-03-15 09:32:53,18 2015-03-15 09:37:53,17 2015-03-15 09:42:53,24 2015-03-15 09:47:53,18 2015-03-15 09:52:53,9 2015-03-15 09:57:53,10 2015-03-15 10:02:53,9 2015-03-15 10:07:53,9 2015-03-15 10:12:53,22 2015-03-15 10:17:53,12 2015-03-15 10:22:53,12 2015-03-15 10:27:53,13 2015-03-15 10:32:53,10 2015-03-15 10:37:53,9 2015-03-15 10:42:53,9 2015-03-15 10:47:53,5 2015-03-15 10:52:53,13 2015-03-15 10:57:53,5 2015-03-15 11:02:53,13 2015-03-15 11:07:53,6 2015-03-15 11:12:53,9 2015-03-15 11:17:53,10 2015-03-15 11:22:53,10 2015-03-15 11:27:53,9 2015-03-15 11:32:53,6 2015-03-15 11:37:53,15 2015-03-15 11:42:53,7 2015-03-15 11:47:53,7 2015-03-15 11:52:53,24 2015-03-15 11:57:53,29 2015-03-15 12:02:53,21 2015-03-15 12:07:53,14 2015-03-15 12:12:53,12 2015-03-15 12:17:53,11 2015-03-15 12:22:53,9 2015-03-15 12:27:53,15 2015-03-15 12:32:53,11 2015-03-15 12:37:53,10 2015-03-15 12:42:53,7 2015-03-15 12:47:53,3 2015-03-15 12:52:53,10 2015-03-15 12:57:53,12 2015-03-15 13:02:53,6 2015-03-15 13:07:53,15 2015-03-15 13:12:53,12 2015-03-15 13:17:53,12 2015-03-15 13:22:53,2 2015-03-15 13:27:53,8 2015-03-15 13:32:53,9 2015-03-15 13:37:53,5 2015-03-15 13:42:53,11 2015-03-15 13:47:53,7 2015-03-15 13:52:53,5 2015-03-15 13:57:53,13 2015-03-15 14:02:53,17 2015-03-15 14:07:53,20 2015-03-15 14:12:53,12 2015-03-15 14:17:53,8 2015-03-15 14:22:53,3 2015-03-15 14:27:53,14 2015-03-15 14:32:53,10 2015-03-15 14:37:53,9 2015-03-15 14:42:53,15 2015-03-15 14:47:53,4 2015-03-15 14:52:53,4 2015-03-15 14:57:53,13 2015-03-15 15:02:53,11 2015-03-15 15:07:53,14 2015-03-15 15:12:53,4 2015-03-15 15:17:53,8 2015-03-15 15:22:53,11 2015-03-15 15:27:53,12 2015-03-15 15:32:53,9 2015-03-15 15:37:53,13 2015-03-15 15:42:53,13 2015-03-15 15:47:53,24 2015-03-15 15:52:53,12 2015-03-15 15:57:53,12 2015-03-15 16:02:53,13 2015-03-15 16:07:53,14 2015-03-15 16:12:53,12 2015-03-15 16:17:53,6 2015-03-15 16:22:53,11 2015-03-15 16:27:53,15 2015-03-15 16:32:53,10 2015-03-15 16:37:53,15 2015-03-15 16:42:53,13 2015-03-15 16:47:53,18 2015-03-15 16:52:53,21 2015-03-15 16:57:53,24 2015-03-15 17:02:53,13 2015-03-15 17:07:53,18 2015-03-15 17:12:53,15 2015-03-15 17:17:53,17 2015-03-15 17:22:53,10 2015-03-15 17:27:53,11 2015-03-15 17:32:53,12 2015-03-15 17:37:53,10 2015-03-15 17:42:53,10 2015-03-15 17:47:53,12 2015-03-15 17:52:53,12 2015-03-15 17:57:53,12 2015-03-15 18:02:53,18 2015-03-15 18:07:53,13 2015-03-15 18:12:53,16 2015-03-15 18:17:53,12 2015-03-15 18:22:53,11 2015-03-15 18:27:53,17 2015-03-15 18:32:53,7 2015-03-15 18:37:53,19 2015-03-15 18:42:53,7 2015-03-15 18:47:53,22 2015-03-15 18:52:53,17 2015-03-15 18:57:53,22 2015-03-15 19:02:53,30 2015-03-15 19:07:53,13 2015-03-15 19:12:53,16 2015-03-15 19:17:53,17 2015-03-15 19:22:53,12 2015-03-15 19:27:53,10 2015-03-15 19:32:53,16 2015-03-15 19:37:53,20 2015-03-15 19:42:53,17 2015-03-15 19:47:53,21 2015-03-15 19:52:53,16 2015-03-15 19:57:53,12 2015-03-15 20:02:53,23 2015-03-15 20:07:53,38 2015-03-15 20:12:53,23 2015-03-15 20:17:53,31 2015-03-15 20:22:53,58 2015-03-15 20:27:53,50 2015-03-15 20:32:53,51 2015-03-15 20:37:53,80 2015-03-15 20:42:53,90 2015-03-15 20:47:53,80 2015-03-15 20:52:53,91 2015-03-15 20:57:53,57 2015-03-15 21:02:53,62 2015-03-15 21:07:53,91 2015-03-15 21:12:53,99 2015-03-15 21:17:53,72 2015-03-15 21:22:53,75 2015-03-15 21:27:53,80 2015-03-15 21:32:53,74 2015-03-15 21:37:53,36 2015-03-15 21:42:53,50 2015-03-15 21:47:53,57 2015-03-15 21:52:53,70 2015-03-15 21:57:53,23 2015-03-15 22:02:53,19 2015-03-15 22:07:53,13 2015-03-15 22:12:53,25 2015-03-15 22:17:53,20 2015-03-15 22:22:53,14 2015-03-15 22:27:53,14 2015-03-15 22:32:53,24 2015-03-15 22:37:53,22 2015-03-15 22:42:53,26 2015-03-15 22:47:53,30 2015-03-15 22:52:53,17 2015-03-15 22:57:53,19 2015-03-15 23:02:53,9 2015-03-15 23:07:53,9 2015-03-15 23:12:53,7 2015-03-15 23:17:53,8 2015-03-15 23:22:53,8 2015-03-15 23:27:53,9 2015-03-15 23:32:53,9 2015-03-15 23:37:53,11 2015-03-15 23:42:53,8 2015-03-15 23:47:53,9 2015-03-15 23:52:53,10 2015-03-15 23:57:53,6 2015-03-16 00:02:53,14 2015-03-16 00:07:53,13 2015-03-16 00:12:53,11 2015-03-16 00:17:53,3 2015-03-16 00:22:53,6 2015-03-16 00:27:53,10 2015-03-16 00:32:53,8 2015-03-16 00:37:53,10 2015-03-16 00:42:53,7 2015-03-16 00:47:53,2 2015-03-16 00:52:53,7 2015-03-16 00:57:53,13 2015-03-16 01:02:53,29 2015-03-16 01:07:53,17 2015-03-16 01:12:53,12 2015-03-16 01:17:53,13 2015-03-16 01:22:53,18 2015-03-16 01:27:53,27 2015-03-16 01:32:53,22 2015-03-16 01:37:53,29 2015-03-16 01:42:53,12 2015-03-16 01:47:53,14 2015-03-16 01:52:53,10 2015-03-16 01:57:53,18 2015-03-16 02:02:53,11 2015-03-16 02:07:53,16 2015-03-16 02:12:53,9 2015-03-16 02:17:53,17 2015-03-16 02:22:53,13 2015-03-16 02:27:53,7 2015-03-16 02:32:53,10 2015-03-16 02:37:53,14 2015-03-16 02:42:53,8 2015-03-16 02:47:53,13 2015-03-16 02:52:53,6 2015-03-16 02:57:53,5 2015-03-16 03:02:53,9 2015-03-16 03:07:53,9 2015-03-16 03:12:53,6 2015-03-16 03:17:53,12 2015-03-16 03:22:53,10 2015-03-16 03:27:53,13 2015-03-16 03:32:53,4 2015-03-16 03:37:53,7 2015-03-16 03:42:53,14 2015-03-16 03:47:53,15 2015-03-16 03:52:53,7 2015-03-16 03:57:53,11 2015-03-16 04:02:53,13 2015-03-16 04:07:53,11 2015-03-16 04:12:53,10 2015-03-16 04:17:53,5 2015-03-16 04:22:53,2 2015-03-16 04:27:53,7 2015-03-16 04:32:53,8 2015-03-16 04:37:53,9 2015-03-16 04:42:53,11 2015-03-16 04:47:53,7 2015-03-16 04:52:53,9 2015-03-16 04:57:53,7 2015-03-16 05:02:53,4 2015-03-16 05:07:53,13 2015-03-16 05:12:53,5 2015-03-16 05:17:53,1 2015-03-16 05:22:53,10 2015-03-16 05:27:53,6 2015-03-16 05:32:53,11 2015-03-16 05:37:53,3 2015-03-16 05:42:53,8 2015-03-16 05:47:53,16 2015-03-16 05:52:53,2 2015-03-16 05:57:53,9 2015-03-16 06:02:53,8 2015-03-16 06:07:53,8 2015-03-16 06:12:53,5 2015-03-16 06:17:53,10 2015-03-16 06:22:53,17 2015-03-16 06:27:53,7 2015-03-16 06:32:53,7 2015-03-16 06:37:53,10 2015-03-16 06:42:53,5 2015-03-16 06:47:53,4 2015-03-16 06:52:53,8 2015-03-16 06:57:53,15 2015-03-16 07:02:53,8 2015-03-16 07:07:53,7 2015-03-16 07:12:53,5 2015-03-16 07:17:53,11 2015-03-16 07:22:53,4 2015-03-16 07:27:53,12 2015-03-16 07:32:53,7 2015-03-16 07:37:53,3 2015-03-16 07:42:53,6 2015-03-16 07:47:53,5 2015-03-16 07:52:53,7 2015-03-16 07:57:53,7 2015-03-16 08:02:53,8 2015-03-16 08:07:53,6 2015-03-16 08:12:53,4 2015-03-16 08:17:53,13 2015-03-16 08:22:53,14 2015-03-16 08:27:53,5 2015-03-16 08:32:53,7 2015-03-16 08:37:53,21 2015-03-16 08:42:53,7 2015-03-16 08:47:53,10 2015-03-16 08:52:53,9 2015-03-16 08:57:53,8 2015-03-16 09:02:53,5 2015-03-16 09:07:53,15 2015-03-16 09:12:53,12 2015-03-16 09:17:53,13 2015-03-16 09:22:53,18 2015-03-16 09:27:53,21 2015-03-16 09:32:53,8 2015-03-16 09:37:53,9 2015-03-16 09:42:53,16 2015-03-16 09:47:53,7 2015-03-16 09:52:53,9 2015-03-16 09:57:53,13 2015-03-16 10:02:53,8 2015-03-16 10:07:53,10 2015-03-16 10:12:53,5 2015-03-16 10:17:53,7 2015-03-16 10:22:53,13 2015-03-16 10:27:53,10 2015-03-16 10:32:53,6 2015-03-16 10:37:53,22 2015-03-16 10:42:53,12 2015-03-16 10:47:53,16 2015-03-16 10:52:53,16 2015-03-16 10:57:53,14 2015-03-16 11:02:53,8 2015-03-16 11:07:53,13 2015-03-16 11:12:53,4 2015-03-16 11:17:53,6 2015-03-16 11:22:53,11 2015-03-16 11:27:53,20 2015-03-16 11:32:53,5 2015-03-16 11:37:53,4 2015-03-16 11:42:53,12 2015-03-16 11:47:53,11 2015-03-16 11:52:53,19 2015-03-16 11:57:53,17 2015-03-16 12:02:53,18 2015-03-16 12:07:53,8 2015-03-16 12:12:53,14 2015-03-16 12:17:53,16 2015-03-16 12:22:53,20 2015-03-16 12:27:53,26 2015-03-16 12:32:53,38 2015-03-16 12:37:53,52 2015-03-16 12:42:53,6 2015-03-16 12:47:53,11 2015-03-16 12:52:53,16 2015-03-16 12:57:53,29 2015-03-16 13:02:53,22 2015-03-16 13:07:53,23 2015-03-16 13:12:53,18 2015-03-16 13:17:53,16 2015-03-16 13:22:53,10 2015-03-16 13:27:53,23 2015-03-16 13:32:53,17 2015-03-16 13:37:53,19 2015-03-16 13:42:53,26 2015-03-16 13:47:53,23 2015-03-16 13:52:53,13 2015-03-16 13:57:53,19 2015-03-16 14:02:53,14 2015-03-16 14:07:53,23 2015-03-16 14:12:53,15 2015-03-16 14:17:53,24 2015-03-16 14:22:53,25 2015-03-16 14:27:53,17 2015-03-16 14:32:53,15 2015-03-16 14:37:53,13 2015-03-16 14:42:53,19 2015-03-16 14:47:53,14 2015-03-16 14:52:53,26 2015-03-16 14:57:53,22 2015-03-16 15:02:53,18 2015-03-16 15:07:53,11 2015-03-16 15:12:53,16 2015-03-16 15:17:53,20 2015-03-16 15:22:53,28 2015-03-16 15:27:53,25 2015-03-16 15:32:53,21 2015-03-16 15:37:53,24 2015-03-16 15:42:53,20 2015-03-16 15:47:53,21 2015-03-16 15:52:53,29 2015-03-16 15:57:53,45 2015-03-16 16:02:53,19 2015-03-16 16:07:53,26 2015-03-16 16:12:53,19 2015-03-16 16:17:53,23 2015-03-16 16:22:53,15 2015-03-16 16:27:53,19 2015-03-16 16:32:53,20 2015-03-16 16:37:53,16 2015-03-16 16:42:53,25 2015-03-16 16:47:53,13 2015-03-16 16:52:53,30 2015-03-16 16:57:53,29 2015-03-16 17:02:53,36 2015-03-16 17:07:53,21 2015-03-16 17:12:53,24 2015-03-16 17:17:53,52 2015-03-16 17:22:53,63 2015-03-16 17:27:53,61 2015-03-16 17:32:53,43 2015-03-16 17:37:53,41 2015-03-16 17:42:53,37 2015-03-16 17:47:53,21 2015-03-16 17:52:53,22 2015-03-16 17:57:53,52 2015-03-16 18:02:53,41 2015-03-16 18:07:53,54 2015-03-16 18:12:53,35 2015-03-16 18:17:53,28 2015-03-16 18:22:53,26 2015-03-16 18:27:53,33 2015-03-16 18:32:53,19 2015-03-16 18:37:53,20 2015-03-16 18:42:53,22 2015-03-16 18:47:53,35 2015-03-16 18:52:53,28 2015-03-16 18:57:53,28 2015-03-16 19:02:53,23 2015-03-16 19:07:53,22 2015-03-16 19:12:53,22 2015-03-16 19:17:53,19 2015-03-16 19:22:53,15 2015-03-16 19:27:53,34 2015-03-16 19:32:53,25 2015-03-16 19:37:53,27 2015-03-16 19:42:53,23 2015-03-16 19:47:53,16 2015-03-16 19:52:53,25 2015-03-16 19:57:53,17 2015-03-16 20:02:53,19 2015-03-16 20:07:53,26 2015-03-16 20:12:53,34 2015-03-16 20:17:53,17 2015-03-16 20:22:53,22 2015-03-16 20:27:53,34 2015-03-16 20:32:53,24 2015-03-16 20:37:53,19 2015-03-16 20:42:53,32 2015-03-16 20:47:53,34 2015-03-16 20:52:53,22 2015-03-16 20:57:53,20 2015-03-16 21:02:53,17 2015-03-16 21:07:53,15 2015-03-16 21:12:53,21 2015-03-16 21:17:53,11 2015-03-16 21:22:53,17 2015-03-16 21:27:53,54 2015-03-16 21:32:53,26 2015-03-16 21:37:53,37 2015-03-16 21:42:53,32 2015-03-16 21:47:53,20 2015-03-16 21:52:53,31 2015-03-16 21:57:53,27 2015-03-16 22:02:53,22 2015-03-16 22:07:53,17 2015-03-16 22:12:53,24 2015-03-16 22:17:53,18 2015-03-16 22:22:53,21 2015-03-16 22:27:53,29 2015-03-16 22:32:53,19 2015-03-16 22:37:53,24 2015-03-16 22:42:53,21 2015-03-16 22:47:53,12 2015-03-16 22:52:53,18 2015-03-16 22:57:53,22 2015-03-16 23:02:53,19 2015-03-16 23:07:53,11 2015-03-16 23:12:53,13 2015-03-16 23:17:53,12 2015-03-16 23:22:53,25 2015-03-16 23:27:53,11 2015-03-16 23:32:53,20 2015-03-16 23:37:53,22 2015-03-16 23:42:53,20 2015-03-16 23:47:53,13 2015-03-16 23:52:53,17 2015-03-16 23:57:53,18 2015-03-17 00:02:53,29 2015-03-17 00:07:53,15 2015-03-17 00:12:53,11 2015-03-17 00:17:53,19 2015-03-17 00:22:53,14 2015-03-17 00:27:53,14 2015-03-17 00:32:53,18 2015-03-17 00:37:53,7 2015-03-17 00:42:53,23 2015-03-17 00:47:53,22 2015-03-17 00:52:53,15 2015-03-17 00:57:53,36 2015-03-17 01:02:53,17 2015-03-17 01:07:53,21 2015-03-17 01:12:53,34 2015-03-17 01:17:53,18 2015-03-17 01:22:53,19 2015-03-17 01:27:53,20 2015-03-17 01:32:53,22 2015-03-17 01:37:53,16 2015-03-17 01:42:53,21 2015-03-17 01:47:53,19 2015-03-17 01:52:53,31 2015-03-17 01:57:53,17 2015-03-17 02:02:53,12 2015-03-17 02:07:53,10 2015-03-17 02:12:53,11 2015-03-17 02:17:53,15 2015-03-17 02:22:53,10 2015-03-17 02:27:53,17 2015-03-17 02:32:53,16 2015-03-17 02:37:53,20 2015-03-17 02:42:53,33 2015-03-17 02:47:53,12 2015-03-17 02:52:53,3 2015-03-17 02:57:53,6 2015-03-17 03:02:53,16 2015-03-17 03:07:53,8 2015-03-17 03:12:53,8 2015-03-17 03:17:53,11 2015-03-17 03:22:53,10 2015-03-17 03:27:53,17 2015-03-17 03:32:53,18 2015-03-17 03:37:53,20 2015-03-17 03:42:53,11 2015-03-17 03:47:53,8 2015-03-17 03:52:53,11 2015-03-17 03:57:53,9 2015-03-17 04:02:53,16 2015-03-17 04:07:53,27 2015-03-17 04:12:53,17 2015-03-17 04:17:53,14 2015-03-17 04:22:53,6 2015-03-17 04:27:53,11 2015-03-17 04:32:53,13 2015-03-17 04:37:53,9 2015-03-17 04:42:53,14 2015-03-17 04:47:53,19 2015-03-17 04:52:53,13 2015-03-17 04:57:53,19 2015-03-17 05:02:53,10 2015-03-17 05:07:53,14 2015-03-17 05:12:53,18 2015-03-17 05:17:53,13 2015-03-17 05:22:53,10 2015-03-17 05:27:53,14 2015-03-17 05:32:53,11 2015-03-17 05:37:53,7 2015-03-17 05:42:53,16 2015-03-17 05:47:53,12 2015-03-17 05:52:53,12 2015-03-17 05:57:53,23 2015-03-17 06:02:53,16 2015-03-17 06:07:53,19 2015-03-17 06:12:53,22 2015-03-17 06:17:53,5 2015-03-17 06:22:53,18 2015-03-17 06:27:53,17 2015-03-17 06:32:53,7 2015-03-17 06:37:53,13 2015-03-17 06:42:53,14 2015-03-17 06:47:53,14 2015-03-17 06:52:53,14 2015-03-17 06:57:53,12 2015-03-17 07:02:53,11 2015-03-17 07:07:53,20 2015-03-17 07:12:53,12 2015-03-17 07:17:53,12 2015-03-17 07:22:53,8 2015-03-17 07:27:53,11 2015-03-17 07:32:53,8 2015-03-17 07:37:53,3 2015-03-17 07:42:53,13 2015-03-17 07:47:53,10 2015-03-17 07:52:53,15 2015-03-17 07:57:53,16 2015-03-17 08:02:53,17 2015-03-17 08:07:53,17 2015-03-17 08:12:53,16 2015-03-17 08:17:53,23 2015-03-17 08:22:53,14 2015-03-17 08:27:53,7 2015-03-17 08:32:53,4 2015-03-17 08:37:53,10 2015-03-17 08:42:53,14 2015-03-17 08:47:53,11 2015-03-17 08:52:53,11 2015-03-17 08:57:53,15 2015-03-17 09:02:53,12 2015-03-17 09:07:53,19 2015-03-17 09:12:53,17 2015-03-17 09:17:53,22 2015-03-17 09:22:53,14 2015-03-17 09:27:53,18 2015-03-17 09:32:53,15 2015-03-17 09:37:53,15 2015-03-17 09:42:53,21 2015-03-17 09:47:53,27 2015-03-17 09:52:53,11 2015-03-17 09:57:53,11 2015-03-17 10:02:53,18 2015-03-17 10:07:53,9 2015-03-17 10:12:53,14 2015-03-17 10:17:53,27 2015-03-17 10:22:53,12 2015-03-17 10:27:53,14 2015-03-17 10:32:53,14 2015-03-17 10:37:53,27 2015-03-17 10:42:53,12 2015-03-17 10:47:53,15 2015-03-17 10:52:53,11 2015-03-17 10:57:53,22 2015-03-17 11:02:53,19 2015-03-17 11:07:53,27 2015-03-17 11:12:53,15 2015-03-17 11:17:53,15 2015-03-17 11:22:53,25 2015-03-17 11:27:53,36 2015-03-17 11:32:53,18 2015-03-17 11:37:53,8 2015-03-17 11:42:53,13 2015-03-17 11:47:53,14 2015-03-17 11:52:53,18 2015-03-17 11:57:53,20 2015-03-17 12:02:53,18 2015-03-17 12:07:53,22 2015-03-17 12:12:53,18 2015-03-17 12:17:53,15 2015-03-17 12:22:53,11 2015-03-17 12:27:53,22 2015-03-17 12:32:53,20 2015-03-17 12:37:53,30 2015-03-17 12:42:53,18 2015-03-17 12:47:53,20 2015-03-17 12:52:53,16 2015-03-17 12:57:53,22 2015-03-17 13:02:53,28 2015-03-17 13:07:53,21 2015-03-17 13:12:53,16 2015-03-17 13:17:53,21 2015-03-17 13:22:53,28 2015-03-17 13:27:53,17 2015-03-17 13:32:53,23 2015-03-17 13:37:53,20 2015-03-17 13:42:53,13 2015-03-17 13:47:53,26 2015-03-17 13:52:53,26 2015-03-17 13:57:53,46 2015-03-17 14:02:53,41 2015-03-17 14:07:53,38 2015-03-17 14:12:53,37 2015-03-17 14:17:53,30 2015-03-17 14:22:53,37 2015-03-17 14:27:53,30 2015-03-17 14:32:53,35 2015-03-17 14:37:53,61 2015-03-17 14:42:53,86 2015-03-17 14:47:53,38 2015-03-17 14:52:53,43 2015-03-17 14:57:53,42 2015-03-17 15:02:53,46 2015-03-17 15:07:53,39 2015-03-17 15:12:53,39 2015-03-17 15:17:53,51 2015-03-17 15:22:53,45 2015-03-17 15:27:53,53 2015-03-17 15:32:53,52 2015-03-17 15:37:53,37 2015-03-17 15:42:53,43 2015-03-17 15:47:53,35 2015-03-17 15:52:53,38 2015-03-17 15:57:53,31 2015-03-17 16:02:53,45 2015-03-17 16:07:53,24 2015-03-17 16:12:53,43 2015-03-17 16:17:53,52 2015-03-17 16:22:53,34 2015-03-17 16:27:53,32 2015-03-17 16:32:53,44 2015-03-17 16:37:53,28 2015-03-17 16:42:53,27 2015-03-17 16:47:53,27 2015-03-17 16:52:53,33 2015-03-17 16:57:53,30 2015-03-17 17:02:53,26 2015-03-17 17:07:53,52 2015-03-17 17:12:53,53 2015-03-17 17:17:53,37 2015-03-17 17:22:53,37 2015-03-17 17:27:53,35 2015-03-17 17:32:53,29 2015-03-17 17:37:53,35 2015-03-17 17:42:53,31 2015-03-17 17:47:53,27 2015-03-17 17:52:53,28 2015-03-17 17:57:53,34 2015-03-17 18:02:53,29 2015-03-17 18:07:53,22 2015-03-17 18:12:53,30 2015-03-17 18:17:53,18 2015-03-17 18:22:53,26 2015-03-17 18:27:53,39 2015-03-17 18:32:53,33 2015-03-17 18:37:53,22 2015-03-17 18:42:53,53 2015-03-17 18:47:53,100 2015-03-17 18:52:53,78 2015-03-17 18:57:53,52 2015-03-17 19:02:53,51 2015-03-17 19:07:53,52 2015-03-17 19:12:53,52 2015-03-17 19:17:53,43 2015-03-17 19:22:53,41 2015-03-17 19:27:53,49 2015-03-17 19:32:53,41 2015-03-17 19:37:53,57 2015-03-17 19:42:53,49 2015-03-17 19:47:53,48 2015-03-17 19:52:53,34 2015-03-17 19:57:53,37 2015-03-17 20:02:53,34 2015-03-17 20:07:53,22 2015-03-17 20:12:53,44 2015-03-17 20:17:53,69 2015-03-17 20:22:53,46 2015-03-17 20:27:53,24 2015-03-17 20:32:53,23 2015-03-17 20:37:53,17 2015-03-17 20:42:53,21 2015-03-17 20:47:53,23 2015-03-17 20:52:53,26 2015-03-17 20:57:53,24 2015-03-17 21:02:53,36 2015-03-17 21:07:53,31 2015-03-17 21:12:53,37 2015-03-17 21:17:53,23 2015-03-17 21:22:53,23 2015-03-17 21:27:53,33 2015-03-17 21:32:53,64 2015-03-17 21:37:53,65 2015-03-17 21:42:53,30 2015-03-17 21:47:53,30 2015-03-17 21:52:53,29 2015-03-17 21:57:53,24 2015-03-17 22:02:53,43 2015-03-17 22:07:53,26 2015-03-17 22:12:53,24 2015-03-17 22:17:53,15 2015-03-17 22:22:53,19 2015-03-17 22:27:53,26 2015-03-17 22:32:53,38 2015-03-17 22:37:53,44 2015-03-17 22:42:53,26 2015-03-17 22:47:53,22 2015-03-17 22:52:53,24 2015-03-17 22:57:53,16 2015-03-17 23:02:53,17 2015-03-17 23:07:53,11 2015-03-17 23:12:53,41 2015-03-17 23:17:53,18 2015-03-17 23:22:53,30 2015-03-17 23:27:53,45 2015-03-17 23:32:53,29 2015-03-17 23:37:53,26 2015-03-17 23:42:53,12 2015-03-17 23:47:53,19 2015-03-17 23:52:53,17 2015-03-17 23:57:53,30 2015-03-18 00:02:53,21 2015-03-18 00:07:53,17 2015-03-18 00:12:53,20 2015-03-18 00:17:53,19 2015-03-18 00:22:53,19 2015-03-18 00:27:53,15 2015-03-18 00:32:53,11 2015-03-18 00:37:53,14 2015-03-18 00:42:53,15 2015-03-18 00:47:53,11 2015-03-18 00:52:53,20 2015-03-18 00:57:53,16 2015-03-18 01:02:53,16 2015-03-18 01:07:53,16 2015-03-18 01:12:53,5 2015-03-18 01:17:53,12 2015-03-18 01:22:53,17 2015-03-18 01:27:53,22 2015-03-18 01:32:53,9 2015-03-18 01:37:53,11 2015-03-18 01:42:53,20 2015-03-18 01:47:53,16 2015-03-18 01:52:53,15 2015-03-18 01:57:53,20 2015-03-18 02:02:53,25 2015-03-18 02:07:53,15 2015-03-18 02:12:53,15 2015-03-18 02:17:53,9 2015-03-18 02:22:53,9 2015-03-18 02:27:53,9 2015-03-18 02:32:53,19 2015-03-18 02:37:53,11 2015-03-18 02:42:53,9 2015-03-18 02:47:53,12 2015-03-18 02:52:53,14 2015-03-18 02:57:53,16 2015-03-18 03:02:53,18 2015-03-18 03:07:53,13 2015-03-18 03:12:53,16 2015-03-18 03:17:53,15 2015-03-18 03:22:53,13 2015-03-18 03:27:53,18 2015-03-18 03:32:53,18 2015-03-18 03:37:53,19 2015-03-18 03:42:53,21 2015-03-18 03:47:53,9 2015-03-18 03:52:53,12 2015-03-18 03:57:53,17 2015-03-18 04:02:53,5 2015-03-18 04:07:53,14 2015-03-18 04:12:53,9 2015-03-18 04:17:53,10 2015-03-18 04:22:53,7 2015-03-18 04:27:53,21 2015-03-18 04:32:53,6 2015-03-18 04:37:53,12 2015-03-18 04:42:53,7 2015-03-18 04:47:53,8 2015-03-18 04:52:53,9 2015-03-18 04:57:53,19 2015-03-18 05:02:53,6 2015-03-18 05:07:53,15 2015-03-18 05:12:53,8 2015-03-18 05:17:53,7 2015-03-18 05:22:53,65 2015-03-18 05:27:53,47 2015-03-18 05:32:53,27 2015-03-18 05:37:53,21 2015-03-18 05:42:53,26 2015-03-18 05:47:53,8 2015-03-18 05:52:53,15 2015-03-18 05:57:53,14 2015-03-18 06:02:53,16 2015-03-18 06:07:53,7 2015-03-18 06:12:53,16 2015-03-18 06:17:53,6 2015-03-18 06:22:53,12 2015-03-18 06:27:53,11 2015-03-18 06:32:53,18 2015-03-18 06:37:53,17 2015-03-18 06:42:53,18 2015-03-18 06:47:53,13 2015-03-18 06:52:53,12 2015-03-18 06:57:53,13 2015-03-18 07:02:53,14 2015-03-18 07:07:53,11 2015-03-18 07:12:53,7 2015-03-18 07:17:53,10 2015-03-18 07:22:53,15 2015-03-18 07:27:53,15 2015-03-18 07:32:53,20 2015-03-18 07:37:53,26 2015-03-18 07:42:53,16 2015-03-18 07:47:53,10 2015-03-18 07:52:53,14 2015-03-18 07:57:53,15 2015-03-18 08:02:53,18 2015-03-18 08:07:53,10 2015-03-18 08:12:53,13 2015-03-18 08:17:53,9 2015-03-18 08:22:53,16 2015-03-18 08:27:53,23 2015-03-18 08:32:53,21 2015-03-18 08:37:53,18 2015-03-18 08:42:53,15 2015-03-18 08:47:53,11 2015-03-18 08:52:53,15 2015-03-18 08:57:53,17 2015-03-18 09:02:53,16 2015-03-18 09:07:53,16 2015-03-18 09:12:53,18 2015-03-18 09:17:53,16 2015-03-18 09:22:53,17 2015-03-18 09:27:53,19 2015-03-18 09:32:53,15 2015-03-18 09:37:53,19 2015-03-18 09:42:53,21 2015-03-18 09:47:53,16 2015-03-18 09:52:53,18 2015-03-18 09:57:53,14 2015-03-18 10:02:53,13 2015-03-18 10:07:53,23 2015-03-18 10:12:53,30 2015-03-18 10:17:53,20 2015-03-18 10:22:53,14 2015-03-18 10:27:53,27 2015-03-18 10:32:53,12 2015-03-18 10:37:53,27 2015-03-18 10:42:53,23 2015-03-18 10:47:53,35 2015-03-18 10:52:53,19 2015-03-18 10:57:53,20 2015-03-18 11:02:53,24 2015-03-18 11:07:53,23 2015-03-18 11:12:53,17 2015-03-18 11:17:53,17 2015-03-18 11:22:53,15 2015-03-18 11:27:53,23 2015-03-18 11:32:53,22 2015-03-18 11:37:53,22 2015-03-18 11:42:53,15 2015-03-18 11:47:53,21 2015-03-18 11:52:53,21 2015-03-18 11:57:53,45 2015-03-18 12:02:53,17 2015-03-18 12:07:53,9 2015-03-18 12:12:53,13 2015-03-18 12:17:53,11 2015-03-18 12:22:53,16 2015-03-18 12:27:53,21 2015-03-18 12:32:53,22 2015-03-18 12:37:53,20 2015-03-18 12:42:53,27 2015-03-18 12:47:53,16 2015-03-18 12:52:53,22 2015-03-18 12:57:53,22 2015-03-18 13:02:53,26 2015-03-18 13:07:53,12 2015-03-18 13:12:53,15 2015-03-18 13:17:53,26 2015-03-18 13:22:53,21 2015-03-18 13:27:53,17 2015-03-18 13:32:53,11 2015-03-18 13:37:53,27 2015-03-18 13:42:53,29 2015-03-18 13:47:53,44 2015-03-18 13:52:53,38 2015-03-18 13:57:53,36 2015-03-18 14:02:53,28 2015-03-18 14:07:53,30 2015-03-18 14:12:53,18 2015-03-18 14:17:53,26 2015-03-18 14:22:53,26 2015-03-18 14:27:53,35 2015-03-18 14:32:53,29 2015-03-18 14:37:53,28 2015-03-18 14:42:53,29 2015-03-18 14:47:53,24 2015-03-18 14:52:53,32 2015-03-18 14:57:53,27 2015-03-18 15:02:53,26 2015-03-18 15:07:53,48 2015-03-18 15:12:53,40 2015-03-18 15:17:53,41 2015-03-18 15:22:53,47 2015-03-18 15:27:53,53 2015-03-18 15:32:53,32 2015-03-18 15:37:53,29 2015-03-18 15:42:53,36 2015-03-18 15:47:53,40 2015-03-18 15:52:53,19 2015-03-18 15:57:53,89 2015-03-18 16:02:53,73 2015-03-18 16:07:53,48 2015-03-18 16:12:53,37 2015-03-18 16:17:53,37 2015-03-18 16:22:53,25 2015-03-18 16:27:53,38 2015-03-18 16:32:53,24 2015-03-18 16:37:53,24 2015-03-18 16:42:53,38 2015-03-18 16:47:53,26 2015-03-18 16:52:53,20 2015-03-18 16:57:53,31 2015-03-18 17:02:53,29 2015-03-18 17:07:53,22 2015-03-18 17:12:53,37 2015-03-18 17:17:53,25 2015-03-18 17:22:53,27 2015-03-18 17:27:53,46 2015-03-18 17:32:53,39 2015-03-18 17:37:53,31 2015-03-18 17:42:53,32 2015-03-18 17:47:53,27 2015-03-18 17:52:53,34 2015-03-18 17:57:53,61 2015-03-18 18:02:53,61 2015-03-18 18:07:53,42 2015-03-18 18:12:53,32 2015-03-18 18:17:53,33 2015-03-18 18:22:53,39 2015-03-18 18:27:53,41 2015-03-18 18:32:53,31 2015-03-18 18:37:53,24 2015-03-18 18:42:53,31 2015-03-18 18:47:53,20 2015-03-18 18:52:53,50 2015-03-18 18:57:53,37 2015-03-18 19:02:53,37 2015-03-18 19:07:53,31 2015-03-18 19:12:53,31 2015-03-18 19:17:53,26 2015-03-18 19:22:53,22 2015-03-18 19:27:53,32 2015-03-18 19:32:53,34 2015-03-18 19:37:53,26 2015-03-18 19:42:53,24 2015-03-18 19:47:53,28 2015-03-18 19:52:53,24 2015-03-18 19:57:53,34 2015-03-18 20:02:53,19 2015-03-18 20:07:53,21 2015-03-18 20:12:53,30 2015-03-18 20:17:53,28 2015-03-18 20:22:53,25 2015-03-18 20:27:53,16 2015-03-18 20:32:53,21 2015-03-18 20:37:53,32 2015-03-18 20:42:53,24 2015-03-18 20:47:53,18 2015-03-18 20:52:53,10 2015-03-18 20:57:53,27 2015-03-18 21:02:53,22 2015-03-18 21:07:53,22 2015-03-18 21:12:53,43 2015-03-18 21:17:53,55 2015-03-18 21:22:53,48 2015-03-18 21:27:53,25 2015-03-18 21:32:53,38 2015-03-18 21:37:53,27 2015-03-18 21:42:53,35 2015-03-18 21:47:53,62 2015-03-18 21:52:53,70 2015-03-18 21:57:53,47 2015-03-18 22:02:53,14 2015-03-18 22:07:53,31 2015-03-18 22:12:53,25 2015-03-18 22:17:53,16 2015-03-18 22:22:53,29 2015-03-18 22:27:53,31 2015-03-18 22:32:53,29 2015-03-18 22:37:53,25 2015-03-18 22:42:53,45 2015-03-18 22:47:53,29 2015-03-18 22:52:53,19 2015-03-18 22:57:53,36 2015-03-18 23:02:53,27 2015-03-18 23:07:53,23 2015-03-18 23:12:53,19 2015-03-18 23:17:53,18 2015-03-18 23:22:53,15 2015-03-18 23:27:53,29 2015-03-18 23:32:53,17 2015-03-18 23:37:53,30 2015-03-18 23:42:53,47 2015-03-18 23:47:53,35 2015-03-18 23:52:53,14 2015-03-18 23:57:53,24 2015-03-19 00:02:53,28 2015-03-19 00:07:53,22 2015-03-19 00:12:53,36 2015-03-19 00:17:53,15 2015-03-19 00:22:53,20 2015-03-19 00:27:53,36 2015-03-19 00:32:53,25 2015-03-19 00:37:53,18 2015-03-19 00:42:53,23 2015-03-19 00:47:53,22 2015-03-19 00:52:53,22 2015-03-19 00:57:53,15 2015-03-19 01:02:53,10 2015-03-19 01:07:53,22 2015-03-19 01:12:53,23 2015-03-19 01:17:53,13 2015-03-19 01:22:53,22 2015-03-19 01:27:53,22 2015-03-19 01:32:53,14 2015-03-19 01:37:53,29 2015-03-19 01:42:53,24 2015-03-19 01:47:53,25 2015-03-19 01:52:53,19 2015-03-19 01:57:53,29 2015-03-19 02:02:53,25 2015-03-19 02:07:53,18 2015-03-19 02:12:53,22 2015-03-19 02:17:53,33 2015-03-19 02:22:53,18 2015-03-19 02:27:53,24 2015-03-19 02:32:53,24 2015-03-19 02:37:53,17 2015-03-19 02:42:53,15 2015-03-19 02:47:53,18 2015-03-19 02:52:53,21 2015-03-19 02:57:53,27 2015-03-19 03:02:53,24 2015-03-19 03:07:53,6 2015-03-19 03:12:53,9 2015-03-19 03:17:53,22 2015-03-19 03:22:53,11 2015-03-19 03:27:53,12 2015-03-19 03:32:53,22 2015-03-19 03:37:53,12 2015-03-19 03:42:53,15 2015-03-19 03:47:53,23 2015-03-19 03:52:53,13 2015-03-19 03:57:53,23 2015-03-19 04:02:53,8 2015-03-19 04:07:53,7 2015-03-19 04:12:53,16 2015-03-19 04:17:53,9 2015-03-19 04:22:53,9 2015-03-19 04:27:53,10 2015-03-19 04:32:53,11 2015-03-19 04:37:53,8 2015-03-19 04:42:53,14 2015-03-19 04:47:53,13 2015-03-19 04:52:53,15 2015-03-19 04:57:53,11 2015-03-19 05:02:53,5 2015-03-19 05:07:53,12 2015-03-19 05:12:53,15 2015-03-19 05:17:53,11 2015-03-19 05:22:53,18 2015-03-19 05:27:53,5 2015-03-19 05:32:53,5 2015-03-19 05:37:53,7 2015-03-19 05:42:53,10 2015-03-19 05:47:53,18 2015-03-19 05:52:53,9 2015-03-19 05:57:53,8 2015-03-19 06:02:53,21 2015-03-19 06:07:53,5 2015-03-19 06:12:53,18 2015-03-19 06:17:53,6 2015-03-19 06:22:53,7 2015-03-19 06:27:53,11 2015-03-19 06:32:53,5 2015-03-19 06:37:53,17 2015-03-19 06:42:53,8 2015-03-19 06:47:53,9 2015-03-19 06:52:53,7 2015-03-19 06:57:53,10 2015-03-19 07:02:53,7 2015-03-19 07:07:53,2 2015-03-19 07:12:53,7 2015-03-19 07:17:53,5 2015-03-19 07:22:53,11 2015-03-19 07:27:53,6 2015-03-19 07:32:53,7 2015-03-19 07:37:53,10 2015-03-19 07:42:53,9 2015-03-19 07:47:53,20 2015-03-19 07:52:53,30 2015-03-19 07:57:53,18 2015-03-19 08:02:53,38 2015-03-19 08:07:53,20 2015-03-19 08:12:53,22 2015-03-19 08:17:53,14 2015-03-19 08:22:53,18 2015-03-19 08:27:53,42 2015-03-19 08:32:53,17 2015-03-19 08:37:53,11 2015-03-19 08:42:53,24 2015-03-19 08:47:53,12 2015-03-19 08:52:53,14 2015-03-19 08:57:53,23 2015-03-19 09:02:53,19 2015-03-19 09:07:53,11 2015-03-19 09:12:53,13 2015-03-19 09:17:53,18 2015-03-19 09:22:53,13 2015-03-19 09:27:53,15 2015-03-19 09:32:53,9 2015-03-19 09:37:53,14 2015-03-19 09:42:53,10 2015-03-19 09:47:53,29 2015-03-19 09:52:53,29 2015-03-19 09:57:53,23 2015-03-19 10:02:53,24 2015-03-19 10:07:53,23 2015-03-19 10:12:53,20 2015-03-19 10:17:53,17 2015-03-19 10:22:53,20 2015-03-19 10:27:53,16 2015-03-19 10:32:53,20 2015-03-19 10:37:53,18 2015-03-19 10:42:53,15 2015-03-19 10:47:53,21 2015-03-19 10:52:53,18 2015-03-19 10:57:53,22 2015-03-19 11:02:53,25 2015-03-19 11:07:53,22 2015-03-19 11:12:53,12 2015-03-19 11:17:53,19 2015-03-19 11:22:53,16 2015-03-19 11:27:53,17 2015-03-19 11:32:53,19 2015-03-19 11:37:53,20 2015-03-19 11:42:53,21 2015-03-19 11:47:53,8 2015-03-19 11:52:53,18 2015-03-19 11:57:53,26 2015-03-19 12:02:53,21 2015-03-19 12:07:53,29 2015-03-19 12:12:53,25 2015-03-19 12:17:53,24 2015-03-19 12:22:53,34 2015-03-19 12:27:53,15 2015-03-19 12:32:53,13 2015-03-19 12:37:53,21 2015-03-19 12:42:53,25 2015-03-19 12:47:53,17 2015-03-19 12:52:53,19 2015-03-19 12:57:53,39 2015-03-19 13:02:53,28 2015-03-19 13:07:53,53 2015-03-19 13:12:53,47 2015-03-19 13:17:53,45 2015-03-19 13:22:53,55 2015-03-19 13:27:53,42 2015-03-19 13:32:53,43 2015-03-19 13:37:53,41 2015-03-19 13:42:53,32 2015-03-19 13:47:53,40 2015-03-19 13:52:53,29 2015-03-19 13:57:53,47 2015-03-19 14:02:53,50 2015-03-19 14:07:53,44 2015-03-19 14:12:53,46 2015-03-19 14:17:53,32 2015-03-19 14:22:53,35 2015-03-19 14:27:53,52 2015-03-19 14:32:53,39 2015-03-19 14:37:53,34 2015-03-19 14:42:53,41 2015-03-19 14:47:53,35 2015-03-19 14:52:53,51 2015-03-19 14:57:53,35 2015-03-19 15:02:53,44 2015-03-19 15:07:53,32 2015-03-19 15:12:53,27 2015-03-19 15:17:53,28 2015-03-19 15:22:53,29 2015-03-19 15:27:53,32 2015-03-19 15:32:53,38 2015-03-19 15:37:53,27 2015-03-19 15:42:53,22 2015-03-19 15:47:53,48 2015-03-19 15:52:53,33 2015-03-19 15:57:53,62 2015-03-19 16:02:53,36 2015-03-19 16:07:53,25 2015-03-19 16:12:53,33 2015-03-19 16:17:53,28 2015-03-19 16:22:53,31 2015-03-19 16:27:53,28 2015-03-19 16:32:53,26 2015-03-19 16:37:53,50 2015-03-19 16:42:53,30 2015-03-19 16:47:53,36 2015-03-19 16:52:53,52 2015-03-19 16:57:53,46 2015-03-19 17:02:53,44 2015-03-19 17:07:53,41 2015-03-19 17:12:53,56 2015-03-19 17:17:53,48 2015-03-19 17:22:53,33 2015-03-19 17:27:53,33 2015-03-19 17:32:53,32 2015-03-19 17:37:53,33 2015-03-19 17:42:53,33 2015-03-19 17:47:53,26 2015-03-19 17:52:53,23 2015-03-19 17:57:53,15 2015-03-19 18:02:53,37 2015-03-19 18:07:53,47 2015-03-19 18:12:53,27 2015-03-19 18:17:53,25 2015-03-19 18:22:53,34 2015-03-19 18:27:53,27 2015-03-19 18:32:53,39 2015-03-19 18:37:53,38 2015-03-19 18:42:53,26 2015-03-19 18:47:53,22 2015-03-19 18:52:53,37 2015-03-19 18:57:53,41 2015-03-19 19:02:53,35 2015-03-19 19:07:53,24 2015-03-19 19:12:53,25 2015-03-19 19:17:53,35 2015-03-19 19:22:53,20 2015-03-19 19:27:53,31 2015-03-19 19:32:53,32 2015-03-19 19:37:53,40 2015-03-19 19:42:53,38 2015-03-19 19:47:53,43 2015-03-19 19:52:53,35 2015-03-19 19:57:53,46 2015-03-19 20:02:53,59 2015-03-19 20:07:53,58 2015-03-19 20:12:53,29 2015-03-19 20:17:53,12 2015-03-19 20:22:53,34 2015-03-19 20:27:53,31 2015-03-19 20:32:53,21 2015-03-19 20:37:53,44 2015-03-19 20:42:53,14 2015-03-19 20:47:53,23 2015-03-19 20:52:53,26 2015-03-19 20:57:53,34 2015-03-19 21:02:53,33 2015-03-19 21:07:53,26 2015-03-19 21:12:53,23 2015-03-19 21:17:53,15 2015-03-19 21:22:53,18 2015-03-19 21:27:53,36 2015-03-19 21:32:53,17 2015-03-19 21:37:53,18 2015-03-19 21:42:53,27 2015-03-19 21:47:53,28 2015-03-19 21:52:53,20 2015-03-19 21:57:53,21 2015-03-19 22:02:53,20 2015-03-19 22:07:53,17 2015-03-19 22:12:53,13 2015-03-19 22:17:53,33 2015-03-19 22:22:53,18 2015-03-19 22:27:53,40 2015-03-19 22:32:53,28 2015-03-19 22:37:53,22 2015-03-19 22:42:53,17 2015-03-19 22:47:53,27 2015-03-19 22:52:53,21 2015-03-19 22:57:53,26 2015-03-19 23:02:53,28 2015-03-19 23:07:53,25 2015-03-19 23:12:53,16 2015-03-19 23:17:53,16 2015-03-19 23:22:53,26 2015-03-19 23:27:53,17 2015-03-19 23:32:53,38 2015-03-19 23:37:53,37 2015-03-19 23:42:53,33 2015-03-19 23:47:53,22 2015-03-19 23:52:53,25 2015-03-19 23:57:53,20 2015-03-20 00:02:53,21 2015-03-20 00:07:53,16 2015-03-20 00:12:53,40 2015-03-20 00:17:53,40 2015-03-20 00:22:53,30 2015-03-20 00:27:53,20 2015-03-20 00:32:53,17 2015-03-20 00:37:53,30 2015-03-20 00:42:53,23 2015-03-20 00:47:53,12 2015-03-20 00:52:53,18 2015-03-20 00:57:53,33 2015-03-20 01:02:53,15 2015-03-20 01:07:53,30 2015-03-20 01:12:53,27 2015-03-20 01:17:53,18 2015-03-20 01:22:53,27 2015-03-20 01:27:53,21 2015-03-20 01:32:53,20 2015-03-20 01:37:53,27 2015-03-20 01:42:53,29 2015-03-20 01:47:53,20 2015-03-20 01:52:53,32 2015-03-20 01:57:53,27 2015-03-20 02:02:53,26 2015-03-20 02:07:53,24 2015-03-20 02:12:53,13 2015-03-20 02:17:53,11 2015-03-20 02:22:53,15 2015-03-20 02:27:53,15 2015-03-20 02:32:53,10 2015-03-20 02:37:53,23 2015-03-20 02:42:53,9 2015-03-20 02:47:53,13 2015-03-20 02:52:53,14 2015-03-20 02:57:53,30 2015-03-20 03:02:53,19 2015-03-20 03:07:53,20 2015-03-20 03:12:53,19 2015-03-20 03:17:53,81 2015-03-20 03:22:53,34 2015-03-20 03:27:53,32 2015-03-20 03:32:53,13 2015-03-20 03:37:53,16 2015-03-20 03:42:53,12 2015-03-20 03:47:53,11 2015-03-20 03:52:53,7 2015-03-20 03:57:53,12 2015-03-20 04:02:53,14 2015-03-20 04:07:53,7 2015-03-20 04:12:53,7 2015-03-20 04:17:53,8 2015-03-20 04:22:53,18 2015-03-20 04:27:53,25 2015-03-20 04:32:53,14 2015-03-20 04:37:53,15 2015-03-20 04:42:53,12 2015-03-20 04:47:53,15 2015-03-20 04:52:53,12 2015-03-20 04:57:53,18 2015-03-20 05:02:53,9 2015-03-20 05:07:53,17 2015-03-20 05:12:53,14 2015-03-20 05:17:53,7 2015-03-20 05:22:53,12 2015-03-20 05:27:53,12 2015-03-20 05:32:53,5 2015-03-20 05:37:53,7 2015-03-20 05:42:53,9 2015-03-20 05:47:53,15 2015-03-20 05:52:53,11 2015-03-20 05:57:53,26 2015-03-20 06:02:53,15 2015-03-20 06:07:53,14 2015-03-20 06:12:53,20 2015-03-20 06:17:53,14 2015-03-20 06:22:53,7 2015-03-20 06:27:53,8 2015-03-20 06:32:53,9 2015-03-20 06:37:53,12 2015-03-20 06:42:53,8 2015-03-20 06:47:53,11 2015-03-20 06:52:53,9 2015-03-20 06:57:53,11 2015-03-20 07:02:53,15 2015-03-20 07:07:53,5 2015-03-20 07:12:53,22 2015-03-20 07:17:53,23 2015-03-20 07:22:53,19 2015-03-20 07:27:53,26 2015-03-20 07:32:53,13 2015-03-20 07:37:53,9 2015-03-20 07:42:53,9 2015-03-20 07:47:53,6 2015-03-20 07:52:53,13 2015-03-20 07:57:53,15 2015-03-20 08:02:53,16 2015-03-20 08:07:53,12 2015-03-20 08:12:53,27 2015-03-20 08:17:53,12 2015-03-20 08:22:53,9 2015-03-20 08:27:53,16 2015-03-20 08:32:53,11 2015-03-20 08:37:53,10 2015-03-20 08:42:53,8 2015-03-20 08:47:53,20 2015-03-20 08:52:53,13 2015-03-20 08:57:53,21 2015-03-20 09:02:53,21 2015-03-20 09:07:53,25 2015-03-20 09:12:53,14 2015-03-20 09:17:53,12 2015-03-20 09:22:53,11 2015-03-20 09:27:53,12 2015-03-20 09:32:53,21 2015-03-20 09:37:53,14 2015-03-20 09:42:53,17 2015-03-20 09:47:53,16 2015-03-20 09:52:53,22 2015-03-20 09:57:53,20 2015-03-20 10:02:53,13 2015-03-20 10:07:53,11 2015-03-20 10:12:53,17 2015-03-20 10:17:53,15 2015-03-20 10:22:53,14 2015-03-20 10:27:53,18 2015-03-20 10:32:53,19 2015-03-20 10:37:53,8 2015-03-20 10:42:53,12 2015-03-20 10:47:53,13 2015-03-20 10:52:53,18 2015-03-20 10:57:53,16 2015-03-20 11:02:53,11 2015-03-20 11:07:53,12 2015-03-20 11:12:53,10 2015-03-20 11:17:53,14 2015-03-20 11:22:53,19 2015-03-20 11:27:53,16 2015-03-20 11:32:53,13 2015-03-20 11:37:53,21 2015-03-20 11:42:53,20 2015-03-20 11:47:53,21 2015-03-20 11:52:53,19 2015-03-20 11:57:53,26 2015-03-20 12:02:53,17 2015-03-20 12:07:53,25 2015-03-20 12:12:53,33 2015-03-20 12:17:53,21 2015-03-20 12:22:53,17 2015-03-20 12:27:53,27 2015-03-20 12:32:53,15 2015-03-20 12:37:53,12 2015-03-20 12:42:53,36 2015-03-20 12:47:53,19 2015-03-20 12:52:53,22 2015-03-20 12:57:53,27 2015-03-20 13:02:53,19 2015-03-20 13:07:53,20 2015-03-20 13:12:53,21 2015-03-20 13:17:53,25 2015-03-20 13:22:53,30 2015-03-20 13:27:53,16 2015-03-20 13:32:53,19 2015-03-20 13:37:53,35 2015-03-20 13:42:53,33 2015-03-20 13:47:53,34 2015-03-20 13:52:53,29 2015-03-20 13:57:53,53 2015-03-20 14:02:53,39 2015-03-20 14:07:53,30 2015-03-20 14:12:53,34 2015-03-20 14:17:53,30 2015-03-20 14:22:53,58 2015-03-20 14:27:53,41 2015-03-20 14:32:53,18 2015-03-20 14:37:53,24 2015-03-20 14:42:53,29 2015-03-20 14:47:53,31 2015-03-20 14:52:53,15 2015-03-20 14:57:53,45 2015-03-20 15:02:53,33 2015-03-20 15:07:53,23 2015-03-20 15:12:53,31 2015-03-20 15:17:53,33 2015-03-20 15:22:53,38 2015-03-20 15:27:53,22 2015-03-20 15:32:53,38 2015-03-20 15:37:53,33 2015-03-20 15:42:53,40 2015-03-20 15:47:53,28 2015-03-20 15:52:53,23 2015-03-20 15:57:53,64 2015-03-20 16:02:53,47 2015-03-20 16:07:53,34 2015-03-20 16:12:53,24 2015-03-20 16:17:53,29 2015-03-20 16:22:53,30 2015-03-20 16:27:53,54 2015-03-20 16:32:53,42 2015-03-20 16:37:53,31 2015-03-20 16:42:53,43 2015-03-20 16:47:53,41 2015-03-20 16:52:53,78 2015-03-20 16:57:53,59 2015-03-20 17:02:53,38 2015-03-20 17:07:53,41 2015-03-20 17:12:53,24 2015-03-20 17:17:53,70 2015-03-20 17:22:53,67 2015-03-20 17:27:53,40 2015-03-20 17:32:53,31 2015-03-20 17:37:53,40 2015-03-20 17:42:53,94 2015-03-20 17:47:53,30 2015-03-20 17:52:53,23 2015-03-20 17:57:53,28 2015-03-20 18:02:53,40 2015-03-20 18:07:53,42 2015-03-20 18:12:53,53 2015-03-20 18:17:53,55 2015-03-20 18:22:53,45 2015-03-20 18:27:53,55 2015-03-20 18:32:53,50 2015-03-20 18:37:53,50 2015-03-20 18:42:53,48 2015-03-20 18:47:53,51 2015-03-20 18:52:53,24 2015-03-20 18:57:53,22 2015-03-20 19:02:53,32 2015-03-20 19:07:53,26 2015-03-20 19:12:53,42 2015-03-20 19:17:53,34 2015-03-20 19:22:53,43 2015-03-20 19:27:53,33 2015-03-20 19:32:53,29 2015-03-20 19:37:53,33 2015-03-20 19:42:53,28 2015-03-20 19:47:53,27 2015-03-20 19:52:53,29 2015-03-20 19:57:53,35 2015-03-20 20:02:53,38 2015-03-20 20:07:53,36 2015-03-20 20:12:53,43 2015-03-20 20:17:53,36 2015-03-20 20:22:53,34 2015-03-20 20:27:53,19 2015-03-20 20:32:53,21 2015-03-20 20:37:53,25 2015-03-20 20:42:53,20 2015-03-20 20:47:53,16 2015-03-20 20:52:53,38 2015-03-20 20:57:53,23 2015-03-20 21:02:53,26 2015-03-20 21:07:53,21 2015-03-20 21:12:53,31 2015-03-20 21:17:53,27 2015-03-20 21:22:53,25 2015-03-20 21:27:53,32 2015-03-20 21:32:53,19 2015-03-20 21:37:53,38 2015-03-20 21:42:53,33 2015-03-20 21:47:53,30 2015-03-20 21:52:53,26 2015-03-20 21:57:53,45 2015-03-20 22:02:53,36 2015-03-20 22:07:53,27 2015-03-20 22:12:53,25 2015-03-20 22:17:53,21 2015-03-20 22:22:53,22 2015-03-20 22:27:53,17 2015-03-20 22:32:53,22 2015-03-20 22:37:53,15 2015-03-20 22:42:53,25 2015-03-20 22:47:53,18 2015-03-20 22:52:53,26 2015-03-20 22:57:53,16 2015-03-20 23:02:53,14 2015-03-20 23:07:53,11 2015-03-20 23:12:53,24 2015-03-20 23:17:53,24 2015-03-20 23:22:53,17 2015-03-20 23:27:53,27 2015-03-20 23:32:53,31 2015-03-20 23:37:53,26 2015-03-20 23:42:53,22 2015-03-20 23:47:53,24 2015-03-20 23:52:53,25 2015-03-20 23:57:53,46 2015-03-21 00:02:53,47 2015-03-21 00:07:53,50 2015-03-21 00:12:53,29 2015-03-21 00:17:53,35 2015-03-21 00:22:53,55 2015-03-21 00:27:53,54 2015-03-21 00:32:53,62 2015-03-21 00:37:53,30 2015-03-21 00:42:53,44 2015-03-21 00:47:53,21 2015-03-21 00:52:53,17 2015-03-21 00:57:53,22 2015-03-21 01:02:53,21 2015-03-21 01:07:53,14 2015-03-21 01:12:53,16 2015-03-21 01:17:53,26 2015-03-21 01:22:53,28 2015-03-21 01:27:53,20 2015-03-21 01:32:53,26 2015-03-21 01:37:53,14 2015-03-21 01:42:53,19 2015-03-21 01:47:53,15 2015-03-21 01:52:53,24 2015-03-21 01:57:53,24 2015-03-21 02:02:53,22 2015-03-21 02:07:53,14 2015-03-21 02:12:53,19 2015-03-21 02:17:53,12 2015-03-21 02:22:53,19 2015-03-21 02:27:53,11 2015-03-21 02:32:53,24 2015-03-21 02:37:53,12 2015-03-21 02:42:53,21 2015-03-21 02:47:53,8 2015-03-21 02:52:53,13 2015-03-21 02:57:53,9 2015-03-21 03:02:53,11 2015-03-21 03:07:53,12 2015-03-21 03:12:53,14 2015-03-21 03:17:53,11 2015-03-21 03:22:53,13 2015-03-21 03:27:53,10 2015-03-21 03:32:53,12 2015-03-21 03:37:53,5 2015-03-21 03:42:53,9 2015-03-21 03:47:53,12 2015-03-21 03:52:53,15 2015-03-21 03:57:53,12 2015-03-21 04:02:53,7 2015-03-21 04:07:53,7 2015-03-21 04:12:53,19 2015-03-21 04:17:53,10 2015-03-21 04:22:53,12 2015-03-21 04:27:53,9 2015-03-21 04:32:53,5 2015-03-21 04:37:53,13 2015-03-21 04:42:53,9 2015-03-21 04:47:53,9 2015-03-21 04:52:53,17 2015-03-21 04:57:53,17 2015-03-21 05:02:53,8 2015-03-21 05:07:53,1 2015-03-21 05:12:53,8 2015-03-21 05:17:53,14 2015-03-21 05:22:53,12 2015-03-21 05:27:53,9 2015-03-21 05:32:53,4 2015-03-21 05:37:53,6 2015-03-21 05:42:53,6 2015-03-21 05:47:53,12 2015-03-21 05:52:53,10 2015-03-21 05:57:53,9 2015-03-21 06:02:53,18 2015-03-21 06:07:53,5 2015-03-21 06:12:53,9 2015-03-21 06:17:53,17 2015-03-21 06:22:53,16 2015-03-21 06:27:53,17 2015-03-21 06:32:53,12 2015-03-21 06:37:53,5 2015-03-21 06:42:53,12 2015-03-21 06:47:53,8 2015-03-21 06:52:53,12 2015-03-21 06:57:53,17 2015-03-21 07:02:53,7 2015-03-21 07:07:53,19 2015-03-21 07:12:53,13 2015-03-21 07:17:53,11 2015-03-21 07:22:53,14 2015-03-21 07:27:53,28 2015-03-21 07:32:53,9 2015-03-21 07:37:53,4 2015-03-21 07:42:53,12 2015-03-21 07:47:53,13 2015-03-21 07:52:53,12 2015-03-21 07:57:53,6 2015-03-21 08:02:53,10 2015-03-21 08:07:53,14 2015-03-21 08:12:53,19 2015-03-21 08:17:53,11 2015-03-21 08:22:53,14 2015-03-21 08:27:53,16 2015-03-21 08:32:53,20 2015-03-21 08:37:53,22 2015-03-21 08:42:53,20 2015-03-21 08:47:53,10 2015-03-21 08:52:53,18 2015-03-21 08:57:53,18 2015-03-21 09:02:53,15 2015-03-21 09:07:53,15 2015-03-21 09:12:53,10 2015-03-21 09:17:53,13 2015-03-21 09:22:53,5 2015-03-21 09:27:53,11 2015-03-21 09:32:53,7 2015-03-21 09:37:53,13 2015-03-21 09:42:53,10 2015-03-21 09:47:53,5 2015-03-21 09:52:53,10 2015-03-21 09:57:53,13 2015-03-21 10:02:53,9 2015-03-21 10:07:53,9 2015-03-21 10:12:53,22 2015-03-21 10:17:53,14 2015-03-21 10:22:53,4 2015-03-21 10:27:53,9 2015-03-21 10:32:53,8 2015-03-21 10:37:53,4 2015-03-21 10:42:53,3 2015-03-21 10:47:53,3 2015-03-21 10:52:53,5 2015-03-21 10:57:53,16 2015-03-21 11:02:53,8 2015-03-21 11:07:53,12 2015-03-21 11:12:53,7 2015-03-21 11:17:53,7 2015-03-21 11:22:53,4 2015-03-21 11:27:53,5 2015-03-21 11:32:53,14 2015-03-21 11:37:53,6 2015-03-21 11:42:53,20 2015-03-21 11:47:53,9 2015-03-21 11:52:53,9 2015-03-21 11:57:53,16 2015-03-21 12:02:53,10 2015-03-21 12:07:53,9 2015-03-21 12:12:53,13 2015-03-21 12:17:53,11 2015-03-21 12:22:53,16 2015-03-21 12:27:53,11 2015-03-21 12:32:53,9 2015-03-21 12:37:53,13 2015-03-21 12:42:53,17 2015-03-21 12:47:53,11 2015-03-21 12:52:53,1 2015-03-21 12:57:53,11 2015-03-21 13:02:53,14 2015-03-21 13:07:53,5 2015-03-21 13:12:53,12 2015-03-21 13:17:53,11 2015-03-21 13:22:53,5 2015-03-21 13:27:53,15 2015-03-21 13:32:53,21 2015-03-21 13:37:53,9 2015-03-21 13:42:53,15 2015-03-21 13:47:53,15 2015-03-21 13:52:53,13 2015-03-21 13:57:53,10 2015-03-21 14:02:53,15 2015-03-21 14:07:53,12 2015-03-21 14:12:53,11 2015-03-21 14:17:53,14 2015-03-21 14:22:53,10 2015-03-21 14:27:53,5 2015-03-21 14:32:53,13 2015-03-21 14:37:53,14 2015-03-21 14:42:53,7 2015-03-21 14:47:53,17 2015-03-21 14:52:53,20 2015-03-21 14:57:53,23 2015-03-21 15:02:53,16 2015-03-21 15:07:53,21 2015-03-21 15:12:53,24 2015-03-21 15:17:53,11 2015-03-21 15:22:53,18 2015-03-21 15:27:53,17 2015-03-21 15:32:53,7 2015-03-21 15:37:53,19 2015-03-21 15:42:53,17 2015-03-21 15:47:53,17 2015-03-21 15:52:53,5 2015-03-21 15:57:53,13 2015-03-21 16:02:53,17 2015-03-21 16:07:53,24 2015-03-21 16:12:53,11 2015-03-21 16:17:53,11 2015-03-21 16:22:53,11 2015-03-21 16:27:53,10 2015-03-21 16:32:53,16 2015-03-21 16:37:53,16 2015-03-21 16:42:53,26 2015-03-21 16:47:53,24 2015-03-21 16:52:53,12 2015-03-21 16:57:53,13 2015-03-21 17:02:53,18 2015-03-21 17:07:53,8 2015-03-21 17:12:53,12 2015-03-21 17:17:53,5 2015-03-21 17:22:53,19 2015-03-21 17:27:53,14 2015-03-21 17:32:53,17 2015-03-21 17:37:53,16 2015-03-21 17:42:53,24 2015-03-21 17:47:53,21 2015-03-21 17:52:53,9 2015-03-21 17:57:53,22 2015-03-21 18:02:53,10 2015-03-21 18:07:53,9 2015-03-21 18:12:53,15 2015-03-21 18:17:53,8 2015-03-21 18:22:53,14 2015-03-21 18:27:53,9 2015-03-21 18:32:53,10 2015-03-21 18:37:53,15 2015-03-21 18:42:53,11 2015-03-21 18:47:53,20 2015-03-21 18:52:53,13 2015-03-21 18:57:53,26 2015-03-21 19:02:53,19 2015-03-21 19:07:53,16 2015-03-21 19:12:53,10 2015-03-21 19:17:53,15 2015-03-21 19:22:53,9 2015-03-21 19:27:53,11 2015-03-21 19:32:53,15 2015-03-21 19:37:53,20 2015-03-21 19:42:53,26 2015-03-21 19:47:53,15 2015-03-21 19:52:53,17 2015-03-21 19:57:53,20 2015-03-21 20:02:53,9 2015-03-21 20:07:53,9 2015-03-21 20:12:53,22 2015-03-21 20:17:53,13 2015-03-21 20:22:53,10 2015-03-21 20:27:53,14 2015-03-21 20:32:53,11 2015-03-21 20:37:53,17 2015-03-21 20:42:53,9 2015-03-21 20:47:53,11 2015-03-21 20:52:53,18 2015-03-21 20:57:53,15 2015-03-21 21:02:53,6 2015-03-21 21:07:53,11 2015-03-21 21:12:53,3 2015-03-21 21:17:53,7 2015-03-21 21:22:53,13 2015-03-21 21:27:53,15 2015-03-21 21:32:53,8 2015-03-21 21:37:53,10 2015-03-21 21:42:53,20 2015-03-21 21:47:53,12 2015-03-21 21:52:53,17 2015-03-21 21:57:53,14 2015-03-21 22:02:53,14 2015-03-21 22:07:53,3 2015-03-21 22:12:53,14 2015-03-21 22:17:53,1 2015-03-21 22:22:53,9 2015-03-21 22:27:53,15 2015-03-21 22:32:53,10 2015-03-21 22:37:53,4 2015-03-21 22:42:53,9 2015-03-21 22:47:53,12 2015-03-21 22:52:53,11 2015-03-21 22:57:53,17 2015-03-21 23:02:53,14 2015-03-21 23:07:53,9 2015-03-21 23:12:53,12 2015-03-21 23:17:53,12 2015-03-21 23:22:53,6 2015-03-21 23:27:53,4 2015-03-21 23:32:53,13 2015-03-21 23:37:53,10 2015-03-21 23:42:53,9 2015-03-21 23:47:53,20 2015-03-21 23:52:53,9 2015-03-21 23:57:53,14 2015-03-22 00:02:53,15 2015-03-22 00:07:53,14 2015-03-22 00:12:53,2 2015-03-22 00:17:53,8 2015-03-22 00:22:53,9 2015-03-22 00:27:53,8 2015-03-22 00:32:53,7 2015-03-22 00:37:53,7 2015-03-22 00:42:53,7 2015-03-22 00:47:53,15 2015-03-22 00:52:53,8 2015-03-22 00:57:53,6 2015-03-22 01:02:53,6 2015-03-22 01:07:53,5 2015-03-22 01:12:53,7 2015-03-22 01:17:53,8 2015-03-22 01:22:53,10 2015-03-22 01:27:53,15 2015-03-22 01:32:53,10 2015-03-22 01:37:53,7 2015-03-22 01:42:53,4 2015-03-22 01:47:53,7 2015-03-22 01:52:53,7 2015-03-22 01:57:53,16 2015-03-22 02:02:53,3 2015-03-22 02:07:53,5 2015-03-22 02:12:53,5 2015-03-22 02:17:53,5 2015-03-22 02:22:53,6 2015-03-22 02:27:53,11 2015-03-22 02:32:53,8 2015-03-22 02:37:53,2 2015-03-22 02:42:53,5 2015-03-22 02:47:53,4 2015-03-22 02:52:53,12 2015-03-22 02:57:53,5 2015-03-22 03:02:53,17 2015-03-22 03:07:53,3 2015-03-22 03:12:53,4 2015-03-22 03:17:53,5 2015-03-22 03:22:53,8 2015-03-22 03:27:53,15 2015-03-22 03:32:53,7 2015-03-22 03:37:53,4 2015-03-22 03:42:53,14 2015-03-22 03:47:53,3 2015-03-22 03:52:53,3 2015-03-22 03:57:53,3 2015-03-22 04:02:53,6 2015-03-22 04:07:53,1 2015-03-22 04:12:53,1 2015-03-22 04:17:53,10 2015-03-22 04:22:53,3 2015-03-22 04:27:53,6 2015-03-22 04:32:53,3 2015-03-22 04:37:53,3 2015-03-22 04:42:53,7 2015-03-22 04:47:53,10 2015-03-22 04:52:53,11 2015-03-22 04:57:53,4 2015-03-22 05:02:53,2 2015-03-22 05:07:53,4 2015-03-22 05:12:53,3 2015-03-22 05:17:53,3 2015-03-22 05:22:53,8 2015-03-22 05:27:53,2 2015-03-22 05:32:53,4 2015-03-22 05:37:53,7 2015-03-22 05:42:53,7 2015-03-22 05:47:53,3 2015-03-22 05:52:53,3 2015-03-22 05:57:53,13 2015-03-22 06:02:53,7 2015-03-22 06:07:53,16 2015-03-22 06:12:53,5 2015-03-22 06:17:53,7 2015-03-22 06:22:53,5 2015-03-22 06:27:53,4 2015-03-22 06:32:53,6 2015-03-22 06:37:53,4 2015-03-22 06:42:53,5 2015-03-22 06:47:53,6 2015-03-22 06:52:53,1 2015-03-22 06:57:53,4 2015-03-22 07:02:53,7 2015-03-22 07:07:53,5 2015-03-22 07:12:53,5 2015-03-22 07:17:53,2 2015-03-22 07:22:53,3 2015-03-22 07:27:53,1 2015-03-22 07:32:53,0 2015-03-22 07:37:53,9 2015-03-22 07:42:53,10 2015-03-22 07:47:53,11 2015-03-22 07:52:53,8 2015-03-22 07:57:53,7 2015-03-22 08:02:53,7 2015-03-22 08:07:53,9 2015-03-22 08:12:53,11 2015-03-22 08:17:53,2 2015-03-22 08:22:53,14 2015-03-22 08:27:53,6 2015-03-22 08:32:53,4 2015-03-22 08:37:53,6 2015-03-22 08:42:53,6 2015-03-22 08:47:53,6 2015-03-22 08:52:53,6 2015-03-22 08:57:53,18 2015-03-22 09:02:53,2 2015-03-22 09:07:53,6 2015-03-22 09:12:53,6 2015-03-22 09:17:53,8 2015-03-22 09:22:53,10 2015-03-22 09:27:53,8 2015-03-22 09:32:53,8 2015-03-22 09:37:53,2 2015-03-22 09:42:53,8 2015-03-22 09:47:53,10 2015-03-22 09:52:53,4 2015-03-22 09:57:53,6 2015-03-22 10:02:53,11 2015-03-22 10:07:53,5 2015-03-22 10:12:53,2 2015-03-22 10:17:53,6 2015-03-22 10:22:53,4 2015-03-22 10:27:53,5 2015-03-22 10:32:53,2 2015-03-22 10:37:53,0 2015-03-22 10:42:53,8 2015-03-22 10:47:53,6 2015-03-22 10:52:53,13 2015-03-22 10:57:53,7 2015-03-22 11:02:53,7 2015-03-22 11:07:53,20 2015-03-22 11:12:53,15 2015-03-22 11:17:53,33 2015-03-22 11:22:53,49 2015-03-22 11:27:53,25 2015-03-22 11:32:53,6 2015-03-22 11:37:53,5 2015-03-22 11:42:53,2 2015-03-22 11:47:53,8 2015-03-22 11:52:53,7 2015-03-22 11:57:53,4 2015-03-22 12:02:53,5 2015-03-22 12:07:53,4 2015-03-22 12:12:53,2 2015-03-22 12:17:53,15 2015-03-22 12:22:53,47 2015-03-22 12:27:53,6 2015-03-22 12:32:53,7 2015-03-22 12:37:53,3 2015-03-22 12:42:53,14 2015-03-22 12:47:53,6 2015-03-22 12:52:53,7 2015-03-22 12:57:53,10 2015-03-22 13:02:53,5 2015-03-22 13:07:53,13 2015-03-22 13:12:53,9 2015-03-22 13:17:53,5 2015-03-22 13:22:53,6 2015-03-22 13:27:53,5 2015-03-22 13:32:53,2 2015-03-22 13:37:53,51 2015-03-22 13:42:53,10 2015-03-22 13:47:53,7 2015-03-22 13:52:53,7 2015-03-22 13:57:53,7 2015-03-22 14:02:53,14 2015-03-22 14:07:53,10 2015-03-22 14:12:53,10 2015-03-22 14:17:53,23 2015-03-22 14:22:53,13 2015-03-22 14:27:53,19 2015-03-22 14:32:53,5 2015-03-22 14:37:53,20 2015-03-22 14:42:53,10 2015-03-22 14:47:53,9 2015-03-22 14:52:53,9 2015-03-22 14:57:53,12 2015-03-22 15:02:53,7 2015-03-22 15:07:53,19 2015-03-22 15:12:53,12 2015-03-22 15:17:53,8 2015-03-22 15:22:53,8 2015-03-22 15:27:53,38 2015-03-22 15:32:53,21 2015-03-22 15:37:53,8 2015-03-22 15:42:53,14 2015-03-22 15:47:53,20 2015-03-22 15:52:53,11 2015-03-22 15:57:53,9 2015-03-22 16:02:53,17 2015-03-22 16:07:53,9 2015-03-22 16:12:53,9 2015-03-22 16:17:53,20 2015-03-22 16:22:53,16 2015-03-22 16:27:53,15 2015-03-22 16:32:53,17 2015-03-22 16:37:53,17 2015-03-22 16:42:53,12 2015-03-22 16:47:53,9 2015-03-22 16:52:53,8 2015-03-22 16:57:53,15 2015-03-22 17:02:53,11 2015-03-22 17:07:53,13 2015-03-22 17:12:53,13 2015-03-22 17:17:53,14 2015-03-22 17:22:53,15 2015-03-22 17:27:53,14 2015-03-22 17:32:53,21 2015-03-22 17:37:53,9 2015-03-22 17:42:53,10 2015-03-22 17:47:53,14 2015-03-22 17:52:53,4 2015-03-22 17:57:53,13 2015-03-22 18:02:53,14 2015-03-22 18:07:53,12 2015-03-22 18:12:53,15 2015-03-22 18:17:53,7 2015-03-22 18:22:53,8 2015-03-22 18:27:53,12 2015-03-22 18:32:53,11 2015-03-22 18:37:53,15 2015-03-22 18:42:53,9 2015-03-22 18:47:53,14 2015-03-22 18:52:53,7 2015-03-22 18:57:53,14 2015-03-22 19:02:53,12 2015-03-22 19:07:53,8 2015-03-22 19:12:53,67 2015-03-22 19:17:53,5 2015-03-22 19:22:53,8 2015-03-22 19:27:53,11 2015-03-22 19:32:53,3 2015-03-22 19:37:53,13 2015-03-22 19:42:53,20 2015-03-22 19:47:53,9 2015-03-22 19:52:53,13 2015-03-22 19:57:53,12 2015-03-22 20:02:53,31 2015-03-22 20:07:53,21 2015-03-22 20:12:53,27 2015-03-22 20:17:53,18 2015-03-22 20:22:53,25 2015-03-22 20:27:53,20 2015-03-22 20:32:53,28 2015-03-22 20:37:53,20 2015-03-22 20:42:53,25 2015-03-22 20:47:53,20 2015-03-22 20:52:53,16 2015-03-22 20:57:53,21 2015-03-22 21:02:53,67 2015-03-22 21:07:53,23 2015-03-22 21:12:53,32 2015-03-22 21:17:53,19 2015-03-22 21:22:53,26 2015-03-22 21:27:53,18 2015-03-22 21:32:53,21 2015-03-22 21:37:53,25 2015-03-22 21:42:53,15 2015-03-22 21:47:53,12 2015-03-22 21:52:53,9 2015-03-22 21:57:53,14 2015-03-22 22:02:53,18 2015-03-22 22:07:53,9 2015-03-22 22:12:53,11 2015-03-22 22:17:53,14 2015-03-22 22:22:53,9 2015-03-22 22:27:53,30 2015-03-22 22:32:53,32 2015-03-22 22:37:53,6 2015-03-22 22:42:53,12 2015-03-22 22:47:53,9 2015-03-22 22:52:53,50 2015-03-22 22:57:53,9 2015-03-22 23:02:53,9 2015-03-22 23:07:53,6 2015-03-22 23:12:53,14 2015-03-22 23:17:53,9 2015-03-22 23:22:53,53 2015-03-22 23:27:53,17 2015-03-22 23:32:53,9 2015-03-22 23:37:53,5 2015-03-22 23:42:53,6 2015-03-22 23:47:53,9 2015-03-22 23:52:53,13 2015-03-22 23:57:53,11 2015-03-23 00:02:53,12 2015-03-23 00:07:53,10 2015-03-23 00:12:53,11 2015-03-23 00:17:53,4 2015-03-23 00:22:53,8 2015-03-23 00:27:53,4 2015-03-23 00:32:53,9 2015-03-23 00:37:53,7 2015-03-23 00:42:53,9 2015-03-23 00:47:53,18 2015-03-23 00:52:53,7 2015-03-23 00:57:53,9 2015-03-23 01:02:53,6 2015-03-23 01:07:53,12 2015-03-23 01:12:53,11 2015-03-23 01:17:53,7 2015-03-23 01:22:53,13 2015-03-23 01:27:53,6 2015-03-23 01:32:53,7 2015-03-23 01:37:53,53 2015-03-23 01:42:53,4 2015-03-23 01:47:53,46 2015-03-23 01:52:53,7 2015-03-23 01:57:53,10 2015-03-23 02:02:53,9 2015-03-23 02:07:53,2 2015-03-23 02:12:53,14 2015-03-23 02:17:53,16 2015-03-23 02:22:53,5 2015-03-23 02:27:53,1 2015-03-23 02:32:53,14 2015-03-23 02:37:53,7 2015-03-23 02:42:53,7 2015-03-23 02:47:53,7 2015-03-23 02:52:53,7 2015-03-23 02:57:53,7 2015-03-23 03:02:53,13 2015-03-23 03:07:53,5 2015-03-23 03:12:53,4 2015-03-23 03:17:53,4 2015-03-23 03:22:53,7 2015-03-23 03:27:53,11 2015-03-23 03:32:53,7 2015-03-23 03:37:53,0 2015-03-23 03:42:53,10 2015-03-23 03:47:53,7 2015-03-23 03:52:53,8 2015-03-23 03:57:53,8 2015-03-23 04:02:53,3 2015-03-23 04:07:53,3 2015-03-23 04:12:53,11 2015-03-23 04:17:53,4 2015-03-23 04:22:53,15 2015-03-23 04:27:53,13 2015-03-23 04:32:53,10 2015-03-23 04:37:53,13 2015-03-23 04:42:53,8 2015-03-23 04:47:53,3 2015-03-23 04:52:53,19 2015-03-23 04:57:53,50 2015-03-23 05:02:53,7 2015-03-23 05:07:53,4 2015-03-23 05:12:53,15 2015-03-23 05:17:53,1 2015-03-23 05:22:53,7 2015-03-23 05:27:53,6 2015-03-23 05:32:53,10 2015-03-23 05:37:53,5 2015-03-23 05:42:53,13 2015-03-23 05:47:53,4 2015-03-23 05:52:53,47 2015-03-23 05:57:53,14 2015-03-23 06:02:53,5 2015-03-23 06:07:53,7 2015-03-23 06:12:53,7 2015-03-23 06:17:53,10 2015-03-23 06:22:53,11 2015-03-23 06:27:53,5 2015-03-23 06:32:53,4 2015-03-23 06:37:53,5 2015-03-23 06:42:53,13 2015-03-23 06:47:53,2 2015-03-23 06:52:53,5 2015-03-23 06:57:53,12 2015-03-23 07:02:53,15 2015-03-23 07:07:53,10 2015-03-23 07:12:53,6 2015-03-23 07:17:53,7 2015-03-23 07:22:53,9 2015-03-23 07:27:53,22 2015-03-23 07:32:53,3 2015-03-23 07:37:53,8 2015-03-23 07:42:53,8 2015-03-23 07:47:53,11 2015-03-23 07:52:53,11 2015-03-23 07:57:53,12 2015-03-23 08:02:53,9 2015-03-23 08:07:53,10 2015-03-23 08:12:53,10 2015-03-23 08:17:53,16 2015-03-23 08:22:53,8 2015-03-23 08:27:53,10 2015-03-23 08:32:53,4 2015-03-23 08:37:53,8 2015-03-23 08:42:53,14 2015-03-23 08:47:53,8 2015-03-23 08:52:53,20 2015-03-23 08:57:53,16 2015-03-23 09:02:53,12 2015-03-23 09:07:53,14 2015-03-23 09:12:53,52 2015-03-23 09:17:53,21 2015-03-23 09:22:53,7 2015-03-23 09:27:53,10 2015-03-23 09:32:53,10 2015-03-23 09:37:53,15 2015-03-23 09:42:53,50 2015-03-23 09:47:53,14 2015-03-23 09:52:53,20 2015-03-23 09:57:53,21 2015-03-23 10:02:53,17 2015-03-23 10:07:53,26 2015-03-23 10:12:53,10 2015-03-23 10:17:53,20 2015-03-23 10:22:53,21 2015-03-23 10:27:53,12 2015-03-23 10:32:53,16 2015-03-23 10:37:53,8 2015-03-23 10:42:53,13 2015-03-23 10:47:53,14 2015-03-23 10:52:53,15 2015-03-23 10:57:53,13 2015-03-23 11:02:53,17 2015-03-23 11:07:53,22 2015-03-23 11:12:53,21 2015-03-23 11:17:53,18 2015-03-23 11:22:53,18 2015-03-23 11:27:53,16 2015-03-23 11:32:53,13 2015-03-23 11:37:53,13 2015-03-23 11:42:53,8 2015-03-23 11:47:53,8 2015-03-23 11:52:53,16 2015-03-23 11:57:53,66 2015-03-23 12:02:53,18 2015-03-23 12:07:53,17 2015-03-23 12:12:53,10 2015-03-23 12:17:53,14 2015-03-23 12:22:53,10 2015-03-23 12:27:53,19 2015-03-23 12:32:53,15 2015-03-23 12:37:53,13 2015-03-23 12:42:53,11 2015-03-23 12:47:53,15 2015-03-23 12:52:53,9 2015-03-23 12:57:53,20 2015-03-23 13:02:53,35 2015-03-23 13:07:53,29 2015-03-23 13:12:53,14 2015-03-23 13:17:53,18 2015-03-23 13:22:53,28 2015-03-23 13:27:53,40 2015-03-23 13:32:53,22 2015-03-23 13:37:53,13 2015-03-23 13:42:53,24 2015-03-23 13:47:53,21 2015-03-23 13:52:53,22 2015-03-23 13:57:53,24 2015-03-23 14:02:53,29 2015-03-23 14:07:53,26 2015-03-23 14:12:53,25 2015-03-23 14:17:53,37 2015-03-23 14:22:53,16 2015-03-23 14:27:53,29 2015-03-23 14:32:53,24 2015-03-23 14:37:53,41 2015-03-23 14:42:53,32 2015-03-23 14:47:53,21 2015-03-23 14:52:53,30 2015-03-23 14:57:53,32 2015-03-23 15:02:53,76 2015-03-23 15:07:53,32 2015-03-23 15:12:53,27 2015-03-23 15:17:53,25 2015-03-23 15:22:53,21 2015-03-23 15:27:53,42 2015-03-23 15:32:53,27 2015-03-23 15:37:53,66 2015-03-23 15:42:53,28 2015-03-23 15:47:53,29 2015-03-23 15:52:53,25 2015-03-23 15:57:53,51 2015-03-23 16:02:53,28 2015-03-23 16:07:53,34 2015-03-23 16:12:53,20 2015-03-23 16:17:53,14 2015-03-23 16:22:53,31 2015-03-23 16:27:53,28 2015-03-23 16:32:53,28 2015-03-23 16:37:53,27 2015-03-23 16:42:53,21 2015-03-23 16:47:53,29 2015-03-23 16:52:53,25 2015-03-23 16:57:53,37 2015-03-23 17:02:53,17 2015-03-23 17:07:53,27 2015-03-23 17:12:53,26 2015-03-23 17:17:53,31 2015-03-23 17:22:53,25 2015-03-23 17:27:53,25 2015-03-23 17:32:53,22 2015-03-23 17:37:53,32 2015-03-23 17:42:53,20 2015-03-23 17:47:53,55 2015-03-23 17:52:53,27 2015-03-23 17:57:53,36 2015-03-23 18:02:53,25 2015-03-23 18:07:53,19 2015-03-23 18:12:53,85 2015-03-23 18:17:53,65 2015-03-23 18:22:53,37 2015-03-23 18:27:53,38 2015-03-23 18:32:53,47 2015-03-23 18:37:53,34 2015-03-23 18:42:53,28 2015-03-23 18:47:53,33 2015-03-23 18:52:53,30 2015-03-23 18:57:53,30 2015-03-23 19:02:53,46 2015-03-23 19:07:53,31 2015-03-23 19:12:53,22 2015-03-23 19:17:53,36 2015-03-23 19:22:53,28 2015-03-23 19:27:53,17 2015-03-23 19:32:53,41 2015-03-23 19:37:53,15 2015-03-23 19:42:53,19 2015-03-23 19:47:53,16 2015-03-23 19:52:53,30 2015-03-23 19:57:53,29 2015-03-23 20:02:53,29 2015-03-23 20:07:53,59 2015-03-23 20:12:53,21 2015-03-23 20:17:53,30 2015-03-23 20:22:53,23 2015-03-23 20:27:53,23 2015-03-23 20:32:53,25 2015-03-23 20:37:53,29 2015-03-23 20:42:53,17 2015-03-23 20:47:53,18 2015-03-23 20:52:53,12 2015-03-23 20:57:53,35 2015-03-23 21:02:53,19 2015-03-23 21:07:53,16 2015-03-23 21:12:53,16 2015-03-23 21:17:53,24 2015-03-23 21:22:53,18 2015-03-23 21:27:53,13 2015-03-23 21:32:53,16 2015-03-23 21:37:53,25 2015-03-23 21:42:53,29 2015-03-23 21:47:53,28 2015-03-23 21:52:53,32 2015-03-23 21:57:53,26 2015-03-23 22:02:53,19 2015-03-23 22:07:53,25 2015-03-23 22:12:53,11 2015-03-23 22:17:53,16 2015-03-23 22:22:53,12 2015-03-23 22:27:53,14 2015-03-23 22:32:53,16 2015-03-23 22:37:53,19 2015-03-23 22:42:53,56 2015-03-23 22:47:53,26 2015-03-23 22:52:53,15 2015-03-23 22:57:53,24 2015-03-23 23:02:53,28 2015-03-23 23:07:53,24 2015-03-23 23:12:53,23 2015-03-23 23:17:53,26 2015-03-23 23:22:53,22 2015-03-23 23:27:53,28 2015-03-23 23:32:53,16 2015-03-23 23:37:53,19 2015-03-23 23:42:53,12 2015-03-23 23:47:53,17 2015-03-23 23:52:53,16 2015-03-23 23:57:53,16 2015-03-24 00:02:53,25 2015-03-24 00:07:53,13 2015-03-24 00:12:53,22 2015-03-24 00:17:53,13 2015-03-24 00:22:53,14 2015-03-24 00:27:53,11 2015-03-24 00:32:53,12 2015-03-24 00:37:53,17 2015-03-24 00:42:53,9 2015-03-24 00:47:53,142 2015-03-24 00:52:53,85 2015-03-24 00:57:53,26 2015-03-24 01:02:53,19 2015-03-24 01:07:53,11 2015-03-24 01:12:53,50 2015-03-24 01:17:53,14 2015-03-24 01:22:53,22 2015-03-24 01:27:53,7 2015-03-24 01:32:53,7 2015-03-24 01:37:53,7 2015-03-24 01:42:53,12 2015-03-24 01:47:53,17 2015-03-24 01:52:53,7 2015-03-24 01:57:53,15 2015-03-24 02:02:53,50 2015-03-24 02:07:53,28 2015-03-24 02:12:53,5 2015-03-24 02:17:53,10 2015-03-24 02:22:53,4 2015-03-24 02:27:53,11 2015-03-24 02:32:53,7 2015-03-24 02:37:53,12 2015-03-24 02:42:53,16 2015-03-24 02:47:53,10 2015-03-24 02:52:53,5 2015-03-24 02:57:53,7 2015-03-24 03:02:53,11 2015-03-24 03:07:53,7 2015-03-24 03:12:53,19 2015-03-24 03:17:53,20 2015-03-24 03:22:53,51 2015-03-24 03:27:53,4 2015-03-24 03:32:53,5 2015-03-24 03:37:53,16 2015-03-24 03:42:53,13 2015-03-24 03:47:53,12 2015-03-24 03:52:53,22 2015-03-24 03:57:53,16 2015-03-24 04:02:53,10 2015-03-24 04:07:53,11 2015-03-24 04:12:53,13 2015-03-24 04:17:53,17 2015-03-24 04:22:53,6 2015-03-24 04:27:53,11 2015-03-24 04:32:53,11 2015-03-24 04:37:53,6 2015-03-24 04:42:53,7 2015-03-24 04:47:53,15 2015-03-24 04:52:53,6 2015-03-24 04:57:53,15 2015-03-24 05:02:53,12 2015-03-24 05:07:53,3 2015-03-24 05:12:53,50 2015-03-24 05:17:53,8 2015-03-24 05:22:53,14 2015-03-24 05:27:53,7 2015-03-24 05:32:53,44 2015-03-24 05:37:53,3 2015-03-24 05:42:53,1 2015-03-24 05:47:53,6 2015-03-24 05:52:53,10 2015-03-24 05:57:53,12 2015-03-24 06:02:53,22 2015-03-24 06:07:53,6 2015-03-24 06:12:53,6 2015-03-24 06:17:53,7 2015-03-24 06:22:53,9 2015-03-24 06:27:53,11 2015-03-24 06:32:53,11 2015-03-24 06:37:53,6 2015-03-24 06:42:53,4 2015-03-24 06:47:53,11 2015-03-24 06:52:53,2 2015-03-24 06:57:53,12 2015-03-24 07:02:53,6 2015-03-24 07:07:53,10 2015-03-24 07:12:53,4 2015-03-24 07:17:53,15 2015-03-24 07:22:53,18 2015-03-24 07:27:53,9 2015-03-24 07:32:53,13 2015-03-24 07:37:53,12 2015-03-24 07:42:53,10 2015-03-24 07:47:53,12 2015-03-24 07:52:53,6 2015-03-24 07:57:53,51 2015-03-24 08:02:53,10 2015-03-24 08:07:53,10 2015-03-24 08:12:53,13 2015-03-24 08:17:53,27 2015-03-24 08:22:53,13 2015-03-24 08:27:53,13 2015-03-24 08:32:53,14 2015-03-24 08:37:53,12 2015-03-24 08:42:53,4 2015-03-24 08:47:53,49 2015-03-24 08:52:53,14 2015-03-24 08:57:53,20 2015-03-24 09:02:53,14 2015-03-24 09:07:53,18 2015-03-24 09:12:53,12 2015-03-24 09:17:53,9 2015-03-24 09:22:53,14 2015-03-24 09:27:53,7 2015-03-24 09:32:53,14 2015-03-24 09:37:53,13 2015-03-24 09:42:53,15 2015-03-24 09:47:53,19 2015-03-24 09:52:53,12 2015-03-24 09:57:53,12 2015-03-24 10:02:53,22 2015-03-24 10:07:53,19 2015-03-24 10:12:53,10 2015-03-24 10:17:53,20 2015-03-24 10:22:53,17 2015-03-24 10:27:53,10 2015-03-24 10:32:53,9 2015-03-24 10:37:53,15 2015-03-24 10:42:53,17 2015-03-24 10:47:53,17 2015-03-24 10:52:53,11 2015-03-24 10:57:53,14 2015-03-24 11:02:53,19 2015-03-24 11:07:53,17 2015-03-24 11:12:53,12 2015-03-24 11:17:53,4 2015-03-24 11:22:53,10 2015-03-24 11:27:53,17 2015-03-24 11:32:53,23 2015-03-24 11:37:53,16 2015-03-24 11:42:53,25 2015-03-24 11:47:53,7 2015-03-24 11:52:53,25 2015-03-24 11:57:53,24 2015-03-24 12:02:53,16 2015-03-24 12:07:53,20 2015-03-24 12:12:53,10 2015-03-24 12:17:53,18 2015-03-24 12:22:53,52 2015-03-24 12:27:53,22 2015-03-24 12:32:53,10 2015-03-24 12:37:53,8 2015-03-24 12:42:53,13 2015-03-24 12:47:53,18 2015-03-24 12:52:53,64 2015-03-24 12:57:53,94 2015-03-24 13:02:53,77 2015-03-24 13:07:53,65 2015-03-24 13:12:53,61 2015-03-24 13:17:53,82 2015-03-24 13:22:53,34 2015-03-24 13:27:53,31 2015-03-24 13:32:53,31 2015-03-24 13:37:53,18 2015-03-24 13:42:53,28 2015-03-24 13:47:53,24 2015-03-24 13:52:53,20 2015-03-24 13:57:53,37 2015-03-24 14:02:53,24 2015-03-24 14:07:53,27 2015-03-24 14:12:53,23 2015-03-24 14:17:53,36 2015-03-24 14:22:53,15 2015-03-24 14:27:53,39 2015-03-24 14:32:53,27 2015-03-24 14:37:53,33 2015-03-24 14:42:53,28 2015-03-24 14:47:53,24 2015-03-24 14:52:53,36 2015-03-24 14:57:53,44 2015-03-24 15:02:53,20 2015-03-24 15:07:53,48 2015-03-24 15:12:53,43 2015-03-24 15:17:53,29 2015-03-24 15:22:53,35 2015-03-24 15:27:53,30 2015-03-24 15:32:53,46 2015-03-24 15:37:53,29 2015-03-24 15:42:53,18 2015-03-24 15:47:53,29 2015-03-24 15:52:53,46 2015-03-24 15:57:53,20 2015-03-24 16:02:53,26 2015-03-24 16:07:53,101 2015-03-24 16:12:53,35 2015-03-24 16:17:53,32 2015-03-24 16:22:53,28 2015-03-24 16:27:53,30 2015-03-24 16:32:53,45 2015-03-24 16:37:53,61 2015-03-24 16:42:53,50 2015-03-24 16:47:53,60 2015-03-24 16:52:53,54 2015-03-24 16:57:53,61 2015-03-24 17:02:53,45 2015-03-24 17:07:53,37 2015-03-24 17:12:53,34 2015-03-24 17:17:53,35 2015-03-24 17:22:53,23 2015-03-24 17:27:53,39 2015-03-24 17:32:53,38 2015-03-24 17:37:53,67 2015-03-24 17:42:53,47 2015-03-24 17:47:53,41 2015-03-24 17:52:53,41 2015-03-24 17:57:53,49 2015-03-24 18:02:53,51 2015-03-24 18:07:53,18 2015-03-24 18:12:53,39 2015-03-24 18:17:53,22 2015-03-24 18:22:53,31 2015-03-24 18:27:53,21 2015-03-24 18:32:53,35 2015-03-24 18:37:53,28 2015-03-24 18:42:53,35 2015-03-24 18:47:53,75 2015-03-24 18:52:53,79 2015-03-24 18:57:53,65 2015-03-24 19:02:53,51 2015-03-24 19:07:53,41 2015-03-24 19:12:53,49 2015-03-24 19:17:53,28 2015-03-24 19:22:53,41 2015-03-24 19:27:53,31 2015-03-24 19:32:53,34 2015-03-24 19:37:53,26 2015-03-24 19:42:53,35 2015-03-24 19:47:53,33 2015-03-24 19:52:53,26 2015-03-24 19:57:53,33 2015-03-24 20:02:53,40 2015-03-24 20:07:53,32 2015-03-24 20:12:53,22 2015-03-24 20:17:53,31 2015-03-24 20:22:53,31 2015-03-24 20:27:53,31 2015-03-24 20:32:53,21 2015-03-24 20:37:53,30 2015-03-24 20:42:53,17 2015-03-24 20:47:53,22 2015-03-24 20:52:53,16 2015-03-24 20:57:53,20 2015-03-24 21:02:53,21 2015-03-24 21:07:53,23 2015-03-24 21:12:53,32 2015-03-24 21:17:53,25 2015-03-24 21:22:53,64 2015-03-24 21:27:53,28 2015-03-24 21:32:53,27 2015-03-24 21:37:53,17 2015-03-24 21:42:53,16 2015-03-24 21:47:53,27 2015-03-24 21:52:53,18 2015-03-24 21:57:53,26 2015-03-24 22:02:53,19 2015-03-24 22:07:53,15 2015-03-24 22:12:53,29 2015-03-24 22:17:53,23 2015-03-24 22:22:53,22 2015-03-24 22:27:53,21 2015-03-24 22:32:53,14 2015-03-24 22:37:53,11 2015-03-24 22:42:53,12 2015-03-24 22:47:53,17 2015-03-24 22:52:53,12 2015-03-24 22:57:53,28 2015-03-24 23:02:53,20 2015-03-24 23:07:53,31 2015-03-24 23:12:53,15 2015-03-24 23:17:53,24 2015-03-24 23:22:53,24 2015-03-24 23:27:53,56 2015-03-24 23:32:53,26 2015-03-24 23:37:53,11 2015-03-24 23:42:53,23 2015-03-24 23:47:53,25 2015-03-24 23:52:53,53 2015-03-24 23:57:53,34 2015-03-25 00:02:53,29 2015-03-25 00:07:53,19 2015-03-25 00:12:53,22 2015-03-25 00:17:53,7 2015-03-25 00:22:53,19 2015-03-25 00:27:53,16 2015-03-25 00:32:53,25 2015-03-25 00:37:53,14 2015-03-25 00:42:53,13 2015-03-25 00:47:53,19 2015-03-25 00:52:53,25 2015-03-25 00:57:53,16 2015-03-25 01:02:53,20 2015-03-25 01:07:53,9 2015-03-25 01:12:53,15 2015-03-25 01:17:53,28 2015-03-25 01:22:53,13 2015-03-25 01:27:53,15 2015-03-25 01:32:53,9 2015-03-25 01:37:53,12 2015-03-25 01:42:53,5 2015-03-25 01:47:53,14 2015-03-25 01:52:53,13 2015-03-25 01:57:53,19 2015-03-25 02:02:53,14 2015-03-25 02:07:53,18 2015-03-25 02:12:53,10 2015-03-25 02:17:53,12 2015-03-25 02:22:53,56 2015-03-25 02:27:53,64 2015-03-25 02:32:53,25 2015-03-25 02:37:53,26 2015-03-25 02:42:53,69 2015-03-25 02:47:53,13 2015-03-25 02:52:53,17 2015-03-25 02:57:53,11 2015-03-25 03:02:53,13 2015-03-25 03:07:53,27 2015-03-25 03:12:53,16 2015-03-25 03:17:53,22 2015-03-25 03:22:53,23 2015-03-25 03:27:53,14 2015-03-25 03:32:53,15 2015-03-25 03:37:53,20 2015-03-25 03:42:53,16 2015-03-25 03:47:53,22 2015-03-25 03:52:53,12 2015-03-25 03:57:53,13 2015-03-25 04:02:53,12 2015-03-25 04:07:53,11 2015-03-25 04:12:53,11 2015-03-25 04:17:53,10 2015-03-25 04:22:53,9 2015-03-25 04:27:53,49 2015-03-25 04:32:53,6 2015-03-25 04:37:53,4 2015-03-25 04:42:53,1 2015-03-25 04:47:53,5 2015-03-25 04:52:53,8 2015-03-25 04:57:53,11 2015-03-25 05:02:53,7 2015-03-25 05:07:53,6 2015-03-25 05:12:53,12 2015-03-25 05:17:53,11 2015-03-25 05:22:53,8 2015-03-25 05:27:53,12 2015-03-25 05:32:53,24 2015-03-25 05:37:53,15 2015-03-25 05:42:53,11 2015-03-25 05:47:53,16 2015-03-25 05:52:53,6 2015-03-25 05:57:53,55 2015-03-25 06:02:53,12 2015-03-25 06:07:53,21 2015-03-25 06:12:53,6 2015-03-25 06:17:53,14 2015-03-25 06:22:53,9 2015-03-25 06:27:53,8 2015-03-25 06:32:53,12 2015-03-25 06:37:53,50 2015-03-25 06:42:53,11 2015-03-25 06:47:53,10 2015-03-25 06:52:53,10 2015-03-25 06:57:53,27 2015-03-25 07:02:53,11 2015-03-25 07:07:53,8 2015-03-25 07:12:53,10 2015-03-25 07:17:53,10 2015-03-25 07:22:53,36 2015-03-25 07:27:53,10 2015-03-25 07:32:53,5 2015-03-25 07:37:53,6 2015-03-25 07:42:53,13 2015-03-25 07:47:53,15 2015-03-25 07:52:53,14 2015-03-25 07:57:53,7 2015-03-25 08:02:53,17 2015-03-25 08:07:53,10 2015-03-25 08:12:53,7 2015-03-25 08:17:53,11 2015-03-25 08:22:53,9 2015-03-25 08:27:53,11 2015-03-25 08:32:53,7 2015-03-25 08:37:53,7 2015-03-25 08:42:53,11 2015-03-25 08:47:53,17 2015-03-25 08:52:53,18 2015-03-25 08:57:53,14 2015-03-25 09:02:53,15 2015-03-25 09:07:53,46 2015-03-25 09:12:53,16 2015-03-25 09:17:53,6 2015-03-25 09:22:53,55 2015-03-25 09:27:53,110 2015-03-25 09:32:53,15 2015-03-25 09:37:53,12 2015-03-25 09:42:53,9 2015-03-25 09:47:53,29 2015-03-25 09:52:53,25 2015-03-25 09:57:53,27 2015-03-25 10:02:53,10 2015-03-25 10:07:53,13 2015-03-25 10:12:53,12 2015-03-25 10:17:53,12 2015-03-25 10:22:53,12 2015-03-25 10:27:53,10 2015-03-25 10:32:53,22 2015-03-25 10:37:53,11 2015-03-25 10:42:53,24 2015-03-25 10:47:53,12 2015-03-25 10:52:53,15 2015-03-25 10:57:53,22 2015-03-25 11:02:53,15 2015-03-25 11:07:53,14 2015-03-25 11:12:53,10 2015-03-25 11:17:53,14 2015-03-25 11:22:53,10 2015-03-25 11:27:53,43 2015-03-25 11:32:53,38 2015-03-25 11:37:53,45 2015-03-25 11:42:53,56 2015-03-25 11:47:53,52 2015-03-25 11:52:53,19 2015-03-25 11:57:53,51 2015-03-25 12:02:53,49 2015-03-25 12:07:53,28 2015-03-25 12:12:53,30 2015-03-25 12:17:53,33 2015-03-25 12:22:53,19 2015-03-25 12:27:53,26 2015-03-25 12:32:53,24 2015-03-25 12:37:53,14 2015-03-25 12:42:53,27 2015-03-25 12:47:53,22 2015-03-25 12:52:53,23 2015-03-25 12:57:53,28 2015-03-25 13:02:53,56 2015-03-25 13:07:53,26 2015-03-25 13:12:53,20 2015-03-25 13:17:53,15 2015-03-25 13:22:53,24 2015-03-25 13:27:53,32 2015-03-25 13:32:53,30 2015-03-25 13:37:53,33 2015-03-25 13:42:53,25 2015-03-25 13:47:53,21 2015-03-25 13:52:53,29 2015-03-25 13:57:53,30 2015-03-25 14:02:53,18 2015-03-25 14:07:53,17 2015-03-25 14:12:53,17 2015-03-25 14:17:53,19 2015-03-25 14:22:53,25 2015-03-25 14:27:53,20 2015-03-25 14:32:53,56 2015-03-25 14:37:53,21 2015-03-25 14:42:53,34 2015-03-25 14:47:53,43 2015-03-25 14:52:53,53 2015-03-25 14:57:53,42 2015-03-25 15:02:53,47 2015-03-25 15:07:53,19 2015-03-25 15:12:53,32 2015-03-25 15:17:53,30 2015-03-25 15:22:53,27 2015-03-25 15:27:53,38 2015-03-25 15:32:53,30 2015-03-25 15:37:53,51 2015-03-25 15:42:53,35 2015-03-25 15:47:53,30 2015-03-25 15:52:53,31 2015-03-25 15:57:53,47 2015-03-25 16:02:53,36 2015-03-25 16:07:53,32 2015-03-25 16:12:53,39 2015-03-25 16:17:53,26 2015-03-25 16:22:53,25 2015-03-25 16:27:53,34 2015-03-25 16:32:53,34 2015-03-25 16:37:53,31 2015-03-25 16:42:53,34 2015-03-25 16:47:53,24 2015-03-25 16:52:53,64 2015-03-25 16:57:53,28 2015-03-25 17:02:53,48 2015-03-25 17:07:53,25 2015-03-25 17:12:53,69 2015-03-25 17:17:53,29 2015-03-25 17:22:53,32 2015-03-25 17:27:53,40 2015-03-25 17:32:53,22 2015-03-25 17:37:53,17 2015-03-25 17:42:53,27 2015-03-25 17:47:53,29 2015-03-25 17:52:53,27 2015-03-25 17:57:53,40 2015-03-25 18:02:53,32 2015-03-25 18:07:53,21 2015-03-25 18:12:53,34 2015-03-25 18:17:53,35 2015-03-25 18:22:53,34 2015-03-25 18:27:53,52 2015-03-25 18:32:53,79 2015-03-25 18:37:53,45 2015-03-25 18:42:53,46 2015-03-25 18:47:53,32 2015-03-25 18:52:53,54 2015-03-25 18:57:53,35 2015-03-25 19:02:53,79 2015-03-25 19:07:53,27 2015-03-25 19:12:53,27 2015-03-25 19:17:53,49 2015-03-25 19:22:53,28 2015-03-25 19:27:53,30 2015-03-25 19:32:53,18 2015-03-25 19:37:53,34 2015-03-25 19:42:53,80 2015-03-25 19:47:53,38 2015-03-25 19:52:53,120 2015-03-25 19:57:53,51 2015-03-25 20:02:53,40 2015-03-25 20:07:53,39 2015-03-25 20:12:53,35 2015-03-25 20:17:53,35 2015-03-25 20:22:53,44 2015-03-25 20:27:53,83 2015-03-25 20:32:53,36 2015-03-25 20:37:53,31 2015-03-25 20:42:53,20 2015-03-25 20:47:53,66 2015-03-25 20:52:53,28 2015-03-25 20:57:53,52 2015-03-25 21:02:53,38 2015-03-25 21:07:53,34 2015-03-25 21:12:53,34 2015-03-25 21:17:53,56 2015-03-25 21:22:53,56 2015-03-25 21:27:53,41 2015-03-25 21:32:53,30 2015-03-25 21:37:53,44 2015-03-25 21:42:53,41 2015-03-25 21:47:53,33 2015-03-25 21:52:53,25 2015-03-25 21:57:53,49 2015-03-25 22:02:53,31 2015-03-25 22:07:53,22 2015-03-25 22:12:53,23 2015-03-25 22:17:53,14 2015-03-25 22:22:53,47 2015-03-25 22:27:53,59 2015-03-25 22:32:53,18 2015-03-25 22:37:53,33 2015-03-25 22:42:53,13 2015-03-25 22:47:53,16 2015-03-25 22:52:53,26 2015-03-25 22:57:53,37 2015-03-25 23:02:53,28 2015-03-25 23:07:53,25 2015-03-25 23:12:53,31 2015-03-25 23:17:53,20 2015-03-25 23:22:53,18 2015-03-25 23:27:53,25 2015-03-25 23:32:53,26 2015-03-25 23:37:53,34 2015-03-25 23:42:53,28 2015-03-25 23:47:53,23 2015-03-25 23:52:53,17 2015-03-25 23:57:53,25 2015-03-26 00:02:53,56 2015-03-26 00:07:53,29 2015-03-26 00:12:53,32 2015-03-26 00:17:53,20 2015-03-26 00:22:53,12 2015-03-26 00:27:53,19 2015-03-26 00:32:53,26 2015-03-26 00:37:53,39 2015-03-26 00:42:53,24 2015-03-26 00:47:53,25 2015-03-26 00:52:53,56 2015-03-26 00:57:53,23 2015-03-26 01:02:53,22 2015-03-26 01:07:53,23 2015-03-26 01:12:53,20 2015-03-26 01:17:53,20 2015-03-26 01:22:53,28 2015-03-26 01:27:53,22 2015-03-26 01:32:53,7 2015-03-26 01:37:53,19 2015-03-26 01:42:53,15 2015-03-26 01:47:53,13 2015-03-26 01:52:53,12 2015-03-26 01:57:53,21 2015-03-26 02:02:53,17 2015-03-26 02:07:53,14 2015-03-26 02:12:53,48 2015-03-26 02:17:53,64 2015-03-26 02:22:53,25 2015-03-26 02:27:53,17 2015-03-26 02:32:53,19 2015-03-26 02:37:53,24 2015-03-26 02:42:53,17 2015-03-26 02:47:53,35 2015-03-26 02:52:53,23 2015-03-26 02:57:53,18 2015-03-26 03:02:53,26 2015-03-26 03:07:53,50 2015-03-26 03:12:53,34 2015-03-26 03:17:53,64 2015-03-26 03:22:53,32 2015-03-26 03:27:53,32 2015-03-26 03:32:53,21 2015-03-26 03:37:53,21 2015-03-26 03:42:53,8 2015-03-26 03:47:53,17 2015-03-26 03:52:53,11 2015-03-26 03:57:53,17 2015-03-26 04:02:53,22 2015-03-26 04:07:53,12 2015-03-26 04:12:53,8 2015-03-26 04:17:53,13 2015-03-26 04:22:53,12 2015-03-26 04:27:53,15 2015-03-26 04:32:53,8 2015-03-26 04:37:53,14 2015-03-26 04:42:53,12 2015-03-26 04:47:53,10 2015-03-26 04:52:53,8 2015-03-26 04:57:53,13 2015-03-26 05:02:53,15 2015-03-26 05:07:53,10 2015-03-26 05:12:53,6 2015-03-26 05:17:53,12 2015-03-26 05:22:53,28 2015-03-26 05:27:53,15 2015-03-26 05:32:53,13 2015-03-26 05:37:53,14 2015-03-26 05:42:53,8 2015-03-26 05:47:53,9 2015-03-26 05:52:53,20 2015-03-26 05:57:53,4 2015-03-26 06:02:53,12 2015-03-26 06:07:53,4 2015-03-26 06:12:53,6 2015-03-26 06:17:53,15 2015-03-26 06:22:53,14 2015-03-26 06:27:53,14 2015-03-26 06:32:53,44 2015-03-26 06:37:53,13 2015-03-26 06:42:53,6 2015-03-26 06:47:53,15 2015-03-26 06:52:53,14 2015-03-26 06:57:53,16 2015-03-26 07:02:53,7 2015-03-26 07:07:53,5 2015-03-26 07:12:53,12 2015-03-26 07:17:53,27 2015-03-26 07:22:53,20 2015-03-26 07:27:53,16 2015-03-26 07:32:53,18 2015-03-26 07:37:53,10 2015-03-26 07:42:53,50 2015-03-26 07:47:53,11 2015-03-26 07:52:53,12 2015-03-26 07:57:53,12 2015-03-26 08:02:53,13 2015-03-26 08:07:53,31 2015-03-26 08:12:53,28 2015-03-26 08:17:53,19 2015-03-26 08:22:53,22 2015-03-26 08:27:53,14 2015-03-26 08:32:53,29 2015-03-26 08:37:53,8 2015-03-26 08:42:53,16 2015-03-26 08:47:53,14 2015-03-26 08:52:53,11 2015-03-26 08:57:53,15 2015-03-26 09:02:53,16 2015-03-26 09:07:53,10 2015-03-26 09:12:53,16 2015-03-26 09:17:53,14 2015-03-26 09:22:53,13 2015-03-26 09:27:53,19 2015-03-26 09:32:53,8 2015-03-26 09:37:53,13 2015-03-26 09:42:53,10 2015-03-26 09:47:53,13 2015-03-26 09:52:53,27 2015-03-26 09:57:53,37 2015-03-26 10:02:53,28 2015-03-26 10:07:53,20 2015-03-26 10:12:53,27 2015-03-26 10:17:53,47 2015-03-26 10:22:53,23 2015-03-26 10:27:53,21 2015-03-26 10:32:53,20 2015-03-26 10:37:53,18 2015-03-26 10:42:53,20 2015-03-26 10:47:53,25 2015-03-26 10:52:53,16 2015-03-26 10:57:53,17 2015-03-26 11:02:53,18 2015-03-26 11:07:53,17 2015-03-26 11:12:53,13 2015-03-26 11:17:53,17 2015-03-26 11:22:53,10 2015-03-26 11:27:53,26 2015-03-26 11:32:53,13 2015-03-26 11:37:53,22 2015-03-26 11:42:53,28 2015-03-26 11:47:53,34 2015-03-26 11:52:53,37 2015-03-26 11:57:53,20 2015-03-26 12:02:53,16 2015-03-26 12:07:53,20 2015-03-26 12:12:53,25 2015-03-26 12:17:53,32 2015-03-26 12:22:53,19 2015-03-26 12:27:53,33 2015-03-26 12:32:53,20 2015-03-26 12:37:53,11 2015-03-26 12:42:53,18 2015-03-26 12:47:53,31 2015-03-26 12:52:53,23 2015-03-26 12:57:53,26 2015-03-26 13:02:53,31 2015-03-26 13:07:53,15 2015-03-26 13:12:53,25 2015-03-26 13:17:53,22 2015-03-26 13:22:53,42 2015-03-26 13:27:53,34 2015-03-26 13:32:53,49 2015-03-26 13:37:53,27 2015-03-26 13:42:53,26 2015-03-26 13:47:53,79 2015-03-26 13:52:53,33 2015-03-26 13:57:53,26 2015-03-26 14:02:53,35 2015-03-26 14:07:53,38 2015-03-26 14:12:53,18 2015-03-26 14:17:53,19 2015-03-26 14:22:53,30 2015-03-26 14:27:53,33 2015-03-26 14:32:53,28 2015-03-26 14:37:53,26 2015-03-26 14:42:53,35 2015-03-26 14:47:53,33 2015-03-26 14:52:53,29 2015-03-26 14:57:53,27 2015-03-26 15:02:53,51 2015-03-26 15:07:53,31 2015-03-26 15:12:53,41 2015-03-26 15:17:53,40 2015-03-26 15:22:53,37 2015-03-26 15:27:53,39 2015-03-26 15:32:53,34 2015-03-26 15:37:53,35 2015-03-26 15:42:53,65 2015-03-26 15:47:53,24 2015-03-26 15:52:53,22 2015-03-26 15:57:53,26 2015-03-26 16:02:53,37 2015-03-26 16:07:53,37 2015-03-26 16:12:53,93 2015-03-26 16:17:53,82 2015-03-26 16:22:53,30 2015-03-26 16:27:53,32 2015-03-26 16:32:53,32 2015-03-26 16:37:53,30 2015-03-26 16:42:53,28 2015-03-26 16:47:53,23 2015-03-26 16:52:53,21 2015-03-26 16:57:53,40 2015-03-26 17:02:53,25 2015-03-26 17:07:53,25 2015-03-26 17:12:53,23 2015-03-26 17:17:53,22 2015-03-26 17:22:53,29 2015-03-26 17:27:53,25 2015-03-26 17:32:53,34 2015-03-26 17:37:53,53 2015-03-26 17:42:53,18 2015-03-26 17:47:53,38 2015-03-26 17:52:53,29 2015-03-26 17:57:53,40 2015-03-26 18:02:53,46 2015-03-26 18:07:53,24 2015-03-26 18:12:53,28 2015-03-26 18:17:53,25 2015-03-26 18:22:53,38 2015-03-26 18:27:53,88 2015-03-26 18:32:53,35 2015-03-26 18:37:53,28 2015-03-26 18:42:53,23 2015-03-26 18:47:53,32 2015-03-26 18:52:53,24 2015-03-26 18:57:53,28 2015-03-26 19:02:53,29 2015-03-26 19:07:53,25 2015-03-26 19:12:53,20 2015-03-26 19:17:53,17 2015-03-26 19:22:53,22 2015-03-26 19:27:53,16 2015-03-26 19:32:53,11 2015-03-26 19:37:53,20 2015-03-26 19:42:53,16 2015-03-26 19:47:53,19 2015-03-26 19:52:53,12 2015-03-26 19:57:53,27 2015-03-26 20:02:53,10 2015-03-26 20:07:53,20 2015-03-26 20:12:53,25 2015-03-26 20:17:53,11 2015-03-26 20:22:53,15 2015-03-26 20:27:53,22 2015-03-26 20:32:53,32 2015-03-26 20:37:53,30 2015-03-26 20:42:53,24 2015-03-26 20:47:53,30 2015-03-26 20:52:53,13 2015-03-26 20:57:53,19 2015-03-26 21:02:53,24 2015-03-26 21:07:53,17 2015-03-26 21:12:53,21 2015-03-26 21:17:53,55 2015-03-26 21:22:53,20 2015-03-26 21:27:53,26 2015-03-26 21:32:53,23 2015-03-26 21:37:53,31 2015-03-26 21:42:53,19 2015-03-26 21:47:53,23 2015-03-26 21:52:53,17 2015-03-26 21:57:53,25 2015-03-26 22:02:53,12 2015-03-26 22:07:53,18 2015-03-26 22:12:53,11 2015-03-26 22:17:53,18 2015-03-26 22:22:53,13 2015-03-26 22:27:53,22 2015-03-26 22:32:53,16 2015-03-26 22:37:53,12 2015-03-26 22:42:53,21 2015-03-26 22:47:53,19 2015-03-26 22:52:53,18 2015-03-26 22:57:53,24 2015-03-26 23:02:53,14 2015-03-26 23:07:53,25 2015-03-26 23:12:53,25 2015-03-26 23:17:53,13 2015-03-26 23:22:53,13 2015-03-26 23:27:53,20 2015-03-26 23:32:53,16 2015-03-26 23:37:53,13 2015-03-26 23:42:53,70 2015-03-26 23:47:53,26 2015-03-26 23:52:53,20 2015-03-26 23:57:53,32 2015-03-27 00:02:53,22 2015-03-27 00:07:53,10 2015-03-27 00:12:53,44 2015-03-27 00:17:53,16 2015-03-27 00:22:53,11 2015-03-27 00:27:53,20 2015-03-27 00:32:53,9 2015-03-27 00:37:53,12 2015-03-27 00:42:53,51 2015-03-27 00:47:53,8 2015-03-27 00:52:53,14 2015-03-27 00:57:53,15 2015-03-27 01:02:53,23 2015-03-27 01:07:53,12 2015-03-27 01:12:53,9 2015-03-27 01:17:53,14 2015-03-27 01:22:53,11 2015-03-27 01:27:53,19 2015-03-27 01:32:53,14 2015-03-27 01:37:53,33 2015-03-27 01:42:53,18 2015-03-27 01:47:53,20 2015-03-27 01:52:53,9 2015-03-27 01:57:53,19 2015-03-27 02:02:53,21 2015-03-27 02:07:53,16 2015-03-27 02:12:53,17 2015-03-27 02:17:53,15 2015-03-27 02:22:53,6 2015-03-27 02:27:53,14 2015-03-27 02:32:53,22 2015-03-27 02:37:53,25 2015-03-27 02:42:53,11 2015-03-27 02:47:53,12 2015-03-27 02:52:53,13 2015-03-27 02:57:53,23 2015-03-27 03:02:53,4 2015-03-27 03:07:53,13 2015-03-27 03:12:53,8 2015-03-27 03:17:53,11 2015-03-27 03:22:53,12 2015-03-27 03:27:53,9 2015-03-27 03:32:53,14 2015-03-27 03:37:53,12 2015-03-27 03:42:53,4 2015-03-27 03:47:53,19 2015-03-27 03:52:53,16 2015-03-27 03:57:53,49 2015-03-27 04:02:53,1 2015-03-27 04:07:53,13 2015-03-27 04:12:53,46 2015-03-27 04:17:53,9 2015-03-27 04:22:53,9 2015-03-27 04:27:53,14 2015-03-27 04:32:53,5 2015-03-27 04:37:53,10 2015-03-27 04:42:53,8 2015-03-27 04:47:53,8 2015-03-27 04:52:53,8 2015-03-27 04:57:53,10 2015-03-27 05:02:53,7 2015-03-27 05:07:53,9 2015-03-27 05:12:53,4 2015-03-27 05:17:53,10 2015-03-27 05:22:53,9 2015-03-27 05:27:53,5 2015-03-27 05:32:53,8 2015-03-27 05:37:53,22 2015-03-27 05:42:53,12 2015-03-27 05:47:53,14 2015-03-27 05:52:53,13 2015-03-27 05:57:53,12 2015-03-27 06:02:53,4 2015-03-27 06:07:53,6 2015-03-27 06:12:53,9 2015-03-27 06:17:53,6 2015-03-27 06:22:53,5 2015-03-27 06:27:53,5 2015-03-27 06:32:53,17 2015-03-27 06:37:53,7 2015-03-27 06:42:53,16 2015-03-27 06:47:53,7 2015-03-27 06:52:53,5 2015-03-27 06:57:53,7 2015-03-27 07:02:53,10 2015-03-27 07:07:53,2 2015-03-27 07:12:53,8 2015-03-27 07:17:53,57 2015-03-27 07:22:53,5 2015-03-27 07:27:53,6 2015-03-27 07:32:53,13 2015-03-27 07:37:53,8 2015-03-27 07:42:53,11 2015-03-27 07:47:53,5 2015-03-27 07:52:53,11 2015-03-27 07:57:53,14 2015-03-27 08:02:53,7 2015-03-27 08:07:53,6 2015-03-27 08:12:53,11 2015-03-27 08:17:53,11 2015-03-27 08:22:53,13 2015-03-27 08:27:53,16 2015-03-27 08:32:53,6 2015-03-27 08:37:53,17 2015-03-27 08:42:53,12 2015-03-27 08:47:53,14 2015-03-27 08:52:53,7 2015-03-27 08:57:53,13 2015-03-27 09:02:53,16 2015-03-27 09:07:53,7 2015-03-27 09:12:53,11 2015-03-27 09:17:53,10 2015-03-27 09:22:53,12 2015-03-27 09:27:53,16 2015-03-27 09:32:53,8 2015-03-27 09:37:53,9 2015-03-27 09:42:53,6 2015-03-27 09:47:53,16 2015-03-27 09:52:53,12 2015-03-27 09:57:53,15 2015-03-27 10:02:53,11 2015-03-27 10:07:53,14 2015-03-27 10:12:53,8 2015-03-27 10:17:53,12 2015-03-27 10:22:53,3 2015-03-27 10:27:53,7 2015-03-27 10:32:53,15 2015-03-27 10:37:53,11 2015-03-27 10:42:53,9 2015-03-27 10:47:53,8 2015-03-27 10:52:53,17 2015-03-27 10:57:53,45 2015-03-27 11:02:53,14 2015-03-27 11:07:53,10 2015-03-27 11:12:53,18 2015-03-27 11:17:53,10 2015-03-27 11:22:53,6 2015-03-27 11:27:53,12 2015-03-27 11:32:53,49 2015-03-27 11:37:53,14 2015-03-27 11:42:53,18 2015-03-27 11:47:53,13 2015-03-27 11:52:53,11 2015-03-27 11:57:53,25 2015-03-27 12:02:53,18 2015-03-27 12:07:53,17 2015-03-27 12:12:53,14 2015-03-27 12:17:53,10 2015-03-27 12:22:53,21 2015-03-27 12:27:53,19 2015-03-27 12:32:53,12 2015-03-27 12:37:53,13 2015-03-27 12:42:53,18 2015-03-27 12:47:53,12 2015-03-27 12:52:53,13 2015-03-27 12:57:53,23 2015-03-27 13:02:53,20 2015-03-27 13:07:53,18 2015-03-27 13:12:53,24 2015-03-27 13:17:53,21 2015-03-27 13:22:53,25 2015-03-27 13:27:53,19 2015-03-27 13:32:53,20 2015-03-27 13:37:53,17 2015-03-27 13:42:53,17 2015-03-27 13:47:53,18 2015-03-27 13:52:53,26 2015-03-27 13:57:53,24 2015-03-27 14:02:53,17 2015-03-27 14:07:53,15 2015-03-27 14:12:53,18 2015-03-27 14:17:53,24 2015-03-27 14:22:53,63 2015-03-27 14:27:53,21 2015-03-27 14:32:53,16 2015-03-27 14:37:53,64 2015-03-27 14:42:53,19 2015-03-27 14:47:53,25 2015-03-27 14:52:53,28 2015-03-27 14:57:53,26 2015-03-27 15:02:53,18 2015-03-27 15:07:53,18 2015-03-27 15:12:53,10 2015-03-27 15:17:53,29 2015-03-27 15:22:53,24 2015-03-27 15:27:53,26 2015-03-27 15:32:53,13 2015-03-27 15:37:53,29 2015-03-27 15:42:53,35 2015-03-27 15:47:53,29 2015-03-27 15:52:53,23 2015-03-27 15:57:53,32 2015-03-27 16:02:53,33 2015-03-27 16:07:53,26 2015-03-27 16:12:53,28 2015-03-27 16:17:53,28 2015-03-27 16:22:53,49 2015-03-27 16:27:53,25 2015-03-27 16:32:53,18 2015-03-27 16:37:53,26 2015-03-27 16:42:53,25 2015-03-27 16:47:53,34 2015-03-27 16:52:53,60 2015-03-27 16:57:53,26 2015-03-27 17:02:53,31 2015-03-27 17:07:53,36 2015-03-27 17:12:53,24 2015-03-27 17:17:53,20 2015-03-27 17:22:53,35 2015-03-27 17:27:53,19 2015-03-27 17:32:53,22 2015-03-27 17:37:53,13 2015-03-27 17:42:53,17 2015-03-27 17:47:53,21 2015-03-27 17:52:53,18 2015-03-27 17:57:53,21 2015-03-27 18:02:53,16 2015-03-27 18:07:53,12 2015-03-27 18:12:53,14 2015-03-27 18:17:53,53 2015-03-27 18:22:53,12 2015-03-27 18:27:53,12 2015-03-27 18:32:53,18 2015-03-27 18:37:53,17 2015-03-27 18:42:53,20 2015-03-27 18:47:53,11 2015-03-27 18:52:53,15 2015-03-27 18:57:53,33 2015-03-27 19:02:53,16 2015-03-27 19:07:53,12 2015-03-27 19:12:53,29 2015-03-27 19:17:53,21 2015-03-27 19:22:53,21 2015-03-27 19:27:53,25 2015-03-27 19:32:53,27 2015-03-27 19:37:53,18 2015-03-27 19:42:53,23 2015-03-27 19:47:53,17 2015-03-27 19:52:53,56 2015-03-27 19:57:53,22 2015-03-27 20:02:53,19 2015-03-27 20:07:53,19 2015-03-27 20:12:53,18 2015-03-27 20:17:53,31 2015-03-27 20:22:53,35 2015-03-27 20:27:53,20 2015-03-27 20:32:53,10 2015-03-27 20:37:53,18 2015-03-27 20:42:53,16 2015-03-27 20:47:53,19 2015-03-27 20:52:53,22 2015-03-27 20:57:53,31 2015-03-27 21:02:53,23 2015-03-27 21:07:53,13 2015-03-27 21:12:53,11 2015-03-27 21:17:53,17 2015-03-27 21:22:53,22 2015-03-27 21:27:53,18 2015-03-27 21:32:53,17 2015-03-27 21:37:53,9 2015-03-27 21:42:53,10 2015-03-27 21:47:53,40 2015-03-27 21:52:53,17 2015-03-27 21:57:53,55 2015-03-27 22:02:53,12 2015-03-27 22:07:53,47 2015-03-27 22:12:53,21 2015-03-27 22:17:53,25 2015-03-27 22:22:53,11 2015-03-27 22:27:53,21 2015-03-27 22:32:53,27 2015-03-27 22:37:53,12 2015-03-27 22:42:53,6 2015-03-27 22:47:53,26 2015-03-27 22:52:53,7 2015-03-27 22:57:53,13 2015-03-27 23:02:53,8 2015-03-27 23:07:53,32 2015-03-27 23:12:53,15 2015-03-27 23:17:53,13 2015-03-27 23:22:53,18 2015-03-27 23:27:53,15 2015-03-27 23:32:53,14 2015-03-27 23:37:53,11 2015-03-27 23:42:53,11 2015-03-27 23:47:53,17 2015-03-27 23:52:53,6 2015-03-27 23:57:53,25 2015-03-28 00:02:53,27 2015-03-28 00:07:53,12 2015-03-28 00:12:53,13 2015-03-28 00:17:53,25 2015-03-28 00:22:53,14 2015-03-28 00:27:53,13 2015-03-28 00:32:53,7 2015-03-28 00:37:53,13 2015-03-28 00:42:53,14 2015-03-28 00:47:53,15 2015-03-28 00:52:53,7 2015-03-28 00:57:53,10 2015-03-28 01:02:53,21 2015-03-28 01:07:53,11 2015-03-28 01:12:53,25 2015-03-28 01:17:53,33 2015-03-28 01:22:53,8 2015-03-28 01:27:53,9 2015-03-28 01:32:53,5 2015-03-28 01:37:53,11 2015-03-28 01:42:53,7 2015-03-28 01:47:53,12 2015-03-28 01:52:53,3 2015-03-28 01:57:53,16 2015-03-28 02:02:53,10 2015-03-28 02:07:53,3 2015-03-28 02:12:53,17 2015-03-28 02:17:53,14 2015-03-28 02:22:53,14 2015-03-28 02:27:53,11 2015-03-28 02:32:53,6 2015-03-28 02:37:53,16 2015-03-28 02:42:53,10 2015-03-28 02:47:53,12 2015-03-28 02:52:53,16 2015-03-28 02:57:53,25 2015-03-28 03:02:53,10 2015-03-28 03:07:53,15 2015-03-28 03:12:53,12 2015-03-28 03:17:53,18 2015-03-28 03:22:53,18 2015-03-28 03:27:53,8 2015-03-28 03:32:53,11 2015-03-28 03:37:53,14 2015-03-28 03:42:53,10 2015-03-28 03:47:53,20 2015-03-28 03:52:53,14 2015-03-28 03:57:53,12 2015-03-28 04:02:53,17 2015-03-28 04:07:53,7 2015-03-28 04:12:53,7 2015-03-28 04:17:53,48 2015-03-28 04:22:53,11 2015-03-28 04:27:53,73 2015-03-28 04:32:53,115 2015-03-28 04:37:53,110 2015-03-28 04:42:53,105 2015-03-28 04:47:53,36 2015-03-28 04:52:53,86 2015-03-28 04:57:53,86 2015-03-28 05:02:53,109 2015-03-28 05:07:53,76 2015-03-28 05:12:53,77 2015-03-28 05:17:53,80 2015-03-28 05:22:53,64 2015-03-28 05:27:53,115 2015-03-28 05:32:53,152 2015-03-28 05:37:53,174 2015-03-28 05:42:53,154 2015-03-28 05:47:53,199 2015-03-28 05:52:53,123 2015-03-28 05:57:53,204 2015-03-28 06:02:53,88 2015-03-28 06:07:53,27 2015-03-28 06:12:53,8 2015-03-28 06:17:53,5 2015-03-28 06:22:53,11 2015-03-28 06:27:53,12 2015-03-28 06:32:53,18 2015-03-28 06:37:53,13 2015-03-28 06:42:53,3 2015-03-28 06:47:53,6 2015-03-28 06:52:53,10 2015-03-28 06:57:53,20 2015-03-28 07:02:53,14 2015-03-28 07:07:53,18 2015-03-28 07:12:53,15 2015-03-28 07:17:53,13 2015-03-28 07:22:53,16 2015-03-28 07:27:53,4 2015-03-28 07:32:53,43 2015-03-28 07:37:53,9 2015-03-28 07:42:53,6 2015-03-28 07:47:53,8 2015-03-28 07:52:53,4 2015-03-28 07:57:53,6 2015-03-28 08:02:53,5 2015-03-28 08:07:53,18 2015-03-28 08:12:53,10 2015-03-28 08:17:53,2 2015-03-28 08:22:53,5 2015-03-28 08:27:53,5 2015-03-28 08:32:53,11 2015-03-28 08:37:53,12 2015-03-28 08:42:53,7 2015-03-28 08:47:53,8 2015-03-28 08:52:53,12 2015-03-28 08:57:53,18 2015-03-28 09:02:53,10 2015-03-28 09:07:53,14 2015-03-28 09:12:53,8 2015-03-28 09:17:53,10 2015-03-28 09:22:53,11 2015-03-28 09:27:53,12 2015-03-28 09:32:53,46 2015-03-28 09:37:53,8 2015-03-28 09:42:53,6 2015-03-28 09:47:53,6 2015-03-28 09:52:53,13 2015-03-28 09:57:53,13 2015-03-28 10:02:53,7 2015-03-28 10:07:53,8 2015-03-28 10:12:53,8 2015-03-28 10:17:53,7 2015-03-28 10:22:53,8 2015-03-28 10:27:53,8 2015-03-28 10:32:53,14 2015-03-28 10:37:53,5 2015-03-28 10:42:53,9 2015-03-28 10:47:53,6 2015-03-28 10:52:53,49 2015-03-28 10:57:53,12 2015-03-28 11:02:53,8 2015-03-28 11:07:53,15 2015-03-28 11:12:53,14 2015-03-28 11:17:53,2 2015-03-28 11:22:53,11 2015-03-28 11:27:53,8 2015-03-28 11:32:53,7 2015-03-28 11:37:53,7 2015-03-28 11:42:53,5 2015-03-28 11:47:53,3 2015-03-28 11:52:53,14 2015-03-28 11:57:53,52 2015-03-28 12:02:53,6 2015-03-28 12:07:53,9 2015-03-28 12:12:53,15 2015-03-28 12:17:53,12 2015-03-28 12:22:53,17 2015-03-28 12:27:53,8 2015-03-28 12:32:53,19 2015-03-28 12:37:53,19 2015-03-28 12:42:53,21 2015-03-28 12:47:53,8 2015-03-28 12:52:53,19 2015-03-28 12:57:53,14 2015-03-28 13:02:53,11 2015-03-28 13:07:53,8 2015-03-28 13:12:53,32 2015-03-28 13:17:53,14 2015-03-28 13:22:53,7 2015-03-28 13:27:53,24 2015-03-28 13:32:53,12 2015-03-28 13:37:53,5 2015-03-28 13:42:53,20 2015-03-28 13:47:53,15 2015-03-28 13:52:53,12 2015-03-28 13:57:53,20 2015-03-28 14:02:53,19 2015-03-28 14:07:53,8 2015-03-28 14:12:53,5 2015-03-28 14:17:53,12 2015-03-28 14:22:53,15 2015-03-28 14:27:53,18 2015-03-28 14:32:53,53 2015-03-28 14:37:53,6 2015-03-28 14:42:53,17 2015-03-28 14:47:53,16 2015-03-28 14:52:53,43 2015-03-28 14:57:53,16 2015-03-28 15:02:53,15 2015-03-28 15:07:53,24 2015-03-28 15:12:53,23 2015-03-28 15:17:53,14 2015-03-28 15:22:53,19 2015-03-28 15:27:53,13 2015-03-28 15:32:53,8 2015-03-28 15:37:53,14 2015-03-28 15:42:53,20 2015-03-28 15:47:53,11 2015-03-28 15:52:53,25 2015-03-28 15:57:53,27 2015-03-28 16:02:53,18 2015-03-28 16:07:53,23 2015-03-28 16:12:53,32 2015-03-28 16:17:53,20 2015-03-28 16:22:53,17 2015-03-28 16:27:53,15 2015-03-28 16:32:53,8 2015-03-28 16:37:53,12 2015-03-28 16:42:53,12 2015-03-28 16:47:53,11 2015-03-28 16:52:53,11 2015-03-28 16:57:53,18 2015-03-28 17:02:53,46 2015-03-28 17:07:53,11 2015-03-28 17:12:53,10 2015-03-28 17:17:53,20 2015-03-28 17:22:53,9 2015-03-28 17:27:53,15 2015-03-28 17:32:53,10 2015-03-28 17:37:53,10 2015-03-28 17:42:53,29 2015-03-28 17:47:53,21 2015-03-28 17:52:53,15 2015-03-28 17:57:53,11 2015-03-28 18:02:53,22 2015-03-28 18:07:53,51 2015-03-28 18:12:53,12 2015-03-28 18:17:53,11 2015-03-28 18:22:53,5 2015-03-28 18:27:53,6 2015-03-28 18:32:53,7 2015-03-28 18:37:53,6 2015-03-28 18:42:53,6 2015-03-28 18:47:53,15 2015-03-28 18:52:53,6 2015-03-28 18:57:53,16 2015-03-28 19:02:53,12 2015-03-28 19:07:53,12 2015-03-28 19:12:53,4 2015-03-28 19:17:53,13 2015-03-28 19:22:53,7 2015-03-28 19:27:53,47 2015-03-28 19:32:53,11 2015-03-28 19:37:53,12 2015-03-28 19:42:53,12 2015-03-28 19:47:53,15 2015-03-28 19:52:53,12 2015-03-28 19:57:53,22 2015-03-28 20:02:53,7 2015-03-28 20:07:53,5 2015-03-28 20:12:53,8 2015-03-28 20:17:53,5 2015-03-28 20:22:53,8 2015-03-28 20:27:53,7 2015-03-28 20:32:53,35 2015-03-28 20:37:53,3 2015-03-28 20:42:53,16 2015-03-28 20:47:53,7 2015-03-28 20:52:53,15 2015-03-28 20:57:53,24 2015-03-28 21:02:53,18 2015-03-28 21:07:53,15 2015-03-28 21:12:53,28 2015-03-28 21:17:53,11 2015-03-28 21:22:53,13 2015-03-28 21:27:53,3 2015-03-28 21:32:53,8 2015-03-28 21:37:53,45 2015-03-28 21:42:53,14 2015-03-28 21:47:53,4 2015-03-28 21:52:53,10 2015-03-28 21:57:53,8 2015-03-28 22:02:53,8 2015-03-28 22:07:53,9 2015-03-28 22:12:53,10 2015-03-28 22:17:53,5 2015-03-28 22:22:53,6 2015-03-28 22:27:53,14 2015-03-28 22:32:53,17 2015-03-28 22:37:53,27 2015-03-28 22:42:53,16 2015-03-28 22:47:53,19 2015-03-28 22:52:53,15 2015-03-28 22:57:53,13 2015-03-28 23:02:53,17 2015-03-28 23:07:53,8 2015-03-28 23:12:53,6 2015-03-28 23:17:53,13 2015-03-28 23:22:53,20 2015-03-28 23:27:53,10 2015-03-28 23:32:53,8 2015-03-28 23:37:53,7 2015-03-28 23:42:53,13 2015-03-28 23:47:53,20 2015-03-28 23:52:53,22 2015-03-28 23:57:53,18 2015-03-29 00:02:53,13 2015-03-29 00:07:53,49 2015-03-29 00:12:53,10 2015-03-29 00:17:53,9 2015-03-29 00:22:53,9 2015-03-29 00:27:53,6 2015-03-29 00:32:53,13 2015-03-29 00:37:53,14 2015-03-29 00:42:53,43 2015-03-29 00:47:53,11 2015-03-29 00:52:53,5 2015-03-29 00:57:53,24 2015-03-29 01:02:53,14 2015-03-29 01:07:53,7 2015-03-29 01:12:53,15 2015-03-29 01:17:53,4 2015-03-29 01:22:53,8 2015-03-29 01:27:53,9 2015-03-29 01:32:53,8 2015-03-29 01:37:53,6 2015-03-29 01:42:53,12 2015-03-29 01:47:53,6 2015-03-29 01:52:53,12 2015-03-29 01:57:53,10 2015-03-29 02:02:53,9 2015-03-29 02:07:53,8 2015-03-29 02:12:53,20 2015-03-29 02:17:53,2 2015-03-29 02:22:53,5 2015-03-29 02:27:53,11 2015-03-29 02:32:53,4 2015-03-29 02:37:53,8 2015-03-29 02:42:53,7 2015-03-29 02:47:53,8 2015-03-29 02:52:53,2 2015-03-29 02:57:53,6 2015-03-29 03:02:53,4 2015-03-29 03:07:53,12 2015-03-29 03:12:53,16 2015-03-29 03:17:53,8 2015-03-29 03:22:53,8 2015-03-29 03:27:53,3 2015-03-29 03:32:53,7 2015-03-29 03:37:53,5 2015-03-29 03:42:53,5 2015-03-29 03:47:53,4 2015-03-29 03:52:53,9 2015-03-29 03:57:53,37 2015-03-29 04:02:53,10 2015-03-29 04:07:53,13 2015-03-29 04:12:53,7 2015-03-29 04:17:53,1 2015-03-29 04:22:53,7 2015-03-29 04:27:53,44 2015-03-29 04:32:53,5 2015-03-29 04:37:53,3 2015-03-29 04:42:53,11 2015-03-29 04:47:53,4 2015-03-29 04:52:53,3 2015-03-29 04:57:53,5 2015-03-29 05:02:53,7 2015-03-29 05:07:53,9 2015-03-29 05:12:53,3 2015-03-29 05:17:53,7 2015-03-29 05:22:53,5 2015-03-29 05:27:53,15 2015-03-29 05:32:53,6 2015-03-29 05:37:53,3 2015-03-29 05:42:53,1 2015-03-29 05:47:53,7 2015-03-29 05:52:53,5 2015-03-29 05:57:53,10 2015-03-29 06:02:53,5 2015-03-29 06:07:53,2 2015-03-29 06:12:53,8 2015-03-29 06:17:53,4 2015-03-29 06:22:53,3 2015-03-29 06:27:53,4 2015-03-29 06:32:53,9 2015-03-29 06:37:53,3 2015-03-29 06:42:53,12 2015-03-29 06:47:53,42 2015-03-29 06:52:53,3 2015-03-29 06:57:53,4 2015-03-29 07:02:53,9 2015-03-29 07:07:53,9 2015-03-29 07:12:53,8 2015-03-29 07:17:53,2 2015-03-29 07:22:53,5 2015-03-29 07:27:53,13 2015-03-29 07:32:53,11 2015-03-29 07:37:53,5 2015-03-29 07:42:53,4 2015-03-29 07:47:53,1 2015-03-29 07:52:53,6 2015-03-29 07:57:53,7 2015-03-29 08:02:53,6 2015-03-29 08:07:53,5 2015-03-29 08:12:53,4 2015-03-29 08:17:53,8 2015-03-29 08:22:53,8 2015-03-29 08:27:53,5 2015-03-29 08:32:53,4 2015-03-29 08:37:53,1 2015-03-29 08:42:53,3 2015-03-29 08:47:53,9 2015-03-29 08:52:53,5 2015-03-29 08:57:53,4 2015-03-29 09:02:53,8 2015-03-29 09:07:53,53 2015-03-29 09:12:53,6 2015-03-29 09:17:53,11 2015-03-29 09:22:53,6 2015-03-29 09:27:53,4 2015-03-29 09:32:53,6 2015-03-29 09:37:53,0 2015-03-29 09:42:53,4 2015-03-29 09:47:53,4 2015-03-29 09:52:53,6 2015-03-29 09:57:53,4 2015-03-29 10:02:53,1 2015-03-29 10:07:53,3 2015-03-29 10:12:53,8 2015-03-29 10:17:53,5 2015-03-29 10:22:53,6 2015-03-29 10:27:53,43 2015-03-29 10:32:53,5 2015-03-29 10:37:53,2 2015-03-29 10:42:53,5 2015-03-29 10:47:53,11 2015-03-29 10:52:53,6 2015-03-29 10:57:53,9 2015-03-29 11:02:53,9 2015-03-29 11:07:53,3 2015-03-29 11:12:53,4 2015-03-29 11:17:53,4 2015-03-29 11:22:53,3 2015-03-29 11:27:53,6 2015-03-29 11:32:53,0 2015-03-29 11:37:53,43 2015-03-29 11:42:53,7 2015-03-29 11:47:53,15 2015-03-29 11:52:53,10 2015-03-29 11:57:53,10 2015-03-29 12:02:53,2 2015-03-29 12:07:53,21 2015-03-29 12:12:53,2 2015-03-29 12:17:53,5 2015-03-29 12:22:53,7 2015-03-29 12:27:53,5 2015-03-29 12:32:53,7 2015-03-29 12:37:53,17 2015-03-29 12:42:53,10 2015-03-29 12:47:53,16 2015-03-29 12:52:53,7 2015-03-29 12:57:53,7 2015-03-29 13:02:53,8 2015-03-29 13:07:53,7 2015-03-29 13:12:53,7 2015-03-29 13:17:53,11 2015-03-29 13:22:53,0 2015-03-29 13:27:53,5 2015-03-29 13:32:53,6 2015-03-29 13:37:53,2 2015-03-29 13:42:53,6 2015-03-29 13:47:53,7 2015-03-29 13:52:53,11 2015-03-29 13:57:53,24 2015-03-29 14:02:53,45 2015-03-29 14:07:53,59 2015-03-29 14:12:53,16 2015-03-29 14:17:53,18 2015-03-29 14:22:53,13 2015-03-29 14:27:53,11 2015-03-29 14:32:53,5 2015-03-29 14:37:53,14 2015-03-29 14:42:53,8 2015-03-29 14:47:53,8 2015-03-29 14:52:53,8 2015-03-29 14:57:53,23 2015-03-29 15:02:53,10 2015-03-29 15:07:53,10 2015-03-29 15:12:53,12 2015-03-29 15:17:53,11 2015-03-29 15:22:53,14 2015-03-29 15:27:53,16 2015-03-29 15:32:53,9 2015-03-29 15:37:53,8 2015-03-29 15:42:53,14 2015-03-29 15:47:53,15 2015-03-29 15:52:53,10 2015-03-29 15:57:53,13 2015-03-29 16:02:53,17 2015-03-29 16:07:53,10 2015-03-29 16:12:53,15 2015-03-29 16:17:53,11 2015-03-29 16:22:53,12 2015-03-29 16:27:53,21 2015-03-29 16:32:53,10 2015-03-29 16:37:53,39 2015-03-29 16:42:53,26 2015-03-29 16:47:53,19 2015-03-29 16:52:53,14 2015-03-29 16:57:53,15 2015-03-29 17:02:53,15 2015-03-29 17:07:53,17 2015-03-29 17:12:53,12 2015-03-29 17:17:53,13 2015-03-29 17:22:53,16 2015-03-29 17:27:53,11 2015-03-29 17:32:53,15 2015-03-29 17:37:53,45 2015-03-29 17:42:53,16 2015-03-29 17:47:53,14 2015-03-29 17:52:53,17 2015-03-29 17:57:53,30 2015-03-29 18:02:53,21 2015-03-29 18:07:53,11 2015-03-29 18:12:53,7 2015-03-29 18:17:53,11 2015-03-29 18:22:53,15 2015-03-29 18:27:53,16 2015-03-29 18:32:53,15 2015-03-29 18:37:53,10 2015-03-29 18:42:53,17 2015-03-29 18:47:53,11 2015-03-29 18:52:53,6 2015-03-29 18:57:53,14 2015-03-29 19:02:53,15 2015-03-29 19:07:53,9 2015-03-29 19:12:53,11 2015-03-29 19:17:53,7 2015-03-29 19:22:53,59 2015-03-29 19:27:53,12 2015-03-29 19:32:53,8 2015-03-29 19:37:53,11 2015-03-29 19:42:53,12 2015-03-29 19:47:53,18 2015-03-29 19:52:53,10 2015-03-29 19:57:53,12 2015-03-29 20:02:53,29 2015-03-29 20:07:53,10 2015-03-29 20:12:53,12 2015-03-29 20:17:53,15 2015-03-29 20:22:53,11 2015-03-29 20:27:53,12 2015-03-29 20:32:53,19 2015-03-29 20:37:53,11 2015-03-29 20:42:53,16 2015-03-29 20:47:53,12 2015-03-29 20:52:53,8 2015-03-29 20:57:53,15 2015-03-29 21:02:53,11 2015-03-29 21:07:53,18 2015-03-29 21:12:53,5 2015-03-29 21:17:53,13 2015-03-29 21:22:53,14 2015-03-29 21:27:53,8 2015-03-29 21:32:53,8 2015-03-29 21:37:53,13 2015-03-29 21:42:53,8 2015-03-29 21:47:53,42 2015-03-29 21:52:53,5 2015-03-29 21:57:53,15 2015-03-29 22:02:53,7 2015-03-29 22:07:53,10 2015-03-29 22:12:53,9 2015-03-29 22:17:53,18 2015-03-29 22:22:53,12 2015-03-29 22:27:53,20 2015-03-29 22:32:53,12 2015-03-29 22:37:53,13 2015-03-29 22:42:53,24 2015-03-29 22:47:53,15 2015-03-29 22:52:53,10 2015-03-29 22:57:53,10 2015-03-29 23:02:53,12 2015-03-29 23:07:53,13 2015-03-29 23:12:53,5 2015-03-29 23:17:53,6 2015-03-29 23:22:53,11 2015-03-29 23:27:53,17 2015-03-29 23:32:53,9 2015-03-29 23:37:53,12 2015-03-29 23:42:53,27 2015-03-29 23:47:53,12 2015-03-29 23:52:53,23 2015-03-29 23:57:53,9 2015-03-30 00:02:53,8 2015-03-30 00:07:53,52 2015-03-30 00:12:53,25 2015-03-30 00:17:53,10 2015-03-30 00:22:53,18 2015-03-30 00:27:53,45 2015-03-30 00:32:53,8 2015-03-30 00:37:53,7 2015-03-30 00:42:53,13 2015-03-30 00:47:53,19 2015-03-30 00:52:53,12 2015-03-30 00:57:53,7 2015-03-30 01:02:53,7 2015-03-30 01:07:53,15 2015-03-30 01:12:53,9 2015-03-30 01:17:53,15 2015-03-30 01:22:53,22 2015-03-30 01:27:53,12 2015-03-30 01:32:53,9 2015-03-30 01:37:53,8 2015-03-30 01:42:53,5 2015-03-30 01:47:53,11 2015-03-30 01:52:53,3 2015-03-30 01:57:53,10 2015-03-30 02:02:53,8 2015-03-30 02:07:53,3 2015-03-30 02:12:53,9 2015-03-30 02:17:53,6 2015-03-30 02:22:53,6 2015-03-30 02:27:53,15 2015-03-30 02:32:53,50 2015-03-30 02:37:53,10 2015-03-30 02:42:53,14 2015-03-30 02:47:53,11 2015-03-30 02:52:53,17 2015-03-30 02:57:53,9 2015-03-30 03:02:53,11 2015-03-30 03:07:53,4 2015-03-30 03:12:53,13 2015-03-30 03:17:53,4 2015-03-30 03:22:53,10 2015-03-30 03:27:53,6 2015-03-30 03:32:53,13 2015-03-30 03:37:53,51 2015-03-30 03:42:53,8 2015-03-30 03:47:53,10 2015-03-30 03:52:53,10 2015-03-30 03:57:53,6 2015-03-30 04:02:53,3 2015-03-30 04:07:53,7 2015-03-30 04:12:53,6 2015-03-30 04:17:53,4 2015-03-30 04:22:53,6 2015-03-30 04:27:53,6 2015-03-30 04:32:53,9 2015-03-30 04:37:53,11 2015-03-30 04:42:53,47 2015-03-30 04:47:53,11 2015-03-30 04:52:53,12 2015-03-30 04:57:53,17 2015-03-30 05:02:53,18 2015-03-30 05:07:53,11 2015-03-30 05:12:53,8 2015-03-30 05:17:53,6 2015-03-30 05:22:53,98 2015-03-30 05:27:53,4 2015-03-30 05:32:53,4 2015-03-30 05:37:53,10 2015-03-30 05:42:53,7 2015-03-30 05:47:53,14 2015-03-30 05:52:53,4 2015-03-30 05:57:53,16 2015-03-30 06:02:53,4 2015-03-30 06:07:53,8 2015-03-30 06:12:53,12 2015-03-30 06:17:53,2 2015-03-30 06:22:53,14 2015-03-30 06:27:53,12 2015-03-30 06:32:53,13 2015-03-30 06:37:53,23 2015-03-30 06:42:53,3 2015-03-30 06:47:53,15 2015-03-30 06:52:53,7 2015-03-30 06:57:53,17 2015-03-30 07:02:53,53 2015-03-30 07:07:53,18 2015-03-30 07:12:53,5 2015-03-30 07:17:53,9 2015-03-30 07:22:53,2 2015-03-30 07:27:53,11 2015-03-30 07:32:53,8 2015-03-30 07:37:53,8 2015-03-30 07:42:53,16 2015-03-30 07:47:53,22 2015-03-30 07:52:53,8 2015-03-30 07:57:53,12 2015-03-30 08:02:53,9 2015-03-30 08:07:53,8 2015-03-30 08:12:53,12 2015-03-30 08:17:53,9 2015-03-30 08:22:53,4 2015-03-30 08:27:53,6 2015-03-30 08:32:53,12 2015-03-30 08:37:53,6 2015-03-30 08:42:53,8 2015-03-30 08:47:53,12 2015-03-30 08:52:53,8 2015-03-30 08:57:53,13 2015-03-30 09:02:53,3 2015-03-30 09:07:53,9 2015-03-30 09:12:53,11 2015-03-30 09:17:53,11 2015-03-30 09:22:53,9 2015-03-30 09:27:53,14 2015-03-30 09:32:53,10 2015-03-30 09:37:53,7 2015-03-30 09:42:53,54 2015-03-30 09:47:53,13 2015-03-30 09:52:53,8 2015-03-30 09:57:53,15 2015-03-30 10:02:53,10 2015-03-30 10:07:53,10 2015-03-30 10:12:53,15 2015-03-30 10:17:53,15 2015-03-30 10:22:53,13 2015-03-30 10:27:53,14 2015-03-30 10:32:53,8 2015-03-30 10:37:53,44 2015-03-30 10:42:53,9 2015-03-30 10:47:53,13 2015-03-30 10:52:53,7 2015-03-30 10:57:53,10 2015-03-30 11:02:53,7 2015-03-30 11:07:53,4 2015-03-30 11:12:53,8 2015-03-30 11:17:53,12 2015-03-30 11:22:53,5 2015-03-30 11:27:53,14 2015-03-30 11:32:53,13 2015-03-30 11:37:53,10 2015-03-30 11:42:53,7 2015-03-30 11:47:53,17 2015-03-30 11:52:53,2 2015-03-30 11:57:53,15 2015-03-30 12:02:53,19 2015-03-30 12:07:53,9 2015-03-30 12:12:53,7 2015-03-30 12:17:53,12 2015-03-30 12:22:53,8 2015-03-30 12:27:53,51 2015-03-30 12:32:53,10 2015-03-30 12:37:53,12 2015-03-30 12:42:53,14 2015-03-30 12:47:53,13 2015-03-30 12:52:53,25 2015-03-30 12:57:53,26 2015-03-30 13:02:53,22 2015-03-30 13:07:53,12 2015-03-30 13:12:53,22 2015-03-30 13:17:53,11 2015-03-30 13:22:53,11 2015-03-30 13:27:53,12 2015-03-30 13:32:53,11 2015-03-30 13:37:53,13 2015-03-30 13:42:53,15 2015-03-30 13:47:53,15 2015-03-30 13:52:53,27 2015-03-30 13:57:53,15 2015-03-30 14:02:53,13 2015-03-30 14:07:53,23 2015-03-30 14:12:53,12 2015-03-30 14:17:53,47 2015-03-30 14:22:53,15 2015-03-30 14:27:53,18 2015-03-30 14:32:53,15 2015-03-30 14:37:53,23 2015-03-30 14:42:53,21 2015-03-30 14:47:53,22 2015-03-30 14:52:53,25 2015-03-30 14:57:53,23 2015-03-30 15:02:53,10 2015-03-30 15:07:53,6 2015-03-30 15:12:53,21 2015-03-30 15:17:53,69 2015-03-30 15:22:53,20 2015-03-30 15:27:53,23 2015-03-30 15:32:53,32 2015-03-30 15:37:53,29 2015-03-30 15:42:53,12 2015-03-30 15:47:53,19 2015-03-30 15:52:53,15 2015-03-30 15:57:53,36 2015-03-30 16:02:53,24 2015-03-30 16:07:53,34 2015-03-30 16:12:53,19 2015-03-30 16:17:53,24 2015-03-30 16:22:53,31 2015-03-30 16:27:53,33 2015-03-30 16:32:53,15 2015-03-30 16:37:53,17 2015-03-30 16:42:53,25 2015-03-30 16:47:53,27 2015-03-30 16:52:53,31 2015-03-30 16:57:53,34 2015-03-30 17:02:53,22 2015-03-30 17:07:53,16 2015-03-30 17:12:53,18 2015-03-30 17:17:53,30 2015-03-30 17:22:53,28 2015-03-30 17:27:53,27 2015-03-30 17:32:53,28 2015-03-30 17:37:53,30 2015-03-30 17:42:53,17 2015-03-30 17:47:53,19 2015-03-30 17:52:53,18 2015-03-30 17:57:53,22 2015-03-30 18:02:53,41 2015-03-30 18:07:53,35 2015-03-30 18:12:53,43 2015-03-30 18:17:53,27 2015-03-30 18:22:53,19 2015-03-30 18:27:53,19 2015-03-30 18:32:53,12 2015-03-30 18:37:53,19 2015-03-30 18:42:53,20 2015-03-30 18:47:53,58 2015-03-30 18:52:53,24 2015-03-30 18:57:53,27 2015-03-30 19:02:53,38 2015-03-30 19:07:53,26 2015-03-30 19:12:53,22 2015-03-30 19:17:53,28 2015-03-30 19:22:53,15 2015-03-30 19:27:53,39 2015-03-30 19:32:53,43 2015-03-30 19:37:53,19 2015-03-30 19:42:53,22 2015-03-30 19:47:53,23 2015-03-30 19:52:53,26 2015-03-30 19:57:53,27 2015-03-30 20:02:53,27 2015-03-30 20:07:53,26 2015-03-30 20:12:53,33 2015-03-30 20:17:53,20 2015-03-30 20:22:53,12 2015-03-30 20:27:53,20 2015-03-30 20:32:53,20 2015-03-30 20:37:53,19 2015-03-30 20:42:53,9 2015-03-30 20:47:53,12 2015-03-30 20:52:53,18 2015-03-30 20:57:53,29 2015-03-30 21:02:53,14 2015-03-30 21:07:53,14 2015-03-30 21:12:53,19 2015-03-30 21:17:53,8 2015-03-30 21:22:53,12 2015-03-30 21:27:53,18 2015-03-30 21:32:53,53 2015-03-30 21:37:53,21 2015-03-30 21:42:53,21 2015-03-30 21:47:53,15 2015-03-30 21:52:53,12 2015-03-30 21:57:53,23 2015-03-30 22:02:53,15 2015-03-30 22:07:53,15 2015-03-30 22:12:53,38 2015-03-30 22:17:53,30 2015-03-30 22:22:53,14 2015-03-30 22:27:53,20 2015-03-30 22:32:53,26 2015-03-30 22:37:53,10 2015-03-30 22:42:53,19 2015-03-30 22:47:53,15 2015-03-30 22:52:53,10 2015-03-30 22:57:53,19 2015-03-30 23:02:53,11 2015-03-30 23:07:53,51 2015-03-30 23:12:53,50 2015-03-30 23:17:53,34 2015-03-30 23:22:53,32 2015-03-30 23:27:53,21 2015-03-30 23:32:53,20 2015-03-30 23:37:53,15 2015-03-30 23:42:53,17 2015-03-30 23:47:53,17 2015-03-30 23:52:53,15 2015-03-30 23:57:53,34 2015-03-31 00:02:53,25 2015-03-31 00:07:53,15 2015-03-31 00:12:53,21 2015-03-31 00:17:53,17 2015-03-31 00:22:53,23 2015-03-31 00:27:53,14 2015-03-31 00:32:53,18 2015-03-31 00:37:53,18 2015-03-31 00:42:53,10 2015-03-31 00:47:53,9 2015-03-31 00:52:53,16 2015-03-31 00:57:53,56 2015-03-31 01:02:53,12 2015-03-31 01:07:53,18 2015-03-31 01:12:53,14 2015-03-31 01:17:53,13 2015-03-31 01:22:53,7 2015-03-31 01:27:53,48 2015-03-31 01:32:53,8 2015-03-31 01:37:53,20 2015-03-31 01:42:53,11 2015-03-31 01:47:53,16 2015-03-31 01:52:53,11 2015-03-31 01:57:53,16 2015-03-31 02:02:53,11 2015-03-31 02:07:53,17 2015-03-31 02:12:53,9 2015-03-31 02:17:53,13 2015-03-31 02:22:53,13 2015-03-31 02:27:53,12 2015-03-31 02:32:53,20 2015-03-31 02:37:53,11 2015-03-31 02:42:53,11 2015-03-31 02:47:53,11 2015-03-31 02:52:53,12 2015-03-31 02:57:53,14 2015-03-31 03:02:53,21 2015-03-31 03:07:53,7 2015-03-31 03:12:53,12 2015-03-31 03:17:53,10 2015-03-31 03:22:53,8 2015-03-31 03:27:53,6 2015-03-31 03:32:53,14 2015-03-31 03:37:53,12 2015-03-31 03:42:53,5 2015-03-31 03:47:53,43 2015-03-31 03:52:53,16 2015-03-31 03:57:53,10 2015-03-31 04:02:53,10 2015-03-31 04:07:53,15 2015-03-31 04:12:53,12 2015-03-31 04:17:53,12 2015-03-31 04:22:53,59 2015-03-31 04:27:53,9 2015-03-31 04:32:53,10 2015-03-31 04:37:53,10 2015-03-31 04:42:53,15 2015-03-31 04:47:53,24 2015-03-31 04:52:53,4 2015-03-31 04:57:53,9 2015-03-31 05:02:53,15 2015-03-31 05:07:53,9 2015-03-31 05:12:53,8 2015-03-31 05:17:53,10 2015-03-31 05:22:53,8 2015-03-31 05:27:53,10 2015-03-31 05:32:53,14 2015-03-31 05:37:53,10 2015-03-31 05:42:53,8 2015-03-31 05:47:53,9 2015-03-31 05:52:53,14 2015-03-31 05:57:53,28 2015-03-31 06:02:53,15 2015-03-31 06:07:53,15 2015-03-31 06:12:53,46 2015-03-31 06:17:53,14 2015-03-31 06:22:53,13 2015-03-31 06:27:53,14 2015-03-31 06:32:53,8 2015-03-31 06:37:53,15 2015-03-31 06:42:53,6 2015-03-31 06:47:53,19 2015-03-31 06:52:53,8 2015-03-31 06:57:53,23 2015-03-31 07:02:53,17 2015-03-31 07:07:53,25 2015-03-31 07:12:53,7 2015-03-31 07:17:53,11 2015-03-31 07:22:53,18 2015-03-31 07:27:53,21 2015-03-31 07:32:53,11 2015-03-31 07:37:53,12 2015-03-31 07:42:53,13 2015-03-31 07:47:53,15 2015-03-31 07:52:53,43 2015-03-31 07:57:53,9 2015-03-31 08:02:53,13 2015-03-31 08:07:53,11 2015-03-31 08:12:53,3 2015-03-31 08:17:53,20 2015-03-31 08:22:53,11 2015-03-31 08:27:53,13 2015-03-31 08:32:53,14 2015-03-31 08:37:53,7 2015-03-31 08:42:53,9 2015-03-31 08:47:53,43 2015-03-31 08:52:53,7 2015-03-31 08:57:53,25 2015-03-31 09:02:53,17 2015-03-31 09:07:53,18 2015-03-31 09:12:53,8 2015-03-31 09:17:53,9 2015-03-31 09:22:53,13 2015-03-31 09:27:53,12 2015-03-31 09:32:53,12 2015-03-31 09:37:53,16 2015-03-31 09:42:53,19 2015-03-31 09:47:53,15 2015-03-31 09:52:53,18 2015-03-31 09:57:53,26 2015-03-31 10:02:53,13 2015-03-31 10:07:53,18 2015-03-31 10:12:53,28 2015-03-31 10:17:53,9 2015-03-31 10:22:53,22 2015-03-31 10:27:53,6 2015-03-31 10:32:53,9 2015-03-31 10:37:53,33 2015-03-31 10:42:53,12 2015-03-31 10:47:53,13 2015-03-31 10:52:53,26 2015-03-31 10:57:53,26 2015-03-31 11:02:53,23 2015-03-31 11:07:53,18 2015-03-31 11:12:53,23 2015-03-31 11:17:53,12 2015-03-31 11:22:53,45 2015-03-31 11:27:53,37 2015-03-31 11:32:53,26 2015-03-31 11:37:53,12 2015-03-31 11:42:53,16 2015-03-31 11:47:53,31 2015-03-31 11:52:53,17 2015-03-31 11:57:53,19 2015-03-31 12:02:53,39 2015-03-31 12:07:53,34 2015-03-31 12:12:53,24 2015-03-31 12:17:53,26 2015-03-31 12:22:53,16 2015-03-31 12:27:53,16 2015-03-31 12:32:53,18 2015-03-31 12:37:53,25 2015-03-31 12:42:53,32 2015-03-31 12:47:53,27 2015-03-31 12:52:53,20 2015-03-31 12:57:53,16 2015-03-31 13:02:53,16 2015-03-31 13:07:53,23 2015-03-31 13:12:53,25 2015-03-31 13:17:53,32 2015-03-31 13:22:53,26 2015-03-31 13:27:53,20 2015-03-31 13:32:53,31 2015-03-31 13:37:53,23 2015-03-31 13:42:53,23 2015-03-31 13:47:53,14 2015-03-31 13:52:53,17 2015-03-31 13:57:53,51 2015-03-31 14:02:53,11 2015-03-31 14:07:53,21 2015-03-31 14:12:53,14 2015-03-31 14:17:53,24 2015-03-31 14:22:53,24 2015-03-31 14:27:53,19 2015-03-31 14:32:53,27 2015-03-31 14:37:53,27 2015-03-31 14:42:53,29 2015-03-31 14:47:53,31 2015-03-31 14:52:53,37 2015-03-31 14:57:53,36 2015-03-31 15:02:53,38 2015-03-31 15:07:53,34 2015-03-31 15:12:53,27 2015-03-31 15:17:53,27 2015-03-31 15:22:53,37 2015-03-31 15:27:53,36 2015-03-31 15:32:53,35 2015-03-31 15:37:53,40 2015-03-31 15:42:53,28 2015-03-31 15:47:53,28 2015-03-31 15:52:53,37 2015-03-31 15:57:53,15 2015-03-31 16:02:53,29 2015-03-31 16:07:53,35 2015-03-31 16:12:53,28 2015-03-31 16:17:53,28 2015-03-31 16:22:53,35 2015-03-31 16:27:53,44 2015-03-31 16:32:53,36 2015-03-31 16:37:53,50 2015-03-31 16:42:53,59 2015-03-31 16:47:53,61 2015-03-31 16:52:53,72 2015-03-31 16:57:53,58 2015-03-31 17:02:53,73 2015-03-31 17:07:53,88 2015-03-31 17:12:53,73 2015-03-31 17:17:53,66 2015-03-31 17:22:53,64 2015-03-31 17:27:53,57 2015-03-31 17:32:53,41 2015-03-31 17:37:53,32 2015-03-31 17:42:53,45 2015-03-31 17:47:53,37 2015-03-31 17:52:53,42 2015-03-31 17:57:53,59 2015-03-31 18:02:53,44 2015-03-31 18:07:53,39 2015-03-31 18:12:53,35 2015-03-31 18:17:53,47 2015-03-31 18:22:53,35 2015-03-31 18:27:53,44 2015-03-31 18:32:53,56 2015-03-31 18:37:53,43 2015-03-31 18:42:53,28 2015-03-31 18:47:53,67 2015-03-31 18:52:53,29 2015-03-31 18:57:53,34 2015-03-31 19:02:53,33 2015-03-31 19:07:53,24 2015-03-31 19:12:53,52 2015-03-31 19:17:53,60 2015-03-31 19:22:53,53 2015-03-31 19:27:53,44 2015-03-31 19:32:53,54 2015-03-31 19:37:53,35 2015-03-31 19:42:53,60 2015-03-31 19:47:53,34 2015-03-31 19:52:53,48 2015-03-31 19:57:53,46 2015-03-31 20:02:53,41 2015-03-31 20:07:53,34 2015-03-31 20:12:53,33 2015-03-31 20:17:53,41 2015-03-31 20:22:53,40 2015-03-31 20:27:53,30 2015-03-31 20:32:53,42 2015-03-31 20:37:53,37 2015-03-31 20:42:53,46 2015-03-31 20:47:53,33 2015-03-31 20:52:53,39 2015-03-31 20:57:53,23 2015-03-31 21:02:53,23 2015-03-31 21:07:53,38 2015-03-31 21:12:53,27 2015-03-31 21:17:53,28 2015-03-31 21:22:53,31 2015-03-31 21:27:53,101 2015-03-31 21:32:53,58 2015-03-31 21:37:53,53 2015-03-31 21:42:53,37 2015-03-31 21:47:53,28 2015-03-31 21:52:53,41 2015-03-31 21:57:53,49 2015-03-31 22:02:53,26 2015-03-31 22:07:53,33 2015-03-31 22:12:53,41 2015-03-31 22:17:53,23 2015-03-31 22:22:53,42 2015-03-31 22:27:53,27 2015-03-31 22:32:53,55 2015-03-31 22:37:53,39 2015-03-31 22:42:53,28 2015-03-31 22:47:53,20 2015-03-31 22:52:53,28 2015-03-31 22:57:53,33 2015-03-31 23:02:53,29 2015-03-31 23:07:53,25 2015-03-31 23:12:53,23 2015-03-31 23:17:53,22 2015-03-31 23:22:53,29 2015-03-31 23:27:53,37 2015-03-31 23:32:53,16 2015-03-31 23:37:53,23 2015-03-31 23:42:53,44 2015-03-31 23:47:53,26 2015-03-31 23:52:53,30 2015-03-31 23:57:53,42 2015-04-01 00:02:53,22 2015-04-01 00:07:53,31 2015-04-01 00:12:53,22 2015-04-01 00:17:53,18 2015-04-01 00:22:53,32 2015-04-01 00:27:53,38 2015-04-01 00:32:53,20 2015-04-01 00:37:53,21 2015-04-01 00:42:53,22 2015-04-01 00:47:53,23 2015-04-01 00:52:53,17 2015-04-01 00:57:53,28 2015-04-01 01:02:53,79 2015-04-01 01:07:53,93 2015-04-01 01:12:53,63 2015-04-01 01:17:53,45 2015-04-01 01:22:53,52 2015-04-01 01:27:53,37 2015-04-01 01:32:53,46 2015-04-01 01:37:53,31 2015-04-01 01:42:53,30 2015-04-01 01:47:53,38 2015-04-01 01:52:53,30 2015-04-01 01:57:53,29 2015-04-01 02:02:53,33 2015-04-01 02:07:53,25 2015-04-01 02:12:53,26 2015-04-01 02:17:53,24 2015-04-01 02:22:53,30 2015-04-01 02:27:53,52 2015-04-01 02:32:53,33 2015-04-01 02:37:53,22 2015-04-01 02:42:53,21 2015-04-01 02:47:53,19 2015-04-01 02:52:53,21 2015-04-01 02:57:53,35 2015-04-01 03:02:53,26 2015-04-01 03:07:53,20 2015-04-01 03:12:53,27 2015-04-01 03:17:53,17 2015-04-01 03:22:53,34 2015-04-01 03:27:53,23 2015-04-01 03:32:53,24 2015-04-01 03:37:53,15 2015-04-01 03:42:53,23 2015-04-01 03:47:53,19 2015-04-01 03:52:53,24 2015-04-01 03:57:53,187 2015-04-01 04:02:53,244 2015-04-01 04:07:53,179 2015-04-01 04:12:53,121 2015-04-01 04:17:53,136 2015-04-01 04:22:53,112 2015-04-01 04:27:53,100 2015-04-01 04:32:53,103 2015-04-01 04:37:53,98 2015-04-01 04:42:53,100 2015-04-01 04:47:53,83 2015-04-01 04:52:53,77 2015-04-01 04:57:53,70 2015-04-01 05:02:53,88 2015-04-01 05:07:53,67 2015-04-01 05:12:53,73 2015-04-01 05:17:53,53 2015-04-01 05:22:53,60 2015-04-01 05:27:53,53 2015-04-01 05:32:53,89 2015-04-01 05:37:53,71 2015-04-01 05:42:53,63 2015-04-01 05:47:53,110 2015-04-01 05:52:53,215 2015-04-01 05:57:53,69 2015-04-01 06:02:53,55 2015-04-01 06:07:53,63 2015-04-01 06:12:53,56 2015-04-01 06:17:53,67 2015-04-01 06:22:53,73 2015-04-01 06:27:53,49 2015-04-01 06:32:53,134 2015-04-01 06:37:53,206 2015-04-01 06:42:53,156 2015-04-01 06:47:53,140 2015-04-01 06:52:53,105 2015-04-01 06:57:53,96 2015-04-01 07:02:53,97 2015-04-01 07:07:53,91 2015-04-01 07:12:53,99 2015-04-01 07:17:53,79 2015-04-01 07:22:53,72 2015-04-01 07:27:53,55 2015-04-01 07:32:53,71 2015-04-01 07:37:53,60 2015-04-01 07:42:53,74 2015-04-01 07:47:53,62 2015-04-01 07:52:53,88 2015-04-01 07:57:53,66 2015-04-01 08:02:53,72 2015-04-01 08:07:53,62 2015-04-01 08:12:53,73 2015-04-01 08:17:53,82 2015-04-01 08:22:53,70 2015-04-01 08:27:53,64 2015-04-01 08:32:53,44 2015-04-01 08:37:53,62 2015-04-01 08:42:53,55 2015-04-01 08:47:53,52 2015-04-01 08:52:53,72 2015-04-01 08:57:53,63 2015-04-01 09:02:53,71 2015-04-01 09:07:53,47 2015-04-01 09:12:53,59 2015-04-01 09:17:53,44 2015-04-01 09:22:53,41 2015-04-01 09:27:53,54 2015-04-01 09:32:53,67 2015-04-01 09:37:53,59 2015-04-01 09:42:53,50 2015-04-01 09:47:53,40 2015-04-01 09:52:53,49 2015-04-01 09:57:53,42 2015-04-01 10:02:53,44 2015-04-01 10:07:53,73 2015-04-01 10:12:53,44 2015-04-01 10:17:53,36 2015-04-01 10:22:53,61 2015-04-01 10:27:53,41 2015-04-01 10:32:53,51 2015-04-01 10:37:53,40 2015-04-01 10:42:53,39 2015-04-01 10:47:53,36 2015-04-01 10:52:53,48 2015-04-01 10:57:53,47 2015-04-01 11:02:53,57 2015-04-01 11:07:53,48 2015-04-01 11:12:53,56 2015-04-01 11:17:53,50 2015-04-01 11:22:53,31 2015-04-01 11:27:53,63 2015-04-01 11:32:53,44 2015-04-01 11:37:53,49 2015-04-01 11:42:53,57 2015-04-01 11:47:53,54 2015-04-01 11:52:53,52 2015-04-01 11:57:53,59 2015-04-01 12:02:53,45 2015-04-01 12:07:53,41 2015-04-01 12:12:53,54 2015-04-01 12:17:53,36 2015-04-01 12:22:53,50 2015-04-01 12:27:53,55 2015-04-01 12:32:53,52 2015-04-01 12:37:53,53 2015-04-01 12:42:53,52 2015-04-01 12:47:53,62 2015-04-01 12:52:53,48 2015-04-01 12:57:53,56 2015-04-01 13:02:53,61 2015-04-01 13:07:53,58 2015-04-01 13:12:53,53 2015-04-01 13:17:53,36 2015-04-01 13:22:53,42 2015-04-01 13:27:53,96 2015-04-01 13:32:53,86 2015-04-01 13:37:53,68 2015-04-01 13:42:53,59 2015-04-01 13:47:53,55 2015-04-01 13:52:53,43 2015-04-01 13:57:53,94 2015-04-01 14:02:53,100 2015-04-01 14:07:53,62 2015-04-01 14:12:53,64 2015-04-01 14:17:53,60 2015-04-01 14:22:53,77 2015-04-01 14:27:53,74 2015-04-01 14:32:53,61 2015-04-01 14:37:53,65 2015-04-01 14:42:53,48 2015-04-01 14:47:53,53 2015-04-01 14:52:53,59 2015-04-01 14:57:53,57 2015-04-01 15:02:53,57 2015-04-01 15:07:53,58 2015-04-01 15:12:53,46 2015-04-01 15:17:53,45 2015-04-01 15:22:53,45 2015-04-01 15:27:53,46 2015-04-01 15:32:53,49 2015-04-01 15:37:53,42 2015-04-01 15:42:53,65 2015-04-01 15:47:53,52 2015-04-01 15:52:53,47 2015-04-01 15:57:53,63 2015-04-01 16:02:53,49 2015-04-01 16:07:53,58 2015-04-01 16:12:53,55 2015-04-01 16:17:53,42 2015-04-01 16:22:53,68 2015-04-01 16:27:53,38 2015-04-01 16:32:53,49 2015-04-01 16:37:53,41 2015-04-01 16:42:53,61 2015-04-01 16:47:53,39 2015-04-01 16:52:53,41 2015-04-01 16:57:53,45 2015-04-01 17:02:53,46 2015-04-01 17:07:53,38 2015-04-01 17:12:53,37 2015-04-01 17:17:53,41 2015-04-01 17:22:53,39 2015-04-01 17:27:53,53 2015-04-01 17:32:53,42 2015-04-01 17:37:53,53 2015-04-01 17:42:53,56 2015-04-01 17:47:53,45 2015-04-01 17:52:53,45 2015-04-01 17:57:53,48 2015-04-01 18:02:53,44 2015-04-01 18:07:53,30 2015-04-01 18:12:53,51 2015-04-01 18:17:53,60 2015-04-01 18:22:53,35 2015-04-01 18:27:53,34 2015-04-01 18:32:53,43 2015-04-01 18:37:53,45 2015-04-01 18:42:53,42 2015-04-01 18:47:53,36 2015-04-01 18:52:53,31 2015-04-01 18:57:53,36 2015-04-01 19:02:53,34 2015-04-01 19:07:53,30 2015-04-01 19:12:53,218 2015-04-01 19:17:53,465 2015-04-01 19:22:53,174 2015-04-01 19:27:53,172 2015-04-01 19:32:53,100 2015-04-01 19:37:53,103 2015-04-01 19:42:53,90 2015-04-01 19:47:53,76 2015-04-01 19:52:53,98 2015-04-01 19:57:53,69 2015-04-01 20:02:53,67 2015-04-01 20:07:53,68 2015-04-01 20:12:53,59 2015-04-01 20:17:53,44 2015-04-01 20:22:53,40 2015-04-01 20:27:53,50 2015-04-01 20:32:53,38 2015-04-01 20:37:53,47 2015-04-01 20:42:53,48 2015-04-01 20:47:53,51 2015-04-01 20:52:53,46 2015-04-01 20:57:53,58 2015-04-01 21:02:53,48 2015-04-01 21:07:53,238 2015-04-01 21:12:53,160 2015-04-01 21:17:53,59 2015-04-01 21:22:53,40 2015-04-01 21:27:53,62 2015-04-01 21:32:53,40 2015-04-01 21:37:53,31 2015-04-01 21:42:53,40 2015-04-01 21:47:53,29 2015-04-01 21:52:53,41 2015-04-01 21:57:53,41 2015-04-01 22:02:53,57 2015-04-01 22:07:53,35 2015-04-01 22:12:53,33 2015-04-01 22:17:53,39 2015-04-01 22:22:53,23 2015-04-01 22:27:53,35 2015-04-01 22:32:53,45 2015-04-01 22:37:53,30 2015-04-01 22:42:53,32 2015-04-01 22:47:53,21 2015-04-01 22:52:53,22 2015-04-01 22:57:53,34 2015-04-01 23:02:53,22 2015-04-01 23:07:53,22 2015-04-01 23:12:53,33 2015-04-01 23:17:53,22 2015-04-01 23:22:53,34 2015-04-01 23:27:53,41 2015-04-01 23:32:53,15 2015-04-01 23:37:53,16 2015-04-01 23:42:53,18 2015-04-01 23:47:53,21 2015-04-01 23:52:53,19 2015-04-01 23:57:53,25 2015-04-02 00:02:53,26 2015-04-02 00:07:53,18 2015-04-02 00:12:53,24 2015-04-02 00:17:53,10 2015-04-02 00:22:53,22 2015-04-02 00:27:53,21 2015-04-02 00:32:53,22 2015-04-02 00:37:53,15 2015-04-02 00:42:53,19 2015-04-02 00:47:53,17 2015-04-02 00:52:53,22 2015-04-02 00:57:53,38 2015-04-02 01:02:53,27 2015-04-02 01:07:53,14 2015-04-02 01:12:53,19 2015-04-02 01:17:53,13 2015-04-02 01:22:53,24 2015-04-02 01:27:53,20 2015-04-02 01:32:53,25 2015-04-02 01:37:53,20 2015-04-02 01:42:53,30 2015-04-02 01:47:53,24 2015-04-02 01:52:53,14 2015-04-02 01:57:53,20 2015-04-02 02:02:53,19 2015-04-02 02:07:53,15 2015-04-02 02:12:53,22 2015-04-02 02:17:53,21 2015-04-02 02:22:53,18 2015-04-02 02:27:53,22 2015-04-02 02:32:53,32 2015-04-02 02:37:53,19 2015-04-02 02:42:53,17 2015-04-02 02:47:53,30 2015-04-02 02:52:53,23 2015-04-02 02:57:53,29 2015-04-02 03:02:53,32 2015-04-02 03:07:53,26 2015-04-02 03:12:53,40 2015-04-02 03:17:53,33 2015-04-02 03:22:53,19 2015-04-02 03:27:53,30 2015-04-02 03:32:53,26 2015-04-02 03:37:53,23 2015-04-02 03:42:53,36 2015-04-02 03:47:53,45 2015-04-02 03:52:53,29 2015-04-02 03:57:53,38 2015-04-02 04:02:53,16 2015-04-02 04:07:53,16 2015-04-02 04:12:53,20 2015-04-02 04:17:53,15 2015-04-02 04:22:53,13 2015-04-02 04:27:53,20 2015-04-02 04:32:53,18 2015-04-02 04:37:53,16 2015-04-02 04:42:53,20 2015-04-02 04:47:53,16 2015-04-02 04:52:53,20 2015-04-02 04:57:53,20 2015-04-02 05:02:53,13 2015-04-02 05:07:53,20 2015-04-02 05:12:53,17 2015-04-02 05:17:53,23 2015-04-02 05:22:53,13 2015-04-02 05:27:53,12 2015-04-02 05:32:53,13 2015-04-02 05:37:53,11 2015-04-02 05:42:53,14 2015-04-02 05:47:53,14 2015-04-02 05:52:53,16 2015-04-02 05:57:53,13 2015-04-02 06:02:53,21 2015-04-02 06:07:53,20 2015-04-02 06:12:53,11 2015-04-02 06:17:53,9 2015-04-02 06:22:53,15 2015-04-02 06:27:53,22 2015-04-02 06:32:53,27 2015-04-02 06:37:53,9 2015-04-02 06:42:53,11 2015-04-02 06:47:53,10 2015-04-02 06:52:53,12 2015-04-02 06:57:53,17 2015-04-02 07:02:53,11 2015-04-02 07:07:53,16 2015-04-02 07:12:53,7 2015-04-02 07:17:53,17 2015-04-02 07:22:53,23 2015-04-02 07:27:53,9 2015-04-02 07:32:53,23 2015-04-02 07:37:53,10 2015-04-02 07:42:53,20 2015-04-02 07:47:53,13 2015-04-02 07:52:53,13 2015-04-02 07:57:53,15 2015-04-02 08:02:53,17 2015-04-02 08:07:53,11 2015-04-02 08:12:53,12 2015-04-02 08:17:53,11 2015-04-02 08:22:53,18 2015-04-02 08:27:53,9 2015-04-02 08:32:53,15 2015-04-02 08:37:53,17 2015-04-02 08:42:53,14 2015-04-02 08:47:53,10 2015-04-02 08:52:53,26 2015-04-02 08:57:53,16 2015-04-02 09:02:53,16 2015-04-02 09:07:53,16 2015-04-02 09:12:53,11 2015-04-02 09:17:53,13 2015-04-02 09:22:53,26 2015-04-02 09:27:53,13 2015-04-02 09:32:53,16 2015-04-02 09:37:53,19 2015-04-02 09:42:53,11 2015-04-02 09:47:53,13 2015-04-02 09:52:53,8 2015-04-02 09:57:53,20 2015-04-02 10:02:53,20 2015-04-02 10:07:53,13 2015-04-02 10:12:53,25 2015-04-02 10:17:53,7 2015-04-02 10:22:53,6 2015-04-02 10:27:53,20 2015-04-02 10:32:53,12 2015-04-02 10:37:53,7 2015-04-02 10:42:53,18 2015-04-02 10:47:53,18 2015-04-02 10:52:53,15 2015-04-02 10:57:53,13 2015-04-02 11:02:53,16 2015-04-02 11:07:53,8 2015-04-02 11:12:53,11 2015-04-02 11:17:53,21 2015-04-02 11:22:53,15 2015-04-02 11:27:53,6 2015-04-02 11:32:53,14 2015-04-02 11:37:53,16 2015-04-02 11:42:53,11 2015-04-02 11:47:53,13 2015-04-02 11:52:53,15 2015-04-02 11:57:53,52 2015-04-02 12:02:53,38 2015-04-02 12:07:53,17 2015-04-02 12:12:53,20 2015-04-02 12:17:53,25 2015-04-02 12:22:53,33 2015-04-02 12:27:53,11 2015-04-02 12:32:53,31 2015-04-02 12:37:53,31 2015-04-02 12:42:53,30 2015-04-02 12:47:53,34 2015-04-02 12:52:53,24 2015-04-02 12:57:53,27 2015-04-02 13:02:53,19 2015-04-02 13:07:53,26 2015-04-02 13:12:53,18 2015-04-02 13:17:53,30 2015-04-02 13:22:53,24 2015-04-02 13:27:53,27 2015-04-02 13:32:53,36 2015-04-02 13:37:53,22 2015-04-02 13:42:53,21 2015-04-02 13:47:53,15 2015-04-02 13:52:53,25 2015-04-02 13:57:53,29 2015-04-02 14:02:53,22 2015-04-02 14:07:53,23 2015-04-02 14:12:53,37 2015-04-02 14:17:53,20 2015-04-02 14:22:53,25 2015-04-02 14:27:53,9 2015-04-02 14:32:53,27 2015-04-02 14:37:53,35 2015-04-02 14:42:53,35 2015-04-02 14:47:53,33 2015-04-02 14:52:53,31 2015-04-02 14:57:53,46 2015-04-02 15:02:53,36 2015-04-02 15:07:53,33 2015-04-02 15:12:53,38 2015-04-02 15:17:53,20 2015-04-02 15:22:53,27 2015-04-02 15:27:53,22 2015-04-02 15:32:53,23 2015-04-02 15:37:53,33 2015-04-02 15:42:53,47 2015-04-02 15:47:53,30 2015-04-02 15:52:53,17 2015-04-02 15:57:53,30 2015-04-02 16:02:53,17 2015-04-02 16:07:53,24 2015-04-02 16:12:53,28 2015-04-02 16:17:53,18 2015-04-02 16:22:53,27 2015-04-02 16:27:53,19 2015-04-02 16:32:53,20 2015-04-02 16:37:53,15 2015-04-02 16:42:53,19 2015-04-02 16:47:53,36 2015-04-02 16:52:53,42 2015-04-02 16:57:53,40 2015-04-02 17:02:53,34 2015-04-02 17:07:53,25 2015-04-02 17:12:53,32 2015-04-02 17:17:53,14 2015-04-02 17:22:53,23 2015-04-02 17:27:53,26 2015-04-02 17:32:53,17 2015-04-02 17:37:53,19 2015-04-02 17:42:53,20 2015-04-02 17:47:53,16 2015-04-02 17:52:53,18 2015-04-02 17:57:53,31 2015-04-02 18:02:53,26 2015-04-02 18:07:53,20 2015-04-02 18:12:53,15 2015-04-02 18:17:53,23 2015-04-02 18:22:53,22 2015-04-02 18:27:53,13 2015-04-02 18:32:53,20 2015-04-02 18:37:53,19 2015-04-02 18:42:53,25 2015-04-02 18:47:53,22 2015-04-02 18:52:53,21 2015-04-02 18:57:53,27 2015-04-02 19:02:53,45 2015-04-02 19:07:53,79 2015-04-02 19:12:53,45 2015-04-02 19:17:53,39 2015-04-02 19:22:53,28 2015-04-02 19:27:53,43 2015-04-02 19:32:53,41 2015-04-02 19:37:53,26 2015-04-02 19:42:53,27 2015-04-02 19:47:53,23 2015-04-02 19:52:53,22 2015-04-02 19:57:53,20 2015-04-02 20:02:53,29 2015-04-02 20:07:53,17 2015-04-02 20:12:53,25 2015-04-02 20:17:53,24 2015-04-02 20:22:53,50 2015-04-02 20:27:53,28 2015-04-02 20:32:53,21 2015-04-02 20:37:53,28 2015-04-02 20:42:53,20 2015-04-02 20:47:53,25 2015-04-02 20:52:53,28 2015-04-02 20:57:53,26 2015-04-02 21:02:53,28 2015-04-02 21:07:53,13 2015-04-02 21:12:53,15 2015-04-02 21:17:53,36 2015-04-02 21:22:53,29 2015-04-02 21:27:53,27 2015-04-02 21:32:53,21 2015-04-02 21:37:53,28 2015-04-02 21:42:53,16 2015-04-02 21:47:53,20 2015-04-02 21:52:53,16 2015-04-02 21:57:53,27 2015-04-02 22:02:53,19 2015-04-02 22:07:53,17 2015-04-02 22:12:53,12 2015-04-02 22:17:53,20 2015-04-02 22:22:53,16 2015-04-02 22:27:53,12 2015-04-02 22:32:53,20 2015-04-02 22:37:53,12 2015-04-02 22:42:53,14 2015-04-02 22:47:53,17 2015-04-02 22:52:53,14 2015-04-02 22:57:53,20 2015-04-02 23:02:53,13 2015-04-02 23:07:53,15 2015-04-02 23:12:53,21 2015-04-02 23:17:53,12 2015-04-02 23:22:53,21 2015-04-02 23:27:53,13 2015-04-02 23:32:53,14 2015-04-02 23:37:53,17 2015-04-02 23:42:53,15 2015-04-02 23:47:53,17 2015-04-02 23:52:53,18 2015-04-02 23:57:53,16 2015-04-03 00:02:53,18 2015-04-03 00:07:53,22 2015-04-03 00:12:53,13 2015-04-03 00:17:53,7 2015-04-03 00:22:53,11 2015-04-03 00:27:53,16 2015-04-03 00:32:53,23 2015-04-03 00:37:53,11 2015-04-03 00:42:53,13 2015-04-03 00:47:53,10 2015-04-03 00:52:53,15 2015-04-03 00:57:53,19 2015-04-03 01:02:53,9 2015-04-03 01:07:53,14 2015-04-03 01:12:53,15 2015-04-03 01:17:53,11 2015-04-03 01:22:53,12 2015-04-03 01:27:53,7 2015-04-03 01:32:53,7 2015-04-03 01:37:53,12 2015-04-03 01:42:53,13 2015-04-03 01:47:53,13 2015-04-03 01:52:53,15 2015-04-03 01:57:53,14 2015-04-03 02:02:53,21 2015-04-03 02:07:53,16 2015-04-03 02:12:53,36 2015-04-03 02:17:53,10 2015-04-03 02:22:53,3 2015-04-03 02:27:53,10 2015-04-03 02:32:53,9 2015-04-03 02:37:53,8 2015-04-03 02:42:53,9 2015-04-03 02:47:53,9 2015-04-03 02:52:53,14 2015-04-03 02:57:53,5 2015-04-03 03:02:53,6 2015-04-03 03:07:53,6 2015-04-03 03:12:53,14 2015-04-03 03:17:53,6 2015-04-03 03:22:53,11 2015-04-03 03:27:53,15 2015-04-03 03:32:53,10 2015-04-03 03:37:53,14 2015-04-03 03:42:53,13 2015-04-03 03:47:53,5 2015-04-03 03:52:53,11 2015-04-03 03:57:53,28 2015-04-03 04:02:53,11 2015-04-03 04:07:53,5 2015-04-03 04:12:53,14 2015-04-03 04:17:53,8 2015-04-03 04:22:53,11 2015-04-03 04:27:53,14 2015-04-03 04:32:53,7 2015-04-03 04:37:53,14 2015-04-03 04:42:53,5 2015-04-03 04:47:53,10 2015-04-03 04:52:53,11 2015-04-03 04:57:53,10 2015-04-03 05:02:53,4 2015-04-03 05:07:53,5 2015-04-03 05:12:53,4 2015-04-03 05:17:53,11 2015-04-03 05:22:53,8 2015-04-03 05:27:53,10 2015-04-03 05:32:53,6 2015-04-03 05:37:53,10 2015-04-03 05:42:53,18 2015-04-03 05:47:53,12 2015-04-03 05:52:53,8 2015-04-03 05:57:53,13 2015-04-03 06:02:53,8 2015-04-03 06:07:53,8 2015-04-03 06:12:53,7 2015-04-03 06:17:53,20 2015-04-03 06:22:53,9 2015-04-03 06:27:53,9 2015-04-03 06:32:53,13 2015-04-03 06:37:53,5 2015-04-03 06:42:53,12 2015-04-03 06:47:53,10 2015-04-03 06:52:53,13 2015-04-03 06:57:53,19 2015-04-03 07:02:53,2 2015-04-03 07:07:53,8 2015-04-03 07:12:53,4 2015-04-03 07:17:53,5 2015-04-03 07:22:53,14 2015-04-03 07:27:53,10 2015-04-03 07:32:53,7 2015-04-03 07:37:53,7 2015-04-03 07:42:53,7 2015-04-03 07:47:53,8 2015-04-03 07:52:53,8 2015-04-03 07:57:53,13 2015-04-03 08:02:53,17 2015-04-03 08:07:53,33 2015-04-03 08:12:53,8 2015-04-03 08:17:53,10 2015-04-03 08:22:53,7 2015-04-03 08:27:53,9 2015-04-03 08:32:53,14 2015-04-03 08:37:53,10 2015-04-03 08:42:53,4 2015-04-03 08:47:53,7 2015-04-03 08:52:53,5 2015-04-03 08:57:53,16 2015-04-03 09:02:53,12 2015-04-03 09:07:53,10 2015-04-03 09:12:53,8 2015-04-03 09:17:53,11 2015-04-03 09:22:53,8 2015-04-03 09:27:53,11 2015-04-03 09:32:53,10 2015-04-03 09:37:53,7 2015-04-03 09:42:53,5 2015-04-03 09:47:53,8 2015-04-03 09:52:53,10 2015-04-03 09:57:53,10 2015-04-03 10:02:53,12 2015-04-03 10:07:53,6 2015-04-03 10:12:53,6 2015-04-03 10:17:53,9 2015-04-03 10:22:53,16 2015-04-03 10:27:53,12 2015-04-03 10:32:53,7 2015-04-03 10:37:53,14 2015-04-03 10:42:53,8 2015-04-03 10:47:53,10 2015-04-03 10:52:53,8 2015-04-03 10:57:53,19 2015-04-03 11:02:53,16 2015-04-03 11:07:53,25 2015-04-03 11:12:53,14 2015-04-03 11:17:53,12 2015-04-03 11:22:53,17 2015-04-03 11:27:53,14 2015-04-03 11:32:53,8 2015-04-03 11:37:53,11 2015-04-03 11:42:53,15 2015-04-03 11:47:53,10 2015-04-03 11:52:53,3 2015-04-03 11:57:53,17 2015-04-03 12:02:53,15 2015-04-03 12:07:53,17 2015-04-03 12:12:53,11 2015-04-03 12:17:53,24 2015-04-03 12:22:53,14 2015-04-03 12:27:53,17 2015-04-03 12:32:53,24 2015-04-03 12:37:53,17 2015-04-03 12:42:53,9 2015-04-03 12:47:53,15 2015-04-03 12:52:53,9 2015-04-03 12:57:53,13 2015-04-03 13:02:53,17 2015-04-03 13:07:53,12 2015-04-03 13:12:53,13 2015-04-03 13:17:53,20 2015-04-03 13:22:53,15 2015-04-03 13:27:53,21 2015-04-03 13:32:53,30 2015-04-03 13:37:53,20 2015-04-03 13:42:53,20 2015-04-03 13:47:53,34 2015-04-03 13:52:53,18 2015-04-03 13:57:53,32 2015-04-03 14:02:53,13 2015-04-03 14:07:53,21 2015-04-03 14:12:53,19 2015-04-03 14:17:53,26 2015-04-03 14:22:53,19 2015-04-03 14:27:53,19 2015-04-03 14:32:53,9 2015-04-03 14:37:53,22 2015-04-03 14:42:53,24 2015-04-03 14:47:53,18 2015-04-03 14:52:53,24 2015-04-03 14:57:53,26 2015-04-03 15:02:53,27 2015-04-03 15:07:53,22 2015-04-03 15:12:53,21 2015-04-03 15:17:53,8 2015-04-03 15:22:53,11 2015-04-03 15:27:53,26 2015-04-03 15:32:53,11 2015-04-03 15:37:53,14 2015-04-03 15:42:53,23 2015-04-03 15:47:53,13 2015-04-03 15:52:53,22 2015-04-03 15:57:53,18 2015-04-03 16:02:53,18 2015-04-03 16:07:53,18 2015-04-03 16:12:53,15 2015-04-03 16:17:53,16 2015-04-03 16:22:53,10 2015-04-03 16:27:53,16 2015-04-03 16:32:53,12 2015-04-03 16:37:53,15 2015-04-03 16:42:53,17 2015-04-03 16:47:53,13 2015-04-03 16:52:53,14 2015-04-03 16:57:53,13 2015-04-03 17:02:53,21 2015-04-03 17:07:53,8 2015-04-03 17:12:53,10 2015-04-03 17:17:53,14 2015-04-03 17:22:53,21 2015-04-03 17:27:53,14 2015-04-03 17:32:53,16 2015-04-03 17:37:53,12 2015-04-03 17:42:53,13 2015-04-03 17:47:53,9 2015-04-03 17:52:53,33 2015-04-03 17:57:53,25 2015-04-03 18:02:53,15 2015-04-03 18:07:53,8 2015-04-03 18:12:53,39 2015-04-03 18:17:53,11 2015-04-03 18:22:53,23 2015-04-03 18:27:53,10 2015-04-03 18:32:53,13 2015-04-03 18:37:53,11 2015-04-03 18:42:53,16 2015-04-03 18:47:53,10 2015-04-03 18:52:53,15 2015-04-03 18:57:53,26 2015-04-03 19:02:53,12 2015-04-03 19:07:53,9 2015-04-03 19:12:53,18 2015-04-03 19:17:53,22 2015-04-03 19:22:53,23 2015-04-03 19:27:53,14 2015-04-03 19:32:53,14 2015-04-03 19:37:53,10 2015-04-03 19:42:53,15 2015-04-03 19:47:53,19 2015-04-03 19:52:53,17 2015-04-03 19:57:53,16 2015-04-03 20:02:53,19 2015-04-03 20:07:53,10 2015-04-03 20:12:53,23 2015-04-03 20:17:53,24 2015-04-03 20:22:53,21 2015-04-03 20:27:53,13 2015-04-03 20:32:53,20 2015-04-03 20:37:53,18 2015-04-03 20:42:53,23 2015-04-03 20:47:53,17 2015-04-03 20:52:53,15 2015-04-03 20:57:53,20 2015-04-03 21:02:53,14 2015-04-03 21:07:53,14 2015-04-03 21:12:53,17 2015-04-03 21:17:53,19 2015-04-03 21:22:53,20 2015-04-03 21:27:53,20 2015-04-03 21:32:53,10 2015-04-03 21:37:53,5 2015-04-03 21:42:53,13 2015-04-03 21:47:53,16 2015-04-03 21:52:53,13 2015-04-03 21:57:53,26 2015-04-03 22:02:53,9 2015-04-03 22:07:53,11 2015-04-03 22:12:53,12 2015-04-03 22:17:53,17 2015-04-03 22:22:53,5 2015-04-03 22:27:53,8 2015-04-03 22:32:53,20 2015-04-03 22:37:53,18 2015-04-03 22:42:53,25 2015-04-03 22:47:53,12 2015-04-03 22:52:53,8 2015-04-03 22:57:53,16 2015-04-03 23:02:53,12 2015-04-03 23:07:53,9 2015-04-03 23:12:53,3 2015-04-03 23:17:53,9 2015-04-03 23:22:53,13 2015-04-03 23:27:53,14 2015-04-03 23:32:53,9 2015-04-03 23:37:53,14 2015-04-03 23:42:53,14 2015-04-03 23:47:53,9 2015-04-03 23:52:53,12 2015-04-03 23:57:53,22 2015-04-04 00:02:53,7 2015-04-04 00:07:53,16 2015-04-04 00:12:53,16 2015-04-04 00:17:53,4 2015-04-04 00:22:53,9 2015-04-04 00:27:53,6 2015-04-04 00:32:53,10 2015-04-04 00:37:53,4 2015-04-04 00:42:53,5 2015-04-04 00:47:53,13 2015-04-04 00:52:53,4 2015-04-04 00:57:53,7 2015-04-04 01:02:53,3 2015-04-04 01:07:53,10 2015-04-04 01:12:53,8 2015-04-04 01:17:53,11 2015-04-04 01:22:53,9 2015-04-04 01:27:53,17 2015-04-04 01:32:53,15 2015-04-04 01:37:53,14 2015-04-04 01:42:53,16 2015-04-04 01:47:53,13 2015-04-04 01:52:53,5 2015-04-04 01:57:53,13 2015-04-04 02:02:53,7 2015-04-04 02:07:53,13 2015-04-04 02:12:53,5 2015-04-04 02:17:53,12 2015-04-04 02:22:53,2 2015-04-04 02:27:53,6 2015-04-04 02:32:53,2 2015-04-04 02:37:53,4 2015-04-04 02:42:53,8 2015-04-04 02:47:53,17 2015-04-04 02:52:53,12 2015-04-04 02:57:53,23 2015-04-04 03:02:53,8 2015-04-04 03:07:53,2 2015-04-04 03:12:53,9 2015-04-04 03:17:53,12 2015-04-04 03:22:53,16 2015-04-04 03:27:53,23 2015-04-04 03:32:53,12 2015-04-04 03:37:53,8 2015-04-04 03:42:53,11 2015-04-04 03:47:53,6 2015-04-04 03:52:53,10 2015-04-04 03:57:53,10 2015-04-04 04:02:53,12 2015-04-04 04:07:53,10 2015-04-04 04:12:53,5 2015-04-04 04:17:53,8 2015-04-04 04:22:53,8 2015-04-04 04:27:53,10 2015-04-04 04:32:53,6 2015-04-04 04:37:53,4 2015-04-04 04:42:53,2 2015-04-04 04:47:53,6 2015-04-04 04:52:53,4 2015-04-04 04:57:53,6 2015-04-04 05:02:53,9 2015-04-04 05:07:53,5 2015-04-04 05:12:53,12 2015-04-04 05:17:53,13 2015-04-04 05:22:53,5 2015-04-04 05:27:53,3 2015-04-04 05:32:53,12 2015-04-04 05:37:53,4 2015-04-04 05:42:53,3 2015-04-04 05:47:53,10 2015-04-04 05:52:53,5 2015-04-04 05:57:53,10 2015-04-04 06:02:53,6 2015-04-04 06:07:53,6 2015-04-04 06:12:53,2 2015-04-04 06:17:53,10 2015-04-04 06:22:53,7 2015-04-04 06:27:53,1 2015-04-04 06:32:53,4 2015-04-04 06:37:53,17 2015-04-04 06:42:53,7 2015-04-04 06:47:53,5 2015-04-04 06:52:53,10 2015-04-04 06:57:53,10 2015-04-04 07:02:53,26 2015-04-04 07:07:53,16 2015-04-04 07:12:53,7 2015-04-04 07:17:53,13 2015-04-04 07:22:53,12 2015-04-04 07:27:53,16 2015-04-04 07:32:53,9 2015-04-04 07:37:53,8 2015-04-04 07:42:53,8 2015-04-04 07:47:53,17 2015-04-04 07:52:53,15 2015-04-04 07:57:53,11 2015-04-04 08:02:53,12 2015-04-04 08:07:53,9 2015-04-04 08:12:53,10 2015-04-04 08:17:53,9 2015-04-04 08:22:53,8 2015-04-04 08:27:53,18 2015-04-04 08:32:53,12 2015-04-04 08:37:53,12 2015-04-04 08:42:53,8 2015-04-04 08:47:53,15 2015-04-04 08:52:53,6 2015-04-04 08:57:53,17 2015-04-04 09:02:53,12 2015-04-04 09:07:53,8 2015-04-04 09:12:53,11 2015-04-04 09:17:53,12 2015-04-04 09:22:53,13 2015-04-04 09:27:53,14 2015-04-04 09:32:53,12 2015-04-04 09:37:53,9 2015-04-04 09:42:53,11 2015-04-04 09:47:53,6 2015-04-04 09:52:53,8 2015-04-04 09:57:53,7 2015-04-04 10:02:53,7 2015-04-04 10:07:53,1 2015-04-04 10:12:53,4 2015-04-04 10:17:53,12 2015-04-04 10:22:53,15 2015-04-04 10:27:53,8 2015-04-04 10:32:53,17 2015-04-04 10:37:53,5 2015-04-04 10:42:53,8 2015-04-04 10:47:53,12 2015-04-04 10:52:53,11 2015-04-04 10:57:53,7 2015-04-04 11:02:53,7 2015-04-04 11:07:53,6 2015-04-04 11:12:53,7 2015-04-04 11:17:53,9 2015-04-04 11:22:53,6 2015-04-04 11:27:53,9 2015-04-04 11:32:53,8 2015-04-04 11:37:53,9 2015-04-04 11:42:53,7 2015-04-04 11:47:53,1 2015-04-04 11:52:53,16 2015-04-04 11:57:53,9 2015-04-04 12:02:53,11 2015-04-04 12:07:53,14 2015-04-04 12:12:53,3 2015-04-04 12:17:53,6 2015-04-04 12:22:53,6 2015-04-04 12:27:53,4 2015-04-04 12:32:53,6 2015-04-04 12:37:53,9 2015-04-04 12:42:53,8 2015-04-04 12:47:53,17 2015-04-04 12:52:53,12 2015-04-04 12:57:53,12 2015-04-04 13:02:53,10 2015-04-04 13:07:53,8 2015-04-04 13:12:53,4 2015-04-04 13:17:53,11 2015-04-04 13:22:53,14 2015-04-04 13:27:53,5 2015-04-04 13:32:53,5 2015-04-04 13:37:53,8 2015-04-04 13:42:53,9 2015-04-04 13:47:53,11 2015-04-04 13:52:53,17 2015-04-04 13:57:53,14 2015-04-04 14:02:53,25 2015-04-04 14:07:53,13 2015-04-04 14:12:53,7 2015-04-04 14:17:53,11 2015-04-04 14:22:53,17 2015-04-04 14:27:53,14 2015-04-04 14:32:53,5 2015-04-04 14:37:53,16 2015-04-04 14:42:53,11 2015-04-04 14:47:53,8 2015-04-04 14:52:53,17 2015-04-04 14:57:53,11 2015-04-04 15:02:53,22 2015-04-04 15:07:53,26 2015-04-04 15:12:53,8 2015-04-04 15:17:53,18 2015-04-04 15:22:53,14 2015-04-04 15:27:53,5 2015-04-04 15:32:53,15 2015-04-04 15:37:53,8 2015-04-04 15:42:53,10 2015-04-04 15:47:53,25 2015-04-04 15:52:53,28 2015-04-04 15:57:53,12 2015-04-04 16:02:53,9 2015-04-04 16:07:53,15 2015-04-04 16:12:53,19 2015-04-04 16:17:53,12 2015-04-04 16:22:53,14 2015-04-04 16:27:53,12 2015-04-04 16:32:53,12 2015-04-04 16:37:53,11 2015-04-04 16:42:53,17 2015-04-04 16:47:53,18 2015-04-04 16:52:53,17 2015-04-04 16:57:53,27 2015-04-04 17:02:53,20 2015-04-04 17:07:53,18 2015-04-04 17:12:53,10 2015-04-04 17:17:53,14 2015-04-04 17:22:53,18 2015-04-04 17:27:53,10 2015-04-04 17:32:53,6 2015-04-04 17:37:53,11 2015-04-04 17:42:53,8 2015-04-04 17:47:53,8 2015-04-04 17:52:53,17 2015-04-04 17:57:53,23 2015-04-04 18:02:53,41 2015-04-04 18:07:53,25 2015-04-04 18:12:53,19 2015-04-04 18:17:53,23 2015-04-04 18:22:53,18 2015-04-04 18:27:53,27 2015-04-04 18:32:53,13 2015-04-04 18:37:53,17 2015-04-04 18:42:53,8 2015-04-04 18:47:53,13 2015-04-04 18:52:53,26 2015-04-04 18:57:53,18 2015-04-04 19:02:53,13 2015-04-04 19:07:53,11 2015-04-04 19:12:53,15 2015-04-04 19:17:53,14 2015-04-04 19:22:53,8 2015-04-04 19:27:53,13 2015-04-04 19:32:53,4 2015-04-04 19:37:53,6 2015-04-04 19:42:53,20 2015-04-04 19:47:53,8 2015-04-04 19:52:53,5 2015-04-04 19:57:53,6 2015-04-04 20:02:53,6 2015-04-04 20:07:53,8 2015-04-04 20:12:53,11 2015-04-04 20:17:53,28 2015-04-04 20:22:53,11 2015-04-04 20:27:53,16 2015-04-04 20:32:53,23 2015-04-04 20:37:53,14 2015-04-04 20:42:53,6 2015-04-04 20:47:53,6 2015-04-04 20:52:53,6 2015-04-04 20:57:53,9 2015-04-04 21:02:53,7 2015-04-04 21:07:53,7 2015-04-04 21:12:53,7 2015-04-04 21:17:53,9 2015-04-04 21:22:53,6 2015-04-04 21:27:53,8 2015-04-04 21:32:53,4 2015-04-04 21:37:53,6 2015-04-04 21:42:53,7 2015-04-04 21:47:53,16 2015-04-04 21:52:53,8 2015-04-04 21:57:53,7 2015-04-04 22:02:53,6 2015-04-04 22:07:53,9 2015-04-04 22:12:53,4 2015-04-04 22:17:53,5 2015-04-04 22:22:53,12 2015-04-04 22:27:53,6 2015-04-04 22:32:53,12 2015-04-04 22:37:53,16 2015-04-04 22:42:53,18 2015-04-04 22:47:53,12 2015-04-04 22:52:53,15 2015-04-04 22:57:53,15 2015-04-04 23:02:53,12 2015-04-04 23:07:53,14 2015-04-04 23:12:53,13 2015-04-04 23:17:53,6 2015-04-04 23:22:53,6 2015-04-04 23:27:53,10 2015-04-04 23:32:53,8 2015-04-04 23:37:53,8 2015-04-04 23:42:53,6 2015-04-04 23:47:53,8 2015-04-04 23:52:53,5 2015-04-04 23:57:53,10 2015-04-05 00:02:53,10 2015-04-05 00:07:53,2 2015-04-05 00:12:53,10 2015-04-05 00:17:53,9 2015-04-05 00:22:53,11 2015-04-05 00:27:53,5 2015-04-05 00:32:53,23 2015-04-05 00:37:53,20 2015-04-05 00:42:53,9 2015-04-05 00:47:53,15 2015-04-05 00:52:53,14 2015-04-05 00:57:53,23 2015-04-05 01:02:53,16 2015-04-05 01:07:53,6 2015-04-05 01:12:53,13 2015-04-05 01:17:53,10 2015-04-05 01:22:53,11 2015-04-05 01:27:53,15 2015-04-05 01:32:53,13 2015-04-05 01:37:53,18 2015-04-05 01:42:53,6 2015-04-05 01:47:53,9 2015-04-05 01:52:53,10 2015-04-05 01:57:53,8 2015-04-05 02:02:53,3 2015-04-05 02:07:53,5 2015-04-05 02:12:53,6 2015-04-05 02:17:53,6 2015-04-05 02:22:53,5 2015-04-05 02:27:53,6 2015-04-05 02:32:53,4 2015-04-05 02:37:53,8 2015-04-05 02:42:53,63 2015-04-05 02:47:53,96 2015-04-05 02:52:53,64 2015-04-05 02:57:53,34 2015-04-05 03:02:53,39 2015-04-05 03:07:53,39 2015-04-05 03:12:53,40 2015-04-05 03:17:53,16 2015-04-05 03:22:53,18 2015-04-05 03:27:53,23 2015-04-05 03:32:53,24 2015-04-05 03:37:53,21 2015-04-05 03:42:53,17 2015-04-05 03:47:53,26 2015-04-05 03:52:53,7 2015-04-05 03:57:53,16 2015-04-05 04:02:53,7 2015-04-05 04:07:53,9 2015-04-05 04:12:53,12 2015-04-05 04:17:53,7 2015-04-05 04:22:53,14 2015-04-05 04:27:53,18 2015-04-05 04:32:53,14 2015-04-05 04:37:53,35 2015-04-05 04:42:53,37 2015-04-05 04:47:53,19 2015-04-05 04:52:53,21 2015-04-05 04:57:53,27 2015-04-05 05:02:53,10 2015-04-05 05:07:53,10 2015-04-05 05:12:53,20 2015-04-05 05:17:53,11 2015-04-05 05:22:53,9 2015-04-05 05:27:53,11 2015-04-05 05:32:53,17 2015-04-05 05:37:53,13 2015-04-05 05:42:53,13 2015-04-05 05:47:53,11 2015-04-05 05:52:53,7 2015-04-05 05:57:53,22 2015-04-05 06:02:53,13 2015-04-05 06:07:53,11 2015-04-05 06:12:53,12 2015-04-05 06:17:53,9 2015-04-05 06:22:53,5 2015-04-05 06:27:53,14 2015-04-05 06:32:53,9 2015-04-05 06:37:53,12 2015-04-05 06:42:53,8 2015-04-05 06:47:53,12 2015-04-05 06:52:53,5 2015-04-05 06:57:53,15 2015-04-05 07:02:53,15 2015-04-05 07:07:53,15 2015-04-05 07:12:53,22 2015-04-05 07:17:53,13 2015-04-05 07:22:53,10 2015-04-05 07:27:53,23 2015-04-05 07:32:53,11 2015-04-05 07:37:53,31 2015-04-05 07:42:53,18 2015-04-05 07:47:53,12 2015-04-05 07:52:53,10 2015-04-05 07:57:53,4 2015-04-05 08:02:53,12 2015-04-05 08:07:53,7 2015-04-05 08:12:53,11 2015-04-05 08:17:53,11 2015-04-05 08:22:53,15 2015-04-05 08:27:53,5 2015-04-05 08:32:53,8 2015-04-05 08:37:53,2 2015-04-05 08:42:53,4 2015-04-05 08:47:53,14 2015-04-05 08:52:53,14 2015-04-05 08:57:53,7 2015-04-05 09:02:53,14 2015-04-05 09:07:53,15 2015-04-05 09:12:53,12 2015-04-05 09:17:53,10 2015-04-05 09:22:53,8 2015-04-05 09:27:53,13 2015-04-05 09:32:53,16 2015-04-05 09:37:53,12 2015-04-05 09:42:53,11 2015-04-05 09:47:53,12 2015-04-05 09:52:53,8 2015-04-05 09:57:53,7 2015-04-05 10:02:53,49 2015-04-05 10:07:53,12 2015-04-05 10:12:53,6 2015-04-05 10:17:53,18 2015-04-05 10:22:53,9 2015-04-05 10:27:53,8 2015-04-05 10:32:53,13 2015-04-05 10:37:53,3 2015-04-05 10:42:53,10 2015-04-05 10:47:53,6 2015-04-05 10:52:53,17 2015-04-05 10:57:53,21 2015-04-05 11:02:53,6 2015-04-05 11:07:53,12 2015-04-05 11:12:53,13 2015-04-05 11:17:53,7 2015-04-05 11:22:53,7 2015-04-05 11:27:53,10 2015-04-05 11:32:53,10 2015-04-05 11:37:53,7 2015-04-05 11:42:53,13 2015-04-05 11:47:53,8 2015-04-05 11:52:53,13 2015-04-05 11:57:53,12 2015-04-05 12:02:53,10 2015-04-05 12:07:53,16 2015-04-05 12:12:53,30 2015-04-05 12:17:53,14 2015-04-05 12:22:53,14 2015-04-05 12:27:53,15 2015-04-05 12:32:53,21 2015-04-05 12:37:53,36 2015-04-05 12:42:53,36 2015-04-05 12:47:53,36 2015-04-05 12:52:53,14 2015-04-05 12:57:53,38 2015-04-05 13:02:53,38 2015-04-05 13:07:53,17 2015-04-05 13:12:53,18 2015-04-05 13:17:53,22 2015-04-05 13:22:53,16 2015-04-05 13:27:53,30 2015-04-05 13:32:53,25 2015-04-05 13:37:53,29 2015-04-05 13:42:53,17 2015-04-05 13:47:53,11 2015-04-05 13:52:53,10 2015-04-05 13:57:53,16 2015-04-05 14:02:53,28 2015-04-05 14:07:53,26 2015-04-05 14:12:53,48 2015-04-05 14:17:53,18 2015-04-05 14:22:53,19 2015-04-05 14:27:53,18 2015-04-05 14:32:53,18 2015-04-05 14:37:53,16 2015-04-05 14:42:53,22 2015-04-05 14:47:53,18 2015-04-05 14:52:53,23 2015-04-05 14:57:53,19 2015-04-05 15:02:53,27 2015-04-05 15:07:53,33 2015-04-05 15:12:53,19 2015-04-05 15:17:53,15 2015-04-05 15:22:53,13 2015-04-05 15:27:53,21 2015-04-05 15:32:53,10 2015-04-05 15:37:53,20 2015-04-05 15:42:53,15 2015-04-05 15:47:53,113 2015-04-05 15:52:53,201 2015-04-05 15:57:53,161 2015-04-05 16:02:53,15 2015-04-05 16:07:53,16 2015-04-05 16:12:53,22 2015-04-05 16:17:53,19 2015-04-05 16:22:53,22 2015-04-05 16:27:53,83 2015-04-05 16:32:53,89 2015-04-05 16:37:53,12 2015-04-05 16:42:53,13 2015-04-05 16:47:53,10 2015-04-05 16:52:53,12 2015-04-05 16:57:53,13 2015-04-05 17:02:53,18 2015-04-05 17:07:53,14 2015-04-05 17:12:53,9 2015-04-05 17:17:53,16 2015-04-05 17:22:53,11 2015-04-05 17:27:53,3 2015-04-05 17:32:53,23 2015-04-05 17:37:53,54 2015-04-05 17:42:53,28 2015-04-05 17:47:53,6 2015-04-05 17:52:53,7 2015-04-05 17:57:53,18 2015-04-05 18:02:53,13 2015-04-05 18:07:53,6 2015-04-05 18:12:53,12 2015-04-05 18:17:53,10 2015-04-05 18:22:53,10 2015-04-05 18:27:53,13 2015-04-05 18:32:53,24 2015-04-05 18:37:53,11 2015-04-05 18:42:53,10 2015-04-05 18:47:53,13 2015-04-05 18:52:53,12 2015-04-05 18:57:53,22 2015-04-05 19:02:53,21 2015-04-05 19:07:53,12 2015-04-05 19:12:53,14 2015-04-05 19:17:53,10 2015-04-05 19:22:53,12 2015-04-05 19:27:53,8 2015-04-05 19:32:53,17 2015-04-05 19:37:53,14 2015-04-05 19:42:53,17 2015-04-05 19:47:53,13 2015-04-05 19:52:53,11 2015-04-05 19:57:53,23 2015-04-05 20:02:53,14 2015-04-05 20:07:53,13 2015-04-05 20:12:53,15 2015-04-05 20:17:53,9 2015-04-05 20:22:53,12 2015-04-05 20:27:53,11 2015-04-05 20:32:53,6 2015-04-05 20:37:53,14 2015-04-05 20:42:53,19 2015-04-05 20:47:53,7 2015-04-05 20:52:53,19 2015-04-05 20:57:53,19 2015-04-05 21:02:53,31 2015-04-05 21:07:53,15 2015-04-05 21:12:53,12 2015-04-05 21:17:53,15 2015-04-05 21:22:53,9 2015-04-05 21:27:53,8 2015-04-05 21:32:53,12 2015-04-05 21:37:53,7 2015-04-05 21:42:53,6 2015-04-05 21:47:53,14 2015-04-05 21:52:53,10 2015-04-05 21:57:53,9 2015-04-05 22:02:53,15 2015-04-05 22:07:53,6 2015-04-05 22:12:53,13 2015-04-05 22:17:53,4 2015-04-05 22:22:53,10 2015-04-05 22:27:53,12 2015-04-05 22:32:53,22 2015-04-05 22:37:53,13 2015-04-05 22:42:53,11 2015-04-05 22:47:53,14 2015-04-05 22:52:53,12 2015-04-05 22:57:53,23 2015-04-05 23:02:53,19 2015-04-05 23:07:53,12 2015-04-05 23:12:53,16 2015-04-05 23:17:53,16 2015-04-05 23:22:53,9 2015-04-05 23:27:53,14 2015-04-05 23:32:53,9 2015-04-05 23:37:53,10 2015-04-05 23:42:53,9 2015-04-05 23:47:53,16 2015-04-05 23:52:53,18 2015-04-05 23:57:53,18 2015-04-06 00:02:53,9 2015-04-06 00:07:53,7 2015-04-06 00:12:53,9 2015-04-06 00:17:53,12 2015-04-06 00:22:53,13 2015-04-06 00:27:53,14 2015-04-06 00:32:53,12 2015-04-06 00:37:53,8 2015-04-06 00:42:53,44 2015-04-06 00:47:53,24 2015-04-06 00:52:53,28 2015-04-06 00:57:53,19 2015-04-06 01:02:53,17 2015-04-06 01:07:53,16 2015-04-06 01:12:53,13 2015-04-06 01:17:53,9 2015-04-06 01:22:53,12 2015-04-06 01:27:53,14 2015-04-06 01:32:53,9 2015-04-06 01:37:53,8 2015-04-06 01:42:53,9 2015-04-06 01:47:53,12 2015-04-06 01:52:53,23 2015-04-06 01:57:53,16 2015-04-06 02:02:53,6 2015-04-06 02:07:53,20 2015-04-06 02:12:53,12 2015-04-06 02:17:53,6 2015-04-06 02:22:53,7 2015-04-06 02:27:53,13 2015-04-06 02:32:53,6 2015-04-06 02:37:53,12 2015-04-06 02:42:53,9 2015-04-06 02:47:53,5 2015-04-06 02:52:53,10 2015-04-06 02:57:53,11 2015-04-06 03:02:53,10 2015-04-06 03:07:53,9 2015-04-06 03:12:53,12 2015-04-06 03:17:53,11 2015-04-06 03:22:53,12 2015-04-06 03:27:53,14 2015-04-06 03:32:53,9 2015-04-06 03:37:53,9 2015-04-06 03:42:53,10 2015-04-06 03:47:53,11 2015-04-06 03:52:53,5 2015-04-06 03:57:53,7 2015-04-06 04:02:53,11 2015-04-06 04:07:53,14 2015-04-06 04:12:53,13 2015-04-06 04:17:53,7 2015-04-06 04:22:53,9 2015-04-06 04:27:53,4 2015-04-06 04:32:53,5 2015-04-06 04:37:53,5 2015-04-06 04:42:53,8 2015-04-06 04:47:53,6 2015-04-06 04:52:53,6 2015-04-06 04:57:53,9 2015-04-06 05:02:53,4 2015-04-06 05:07:53,5 2015-04-06 05:12:53,5 2015-04-06 05:17:53,7 2015-04-06 05:22:53,4 2015-04-06 05:27:53,12 2015-04-06 05:32:53,4 2015-04-06 05:37:53,7 2015-04-06 05:42:53,7 2015-04-06 05:47:53,4 2015-04-06 05:52:53,14 2015-04-06 05:57:53,5 2015-04-06 06:02:53,9 2015-04-06 06:07:53,7 2015-04-06 06:12:53,9 2015-04-06 06:17:53,7 2015-04-06 06:22:53,6 2015-04-06 06:27:53,11 2015-04-06 06:32:53,13 2015-04-06 06:37:53,2 2015-04-06 06:42:53,3 2015-04-06 06:47:53,9 2015-04-06 06:52:53,9 2015-04-06 06:57:53,6 2015-04-06 07:02:53,14 2015-04-06 07:07:53,14 2015-04-06 07:12:53,10 2015-04-06 07:17:53,9 2015-04-06 07:22:53,7 2015-04-06 07:27:53,12 2015-04-06 07:32:53,12 2015-04-06 07:37:53,9 2015-04-06 07:42:53,11 2015-04-06 07:47:53,11 2015-04-06 07:52:53,6 2015-04-06 07:57:53,15 2015-04-06 08:02:53,14 2015-04-06 08:07:53,10 2015-04-06 08:12:53,6 2015-04-06 08:17:53,12 2015-04-06 08:22:53,9 2015-04-06 08:27:53,22 2015-04-06 08:32:53,23 2015-04-06 08:37:53,14 2015-04-06 08:42:53,15 2015-04-06 08:47:53,3 2015-04-06 08:52:53,8 2015-04-06 08:57:53,12 2015-04-06 09:02:53,11 2015-04-06 09:07:53,6 2015-04-06 09:12:53,8 2015-04-06 09:17:53,10 2015-04-06 09:22:53,10 2015-04-06 09:27:53,6 2015-04-06 09:32:53,14 2015-04-06 09:37:53,7 2015-04-06 09:42:53,7 2015-04-06 09:47:53,9 2015-04-06 09:52:53,3 2015-04-06 09:57:53,9 2015-04-06 10:02:53,5 2015-04-06 10:07:53,7 2015-04-06 10:12:53,5 2015-04-06 10:17:53,5 2015-04-06 10:22:53,8 2015-04-06 10:27:53,17 2015-04-06 10:32:53,10 2015-04-06 10:37:53,8 2015-04-06 10:42:53,11 2015-04-06 10:47:53,3 2015-04-06 10:52:53,12 2015-04-06 10:57:53,6 2015-04-06 11:02:53,7 2015-04-06 11:07:53,19 2015-04-06 11:12:53,9 2015-04-06 11:17:53,11 2015-04-06 11:22:53,10 2015-04-06 11:27:53,12 2015-04-06 11:32:53,21 2015-04-06 11:37:53,26 2015-04-06 11:42:53,28 2015-04-06 11:47:53,16 2015-04-06 11:52:53,6 2015-04-06 11:57:53,9 2015-04-06 12:02:53,10 2015-04-06 12:07:53,12 2015-04-06 12:12:53,13 2015-04-06 12:17:53,16 2015-04-06 12:22:53,27 2015-04-06 12:27:53,29 2015-04-06 12:32:53,21 2015-04-06 12:37:53,14 2015-04-06 12:42:53,19 2015-04-06 12:47:53,12 2015-04-06 12:52:53,16 2015-04-06 12:57:53,19 2015-04-06 13:02:53,10 2015-04-06 13:07:53,14 2015-04-06 13:12:53,19 2015-04-06 13:17:53,15 2015-04-06 13:22:53,22 2015-04-06 13:27:53,16 2015-04-06 13:32:53,23 2015-04-06 13:37:53,17 2015-04-06 13:42:53,26 2015-04-06 13:47:53,33 2015-04-06 13:52:53,23 2015-04-06 13:57:53,30 2015-04-06 14:02:53,16 2015-04-06 14:07:53,20 2015-04-06 14:12:53,19 2015-04-06 14:17:53,17 2015-04-06 14:22:53,19 2015-04-06 14:27:53,16 2015-04-06 14:32:53,20 2015-04-06 14:37:53,17 2015-04-06 14:42:53,28 2015-04-06 14:47:53,30 2015-04-06 14:52:53,47 2015-04-06 14:57:53,40 2015-04-06 15:02:53,15 2015-04-06 15:07:53,29 2015-04-06 15:12:53,22 2015-04-06 15:17:53,27 2015-04-06 15:22:53,17 2015-04-06 15:27:53,14 2015-04-06 15:32:53,14 2015-04-06 15:37:53,31 2015-04-06 15:42:53,44 2015-04-06 15:47:53,26 2015-04-06 15:52:53,43 2015-04-06 15:57:53,23 2015-04-06 16:02:53,32 2015-04-06 16:07:53,25 2015-04-06 16:12:53,13 2015-04-06 16:17:53,13 2015-04-06 16:22:53,14 2015-04-06 16:27:53,19 2015-04-06 16:32:53,30 2015-04-06 16:37:53,27 2015-04-06 16:42:53,32 2015-04-06 16:47:53,14 2015-04-06 16:52:53,23 2015-04-06 16:57:53,29 2015-04-06 17:02:53,28 2015-04-06 17:07:53,23 2015-04-06 17:12:53,23 2015-04-06 17:17:53,16 2015-04-06 17:22:53,17 2015-04-06 17:27:53,34 2015-04-06 17:32:53,23 2015-04-06 17:37:53,15 2015-04-06 17:42:53,19 2015-04-06 17:47:53,28 2015-04-06 17:52:53,28 2015-04-06 17:57:53,20 2015-04-06 18:02:53,15 2015-04-06 18:07:53,26 2015-04-06 18:12:53,31 2015-04-06 18:17:53,56 2015-04-06 18:22:53,48 2015-04-06 18:27:53,44 2015-04-06 18:32:53,28 2015-04-06 18:37:53,18 2015-04-06 18:42:53,111 2015-04-06 18:47:53,120 2015-04-06 18:52:53,22 2015-04-06 18:57:53,27 2015-04-06 19:02:53,44 2015-04-06 19:07:53,28 2015-04-06 19:12:53,54 2015-04-06 19:17:53,70 2015-04-06 19:22:53,28 2015-04-06 19:27:53,31 2015-04-06 19:32:53,24 2015-04-06 19:37:53,23 2015-04-06 19:42:53,27 2015-04-06 19:47:53,37 2015-04-06 19:52:53,35 2015-04-06 19:57:53,38 2015-04-06 20:02:53,42 2015-04-06 20:07:53,42 2015-04-06 20:12:53,54 2015-04-06 20:17:53,49 2015-04-06 20:22:53,41 2015-04-06 20:27:53,53 2015-04-06 20:32:53,73 2015-04-06 20:37:53,52 2015-04-06 20:42:53,105 2015-04-06 20:47:53,52 2015-04-06 20:52:53,50 2015-04-06 20:57:53,21 2015-04-06 21:02:53,43 2015-04-06 21:07:53,25 2015-04-06 21:12:53,22 2015-04-06 21:17:53,35 2015-04-06 21:22:53,39 2015-04-06 21:27:53,43 2015-04-06 21:32:53,35 2015-04-06 21:37:53,27 2015-04-06 21:42:53,22 2015-04-06 21:47:53,18 2015-04-06 21:52:53,25 2015-04-06 21:57:53,41 2015-04-06 22:02:53,69 2015-04-06 22:07:53,51 2015-04-06 22:12:53,47 2015-04-06 22:17:53,77 2015-04-06 22:22:53,53 2015-04-06 22:27:53,61 2015-04-06 22:32:53,55 2015-04-06 22:37:53,53 2015-04-06 22:42:53,43 2015-04-06 22:47:53,56 2015-04-06 22:52:53,39 2015-04-06 22:57:53,46 2015-04-06 23:02:53,27 2015-04-06 23:07:53,25 2015-04-06 23:12:53,22 2015-04-06 23:17:53,21 2015-04-06 23:22:53,43 2015-04-06 23:27:53,26 2015-04-06 23:32:53,16 2015-04-06 23:37:53,26 2015-04-06 23:42:53,17 2015-04-06 23:47:53,15 2015-04-06 23:52:53,16 2015-04-06 23:57:53,20 2015-04-07 00:02:53,24 2015-04-07 00:07:53,13 2015-04-07 00:12:53,28 2015-04-07 00:17:53,26 2015-04-07 00:22:53,23 2015-04-07 00:27:53,12 2015-04-07 00:32:53,30 2015-04-07 00:37:53,29 2015-04-07 00:42:53,19 2015-04-07 00:47:53,9 2015-04-07 00:52:53,7 2015-04-07 00:57:53,18 2015-04-07 01:02:53,10 2015-04-07 01:07:53,21 2015-04-07 01:12:53,65 2015-04-07 01:17:53,48 2015-04-07 01:22:53,24 2015-04-07 01:27:53,15 2015-04-07 01:32:53,22 2015-04-07 01:37:53,22 2015-04-07 01:42:53,13 2015-04-07 01:47:53,20 2015-04-07 01:52:53,9 2015-04-07 01:57:53,9 2015-04-07 02:02:53,5 2015-04-07 02:07:53,6 2015-04-07 02:12:53,7 2015-04-07 02:17:53,14 2015-04-07 02:22:53,16 2015-04-07 02:27:53,23 2015-04-07 02:32:53,10 2015-04-07 02:37:53,17 2015-04-07 02:42:53,9 2015-04-07 02:47:53,8 2015-04-07 02:52:53,10 2015-04-07 02:57:53,20 2015-04-07 03:02:53,16 2015-04-07 03:07:53,12 2015-04-07 03:12:53,16 2015-04-07 03:17:53,14 2015-04-07 03:22:53,10 2015-04-07 03:27:53,21 2015-04-07 03:32:53,8 2015-04-07 03:37:53,24 2015-04-07 03:42:53,14 2015-04-07 03:47:53,25 2015-04-07 03:52:53,70 2015-04-07 03:57:53,39 2015-04-07 04:02:53,33 2015-04-07 04:07:53,19 2015-04-07 04:12:53,13 2015-04-07 04:17:53,19 2015-04-07 04:22:53,12 2015-04-07 04:27:53,13 2015-04-07 04:32:53,12 2015-04-07 04:37:53,15 2015-04-07 04:42:53,17 2015-04-07 04:47:53,23 2015-04-07 04:52:53,9 2015-04-07 04:57:53,33 2015-04-07 05:02:53,19 2015-04-07 05:07:53,18 2015-04-07 05:12:53,15 2015-04-07 05:17:53,18 2015-04-07 05:22:53,15 2015-04-07 05:27:53,7 2015-04-07 05:32:53,17 2015-04-07 05:37:53,8 2015-04-07 05:42:53,8 2015-04-07 05:47:53,15 2015-04-07 05:52:53,15 2015-04-07 05:57:53,19 2015-04-07 06:02:53,12 2015-04-07 06:07:53,12 2015-04-07 06:12:53,23 2015-04-07 06:17:53,9 2015-04-07 06:22:53,14 2015-04-07 06:27:53,10 2015-04-07 06:32:53,14 2015-04-07 06:37:53,13 2015-04-07 06:42:53,13 2015-04-07 06:47:53,8 2015-04-07 06:52:53,10 2015-04-07 06:57:53,13 2015-04-07 07:02:53,15 2015-04-07 07:07:53,11 2015-04-07 07:12:53,10 2015-04-07 07:17:53,17 2015-04-07 07:22:53,22 2015-04-07 07:27:53,11 2015-04-07 07:32:53,17 2015-04-07 07:37:53,7 2015-04-07 07:42:53,10 2015-04-07 07:47:53,22 2015-04-07 07:52:53,9 2015-04-07 07:57:53,19 2015-04-07 08:02:53,9 2015-04-07 08:07:53,27 2015-04-07 08:12:53,26 2015-04-07 08:17:53,35 2015-04-07 08:22:53,21 2015-04-07 08:27:53,19 2015-04-07 08:32:53,26 2015-04-07 08:37:53,15 2015-04-07 08:42:53,18 2015-04-07 08:47:53,16 2015-04-07 08:52:53,18 2015-04-07 08:57:53,16 2015-04-07 09:02:53,9 2015-04-07 09:07:53,9 2015-04-07 09:12:53,6 2015-04-07 09:17:53,26 2015-04-07 09:22:53,8 2015-04-07 09:27:53,15 2015-04-07 09:32:53,10 2015-04-07 09:37:53,17 2015-04-07 09:42:53,12 2015-04-07 09:47:53,43 2015-04-07 09:52:53,17 2015-04-07 09:57:53,19 2015-04-07 10:02:53,13 2015-04-07 10:07:53,10 2015-04-07 10:12:53,19 2015-04-07 10:17:53,15 2015-04-07 10:22:53,10 2015-04-07 10:27:53,21 2015-04-07 10:32:53,11 2015-04-07 10:37:53,12 2015-04-07 10:42:53,12 2015-04-07 10:47:53,19 2015-04-07 10:52:53,15 2015-04-07 10:57:53,24 2015-04-07 11:02:53,15 2015-04-07 11:07:53,9 2015-04-07 11:12:53,21 2015-04-07 11:17:53,11 2015-04-07 11:22:53,15 2015-04-07 11:27:53,20 2015-04-07 11:32:53,16 2015-04-07 11:37:53,12 2015-04-07 11:42:53,14 2015-04-07 11:47:53,20 2015-04-07 11:52:53,21 2015-04-07 11:57:53,18 2015-04-07 12:02:53,18 2015-04-07 12:07:53,12 2015-04-07 12:12:53,19 2015-04-07 12:17:53,27 2015-04-07 12:22:53,16 2015-04-07 12:27:53,27 2015-04-07 12:32:53,11 2015-04-07 12:37:53,8 2015-04-07 12:42:53,29 2015-04-07 12:47:53,21 2015-04-07 12:52:53,31 2015-04-07 12:57:53,23 2015-04-07 13:02:53,25 2015-04-07 13:07:53,31 2015-04-07 13:12:53,20 2015-04-07 13:17:53,19 2015-04-07 13:22:53,30 2015-04-07 13:27:53,33 2015-04-07 13:32:53,27 2015-04-07 13:37:53,31 2015-04-07 13:42:53,23 2015-04-07 13:47:53,25 2015-04-07 13:52:53,25 2015-04-07 13:57:53,32 2015-04-07 14:02:53,32 2015-04-07 14:07:53,16 2015-04-07 14:12:53,22 2015-04-07 14:17:53,17 2015-04-07 14:22:53,30 2015-04-07 14:27:53,18 2015-04-07 14:32:53,22 2015-04-07 14:37:53,29 2015-04-07 14:42:53,21 2015-04-07 14:47:53,24 2015-04-07 14:52:53,27 2015-04-07 14:57:53,27 2015-04-07 15:02:53,33 2015-04-07 15:07:53,45 2015-04-07 15:12:53,35 2015-04-07 15:17:53,35 2015-04-07 15:22:53,30 2015-04-07 15:27:53,34 2015-04-07 15:32:53,36 2015-04-07 15:37:53,67 2015-04-07 15:42:53,60 2015-04-07 15:47:53,31 2015-04-07 15:52:53,36 2015-04-07 15:57:53,54 2015-04-07 16:02:53,70 2015-04-07 16:07:53,31 2015-04-07 16:12:53,26 2015-04-07 16:17:53,36 2015-04-07 16:22:53,27 2015-04-07 16:27:53,34 2015-04-07 16:32:53,35 2015-04-07 16:37:53,36 2015-04-07 16:42:53,22 2015-04-07 16:47:53,40 2015-04-07 16:52:53,28 2015-04-07 16:57:53,20 2015-04-07 17:02:53,30 2015-04-07 17:07:53,34 2015-04-07 17:12:53,34 2015-04-07 17:17:53,69 2015-04-07 17:22:53,27 2015-04-07 17:27:53,48 2015-04-07 17:32:53,30 2015-04-07 17:37:53,22 2015-04-07 17:42:53,30 2015-04-07 17:47:53,34 2015-04-07 17:52:53,30 2015-04-07 17:57:53,31 2015-04-07 18:02:53,30 2015-04-07 18:07:53,41 2015-04-07 18:12:53,27 2015-04-07 18:17:53,28 2015-04-07 18:22:53,29 2015-04-07 18:27:53,37 2015-04-07 18:32:53,22 2015-04-07 18:37:53,30 2015-04-07 18:42:53,27 2015-04-07 18:47:53,28 2015-04-07 18:52:53,23 2015-04-07 18:57:53,26 2015-04-07 19:02:53,20 2015-04-07 19:07:53,26 2015-04-07 19:12:53,34 2015-04-07 19:17:53,15 2015-04-07 19:22:53,19 2015-04-07 19:27:53,16 2015-04-07 19:32:53,23 2015-04-07 19:37:53,29 2015-04-07 19:42:53,38 2015-04-07 19:47:53,23 2015-04-07 19:52:53,28 2015-04-07 19:57:53,16 2015-04-07 20:02:53,25 2015-04-07 20:07:53,20 2015-04-07 20:12:53,24 2015-04-07 20:17:53,28 2015-04-07 20:22:53,30 2015-04-07 20:27:53,23 2015-04-07 20:32:53,30 2015-04-07 20:37:53,31 2015-04-07 20:42:53,24 2015-04-07 20:47:53,16 2015-04-07 20:52:53,62 2015-04-07 20:57:53,62 2015-04-07 21:02:53,47 2015-04-07 21:07:53,44 2015-04-07 21:12:53,44 2015-04-07 21:17:53,38 2015-04-07 21:22:53,39 2015-04-07 21:27:53,18 2015-04-07 21:32:53,25 2015-04-07 21:37:53,21 2015-04-07 21:42:53,17 2015-04-07 21:47:53,24 2015-04-07 21:52:53,17 2015-04-07 21:57:53,32 2015-04-07 22:02:53,26 2015-04-07 22:07:53,12 2015-04-07 22:12:53,16 2015-04-07 22:17:53,16 2015-04-07 22:22:53,24 2015-04-07 22:27:53,15 2015-04-07 22:32:53,20 2015-04-07 22:37:53,19 2015-04-07 22:42:53,16 2015-04-07 22:47:53,26 2015-04-07 22:52:53,27 2015-04-07 22:57:53,8 2015-04-07 23:02:53,26 2015-04-07 23:07:53,17 2015-04-07 23:12:53,16 2015-04-07 23:17:53,14 2015-04-07 23:22:53,18 2015-04-07 23:27:53,60 2015-04-07 23:32:53,19 2015-04-07 23:37:53,19 2015-04-07 23:42:53,15 2015-04-07 23:47:53,14 2015-04-07 23:52:53,19 2015-04-07 23:57:53,10 2015-04-08 00:02:53,23 2015-04-08 00:07:53,21 2015-04-08 00:12:53,14 2015-04-08 00:17:53,11 2015-04-08 00:22:53,15 2015-04-08 00:27:53,21 2015-04-08 00:32:53,18 2015-04-08 00:37:53,16 2015-04-08 00:42:53,17 2015-04-08 00:47:53,5 2015-04-08 00:52:53,9 2015-04-08 00:57:53,12 2015-04-08 01:02:53,14 2015-04-08 01:07:53,16 2015-04-08 01:12:53,12 2015-04-08 01:17:53,14 2015-04-08 01:22:53,14 2015-04-08 01:27:53,13 2015-04-08 01:32:53,20 2015-04-08 01:37:53,19 2015-04-08 01:42:53,13 2015-04-08 01:47:53,14 2015-04-08 01:52:53,13 2015-04-08 01:57:53,27 2015-04-08 02:02:53,21 2015-04-08 02:07:53,16 2015-04-08 02:12:53,7 2015-04-08 02:17:53,8 2015-04-08 02:22:53,6 2015-04-08 02:27:53,11 2015-04-08 02:32:53,10 2015-04-08 02:37:53,17 2015-04-08 02:42:53,16 2015-04-08 02:47:53,6 2015-04-08 02:52:53,21 2015-04-08 02:57:53,14 2015-04-08 03:02:53,11 2015-04-08 03:07:53,12 2015-04-08 03:12:53,11 2015-04-08 03:17:53,14 2015-04-08 03:22:53,10 2015-04-08 03:27:53,15 2015-04-08 03:32:53,7 2015-04-08 03:37:53,10 2015-04-08 03:42:53,5 2015-04-08 03:47:53,7 2015-04-08 03:52:53,13 2015-04-08 03:57:53,21 2015-04-08 04:02:53,25 2015-04-08 04:07:53,17 2015-04-08 04:12:53,9 2015-04-08 04:17:53,11 2015-04-08 04:22:53,10 2015-04-08 04:27:53,23 2015-04-08 04:32:53,12 2015-04-08 04:37:53,11 2015-04-08 04:42:53,15 2015-04-08 04:47:53,9 2015-04-08 04:52:53,17 2015-04-08 04:57:53,13 2015-04-08 05:02:53,12 2015-04-08 05:07:53,9 2015-04-08 05:12:53,23 2015-04-08 05:17:53,20 2015-04-08 05:22:53,12 2015-04-08 05:27:53,7 2015-04-08 05:32:53,9 2015-04-08 05:37:53,9 2015-04-08 05:42:53,3 2015-04-08 05:47:53,10 2015-04-08 05:52:53,12 2015-04-08 05:57:53,9 2015-04-08 06:02:53,11 2015-04-08 06:07:53,11 2015-04-08 06:12:53,21 2015-04-08 06:17:53,17 2015-04-08 06:22:53,14 2015-04-08 06:27:53,15 2015-04-08 06:32:53,11 2015-04-08 06:37:53,10 2015-04-08 06:42:53,9 2015-04-08 06:47:53,14 2015-04-08 06:52:53,10 2015-04-08 06:57:53,14 2015-04-08 07:02:53,11 2015-04-08 07:07:53,14 2015-04-08 07:12:53,8 2015-04-08 07:17:53,17 2015-04-08 07:22:53,11 2015-04-08 07:27:53,24 2015-04-08 07:32:53,19 2015-04-08 07:37:53,9 2015-04-08 07:42:53,14 2015-04-08 07:47:53,18 2015-04-08 07:52:53,14 2015-04-08 07:57:53,6 2015-04-08 08:02:53,12 2015-04-08 08:07:53,17 2015-04-08 08:12:53,8 2015-04-08 08:17:53,13 2015-04-08 08:22:53,6 2015-04-08 08:27:53,13 2015-04-08 08:32:53,18 2015-04-08 08:37:53,14 2015-04-08 08:42:53,16 2015-04-08 08:47:53,16 2015-04-08 08:52:53,23 2015-04-08 08:57:53,11 2015-04-08 09:02:53,17 2015-04-08 09:07:53,13 2015-04-08 09:12:53,6 2015-04-08 09:17:53,6 2015-04-08 09:22:53,24 2015-04-08 09:27:53,12 2015-04-08 09:32:53,11 2015-04-08 09:37:53,11 2015-04-08 09:42:53,12 2015-04-08 09:47:53,10 2015-04-08 09:52:53,18 2015-04-08 09:57:53,22 2015-04-08 10:02:53,8 2015-04-08 10:07:53,5 2015-04-08 10:12:53,10 2015-04-08 10:17:53,16 2015-04-08 10:22:53,11 2015-04-08 10:27:53,16 2015-04-08 10:32:53,8 2015-04-08 10:37:53,11 2015-04-08 10:42:53,13 2015-04-08 10:47:53,16 2015-04-08 10:52:53,16 2015-04-08 10:57:53,10 2015-04-08 11:02:53,17 2015-04-08 11:07:53,12 2015-04-08 11:12:53,15 2015-04-08 11:17:53,10 2015-04-08 11:22:53,5 2015-04-08 11:27:53,15 2015-04-08 11:32:53,22 2015-04-08 11:37:53,22 2015-04-08 11:42:53,26 2015-04-08 11:47:53,19 2015-04-08 11:52:53,16 2015-04-08 11:57:53,19 2015-04-08 12:02:53,23 2015-04-08 12:07:53,17 2015-04-08 12:12:53,14 2015-04-08 12:17:53,18 2015-04-08 12:22:53,12 2015-04-08 12:27:53,13 2015-04-08 12:32:53,25 2015-04-08 12:37:53,28 2015-04-08 12:42:53,32 2015-04-08 12:47:53,22 2015-04-08 12:52:53,22 2015-04-08 12:57:53,29 2015-04-08 13:02:53,19 2015-04-08 13:07:53,20 2015-04-08 13:12:53,21 2015-04-08 13:17:53,16 2015-04-08 13:22:53,23 2015-04-08 13:27:53,15 2015-04-08 13:32:53,23 2015-04-08 13:37:53,17 2015-04-08 13:42:53,29 2015-04-08 13:47:53,18 2015-04-08 13:52:53,27 2015-04-08 13:57:53,23 2015-04-08 14:02:53,23 2015-04-08 14:07:53,14 2015-04-08 14:12:53,23 2015-04-08 14:17:53,28 2015-04-08 14:22:53,19 2015-04-08 14:27:53,36 2015-04-08 14:32:53,23 2015-04-08 14:37:53,21 2015-04-08 14:42:53,30 2015-04-08 14:47:53,18 2015-04-08 14:52:53,20 2015-04-08 14:57:53,28 2015-04-08 15:02:53,25 2015-04-08 15:07:53,19 2015-04-08 15:12:53,21 2015-04-08 15:17:53,22 2015-04-08 15:22:53,29 2015-04-08 15:27:53,32 2015-04-08 15:32:53,23 2015-04-08 15:37:53,22 2015-04-08 15:42:53,25 2015-04-08 15:47:53,25 2015-04-08 15:52:53,33 2015-04-08 15:57:53,31 2015-04-08 16:02:53,24 2015-04-08 16:07:53,24 2015-04-08 16:12:53,36 2015-04-08 16:17:53,23 2015-04-08 16:22:53,24 2015-04-08 16:27:53,44 2015-04-08 16:32:53,41 2015-04-08 16:37:53,41 2015-04-08 16:42:53,47 2015-04-08 16:47:53,21 2015-04-08 16:52:53,25 2015-04-08 16:57:53,30 2015-04-08 17:02:53,45 2015-04-08 17:07:53,33 2015-04-08 17:12:53,30 2015-04-08 17:17:53,17 2015-04-08 17:22:53,25 2015-04-08 17:27:53,33 2015-04-08 17:32:53,23 2015-04-08 17:37:53,34 2015-04-08 17:42:53,25 2015-04-08 17:47:53,38 2015-04-08 17:52:53,52 2015-04-08 17:57:53,40 2015-04-08 18:02:53,37 2015-04-08 18:07:53,33 2015-04-08 18:12:53,29 2015-04-08 18:17:53,28 2015-04-08 18:22:53,29 2015-04-08 18:27:53,23 2015-04-08 18:32:53,26 2015-04-08 18:37:53,27 2015-04-08 18:42:53,16 2015-04-08 18:47:53,25 2015-04-08 18:52:53,33 2015-04-08 18:57:53,28 2015-04-08 19:02:53,36 2015-04-08 19:07:53,36 2015-04-08 19:12:53,37 2015-04-08 19:17:53,22 2015-04-08 19:22:53,29 2015-04-08 19:27:53,26 2015-04-08 19:32:53,21 2015-04-08 19:37:53,36 2015-04-08 19:42:53,17 2015-04-08 19:47:53,28 2015-04-08 19:52:53,23 2015-04-08 19:57:53,42 2015-04-08 20:02:53,31 2015-04-08 20:07:53,38 2015-04-08 20:12:53,18 2015-04-08 20:17:53,26 2015-04-08 20:22:53,14 2015-04-08 20:27:53,28 2015-04-08 20:32:53,21 2015-04-08 20:37:53,18 2015-04-08 20:42:53,21 2015-04-08 20:47:53,26 2015-04-08 20:52:53,31 2015-04-08 20:57:53,33 2015-04-08 21:02:53,23 2015-04-08 21:07:53,25 2015-04-08 21:12:53,21 2015-04-08 21:17:53,22 2015-04-08 21:22:53,26 2015-04-08 21:27:53,23 2015-04-08 21:32:53,28 2015-04-08 21:37:53,17 2015-04-08 21:42:53,30 2015-04-08 21:47:53,18 2015-04-08 21:52:53,17 2015-04-08 21:57:53,16 2015-04-08 22:02:53,18 2015-04-08 22:07:53,15 2015-04-08 22:12:53,24 2015-04-08 22:17:53,18 2015-04-08 22:22:53,10 2015-04-08 22:27:53,20 2015-04-08 22:32:53,22 2015-04-08 22:37:53,15 2015-04-08 22:42:53,20 2015-04-08 22:47:53,14 2015-04-08 22:52:53,18 2015-04-08 22:57:53,56 2015-04-08 23:02:53,34 2015-04-08 23:07:53,26 2015-04-08 23:12:53,19 2015-04-08 23:17:53,19 2015-04-08 23:22:53,21 2015-04-08 23:27:53,17 2015-04-08 23:32:53,27 2015-04-08 23:37:53,17 2015-04-08 23:42:53,15 2015-04-08 23:47:53,14 2015-04-08 23:52:53,18 2015-04-08 23:57:53,12 2015-04-09 00:02:53,22 2015-04-09 00:07:53,12 2015-04-09 00:12:53,17 2015-04-09 00:17:53,15 2015-04-09 00:22:53,20 2015-04-09 00:27:53,21 2015-04-09 00:32:53,22 2015-04-09 00:37:53,13 2015-04-09 00:42:53,23 2015-04-09 00:47:53,16 2015-04-09 00:52:53,28 2015-04-09 00:57:53,20 2015-04-09 01:02:53,18 2015-04-09 01:07:53,13 2015-04-09 01:12:53,24 2015-04-09 01:17:53,21 2015-04-09 01:22:53,20 2015-04-09 01:27:53,18 2015-04-09 01:32:53,13 2015-04-09 01:37:53,15 2015-04-09 01:42:53,18 2015-04-09 01:47:53,22 2015-04-09 01:52:53,18 2015-04-09 01:57:53,19 2015-04-09 02:02:53,16 2015-04-09 02:07:53,11 2015-04-09 02:12:53,22 2015-04-09 02:17:53,16 2015-04-09 02:22:53,15 2015-04-09 02:27:53,27 2015-04-09 02:32:53,3 2015-04-09 02:37:53,11 2015-04-09 02:42:53,14 2015-04-09 02:47:53,6 2015-04-09 02:52:53,31 2015-04-09 02:57:53,33 2015-04-09 03:02:53,35 2015-04-09 03:07:53,23 2015-04-09 03:12:53,16 2015-04-09 03:17:53,11 2015-04-09 03:22:53,11 2015-04-09 03:27:53,15 2015-04-09 03:32:53,16 2015-04-09 03:37:53,13 2015-04-09 03:42:53,12 2015-04-09 03:47:53,17 2015-04-09 03:52:53,13 2015-04-09 03:57:53,8 2015-04-09 04:02:53,7 2015-04-09 04:07:53,13 2015-04-09 04:12:53,13 2015-04-09 04:17:53,13 2015-04-09 04:22:53,10 2015-04-09 04:27:53,15 2015-04-09 04:32:53,8 2015-04-09 04:37:53,9 2015-04-09 04:42:53,13 2015-04-09 04:47:53,17 2015-04-09 04:52:53,17 2015-04-09 04:57:53,12 2015-04-09 05:02:53,12 2015-04-09 05:07:53,10 2015-04-09 05:12:53,13 2015-04-09 05:17:53,7 2015-04-09 05:22:53,15 2015-04-09 05:27:53,17 2015-04-09 05:32:53,15 2015-04-09 05:37:53,30 2015-04-09 05:42:53,16 2015-04-09 05:47:53,3 2015-04-09 05:52:53,13 2015-04-09 05:57:53,15 2015-04-09 06:02:53,8 2015-04-09 06:07:53,11 2015-04-09 06:12:53,11 2015-04-09 06:17:53,14 2015-04-09 06:22:53,16 2015-04-09 06:27:53,13 2015-04-09 06:32:53,5 2015-04-09 06:37:53,8 2015-04-09 06:42:53,10 2015-04-09 06:47:53,6 2015-04-09 06:52:53,17 2015-04-09 06:57:53,16 2015-04-09 07:02:53,10 2015-04-09 07:07:53,5 2015-04-09 07:12:53,17 2015-04-09 07:17:53,17 2015-04-09 07:22:53,25 2015-04-09 07:27:53,17 2015-04-09 07:32:53,13 2015-04-09 07:37:53,7 2015-04-09 07:42:53,20 2015-04-09 07:47:53,9 2015-04-09 07:52:53,19 2015-04-09 07:57:53,12 2015-04-09 08:02:53,18 2015-04-09 08:07:53,17 2015-04-09 08:12:53,12 2015-04-09 08:17:53,16 2015-04-09 08:22:53,9 2015-04-09 08:27:53,9 2015-04-09 08:32:53,16 2015-04-09 08:37:53,10 2015-04-09 08:42:53,14 2015-04-09 08:47:53,21 2015-04-09 08:52:53,23 2015-04-09 08:57:53,16 2015-04-09 09:02:53,17 2015-04-09 09:07:53,13 2015-04-09 09:12:53,12 2015-04-09 09:17:53,14 2015-04-09 09:22:53,7 2015-04-09 09:27:53,11 2015-04-09 09:32:53,6 2015-04-09 09:37:53,11 2015-04-09 09:42:53,14 2015-04-09 09:47:53,9 2015-04-09 09:52:53,9 2015-04-09 09:57:53,17 2015-04-09 10:02:53,8 2015-04-09 10:07:53,7 2015-04-09 10:12:53,19 2015-04-09 10:17:53,10 2015-04-09 10:22:53,13 2015-04-09 10:27:53,13 2015-04-09 10:32:53,6 2015-04-09 10:37:53,14 2015-04-09 10:42:53,10 2015-04-09 10:47:53,11 2015-04-09 10:52:53,11 2015-04-09 10:57:53,17 2015-04-09 11:02:53,10 2015-04-09 11:07:53,11 2015-04-09 11:12:53,23 2015-04-09 11:17:53,24 2015-04-09 11:22:53,14 2015-04-09 11:27:53,10 2015-04-09 11:32:53,6 2015-04-09 11:37:53,12 2015-04-09 11:42:53,11 2015-04-09 11:47:53,11 2015-04-09 11:52:53,10 2015-04-09 11:57:53,18 2015-04-09 12:02:53,22 2015-04-09 12:07:53,16 2015-04-09 12:12:53,15 2015-04-09 12:17:53,16 2015-04-09 12:22:53,21 2015-04-09 12:27:53,11 2015-04-09 12:32:53,13 2015-04-09 12:37:53,17 2015-04-09 12:42:53,12 2015-04-09 12:47:53,17 2015-04-09 12:52:53,27 2015-04-09 12:57:53,17 2015-04-09 13:02:53,37 2015-04-09 13:07:53,27 2015-04-09 13:12:53,52 2015-04-09 13:17:53,25 2015-04-09 13:22:53,23 2015-04-09 13:27:53,26 2015-04-09 13:32:53,18 2015-04-09 13:37:53,18 2015-04-09 13:42:53,13 2015-04-09 13:47:53,15 2015-04-09 13:52:53,12 2015-04-09 13:57:53,14 2015-04-09 14:02:53,30 2015-04-09 14:07:53,24 2015-04-09 14:12:53,34 2015-04-09 14:17:53,36 2015-04-09 14:22:53,33 2015-04-09 14:27:53,31 2015-04-09 14:32:53,18 2015-04-09 14:37:53,16 2015-04-09 14:42:53,33 2015-04-09 14:47:53,22 2015-04-09 14:52:53,22 2015-04-09 14:57:53,33 2015-04-09 15:02:53,27 2015-04-09 15:07:53,26 2015-04-09 15:12:53,25 2015-04-09 15:17:53,14 2015-04-09 15:22:53,20 2015-04-09 15:27:53,22 2015-04-09 15:32:53,22 2015-04-09 15:37:53,27 2015-04-09 15:42:53,40 2015-04-09 15:47:53,25 2015-04-09 15:52:53,35 2015-04-09 15:57:53,31 2015-04-09 16:02:53,26 2015-04-09 16:07:53,40 2015-04-09 16:12:53,19 2015-04-09 16:17:53,28 2015-04-09 16:22:53,25 2015-04-09 16:27:53,28 2015-04-09 16:32:53,16 2015-04-09 16:37:53,13 2015-04-09 16:42:53,17 2015-04-09 16:47:53,36 2015-04-09 16:52:53,23 2015-04-09 16:57:53,36 2015-04-09 17:02:53,27 2015-04-09 17:07:53,24 2015-04-09 17:12:53,15 2015-04-09 17:17:53,19 2015-04-09 17:22:53,29 2015-04-09 17:27:53,37 2015-04-09 17:32:53,23 2015-04-09 17:37:53,26 2015-04-09 17:42:53,20 2015-04-09 17:47:53,23 2015-04-09 17:52:53,16 2015-04-09 17:57:53,20 2015-04-09 18:02:53,21 2015-04-09 18:07:53,26 2015-04-09 18:12:53,23 2015-04-09 18:17:53,23 2015-04-09 18:22:53,14 2015-04-09 18:27:53,29 2015-04-09 18:32:53,22 2015-04-09 18:37:53,29 2015-04-09 18:42:53,26 2015-04-09 18:47:53,39 2015-04-09 18:52:53,22 2015-04-09 18:57:53,25 2015-04-09 19:02:53,33 2015-04-09 19:07:53,28 2015-04-09 19:12:53,15 2015-04-09 19:17:53,23 2015-04-09 19:22:53,17 2015-04-09 19:27:53,21 2015-04-09 19:32:53,23 2015-04-09 19:37:53,18 2015-04-09 19:42:53,13 2015-04-09 19:47:53,17 2015-04-09 19:52:53,21 2015-04-09 19:57:53,25 2015-04-09 20:02:53,51 2015-04-09 20:07:53,39 2015-04-09 20:12:53,45 2015-04-09 20:17:53,22 2015-04-09 20:22:53,27 2015-04-09 20:27:53,19 2015-04-09 20:32:53,32 2015-04-09 20:37:53,22 2015-04-09 20:42:53,27 2015-04-09 20:47:53,20 2015-04-09 20:52:53,23 2015-04-09 20:57:53,24 2015-04-09 21:02:53,12 2015-04-09 21:07:53,17 2015-04-09 21:12:53,26 2015-04-09 21:17:53,8 2015-04-09 21:22:53,20 2015-04-09 21:27:53,28 2015-04-09 21:32:53,33 2015-04-09 21:37:53,46 2015-04-09 21:42:53,20 2015-04-09 21:47:53,14 2015-04-09 21:52:53,11 2015-04-09 21:57:53,16 2015-04-09 22:02:53,24 2015-04-09 22:07:53,32 2015-04-09 22:12:53,44 2015-04-09 22:17:53,24 2015-04-09 22:22:53,22 2015-04-09 22:27:53,14 2015-04-09 22:32:53,22 2015-04-09 22:37:53,22 2015-04-09 22:42:53,19 2015-04-09 22:47:53,22 2015-04-09 22:52:53,17 2015-04-09 22:57:53,15 2015-04-09 23:02:53,17 2015-04-09 23:07:53,20 2015-04-09 23:12:53,8 2015-04-09 23:17:53,24 2015-04-09 23:22:53,26 2015-04-09 23:27:53,15 2015-04-09 23:32:53,15 2015-04-09 23:37:53,12 2015-04-09 23:42:53,12 2015-04-09 23:47:53,8 2015-04-09 23:52:53,14 2015-04-09 23:57:53,17 2015-04-10 00:02:53,18 2015-04-10 00:07:53,36 2015-04-10 00:12:53,21 2015-04-10 00:17:53,18 2015-04-10 00:22:53,25 2015-04-10 00:27:53,21 2015-04-10 00:32:53,23 2015-04-10 00:37:53,21 2015-04-10 00:42:53,17 2015-04-10 00:47:53,15 2015-04-10 00:52:53,13 2015-04-10 00:57:53,23 2015-04-10 01:02:53,9 2015-04-10 01:07:53,9 2015-04-10 01:12:53,16 2015-04-10 01:17:53,16 2015-04-10 01:22:53,8 2015-04-10 01:27:53,18 2015-04-10 01:32:53,15 2015-04-10 01:37:53,19 2015-04-10 01:42:53,14 2015-04-10 01:47:53,13 2015-04-10 01:52:53,15 2015-04-10 01:57:53,15 2015-04-10 02:02:53,13 2015-04-10 02:07:53,12 2015-04-10 02:12:53,10 2015-04-10 02:17:53,8 2015-04-10 02:22:53,11 2015-04-10 02:27:53,18 2015-04-10 02:32:53,20 2015-04-10 02:37:53,16 2015-04-10 02:42:53,20 2015-04-10 02:47:53,14 2015-04-10 02:52:53,18 2015-04-10 02:57:53,23 2015-04-10 03:02:53,29 2015-04-10 03:07:53,13 2015-04-10 03:12:53,10 2015-04-10 03:17:53,7 2015-04-10 03:22:53,5 2015-04-10 03:27:53,12 2015-04-10 03:32:53,11 2015-04-10 03:37:53,14 2015-04-10 03:42:53,15 2015-04-10 03:47:53,4 2015-04-10 03:52:53,3 2015-04-10 03:57:53,26 2015-04-10 04:02:53,11 2015-04-10 04:07:53,11 2015-04-10 04:12:53,11 2015-04-10 04:17:53,6 2015-04-10 04:22:53,11 2015-04-10 04:27:53,8 2015-04-10 04:32:53,23 2015-04-10 04:37:53,13 2015-04-10 04:42:53,20 2015-04-10 04:47:53,11 2015-04-10 04:52:53,5 2015-04-10 04:57:53,13 2015-04-10 05:02:53,5 2015-04-10 05:07:53,8 2015-04-10 05:12:53,46 2015-04-10 05:17:53,34 2015-04-10 05:22:53,38 2015-04-10 05:27:53,18 2015-04-10 05:32:53,32 2015-04-10 05:37:53,18 2015-04-10 05:42:53,15 2015-04-10 05:47:53,23 2015-04-10 05:52:53,23 2015-04-10 05:57:53,12 2015-04-10 06:02:53,11 2015-04-10 06:07:53,21 2015-04-10 06:12:53,16 2015-04-10 06:17:53,7 2015-04-10 06:22:53,11 2015-04-10 06:27:53,9 2015-04-10 06:32:53,8 2015-04-10 06:37:53,10 2015-04-10 06:42:53,13 2015-04-10 06:47:53,10 2015-04-10 06:52:53,7 2015-04-10 06:57:53,10 2015-04-10 07:02:53,35 2015-04-10 07:07:53,17 2015-04-10 07:12:53,22 2015-04-10 07:17:53,12 2015-04-10 07:22:53,18 2015-04-10 07:27:53,15 2015-04-10 07:32:53,11 2015-04-10 07:37:53,14 2015-04-10 07:42:53,11 2015-04-10 07:47:53,5 2015-04-10 07:52:53,16 2015-04-10 07:57:53,17 2015-04-10 08:02:53,19 2015-04-10 08:07:53,20 2015-04-10 08:12:53,14 2015-04-10 08:17:53,13 2015-04-10 08:22:53,9 2015-04-10 08:27:53,7 2015-04-10 08:32:53,8 2015-04-10 08:37:53,15 2015-04-10 08:42:53,12 2015-04-10 08:47:53,16 2015-04-10 08:52:53,14 2015-04-10 08:57:53,17 2015-04-10 09:02:53,22 2015-04-10 09:07:53,23 2015-04-10 09:12:53,13 2015-04-10 09:17:53,16 2015-04-10 09:22:53,12 2015-04-10 09:27:53,25 2015-04-10 09:32:53,35 2015-04-10 09:37:53,23 2015-04-10 09:42:53,24 2015-04-10 09:47:53,32 2015-04-10 09:52:53,16 2015-04-10 09:57:53,29 2015-04-10 10:02:53,22 2015-04-10 10:07:53,12 2015-04-10 10:12:53,16 2015-04-10 10:17:53,9 2015-04-10 10:22:53,3 2015-04-10 10:27:53,12 2015-04-10 10:32:53,14 2015-04-10 10:37:53,33 2015-04-10 10:42:53,13 2015-04-10 10:47:53,14 2015-04-10 10:52:53,12 2015-04-10 10:57:53,20 2015-04-10 11:02:53,22 2015-04-10 11:07:53,15 2015-04-10 11:12:53,17 2015-04-10 11:17:53,11 2015-04-10 11:22:53,12 2015-04-10 11:27:53,16 2015-04-10 11:32:53,15 2015-04-10 11:37:53,12 2015-04-10 11:42:53,16 2015-04-10 11:47:53,11 2015-04-10 11:52:53,13 2015-04-10 11:57:53,18 2015-04-10 12:02:53,19 2015-04-10 12:07:53,15 2015-04-10 12:12:53,17 2015-04-10 12:17:53,9 2015-04-10 12:22:53,16 2015-04-10 12:27:53,15 2015-04-10 12:32:53,19 2015-04-10 12:37:53,18 2015-04-10 12:42:53,19 2015-04-10 12:47:53,13 2015-04-10 12:52:53,18 2015-04-10 12:57:53,20 2015-04-10 13:02:53,13 2015-04-10 13:07:53,17 2015-04-10 13:12:53,14 2015-04-10 13:17:53,20 2015-04-10 13:22:53,19 2015-04-10 13:27:53,25 2015-04-10 13:32:53,11 2015-04-10 13:37:53,16 2015-04-10 13:42:53,18 2015-04-10 13:47:53,26 2015-04-10 13:52:53,10 2015-04-10 13:57:53,17 2015-04-10 14:02:53,34 2015-04-10 14:07:53,29 2015-04-10 14:12:53,24 2015-04-10 14:17:53,11 2015-04-10 14:22:53,18 2015-04-10 14:27:53,12 2015-04-10 14:32:53,9 2015-04-10 14:37:53,18 2015-04-10 14:42:53,21 2015-04-10 14:47:53,19 2015-04-10 14:52:53,19 2015-04-10 14:57:53,28 2015-04-10 15:02:53,27 2015-04-10 15:07:53,18 2015-04-10 15:12:53,27 2015-04-10 15:17:53,18 2015-04-10 15:22:53,20 2015-04-10 15:27:53,18 2015-04-10 15:32:53,21 2015-04-10 15:37:53,17 2015-04-10 15:42:53,23 2015-04-10 15:47:53,28 2015-04-10 15:52:53,18 2015-04-10 15:57:53,29 2015-04-10 16:02:53,18 2015-04-10 16:07:53,19 2015-04-10 16:12:53,25 2015-04-10 16:17:53,10 2015-04-10 16:22:53,20 2015-04-10 16:27:53,26 2015-04-10 16:32:53,16 2015-04-10 16:37:53,12 2015-04-10 16:42:53,14 2015-04-10 16:47:53,18 2015-04-10 16:52:53,20 2015-04-10 16:57:53,24 2015-04-10 17:02:53,17 2015-04-10 17:07:53,30 2015-04-10 17:12:53,19 2015-04-10 17:17:53,11 2015-04-10 17:22:53,18 2015-04-10 17:27:53,18 2015-04-10 17:32:53,16 2015-04-10 17:37:53,19 2015-04-10 17:42:53,17 2015-04-10 17:47:53,11 2015-04-10 17:52:53,20 2015-04-10 17:57:53,21 2015-04-10 18:02:53,23 2015-04-10 18:07:53,31 2015-04-10 18:12:53,28 2015-04-10 18:17:53,35 2015-04-10 18:22:53,52 2015-04-10 18:27:53,25 2015-04-10 18:32:53,16 2015-04-10 18:37:53,18 2015-04-10 18:42:53,15 2015-04-10 18:47:53,18 2015-04-10 18:52:53,18 2015-04-10 18:57:53,35 2015-04-10 19:02:53,30 2015-04-10 19:07:53,17 2015-04-10 19:12:53,26 2015-04-10 19:17:53,13 2015-04-10 19:22:53,21 2015-04-10 19:27:53,33 2015-04-10 19:32:53,26 2015-04-10 19:37:53,17 2015-04-10 19:42:53,21 2015-04-10 19:47:53,13 2015-04-10 19:52:53,14 2015-04-10 19:57:53,33 2015-04-10 20:02:53,48 2015-04-10 20:07:53,31 2015-04-10 20:12:53,19 2015-04-10 20:17:53,20 2015-04-10 20:22:53,14 2015-04-10 20:27:53,19 2015-04-10 20:32:53,11 2015-04-10 20:37:53,12 2015-04-10 20:42:53,25 2015-04-10 20:47:53,25 2015-04-10 20:52:53,21 2015-04-10 20:57:53,21 2015-04-10 21:02:53,26 2015-04-10 21:07:53,17 2015-04-10 21:12:53,10 2015-04-10 21:17:53,16 2015-04-10 21:22:53,17 2015-04-10 21:27:53,14 2015-04-10 21:32:53,16 2015-04-10 21:37:53,7 2015-04-10 21:42:53,21 2015-04-10 21:47:53,30 2015-04-10 21:52:53,23 2015-04-10 21:57:53,24 2015-04-10 22:02:53,18 2015-04-10 22:07:53,17 2015-04-10 22:12:53,15 2015-04-10 22:17:53,17 2015-04-10 22:22:53,15 2015-04-10 22:27:53,24 2015-04-10 22:32:53,22 2015-04-10 22:37:53,16 2015-04-10 22:42:53,20 2015-04-10 22:47:53,15 2015-04-10 22:52:53,16 2015-04-10 22:57:53,26 2015-04-10 23:02:53,21 2015-04-10 23:07:53,19 2015-04-10 23:12:53,14 2015-04-10 23:17:53,26 2015-04-10 23:22:53,17 2015-04-10 23:27:53,15 2015-04-10 23:32:53,13 2015-04-10 23:37:53,10 2015-04-10 23:42:53,10 2015-04-10 23:47:53,13 2015-04-10 23:52:53,9 2015-04-10 23:57:53,10 2015-04-11 00:02:53,8 2015-04-11 00:07:53,8 2015-04-11 00:12:53,13 2015-04-11 00:17:53,8 2015-04-11 00:22:53,14 2015-04-11 00:27:53,11 2015-04-11 00:32:53,18 2015-04-11 00:37:53,6 2015-04-11 00:42:53,12 2015-04-11 00:47:53,9 2015-04-11 00:52:53,19 2015-04-11 00:57:53,18 2015-04-11 01:02:53,11 2015-04-11 01:07:53,9 2015-04-11 01:12:53,9 2015-04-11 01:17:53,5 2015-04-11 01:22:53,6 2015-04-11 01:27:53,8 2015-04-11 01:32:53,9 2015-04-11 01:37:53,7 2015-04-11 01:42:53,16 2015-04-11 01:47:53,11 2015-04-11 01:52:53,4 2015-04-11 01:57:53,11 2015-04-11 02:02:53,25 2015-04-11 02:07:53,9 2015-04-11 02:12:53,4 2015-04-11 02:17:53,8 2015-04-11 02:22:53,13 2015-04-11 02:27:53,8 2015-04-11 02:32:53,6 2015-04-11 02:37:53,10 2015-04-11 02:42:53,15 2015-04-11 02:47:53,14 2015-04-11 02:52:53,4 2015-04-11 02:57:53,8 2015-04-11 03:02:53,7 2015-04-11 03:07:53,8 2015-04-11 03:12:53,14 2015-04-11 03:17:53,16 2015-04-11 03:22:53,12 2015-04-11 03:27:53,9 2015-04-11 03:32:53,15 2015-04-11 03:37:53,8 2015-04-11 03:42:53,3 2015-04-11 03:47:53,5 2015-04-11 03:52:53,6 2015-04-11 03:57:53,10 2015-04-11 04:02:53,16 2015-04-11 04:07:53,14 2015-04-11 04:12:53,12 2015-04-11 04:17:53,7 2015-04-11 04:22:53,9 2015-04-11 04:27:53,8 2015-04-11 04:32:53,4 2015-04-11 04:37:53,7 2015-04-11 04:42:53,4 2015-04-11 04:47:53,10 2015-04-11 04:52:53,9 2015-04-11 04:57:53,5 2015-04-11 05:02:53,10 2015-04-11 05:07:53,8 2015-04-11 05:12:53,10 2015-04-11 05:17:53,16 2015-04-11 05:22:53,4 2015-04-11 05:27:53,3 2015-04-11 05:32:53,5 2015-04-11 05:37:53,10 2015-04-11 05:42:53,16 2015-04-11 05:47:53,4 2015-04-11 05:52:53,5 2015-04-11 05:57:53,8 2015-04-11 06:02:53,8 2015-04-11 06:07:53,10 2015-04-11 06:12:53,4 2015-04-11 06:17:53,6 2015-04-11 06:22:53,8 2015-04-11 06:27:53,4 2015-04-11 06:32:53,5 2015-04-11 06:37:53,3 2015-04-11 06:42:53,14 2015-04-11 06:47:53,9 2015-04-11 06:52:53,3 2015-04-11 06:57:53,5 2015-04-11 07:02:53,5 2015-04-11 07:07:53,5 2015-04-11 07:12:53,5 2015-04-11 07:17:53,13 2015-04-11 07:22:53,2 2015-04-11 07:27:53,7 2015-04-11 07:32:53,13 2015-04-11 07:37:53,4 2015-04-11 07:42:53,12 2015-04-11 07:47:53,10 2015-04-11 07:52:53,10 2015-04-11 07:57:53,3 2015-04-11 08:02:53,13 2015-04-11 08:07:53,10 2015-04-11 08:12:53,6 2015-04-11 08:17:53,6 2015-04-11 08:22:53,3 2015-04-11 08:27:53,9 2015-04-11 08:32:53,4 2015-04-11 08:37:53,16 2015-04-11 08:42:53,8 2015-04-11 08:47:53,5 2015-04-11 08:52:53,11 2015-04-11 08:57:53,18 2015-04-11 09:02:53,8 2015-04-11 09:07:53,12 2015-04-11 09:12:53,13 2015-04-11 09:17:53,11 2015-04-11 09:22:53,9 2015-04-11 09:27:53,2 2015-04-11 09:32:53,6 2015-04-11 09:37:53,8 2015-04-11 09:42:53,3 2015-04-11 09:47:53,4 2015-04-11 09:52:53,10 2015-04-11 09:57:53,5 2015-04-11 10:02:53,5 2015-04-11 10:07:53,10 2015-04-11 10:12:53,4 2015-04-11 10:17:53,10 2015-04-11 10:22:53,6 2015-04-11 10:27:53,8 2015-04-11 10:32:53,8 2015-04-11 10:37:53,14 2015-04-11 10:42:53,6 2015-04-11 10:47:53,8 2015-04-11 10:52:53,15 2015-04-11 10:57:53,7 2015-04-11 11:02:53,8 2015-04-11 11:07:53,11 2015-04-11 11:12:53,8 2015-04-11 11:17:53,7 2015-04-11 11:22:53,5 2015-04-11 11:27:53,13 2015-04-11 11:32:53,27 2015-04-11 11:37:53,17 2015-04-11 11:42:53,9 2015-04-11 11:47:53,4 2015-04-11 11:52:53,25 2015-04-11 11:57:53,21 2015-04-11 12:02:53,13 2015-04-11 12:07:53,14 2015-04-11 12:12:53,8 2015-04-11 12:17:53,8 2015-04-11 12:22:53,19 2015-04-11 12:27:53,7 2015-04-11 12:32:53,8 2015-04-11 12:37:53,16 2015-04-11 12:42:53,10 2015-04-11 12:47:53,7 2015-04-11 12:52:53,12 2015-04-11 12:57:53,13 2015-04-11 13:02:53,13 2015-04-11 13:07:53,13 2015-04-11 13:12:53,12 2015-04-11 13:17:53,12 2015-04-11 13:22:53,8 2015-04-11 13:27:53,9 2015-04-11 13:32:53,5 2015-04-11 13:37:53,11 2015-04-11 13:42:53,11 2015-04-11 13:47:53,12 2015-04-11 13:52:53,15 2015-04-11 13:57:53,14 2015-04-11 14:02:53,14 2015-04-11 14:07:53,12 2015-04-11 14:12:53,12 2015-04-11 14:17:53,13 2015-04-11 14:22:53,12 2015-04-11 14:27:53,18 2015-04-11 14:32:53,14 2015-04-11 14:37:53,17 2015-04-11 14:42:53,14 2015-04-11 14:47:53,16 2015-04-11 14:52:53,10 2015-04-11 14:57:53,14 2015-04-11 15:02:53,19 2015-04-11 15:07:53,15 2015-04-11 15:12:53,8 2015-04-11 15:17:53,10 2015-04-11 15:22:53,10 2015-04-11 15:27:53,10 2015-04-11 15:32:53,13 2015-04-11 15:37:53,8 2015-04-11 15:42:53,16 2015-04-11 15:47:53,13 2015-04-11 15:52:53,15 2015-04-11 15:57:53,11 2015-04-11 16:02:53,6 2015-04-11 16:07:53,10 2015-04-11 16:12:53,13 2015-04-11 16:17:53,13 2015-04-11 16:22:53,12 2015-04-11 16:27:53,8 2015-04-11 16:32:53,9 2015-04-11 16:37:53,6 2015-04-11 16:42:53,14 2015-04-11 16:47:53,9 2015-04-11 16:52:53,6 2015-04-11 16:57:53,10 2015-04-11 17:02:53,17 2015-04-11 17:07:53,10 2015-04-11 17:12:53,23 2015-04-11 17:17:53,3 2015-04-11 17:22:53,8 2015-04-11 17:27:53,11 2015-04-11 17:32:53,15 2015-04-11 17:37:53,9 2015-04-11 17:42:53,10 2015-04-11 17:47:53,12 2015-04-11 17:52:53,12 2015-04-11 17:57:53,15 2015-04-11 18:02:53,17 2015-04-11 18:07:53,17 2015-04-11 18:12:53,12 2015-04-11 18:17:53,11 2015-04-11 18:22:53,11 2015-04-11 18:27:53,20 2015-04-11 18:32:53,21 2015-04-11 18:37:53,8 2015-04-11 18:42:53,13 2015-04-11 18:47:53,14 2015-04-11 18:52:53,8 2015-04-11 18:57:53,13 2015-04-11 19:02:53,16 2015-04-11 19:07:53,4 2015-04-11 19:12:53,22 2015-04-11 19:17:53,20 2015-04-11 19:22:53,19 2015-04-11 19:27:53,14 2015-04-11 19:32:53,9 2015-04-11 19:37:53,5 2015-04-11 19:42:53,3 2015-04-11 19:47:53,33 2015-04-11 19:52:53,23 2015-04-11 19:57:53,24 2015-04-11 20:02:53,15 2015-04-11 20:07:53,8 2015-04-11 20:12:53,13 2015-04-11 20:17:53,12 2015-04-11 20:22:53,11 2015-04-11 20:27:53,17 2015-04-11 20:32:53,9 2015-04-11 20:37:53,7 2015-04-11 20:42:53,6 2015-04-11 20:47:53,12 2015-04-11 20:52:53,7 2015-04-11 20:57:53,28 2015-04-11 21:02:53,10 2015-04-11 21:07:53,25 2015-04-11 21:12:53,12 2015-04-11 21:17:53,19 2015-04-11 21:22:53,8 2015-04-11 21:27:53,10 2015-04-11 21:32:53,8 2015-04-11 21:37:53,15 2015-04-11 21:42:53,7 2015-04-11 21:47:53,7 2015-04-11 21:52:53,10 2015-04-11 21:57:53,13 2015-04-11 22:02:53,2 2015-04-11 22:07:53,7 2015-04-11 22:12:53,7 2015-04-11 22:17:53,17 2015-04-11 22:22:53,5 2015-04-11 22:27:53,11 2015-04-11 22:32:53,25 2015-04-11 22:37:53,19 2015-04-11 22:42:53,6 2015-04-11 22:47:53,9 2015-04-11 22:52:53,6 2015-04-11 22:57:53,7 2015-04-11 23:02:53,9 2015-04-11 23:07:53,3 2015-04-11 23:12:53,6 2015-04-11 23:17:53,14 2015-04-11 23:22:53,5 2015-04-11 23:27:53,12 2015-04-11 23:32:53,8 2015-04-11 23:37:53,8 2015-04-11 23:42:53,5 2015-04-11 23:47:53,8 2015-04-11 23:52:53,2 2015-04-11 23:57:53,9 2015-04-12 00:02:53,7 2015-04-12 00:07:53,16 2015-04-12 00:12:53,12 2015-04-12 00:17:53,10 2015-04-12 00:22:53,8 2015-04-12 00:27:53,11 2015-04-12 00:32:53,12 2015-04-12 00:37:53,13 2015-04-12 00:42:53,8 2015-04-12 00:47:53,17 2015-04-12 00:52:53,14 2015-04-12 00:57:53,10 2015-04-12 01:02:53,7 2015-04-12 01:07:53,4 2015-04-12 01:12:53,14 2015-04-12 01:17:53,7 2015-04-12 01:22:53,5 2015-04-12 01:27:53,7 2015-04-12 01:32:53,9 2015-04-12 01:37:53,5 2015-04-12 01:42:53,7 2015-04-12 01:47:53,2 2015-04-12 01:52:53,11 2015-04-12 01:57:53,15 2015-04-12 02:02:53,7 2015-04-12 02:07:53,1 2015-04-12 02:12:53,3 2015-04-12 02:17:53,8 2015-04-12 02:22:53,1 2015-04-12 02:27:53,12 2015-04-12 02:32:53,1 2015-04-12 02:37:53,9 2015-04-12 02:42:53,27 2015-04-12 02:47:53,4 2015-04-12 02:52:53,5 2015-04-12 02:57:53,6 2015-04-12 03:02:53,4 2015-04-12 03:07:53,10 2015-04-12 03:12:53,8 2015-04-12 03:17:53,7 2015-04-12 03:22:53,6 2015-04-12 03:27:53,12 2015-04-12 03:32:53,6 2015-04-12 03:37:53,4 2015-04-12 03:42:53,11 2015-04-12 03:47:53,3 2015-04-12 03:52:53,6 2015-04-12 03:57:53,10 2015-04-12 04:02:53,8 2015-04-12 04:07:53,4 2015-04-12 04:12:53,6 2015-04-12 04:17:53,9 2015-04-12 04:22:53,3 2015-04-12 04:27:53,9 2015-04-12 04:32:53,6 2015-04-12 04:37:53,7 2015-04-12 04:42:53,11 2015-04-12 04:47:53,14 2015-04-12 04:52:53,7 2015-04-12 04:57:53,7 2015-04-12 05:02:53,22 2015-04-12 05:07:53,13 2015-04-12 05:12:53,12 2015-04-12 05:17:53,13 2015-04-12 05:22:53,15 2015-04-12 05:27:53,11 2015-04-12 05:32:53,11 2015-04-12 05:37:53,10 2015-04-12 05:42:53,8 2015-04-12 05:47:53,12 2015-04-12 05:52:53,17 2015-04-12 05:57:53,15 2015-04-12 06:02:53,4 2015-04-12 06:07:53,31 2015-04-12 06:12:53,11 2015-04-12 06:17:53,6 2015-04-12 06:22:53,6 2015-04-12 06:27:53,8 2015-04-12 06:32:53,7 2015-04-12 06:37:53,12 2015-04-12 06:42:53,9 2015-04-12 06:47:53,19 2015-04-12 06:52:53,7 2015-04-12 06:57:53,5 2015-04-12 07:02:53,10 2015-04-12 07:07:53,8 2015-04-12 07:12:53,2 2015-04-12 07:17:53,9 2015-04-12 07:22:53,4 2015-04-12 07:27:53,3 2015-04-12 07:32:53,12 2015-04-12 07:37:53,5 2015-04-12 07:42:53,6 2015-04-12 07:47:53,5 2015-04-12 07:52:53,6 2015-04-12 07:57:53,11 2015-04-12 08:02:53,8 2015-04-12 08:07:53,2 2015-04-12 08:12:53,4 2015-04-12 08:17:53,10 2015-04-12 08:22:53,5 2015-04-12 08:27:53,13 2015-04-12 08:32:53,1 2015-04-12 08:37:53,15 2015-04-12 08:42:53,14 2015-04-12 08:47:53,7 2015-04-12 08:52:53,2 2015-04-12 08:57:53,3 2015-04-12 09:02:53,6 2015-04-12 09:07:53,8 2015-04-12 09:12:53,7 2015-04-12 09:17:53,12 2015-04-12 09:22:53,8 2015-04-12 09:27:53,5 2015-04-12 09:32:53,10 2015-04-12 09:37:53,7 2015-04-12 09:42:53,9 2015-04-12 09:47:53,5 2015-04-12 09:52:53,5 2015-04-12 09:57:53,17 2015-04-12 10:02:53,6 2015-04-12 10:07:53,5 2015-04-12 10:12:53,9 2015-04-12 10:17:53,2 2015-04-12 10:22:53,9 2015-04-12 10:27:53,6 2015-04-12 10:32:53,9 2015-04-12 10:37:53,5 2015-04-12 10:42:53,9 2015-04-12 10:47:53,9 2015-04-12 10:52:53,5 2015-04-12 10:57:53,15 2015-04-12 11:02:53,10 2015-04-12 11:07:53,7 2015-04-12 11:12:53,3 2015-04-12 11:17:53,3 2015-04-12 11:22:53,2 2015-04-12 11:27:53,5 2015-04-12 11:32:53,5 2015-04-12 11:37:53,4 2015-04-12 11:42:53,5 2015-04-12 11:47:53,9 2015-04-12 11:52:53,2 2015-04-12 11:57:53,1 2015-04-12 12:02:53,6 2015-04-12 12:07:53,10 2015-04-12 12:12:53,5 2015-04-12 12:17:53,14 2015-04-12 12:22:53,7 2015-04-12 12:27:53,5 2015-04-12 12:32:53,6 2015-04-12 12:37:53,6 2015-04-12 12:42:53,5 2015-04-12 12:47:53,5 2015-04-12 12:52:53,5 2015-04-12 12:57:53,10 2015-04-12 13:02:53,4 2015-04-12 13:07:53,5 2015-04-12 13:12:53,2 2015-04-12 13:17:53,7 2015-04-12 13:22:53,27 2015-04-12 13:27:53,11 2015-04-12 13:32:53,7 2015-04-12 13:37:53,3 2015-04-12 13:42:53,11 2015-04-12 13:47:53,9 2015-04-12 13:52:53,4 2015-04-12 13:57:53,6 2015-04-12 14:02:53,8 2015-04-12 14:07:53,7 2015-04-12 14:12:53,6 2015-04-12 14:17:53,9 2015-04-12 14:22:53,12 2015-04-12 14:27:53,12 2015-04-12 14:32:53,14 2015-04-12 14:37:53,9 2015-04-12 14:42:53,9 2015-04-12 14:47:53,11 2015-04-12 14:52:53,11 2015-04-12 14:57:53,14 2015-04-12 15:02:53,18 2015-04-12 15:07:53,9 2015-04-12 15:12:53,6 2015-04-12 15:17:53,4 2015-04-12 15:22:53,10 2015-04-12 15:27:53,11 2015-04-12 15:32:53,7 2015-04-12 15:37:53,10 2015-04-12 15:42:53,15 2015-04-12 15:47:53,13 2015-04-12 15:52:53,5 2015-04-12 15:57:53,12 2015-04-12 16:02:53,13 2015-04-12 16:07:53,11 2015-04-12 16:12:53,14 2015-04-12 16:17:53,26 2015-04-12 16:22:53,9 2015-04-12 16:27:53,14 2015-04-12 16:32:53,16 2015-04-12 16:37:53,18 2015-04-12 16:42:53,5 2015-04-12 16:47:53,5 2015-04-12 16:52:53,7 2015-04-12 16:57:53,8 2015-04-12 17:02:53,6 2015-04-12 17:07:53,17 2015-04-12 17:12:53,8 2015-04-12 17:17:53,12 2015-04-12 17:22:53,9 2015-04-12 17:27:53,18 2015-04-12 17:32:53,8 2015-04-12 17:37:53,15 2015-04-12 17:42:53,11 2015-04-12 17:47:53,7 2015-04-12 17:52:53,5 2015-04-12 17:57:53,8 2015-04-12 18:02:53,12 2015-04-12 18:07:53,12 2015-04-12 18:12:53,15 2015-04-12 18:17:53,8 2015-04-12 18:22:53,8 2015-04-12 18:27:53,14 2015-04-12 18:32:53,11 2015-04-12 18:37:53,16 2015-04-12 18:42:53,8 2015-04-12 18:47:53,6 2015-04-12 18:52:53,8 2015-04-12 18:57:53,7 2015-04-12 19:02:53,13 2015-04-12 19:07:53,5 2015-04-12 19:12:53,11 2015-04-12 19:17:53,8 2015-04-12 19:22:53,9 2015-04-12 19:27:53,13 2015-04-12 19:32:53,13 2015-04-12 19:37:53,8 2015-04-12 19:42:53,12 2015-04-12 19:47:53,7 2015-04-12 19:52:53,7 2015-04-12 19:57:53,11 2015-04-12 20:02:53,10 2015-04-12 20:07:53,6 2015-04-12 20:12:53,9 2015-04-12 20:17:53,8 2015-04-12 20:22:53,12 2015-04-12 20:27:53,12 2015-04-12 20:32:53,5 2015-04-12 20:37:53,4 2015-04-12 20:42:53,6 2015-04-12 20:47:53,6 2015-04-12 20:52:53,11 2015-04-12 20:57:53,8 2015-04-12 21:02:53,7 2015-04-12 21:07:53,11 2015-04-12 21:12:53,8 2015-04-12 21:17:53,16 2015-04-12 21:22:53,10 2015-04-12 21:27:53,13 2015-04-12 21:32:53,8 2015-04-12 21:37:53,21 2015-04-12 21:42:53,25 2015-04-12 21:47:53,26 2015-04-12 21:52:53,22 2015-04-12 21:57:53,20 2015-04-12 22:02:53,20 2015-04-12 22:07:53,19 2015-04-12 22:12:53,14 2015-04-12 22:17:53,22 2015-04-12 22:22:53,38 2015-04-12 22:27:53,15 2015-04-12 22:32:53,9 2015-04-12 22:37:53,15 2015-04-12 22:42:53,9 2015-04-12 22:47:53,12 2015-04-12 22:52:53,16 2015-04-12 22:57:53,13 2015-04-12 23:02:53,16 2015-04-12 23:07:53,9 2015-04-12 23:12:53,12 2015-04-12 23:17:53,10 2015-04-12 23:22:53,13 2015-04-12 23:27:53,11 2015-04-12 23:32:53,16 2015-04-12 23:37:53,19 2015-04-12 23:42:53,29 2015-04-12 23:47:53,20 2015-04-12 23:52:53,16 2015-04-12 23:57:53,13 2015-04-13 00:02:53,16 2015-04-13 00:07:53,13 2015-04-13 00:12:53,16 2015-04-13 00:17:53,7 2015-04-13 00:22:53,7 2015-04-13 00:27:53,12 2015-04-13 00:32:53,8 2015-04-13 00:37:53,11 2015-04-13 00:42:53,21 2015-04-13 00:47:53,13 2015-04-13 00:52:53,6 2015-04-13 00:57:53,9 2015-04-13 01:02:53,14 2015-04-13 01:07:53,11 2015-04-13 01:12:53,12 2015-04-13 01:17:53,7 2015-04-13 01:22:53,9 2015-04-13 01:27:53,9 2015-04-13 01:32:53,7 2015-04-13 01:37:53,6 2015-04-13 01:42:53,9 2015-04-13 01:47:53,7 2015-04-13 01:52:53,6 2015-04-13 01:57:53,11 2015-04-13 02:02:53,5 2015-04-13 02:07:53,12 2015-04-13 02:12:53,6 2015-04-13 02:17:53,19 2015-04-13 02:22:53,11 2015-04-13 02:27:53,11 2015-04-13 02:32:53,11 2015-04-13 02:37:53,12 2015-04-13 02:42:53,9 2015-04-13 02:47:53,11 2015-04-13 02:52:53,17 2015-04-13 02:57:53,10 2015-04-13 03:02:53,11 2015-04-13 03:07:53,10 2015-04-13 03:12:53,10 2015-04-13 03:17:53,5 2015-04-13 03:22:53,13 2015-04-13 03:27:53,9 2015-04-13 03:32:53,9 2015-04-13 03:37:53,17 2015-04-13 03:42:53,12 2015-04-13 03:47:53,9 2015-04-13 03:52:53,17 2015-04-13 03:57:53,10 2015-04-13 04:02:53,10 2015-04-13 04:07:53,7 2015-04-13 04:12:53,8 2015-04-13 04:17:53,5 2015-04-13 04:22:53,4 2015-04-13 04:27:53,6 2015-04-13 04:32:53,11 2015-04-13 04:37:53,15 2015-04-13 04:42:53,15 2015-04-13 04:47:53,6 2015-04-13 04:52:53,8 2015-04-13 04:57:53,5 2015-04-13 05:02:53,5 2015-04-13 05:07:53,3 2015-04-13 05:12:53,6 2015-04-13 05:17:53,8 2015-04-13 05:22:53,7 2015-04-13 05:27:53,2 2015-04-13 05:32:53,5 2015-04-13 05:37:53,7 2015-04-13 05:42:53,2 2015-04-13 05:47:53,2 2015-04-13 05:52:53,7 2015-04-13 05:57:53,7 2015-04-13 06:02:53,8 2015-04-13 06:07:53,14 2015-04-13 06:12:53,8 2015-04-13 06:17:53,8 2015-04-13 06:22:53,5 2015-04-13 06:27:53,7 2015-04-13 06:32:53,10 2015-04-13 06:37:53,5 2015-04-13 06:42:53,4 2015-04-13 06:47:53,3 2015-04-13 06:52:53,9 2015-04-13 06:57:53,5 2015-04-13 07:02:53,12 2015-04-13 07:07:53,10 2015-04-13 07:12:53,5 2015-04-13 07:17:53,8 2015-04-13 07:22:53,10 2015-04-13 07:27:53,9 2015-04-13 07:32:53,5 2015-04-13 07:37:53,6 2015-04-13 07:42:53,9 2015-04-13 07:47:53,6 2015-04-13 07:52:53,9 2015-04-13 07:57:53,18 2015-04-13 08:02:53,13 2015-04-13 08:07:53,14 2015-04-13 08:12:53,10 2015-04-13 08:17:53,17 2015-04-13 08:22:53,12 2015-04-13 08:27:53,12 2015-04-13 08:32:53,13 2015-04-13 08:37:53,12 2015-04-13 08:42:53,14 2015-04-13 08:47:53,8 2015-04-13 08:52:53,15 2015-04-13 08:57:53,9 2015-04-13 09:02:53,9 2015-04-13 09:07:53,17 2015-04-13 09:12:53,10 2015-04-13 09:17:53,14 2015-04-13 09:22:53,9 2015-04-13 09:27:53,17 2015-04-13 09:32:53,16 2015-04-13 09:37:53,12 2015-04-13 09:42:53,11 2015-04-13 09:47:53,6 2015-04-13 09:52:53,15 2015-04-13 09:57:53,11 2015-04-13 10:02:53,11 2015-04-13 10:07:53,9 2015-04-13 10:12:53,11 2015-04-13 10:17:53,10 2015-04-13 10:22:53,11 2015-04-13 10:27:53,10 2015-04-13 10:32:53,6 2015-04-13 10:37:53,4 2015-04-13 10:42:53,12 2015-04-13 10:47:53,8 2015-04-13 10:52:53,5 2015-04-13 10:57:53,13 2015-04-13 11:02:53,12 2015-04-13 11:07:53,11 2015-04-13 11:12:53,13 2015-04-13 11:17:53,15 2015-04-13 11:22:53,9 2015-04-13 11:27:53,17 2015-04-13 11:32:53,21 2015-04-13 11:37:53,6 2015-04-13 11:42:53,10 2015-04-13 11:47:53,5 2015-04-13 11:52:53,20 2015-04-13 11:57:53,16 2015-04-13 12:02:53,11 2015-04-13 12:07:53,17 2015-04-13 12:12:53,10 2015-04-13 12:17:53,12 2015-04-13 12:22:53,20 2015-04-13 12:27:53,10 2015-04-13 12:32:53,9 2015-04-13 12:37:53,12 2015-04-13 12:42:53,13 2015-04-13 12:47:53,7 2015-04-13 12:52:53,4 2015-04-13 12:57:53,16 2015-04-13 13:02:53,26 2015-04-13 13:07:53,13 2015-04-13 13:12:53,18 2015-04-13 13:17:53,10 2015-04-13 13:22:53,12 2015-04-13 13:27:53,11 2015-04-13 13:32:53,13 2015-04-13 13:37:53,12 2015-04-13 13:42:53,11 2015-04-13 13:47:53,15 2015-04-13 13:52:53,25 2015-04-13 13:57:53,35 2015-04-13 14:02:53,31 2015-04-13 14:07:53,29 2015-04-13 14:12:53,35 2015-04-13 14:17:53,34 2015-04-13 14:22:53,31 2015-04-13 14:27:53,20 2015-04-13 14:32:53,20 2015-04-13 14:37:53,30 2015-04-13 14:42:53,34 2015-04-13 14:47:53,25 2015-04-13 14:52:53,36 2015-04-13 14:57:53,34 2015-04-13 15:02:53,36 2015-04-13 15:07:53,39 2015-04-13 15:12:53,29 2015-04-13 15:17:53,29 2015-04-13 15:22:53,34 2015-04-13 15:27:53,30 2015-04-13 15:32:53,34 2015-04-13 15:37:53,32 2015-04-13 15:42:53,32 2015-04-13 15:47:53,32 2015-04-13 15:52:53,34 2015-04-13 15:57:53,40 2015-04-13 16:02:53,34 2015-04-13 16:07:53,54 2015-04-13 16:12:53,84 2015-04-13 16:17:53,71 2015-04-13 16:22:53,42 2015-04-13 16:27:53,39 2015-04-13 16:32:53,46 2015-04-13 16:37:53,32 2015-04-13 16:42:53,30 2015-04-13 16:47:53,28 2015-04-13 16:52:53,33 2015-04-13 16:57:53,34 2015-04-13 17:02:53,29 2015-04-13 17:07:53,38 2015-04-13 17:12:53,41 2015-04-13 17:17:53,28 2015-04-13 17:22:53,29 2015-04-13 17:27:53,40 2015-04-13 17:32:53,37 2015-04-13 17:37:53,37 2015-04-13 17:42:53,41 2015-04-13 17:47:53,37 2015-04-13 17:52:53,36 2015-04-13 17:57:53,38 2015-04-13 18:02:53,39 2015-04-13 18:07:53,29 2015-04-13 18:12:53,26 2015-04-13 18:17:53,26 2015-04-13 18:22:53,31 2015-04-13 18:27:53,34 2015-04-13 18:32:53,23 2015-04-13 18:37:53,27 2015-04-13 18:42:53,33 2015-04-13 18:47:53,43 2015-04-13 18:52:53,31 2015-04-13 18:57:53,31 2015-04-13 19:02:53,40 2015-04-13 19:07:53,38 2015-04-13 19:12:53,36 2015-04-13 19:17:53,36 2015-04-13 19:22:53,22 2015-04-13 19:27:53,21 2015-04-13 19:32:53,35 2015-04-13 19:37:53,36 2015-04-13 19:42:53,28 2015-04-13 19:47:53,32 2015-04-13 19:52:53,12 2015-04-13 19:57:53,30 2015-04-13 20:02:53,23 2015-04-13 20:07:53,32 2015-04-13 20:12:53,44 2015-04-13 20:17:53,36 2015-04-13 20:22:53,32 2015-04-13 20:27:53,30 2015-04-13 20:32:53,32 2015-04-13 20:37:53,30 2015-04-13 20:42:53,42 2015-04-13 20:47:53,29 2015-04-13 20:52:53,28 2015-04-13 20:57:53,28 2015-04-13 21:02:53,32 2015-04-13 21:07:53,37 2015-04-13 21:12:53,38 2015-04-13 21:17:53,32 2015-04-13 21:22:53,31 2015-04-13 21:27:53,30 2015-04-13 21:32:53,4 2015-04-13 21:37:53,10 2015-04-13 21:42:53,22 2015-04-13 21:47:53,15 2015-04-13 21:52:53,11 2015-04-13 21:57:53,16 2015-04-13 22:02:53,25 2015-04-13 22:07:53,11 2015-04-13 22:12:53,24 2015-04-13 22:17:53,16 2015-04-13 22:22:53,9 2015-04-13 22:27:53,8 2015-04-13 22:32:53,21 2015-04-13 22:37:53,14 2015-04-13 22:42:53,21 2015-04-13 22:47:53,10 2015-04-13 22:52:53,12 2015-04-13 22:57:53,22 2015-04-13 23:02:53,18 2015-04-13 23:07:53,7 2015-04-13 23:12:53,4 2015-04-13 23:17:53,12 2015-04-13 23:22:53,9 2015-04-13 23:27:53,13 2015-04-13 23:32:53,18 2015-04-13 23:37:53,10 2015-04-13 23:42:53,9 2015-04-13 23:47:53,14 2015-04-13 23:52:53,11 2015-04-13 23:57:53,26 2015-04-14 00:02:53,11 2015-04-14 00:07:53,10 2015-04-14 00:12:53,7 2015-04-14 00:17:53,11 2015-04-14 00:22:53,11 2015-04-14 00:27:53,10 2015-04-14 00:32:53,12 2015-04-14 00:37:53,8 2015-04-14 00:42:53,14 2015-04-14 00:47:53,12 2015-04-14 00:52:53,14 2015-04-14 00:57:53,25 2015-04-14 01:02:53,24 2015-04-14 01:07:53,13 2015-04-14 01:12:53,11 2015-04-14 01:17:53,20 2015-04-14 01:22:53,11 2015-04-14 01:27:53,10 2015-04-14 01:32:53,9 2015-04-14 01:37:53,12 2015-04-14 01:42:53,7 2015-04-14 01:47:53,11 2015-04-14 01:52:53,14 2015-04-14 01:57:53,12 2015-04-14 02:02:53,14 2015-04-14 02:07:53,16 2015-04-14 02:12:53,18 2015-04-14 02:17:53,13 2015-04-14 02:22:53,10 2015-04-14 02:27:53,8 2015-04-14 02:32:53,9 2015-04-14 02:37:53,22 2015-04-14 02:42:53,30 2015-04-14 02:47:53,23 2015-04-14 02:52:53,20 2015-04-14 02:57:53,18 2015-04-14 03:02:53,21 2015-04-14 03:07:53,8 2015-04-14 03:12:53,20 2015-04-14 03:17:53,22 2015-04-14 03:22:53,18 2015-04-14 03:27:53,10 2015-04-14 03:32:53,14 2015-04-14 03:37:53,9 2015-04-14 03:42:53,9 2015-04-14 03:47:53,10 2015-04-14 03:52:53,17 2015-04-14 03:57:53,17 2015-04-14 04:02:53,15 2015-04-14 04:07:53,19 2015-04-14 04:12:53,17 2015-04-14 04:17:53,21 2015-04-14 04:22:53,20 2015-04-14 04:27:53,11 2015-04-14 04:32:53,22 2015-04-14 04:37:53,27 2015-04-14 04:42:53,16 2015-04-14 04:47:53,18 2015-04-14 04:52:53,9 2015-04-14 04:57:53,14 2015-04-14 05:02:53,16 2015-04-14 05:07:53,14 2015-04-14 05:12:53,14 2015-04-14 05:17:53,16 2015-04-14 05:22:53,16 2015-04-14 05:27:53,16 2015-04-14 05:32:53,12 2015-04-14 05:37:53,12 2015-04-14 05:42:53,11 2015-04-14 05:47:53,11 2015-04-14 05:52:53,13 2015-04-14 05:57:53,16 2015-04-14 06:02:53,8 2015-04-14 06:07:53,11 2015-04-14 06:12:53,7 2015-04-14 06:17:53,9 2015-04-14 06:22:53,7 2015-04-14 06:27:53,18 2015-04-14 06:32:53,8 2015-04-14 06:37:53,8 2015-04-14 06:42:53,8 2015-04-14 06:47:53,13 2015-04-14 06:52:53,9 2015-04-14 06:57:53,16 2015-04-14 07:02:53,10 2015-04-14 07:07:53,11 2015-04-14 07:12:53,17 2015-04-14 07:17:53,10 2015-04-14 07:22:53,11 2015-04-14 07:27:53,13 2015-04-14 07:32:53,11 2015-04-14 07:37:53,13 2015-04-14 07:42:53,15 2015-04-14 07:47:53,14 2015-04-14 07:52:53,21 2015-04-14 07:57:53,10 2015-04-14 08:02:53,19 2015-04-14 08:07:53,20 2015-04-14 08:12:53,22 2015-04-14 08:17:53,19 2015-04-14 08:22:53,13 2015-04-14 08:27:53,13 2015-04-14 08:32:53,13 2015-04-14 08:37:53,19 2015-04-14 08:42:53,18 2015-04-14 08:47:53,12 2015-04-14 08:52:53,12 2015-04-14 08:57:53,30 2015-04-14 09:02:53,32 2015-04-14 09:07:53,21 2015-04-14 09:12:53,22 2015-04-14 09:17:53,18 2015-04-14 09:22:53,17 2015-04-14 09:27:53,13 2015-04-14 09:32:53,20 2015-04-14 09:37:53,12 2015-04-14 09:42:53,17 2015-04-14 09:47:53,12 2015-04-14 09:52:53,14 2015-04-14 09:57:53,14 2015-04-14 10:02:53,10 2015-04-14 10:07:53,13 2015-04-14 10:12:53,7 2015-04-14 10:17:53,14 2015-04-14 10:22:53,9 2015-04-14 10:27:53,6 2015-04-14 10:32:53,9 2015-04-14 10:37:53,18 2015-04-14 10:42:53,13 2015-04-14 10:47:53,12 2015-04-14 10:52:53,4 2015-04-14 10:57:53,30 2015-04-14 11:02:53,19 2015-04-14 11:07:53,18 2015-04-14 11:12:53,13 2015-04-14 11:17:53,24 2015-04-14 11:22:53,14 2015-04-14 11:27:53,16 2015-04-14 11:32:53,23 2015-04-14 11:37:53,18 2015-04-14 11:42:53,29 2015-04-14 11:47:53,14 2015-04-14 11:52:53,11 2015-04-14 11:57:53,14 2015-04-14 12:02:53,26 2015-04-14 12:07:53,19 2015-04-14 12:12:53,18 2015-04-14 12:17:53,15 2015-04-14 12:22:53,28 2015-04-14 12:27:53,17 2015-04-14 12:32:53,15 2015-04-14 12:37:53,16 2015-04-14 12:42:53,13 2015-04-14 12:47:53,24 2015-04-14 12:52:53,25 2015-04-14 12:57:53,32 2015-04-14 13:02:53,38 2015-04-14 13:07:53,32 2015-04-14 13:12:53,31 2015-04-14 13:17:53,35 2015-04-14 13:22:53,36 2015-04-14 13:27:53,56 2015-04-14 13:32:53,35 2015-04-14 13:37:53,32 2015-04-14 13:42:53,28 2015-04-14 13:47:53,26 2015-04-14 13:52:53,32 2015-04-14 13:57:53,27 2015-04-14 14:02:53,27 2015-04-14 14:07:53,39 2015-04-14 14:12:53,31 2015-04-14 14:17:53,22 2015-04-14 14:22:53,30 2015-04-14 14:27:53,26 2015-04-14 14:32:53,78 2015-04-14 14:37:53,57 2015-04-14 14:42:53,54 2015-04-14 14:47:53,29 2015-04-14 14:52:53,37 2015-04-14 14:57:53,33 2015-04-14 15:02:53,31 2015-04-14 15:07:53,50 2015-04-14 15:12:53,32 2015-04-14 15:17:53,38 2015-04-14 15:22:53,23 2015-04-14 15:27:53,38 2015-04-14 15:32:53,36 2015-04-14 15:37:53,39 2015-04-14 15:42:53,38 2015-04-14 15:47:53,37 2015-04-14 15:52:53,44 2015-04-14 15:57:53,40 2015-04-14 16:02:53,28 2015-04-14 16:07:53,26 2015-04-14 16:12:53,31 2015-04-14 16:17:53,29 2015-04-14 16:22:53,38 2015-04-14 16:27:53,39 2015-04-14 16:32:53,23 2015-04-14 16:37:53,28 2015-04-14 16:42:53,27 2015-04-14 16:47:53,31 2015-04-14 16:52:53,17 2015-04-14 16:57:53,30 2015-04-14 17:02:53,20 2015-04-14 17:07:53,12 2015-04-14 17:12:53,44 2015-04-14 17:17:53,50 2015-04-14 17:22:53,27 2015-04-14 17:27:53,37 2015-04-14 17:32:53,31 2015-04-14 17:37:53,30 2015-04-14 17:42:53,19 2015-04-14 17:47:53,47 2015-04-14 17:52:53,30 2015-04-14 17:57:53,23 2015-04-14 18:02:53,21 2015-04-14 18:07:53,33 2015-04-14 18:12:53,29 2015-04-14 18:17:53,45 2015-04-14 18:22:53,26 2015-04-14 18:27:53,30 2015-04-14 18:32:53,22 2015-04-14 18:37:53,30 2015-04-14 18:42:53,29 2015-04-14 18:47:53,31 2015-04-14 18:52:53,39 2015-04-14 18:57:53,65 2015-04-14 19:02:53,23 2015-04-14 19:07:53,29 2015-04-14 19:12:53,26 2015-04-14 19:17:53,24 2015-04-14 19:22:53,22 2015-04-14 19:27:53,33 2015-04-14 19:32:53,36 2015-04-14 19:37:53,38 2015-04-14 19:42:53,34 2015-04-14 19:47:53,43 2015-04-14 19:52:53,39 2015-04-14 19:57:53,52 2015-04-14 20:02:53,41 2015-04-14 20:07:53,18 2015-04-14 20:12:53,37 2015-04-14 20:17:53,32 2015-04-14 20:22:53,44 2015-04-14 20:27:53,36 2015-04-14 20:32:53,25 2015-04-14 20:37:53,101 2015-04-14 20:42:53,45 2015-04-14 20:47:53,57 2015-04-14 20:52:53,40 2015-04-14 20:57:53,53 2015-04-14 21:02:53,25 2015-04-14 21:07:53,26 2015-04-14 21:12:53,21 2015-04-14 21:17:53,29 2015-04-14 21:22:53,28 2015-04-14 21:27:53,40 2015-04-14 21:32:53,24 2015-04-14 21:37:53,17 2015-04-14 21:42:53,16 2015-04-14 21:47:53,25 2015-04-14 21:52:53,36 2015-04-14 21:57:53,23 2015-04-14 22:02:53,20 2015-04-14 22:07:53,21 2015-04-14 22:12:53,31 2015-04-14 22:17:53,27 2015-04-14 22:22:53,21 2015-04-14 22:27:53,33 2015-04-14 22:32:53,31 2015-04-14 22:37:53,22 2015-04-14 22:42:53,17 2015-04-14 22:47:53,17 2015-04-14 22:52:53,23 2015-04-14 22:57:53,22 2015-04-14 23:02:53,15 2015-04-14 23:07:53,15 2015-04-14 23:12:53,23 2015-04-14 23:17:53,13 2015-04-14 23:22:53,10 2015-04-14 23:27:53,25 2015-04-14 23:32:53,19 2015-04-14 23:37:53,19 2015-04-14 23:42:53,17 2015-04-14 23:47:53,20 2015-04-14 23:52:53,20 2015-04-14 23:57:53,11 2015-04-15 00:02:53,22 2015-04-15 00:07:53,14 2015-04-15 00:12:53,17 2015-04-15 00:17:53,15 2015-04-15 00:22:53,11 2015-04-15 00:27:53,13 2015-04-15 00:32:53,19 2015-04-15 00:37:53,20 2015-04-15 00:42:53,25 2015-04-15 00:47:53,16 2015-04-15 00:52:53,15 2015-04-15 00:57:53,24 2015-04-15 01:02:53,19 2015-04-15 01:07:53,14 2015-04-15 01:12:53,55 2015-04-15 01:17:53,29 2015-04-15 01:22:53,16 2015-04-15 01:27:53,18 2015-04-15 01:32:53,26 2015-04-15 01:37:53,16 2015-04-15 01:42:53,23 2015-04-15 01:47:53,16 2015-04-15 01:52:53,28 2015-04-15 01:57:53,20 2015-04-15 02:02:53,24 2015-04-15 02:07:53,21 2015-04-15 02:12:53,35 2015-04-15 02:17:53,38 2015-04-15 02:22:53,54 2015-04-15 02:27:53,30 2015-04-15 02:32:53,35 2015-04-15 02:37:53,19 2015-04-15 02:42:53,29 2015-04-15 02:47:53,32 2015-04-15 02:52:53,14 2015-04-15 02:57:53,17 2015-04-15 03:02:53,26 2015-04-15 03:07:53,18 2015-04-15 03:12:53,19 2015-04-15 03:17:53,9 2015-04-15 03:22:53,15 2015-04-15 03:27:53,11 2015-04-15 03:32:53,21 2015-04-15 03:37:53,13 2015-04-15 03:42:53,12 2015-04-15 03:47:53,17 2015-04-15 03:52:53,22 2015-04-15 03:57:53,16 2015-04-15 04:02:53,18 2015-04-15 04:07:53,13 2015-04-15 04:12:53,16 2015-04-15 04:17:53,21 2015-04-15 04:22:53,27 2015-04-15 04:27:53,17 2015-04-15 04:32:53,8 2015-04-15 04:37:53,11 2015-04-15 04:42:53,22 2015-04-15 04:47:53,9 2015-04-15 04:52:53,14 2015-04-15 04:57:53,16 2015-04-15 05:02:53,13 2015-04-15 05:07:53,20 2015-04-15 05:12:53,5 2015-04-15 05:17:53,15 2015-04-15 05:22:53,18 2015-04-15 05:27:53,20 2015-04-15 05:32:53,10 2015-04-15 05:37:53,17 2015-04-15 05:42:53,15 2015-04-15 05:47:53,8 2015-04-15 05:52:53,16 2015-04-15 05:57:53,47 2015-04-15 06:02:53,31 2015-04-15 06:07:53,17 2015-04-15 06:12:53,21 2015-04-15 06:17:53,24 2015-04-15 06:22:53,16 2015-04-15 06:27:53,29 2015-04-15 06:32:53,10 2015-04-15 06:37:53,22 2015-04-15 06:42:53,37 2015-04-15 06:47:53,16 2015-04-15 06:52:53,22 2015-04-15 06:57:53,19 2015-04-15 07:02:53,15 2015-04-15 07:07:53,18 2015-04-15 07:12:53,26 2015-04-15 07:17:53,23 2015-04-15 07:22:53,25 2015-04-15 07:27:53,17 2015-04-15 07:32:53,16 2015-04-15 07:37:53,14 2015-04-15 07:42:53,12 2015-04-15 07:47:53,27 2015-04-15 07:52:53,10 2015-04-15 07:57:53,11 2015-04-15 08:02:53,12 2015-04-15 08:07:53,12 2015-04-15 08:12:53,18 2015-04-15 08:17:53,25 2015-04-15 08:22:53,14 2015-04-15 08:27:53,12 2015-04-15 08:32:53,19 2015-04-15 08:37:53,19 2015-04-15 08:42:53,14 2015-04-15 08:47:53,19 2015-04-15 08:52:53,16 2015-04-15 08:57:53,22 2015-04-15 09:02:53,18 2015-04-15 09:07:53,21 2015-04-15 09:12:53,17 2015-04-15 09:17:53,27 2015-04-15 09:22:53,13 2015-04-15 09:27:53,15 2015-04-15 09:32:53,18 2015-04-15 09:37:53,18 2015-04-15 09:42:53,15 2015-04-15 09:47:53,18 2015-04-15 09:52:53,20 2015-04-15 09:57:53,14 2015-04-15 10:02:53,42 2015-04-15 10:07:53,92 2015-04-15 10:12:53,61 2015-04-15 10:17:53,35 2015-04-15 10:22:53,64 2015-04-15 10:27:53,87 2015-04-15 10:32:53,71 2015-04-15 10:37:53,60 2015-04-15 10:42:53,60 2015-04-15 10:47:53,40 2015-04-15 10:52:53,47 2015-04-15 10:57:53,36 2015-04-15 11:02:53,41 2015-04-15 11:07:53,46 2015-04-15 11:12:53,53 2015-04-15 11:17:53,60 2015-04-15 11:22:53,55 2015-04-15 11:27:53,32 2015-04-15 11:32:53,71 2015-04-15 11:37:53,58 2015-04-15 11:42:53,36 2015-04-15 11:47:53,26 2015-04-15 11:52:53,43 2015-04-15 11:57:53,47 2015-04-15 12:02:53,37 2015-04-15 12:07:53,35 2015-04-15 12:12:53,36 2015-04-15 12:17:53,24 2015-04-15 12:22:53,41 2015-04-15 12:27:53,40 2015-04-15 12:32:53,36 2015-04-15 12:37:53,38 2015-04-15 12:42:53,37 2015-04-15 12:47:53,38 2015-04-15 12:52:53,34 2015-04-15 12:57:53,44 2015-04-15 13:02:53,26 2015-04-15 13:07:53,34 2015-04-15 13:12:53,53 2015-04-15 13:17:53,38 2015-04-15 13:22:53,38 2015-04-15 13:27:53,37 2015-04-15 13:32:53,60 2015-04-15 13:37:53,43 2015-04-15 13:42:53,30 2015-04-15 13:47:53,26 2015-04-15 13:52:53,40 2015-04-15 13:57:53,62 2015-04-15 14:02:53,54 2015-04-15 14:07:53,69 2015-04-15 14:12:53,48 2015-04-15 14:17:53,48 2015-04-15 14:22:53,60 2015-04-15 14:27:53,47 2015-04-15 14:32:53,43 2015-04-15 14:37:53,36 2015-04-15 14:42:53,61 2015-04-15 14:47:53,59 2015-04-15 14:52:53,56 2015-04-15 14:57:53,52 2015-04-15 15:02:53,46 2015-04-15 15:07:53,29 2015-04-15 15:12:53,48 2015-04-15 15:17:53,41 2015-04-15 15:22:53,34 2015-04-15 15:27:53,55 2015-04-15 15:32:53,49 2015-04-15 15:37:53,39 2015-04-15 15:42:53,36 2015-04-15 15:47:53,54 2015-04-15 15:52:53,43 2015-04-15 15:57:53,67 2015-04-15 16:02:53,62 2015-04-15 16:07:53,44 2015-04-15 16:12:53,44 2015-04-15 16:17:53,52 2015-04-15 16:22:53,57 2015-04-15 16:27:53,39 2015-04-15 16:32:53,38 2015-04-15 16:37:53,38 2015-04-15 16:42:53,32 2015-04-15 16:47:53,26 2015-04-15 16:52:53,29 2015-04-15 16:57:53,61 2015-04-15 17:02:53,42 2015-04-15 17:07:53,38 2015-04-15 17:12:53,41 2015-04-15 17:17:53,30 2015-04-15 17:22:53,23 2015-04-15 17:27:53,35 2015-04-15 17:32:53,24 2015-04-15 17:37:53,36 2015-04-15 17:42:53,23 2015-04-15 17:47:53,27 2015-04-15 17:52:53,30 2015-04-15 17:57:53,59 2015-04-15 18:02:53,40 2015-04-15 18:07:53,26 2015-04-15 18:12:53,30 2015-04-15 18:17:53,28 2015-04-15 18:22:53,31 2015-04-15 18:27:53,39 2015-04-15 18:32:53,24 2015-04-15 18:37:53,31 2015-04-15 18:42:53,29 2015-04-15 18:47:53,30 2015-04-15 18:52:53,28 2015-04-15 18:57:53,33 2015-04-15 19:02:53,23 2015-04-15 19:07:53,26 2015-04-15 19:12:53,20 2015-04-15 19:17:53,31 2015-04-15 19:22:53,14 2015-04-15 19:27:53,18 2015-04-15 19:32:53,31 2015-04-15 19:37:53,17 2015-04-15 19:42:53,23 2015-04-15 19:47:53,30 2015-04-15 19:52:53,24 2015-04-15 19:57:53,44 2015-04-15 20:02:53,35 2015-04-15 20:07:53,27 2015-04-15 20:12:53,24 2015-04-15 20:17:53,25 2015-04-15 20:22:53,30 2015-04-15 20:27:53,23 2015-04-15 20:32:53,25 2015-04-15 20:37:53,31 2015-04-15 20:42:53,21 2015-04-15 20:47:53,33 2015-04-15 20:52:53,37 2015-04-15 20:57:53,27 2015-04-15 21:02:53,22 2015-04-15 21:07:53,39 2015-04-15 21:12:53,39 2015-04-15 21:17:53,52 2015-04-15 21:22:53,42 2015-04-15 21:27:53,32 2015-04-15 21:32:53,32 2015-04-15 21:37:53,25 2015-04-15 21:42:53,29 2015-04-15 21:47:53,26 2015-04-15 21:52:53,22 2015-04-15 21:57:53,28 2015-04-15 22:02:53,26 2015-04-15 22:07:53,25 2015-04-15 22:12:53,19 2015-04-15 22:17:53,26 2015-04-15 22:22:53,13 2015-04-15 22:27:53,30 2015-04-15 22:32:53,27 2015-04-15 22:37:53,25 2015-04-15 22:42:53,14 2015-04-15 22:47:53,14 2015-04-15 22:52:53,17 2015-04-15 22:57:53,23 2015-04-15 23:02:53,21 2015-04-15 23:07:53,14 2015-04-15 23:12:53,20 2015-04-15 23:17:53,26 2015-04-15 23:22:53,17 2015-04-15 23:27:53,20 2015-04-15 23:32:53,13 2015-04-15 23:37:53,23 2015-04-15 23:42:53,24 2015-04-15 23:47:53,34 2015-04-15 23:52:53,22 2015-04-15 23:57:53,15 2015-04-16 00:02:53,22 2015-04-16 00:07:53,17 2015-04-16 00:12:53,20 2015-04-16 00:17:53,16 2015-04-16 00:22:53,24 2015-04-16 00:27:53,12 2015-04-16 00:32:53,15 2015-04-16 00:37:53,22 2015-04-16 00:42:53,16 2015-04-16 00:47:53,15 2015-04-16 00:52:53,8 2015-04-16 00:57:53,33 2015-04-16 01:02:53,17 2015-04-16 01:07:53,18 2015-04-16 01:12:53,10 2015-04-16 01:17:53,16 2015-04-16 01:22:53,14 2015-04-16 01:27:53,7 2015-04-16 01:32:53,17 2015-04-16 01:37:53,8 2015-04-16 01:42:53,11 2015-04-16 01:47:53,10 2015-04-16 01:52:53,20 2015-04-16 01:57:53,35 2015-04-16 02:02:53,20 2015-04-16 02:07:53,8 2015-04-16 02:12:53,21 2015-04-16 02:17:53,15 2015-04-16 02:22:53,20 2015-04-16 02:27:53,20 2015-04-16 02:32:53,14 2015-04-16 02:37:53,20 2015-04-16 02:42:53,24 2015-04-16 02:47:53,17 2015-04-16 02:52:53,13 2015-04-16 02:57:53,23 2015-04-16 03:02:53,21 2015-04-16 03:07:53,11 2015-04-16 03:12:53,10 2015-04-16 03:17:53,13 2015-04-16 03:22:53,17 2015-04-16 03:27:53,19 2015-04-16 03:32:53,9 2015-04-16 03:37:53,17 2015-04-16 03:42:53,10 2015-04-16 03:47:53,8 2015-04-16 03:52:53,12 2015-04-16 03:57:53,15 2015-04-16 04:02:53,13 2015-04-16 04:07:53,10 2015-04-16 04:12:53,7 2015-04-16 04:17:53,9 2015-04-16 04:22:53,9 2015-04-16 04:27:53,11 2015-04-16 04:32:53,19 2015-04-16 04:37:53,9 2015-04-16 04:42:53,8 2015-04-16 04:47:53,10 2015-04-16 04:52:53,8 2015-04-16 04:57:53,13 2015-04-16 05:02:53,8 2015-04-16 05:07:53,17 2015-04-16 05:12:53,5 2015-04-16 05:17:53,14 2015-04-16 05:22:53,12 2015-04-16 05:27:53,12 2015-04-16 05:32:53,9 2015-04-16 05:37:53,15 2015-04-16 05:42:53,24 2015-04-16 05:47:53,18 2015-04-16 05:52:53,23 2015-04-16 05:57:53,19 2015-04-16 06:02:53,14 2015-04-16 06:07:53,16 2015-04-16 06:12:53,28 2015-04-16 06:17:53,22 2015-04-16 06:22:53,23 2015-04-16 06:27:53,26 2015-04-16 06:32:53,19 2015-04-16 06:37:53,22 2015-04-16 06:42:53,20 2015-04-16 06:47:53,21 2015-04-16 06:52:53,23 2015-04-16 06:57:53,15 2015-04-16 07:02:53,16 2015-04-16 07:07:53,17 2015-04-16 07:12:53,14 2015-04-16 07:17:53,13 2015-04-16 07:22:53,14 2015-04-16 07:27:53,10 2015-04-16 07:32:53,17 2015-04-16 07:37:53,12 2015-04-16 07:42:53,22 2015-04-16 07:47:53,19 2015-04-16 07:52:53,15 2015-04-16 07:57:53,18 2015-04-16 08:02:53,12 2015-04-16 08:07:53,17 2015-04-16 08:12:53,16 2015-04-16 08:17:53,22 2015-04-16 08:22:53,15 2015-04-16 08:27:53,18 2015-04-16 08:32:53,12 2015-04-16 08:37:53,18 2015-04-16 08:42:53,16 2015-04-16 08:47:53,18 2015-04-16 08:52:53,11 2015-04-16 08:57:53,13 2015-04-16 09:02:53,13 2015-04-16 09:07:53,11 2015-04-16 09:12:53,13 2015-04-16 09:17:53,14 2015-04-16 09:22:53,17 2015-04-16 09:27:53,29 2015-04-16 09:32:53,23 2015-04-16 09:37:53,25 2015-04-16 09:42:53,11 2015-04-16 09:47:53,25 2015-04-16 09:52:53,21 2015-04-16 09:57:53,20 2015-04-16 10:02:53,15 2015-04-16 10:07:53,18 2015-04-16 10:12:53,30 2015-04-16 10:17:53,13 2015-04-16 10:22:53,16 2015-04-16 10:27:53,19 2015-04-16 10:32:53,27 2015-04-16 10:37:53,24 2015-04-16 10:42:53,18 2015-04-16 10:47:53,12 2015-04-16 10:52:53,24 2015-04-16 10:57:53,19 2015-04-16 11:02:53,29 2015-04-16 11:07:53,31 2015-04-16 11:12:53,18 2015-04-16 11:17:53,19 2015-04-16 11:22:53,11 2015-04-16 11:27:53,20 2015-04-16 11:32:53,12 2015-04-16 11:37:53,14 2015-04-16 11:42:53,12 2015-04-16 11:47:53,11 2015-04-16 11:52:53,10 2015-04-16 11:57:53,24 2015-04-16 12:02:53,22 2015-04-16 12:07:53,23 2015-04-16 12:12:53,21 2015-04-16 12:17:53,13 2015-04-16 12:22:53,20 2015-04-16 12:27:53,24 2015-04-16 12:32:53,9 2015-04-16 12:37:53,15 2015-04-16 12:42:53,24 2015-04-16 12:47:53,22 2015-04-16 12:52:53,17 2015-04-16 12:57:53,31 2015-04-16 13:02:53,39 2015-04-16 13:07:53,18 2015-04-16 13:12:53,41 2015-04-16 13:17:53,35 2015-04-16 13:22:53,44 2015-04-16 13:27:53,32 2015-04-16 13:32:53,34 2015-04-16 13:37:53,28 2015-04-16 13:42:53,34 2015-04-16 13:47:53,44 2015-04-16 13:52:53,40 2015-04-16 13:57:53,31 2015-04-16 14:02:53,43 2015-04-16 14:07:53,27 2015-04-16 14:12:53,33 2015-04-16 14:17:53,40 2015-04-16 14:22:53,34 2015-04-16 14:27:53,22 2015-04-16 14:32:53,30 2015-04-16 14:37:53,30 2015-04-16 14:42:53,26 2015-04-16 14:47:53,40 2015-04-16 14:52:53,34 2015-04-16 14:57:53,27 2015-04-16 15:02:53,29 2015-04-16 15:07:53,21 2015-04-16 15:12:53,22 2015-04-16 15:17:53,21 2015-04-16 15:22:53,36 2015-04-16 15:27:53,26 2015-04-16 15:32:53,19 2015-04-16 15:37:53,24 2015-04-16 15:42:53,30 2015-04-16 15:47:53,29 2015-04-16 15:52:53,17 2015-04-16 15:57:53,41 2015-04-16 16:02:53,20 2015-04-16 16:07:53,28 2015-04-16 16:12:53,36 2015-04-16 16:17:53,30 2015-04-16 16:22:53,42 2015-04-16 16:27:53,29 2015-04-16 16:32:53,24 2015-04-16 16:37:53,23 2015-04-16 16:42:53,27 2015-04-16 16:47:53,23 2015-04-16 16:52:53,27 2015-04-16 16:57:53,28 2015-04-16 17:02:53,26 2015-04-16 17:07:53,37 2015-04-16 17:12:53,42 2015-04-16 17:17:53,31 2015-04-16 17:22:53,27 2015-04-16 17:27:53,34 2015-04-16 17:32:53,22 2015-04-16 17:37:53,38 2015-04-16 17:42:53,24 2015-04-16 17:47:53,26 2015-04-16 17:52:53,25 2015-04-16 17:57:53,32 2015-04-16 18:02:53,31 2015-04-16 18:07:53,30 2015-04-16 18:12:53,24 2015-04-16 18:17:53,29 2015-04-16 18:22:53,35 2015-04-16 18:27:53,36 2015-04-16 18:32:53,20 2015-04-16 18:37:53,22 2015-04-16 18:42:53,36 2015-04-16 18:47:53,43 2015-04-16 18:52:53,39 2015-04-16 18:57:53,46 2015-04-16 19:02:53,23 2015-04-16 19:07:53,23 2015-04-16 19:12:53,30 2015-04-16 19:17:53,25 2015-04-16 19:22:53,26 2015-04-16 19:27:53,17 2015-04-16 19:32:53,14 2015-04-16 19:37:53,15 2015-04-16 19:42:53,53 2015-04-16 19:47:53,28 2015-04-16 19:52:53,29 2015-04-16 19:57:53,40 2015-04-16 20:02:53,34 2015-04-16 20:07:53,18 2015-04-16 20:12:53,22 2015-04-16 20:17:53,23 2015-04-16 20:22:53,31 2015-04-16 20:27:53,21 2015-04-16 20:32:53,21 2015-04-16 20:37:53,26 2015-04-16 20:42:53,29 2015-04-16 20:47:53,26 2015-04-16 20:52:53,21 2015-04-16 20:57:53,25 2015-04-16 21:02:53,86 2015-04-16 21:07:53,76 2015-04-16 21:12:53,43 2015-04-16 21:17:53,43 2015-04-16 21:22:53,62 2015-04-16 21:27:53,41 2015-04-16 21:32:53,36 2015-04-16 21:37:53,46 2015-04-16 21:42:53,28 2015-04-16 21:47:53,25 2015-04-16 21:52:53,20 2015-04-16 21:57:53,30 2015-04-16 22:02:53,44 2015-04-16 22:07:53,21 2015-04-16 22:12:53,18 2015-04-16 22:17:53,27 2015-04-16 22:22:53,25 2015-04-16 22:27:53,18 2015-04-16 22:32:53,42 2015-04-16 22:37:53,30 2015-04-16 22:42:53,28 2015-04-16 22:47:53,22 2015-04-16 22:52:53,26 2015-04-16 22:57:53,29 2015-04-16 23:02:53,18 2015-04-16 23:07:53,18 2015-04-16 23:12:53,20 2015-04-16 23:17:53,30 2015-04-16 23:22:53,16 2015-04-16 23:27:53,25 2015-04-16 23:32:53,19 2015-04-16 23:37:53,15 2015-04-16 23:42:53,19 2015-04-16 23:47:53,21 2015-04-16 23:52:53,25 2015-04-16 23:57:53,20 2015-04-17 00:02:53,23 2015-04-17 00:07:53,21 2015-04-17 00:12:53,17 2015-04-17 00:17:53,17 2015-04-17 00:22:53,24 2015-04-17 00:27:53,22 2015-04-17 00:32:53,28 2015-04-17 00:37:53,14 2015-04-17 00:42:53,11 2015-04-17 00:47:53,8 2015-04-17 00:52:53,25 2015-04-17 00:57:53,22 2015-04-17 01:02:53,22 2015-04-17 01:07:53,14 2015-04-17 01:12:53,14 2015-04-17 01:17:53,14 2015-04-17 01:22:53,13 2015-04-17 01:27:53,14 2015-04-17 01:32:53,14 2015-04-17 01:37:53,19 2015-04-17 01:42:53,15 2015-04-17 01:47:53,20 2015-04-17 01:52:53,14 2015-04-17 01:57:53,26 2015-04-17 02:02:53,13 2015-04-17 02:07:53,16 2015-04-17 02:12:53,20 2015-04-17 02:17:53,24 2015-04-17 02:22:53,17 2015-04-17 02:27:53,14 2015-04-17 02:32:53,12 2015-04-17 02:37:53,15 2015-04-17 02:42:53,15 2015-04-17 02:47:53,14 2015-04-17 02:52:53,12 2015-04-17 02:57:53,17 2015-04-17 03:02:53,18 2015-04-17 03:07:53,9 2015-04-17 03:12:53,7 2015-04-17 03:17:53,9 2015-04-17 03:22:53,9 2015-04-17 03:27:53,20 2015-04-17 03:32:53,11 2015-04-17 03:37:53,10 2015-04-17 03:42:53,11 2015-04-17 03:47:53,15 2015-04-17 03:52:53,8 2015-04-17 03:57:53,31 2015-04-17 04:02:53,24 2015-04-17 04:07:53,12 2015-04-17 04:12:53,14 2015-04-17 04:17:53,6 2015-04-17 04:22:53,27 2015-04-17 04:27:53,31 2015-04-17 04:32:53,25 2015-04-17 04:37:53,12 2015-04-17 04:42:53,15 2015-04-17 04:47:53,18 2015-04-17 04:52:53,14 2015-04-17 04:57:53,25 2015-04-17 05:02:53,13 2015-04-17 05:07:53,16 2015-04-17 05:12:53,14 2015-04-17 05:17:53,9 2015-04-17 05:22:53,13 2015-04-17 05:27:53,13 2015-04-17 05:32:53,9 2015-04-17 05:37:53,16 2015-04-17 05:42:53,17 2015-04-17 05:47:53,10 2015-04-17 05:52:53,9 2015-04-17 05:57:53,15 2015-04-17 06:02:53,12 2015-04-17 06:07:53,16 2015-04-17 06:12:53,7 2015-04-17 06:17:53,35 2015-04-17 06:22:53,17 2015-04-17 06:27:53,15 2015-04-17 06:32:53,22 2015-04-17 06:37:53,14 2015-04-17 06:42:53,14 2015-04-17 06:47:53,9 2015-04-17 06:52:53,13 2015-04-17 06:57:53,10 2015-04-17 07:02:53,16 2015-04-17 07:07:53,26 2015-04-17 07:12:53,8 2015-04-17 07:17:53,10 2015-04-17 07:22:53,15 2015-04-17 07:27:53,22 2015-04-17 07:32:53,21 2015-04-17 07:37:53,14 2015-04-17 07:42:53,22 2015-04-17 07:47:53,16 2015-04-17 07:52:53,22 2015-04-17 07:57:53,10 2015-04-17 08:02:53,21 2015-04-17 08:07:53,10 2015-04-17 08:12:53,12 2015-04-17 08:17:53,12 2015-04-17 08:22:53,22 2015-04-17 08:27:53,10 2015-04-17 08:32:53,12 2015-04-17 08:37:53,20 2015-04-17 08:42:53,10 2015-04-17 08:47:53,132 2015-04-17 08:52:53,6 2015-04-17 08:57:53,20 2015-04-17 09:02:53,10 2015-04-17 09:07:53,24 2015-04-17 09:12:53,14 2015-04-17 09:17:53,15 2015-04-17 09:22:53,13 2015-04-17 09:27:53,19 2015-04-17 09:32:53,11 2015-04-17 09:37:53,10 2015-04-17 09:42:53,10 2015-04-17 09:47:53,130 2015-04-17 09:52:53,15 2015-04-17 09:57:53,17 2015-04-17 10:02:53,13 2015-04-17 10:07:53,21 2015-04-17 10:12:53,16 2015-04-17 10:17:53,9 2015-04-17 10:22:53,8 2015-04-17 10:27:53,13 2015-04-17 10:32:53,11 2015-04-17 10:37:53,15 2015-04-17 10:42:53,18 2015-04-17 10:47:53,11 2015-04-17 10:52:53,11 2015-04-17 10:57:53,22 2015-04-17 11:02:53,20 2015-04-17 11:07:53,30 2015-04-17 11:12:53,18 2015-04-17 11:17:53,18 2015-04-17 11:22:53,14 2015-04-17 11:27:53,25 2015-04-17 11:32:53,12 2015-04-17 11:37:53,6 2015-04-17 11:42:53,15 2015-04-17 11:47:53,8 2015-04-17 11:52:53,13 2015-04-17 11:57:53,19 2015-04-17 12:02:53,20 2015-04-17 12:07:53,11 2015-04-17 12:12:53,18 2015-04-17 12:17:53,19 2015-04-17 12:22:53,8 2015-04-17 12:27:53,19 2015-04-17 12:32:53,18 2015-04-17 12:37:53,17 2015-04-17 12:42:53,26 2015-04-17 12:47:53,25 2015-04-17 12:52:53,24 2015-04-17 12:57:53,29 2015-04-17 13:02:53,36 2015-04-17 13:07:53,30 2015-04-17 13:12:53,22 2015-04-17 13:17:53,14 2015-04-17 13:22:53,20 2015-04-17 13:27:53,14 2015-04-17 13:32:53,22 2015-04-17 13:37:53,22 2015-04-17 13:42:53,23 2015-04-17 13:47:53,24 2015-04-17 13:52:53,27 2015-04-17 13:57:53,20 2015-04-17 14:02:53,25 2015-04-17 14:07:53,36 2015-04-17 14:12:53,27 2015-04-17 14:17:53,26 2015-04-17 14:22:53,23 2015-04-17 14:27:53,32 2015-04-17 14:32:53,26 2015-04-17 14:37:53,23 2015-04-17 14:42:53,33 2015-04-17 14:47:53,33 2015-04-17 14:52:53,29 2015-04-17 14:57:53,31 2015-04-17 15:02:53,27 2015-04-17 15:07:53,25 2015-04-17 15:12:53,28 2015-04-17 15:17:53,27 2015-04-17 15:22:53,26 2015-04-17 15:27:53,42 2015-04-17 15:32:53,37 2015-04-17 15:37:53,37 2015-04-17 15:42:53,30 2015-04-17 15:47:53,31 2015-04-17 15:52:53,28 2015-04-17 15:57:53,37 2015-04-17 16:02:53,36 2015-04-17 16:07:53,14 2015-04-17 16:12:53,21 2015-04-17 16:17:53,18 2015-04-17 16:22:53,17 2015-04-17 16:27:53,26 2015-04-17 16:32:53,18 2015-04-17 16:37:53,22 2015-04-17 16:42:53,9 2015-04-17 16:47:53,23 2015-04-17 16:52:53,22 2015-04-17 16:57:53,31 2015-04-17 17:02:53,19 2015-04-17 17:07:53,17 2015-04-17 17:12:53,15 2015-04-17 17:17:53,33 2015-04-17 17:22:53,18 2015-04-17 17:27:53,26 2015-04-17 17:32:53,19 2015-04-17 17:37:53,47 2015-04-17 17:42:53,26 2015-04-17 17:47:53,19 2015-04-17 17:52:53,27 2015-04-17 17:57:53,23 2015-04-17 18:02:53,28 2015-04-17 18:07:53,21 2015-04-17 18:12:53,22 2015-04-17 18:17:53,31 2015-04-17 18:22:53,26 2015-04-17 18:27:53,37 2015-04-17 18:32:53,19 2015-04-17 18:37:53,5 2015-04-17 18:42:53,32 2015-04-17 18:47:53,42 2015-04-17 18:52:53,28 2015-04-17 18:57:53,25 2015-04-17 19:02:53,28 2015-04-17 19:07:53,26 2015-04-17 19:12:53,25 2015-04-17 19:17:53,24 2015-04-17 19:22:53,15 2015-04-17 19:27:53,14 2015-04-17 19:32:53,22 2015-04-17 19:37:53,22 2015-04-17 19:42:53,28 2015-04-17 19:47:53,45 2015-04-17 19:52:53,38 2015-04-17 19:57:53,40 2015-04-17 20:02:53,27 2015-04-17 20:07:53,22 2015-04-17 20:12:53,23 2015-04-17 20:17:53,21 2015-04-17 20:22:53,18 2015-04-17 20:27:53,29 2015-04-17 20:32:53,12 2015-04-17 20:37:53,26 2015-04-17 20:42:53,11 2015-04-17 20:47:53,15 2015-04-17 20:52:53,33 2015-04-17 20:57:53,19 2015-04-17 21:02:53,12 2015-04-17 21:07:53,21 2015-04-17 21:12:53,21 2015-04-17 21:17:53,12 2015-04-17 21:22:53,16 2015-04-17 21:27:53,13 2015-04-17 21:32:53,9 2015-04-17 21:37:53,14 2015-04-17 21:42:53,20 2015-04-17 21:47:53,13 2015-04-17 21:52:53,11 2015-04-17 21:57:53,16 2015-04-17 22:02:53,17 2015-04-17 22:07:53,18 2015-04-17 22:12:53,24 2015-04-17 22:17:53,8 2015-04-17 22:22:53,10 2015-04-17 22:27:53,15 2015-04-17 22:32:53,15 2015-04-17 22:37:53,9 2015-04-17 22:42:53,4 2015-04-17 22:47:53,18 2015-04-17 22:52:53,9 2015-04-17 22:57:53,17 2015-04-17 23:02:53,19 2015-04-17 23:07:53,10 2015-04-17 23:12:53,5 2015-04-17 23:17:53,9 2015-04-17 23:22:53,3 2015-04-17 23:27:53,20 2015-04-17 23:32:53,14 2015-04-17 23:37:53,17 2015-04-17 23:42:53,15 2015-04-17 23:47:53,19 2015-04-17 23:52:53,10 2015-04-17 23:57:53,23 2015-04-18 00:02:53,15 2015-04-18 00:07:53,11 2015-04-18 00:12:53,9 2015-04-18 00:17:53,13 2015-04-18 00:22:53,14 2015-04-18 00:27:53,13 2015-04-18 00:32:53,13 2015-04-18 00:37:53,10 2015-04-18 00:42:53,13 2015-04-18 00:47:53,7 2015-04-18 00:52:53,11 2015-04-18 00:57:53,25 2015-04-18 01:02:53,13 2015-04-18 01:07:53,12 2015-04-18 01:12:53,15 2015-04-18 01:17:53,11 2015-04-18 01:22:53,11 2015-04-18 01:27:53,8 2015-04-18 01:32:53,14 2015-04-18 01:37:53,12 2015-04-18 01:42:53,10 2015-04-18 01:47:53,8 2015-04-18 01:52:53,19 2015-04-18 01:57:53,10 2015-04-18 02:02:53,15 2015-04-18 02:07:53,14 2015-04-18 02:12:53,13 2015-04-18 02:17:53,10 2015-04-18 02:22:53,12 2015-04-18 02:27:53,6 2015-04-18 02:32:53,8 2015-04-18 02:37:53,12 2015-04-18 02:42:53,9 2015-04-18 02:47:53,10 2015-04-18 02:52:53,14 2015-04-18 02:57:53,7 2015-04-18 03:02:53,19 2015-04-18 03:07:53,8 2015-04-18 03:12:53,3 2015-04-18 03:17:53,8 2015-04-18 03:22:53,3 2015-04-18 03:27:53,19 2015-04-18 03:32:53,8 2015-04-18 03:37:53,9 2015-04-18 03:42:53,12 2015-04-18 03:47:53,12 2015-04-18 03:52:53,9 2015-04-18 03:57:53,12 2015-04-18 04:02:53,19 2015-04-18 04:07:53,18 2015-04-18 04:12:53,15 2015-04-18 04:17:53,9 2015-04-18 04:22:53,8 2015-04-18 04:27:53,14 2015-04-18 04:32:53,5 2015-04-18 04:37:53,8 2015-04-18 04:42:53,10 2015-04-18 04:47:53,7 2015-04-18 04:52:53,5 2015-04-18 04:57:53,9 2015-04-18 05:02:53,16 2015-04-18 05:07:53,13 2015-04-18 05:12:53,13 2015-04-18 05:17:53,9 2015-04-18 05:22:53,5 2015-04-18 05:27:53,14 2015-04-18 05:32:53,7 2015-04-18 05:37:53,10 2015-04-18 05:42:53,9 2015-04-18 05:47:53,12 2015-04-18 05:52:53,10 2015-04-18 05:57:53,19 2015-04-18 06:02:53,14 2015-04-18 06:07:53,5 2015-04-18 06:12:53,7 2015-04-18 06:17:53,7 2015-04-18 06:22:53,8 2015-04-18 06:27:53,8 2015-04-18 06:32:53,10 2015-04-18 06:37:53,9 2015-04-18 06:42:53,4 2015-04-18 06:47:53,5 2015-04-18 06:52:53,5 2015-04-18 06:57:53,4 2015-04-18 07:02:53,3 2015-04-18 07:07:53,4 2015-04-18 07:12:53,9 2015-04-18 07:17:53,4 2015-04-18 07:22:53,1 2015-04-18 07:27:53,5 2015-04-18 07:32:53,4 2015-04-18 07:37:53,15 2015-04-18 07:42:53,5 2015-04-18 07:47:53,7 2015-04-18 07:52:53,9 2015-04-18 07:57:53,7 2015-04-18 08:02:53,12 2015-04-18 08:07:53,7 2015-04-18 08:12:53,6 2015-04-18 08:17:53,5 2015-04-18 08:22:53,7 2015-04-18 08:27:53,7 2015-04-18 08:32:53,4 2015-04-18 08:37:53,12 2015-04-18 08:42:53,7 2015-04-18 08:47:53,5 2015-04-18 08:52:53,10 2015-04-18 08:57:53,19 2015-04-18 09:02:53,6 2015-04-18 09:07:53,8 2015-04-18 09:12:53,4 2015-04-18 09:17:53,6 2015-04-18 09:22:53,5 2015-04-18 09:27:53,10 2015-04-18 09:32:53,8 2015-04-18 09:37:53,6 2015-04-18 09:42:53,9 2015-04-18 09:47:53,6 2015-04-18 09:52:53,5 2015-04-18 09:57:53,13 2015-04-18 10:02:53,15 2015-04-18 10:07:53,5 2015-04-18 10:12:53,4 2015-04-18 10:17:53,16 2015-04-18 10:22:53,9 2015-04-18 10:27:53,17 2015-04-18 10:32:53,7 2015-04-18 10:37:53,8 2015-04-18 10:42:53,9 2015-04-18 10:47:53,5 2015-04-18 10:52:53,6 2015-04-18 10:57:53,9 2015-04-18 11:02:53,2 2015-04-18 11:07:53,10 2015-04-18 11:12:53,11 2015-04-18 11:17:53,14 2015-04-18 11:22:53,8 2015-04-18 11:27:53,11 2015-04-18 11:32:53,11 2015-04-18 11:37:53,7 2015-04-18 11:42:53,9 2015-04-18 11:47:53,7 2015-04-18 11:52:53,5 2015-04-18 11:57:53,9 2015-04-18 12:02:53,19 2015-04-18 12:07:53,11 2015-04-18 12:12:53,5 2015-04-18 12:17:53,7 2015-04-18 12:22:53,15 2015-04-18 12:27:53,7 2015-04-18 12:32:53,6 2015-04-18 12:37:53,5 2015-04-18 12:42:53,7 2015-04-18 12:47:53,7 2015-04-18 12:52:53,14 2015-04-18 12:57:53,15 2015-04-18 13:02:53,10 2015-04-18 13:07:53,11 2015-04-18 13:12:53,17 2015-04-18 13:17:53,8 2015-04-18 13:22:53,7 2015-04-18 13:27:53,5 2015-04-18 13:32:53,7 2015-04-18 13:37:53,17 2015-04-18 13:42:53,12 2015-04-18 13:47:53,13 2015-04-18 13:52:53,14 2015-04-18 13:57:53,16 2015-04-18 14:02:53,16 2015-04-18 14:07:53,17 2015-04-18 14:12:53,13 2015-04-18 14:17:53,9 2015-04-18 14:22:53,10 2015-04-18 14:27:53,10 2015-04-18 14:32:53,23 2015-04-18 14:37:53,13 2015-04-18 14:42:53,11 2015-04-18 14:47:53,22 2015-04-18 14:52:53,18 2015-04-18 14:57:53,16 2015-04-18 15:02:53,16 2015-04-18 15:07:53,17 2015-04-18 15:12:53,12 2015-04-18 15:17:53,11 2015-04-18 15:22:53,25 2015-04-18 15:27:53,7 2015-04-18 15:32:53,15 2015-04-18 15:37:53,11 2015-04-18 15:42:53,15 2015-04-18 15:47:53,18 2015-04-18 15:52:53,12 2015-04-18 15:57:53,13 2015-04-18 16:02:53,17 2015-04-18 16:07:53,14 2015-04-18 16:12:53,14 2015-04-18 16:17:53,32 2015-04-18 16:22:53,26 2015-04-18 16:27:53,18 2015-04-18 16:32:53,13 2015-04-18 16:37:53,20 2015-04-18 16:42:53,16 2015-04-18 16:47:53,15 2015-04-18 16:52:53,16 2015-04-18 16:57:53,10 2015-04-18 17:02:53,10 2015-04-18 17:07:53,19 2015-04-18 17:12:53,17 2015-04-18 17:17:53,14 2015-04-18 17:22:53,18 2015-04-18 17:27:53,18 2015-04-18 17:32:53,10 2015-04-18 17:37:53,15 2015-04-18 17:42:53,8 2015-04-18 17:47:53,7 2015-04-18 17:52:53,7 2015-04-18 17:57:53,12 2015-04-18 18:02:53,13 2015-04-18 18:07:53,17 2015-04-18 18:12:53,18 2015-04-18 18:17:53,18 2015-04-18 18:22:53,7 2015-04-18 18:27:53,13 2015-04-18 18:32:53,20 2015-04-18 18:37:53,11 2015-04-18 18:42:53,5 2015-04-18 18:47:53,20 2015-04-18 18:52:53,6 2015-04-18 18:57:53,12 2015-04-18 19:02:53,21 2015-04-18 19:07:53,10 2015-04-18 19:12:53,9 2015-04-18 19:17:53,5 2015-04-18 19:22:53,9 2015-04-18 19:27:53,12 2015-04-18 19:32:53,28 2015-04-18 19:37:53,11 2015-04-18 19:42:53,13 2015-04-18 19:47:53,20 2015-04-18 19:52:53,12 2015-04-18 19:57:53,10 2015-04-18 20:02:53,14 2015-04-18 20:07:53,7 2015-04-18 20:12:53,11 2015-04-18 20:17:53,9 2015-04-18 20:22:53,9 2015-04-18 20:27:53,8 2015-04-18 20:32:53,9 2015-04-18 20:37:53,8 2015-04-18 20:42:53,9 2015-04-18 20:47:53,8 2015-04-18 20:52:53,6 2015-04-18 20:57:53,10 2015-04-18 21:02:53,14 2015-04-18 21:07:53,10 2015-04-18 21:12:53,9 2015-04-18 21:17:53,8 2015-04-18 21:22:53,7 2015-04-18 21:27:53,6 2015-04-18 21:32:53,10 2015-04-18 21:37:53,13 2015-04-18 21:42:53,7 2015-04-18 21:47:53,2 2015-04-18 21:52:53,7 2015-04-18 21:57:53,9 2015-04-18 22:02:53,7 2015-04-18 22:07:53,6 2015-04-18 22:12:53,6 2015-04-18 22:17:53,8 2015-04-18 22:22:53,6 2015-04-18 22:27:53,7 2015-04-18 22:32:53,7 2015-04-18 22:37:53,5 2015-04-18 22:42:53,6 2015-04-18 22:47:53,3 2015-04-18 22:52:53,11 2015-04-18 22:57:53,9 2015-04-18 23:02:53,7 2015-04-18 23:07:53,6 2015-04-18 23:12:53,11 2015-04-18 23:17:53,18 2015-04-18 23:22:53,11 2015-04-18 23:27:53,8 2015-04-18 23:32:53,8 2015-04-18 23:37:53,8 2015-04-18 23:42:53,13 2015-04-18 23:47:53,15 2015-04-18 23:52:53,9 2015-04-18 23:57:53,13 2015-04-19 00:02:53,10 2015-04-19 00:07:53,8 2015-04-19 00:12:53,5 2015-04-19 00:17:53,2 2015-04-19 00:22:53,11 2015-04-19 00:27:53,8 2015-04-19 00:32:53,9 2015-04-19 00:37:53,15 2015-04-19 00:42:53,5 2015-04-19 00:47:53,5 2015-04-19 00:52:53,5 2015-04-19 00:57:53,5 2015-04-19 01:02:53,5 2015-04-19 01:07:53,7 2015-04-19 01:12:53,11 2015-04-19 01:17:53,6 2015-04-19 01:22:53,12 2015-04-19 01:27:53,10 2015-04-19 01:32:53,14 2015-04-19 01:37:53,8 2015-04-19 01:42:53,7 2015-04-19 01:47:53,7 2015-04-19 01:52:53,7 2015-04-19 01:57:53,6 2015-04-19 02:02:53,6 2015-04-19 02:07:53,15 2015-04-19 02:12:53,7 2015-04-19 02:17:53,6 2015-04-19 02:22:53,10 2015-04-19 02:27:53,3 2015-04-19 02:32:53,6 2015-04-19 02:37:53,8 2015-04-19 02:42:53,5 2015-04-19 02:47:53,9 2015-04-19 02:52:53,8 2015-04-19 02:57:53,11 2015-04-19 03:02:53,4 2015-04-19 03:07:53,15 2015-04-19 03:12:53,8 2015-04-19 03:17:53,11 2015-04-19 03:22:53,5 2015-04-19 03:27:53,2 2015-04-19 03:32:53,11 2015-04-19 03:37:53,8 2015-04-19 03:42:53,4 2015-04-19 03:47:53,10 2015-04-19 03:52:53,2 2015-04-19 03:57:53,3 2015-04-19 04:02:53,10 2015-04-19 04:07:53,5 2015-04-19 04:12:53,4 2015-04-19 04:17:53,4 2015-04-19 04:22:53,4 2015-04-19 04:27:53,4 2015-04-19 04:32:53,6 2015-04-19 04:37:53,11 2015-04-19 04:42:53,8 2015-04-19 04:47:53,6 2015-04-19 04:52:53,5 2015-04-19 04:57:53,18 2015-04-19 05:02:53,19 2015-04-19 05:07:53,13 2015-04-19 05:12:53,11 2015-04-19 05:17:53,8 2015-04-19 05:22:53,10 2015-04-19 05:27:53,8 2015-04-19 05:32:53,11 2015-04-19 05:37:53,6 2015-04-19 05:42:53,14 2015-04-19 05:47:53,14 2015-04-19 05:52:53,6 2015-04-19 05:57:53,3 2015-04-19 06:02:53,7 2015-04-19 06:07:53,8 2015-04-19 06:12:53,5 2015-04-19 06:17:53,5 2015-04-19 06:22:53,7 2015-04-19 06:27:53,3 2015-04-19 06:32:53,3 2015-04-19 06:37:53,5 2015-04-19 06:42:53,8 2015-04-19 06:47:53,9 2015-04-19 06:52:53,6 2015-04-19 06:57:53,5 2015-04-19 07:02:53,10 2015-04-19 07:07:53,4 2015-04-19 07:12:53,8 2015-04-19 07:17:53,3 2015-04-19 07:22:53,12 2015-04-19 07:27:53,6 2015-04-19 07:32:53,6 2015-04-19 07:37:53,6 2015-04-19 07:42:53,9 2015-04-19 07:47:53,4 2015-04-19 07:52:53,5 2015-04-19 07:57:53,5 2015-04-19 08:02:53,5 2015-04-19 08:07:53,10 2015-04-19 08:12:53,8 2015-04-19 08:17:53,7 2015-04-19 08:22:53,5 2015-04-19 08:27:53,6 2015-04-19 08:32:53,6 2015-04-19 08:37:53,12 2015-04-19 08:42:53,6 2015-04-19 08:47:53,3 2015-04-19 08:52:53,4 2015-04-19 08:57:53,6 2015-04-19 09:02:53,11 2015-04-19 09:07:53,3 2015-04-19 09:12:53,11 2015-04-19 09:17:53,4 2015-04-19 09:22:53,8 2015-04-19 09:27:53,10 2015-04-19 09:32:53,13 2015-04-19 09:37:53,4 2015-04-19 09:42:53,11 2015-04-19 09:47:53,10 2015-04-19 09:52:53,6 2015-04-19 09:57:53,5 2015-04-19 10:02:53,8 2015-04-19 10:07:53,4 2015-04-19 10:12:53,6 2015-04-19 10:17:53,6 2015-04-19 10:22:53,4 2015-04-19 10:27:53,8 2015-04-19 10:32:53,2 2015-04-19 10:37:53,8 2015-04-19 10:42:53,11 2015-04-19 10:47:53,15 2015-04-19 10:52:53,8 2015-04-19 10:57:53,13 2015-04-19 11:02:53,6 2015-04-19 11:07:53,7 2015-04-19 11:12:53,12 2015-04-19 11:17:53,3 2015-04-19 11:22:53,5 2015-04-19 11:27:53,5 2015-04-19 11:32:53,12 2015-04-19 11:37:53,5 2015-04-19 11:42:53,1 2015-04-19 11:47:53,5 2015-04-19 11:52:53,10 2015-04-19 11:57:53,14 2015-04-19 12:02:53,8 2015-04-19 12:07:53,4 2015-04-19 12:12:53,2 2015-04-19 12:17:53,13 2015-04-19 12:22:53,6 2015-04-19 12:27:53,5 2015-04-19 12:32:53,10 2015-04-19 12:37:53,12 2015-04-19 12:42:53,11 2015-04-19 12:47:53,12 2015-04-19 12:52:53,11 2015-04-19 12:57:53,7 2015-04-19 13:02:53,15 2015-04-19 13:07:53,8 2015-04-19 13:12:53,14 2015-04-19 13:17:53,15 2015-04-19 13:22:53,5 2015-04-19 13:27:53,5 2015-04-19 13:32:53,11 2015-04-19 13:37:53,4 2015-04-19 13:42:53,10 2015-04-19 13:47:53,6 2015-04-19 13:52:53,7 2015-04-19 13:57:53,4 2015-04-19 14:02:53,11 2015-04-19 14:07:53,7 2015-04-19 14:12:53,7 2015-04-19 14:17:53,4 2015-04-19 14:22:53,13 2015-04-19 14:27:53,8 2015-04-19 14:32:53,8 2015-04-19 14:37:53,10 2015-04-19 14:42:53,7 2015-04-19 14:47:53,14 2015-04-19 14:52:53,20 2015-04-19 14:57:53,9 2015-04-19 15:02:53,12 2015-04-19 15:07:53,12 2015-04-19 15:12:53,3 2015-04-19 15:17:53,6 2015-04-19 15:22:53,7 2015-04-19 15:27:53,5 2015-04-19 15:32:53,16 2015-04-19 15:37:53,14 2015-04-19 15:42:53,10 2015-04-19 15:47:53,12 2015-04-19 15:52:53,9 2015-04-19 15:57:53,16 2015-04-19 16:02:53,23 2015-04-19 16:07:53,9 2015-04-19 16:12:53,8 2015-04-19 16:17:53,6 2015-04-19 16:22:53,4 2015-04-19 16:27:53,11 2015-04-19 16:32:53,12 2015-04-19 16:37:53,6 2015-04-19 16:42:53,6 2015-04-19 16:47:53,12 2015-04-19 16:52:53,12 2015-04-19 16:57:53,7 2015-04-19 17:02:53,20 2015-04-19 17:07:53,14 2015-04-19 17:12:53,11 2015-04-19 17:17:53,10 2015-04-19 17:22:53,9 2015-04-19 17:27:53,15 2015-04-19 17:32:53,14 2015-04-19 17:37:53,11 2015-04-19 17:42:53,13 2015-04-19 17:47:53,21 2015-04-19 17:52:53,7 2015-04-19 17:57:53,15 2015-04-19 18:02:53,9 2015-04-19 18:07:53,12 2015-04-19 18:12:53,11 2015-04-19 18:17:53,14 2015-04-19 18:22:53,8 2015-04-19 18:27:53,19 2015-04-19 18:32:53,18 2015-04-19 18:37:53,12 2015-04-19 18:42:53,26 2015-04-19 18:47:53,18 2015-04-19 18:52:53,17 2015-04-19 18:57:53,12 2015-04-19 19:02:53,7 2015-04-19 19:07:53,10 2015-04-19 19:12:53,10 2015-04-19 19:17:53,10 2015-04-19 19:22:53,8 2015-04-19 19:27:53,10 2015-04-19 19:32:53,14 2015-04-19 19:37:53,5 2015-04-19 19:42:53,9 2015-04-19 19:47:53,11 2015-04-19 19:52:53,7 2015-04-19 19:57:53,12 2015-04-19 20:02:53,9 2015-04-19 20:07:53,14 2015-04-19 20:12:53,8 2015-04-19 20:17:53,19 2015-04-19 20:22:53,6 2015-04-19 20:27:53,11 2015-04-19 20:32:53,12 2015-04-19 20:37:53,14 2015-04-19 20:42:53,18 2015-04-19 20:47:53,5 2015-04-19 20:52:53,8 2015-04-19 20:57:53,19 2015-04-19 21:02:53,19 2015-04-19 21:07:53,10 2015-04-19 21:12:53,14 2015-04-19 21:17:53,8 2015-04-19 21:22:53,8 2015-04-19 21:27:53,16 2015-04-19 21:32:53,16 2015-04-19 21:37:53,15 2015-04-19 21:42:53,16 2015-04-19 21:47:53,16 2015-04-19 21:52:53,10 2015-04-19 21:57:53,6 2015-04-19 22:02:53,15 2015-04-19 22:07:53,6 2015-04-19 22:12:53,9 2015-04-19 22:17:53,6 2015-04-19 22:22:53,10 2015-04-19 22:27:53,19 2015-04-19 22:32:53,10 2015-04-19 22:37:53,2 2015-04-19 22:42:53,9 2015-04-19 22:47:53,11 2015-04-19 22:52:53,18 2015-04-19 22:57:53,19 2015-04-19 23:02:53,13 2015-04-19 23:07:53,9 2015-04-19 23:12:53,13 2015-04-19 23:17:53,17 2015-04-19 23:22:53,5 2015-04-19 23:27:53,12 2015-04-19 23:32:53,12 2015-04-19 23:37:53,8 2015-04-19 23:42:53,4 2015-04-19 23:47:53,7 2015-04-19 23:52:53,7 2015-04-19 23:57:53,6 2015-04-20 00:02:53,4 2015-04-20 00:07:53,13 2015-04-20 00:12:53,14 2015-04-20 00:17:53,4 2015-04-20 00:22:53,4 2015-04-20 00:27:53,10 2015-04-20 00:32:53,5 2015-04-20 00:37:53,3 2015-04-20 00:42:53,7 2015-04-20 00:47:53,23 2015-04-20 00:52:53,7 2015-04-20 00:57:53,12 2015-04-20 01:02:53,8 2015-04-20 01:07:53,15 2015-04-20 01:12:53,10 2015-04-20 01:17:53,7 2015-04-20 01:22:53,18 2015-04-20 01:27:53,13 2015-04-20 01:32:53,10 2015-04-20 01:37:53,16 2015-04-20 01:42:53,8 2015-04-20 01:47:53,9 2015-04-20 01:52:53,6 2015-04-20 01:57:53,19 2015-04-20 02:02:53,5 2015-04-20 02:07:53,10 2015-04-20 02:12:53,10 2015-04-20 02:17:53,14 2015-04-20 02:22:53,7 2015-04-20 02:27:53,14 2015-04-20 02:32:53,7 2015-04-20 02:37:53,7 2015-04-20 02:42:53,5 2015-04-20 02:47:53,8 2015-04-20 02:52:53,5 2015-04-20 02:57:53,10 2015-04-20 03:02:53,0 2015-04-20 03:07:53,16 2015-04-20 03:12:53,7 2015-04-20 03:17:53,11 2015-04-20 03:22:53,13 2015-04-20 03:27:53,14 2015-04-20 03:32:53,15 2015-04-20 03:37:53,6 2015-04-20 03:42:53,9 2015-04-20 03:47:53,8 2015-04-20 03:52:53,16 2015-04-20 03:57:53,15 2015-04-20 04:02:53,14 2015-04-20 04:07:53,9 2015-04-20 04:12:53,13 2015-04-20 04:17:53,11 2015-04-20 04:22:53,9 2015-04-20 04:27:53,8 2015-04-20 04:32:53,3 2015-04-20 04:37:53,6 2015-04-20 04:42:53,8 2015-04-20 04:47:53,14 2015-04-20 04:52:53,9 2015-04-20 04:57:53,10 2015-04-20 05:02:53,6 2015-04-20 05:07:53,4 2015-04-20 05:12:53,9 2015-04-20 05:17:53,16 2015-04-20 05:22:53,11 2015-04-20 05:27:53,8 2015-04-20 05:32:53,8 2015-04-20 05:37:53,1 2015-04-20 05:42:53,5 2015-04-20 05:47:53,12 2015-04-20 05:52:53,3 2015-04-20 05:57:53,15 2015-04-20 06:02:53,16 2015-04-20 06:07:53,7 2015-04-20 06:12:53,4 2015-04-20 06:17:53,10 2015-04-20 06:22:53,7 2015-04-20 06:27:53,13 2015-04-20 06:32:53,5 2015-04-20 06:37:53,15 2015-04-20 06:42:53,5 2015-04-20 06:47:53,7 2015-04-20 06:52:53,15 2015-04-20 06:57:53,14 2015-04-20 07:02:53,4 2015-04-20 07:07:53,11 2015-04-20 07:12:53,10 2015-04-20 07:17:53,9 2015-04-20 07:22:53,7 2015-04-20 07:27:53,8 2015-04-20 07:32:53,9 2015-04-20 07:37:53,12 2015-04-20 07:42:53,8 2015-04-20 07:47:53,13 2015-04-20 07:52:53,11 2015-04-20 07:57:53,20 2015-04-20 08:02:53,14 2015-04-20 08:07:53,15 2015-04-20 08:12:53,11 2015-04-20 08:17:53,11 2015-04-20 08:22:53,12 2015-04-20 08:27:53,10 2015-04-20 08:32:53,14 2015-04-20 08:37:53,8 2015-04-20 08:42:53,9 2015-04-20 08:47:53,8 2015-04-20 08:52:53,8 2015-04-20 08:57:53,13 2015-04-20 09:02:53,12 2015-04-20 09:07:53,18 2015-04-20 09:12:53,10 2015-04-20 09:17:53,7 2015-04-20 09:22:53,13 2015-04-20 09:27:53,11 2015-04-20 09:32:53,12 2015-04-20 09:37:53,9 2015-04-20 09:42:53,14 2015-04-20 09:47:53,8 2015-04-20 09:52:53,10 2015-04-20 09:57:53,16 2015-04-20 10:02:53,11 2015-04-20 10:07:53,7 2015-04-20 10:12:53,11 2015-04-20 10:17:53,10 2015-04-20 10:22:53,16 2015-04-20 10:27:53,10 2015-04-20 10:32:53,11 2015-04-20 10:37:53,7 2015-04-20 10:42:53,7 2015-04-20 10:47:53,7 2015-04-20 10:52:53,8 2015-04-20 10:57:53,13 2015-04-20 11:02:53,7 2015-04-20 11:07:53,15 2015-04-20 11:12:53,11 2015-04-20 11:17:53,13 2015-04-20 11:22:53,13 2015-04-20 11:27:53,14 2015-04-20 11:32:53,16 2015-04-20 11:37:53,27 2015-04-20 11:42:53,16 2015-04-20 11:47:53,27 2015-04-20 11:52:53,12 2015-04-20 11:57:53,32 2015-04-20 12:02:53,26 2015-04-20 12:07:53,19 2015-04-20 12:12:53,21 2015-04-20 12:17:53,27 2015-04-20 12:22:53,16 2015-04-20 12:27:53,29 2015-04-20 12:32:53,15 2015-04-20 12:37:53,18 2015-04-20 12:42:53,16 2015-04-20 12:47:53,16 2015-04-20 12:52:53,27 2015-04-20 12:57:53,41 2015-04-20 13:02:53,27 2015-04-20 13:07:53,24 2015-04-20 13:12:53,32 2015-04-20 13:17:53,38 2015-04-20 13:22:53,33 2015-04-20 13:27:53,24 2015-04-20 13:32:53,33 2015-04-20 13:37:53,25 2015-04-20 13:42:53,35 2015-04-20 13:47:53,32 2015-04-20 13:52:53,23 2015-04-20 13:57:53,33 2015-04-20 14:02:53,35 2015-04-20 14:07:53,35 2015-04-20 14:12:53,36 2015-04-20 14:17:53,44 2015-04-20 14:22:53,26 2015-04-20 14:27:53,37 2015-04-20 14:32:53,30 2015-04-20 14:37:53,21 2015-04-20 14:42:53,32 2015-04-20 14:47:53,23 2015-04-20 14:52:53,32 2015-04-20 14:57:53,30 2015-04-20 15:02:53,25 2015-04-20 15:07:53,28 2015-04-20 15:12:53,26 2015-04-20 15:17:53,24 2015-04-20 15:22:53,32 2015-04-20 15:27:53,29 2015-04-20 15:32:53,29 2015-04-20 15:37:53,26 2015-04-20 15:42:53,29 2015-04-20 15:47:53,30 2015-04-20 15:52:53,25 2015-04-20 15:57:53,38 2015-04-20 16:02:53,19 2015-04-20 16:07:53,28 2015-04-20 16:12:53,23 2015-04-20 16:17:53,32 2015-04-20 16:22:53,25 2015-04-20 16:27:53,22 2015-04-20 16:32:53,24 2015-04-20 16:37:53,22 2015-04-20 16:42:53,59 2015-04-20 16:47:53,39 2015-04-20 16:52:53,36 2015-04-20 16:57:53,27 2015-04-20 17:02:53,49 2015-04-20 17:07:53,31 2015-04-20 17:12:53,29 2015-04-20 17:17:53,32 2015-04-20 17:22:53,30 2015-04-20 17:27:53,27 2015-04-20 17:32:53,23 2015-04-20 17:37:53,24 2015-04-20 17:42:53,34 2015-04-20 17:47:53,27 2015-04-20 17:52:53,28 2015-04-20 17:57:53,42 2015-04-20 18:02:53,75 2015-04-20 18:07:53,39 2015-04-20 18:12:53,34 2015-04-20 18:17:53,42 2015-04-20 18:22:53,43 2015-04-20 18:27:53,25 2015-04-20 18:32:53,46 2015-04-20 18:37:53,35 2015-04-20 18:42:53,43 2015-04-20 18:47:53,30 2015-04-20 18:52:53,29 2015-04-20 18:57:53,31 2015-04-20 19:02:53,46 2015-04-20 19:07:53,23 2015-04-20 19:12:53,25 2015-04-20 19:17:53,28 2015-04-20 19:22:53,27 2015-04-20 19:27:53,32 2015-04-20 19:32:53,20 2015-04-20 19:37:53,17 2015-04-20 19:42:53,22 2015-04-20 19:47:53,16 2015-04-20 19:52:53,19 2015-04-20 19:57:53,30 2015-04-20 20:02:53,32 2015-04-20 20:07:53,33 2015-04-20 20:12:53,16 2015-04-20 20:17:53,20 2015-04-20 20:22:53,17 2015-04-20 20:27:53,17 2015-04-20 20:32:53,17 2015-04-20 20:37:53,26 2015-04-20 20:42:53,31 2015-04-20 20:47:53,23 2015-04-20 20:52:53,17 2015-04-20 20:57:53,29 2015-04-20 21:02:53,14 2015-04-20 21:07:53,29 2015-04-20 21:12:53,16 2015-04-20 21:17:53,14 2015-04-20 21:22:53,15 2015-04-20 21:27:53,26 2015-04-20 21:32:53,22 2015-04-20 21:37:53,27 2015-04-20 21:42:53,18 2015-04-20 21:47:53,18 2015-04-20 21:52:53,22 2015-04-20 21:57:53,29 2015-04-20 22:02:53,34 2015-04-20 22:07:53,42 2015-04-20 22:12:53,25 2015-04-20 22:17:53,15 2015-04-20 22:22:53,14 2015-04-20 22:27:53,28 2015-04-20 22:32:53,16 2015-04-20 22:37:53,29 2015-04-20 22:42:53,31 2015-04-20 22:47:53,28 2015-04-20 22:52:53,16 2015-04-20 22:57:53,28 2015-04-20 23:02:53,24 2015-04-20 23:07:53,16 2015-04-20 23:12:53,15 2015-04-20 23:17:53,10 2015-04-20 23:22:53,10 2015-04-20 23:27:53,15 2015-04-20 23:32:53,12 2015-04-20 23:37:53,20 2015-04-20 23:42:53,13 2015-04-20 23:47:53,29 2015-04-20 23:52:53,22 2015-04-20 23:57:53,18 2015-04-21 00:02:53,14 2015-04-21 00:07:53,21 2015-04-21 00:12:53,16 2015-04-21 00:17:53,17 2015-04-21 00:22:53,20 2015-04-21 00:27:53,14 2015-04-21 00:32:53,16 2015-04-21 00:37:53,20 2015-04-21 00:42:53,21 2015-04-21 00:47:53,23 2015-04-21 00:52:53,26 2015-04-21 00:57:53,35 2015-04-21 01:02:53,16 2015-04-21 01:07:53,18 2015-04-21 01:12:53,25 2015-04-21 01:17:53,15 2015-04-21 01:22:53,14 2015-04-21 01:27:53,17 2015-04-21 01:32:53,11 2015-04-21 01:37:53,16 2015-04-21 01:42:53,35 2015-04-21 01:47:53,10 2015-04-21 01:52:53,14 2015-04-21 01:57:53,9 2015-04-21 02:02:53,13 2015-04-21 02:07:53,20 2015-04-21 02:12:53,19 2015-04-21 02:17:53,10 2015-04-21 02:22:53,20 2015-04-21 02:27:53,16 2015-04-21 02:32:53,12 2015-04-21 02:37:53,11 2015-04-21 02:42:53,11 2015-04-21 02:47:53,12 2015-04-21 02:52:53,13 2015-04-21 02:57:53,11 2015-04-21 03:02:53,8 2015-04-21 03:07:53,8 2015-04-21 03:12:53,13 2015-04-21 03:17:53,13 2015-04-21 03:22:53,7 2015-04-21 03:27:53,20 2015-04-21 03:32:53,20 2015-04-21 03:37:53,14 2015-04-21 03:42:53,11 2015-04-21 03:47:53,17 2015-04-21 03:52:53,13 2015-04-21 03:57:53,12 2015-04-21 04:02:53,12 2015-04-21 04:07:53,12 2015-04-21 04:12:53,14 2015-04-21 04:17:53,16 2015-04-21 04:22:53,13 2015-04-21 04:27:53,15 2015-04-21 04:32:53,10 2015-04-21 04:37:53,14 2015-04-21 04:42:53,9 2015-04-21 04:47:53,13 2015-04-21 04:52:53,12 2015-04-21 04:57:53,14 2015-04-21 05:02:53,9 2015-04-21 05:07:53,14 2015-04-21 05:12:53,21 2015-04-21 05:17:53,16 2015-04-21 05:22:53,12 2015-04-21 05:27:53,16 2015-04-21 05:32:53,8 2015-04-21 05:37:53,18 2015-04-21 05:42:53,14 2015-04-21 05:47:53,11 2015-04-21 05:52:53,26 2015-04-21 05:57:53,8 2015-04-21 06:02:53,18 2015-04-21 06:07:53,19 2015-04-21 06:12:53,14 2015-04-21 06:17:53,8 2015-04-21 06:22:53,8 2015-04-21 06:27:53,27 2015-04-21 06:32:53,17 2015-04-21 06:37:53,26 2015-04-21 06:42:53,16 2015-04-21 06:47:53,24 2015-04-21 06:52:53,24 2015-04-21 06:57:53,17 2015-04-21 07:02:53,17 2015-04-21 07:07:53,14 2015-04-21 07:12:53,24 2015-04-21 07:17:53,19 2015-04-21 07:22:53,11 2015-04-21 07:27:53,25 2015-04-21 07:32:53,13 2015-04-21 07:37:53,20 2015-04-21 07:42:53,27 2015-04-21 07:47:53,32 2015-04-21 07:52:53,38 2015-04-21 07:57:53,18 2015-04-21 08:02:53,23 2015-04-21 08:07:53,8 2015-04-21 08:12:53,23 2015-04-21 08:17:53,19 2015-04-21 08:22:53,14 2015-04-21 08:27:53,27 2015-04-21 08:32:53,24 2015-04-21 08:37:53,17 2015-04-21 08:42:53,21 2015-04-21 08:47:53,18 2015-04-21 08:52:53,23 2015-04-21 08:57:53,23 2015-04-21 09:02:53,23 2015-04-21 09:07:53,20 2015-04-21 09:12:53,29 2015-04-21 09:17:53,24 2015-04-21 09:22:53,18 2015-04-21 09:27:53,17 2015-04-21 09:32:53,16 2015-04-21 09:37:53,15 2015-04-21 09:42:53,17 2015-04-21 09:47:53,13 2015-04-21 09:52:53,35 2015-04-21 09:57:53,29 2015-04-21 10:02:53,34 2015-04-21 10:07:53,13 2015-04-21 10:12:53,19 2015-04-21 10:17:53,29 2015-04-21 10:22:53,32 2015-04-21 10:27:53,18 2015-04-21 10:32:53,19 2015-04-21 10:37:53,22 2015-04-21 10:42:53,25 2015-04-21 10:47:53,33 2015-04-21 10:52:53,24 2015-04-21 10:57:53,33 2015-04-21 11:02:53,22 2015-04-21 11:07:53,24 2015-04-21 11:12:53,30 2015-04-21 11:17:53,29 2015-04-21 11:22:53,24 2015-04-21 11:27:53,25 2015-04-21 11:32:53,20 2015-04-21 11:37:53,22 2015-04-21 11:42:53,27 2015-04-21 11:47:53,26 2015-04-21 11:52:53,34 2015-04-21 11:57:53,24 2015-04-21 12:02:53,49 2015-04-21 12:07:53,27 2015-04-21 12:12:53,24 2015-04-21 12:17:53,32 2015-04-21 12:22:53,24 2015-04-21 12:27:53,31 2015-04-21 12:32:53,32 2015-04-21 12:37:53,39 2015-04-21 12:42:53,28 2015-04-21 12:47:53,21 2015-04-21 12:52:53,21 2015-04-21 12:57:53,29 2015-04-21 13:02:53,43 2015-04-21 13:07:53,17 2015-04-21 13:12:53,30 2015-04-21 13:17:53,27 2015-04-21 13:22:53,22 2015-04-21 13:27:53,22 2015-04-21 13:32:53,44 2015-04-21 13:37:53,41 2015-04-21 13:42:53,23 2015-04-21 13:47:53,34 2015-04-21 13:52:53,36 2015-04-21 13:57:53,24 2015-04-21 14:02:53,40 2015-04-21 14:07:53,32 2015-04-21 14:12:53,27 2015-04-21 14:17:53,36 2015-04-21 14:22:53,54 2015-04-21 14:27:53,79 2015-04-21 14:32:53,52 2015-04-21 14:37:53,55 2015-04-21 14:42:53,60 2015-04-21 14:47:53,44 2015-04-21 14:52:53,51 2015-04-21 14:57:53,56 2015-04-21 15:02:53,67 2015-04-21 15:07:53,38 2015-04-21 15:12:53,82 2015-04-21 15:17:53,59 2015-04-21 15:22:53,46 2015-04-21 15:27:53,74 2015-04-21 15:32:53,41 2015-04-21 15:37:53,34 2015-04-21 15:42:53,57 2015-04-21 15:47:53,47 2015-04-21 15:52:53,42 2015-04-21 15:57:53,31 2015-04-21 16:02:53,42 2015-04-21 16:07:53,44 2015-04-21 16:12:53,52 2015-04-21 16:17:53,43 2015-04-21 16:22:53,47 2015-04-21 16:27:53,59 2015-04-21 16:32:53,39 2015-04-21 16:37:53,36 2015-04-21 16:42:53,43 2015-04-21 16:47:53,30 2015-04-21 16:52:53,32 2015-04-21 16:57:53,52 2015-04-21 17:02:53,40 2015-04-21 17:07:53,36 2015-04-21 17:12:53,34 2015-04-21 17:17:53,39 2015-04-21 17:22:53,54 2015-04-21 17:27:53,30 2015-04-21 17:32:53,36 2015-04-21 17:37:53,44 2015-04-21 17:42:53,25 2015-04-21 17:47:53,29 2015-04-21 17:52:53,45 2015-04-21 17:57:53,41 2015-04-21 18:02:53,37 2015-04-21 18:07:53,38 2015-04-21 18:12:53,35 2015-04-21 18:17:53,32 2015-04-21 18:22:53,40 2015-04-21 18:27:53,29 2015-04-21 18:32:53,37 2015-04-21 18:37:53,41 2015-04-21 18:42:53,32 2015-04-21 18:47:53,28 2015-04-21 18:52:53,36 2015-04-21 18:57:53,119 2015-04-21 19:02:53,69 2015-04-21 19:07:53,43 2015-04-21 19:12:53,61 2015-04-21 19:17:53,30 2015-04-21 19:22:53,25 2015-04-21 19:27:53,59 2015-04-21 19:32:53,31 2015-04-21 19:37:53,34 2015-04-21 19:42:53,27 2015-04-21 19:47:53,81 2015-04-21 19:52:53,93 2015-04-21 19:57:53,68 2015-04-21 20:02:53,44 2015-04-21 20:07:53,46 2015-04-21 20:12:53,46 2015-04-21 20:17:53,52 2015-04-21 20:22:53,34 2015-04-21 20:27:53,47 2015-04-21 20:32:53,60 2015-04-21 20:37:53,37 2015-04-21 20:42:53,44 2015-04-21 20:47:53,53 2015-04-21 20:52:53,29 2015-04-21 20:57:53,39 2015-04-21 21:02:53,38 2015-04-21 21:07:53,29 2015-04-21 21:12:53,30 2015-04-21 21:17:53,43 2015-04-21 21:22:53,26 2015-04-21 21:27:53,21 2015-04-21 21:32:53,25 2015-04-21 21:37:53,32 2015-04-21 21:42:53,21 2015-04-21 21:47:53,16 2015-04-21 21:52:53,19 2015-04-21 21:57:53,32 2015-04-21 22:02:53,22 2015-04-21 22:07:53,19 2015-04-21 22:12:53,16 2015-04-21 22:17:53,30 2015-04-21 22:22:53,23 2015-04-21 22:27:53,35 2015-04-21 22:32:53,31 2015-04-21 22:37:53,27 2015-04-21 22:42:53,32 2015-04-21 22:47:53,24 2015-04-21 22:52:53,21 2015-04-21 22:57:53,23 2015-04-21 23:02:53,22 2015-04-21 23:07:53,28 2015-04-21 23:12:53,19 2015-04-21 23:17:53,30 2015-04-21 23:22:53,23 2015-04-21 23:27:53,30 2015-04-21 23:32:53,13 2015-04-21 23:37:53,14 2015-04-21 23:42:53,13 2015-04-21 23:47:53,30 2015-04-21 23:52:53,60 2015-04-21 23:57:53,53 2015-04-22 00:02:53,30 2015-04-22 00:07:53,35 2015-04-22 00:12:53,32 2015-04-22 00:17:53,32 2015-04-22 00:22:53,21 2015-04-22 00:27:53,32 2015-04-22 00:32:53,24 2015-04-22 00:37:53,30 2015-04-22 00:42:53,16 2015-04-22 00:47:53,27 2015-04-22 00:52:53,25 2015-04-22 00:57:53,16 2015-04-22 01:02:53,37 2015-04-22 01:07:53,31 2015-04-22 01:12:53,18 2015-04-22 01:17:53,56 2015-04-22 01:22:53,38 2015-04-22 01:27:53,19 2015-04-22 01:32:53,13 2015-04-22 01:37:53,28 2015-04-22 01:42:53,16 2015-04-22 01:47:53,21 2015-04-22 01:52:53,19 2015-04-22 01:57:53,31 2015-04-22 02:02:53,59 2015-04-22 02:07:53,39 2015-04-22 02:12:53,29 2015-04-22 02:17:53,35 2015-04-22 02:22:53,29 2015-04-22 02:27:53,36 2015-04-22 02:32:53,21 2015-04-22 02:37:53,14 2015-04-22 02:42:53,23 2015-04-22 02:47:53,17 2015-04-22 02:52:53,29 2015-04-22 02:57:53,33 2015-04-22 03:02:53,17 2015-04-22 03:07:53,23 2015-04-22 03:12:53,14 2015-04-22 03:17:53,14 2015-04-22 03:22:53,22 2015-04-22 03:27:53,22 2015-04-22 03:32:53,22 2015-04-22 03:37:53,26 2015-04-22 03:42:53,12 2015-04-22 03:47:53,16 2015-04-22 03:52:53,23 2015-04-22 03:57:53,29 2015-04-22 04:02:53,18 2015-04-22 04:07:53,13 2015-04-22 04:12:53,11 2015-04-22 04:17:53,17 2015-04-22 04:22:53,18 2015-04-22 04:27:53,19 2015-04-22 04:32:53,29 2015-04-22 04:37:53,17 2015-04-22 04:42:53,22 2015-04-22 04:47:53,18 2015-04-22 04:52:53,26 2015-04-22 04:57:53,24 2015-04-22 05:02:53,31 2015-04-22 05:07:53,21 2015-04-22 05:12:53,32 2015-04-22 05:17:53,39 2015-04-22 05:22:53,22 2015-04-22 05:27:53,41 2015-04-22 05:32:53,22 2015-04-22 05:37:53,23 2015-04-22 05:42:53,37 2015-04-22 05:47:53,23 2015-04-22 05:52:53,34 2015-04-22 05:57:53,29 2015-04-22 06:02:53,23 2015-04-22 06:07:53,28 2015-04-22 06:12:53,30 2015-04-22 06:17:53,21 2015-04-22 06:22:53,28 2015-04-22 06:27:53,18 2015-04-22 06:32:53,10 2015-04-22 06:37:53,24 2015-04-22 06:42:53,21 2015-04-22 06:47:53,26 2015-04-22 06:52:53,21 2015-04-22 06:57:53,22 2015-04-22 07:02:53,37 2015-04-22 07:07:53,29 2015-04-22 07:12:53,26 2015-04-22 07:17:53,28 2015-04-22 07:22:53,25 2015-04-22 07:27:53,19 2015-04-22 07:32:53,26 2015-04-22 07:37:53,26 2015-04-22 07:42:53,18 2015-04-22 07:47:53,16 2015-04-22 07:52:53,26 2015-04-22 07:57:53,24 2015-04-22 08:02:53,29 2015-04-22 08:07:53,40 2015-04-22 08:12:53,28 2015-04-22 08:17:53,39 2015-04-22 08:22:53,26 2015-04-22 08:27:53,35 2015-04-22 08:32:53,24 2015-04-22 08:37:53,31 2015-04-22 08:42:53,26 2015-04-22 08:47:53,28 2015-04-22 08:52:53,28 2015-04-22 08:57:53,30 2015-04-22 09:02:53,41 2015-04-22 09:07:53,31 2015-04-22 09:12:53,28 2015-04-22 09:17:53,23 2015-04-22 09:22:53,32 2015-04-22 09:27:53,23 2015-04-22 09:32:53,30 2015-04-22 09:37:53,18 2015-04-22 09:42:53,40 2015-04-22 09:47:53,21 2015-04-22 09:52:53,26 2015-04-22 09:57:53,30 2015-04-22 10:02:53,27 2015-04-22 10:07:53,29 2015-04-22 10:12:53,34 2015-04-22 10:17:53,31 2015-04-22 10:22:53,39 2015-04-22 10:27:53,39 2015-04-22 10:32:53,31 2015-04-22 10:37:53,37 2015-04-22 10:42:53,30 2015-04-22 10:47:53,29 2015-04-22 10:52:53,24 2015-04-22 10:57:53,36 2015-04-22 11:02:53,38 2015-04-22 11:07:53,41 2015-04-22 11:12:53,27 2015-04-22 11:17:53,21 2015-04-22 11:22:53,33 2015-04-22 11:27:53,36 2015-04-22 11:32:53,33 2015-04-22 11:37:53,44 2015-04-22 11:42:53,37 2015-04-22 11:47:53,26 2015-04-22 11:52:53,31 2015-04-22 11:57:53,50 2015-04-22 12:02:53,45 2015-04-22 12:07:53,131 2015-04-22 12:12:53,127 2015-04-22 12:17:53,39 2015-04-22 12:22:53,30 2015-04-22 12:27:53,42 2015-04-22 12:32:53,38 2015-04-22 12:37:53,40 2015-04-22 12:42:53,36 2015-04-22 12:47:53,58 2015-04-22 12:52:53,31 2015-04-22 12:57:53,47 2015-04-22 13:02:53,46 2015-04-22 13:07:53,35 2015-04-22 13:12:53,47 2015-04-22 13:17:53,53 2015-04-22 13:22:53,57 2015-04-22 13:27:53,51 2015-04-22 13:32:53,42 2015-04-22 13:37:53,42 2015-04-22 13:42:53,48 2015-04-22 13:47:53,39 2015-04-22 13:52:53,38 2015-04-22 13:57:53,62 2015-04-22 14:02:53,134 2015-04-22 14:07:53,30 2015-04-22 14:12:53,31 2015-04-22 14:17:53,54 2015-04-22 14:22:53,29 2015-04-22 14:27:53,116 2015-04-22 14:32:53,59 2015-04-22 14:37:53,65 2015-04-22 14:42:53,69 2015-04-22 14:47:53,68 2015-04-22 14:52:53,42 2015-04-22 14:57:53,65 2015-04-22 15:02:53,72 2015-04-22 15:07:53,73 2015-04-22 15:12:53,72 2015-04-22 15:17:53,62 2015-04-22 15:22:53,56 2015-04-22 15:27:53,71 2015-04-22 15:32:53,67 2015-04-22 15:37:53,55 2015-04-22 15:42:53,148 2015-04-22 15:47:53,127 2015-04-22 15:52:53,88 2015-04-22 15:57:53,107 2015-04-22 16:02:53,73 2015-04-22 16:07:53,73 2015-04-22 16:12:53,73 2015-04-22 16:17:53,83 2015-04-22 16:22:53,62 2015-04-22 16:27:53,59 2015-04-22 16:32:53,43 2015-04-22 16:37:53,55 2015-04-22 16:42:53,66 2015-04-22 16:47:53,45 2015-04-22 16:52:53,48 2015-04-22 16:57:53,65 2015-04-22 17:02:53,36 2015-04-22 17:07:53,53 2015-04-22 17:12:53,53 2015-04-22 17:17:53,65 2015-04-22 17:22:53,64 2015-04-22 17:27:53,77 2015-04-22 17:32:53,74 2015-04-22 17:37:53,67 2015-04-22 17:42:53,85 2015-04-22 17:47:53,89 2015-04-22 17:52:53,89 2015-04-22 17:57:53,87 2015-04-22 18:02:53,139 2015-04-22 18:07:53,111 2015-04-22 18:12:53,106 2015-04-22 18:17:53,77 2015-04-22 18:22:53,98 2015-04-22 18:27:53,107 2015-04-22 18:32:53,94 2015-04-22 18:37:53,87 2015-04-22 18:42:53,64 2015-04-22 18:47:53,71 2015-04-22 18:52:53,98 2015-04-22 18:57:53,102 2015-04-22 19:02:53,68 2015-04-22 19:07:53,59 2015-04-22 19:12:53,58 2015-04-22 19:17:53,50 2015-04-22 19:22:53,61 2015-04-22 19:27:53,70 2015-04-22 19:32:53,60 2015-04-22 19:37:53,60 2015-04-22 19:42:53,61 2015-04-22 19:47:53,52 2015-04-22 19:52:53,51 2015-04-22 19:57:53,67 2015-04-22 20:02:53,106 2015-04-22 20:07:53,86 2015-04-22 20:12:53,61 2015-04-22 20:17:53,62 2015-04-22 20:22:53,54 2015-04-22 20:27:53,54 2015-04-22 20:32:53,57 2015-04-22 20:37:53,58 2015-04-22 20:42:53,65 2015-04-22 20:47:53,59 2015-04-22 20:52:53,52 2015-04-22 20:57:53,50 2015-04-22 21:02:53,61 2015-04-22 21:07:53,56 2015-04-22 21:12:53,59 2015-04-22 21:17:53,57 2015-04-22 21:22:53,62 2015-04-22 21:27:53,58 2015-04-22 21:32:53,50 2015-04-22 21:37:53,32 2015-04-22 21:42:53,72 2015-04-22 21:47:53,72 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/art_daily_jumpsdown.csv ================================================ timestamp,value 2014-04-01 00:00:00,18.090486228499998 2014-04-01 00:05:00,20.359842585899997 2014-04-01 00:10:00,21.105469847200002 2014-04-01 00:15:00,21.1515852522 2014-04-01 00:20:00,18.1371405424 2014-04-01 00:25:00,21.6256605306 2014-04-01 00:30:00,21.6738066877 2014-04-01 00:35:00,20.2455614926 2014-04-01 00:40:00,19.9283327955 2014-04-01 00:45:00,18.1794698523 2014-04-01 00:50:00,20.24781657 2014-04-01 00:55:00,19.637516327100002 2014-04-01 01:00:00,21.0912256296 2014-04-01 01:05:00,19.6155342675 2014-04-01 01:10:00,20.7343233333 2014-04-01 01:15:00,18.405632585 2014-04-01 01:20:00,18.5318090831 2014-04-01 01:25:00,18.5588407626 2014-04-01 01:30:00,18.1821019992 2014-04-01 01:35:00,20.165315437100002 2014-04-01 01:40:00,21.1758709042 2014-04-01 01:45:00,20.4416448148 2014-04-01 01:50:00,20.2998195422 2014-04-01 01:55:00,20.722495713599997 2014-04-01 02:00:00,19.3585812923 2014-04-01 02:05:00,19.447816286600002 2014-04-01 02:10:00,19.2570803929 2014-04-01 02:15:00,20.848435731400002 2014-04-01 02:20:00,18.6465613427 2014-04-01 02:25:00,18.0521011213 2014-04-01 02:30:00,20.3847857869 2014-04-01 02:35:00,21.7695254589 2014-04-01 02:40:00,20.437631667999998 2014-04-01 02:45:00,21.1316866118 2014-04-01 02:50:00,20.6911628379 2014-04-01 02:55:00,19.9897466141 2014-04-01 03:00:00,20.873569607100002 2014-04-01 03:05:00,21.2964164954 2014-04-01 03:10:00,18.8989265767 2014-04-01 03:15:00,19.3445219219 2014-04-01 03:20:00,18.89490293 2014-04-01 03:25:00,19.8086918224 2014-04-01 03:30:00,21.5402582037 2014-04-01 03:35:00,19.3808284033 2014-04-01 03:40:00,19.4978675565 2014-04-01 03:45:00,21.441468938699998 2014-04-01 03:50:00,20.061497323 2014-04-01 03:55:00,20.1417959986 2014-04-01 04:00:00,21.4432048133 2014-04-01 04:05:00,19.9621069481 2014-04-01 04:10:00,20.7262301385 2014-04-01 04:15:00,18.3425786635 2014-04-01 04:20:00,18.7145268525 2014-04-01 04:25:00,19.6175048029 2014-04-01 04:30:00,19.979356271300002 2014-04-01 04:35:00,21.862934804899997 2014-04-01 04:40:00,21.882606532199997 2014-04-01 04:45:00,21.4047883499 2014-04-01 04:50:00,19.2623953411 2014-04-01 04:55:00,21.856113163299998 2014-04-01 05:00:00,20.7573634587 2014-04-01 05:05:00,19.571760511300003 2014-04-01 05:10:00,20.8066996679 2014-04-01 05:15:00,18.066090919100002 2014-04-01 05:20:00,18.5846187291 2014-04-01 05:25:00,21.3187428462 2014-04-01 05:30:00,20.5822945475 2014-04-01 05:35:00,19.4567788052 2014-04-01 05:40:00,20.0026665609 2014-04-01 05:45:00,21.620568598600002 2014-04-01 05:50:00,20.5263124379 2014-04-01 05:55:00,19.5925971357 2014-04-01 06:00:00,18.4813066296 2014-04-01 06:05:00,19.174987206500003 2014-04-01 06:10:00,21.9133609312 2014-04-01 06:15:00,19.7494522514 2014-04-01 06:20:00,19.8873578554 2014-04-01 06:25:00,19.9943921296 2014-04-01 06:30:00,21.5364160918 2014-04-01 06:35:00,20.4157131375 2014-04-01 06:40:00,20.7747081458 2014-04-01 06:45:00,19.5576541702 2014-04-01 06:50:00,18.1163504744 2014-04-01 06:55:00,21.723891657 2014-04-01 07:00:00,21.7965107237 2014-04-01 07:05:00,21.796612213400003 2014-04-01 07:10:00,21.7747483466 2014-04-01 07:15:00,21.260967764300002 2014-04-01 07:20:00,20.7383842005 2014-04-01 07:25:00,21.378039673099998 2014-04-01 07:30:00,20.402184956 2014-04-01 07:35:00,18.5374784556 2014-04-01 07:40:00,19.5648726602 2014-04-01 07:45:00,21.8851796479 2014-04-01 07:50:00,19.4045512544 2014-04-01 07:55:00,21.4713116549 2014-04-01 08:00:00,18.3728458831 2014-04-01 08:05:00,19.3367353695 2014-04-01 08:10:00,19.4038132989 2014-04-01 08:15:00,18.206410172400002 2014-04-01 08:20:00,18.4763773207 2014-04-01 08:25:00,18.7726608445 2014-04-01 08:30:00,21.3512623632 2014-04-01 08:35:00,18.2536079598 2014-04-01 08:40:00,19.1948036054 2014-04-01 08:45:00,18.0407000104 2014-04-01 08:50:00,20.7825109816 2014-04-01 08:55:00,20.4812123602 2014-04-01 09:00:00,69.9717587639 2014-04-01 09:05:00,66.2916058721 2014-04-01 09:10:00,64.0324423692 2014-04-01 09:15:00,70.9963549007 2014-04-01 09:20:00,72.23120306930001 2014-04-01 09:25:00,63.0849803741 2014-04-01 09:30:00,67.8208802199 2014-04-01 09:35:00,64.5825332749 2014-04-01 09:40:00,63.486253312399995 2014-04-01 09:45:00,71.1868242635 2014-04-01 09:50:00,68.5181183224 2014-04-01 09:55:00,64.1401205203 2014-04-01 10:00:00,74.651200174 2014-04-01 10:05:00,84.842464979 2014-04-01 10:10:00,83.0115068443 2014-04-01 10:15:00,83.4967734494 2014-04-01 10:20:00,76.9793877467 2014-04-01 10:25:00,79.5214887361 2014-04-01 10:30:00,75.687435328 2014-04-01 10:35:00,71.0460898627 2014-04-01 10:40:00,76.06459570140001 2014-04-01 10:45:00,79.05858128979999 2014-04-01 10:50:00,74.2964790823 2014-04-01 10:55:00,83.0001929198 2014-04-01 11:00:00,73.9710969315 2014-04-01 11:05:00,77.4068210384 2014-04-01 11:10:00,73.55447171029999 2014-04-01 11:15:00,78.0064502589 2014-04-01 11:20:00,72.1987733943 2014-04-01 11:25:00,75.9026255791 2014-04-01 11:30:00,77.9412934973 2014-04-01 11:35:00,79.17274193760001 2014-04-01 11:40:00,80.2149468852 2014-04-01 11:45:00,75.94145892819999 2014-04-01 11:50:00,79.88644938569999 2014-04-01 11:55:00,79.6632095013 2014-04-01 12:00:00,76.9663781954 2014-04-01 12:05:00,85.1808654442 2014-04-01 12:10:00,80.6333817159 2014-04-01 12:15:00,77.2235359213 2014-04-01 12:20:00,87.0528272939 2014-04-01 12:25:00,85.4191724508 2014-04-01 12:30:00,87.6161392988 2014-04-01 12:35:00,82.9760511039 2014-04-01 12:40:00,77.9579046083 2014-04-01 12:45:00,76.4019781421 2014-04-01 12:50:00,82.5139497962 2014-04-01 12:55:00,87.5878336415 2014-04-01 13:00:00,82.0077546958 2014-04-01 13:05:00,86.08517365450001 2014-04-01 13:10:00,77.2471111396 2014-04-01 13:15:00,78.4924178171 2014-04-01 13:20:00,86.4796437365 2014-04-01 13:25:00,84.0896808632 2014-04-01 13:30:00,87.6815165103 2014-04-01 13:35:00,84.3759722612 2014-04-01 13:40:00,79.15724901520001 2014-04-01 13:45:00,80.47776901600001 2014-04-01 13:50:00,86.3875098999 2014-04-01 13:55:00,80.80694945409999 2014-04-01 14:00:00,76.0827058414 2014-04-01 14:05:00,78.9661264483 2014-04-01 14:10:00,80.25720329090001 2014-04-01 14:15:00,73.543987056 2014-04-01 14:20:00,83.8961755783 2014-04-01 14:25:00,73.7461229499 2014-04-01 14:30:00,78.4749164371 2014-04-01 14:35:00,84.8698851146 2014-04-01 14:40:00,79.4773106918 2014-04-01 14:45:00,85.4681456476 2014-04-01 14:50:00,77.466382588 2014-04-01 14:55:00,87.3179892393 2014-04-01 15:00:00,75.3507715345 2014-04-01 15:05:00,72.6115292425 2014-04-01 15:10:00,85.9579994831 2014-04-01 15:15:00,84.03443671689999 2014-04-01 15:20:00,75.7110145604 2014-04-01 15:25:00,87.7550232579 2014-04-01 15:30:00,80.0357137181 2014-04-01 15:35:00,87.2162097587 2014-04-01 15:40:00,80.07969156979999 2014-04-01 15:45:00,79.5492297084 2014-04-01 15:50:00,79.1854564066 2014-04-01 15:55:00,77.3572617813 2014-04-01 16:00:00,80.5390693195 2014-04-01 16:05:00,79.2407224487 2014-04-01 16:10:00,72.58781065710002 2014-04-01 16:15:00,76.1668174942 2014-04-01 16:20:00,75.4098200146 2014-04-01 16:25:00,85.87880474949999 2014-04-01 16:30:00,81.5817629983 2014-04-01 16:35:00,84.2187679069 2014-04-01 16:40:00,87.30904897030001 2014-04-01 16:45:00,82.3044703355 2014-04-01 16:50:00,87.7215914367 2014-04-01 16:55:00,76.988077009 2014-04-01 17:00:00,74.9802461246 2014-04-01 17:05:00,78.452928082 2014-04-01 17:10:00,79.5327600984 2014-04-01 17:15:00,86.3257515365 2014-04-01 17:20:00,80.9590159363 2014-04-01 17:25:00,76.6748665475 2014-04-01 17:30:00,83.8821163151 2014-04-01 17:35:00,80.0932802384 2014-04-01 17:40:00,74.5940824803 2014-04-01 17:45:00,81.2290854095 2014-04-01 17:50:00,86.5822793413 2014-04-01 17:55:00,85.4819290545 2014-04-01 18:00:00,32.5555775742 2014-04-01 18:05:00,31.2133263199 2014-04-01 18:10:00,29.356658370300003 2014-04-01 18:15:00,31.805747002600004 2014-04-01 18:20:00,33.6133019464 2014-04-01 18:25:00,31.105745834 2014-04-01 18:30:00,30.3068538646 2014-04-01 18:35:00,34.7608235293 2014-04-01 18:40:00,34.057949943800004 2014-04-01 18:45:00,32.8849576504 2014-04-01 18:50:00,29.6754077034 2014-04-01 18:55:00,29.727410870900002 2014-04-01 19:00:00,20.6224226384 2014-04-01 19:05:00,22.9210078103 2014-04-01 19:10:00,20.6777201939 2014-04-01 19:15:00,23.934968537899998 2014-04-01 19:20:00,24.6084818582 2014-04-01 19:25:00,21.801238671500002 2014-04-01 19:30:00,22.192439696999998 2014-04-01 19:35:00,23.3482676721 2014-04-01 19:40:00,24.3584441321 2014-04-01 19:45:00,24.165538779899997 2014-04-01 19:50:00,20.4180102727 2014-04-01 19:55:00,20.917440528 2014-04-01 20:00:00,21.522829867 2014-04-01 20:05:00,21.2537059155 2014-04-01 20:10:00,18.9776631335 2014-04-01 20:15:00,20.488456282 2014-04-01 20:20:00,21.6302164694 2014-04-01 20:25:00,19.3281254426 2014-04-01 20:30:00,22.000793891999997 2014-04-01 20:35:00,18.6489721659 2014-04-01 20:40:00,21.6358708088 2014-04-01 20:45:00,20.9543939621 2014-04-01 20:50:00,19.7230562872 2014-04-01 20:55:00,21.384939461400002 2014-04-01 21:00:00,21.2308845519 2014-04-01 21:05:00,21.839926692 2014-04-01 21:10:00,19.564559914500002 2014-04-01 21:15:00,20.8436384143 2014-04-01 21:20:00,20.5084352901 2014-04-01 21:25:00,20.197308185 2014-04-01 21:30:00,21.665161839899998 2014-04-01 21:35:00,18.0991300247 2014-04-01 21:40:00,19.2202629202 2014-04-01 21:45:00,20.2498438317 2014-04-01 21:50:00,18.802996231199998 2014-04-01 21:55:00,21.735297119200002 2014-04-01 22:00:00,20.6101472256 2014-04-01 22:05:00,19.9306470394 2014-04-01 22:10:00,21.279215480599998 2014-04-01 22:15:00,19.8225561591 2014-04-01 22:20:00,20.2540372653 2014-04-01 22:25:00,18.0282945372 2014-04-01 22:30:00,19.481486401199998 2014-04-01 22:35:00,18.5729748357 2014-04-01 22:40:00,20.778683117 2014-04-01 22:45:00,19.9352272896 2014-04-01 22:50:00,19.225468968599998 2014-04-01 22:55:00,19.8904058239 2014-04-01 23:00:00,18.8421365457 2014-04-01 23:05:00,21.7045129943 2014-04-01 23:10:00,18.2193879794 2014-04-01 23:15:00,21.4657887794 2014-04-01 23:20:00,20.049283876500002 2014-04-01 23:25:00,20.4797173335 2014-04-01 23:30:00,19.2141108829 2014-04-01 23:35:00,21.8709888888 2014-04-01 23:40:00,19.131076293699998 2014-04-01 23:45:00,20.3594202449 2014-04-01 23:50:00,21.9778857623 2014-04-01 23:55:00,21.5285102639 2014-04-02 00:00:00,20.1453193011 2014-04-02 00:05:00,21.9614980919 2014-04-02 00:10:00,20.8054794469 2014-04-02 00:15:00,18.8348016646 2014-04-02 00:20:00,19.6223848417 2014-04-02 00:25:00,19.337973335999997 2014-04-02 00:30:00,19.3760548331 2014-04-02 00:35:00,21.0418257574 2014-04-02 00:40:00,20.337051709100002 2014-04-02 00:45:00,18.1523708464 2014-04-02 00:50:00,21.5097939346 2014-04-02 00:55:00,19.1871845619 2014-04-02 01:00:00,21.9882995077 2014-04-02 01:05:00,21.8167629213 2014-04-02 01:10:00,21.7621228667 2014-04-02 01:15:00,21.244510416300002 2014-04-02 01:20:00,18.882453326700002 2014-04-02 01:25:00,20.130530976099998 2014-04-02 01:30:00,18.8972105073 2014-04-02 01:35:00,19.0387018224 2014-04-02 01:40:00,20.4438070777 2014-04-02 01:45:00,18.1633341814 2014-04-02 01:50:00,21.8778342673 2014-04-02 01:55:00,21.674692690300002 2014-04-02 02:00:00,19.5230702886 2014-04-02 02:05:00,20.061689792 2014-04-02 02:10:00,19.864477677100002 2014-04-02 02:15:00,21.528799114499996 2014-04-02 02:20:00,20.7544075053 2014-04-02 02:25:00,19.112444989700002 2014-04-02 02:30:00,19.7873650179 2014-04-02 02:35:00,19.7158639027 2014-04-02 02:40:00,21.837340673099998 2014-04-02 02:45:00,18.7012436421 2014-04-02 02:50:00,18.358305349200002 2014-04-02 02:55:00,21.522475328600002 2014-04-02 03:00:00,21.586743958000003 2014-04-02 03:05:00,21.4869563516 2014-04-02 03:10:00,20.0439076625 2014-04-02 03:15:00,20.6389777131 2014-04-02 03:20:00,20.2534521902 2014-04-02 03:25:00,18.2777913042 2014-04-02 03:30:00,20.3833395876 2014-04-02 03:35:00,18.054456589 2014-04-02 03:40:00,19.2999496382 2014-04-02 03:45:00,21.7291703035 2014-04-02 03:50:00,19.2161810785 2014-04-02 03:55:00,21.7593065706 2014-04-02 04:00:00,19.0005358286 2014-04-02 04:05:00,19.2582489618 2014-04-02 04:10:00,20.513629985799998 2014-04-02 04:15:00,21.046507891199997 2014-04-02 04:20:00,20.005551072 2014-04-02 04:25:00,21.528462748800006 2014-04-02 04:30:00,18.1609616864 2014-04-02 04:35:00,21.6887793545 2014-04-02 04:40:00,18.785231199600002 2014-04-02 04:45:00,21.536954980300003 2014-04-02 04:50:00,19.603452717899998 2014-04-02 04:55:00,21.3310282235 2014-04-02 05:00:00,20.6866621992 2014-04-02 05:05:00,18.7037665299 2014-04-02 05:10:00,21.672190279499997 2014-04-02 05:15:00,18.982069562 2014-04-02 05:20:00,18.9765604748 2014-04-02 05:25:00,21.2567155865 2014-04-02 05:30:00,18.4234930223 2014-04-02 05:35:00,18.8881436255 2014-04-02 05:40:00,20.0147102937 2014-04-02 05:45:00,21.3219081147 2014-04-02 05:50:00,18.589935898900002 2014-04-02 05:55:00,20.190672938 2014-04-02 06:00:00,20.8449623672 2014-04-02 06:05:00,21.4423808989 2014-04-02 06:10:00,21.7422622408 2014-04-02 06:15:00,21.1385596579 2014-04-02 06:20:00,20.6113135929 2014-04-02 06:25:00,19.7344803413 2014-04-02 06:30:00,18.4484406168 2014-04-02 06:35:00,20.8389487701 2014-04-02 06:40:00,21.9709492179 2014-04-02 06:45:00,20.9470423789 2014-04-02 06:50:00,18.066844375 2014-04-02 06:55:00,19.9850399122 2014-04-02 07:00:00,20.4585865299 2014-04-02 07:05:00,20.7586968044 2014-04-02 07:10:00,20.8789033424 2014-04-02 07:15:00,20.2324337649 2014-04-02 07:20:00,18.8934413309 2014-04-02 07:25:00,21.768802645900003 2014-04-02 07:30:00,20.7866658707 2014-04-02 07:35:00,18.9473601475 2014-04-02 07:40:00,19.289287329100002 2014-04-02 07:45:00,21.6877106825 2014-04-02 07:50:00,21.549940746799997 2014-04-02 07:55:00,19.6205857534 2014-04-02 08:00:00,18.153228888 2014-04-02 08:05:00,18.1939894756 2014-04-02 08:10:00,19.135673163699998 2014-04-02 08:15:00,20.5164888774 2014-04-02 08:20:00,20.336778541300003 2014-04-02 08:25:00,20.535311147799998 2014-04-02 08:30:00,20.8691318877 2014-04-02 08:35:00,18.0761290144 2014-04-02 08:40:00,18.4203423807 2014-04-02 08:45:00,19.4379338073 2014-04-02 08:50:00,18.6194399901 2014-04-02 08:55:00,18.3012801702 2014-04-02 09:00:00,69.9171157856 2014-04-02 09:05:00,72.2885760939 2014-04-02 09:10:00,71.43572254109999 2014-04-02 09:15:00,72.3117409891 2014-04-02 09:20:00,70.2556489992 2014-04-02 09:25:00,71.2006963767 2014-04-02 09:30:00,64.89619132920001 2014-04-02 09:35:00,74.70490929350001 2014-04-02 09:40:00,63.691052901099994 2014-04-02 09:45:00,64.1171166917 2014-04-02 09:50:00,65.1293369127 2014-04-02 09:55:00,74.46452104939999 2014-04-02 10:00:00,85.1782389068 2014-04-02 10:05:00,82.1767509954 2014-04-02 10:10:00,79.6029739296 2014-04-02 10:15:00,77.9113711669 2014-04-02 10:20:00,84.9040355251 2014-04-02 10:25:00,80.6360659004 2014-04-02 10:30:00,84.5022115916 2014-04-02 10:35:00,74.7528684079 2014-04-02 10:40:00,75.02018477600001 2014-04-02 10:45:00,83.10532570069999 2014-04-02 10:50:00,72.1657483675 2014-04-02 10:55:00,84.5208004073 2014-04-02 11:00:00,79.6388721366 2014-04-02 11:05:00,86.301686325 2014-04-02 11:10:00,76.9243525119 2014-04-02 11:15:00,82.9546104114 2014-04-02 11:20:00,79.2476459399 2014-04-02 11:25:00,81.5366849354 2014-04-02 11:30:00,79.5895401309 2014-04-02 11:35:00,86.94900677870001 2014-04-02 11:40:00,82.5752442468 2014-04-02 11:45:00,75.56497687699999 2014-04-02 11:50:00,86.03550176600002 2014-04-02 11:55:00,76.2442489556 2014-04-02 12:00:00,77.8521467709 2014-04-02 12:05:00,73.5456183933 2014-04-02 12:10:00,86.29578495959998 2014-04-02 12:15:00,76.4858990208 2014-04-02 12:20:00,76.0513106686 2014-04-02 12:25:00,86.620132526 2014-04-02 12:30:00,84.7865636827 2014-04-02 12:35:00,74.168154029 2014-04-02 12:40:00,84.208021032 2014-04-02 12:45:00,86.5045993334 2014-04-02 12:50:00,73.16827207600001 2014-04-02 12:55:00,85.1011957906 2014-04-02 13:00:00,80.739338737 2014-04-02 13:05:00,82.6873094719 2014-04-02 13:10:00,79.8664968618 2014-04-02 13:15:00,83.1448897946 2014-04-02 13:20:00,72.5281548509 2014-04-02 13:25:00,84.1830987778 2014-04-02 13:30:00,72.5160911259 2014-04-02 13:35:00,79.2657692125 2014-04-02 13:40:00,74.3975801845 2014-04-02 13:45:00,85.1567459124 2014-04-02 13:50:00,77.00009008890001 2014-04-02 13:55:00,79.2464729945 2014-04-02 14:00:00,78.8562265802 2014-04-02 14:05:00,84.3559821694 2014-04-02 14:10:00,79.6944842379 2014-04-02 14:15:00,84.61927144020001 2014-04-02 14:20:00,73.1726199745 2014-04-02 14:25:00,75.06190034229999 2014-04-02 14:30:00,80.820668416 2014-04-02 14:35:00,87.14922983219999 2014-04-02 14:40:00,73.1926121335 2014-04-02 14:45:00,72.6858583698 2014-04-02 14:50:00,74.5012345679 2014-04-02 14:55:00,82.2545016562 2014-04-02 15:00:00,78.38313418140001 2014-04-02 15:05:00,85.2080200658 2014-04-02 15:10:00,73.15022817479999 2014-04-02 15:15:00,75.1419040198 2014-04-02 15:20:00,76.7996852034 2014-04-02 15:25:00,82.0268939213 2014-04-02 15:30:00,82.9619666023 2014-04-02 15:35:00,73.9865424258 2014-04-02 15:40:00,87.10003917549999 2014-04-02 15:45:00,77.4559625787 2014-04-02 15:50:00,83.4098994653 2014-04-02 15:55:00,80.38655178489999 2014-04-02 16:00:00,75.5639847336 2014-04-02 16:05:00,85.5394889337 2014-04-02 16:10:00,85.0916450748 2014-04-02 16:15:00,78.3369992553 2014-04-02 16:20:00,81.41756504909999 2014-04-02 16:25:00,76.1250649746 2014-04-02 16:30:00,83.0374666277 2014-04-02 16:35:00,76.9442812686 2014-04-02 16:40:00,85.50509558 2014-04-02 16:45:00,75.4780167504 2014-04-02 16:50:00,72.23671607029999 2014-04-02 16:55:00,76.2959821829 2014-04-02 17:00:00,75.05681096149999 2014-04-02 17:05:00,80.1325522647 2014-04-02 17:10:00,75.259223767 2014-04-02 17:15:00,84.2110055945 2014-04-02 17:20:00,75.8619010771 2014-04-02 17:25:00,83.311458887 2014-04-02 17:30:00,81.2555035661 2014-04-02 17:35:00,87.779963996 2014-04-02 17:40:00,87.9983818408 2014-04-02 17:45:00,85.91238434270002 2014-04-02 17:50:00,84.15970159140001 2014-04-02 17:55:00,78.1832726016 2014-04-02 18:00:00,33.6209645984 2014-04-02 18:05:00,34.9227167321 2014-04-02 18:10:00,28.9496109242 2014-04-02 18:15:00,32.2426478907 2014-04-02 18:20:00,30.1951833506 2014-04-02 18:25:00,32.3704022064 2014-04-02 18:30:00,31.785255271700002 2014-04-02 18:35:00,32.4849126848 2014-04-02 18:40:00,32.3261520105 2014-04-02 18:45:00,34.9446783413 2014-04-02 18:50:00,32.3339848891 2014-04-02 18:55:00,34.2158787945 2014-04-02 19:00:00,21.592793700300003 2014-04-02 19:05:00,22.1226898722 2014-04-02 19:10:00,22.2674511512 2014-04-02 19:15:00,21.4087004597 2014-04-02 19:20:00,21.861459172199996 2014-04-02 19:25:00,22.841337343000003 2014-04-02 19:30:00,22.7592399311 2014-04-02 19:35:00,23.0112290814 2014-04-02 19:40:00,21.7361430687 2014-04-02 19:45:00,21.574923914699998 2014-04-02 19:50:00,22.900046858499998 2014-04-02 19:55:00,20.755219494400002 2014-04-02 20:00:00,19.468416968699998 2014-04-02 20:05:00,18.6045549873 2014-04-02 20:10:00,18.7294138275 2014-04-02 20:15:00,19.4288976787 2014-04-02 20:20:00,18.51199171 2014-04-02 20:25:00,19.4372015519 2014-04-02 20:30:00,21.1147827659 2014-04-02 20:35:00,18.6822943692 2014-04-02 20:40:00,20.2208731896 2014-04-02 20:45:00,22.1720933252 2014-04-02 20:50:00,21.6731023992 2014-04-02 20:55:00,19.6830717732 2014-04-02 21:00:00,21.803378128600002 2014-04-02 21:05:00,19.4113151523 2014-04-02 21:10:00,18.3778542379 2014-04-02 21:15:00,22.081709647399997 2014-04-02 21:20:00,21.5831944885 2014-04-02 21:25:00,19.9590769938 2014-04-02 21:30:00,20.7647004752 2014-04-02 21:35:00,20.7841998397 2014-04-02 21:40:00,18.8680629356 2014-04-02 21:45:00,18.8904354202 2014-04-02 21:50:00,19.9737387141 2014-04-02 21:55:00,21.7501947116 2014-04-02 22:00:00,18.0572934667 2014-04-02 22:05:00,21.1503073551 2014-04-02 22:10:00,18.2476080287 2014-04-02 22:15:00,19.9320048227 2014-04-02 22:20:00,20.5712207539 2014-04-02 22:25:00,20.7669542137 2014-04-02 22:30:00,18.2514216059 2014-04-02 22:35:00,19.6933018978 2014-04-02 22:40:00,20.354870967100002 2014-04-02 22:45:00,18.2817157551 2014-04-02 22:50:00,18.5581769804 2014-04-02 22:55:00,20.67442436 2014-04-02 23:00:00,20.0904094025 2014-04-02 23:05:00,18.6508949277 2014-04-02 23:10:00,20.1448244095 2014-04-02 23:15:00,21.6549264394 2014-04-02 23:20:00,18.065818308599997 2014-04-02 23:25:00,20.5744846347 2014-04-02 23:30:00,18.298114300199998 2014-04-02 23:35:00,18.0292587233 2014-04-02 23:40:00,18.6061896555 2014-04-02 23:45:00,19.6954073178 2014-04-02 23:50:00,21.213448194 2014-04-02 23:55:00,19.130814395799998 2014-04-03 00:00:00,20.5026928496 2014-04-03 00:05:00,19.644626551800002 2014-04-03 00:10:00,18.9373271679 2014-04-03 00:15:00,20.0569884571 2014-04-03 00:20:00,21.1898579615 2014-04-03 00:25:00,21.3299694802 2014-04-03 00:30:00,21.3860781275 2014-04-03 00:35:00,19.3542312502 2014-04-03 00:40:00,21.1738242589 2014-04-03 00:45:00,18.8487138204 2014-04-03 00:50:00,20.953700405 2014-04-03 00:55:00,21.793537705100004 2014-04-03 01:00:00,18.054975338800002 2014-04-03 01:05:00,19.7614557247 2014-04-03 01:10:00,20.5910839537 2014-04-03 01:15:00,20.807103082 2014-04-03 01:20:00,18.7043510331 2014-04-03 01:25:00,21.888733101 2014-04-03 01:30:00,20.4610614719 2014-04-03 01:35:00,18.6573624049 2014-04-03 01:40:00,18.0820900469 2014-04-03 01:45:00,21.133056795199998 2014-04-03 01:50:00,18.3188189578 2014-04-03 01:55:00,18.5642036843 2014-04-03 02:00:00,20.2993201074 2014-04-03 02:05:00,20.4140220138 2014-04-03 02:10:00,20.747548474400002 2014-04-03 02:15:00,19.574056050699998 2014-04-03 02:20:00,21.0955946759 2014-04-03 02:25:00,21.8974343985 2014-04-03 02:30:00,19.0843797723 2014-04-03 02:35:00,20.8121144662 2014-04-03 02:40:00,21.7138746096 2014-04-03 02:45:00,20.745147050499998 2014-04-03 02:50:00,20.7244379946 2014-04-03 02:55:00,18.8950902763 2014-04-03 03:00:00,20.140520801300003 2014-04-03 03:05:00,20.2500913744 2014-04-03 03:10:00,20.8005182498 2014-04-03 03:15:00,21.9872857996 2014-04-03 03:20:00,18.1345752902 2014-04-03 03:25:00,18.2609306451 2014-04-03 03:30:00,18.3118002777 2014-04-03 03:35:00,20.971916538 2014-04-03 03:40:00,18.5454151804 2014-04-03 03:45:00,20.489807498 2014-04-03 03:50:00,19.298675511600003 2014-04-03 03:55:00,19.8292798248 2014-04-03 04:00:00,18.862652639300002 2014-04-03 04:05:00,21.4644262452 2014-04-03 04:10:00,20.344601296700002 2014-04-03 04:15:00,21.7782530543 2014-04-03 04:20:00,20.2983849988 2014-04-03 04:25:00,18.4956321224 2014-04-03 04:30:00,18.6834817354 2014-04-03 04:35:00,21.956295905500003 2014-04-03 04:40:00,20.9022607893 2014-04-03 04:45:00,18.1971150001 2014-04-03 04:50:00,20.8151240201 2014-04-03 04:55:00,19.6486921872 2014-04-03 05:00:00,19.2288335473 2014-04-03 05:05:00,18.6162431749 2014-04-03 05:10:00,21.359615818199998 2014-04-03 05:15:00,18.255365515999998 2014-04-03 05:20:00,19.1593418495 2014-04-03 05:25:00,19.2255315753 2014-04-03 05:30:00,18.6436211359 2014-04-03 05:35:00,20.0327395331 2014-04-03 05:40:00,18.0468105072 2014-04-03 05:45:00,19.2039020616 2014-04-03 05:50:00,21.734517776100002 2014-04-03 05:55:00,19.2421182774 2014-04-03 06:00:00,19.4418375484 2014-04-03 06:05:00,19.8926601929 2014-04-03 06:10:00,20.2467734994 2014-04-03 06:15:00,21.2348345793 2014-04-03 06:20:00,18.7612848926 2014-04-03 06:25:00,21.4869855088 2014-04-03 06:30:00,21.030197428599998 2014-04-03 06:35:00,20.8906013386 2014-04-03 06:40:00,18.3472182949 2014-04-03 06:45:00,18.0865627599 2014-04-03 06:50:00,20.3760508036 2014-04-03 06:55:00,21.4525358501 2014-04-03 07:00:00,20.3377658566 2014-04-03 07:05:00,18.852939461800002 2014-04-03 07:10:00,18.3620795918 2014-04-03 07:15:00,20.7983858113 2014-04-03 07:20:00,20.887081109300002 2014-04-03 07:25:00,18.6901268027 2014-04-03 07:30:00,18.112761262 2014-04-03 07:35:00,19.6331340529 2014-04-03 07:40:00,20.3308748085 2014-04-03 07:45:00,20.824009638299998 2014-04-03 07:50:00,21.2397800366 2014-04-03 07:55:00,20.442149709200002 2014-04-03 08:00:00,18.443522434400002 2014-04-03 08:05:00,20.730326688599998 2014-04-03 08:10:00,21.9367065716 2014-04-03 08:15:00,21.622338338400002 2014-04-03 08:20:00,21.4866756371 2014-04-03 08:25:00,19.2086806134 2014-04-03 08:30:00,21.003152705799998 2014-04-03 08:35:00,21.4044137839 2014-04-03 08:40:00,20.7133048185 2014-04-03 08:45:00,19.0022470263 2014-04-03 08:50:00,21.8153358875 2014-04-03 08:55:00,19.803277645799998 2014-04-03 09:00:00,62.9653555979 2014-04-03 09:05:00,62.692979372799996 2014-04-03 09:10:00,70.0062582273 2014-04-03 09:15:00,67.1528511913 2014-04-03 09:20:00,62.484980702399994 2014-04-03 09:25:00,71.26895818130002 2014-04-03 09:30:00,72.0708222747 2014-04-03 09:35:00,71.0656525787 2014-04-03 09:40:00,63.950747936499994 2014-04-03 09:45:00,70.5809462015 2014-04-03 09:50:00,61.3458301194 2014-04-03 09:55:00,65.3495250996 2014-04-03 10:00:00,76.0297101674 2014-04-03 10:05:00,82.8030326467 2014-04-03 10:10:00,75.89892067 2014-04-03 10:15:00,70.01490180489999 2014-04-03 10:20:00,75.3084163116 2014-04-03 10:25:00,77.58330200649999 2014-04-03 10:30:00,84.5685542892 2014-04-03 10:35:00,84.4448523948 2014-04-03 10:40:00,72.6471650732 2014-04-03 10:45:00,72.7134743278 2014-04-03 10:50:00,72.3756802043 2014-04-03 10:55:00,82.08406839109999 2014-04-03 11:00:00,71.66377453 2014-04-03 11:05:00,73.59062616 2014-04-03 11:10:00,80.1237099817 2014-04-03 11:15:00,75.5052271118 2014-04-03 11:20:00,73.0368371118 2014-04-03 11:25:00,77.2914999082 2014-04-03 11:30:00,75.9289977509 2014-04-03 11:35:00,79.6966028908 2014-04-03 11:40:00,87.14173107629999 2014-04-03 11:45:00,73.5449409439 2014-04-03 11:50:00,77.4958455137 2014-04-03 11:55:00,86.3902897242 2014-04-03 12:00:00,85.9267327335 2014-04-03 12:05:00,78.2143665527 2014-04-03 12:10:00,83.0834323296 2014-04-03 12:15:00,73.3176253626 2014-04-03 12:20:00,83.3005761004 2014-04-03 12:25:00,87.4606448033 2014-04-03 12:30:00,80.5030906728 2014-04-03 12:35:00,79.8798726202 2014-04-03 12:40:00,74.9071013977 2014-04-03 12:45:00,82.0420424491 2014-04-03 12:50:00,81.34926009670002 2014-04-03 12:55:00,82.3320118369 2014-04-03 13:00:00,72.3999524271 2014-04-03 13:05:00,80.7601887154 2014-04-03 13:10:00,81.4993929462 2014-04-03 13:15:00,75.30240525090001 2014-04-03 13:20:00,75.3152457216 2014-04-03 13:25:00,76.4011500184 2014-04-03 13:30:00,83.3675324567 2014-04-03 13:35:00,81.68064895479999 2014-04-03 13:40:00,85.5116746093 2014-04-03 13:45:00,76.7121218206 2014-04-03 13:50:00,86.57230661690002 2014-04-03 13:55:00,83.8791627601 2014-04-03 14:00:00,78.3164273513 2014-04-03 14:05:00,73.5206638887 2014-04-03 14:10:00,76.1080852363 2014-04-03 14:15:00,87.3041006774 2014-04-03 14:20:00,76.9621196551 2014-04-03 14:25:00,77.2747059984 2014-04-03 14:30:00,75.0298212933 2014-04-03 14:35:00,84.905533957 2014-04-03 14:40:00,76.4066399891 2014-04-03 14:45:00,77.28042233560001 2014-04-03 14:50:00,78.6257955156 2014-04-03 14:55:00,78.9358633731 2014-04-03 15:00:00,78.5806982647 2014-04-03 15:05:00,80.05913055100001 2014-04-03 15:10:00,85.03138976470001 2014-04-03 15:15:00,85.10774360970001 2014-04-03 15:20:00,84.77219631930001 2014-04-03 15:25:00,73.6172906931 2014-04-03 15:30:00,84.79404682170002 2014-04-03 15:35:00,73.9233187051 2014-04-03 15:40:00,73.9948699633 2014-04-03 15:45:00,87.16496755440002 2014-04-03 15:50:00,85.1095484558 2014-04-03 15:55:00,80.8377914196 2014-04-03 16:00:00,85.9993581526 2014-04-03 16:05:00,87.8296656475 2014-04-03 16:10:00,81.77011606720001 2014-04-03 16:15:00,81.8062179235 2014-04-03 16:20:00,84.0706710506 2014-04-03 16:25:00,75.71407786649999 2014-04-03 16:30:00,74.67385441020001 2014-04-03 16:35:00,84.1531304259 2014-04-03 16:40:00,77.5183278844 2014-04-03 16:45:00,74.16098331149999 2014-04-03 16:50:00,77.0378957016 2014-04-03 16:55:00,77.7380406287 2014-04-03 17:00:00,87.44360897370001 2014-04-03 17:05:00,83.1673234411 2014-04-03 17:10:00,80.4936701688 2014-04-03 17:15:00,87.50193661819998 2014-04-03 17:20:00,86.45020265069998 2014-04-03 17:25:00,80.1919829121 2014-04-03 17:30:00,86.4908409535 2014-04-03 17:35:00,78.468844397 2014-04-03 17:40:00,75.686701582 2014-04-03 17:45:00,75.7228217516 2014-04-03 17:50:00,82.5970166738 2014-04-03 17:55:00,80.0170944047 2014-04-03 18:00:00,33.0172790815 2014-04-03 18:05:00,33.1908797986 2014-04-03 18:10:00,28.9428608295 2014-04-03 18:15:00,29.145847795 2014-04-03 18:20:00,32.209131266 2014-04-03 18:25:00,30.0226212933 2014-04-03 18:30:00,32.8482098135 2014-04-03 18:35:00,32.3339825226 2014-04-03 18:40:00,32.5488600442 2014-04-03 18:45:00,30.7357085297 2014-04-03 18:50:00,32.894992124299996 2014-04-03 18:55:00,34.1087463246 2014-04-03 19:00:00,24.631357864899996 2014-04-03 19:05:00,23.916229538099998 2014-04-03 19:10:00,22.6575932004 2014-04-03 19:15:00,21.0265634173 2014-04-03 19:20:00,23.212876251599997 2014-04-03 19:25:00,24.3606876229 2014-04-03 19:30:00,21.10916094 2014-04-03 19:35:00,21.306859211099997 2014-04-03 19:40:00,20.8275571319 2014-04-03 19:45:00,23.4605116765 2014-04-03 19:50:00,21.9813943295 2014-04-03 19:55:00,20.4408753409 2014-04-03 20:00:00,22.015794901 2014-04-03 20:05:00,20.7162238731 2014-04-03 20:10:00,19.7881619826 2014-04-03 20:15:00,19.8409540319 2014-04-03 20:20:00,19.6208687625 2014-04-03 20:25:00,20.2976465425 2014-04-03 20:30:00,19.8125225183 2014-04-03 20:35:00,20.676387813399998 2014-04-03 20:40:00,21.600326406100002 2014-04-03 20:45:00,21.1945931627 2014-04-03 20:50:00,19.6380951971 2014-04-03 20:55:00,20.5977229361 2014-04-03 21:00:00,21.463035009400002 2014-04-03 21:05:00,18.3605344538 2014-04-03 21:10:00,18.4010923305 2014-04-03 21:15:00,20.3217586878 2014-04-03 21:20:00,20.6551314735 2014-04-03 21:25:00,18.9361111467 2014-04-03 21:30:00,21.0815886816 2014-04-03 21:35:00,20.6838617144 2014-04-03 21:40:00,21.7972841736 2014-04-03 21:45:00,18.7654606822 2014-04-03 21:50:00,21.1063233957 2014-04-03 21:55:00,18.422578264600002 2014-04-03 22:00:00,20.280620351 2014-04-03 22:05:00,20.2269798254 2014-04-03 22:10:00,19.5723115675 2014-04-03 22:15:00,21.398807733399998 2014-04-03 22:20:00,18.034779353599998 2014-04-03 22:25:00,20.0999950866 2014-04-03 22:30:00,18.8867280597 2014-04-03 22:35:00,20.994129500899998 2014-04-03 22:40:00,18.1897150752 2014-04-03 22:45:00,21.3466919122 2014-04-03 22:50:00,21.3728671705 2014-04-03 22:55:00,21.3519422446 2014-04-03 23:00:00,18.6138472777 2014-04-03 23:05:00,20.525566224400002 2014-04-03 23:10:00,18.0609364691 2014-04-03 23:15:00,21.3959575983 2014-04-03 23:20:00,20.895912016900002 2014-04-03 23:25:00,20.1284788477 2014-04-03 23:30:00,20.9263828246 2014-04-03 23:35:00,18.3808248257 2014-04-03 23:40:00,20.1184853344 2014-04-03 23:45:00,19.1687856657 2014-04-03 23:50:00,21.8946808225 2014-04-03 23:55:00,21.432586067 2014-04-04 00:00:00,20.9331027833 2014-04-04 00:05:00,21.734990541 2014-04-04 00:10:00,19.3873732183 2014-04-04 00:15:00,21.603519595999998 2014-04-04 00:20:00,19.300952928399997 2014-04-04 00:25:00,20.931186878800002 2014-04-04 00:30:00,20.9456676471 2014-04-04 00:35:00,18.073399505799998 2014-04-04 00:40:00,19.4442387931 2014-04-04 00:45:00,18.0777306896 2014-04-04 00:50:00,21.9883680704 2014-04-04 00:55:00,18.4887870473 2014-04-04 01:00:00,20.1712435826 2014-04-04 01:05:00,21.1622249551 2014-04-04 01:10:00,18.805054409 2014-04-04 01:15:00,19.9402106724 2014-04-04 01:20:00,20.4297150437 2014-04-04 01:25:00,18.6408190176 2014-04-04 01:30:00,21.1142218396 2014-04-04 01:35:00,19.1973458288 2014-04-04 01:40:00,18.8440923054 2014-04-04 01:45:00,20.2331549857 2014-04-04 01:50:00,19.6412545106 2014-04-04 01:55:00,21.681143778499997 2014-04-04 02:00:00,21.520250792800002 2014-04-04 02:05:00,19.933402653599998 2014-04-04 02:10:00,19.4370550989 2014-04-04 02:15:00,19.302071926500002 2014-04-04 02:20:00,19.070254492300002 2014-04-04 02:25:00,20.1781914149 2014-04-04 02:30:00,21.2199144189 2014-04-04 02:35:00,19.2430264328 2014-04-04 02:40:00,18.760376358800002 2014-04-04 02:45:00,19.9019352247 2014-04-04 02:50:00,18.2761376672 2014-04-04 02:55:00,20.805116024500002 2014-04-04 03:00:00,20.0734330652 2014-04-04 03:05:00,19.9854992319 2014-04-04 03:10:00,19.2017815182 2014-04-04 03:15:00,21.618693750100004 2014-04-04 03:20:00,18.361945167400002 2014-04-04 03:25:00,21.479296035500003 2014-04-04 03:30:00,19.5068208097 2014-04-04 03:35:00,21.522494063899998 2014-04-04 03:40:00,20.9150458333 2014-04-04 03:45:00,18.416682906600002 2014-04-04 03:50:00,21.326145145999998 2014-04-04 03:55:00,20.7287073348 2014-04-04 04:00:00,18.1292076517 2014-04-04 04:05:00,18.5348107284 2014-04-04 04:10:00,20.542512223299997 2014-04-04 04:15:00,20.650402011500002 2014-04-04 04:20:00,20.9866057314 2014-04-04 04:25:00,20.8809816031 2014-04-04 04:30:00,20.6380798187 2014-04-04 04:35:00,21.064955607 2014-04-04 04:40:00,20.300342823599998 2014-04-04 04:45:00,19.0431655421 2014-04-04 04:50:00,21.6495064549 2014-04-04 04:55:00,18.0728561237 2014-04-04 05:00:00,19.4662468795 2014-04-04 05:05:00,20.9154811724 2014-04-04 05:10:00,19.7086241646 2014-04-04 05:15:00,18.0993376299 2014-04-04 05:20:00,18.2639236125 2014-04-04 05:25:00,20.5945494766 2014-04-04 05:30:00,21.8594583976 2014-04-04 05:35:00,20.2074545433 2014-04-04 05:40:00,20.0270312721 2014-04-04 05:45:00,19.273300852200002 2014-04-04 05:50:00,19.0267626955 2014-04-04 05:55:00,18.083939927 2014-04-04 06:00:00,19.0918194706 2014-04-04 06:05:00,19.7964417635 2014-04-04 06:10:00,18.7917991322 2014-04-04 06:15:00,18.3493919539 2014-04-04 06:20:00,20.870911469 2014-04-04 06:25:00,21.5784810763 2014-04-04 06:30:00,21.747088278699998 2014-04-04 06:35:00,20.471994914 2014-04-04 06:40:00,18.2110983304 2014-04-04 06:45:00,20.9634505198 2014-04-04 06:50:00,18.440381221 2014-04-04 06:55:00,20.6789924708 2014-04-04 07:00:00,21.117463343 2014-04-04 07:05:00,20.903458843299997 2014-04-04 07:10:00,21.807535223000002 2014-04-04 07:15:00,20.952585137899998 2014-04-04 07:20:00,20.7728391119 2014-04-04 07:25:00,19.0469726887 2014-04-04 07:30:00,21.699074745700003 2014-04-04 07:35:00,18.7181754832 2014-04-04 07:40:00,21.6195864459 2014-04-04 07:45:00,19.2506501734 2014-04-04 07:50:00,18.5206543755 2014-04-04 07:55:00,21.3067321091 2014-04-04 08:00:00,18.0099818144 2014-04-04 08:05:00,21.3283532707 2014-04-04 08:10:00,19.0492473682 2014-04-04 08:15:00,21.538885090999997 2014-04-04 08:20:00,20.765916729 2014-04-04 08:25:00,20.6647333314 2014-04-04 08:30:00,19.4612782527 2014-04-04 08:35:00,18.2376118956 2014-04-04 08:40:00,21.3202923928 2014-04-04 08:45:00,18.6836151807 2014-04-04 08:50:00,19.4890345676 2014-04-04 08:55:00,20.401418742 2014-04-04 09:00:00,67.7586508444 2014-04-04 09:05:00,63.9017846383 2014-04-04 09:10:00,63.1123824536 2014-04-04 09:15:00,62.87614930260001 2014-04-04 09:20:00,72.9369071884 2014-04-04 09:25:00,61.629209867200004 2014-04-04 09:30:00,74.4873939306 2014-04-04 09:35:00,63.899990189200004 2014-04-04 09:40:00,62.7003832376 2014-04-04 09:45:00,69.046814505 2014-04-04 09:50:00,62.28780902800001 2014-04-04 09:55:00,69.39336437899999 2014-04-04 10:00:00,83.0417255275 2014-04-04 10:05:00,70.5833772932 2014-04-04 10:10:00,82.2539607423 2014-04-04 10:15:00,75.962289884 2014-04-04 10:20:00,72.3152946371 2014-04-04 10:25:00,72.5730173738 2014-04-04 10:30:00,84.0992257181 2014-04-04 10:35:00,71.5566012701 2014-04-04 10:40:00,83.292468856 2014-04-04 10:45:00,78.2866765177 2014-04-04 10:50:00,70.4461518952 2014-04-04 10:55:00,77.0486697815 2014-04-04 11:00:00,84.5687170782 2014-04-04 11:05:00,83.1175291346 2014-04-04 11:10:00,79.3415955709 2014-04-04 11:15:00,85.2462332867 2014-04-04 11:20:00,73.4822811714 2014-04-04 11:25:00,86.0397025132 2014-04-04 11:30:00,85.0298009797 2014-04-04 11:35:00,82.8324346353 2014-04-04 11:40:00,84.5756866508 2014-04-04 11:45:00,80.2168418208 2014-04-04 11:50:00,82.30578327239999 2014-04-04 11:55:00,80.4837517165 2014-04-04 12:00:00,77.5936322603 2014-04-04 12:05:00,81.0044506305 2014-04-04 12:10:00,76.0281019861 2014-04-04 12:15:00,78.9496133734 2014-04-04 12:20:00,76.4006156283 2014-04-04 12:25:00,73.8774451858 2014-04-04 12:30:00,77.0572099546 2014-04-04 12:35:00,85.52903733640001 2014-04-04 12:40:00,78.0035755795 2014-04-04 12:45:00,83.8672967134 2014-04-04 12:50:00,74.713401869 2014-04-04 12:55:00,78.69615769880002 2014-04-04 13:00:00,73.8199760621 2014-04-04 13:05:00,74.200124709 2014-04-04 13:10:00,81.8593311225 2014-04-04 13:15:00,81.70009634899999 2014-04-04 13:20:00,75.39585116960002 2014-04-04 13:25:00,79.57166932359999 2014-04-04 13:30:00,85.79230357600001 2014-04-04 13:35:00,74.769275205 2014-04-04 13:40:00,72.2900147607 2014-04-04 13:45:00,82.4121385893 2014-04-04 13:50:00,72.8384858963 2014-04-04 13:55:00,87.6580008466 2014-04-04 14:00:00,81.7500003524 2014-04-04 14:05:00,79.5225243811 2014-04-04 14:10:00,78.8760944061 2014-04-04 14:15:00,81.165234418 2014-04-04 14:20:00,73.44646538800001 2014-04-04 14:25:00,86.8761346865 2014-04-04 14:30:00,82.00633660369998 2014-04-04 14:35:00,74.9400586663 2014-04-04 14:40:00,80.997408798 2014-04-04 14:45:00,74.1285457523 2014-04-04 14:50:00,72.2773740004 2014-04-04 14:55:00,82.0843315264 2014-04-04 15:00:00,82.3749426629 2014-04-04 15:05:00,81.3383644691 2014-04-04 15:10:00,74.9350118867 2014-04-04 15:15:00,81.6540938491 2014-04-04 15:20:00,72.9034751747 2014-04-04 15:25:00,81.7470289101 2014-04-04 15:30:00,80.8634960087 2014-04-04 15:35:00,82.4832854463 2014-04-04 15:40:00,86.326780947 2014-04-04 15:45:00,85.6049078688 2014-04-04 15:50:00,87.68962523649998 2014-04-04 15:55:00,87.6190153764 2014-04-04 16:00:00,84.3569531283 2014-04-04 16:05:00,87.3025463336 2014-04-04 16:10:00,85.8763772913 2014-04-04 16:15:00,83.641158607 2014-04-04 16:20:00,73.2060075185 2014-04-04 16:25:00,72.7846584655 2014-04-04 16:30:00,85.40142910899999 2014-04-04 16:35:00,79.8343404437 2014-04-04 16:40:00,85.0335436853 2014-04-04 16:45:00,77.0065444776 2014-04-04 16:50:00,78.3622472774 2014-04-04 16:55:00,83.2028277865 2014-04-04 17:00:00,86.6451945191 2014-04-04 17:05:00,73.4041554045 2014-04-04 17:10:00,85.7836173732 2014-04-04 17:15:00,84.68817107779999 2014-04-04 17:20:00,77.048598745 2014-04-04 17:25:00,77.6834359957 2014-04-04 17:30:00,72.7433557021 2014-04-04 17:35:00,72.2518220332 2014-04-04 17:40:00,79.632067443 2014-04-04 17:45:00,73.52860609300001 2014-04-04 17:50:00,75.10400019069999 2014-04-04 17:55:00,85.54824234189999 2014-04-04 18:00:00,32.4545754727 2014-04-04 18:05:00,32.8552412903 2014-04-04 18:10:00,29.9998619573 2014-04-04 18:15:00,34.1034290006 2014-04-04 18:20:00,34.3550639474 2014-04-04 18:25:00,32.1492904271 2014-04-04 18:30:00,34.6403630891 2014-04-04 18:35:00,34.206896631999996 2014-04-04 18:40:00,33.4804683025 2014-04-04 18:45:00,33.498079428800004 2014-04-04 18:50:00,29.474512574200002 2014-04-04 18:55:00,30.5333447788 2014-04-04 19:00:00,20.4594744224 2014-04-04 19:05:00,20.198890709300002 2014-04-04 19:10:00,20.8692255558 2014-04-04 19:15:00,24.1045812559 2014-04-04 19:20:00,21.2346346196 2014-04-04 19:25:00,24.506288408099998 2014-04-04 19:30:00,22.835862425300004 2014-04-04 19:35:00,21.222916860399998 2014-04-04 19:40:00,22.3871447715 2014-04-04 19:45:00,21.1415436459 2014-04-04 19:50:00,24.5682001929 2014-04-04 19:55:00,23.9557458138 2014-04-04 20:00:00,18.5394738564 2014-04-04 20:05:00,22.3140903571 2014-04-04 20:10:00,21.3854824229 2014-04-04 20:15:00,18.769433383 2014-04-04 20:20:00,21.1789319548 2014-04-04 20:25:00,21.0818115019 2014-04-04 20:30:00,19.3281584709 2014-04-04 20:35:00,21.5385974248 2014-04-04 20:40:00,18.7886167993 2014-04-04 20:45:00,20.4367672171 2014-04-04 20:50:00,18.4726452349 2014-04-04 20:55:00,22.3999484857 2014-04-04 21:00:00,21.1070844972 2014-04-04 21:05:00,18.7248582187 2014-04-04 21:10:00,19.459656253800002 2014-04-04 21:15:00,18.7317322631 2014-04-04 21:20:00,21.1675888601 2014-04-04 21:25:00,18.323116066300003 2014-04-04 21:30:00,21.4641623775 2014-04-04 21:35:00,21.8732754715 2014-04-04 21:40:00,20.805902976800002 2014-04-04 21:45:00,18.9423506903 2014-04-04 21:50:00,19.5336740653 2014-04-04 21:55:00,20.0045224559 2014-04-04 22:00:00,20.4381008379 2014-04-04 22:05:00,20.6945000153 2014-04-04 22:10:00,20.2362670358 2014-04-04 22:15:00,19.4238847192 2014-04-04 22:20:00,21.584370234 2014-04-04 22:25:00,18.3431607686 2014-04-04 22:30:00,19.884094630499998 2014-04-04 22:35:00,21.1225175125 2014-04-04 22:40:00,18.261004403199998 2014-04-04 22:45:00,20.841329344200002 2014-04-04 22:50:00,21.2992741732 2014-04-04 22:55:00,20.6631427761 2014-04-04 23:00:00,18.0552135029 2014-04-04 23:05:00,18.7241424519 2014-04-04 23:10:00,19.3721710565 2014-04-04 23:15:00,18.9383956146 2014-04-04 23:20:00,21.8548038756 2014-04-04 23:25:00,20.6103320786 2014-04-04 23:30:00,19.1915679012 2014-04-04 23:35:00,21.7229600002 2014-04-04 23:40:00,20.9664015722 2014-04-04 23:45:00,19.142103423800002 2014-04-04 23:50:00,19.5192732567 2014-04-04 23:55:00,18.8013245927 2014-04-05 00:00:00,21.8842959931 2014-04-05 00:05:00,20.0691859836 2014-04-05 00:10:00,21.58422675 2014-04-05 00:15:00,19.3859990841 2014-04-05 00:20:00,21.4433664124 2014-04-05 00:25:00,18.2155473937 2014-04-05 00:30:00,21.9283612701 2014-04-05 00:35:00,21.6481374681 2014-04-05 00:40:00,19.4528117791 2014-04-05 00:45:00,21.098888661300002 2014-04-05 00:50:00,21.0090317059 2014-04-05 00:55:00,21.6050191884 2014-04-05 01:00:00,19.2290199245 2014-04-05 01:05:00,19.862080021300002 2014-04-05 01:10:00,21.4599984504 2014-04-05 01:15:00,21.1143178165 2014-04-05 01:20:00,19.573866875 2014-04-05 01:25:00,21.382900931600002 2014-04-05 01:30:00,18.187816156900002 2014-04-05 01:35:00,21.1281852119 2014-04-05 01:40:00,18.8270634377 2014-04-05 01:45:00,19.1444836313 2014-04-05 01:50:00,19.972859374400002 2014-04-05 01:55:00,19.798938004300002 2014-04-05 02:00:00,20.0822804275 2014-04-05 02:05:00,20.1791023827 2014-04-05 02:10:00,19.3261107641 2014-04-05 02:15:00,18.7009100521 2014-04-05 02:20:00,21.0739249171 2014-04-05 02:25:00,19.5999045963 2014-04-05 02:30:00,20.0233634498 2014-04-05 02:35:00,20.5787868734 2014-04-05 02:40:00,21.6385516892 2014-04-05 02:45:00,20.8302113246 2014-04-05 02:50:00,18.1818369024 2014-04-05 02:55:00,21.3542414536 2014-04-05 03:00:00,21.957420060500002 2014-04-05 03:05:00,19.889940101500002 2014-04-05 03:10:00,21.8783613458 2014-04-05 03:15:00,20.1893149694 2014-04-05 03:20:00,19.8384639835 2014-04-05 03:25:00,19.325619058900003 2014-04-05 03:30:00,20.630219503299998 2014-04-05 03:35:00,18.9192816821 2014-04-05 03:40:00,18.4197368741 2014-04-05 03:45:00,18.1089484103 2014-04-05 03:50:00,19.1695204509 2014-04-05 03:55:00,19.5830833287 2014-04-05 04:00:00,20.2083067851 2014-04-05 04:05:00,19.1709993007 2014-04-05 04:10:00,21.936238289499997 2014-04-05 04:15:00,19.166980673 2014-04-05 04:20:00,19.7639015538 2014-04-05 04:25:00,18.4131046621 2014-04-05 04:30:00,19.0425060533 2014-04-05 04:35:00,18.1933285592 2014-04-05 04:40:00,20.2380345337 2014-04-05 04:45:00,21.0042587325 2014-04-05 04:50:00,18.7828392573 2014-04-05 04:55:00,19.4716437513 2014-04-05 05:00:00,18.066464906900002 2014-04-05 05:05:00,21.3580882229 2014-04-05 05:10:00,21.1198540997 2014-04-05 05:15:00,18.2530161235 2014-04-05 05:20:00,19.4594704373 2014-04-05 05:25:00,21.8211464554 2014-04-05 05:30:00,19.5681082243 2014-04-05 05:35:00,20.1048347069 2014-04-05 05:40:00,19.420971444 2014-04-05 05:45:00,20.3845255525 2014-04-05 05:50:00,21.9126275025 2014-04-05 05:55:00,21.990010013899997 2014-04-05 06:00:00,21.098859912 2014-04-05 06:05:00,19.6172443921 2014-04-05 06:10:00,19.9777288033 2014-04-05 06:15:00,19.4269253124 2014-04-05 06:20:00,21.9422985196 2014-04-05 06:25:00,20.831041223299998 2014-04-05 06:30:00,19.7957257817 2014-04-05 06:35:00,18.0484610804 2014-04-05 06:40:00,20.0819336576 2014-04-05 06:45:00,21.935712806799998 2014-04-05 06:50:00,20.092243635899997 2014-04-05 06:55:00,18.729706742 2014-04-05 07:00:00,18.0883749884 2014-04-05 07:05:00,19.4188150325 2014-04-05 07:10:00,21.6729122228 2014-04-05 07:15:00,21.9862164327 2014-04-05 07:20:00,21.7814718992 2014-04-05 07:25:00,20.917679973 2014-04-05 07:30:00,20.2325709138 2014-04-05 07:35:00,20.3627445855 2014-04-05 07:40:00,20.1559680364 2014-04-05 07:45:00,20.8281972197 2014-04-05 07:50:00,19.675492906800002 2014-04-05 07:55:00,20.6768160198 2014-04-05 08:00:00,18.486448459800002 2014-04-05 08:05:00,19.0627812262 2014-04-05 08:10:00,21.3440121552 2014-04-05 08:15:00,21.614995723000003 2014-04-05 08:20:00,20.1560329502 2014-04-05 08:25:00,18.126542468900002 2014-04-05 08:30:00,21.7078942832 2014-04-05 08:35:00,20.808257032100002 2014-04-05 08:40:00,19.656111695 2014-04-05 08:45:00,20.3935157728 2014-04-05 08:50:00,19.7190993378 2014-04-05 08:55:00,19.8613569069 2014-04-05 09:00:00,73.26061417300001 2014-04-05 09:05:00,63.3907457581 2014-04-05 09:10:00,62.60990024260001 2014-04-05 09:15:00,61.237110925399996 2014-04-05 09:20:00,65.4704051083 2014-04-05 09:25:00,63.2048272242 2014-04-05 09:30:00,64.1918027339 2014-04-05 09:35:00,61.3528501642 2014-04-05 09:40:00,64.28985763979999 2014-04-05 09:45:00,65.7248775143 2014-04-05 09:50:00,61.6293179512 2014-04-05 09:55:00,69.4674960904 2014-04-05 10:00:00,78.6677814147 2014-04-05 10:05:00,71.3459952825 2014-04-05 10:10:00,79.0745517471 2014-04-05 10:15:00,85.3391088168 2014-04-05 10:20:00,84.49815814760001 2014-04-05 10:25:00,69.8814538171 2014-04-05 10:30:00,82.18427139180001 2014-04-05 10:35:00,75.3279538872 2014-04-05 10:40:00,70.82786926760001 2014-04-05 10:45:00,74.43365947689999 2014-04-05 10:50:00,74.83335073319999 2014-04-05 10:55:00,77.96075059409999 2014-04-05 11:00:00,82.0818762346 2014-04-05 11:05:00,83.4809804566 2014-04-05 11:10:00,75.4788419889 2014-04-05 11:15:00,76.68543914920002 2014-04-05 11:20:00,76.4725026659 2014-04-05 11:25:00,77.3369671506 2014-04-05 11:30:00,87.4665339376 2014-04-05 11:35:00,83.9404102882 2014-04-05 11:40:00,87.07424835959999 2014-04-05 11:45:00,82.59123829100001 2014-04-05 11:50:00,78.02932923899999 2014-04-05 11:55:00,77.76649149640001 2014-04-05 12:00:00,79.7215175616 2014-04-05 12:05:00,78.57551263399999 2014-04-05 12:10:00,85.1509160736 2014-04-05 12:15:00,79.3447041698 2014-04-05 12:20:00,76.63775396770001 2014-04-05 12:25:00,84.296486982 2014-04-05 12:30:00,85.5679216782 2014-04-05 12:35:00,78.6323910623 2014-04-05 12:40:00,82.5857152259 2014-04-05 12:45:00,72.85334349520001 2014-04-05 12:50:00,80.3748719064 2014-04-05 12:55:00,72.6324345661 2014-04-05 13:00:00,72.4496613551 2014-04-05 13:05:00,81.78716397689999 2014-04-05 13:10:00,76.83492131050001 2014-04-05 13:15:00,83.8604632566 2014-04-05 13:20:00,86.3166000131 2014-04-05 13:25:00,74.21244351760001 2014-04-05 13:30:00,83.5723032496 2014-04-05 13:35:00,80.2130642158 2014-04-05 13:40:00,73.7761974647 2014-04-05 13:45:00,82.4056995881 2014-04-05 13:50:00,81.7318484972 2014-04-05 13:55:00,80.2310098136 2014-04-05 14:00:00,86.81937174309998 2014-04-05 14:05:00,80.3334189485 2014-04-05 14:10:00,87.84402513159998 2014-04-05 14:15:00,80.1438139338 2014-04-05 14:20:00,73.8500876385 2014-04-05 14:25:00,79.5237226953 2014-04-05 14:30:00,74.9136641724 2014-04-05 14:35:00,81.550221165 2014-04-05 14:40:00,83.0861264776 2014-04-05 14:45:00,79.491148701 2014-04-05 14:50:00,73.5597164471 2014-04-05 14:55:00,79.49444646069999 2014-04-05 15:00:00,73.3025637244 2014-04-05 15:05:00,82.9132193136 2014-04-05 15:10:00,84.64507899729999 2014-04-05 15:15:00,87.39724621399998 2014-04-05 15:20:00,74.3801196581 2014-04-05 15:25:00,80.5179523888 2014-04-05 15:30:00,81.0798195068 2014-04-05 15:35:00,86.7587916481 2014-04-05 15:40:00,82.03563869989999 2014-04-05 15:45:00,74.32744078 2014-04-05 15:50:00,78.98086295979999 2014-04-05 15:55:00,82.4754086846 2014-04-05 16:00:00,83.2043911604 2014-04-05 16:05:00,85.80901922380002 2014-04-05 16:10:00,74.8879701323 2014-04-05 16:15:00,87.2245068767 2014-04-05 16:20:00,72.9460905355 2014-04-05 16:25:00,87.7400256919 2014-04-05 16:30:00,85.72410889529999 2014-04-05 16:35:00,82.56420600060001 2014-04-05 16:40:00,83.7597671852 2014-04-05 16:45:00,73.1629316216 2014-04-05 16:50:00,72.663538292 2014-04-05 16:55:00,73.6281113786 2014-04-05 17:00:00,73.39772884989999 2014-04-05 17:05:00,80.75806872439999 2014-04-05 17:10:00,75.4470748221 2014-04-05 17:15:00,85.7632572622 2014-04-05 17:20:00,79.1319475824 2014-04-05 17:25:00,83.1281357021 2014-04-05 17:30:00,82.4459378283 2014-04-05 17:35:00,77.11761900970001 2014-04-05 17:40:00,75.89065203439999 2014-04-05 17:45:00,77.47927081270001 2014-04-05 17:50:00,84.7465014389 2014-04-05 17:55:00,81.3803983246 2014-04-05 18:00:00,30.422641599000002 2014-04-05 18:05:00,34.034210701 2014-04-05 18:10:00,29.1504544742 2014-04-05 18:15:00,33.2747672112 2014-04-05 18:20:00,31.610239087600004 2014-04-05 18:25:00,33.4802520426 2014-04-05 18:30:00,34.7357455243 2014-04-05 18:35:00,33.6002117756 2014-04-05 18:40:00,31.62857220130001 2014-04-05 18:45:00,29.766238646599998 2014-04-05 18:50:00,33.960639724699995 2014-04-05 18:55:00,31.7485092766 2014-04-05 19:00:00,20.4973980847 2014-04-05 19:05:00,23.3813668994 2014-04-05 19:10:00,21.4674956297 2014-04-05 19:15:00,20.3790181502 2014-04-05 19:20:00,24.204323219299997 2014-04-05 19:25:00,22.3242916679 2014-04-05 19:30:00,21.418704343199998 2014-04-05 19:35:00,23.3694104973 2014-04-05 19:40:00,24.1288413284 2014-04-05 19:45:00,20.1613745902 2014-04-05 19:50:00,23.241576514000002 2014-04-05 19:55:00,23.5962110948 2014-04-05 20:00:00,19.291862510599998 2014-04-05 20:05:00,20.4374989682 2014-04-05 20:10:00,18.797714816400003 2014-04-05 20:15:00,21.490687260900003 2014-04-05 20:20:00,21.9031795892 2014-04-05 20:25:00,18.8751323219 2014-04-05 20:30:00,21.7762209367 2014-04-05 20:35:00,21.5923511592 2014-04-05 20:40:00,19.852956722000002 2014-04-05 20:45:00,21.2594256595 2014-04-05 20:50:00,18.432196894300002 2014-04-05 20:55:00,22.2486429257 2014-04-05 21:00:00,20.2985002497 2014-04-05 21:05:00,20.5796659121 2014-04-05 21:10:00,20.757799064100002 2014-04-05 21:15:00,20.3426543042 2014-04-05 21:20:00,21.5299053641 2014-04-05 21:25:00,20.536913553599998 2014-04-05 21:30:00,21.734868903600002 2014-04-05 21:35:00,20.426907206099997 2014-04-05 21:40:00,18.7741751925 2014-04-05 21:45:00,21.7581905712 2014-04-05 21:50:00,20.8259971905 2014-04-05 21:55:00,20.8967813153 2014-04-05 22:00:00,21.962991241399997 2014-04-05 22:05:00,18.3183549626 2014-04-05 22:10:00,19.7332962143 2014-04-05 22:15:00,18.9745796889 2014-04-05 22:20:00,20.541406686400002 2014-04-05 22:25:00,21.2476248814 2014-04-05 22:30:00,21.8862334579 2014-04-05 22:35:00,19.8374100671 2014-04-05 22:40:00,21.1651719902 2014-04-05 22:45:00,21.6890078356 2014-04-05 22:50:00,20.7532056896 2014-04-05 22:55:00,18.9891422935 2014-04-05 23:00:00,20.4353394344 2014-04-05 23:05:00,21.8840091123 2014-04-05 23:10:00,21.9544297546 2014-04-05 23:15:00,20.5733886252 2014-04-05 23:20:00,21.552088236 2014-04-05 23:25:00,18.8050073219 2014-04-05 23:30:00,18.9879594063 2014-04-05 23:35:00,21.8157382671 2014-04-05 23:40:00,18.5445013609 2014-04-05 23:45:00,18.7680285203 2014-04-05 23:50:00,19.685973375899998 2014-04-05 23:55:00,20.3622459497 2014-04-06 00:00:00,20.4152688759 2014-04-06 00:05:00,19.1679040347 2014-04-06 00:10:00,21.682455591799997 2014-04-06 00:15:00,21.6603996304 2014-04-06 00:20:00,19.5682722122 2014-04-06 00:25:00,19.7371670777 2014-04-06 00:30:00,20.809988467300002 2014-04-06 00:35:00,20.6519835856 2014-04-06 00:40:00,19.5291880598 2014-04-06 00:45:00,19.6569770061 2014-04-06 00:50:00,19.392155773699997 2014-04-06 00:55:00,18.9415400278 2014-04-06 01:00:00,19.8325534517 2014-04-06 01:05:00,20.7457365276 2014-04-06 01:10:00,20.9678668213 2014-04-06 01:15:00,21.115494593 2014-04-06 01:20:00,19.4989280538 2014-04-06 01:25:00,21.0585439771 2014-04-06 01:30:00,18.0260652628 2014-04-06 01:35:00,19.9081997509 2014-04-06 01:40:00,21.1756176005 2014-04-06 01:45:00,20.5201788826 2014-04-06 01:50:00,19.896252496600003 2014-04-06 01:55:00,20.578568026400003 2014-04-06 02:00:00,21.627784012600003 2014-04-06 02:05:00,20.2655272024 2014-04-06 02:10:00,21.1991447658 2014-04-06 02:15:00,21.9229709009 2014-04-06 02:20:00,20.8222728083 2014-04-06 02:25:00,20.2933030556 2014-04-06 02:30:00,18.1499437885 2014-04-06 02:35:00,19.497911592999998 2014-04-06 02:40:00,20.2617709341 2014-04-06 02:45:00,21.1888262868 2014-04-06 02:50:00,19.7524191586 2014-04-06 02:55:00,21.8402331031 2014-04-06 03:00:00,19.0871750105 2014-04-06 03:05:00,20.9782687808 2014-04-06 03:10:00,19.6761256683 2014-04-06 03:15:00,19.943953978299998 2014-04-06 03:20:00,21.2100081355 2014-04-06 03:25:00,19.184861046600002 2014-04-06 03:30:00,18.3872482264 2014-04-06 03:35:00,20.0810223385 2014-04-06 03:40:00,20.1151784472 2014-04-06 03:45:00,21.1886710889 2014-04-06 03:50:00,21.873276824899996 2014-04-06 03:55:00,18.2212027453 2014-04-06 04:00:00,20.366757895 2014-04-06 04:05:00,20.725114121300003 2014-04-06 04:10:00,21.943205403 2014-04-06 04:15:00,21.770360857100002 2014-04-06 04:20:00,20.849803058800003 2014-04-06 04:25:00,20.087157645 2014-04-06 04:30:00,18.6460956892 2014-04-06 04:35:00,19.5367062208 2014-04-06 04:40:00,20.3404893002 2014-04-06 04:45:00,20.9008015864 2014-04-06 04:50:00,20.5415982299 2014-04-06 04:55:00,20.8564912073 2014-04-06 05:00:00,19.7166100182 2014-04-06 05:05:00,20.9105091623 2014-04-06 05:10:00,18.574965024100003 2014-04-06 05:15:00,18.6503452471 2014-04-06 05:20:00,18.6513285833 2014-04-06 05:25:00,21.5634598281 2014-04-06 05:30:00,18.3041362532 2014-04-06 05:35:00,21.206033490899998 2014-04-06 05:40:00,18.9342835922 2014-04-06 05:45:00,19.873719762 2014-04-06 05:50:00,21.6638263819 2014-04-06 05:55:00,20.343748918800003 2014-04-06 06:00:00,18.8404707449 2014-04-06 06:05:00,19.1363602413 2014-04-06 06:10:00,21.6817864956 2014-04-06 06:15:00,19.7085757004 2014-04-06 06:20:00,20.347941932 2014-04-06 06:25:00,19.8397287865 2014-04-06 06:30:00,19.5137523522 2014-04-06 06:35:00,18.8931165077 2014-04-06 06:40:00,20.7447660019 2014-04-06 06:45:00,20.8729681051 2014-04-06 06:50:00,19.0995403664 2014-04-06 06:55:00,21.1560433722 2014-04-06 07:00:00,21.4181408012 2014-04-06 07:05:00,21.682700385 2014-04-06 07:10:00,18.6448496557 2014-04-06 07:15:00,19.2156947345 2014-04-06 07:20:00,21.44141339 2014-04-06 07:25:00,18.7941608113 2014-04-06 07:30:00,18.013873837000002 2014-04-06 07:35:00,21.483309241 2014-04-06 07:40:00,19.305797767 2014-04-06 07:45:00,19.6579901006 2014-04-06 07:50:00,19.7853361029 2014-04-06 07:55:00,21.3930984027 2014-04-06 08:00:00,19.3515685784 2014-04-06 08:05:00,21.569119543400003 2014-04-06 08:10:00,20.4677565522 2014-04-06 08:15:00,20.1091468961 2014-04-06 08:20:00,19.3024580285 2014-04-06 08:25:00,18.9748467851 2014-04-06 08:30:00,20.496233771099998 2014-04-06 08:35:00,19.7875766402 2014-04-06 08:40:00,21.6420640397 2014-04-06 08:45:00,19.9665548645 2014-04-06 08:50:00,20.0471796668 2014-04-06 08:55:00,19.6668931245 2014-04-06 09:00:00,71.9339767591 2014-04-06 09:05:00,66.9778130943 2014-04-06 09:10:00,64.8630511966 2014-04-06 09:15:00,72.9236198904 2014-04-06 09:20:00,69.3168638106 2014-04-06 09:25:00,69.2445389889 2014-04-06 09:30:00,69.5071820174 2014-04-06 09:35:00,70.97622057560001 2014-04-06 09:40:00,65.4577246547 2014-04-06 09:45:00,61.6602834433 2014-04-06 09:50:00,72.2240669879 2014-04-06 09:55:00,62.9531087328 2014-04-06 10:00:00,81.0426423215 2014-04-06 10:05:00,71.1175334294 2014-04-06 10:10:00,75.6647777083 2014-04-06 10:15:00,70.8181646038 2014-04-06 10:20:00,77.94475630779999 2014-04-06 10:25:00,79.9766671936 2014-04-06 10:30:00,72.5006423511 2014-04-06 10:35:00,75.6076606382 2014-04-06 10:40:00,84.277316901 2014-04-06 10:45:00,76.7058790975 2014-04-06 10:50:00,82.2954761905 2014-04-06 10:55:00,84.2299072433 2014-04-06 11:00:00,87.06399600040001 2014-04-06 11:05:00,85.8549134012 2014-04-06 11:10:00,76.6160143549 2014-04-06 11:15:00,86.87675918149998 2014-04-06 11:20:00,84.4883339247 2014-04-06 11:25:00,84.8824404822 2014-04-06 11:30:00,71.8093111403 2014-04-06 11:35:00,86.7442148822 2014-04-06 11:40:00,83.9427469201 2014-04-06 11:45:00,83.7817550645 2014-04-06 11:50:00,72.8645693207 2014-04-06 11:55:00,75.26677007720001 2014-04-06 12:00:00,87.2913112182 2014-04-06 12:05:00,79.9148201971 2014-04-06 12:10:00,78.27168941779999 2014-04-06 12:15:00,85.3365262107 2014-04-06 12:20:00,73.3093696899 2014-04-06 12:25:00,78.5766669736 2014-04-06 12:30:00,77.9175989359 2014-04-06 12:35:00,77.5045050459 2014-04-06 12:40:00,76.8307682074 2014-04-06 12:45:00,75.2707658695 2014-04-06 12:50:00,74.6768529604 2014-04-06 12:55:00,82.1478020733 2014-04-06 13:00:00,86.68950698309997 2014-04-06 13:05:00,80.1223923337 2014-04-06 13:10:00,76.7491686153 2014-04-06 13:15:00,74.5286719884 2014-04-06 13:20:00,85.26182609029999 2014-04-06 13:25:00,87.5228623741 2014-04-06 13:30:00,77.5678656667 2014-04-06 13:35:00,76.6368095592 2014-04-06 13:40:00,81.60429751470001 2014-04-06 13:45:00,84.385006432 2014-04-06 13:50:00,79.26741611 2014-04-06 13:55:00,82.06147091689999 2014-04-06 14:00:00,83.4607787787 2014-04-06 14:05:00,87.3652828708 2014-04-06 14:10:00,74.6370145397 2014-04-06 14:15:00,87.9538979115 2014-04-06 14:20:00,78.2707493075 2014-04-06 14:25:00,83.5671908659 2014-04-06 14:30:00,81.15473443329998 2014-04-06 14:35:00,79.7828681106 2014-04-06 14:40:00,83.16521377779999 2014-04-06 14:45:00,78.3283016646 2014-04-06 14:50:00,74.0142068489 2014-04-06 14:55:00,79.81846265979999 2014-04-06 15:00:00,80.3498825646 2014-04-06 15:05:00,75.22971224220001 2014-04-06 15:10:00,86.9690747901 2014-04-06 15:15:00,75.6388842061 2014-04-06 15:20:00,78.546887448 2014-04-06 15:25:00,74.4781599923 2014-04-06 15:30:00,80.5719728406 2014-04-06 15:35:00,76.92146327649999 2014-04-06 15:40:00,79.82759396739999 2014-04-06 15:45:00,75.5931449622 2014-04-06 15:50:00,72.85970258729999 2014-04-06 15:55:00,84.4668155281 2014-04-06 16:00:00,82.2572226092 2014-04-06 16:05:00,77.4516809839 2014-04-06 16:10:00,72.7597678959 2014-04-06 16:15:00,85.84903617270001 2014-04-06 16:20:00,74.71657662289998 2014-04-06 16:25:00,86.89170866010002 2014-04-06 16:30:00,79.6573731151 2014-04-06 16:35:00,77.44603866189999 2014-04-06 16:40:00,83.8679906034 2014-04-06 16:45:00,86.02926532069998 2014-04-06 16:50:00,77.93126739 2014-04-06 16:55:00,78.5173492811 2014-04-06 17:00:00,78.9305012002 2014-04-06 17:05:00,86.75713566889999 2014-04-06 17:10:00,83.0809919611 2014-04-06 17:15:00,75.9623087032 2014-04-06 17:20:00,74.9599663754 2014-04-06 17:25:00,75.6858535514 2014-04-06 17:30:00,76.2169929596 2014-04-06 17:35:00,75.6829067991 2014-04-06 17:40:00,82.5360714612 2014-04-06 17:45:00,73.8549078102 2014-04-06 17:50:00,78.1977058074 2014-04-06 17:55:00,82.0008256792 2014-04-06 18:00:00,30.661497946199997 2014-04-06 18:05:00,29.2177504523 2014-04-06 18:10:00,29.323667476100002 2014-04-06 18:15:00,29.60618168400001 2014-04-06 18:20:00,34.1493888025 2014-04-06 18:25:00,33.0103200979 2014-04-06 18:30:00,29.2129378221 2014-04-06 18:35:00,31.302834816399997 2014-04-06 18:40:00,30.5829392343 2014-04-06 18:45:00,32.4994504745 2014-04-06 18:50:00,32.1459519059 2014-04-06 18:55:00,31.8791876288 2014-04-06 19:00:00,21.569014236100006 2014-04-06 19:05:00,20.777341839 2014-04-06 19:10:00,23.4858449069 2014-04-06 19:15:00,24.1017570023 2014-04-06 19:20:00,24.3897947354 2014-04-06 19:25:00,20.422611868 2014-04-06 19:30:00,23.4747897402 2014-04-06 19:35:00,23.414734213699997 2014-04-06 19:40:00,24.4030497327 2014-04-06 19:45:00,21.2930562153 2014-04-06 19:50:00,23.484960803200003 2014-04-06 19:55:00,20.4047246543 2014-04-06 20:00:00,21.01758222 2014-04-06 20:05:00,19.869072448900003 2014-04-06 20:10:00,21.581452805399998 2014-04-06 20:15:00,21.9680940936 2014-04-06 20:20:00,19.926306749800002 2014-04-06 20:25:00,20.5848003887 2014-04-06 20:30:00,18.9128868125 2014-04-06 20:35:00,20.139650687899998 2014-04-06 20:40:00,19.9098381719 2014-04-06 20:45:00,19.1820734611 2014-04-06 20:50:00,22.0957841819 2014-04-06 20:55:00,19.0385675561 2014-04-06 21:00:00,20.6415635753 2014-04-06 21:05:00,21.6640612597 2014-04-06 21:10:00,21.751784063000002 2014-04-06 21:15:00,21.274588949600002 2014-04-06 21:20:00,18.7943463993 2014-04-06 21:25:00,21.3718202676 2014-04-06 21:30:00,19.1979692471 2014-04-06 21:35:00,21.7937020986 2014-04-06 21:40:00,20.936361138800002 2014-04-06 21:45:00,21.2425473293 2014-04-06 21:50:00,18.428162392 2014-04-06 21:55:00,20.428649494000002 2014-04-06 22:00:00,21.3050016829 2014-04-06 22:05:00,21.4669499075 2014-04-06 22:10:00,18.1319167558 2014-04-06 22:15:00,21.777523290999998 2014-04-06 22:20:00,18.190801345 2014-04-06 22:25:00,20.477714460399998 2014-04-06 22:30:00,20.7934927084 2014-04-06 22:35:00,18.4470733615 2014-04-06 22:40:00,18.2095118191 2014-04-06 22:45:00,21.1599426701 2014-04-06 22:50:00,19.5574396248 2014-04-06 22:55:00,18.4461413643 2014-04-06 23:00:00,21.0547129924 2014-04-06 23:05:00,21.4007604357 2014-04-06 23:10:00,20.353451873599997 2014-04-06 23:15:00,18.6485270618 2014-04-06 23:20:00,18.064357575 2014-04-06 23:25:00,20.8072041395 2014-04-06 23:30:00,20.2044372046 2014-04-06 23:35:00,20.6071443771 2014-04-06 23:40:00,21.2568192045 2014-04-06 23:45:00,19.740700593 2014-04-06 23:50:00,18.5016135014 2014-04-06 23:55:00,21.7641110466 2014-04-07 00:00:00,20.181048509 2014-04-07 00:05:00,20.461176476400002 2014-04-07 00:10:00,21.733645718200002 2014-04-07 00:15:00,21.7263346252 2014-04-07 00:20:00,20.2883784269 2014-04-07 00:25:00,19.1904456989 2014-04-07 00:30:00,21.9884545361 2014-04-07 00:35:00,20.7232683598 2014-04-07 00:40:00,19.6337467076 2014-04-07 00:45:00,20.239347211400002 2014-04-07 00:50:00,19.663336201099998 2014-04-07 00:55:00,21.5532206092 2014-04-07 01:00:00,19.9299974995 2014-04-07 01:05:00,21.2941135039 2014-04-07 01:10:00,21.360705191300003 2014-04-07 01:15:00,21.2973293509 2014-04-07 01:20:00,20.8887544499 2014-04-07 01:25:00,21.4195108672 2014-04-07 01:30:00,19.5489183185 2014-04-07 01:35:00,18.4586528246 2014-04-07 01:40:00,21.3698168175 2014-04-07 01:45:00,19.9926736627 2014-04-07 01:50:00,18.5095041301 2014-04-07 01:55:00,18.461250088699998 2014-04-07 02:00:00,18.636969576 2014-04-07 02:05:00,21.0038930387 2014-04-07 02:10:00,20.8434266939 2014-04-07 02:15:00,18.8152747207 2014-04-07 02:20:00,21.3876936724 2014-04-07 02:25:00,19.125179182100002 2014-04-07 02:30:00,21.1719423333 2014-04-07 02:35:00,19.9552236309 2014-04-07 02:40:00,20.9261947302 2014-04-07 02:45:00,19.5255506523 2014-04-07 02:50:00,19.3885623884 2014-04-07 02:55:00,21.3654383958 2014-04-07 03:00:00,18.1412090181 2014-04-07 03:05:00,21.898947789 2014-04-07 03:10:00,20.5927182331 2014-04-07 03:15:00,19.7299335528 2014-04-07 03:20:00,20.5122181246 2014-04-07 03:25:00,18.490963785799998 2014-04-07 03:30:00,20.0562098212 2014-04-07 03:35:00,21.9403820934 2014-04-07 03:40:00,18.9410777514 2014-04-07 03:45:00,20.8891123961 2014-04-07 03:50:00,19.7398855033 2014-04-07 03:55:00,20.609832594 2014-04-07 04:00:00,18.8195489148 2014-04-07 04:05:00,19.8818599305 2014-04-07 04:10:00,21.920370855399998 2014-04-07 04:15:00,18.7811486041 2014-04-07 04:20:00,20.545780111400003 2014-04-07 04:25:00,20.3023909951 2014-04-07 04:30:00,20.2602063452 2014-04-07 04:35:00,20.4604931586 2014-04-07 04:40:00,20.0089518948 2014-04-07 04:45:00,18.067723000999997 2014-04-07 04:50:00,21.600387245900002 2014-04-07 04:55:00,21.3079153099 2014-04-07 05:00:00,18.6966707237 2014-04-07 05:05:00,19.6530927095 2014-04-07 05:10:00,21.0821959228 2014-04-07 05:15:00,21.9202492615 2014-04-07 05:20:00,21.804548185799998 2014-04-07 05:25:00,21.5974367987 2014-04-07 05:30:00,18.633495589200002 2014-04-07 05:35:00,21.657900424 2014-04-07 05:40:00,21.513779651799997 2014-04-07 05:45:00,19.5077996447 2014-04-07 05:50:00,19.5780903781 2014-04-07 05:55:00,19.8396356878 2014-04-07 06:00:00,20.6247025239 2014-04-07 06:05:00,19.0433424639 2014-04-07 06:10:00,18.091793717799998 2014-04-07 06:15:00,18.5649180984 2014-04-07 06:20:00,19.7604636303 2014-04-07 06:25:00,19.1280102777 2014-04-07 06:30:00,21.0580662441 2014-04-07 06:35:00,18.4267602822 2014-04-07 06:40:00,21.669860902199996 2014-04-07 06:45:00,21.5813087198 2014-04-07 06:50:00,21.6350272677 2014-04-07 06:55:00,20.9584399944 2014-04-07 07:00:00,18.4279998859 2014-04-07 07:05:00,19.7525502855 2014-04-07 07:10:00,18.5256214872 2014-04-07 07:15:00,21.950796771 2014-04-07 07:20:00,19.3321536936 2014-04-07 07:25:00,20.3413221676 2014-04-07 07:30:00,21.117572217 2014-04-07 07:35:00,21.6824643369 2014-04-07 07:40:00,21.0221909034 2014-04-07 07:45:00,20.6980151151 2014-04-07 07:50:00,19.8639271282 2014-04-07 07:55:00,20.421600535 2014-04-07 08:00:00,18.3766552354 2014-04-07 08:05:00,21.535690167800002 2014-04-07 08:10:00,20.1751092354 2014-04-07 08:15:00,18.1605402017 2014-04-07 08:20:00,21.6796085026 2014-04-07 08:25:00,19.957207895299998 2014-04-07 08:30:00,21.474356566199997 2014-04-07 08:35:00,21.4275518168 2014-04-07 08:40:00,21.2630063498 2014-04-07 08:45:00,18.2456120772 2014-04-07 08:50:00,18.9882665817 2014-04-07 08:55:00,21.502191489899996 2014-04-07 09:00:00,73.4262783623 2014-04-07 09:05:00,67.4297365282 2014-04-07 09:10:00,67.18456396010001 2014-04-07 09:15:00,63.5819126209 2014-04-07 09:20:00,74.3703867262 2014-04-07 09:25:00,64.0986832649 2014-04-07 09:30:00,63.7967402672 2014-04-07 09:35:00,70.18591399399999 2014-04-07 09:40:00,64.5026825208 2014-04-07 09:45:00,73.96729390979999 2014-04-07 09:50:00,61.3483351363 2014-04-07 09:55:00,61.2782443676 2014-04-07 10:00:00,77.6756879583 2014-04-07 10:05:00,77.4147293779 2014-04-07 10:10:00,72.3754096199 2014-04-07 10:15:00,77.51494361729999 2014-04-07 10:20:00,76.2289803522 2014-04-07 10:25:00,83.6579142333 2014-04-07 10:30:00,69.9836208418 2014-04-07 10:35:00,84.9917073741 2014-04-07 10:40:00,79.53057570189999 2014-04-07 10:45:00,72.19661027640001 2014-04-07 10:50:00,70.5657154143 2014-04-07 10:55:00,78.1913998208 2014-04-07 11:00:00,75.3036931996 2014-04-07 11:05:00,76.3577367005 2014-04-07 11:10:00,75.4665819495 2014-04-07 11:15:00,81.9083404751 2014-04-07 11:20:00,80.37132461350001 2014-04-07 11:25:00,72.8081052317 2014-04-07 11:30:00,79.9418779836 2014-04-07 11:35:00,84.1510820315 2014-04-07 11:40:00,72.8593187724 2014-04-07 11:45:00,85.718408678 2014-04-07 11:50:00,80.7653889528 2014-04-07 11:55:00,86.6867315593 2014-04-07 12:00:00,74.2810151722 2014-04-07 12:05:00,87.7915635417 2014-04-07 12:10:00,82.2095958165 2014-04-07 12:15:00,80.9826113031 2014-04-07 12:20:00,80.148180617 2014-04-07 12:25:00,72.2916158056 2014-04-07 12:30:00,86.9297859923 2014-04-07 12:35:00,82.2051468718 2014-04-07 12:40:00,73.37786452350001 2014-04-07 12:45:00,72.248432443 2014-04-07 12:50:00,72.7251631819 2014-04-07 12:55:00,81.6522318163 2014-04-07 13:00:00,81.8046088191 2014-04-07 13:05:00,79.9754779461 2014-04-07 13:10:00,76.8897951497 2014-04-07 13:15:00,80.4885618137 2014-04-07 13:20:00,80.241566535 2014-04-07 13:25:00,72.29329440229999 2014-04-07 13:30:00,76.5011430034 2014-04-07 13:35:00,72.83348123180001 2014-04-07 13:40:00,86.38173942889999 2014-04-07 13:45:00,83.5835057476 2014-04-07 13:50:00,87.9167376408 2014-04-07 13:55:00,76.8162998752 2014-04-07 14:00:00,86.05164288700001 2014-04-07 14:05:00,81.6449491412 2014-04-07 14:10:00,79.2462025101 2014-04-07 14:15:00,75.55754284449999 2014-04-07 14:20:00,83.8102515594 2014-04-07 14:25:00,86.4621016024 2014-04-07 14:30:00,75.7612976524 2014-04-07 14:35:00,74.8026546598 2014-04-07 14:40:00,83.1355599416 2014-04-07 14:45:00,87.6273642882 2014-04-07 14:50:00,83.9952496521 2014-04-07 14:55:00,76.5496172668 2014-04-07 15:00:00,78.7185310812 2014-04-07 15:05:00,78.14833193609999 2014-04-07 15:10:00,85.632698207 2014-04-07 15:15:00,84.3411227794 2014-04-07 15:20:00,81.4228252896 2014-04-07 15:25:00,76.3986123326 2014-04-07 15:30:00,87.0069811685 2014-04-07 15:35:00,82.4522520471 2014-04-07 15:40:00,87.52678607790001 2014-04-07 15:45:00,81.28109222270001 2014-04-07 15:50:00,85.1382667986 2014-04-07 15:55:00,85.0088699773 2014-04-07 16:00:00,77.3971118266 2014-04-07 16:05:00,87.4241637126 2014-04-07 16:10:00,72.3509245675 2014-04-07 16:15:00,84.2992126855 2014-04-07 16:20:00,87.44874547030001 2014-04-07 16:25:00,77.4223826013 2014-04-07 16:30:00,82.3696112547 2014-04-07 16:35:00,80.99541648600001 2014-04-07 16:40:00,84.1839553213 2014-04-07 16:45:00,85.8586818973 2014-04-07 16:50:00,81.6485563433 2014-04-07 16:55:00,85.0543100775 2014-04-07 17:00:00,76.9965396475 2014-04-07 17:05:00,75.6573638868 2014-04-07 17:10:00,78.89065273850001 2014-04-07 17:15:00,82.8437537813 2014-04-07 17:20:00,74.99592238460002 2014-04-07 17:25:00,82.88560324630002 2014-04-07 17:30:00,78.3054683078 2014-04-07 17:35:00,84.7291718463 2014-04-07 17:40:00,72.5893451993 2014-04-07 17:45:00,82.68769045319999 2014-04-07 17:50:00,82.3971257459 2014-04-07 17:55:00,87.05493418889999 2014-04-07 18:00:00,33.3655459366 2014-04-07 18:05:00,33.896325629 2014-04-07 18:10:00,34.5893758603 2014-04-07 18:15:00,33.120325918 2014-04-07 18:20:00,30.6569773776 2014-04-07 18:25:00,34.366545719 2014-04-07 18:30:00,33.5844935164 2014-04-07 18:35:00,31.516394614499998 2014-04-07 18:40:00,33.3473803023 2014-04-07 18:45:00,34.3532022181 2014-04-07 18:50:00,35.044166912399994 2014-04-07 18:55:00,34.8950429255 2014-04-07 19:00:00,21.617467478000002 2014-04-07 19:05:00,22.0491866279 2014-04-07 19:10:00,20.6507228575 2014-04-07 19:15:00,21.268997239100003 2014-04-07 19:20:00,24.1132456912 2014-04-07 19:25:00,21.776606475100003 2014-04-07 19:30:00,22.9400746521 2014-04-07 19:35:00,23.1435247004 2014-04-07 19:40:00,23.6625938546 2014-04-07 19:45:00,20.9789429847 2014-04-07 19:50:00,21.525561662199998 2014-04-07 19:55:00,22.1685455936 2014-04-07 20:00:00,19.9263887477 2014-04-07 20:05:00,22.457979564299997 2014-04-07 20:10:00,21.8519172677 2014-04-07 20:15:00,20.3967967022 2014-04-07 20:20:00,22.033484028 2014-04-07 20:25:00,19.855986235 2014-04-07 20:30:00,21.6507525548 2014-04-07 20:35:00,19.3481750177 2014-04-07 20:40:00,21.5954308381 2014-04-07 20:45:00,20.3016328959 2014-04-07 20:50:00,18.8723169923 2014-04-07 20:55:00,19.5512827792 2014-04-07 21:00:00,19.703222120699998 2014-04-07 21:05:00,21.097958019 2014-04-07 21:10:00,18.379732082100002 2014-04-07 21:15:00,20.737251232000002 2014-04-07 21:20:00,20.9642019744 2014-04-07 21:25:00,20.7146407193 2014-04-07 21:30:00,21.143683358 2014-04-07 21:35:00,18.8024952555 2014-04-07 21:40:00,20.4460857547 2014-04-07 21:45:00,21.869049718299998 2014-04-07 21:50:00,20.541264087000002 2014-04-07 21:55:00,20.543482995399998 2014-04-07 22:00:00,20.9658664864 2014-04-07 22:05:00,19.3513764233 2014-04-07 22:10:00,20.8218734225 2014-04-07 22:15:00,21.685733660500002 2014-04-07 22:20:00,18.0609037218 2014-04-07 22:25:00,21.501073388000002 2014-04-07 22:30:00,18.8925928102 2014-04-07 22:35:00,19.8427238304 2014-04-07 22:40:00,21.429944208800002 2014-04-07 22:45:00,21.3160923219 2014-04-07 22:50:00,21.5884149034 2014-04-07 22:55:00,21.7825583603 2014-04-07 23:00:00,19.7924272417 2014-04-07 23:05:00,20.6294153286 2014-04-07 23:10:00,19.5656696476 2014-04-07 23:15:00,19.4065922185 2014-04-07 23:20:00,19.7301691057 2014-04-07 23:25:00,20.9763312195 2014-04-07 23:30:00,20.0096040931 2014-04-07 23:35:00,21.2603198935 2014-04-07 23:40:00,20.9849022345 2014-04-07 23:45:00,18.0853855702 2014-04-07 23:50:00,20.5248926493 2014-04-07 23:55:00,19.7500757779 2014-04-08 00:00:00,19.8265159566 2014-04-08 00:05:00,21.2734922155 2014-04-08 00:10:00,20.190431944300002 2014-04-08 00:15:00,21.5424872938 2014-04-08 00:20:00,20.851222369600002 2014-04-08 00:25:00,20.2113600351 2014-04-08 00:30:00,21.0181519046 2014-04-08 00:35:00,18.153396203699998 2014-04-08 00:40:00,18.1083346193 2014-04-08 00:45:00,18.3333973077 2014-04-08 00:50:00,19.7502613006 2014-04-08 00:55:00,18.9418005825 2014-04-08 01:00:00,21.9370451777 2014-04-08 01:05:00,20.169160555999998 2014-04-08 01:10:00,20.6496629843 2014-04-08 01:15:00,19.115280545 2014-04-08 01:20:00,19.287187634400002 2014-04-08 01:25:00,19.341847656600002 2014-04-08 01:30:00,20.7949428206 2014-04-08 01:35:00,19.894824830799998 2014-04-08 01:40:00,20.0707346101 2014-04-08 01:45:00,20.368011928599998 2014-04-08 01:50:00,21.075246625 2014-04-08 01:55:00,18.3614789941 2014-04-08 02:00:00,21.107495648900002 2014-04-08 02:05:00,20.2529402755 2014-04-08 02:10:00,20.6763817794 2014-04-08 02:15:00,19.3102070594 2014-04-08 02:20:00,19.6375473473 2014-04-08 02:25:00,18.9246632786 2014-04-08 02:30:00,21.9171999897 2014-04-08 02:35:00,19.98801189 2014-04-08 02:40:00,21.984307663200003 2014-04-08 02:45:00,19.959143912200002 2014-04-08 02:50:00,18.8790050575 2014-04-08 02:55:00,20.0298095869 2014-04-08 03:00:00,18.158382287200002 2014-04-08 03:05:00,21.6190792057 2014-04-08 03:10:00,21.274201004800002 2014-04-08 03:15:00,20.9032820828 2014-04-08 03:20:00,20.439306861800002 2014-04-08 03:25:00,20.3193369347 2014-04-08 03:30:00,21.986912856300002 2014-04-08 03:35:00,19.1119897361 2014-04-08 03:40:00,21.1187374615 2014-04-08 03:45:00,20.325619080899997 2014-04-08 03:50:00,21.903522175 2014-04-08 03:55:00,21.311212733199998 2014-04-08 04:00:00,21.994100451999998 2014-04-08 04:05:00,20.3532999778 2014-04-08 04:10:00,18.8181758302 2014-04-08 04:15:00,20.0147481428 2014-04-08 04:20:00,20.844444536199997 2014-04-08 04:25:00,21.0974415447 2014-04-08 04:30:00,18.0020399561 2014-04-08 04:35:00,20.020108354 2014-04-08 04:40:00,18.9409383199 2014-04-08 04:45:00,21.499647333000002 2014-04-08 04:50:00,18.6116217762 2014-04-08 04:55:00,20.6658249983 2014-04-08 05:00:00,19.0642487613 2014-04-08 05:05:00,19.4261685729 2014-04-08 05:10:00,21.762237043000003 2014-04-08 05:15:00,18.9617925016 2014-04-08 05:20:00,18.380011047300002 2014-04-08 05:25:00,18.2771396058 2014-04-08 05:30:00,20.0184604404 2014-04-08 05:35:00,20.5668459291 2014-04-08 05:40:00,19.309174574300002 2014-04-08 05:45:00,20.7610389672 2014-04-08 05:50:00,18.244134874300002 2014-04-08 05:55:00,21.4293385797 2014-04-08 06:00:00,21.266268839000002 2014-04-08 06:05:00,21.9419850856 2014-04-08 06:10:00,21.746019923600002 2014-04-08 06:15:00,19.4247886557 2014-04-08 06:20:00,19.5971015361 2014-04-08 06:25:00,20.9838593899 2014-04-08 06:30:00,18.5363310878 2014-04-08 06:35:00,19.256058840999998 2014-04-08 06:40:00,18.4741637479 2014-04-08 06:45:00,19.8195457963 2014-04-08 06:50:00,20.2080171195 2014-04-08 06:55:00,18.8446418799 2014-04-08 07:00:00,18.1065267477 2014-04-08 07:05:00,20.877423327 2014-04-08 07:10:00,18.0800206577 2014-04-08 07:15:00,21.8936104357 2014-04-08 07:20:00,18.886429027000002 2014-04-08 07:25:00,20.6556003685 2014-04-08 07:30:00,19.739006905 2014-04-08 07:35:00,18.238695441300003 2014-04-08 07:40:00,19.8887344265 2014-04-08 07:45:00,20.0670425372 2014-04-08 07:50:00,21.4187328324 2014-04-08 07:55:00,20.9293962786 2014-04-08 08:00:00,18.317209899 2014-04-08 08:05:00,18.836650733699997 2014-04-08 08:10:00,19.2475507369 2014-04-08 08:15:00,18.4656307459 2014-04-08 08:20:00,19.8275962837 2014-04-08 08:25:00,21.9372367635 2014-04-08 08:30:00,20.058451165 2014-04-08 08:35:00,20.9675286733 2014-04-08 08:40:00,20.7317511908 2014-04-08 08:45:00,21.3996457404 2014-04-08 08:50:00,18.8628939619 2014-04-08 08:55:00,21.0153050468 2014-04-08 09:00:00,73.1864312682 2014-04-08 09:05:00,63.5325335925 2014-04-08 09:10:00,65.9165101891 2014-04-08 09:15:00,74.39338399489999 2014-04-08 09:20:00,71.8187147053 2014-04-08 09:25:00,65.0432353225 2014-04-08 09:30:00,68.8696080672 2014-04-08 09:35:00,66.6988352708 2014-04-08 09:40:00,67.863526398 2014-04-08 09:45:00,66.0302602029 2014-04-08 09:50:00,64.998901852 2014-04-08 09:55:00,70.3767773629 2014-04-08 10:00:00,81.9229689701 2014-04-08 10:05:00,83.403814545 2014-04-08 10:10:00,72.25072109279999 2014-04-08 10:15:00,82.610717727 2014-04-08 10:20:00,73.7945087959 2014-04-08 10:25:00,76.4722607714 2014-04-08 10:30:00,83.83040600439999 2014-04-08 10:35:00,76.89389588729999 2014-04-08 10:40:00,72.8984260484 2014-04-08 10:45:00,72.3211615293 2014-04-08 10:50:00,77.1807080584 2014-04-08 10:55:00,81.6766760201 2014-04-08 11:00:00,87.4275506098 2014-04-08 11:05:00,84.0909468266 2014-04-08 11:10:00,85.515998195 2014-04-08 11:15:00,83.4615258683 2014-04-08 11:20:00,85.8089998424 2014-04-08 11:25:00,72.7813725129 2014-04-08 11:30:00,86.3576321502 2014-04-08 11:35:00,77.8724434689 2014-04-08 11:40:00,86.22535260709999 2014-04-08 11:45:00,72.772455047 2014-04-08 11:50:00,82.94322399010001 2014-04-08 11:55:00,83.2683938589 2014-04-08 12:00:00,87.8450335397 2014-04-08 12:05:00,84.2005223098 2014-04-08 12:10:00,78.0274338779 2014-04-08 12:15:00,80.8188776537 2014-04-08 12:20:00,77.7713772327 2014-04-08 12:25:00,75.0461347669 2014-04-08 12:30:00,75.8848659953 2014-04-08 12:35:00,75.46150594609999 2014-04-08 12:40:00,80.6841080283 2014-04-08 12:45:00,86.3947718683 2014-04-08 12:50:00,86.49970166620001 2014-04-08 12:55:00,72.7887689759 2014-04-08 13:00:00,73.2608036015 2014-04-08 13:05:00,75.9036836576 2014-04-08 13:10:00,76.0626918112 2014-04-08 13:15:00,73.5005824294 2014-04-08 13:20:00,78.1966417595 2014-04-08 13:25:00,81.3840694176 2014-04-08 13:30:00,81.23109506670002 2014-04-08 13:35:00,80.6755081302 2014-04-08 13:40:00,77.400170298 2014-04-08 13:45:00,83.2832981752 2014-04-08 13:50:00,85.2032893574 2014-04-08 13:55:00,77.5217785705 2014-04-08 14:00:00,73.3650440576 2014-04-08 14:05:00,76.7376004358 2014-04-08 14:10:00,74.1943369741 2014-04-08 14:15:00,79.4739247041 2014-04-08 14:20:00,74.4913866629 2014-04-08 14:25:00,79.4017046578 2014-04-08 14:30:00,75.532420547 2014-04-08 14:35:00,83.81567434189999 2014-04-08 14:40:00,72.437614681 2014-04-08 14:45:00,80.8720588161 2014-04-08 14:50:00,74.7082262317 2014-04-08 14:55:00,72.01241306979999 2014-04-08 15:00:00,85.9063766999 2014-04-08 15:05:00,82.7436502584 2014-04-08 15:10:00,73.58237875520001 2014-04-08 15:15:00,82.62436468140001 2014-04-08 15:20:00,81.7855721748 2014-04-08 15:25:00,79.57294308510001 2014-04-08 15:30:00,78.7073739768 2014-04-08 15:35:00,86.19228875270002 2014-04-08 15:40:00,75.9216394636 2014-04-08 15:45:00,78.3722085318 2014-04-08 15:50:00,77.2651048542 2014-04-08 15:55:00,84.3384068081 2014-04-08 16:00:00,86.6632785059 2014-04-08 16:05:00,85.59634283449999 2014-04-08 16:10:00,84.76310013930001 2014-04-08 16:15:00,87.7884705749 2014-04-08 16:20:00,83.1541531503 2014-04-08 16:25:00,84.016699347 2014-04-08 16:30:00,87.72467220360001 2014-04-08 16:35:00,72.1117141116 2014-04-08 16:40:00,82.144616305 2014-04-08 16:45:00,83.82338357 2014-04-08 16:50:00,86.68506642450001 2014-04-08 16:55:00,86.1413434753 2014-04-08 17:00:00,85.4713380787 2014-04-08 17:05:00,87.13262689209999 2014-04-08 17:10:00,80.598036057 2014-04-08 17:15:00,72.1106938388 2014-04-08 17:20:00,72.17684266319999 2014-04-08 17:25:00,80.7141938956 2014-04-08 17:30:00,78.96432549949999 2014-04-08 17:35:00,79.2198904334 2014-04-08 17:40:00,78.40644568729999 2014-04-08 17:45:00,86.683579659 2014-04-08 17:50:00,77.746695764 2014-04-08 17:55:00,85.6995981596 2014-04-08 18:00:00,34.578328041199995 2014-04-08 18:05:00,31.9968051846 2014-04-08 18:10:00,31.660397360300003 2014-04-08 18:15:00,33.6705254022 2014-04-08 18:20:00,33.3310112493 2014-04-08 18:25:00,30.9026188129 2014-04-08 18:30:00,29.456302350300003 2014-04-08 18:35:00,30.49504950610001 2014-04-08 18:40:00,29.6385767466 2014-04-08 18:45:00,30.686280673200002 2014-04-08 18:50:00,30.4756521684 2014-04-08 18:55:00,32.8813467997 2014-04-08 19:00:00,24.436140867 2014-04-08 19:05:00,23.232130646399998 2014-04-08 19:10:00,24.311388014499997 2014-04-08 19:15:00,23.672911219899998 2014-04-08 19:20:00,23.4208904621 2014-04-08 19:25:00,22.014996284499997 2014-04-08 19:30:00,21.6150781871 2014-04-08 19:35:00,23.9513213148 2014-04-08 19:40:00,24.2161603551 2014-04-08 19:45:00,22.184432354600002 2014-04-08 19:50:00,20.200601571700002 2014-04-08 19:55:00,23.7105378432 2014-04-08 20:00:00,19.5996417354 2014-04-08 20:05:00,18.4725004734 2014-04-08 20:10:00,21.729232876799998 2014-04-08 20:15:00,20.5513282708 2014-04-08 20:20:00,21.2386229621 2014-04-08 20:25:00,22.1785692413 2014-04-08 20:30:00,20.6486477605 2014-04-08 20:35:00,20.4930826754 2014-04-08 20:40:00,19.622551813599998 2014-04-08 20:45:00,19.6820737097 2014-04-08 20:50:00,21.6946360421 2014-04-08 20:55:00,20.2712235467 2014-04-08 21:00:00,18.7436444918 2014-04-08 21:05:00,18.466329963099998 2014-04-08 21:10:00,19.9871604848 2014-04-08 21:15:00,19.9551471821 2014-04-08 21:20:00,20.7127794611 2014-04-08 21:25:00,19.9797143577 2014-04-08 21:30:00,18.6630575044 2014-04-08 21:35:00,20.1273613054 2014-04-08 21:40:00,21.7309679189 2014-04-08 21:45:00,18.7272268758 2014-04-08 21:50:00,20.858661802 2014-04-08 21:55:00,20.4732391077 2014-04-08 22:00:00,21.0144974657 2014-04-08 22:05:00,18.6202593896 2014-04-08 22:10:00,21.7873171014 2014-04-08 22:15:00,20.5035302121 2014-04-08 22:20:00,21.4088172934 2014-04-08 22:25:00,19.0046540154 2014-04-08 22:30:00,20.9777708928 2014-04-08 22:35:00,21.1444019649 2014-04-08 22:40:00,19.6085472314 2014-04-08 22:45:00,19.5545681832 2014-04-08 22:50:00,20.6509909876 2014-04-08 22:55:00,18.391269403499997 2014-04-08 23:00:00,20.9465175582 2014-04-08 23:05:00,18.1750359746 2014-04-08 23:10:00,18.765963576 2014-04-08 23:15:00,20.6605410893 2014-04-08 23:20:00,18.3968261791 2014-04-08 23:25:00,21.8915707385 2014-04-08 23:30:00,21.477707764 2014-04-08 23:35:00,20.5091463278 2014-04-08 23:40:00,21.280314856700002 2014-04-08 23:45:00,21.554457853699997 2014-04-08 23:50:00,19.0415578737 2014-04-08 23:55:00,21.4017546978 2014-04-09 00:00:00,18.7791751346 2014-04-09 00:05:00,19.653369056600003 2014-04-09 00:10:00,20.233038525 2014-04-09 00:15:00,20.8555638523 2014-04-09 00:20:00,18.1205652709 2014-04-09 00:25:00,19.1620376511 2014-04-09 00:30:00,20.434076392799998 2014-04-09 00:35:00,19.4294747166 2014-04-09 00:40:00,21.1001002225 2014-04-09 00:45:00,20.6066086446 2014-04-09 00:50:00,18.9376058149 2014-04-09 00:55:00,18.5837159184 2014-04-09 01:00:00,20.5161879743 2014-04-09 01:05:00,19.8018693108 2014-04-09 01:10:00,18.675828164400002 2014-04-09 01:15:00,19.3054968213 2014-04-09 01:20:00,19.212186993299998 2014-04-09 01:25:00,18.4325278894 2014-04-09 01:30:00,20.1876360771 2014-04-09 01:35:00,21.054594535699998 2014-04-09 01:40:00,20.3018675554 2014-04-09 01:45:00,21.3051654597 2014-04-09 01:50:00,18.510274188900002 2014-04-09 01:55:00,19.7424474313 2014-04-09 02:00:00,20.4376604146 2014-04-09 02:05:00,20.704006243800002 2014-04-09 02:10:00,20.7831452257 2014-04-09 02:15:00,20.915861708399998 2014-04-09 02:20:00,20.6057192488 2014-04-09 02:25:00,18.3769123558 2014-04-09 02:30:00,20.781222710399998 2014-04-09 02:35:00,20.8991306271 2014-04-09 02:40:00,21.9739197373 2014-04-09 02:45:00,20.7734497468 2014-04-09 02:50:00,20.747321582999998 2014-04-09 02:55:00,20.0592531607 2014-04-09 03:00:00,21.4716916343 2014-04-09 03:05:00,21.987339047800003 2014-04-09 03:10:00,21.1161794808 2014-04-09 03:15:00,20.4500015114 2014-04-09 03:20:00,18.3158193077 2014-04-09 03:25:00,20.9069565269 2014-04-09 03:30:00,20.8342462743 2014-04-09 03:35:00,21.1022725912 2014-04-09 03:40:00,18.4982215536 2014-04-09 03:45:00,20.6149300005 2014-04-09 03:50:00,19.1828956198 2014-04-09 03:55:00,21.0410849736 2014-04-09 04:00:00,18.961495816099998 2014-04-09 04:05:00,20.7359147073 2014-04-09 04:10:00,19.1799717879 2014-04-09 04:15:00,18.0359771713 2014-04-09 04:20:00,20.5334316479 2014-04-09 04:25:00,18.4530763326 2014-04-09 04:30:00,20.6371658912 2014-04-09 04:35:00,21.7024377934 2014-04-09 04:40:00,21.8769837368 2014-04-09 04:45:00,18.9436923493 2014-04-09 04:50:00,21.2370129106 2014-04-09 04:55:00,19.4142131075 2014-04-09 05:00:00,21.601828291 2014-04-09 05:05:00,21.1499582745 2014-04-09 05:10:00,18.2956868666 2014-04-09 05:15:00,19.6285479755 2014-04-09 05:20:00,19.349271304000002 2014-04-09 05:25:00,21.1407240829 2014-04-09 05:30:00,19.6411428426 2014-04-09 05:35:00,20.7383535906 2014-04-09 05:40:00,20.4097410224 2014-04-09 05:45:00,21.9025548764 2014-04-09 05:50:00,21.7511398272 2014-04-09 05:55:00,19.710798059000002 2014-04-09 06:00:00,20.894312846600002 2014-04-09 06:05:00,21.317840375899998 2014-04-09 06:10:00,21.5955430154 2014-04-09 06:15:00,18.2725370551 2014-04-09 06:20:00,19.2083151971 2014-04-09 06:25:00,19.2809201639 2014-04-09 06:30:00,19.7377838049 2014-04-09 06:35:00,18.6770590029 2014-04-09 06:40:00,19.9848235198 2014-04-09 06:45:00,20.6528573092 2014-04-09 06:50:00,19.9894556809 2014-04-09 06:55:00,20.6631723808 2014-04-09 07:00:00,18.2657665273 2014-04-09 07:05:00,21.503949326799997 2014-04-09 07:10:00,21.756276768400003 2014-04-09 07:15:00,20.471629696500003 2014-04-09 07:20:00,21.525563994499997 2014-04-09 07:25:00,18.5257840666 2014-04-09 07:30:00,21.1897956803 2014-04-09 07:35:00,18.476592773900002 2014-04-09 07:40:00,19.632040926 2014-04-09 07:45:00,19.2952741382 2014-04-09 07:50:00,20.342367300899998 2014-04-09 07:55:00,19.206058141 2014-04-09 08:00:00,20.5492545187 2014-04-09 08:05:00,19.4695491566 2014-04-09 08:10:00,21.443161524100002 2014-04-09 08:15:00,20.5355353609 2014-04-09 08:20:00,18.8611931893 2014-04-09 08:25:00,19.344517688099998 2014-04-09 08:30:00,21.3896835505 2014-04-09 08:35:00,19.5459189999 2014-04-09 08:40:00,20.143196262300002 2014-04-09 08:45:00,20.5957677438 2014-04-09 08:50:00,19.3912385983 2014-04-09 08:55:00,19.175914523 2014-04-09 09:00:00,67.6634666755 2014-04-09 09:05:00,64.1223812205 2014-04-09 09:10:00,65.0652639821 2014-04-09 09:15:00,62.044267382799994 2014-04-09 09:20:00,65.3339957532 2014-04-09 09:25:00,65.5615756697 2014-04-09 09:30:00,74.2809310616 2014-04-09 09:35:00,69.22031202630001 2014-04-09 09:40:00,71.9084009857 2014-04-09 09:45:00,61.8171306378 2014-04-09 09:50:00,62.6488990331 2014-04-09 09:55:00,72.2777026677 2014-04-09 10:00:00,79.517489007 2014-04-09 10:05:00,72.804041114 2014-04-09 10:10:00,76.12242469899999 2014-04-09 10:15:00,78.2001971997 2014-04-09 10:20:00,82.9328245482 2014-04-09 10:25:00,70.7775941111 2014-04-09 10:30:00,79.101129931 2014-04-09 10:35:00,80.968397503 2014-04-09 10:40:00,85.0168816348 2014-04-09 10:45:00,82.36712441510001 2014-04-09 10:50:00,74.1270479065 2014-04-09 10:55:00,80.852669089 2014-04-09 11:00:00,83.70717148189999 2014-04-09 11:05:00,83.1737133907 2014-04-09 11:10:00,84.6115712567 2014-04-09 11:15:00,85.9409215417 2014-04-09 11:20:00,73.1334286364 2014-04-09 11:25:00,73.23416439260001 2014-04-09 11:30:00,84.23394542140001 2014-04-09 11:35:00,75.5817318666 2014-04-09 11:40:00,72.4990427747 2014-04-09 11:45:00,77.94914889430001 2014-04-09 11:50:00,84.6073224057 2014-04-09 11:55:00,73.5808901387 2014-04-09 12:00:00,82.650172183 2014-04-09 12:05:00,71.9713843638 2014-04-09 12:10:00,73.6672921964 2014-04-09 12:15:00,77.5204692057 2014-04-09 12:20:00,73.2496313326 2014-04-09 12:25:00,85.431785367 2014-04-09 12:30:00,85.7221378967 2014-04-09 12:35:00,83.9882242921 2014-04-09 12:40:00,75.78861849340001 2014-04-09 12:45:00,80.27550686 2014-04-09 12:50:00,74.8570799887 2014-04-09 12:55:00,76.4086546549 2014-04-09 13:00:00,80.23682321449999 2014-04-09 13:05:00,83.74011848229999 2014-04-09 13:10:00,73.4968266135 2014-04-09 13:15:00,76.7287278467 2014-04-09 13:20:00,86.8051033512 2014-04-09 13:25:00,78.847045251 2014-04-09 13:30:00,87.00102952299999 2014-04-09 13:35:00,87.8413216868 2014-04-09 13:40:00,80.4072548441 2014-04-09 13:45:00,76.59031806760001 2014-04-09 13:50:00,84.6321123542 2014-04-09 13:55:00,74.5310800152 2014-04-09 14:00:00,76.0291001828 2014-04-09 14:05:00,84.5540197642 2014-04-09 14:10:00,78.9345457556 2014-04-09 14:15:00,75.2209962107 2014-04-09 14:20:00,82.41405585470001 2014-04-09 14:25:00,83.720171021 2014-04-09 14:30:00,73.9975877765 2014-04-09 14:35:00,76.4280154388 2014-04-09 14:40:00,75.5368021454 2014-04-09 14:45:00,78.07392633180001 2014-04-09 14:50:00,84.2110760035 2014-04-09 14:55:00,83.41532550859999 2014-04-09 15:00:00,82.5995896025 2014-04-09 15:05:00,72.0998765684 2014-04-09 15:10:00,74.2735799809 2014-04-09 15:15:00,75.57203528710002 2014-04-09 15:20:00,76.3505605642 2014-04-09 15:25:00,74.3421109753 2014-04-09 15:30:00,78.5642945991 2014-04-09 15:35:00,73.2021866125 2014-04-09 15:40:00,83.9995486428 2014-04-09 15:45:00,84.6027204028 2014-04-09 15:50:00,81.1874876263 2014-04-09 15:55:00,73.434573054 2014-04-09 16:00:00,86.2411651294 2014-04-09 16:05:00,87.450005355 2014-04-09 16:10:00,75.2376725085 2014-04-09 16:15:00,83.2740772245 2014-04-09 16:20:00,85.4708539859 2014-04-09 16:25:00,80.6373415367 2014-04-09 16:30:00,77.1730214199 2014-04-09 16:35:00,79.6567865 2014-04-09 16:40:00,80.1961460357 2014-04-09 16:45:00,78.41004215939999 2014-04-09 16:50:00,86.8773130934 2014-04-09 16:55:00,83.901968683 2014-04-09 17:00:00,75.8607971455 2014-04-09 17:05:00,81.3688837515 2014-04-09 17:10:00,83.0189945356 2014-04-09 17:15:00,74.2424742381 2014-04-09 17:20:00,77.7347820279 2014-04-09 17:25:00,86.488739294 2014-04-09 17:30:00,81.07473847029999 2014-04-09 17:35:00,75.4719349557 2014-04-09 17:40:00,73.9645283675 2014-04-09 17:45:00,80.2915994636 2014-04-09 17:50:00,80.7629405555 2014-04-09 17:55:00,77.350601519 2014-04-09 18:00:00,32.834656277600004 2014-04-09 18:05:00,29.239576377800002 2014-04-09 18:10:00,29.728888329 2014-04-09 18:15:00,32.2961462536 2014-04-09 18:20:00,29.195614835 2014-04-09 18:25:00,34.4378094839 2014-04-09 18:30:00,29.7097310667 2014-04-09 18:35:00,33.1130808364 2014-04-09 18:40:00,31.303696016700002 2014-04-09 18:45:00,31.3586355634 2014-04-09 18:50:00,33.6952865136 2014-04-09 18:55:00,31.9965515154 2014-04-09 19:00:00,23.4109351929 2014-04-09 19:05:00,22.4232554747 2014-04-09 19:10:00,22.8162146779 2014-04-09 19:15:00,23.56800024 2014-04-09 19:20:00,22.8807419131 2014-04-09 19:25:00,22.917954432800002 2014-04-09 19:30:00,23.6957024697 2014-04-09 19:35:00,24.4119075957 2014-04-09 19:40:00,21.847687171100002 2014-04-09 19:45:00,22.745483616599998 2014-04-09 19:50:00,20.5465026195 2014-04-09 19:55:00,21.7674401908 2014-04-09 20:00:00,20.1197533878 2014-04-09 20:05:00,21.8531317875 2014-04-09 20:10:00,20.5348550327 2014-04-09 20:15:00,21.4264476079 2014-04-09 20:20:00,18.5098540884 2014-04-09 20:25:00,20.3345617308 2014-04-09 20:30:00,22.123796890999998 2014-04-09 20:35:00,19.3507895403 2014-04-09 20:40:00,18.5611146483 2014-04-09 20:45:00,20.2072419308 2014-04-09 20:50:00,21.3173524816 2014-04-09 20:55:00,20.2934822805 2014-04-09 21:00:00,19.9351447889 2014-04-09 21:05:00,20.7784803709 2014-04-09 21:10:00,19.1088394515 2014-04-09 21:15:00,21.1083953989 2014-04-09 21:20:00,18.7017938577 2014-04-09 21:25:00,19.6770007846 2014-04-09 21:30:00,20.7230277389 2014-04-09 21:35:00,21.4157806615 2014-04-09 21:40:00,21.2677216292 2014-04-09 21:45:00,20.9869987094 2014-04-09 21:50:00,19.5296801369 2014-04-09 21:55:00,18.577965462599998 2014-04-09 22:00:00,18.8854495049 2014-04-09 22:05:00,21.4799362096 2014-04-09 22:10:00,21.4498976225 2014-04-09 22:15:00,21.827177393099998 2014-04-09 22:20:00,18.321526395 2014-04-09 22:25:00,20.166577678099998 2014-04-09 22:30:00,20.6145031124 2014-04-09 22:35:00,20.8626384224 2014-04-09 22:40:00,20.5952053648 2014-04-09 22:45:00,21.100282393 2014-04-09 22:50:00,19.4565466665 2014-04-09 22:55:00,18.7357001012 2014-04-09 23:00:00,18.8219466068 2014-04-09 23:05:00,18.0513799557 2014-04-09 23:10:00,19.4050125337 2014-04-09 23:15:00,18.370502661099998 2014-04-09 23:20:00,19.2896576726 2014-04-09 23:25:00,20.516778772000002 2014-04-09 23:30:00,21.5820551794 2014-04-09 23:35:00,21.3625226188 2014-04-09 23:40:00,19.0143468998 2014-04-09 23:45:00,18.5398915428 2014-04-09 23:50:00,18.7758933728 2014-04-09 23:55:00,21.888148323200003 2014-04-10 00:00:00,20.197897918699997 2014-04-10 00:05:00,18.730008892 2014-04-10 00:10:00,21.3629846187 2014-04-10 00:15:00,19.5807649773 2014-04-10 00:20:00,21.5968886079 2014-04-10 00:25:00,19.0427085073 2014-04-10 00:30:00,19.5728870352 2014-04-10 00:35:00,20.0197910512 2014-04-10 00:40:00,21.570461336399998 2014-04-10 00:45:00,21.4750297264 2014-04-10 00:50:00,20.297420281199997 2014-04-10 00:55:00,18.8871020391 2014-04-10 01:00:00,19.613427887 2014-04-10 01:05:00,21.9025322615 2014-04-10 01:10:00,20.4310928955 2014-04-10 01:15:00,21.1243910205 2014-04-10 01:20:00,19.799458781400002 2014-04-10 01:25:00,20.1280291019 2014-04-10 01:30:00,19.7158164489 2014-04-10 01:35:00,20.8116839922 2014-04-10 01:40:00,21.4058840555 2014-04-10 01:45:00,20.0294541729 2014-04-10 01:50:00,19.9234698345 2014-04-10 01:55:00,19.361145868399998 2014-04-10 02:00:00,18.7083867772 2014-04-10 02:05:00,21.7569908915 2014-04-10 02:10:00,19.2643188747 2014-04-10 02:15:00,21.2027658543 2014-04-10 02:20:00,20.8613880851 2014-04-10 02:25:00,21.1636704011 2014-04-10 02:30:00,21.7470725335 2014-04-10 02:35:00,20.4934830409 2014-04-10 02:40:00,21.591801373499997 2014-04-10 02:45:00,18.670789291600002 2014-04-10 02:50:00,20.5068503038 2014-04-10 02:55:00,21.0891024517 2014-04-10 03:00:00,19.086564523 2014-04-10 03:05:00,20.9630152052 2014-04-10 03:10:00,21.1139073165 2014-04-10 03:15:00,21.3247518241 2014-04-10 03:20:00,19.2515316504 2014-04-10 03:25:00,20.7264263607 2014-04-10 03:30:00,19.2170131336 2014-04-10 03:35:00,20.95616155 2014-04-10 03:40:00,19.8518946606 2014-04-10 03:45:00,20.390177498099998 2014-04-10 03:50:00,19.6633599257 2014-04-10 03:55:00,18.6479317077 2014-04-10 04:00:00,18.7121181184 2014-04-10 04:05:00,18.310275629 2014-04-10 04:10:00,20.472290718900002 2014-04-10 04:15:00,21.3945535918 2014-04-10 04:20:00,18.083347305 2014-04-10 04:25:00,18.2649580084 2014-04-10 04:30:00,19.829867969200002 2014-04-10 04:35:00,20.950882944700002 2014-04-10 04:40:00,18.6308305788 2014-04-10 04:45:00,19.0866052782 2014-04-10 04:50:00,18.9280248051 2014-04-10 04:55:00,19.5962048747 2014-04-10 05:00:00,18.8999947081 2014-04-10 05:05:00,19.410394714200002 2014-04-10 05:10:00,20.9141703946 2014-04-10 05:15:00,20.4440369938 2014-04-10 05:20:00,18.324726821600002 2014-04-10 05:25:00,20.550982665 2014-04-10 05:30:00,19.908308686199998 2014-04-10 05:35:00,21.738262298800002 2014-04-10 05:40:00,19.1572172684 2014-04-10 05:45:00,20.9046656788 2014-04-10 05:50:00,20.9234432922 2014-04-10 05:55:00,18.886003124000002 2014-04-10 06:00:00,21.612894499899998 2014-04-10 06:05:00,19.964732801700002 2014-04-10 06:10:00,20.7155334676 2014-04-10 06:15:00,18.5834222355 2014-04-10 06:20:00,19.031215667999998 2014-04-10 06:25:00,20.344428471700002 2014-04-10 06:30:00,19.2761090735 2014-04-10 06:35:00,19.998771674300002 2014-04-10 06:40:00,19.4960207975 2014-04-10 06:45:00,20.5622151866 2014-04-10 06:50:00,19.948581451099997 2014-04-10 06:55:00,18.0184397439 2014-04-10 07:00:00,20.5987233518 2014-04-10 07:05:00,19.6884862282 2014-04-10 07:10:00,19.366793362 2014-04-10 07:15:00,18.3765870091 2014-04-10 07:20:00,18.8814787623 2014-04-10 07:25:00,18.8950891663 2014-04-10 07:30:00,21.7414779976 2014-04-10 07:35:00,19.730051899 2014-04-10 07:40:00,18.1682633889 2014-04-10 07:45:00,18.555266729 2014-04-10 07:50:00,18.3161307029 2014-04-10 07:55:00,20.3554775608 2014-04-10 08:00:00,18.7464859663 2014-04-10 08:05:00,19.9942305611 2014-04-10 08:10:00,19.4802482515 2014-04-10 08:15:00,21.2155055086 2014-04-10 08:20:00,19.2819585491 2014-04-10 08:25:00,19.8330619296 2014-04-10 08:30:00,20.8851421944 2014-04-10 08:35:00,19.7334048277 2014-04-10 08:40:00,21.1728621441 2014-04-10 08:45:00,20.6467374249 2014-04-10 08:50:00,19.6421164558 2014-04-10 08:55:00,20.0159277027 2014-04-10 09:00:00,74.3539669995 2014-04-10 09:05:00,70.1979163525 2014-04-10 09:10:00,73.5079350732 2014-04-10 09:15:00,63.63111564720001 2014-04-10 09:20:00,67.7720117249 2014-04-10 09:25:00,73.5577987099 2014-04-10 09:30:00,65.5875240356 2014-04-10 09:35:00,74.3602330948 2014-04-10 09:40:00,62.5202538704 2014-04-10 09:45:00,73.4763279157 2014-04-10 09:50:00,67.2548848601 2014-04-10 09:55:00,62.2029206459 2014-04-10 10:00:00,83.49017511689999 2014-04-10 10:05:00,73.75011209659999 2014-04-10 10:10:00,70.1853219477 2014-04-10 10:15:00,71.9477262784 2014-04-10 10:20:00,80.0694607943 2014-04-10 10:25:00,85.0156343114 2014-04-10 10:30:00,71.5698924063 2014-04-10 10:35:00,77.0094337069 2014-04-10 10:40:00,72.6434792707 2014-04-10 10:45:00,81.4029670093 2014-04-10 10:50:00,71.6722741243 2014-04-10 10:55:00,73.5623439364 2014-04-10 11:00:00,74.6916405095 2014-04-10 11:05:00,80.355274587 2014-04-10 11:10:00,85.4551197992 2014-04-10 11:15:00,79.6963785592 2014-04-10 11:20:00,72.4943038729 2014-04-10 11:25:00,80.52813755220001 2014-04-10 11:30:00,84.2517739732 2014-04-10 11:35:00,73.6698121619 2014-04-10 11:40:00,72.7243991529 2014-04-10 11:45:00,74.5548948943 2014-04-10 11:50:00,83.4337568782 2014-04-10 11:55:00,80.9780853922 2014-04-10 12:00:00,80.55273504600001 2014-04-10 12:05:00,75.90048830010001 2014-04-10 12:10:00,77.2230065813 2014-04-10 12:15:00,87.3492152148 2014-04-10 12:20:00,75.7589836233 2014-04-10 12:25:00,86.32261518 2014-04-10 12:30:00,81.1909578664 2014-04-10 12:35:00,73.8839761698 2014-04-10 12:40:00,79.3816256528 2014-04-10 12:45:00,87.0721673424 2014-04-10 12:50:00,78.60261311069999 2014-04-10 12:55:00,85.7112080146 2014-04-10 13:00:00,76.08459442819999 2014-04-10 13:05:00,81.11528208770001 2014-04-10 13:10:00,85.4811125393 2014-04-10 13:15:00,86.7101996151 2014-04-10 13:20:00,79.7540283127 2014-04-10 13:25:00,82.215273232 2014-04-10 13:30:00,72.03039064880002 2014-04-10 13:35:00,76.03332054270001 2014-04-10 13:40:00,76.4410434055 2014-04-10 13:45:00,73.4782491733 2014-04-10 13:50:00,76.4567661849 2014-04-10 13:55:00,77.1194394203 2014-04-10 14:00:00,87.4960566208 2014-04-10 14:05:00,82.6936686023 2014-04-10 14:10:00,78.8122980988 2014-04-10 14:15:00,87.8046565453 2014-04-10 14:20:00,74.4481434413 2014-04-10 14:25:00,79.6129974956 2014-04-10 14:30:00,82.349042369 2014-04-10 14:35:00,72.8857914658 2014-04-10 14:40:00,83.4679750742 2014-04-10 14:45:00,73.5943449486 2014-04-10 14:50:00,74.24095320079998 2014-04-10 14:55:00,74.5514535578 2014-04-10 15:00:00,86.861403349 2014-04-10 15:05:00,82.93097257720001 2014-04-10 15:10:00,82.486048144 2014-04-10 15:15:00,80.8871194196 2014-04-10 15:20:00,76.6841598041 2014-04-10 15:25:00,81.9334487049 2014-04-10 15:30:00,78.5616413192 2014-04-10 15:35:00,74.32594486560001 2014-04-10 15:40:00,83.0327595231 2014-04-10 15:45:00,74.0726035831 2014-04-10 15:50:00,75.0499768096 2014-04-10 15:55:00,85.0823721909 2014-04-10 16:00:00,82.5617150192 2014-04-10 16:05:00,82.0957008434 2014-04-10 16:10:00,78.69109346229999 2014-04-10 16:15:00,78.3403378781 2014-04-10 16:20:00,83.0440423021 2014-04-10 16:25:00,83.8399276448 2014-04-10 16:30:00,80.1632573241 2014-04-10 16:35:00,87.5081398936 2014-04-10 16:40:00,87.29102534360001 2014-04-10 16:45:00,78.5987209304 2014-04-10 16:50:00,85.129792619 2014-04-10 16:55:00,80.6921305364 2014-04-10 17:00:00,80.1880634087 2014-04-10 17:05:00,72.8793969964 2014-04-10 17:10:00,81.183564193 2014-04-10 17:15:00,86.40921370790001 2014-04-10 17:20:00,84.482109146 2014-04-10 17:25:00,84.5810418361 2014-04-10 17:30:00,74.5588359866 2014-04-10 17:35:00,77.7351613038 2014-04-10 17:40:00,75.73124958560001 2014-04-10 17:45:00,77.05461493029999 2014-04-10 17:50:00,81.2725982872 2014-04-10 17:55:00,77.8365111247 2014-04-10 18:00:00,32.3884598132 2014-04-10 18:05:00,31.6064019205 2014-04-10 18:10:00,30.6343336923 2014-04-10 18:15:00,29.4105763321 2014-04-10 18:20:00,34.507759501500004 2014-04-10 18:25:00,28.872783998899997 2014-04-10 18:30:00,28.8105703925 2014-04-10 18:35:00,34.0914989889 2014-04-10 18:40:00,35.1795832636 2014-04-10 18:45:00,33.4534516743 2014-04-10 18:50:00,28.8977470152 2014-04-10 18:55:00,30.2508116425 2014-04-10 19:00:00,24.5137643524 2014-04-10 19:05:00,23.782545745100002 2014-04-10 19:10:00,22.699262055 2014-04-10 19:15:00,21.2211348142 2014-04-10 19:20:00,20.2243774131 2014-04-10 19:25:00,20.2534582864 2014-04-10 19:30:00,22.9016730123 2014-04-10 19:35:00,20.257805694800002 2014-04-10 19:40:00,24.6114616857 2014-04-10 19:45:00,20.9815584231 2014-04-10 19:50:00,23.3439677006 2014-04-10 19:55:00,20.854666407899998 2014-04-10 20:00:00,20.6442224051 2014-04-10 20:05:00,18.7621836124 2014-04-10 20:10:00,21.572724168 2014-04-10 20:15:00,20.8278365541 2014-04-10 20:20:00,18.7849385508 2014-04-10 20:25:00,21.9078087681 2014-04-10 20:30:00,20.6725879981 2014-04-10 20:35:00,22.2068418353 2014-04-10 20:40:00,22.1864890723 2014-04-10 20:45:00,22.202399639299998 2014-04-10 20:50:00,18.750607955 2014-04-10 20:55:00,18.927442765 2014-04-10 21:00:00,22.0561871365 2014-04-10 21:05:00,20.0461651723 2014-04-10 21:10:00,19.0438298746 2014-04-10 21:15:00,21.1798354604 2014-04-10 21:20:00,19.1486151143 2014-04-10 21:25:00,21.0092252419 2014-04-10 21:30:00,21.451618945899998 2014-04-10 21:35:00,21.238511314100002 2014-04-10 21:40:00,19.1878529038 2014-04-10 21:45:00,19.7005853248 2014-04-10 21:50:00,19.7473383839 2014-04-10 21:55:00,20.060924063399998 2014-04-10 22:00:00,18.6874141087 2014-04-10 22:05:00,19.828897676900002 2014-04-10 22:10:00,20.0623733589 2014-04-10 22:15:00,20.146157739 2014-04-10 22:20:00,21.3000301271 2014-04-10 22:25:00,20.088604548499998 2014-04-10 22:30:00,18.941301891 2014-04-10 22:35:00,20.6723413572 2014-04-10 22:40:00,21.2095982522 2014-04-10 22:45:00,19.295993043499998 2014-04-10 22:50:00,20.6009816807 2014-04-10 22:55:00,18.605596216600002 2014-04-10 23:00:00,19.3714238158 2014-04-10 23:05:00,21.64105 2014-04-10 23:10:00,21.6493885352 2014-04-10 23:15:00,20.3051961623 2014-04-10 23:20:00,20.8134012473 2014-04-10 23:25:00,21.4201735426 2014-04-10 23:30:00,21.838404908 2014-04-10 23:35:00,19.963377992 2014-04-10 23:40:00,20.2501902347 2014-04-10 23:45:00,19.6663414774 2014-04-10 23:50:00,18.2914390286 2014-04-10 23:55:00,19.6949946009 2014-04-11 00:00:00,21.1625093575 2014-04-11 00:05:00,21.219541992 2014-04-11 00:10:00,21.5695084584 2014-04-11 00:15:00,18.2058668207 2014-04-11 00:20:00,20.1086183583 2014-04-11 00:25:00,18.4296979517 2014-04-11 00:30:00,18.8029687327 2014-04-11 00:35:00,21.6008660095 2014-04-11 00:40:00,19.9871650337 2014-04-11 00:45:00,21.034179683599998 2014-04-11 00:50:00,18.2575364237 2014-04-11 00:55:00,19.6673060157 2014-04-11 01:00:00,20.6969611227 2014-04-11 01:05:00,18.5336259251 2014-04-11 01:10:00,19.303271516400002 2014-04-11 01:15:00,18.2581912201 2014-04-11 01:20:00,20.605359763499997 2014-04-11 01:25:00,21.8835650362 2014-04-11 01:30:00,21.3081819646 2014-04-11 01:35:00,21.898492467199997 2014-04-11 01:40:00,21.3824191804 2014-04-11 01:45:00,21.4207832248 2014-04-11 01:50:00,20.308708781500002 2014-04-11 01:55:00,20.0730092457 2014-04-11 02:00:00,19.6250170657 2014-04-11 02:05:00,21.2723795802 2014-04-11 02:10:00,18.728270449100002 2014-04-11 02:15:00,18.2248996633 2014-04-11 02:20:00,21.791575290700003 2014-04-11 02:25:00,18.0151127408 2014-04-11 02:30:00,21.9073172875 2014-04-11 02:35:00,20.9154134795 2014-04-11 02:40:00,19.3139956788 2014-04-11 02:45:00,20.7912793723 2014-04-11 02:50:00,21.2715006287 2014-04-11 02:55:00,18.9814482239 2014-04-11 03:00:00,21.0835827331 2014-04-11 03:05:00,21.2174785 2014-04-11 03:10:00,18.9974185205 2014-04-11 03:15:00,18.1677054175 2014-04-11 03:20:00,18.816489138199998 2014-04-11 03:25:00,18.8025856356 2014-04-11 03:30:00,18.2609618167 2014-04-11 03:35:00,20.9040295386 2014-04-11 03:40:00,19.5198996978 2014-04-11 03:45:00,21.5375446698 2014-04-11 03:50:00,19.0086844227 2014-04-11 03:55:00,19.8129286604 2014-04-11 04:00:00,20.556069715699998 2014-04-11 04:05:00,21.5098597987 2014-04-11 04:10:00,20.098484406500003 2014-04-11 04:15:00,19.494098511199997 2014-04-11 04:20:00,21.4680603139 2014-04-11 04:25:00,19.2409856988 2014-04-11 04:30:00,18.3176947985 2014-04-11 04:35:00,19.78016843 2014-04-11 04:40:00,21.140373225999998 2014-04-11 04:45:00,18.123123327000002 2014-04-11 04:50:00,20.34352898 2014-04-11 04:55:00,20.3778561941 2014-04-11 05:00:00,21.7141670537 2014-04-11 05:05:00,19.1458592686 2014-04-11 05:10:00,19.1153464528 2014-04-11 05:15:00,19.7619346054 2014-04-11 05:20:00,19.4276596059 2014-04-11 05:25:00,20.945383450799998 2014-04-11 05:30:00,20.5670083085 2014-04-11 05:35:00,21.0356841516 2014-04-11 05:40:00,21.2801671648 2014-04-11 05:45:00,21.691924530900003 2014-04-11 05:50:00,19.7237469271 2014-04-11 05:55:00,21.938789557899998 2014-04-11 06:00:00,18.862643253599998 2014-04-11 06:05:00,20.8574606478 2014-04-11 06:10:00,20.1360372692 2014-04-11 06:15:00,21.267602378699998 2014-04-11 06:20:00,19.9070820824 2014-04-11 06:25:00,21.1357545414 2014-04-11 06:30:00,21.720674858600002 2014-04-11 06:35:00,20.9291770646 2014-04-11 06:40:00,21.1043771449 2014-04-11 06:45:00,18.2687017251 2014-04-11 06:50:00,18.819830648900002 2014-04-11 06:55:00,21.897214962 2014-04-11 07:00:00,20.7727480151 2014-04-11 07:05:00,20.2457960692 2014-04-11 07:10:00,19.4679054936 2014-04-11 07:15:00,18.1775560048 2014-04-11 07:20:00,19.4765436319 2014-04-11 07:25:00,19.9956514932 2014-04-11 07:30:00,18.8458380375 2014-04-11 07:35:00,18.6925471651 2014-04-11 07:40:00,20.0336662054 2014-04-11 07:45:00,20.3436169425 2014-04-11 07:50:00,18.9596716754 2014-04-11 07:55:00,20.3495578978 2014-04-11 08:00:00,21.6013598555 2014-04-11 08:05:00,19.8926930321 2014-04-11 08:10:00,21.4295606783 2014-04-11 08:15:00,21.7090857781 2014-04-11 08:20:00,18.3695761157 2014-04-11 08:25:00,18.383246318599998 2014-04-11 08:30:00,19.9041767316 2014-04-11 08:35:00,20.3524097773 2014-04-11 08:40:00,19.7035338579 2014-04-11 08:45:00,19.305803081700002 2014-04-11 08:50:00,20.5639764645 2014-04-11 08:55:00,18.0083260494 2014-04-11 09:00:00,39.370127622199995 2014-04-11 09:05:00,34.070969435 2014-04-11 09:10:00,39.003111133800004 2014-04-11 09:15:00,33.1849061606 2014-04-11 09:20:00,34.1142277107 2014-04-11 09:25:00,34.0910906478 2014-04-11 09:30:00,39.5723009102 2014-04-11 09:35:00,32.4331239292 2014-04-11 09:40:00,37.005395107 2014-04-11 09:45:00,38.661743383600005 2014-04-11 09:50:00,37.240370309 2014-04-11 09:55:00,35.011683491199996 2014-04-11 10:00:00,42.7931454036 2014-04-11 10:05:00,42.285202716 2014-04-11 10:10:00,38.6822065748 2014-04-11 10:15:00,39.7748953821 2014-04-11 10:20:00,42.8653504324 2014-04-11 10:25:00,42.9832732375 2014-04-11 10:30:00,38.8066144816 2014-04-11 10:35:00,41.9232242206 2014-04-11 10:40:00,37.6475249793 2014-04-11 10:45:00,38.1950129238 2014-04-11 10:50:00,36.5722035626 2014-04-11 10:55:00,36.9200072074 2014-04-11 11:00:00,41.0899664724 2014-04-11 11:05:00,39.9259079323 2014-04-11 11:10:00,37.6976586655 2014-04-11 11:15:00,39.0663838232 2014-04-11 11:20:00,38.8295258082 2014-04-11 11:25:00,43.72328610970001 2014-04-11 11:30:00,42.6572125909 2014-04-11 11:35:00,38.9473157444 2014-04-11 11:40:00,43.138087300600006 2014-04-11 11:45:00,38.5861188005 2014-04-11 11:50:00,41.1778392535 2014-04-11 11:55:00,43.558267173599994 2014-04-11 12:00:00,39.090933127199996 2014-04-11 12:05:00,41.4059284571 2014-04-11 12:10:00,38.3366965761 2014-04-11 12:15:00,38.099994126 2014-04-11 12:20:00,40.5607787288 2014-04-11 12:25:00,43.7990494908 2014-04-11 12:30:00,39.5933707331 2014-04-11 12:35:00,43.4662948859 2014-04-11 12:40:00,43.2802562354 2014-04-11 12:45:00,37.999676818000005 2014-04-11 12:50:00,39.1831836125 2014-04-11 12:55:00,41.1135026921 2014-04-11 13:00:00,40.1379439766 2014-04-11 13:05:00,36.761785411999995 2014-04-11 13:10:00,43.9425523075 2014-04-11 13:15:00,42.014508612600004 2014-04-11 13:20:00,39.495232057399996 2014-04-11 13:25:00,40.9387971416 2014-04-11 13:30:00,36.6947104449 2014-04-11 13:35:00,39.9560192434 2014-04-11 13:40:00,43.439707861 2014-04-11 13:45:00,43.1659000152 2014-04-11 13:50:00,38.6928549164 2014-04-11 13:55:00,40.2445027597 2014-04-11 14:00:00,41.5777376625 2014-04-11 14:05:00,38.7188350929 2014-04-11 14:10:00,36.5178651357 2014-04-11 14:15:00,40.0422518607 2014-04-11 14:20:00,40.8117798678 2014-04-11 14:25:00,36.0455793055 2014-04-11 14:30:00,36.763426521 2014-04-11 14:35:00,37.6571200823 2014-04-11 14:40:00,38.7831771945 2014-04-11 14:45:00,40.327119273499996 2014-04-11 14:50:00,38.3495161263 2014-04-11 14:55:00,38.2082478122 2014-04-11 15:00:00,42.95451983979999 2014-04-11 15:05:00,37.1601672998 2014-04-11 15:10:00,39.9634252978 2014-04-11 15:15:00,43.62231855090001 2014-04-11 15:20:00,40.9998435923 2014-04-11 15:25:00,41.737376718200004 2014-04-11 15:30:00,39.4496434518 2014-04-11 15:35:00,36.1592259164 2014-04-11 15:40:00,41.1687794651 2014-04-11 15:45:00,41.0551314969 2014-04-11 15:50:00,36.883185037800004 2014-04-11 15:55:00,39.6970236464 2014-04-11 16:00:00,43.32257610439999 2014-04-11 16:05:00,37.6406304757 2014-04-11 16:10:00,39.6887392354 2014-04-11 16:15:00,39.6887746799 2014-04-11 16:20:00,42.486037363 2014-04-11 16:25:00,42.596552439 2014-04-11 16:30:00,42.0741015024 2014-04-11 16:35:00,38.923583451300004 2014-04-11 16:40:00,36.5762485825 2014-04-11 16:45:00,38.7958141591 2014-04-11 16:50:00,41.4382765691 2014-04-11 16:55:00,41.6219193198 2014-04-11 17:00:00,43.719990483500005 2014-04-11 17:05:00,39.6291197065 2014-04-11 17:10:00,41.0594741523 2014-04-11 17:15:00,40.3135166455 2014-04-11 17:20:00,37.2049389564 2014-04-11 17:25:00,39.6896096165 2014-04-11 17:30:00,40.3586709057 2014-04-11 17:35:00,43.605985685200004 2014-04-11 17:40:00,38.9323024686 2014-04-11 17:45:00,43.8407816016 2014-04-11 17:50:00,40.3383902656 2014-04-11 17:55:00,37.9397442338 2014-04-11 18:00:00,22.519987135999997 2014-04-11 18:05:00,22.280133701599997 2014-04-11 18:10:00,23.77407575 2014-04-11 18:15:00,21.7052450108 2014-04-11 18:20:00,23.7362153344 2014-04-11 18:25:00,26.3443402743 2014-04-11 18:30:00,24.8165105018 2014-04-11 18:35:00,25.246971227399996 2014-04-11 18:40:00,22.1712239835 2014-04-11 18:45:00,23.870882098200003 2014-04-11 18:50:00,22.9738689245 2014-04-11 18:55:00,25.891665924899996 2014-04-11 19:00:00,19.4741763001 2014-04-11 19:05:00,20.6283302347 2014-04-11 19:10:00,21.1662780915 2014-04-11 19:15:00,20.8584105302 2014-04-11 19:20:00,22.1738126397 2014-04-11 19:25:00,19.6828448051 2014-04-11 19:30:00,20.2899466198 2014-04-11 19:35:00,22.0150702402 2014-04-11 19:40:00,20.9167766609 2014-04-11 19:45:00,20.3928079227 2014-04-11 19:50:00,18.842480490299998 2014-04-11 19:55:00,21.8540829335 2014-04-11 20:00:00,22.0638380487 2014-04-11 20:05:00,20.6449971384 2014-04-11 20:10:00,21.5975741141 2014-04-11 20:15:00,20.2280429144 2014-04-11 20:20:00,19.0781375751 2014-04-11 20:25:00,18.2022304903 2014-04-11 20:30:00,20.7785017305 2014-04-11 20:35:00,20.1322147943 2014-04-11 20:40:00,21.2974196425 2014-04-11 20:45:00,20.944959422 2014-04-11 20:50:00,22.1274238587 2014-04-11 20:55:00,20.2015802542 2014-04-11 21:00:00,19.740233061199998 2014-04-11 21:05:00,19.177593876099998 2014-04-11 21:10:00,19.9392970631 2014-04-11 21:15:00,21.5258722723 2014-04-11 21:20:00,18.1988305025 2014-04-11 21:25:00,21.9466587315 2014-04-11 21:30:00,22.0083859253 2014-04-11 21:35:00,20.423911554500002 2014-04-11 21:40:00,19.357098681900002 2014-04-11 21:45:00,18.922423371199997 2014-04-11 21:50:00,19.1365311056 2014-04-11 21:55:00,18.2295423658 2014-04-11 22:00:00,19.906811972699998 2014-04-11 22:05:00,18.2351304555 2014-04-11 22:10:00,20.8805765027 2014-04-11 22:15:00,19.4939538886 2014-04-11 22:20:00,18.8034741108 2014-04-11 22:25:00,20.1858716406 2014-04-11 22:30:00,21.9020436373 2014-04-11 22:35:00,20.7871739604 2014-04-11 22:40:00,19.973376833099998 2014-04-11 22:45:00,21.114411643900002 2014-04-11 22:50:00,20.956609854 2014-04-11 22:55:00,21.5738432621 2014-04-11 23:00:00,18.819880185 2014-04-11 23:05:00,21.436882177 2014-04-11 23:10:00,19.2053334102 2014-04-11 23:15:00,21.7653886063 2014-04-11 23:20:00,19.1254845478 2014-04-11 23:25:00,21.708783445199998 2014-04-11 23:30:00,21.8565615876 2014-04-11 23:35:00,18.583154675 2014-04-11 23:40:00,21.8994010043 2014-04-11 23:45:00,18.3440658182 2014-04-11 23:50:00,18.8754790992 2014-04-11 23:55:00,19.7779408301 2014-04-12 00:00:00,21.9743894628 2014-04-12 00:05:00,19.9542522047 2014-04-12 00:10:00,20.2016377727 2014-04-12 00:15:00,20.7776997981 2014-04-12 00:20:00,21.8731742331 2014-04-12 00:25:00,21.133405600499998 2014-04-12 00:30:00,18.8966160177 2014-04-12 00:35:00,19.2119637227 2014-04-12 00:40:00,18.3905129584 2014-04-12 00:45:00,20.577809456700002 2014-04-12 00:50:00,18.7229612262 2014-04-12 00:55:00,19.0296195539 2014-04-12 01:00:00,21.5524546207 2014-04-12 01:05:00,19.307022701300003 2014-04-12 01:10:00,20.266586873399998 2014-04-12 01:15:00,19.5902640352 2014-04-12 01:20:00,18.2961251496 2014-04-12 01:25:00,19.4514553196 2014-04-12 01:30:00,19.632272812100002 2014-04-12 01:35:00,21.5828044076 2014-04-12 01:40:00,19.297802614600002 2014-04-12 01:45:00,19.516964479000002 2014-04-12 01:50:00,21.1315870747 2014-04-12 01:55:00,21.0358266048 2014-04-12 02:00:00,21.193141106600002 2014-04-12 02:05:00,21.815082960300003 2014-04-12 02:10:00,21.1822299936 2014-04-12 02:15:00,19.6304328129 2014-04-12 02:20:00,21.2860340676 2014-04-12 02:25:00,20.0346985284 2014-04-12 02:30:00,19.1108561301 2014-04-12 02:35:00,19.2116682725 2014-04-12 02:40:00,18.8953695543 2014-04-12 02:45:00,18.5799718313 2014-04-12 02:50:00,18.7379616474 2014-04-12 02:55:00,18.2527121998 2014-04-12 03:00:00,21.5538034597 2014-04-12 03:05:00,21.724031238600002 2014-04-12 03:10:00,20.34708157 2014-04-12 03:15:00,21.361958226400002 2014-04-12 03:20:00,18.7342844106 2014-04-12 03:25:00,21.6066953009 2014-04-12 03:30:00,20.0254462385 2014-04-12 03:35:00,18.268659970399998 2014-04-12 03:40:00,18.565250977999998 2014-04-12 03:45:00,19.2359058431 2014-04-12 03:50:00,18.1742303214 2014-04-12 03:55:00,19.2371735121 2014-04-12 04:00:00,18.2397217325 2014-04-12 04:05:00,18.944110420799998 2014-04-12 04:10:00,19.062679023399998 2014-04-12 04:15:00,21.9774759055 2014-04-12 04:20:00,18.9421866951 2014-04-12 04:25:00,18.9567457958 2014-04-12 04:30:00,20.7471558734 2014-04-12 04:35:00,21.4374299141 2014-04-12 04:40:00,19.5482216504 2014-04-12 04:45:00,21.5024720798 2014-04-12 04:50:00,19.360568083 2014-04-12 04:55:00,18.7880635185 2014-04-12 05:00:00,19.3185552973 2014-04-12 05:05:00,20.437425495699998 2014-04-12 05:10:00,19.4685726372 2014-04-12 05:15:00,20.691575216 2014-04-12 05:20:00,18.9477435177 2014-04-12 05:25:00,20.803971576 2014-04-12 05:30:00,19.389753453 2014-04-12 05:35:00,19.8234734864 2014-04-12 05:40:00,20.2309805618 2014-04-12 05:45:00,20.7449000127 2014-04-12 05:50:00,18.9548547674 2014-04-12 05:55:00,21.3437821496 2014-04-12 06:00:00,20.887370999 2014-04-12 06:05:00,18.936391676099998 2014-04-12 06:10:00,21.8998982504 2014-04-12 06:15:00,20.6591879641 2014-04-12 06:20:00,19.8097075459 2014-04-12 06:25:00,18.6301093022 2014-04-12 06:30:00,20.1328840092 2014-04-12 06:35:00,18.6591035473 2014-04-12 06:40:00,19.7179667148 2014-04-12 06:45:00,19.634850091 2014-04-12 06:50:00,20.8797585774 2014-04-12 06:55:00,18.7695327249 2014-04-12 07:00:00,21.2874854195 2014-04-12 07:05:00,19.3045293081 2014-04-12 07:10:00,19.7759545079 2014-04-12 07:15:00,21.0893639022 2014-04-12 07:20:00,20.5015695989 2014-04-12 07:25:00,19.232101407200002 2014-04-12 07:30:00,19.5448116982 2014-04-12 07:35:00,19.223147256 2014-04-12 07:40:00,20.379080669100002 2014-04-12 07:45:00,19.3304981328 2014-04-12 07:50:00,20.902790779100002 2014-04-12 07:55:00,20.3191486343 2014-04-12 08:00:00,18.582826447000002 2014-04-12 08:05:00,19.2410744747 2014-04-12 08:10:00,18.8857897676 2014-04-12 08:15:00,19.5612528502 2014-04-12 08:20:00,20.063936344800002 2014-04-12 08:25:00,20.027051429100002 2014-04-12 08:30:00,21.0180947063 2014-04-12 08:35:00,18.7566874544 2014-04-12 08:40:00,21.785891317199997 2014-04-12 08:45:00,19.3713804275 2014-04-12 08:50:00,19.2009953877 2014-04-12 08:55:00,20.7407143127 2014-04-12 09:00:00,72.1550261501 2014-04-12 09:05:00,66.3472160015 2014-04-12 09:10:00,71.3571188586 2014-04-12 09:15:00,73.2188090035 2014-04-12 09:20:00,71.6285298468 2014-04-12 09:25:00,61.6650722038 2014-04-12 09:30:00,72.4522171946 2014-04-12 09:35:00,71.732941035 2014-04-12 09:40:00,70.3023472389 2014-04-12 09:45:00,71.5363048996 2014-04-12 09:50:00,74.5201853833 2014-04-12 09:55:00,67.06313527430001 2014-04-12 10:00:00,70.88330460649999 2014-04-12 10:05:00,76.9930123286 2014-04-12 10:10:00,70.5606503317 2014-04-12 10:15:00,74.4067663335 2014-04-12 10:20:00,78.9483743687 2014-04-12 10:25:00,74.6453472982 2014-04-12 10:30:00,80.4773342165 2014-04-12 10:35:00,82.5972278057 2014-04-12 10:40:00,76.3652160624 2014-04-12 10:45:00,83.8101410041 2014-04-12 10:50:00,71.0791002146 2014-04-12 10:55:00,82.87855630840001 2014-04-12 11:00:00,84.7456273051 2014-04-12 11:05:00,76.68899092720001 2014-04-12 11:10:00,76.31876633600001 2014-04-12 11:15:00,76.4202305803 2014-04-12 11:20:00,84.4724056011 2014-04-12 11:25:00,84.794617067 2014-04-12 11:30:00,76.8119059852 2014-04-12 11:35:00,80.9925568858 2014-04-12 11:40:00,73.777594081 2014-04-12 11:45:00,79.0234570536 2014-04-12 11:50:00,87.4528015 2014-04-12 11:55:00,74.0941778051 2014-04-12 12:00:00,87.0564090367 2014-04-12 12:05:00,85.0858498608 2014-04-12 12:10:00,87.45036789379999 2014-04-12 12:15:00,74.7834122576 2014-04-12 12:20:00,75.3257962921 2014-04-12 12:25:00,72.1831510579 2014-04-12 12:30:00,83.49491473180001 2014-04-12 12:35:00,82.20674847689999 2014-04-12 12:40:00,74.7592281568 2014-04-12 12:45:00,84.5567294653 2014-04-12 12:50:00,76.69498354439999 2014-04-12 12:55:00,74.0709371944 2014-04-12 13:00:00,78.7420999997 2014-04-12 13:05:00,73.43788825060001 2014-04-12 13:10:00,76.19360764470001 2014-04-12 13:15:00,77.92262781470001 2014-04-12 13:20:00,85.6092756338 2014-04-12 13:25:00,84.6604564735 2014-04-12 13:30:00,79.0650883956 2014-04-12 13:35:00,83.5731385558 2014-04-12 13:40:00,81.07893056430001 2014-04-12 13:45:00,77.4348808485 2014-04-12 13:50:00,83.5939221384 2014-04-12 13:55:00,82.91608183470001 2014-04-12 14:00:00,81.90157961060001 2014-04-12 14:05:00,81.88335774689999 2014-04-12 14:10:00,82.9237313471 2014-04-12 14:15:00,78.14897687130002 2014-04-12 14:20:00,85.9010895909 2014-04-12 14:25:00,74.59334487550001 2014-04-12 14:30:00,86.13803258780001 2014-04-12 14:35:00,77.4727906161 2014-04-12 14:40:00,73.9969538255 2014-04-12 14:45:00,81.59652162180001 2014-04-12 14:50:00,78.0120419474 2014-04-12 14:55:00,85.0439133299 2014-04-12 15:00:00,78.8918101278 2014-04-12 15:05:00,82.6962065178 2014-04-12 15:10:00,76.9313892837 2014-04-12 15:15:00,75.35051462850001 2014-04-12 15:20:00,78.2080336909 2014-04-12 15:25:00,81.70814094800001 2014-04-12 15:30:00,82.5103557204 2014-04-12 15:35:00,81.2505266322 2014-04-12 15:40:00,87.8080485326 2014-04-12 15:45:00,83.0566456325 2014-04-12 15:50:00,86.9034797601 2014-04-12 15:55:00,73.8862218038 2014-04-12 16:00:00,72.9818267516 2014-04-12 16:05:00,76.9757674384 2014-04-12 16:10:00,74.185280578 2014-04-12 16:15:00,80.413742057 2014-04-12 16:20:00,80.3035458733 2014-04-12 16:25:00,81.2005987577 2014-04-12 16:30:00,83.9234849599 2014-04-12 16:35:00,87.5411071241 2014-04-12 16:40:00,86.05197384290001 2014-04-12 16:45:00,73.893733957 2014-04-12 16:50:00,77.4160703812 2014-04-12 16:55:00,76.09302230189999 2014-04-12 17:00:00,74.8290489901 2014-04-12 17:05:00,80.7155670317 2014-04-12 17:10:00,80.8521993853 2014-04-12 17:15:00,75.635888202 2014-04-12 17:20:00,83.390323983 2014-04-12 17:25:00,83.72659663569999 2014-04-12 17:30:00,72.3356521404 2014-04-12 17:35:00,78.33209318 2014-04-12 17:40:00,86.24221714219999 2014-04-12 17:45:00,80.32506688710002 2014-04-12 17:50:00,77.5620150392 2014-04-12 17:55:00,76.0587892189 2014-04-12 18:00:00,30.3574630988 2014-04-12 18:05:00,29.438509764499997 2014-04-12 18:10:00,34.030242548400004 2014-04-12 18:15:00,29.3546017584 2014-04-12 18:20:00,30.6706806127 2014-04-12 18:25:00,29.09231914110001 2014-04-12 18:30:00,33.8008675565 2014-04-12 18:35:00,29.051409988400003 2014-04-12 18:40:00,30.7731211563 2014-04-12 18:45:00,32.4690969345 2014-04-12 18:50:00,31.421186673 2014-04-12 18:55:00,30.6065289539 2014-04-12 19:00:00,21.3928458709 2014-04-12 19:05:00,23.7340992689 2014-04-12 19:10:00,24.5234205207 2014-04-12 19:15:00,21.7192228042 2014-04-12 19:20:00,20.3353707854 2014-04-12 19:25:00,20.3238135701 2014-04-12 19:30:00,23.561274807600004 2014-04-12 19:35:00,22.6346155591 2014-04-12 19:40:00,23.6704938067 2014-04-12 19:45:00,23.2847853288 2014-04-12 19:50:00,24.2256271158 2014-04-12 19:55:00,24.1284915003 2014-04-12 20:00:00,21.6609887525 2014-04-12 20:05:00,20.378374555 2014-04-12 20:10:00,19.694085529200002 2014-04-12 20:15:00,20.5087814753 2014-04-12 20:20:00,20.4884850577 2014-04-12 20:25:00,20.9316883971 2014-04-12 20:30:00,19.194255407300002 2014-04-12 20:35:00,21.1174187769 2014-04-12 20:40:00,20.3022371419 2014-04-12 20:45:00,20.97235874 2014-04-12 20:50:00,19.4134211217 2014-04-12 20:55:00,20.2112812428 2014-04-12 21:00:00,18.9312406748 2014-04-12 21:05:00,21.6044264332 2014-04-12 21:10:00,20.0476129832 2014-04-12 21:15:00,18.990645259 2014-04-12 21:20:00,18.252025945299998 2014-04-12 21:25:00,20.8023287901 2014-04-12 21:30:00,18.9490999881 2014-04-12 21:35:00,22.0637286934 2014-04-12 21:40:00,20.2314484913 2014-04-12 21:45:00,19.2478562962 2014-04-12 21:50:00,20.7297370912 2014-04-12 21:55:00,19.1925638693 2014-04-12 22:00:00,21.3015270185 2014-04-12 22:05:00,19.2514078207 2014-04-12 22:10:00,21.974065790100003 2014-04-12 22:15:00,20.4401828877 2014-04-12 22:20:00,21.398167124100002 2014-04-12 22:25:00,18.3088214807 2014-04-12 22:30:00,19.4118151298 2014-04-12 22:35:00,20.9700602848 2014-04-12 22:40:00,20.6400314859 2014-04-12 22:45:00,18.7949983701 2014-04-12 22:50:00,19.4434595317 2014-04-12 22:55:00,19.0720652433 2014-04-12 23:00:00,20.4574077453 2014-04-12 23:05:00,19.381993544300002 2014-04-12 23:10:00,19.2399103198 2014-04-12 23:15:00,18.8331271862 2014-04-12 23:20:00,19.6398786146 2014-04-12 23:25:00,18.7856165049 2014-04-12 23:30:00,21.8544736008 2014-04-12 23:35:00,18.6215819015 2014-04-12 23:40:00,21.657376275700003 2014-04-12 23:45:00,19.717677458 2014-04-12 23:50:00,19.5152101654 2014-04-12 23:55:00,18.9289128554 2014-04-13 00:00:00,20.5430253375 2014-04-13 00:05:00,20.74211206 2014-04-13 00:10:00,19.870283849 2014-04-13 00:15:00,18.2228275828 2014-04-13 00:20:00,21.6740406028 2014-04-13 00:25:00,21.9213165315 2014-04-13 00:30:00,19.7241736608 2014-04-13 00:35:00,20.454643229600002 2014-04-13 00:40:00,19.801194505 2014-04-13 00:45:00,19.2875186035 2014-04-13 00:50:00,18.3092751714 2014-04-13 00:55:00,19.8242709216 2014-04-13 01:00:00,21.2735382254 2014-04-13 01:05:00,18.0681258444 2014-04-13 01:10:00,20.3284307327 2014-04-13 01:15:00,21.523088434899996 2014-04-13 01:20:00,18.8701977201 2014-04-13 01:25:00,18.7330234588 2014-04-13 01:30:00,21.0891065028 2014-04-13 01:35:00,19.0203457245 2014-04-13 01:40:00,18.7679370702 2014-04-13 01:45:00,19.5119570023 2014-04-13 01:50:00,19.5700080491 2014-04-13 01:55:00,21.4964042521 2014-04-13 02:00:00,20.4737738877 2014-04-13 02:05:00,19.6238458254 2014-04-13 02:10:00,20.1375518571 2014-04-13 02:15:00,21.815860933299998 2014-04-13 02:20:00,18.4528587064 2014-04-13 02:25:00,18.8308620869 2014-04-13 02:30:00,21.8501148263 2014-04-13 02:35:00,21.829299394099998 2014-04-13 02:40:00,18.7086616851 2014-04-13 02:45:00,18.5804352685 2014-04-13 02:50:00,19.6843405374 2014-04-13 02:55:00,18.19887317 2014-04-13 03:00:00,20.6196141291 2014-04-13 03:05:00,18.3099840866 2014-04-13 03:10:00,18.2321185084 2014-04-13 03:15:00,19.9407477448 2014-04-13 03:20:00,21.8311465444 2014-04-13 03:25:00,19.7071837443 2014-04-13 03:30:00,19.4259246346 2014-04-13 03:35:00,21.991826861999996 2014-04-13 03:40:00,20.1278758431 2014-04-13 03:45:00,19.5009656276 2014-04-13 03:50:00,19.5434432534 2014-04-13 03:55:00,18.779837984100002 2014-04-13 04:00:00,20.0488922298 2014-04-13 04:05:00,19.7554201127 2014-04-13 04:10:00,19.0831811854 2014-04-13 04:15:00,18.6421603464 2014-04-13 04:20:00,19.2449554747 2014-04-13 04:25:00,20.0347333108 2014-04-13 04:30:00,18.2333330891 2014-04-13 04:35:00,18.6149761143 2014-04-13 04:40:00,21.7906290679 2014-04-13 04:45:00,20.171421404100002 2014-04-13 04:50:00,18.2537972146 2014-04-13 04:55:00,20.7723510351 2014-04-13 05:00:00,18.2472114803 2014-04-13 05:05:00,20.9554969082 2014-04-13 05:10:00,20.9998508869 2014-04-13 05:15:00,20.604315903 2014-04-13 05:20:00,20.9288181785 2014-04-13 05:25:00,18.3518631241 2014-04-13 05:30:00,20.9071222094 2014-04-13 05:35:00,18.546753278900002 2014-04-13 05:40:00,19.3580236291 2014-04-13 05:45:00,21.770981014 2014-04-13 05:50:00,20.0115019106 2014-04-13 05:55:00,21.869705728299998 2014-04-13 06:00:00,18.355689835499998 2014-04-13 06:05:00,19.9102263983 2014-04-13 06:10:00,18.2496092811 2014-04-13 06:15:00,20.5208410496 2014-04-13 06:20:00,18.3148280055 2014-04-13 06:25:00,18.7014712102 2014-04-13 06:30:00,19.0353212403 2014-04-13 06:35:00,20.9949754067 2014-04-13 06:40:00,18.6558484753 2014-04-13 06:45:00,21.3865282132 2014-04-13 06:50:00,18.5276157553 2014-04-13 06:55:00,18.1409777963 2014-04-13 07:00:00,19.5801816759 2014-04-13 07:05:00,21.9177665679 2014-04-13 07:10:00,18.441368911199998 2014-04-13 07:15:00,18.406873776199998 2014-04-13 07:20:00,21.0046660432 2014-04-13 07:25:00,19.248646775999998 2014-04-13 07:30:00,20.8691264689 2014-04-13 07:35:00,18.8000423578 2014-04-13 07:40:00,19.8402879768 2014-04-13 07:45:00,19.061159511 2014-04-13 07:50:00,19.8061128595 2014-04-13 07:55:00,21.0763883703 2014-04-13 08:00:00,21.0480397619 2014-04-13 08:05:00,20.063089150699998 2014-04-13 08:10:00,21.713487374899998 2014-04-13 08:15:00,19.0551364098 2014-04-13 08:20:00,18.9612454045 2014-04-13 08:25:00,20.4552256047 2014-04-13 08:30:00,20.4851881369 2014-04-13 08:35:00,18.186160158299998 2014-04-13 08:40:00,20.4311108495 2014-04-13 08:45:00,19.4977446294 2014-04-13 08:50:00,20.9897701013 2014-04-13 08:55:00,21.2324226582 2014-04-13 09:00:00,68.7092919458 2014-04-13 09:05:00,61.2231884284 2014-04-13 09:10:00,69.8545750183 2014-04-13 09:15:00,71.3847854035 2014-04-13 09:20:00,64.5861724207 2014-04-13 09:25:00,67.5191856155 2014-04-13 09:30:00,74.3338820784 2014-04-13 09:35:00,65.2543715262 2014-04-13 09:40:00,64.2348842142 2014-04-13 09:45:00,64.0676251505 2014-04-13 09:50:00,68.7996913472 2014-04-13 09:55:00,74.11710457779999 2014-04-13 10:00:00,79.28687080520001 2014-04-13 10:05:00,74.5475748261 2014-04-13 10:10:00,79.7506029556 2014-04-13 10:15:00,79.5375524587 2014-04-13 10:20:00,79.10427810649999 2014-04-13 10:25:00,72.3142947309 2014-04-13 10:30:00,79.6884767258 2014-04-13 10:35:00,76.516152303 2014-04-13 10:40:00,70.12854874979999 2014-04-13 10:45:00,78.2171448405 2014-04-13 10:50:00,85.1934198858 2014-04-13 10:55:00,75.2679584499 2014-04-13 11:00:00,86.92425380809998 2014-04-13 11:05:00,73.0980561154 2014-04-13 11:10:00,83.21688664279999 2014-04-13 11:15:00,73.3863042351 2014-04-13 11:20:00,75.9188823058 2014-04-13 11:25:00,80.646652645 2014-04-13 11:30:00,80.995568253 2014-04-13 11:35:00,83.8969607893 2014-04-13 11:40:00,81.3539126205 2014-04-13 11:45:00,81.00884825850001 2014-04-13 11:50:00,86.07806349549999 2014-04-13 11:55:00,78.7591646031 2014-04-13 12:00:00,75.5135273562 2014-04-13 12:05:00,74.49911101949999 2014-04-13 12:10:00,78.3058336527 2014-04-13 12:15:00,83.30395923020001 2014-04-13 12:20:00,72.593478924 2014-04-13 12:25:00,73.9759763591 2014-04-13 12:30:00,73.60937798319999 2014-04-13 12:35:00,81.2663656459 2014-04-13 12:40:00,75.7947714072 2014-04-13 12:45:00,74.5705586718 2014-04-13 12:50:00,81.3865503181 2014-04-13 12:55:00,84.07994149689999 2014-04-13 13:00:00,77.2959231884 2014-04-13 13:05:00,81.2317733851 2014-04-13 13:10:00,73.5523338134 2014-04-13 13:15:00,86.94218535379999 2014-04-13 13:20:00,77.3717652837 2014-04-13 13:25:00,87.93898066889999 2014-04-13 13:30:00,87.6363663166 2014-04-13 13:35:00,84.44090450729999 2014-04-13 13:40:00,72.3037164689 2014-04-13 13:45:00,80.6762317825 2014-04-13 13:50:00,73.37176927520001 2014-04-13 13:55:00,86.3014910854 2014-04-13 14:00:00,84.63011760170002 2014-04-13 14:05:00,87.55324326809998 2014-04-13 14:10:00,81.73020401229999 2014-04-13 14:15:00,80.350907843 2014-04-13 14:20:00,80.2997271232 2014-04-13 14:25:00,78.1794211989 2014-04-13 14:30:00,79.4952251217 2014-04-13 14:35:00,82.1626573333 2014-04-13 14:40:00,86.9229892171 2014-04-13 14:45:00,81.5302357729 2014-04-13 14:50:00,85.70974081199999 2014-04-13 14:55:00,85.8003599659 2014-04-13 15:00:00,80.3005519209 2014-04-13 15:05:00,77.55876969260001 2014-04-13 15:10:00,82.2323925348 2014-04-13 15:15:00,79.1332777839 2014-04-13 15:20:00,73.3023501678 2014-04-13 15:25:00,78.0441963754 2014-04-13 15:30:00,87.90431031930002 2014-04-13 15:35:00,72.775491269 2014-04-13 15:40:00,83.1458723824 2014-04-13 15:45:00,85.4581988746 2014-04-13 15:50:00,82.3788236113 2014-04-13 15:55:00,81.1151929853 2014-04-13 16:00:00,83.3207106956 2014-04-13 16:05:00,78.86933236739999 2014-04-13 16:10:00,73.46164675029999 2014-04-13 16:15:00,87.39778026479998 2014-04-13 16:20:00,78.9166607995 2014-04-13 16:25:00,82.6460691139 2014-04-13 16:30:00,80.5008124284 2014-04-13 16:35:00,72.8746292321 2014-04-13 16:40:00,87.2437781075 2014-04-13 16:45:00,84.6804330311 2014-04-13 16:50:00,74.3854234912 2014-04-13 16:55:00,87.70621362440002 2014-04-13 17:00:00,83.7903897792 2014-04-13 17:05:00,79.5571158569 2014-04-13 17:10:00,81.7818895007 2014-04-13 17:15:00,73.7077586084 2014-04-13 17:20:00,80.9665530691 2014-04-13 17:25:00,73.1785490517 2014-04-13 17:30:00,80.71765311829998 2014-04-13 17:35:00,80.8430999764 2014-04-13 17:40:00,85.99098754200001 2014-04-13 17:45:00,83.6008879016 2014-04-13 17:50:00,75.9928090942 2014-04-13 17:55:00,86.2147851685 2014-04-13 18:00:00,32.468746820999996 2014-04-13 18:05:00,32.6808223882 2014-04-13 18:10:00,29.8814750258 2014-04-13 18:15:00,34.2897444306 2014-04-13 18:20:00,34.7581700625 2014-04-13 18:25:00,33.7599336749 2014-04-13 18:30:00,34.8208090113 2014-04-13 18:35:00,30.734713485300002 2014-04-13 18:40:00,34.3111560898 2014-04-13 18:45:00,31.928909984 2014-04-13 18:50:00,29.8490643678 2014-04-13 18:55:00,33.0803174824 2014-04-13 19:00:00,23.2248575387 2014-04-13 19:05:00,21.4454206452 2014-04-13 19:10:00,20.283169013 2014-04-13 19:15:00,21.055314565699998 2014-04-13 19:20:00,21.951002209400002 2014-04-13 19:25:00,20.9106806944 2014-04-13 19:30:00,21.0292530145 2014-04-13 19:35:00,21.913428974299997 2014-04-13 19:40:00,24.4688026898 2014-04-13 19:45:00,23.5838096553 2014-04-13 19:50:00,21.592471653 2014-04-13 19:55:00,24.423184889 2014-04-13 20:00:00,21.0765690082 2014-04-13 20:05:00,20.2975215009 2014-04-13 20:10:00,20.3501573707 2014-04-13 20:15:00,20.1144090989 2014-04-13 20:20:00,19.3863352146 2014-04-13 20:25:00,20.0156452191 2014-04-13 20:30:00,20.5942633419 2014-04-13 20:35:00,20.5947997815 2014-04-13 20:40:00,21.5520740928 2014-04-13 20:45:00,19.9016357841 2014-04-13 20:50:00,21.368004471600003 2014-04-13 20:55:00,20.799863922 2014-04-13 21:00:00,21.952248996199998 2014-04-13 21:05:00,19.634937126700002 2014-04-13 21:10:00,21.7085691601 2014-04-13 21:15:00,21.3847264738 2014-04-13 21:20:00,20.6493002421 2014-04-13 21:25:00,20.717024494100002 2014-04-13 21:30:00,18.4266249721 2014-04-13 21:35:00,21.9055426812 2014-04-13 21:40:00,18.5161973811 2014-04-13 21:45:00,20.3501472647 2014-04-13 21:50:00,19.413020513699998 2014-04-13 21:55:00,19.8140610227 2014-04-13 22:00:00,20.4603551361 2014-04-13 22:05:00,21.6561754902 2014-04-13 22:10:00,19.8493055423 2014-04-13 22:15:00,21.9719910919 2014-04-13 22:20:00,20.3908046497 2014-04-13 22:25:00,18.6601122885 2014-04-13 22:30:00,18.7780468058 2014-04-13 22:35:00,20.8844739985 2014-04-13 22:40:00,18.2190646956 2014-04-13 22:45:00,19.9404908067 2014-04-13 22:50:00,18.6107255915 2014-04-13 22:55:00,19.7518180906 2014-04-13 23:00:00,21.0037016228 2014-04-13 23:05:00,19.8390600793 2014-04-13 23:10:00,18.6573859645 2014-04-13 23:15:00,19.011350958199998 2014-04-13 23:20:00,19.4738966231 2014-04-13 23:25:00,18.2817541551 2014-04-13 23:30:00,20.341255313599998 2014-04-13 23:35:00,20.434057749100003 2014-04-13 23:40:00,18.2521114394 2014-04-13 23:45:00,19.6130102579 2014-04-13 23:50:00,19.6597766821 2014-04-13 23:55:00,19.3389906457 2014-04-14 00:00:00,20.2309589613 2014-04-14 00:05:00,19.3838299602 2014-04-14 00:10:00,19.6656371179 2014-04-14 00:15:00,21.1900941898 2014-04-14 00:20:00,18.648437421700002 2014-04-14 00:25:00,20.476458781199998 2014-04-14 00:30:00,20.0223776068 2014-04-14 00:35:00,19.2202865499 2014-04-14 00:40:00,20.910138626 2014-04-14 00:45:00,20.2047534382 2014-04-14 00:50:00,19.9094461078 2014-04-14 00:55:00,20.6706772591 2014-04-14 01:00:00,21.2091612319 2014-04-14 01:05:00,21.890675160100002 2014-04-14 01:10:00,20.517401473499998 2014-04-14 01:15:00,21.4977599416 2014-04-14 01:20:00,18.004366164100002 2014-04-14 01:25:00,20.120942770899997 2014-04-14 01:30:00,18.8585901951 2014-04-14 01:35:00,18.3767698283 2014-04-14 01:40:00,20.1278840683 2014-04-14 01:45:00,20.9873060246 2014-04-14 01:50:00,19.6490900899 2014-04-14 01:55:00,20.6804297974 2014-04-14 02:00:00,19.9588770154 2014-04-14 02:05:00,19.7483434638 2014-04-14 02:10:00,19.1610265617 2014-04-14 02:15:00,19.530374058 2014-04-14 02:20:00,19.3991825232 2014-04-14 02:25:00,20.5847487361 2014-04-14 02:30:00,18.4640740451 2014-04-14 02:35:00,18.3705454748 2014-04-14 02:40:00,20.640051976800002 2014-04-14 02:45:00,20.1851922795 2014-04-14 02:50:00,19.720800387 2014-04-14 02:55:00,18.6097715376 2014-04-14 03:00:00,19.6441084475 2014-04-14 03:05:00,21.158927053299998 2014-04-14 03:10:00,21.558484943200003 2014-04-14 03:15:00,20.8103062799 2014-04-14 03:20:00,18.2396487035 2014-04-14 03:25:00,20.681639106400002 2014-04-14 03:30:00,18.9639423582 2014-04-14 03:35:00,19.2610049721 2014-04-14 03:40:00,18.7834928318 2014-04-14 03:45:00,21.1030231625 2014-04-14 03:50:00,20.5944084905 2014-04-14 03:55:00,20.4473402184 2014-04-14 04:00:00,20.6718904387 2014-04-14 04:05:00,18.9470890456 2014-04-14 04:10:00,19.7785776573 2014-04-14 04:15:00,20.5330148862 2014-04-14 04:20:00,20.5463761105 2014-04-14 04:25:00,21.167407451 2014-04-14 04:30:00,19.1484158668 2014-04-14 04:35:00,21.0813444868 2014-04-14 04:40:00,19.7607379225 2014-04-14 04:45:00,20.680690768199998 2014-04-14 04:50:00,19.8228775203 2014-04-14 04:55:00,21.7944406792 2014-04-14 05:00:00,18.717209059 2014-04-14 05:05:00,20.7000203543 2014-04-14 05:10:00,20.306140003099998 2014-04-14 05:15:00,18.690924163800002 2014-04-14 05:20:00,18.2640253432 2014-04-14 05:25:00,21.1965775559 2014-04-14 05:30:00,18.6298053346 2014-04-14 05:35:00,18.7460267311 2014-04-14 05:40:00,21.913736896 2014-04-14 05:45:00,20.869043405899998 2014-04-14 05:50:00,19.0019473664 2014-04-14 05:55:00,20.363795840599998 2014-04-14 06:00:00,20.136447353599998 2014-04-14 06:05:00,21.3778930701 2014-04-14 06:10:00,20.917282991300002 2014-04-14 06:15:00,21.326884502000002 2014-04-14 06:20:00,18.8460263519 2014-04-14 06:25:00,20.5608768175 2014-04-14 06:30:00,18.160963433699997 2014-04-14 06:35:00,18.2757624491 2014-04-14 06:40:00,20.8541081308 2014-04-14 06:45:00,18.0976804106 2014-04-14 06:50:00,20.3190600356 2014-04-14 06:55:00,21.361620393800003 2014-04-14 07:00:00,19.519767233699998 2014-04-14 07:05:00,18.1793617474 2014-04-14 07:10:00,20.8553897985 2014-04-14 07:15:00,21.718745809899996 2014-04-14 07:20:00,20.8686855682 2014-04-14 07:25:00,20.313788972 2014-04-14 07:30:00,18.9201153195 2014-04-14 07:35:00,18.0615024962 2014-04-14 07:40:00,20.7786884339 2014-04-14 07:45:00,18.924104703399998 2014-04-14 07:50:00,21.4326507087 2014-04-14 07:55:00,19.8654564753 2014-04-14 08:00:00,20.1225423295 2014-04-14 08:05:00,21.0157461771 2014-04-14 08:10:00,21.117722431199997 2014-04-14 08:15:00,20.5706033323 2014-04-14 08:20:00,21.7537272617 2014-04-14 08:25:00,21.9291937453 2014-04-14 08:30:00,21.7875417775 2014-04-14 08:35:00,21.2967167414 2014-04-14 08:40:00,20.822500881 2014-04-14 08:45:00,20.6533034315 2014-04-14 08:50:00,18.4150007077 2014-04-14 08:55:00,19.0859373873 2014-04-14 09:00:00,61.27735984 2014-04-14 09:05:00,63.0687742352 2014-04-14 09:10:00,67.1735208895 2014-04-14 09:15:00,63.192897090699994 2014-04-14 09:20:00,73.4626224396 2014-04-14 09:25:00,72.15750892060001 2014-04-14 09:30:00,62.1739220044 2014-04-14 09:35:00,64.58522653039999 2014-04-14 09:40:00,72.3393776307 2014-04-14 09:45:00,72.1214273212 2014-04-14 09:50:00,74.0581274816 2014-04-14 09:55:00,74.766649558 2014-04-14 10:00:00,84.9917113815 2014-04-14 10:05:00,76.2053415384 2014-04-14 10:10:00,73.7250974478 2014-04-14 10:15:00,81.6105261554 2014-04-14 10:20:00,74.4847152954 2014-04-14 10:25:00,82.3553335892 2014-04-14 10:30:00,78.1269774158 2014-04-14 10:35:00,82.1617513116 2014-04-14 10:40:00,74.1216557332 2014-04-14 10:45:00,77.7245839374 2014-04-14 10:50:00,78.5936492767 2014-04-14 10:55:00,84.47703721100001 2014-04-14 11:00:00,75.8079678619 2014-04-14 11:05:00,86.4650897576 2014-04-14 11:10:00,84.3684761916 2014-04-14 11:15:00,83.1921390362 2014-04-14 11:20:00,84.0823847611 2014-04-14 11:25:00,81.1966799297 2014-04-14 11:30:00,75.4498484864 2014-04-14 11:35:00,74.58172798439999 2014-04-14 11:40:00,85.3462941958 2014-04-14 11:45:00,83.1006170589 2014-04-14 11:50:00,74.958800913 2014-04-14 11:55:00,81.35044489090001 2014-04-14 12:00:00,79.0657508102 2014-04-14 12:05:00,74.4490365401 2014-04-14 12:10:00,80.4131020932 2014-04-14 12:15:00,76.4125003129 2014-04-14 12:20:00,73.4516580993 2014-04-14 12:25:00,79.3759671774 2014-04-14 12:30:00,81.34400674930001 2014-04-14 12:35:00,72.663201963 2014-04-14 12:40:00,78.33936380979999 2014-04-14 12:45:00,76.0312436085 2014-04-14 12:50:00,72.40342096 2014-04-14 12:55:00,73.9217880728 2014-04-14 13:00:00,74.2067326499 2014-04-14 13:05:00,74.90800573279999 2014-04-14 13:10:00,84.8336761731 2014-04-14 13:15:00,79.0129022149 2014-04-14 13:20:00,74.3355310661 2014-04-14 13:25:00,73.5870863305 2014-04-14 13:30:00,76.74862324829998 2014-04-14 13:35:00,84.74790391970001 2014-04-14 13:40:00,77.8126780412 2014-04-14 13:45:00,74.5404637588 2014-04-14 13:50:00,78.4470270986 2014-04-14 13:55:00,80.8655725202 2014-04-14 14:00:00,72.46986821760001 2014-04-14 14:05:00,82.0383307941 2014-04-14 14:10:00,78.3178526109 2014-04-14 14:15:00,72.1521505326 2014-04-14 14:20:00,82.7782568361 2014-04-14 14:25:00,83.39419905529999 2014-04-14 14:30:00,82.057497668 2014-04-14 14:35:00,77.4671648792 2014-04-14 14:40:00,80.4698149285 2014-04-14 14:45:00,78.190769961 2014-04-14 14:50:00,83.2059536051 2014-04-14 14:55:00,81.3333787902 2014-04-14 15:00:00,73.30808205689999 2014-04-14 15:05:00,82.28870695229999 2014-04-14 15:10:00,82.9950178696 2014-04-14 15:15:00,77.93048675 2014-04-14 15:20:00,86.01174677469999 2014-04-14 15:25:00,85.4874089905 2014-04-14 15:30:00,74.80194627680001 2014-04-14 15:35:00,86.46743084049999 2014-04-14 15:40:00,79.0531990259 2014-04-14 15:45:00,83.5791920742 2014-04-14 15:50:00,85.0247358662 2014-04-14 15:55:00,80.0810299518 2014-04-14 16:00:00,78.3854805295 2014-04-14 16:05:00,86.64705553520002 2014-04-14 16:10:00,75.6935115151 2014-04-14 16:15:00,76.1113751094 2014-04-14 16:20:00,77.7857756752 2014-04-14 16:25:00,85.7512878047 2014-04-14 16:30:00,87.0204451478 2014-04-14 16:35:00,75.5209384356 2014-04-14 16:40:00,85.821757584 2014-04-14 16:45:00,76.13110117949999 2014-04-14 16:50:00,87.53009188989998 2014-04-14 16:55:00,81.5583696793 2014-04-14 17:00:00,72.1133557876 2014-04-14 17:05:00,72.54605060739999 2014-04-14 17:10:00,74.3597239387 2014-04-14 17:15:00,75.0011417247 2014-04-14 17:20:00,84.281873601 2014-04-14 17:25:00,75.564225006 2014-04-14 17:30:00,87.5062323184 2014-04-14 17:35:00,82.177761359 2014-04-14 17:40:00,83.08024824520001 2014-04-14 17:45:00,75.48503532229999 2014-04-14 17:50:00,86.28326789270002 2014-04-14 17:55:00,82.6850014141 2014-04-14 18:00:00,34.332189404 2014-04-14 18:05:00,34.921472317399996 2014-04-14 18:10:00,29.604096569499998 2014-04-14 18:15:00,29.4181526254 2014-04-14 18:20:00,33.9418035733 2014-04-14 18:25:00,34.343200184299995 2014-04-14 18:30:00,32.5360668467 2014-04-14 18:35:00,31.1423975263 2014-04-14 18:40:00,32.9768233393 2014-04-14 18:45:00,30.7562441594 2014-04-14 18:50:00,30.3256626073 2014-04-14 18:55:00,31.9241232115 2014-04-14 19:00:00,21.128367988599997 2014-04-14 19:05:00,22.326990940500004 2014-04-14 19:10:00,24.445595803499998 2014-04-14 19:15:00,23.9222311673 2014-04-14 19:20:00,24.378505181999998 2014-04-14 19:25:00,23.7723525032 2014-04-14 19:30:00,21.749282999899997 2014-04-14 19:35:00,23.797961363200002 2014-04-14 19:40:00,24.2946611984 2014-04-14 19:45:00,24.4027189908 2014-04-14 19:50:00,23.2207250972 2014-04-14 19:55:00,21.1069214064 2014-04-14 20:00:00,18.594730389000002 2014-04-14 20:05:00,19.0349319061 2014-04-14 20:10:00,22.3868799071 2014-04-14 20:15:00,20.324748348 2014-04-14 20:20:00,21.9340224535 2014-04-14 20:25:00,20.336820608900002 2014-04-14 20:30:00,21.1387085682 2014-04-14 20:35:00,18.5308804007 2014-04-14 20:40:00,19.4554465719 2014-04-14 20:45:00,20.2189587284 2014-04-14 20:50:00,21.015064517 2014-04-14 20:55:00,19.134550556700002 2014-04-14 21:00:00,21.1592851934 2014-04-14 21:05:00,19.5510153471 2014-04-14 21:10:00,21.3718357818 2014-04-14 21:15:00,18.4801573229 2014-04-14 21:20:00,20.8184776263 2014-04-14 21:25:00,19.2653451897 2014-04-14 21:30:00,21.2832040014 2014-04-14 21:35:00,19.702803332200002 2014-04-14 21:40:00,20.7605731912 2014-04-14 21:45:00,21.8415596823 2014-04-14 21:50:00,18.169302515 2014-04-14 21:55:00,18.1310805272 2014-04-14 22:00:00,21.1013548707 2014-04-14 22:05:00,20.6053343452 2014-04-14 22:10:00,19.1903239147 2014-04-14 22:15:00,19.996765284600002 2014-04-14 22:20:00,18.185183686400002 2014-04-14 22:25:00,18.787801403299998 2014-04-14 22:30:00,19.7168955545 2014-04-14 22:35:00,21.356660385 2014-04-14 22:40:00,19.9377906436 2014-04-14 22:45:00,20.3649816401 2014-04-14 22:50:00,21.515650372 2014-04-14 22:55:00,19.2537415095 2014-04-14 23:00:00,20.8067914194 2014-04-14 23:05:00,21.4507867931 2014-04-14 23:10:00,18.8140744098 2014-04-14 23:15:00,19.4296424339 2014-04-14 23:20:00,21.923449187600003 2014-04-14 23:25:00,21.9370853689 2014-04-14 23:30:00,18.8965471599 2014-04-14 23:35:00,18.2692903842 2014-04-14 23:40:00,19.0873505112 2014-04-14 23:45:00,19.5946892854 2014-04-14 23:50:00,19.7678170941 2014-04-14 23:55:00,20.4791564706 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/art_daily_jumpsup.csv ================================================ timestamp,value 2014-04-01 00:00:00,19.761251902999998 2014-04-01 00:05:00,20.500833287 2014-04-01 00:10:00,19.9616414445 2014-04-01 00:15:00,21.4902660734 2014-04-01 00:20:00,20.1877394098 2014-04-01 00:25:00,19.9231256718 2014-04-01 00:30:00,21.698403961700002 2014-04-01 00:35:00,20.8787583842 2014-04-01 00:40:00,18.4461996294 2014-04-01 00:45:00,18.7108178448 2014-04-01 00:50:00,21.148491451800002 2014-04-01 00:55:00,21.3434052847 2014-04-01 01:00:00,20.1807633164 2014-04-01 01:05:00,20.217820911500002 2014-04-01 01:10:00,20.527731851400002 2014-04-01 01:15:00,19.7564630971 2014-04-01 01:20:00,20.7207964939 2014-04-01 01:25:00,18.4339250303 2014-04-01 01:30:00,21.845116969499998 2014-04-01 01:35:00,21.0006192952 2014-04-01 01:40:00,20.524696816 2014-04-01 01:45:00,19.265288228 2014-04-01 01:50:00,18.6438219498 2014-04-01 01:55:00,19.6373718553 2014-04-01 02:00:00,20.6463069623 2014-04-01 02:05:00,20.534838973699998 2014-04-01 02:10:00,19.530564620299998 2014-04-01 02:15:00,20.4531455753 2014-04-01 02:20:00,21.2549931823 2014-04-01 02:25:00,18.1051390894 2014-04-01 02:30:00,19.8024841917 2014-04-01 02:35:00,21.0342209139 2014-04-01 02:40:00,20.1845778819 2014-04-01 02:45:00,20.6059043517 2014-04-01 02:50:00,20.0667055704 2014-04-01 02:55:00,21.967498178699998 2014-04-01 03:00:00,18.218486146 2014-04-01 03:05:00,19.964179287100002 2014-04-01 03:10:00,18.3656661965 2014-04-01 03:15:00,18.6391422485 2014-04-01 03:20:00,19.5321534017 2014-04-01 03:25:00,18.622160366 2014-04-01 03:30:00,21.854748663800002 2014-04-01 03:35:00,21.7871591069 2014-04-01 03:40:00,19.3444385849 2014-04-01 03:45:00,20.5589908482 2014-04-01 03:50:00,20.1350132824 2014-04-01 03:55:00,21.262347922100002 2014-04-01 04:00:00,20.5097824393 2014-04-01 04:05:00,18.001009818 2014-04-01 04:10:00,21.0526975424 2014-04-01 04:15:00,20.9873924852 2014-04-01 04:20:00,20.0388908223 2014-04-01 04:25:00,21.6116758929 2014-04-01 04:30:00,21.633784822800003 2014-04-01 04:35:00,20.0956467068 2014-04-01 04:40:00,20.4319529248 2014-04-01 04:45:00,21.9860882877 2014-04-01 04:50:00,19.1952809392 2014-04-01 04:55:00,19.2984689692 2014-04-01 05:00:00,18.7310956107 2014-04-01 05:05:00,21.583467756599998 2014-04-01 05:10:00,20.9779535598 2014-04-01 05:15:00,18.4225713955 2014-04-01 05:20:00,21.9270694048 2014-04-01 05:25:00,20.9238468326 2014-04-01 05:30:00,21.4020884384 2014-04-01 05:35:00,18.192603156700002 2014-04-01 05:40:00,20.0198436758 2014-04-01 05:45:00,20.7943931469 2014-04-01 05:50:00,20.1717863383 2014-04-01 05:55:00,20.6665898628 2014-04-01 06:00:00,21.2714962544 2014-04-01 06:05:00,19.497348251800002 2014-04-01 06:10:00,21.3946747025 2014-04-01 06:15:00,18.6516644191 2014-04-01 06:20:00,19.0835442201 2014-04-01 06:25:00,18.1733824797 2014-04-01 06:30:00,19.4577072453 2014-04-01 06:35:00,19.5196381793 2014-04-01 06:40:00,21.221082388800003 2014-04-01 06:45:00,20.612522681199998 2014-04-01 06:50:00,19.7468902326 2014-04-01 06:55:00,20.608455914500002 2014-04-01 07:00:00,18.2111334021 2014-04-01 07:05:00,18.7210861441 2014-04-01 07:10:00,20.507791421 2014-04-01 07:15:00,20.5654672769 2014-04-01 07:20:00,21.0965386348 2014-04-01 07:25:00,19.6119990362 2014-04-01 07:30:00,20.8902163865 2014-04-01 07:35:00,20.7359213302 2014-04-01 07:40:00,21.8535735135 2014-04-01 07:45:00,18.8605209057 2014-04-01 07:50:00,20.206718255 2014-04-01 07:55:00,20.407057768399998 2014-04-01 08:00:00,21.994591539699996 2014-04-01 08:05:00,18.804736568699997 2014-04-01 08:10:00,20.0928720799 2014-04-01 08:15:00,19.384741230899998 2014-04-01 08:20:00,20.103571874300002 2014-04-01 08:25:00,18.928514408399998 2014-04-01 08:30:00,18.1904495137 2014-04-01 08:35:00,20.2902618156 2014-04-01 08:40:00,19.3434172634 2014-04-01 08:45:00,18.727765607000002 2014-04-01 08:50:00,19.2957422643 2014-04-01 08:55:00,18.1971208058 2014-04-01 09:00:00,74.1260143836 2014-04-01 09:05:00,69.10361164359999 2014-04-01 09:10:00,72.2808540663 2014-04-01 09:15:00,66.9544074866 2014-04-01 09:20:00,73.4850794789 2014-04-01 09:25:00,67.7731278131 2014-04-01 09:30:00,69.0056563819 2014-04-01 09:35:00,67.88839812890001 2014-04-01 09:40:00,71.1725848238 2014-04-01 09:45:00,68.9065226554 2014-04-01 09:50:00,64.8937453607 2014-04-01 09:55:00,63.179337626000006 2014-04-01 10:00:00,79.2470505155 2014-04-01 10:05:00,77.4320730032 2014-04-01 10:10:00,71.3295428127 2014-04-01 10:15:00,75.9799830691 2014-04-01 10:20:00,77.8293300694 2014-04-01 10:25:00,82.67338298899999 2014-04-01 10:30:00,71.0210883865 2014-04-01 10:35:00,75.2486478048 2014-04-01 10:40:00,82.6076230245 2014-04-01 10:45:00,79.90353942109999 2014-04-01 10:50:00,74.3401531544 2014-04-01 10:55:00,82.9596010938 2014-04-01 11:00:00,79.41334110529999 2014-04-01 11:05:00,79.4937884794 2014-04-01 11:10:00,87.0996450426 2014-04-01 11:15:00,86.6309408675 2014-04-01 11:20:00,77.2701037963 2014-04-01 11:25:00,73.8037704623 2014-04-01 11:30:00,76.7474037102 2014-04-01 11:35:00,72.052805772 2014-04-01 11:40:00,71.8982924702 2014-04-01 11:45:00,77.8583840549 2014-04-01 11:50:00,86.5339792602 2014-04-01 11:55:00,85.426067155 2014-04-01 12:00:00,80.08686564029999 2014-04-01 12:05:00,80.9463697522 2014-04-01 12:10:00,72.0084220248 2014-04-01 12:15:00,75.3574808711 2014-04-01 12:20:00,72.3095103677 2014-04-01 12:25:00,83.9717453641 2014-04-01 12:30:00,74.2411363371 2014-04-01 12:35:00,85.8016679353 2014-04-01 12:40:00,82.194437192 2014-04-01 12:45:00,75.5798939857 2014-04-01 12:50:00,74.4340968432 2014-04-01 12:55:00,81.94354482050001 2014-04-01 13:00:00,86.3926524705 2014-04-01 13:05:00,83.47372499939999 2014-04-01 13:10:00,77.5581280065 2014-04-01 13:15:00,81.3786019713 2014-04-01 13:20:00,76.953713801 2014-04-01 13:25:00,87.9652763341 2014-04-01 13:30:00,83.9612714729 2014-04-01 13:35:00,81.81046701060001 2014-04-01 13:40:00,78.7532409691 2014-04-01 13:45:00,81.8707829394 2014-04-01 13:50:00,77.4472651938 2014-04-01 13:55:00,72.4444465903 2014-04-01 14:00:00,78.31765692970001 2014-04-01 14:05:00,86.883522504 2014-04-01 14:10:00,82.0168805171 2014-04-01 14:15:00,73.3397707712 2014-04-01 14:20:00,86.15576213920002 2014-04-01 14:25:00,76.2983350936 2014-04-01 14:30:00,75.89666867439999 2014-04-01 14:35:00,76.7497713346 2014-04-01 14:40:00,81.2313364867 2014-04-01 14:45:00,80.7111351745 2014-04-01 14:50:00,79.8587866682 2014-04-01 14:55:00,83.4765827479 2014-04-01 15:00:00,77.06386388119998 2014-04-01 15:05:00,84.51222102 2014-04-01 15:10:00,74.8044287246 2014-04-01 15:15:00,84.5211212147 2014-04-01 15:20:00,82.6201685228 2014-04-01 15:25:00,82.930536812 2014-04-01 15:30:00,79.7040891874 2014-04-01 15:35:00,82.6712308715 2014-04-01 15:40:00,73.2760492881 2014-04-01 15:45:00,85.6239958745 2014-04-01 15:50:00,72.8880560037 2014-04-01 15:55:00,74.3791501112 2014-04-01 16:00:00,81.228479377 2014-04-01 16:05:00,83.83042233260001 2014-04-01 16:10:00,73.2198844471 2014-04-01 16:15:00,86.73207050010002 2014-04-01 16:20:00,87.5775542316 2014-04-01 16:25:00,81.69504591329998 2014-04-01 16:30:00,79.6997422622 2014-04-01 16:35:00,83.8621585408 2014-04-01 16:40:00,77.2535693101 2014-04-01 16:45:00,79.8920775526 2014-04-01 16:50:00,86.6582500449 2014-04-01 16:55:00,87.29031920610001 2014-04-01 17:00:00,86.8330725129 2014-04-01 17:05:00,76.19913981090001 2014-04-01 17:10:00,75.7194755672 2014-04-01 17:15:00,76.762602618 2014-04-01 17:20:00,79.0609474388 2014-04-01 17:25:00,77.02664902640001 2014-04-01 17:30:00,77.98737478470001 2014-04-01 17:35:00,81.93015977270001 2014-04-01 17:40:00,84.20037850050001 2014-04-01 17:45:00,83.768899005 2014-04-01 17:50:00,85.0307444214 2014-04-01 17:55:00,72.5149226057 2014-04-01 18:00:00,29.105490665700003 2014-04-01 18:05:00,33.8520444488 2014-04-01 18:10:00,32.211698278200004 2014-04-01 18:15:00,32.5000940721 2014-04-01 18:20:00,29.1365503112 2014-04-01 18:25:00,30.4340024842 2014-04-01 18:30:00,32.8854612373 2014-04-01 18:35:00,34.2987575113 2014-04-01 18:40:00,34.6686870856 2014-04-01 18:45:00,32.0026786288 2014-04-01 18:50:00,32.2910288896 2014-04-01 18:55:00,34.131511085599996 2014-04-01 19:00:00,22.568556973299998 2014-04-01 19:05:00,22.4755249615 2014-04-01 19:10:00,24.2147751608 2014-04-01 19:15:00,23.698897290300003 2014-04-01 19:20:00,24.232643588800002 2014-04-01 19:25:00,21.1377456459 2014-04-01 19:30:00,22.5092009454 2014-04-01 19:35:00,23.9342738231 2014-04-01 19:40:00,20.6579411338 2014-04-01 19:45:00,23.72008515 2014-04-01 19:50:00,20.9797196068 2014-04-01 19:55:00,23.7803707178 2014-04-01 20:00:00,20.938755589 2014-04-01 20:05:00,19.2234943904 2014-04-01 20:10:00,20.3708584741 2014-04-01 20:15:00,21.2250833071 2014-04-01 20:20:00,21.0282612297 2014-04-01 20:25:00,20.1820042736 2014-04-01 20:30:00,22.1158050371 2014-04-01 20:35:00,20.558902699 2014-04-01 20:40:00,20.5040322087 2014-04-01 20:45:00,18.6869781922 2014-04-01 20:50:00,22.2090048501 2014-04-01 20:55:00,19.1574692354 2014-04-01 21:00:00,20.2099229424 2014-04-01 21:05:00,21.3160988514 2014-04-01 21:10:00,18.9523497644 2014-04-01 21:15:00,20.2060186776 2014-04-01 21:20:00,19.0537607405 2014-04-01 21:25:00,21.1397660835 2014-04-01 21:30:00,20.3545999721 2014-04-01 21:35:00,21.526738125399998 2014-04-01 21:40:00,21.6818074721 2014-04-01 21:45:00,20.693789562 2014-04-01 21:50:00,21.0018924452 2014-04-01 21:55:00,20.2938253758 2014-04-01 22:00:00,19.556471129000002 2014-04-01 22:05:00,20.6122404548 2014-04-01 22:10:00,21.6539223116 2014-04-01 22:15:00,19.6856015647 2014-04-01 22:20:00,19.2761274305 2014-04-01 22:25:00,19.5725193424 2014-04-01 22:30:00,19.760542437999998 2014-04-01 22:35:00,18.3118065813 2014-04-01 22:40:00,20.0129613686 2014-04-01 22:45:00,19.9964351491 2014-04-01 22:50:00,20.3733149249 2014-04-01 22:55:00,19.4699533412 2014-04-01 23:00:00,20.4563572484 2014-04-01 23:05:00,21.516995709099998 2014-04-01 23:10:00,21.8260737616 2014-04-01 23:15:00,20.338353076700002 2014-04-01 23:20:00,18.173852523900003 2014-04-01 23:25:00,21.8811443602 2014-04-01 23:30:00,20.8274463436 2014-04-01 23:35:00,19.3475686124 2014-04-01 23:40:00,18.5921998191 2014-04-01 23:45:00,18.5772405926 2014-04-01 23:50:00,18.6745624504 2014-04-01 23:55:00,18.185781084400002 2014-04-02 00:00:00,21.6086167546 2014-04-02 00:05:00,20.1630729313 2014-04-02 00:10:00,20.7998376509 2014-04-02 00:15:00,21.3124340371 2014-04-02 00:20:00,21.1661640253 2014-04-02 00:25:00,21.530422494899998 2014-04-02 00:30:00,21.869018490100004 2014-04-02 00:35:00,19.756282459 2014-04-02 00:40:00,21.8013418667 2014-04-02 00:45:00,20.8931597934 2014-04-02 00:50:00,18.2826727612 2014-04-02 00:55:00,20.7271324848 2014-04-02 01:00:00,20.7468666384 2014-04-02 01:05:00,21.6234422552 2014-04-02 01:10:00,19.4917285299 2014-04-02 01:15:00,20.3396460011 2014-04-02 01:20:00,18.048750204 2014-04-02 01:25:00,19.3283009687 2014-04-02 01:30:00,18.2489749046 2014-04-02 01:35:00,20.087491891099997 2014-04-02 01:40:00,21.269790602 2014-04-02 01:45:00,18.8257707685 2014-04-02 01:50:00,20.1097641822 2014-04-02 01:55:00,18.816034545999997 2014-04-02 02:00:00,18.4827538714 2014-04-02 02:05:00,20.0439871677 2014-04-02 02:10:00,18.3165944838 2014-04-02 02:15:00,20.3494185246 2014-04-02 02:20:00,18.1253498427 2014-04-02 02:25:00,18.4268598875 2014-04-02 02:30:00,20.1999899419 2014-04-02 02:35:00,20.365629651600003 2014-04-02 02:40:00,18.1159477204 2014-04-02 02:45:00,20.293507152 2014-04-02 02:50:00,21.354010101300002 2014-04-02 02:55:00,20.8892647092 2014-04-02 03:00:00,18.5247404157 2014-04-02 03:05:00,20.3698985903 2014-04-02 03:10:00,20.6890100003 2014-04-02 03:15:00,18.148924807 2014-04-02 03:20:00,21.4213906747 2014-04-02 03:25:00,21.625069589200002 2014-04-02 03:30:00,21.4018090934 2014-04-02 03:35:00,21.298525872 2014-04-02 03:40:00,20.9798607938 2014-04-02 03:45:00,20.5337281251 2014-04-02 03:50:00,20.71450802 2014-04-02 03:55:00,21.2255811733 2014-04-02 04:00:00,20.6499938334 2014-04-02 04:05:00,19.3109078267 2014-04-02 04:10:00,19.5038444086 2014-04-02 04:15:00,21.588229873499998 2014-04-02 04:20:00,18.0684883432 2014-04-02 04:25:00,20.795282325 2014-04-02 04:30:00,21.819110209699996 2014-04-02 04:35:00,20.8249126798 2014-04-02 04:40:00,21.9756479529 2014-04-02 04:45:00,20.7501796221 2014-04-02 04:50:00,18.1374521169 2014-04-02 04:55:00,21.308039526600002 2014-04-02 05:00:00,19.1385196478 2014-04-02 05:05:00,19.7842289027 2014-04-02 05:10:00,19.2483676636 2014-04-02 05:15:00,19.0742164248 2014-04-02 05:20:00,19.7256228147 2014-04-02 05:25:00,19.5150057938 2014-04-02 05:30:00,20.5333543274 2014-04-02 05:35:00,21.252604804 2014-04-02 05:40:00,19.1883546127 2014-04-02 05:45:00,18.8548846113 2014-04-02 05:50:00,20.6675810835 2014-04-02 05:55:00,20.6812802633 2014-04-02 06:00:00,21.6045249571 2014-04-02 06:05:00,18.063782745799998 2014-04-02 06:10:00,21.4121626485 2014-04-02 06:15:00,20.0840086918 2014-04-02 06:20:00,20.4852083567 2014-04-02 06:25:00,18.3654857622 2014-04-02 06:30:00,19.7304597315 2014-04-02 06:35:00,18.909209629 2014-04-02 06:40:00,19.0169001203 2014-04-02 06:45:00,20.0163804587 2014-04-02 06:50:00,21.2498238016 2014-04-02 06:55:00,20.9751237206 2014-04-02 07:00:00,20.3639998363 2014-04-02 07:05:00,20.157672770999998 2014-04-02 07:10:00,19.7092241729 2014-04-02 07:15:00,21.8908398942 2014-04-02 07:20:00,20.2407702169 2014-04-02 07:25:00,19.0158655932 2014-04-02 07:30:00,18.920363168199998 2014-04-02 07:35:00,20.4454121231 2014-04-02 07:40:00,20.091310109200002 2014-04-02 07:45:00,18.0307912118 2014-04-02 07:50:00,21.3202614888 2014-04-02 07:55:00,20.8164894169 2014-04-02 08:00:00,20.647317158699998 2014-04-02 08:05:00,18.2751226308 2014-04-02 08:10:00,19.448223400699998 2014-04-02 08:15:00,21.741529042899998 2014-04-02 08:20:00,21.4503569654 2014-04-02 08:25:00,19.1421717515 2014-04-02 08:30:00,18.628235536400002 2014-04-02 08:35:00,19.796351828699997 2014-04-02 08:40:00,19.4233215147 2014-04-02 08:45:00,20.7289055068 2014-04-02 08:50:00,21.8657392403 2014-04-02 08:55:00,19.4520057999 2014-04-02 09:00:00,62.046248748100005 2014-04-02 09:05:00,73.4075505135 2014-04-02 09:10:00,61.7161163313 2014-04-02 09:15:00,74.1576162013 2014-04-02 09:20:00,70.2382802209 2014-04-02 09:25:00,74.0069732348 2014-04-02 09:30:00,63.91537173840001 2014-04-02 09:35:00,61.753517215500004 2014-04-02 09:40:00,67.8396557046 2014-04-02 09:45:00,67.3284784382 2014-04-02 09:50:00,65.7082949163 2014-04-02 09:55:00,74.2241280517 2014-04-02 10:00:00,82.6064995231 2014-04-02 10:05:00,80.1077529717 2014-04-02 10:10:00,72.3675606862 2014-04-02 10:15:00,81.2366992956 2014-04-02 10:20:00,81.1232332969 2014-04-02 10:25:00,76.4370580545 2014-04-02 10:30:00,84.1926773188 2014-04-02 10:35:00,72.4314967322 2014-04-02 10:40:00,73.9890789686 2014-04-02 10:45:00,70.8212417452 2014-04-02 10:50:00,82.1853988709 2014-04-02 10:55:00,79.4897056722 2014-04-02 11:00:00,76.5768106216 2014-04-02 11:05:00,74.1732925058 2014-04-02 11:10:00,72.2065101345 2014-04-02 11:15:00,74.2199215234 2014-04-02 11:20:00,78.77703901539998 2014-04-02 11:25:00,75.4991025151 2014-04-02 11:30:00,75.6868525499 2014-04-02 11:35:00,85.4931665355 2014-04-02 11:40:00,79.7607495587 2014-04-02 11:45:00,83.16602338060001 2014-04-02 11:50:00,72.1359469333 2014-04-02 11:55:00,77.3755580087 2014-04-02 12:00:00,79.5711095069 2014-04-02 12:05:00,74.89269047970001 2014-04-02 12:10:00,73.83435698550001 2014-04-02 12:15:00,85.82175062350001 2014-04-02 12:20:00,86.92646894639999 2014-04-02 12:25:00,73.1729940801 2014-04-02 12:30:00,77.4911982414 2014-04-02 12:35:00,87.22777096629999 2014-04-02 12:40:00,73.24259102479999 2014-04-02 12:45:00,82.1995040517 2014-04-02 12:50:00,87.4504752851 2014-04-02 12:55:00,87.5463968029 2014-04-02 13:00:00,79.5204837969 2014-04-02 13:05:00,74.5860807679 2014-04-02 13:10:00,75.2152930359 2014-04-02 13:15:00,86.2129262526 2014-04-02 13:20:00,86.56614720649998 2014-04-02 13:25:00,81.7064600441 2014-04-02 13:30:00,84.2386002741 2014-04-02 13:35:00,83.8187786875 2014-04-02 13:40:00,82.5693241729 2014-04-02 13:45:00,85.21597453439999 2014-04-02 13:50:00,82.9465940072 2014-04-02 13:55:00,80.5247063231 2014-04-02 14:00:00,75.7876638189 2014-04-02 14:05:00,83.8981829998 2014-04-02 14:10:00,79.5711862851 2014-04-02 14:15:00,76.7129845441 2014-04-02 14:20:00,84.8270685171 2014-04-02 14:25:00,83.1434265296 2014-04-02 14:30:00,86.9932571332 2014-04-02 14:35:00,74.6434831811 2014-04-02 14:40:00,82.3830739768 2014-04-02 14:45:00,75.90418791350001 2014-04-02 14:50:00,86.4531778131 2014-04-02 14:55:00,73.5884582126 2014-04-02 15:00:00,82.4977969167 2014-04-02 15:05:00,84.6565588337 2014-04-02 15:10:00,77.6779397305 2014-04-02 15:15:00,87.2653715145 2014-04-02 15:20:00,85.61086908109999 2014-04-02 15:25:00,76.7131563416 2014-04-02 15:30:00,72.11996512510001 2014-04-02 15:35:00,76.74577805130002 2014-04-02 15:40:00,76.5002331182 2014-04-02 15:45:00,86.2386058215 2014-04-02 15:50:00,87.4730991023 2014-04-02 15:55:00,73.1263377559 2014-04-02 16:00:00,79.5405645384 2014-04-02 16:05:00,80.7731568917 2014-04-02 16:10:00,73.486445487 2014-04-02 16:15:00,78.0398135095 2014-04-02 16:20:00,77.0731706975 2014-04-02 16:25:00,80.5767469616 2014-04-02 16:30:00,82.5788958439 2014-04-02 16:35:00,83.25560191689999 2014-04-02 16:40:00,74.1879379367 2014-04-02 16:45:00,85.0070000174 2014-04-02 16:50:00,82.85651339180001 2014-04-02 16:55:00,86.2250331156 2014-04-02 17:00:00,79.1893465422 2014-04-02 17:05:00,86.3022030635 2014-04-02 17:10:00,85.8523529904 2014-04-02 17:15:00,79.0145189762 2014-04-02 17:20:00,78.0982630549 2014-04-02 17:25:00,86.92495886030001 2014-04-02 17:30:00,83.44260371060001 2014-04-02 17:35:00,86.8518921919 2014-04-02 17:40:00,84.75156391770001 2014-04-02 17:45:00,81.7487276371 2014-04-02 17:50:00,73.8536160723 2014-04-02 17:55:00,76.6636613224 2014-04-02 18:00:00,35.000584685300005 2014-04-02 18:05:00,30.844295509699997 2014-04-02 18:10:00,29.396825522399997 2014-04-02 18:15:00,33.3283350788 2014-04-02 18:20:00,33.4976207975 2014-04-02 18:25:00,30.626923529499997 2014-04-02 18:30:00,30.7050947724 2014-04-02 18:35:00,31.80090900150001 2014-04-02 18:40:00,28.939443722100002 2014-04-02 18:45:00,33.851660766799995 2014-04-02 18:50:00,30.8293623193 2014-04-02 18:55:00,34.264077274099996 2014-04-02 19:00:00,23.7557829856 2014-04-02 19:05:00,23.123079839899997 2014-04-02 19:10:00,21.6154382188 2014-04-02 19:15:00,22.473096963400003 2014-04-02 19:20:00,22.1528338588 2014-04-02 19:25:00,21.678189661199998 2014-04-02 19:30:00,23.9596492617 2014-04-02 19:35:00,22.3261104694 2014-04-02 19:40:00,23.890598167600004 2014-04-02 19:45:00,20.6313776324 2014-04-02 19:50:00,20.7917899124 2014-04-02 19:55:00,24.5383936208 2014-04-02 20:00:00,20.8394993728 2014-04-02 20:05:00,20.5200163364 2014-04-02 20:10:00,20.5748469877 2014-04-02 20:15:00,19.3137406667 2014-04-02 20:20:00,21.3758111207 2014-04-02 20:25:00,18.7792612094 2014-04-02 20:30:00,20.7803336795 2014-04-02 20:35:00,20.7698687416 2014-04-02 20:40:00,22.176515519099997 2014-04-02 20:45:00,20.5872445431 2014-04-02 20:50:00,18.9934085748 2014-04-02 20:55:00,20.7779971005 2014-04-02 21:00:00,18.4534640231 2014-04-02 21:05:00,18.905488136600002 2014-04-02 21:10:00,18.211431577 2014-04-02 21:15:00,20.1494295173 2014-04-02 21:20:00,18.4261534423 2014-04-02 21:25:00,19.972989837300002 2014-04-02 21:30:00,21.836092632600003 2014-04-02 21:35:00,20.9792650199 2014-04-02 21:40:00,18.397532956 2014-04-02 21:45:00,18.9875440308 2014-04-02 21:50:00,20.7939839472 2014-04-02 21:55:00,21.6823856668 2014-04-02 22:00:00,18.1490807455 2014-04-02 22:05:00,21.270204328800002 2014-04-02 22:10:00,20.266692876700002 2014-04-02 22:15:00,20.203742282 2014-04-02 22:20:00,21.8522107229 2014-04-02 22:25:00,21.0107293954 2014-04-02 22:30:00,21.4210199182 2014-04-02 22:35:00,19.4346216116 2014-04-02 22:40:00,20.2368649113 2014-04-02 22:45:00,20.4812658575 2014-04-02 22:50:00,19.3048506343 2014-04-02 22:55:00,20.3004622426 2014-04-02 23:00:00,18.9502592674 2014-04-02 23:05:00,18.577068795 2014-04-02 23:10:00,19.4996242444 2014-04-02 23:15:00,20.9611822874 2014-04-02 23:20:00,21.6689082219 2014-04-02 23:25:00,19.8346637284 2014-04-02 23:30:00,20.5752444397 2014-04-02 23:35:00,18.4156836546 2014-04-02 23:40:00,21.6220056603 2014-04-02 23:45:00,20.2783095403 2014-04-02 23:50:00,21.1254082882 2014-04-02 23:55:00,21.1818309324 2014-04-03 00:00:00,19.0259221055 2014-04-03 00:05:00,20.1166978127 2014-04-03 00:10:00,21.841919006199998 2014-04-03 00:15:00,18.3585381793 2014-04-03 00:20:00,20.7321995921 2014-04-03 00:25:00,21.8490563121 2014-04-03 00:30:00,19.2023084322 2014-04-03 00:35:00,21.4457916856 2014-04-03 00:40:00,21.7346301816 2014-04-03 00:45:00,20.9883448376 2014-04-03 00:50:00,18.925313249200002 2014-04-03 00:55:00,19.3360028753 2014-04-03 01:00:00,18.1432371777 2014-04-03 01:05:00,21.325812937000002 2014-04-03 01:10:00,21.398444746 2014-04-03 01:15:00,20.5308412399 2014-04-03 01:20:00,19.4101114051 2014-04-03 01:25:00,18.3072441106 2014-04-03 01:30:00,21.0122304397 2014-04-03 01:35:00,20.9061047744 2014-04-03 01:40:00,21.650410086999997 2014-04-03 01:45:00,20.922128084 2014-04-03 01:50:00,21.314779769 2014-04-03 01:55:00,20.9838184716 2014-04-03 02:00:00,20.5227487532 2014-04-03 02:05:00,19.7078655768 2014-04-03 02:10:00,21.6084692346 2014-04-03 02:15:00,20.6038742876 2014-04-03 02:20:00,19.5934212879 2014-04-03 02:25:00,18.3338771807 2014-04-03 02:30:00,19.1628194236 2014-04-03 02:35:00,20.1749069393 2014-04-03 02:40:00,19.1025414801 2014-04-03 02:45:00,18.8849413917 2014-04-03 02:50:00,20.1095740564 2014-04-03 02:55:00,18.6792813836 2014-04-03 03:00:00,21.2016402533 2014-04-03 03:05:00,19.9374726054 2014-04-03 03:10:00,20.2954510959 2014-04-03 03:15:00,18.589533070399998 2014-04-03 03:20:00,19.2983053425 2014-04-03 03:25:00,19.640358733 2014-04-03 03:30:00,21.2328513221 2014-04-03 03:35:00,21.0806380923 2014-04-03 03:40:00,18.8919098992 2014-04-03 03:45:00,20.4647163264 2014-04-03 03:50:00,18.9738254311 2014-04-03 03:55:00,21.952988622800003 2014-04-03 04:00:00,21.8084955125 2014-04-03 04:05:00,20.2530588821 2014-04-03 04:10:00,20.7956102876 2014-04-03 04:15:00,21.2057215288 2014-04-03 04:20:00,20.8839936802 2014-04-03 04:25:00,20.7993147643 2014-04-03 04:30:00,21.834216031799997 2014-04-03 04:35:00,20.3858244252 2014-04-03 04:40:00,20.5452106873 2014-04-03 04:45:00,21.3970750018 2014-04-03 04:50:00,20.6795634714 2014-04-03 04:55:00,20.931730488099998 2014-04-03 05:00:00,18.9366747448 2014-04-03 05:05:00,19.4850676965 2014-04-03 05:10:00,18.5892053828 2014-04-03 05:15:00,20.0230617693 2014-04-03 05:20:00,19.8229096027 2014-04-03 05:25:00,21.9886512571 2014-04-03 05:30:00,20.444834611300003 2014-04-03 05:35:00,21.1457792928 2014-04-03 05:40:00,19.336058683 2014-04-03 05:45:00,21.3261813254 2014-04-03 05:50:00,20.460339865999998 2014-04-03 05:55:00,20.787969326400003 2014-04-03 06:00:00,19.177723111800002 2014-04-03 06:05:00,20.1945535668 2014-04-03 06:10:00,20.536147893699997 2014-04-03 06:15:00,20.3563787033 2014-04-03 06:20:00,21.6607748457 2014-04-03 06:25:00,21.593090658 2014-04-03 06:30:00,21.8839362315 2014-04-03 06:35:00,20.669712024000003 2014-04-03 06:40:00,21.887656520500002 2014-04-03 06:45:00,21.3299120001 2014-04-03 06:50:00,19.083328561400002 2014-04-03 06:55:00,19.709742678199998 2014-04-03 07:00:00,18.9535697688 2014-04-03 07:05:00,18.0167886433 2014-04-03 07:10:00,18.7521950126 2014-04-03 07:15:00,18.0162423451 2014-04-03 07:20:00,20.8793538454 2014-04-03 07:25:00,19.7021371909 2014-04-03 07:30:00,19.2502989083 2014-04-03 07:35:00,21.0468835644 2014-04-03 07:40:00,21.3299470985 2014-04-03 07:45:00,21.9011981546 2014-04-03 07:50:00,20.568054338699998 2014-04-03 07:55:00,19.8461158342 2014-04-03 08:00:00,19.2210572064 2014-04-03 08:05:00,18.889272836900002 2014-04-03 08:10:00,18.8517038019 2014-04-03 08:15:00,19.6367574989 2014-04-03 08:20:00,21.967145421199998 2014-04-03 08:25:00,18.0034147897 2014-04-03 08:30:00,18.7888235889 2014-04-03 08:35:00,18.7535719296 2014-04-03 08:40:00,20.8684779421 2014-04-03 08:45:00,19.4099389104 2014-04-03 08:50:00,19.8290432184 2014-04-03 08:55:00,18.594496521900002 2014-04-03 09:00:00,66.7079597287 2014-04-03 09:05:00,62.603517441899996 2014-04-03 09:10:00,68.4493887153 2014-04-03 09:15:00,62.5319617692 2014-04-03 09:20:00,71.950913984 2014-04-03 09:25:00,68.90578335859999 2014-04-03 09:30:00,71.0459630833 2014-04-03 09:35:00,66.8918228585 2014-04-03 09:40:00,66.3882815881 2014-04-03 09:45:00,62.535640891099995 2014-04-03 09:50:00,68.3244362558 2014-04-03 09:55:00,68.1972294421 2014-04-03 10:00:00,77.1049437299 2014-04-03 10:05:00,81.33284501989999 2014-04-03 10:10:00,82.76046828850001 2014-04-03 10:15:00,81.4922557552 2014-04-03 10:20:00,72.0727963284 2014-04-03 10:25:00,79.4943635841 2014-04-03 10:30:00,71.0866146003 2014-04-03 10:35:00,80.6205379011 2014-04-03 10:40:00,75.7661427786 2014-04-03 10:45:00,71.8963838013 2014-04-03 10:50:00,83.2190293003 2014-04-03 10:55:00,79.3694094219 2014-04-03 11:00:00,77.2095458902 2014-04-03 11:05:00,72.0566850652 2014-04-03 11:10:00,80.1133823592 2014-04-03 11:15:00,86.2509843714 2014-04-03 11:20:00,81.0528248593 2014-04-03 11:25:00,87.0211312159 2014-04-03 11:30:00,73.738118585 2014-04-03 11:35:00,80.60632438350001 2014-04-03 11:40:00,84.2613807635 2014-04-03 11:45:00,79.9261997878 2014-04-03 11:50:00,73.01631932560001 2014-04-03 11:55:00,80.8382189686 2014-04-03 12:00:00,81.6896611257 2014-04-03 12:05:00,83.55895675800001 2014-04-03 12:10:00,84.0783689816 2014-04-03 12:15:00,84.2311641758 2014-04-03 12:20:00,82.5159721659 2014-04-03 12:25:00,75.3624354079 2014-04-03 12:30:00,78.3736107669 2014-04-03 12:35:00,84.3167778664 2014-04-03 12:40:00,87.15012593629999 2014-04-03 12:45:00,73.17523565569999 2014-04-03 12:50:00,80.4719045405 2014-04-03 12:55:00,76.90795591359999 2014-04-03 13:00:00,75.5881567965 2014-04-03 13:05:00,80.0737486233 2014-04-03 13:10:00,81.6778220658 2014-04-03 13:15:00,72.1390381773 2014-04-03 13:20:00,84.463029162 2014-04-03 13:25:00,85.0976857528 2014-04-03 13:30:00,87.4271856315 2014-04-03 13:35:00,74.8723260597 2014-04-03 13:40:00,81.4932779159 2014-04-03 13:45:00,78.8070877342 2014-04-03 13:50:00,77.3386798859 2014-04-03 13:55:00,81.0306831905 2014-04-03 14:00:00,84.5140726214 2014-04-03 14:05:00,72.3653708306 2014-04-03 14:10:00,87.5062013018 2014-04-03 14:15:00,84.9540273822 2014-04-03 14:20:00,84.0144263723 2014-04-03 14:25:00,84.1621581374 2014-04-03 14:30:00,78.2212165553 2014-04-03 14:35:00,84.0218955689 2014-04-03 14:40:00,78.1845702981 2014-04-03 14:45:00,86.37516306639999 2014-04-03 14:50:00,74.83196602609999 2014-04-03 14:55:00,76.6738782646 2014-04-03 15:00:00,80.8206247977 2014-04-03 15:05:00,77.1066363434 2014-04-03 15:10:00,78.7870395619 2014-04-03 15:15:00,79.8779961943 2014-04-03 15:20:00,85.7008308451 2014-04-03 15:25:00,80.3703044954 2014-04-03 15:30:00,77.798610704 2014-04-03 15:35:00,75.96304937229999 2014-04-03 15:40:00,78.538061688 2014-04-03 15:45:00,80.2510072536 2014-04-03 15:50:00,83.937031912 2014-04-03 15:55:00,73.9360706257 2014-04-03 16:00:00,75.545601964 2014-04-03 16:05:00,78.0743143509 2014-04-03 16:10:00,77.76622517050001 2014-04-03 16:15:00,78.2678191272 2014-04-03 16:20:00,84.6961776173 2014-04-03 16:25:00,77.18632224939999 2014-04-03 16:30:00,80.0302172281 2014-04-03 16:35:00,81.98235511930001 2014-04-03 16:40:00,75.7147114304 2014-04-03 16:45:00,83.498965876 2014-04-03 16:50:00,80.7536260686 2014-04-03 16:55:00,79.1483466434 2014-04-03 17:00:00,84.9565118045 2014-04-03 17:05:00,75.8958950029 2014-04-03 17:10:00,86.1307824556 2014-04-03 17:15:00,80.97674867079998 2014-04-03 17:20:00,81.74676667930001 2014-04-03 17:25:00,86.0009104023 2014-04-03 17:30:00,85.0812903344 2014-04-03 17:35:00,81.6249617572 2014-04-03 17:40:00,84.05097098600001 2014-04-03 17:45:00,78.9330815334 2014-04-03 17:50:00,80.7580130449 2014-04-03 17:55:00,72.993094158 2014-04-03 18:00:00,29.3750850352 2014-04-03 18:05:00,34.108316038000005 2014-04-03 18:10:00,29.1818929934 2014-04-03 18:15:00,29.8841486663 2014-04-03 18:20:00,33.8933225098 2014-04-03 18:25:00,28.807328553 2014-04-03 18:30:00,30.607381828 2014-04-03 18:35:00,32.5378411628 2014-04-03 18:40:00,32.6108733001 2014-04-03 18:45:00,33.7737721281 2014-04-03 18:50:00,32.0379218775 2014-04-03 18:55:00,32.0601658094 2014-04-03 19:00:00,23.409390094299997 2014-04-03 19:05:00,22.393836367 2014-04-03 19:10:00,22.8860388123 2014-04-03 19:15:00,24.1820264992 2014-04-03 19:20:00,21.9584993095 2014-04-03 19:25:00,21.885359117100002 2014-04-03 19:30:00,20.1758983768 2014-04-03 19:35:00,22.908148394899996 2014-04-03 19:40:00,20.2933770319 2014-04-03 19:45:00,22.4185840042 2014-04-03 19:50:00,23.76296607130001 2014-04-03 19:55:00,22.623645154899997 2014-04-03 20:00:00,19.5364294983 2014-04-03 20:05:00,21.6521455944 2014-04-03 20:10:00,19.5367606143 2014-04-03 20:15:00,21.4344979175 2014-04-03 20:20:00,20.9316183813 2014-04-03 20:25:00,19.128304601900002 2014-04-03 20:30:00,22.1394280857 2014-04-03 20:35:00,19.2538362943 2014-04-03 20:40:00,22.4853483859 2014-04-03 20:45:00,18.46194354 2014-04-03 20:50:00,19.511227678599997 2014-04-03 20:55:00,19.2506275466 2014-04-03 21:00:00,18.1426422698 2014-04-03 21:05:00,21.0299330128 2014-04-03 21:10:00,20.8734169327 2014-04-03 21:15:00,21.2710169439 2014-04-03 21:20:00,19.118122751199998 2014-04-03 21:25:00,19.8722718549 2014-04-03 21:30:00,20.735509015399998 2014-04-03 21:35:00,19.8539175223 2014-04-03 21:40:00,20.889091685 2014-04-03 21:45:00,20.634465872699998 2014-04-03 21:50:00,18.5471924045 2014-04-03 21:55:00,21.2255684603 2014-04-03 22:00:00,20.9027528233 2014-04-03 22:05:00,20.6431359444 2014-04-03 22:10:00,18.6382499754 2014-04-03 22:15:00,19.0902948922 2014-04-03 22:20:00,19.5914979165 2014-04-03 22:25:00,19.138073407 2014-04-03 22:30:00,18.9293959449 2014-04-03 22:35:00,21.241803243699998 2014-04-03 22:40:00,20.5726597872 2014-04-03 22:45:00,20.2813399292 2014-04-03 22:50:00,18.9219584925 2014-04-03 22:55:00,21.6931116524 2014-04-03 23:00:00,18.7683349831 2014-04-03 23:05:00,21.1838702515 2014-04-03 23:10:00,21.8708890693 2014-04-03 23:15:00,20.9123853221 2014-04-03 23:20:00,21.975653614099997 2014-04-03 23:25:00,20.6081604731 2014-04-03 23:30:00,18.8734643821 2014-04-03 23:35:00,18.818890506400002 2014-04-03 23:40:00,19.3019624005 2014-04-03 23:45:00,18.031981555 2014-04-03 23:50:00,20.7307734227 2014-04-03 23:55:00,19.0783334735 2014-04-04 00:00:00,21.2607329292 2014-04-04 00:05:00,19.4366906022 2014-04-04 00:10:00,19.9198259739 2014-04-04 00:15:00,21.862755666199998 2014-04-04 00:20:00,18.968688492200002 2014-04-04 00:25:00,20.8850163897 2014-04-04 00:30:00,21.0204711572 2014-04-04 00:35:00,18.8839926301 2014-04-04 00:40:00,20.003987346400002 2014-04-04 00:45:00,19.4008077013 2014-04-04 00:50:00,21.0876249736 2014-04-04 00:55:00,20.4899332761 2014-04-04 01:00:00,19.9039322194 2014-04-04 01:05:00,21.1174530602 2014-04-04 01:10:00,18.94062228 2014-04-04 01:15:00,21.0144875223 2014-04-04 01:20:00,21.4614972484 2014-04-04 01:25:00,21.514486387199998 2014-04-04 01:30:00,21.1346943721 2014-04-04 01:35:00,19.632056668 2014-04-04 01:40:00,21.927232090900002 2014-04-04 01:45:00,19.5183745753 2014-04-04 01:50:00,20.5545015964 2014-04-04 01:55:00,18.6442967123 2014-04-04 02:00:00,21.921795594499997 2014-04-04 02:05:00,20.8159436875 2014-04-04 02:10:00,21.013510180999997 2014-04-04 02:15:00,18.2631068136 2014-04-04 02:20:00,21.0536712569 2014-04-04 02:25:00,21.0988937169 2014-04-04 02:30:00,20.687090905399998 2014-04-04 02:35:00,19.1676384552 2014-04-04 02:40:00,19.958760168599998 2014-04-04 02:45:00,18.4417374852 2014-04-04 02:50:00,19.8863482658 2014-04-04 02:55:00,18.9752954104 2014-04-04 03:00:00,19.396387945999997 2014-04-04 03:05:00,18.650401633599998 2014-04-04 03:10:00,18.920217470999997 2014-04-04 03:15:00,18.3062745673 2014-04-04 03:20:00,21.679605465700003 2014-04-04 03:25:00,20.1216427519 2014-04-04 03:30:00,19.586967885099998 2014-04-04 03:35:00,20.1401168511 2014-04-04 03:40:00,20.5131729139 2014-04-04 03:45:00,21.6875151735 2014-04-04 03:50:00,18.7147718091 2014-04-04 03:55:00,19.1822099945 2014-04-04 04:00:00,21.9031573454 2014-04-04 04:05:00,19.484771946600002 2014-04-04 04:10:00,18.090246603 2014-04-04 04:15:00,18.5905739705 2014-04-04 04:20:00,18.105354807 2014-04-04 04:25:00,21.9596925697 2014-04-04 04:30:00,19.115483396 2014-04-04 04:35:00,21.6941710277 2014-04-04 04:40:00,21.983545103 2014-04-04 04:45:00,20.3993648846 2014-04-04 04:50:00,18.1327852603 2014-04-04 04:55:00,18.326366521500002 2014-04-04 05:00:00,19.9263562204 2014-04-04 05:05:00,19.6246880516 2014-04-04 05:10:00,20.4247092231 2014-04-04 05:15:00,19.7553912388 2014-04-04 05:20:00,21.7363073971 2014-04-04 05:25:00,20.1389588617 2014-04-04 05:30:00,20.7749042458 2014-04-04 05:35:00,21.5859410906 2014-04-04 05:40:00,18.5874875033 2014-04-04 05:45:00,18.9189386165 2014-04-04 05:50:00,18.4292746419 2014-04-04 05:55:00,18.5585535969 2014-04-04 06:00:00,20.0503358677 2014-04-04 06:05:00,19.284717035899998 2014-04-04 06:10:00,19.6926913581 2014-04-04 06:15:00,21.9299593272 2014-04-04 06:20:00,18.6268173912 2014-04-04 06:25:00,20.163248283199998 2014-04-04 06:30:00,18.3954846202 2014-04-04 06:35:00,19.2739852531 2014-04-04 06:40:00,20.1101036947 2014-04-04 06:45:00,21.7865269839 2014-04-04 06:50:00,19.5649128851 2014-04-04 06:55:00,18.2596267849 2014-04-04 07:00:00,19.5526457918 2014-04-04 07:05:00,18.5829647035 2014-04-04 07:10:00,18.9199584532 2014-04-04 07:15:00,20.4723624927 2014-04-04 07:20:00,18.2696954648 2014-04-04 07:25:00,19.858895025 2014-04-04 07:30:00,20.437846344 2014-04-04 07:35:00,19.6874335695 2014-04-04 07:40:00,18.0765054025 2014-04-04 07:45:00,21.9420774276 2014-04-04 07:50:00,19.468463069400002 2014-04-04 07:55:00,21.1143087477 2014-04-04 08:00:00,19.302585968699997 2014-04-04 08:05:00,19.900067028 2014-04-04 08:10:00,19.5538545704 2014-04-04 08:15:00,19.370156918 2014-04-04 08:20:00,18.0874055088 2014-04-04 08:25:00,19.4400837514 2014-04-04 08:30:00,21.557959961599998 2014-04-04 08:35:00,20.7615733544 2014-04-04 08:40:00,18.5816914364 2014-04-04 08:45:00,20.3646200185 2014-04-04 08:50:00,21.5689234398 2014-04-04 08:55:00,20.8001361639 2014-04-04 09:00:00,63.2221077361 2014-04-04 09:05:00,73.0025219556 2014-04-04 09:10:00,65.3009985807 2014-04-04 09:15:00,67.3754355626 2014-04-04 09:20:00,68.3555415318 2014-04-04 09:25:00,72.7668898195 2014-04-04 09:30:00,73.869861934 2014-04-04 09:35:00,73.843279138 2014-04-04 09:40:00,61.3081768654 2014-04-04 09:45:00,73.737683404 2014-04-04 09:50:00,61.9396627376 2014-04-04 09:55:00,64.8145217327 2014-04-04 10:00:00,77.8326115054 2014-04-04 10:05:00,77.2884466933 2014-04-04 10:10:00,79.2250960011 2014-04-04 10:15:00,77.28100547 2014-04-04 10:20:00,84.341510548 2014-04-04 10:25:00,73.5733181243 2014-04-04 10:30:00,74.09286325149999 2014-04-04 10:35:00,84.129852762 2014-04-04 10:40:00,71.0309972533 2014-04-04 10:45:00,79.300383956 2014-04-04 10:50:00,80.4205419761 2014-04-04 10:55:00,77.6860075476 2014-04-04 11:00:00,82.6090638008 2014-04-04 11:05:00,74.3154898902 2014-04-04 11:10:00,85.12826303 2014-04-04 11:15:00,73.7949685653 2014-04-04 11:20:00,77.9425211144 2014-04-04 11:25:00,72.7648968912 2014-04-04 11:30:00,80.2390369975 2014-04-04 11:35:00,82.2196373213 2014-04-04 11:40:00,86.53718888459998 2014-04-04 11:45:00,83.32640285949999 2014-04-04 11:50:00,80.17370078329998 2014-04-04 11:55:00,86.4003410411 2014-04-04 12:00:00,79.5594034214 2014-04-04 12:05:00,80.882115301 2014-04-04 12:10:00,81.439731351 2014-04-04 12:15:00,78.4654040034 2014-04-04 12:20:00,85.3132241814 2014-04-04 12:25:00,74.87285964350001 2014-04-04 12:30:00,80.7804220759 2014-04-04 12:35:00,83.4554652205 2014-04-04 12:40:00,86.3598624075 2014-04-04 12:45:00,86.03932310969999 2014-04-04 12:50:00,80.0436768173 2014-04-04 12:55:00,82.19183451880002 2014-04-04 13:00:00,78.2890099052 2014-04-04 13:05:00,79.4717664035 2014-04-04 13:10:00,86.4794926205 2014-04-04 13:15:00,86.8704099877 2014-04-04 13:20:00,86.3059065391 2014-04-04 13:25:00,74.1961224449 2014-04-04 13:30:00,85.5808000186 2014-04-04 13:35:00,87.15289797959998 2014-04-04 13:40:00,77.7613279144 2014-04-04 13:45:00,80.279069029 2014-04-04 13:50:00,84.4452523672 2014-04-04 13:55:00,80.973811821 2014-04-04 14:00:00,87.89151735200001 2014-04-04 14:05:00,79.2876078546 2014-04-04 14:10:00,83.4190790713 2014-04-04 14:15:00,84.6773935331 2014-04-04 14:20:00,79.90177118300001 2014-04-04 14:25:00,85.70762672779999 2014-04-04 14:30:00,80.7345980126 2014-04-04 14:35:00,78.58264060100001 2014-04-04 14:40:00,73.721639973 2014-04-04 14:45:00,78.29085908 2014-04-04 14:50:00,83.7389636125 2014-04-04 14:55:00,86.7364190389 2014-04-04 15:00:00,76.0261406038 2014-04-04 15:05:00,77.6830225131 2014-04-04 15:10:00,74.4626610573 2014-04-04 15:15:00,83.0507690126 2014-04-04 15:20:00,87.3621761952 2014-04-04 15:25:00,82.25444586729999 2014-04-04 15:30:00,81.8724384971 2014-04-04 15:35:00,80.855062672 2014-04-04 15:40:00,73.4145870642 2014-04-04 15:45:00,83.67125797109999 2014-04-04 15:50:00,81.63200902199999 2014-04-04 15:55:00,82.58283549890001 2014-04-04 16:00:00,86.38081163700001 2014-04-04 16:05:00,84.5432102697 2014-04-04 16:10:00,84.49448180479999 2014-04-04 16:15:00,86.834773579 2014-04-04 16:20:00,87.8387905726 2014-04-04 16:25:00,81.3003676144 2014-04-04 16:30:00,73.7419642717 2014-04-04 16:35:00,79.3459261799 2014-04-04 16:40:00,84.6014559083 2014-04-04 16:45:00,72.4434661045 2014-04-04 16:50:00,72.9100590261 2014-04-04 16:55:00,73.074384215 2014-04-04 17:00:00,83.6965399938 2014-04-04 17:05:00,80.01863532979999 2014-04-04 17:10:00,77.90233718180001 2014-04-04 17:15:00,73.6898444273 2014-04-04 17:20:00,83.71581185640001 2014-04-04 17:25:00,77.1362873485 2014-04-04 17:30:00,76.2451558429 2014-04-04 17:35:00,82.437075569 2014-04-04 17:40:00,80.944143199 2014-04-04 17:45:00,77.79854039439999 2014-04-04 17:50:00,82.2637679436 2014-04-04 17:55:00,76.3395150118 2014-04-04 18:00:00,33.886907168 2014-04-04 18:05:00,30.2676354706 2014-04-04 18:10:00,29.8165555257 2014-04-04 18:15:00,33.8076057297 2014-04-04 18:20:00,33.330502597 2014-04-04 18:25:00,29.9688836905 2014-04-04 18:30:00,29.5439671448 2014-04-04 18:35:00,34.1657476065 2014-04-04 18:40:00,33.7702238022 2014-04-04 18:45:00,30.8944412599 2014-04-04 18:50:00,33.0124570742 2014-04-04 18:55:00,29.5946195117 2014-04-04 19:00:00,22.431572281999998 2014-04-04 19:05:00,20.2439105979 2014-04-04 19:10:00,21.9143752244 2014-04-04 19:15:00,20.4952947159 2014-04-04 19:20:00,22.2886581444 2014-04-04 19:25:00,22.0491325683 2014-04-04 19:30:00,22.1508437042 2014-04-04 19:35:00,20.3630831161 2014-04-04 19:40:00,21.7800400142 2014-04-04 19:45:00,23.5490463521 2014-04-04 19:50:00,21.812735196 2014-04-04 19:55:00,23.363969066 2014-04-04 20:00:00,19.9453846127 2014-04-04 20:05:00,20.1655885104 2014-04-04 20:10:00,20.7417018452 2014-04-04 20:15:00,22.3259929452 2014-04-04 20:20:00,18.8778921629 2014-04-04 20:25:00,18.5668145736 2014-04-04 20:30:00,20.9221923738 2014-04-04 20:35:00,22.3195014084 2014-04-04 20:40:00,22.4859056811 2014-04-04 20:45:00,20.415136512300002 2014-04-04 20:50:00,20.3492620758 2014-04-04 20:55:00,21.0737713521 2014-04-04 21:00:00,20.319607166500003 2014-04-04 21:05:00,20.6349266707 2014-04-04 21:10:00,21.5991784383 2014-04-04 21:15:00,21.0859537048 2014-04-04 21:20:00,20.0834495635 2014-04-04 21:25:00,19.9427255848 2014-04-04 21:30:00,20.657087297100002 2014-04-04 21:35:00,19.9179746496 2014-04-04 21:40:00,19.9263067199 2014-04-04 21:45:00,18.1519366361 2014-04-04 21:50:00,18.7859985351 2014-04-04 21:55:00,20.0498339728 2014-04-04 22:00:00,21.311052815 2014-04-04 22:05:00,19.1332583292 2014-04-04 22:10:00,20.1098606734 2014-04-04 22:15:00,19.3984529839 2014-04-04 22:20:00,18.4368983964 2014-04-04 22:25:00,21.8541537877 2014-04-04 22:30:00,21.4392574181 2014-04-04 22:35:00,18.3315510998 2014-04-04 22:40:00,20.8991930227 2014-04-04 22:45:00,19.4089343147 2014-04-04 22:50:00,22.0004994407 2014-04-04 22:55:00,19.2280352802 2014-04-04 23:00:00,18.9585931307 2014-04-04 23:05:00,20.2754543312 2014-04-04 23:10:00,21.3446020282 2014-04-04 23:15:00,18.7736793399 2014-04-04 23:20:00,20.8416118982 2014-04-04 23:25:00,18.249129490999998 2014-04-04 23:30:00,21.6799007122 2014-04-04 23:35:00,18.3278179283 2014-04-04 23:40:00,21.6610836329 2014-04-04 23:45:00,19.9670619358 2014-04-04 23:50:00,19.7961645832 2014-04-04 23:55:00,21.897431815700003 2014-04-05 00:00:00,21.9615367108 2014-04-05 00:05:00,20.6007125038 2014-04-05 00:10:00,18.5084771674 2014-04-05 00:15:00,20.0246803426 2014-04-05 00:20:00,20.1166524038 2014-04-05 00:25:00,20.0577857125 2014-04-05 00:30:00,20.2779673541 2014-04-05 00:35:00,18.0748988552 2014-04-05 00:40:00,20.8449091259 2014-04-05 00:45:00,20.8495772078 2014-04-05 00:50:00,18.4618791007 2014-04-05 00:55:00,20.2809577698 2014-04-05 01:00:00,20.2734447297 2014-04-05 01:05:00,20.729801680799998 2014-04-05 01:10:00,18.341590768499998 2014-04-05 01:15:00,20.506013229100002 2014-04-05 01:20:00,19.123007803 2014-04-05 01:25:00,20.028011962 2014-04-05 01:30:00,21.0932942108 2014-04-05 01:35:00,20.8225837455 2014-04-05 01:40:00,18.4756120707 2014-04-05 01:45:00,20.3647391485 2014-04-05 01:50:00,21.8764661238 2014-04-05 01:55:00,18.6270777493 2014-04-05 02:00:00,21.4116283509 2014-04-05 02:05:00,20.8101923222 2014-04-05 02:10:00,21.096013251600002 2014-04-05 02:15:00,19.1278333086 2014-04-05 02:20:00,19.1515557175 2014-04-05 02:25:00,21.6240778231 2014-04-05 02:30:00,19.4393281284 2014-04-05 02:35:00,18.252061562799998 2014-04-05 02:40:00,20.4023868143 2014-04-05 02:45:00,18.4992706762 2014-04-05 02:50:00,21.1863849656 2014-04-05 02:55:00,20.56698577 2014-04-05 03:00:00,21.4989060209 2014-04-05 03:05:00,21.1393489991 2014-04-05 03:10:00,18.448454593399997 2014-04-05 03:15:00,19.5242827057 2014-04-05 03:20:00,21.0982409997 2014-04-05 03:25:00,19.6693658931 2014-04-05 03:30:00,21.8894619391 2014-04-05 03:35:00,20.9429617996 2014-04-05 03:40:00,18.061999666800002 2014-04-05 03:45:00,21.5199427662 2014-04-05 03:50:00,18.4032191395 2014-04-05 03:55:00,18.5620948967 2014-04-05 04:00:00,20.9379696024 2014-04-05 04:05:00,21.4598742377 2014-04-05 04:10:00,20.1453985116 2014-04-05 04:15:00,19.156198931800002 2014-04-05 04:20:00,19.405262180999998 2014-04-05 04:25:00,19.3715573184 2014-04-05 04:30:00,19.3067124152 2014-04-05 04:35:00,18.9716386873 2014-04-05 04:40:00,20.435468378499998 2014-04-05 04:45:00,21.601621274299998 2014-04-05 04:50:00,19.2283296523 2014-04-05 04:55:00,18.7467771898 2014-04-05 05:00:00,21.354310665499998 2014-04-05 05:05:00,20.9671333236 2014-04-05 05:10:00,21.723348126199998 2014-04-05 05:15:00,18.6620789424 2014-04-05 05:20:00,18.5770052565 2014-04-05 05:25:00,20.1657175772 2014-04-05 05:30:00,20.457734619300002 2014-04-05 05:35:00,19.9206937674 2014-04-05 05:40:00,20.3958665453 2014-04-05 05:45:00,18.721519075499998 2014-04-05 05:50:00,19.9184550167 2014-04-05 05:55:00,20.6323702438 2014-04-05 06:00:00,19.730825797 2014-04-05 06:05:00,20.717789343299998 2014-04-05 06:10:00,19.8047651222 2014-04-05 06:15:00,19.3343983234 2014-04-05 06:20:00,19.2144201883 2014-04-05 06:25:00,19.643608236 2014-04-05 06:30:00,18.0923584907 2014-04-05 06:35:00,20.674100553800002 2014-04-05 06:40:00,21.3804225639 2014-04-05 06:45:00,19.4185083778 2014-04-05 06:50:00,18.1841325446 2014-04-05 06:55:00,21.9471023895 2014-04-05 07:00:00,19.054793021800002 2014-04-05 07:05:00,18.5064844868 2014-04-05 07:10:00,19.4790100319 2014-04-05 07:15:00,20.9542281625 2014-04-05 07:20:00,19.1756663876 2014-04-05 07:25:00,20.2988128157 2014-04-05 07:30:00,19.6622399777 2014-04-05 07:35:00,18.4710559691 2014-04-05 07:40:00,19.32114805 2014-04-05 07:45:00,20.8994820229 2014-04-05 07:50:00,20.448015589300002 2014-04-05 07:55:00,18.4791135195 2014-04-05 08:00:00,18.653289638900002 2014-04-05 08:05:00,20.5629334372 2014-04-05 08:10:00,21.2536616573 2014-04-05 08:15:00,19.3978979838 2014-04-05 08:20:00,20.3812430074 2014-04-05 08:25:00,18.682574355 2014-04-05 08:30:00,19.245505347599998 2014-04-05 08:35:00,18.0810808227 2014-04-05 08:40:00,21.073103791199998 2014-04-05 08:45:00,19.6040392791 2014-04-05 08:50:00,21.2645022946 2014-04-05 08:55:00,20.8334919841 2014-04-05 09:00:00,72.47092201390001 2014-04-05 09:05:00,65.0849579063 2014-04-05 09:10:00,63.7174787338 2014-04-05 09:15:00,74.4179172841 2014-04-05 09:20:00,70.9556579038 2014-04-05 09:25:00,72.5429748438 2014-04-05 09:30:00,61.3786138825 2014-04-05 09:35:00,66.020678036 2014-04-05 09:40:00,71.3023069919 2014-04-05 09:45:00,62.2605665287 2014-04-05 09:50:00,68.9158230421 2014-04-05 09:55:00,67.0353896374 2014-04-05 10:00:00,70.1134081908 2014-04-05 10:05:00,73.5023409569 2014-04-05 10:10:00,74.2599716703 2014-04-05 10:15:00,71.5760663673 2014-04-05 10:20:00,79.6414528392 2014-04-05 10:25:00,73.6020150394 2014-04-05 10:30:00,74.1486546341 2014-04-05 10:35:00,83.7806630441 2014-04-05 10:40:00,77.0897503986 2014-04-05 10:45:00,75.925828841 2014-04-05 10:50:00,81.0744785146 2014-04-05 10:55:00,83.9572061276 2014-04-05 11:00:00,71.9661778915 2014-04-05 11:05:00,78.69679061560001 2014-04-05 11:10:00,81.2818666871 2014-04-05 11:15:00,76.6344275126 2014-04-05 11:20:00,83.8523724126 2014-04-05 11:25:00,87.0183713256 2014-04-05 11:30:00,86.5722688328 2014-04-05 11:35:00,75.7981863063 2014-04-05 11:40:00,75.1676839803 2014-04-05 11:45:00,86.7959294054 2014-04-05 11:50:00,78.8620274641 2014-04-05 11:55:00,74.8807669879 2014-04-05 12:00:00,83.2119770764 2014-04-05 12:05:00,76.4588643122 2014-04-05 12:10:00,76.1844204592 2014-04-05 12:15:00,85.9647031076 2014-04-05 12:20:00,74.5101468543 2014-04-05 12:25:00,72.9426507989 2014-04-05 12:30:00,76.2154146631 2014-04-05 12:35:00,81.6130732535 2014-04-05 12:40:00,73.8806423677 2014-04-05 12:45:00,79.4500601387 2014-04-05 12:50:00,81.9389488943 2014-04-05 12:55:00,85.4770961312 2014-04-05 13:00:00,75.65975076 2014-04-05 13:05:00,85.0571225642 2014-04-05 13:10:00,75.74031813810001 2014-04-05 13:15:00,82.80838587630002 2014-04-05 13:20:00,78.8718433572 2014-04-05 13:25:00,73.8171795021 2014-04-05 13:30:00,83.40819263350001 2014-04-05 13:35:00,75.4660856883 2014-04-05 13:40:00,74.8080165824 2014-04-05 13:45:00,77.7145108974 2014-04-05 13:50:00,82.4328552816 2014-04-05 13:55:00,75.7257651142 2014-04-05 14:00:00,74.9349875684 2014-04-05 14:05:00,72.155794367 2014-04-05 14:10:00,79.5424713317 2014-04-05 14:15:00,78.8545439092 2014-04-05 14:20:00,75.73824828779999 2014-04-05 14:25:00,72.8549374193 2014-04-05 14:30:00,78.864308325 2014-04-05 14:35:00,84.6072204356 2014-04-05 14:40:00,83.4405087646 2014-04-05 14:45:00,85.76860114729999 2014-04-05 14:50:00,72.1498596439 2014-04-05 14:55:00,87.4585108588 2014-04-05 15:00:00,77.4618524011 2014-04-05 15:05:00,87.8455214124 2014-04-05 15:10:00,76.0411813673 2014-04-05 15:15:00,79.5438185733 2014-04-05 15:20:00,77.6620972619 2014-04-05 15:25:00,77.6914255951 2014-04-05 15:30:00,85.4756930054 2014-04-05 15:35:00,83.9418971858 2014-04-05 15:40:00,87.8735793692 2014-04-05 15:45:00,81.8154494876 2014-04-05 15:50:00,79.4113433141 2014-04-05 15:55:00,73.44047677180001 2014-04-05 16:00:00,87.94481385790002 2014-04-05 16:05:00,80.8243352639 2014-04-05 16:10:00,83.2074797564 2014-04-05 16:15:00,78.5077274599 2014-04-05 16:20:00,80.763296265 2014-04-05 16:25:00,87.08107651430002 2014-04-05 16:30:00,74.6625676545 2014-04-05 16:35:00,76.6778141276 2014-04-05 16:40:00,74.4328127332 2014-04-05 16:45:00,84.67529188399999 2014-04-05 16:50:00,72.9925840207 2014-04-05 16:55:00,73.3059656499 2014-04-05 17:00:00,76.7758763227 2014-04-05 17:05:00,80.2269800876 2014-04-05 17:10:00,78.5003666648 2014-04-05 17:15:00,72.7170330474 2014-04-05 17:20:00,87.3198313951 2014-04-05 17:25:00,87.2458788233 2014-04-05 17:30:00,76.4696718075 2014-04-05 17:35:00,83.7043777018 2014-04-05 17:40:00,81.2571753794 2014-04-05 17:45:00,75.79959801300001 2014-04-05 17:50:00,76.1947155691 2014-04-05 17:55:00,79.8584201233 2014-04-05 18:00:00,31.4831103808 2014-04-05 18:05:00,30.6638618132 2014-04-05 18:10:00,33.9680676945 2014-04-05 18:15:00,31.8813565517 2014-04-05 18:20:00,32.991021265 2014-04-05 18:25:00,30.0113446389 2014-04-05 18:30:00,32.2144428549 2014-04-05 18:35:00,30.83504079610001 2014-04-05 18:40:00,32.1690409301 2014-04-05 18:45:00,33.7972788448 2014-04-05 18:50:00,33.7210380701 2014-04-05 18:55:00,31.067006374600002 2014-04-05 19:00:00,23.270360208000003 2014-04-05 19:05:00,24.3769776405 2014-04-05 19:10:00,22.9629973384 2014-04-05 19:15:00,20.8248762104 2014-04-05 19:20:00,23.205093386199998 2014-04-05 19:25:00,20.629970519100002 2014-04-05 19:30:00,24.0670533111 2014-04-05 19:35:00,22.4746377883 2014-04-05 19:40:00,21.8854292981 2014-04-05 19:45:00,20.4153884241 2014-04-05 19:50:00,21.865909931500006 2014-04-05 19:55:00,24.2063645444 2014-04-05 20:00:00,18.5179461306 2014-04-05 20:05:00,20.3761586098 2014-04-05 20:10:00,22.246023274200002 2014-04-05 20:15:00,20.0492684944 2014-04-05 20:20:00,20.1858073736 2014-04-05 20:25:00,20.8017817365 2014-04-05 20:30:00,20.3281910744 2014-04-05 20:35:00,19.1225922978 2014-04-05 20:40:00,18.508003265899998 2014-04-05 20:45:00,20.9297882999 2014-04-05 20:50:00,22.2036235139 2014-04-05 20:55:00,18.8676672625 2014-04-05 21:00:00,18.9342611229 2014-04-05 21:05:00,19.574426301600003 2014-04-05 21:10:00,21.3368967147 2014-04-05 21:15:00,19.1686110171 2014-04-05 21:20:00,21.6315530088 2014-04-05 21:25:00,18.307286645 2014-04-05 21:30:00,21.868292798699997 2014-04-05 21:35:00,20.3401546056 2014-04-05 21:40:00,20.734159194700002 2014-04-05 21:45:00,19.5642176811 2014-04-05 21:50:00,21.2293913804 2014-04-05 21:55:00,18.755863026500002 2014-04-05 22:00:00,18.2131151136 2014-04-05 22:05:00,19.6008665479 2014-04-05 22:10:00,21.4353410369 2014-04-05 22:15:00,21.0398862553 2014-04-05 22:20:00,20.087889751 2014-04-05 22:25:00,20.3080279876 2014-04-05 22:30:00,18.5373500845 2014-04-05 22:35:00,21.383234241 2014-04-05 22:40:00,21.1681406466 2014-04-05 22:45:00,20.6456824117 2014-04-05 22:50:00,19.8838343091 2014-04-05 22:55:00,21.878820586 2014-04-05 23:00:00,21.5202589819 2014-04-05 23:05:00,20.5816728947 2014-04-05 23:10:00,19.4909455321 2014-04-05 23:15:00,20.476019753800003 2014-04-05 23:20:00,20.3056616428 2014-04-05 23:25:00,19.5807267273 2014-04-05 23:30:00,19.2303874105 2014-04-05 23:35:00,19.631811751300003 2014-04-05 23:40:00,20.2995423861 2014-04-05 23:45:00,19.7163241845 2014-04-05 23:50:00,19.057956376099998 2014-04-05 23:55:00,21.047893688800002 2014-04-06 00:00:00,20.1258699838 2014-04-06 00:05:00,18.2707006529 2014-04-06 00:10:00,19.4732660225 2014-04-06 00:15:00,21.539653828800002 2014-04-06 00:20:00,21.020946124800002 2014-04-06 00:25:00,19.2929871358 2014-04-06 00:30:00,21.752732608200002 2014-04-06 00:35:00,18.3064116334 2014-04-06 00:40:00,21.8449388156 2014-04-06 00:45:00,18.9828203699 2014-04-06 00:50:00,18.0363767212 2014-04-06 00:55:00,19.7352321461 2014-04-06 01:00:00,19.4358817187 2014-04-06 01:05:00,20.1563560208 2014-04-06 01:10:00,21.1870914423 2014-04-06 01:15:00,21.3697232086 2014-04-06 01:20:00,19.6049199984 2014-04-06 01:25:00,19.7193829748 2014-04-06 01:30:00,18.5927109213 2014-04-06 01:35:00,18.1901904355 2014-04-06 01:40:00,20.564859960899998 2014-04-06 01:45:00,18.2577505022 2014-04-06 01:50:00,20.9353204777 2014-04-06 01:55:00,20.1563605801 2014-04-06 02:00:00,18.7943319129 2014-04-06 02:05:00,20.1580917741 2014-04-06 02:10:00,18.7319908664 2014-04-06 02:15:00,19.75494883 2014-04-06 02:20:00,21.198241265 2014-04-06 02:25:00,19.847677173599998 2014-04-06 02:30:00,18.5947972732 2014-04-06 02:35:00,20.8953147273 2014-04-06 02:40:00,18.7470736651 2014-04-06 02:45:00,20.9541994975 2014-04-06 02:50:00,19.9174091569 2014-04-06 02:55:00,19.814967036400002 2014-04-06 03:00:00,21.4057401514 2014-04-06 03:05:00,20.8344140974 2014-04-06 03:10:00,18.131643187799998 2014-04-06 03:15:00,19.1846972584 2014-04-06 03:20:00,21.4836826434 2014-04-06 03:25:00,18.0733046742 2014-04-06 03:30:00,20.181013785 2014-04-06 03:35:00,20.9113026767 2014-04-06 03:40:00,20.4874243419 2014-04-06 03:45:00,21.042128808399998 2014-04-06 03:50:00,20.9027673957 2014-04-06 03:55:00,20.7681227806 2014-04-06 04:00:00,21.286159443699997 2014-04-06 04:05:00,20.5827626738 2014-04-06 04:10:00,19.609673977 2014-04-06 04:15:00,19.8876364397 2014-04-06 04:20:00,20.8668991307 2014-04-06 04:25:00,21.5052241187 2014-04-06 04:30:00,19.0888752034 2014-04-06 04:35:00,19.3683071839 2014-04-06 04:40:00,21.7229575854 2014-04-06 04:45:00,20.314047169600002 2014-04-06 04:50:00,18.7158472685 2014-04-06 04:55:00,20.6547805556 2014-04-06 05:00:00,21.9630486222 2014-04-06 05:05:00,21.2938142579 2014-04-06 05:10:00,20.982964546199998 2014-04-06 05:15:00,18.8321866171 2014-04-06 05:20:00,21.5045591387 2014-04-06 05:25:00,20.1031553741 2014-04-06 05:30:00,21.557160088299998 2014-04-06 05:35:00,19.3193113177 2014-04-06 05:40:00,18.2482042105 2014-04-06 05:45:00,19.9039038746 2014-04-06 05:50:00,19.0793504193 2014-04-06 05:55:00,20.8609171591 2014-04-06 06:00:00,21.8284262114 2014-04-06 06:05:00,20.7638966046 2014-04-06 06:10:00,21.547735718800002 2014-04-06 06:15:00,19.8120960544 2014-04-06 06:20:00,21.0865629488 2014-04-06 06:25:00,21.3721737467 2014-04-06 06:30:00,20.8435025103 2014-04-06 06:35:00,20.0311091443 2014-04-06 06:40:00,20.5034644385 2014-04-06 06:45:00,20.8020279827 2014-04-06 06:50:00,19.012337612899998 2014-04-06 06:55:00,21.2383170437 2014-04-06 07:00:00,21.801298155900003 2014-04-06 07:05:00,19.860957260699998 2014-04-06 07:10:00,20.8042687324 2014-04-06 07:15:00,20.948103623199998 2014-04-06 07:20:00,20.6489901901 2014-04-06 07:25:00,20.188460433299998 2014-04-06 07:30:00,21.5265918183 2014-04-06 07:35:00,19.7957068371 2014-04-06 07:40:00,18.2444118259 2014-04-06 07:45:00,21.3782255028 2014-04-06 07:50:00,20.6959250893 2014-04-06 07:55:00,21.397034506 2014-04-06 08:00:00,18.5541897698 2014-04-06 08:05:00,18.123011762 2014-04-06 08:10:00,21.7374981615 2014-04-06 08:15:00,18.590913223399998 2014-04-06 08:20:00,21.2386093283 2014-04-06 08:25:00,21.2928397687 2014-04-06 08:30:00,20.8348208022 2014-04-06 08:35:00,18.5250488444 2014-04-06 08:40:00,20.6695944982 2014-04-06 08:45:00,21.5563463333 2014-04-06 08:50:00,19.7021265792 2014-04-06 08:55:00,19.6540674175 2014-04-06 09:00:00,67.22287301029999 2014-04-06 09:05:00,62.318897713199995 2014-04-06 09:10:00,73.3315477388 2014-04-06 09:15:00,73.0208869501 2014-04-06 09:20:00,74.7715667763 2014-04-06 09:25:00,69.1584907244 2014-04-06 09:30:00,71.41620625569999 2014-04-06 09:35:00,63.9563379258 2014-04-06 09:40:00,70.2783919278 2014-04-06 09:45:00,70.0363667431 2014-04-06 09:50:00,73.45643880739999 2014-04-06 09:55:00,72.4987810306 2014-04-06 10:00:00,84.4049994998 2014-04-06 10:05:00,83.3242954963 2014-04-06 10:10:00,83.3221292488 2014-04-06 10:15:00,70.8289860302 2014-04-06 10:20:00,82.9693295058 2014-04-06 10:25:00,79.2680646827 2014-04-06 10:30:00,75.7444978914 2014-04-06 10:35:00,70.7171069705 2014-04-06 10:40:00,80.3574969844 2014-04-06 10:45:00,74.9336911683 2014-04-06 10:50:00,77.0998876326 2014-04-06 10:55:00,80.4204253431 2014-04-06 11:00:00,86.0688623959 2014-04-06 11:05:00,84.6957487058 2014-04-06 11:10:00,78.7342967413 2014-04-06 11:15:00,77.735303336 2014-04-06 11:20:00,75.3814569666 2014-04-06 11:25:00,77.49107505069999 2014-04-06 11:30:00,73.33408174350001 2014-04-06 11:35:00,87.012462005 2014-04-06 11:40:00,80.6955830287 2014-04-06 11:45:00,73.6006241238 2014-04-06 11:50:00,77.1790267714 2014-04-06 11:55:00,80.2681105401 2014-04-06 12:00:00,80.429538782 2014-04-06 12:05:00,72.48097223479999 2014-04-06 12:10:00,87.10880039979997 2014-04-06 12:15:00,76.3143236905 2014-04-06 12:20:00,72.1722439573 2014-04-06 12:25:00,73.1352364182 2014-04-06 12:30:00,81.1855787098 2014-04-06 12:35:00,74.1155228488 2014-04-06 12:40:00,72.5803955696 2014-04-06 12:45:00,77.9803346344 2014-04-06 12:50:00,81.8658220626 2014-04-06 12:55:00,73.7008895532 2014-04-06 13:00:00,76.9947621355 2014-04-06 13:05:00,78.665286545 2014-04-06 13:10:00,74.53346923779999 2014-04-06 13:15:00,80.0779590517 2014-04-06 13:20:00,73.3458181683 2014-04-06 13:25:00,72.7268373105 2014-04-06 13:30:00,80.2980897067 2014-04-06 13:35:00,75.9481196396 2014-04-06 13:40:00,73.5083346909 2014-04-06 13:45:00,78.7636935755 2014-04-06 13:50:00,86.6214576918 2014-04-06 13:55:00,83.5670182475 2014-04-06 14:00:00,85.0457722525 2014-04-06 14:05:00,85.9464981902 2014-04-06 14:10:00,87.5578408842 2014-04-06 14:15:00,84.2079030029 2014-04-06 14:20:00,81.7306034937 2014-04-06 14:25:00,77.84307743779999 2014-04-06 14:30:00,74.9026962829 2014-04-06 14:35:00,82.9825746289 2014-04-06 14:40:00,87.91497965639999 2014-04-06 14:45:00,79.4739240224 2014-04-06 14:50:00,83.5748581037 2014-04-06 14:55:00,79.9176429689 2014-04-06 15:00:00,78.9101772288 2014-04-06 15:05:00,78.56413559399999 2014-04-06 15:10:00,80.0732262166 2014-04-06 15:15:00,77.8695830347 2014-04-06 15:20:00,83.9795669376 2014-04-06 15:25:00,85.98752693729998 2014-04-06 15:30:00,86.1253380951 2014-04-06 15:35:00,75.6424532403 2014-04-06 15:40:00,86.3337174081 2014-04-06 15:45:00,77.4640760474 2014-04-06 15:50:00,76.9481839381 2014-04-06 15:55:00,83.6272940886 2014-04-06 16:00:00,76.8749938411 2014-04-06 16:05:00,72.8473226226 2014-04-06 16:10:00,77.9777346394 2014-04-06 16:15:00,83.5432892023 2014-04-06 16:20:00,77.2311864402 2014-04-06 16:25:00,82.0727873159 2014-04-06 16:30:00,82.5617525893 2014-04-06 16:35:00,83.7396154073 2014-04-06 16:40:00,86.3539216611 2014-04-06 16:45:00,78.9208804599 2014-04-06 16:50:00,74.6627698738 2014-04-06 16:55:00,77.1026634095 2014-04-06 17:00:00,78.91464577949999 2014-04-06 17:05:00,83.4222314751 2014-04-06 17:10:00,72.2099262804 2014-04-06 17:15:00,77.0525365469 2014-04-06 17:20:00,84.477448857 2014-04-06 17:25:00,82.73369148350001 2014-04-06 17:30:00,83.7078074336 2014-04-06 17:35:00,84.9889396753 2014-04-06 17:40:00,84.53173904180001 2014-04-06 17:45:00,82.9148988191 2014-04-06 17:50:00,79.0345541686 2014-04-06 17:55:00,87.7375395708 2014-04-06 18:00:00,32.4420622229 2014-04-06 18:05:00,30.0977171612 2014-04-06 18:10:00,30.6739963833 2014-04-06 18:15:00,33.2387933364 2014-04-06 18:20:00,34.7183265514 2014-04-06 18:25:00,29.9438030777 2014-04-06 18:30:00,29.327011942 2014-04-06 18:35:00,34.441792094600004 2014-04-06 18:40:00,34.657772410700005 2014-04-06 18:45:00,30.5688219408 2014-04-06 18:50:00,31.214622642800002 2014-04-06 18:55:00,33.0251968431 2014-04-06 19:00:00,21.638085306399997 2014-04-06 19:05:00,24.089669691599997 2014-04-06 19:10:00,20.641951455799997 2014-04-06 19:15:00,20.3301592346 2014-04-06 19:20:00,21.0940170491 2014-04-06 19:25:00,21.4416720701 2014-04-06 19:30:00,20.665909995299998 2014-04-06 19:35:00,20.454292001400002 2014-04-06 19:40:00,23.545121264899997 2014-04-06 19:45:00,20.895957868900002 2014-04-06 19:50:00,24.25437012130001 2014-04-06 19:55:00,21.8086372869 2014-04-06 20:00:00,21.1788011425 2014-04-06 20:05:00,19.3552468298 2014-04-06 20:10:00,19.4163618267 2014-04-06 20:15:00,20.7860086455 2014-04-06 20:20:00,20.7283931727 2014-04-06 20:25:00,21.580714659 2014-04-06 20:30:00,21.5360030417 2014-04-06 20:35:00,21.1791368299 2014-04-06 20:40:00,20.2716385546 2014-04-06 20:45:00,22.080062757199997 2014-04-06 20:50:00,20.9820812442 2014-04-06 20:55:00,22.4878527471 2014-04-06 21:00:00,21.37961112 2014-04-06 21:05:00,18.2644899487 2014-04-06 21:10:00,19.3749309839 2014-04-06 21:15:00,20.3848828298 2014-04-06 21:20:00,20.9861303153 2014-04-06 21:25:00,20.2983124022 2014-04-06 21:30:00,21.246015342 2014-04-06 21:35:00,19.2224495525 2014-04-06 21:40:00,18.8255792703 2014-04-06 21:45:00,18.3031018907 2014-04-06 21:50:00,20.3906625523 2014-04-06 21:55:00,20.8540191425 2014-04-06 22:00:00,19.3231312739 2014-04-06 22:05:00,20.4739728926 2014-04-06 22:10:00,18.2261091982 2014-04-06 22:15:00,18.4148346626 2014-04-06 22:20:00,20.8269938171 2014-04-06 22:25:00,19.490972199 2014-04-06 22:30:00,20.7051940369 2014-04-06 22:35:00,21.3473582797 2014-04-06 22:40:00,21.4310438095 2014-04-06 22:45:00,18.7066116964 2014-04-06 22:50:00,19.9642896162 2014-04-06 22:55:00,20.9558051629 2014-04-06 23:00:00,21.0999728001 2014-04-06 23:05:00,21.142762552 2014-04-06 23:10:00,18.9163005682 2014-04-06 23:15:00,18.7737431358 2014-04-06 23:20:00,20.3639590007 2014-04-06 23:25:00,20.968368342799998 2014-04-06 23:30:00,19.2802591594 2014-04-06 23:35:00,18.4223570392 2014-04-06 23:40:00,20.8709919908 2014-04-06 23:45:00,19.2024774916 2014-04-06 23:50:00,18.669034662 2014-04-06 23:55:00,18.594463563399998 2014-04-07 00:00:00,19.2596381901 2014-04-07 00:05:00,20.3707122637 2014-04-07 00:10:00,19.4336089548 2014-04-07 00:15:00,18.0826474064 2014-04-07 00:20:00,18.3876337387 2014-04-07 00:25:00,19.1620129888 2014-04-07 00:30:00,20.638817928599998 2014-04-07 00:35:00,18.3940602939 2014-04-07 00:40:00,20.242627414 2014-04-07 00:45:00,18.4795434833 2014-04-07 00:50:00,18.846461309400002 2014-04-07 00:55:00,18.6887541102 2014-04-07 01:00:00,18.2689145423 2014-04-07 01:05:00,20.6853192695 2014-04-07 01:10:00,19.8536141895 2014-04-07 01:15:00,21.3242137636 2014-04-07 01:20:00,18.3955633599 2014-04-07 01:25:00,18.578931733399997 2014-04-07 01:30:00,19.2258309254 2014-04-07 01:35:00,21.0634639478 2014-04-07 01:40:00,19.2230352926 2014-04-07 01:45:00,19.63367483 2014-04-07 01:50:00,19.2064142652 2014-04-07 01:55:00,18.320897167200002 2014-04-07 02:00:00,21.757734491599997 2014-04-07 02:05:00,20.1941559683 2014-04-07 02:10:00,21.1513327527 2014-04-07 02:15:00,20.6334283687 2014-04-07 02:20:00,20.057017116199997 2014-04-07 02:25:00,18.3587130266 2014-04-07 02:30:00,20.5709341811 2014-04-07 02:35:00,18.6214814237 2014-04-07 02:40:00,19.6575326774 2014-04-07 02:45:00,20.5164525739 2014-04-07 02:50:00,21.128916001900002 2014-04-07 02:55:00,20.7401807028 2014-04-07 03:00:00,20.686134116199998 2014-04-07 03:05:00,18.596168836700002 2014-04-07 03:10:00,19.3845141603 2014-04-07 03:15:00,18.1716490906 2014-04-07 03:20:00,20.8779075727 2014-04-07 03:25:00,21.810343925300003 2014-04-07 03:30:00,19.056441560699998 2014-04-07 03:35:00,18.3507868366 2014-04-07 03:40:00,19.902280307 2014-04-07 03:45:00,21.4267928925 2014-04-07 03:50:00,20.2078967811 2014-04-07 03:55:00,18.1871086008 2014-04-07 04:00:00,21.8970889621 2014-04-07 04:05:00,21.3145996399 2014-04-07 04:10:00,18.5263763082 2014-04-07 04:15:00,21.687191026 2014-04-07 04:20:00,19.8027531544 2014-04-07 04:25:00,19.4875919623 2014-04-07 04:30:00,19.8442133221 2014-04-07 04:35:00,21.3382878275 2014-04-07 04:40:00,20.6379187131 2014-04-07 04:45:00,18.2369938096 2014-04-07 04:50:00,21.8304174845 2014-04-07 04:55:00,18.591136533900002 2014-04-07 05:00:00,20.982271806900002 2014-04-07 05:05:00,20.5445461217 2014-04-07 05:10:00,18.7501121918 2014-04-07 05:15:00,18.6829283045 2014-04-07 05:20:00,21.4813103748 2014-04-07 05:25:00,19.678779694 2014-04-07 05:30:00,20.6183060567 2014-04-07 05:35:00,20.0162840154 2014-04-07 05:40:00,20.9094140683 2014-04-07 05:45:00,19.9169695002 2014-04-07 05:50:00,19.149519661 2014-04-07 05:55:00,19.453533484 2014-04-07 06:00:00,21.4363107778 2014-04-07 06:05:00,19.8721387717 2014-04-07 06:10:00,18.853797329000002 2014-04-07 06:15:00,21.7384215523 2014-04-07 06:20:00,21.186401825999997 2014-04-07 06:25:00,18.2226645842 2014-04-07 06:30:00,21.9957718479 2014-04-07 06:35:00,20.7797067858 2014-04-07 06:40:00,18.6410663962 2014-04-07 06:45:00,18.9486707252 2014-04-07 06:50:00,20.769781925 2014-04-07 06:55:00,21.119044221099998 2014-04-07 07:00:00,18.9561437726 2014-04-07 07:05:00,19.0278754156 2014-04-07 07:10:00,19.228482779500002 2014-04-07 07:15:00,20.3920734593 2014-04-07 07:20:00,18.687264713199998 2014-04-07 07:25:00,18.416972795499998 2014-04-07 07:30:00,20.715456356300002 2014-04-07 07:35:00,21.1163917592 2014-04-07 07:40:00,20.0037176177 2014-04-07 07:45:00,19.4553308411 2014-04-07 07:50:00,19.7281708541 2014-04-07 07:55:00,19.5536313355 2014-04-07 08:00:00,21.839939633 2014-04-07 08:05:00,21.0723596209 2014-04-07 08:10:00,18.8323488594 2014-04-07 08:15:00,19.5367566082 2014-04-07 08:20:00,20.1760491655 2014-04-07 08:25:00,20.4519434483 2014-04-07 08:30:00,19.872735584100003 2014-04-07 08:35:00,21.24050654 2014-04-07 08:40:00,21.0704240778 2014-04-07 08:45:00,20.0206316745 2014-04-07 08:50:00,21.4177175471 2014-04-07 08:55:00,21.0043581218 2014-04-07 09:00:00,71.7887131426 2014-04-07 09:05:00,74.2070506003 2014-04-07 09:10:00,64.8239504004 2014-04-07 09:15:00,64.8400150082 2014-04-07 09:20:00,73.2897506774 2014-04-07 09:25:00,71.702278678 2014-04-07 09:30:00,73.8010193635 2014-04-07 09:35:00,62.0585701804 2014-04-07 09:40:00,69.73749625079999 2014-04-07 09:45:00,63.166945398500005 2014-04-07 09:50:00,68.0530018968 2014-04-07 09:55:00,63.3181582732 2014-04-07 10:00:00,71.8277784594 2014-04-07 10:05:00,70.0288527203 2014-04-07 10:10:00,79.6213063682 2014-04-07 10:15:00,75.41203101100001 2014-04-07 10:20:00,71.47252218130002 2014-04-07 10:25:00,74.8504423104 2014-04-07 10:30:00,72.4620122993 2014-04-07 10:35:00,84.4551037849 2014-04-07 10:40:00,74.806475827 2014-04-07 10:45:00,75.0229586815 2014-04-07 10:50:00,82.8745962128 2014-04-07 10:55:00,79.8931694152 2014-04-07 11:00:00,82.8625692441 2014-04-07 11:05:00,81.68297269060001 2014-04-07 11:10:00,86.6163056999 2014-04-07 11:15:00,74.86014122510001 2014-04-07 11:20:00,87.2976801009 2014-04-07 11:25:00,84.7835270479 2014-04-07 11:30:00,80.9350200535 2014-04-07 11:35:00,82.10235831439999 2014-04-07 11:40:00,81.88692673989999 2014-04-07 11:45:00,72.4967335474 2014-04-07 11:50:00,75.03533439270001 2014-04-07 11:55:00,86.8592329475 2014-04-07 12:00:00,80.4531710647 2014-04-07 12:05:00,77.959993263 2014-04-07 12:10:00,84.0915842757 2014-04-07 12:15:00,80.2958323188 2014-04-07 12:20:00,72.1239516177 2014-04-07 12:25:00,83.67926578560001 2014-04-07 12:30:00,83.6150223837 2014-04-07 12:35:00,74.5528085385 2014-04-07 12:40:00,87.2017935411 2014-04-07 12:45:00,75.4918310685 2014-04-07 12:50:00,79.2288010903 2014-04-07 12:55:00,73.7471724497 2014-04-07 13:00:00,81.6329205071 2014-04-07 13:05:00,77.9884961886 2014-04-07 13:10:00,77.63213920930001 2014-04-07 13:15:00,85.2111744443 2014-04-07 13:20:00,72.1356706886 2014-04-07 13:25:00,84.74680421869998 2014-04-07 13:30:00,81.12370268949999 2014-04-07 13:35:00,87.7565095974 2014-04-07 13:40:00,81.41154806770001 2014-04-07 13:45:00,72.8685734905 2014-04-07 13:50:00,72.792850745 2014-04-07 13:55:00,86.10977647450001 2014-04-07 14:00:00,85.4553242757 2014-04-07 14:05:00,77.53051956569999 2014-04-07 14:10:00,81.884589098 2014-04-07 14:15:00,79.8296297067 2014-04-07 14:20:00,87.4704261002 2014-04-07 14:25:00,87.1951888441 2014-04-07 14:30:00,87.7372125483 2014-04-07 14:35:00,85.8590590575 2014-04-07 14:40:00,86.5486709168 2014-04-07 14:45:00,75.4728375902 2014-04-07 14:50:00,85.2920144106 2014-04-07 14:55:00,83.337713409 2014-04-07 15:00:00,87.4037450572 2014-04-07 15:05:00,81.1394103093 2014-04-07 15:10:00,73.36197038569999 2014-04-07 15:15:00,81.55759929850001 2014-04-07 15:20:00,82.9844981895 2014-04-07 15:25:00,75.5244114181 2014-04-07 15:30:00,78.3050624004 2014-04-07 15:35:00,81.5752714947 2014-04-07 15:40:00,77.9849431344 2014-04-07 15:45:00,77.99841468380002 2014-04-07 15:50:00,74.12867458470001 2014-04-07 15:55:00,87.0511118705 2014-04-07 16:00:00,84.0077488567 2014-04-07 16:05:00,72.0197567437 2014-04-07 16:10:00,84.24965078470001 2014-04-07 16:15:00,83.836558916 2014-04-07 16:20:00,72.1555568236 2014-04-07 16:25:00,77.9135191676 2014-04-07 16:30:00,81.7078061659 2014-04-07 16:35:00,79.2438582812 2014-04-07 16:40:00,84.4476157598 2014-04-07 16:45:00,78.8071820121 2014-04-07 16:50:00,74.4616645446 2014-04-07 16:55:00,87.62248175290001 2014-04-07 17:00:00,75.87261074930001 2014-04-07 17:05:00,83.4830449112 2014-04-07 17:10:00,74.2904724591 2014-04-07 17:15:00,77.2641721511 2014-04-07 17:20:00,79.0724113711 2014-04-07 17:25:00,75.07568324340001 2014-04-07 17:30:00,79.1993228093 2014-04-07 17:35:00,74.5145765543 2014-04-07 17:40:00,80.9440735412 2014-04-07 17:45:00,82.61938031449999 2014-04-07 17:50:00,72.9989205129 2014-04-07 17:55:00,85.9380809371 2014-04-07 18:00:00,29.9848959072 2014-04-07 18:05:00,30.242313715500003 2014-04-07 18:10:00,33.0326326343 2014-04-07 18:15:00,31.8000006812 2014-04-07 18:20:00,31.9961256914 2014-04-07 18:25:00,29.6201862141 2014-04-07 18:30:00,33.9567027403 2014-04-07 18:35:00,32.7491408872 2014-04-07 18:40:00,29.6664393812 2014-04-07 18:45:00,31.1935899598 2014-04-07 18:50:00,33.9866170441 2014-04-07 18:55:00,32.437466066300004 2014-04-07 19:00:00,20.6467453979 2014-04-07 19:05:00,21.8300399676 2014-04-07 19:10:00,21.247269739500002 2014-04-07 19:15:00,22.4782444473 2014-04-07 19:20:00,23.9382565442 2014-04-07 19:25:00,22.114475550799998 2014-04-07 19:30:00,22.1013710836 2014-04-07 19:35:00,24.215970714 2014-04-07 19:40:00,22.7413094005 2014-04-07 19:45:00,22.696534826500002 2014-04-07 19:50:00,21.3333551453 2014-04-07 19:55:00,22.882596655 2014-04-07 20:00:00,20.7909290251 2014-04-07 20:05:00,20.0575033818 2014-04-07 20:10:00,22.489888768 2014-04-07 20:15:00,22.0442251279 2014-04-07 20:20:00,21.502305186100006 2014-04-07 20:25:00,20.6329672825 2014-04-07 20:30:00,20.3245967047 2014-04-07 20:35:00,19.1893395006 2014-04-07 20:40:00,19.6843004574 2014-04-07 20:45:00,21.6021431769 2014-04-07 20:50:00,20.2905554718 2014-04-07 20:55:00,22.045775675300003 2014-04-07 21:00:00,18.680884393499998 2014-04-07 21:05:00,20.1295485991 2014-04-07 21:10:00,20.6866844266 2014-04-07 21:15:00,20.1637172663 2014-04-07 21:20:00,21.660380669699997 2014-04-07 21:25:00,22.0636526884 2014-04-07 21:30:00,18.5519626134 2014-04-07 21:35:00,18.608714705 2014-04-07 21:40:00,18.6101986317 2014-04-07 21:45:00,20.8241869336 2014-04-07 21:50:00,19.5842597151 2014-04-07 21:55:00,21.0337382351 2014-04-07 22:00:00,19.6407228924 2014-04-07 22:05:00,20.5301168851 2014-04-07 22:10:00,21.0996682671 2014-04-07 22:15:00,20.2122487818 2014-04-07 22:20:00,20.177366045699998 2014-04-07 22:25:00,18.3705561119 2014-04-07 22:30:00,19.6619843639 2014-04-07 22:35:00,20.202484387200002 2014-04-07 22:40:00,19.8669772993 2014-04-07 22:45:00,21.623866993000004 2014-04-07 22:50:00,21.6468835955 2014-04-07 22:55:00,21.3081056746 2014-04-07 23:00:00,19.5049365285 2014-04-07 23:05:00,20.873203490399998 2014-04-07 23:10:00,19.5849134239 2014-04-07 23:15:00,18.9340090259 2014-04-07 23:20:00,19.3753299215 2014-04-07 23:25:00,18.2873690322 2014-04-07 23:30:00,19.3308208392 2014-04-07 23:35:00,19.8467787171 2014-04-07 23:40:00,21.8261133863 2014-04-07 23:45:00,19.2573390423 2014-04-07 23:50:00,21.613963239 2014-04-07 23:55:00,18.9190648646 2014-04-08 00:00:00,18.763875590999998 2014-04-08 00:05:00,20.075981825699998 2014-04-08 00:10:00,20.6900454772 2014-04-08 00:15:00,18.1773290032 2014-04-08 00:20:00,18.8842634602 2014-04-08 00:25:00,19.822734666 2014-04-08 00:30:00,19.3240173439 2014-04-08 00:35:00,20.8504843174 2014-04-08 00:40:00,20.0446423842 2014-04-08 00:45:00,18.6414364224 2014-04-08 00:50:00,21.5778615173 2014-04-08 00:55:00,19.171622701900002 2014-04-08 01:00:00,20.9245244359 2014-04-08 01:05:00,21.1196631164 2014-04-08 01:10:00,21.852630801 2014-04-08 01:15:00,19.9940298661 2014-04-08 01:20:00,20.4633420619 2014-04-08 01:25:00,19.3395051739 2014-04-08 01:30:00,20.712717173599998 2014-04-08 01:35:00,19.8535339435 2014-04-08 01:40:00,19.7506094589 2014-04-08 01:45:00,21.421870116500003 2014-04-08 01:50:00,18.200675374 2014-04-08 01:55:00,21.5278497113 2014-04-08 02:00:00,21.408279351300003 2014-04-08 02:05:00,20.0254650142 2014-04-08 02:10:00,19.960811416800002 2014-04-08 02:15:00,19.447229472100002 2014-04-08 02:20:00,21.9766951667 2014-04-08 02:25:00,18.444677330999998 2014-04-08 02:30:00,20.3608609425 2014-04-08 02:35:00,20.7267263604 2014-04-08 02:40:00,21.7373200329 2014-04-08 02:45:00,21.120813987400002 2014-04-08 02:50:00,20.5753888112 2014-04-08 02:55:00,18.4672492672 2014-04-08 03:00:00,19.4949340673 2014-04-08 03:05:00,18.5553665702 2014-04-08 03:10:00,21.524850929899998 2014-04-08 03:15:00,20.9984846223 2014-04-08 03:20:00,21.0301471472 2014-04-08 03:25:00,20.6090260711 2014-04-08 03:30:00,20.0281741477 2014-04-08 03:35:00,18.5998842379 2014-04-08 03:40:00,19.318779546800002 2014-04-08 03:45:00,18.5476631699 2014-04-08 03:50:00,20.8996525714 2014-04-08 03:55:00,18.6409151041 2014-04-08 04:00:00,20.808454200699998 2014-04-08 04:05:00,20.7690215584 2014-04-08 04:10:00,19.837217916 2014-04-08 04:15:00,18.5409146165 2014-04-08 04:20:00,19.2592033045 2014-04-08 04:25:00,19.280372436300002 2014-04-08 04:30:00,20.8015405326 2014-04-08 04:35:00,18.4549720777 2014-04-08 04:40:00,21.3162745849 2014-04-08 04:45:00,21.0440291607 2014-04-08 04:50:00,18.7452276727 2014-04-08 04:55:00,20.8766575271 2014-04-08 05:00:00,20.674052725899998 2014-04-08 05:05:00,20.9924832004 2014-04-08 05:10:00,18.7557142218 2014-04-08 05:15:00,18.6303612886 2014-04-08 05:20:00,18.9459359437 2014-04-08 05:25:00,19.4634868126 2014-04-08 05:30:00,21.174659924100002 2014-04-08 05:35:00,20.9516957499 2014-04-08 05:40:00,21.701806369099998 2014-04-08 05:45:00,18.2345182364 2014-04-08 05:50:00,18.0462251241 2014-04-08 05:55:00,20.7965553188 2014-04-08 06:00:00,19.1171499832 2014-04-08 06:05:00,19.3363155821 2014-04-08 06:10:00,20.187208103699998 2014-04-08 06:15:00,18.4096524925 2014-04-08 06:20:00,20.570777666199998 2014-04-08 06:25:00,19.3005897849 2014-04-08 06:30:00,20.5308604972 2014-04-08 06:35:00,21.3360276523 2014-04-08 06:40:00,18.684445333299998 2014-04-08 06:45:00,21.7234923717 2014-04-08 06:50:00,20.122752564200002 2014-04-08 06:55:00,21.6917110607 2014-04-08 07:00:00,18.8309203288 2014-04-08 07:05:00,20.418250658399998 2014-04-08 07:10:00,19.615548469300002 2014-04-08 07:15:00,21.0968887646 2014-04-08 07:20:00,20.4236357729 2014-04-08 07:25:00,19.9780618278 2014-04-08 07:30:00,21.6519416257 2014-04-08 07:35:00,19.508468256700002 2014-04-08 07:40:00,18.8799208196 2014-04-08 07:45:00,20.4324047474 2014-04-08 07:50:00,20.496113748699997 2014-04-08 07:55:00,19.7563784863 2014-04-08 08:00:00,19.9464401748 2014-04-08 08:05:00,21.838213657199997 2014-04-08 08:10:00,20.930742765599998 2014-04-08 08:15:00,18.442407005899998 2014-04-08 08:20:00,18.848520283499997 2014-04-08 08:25:00,21.9023065377 2014-04-08 08:30:00,20.9058622152 2014-04-08 08:35:00,21.6601805046 2014-04-08 08:40:00,19.215445856 2014-04-08 08:45:00,20.9674674403 2014-04-08 08:50:00,20.8560108341 2014-04-08 08:55:00,19.1787599418 2014-04-08 09:00:00,68.6911020261 2014-04-08 09:05:00,69.7328455133 2014-04-08 09:10:00,67.7433926273 2014-04-08 09:15:00,72.4496304105 2014-04-08 09:20:00,72.5270189685 2014-04-08 09:25:00,72.7681674569 2014-04-08 09:30:00,72.12656053970001 2014-04-08 09:35:00,67.8379352899 2014-04-08 09:40:00,66.3875608548 2014-04-08 09:45:00,72.5067174585 2014-04-08 09:50:00,67.8667398364 2014-04-08 09:55:00,64.5506510213 2014-04-08 10:00:00,77.7139716216 2014-04-08 10:05:00,72.0415092362 2014-04-08 10:10:00,80.5740896941 2014-04-08 10:15:00,75.0534982908 2014-04-08 10:20:00,73.8854245519 2014-04-08 10:25:00,84.6850157416 2014-04-08 10:30:00,81.8971930542 2014-04-08 10:35:00,82.0553186823 2014-04-08 10:40:00,79.5201649632 2014-04-08 10:45:00,82.8639620191 2014-04-08 10:50:00,81.6222017077 2014-04-08 10:55:00,79.1329678882 2014-04-08 11:00:00,86.85372248700001 2014-04-08 11:05:00,74.61512607979999 2014-04-08 11:10:00,86.5715110509 2014-04-08 11:15:00,77.95247252840001 2014-04-08 11:20:00,79.971657432 2014-04-08 11:25:00,73.520046138 2014-04-08 11:30:00,80.15786870859999 2014-04-08 11:35:00,81.2886321816 2014-04-08 11:40:00,87.4354453209 2014-04-08 11:45:00,87.0774601057 2014-04-08 11:50:00,86.93758253 2014-04-08 11:55:00,77.1087637079 2014-04-08 12:00:00,87.75483166309998 2014-04-08 12:05:00,79.192505245 2014-04-08 12:10:00,85.526624884 2014-04-08 12:15:00,75.3705661609 2014-04-08 12:20:00,79.9972188775 2014-04-08 12:25:00,87.3512461058 2014-04-08 12:30:00,87.047919348 2014-04-08 12:35:00,82.8402303355 2014-04-08 12:40:00,84.6633111259 2014-04-08 12:45:00,74.7330397531 2014-04-08 12:50:00,83.4462809476 2014-04-08 12:55:00,81.7905463578 2014-04-08 13:00:00,73.4471962134 2014-04-08 13:05:00,73.7928295748 2014-04-08 13:10:00,73.7174014605 2014-04-08 13:15:00,83.5696494266 2014-04-08 13:20:00,74.24961914560001 2014-04-08 13:25:00,79.4646402459 2014-04-08 13:30:00,77.6930580839 2014-04-08 13:35:00,80.78867231640001 2014-04-08 13:40:00,83.2836309258 2014-04-08 13:45:00,82.935651261 2014-04-08 13:50:00,80.2290590582 2014-04-08 13:55:00,79.4102949319 2014-04-08 14:00:00,78.3612879996 2014-04-08 14:05:00,85.78644122600001 2014-04-08 14:10:00,77.2899187838 2014-04-08 14:15:00,76.1461979457 2014-04-08 14:20:00,83.8890210322 2014-04-08 14:25:00,77.7524830888 2014-04-08 14:30:00,85.5478711012 2014-04-08 14:35:00,77.2425116797 2014-04-08 14:40:00,83.2271220996 2014-04-08 14:45:00,72.7182534568 2014-04-08 14:50:00,78.1652539695 2014-04-08 14:55:00,77.4879631987 2014-04-08 15:00:00,85.0660431866 2014-04-08 15:05:00,87.4720467119 2014-04-08 15:10:00,79.37333843569999 2014-04-08 15:15:00,85.1965625396 2014-04-08 15:20:00,83.1943165422 2014-04-08 15:25:00,87.4773360121 2014-04-08 15:30:00,84.9769204432 2014-04-08 15:35:00,73.2389459548 2014-04-08 15:40:00,83.411706798 2014-04-08 15:45:00,80.567221994 2014-04-08 15:50:00,72.2622832023 2014-04-08 15:55:00,76.0202775379 2014-04-08 16:00:00,86.7479173641 2014-04-08 16:05:00,86.816815276 2014-04-08 16:10:00,84.7814445825 2014-04-08 16:15:00,87.70830525219999 2014-04-08 16:20:00,84.9045605769 2014-04-08 16:25:00,72.1631284431 2014-04-08 16:30:00,76.6052023626 2014-04-08 16:35:00,72.489847735 2014-04-08 16:40:00,73.5055863688 2014-04-08 16:45:00,75.5013081084 2014-04-08 16:50:00,80.0567830319 2014-04-08 16:55:00,85.5603477792 2014-04-08 17:00:00,85.7914351546 2014-04-08 17:05:00,81.859198303 2014-04-08 17:10:00,86.85078167430002 2014-04-08 17:15:00,80.0009665051 2014-04-08 17:20:00,86.2245435959 2014-04-08 17:25:00,79.2650136635 2014-04-08 17:30:00,76.4355707675 2014-04-08 17:35:00,86.66257341120001 2014-04-08 17:40:00,78.2069311794 2014-04-08 17:45:00,80.05443500060001 2014-04-08 17:50:00,77.261740452 2014-04-08 17:55:00,82.6053698842 2014-04-08 18:00:00,35.1681930877 2014-04-08 18:05:00,28.963281151799997 2014-04-08 18:10:00,34.5590206031 2014-04-08 18:15:00,28.825121230300002 2014-04-08 18:20:00,31.1310524622 2014-04-08 18:25:00,29.879077823499998 2014-04-08 18:30:00,33.6469809361 2014-04-08 18:35:00,29.123903789099998 2014-04-08 18:40:00,32.3422974932 2014-04-08 18:45:00,30.687521364600002 2014-04-08 18:50:00,29.6554838989 2014-04-08 18:55:00,33.7396300794 2014-04-08 19:00:00,21.1340262581 2014-04-08 19:05:00,21.1620637891 2014-04-08 19:10:00,21.3923428239 2014-04-08 19:15:00,22.788713851799997 2014-04-08 19:20:00,23.115302105900003 2014-04-08 19:25:00,20.2388581959 2014-04-08 19:30:00,21.2435748044 2014-04-08 19:35:00,22.0907481626 2014-04-08 19:40:00,21.6472555582 2014-04-08 19:45:00,24.1210832269 2014-04-08 19:50:00,23.688933814899997 2014-04-08 19:55:00,22.9639869059 2014-04-08 20:00:00,19.816621498099998 2014-04-08 20:05:00,21.3019536689 2014-04-08 20:10:00,21.887541038000002 2014-04-08 20:15:00,20.8684249752 2014-04-08 20:20:00,21.6451539087 2014-04-08 20:25:00,21.500333663899998 2014-04-08 20:30:00,20.7738357772 2014-04-08 20:35:00,19.7107022196 2014-04-08 20:40:00,21.486723461300002 2014-04-08 20:45:00,19.2790376853 2014-04-08 20:50:00,21.6247840077 2014-04-08 20:55:00,21.727422990300003 2014-04-08 21:00:00,21.3907646477 2014-04-08 21:05:00,19.987143821700002 2014-04-08 21:10:00,18.8600186557 2014-04-08 21:15:00,18.4872090482 2014-04-08 21:20:00,21.074117486400002 2014-04-08 21:25:00,21.648461703800002 2014-04-08 21:30:00,20.7022494812 2014-04-08 21:35:00,18.665808069100002 2014-04-08 21:40:00,21.8439357525 2014-04-08 21:45:00,22.0617987629 2014-04-08 21:50:00,19.8282352606 2014-04-08 21:55:00,20.4771217526 2014-04-08 22:00:00,21.1291786271 2014-04-08 22:05:00,20.9656668867 2014-04-08 22:10:00,21.8921450598 2014-04-08 22:15:00,18.477253506300002 2014-04-08 22:20:00,20.3424094381 2014-04-08 22:25:00,20.7876626851 2014-04-08 22:30:00,21.581091664099997 2014-04-08 22:35:00,21.5170750813 2014-04-08 22:40:00,21.9330346827 2014-04-08 22:45:00,20.0675601872 2014-04-08 22:50:00,21.343513578499998 2014-04-08 22:55:00,19.7280475846 2014-04-08 23:00:00,19.693035846500003 2014-04-08 23:05:00,19.0170440276 2014-04-08 23:10:00,21.2770335522 2014-04-08 23:15:00,21.9474735271 2014-04-08 23:20:00,19.029019782 2014-04-08 23:25:00,18.2280254594 2014-04-08 23:30:00,21.2662520842 2014-04-08 23:35:00,20.4848525448 2014-04-08 23:40:00,21.8429882487 2014-04-08 23:45:00,19.0126065942 2014-04-08 23:50:00,18.287621179400002 2014-04-08 23:55:00,19.9736032372 2014-04-09 00:00:00,18.3418640919 2014-04-09 00:05:00,19.047160004400002 2014-04-09 00:10:00,18.503911443299998 2014-04-09 00:15:00,18.8965287186 2014-04-09 00:20:00,18.4245786113 2014-04-09 00:25:00,21.8156239977 2014-04-09 00:30:00,19.1142508538 2014-04-09 00:35:00,19.775590344 2014-04-09 00:40:00,21.594447230500002 2014-04-09 00:45:00,20.7092863518 2014-04-09 00:50:00,20.4721499222 2014-04-09 00:55:00,20.8222527614 2014-04-09 01:00:00,21.3152890284 2014-04-09 01:05:00,21.5106770714 2014-04-09 01:10:00,20.5705586827 2014-04-09 01:15:00,21.5600290988 2014-04-09 01:20:00,20.1415901097 2014-04-09 01:25:00,19.1091634251 2014-04-09 01:30:00,21.5203068355 2014-04-09 01:35:00,20.1658913097 2014-04-09 01:40:00,21.6245503503 2014-04-09 01:45:00,18.1606712558 2014-04-09 01:50:00,19.590063006199998 2014-04-09 01:55:00,21.7912200734 2014-04-09 02:00:00,18.998600371 2014-04-09 02:05:00,21.7661449842 2014-04-09 02:10:00,21.8156098445 2014-04-09 02:15:00,21.5285692569 2014-04-09 02:20:00,20.2546721804 2014-04-09 02:25:00,20.5877577963 2014-04-09 02:30:00,21.478467993800002 2014-04-09 02:35:00,21.1035883296 2014-04-09 02:40:00,20.5203753978 2014-04-09 02:45:00,21.9290376315 2014-04-09 02:50:00,20.7427065453 2014-04-09 02:55:00,21.9019279698 2014-04-09 03:00:00,18.2295538984 2014-04-09 03:05:00,18.555841483 2014-04-09 03:10:00,19.805835384 2014-04-09 03:15:00,19.5395178435 2014-04-09 03:20:00,21.1309393654 2014-04-09 03:25:00,18.6424561059 2014-04-09 03:30:00,21.9043807164 2014-04-09 03:35:00,19.260263501 2014-04-09 03:40:00,19.715694831 2014-04-09 03:45:00,19.0989801298 2014-04-09 03:50:00,20.3174544693 2014-04-09 03:55:00,18.2345148017 2014-04-09 04:00:00,18.5987100223 2014-04-09 04:05:00,20.9831908137 2014-04-09 04:10:00,18.7460023336 2014-04-09 04:15:00,18.942057806199998 2014-04-09 04:20:00,21.1719289429 2014-04-09 04:25:00,18.3732047134 2014-04-09 04:30:00,19.7498952911 2014-04-09 04:35:00,18.092253548 2014-04-09 04:40:00,19.3872295973 2014-04-09 04:45:00,20.7959256104 2014-04-09 04:50:00,18.360413118900002 2014-04-09 04:55:00,21.5533385071 2014-04-09 05:00:00,21.637996171799998 2014-04-09 05:05:00,18.4199615005 2014-04-09 05:10:00,21.962929745500002 2014-04-09 05:15:00,19.190118213599998 2014-04-09 05:20:00,18.3364066845 2014-04-09 05:25:00,18.020268458 2014-04-09 05:30:00,19.6340915831 2014-04-09 05:35:00,20.5192399428 2014-04-09 05:40:00,19.3287169996 2014-04-09 05:45:00,21.3468694619 2014-04-09 05:50:00,20.8664251023 2014-04-09 05:55:00,19.4006461279 2014-04-09 06:00:00,20.937238666400003 2014-04-09 06:05:00,21.7619509479 2014-04-09 06:10:00,18.3723839942 2014-04-09 06:15:00,19.2244158406 2014-04-09 06:20:00,19.8533037565 2014-04-09 06:25:00,19.991960511 2014-04-09 06:30:00,20.1687825795 2014-04-09 06:35:00,19.2025076262 2014-04-09 06:40:00,20.6690385839 2014-04-09 06:45:00,20.5803380141 2014-04-09 06:50:00,20.3112860251 2014-04-09 06:55:00,18.4550468868 2014-04-09 07:00:00,19.9078715644 2014-04-09 07:05:00,19.42490755 2014-04-09 07:10:00,19.9641538794 2014-04-09 07:15:00,21.6874657421 2014-04-09 07:20:00,19.9221253726 2014-04-09 07:25:00,18.0559231674 2014-04-09 07:30:00,19.755346952300002 2014-04-09 07:35:00,21.2825927202 2014-04-09 07:40:00,21.1202436929 2014-04-09 07:45:00,20.053560294100002 2014-04-09 07:50:00,18.9990760514 2014-04-09 07:55:00,19.8603546517 2014-04-09 08:00:00,20.2548088777 2014-04-09 08:05:00,21.9994857531 2014-04-09 08:10:00,20.5767123607 2014-04-09 08:15:00,20.7770597203 2014-04-09 08:20:00,19.9658165743 2014-04-09 08:25:00,19.4179582031 2014-04-09 08:30:00,21.2518119346 2014-04-09 08:35:00,19.9797292974 2014-04-09 08:40:00,21.978760519899996 2014-04-09 08:45:00,19.8284822971 2014-04-09 08:50:00,18.2720011346 2014-04-09 08:55:00,20.7303125484 2014-04-09 09:00:00,61.83432373260001 2014-04-09 09:05:00,64.6068217176 2014-04-09 09:10:00,66.0108402378 2014-04-09 09:15:00,71.2569767645 2014-04-09 09:20:00,67.9216085991 2014-04-09 09:25:00,61.5895846658 2014-04-09 09:30:00,69.58915797739999 2014-04-09 09:35:00,66.795532829 2014-04-09 09:40:00,73.7369493356 2014-04-09 09:45:00,67.9940474315 2014-04-09 09:50:00,70.8420619848 2014-04-09 09:55:00,64.1766114957 2014-04-09 10:00:00,81.6503097215 2014-04-09 10:05:00,81.0292264187 2014-04-09 10:10:00,83.8713481166 2014-04-09 10:15:00,70.3649118795 2014-04-09 10:20:00,76.785210827 2014-04-09 10:25:00,80.38049185050001 2014-04-09 10:30:00,71.3169437292 2014-04-09 10:35:00,76.21257512220001 2014-04-09 10:40:00,84.4621152796 2014-04-09 10:45:00,76.60570329859999 2014-04-09 10:50:00,85.1334822396 2014-04-09 10:55:00,70.722142228 2014-04-09 11:00:00,82.9843647597 2014-04-09 11:05:00,80.8084822213 2014-04-09 11:10:00,79.5285830251 2014-04-09 11:15:00,87.0083570732 2014-04-09 11:20:00,73.62995996939999 2014-04-09 11:25:00,85.8179673275 2014-04-09 11:30:00,82.5614874987 2014-04-09 11:35:00,75.68707354979999 2014-04-09 11:40:00,85.9081460921 2014-04-09 11:45:00,78.3955063737 2014-04-09 11:50:00,84.5174714257 2014-04-09 11:55:00,77.7520559671 2014-04-09 12:00:00,85.51215536699999 2014-04-09 12:05:00,82.087442616 2014-04-09 12:10:00,74.167638042 2014-04-09 12:15:00,82.2957370828 2014-04-09 12:20:00,74.9714423838 2014-04-09 12:25:00,78.4964531319 2014-04-09 12:30:00,74.6350596728 2014-04-09 12:35:00,72.2654351413 2014-04-09 12:40:00,75.2997164096 2014-04-09 12:45:00,80.4852540367 2014-04-09 12:50:00,79.60932951390001 2014-04-09 12:55:00,79.9279247843 2014-04-09 13:00:00,75.9447589375 2014-04-09 13:05:00,82.9426681908 2014-04-09 13:10:00,83.24822821810001 2014-04-09 13:15:00,77.7088306125 2014-04-09 13:20:00,86.0780577224 2014-04-09 13:25:00,82.284618417 2014-04-09 13:30:00,83.3886103333 2014-04-09 13:35:00,76.4190937017 2014-04-09 13:40:00,71.9925038138 2014-04-09 13:45:00,85.82540675130002 2014-04-09 13:50:00,85.1383520436 2014-04-09 13:55:00,73.95331715180001 2014-04-09 14:00:00,77.9819388466 2014-04-09 14:05:00,82.5774650256 2014-04-09 14:10:00,82.42981689439999 2014-04-09 14:15:00,85.7614886079 2014-04-09 14:20:00,74.2407268602 2014-04-09 14:25:00,78.8752497708 2014-04-09 14:30:00,73.5520600185 2014-04-09 14:35:00,78.2297687659 2014-04-09 14:40:00,72.2382515269 2014-04-09 14:45:00,86.36822316799999 2014-04-09 14:50:00,80.42884317949999 2014-04-09 14:55:00,85.59272752470001 2014-04-09 15:00:00,72.9577748147 2014-04-09 15:05:00,75.63860363 2014-04-09 15:10:00,76.1493488828 2014-04-09 15:15:00,78.1863133184 2014-04-09 15:20:00,84.84504743810001 2014-04-09 15:25:00,78.1841754044 2014-04-09 15:30:00,75.2737338396 2014-04-09 15:35:00,73.0391429829 2014-04-09 15:40:00,73.2711645637 2014-04-09 15:45:00,84.1599473521 2014-04-09 15:50:00,79.1160883348 2014-04-09 15:55:00,83.6180952106 2014-04-09 16:00:00,82.91643474840001 2014-04-09 16:05:00,74.1656569898 2014-04-09 16:10:00,74.28606431760001 2014-04-09 16:15:00,84.0853108028 2014-04-09 16:20:00,83.5401322984 2014-04-09 16:25:00,78.0483424169 2014-04-09 16:30:00,73.2386155949 2014-04-09 16:35:00,72.1934297355 2014-04-09 16:40:00,76.6103640992 2014-04-09 16:45:00,72.1474178541 2014-04-09 16:50:00,75.6810166298 2014-04-09 16:55:00,78.7118607163 2014-04-09 17:00:00,73.94262385100001 2014-04-09 17:05:00,73.6684158366 2014-04-09 17:10:00,86.3429658158 2014-04-09 17:15:00,81.3674892192 2014-04-09 17:20:00,86.9512575989 2014-04-09 17:25:00,77.53318884779999 2014-04-09 17:30:00,82.8342871889 2014-04-09 17:35:00,75.2750378883 2014-04-09 17:40:00,81.8934136294 2014-04-09 17:45:00,74.073343236 2014-04-09 17:50:00,72.033262566 2014-04-09 17:55:00,86.90447545120001 2014-04-09 18:00:00,32.3513177961 2014-04-09 18:05:00,34.7324135732 2014-04-09 18:10:00,30.9365158119 2014-04-09 18:15:00,30.897824910300002 2014-04-09 18:20:00,31.3641859894 2014-04-09 18:25:00,33.318655900100005 2014-04-09 18:30:00,32.4211690339 2014-04-09 18:35:00,34.7222647388 2014-04-09 18:40:00,28.9628162064 2014-04-09 18:45:00,33.3324476032 2014-04-09 18:50:00,30.914091276399997 2014-04-09 18:55:00,29.9534896206 2014-04-09 19:00:00,22.4465711575 2014-04-09 19:05:00,22.4226845231 2014-04-09 19:10:00,20.7738082689 2014-04-09 19:15:00,21.064493175899997 2014-04-09 19:20:00,21.9885764925 2014-04-09 19:25:00,21.991473921100006 2014-04-09 19:30:00,21.5826592815 2014-04-09 19:35:00,20.825481136300002 2014-04-09 19:40:00,20.1795929754 2014-04-09 19:45:00,24.506651735300004 2014-04-09 19:50:00,24.3868752113 2014-04-09 19:55:00,22.326752473899997 2014-04-09 20:00:00,22.5077317113 2014-04-09 20:05:00,21.1912878846 2014-04-09 20:10:00,18.714040249500002 2014-04-09 20:15:00,18.9141735165 2014-04-09 20:20:00,22.184389750300003 2014-04-09 20:25:00,21.0126935679 2014-04-09 20:30:00,21.885679872199997 2014-04-09 20:35:00,22.111312219600002 2014-04-09 20:40:00,20.266770235 2014-04-09 20:45:00,18.6307620741 2014-04-09 20:50:00,19.203196078599998 2014-04-09 20:55:00,18.7046784717 2014-04-09 21:00:00,18.844983141700002 2014-04-09 21:05:00,19.7364138897 2014-04-09 21:10:00,18.5614565754 2014-04-09 21:15:00,18.756534223699997 2014-04-09 21:20:00,19.8782468579 2014-04-09 21:25:00,19.4536150362 2014-04-09 21:30:00,19.9660114839 2014-04-09 21:35:00,19.8113281655 2014-04-09 21:40:00,20.676686031400003 2014-04-09 21:45:00,21.8531521814 2014-04-09 21:50:00,18.5199283038 2014-04-09 21:55:00,18.485346346900002 2014-04-09 22:00:00,21.4317792093 2014-04-09 22:05:00,20.0448113721 2014-04-09 22:10:00,21.0858430792 2014-04-09 22:15:00,18.8797948253 2014-04-09 22:20:00,21.335913114500002 2014-04-09 22:25:00,21.7162140571 2014-04-09 22:30:00,20.5616523069 2014-04-09 22:35:00,18.4412026523 2014-04-09 22:40:00,21.6018971781 2014-04-09 22:45:00,21.1902740519 2014-04-09 22:50:00,21.023674466400003 2014-04-09 22:55:00,18.1643337829 2014-04-09 23:00:00,21.1999197022 2014-04-09 23:05:00,18.555365986400002 2014-04-09 23:10:00,18.8931714955 2014-04-09 23:15:00,20.312438577 2014-04-09 23:20:00,19.063582595 2014-04-09 23:25:00,20.649356738599998 2014-04-09 23:30:00,20.4362047869 2014-04-09 23:35:00,18.436137449100002 2014-04-09 23:40:00,20.6280181355 2014-04-09 23:45:00,21.699985234499998 2014-04-09 23:50:00,18.6480193513 2014-04-09 23:55:00,20.3921626254 2014-04-10 00:00:00,19.367461487699998 2014-04-10 00:05:00,19.8384466871 2014-04-10 00:10:00,19.1480007163 2014-04-10 00:15:00,19.4165225454 2014-04-10 00:20:00,18.1156472931 2014-04-10 00:25:00,21.9262069517 2014-04-10 00:30:00,20.4991996883 2014-04-10 00:35:00,20.002822362 2014-04-10 00:40:00,19.534861398 2014-04-10 00:45:00,20.1574982353 2014-04-10 00:50:00,19.5204239949 2014-04-10 00:55:00,19.43963171 2014-04-10 01:00:00,19.8557861669 2014-04-10 01:05:00,19.1039321347 2014-04-10 01:10:00,18.7201995999 2014-04-10 01:15:00,20.2264235927 2014-04-10 01:20:00,21.3710617446 2014-04-10 01:25:00,18.6113127109 2014-04-10 01:30:00,18.1309373624 2014-04-10 01:35:00,18.9872469806 2014-04-10 01:40:00,21.9188825738 2014-04-10 01:45:00,21.315032295 2014-04-10 01:50:00,20.3834642141 2014-04-10 01:55:00,21.716995661 2014-04-10 02:00:00,19.7811164673 2014-04-10 02:05:00,21.9331224103 2014-04-10 02:10:00,19.1852081805 2014-04-10 02:15:00,18.9612229981 2014-04-10 02:20:00,20.5521928046 2014-04-10 02:25:00,19.5126158718 2014-04-10 02:30:00,20.5054621679 2014-04-10 02:35:00,19.2199820732 2014-04-10 02:40:00,20.4716730274 2014-04-10 02:45:00,19.1029850423 2014-04-10 02:50:00,18.2038882753 2014-04-10 02:55:00,21.6485436077 2014-04-10 03:00:00,21.5328208075 2014-04-10 03:05:00,21.8831925971 2014-04-10 03:10:00,20.8661087049 2014-04-10 03:15:00,20.7308847109 2014-04-10 03:20:00,20.2360122803 2014-04-10 03:25:00,18.5037696654 2014-04-10 03:30:00,18.7569412438 2014-04-10 03:35:00,19.1578787547 2014-04-10 03:40:00,21.5606254503 2014-04-10 03:45:00,18.6918780984 2014-04-10 03:50:00,21.691492698 2014-04-10 03:55:00,20.0911429322 2014-04-10 04:00:00,20.8622785419 2014-04-10 04:05:00,18.440977946700002 2014-04-10 04:10:00,19.0761341951 2014-04-10 04:15:00,21.8340744327 2014-04-10 04:20:00,19.0645997877 2014-04-10 04:25:00,19.1860868816 2014-04-10 04:30:00,18.7903895394 2014-04-10 04:35:00,18.5162946612 2014-04-10 04:40:00,18.9330305658 2014-04-10 04:45:00,20.5693075678 2014-04-10 04:50:00,19.821470934 2014-04-10 04:55:00,20.2150233454 2014-04-10 05:00:00,18.4894593151 2014-04-10 05:05:00,21.2084657887 2014-04-10 05:10:00,21.1363788023 2014-04-10 05:15:00,18.0863596446 2014-04-10 05:20:00,19.534060378 2014-04-10 05:25:00,18.2750824079 2014-04-10 05:30:00,21.1684231177 2014-04-10 05:35:00,20.9490787325 2014-04-10 05:40:00,21.607952377199997 2014-04-10 05:45:00,18.945615835799998 2014-04-10 05:50:00,19.8251835325 2014-04-10 05:55:00,18.7379515087 2014-04-10 06:00:00,19.4849397379 2014-04-10 06:05:00,20.0889730063 2014-04-10 06:10:00,18.2133231594 2014-04-10 06:15:00,20.8594816427 2014-04-10 06:20:00,20.1731734415 2014-04-10 06:25:00,21.3158360688 2014-04-10 06:30:00,19.0871220048 2014-04-10 06:35:00,21.6132844211 2014-04-10 06:40:00,21.994777012100002 2014-04-10 06:45:00,21.6771937535 2014-04-10 06:50:00,21.111569903299998 2014-04-10 06:55:00,21.249475211500002 2014-04-10 07:00:00,20.2949769702 2014-04-10 07:05:00,18.7606154517 2014-04-10 07:10:00,20.7081627406 2014-04-10 07:15:00,20.851012008199998 2014-04-10 07:20:00,21.941540561100002 2014-04-10 07:25:00,20.165205265 2014-04-10 07:30:00,19.0854760601 2014-04-10 07:35:00,20.734690087 2014-04-10 07:40:00,21.9175032787 2014-04-10 07:45:00,18.7088556331 2014-04-10 07:50:00,19.3039916741 2014-04-10 07:55:00,20.1675238151 2014-04-10 08:00:00,18.6808585395 2014-04-10 08:05:00,18.0888825581 2014-04-10 08:10:00,19.3479324898 2014-04-10 08:15:00,21.461483206 2014-04-10 08:20:00,18.173873597300002 2014-04-10 08:25:00,19.7157162361 2014-04-10 08:30:00,21.0488030917 2014-04-10 08:35:00,21.812730387600002 2014-04-10 08:40:00,21.941901595999997 2014-04-10 08:45:00,19.6878775224 2014-04-10 08:50:00,21.8015371775 2014-04-10 08:55:00,18.1416758931 2014-04-10 09:00:00,71.3444703568 2014-04-10 09:05:00,69.941346071 2014-04-10 09:10:00,64.59349726319999 2014-04-10 09:15:00,68.0995316092 2014-04-10 09:20:00,62.961930833500006 2014-04-10 09:25:00,73.0537212529 2014-04-10 09:30:00,66.0674139634 2014-04-10 09:35:00,69.7142047983 2014-04-10 09:40:00,63.359357493500006 2014-04-10 09:45:00,64.003841887 2014-04-10 09:50:00,74.6906066429 2014-04-10 09:55:00,71.44197496439999 2014-04-10 10:00:00,84.7698034189 2014-04-10 10:05:00,74.4316100841 2014-04-10 10:10:00,72.3940158451 2014-04-10 10:15:00,77.6476225532 2014-04-10 10:20:00,77.51725174020001 2014-04-10 10:25:00,72.55516989350001 2014-04-10 10:30:00,81.2195677199 2014-04-10 10:35:00,75.4547873345 2014-04-10 10:40:00,72.73238838399999 2014-04-10 10:45:00,74.9923822833 2014-04-10 10:50:00,78.5879830183 2014-04-10 10:55:00,81.11482886739999 2014-04-10 11:00:00,79.2319926519 2014-04-10 11:05:00,79.92706271819999 2014-04-10 11:10:00,73.7777961652 2014-04-10 11:15:00,86.1152444666 2014-04-10 11:20:00,86.3384296449 2014-04-10 11:25:00,82.437216494 2014-04-10 11:30:00,71.8484099277 2014-04-10 11:35:00,80.1096283297 2014-04-10 11:40:00,81.5750985321 2014-04-10 11:45:00,87.3869807619 2014-04-10 11:50:00,87.40944885540002 2014-04-10 11:55:00,85.2074490866 2014-04-10 12:00:00,72.9336703174 2014-04-10 12:05:00,87.1477193458 2014-04-10 12:10:00,81.70441685850001 2014-04-10 12:15:00,84.7124113017 2014-04-10 12:20:00,78.42086749229999 2014-04-10 12:25:00,77.0221738859 2014-04-10 12:30:00,79.3166120401 2014-04-10 12:35:00,74.2607722169 2014-04-10 12:40:00,77.6198025502 2014-04-10 12:45:00,85.61901374029999 2014-04-10 12:50:00,72.5200791308 2014-04-10 12:55:00,74.3247518907 2014-04-10 13:00:00,73.9840981083 2014-04-10 13:05:00,78.4303808731 2014-04-10 13:10:00,87.93068198459999 2014-04-10 13:15:00,74.7557811889 2014-04-10 13:20:00,74.30988374020001 2014-04-10 13:25:00,86.6200978624 2014-04-10 13:30:00,86.0921411975 2014-04-10 13:35:00,72.4984421169 2014-04-10 13:40:00,84.007128812 2014-04-10 13:45:00,82.4676542353 2014-04-10 13:50:00,84.26362483289998 2014-04-10 13:55:00,79.89286038729999 2014-04-10 14:00:00,87.8578501159 2014-04-10 14:05:00,72.6980626249 2014-04-10 14:10:00,75.7463093851 2014-04-10 14:15:00,78.3409752443 2014-04-10 14:20:00,79.1926456356 2014-04-10 14:25:00,86.737714833 2014-04-10 14:30:00,80.95618374189999 2014-04-10 14:35:00,72.7182852831 2014-04-10 14:40:00,78.5220381761 2014-04-10 14:45:00,78.6600707333 2014-04-10 14:50:00,87.443657518 2014-04-10 14:55:00,81.58323727300001 2014-04-10 15:00:00,82.1696283025 2014-04-10 15:05:00,83.4112477444 2014-04-10 15:10:00,84.3198195729 2014-04-10 15:15:00,82.16002837939999 2014-04-10 15:20:00,75.7943819851 2014-04-10 15:25:00,85.983909176 2014-04-10 15:30:00,83.71311315300001 2014-04-10 15:35:00,83.86912261020001 2014-04-10 15:40:00,87.9440635566 2014-04-10 15:45:00,84.8396100897 2014-04-10 15:50:00,85.2656038928 2014-04-10 15:55:00,87.22165091549999 2014-04-10 16:00:00,74.4180011147 2014-04-10 16:05:00,79.9634844935 2014-04-10 16:10:00,81.2889163024 2014-04-10 16:15:00,77.2682633122 2014-04-10 16:20:00,85.4302894758 2014-04-10 16:25:00,84.1985522848 2014-04-10 16:30:00,83.5339688066 2014-04-10 16:35:00,87.95422216370001 2014-04-10 16:40:00,76.1499557663 2014-04-10 16:45:00,83.76715519359999 2014-04-10 16:50:00,80.82231641930001 2014-04-10 16:55:00,77.0076790649 2014-04-10 17:00:00,74.5693612969 2014-04-10 17:05:00,86.3341082408 2014-04-10 17:10:00,81.5272564168 2014-04-10 17:15:00,85.19890868590001 2014-04-10 17:20:00,80.7254887454 2014-04-10 17:25:00,75.5196042909 2014-04-10 17:30:00,77.4007512877 2014-04-10 17:35:00,78.1045914874 2014-04-10 17:40:00,87.5669233743 2014-04-10 17:45:00,72.0901047715 2014-04-10 17:50:00,87.77062266450001 2014-04-10 17:55:00,87.68735248979998 2014-04-10 18:00:00,35.1753583057 2014-04-10 18:05:00,31.850158229899996 2014-04-10 18:10:00,34.9683706916 2014-04-10 18:15:00,31.331828748099998 2014-04-10 18:20:00,28.9682788584 2014-04-10 18:25:00,30.2358161875 2014-04-10 18:30:00,34.8498892764 2014-04-10 18:35:00,28.888088490799998 2014-04-10 18:40:00,32.2943562662 2014-04-10 18:45:00,29.283844546399997 2014-04-10 18:50:00,30.6329322204 2014-04-10 18:55:00,29.363788606700002 2014-04-10 19:00:00,24.0106869054 2014-04-10 19:05:00,22.807995528000003 2014-04-10 19:10:00,24.2014356388 2014-04-10 19:15:00,23.2438210589 2014-04-10 19:20:00,24.510209163400003 2014-04-10 19:25:00,22.4442506621 2014-04-10 19:30:00,23.021422143400002 2014-04-10 19:35:00,22.741862265500004 2014-04-10 19:40:00,22.329485499 2014-04-10 19:45:00,23.9498966433 2014-04-10 19:50:00,23.0474713435 2014-04-10 19:55:00,23.7498776437 2014-04-10 20:00:00,21.652946424499998 2014-04-10 20:05:00,19.2145207475 2014-04-10 20:10:00,21.0950695761 2014-04-10 20:15:00,19.2497580556 2014-04-10 20:20:00,20.821280429 2014-04-10 20:25:00,21.206772213 2014-04-10 20:30:00,22.516674583 2014-04-10 20:35:00,18.5570997198 2014-04-10 20:40:00,18.8057286206 2014-04-10 20:45:00,18.7475011234 2014-04-10 20:50:00,20.0636875878 2014-04-10 20:55:00,21.7972256671 2014-04-10 21:00:00,21.4788311602 2014-04-10 21:05:00,21.0484683396 2014-04-10 21:10:00,21.6911329765 2014-04-10 21:15:00,19.3840386402 2014-04-10 21:20:00,18.4407111011 2014-04-10 21:25:00,18.3201286053 2014-04-10 21:30:00,21.5112917741 2014-04-10 21:35:00,21.0221695028 2014-04-10 21:40:00,20.8942745868 2014-04-10 21:45:00,19.4516270923 2014-04-10 21:50:00,19.6133148861 2014-04-10 21:55:00,21.9372498417 2014-04-10 22:00:00,18.2727439776 2014-04-10 22:05:00,21.1151780673 2014-04-10 22:10:00,19.2570022773 2014-04-10 22:15:00,18.173648434500002 2014-04-10 22:20:00,20.9904119019 2014-04-10 22:25:00,19.3421982349 2014-04-10 22:30:00,20.9086431112 2014-04-10 22:35:00,20.8506149151 2014-04-10 22:40:00,20.1584810734 2014-04-10 22:45:00,21.1297576193 2014-04-10 22:50:00,20.343664473900002 2014-04-10 22:55:00,19.1649280875 2014-04-10 23:00:00,20.9404810028 2014-04-10 23:05:00,20.3604677209 2014-04-10 23:10:00,18.0543748995 2014-04-10 23:15:00,21.6107251717 2014-04-10 23:20:00,20.1864495256 2014-04-10 23:25:00,21.478632165500002 2014-04-10 23:30:00,21.535081295700003 2014-04-10 23:35:00,19.7836643594 2014-04-10 23:40:00,20.034485866700003 2014-04-10 23:45:00,19.6667928481 2014-04-10 23:50:00,19.8015482667 2014-04-10 23:55:00,21.584732106799997 2014-04-11 00:00:00,21.1525760559 2014-04-11 00:05:00,18.5061027053 2014-04-11 00:10:00,20.441231126199998 2014-04-11 00:15:00,21.9836265615 2014-04-11 00:20:00,20.3822028049 2014-04-11 00:25:00,21.143486502400002 2014-04-11 00:30:00,21.076245893499998 2014-04-11 00:35:00,19.4012701035 2014-04-11 00:40:00,19.487397210799998 2014-04-11 00:45:00,20.8963056872 2014-04-11 00:50:00,19.9999341264 2014-04-11 00:55:00,20.282282836500002 2014-04-11 01:00:00,20.8516231615 2014-04-11 01:05:00,21.1103001082 2014-04-11 01:10:00,19.086066310899998 2014-04-11 01:15:00,18.5871750377 2014-04-11 01:20:00,19.1671785869 2014-04-11 01:25:00,20.0301533004 2014-04-11 01:30:00,19.3685652692 2014-04-11 01:35:00,20.2734510354 2014-04-11 01:40:00,18.2138628965 2014-04-11 01:45:00,20.0390016465 2014-04-11 01:50:00,19.4719396278 2014-04-11 01:55:00,20.1386670196 2014-04-11 02:00:00,19.6901334195 2014-04-11 02:05:00,19.1369034026 2014-04-11 02:10:00,21.616431621799997 2014-04-11 02:15:00,18.7390599537 2014-04-11 02:20:00,20.7254623023 2014-04-11 02:25:00,21.698578850300002 2014-04-11 02:30:00,20.154679838699998 2014-04-11 02:35:00,21.5056339543 2014-04-11 02:40:00,18.4994059137 2014-04-11 02:45:00,19.975155081 2014-04-11 02:50:00,19.8281011219 2014-04-11 02:55:00,18.0324752281 2014-04-11 03:00:00,19.7730293654 2014-04-11 03:05:00,19.4761190255 2014-04-11 03:10:00,20.679194911099998 2014-04-11 03:15:00,21.753319114299998 2014-04-11 03:20:00,18.343164353 2014-04-11 03:25:00,19.3099055469 2014-04-11 03:30:00,19.7762589496 2014-04-11 03:35:00,19.8207415121 2014-04-11 03:40:00,21.099238883399998 2014-04-11 03:45:00,19.7735826633 2014-04-11 03:50:00,18.1086452058 2014-04-11 03:55:00,20.8404163784 2014-04-11 04:00:00,21.5393187806 2014-04-11 04:05:00,20.0556188502 2014-04-11 04:10:00,20.3244340868 2014-04-11 04:15:00,18.6517457559 2014-04-11 04:20:00,18.8825837787 2014-04-11 04:25:00,18.9406809565 2014-04-11 04:30:00,19.722967899500002 2014-04-11 04:35:00,21.7125808836 2014-04-11 04:40:00,20.0871390669 2014-04-11 04:45:00,18.7683905808 2014-04-11 04:50:00,19.0643509435 2014-04-11 04:55:00,19.5360601189 2014-04-11 05:00:00,20.4930359028 2014-04-11 05:05:00,19.760132612 2014-04-11 05:10:00,19.5697793767 2014-04-11 05:15:00,20.258914401600002 2014-04-11 05:20:00,18.9673399798 2014-04-11 05:25:00,18.3156130903 2014-04-11 05:30:00,18.0976572593 2014-04-11 05:35:00,19.0050366539 2014-04-11 05:40:00,18.366368136600002 2014-04-11 05:45:00,19.3453625541 2014-04-11 05:50:00,21.0917341614 2014-04-11 05:55:00,20.8651773219 2014-04-11 06:00:00,20.443710491199997 2014-04-11 06:05:00,21.4100009755 2014-04-11 06:10:00,19.1282704982 2014-04-11 06:15:00,21.5402150121 2014-04-11 06:20:00,19.5969566787 2014-04-11 06:25:00,19.6035732731 2014-04-11 06:30:00,19.6214064545 2014-04-11 06:35:00,18.392377465 2014-04-11 06:40:00,21.9019619933 2014-04-11 06:45:00,18.5540271113 2014-04-11 06:50:00,19.3635428979 2014-04-11 06:55:00,19.2772012813 2014-04-11 07:00:00,18.298717731300002 2014-04-11 07:05:00,18.6090405204 2014-04-11 07:10:00,18.1794333447 2014-04-11 07:15:00,19.1696179742 2014-04-11 07:20:00,21.466627696099998 2014-04-11 07:25:00,19.3577688229 2014-04-11 07:30:00,18.4947673283 2014-04-11 07:35:00,20.5827754735 2014-04-11 07:40:00,21.986403648200003 2014-04-11 07:45:00,18.9292951581 2014-04-11 07:50:00,19.118284021500003 2014-04-11 07:55:00,21.8873882171 2014-04-11 08:00:00,18.7151051502 2014-04-11 08:05:00,20.0448562698 2014-04-11 08:10:00,18.9586085321 2014-04-11 08:15:00,21.729407591599998 2014-04-11 08:20:00,21.9260840583 2014-04-11 08:25:00,21.2587913845 2014-04-11 08:30:00,19.2591352633 2014-04-11 08:35:00,19.6139499011 2014-04-11 08:40:00,18.9692227347 2014-04-11 08:45:00,21.563031868000003 2014-04-11 08:50:00,21.658233110799998 2014-04-11 08:55:00,19.675482649 2014-04-11 09:00:00,127.882020134 2014-04-11 09:05:00,115.705718858 2014-04-11 09:10:00,122.386410329 2014-04-11 09:15:00,127.26117784600001 2014-04-11 09:20:00,121.15799733899999 2014-04-11 09:25:00,120.46846823700001 2014-04-11 09:30:00,111.62477500799999 2014-04-11 09:35:00,131.54647790200002 2014-04-11 09:40:00,133.655572778 2014-04-11 09:45:00,135.642695533 2014-04-11 09:50:00,129.43793035 2014-04-11 09:55:00,125.21004934700001 2014-04-11 10:00:00,138.118479694 2014-04-11 10:05:00,159.259712824 2014-04-11 10:10:00,147.399242667 2014-04-11 10:15:00,150.046221935 2014-04-11 10:20:00,150.08248245 2014-04-11 10:25:00,154.798492005 2014-04-11 10:30:00,130.600116725 2014-04-11 10:35:00,136.698351395 2014-04-11 10:40:00,149.593864645 2014-04-11 10:45:00,156.24342053799998 2014-04-11 10:50:00,150.16741112399998 2014-04-11 10:55:00,142.294707802 2014-04-11 11:00:00,144.83546133299998 2014-04-11 11:05:00,156.04894706299999 2014-04-11 11:10:00,156.146953473 2014-04-11 11:15:00,152.149471713 2014-04-11 11:20:00,142.74738558200002 2014-04-11 11:25:00,161.62621235 2014-04-11 11:30:00,150.505607236 2014-04-11 11:35:00,157.614348277 2014-04-11 11:40:00,140.448671746 2014-04-11 11:45:00,144.313663174 2014-04-11 11:50:00,160.119472952 2014-04-11 11:55:00,135.556788636 2014-04-11 12:00:00,150.160947021 2014-04-11 12:05:00,149.243925447 2014-04-11 12:10:00,157.318454491 2014-04-11 12:15:00,143.257886337 2014-04-11 12:20:00,141.37569147600001 2014-04-11 12:25:00,162.558258037 2014-04-11 12:30:00,151.940306437 2014-04-11 12:35:00,137.949131962 2014-04-11 12:40:00,140.595854562 2014-04-11 12:45:00,164.736030621 2014-04-11 12:50:00,140.67293255299998 2014-04-11 12:55:00,153.101669559 2014-04-11 13:00:00,147.562906904 2014-04-11 13:05:00,161.523164661 2014-04-11 13:10:00,157.611334766 2014-04-11 13:15:00,152.86613525200002 2014-04-11 13:20:00,135.284640106 2014-04-11 13:25:00,161.349096329 2014-04-11 13:30:00,148.298884492 2014-04-11 13:35:00,162.902138864 2014-04-11 13:40:00,149.824607501 2014-04-11 13:45:00,155.783518728 2014-04-11 13:50:00,137.04076296899999 2014-04-11 13:55:00,157.310909944 2014-04-11 14:00:00,145.131830514 2014-04-11 14:05:00,145.532697769 2014-04-11 14:10:00,138.551989898 2014-04-11 14:15:00,139.397982089 2014-04-11 14:20:00,140.56497458299998 2014-04-11 14:25:00,144.838150922 2014-04-11 14:30:00,161.750125145 2014-04-11 14:35:00,146.039706362 2014-04-11 14:40:00,156.722187857 2014-04-11 14:45:00,137.474799425 2014-04-11 14:50:00,152.72449239 2014-04-11 14:55:00,149.448447071 2014-04-11 15:00:00,164.336915344 2014-04-11 15:05:00,160.384453878 2014-04-11 15:10:00,148.643244206 2014-04-11 15:15:00,158.252527354 2014-04-11 15:20:00,140.789600396 2014-04-11 15:25:00,151.86840507600002 2014-04-11 15:30:00,137.23704923399998 2014-04-11 15:35:00,145.441057524 2014-04-11 15:40:00,141.774292682 2014-04-11 15:45:00,156.56555760700002 2014-04-11 15:50:00,149.701060034 2014-04-11 15:55:00,157.530366809 2014-04-11 16:00:00,150.458529311 2014-04-11 16:05:00,137.594227988 2014-04-11 16:10:00,157.060681026 2014-04-11 16:15:00,159.99652294 2014-04-11 16:20:00,162.10557711799999 2014-04-11 16:25:00,152.159420767 2014-04-11 16:30:00,157.607211091 2014-04-11 16:35:00,157.56098053 2014-04-11 16:40:00,139.672182907 2014-04-11 16:45:00,139.926310173 2014-04-11 16:50:00,137.126260936 2014-04-11 16:55:00,144.597088241 2014-04-11 17:00:00,149.205191425 2014-04-11 17:05:00,164.936862395 2014-04-11 17:10:00,147.929734621 2014-04-11 17:15:00,156.787208083 2014-04-11 17:20:00,155.801841654 2014-04-11 17:25:00,141.134395882 2014-04-11 17:30:00,136.755153861 2014-04-11 17:35:00,151.380135374 2014-04-11 17:40:00,156.009098543 2014-04-11 17:45:00,164.947480513 2014-04-11 17:50:00,145.758266891 2014-04-11 17:55:00,161.890865026 2014-04-11 18:00:00,44.9137655963 2014-04-11 18:05:00,47.7425739013 2014-04-11 18:10:00,46.9039133872 2014-04-11 18:15:00,41.8873927765 2014-04-11 18:20:00,42.121161338600004 2014-04-11 18:25:00,41.5910175894 2014-04-11 18:30:00,44.81166061020001 2014-04-11 18:35:00,48.26135568220001 2014-04-11 18:40:00,42.98933718399999 2014-04-11 18:45:00,46.973833715299996 2014-04-11 18:50:00,44.057202826499996 2014-04-11 18:55:00,48.7323180379 2014-04-11 19:00:00,26.703913769699998 2014-04-11 19:05:00,26.588086346399997 2014-04-11 19:10:00,25.325158233899998 2014-04-11 19:15:00,24.1142136711 2014-04-11 19:20:00,26.759595154 2014-04-11 19:25:00,23.6179443369 2014-04-11 19:30:00,24.1403858438 2014-04-11 19:35:00,23.607093944899997 2014-04-11 19:40:00,26.0780164532 2014-04-11 19:45:00,26.1386268201 2014-04-11 19:50:00,25.96864762 2014-04-11 19:55:00,24.774628775500002 2014-04-11 20:00:00,19.3575191084 2014-04-11 20:05:00,22.7702010354 2014-04-11 20:10:00,21.072531363299998 2014-04-11 20:15:00,20.6485384736 2014-04-11 20:20:00,21.4137746088 2014-04-11 20:25:00,19.7472616542 2014-04-11 20:30:00,19.4937647691 2014-04-11 20:35:00,20.6424496095 2014-04-11 20:40:00,19.8921441773 2014-04-11 20:45:00,19.9639730542 2014-04-11 20:50:00,22.6916877663 2014-04-11 20:55:00,21.169434081800002 2014-04-11 21:00:00,20.141188464200003 2014-04-11 21:05:00,20.9738006155 2014-04-11 21:10:00,22.032976740100004 2014-04-11 21:15:00,18.6406616199 2014-04-11 21:20:00,21.556013192800002 2014-04-11 21:25:00,20.547571809100003 2014-04-11 21:30:00,18.777941795 2014-04-11 21:35:00,19.3881585842 2014-04-11 21:40:00,20.136711794700002 2014-04-11 21:45:00,20.980661437000002 2014-04-11 21:50:00,19.1677204187 2014-04-11 21:55:00,20.3489661134 2014-04-11 22:00:00,20.7818229555 2014-04-11 22:05:00,19.8361365054 2014-04-11 22:10:00,21.496724197600003 2014-04-11 22:15:00,21.522510288200003 2014-04-11 22:20:00,19.9241210003 2014-04-11 22:25:00,21.9372375602 2014-04-11 22:30:00,18.3404092181 2014-04-11 22:35:00,18.0509174691 2014-04-11 22:40:00,19.5632801944 2014-04-11 22:45:00,20.4468293513 2014-04-11 22:50:00,20.5594755533 2014-04-11 22:55:00,19.9471869525 2014-04-11 23:00:00,18.5072290549 2014-04-11 23:05:00,18.689761791 2014-04-11 23:10:00,21.4174979051 2014-04-11 23:15:00,21.4805767265 2014-04-11 23:20:00,20.7042035142 2014-04-11 23:25:00,20.6654651434 2014-04-11 23:30:00,20.399211050799998 2014-04-11 23:35:00,18.8195292075 2014-04-11 23:40:00,19.721203406 2014-04-11 23:45:00,20.7922245701 2014-04-11 23:50:00,20.1573910715 2014-04-11 23:55:00,18.08184025 2014-04-12 00:00:00,21.8142272269 2014-04-12 00:05:00,21.3792642103 2014-04-12 00:10:00,19.0421800564 2014-04-12 00:15:00,20.465835740699998 2014-04-12 00:20:00,21.692957534899996 2014-04-12 00:25:00,18.384044048499998 2014-04-12 00:30:00,20.012117923199998 2014-04-12 00:35:00,19.8249721034 2014-04-12 00:40:00,19.640820021099998 2014-04-12 00:45:00,21.3423544356 2014-04-12 00:50:00,19.5225845868 2014-04-12 00:55:00,18.254653333 2014-04-12 01:00:00,18.2633509687 2014-04-12 01:05:00,18.1709784261 2014-04-12 01:10:00,19.6365816875 2014-04-12 01:15:00,20.8736251108 2014-04-12 01:20:00,18.814889847699998 2014-04-12 01:25:00,20.585874081700002 2014-04-12 01:30:00,20.7483538884 2014-04-12 01:35:00,19.0208084961 2014-04-12 01:40:00,20.4022306242 2014-04-12 01:45:00,20.7394733601 2014-04-12 01:50:00,19.8664544912 2014-04-12 01:55:00,19.3468663891 2014-04-12 02:00:00,20.4766062063 2014-04-12 02:05:00,21.911388349299997 2014-04-12 02:10:00,19.7073656375 2014-04-12 02:15:00,19.5669403851 2014-04-12 02:20:00,19.8570676097 2014-04-12 02:25:00,18.304873573800002 2014-04-12 02:30:00,20.2126531187 2014-04-12 02:35:00,19.314789548900002 2014-04-12 02:40:00,18.4856884893 2014-04-12 02:45:00,19.8650269645 2014-04-12 02:50:00,18.013535946300003 2014-04-12 02:55:00,19.6071409807 2014-04-12 03:00:00,18.422941071700002 2014-04-12 03:05:00,18.0971708136 2014-04-12 03:10:00,21.297900185 2014-04-12 03:15:00,21.6649952131 2014-04-12 03:20:00,18.830698593399998 2014-04-12 03:25:00,20.1571930553 2014-04-12 03:30:00,19.1118326285 2014-04-12 03:35:00,19.974309754700002 2014-04-12 03:40:00,19.7465252836 2014-04-12 03:45:00,19.0762042203 2014-04-12 03:50:00,20.8015743185 2014-04-12 03:55:00,18.5059638373 2014-04-12 04:00:00,18.2122911287 2014-04-12 04:05:00,21.0707017321 2014-04-12 04:10:00,20.6637201249 2014-04-12 04:15:00,19.994104496600002 2014-04-12 04:20:00,19.8711590819 2014-04-12 04:25:00,19.989645518 2014-04-12 04:30:00,19.7480963044 2014-04-12 04:35:00,19.5715691833 2014-04-12 04:40:00,19.9987624115 2014-04-12 04:45:00,20.114060684600002 2014-04-12 04:50:00,20.767609256300002 2014-04-12 04:55:00,20.8448286429 2014-04-12 05:00:00,19.5105163206 2014-04-12 05:05:00,19.654162091 2014-04-12 05:10:00,19.4947886789 2014-04-12 05:15:00,20.1461430945 2014-04-12 05:20:00,19.8134141517 2014-04-12 05:25:00,21.5583858525 2014-04-12 05:30:00,20.7854450677 2014-04-12 05:35:00,21.594625535 2014-04-12 05:40:00,20.836547966199998 2014-04-12 05:45:00,21.883968594099997 2014-04-12 05:50:00,20.542947113 2014-04-12 05:55:00,21.8542005527 2014-04-12 06:00:00,18.6326795616 2014-04-12 06:05:00,18.2099107233 2014-04-12 06:10:00,20.3165007408 2014-04-12 06:15:00,21.9339728232 2014-04-12 06:20:00,19.6704209892 2014-04-12 06:25:00,18.8481734488 2014-04-12 06:30:00,20.0861657968 2014-04-12 06:35:00,20.5951944983 2014-04-12 06:40:00,19.2607147821 2014-04-12 06:45:00,20.859077434 2014-04-12 06:50:00,21.900458028200003 2014-04-12 06:55:00,21.5878524868 2014-04-12 07:00:00,19.166341494 2014-04-12 07:05:00,19.3068947326 2014-04-12 07:10:00,19.4861648978 2014-04-12 07:15:00,19.5782111136 2014-04-12 07:20:00,18.4012779968 2014-04-12 07:25:00,21.0478513556 2014-04-12 07:30:00,19.4613570544 2014-04-12 07:35:00,21.519279906799998 2014-04-12 07:40:00,21.7077624925 2014-04-12 07:45:00,18.0977252372 2014-04-12 07:50:00,21.9540122797 2014-04-12 07:55:00,20.840090926 2014-04-12 08:00:00,20.081568904 2014-04-12 08:05:00,19.558110433499998 2014-04-12 08:10:00,20.0740725304 2014-04-12 08:15:00,19.2984988959 2014-04-12 08:20:00,20.4907512548 2014-04-12 08:25:00,18.3719211058 2014-04-12 08:30:00,20.4844904116 2014-04-12 08:35:00,19.1013794006 2014-04-12 08:40:00,18.070539316199998 2014-04-12 08:45:00,20.2108230647 2014-04-12 08:50:00,20.3137910234 2014-04-12 08:55:00,19.7062760188 2014-04-12 09:00:00,62.18309276270001 2014-04-12 09:05:00,73.3494641581 2014-04-12 09:10:00,69.5154589783 2014-04-12 09:15:00,62.7737008741 2014-04-12 09:20:00,68.1486558417 2014-04-12 09:25:00,67.9626586969 2014-04-12 09:30:00,62.021465415600005 2014-04-12 09:35:00,69.45329196899999 2014-04-12 09:40:00,72.1932390253 2014-04-12 09:45:00,71.3865095378 2014-04-12 09:50:00,63.960384032600004 2014-04-12 09:55:00,72.9271784019 2014-04-12 10:00:00,75.156254411 2014-04-12 10:05:00,84.5298100311 2014-04-12 10:10:00,70.9535284048 2014-04-12 10:15:00,77.3859588458 2014-04-12 10:20:00,79.1073703338 2014-04-12 10:25:00,73.6835295283 2014-04-12 10:30:00,81.8118205289 2014-04-12 10:35:00,79.56942095069999 2014-04-12 10:40:00,70.1210584667 2014-04-12 10:45:00,79.28188052760001 2014-04-12 10:50:00,77.4677421982 2014-04-12 10:55:00,72.8823732104 2014-04-12 11:00:00,87.4043798032 2014-04-12 11:05:00,85.83646754649999 2014-04-12 11:10:00,76.2200423817 2014-04-12 11:15:00,80.1731919244 2014-04-12 11:20:00,76.6016500331 2014-04-12 11:25:00,83.901484434 2014-04-12 11:30:00,86.36399111360001 2014-04-12 11:35:00,77.2748101644 2014-04-12 11:40:00,84.3800118984 2014-04-12 11:45:00,79.4946735593 2014-04-12 11:50:00,77.8751854391 2014-04-12 11:55:00,86.4926611358 2014-04-12 12:00:00,80.0702752495 2014-04-12 12:05:00,79.3831937225 2014-04-12 12:10:00,82.65963969090001 2014-04-12 12:15:00,76.0883315196 2014-04-12 12:20:00,77.10404990949999 2014-04-12 12:25:00,86.8084380998 2014-04-12 12:30:00,82.757049754 2014-04-12 12:35:00,85.1239229311 2014-04-12 12:40:00,76.24618284510001 2014-04-12 12:45:00,80.60380226720001 2014-04-12 12:50:00,87.43728946350002 2014-04-12 12:55:00,77.0067432696 2014-04-12 13:00:00,74.5497273914 2014-04-12 13:05:00,80.1549343293 2014-04-12 13:10:00,78.18636818659999 2014-04-12 13:15:00,74.53534294800001 2014-04-12 13:20:00,86.1961300859 2014-04-12 13:25:00,87.830498189 2014-04-12 13:30:00,81.0778515355 2014-04-12 13:35:00,84.3745735352 2014-04-12 13:40:00,85.7240352054 2014-04-12 13:45:00,83.1957403254 2014-04-12 13:50:00,72.6890472266 2014-04-12 13:55:00,74.504262392 2014-04-12 14:00:00,73.1323165387 2014-04-12 14:05:00,72.15461011869998 2014-04-12 14:10:00,76.8922515349 2014-04-12 14:15:00,78.2739380383 2014-04-12 14:20:00,75.8528346065 2014-04-12 14:25:00,73.030168753 2014-04-12 14:30:00,80.4739465185 2014-04-12 14:35:00,76.3694432101 2014-04-12 14:40:00,84.7325271213 2014-04-12 14:45:00,72.1253797616 2014-04-12 14:50:00,85.4763297598 2014-04-12 14:55:00,87.2718696123 2014-04-12 15:00:00,83.4573598121 2014-04-12 15:05:00,83.7375011565 2014-04-12 15:10:00,86.93616239049999 2014-04-12 15:15:00,75.34441725149999 2014-04-12 15:20:00,87.9122051261 2014-04-12 15:25:00,84.37488924729999 2014-04-12 15:30:00,83.62432853199999 2014-04-12 15:35:00,77.7767026004 2014-04-12 15:40:00,80.7316647351 2014-04-12 15:45:00,82.4618929706 2014-04-12 15:50:00,81.92469929640001 2014-04-12 15:55:00,83.27895473 2014-04-12 16:00:00,73.3179670545 2014-04-12 16:05:00,77.6902257598 2014-04-12 16:10:00,78.943848693 2014-04-12 16:15:00,76.16992251949999 2014-04-12 16:20:00,74.7618927812 2014-04-12 16:25:00,74.2226971708 2014-04-12 16:30:00,77.8619847808 2014-04-12 16:35:00,79.8949138105 2014-04-12 16:40:00,73.0074828677 2014-04-12 16:45:00,87.1431621983 2014-04-12 16:50:00,84.2437314175 2014-04-12 16:55:00,83.6934676792 2014-04-12 17:00:00,74.7657396898 2014-04-12 17:05:00,81.6607809304 2014-04-12 17:10:00,80.4755682463 2014-04-12 17:15:00,87.7194678483 2014-04-12 17:20:00,83.9627160796 2014-04-12 17:25:00,81.212158954 2014-04-12 17:30:00,85.6129697881 2014-04-12 17:35:00,74.4814797329 2014-04-12 17:40:00,72.24343673359999 2014-04-12 17:45:00,83.0437014458 2014-04-12 17:50:00,73.5729551118 2014-04-12 17:55:00,73.8469098825 2014-04-12 18:00:00,33.5659502045 2014-04-12 18:05:00,30.5314171404 2014-04-12 18:10:00,32.8232334776 2014-04-12 18:15:00,34.6713976701 2014-04-12 18:20:00,30.825431084 2014-04-12 18:25:00,30.1897168137 2014-04-12 18:30:00,29.4819967954 2014-04-12 18:35:00,29.634953423200002 2014-04-12 18:40:00,29.1982196444 2014-04-12 18:45:00,29.360905587199998 2014-04-12 18:50:00,31.5648233079 2014-04-12 18:55:00,30.8535303643 2014-04-12 19:00:00,23.32539116860001 2014-04-12 19:05:00,24.0586813092 2014-04-12 19:10:00,23.6757826513 2014-04-12 19:15:00,22.5372536735 2014-04-12 19:20:00,20.6189395496 2014-04-12 19:25:00,23.3397561517 2014-04-12 19:30:00,21.7854714917 2014-04-12 19:35:00,20.5437126378 2014-04-12 19:40:00,23.9342481913 2014-04-12 19:45:00,21.6752088079 2014-04-12 19:50:00,21.1377536101 2014-04-12 19:55:00,24.0641039294 2014-04-12 20:00:00,22.127140059600002 2014-04-12 20:05:00,19.820424311300002 2014-04-12 20:10:00,19.8852663748 2014-04-12 20:15:00,20.8061581993 2014-04-12 20:20:00,21.4361761014 2014-04-12 20:25:00,18.6906589067 2014-04-12 20:30:00,20.862335369500002 2014-04-12 20:35:00,22.334750705 2014-04-12 20:40:00,19.5055363688 2014-04-12 20:45:00,22.154556003099998 2014-04-12 20:50:00,22.323889255900003 2014-04-12 20:55:00,19.534453079000002 2014-04-12 21:00:00,21.1176880877 2014-04-12 21:05:00,19.046084466900002 2014-04-12 21:10:00,21.0510067297 2014-04-12 21:15:00,21.2913902965 2014-04-12 21:20:00,19.0799691177 2014-04-12 21:25:00,20.9636228183 2014-04-12 21:30:00,21.3504105104 2014-04-12 21:35:00,19.527600155 2014-04-12 21:40:00,18.7604309514 2014-04-12 21:45:00,18.4560239438 2014-04-12 21:50:00,20.398974093299998 2014-04-12 21:55:00,22.0175719073 2014-04-12 22:00:00,21.3122413989 2014-04-12 22:05:00,19.7623121702 2014-04-12 22:10:00,20.165824225799998 2014-04-12 22:15:00,19.1364649193 2014-04-12 22:20:00,18.6701696332 2014-04-12 22:25:00,19.9474558148 2014-04-12 22:30:00,19.873066100899997 2014-04-12 22:35:00,20.1070040124 2014-04-12 22:40:00,21.8321571011 2014-04-12 22:45:00,20.4351801485 2014-04-12 22:50:00,20.4426935003 2014-04-12 22:55:00,18.5298706574 2014-04-12 23:00:00,21.990176765999998 2014-04-12 23:05:00,21.0954293198 2014-04-12 23:10:00,21.5129430664 2014-04-12 23:15:00,19.6609758281 2014-04-12 23:20:00,20.0123540156 2014-04-12 23:25:00,20.092192195 2014-04-12 23:30:00,18.7799832199 2014-04-12 23:35:00,20.761942150899998 2014-04-12 23:40:00,21.616056378499998 2014-04-12 23:45:00,18.6584049968 2014-04-12 23:50:00,18.3487953846 2014-04-12 23:55:00,20.9568985722 2014-04-13 00:00:00,19.0928073267 2014-04-13 00:05:00,20.4954501665 2014-04-13 00:10:00,20.783033352 2014-04-13 00:15:00,19.287643054300002 2014-04-13 00:20:00,21.2605783897 2014-04-13 00:25:00,20.1999559285 2014-04-13 00:30:00,21.4759976318 2014-04-13 00:35:00,21.053174210199998 2014-04-13 00:40:00,21.4743025281 2014-04-13 00:45:00,18.0806455285 2014-04-13 00:50:00,18.974025043 2014-04-13 00:55:00,18.360031761800002 2014-04-13 01:00:00,19.7683320688 2014-04-13 01:05:00,21.5598404865 2014-04-13 01:10:00,19.870161049100002 2014-04-13 01:15:00,21.3988521783 2014-04-13 01:20:00,19.3087129521 2014-04-13 01:25:00,19.3582802912 2014-04-13 01:30:00,21.5822469213 2014-04-13 01:35:00,19.703268586 2014-04-13 01:40:00,21.159061951199998 2014-04-13 01:45:00,18.9465741915 2014-04-13 01:50:00,21.7952033187 2014-04-13 01:55:00,20.298312986099997 2014-04-13 02:00:00,21.037294274300002 2014-04-13 02:05:00,18.358062799200003 2014-04-13 02:10:00,19.9706569033 2014-04-13 02:15:00,21.604153990900002 2014-04-13 02:20:00,21.508154516199998 2014-04-13 02:25:00,18.1872558289 2014-04-13 02:30:00,19.2147938765 2014-04-13 02:35:00,19.7732800259 2014-04-13 02:40:00,18.6890592574 2014-04-13 02:45:00,20.919993244 2014-04-13 02:50:00,18.7380479824 2014-04-13 02:55:00,19.3865587775 2014-04-13 03:00:00,20.6531225474 2014-04-13 03:05:00,19.9283573781 2014-04-13 03:10:00,20.9542841545 2014-04-13 03:15:00,21.844831604899998 2014-04-13 03:20:00,18.4661867509 2014-04-13 03:25:00,20.8382708656 2014-04-13 03:30:00,18.9213766225 2014-04-13 03:35:00,19.6579069096 2014-04-13 03:40:00,18.1314509032 2014-04-13 03:45:00,18.5436295292 2014-04-13 03:50:00,19.2791091562 2014-04-13 03:55:00,19.367943221199997 2014-04-13 04:00:00,21.5983408658 2014-04-13 04:05:00,20.9672516371 2014-04-13 04:10:00,21.8887318727 2014-04-13 04:15:00,20.3962860413 2014-04-13 04:20:00,18.9668549284 2014-04-13 04:25:00,19.3106201197 2014-04-13 04:30:00,19.279343693199998 2014-04-13 04:35:00,19.305977310699998 2014-04-13 04:40:00,20.691856692400002 2014-04-13 04:45:00,20.1232317124 2014-04-13 04:50:00,19.5416967123 2014-04-13 04:55:00,18.5963590749 2014-04-13 05:00:00,18.0885566518 2014-04-13 05:05:00,18.8753387104 2014-04-13 05:10:00,18.429885615899998 2014-04-13 05:15:00,21.1417801234 2014-04-13 05:20:00,18.4499918313 2014-04-13 05:25:00,20.8969129492 2014-04-13 05:30:00,19.5426347591 2014-04-13 05:35:00,18.293513559 2014-04-13 05:40:00,21.2509201977 2014-04-13 05:45:00,20.318522280899998 2014-04-13 05:50:00,18.9430460515 2014-04-13 05:55:00,21.5787246973 2014-04-13 06:00:00,18.1810332555 2014-04-13 06:05:00,18.8072784328 2014-04-13 06:10:00,21.008187711199998 2014-04-13 06:15:00,20.8375117212 2014-04-13 06:20:00,19.1570867749 2014-04-13 06:25:00,18.248099501400002 2014-04-13 06:30:00,21.4323122889 2014-04-13 06:35:00,19.2547905523 2014-04-13 06:40:00,18.7828536597 2014-04-13 06:45:00,20.0642472894 2014-04-13 06:50:00,21.6409087971 2014-04-13 06:55:00,18.1741863114 2014-04-13 07:00:00,21.0632163521 2014-04-13 07:05:00,20.2898929118 2014-04-13 07:10:00,19.701796466199998 2014-04-13 07:15:00,20.976321776400003 2014-04-13 07:20:00,21.863297697800004 2014-04-13 07:25:00,18.9168248447 2014-04-13 07:30:00,18.5745894603 2014-04-13 07:35:00,21.6515269809 2014-04-13 07:40:00,20.6758123098 2014-04-13 07:45:00,19.751944086199998 2014-04-13 07:50:00,20.2930382811 2014-04-13 07:55:00,20.982455620699998 2014-04-13 08:00:00,21.0921275948 2014-04-13 08:05:00,21.6795767233 2014-04-13 08:10:00,19.7073711556 2014-04-13 08:15:00,19.1736436401 2014-04-13 08:20:00,20.5586570672 2014-04-13 08:25:00,19.6629115971 2014-04-13 08:30:00,20.3783938158 2014-04-13 08:35:00,19.6799431938 2014-04-13 08:40:00,18.611983146700002 2014-04-13 08:45:00,19.8777070066 2014-04-13 08:50:00,20.7636712878 2014-04-13 08:55:00,21.1971352307 2014-04-13 09:00:00,67.9092373644 2014-04-13 09:05:00,63.4472353069 2014-04-13 09:10:00,66.8397528512 2014-04-13 09:15:00,71.8935974322 2014-04-13 09:20:00,66.8148860804 2014-04-13 09:25:00,70.672818793 2014-04-13 09:30:00,68.0981060708 2014-04-13 09:35:00,64.48063450149999 2014-04-13 09:40:00,72.0276469091 2014-04-13 09:45:00,62.3453029754 2014-04-13 09:50:00,68.3385078455 2014-04-13 09:55:00,64.0409180657 2014-04-13 10:00:00,70.880858555 2014-04-13 10:05:00,77.6455347035 2014-04-13 10:10:00,77.5932046601 2014-04-13 10:15:00,80.811101994 2014-04-13 10:20:00,81.3985307562 2014-04-13 10:25:00,81.1353239045 2014-04-13 10:30:00,76.1963515349 2014-04-13 10:35:00,79.6438254978 2014-04-13 10:40:00,78.7941901658 2014-04-13 10:45:00,76.3826384549 2014-04-13 10:50:00,79.1087410138 2014-04-13 10:55:00,84.5412870465 2014-04-13 11:00:00,74.63578209949999 2014-04-13 11:05:00,85.9733994114 2014-04-13 11:10:00,72.4181564944 2014-04-13 11:15:00,76.472622042 2014-04-13 11:20:00,76.1506620339 2014-04-13 11:25:00,81.5297106757 2014-04-13 11:30:00,73.6550016331 2014-04-13 11:35:00,85.6008564187 2014-04-13 11:40:00,84.7452816002 2014-04-13 11:45:00,81.93845479630002 2014-04-13 11:50:00,78.8586135808 2014-04-13 11:55:00,86.4057328942 2014-04-13 12:00:00,85.1895945417 2014-04-13 12:05:00,79.8930555185 2014-04-13 12:10:00,83.1300977029 2014-04-13 12:15:00,80.97359417979999 2014-04-13 12:20:00,81.3093873232 2014-04-13 12:25:00,77.2028623705 2014-04-13 12:30:00,79.29808164960002 2014-04-13 12:35:00,73.1620429612 2014-04-13 12:40:00,77.6243179718 2014-04-13 12:45:00,83.0334963383 2014-04-13 12:50:00,87.14675474030001 2014-04-13 12:55:00,87.3041349732 2014-04-13 13:00:00,80.8721519302 2014-04-13 13:05:00,81.6863465995 2014-04-13 13:10:00,74.9535457987 2014-04-13 13:15:00,83.1049797464 2014-04-13 13:20:00,73.112989353 2014-04-13 13:25:00,76.53659777979999 2014-04-13 13:30:00,82.6739670413 2014-04-13 13:35:00,76.9464905138 2014-04-13 13:40:00,72.7800785738 2014-04-13 13:45:00,85.2894521672 2014-04-13 13:50:00,76.9468084469 2014-04-13 13:55:00,72.99216127369998 2014-04-13 14:00:00,73.1930971947 2014-04-13 14:05:00,76.0244914299 2014-04-13 14:10:00,74.84466243930001 2014-04-13 14:15:00,84.38475122199999 2014-04-13 14:20:00,77.1432416933 2014-04-13 14:25:00,84.8710585543 2014-04-13 14:30:00,74.7779464514 2014-04-13 14:35:00,79.8822323415 2014-04-13 14:40:00,83.0046097243 2014-04-13 14:45:00,82.4278969329 2014-04-13 14:50:00,81.6141528915 2014-04-13 14:55:00,86.7929793679 2014-04-13 15:00:00,75.65567606180001 2014-04-13 15:05:00,79.8987402361 2014-04-13 15:10:00,86.1430538199 2014-04-13 15:15:00,73.245597085 2014-04-13 15:20:00,72.89351250760001 2014-04-13 15:25:00,75.7321095657 2014-04-13 15:30:00,82.1275510805 2014-04-13 15:35:00,76.15734290569999 2014-04-13 15:40:00,75.0431177201 2014-04-13 15:45:00,79.3400753737 2014-04-13 15:50:00,81.8167836516 2014-04-13 15:55:00,75.9761939338 2014-04-13 16:00:00,76.8109115103 2014-04-13 16:05:00,81.8167917884 2014-04-13 16:10:00,87.1316474587 2014-04-13 16:15:00,82.7957086709 2014-04-13 16:20:00,84.5263040065 2014-04-13 16:25:00,77.8688120077 2014-04-13 16:30:00,76.35592314649999 2014-04-13 16:35:00,79.2681316961 2014-04-13 16:40:00,84.91396222430001 2014-04-13 16:45:00,79.3006420111 2014-04-13 16:50:00,85.5474422892 2014-04-13 16:55:00,87.820183076 2014-04-13 17:00:00,73.1523985612 2014-04-13 17:05:00,72.7265345703 2014-04-13 17:10:00,74.3934066795 2014-04-13 17:15:00,78.1498848022 2014-04-13 17:20:00,74.0966468932 2014-04-13 17:25:00,85.93059864450001 2014-04-13 17:30:00,72.3703122262 2014-04-13 17:35:00,77.0526538731 2014-04-13 17:40:00,74.9550852891 2014-04-13 17:45:00,86.9045959111 2014-04-13 17:50:00,82.7116643169 2014-04-13 17:55:00,86.59245085170002 2014-04-13 18:00:00,35.022897021599995 2014-04-13 18:05:00,31.981422619099998 2014-04-13 18:10:00,30.299636474 2014-04-13 18:15:00,30.039858464 2014-04-13 18:20:00,30.2266749113 2014-04-13 18:25:00,33.3349907685 2014-04-13 18:30:00,29.0588470807 2014-04-13 18:35:00,29.128705274699996 2014-04-13 18:40:00,32.6921085544 2014-04-13 18:45:00,32.9091594206 2014-04-13 18:50:00,33.0576763686 2014-04-13 18:55:00,31.180029242800003 2014-04-13 19:00:00,23.7706317975 2014-04-13 19:05:00,22.550636916 2014-04-13 19:10:00,20.6324848906 2014-04-13 19:15:00,23.7310035938 2014-04-13 19:20:00,24.4297423423 2014-04-13 19:25:00,20.4289615616 2014-04-13 19:30:00,21.913252795300004 2014-04-13 19:35:00,22.3440706551 2014-04-13 19:40:00,20.8161878632 2014-04-13 19:45:00,24.0473347669 2014-04-13 19:50:00,21.4329892334 2014-04-13 19:55:00,23.6678769606 2014-04-13 20:00:00,21.1803931442 2014-04-13 20:05:00,20.881595438199998 2014-04-13 20:10:00,19.2190168776 2014-04-13 20:15:00,19.336001388099998 2014-04-13 20:20:00,18.625938842300002 2014-04-13 20:25:00,19.4179578794 2014-04-13 20:30:00,19.8469367862 2014-04-13 20:35:00,21.8445629025 2014-04-13 20:40:00,19.932744123699997 2014-04-13 20:45:00,21.522930563899997 2014-04-13 20:50:00,20.231955341400003 2014-04-13 20:55:00,21.6468203462 2014-04-13 21:00:00,22.010230762600003 2014-04-13 21:05:00,19.0503711436 2014-04-13 21:10:00,21.552323354099997 2014-04-13 21:15:00,20.5856353173 2014-04-13 21:20:00,21.3712690439 2014-04-13 21:25:00,20.7052540078 2014-04-13 21:30:00,19.7903378112 2014-04-13 21:35:00,19.0030787501 2014-04-13 21:40:00,18.3678855327 2014-04-13 21:45:00,20.2387553609 2014-04-13 21:50:00,22.0667185852 2014-04-13 21:55:00,21.052737571199998 2014-04-13 22:00:00,19.327919163 2014-04-13 22:05:00,21.329275656300002 2014-04-13 22:10:00,21.0961688889 2014-04-13 22:15:00,19.1449046455 2014-04-13 22:20:00,18.0745648911 2014-04-13 22:25:00,18.4903842896 2014-04-13 22:30:00,21.5298736064 2014-04-13 22:35:00,21.3667445328 2014-04-13 22:40:00,19.1992495966 2014-04-13 22:45:00,19.1591568462 2014-04-13 22:50:00,21.1917845396 2014-04-13 22:55:00,21.7718307808 2014-04-13 23:00:00,21.1206034025 2014-04-13 23:05:00,20.426235790499998 2014-04-13 23:10:00,18.9743277711 2014-04-13 23:15:00,20.106851428800002 2014-04-13 23:20:00,18.937682769600002 2014-04-13 23:25:00,21.236122231099998 2014-04-13 23:30:00,19.5515975023 2014-04-13 23:35:00,21.3388851453 2014-04-13 23:40:00,19.530185945899998 2014-04-13 23:45:00,21.3006865654 2014-04-13 23:50:00,19.3369832468 2014-04-13 23:55:00,19.7643248384 2014-04-14 00:00:00,20.4619536774 2014-04-14 00:05:00,18.2811504561 2014-04-14 00:10:00,21.7928282473 2014-04-14 00:15:00,20.2944231445 2014-04-14 00:20:00,20.0312800588 2014-04-14 00:25:00,21.3575758845 2014-04-14 00:30:00,21.4630509196 2014-04-14 00:35:00,20.089041618099998 2014-04-14 00:40:00,21.7090493032 2014-04-14 00:45:00,18.2589510643 2014-04-14 00:50:00,18.452903169000002 2014-04-14 00:55:00,20.3871529201 2014-04-14 01:00:00,19.4162634472 2014-04-14 01:05:00,19.8569006648 2014-04-14 01:10:00,19.3123168716 2014-04-14 01:15:00,19.6189012458 2014-04-14 01:20:00,21.2905853886 2014-04-14 01:25:00,20.3739047994 2014-04-14 01:30:00,21.9893781971 2014-04-14 01:35:00,21.147516791300003 2014-04-14 01:40:00,19.0946650164 2014-04-14 01:45:00,19.0573804709 2014-04-14 01:50:00,19.3435930805 2014-04-14 01:55:00,21.3730379226 2014-04-14 02:00:00,18.1091506026 2014-04-14 02:05:00,18.920725115499998 2014-04-14 02:10:00,21.6196736814 2014-04-14 02:15:00,20.5595857443 2014-04-14 02:20:00,18.907388382 2014-04-14 02:25:00,18.8765798729 2014-04-14 02:30:00,21.450472407 2014-04-14 02:35:00,21.5750300331 2014-04-14 02:40:00,19.0245243638 2014-04-14 02:45:00,19.6820414323 2014-04-14 02:50:00,21.338382954500002 2014-04-14 02:55:00,21.0840297544 2014-04-14 03:00:00,21.2556644263 2014-04-14 03:05:00,20.0735927632 2014-04-14 03:10:00,21.6461961932 2014-04-14 03:15:00,19.3038061758 2014-04-14 03:20:00,18.6266885374 2014-04-14 03:25:00,20.8349293303 2014-04-14 03:30:00,20.157417664 2014-04-14 03:35:00,21.4183430752 2014-04-14 03:40:00,18.3246369965 2014-04-14 03:45:00,21.3747696138 2014-04-14 03:50:00,19.1731786128 2014-04-14 03:55:00,20.6194226687 2014-04-14 04:00:00,18.1605151563 2014-04-14 04:05:00,20.4383251852 2014-04-14 04:10:00,20.8690867567 2014-04-14 04:15:00,19.475000857999998 2014-04-14 04:20:00,18.861642821 2014-04-14 04:25:00,20.1505227064 2014-04-14 04:30:00,21.3327632177 2014-04-14 04:35:00,19.2941894332 2014-04-14 04:40:00,19.0098771901 2014-04-14 04:45:00,19.1157412346 2014-04-14 04:50:00,21.7965286117 2014-04-14 04:55:00,19.4371076631 2014-04-14 05:00:00,18.014416959600002 2014-04-14 05:05:00,21.1267248318 2014-04-14 05:10:00,20.797099181300002 2014-04-14 05:15:00,18.5142730584 2014-04-14 05:20:00,21.9396169965 2014-04-14 05:25:00,20.4322491412 2014-04-14 05:30:00,20.0031179638 2014-04-14 05:35:00,19.5288770705 2014-04-14 05:40:00,21.5946910223 2014-04-14 05:45:00,18.9758539257 2014-04-14 05:50:00,19.143075600899998 2014-04-14 05:55:00,18.4896432267 2014-04-14 06:00:00,21.036476382300002 2014-04-14 06:05:00,20.3821971216 2014-04-14 06:10:00,20.436264677 2014-04-14 06:15:00,18.873881724100002 2014-04-14 06:20:00,20.6046735565 2014-04-14 06:25:00,21.061833789 2014-04-14 06:30:00,19.4315541229 2014-04-14 06:35:00,21.2053885758 2014-04-14 06:40:00,19.395162354100002 2014-04-14 06:45:00,21.032553846 2014-04-14 06:50:00,18.1349204298 2014-04-14 06:55:00,20.2046584059 2014-04-14 07:00:00,21.8781062426 2014-04-14 07:05:00,21.9249784027 2014-04-14 07:10:00,19.1270103134 2014-04-14 07:15:00,19.765596364300002 2014-04-14 07:20:00,18.2519116319 2014-04-14 07:25:00,21.4933652304 2014-04-14 07:30:00,20.2742886126 2014-04-14 07:35:00,19.5404027158 2014-04-14 07:40:00,18.451082234 2014-04-14 07:45:00,21.787069141999996 2014-04-14 07:50:00,20.120876191300002 2014-04-14 07:55:00,19.1317117163 2014-04-14 08:00:00,19.4008605205 2014-04-14 08:05:00,19.0827887237 2014-04-14 08:10:00,20.4072392354 2014-04-14 08:15:00,21.7198543031 2014-04-14 08:20:00,21.4267752133 2014-04-14 08:25:00,19.8415235017 2014-04-14 08:30:00,21.3059974492 2014-04-14 08:35:00,19.6924219251 2014-04-14 08:40:00,19.009228563 2014-04-14 08:45:00,21.9336604611 2014-04-14 08:50:00,19.2155502719 2014-04-14 08:55:00,19.2948969239 2014-04-14 09:00:00,74.6598230019 2014-04-14 09:05:00,63.0214139071 2014-04-14 09:10:00,71.54326223689999 2014-04-14 09:15:00,73.9270535154 2014-04-14 09:20:00,68.1604119221 2014-04-14 09:25:00,61.234295959200004 2014-04-14 09:30:00,66.3008016399 2014-04-14 09:35:00,62.7173382964 2014-04-14 09:40:00,66.8601521887 2014-04-14 09:45:00,71.9443639583 2014-04-14 09:50:00,67.16647706479999 2014-04-14 09:55:00,67.07418165029999 2014-04-14 10:00:00,78.4813726818 2014-04-14 10:05:00,78.8678378753 2014-04-14 10:10:00,83.1297187126 2014-04-14 10:15:00,74.6256764168 2014-04-14 10:20:00,82.592338023 2014-04-14 10:25:00,78.6232917797 2014-04-14 10:30:00,74.5042186116 2014-04-14 10:35:00,74.420356203 2014-04-14 10:40:00,75.4448542655 2014-04-14 10:45:00,79.50419912550001 2014-04-14 10:50:00,73.42219807069999 2014-04-14 10:55:00,84.12357687720001 2014-04-14 11:00:00,80.7114097388 2014-04-14 11:05:00,86.1999309173 2014-04-14 11:10:00,72.3060149188 2014-04-14 11:15:00,77.0168912358 2014-04-14 11:20:00,71.9307330356 2014-04-14 11:25:00,75.8978928673 2014-04-14 11:30:00,85.277350935 2014-04-14 11:35:00,72.1502409208 2014-04-14 11:40:00,78.5044834771 2014-04-14 11:45:00,73.4377866888 2014-04-14 11:50:00,78.1974338449 2014-04-14 11:55:00,84.9090955961 2014-04-14 12:00:00,81.87077357060001 2014-04-14 12:05:00,83.6875558035 2014-04-14 12:10:00,77.4925630482 2014-04-14 12:15:00,87.00583068440002 2014-04-14 12:20:00,83.2481756683 2014-04-14 12:25:00,78.6542825712 2014-04-14 12:30:00,78.7288486795 2014-04-14 12:35:00,86.59490811090002 2014-04-14 12:40:00,81.12500812489999 2014-04-14 12:45:00,83.20210487760001 2014-04-14 12:50:00,78.5781565159 2014-04-14 12:55:00,75.48838933520001 2014-04-14 13:00:00,83.5568902042 2014-04-14 13:05:00,81.705566311 2014-04-14 13:10:00,80.0022809301 2014-04-14 13:15:00,81.9646587995 2014-04-14 13:20:00,75.3144895604 2014-04-14 13:25:00,84.6826905799 2014-04-14 13:30:00,87.1496839352 2014-04-14 13:35:00,86.2369484706 2014-04-14 13:40:00,77.1244576117 2014-04-14 13:45:00,78.4772533103 2014-04-14 13:50:00,84.9140525319 2014-04-14 13:55:00,81.5023088434 2014-04-14 14:00:00,80.7627543005 2014-04-14 14:05:00,86.8221038195 2014-04-14 14:10:00,80.57253170850001 2014-04-14 14:15:00,80.2351674005 2014-04-14 14:20:00,72.66880919 2014-04-14 14:25:00,73.10716202520001 2014-04-14 14:30:00,72.11526322729999 2014-04-14 14:35:00,86.607750241 2014-04-14 14:40:00,78.53041691930001 2014-04-14 14:45:00,79.493166163 2014-04-14 14:50:00,85.5220859043 2014-04-14 14:55:00,81.74401706479999 2014-04-14 15:00:00,81.75124072279999 2014-04-14 15:05:00,76.743814122 2014-04-14 15:10:00,85.3417146945 2014-04-14 15:15:00,74.6525629451 2014-04-14 15:20:00,72.849694111 2014-04-14 15:25:00,75.06493309 2014-04-14 15:30:00,76.283063176 2014-04-14 15:35:00,76.5162423627 2014-04-14 15:40:00,82.727423387 2014-04-14 15:45:00,75.4844687394 2014-04-14 15:50:00,82.8257377372 2014-04-14 15:55:00,73.4574095738 2014-04-14 16:00:00,74.3550966155 2014-04-14 16:05:00,80.1409893049 2014-04-14 16:10:00,86.7501662806 2014-04-14 16:15:00,85.7529167751 2014-04-14 16:20:00,87.49988707899998 2014-04-14 16:25:00,82.4075068217 2014-04-14 16:30:00,82.8128788616 2014-04-14 16:35:00,82.00021054220001 2014-04-14 16:40:00,81.9649453927 2014-04-14 16:45:00,74.3537827615 2014-04-14 16:50:00,80.699668355 2014-04-14 16:55:00,78.17693683520001 2014-04-14 17:00:00,79.0805650855 2014-04-14 17:05:00,80.37757830390001 2014-04-14 17:10:00,74.054310312 2014-04-14 17:15:00,77.7517738849 2014-04-14 17:20:00,73.0151649362 2014-04-14 17:25:00,87.6746564197 2014-04-14 17:30:00,73.8964200849 2014-04-14 17:35:00,76.13636658029999 2014-04-14 17:40:00,86.26065370319998 2014-04-14 17:45:00,79.7233301261 2014-04-14 17:50:00,74.170166743 2014-04-14 17:55:00,78.1476585999 2014-04-14 18:00:00,29.541549490799998 2014-04-14 18:05:00,30.0813766057 2014-04-14 18:10:00,29.1329854269 2014-04-14 18:15:00,31.604649896999998 2014-04-14 18:20:00,33.9624646582 2014-04-14 18:25:00,32.550196494 2014-04-14 18:30:00,32.6806036804 2014-04-14 18:35:00,30.0837320165 2014-04-14 18:40:00,31.0009146446 2014-04-14 18:45:00,34.2095428963 2014-04-14 18:50:00,29.3622739421 2014-04-14 18:55:00,34.2907495997 2014-04-14 19:00:00,22.3269300929 2014-04-14 19:05:00,23.9104191807 2014-04-14 19:10:00,21.5846675748 2014-04-14 19:15:00,21.6780152339 2014-04-14 19:20:00,23.527188519499997 2014-04-14 19:25:00,23.676781558000002 2014-04-14 19:30:00,21.188806995 2014-04-14 19:35:00,24.5184621902 2014-04-14 19:40:00,20.5385145403 2014-04-14 19:45:00,20.4668921519 2014-04-14 19:50:00,22.827857632199997 2014-04-14 19:55:00,23.3978773561 2014-04-14 20:00:00,22.3677893169 2014-04-14 20:05:00,20.0906576771 2014-04-14 20:10:00,18.535593388800002 2014-04-14 20:15:00,20.9014631556 2014-04-14 20:20:00,19.6185946649 2014-04-14 20:25:00,20.205351166 2014-04-14 20:30:00,20.4327707541 2014-04-14 20:35:00,18.6962434292 2014-04-14 20:40:00,20.4225811445 2014-04-14 20:45:00,20.1782051131 2014-04-14 20:50:00,21.3505810544 2014-04-14 20:55:00,21.0766473194 2014-04-14 21:00:00,18.8308189683 2014-04-14 21:05:00,18.9149134938 2014-04-14 21:10:00,19.095243987 2014-04-14 21:15:00,18.805637563599998 2014-04-14 21:20:00,20.727871241400003 2014-04-14 21:25:00,22.083213722199996 2014-04-14 21:30:00,20.7073537916 2014-04-14 21:35:00,20.524774420299998 2014-04-14 21:40:00,19.7339823015 2014-04-14 21:45:00,19.3427225291 2014-04-14 21:50:00,21.7481875906 2014-04-14 21:55:00,21.9810122788 2014-04-14 22:00:00,20.006292313 2014-04-14 22:05:00,19.1791963425 2014-04-14 22:10:00,21.100726089600002 2014-04-14 22:15:00,18.547615788399998 2014-04-14 22:20:00,21.0825727991 2014-04-14 22:25:00,21.2962182485 2014-04-14 22:30:00,18.5173754006 2014-04-14 22:35:00,21.9284770125 2014-04-14 22:40:00,21.963113518000004 2014-04-14 22:45:00,21.7677549094 2014-04-14 22:50:00,20.0033240015 2014-04-14 22:55:00,19.0025214845 2014-04-14 23:00:00,20.3319401047 2014-04-14 23:05:00,19.6835138611 2014-04-14 23:10:00,18.8274087456 2014-04-14 23:15:00,19.69848702 2014-04-14 23:20:00,20.6595252081 2014-04-14 23:25:00,18.2871637028 2014-04-14 23:30:00,19.3373840689 2014-04-14 23:35:00,18.0746492248 2014-04-14 23:40:00,21.0020136323 2014-04-14 23:45:00,20.5667131193 2014-04-14 23:50:00,18.254192669200002 2014-04-14 23:55:00,21.8631471547 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/art_daily_jumpsup_noised.csv ================================================ timestamp,value 2014-04-01 00:00:00,19.761251902999998 2014-04-01 00:05:00,20.500833287 2014-04-01 00:10:00,19.9616414445 2014-04-01 00:15:00,21.4902660734 2014-04-01 00:20:00,20.1877394098 2014-04-01 00:25:00,19.9231256718 2014-04-01 00:30:00,21.698403961700002 2014-04-01 00:35:00,20.8787583842 2014-04-01 00:40:00,18.4461996294 2014-04-01 00:45:00,18.7108178448 2014-04-01 00:50:00,21.148491451800002 2014-04-01 00:55:00,21.3434052847 2014-04-01 01:00:00,20.1807633164 2014-04-01 01:05:00,20.217820911500002 2014-04-01 01:10:00,20.527731851400002 2014-04-01 01:15:00,19.7564630971 2014-04-01 01:20:00,20.7207964939 2014-04-01 01:25:00,18.4339250303 2014-04-01 01:30:00,21.845116969499998 2014-04-01 01:35:00,21.0006192952 2014-04-01 01:40:00,20.524696816 2014-04-01 01:45:00,19.265288228 2014-04-01 01:50:00,18.6438219498 2014-04-01 01:55:00,19.6373718553 2014-04-01 02:00:00,20.6463069623 2014-04-01 02:05:00,20.534838973699998 2014-04-01 02:10:00,19.530564620299998 2014-04-01 02:15:00,20.4531455753 2014-04-01 02:20:00,21.2549931823 2014-04-01 02:25:00,18.1051390894 2014-04-01 02:30:00,19.8024841917 2014-04-01 02:35:00,21.0342209139 2014-04-01 02:40:00,20.1845778819 2014-04-01 02:45:00,20.6059043517 2014-04-01 02:50:00,20.0667055704 2014-04-01 02:55:00,21.967498178699998 2014-04-01 03:00:00,18.218486146 2014-04-01 03:05:00,19.964179287100002 2014-04-01 03:10:00,18.3656661965 2014-04-01 03:15:00,18.6391422485 2014-04-01 03:20:00,19.5321534017 2014-04-01 03:25:00,18.622160366 2014-04-01 03:30:00,21.854748663800002 2014-04-01 03:35:00,21.7871591069 2014-04-01 03:40:00,19.3444385849 2014-04-01 03:45:00,20.5589908482 2014-04-01 03:50:00,20.1350132824 2014-04-01 03:55:00,21.262347922100002 2014-04-01 04:00:00,20.5097824393 2014-04-01 04:05:00,18.001009818 2014-04-01 04:10:00,21.0526975424 2014-04-01 04:15:00,20.9873924852 2014-04-01 04:20:00,20.0388908223 2014-04-01 04:25:00,21.6116758929 2014-04-01 04:30:00,21.633784822800003 2014-04-01 04:35:00,20.0956467068 2014-04-01 04:40:00,20.4319529248 2014-04-01 04:45:00,21.9860882877 2014-04-01 04:50:00,19.1952809392 2014-04-01 04:55:00,19.2984689692 2014-04-01 05:00:00,18.7310956107 2014-04-01 05:05:00,21.583467756599998 2014-04-01 05:10:00,20.9779535598 2014-04-01 05:15:00,18.4225713955 2014-04-01 05:20:00,21.9270694048 2014-04-01 05:25:00,20.9238468326 2014-04-01 05:30:00,21.4020884384 2014-04-01 05:35:00,18.192603156700002 2014-04-01 05:40:00,20.0198436758 2014-04-01 05:45:00,20.7943931469 2014-04-01 05:50:00,20.1717863383 2014-04-01 05:55:00,20.6665898628 2014-04-01 06:00:00,21.2714962544 2014-04-01 06:05:00,19.497348251800002 2014-04-01 06:10:00,21.3946747025 2014-04-01 06:15:00,18.6516644191 2014-04-01 06:20:00,19.0835442201 2014-04-01 06:25:00,18.1733824797 2014-04-01 06:30:00,19.4577072453 2014-04-01 06:35:00,19.5196381793 2014-04-01 06:40:00,21.221082388800003 2014-04-01 06:45:00,20.612522681199998 2014-04-01 06:50:00,19.7468902326 2014-04-01 06:55:00,20.608455914500002 2014-04-01 07:00:00,18.2111334021 2014-04-01 07:05:00,18.7210861441 2014-04-01 07:10:00,20.507791421 2014-04-01 07:15:00,20.5654672769 2014-04-01 07:20:00,21.0965386348 2014-04-01 07:25:00,19.6119990362 2014-04-01 07:30:00,20.8902163865 2014-04-01 07:35:00,20.7359213302 2014-04-01 07:40:00,21.8535735135 2014-04-01 07:45:00,18.8605209057 2014-04-01 07:50:00,20.206718255 2014-04-01 07:55:00,20.407057768399998 2014-04-01 08:00:00,21.994591539699996 2014-04-01 08:05:00,18.804736568699997 2014-04-01 08:10:00,20.0928720799 2014-04-01 08:15:00,19.384741230899998 2014-04-01 08:20:00,20.103571874300002 2014-04-01 08:25:00,18.928514408399998 2014-04-01 08:30:00,18.1904495137 2014-04-01 08:35:00,20.2902618156 2014-04-01 08:40:00,19.3434172634 2014-04-01 08:45:00,18.727765607000002 2014-04-01 08:50:00,19.2957422643 2014-04-01 08:55:00,18.1971208058 2014-04-01 09:00:00,74.1260143836 2014-04-01 09:05:00,69.10361164359999 2014-04-01 09:10:00,72.2808540663 2014-04-01 09:15:00,66.9544074866 2014-04-01 09:20:00,73.4850794789 2014-04-01 09:25:00,67.7731278131 2014-04-01 09:30:00,69.0056563819 2014-04-01 09:35:00,67.88839812890001 2014-04-01 09:40:00,71.1725848238 2014-04-01 09:45:00,68.9065226554 2014-04-01 09:50:00,64.8937453607 2014-04-01 09:55:00,63.179337626000006 2014-04-01 10:00:00,79.2470505155 2014-04-01 10:05:00,77.4320730032 2014-04-01 10:10:00,71.3295428127 2014-04-01 10:15:00,75.9799830691 2014-04-01 10:20:00,77.8293300694 2014-04-01 10:25:00,82.67338298899999 2014-04-01 10:30:00,71.0210883865 2014-04-01 10:35:00,75.2486478048 2014-04-01 10:40:00,82.6076230245 2014-04-01 10:45:00,79.90353942109999 2014-04-01 10:50:00,74.3401531544 2014-04-01 10:55:00,82.9596010938 2014-04-01 11:00:00,79.41334110529999 2014-04-01 11:05:00,79.4937884794 2014-04-01 11:10:00,87.0996450426 2014-04-01 11:15:00,86.6309408675 2014-04-01 11:20:00,77.2701037963 2014-04-01 11:25:00,73.8037704623 2014-04-01 11:30:00,76.7474037102 2014-04-01 11:35:00,72.052805772 2014-04-01 11:40:00,71.8982924702 2014-04-01 11:45:00,77.8583840549 2014-04-01 11:50:00,86.5339792602 2014-04-01 11:55:00,85.426067155 2014-04-01 12:00:00,80.08686564029999 2014-04-01 12:05:00,80.9463697522 2014-04-01 12:10:00,72.0084220248 2014-04-01 12:15:00,75.3574808711 2014-04-01 12:20:00,72.3095103677 2014-04-01 12:25:00,83.9717453641 2014-04-01 12:30:00,74.2411363371 2014-04-01 12:35:00,85.8016679353 2014-04-01 12:40:00,82.194437192 2014-04-01 12:45:00,75.5798939857 2014-04-01 12:50:00,74.4340968432 2014-04-01 12:55:00,81.94354482050001 2014-04-01 13:00:00,86.3926524705 2014-04-01 13:05:00,83.47372499939999 2014-04-01 13:10:00,77.5581280065 2014-04-01 13:15:00,81.3786019713 2014-04-01 13:20:00,76.953713801 2014-04-01 13:25:00,87.9652763341 2014-04-01 13:30:00,83.9612714729 2014-04-01 13:35:00,81.81046701060001 2014-04-01 13:40:00,78.7532409691 2014-04-01 13:45:00,81.8707829394 2014-04-01 13:50:00,77.4472651938 2014-04-01 13:55:00,72.4444465903 2014-04-01 14:00:00,78.31765692970001 2014-04-01 14:05:00,86.883522504 2014-04-01 14:10:00,82.0168805171 2014-04-01 14:15:00,73.3397707712 2014-04-01 14:20:00,86.15576213920002 2014-04-01 14:25:00,76.2983350936 2014-04-01 14:30:00,75.89666867439999 2014-04-01 14:35:00,76.7497713346 2014-04-01 14:40:00,81.2313364867 2014-04-01 14:45:00,80.7111351745 2014-04-01 14:50:00,79.8587866682 2014-04-01 14:55:00,83.4765827479 2014-04-01 15:00:00,77.06386388119998 2014-04-01 15:05:00,84.51222102 2014-04-01 15:10:00,74.8044287246 2014-04-01 15:15:00,84.5211212147 2014-04-01 15:20:00,82.6201685228 2014-04-01 15:25:00,82.930536812 2014-04-01 15:30:00,79.7040891874 2014-04-01 15:35:00,82.6712308715 2014-04-01 15:40:00,73.2760492881 2014-04-01 15:45:00,85.6239958745 2014-04-01 15:50:00,72.8880560037 2014-04-01 15:55:00,74.3791501112 2014-04-01 16:00:00,81.228479377 2014-04-01 16:05:00,83.83042233260001 2014-04-01 16:10:00,73.2198844471 2014-04-01 16:15:00,86.73207050010002 2014-04-01 16:20:00,87.5775542316 2014-04-01 16:25:00,81.69504591329998 2014-04-01 16:30:00,79.6997422622 2014-04-01 16:35:00,83.8621585408 2014-04-01 16:40:00,77.2535693101 2014-04-01 16:45:00,79.8920775526 2014-04-01 16:50:00,86.6582500449 2014-04-01 16:55:00,87.29031920610001 2014-04-01 17:00:00,86.8330725129 2014-04-01 17:05:00,76.19913981090001 2014-04-01 17:10:00,75.7194755672 2014-04-01 17:15:00,76.762602618 2014-04-01 17:20:00,79.0609474388 2014-04-01 17:25:00,77.02664902640001 2014-04-01 17:30:00,77.98737478470001 2014-04-01 17:35:00,81.93015977270001 2014-04-01 17:40:00,84.20037850050001 2014-04-01 17:45:00,83.768899005 2014-04-01 17:50:00,85.0307444214 2014-04-01 17:55:00,72.5149226057 2014-04-01 18:00:00,29.105490665700003 2014-04-01 18:05:00,33.8520444488 2014-04-01 18:10:00,32.211698278200004 2014-04-01 18:15:00,32.5000940721 2014-04-01 18:20:00,29.1365503112 2014-04-01 18:25:00,30.4340024842 2014-04-01 18:30:00,32.8854612373 2014-04-01 18:35:00,34.2987575113 2014-04-01 18:40:00,34.6686870856 2014-04-01 18:45:00,32.0026786288 2014-04-01 18:50:00,32.2910288896 2014-04-01 18:55:00,34.131511085599996 2014-04-01 19:00:00,22.568556973299998 2014-04-01 19:05:00,22.4755249615 2014-04-01 19:10:00,24.2147751608 2014-04-01 19:15:00,23.698897290300003 2014-04-01 19:20:00,24.232643588800002 2014-04-01 19:25:00,21.1377456459 2014-04-01 19:30:00,22.5092009454 2014-04-01 19:35:00,23.9342738231 2014-04-01 19:40:00,20.6579411338 2014-04-01 19:45:00,23.72008515 2014-04-01 19:50:00,20.9797196068 2014-04-01 19:55:00,23.7803707178 2014-04-01 20:00:00,20.938755589 2014-04-01 20:05:00,19.2234943904 2014-04-01 20:10:00,20.3708584741 2014-04-01 20:15:00,21.2250833071 2014-04-01 20:20:00,21.0282612297 2014-04-01 20:25:00,20.1820042736 2014-04-01 20:30:00,22.1158050371 2014-04-01 20:35:00,20.558902699 2014-04-01 20:40:00,20.5040322087 2014-04-01 20:45:00,18.6869781922 2014-04-01 20:50:00,22.2090048501 2014-04-01 20:55:00,19.1574692354 2014-04-01 21:00:00,20.2099229424 2014-04-01 21:05:00,21.3160988514 2014-04-01 21:10:00,18.9523497644 2014-04-01 21:15:00,20.2060186776 2014-04-01 21:20:00,19.0537607405 2014-04-01 21:25:00,21.1397660835 2014-04-01 21:30:00,20.3545999721 2014-04-01 21:35:00,21.526738125399998 2014-04-01 21:40:00,21.6818074721 2014-04-01 21:45:00,20.693789562 2014-04-01 21:50:00,21.0018924452 2014-04-01 21:55:00,20.2938253758 2014-04-01 22:00:00,19.556471129000002 2014-04-01 22:05:00,20.6122404548 2014-04-01 22:10:00,21.6539223116 2014-04-01 22:15:00,19.6856015647 2014-04-01 22:20:00,19.2761274305 2014-04-01 22:25:00,19.5725193424 2014-04-01 22:30:00,19.760542437999998 2014-04-01 22:35:00,18.3118065813 2014-04-01 22:40:00,20.0129613686 2014-04-01 22:45:00,19.9964351491 2014-04-01 22:50:00,20.3733149249 2014-04-01 22:55:00,19.4699533412 2014-04-01 23:00:00,20.4563572484 2014-04-01 23:05:00,21.516995709099998 2014-04-01 23:10:00,21.8260737616 2014-04-01 23:15:00,20.338353076700002 2014-04-01 23:20:00,18.173852523900003 2014-04-01 23:25:00,21.8811443602 2014-04-01 23:30:00,20.8274463436 2014-04-01 23:35:00,19.3475686124 2014-04-01 23:40:00,18.5921998191 2014-04-01 23:45:00,18.5772405926 2014-04-01 23:50:00,18.6745624504 2014-04-01 23:55:00,18.185781084400002 2014-04-02 00:00:00,21.6086167546 2014-04-02 00:05:00,20.1630729313 2014-04-02 00:10:00,20.7998376509 2014-04-02 00:15:00,21.3124340371 2014-04-02 00:20:00,21.1661640253 2014-04-02 00:25:00,21.530422494899998 2014-04-02 00:30:00,21.869018490100004 2014-04-02 00:35:00,19.756282459 2014-04-02 00:40:00,21.8013418667 2014-04-02 00:45:00,20.8931597934 2014-04-02 00:50:00,18.2826727612 2014-04-02 00:55:00,20.7271324848 2014-04-02 01:00:00,20.7468666384 2014-04-02 01:05:00,21.6234422552 2014-04-02 01:10:00,19.4917285299 2014-04-02 01:15:00,20.3396460011 2014-04-02 01:20:00,18.048750204 2014-04-02 01:25:00,19.3283009687 2014-04-02 01:30:00,18.2489749046 2014-04-02 01:35:00,20.087491891099997 2014-04-02 01:40:00,21.269790602 2014-04-02 01:45:00,18.8257707685 2014-04-02 01:50:00,20.1097641822 2014-04-02 01:55:00,18.816034545999997 2014-04-02 02:00:00,18.4827538714 2014-04-02 02:05:00,20.0439871677 2014-04-02 02:10:00,18.3165944838 2014-04-02 02:15:00,20.3494185246 2014-04-02 02:20:00,18.1253498427 2014-04-02 02:25:00,18.4268598875 2014-04-02 02:30:00,20.1999899419 2014-04-02 02:35:00,20.365629651600003 2014-04-02 02:40:00,18.1159477204 2014-04-02 02:45:00,20.293507152 2014-04-02 02:50:00,21.354010101300002 2014-04-02 02:55:00,20.8892647092 2014-04-02 03:00:00,18.5247404157 2014-04-02 03:05:00,20.3698985903 2014-04-02 03:10:00,20.6890100003 2014-04-02 03:15:00,18.148924807 2014-04-02 03:20:00,21.4213906747 2014-04-02 03:25:00,21.625069589200002 2014-04-02 03:30:00,21.4018090934 2014-04-02 03:35:00,21.298525872 2014-04-02 03:40:00,20.9798607938 2014-04-02 03:45:00,20.5337281251 2014-04-02 03:50:00,20.71450802 2014-04-02 03:55:00,21.2255811733 2014-04-02 04:00:00,20.6499938334 2014-04-02 04:05:00,19.3109078267 2014-04-02 04:10:00,19.5038444086 2014-04-02 04:15:00,21.588229873499998 2014-04-02 04:20:00,18.0684883432 2014-04-02 04:25:00,20.795282325 2014-04-02 04:30:00,21.819110209699996 2014-04-02 04:35:00,20.8249126798 2014-04-02 04:40:00,21.9756479529 2014-04-02 04:45:00,20.7501796221 2014-04-02 04:50:00,18.1374521169 2014-04-02 04:55:00,21.308039526600002 2014-04-02 05:00:00,19.1385196478 2014-04-02 05:05:00,19.7842289027 2014-04-02 05:10:00,19.2483676636 2014-04-02 05:15:00,19.0742164248 2014-04-02 05:20:00,19.7256228147 2014-04-02 05:25:00,19.5150057938 2014-04-02 05:30:00,20.5333543274 2014-04-02 05:35:00,21.252604804 2014-04-02 05:40:00,19.1883546127 2014-04-02 05:45:00,18.8548846113 2014-04-02 05:50:00,20.6675810835 2014-04-02 05:55:00,20.6812802633 2014-04-02 06:00:00,21.6045249571 2014-04-02 06:05:00,18.063782745799998 2014-04-02 06:10:00,21.4121626485 2014-04-02 06:15:00,20.0840086918 2014-04-02 06:20:00,20.4852083567 2014-04-02 06:25:00,18.3654857622 2014-04-02 06:30:00,19.7304597315 2014-04-02 06:35:00,18.909209629 2014-04-02 06:40:00,19.0169001203 2014-04-02 06:45:00,20.0163804587 2014-04-02 06:50:00,21.2498238016 2014-04-02 06:55:00,20.9751237206 2014-04-02 07:00:00,20.3639998363 2014-04-02 07:05:00,20.157672770999998 2014-04-02 07:10:00,19.7092241729 2014-04-02 07:15:00,21.8908398942 2014-04-02 07:20:00,20.2407702169 2014-04-02 07:25:00,19.0158655932 2014-04-02 07:30:00,18.920363168199998 2014-04-02 07:35:00,20.4454121231 2014-04-02 07:40:00,20.091310109200002 2014-04-02 07:45:00,18.0307912118 2014-04-02 07:50:00,21.3202614888 2014-04-02 07:55:00,20.8164894169 2014-04-02 08:00:00,20.647317158699998 2014-04-02 08:05:00,18.2751226308 2014-04-02 08:10:00,19.448223400699998 2014-04-02 08:15:00,21.741529042899998 2014-04-02 08:20:00,21.4503569654 2014-04-02 08:25:00,19.1421717515 2014-04-02 08:30:00,18.628235536400002 2014-04-02 08:35:00,19.796351828699997 2014-04-02 08:40:00,19.4233215147 2014-04-02 08:45:00,20.7289055068 2014-04-02 08:50:00,21.8657392403 2014-04-02 08:55:00,19.4520057999 2014-04-02 09:00:00,62.046248748100005 2014-04-02 09:05:00,73.4075505135 2014-04-02 09:10:00,61.7161163313 2014-04-02 09:15:00,74.1576162013 2014-04-02 09:20:00,70.2382802209 2014-04-02 09:25:00,74.0069732348 2014-04-02 09:30:00,63.91537173840001 2014-04-02 09:35:00,61.753517215500004 2014-04-02 09:40:00,67.8396557046 2014-04-02 09:45:00,67.3284784382 2014-04-02 09:50:00,65.7082949163 2014-04-02 09:55:00,74.2241280517 2014-04-02 10:00:00,82.6064995231 2014-04-02 10:05:00,80.1077529717 2014-04-02 10:10:00,72.3675606862 2014-04-02 10:15:00,81.2366992956 2014-04-02 10:20:00,81.1232332969 2014-04-02 10:25:00,76.4370580545 2014-04-02 10:30:00,84.1926773188 2014-04-02 10:35:00,72.4314967322 2014-04-02 10:40:00,73.9890789686 2014-04-02 10:45:00,70.8212417452 2014-04-02 10:50:00,82.1853988709 2014-04-02 10:55:00,79.4897056722 2014-04-02 11:00:00,76.5768106216 2014-04-02 11:05:00,74.1732925058 2014-04-02 11:10:00,72.2065101345 2014-04-02 11:15:00,74.2199215234 2014-04-02 11:20:00,78.77703901539998 2014-04-02 11:25:00,75.4991025151 2014-04-02 11:30:00,75.6868525499 2014-04-02 11:35:00,85.4931665355 2014-04-02 11:40:00,79.7607495587 2014-04-02 11:45:00,83.16602338060001 2014-04-02 11:50:00,72.1359469333 2014-04-02 11:55:00,77.3755580087 2014-04-02 12:00:00,79.5711095069 2014-04-02 12:05:00,74.89269047970001 2014-04-02 12:10:00,73.83435698550001 2014-04-02 12:15:00,85.82175062350001 2014-04-02 12:20:00,86.92646894639999 2014-04-02 12:25:00,73.1729940801 2014-04-02 12:30:00,77.4911982414 2014-04-02 12:35:00,87.22777096629999 2014-04-02 12:40:00,73.24259102479999 2014-04-02 12:45:00,82.1995040517 2014-04-02 12:50:00,87.4504752851 2014-04-02 12:55:00,87.5463968029 2014-04-02 13:00:00,79.5204837969 2014-04-02 13:05:00,74.5860807679 2014-04-02 13:10:00,75.2152930359 2014-04-02 13:15:00,86.2129262526 2014-04-02 13:20:00,86.56614720649998 2014-04-02 13:25:00,81.7064600441 2014-04-02 13:30:00,84.2386002741 2014-04-02 13:35:00,83.8187786875 2014-04-02 13:40:00,82.5693241729 2014-04-02 13:45:00,85.21597453439999 2014-04-02 13:50:00,82.9465940072 2014-04-02 13:55:00,80.5247063231 2014-04-02 14:00:00,75.7876638189 2014-04-02 14:05:00,83.8981829998 2014-04-02 14:10:00,79.5711862851 2014-04-02 14:15:00,76.7129845441 2014-04-02 14:20:00,84.8270685171 2014-04-02 14:25:00,83.1434265296 2014-04-02 14:30:00,86.9932571332 2014-04-02 14:35:00,74.6434831811 2014-04-02 14:40:00,82.3830739768 2014-04-02 14:45:00,75.90418791350001 2014-04-02 14:50:00,86.4531778131 2014-04-02 14:55:00,73.5884582126 2014-04-02 15:00:00,82.4977969167 2014-04-02 15:05:00,84.6565588337 2014-04-02 15:10:00,77.6779397305 2014-04-02 15:15:00,87.2653715145 2014-04-02 15:20:00,85.61086908109999 2014-04-02 15:25:00,76.7131563416 2014-04-02 15:30:00,72.11996512510001 2014-04-02 15:35:00,76.74577805130002 2014-04-02 15:40:00,76.5002331182 2014-04-02 15:45:00,86.2386058215 2014-04-02 15:50:00,87.4730991023 2014-04-02 15:55:00,73.1263377559 2014-04-02 16:00:00,79.5405645384 2014-04-02 16:05:00,80.7731568917 2014-04-02 16:10:00,73.486445487 2014-04-02 16:15:00,78.0398135095 2014-04-02 16:20:00,77.0731706975 2014-04-02 16:25:00,80.5767469616 2014-04-02 16:30:00,82.5788958439 2014-04-02 16:35:00,83.25560191689999 2014-04-02 16:40:00,74.1879379367 2014-04-02 16:45:00,85.0070000174 2014-04-02 16:50:00,82.85651339180001 2014-04-02 16:55:00,86.2250331156 2014-04-02 17:00:00,79.1893465422 2014-04-02 17:05:00,86.3022030635 2014-04-02 17:10:00,85.8523529904 2014-04-02 17:15:00,79.0145189762 2014-04-02 17:20:00,178.0982630549 2014-04-02 17:25:00,86.92495886030001 2014-04-02 17:30:00,83.44260371060001 2014-04-02 17:35:00,86.8518921919 2014-04-02 17:40:00,84.75156391770001 2014-04-02 17:45:00,81.7487276371 2014-04-02 17:50:00,73.8536160723 2014-04-02 17:55:00,76.6636613224 2014-04-02 18:00:00,35.000584685300005 2014-04-02 18:05:00,30.844295509699997 2014-04-02 18:10:00,29.396825522399997 2014-04-02 18:15:00,33.3283350788 2014-04-02 18:20:00,33.4976207975 2014-04-02 18:25:00,30.626923529499997 2014-04-02 18:30:00,30.7050947724 2014-04-02 18:35:00,31.80090900150001 2014-04-02 18:40:00,28.939443722100002 2014-04-02 18:45:00,33.851660766799995 2014-04-02 18:50:00,30.8293623193 2014-04-02 18:55:00,34.264077274099996 2014-04-02 19:00:00,23.7557829856 2014-04-02 19:05:00,23.123079839899997 2014-04-02 19:10:00,21.6154382188 2014-04-02 19:15:00,22.473096963400003 2014-04-02 19:20:00,22.1528338588 2014-04-02 19:25:00,21.678189661199998 2014-04-02 19:30:00,23.9596492617 2014-04-02 19:35:00,22.3261104694 2014-04-02 19:40:00,23.890598167600004 2014-04-02 19:45:00,20.6313776324 2014-04-02 19:50:00,20.7917899124 2014-04-02 19:55:00,24.5383936208 2014-04-02 20:00:00,20.8394993728 2014-04-02 20:05:00,20.5200163364 2014-04-02 20:10:00,20.5748469877 2014-04-02 20:15:00,19.3137406667 2014-04-02 20:20:00,21.3758111207 2014-04-02 20:25:00,18.7792612094 2014-04-02 20:30:00,20.7803336795 2014-04-02 20:35:00,20.7698687416 2014-04-02 20:40:00,22.176515519099997 2014-04-02 20:45:00,20.5872445431 2014-04-02 20:50:00,18.9934085748 2014-04-02 20:55:00,20.7779971005 2014-04-02 21:00:00,18.4534640231 2014-04-02 21:05:00,18.905488136600002 2014-04-02 21:10:00,18.211431577 2014-04-02 21:15:00,20.1494295173 2014-04-02 21:20:00,18.4261534423 2014-04-02 21:25:00,19.972989837300002 2014-04-02 21:30:00,21.836092632600003 2014-04-02 21:35:00,20.9792650199 2014-04-02 21:40:00,18.397532956 2014-04-02 21:45:00,18.9875440308 2014-04-02 21:50:00,20.7939839472 2014-04-02 21:55:00,21.6823856668 2014-04-02 22:00:00,18.1490807455 2014-04-02 22:05:00,21.270204328800002 2014-04-02 22:10:00,20.266692876700002 2014-04-02 22:15:00,20.203742282 2014-04-02 22:20:00,21.8522107229 2014-04-02 22:25:00,21.0107293954 2014-04-02 22:30:00,21.4210199182 2014-04-02 22:35:00,19.4346216116 2014-04-02 22:40:00,20.2368649113 2014-04-02 22:45:00,20.4812658575 2014-04-02 22:50:00,19.3048506343 2014-04-02 22:55:00,20.3004622426 2014-04-02 23:00:00,18.9502592674 2014-04-02 23:05:00,18.577068795 2014-04-02 23:10:00,19.4996242444 2014-04-02 23:15:00,20.9611822874 2014-04-02 23:20:00,21.6689082219 2014-04-02 23:25:00,19.8346637284 2014-04-02 23:30:00,20.5752444397 2014-04-02 23:35:00,18.4156836546 2014-04-02 23:40:00,21.6220056603 2014-04-02 23:45:00,20.2783095403 2014-04-02 23:50:00,21.1254082882 2014-04-02 23:55:00,21.1818309324 2014-04-03 00:00:00,19.0259221055 2014-04-03 00:05:00,20.1166978127 2014-04-03 00:10:00,21.841919006199998 2014-04-03 00:15:00,18.3585381793 2014-04-03 00:20:00,20.7321995921 2014-04-03 00:25:00,21.8490563121 2014-04-03 00:30:00,19.2023084322 2014-04-03 00:35:00,21.4457916856 2014-04-03 00:40:00,21.7346301816 2014-04-03 00:45:00,20.9883448376 2014-04-03 00:50:00,18.925313249200002 2014-04-03 00:55:00,19.3360028753 2014-04-03 01:00:00,18.1432371777 2014-04-03 01:05:00,21.325812937000002 2014-04-03 01:10:00,21.398444746 2014-04-03 01:15:00,20.5308412399 2014-04-03 01:20:00,19.4101114051 2014-04-03 01:25:00,18.3072441106 2014-04-03 01:30:00,21.0122304397 2014-04-03 01:35:00,20.9061047744 2014-04-03 01:40:00,21.650410086999997 2014-04-03 01:45:00,20.922128084 2014-04-03 01:50:00,21.314779769 2014-04-03 01:55:00,20.9838184716 2014-04-03 02:00:00,20.5227487532 2014-04-03 02:05:00,19.7078655768 2014-04-03 02:10:00,21.6084692346 2014-04-03 02:15:00,20.6038742876 2014-04-03 02:20:00,19.5934212879 2014-04-03 02:25:00,18.3338771807 2014-04-03 02:30:00,19.1628194236 2014-04-03 02:35:00,20.1749069393 2014-04-03 02:40:00,19.1025414801 2014-04-03 02:45:00,18.8849413917 2014-04-03 02:50:00,20.1095740564 2014-04-03 02:55:00,18.6792813836 2014-04-03 03:00:00,21.2016402533 2014-04-03 03:05:00,19.9374726054 2014-04-03 03:10:00,20.2954510959 2014-04-03 03:15:00,18.589533070399998 2014-04-03 03:20:00,19.2983053425 2014-04-03 03:25:00,19.640358733 2014-04-03 03:30:00,21.2328513221 2014-04-03 03:35:00,21.0806380923 2014-04-03 03:40:00,18.8919098992 2014-04-03 03:45:00,20.4647163264 2014-04-03 03:50:00,18.9738254311 2014-04-03 03:55:00,21.952988622800003 2014-04-03 04:00:00,21.8084955125 2014-04-03 04:05:00,20.2530588821 2014-04-03 04:10:00,20.7956102876 2014-04-03 04:15:00,21.2057215288 2014-04-03 04:20:00,20.8839936802 2014-04-03 04:25:00,20.7993147643 2014-04-03 04:30:00,21.834216031799997 2014-04-03 04:35:00,20.3858244252 2014-04-03 04:40:00,20.5452106873 2014-04-03 04:45:00,21.3970750018 2014-04-03 04:50:00,20.6795634714 2014-04-03 04:55:00,20.931730488099998 2014-04-03 05:00:00,18.9366747448 2014-04-03 05:05:00,19.4850676965 2014-04-03 05:10:00,18.5892053828 2014-04-03 05:15:00,20.0230617693 2014-04-03 05:20:00,19.8229096027 2014-04-03 05:25:00,21.9886512571 2014-04-03 05:30:00,20.444834611300003 2014-04-03 05:35:00,21.1457792928 2014-04-03 05:40:00,19.336058683 2014-04-03 05:45:00,21.3261813254 2014-04-03 05:50:00,20.460339865999998 2014-04-03 05:55:00,20.787969326400003 2014-04-03 06:00:00,19.177723111800002 2014-04-03 06:05:00,20.1945535668 2014-04-03 06:10:00,20.536147893699997 2014-04-03 06:15:00,20.3563787033 2014-04-03 06:20:00,21.6607748457 2014-04-03 06:25:00,21.593090658 2014-04-03 06:30:00,21.8839362315 2014-04-03 06:35:00,20.669712024000003 2014-04-03 06:40:00,21.887656520500002 2014-04-03 06:45:00,21.3299120001 2014-04-03 06:50:00,19.083328561400002 2014-04-03 06:55:00,19.709742678199998 2014-04-03 07:00:00,18.9535697688 2014-04-03 07:05:00,18.0167886433 2014-04-03 07:10:00,18.7521950126 2014-04-03 07:15:00,18.0162423451 2014-04-03 07:20:00,20.8793538454 2014-04-03 07:25:00,19.7021371909 2014-04-03 07:30:00,19.2502989083 2014-04-03 07:35:00,21.0468835644 2014-04-03 07:40:00,21.3299470985 2014-04-03 07:45:00,21.9011981546 2014-04-03 07:50:00,20.568054338699998 2014-04-03 07:55:00,19.8461158342 2014-04-03 08:00:00,19.2210572064 2014-04-03 08:05:00,18.889272836900002 2014-04-03 08:10:00,18.8517038019 2014-04-03 08:15:00,19.6367574989 2014-04-03 08:20:00,21.967145421199998 2014-04-03 08:25:00,18.0034147897 2014-04-03 08:30:00,18.7888235889 2014-04-03 08:35:00,18.7535719296 2014-04-03 08:40:00,20.8684779421 2014-04-03 08:45:00,19.4099389104 2014-04-03 08:50:00,19.8290432184 2014-04-03 08:55:00,18.594496521900002 2014-04-03 09:00:00,66.7079597287 2014-04-03 09:05:00,62.603517441899996 2014-04-03 09:10:00,68.4493887153 2014-04-03 09:15:00,62.5319617692 2014-04-03 09:20:00,71.950913984 2014-04-03 09:25:00,68.90578335859999 2014-04-03 09:30:00,71.0459630833 2014-04-03 09:35:00,66.8918228585 2014-04-03 09:40:00,66.3882815881 2014-04-03 09:45:00,62.535640891099995 2014-04-03 09:50:00,68.3244362558 2014-04-03 09:55:00,68.1972294421 2014-04-03 10:00:00,77.1049437299 2014-04-03 10:05:00,81.33284501989999 2014-04-03 10:10:00,82.76046828850001 2014-04-03 10:15:00,81.4922557552 2014-04-03 10:20:00,72.0727963284 2014-04-03 10:25:00,79.4943635841 2014-04-03 10:30:00,71.0866146003 2014-04-03 10:35:00,80.6205379011 2014-04-03 10:40:00,75.7661427786 2014-04-03 10:45:00,71.8963838013 2014-04-03 10:50:00,83.2190293003 2014-04-03 10:55:00,79.3694094219 2014-04-03 11:00:00,77.2095458902 2014-04-03 11:05:00,72.0566850652 2014-04-03 11:10:00,80.1133823592 2014-04-03 11:15:00,86.2509843714 2014-04-03 11:20:00,81.0528248593 2014-04-03 11:25:00,87.0211312159 2014-04-03 11:30:00,73.738118585 2014-04-03 11:35:00,80.60632438350001 2014-04-03 11:40:00,84.2613807635 2014-04-03 11:45:00,79.9261997878 2014-04-03 11:50:00,73.01631932560001 2014-04-03 11:55:00,80.8382189686 2014-04-03 12:00:00,81.6896611257 2014-04-03 12:05:00,83.55895675800001 2014-04-03 12:10:00,84.0783689816 2014-04-03 12:15:00,84.2311641758 2014-04-03 12:20:00,82.5159721659 2014-04-03 12:25:00,75.3624354079 2014-04-03 12:30:00,78.3736107669 2014-04-03 12:35:00,84.3167778664 2014-04-03 12:40:00,87.15012593629999 2014-04-03 12:45:00,73.17523565569999 2014-04-03 12:50:00,80.4719045405 2014-04-03 12:55:00,76.90795591359999 2014-04-03 13:00:00,75.5881567965 2014-04-03 13:05:00,80.0737486233 2014-04-03 13:10:00,81.6778220658 2014-04-03 13:15:00,72.1390381773 2014-04-03 13:20:00,84.463029162 2014-04-03 13:25:00,85.0976857528 2014-04-03 13:30:00,87.4271856315 2014-04-03 13:35:00,74.8723260597 2014-04-03 13:40:00,81.4932779159 2014-04-03 13:45:00,78.8070877342 2014-04-03 13:50:00,77.3386798859 2014-04-03 13:55:00,81.0306831905 2014-04-03 14:00:00,84.5140726214 2014-04-03 14:05:00,72.3653708306 2014-04-03 14:10:00,87.5062013018 2014-04-03 14:15:00,84.9540273822 2014-04-03 14:20:00,84.0144263723 2014-04-03 14:25:00,84.1621581374 2014-04-03 14:30:00,78.2212165553 2014-04-03 14:35:00,84.0218955689 2014-04-03 14:40:00,78.1845702981 2014-04-03 14:45:00,86.37516306639999 2014-04-03 14:50:00,74.83196602609999 2014-04-03 14:55:00,76.6738782646 2014-04-03 15:00:00,80.8206247977 2014-04-03 15:05:00,77.1066363434 2014-04-03 15:10:00,78.7870395619 2014-04-03 15:15:00,79.8779961943 2014-04-03 15:20:00,85.7008308451 2014-04-03 15:25:00,80.3703044954 2014-04-03 15:30:00,77.798610704 2014-04-03 15:35:00,75.96304937229999 2014-04-03 15:40:00,78.538061688 2014-04-03 15:45:00,80.2510072536 2014-04-03 15:50:00,83.937031912 2014-04-03 15:55:00,73.9360706257 2014-04-03 16:00:00,75.545601964 2014-04-03 16:05:00,78.0743143509 2014-04-03 16:10:00,77.76622517050001 2014-04-03 16:15:00,78.2678191272 2014-04-03 16:20:00,84.6961776173 2014-04-03 16:25:00,77.18632224939999 2014-04-03 16:30:00,80.0302172281 2014-04-03 16:35:00,81.98235511930001 2014-04-03 16:40:00,75.7147114304 2014-04-03 16:45:00,83.498965876 2014-04-03 16:50:00,80.7536260686 2014-04-03 16:55:00,79.1483466434 2014-04-03 17:00:00,84.9565118045 2014-04-03 17:05:00,75.8958950029 2014-04-03 17:10:00,86.1307824556 2014-04-03 17:15:00,80.97674867079998 2014-04-03 17:20:00,81.74676667930001 2014-04-03 17:25:00,86.0009104023 2014-04-03 17:30:00,85.0812903344 2014-04-03 17:35:00,81.6249617572 2014-04-03 17:40:00,84.05097098600001 2014-04-03 17:45:00,78.9330815334 2014-04-03 17:50:00,80.7580130449 2014-04-03 17:55:00,72.993094158 2014-04-03 18:00:00,29.3750850352 2014-04-03 18:05:00,34.108316038000005 2014-04-03 18:10:00,29.1818929934 2014-04-03 18:15:00,29.8841486663 2014-04-03 18:20:00,33.8933225098 2014-04-03 18:25:00,28.807328553 2014-04-03 18:30:00,30.607381828 2014-04-03 18:35:00,32.5378411628 2014-04-03 18:40:00,32.6108733001 2014-04-03 18:45:00,33.7737721281 2014-04-03 18:50:00,32.0379218775 2014-04-03 18:55:00,32.0601658094 2014-04-03 19:00:00,23.409390094299997 2014-04-03 19:05:00,22.393836367 2014-04-03 19:10:00,22.8860388123 2014-04-03 19:15:00,24.1820264992 2014-04-03 19:20:00,21.9584993095 2014-04-03 19:25:00,21.885359117100002 2014-04-03 19:30:00,20.1758983768 2014-04-03 19:35:00,22.908148394899996 2014-04-03 19:40:00,20.2933770319 2014-04-03 19:45:00,22.4185840042 2014-04-03 19:50:00,23.76296607130001 2014-04-03 19:55:00,22.623645154899997 2014-04-03 20:00:00,19.5364294983 2014-04-03 20:05:00,21.6521455944 2014-04-03 20:10:00,19.5367606143 2014-04-03 20:15:00,80.0000000000 2014-04-03 20:20:00,20.9316183813 2014-04-03 20:25:00,19.128304601900002 2014-04-03 20:30:00,22.1394280857 2014-04-03 20:35:00,19.2538362943 2014-04-03 20:40:00,22.4853483859 2014-04-03 20:45:00,18.46194354 2014-04-03 20:50:00,19.511227678599997 2014-04-03 20:55:00,19.2506275466 2014-04-03 21:00:00,18.1426422698 2014-04-03 21:05:00,21.0299330128 2014-04-03 21:10:00,20.8734169327 2014-04-03 21:15:00,21.2710169439 2014-04-03 21:20:00,19.118122751199998 2014-04-03 21:25:00,19.8722718549 2014-04-03 21:30:00,20.735509015399998 2014-04-03 21:35:00,19.8539175223 2014-04-03 21:40:00,20.889091685 2014-04-03 21:45:00,20.634465872699998 2014-04-03 21:50:00,18.5471924045 2014-04-03 21:55:00,21.2255684603 2014-04-03 22:00:00,20.9027528233 2014-04-03 22:05:00,20.6431359444 2014-04-03 22:10:00,18.6382499754 2014-04-03 22:15:00,19.0902948922 2014-04-03 22:20:00,19.5914979165 2014-04-03 22:25:00,19.138073407 2014-04-03 22:30:00,18.9293959449 2014-04-03 22:35:00,21.241803243699998 2014-04-03 22:40:00,20.5726597872 2014-04-03 22:45:00,20.2813399292 2014-04-03 22:50:00,18.9219584925 2014-04-03 22:55:00,21.6931116524 2014-04-03 23:00:00,18.7683349831 2014-04-03 23:05:00,21.1838702515 2014-04-03 23:10:00,21.8708890693 2014-04-03 23:15:00,20.9123853221 2014-04-03 23:20:00,21.975653614099997 2014-04-03 23:25:00,20.6081604731 2014-04-03 23:30:00,18.8734643821 2014-04-03 23:35:00,18.818890506400002 2014-04-03 23:40:00,19.3019624005 2014-04-03 23:45:00,18.031981555 2014-04-03 23:50:00,20.7307734227 2014-04-03 23:55:00,19.0783334735 2014-04-04 00:00:00,21.2607329292 2014-04-04 00:05:00,19.4366906022 2014-04-04 00:10:00,19.9198259739 2014-04-04 00:15:00,21.862755666199998 2014-04-04 00:20:00,18.968688492200002 2014-04-04 00:25:00,20.8850163897 2014-04-04 00:30:00,21.0204711572 2014-04-04 00:35:00,18.8839926301 2014-04-04 00:40:00,20.003987346400002 2014-04-04 00:45:00,19.4008077013 2014-04-04 00:50:00,21.0876249736 2014-04-04 00:55:00,20.4899332761 2014-04-04 01:00:00,19.9039322194 2014-04-04 01:05:00,21.1174530602 2014-04-04 01:10:00,18.94062228 2014-04-04 01:15:00,21.0144875223 2014-04-04 01:20:00,21.4614972484 2014-04-04 01:25:00,21.514486387199998 2014-04-04 01:30:00,21.1346943721 2014-04-04 01:35:00,19.632056668 2014-04-04 01:40:00,21.927232090900002 2014-04-04 01:45:00,19.5183745753 2014-04-04 01:50:00,20.5545015964 2014-04-04 01:55:00,18.6442967123 2014-04-04 02:00:00,21.921795594499997 2014-04-04 02:05:00,20.8159436875 2014-04-04 02:10:00,21.013510180999997 2014-04-04 02:15:00,18.2631068136 2014-04-04 02:20:00,21.0536712569 2014-04-04 02:25:00,21.0988937169 2014-04-04 02:30:00,20.687090905399998 2014-04-04 02:35:00,19.1676384552 2014-04-04 02:40:00,19.958760168599998 2014-04-04 02:45:00,18.4417374852 2014-04-04 02:50:00,19.8863482658 2014-04-04 02:55:00,18.9752954104 2014-04-04 03:00:00,19.396387945999997 2014-04-04 03:05:00,18.650401633599998 2014-04-04 03:10:00,18.920217470999997 2014-04-04 03:15:00,18.3062745673 2014-04-04 03:20:00,21.679605465700003 2014-04-04 03:25:00,20.1216427519 2014-04-04 03:30:00,19.586967885099998 2014-04-04 03:35:00,20.1401168511 2014-04-04 03:40:00,20.5131729139 2014-04-04 03:45:00,21.6875151735 2014-04-04 03:50:00,18.7147718091 2014-04-04 03:55:00,19.1822099945 2014-04-04 04:00:00,21.9031573454 2014-04-04 04:05:00,19.484771946600002 2014-04-04 04:10:00,18.090246603 2014-04-04 04:15:00,18.5905739705 2014-04-04 04:20:00,18.105354807 2014-04-04 04:25:00,21.9596925697 2014-04-04 04:30:00,19.115483396 2014-04-04 04:35:00,21.6941710277 2014-04-04 04:40:00,21.983545103 2014-04-04 04:45:00,20.3993648846 2014-04-04 04:50:00,18.1327852603 2014-04-04 04:55:00,18.326366521500002 2014-04-04 05:00:00,19.9263562204 2014-04-04 05:05:00,19.6246880516 2014-04-04 05:10:00,20.4247092231 2014-04-04 05:15:00,19.7553912388 2014-04-04 05:20:00,21.7363073971 2014-04-04 05:25:00,20.1389588617 2014-04-04 05:30:00,20.7749042458 2014-04-04 05:35:00,21.5859410906 2014-04-04 05:40:00,18.5874875033 2014-04-04 05:45:00,18.9189386165 2014-04-04 05:50:00,18.4292746419 2014-04-04 05:55:00,18.5585535969 2014-04-04 06:00:00,20.0503358677 2014-04-04 06:05:00,19.284717035899998 2014-04-04 06:10:00,19.6926913581 2014-04-04 06:15:00,21.9299593272 2014-04-04 06:20:00,18.6268173912 2014-04-04 06:25:00,20.163248283199998 2014-04-04 06:30:00,18.3954846202 2014-04-04 06:35:00,19.2739852531 2014-04-04 06:40:00,20.1101036947 2014-04-04 06:45:00,21.7865269839 2014-04-04 06:50:00,19.5649128851 2014-04-04 06:55:00,18.2596267849 2014-04-04 07:00:00,19.5526457918 2014-04-04 07:05:00,18.5829647035 2014-04-04 07:10:00,18.9199584532 2014-04-04 07:15:00,20.4723624927 2014-04-04 07:20:00,18.2696954648 2014-04-04 07:25:00,19.858895025 2014-04-04 07:30:00,20.437846344 2014-04-04 07:35:00,19.6874335695 2014-04-04 07:40:00,18.0765054025 2014-04-04 07:45:00,21.9420774276 2014-04-04 07:50:00,19.468463069400002 2014-04-04 07:55:00,21.1143087477 2014-04-04 08:00:00,19.302585968699997 2014-04-04 08:05:00,19.900067028 2014-04-04 08:10:00,19.5538545704 2014-04-04 08:15:00,19.370156918 2014-04-04 08:20:00,18.0874055088 2014-04-04 08:25:00,19.4400837514 2014-04-04 08:30:00,21.557959961599998 2014-04-04 08:35:00,20.7615733544 2014-04-04 08:40:00,18.5816914364 2014-04-04 08:45:00,20.3646200185 2014-04-04 08:50:00,21.5689234398 2014-04-04 08:55:00,20.8001361639 2014-04-04 09:00:00,63.2221077361 2014-04-04 09:05:00,73.0025219556 2014-04-04 09:10:00,65.3009985807 2014-04-04 09:15:00,67.3754355626 2014-04-04 09:20:00,68.3555415318 2014-04-04 09:25:00,72.7668898195 2014-04-04 09:30:00,73.869861934 2014-04-04 09:35:00,73.843279138 2014-04-04 09:40:00,61.3081768654 2014-04-04 09:45:00,73.737683404 2014-04-04 09:50:00,61.9396627376 2014-04-04 09:55:00,64.8145217327 2014-04-04 10:00:00,77.8326115054 2014-04-04 10:05:00,77.2884466933 2014-04-04 10:10:00,79.2250960011 2014-04-04 10:15:00,77.28100547 2014-04-04 10:20:00,84.341510548 2014-04-04 10:25:00,73.5733181243 2014-04-04 10:30:00,74.09286325149999 2014-04-04 10:35:00,84.129852762 2014-04-04 10:40:00,71.0309972533 2014-04-04 10:45:00,79.300383956 2014-04-04 10:50:00,80.4205419761 2014-04-04 10:55:00,77.6860075476 2014-04-04 11:00:00,82.6090638008 2014-04-04 11:05:00,74.3154898902 2014-04-04 11:10:00,85.12826303 2014-04-04 11:15:00,73.7949685653 2014-04-04 11:20:00,77.9425211144 2014-04-04 11:25:00,72.7648968912 2014-04-04 11:30:00,80.2390369975 2014-04-04 11:35:00,82.2196373213 2014-04-04 11:40:00,86.53718888459998 2014-04-04 11:45:00,83.32640285949999 2014-04-04 11:50:00,80.17370078329998 2014-04-04 11:55:00,86.4003410411 2014-04-04 12:00:00,79.5594034214 2014-04-04 12:05:00,80.882115301 2014-04-04 12:10:00,81.439731351 2014-04-04 12:15:00,78.4654040034 2014-04-04 12:20:00,85.3132241814 2014-04-04 12:25:00,74.87285964350001 2014-04-04 12:30:00,80.7804220759 2014-04-04 12:35:00,83.4554652205 2014-04-04 12:40:00,86.3598624075 2014-04-04 12:45:00,86.03932310969999 2014-04-04 12:50:00,80.0436768173 2014-04-04 12:55:00,82.19183451880002 2014-04-04 13:00:00,78.2890099052 2014-04-04 13:05:00,79.4717664035 2014-04-04 13:10:00,86.4794926205 2014-04-04 13:15:00,86.8704099877 2014-04-04 13:20:00,86.3059065391 2014-04-04 13:25:00,74.1961224449 2014-04-04 13:30:00,85.5808000186 2014-04-04 13:35:00,87.15289797959998 2014-04-04 13:40:00,77.7613279144 2014-04-04 13:45:00,80.279069029 2014-04-04 13:50:00,84.4452523672 2014-04-04 13:55:00,80.973811821 2014-04-04 14:00:00,87.89151735200001 2014-04-04 14:05:00,79.2876078546 2014-04-04 14:10:00,83.4190790713 2014-04-04 14:15:00,84.6773935331 2014-04-04 14:20:00,79.90177118300001 2014-04-04 14:25:00,85.70762672779999 2014-04-04 14:30:00,80.7345980126 2014-04-04 14:35:00,78.58264060100001 2014-04-04 14:40:00,73.721639973 2014-04-04 14:45:00,78.29085908 2014-04-04 14:50:00,83.7389636125 2014-04-04 14:55:00,86.7364190389 2014-04-04 15:00:00,76.0261406038 2014-04-04 15:05:00,77.6830225131 2014-04-04 15:10:00,74.4626610573 2014-04-04 15:15:00,83.0507690126 2014-04-04 15:20:00,87.3621761952 2014-04-04 15:25:00,82.25444586729999 2014-04-04 15:30:00,81.8724384971 2014-04-04 15:35:00,80.855062672 2014-04-04 15:40:00,73.4145870642 2014-04-04 15:45:00,83.67125797109999 2014-04-04 15:50:00,81.63200902199999 2014-04-04 15:55:00,82.58283549890001 2014-04-04 16:00:00,86.38081163700001 2014-04-04 16:05:00,84.5432102697 2014-04-04 16:10:00,84.49448180479999 2014-04-04 16:15:00,86.834773579 2014-04-04 16:20:00,87.8387905726 2014-04-04 16:25:00,81.3003676144 2014-04-04 16:30:00,73.7419642717 2014-04-04 16:35:00,79.3459261799 2014-04-04 16:40:00,84.6014559083 2014-04-04 16:45:00,72.4434661045 2014-04-04 16:50:00,72.9100590261 2014-04-04 16:55:00,73.074384215 2014-04-04 17:00:00,83.6965399938 2014-04-04 17:05:00,80.01863532979999 2014-04-04 17:10:00,77.90233718180001 2014-04-04 17:15:00,73.6898444273 2014-04-04 17:20:00,83.71581185640001 2014-04-04 17:25:00,77.1362873485 2014-04-04 17:30:00,76.2451558429 2014-04-04 17:35:00,82.437075569 2014-04-04 17:40:00,80.944143199 2014-04-04 17:45:00,77.79854039439999 2014-04-04 17:50:00,82.2637679436 2014-04-04 17:55:00,76.3395150118 2014-04-04 18:00:00,33.886907168 2014-04-04 18:05:00,30.2676354706 2014-04-04 18:10:00,29.8165555257 2014-04-04 18:15:00,33.8076057297 2014-04-04 18:20:00,33.330502597 2014-04-04 18:25:00,29.9688836905 2014-04-04 18:30:00,29.5439671448 2014-04-04 18:35:00,34.1657476065 2014-04-04 18:40:00,33.7702238022 2014-04-04 18:45:00,30.8944412599 2014-04-04 18:50:00,33.0124570742 2014-04-04 18:55:00,29.5946195117 2014-04-04 19:00:00,22.431572281999998 2014-04-04 19:05:00,20.2439105979 2014-04-04 19:10:00,21.9143752244 2014-04-04 19:15:00,20.4952947159 2014-04-04 19:20:00,22.2886581444 2014-04-04 19:25:00,22.0491325683 2014-04-04 19:30:00,22.1508437042 2014-04-04 19:35:00,20.3630831161 2014-04-04 19:40:00,21.7800400142 2014-04-04 19:45:00,23.5490463521 2014-04-04 19:50:00,21.812735196 2014-04-04 19:55:00,23.363969066 2014-04-04 20:00:00,19.9453846127 2014-04-04 20:05:00,20.1655885104 2014-04-04 20:10:00,20.7417018452 2014-04-04 20:15:00,22.3259929452 2014-04-04 20:20:00,18.8778921629 2014-04-04 20:25:00,18.5668145736 2014-04-04 20:30:00,20.9221923738 2014-04-04 20:35:00,22.3195014084 2014-04-04 20:40:00,22.4859056811 2014-04-04 20:45:00,20.415136512300002 2014-04-04 20:50:00,20.3492620758 2014-04-04 20:55:00,21.0737713521 2014-04-04 21:00:00,20.319607166500003 2014-04-04 21:05:00,20.6349266707 2014-04-04 21:10:00,21.5991784383 2014-04-04 21:15:00,21.0859537048 2014-04-04 21:20:00,20.0834495635 2014-04-04 21:25:00,19.9427255848 2014-04-04 21:30:00,20.657087297100002 2014-04-04 21:35:00,19.9179746496 2014-04-04 21:40:00,19.9263067199 2014-04-04 21:45:00,18.1519366361 2014-04-04 21:50:00,18.7859985351 2014-04-04 21:55:00,20.0498339728 2014-04-04 22:00:00,21.311052815 2014-04-04 22:05:00,19.1332583292 2014-04-04 22:10:00,20.1098606734 2014-04-04 22:15:00,19.3984529839 2014-04-04 22:20:00,18.4368983964 2014-04-04 22:25:00,21.8541537877 2014-04-04 22:30:00,21.4392574181 2014-04-04 22:35:00,18.3315510998 2014-04-04 22:40:00,20.8991930227 2014-04-04 22:45:00,19.4089343147 2014-04-04 22:50:00,22.0004994407 2014-04-04 22:55:00,19.2280352802 2014-04-04 23:00:00,18.9585931307 2014-04-04 23:05:00,20.2754543312 2014-04-04 23:10:00,21.3446020282 2014-04-04 23:15:00,18.7736793399 2014-04-04 23:20:00,20.8416118982 2014-04-04 23:25:00,18.249129490999998 2014-04-04 23:30:00,21.6799007122 2014-04-04 23:35:00,18.3278179283 2014-04-04 23:40:00,21.6610836329 2014-04-04 23:45:00,19.9670619358 2014-04-04 23:50:00,19.7961645832 2014-04-04 23:55:00,21.897431815700003 2014-04-05 00:00:00,21.9615367108 2014-04-05 00:05:00,20.6007125038 2014-04-05 00:10:00,18.5084771674 2014-04-05 00:15:00,20.0246803426 2014-04-05 00:20:00,20.1166524038 2014-04-05 00:25:00,20.0577857125 2014-04-05 00:30:00,20.2779673541 2014-04-05 00:35:00,18.0748988552 2014-04-05 00:40:00,20.8449091259 2014-04-05 00:45:00,20.8495772078 2014-04-05 00:50:00,18.4618791007 2014-04-05 00:55:00,20.2809577698 2014-04-05 01:00:00,20.2734447297 2014-04-05 01:05:00,20.729801680799998 2014-04-05 01:10:00,18.341590768499998 2014-04-05 01:15:00,20.506013229100002 2014-04-05 01:20:00,19.123007803 2014-04-05 01:25:00,20.028011962 2014-04-05 01:30:00,21.0932942108 2014-04-05 01:35:00,20.8225837455 2014-04-05 01:40:00,18.4756120707 2014-04-05 01:45:00,20.3647391485 2014-04-05 01:50:00,21.8764661238 2014-04-05 01:55:00,18.6270777493 2014-04-05 02:00:00,21.4116283509 2014-04-05 02:05:00,20.8101923222 2014-04-05 02:10:00,21.096013251600002 2014-04-05 02:15:00,19.1278333086 2014-04-05 02:20:00,19.1515557175 2014-04-05 02:25:00,21.6240778231 2014-04-05 02:30:00,19.4393281284 2014-04-05 02:35:00,18.252061562799998 2014-04-05 02:40:00,20.4023868143 2014-04-05 02:45:00,18.4992706762 2014-04-05 02:50:00,21.1863849656 2014-04-05 02:55:00,20.56698577 2014-04-05 03:00:00,21.4989060209 2014-04-05 03:05:00,21.1393489991 2014-04-05 03:10:00,18.448454593399997 2014-04-05 03:15:00,19.5242827057 2014-04-05 03:20:00,21.0982409997 2014-04-05 03:25:00,19.6693658931 2014-04-05 03:30:00,21.8894619391 2014-04-05 03:35:00,20.9429617996 2014-04-05 03:40:00,18.061999666800002 2014-04-05 03:45:00,21.5199427662 2014-04-05 03:50:00,18.4032191395 2014-04-05 03:55:00,18.5620948967 2014-04-05 04:00:00,20.9379696024 2014-04-05 04:05:00,21.4598742377 2014-04-05 04:10:00,20.1453985116 2014-04-05 04:15:00,19.156198931800002 2014-04-05 04:20:00,19.405262180999998 2014-04-05 04:25:00,19.3715573184 2014-04-05 04:30:00,19.3067124152 2014-04-05 04:35:00,18.9716386873 2014-04-05 04:40:00,20.435468378499998 2014-04-05 04:45:00,21.601621274299998 2014-04-05 04:50:00,19.2283296523 2014-04-05 04:55:00,18.7467771898 2014-04-05 05:00:00,21.354310665499998 2014-04-05 05:05:00,20.9671333236 2014-04-05 05:10:00,21.723348126199998 2014-04-05 05:15:00,18.6620789424 2014-04-05 05:20:00,18.5770052565 2014-04-05 05:25:00,20.1657175772 2014-04-05 05:30:00,20.457734619300002 2014-04-05 05:35:00,19.9206937674 2014-04-05 05:40:00,20.3958665453 2014-04-05 05:45:00,18.721519075499998 2014-04-05 05:50:00,19.9184550167 2014-04-05 05:55:00,20.6323702438 2014-04-05 06:00:00,19.730825797 2014-04-05 06:05:00,20.717789343299998 2014-04-05 06:10:00,19.8047651222 2014-04-05 06:15:00,19.3343983234 2014-04-05 06:20:00,19.2144201883 2014-04-05 06:25:00,19.643608236 2014-04-05 06:30:00,18.0923584907 2014-04-05 06:35:00,20.674100553800002 2014-04-05 06:40:00,21.3804225639 2014-04-05 06:45:00,19.4185083778 2014-04-05 06:50:00,18.1841325446 2014-04-05 06:55:00,21.9471023895 2014-04-05 07:00:00,19.054793021800002 2014-04-05 07:05:00,18.5064844868 2014-04-05 07:10:00,19.4790100319 2014-04-05 07:15:00,20.9542281625 2014-04-05 07:20:00,19.1756663876 2014-04-05 07:25:00,20.2988128157 2014-04-05 07:30:00,19.6622399777 2014-04-05 07:35:00,18.4710559691 2014-04-05 07:40:00,19.32114805 2014-04-05 07:45:00,20.8994820229 2014-04-05 07:50:00,20.448015589300002 2014-04-05 07:55:00,18.4791135195 2014-04-05 08:00:00,18.653289638900002 2014-04-05 08:05:00,20.5629334372 2014-04-05 08:10:00,21.2536616573 2014-04-05 08:15:00,19.3978979838 2014-04-05 08:20:00,20.3812430074 2014-04-05 08:25:00,18.682574355 2014-04-05 08:30:00,19.245505347599998 2014-04-05 08:35:00,18.0810808227 2014-04-05 08:40:00,21.073103791199998 2014-04-05 08:45:00,19.6040392791 2014-04-05 08:50:00,21.2645022946 2014-04-05 08:55:00,20.8334919841 2014-04-05 09:00:00,72.47092201390001 2014-04-05 09:05:00,65.0849579063 2014-04-05 09:10:00,63.7174787338 2014-04-05 09:15:00,74.4179172841 2014-04-05 09:20:00,70.9556579038 2014-04-05 09:25:00,72.5429748438 2014-04-05 09:30:00,61.3786138825 2014-04-05 09:35:00,66.020678036 2014-04-05 09:40:00,71.3023069919 2014-04-05 09:45:00,62.2605665287 2014-04-05 09:50:00,68.9158230421 2014-04-05 09:55:00,67.0353896374 2014-04-05 10:00:00,70.1134081908 2014-04-05 10:05:00,73.5023409569 2014-04-05 10:10:00,74.2599716703 2014-04-05 10:15:00,71.5760663673 2014-04-05 10:20:00,79.6414528392 2014-04-05 10:25:00,73.6020150394 2014-04-05 10:30:00,74.1486546341 2014-04-05 10:35:00,83.7806630441 2014-04-05 10:40:00,77.0897503986 2014-04-05 10:45:00,75.925828841 2014-04-05 10:50:00,81.0744785146 2014-04-05 10:55:00,83.9572061276 2014-04-05 11:00:00,71.9661778915 2014-04-05 11:05:00,78.69679061560001 2014-04-05 11:10:00,81.2818666871 2014-04-05 11:15:00,76.6344275126 2014-04-05 11:20:00,83.8523724126 2014-04-05 11:25:00,87.0183713256 2014-04-05 11:30:00,86.5722688328 2014-04-05 11:35:00,75.7981863063 2014-04-05 11:40:00,75.1676839803 2014-04-05 11:45:00,86.7959294054 2014-04-05 11:50:00,78.8620274641 2014-04-05 11:55:00,74.8807669879 2014-04-05 12:00:00,83.2119770764 2014-04-05 12:05:00,76.4588643122 2014-04-05 12:10:00,76.1844204592 2014-04-05 12:15:00,85.9647031076 2014-04-05 12:20:00,74.5101468543 2014-04-05 12:25:00,72.9426507989 2014-04-05 12:30:00,76.2154146631 2014-04-05 12:35:00,81.6130732535 2014-04-05 12:40:00,73.8806423677 2014-04-05 12:45:00,79.4500601387 2014-04-05 12:50:00,81.9389488943 2014-04-05 12:55:00,85.4770961312 2014-04-05 13:00:00,75.65975076 2014-04-05 13:05:00,85.0571225642 2014-04-05 13:10:00,75.74031813810001 2014-04-05 13:15:00,82.80838587630002 2014-04-05 13:20:00,78.8718433572 2014-04-05 13:25:00,73.8171795021 2014-04-05 13:30:00,83.40819263350001 2014-04-05 13:35:00,75.4660856883 2014-04-05 13:40:00,74.8080165824 2014-04-05 13:45:00,77.7145108974 2014-04-05 13:50:00,82.4328552816 2014-04-05 13:55:00,75.7257651142 2014-04-05 14:00:00,74.9349875684 2014-04-05 14:05:00,72.155794367 2014-04-05 14:10:00,79.5424713317 2014-04-05 14:15:00,78.8545439092 2014-04-05 14:20:00,75.73824828779999 2014-04-05 14:25:00,72.8549374193 2014-04-05 14:30:00,78.864308325 2014-04-05 14:35:00,84.6072204356 2014-04-05 14:40:00,83.4405087646 2014-04-05 14:45:00,85.76860114729999 2014-04-05 14:50:00,72.1498596439 2014-04-05 14:55:00,87.4585108588 2014-04-05 15:00:00,77.4618524011 2014-04-05 15:05:00,87.8455214124 2014-04-05 15:10:00,76.0411813673 2014-04-05 15:15:00,79.5438185733 2014-04-05 15:20:00,77.6620972619 2014-04-05 15:25:00,77.6914255951 2014-04-05 15:30:00,85.4756930054 2014-04-05 15:35:00,83.9418971858 2014-04-05 15:40:00,87.8735793692 2014-04-05 15:45:00,81.8154494876 2014-04-05 15:50:00,79.4113433141 2014-04-05 15:55:00,73.44047677180001 2014-04-05 16:00:00,87.94481385790002 2014-04-05 16:05:00,80.8243352639 2014-04-05 16:10:00,83.2074797564 2014-04-05 16:15:00,78.5077274599 2014-04-05 16:20:00,80.763296265 2014-04-05 16:25:00,87.08107651430002 2014-04-05 16:30:00,74.6625676545 2014-04-05 16:35:00,76.6778141276 2014-04-05 16:40:00,74.4328127332 2014-04-05 16:45:00,84.67529188399999 2014-04-05 16:50:00,72.9925840207 2014-04-05 16:55:00,73.3059656499 2014-04-05 17:00:00,76.7758763227 2014-04-05 17:05:00,80.2269800876 2014-04-05 17:10:00,78.5003666648 2014-04-05 17:15:00,72.7170330474 2014-04-05 17:20:00,87.3198313951 2014-04-05 17:25:00,87.2458788233 2014-04-05 17:30:00,76.4696718075 2014-04-05 17:35:00,83.7043777018 2014-04-05 17:40:00,81.2571753794 2014-04-05 17:45:00,75.79959801300001 2014-04-05 17:50:00,76.1947155691 2014-04-05 17:55:00,79.8584201233 2014-04-05 18:00:00,31.4831103808 2014-04-05 18:05:00,30.6638618132 2014-04-05 18:10:00,33.9680676945 2014-04-05 18:15:00,31.8813565517 2014-04-05 18:20:00,32.991021265 2014-04-05 18:25:00,30.0113446389 2014-04-05 18:30:00,32.2144428549 2014-04-05 18:35:00,30.83504079610001 2014-04-05 18:40:00,32.1690409301 2014-04-05 18:45:00,33.7972788448 2014-04-05 18:50:00,33.7210380701 2014-04-05 18:55:00,31.067006374600002 2014-04-05 19:00:00,23.270360208000003 2014-04-05 19:05:00,24.3769776405 2014-04-05 19:10:00,22.9629973384 2014-04-05 19:15:00,20.8248762104 2014-04-05 19:20:00,23.205093386199998 2014-04-05 19:25:00,20.629970519100002 2014-04-05 19:30:00,24.0670533111 2014-04-05 19:35:00,22.4746377883 2014-04-05 19:40:00,21.8854292981 2014-04-05 19:45:00,20.4153884241 2014-04-05 19:50:00,21.865909931500006 2014-04-05 19:55:00,24.2063645444 2014-04-05 20:00:00,18.5179461306 2014-04-05 20:05:00,20.3761586098 2014-04-05 20:10:00,22.246023274200002 2014-04-05 20:15:00,20.0492684944 2014-04-05 20:20:00,20.1858073736 2014-04-05 20:25:00,20.8017817365 2014-04-05 20:30:00,20.3281910744 2014-04-05 20:35:00,19.1225922978 2014-04-05 20:40:00,18.508003265899998 2014-04-05 20:45:00,20.9297882999 2014-04-05 20:50:00,22.2036235139 2014-04-05 20:55:00,18.8676672625 2014-04-05 21:00:00,18.9342611229 2014-04-05 21:05:00,19.574426301600003 2014-04-05 21:10:00,21.3368967147 2014-04-05 21:15:00,19.1686110171 2014-04-05 21:20:00,21.6315530088 2014-04-05 21:25:00,18.307286645 2014-04-05 21:30:00,21.868292798699997 2014-04-05 21:35:00,20.3401546056 2014-04-05 21:40:00,20.734159194700002 2014-04-05 21:45:00,19.5642176811 2014-04-05 21:50:00,21.2293913804 2014-04-05 21:55:00,18.755863026500002 2014-04-05 22:00:00,18.2131151136 2014-04-05 22:05:00,19.6008665479 2014-04-05 22:10:00,21.4353410369 2014-04-05 22:15:00,21.0398862553 2014-04-05 22:20:00,20.087889751 2014-04-05 22:25:00,20.3080279876 2014-04-05 22:30:00,18.5373500845 2014-04-05 22:35:00,21.383234241 2014-04-05 22:40:00,21.1681406466 2014-04-05 22:45:00,20.6456824117 2014-04-05 22:50:00,19.8838343091 2014-04-05 22:55:00,21.878820586 2014-04-05 23:00:00,21.5202589819 2014-04-05 23:05:00,20.5816728947 2014-04-05 23:10:00,19.4909455321 2014-04-05 23:15:00,20.476019753800003 2014-04-05 23:20:00,20.3056616428 2014-04-05 23:25:00,19.5807267273 2014-04-05 23:30:00,19.2303874105 2014-04-05 23:35:00,19.631811751300003 2014-04-05 23:40:00,20.2995423861 2014-04-05 23:45:00,19.7163241845 2014-04-05 23:50:00,19.057956376099998 2014-04-05 23:55:00,21.047893688800002 2014-04-06 00:00:00,20.1258699838 2014-04-06 00:05:00,18.2707006529 2014-04-06 00:10:00,19.4732660225 2014-04-06 00:15:00,21.539653828800002 2014-04-06 00:20:00,21.020946124800002 2014-04-06 00:25:00,19.2929871358 2014-04-06 00:30:00,21.752732608200002 2014-04-06 00:35:00,18.3064116334 2014-04-06 00:40:00,21.8449388156 2014-04-06 00:45:00,18.9828203699 2014-04-06 00:50:00,18.0363767212 2014-04-06 00:55:00,19.7352321461 2014-04-06 01:00:00,19.4358817187 2014-04-06 01:05:00,20.1563560208 2014-04-06 01:10:00,21.1870914423 2014-04-06 01:15:00,21.3697232086 2014-04-06 01:20:00,19.6049199984 2014-04-06 01:25:00,19.7193829748 2014-04-06 01:30:00,18.5927109213 2014-04-06 01:35:00,18.1901904355 2014-04-06 01:40:00,20.564859960899998 2014-04-06 01:45:00,18.2577505022 2014-04-06 01:50:00,20.9353204777 2014-04-06 01:55:00,20.1563605801 2014-04-06 02:00:00,18.7943319129 2014-04-06 02:05:00,20.1580917741 2014-04-06 02:10:00,18.7319908664 2014-04-06 02:15:00,19.75494883 2014-04-06 02:20:00,21.198241265 2014-04-06 02:25:00,19.847677173599998 2014-04-06 02:30:00,18.5947972732 2014-04-06 02:35:00,20.8953147273 2014-04-06 02:40:00,18.7470736651 2014-04-06 02:45:00,20.9541994975 2014-04-06 02:50:00,19.9174091569 2014-04-06 02:55:00,19.814967036400002 2014-04-06 03:00:00,21.4057401514 2014-04-06 03:05:00,20.8344140974 2014-04-06 03:10:00,18.131643187799998 2014-04-06 03:15:00,19.1846972584 2014-04-06 03:20:00,21.4836826434 2014-04-06 03:25:00,18.0733046742 2014-04-06 03:30:00,20.181013785 2014-04-06 03:35:00,20.9113026767 2014-04-06 03:40:00,20.4874243419 2014-04-06 03:45:00,21.042128808399998 2014-04-06 03:50:00,20.9027673957 2014-04-06 03:55:00,20.7681227806 2014-04-06 04:00:00,21.286159443699997 2014-04-06 04:05:00,20.5827626738 2014-04-06 04:10:00,19.609673977 2014-04-06 04:15:00,19.8876364397 2014-04-06 04:20:00,20.8668991307 2014-04-06 04:25:00,21.5052241187 2014-04-06 04:30:00,19.0888752034 2014-04-06 04:35:00,19.3683071839 2014-04-06 04:40:00,21.7229575854 2014-04-06 04:45:00,20.314047169600002 2014-04-06 04:50:00,18.7158472685 2014-04-06 04:55:00,20.6547805556 2014-04-06 05:00:00,21.9630486222 2014-04-06 05:05:00,21.2938142579 2014-04-06 05:10:00,20.982964546199998 2014-04-06 05:15:00,18.8321866171 2014-04-06 05:20:00,21.5045591387 2014-04-06 05:25:00,20.1031553741 2014-04-06 05:30:00,21.557160088299998 2014-04-06 05:35:00,19.3193113177 2014-04-06 05:40:00,18.2482042105 2014-04-06 05:45:00,19.9039038746 2014-04-06 05:50:00,19.0793504193 2014-04-06 05:55:00,20.8609171591 2014-04-06 06:00:00,21.8284262114 2014-04-06 06:05:00,20.7638966046 2014-04-06 06:10:00,21.547735718800002 2014-04-06 06:15:00,19.8120960544 2014-04-06 06:20:00,21.0865629488 2014-04-06 06:25:00,21.3721737467 2014-04-06 06:30:00,20.8435025103 2014-04-06 06:35:00,20.0311091443 2014-04-06 06:40:00,20.5034644385 2014-04-06 06:45:00,20.8020279827 2014-04-06 06:50:00,19.012337612899998 2014-04-06 06:55:00,21.2383170437 2014-04-06 07:00:00,21.801298155900003 2014-04-06 07:05:00,19.860957260699998 2014-04-06 07:10:00,20.8042687324 2014-04-06 07:15:00,20.948103623199998 2014-04-06 07:20:00,20.6489901901 2014-04-06 07:25:00,20.188460433299998 2014-04-06 07:30:00,21.5265918183 2014-04-06 07:35:00,19.7957068371 2014-04-06 07:40:00,18.2444118259 2014-04-06 07:45:00,21.3782255028 2014-04-06 07:50:00,20.6959250893 2014-04-06 07:55:00,21.397034506 2014-04-06 08:00:00,18.5541897698 2014-04-06 08:05:00,18.123011762 2014-04-06 08:10:00,21.7374981615 2014-04-06 08:15:00,18.590913223399998 2014-04-06 08:20:00,21.2386093283 2014-04-06 08:25:00,21.2928397687 2014-04-06 08:30:00,20.8348208022 2014-04-06 08:35:00,18.5250488444 2014-04-06 08:40:00,20.6695944982 2014-04-06 08:45:00,21.5563463333 2014-04-06 08:50:00,19.7021265792 2014-04-06 08:55:00,19.6540674175 2014-04-06 09:00:00,67.22287301029999 2014-04-06 09:05:00,62.318897713199995 2014-04-06 09:10:00,73.3315477388 2014-04-06 09:15:00,73.0208869501 2014-04-06 09:20:00,74.7715667763 2014-04-06 09:25:00,69.1584907244 2014-04-06 09:30:00,71.41620625569999 2014-04-06 09:35:00,63.9563379258 2014-04-06 09:40:00,70.2783919278 2014-04-06 09:45:00,70.0363667431 2014-04-06 09:50:00,73.45643880739999 2014-04-06 09:55:00,72.4987810306 2014-04-06 10:00:00,84.4049994998 2014-04-06 10:05:00,83.3242954963 2014-04-06 10:10:00,83.3221292488 2014-04-06 10:15:00,70.8289860302 2014-04-06 10:20:00,82.9693295058 2014-04-06 10:25:00,79.2680646827 2014-04-06 10:30:00,75.7444978914 2014-04-06 10:35:00,70.7171069705 2014-04-06 10:40:00,80.3574969844 2014-04-06 10:45:00,74.9336911683 2014-04-06 10:50:00,77.0998876326 2014-04-06 10:55:00,80.4204253431 2014-04-06 11:00:00,86.0688623959 2014-04-06 11:05:00,84.6957487058 2014-04-06 11:10:00,78.7342967413 2014-04-06 11:15:00,77.735303336 2014-04-06 11:20:00,75.3814569666 2014-04-06 11:25:00,77.49107505069999 2014-04-06 11:30:00,73.33408174350001 2014-04-06 11:35:00,87.012462005 2014-04-06 11:40:00,80.6955830287 2014-04-06 11:45:00,73.6006241238 2014-04-06 11:50:00,77.1790267714 2014-04-06 11:55:00,80.2681105401 2014-04-06 12:00:00,80.429538782 2014-04-06 12:05:00,72.48097223479999 2014-04-06 12:10:00,87.10880039979997 2014-04-06 12:15:00,76.3143236905 2014-04-06 12:20:00,72.1722439573 2014-04-06 12:25:00,73.1352364182 2014-04-06 12:30:00,81.1855787098 2014-04-06 12:35:00,74.1155228488 2014-04-06 12:40:00,72.5803955696 2014-04-06 12:45:00,77.9803346344 2014-04-06 12:50:00,81.8658220626 2014-04-06 12:55:00,73.7008895532 2014-04-06 13:00:00,76.9947621355 2014-04-06 13:05:00,78.665286545 2014-04-06 13:10:00,74.53346923779999 2014-04-06 13:15:00,80.0779590517 2014-04-06 13:20:00,73.3458181683 2014-04-06 13:25:00,72.7268373105 2014-04-06 13:30:00,80.2980897067 2014-04-06 13:35:00,75.9481196396 2014-04-06 13:40:00,73.5083346909 2014-04-06 13:45:00,78.7636935755 2014-04-06 13:50:00,86.6214576918 2014-04-06 13:55:00,83.5670182475 2014-04-06 14:00:00,85.0457722525 2014-04-06 14:05:00,85.9464981902 2014-04-06 14:10:00,87.5578408842 2014-04-06 14:15:00,84.2079030029 2014-04-06 14:20:00,81.7306034937 2014-04-06 14:25:00,77.84307743779999 2014-04-06 14:30:00,74.9026962829 2014-04-06 14:35:00,82.9825746289 2014-04-06 14:40:00,87.91497965639999 2014-04-06 14:45:00,79.4739240224 2014-04-06 14:50:00,83.5748581037 2014-04-06 14:55:00,79.9176429689 2014-04-06 15:00:00,78.9101772288 2014-04-06 15:05:00,78.56413559399999 2014-04-06 15:10:00,80.0732262166 2014-04-06 15:15:00,77.8695830347 2014-04-06 15:20:00,83.9795669376 2014-04-06 15:25:00,85.98752693729998 2014-04-06 15:30:00,86.1253380951 2014-04-06 15:35:00,75.6424532403 2014-04-06 15:40:00,86.3337174081 2014-04-06 15:45:00,77.4640760474 2014-04-06 15:50:00,76.9481839381 2014-04-06 15:55:00,83.6272940886 2014-04-06 16:00:00,76.8749938411 2014-04-06 16:05:00,72.8473226226 2014-04-06 16:10:00,77.9777346394 2014-04-06 16:15:00,83.5432892023 2014-04-06 16:20:00,77.2311864402 2014-04-06 16:25:00,82.0727873159 2014-04-06 16:30:00,82.5617525893 2014-04-06 16:35:00,83.7396154073 2014-04-06 16:40:00,86.3539216611 2014-04-06 16:45:00,78.9208804599 2014-04-06 16:50:00,74.6627698738 2014-04-06 16:55:00,77.1026634095 2014-04-06 17:00:00,78.91464577949999 2014-04-06 17:05:00,83.4222314751 2014-04-06 17:10:00,72.2099262804 2014-04-06 17:15:00,77.0525365469 2014-04-06 17:20:00,84.477448857 2014-04-06 17:25:00,82.73369148350001 2014-04-06 17:30:00,83.7078074336 2014-04-06 17:35:00,84.9889396753 2014-04-06 17:40:00,84.53173904180001 2014-04-06 17:45:00,82.9148988191 2014-04-06 17:50:00,79.0345541686 2014-04-06 17:55:00,87.7375395708 2014-04-06 18:00:00,32.4420622229 2014-04-06 18:05:00,30.0977171612 2014-04-06 18:10:00,30.6739963833 2014-04-06 18:15:00,33.2387933364 2014-04-06 18:20:00,34.7183265514 2014-04-06 18:25:00,29.9438030777 2014-04-06 18:30:00,29.327011942 2014-04-06 18:35:00,34.441792094600004 2014-04-06 18:40:00,34.657772410700005 2014-04-06 18:45:00,30.5688219408 2014-04-06 18:50:00,31.214622642800002 2014-04-06 18:55:00,33.0251968431 2014-04-06 19:00:00,21.638085306399997 2014-04-06 19:05:00,24.089669691599997 2014-04-06 19:10:00,20.641951455799997 2014-04-06 19:15:00,20.3301592346 2014-04-06 19:20:00,21.0940170491 2014-04-06 19:25:00,21.4416720701 2014-04-06 19:30:00,20.665909995299998 2014-04-06 19:35:00,20.454292001400002 2014-04-06 19:40:00,23.545121264899997 2014-04-06 19:45:00,20.895957868900002 2014-04-06 19:50:00,24.25437012130001 2014-04-06 19:55:00,21.8086372869 2014-04-06 20:00:00,21.1788011425 2014-04-06 20:05:00,19.3552468298 2014-04-06 20:10:00,19.4163618267 2014-04-06 20:15:00,20.7860086455 2014-04-06 20:20:00,20.7283931727 2014-04-06 20:25:00,21.580714659 2014-04-06 20:30:00,21.5360030417 2014-04-06 20:35:00,21.1791368299 2014-04-06 20:40:00,20.2716385546 2014-04-06 20:45:00,22.080062757199997 2014-04-06 20:50:00,20.9820812442 2014-04-06 20:55:00,22.4878527471 2014-04-06 21:00:00,21.37961112 2014-04-06 21:05:00,18.2644899487 2014-04-06 21:10:00,19.3749309839 2014-04-06 21:15:00,20.3848828298 2014-04-06 21:20:00,20.9861303153 2014-04-06 21:25:00,20.2983124022 2014-04-06 21:30:00,21.246015342 2014-04-06 21:35:00,19.2224495525 2014-04-06 21:40:00,18.8255792703 2014-04-06 21:45:00,18.3031018907 2014-04-06 21:50:00,20.3906625523 2014-04-06 21:55:00,20.8540191425 2014-04-06 22:00:00,19.3231312739 2014-04-06 22:05:00,20.4739728926 2014-04-06 22:10:00,18.2261091982 2014-04-06 22:15:00,18.4148346626 2014-04-06 22:20:00,20.8269938171 2014-04-06 22:25:00,19.490972199 2014-04-06 22:30:00,20.7051940369 2014-04-06 22:35:00,21.3473582797 2014-04-06 22:40:00,21.4310438095 2014-04-06 22:45:00,18.7066116964 2014-04-06 22:50:00,19.9642896162 2014-04-06 22:55:00,20.9558051629 2014-04-06 23:00:00,21.0999728001 2014-04-06 23:05:00,21.142762552 2014-04-06 23:10:00,18.9163005682 2014-04-06 23:15:00,18.7737431358 2014-04-06 23:20:00,20.3639590007 2014-04-06 23:25:00,20.968368342799998 2014-04-06 23:30:00,19.2802591594 2014-04-06 23:35:00,18.4223570392 2014-04-06 23:40:00,20.8709919908 2014-04-06 23:45:00,19.2024774916 2014-04-06 23:50:00,18.669034662 2014-04-06 23:55:00,18.594463563399998 2014-04-07 00:00:00,19.2596381901 2014-04-07 00:05:00,20.3707122637 2014-04-07 00:10:00,19.4336089548 2014-04-07 00:15:00,18.0826474064 2014-04-07 00:20:00,18.3876337387 2014-04-07 00:25:00,19.1620129888 2014-04-07 00:30:00,20.638817928599998 2014-04-07 00:35:00,18.3940602939 2014-04-07 00:40:00,20.242627414 2014-04-07 00:45:00,18.4795434833 2014-04-07 00:50:00,18.846461309400002 2014-04-07 00:55:00,18.6887541102 2014-04-07 01:00:00,18.2689145423 2014-04-07 01:05:00,20.6853192695 2014-04-07 01:10:00,19.8536141895 2014-04-07 01:15:00,21.3242137636 2014-04-07 01:20:00,18.3955633599 2014-04-07 01:25:00,18.578931733399997 2014-04-07 01:30:00,19.2258309254 2014-04-07 01:35:00,21.0634639478 2014-04-07 01:40:00,19.2230352926 2014-04-07 01:45:00,19.63367483 2014-04-07 01:50:00,19.2064142652 2014-04-07 01:55:00,18.320897167200002 2014-04-07 02:00:00,21.757734491599997 2014-04-07 02:05:00,20.1941559683 2014-04-07 02:10:00,21.1513327527 2014-04-07 02:15:00,20.6334283687 2014-04-07 02:20:00,20.057017116199997 2014-04-07 02:25:00,18.3587130266 2014-04-07 02:30:00,20.5709341811 2014-04-07 02:35:00,18.6214814237 2014-04-07 02:40:00,19.6575326774 2014-04-07 02:45:00,20.5164525739 2014-04-07 02:50:00,21.128916001900002 2014-04-07 02:55:00,20.7401807028 2014-04-07 03:00:00,20.686134116199998 2014-04-07 03:05:00,18.596168836700002 2014-04-07 03:10:00,19.3845141603 2014-04-07 03:15:00,18.1716490906 2014-04-07 03:20:00,20.8779075727 2014-04-07 03:25:00,21.810343925300003 2014-04-07 03:30:00,19.056441560699998 2014-04-07 03:35:00,18.3507868366 2014-04-07 03:40:00,19.902280307 2014-04-07 03:45:00,21.4267928925 2014-04-07 03:50:00,20.2078967811 2014-04-07 03:55:00,18.1871086008 2014-04-07 04:00:00,21.8970889621 2014-04-07 04:05:00,21.3145996399 2014-04-07 04:10:00,18.5263763082 2014-04-07 04:15:00,21.687191026 2014-04-07 04:20:00,19.8027531544 2014-04-07 04:25:00,19.4875919623 2014-04-07 04:30:00,19.8442133221 2014-04-07 04:35:00,21.3382878275 2014-04-07 04:40:00,20.6379187131 2014-04-07 04:45:00,18.2369938096 2014-04-07 04:50:00,21.8304174845 2014-04-07 04:55:00,18.591136533900002 2014-04-07 05:00:00,20.982271806900002 2014-04-07 05:05:00,20.5445461217 2014-04-07 05:10:00,18.7501121918 2014-04-07 05:15:00,18.6829283045 2014-04-07 05:20:00,21.4813103748 2014-04-07 05:25:00,19.678779694 2014-04-07 05:30:00,20.6183060567 2014-04-07 05:35:00,20.0162840154 2014-04-07 05:40:00,20.9094140683 2014-04-07 05:45:00,19.9169695002 2014-04-07 05:50:00,19.149519661 2014-04-07 05:55:00,19.453533484 2014-04-07 06:00:00,21.4363107778 2014-04-07 06:05:00,19.8721387717 2014-04-07 06:10:00,18.853797329000002 2014-04-07 06:15:00,21.7384215523 2014-04-07 06:20:00,21.186401825999997 2014-04-07 06:25:00,18.2226645842 2014-04-07 06:30:00,21.9957718479 2014-04-07 06:35:00,20.7797067858 2014-04-07 06:40:00,18.6410663962 2014-04-07 06:45:00,18.9486707252 2014-04-07 06:50:00,20.769781925 2014-04-07 06:55:00,21.119044221099998 2014-04-07 07:00:00,18.9561437726 2014-04-07 07:05:00,19.0278754156 2014-04-07 07:10:00,19.228482779500002 2014-04-07 07:15:00,20.3920734593 2014-04-07 07:20:00,18.687264713199998 2014-04-07 07:25:00,18.416972795499998 2014-04-07 07:30:00,20.715456356300002 2014-04-07 07:35:00,21.1163917592 2014-04-07 07:40:00,20.0037176177 2014-04-07 07:45:00,19.4553308411 2014-04-07 07:50:00,19.7281708541 2014-04-07 07:55:00,19.5536313355 2014-04-07 08:00:00,21.839939633 2014-04-07 08:05:00,21.0723596209 2014-04-07 08:10:00,18.8323488594 2014-04-07 08:15:00,19.5367566082 2014-04-07 08:20:00,20.1760491655 2014-04-07 08:25:00,20.4519434483 2014-04-07 08:30:00,19.872735584100003 2014-04-07 08:35:00,21.24050654 2014-04-07 08:40:00,21.0704240778 2014-04-07 08:45:00,20.0206316745 2014-04-07 08:50:00,21.4177175471 2014-04-07 08:55:00,21.0043581218 2014-04-07 09:00:00,71.7887131426 2014-04-07 09:05:00,74.2070506003 2014-04-07 09:10:00,64.8239504004 2014-04-07 09:15:00,64.8400150082 2014-04-07 09:20:00,73.2897506774 2014-04-07 09:25:00,71.702278678 2014-04-07 09:30:00,73.8010193635 2014-04-07 09:35:00,62.0585701804 2014-04-07 09:40:00,69.73749625079999 2014-04-07 09:45:00,63.166945398500005 2014-04-07 09:50:00,68.0530018968 2014-04-07 09:55:00,63.3181582732 2014-04-07 10:00:00,71.8277784594 2014-04-07 10:05:00,70.0288527203 2014-04-07 10:10:00,79.6213063682 2014-04-07 10:15:00,75.41203101100001 2014-04-07 10:20:00,71.47252218130002 2014-04-07 10:25:00,74.8504423104 2014-04-07 10:30:00,72.4620122993 2014-04-07 10:35:00,84.4551037849 2014-04-07 10:40:00,74.806475827 2014-04-07 10:45:00,75.0229586815 2014-04-07 10:50:00,82.8745962128 2014-04-07 10:55:00,79.8931694152 2014-04-07 11:00:00,82.8625692441 2014-04-07 11:05:00,81.68297269060001 2014-04-07 11:10:00,86.6163056999 2014-04-07 11:15:00,74.86014122510001 2014-04-07 11:20:00,87.2976801009 2014-04-07 11:25:00,84.7835270479 2014-04-07 11:30:00,80.9350200535 2014-04-07 11:35:00,82.10235831439999 2014-04-07 11:40:00,81.88692673989999 2014-04-07 11:45:00,72.4967335474 2014-04-07 11:50:00,75.03533439270001 2014-04-07 11:55:00,86.8592329475 2014-04-07 12:00:00,80.4531710647 2014-04-07 12:05:00,77.959993263 2014-04-07 12:10:00,84.0915842757 2014-04-07 12:15:00,80.2958323188 2014-04-07 12:20:00,72.1239516177 2014-04-07 12:25:00,83.67926578560001 2014-04-07 12:30:00,83.6150223837 2014-04-07 12:35:00,74.5528085385 2014-04-07 12:40:00,87.2017935411 2014-04-07 12:45:00,75.4918310685 2014-04-07 12:50:00,79.2288010903 2014-04-07 12:55:00,73.7471724497 2014-04-07 13:00:00,81.6329205071 2014-04-07 13:05:00,77.9884961886 2014-04-07 13:10:00,77.63213920930001 2014-04-07 13:15:00,85.2111744443 2014-04-07 13:20:00,72.1356706886 2014-04-07 13:25:00,84.74680421869998 2014-04-07 13:30:00,81.12370268949999 2014-04-07 13:35:00,87.7565095974 2014-04-07 13:40:00,81.41154806770001 2014-04-07 13:45:00,72.8685734905 2014-04-07 13:50:00,72.792850745 2014-04-07 13:55:00,86.10977647450001 2014-04-07 14:00:00,85.4553242757 2014-04-07 14:05:00,77.53051956569999 2014-04-07 14:10:00,81.884589098 2014-04-07 14:15:00,79.8296297067 2014-04-07 14:20:00,87.4704261002 2014-04-07 14:25:00,87.1951888441 2014-04-07 14:30:00,87.7372125483 2014-04-07 14:35:00,85.8590590575 2014-04-07 14:40:00,86.5486709168 2014-04-07 14:45:00,75.4728375902 2014-04-07 14:50:00,85.2920144106 2014-04-07 14:55:00,83.337713409 2014-04-07 15:00:00,87.4037450572 2014-04-07 15:05:00,81.1394103093 2014-04-07 15:10:00,73.36197038569999 2014-04-07 15:15:00,81.55759929850001 2014-04-07 15:20:00,82.9844981895 2014-04-07 15:25:00,75.5244114181 2014-04-07 15:30:00,78.3050624004 2014-04-07 15:35:00,81.5752714947 2014-04-07 15:40:00,77.9849431344 2014-04-07 15:45:00,77.99841468380002 2014-04-07 15:50:00,74.12867458470001 2014-04-07 15:55:00,87.0511118705 2014-04-07 16:00:00,84.0077488567 2014-04-07 16:05:00,72.0197567437 2014-04-07 16:10:00,84.24965078470001 2014-04-07 16:15:00,83.836558916 2014-04-07 16:20:00,72.1555568236 2014-04-07 16:25:00,77.9135191676 2014-04-07 16:30:00,81.7078061659 2014-04-07 16:35:00,79.2438582812 2014-04-07 16:40:00,84.4476157598 2014-04-07 16:45:00,78.8071820121 2014-04-07 16:50:00,74.4616645446 2014-04-07 16:55:00,87.62248175290001 2014-04-07 17:00:00,75.87261074930001 2014-04-07 17:05:00,83.4830449112 2014-04-07 17:10:00,74.2904724591 2014-04-07 17:15:00,77.2641721511 2014-04-07 17:20:00,79.0724113711 2014-04-07 17:25:00,75.07568324340001 2014-04-07 17:30:00,79.1993228093 2014-04-07 17:35:00,74.5145765543 2014-04-07 17:40:00,80.9440735412 2014-04-07 17:45:00,82.61938031449999 2014-04-07 17:50:00,72.9989205129 2014-04-07 17:55:00,85.9380809371 2014-04-07 18:00:00,29.9848959072 2014-04-07 18:05:00,30.242313715500003 2014-04-07 18:10:00,33.0326326343 2014-04-07 18:15:00,31.8000006812 2014-04-07 18:20:00,31.9961256914 2014-04-07 18:25:00,29.6201862141 2014-04-07 18:30:00,33.9567027403 2014-04-07 18:35:00,32.7491408872 2014-04-07 18:40:00,29.6664393812 2014-04-07 18:45:00,31.1935899598 2014-04-07 18:50:00,33.9866170441 2014-04-07 18:55:00,32.437466066300004 2014-04-07 19:00:00,20.6467453979 2014-04-07 19:05:00,21.8300399676 2014-04-07 19:10:00,21.247269739500002 2014-04-07 19:15:00,22.4782444473 2014-04-07 19:20:00,23.9382565442 2014-04-07 19:25:00,22.114475550799998 2014-04-07 19:30:00,22.1013710836 2014-04-07 19:35:00,24.215970714 2014-04-07 19:40:00,22.7413094005 2014-04-07 19:45:00,22.696534826500002 2014-04-07 19:50:00,21.3333551453 2014-04-07 19:55:00,22.882596655 2014-04-07 20:00:00,20.7909290251 2014-04-07 20:05:00,20.0575033818 2014-04-07 20:10:00,22.489888768 2014-04-07 20:15:00,22.0442251279 2014-04-07 20:20:00,21.502305186100006 2014-04-07 20:25:00,20.6329672825 2014-04-07 20:30:00,20.3245967047 2014-04-07 20:35:00,19.1893395006 2014-04-07 20:40:00,19.6843004574 2014-04-07 20:45:00,21.6021431769 2014-04-07 20:50:00,20.2905554718 2014-04-07 20:55:00,22.045775675300003 2014-04-07 21:00:00,18.680884393499998 2014-04-07 21:05:00,20.1295485991 2014-04-07 21:10:00,20.6866844266 2014-04-07 21:15:00,20.1637172663 2014-04-07 21:20:00,21.660380669699997 2014-04-07 21:25:00,22.0636526884 2014-04-07 21:30:00,18.5519626134 2014-04-07 21:35:00,18.608714705 2014-04-07 21:40:00,18.6101986317 2014-04-07 21:45:00,20.8241869336 2014-04-07 21:50:00,19.5842597151 2014-04-07 21:55:00,21.0337382351 2014-04-07 22:00:00,19.6407228924 2014-04-07 22:05:00,20.5301168851 2014-04-07 22:10:00,21.0996682671 2014-04-07 22:15:00,20.2122487818 2014-04-07 22:20:00,20.177366045699998 2014-04-07 22:25:00,18.3705561119 2014-04-07 22:30:00,19.6619843639 2014-04-07 22:35:00,20.202484387200002 2014-04-07 22:40:00,19.8669772993 2014-04-07 22:45:00,21.623866993000004 2014-04-07 22:50:00,21.6468835955 2014-04-07 22:55:00,21.3081056746 2014-04-07 23:00:00,19.5049365285 2014-04-07 23:05:00,20.873203490399998 2014-04-07 23:10:00,19.5849134239 2014-04-07 23:15:00,18.9340090259 2014-04-07 23:20:00,19.3753299215 2014-04-07 23:25:00,18.2873690322 2014-04-07 23:30:00,19.3308208392 2014-04-07 23:35:00,19.8467787171 2014-04-07 23:40:00,21.8261133863 2014-04-07 23:45:00,19.2573390423 2014-04-07 23:50:00,21.613963239 2014-04-07 23:55:00,18.9190648646 2014-04-08 00:00:00,18.763875590999998 2014-04-08 00:05:00,20.075981825699998 2014-04-08 00:10:00,20.6900454772 2014-04-08 00:15:00,18.1773290032 2014-04-08 00:20:00,18.8842634602 2014-04-08 00:25:00,19.822734666 2014-04-08 00:30:00,19.3240173439 2014-04-08 00:35:00,20.8504843174 2014-04-08 00:40:00,20.0446423842 2014-04-08 00:45:00,18.6414364224 2014-04-08 00:50:00,21.5778615173 2014-04-08 00:55:00,19.171622701900002 2014-04-08 01:00:00,20.9245244359 2014-04-08 01:05:00,21.1196631164 2014-04-08 01:10:00,21.852630801 2014-04-08 01:15:00,19.9940298661 2014-04-08 01:20:00,20.4633420619 2014-04-08 01:25:00,19.3395051739 2014-04-08 01:30:00,20.712717173599998 2014-04-08 01:35:00,19.8535339435 2014-04-08 01:40:00,19.7506094589 2014-04-08 01:45:00,21.421870116500003 2014-04-08 01:50:00,18.200675374 2014-04-08 01:55:00,21.5278497113 2014-04-08 02:00:00,21.408279351300003 2014-04-08 02:05:00,20.0254650142 2014-04-08 02:10:00,19.960811416800002 2014-04-08 02:15:00,19.447229472100002 2014-04-08 02:20:00,21.9766951667 2014-04-08 02:25:00,18.444677330999998 2014-04-08 02:30:00,20.3608609425 2014-04-08 02:35:00,20.7267263604 2014-04-08 02:40:00,21.7373200329 2014-04-08 02:45:00,21.120813987400002 2014-04-08 02:50:00,20.5753888112 2014-04-08 02:55:00,18.4672492672 2014-04-08 03:00:00,19.4949340673 2014-04-08 03:05:00,18.5553665702 2014-04-08 03:10:00,21.524850929899998 2014-04-08 03:15:00,20.9984846223 2014-04-08 03:20:00,21.0301471472 2014-04-08 03:25:00,20.6090260711 2014-04-08 03:30:00,20.0281741477 2014-04-08 03:35:00,18.5998842379 2014-04-08 03:40:00,19.318779546800002 2014-04-08 03:45:00,18.5476631699 2014-04-08 03:50:00,20.8996525714 2014-04-08 03:55:00,18.6409151041 2014-04-08 04:00:00,20.808454200699998 2014-04-08 04:05:00,20.7690215584 2014-04-08 04:10:00,19.837217916 2014-04-08 04:15:00,18.5409146165 2014-04-08 04:20:00,19.2592033045 2014-04-08 04:25:00,19.280372436300002 2014-04-08 04:30:00,20.8015405326 2014-04-08 04:35:00,18.4549720777 2014-04-08 04:40:00,21.3162745849 2014-04-08 04:45:00,21.0440291607 2014-04-08 04:50:00,18.7452276727 2014-04-08 04:55:00,20.8766575271 2014-04-08 05:00:00,20.674052725899998 2014-04-08 05:05:00,20.9924832004 2014-04-08 05:10:00,18.7557142218 2014-04-08 05:15:00,18.6303612886 2014-04-08 05:20:00,18.9459359437 2014-04-08 05:25:00,19.4634868126 2014-04-08 05:30:00,21.174659924100002 2014-04-08 05:35:00,20.9516957499 2014-04-08 05:40:00,21.701806369099998 2014-04-08 05:45:00,18.2345182364 2014-04-08 05:50:00,18.0462251241 2014-04-08 05:55:00,20.7965553188 2014-04-08 06:00:00,19.1171499832 2014-04-08 06:05:00,19.3363155821 2014-04-08 06:10:00,20.187208103699998 2014-04-08 06:15:00,18.4096524925 2014-04-08 06:20:00,20.570777666199998 2014-04-08 06:25:00,19.3005897849 2014-04-08 06:30:00,20.5308604972 2014-04-08 06:35:00,21.3360276523 2014-04-08 06:40:00,18.684445333299998 2014-04-08 06:45:00,21.7234923717 2014-04-08 06:50:00,20.122752564200002 2014-04-08 06:55:00,21.6917110607 2014-04-08 07:00:00,18.8309203288 2014-04-08 07:05:00,20.418250658399998 2014-04-08 07:10:00,19.615548469300002 2014-04-08 07:15:00,21.0968887646 2014-04-08 07:20:00,20.4236357729 2014-04-08 07:25:00,19.9780618278 2014-04-08 07:30:00,21.6519416257 2014-04-08 07:35:00,19.508468256700002 2014-04-08 07:40:00,18.8799208196 2014-04-08 07:45:00,20.4324047474 2014-04-08 07:50:00,20.496113748699997 2014-04-08 07:55:00,19.7563784863 2014-04-08 08:00:00,19.9464401748 2014-04-08 08:05:00,21.838213657199997 2014-04-08 08:10:00,20.930742765599998 2014-04-08 08:15:00,18.442407005899998 2014-04-08 08:20:00,18.848520283499997 2014-04-08 08:25:00,21.9023065377 2014-04-08 08:30:00,20.9058622152 2014-04-08 08:35:00,21.6601805046 2014-04-08 08:40:00,19.215445856 2014-04-08 08:45:00,20.9674674403 2014-04-08 08:50:00,20.8560108341 2014-04-08 08:55:00,19.1787599418 2014-04-08 09:00:00,68.6911020261 2014-04-08 09:05:00,69.7328455133 2014-04-08 09:10:00,67.7433926273 2014-04-08 09:15:00,72.4496304105 2014-04-08 09:20:00,72.5270189685 2014-04-08 09:25:00,72.7681674569 2014-04-08 09:30:00,72.12656053970001 2014-04-08 09:35:00,67.8379352899 2014-04-08 09:40:00,66.3875608548 2014-04-08 09:45:00,72.5067174585 2014-04-08 09:50:00,67.8667398364 2014-04-08 09:55:00,64.5506510213 2014-04-08 10:00:00,77.7139716216 2014-04-08 10:05:00,72.0415092362 2014-04-08 10:10:00,80.5740896941 2014-04-08 10:15:00,75.0534982908 2014-04-08 10:20:00,73.8854245519 2014-04-08 10:25:00,84.6850157416 2014-04-08 10:30:00,81.8971930542 2014-04-08 10:35:00,82.0553186823 2014-04-08 10:40:00,79.5201649632 2014-04-08 10:45:00,82.8639620191 2014-04-08 10:50:00,81.6222017077 2014-04-08 10:55:00,79.1329678882 2014-04-08 11:00:00,86.85372248700001 2014-04-08 11:05:00,74.61512607979999 2014-04-08 11:10:00,86.5715110509 2014-04-08 11:15:00,77.95247252840001 2014-04-08 11:20:00,79.971657432 2014-04-08 11:25:00,73.520046138 2014-04-08 11:30:00,80.15786870859999 2014-04-08 11:35:00,81.2886321816 2014-04-08 11:40:00,87.4354453209 2014-04-08 11:45:00,87.0774601057 2014-04-08 11:50:00,86.93758253 2014-04-08 11:55:00,77.1087637079 2014-04-08 12:00:00,87.75483166309998 2014-04-08 12:05:00,79.192505245 2014-04-08 12:10:00,85.526624884 2014-04-08 12:15:00,75.3705661609 2014-04-08 12:20:00,79.9972188775 2014-04-08 12:25:00,87.3512461058 2014-04-08 12:30:00,87.047919348 2014-04-08 12:35:00,82.8402303355 2014-04-08 12:40:00,84.6633111259 2014-04-08 12:45:00,74.7330397531 2014-04-08 12:50:00,83.4462809476 2014-04-08 12:55:00,81.7905463578 2014-04-08 13:00:00,73.4471962134 2014-04-08 13:05:00,73.7928295748 2014-04-08 13:10:00,73.7174014605 2014-04-08 13:15:00,83.5696494266 2014-04-08 13:20:00,74.24961914560001 2014-04-08 13:25:00,79.4646402459 2014-04-08 13:30:00,77.6930580839 2014-04-08 13:35:00,80.78867231640001 2014-04-08 13:40:00,83.2836309258 2014-04-08 13:45:00,82.935651261 2014-04-08 13:50:00,80.2290590582 2014-04-08 13:55:00,79.4102949319 2014-04-08 14:00:00,78.3612879996 2014-04-08 14:05:00,85.78644122600001 2014-04-08 14:10:00,77.2899187838 2014-04-08 14:15:00,76.1461979457 2014-04-08 14:20:00,83.8890210322 2014-04-08 14:25:00,77.7524830888 2014-04-08 14:30:00,85.5478711012 2014-04-08 14:35:00,77.2425116797 2014-04-08 14:40:00,83.2271220996 2014-04-08 14:45:00,72.7182534568 2014-04-08 14:50:00,78.1652539695 2014-04-08 14:55:00,77.4879631987 2014-04-08 15:00:00,85.0660431866 2014-04-08 15:05:00,87.4720467119 2014-04-08 15:10:00,79.37333843569999 2014-04-08 15:15:00,85.1965625396 2014-04-08 15:20:00,83.1943165422 2014-04-08 15:25:00,87.4773360121 2014-04-08 15:30:00,84.9769204432 2014-04-08 15:35:00,73.2389459548 2014-04-08 15:40:00,83.411706798 2014-04-08 15:45:00,80.567221994 2014-04-08 15:50:00,72.2622832023 2014-04-08 15:55:00,76.0202775379 2014-04-08 16:00:00,86.7479173641 2014-04-08 16:05:00,86.816815276 2014-04-08 16:10:00,84.7814445825 2014-04-08 16:15:00,87.70830525219999 2014-04-08 16:20:00,84.9045605769 2014-04-08 16:25:00,72.1631284431 2014-04-08 16:30:00,76.6052023626 2014-04-08 16:35:00,72.489847735 2014-04-08 16:40:00,73.5055863688 2014-04-08 16:45:00,75.5013081084 2014-04-08 16:50:00,80.0567830319 2014-04-08 16:55:00,85.5603477792 2014-04-08 17:00:00,85.7914351546 2014-04-08 17:05:00,81.859198303 2014-04-08 17:10:00,86.85078167430002 2014-04-08 17:15:00,80.0009665051 2014-04-08 17:20:00,86.2245435959 2014-04-08 17:25:00,79.2650136635 2014-04-08 17:30:00,76.4355707675 2014-04-08 17:35:00,86.66257341120001 2014-04-08 17:40:00,78.2069311794 2014-04-08 17:45:00,80.05443500060001 2014-04-08 17:50:00,77.261740452 2014-04-08 17:55:00,82.6053698842 2014-04-08 18:00:00,35.1681930877 2014-04-08 18:05:00,28.963281151799997 2014-04-08 18:10:00,34.5590206031 2014-04-08 18:15:00,28.825121230300002 2014-04-08 18:20:00,31.1310524622 2014-04-08 18:25:00,29.879077823499998 2014-04-08 18:30:00,33.6469809361 2014-04-08 18:35:00,29.123903789099998 2014-04-08 18:40:00,32.3422974932 2014-04-08 18:45:00,30.687521364600002 2014-04-08 18:50:00,29.6554838989 2014-04-08 18:55:00,33.7396300794 2014-04-08 19:00:00,21.1340262581 2014-04-08 19:05:00,21.1620637891 2014-04-08 19:10:00,21.3923428239 2014-04-08 19:15:00,22.788713851799997 2014-04-08 19:20:00,23.115302105900003 2014-04-08 19:25:00,20.2388581959 2014-04-08 19:30:00,21.2435748044 2014-04-08 19:35:00,22.0907481626 2014-04-08 19:40:00,21.6472555582 2014-04-08 19:45:00,24.1210832269 2014-04-08 19:50:00,23.688933814899997 2014-04-08 19:55:00,22.9639869059 2014-04-08 20:00:00,19.816621498099998 2014-04-08 20:05:00,21.3019536689 2014-04-08 20:10:00,21.887541038000002 2014-04-08 20:15:00,20.8684249752 2014-04-08 20:20:00,21.6451539087 2014-04-08 20:25:00,21.500333663899998 2014-04-08 20:30:00,20.7738357772 2014-04-08 20:35:00,19.7107022196 2014-04-08 20:40:00,21.486723461300002 2014-04-08 20:45:00,19.2790376853 2014-04-08 20:50:00,21.6247840077 2014-04-08 20:55:00,21.727422990300003 2014-04-08 21:00:00,21.3907646477 2014-04-08 21:05:00,19.987143821700002 2014-04-08 21:10:00,18.8600186557 2014-04-08 21:15:00,18.4872090482 2014-04-08 21:20:00,21.074117486400002 2014-04-08 21:25:00,21.648461703800002 2014-04-08 21:30:00,20.7022494812 2014-04-08 21:35:00,18.665808069100002 2014-04-08 21:40:00,21.8439357525 2014-04-08 21:45:00,22.0617987629 2014-04-08 21:50:00,19.8282352606 2014-04-08 21:55:00,20.4771217526 2014-04-08 22:00:00,21.1291786271 2014-04-08 22:05:00,20.9656668867 2014-04-08 22:10:00,21.8921450598 2014-04-08 22:15:00,18.477253506300002 2014-04-08 22:20:00,20.3424094381 2014-04-08 22:25:00,20.7876626851 2014-04-08 22:30:00,21.581091664099997 2014-04-08 22:35:00,21.5170750813 2014-04-08 22:40:00,21.9330346827 2014-04-08 22:45:00,20.0675601872 2014-04-08 22:50:00,21.343513578499998 2014-04-08 22:55:00,19.7280475846 2014-04-08 23:00:00,19.693035846500003 2014-04-08 23:05:00,19.0170440276 2014-04-08 23:10:00,21.2770335522 2014-04-08 23:15:00,21.9474735271 2014-04-08 23:20:00,19.029019782 2014-04-08 23:25:00,18.2280254594 2014-04-08 23:30:00,21.2662520842 2014-04-08 23:35:00,20.4848525448 2014-04-08 23:40:00,21.8429882487 2014-04-08 23:45:00,19.0126065942 2014-04-08 23:50:00,18.287621179400002 2014-04-08 23:55:00,19.9736032372 2014-04-09 00:00:00,18.3418640919 2014-04-09 00:05:00,19.047160004400002 2014-04-09 00:10:00,18.503911443299998 2014-04-09 00:15:00,18.8965287186 2014-04-09 00:20:00,18.4245786113 2014-04-09 00:25:00,21.8156239977 2014-04-09 00:30:00,19.1142508538 2014-04-09 00:35:00,19.775590344 2014-04-09 00:40:00,21.594447230500002 2014-04-09 00:45:00,20.7092863518 2014-04-09 00:50:00,20.4721499222 2014-04-09 00:55:00,20.8222527614 2014-04-09 01:00:00,21.3152890284 2014-04-09 01:05:00,21.5106770714 2014-04-09 01:10:00,20.5705586827 2014-04-09 01:15:00,21.5600290988 2014-04-09 01:20:00,20.1415901097 2014-04-09 01:25:00,19.1091634251 2014-04-09 01:30:00,21.5203068355 2014-04-09 01:35:00,20.1658913097 2014-04-09 01:40:00,21.6245503503 2014-04-09 01:45:00,18.1606712558 2014-04-09 01:50:00,19.590063006199998 2014-04-09 01:55:00,21.7912200734 2014-04-09 02:00:00,18.998600371 2014-04-09 02:05:00,21.7661449842 2014-04-09 02:10:00,21.8156098445 2014-04-09 02:15:00,21.5285692569 2014-04-09 02:20:00,20.2546721804 2014-04-09 02:25:00,20.5877577963 2014-04-09 02:30:00,21.478467993800002 2014-04-09 02:35:00,21.1035883296 2014-04-09 02:40:00,20.5203753978 2014-04-09 02:45:00,21.9290376315 2014-04-09 02:50:00,20.7427065453 2014-04-09 02:55:00,21.9019279698 2014-04-09 03:00:00,18.2295538984 2014-04-09 03:05:00,18.555841483 2014-04-09 03:10:00,19.805835384 2014-04-09 03:15:00,19.5395178435 2014-04-09 03:20:00,21.1309393654 2014-04-09 03:25:00,18.6424561059 2014-04-09 03:30:00,21.9043807164 2014-04-09 03:35:00,19.260263501 2014-04-09 03:40:00,19.715694831 2014-04-09 03:45:00,19.0989801298 2014-04-09 03:50:00,20.3174544693 2014-04-09 03:55:00,18.2345148017 2014-04-09 04:00:00,18.5987100223 2014-04-09 04:05:00,20.9831908137 2014-04-09 04:10:00,18.7460023336 2014-04-09 04:15:00,18.942057806199998 2014-04-09 04:20:00,21.1719289429 2014-04-09 04:25:00,18.3732047134 2014-04-09 04:30:00,19.7498952911 2014-04-09 04:35:00,18.092253548 2014-04-09 04:40:00,19.3872295973 2014-04-09 04:45:00,20.7959256104 2014-04-09 04:50:00,18.360413118900002 2014-04-09 04:55:00,21.5533385071 2014-04-09 05:00:00,21.637996171799998 2014-04-09 05:05:00,18.4199615005 2014-04-09 05:10:00,21.962929745500002 2014-04-09 05:15:00,19.190118213599998 2014-04-09 05:20:00,18.3364066845 2014-04-09 05:25:00,18.020268458 2014-04-09 05:30:00,19.6340915831 2014-04-09 05:35:00,20.5192399428 2014-04-09 05:40:00,19.3287169996 2014-04-09 05:45:00,21.3468694619 2014-04-09 05:50:00,20.8664251023 2014-04-09 05:55:00,19.4006461279 2014-04-09 06:00:00,20.937238666400003 2014-04-09 06:05:00,21.7619509479 2014-04-09 06:10:00,18.3723839942 2014-04-09 06:15:00,19.2244158406 2014-04-09 06:20:00,19.8533037565 2014-04-09 06:25:00,19.991960511 2014-04-09 06:30:00,20.1687825795 2014-04-09 06:35:00,19.2025076262 2014-04-09 06:40:00,20.6690385839 2014-04-09 06:45:00,20.5803380141 2014-04-09 06:50:00,20.3112860251 2014-04-09 06:55:00,18.4550468868 2014-04-09 07:00:00,19.9078715644 2014-04-09 07:05:00,19.42490755 2014-04-09 07:10:00,19.9641538794 2014-04-09 07:15:00,21.6874657421 2014-04-09 07:20:00,19.9221253726 2014-04-09 07:25:00,18.0559231674 2014-04-09 07:30:00,19.755346952300002 2014-04-09 07:35:00,21.2825927202 2014-04-09 07:40:00,21.1202436929 2014-04-09 07:45:00,20.053560294100002 2014-04-09 07:50:00,18.9990760514 2014-04-09 07:55:00,19.8603546517 2014-04-09 08:00:00,20.2548088777 2014-04-09 08:05:00,21.9994857531 2014-04-09 08:10:00,20.5767123607 2014-04-09 08:15:00,20.7770597203 2014-04-09 08:20:00,19.9658165743 2014-04-09 08:25:00,19.4179582031 2014-04-09 08:30:00,21.2518119346 2014-04-09 08:35:00,19.9797292974 2014-04-09 08:40:00,21.978760519899996 2014-04-09 08:45:00,19.8284822971 2014-04-09 08:50:00,18.2720011346 2014-04-09 08:55:00,20.7303125484 2014-04-09 09:00:00,61.83432373260001 2014-04-09 09:05:00,64.6068217176 2014-04-09 09:10:00,66.0108402378 2014-04-09 09:15:00,71.2569767645 2014-04-09 09:20:00,67.9216085991 2014-04-09 09:25:00,61.5895846658 2014-04-09 09:30:00,69.58915797739999 2014-04-09 09:35:00,66.795532829 2014-04-09 09:40:00,73.7369493356 2014-04-09 09:45:00,67.9940474315 2014-04-09 09:50:00,70.8420619848 2014-04-09 09:55:00,64.1766114957 2014-04-09 10:00:00,81.6503097215 2014-04-09 10:05:00,81.0292264187 2014-04-09 10:10:00,83.8713481166 2014-04-09 10:15:00,70.3649118795 2014-04-09 10:20:00,76.785210827 2014-04-09 10:25:00,80.38049185050001 2014-04-09 10:30:00,71.3169437292 2014-04-09 10:35:00,76.21257512220001 2014-04-09 10:40:00,84.4621152796 2014-04-09 10:45:00,76.60570329859999 2014-04-09 10:50:00,85.1334822396 2014-04-09 10:55:00,70.722142228 2014-04-09 11:00:00,82.9843647597 2014-04-09 11:05:00,80.8084822213 2014-04-09 11:10:00,79.5285830251 2014-04-09 11:15:00,87.0083570732 2014-04-09 11:20:00,73.62995996939999 2014-04-09 11:25:00,85.8179673275 2014-04-09 11:30:00,82.5614874987 2014-04-09 11:35:00,75.68707354979999 2014-04-09 11:40:00,85.9081460921 2014-04-09 11:45:00,78.3955063737 2014-04-09 11:50:00,84.5174714257 2014-04-09 11:55:00,77.7520559671 2014-04-09 12:00:00,85.51215536699999 2014-04-09 12:05:00,82.087442616 2014-04-09 12:10:00,74.167638042 2014-04-09 12:15:00,82.2957370828 2014-04-09 12:20:00,74.9714423838 2014-04-09 12:25:00,78.4964531319 2014-04-09 12:30:00,74.6350596728 2014-04-09 12:35:00,72.2654351413 2014-04-09 12:40:00,75.2997164096 2014-04-09 12:45:00,80.4852540367 2014-04-09 12:50:00,79.60932951390001 2014-04-09 12:55:00,79.9279247843 2014-04-09 13:00:00,75.9447589375 2014-04-09 13:05:00,82.9426681908 2014-04-09 13:10:00,83.24822821810001 2014-04-09 13:15:00,77.7088306125 2014-04-09 13:20:00,86.0780577224 2014-04-09 13:25:00,82.284618417 2014-04-09 13:30:00,83.3886103333 2014-04-09 13:35:00,76.4190937017 2014-04-09 13:40:00,71.9925038138 2014-04-09 13:45:00,85.82540675130002 2014-04-09 13:50:00,85.1383520436 2014-04-09 13:55:00,73.95331715180001 2014-04-09 14:00:00,77.9819388466 2014-04-09 14:05:00,82.5774650256 2014-04-09 14:10:00,82.42981689439999 2014-04-09 14:15:00,85.7614886079 2014-04-09 14:20:00,74.2407268602 2014-04-09 14:25:00,78.8752497708 2014-04-09 14:30:00,73.5520600185 2014-04-09 14:35:00,78.2297687659 2014-04-09 14:40:00,72.2382515269 2014-04-09 14:45:00,86.36822316799999 2014-04-09 14:50:00,80.42884317949999 2014-04-09 14:55:00,85.59272752470001 2014-04-09 15:00:00,72.9577748147 2014-04-09 15:05:00,75.63860363 2014-04-09 15:10:00,76.1493488828 2014-04-09 15:15:00,78.1863133184 2014-04-09 15:20:00,84.84504743810001 2014-04-09 15:25:00,78.1841754044 2014-04-09 15:30:00,75.2737338396 2014-04-09 15:35:00,73.0391429829 2014-04-09 15:40:00,73.2711645637 2014-04-09 15:45:00,84.1599473521 2014-04-09 15:50:00,79.1160883348 2014-04-09 15:55:00,83.6180952106 2014-04-09 16:00:00,82.91643474840001 2014-04-09 16:05:00,74.1656569898 2014-04-09 16:10:00,74.28606431760001 2014-04-09 16:15:00,84.0853108028 2014-04-09 16:20:00,83.5401322984 2014-04-09 16:25:00,78.0483424169 2014-04-09 16:30:00,73.2386155949 2014-04-09 16:35:00,72.1934297355 2014-04-09 16:40:00,76.6103640992 2014-04-09 16:45:00,72.1474178541 2014-04-09 16:50:00,75.6810166298 2014-04-09 16:55:00,78.7118607163 2014-04-09 17:00:00,73.94262385100001 2014-04-09 17:05:00,73.6684158366 2014-04-09 17:10:00,86.3429658158 2014-04-09 17:15:00,81.3674892192 2014-04-09 17:20:00,86.9512575989 2014-04-09 17:25:00,77.53318884779999 2014-04-09 17:30:00,82.8342871889 2014-04-09 17:35:00,75.2750378883 2014-04-09 17:40:00,81.8934136294 2014-04-09 17:45:00,74.073343236 2014-04-09 17:50:00,72.033262566 2014-04-09 17:55:00,86.90447545120001 2014-04-09 18:00:00,32.3513177961 2014-04-09 18:05:00,34.7324135732 2014-04-09 18:10:00,30.9365158119 2014-04-09 18:15:00,30.897824910300002 2014-04-09 18:20:00,31.3641859894 2014-04-09 18:25:00,33.318655900100005 2014-04-09 18:30:00,32.4211690339 2014-04-09 18:35:00,34.7222647388 2014-04-09 18:40:00,28.9628162064 2014-04-09 18:45:00,33.3324476032 2014-04-09 18:50:00,30.914091276399997 2014-04-09 18:55:00,29.9534896206 2014-04-09 19:00:00,22.4465711575 2014-04-09 19:05:00,22.4226845231 2014-04-09 19:10:00,20.7738082689 2014-04-09 19:15:00,21.064493175899997 2014-04-09 19:20:00,21.9885764925 2014-04-09 19:25:00,21.991473921100006 2014-04-09 19:30:00,21.5826592815 2014-04-09 19:35:00,20.825481136300002 2014-04-09 19:40:00,20.1795929754 2014-04-09 19:45:00,24.506651735300004 2014-04-09 19:50:00,24.3868752113 2014-04-09 19:55:00,22.326752473899997 2014-04-09 20:00:00,22.5077317113 2014-04-09 20:05:00,21.1912878846 2014-04-09 20:10:00,18.714040249500002 2014-04-09 20:15:00,18.9141735165 2014-04-09 20:20:00,22.184389750300003 2014-04-09 20:25:00,21.0126935679 2014-04-09 20:30:00,21.885679872199997 2014-04-09 20:35:00,22.111312219600002 2014-04-09 20:40:00,20.266770235 2014-04-09 20:45:00,18.6307620741 2014-04-09 20:50:00,19.203196078599998 2014-04-09 20:55:00,18.7046784717 2014-04-09 21:00:00,18.844983141700002 2014-04-09 21:05:00,19.7364138897 2014-04-09 21:10:00,18.5614565754 2014-04-09 21:15:00,18.756534223699997 2014-04-09 21:20:00,19.8782468579 2014-04-09 21:25:00,19.4536150362 2014-04-09 21:30:00,19.9660114839 2014-04-09 21:35:00,19.8113281655 2014-04-09 21:40:00,20.676686031400003 2014-04-09 21:45:00,21.8531521814 2014-04-09 21:50:00,18.5199283038 2014-04-09 21:55:00,18.485346346900002 2014-04-09 22:00:00,21.4317792093 2014-04-09 22:05:00,20.0448113721 2014-04-09 22:10:00,21.0858430792 2014-04-09 22:15:00,18.8797948253 2014-04-09 22:20:00,21.335913114500002 2014-04-09 22:25:00,21.7162140571 2014-04-09 22:30:00,20.5616523069 2014-04-09 22:35:00,18.4412026523 2014-04-09 22:40:00,21.6018971781 2014-04-09 22:45:00,21.1902740519 2014-04-09 22:50:00,21.023674466400003 2014-04-09 22:55:00,18.1643337829 2014-04-09 23:00:00,21.1999197022 2014-04-09 23:05:00,18.555365986400002 2014-04-09 23:10:00,18.8931714955 2014-04-09 23:15:00,20.312438577 2014-04-09 23:20:00,19.063582595 2014-04-09 23:25:00,20.649356738599998 2014-04-09 23:30:00,20.4362047869 2014-04-09 23:35:00,18.436137449100002 2014-04-09 23:40:00,20.6280181355 2014-04-09 23:45:00,21.699985234499998 2014-04-09 23:50:00,18.6480193513 2014-04-09 23:55:00,20.3921626254 2014-04-10 00:00:00,19.367461487699998 2014-04-10 00:05:00,19.8384466871 2014-04-10 00:10:00,19.1480007163 2014-04-10 00:15:00,19.4165225454 2014-04-10 00:20:00,18.1156472931 2014-04-10 00:25:00,21.9262069517 2014-04-10 00:30:00,20.4991996883 2014-04-10 00:35:00,20.002822362 2014-04-10 00:40:00,19.534861398 2014-04-10 00:45:00,20.1574982353 2014-04-10 00:50:00,19.5204239949 2014-04-10 00:55:00,19.43963171 2014-04-10 01:00:00,19.8557861669 2014-04-10 01:05:00,19.1039321347 2014-04-10 01:10:00,18.7201995999 2014-04-10 01:15:00,20.2264235927 2014-04-10 01:20:00,21.3710617446 2014-04-10 01:25:00,18.6113127109 2014-04-10 01:30:00,18.1309373624 2014-04-10 01:35:00,18.9872469806 2014-04-10 01:40:00,21.9188825738 2014-04-10 01:45:00,21.315032295 2014-04-10 01:50:00,20.3834642141 2014-04-10 01:55:00,21.716995661 2014-04-10 02:00:00,19.7811164673 2014-04-10 02:05:00,21.9331224103 2014-04-10 02:10:00,19.1852081805 2014-04-10 02:15:00,18.9612229981 2014-04-10 02:20:00,20.5521928046 2014-04-10 02:25:00,19.5126158718 2014-04-10 02:30:00,20.5054621679 2014-04-10 02:35:00,19.2199820732 2014-04-10 02:40:00,20.4716730274 2014-04-10 02:45:00,19.1029850423 2014-04-10 02:50:00,18.2038882753 2014-04-10 02:55:00,21.6485436077 2014-04-10 03:00:00,21.5328208075 2014-04-10 03:05:00,21.8831925971 2014-04-10 03:10:00,20.8661087049 2014-04-10 03:15:00,20.7308847109 2014-04-10 03:20:00,20.2360122803 2014-04-10 03:25:00,18.5037696654 2014-04-10 03:30:00,18.7569412438 2014-04-10 03:35:00,19.1578787547 2014-04-10 03:40:00,21.5606254503 2014-04-10 03:45:00,18.6918780984 2014-04-10 03:50:00,21.691492698 2014-04-10 03:55:00,20.0911429322 2014-04-10 04:00:00,20.8622785419 2014-04-10 04:05:00,18.440977946700002 2014-04-10 04:10:00,19.0761341951 2014-04-10 04:15:00,21.8340744327 2014-04-10 04:20:00,19.0645997877 2014-04-10 04:25:00,19.1860868816 2014-04-10 04:30:00,18.7903895394 2014-04-10 04:35:00,18.5162946612 2014-04-10 04:40:00,18.9330305658 2014-04-10 04:45:00,20.5693075678 2014-04-10 04:50:00,19.821470934 2014-04-10 04:55:00,20.2150233454 2014-04-10 05:00:00,18.4894593151 2014-04-10 05:05:00,21.2084657887 2014-04-10 05:10:00,21.1363788023 2014-04-10 05:15:00,18.0863596446 2014-04-10 05:20:00,19.534060378 2014-04-10 05:25:00,18.2750824079 2014-04-10 05:30:00,21.1684231177 2014-04-10 05:35:00,20.9490787325 2014-04-10 05:40:00,21.607952377199997 2014-04-10 05:45:00,18.945615835799998 2014-04-10 05:50:00,19.8251835325 2014-04-10 05:55:00,18.7379515087 2014-04-10 06:00:00,19.4849397379 2014-04-10 06:05:00,20.0889730063 2014-04-10 06:10:00,18.2133231594 2014-04-10 06:15:00,20.8594816427 2014-04-10 06:20:00,20.1731734415 2014-04-10 06:25:00,21.3158360688 2014-04-10 06:30:00,19.0871220048 2014-04-10 06:35:00,21.6132844211 2014-04-10 06:40:00,21.994777012100002 2014-04-10 06:45:00,21.6771937535 2014-04-10 06:50:00,21.111569903299998 2014-04-10 06:55:00,21.249475211500002 2014-04-10 07:00:00,20.2949769702 2014-04-10 07:05:00,18.7606154517 2014-04-10 07:10:00,20.7081627406 2014-04-10 07:15:00,20.851012008199998 2014-04-10 07:20:00,21.941540561100002 2014-04-10 07:25:00,20.165205265 2014-04-10 07:30:00,19.0854760601 2014-04-10 07:35:00,20.734690087 2014-04-10 07:40:00,21.9175032787 2014-04-10 07:45:00,18.7088556331 2014-04-10 07:50:00,19.3039916741 2014-04-10 07:55:00,20.1675238151 2014-04-10 08:00:00,18.6808585395 2014-04-10 08:05:00,18.0888825581 2014-04-10 08:10:00,19.3479324898 2014-04-10 08:15:00,21.461483206 2014-04-10 08:20:00,18.173873597300002 2014-04-10 08:25:00,19.7157162361 2014-04-10 08:30:00,21.0488030917 2014-04-10 08:35:00,21.812730387600002 2014-04-10 08:40:00,21.941901595999997 2014-04-10 08:45:00,19.6878775224 2014-04-10 08:50:00,21.8015371775 2014-04-10 08:55:00,18.1416758931 2014-04-10 09:00:00,71.3444703568 2014-04-10 09:05:00,69.941346071 2014-04-10 09:10:00,64.59349726319999 2014-04-10 09:15:00,68.0995316092 2014-04-10 09:20:00,62.961930833500006 2014-04-10 09:25:00,73.0537212529 2014-04-10 09:30:00,66.0674139634 2014-04-10 09:35:00,69.7142047983 2014-04-10 09:40:00,63.359357493500006 2014-04-10 09:45:00,64.003841887 2014-04-10 09:50:00,74.6906066429 2014-04-10 09:55:00,71.44197496439999 2014-04-10 10:00:00,84.7698034189 2014-04-10 10:05:00,74.4316100841 2014-04-10 10:10:00,72.3940158451 2014-04-10 10:15:00,77.6476225532 2014-04-10 10:20:00,77.51725174020001 2014-04-10 10:25:00,72.55516989350001 2014-04-10 10:30:00,81.2195677199 2014-04-10 10:35:00,75.4547873345 2014-04-10 10:40:00,72.73238838399999 2014-04-10 10:45:00,74.9923822833 2014-04-10 10:50:00,78.5879830183 2014-04-10 10:55:00,81.11482886739999 2014-04-10 11:00:00,79.2319926519 2014-04-10 11:05:00,79.92706271819999 2014-04-10 11:10:00,73.7777961652 2014-04-10 11:15:00,86.1152444666 2014-04-10 11:20:00,86.3384296449 2014-04-10 11:25:00,82.437216494 2014-04-10 11:30:00,71.8484099277 2014-04-10 11:35:00,80.1096283297 2014-04-10 11:40:00,81.5750985321 2014-04-10 11:45:00,87.3869807619 2014-04-10 11:50:00,87.40944885540002 2014-04-10 11:55:00,85.2074490866 2014-04-10 12:00:00,72.9336703174 2014-04-10 12:05:00,87.1477193458 2014-04-10 12:10:00,81.70441685850001 2014-04-10 12:15:00,84.7124113017 2014-04-10 12:20:00,78.42086749229999 2014-04-10 12:25:00,77.0221738859 2014-04-10 12:30:00,79.3166120401 2014-04-10 12:35:00,74.2607722169 2014-04-10 12:40:00,77.6198025502 2014-04-10 12:45:00,85.61901374029999 2014-04-10 12:50:00,72.5200791308 2014-04-10 12:55:00,74.3247518907 2014-04-10 13:00:00,73.9840981083 2014-04-10 13:05:00,78.4303808731 2014-04-10 13:10:00,87.93068198459999 2014-04-10 13:15:00,74.7557811889 2014-04-10 13:20:00,74.30988374020001 2014-04-10 13:25:00,86.6200978624 2014-04-10 13:30:00,86.0921411975 2014-04-10 13:35:00,72.4984421169 2014-04-10 13:40:00,84.007128812 2014-04-10 13:45:00,82.4676542353 2014-04-10 13:50:00,84.26362483289998 2014-04-10 13:55:00,79.89286038729999 2014-04-10 14:00:00,87.8578501159 2014-04-10 14:05:00,72.6980626249 2014-04-10 14:10:00,75.7463093851 2014-04-10 14:15:00,78.3409752443 2014-04-10 14:20:00,79.1926456356 2014-04-10 14:25:00,86.737714833 2014-04-10 14:30:00,80.95618374189999 2014-04-10 14:35:00,72.7182852831 2014-04-10 14:40:00,78.5220381761 2014-04-10 14:45:00,78.6600707333 2014-04-10 14:50:00,87.443657518 2014-04-10 14:55:00,81.58323727300001 2014-04-10 15:00:00,82.1696283025 2014-04-10 15:05:00,83.4112477444 2014-04-10 15:10:00,84.3198195729 2014-04-10 15:15:00,82.16002837939999 2014-04-10 15:20:00,75.7943819851 2014-04-10 15:25:00,85.983909176 2014-04-10 15:30:00,83.71311315300001 2014-04-10 15:35:00,83.86912261020001 2014-04-10 15:40:00,87.9440635566 2014-04-10 15:45:00,84.8396100897 2014-04-10 15:50:00,85.2656038928 2014-04-10 15:55:00,87.22165091549999 2014-04-10 16:00:00,74.4180011147 2014-04-10 16:05:00,79.9634844935 2014-04-10 16:10:00,81.2889163024 2014-04-10 16:15:00,77.2682633122 2014-04-10 16:20:00,85.4302894758 2014-04-10 16:25:00,84.1985522848 2014-04-10 16:30:00,83.5339688066 2014-04-10 16:35:00,87.95422216370001 2014-04-10 16:40:00,76.1499557663 2014-04-10 16:45:00,83.76715519359999 2014-04-10 16:50:00,80.82231641930001 2014-04-10 16:55:00,77.0076790649 2014-04-10 17:00:00,74.5693612969 2014-04-10 17:05:00,86.3341082408 2014-04-10 17:10:00,81.5272564168 2014-04-10 17:15:00,85.19890868590001 2014-04-10 17:20:00,80.7254887454 2014-04-10 17:25:00,75.5196042909 2014-04-10 17:30:00,77.4007512877 2014-04-10 17:35:00,78.1045914874 2014-04-10 17:40:00,87.5669233743 2014-04-10 17:45:00,72.0901047715 2014-04-10 17:50:00,87.77062266450001 2014-04-10 17:55:00,87.68735248979998 2014-04-10 18:00:00,35.1753583057 2014-04-10 18:05:00,31.850158229899996 2014-04-10 18:10:00,34.9683706916 2014-04-10 18:15:00,31.331828748099998 2014-04-10 18:20:00,28.9682788584 2014-04-10 18:25:00,30.2358161875 2014-04-10 18:30:00,34.8498892764 2014-04-10 18:35:00,28.888088490799998 2014-04-10 18:40:00,32.2943562662 2014-04-10 18:45:00,29.283844546399997 2014-04-10 18:50:00,30.6329322204 2014-04-10 18:55:00,29.363788606700002 2014-04-10 19:00:00,24.0106869054 2014-04-10 19:05:00,22.807995528000003 2014-04-10 19:10:00,24.2014356388 2014-04-10 19:15:00,23.2438210589 2014-04-10 19:20:00,24.510209163400003 2014-04-10 19:25:00,22.4442506621 2014-04-10 19:30:00,23.021422143400002 2014-04-10 19:35:00,22.741862265500004 2014-04-10 19:40:00,22.329485499 2014-04-10 19:45:00,23.9498966433 2014-04-10 19:50:00,23.0474713435 2014-04-10 19:55:00,23.7498776437 2014-04-10 20:00:00,21.652946424499998 2014-04-10 20:05:00,19.2145207475 2014-04-10 20:10:00,21.0950695761 2014-04-10 20:15:00,19.2497580556 2014-04-10 20:20:00,20.821280429 2014-04-10 20:25:00,21.206772213 2014-04-10 20:30:00,22.516674583 2014-04-10 20:35:00,18.5570997198 2014-04-10 20:40:00,18.8057286206 2014-04-10 20:45:00,18.7475011234 2014-04-10 20:50:00,20.0636875878 2014-04-10 20:55:00,21.7972256671 2014-04-10 21:00:00,21.4788311602 2014-04-10 21:05:00,21.0484683396 2014-04-10 21:10:00,21.6911329765 2014-04-10 21:15:00,19.3840386402 2014-04-10 21:20:00,18.4407111011 2014-04-10 21:25:00,18.3201286053 2014-04-10 21:30:00,21.5112917741 2014-04-10 21:35:00,21.0221695028 2014-04-10 21:40:00,20.8942745868 2014-04-10 21:45:00,19.4516270923 2014-04-10 21:50:00,19.6133148861 2014-04-10 21:55:00,21.9372498417 2014-04-10 22:00:00,18.2727439776 2014-04-10 22:05:00,21.1151780673 2014-04-10 22:10:00,19.2570022773 2014-04-10 22:15:00,18.173648434500002 2014-04-10 22:20:00,20.9904119019 2014-04-10 22:25:00,19.3421982349 2014-04-10 22:30:00,20.9086431112 2014-04-10 22:35:00,20.8506149151 2014-04-10 22:40:00,20.1584810734 2014-04-10 22:45:00,21.1297576193 2014-04-10 22:50:00,20.343664473900002 2014-04-10 22:55:00,19.1649280875 2014-04-10 23:00:00,20.9404810028 2014-04-10 23:05:00,20.3604677209 2014-04-10 23:10:00,18.0543748995 2014-04-10 23:15:00,21.6107251717 2014-04-10 23:20:00,20.1864495256 2014-04-10 23:25:00,21.478632165500002 2014-04-10 23:30:00,21.535081295700003 2014-04-10 23:35:00,19.7836643594 2014-04-10 23:40:00,20.034485866700003 2014-04-10 23:45:00,19.6667928481 2014-04-10 23:50:00,19.8015482667 2014-04-10 23:55:00,21.584732106799997 2014-04-11 00:00:00,21.1525760559 2014-04-11 00:05:00,18.5061027053 2014-04-11 00:10:00,20.441231126199998 2014-04-11 00:15:00,21.9836265615 2014-04-11 00:20:00,20.3822028049 2014-04-11 00:25:00,21.143486502400002 2014-04-11 00:30:00,21.076245893499998 2014-04-11 00:35:00,19.4012701035 2014-04-11 00:40:00,19.487397210799998 2014-04-11 00:45:00,20.8963056872 2014-04-11 00:50:00,19.9999341264 2014-04-11 00:55:00,20.282282836500002 2014-04-11 01:00:00,20.8516231615 2014-04-11 01:05:00,21.1103001082 2014-04-11 01:10:00,19.086066310899998 2014-04-11 01:15:00,18.5871750377 2014-04-11 01:20:00,19.1671785869 2014-04-11 01:25:00,20.0301533004 2014-04-11 01:30:00,19.3685652692 2014-04-11 01:35:00,20.2734510354 2014-04-11 01:40:00,18.2138628965 2014-04-11 01:45:00,20.0390016465 2014-04-11 01:50:00,19.4719396278 2014-04-11 01:55:00,20.1386670196 2014-04-11 02:00:00,19.6901334195 2014-04-11 02:05:00,19.1369034026 2014-04-11 02:10:00,21.616431621799997 2014-04-11 02:15:00,18.7390599537 2014-04-11 02:20:00,20.7254623023 2014-04-11 02:25:00,21.698578850300002 2014-04-11 02:30:00,20.154679838699998 2014-04-11 02:35:00,21.5056339543 2014-04-11 02:40:00,18.4994059137 2014-04-11 02:45:00,19.975155081 2014-04-11 02:50:00,19.8281011219 2014-04-11 02:55:00,18.0324752281 2014-04-11 03:00:00,19.7730293654 2014-04-11 03:05:00,19.4761190255 2014-04-11 03:10:00,20.679194911099998 2014-04-11 03:15:00,21.753319114299998 2014-04-11 03:20:00,18.343164353 2014-04-11 03:25:00,19.3099055469 2014-04-11 03:30:00,19.7762589496 2014-04-11 03:35:00,19.8207415121 2014-04-11 03:40:00,21.099238883399998 2014-04-11 03:45:00,19.7735826633 2014-04-11 03:50:00,18.1086452058 2014-04-11 03:55:00,20.8404163784 2014-04-11 04:00:00,21.5393187806 2014-04-11 04:05:00,20.0556188502 2014-04-11 04:10:00,20.3244340868 2014-04-11 04:15:00,18.6517457559 2014-04-11 04:20:00,18.8825837787 2014-04-11 04:25:00,18.9406809565 2014-04-11 04:30:00,19.722967899500002 2014-04-11 04:35:00,21.7125808836 2014-04-11 04:40:00,20.0871390669 2014-04-11 04:45:00,18.7683905808 2014-04-11 04:50:00,19.0643509435 2014-04-11 04:55:00,19.5360601189 2014-04-11 05:00:00,20.4930359028 2014-04-11 05:05:00,19.760132612 2014-04-11 05:10:00,19.5697793767 2014-04-11 05:15:00,20.258914401600002 2014-04-11 05:20:00,18.9673399798 2014-04-11 05:25:00,18.3156130903 2014-04-11 05:30:00,18.0976572593 2014-04-11 05:35:00,19.0050366539 2014-04-11 05:40:00,18.366368136600002 2014-04-11 05:45:00,19.3453625541 2014-04-11 05:50:00,21.0917341614 2014-04-11 05:55:00,20.8651773219 2014-04-11 06:00:00,20.443710491199997 2014-04-11 06:05:00,21.4100009755 2014-04-11 06:10:00,19.1282704982 2014-04-11 06:15:00,21.5402150121 2014-04-11 06:20:00,19.5969566787 2014-04-11 06:25:00,19.6035732731 2014-04-11 06:30:00,19.6214064545 2014-04-11 06:35:00,18.392377465 2014-04-11 06:40:00,21.9019619933 2014-04-11 06:45:00,18.5540271113 2014-04-11 06:50:00,19.3635428979 2014-04-11 06:55:00,19.2772012813 2014-04-11 07:00:00,18.298717731300002 2014-04-11 07:05:00,18.6090405204 2014-04-11 07:10:00,18.1794333447 2014-04-11 07:15:00,19.1696179742 2014-04-11 07:20:00,21.466627696099998 2014-04-11 07:25:00,19.3577688229 2014-04-11 07:30:00,18.4947673283 2014-04-11 07:35:00,20.5827754735 2014-04-11 07:40:00,21.986403648200003 2014-04-11 07:45:00,18.9292951581 2014-04-11 07:50:00,19.118284021500003 2014-04-11 07:55:00,21.8873882171 2014-04-11 08:00:00,18.7151051502 2014-04-11 08:05:00,20.0448562698 2014-04-11 08:10:00,18.9586085321 2014-04-11 08:15:00,21.729407591599998 2014-04-11 08:20:00,21.9260840583 2014-04-11 08:25:00,21.2587913845 2014-04-11 08:30:00,19.2591352633 2014-04-11 08:35:00,19.6139499011 2014-04-11 08:40:00,18.9692227347 2014-04-11 08:45:00,21.563031868000003 2014-04-11 08:50:00,21.658233110799998 2014-04-11 08:55:00,19.675482649 2014-04-11 09:00:00,127.882020134 2014-04-11 09:05:00,115.705718858 2014-04-11 09:10:00,122.386410329 2014-04-11 09:15:00,127.26117784600001 2014-04-11 09:20:00,121.15799733899999 2014-04-11 09:25:00,120.46846823700001 2014-04-11 09:30:00,111.62477500799999 2014-04-11 09:35:00,131.54647790200002 2014-04-11 09:40:00,133.655572778 2014-04-11 09:45:00,135.642695533 2014-04-11 09:50:00,129.43793035 2014-04-11 09:55:00,125.21004934700001 2014-04-11 10:00:00,138.118479694 2014-04-11 10:05:00,159.259712824 2014-04-11 10:10:00,147.399242667 2014-04-11 10:15:00,150.046221935 2014-04-11 10:20:00,150.08248245 2014-04-11 10:25:00,154.798492005 2014-04-11 10:30:00,130.600116725 2014-04-11 10:35:00,136.698351395 2014-04-11 10:40:00,149.593864645 2014-04-11 10:45:00,156.24342053799998 2014-04-11 10:50:00,150.16741112399998 2014-04-11 10:55:00,142.294707802 2014-04-11 11:00:00,144.83546133299998 2014-04-11 11:05:00,156.04894706299999 2014-04-11 11:10:00,156.146953473 2014-04-11 11:15:00,152.149471713 2014-04-11 11:20:00,142.74738558200002 2014-04-11 11:25:00,161.62621235 2014-04-11 11:30:00,150.505607236 2014-04-11 11:35:00,157.614348277 2014-04-11 11:40:00,140.448671746 2014-04-11 11:45:00,144.313663174 2014-04-11 11:50:00,160.119472952 2014-04-11 11:55:00,135.556788636 2014-04-11 12:00:00,150.160947021 2014-04-11 12:05:00,149.243925447 2014-04-11 12:10:00,157.318454491 2014-04-11 12:15:00,143.257886337 2014-04-11 12:20:00,141.37569147600001 2014-04-11 12:25:00,162.558258037 2014-04-11 12:30:00,151.940306437 2014-04-11 12:35:00,137.949131962 2014-04-11 12:40:00,140.595854562 2014-04-11 12:45:00,164.736030621 2014-04-11 12:50:00,140.67293255299998 2014-04-11 12:55:00,153.101669559 2014-04-11 13:00:00,147.562906904 2014-04-11 13:05:00,161.523164661 2014-04-11 13:10:00,157.611334766 2014-04-11 13:15:00,152.86613525200002 2014-04-11 13:20:00,135.284640106 2014-04-11 13:25:00,161.349096329 2014-04-11 13:30:00,148.298884492 2014-04-11 13:35:00,162.902138864 2014-04-11 13:40:00,149.824607501 2014-04-11 13:45:00,155.783518728 2014-04-11 13:50:00,137.04076296899999 2014-04-11 13:55:00,157.310909944 2014-04-11 14:00:00,145.131830514 2014-04-11 14:05:00,145.532697769 2014-04-11 14:10:00,138.551989898 2014-04-11 14:15:00,139.397982089 2014-04-11 14:20:00,140.56497458299998 2014-04-11 14:25:00,144.838150922 2014-04-11 14:30:00,161.750125145 2014-04-11 14:35:00,146.039706362 2014-04-11 14:40:00,156.722187857 2014-04-11 14:45:00,137.474799425 2014-04-11 14:50:00,152.72449239 2014-04-11 14:55:00,149.448447071 2014-04-11 15:00:00,164.336915344 2014-04-11 15:05:00,160.384453878 2014-04-11 15:10:00,148.643244206 2014-04-11 15:15:00,158.252527354 2014-04-11 15:20:00,140.789600396 2014-04-11 15:25:00,151.86840507600002 2014-04-11 15:30:00,137.23704923399998 2014-04-11 15:35:00,145.441057524 2014-04-11 15:40:00,141.774292682 2014-04-11 15:45:00,156.56555760700002 2014-04-11 15:50:00,149.701060034 2014-04-11 15:55:00,157.530366809 2014-04-11 16:00:00,150.458529311 2014-04-11 16:05:00,137.594227988 2014-04-11 16:10:00,157.060681026 2014-04-11 16:15:00,159.99652294 2014-04-11 16:20:00,162.10557711799999 2014-04-11 16:25:00,152.159420767 2014-04-11 16:30:00,157.607211091 2014-04-11 16:35:00,157.56098053 2014-04-11 16:40:00,139.672182907 2014-04-11 16:45:00,139.926310173 2014-04-11 16:50:00,137.126260936 2014-04-11 16:55:00,144.597088241 2014-04-11 17:00:00,149.205191425 2014-04-11 17:05:00,164.936862395 2014-04-11 17:10:00,147.929734621 2014-04-11 17:15:00,156.787208083 2014-04-11 17:20:00,155.801841654 2014-04-11 17:25:00,141.134395882 2014-04-11 17:30:00,136.755153861 2014-04-11 17:35:00,151.380135374 2014-04-11 17:40:00,156.009098543 2014-04-11 17:45:00,164.947480513 2014-04-11 17:50:00,145.758266891 2014-04-11 17:55:00,161.890865026 2014-04-11 18:00:00,44.9137655963 2014-04-11 18:05:00,47.7425739013 2014-04-11 18:10:00,46.9039133872 2014-04-11 18:15:00,41.8873927765 2014-04-11 18:20:00,42.121161338600004 2014-04-11 18:25:00,41.5910175894 2014-04-11 18:30:00,44.81166061020001 2014-04-11 18:35:00,48.26135568220001 2014-04-11 18:40:00,42.98933718399999 2014-04-11 18:45:00,46.973833715299996 2014-04-11 18:50:00,44.057202826499996 2014-04-11 18:55:00,48.7323180379 2014-04-11 19:00:00,26.703913769699998 2014-04-11 19:05:00,26.588086346399997 2014-04-11 19:10:00,25.325158233899998 2014-04-11 19:15:00,24.1142136711 2014-04-11 19:20:00,26.759595154 2014-04-11 19:25:00,23.6179443369 2014-04-11 19:30:00,24.1403858438 2014-04-11 19:35:00,23.607093944899997 2014-04-11 19:40:00,26.0780164532 2014-04-11 19:45:00,26.1386268201 2014-04-11 19:50:00,25.96864762 2014-04-11 19:55:00,24.774628775500002 2014-04-11 20:00:00,19.3575191084 2014-04-11 20:05:00,22.7702010354 2014-04-11 20:10:00,21.072531363299998 2014-04-11 20:15:00,20.6485384736 2014-04-11 20:20:00,21.4137746088 2014-04-11 20:25:00,19.7472616542 2014-04-11 20:30:00,19.4937647691 2014-04-11 20:35:00,20.6424496095 2014-04-11 20:40:00,19.8921441773 2014-04-11 20:45:00,19.9639730542 2014-04-11 20:50:00,22.6916877663 2014-04-11 20:55:00,21.169434081800002 2014-04-11 21:00:00,20.141188464200003 2014-04-11 21:05:00,20.9738006155 2014-04-11 21:10:00,22.032976740100004 2014-04-11 21:15:00,18.6406616199 2014-04-11 21:20:00,21.556013192800002 2014-04-11 21:25:00,20.547571809100003 2014-04-11 21:30:00,18.777941795 2014-04-11 21:35:00,19.3881585842 2014-04-11 21:40:00,20.136711794700002 2014-04-11 21:45:00,20.980661437000002 2014-04-11 21:50:00,19.1677204187 2014-04-11 21:55:00,20.3489661134 2014-04-11 22:00:00,20.7818229555 2014-04-11 22:05:00,19.8361365054 2014-04-11 22:10:00,21.496724197600003 2014-04-11 22:15:00,21.522510288200003 2014-04-11 22:20:00,19.9241210003 2014-04-11 22:25:00,21.9372375602 2014-04-11 22:30:00,18.3404092181 2014-04-11 22:35:00,18.0509174691 2014-04-11 22:40:00,19.5632801944 2014-04-11 22:45:00,20.4468293513 2014-04-11 22:50:00,20.5594755533 2014-04-11 22:55:00,19.9471869525 2014-04-11 23:00:00,18.5072290549 2014-04-11 23:05:00,18.689761791 2014-04-11 23:10:00,21.4174979051 2014-04-11 23:15:00,21.4805767265 2014-04-11 23:20:00,20.7042035142 2014-04-11 23:25:00,20.6654651434 2014-04-11 23:30:00,20.399211050799998 2014-04-11 23:35:00,18.8195292075 2014-04-11 23:40:00,19.721203406 2014-04-11 23:45:00,20.7922245701 2014-04-11 23:50:00,20.1573910715 2014-04-11 23:55:00,18.08184025 2014-04-12 00:00:00,21.8142272269 2014-04-12 00:05:00,21.3792642103 2014-04-12 00:10:00,19.0421800564 2014-04-12 00:15:00,20.465835740699998 2014-04-12 00:20:00,21.692957534899996 2014-04-12 00:25:00,18.384044048499998 2014-04-12 00:30:00,20.012117923199998 2014-04-12 00:35:00,19.8249721034 2014-04-12 00:40:00,19.640820021099998 2014-04-12 00:45:00,21.3423544356 2014-04-12 00:50:00,19.5225845868 2014-04-12 00:55:00,18.254653333 2014-04-12 01:00:00,18.2633509687 2014-04-12 01:05:00,18.1709784261 2014-04-12 01:10:00,19.6365816875 2014-04-12 01:15:00,20.8736251108 2014-04-12 01:20:00,18.814889847699998 2014-04-12 01:25:00,20.585874081700002 2014-04-12 01:30:00,20.7483538884 2014-04-12 01:35:00,19.0208084961 2014-04-12 01:40:00,20.4022306242 2014-04-12 01:45:00,20.7394733601 2014-04-12 01:50:00,19.8664544912 2014-04-12 01:55:00,19.3468663891 2014-04-12 02:00:00,20.4766062063 2014-04-12 02:05:00,21.911388349299997 2014-04-12 02:10:00,19.7073656375 2014-04-12 02:15:00,19.5669403851 2014-04-12 02:20:00,19.8570676097 2014-04-12 02:25:00,18.304873573800002 2014-04-12 02:30:00,20.2126531187 2014-04-12 02:35:00,19.314789548900002 2014-04-12 02:40:00,18.4856884893 2014-04-12 02:45:00,19.8650269645 2014-04-12 02:50:00,18.013535946300003 2014-04-12 02:55:00,19.6071409807 2014-04-12 03:00:00,18.422941071700002 2014-04-12 03:05:00,18.0971708136 2014-04-12 03:10:00,21.297900185 2014-04-12 03:15:00,21.6649952131 2014-04-12 03:20:00,18.830698593399998 2014-04-12 03:25:00,20.1571930553 2014-04-12 03:30:00,19.1118326285 2014-04-12 03:35:00,19.974309754700002 2014-04-12 03:40:00,19.7465252836 2014-04-12 03:45:00,19.0762042203 2014-04-12 03:50:00,20.8015743185 2014-04-12 03:55:00,18.5059638373 2014-04-12 04:00:00,18.2122911287 2014-04-12 04:05:00,21.0707017321 2014-04-12 04:10:00,20.6637201249 2014-04-12 04:15:00,19.994104496600002 2014-04-12 04:20:00,19.8711590819 2014-04-12 04:25:00,19.989645518 2014-04-12 04:30:00,19.7480963044 2014-04-12 04:35:00,19.5715691833 2014-04-12 04:40:00,19.9987624115 2014-04-12 04:45:00,20.114060684600002 2014-04-12 04:50:00,20.767609256300002 2014-04-12 04:55:00,20.8448286429 2014-04-12 05:00:00,19.5105163206 2014-04-12 05:05:00,19.654162091 2014-04-12 05:10:00,19.4947886789 2014-04-12 05:15:00,20.1461430945 2014-04-12 05:20:00,19.8134141517 2014-04-12 05:25:00,21.5583858525 2014-04-12 05:30:00,20.7854450677 2014-04-12 05:35:00,21.594625535 2014-04-12 05:40:00,20.836547966199998 2014-04-12 05:45:00,21.883968594099997 2014-04-12 05:50:00,20.542947113 2014-04-12 05:55:00,21.8542005527 2014-04-12 06:00:00,18.6326795616 2014-04-12 06:05:00,18.2099107233 2014-04-12 06:10:00,20.3165007408 2014-04-12 06:15:00,21.9339728232 2014-04-12 06:20:00,19.6704209892 2014-04-12 06:25:00,18.8481734488 2014-04-12 06:30:00,20.0861657968 2014-04-12 06:35:00,20.5951944983 2014-04-12 06:40:00,19.2607147821 2014-04-12 06:45:00,20.859077434 2014-04-12 06:50:00,21.900458028200003 2014-04-12 06:55:00,21.5878524868 2014-04-12 07:00:00,19.166341494 2014-04-12 07:05:00,19.3068947326 2014-04-12 07:10:00,19.4861648978 2014-04-12 07:15:00,19.5782111136 2014-04-12 07:20:00,18.4012779968 2014-04-12 07:25:00,21.0478513556 2014-04-12 07:30:00,19.4613570544 2014-04-12 07:35:00,21.519279906799998 2014-04-12 07:40:00,21.7077624925 2014-04-12 07:45:00,18.0977252372 2014-04-12 07:50:00,21.9540122797 2014-04-12 07:55:00,20.840090926 2014-04-12 08:00:00,20.081568904 2014-04-12 08:05:00,19.558110433499998 2014-04-12 08:10:00,20.0740725304 2014-04-12 08:15:00,19.2984988959 2014-04-12 08:20:00,20.4907512548 2014-04-12 08:25:00,18.3719211058 2014-04-12 08:30:00,20.4844904116 2014-04-12 08:35:00,19.1013794006 2014-04-12 08:40:00,18.070539316199998 2014-04-12 08:45:00,20.2108230647 2014-04-12 08:50:00,20.3137910234 2014-04-12 08:55:00,19.7062760188 2014-04-12 09:00:00,62.18309276270001 2014-04-12 09:05:00,73.3494641581 2014-04-12 09:10:00,69.5154589783 2014-04-12 09:15:00,62.7737008741 2014-04-12 09:20:00,68.1486558417 2014-04-12 09:25:00,67.9626586969 2014-04-12 09:30:00,62.021465415600005 2014-04-12 09:35:00,69.45329196899999 2014-04-12 09:40:00,72.1932390253 2014-04-12 09:45:00,71.3865095378 2014-04-12 09:50:00,63.960384032600004 2014-04-12 09:55:00,72.9271784019 2014-04-12 10:00:00,75.156254411 2014-04-12 10:05:00,84.5298100311 2014-04-12 10:10:00,70.9535284048 2014-04-12 10:15:00,77.3859588458 2014-04-12 10:20:00,79.1073703338 2014-04-12 10:25:00,73.6835295283 2014-04-12 10:30:00,81.8118205289 2014-04-12 10:35:00,79.56942095069999 2014-04-12 10:40:00,70.1210584667 2014-04-12 10:45:00,79.28188052760001 2014-04-12 10:50:00,77.4677421982 2014-04-12 10:55:00,72.8823732104 2014-04-12 11:00:00,87.4043798032 2014-04-12 11:05:00,85.83646754649999 2014-04-12 11:10:00,76.2200423817 2014-04-12 11:15:00,80.1731919244 2014-04-12 11:20:00,76.6016500331 2014-04-12 11:25:00,83.901484434 2014-04-12 11:30:00,86.36399111360001 2014-04-12 11:35:00,77.2748101644 2014-04-12 11:40:00,84.3800118984 2014-04-12 11:45:00,79.4946735593 2014-04-12 11:50:00,77.8751854391 2014-04-12 11:55:00,86.4926611358 2014-04-12 12:00:00,80.0702752495 2014-04-12 12:05:00,79.3831937225 2014-04-12 12:10:00,82.65963969090001 2014-04-12 12:15:00,76.0883315196 2014-04-12 12:20:00,77.10404990949999 2014-04-12 12:25:00,86.8084380998 2014-04-12 12:30:00,82.757049754 2014-04-12 12:35:00,85.1239229311 2014-04-12 12:40:00,76.24618284510001 2014-04-12 12:45:00,80.60380226720001 2014-04-12 12:50:00,87.43728946350002 2014-04-12 12:55:00,77.0067432696 2014-04-12 13:00:00,74.5497273914 2014-04-12 13:05:00,80.1549343293 2014-04-12 13:10:00,78.18636818659999 2014-04-12 13:15:00,74.53534294800001 2014-04-12 13:20:00,86.1961300859 2014-04-12 13:25:00,87.830498189 2014-04-12 13:30:00,81.0778515355 2014-04-12 13:35:00,84.3745735352 2014-04-12 13:40:00,85.7240352054 2014-04-12 13:45:00,83.1957403254 2014-04-12 13:50:00,72.6890472266 2014-04-12 13:55:00,74.504262392 2014-04-12 14:00:00,73.1323165387 2014-04-12 14:05:00,72.15461011869998 2014-04-12 14:10:00,76.8922515349 2014-04-12 14:15:00,78.2739380383 2014-04-12 14:20:00,75.8528346065 2014-04-12 14:25:00,73.030168753 2014-04-12 14:30:00,80.4739465185 2014-04-12 14:35:00,76.3694432101 2014-04-12 14:40:00,84.7325271213 2014-04-12 14:45:00,72.1253797616 2014-04-12 14:50:00,85.4763297598 2014-04-12 14:55:00,87.2718696123 2014-04-12 15:00:00,83.4573598121 2014-04-12 15:05:00,83.7375011565 2014-04-12 15:10:00,86.93616239049999 2014-04-12 15:15:00,75.34441725149999 2014-04-12 15:20:00,87.9122051261 2014-04-12 15:25:00,84.37488924729999 2014-04-12 15:30:00,83.62432853199999 2014-04-12 15:35:00,77.7767026004 2014-04-12 15:40:00,80.7316647351 2014-04-12 15:45:00,82.4618929706 2014-04-12 15:50:00,81.92469929640001 2014-04-12 15:55:00,83.27895473 2014-04-12 16:00:00,73.3179670545 2014-04-12 16:05:00,77.6902257598 2014-04-12 16:10:00,78.943848693 2014-04-12 16:15:00,76.16992251949999 2014-04-12 16:20:00,74.7618927812 2014-04-12 16:25:00,74.2226971708 2014-04-12 16:30:00,77.8619847808 2014-04-12 16:35:00,79.8949138105 2014-04-12 16:40:00,73.0074828677 2014-04-12 16:45:00,87.1431621983 2014-04-12 16:50:00,84.2437314175 2014-04-12 16:55:00,83.6934676792 2014-04-12 17:00:00,74.7657396898 2014-04-12 17:05:00,81.6607809304 2014-04-12 17:10:00,80.4755682463 2014-04-12 17:15:00,87.7194678483 2014-04-12 17:20:00,83.9627160796 2014-04-12 17:25:00,81.212158954 2014-04-12 17:30:00,85.6129697881 2014-04-12 17:35:00,74.4814797329 2014-04-12 17:40:00,72.24343673359999 2014-04-12 17:45:00,83.0437014458 2014-04-12 17:50:00,73.5729551118 2014-04-12 17:55:00,73.8469098825 2014-04-12 18:00:00,33.5659502045 2014-04-12 18:05:00,30.5314171404 2014-04-12 18:10:00,32.8232334776 2014-04-12 18:15:00,34.6713976701 2014-04-12 18:20:00,30.825431084 2014-04-12 18:25:00,30.1897168137 2014-04-12 18:30:00,29.4819967954 2014-04-12 18:35:00,29.634953423200002 2014-04-12 18:40:00,29.1982196444 2014-04-12 18:45:00,29.360905587199998 2014-04-12 18:50:00,31.5648233079 2014-04-12 18:55:00,30.8535303643 2014-04-12 19:00:00,23.32539116860001 2014-04-12 19:05:00,24.0586813092 2014-04-12 19:10:00,23.6757826513 2014-04-12 19:15:00,22.5372536735 2014-04-12 19:20:00,20.6189395496 2014-04-12 19:25:00,23.3397561517 2014-04-12 19:30:00,21.7854714917 2014-04-12 19:35:00,20.5437126378 2014-04-12 19:40:00,23.9342481913 2014-04-12 19:45:00,21.6752088079 2014-04-12 19:50:00,21.1377536101 2014-04-12 19:55:00,24.0641039294 2014-04-12 20:00:00,22.127140059600002 2014-04-12 20:05:00,19.820424311300002 2014-04-12 20:10:00,19.8852663748 2014-04-12 20:15:00,20.8061581993 2014-04-12 20:20:00,21.4361761014 2014-04-12 20:25:00,18.6906589067 2014-04-12 20:30:00,20.862335369500002 2014-04-12 20:35:00,22.334750705 2014-04-12 20:40:00,19.5055363688 2014-04-12 20:45:00,22.154556003099998 2014-04-12 20:50:00,22.323889255900003 2014-04-12 20:55:00,19.534453079000002 2014-04-12 21:00:00,21.1176880877 2014-04-12 21:05:00,19.046084466900002 2014-04-12 21:10:00,21.0510067297 2014-04-12 21:15:00,21.2913902965 2014-04-12 21:20:00,19.0799691177 2014-04-12 21:25:00,20.9636228183 2014-04-12 21:30:00,21.3504105104 2014-04-12 21:35:00,19.527600155 2014-04-12 21:40:00,18.7604309514 2014-04-12 21:45:00,18.4560239438 2014-04-12 21:50:00,20.398974093299998 2014-04-12 21:55:00,22.0175719073 2014-04-12 22:00:00,21.3122413989 2014-04-12 22:05:00,19.7623121702 2014-04-12 22:10:00,20.165824225799998 2014-04-12 22:15:00,19.1364649193 2014-04-12 22:20:00,18.6701696332 2014-04-12 22:25:00,19.9474558148 2014-04-12 22:30:00,19.873066100899997 2014-04-12 22:35:00,20.1070040124 2014-04-12 22:40:00,21.8321571011 2014-04-12 22:45:00,20.4351801485 2014-04-12 22:50:00,20.4426935003 2014-04-12 22:55:00,18.5298706574 2014-04-12 23:00:00,21.990176765999998 2014-04-12 23:05:00,21.0954293198 2014-04-12 23:10:00,21.5129430664 2014-04-12 23:15:00,19.6609758281 2014-04-12 23:20:00,20.0123540156 2014-04-12 23:25:00,20.092192195 2014-04-12 23:30:00,18.7799832199 2014-04-12 23:35:00,20.761942150899998 2014-04-12 23:40:00,21.616056378499998 2014-04-12 23:45:00,18.6584049968 2014-04-12 23:50:00,18.3487953846 2014-04-12 23:55:00,20.9568985722 2014-04-13 00:00:00,19.0928073267 2014-04-13 00:05:00,20.4954501665 2014-04-13 00:10:00,20.783033352 2014-04-13 00:15:00,19.287643054300002 2014-04-13 00:20:00,100.000000000 2014-04-13 00:25:00,20.1999559285 2014-04-13 00:30:00,21.4759976318 2014-04-13 00:35:00,21.053174210199998 2014-04-13 00:40:00,21.4743025281 2014-04-13 00:45:00,18.0806455285 2014-04-13 00:50:00,18.974025043 2014-04-13 00:55:00,18.360031761800002 2014-04-13 01:00:00,19.7683320688 2014-04-13 01:05:00,21.5598404865 2014-04-13 01:10:00,19.870161049100002 2014-04-13 01:15:00,21.3988521783 2014-04-13 01:20:00,19.3087129521 2014-04-13 01:25:00,19.3582802912 2014-04-13 01:30:00,21.5822469213 2014-04-13 01:35:00,19.703268586 2014-04-13 01:40:00,21.159061951199998 2014-04-13 01:45:00,18.9465741915 2014-04-13 01:50:00,21.7952033187 2014-04-13 01:55:00,20.298312986099997 2014-04-13 02:00:00,21.037294274300002 2014-04-13 02:05:00,18.358062799200003 2014-04-13 02:10:00,19.9706569033 2014-04-13 02:15:00,21.604153990900002 2014-04-13 02:20:00,21.508154516199998 2014-04-13 02:25:00,18.1872558289 2014-04-13 02:30:00,19.2147938765 2014-04-13 02:35:00,19.7732800259 2014-04-13 02:40:00,18.6890592574 2014-04-13 02:45:00,20.919993244 2014-04-13 02:50:00,18.7380479824 2014-04-13 02:55:00,19.3865587775 2014-04-13 03:00:00,20.6531225474 2014-04-13 03:05:00,19.9283573781 2014-04-13 03:10:00,20.9542841545 2014-04-13 03:15:00,21.844831604899998 2014-04-13 03:20:00,18.4661867509 2014-04-13 03:25:00,20.8382708656 2014-04-13 03:30:00,18.9213766225 2014-04-13 03:35:00,19.6579069096 2014-04-13 03:40:00,18.1314509032 2014-04-13 03:45:00,18.5436295292 2014-04-13 03:50:00,19.2791091562 2014-04-13 03:55:00,19.367943221199997 2014-04-13 04:00:00,21.5983408658 2014-04-13 04:05:00,20.9672516371 2014-04-13 04:10:00,21.8887318727 2014-04-13 04:15:00,20.3962860413 2014-04-13 04:20:00,18.9668549284 2014-04-13 04:25:00,19.3106201197 2014-04-13 04:30:00,19.279343693199998 2014-04-13 04:35:00,19.305977310699998 2014-04-13 04:40:00,20.691856692400002 2014-04-13 04:45:00,20.1232317124 2014-04-13 04:50:00,19.5416967123 2014-04-13 04:55:00,18.5963590749 2014-04-13 05:00:00,18.0885566518 2014-04-13 05:05:00,18.8753387104 2014-04-13 05:10:00,18.429885615899998 2014-04-13 05:15:00,21.1417801234 2014-04-13 05:20:00,18.4499918313 2014-04-13 05:25:00,20.8969129492 2014-04-13 05:30:00,19.5426347591 2014-04-13 05:35:00,18.293513559 2014-04-13 05:40:00,21.2509201977 2014-04-13 05:45:00,20.318522280899998 2014-04-13 05:50:00,18.9430460515 2014-04-13 05:55:00,21.5787246973 2014-04-13 06:00:00,18.1810332555 2014-04-13 06:05:00,18.8072784328 2014-04-13 06:10:00,21.008187711199998 2014-04-13 06:15:00,20.8375117212 2014-04-13 06:20:00,19.1570867749 2014-04-13 06:25:00,18.248099501400002 2014-04-13 06:30:00,21.4323122889 2014-04-13 06:35:00,19.2547905523 2014-04-13 06:40:00,18.7828536597 2014-04-13 06:45:00,20.0642472894 2014-04-13 06:50:00,21.6409087971 2014-04-13 06:55:00,18.1741863114 2014-04-13 07:00:00,21.0632163521 2014-04-13 07:05:00,20.2898929118 2014-04-13 07:10:00,19.701796466199998 2014-04-13 07:15:00,20.976321776400003 2014-04-13 07:20:00,21.863297697800004 2014-04-13 07:25:00,18.9168248447 2014-04-13 07:30:00,18.5745894603 2014-04-13 07:35:00,21.6515269809 2014-04-13 07:40:00,20.6758123098 2014-04-13 07:45:00,19.751944086199998 2014-04-13 07:50:00,20.2930382811 2014-04-13 07:55:00,20.982455620699998 2014-04-13 08:00:00,21.0921275948 2014-04-13 08:05:00,21.6795767233 2014-04-13 08:10:00,19.7073711556 2014-04-13 08:15:00,19.1736436401 2014-04-13 08:20:00,20.5586570672 2014-04-13 08:25:00,19.6629115971 2014-04-13 08:30:00,20.3783938158 2014-04-13 08:35:00,19.6799431938 2014-04-13 08:40:00,18.611983146700002 2014-04-13 08:45:00,19.8777070066 2014-04-13 08:50:00,20.7636712878 2014-04-13 08:55:00,21.1971352307 2014-04-13 09:00:00,67.9092373644 2014-04-13 09:05:00,63.4472353069 2014-04-13 09:10:00,66.8397528512 2014-04-13 09:15:00,71.8935974322 2014-04-13 09:20:00,66.8148860804 2014-04-13 09:25:00,70.672818793 2014-04-13 09:30:00,68.0981060708 2014-04-13 09:35:00,64.48063450149999 2014-04-13 09:40:00,72.0276469091 2014-04-13 09:45:00,62.3453029754 2014-04-13 09:50:00,68.3385078455 2014-04-13 09:55:00,64.0409180657 2014-04-13 10:00:00,70.880858555 2014-04-13 10:05:00,77.6455347035 2014-04-13 10:10:00,77.5932046601 2014-04-13 10:15:00,80.811101994 2014-04-13 10:20:00,81.3985307562 2014-04-13 10:25:00,81.1353239045 2014-04-13 10:30:00,76.1963515349 2014-04-13 10:35:00,79.6438254978 2014-04-13 10:40:00,78.7941901658 2014-04-13 10:45:00,76.3826384549 2014-04-13 10:50:00,79.1087410138 2014-04-13 10:55:00,84.5412870465 2014-04-13 11:00:00,74.63578209949999 2014-04-13 11:05:00,85.9733994114 2014-04-13 11:10:00,72.4181564944 2014-04-13 11:15:00,76.472622042 2014-04-13 11:20:00,76.1506620339 2014-04-13 11:25:00,81.5297106757 2014-04-13 11:30:00,73.6550016331 2014-04-13 11:35:00,85.6008564187 2014-04-13 11:40:00,84.7452816002 2014-04-13 11:45:00,81.93845479630002 2014-04-13 11:50:00,78.8586135808 2014-04-13 11:55:00,86.4057328942 2014-04-13 12:00:00,85.1895945417 2014-04-13 12:05:00,79.8930555185 2014-04-13 12:10:00,83.1300977029 2014-04-13 12:15:00,80.97359417979999 2014-04-13 12:20:00,81.3093873232 2014-04-13 12:25:00,77.2028623705 2014-04-13 12:30:00,79.29808164960002 2014-04-13 12:35:00,73.1620429612 2014-04-13 12:40:00,77.6243179718 2014-04-13 12:45:00,83.0334963383 2014-04-13 12:50:00,87.14675474030001 2014-04-13 12:55:00,87.3041349732 2014-04-13 13:00:00,80.8721519302 2014-04-13 13:05:00,81.6863465995 2014-04-13 13:10:00,74.9535457987 2014-04-13 13:15:00,83.1049797464 2014-04-13 13:20:00,73.112989353 2014-04-13 13:25:00,76.53659777979999 2014-04-13 13:30:00,82.6739670413 2014-04-13 13:35:00,76.9464905138 2014-04-13 13:40:00,72.7800785738 2014-04-13 13:45:00,85.2894521672 2014-04-13 13:50:00,76.9468084469 2014-04-13 13:55:00,72.99216127369998 2014-04-13 14:00:00,73.1930971947 2014-04-13 14:05:00,76.0244914299 2014-04-13 14:10:00,74.84466243930001 2014-04-13 14:15:00,84.38475122199999 2014-04-13 14:20:00,77.1432416933 2014-04-13 14:25:00,84.8710585543 2014-04-13 14:30:00,74.7779464514 2014-04-13 14:35:00,79.8822323415 2014-04-13 14:40:00,83.0046097243 2014-04-13 14:45:00,82.4278969329 2014-04-13 14:50:00,81.6141528915 2014-04-13 14:55:00,86.7929793679 2014-04-13 15:00:00,75.65567606180001 2014-04-13 15:05:00,79.8987402361 2014-04-13 15:10:00,86.1430538199 2014-04-13 15:15:00,73.245597085 2014-04-13 15:20:00,72.89351250760001 2014-04-13 15:25:00,75.7321095657 2014-04-13 15:30:00,82.1275510805 2014-04-13 15:35:00,76.15734290569999 2014-04-13 15:40:00,75.0431177201 2014-04-13 15:45:00,79.3400753737 2014-04-13 15:50:00,81.8167836516 2014-04-13 15:55:00,75.9761939338 2014-04-13 16:00:00,76.8109115103 2014-04-13 16:05:00,81.8167917884 2014-04-13 16:10:00,87.1316474587 2014-04-13 16:15:00,82.7957086709 2014-04-13 16:20:00,84.5263040065 2014-04-13 16:25:00,77.8688120077 2014-04-13 16:30:00,76.35592314649999 2014-04-13 16:35:00,79.2681316961 2014-04-13 16:40:00,84.91396222430001 2014-04-13 16:45:00,79.3006420111 2014-04-13 16:50:00,85.5474422892 2014-04-13 16:55:00,87.820183076 2014-04-13 17:00:00,73.1523985612 2014-04-13 17:05:00,72.7265345703 2014-04-13 17:10:00,74.3934066795 2014-04-13 17:15:00,78.1498848022 2014-04-13 17:20:00,74.0966468932 2014-04-13 17:25:00,85.93059864450001 2014-04-13 17:30:00,72.3703122262 2014-04-13 17:35:00,77.0526538731 2014-04-13 17:40:00,74.9550852891 2014-04-13 17:45:00,86.9045959111 2014-04-13 17:50:00,82.7116643169 2014-04-13 17:55:00,86.59245085170002 2014-04-13 18:00:00,35.022897021599995 2014-04-13 18:05:00,31.981422619099998 2014-04-13 18:10:00,30.299636474 2014-04-13 18:15:00,30.039858464 2014-04-13 18:20:00,30.2266749113 2014-04-13 18:25:00,33.3349907685 2014-04-13 18:30:00,29.0588470807 2014-04-13 18:35:00,29.128705274699996 2014-04-13 18:40:00,32.6921085544 2014-04-13 18:45:00,32.9091594206 2014-04-13 18:50:00,33.0576763686 2014-04-13 18:55:00,31.180029242800003 2014-04-13 19:00:00,23.7706317975 2014-04-13 19:05:00,22.550636916 2014-04-13 19:10:00,20.6324848906 2014-04-13 19:15:00,23.7310035938 2014-04-13 19:20:00,24.4297423423 2014-04-13 19:25:00,20.4289615616 2014-04-13 19:30:00,21.913252795300004 2014-04-13 19:35:00,22.3440706551 2014-04-13 19:40:00,20.8161878632 2014-04-13 19:45:00,24.0473347669 2014-04-13 19:50:00,21.4329892334 2014-04-13 19:55:00,23.6678769606 2014-04-13 20:00:00,21.1803931442 2014-04-13 20:05:00,20.881595438199998 2014-04-13 20:10:00,19.2190168776 2014-04-13 20:15:00,19.336001388099998 2014-04-13 20:20:00,18.625938842300002 2014-04-13 20:25:00,19.4179578794 2014-04-13 20:30:00,19.8469367862 2014-04-13 20:35:00,21.8445629025 2014-04-13 20:40:00,19.932744123699997 2014-04-13 20:45:00,21.522930563899997 2014-04-13 20:50:00,20.231955341400003 2014-04-13 20:55:00,21.6468203462 2014-04-13 21:00:00,22.010230762600003 2014-04-13 21:05:00,19.0503711436 2014-04-13 21:10:00,21.552323354099997 2014-04-13 21:15:00,20.5856353173 2014-04-13 21:20:00,21.3712690439 2014-04-13 21:25:00,20.7052540078 2014-04-13 21:30:00,19.7903378112 2014-04-13 21:35:00,19.0030787501 2014-04-13 21:40:00,18.3678855327 2014-04-13 21:45:00,20.2387553609 2014-04-13 21:50:00,22.0667185852 2014-04-13 21:55:00,21.052737571199998 2014-04-13 22:00:00,19.327919163 2014-04-13 22:05:00,21.329275656300002 2014-04-13 22:10:00,21.0961688889 2014-04-13 22:15:00,19.1449046455 2014-04-13 22:20:00,18.0745648911 2014-04-13 22:25:00,18.4903842896 2014-04-13 22:30:00,21.5298736064 2014-04-13 22:35:00,21.3667445328 2014-04-13 22:40:00,19.1992495966 2014-04-13 22:45:00,19.1591568462 2014-04-13 22:50:00,21.1917845396 2014-04-13 22:55:00,21.7718307808 2014-04-13 23:00:00,21.1206034025 2014-04-13 23:05:00,20.426235790499998 2014-04-13 23:10:00,18.9743277711 2014-04-13 23:15:00,20.106851428800002 2014-04-13 23:20:00,18.937682769600002 2014-04-13 23:25:00,21.236122231099998 2014-04-13 23:30:00,19.5515975023 2014-04-13 23:35:00,21.3388851453 2014-04-13 23:40:00,19.530185945899998 2014-04-13 23:45:00,21.3006865654 2014-04-13 23:50:00,19.3369832468 2014-04-13 23:55:00,19.7643248384 2014-04-14 00:00:00,20.4619536774 2014-04-14 00:05:00,18.2811504561 2014-04-14 00:10:00,21.7928282473 2014-04-14 00:15:00,20.2944231445 2014-04-14 00:20:00,20.0312800588 2014-04-14 00:25:00,21.3575758845 2014-04-14 00:30:00,21.4630509196 2014-04-14 00:35:00,20.089041618099998 2014-04-14 00:40:00,21.7090493032 2014-04-14 00:45:00,18.2589510643 2014-04-14 00:50:00,18.452903169000002 2014-04-14 00:55:00,20.3871529201 2014-04-14 01:00:00,19.4162634472 2014-04-14 01:05:00,19.8569006648 2014-04-14 01:10:00,19.3123168716 2014-04-14 01:15:00,19.6189012458 2014-04-14 01:20:00,21.2905853886 2014-04-14 01:25:00,20.3739047994 2014-04-14 01:30:00,21.9893781971 2014-04-14 01:35:00,21.147516791300003 2014-04-14 01:40:00,19.0946650164 2014-04-14 01:45:00,19.0573804709 2014-04-14 01:50:00,19.3435930805 2014-04-14 01:55:00,21.3730379226 2014-04-14 02:00:00,18.1091506026 2014-04-14 02:05:00,18.920725115499998 2014-04-14 02:10:00,21.6196736814 2014-04-14 02:15:00,20.5595857443 2014-04-14 02:20:00,18.907388382 2014-04-14 02:25:00,18.8765798729 2014-04-14 02:30:00,21.450472407 2014-04-14 02:35:00,21.5750300331 2014-04-14 02:40:00,19.0245243638 2014-04-14 02:45:00,19.6820414323 2014-04-14 02:50:00,21.338382954500002 2014-04-14 02:55:00,21.0840297544 2014-04-14 03:00:00,21.2556644263 2014-04-14 03:05:00,20.0735927632 2014-04-14 03:10:00,21.6461961932 2014-04-14 03:15:00,19.3038061758 2014-04-14 03:20:00,18.6266885374 2014-04-14 03:25:00,20.8349293303 2014-04-14 03:30:00,20.157417664 2014-04-14 03:35:00,21.4183430752 2014-04-14 03:40:00,18.3246369965 2014-04-14 03:45:00,21.3747696138 2014-04-14 03:50:00,19.1731786128 2014-04-14 03:55:00,20.6194226687 2014-04-14 04:00:00,18.1605151563 2014-04-14 04:05:00,20.4383251852 2014-04-14 04:10:00,20.8690867567 2014-04-14 04:15:00,19.475000857999998 2014-04-14 04:20:00,18.861642821 2014-04-14 04:25:00,20.1505227064 2014-04-14 04:30:00,21.3327632177 2014-04-14 04:35:00,19.2941894332 2014-04-14 04:40:00,19.0098771901 2014-04-14 04:45:00,19.1157412346 2014-04-14 04:50:00,21.7965286117 2014-04-14 04:55:00,19.4371076631 2014-04-14 05:00:00,18.014416959600002 2014-04-14 05:05:00,21.1267248318 2014-04-14 05:10:00,20.797099181300002 2014-04-14 05:15:00,18.5142730584 2014-04-14 05:20:00,21.9396169965 2014-04-14 05:25:00,20.4322491412 2014-04-14 05:30:00,20.0031179638 2014-04-14 05:35:00,19.5288770705 2014-04-14 05:40:00,21.5946910223 2014-04-14 05:45:00,18.9758539257 2014-04-14 05:50:00,19.143075600899998 2014-04-14 05:55:00,18.4896432267 2014-04-14 06:00:00,21.036476382300002 2014-04-14 06:05:00,20.3821971216 2014-04-14 06:10:00,20.436264677 2014-04-14 06:15:00,18.873881724100002 2014-04-14 06:20:00,20.6046735565 2014-04-14 06:25:00,21.061833789 2014-04-14 06:30:00,19.4315541229 2014-04-14 06:35:00,21.2053885758 2014-04-14 06:40:00,19.395162354100002 2014-04-14 06:45:00,21.032553846 2014-04-14 06:50:00,18.1349204298 2014-04-14 06:55:00,20.2046584059 2014-04-14 07:00:00,21.8781062426 2014-04-14 07:05:00,21.9249784027 2014-04-14 07:10:00,19.1270103134 2014-04-14 07:15:00,19.765596364300002 2014-04-14 07:20:00,18.2519116319 2014-04-14 07:25:00,21.4933652304 2014-04-14 07:30:00,20.2742886126 2014-04-14 07:35:00,19.5404027158 2014-04-14 07:40:00,18.451082234 2014-04-14 07:45:00,21.787069141999996 2014-04-14 07:50:00,20.120876191300002 2014-04-14 07:55:00,19.1317117163 2014-04-14 08:00:00,19.4008605205 2014-04-14 08:05:00,19.0827887237 2014-04-14 08:10:00,20.4072392354 2014-04-14 08:15:00,21.7198543031 2014-04-14 08:20:00,21.4267752133 2014-04-14 08:25:00,19.8415235017 2014-04-14 08:30:00,21.3059974492 2014-04-14 08:35:00,19.6924219251 2014-04-14 08:40:00,19.009228563 2014-04-14 08:45:00,21.9336604611 2014-04-14 08:50:00,19.2155502719 2014-04-14 08:55:00,19.2948969239 2014-04-14 09:00:00,74.6598230019 2014-04-14 09:05:00,63.0214139071 2014-04-14 09:10:00,71.54326223689999 2014-04-14 09:15:00,73.9270535154 2014-04-14 09:20:00,68.1604119221 2014-04-14 09:25:00,61.234295959200004 2014-04-14 09:30:00,66.3008016399 2014-04-14 09:35:00,62.7173382964 2014-04-14 09:40:00,66.8601521887 2014-04-14 09:45:00,71.9443639583 2014-04-14 09:50:00,67.16647706479999 2014-04-14 09:55:00,67.07418165029999 2014-04-14 10:00:00,78.4813726818 2014-04-14 10:05:00,78.8678378753 2014-04-14 10:10:00,83.1297187126 2014-04-14 10:15:00,74.6256764168 2014-04-14 10:20:00,82.592338023 2014-04-14 10:25:00,78.6232917797 2014-04-14 10:30:00,74.5042186116 2014-04-14 10:35:00,74.420356203 2014-04-14 10:40:00,75.4448542655 2014-04-14 10:45:00,79.50419912550001 2014-04-14 10:50:00,73.42219807069999 2014-04-14 10:55:00,84.12357687720001 2014-04-14 11:00:00,80.7114097388 2014-04-14 11:05:00,86.1999309173 2014-04-14 11:10:00,72.3060149188 2014-04-14 11:15:00,77.0168912358 2014-04-14 11:20:00,71.9307330356 2014-04-14 11:25:00,75.8978928673 2014-04-14 11:30:00,85.277350935 2014-04-14 11:35:00,72.1502409208 2014-04-14 11:40:00,78.5044834771 2014-04-14 11:45:00,73.4377866888 2014-04-14 11:50:00,78.1974338449 2014-04-14 11:55:00,84.9090955961 2014-04-14 12:00:00,81.87077357060001 2014-04-14 12:05:00,83.6875558035 2014-04-14 12:10:00,77.4925630482 2014-04-14 12:15:00,87.00583068440002 2014-04-14 12:20:00,83.2481756683 2014-04-14 12:25:00,78.6542825712 2014-04-14 12:30:00,78.7288486795 2014-04-14 12:35:00,86.59490811090002 2014-04-14 12:40:00,81.12500812489999 2014-04-14 12:45:00,83.20210487760001 2014-04-14 12:50:00,78.5781565159 2014-04-14 12:55:00,75.48838933520001 2014-04-14 13:00:00,83.5568902042 2014-04-14 13:05:00,181.705566311 2014-04-14 13:10:00,80.0022809301 2014-04-14 13:15:00,81.9646587995 2014-04-14 13:20:00,75.3144895604 2014-04-14 13:25:00,84.6826905799 2014-04-14 13:30:00,87.1496839352 2014-04-14 13:35:00,86.2369484706 2014-04-14 13:40:00,77.1244576117 2014-04-14 13:45:00,78.4772533103 2014-04-14 13:50:00,84.9140525319 2014-04-14 13:55:00,81.5023088434 2014-04-14 14:00:00,80.7627543005 2014-04-14 14:05:00,86.8221038195 2014-04-14 14:10:00,80.57253170850001 2014-04-14 14:15:00,80.2351674005 2014-04-14 14:20:00,72.66880919 2014-04-14 14:25:00,73.10716202520001 2014-04-14 14:30:00,72.11526322729999 2014-04-14 14:35:00,86.607750241 2014-04-14 14:40:00,78.53041691930001 2014-04-14 14:45:00,79.493166163 2014-04-14 14:50:00,85.5220859043 2014-04-14 14:55:00,81.74401706479999 2014-04-14 15:00:00,81.75124072279999 2014-04-14 15:05:00,76.743814122 2014-04-14 15:10:00,85.3417146945 2014-04-14 15:15:00,74.6525629451 2014-04-14 15:20:00,72.849694111 2014-04-14 15:25:00,75.06493309 2014-04-14 15:30:00,76.283063176 2014-04-14 15:35:00,76.5162423627 2014-04-14 15:40:00,82.727423387 2014-04-14 15:45:00,75.4844687394 2014-04-14 15:50:00,82.8257377372 2014-04-14 15:55:00,73.4574095738 2014-04-14 16:00:00,74.3550966155 2014-04-14 16:05:00,80.1409893049 2014-04-14 16:10:00,86.7501662806 2014-04-14 16:15:00,85.7529167751 2014-04-14 16:20:00,87.49988707899998 2014-04-14 16:25:00,82.4075068217 2014-04-14 16:30:00,82.8128788616 2014-04-14 16:35:00,82.00021054220001 2014-04-14 16:40:00,81.9649453927 2014-04-14 16:45:00,74.3537827615 2014-04-14 16:50:00,80.699668355 2014-04-14 16:55:00,78.17693683520001 2014-04-14 17:00:00,79.0805650855 2014-04-14 17:05:00,80.37757830390001 2014-04-14 17:10:00,74.054310312 2014-04-14 17:15:00,77.7517738849 2014-04-14 17:20:00,73.0151649362 2014-04-14 17:25:00,87.6746564197 2014-04-14 17:30:00,73.8964200849 2014-04-14 17:35:00,76.13636658029999 2014-04-14 17:40:00,86.26065370319998 2014-04-14 17:45:00,79.7233301261 2014-04-14 17:50:00,74.170166743 2014-04-14 17:55:00,78.1476585999 2014-04-14 18:00:00,29.541549490799998 2014-04-14 18:05:00,30.0813766057 2014-04-14 18:10:00,29.1329854269 2014-04-14 18:15:00,31.604649896999998 2014-04-14 18:20:00,33.9624646582 2014-04-14 18:25:00,32.550196494 2014-04-14 18:30:00,32.6806036804 2014-04-14 18:35:00,30.0837320165 2014-04-14 18:40:00,31.0009146446 2014-04-14 18:45:00,34.2095428963 2014-04-14 18:50:00,29.3622739421 2014-04-14 18:55:00,34.2907495997 2014-04-14 19:00:00,22.3269300929 2014-04-14 19:05:00,23.9104191807 2014-04-14 19:10:00,21.5846675748 2014-04-14 19:15:00,21.6780152339 2014-04-14 19:20:00,23.527188519499997 2014-04-14 19:25:00,23.676781558000002 2014-04-14 19:30:00,21.188806995 2014-04-14 19:35:00,24.5184621902 2014-04-14 19:40:00,20.5385145403 2014-04-14 19:45:00,20.4668921519 2014-04-14 19:50:00,22.827857632199997 2014-04-14 19:55:00,23.3978773561 2014-04-14 20:00:00,22.3677893169 2014-04-14 20:05:00,20.0906576771 2014-04-14 20:10:00,18.535593388800002 2014-04-14 20:15:00,20.9014631556 2014-04-14 20:20:00,19.6185946649 2014-04-14 20:25:00,20.205351166 2014-04-14 20:30:00,20.4327707541 2014-04-14 20:35:00,18.6962434292 2014-04-14 20:40:00,20.4225811445 2014-04-14 20:45:00,20.1782051131 2014-04-14 20:50:00,21.3505810544 2014-04-14 20:55:00,21.0766473194 2014-04-14 21:00:00,18.8308189683 2014-04-14 21:05:00,18.9149134938 2014-04-14 21:10:00,19.095243987 2014-04-14 21:15:00,18.805637563599998 2014-04-14 21:20:00,20.727871241400003 2014-04-14 21:25:00,22.083213722199996 2014-04-14 21:30:00,20.7073537916 2014-04-14 21:35:00,20.524774420299998 2014-04-14 21:40:00,19.7339823015 2014-04-14 21:45:00,19.3427225291 2014-04-14 21:50:00,21.7481875906 2014-04-14 21:55:00,21.9810122788 2014-04-14 22:00:00,20.006292313 2014-04-14 22:05:00,19.1791963425 2014-04-14 22:10:00,21.100726089600002 2014-04-14 22:15:00,18.547615788399998 2014-04-14 22:20:00,21.0825727991 2014-04-14 22:25:00,21.2962182485 2014-04-14 22:30:00,18.5173754006 2014-04-14 22:35:00,21.9284770125 2014-04-14 22:40:00,21.963113518000004 2014-04-14 22:45:00,21.7677549094 2014-04-14 22:50:00,20.0033240015 2014-04-14 22:55:00,19.0025214845 2014-04-14 23:00:00,20.3319401047 2014-04-14 23:05:00,19.6835138611 2014-04-14 23:10:00,18.8274087456 2014-04-14 23:15:00,19.69848702 2014-04-14 23:20:00,20.6595252081 2014-04-14 23:25:00,18.2871637028 2014-04-14 23:30:00,19.3373840689 2014-04-14 23:35:00,18.0746492248 2014-04-14 23:40:00,21.0020136323 2014-04-14 23:45:00,20.5667131193 2014-04-14 23:50:00,18.254192669200002 2014-04-14 23:55:00,21.8631471547 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/art_daily_jumpsup_noised_trended.csv ================================================ timestamp,value 2014-04-01 00:00:00,19.761251902999998 2014-04-01 00:05:00,20.500833287 2014-04-01 00:10:00,19.9616414445 2014-04-01 00:15:00,21.4902660734 2014-04-01 00:20:00,20.1877394098 2014-04-01 00:25:00,19.9231256718 2014-04-01 00:30:00,21.698403961700002 2014-04-01 00:35:00,20.8787583842 2014-04-01 00:40:00,18.4461996294 2014-04-01 00:45:00,18.7108178448 2014-04-01 00:50:00,21.148491451800002 2014-04-01 00:55:00,21.3434052847 2014-04-01 01:00:00,20.1807633164 2014-04-01 01:05:00,20.217820911500002 2014-04-01 01:10:00,20.527731851400002 2014-04-01 01:15:00,19.7564630971 2014-04-01 01:20:00,20.7207964939 2014-04-01 01:25:00,18.4339250303 2014-04-01 01:30:00,21.845116969499998 2014-04-01 01:35:00,21.0006192952 2014-04-01 01:40:00,20.524696816 2014-04-01 01:45:00,19.265288228 2014-04-01 01:50:00,18.6438219498 2014-04-01 01:55:00,19.6373718553 2014-04-01 02:00:00,20.6463069623 2014-04-01 02:05:00,20.534838973699998 2014-04-01 02:10:00,19.530564620299998 2014-04-01 02:15:00,20.4531455753 2014-04-01 02:20:00,21.2549931823 2014-04-01 02:25:00,18.1051390894 2014-04-01 02:30:00,19.8024841917 2014-04-01 02:35:00,21.0342209139 2014-04-01 02:40:00,20.1845778819 2014-04-01 02:45:00,20.6059043517 2014-04-01 02:50:00,20.0667055704 2014-04-01 02:55:00,21.967498178699998 2014-04-01 03:00:00,18.218486146 2014-04-01 03:05:00,19.964179287100002 2014-04-01 03:10:00,18.3656661965 2014-04-01 03:15:00,18.6391422485 2014-04-01 03:20:00,19.5321534017 2014-04-01 03:25:00,18.622160366 2014-04-01 03:30:00,21.854748663800002 2014-04-01 03:35:00,21.7871591069 2014-04-01 03:40:00,19.3444385849 2014-04-01 03:45:00,20.5589908482 2014-04-01 03:50:00,20.1350132824 2014-04-01 03:55:00,21.262347922100002 2014-04-01 04:00:00,20.5097824393 2014-04-01 04:05:00,18.001009818 2014-04-01 04:10:00,21.0526975424 2014-04-01 04:15:00,20.9873924852 2014-04-01 04:20:00,20.0388908223 2014-04-01 04:25:00,21.6116758929 2014-04-01 04:30:00,21.633784822800003 2014-04-01 04:35:00,20.0956467068 2014-04-01 04:40:00,20.4319529248 2014-04-01 04:45:00,21.9860882877 2014-04-01 04:50:00,19.1952809392 2014-04-01 04:55:00,19.2984689692 2014-04-01 05:00:00,18.7310956107 2014-04-01 05:05:00,21.583467756599998 2014-04-01 05:10:00,20.9779535598 2014-04-01 05:15:00,18.4225713955 2014-04-01 05:20:00,21.9270694048 2014-04-01 05:25:00,20.9238468326 2014-04-01 05:30:00,21.4020884384 2014-04-01 05:35:00,18.192603156700002 2014-04-01 05:40:00,20.0198436758 2014-04-01 05:45:00,20.7943931469 2014-04-01 05:50:00,20.1717863383 2014-04-01 05:55:00,20.6665898628 2014-04-01 06:00:00,21.2714962544 2014-04-01 06:05:00,19.497348251800002 2014-04-01 06:10:00,21.3946747025 2014-04-01 06:15:00,18.6516644191 2014-04-01 06:20:00,19.0835442201 2014-04-01 06:25:00,18.1733824797 2014-04-01 06:30:00,19.4577072453 2014-04-01 06:35:00,19.5196381793 2014-04-01 06:40:00,21.221082388800003 2014-04-01 06:45:00,20.612522681199998 2014-04-01 06:50:00,19.7468902326 2014-04-01 06:55:00,20.608455914500002 2014-04-01 07:00:00,18.2111334021 2014-04-01 07:05:00,18.7210861441 2014-04-01 07:10:00,20.507791421 2014-04-01 07:15:00,20.5654672769 2014-04-01 07:20:00,21.0965386348 2014-04-01 07:25:00,19.6119990362 2014-04-01 07:30:00,20.8902163865 2014-04-01 07:35:00,20.7359213302 2014-04-01 07:40:00,21.8535735135 2014-04-01 07:45:00,18.8605209057 2014-04-01 07:50:00,20.206718255 2014-04-01 07:55:00,20.407057768399998 2014-04-01 08:00:00,21.994591539699996 2014-04-01 08:05:00,18.804736568699997 2014-04-01 08:10:00,20.0928720799 2014-04-01 08:15:00,19.384741230899998 2014-04-01 08:20:00,20.103571874300002 2014-04-01 08:25:00,18.928514408399998 2014-04-01 08:30:00,18.1904495137 2014-04-01 08:35:00,20.2902618156 2014-04-01 08:40:00,19.3434172634 2014-04-01 08:45:00,18.727765607000002 2014-04-01 08:50:00,19.2957422643 2014-04-01 08:55:00,18.1971208058 2014-04-01 09:00:00,74.1260143836 2014-04-01 09:05:00,69.10361164359999 2014-04-01 09:10:00,72.2808540663 2014-04-01 09:15:00,66.9544074866 2014-04-01 09:20:00,73.4850794789 2014-04-01 09:25:00,67.7731278131 2014-04-01 09:30:00,69.0056563819 2014-04-01 09:35:00,67.88839812890001 2014-04-01 09:40:00,71.1725848238 2014-04-01 09:45:00,68.9065226554 2014-04-01 09:50:00,64.8937453607 2014-04-01 09:55:00,63.179337626000006 2014-04-01 10:00:00,79.2470505155 2014-04-01 10:05:00,77.4320730032 2014-04-01 10:10:00,71.3295428127 2014-04-01 10:15:00,75.9799830691 2014-04-01 10:20:00,77.8293300694 2014-04-01 10:25:00,82.67338298899999 2014-04-01 10:30:00,71.0210883865 2014-04-01 10:35:00,75.2486478048 2014-04-01 10:40:00,82.6076230245 2014-04-01 10:45:00,79.90353942109999 2014-04-01 10:50:00,74.3401531544 2014-04-01 10:55:00,82.9596010938 2014-04-01 11:00:00,79.41334110529999 2014-04-01 11:05:00,79.4937884794 2014-04-01 11:10:00,87.0996450426 2014-04-01 11:15:00,86.6309408675 2014-04-01 11:20:00,77.2701037963 2014-04-01 11:25:00,73.8037704623 2014-04-01 11:30:00,76.7474037102 2014-04-01 11:35:00,72.052805772 2014-04-01 11:40:00,71.8982924702 2014-04-01 11:45:00,77.8583840549 2014-04-01 11:50:00,86.5339792602 2014-04-01 11:55:00,85.426067155 2014-04-01 12:00:00,80.08686564029999 2014-04-01 12:05:00,80.9463697522 2014-04-01 12:10:00,72.0084220248 2014-04-01 12:15:00,75.3574808711 2014-04-01 12:20:00,72.3095103677 2014-04-01 12:25:00,83.9717453641 2014-04-01 12:30:00,74.2411363371 2014-04-01 12:35:00,85.8016679353 2014-04-01 12:40:00,82.194437192 2014-04-01 12:45:00,75.5798939857 2014-04-01 12:50:00,74.4340968432 2014-04-01 12:55:00,81.94354482050001 2014-04-01 13:00:00,86.3926524705 2014-04-01 13:05:00,83.47372499939999 2014-04-01 13:10:00,77.5581280065 2014-04-01 13:15:00,81.3786019713 2014-04-01 13:20:00,76.953713801 2014-04-01 13:25:00,87.9652763341 2014-04-01 13:30:00,83.9612714729 2014-04-01 13:35:00,81.81046701060001 2014-04-01 13:40:00,78.7532409691 2014-04-01 13:45:00,81.8707829394 2014-04-01 13:50:00,77.4472651938 2014-04-01 13:55:00,72.4444465903 2014-04-01 14:00:00,78.31765692970001 2014-04-01 14:05:00,86.883522504 2014-04-01 14:10:00,82.0168805171 2014-04-01 14:15:00,73.3397707712 2014-04-01 14:20:00,86.15576213920002 2014-04-01 14:25:00,76.2983350936 2014-04-01 14:30:00,75.89666867439999 2014-04-01 14:35:00,76.7497713346 2014-04-01 14:40:00,81.2313364867 2014-04-01 14:45:00,80.7111351745 2014-04-01 14:50:00,79.8587866682 2014-04-01 14:55:00,83.4765827479 2014-04-01 15:00:00,77.06386388119998 2014-04-01 15:05:00,84.51222102 2014-04-01 15:10:00,74.8044287246 2014-04-01 15:15:00,84.5211212147 2014-04-01 15:20:00,82.6201685228 2014-04-01 15:25:00,82.930536812 2014-04-01 15:30:00,79.7040891874 2014-04-01 15:35:00,82.6712308715 2014-04-01 15:40:00,73.2760492881 2014-04-01 15:45:00,85.6239958745 2014-04-01 15:50:00,72.8880560037 2014-04-01 15:55:00,74.3791501112 2014-04-01 16:00:00,81.228479377 2014-04-01 16:05:00,83.83042233260001 2014-04-01 16:10:00,73.2198844471 2014-04-01 16:15:00,86.73207050010002 2014-04-01 16:20:00,87.5775542316 2014-04-01 16:25:00,81.69504591329998 2014-04-01 16:30:00,79.6997422622 2014-04-01 16:35:00,83.8621585408 2014-04-01 16:40:00,77.2535693101 2014-04-01 16:45:00,79.8920775526 2014-04-01 16:50:00,86.6582500449 2014-04-01 16:55:00,87.29031920610001 2014-04-01 17:00:00,86.8330725129 2014-04-01 17:05:00,76.19913981090001 2014-04-01 17:10:00,75.7194755672 2014-04-01 17:15:00,76.762602618 2014-04-01 17:20:00,79.0609474388 2014-04-01 17:25:00,77.02664902640001 2014-04-01 17:30:00,77.98737478470001 2014-04-01 17:35:00,81.93015977270001 2014-04-01 17:40:00,84.20037850050001 2014-04-01 17:45:00,83.768899005 2014-04-01 17:50:00,85.0307444214 2014-04-01 17:55:00,72.5149226057 2014-04-01 18:00:00,29.105490665700003 2014-04-01 18:05:00,33.8520444488 2014-04-01 18:10:00,32.211698278200004 2014-04-01 18:15:00,32.5000940721 2014-04-01 18:20:00,29.1365503112 2014-04-01 18:25:00,30.4340024842 2014-04-01 18:30:00,32.8854612373 2014-04-01 18:35:00,34.2987575113 2014-04-01 18:40:00,34.6686870856 2014-04-01 18:45:00,32.0026786288 2014-04-01 18:50:00,32.2910288896 2014-04-01 18:55:00,34.131511085599996 2014-04-01 19:00:00,22.568556973299998 2014-04-01 19:05:00,22.4755249615 2014-04-01 19:10:00,24.2147751608 2014-04-01 19:15:00,23.698897290300003 2014-04-01 19:20:00,24.232643588800002 2014-04-01 19:25:00,21.1377456459 2014-04-01 19:30:00,22.5092009454 2014-04-01 19:35:00,23.9342738231 2014-04-01 19:40:00,20.6579411338 2014-04-01 19:45:00,23.72008515 2014-04-01 19:50:00,20.9797196068 2014-04-01 19:55:00,23.7803707178 2014-04-01 20:00:00,20.938755589 2014-04-01 20:05:00,19.2234943904 2014-04-01 20:10:00,20.3708584741 2014-04-01 20:15:00,21.2250833071 2014-04-01 20:20:00,21.0282612297 2014-04-01 20:25:00,20.1820042736 2014-04-01 20:30:00,22.1158050371 2014-04-01 20:35:00,20.558902699 2014-04-01 20:40:00,20.5040322087 2014-04-01 20:45:00,18.6869781922 2014-04-01 20:50:00,22.2090048501 2014-04-01 20:55:00,19.1574692354 2014-04-01 21:00:00,20.2099229424 2014-04-01 21:05:00,21.3160988514 2014-04-01 21:10:00,18.9523497644 2014-04-01 21:15:00,20.2060186776 2014-04-01 21:20:00,19.0537607405 2014-04-01 21:25:00,21.1397660835 2014-04-01 21:30:00,20.3545999721 2014-04-01 21:35:00,21.526738125399998 2014-04-01 21:40:00,21.6818074721 2014-04-01 21:45:00,20.693789562 2014-04-01 21:50:00,21.0018924452 2014-04-01 21:55:00,20.2938253758 2014-04-01 22:00:00,19.556471129000002 2014-04-01 22:05:00,20.6122404548 2014-04-01 22:10:00,21.6539223116 2014-04-01 22:15:00,19.6856015647 2014-04-01 22:20:00,19.2761274305 2014-04-01 22:25:00,19.5725193424 2014-04-01 22:30:00,19.760542437999998 2014-04-01 22:35:00,18.3118065813 2014-04-01 22:40:00,20.0129613686 2014-04-01 22:45:00,19.9964351491 2014-04-01 22:50:00,20.3733149249 2014-04-01 22:55:00,19.4699533412 2014-04-01 23:00:00,20.4563572484 2014-04-01 23:05:00,21.516995709099998 2014-04-01 23:10:00,21.8260737616 2014-04-01 23:15:00,20.338353076700002 2014-04-01 23:20:00,18.173852523900003 2014-04-01 23:25:00,21.8811443602 2014-04-01 23:30:00,20.8274463436 2014-04-01 23:35:00,19.3475686124 2014-04-01 23:40:00,18.5921998191 2014-04-01 23:45:00,18.5772405926 2014-04-01 23:50:00,18.6745624504 2014-04-01 23:55:00,18.185781084400002 2014-04-02 00:00:00,21.6086167546 2014-04-02 00:05:00,20.1630729313 2014-04-02 00:10:00,20.7998376509 2014-04-02 00:15:00,21.3124340371 2014-04-02 00:20:00,21.1661640253 2014-04-02 00:25:00,21.530422494899998 2014-04-02 00:30:00,21.869018490100004 2014-04-02 00:35:00,19.756282459 2014-04-02 00:40:00,21.8013418667 2014-04-02 00:45:00,20.8931597934 2014-04-02 00:50:00,18.2826727612 2014-04-02 00:55:00,20.7271324848 2014-04-02 01:00:00,20.7468666384 2014-04-02 01:05:00,21.6234422552 2014-04-02 01:10:00,19.4917285299 2014-04-02 01:15:00,20.3396460011 2014-04-02 01:20:00,18.048750204 2014-04-02 01:25:00,19.3283009687 2014-04-02 01:30:00,18.2489749046 2014-04-02 01:35:00,20.087491891099997 2014-04-02 01:40:00,21.269790602 2014-04-02 01:45:00,18.8257707685 2014-04-02 01:50:00,20.1097641822 2014-04-02 01:55:00,18.816034545999997 2014-04-02 02:00:00,18.4827538714 2014-04-02 02:05:00,20.0439871677 2014-04-02 02:10:00,18.3165944838 2014-04-02 02:15:00,20.3494185246 2014-04-02 02:20:00,18.1253498427 2014-04-02 02:25:00,18.4268598875 2014-04-02 02:30:00,20.1999899419 2014-04-02 02:35:00,20.365629651600003 2014-04-02 02:40:00,18.1159477204 2014-04-02 02:45:00,20.293507152 2014-04-02 02:50:00,21.354010101300002 2014-04-02 02:55:00,20.8892647092 2014-04-02 03:00:00,18.5247404157 2014-04-02 03:05:00,20.3698985903 2014-04-02 03:10:00,20.6890100003 2014-04-02 03:15:00,18.148924807 2014-04-02 03:20:00,21.4213906747 2014-04-02 03:25:00,21.625069589200002 2014-04-02 03:30:00,21.4018090934 2014-04-02 03:35:00,21.298525872 2014-04-02 03:40:00,20.9798607938 2014-04-02 03:45:00,20.5337281251 2014-04-02 03:50:00,20.71450802 2014-04-02 03:55:00,21.2255811733 2014-04-02 04:00:00,20.6499938334 2014-04-02 04:05:00,19.3109078267 2014-04-02 04:10:00,19.5038444086 2014-04-02 04:15:00,21.588229873499998 2014-04-02 04:20:00,18.0684883432 2014-04-02 04:25:00,20.795282325 2014-04-02 04:30:00,21.819110209699996 2014-04-02 04:35:00,20.8249126798 2014-04-02 04:40:00,21.9756479529 2014-04-02 04:45:00,20.7501796221 2014-04-02 04:50:00,18.1374521169 2014-04-02 04:55:00,21.308039526600002 2014-04-02 05:00:00,19.1385196478 2014-04-02 05:05:00,19.7842289027 2014-04-02 05:10:00,19.2483676636 2014-04-02 05:15:00,19.0742164248 2014-04-02 05:20:00,19.7256228147 2014-04-02 05:25:00,19.5150057938 2014-04-02 05:30:00,20.5333543274 2014-04-02 05:35:00,21.252604804 2014-04-02 05:40:00,19.1883546127 2014-04-02 05:45:00,18.8548846113 2014-04-02 05:50:00,20.6675810835 2014-04-02 05:55:00,20.6812802633 2014-04-02 06:00:00,21.6045249571 2014-04-02 06:05:00,18.063782745799998 2014-04-02 06:10:00,21.4121626485 2014-04-02 06:15:00,20.0840086918 2014-04-02 06:20:00,20.4852083567 2014-04-02 06:25:00,18.3654857622 2014-04-02 06:30:00,19.7304597315 2014-04-02 06:35:00,18.909209629 2014-04-02 06:40:00,19.0169001203 2014-04-02 06:45:00,20.0163804587 2014-04-02 06:50:00,21.2498238016 2014-04-02 06:55:00,20.9751237206 2014-04-02 07:00:00,20.3639998363 2014-04-02 07:05:00,20.157672770999998 2014-04-02 07:10:00,19.7092241729 2014-04-02 07:15:00,21.8908398942 2014-04-02 07:20:00,20.2407702169 2014-04-02 07:25:00,19.0158655932 2014-04-02 07:30:00,18.920363168199998 2014-04-02 07:35:00,20.4454121231 2014-04-02 07:40:00,20.091310109200002 2014-04-02 07:45:00,18.0307912118 2014-04-02 07:50:00,21.3202614888 2014-04-02 07:55:00,20.8164894169 2014-04-02 08:00:00,20.647317158699998 2014-04-02 08:05:00,18.2751226308 2014-04-02 08:10:00,19.448223400699998 2014-04-02 08:15:00,21.741529042899998 2014-04-02 08:20:00,21.4503569654 2014-04-02 08:25:00,19.1421717515 2014-04-02 08:30:00,18.628235536400002 2014-04-02 08:35:00,19.796351828699997 2014-04-02 08:40:00,19.4233215147 2014-04-02 08:45:00,20.7289055068 2014-04-02 08:50:00,21.8657392403 2014-04-02 08:55:00,19.4520057999 2014-04-02 09:00:00,62.046248748100005 2014-04-02 09:05:00,73.4075505135 2014-04-02 09:10:00,61.7161163313 2014-04-02 09:15:00,74.1576162013 2014-04-02 09:20:00,70.2382802209 2014-04-02 09:25:00,74.0069732348 2014-04-02 09:30:00,63.91537173840001 2014-04-02 09:35:00,61.753517215500004 2014-04-02 09:40:00,67.8396557046 2014-04-02 09:45:00,67.3284784382 2014-04-02 09:50:00,65.7082949163 2014-04-02 09:55:00,74.2241280517 2014-04-02 10:00:00,82.6064995231 2014-04-02 10:05:00,80.1077529717 2014-04-02 10:10:00,72.3675606862 2014-04-02 10:15:00,81.2366992956 2014-04-02 10:20:00,81.1232332969 2014-04-02 10:25:00,76.4370580545 2014-04-02 10:30:00,84.1926773188 2014-04-02 10:35:00,72.4314967322 2014-04-02 10:40:00,73.9890789686 2014-04-02 10:45:00,70.8212417452 2014-04-02 10:50:00,82.1853988709 2014-04-02 10:55:00,79.4897056722 2014-04-02 11:00:00,76.5768106216 2014-04-02 11:05:00,74.1732925058 2014-04-02 11:10:00,72.2065101345 2014-04-02 11:15:00,74.2199215234 2014-04-02 11:20:00,78.77703901539998 2014-04-02 11:25:00,75.4991025151 2014-04-02 11:30:00,75.6868525499 2014-04-02 11:35:00,85.4931665355 2014-04-02 11:40:00,79.7607495587 2014-04-02 11:45:00,83.16602338060001 2014-04-02 11:50:00,72.1359469333 2014-04-02 11:55:00,77.3755580087 2014-04-02 12:00:00,79.5711095069 2014-04-02 12:05:00,74.89269047970001 2014-04-02 12:10:00,73.83435698550001 2014-04-02 12:15:00,85.82175062350001 2014-04-02 12:20:00,86.92646894639999 2014-04-02 12:25:00,73.1729940801 2014-04-02 12:30:00,77.4911982414 2014-04-02 12:35:00,87.22777096629999 2014-04-02 12:40:00,73.24259102479999 2014-04-02 12:45:00,82.1995040517 2014-04-02 12:50:00,87.4504752851 2014-04-02 12:55:00,87.5463968029 2014-04-02 13:00:00,79.5204837969 2014-04-02 13:05:00,74.5860807679 2014-04-02 13:10:00,75.2152930359 2014-04-02 13:15:00,86.2129262526 2014-04-02 13:20:00,86.56614720649998 2014-04-02 13:25:00,81.7064600441 2014-04-02 13:30:00,84.2386002741 2014-04-02 13:35:00,83.8187786875 2014-04-02 13:40:00,82.5693241729 2014-04-02 13:45:00,85.21597453439999 2014-04-02 13:50:00,82.9465940072 2014-04-02 13:55:00,80.5247063231 2014-04-02 14:00:00,75.7876638189 2014-04-02 14:05:00,83.8981829998 2014-04-02 14:10:00,79.5711862851 2014-04-02 14:15:00,76.7129845441 2014-04-02 14:20:00,84.8270685171 2014-04-02 14:25:00,83.1434265296 2014-04-02 14:30:00,86.9932571332 2014-04-02 14:35:00,74.6434831811 2014-04-02 14:40:00,82.3830739768 2014-04-02 14:45:00,75.90418791350001 2014-04-02 14:50:00,86.4531778131 2014-04-02 14:55:00,73.5884582126 2014-04-02 15:00:00,82.4977969167 2014-04-02 15:05:00,84.6565588337 2014-04-02 15:10:00,77.6779397305 2014-04-02 15:15:00,87.2653715145 2014-04-02 15:20:00,85.61086908109999 2014-04-02 15:25:00,76.7131563416 2014-04-02 15:30:00,72.11996512510001 2014-04-02 15:35:00,76.74577805130002 2014-04-02 15:40:00,76.5002331182 2014-04-02 15:45:00,86.2386058215 2014-04-02 15:50:00,87.4730991023 2014-04-02 15:55:00,73.1263377559 2014-04-02 16:00:00,79.5405645384 2014-04-02 16:05:00,80.7731568917 2014-04-02 16:10:00,73.486445487 2014-04-02 16:15:00,78.0398135095 2014-04-02 16:20:00,77.0731706975 2014-04-02 16:25:00,80.5767469616 2014-04-02 16:30:00,82.5788958439 2014-04-02 16:35:00,83.25560191689999 2014-04-02 16:40:00,74.1879379367 2014-04-02 16:45:00,85.0070000174 2014-04-02 16:50:00,82.85651339180001 2014-04-02 16:55:00,86.2250331156 2014-04-02 17:00:00,79.1893465422 2014-04-02 17:05:00,86.3022030635 2014-04-02 17:10:00,85.8523529904 2014-04-02 17:15:00,79.0145189762 2014-04-02 17:20:00,178.0982630549 2014-04-02 17:25:00,86.92495886030001 2014-04-02 17:30:00,83.44260371060001 2014-04-02 17:35:00,86.8518921919 2014-04-02 17:40:00,84.75156391770001 2014-04-02 17:45:00,81.7487276371 2014-04-02 17:50:00,73.8536160723 2014-04-02 17:55:00,76.6636613224 2014-04-02 18:00:00,35.000584685300005 2014-04-02 18:05:00,30.844295509699997 2014-04-02 18:10:00,29.396825522399997 2014-04-02 18:15:00,33.3283350788 2014-04-02 18:20:00,33.4976207975 2014-04-02 18:25:00,30.626923529499997 2014-04-02 18:30:00,30.7050947724 2014-04-02 18:35:00,31.80090900150001 2014-04-02 18:40:00,28.939443722100002 2014-04-02 18:45:00,33.851660766799995 2014-04-02 18:50:00,30.8293623193 2014-04-02 18:55:00,34.264077274099996 2014-04-02 19:00:00,23.7557829856 2014-04-02 19:05:00,23.123079839899997 2014-04-02 19:10:00,21.6154382188 2014-04-02 19:15:00,22.473096963400003 2014-04-02 19:20:00,22.1528338588 2014-04-02 19:25:00,21.678189661199998 2014-04-02 19:30:00,23.9596492617 2014-04-02 19:35:00,22.3261104694 2014-04-02 19:40:00,23.890598167600004 2014-04-02 19:45:00,20.6313776324 2014-04-02 19:50:00,20.7917899124 2014-04-02 19:55:00,24.5383936208 2014-04-02 20:00:00,20.8394993728 2014-04-02 20:05:00,20.5200163364 2014-04-02 20:10:00,20.5748469877 2014-04-02 20:15:00,19.3137406667 2014-04-02 20:20:00,21.3758111207 2014-04-02 20:25:00,18.7792612094 2014-04-02 20:30:00,20.7803336795 2014-04-02 20:35:00,20.7698687416 2014-04-02 20:40:00,22.176515519099997 2014-04-02 20:45:00,20.5872445431 2014-04-02 20:50:00,18.9934085748 2014-04-02 20:55:00,20.7779971005 2014-04-02 21:00:00,18.4534640231 2014-04-02 21:05:00,18.905488136600002 2014-04-02 21:10:00,18.211431577 2014-04-02 21:15:00,20.1494295173 2014-04-02 21:20:00,18.4261534423 2014-04-02 21:25:00,19.972989837300002 2014-04-02 21:30:00,21.836092632600003 2014-04-02 21:35:00,20.9792650199 2014-04-02 21:40:00,18.397532956 2014-04-02 21:45:00,18.9875440308 2014-04-02 21:50:00,20.7939839472 2014-04-02 21:55:00,21.6823856668 2014-04-02 22:00:00,18.1490807455 2014-04-02 22:05:00,21.270204328800002 2014-04-02 22:10:00,20.266692876700002 2014-04-02 22:15:00,20.203742282 2014-04-02 22:20:00,21.8522107229 2014-04-02 22:25:00,21.0107293954 2014-04-02 22:30:00,21.4210199182 2014-04-02 22:35:00,19.4346216116 2014-04-02 22:40:00,20.2368649113 2014-04-02 22:45:00,20.4812658575 2014-04-02 22:50:00,19.3048506343 2014-04-02 22:55:00,20.3004622426 2014-04-02 23:00:00,18.9502592674 2014-04-02 23:05:00,18.577068795 2014-04-02 23:10:00,19.4996242444 2014-04-02 23:15:00,20.9611822874 2014-04-02 23:20:00,21.6689082219 2014-04-02 23:25:00,19.8346637284 2014-04-02 23:30:00,20.5752444397 2014-04-02 23:35:00,18.4156836546 2014-04-02 23:40:00,21.6220056603 2014-04-02 23:45:00,20.2783095403 2014-04-02 23:50:00,21.1254082882 2014-04-02 23:55:00,21.1818309324 2014-04-03 00:00:00,19.0259221055 2014-04-03 00:05:00,20.1166978127 2014-04-03 00:10:00,21.841919006199998 2014-04-03 00:15:00,18.3585381793 2014-04-03 00:20:00,20.7321995921 2014-04-03 00:25:00,21.8490563121 2014-04-03 00:30:00,19.2023084322 2014-04-03 00:35:00,21.4457916856 2014-04-03 00:40:00,21.7346301816 2014-04-03 00:45:00,20.9883448376 2014-04-03 00:50:00,18.925313249200002 2014-04-03 00:55:00,19.3360028753 2014-04-03 01:00:00,18.1432371777 2014-04-03 01:05:00,21.325812937000002 2014-04-03 01:10:00,21.398444746 2014-04-03 01:15:00,20.5308412399 2014-04-03 01:20:00,19.4101114051 2014-04-03 01:25:00,18.3072441106 2014-04-03 01:30:00,21.0122304397 2014-04-03 01:35:00,20.9061047744 2014-04-03 01:40:00,21.650410086999997 2014-04-03 01:45:00,20.922128084 2014-04-03 01:50:00,21.314779769 2014-04-03 01:55:00,20.9838184716 2014-04-03 02:00:00,20.5227487532 2014-04-03 02:05:00,19.7078655768 2014-04-03 02:10:00,21.6084692346 2014-04-03 02:15:00,20.6038742876 2014-04-03 02:20:00,19.5934212879 2014-04-03 02:25:00,18.3338771807 2014-04-03 02:30:00,19.1628194236 2014-04-03 02:35:00,20.1749069393 2014-04-03 02:40:00,19.1025414801 2014-04-03 02:45:00,18.8849413917 2014-04-03 02:50:00,20.1095740564 2014-04-03 02:55:00,18.6792813836 2014-04-03 03:00:00,21.2016402533 2014-04-03 03:05:00,19.9374726054 2014-04-03 03:10:00,20.2954510959 2014-04-03 03:15:00,18.589533070399998 2014-04-03 03:20:00,19.2983053425 2014-04-03 03:25:00,19.640358733 2014-04-03 03:30:00,21.2328513221 2014-04-03 03:35:00,21.0806380923 2014-04-03 03:40:00,18.8919098992 2014-04-03 03:45:00,20.4647163264 2014-04-03 03:50:00,18.9738254311 2014-04-03 03:55:00,21.952988622800003 2014-04-03 04:00:00,21.8084955125 2014-04-03 04:05:00,20.2530588821 2014-04-03 04:10:00,20.7956102876 2014-04-03 04:15:00,21.2057215288 2014-04-03 04:20:00,20.8839936802 2014-04-03 04:25:00,20.7993147643 2014-04-03 04:30:00,21.834216031799997 2014-04-03 04:35:00,20.3858244252 2014-04-03 04:40:00,20.5452106873 2014-04-03 04:45:00,21.3970750018 2014-04-03 04:50:00,20.6795634714 2014-04-03 04:55:00,20.931730488099998 2014-04-03 05:00:00,18.9366747448 2014-04-03 05:05:00,19.4850676965 2014-04-03 05:10:00,18.5892053828 2014-04-03 05:15:00,20.0230617693 2014-04-03 05:20:00,19.8229096027 2014-04-03 05:25:00,21.9886512571 2014-04-03 05:30:00,20.444834611300003 2014-04-03 05:35:00,21.1457792928 2014-04-03 05:40:00,19.336058683 2014-04-03 05:45:00,21.3261813254 2014-04-03 05:50:00,20.460339865999998 2014-04-03 05:55:00,20.787969326400003 2014-04-03 06:00:00,19.177723111800002 2014-04-03 06:05:00,20.1945535668 2014-04-03 06:10:00,20.536147893699997 2014-04-03 06:15:00,20.3563787033 2014-04-03 06:20:00,21.6607748457 2014-04-03 06:25:00,21.593090658 2014-04-03 06:30:00,21.8839362315 2014-04-03 06:35:00,20.669712024000003 2014-04-03 06:40:00,21.887656520500002 2014-04-03 06:45:00,21.3299120001 2014-04-03 06:50:00,19.083328561400002 2014-04-03 06:55:00,19.709742678199998 2014-04-03 07:00:00,18.9535697688 2014-04-03 07:05:00,18.0167886433 2014-04-03 07:10:00,18.7521950126 2014-04-03 07:15:00,18.0162423451 2014-04-03 07:20:00,20.8793538454 2014-04-03 07:25:00,19.7021371909 2014-04-03 07:30:00,19.2502989083 2014-04-03 07:35:00,21.0468835644 2014-04-03 07:40:00,21.3299470985 2014-04-03 07:45:00,21.9011981546 2014-04-03 07:50:00,20.568054338699998 2014-04-03 07:55:00,19.8461158342 2014-04-03 08:00:00,19.2210572064 2014-04-03 08:05:00,18.889272836900002 2014-04-03 08:10:00,18.8517038019 2014-04-03 08:15:00,19.6367574989 2014-04-03 08:20:00,21.967145421199998 2014-04-03 08:25:00,18.0034147897 2014-04-03 08:30:00,18.7888235889 2014-04-03 08:35:00,18.7535719296 2014-04-03 08:40:00,20.8684779421 2014-04-03 08:45:00,19.4099389104 2014-04-03 08:50:00,19.8290432184 2014-04-03 08:55:00,18.594496521900002 2014-04-03 09:00:00,66.7079597287 2014-04-03 09:05:00,62.603517441899996 2014-04-03 09:10:00,68.4493887153 2014-04-03 09:15:00,62.5319617692 2014-04-03 09:20:00,71.950913984 2014-04-03 09:25:00,68.90578335859999 2014-04-03 09:30:00,71.0459630833 2014-04-03 09:35:00,66.8918228585 2014-04-03 09:40:00,66.3882815881 2014-04-03 09:45:00,62.535640891099995 2014-04-03 09:50:00,68.3244362558 2014-04-03 09:55:00,68.1972294421 2014-04-03 10:00:00,77.1049437299 2014-04-03 10:05:00,81.33284501989999 2014-04-03 10:10:00,82.76046828850001 2014-04-03 10:15:00,81.4922557552 2014-04-03 10:20:00,72.0727963284 2014-04-03 10:25:00,79.4943635841 2014-04-03 10:30:00,71.0866146003 2014-04-03 10:35:00,80.6205379011 2014-04-03 10:40:00,75.7661427786 2014-04-03 10:45:00,71.8963838013 2014-04-03 10:50:00,83.2190293003 2014-04-03 10:55:00,79.3694094219 2014-04-03 11:00:00,77.2095458902 2014-04-03 11:05:00,72.0566850652 2014-04-03 11:10:00,80.1133823592 2014-04-03 11:15:00,86.2509843714 2014-04-03 11:20:00,81.0528248593 2014-04-03 11:25:00,87.0211312159 2014-04-03 11:30:00,73.738118585 2014-04-03 11:35:00,80.60632438350001 2014-04-03 11:40:00,84.2613807635 2014-04-03 11:45:00,79.9261997878 2014-04-03 11:50:00,73.01631932560001 2014-04-03 11:55:00,80.8382189686 2014-04-03 12:00:00,81.6896611257 2014-04-03 12:05:00,83.55895675800001 2014-04-03 12:10:00,84.0783689816 2014-04-03 12:15:00,84.2311641758 2014-04-03 12:20:00,82.5159721659 2014-04-03 12:25:00,75.3624354079 2014-04-03 12:30:00,78.3736107669 2014-04-03 12:35:00,84.3167778664 2014-04-03 12:40:00,87.15012593629999 2014-04-03 12:45:00,73.17523565569999 2014-04-03 12:50:00,80.4719045405 2014-04-03 12:55:00,76.90795591359999 2014-04-03 13:00:00,75.5881567965 2014-04-03 13:05:00,80.0737486233 2014-04-03 13:10:00,81.6778220658 2014-04-03 13:15:00,72.1390381773 2014-04-03 13:20:00,84.463029162 2014-04-03 13:25:00,85.0976857528 2014-04-03 13:30:00,87.4271856315 2014-04-03 13:35:00,74.8723260597 2014-04-03 13:40:00,81.4932779159 2014-04-03 13:45:00,78.8070877342 2014-04-03 13:50:00,77.3386798859 2014-04-03 13:55:00,81.0306831905 2014-04-03 14:00:00,84.5140726214 2014-04-03 14:05:00,72.3653708306 2014-04-03 14:10:00,87.5062013018 2014-04-03 14:15:00,84.9540273822 2014-04-03 14:20:00,84.0144263723 2014-04-03 14:25:00,84.1621581374 2014-04-03 14:30:00,78.2212165553 2014-04-03 14:35:00,84.0218955689 2014-04-03 14:40:00,78.1845702981 2014-04-03 14:45:00,86.37516306639999 2014-04-03 14:50:00,74.83196602609999 2014-04-03 14:55:00,76.6738782646 2014-04-03 15:00:00,80.8206247977 2014-04-03 15:05:00,77.1066363434 2014-04-03 15:10:00,78.7870395619 2014-04-03 15:15:00,79.8779961943 2014-04-03 15:20:00,85.7008308451 2014-04-03 15:25:00,80.3703044954 2014-04-03 15:30:00,77.798610704 2014-04-03 15:35:00,75.96304937229999 2014-04-03 15:40:00,78.538061688 2014-04-03 15:45:00,80.2510072536 2014-04-03 15:50:00,83.937031912 2014-04-03 15:55:00,73.9360706257 2014-04-03 16:00:00,75.545601964 2014-04-03 16:05:00,78.0743143509 2014-04-03 16:10:00,77.76622517050001 2014-04-03 16:15:00,78.2678191272 2014-04-03 16:20:00,84.6961776173 2014-04-03 16:25:00,77.18632224939999 2014-04-03 16:30:00,80.0302172281 2014-04-03 16:35:00,81.98235511930001 2014-04-03 16:40:00,75.7147114304 2014-04-03 16:45:00,83.498965876 2014-04-03 16:50:00,80.7536260686 2014-04-03 16:55:00,79.1483466434 2014-04-03 17:00:00,84.9565118045 2014-04-03 17:05:00,75.8958950029 2014-04-03 17:10:00,86.1307824556 2014-04-03 17:15:00,80.97674867079998 2014-04-03 17:20:00,81.74676667930001 2014-04-03 17:25:00,86.0009104023 2014-04-03 17:30:00,85.0812903344 2014-04-03 17:35:00,81.6249617572 2014-04-03 17:40:00,84.05097098600001 2014-04-03 17:45:00,78.9330815334 2014-04-03 17:50:00,80.7580130449 2014-04-03 17:55:00,72.993094158 2014-04-03 18:00:00,29.3750850352 2014-04-03 18:05:00,34.108316038000005 2014-04-03 18:10:00,29.1818929934 2014-04-03 18:15:00,29.8841486663 2014-04-03 18:20:00,33.8933225098 2014-04-03 18:25:00,28.807328553 2014-04-03 18:30:00,30.607381828 2014-04-03 18:35:00,32.5378411628 2014-04-03 18:40:00,32.6108733001 2014-04-03 18:45:00,33.7737721281 2014-04-03 18:50:00,32.0379218775 2014-04-03 18:55:00,32.0601658094 2014-04-03 19:00:00,23.409390094299997 2014-04-03 19:05:00,22.393836367 2014-04-03 19:10:00,22.8860388123 2014-04-03 19:15:00,24.1820264992 2014-04-03 19:20:00,21.9584993095 2014-04-03 19:25:00,21.885359117100002 2014-04-03 19:30:00,20.1758983768 2014-04-03 19:35:00,22.908148394899996 2014-04-03 19:40:00,20.2933770319 2014-04-03 19:45:00,22.4185840042 2014-04-03 19:50:00,23.76296607130001 2014-04-03 19:55:00,22.623645154899997 2014-04-03 20:00:00,19.5364294983 2014-04-03 20:05:00,21.6521455944 2014-04-03 20:10:00,19.5367606143 2014-04-03 20:15:00,80.0000000000 2014-04-03 20:20:00,20.9316183813 2014-04-03 20:25:00,19.128304601900002 2014-04-03 20:30:00,22.1394280857 2014-04-03 20:35:00,19.2538362943 2014-04-03 20:40:00,22.4853483859 2014-04-03 20:45:00,18.46194354 2014-04-03 20:50:00,19.511227678599997 2014-04-03 20:55:00,19.2506275466 2014-04-03 21:00:00,18.1426422698 2014-04-03 21:05:00,21.0299330128 2014-04-03 21:10:00,20.8734169327 2014-04-03 21:15:00,21.2710169439 2014-04-03 21:20:00,19.118122751199998 2014-04-03 21:25:00,19.8722718549 2014-04-03 21:30:00,20.735509015399998 2014-04-03 21:35:00,19.8539175223 2014-04-03 21:40:00,20.889091685 2014-04-03 21:45:00,20.634465872699998 2014-04-03 21:50:00,18.5471924045 2014-04-03 21:55:00,21.2255684603 2014-04-03 22:00:00,20.9027528233 2014-04-03 22:05:00,20.6431359444 2014-04-03 22:10:00,18.6382499754 2014-04-03 22:15:00,19.0902948922 2014-04-03 22:20:00,19.5914979165 2014-04-03 22:25:00,19.138073407 2014-04-03 22:30:00,18.9293959449 2014-04-03 22:35:00,21.241803243699998 2014-04-03 22:40:00,20.5726597872 2014-04-03 22:45:00,20.2813399292 2014-04-03 22:50:00,18.9219584925 2014-04-03 22:55:00,21.6931116524 2014-04-03 23:00:00,18.7683349831 2014-04-03 23:05:00,21.1838702515 2014-04-03 23:10:00,21.8708890693 2014-04-03 23:15:00,20.9123853221 2014-04-03 23:20:00,21.975653614099997 2014-04-03 23:25:00,20.6081604731 2014-04-03 23:30:00,18.8734643821 2014-04-03 23:35:00,18.818890506400002 2014-04-03 23:40:00,19.3019624005 2014-04-03 23:45:00,18.031981555 2014-04-03 23:50:00,20.7307734227 2014-04-03 23:55:00,19.0783334735 2014-04-04 00:00:00,21.2607329292 2014-04-04 00:05:00,19.4366906022 2014-04-04 00:10:00,19.9198259739 2014-04-04 00:15:00,21.862755666199998 2014-04-04 00:20:00,18.968688492200002 2014-04-04 00:25:00,20.8850163897 2014-04-04 00:30:00,21.0204711572 2014-04-04 00:35:00,18.8839926301 2014-04-04 00:40:00,20.003987346400002 2014-04-04 00:45:00,19.4008077013 2014-04-04 00:50:00,21.0876249736 2014-04-04 00:55:00,20.4899332761 2014-04-04 01:00:00,19.9039322194 2014-04-04 01:05:00,21.1174530602 2014-04-04 01:10:00,18.94062228 2014-04-04 01:15:00,21.0144875223 2014-04-04 01:20:00,21.4614972484 2014-04-04 01:25:00,21.514486387199998 2014-04-04 01:30:00,21.1346943721 2014-04-04 01:35:00,19.632056668 2014-04-04 01:40:00,21.927232090900002 2014-04-04 01:45:00,19.5183745753 2014-04-04 01:50:00,20.5545015964 2014-04-04 01:55:00,18.6442967123 2014-04-04 02:00:00,21.921795594499997 2014-04-04 02:05:00,20.8159436875 2014-04-04 02:10:00,21.013510180999997 2014-04-04 02:15:00,18.2631068136 2014-04-04 02:20:00,21.0536712569 2014-04-04 02:25:00,21.0988937169 2014-04-04 02:30:00,20.687090905399998 2014-04-04 02:35:00,19.1676384552 2014-04-04 02:40:00,19.958760168599998 2014-04-04 02:45:00,18.4417374852 2014-04-04 02:50:00,19.8863482658 2014-04-04 02:55:00,18.9752954104 2014-04-04 03:00:00,19.396387945999997 2014-04-04 03:05:00,18.650401633599998 2014-04-04 03:10:00,18.920217470999997 2014-04-04 03:15:00,18.3062745673 2014-04-04 03:20:00,21.679605465700003 2014-04-04 03:25:00,20.1216427519 2014-04-04 03:30:00,19.586967885099998 2014-04-04 03:35:00,20.1401168511 2014-04-04 03:40:00,20.5131729139 2014-04-04 03:45:00,21.6875151735 2014-04-04 03:50:00,18.7147718091 2014-04-04 03:55:00,19.1822099945 2014-04-04 04:00:00,21.9031573454 2014-04-04 04:05:00,19.484771946600002 2014-04-04 04:10:00,18.090246603 2014-04-04 04:15:00,18.5905739705 2014-04-04 04:20:00,18.105354807 2014-04-04 04:25:00,21.9596925697 2014-04-04 04:30:00,19.115483396 2014-04-04 04:35:00,21.6941710277 2014-04-04 04:40:00,21.983545103 2014-04-04 04:45:00,20.3993648846 2014-04-04 04:50:00,18.1327852603 2014-04-04 04:55:00,18.326366521500002 2014-04-04 05:00:00,19.9263562204 2014-04-04 05:05:00,19.6246880516 2014-04-04 05:10:00,20.4247092231 2014-04-04 05:15:00,19.7553912388 2014-04-04 05:20:00,21.7363073971 2014-04-04 05:25:00,20.1389588617 2014-04-04 05:30:00,20.7749042458 2014-04-04 05:35:00,21.5859410906 2014-04-04 05:40:00,18.5874875033 2014-04-04 05:45:00,18.9189386165 2014-04-04 05:50:00,18.4292746419 2014-04-04 05:55:00,18.5585535969 2014-04-04 06:00:00,20.0503358677 2014-04-04 06:05:00,19.284717035899998 2014-04-04 06:10:00,19.6926913581 2014-04-04 06:15:00,21.9299593272 2014-04-04 06:20:00,18.6268173912 2014-04-04 06:25:00,20.163248283199998 2014-04-04 06:30:00,18.3954846202 2014-04-04 06:35:00,19.2739852531 2014-04-04 06:40:00,20.1101036947 2014-04-04 06:45:00,21.7865269839 2014-04-04 06:50:00,19.5649128851 2014-04-04 06:55:00,18.2596267849 2014-04-04 07:00:00,19.5526457918 2014-04-04 07:05:00,18.5829647035 2014-04-04 07:10:00,18.9199584532 2014-04-04 07:15:00,20.4723624927 2014-04-04 07:20:00,18.2696954648 2014-04-04 07:25:00,19.858895025 2014-04-04 07:30:00,20.437846344 2014-04-04 07:35:00,19.6874335695 2014-04-04 07:40:00,18.0765054025 2014-04-04 07:45:00,21.9420774276 2014-04-04 07:50:00,19.468463069400002 2014-04-04 07:55:00,21.1143087477 2014-04-04 08:00:00,19.302585968699997 2014-04-04 08:05:00,19.900067028 2014-04-04 08:10:00,19.5538545704 2014-04-04 08:15:00,19.370156918 2014-04-04 08:20:00,18.0874055088 2014-04-04 08:25:00,19.4400837514 2014-04-04 08:30:00,21.557959961599998 2014-04-04 08:35:00,20.7615733544 2014-04-04 08:40:00,18.5816914364 2014-04-04 08:45:00,20.3646200185 2014-04-04 08:50:00,21.5689234398 2014-04-04 08:55:00,20.8001361639 2014-04-04 09:00:00,63.2221077361 2014-04-04 09:05:00,73.0025219556 2014-04-04 09:10:00,65.3009985807 2014-04-04 09:15:00,67.3754355626 2014-04-04 09:20:00,68.3555415318 2014-04-04 09:25:00,72.7668898195 2014-04-04 09:30:00,73.869861934 2014-04-04 09:35:00,73.843279138 2014-04-04 09:40:00,61.3081768654 2014-04-04 09:45:00,73.737683404 2014-04-04 09:50:00,61.9396627376 2014-04-04 09:55:00,64.8145217327 2014-04-04 10:00:00,77.8326115054 2014-04-04 10:05:00,77.2884466933 2014-04-04 10:10:00,79.2250960011 2014-04-04 10:15:00,77.28100547 2014-04-04 10:20:00,84.341510548 2014-04-04 10:25:00,73.5733181243 2014-04-04 10:30:00,74.09286325149999 2014-04-04 10:35:00,84.129852762 2014-04-04 10:40:00,71.0309972533 2014-04-04 10:45:00,79.300383956 2014-04-04 10:50:00,80.4205419761 2014-04-04 10:55:00,77.6860075476 2014-04-04 11:00:00,82.6090638008 2014-04-04 11:05:00,74.3154898902 2014-04-04 11:10:00,85.12826303 2014-04-04 11:15:00,73.7949685653 2014-04-04 11:20:00,77.9425211144 2014-04-04 11:25:00,72.7648968912 2014-04-04 11:30:00,80.2390369975 2014-04-04 11:35:00,82.2196373213 2014-04-04 11:40:00,86.53718888459998 2014-04-04 11:45:00,83.32640285949999 2014-04-04 11:50:00,80.17370078329998 2014-04-04 11:55:00,86.4003410411 2014-04-04 12:00:00,79.5594034214 2014-04-04 12:05:00,80.882115301 2014-04-04 12:10:00,81.439731351 2014-04-04 12:15:00,78.4654040034 2014-04-04 12:20:00,85.3132241814 2014-04-04 12:25:00,74.87285964350001 2014-04-04 12:30:00,80.7804220759 2014-04-04 12:35:00,83.4554652205 2014-04-04 12:40:00,86.3598624075 2014-04-04 12:45:00,86.03932310969999 2014-04-04 12:50:00,80.0436768173 2014-04-04 12:55:00,82.19183451880002 2014-04-04 13:00:00,78.2890099052 2014-04-04 13:05:00,79.4717664035 2014-04-04 13:10:00,86.4794926205 2014-04-04 13:15:00,86.8704099877 2014-04-04 13:20:00,86.3059065391 2014-04-04 13:25:00,74.1961224449 2014-04-04 13:30:00,85.5808000186 2014-04-04 13:35:00,87.15289797959998 2014-04-04 13:40:00,77.7613279144 2014-04-04 13:45:00,80.279069029 2014-04-04 13:50:00,84.4452523672 2014-04-04 13:55:00,80.973811821 2014-04-04 14:00:00,87.89151735200001 2014-04-04 14:05:00,79.2876078546 2014-04-04 14:10:00,83.4190790713 2014-04-04 14:15:00,84.6773935331 2014-04-04 14:20:00,79.90177118300001 2014-04-04 14:25:00,85.70762672779999 2014-04-04 14:30:00,80.7345980126 2014-04-04 14:35:00,78.58264060100001 2014-04-04 14:40:00,73.721639973 2014-04-04 14:45:00,78.29085908 2014-04-04 14:50:00,83.7389636125 2014-04-04 14:55:00,86.7364190389 2014-04-04 15:00:00,76.0261406038 2014-04-04 15:05:00,77.6830225131 2014-04-04 15:10:00,74.4626610573 2014-04-04 15:15:00,83.0507690126 2014-04-04 15:20:00,87.3621761952 2014-04-04 15:25:00,82.25444586729999 2014-04-04 15:30:00,81.8724384971 2014-04-04 15:35:00,80.855062672 2014-04-04 15:40:00,73.4145870642 2014-04-04 15:45:00,83.67125797109999 2014-04-04 15:50:00,81.63200902199999 2014-04-04 15:55:00,82.58283549890001 2014-04-04 16:00:00,86.38081163700001 2014-04-04 16:05:00,84.5432102697 2014-04-04 16:10:00,84.49448180479999 2014-04-04 16:15:00,86.834773579 2014-04-04 16:20:00,87.8387905726 2014-04-04 16:25:00,81.3003676144 2014-04-04 16:30:00,73.7419642717 2014-04-04 16:35:00,79.3459261799 2014-04-04 16:40:00,84.6014559083 2014-04-04 16:45:00,72.4434661045 2014-04-04 16:50:00,72.9100590261 2014-04-04 16:55:00,73.074384215 2014-04-04 17:00:00,83.6965399938 2014-04-04 17:05:00,80.01863532979999 2014-04-04 17:10:00,77.90233718180001 2014-04-04 17:15:00,73.6898444273 2014-04-04 17:20:00,83.71581185640001 2014-04-04 17:25:00,77.1362873485 2014-04-04 17:30:00,76.2451558429 2014-04-04 17:35:00,82.437075569 2014-04-04 17:40:00,80.944143199 2014-04-04 17:45:00,77.79854039439999 2014-04-04 17:50:00,82.2637679436 2014-04-04 17:55:00,76.3395150118 2014-04-04 18:00:00,33.886907168 2014-04-04 18:05:00,30.2676354706 2014-04-04 18:10:00,29.8165555257 2014-04-04 18:15:00,33.8076057297 2014-04-04 18:20:00,33.330502597 2014-04-04 18:25:00,29.9688836905 2014-04-04 18:30:00,29.5439671448 2014-04-04 18:35:00,34.1657476065 2014-04-04 18:40:00,33.7702238022 2014-04-04 18:45:00,30.8944412599 2014-04-04 18:50:00,33.0124570742 2014-04-04 18:55:00,29.5946195117 2014-04-04 19:00:00,22.431572281999998 2014-04-04 19:05:00,20.2439105979 2014-04-04 19:10:00,21.9143752244 2014-04-04 19:15:00,20.4952947159 2014-04-04 19:20:00,22.2886581444 2014-04-04 19:25:00,22.0491325683 2014-04-04 19:30:00,22.1508437042 2014-04-04 19:35:00,20.3630831161 2014-04-04 19:40:00,21.7800400142 2014-04-04 19:45:00,23.5490463521 2014-04-04 19:50:00,21.812735196 2014-04-04 19:55:00,23.363969066 2014-04-04 20:00:00,19.9453846127 2014-04-04 20:05:00,20.1655885104 2014-04-04 20:10:00,20.7417018452 2014-04-04 20:15:00,22.3259929452 2014-04-04 20:20:00,18.8778921629 2014-04-04 20:25:00,18.5668145736 2014-04-04 20:30:00,20.9221923738 2014-04-04 20:35:00,22.3195014084 2014-04-04 20:40:00,22.4859056811 2014-04-04 20:45:00,20.415136512300002 2014-04-04 20:50:00,20.3492620758 2014-04-04 20:55:00,21.0737713521 2014-04-04 21:00:00,20.319607166500003 2014-04-04 21:05:00,20.6349266707 2014-04-04 21:10:00,21.5991784383 2014-04-04 21:15:00,21.0859537048 2014-04-04 21:20:00,20.0834495635 2014-04-04 21:25:00,19.9427255848 2014-04-04 21:30:00,20.657087297100002 2014-04-04 21:35:00,19.9179746496 2014-04-04 21:40:00,19.9263067199 2014-04-04 21:45:00,18.1519366361 2014-04-04 21:50:00,18.7859985351 2014-04-04 21:55:00,20.0498339728 2014-04-04 22:00:00,21.311052815 2014-04-04 22:05:00,19.1332583292 2014-04-04 22:10:00,20.1098606734 2014-04-04 22:15:00,19.3984529839 2014-04-04 22:20:00,18.4368983964 2014-04-04 22:25:00,21.8541537877 2014-04-04 22:30:00,21.4392574181 2014-04-04 22:35:00,18.3315510998 2014-04-04 22:40:00,20.8991930227 2014-04-04 22:45:00,19.4089343147 2014-04-04 22:50:00,22.0004994407 2014-04-04 22:55:00,19.2280352802 2014-04-04 23:00:00,18.9585931307 2014-04-04 23:05:00,20.2754543312 2014-04-04 23:10:00,21.3446020282 2014-04-04 23:15:00,18.7736793399 2014-04-04 23:20:00,20.8416118982 2014-04-04 23:25:00,18.249129490999998 2014-04-04 23:30:00,21.6799007122 2014-04-04 23:35:00,18.3278179283 2014-04-04 23:40:00,21.6610836329 2014-04-04 23:45:00,19.9670619358 2014-04-04 23:50:00,19.7961645832 2014-04-04 23:55:00,21.897431815700003 2014-04-05 00:00:00,21.9615367108 2014-04-05 00:05:00,20.6007125038 2014-04-05 00:10:00,18.5084771674 2014-04-05 00:15:00,20.0246803426 2014-04-05 00:20:00,20.1166524038 2014-04-05 00:25:00,20.0577857125 2014-04-05 00:30:00,20.2779673541 2014-04-05 00:35:00,18.0748988552 2014-04-05 00:40:00,20.8449091259 2014-04-05 00:45:00,20.8495772078 2014-04-05 00:50:00,18.4618791007 2014-04-05 00:55:00,20.2809577698 2014-04-05 01:00:00,20.2734447297 2014-04-05 01:05:00,20.729801680799998 2014-04-05 01:10:00,18.341590768499998 2014-04-05 01:15:00,20.506013229100002 2014-04-05 01:20:00,19.123007803 2014-04-05 01:25:00,20.028011962 2014-04-05 01:30:00,21.0932942108 2014-04-05 01:35:00,20.8225837455 2014-04-05 01:40:00,18.4756120707 2014-04-05 01:45:00,20.3647391485 2014-04-05 01:50:00,21.8764661238 2014-04-05 01:55:00,18.6270777493 2014-04-05 02:00:00,21.4116283509 2014-04-05 02:05:00,20.8101923222 2014-04-05 02:10:00,21.096013251600002 2014-04-05 02:15:00,19.1278333086 2014-04-05 02:20:00,19.1515557175 2014-04-05 02:25:00,21.6240778231 2014-04-05 02:30:00,19.4393281284 2014-04-05 02:35:00,18.252061562799998 2014-04-05 02:40:00,20.4023868143 2014-04-05 02:45:00,18.4992706762 2014-04-05 02:50:00,21.1863849656 2014-04-05 02:55:00,20.56698577 2014-04-05 03:00:00,21.4989060209 2014-04-05 03:05:00,21.1393489991 2014-04-05 03:10:00,18.448454593399997 2014-04-05 03:15:00,19.5242827057 2014-04-05 03:20:00,21.0982409997 2014-04-05 03:25:00,19.6693658931 2014-04-05 03:30:00,21.8894619391 2014-04-05 03:35:00,20.9429617996 2014-04-05 03:40:00,18.061999666800002 2014-04-05 03:45:00,21.5199427662 2014-04-05 03:50:00,18.4032191395 2014-04-05 03:55:00,18.5620948967 2014-04-05 04:00:00,20.9379696024 2014-04-05 04:05:00,21.4598742377 2014-04-05 04:10:00,20.1453985116 2014-04-05 04:15:00,19.156198931800002 2014-04-05 04:20:00,19.405262180999998 2014-04-05 04:25:00,19.3715573184 2014-04-05 04:30:00,19.3067124152 2014-04-05 04:35:00,18.9716386873 2014-04-05 04:40:00,20.435468378499998 2014-04-05 04:45:00,21.601621274299998 2014-04-05 04:50:00,19.2283296523 2014-04-05 04:55:00,18.7467771898 2014-04-05 05:00:00,21.354310665499998 2014-04-05 05:05:00,20.9671333236 2014-04-05 05:10:00,21.723348126199998 2014-04-05 05:15:00,18.6620789424 2014-04-05 05:20:00,18.5770052565 2014-04-05 05:25:00,20.1657175772 2014-04-05 05:30:00,20.457734619300002 2014-04-05 05:35:00,19.9206937674 2014-04-05 05:40:00,20.3958665453 2014-04-05 05:45:00,18.721519075499998 2014-04-05 05:50:00,19.9184550167 2014-04-05 05:55:00,20.6323702438 2014-04-05 06:00:00,19.730825797 2014-04-05 06:05:00,20.717789343299998 2014-04-05 06:10:00,19.8047651222 2014-04-05 06:15:00,19.3343983234 2014-04-05 06:20:00,19.2144201883 2014-04-05 06:25:00,19.643608236 2014-04-05 06:30:00,18.0923584907 2014-04-05 06:35:00,20.674100553800002 2014-04-05 06:40:00,21.3804225639 2014-04-05 06:45:00,19.4185083778 2014-04-05 06:50:00,18.1841325446 2014-04-05 06:55:00,21.9471023895 2014-04-05 07:00:00,19.054793021800002 2014-04-05 07:05:00,18.5064844868 2014-04-05 07:10:00,19.4790100319 2014-04-05 07:15:00,20.9542281625 2014-04-05 07:20:00,19.1756663876 2014-04-05 07:25:00,20.2988128157 2014-04-05 07:30:00,19.6622399777 2014-04-05 07:35:00,18.4710559691 2014-04-05 07:40:00,19.32114805 2014-04-05 07:45:00,20.8994820229 2014-04-05 07:50:00,20.448015589300002 2014-04-05 07:55:00,18.4791135195 2014-04-05 08:00:00,18.653289638900002 2014-04-05 08:05:00,20.5629334372 2014-04-05 08:10:00,21.2536616573 2014-04-05 08:15:00,19.3978979838 2014-04-05 08:20:00,20.3812430074 2014-04-05 08:25:00,18.682574355 2014-04-05 08:30:00,19.245505347599998 2014-04-05 08:35:00,18.0810808227 2014-04-05 08:40:00,21.073103791199998 2014-04-05 08:45:00,19.6040392791 2014-04-05 08:50:00,21.2645022946 2014-04-05 08:55:00,20.8334919841 2014-04-05 09:00:00,72.47092201390001 2014-04-05 09:05:00,65.0849579063 2014-04-05 09:10:00,63.7174787338 2014-04-05 09:15:00,74.4179172841 2014-04-05 09:20:00,70.9556579038 2014-04-05 09:25:00,72.5429748438 2014-04-05 09:30:00,61.3786138825 2014-04-05 09:35:00,66.020678036 2014-04-05 09:40:00,71.3023069919 2014-04-05 09:45:00,62.2605665287 2014-04-05 09:50:00,68.9158230421 2014-04-05 09:55:00,67.0353896374 2014-04-05 10:00:00,70.1134081908 2014-04-05 10:05:00,73.5023409569 2014-04-05 10:10:00,74.2599716703 2014-04-05 10:15:00,71.5760663673 2014-04-05 10:20:00,79.6414528392 2014-04-05 10:25:00,73.6020150394 2014-04-05 10:30:00,74.1486546341 2014-04-05 10:35:00,83.7806630441 2014-04-05 10:40:00,77.0897503986 2014-04-05 10:45:00,75.925828841 2014-04-05 10:50:00,81.0744785146 2014-04-05 10:55:00,83.9572061276 2014-04-05 11:00:00,71.9661778915 2014-04-05 11:05:00,78.69679061560001 2014-04-05 11:10:00,81.2818666871 2014-04-05 11:15:00,76.6344275126 2014-04-05 11:20:00,83.8523724126 2014-04-05 11:25:00,87.0183713256 2014-04-05 11:30:00,86.5722688328 2014-04-05 11:35:00,75.7981863063 2014-04-05 11:40:00,75.1676839803 2014-04-05 11:45:00,86.7959294054 2014-04-05 11:50:00,78.8620274641 2014-04-05 11:55:00,74.8807669879 2014-04-05 12:00:00,83.2119770764 2014-04-05 12:05:00,76.4588643122 2014-04-05 12:10:00,76.1844204592 2014-04-05 12:15:00,85.9647031076 2014-04-05 12:20:00,74.5101468543 2014-04-05 12:25:00,72.9426507989 2014-04-05 12:30:00,76.2154146631 2014-04-05 12:35:00,81.6130732535 2014-04-05 12:40:00,73.8806423677 2014-04-05 12:45:00,79.4500601387 2014-04-05 12:50:00,81.9389488943 2014-04-05 12:55:00,85.4770961312 2014-04-05 13:00:00,75.65975076 2014-04-05 13:05:00,85.0571225642 2014-04-05 13:10:00,75.74031813810001 2014-04-05 13:15:00,82.80838587630002 2014-04-05 13:20:00,78.8718433572 2014-04-05 13:25:00,73.8171795021 2014-04-05 13:30:00,83.40819263350001 2014-04-05 13:35:00,75.4660856883 2014-04-05 13:40:00,74.8080165824 2014-04-05 13:45:00,77.7145108974 2014-04-05 13:50:00,82.4328552816 2014-04-05 13:55:00,75.7257651142 2014-04-05 14:00:00,74.9349875684 2014-04-05 14:05:00,72.155794367 2014-04-05 14:10:00,79.5424713317 2014-04-05 14:15:00,78.8545439092 2014-04-05 14:20:00,75.73824828779999 2014-04-05 14:25:00,72.8549374193 2014-04-05 14:30:00,78.864308325 2014-04-05 14:35:00,84.6072204356 2014-04-05 14:40:00,83.4405087646 2014-04-05 14:45:00,85.76860114729999 2014-04-05 14:50:00,72.1498596439 2014-04-05 14:55:00,87.4585108588 2014-04-05 15:00:00,77.4618524011 2014-04-05 15:05:00,87.8455214124 2014-04-05 15:10:00,76.0411813673 2014-04-05 15:15:00,79.5438185733 2014-04-05 15:20:00,77.6620972619 2014-04-05 15:25:00,77.6914255951 2014-04-05 15:30:00,85.4756930054 2014-04-05 15:35:00,83.9418971858 2014-04-05 15:40:00,87.8735793692 2014-04-05 15:45:00,81.8154494876 2014-04-05 15:50:00,79.4113433141 2014-04-05 15:55:00,73.44047677180001 2014-04-05 16:00:00,87.94481385790002 2014-04-05 16:05:00,80.8243352639 2014-04-05 16:10:00,83.2074797564 2014-04-05 16:15:00,78.5077274599 2014-04-05 16:20:00,80.763296265 2014-04-05 16:25:00,87.08107651430002 2014-04-05 16:30:00,74.6625676545 2014-04-05 16:35:00,76.6778141276 2014-04-05 16:40:00,74.4328127332 2014-04-05 16:45:00,84.67529188399999 2014-04-05 16:50:00,72.9925840207 2014-04-05 16:55:00,73.3059656499 2014-04-05 17:00:00,76.7758763227 2014-04-05 17:05:00,80.2269800876 2014-04-05 17:10:00,78.5003666648 2014-04-05 17:15:00,72.7170330474 2014-04-05 17:20:00,87.3198313951 2014-04-05 17:25:00,87.2458788233 2014-04-05 17:30:00,76.4696718075 2014-04-05 17:35:00,83.7043777018 2014-04-05 17:40:00,81.2571753794 2014-04-05 17:45:00,75.79959801300001 2014-04-05 17:50:00,76.1947155691 2014-04-05 17:55:00,79.8584201233 2014-04-05 18:00:00,31.4831103808 2014-04-05 18:05:00,30.6638618132 2014-04-05 18:10:00,33.9680676945 2014-04-05 18:15:00,31.8813565517 2014-04-05 18:20:00,32.991021265 2014-04-05 18:25:00,30.0113446389 2014-04-05 18:30:00,32.2144428549 2014-04-05 18:35:00,30.83504079610001 2014-04-05 18:40:00,32.1690409301 2014-04-05 18:45:00,33.7972788448 2014-04-05 18:50:00,33.7210380701 2014-04-05 18:55:00,31.067006374600002 2014-04-05 19:00:00,23.270360208000003 2014-04-05 19:05:00,24.3769776405 2014-04-05 19:10:00,22.9629973384 2014-04-05 19:15:00,20.8248762104 2014-04-05 19:20:00,23.205093386199998 2014-04-05 19:25:00,20.629970519100002 2014-04-05 19:30:00,24.0670533111 2014-04-05 19:35:00,22.4746377883 2014-04-05 19:40:00,21.8854292981 2014-04-05 19:45:00,20.4153884241 2014-04-05 19:50:00,21.865909931500006 2014-04-05 19:55:00,24.2063645444 2014-04-05 20:00:00,18.5179461306 2014-04-05 20:05:00,20.3761586098 2014-04-05 20:10:00,22.246023274200002 2014-04-05 20:15:00,20.0492684944 2014-04-05 20:20:00,20.1858073736 2014-04-05 20:25:00,20.8017817365 2014-04-05 20:30:00,20.3281910744 2014-04-05 20:35:00,19.1225922978 2014-04-05 20:40:00,18.508003265899998 2014-04-05 20:45:00,20.9297882999 2014-04-05 20:50:00,22.2036235139 2014-04-05 20:55:00,18.8676672625 2014-04-05 21:00:00,18.9342611229 2014-04-05 21:05:00,19.574426301600003 2014-04-05 21:10:00,21.3368967147 2014-04-05 21:15:00,19.1686110171 2014-04-05 21:20:00,21.6315530088 2014-04-05 21:25:00,18.307286645 2014-04-05 21:30:00,21.868292798699997 2014-04-05 21:35:00,20.3401546056 2014-04-05 21:40:00,20.734159194700002 2014-04-05 21:45:00,19.5642176811 2014-04-05 21:50:00,21.2293913804 2014-04-05 21:55:00,18.755863026500002 2014-04-05 22:00:00,18.2131151136 2014-04-05 22:05:00,19.6008665479 2014-04-05 22:10:00,21.4353410369 2014-04-05 22:15:00,21.0398862553 2014-04-05 22:20:00,20.087889751 2014-04-05 22:25:00,20.3080279876 2014-04-05 22:30:00,18.5373500845 2014-04-05 22:35:00,21.383234241 2014-04-05 22:40:00,21.1681406466 2014-04-05 22:45:00,20.6456824117 2014-04-05 22:50:00,19.8838343091 2014-04-05 22:55:00,21.878820586 2014-04-05 23:00:00,21.5202589819 2014-04-05 23:05:00,20.5816728947 2014-04-05 23:10:00,19.4909455321 2014-04-05 23:15:00,20.476019753800003 2014-04-05 23:20:00,20.3056616428 2014-04-05 23:25:00,19.5807267273 2014-04-05 23:30:00,19.2303874105 2014-04-05 23:35:00,19.631811751300003 2014-04-05 23:40:00,20.2995423861 2014-04-05 23:45:00,19.7163241845 2014-04-05 23:50:00,19.057956376099998 2014-04-05 23:55:00,21.047893688800002 2014-04-06 00:00:00,20.1258699838 2014-04-06 00:05:00,18.2707006529 2014-04-06 00:10:00,19.4732660225 2014-04-06 00:15:00,21.539653828800002 2014-04-06 00:20:00,21.020946124800002 2014-04-06 00:25:00,19.2929871358 2014-04-06 00:30:00,21.752732608200002 2014-04-06 00:35:00,18.3064116334 2014-04-06 00:40:00,21.8449388156 2014-04-06 00:45:00,18.9828203699 2014-04-06 00:50:00,18.0363767212 2014-04-06 00:55:00,19.7352321461 2014-04-06 01:00:00,19.4358817187 2014-04-06 01:05:00,20.1563560208 2014-04-06 01:10:00,21.1870914423 2014-04-06 01:15:00,21.3697232086 2014-04-06 01:20:00,19.6049199984 2014-04-06 01:25:00,19.7193829748 2014-04-06 01:30:00,18.5927109213 2014-04-06 01:35:00,18.1901904355 2014-04-06 01:40:00,20.564859960899998 2014-04-06 01:45:00,18.2577505022 2014-04-06 01:50:00,20.9353204777 2014-04-06 01:55:00,20.1563605801 2014-04-06 02:00:00,18.7943319129 2014-04-06 02:05:00,20.1580917741 2014-04-06 02:10:00,18.7319908664 2014-04-06 02:15:00,19.75494883 2014-04-06 02:20:00,21.198241265 2014-04-06 02:25:00,19.847677173599998 2014-04-06 02:30:00,18.5947972732 2014-04-06 02:35:00,20.8953147273 2014-04-06 02:40:00,18.7470736651 2014-04-06 02:45:00,20.9541994975 2014-04-06 02:50:00,19.9174091569 2014-04-06 02:55:00,19.814967036400002 2014-04-06 03:00:00,21.4057401514 2014-04-06 03:05:00,20.8344140974 2014-04-06 03:10:00,18.131643187799998 2014-04-06 03:15:00,19.1846972584 2014-04-06 03:20:00,21.4836826434 2014-04-06 03:25:00,18.0733046742 2014-04-06 03:30:00,20.181013785 2014-04-06 03:35:00,20.9113026767 2014-04-06 03:40:00,20.4874243419 2014-04-06 03:45:00,21.042128808399998 2014-04-06 03:50:00,20.9027673957 2014-04-06 03:55:00,20.7681227806 2014-04-06 04:00:00,21.286159443699997 2014-04-06 04:05:00,20.5827626738 2014-04-06 04:10:00,19.609673977 2014-04-06 04:15:00,19.8876364397 2014-04-06 04:20:00,20.8668991307 2014-04-06 04:25:00,21.5052241187 2014-04-06 04:30:00,19.0888752034 2014-04-06 04:35:00,19.3683071839 2014-04-06 04:40:00,21.7229575854 2014-04-06 04:45:00,20.314047169600002 2014-04-06 04:50:00,18.7158472685 2014-04-06 04:55:00,20.6547805556 2014-04-06 05:00:00,21.9630486222 2014-04-06 05:05:00,21.2938142579 2014-04-06 05:10:00,20.982964546199998 2014-04-06 05:15:00,18.8321866171 2014-04-06 05:20:00,21.5045591387 2014-04-06 05:25:00,20.1031553741 2014-04-06 05:30:00,21.557160088299998 2014-04-06 05:35:00,19.3193113177 2014-04-06 05:40:00,18.2482042105 2014-04-06 05:45:00,19.9039038746 2014-04-06 05:50:00,19.0793504193 2014-04-06 05:55:00,20.8609171591 2014-04-06 06:00:00,21.8284262114 2014-04-06 06:05:00,20.7638966046 2014-04-06 06:10:00,21.547735718800002 2014-04-06 06:15:00,19.8120960544 2014-04-06 06:20:00,21.0865629488 2014-04-06 06:25:00,21.3721737467 2014-04-06 06:30:00,20.8435025103 2014-04-06 06:35:00,20.0311091443 2014-04-06 06:40:00,20.5034644385 2014-04-06 06:45:00,20.8020279827 2014-04-06 06:50:00,19.012337612899998 2014-04-06 06:55:00,21.2383170437 2014-04-06 07:00:00,21.801298155900003 2014-04-06 07:05:00,19.860957260699998 2014-04-06 07:10:00,20.8042687324 2014-04-06 07:15:00,20.948103623199998 2014-04-06 07:20:00,20.6489901901 2014-04-06 07:25:00,20.188460433299998 2014-04-06 07:30:00,21.5265918183 2014-04-06 07:35:00,19.7957068371 2014-04-06 07:40:00,18.2444118259 2014-04-06 07:45:00,21.3782255028 2014-04-06 07:50:00,20.6959250893 2014-04-06 07:55:00,21.397034506 2014-04-06 08:00:00,18.5541897698 2014-04-06 08:05:00,18.123011762 2014-04-06 08:10:00,21.7374981615 2014-04-06 08:15:00,18.590913223399998 2014-04-06 08:20:00,21.2386093283 2014-04-06 08:25:00,21.2928397687 2014-04-06 08:30:00,20.8348208022 2014-04-06 08:35:00,18.5250488444 2014-04-06 08:40:00,20.6695944982 2014-04-06 08:45:00,21.5563463333 2014-04-06 08:50:00,19.7021265792 2014-04-06 08:55:00,19.6540674175 2014-04-06 09:00:00,67.22287301029999 2014-04-06 09:05:00,62.318897713199995 2014-04-06 09:10:00,73.3315477388 2014-04-06 09:15:00,73.0208869501 2014-04-06 09:20:00,74.7715667763 2014-04-06 09:25:00,69.1584907244 2014-04-06 09:30:00,71.41620625569999 2014-04-06 09:35:00,63.9563379258 2014-04-06 09:40:00,70.2783919278 2014-04-06 09:45:00,70.0363667431 2014-04-06 09:50:00,73.45643880739999 2014-04-06 09:55:00,72.4987810306 2014-04-06 10:00:00,84.4049994998 2014-04-06 10:05:00,83.3242954963 2014-04-06 10:10:00,83.3221292488 2014-04-06 10:15:00,70.8289860302 2014-04-06 10:20:00,82.9693295058 2014-04-06 10:25:00,79.2680646827 2014-04-06 10:30:00,75.7444978914 2014-04-06 10:35:00,70.7171069705 2014-04-06 10:40:00,80.3574969844 2014-04-06 10:45:00,74.9336911683 2014-04-06 10:50:00,77.0998876326 2014-04-06 10:55:00,80.4204253431 2014-04-06 11:00:00,86.0688623959 2014-04-06 11:05:00,84.6957487058 2014-04-06 11:10:00,78.7342967413 2014-04-06 11:15:00,77.735303336 2014-04-06 11:20:00,75.3814569666 2014-04-06 11:25:00,77.49107505069999 2014-04-06 11:30:00,73.33408174350001 2014-04-06 11:35:00,87.012462005 2014-04-06 11:40:00,80.6955830287 2014-04-06 11:45:00,73.6006241238 2014-04-06 11:50:00,77.1790267714 2014-04-06 11:55:00,80.2681105401 2014-04-06 12:00:00,80.429538782 2014-04-06 12:05:00,72.48097223479999 2014-04-06 12:10:00,87.10880039979997 2014-04-06 12:15:00,76.3143236905 2014-04-06 12:20:00,72.1722439573 2014-04-06 12:25:00,73.1352364182 2014-04-06 12:30:00,81.1855787098 2014-04-06 12:35:00,74.1155228488 2014-04-06 12:40:00,72.5803955696 2014-04-06 12:45:00,77.9803346344 2014-04-06 12:50:00,81.8658220626 2014-04-06 12:55:00,73.7008895532 2014-04-06 13:00:00,76.9947621355 2014-04-06 13:05:00,78.665286545 2014-04-06 13:10:00,74.53346923779999 2014-04-06 13:15:00,80.0779590517 2014-04-06 13:20:00,73.3458181683 2014-04-06 13:25:00,72.7268373105 2014-04-06 13:30:00,80.2980897067 2014-04-06 13:35:00,75.9481196396 2014-04-06 13:40:00,73.5083346909 2014-04-06 13:45:00,78.7636935755 2014-04-06 13:50:00,86.6214576918 2014-04-06 13:55:00,83.5670182475 2014-04-06 14:00:00,85.0457722525 2014-04-06 14:05:00,85.9464981902 2014-04-06 14:10:00,87.5578408842 2014-04-06 14:15:00,84.2079030029 2014-04-06 14:20:00,81.7306034937 2014-04-06 14:25:00,77.84307743779999 2014-04-06 14:30:00,74.9026962829 2014-04-06 14:35:00,82.9825746289 2014-04-06 14:40:00,87.91497965639999 2014-04-06 14:45:00,79.4739240224 2014-04-06 14:50:00,83.5748581037 2014-04-06 14:55:00,79.9176429689 2014-04-06 15:00:00,78.9101772288 2014-04-06 15:05:00,78.56413559399999 2014-04-06 15:10:00,80.0732262166 2014-04-06 15:15:00,77.8695830347 2014-04-06 15:20:00,83.9795669376 2014-04-06 15:25:00,85.98752693729998 2014-04-06 15:30:00,86.1253380951 2014-04-06 15:35:00,75.6424532403 2014-04-06 15:40:00,86.3337174081 2014-04-06 15:45:00,77.4640760474 2014-04-06 15:50:00,76.9481839381 2014-04-06 15:55:00,83.6272940886 2014-04-06 16:00:00,76.8749938411 2014-04-06 16:05:00,72.8473226226 2014-04-06 16:10:00,77.9777346394 2014-04-06 16:15:00,83.5432892023 2014-04-06 16:20:00,77.2311864402 2014-04-06 16:25:00,82.0727873159 2014-04-06 16:30:00,82.5617525893 2014-04-06 16:35:00,83.7396154073 2014-04-06 16:40:00,86.3539216611 2014-04-06 16:45:00,78.9208804599 2014-04-06 16:50:00,74.6627698738 2014-04-06 16:55:00,77.1026634095 2014-04-06 17:00:00,78.91464577949999 2014-04-06 17:05:00,83.4222314751 2014-04-06 17:10:00,72.2099262804 2014-04-06 17:15:00,77.0525365469 2014-04-06 17:20:00,84.477448857 2014-04-06 17:25:00,82.73369148350001 2014-04-06 17:30:00,83.7078074336 2014-04-06 17:35:00,84.9889396753 2014-04-06 17:40:00,84.53173904180001 2014-04-06 17:45:00,82.9148988191 2014-04-06 17:50:00,79.0345541686 2014-04-06 17:55:00,87.7375395708 2014-04-06 18:00:00,32.4420622229 2014-04-06 18:05:00,30.0977171612 2014-04-06 18:10:00,30.6739963833 2014-04-06 18:15:00,33.2387933364 2014-04-06 18:20:00,34.7183265514 2014-04-06 18:25:00,29.9438030777 2014-04-06 18:30:00,29.327011942 2014-04-06 18:35:00,34.441792094600004 2014-04-06 18:40:00,34.657772410700005 2014-04-06 18:45:00,30.5688219408 2014-04-06 18:50:00,31.214622642800002 2014-04-06 18:55:00,33.0251968431 2014-04-06 19:00:00,21.638085306399997 2014-04-06 19:05:00,24.089669691599997 2014-04-06 19:10:00,20.641951455799997 2014-04-06 19:15:00,20.3301592346 2014-04-06 19:20:00,21.0940170491 2014-04-06 19:25:00,21.4416720701 2014-04-06 19:30:00,20.665909995299998 2014-04-06 19:35:00,20.454292001400002 2014-04-06 19:40:00,23.545121264899997 2014-04-06 19:45:00,20.895957868900002 2014-04-06 19:50:00,24.25437012130001 2014-04-06 19:55:00,21.8086372869 2014-04-06 20:00:00,21.1788011425 2014-04-06 20:05:00,19.3552468298 2014-04-06 20:10:00,19.4163618267 2014-04-06 20:15:00,20.7860086455 2014-04-06 20:20:00,20.7283931727 2014-04-06 20:25:00,21.580714659 2014-04-06 20:30:00,21.5360030417 2014-04-06 20:35:00,21.1791368299 2014-04-06 20:40:00,20.2716385546 2014-04-06 20:45:00,22.080062757199997 2014-04-06 20:50:00,20.9820812442 2014-04-06 20:55:00,22.4878527471 2014-04-06 21:00:00,21.37961112 2014-04-06 21:05:00,18.2644899487 2014-04-06 21:10:00,19.3749309839 2014-04-06 21:15:00,20.3848828298 2014-04-06 21:20:00,20.9861303153 2014-04-06 21:25:00,20.2983124022 2014-04-06 21:30:00,21.246015342 2014-04-06 21:35:00,19.2224495525 2014-04-06 21:40:00,18.8255792703 2014-04-06 21:45:00,18.3031018907 2014-04-06 21:50:00,20.3906625523 2014-04-06 21:55:00,20.8540191425 2014-04-06 22:00:00,19.3231312739 2014-04-06 22:05:00,20.4739728926 2014-04-06 22:10:00,18.2261091982 2014-04-06 22:15:00,18.4148346626 2014-04-06 22:20:00,20.8269938171 2014-04-06 22:25:00,19.490972199 2014-04-06 22:30:00,20.7051940369 2014-04-06 22:35:00,21.3473582797 2014-04-06 22:40:00,21.4310438095 2014-04-06 22:45:00,18.7066116964 2014-04-06 22:50:00,19.9642896162 2014-04-06 22:55:00,20.9558051629 2014-04-06 23:00:00,21.0999728001 2014-04-06 23:05:00,21.142762552 2014-04-06 23:10:00,18.9163005682 2014-04-06 23:15:00,18.7737431358 2014-04-06 23:20:00,20.3639590007 2014-04-06 23:25:00,20.968368342799998 2014-04-06 23:30:00,19.2802591594 2014-04-06 23:35:00,18.4223570392 2014-04-06 23:40:00,20.8709919908 2014-04-06 23:45:00,19.2024774916 2014-04-06 23:50:00,18.669034662 2014-04-06 23:55:00,18.594463563399998 2014-04-07 00:00:00,19.2596381901 2014-04-07 00:05:00,20.3707122637 2014-04-07 00:10:00,19.4336089548 2014-04-07 00:15:00,18.0826474064 2014-04-07 00:20:00,18.3876337387 2014-04-07 00:25:00,19.1620129888 2014-04-07 00:30:00,20.638817928599998 2014-04-07 00:35:00,18.3940602939 2014-04-07 00:40:00,20.242627414 2014-04-07 00:45:00,18.4795434833 2014-04-07 00:50:00,18.846461309400002 2014-04-07 00:55:00,18.6887541102 2014-04-07 01:00:00,18.2689145423 2014-04-07 01:05:00,20.6853192695 2014-04-07 01:10:00,19.8536141895 2014-04-07 01:15:00,21.3242137636 2014-04-07 01:20:00,18.3955633599 2014-04-07 01:25:00,18.578931733399997 2014-04-07 01:30:00,19.2258309254 2014-04-07 01:35:00,21.0634639478 2014-04-07 01:40:00,19.2230352926 2014-04-07 01:45:00,19.63367483 2014-04-07 01:50:00,19.2064142652 2014-04-07 01:55:00,18.320897167200002 2014-04-07 02:00:00,21.757734491599997 2014-04-07 02:05:00,20.1941559683 2014-04-07 02:10:00,21.1513327527 2014-04-07 02:15:00,20.6334283687 2014-04-07 02:20:00,20.057017116199997 2014-04-07 02:25:00,18.3587130266 2014-04-07 02:30:00,20.5709341811 2014-04-07 02:35:00,18.6214814237 2014-04-07 02:40:00,19.6575326774 2014-04-07 02:45:00,20.5164525739 2014-04-07 02:50:00,21.128916001900002 2014-04-07 02:55:00,20.7401807028 2014-04-07 03:00:00,20.686134116199998 2014-04-07 03:05:00,18.596168836700002 2014-04-07 03:10:00,19.3845141603 2014-04-07 03:15:00,18.1716490906 2014-04-07 03:20:00,20.8779075727 2014-04-07 03:25:00,21.810343925300003 2014-04-07 03:30:00,19.056441560699998 2014-04-07 03:35:00,18.3507868366 2014-04-07 03:40:00,19.902280307 2014-04-07 03:45:00,21.4267928925 2014-04-07 03:50:00,20.2078967811 2014-04-07 03:55:00,18.1871086008 2014-04-07 04:00:00,21.8970889621 2014-04-07 04:05:00,21.3145996399 2014-04-07 04:10:00,18.5263763082 2014-04-07 04:15:00,21.687191026 2014-04-07 04:20:00,19.8027531544 2014-04-07 04:25:00,19.4875919623 2014-04-07 04:30:00,19.8442133221 2014-04-07 04:35:00,21.3382878275 2014-04-07 04:40:00,20.6379187131 2014-04-07 04:45:00,18.2369938096 2014-04-07 04:50:00,21.8304174845 2014-04-07 04:55:00,18.591136533900002 2014-04-07 05:00:00,20.982271806900002 2014-04-07 05:05:00,20.5445461217 2014-04-07 05:10:00,18.7501121918 2014-04-07 05:15:00,18.6829283045 2014-04-07 05:20:00,21.4813103748 2014-04-07 05:25:00,19.678779694 2014-04-07 05:30:00,20.6183060567 2014-04-07 05:35:00,20.0162840154 2014-04-07 05:40:00,20.9094140683 2014-04-07 05:45:00,19.9169695002 2014-04-07 05:50:00,19.149519661 2014-04-07 05:55:00,19.453533484 2014-04-07 06:00:00,21.4363107778 2014-04-07 06:05:00,19.8721387717 2014-04-07 06:10:00,18.853797329000002 2014-04-07 06:15:00,21.7384215523 2014-04-07 06:20:00,21.186401825999997 2014-04-07 06:25:00,18.2226645842 2014-04-07 06:30:00,21.9957718479 2014-04-07 06:35:00,20.7797067858 2014-04-07 06:40:00,18.6410663962 2014-04-07 06:45:00,18.9486707252 2014-04-07 06:50:00,20.769781925 2014-04-07 06:55:00,21.119044221099998 2014-04-07 07:00:00,18.9561437726 2014-04-07 07:05:00,19.0278754156 2014-04-07 07:10:00,19.228482779500002 2014-04-07 07:15:00,20.3920734593 2014-04-07 07:20:00,18.687264713199998 2014-04-07 07:25:00,18.416972795499998 2014-04-07 07:30:00,20.715456356300002 2014-04-07 07:35:00,21.1163917592 2014-04-07 07:40:00,20.0037176177 2014-04-07 07:45:00,19.4553308411 2014-04-07 07:50:00,19.7281708541 2014-04-07 07:55:00,19.5536313355 2014-04-07 08:00:00,21.839939633 2014-04-07 08:05:00,21.0723596209 2014-04-07 08:10:00,18.8323488594 2014-04-07 08:15:00,19.5367566082 2014-04-07 08:20:00,20.1760491655 2014-04-07 08:25:00,20.4519434483 2014-04-07 08:30:00,19.872735584100003 2014-04-07 08:35:00,21.24050654 2014-04-07 08:40:00,21.0704240778 2014-04-07 08:45:00,20.0206316745 2014-04-07 08:50:00,21.4177175471 2014-04-07 08:55:00,21.0043581218 2014-04-07 09:00:00,71.7887131426 2014-04-07 09:05:00,74.2070506003 2014-04-07 09:10:00,64.8239504004 2014-04-07 09:15:00,64.8400150082 2014-04-07 09:20:00,73.2897506774 2014-04-07 09:25:00,71.702278678 2014-04-07 09:30:00,73.8010193635 2014-04-07 09:35:00,62.0585701804 2014-04-07 09:40:00,69.73749625079999 2014-04-07 09:45:00,63.166945398500005 2014-04-07 09:50:00,68.0530018968 2014-04-07 09:55:00,63.3181582732 2014-04-07 10:00:00,71.8277784594 2014-04-07 10:05:00,70.0288527203 2014-04-07 10:10:00,79.6213063682 2014-04-07 10:15:00,75.41203101100001 2014-04-07 10:20:00,71.47252218130002 2014-04-07 10:25:00,74.8504423104 2014-04-07 10:30:00,72.4620122993 2014-04-07 10:35:00,84.4551037849 2014-04-07 10:40:00,74.806475827 2014-04-07 10:45:00,75.0229586815 2014-04-07 10:50:00,82.8745962128 2014-04-07 10:55:00,79.8931694152 2014-04-07 11:00:00,82.8625692441 2014-04-07 11:05:00,81.68297269060001 2014-04-07 11:10:00,86.6163056999 2014-04-07 11:15:00,74.86014122510001 2014-04-07 11:20:00,87.2976801009 2014-04-07 11:25:00,84.7835270479 2014-04-07 11:30:00,80.9350200535 2014-04-07 11:35:00,82.10235831439999 2014-04-07 11:40:00,81.88692673989999 2014-04-07 11:45:00,72.4967335474 2014-04-07 11:50:00,75.03533439270001 2014-04-07 11:55:00,86.8592329475 2014-04-07 12:00:00,80.4531710647 2014-04-07 12:05:00,77.959993263 2014-04-07 12:10:00,84.0915842757 2014-04-07 12:15:00,80.2958323188 2014-04-07 12:20:00,72.1239516177 2014-04-07 12:25:00,83.67926578560001 2014-04-07 12:30:00,83.6150223837 2014-04-07 12:35:00,74.5528085385 2014-04-07 12:40:00,87.2017935411 2014-04-07 12:45:00,75.4918310685 2014-04-07 12:50:00,79.2288010903 2014-04-07 12:55:00,73.7471724497 2014-04-07 13:00:00,81.6329205071 2014-04-07 13:05:00,77.9884961886 2014-04-07 13:10:00,77.63213920930001 2014-04-07 13:15:00,85.2111744443 2014-04-07 13:20:00,72.1356706886 2014-04-07 13:25:00,84.74680421869998 2014-04-07 13:30:00,81.12370268949999 2014-04-07 13:35:00,87.7565095974 2014-04-07 13:40:00,81.41154806770001 2014-04-07 13:45:00,72.8685734905 2014-04-07 13:50:00,72.792850745 2014-04-07 13:55:00,86.10977647450001 2014-04-07 14:00:00,85.4553242757 2014-04-07 14:05:00,77.53051956569999 2014-04-07 14:10:00,81.884589098 2014-04-07 14:15:00,79.8296297067 2014-04-07 14:20:00,87.4704261002 2014-04-07 14:25:00,87.1951888441 2014-04-07 14:30:00,87.7372125483 2014-04-07 14:35:00,85.8590590575 2014-04-07 14:40:00,86.5486709168 2014-04-07 14:45:00,75.4728375902 2014-04-07 14:50:00,85.2920144106 2014-04-07 14:55:00,83.337713409 2014-04-07 15:00:00,87.4037450572 2014-04-07 15:05:00,81.1394103093 2014-04-07 15:10:00,73.36197038569999 2014-04-07 15:15:00,81.55759929850001 2014-04-07 15:20:00,82.9844981895 2014-04-07 15:25:00,75.5244114181 2014-04-07 15:30:00,78.3050624004 2014-04-07 15:35:00,81.5752714947 2014-04-07 15:40:00,77.9849431344 2014-04-07 15:45:00,77.99841468380002 2014-04-07 15:50:00,74.12867458470001 2014-04-07 15:55:00,87.0511118705 2014-04-07 16:00:00,84.0077488567 2014-04-07 16:05:00,72.0197567437 2014-04-07 16:10:00,84.24965078470001 2014-04-07 16:15:00,83.836558916 2014-04-07 16:20:00,72.1555568236 2014-04-07 16:25:00,77.9135191676 2014-04-07 16:30:00,81.7078061659 2014-04-07 16:35:00,79.2438582812 2014-04-07 16:40:00,84.4476157598 2014-04-07 16:45:00,78.8071820121 2014-04-07 16:50:00,74.4616645446 2014-04-07 16:55:00,87.62248175290001 2014-04-07 17:00:00,75.87261074930001 2014-04-07 17:05:00,83.4830449112 2014-04-07 17:10:00,74.2904724591 2014-04-07 17:15:00,77.2641721511 2014-04-07 17:20:00,79.0724113711 2014-04-07 17:25:00,75.07568324340001 2014-04-07 17:30:00,79.1993228093 2014-04-07 17:35:00,74.5145765543 2014-04-07 17:40:00,80.9440735412 2014-04-07 17:45:00,82.61938031449999 2014-04-07 17:50:00,72.9989205129 2014-04-07 17:55:00,85.9380809371 2014-04-07 18:00:00,29.9848959072 2014-04-07 18:05:00,30.242313715500003 2014-04-07 18:10:00,33.0326326343 2014-04-07 18:15:00,31.8000006812 2014-04-07 18:20:00,31.9961256914 2014-04-07 18:25:00,29.6201862141 2014-04-07 18:30:00,33.9567027403 2014-04-07 18:35:00,32.7491408872 2014-04-07 18:40:00,29.6664393812 2014-04-07 18:45:00,31.1935899598 2014-04-07 18:50:00,33.9866170441 2014-04-07 18:55:00,32.437466066300004 2014-04-07 19:00:00,20.6467453979 2014-04-07 19:05:00,21.8300399676 2014-04-07 19:10:00,21.247269739500002 2014-04-07 19:15:00,22.4782444473 2014-04-07 19:20:00,23.9382565442 2014-04-07 19:25:00,22.114475550799998 2014-04-07 19:30:00,22.1013710836 2014-04-07 19:35:00,24.215970714 2014-04-07 19:40:00,22.7413094005 2014-04-07 19:45:00,22.696534826500002 2014-04-07 19:50:00,21.3333551453 2014-04-07 19:55:00,22.882596655 2014-04-07 20:00:00,20.7909290251 2014-04-07 20:05:00,20.0575033818 2014-04-07 20:10:00,22.489888768 2014-04-07 20:15:00,22.0442251279 2014-04-07 20:20:00,21.502305186100006 2014-04-07 20:25:00,20.6329672825 2014-04-07 20:30:00,20.3245967047 2014-04-07 20:35:00,19.1893395006 2014-04-07 20:40:00,19.6843004574 2014-04-07 20:45:00,21.6021431769 2014-04-07 20:50:00,20.2905554718 2014-04-07 20:55:00,22.045775675300003 2014-04-07 21:00:00,18.680884393499998 2014-04-07 21:05:00,20.1295485991 2014-04-07 21:10:00,20.6866844266 2014-04-07 21:15:00,20.1637172663 2014-04-07 21:20:00,21.660380669699997 2014-04-07 21:25:00,22.0636526884 2014-04-07 21:30:00,18.5519626134 2014-04-07 21:35:00,18.608714705 2014-04-07 21:40:00,18.6101986317 2014-04-07 21:45:00,20.8241869336 2014-04-07 21:50:00,19.5842597151 2014-04-07 21:55:00,21.0337382351 2014-04-07 22:00:00,19.6407228924 2014-04-07 22:05:00,20.5301168851 2014-04-07 22:10:00,21.0996682671 2014-04-07 22:15:00,20.2122487818 2014-04-07 22:20:00,20.177366045699998 2014-04-07 22:25:00,18.3705561119 2014-04-07 22:30:00,19.6619843639 2014-04-07 22:35:00,20.202484387200002 2014-04-07 22:40:00,19.8669772993 2014-04-07 22:45:00,21.623866993000004 2014-04-07 22:50:00,21.6468835955 2014-04-07 22:55:00,21.3081056746 2014-04-07 23:00:00,19.5049365285 2014-04-07 23:05:00,20.873203490399998 2014-04-07 23:10:00,19.5849134239 2014-04-07 23:15:00,18.9340090259 2014-04-07 23:20:00,19.3753299215 2014-04-07 23:25:00,18.2873690322 2014-04-07 23:30:00,19.3308208392 2014-04-07 23:35:00,19.8467787171 2014-04-07 23:40:00,21.8261133863 2014-04-07 23:45:00,19.2573390423 2014-04-07 23:50:00,21.613963239 2014-04-07 23:55:00,18.9190648646 2014-04-08 00:00:00,18.763875590999998 2014-04-08 00:05:00,20.075981825699998 2014-04-08 00:10:00,20.6900454772 2014-04-08 00:15:00,18.1773290032 2014-04-08 00:20:00,18.8842634602 2014-04-08 00:25:00,19.822734666 2014-04-08 00:30:00,19.3240173439 2014-04-08 00:35:00,20.8504843174 2014-04-08 00:40:00,20.0446423842 2014-04-08 00:45:00,18.6414364224 2014-04-08 00:50:00,21.5778615173 2014-04-08 00:55:00,19.171622701900002 2014-04-08 01:00:00,20.9245244359 2014-04-08 01:05:00,21.1196631164 2014-04-08 01:10:00,21.852630801 2014-04-08 01:15:00,19.9940298661 2014-04-08 01:20:00,20.4633420619 2014-04-08 01:25:00,19.3395051739 2014-04-08 01:30:00,20.712717173599998 2014-04-08 01:35:00,19.8535339435 2014-04-08 01:40:00,19.7506094589 2014-04-08 01:45:00,21.421870116500003 2014-04-08 01:50:00,18.200675374 2014-04-08 01:55:00,21.5278497113 2014-04-08 02:00:00,21.408279351300003 2014-04-08 02:05:00,20.0254650142 2014-04-08 02:10:00,19.960811416800002 2014-04-08 02:15:00,19.447229472100002 2014-04-08 02:20:00,21.9766951667 2014-04-08 02:25:00,18.444677330999998 2014-04-08 02:30:00,20.3608609425 2014-04-08 02:35:00,20.7267263604 2014-04-08 02:40:00,21.7373200329 2014-04-08 02:45:00,21.120813987400002 2014-04-08 02:50:00,20.5753888112 2014-04-08 02:55:00,18.4672492672 2014-04-08 03:00:00,19.4949340673 2014-04-08 03:05:00,18.5553665702 2014-04-08 03:10:00,21.524850929899998 2014-04-08 03:15:00,20.9984846223 2014-04-08 03:20:00,21.0301471472 2014-04-08 03:25:00,20.6090260711 2014-04-08 03:30:00,20.0281741477 2014-04-08 03:35:00,18.5998842379 2014-04-08 03:40:00,19.318779546800002 2014-04-08 03:45:00,18.5476631699 2014-04-08 03:50:00,20.8996525714 2014-04-08 03:55:00,18.6409151041 2014-04-08 04:00:00,20.808454200699998 2014-04-08 04:05:00,20.7690215584 2014-04-08 04:10:00,19.837217916 2014-04-08 04:15:00,18.5409146165 2014-04-08 04:20:00,19.2592033045 2014-04-08 04:25:00,19.280372436300002 2014-04-08 04:30:00,20.8015405326 2014-04-08 04:35:00,18.4549720777 2014-04-08 04:40:00,21.3162745849 2014-04-08 04:45:00,21.0440291607 2014-04-08 04:50:00,18.7452276727 2014-04-08 04:55:00,20.8766575271 2014-04-08 05:00:00,20.674052725899998 2014-04-08 05:05:00,20.9924832004 2014-04-08 05:10:00,18.7557142218 2014-04-08 05:15:00,18.6303612886 2014-04-08 05:20:00,18.9459359437 2014-04-08 05:25:00,19.4634868126 2014-04-08 05:30:00,21.174659924100002 2014-04-08 05:35:00,20.9516957499 2014-04-08 05:40:00,21.701806369099998 2014-04-08 05:45:00,18.2345182364 2014-04-08 05:50:00,18.0462251241 2014-04-08 05:55:00,20.7965553188 2014-04-08 06:00:00,19.1171499832 2014-04-08 06:05:00,19.3363155821 2014-04-08 06:10:00,20.187208103699998 2014-04-08 06:15:00,18.4096524925 2014-04-08 06:20:00,20.570777666199998 2014-04-08 06:25:00,19.3005897849 2014-04-08 06:30:00,20.5308604972 2014-04-08 06:35:00,21.3360276523 2014-04-08 06:40:00,18.684445333299998 2014-04-08 06:45:00,21.7234923717 2014-04-08 06:50:00,20.122752564200002 2014-04-08 06:55:00,21.6917110607 2014-04-08 07:00:00,18.8309203288 2014-04-08 07:05:00,20.418250658399998 2014-04-08 07:10:00,19.615548469300002 2014-04-08 07:15:00,21.0968887646 2014-04-08 07:20:00,20.4236357729 2014-04-08 07:25:00,19.9780618278 2014-04-08 07:30:00,21.6519416257 2014-04-08 07:35:00,19.508468256700002 2014-04-08 07:40:00,18.8799208196 2014-04-08 07:45:00,20.4324047474 2014-04-08 07:50:00,20.496113748699997 2014-04-08 07:55:00,19.7563784863 2014-04-08 08:00:00,19.9464401748 2014-04-08 08:05:00,21.838213657199997 2014-04-08 08:10:00,20.930742765599998 2014-04-08 08:15:00,18.442407005899998 2014-04-08 08:20:00,18.848520283499997 2014-04-08 08:25:00,21.9023065377 2014-04-08 08:30:00,20.9058622152 2014-04-08 08:35:00,21.6601805046 2014-04-08 08:40:00,19.215445856 2014-04-08 08:45:00,20.9674674403 2014-04-08 08:50:00,20.8560108341 2014-04-08 08:55:00,19.1787599418 2014-04-08 09:00:00,68.6911020261 2014-04-08 09:05:00,69.7328455133 2014-04-08 09:10:00,67.7433926273 2014-04-08 09:15:00,72.4496304105 2014-04-08 09:20:00,72.5270189685 2014-04-08 09:25:00,72.7681674569 2014-04-08 09:30:00,72.12656053970001 2014-04-08 09:35:00,67.8379352899 2014-04-08 09:40:00,66.3875608548 2014-04-08 09:45:00,72.5067174585 2014-04-08 09:50:00,67.8667398364 2014-04-08 09:55:00,64.5506510213 2014-04-08 10:00:00,77.7139716216 2014-04-08 10:05:00,72.0415092362 2014-04-08 10:10:00,80.5740896941 2014-04-08 10:15:00,75.0534982908 2014-04-08 10:20:00,73.8854245519 2014-04-08 10:25:00,84.6850157416 2014-04-08 10:30:00,81.8971930542 2014-04-08 10:35:00,82.0553186823 2014-04-08 10:40:00,79.5201649632 2014-04-08 10:45:00,82.8639620191 2014-04-08 10:50:00,81.6222017077 2014-04-08 10:55:00,79.1329678882 2014-04-08 11:00:00,86.85372248700001 2014-04-08 11:05:00,74.61512607979999 2014-04-08 11:10:00,86.5715110509 2014-04-08 11:15:00,77.95247252840001 2014-04-08 11:20:00,79.971657432 2014-04-08 11:25:00,73.520046138 2014-04-08 11:30:00,80.15786870859999 2014-04-08 11:35:00,81.2886321816 2014-04-08 11:40:00,87.4354453209 2014-04-08 11:45:00,87.0774601057 2014-04-08 11:50:00,86.93758253 2014-04-08 11:55:00,77.1087637079 2014-04-08 12:00:00,87.75483166309998 2014-04-08 12:05:00,79.192505245 2014-04-08 12:10:00,85.526624884 2014-04-08 12:15:00,75.3705661609 2014-04-08 12:20:00,79.9972188775 2014-04-08 12:25:00,87.3512461058 2014-04-08 12:30:00,87.047919348 2014-04-08 12:35:00,82.8402303355 2014-04-08 12:40:00,84.6633111259 2014-04-08 12:45:00,74.7330397531 2014-04-08 12:50:00,83.4462809476 2014-04-08 12:55:00,81.7905463578 2014-04-08 13:00:00,73.4471962134 2014-04-08 13:05:00,73.7928295748 2014-04-08 13:10:00,73.7174014605 2014-04-08 13:15:00,83.5696494266 2014-04-08 13:20:00,74.24961914560001 2014-04-08 13:25:00,79.4646402459 2014-04-08 13:30:00,77.6930580839 2014-04-08 13:35:00,80.78867231640001 2014-04-08 13:40:00,83.2836309258 2014-04-08 13:45:00,82.935651261 2014-04-08 13:50:00,80.2290590582 2014-04-08 13:55:00,79.4102949319 2014-04-08 14:00:00,78.3612879996 2014-04-08 14:05:00,85.78644122600001 2014-04-08 14:10:00,77.2899187838 2014-04-08 14:15:00,76.1461979457 2014-04-08 14:20:00,83.8890210322 2014-04-08 14:25:00,77.7524830888 2014-04-08 14:30:00,85.5478711012 2014-04-08 14:35:00,77.2425116797 2014-04-08 14:40:00,83.2271220996 2014-04-08 14:45:00,72.7182534568 2014-04-08 14:50:00,78.1652539695 2014-04-08 14:55:00,77.4879631987 2014-04-08 15:00:00,85.0660431866 2014-04-08 15:05:00,87.4720467119 2014-04-08 15:10:00,79.37333843569999 2014-04-08 15:15:00,85.1965625396 2014-04-08 15:20:00,83.1943165422 2014-04-08 15:25:00,87.4773360121 2014-04-08 15:30:00,84.9769204432 2014-04-08 15:35:00,73.2389459548 2014-04-08 15:40:00,83.411706798 2014-04-08 15:45:00,80.567221994 2014-04-08 15:50:00,72.2622832023 2014-04-08 15:55:00,76.0202775379 2014-04-08 16:00:00,86.7479173641 2014-04-08 16:05:00,86.816815276 2014-04-08 16:10:00,84.7814445825 2014-04-08 16:15:00,87.70830525219999 2014-04-08 16:20:00,84.9045605769 2014-04-08 16:25:00,72.1631284431 2014-04-08 16:30:00,76.6052023626 2014-04-08 16:35:00,72.489847735 2014-04-08 16:40:00,73.5055863688 2014-04-08 16:45:00,75.5013081084 2014-04-08 16:50:00,80.0567830319 2014-04-08 16:55:00,85.5603477792 2014-04-08 17:00:00,85.7914351546 2014-04-08 17:05:00,81.859198303 2014-04-08 17:10:00,86.85078167430002 2014-04-08 17:15:00,80.0009665051 2014-04-08 17:20:00,86.2245435959 2014-04-08 17:25:00,79.2650136635 2014-04-08 17:30:00,76.4355707675 2014-04-08 17:35:00,86.66257341120001 2014-04-08 17:40:00,78.2069311794 2014-04-08 17:45:00,80.05443500060001 2014-04-08 17:50:00,77.261740452 2014-04-08 17:55:00,82.6053698842 2014-04-08 18:00:00,35.1681930877 2014-04-08 18:05:00,28.963281151799997 2014-04-08 18:10:00,34.5590206031 2014-04-08 18:15:00,28.825121230300002 2014-04-08 18:20:00,31.1310524622 2014-04-08 18:25:00,29.879077823499998 2014-04-08 18:30:00,33.6469809361 2014-04-08 18:35:00,29.123903789099998 2014-04-08 18:40:00,32.3422974932 2014-04-08 18:45:00,30.687521364600002 2014-04-08 18:50:00,29.6554838989 2014-04-08 18:55:00,33.7396300794 2014-04-08 19:00:00,21.1340262581 2014-04-08 19:05:00,21.1620637891 2014-04-08 19:10:00,21.3923428239 2014-04-08 19:15:00,22.788713851799997 2014-04-08 19:20:00,23.115302105900003 2014-04-08 19:25:00,20.2388581959 2014-04-08 19:30:00,21.2435748044 2014-04-08 19:35:00,22.0907481626 2014-04-08 19:40:00,21.6472555582 2014-04-08 19:45:00,24.1210832269 2014-04-08 19:50:00,23.688933814899997 2014-04-08 19:55:00,22.9639869059 2014-04-08 20:00:00,19.816621498099998 2014-04-08 20:05:00,21.3019536689 2014-04-08 20:10:00,21.887541038000002 2014-04-08 20:15:00,20.8684249752 2014-04-08 20:20:00,21.6451539087 2014-04-08 20:25:00,21.500333663899998 2014-04-08 20:30:00,20.7738357772 2014-04-08 20:35:00,19.7107022196 2014-04-08 20:40:00,21.486723461300002 2014-04-08 20:45:00,19.2790376853 2014-04-08 20:50:00,21.6247840077 2014-04-08 20:55:00,21.727422990300003 2014-04-08 21:00:00,21.3907646477 2014-04-08 21:05:00,19.987143821700002 2014-04-08 21:10:00,18.8600186557 2014-04-08 21:15:00,18.4872090482 2014-04-08 21:20:00,21.074117486400002 2014-04-08 21:25:00,21.648461703800002 2014-04-08 21:30:00,20.7022494812 2014-04-08 21:35:00,18.665808069100002 2014-04-08 21:40:00,21.8439357525 2014-04-08 21:45:00,22.0617987629 2014-04-08 21:50:00,19.8282352606 2014-04-08 21:55:00,20.4771217526 2014-04-08 22:00:00,21.1291786271 2014-04-08 22:05:00,20.9656668867 2014-04-08 22:10:00,21.8921450598 2014-04-08 22:15:00,18.477253506300002 2014-04-08 22:20:00,20.3424094381 2014-04-08 22:25:00,20.7876626851 2014-04-08 22:30:00,21.581091664099997 2014-04-08 22:35:00,21.5170750813 2014-04-08 22:40:00,21.9330346827 2014-04-08 22:45:00,20.0675601872 2014-04-08 22:50:00,21.343513578499998 2014-04-08 22:55:00,19.7280475846 2014-04-08 23:00:00,19.693035846500003 2014-04-08 23:05:00,19.0170440276 2014-04-08 23:10:00,21.2770335522 2014-04-08 23:15:00,21.9474735271 2014-04-08 23:20:00,19.029019782 2014-04-08 23:25:00,18.2280254594 2014-04-08 23:30:00,21.2662520842 2014-04-08 23:35:00,20.4848525448 2014-04-08 23:40:00,21.8429882487 2014-04-08 23:45:00,19.0126065942 2014-04-08 23:50:00,18.287621179400002 2014-04-08 23:55:00,19.9736032372 2014-04-09 00:00:00,18.3418640919 2014-04-09 00:05:00,19.047160004400002 2014-04-09 00:10:00,18.503911443299998 2014-04-09 00:15:00,18.8965287186 2014-04-09 00:20:00,18.4245786113 2014-04-09 00:25:00,21.8156239977 2014-04-09 00:30:00,19.1142508538 2014-04-09 00:35:00,19.775590344 2014-04-09 00:40:00,21.594447230500002 2014-04-09 00:45:00,20.7092863518 2014-04-09 00:50:00,20.4721499222 2014-04-09 00:55:00,20.8222527614 2014-04-09 01:00:00,21.3152890284 2014-04-09 01:05:00,21.5106770714 2014-04-09 01:10:00,20.5705586827 2014-04-09 01:15:00,21.5600290988 2014-04-09 01:20:00,20.1415901097 2014-04-09 01:25:00,19.1091634251 2014-04-09 01:30:00,21.5203068355 2014-04-09 01:35:00,20.1658913097 2014-04-09 01:40:00,21.6245503503 2014-04-09 01:45:00,18.1606712558 2014-04-09 01:50:00,19.590063006199998 2014-04-09 01:55:00,21.7912200734 2014-04-09 02:00:00,18.998600371 2014-04-09 02:05:00,21.7661449842 2014-04-09 02:10:00,21.8156098445 2014-04-09 02:15:00,21.5285692569 2014-04-09 02:20:00,20.2546721804 2014-04-09 02:25:00,20.5877577963 2014-04-09 02:30:00,21.478467993800002 2014-04-09 02:35:00,21.1035883296 2014-04-09 02:40:00,20.5203753978 2014-04-09 02:45:00,21.9290376315 2014-04-09 02:50:00,20.7427065453 2014-04-09 02:55:00,21.9019279698 2014-04-09 03:00:00,18.2295538984 2014-04-09 03:05:00,18.555841483 2014-04-09 03:10:00,19.805835384 2014-04-09 03:15:00,19.5395178435 2014-04-09 03:20:00,21.1309393654 2014-04-09 03:25:00,18.6424561059 2014-04-09 03:30:00,21.9043807164 2014-04-09 03:35:00,19.260263501 2014-04-09 03:40:00,19.715694831 2014-04-09 03:45:00,19.0989801298 2014-04-09 03:50:00,20.3174544693 2014-04-09 03:55:00,18.2345148017 2014-04-09 04:00:00,18.5987100223 2014-04-09 04:05:00,20.9831908137 2014-04-09 04:10:00,18.7460023336 2014-04-09 04:15:00,18.942057806199998 2014-04-09 04:20:00,21.1719289429 2014-04-09 04:25:00,18.3732047134 2014-04-09 04:30:00,19.7498952911 2014-04-09 04:35:00,18.092253548 2014-04-09 04:40:00,19.3872295973 2014-04-09 04:45:00,20.7959256104 2014-04-09 04:50:00,18.360413118900002 2014-04-09 04:55:00,21.5533385071 2014-04-09 05:00:00,21.637996171799998 2014-04-09 05:05:00,18.4199615005 2014-04-09 05:10:00,21.962929745500002 2014-04-09 05:15:00,19.190118213599998 2014-04-09 05:20:00,18.3364066845 2014-04-09 05:25:00,18.020268458 2014-04-09 05:30:00,19.6340915831 2014-04-09 05:35:00,20.5192399428 2014-04-09 05:40:00,19.3287169996 2014-04-09 05:45:00,21.3468694619 2014-04-09 05:50:00,20.8664251023 2014-04-09 05:55:00,19.4006461279 2014-04-09 06:00:00,20.937238666400003 2014-04-09 06:05:00,21.7619509479 2014-04-09 06:10:00,18.3723839942 2014-04-09 06:15:00,19.2244158406 2014-04-09 06:20:00,19.8533037565 2014-04-09 06:25:00,19.991960511 2014-04-09 06:30:00,20.1687825795 2014-04-09 06:35:00,19.2025076262 2014-04-09 06:40:00,20.6690385839 2014-04-09 06:45:00,20.5803380141 2014-04-09 06:50:00,20.3112860251 2014-04-09 06:55:00,18.4550468868 2014-04-09 07:00:00,19.9078715644 2014-04-09 07:05:00,19.42490755 2014-04-09 07:10:00,19.9641538794 2014-04-09 07:15:00,21.6874657421 2014-04-09 07:20:00,19.9221253726 2014-04-09 07:25:00,18.0559231674 2014-04-09 07:30:00,19.755346952300002 2014-04-09 07:35:00,21.2825927202 2014-04-09 07:40:00,21.1202436929 2014-04-09 07:45:00,20.053560294100002 2014-04-09 07:50:00,18.9990760514 2014-04-09 07:55:00,19.8603546517 2014-04-09 08:00:00,20.2548088777 2014-04-09 08:05:00,21.9994857531 2014-04-09 08:10:00,20.5767123607 2014-04-09 08:15:00,20.7770597203 2014-04-09 08:20:00,19.9658165743 2014-04-09 08:25:00,19.4179582031 2014-04-09 08:30:00,21.2518119346 2014-04-09 08:35:00,19.9797292974 2014-04-09 08:40:00,21.978760519899996 2014-04-09 08:45:00,19.8284822971 2014-04-09 08:50:00,18.2720011346 2014-04-09 08:55:00,20.7303125484 2014-04-09 09:00:00,61.83432373260001 2014-04-09 09:05:00,64.6068217176 2014-04-09 09:10:00,66.0108402378 2014-04-09 09:15:00,71.2569767645 2014-04-09 09:20:00,67.9216085991 2014-04-09 09:25:00,61.5895846658 2014-04-09 09:30:00,69.58915797739999 2014-04-09 09:35:00,66.795532829 2014-04-09 09:40:00,73.7369493356 2014-04-09 09:45:00,67.9940474315 2014-04-09 09:50:00,70.8420619848 2014-04-09 09:55:00,64.1766114957 2014-04-09 10:00:00,81.6503097215 2014-04-09 10:05:00,81.0292264187 2014-04-09 10:10:00,83.8713481166 2014-04-09 10:15:00,70.3649118795 2014-04-09 10:20:00,76.785210827 2014-04-09 10:25:00,80.38049185050001 2014-04-09 10:30:00,71.3169437292 2014-04-09 10:35:00,76.21257512220001 2014-04-09 10:40:00,84.4621152796 2014-04-09 10:45:00,76.60570329859999 2014-04-09 10:50:00,85.1334822396 2014-04-09 10:55:00,70.722142228 2014-04-09 11:00:00,82.9843647597 2014-04-09 11:05:00,80.8084822213 2014-04-09 11:10:00,79.5285830251 2014-04-09 11:15:00,87.0083570732 2014-04-09 11:20:00,73.62995996939999 2014-04-09 11:25:00,85.8179673275 2014-04-09 11:30:00,82.5614874987 2014-04-09 11:35:00,75.68707354979999 2014-04-09 11:40:00,85.9081460921 2014-04-09 11:45:00,78.3955063737 2014-04-09 11:50:00,84.5174714257 2014-04-09 11:55:00,77.7520559671 2014-04-09 12:00:00,85.51215536699999 2014-04-09 12:05:00,82.087442616 2014-04-09 12:10:00,74.167638042 2014-04-09 12:15:00,82.2957370828 2014-04-09 12:20:00,74.9714423838 2014-04-09 12:25:00,78.4964531319 2014-04-09 12:30:00,74.6350596728 2014-04-09 12:35:00,72.2654351413 2014-04-09 12:40:00,75.2997164096 2014-04-09 12:45:00,80.4852540367 2014-04-09 12:50:00,79.60932951390001 2014-04-09 12:55:00,79.9279247843 2014-04-09 13:00:00,75.9447589375 2014-04-09 13:05:00,82.9426681908 2014-04-09 13:10:00,83.24822821810001 2014-04-09 13:15:00,77.7088306125 2014-04-09 13:20:00,86.0780577224 2014-04-09 13:25:00,82.284618417 2014-04-09 13:30:00,83.3886103333 2014-04-09 13:35:00,76.4190937017 2014-04-09 13:40:00,71.9925038138 2014-04-09 13:45:00,85.82540675130002 2014-04-09 13:50:00,85.1383520436 2014-04-09 13:55:00,73.95331715180001 2014-04-09 14:00:00,77.9819388466 2014-04-09 14:05:00,82.5774650256 2014-04-09 14:10:00,82.42981689439999 2014-04-09 14:15:00,85.7614886079 2014-04-09 14:20:00,74.2407268602 2014-04-09 14:25:00,78.8752497708 2014-04-09 14:30:00,73.5520600185 2014-04-09 14:35:00,78.2297687659 2014-04-09 14:40:00,72.2382515269 2014-04-09 14:45:00,86.36822316799999 2014-04-09 14:50:00,80.42884317949999 2014-04-09 14:55:00,85.59272752470001 2014-04-09 15:00:00,72.9577748147 2014-04-09 15:05:00,75.63860363 2014-04-09 15:10:00,76.1493488828 2014-04-09 15:15:00,78.1863133184 2014-04-09 15:20:00,84.84504743810001 2014-04-09 15:25:00,78.1841754044 2014-04-09 15:30:00,75.2737338396 2014-04-09 15:35:00,73.0391429829 2014-04-09 15:40:00,73.2711645637 2014-04-09 15:45:00,84.1599473521 2014-04-09 15:50:00,79.1160883348 2014-04-09 15:55:00,83.6180952106 2014-04-09 16:00:00,82.91643474840001 2014-04-09 16:05:00,74.1656569898 2014-04-09 16:10:00,74.28606431760001 2014-04-09 16:15:00,84.0853108028 2014-04-09 16:20:00,83.5401322984 2014-04-09 16:25:00,78.0483424169 2014-04-09 16:30:00,73.2386155949 2014-04-09 16:35:00,72.1934297355 2014-04-09 16:40:00,76.6103640992 2014-04-09 16:45:00,72.1474178541 2014-04-09 16:50:00,75.6810166298 2014-04-09 16:55:00,78.7118607163 2014-04-09 17:00:00,73.94262385100001 2014-04-09 17:05:00,73.6684158366 2014-04-09 17:10:00,86.3429658158 2014-04-09 17:15:00,81.3674892192 2014-04-09 17:20:00,86.9512575989 2014-04-09 17:25:00,77.53318884779999 2014-04-09 17:30:00,82.8342871889 2014-04-09 17:35:00,75.2750378883 2014-04-09 17:40:00,81.8934136294 2014-04-09 17:45:00,74.073343236 2014-04-09 17:50:00,72.033262566 2014-04-09 17:55:00,86.90447545120001 2014-04-09 18:00:00,32.3513177961 2014-04-09 18:05:00,34.7324135732 2014-04-09 18:10:00,30.9365158119 2014-04-09 18:15:00,30.897824910300002 2014-04-09 18:20:00,31.3641859894 2014-04-09 18:25:00,33.318655900100005 2014-04-09 18:30:00,32.4211690339 2014-04-09 18:35:00,34.7222647388 2014-04-09 18:40:00,28.9628162064 2014-04-09 18:45:00,33.3324476032 2014-04-09 18:50:00,30.914091276399997 2014-04-09 18:55:00,29.9534896206 2014-04-09 19:00:00,22.4465711575 2014-04-09 19:05:00,22.4226845231 2014-04-09 19:10:00,20.7738082689 2014-04-09 19:15:00,21.064493175899997 2014-04-09 19:20:00,21.9885764925 2014-04-09 19:25:00,21.991473921100006 2014-04-09 19:30:00,21.5826592815 2014-04-09 19:35:00,20.825481136300002 2014-04-09 19:40:00,20.1795929754 2014-04-09 19:45:00,24.506651735300004 2014-04-09 19:50:00,24.3868752113 2014-04-09 19:55:00,22.326752473899997 2014-04-09 20:00:00,22.5077317113 2014-04-09 20:05:00,21.1912878846 2014-04-09 20:10:00,18.714040249500002 2014-04-09 20:15:00,18.9141735165 2014-04-09 20:20:00,22.184389750300003 2014-04-09 20:25:00,21.0126935679 2014-04-09 20:30:00,21.885679872199997 2014-04-09 20:35:00,22.111312219600002 2014-04-09 20:40:00,20.266770235 2014-04-09 20:45:00,18.6307620741 2014-04-09 20:50:00,19.203196078599998 2014-04-09 20:55:00,18.7046784717 2014-04-09 21:00:00,18.844983141700002 2014-04-09 21:05:00,19.7364138897 2014-04-09 21:10:00,18.5614565754 2014-04-09 21:15:00,18.756534223699997 2014-04-09 21:20:00,19.8782468579 2014-04-09 21:25:00,19.4536150362 2014-04-09 21:30:00,19.9660114839 2014-04-09 21:35:00,19.8113281655 2014-04-09 21:40:00,20.676686031400003 2014-04-09 21:45:00,21.8531521814 2014-04-09 21:50:00,18.5199283038 2014-04-09 21:55:00,18.485346346900002 2014-04-09 22:00:00,21.4317792093 2014-04-09 22:05:00,20.0448113721 2014-04-09 22:10:00,21.0858430792 2014-04-09 22:15:00,18.8797948253 2014-04-09 22:20:00,21.335913114500002 2014-04-09 22:25:00,21.7162140571 2014-04-09 22:30:00,20.5616523069 2014-04-09 22:35:00,18.4412026523 2014-04-09 22:40:00,21.6018971781 2014-04-09 22:45:00,21.1902740519 2014-04-09 22:50:00,21.023674466400003 2014-04-09 22:55:00,18.1643337829 2014-04-09 23:00:00,21.1999197022 2014-04-09 23:05:00,18.555365986400002 2014-04-09 23:10:00,18.8931714955 2014-04-09 23:15:00,20.312438577 2014-04-09 23:20:00,19.063582595 2014-04-09 23:25:00,20.649356738599998 2014-04-09 23:30:00,20.4362047869 2014-04-09 23:35:00,18.436137449100002 2014-04-09 23:40:00,20.6280181355 2014-04-09 23:45:00,21.699985234499998 2014-04-09 23:50:00,18.6480193513 2014-04-09 23:55:00,20.3921626254 2014-04-10 00:00:00,19.367461487699998 2014-04-10 00:05:00,19.8384466871 2014-04-10 00:10:00,19.1480007163 2014-04-10 00:15:00,19.4165225454 2014-04-10 00:20:00,18.1156472931 2014-04-10 00:25:00,21.9262069517 2014-04-10 00:30:00,20.4991996883 2014-04-10 00:35:00,20.002822362 2014-04-10 00:40:00,19.534861398 2014-04-10 00:45:00,20.1574982353 2014-04-10 00:50:00,19.5204239949 2014-04-10 00:55:00,19.43963171 2014-04-10 01:00:00,19.8557861669 2014-04-10 01:05:00,19.1039321347 2014-04-10 01:10:00,18.7201995999 2014-04-10 01:15:00,20.2264235927 2014-04-10 01:20:00,21.3710617446 2014-04-10 01:25:00,18.6113127109 2014-04-10 01:30:00,18.1309373624 2014-04-10 01:35:00,18.9872469806 2014-04-10 01:40:00,21.9188825738 2014-04-10 01:45:00,21.315032295 2014-04-10 01:50:00,20.3834642141 2014-04-10 01:55:00,21.716995661 2014-04-10 02:00:00,19.7811164673 2014-04-10 02:05:00,21.9331224103 2014-04-10 02:10:00,19.1852081805 2014-04-10 02:15:00,18.9612229981 2014-04-10 02:20:00,20.5521928046 2014-04-10 02:25:00,19.5126158718 2014-04-10 02:30:00,20.5054621679 2014-04-10 02:35:00,19.2199820732 2014-04-10 02:40:00,20.4716730274 2014-04-10 02:45:00,19.1029850423 2014-04-10 02:50:00,18.2038882753 2014-04-10 02:55:00,21.6485436077 2014-04-10 03:00:00,21.5328208075 2014-04-10 03:05:00,21.8831925971 2014-04-10 03:10:00,20.8661087049 2014-04-10 03:15:00,20.7308847109 2014-04-10 03:20:00,20.2360122803 2014-04-10 03:25:00,18.5037696654 2014-04-10 03:30:00,18.7569412438 2014-04-10 03:35:00,19.1578787547 2014-04-10 03:40:00,21.5606254503 2014-04-10 03:45:00,18.6918780984 2014-04-10 03:50:00,21.691492698 2014-04-10 03:55:00,20.0911429322 2014-04-10 04:00:00,20.8622785419 2014-04-10 04:05:00,18.440977946700002 2014-04-10 04:10:00,19.0761341951 2014-04-10 04:15:00,21.8340744327 2014-04-10 04:20:00,19.0645997877 2014-04-10 04:25:00,19.1860868816 2014-04-10 04:30:00,18.7903895394 2014-04-10 04:35:00,18.5162946612 2014-04-10 04:40:00,18.9330305658 2014-04-10 04:45:00,20.5693075678 2014-04-10 04:50:00,19.821470934 2014-04-10 04:55:00,20.2150233454 2014-04-10 05:00:00,18.4894593151 2014-04-10 05:05:00,21.2084657887 2014-04-10 05:10:00,21.1363788023 2014-04-10 05:15:00,18.0863596446 2014-04-10 05:20:00,19.534060378 2014-04-10 05:25:00,18.2750824079 2014-04-10 05:30:00,21.1684231177 2014-04-10 05:35:00,20.9490787325 2014-04-10 05:40:00,21.607952377199997 2014-04-10 05:45:00,18.945615835799998 2014-04-10 05:50:00,19.8251835325 2014-04-10 05:55:00,18.7379515087 2014-04-10 06:00:00,19.4849397379 2014-04-10 06:05:00,20.0889730063 2014-04-10 06:10:00,18.2133231594 2014-04-10 06:15:00,20.8594816427 2014-04-10 06:20:00,20.1731734415 2014-04-10 06:25:00,21.3158360688 2014-04-10 06:30:00,19.0871220048 2014-04-10 06:35:00,21.6132844211 2014-04-10 06:40:00,21.994777012100002 2014-04-10 06:45:00,21.6771937535 2014-04-10 06:50:00,21.111569903299998 2014-04-10 06:55:00,21.249475211500002 2014-04-10 07:00:00,20.2949769702 2014-04-10 07:05:00,18.7606154517 2014-04-10 07:10:00,20.7081627406 2014-04-10 07:15:00,20.851012008199998 2014-04-10 07:20:00,21.941540561100002 2014-04-10 07:25:00,20.165205265 2014-04-10 07:30:00,19.0854760601 2014-04-10 07:35:00,20.734690087 2014-04-10 07:40:00,21.9175032787 2014-04-10 07:45:00,18.7088556331 2014-04-10 07:50:00,19.3039916741 2014-04-10 07:55:00,20.1675238151 2014-04-10 08:00:00,18.6808585395 2014-04-10 08:05:00,18.0888825581 2014-04-10 08:10:00,19.3479324898 2014-04-10 08:15:00,21.461483206 2014-04-10 08:20:00,18.173873597300002 2014-04-10 08:25:00,19.7157162361 2014-04-10 08:30:00,21.0488030917 2014-04-10 08:35:00,21.812730387600002 2014-04-10 08:40:00,21.941901595999997 2014-04-10 08:45:00,19.6878775224 2014-04-10 08:50:00,21.8015371775 2014-04-10 08:55:00,18.1416758931 2014-04-10 09:00:00,71.3444703568 2014-04-10 09:05:00,69.941346071 2014-04-10 09:10:00,64.59349726319999 2014-04-10 09:15:00,68.0995316092 2014-04-10 09:20:00,62.961930833500006 2014-04-10 09:25:00,73.0537212529 2014-04-10 09:30:00,66.0674139634 2014-04-10 09:35:00,69.7142047983 2014-04-10 09:40:00,63.359357493500006 2014-04-10 09:45:00,64.003841887 2014-04-10 09:50:00,74.6906066429 2014-04-10 09:55:00,71.44197496439999 2014-04-10 10:00:00,84.7698034189 2014-04-10 10:05:00,74.4316100841 2014-04-10 10:10:00,72.3940158451 2014-04-10 10:15:00,77.6476225532 2014-04-10 10:20:00,77.51725174020001 2014-04-10 10:25:00,72.55516989350001 2014-04-10 10:30:00,81.2195677199 2014-04-10 10:35:00,75.4547873345 2014-04-10 10:40:00,72.73238838399999 2014-04-10 10:45:00,74.9923822833 2014-04-10 10:50:00,78.5879830183 2014-04-10 10:55:00,81.11482886739999 2014-04-10 11:00:00,79.2319926519 2014-04-10 11:05:00,79.92706271819999 2014-04-10 11:10:00,73.7777961652 2014-04-10 11:15:00,86.1152444666 2014-04-10 11:20:00,86.3384296449 2014-04-10 11:25:00,82.437216494 2014-04-10 11:30:00,71.8484099277 2014-04-10 11:35:00,80.1096283297 2014-04-10 11:40:00,81.5750985321 2014-04-10 11:45:00,87.3869807619 2014-04-10 11:50:00,87.40944885540002 2014-04-10 11:55:00,85.2074490866 2014-04-10 12:00:00,72.9336703174 2014-04-10 12:05:00,87.1477193458 2014-04-10 12:10:00,81.70441685850001 2014-04-10 12:15:00,84.7124113017 2014-04-10 12:20:00,78.42086749229999 2014-04-10 12:25:00,77.0221738859 2014-04-10 12:30:00,79.3166120401 2014-04-10 12:35:00,74.2607722169 2014-04-10 12:40:00,77.6198025502 2014-04-10 12:45:00,85.61901374029999 2014-04-10 12:50:00,72.5200791308 2014-04-10 12:55:00,74.3247518907 2014-04-10 13:00:00,73.9840981083 2014-04-10 13:05:00,78.4303808731 2014-04-10 13:10:00,87.93068198459999 2014-04-10 13:15:00,74.7557811889 2014-04-10 13:20:00,74.30988374020001 2014-04-10 13:25:00,86.6200978624 2014-04-10 13:30:00,86.0921411975 2014-04-10 13:35:00,72.4984421169 2014-04-10 13:40:00,84.007128812 2014-04-10 13:45:00,82.4676542353 2014-04-10 13:50:00,84.26362483289998 2014-04-10 13:55:00,79.89286038729999 2014-04-10 14:00:00,87.8578501159 2014-04-10 14:05:00,72.6980626249 2014-04-10 14:10:00,75.7463093851 2014-04-10 14:15:00,78.3409752443 2014-04-10 14:20:00,79.1926456356 2014-04-10 14:25:00,86.737714833 2014-04-10 14:30:00,80.95618374189999 2014-04-10 14:35:00,72.7182852831 2014-04-10 14:40:00,78.5220381761 2014-04-10 14:45:00,78.6600707333 2014-04-10 14:50:00,87.443657518 2014-04-10 14:55:00,81.58323727300001 2014-04-10 15:00:00,82.1696283025 2014-04-10 15:05:00,83.4112477444 2014-04-10 15:10:00,84.3198195729 2014-04-10 15:15:00,82.16002837939999 2014-04-10 15:20:00,75.7943819851 2014-04-10 15:25:00,85.983909176 2014-04-10 15:30:00,83.71311315300001 2014-04-10 15:35:00,83.86912261020001 2014-04-10 15:40:00,87.9440635566 2014-04-10 15:45:00,84.8396100897 2014-04-10 15:50:00,85.2656038928 2014-04-10 15:55:00,87.22165091549999 2014-04-10 16:00:00,74.4180011147 2014-04-10 16:05:00,79.9634844935 2014-04-10 16:10:00,81.2889163024 2014-04-10 16:15:00,77.2682633122 2014-04-10 16:20:00,85.4302894758 2014-04-10 16:25:00,84.1985522848 2014-04-10 16:30:00,83.5339688066 2014-04-10 16:35:00,87.95422216370001 2014-04-10 16:40:00,76.1499557663 2014-04-10 16:45:00,83.76715519359999 2014-04-10 16:50:00,80.82231641930001 2014-04-10 16:55:00,77.0076790649 2014-04-10 17:00:00,74.5693612969 2014-04-10 17:05:00,86.3341082408 2014-04-10 17:10:00,81.5272564168 2014-04-10 17:15:00,85.19890868590001 2014-04-10 17:20:00,80.7254887454 2014-04-10 17:25:00,75.5196042909 2014-04-10 17:30:00,77.4007512877 2014-04-10 17:35:00,78.1045914874 2014-04-10 17:40:00,87.5669233743 2014-04-10 17:45:00,72.0901047715 2014-04-10 17:50:00,87.77062266450001 2014-04-10 17:55:00,87.68735248979998 2014-04-10 18:00:00,35.1753583057 2014-04-10 18:05:00,31.850158229899996 2014-04-10 18:10:00,34.9683706916 2014-04-10 18:15:00,31.331828748099998 2014-04-10 18:20:00,28.9682788584 2014-04-10 18:25:00,30.2358161875 2014-04-10 18:30:00,34.8498892764 2014-04-10 18:35:00,28.888088490799998 2014-04-10 18:40:00,32.2943562662 2014-04-10 18:45:00,29.283844546399997 2014-04-10 18:50:00,30.6329322204 2014-04-10 18:55:00,29.363788606700002 2014-04-10 19:00:00,24.0106869054 2014-04-10 19:05:00,22.807995528000003 2014-04-10 19:10:00,24.2014356388 2014-04-10 19:15:00,23.2438210589 2014-04-10 19:20:00,24.510209163400003 2014-04-10 19:25:00,22.4442506621 2014-04-10 19:30:00,23.021422143400002 2014-04-10 19:35:00,22.741862265500004 2014-04-10 19:40:00,22.329485499 2014-04-10 19:45:00,23.9498966433 2014-04-10 19:50:00,23.0474713435 2014-04-10 19:55:00,23.7498776437 2014-04-10 20:00:00,21.652946424499998 2014-04-10 20:05:00,19.2145207475 2014-04-10 20:10:00,21.0950695761 2014-04-10 20:15:00,19.2497580556 2014-04-10 20:20:00,20.821280429 2014-04-10 20:25:00,21.206772213 2014-04-10 20:30:00,22.516674583 2014-04-10 20:35:00,18.5570997198 2014-04-10 20:40:00,18.8057286206 2014-04-10 20:45:00,18.7475011234 2014-04-10 20:50:00,20.0636875878 2014-04-10 20:55:00,21.7972256671 2014-04-10 21:00:00,21.4788311602 2014-04-10 21:05:00,21.0484683396 2014-04-10 21:10:00,21.6911329765 2014-04-10 21:15:00,19.3840386402 2014-04-10 21:20:00,18.4407111011 2014-04-10 21:25:00,18.3201286053 2014-04-10 21:30:00,21.5112917741 2014-04-10 21:35:00,21.0221695028 2014-04-10 21:40:00,20.8942745868 2014-04-10 21:45:00,19.4516270923 2014-04-10 21:50:00,19.6133148861 2014-04-10 21:55:00,21.9372498417 2014-04-10 22:00:00,18.2727439776 2014-04-10 22:05:00,21.1151780673 2014-04-10 22:10:00,19.2570022773 2014-04-10 22:15:00,18.173648434500002 2014-04-10 22:20:00,20.9904119019 2014-04-10 22:25:00,19.3421982349 2014-04-10 22:30:00,20.9086431112 2014-04-10 22:35:00,20.8506149151 2014-04-10 22:40:00,20.1584810734 2014-04-10 22:45:00,21.1297576193 2014-04-10 22:50:00,20.343664473900002 2014-04-10 22:55:00,19.1649280875 2014-04-10 23:00:00,20.9404810028 2014-04-10 23:05:00,20.3604677209 2014-04-10 23:10:00,18.0543748995 2014-04-10 23:15:00,21.6107251717 2014-04-10 23:20:00,20.1864495256 2014-04-10 23:25:00,21.478632165500002 2014-04-10 23:30:00,21.535081295700003 2014-04-10 23:35:00,19.7836643594 2014-04-10 23:40:00,20.034485866700003 2014-04-10 23:45:00,19.6667928481 2014-04-10 23:50:00,19.8015482667 2014-04-10 23:55:00,21.584732106799997 2014-04-11 00:00:00,21.1525760559 2014-04-11 00:05:00,18.5061027053 2014-04-11 00:10:00,20.441231126199998 2014-04-11 00:15:00,21.9836265615 2014-04-11 00:20:00,20.3822028049 2014-04-11 00:25:00,21.143486502400002 2014-04-11 00:30:00,21.076245893499998 2014-04-11 00:35:00,19.4012701035 2014-04-11 00:40:00,19.487397210799998 2014-04-11 00:45:00,20.8963056872 2014-04-11 00:50:00,19.9999341264 2014-04-11 00:55:00,20.282282836500002 2014-04-11 01:00:00,20.8516231615 2014-04-11 01:05:00,21.1103001082 2014-04-11 01:10:00,19.086066310899998 2014-04-11 01:15:00,18.5871750377 2014-04-11 01:20:00,19.1671785869 2014-04-11 01:25:00,20.0301533004 2014-04-11 01:30:00,19.3685652692 2014-04-11 01:35:00,20.2734510354 2014-04-11 01:40:00,18.2138628965 2014-04-11 01:45:00,20.0390016465 2014-04-11 01:50:00,19.4719396278 2014-04-11 01:55:00,20.1386670196 2014-04-11 02:00:00,19.6901334195 2014-04-11 02:05:00,19.1369034026 2014-04-11 02:10:00,21.616431621799997 2014-04-11 02:15:00,18.7390599537 2014-04-11 02:20:00,20.7254623023 2014-04-11 02:25:00,21.698578850300002 2014-04-11 02:30:00,20.154679838699998 2014-04-11 02:35:00,21.5056339543 2014-04-11 02:40:00,18.4994059137 2014-04-11 02:45:00,19.975155081 2014-04-11 02:50:00,19.8281011219 2014-04-11 02:55:00,18.0324752281 2014-04-11 03:00:00,19.7730293654 2014-04-11 03:05:00,19.4761190255 2014-04-11 03:10:00,20.679194911099998 2014-04-11 03:15:00,21.753319114299998 2014-04-11 03:20:00,18.343164353 2014-04-11 03:25:00,19.3099055469 2014-04-11 03:30:00,19.7762589496 2014-04-11 03:35:00,19.8207415121 2014-04-11 03:40:00,21.099238883399998 2014-04-11 03:45:00,19.7735826633 2014-04-11 03:50:00,18.1086452058 2014-04-11 03:55:00,20.8404163784 2014-04-11 04:00:00,21.5393187806 2014-04-11 04:05:00,20.0556188502 2014-04-11 04:10:00,20.3244340868 2014-04-11 04:15:00,18.6517457559 2014-04-11 04:20:00,18.8825837787 2014-04-11 04:25:00,18.9406809565 2014-04-11 04:30:00,19.722967899500002 2014-04-11 04:35:00,21.7125808836 2014-04-11 04:40:00,20.0871390669 2014-04-11 04:45:00,18.7683905808 2014-04-11 04:50:00,19.0643509435 2014-04-11 04:55:00,19.5360601189 2014-04-11 05:00:00,20.4930359028 2014-04-11 05:05:00,19.760132612 2014-04-11 05:10:00,19.5697793767 2014-04-11 05:15:00,20.258914401600002 2014-04-11 05:20:00,18.9673399798 2014-04-11 05:25:00,18.3156130903 2014-04-11 05:30:00,18.0976572593 2014-04-11 05:35:00,19.0050366539 2014-04-11 05:40:00,18.366368136600002 2014-04-11 05:45:00,19.3453625541 2014-04-11 05:50:00,21.0917341614 2014-04-11 05:55:00,20.8651773219 2014-04-11 06:00:00,20.443710491199997 2014-04-11 06:05:00,21.4100009755 2014-04-11 06:10:00,19.1282704982 2014-04-11 06:15:00,21.5402150121 2014-04-11 06:20:00,19.5969566787 2014-04-11 06:25:00,19.6035732731 2014-04-11 06:30:00,19.6214064545 2014-04-11 06:35:00,18.392377465 2014-04-11 06:40:00,21.9019619933 2014-04-11 06:45:00,18.5540271113 2014-04-11 06:50:00,19.3635428979 2014-04-11 06:55:00,19.2772012813 2014-04-11 07:00:00,18.298717731300002 2014-04-11 07:05:00,18.6090405204 2014-04-11 07:10:00,18.1794333447 2014-04-11 07:15:00,19.1696179742 2014-04-11 07:20:00,21.466627696099998 2014-04-11 07:25:00,19.3577688229 2014-04-11 07:30:00,18.4947673283 2014-04-11 07:35:00,20.5827754735 2014-04-11 07:40:00,21.986403648200003 2014-04-11 07:45:00,18.9292951581 2014-04-11 07:50:00,19.118284021500003 2014-04-11 07:55:00,21.8873882171 2014-04-11 08:00:00,18.7151051502 2014-04-11 08:05:00,20.0448562698 2014-04-11 08:10:00,18.9586085321 2014-04-11 08:15:00,21.729407591599998 2014-04-11 08:20:00,21.9260840583 2014-04-11 08:25:00,21.2587913845 2014-04-11 08:30:00,19.2591352633 2014-04-11 08:35:00,19.6139499011 2014-04-11 08:40:00,18.9692227347 2014-04-11 08:45:00,21.563031868000003 2014-04-11 08:50:00,21.658233110799998 2014-04-11 08:55:00,19.675482649 2014-04-11 09:00:00,127.882020134 2014-04-11 09:05:00,115.705718858 2014-04-11 09:10:00,122.386410329 2014-04-11 09:15:00,127.26117784600001 2014-04-11 09:20:00,121.15799733899999 2014-04-11 09:25:00,120.46846823700001 2014-04-11 09:30:00,111.62477500799999 2014-04-11 09:35:00,131.54647790200002 2014-04-11 09:40:00,133.655572778 2014-04-11 09:45:00,135.642695533 2014-04-11 09:50:00,129.43793035 2014-04-11 09:55:00,125.21004934700001 2014-04-11 10:00:00,138.118479694 2014-04-11 10:05:00,159.259712824 2014-04-11 10:10:00,147.399242667 2014-04-11 10:15:00,150.046221935 2014-04-11 10:20:00,150.08248245 2014-04-11 10:25:00,154.798492005 2014-04-11 10:30:00,130.600116725 2014-04-11 10:35:00,136.698351395 2014-04-11 10:40:00,149.593864645 2014-04-11 10:45:00,156.24342053799998 2014-04-11 10:50:00,150.16741112399998 2014-04-11 10:55:00,142.294707802 2014-04-11 11:00:00,144.83546133299998 2014-04-11 11:05:00,156.04894706299999 2014-04-11 11:10:00,156.146953473 2014-04-11 11:15:00,152.149471713 2014-04-11 11:20:00,142.74738558200002 2014-04-11 11:25:00,161.62621235 2014-04-11 11:30:00,150.505607236 2014-04-11 11:35:00,157.614348277 2014-04-11 11:40:00,140.448671746 2014-04-11 11:45:00,144.313663174 2014-04-11 11:50:00,160.119472952 2014-04-11 11:55:00,135.556788636 2014-04-11 12:00:00,150.160947021 2014-04-11 12:05:00,149.243925447 2014-04-11 12:10:00,157.318454491 2014-04-11 12:15:00,143.257886337 2014-04-11 12:20:00,141.37569147600001 2014-04-11 12:25:00,162.558258037 2014-04-11 12:30:00,151.940306437 2014-04-11 12:35:00,137.949131962 2014-04-11 12:40:00,140.595854562 2014-04-11 12:45:00,164.736030621 2014-04-11 12:50:00,140.67293255299998 2014-04-11 12:55:00,153.101669559 2014-04-11 13:00:00,147.562906904 2014-04-11 13:05:00,161.523164661 2014-04-11 13:10:00,157.611334766 2014-04-11 13:15:00,152.86613525200002 2014-04-11 13:20:00,135.284640106 2014-04-11 13:25:00,161.349096329 2014-04-11 13:30:00,148.298884492 2014-04-11 13:35:00,162.902138864 2014-04-11 13:40:00,149.824607501 2014-04-11 13:45:00,155.783518728 2014-04-11 13:50:00,137.04076296899999 2014-04-11 13:55:00,157.310909944 2014-04-11 14:00:00,145.131830514 2014-04-11 14:05:00,145.532697769 2014-04-11 14:10:00,138.551989898 2014-04-11 14:15:00,139.397982089 2014-04-11 14:20:00,140.56497458299998 2014-04-11 14:25:00,144.838150922 2014-04-11 14:30:00,161.750125145 2014-04-11 14:35:00,146.039706362 2014-04-11 14:40:00,156.722187857 2014-04-11 14:45:00,137.474799425 2014-04-11 14:50:00,152.72449239 2014-04-11 14:55:00,149.448447071 2014-04-11 15:00:00,164.336915344 2014-04-11 15:05:00,160.384453878 2014-04-11 15:10:00,148.643244206 2014-04-11 15:15:00,158.252527354 2014-04-11 15:20:00,140.789600396 2014-04-11 15:25:00,151.86840507600002 2014-04-11 15:30:00,137.23704923399998 2014-04-11 15:35:00,145.441057524 2014-04-11 15:40:00,141.774292682 2014-04-11 15:45:00,156.56555760700002 2014-04-11 15:50:00,149.701060034 2014-04-11 15:55:00,157.530366809 2014-04-11 16:00:00,150.458529311 2014-04-11 16:05:00,137.594227988 2014-04-11 16:10:00,157.060681026 2014-04-11 16:15:00,159.99652294 2014-04-11 16:20:00,162.10557711799999 2014-04-11 16:25:00,152.159420767 2014-04-11 16:30:00,157.607211091 2014-04-11 16:35:00,157.56098053 2014-04-11 16:40:00,139.672182907 2014-04-11 16:45:00,139.926310173 2014-04-11 16:50:00,137.126260936 2014-04-11 16:55:00,144.597088241 2014-04-11 17:00:00,149.205191425 2014-04-11 17:05:00,164.936862395 2014-04-11 17:10:00,147.929734621 2014-04-11 17:15:00,156.787208083 2014-04-11 17:20:00,155.801841654 2014-04-11 17:25:00,141.134395882 2014-04-11 17:30:00,136.755153861 2014-04-11 17:35:00,151.380135374 2014-04-11 17:40:00,156.009098543 2014-04-11 17:45:00,164.947480513 2014-04-11 17:50:00,145.758266891 2014-04-11 17:55:00,161.890865026 2014-04-11 18:00:00,44.9137655963 2014-04-11 18:05:00,47.7425739013 2014-04-11 18:10:00,46.9039133872 2014-04-11 18:15:00,41.8873927765 2014-04-11 18:20:00,42.121161338600004 2014-04-11 18:25:00,41.5910175894 2014-04-11 18:30:00,44.81166061020001 2014-04-11 18:35:00,48.26135568220001 2014-04-11 18:40:00,42.98933718399999 2014-04-11 18:45:00,46.973833715299996 2014-04-11 18:50:00,44.057202826499996 2014-04-11 18:55:00,48.7323180379 2014-04-11 19:00:00,26.703913769699998 2014-04-11 19:05:00,26.588086346399997 2014-04-11 19:10:00,25.325158233899998 2014-04-11 19:15:00,24.1142136711 2014-04-11 19:20:00,26.759595154 2014-04-11 19:25:00,23.6179443369 2014-04-11 19:30:00,24.1403858438 2014-04-11 19:35:00,23.607093944899997 2014-04-11 19:40:00,26.0780164532 2014-04-11 19:45:00,26.1386268201 2014-04-11 19:50:00,25.96864762 2014-04-11 19:55:00,24.774628775500002 2014-04-11 20:00:00,19.3575191084 2014-04-11 20:05:00,22.7702010354 2014-04-11 20:10:00,21.072531363299998 2014-04-11 20:15:00,20.6485384736 2014-04-11 20:20:00,21.4137746088 2014-04-11 20:25:00,19.7472616542 2014-04-11 20:30:00,19.4937647691 2014-04-11 20:35:00,20.6424496095 2014-04-11 20:40:00,19.8921441773 2014-04-11 20:45:00,19.9639730542 2014-04-11 20:50:00,22.6916877663 2014-04-11 20:55:00,21.169434081800002 2014-04-11 21:00:00,20.141188464200003 2014-04-11 21:05:00,20.9738006155 2014-04-11 21:10:00,22.032976740100004 2014-04-11 21:15:00,18.6406616199 2014-04-11 21:20:00,21.556013192800002 2014-04-11 21:25:00,20.547571809100003 2014-04-11 21:30:00,18.777941795 2014-04-11 21:35:00,19.3881585842 2014-04-11 21:40:00,20.136711794700002 2014-04-11 21:45:00,20.980661437000002 2014-04-11 21:50:00,19.1677204187 2014-04-11 21:55:00,20.3489661134 2014-04-11 22:00:00,20.7818229555 2014-04-11 22:05:00,19.8361365054 2014-04-11 22:10:00,21.496724197600003 2014-04-11 22:15:00,21.522510288200003 2014-04-11 22:20:00,19.9241210003 2014-04-11 22:25:00,21.9372375602 2014-04-11 22:30:00,18.3404092181 2014-04-11 22:35:00,18.0509174691 2014-04-11 22:40:00,19.5632801944 2014-04-11 22:45:00,20.4468293513 2014-04-11 22:50:00,20.5594755533 2014-04-11 22:55:00,19.9471869525 2014-04-11 23:00:00,18.5072290549 2014-04-11 23:05:00,18.689761791 2014-04-11 23:10:00,21.4174979051 2014-04-11 23:15:00,21.4805767265 2014-04-11 23:20:00,20.7042035142 2014-04-11 23:25:00,20.6654651434 2014-04-11 23:30:00,20.399211050799998 2014-04-11 23:35:00,18.8195292075 2014-04-11 23:40:00,19.721203406 2014-04-11 23:45:00,20.7922245701 2014-04-11 23:50:00,20.1573910715 2014-04-11 23:55:00,18.08184025 2014-04-12 00:00:00,21.8142272269 2014-04-12 00:05:00,21.3792642103 2014-04-12 00:10:00,19.0421800564 2014-04-12 00:15:00,20.465835740699998 2014-04-12 00:20:00,21.692957534899996 2014-04-12 00:25:00,18.384044048499998 2014-04-12 00:30:00,20.012117923199998 2014-04-12 00:35:00,19.8249721034 2014-04-12 00:40:00,19.640820021099998 2014-04-12 00:45:00,21.3423544356 2014-04-12 00:50:00,19.5225845868 2014-04-12 00:55:00,18.254653333 2014-04-12 01:00:00,18.2633509687 2014-04-12 01:05:00,18.1709784261 2014-04-12 01:10:00,19.6365816875 2014-04-12 01:15:00,20.8736251108 2014-04-12 01:20:00,18.814889847699998 2014-04-12 01:25:00,20.585874081700002 2014-04-12 01:30:00,20.7483538884 2014-04-12 01:35:00,19.0208084961 2014-04-12 01:40:00,20.4022306242 2014-04-12 01:45:00,20.7394733601 2014-04-12 01:50:00,19.8664544912 2014-04-12 01:55:00,19.3468663891 2014-04-12 02:00:00,20.4766062063 2014-04-12 02:05:00,21.911388349299997 2014-04-12 02:10:00,19.7073656375 2014-04-12 02:15:00,19.5669403851 2014-04-12 02:20:00,19.8570676097 2014-04-12 02:25:00,18.304873573800002 2014-04-12 02:30:00,20.2126531187 2014-04-12 02:35:00,19.314789548900002 2014-04-12 02:40:00,18.4856884893 2014-04-12 02:45:00,19.8650269645 2014-04-12 02:50:00,18.013535946300003 2014-04-12 02:55:00,19.6071409807 2014-04-12 03:00:00,18.422941071700002 2014-04-12 03:05:00,18.0971708136 2014-04-12 03:10:00,21.297900185 2014-04-12 03:15:00,21.6649952131 2014-04-12 03:20:00,18.830698593399998 2014-04-12 03:25:00,20.1571930553 2014-04-12 03:30:00,19.1118326285 2014-04-12 03:35:00,19.974309754700002 2014-04-12 03:40:00,19.7465252836 2014-04-12 03:45:00,19.0762042203 2014-04-12 03:50:00,20.8015743185 2014-04-12 03:55:00,18.5059638373 2014-04-12 04:00:00,18.2122911287 2014-04-12 04:05:00,21.0707017321 2014-04-12 04:10:00,20.6637201249 2014-04-12 04:15:00,19.994104496600002 2014-04-12 04:20:00,19.8711590819 2014-04-12 04:25:00,19.989645518 2014-04-12 04:30:00,19.7480963044 2014-04-12 04:35:00,19.5715691833 2014-04-12 04:40:00,19.9987624115 2014-04-12 04:45:00,20.114060684600002 2014-04-12 04:50:00,20.767609256300002 2014-04-12 04:55:00,20.8448286429 2014-04-12 05:00:00,19.5105163206 2014-04-12 05:05:00,19.654162091 2014-04-12 05:10:00,19.4947886789 2014-04-12 05:15:00,20.1461430945 2014-04-12 05:20:00,19.8134141517 2014-04-12 05:25:00,21.5583858525 2014-04-12 05:30:00,20.7854450677 2014-04-12 05:35:00,21.594625535 2014-04-12 05:40:00,20.836547966199998 2014-04-12 05:45:00,21.883968594099997 2014-04-12 05:50:00,20.542947113 2014-04-12 05:55:00,21.8542005527 2014-04-12 06:00:00,18.6326795616 2014-04-12 06:05:00,18.2099107233 2014-04-12 06:10:00,20.3165007408 2014-04-12 06:15:00,21.9339728232 2014-04-12 06:20:00,19.6704209892 2014-04-12 06:25:00,18.8481734488 2014-04-12 06:30:00,20.0861657968 2014-04-12 06:35:00,20.5951944983 2014-04-12 06:40:00,19.2607147821 2014-04-12 06:45:00,20.859077434 2014-04-12 06:50:00,21.900458028200003 2014-04-12 06:55:00,21.5878524868 2014-04-12 07:00:00,19.166341494 2014-04-12 07:05:00,19.3068947326 2014-04-12 07:10:00,19.4861648978 2014-04-12 07:15:00,19.5782111136 2014-04-12 07:20:00,18.4012779968 2014-04-12 07:25:00,21.0478513556 2014-04-12 07:30:00,19.4613570544 2014-04-12 07:35:00,21.519279906799998 2014-04-12 07:40:00,21.7077624925 2014-04-12 07:45:00,18.0977252372 2014-04-12 07:50:00,21.9540122797 2014-04-12 07:55:00,20.840090926 2014-04-12 08:00:00,20.081568904 2014-04-12 08:05:00,19.558110433499998 2014-04-12 08:10:00,20.0740725304 2014-04-12 08:15:00,19.2984988959 2014-04-12 08:20:00,20.4907512548 2014-04-12 08:25:00,18.3719211058 2014-04-12 08:30:00,20.4844904116 2014-04-12 08:35:00,19.1013794006 2014-04-12 08:40:00,18.070539316199998 2014-04-12 08:45:00,20.2108230647 2014-04-12 08:50:00,20.3137910234 2014-04-12 08:55:00,19.7062760188 2014-04-12 09:00:00,62.18309276270001 2014-04-12 09:05:00,73.3494641581 2014-04-12 09:10:00,69.5154589783 2014-04-12 09:15:00,62.7737008741 2014-04-12 09:20:00,68.1486558417 2014-04-12 09:25:00,67.9626586969 2014-04-12 09:30:00,62.021465415600005 2014-04-12 09:35:00,69.45329196899999 2014-04-12 09:40:00,72.1932390253 2014-04-12 09:45:00,71.3865095378 2014-04-12 09:50:00,63.960384032600004 2014-04-12 09:55:00,72.9271784019 2014-04-12 10:00:00,75.156254411 2014-04-12 10:05:00,84.5298100311 2014-04-12 10:10:00,70.9535284048 2014-04-12 10:15:00,77.3859588458 2014-04-12 10:20:00,79.1073703338 2014-04-12 10:25:00,73.6835295283 2014-04-12 10:30:00,81.8118205289 2014-04-12 10:35:00,79.56942095069999 2014-04-12 10:40:00,70.1210584667 2014-04-12 10:45:00,79.28188052760001 2014-04-12 10:50:00,77.4677421982 2014-04-12 10:55:00,72.8823732104 2014-04-12 11:00:00,87.4043798032 2014-04-12 11:05:00,85.83646754649999 2014-04-12 11:10:00,76.2200423817 2014-04-12 11:15:00,80.1731919244 2014-04-12 11:20:00,76.6016500331 2014-04-12 11:25:00,83.901484434 2014-04-12 11:30:00,86.36399111360001 2014-04-12 11:35:00,77.2748101644 2014-04-12 11:40:00,84.3800118984 2014-04-12 11:45:00,79.4946735593 2014-04-12 11:50:00,77.8751854391 2014-04-12 11:55:00,86.4926611358 2014-04-12 12:00:00,80.0702752495 2014-04-12 12:05:00,79.3831937225 2014-04-12 12:10:00,82.65963969090001 2014-04-12 12:15:00,76.0883315196 2014-04-12 12:20:00,77.10404990949999 2014-04-12 12:25:00,86.8084380998 2014-04-12 12:30:00,82.757049754 2014-04-12 12:35:00,85.1239229311 2014-04-12 12:40:00,76.24618284510001 2014-04-12 12:45:00,80.60380226720001 2014-04-12 12:50:00,87.43728946350002 2014-04-12 12:55:00,77.0067432696 2014-04-12 13:00:00,74.5497273914 2014-04-12 13:05:00,80.1549343293 2014-04-12 13:10:00,78.18636818659999 2014-04-12 13:15:00,74.53534294800001 2014-04-12 13:20:00,86.1961300859 2014-04-12 13:25:00,87.830498189 2014-04-12 13:30:00,81.0778515355 2014-04-12 13:35:00,84.3745735352 2014-04-12 13:40:00,85.7240352054 2014-04-12 13:45:00,83.1957403254 2014-04-12 13:50:00,72.6890472266 2014-04-12 13:55:00,74.504262392 2014-04-12 14:00:00,73.1323165387 2014-04-12 14:05:00,72.15461011869998 2014-04-12 14:10:00,76.8922515349 2014-04-12 14:15:00,78.2739380383 2014-04-12 14:20:00,75.8528346065 2014-04-12 14:25:00,73.030168753 2014-04-12 14:30:00,80.4739465185 2014-04-12 14:35:00,76.3694432101 2014-04-12 14:40:00,84.7325271213 2014-04-12 14:45:00,72.1253797616 2014-04-12 14:50:00,85.4763297598 2014-04-12 14:55:00,87.2718696123 2014-04-12 15:00:00,83.4573598121 2014-04-12 15:05:00,83.7375011565 2014-04-12 15:10:00,86.93616239049999 2014-04-12 15:15:00,75.34441725149999 2014-04-12 15:20:00,87.9122051261 2014-04-12 15:25:00,84.37488924729999 2014-04-12 15:30:00,83.62432853199999 2014-04-12 15:35:00,77.7767026004 2014-04-12 15:40:00,80.7316647351 2014-04-12 15:45:00,82.4618929706 2014-04-12 15:50:00,81.92469929640001 2014-04-12 15:55:00,83.27895473 2014-04-12 16:00:00,73.3179670545 2014-04-12 16:05:00,77.6902257598 2014-04-12 16:10:00,78.943848693 2014-04-12 16:15:00,76.16992251949999 2014-04-12 16:20:00,74.7618927812 2014-04-12 16:25:00,74.2226971708 2014-04-12 16:30:00,77.8619847808 2014-04-12 16:35:00,79.8949138105 2014-04-12 16:40:00,73.0074828677 2014-04-12 16:45:00,87.1431621983 2014-04-12 16:50:00,84.2437314175 2014-04-12 16:55:00,83.6934676792 2014-04-12 17:00:00,74.7657396898 2014-04-12 17:05:00,81.6607809304 2014-04-12 17:10:00,80.4755682463 2014-04-12 17:15:00,87.7194678483 2014-04-12 17:20:00,83.9627160796 2014-04-12 17:25:00,81.212158954 2014-04-12 17:30:00,85.6129697881 2014-04-12 17:35:00,74.4814797329 2014-04-12 17:40:00,72.24343673359999 2014-04-12 17:45:00,83.0437014458 2014-04-12 17:50:00,73.5729551118 2014-04-12 17:55:00,73.8469098825 2014-04-12 18:00:00,33.5659502045 2014-04-12 18:05:00,30.5314171404 2014-04-12 18:10:00,32.8232334776 2014-04-12 18:15:00,34.6713976701 2014-04-12 18:20:00,30.825431084 2014-04-12 18:25:00,30.1897168137 2014-04-12 18:30:00,29.4819967954 2014-04-12 18:35:00,29.634953423200002 2014-04-12 18:40:00,29.1982196444 2014-04-12 18:45:00,29.360905587199998 2014-04-12 18:50:00,31.5648233079 2014-04-12 18:55:00,30.8535303643 2014-04-12 19:00:00,23.32539116860001 2014-04-12 19:05:00,24.0586813092 2014-04-12 19:10:00,23.6757826513 2014-04-12 19:15:00,22.5372536735 2014-04-12 19:20:00,20.6189395496 2014-04-12 19:25:00,23.3397561517 2014-04-12 19:30:00,21.7854714917 2014-04-12 19:35:00,20.5437126378 2014-04-12 19:40:00,23.9342481913 2014-04-12 19:45:00,21.6752088079 2014-04-12 19:50:00,21.1377536101 2014-04-12 19:55:00,24.0641039294 2014-04-12 20:00:00,22.127140059600002 2014-04-12 20:05:00,19.820424311300002 2014-04-12 20:10:00,19.8852663748 2014-04-12 20:15:00,20.8061581993 2014-04-12 20:20:00,21.4361761014 2014-04-12 20:25:00,18.6906589067 2014-04-12 20:30:00,20.862335369500002 2014-04-12 20:35:00,22.334750705 2014-04-12 20:40:00,19.5055363688 2014-04-12 20:45:00,22.154556003099998 2014-04-12 20:50:00,22.323889255900003 2014-04-12 20:55:00,19.534453079000002 2014-04-12 21:00:00,21.1176880877 2014-04-12 21:05:00,19.046084466900002 2014-04-12 21:10:00,21.0510067297 2014-04-12 21:15:00,21.2913902965 2014-04-12 21:20:00,19.0799691177 2014-04-12 21:25:00,20.9636228183 2014-04-12 21:30:00,21.3504105104 2014-04-12 21:35:00,19.527600155 2014-04-12 21:40:00,18.7604309514 2014-04-12 21:45:00,18.4560239438 2014-04-12 21:50:00,20.398974093299998 2014-04-12 21:55:00,22.0175719073 2014-04-12 22:00:00,21.3122413989 2014-04-12 22:05:00,19.7623121702 2014-04-12 22:10:00,20.165824225799998 2014-04-12 22:15:00,19.1364649193 2014-04-12 22:20:00,18.6701696332 2014-04-12 22:25:00,19.9474558148 2014-04-12 22:30:00,19.873066100899997 2014-04-12 22:35:00,20.1070040124 2014-04-12 22:40:00,21.8321571011 2014-04-12 22:45:00,20.4351801485 2014-04-12 22:50:00,20.4426935003 2014-04-12 22:55:00,18.5298706574 2014-04-12 23:00:00,21.990176765999998 2014-04-12 23:05:00,21.0954293198 2014-04-12 23:10:00,21.5129430664 2014-04-12 23:15:00,19.6609758281 2014-04-12 23:20:00,20.0123540156 2014-04-12 23:25:00,20.092192195 2014-04-12 23:30:00,18.7799832199 2014-04-12 23:35:00,20.761942150899998 2014-04-12 23:40:00,21.616056378499998 2014-04-12 23:45:00,18.6584049968 2014-04-12 23:50:00,18.3487953846 2014-04-12 23:55:00,20.9568985722 2014-04-13 00:00:00,19.0928073267 2014-04-13 00:05:00,20.4954501665 2014-04-13 00:10:00,20.783033352 2014-04-13 00:15:00,19.287643054300002 2014-04-13 00:20:00,100.000000000 2014-04-13 00:25:00,20.1999559285 2014-04-13 00:30:00,21.4759976318 2014-04-13 00:35:00,21.053174210199998 2014-04-13 00:40:00,21.4743025281 2014-04-13 00:45:00,18.0806455285 2014-04-13 00:50:00,18.974025043 2014-04-13 00:55:00,18.360031761800002 2014-04-13 01:00:00,19.7683320688 2014-04-13 01:05:00,21.5598404865 2014-04-13 01:10:00,19.870161049100002 2014-04-13 01:15:00,21.3988521783 2014-04-13 01:20:00,19.3087129521 2014-04-13 01:25:00,19.3582802912 2014-04-13 01:30:00,21.5822469213 2014-04-13 01:35:00,19.703268586 2014-04-13 01:40:00,21.159061951199998 2014-04-13 01:45:00,18.9465741915 2014-04-13 01:50:00,21.7952033187 2014-04-13 01:55:00,20.298312986099997 2014-04-13 02:00:00,21.037294274300002 2014-04-13 02:05:00,18.358062799200003 2014-04-13 02:10:00,19.9706569033 2014-04-13 02:15:00,21.604153990900002 2014-04-13 02:20:00,21.508154516199998 2014-04-13 02:25:00,18.1872558289 2014-04-13 02:30:00,19.2147938765 2014-04-13 02:35:00,19.7732800259 2014-04-13 02:40:00,18.6890592574 2014-04-13 02:45:00,20.919993244 2014-04-13 02:50:00,18.7380479824 2014-04-13 02:55:00,19.3865587775 2014-04-13 03:00:00,20.6531225474 2014-04-13 03:05:00,19.9283573781 2014-04-13 03:10:00,20.9542841545 2014-04-13 03:15:00,21.844831604899998 2014-04-13 03:20:00,18.4661867509 2014-04-13 03:25:00,20.8382708656 2014-04-13 03:30:00,18.9213766225 2014-04-13 03:35:00,19.6579069096 2014-04-13 03:40:00,18.1314509032 2014-04-13 03:45:00,18.5436295292 2014-04-13 03:50:00,19.2791091562 2014-04-13 03:55:00,19.367943221199997 2014-04-13 04:00:00,21.5983408658 2014-04-13 04:05:00,20.9672516371 2014-04-13 04:10:00,21.8887318727 2014-04-13 04:15:00,20.3962860413 2014-04-13 04:20:00,18.9668549284 2014-04-13 04:25:00,19.3106201197 2014-04-13 04:30:00,19.279343693199998 2014-04-13 04:35:00,19.305977310699998 2014-04-13 04:40:00,20.691856692400002 2014-04-13 04:45:00,20.1232317124 2014-04-13 04:50:00,19.5416967123 2014-04-13 04:55:00,18.5963590749 2014-04-13 05:00:00,18.0885566518 2014-04-13 05:05:00,18.8753387104 2014-04-13 05:10:00,18.429885615899998 2014-04-13 05:15:00,21.1417801234 2014-04-13 05:20:00,18.4499918313 2014-04-13 05:25:00,20.8969129492 2014-04-13 05:30:00,19.5426347591 2014-04-13 05:35:00,18.293513559 2014-04-13 05:40:00,21.2509201977 2014-04-13 05:45:00,20.318522280899998 2014-04-13 05:50:00,18.9430460515 2014-04-13 05:55:00,21.5787246973 2014-04-13 06:00:00,18.1810332555 2014-04-13 06:05:00,18.8072784328 2014-04-13 06:10:00,21.008187711199998 2014-04-13 06:15:00,20.8375117212 2014-04-13 06:20:00,19.1570867749 2014-04-13 06:25:00,18.248099501400002 2014-04-13 06:30:00,21.4323122889 2014-04-13 06:35:00,19.2547905523 2014-04-13 06:40:00,18.7828536597 2014-04-13 06:45:00,20.0642472894 2014-04-13 06:50:00,21.6409087971 2014-04-13 06:55:00,18.1741863114 2014-04-13 07:00:00,21.0632163521 2014-04-13 07:05:00,20.2898929118 2014-04-13 07:10:00,19.701796466199998 2014-04-13 07:15:00,20.976321776400003 2014-04-13 07:20:00,21.863297697800004 2014-04-13 07:25:00,18.9168248447 2014-04-13 07:30:00,18.5745894603 2014-04-13 07:35:00,21.6515269809 2014-04-13 07:40:00,20.6758123098 2014-04-13 07:45:00,19.751944086199998 2014-04-13 07:50:00,20.2930382811 2014-04-13 07:55:00,20.982455620699998 2014-04-13 08:00:00,21.0921275948 2014-04-13 08:05:00,21.6795767233 2014-04-13 08:10:00,19.7073711556 2014-04-13 08:15:00,19.1736436401 2014-04-13 08:20:00,20.5586570672 2014-04-13 08:25:00,19.6629115971 2014-04-13 08:30:00,20.3783938158 2014-04-13 08:35:00,19.6799431938 2014-04-13 08:40:00,18.611983146700002 2014-04-13 08:45:00,19.8777070066 2014-04-13 08:50:00,20.7636712878 2014-04-13 08:55:00,21.1971352307 2014-04-13 09:00:00,67.9092373644 2014-04-13 09:05:00,63.4472353069 2014-04-13 09:10:00,66.8397528512 2014-04-13 09:15:00,71.8935974322 2014-04-13 09:20:00,66.8148860804 2014-04-13 09:25:00,70.672818793 2014-04-13 09:30:00,68.0981060708 2014-04-13 09:35:00,64.48063450149999 2014-04-13 09:40:00,72.0276469091 2014-04-13 09:45:00,62.3453029754 2014-04-13 09:50:00,68.3385078455 2014-04-13 09:55:00,64.0409180657 2014-04-13 10:00:00,70.880858555 2014-04-13 10:05:00,77.6455347035 2014-04-13 10:10:00,77.5932046601 2014-04-13 10:15:00,80.811101994 2014-04-13 10:20:00,81.3985307562 2014-04-13 10:25:00,81.1353239045 2014-04-13 10:30:00,76.1963515349 2014-04-13 10:35:00,79.6438254978 2014-04-13 10:40:00,78.7941901658 2014-04-13 10:45:00,76.3826384549 2014-04-13 10:50:00,79.1087410138 2014-04-13 10:55:00,84.5412870465 2014-04-13 11:00:00,74.63578209949999 2014-04-13 11:05:00,85.9733994114 2014-04-13 11:10:00,72.4181564944 2014-04-13 11:15:00,76.472622042 2014-04-13 11:20:00,76.1506620339 2014-04-13 11:25:00,81.5297106757 2014-04-13 11:30:00,73.6550016331 2014-04-13 11:35:00,85.6008564187 2014-04-13 11:40:00,84.7452816002 2014-04-13 11:45:00,81.93845479630002 2014-04-13 11:50:00,78.8586135808 2014-04-13 11:55:00,86.4057328942 2014-04-13 12:00:00,85.1895945417 2014-04-13 12:05:00,79.8930555185 2014-04-13 12:10:00,83.1300977029 2014-04-13 12:15:00,80.97359417979999 2014-04-13 12:20:00,81.3093873232 2014-04-13 12:25:00,77.2028623705 2014-04-13 12:30:00,79.29808164960002 2014-04-13 12:35:00,73.1620429612 2014-04-13 12:40:00,77.6243179718 2014-04-13 12:45:00,83.0334963383 2014-04-13 12:50:00,87.14675474030001 2014-04-13 12:55:00,87.3041349732 2014-04-13 13:00:00,80.8721519302 2014-04-13 13:05:00,81.6863465995 2014-04-13 13:10:00,74.9535457987 2014-04-13 13:15:00,83.1049797464 2014-04-13 13:20:00,73.112989353 2014-04-13 13:25:00,76.53659777979999 2014-04-13 13:30:00,82.6739670413 2014-04-13 13:35:00,76.9464905138 2014-04-13 13:40:00,72.7800785738 2014-04-13 13:45:00,85.2894521672 2014-04-13 13:50:00,76.9468084469 2014-04-13 13:55:00,72.99216127369998 2014-04-13 14:00:00,73.1930971947 2014-04-13 14:05:00,76.0244914299 2014-04-13 14:10:00,74.84466243930001 2014-04-13 14:15:00,84.38475122199999 2014-04-13 14:20:00,77.1432416933 2014-04-13 14:25:00,84.8710585543 2014-04-13 14:30:00,74.7779464514 2014-04-13 14:35:00,79.8822323415 2014-04-13 14:40:00,83.0046097243 2014-04-13 14:45:00,82.4278969329 2014-04-13 14:50:00,81.6141528915 2014-04-13 14:55:00,86.7929793679 2014-04-13 15:00:00,75.65567606180001 2014-04-13 15:05:00,79.8987402361 2014-04-13 15:10:00,86.1430538199 2014-04-13 15:15:00,73.245597085 2014-04-13 15:20:00,72.89351250760001 2014-04-13 15:25:00,75.7321095657 2014-04-13 15:30:00,82.1275510805 2014-04-13 15:35:00,76.15734290569999 2014-04-13 15:40:00,75.0431177201 2014-04-13 15:45:00,79.3400753737 2014-04-13 15:50:00,81.8167836516 2014-04-13 15:55:00,75.9761939338 2014-04-13 16:00:00,76.8109115103 2014-04-13 16:05:00,81.8167917884 2014-04-13 16:10:00,87.1316474587 2014-04-13 16:15:00,82.7957086709 2014-04-13 16:20:00,84.5263040065 2014-04-13 16:25:00,77.8688120077 2014-04-13 16:30:00,76.35592314649999 2014-04-13 16:35:00,79.2681316961 2014-04-13 16:40:00,84.91396222430001 2014-04-13 16:45:00,79.3006420111 2014-04-13 16:50:00,85.5474422892 2014-04-13 16:55:00,87.820183076 2014-04-13 17:00:00,73.1523985612 2014-04-13 17:05:00,72.7265345703 2014-04-13 17:10:00,74.3934066795 2014-04-13 17:15:00,78.1498848022 2014-04-13 17:20:00,74.0966468932 2014-04-13 17:25:00,85.93059864450001 2014-04-13 17:30:00,72.3703122262 2014-04-13 17:35:00,77.0526538731 2014-04-13 17:40:00,74.9550852891 2014-04-13 17:45:00,86.9045959111 2014-04-13 17:50:00,82.7116643169 2014-04-13 17:55:00,86.59245085170002 2014-04-13 18:00:00,35.022897021599995 2014-04-13 18:05:00,31.981422619099998 2014-04-13 18:10:00,30.299636474 2014-04-13 18:15:00,30.039858464 2014-04-13 18:20:00,30.2266749113 2014-04-13 18:25:00,33.3349907685 2014-04-13 18:30:00,29.0588470807 2014-04-13 18:35:00,29.128705274699996 2014-04-13 18:40:00,32.6921085544 2014-04-13 18:45:00,32.9091594206 2014-04-13 18:50:00,33.0576763686 2014-04-13 18:55:00,31.180029242800003 2014-04-13 19:00:00,23.7706317975 2014-04-13 19:05:00,22.550636916 2014-04-13 19:10:00,20.6324848906 2014-04-13 19:15:00,23.7310035938 2014-04-13 19:20:00,24.4297423423 2014-04-13 19:25:00,20.4289615616 2014-04-13 19:30:00,21.913252795300004 2014-04-13 19:35:00,22.3440706551 2014-04-13 19:40:00,20.8161878632 2014-04-13 19:45:00,24.0473347669 2014-04-13 19:50:00,21.4329892334 2014-04-13 19:55:00,23.6678769606 2014-04-13 20:00:00,21.1803931442 2014-04-13 20:05:00,20.881595438199998 2014-04-13 20:10:00,19.2190168776 2014-04-13 20:15:00,19.336001388099998 2014-04-13 20:20:00,18.625938842300002 2014-04-13 20:25:00,19.4179578794 2014-04-13 20:30:00,19.8469367862 2014-04-13 20:35:00,21.8445629025 2014-04-13 20:40:00,19.932744123699997 2014-04-13 20:45:00,21.522930563899997 2014-04-13 20:50:00,20.231955341400003 2014-04-13 20:55:00,21.6468203462 2014-04-13 21:00:00,22.010230762600003 2014-04-13 21:05:00,19.0503711436 2014-04-13 21:10:00,21.552323354099997 2014-04-13 21:15:00,20.5856353173 2014-04-13 21:20:00,21.3712690439 2014-04-13 21:25:00,20.7052540078 2014-04-13 21:30:00,19.7903378112 2014-04-13 21:35:00,19.0030787501 2014-04-13 21:40:00,18.3678855327 2014-04-13 21:45:00,20.2387553609 2014-04-13 21:50:00,22.0667185852 2014-04-13 21:55:00,21.052737571199998 2014-04-13 22:00:00,19.327919163 2014-04-13 22:05:00,21.329275656300002 2014-04-13 22:10:00,21.0961688889 2014-04-13 22:15:00,19.1449046455 2014-04-13 22:20:00,18.0745648911 2014-04-13 22:25:00,18.4903842896 2014-04-13 22:30:00,21.5298736064 2014-04-13 22:35:00,21.3667445328 2014-04-13 22:40:00,19.1992495966 2014-04-13 22:45:00,19.1591568462 2014-04-13 22:50:00,21.1917845396 2014-04-13 22:55:00,21.7718307808 2014-04-13 23:00:00,21.1206034025 2014-04-13 23:05:00,20.426235790499998 2014-04-13 23:10:00,18.9743277711 2014-04-13 23:15:00,20.106851428800002 2014-04-13 23:20:00,18.937682769600002 2014-04-13 23:25:00,21.236122231099998 2014-04-13 23:30:00,19.5515975023 2014-04-13 23:35:00,21.3388851453 2014-04-13 23:40:00,19.530185945899998 2014-04-13 23:45:00,21.3006865654 2014-04-13 23:50:00,19.3369832468 2014-04-13 23:55:00,19.7643248384 2014-04-14 00:00:00,20.4619536774 2014-04-14 00:05:00,18.2811504561 2014-04-14 00:10:00,21.7928282473 2014-04-14 00:15:00,20.2944231445 2014-04-14 00:20:00,20.0312800588 2014-04-14 00:25:00,21.3575758845 2014-04-14 00:30:00,21.4630509196 2014-04-14 00:35:00,20.089041618099998 2014-04-14 00:40:00,21.7090493032 2014-04-14 00:45:00,18.2589510643 2014-04-14 00:50:00,18.452903169000002 2014-04-14 00:55:00,20.3871529201 2014-04-14 01:00:00,19.4162634472 2014-04-14 01:05:00,19.8569006648 2014-04-14 01:10:00,19.3123168716 2014-04-14 01:15:00,19.6189012458 2014-04-14 01:20:00,21.2905853886 2014-04-14 01:25:00,20.3739047994 2014-04-14 01:30:00,21.9893781971 2014-04-14 01:35:00,21.147516791300003 2014-04-14 01:40:00,19.0946650164 2014-04-14 01:45:00,19.0573804709 2014-04-14 01:50:00,19.3435930805 2014-04-14 01:55:00,21.3730379226 2014-04-14 02:00:00,18.1091506026 2014-04-14 02:05:00,18.920725115499998 2014-04-14 02:10:00,21.6196736814 2014-04-14 02:15:00,20.5595857443 2014-04-14 02:20:00,18.907388382 2014-04-14 02:25:00,18.8765798729 2014-04-14 02:30:00,21.450472407 2014-04-14 02:35:00,21.5750300331 2014-04-14 02:40:00,19.0245243638 2014-04-14 02:45:00,19.6820414323 2014-04-14 02:50:00,21.338382954500002 2014-04-14 02:55:00,21.0840297544 2014-04-14 03:00:00,21.2556644263 2014-04-14 03:05:00,20.0735927632 2014-04-14 03:10:00,21.6461961932 2014-04-14 03:15:00,19.3038061758 2014-04-14 03:20:00,18.6266885374 2014-04-14 03:25:00,20.8349293303 2014-04-14 03:30:00,20.157417664 2014-04-14 03:35:00,21.4183430752 2014-04-14 03:40:00,18.3246369965 2014-04-14 03:45:00,21.3747696138 2014-04-14 03:50:00,19.1731786128 2014-04-14 03:55:00,20.6194226687 2014-04-14 04:00:00,18.1605151563 2014-04-14 04:05:00,20.4383251852 2014-04-14 04:10:00,20.8690867567 2014-04-14 04:15:00,19.475000857999998 2014-04-14 04:20:00,18.861642821 2014-04-14 04:25:00,20.1505227064 2014-04-14 04:30:00,21.3327632177 2014-04-14 04:35:00,19.2941894332 2014-04-14 04:40:00,19.0098771901 2014-04-14 04:45:00,19.1157412346 2014-04-14 04:50:00,21.7965286117 2014-04-14 04:55:00,19.4371076631 2014-04-14 05:00:00,18.014416959600002 2014-04-14 05:05:00,21.1267248318 2014-04-14 05:10:00,20.797099181300002 2014-04-14 05:15:00,18.5142730584 2014-04-14 05:20:00,21.9396169965 2014-04-14 05:25:00,20.4322491412 2014-04-14 05:30:00,20.0031179638 2014-04-14 05:35:00,19.5288770705 2014-04-14 05:40:00,21.5946910223 2014-04-14 05:45:00,18.9758539257 2014-04-14 05:50:00,19.143075600899998 2014-04-14 05:55:00,18.4896432267 2014-04-14 06:00:00,21.036476382300002 2014-04-14 06:05:00,20.3821971216 2014-04-14 06:10:00,20.436264677 2014-04-14 06:15:00,18.873881724100002 2014-04-14 06:20:00,20.6046735565 2014-04-14 06:25:00,21.061833789 2014-04-14 06:30:00,19.4315541229 2014-04-14 06:35:00,21.2053885758 2014-04-14 06:40:00,19.395162354100002 2014-04-14 06:45:00,21.032553846 2014-04-14 06:50:00,18.1349204298 2014-04-14 06:55:00,20.2046584059 2014-04-14 07:00:00,21.8781062426 2014-04-14 07:05:00,21.9249784027 2014-04-14 07:10:00,19.1270103134 2014-04-14 07:15:00,19.765596364300002 2014-04-14 07:20:00,18.2519116319 2014-04-14 07:25:00,21.4933652304 2014-04-14 07:30:00,20.2742886126 2014-04-14 07:35:00,19.5404027158 2014-04-14 07:40:00,18.451082234 2014-04-14 07:45:00,21.787069141999996 2014-04-14 07:50:00,20.120876191300002 2014-04-14 07:55:00,19.1317117163 2014-04-14 08:00:00,19.4008605205 2014-04-14 08:05:00,19.0827887237 2014-04-14 08:10:00,20.4072392354 2014-04-14 08:15:00,21.7198543031 2014-04-14 08:20:00,21.4267752133 2014-04-14 08:25:00,19.8415235017 2014-04-14 08:30:00,21.3059974492 2014-04-14 08:35:00,19.6924219251 2014-04-14 08:40:00,19.009228563 2014-04-14 08:45:00,21.9336604611 2014-04-14 08:50:00,19.2155502719 2014-04-14 08:55:00,19.2948969239 2014-04-14 09:00:00,74.6598230019 2014-04-14 09:05:00,63.0214139071 2014-04-14 09:10:00,71.54326223689999 2014-04-14 09:15:00,73.9270535154 2014-04-14 09:20:00,68.1604119221 2014-04-14 09:25:00,61.234295959200004 2014-04-14 09:30:00,66.3008016399 2014-04-14 09:35:00,62.7173382964 2014-04-14 09:40:00,66.8601521887 2014-04-14 09:45:00,71.9443639583 2014-04-14 09:50:00,67.16647706479999 2014-04-14 09:55:00,67.07418165029999 2014-04-14 10:00:00,78.4813726818 2014-04-14 10:05:00,78.8678378753 2014-04-14 10:10:00,83.1297187126 2014-04-14 10:15:00,74.6256764168 2014-04-14 10:20:00,82.592338023 2014-04-14 10:25:00,78.6232917797 2014-04-14 10:30:00,74.5042186116 2014-04-14 10:35:00,74.420356203 2014-04-14 10:40:00,75.4448542655 2014-04-14 10:45:00,79.50419912550001 2014-04-14 10:50:00,73.42219807069999 2014-04-14 10:55:00,84.12357687720001 2014-04-14 11:00:00,80.7114097388 2014-04-14 11:05:00,86.1999309173 2014-04-14 11:10:00,72.3060149188 2014-04-14 11:15:00,77.0168912358 2014-04-14 11:20:00,71.9307330356 2014-04-14 11:25:00,75.8978928673 2014-04-14 11:30:00,85.277350935 2014-04-14 11:35:00,72.1502409208 2014-04-14 11:40:00,78.5044834771 2014-04-14 11:45:00,73.4377866888 2014-04-14 11:50:00,78.1974338449 2014-04-14 11:55:00,84.9090955961 2014-04-14 12:00:00,81.87077357060001 2014-04-14 12:05:00,83.6875558035 2014-04-14 12:10:00,77.4925630482 2014-04-14 12:15:00,87.00583068440002 2014-04-14 12:20:00,83.2481756683 2014-04-14 12:25:00,78.6542825712 2014-04-14 12:30:00,78.7288486795 2014-04-14 12:35:00,86.59490811090002 2014-04-14 12:40:00,81.12500812489999 2014-04-14 12:45:00,83.20210487760001 2014-04-14 12:50:00,78.5781565159 2014-04-14 12:55:00,75.48838933520001 2014-04-14 13:00:00,83.5568902042 2014-04-14 13:05:00,181.705566311 2014-04-14 13:10:00,80.0022809301 2014-04-14 13:15:00,81.9646587995 2014-04-14 13:20:00,75.3144895604 2014-04-14 13:25:00,84.6826905799 2014-04-14 13:30:00,87.1496839352 2014-04-14 13:35:00,86.2369484706 2014-04-14 13:40:00,77.1244576117 2014-04-14 13:45:00,78.4772533103 2014-04-14 13:50:00,84.9140525319 2014-04-14 13:55:00,81.5023088434 2014-04-14 14:00:00,80.7627543005 2014-04-14 14:05:00,86.8221038195 2014-04-14 14:10:00,80.57253170850001 2014-04-14 14:15:00,80.2351674005 2014-04-14 14:20:00,72.66880919 2014-04-14 14:25:00,73.10716202520001 2014-04-14 14:30:00,72.11526322729999 2014-04-14 14:35:00,86.607750241 2014-04-14 14:40:00,78.53041691930001 2014-04-14 14:45:00,79.493166163 2014-04-14 14:50:00,85.5220859043 2014-04-14 14:55:00,81.74401706479999 2014-04-14 15:00:00,81.75124072279999 2014-04-14 15:05:00,76.743814122 2014-04-14 15:10:00,85.3417146945 2014-04-14 15:15:00,74.6525629451 2014-04-14 15:20:00,72.849694111 2014-04-14 15:25:00,75.06493309 2014-04-14 15:30:00,76.283063176 2014-04-14 15:35:00,76.5162423627 2014-04-14 15:40:00,82.727423387 2014-04-14 15:45:00,75.4844687394 2014-04-14 15:50:00,82.8257377372 2014-04-14 15:55:00,73.4574095738 2014-04-14 16:00:00,74.3550966155 2014-04-14 16:05:00,80.1409893049 2014-04-14 16:10:00,86.7501662806 2014-04-14 16:15:00,85.7529167751 2014-04-14 16:20:00,87.49988707899998 2014-04-14 16:25:00,82.4075068217 2014-04-14 16:30:00,82.8128788616 2014-04-14 16:35:00,82.00021054220001 2014-04-14 16:40:00,81.9649453927 2014-04-14 16:45:00,74.3537827615 2014-04-14 16:50:00,80.699668355 2014-04-14 16:55:00,78.17693683520001 2014-04-14 17:00:00,79.0805650855 2014-04-14 17:05:00,80.37757830390001 2014-04-14 17:10:00,74.054310312 2014-04-14 17:15:00,77.7517738849 2014-04-14 17:20:00,73.0151649362 2014-04-14 17:25:00,87.6746564197 2014-04-14 17:30:00,73.8964200849 2014-04-14 17:35:00,76.13636658029999 2014-04-14 17:40:00,86.26065370319998 2014-04-14 17:45:00,79.7233301261 2014-04-14 17:50:00,74.170166743 2014-04-14 17:55:00,78.1476585999 2014-04-14 18:00:00,29.541549490799998 2014-04-14 18:05:00,30.0813766057 2014-04-14 18:10:00,29.1329854269 2014-04-14 18:15:00,31.604649896999998 2014-04-14 18:20:00,33.9624646582 2014-04-14 18:25:00,32.550196494 2014-04-14 18:30:00,32.6806036804 2014-04-14 18:35:00,30.0837320165 2014-04-14 18:40:00,31.0009146446 2014-04-14 18:45:00,34.2095428963 2014-04-14 18:50:00,29.3622739421 2014-04-14 18:55:00,34.2907495997 2014-04-14 19:00:00,22.3269300929 2014-04-14 19:05:00,23.9104191807 2014-04-14 19:10:00,21.5846675748 2014-04-14 19:15:00,21.6780152339 2014-04-14 19:20:00,23.527188519499997 2014-04-14 19:25:00,23.676781558000002 2014-04-14 19:30:00,21.188806995 2014-04-14 19:35:00,24.5184621902 2014-04-14 19:40:00,20.5385145403 2014-04-14 19:45:00,20.4668921519 2014-04-14 19:50:00,22.827857632199997 2014-04-14 19:55:00,23.3978773561 2014-04-14 20:00:00,22.3677893169 2014-04-14 20:05:00,20.0906576771 2014-04-14 20:10:00,18.535593388800002 2014-04-14 20:15:00,20.9014631556 2014-04-14 20:20:00,19.6185946649 2014-04-14 20:25:00,20.205351166 2014-04-14 20:30:00,20.4327707541 2014-04-14 20:35:00,18.6962434292 2014-04-14 20:40:00,20.4225811445 2014-04-14 20:45:00,20.1782051131 2014-04-14 20:50:00,21.3505810544 2014-04-14 20:55:00,21.0766473194 2014-04-14 21:00:00,18.8308189683 2014-04-14 21:05:00,18.9149134938 2014-04-14 21:10:00,19.095243987 2014-04-14 21:15:00,18.805637563599998 2014-04-14 21:20:00,20.727871241400003 2014-04-14 21:25:00,22.083213722199996 2014-04-14 21:30:00,20.7073537916 2014-04-14 21:35:00,20.524774420299998 2014-04-14 21:40:00,19.7339823015 2014-04-14 21:45:00,19.3427225291 2014-04-14 21:50:00,21.7481875906 2014-04-14 21:55:00,21.9810122788 2014-04-14 22:00:00,20.006292313 2014-04-14 22:05:00,19.1791963425 2014-04-14 22:10:00,21.100726089600002 2014-04-14 22:15:00,18.547615788399998 2014-04-14 22:20:00,21.0825727991 2014-04-14 22:25:00,21.2962182485 2014-04-14 22:30:00,18.5173754006 2014-04-14 22:35:00,21.9284770125 2014-04-14 22:40:00,21.963113518000004 2014-04-14 22:45:00,21.7677549094 2014-04-14 22:50:00,20.0033240015 2014-04-14 22:55:00,19.0025214845 2014-04-14 23:00:00,20.3319401047 2014-04-14 23:05:00,19.6835138611 2014-04-14 23:10:00,18.8274087456 2014-04-14 23:15:00,19.69848702 2014-04-14 23:20:00,20.6595252081 2014-04-14 23:25:00,18.2871637028 2014-04-14 23:30:00,19.3373840689 2014-04-14 23:35:00,18.0746492248 2014-04-14 23:40:00,21.0020136323 2014-04-14 23:45:00,20.5667131193 2014-04-14 23:50:00,18.254192669200002 2014-04-14 23:55:00,21.8631471547 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/art_daily_jumpsup_noised_trended_det.csv ================================================ ,timestamp,value 0,2014-04-01 00:00:00,19.761251902999998 1,2014-04-01 00:05:00,20.508273763190473 2,2014-04-01 00:10:00,19.976522396880952 3,2014-04-01 00:15:00,21.512587501971428 4,2014-04-01 00:20:00,20.217501314561904 5,2014-04-01 00:25:00,19.96032805275238 6,2014-04-01 00:30:00,21.74304681884286 7,2014-04-01 00:35:00,20.930841717533333 8,2014-04-01 00:40:00,18.50572343892381 9,2014-04-01 00:45:00,18.777782130514286 10,2014-04-01 00:50:00,21.222896213704765 11,2014-04-01 00:55:00,21.42525052279524 12,2014-04-01 01:00:00,20.270049030685716 13,2014-04-01 01:05:00,20.314547101976192 14,2014-04-01 01:10:00,20.63189851806667 15,2014-04-01 01:15:00,19.86807023995714 16,2014-04-01 01:20:00,20.83984411294762 17,2014-04-01 01:25:00,18.560413125538094 18,2014-04-01 01:30:00,21.97904554092857 19,2014-04-01 01:35:00,21.141988342819047 20,2014-04-01 01:40:00,20.673506339809524 21,2014-04-01 01:45:00,19.421538228 22,2014-04-01 01:50:00,18.807512425990474 23,2014-04-01 01:55:00,19.808502807680952 24,2014-04-01 02:00:00,20.824878390871426 25,2014-04-01 02:05:00,20.720850878461903 26,2014-04-01 02:10:00,19.724017001252378 27,2014-04-01 02:15:00,20.654038432442857 28,2014-04-01 02:20:00,21.463326515633334 29,2014-04-01 02:25:00,18.32091289892381 30,2014-04-01 02:30:00,20.025698477414284 31,2014-04-01 02:35:00,21.264875675804763 32,2014-04-01 02:40:00,20.42267311999524 33,2014-04-01 02:45:00,20.851440065985717 34,2014-04-01 02:50:00,20.31968176087619 35,2014-04-01 02:55:00,22.227914845366666 36,2014-04-01 03:00:00,18.486343288857142 37,2014-04-01 03:05:00,20.239476906147623 38,2014-04-01 03:10:00,18.648404291738096 39,2014-04-01 03:15:00,18.929320819928574 40,2014-04-01 03:20:00,19.829772449319048 41,2014-04-01 03:25:00,18.927219889809525 42,2014-04-01 03:30:00,22.167248663800002 43,2014-04-01 03:35:00,22.107099583090474 44,2014-04-01 03:40:00,19.671819537280953 45,2014-04-01 03:45:00,20.893812276771428 46,2014-04-01 03:50:00,20.477275187161904 47,2014-04-01 03:55:00,21.61205030305238 48,2014-04-01 04:00:00,20.866925296442858 49,2014-04-01 04:05:00,18.365593151333332 50,2014-04-01 04:10:00,21.42472135192381 51,2014-04-01 04:15:00,21.366856770914286 52,2014-04-01 04:20:00,20.425795584204764 53,2014-04-01 04:25:00,22.006021130995236 54,2014-04-01 04:30:00,22.035570537085718 55,2014-04-01 04:35:00,20.50487289727619 56,2014-04-01 04:40:00,20.84861959146667 57,2014-04-01 04:45:00,22.410195430557142 58,2014-04-01 04:50:00,19.62682855824762 59,2014-04-01 04:55:00,19.737457064438097 60,2014-04-01 05:00:00,19.177524182128572 61,2014-04-01 05:05:00,22.037336804219045 62,2014-04-01 05:10:00,21.439263083609525 63,2014-04-01 05:15:00,18.8913213955 64,2014-04-01 05:20:00,22.403259880990475 65,2014-04-01 05:25:00,21.40747778498095 66,2014-04-01 05:30:00,21.893159866971427 67,2014-04-01 05:35:00,18.691115061461907 68,2014-04-01 05:40:00,20.52579605675238 69,2014-04-01 05:45:00,21.307786004042857 70,2014-04-01 05:50:00,20.69261967163333 71,2014-04-01 05:55:00,21.19486367232381 72,2014-04-01 06:00:00,21.807210540114284 73,2014-04-01 06:05:00,20.040503013704765 74,2014-04-01 06:10:00,21.94526994059524 75,2014-04-01 06:15:00,19.209700133385716 76,2014-04-01 06:20:00,19.64902041057619 77,2014-04-01 06:25:00,18.746299146366667 78,2014-04-01 06:30:00,20.038064388157142 79,2014-04-01 06:35:00,20.10743579834762 80,2014-04-01 06:40:00,21.816320484038098 81,2014-04-01 06:45:00,21.21520125262857 82,2014-04-01 06:50:00,20.357009280219046 83,2014-04-01 06:55:00,21.226015438309524 84,2014-04-01 07:00:00,18.8361334021 85,2014-04-01 07:05:00,19.353526620290474 86,2014-04-01 07:10:00,21.147672373380953 87,2014-04-01 07:15:00,21.21278870547143 88,2014-04-01 07:20:00,21.751300539561907 89,2014-04-01 07:25:00,20.27420141715238 90,2014-04-01 07:30:00,21.559859243642858 91,2014-04-01 07:35:00,21.413004663533332 92,2014-04-01 07:40:00,22.53809732302381 93,2014-04-01 07:45:00,19.552485191414284 94,2014-04-01 07:50:00,20.90612301690476 95,2014-04-01 07:55:00,21.113903006495235 96,2014-04-01 08:00:00,22.70887725398571 97,2014-04-01 08:05:00,19.526462759176187 98,2014-04-01 08:10:00,20.82203874656667 99,2014-04-01 08:15:00,20.12134837375714 100,2014-04-01 08:20:00,20.847619493347622 101,2014-04-01 08:25:00,19.680002503638093 102,2014-04-01 08:30:00,18.949378085128572 103,2014-04-01 08:35:00,21.05663086321905 104,2014-04-01 08:40:00,20.117226787209525 105,2014-04-01 08:45:00,19.509015607000002 106,2014-04-01 08:50:00,20.084432740490474 107,2014-04-01 08:55:00,18.993251758180953 108,2014-04-01 09:00:00,74.92958581217142 109,2014-04-01 09:05:00,69.91462354836189 110,2014-04-01 09:10:00,73.09930644725237 111,2014-04-01 09:15:00,67.78030034374287 112,2014-04-01 09:20:00,74.31841281223333 113,2014-04-01 09:25:00,68.61390162262381 114,2014-04-01 09:30:00,69.85387066761429 115,2014-04-01 09:35:00,68.74405289080477 116,2014-04-01 09:40:00,72.03568006189523 117,2014-04-01 09:45:00,69.7770583696857 118,2014-04-01 09:50:00,65.77172155117619 119,2014-04-01 09:55:00,64.06475429266668 120,2014-04-01 10:00:00,80.13990765835715 121,2014-04-01 10:05:00,78.33237062224762 122,2014-04-01 10:10:00,72.2372809079381 123,2014-04-01 10:15:00,76.89516164052857 124,2014-04-01 10:20:00,78.75194911701905 125,2014-04-01 10:25:00,83.60344251280951 126,2014-04-01 10:30:00,71.9585883865 127,2014-04-01 10:35:00,76.19358828099048 128,2014-04-01 10:40:00,83.56000397688095 129,2014-04-01 10:45:00,80.86336084967142 130,2014-04-01 10:50:00,75.3074150591619 131,2014-04-01 10:55:00,83.93430347475238 132,2014-04-01 11:00:00,80.39548396244285 133,2014-04-01 11:05:00,80.48337181273332 134,2014-04-01 11:10:00,88.09666885212381 135,2014-04-01 11:15:00,87.6354051532143 136,2014-04-01 11:20:00,78.28200855820477 137,2014-04-01 11:25:00,74.82311570039523 138,2014-04-01 11:30:00,77.77418942448571 139,2014-04-01 11:35:00,73.08703196247619 140,2014-04-01 11:40:00,72.93995913686668 141,2014-04-01 11:45:00,78.90749119775714 142,2014-04-01 11:50:00,87.59052687924762 143,2014-04-01 11:55:00,86.4900552502381 144,2014-04-01 12:00:00,81.15829421172856 145,2014-04-01 12:05:00,82.02523879981905 146,2014-04-01 12:10:00,73.09473154860952 147,2014-04-01 12:15:00,76.4512308711 148,2014-04-01 12:20:00,73.41070084389048 149,2014-04-01 12:25:00,85.08037631648095 150,2014-04-01 12:30:00,75.35720776567143 151,2014-04-01 12:35:00,86.9251798400619 152,2014-04-01 12:40:00,83.32538957295237 153,2014-04-01 12:45:00,76.71828684284286 154,2014-04-01 12:50:00,75.57993017653332 155,2014-04-01 12:55:00,83.09681863002382 156,2014-04-01 13:00:00,87.55336675621429 157,2014-04-01 13:05:00,84.64187976130475 158,2014-04-01 13:10:00,78.73372324459524 159,2014-04-01 13:15:00,82.56163768558571 160,2014-04-01 13:20:00,78.1441899914762 161,2014-04-01 13:25:00,89.16319300076667 162,2014-04-01 13:30:00,85.16662861575713 163,2014-04-01 13:35:00,83.02326462964763 164,2014-04-01 13:40:00,79.97347906433811 165,2014-04-01 13:45:00,83.09846151082857 166,2014-04-01 13:50:00,78.68238424141906 167,2014-04-01 13:55:00,73.68700611410952 168,2014-04-01 14:00:00,79.56765692970001 169,2014-04-01 14:05:00,88.14096298019048 170,2014-04-01 14:10:00,83.28176146948095 171,2014-04-01 14:15:00,74.61209219977142 172,2014-04-01 14:20:00,87.43552404396192 173,2014-04-01 14:25:00,77.58553747455238 174,2014-04-01 14:30:00,77.19131153154285 175,2014-04-01 14:35:00,78.05185466793333 176,2014-04-01 14:40:00,82.54086029622381 177,2014-04-01 14:45:00,82.02809946021429 178,2014-04-01 14:50:00,81.18319143010476 179,2014-04-01 14:55:00,84.80842798599524 180,2014-04-01 15:00:00,78.40314959548569 181,2014-04-01 15:05:00,85.85894721047619 182,2014-04-01 15:10:00,76.15859539126667 183,2014-04-01 15:15:00,85.88272835755714 184,2014-04-01 15:20:00,83.98921614184762 185,2014-04-01 15:25:00,84.3070249072381 186,2014-04-01 15:30:00,81.08801775882857 187,2014-04-01 15:35:00,84.06259991911905 188,2014-04-01 15:40:00,74.67485881190952 189,2014-04-01 15:45:00,87.0302458745 190,2014-04-01 15:50:00,74.30174647989048 191,2014-04-01 15:55:00,75.80028106358095 192,2014-04-01 16:00:00,82.65705080557143 193,2014-04-01 16:05:00,85.2664342373619 194,2014-04-01 16:10:00,74.66333682805238 195,2014-04-01 16:15:00,88.18296335724288 196,2014-04-01 16:20:00,89.03588756493333 197,2014-04-01 16:25:00,83.16081972282379 198,2014-04-01 16:30:00,81.1729565479143 199,2014-04-01 16:35:00,85.34281330270476 200,2014-04-01 16:40:00,78.74166454819525 201,2014-04-01 16:45:00,81.38761326688571 202,2014-04-01 16:50:00,88.16122623537619 203,2014-04-01 16:55:00,88.80073587276668 204,2014-04-01 17:00:00,88.35092965575714 205,2014-04-01 17:05:00,77.72443742994763 206,2014-04-01 17:10:00,77.25221366243811 207,2014-04-01 17:15:00,78.30278118942857 208,2014-04-01 17:20:00,80.60856648641905 209,2014-04-01 17:25:00,78.58170855020953 210,2014-04-01 17:30:00,79.54987478470001 211,2014-04-01 17:35:00,83.50010024889049 212,2014-04-01 17:40:00,85.77775945288096 213,2014-04-01 17:45:00,85.35372043357143 214,2014-04-01 17:50:00,86.6230063261619 215,2014-04-01 17:55:00,74.11462498665237 216,2014-04-01 18:00:00,30.71263352284286 217,2014-04-01 18:05:00,35.46662778213334 218,2014-04-01 18:10:00,33.833722087723814 219,2014-04-01 18:15:00,34.12955835781428 220,2014-04-01 18:20:00,30.773455073104763 221,2014-04-01 18:25:00,32.07834772229524 222,2014-04-01 18:30:00,34.537246951585715 223,2014-04-01 18:35:00,35.95798370177619 224,2014-04-01 18:40:00,36.33535375226666 225,2014-04-01 18:45:00,33.676785771657144 226,2014-04-01 18:50:00,33.97257650864762 227,2014-04-01 18:55:00,35.82049918083809 228,2014-04-01 19:00:00,24.26498554472857 229,2014-04-01 19:05:00,24.179394009119047 230,2014-04-01 19:10:00,25.92608468460952 231,2014-04-01 19:15:00,25.417647290300003 232,2014-04-01 19:20:00,25.958834064990477 233,2014-04-01 19:25:00,22.871376598280953 234,2014-04-01 19:30:00,24.250272373971427 235,2014-04-01 19:35:00,25.682785727861905 236,2014-04-01 19:40:00,22.41389351475238 237,2014-04-01 19:45:00,25.483478007142857 238,2014-04-01 19:50:00,22.750552940133332 239,2014-04-01 19:55:00,25.55864452732381 240,2014-04-01 20:00:00,22.724469874714284 241,2014-04-01 20:05:00,21.016649152304762 242,2014-04-01 20:10:00,22.171453712195238 243,2014-04-01 20:15:00,23.033119021385716 244,2014-04-01 20:20:00,22.84373742017619 245,2014-04-01 20:25:00,22.00492094026667 246,2014-04-01 20:30:00,23.946162179957142 247,2014-04-01 20:35:00,22.39670031804762 248,2014-04-01 20:40:00,22.349270303938095 249,2014-04-01 20:45:00,20.539656763628575 250,2014-04-01 20:50:00,24.06912389771905 251,2014-04-01 20:55:00,21.025028759209526 252,2014-04-01 21:00:00,22.0849229424 253,2014-04-01 21:05:00,23.198539327590474 254,2014-04-01 21:10:00,20.842230716780954 255,2014-04-01 21:15:00,22.103340106171427 256,2014-04-01 21:20:00,20.958522645261905 257,2014-04-01 21:25:00,23.05196846445238 258,2014-04-01 21:30:00,22.27424282924286 259,2014-04-01 21:35:00,23.45382145873333 260,2014-04-01 21:40:00,23.61633128162381 261,2014-04-01 21:45:00,22.635753847714284 262,2014-04-01 21:50:00,22.951297207104762 263,2014-04-01 21:55:00,22.250670613895238 264,2014-04-01 22:00:00,21.520756843285717 265,2014-04-01 22:05:00,22.58396664527619 266,2014-04-01 22:10:00,23.633088978266667 267,2014-04-01 22:15:00,21.672208707557143 268,2014-04-01 22:20:00,21.27017504954762 269,2014-04-01 22:25:00,21.574007437638095 270,2014-04-01 22:30:00,21.76947100942857 271,2014-04-01 22:35:00,20.32817562891905 272,2014-04-01 22:40:00,22.03677089240952 273,2014-04-01 22:45:00,22.0276851491 274,2014-04-01 22:50:00,22.412005401090475 275,2014-04-01 22:55:00,21.516084293580953 276,2014-04-01 23:00:00,22.509928676971427 277,2014-04-01 23:05:00,23.578007613861903 278,2014-04-01 23:10:00,23.89452614255238 279,2014-04-01 23:15:00,22.41424593384286 280,2014-04-01 23:20:00,20.257185857233335 281,2014-04-01 23:25:00,23.97191816972381 282,2014-04-01 23:30:00,22.925660629314283 283,2014-04-01 23:35:00,21.453223374304763 284,2014-04-01 23:40:00,20.705295057195237 285,2014-04-01 23:45:00,20.697776306885714 286,2014-04-01 23:50:00,20.80253864087619 287,2014-04-01 23:55:00,20.32119775106667 288,2014-04-02 00:00:00,23.751473897457142 289,2014-04-02 00:05:00,22.31337055034762 290,2014-04-02 00:10:00,22.957575746138094 291,2014-04-02 00:15:00,23.477612608528574 292,2014-04-02 00:20:00,23.338783072919046 293,2014-04-02 00:25:00,23.71048201870952 294,2014-04-02 00:30:00,24.056518490100004 295,2014-04-02 00:35:00,21.95122293519048 296,2014-04-02 00:40:00,24.003722819080952 297,2014-04-02 00:45:00,23.102981221971426 298,2014-04-02 00:50:00,20.499934665961906 299,2014-04-02 00:55:00,22.951834865752378 300,2014-04-02 01:00:00,22.979009495542858 301,2014-04-02 01:05:00,23.863025588533333 302,2014-04-02 01:10:00,21.73875233942381 303,2014-04-02 01:15:00,22.594110286814285 304,2014-04-02 01:20:00,20.310654965904764 305,2014-04-02 01:25:00,21.597646206795236 306,2014-04-02 01:30:00,20.525760618885716 307,2014-04-02 01:35:00,22.371718081576187 308,2014-04-02 01:40:00,23.56145726866667 309,2014-04-02 01:45:00,21.124877911357142 310,2014-04-02 01:50:00,22.41631180124762 311,2014-04-02 01:55:00,21.130022641238092 312,2014-04-02 02:00:00,20.80418244282857 313,2014-04-02 02:05:00,22.372856215319047 314,2014-04-02 02:10:00,20.65290400760952 315,2014-04-02 02:15:00,22.6931685246 316,2014-04-02 02:20:00,20.47654031889048 317,2014-04-02 02:25:00,20.785490839880953 318,2014-04-02 02:30:00,22.566061370471427 319,2014-04-02 02:35:00,22.739141556361908 320,2014-04-02 02:40:00,20.49690010135238 321,2014-04-02 02:45:00,22.681900009142858 322,2014-04-02 02:50:00,23.749843434633334 323,2014-04-02 02:55:00,23.29253851872381 324,2014-04-02 03:00:00,20.935454701414283 325,2014-04-02 03:05:00,22.788053352204763 326,2014-04-02 03:10:00,23.11460523839524 327,2014-04-02 03:15:00,20.581960521285716 328,2014-04-02 03:20:00,23.86186686517619 329,2014-04-02 03:25:00,24.07298625586667 330,2014-04-02 03:30:00,23.857166236257143 331,2014-04-02 03:35:00,23.76132349104762 332,2014-04-02 03:40:00,23.450098889038095 333,2014-04-02 03:45:00,23.011406696528574 334,2014-04-02 03:50:00,23.199627067619048 335,2014-04-02 03:55:00,23.718140697109526 336,2014-04-02 04:00:00,23.1499938334 337,2014-04-02 04:05:00,21.818348302890474 338,2014-04-02 04:10:00,22.01872536098095 339,2014-04-02 04:15:00,24.110551302071425 340,2014-04-02 04:20:00,20.598250247961904 341,2014-04-02 04:25:00,23.33248470595238 342,2014-04-02 04:30:00,24.363753066842854 343,2014-04-02 04:35:00,23.376996013133333 344,2014-04-02 04:40:00,24.53517176242381 345,2014-04-02 04:45:00,23.317143907814284 346,2014-04-02 04:50:00,20.711856878804763 347,2014-04-02 04:55:00,23.88988476469524 348,2014-04-02 05:00:00,21.727805362085714 349,2014-04-02 05:05:00,22.38095509317619 350,2014-04-02 05:10:00,21.852534330266668 351,2014-04-02 05:15:00,21.685823567657142 352,2014-04-02 05:20:00,22.34467043374762 353,2014-04-02 05:25:00,22.141493889038095 354,2014-04-02 05:30:00,23.167282898828574 355,2014-04-02 05:35:00,23.893973851619048 356,2014-04-02 05:40:00,21.83716413650952 357,2014-04-02 05:45:00,21.5111346113 358,2014-04-02 05:50:00,23.331271559690475 359,2014-04-02 05:55:00,23.352411215680952 360,2014-04-02 06:00:00,24.283096385671428 361,2014-04-02 06:05:00,20.749794650561903 362,2014-04-02 06:10:00,24.10561502945238 363,2014-04-02 06:15:00,22.78490154894286 364,2014-04-02 06:20:00,23.19354169003333 365,2014-04-02 06:25:00,21.08125957172381 366,2014-04-02 06:30:00,22.453674017214286 367,2014-04-02 06:35:00,21.639864390904762 368,2014-04-02 06:40:00,21.754995358395238 369,2014-04-02 06:45:00,22.761916172985714 370,2014-04-02 06:50:00,24.00279999207619 371,2014-04-02 06:55:00,23.735540387266667 372,2014-04-02 07:00:00,23.131856979157142 373,2014-04-02 07:05:00,22.93297039004762 374,2014-04-02 07:10:00,22.491962268138096 375,2014-04-02 07:15:00,24.68101846562857 376,2014-04-02 07:20:00,23.038389264519047 377,2014-04-02 07:25:00,21.820925117009523 378,2014-04-02 07:30:00,21.732863168199998 379,2014-04-02 07:35:00,23.265352599290473 380,2014-04-02 07:40:00,22.918691061580954 381,2014-04-02 07:45:00,20.865612640371427 382,2014-04-02 07:50:00,24.162523393561905 383,2014-04-02 07:55:00,23.66619179785238 384,2014-04-02 08:00:00,23.504460015842856 385,2014-04-02 08:05:00,21.13970596413333 386,2014-04-02 08:10:00,22.32024721022381 387,2014-04-02 08:15:00,24.620993328614283 388,2014-04-02 08:20:00,24.337261727304764 389,2014-04-02 08:25:00,22.03651698959524 390,2014-04-02 08:30:00,21.530021250685717 391,2014-04-02 08:35:00,22.705578019176187 392,2014-04-02 08:40:00,22.339988181366667 393,2014-04-02 08:45:00,23.653012649657143 394,2014-04-02 08:50:00,24.797286859347622 395,2014-04-02 08:55:00,22.390993895138095 396,2014-04-02 09:00:00,64.99267731952858 397,2014-04-02 09:05:00,76.36141956111905 398,2014-04-02 09:10:00,64.67742585510952 399,2014-04-02 09:15:00,77.1263662013 400,2014-04-02 09:20:00,73.21447069709048 401,2014-04-02 09:25:00,76.99060418718095 402,2014-04-02 09:30:00,66.90644316697144 403,2014-04-02 09:35:00,64.75202912026191 404,2014-04-02 09:40:00,70.84560808555239 405,2014-04-02 09:45:00,70.34187129534286 406,2014-04-02 09:50:00,68.72912824963333 407,2014-04-02 09:55:00,77.25240186122382 408,2014-04-02 10:00:00,85.64221380881429 409,2014-04-02 10:05:00,83.15090773360475 410,2014-04-02 10:10:00,75.41815592429523 411,2014-04-02 10:15:00,84.29473500988571 412,2014-04-02 10:20:00,84.18870948737619 413,2014-04-02 10:25:00,79.50997472116667 414,2014-04-02 10:30:00,87.27303446165713 415,2014-04-02 10:35:00,75.51929435124762 416,2014-04-02 10:40:00,77.08431706383809 417,2014-04-02 10:45:00,73.92392031662857 418,2014-04-02 10:50:00,85.29551791851905 419,2014-04-02 10:55:00,82.60726519600952 420,2014-04-02 11:00:00,79.7018106216 421,2014-04-02 11:05:00,77.30573298199049 422,2014-04-02 11:10:00,75.34639108688094 423,2014-04-02 11:15:00,77.36724295197143 424,2014-04-02 11:20:00,81.93180092016188 425,2014-04-02 11:25:00,78.66130489605239 426,2014-04-02 11:30:00,78.85649540704286 427,2014-04-02 11:35:00,88.67024986883332 428,2014-04-02 11:40:00,82.94527336822381 429,2014-04-02 11:45:00,86.3579876663143 430,2014-04-02 11:50:00,75.33535169520476 431,2014-04-02 11:55:00,80.58240324679524 432,2014-04-02 12:00:00,82.78539522118571 433,2014-04-02 12:05:00,78.1144166701762 434,2014-04-02 12:10:00,77.06352365216668 435,2014-04-02 12:15:00,89.05835776635715 436,2014-04-02 12:20:00,90.17051656544761 437,2014-04-02 12:25:00,76.42448217533808 438,2014-04-02 12:30:00,80.75012681282857 439,2014-04-02 12:35:00,90.49414001391904 440,2014-04-02 12:40:00,76.51640054860951 441,2014-04-02 12:45:00,85.4807540517 442,2014-04-02 12:50:00,90.73916576129048 443,2014-04-02 12:55:00,90.84252775528095 444,2014-04-02 13:00:00,82.82405522547143 445,2014-04-02 13:05:00,77.8970926726619 446,2014-04-02 13:10:00,78.53374541685238 447,2014-04-02 13:15:00,89.53881910974286 448,2014-04-02 13:20:00,89.8994805398333 449,2014-04-02 13:25:00,85.04723385362381 450,2014-04-02 13:30:00,87.58681455981429 451,2014-04-02 13:35:00,87.17443344940476 452,2014-04-02 13:40:00,85.93241941099524 453,2014-04-02 13:45:00,88.5865102486857 454,2014-04-02 13:50:00,86.3245701976762 455,2014-04-02 13:55:00,83.91012298976668 456,2014-04-02 14:00:00,79.18052096175714 457,2014-04-02 14:05:00,87.29848061884762 458,2014-04-02 14:10:00,82.9789243803381 459,2014-04-02 14:15:00,80.12816311552857 460,2014-04-02 14:20:00,88.24968756471905 461,2014-04-02 14:25:00,86.57348605340952 462,2014-04-02 14:30:00,90.4307571332 463,2014-04-02 14:35:00,78.08842365729048 464,2014-04-02 14:40:00,85.83545492918095 465,2014-04-02 14:45:00,79.36400934207144 466,2014-04-02 14:50:00,89.9204397178619 467,2014-04-02 14:55:00,77.06316059355238 468,2014-04-02 15:00:00,85.97993977384286 469,2014-04-02 15:05:00,88.14614216703333 470,2014-04-02 15:10:00,81.17496354002381 471,2014-04-02 15:15:00,90.7698358002143 472,2014-04-02 15:20:00,89.12277384300475 473,2014-04-02 15:25:00,80.23250157969524 474,2014-04-02 15:30:00,75.64675083938572 475,2014-04-02 15:35:00,80.28000424177621 476,2014-04-02 15:40:00,80.04189978486667 477,2014-04-02 15:45:00,89.78771296435714 478,2014-04-02 15:50:00,91.02964672134762 479,2014-04-02 15:55:00,76.69032585113808 480,2014-04-02 16:00:00,83.11199310982857 481,2014-04-02 16:05:00,84.35202593931905 482,2014-04-02 16:10:00,77.07275501080952 483,2014-04-02 16:15:00,81.6335635095 484,2014-04-02 16:20:00,80.67436117369049 485,2014-04-02 16:25:00,84.18537791398094 486,2014-04-02 16:30:00,86.19496727247143 487,2014-04-02 16:35:00,86.87911382166189 488,2014-04-02 16:40:00,77.81889031765238 489,2014-04-02 16:45:00,88.64539287454286 490,2014-04-02 16:50:00,86.50234672513334 491,2014-04-02 16:55:00,89.87830692512381 492,2014-04-02 17:00:00,82.85006082791429 493,2014-04-02 17:05:00,89.97035782540476 494,2014-04-02 17:10:00,89.52794822849523 495,2014-04-02 17:15:00,82.6975546904857 496,2014-04-02 17:20:00,181.78873924537623 497,2014-04-02 17:25:00,90.62287552696668 498,2014-04-02 17:30:00,87.14796085345715 499,2014-04-02 17:35:00,90.56468981094763 500,2014-04-02 17:40:00,88.4718020129381 501,2014-04-02 17:45:00,85.47640620852857 502,2014-04-02 17:50:00,77.58873511991905 503,2014-04-02 17:55:00,80.40622084620952 504,2014-04-02 18:00:00,38.750584685300005 505,2014-04-02 18:05:00,34.60173598589047 506,2014-04-02 18:10:00,33.16170647478095 507,2014-04-02 18:15:00,37.10065650737143 508,2014-04-02 18:20:00,37.2773827022619 509,2014-04-02 18:25:00,34.41412591045238 510,2014-04-02 18:30:00,34.49973762954286 511,2014-04-02 18:35:00,35.602992334833345 512,2014-04-02 18:40:00,32.74896753162381 513,2014-04-02 18:45:00,37.66862505251428 514,2014-04-02 18:50:00,34.65376708120476 515,2014-04-02 18:55:00,38.09592251219524 516,2014-04-02 19:00:00,27.595068699885715 517,2014-04-02 19:05:00,26.969806030376187 518,2014-04-02 19:10:00,25.46960488546667 519,2014-04-02 19:15:00,26.334704106257146 520,2014-04-02 19:20:00,26.02188147784762 521,2014-04-02 19:25:00,25.554677756438092 522,2014-04-02 19:30:00,27.84357783312857 523,2014-04-02 19:35:00,26.217479517019047 524,2014-04-02 19:40:00,27.78940769140953 525,2014-04-02 19:45:00,24.5376276324 526,2014-04-02 19:50:00,24.705480388590473 527,2014-04-02 19:55:00,28.459524573180953 528,2014-04-02 20:00:00,24.768070801371426 529,2014-04-02 20:05:00,24.456028241161906 530,2014-04-02 20:10:00,24.51829936865238 531,2014-04-02 20:15:00,23.264633523842857 532,2014-04-02 20:20:00,25.334144454033332 533,2014-04-02 20:25:00,22.74503501892381 534,2014-04-02 20:30:00,24.753547965214285 535,2014-04-02 20:35:00,24.750523503504763 536,2014-04-02 20:40:00,26.164610757195234 537,2014-04-02 20:45:00,24.582780257385714 538,2014-04-02 20:50:00,22.99638476527619 539,2014-04-02 20:55:00,24.788413767166666 540,2014-04-02 21:00:00,22.471321165957143 541,2014-04-02 21:05:00,22.93078575564762 542,2014-04-02 21:10:00,22.244169672238094 543,2014-04-02 21:15:00,24.18960808872857 544,2014-04-02 21:20:00,22.473772489919046 545,2014-04-02 21:25:00,24.028049361109524 546,2014-04-02 21:30:00,25.898592632600003 547,2014-04-02 21:35:00,25.04920549609048 548,2014-04-02 21:40:00,22.47491390838095 549,2014-04-02 21:45:00,23.072365459371426 550,2014-04-02 21:50:00,24.886245851961906 551,2014-04-02 21:55:00,25.782088047752378 552,2014-04-02 22:00:00,22.25622360264286 553,2014-04-02 22:05:00,25.384787662133334 554,2014-04-02 22:10:00,24.388716686223813 555,2014-04-02 22:15:00,24.333206567714285 556,2014-04-02 22:20:00,25.989115484804763 557,2014-04-02 22:25:00,25.155074633495236 558,2014-04-02 22:30:00,25.572805632485714 559,2014-04-02 22:35:00,23.59384780207619 560,2014-04-02 22:40:00,24.403531577966667 561,2014-04-02 22:45:00,24.65537300035714 562,2014-04-02 22:50:00,23.486398253347616 563,2014-04-02 22:55:00,24.489450337838093 564,2014-04-02 23:00:00,23.14668783882857 565,2014-04-02 23:05:00,22.780937842619046 566,2014-04-02 23:10:00,23.71093376820952 567,2014-04-02 23:15:00,25.1799322874 568,2014-04-02 23:20:00,25.89509869809048 569,2014-04-02 23:25:00,24.06829468078095 570,2014-04-02 23:30:00,24.816315868271428 571,2014-04-02 23:35:00,22.664195559361904 572,2014-04-02 23:40:00,25.87795804125238 573,2014-04-02 23:45:00,24.541702397442858 574,2014-04-02 23:50:00,25.39624162153333 575,2014-04-02 23:55:00,25.46010474192381 576,2014-04-03 00:00:00,23.311636391214286 577,2014-04-03 00:05:00,24.409852574604763 578,2014-04-03 00:10:00,26.142514244295235 579,2014-04-03 00:15:00,22.666573893585717 580,2014-04-03 00:20:00,25.04767578257619 581,2014-04-03 00:25:00,26.171972978766668 582,2014-04-03 00:30:00,23.53266557505714 583,2014-04-03 00:35:00,25.78358930464762 584,2014-04-03 00:40:00,26.079868276838095 585,2014-04-03 00:45:00,25.341023409028573 586,2014-04-03 00:50:00,23.28543229681905 587,2014-04-03 00:55:00,23.703562399109522 588,2014-04-03 01:00:00,22.5182371777 589,2014-04-03 01:05:00,25.708253413190477 590,2014-04-03 01:10:00,25.78832569838095 591,2014-04-03 01:15:00,24.928162668471426 592,2014-04-03 01:20:00,23.814873309861905 593,2014-04-03 01:25:00,22.71944649155238 594,2014-04-03 01:30:00,25.43187329684286 595,2014-04-03 01:35:00,25.33318810773333 596,2014-04-03 01:40:00,26.084933896523808 597,2014-04-03 01:45:00,25.364092369714285 598,2014-04-03 01:50:00,25.764184530904764 599,2014-04-03 01:55:00,25.440663709695237 600,2014-04-03 02:00:00,24.987034467485714 601,2014-04-03 02:05:00,24.17959176727619 602,2014-04-03 02:10:00,26.087635901266665 603,2014-04-03 02:15:00,25.090481430457142 604,2014-04-03 02:20:00,24.08746890694762 605,2014-04-03 02:25:00,22.835365275938095 606,2014-04-03 02:30:00,23.671747995028568 607,2014-04-03 02:35:00,24.69127598691905 608,2014-04-03 02:40:00,23.626351003909527 609,2014-04-03 02:45:00,23.4161913917 610,2014-04-03 02:50:00,24.648264532590474 611,2014-04-03 02:55:00,23.225412335980952 612,2014-04-03 03:00:00,25.755211681871426 613,2014-04-03 03:05:00,24.498484510161905 614,2014-04-03 03:10:00,24.86390347685238 615,2014-04-03 03:15:00,23.165425927542856 616,2014-04-03 03:20:00,23.881638675833333 617,2014-04-03 03:25:00,24.23113254252381 618,2014-04-03 03:30:00,25.831065607814285 619,2014-04-03 03:35:00,25.686292854204762 620,2014-04-03 03:40:00,23.50500513729524 621,2014-04-03 03:45:00,25.085252040685717 622,2014-04-03 03:50:00,23.60180162157619 623,2014-04-03 03:55:00,26.58840528946667 624,2014-04-03 04:00:00,26.45135265535714 625,2014-04-03 04:05:00,24.90335650114762 626,2014-04-03 04:10:00,25.453348382838094 627,2014-04-03 04:15:00,25.870900100228575 628,2014-04-03 04:20:00,25.556612727819047 629,2014-04-03 04:25:00,25.479374288109526 630,2014-04-03 04:30:00,26.521716031799997 631,2014-04-03 04:35:00,25.080764901390474 632,2014-04-03 04:40:00,25.24759163968095 633,2014-04-03 04:45:00,26.106896430371428 634,2014-04-03 04:50:00,25.396825376161907 635,2014-04-03 04:55:00,25.656432869052377 636,2014-04-03 05:00:00,23.66881760194286 637,2014-04-03 05:05:00,24.224651029833332 638,2014-04-03 05:10:00,23.33622919232381 639,2014-04-03 05:15:00,24.777526055014285 640,2014-04-03 05:20:00,24.584814364604764 641,2014-04-03 05:25:00,26.757996495195236 642,2014-04-03 05:30:00,25.221620325585718 643,2014-04-03 05:35:00,25.93000548327619 644,2014-04-03 05:40:00,24.12772534966667 645,2014-04-03 05:45:00,26.125288468257143 646,2014-04-03 05:50:00,25.26688748504762 647,2014-04-03 05:55:00,25.601957421638097 648,2014-04-03 06:00:00,23.999151683228575 649,2014-04-03 06:05:00,25.023422614419047 650,2014-04-03 06:10:00,25.372457417509523 651,2014-04-03 06:15:00,25.2001287033 652,2014-04-03 06:20:00,26.51196532189048 653,2014-04-03 06:25:00,26.451721610380954 654,2014-04-03 06:30:00,26.75000766007143 655,2014-04-03 06:35:00,25.543223928761908 656,2014-04-03 06:40:00,26.76860890145238 657,2014-04-03 06:45:00,26.218304857242856 658,2014-04-03 06:50:00,23.979161894733334 659,2014-04-03 06:55:00,24.613016487723808 660,2014-04-03 07:00:00,23.864284054514286 661,2014-04-03 07:05:00,22.934943405204763 662,2014-04-03 07:10:00,23.67779025069524 663,2014-04-03 07:15:00,22.949278059385716 664,2014-04-03 07:20:00,25.81983003587619 665,2014-04-03 07:25:00,24.650053857566668 666,2014-04-03 07:30:00,24.205656051157142 667,2014-04-03 07:35:00,26.00968118344762 668,2014-04-03 07:40:00,26.300185193738095 669,2014-04-03 07:45:00,26.878876726028572 670,2014-04-03 07:50:00,25.553173386319045 671,2014-04-03 07:55:00,24.838675358009525 672,2014-04-03 08:00:00,24.2210572064 673,2014-04-03 08:05:00,23.89671331309048 674,2014-04-03 08:10:00,23.866584754280954 675,2014-04-03 08:15:00,24.659078927471427 676,2014-04-03 08:20:00,26.996907325961903 677,2014-04-03 08:25:00,23.04061717065238 678,2014-04-03 08:30:00,23.83346644604286 679,2014-04-03 08:35:00,23.805655262933332 680,2014-04-03 08:40:00,25.92800175162381 681,2014-04-03 08:45:00,24.476903196114286 682,2014-04-03 08:50:00,24.90344798030476 683,2014-04-03 08:55:00,23.67634175999524 684,2014-04-03 09:00:00,71.79724544298571 685,2014-04-03 09:05:00,67.70024363237619 686,2014-04-03 09:10:00,73.55355538196667 687,2014-04-03 09:15:00,67.64356891205715 688,2014-04-03 09:20:00,77.06996160304762 689,2014-04-03 09:25:00,74.03227145383809 690,2014-04-03 09:30:00,76.17989165472856 691,2014-04-03 09:35:00,72.03319190611906 692,2014-04-03 09:40:00,71.53709111190952 693,2014-04-03 09:45:00,67.6918908911 694,2014-04-03 09:50:00,73.48812673199048 695,2014-04-03 09:55:00,73.36836039448094 696,2014-04-03 10:00:00,82.28351515847143 697,2014-04-03 10:05:00,86.51885692466189 698,2014-04-03 10:10:00,87.95392066945239 699,2014-04-03 10:15:00,86.69314861234287 700,2014-04-03 10:20:00,77.28112966173333 701,2014-04-03 10:25:00,84.71013739362381 702,2014-04-03 10:30:00,76.30982888601429 703,2014-04-03 10:35:00,85.85119266300475 704,2014-04-03 10:40:00,81.00423801669524 705,2014-04-03 10:45:00,77.14191951558571 706,2014-04-03 10:50:00,88.47200549077618 707,2014-04-03 10:55:00,84.62982608856667 708,2014-04-03 11:00:00,82.47740303305714 709,2014-04-03 11:05:00,77.33198268424762 710,2014-04-03 11:10:00,85.39612045443809 711,2014-04-03 11:15:00,91.54116294282856 712,2014-04-03 11:20:00,86.35044390691905 713,2014-04-03 11:25:00,92.32619073970952 714,2014-04-03 11:30:00,79.050618585 715,2014-04-03 11:35:00,85.92626485969049 716,2014-04-03 11:40:00,89.58876171588095 717,2014-04-03 11:45:00,85.26102121637143 718,2014-04-03 11:50:00,78.3585812303619 719,2014-04-03 11:55:00,86.18792134955238 720,2014-04-03 12:00:00,87.04680398284286 721,2014-04-03 12:05:00,88.92354009133334 722,2014-04-03 12:10:00,89.4503927911238 723,2014-04-03 12:15:00,89.6106284615143 724,2014-04-03 12:20:00,87.90287692780475 725,2014-04-03 12:25:00,80.75678064599524 726,2014-04-03 12:30:00,83.77539648118571 727,2014-04-03 12:35:00,89.72600405687619 728,2014-04-03 12:40:00,92.56679260296666 729,2014-04-03 12:45:00,78.59934279855713 730,2014-04-03 12:50:00,85.90345215954763 731,2014-04-03 12:55:00,82.34694400883808 732,2014-04-03 13:00:00,81.03458536792857 733,2014-04-03 13:05:00,85.52761767091906 734,2014-04-03 13:10:00,87.13913158960952 735,2014-04-03 13:15:00,77.6077881773 736,2014-04-03 13:20:00,89.93921963819048 737,2014-04-03 13:25:00,90.58131670518095 738,2014-04-03 13:30:00,92.91825706007143 739,2014-04-03 13:35:00,80.3708379644619 740,2014-04-03 13:40:00,86.99923029685237 741,2014-04-03 13:45:00,84.32048059134286 742,2014-04-03 13:50:00,82.85951321923334 743,2014-04-03 13:55:00,86.55895700002381 744,2014-04-03 14:00:00,90.0497869071143 745,2014-04-03 14:05:00,77.90852559250476 746,2014-04-03 14:10:00,93.05679653989525 747,2014-04-03 14:15:00,90.5120630964857 748,2014-04-03 14:20:00,89.57990256277618 749,2014-04-03 14:25:00,89.73507480406667 750,2014-04-03 14:30:00,83.80157369815714 751,2014-04-03 14:35:00,89.60969318794763 752,2014-04-03 14:40:00,83.7798083933381 753,2014-04-03 14:45:00,91.97784163782856 754,2014-04-03 14:50:00,80.44208507371904 755,2014-04-03 14:55:00,82.29143778840952 756,2014-04-03 15:00:00,86.4456247977 757,2014-04-03 15:05:00,82.73907681959048 758,2014-04-03 15:10:00,84.42692051428095 759,2014-04-03 15:15:00,85.52531762287143 760,2014-04-03 15:20:00,91.3555927498619 761,2014-04-03 15:25:00,86.03250687635239 762,2014-04-03 15:30:00,83.46825356114286 763,2014-04-03 15:35:00,81.64013270563332 764,2014-04-03 15:40:00,84.22258549752381 765,2014-04-03 15:45:00,85.94297153931429 766,2014-04-03 15:50:00,89.63643667390475 767,2014-04-03 15:55:00,79.64291586379524 768,2014-04-03 16:00:00,81.25988767828571 769,2014-04-03 16:05:00,83.79604054137619 770,2014-04-03 16:10:00,83.49539183716668 771,2014-04-03 16:15:00,84.00442627005714 772,2014-04-03 16:20:00,90.44022523634762 773,2014-04-03 16:25:00,82.93781034463808 774,2014-04-03 16:30:00,85.78914579952857 775,2014-04-03 16:35:00,87.74872416691906 776,2014-04-03 16:40:00,81.48852095420952 777,2014-04-03 16:45:00,89.280215876 778,2014-04-03 16:50:00,86.54231654479048 779,2014-04-03 16:55:00,84.94447759578095 780,2014-04-03 17:00:00,90.76008323307143 781,2014-04-03 17:05:00,81.7069069076619 782,2014-04-03 17:10:00,91.94923483655238 783,2014-04-03 17:15:00,86.80264152794284 784,2014-04-03 17:20:00,87.58010001263334 785,2014-04-03 17:25:00,91.8416842118238 786,2014-04-03 17:30:00,90.92950462011429 787,2014-04-03 17:35:00,87.48061651910476 788,2014-04-03 17:40:00,89.91406622409525 789,2014-04-03 17:45:00,84.80361724768571 790,2014-04-03 17:50:00,86.63598923537619 791,2014-04-03 17:55:00,78.87851082466668 792,2014-04-03 18:00:00,35.26794217805714 793,2014-04-03 18:05:00,40.008613657047626 794,2014-04-03 18:10:00,35.0896310886381 795,2014-04-03 18:15:00,35.79932723772857 796,2014-04-03 18:20:00,39.81594155741905 797,2014-04-03 18:25:00,34.73738807680952 798,2014-04-03 18:30:00,36.544881828 799,2014-04-03 18:35:00,38.482781638990474 800,2014-04-03 18:40:00,38.56325425248095 801,2014-04-03 18:45:00,39.73359355667143 802,2014-04-03 18:50:00,38.0051837822619 803,2014-04-03 18:55:00,38.03486819035238 804,2014-04-03 19:00:00,29.391532951442855 805,2014-04-03 19:05:00,28.38341970033333 806,2014-04-03 19:10:00,28.88306262182381 807,2014-04-03 19:15:00,30.186490784914284 808,2014-04-03 19:20:00,27.97040407140476 809,2014-04-03 19:25:00,27.90470435519524 810,2014-04-03 19:30:00,26.202684091085715 811,2014-04-03 19:35:00,28.942374585376186 812,2014-04-03 19:40:00,26.335043698566665 813,2014-04-03 19:45:00,28.467691147057142 814,2014-04-03 19:50:00,29.819513690347627 815,2014-04-03 19:55:00,28.68763325013809 816,2014-04-03 20:00:00,25.60785806972857 817,2014-04-03 20:05:00,27.731014642019048 818,2014-04-03 20:10:00,25.623070138109526 819,2014-04-03 20:15:00,86.09375 820,2014-04-03 20:20:00,27.03280885749048 821,2014-04-03 20:25:00,25.236935554280954 822,2014-04-03 20:30:00,28.255499514271428 823,2014-04-03 20:35:00,25.377348199061906 824,2014-04-03 20:40:00,28.61630076685238 825,2014-04-03 20:45:00,24.600336397142858 826,2014-04-03 20:50:00,25.65706101193333 827,2014-04-03 20:55:00,25.40390135612381 828,2014-04-03 21:00:00,24.303356555514284 829,2014-04-03 21:05:00,27.198087774704764 830,2014-04-03 21:10:00,27.049012170795237 831,2014-04-03 21:15:00,27.454052658185716 832,2014-04-03 21:20:00,25.308598941676188 833,2014-04-03 21:25:00,26.070188521566664 834,2014-04-03 21:30:00,26.94086615825714 835,2014-04-03 21:35:00,26.066715141347622 836,2014-04-03 21:40:00,27.109329780238095 837,2014-04-03 21:45:00,26.862144444128567 838,2014-04-03 21:50:00,24.782311452119046 839,2014-04-03 21:55:00,27.468127984109522 840,2014-04-03 22:00:00,27.1527528233 841,2014-04-03 22:05:00,26.900576420590475 842,2014-04-03 22:10:00,24.903130927780953 843,2014-04-03 22:15:00,25.362616320771426 844,2014-04-03 22:20:00,25.871259821261905 845,2014-04-03 22:25:00,25.42527578795238 846,2014-04-03 22:30:00,25.22403880204286 847,2014-04-03 22:35:00,27.54388657703333 848,2014-04-03 22:40:00,26.88218359672381 849,2014-04-03 22:45:00,26.598304214914286 850,2014-04-03 22:50:00,25.246363254404763 851,2014-04-03 22:55:00,28.024956890495236 852,2014-04-03 23:00:00,25.107620697385713 853,2014-04-03 23:05:00,27.53059644197619 854,2014-04-03 23:10:00,28.225055735966663 855,2014-04-03 23:15:00,27.273992464957143 856,2014-04-03 23:20:00,28.344701233147617 857,2014-04-03 23:25:00,26.984648568338095 858,2014-04-03 23:30:00,25.257392953528573 859,2014-04-03 23:35:00,25.21025955401905 860,2014-04-03 23:40:00,25.70077192430952 861,2014-04-03 23:45:00,24.438231555 862,2014-04-03 23:50:00,27.14446389889048 863,2014-04-03 23:55:00,25.49946442588095 864,2014-04-04 00:00:00,27.689304357771427 865,2014-04-04 00:05:00,25.872702506961904 866,2014-04-04 00:10:00,26.36327835485238 867,2014-04-04 00:15:00,28.313648523342856 868,2014-04-04 00:20:00,25.427021825533334 869,2014-04-04 00:25:00,27.35079019922381 870,2014-04-04 00:30:00,27.493685442914284 871,2014-04-04 00:35:00,25.364647392004763 872,2014-04-04 00:40:00,26.49208258449524 873,2014-04-04 00:45:00,25.89634341558571 874,2014-04-04 00:50:00,27.59060116407619 875,2014-04-04 00:55:00,27.000349942766668 876,2014-04-04 01:00:00,26.421789362257144 877,2014-04-04 01:05:00,27.64275067924762 878,2014-04-04 01:10:00,25.473360375238094 879,2014-04-04 01:15:00,27.55466609372857 880,2014-04-04 01:20:00,28.009116296019048 881,2014-04-04 01:25:00,28.06954591100952 882,2014-04-04 01:30:00,27.6971943721 883,2014-04-04 01:35:00,26.201997144190475 884,2014-04-04 01:40:00,28.504613043280955 885,2014-04-04 01:45:00,26.103196003871428 886,2014-04-04 01:50:00,27.146763501161907 887,2014-04-04 01:55:00,25.24399909325238 888,2014-04-04 02:00:00,28.528938451642855 889,2014-04-04 02:05:00,27.43052702083333 890,2014-04-04 02:10:00,27.635533990523808 891,2014-04-04 02:15:00,24.892571099314285 892,2014-04-04 02:20:00,27.690576018804762 893,2014-04-04 02:25:00,27.74323895499524 894,2014-04-04 02:30:00,27.338876619685713 895,2014-04-04 02:35:00,25.82686464567619 896,2014-04-04 02:40:00,26.625426835266666 897,2014-04-04 02:45:00,25.115844628057143 898,2014-04-04 02:50:00,26.567895884847616 899,2014-04-04 02:55:00,25.664283505638096 900,2014-04-04 03:00:00,26.092816517428567 901,2014-04-04 03:05:00,25.354270681219045 902,2014-04-04 03:10:00,25.63152699480952 903,2014-04-04 03:15:00,25.0250245673 904,2014-04-04 03:20:00,28.405795941890478 905,2014-04-04 03:25:00,26.855273704280954 906,2014-04-04 03:30:00,26.328039313671425 907,2014-04-04 03:35:00,26.888628755861905 908,2014-04-04 03:40:00,27.26912529485238 909,2014-04-04 03:45:00,28.450908030642857 910,2014-04-04 03:50:00,25.485605142433332 911,2014-04-04 03:55:00,25.96048380402381 912,2014-04-04 04:00:00,28.688871631114285 913,2014-04-04 04:05:00,26.277926708504765 914,2014-04-04 04:10:00,24.890841841095238 915,2014-04-04 04:15:00,25.39860968478571 916,2014-04-04 04:20:00,24.92083099747619 917,2014-04-04 04:25:00,28.782609236366667 918,2014-04-04 04:30:00,25.94584053885714 919,2014-04-04 04:35:00,28.53196864674762 920,2014-04-04 04:40:00,28.828783198238096 921,2014-04-04 04:45:00,27.252043456028574 922,2014-04-04 04:50:00,24.992904307919048 923,2014-04-04 04:55:00,25.193926045309524 924,2014-04-04 05:00:00,26.8013562204 925,2014-04-04 05:05:00,26.507128527790474 926,2014-04-04 05:10:00,27.31459017548095 927,2014-04-04 05:15:00,26.65271266737143 928,2014-04-04 05:20:00,28.641069301861904 929,2014-04-04 05:25:00,27.05116124265238 930,2014-04-04 05:30:00,27.694547102942856 931,2014-04-04 05:35:00,28.51302442393333 932,2014-04-04 05:40:00,25.52201131282381 933,2014-04-04 05:45:00,25.860902902214285 934,2014-04-04 05:50:00,25.378679403804764 935,2014-04-04 05:55:00,25.51539883499524 936,2014-04-04 06:00:00,27.014621581985715 937,2014-04-04 06:05:00,26.256443226376188 938,2014-04-04 06:10:00,26.671858024766664 939,2014-04-04 06:15:00,28.91656647005714 940,2014-04-04 06:20:00,25.62086501024762 941,2014-04-04 06:25:00,27.164736378438093 942,2014-04-04 06:30:00,25.40441319162857 943,2014-04-04 06:35:00,26.29035430071905 944,2014-04-04 06:40:00,27.133913218509527 945,2014-04-04 06:45:00,28.8177769839 946,2014-04-04 06:50:00,26.603603361290475 947,2014-04-04 06:55:00,25.305757737280953 948,2014-04-04 07:00:00,26.606217220371427 949,2014-04-04 07:05:00,25.643976608261905 950,2014-04-04 07:10:00,25.98841083415238 951,2014-04-04 07:15:00,27.548255349842858 952,2014-04-04 07:20:00,25.353028798133334 953,2014-04-04 07:25:00,26.94966883452381 954,2014-04-04 07:30:00,27.536060629714285 955,2014-04-04 07:35:00,26.793088331404764 956,2014-04-04 07:40:00,25.189600640595238 957,2014-04-04 07:45:00,29.062613141885713 958,2014-04-04 07:50:00,26.596439259876192 959,2014-04-04 07:55:00,28.249725414366665 960,2014-04-04 08:00:00,26.44544311155714 961,2014-04-04 08:05:00,27.050364647047616 962,2014-04-04 08:10:00,26.711592665638094 963,2014-04-04 08:15:00,26.53533548942857 964,2014-04-04 08:20:00,25.260024556419047 965,2014-04-04 08:25:00,26.62014327520952 966,2014-04-04 08:30:00,28.745459961599998 967,2014-04-04 08:35:00,27.956513830590474 968,2014-04-04 08:40:00,25.784072388780952 969,2014-04-04 08:45:00,27.574441447071425 970,2014-04-04 08:50:00,28.786185344561904 971,2014-04-04 08:55:00,28.02483854485238 972,2014-04-04 09:00:00,70.45425059324286 973,2014-04-04 09:05:00,80.24210528893333 974,2014-04-04 09:10:00,72.5480223902238 975,2014-04-04 09:15:00,74.6298998483143 976,2014-04-04 09:20:00,75.61744629370476 977,2014-04-04 09:25:00,80.03623505759523 978,2014-04-04 09:30:00,81.14664764828571 979,2014-04-04 09:35:00,81.12750532847619 980,2014-04-04 09:40:00,68.59984353206667 981,2014-04-04 09:45:00,81.03679054685713 982,2014-04-04 09:50:00,69.24621035664762 983,2014-04-04 09:55:00,72.1285098279381 984,2014-04-04 10:00:00,85.15404007682857 985,2014-04-04 10:05:00,84.61731574091905 986,2014-04-04 10:10:00,86.56140552490952 987,2014-04-04 10:15:00,84.62475547 988,2014-04-04 10:20:00,91.69270102419048 989,2014-04-04 10:25:00,80.93194907668095 990,2014-04-04 10:30:00,81.45893468007142 991,2014-04-04 10:35:00,91.5033646667619 992,2014-04-04 10:40:00,78.41194963425238 993,2014-04-04 10:45:00,86.68877681314287 994,2014-04-04 10:50:00,87.81637530943333 995,2014-04-04 10:55:00,85.08928135712381 996,2014-04-04 11:00:00,90.0197780865143 997,2014-04-04 11:05:00,81.73364465210476 998,2014-04-04 11:10:00,92.55385826809524 999,2014-04-04 11:15:00,81.2280042795857 1000,2014-04-04 11:20:00,85.38299730487618 1001,2014-04-04 11:25:00,80.21281355786667 1002,2014-04-04 11:30:00,87.69439414035713 1003,2014-04-04 11:35:00,89.68243494034762 1004,2014-04-04 11:40:00,94.00742697983807 1005,2014-04-04 11:45:00,90.80408143092856 1006,2014-04-04 11:50:00,87.65881983091903 1007,2014-04-04 11:55:00,93.89290056490952 1008,2014-04-04 12:00:00,87.0594034214 1009,2014-04-04 12:05:00,88.38955577719048 1010,2014-04-04 12:10:00,88.95461230338096 1011,2014-04-04 12:15:00,85.98772543197143 1012,2014-04-04 12:20:00,92.8429860861619 1013,2014-04-04 12:25:00,82.41006202445239 1014,2014-04-04 12:30:00,88.32506493304287 1015,2014-04-04 12:35:00,91.00754855383333 1016,2014-04-04 12:40:00,93.91938621702381 1017,2014-04-04 12:45:00,93.60628739541428 1018,2014-04-04 12:50:00,87.61808157920476 1019,2014-04-04 12:55:00,89.77367975689526 1020,2014-04-04 13:00:00,85.87829561948571 1021,2014-04-04 13:05:00,87.06849259397619 1022,2014-04-04 13:10:00,94.08365928716667 1023,2014-04-04 13:15:00,94.48201713055714 1024,2014-04-04 13:20:00,93.92495415814761 1025,2014-04-04 13:25:00,81.8226105401381 1026,2014-04-04 13:30:00,93.21472859002857 1027,2014-04-04 13:35:00,94.79426702721904 1028,2014-04-04 13:40:00,85.41013743820952 1029,2014-04-04 13:45:00,87.935319029 1030,2014-04-04 13:50:00,92.10894284339048 1031,2014-04-04 13:55:00,88.64494277338095 1032,2014-04-04 14:00:00,95.57008878057144 1033,2014-04-04 14:05:00,86.9736197593619 1034,2014-04-04 14:10:00,91.11253145225238 1035,2014-04-04 14:15:00,92.37828639024286 1036,2014-04-04 14:20:00,87.61010451633334 1037,2014-04-04 14:25:00,93.4234005373238 1038,2014-04-04 14:30:00,88.4578122983143 1039,2014-04-04 14:35:00,86.31329536290477 1040,2014-04-04 14:40:00,81.45973521109524 1041,2014-04-04 14:45:00,86.03639479428571 1042,2014-04-04 14:50:00,91.49193980297619 1043,2014-04-04 14:55:00,94.49683570556667 1044,2014-04-04 15:00:00,83.79399774665714 1045,2014-04-04 15:05:00,85.45832013214762 1046,2014-04-04 15:10:00,82.24539915253808 1047,2014-04-04 15:15:00,90.84094758402857 1048,2014-04-04 15:20:00,95.15979524281906 1049,2014-04-04 15:25:00,90.05950539110951 1050,2014-04-04 15:30:00,89.6849384971 1051,2014-04-04 15:35:00,88.67500314819048 1052,2014-04-04 15:40:00,81.24196801658096 1053,2014-04-04 15:45:00,91.50607939967142 1054,2014-04-04 15:50:00,89.47427092676189 1055,2014-04-04 15:55:00,90.43253787985239 1056,2014-04-04 16:00:00,94.23795449414287 1057,2014-04-04 16:05:00,92.40779360303333 1058,2014-04-04 16:10:00,92.3665056143238 1059,2014-04-04 16:15:00,94.71423786471429 1060,2014-04-04 16:20:00,95.72569533450476 1061,2014-04-04 16:25:00,89.19471285249524 1062,2014-04-04 16:30:00,81.6437499859857 1063,2014-04-04 16:35:00,87.2551523703762 1064,2014-04-04 16:40:00,92.51812257496667 1065,2014-04-04 16:45:00,80.36757324735714 1066,2014-04-04 16:50:00,80.84160664514762 1067,2014-04-04 16:55:00,81.01337231023808 1068,2014-04-04 17:00:00,91.64296856522857 1069,2014-04-04 17:05:00,87.97250437741904 1070,2014-04-04 17:10:00,85.86364670560953 1071,2014-04-04 17:15:00,81.6585944273 1072,2014-04-04 17:20:00,91.69200233259049 1073,2014-04-04 17:25:00,85.11991830088095 1074,2014-04-04 17:30:00,84.23622727147144 1075,2014-04-04 17:35:00,90.4355874737619 1076,2014-04-04 17:40:00,88.95009557995238 1077,2014-04-04 17:45:00,85.81193325154285 1078,2014-04-04 17:50:00,90.28460127693333 1079,2014-04-04 17:55:00,84.36778882132381 1080,2014-04-04 18:00:00,41.922621453714285 1081,2014-04-04 18:05:00,38.31079023250476 1082,2014-04-04 18:10:00,37.86715076379524 1083,2014-04-04 18:15:00,41.865641443985716 1084,2014-04-04 18:20:00,41.39597878747619 1085,2014-04-04 18:25:00,38.041800357166665 1086,2014-04-04 18:30:00,37.624324287657146 1087,2014-04-04 18:35:00,42.25354522554762 1088,2014-04-04 18:40:00,41.865461897438095 1089,2014-04-04 18:45:00,38.99711983132857 1090,2014-04-04 18:50:00,41.12257612181905 1091,2014-04-04 18:55:00,37.71217903550952 1092,2014-04-04 19:00:00,30.556572281999998 1093,2014-04-04 19:05:00,28.37635107409048 1094,2014-04-04 19:10:00,30.054256176780953 1095,2014-04-04 19:15:00,28.642616144471425 1096,2014-04-04 19:20:00,30.443420049161904 1097,2014-04-04 19:25:00,30.211334949252382 1098,2014-04-04 19:30:00,30.320486561342854 1099,2014-04-04 19:35:00,28.540166449433332 1100,2014-04-04 19:40:00,29.964563823723807 1101,2014-04-04 19:45:00,31.741010637814284 1102,2014-04-04 19:50:00,30.012139957904758 1103,2014-04-04 19:55:00,31.570814304095236 1104,2014-04-04 20:00:00,28.15967032698571 1105,2014-04-04 20:05:00,28.38731470087619 1106,2014-04-04 20:10:00,28.97086851186667 1107,2014-04-04 20:15:00,30.562600088057142 1108,2014-04-04 20:20:00,27.121939781947617 1109,2014-04-04 20:25:00,26.818302668838093 1110,2014-04-04 20:30:00,29.18112094522857 1111,2014-04-04 20:35:00,30.585870456019048 1112,2014-04-04 20:40:00,30.759715204909526 1113,2014-04-04 20:45:00,28.696386512300002 1114,2014-04-04 20:50:00,28.637952551990473 1115,2014-04-04 20:55:00,29.369902304480952 1116,2014-04-04 21:00:00,28.62317859507143 1117,2014-04-04 21:05:00,28.945938575461906 1118,2014-04-04 21:10:00,29.91763081925238 1119,2014-04-04 21:15:00,29.41184656194286 1120,2014-04-04 21:20:00,28.416782896833332 1121,2014-04-04 21:25:00,28.28349939432381 1122,2014-04-04 21:30:00,29.005301582814287 1123,2014-04-04 21:35:00,28.273629411504764 1124,2014-04-04 21:40:00,28.28940195799524 1125,2014-04-04 21:45:00,26.522472350385712 1126,2014-04-04 21:50:00,27.16397472557619 1127,2014-04-04 21:55:00,28.435250639466666 1128,2014-04-04 22:00:00,29.703909957857142 1129,2014-04-04 22:05:00,27.533555948247617 1130,2014-04-04 22:10:00,28.517598768638095 1131,2014-04-04 22:15:00,27.81363155532857 1132,2014-04-04 22:20:00,26.859517444019048 1133,2014-04-04 22:25:00,30.284213311509525 1134,2014-04-04 22:30:00,29.8767574181 1135,2014-04-04 22:35:00,26.776491575990477 1136,2014-04-04 22:40:00,29.351573975080953 1137,2014-04-04 22:45:00,27.86875574327143 1138,2014-04-04 22:50:00,30.467761345461906 1139,2014-04-04 22:55:00,27.70273766115238 1140,2014-04-04 23:00:00,27.440735987842857 1141,2014-04-04 23:05:00,28.76503766453333 1142,2014-04-04 23:10:00,29.84162583772381 1143,2014-04-04 23:15:00,27.278143625614284 1144,2014-04-04 23:20:00,29.35351666010476 1145,2014-04-04 23:25:00,26.768474729095235 1146,2014-04-04 23:30:00,30.20668642648571 1147,2014-04-04 23:35:00,26.86204411877619 1148,2014-04-04 23:40:00,30.202750299566667 1149,2014-04-04 23:45:00,28.516169078657143 1150,2014-04-04 23:50:00,28.352712202247616 1151,2014-04-04 23:55:00,30.461419910938098 1152,2014-04-05 00:00:00,30.532965282228574 1153,2014-04-05 00:05:00,29.179581551419048 1154,2014-04-05 00:10:00,27.09478669120952 1155,2014-04-05 00:15:00,28.6184303426 1156,2014-04-05 00:20:00,28.717842879990478 1157,2014-04-05 00:25:00,28.666416664880952 1158,2014-04-05 00:30:00,28.89403878267143 1159,2014-04-05 00:35:00,26.698410759961906 1160,2014-04-05 00:40:00,29.47586150685238 1161,2014-04-05 00:45:00,29.487970064942857 1162,2014-04-05 00:50:00,27.10771243403333 1163,2014-04-05 00:55:00,28.934231579323807 1164,2014-04-05 01:00:00,28.934159015414284 1165,2014-04-05 01:05:00,29.39795644270476 1166,2014-04-05 01:10:00,27.017186006595235 1167,2014-04-05 01:15:00,29.189048943385714 1168,2014-04-05 01:20:00,27.81348399347619 1169,2014-04-05 01:25:00,28.725928628666665 1170,2014-04-05 01:30:00,29.798651353657142 1171,2014-04-05 01:35:00,29.535381364547618 1172,2014-04-05 01:40:00,27.195850165938094 1173,2014-04-05 01:45:00,29.09241771992857 1174,2014-04-05 01:50:00,30.611585171419048 1175,2014-04-05 01:55:00,27.369637273109525 1176,2014-04-05 02:00:00,30.1616283509 1177,2014-04-05 02:05:00,29.567632798390477 1178,2014-04-05 02:10:00,29.860894203980955 1179,2014-04-05 02:15:00,27.900154737171427 1180,2014-04-05 02:20:00,27.931317622261904 1181,2014-04-05 02:25:00,30.411280204052378 1182,2014-04-05 02:30:00,28.233970985542854 1183,2014-04-05 02:35:00,27.05414489613333 1184,2014-04-05 02:40:00,29.21191062382381 1185,2014-04-05 02:45:00,27.316234961914283 1186,2014-04-05 02:50:00,30.010789727504758 1187,2014-04-05 02:55:00,29.398831008095236 1188,2014-04-05 03:00:00,30.338191735185717 1189,2014-04-05 03:05:00,29.98607518957619 1190,2014-04-05 03:10:00,27.302621260066665 1191,2014-04-05 03:15:00,28.38588984855714 1192,2014-04-05 03:20:00,29.967288618747617 1193,2014-04-05 03:25:00,28.545853988338095 1194,2014-04-05 03:30:00,30.77339051052857 1195,2014-04-05 03:35:00,29.834330847219046 1196,2014-04-05 03:40:00,26.960809190609524 1197,2014-04-05 03:45:00,30.4261927662 1198,2014-04-05 03:50:00,27.316909615690477 1199,2014-04-05 03:55:00,27.483225849080952 1200,2014-04-05 04:00:00,29.866541030971426 1201,2014-04-05 04:05:00,30.395886142461904 1202,2014-04-05 04:10:00,29.08885089255238 1203,2014-04-05 04:15:00,28.10709178894286 1204,2014-04-05 04:20:00,28.36359551433333 1205,2014-04-05 04:25:00,28.33733112792381 1206,2014-04-05 04:30:00,28.279926700914285 1207,2014-04-05 04:35:00,27.95229344920476 1208,2014-04-05 04:40:00,29.423563616595235 1209,2014-04-05 04:45:00,30.59715698858571 1210,2014-04-05 04:50:00,28.23130584277619 1211,2014-04-05 04:55:00,27.757193856466664 1212,2014-04-05 05:00:00,30.37216780835714 1213,2014-04-05 05:05:00,29.992430942647616 1214,2014-04-05 05:10:00,30.756086221438093 1215,2014-04-05 05:15:00,27.70225751382857 1216,2014-04-05 05:20:00,27.62462430411905 1217,2014-04-05 05:25:00,29.220777101009524 1218,2014-04-05 05:30:00,29.520234619300002 1219,2014-04-05 05:35:00,28.990634243590478 1220,2014-04-05 05:40:00,29.47324749768095 1221,2014-04-05 05:45:00,27.80634050407143 1222,2014-04-05 05:50:00,29.010716921461906 1223,2014-04-05 05:55:00,29.73207262475238 1224,2014-04-05 06:00:00,28.837968654142855 1225,2014-04-05 06:05:00,29.83237267663333 1226,2014-04-05 06:10:00,28.926788931723806 1227,2014-04-05 06:15:00,28.463862609114283 1228,2014-04-05 06:20:00,28.351324950204763 1229,2014-04-05 06:25:00,28.787953474095236 1230,2014-04-05 06:30:00,27.244144204985716 1231,2014-04-05 06:35:00,29.833326744276192 1232,2014-04-05 06:40:00,30.54708923056667 1233,2014-04-05 06:45:00,28.59261552065714 1234,2014-04-05 06:50:00,27.365680163647617 1235,2014-04-05 06:55:00,31.136090484738094 1236,2014-04-05 07:00:00,28.25122159322857 1237,2014-04-05 07:05:00,27.71035353441905 1238,2014-04-05 07:10:00,28.69031955570952 1239,2014-04-05 07:15:00,30.1729781625 1240,2014-04-05 07:20:00,28.401856863790478 1241,2014-04-05 07:25:00,29.532443768080952 1242,2014-04-05 07:30:00,28.903311406271428 1243,2014-04-05 07:35:00,27.719567873861905 1244,2014-04-05 07:40:00,28.57710043095238 1245,2014-04-05 07:45:00,30.162874880042857 1246,2014-04-05 07:50:00,29.718848922633335 1247,2014-04-05 07:55:00,27.757387329023807 1248,2014-04-05 08:00:00,27.939003924614287 1249,2014-04-05 08:05:00,29.85608819910476 1250,2014-04-05 08:10:00,30.554256895395238 1251,2014-04-05 08:15:00,28.705933698085715 1252,2014-04-05 08:20:00,29.696719197876188 1253,2014-04-05 08:25:00,28.005491021666664 1254,2014-04-05 08:30:00,28.57586249045714 1255,2014-04-05 08:35:00,27.418878441747616 1256,2014-04-05 08:40:00,30.418341886438093 1257,2014-04-05 08:45:00,28.95671785052857 1258,2014-04-05 08:50:00,30.624621342219047 1259,2014-04-05 08:55:00,30.201051507909526 1260,2014-04-05 09:00:00,81.84592201390001 1261,2014-04-05 09:05:00,74.46739838249049 1262,2014-04-05 09:10:00,73.10735968618096 1263,2014-04-05 09:15:00,83.81523871267143 1264,2014-04-05 09:20:00,80.36041980856191 1265,2014-04-05 09:25:00,81.95517722475238 1266,2014-04-05 09:30:00,70.79825673964285 1267,2014-04-05 09:35:00,75.44776136933334 1268,2014-04-05 09:40:00,80.7368308014238 1269,2014-04-05 09:45:00,71.70253081441427 1270,2014-04-05 09:50:00,78.36522780400476 1271,2014-04-05 09:55:00,76.49223487549524 1272,2014-04-05 10:00:00,79.57769390508571 1273,2014-04-05 10:05:00,82.97406714737619 1274,2014-04-05 10:10:00,83.73913833696668 1275,2014-04-05 10:15:00,81.06267351015714 1276,2014-04-05 10:20:00,89.13550045824762 1277,2014-04-05 10:25:00,83.10350313463809 1278,2014-04-05 10:30:00,83.65758320552857 1279,2014-04-05 10:35:00,93.29703209171905 1280,2014-04-05 10:40:00,86.61355992240952 1281,2014-04-05 10:45:00,85.457078841 1282,2014-04-05 10:50:00,90.61316899079048 1283,2014-04-05 10:55:00,93.50333707998095 1284,2014-04-05 11:00:00,81.51974932007143 1285,2014-04-05 11:05:00,88.2578025203619 1286,2014-04-05 11:10:00,90.85031906805239 1287,2014-04-05 11:15:00,86.21032036974286 1288,2014-04-05 11:20:00,93.43570574593333 1289,2014-04-05 11:25:00,96.60914513512381 1290,2014-04-05 11:30:00,96.17048311851428 1291,2014-04-05 11:35:00,85.40384106820476 1292,2014-04-05 11:40:00,84.78077921839524 1293,2014-04-05 11:45:00,96.41646511968571 1294,2014-04-05 11:50:00,88.49000365457618 1295,2014-04-05 11:55:00,84.51618365456667 1296,2014-04-05 12:00:00,92.85483421925714 1297,2014-04-05 12:05:00,86.10916193124763 1298,2014-04-05 12:10:00,85.8421585544381 1299,2014-04-05 12:15:00,95.62988167902857 1300,2014-04-05 12:20:00,84.18276590191905 1301,2014-04-05 12:25:00,82.62271032270952 1302,2014-04-05 12:30:00,85.9029146631 1303,2014-04-05 12:35:00,91.30801372969049 1304,2014-04-05 12:40:00,83.58302332008095 1305,2014-04-05 12:45:00,89.15988156727143 1306,2014-04-05 12:50:00,91.65621079906191 1307,2014-04-05 12:55:00,95.20179851215238 1308,2014-04-05 13:00:00,85.39189361714286 1309,2014-04-05 13:05:00,94.79670589753333 1310,2014-04-05 13:10:00,85.48734194762382 1311,2014-04-05 13:15:00,92.56285016201431 1312,2014-04-05 13:20:00,88.63374811910477 1313,2014-04-05 13:25:00,83.58652474019524 1314,2014-04-05 13:30:00,93.18497834778572 1315,2014-04-05 13:35:00,85.25031187877619 1316,2014-04-05 13:40:00,84.59968324906667 1317,2014-04-05 13:45:00,87.51361804025714 1318,2014-04-05 13:50:00,92.23940290064762 1319,2014-04-05 13:55:00,85.53975320943809 1320,2014-04-05 14:00:00,84.75641613982857 1321,2014-04-05 14:05:00,81.98466341461905 1322,2014-04-05 14:10:00,89.37878085550952 1323,2014-04-05 14:15:00,88.6982939092 1324,2014-04-05 14:20:00,85.58943876399047 1325,2014-04-05 14:25:00,82.71356837168095 1326,2014-04-05 14:30:00,88.73037975357143 1327,2014-04-05 14:35:00,94.4807323403619 1328,2014-04-05 14:40:00,93.32146114555238 1329,2014-04-05 14:45:00,95.65699400444285 1330,2014-04-05 14:50:00,82.04569297723333 1331,2014-04-05 14:55:00,97.3617846683238 1332,2014-04-05 15:00:00,87.37256668681428 1333,2014-04-05 15:05:00,97.76367617430476 1334,2014-04-05 15:10:00,85.96677660539524 1335,2014-04-05 15:15:00,89.47685428758571 1336,2014-04-05 15:20:00,87.60257345237619 1337,2014-04-05 15:25:00,87.63934226176667 1338,2014-04-05 15:30:00,95.43105014825714 1339,2014-04-05 15:35:00,93.90469480484762 1340,2014-04-05 15:40:00,97.8438174644381 1341,2014-04-05 15:45:00,91.79312805902858 1342,2014-04-05 15:50:00,89.39646236171905 1343,2014-04-05 15:55:00,83.43303629560953 1344,2014-04-05 16:00:00,97.94481385790002 1345,2014-04-05 16:05:00,90.83177574009048 1346,2014-04-05 16:10:00,93.22236070878095 1347,2014-04-05 16:15:00,88.53004888847143 1348,2014-04-05 16:20:00,90.79305816976189 1349,2014-04-05 16:25:00,97.1182788952524 1350,2014-04-05 16:30:00,84.70721051164286 1351,2014-04-05 16:35:00,86.72989746093333 1352,2014-04-05 16:40:00,84.4923365427238 1353,2014-04-05 16:45:00,94.74225616971427 1354,2014-04-05 16:50:00,83.06698878260475 1355,2014-04-05 16:55:00,83.38781088799524 1356,2014-04-05 17:00:00,86.86516203698571 1357,2014-04-05 17:05:00,90.32370627807619 1358,2014-04-05 17:10:00,88.60453333146667 1359,2014-04-05 17:15:00,82.82864019025713 1360,2014-04-05 17:20:00,97.43887901414762 1361,2014-04-05 17:25:00,97.37236691853809 1362,2014-04-05 17:30:00,86.60360037892858 1363,2014-04-05 17:35:00,93.84574674941905 1364,2014-04-05 17:40:00,91.40598490320951 1365,2014-04-05 17:45:00,85.95584801300001 1366,2014-04-05 17:50:00,86.35840604529048 1367,2014-04-05 17:55:00,90.02955107568094 1368,2014-04-05 18:00:00,41.66168180937143 1369,2014-04-05 18:05:00,40.849873717961906 1370,2014-04-05 18:10:00,44.16152007545238 1371,2014-04-05 18:15:00,42.082249408842856 1372,2014-04-05 18:20:00,43.19935459833333 1373,2014-04-05 18:25:00,40.22711844842381 1374,2014-04-05 18:30:00,42.437657140614284 1375,2014-04-05 18:35:00,41.06569555800477 1376,2014-04-05 18:40:00,42.40713616819524 1377,2014-04-05 18:45:00,44.04281455908571 1378,2014-04-05 18:50:00,43.97401426057619 1379,2014-04-05 18:55:00,41.32742304126667 1380,2014-04-05 19:00:00,33.538217350857146 1381,2014-04-05 19:05:00,34.65227525954762 1382,2014-04-05 19:10:00,33.245735433638096 1383,2014-04-05 19:15:00,31.11505478182857 1384,2014-04-05 19:20:00,33.50271243381904 1385,2014-04-05 19:25:00,30.935030042909524 1386,2014-04-05 19:30:00,34.3795533111 1387,2014-04-05 19:35:00,32.794578264490475 1388,2014-04-05 19:40:00,32.212810250480956 1389,2014-04-05 19:45:00,30.750209852671432 1390,2014-04-05 19:50:00,32.20817183626191 1391,2014-04-05 19:55:00,34.55606692535238 1392,2014-04-05 20:00:00,28.875088987742856 1393,2014-04-05 20:05:00,30.740741943133333 1394,2014-04-05 20:10:00,32.61804708372381 1395,2014-04-05 20:15:00,30.428732780114284 1396,2014-04-05 20:20:00,30.57271213550476 1397,2014-04-05 20:25:00,31.196126974595238 1398,2014-04-05 20:30:00,30.72997678868571 1399,2014-04-05 20:35:00,29.53181848827619 1400,2014-04-05 20:40:00,28.924669932566665 1401,2014-04-05 20:45:00,31.353895442757143 1402,2014-04-05 20:50:00,32.63517113294762 1403,2014-04-05 20:55:00,29.306655357738094 1404,2014-04-05 21:00:00,29.380689694328574 1405,2014-04-05 21:05:00,30.02829534921905 1406,2014-04-05 21:10:00,31.798206238509522 1407,2014-04-05 21:15:00,29.6373610171 1408,2014-04-05 21:20:00,32.10774348499048 1409,2014-04-05 21:25:00,28.790917597380954 1410,2014-04-05 21:30:00,32.35936422727143 1411,2014-04-05 21:35:00,30.838666510361904 1412,2014-04-05 21:40:00,31.24011157565238 1413,2014-04-05 21:45:00,30.07761053824286 1414,2014-04-05 21:50:00,31.75022471373333 1415,2014-04-05 21:55:00,29.284136836023812 1416,2014-04-05 22:00:00,28.748829399314285 1417,2014-04-05 22:05:00,30.144021309804764 1418,2014-04-05 22:10:00,31.985936274995236 1419,2014-04-05 22:15:00,31.597921969585713 1420,2014-04-05 22:20:00,30.65336594147619 1421,2014-04-05 22:25:00,30.880944654266663 1422,2014-04-05 22:30:00,29.117707227357144 1423,2014-04-05 22:35:00,31.971031860047617 1424,2014-04-05 22:40:00,31.763378741838096 1425,2014-04-05 22:45:00,31.24836098312857 1426,2014-04-05 22:50:00,30.493953356719047 1427,2014-04-05 22:55:00,32.49638010980952 1428,2014-04-05 23:00:00,32.1452589819 1429,2014-04-05 23:05:00,31.214113370890473 1430,2014-04-05 23:10:00,30.130826484480952 1431,2014-04-05 23:15:00,31.123341182371433 1432,2014-04-05 23:20:00,30.960423547561902 1433,2014-04-05 23:25:00,30.24292910825238 1434,2014-04-05 23:30:00,29.900030267642855 1435,2014-04-05 23:35:00,30.308895084633335 1436,2014-04-05 23:40:00,30.98406619562381 1437,2014-04-05 23:45:00,30.408288470214284 1438,2014-04-05 23:50:00,29.75736113800476 1439,2014-04-05 23:55:00,31.75473892689524 1440,2014-04-06 00:00:00,30.840155698085717 1441,2014-04-06 00:05:00,28.99242684337619 1442,2014-04-06 00:10:00,30.202432689166663 1443,2014-04-06 00:15:00,32.276260971657145 1444,2014-04-06 00:20:00,31.76499374384762 1445,2014-04-06 00:25:00,30.044475231038096 1446,2014-04-06 00:30:00,32.511661179628575 1447,2014-04-06 00:35:00,29.072780681019047 1448,2014-04-06 00:40:00,32.61874833940952 1449,2014-04-06 00:45:00,29.7640703699 1450,2014-04-06 00:50:00,28.825067197390474 1451,2014-04-06 00:55:00,30.531363098480952 1452,2014-04-06 01:00:00,30.239453147271426 1453,2014-04-06 01:05:00,30.967367925561902 1454,2014-04-06 01:10:00,32.00554382325238 1455,2014-04-06 01:15:00,32.195616065742854 1456,2014-04-06 01:20:00,30.438253331733332 1457,2014-04-06 01:25:00,30.56015678432381 1458,2014-04-06 01:30:00,29.440925207014285 1459,2014-04-06 01:35:00,29.04584519740476 1460,2014-04-06 01:40:00,31.427955198995235 1461,2014-04-06 01:45:00,29.128286216485712 1462,2014-04-06 01:50:00,31.81329666817619 1463,2014-04-06 01:55:00,31.041777246766664 1464,2014-04-06 02:00:00,29.68718905575714 1465,2014-04-06 02:05:00,31.05838939314762 1466,2014-04-06 02:10:00,29.639728961638095 1467,2014-04-06 02:15:00,30.670127401428573 1468,2014-04-06 02:20:00,32.120860312619044 1469,2014-04-06 02:25:00,30.777736697409523 1470,2014-04-06 02:30:00,29.5322972732 1471,2014-04-06 02:35:00,31.84025520349048 1472,2014-04-06 02:40:00,29.699454617480953 1473,2014-04-06 02:45:00,31.91402092607143 1474,2014-04-06 02:50:00,30.884671061661905 1475,2014-04-06 02:55:00,30.789669417352382 1476,2014-04-06 03:00:00,32.38788300854286 1477,2014-04-06 03:05:00,31.823997430733332 1478,2014-04-06 03:10:00,29.128666997323805 1479,2014-04-06 03:15:00,30.189161544114285 1480,2014-04-06 03:20:00,32.49558740530476 1481,2014-04-06 03:25:00,29.092649912295236 1482,2014-04-06 03:30:00,31.207799499285713 1483,2014-04-06 03:35:00,31.94552886717619 1484,2014-04-06 03:40:00,31.529091008566667 1485,2014-04-06 03:45:00,32.09123595125714 1486,2014-04-06 03:50:00,31.959315014747617 1487,2014-04-06 03:55:00,31.832110875838094 1488,2014-04-06 04:00:00,32.35758801512857 1489,2014-04-06 04:05:00,31.66163172141905 1490,2014-04-06 04:10:00,30.695983500809525 1491,2014-04-06 04:15:00,30.9813864397 1492,2014-04-06 04:20:00,31.968089606890473 1493,2014-04-06 04:25:00,32.61385507108095 1494,2014-04-06 04:30:00,30.20494663197143 1495,2014-04-06 04:35:00,30.491819088661906 1496,2014-04-06 04:40:00,32.853909966352376 1497,2014-04-06 04:45:00,31.452440026742856 1498,2014-04-06 04:50:00,29.86168060183333 1499,2014-04-06 04:55:00,31.80805436512381 1500,2014-04-06 05:00:00,33.12376290791428 1501,2014-04-06 05:05:00,32.46196901980476 1502,2014-04-06 05:10:00,32.158559784295235 1503,2014-04-06 05:15:00,30.015222331385715 1504,2014-04-06 05:20:00,32.69503532917619 1505,2014-04-06 05:25:00,31.30107204076667 1506,2014-04-06 05:30:00,32.76251723115714 1507,2014-04-06 05:35:00,30.53210893674762 1508,2014-04-06 05:40:00,29.468442305738094 1509,2014-04-06 05:45:00,31.131582446028574 1510,2014-04-06 05:50:00,30.314469466919046 1511,2014-04-06 05:55:00,32.10347668290952 1512,2014-04-06 06:00:00,33.0784262114 1513,2014-04-06 06:05:00,32.021337080790474 1514,2014-04-06 06:10:00,32.812616671180955 1515,2014-04-06 06:15:00,31.084417482971432 1516,2014-04-06 06:20:00,32.366324853561906 1517,2014-04-06 06:25:00,32.65937612765238 1518,2014-04-06 06:30:00,32.13814536744285 1519,2014-04-06 06:35:00,31.333192477633332 1520,2014-04-06 06:40:00,31.812988248023807 1521,2014-04-06 06:45:00,32.11899226841429 1522,2014-04-06 06:50:00,30.336742374804757 1523,2014-04-06 06:55:00,32.570162281795234 1524,2014-04-06 07:00:00,33.140583870185715 1525,2014-04-06 07:05:00,31.207683451176187 1526,2014-04-06 07:10:00,32.15843539906667 1527,2014-04-06 07:15:00,32.30971076605714 1528,2014-04-06 07:20:00,32.01803780914762 1529,2014-04-06 07:25:00,31.564948528538093 1530,2014-04-06 07:30:00,32.91052038972857 1531,2014-04-06 07:35:00,31.187075884719047 1532,2014-04-06 07:40:00,29.64322134970952 1533,2014-04-06 07:45:00,32.7844755028 1534,2014-04-06 07:50:00,32.10961556549048 1535,2014-04-06 07:55:00,32.81816545838095 1536,2014-04-06 08:00:00,29.982761198371428 1537,2014-04-06 08:05:00,29.559023666761902 1538,2014-04-06 08:10:00,33.18095054245238 1539,2014-04-06 08:15:00,30.041806080542855 1540,2014-04-06 08:20:00,32.69694266163333 1541,2014-04-06 08:25:00,32.75861357822381 1542,2014-04-06 08:30:00,32.308035087914284 1543,2014-04-06 08:35:00,30.005703606304763 1544,2014-04-06 08:40:00,32.15768973629524 1545,2014-04-06 08:45:00,33.051882047585714 1546,2014-04-06 08:50:00,31.20510276967619 1547,2014-04-06 08:55:00,31.164484084166666 1548,2014-04-06 09:00:00,78.74073015315713 1549,2014-04-06 09:05:00,73.84419533224761 1550,2014-04-06 09:10:00,84.8642858340381 1551,2014-04-06 09:15:00,84.56106552152858 1552,2014-04-06 09:20:00,86.31918582391906 1553,2014-04-06 09:25:00,80.71355024820951 1554,2014-04-06 09:30:00,82.97870625569999 1555,2014-04-06 09:35:00,75.52627840199048 1556,2014-04-06 09:40:00,81.85577288018095 1557,2014-04-06 09:45:00,81.62118817167143 1558,2014-04-06 09:50:00,85.04870071216189 1559,2014-04-06 09:55:00,84.09848341155238 1560,2014-04-06 10:00:00,96.01214235694286 1561,2014-04-06 10:05:00,94.93887882963332 1562,2014-04-06 10:10:00,94.9441530583238 1563,2014-04-06 10:15:00,82.45845031591429 1564,2014-04-06 10:20:00,94.60623426770476 1565,2014-04-06 10:25:00,90.91240992079524 1566,2014-04-06 10:30:00,87.39628360568571 1567,2014-04-06 10:35:00,82.37633316097619 1568,2014-04-06 10:40:00,92.02416365106667 1569,2014-04-06 10:45:00,86.60779831115714 1570,2014-04-06 10:50:00,88.78143525164762 1571,2014-04-06 10:55:00,92.1094134383381 1572,2014-04-06 11:00:00,97.76529096732857 1573,2014-04-06 11:05:00,96.39961775341905 1574,2014-04-06 11:10:00,90.44560626510952 1575,2014-04-06 11:15:00,89.454053336 1576,2014-04-06 11:20:00,87.10764744279048 1577,2014-04-06 11:25:00,89.22470600308094 1578,2014-04-06 11:30:00,85.07515317207144 1579,2014-04-06 11:35:00,98.7609739097619 1580,2014-04-06 11:40:00,92.45153540965238 1581,2014-04-06 11:45:00,85.36401698094286 1582,2014-04-06 11:50:00,88.94986010473333 1583,2014-04-06 11:55:00,92.0463843496238 1584,2014-04-06 12:00:00,92.21525306771429 1585,2014-04-06 12:05:00,84.27412699670475 1586,2014-04-06 12:10:00,98.90939563789522 1587,2014-04-06 12:15:00,88.12235940478571 1588,2014-04-06 12:20:00,83.98772014777619 1589,2014-04-06 12:25:00,84.95815308486667 1590,2014-04-06 12:30:00,93.01593585265714 1591,2014-04-06 12:35:00,85.95332046784762 1592,2014-04-06 12:40:00,84.4256336648381 1593,2014-04-06 12:45:00,89.83301320582856 1594,2014-04-06 12:50:00,93.72594111021905 1595,2014-04-06 12:55:00,85.56844907700952 1596,2014-04-06 13:00:00,88.8697621355 1597,2014-04-06 13:05:00,90.54772702119048 1598,2014-04-06 13:10:00,86.42335019018094 1599,2014-04-06 13:15:00,91.97528048027144 1600,2014-04-06 13:20:00,85.2505800730619 1601,2014-04-06 13:25:00,84.63903969145238 1602,2014-04-06 13:30:00,92.21773256384286 1603,2014-04-06 13:35:00,87.87520297293332 1604,2014-04-06 13:40:00,85.44285850042381 1605,2014-04-06 13:45:00,90.70565786121429 1606,2014-04-06 13:50:00,98.57086245370476 1607,2014-04-06 13:55:00,95.52386348559524 1608,2014-04-06 14:00:00,97.01005796678571 1609,2014-04-06 14:05:00,97.9182243806762 1610,2014-04-06 14:10:00,99.53700755086668 1611,2014-04-06 14:15:00,96.19451014575714 1612,2014-04-06 14:20:00,93.72465111274762 1613,2014-04-06 14:25:00,89.8445655330381 1614,2014-04-06 14:30:00,86.91162485432856 1615,2014-04-06 14:35:00,94.99894367651905 1616,2014-04-06 14:40:00,99.93878918020951 1617,2014-04-06 14:45:00,91.5051740224 1618,2014-04-06 14:50:00,95.61354857989048 1619,2014-04-06 14:55:00,91.96377392128095 1620,2014-04-06 15:00:00,90.96374865737143 1621,2014-04-06 15:05:00,90.62514749876189 1622,2014-04-06 15:10:00,92.14167859755239 1623,2014-04-06 15:15:00,89.94547589184286 1624,2014-04-06 15:20:00,96.06290027093333 1625,2014-04-06 15:25:00,98.07830074682379 1626,2014-04-06 15:30:00,98.22355238081428 1627,2014-04-06 15:35:00,87.74810800220476 1628,2014-04-06 15:40:00,98.44681264619524 1629,2014-04-06 15:45:00,89.58461176168571 1630,2014-04-06 15:50:00,89.07616012857619 1631,2014-04-06 15:55:00,95.76271075526667 1632,2014-04-06 16:00:00,89.01785098395713 1633,2014-04-06 16:05:00,84.99762024164762 1634,2014-04-06 16:10:00,90.13547273463809 1635,2014-04-06 16:15:00,95.70846777372857 1636,2014-04-06 16:20:00,89.40380548781906 1637,2014-04-06 16:25:00,94.25284683970952 1638,2014-04-06 16:30:00,94.7492525893 1639,2014-04-06 16:35:00,95.93455588349048 1640,2014-04-06 16:40:00,98.55630261348095 1641,2014-04-06 16:45:00,91.13070188847144 1642,2014-04-06 16:50:00,86.8800317785619 1643,2014-04-06 16:55:00,89.32736579045238 1644,2014-04-06 17:00:00,91.14678863664285 1645,2014-04-06 17:05:00,95.66181480843333 1646,2014-04-06 17:10:00,84.45695008992381 1647,2014-04-06 17:15:00,89.30700083261428 1648,2014-04-06 17:20:00,96.73935361890476 1649,2014-04-06 17:25:00,95.00303672159525 1650,2014-04-06 17:30:00,95.9845931478857 1651,2014-04-06 17:35:00,97.27316586577619 1652,2014-04-06 17:40:00,96.82340570846668 1653,2014-04-06 17:45:00,95.21400596195714 1654,2014-04-06 17:50:00,91.34110178764762 1655,2014-04-06 17:55:00,100.05152766603808 1656,2014-04-06 18:00:00,44.76349079432857 1657,2014-04-06 18:05:00,42.426586208819046 1658,2014-04-06 18:10:00,43.010305907109526 1659,2014-04-06 18:15:00,45.5825433364 1660,2014-04-06 18:20:00,47.06951702759047 1661,2014-04-06 18:25:00,42.30243403008095 1662,2014-04-06 18:30:00,41.69308337057143 1663,2014-04-06 18:35:00,46.81530399936191 1664,2014-04-06 18:40:00,47.038724791652385 1665,2014-04-06 18:45:00,42.957214797942854 1666,2014-04-06 18:50:00,43.61045597613334 1667,2014-04-06 18:55:00,45.42847065262381 1668,2014-04-06 19:00:00,34.04879959211428 1669,2014-04-06 19:05:00,36.50782445350476 1670,2014-04-06 19:10:00,33.06754669389524 1671,2014-04-06 19:15:00,32.76319494888571 1672,2014-04-06 19:20:00,33.53449323957619 1673,2014-04-06 19:25:00,33.88958873676667 1674,2014-04-06 19:30:00,33.12126713815714 1675,2014-04-06 19:35:00,32.91708962044762 1676,2014-04-06 19:40:00,36.01535936013809 1677,2014-04-06 19:45:00,33.373636440328575 1678,2014-04-06 19:50:00,36.73948916891906 1679,2014-04-06 19:55:00,34.30119681070953 1680,2014-04-06 20:00:00,33.6788011425 1681,2014-04-06 20:05:00,31.862687305990477 1682,2014-04-06 20:10:00,31.931242779080954 1683,2014-04-06 20:15:00,33.30833007407143 1684,2014-04-06 20:20:00,33.2581550774619 1685,2014-04-06 20:25:00,34.11791703995238 1686,2014-04-06 20:30:00,34.08064589884285 1687,2014-04-06 20:35:00,33.73122016323333 1688,2014-04-06 20:40:00,32.831162364123806 1689,2014-04-06 20:45:00,34.64702704291428 1690,2014-04-06 20:50:00,33.55648600610476 1691,2014-04-06 20:55:00,35.06969798519523 1692,2014-04-06 21:00:00,33.968896834285715 1693,2014-04-06 21:05:00,30.86121613917619 1694,2014-04-06 21:10:00,31.979097650566665 1695,2014-04-06 21:15:00,32.996489972657145 1696,2014-04-06 21:20:00,33.605177934347616 1697,2014-04-06 21:25:00,32.9248004974381 1698,2014-04-06 21:30:00,33.87994391342857 1699,2014-04-06 21:35:00,31.863818600119046 1700,2014-04-06 21:40:00,31.474388794109522 1701,2014-04-06 21:45:00,30.9593518907 1702,2014-04-06 21:50:00,33.054353028490475 1703,2014-04-06 21:55:00,33.525150094880956 1704,2014-04-06 22:00:00,32.00170270247143 1705,2014-04-06 22:05:00,33.1599847973619 1706,2014-04-06 22:10:00,30.91956157915238 1707,2014-04-06 22:15:00,31.115727519742855 1708,2014-04-06 22:20:00,33.53532715043333 1709,2014-04-06 22:25:00,32.20674600852381 1710,2014-04-06 22:30:00,33.42840832261429 1711,2014-04-06 22:35:00,34.07801304160476 1712,2014-04-06 22:40:00,34.16913904759524 1713,2014-04-06 22:45:00,31.45214741068571 1714,2014-04-06 22:50:00,32.71726580667619 1715,2014-04-06 22:55:00,33.71622182956666 1716,2014-04-06 23:00:00,33.867829942957144 1717,2014-04-06 23:05:00,33.91806017104762 1718,2014-04-06 23:10:00,31.699038663438095 1719,2014-04-06 23:15:00,31.563921707228573 1720,2014-04-06 23:20:00,33.16157804831904 1721,2014-04-06 23:25:00,33.773427866609524 1722,2014-04-06 23:30:00,32.0927591594 1723,2014-04-06 23:35:00,31.242297515390476 1724,2014-04-06 23:40:00,33.698372943180956 1725,2014-04-06 23:45:00,32.03729892017142 1726,2014-04-06 23:50:00,31.511296566761906 1727,2014-04-06 23:55:00,31.444165944352378 1728,2014-04-07 00:00:00,32.11678104724285 1729,2014-04-07 00:05:00,33.23529559703333 1730,2014-04-07 00:10:00,32.30563276432381 1731,2014-04-07 00:15:00,30.962111692114284 1732,2014-04-07 00:20:00,31.274538500604763 1733,2014-04-07 00:25:00,32.05635822689524 1734,2014-04-07 00:30:00,33.54060364288571 1735,2014-04-07 00:35:00,31.30328648437619 1736,2014-04-07 00:40:00,33.15929408066667 1737,2014-04-07 00:45:00,31.40365062615714 1738,2014-04-07 00:50:00,31.77800892844762 1739,2014-04-07 00:55:00,31.627742205438096 1740,2014-04-07 01:00:00,31.215343113728572 1741,2014-04-07 01:05:00,33.63918831711905 1742,2014-04-07 01:10:00,32.814923713309526 1743,2014-04-07 01:15:00,34.2929637636 1744,2014-04-07 01:20:00,31.371753836090477 1745,2014-04-07 01:25:00,31.562562685780946 1746,2014-04-07 01:30:00,32.21690235397143 1747,2014-04-07 01:35:00,34.0619758525619 1748,2014-04-07 01:40:00,32.22898767355238 1749,2014-04-07 01:45:00,32.64706768714286 1750,2014-04-07 01:50:00,32.22724759853333 1751,2014-04-07 01:55:00,31.349170976723812 1752,2014-04-07 02:00:00,34.79344877731428 1753,2014-04-07 02:05:00,33.23731073020476 1754,2014-04-07 02:10:00,34.20192799079524 1755,2014-04-07 02:15:00,33.69146408298571 1756,2014-04-07 02:20:00,33.12249330667619 1757,2014-04-07 02:25:00,31.431629693266665 1758,2014-04-07 02:30:00,33.65129132395714 1759,2014-04-07 02:35:00,31.709279042747617 1760,2014-04-07 02:40:00,32.752770772638094 1761,2014-04-07 02:45:00,33.61913114532857 1762,2014-04-07 02:50:00,34.239035049519046 1763,2014-04-07 02:55:00,33.85774022660952 1764,2014-04-07 03:00:00,33.811134116199995 1765,2014-04-07 03:05:00,31.728609312890477 1766,2014-04-07 03:10:00,32.52439511268095 1767,2014-04-07 03:15:00,31.318970519171426 1768,2014-04-07 03:20:00,34.0326694774619 1769,2014-04-07 03:25:00,34.97254630625238 1770,2014-04-07 03:30:00,32.226084417842856 1771,2014-04-07 03:35:00,31.527870169933333 1772,2014-04-07 03:40:00,33.08680411652381 1773,2014-04-07 03:45:00,34.61875717821428 1774,2014-04-07 03:50:00,33.40730154300476 1775,2014-04-07 03:55:00,31.393953838895236 1776,2014-04-07 04:00:00,35.111374676385715 1777,2014-04-07 04:05:00,34.536325830376185 1778,2014-04-07 04:10:00,31.755542974866664 1779,2014-04-07 04:15:00,34.92379816885715 1780,2014-04-07 04:20:00,33.04680077344762 1781,2014-04-07 04:25:00,32.7390800575381 1782,2014-04-07 04:30:00,33.10314189352857 1783,2014-04-07 04:35:00,34.60465687511905 1784,2014-04-07 04:40:00,33.911728236909525 1785,2014-04-07 04:45:00,31.5182438096 1786,2014-04-07 04:50:00,35.11910796069048 1787,2014-04-07 04:55:00,31.887267486280955 1788,2014-04-07 05:00:00,34.28584323547143 1789,2014-04-07 05:05:00,33.85555802646191 1790,2014-04-07 05:10:00,32.06856457275238 1791,2014-04-07 05:15:00,32.00882116164286 1792,2014-04-07 05:20:00,34.81464370813333 1793,2014-04-07 05:25:00,33.01955350352381 1794,2014-04-07 05:30:00,33.966520342414285 1795,2014-04-07 05:35:00,33.37193877730476 1796,2014-04-07 05:40:00,34.272509306395236 1797,2014-04-07 05:45:00,33.28750521448571 1798,2014-04-07 05:50:00,32.52749585147619 1799,2014-04-07 05:55:00,32.83895015066667 1800,2014-04-07 06:00:00,34.82916792065714 1801,2014-04-07 06:05:00,33.27243639074762 1802,2014-04-07 06:10:00,32.2615354242381 1803,2014-04-07 06:15:00,35.15360012372857 1804,2014-04-07 06:20:00,34.609020873619045 1805,2014-04-07 06:25:00,31.652724108009522 1806,2014-04-07 06:30:00,35.4332718479 1807,2014-04-07 06:35:00,34.22464726199048 1808,2014-04-07 06:40:00,32.09344734858095 1809,2014-04-07 06:45:00,32.40849215377143 1810,2014-04-07 06:50:00,34.2370438297619 1811,2014-04-07 06:55:00,34.59374660205238 1812,2014-04-07 07:00:00,32.438286629742855 1813,2014-04-07 07:05:00,32.517458748933336 1814,2014-04-07 07:10:00,32.72550658902381 1815,2014-04-07 07:15:00,33.896537745014285 1816,2014-04-07 07:20:00,32.19916947510476 1817,2014-04-07 07:25:00,31.936318033595235 1818,2014-04-07 07:30:00,34.24224207058572 1819,2014-04-07 07:35:00,34.65061794967619 1820,2014-04-07 07:40:00,33.54538428436667 1821,2014-04-07 07:45:00,33.004437983957146 1822,2014-04-07 07:50:00,33.28471847314762 1823,2014-04-07 07:55:00,33.117619430738095 1824,2014-04-07 08:00:00,35.41136820442857 1825,2014-04-07 08:05:00,34.651228668519046 1826,2014-04-07 08:10:00,32.418658383209525 1827,2014-04-07 08:15:00,33.1305066082 1828,2014-04-07 08:20:00,33.77723964169048 1829,2014-04-07 08:25:00,34.06057440068095 1830,2014-04-07 08:30:00,33.48880701267143 1831,2014-04-07 08:35:00,34.8640184447619 1832,2014-04-07 08:40:00,34.70137645875238 1833,2014-04-07 08:45:00,33.65902453164286 1834,2014-04-07 08:50:00,35.06355088043333 1835,2014-04-07 08:55:00,34.657631931323806 1836,2014-04-07 09:00:00,85.4494274283143 1837,2014-04-07 09:05:00,87.87520536220475 1838,2014-04-07 09:10:00,78.49954563849523 1839,2014-04-07 09:15:00,78.5230507224857 1840,2014-04-07 09:20:00,86.98022686787618 1841,2014-04-07 09:25:00,85.40019534466667 1842,2014-04-07 09:30:00,87.50637650635714 1843,2014-04-07 09:35:00,75.77136779944762 1844,2014-04-07 09:40:00,83.45773434603808 1845,2014-04-07 09:45:00,76.89462396992857 1846,2014-04-07 09:50:00,81.78812094441905 1847,2014-04-07 09:55:00,77.06071779700952 1848,2014-04-07 10:00:00,85.5777784594 1849,2014-04-07 10:05:00,83.78629319649048 1850,2014-04-07 10:10:00,93.38618732058094 1851,2014-04-07 10:15:00,89.18435243957144 1852,2014-04-07 10:20:00,85.25228408606192 1853,2014-04-07 10:25:00,88.63764469135238 1854,2014-04-07 10:30:00,86.25665515644286 1855,2014-04-07 10:35:00,98.25718711823333 1856,2014-04-07 10:40:00,88.61599963652381 1857,2014-04-07 10:45:00,88.83992296721428 1858,2014-04-07 10:50:00,96.69900097470476 1859,2014-04-07 10:55:00,93.72501465329525 1860,2014-04-07 11:00:00,96.70185495838571 1861,2014-04-07 11:05:00,95.5296988810762 1862,2014-04-07 11:10:00,100.47047236656667 1863,2014-04-07 11:15:00,88.72174836795715 1864,2014-04-07 11:20:00,101.16672771994762 1865,2014-04-07 11:25:00,98.66001514313808 1866,2014-04-07 11:30:00,94.81894862492857 1867,2014-04-07 11:35:00,95.99372736201904 1868,2014-04-07 11:40:00,95.78573626370951 1869,2014-04-07 11:45:00,86.4029835474 1870,2014-04-07 11:50:00,88.94902486889049 1871,2014-04-07 11:55:00,100.78036389988095 1872,2014-04-07 12:00:00,94.38174249327143 1873,2014-04-07 12:05:00,91.8960051677619 1874,2014-04-07 12:10:00,98.03503665665238 1875,2014-04-07 12:15:00,94.24672517594286 1876,2014-04-07 12:20:00,86.08228495103333 1877,2014-04-07 12:25:00,97.64503959512382 1878,2014-04-07 12:30:00,97.58823666941427 1879,2014-04-07 12:35:00,88.53346330040476 1880,2014-04-07 12:40:00,101.18988877919524 1881,2014-04-07 12:45:00,89.48736678278571 1882,2014-04-07 12:50:00,93.23177728077619 1883,2014-04-07 12:55:00,87.75758911636667 1884,2014-04-07 13:00:00,95.65077764995713 1885,2014-04-07 13:05:00,92.01379380764762 1886,2014-04-07 13:10:00,91.6648773045381 1887,2014-04-07 13:15:00,99.25135301572857 1888,2014-04-07 13:20:00,86.18328973621905 1889,2014-04-07 13:25:00,98.8018637425095 1890,2014-04-07 13:30:00,95.18620268949999 1891,2014-04-07 13:35:00,101.82645007359048 1892,2014-04-07 13:40:00,95.48892902008096 1893,2014-04-07 13:45:00,86.95339491907143 1894,2014-04-07 13:50:00,86.8851126497619 1895,2014-04-07 13:55:00,100.20947885545239 1896,2014-04-07 14:00:00,99.56246713284285 1897,2014-04-07 14:05:00,91.64510289903332 1898,2014-04-07 14:10:00,96.00661290752382 1899,2014-04-07 14:15:00,93.9590939924143 1900,2014-04-07 14:20:00,101.60733086210476 1901,2014-04-07 14:25:00,101.33953408219524 1902,2014-04-07 14:30:00,101.8889982625857 1903,2014-04-07 14:35:00,100.0182852479762 1904,2014-04-07 14:40:00,100.71533758346668 1905,2014-04-07 14:45:00,89.64694473305714 1906,2014-04-07 14:50:00,99.47356202964762 1907,2014-04-07 14:55:00,97.5267015042381 1908,2014-04-07 15:00:00,101.60017362862857 1909,2014-04-07 15:05:00,95.34327935691906 1910,2014-04-07 15:10:00,87.57327990950951 1911,2014-04-07 15:15:00,95.77634929850001 1912,2014-04-07 15:20:00,97.21068866569048 1913,2014-04-07 15:25:00,89.75804237048095 1914,2014-04-07 15:30:00,92.54613382897143 1915,2014-04-07 15:35:00,95.8237833994619 1916,2014-04-07 15:40:00,92.24089551535238 1917,2014-04-07 15:45:00,92.26180754094288 1918,2014-04-07 15:50:00,88.39950791803334 1919,2014-04-07 15:55:00,101.3293856800238 1920,2014-04-07 16:00:00,98.29346314241428 1921,2014-04-07 16:05:00,86.31291150560476 1922,2014-04-07 16:10:00,98.55024602279525 1923,2014-04-07 16:15:00,98.14459463028571 1924,2014-04-07 16:20:00,86.47103301407618 1925,2014-04-07 16:25:00,92.23643583426667 1926,2014-04-07 16:30:00,96.03816330875713 1927,2014-04-07 16:35:00,93.58165590024763 1928,2014-04-07 16:40:00,98.79285385503809 1929,2014-04-07 16:45:00,93.15986058352857 1930,2014-04-07 16:50:00,88.82178359221905 1931,2014-04-07 16:55:00,101.99004127670953 1932,2014-04-07 17:00:00,90.24761074930001 1933,2014-04-07 17:05:00,97.86548538739048 1934,2014-04-07 17:10:00,88.68035341148095 1935,2014-04-07 17:15:00,91.66149357967143 1936,2014-04-07 17:20:00,93.4771732758619 1937,2014-04-07 17:25:00,89.48788562435239 1938,2014-04-07 17:30:00,93.61896566644286 1939,2014-04-07 17:35:00,88.94165988763334 1940,2014-04-07 17:40:00,95.37859735072381 1941,2014-04-07 17:45:00,97.06134460021428 1942,2014-04-07 17:50:00,87.44832527480476 1943,2014-04-07 17:55:00,100.39492617519524 1944,2014-04-07 18:00:00,44.449181621485714 1945,2014-04-07 18:05:00,44.71403990597619 1946,2014-04-07 18:10:00,47.511799300966665 1947,2014-04-07 18:15:00,46.28660782405714 1948,2014-04-07 18:20:00,46.49017331044762 1949,2014-04-07 18:25:00,44.12167430933809 1950,2014-04-07 18:30:00,48.46563131172857 1951,2014-04-07 18:35:00,47.26550993481905 1952,2014-04-07 18:40:00,44.190248905009526 1953,2014-04-07 18:45:00,45.7248399598 1954,2014-04-07 18:50:00,48.525307520290475 1955,2014-04-07 18:55:00,46.98359701868095 1956,2014-04-07 19:00:00,35.20031682647142 1957,2014-04-07 19:05:00,36.391051872361906 1958,2014-04-07 19:10:00,35.81572212045238 1959,2014-04-07 19:15:00,37.054137304442854 1960,2014-04-07 19:20:00,38.52158987753333 1961,2014-04-07 19:25:00,36.705249360323805 1962,2014-04-07 19:30:00,36.699585369314285 1963,2014-04-07 19:35:00,38.82162547590476 1964,2014-04-07 19:40:00,37.35440463859524 1965,2014-04-07 19:45:00,37.317070540785714 1966,2014-04-07 19:50:00,35.961331335776194 1967,2014-04-07 19:55:00,37.518013321666665 1968,2014-04-07 20:00:00,35.43378616795714 1969,2014-04-07 20:05:00,34.70780100084762 1970,2014-04-07 20:10:00,37.147626863238095 1971,2014-04-07 20:15:00,36.70940369932857 1972,2014-04-07 20:20:00,36.174924233719054 1973,2014-04-07 20:25:00,35.31302680630952 1974,2014-04-07 20:30:00,35.0120967047 1975,2014-04-07 20:35:00,33.884279976790474 1976,2014-04-07 20:40:00,34.38668140978095 1977,2014-04-07 20:45:00,36.31196460547143 1978,2014-04-07 20:50:00,35.0078173765619 1979,2014-04-07 20:55:00,36.77047805625239 1980,2014-04-07 21:00:00,33.413027250642855 1981,2014-04-07 21:05:00,34.86913193243333 1982,2014-04-07 21:10:00,35.433708236123806 1983,2014-04-07 21:15:00,34.91818155201429 1984,2014-04-07 21:20:00,36.422285431604756 1985,2014-04-07 21:25:00,36.83299792649524 1986,2014-04-07 21:30:00,33.328748327685716 1987,2014-04-07 21:35:00,33.39294089547619 1988,2014-04-07 21:40:00,33.401865298366666 1989,2014-04-07 21:45:00,35.62329407645714 1990,2014-04-07 21:50:00,34.39080733414762 1991,2014-04-07 21:55:00,35.84772633033809 1992,2014-04-07 22:00:00,34.46215146382857 1993,2014-04-07 22:05:00,35.35898593271905 1994,2014-04-07 22:10:00,35.935977790909526 1995,2014-04-07 22:15:00,35.0559987818 1996,2014-04-07 22:20:00,35.02855652189047 1997,2014-04-07 22:25:00,33.22918706428095 1998,2014-04-07 22:30:00,34.52805579247143 1999,2014-04-07 22:35:00,35.07599629196191 2000,2014-04-07 22:40:00,34.74792968025238 2001,2014-04-07 22:45:00,36.51225985014286 2002,2014-04-07 22:50:00,36.54271692883333 2003,2014-04-07 22:55:00,36.21137948412381 2004,2014-04-07 23:00:00,34.41565081421429 2005,2014-04-07 23:05:00,35.79135825230476 2006,2014-04-07 23:10:00,34.51050866199524 2007,2014-04-07 23:15:00,33.86704474018571 2008,2014-04-07 23:20:00,34.31580611197619 2009,2014-04-07 23:25:00,33.23528569886667 2010,2014-04-07 23:30:00,34.28617798205714 2011,2014-04-07 23:35:00,34.80957633614762 2012,2014-04-07 23:40:00,36.796351481538096 2013,2014-04-07 23:45:00,34.23501761372857 2014,2014-04-07 23:50:00,36.59908228661905 2015,2014-04-07 23:55:00,33.91162438840952 2016,2014-04-08 00:00:00,33.763875591 2017,2014-04-08 00:05:00,35.08342230189047 2018,2014-04-08 00:10:00,35.70492642958095 2019,2014-04-08 00:15:00,33.19965043177143 2020,2014-04-08 00:20:00,33.9140253649619 2021,2014-04-08 00:25:00,34.85993704695238 2022,2014-04-08 00:30:00,34.36866020104286 2023,2014-04-08 00:35:00,35.90256765073333 2024,2014-04-08 00:40:00,35.104166193723806 2025,2014-04-08 00:45:00,33.70840070811428 2026,2014-04-08 00:50:00,36.65226627920476 2027,2014-04-08 00:55:00,34.25346793999524 2028,2014-04-08 01:00:00,36.01381015018571 2029,2014-04-08 01:05:00,36.216389306876195 2030,2014-04-08 01:10:00,36.95679746766667 2031,2014-04-08 01:15:00,35.105637008957146 2032,2014-04-08 01:20:00,35.58238968094762 2033,2014-04-08 01:25:00,34.465993269138096 2034,2014-04-08 01:30:00,35.84664574502857 2035,2014-04-08 01:35:00,34.99490299111905 2036,2014-04-08 01:40:00,34.89941898270953 2037,2014-04-08 01:45:00,36.5781201165 2038,2014-04-08 01:50:00,33.364365850190474 2039,2014-04-08 01:55:00,36.69898066368095 2040,2014-04-08 02:00:00,36.586850779871426 2041,2014-04-08 02:05:00,35.21147691896191 2042,2014-04-08 02:10:00,35.15426379775238 2043,2014-04-08 02:15:00,34.64812232924286 2044,2014-04-08 02:20:00,37.18502850003333 2045,2014-04-08 02:25:00,33.660451140523804 2046,2014-04-08 02:30:00,35.58407522821429 2047,2014-04-08 02:35:00,35.95738112230476 2048,2014-04-08 02:40:00,36.97541527099524 2049,2014-04-08 02:45:00,36.366349701685714 2050,2014-04-08 02:50:00,35.82836500167619 2051,2014-04-08 02:55:00,33.72766593386667 2052,2014-04-08 03:00:00,34.76279121015715 2053,2014-04-08 03:05:00,33.83066418924762 2054,2014-04-08 03:10:00,36.80758902513809 2055,2014-04-08 03:15:00,36.288663193728574 2056,2014-04-08 03:20:00,36.32776619481905 2057,2014-04-08 03:25:00,35.91408559490952 2058,2014-04-08 03:30:00,35.3406741477 2059,2014-04-08 03:35:00,33.919824714090474 2060,2014-04-08 03:40:00,34.64616049918095 2061,2014-04-08 03:45:00,33.88248459847143 2062,2014-04-08 03:50:00,36.2419144761619 2063,2014-04-08 03:55:00,33.99061748505238 2064,2014-04-08 04:00:00,36.16559705784285 2065,2014-04-08 04:05:00,36.13360489173333 2066,2014-04-08 04:10:00,35.20924172552381 2067,2014-04-08 04:15:00,33.92037890221428 2068,2014-04-08 04:20:00,34.646108066404764 2069,2014-04-08 04:25:00,34.67471767439524 2070,2014-04-08 04:30:00,36.203326246885716 2071,2014-04-08 04:35:00,33.86419826817619 2072,2014-04-08 04:40:00,36.732941251566665 2073,2014-04-08 04:45:00,36.468136303557145 2074,2014-04-08 04:50:00,34.17677529174762 2075,2014-04-08 04:55:00,36.315645622338096 2076,2014-04-08 05:00:00,36.12048129732857 2077,2014-04-08 05:05:00,36.446352248019046 2078,2014-04-08 05:10:00,34.217023745609524 2079,2014-04-08 05:15:00,34.0991112886 2080,2014-04-08 05:20:00,34.422126419890475 2081,2014-04-08 05:25:00,34.94711776498095 2082,2014-04-08 05:30:00,36.66573135267143 2083,2014-04-08 05:35:00,36.4502076546619 2084,2014-04-08 05:40:00,37.20775875005238 2085,2014-04-08 05:45:00,33.747911093542854 2086,2014-04-08 05:50:00,33.56705845743333 2087,2014-04-08 05:55:00,36.324829128323806 2088,2014-04-08 06:00:00,34.652864268914286 2089,2014-04-08 06:05:00,34.87947034400476 2090,2014-04-08 06:10:00,35.737803341795235 2091,2014-04-08 06:15:00,33.967688206785716 2092,2014-04-08 06:20:00,36.13625385667619 2093,2014-04-08 06:25:00,34.87350645156667 2094,2014-04-08 06:30:00,36.11121764005714 2095,2014-04-08 06:35:00,36.92382527134762 2096,2014-04-08 06:40:00,34.27968342853809 2097,2014-04-08 06:45:00,37.326170943128574 2098,2014-04-08 06:50:00,35.73287161181905 2099,2014-04-08 06:55:00,37.30927058450953 2100,2014-04-08 07:00:00,34.455920328800005 2101,2014-04-08 07:05:00,36.05069113459047 2102,2014-04-08 07:10:00,35.25542942168095 2103,2014-04-08 07:15:00,36.744210193171426 2104,2014-04-08 07:20:00,36.078397677661904 2105,2014-04-08 07:25:00,35.640264208752384 2106,2014-04-08 07:30:00,37.32158448284286 2107,2014-04-08 07:35:00,35.185551590033334 2108,2014-04-08 07:40:00,34.564444629123805 2109,2014-04-08 07:45:00,36.124369033114284 2110,2014-04-08 07:50:00,36.19551851060476 2111,2014-04-08 07:55:00,35.463223724395235 2112,2014-04-08 08:00:00,35.66072588908571 2113,2014-04-08 08:05:00,37.55993984767619 2114,2014-04-08 08:10:00,36.659909432266666 2115,2014-04-08 08:15:00,34.17901414875714 2116,2014-04-08 08:20:00,34.592567902547614 2117,2014-04-08 08:25:00,37.653794632938094 2118,2014-04-08 08:30:00,36.66479078662857 2119,2014-04-08 08:35:00,37.42654955221904 2120,2014-04-08 08:40:00,34.98925537980952 2121,2014-04-08 08:45:00,36.7487174403 2122,2014-04-08 08:50:00,36.64470131029047 2123,2014-04-08 08:55:00,34.97489089418095 2124,2014-04-08 09:00:00,84.49467345467143 2125,2014-04-08 09:05:00,85.5438574180619 2126,2014-04-08 09:10:00,83.56184500825238 2127,2014-04-08 09:15:00,88.27552326764287 2128,2014-04-08 09:20:00,88.36035230183333 2129,2014-04-08 09:25:00,88.60894126642381 2130,2014-04-08 09:30:00,87.9747748254143 2131,2014-04-08 09:35:00,83.69359005180476 2132,2014-04-08 09:40:00,82.25065609289524 2133,2014-04-08 09:45:00,88.37725317278571 2134,2014-04-08 09:50:00,83.74471602687619 2135,2014-04-08 09:55:00,80.43606768796667 2136,2014-04-08 10:00:00,93.60682876445713 2137,2014-04-08 10:05:00,87.94180685524762 2138,2014-04-08 10:10:00,96.4818277893381 2139,2014-04-08 10:15:00,90.96867686222856 2140,2014-04-08 10:20:00,89.80804359951905 2141,2014-04-08 10:25:00,100.61507526540952 2142,2014-04-08 10:30:00,97.8346930542 2143,2014-04-08 10:35:00,98.00025915849048 2144,2014-04-08 10:40:00,95.47254591558095 2145,2014-04-08 10:45:00,98.82378344767143 2146,2014-04-08 10:50:00,97.5894636124619 2147,2014-04-08 10:55:00,95.10767026915238 2148,2014-04-08 11:00:00,102.83586534414287 2149,2014-04-08 11:05:00,90.60470941313332 2150,2014-04-08 11:10:00,102.56853486042381 2151,2014-04-08 11:15:00,93.9569368141143 2152,2014-04-08 11:20:00,95.98356219390476 2153,2014-04-08 11:25:00,89.53939137609524 2154,2014-04-08 11:30:00,96.1846544228857 2155,2014-04-08 11:35:00,97.32285837207618 2156,2014-04-08 11:40:00,103.47711198756667 2157,2014-04-08 11:45:00,103.12656724855714 2158,2014-04-08 11:50:00,102.99413014904762 2159,2014-04-08 11:55:00,93.17275180313808 2160,2014-04-08 12:00:00,103.82626023452855 2161,2014-04-08 12:05:00,95.27137429261906 2162,2014-04-08 12:10:00,101.61293440780952 2163,2014-04-08 12:15:00,91.4643161609 2164,2014-04-08 12:20:00,96.09840935369047 2165,2014-04-08 12:25:00,103.45987705818095 2166,2014-04-08 12:30:00,103.16399077657142 2167,2014-04-08 12:35:00,98.9637422402619 2168,2014-04-08 12:40:00,100.79426350685237 2169,2014-04-08 12:45:00,90.87143261024286 2170,2014-04-08 12:50:00,99.59211428093333 2171,2014-04-08 12:55:00,97.9438201673238 2172,2014-04-08 13:00:00,89.6079104991143 2173,2014-04-08 13:05:00,89.96098433670475 2174,2014-04-08 13:10:00,89.89299669859524 2175,2014-04-08 13:15:00,99.7526851408857 2176,2014-04-08 13:20:00,90.4400953360762 2177,2014-04-08 13:25:00,95.66255691256666 2178,2014-04-08 13:30:00,93.89841522675714 2179,2014-04-08 13:35:00,97.00146993544763 2180,2014-04-08 13:40:00,99.5038690210381 2181,2014-04-08 13:45:00,99.16332983242857 2182,2014-04-08 13:50:00,96.46417810581904 2183,2014-04-08 13:55:00,95.65285445570952 2184,2014-04-08 14:00:00,94.6112879996 2185,2014-04-08 14:05:00,102.04388170219048 2186,2014-04-08 14:10:00,93.55479973618095 2187,2014-04-08 14:15:00,92.41851937427143 2188,2014-04-08 14:20:00,100.16878293696192 2189,2014-04-08 14:25:00,94.03968546975238 2190,2014-04-08 14:30:00,101.84251395834286 2191,2014-04-08 14:35:00,93.54459501303333 2192,2014-04-08 14:40:00,99.5366459091238 2193,2014-04-08 14:45:00,89.03521774251428 2194,2014-04-08 14:50:00,94.48965873140476 2195,2014-04-08 14:55:00,93.81980843679524 2196,2014-04-08 15:00:00,101.4053289008857 2197,2014-04-08 15:05:00,103.8187729023762 2198,2014-04-08 15:10:00,95.72750510236665 2199,2014-04-08 15:15:00,101.55816968245713 2200,2014-04-08 15:20:00,99.56336416124762 2201,2014-04-08 15:25:00,103.85382410733808 2202,2014-04-08 15:30:00,101.36084901462857 2203,2014-04-08 15:35:00,89.63031500241905 2204,2014-04-08 15:40:00,99.81051632180952 2205,2014-04-08 15:45:00,96.973471994 2206,2014-04-08 15:50:00,88.67597367849046 2207,2014-04-08 15:55:00,92.44140849028095 2208,2014-04-08 16:00:00,103.17648879267144 2209,2014-04-08 16:05:00,103.2528271807619 2210,2014-04-08 16:10:00,101.22489696345238 2211,2014-04-08 16:15:00,104.15919810934285 2212,2014-04-08 16:20:00,101.36289391023332 2213,2014-04-08 16:25:00,88.62890225262382 2214,2014-04-08 16:30:00,93.07841664831429 2215,2014-04-08 16:35:00,88.97050249690476 2216,2014-04-08 16:40:00,89.99368160689524 2217,2014-04-08 16:45:00,91.9968438226857 2218,2014-04-08 16:50:00,96.55975922237619 2219,2014-04-08 16:55:00,102.07076444586667 2220,2014-04-08 17:00:00,102.30929229745713 2221,2014-04-08 17:05:00,98.38449592204762 2222,2014-04-08 17:10:00,103.38351976953811 2223,2014-04-08 17:15:00,96.54114507652857 2224,2014-04-08 17:20:00,102.77216264351905 2225,2014-04-08 17:25:00,95.82007318730952 2226,2014-04-08 17:30:00,92.9980707675 2227,2014-04-08 17:35:00,103.2325138873905 2228,2014-04-08 17:40:00,94.78431213178095 2229,2014-04-08 17:45:00,96.63925642917144 2230,2014-04-08 17:50:00,93.8540023567619 2231,2014-04-08 17:55:00,99.20507226515238 2232,2014-04-08 18:00:00,51.77533594484285 2233,2014-04-08 18:05:00,45.57786448513333 2234,2014-04-08 18:10:00,51.18104441262381 2235,2014-04-08 18:15:00,45.45458551601429 2236,2014-04-08 18:20:00,47.76795722410476 2237,2014-04-08 18:25:00,46.52342306159524 2238,2014-04-08 18:30:00,50.298766650385716 2239,2014-04-08 18:35:00,45.78312997957619 2240,2014-04-08 18:40:00,49.008964159866665 2241,2014-04-08 18:45:00,47.36162850745714 2242,2014-04-08 18:50:00,46.337031517947615 2243,2014-04-08 18:55:00,50.428618174638096 2244,2014-04-08 19:00:00,37.83045482952857 2245,2014-04-08 19:05:00,37.86593283671905 2246,2014-04-08 19:10:00,38.10365234770953 2247,2014-04-08 19:15:00,39.5074638518 2248,2014-04-08 19:20:00,39.84149258209048 2249,2014-04-08 19:25:00,36.97248914828096 2250,2014-04-08 19:30:00,37.98464623297143 2251,2014-04-08 19:35:00,38.839260067361906 2252,2014-04-08 19:40:00,38.40320793915238 2253,2014-04-08 19:45:00,40.88447608404286 2254,2014-04-08 19:50:00,40.459767148233325 2255,2014-04-08 19:55:00,39.74226071542381 2256,2014-04-08 20:00:00,36.60233578381428 2257,2014-04-08 20:05:00,38.09510843080476 2258,2014-04-08 20:10:00,38.688136276095236 2259,2014-04-08 20:15:00,37.67646068948571 2260,2014-04-08 20:20:00,38.460630099176186 2261,2014-04-08 20:25:00,38.323250330566665 2262,2014-04-08 20:30:00,37.604192920057145 2263,2014-04-08 20:35:00,36.548499838647615 2264,2014-04-08 20:40:00,38.3319615565381 2265,2014-04-08 20:45:00,36.131716256728566 2266,2014-04-08 20:50:00,38.48490305531905 2267,2014-04-08 20:55:00,38.594982514109525 2268,2014-04-08 21:00:00,38.265764647699996 2269,2014-04-08 21:05:00,36.869584297890476 2270,2014-04-08 21:10:00,35.74989960808095 2271,2014-04-08 21:15:00,35.38453047677143 2272,2014-04-08 21:20:00,37.97887939116191 2273,2014-04-08 21:25:00,38.56066408475238 2274,2014-04-08 21:30:00,37.62189233834286 2275,2014-04-08 21:35:00,35.59289140243334 2276,2014-04-08 21:40:00,38.77845956202381 2277,2014-04-08 21:45:00,39.00376304861429 2278,2014-04-08 21:50:00,36.777640022504755 2279,2014-04-08 21:55:00,37.43396699069524 2280,2014-04-08 22:00:00,38.09346434138571 2281,2014-04-08 22:05:00,37.93739307717619 2282,2014-04-08 22:10:00,38.871311726466665 2283,2014-04-08 22:15:00,35.46386064915714 2284,2014-04-08 22:20:00,37.33645705714761 2285,2014-04-08 22:25:00,37.78915078033809 2286,2014-04-08 22:30:00,38.59002023552857 2287,2014-04-08 22:35:00,38.533444128919044 2288,2014-04-08 22:40:00,38.95684420650952 2289,2014-04-08 22:45:00,37.0988101872 2290,2014-04-08 22:50:00,38.382204054690476 2291,2014-04-08 22:55:00,36.774178536980955 2292,2014-04-08 23:00:00,36.746607275071426 2293,2014-04-08 23:05:00,36.078055932361906 2294,2014-04-08 23:10:00,38.345485933152375 2295,2014-04-08 23:15:00,39.02336638424286 2296,2014-04-08 23:20:00,36.112353115333335 2297,2014-04-08 23:25:00,35.31879926892381 2298,2014-04-08 23:30:00,38.36446636991428 2299,2014-04-08 23:35:00,37.59050730670476 2300,2014-04-08 23:40:00,38.95608348679524 2301,2014-04-08 23:45:00,36.133142308485716 2302,2014-04-08 23:50:00,35.415597369876195 2303,2014-04-08 23:55:00,37.10901990386667 2304,2014-04-09 00:00:00,35.484721234757146 2305,2014-04-09 00:05:00,36.19745762344762 2306,2014-04-09 00:10:00,35.66164953853809 2307,2014-04-09 00:15:00,36.061707290028565 2308,2014-04-09 00:20:00,35.59719765891904 2309,2014-04-09 00:25:00,38.99568352150952 2310,2014-04-09 00:30:00,36.3017508538 2311,2014-04-09 00:35:00,36.970530820190476 2312,2014-04-09 00:40:00,38.79682818288096 2313,2014-04-09 00:45:00,37.91910778037143 2314,2014-04-09 00:50:00,37.6894118269619 2315,2014-04-09 00:55:00,38.04695514235238 2316,2014-04-09 01:00:00,38.547431885542856 2317,2014-04-09 01:05:00,38.75026040473333 2318,2014-04-09 01:10:00,37.817582492223806 2319,2014-04-09 01:15:00,38.814493384514286 2320,2014-04-09 01:20:00,37.403494871604764 2321,2014-04-09 01:25:00,36.378508663195234 2322,2014-04-09 01:30:00,38.79709254978572 2323,2014-04-09 01:35:00,37.45011750017619 2324,2014-04-09 01:40:00,38.91621701696667 2325,2014-04-09 01:45:00,35.45977839865714 2326,2014-04-09 01:50:00,36.89661062524762 2327,2014-04-09 01:55:00,39.1052081686381 2328,2014-04-09 02:00:00,36.320028942428564 2329,2014-04-09 02:05:00,39.09501403181905 2330,2014-04-09 02:10:00,39.15191936830952 2331,2014-04-09 02:15:00,38.8723192569 2332,2014-04-09 02:20:00,37.605862656590475 2333,2014-04-09 02:25:00,37.94638874868095 2334,2014-04-09 02:30:00,38.844539422371426 2335,2014-04-09 02:35:00,38.477100234361906 2336,2014-04-09 02:40:00,37.901327778752375 2337,2014-04-09 02:45:00,39.317430488642856 2338,2014-04-09 02:50:00,38.13853987863333 2339,2014-04-09 02:55:00,39.30520177932381 2340,2014-04-09 03:00:00,35.640268184114284 2341,2014-04-09 03:05:00,35.973996244904754 2342,2014-04-09 03:10:00,37.23143062209524 2343,2014-04-09 03:15:00,36.972553557785716 2344,2014-04-09 03:20:00,38.571415555876186 2345,2014-04-09 03:25:00,36.09037277256667 2346,2014-04-09 03:30:00,39.35973785925714 2347,2014-04-09 03:35:00,36.72306112004762 2348,2014-04-09 03:40:00,37.185932926238095 2349,2014-04-09 03:45:00,36.57665870122857 2350,2014-04-09 03:50:00,37.80257351691905 2351,2014-04-09 03:55:00,35.72707432550952 2352,2014-04-09 04:00:00,36.0987100223 2353,2014-04-09 04:05:00,38.49063128989047 2354,2014-04-09 04:10:00,36.26088328598095 2355,2014-04-09 04:15:00,36.46437923477143 2356,2014-04-09 04:20:00,38.70169084766191 2357,2014-04-09 04:25:00,35.91040709435238 2358,2014-04-09 04:30:00,37.29453814824286 2359,2014-04-09 04:35:00,35.64433688133333 2360,2014-04-09 04:40:00,36.94675340682381 2361,2014-04-09 04:45:00,38.36288989611428 2362,2014-04-09 04:50:00,35.93481788080476 2363,2014-04-09 04:55:00,39.135183745195235 2364,2014-04-09 05:00:00,39.227281886085706 2365,2014-04-09 05:05:00,36.01668769097619 2366,2014-04-09 05:10:00,39.56709641216666 2367,2014-04-09 05:15:00,36.80172535645714 2368,2014-04-09 05:20:00,35.95545430354762 2369,2014-04-09 05:25:00,35.64675655323809 2370,2014-04-09 05:30:00,37.26802015452857 2371,2014-04-09 05:35:00,38.16060899041905 2372,2014-04-09 05:40:00,36.97752652340952 2373,2014-04-09 05:45:00,39.0031194619 2374,2014-04-09 05:50:00,38.530115578490474 2375,2014-04-09 05:55:00,37.07177708028095 2376,2014-04-09 06:00:00,38.61581009497143 2377,2014-04-09 06:05:00,39.4479628526619 2378,2014-04-09 06:10:00,36.06583637515238 2379,2014-04-09 06:15:00,36.92530869774286 2380,2014-04-09 06:20:00,37.56163708983333 2381,2014-04-09 06:25:00,37.70773432052381 2382,2014-04-09 06:30:00,37.89199686521428 2383,2014-04-09 06:35:00,36.93316238810476 2384,2014-04-09 06:40:00,38.40713382199524 2385,2014-04-09 06:45:00,38.325873728385716 2386,2014-04-09 06:50:00,38.06426221557619 2387,2014-04-09 06:55:00,36.21546355346666 2388,2014-04-09 07:00:00,37.67572870725714 2389,2014-04-09 07:05:00,37.20020516904762 2390,2014-04-09 07:10:00,37.746891974638096 2391,2014-04-09 07:15:00,39.47764431352857 2392,2014-04-09 07:20:00,37.719744420219044 2393,2014-04-09 07:25:00,35.86098269120952 2394,2014-04-09 07:30:00,37.5678469523 2395,2014-04-09 07:35:00,39.102533196390475 2396,2014-04-09 07:40:00,38.94762464528095 2397,2014-04-09 07:45:00,37.888381722671426 2398,2014-04-09 07:50:00,36.84133795616191 2399,2014-04-09 07:55:00,37.71005703265238 2400,2014-04-09 08:00:00,38.11195173484286 2401,2014-04-09 08:05:00,39.86406908643333 2402,2014-04-09 08:10:00,38.44873617022381 2403,2014-04-09 08:15:00,38.65652400601428 2404,2014-04-09 08:20:00,37.85272133620476 2405,2014-04-09 08:25:00,37.31230344119524 2406,2014-04-09 08:30:00,39.15359764888571 2407,2014-04-09 08:35:00,37.88895548787619 2408,2014-04-09 08:40:00,39.895427186566664 2409,2014-04-09 08:45:00,37.75258943995714 2410,2014-04-09 08:50:00,36.20354875364762 2411,2014-04-09 08:55:00,38.669300643638095 2412,2014-04-09 09:00:00,79.78075230402858 2413,2014-04-09 09:05:00,82.56069076521905 2414,2014-04-09 09:10:00,83.97214976160951 2415,2014-04-09 09:15:00,89.2257267645 2416,2014-04-09 09:20:00,85.89779907529046 2417,2014-04-09 09:25:00,79.57321561818095 2418,2014-04-09 09:30:00,87.58022940597142 2419,2014-04-09 09:35:00,84.7940447337619 2420,2014-04-09 09:40:00,91.74290171655238 2421,2014-04-09 09:45:00,86.00744028864285 2422,2014-04-09 09:50:00,88.86289531813333 2423,2014-04-09 09:55:00,82.20488530522381 2424,2014-04-09 10:00:00,99.68602400721429 2425,2014-04-09 10:05:00,99.07238118060476 2426,2014-04-09 10:10:00,101.92194335469524 2427,2014-04-09 10:15:00,88.42294759378571 2428,2014-04-09 10:20:00,94.85068701747619 2429,2014-04-09 10:25:00,98.45340851716668 2430,2014-04-09 10:30:00,89.39730087205714 2431,2014-04-09 10:35:00,94.30037274124763 2432,2014-04-09 10:40:00,102.5573533748381 2433,2014-04-09 10:45:00,94.70838187002856 2434,2014-04-09 10:50:00,103.24360128721905 2435,2014-04-09 10:55:00,88.83970175180951 2436,2014-04-09 11:00:00,101.1093647597 2437,2014-04-09 11:05:00,98.94092269749046 2438,2014-04-09 11:10:00,97.66846397748095 2439,2014-04-09 11:15:00,105.15567850177143 2440,2014-04-09 11:20:00,91.7847218741619 2441,2014-04-09 11:25:00,103.98016970845238 2442,2014-04-09 11:30:00,100.73113035584286 2443,2014-04-09 11:35:00,93.86415688313332 2444,2014-04-09 11:40:00,104.09266990162381 2445,2014-04-09 11:45:00,96.5874706594143 2446,2014-04-09 11:50:00,102.71687618760475 2447,2014-04-09 11:55:00,95.95890120519525 2448,2014-04-09 12:00:00,103.7264410812857 2449,2014-04-09 12:05:00,100.3091688064762 2450,2014-04-09 12:10:00,92.39680470866665 2451,2014-04-09 12:15:00,100.53234422565714 2452,2014-04-09 12:20:00,93.21549000284762 2453,2014-04-09 12:25:00,96.74794122713809 2454,2014-04-09 12:30:00,92.89398824422857 2455,2014-04-09 12:35:00,90.53180418891905 2456,2014-04-09 12:40:00,93.57352593340951 2457,2014-04-09 12:45:00,98.7665040367 2458,2014-04-09 12:50:00,97.89801999009049 2459,2014-04-09 12:55:00,98.22405573668095 2460,2014-04-09 13:00:00,94.24833036607143 2461,2014-04-09 13:05:00,101.25368009556192 2462,2014-04-09 13:10:00,101.56668059905239 2463,2014-04-09 13:15:00,96.03472346964286 2464,2014-04-09 13:20:00,104.41139105573333 2465,2014-04-09 13:25:00,100.62539222652381 2466,2014-04-09 13:30:00,101.73682461901427 2467,2014-04-09 13:35:00,94.77474846360477 2468,2014-04-09 13:40:00,90.35559905189524 2469,2014-04-09 13:45:00,104.19594246558573 2470,2014-04-09 13:50:00,103.51632823407618 2471,2014-04-09 13:55:00,92.33873381846666 2472,2014-04-09 14:00:00,96.37479598945714 2473,2014-04-09 14:05:00,100.97776264464763 2474,2014-04-09 14:10:00,100.83755498963808 2475,2014-04-09 14:15:00,104.17666717932858 2476,2014-04-09 14:20:00,92.66334590781905 2477,2014-04-09 14:25:00,97.30530929460951 2478,2014-04-09 14:30:00,91.9895600185 2479,2014-04-09 14:35:00,96.67470924209047 2480,2014-04-09 14:40:00,90.69063247928095 2481,2014-04-09 14:45:00,104.82804459657142 2482,2014-04-09 14:50:00,98.8961050842619 2483,2014-04-09 14:55:00,104.06742990565239 2484,2014-04-09 15:00:00,91.43991767184286 2485,2014-04-09 15:05:00,94.12818696333333 2486,2014-04-09 15:10:00,94.64637269232381 2487,2014-04-09 15:15:00,96.69077760411429 2488,2014-04-09 15:20:00,103.35695220000477 2489,2014-04-09 15:25:00,96.70352064249523 2490,2014-04-09 15:30:00,93.8005195538857 2491,2014-04-09 15:35:00,91.5733691733762 2492,2014-04-09 15:40:00,91.81283123036667 2493,2014-04-09 15:45:00,102.70905449495714 2494,2014-04-09 15:50:00,97.67263595384762 2495,2014-04-09 15:55:00,102.18208330583809 2496,2014-04-09 16:00:00,101.48786331982858 2497,2014-04-09 16:05:00,92.74452603741905 2498,2014-04-09 16:10:00,92.87237384140953 2499,2014-04-09 16:15:00,102.6790608028 2500,2014-04-09 16:20:00,102.14132277459046 2501,2014-04-09 16:25:00,96.65697336928095 2502,2014-04-09 16:30:00,91.85468702347143 2503,2014-04-09 16:35:00,90.81694164026192 2504,2014-04-09 16:40:00,95.24131648015238 2505,2014-04-09 16:45:00,90.78581071124286 2506,2014-04-09 16:50:00,94.32684996313333 2507,2014-04-09 16:55:00,97.3651345258238 2508,2014-04-09 17:00:00,92.60333813671429 2509,2014-04-09 17:05:00,92.33657059850476 2510,2014-04-09 17:10:00,105.01856105389524 2511,2014-04-09 17:15:00,100.0505249334857 2512,2014-04-09 17:20:00,105.64173378937619 2513,2014-04-09 17:25:00,96.23110551446666 2514,2014-04-09 17:30:00,101.53964433175715 2515,2014-04-09 17:35:00,93.98783550734763 2516,2014-04-09 17:40:00,100.61365172463809 2517,2014-04-09 17:45:00,92.80102180742857 2518,2014-04-09 17:50:00,90.76838161361906 2519,2014-04-09 17:55:00,105.64703497500953 2520,2014-04-09 18:00:00,51.1013177961 2521,2014-04-09 18:05:00,53.48985404939047 2522,2014-04-09 18:10:00,49.70139676428096 2523,2014-04-09 18:15:00,49.67014633887143 2524,2014-04-09 18:20:00,50.143947894161904 2525,2014-04-09 18:25:00,52.105858281052384 2526,2014-04-09 18:30:00,51.21581189104286 2527,2014-04-09 18:35:00,53.524348072133336 2528,2014-04-09 18:40:00,47.77234001592381 2529,2014-04-09 18:45:00,52.14941188891429 2530,2014-04-09 18:50:00,49.73849603830476 2531,2014-04-09 18:55:00,48.78533485869524 2532,2014-04-09 19:00:00,41.28585687178571 2533,2014-04-09 19:05:00,41.26941071357619 2534,2014-04-09 19:10:00,39.62797493556667 2535,2014-04-09 19:15:00,39.926100318757136 2536,2014-04-09 19:20:00,40.857624111547615 2537,2014-04-09 19:25:00,40.8679620163381 2538,2014-04-09 19:30:00,40.46658785292857 2539,2014-04-09 19:35:00,39.71685018391905 2540,2014-04-09 19:40:00,39.07840249920952 2541,2014-04-09 19:45:00,43.412901735300004 2542,2014-04-09 19:50:00,43.300565687490476 2543,2014-04-09 19:55:00,41.24788342628095 2544,2014-04-09 20:00:00,41.43630313987143 2545,2014-04-09 20:05:00,40.127299789361906 2546,2014-04-09 20:10:00,37.65749263045238 2547,2014-04-09 20:15:00,37.86506637364286 2548,2014-04-09 20:20:00,41.142723083633335 2549,2014-04-09 20:25:00,39.97846737742381 2550,2014-04-09 20:30:00,40.85889415791428 2551,2014-04-09 20:35:00,41.09196698150476 2552,2014-04-09 20:40:00,39.254865473095236 2553,2014-04-09 20:45:00,37.62629778838571 2554,2014-04-09 20:50:00,38.20617226907619 2555,2014-04-09 20:55:00,37.715095138366664 2556,2014-04-09 21:00:00,37.862840284557144 2557,2014-04-09 21:05:00,38.76171150874762 2558,2014-04-09 21:10:00,37.594194670638096 2559,2014-04-09 21:15:00,37.79671279512857 2560,2014-04-09 21:20:00,38.925865905519046 2561,2014-04-09 21:25:00,38.508674560009524 2562,2014-04-09 21:30:00,39.028511483900004 2563,2014-04-09 21:35:00,38.881268641690475 2564,2014-04-09 21:40:00,39.75406698378096 2565,2014-04-09 21:45:00,40.93797360997142 2566,2014-04-09 21:50:00,37.612190208561906 2567,2014-04-09 21:55:00,37.58504872785238 2568,2014-04-09 22:00:00,40.53892206644286 2569,2014-04-09 22:05:00,39.15939470543333 2570,2014-04-09 22:10:00,40.207866888723814 2571,2014-04-09 22:15:00,38.00925911101429 2572,2014-04-09 22:20:00,40.47281787640476 2573,2014-04-09 22:25:00,40.86055929519524 2574,2014-04-09 22:30:00,39.71343802118571 2575,2014-04-09 22:35:00,37.60042884277619 2576,2014-04-09 22:40:00,40.76856384476666 2577,2014-04-09 22:45:00,40.364381194757144 2578,2014-04-09 22:50:00,40.205222085447616 2579,2014-04-09 22:55:00,37.35332187813809 2580,2014-04-09 23:00:00,40.39634827362857 2581,2014-04-09 23:05:00,37.75923503401905 2582,2014-04-09 23:10:00,38.10448101930952 2583,2014-04-09 23:15:00,39.531188577 2584,2014-04-09 23:20:00,38.289773071190474 2585,2014-04-09 23:25:00,39.882987690980954 2586,2014-04-09 23:30:00,39.67727621547142 2587,2014-04-09 23:35:00,37.68464935386191 2588,2014-04-09 23:40:00,39.88397051645238 2589,2014-04-09 23:45:00,40.96337809164285 2590,2014-04-09 23:50:00,37.918852684633336 2591,2014-04-09 23:55:00,39.670436434923815 2592,2014-04-10 00:00:00,38.65317577341428 2593,2014-04-10 00:05:00,39.13160144900476 2594,2014-04-10 00:10:00,38.44859595439524 2595,2014-04-10 00:15:00,38.72455825968571 2596,2014-04-10 00:20:00,37.43112348357619 2597,2014-04-10 00:25:00,41.24912361836667 2598,2014-04-10 00:30:00,39.82955683115714 2599,2014-04-10 00:35:00,39.34061998104762 2600,2014-04-10 00:40:00,38.88009949323809 2601,2014-04-10 00:45:00,39.510176806728566 2602,2014-04-10 00:50:00,38.88054304251905 2603,2014-04-10 00:55:00,38.80719123380952 2604,2014-04-10 01:00:00,39.2307861669 2605,2014-04-10 01:05:00,38.48637261089047 2606,2014-04-10 01:10:00,38.11008055228095 2607,2014-04-10 01:15:00,39.62374502127143 2608,2014-04-10 01:20:00,40.775823649361904 2609,2014-04-10 01:25:00,38.023515091852374 2610,2014-04-10 01:30:00,37.55058021954286 2611,2014-04-10 01:35:00,38.414330313933334 2612,2014-04-10 01:40:00,41.353406383323815 2613,2014-04-10 01:45:00,40.756996580714286 2614,2014-04-10 01:50:00,39.83286897600476 2615,2014-04-10 01:55:00,41.17384089909524 2616,2014-04-10 02:00:00,39.24540218158571 2617,2014-04-10 02:05:00,41.40484860077619 2618,2014-04-10 02:10:00,38.66437484716666 2619,2014-04-10 02:15:00,38.44783014095714 2620,2014-04-10 02:20:00,40.04624042364762 2621,2014-04-10 02:25:00,39.014103967038096 2622,2014-04-10 02:30:00,40.01439073932857 2623,2014-04-10 02:35:00,38.73635112081905 2624,2014-04-10 02:40:00,39.99548255120952 2625,2014-04-10 02:45:00,38.6342350423 2626,2014-04-10 02:50:00,37.74257875149047 2627,2014-04-10 02:55:00,41.194674560080955 2628,2014-04-10 03:00:00,41.086392236071426 2629,2014-04-10 03:05:00,41.444204501861904 2630,2014-04-10 03:10:00,40.43456108585238 2631,2014-04-10 03:15:00,40.30677756804286 2632,2014-04-10 03:20:00,39.81934561363333 2633,2014-04-10 03:25:00,38.09454347492381 2634,2014-04-10 03:30:00,38.355155529514285 2635,2014-04-10 03:35:00,38.76353351660476 2636,2014-04-10 03:40:00,41.173720688395235 2637,2014-04-10 03:45:00,38.31241381268571 2638,2014-04-10 03:50:00,41.319468888476194 2639,2014-04-10 03:55:00,39.726559598866665 2640,2014-04-10 04:00:00,40.50513568475714 2641,2014-04-10 04:05:00,38.09127556574762 2642,2014-04-10 04:10:00,38.7338722903381 2643,2014-04-10 04:15:00,41.49925300412857 2644,2014-04-10 04:20:00,38.73721883531905 2645,2014-04-10 04:25:00,38.86614640540952 2646,2014-04-10 04:30:00,38.477889539399996 2647,2014-04-10 04:35:00,38.211235137390474 2648,2014-04-10 04:40:00,38.63541151818095 2649,2014-04-10 04:45:00,40.279128996371426 2650,2014-04-10 04:50:00,39.5387328387619 2651,2014-04-10 04:55:00,39.93972572635238 2652,2014-04-10 05:00:00,38.221602172242854 2653,2014-04-10 05:05:00,40.94804912203333 2654,2014-04-10 05:10:00,40.88340261182381 2655,2014-04-10 05:15:00,37.840823930314286 2656,2014-04-10 05:20:00,39.29596513990476 2657,2014-04-10 05:25:00,38.04442764599524 2658,2014-04-10 05:30:00,40.94520883198571 2659,2014-04-10 05:35:00,40.73330492297619 2660,2014-04-10 05:40:00,41.399619043866664 2661,2014-04-10 05:45:00,38.74472297865714 2662,2014-04-10 05:50:00,39.63173115154761 2663,2014-04-10 05:55:00,38.551939603938095 2664,2014-04-10 06:00:00,39.30636830932857 2665,2014-04-10 06:05:00,39.917842053919045 2666,2014-04-10 06:10:00,38.04963268320952 2667,2014-04-10 06:15:00,40.703231642700004 2668,2014-04-10 06:20:00,40.02436391769048 2669,2014-04-10 06:25:00,41.17446702118095 2670,2014-04-10 06:30:00,38.953193433371425 2671,2014-04-10 06:35:00,41.4867963258619 2672,2014-04-10 06:40:00,41.87572939305238 2673,2014-04-10 06:45:00,41.56558661064285 2674,2014-04-10 06:50:00,41.00740323663333 2675,2014-04-10 06:55:00,41.15274902102381 2676,2014-04-10 07:00:00,40.20569125591429 2677,2014-04-10 07:05:00,38.678770213604764 2678,2014-04-10 07:10:00,40.633757978695236 2679,2014-04-10 07:15:00,40.78404772248571 2680,2014-04-10 07:20:00,41.88201675157619 2681,2014-04-10 07:25:00,40.11312193166667 2682,2014-04-10 07:30:00,39.040833202957145 2683,2014-04-10 07:35:00,40.69748770604762 2684,2014-04-10 07:40:00,41.8877413739381 2685,2014-04-10 07:45:00,38.68653420452857 2686,2014-04-10 07:50:00,39.28911072171905 2687,2014-04-10 07:55:00,40.16008333890952 2688,2014-04-10 08:00:00,38.6808585395 2689,2014-04-10 08:05:00,38.09632303429048 2690,2014-04-10 08:10:00,39.36281344218095 2691,2014-04-10 08:15:00,41.48380463457143 2692,2014-04-10 08:20:00,38.20363550206191 2693,2014-04-10 08:25:00,39.75291861705238 2694,2014-04-10 08:30:00,41.093445948842856 2695,2014-04-10 08:35:00,41.864813720933334 2696,2014-04-10 08:40:00,42.001425405523804 2697,2014-04-10 08:45:00,39.754841808114286 2698,2014-04-10 08:50:00,41.875941939404754 2699,2014-04-10 08:55:00,38.22352113119524 2700,2014-04-10 09:00:00,91.43375607108571 2701,2014-04-10 09:05:00,90.03807226147619 2702,2014-04-10 09:10:00,84.69766392986665 2703,2014-04-10 09:15:00,88.21113875205714 2704,2014-04-10 09:20:00,83.08097845254763 2705,2014-04-10 09:25:00,93.1802093481381 2706,2014-04-10 09:30:00,86.20134253482857 2707,2014-04-10 09:35:00,89.85557384591905 2708,2014-04-10 09:40:00,83.50816701730953 2709,2014-04-10 09:45:00,84.160091887 2710,2014-04-10 09:50:00,94.85429711909046 2711,2014-04-10 09:55:00,91.61310591678094 2712,2014-04-10 10:00:00,104.94837484747143 2713,2014-04-10 10:05:00,94.61762198886191 2714,2014-04-10 10:10:00,92.58746822605238 2715,2014-04-10 10:15:00,97.84851541034286 2716,2014-04-10 10:20:00,97.72558507353334 2717,2014-04-10 10:25:00,92.77094370302382 2718,2014-04-10 10:30:00,101.44278200561428 2719,2014-04-10 10:35:00,95.68544209640476 2720,2014-04-10 10:40:00,92.97048362209523 2721,2014-04-10 10:45:00,95.23791799758571 2722,2014-04-10 10:50:00,98.84095920877618 2723,2014-04-10 10:55:00,101.37524553406666 2724,2014-04-10 11:00:00,99.49984979475714 2725,2014-04-10 11:05:00,100.20236033724761 2726,2014-04-10 11:10:00,94.06053426043809 2727,2014-04-10 11:15:00,106.40542303802857 2728,2014-04-10 11:20:00,106.63604869251905 2729,2014-04-10 11:25:00,102.74227601780952 2730,2014-04-10 11:30:00,92.1609099277 2731,2014-04-10 11:35:00,100.42956880589048 2732,2014-04-10 11:40:00,101.90247948448095 2733,2014-04-10 11:45:00,107.72180219047144 2734,2014-04-10 11:50:00,107.75171076016193 2735,2014-04-10 11:55:00,105.55715146755237 2736,2014-04-10 12:00:00,93.29081317454286 2737,2014-04-10 12:05:00,107.51230267913333 2738,2014-04-10 12:10:00,102.07644066802382 2739,2014-04-10 12:15:00,105.09187558741428 2740,2014-04-10 12:20:00,98.80777225420475 2741,2014-04-10 12:25:00,97.41651912399524 2742,2014-04-10 12:30:00,99.7183977543857 2743,2014-04-10 12:35:00,94.66999840737618 2744,2014-04-10 12:40:00,98.03646921686666 2745,2014-04-10 12:45:00,106.04312088315713 2746,2014-04-10 12:50:00,92.95162674984762 2747,2014-04-10 12:55:00,94.76373998593809 2748,2014-04-10 13:00:00,94.43052667972857 2749,2014-04-10 13:05:00,98.88424992071906 2750,2014-04-10 13:10:00,108.3919915084095 2751,2014-04-10 13:15:00,95.2245311889 2752,2014-04-10 13:20:00,94.78607421639049 2753,2014-04-10 13:25:00,107.10372881478095 2754,2014-04-10 13:30:00,106.58321262607143 2755,2014-04-10 13:35:00,92.9969540216619 2756,2014-04-10 13:40:00,104.51308119295238 2757,2014-04-10 13:45:00,102.98104709244286 2758,2014-04-10 13:50:00,104.7844581662333 2759,2014-04-10 13:55:00,100.4211341968238 2760,2014-04-10 14:00:00,108.3935644016143 2761,2014-04-10 14:05:00,93.24121738680476 2762,2014-04-10 14:10:00,96.29690462319525 2763,2014-04-10 14:15:00,98.8990109585857 2764,2014-04-10 14:20:00,99.75812182607619 2765,2014-04-10 14:25:00,107.31063149966667 2766,2014-04-10 14:30:00,101.53654088475713 2767,2014-04-10 14:35:00,93.30608290214762 2768,2014-04-10 14:40:00,99.11727627133808 2769,2014-04-10 14:45:00,99.26274930472857 2770,2014-04-10 14:50:00,108.05377656561905 2771,2014-04-10 14:55:00,102.20079679680953 2772,2014-04-10 15:00:00,102.7946283025 2773,2014-04-10 15:05:00,104.04368822059047 2774,2014-04-10 15:10:00,104.95970052528095 2775,2014-04-10 15:15:00,102.80734980797142 2776,2014-04-10 15:20:00,96.44914388986192 2777,2014-04-10 15:25:00,106.64611155695238 2778,2014-04-10 15:30:00,104.38275601014287 2779,2014-04-10 15:35:00,104.54620594353334 2780,2014-04-10 15:40:00,108.62858736612381 2781,2014-04-10 15:45:00,105.5315743754143 2782,2014-04-10 15:50:00,105.96500865470476 2783,2014-04-10 15:55:00,107.92849615359523 2784,2014-04-10 16:00:00,95.13228682898571 2785,2014-04-10 16:05:00,100.6852106839762 2786,2014-04-10 16:10:00,102.01808296906665 2787,2014-04-10 16:15:00,98.00487045505714 2788,2014-04-10 16:20:00,106.17433709484762 2789,2014-04-10 16:25:00,104.9500403800381 2790,2014-04-10 16:30:00,104.29289737802857 2791,2014-04-10 16:35:00,108.72059121131906 2792,2014-04-10 16:40:00,96.92376529010951 2793,2014-04-10 16:45:00,104.54840519359999 2794,2014-04-10 16:50:00,101.61100689549048 2795,2014-04-10 16:55:00,97.80381001728095 2796,2014-04-10 17:00:00,95.37293272547143 2797,2014-04-10 17:05:00,107.14512014556192 2798,2014-04-10 17:10:00,102.34570879775238 2799,2014-04-10 17:15:00,106.02480154304287 2800,2014-04-10 17:20:00,101.55882207873333 2801,2014-04-10 17:25:00,96.36037810042382 2802,2014-04-10 17:30:00,98.2489655734143 2803,2014-04-10 17:35:00,98.96024624930476 2804,2014-04-10 17:40:00,108.43001861239524 2805,2014-04-10 17:45:00,92.9606404857857 2806,2014-04-10 17:50:00,108.6485988549762 2807,2014-04-10 17:55:00,108.57276915646665 2808,2014-04-10 18:00:00,56.06821544855714 2809,2014-04-10 18:05:00,52.75045584894761 2810,2014-04-10 18:10:00,55.876108786838095 2811,2014-04-10 18:15:00,52.247007319528564 2812,2014-04-10 18:20:00,49.89089790601905 2813,2014-04-10 18:25:00,51.165875711309525 2814,2014-04-10 18:30:00,55.7873892764 2815,2014-04-10 18:35:00,49.83302896699047 2816,2014-04-10 18:40:00,53.24673721858095 2817,2014-04-10 18:45:00,50.24366597497142 2818,2014-04-10 18:50:00,51.600194125161906 2819,2014-04-10 18:55:00,50.33849098765238 2820,2014-04-10 19:00:00,44.992829762542854 2821,2014-04-10 19:05:00,43.797578861333335 2822,2014-04-10 19:10:00,45.1984594483238 2823,2014-04-10 19:15:00,44.24828534461429 2824,2014-04-10 19:20:00,45.522113925304765 2825,2014-04-10 19:25:00,43.46359590019524 2826,2014-04-10 19:30:00,44.04820785768571 2827,2014-04-10 19:35:00,43.77608845597619 2828,2014-04-10 19:40:00,43.371152165666665 2829,2014-04-10 19:45:00,44.99900378615715 2830,2014-04-10 19:50:00,44.10401896254761 2831,2014-04-10 19:55:00,44.81386573893809 2832,2014-04-10 20:00:00,42.72437499592857 2833,2014-04-10 20:05:00,40.29338979511905 2834,2014-04-10 20:10:00,42.18137909990952 2835,2014-04-10 20:15:00,40.3435080556 2836,2014-04-10 20:20:00,41.92247090519048 2837,2014-04-10 20:25:00,42.31540316538096 2838,2014-04-10 20:30:00,43.63274601157143 2839,2014-04-10 20:35:00,39.680611624561905 2840,2014-04-10 20:40:00,39.93668100155238 2841,2014-04-10 20:45:00,39.88589398054286 2842,2014-04-10 20:50:00,41.20952092113333 2843,2014-04-10 20:55:00,42.950499476623804 2844,2014-04-10 21:00:00,42.63954544591428 2845,2014-04-10 21:05:00,42.21662310150476 2846,2014-04-10 21:10:00,42.86672821459524 2847,2014-04-10 21:15:00,40.56707435448571 2848,2014-04-10 21:20:00,39.63118729157619 2849,2014-04-10 21:25:00,39.51804527196666 2850,2014-04-10 21:30:00,42.71664891695714 2851,2014-04-10 21:35:00,42.23496712184762 2852,2014-04-10 21:40:00,42.1145126820381 2853,2014-04-10 21:45:00,40.67930566372857 2854,2014-04-10 21:50:00,40.84843393371905 2855,2014-04-10 21:55:00,43.17980936550953 2856,2014-04-10 22:00:00,39.5227439776 2857,2014-04-10 22:05:00,42.372618543490475 2858,2014-04-10 22:10:00,40.52188322968095 2859,2014-04-10 22:15:00,39.445969863071426 2860,2014-04-10 22:20:00,42.2701738066619 2861,2014-04-10 22:25:00,40.629400615852376 2862,2014-04-10 22:30:00,42.203285968342854 2863,2014-04-10 22:35:00,42.15269824843333 2864,2014-04-10 22:40:00,41.46800488292381 2865,2014-04-10 22:45:00,42.446721905014286 2866,2014-04-10 22:50:00,41.668069235804765 2867,2014-04-10 22:55:00,40.49677332559524 2868,2014-04-10 23:00:00,42.27976671708571 2869,2014-04-10 23:05:00,41.707193911376194 2870,2014-04-10 23:10:00,39.40854156616666 2871,2014-04-10 23:15:00,42.97233231455714 2872,2014-04-10 23:20:00,41.55549714464762 2873,2014-04-10 23:25:00,42.8551202607381 2874,2014-04-10 23:30:00,42.91900986712857 2875,2014-04-10 23:35:00,41.17503340701904 2876,2014-04-10 23:40:00,41.43329539050953 2877,2014-04-10 23:45:00,41.0730428481 2878,2014-04-10 23:50:00,41.21523874289048 2879,2014-04-10 23:55:00,43.00586305918095 2880,2014-04-11 00:00:00,42.58114748447143 2881,2014-04-11 00:05:00,39.94211461006191 2882,2014-04-11 00:10:00,41.884683507152374 2883,2014-04-11 00:15:00,43.43451941864286 2884,2014-04-11 00:20:00,41.84053613823333 2885,2014-04-11 00:25:00,42.609260311923805 2886,2014-04-11 00:30:00,42.54946017921428 2887,2014-04-11 00:35:00,40.881924865404756 2888,2014-04-11 00:40:00,40.97549244889524 2889,2014-04-11 00:45:00,42.39184140148571 2890,2014-04-11 00:50:00,41.50291031687619 2891,2014-04-11 00:55:00,41.792699503166666 2892,2014-04-11 01:00:00,42.36948030435714 2893,2014-04-11 01:05:00,42.635597727247614 2894,2014-04-11 01:10:00,40.618804406138096 2895,2014-04-11 01:15:00,40.12735360912857 2896,2014-04-11 01:20:00,40.714797634519044 2897,2014-04-11 01:25:00,41.58521282420952 2898,2014-04-11 01:30:00,40.931065269200005 2899,2014-04-11 01:35:00,41.843391511590475 2900,2014-04-11 01:40:00,39.79124384888095 2901,2014-04-11 01:45:00,41.62382307507143 2902,2014-04-11 01:50:00,41.06420153256191 2903,2014-04-11 01:55:00,41.73836940055238 2904,2014-04-11 02:00:00,41.29727627664286 2905,2014-04-11 02:05:00,40.751486735933334 2906,2014-04-11 02:10:00,43.2384554313238 2907,2014-04-11 02:15:00,40.368524239414285 2908,2014-04-11 02:20:00,42.36236706420476 2909,2014-04-11 02:25:00,43.342924088395236 2910,2014-04-11 02:30:00,41.80646555298571 2911,2014-04-11 02:35:00,43.164860144776185 2912,2014-04-11 02:40:00,40.16607258036666 2913,2014-04-11 02:45:00,41.64926222385714 2914,2014-04-11 02:50:00,41.50964874094762 2915,2014-04-11 02:55:00,39.7214633233381 2916,2014-04-11 03:00:00,41.46945793682857 2917,2014-04-11 03:05:00,41.17998807311905 2918,2014-04-11 03:10:00,42.390504434909516 2919,2014-04-11 03:15:00,43.4720691143 2920,2014-04-11 03:20:00,40.06935482919047 2921,2014-04-11 03:25:00,41.043536499280954 2922,2014-04-11 03:30:00,41.51733037817142 2923,2014-04-11 03:35:00,41.569253416861905 2924,2014-04-11 03:40:00,42.85519126435238 2925,2014-04-11 03:45:00,41.53697552044286 2926,2014-04-11 03:50:00,39.87947853913333 2927,2014-04-11 03:55:00,42.618690187923804 2928,2014-04-11 04:00:00,43.32503306631428 2929,2014-04-11 04:05:00,41.84877361210476 2930,2014-04-11 04:10:00,42.12502932489524 2931,2014-04-11 04:15:00,40.45978147018571 2932,2014-04-11 04:20:00,40.698059969176185 2933,2014-04-11 04:25:00,40.76359762316666 2934,2014-04-11 04:30:00,41.553325042357145 2935,2014-04-11 04:35:00,43.55037850264762 2936,2014-04-11 04:40:00,41.932377162138096 2937,2014-04-11 04:45:00,40.62106915222857 2938,2014-04-11 04:50:00,40.92446999111905 2939,2014-04-11 04:55:00,41.40361964270952 2940,2014-04-11 05:00:00,42.3680359028 2941,2014-04-11 05:05:00,41.642573088190474 2942,2014-04-11 05:10:00,41.459660329080954 2943,2014-04-11 05:15:00,42.156235830171426 2944,2014-04-11 05:20:00,40.8721018845619 2945,2014-04-11 05:25:00,40.227815471252384 2946,2014-04-11 05:30:00,40.017300116442854 2947,2014-04-11 05:35:00,40.932119987233335 2948,2014-04-11 05:40:00,40.30089194612381 2949,2014-04-11 05:45:00,41.287326839814284 2950,2014-04-11 05:50:00,43.04113892330476 2951,2014-04-11 05:55:00,42.82202255999523 2952,2014-04-11 06:00:00,42.40799620548571 2953,2014-04-11 06:05:00,43.38172716597619 2954,2014-04-11 06:10:00,41.10743716486667 2955,2014-04-11 06:15:00,43.526822154957145 2956,2014-04-11 06:20:00,41.59100429774762 2957,2014-04-11 06:25:00,41.6050613683381 2958,2014-04-11 06:30:00,41.630335025928574 2959,2014-04-11 06:35:00,40.40874651261905 2960,2014-04-11 06:40:00,43.925771517109524 2961,2014-04-11 06:45:00,40.5852771113 2962,2014-04-11 06:50:00,41.40223337409047 2963,2014-04-11 06:55:00,41.32333223368096 2964,2014-04-11 07:00:00,40.35228915987143 2965,2014-04-11 07:05:00,40.670052425161906 2966,2014-04-11 07:10:00,40.24788572565238 2967,2014-04-11 07:15:00,41.245510831342855 2968,2014-04-11 07:20:00,43.549961029433334 2969,2014-04-11 07:25:00,41.44854263242381 2970,2014-04-11 07:30:00,40.592981614014285 2971,2014-04-11 07:35:00,42.68843023540476 2972,2014-04-11 07:40:00,44.09949888629524 2973,2014-04-11 07:45:00,41.04983087238571 2974,2014-04-11 07:50:00,41.24626021197619 2975,2014-04-11 07:55:00,44.02280488376667 2976,2014-04-11 08:00:00,40.85796229305714 2977,2014-04-11 08:05:00,42.195153888847614 2978,2014-04-11 08:10:00,41.116346627338096 2979,2014-04-11 08:15:00,43.89458616302856 2980,2014-04-11 08:20:00,44.09870310591904 2981,2014-04-11 08:25:00,43.43885090830952 2982,2014-04-11 08:30:00,41.446635263299996 2983,2014-04-11 08:35:00,41.808890377290474 2984,2014-04-11 08:40:00,41.17160368708095 2985,2014-04-11 08:45:00,43.77285329657143 2986,2014-04-11 08:50:00,43.8754950155619 2987,2014-04-11 08:55:00,41.90018502995238 2988,2014-04-11 09:00:00,150.11416299114285 2989,2014-04-11 09:05:00,137.94530219133333 2990,2014-04-11 09:10:00,144.6334341385238 2991,2014-04-11 09:15:00,149.5156421317143 2992,2014-04-11 09:20:00,143.41990210090475 2993,2014-04-11 09:25:00,142.73781347509524 2994,2014-04-11 09:30:00,133.9015607222857 2995,2014-04-11 09:35:00,153.8307040924762 2996,2014-04-11 09:40:00,155.94723944466665 2997,2014-04-11 09:45:00,157.94180267585713 2998,2014-04-11 09:50:00,151.7444779690476 2999,2014-04-11 09:55:00,147.5240374422381 3000,2014-04-11 10:00:00,160.43990826542858 3001,2014-04-11 10:05:00,181.58858187161903 3002,2014-04-11 10:10:00,169.73555219080953 3003,2014-04-11 10:15:00,172.389971935 3004,2014-04-11 10:20:00,172.43367292619047 3005,2014-04-11 10:25:00,177.15712295738098 3006,2014-04-11 10:30:00,152.9661881535714 3007,2014-04-11 10:35:00,159.0718632997619 3008,2014-04-11 10:40:00,171.97481702595238 3009,2014-04-11 10:45:00,178.63181339514284 3010,2014-04-11 10:50:00,172.56324445733333 3011,2014-04-11 10:55:00,164.6979816115238 3012,2014-04-11 11:00:00,167.24617561871426 3013,2014-04-11 11:05:00,178.46710182490474 3014,2014-04-11 11:10:00,178.57254871109524 3015,2014-04-11 11:15:00,174.58250742728572 3016,2014-04-11 11:20:00,165.1878617724762 3017,2014-04-11 11:25:00,184.07412901666666 3018,2014-04-11 11:30:00,172.96096437885714 3019,2014-04-11 11:35:00,180.07714589604763 3020,2014-04-11 11:40:00,162.9189098412381 3021,2014-04-11 11:45:00,166.79134174542855 3022,2014-04-11 11:50:00,182.60459199961903 3023,2014-04-11 11:55:00,158.0493481598095 3024,2014-04-11 12:00:00,172.660947021 3025,2014-04-11 12:05:00,171.7513659231905 3026,2014-04-11 12:10:00,179.83333544338097 3027,2014-04-11 12:15:00,165.78020776557142 3028,2014-04-11 12:20:00,163.9054533807619 3029,2014-04-11 12:25:00,185.09546041795238 3030,2014-04-11 12:30:00,174.48494929414287 3031,2014-04-11 12:35:00,160.50121529533334 3032,2014-04-11 12:40:00,163.1553783715238 3033,2014-04-11 12:45:00,187.30299490671428 3034,2014-04-11 12:50:00,163.24733731490474 3035,2014-04-11 12:55:00,175.68351479709523 3036,2014-04-11 13:00:00,170.1521926182857 3037,2014-04-11 13:05:00,184.1198908514762 3038,2014-04-11 13:10:00,180.21550143266666 3039,2014-04-11 13:15:00,175.47774239485716 3040,2014-04-11 13:20:00,157.90368772504763 3041,2014-04-11 13:25:00,183.9755844242381 3042,2014-04-11 13:30:00,170.93281306342857 3043,2014-04-11 13:35:00,185.54350791161903 3044,2014-04-11 13:40:00,172.47341702480952 3045,2014-04-11 13:45:00,178.439768728 3046,2014-04-11 13:50:00,159.70445344519047 3047,2014-04-11 13:55:00,179.98204089638097 3048,2014-04-11 14:00:00,167.81040194257142 3049,2014-04-11 14:05:00,168.2187096737619 3050,2014-04-11 14:10:00,161.24544227895237 3051,2014-04-11 14:15:00,162.09887494614287 3052,2014-04-11 14:20:00,163.27330791633332 3053,2014-04-11 14:25:00,167.5539247315238 3054,2014-04-11 14:30:00,184.47333943071428 3055,2014-04-11 14:35:00,168.77036112390476 3056,2014-04-11 14:40:00,179.46028309509524 3057,2014-04-11 14:45:00,160.2203351392857 3058,2014-04-11 14:50:00,175.47746858047617 3059,2014-04-11 14:55:00,172.20886373766666 3060,2014-04-11 15:00:00,187.10477248685714 3061,2014-04-11 15:05:00,183.1597514970476 3062,2014-04-11 15:10:00,171.4259823012381 3063,2014-04-11 15:15:00,181.04270592542855 3064,2014-04-11 15:20:00,163.58721944361903 3065,2014-04-11 15:25:00,174.67346459980953 3066,2014-04-11 15:30:00,160.04954923399998 3067,2014-04-11 15:35:00,168.26099800019048 3068,2014-04-11 15:40:00,164.60167363438097 3069,2014-04-11 15:45:00,179.40037903557143 3070,2014-04-11 15:50:00,172.5433219387619 3071,2014-04-11 15:55:00,180.38006918995237 3072,2014-04-11 16:00:00,173.31567216814287 3073,2014-04-11 16:05:00,160.45881132133334 3074,2014-04-11 16:10:00,179.9327048355238 3075,2014-04-11 16:15:00,182.87598722571428 3076,2014-04-11 16:20:00,184.99248187990474 3077,2014-04-11 16:25:00,175.05376600509524 3078,2014-04-11 16:30:00,180.50899680528573 3079,2014-04-11 16:35:00,180.4702067204762 3080,2014-04-11 16:40:00,162.58884957366666 3081,2014-04-11 16:45:00,162.85041731585713 3082,2014-04-11 16:50:00,160.05780855504761 3083,2014-04-11 16:55:00,167.5360763362381 3084,2014-04-11 17:00:00,172.15161999642856 3085,2014-04-11 17:05:00,187.89073144261903 3086,2014-04-11 17:10:00,170.8910441448095 3087,2014-04-11 17:15:00,179.755958083 3088,2014-04-11 17:20:00,178.77803213019047 3089,2014-04-11 17:25:00,164.11802683438097 3090,2014-04-11 17:30:00,159.7462252895714 3091,2014-04-11 17:35:00,174.3786472787619 3092,2014-04-11 17:40:00,179.01505092395237 3093,2014-04-11 17:45:00,187.96087337014285 3094,2014-04-11 17:50:00,168.77910022433335 3095,2014-04-11 17:55:00,184.9191388355238 3096,2014-04-11 18:00:00,67.94947988201429 3097,2014-04-11 18:05:00,70.78572866320476 3098,2014-04-11 18:10:00,69.95450862529523 3099,2014-04-11 18:15:00,64.94542849078572 3100,2014-04-11 18:20:00,65.1866375290762 3101,2014-04-11 18:25:00,64.66393425606667 3102,2014-04-11 18:30:00,67.89201775305715 3103,2014-04-11 18:35:00,71.34915330124763 3104,2014-04-11 18:40:00,66.0845752792381 3105,2014-04-11 18:45:00,70.07651228672856 3106,2014-04-11 18:50:00,67.16732187411904 3107,2014-04-11 18:55:00,71.84987756170952 3108,2014-04-11 19:00:00,49.828913769699994 3109,2014-04-11 19:05:00,49.72052682259047 3110,2014-04-11 19:10:00,48.46503918628095 3111,2014-04-11 19:15:00,47.26153509967143 3112,2014-04-11 19:20:00,49.91435705876191 3113,2014-04-11 19:25:00,46.780146717852375 3114,2014-04-11 19:30:00,47.31002870094285 3115,2014-04-11 19:35:00,46.78417727823333 3116,2014-04-11 19:40:00,49.2625402627238 3117,2014-04-11 19:45:00,49.330591105814285 3118,2014-04-11 19:50:00,49.16805238190476 3119,2014-04-11 19:55:00,47.98147401359524 3120,2014-04-11 20:00:00,42.571804822685706 3121,2014-04-11 20:05:00,45.99192722587619 3122,2014-04-11 20:10:00,44.30169802996666 3123,2014-04-11 20:15:00,43.88514561645714 3124,2014-04-11 20:20:00,44.65782222784762 3125,2014-04-11 20:25:00,42.99874974943809 3126,2014-04-11 20:30:00,42.752693340528566 3127,2014-04-11 20:35:00,43.90881865711905 3128,2014-04-11 20:40:00,43.16595370110952 3129,2014-04-11 20:45:00,43.2452230542 3130,2014-04-11 20:50:00,45.980378242490474 3131,2014-04-11 20:55:00,44.465565034180955 3132,2014-04-11 21:00:00,43.44475989277143 3133,2014-04-11 21:05:00,44.28481252026191 3134,2014-04-11 21:10:00,45.351429121052384 3135,2014-04-11 21:15:00,41.966554477042855 3136,2014-04-11 21:20:00,44.88934652613334 3137,2014-04-11 21:25:00,43.88834561862381 3138,2014-04-11 21:30:00,42.12615608071428 3139,2014-04-11 21:35:00,42.74381334610476 3140,2014-04-11 21:40:00,43.49980703279524 3141,2014-04-11 21:45:00,44.35119715128572 3142,2014-04-11 21:50:00,42.54569660917619 3143,2014-04-11 21:55:00,43.73438278006667 3144,2014-04-11 22:00:00,44.17468009835714 3145,2014-04-11 22:05:00,43.23643412444761 3146,2014-04-11 22:10:00,44.9044622928381 3147,2014-04-11 22:15:00,44.93768885962857 3148,2014-04-11 22:20:00,43.34674004791905 3149,2014-04-11 22:25:00,45.36729708400952 3150,2014-04-11 22:30:00,41.7779092181 3151,2014-04-11 22:35:00,41.495857945290474 3152,2014-04-11 22:40:00,43.01566114678096 3153,2014-04-11 22:45:00,43.90665077987143 3154,2014-04-11 22:50:00,44.0267374580619 3155,2014-04-11 22:55:00,43.421889333452384 3156,2014-04-11 23:00:00,41.989371912042856 3157,2014-04-11 23:05:00,42.17934512433333 3158,2014-04-11 23:10:00,44.9145217146238 3159,2014-04-11 23:15:00,44.98504101221428 3160,2014-04-11 23:20:00,44.21610827610476 3161,2014-04-11 23:25:00,44.18481038149524 3162,2014-04-11 23:30:00,43.92599676508571 3163,2014-04-11 23:35:00,42.35375539797619 3164,2014-04-11 23:40:00,43.262870072666665 3165,2014-04-11 23:45:00,44.34133171295714 3166,2014-04-11 23:50:00,43.71393869054762 3167,2014-04-11 23:55:00,41.645828345238094 3168,2014-04-12 00:00:00,45.38565579832857 3169,2014-04-12 00:05:00,44.958133257919044 3170,2014-04-12 00:10:00,42.62848958020952 3171,2014-04-12 00:15:00,44.0595857407 3172,2014-04-12 00:20:00,45.29414801109047 3173,2014-04-12 00:25:00,41.99267500088095 3174,2014-04-12 00:30:00,43.628189351771425 3175,2014-04-12 00:35:00,43.448484008161905 3176,2014-04-12 00:40:00,43.27177240205238 3177,2014-04-12 00:45:00,44.980747292742855 3178,2014-04-12 00:50:00,43.16841792013334 3179,2014-04-12 00:55:00,41.9079271425238 3180,2014-04-12 01:00:00,41.92406525441429 3181,2014-04-12 01:05:00,41.83913318800476 3182,2014-04-12 01:10:00,43.31217692559524 3183,2014-04-12 01:15:00,44.556660825085714 3184,2014-04-12 01:20:00,42.50536603817619 3185,2014-04-12 01:25:00,44.28379074836667 3186,2014-04-12 01:30:00,44.45371103125714 3187,2014-04-12 01:35:00,42.733606115147616 3188,2014-04-12 01:40:00,44.122468719438096 3189,2014-04-12 01:45:00,44.46715193152857 3190,2014-04-12 01:50:00,43.601573538819046 3191,2014-04-12 01:55:00,43.08942591290952 3192,2014-04-12 02:00:00,44.226606206300005 3193,2014-04-12 02:05:00,45.66882882549047 3194,2014-04-12 02:10:00,43.47224658988095 3195,2014-04-12 02:15:00,43.33926181367143 3196,2014-04-12 02:20:00,43.63682951446191 3197,2014-04-12 02:25:00,42.09207595475238 3198,2014-04-12 02:30:00,44.00729597584285 3199,2014-04-12 02:35:00,43.11687288223334 3200,2014-04-12 02:40:00,42.295212298823806 3201,2014-04-12 02:45:00,43.68199125021428 3202,2014-04-12 02:50:00,41.83794070820476 3203,2014-04-12 02:55:00,43.438986218795236 3204,2014-04-12 03:00:00,42.26222678598572 3205,2014-04-12 03:05:00,41.94389700407619 3206,2014-04-12 03:10:00,45.15206685166666 3207,2014-04-12 03:15:00,45.52660235595714 3208,2014-04-12 03:20:00,42.699746212447614 3209,2014-04-12 03:25:00,44.033681150538094 3210,2014-04-12 03:30:00,42.995761199928566 3211,2014-04-12 03:35:00,43.86567880231905 3212,2014-04-12 03:40:00,43.645334807409526 3213,2014-04-12 03:45:00,42.9824542203 3214,2014-04-12 03:50:00,44.71526479469047 3215,2014-04-12 03:55:00,42.42709478968095 3216,2014-04-12 04:00:00,42.140862557271426 3217,2014-04-12 04:05:00,45.0067136368619 3218,2014-04-12 04:10:00,44.607172505852375 3219,2014-04-12 04:15:00,43.944997353742856 3220,2014-04-12 04:20:00,43.82949241523333 3221,2014-04-12 04:25:00,43.955419327523806 3222,2014-04-12 04:30:00,43.721310590114285 3223,2014-04-12 04:35:00,43.55222394520476 3224,2014-04-12 04:40:00,43.98685764959524 3225,2014-04-12 04:45:00,44.109596398885714 3226,2014-04-12 04:50:00,44.770585446776195 3227,2014-04-12 04:55:00,44.85524530956667 3228,2014-04-12 05:00:00,43.52837346345714 3229,2014-04-12 05:05:00,43.67945971004762 3230,2014-04-12 05:10:00,43.527526774138096 3231,2014-04-12 05:15:00,44.186321665928574 3232,2014-04-12 05:20:00,43.86103319931905 3233,2014-04-12 05:25:00,45.61344537630952 3234,2014-04-12 05:30:00,44.847945067699996 3235,2014-04-12 05:35:00,45.66456601119047 3236,2014-04-12 05:40:00,44.91392891858095 3237,2014-04-12 05:45:00,45.96879002267143 3238,2014-04-12 05:50:00,44.63520901776191 3239,2014-04-12 05:55:00,45.95390293365238 3240,2014-04-12 06:00:00,42.739822418742854 3241,2014-04-12 06:05:00,42.32449405663333 3242,2014-04-12 06:10:00,44.438524550323805 3243,2014-04-12 06:15:00,46.063437108914286 3244,2014-04-12 06:20:00,43.807325751104756 3245,2014-04-12 06:25:00,42.99251868689524 3246,2014-04-12 06:30:00,44.23795151108571 3247,2014-04-12 06:35:00,44.75442068877619 3248,2014-04-12 06:40:00,43.42738144876667 3249,2014-04-12 06:45:00,45.03318457685714 3250,2014-04-12 06:50:00,46.08200564724762 3251,2014-04-12 06:55:00,45.77684058203809 3252,2014-04-12 07:00:00,43.36277006542857 3253,2014-04-12 07:05:00,43.51076378021905 3254,2014-04-12 07:10:00,43.69747442160952 3255,2014-04-12 07:15:00,43.7969611136 3256,2014-04-12 07:20:00,42.62746847299047 3257,2014-04-12 07:25:00,45.28148230798095 3258,2014-04-12 07:30:00,43.70242848297143 3259,2014-04-12 07:35:00,45.76779181156191 3260,2014-04-12 07:40:00,45.963714873452375 3261,2014-04-12 07:45:00,42.36111809434286 3262,2014-04-12 07:50:00,46.22484561303333 3263,2014-04-12 07:55:00,45.118364735523805 3264,2014-04-12 08:00:00,44.367283189714286 3265,2014-04-12 08:05:00,43.85126519540476 3266,2014-04-12 08:10:00,44.374667768495236 3267,2014-04-12 08:15:00,43.60653461018571 3268,2014-04-12 08:20:00,44.80622744527619 3269,2014-04-12 08:25:00,42.69483777246666 3270,2014-04-12 08:30:00,44.814847554457145 3271,2014-04-12 08:35:00,43.439177019647616 3272,2014-04-12 08:40:00,42.41577741143809 3273,2014-04-12 08:45:00,44.56350163612857 3274,2014-04-12 08:50:00,44.67391007101905 3275,2014-04-12 08:55:00,44.07383554260952 3276,2014-04-12 09:00:00,86.5580927627 3277,2014-04-12 09:05:00,97.73190463429049 3278,2014-04-12 09:10:00,93.90533993068095 3279,2014-04-12 09:15:00,87.17102230267143 3280,2014-04-12 09:20:00,92.55341774646192 3281,2014-04-12 09:25:00,92.37486107785237 3282,2014-04-12 09:30:00,86.44110827274287 3283,2014-04-12 09:35:00,93.88037530233332 3284,2014-04-12 09:40:00,96.62776283482381 3285,2014-04-12 09:45:00,95.82847382351429 3286,2014-04-12 09:50:00,88.40978879450476 3287,2014-04-12 09:55:00,97.38402363999523 3288,2014-04-12 10:00:00,99.62054012528571 3289,2014-04-12 10:05:00,109.00153622157619 3290,2014-04-12 10:10:00,95.43269507146667 3291,2014-04-12 10:15:00,101.87256598865714 3292,2014-04-12 10:20:00,103.60141795284763 3293,2014-04-12 10:25:00,98.1850176235381 3294,2014-04-12 10:30:00,106.32074910032857 3295,2014-04-12 10:35:00,104.08578999831904 3296,2014-04-12 10:40:00,94.64486799050952 3297,2014-04-12 10:45:00,103.81313052760001 3298,2014-04-12 10:50:00,102.00643267439048 3299,2014-04-12 10:55:00,97.42850416278095 3300,2014-04-12 11:00:00,111.95795123177143 3301,2014-04-12 11:05:00,110.39747945126189 3302,2014-04-12 11:10:00,100.78849476265238 3303,2014-04-12 11:15:00,104.74908478154285 3304,2014-04-12 11:20:00,101.18498336643333 3305,2014-04-12 11:25:00,108.4922582435238 3306,2014-04-12 11:30:00,110.96220539931429 3307,2014-04-12 11:35:00,101.88046492630475 3308,2014-04-12 11:40:00,108.99310713649524 3309,2014-04-12 11:45:00,104.1152092735857 3310,2014-04-12 11:50:00,102.50316162957618 3311,2014-04-12 11:55:00,111.12807780246666 3312,2014-04-12 12:00:00,104.71313239235714 3313,2014-04-12 12:05:00,104.03349134154762 3314,2014-04-12 12:10:00,107.31737778613811 3315,2014-04-12 12:15:00,100.75351009102857 3316,2014-04-12 12:20:00,101.77666895711904 3317,2014-04-12 12:25:00,111.48849762360952 3318,2014-04-12 12:30:00,107.444549754 3319,2014-04-12 12:35:00,109.81886340729048 3320,2014-04-12 12:40:00,100.94856379748096 3321,2014-04-12 12:45:00,105.31362369577144 3322,2014-04-12 12:50:00,112.15455136826193 3323,2014-04-12 12:55:00,101.73144565055237 3324,2014-04-12 13:00:00,99.28187024854284 3325,2014-04-12 13:05:00,104.89451766263333 3326,2014-04-12 13:10:00,102.9333919961238 3327,2014-04-12 13:15:00,99.2898072337143 3328,2014-04-12 13:20:00,110.95803484780475 3329,2014-04-12 13:25:00,112.59984342709524 3330,2014-04-12 13:30:00,105.85463724978571 3331,2014-04-12 13:35:00,109.15879972567619 3332,2014-04-12 13:40:00,110.51570187206667 3333,2014-04-12 13:45:00,107.99484746825713 3334,2014-04-12 13:50:00,97.49559484564762 3335,2014-04-12 13:55:00,99.31825048723809 3336,2014-04-12 14:00:00,97.95374511012857 3337,2014-04-12 14:05:00,96.98347916631903 3338,2014-04-12 14:10:00,101.72856105870952 3339,2014-04-12 14:15:00,103.1176880383 3340,2014-04-12 14:20:00,100.70402508269046 3341,2014-04-12 14:25:00,97.88879970538095 3342,2014-04-12 14:30:00,105.34001794707143 3343,2014-04-12 14:35:00,101.2429551148619 3344,2014-04-12 14:40:00,109.61347950225237 3345,2014-04-12 14:45:00,97.01377261874285 3346,2014-04-12 14:50:00,110.37216309313332 3347,2014-04-12 14:55:00,112.1751434218238 3348,2014-04-12 15:00:00,108.36807409781429 3349,2014-04-12 15:05:00,108.65565591840476 3350,2014-04-12 15:10:00,111.86175762859523 3351,2014-04-12 15:15:00,100.2774529657857 3352,2014-04-12 15:20:00,112.8526813165762 3353,2014-04-12 15:25:00,109.32280591396665 3354,2014-04-12 15:30:00,108.57968567485713 3355,2014-04-12 15:35:00,102.73950021944762 3356,2014-04-12 15:40:00,105.7019028303381 3357,2014-04-12 15:45:00,107.43957154202857 3358,2014-04-12 15:50:00,106.90981834401906 3359,2014-04-12 15:55:00,108.27151425380951 3360,2014-04-12 16:00:00,98.3179670545 3361,2014-04-12 16:05:00,102.69766623599048 3362,2014-04-12 16:10:00,103.95872964538096 3363,2014-04-12 16:15:00,101.19224394807142 3364,2014-04-12 16:20:00,99.7916546859619 3365,2014-04-12 16:25:00,99.25989955175238 3366,2014-04-12 16:30:00,102.90662763794285 3367,2014-04-12 16:35:00,104.94699714383333 3368,2014-04-12 16:40:00,98.06700667722382 3369,2014-04-12 16:45:00,112.2101264840143 3370,2014-04-12 16:50:00,109.31813617940476 3371,2014-04-12 16:55:00,108.77531291729524 3372,2014-04-12 17:00:00,99.85502540408571 3373,2014-04-12 17:05:00,106.75750712087618 3374,2014-04-12 17:10:00,105.57973491296667 3375,2014-04-12 17:15:00,112.83107499115714 3376,2014-04-12 17:20:00,109.08176369864762 3377,2014-04-12 17:25:00,106.33864704923809 3378,2014-04-12 17:30:00,110.74689835952857 3379,2014-04-12 17:35:00,99.62284878051905 3380,2014-04-12 17:40:00,97.39224625740951 3381,2014-04-12 17:45:00,108.1999514458 3382,2014-04-12 17:50:00,98.73664558799047 3383,2014-04-12 17:55:00,99.01804083488095 3384,2014-04-12 18:00:00,58.74452163307143 3385,2014-04-12 18:05:00,55.71742904516191 3386,2014-04-12 18:10:00,58.01668585855238 3387,2014-04-12 18:15:00,59.87229052724285 3388,2014-04-12 18:20:00,56.03376441733333 3389,2014-04-12 18:25:00,55.405490623223805 3390,2014-04-12 18:30:00,54.705211081114285 3391,2014-04-12 18:35:00,54.86560818510476 3392,2014-04-12 18:40:00,54.43631488249524 3393,2014-04-12 18:45:00,54.60644130148571 3394,2014-04-12 18:50:00,56.81779949837619 3395,2014-04-12 18:55:00,56.11394703096666 3396,2014-04-12 19:00:00,48.59324831145715 3397,2014-04-12 19:05:00,49.33397892824762 3398,2014-04-12 19:10:00,48.9585207465381 3399,2014-04-12 19:15:00,47.82743224492857 3400,2014-04-12 19:20:00,45.91655859721905 3401,2014-04-12 19:25:00,48.64481567550952 3402,2014-04-12 19:30:00,47.0979714917 3403,2014-04-12 19:35:00,45.86365311399047 3404,2014-04-12 19:40:00,49.26162914368095 3405,2014-04-12 19:45:00,47.01003023647142 3406,2014-04-12 19:50:00,46.480015514861904 3407,2014-04-12 19:55:00,49.413806310352385 3408,2014-04-12 20:00:00,47.484282916742856 3409,2014-04-12 20:05:00,45.18500764463333 3410,2014-04-12 20:10:00,45.25729018432381 3411,2014-04-12 20:15:00,46.185622485014285 3412,2014-04-12 20:20:00,46.82308086330476 3413,2014-04-12 20:25:00,44.085004144795235 3414,2014-04-12 20:30:00,46.26412108378571 3415,2014-04-12 20:35:00,47.743976895476194 3416,2014-04-12 20:40:00,44.922203035466666 3417,2014-04-12 20:45:00,47.57866314595714 3418,2014-04-12 20:50:00,47.75543687494762 3419,2014-04-12 20:55:00,44.9734411742381 3420,2014-04-12 21:00:00,46.56411665912857 3421,2014-04-12 21:05:00,44.49995351451905 3422,2014-04-12 21:10:00,46.512316253509525 3423,2014-04-12 21:15:00,46.7601402965 3424,2014-04-12 21:20:00,44.55615959389047 3425,2014-04-12 21:25:00,46.44725377068095 3426,2014-04-12 21:30:00,46.84148193897143 3427,2014-04-12 21:35:00,45.0261120597619 3428,2014-04-12 21:40:00,44.266383332352376 3429,2014-04-12 21:45:00,43.96941680094285 3430,2014-04-12 21:50:00,45.91980742663333 3431,2014-04-12 21:55:00,47.545845716823806 3432,2014-04-12 22:00:00,46.847955684614284 3433,2014-04-12 22:05:00,45.305466932104764 3434,2014-04-12 22:10:00,45.716419463895235 3435,2014-04-12 22:15:00,44.69450063358571 3436,2014-04-12 22:20:00,44.235645823676194 3437,2014-04-12 22:25:00,45.520372481466666 3438,2014-04-12 22:30:00,45.45342324375714 3439,2014-04-12 22:35:00,45.69480163144762 3440,2014-04-12 22:40:00,47.4273951963381 3441,2014-04-12 22:45:00,46.037858719928565 3442,2014-04-12 22:50:00,46.052812547919046 3443,2014-04-12 22:55:00,44.14743018120952 3444,2014-04-12 23:00:00,47.615176766 3445,2014-04-12 23:05:00,46.72786979599047 3446,2014-04-12 23:10:00,47.15282401878095 3447,2014-04-12 23:15:00,45.30829725667142 3448,2014-04-12 23:20:00,45.66711592036191 3449,2014-04-12 23:25:00,45.754394575952375 3450,2014-04-12 23:30:00,44.44962607704285 3451,2014-04-12 23:35:00,46.439025484233326 3452,2014-04-12 23:40:00,47.3005801880238 3453,2014-04-12 23:45:00,44.350369282514286 3454,2014-04-12 23:50:00,44.048200146504755 3455,2014-04-12 23:55:00,46.66374381029524 3456,2014-04-13 00:00:00,44.80709304098571 3457,2014-04-13 00:05:00,46.21717635697619 3458,2014-04-13 00:10:00,46.51220001866666 3459,2014-04-13 00:15:00,45.024250197157144 3460,2014-04-13 00:20:00,125.74404761904762 3461,2014-04-13 00:25:00,45.95144402373809 3462,2014-04-13 00:30:00,47.23492620322857 3463,2014-04-13 00:35:00,46.81954325781905 3464,2014-04-13 00:40:00,47.24811205190952 3465,2014-04-13 00:45:00,43.8618955285 3466,2014-04-13 00:50:00,44.76271551919048 3467,2014-04-13 00:55:00,44.15616271418095 3468,2014-04-13 01:00:00,45.57190349737142 3469,2014-04-13 01:05:00,47.370852391261906 3470,2014-04-13 01:10:00,45.688613430052385 3471,2014-04-13 01:15:00,47.22474503544285 3472,2014-04-13 01:20:00,45.14204628543333 3473,2014-04-13 01:25:00,45.19905410072381 3474,2014-04-13 01:30:00,47.43046120701429 3475,2014-04-13 01:35:00,45.55892334790476 3476,2014-04-13 01:40:00,47.022157189295235 3477,2014-04-13 01:45:00,44.81710990578571 3478,2014-04-13 01:50:00,47.673179509176194 3479,2014-04-13 01:55:00,46.18372965276666 3480,2014-04-13 02:00:00,46.93015141715715 3481,2014-04-13 02:05:00,44.25836041824762 3482,2014-04-13 02:10:00,45.8783949985381 3483,2014-04-13 02:15:00,47.51933256232857 3484,2014-04-13 02:20:00,47.430773563819045 3485,2014-04-13 02:25:00,44.117315352709525 3486,2014-04-13 02:30:00,45.152293876499996 3487,2014-04-13 02:35:00,45.718220502090475 3488,2014-04-13 02:40:00,44.64144020978095 3489,2014-04-13 02:45:00,46.87981467257143 3490,2014-04-13 02:50:00,44.7053098871619 3491,2014-04-13 02:55:00,45.36126115845238 3492,2014-04-13 03:00:00,46.63526540454285 3493,2014-04-13 03:05:00,45.91794071143333 3494,2014-04-13 03:10:00,46.95130796402381 3495,2014-04-13 03:15:00,47.849295890614286 3496,2014-04-13 03:20:00,44.47809151280476 3497,2014-04-13 03:25:00,46.857616103695236 3498,2014-04-13 03:30:00,44.948162336785714 3499,2014-04-13 03:35:00,45.69213310007619 3500,2014-04-13 03:40:00,44.17311756986666 3501,2014-04-13 03:45:00,44.59273667205714 3502,2014-04-13 03:50:00,45.335656775247614 3503,2014-04-13 03:55:00,45.431931316438096 3504,2014-04-13 04:00:00,47.66976943722857 3505,2014-04-13 04:05:00,47.04612068471904 3506,2014-04-13 04:10:00,47.975041396509525 3507,2014-04-13 04:15:00,46.4900360413 3508,2014-04-13 04:20:00,45.06804540459048 3509,2014-04-13 04:25:00,45.419251072080954 3510,2014-04-13 04:30:00,45.39541512177142 3511,2014-04-13 04:35:00,45.4294892154619 3512,2014-04-13 04:40:00,46.82280907335238 3513,2014-04-13 04:45:00,46.26162456954285 3514,2014-04-13 04:50:00,45.68753004563333 3515,2014-04-13 04:55:00,44.749632884423804 3516,2014-04-13 05:00:00,44.24927093751428 3517,2014-04-13 05:05:00,45.04349347230476 3518,2014-04-13 05:10:00,44.60548085399523 3519,2014-04-13 05:15:00,47.32481583768571 3520,2014-04-13 05:20:00,44.640468021776186 3521,2014-04-13 05:25:00,47.094829615866665 3522,2014-04-13 05:30:00,45.74799190195714 3523,2014-04-13 05:35:00,44.50631117804762 3524,2014-04-13 05:40:00,47.4711582929381 3525,2014-04-13 05:45:00,46.54620085232857 3526,2014-04-13 05:50:00,45.17816509911905 3527,2014-04-13 05:55:00,47.82128422110952 3528,2014-04-13 06:00:00,44.4310332555 3529,2014-04-13 06:05:00,45.06471890899047 3530,2014-04-13 06:10:00,47.27306866358095 3531,2014-04-13 06:15:00,47.109833149771426 3532,2014-04-13 06:20:00,45.43684867966191 3533,2014-04-13 06:25:00,44.535301882352385 3534,2014-04-13 06:30:00,47.726955146042854 3535,2014-04-13 06:35:00,45.55687388563334 3536,2014-04-13 06:40:00,45.092377469223806 3537,2014-04-13 06:45:00,46.381211575114285 3538,2014-04-13 06:50:00,47.965313559004755 3539,2014-04-13 06:55:00,44.50603154949523 3540,2014-04-13 07:00:00,47.40250206638571 3541,2014-04-13 07:05:00,46.636619102276185 3542,2014-04-13 07:10:00,46.055963132866665 3543,2014-04-13 07:15:00,47.337928919257145 3544,2014-04-13 07:20:00,48.23234531684762 3545,2014-04-13 07:25:00,45.29331293993809 3546,2014-04-13 07:30:00,44.95851803172857 3547,2014-04-13 07:35:00,48.04289602851905 3548,2014-04-13 07:40:00,47.07462183360953 3549,2014-04-13 07:45:00,46.1581940862 3550,2014-04-13 07:50:00,46.70672875729048 3551,2014-04-13 07:55:00,47.40358657308095 3552,2014-04-13 08:00:00,47.52069902337143 3553,2014-04-13 08:05:00,48.1155886280619 3554,2014-04-13 08:10:00,46.15082353655238 3555,2014-04-13 08:15:00,45.62453649724286 3556,2014-04-13 08:20:00,47.01699040053333 3557,2014-04-13 08:25:00,46.1286854066238 3558,2014-04-13 08:30:00,46.85160810151429 3559,2014-04-13 08:35:00,46.16059795570476 3560,2014-04-13 08:40:00,45.10007838479524 3561,2014-04-13 08:45:00,46.37324272088571 3562,2014-04-13 08:50:00,47.26664747827619 3563,2014-04-13 08:55:00,47.70755189736666 3564,2014-04-13 09:00:00,94.42709450725714 3565,2014-04-13 09:05:00,89.97253292594762 3566,2014-04-13 09:10:00,93.37249094643809 3567,2014-04-13 09:15:00,98.43377600362857 3568,2014-04-13 09:20:00,93.36250512801905 3569,2014-04-13 09:25:00,97.22787831680952 3570,2014-04-13 09:30:00,94.6606060708 3571,2014-04-13 09:35:00,91.05057497769047 3572,2014-04-13 09:40:00,98.60502786148095 3573,2014-04-13 09:45:00,88.93012440397143 3574,2014-04-13 09:50:00,94.9307697502619 3575,2014-04-13 09:55:00,90.64062044665238 3576,2014-04-13 10:00:00,97.48800141214286 3577,2014-04-13 10:05:00,104.26011803683333 3578,2014-04-13 10:10:00,104.21522846962381 3579,2014-04-13 10:15:00,107.44056627971429 3580,2014-04-13 10:20:00,108.03543551810476 3581,2014-04-13 10:25:00,107.77966914259524 3582,2014-04-13 10:30:00,102.84813724918571 3583,2014-04-13 10:35:00,106.30305168827618 3584,2014-04-13 10:40:00,105.46085683246667 3585,2014-04-13 10:45:00,103.05674559775714 3586,2014-04-13 10:50:00,105.79028863284762 3587,2014-04-13 10:55:00,111.2302751417381 3588,2014-04-13 11:00:00,101.33221067092856 3589,2014-04-13 11:05:00,112.67726845901905 3590,2014-04-13 11:10:00,99.12946601820951 3591,2014-04-13 11:15:00,103.191372042 3592,2014-04-13 11:20:00,102.87685251009049 3593,2014-04-13 11:25:00,108.26334162808095 3594,2014-04-13 11:30:00,100.39607306167143 3595,2014-04-13 11:35:00,112.3493683234619 3596,2014-04-13 11:40:00,111.50123398115238 3597,2014-04-13 11:45:00,108.70184765344288 3598,2014-04-13 11:50:00,105.62944691413333 3599,2014-04-13 11:55:00,113.18400670372381 3600,2014-04-13 12:00:00,111.9753088274143 3601,2014-04-13 12:05:00,106.68621028040477 3602,2014-04-13 12:10:00,109.93069294099524 3603,2014-04-13 12:15:00,107.7816298940857 3604,2014-04-13 12:20:00,108.12486351367619 3605,2014-04-13 12:25:00,104.02577903716667 3606,2014-04-13 12:30:00,106.12843879245716 3607,2014-04-13 12:35:00,99.99984058024762 3608,2014-04-13 12:40:00,104.4695560670381 3609,2014-04-13 12:45:00,109.88617490972857 3610,2014-04-13 12:50:00,114.00687378791906 3611,2014-04-13 12:55:00,114.17169449700951 3612,2014-04-13 13:00:00,107.7471519302 3613,2014-04-13 13:05:00,108.56878707569047 3614,2014-04-13 13:10:00,101.84342675108095 3615,2014-04-13 13:15:00,110.00230117497144 3616,2014-04-13 13:20:00,100.0177512577619 3617,2014-04-13 13:25:00,103.44880016075237 3618,2014-04-13 13:30:00,109.59360989844285 3619,2014-04-13 13:35:00,103.87357384713333 3620,2014-04-13 13:40:00,99.71460238332381 3621,2014-04-13 13:45:00,112.23141645291429 3622,2014-04-13 13:50:00,103.89621320880475 3623,2014-04-13 13:55:00,99.94900651179522 3624,2014-04-13 14:00:00,100.15738290898571 3625,2014-04-13 14:05:00,102.99621762037619 3626,2014-04-13 14:10:00,101.82382910596667 3627,2014-04-13 14:15:00,111.37135836485713 3628,2014-04-13 14:20:00,104.13728931234762 3629,2014-04-13 14:25:00,111.8725466495381 3630,2014-04-13 14:30:00,101.78687502282857 3631,2014-04-13 14:35:00,106.89860138911905 3632,2014-04-13 14:40:00,110.02841924810951 3633,2014-04-13 14:45:00,109.4591469329 3634,2014-04-13 14:50:00,108.65284336769048 3635,2014-04-13 14:55:00,113.83911032028095 3636,2014-04-13 15:00:00,102.70924749037144 3637,2014-04-13 15:05:00,106.9597521408619 3638,2014-04-13 15:10:00,113.21150620085238 3639,2014-04-13 15:15:00,100.32148994214285 3640,2014-04-13 15:20:00,99.97684584093334 3641,2014-04-13 15:25:00,102.82288337522381 3642,2014-04-13 15:30:00,109.22576536621429 3643,2014-04-13 15:35:00,103.26299766760475 3644,2014-04-13 15:40:00,102.15621295819524 3645,2014-04-13 15:45:00,106.46061108798571 3646,2014-04-13 15:50:00,108.9447598420762 3647,2014-04-13 15:55:00,103.11161060046666 3648,2014-04-13 16:00:00,103.95376865315714 3649,2014-04-13 16:05:00,108.96708940744762 3650,2014-04-13 16:10:00,114.2893855539381 3651,2014-04-13 16:15:00,109.96088724232857 3652,2014-04-13 16:20:00,111.69892305411905 3653,2014-04-13 16:25:00,105.04887153150952 3654,2014-04-13 16:30:00,103.54342314649999 3655,2014-04-13 16:35:00,106.46307217229048 3656,2014-04-13 16:40:00,112.11634317668096 3657,2014-04-13 16:45:00,106.51046343967143 3658,2014-04-13 16:50:00,112.7647041939619 3659,2014-04-13 16:55:00,115.04488545695239 3660,2014-04-13 17:00:00,100.38454141834285 3661,2014-04-13 17:05:00,99.96611790363333 3662,2014-04-13 17:10:00,101.64043048902381 3663,2014-04-13 17:15:00,105.40434908791428 3664,2014-04-13 17:20:00,101.35855165510476 3665,2014-04-13 17:25:00,113.19994388259525 3666,2014-04-13 17:30:00,99.64709794048571 3667,2014-04-13 17:35:00,104.33688006357619 3668,2014-04-13 17:40:00,102.24675195576665 3669,2014-04-13 17:45:00,114.20370305395714 3670,2014-04-13 17:50:00,110.01821193594762 3671,2014-04-13 17:55:00,113.90643894693812 3672,2014-04-13 18:00:00,62.344325593028564 3673,2014-04-13 18:05:00,59.310291666719046 3674,2014-04-13 18:10:00,57.63594599780952 3675,2014-04-13 18:15:00,57.383608464000005 3676,2014-04-13 18:20:00,57.577865387490476 3677,2014-04-13 18:25:00,60.693621720880955 3678,2014-04-13 18:30:00,56.42491850927143 3679,2014-04-13 18:35:00,56.502217179461894 3680,2014-04-13 18:40:00,60.07306093535238 3681,2014-04-13 18:45:00,60.29755227774285 3682,2014-04-13 18:50:00,60.45350970193333 3683,2014-04-13 18:55:00,58.583303052323814 3684,2014-04-13 19:00:00,51.18134608321428 3685,2014-04-13 19:05:00,49.96879167790476 3686,2014-04-13 19:10:00,48.05808012869524 3687,2014-04-13 19:15:00,51.16403930808571 3688,2014-04-13 19:20:00,51.87021853277619 3689,2014-04-13 19:25:00,47.87687822826666 3690,2014-04-13 19:30:00,49.36860993815715 3691,2014-04-13 19:35:00,49.80686827414762 3692,2014-04-13 19:40:00,48.286425958438095 3693,2014-04-13 19:45:00,51.52501333832857 3694,2014-04-13 19:50:00,48.918108281019045 3695,2014-04-13 19:55:00,51.16043648440952 3696,2014-04-13 20:00:00,48.680393144199996 3697,2014-04-13 20:05:00,48.389035914390476 3698,2014-04-13 20:10:00,46.733897829980954 3699,2014-04-13 20:15:00,46.858322816671425 3700,2014-04-13 20:20:00,46.1557007470619 3701,2014-04-13 20:25:00,46.95516026035238 3702,2014-04-13 20:30:00,47.39157964334285 3703,2014-04-13 20:35:00,49.39664623583333 3704,2014-04-13 20:40:00,47.4922679332238 3705,2014-04-13 20:45:00,49.08989484961428 3706,2014-04-13 20:50:00,47.80636010330476 3707,2014-04-13 20:55:00,49.228665584295236 3708,2014-04-13 21:00:00,49.59951647688571 3709,2014-04-13 21:05:00,46.64709733407619 3710,2014-04-13 21:10:00,49.15649002076666 3711,2014-04-13 21:15:00,48.19724246015714 3712,2014-04-13 21:20:00,48.99031666294762 3713,2014-04-13 21:25:00,48.331742103038096 3714,2014-04-13 21:30:00,47.42426638262857 3715,2014-04-13 21:35:00,46.644447797719046 3716,2014-04-13 21:40:00,46.01669505650952 3717,2014-04-13 21:45:00,47.8950053609 3718,2014-04-13 21:50:00,49.730409061390475 3719,2014-04-13 21:55:00,48.72386852358095 3720,2014-04-13 22:00:00,47.00649059157143 3721,2014-04-13 22:05:00,49.0152875610619 3722,2014-04-13 22:10:00,48.789621269852375 3723,2014-04-13 22:15:00,46.84579750264285 3724,2014-04-13 22:20:00,45.78289822443333 3725,2014-04-13 22:25:00,46.20615809912381 3726,2014-04-13 22:30:00,49.25308789211428 3727,2014-04-13 22:35:00,49.09739929470476 3728,2014-04-13 22:40:00,46.93734483469524 3729,2014-04-13 22:45:00,46.904692560485714 3730,2014-04-13 22:50:00,48.94476073007619 3731,2014-04-13 22:55:00,49.53224744746666 3732,2014-04-13 23:00:00,48.88846054535714 3733,2014-04-13 23:05:00,48.201533409547615 3734,2014-04-13 23:10:00,46.757065866338095 3735,2014-04-13 23:15:00,47.89703000022857 3736,2014-04-13 23:20:00,46.73530181721905 3737,2014-04-13 23:25:00,49.041181754909516 3738,2014-04-13 23:30:00,47.3640975023 3739,2014-04-13 23:35:00,49.15882562149048 3740,2014-04-13 23:40:00,47.35756689828095 3741,2014-04-13 23:45:00,49.13550799397143 3742,2014-04-13 23:50:00,47.1792451515619 3743,2014-04-13 23:55:00,47.61402721935238 3744,2014-04-14 00:00:00,48.31909653454285 3745,2014-04-14 00:05:00,46.145733789433336 3746,2014-04-14 00:10:00,49.664852056823804 3747,2014-04-14 00:15:00,48.173887430214286 3748,2014-04-14 00:20:00,47.91818482070476 3749,2014-04-14 00:25:00,49.251921122595235 3750,2014-04-14 00:30:00,49.364836633885716 3751,2014-04-14 00:35:00,47.99826780857619 3752,2014-04-14 00:40:00,49.62571596986666 3753,2014-04-14 00:45:00,46.183058207157146 3754,2014-04-14 00:50:00,46.384450788047616 3755,2014-04-14 00:55:00,48.326141015338095 3756,2014-04-14 01:00:00,47.362692018628564 3757,2014-04-14 01:05:00,47.810769712419045 3758,2014-04-14 01:10:00,47.27362639540952 3759,2014-04-14 01:15:00,47.587651245800004 3760,2014-04-14 01:20:00,49.266775864790475 3761,2014-04-14 01:25:00,48.35753575178096 3762,2014-04-14 01:30:00,49.980449625671426 3763,2014-04-14 01:35:00,49.146028696061904 3764,2014-04-14 01:40:00,47.10061739735238 3765,2014-04-14 01:45:00,47.070773328042854 3766,2014-04-14 01:50:00,47.36442641383333 3767,2014-04-14 01:55:00,49.4013117321238 3768,2014-04-14 02:00:00,46.14486488831429 3769,2014-04-14 02:05:00,46.96387987740476 3770,2014-04-14 02:10:00,49.670268919495236 3771,2014-04-14 02:15:00,48.61762145858572 3772,2014-04-14 02:20:00,46.97286457247619 3773,2014-04-14 02:25:00,46.94949653956667 3774,2014-04-14 02:30:00,49.530829549857145 3775,2014-04-14 02:35:00,49.66282765214761 3776,2014-04-14 02:40:00,47.1197624590381 3777,2014-04-14 02:45:00,47.784720003728566 3778,2014-04-14 02:50:00,49.44850200211905 3779,2014-04-14 02:55:00,49.201589278209525 3780,2014-04-14 03:00:00,49.3806644263 3781,2014-04-14 03:05:00,48.20603323939048 3782,2014-04-14 03:10:00,49.786077145580954 3783,2014-04-14 03:15:00,47.45112760437142 3784,2014-04-14 03:20:00,46.7814504421619 3785,2014-04-14 03:25:00,48.99713171125238 3786,2014-04-14 03:30:00,48.327060521142855 3787,2014-04-14 03:35:00,49.59542640853333 3788,2014-04-14 03:40:00,46.50916080602381 3789,2014-04-14 03:45:00,49.56673389951429 3790,2014-04-14 03:50:00,47.37258337470476 3791,2014-04-14 03:55:00,48.82626790679524 3792,2014-04-14 04:00:00,46.374800870585716 3793,2014-04-14 04:05:00,48.66005137567619 3794,2014-04-14 04:10:00,49.098253423366664 3795,2014-04-14 04:15:00,47.71160800085714 3796,2014-04-14 04:20:00,47.10569044004762 3797,2014-04-14 04:25:00,48.4020108016381 3798,2014-04-14 04:30:00,49.59169178912857 3799,2014-04-14 04:35:00,47.56055848081905 3800,2014-04-14 04:40:00,47.28368671390952 3801,2014-04-14 04:45:00,47.3969912346 3802,2014-04-14 04:50:00,50.08521908789048 3803,2014-04-14 04:55:00,47.73323861548096 3804,2014-04-14 05:00:00,46.31798838817143 3805,2014-04-14 05:05:00,49.4377367365619 3806,2014-04-14 05:10:00,49.11555156225238 3807,2014-04-14 05:15:00,46.840165915542855 3808,2014-04-14 05:20:00,50.272950329833336 3809,2014-04-14 05:25:00,48.773022950723806 3810,2014-04-14 05:30:00,48.351332249514286 3811,2014-04-14 05:35:00,47.88453183240476 3812,2014-04-14 05:40:00,49.95778626039524 3813,2014-04-14 05:45:00,47.346389639985716 3814,2014-04-14 05:50:00,47.52105179137619 3815,2014-04-14 05:55:00,46.87505989336667 3816,2014-04-14 06:00:00,49.42933352515715 3817,2014-04-14 06:05:00,48.78249474064762 3818,2014-04-14 06:10:00,48.8440027722381 3819,2014-04-14 06:15:00,47.28906029552857 3820,2014-04-14 06:20:00,49.02729260411905 3821,2014-04-14 06:25:00,49.49189331280952 3822,2014-04-14 06:30:00,47.869054122899996 3823,2014-04-14 06:35:00,49.650329051990475 3824,2014-04-14 06:40:00,47.84754330648096 3825,2014-04-14 06:45:00,49.49237527457143 3826,2014-04-14 06:50:00,46.6021823345619 3827,2014-04-14 06:55:00,48.67936078685238 3828,2014-04-14 07:00:00,50.36024909974286 3829,2014-04-14 07:05:00,50.414561736033335 3830,2014-04-14 07:10:00,47.6240341229238 3831,2014-04-14 07:15:00,48.27006065001429 3832,2014-04-14 07:20:00,46.76381639380476 3833,2014-04-14 07:25:00,50.012710468495236 3834,2014-04-14 07:30:00,48.80107432688571 3835,2014-04-14 07:35:00,48.07462890627619 3836,2014-04-14 07:40:00,46.99274890066667 3837,2014-04-14 07:45:00,50.33617628485714 3838,2014-04-14 07:50:00,48.67742381034762 3839,2014-04-14 07:55:00,47.69569981153809 3840,2014-04-14 08:00:00,47.97228909192857 3841,2014-04-14 08:05:00,47.66165777131904 3842,2014-04-14 08:10:00,48.99354875920952 3843,2014-04-14 08:15:00,50.3136043031 3844,2014-04-14 08:20:00,50.02796568949047 3845,2014-04-14 08:25:00,48.45015445408095 3846,2014-04-14 08:30:00,49.92206887777142 3847,2014-04-14 08:35:00,48.315933829861905 3848,2014-04-14 08:40:00,47.64018094395238 3849,2014-04-14 08:45:00,50.57205331824285 3850,2014-04-14 08:50:00,47.86138360523333 3851,2014-04-14 08:55:00,47.94817073342381 3852,2014-04-14 09:00:00,103.32053728761429 3853,2014-04-14 09:05:00,91.68956866900476 3854,2014-04-14 09:10:00,100.21885747499523 3855,2014-04-14 09:15:00,102.61008922968571 3856,2014-04-14 09:20:00,96.85088811257619 3857,2014-04-14 09:25:00,89.93221262586667 3858,2014-04-14 09:30:00,95.00615878275714 3859,2014-04-14 09:35:00,91.43013591544762 3860,2014-04-14 09:40:00,95.5803902839381 3861,2014-04-14 09:45:00,100.67204252972857 3862,2014-04-14 09:50:00,95.90159611241904 3863,2014-04-14 09:55:00,95.81674117410951 3864,2014-04-14 10:00:00,107.2313726818 3865,2014-04-14 10:05:00,107.62527835149046 3866,2014-04-14 10:10:00,111.89459966498094 3867,2014-04-14 10:15:00,103.39799784537144 3868,2014-04-14 10:20:00,111.3720999277619 3869,2014-04-14 10:25:00,107.41049416065238 3870,2014-04-14 10:30:00,103.29886146874284 3871,2014-04-14 10:35:00,103.22243953633333 3872,2014-04-14 10:40:00,104.25437807502381 3873,2014-04-14 10:45:00,108.32116341121429 3874,2014-04-14 10:50:00,102.24660283260475 3875,2014-04-14 10:55:00,112.95542211529525 3876,2014-04-14 11:00:00,109.55069545308571 3877,2014-04-14 11:05:00,115.04665710777618 3878,2014-04-14 11:10:00,101.16018158546666 3879,2014-04-14 11:15:00,105.87849837865714 3880,2014-04-14 11:20:00,100.79978065464762 3881,2014-04-14 11:25:00,104.77438096253809 3882,2014-04-14 11:30:00,114.16127950642857 3883,2014-04-14 11:35:00,101.04160996841905 3884,2014-04-14 11:40:00,107.40329300090951 3885,2014-04-14 11:45:00,102.3440366888 3886,2014-04-14 11:50:00,107.11112432109047 3887,2014-04-14 11:55:00,113.83022654848095 3888,2014-04-14 12:00:00,110.79934499917144 3889,2014-04-14 12:05:00,112.6235677082619 3890,2014-04-14 12:10:00,106.43601542915238 3891,2014-04-14 12:15:00,115.95672354154289 3892,2014-04-14 12:20:00,112.20650900163332 3893,2014-04-14 12:25:00,107.62005638072381 3894,2014-04-14 12:30:00,107.70206296521428 3895,2014-04-14 12:35:00,115.57556287280478 3896,2014-04-14 12:40:00,110.11310336299523 3897,2014-04-14 12:45:00,112.19764059188572 3898,2014-04-14 12:50:00,107.5811327063762 3899,2014-04-14 12:55:00,104.49880600186668 3900,2014-04-14 13:00:00,112.57474734705714 3901,2014-04-14 13:05:00,210.7308639300476 3902,2014-04-14 13:10:00,109.0350190253381 3903,2014-04-14 13:15:00,111.00483737092857 3904,2014-04-14 13:20:00,104.36210860801906 3905,2014-04-14 13:25:00,113.73775010370952 3906,2014-04-14 13:30:00,116.2121839352 3907,2014-04-14 13:35:00,115.30688894679048 3908,2014-04-14 13:40:00,106.20183856408094 3909,2014-04-14 13:45:00,107.56207473887143 3910,2014-04-14 13:50:00,114.0063144366619 3911,2014-04-14 13:55:00,110.60201122435238 3912,2014-04-14 14:00:00,109.86989715764287 3913,2014-04-14 14:05:00,115.93668715283333 3914,2014-04-14 14:10:00,109.69455551802382 3915,2014-04-14 14:15:00,109.3646316862143 3916,2014-04-14 14:20:00,101.80571395190476 3917,2014-04-14 14:25:00,102.25150726329525 3918,2014-04-14 14:30:00,101.2670489415857 3919,2014-04-14 14:35:00,115.7669764314762 3920,2014-04-14 14:40:00,107.69708358596668 3921,2014-04-14 14:45:00,108.66727330585714 3922,2014-04-14 14:50:00,114.70363352334762 3923,2014-04-14 14:55:00,110.93300516003808 3924,2014-04-14 15:00:00,110.94766929422856 3925,2014-04-14 15:05:00,105.94768316961905 3926,2014-04-14 15:10:00,114.55302421830952 3927,2014-04-14 15:15:00,103.8713129451 3928,2014-04-14 15:20:00,102.07588458719047 3929,2014-04-14 15:25:00,104.29856404238095 3930,2014-04-14 15:30:00,105.52413460457143 3931,2014-04-14 15:35:00,105.7647542674619 3932,2014-04-14 15:40:00,111.98337576795238 3933,2014-04-14 15:45:00,104.74786159654286 3934,2014-04-14 15:50:00,112.09657107053333 3935,2014-04-14 15:55:00,102.73568338332382 3936,2014-04-14 16:00:00,103.64081090121428 3937,2014-04-14 16:05:00,109.43414406680476 3938,2014-04-14 16:10:00,116.05076151869524 3939,2014-04-14 16:15:00,115.06095248938571 3940,2014-04-14 16:20:00,116.81536326947617 3941,2014-04-14 16:25:00,111.73042348836665 3942,2014-04-14 16:30:00,112.14323600445714 3943,2014-04-14 16:35:00,111.33800816124763 3944,2014-04-14 16:40:00,111.3101834879381 3945,2014-04-14 16:45:00,103.70646133292857 3946,2014-04-14 16:50:00,110.05978740261905 3947,2014-04-14 16:55:00,107.54449635900953 3948,2014-04-14 17:00:00,108.4555650855 3949,2014-04-14 17:05:00,109.76001878009049 3950,2014-04-14 17:10:00,103.44419126438095 3951,2014-04-14 17:15:00,107.14909531347143 3952,2014-04-14 17:20:00,102.41992684096189 3953,2014-04-14 17:25:00,117.08685880065238 3954,2014-04-14 17:30:00,103.31606294204286 3955,2014-04-14 17:35:00,105.56344991363332 3956,2014-04-14 17:40:00,115.69517751272379 3957,2014-04-14 17:45:00,109.16529441181427 3958,2014-04-14 17:50:00,103.61957150490475 3959,2014-04-14 17:55:00,107.60450383799524 3960,2014-04-14 18:00:00,59.00583520508571 3961,2014-04-14 18:05:00,59.55310279617619 3962,2014-04-14 18:10:00,58.612152093566664 3963,2014-04-14 18:15:00,61.09125703985714 3964,2014-04-14 18:20:00,63.45651227724761 3965,2014-04-14 18:25:00,62.05168458923809 3966,2014-04-14 18:30:00,62.18953225182857 3967,2014-04-14 18:35:00,59.600101064119045 3968,2014-04-14 18:40:00,60.52472416840952 3969,2014-04-14 18:45:00,63.7407928963 3970,2014-04-14 18:50:00,58.90096441829047 3971,2014-04-14 18:55:00,63.83688055208095 3972,2014-04-14 19:00:00,51.88050152147143 3973,2014-04-14 19:05:00,53.4714310854619 3974,2014-04-14 19:10:00,51.15311995575238 3975,2014-04-14 19:15:00,51.25390809104285 3976,2014-04-14 19:20:00,53.11052185283333 3977,2014-04-14 19:25:00,53.26755536752381 3978,2014-04-14 19:30:00,50.787021280714285 3979,2014-04-14 19:35:00,54.12411695210476 3980,2014-04-14 19:40:00,50.15160977839524 3981,2014-04-14 19:45:00,50.08742786618571 3982,2014-04-14 19:50:00,52.45583382267618 3983,2014-04-14 19:55:00,53.03329402276667 3984,2014-04-14 20:00:00,52.01064645975714 3985,2014-04-14 20:05:00,49.74095529614762 3986,2014-04-14 20:10:00,48.1933314840381 3987,2014-04-14 20:15:00,50.56664172702857 3988,2014-04-14 20:20:00,49.29121371251905 3989,2014-04-14 20:25:00,49.88541068980952 3990,2014-04-14 20:30:00,50.120270754100005 3991,2014-04-14 20:35:00,48.39118390539048 3992,2014-04-14 20:40:00,50.12496209688095 3993,2014-04-14 20:45:00,49.88802654167142 3994,2014-04-14 20:50:00,51.0678429591619 3995,2014-04-14 20:55:00,50.801349700352375 3996,2014-04-14 21:00:00,48.562961825442855 3997,2014-04-14 21:05:00,48.65449682713333 3998,2014-04-14 21:10:00,48.84226779652381 3999,2014-04-14 21:15:00,48.56010184931428 4000,2014-04-14 21:20:00,50.48977600330476 4001,2014-04-14 21:25:00,51.852558960295234 4002,2014-04-14 21:30:00,50.48413950588571 4003,2014-04-14 21:35:00,50.30900061077619 4004,2014-04-14 21:40:00,49.525648968166664 4005,2014-04-14 21:45:00,49.14182967195714 4006,2014-04-14 21:50:00,51.55473520964762 4007,2014-04-14 21:55:00,51.795000374038096 4008,2014-04-14 22:00:00,49.82772088442857 4009,2014-04-14 22:05:00,49.00806539011904 4010,2014-04-14 22:10:00,50.93703561340952 4011,2014-04-14 22:15:00,48.391365788399995 4012,2014-04-14 22:20:00,50.933763275290474 4013,2014-04-14 22:25:00,51.154849200880946 4014,2014-04-14 22:30:00,48.383446829171426 4015,2014-04-14 22:35:00,51.8019889172619 4016,2014-04-14 22:40:00,51.84406589895238 4017,2014-04-14 22:45:00,51.65614776654286 4018,2014-04-14 22:50:00,49.89915733483333 4019,2014-04-14 22:55:00,48.905795294023804 4020,2014-04-14 23:00:00,50.24265439041429 4021,2014-04-14 23:05:00,49.601668623004755 4022,2014-04-14 23:10:00,48.75300398369524 4023,2014-04-14 23:15:00,49.63152273428571 4024,2014-04-14 23:20:00,50.60000139857619 4025,2014-04-14 23:25:00,48.235080369466665 4026,2014-04-14 23:30:00,49.292741211757146 4027,2014-04-14 23:35:00,48.03744684384762 4028,2014-04-14 23:40:00,50.972251727538094 4029,2014-04-14 23:45:00,50.544391690728574 4030,2014-04-14 23:50:00,48.239311716819046 4031,2014-04-14 23:55:00,51.85570667850952 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/art_daily_jumpsup_noised_trended_det2.csv ================================================ timestamp,value 2014-04-01 00:00:00,19.761251902999998 2014-04-01 00:05:00,20.508273763190473 2014-04-01 00:10:00,19.976522396880952 2014-04-01 00:15:00,21.512587501971428 2014-04-01 00:20:00,20.217501314561904 2014-04-01 00:25:00,19.96032805275238 2014-04-01 00:30:00,21.74304681884286 2014-04-01 00:35:00,20.930841717533333 2014-04-01 00:40:00,18.50572343892381 2014-04-01 00:45:00,18.777782130514286 2014-04-01 00:50:00,21.222896213704765 2014-04-01 00:55:00,21.42525052279524 2014-04-01 01:00:00,20.270049030685716 2014-04-01 01:05:00,20.314547101976192 2014-04-01 01:10:00,20.63189851806667 2014-04-01 01:15:00,19.86807023995714 2014-04-01 01:20:00,20.83984411294762 2014-04-01 01:25:00,18.560413125538094 2014-04-01 01:30:00,21.97904554092857 2014-04-01 01:35:00,21.141988342819047 2014-04-01 01:40:00,20.673506339809524 2014-04-01 01:45:00,19.421538228 2014-04-01 01:50:00,18.807512425990474 2014-04-01 01:55:00,19.808502807680952 2014-04-01 02:00:00,20.824878390871426 2014-04-01 02:05:00,20.720850878461903 2014-04-01 02:10:00,19.724017001252378 2014-04-01 02:15:00,20.654038432442857 2014-04-01 02:20:00,21.463326515633334 2014-04-01 02:25:00,18.32091289892381 2014-04-01 02:30:00,20.025698477414284 2014-04-01 02:35:00,21.264875675804763 2014-04-01 02:40:00,20.42267311999524 2014-04-01 02:45:00,20.851440065985717 2014-04-01 02:50:00,20.31968176087619 2014-04-01 02:55:00,22.227914845366666 2014-04-01 03:00:00,18.486343288857142 2014-04-01 03:05:00,20.239476906147623 2014-04-01 03:10:00,18.648404291738096 2014-04-01 03:15:00,18.929320819928574 2014-04-01 03:20:00,19.829772449319048 2014-04-01 03:25:00,18.927219889809525 2014-04-01 03:30:00,22.167248663800002 2014-04-01 03:35:00,22.107099583090474 2014-04-01 03:40:00,19.671819537280953 2014-04-01 03:45:00,20.893812276771428 2014-04-01 03:50:00,20.477275187161904 2014-04-01 03:55:00,21.61205030305238 2014-04-01 04:00:00,20.866925296442858 2014-04-01 04:05:00,18.365593151333332 2014-04-01 04:10:00,21.42472135192381 2014-04-01 04:15:00,21.366856770914286 2014-04-01 04:20:00,20.425795584204764 2014-04-01 04:25:00,22.006021130995236 2014-04-01 04:30:00,22.035570537085718 2014-04-01 04:35:00,20.50487289727619 2014-04-01 04:40:00,20.84861959146667 2014-04-01 04:45:00,22.410195430557142 2014-04-01 04:50:00,19.62682855824762 2014-04-01 04:55:00,19.737457064438097 2014-04-01 05:00:00,19.177524182128572 2014-04-01 05:05:00,22.037336804219045 2014-04-01 05:10:00,21.439263083609525 2014-04-01 05:15:00,18.8913213955 2014-04-01 05:20:00,22.403259880990475 2014-04-01 05:25:00,21.40747778498095 2014-04-01 05:30:00,21.893159866971427 2014-04-01 05:35:00,18.691115061461907 2014-04-01 05:40:00,20.52579605675238 2014-04-01 05:45:00,21.307786004042857 2014-04-01 05:50:00,20.69261967163333 2014-04-01 05:55:00,21.19486367232381 2014-04-01 06:00:00,21.807210540114284 2014-04-01 06:05:00,20.040503013704765 2014-04-01 06:10:00,21.94526994059524 2014-04-01 06:15:00,19.209700133385716 2014-04-01 06:20:00,19.64902041057619 2014-04-01 06:25:00,18.746299146366667 2014-04-01 06:30:00,20.038064388157142 2014-04-01 06:35:00,20.10743579834762 2014-04-01 06:40:00,21.816320484038098 2014-04-01 06:45:00,21.21520125262857 2014-04-01 06:50:00,20.357009280219046 2014-04-01 06:55:00,21.226015438309524 2014-04-01 07:00:00,18.8361334021 2014-04-01 07:05:00,19.353526620290474 2014-04-01 07:10:00,21.147672373380953 2014-04-01 07:15:00,21.21278870547143 2014-04-01 07:20:00,21.751300539561907 2014-04-01 07:25:00,20.27420141715238 2014-04-01 07:30:00,21.559859243642858 2014-04-01 07:35:00,21.413004663533332 2014-04-01 07:40:00,22.53809732302381 2014-04-01 07:45:00,19.552485191414284 2014-04-01 07:50:00,20.90612301690476 2014-04-01 07:55:00,21.113903006495235 2014-04-01 08:00:00,22.70887725398571 2014-04-01 08:05:00,19.526462759176187 2014-04-01 08:10:00,20.82203874656667 2014-04-01 08:15:00,20.12134837375714 2014-04-01 08:20:00,20.847619493347622 2014-04-01 08:25:00,19.680002503638093 2014-04-01 08:30:00,18.949378085128572 2014-04-01 08:35:00,21.05663086321905 2014-04-01 08:40:00,20.117226787209525 2014-04-01 08:45:00,19.509015607000002 2014-04-01 08:50:00,20.084432740490474 2014-04-01 08:55:00,18.993251758180953 2014-04-01 09:00:00,74.92958581217142 2014-04-01 09:05:00,69.91462354836189 2014-04-01 09:10:00,73.09930644725237 2014-04-01 09:15:00,67.78030034374287 2014-04-01 09:20:00,74.31841281223333 2014-04-01 09:25:00,68.61390162262381 2014-04-01 09:30:00,69.85387066761429 2014-04-01 09:35:00,68.74405289080477 2014-04-01 09:40:00,72.03568006189523 2014-04-01 09:45:00,69.7770583696857 2014-04-01 09:50:00,65.77172155117619 2014-04-01 09:55:00,64.06475429266668 2014-04-01 10:00:00,80.13990765835715 2014-04-01 10:05:00,78.33237062224762 2014-04-01 10:10:00,72.2372809079381 2014-04-01 10:15:00,76.89516164052857 2014-04-01 10:20:00,78.75194911701905 2014-04-01 10:25:00,83.60344251280951 2014-04-01 10:30:00,71.9585883865 2014-04-01 10:35:00,76.19358828099048 2014-04-01 10:40:00,83.56000397688095 2014-04-01 10:45:00,80.86336084967142 2014-04-01 10:50:00,75.3074150591619 2014-04-01 10:55:00,83.93430347475238 2014-04-01 11:00:00,80.39548396244285 2014-04-01 11:05:00,80.48337181273332 2014-04-01 11:10:00,88.09666885212381 2014-04-01 11:15:00,87.6354051532143 2014-04-01 11:20:00,78.28200855820477 2014-04-01 11:25:00,74.82311570039523 2014-04-01 11:30:00,77.77418942448571 2014-04-01 11:35:00,73.08703196247619 2014-04-01 11:40:00,72.93995913686668 2014-04-01 11:45:00,78.90749119775714 2014-04-01 11:50:00,87.59052687924762 2014-04-01 11:55:00,86.4900552502381 2014-04-01 12:00:00,81.15829421172856 2014-04-01 12:05:00,82.02523879981905 2014-04-01 12:10:00,73.09473154860952 2014-04-01 12:15:00,76.4512308711 2014-04-01 12:20:00,73.41070084389048 2014-04-01 12:25:00,85.08037631648095 2014-04-01 12:30:00,75.35720776567143 2014-04-01 12:35:00,86.9251798400619 2014-04-01 12:40:00,83.32538957295237 2014-04-01 12:45:00,76.71828684284286 2014-04-01 12:50:00,75.57993017653332 2014-04-01 12:55:00,83.09681863002382 2014-04-01 13:00:00,87.55336675621429 2014-04-01 13:05:00,84.64187976130475 2014-04-01 13:10:00,78.73372324459524 2014-04-01 13:15:00,82.56163768558571 2014-04-01 13:20:00,78.1441899914762 2014-04-01 13:25:00,89.16319300076667 2014-04-01 13:30:00,85.16662861575713 2014-04-01 13:35:00,83.02326462964763 2014-04-01 13:40:00,79.97347906433811 2014-04-01 13:45:00,83.09846151082857 2014-04-01 13:50:00,78.68238424141906 2014-04-01 13:55:00,73.68700611410952 2014-04-01 14:00:00,79.56765692970001 2014-04-01 14:05:00,88.14096298019048 2014-04-01 14:10:00,83.28176146948095 2014-04-01 14:15:00,74.61209219977142 2014-04-01 14:20:00,87.43552404396192 2014-04-01 14:25:00,77.58553747455238 2014-04-01 14:30:00,77.19131153154285 2014-04-01 14:35:00,78.05185466793333 2014-04-01 14:40:00,82.54086029622381 2014-04-01 14:45:00,82.02809946021429 2014-04-01 14:50:00,81.18319143010476 2014-04-01 14:55:00,84.80842798599524 2014-04-01 15:00:00,78.40314959548569 2014-04-01 15:05:00,85.85894721047619 2014-04-01 15:10:00,76.15859539126667 2014-04-01 15:15:00,85.88272835755714 2014-04-01 15:20:00,83.98921614184762 2014-04-01 15:25:00,84.3070249072381 2014-04-01 15:30:00,81.08801775882857 2014-04-01 15:35:00,84.06259991911905 2014-04-01 15:40:00,74.67485881190952 2014-04-01 15:45:00,87.0302458745 2014-04-01 15:50:00,74.30174647989048 2014-04-01 15:55:00,75.80028106358095 2014-04-01 16:00:00,82.65705080557143 2014-04-01 16:05:00,85.2664342373619 2014-04-01 16:10:00,74.66333682805238 2014-04-01 16:15:00,88.18296335724288 2014-04-01 16:20:00,89.03588756493333 2014-04-01 16:25:00,83.16081972282379 2014-04-01 16:30:00,81.1729565479143 2014-04-01 16:35:00,85.34281330270476 2014-04-01 16:40:00,78.74166454819525 2014-04-01 16:45:00,81.38761326688571 2014-04-01 16:50:00,88.16122623537619 2014-04-01 16:55:00,88.80073587276668 2014-04-01 17:00:00,88.35092965575714 2014-04-01 17:05:00,77.72443742994763 2014-04-01 17:10:00,77.25221366243811 2014-04-01 17:15:00,78.30278118942857 2014-04-01 17:20:00,80.60856648641905 2014-04-01 17:25:00,78.58170855020953 2014-04-01 17:30:00,79.54987478470001 2014-04-01 17:35:00,83.50010024889049 2014-04-01 17:40:00,85.77775945288096 2014-04-01 17:45:00,85.35372043357143 2014-04-01 17:50:00,86.6230063261619 2014-04-01 17:55:00,74.11462498665237 2014-04-01 18:00:00,30.71263352284286 2014-04-01 18:05:00,35.46662778213334 2014-04-01 18:10:00,33.833722087723814 2014-04-01 18:15:00,34.12955835781428 2014-04-01 18:20:00,30.773455073104763 2014-04-01 18:25:00,32.07834772229524 2014-04-01 18:30:00,34.537246951585715 2014-04-01 18:35:00,35.95798370177619 2014-04-01 18:40:00,36.33535375226666 2014-04-01 18:45:00,33.676785771657144 2014-04-01 18:50:00,33.97257650864762 2014-04-01 18:55:00,35.82049918083809 2014-04-01 19:00:00,24.26498554472857 2014-04-01 19:05:00,24.179394009119047 2014-04-01 19:10:00,25.92608468460952 2014-04-01 19:15:00,25.417647290300003 2014-04-01 19:20:00,25.958834064990477 2014-04-01 19:25:00,22.871376598280953 2014-04-01 19:30:00,24.250272373971427 2014-04-01 19:35:00,25.682785727861905 2014-04-01 19:40:00,22.41389351475238 2014-04-01 19:45:00,25.483478007142857 2014-04-01 19:50:00,22.750552940133332 2014-04-01 19:55:00,25.55864452732381 2014-04-01 20:00:00,22.724469874714284 2014-04-01 20:05:00,21.016649152304762 2014-04-01 20:10:00,22.171453712195238 2014-04-01 20:15:00,23.033119021385716 2014-04-01 20:20:00,22.84373742017619 2014-04-01 20:25:00,22.00492094026667 2014-04-01 20:30:00,23.946162179957142 2014-04-01 20:35:00,22.39670031804762 2014-04-01 20:40:00,22.349270303938095 2014-04-01 20:45:00,20.539656763628575 2014-04-01 20:50:00,24.06912389771905 2014-04-01 20:55:00,21.025028759209526 2014-04-01 21:00:00,22.0849229424 2014-04-01 21:05:00,23.198539327590474 2014-04-01 21:10:00,20.842230716780954 2014-04-01 21:15:00,22.103340106171427 2014-04-01 21:20:00,20.958522645261905 2014-04-01 21:25:00,23.05196846445238 2014-04-01 21:30:00,22.27424282924286 2014-04-01 21:35:00,23.45382145873333 2014-04-01 21:40:00,23.61633128162381 2014-04-01 21:45:00,22.635753847714284 2014-04-01 21:50:00,22.951297207104762 2014-04-01 21:55:00,22.250670613895238 2014-04-01 22:00:00,21.520756843285717 2014-04-01 22:05:00,22.58396664527619 2014-04-01 22:10:00,23.633088978266667 2014-04-01 22:15:00,21.672208707557143 2014-04-01 22:20:00,21.27017504954762 2014-04-01 22:25:00,21.574007437638095 2014-04-01 22:30:00,21.76947100942857 2014-04-01 22:35:00,20.32817562891905 2014-04-01 22:40:00,22.03677089240952 2014-04-01 22:45:00,22.0276851491 2014-04-01 22:50:00,22.412005401090475 2014-04-01 22:55:00,21.516084293580953 2014-04-01 23:00:00,22.509928676971427 2014-04-01 23:05:00,23.578007613861903 2014-04-01 23:10:00,23.89452614255238 2014-04-01 23:15:00,22.41424593384286 2014-04-01 23:20:00,20.257185857233335 2014-04-01 23:25:00,23.97191816972381 2014-04-01 23:30:00,22.925660629314283 2014-04-01 23:35:00,21.453223374304763 2014-04-01 23:40:00,20.705295057195237 2014-04-01 23:45:00,20.697776306885714 2014-04-01 23:50:00,20.80253864087619 2014-04-01 23:55:00,20.32119775106667 2014-04-02 00:00:00,23.751473897457142 2014-04-02 00:05:00,22.31337055034762 2014-04-02 00:10:00,22.957575746138094 2014-04-02 00:15:00,23.477612608528574 2014-04-02 00:20:00,23.338783072919046 2014-04-02 00:25:00,23.71048201870952 2014-04-02 00:30:00,24.056518490100004 2014-04-02 00:35:00,21.95122293519048 2014-04-02 00:40:00,24.003722819080952 2014-04-02 00:45:00,23.102981221971426 2014-04-02 00:50:00,20.499934665961906 2014-04-02 00:55:00,22.951834865752378 2014-04-02 01:00:00,22.979009495542858 2014-04-02 01:05:00,23.863025588533333 2014-04-02 01:10:00,21.73875233942381 2014-04-02 01:15:00,22.594110286814285 2014-04-02 01:20:00,20.310654965904764 2014-04-02 01:25:00,21.597646206795236 2014-04-02 01:30:00,20.525760618885716 2014-04-02 01:35:00,22.371718081576187 2014-04-02 01:40:00,23.56145726866667 2014-04-02 01:45:00,21.124877911357142 2014-04-02 01:50:00,22.41631180124762 2014-04-02 01:55:00,21.130022641238092 2014-04-02 02:00:00,20.80418244282857 2014-04-02 02:05:00,22.372856215319047 2014-04-02 02:10:00,20.65290400760952 2014-04-02 02:15:00,22.6931685246 2014-04-02 02:20:00,20.47654031889048 2014-04-02 02:25:00,20.785490839880953 2014-04-02 02:30:00,22.566061370471427 2014-04-02 02:35:00,22.739141556361908 2014-04-02 02:40:00,20.49690010135238 2014-04-02 02:45:00,22.681900009142858 2014-04-02 02:50:00,23.749843434633334 2014-04-02 02:55:00,23.29253851872381 2014-04-02 03:00:00,20.935454701414283 2014-04-02 03:05:00,22.788053352204763 2014-04-02 03:10:00,23.11460523839524 2014-04-02 03:15:00,20.581960521285716 2014-04-02 03:20:00,23.86186686517619 2014-04-02 03:25:00,24.07298625586667 2014-04-02 03:30:00,23.857166236257143 2014-04-02 03:35:00,23.76132349104762 2014-04-02 03:40:00,23.450098889038095 2014-04-02 03:45:00,23.011406696528574 2014-04-02 03:50:00,23.199627067619048 2014-04-02 03:55:00,23.718140697109526 2014-04-02 04:00:00,23.1499938334 2014-04-02 04:05:00,21.818348302890474 2014-04-02 04:10:00,22.01872536098095 2014-04-02 04:15:00,24.110551302071425 2014-04-02 04:20:00,20.598250247961904 2014-04-02 04:25:00,23.33248470595238 2014-04-02 04:30:00,24.363753066842854 2014-04-02 04:35:00,23.376996013133333 2014-04-02 04:40:00,24.53517176242381 2014-04-02 04:45:00,23.317143907814284 2014-04-02 04:50:00,20.711856878804763 2014-04-02 04:55:00,23.88988476469524 2014-04-02 05:00:00,21.727805362085714 2014-04-02 05:05:00,22.38095509317619 2014-04-02 05:10:00,21.852534330266668 2014-04-02 05:15:00,21.685823567657142 2014-04-02 05:20:00,22.34467043374762 2014-04-02 05:25:00,22.141493889038095 2014-04-02 05:30:00,23.167282898828574 2014-04-02 05:35:00,23.893973851619048 2014-04-02 05:40:00,21.83716413650952 2014-04-02 05:45:00,21.5111346113 2014-04-02 05:50:00,23.331271559690475 2014-04-02 05:55:00,23.352411215680952 2014-04-02 06:00:00,24.283096385671428 2014-04-02 06:05:00,20.749794650561903 2014-04-02 06:10:00,24.10561502945238 2014-04-02 06:15:00,22.78490154894286 2014-04-02 06:20:00,23.19354169003333 2014-04-02 06:25:00,21.08125957172381 2014-04-02 06:30:00,22.453674017214286 2014-04-02 06:35:00,21.639864390904762 2014-04-02 06:40:00,21.754995358395238 2014-04-02 06:45:00,22.761916172985714 2014-04-02 06:50:00,24.00279999207619 2014-04-02 06:55:00,23.735540387266667 2014-04-02 07:00:00,23.131856979157142 2014-04-02 07:05:00,22.93297039004762 2014-04-02 07:10:00,22.491962268138096 2014-04-02 07:15:00,24.68101846562857 2014-04-02 07:20:00,23.038389264519047 2014-04-02 07:25:00,21.820925117009523 2014-04-02 07:30:00,21.732863168199998 2014-04-02 07:35:00,23.265352599290473 2014-04-02 07:40:00,22.918691061580954 2014-04-02 07:45:00,20.865612640371427 2014-04-02 07:50:00,24.162523393561905 2014-04-02 07:55:00,23.66619179785238 2014-04-02 08:00:00,23.504460015842856 2014-04-02 08:05:00,21.13970596413333 2014-04-02 08:10:00,22.32024721022381 2014-04-02 08:15:00,24.620993328614283 2014-04-02 08:20:00,24.337261727304764 2014-04-02 08:25:00,22.03651698959524 2014-04-02 08:30:00,21.530021250685717 2014-04-02 08:35:00,22.705578019176187 2014-04-02 08:40:00,22.339988181366667 2014-04-02 08:45:00,23.653012649657143 2014-04-02 08:50:00,24.797286859347622 2014-04-02 08:55:00,22.390993895138095 2014-04-02 09:00:00,64.99267731952858 2014-04-02 09:05:00,76.36141956111905 2014-04-02 09:10:00,64.67742585510952 2014-04-02 09:15:00,77.1263662013 2014-04-02 09:20:00,73.21447069709048 2014-04-02 09:25:00,76.99060418718095 2014-04-02 09:30:00,66.90644316697144 2014-04-02 09:35:00,64.75202912026191 2014-04-02 09:40:00,70.84560808555239 2014-04-02 09:45:00,70.34187129534286 2014-04-02 09:50:00,68.72912824963333 2014-04-02 09:55:00,77.25240186122382 2014-04-02 10:00:00,85.64221380881429 2014-04-02 10:05:00,83.15090773360475 2014-04-02 10:10:00,75.41815592429523 2014-04-02 10:15:00,84.29473500988571 2014-04-02 10:20:00,84.18870948737619 2014-04-02 10:25:00,79.50997472116667 2014-04-02 10:30:00,87.27303446165713 2014-04-02 10:35:00,75.51929435124762 2014-04-02 10:40:00,77.08431706383809 2014-04-02 10:45:00,73.92392031662857 2014-04-02 10:50:00,85.29551791851905 2014-04-02 10:55:00,82.60726519600952 2014-04-02 11:00:00,79.7018106216 2014-04-02 11:05:00,77.30573298199049 2014-04-02 11:10:00,75.34639108688094 2014-04-02 11:15:00,77.36724295197143 2014-04-02 11:20:00,81.93180092016188 2014-04-02 11:25:00,78.66130489605239 2014-04-02 11:30:00,78.85649540704286 2014-04-02 11:35:00,88.67024986883332 2014-04-02 11:40:00,82.94527336822381 2014-04-02 11:45:00,86.3579876663143 2014-04-02 11:50:00,75.33535169520476 2014-04-02 11:55:00,80.58240324679524 2014-04-02 12:00:00,82.78539522118571 2014-04-02 12:05:00,78.1144166701762 2014-04-02 12:10:00,77.06352365216668 2014-04-02 12:15:00,89.05835776635715 2014-04-02 12:20:00,90.17051656544761 2014-04-02 12:25:00,76.42448217533808 2014-04-02 12:30:00,80.75012681282857 2014-04-02 12:35:00,90.49414001391904 2014-04-02 12:40:00,76.51640054860951 2014-04-02 12:45:00,85.4807540517 2014-04-02 12:50:00,90.73916576129048 2014-04-02 12:55:00,90.84252775528095 2014-04-02 13:00:00,82.82405522547143 2014-04-02 13:05:00,77.8970926726619 2014-04-02 13:10:00,78.53374541685238 2014-04-02 13:15:00,89.53881910974286 2014-04-02 13:20:00,89.8994805398333 2014-04-02 13:25:00,85.04723385362381 2014-04-02 13:30:00,87.58681455981429 2014-04-02 13:35:00,87.17443344940476 2014-04-02 13:40:00,85.93241941099524 2014-04-02 13:45:00,88.5865102486857 2014-04-02 13:50:00,86.3245701976762 2014-04-02 13:55:00,83.91012298976668 2014-04-02 14:00:00,79.18052096175714 2014-04-02 14:05:00,87.29848061884762 2014-04-02 14:10:00,82.9789243803381 2014-04-02 14:15:00,80.12816311552857 2014-04-02 14:20:00,88.24968756471905 2014-04-02 14:25:00,86.57348605340952 2014-04-02 14:30:00,90.4307571332 2014-04-02 14:35:00,78.08842365729048 2014-04-02 14:40:00,85.83545492918095 2014-04-02 14:45:00,79.36400934207144 2014-04-02 14:50:00,89.9204397178619 2014-04-02 14:55:00,77.06316059355238 2014-04-02 15:00:00,85.97993977384286 2014-04-02 15:05:00,88.14614216703333 2014-04-02 15:10:00,81.17496354002381 2014-04-02 15:15:00,90.7698358002143 2014-04-02 15:20:00,89.12277384300475 2014-04-02 15:25:00,80.23250157969524 2014-04-02 15:30:00,75.64675083938572 2014-04-02 15:35:00,80.28000424177621 2014-04-02 15:40:00,80.04189978486667 2014-04-02 15:45:00,89.78771296435714 2014-04-02 15:50:00,91.02964672134762 2014-04-02 15:55:00,76.69032585113808 2014-04-02 16:00:00,83.11199310982857 2014-04-02 16:05:00,84.35202593931905 2014-04-02 16:10:00,77.07275501080952 2014-04-02 16:15:00,81.6335635095 2014-04-02 16:20:00,80.67436117369049 2014-04-02 16:25:00,84.18537791398094 2014-04-02 16:30:00,86.19496727247143 2014-04-02 16:35:00,86.87911382166189 2014-04-02 16:40:00,77.81889031765238 2014-04-02 16:45:00,88.64539287454286 2014-04-02 16:50:00,86.50234672513334 2014-04-02 16:55:00,89.87830692512381 2014-04-02 17:00:00,82.85006082791429 2014-04-02 17:05:00,89.97035782540476 2014-04-02 17:10:00,89.52794822849523 2014-04-02 17:15:00,82.6975546904857 2014-04-02 17:20:00,181.78873924537623 2014-04-02 17:25:00,90.62287552696668 2014-04-02 17:30:00,87.14796085345715 2014-04-02 17:35:00,90.56468981094763 2014-04-02 17:40:00,88.4718020129381 2014-04-02 17:45:00,85.47640620852857 2014-04-02 17:50:00,77.58873511991905 2014-04-02 17:55:00,80.40622084620952 2014-04-02 18:00:00,38.750584685300005 2014-04-02 18:05:00,34.60173598589047 2014-04-02 18:10:00,33.16170647478095 2014-04-02 18:15:00,37.10065650737143 2014-04-02 18:20:00,37.2773827022619 2014-04-02 18:25:00,34.41412591045238 2014-04-02 18:30:00,34.49973762954286 2014-04-02 18:35:00,35.602992334833345 2014-04-02 18:40:00,32.74896753162381 2014-04-02 18:45:00,37.66862505251428 2014-04-02 18:50:00,34.65376708120476 2014-04-02 18:55:00,38.09592251219524 2014-04-02 19:00:00,27.595068699885715 2014-04-02 19:05:00,26.969806030376187 2014-04-02 19:10:00,25.46960488546667 2014-04-02 19:15:00,26.334704106257146 2014-04-02 19:20:00,26.02188147784762 2014-04-02 19:25:00,25.554677756438092 2014-04-02 19:30:00,27.84357783312857 2014-04-02 19:35:00,26.217479517019047 2014-04-02 19:40:00,27.78940769140953 2014-04-02 19:45:00,24.5376276324 2014-04-02 19:50:00,24.705480388590473 2014-04-02 19:55:00,28.459524573180953 2014-04-02 20:00:00,24.768070801371426 2014-04-02 20:05:00,24.456028241161906 2014-04-02 20:10:00,24.51829936865238 2014-04-02 20:15:00,23.264633523842857 2014-04-02 20:20:00,25.334144454033332 2014-04-02 20:25:00,22.74503501892381 2014-04-02 20:30:00,24.753547965214285 2014-04-02 20:35:00,24.750523503504763 2014-04-02 20:40:00,26.164610757195234 2014-04-02 20:45:00,24.582780257385714 2014-04-02 20:50:00,22.99638476527619 2014-04-02 20:55:00,24.788413767166666 2014-04-02 21:00:00,22.471321165957143 2014-04-02 21:05:00,22.93078575564762 2014-04-02 21:10:00,22.244169672238094 2014-04-02 21:15:00,24.18960808872857 2014-04-02 21:20:00,22.473772489919046 2014-04-02 21:25:00,24.028049361109524 2014-04-02 21:30:00,25.898592632600003 2014-04-02 21:35:00,25.04920549609048 2014-04-02 21:40:00,22.47491390838095 2014-04-02 21:45:00,23.072365459371426 2014-04-02 21:50:00,24.886245851961906 2014-04-02 21:55:00,25.782088047752378 2014-04-02 22:00:00,22.25622360264286 2014-04-02 22:05:00,25.384787662133334 2014-04-02 22:10:00,24.388716686223813 2014-04-02 22:15:00,24.333206567714285 2014-04-02 22:20:00,25.989115484804763 2014-04-02 22:25:00,25.155074633495236 2014-04-02 22:30:00,25.572805632485714 2014-04-02 22:35:00,23.59384780207619 2014-04-02 22:40:00,24.403531577966667 2014-04-02 22:45:00,24.65537300035714 2014-04-02 22:50:00,23.486398253347616 2014-04-02 22:55:00,24.489450337838093 2014-04-02 23:00:00,23.14668783882857 2014-04-02 23:05:00,22.780937842619046 2014-04-02 23:10:00,23.71093376820952 2014-04-02 23:15:00,25.1799322874 2014-04-02 23:20:00,25.89509869809048 2014-04-02 23:25:00,24.06829468078095 2014-04-02 23:30:00,24.816315868271428 2014-04-02 23:35:00,22.664195559361904 2014-04-02 23:40:00,25.87795804125238 2014-04-02 23:45:00,24.541702397442858 2014-04-02 23:50:00,25.39624162153333 2014-04-02 23:55:00,25.46010474192381 2014-04-03 00:00:00,23.311636391214286 2014-04-03 00:05:00,24.409852574604763 2014-04-03 00:10:00,26.142514244295235 2014-04-03 00:15:00,22.666573893585717 2014-04-03 00:20:00,25.04767578257619 2014-04-03 00:25:00,26.171972978766668 2014-04-03 00:30:00,23.53266557505714 2014-04-03 00:35:00,25.78358930464762 2014-04-03 00:40:00,26.079868276838095 2014-04-03 00:45:00,25.341023409028573 2014-04-03 00:50:00,23.28543229681905 2014-04-03 00:55:00,23.703562399109522 2014-04-03 01:00:00,22.5182371777 2014-04-03 01:05:00,25.708253413190477 2014-04-03 01:10:00,25.78832569838095 2014-04-03 01:15:00,24.928162668471426 2014-04-03 01:20:00,23.814873309861905 2014-04-03 01:25:00,22.71944649155238 2014-04-03 01:30:00,25.43187329684286 2014-04-03 01:35:00,25.33318810773333 2014-04-03 01:40:00,26.084933896523808 2014-04-03 01:45:00,25.364092369714285 2014-04-03 01:50:00,25.764184530904764 2014-04-03 01:55:00,25.440663709695237 2014-04-03 02:00:00,24.987034467485714 2014-04-03 02:05:00,24.17959176727619 2014-04-03 02:10:00,26.087635901266665 2014-04-03 02:15:00,25.090481430457142 2014-04-03 02:20:00,24.08746890694762 2014-04-03 02:25:00,22.835365275938095 2014-04-03 02:30:00,23.671747995028568 2014-04-03 02:35:00,24.69127598691905 2014-04-03 02:40:00,23.626351003909527 2014-04-03 02:45:00,23.4161913917 2014-04-03 02:50:00,24.648264532590474 2014-04-03 02:55:00,23.225412335980952 2014-04-03 03:00:00,25.755211681871426 2014-04-03 03:05:00,24.498484510161905 2014-04-03 03:10:00,24.86390347685238 2014-04-03 03:15:00,23.165425927542856 2014-04-03 03:20:00,23.881638675833333 2014-04-03 03:25:00,24.23113254252381 2014-04-03 03:30:00,25.831065607814285 2014-04-03 03:35:00,25.686292854204762 2014-04-03 03:40:00,23.50500513729524 2014-04-03 03:45:00,25.085252040685717 2014-04-03 03:50:00,23.60180162157619 2014-04-03 03:55:00,26.58840528946667 2014-04-03 04:00:00,26.45135265535714 2014-04-03 04:05:00,24.90335650114762 2014-04-03 04:10:00,25.453348382838094 2014-04-03 04:15:00,25.870900100228575 2014-04-03 04:20:00,25.556612727819047 2014-04-03 04:25:00,25.479374288109526 2014-04-03 04:30:00,26.521716031799997 2014-04-03 04:35:00,25.080764901390474 2014-04-03 04:40:00,25.24759163968095 2014-04-03 04:45:00,26.106896430371428 2014-04-03 04:50:00,25.396825376161907 2014-04-03 04:55:00,25.656432869052377 2014-04-03 05:00:00,23.66881760194286 2014-04-03 05:05:00,24.224651029833332 2014-04-03 05:10:00,23.33622919232381 2014-04-03 05:15:00,24.777526055014285 2014-04-03 05:20:00,24.584814364604764 2014-04-03 05:25:00,26.757996495195236 2014-04-03 05:30:00,25.221620325585718 2014-04-03 05:35:00,25.93000548327619 2014-04-03 05:40:00,24.12772534966667 2014-04-03 05:45:00,26.125288468257143 2014-04-03 05:50:00,25.26688748504762 2014-04-03 05:55:00,25.601957421638097 2014-04-03 06:00:00,23.999151683228575 2014-04-03 06:05:00,25.023422614419047 2014-04-03 06:10:00,25.372457417509523 2014-04-03 06:15:00,25.2001287033 2014-04-03 06:20:00,26.51196532189048 2014-04-03 06:25:00,26.451721610380954 2014-04-03 06:30:00,26.75000766007143 2014-04-03 06:35:00,25.543223928761908 2014-04-03 06:40:00,26.76860890145238 2014-04-03 06:45:00,26.218304857242856 2014-04-03 06:50:00,23.979161894733334 2014-04-03 06:55:00,24.613016487723808 2014-04-03 07:00:00,23.864284054514286 2014-04-03 07:05:00,22.934943405204763 2014-04-03 07:10:00,23.67779025069524 2014-04-03 07:15:00,22.949278059385716 2014-04-03 07:20:00,25.81983003587619 2014-04-03 07:25:00,24.650053857566668 2014-04-03 07:30:00,24.205656051157142 2014-04-03 07:35:00,26.00968118344762 2014-04-03 07:40:00,26.300185193738095 2014-04-03 07:45:00,26.878876726028572 2014-04-03 07:50:00,25.553173386319045 2014-04-03 07:55:00,24.838675358009525 2014-04-03 08:00:00,24.2210572064 2014-04-03 08:05:00,23.89671331309048 2014-04-03 08:10:00,23.866584754280954 2014-04-03 08:15:00,24.659078927471427 2014-04-03 08:20:00,26.996907325961903 2014-04-03 08:25:00,23.04061717065238 2014-04-03 08:30:00,23.83346644604286 2014-04-03 08:35:00,23.805655262933332 2014-04-03 08:40:00,25.92800175162381 2014-04-03 08:45:00,24.476903196114286 2014-04-03 08:50:00,24.90344798030476 2014-04-03 08:55:00,23.67634175999524 2014-04-03 09:00:00,71.79724544298571 2014-04-03 09:05:00,67.70024363237619 2014-04-03 09:10:00,73.55355538196667 2014-04-03 09:15:00,67.64356891205715 2014-04-03 09:20:00,77.06996160304762 2014-04-03 09:25:00,74.03227145383809 2014-04-03 09:30:00,76.17989165472856 2014-04-03 09:35:00,72.03319190611906 2014-04-03 09:40:00,71.53709111190952 2014-04-03 09:45:00,67.6918908911 2014-04-03 09:50:00,73.48812673199048 2014-04-03 09:55:00,73.36836039448094 2014-04-03 10:00:00,82.28351515847143 2014-04-03 10:05:00,86.51885692466189 2014-04-03 10:10:00,87.95392066945239 2014-04-03 10:15:00,86.69314861234287 2014-04-03 10:20:00,77.28112966173333 2014-04-03 10:25:00,84.71013739362381 2014-04-03 10:30:00,76.30982888601429 2014-04-03 10:35:00,85.85119266300475 2014-04-03 10:40:00,81.00423801669524 2014-04-03 10:45:00,77.14191951558571 2014-04-03 10:50:00,88.47200549077618 2014-04-03 10:55:00,84.62982608856667 2014-04-03 11:00:00,82.47740303305714 2014-04-03 11:05:00,77.33198268424762 2014-04-03 11:10:00,85.39612045443809 2014-04-03 11:15:00,91.54116294282856 2014-04-03 11:20:00,86.35044390691905 2014-04-03 11:25:00,92.32619073970952 2014-04-03 11:30:00,79.050618585 2014-04-03 11:35:00,85.92626485969049 2014-04-03 11:40:00,89.58876171588095 2014-04-03 11:45:00,85.26102121637143 2014-04-03 11:50:00,78.3585812303619 2014-04-03 11:55:00,86.18792134955238 2014-04-03 12:00:00,87.04680398284286 2014-04-03 12:05:00,88.92354009133334 2014-04-03 12:10:00,89.4503927911238 2014-04-03 12:15:00,89.6106284615143 2014-04-03 12:20:00,87.90287692780475 2014-04-03 12:25:00,80.75678064599524 2014-04-03 12:30:00,83.77539648118571 2014-04-03 12:35:00,89.72600405687619 2014-04-03 12:40:00,92.56679260296666 2014-04-03 12:45:00,78.59934279855713 2014-04-03 12:50:00,85.90345215954763 2014-04-03 12:55:00,82.34694400883808 2014-04-03 13:00:00,81.03458536792857 2014-04-03 13:05:00,85.52761767091906 2014-04-03 13:10:00,87.13913158960952 2014-04-03 13:15:00,77.6077881773 2014-04-03 13:20:00,89.93921963819048 2014-04-03 13:25:00,90.58131670518095 2014-04-03 13:30:00,92.91825706007143 2014-04-03 13:35:00,80.3708379644619 2014-04-03 13:40:00,86.99923029685237 2014-04-03 13:45:00,84.32048059134286 2014-04-03 13:50:00,82.85951321923334 2014-04-03 13:55:00,86.55895700002381 2014-04-03 14:00:00,90.0497869071143 2014-04-03 14:05:00,77.90852559250476 2014-04-03 14:10:00,93.05679653989525 2014-04-03 14:15:00,90.5120630964857 2014-04-03 14:20:00,89.57990256277618 2014-04-03 14:25:00,89.73507480406667 2014-04-03 14:30:00,83.80157369815714 2014-04-03 14:35:00,89.60969318794763 2014-04-03 14:40:00,83.7798083933381 2014-04-03 14:45:00,91.97784163782856 2014-04-03 14:50:00,80.44208507371904 2014-04-03 14:55:00,82.29143778840952 2014-04-03 15:00:00,86.4456247977 2014-04-03 15:05:00,82.73907681959048 2014-04-03 15:10:00,84.42692051428095 2014-04-03 15:15:00,85.52531762287143 2014-04-03 15:20:00,91.3555927498619 2014-04-03 15:25:00,86.03250687635239 2014-04-03 15:30:00,83.46825356114286 2014-04-03 15:35:00,81.64013270563332 2014-04-03 15:40:00,84.22258549752381 2014-04-03 15:45:00,85.94297153931429 2014-04-03 15:50:00,89.63643667390475 2014-04-03 15:55:00,79.64291586379524 2014-04-03 16:00:00,81.25988767828571 2014-04-03 16:05:00,83.79604054137619 2014-04-03 16:10:00,83.49539183716668 2014-04-03 16:15:00,84.00442627005714 2014-04-03 16:20:00,90.44022523634762 2014-04-03 16:25:00,82.93781034463808 2014-04-03 16:30:00,85.78914579952857 2014-04-03 16:35:00,87.74872416691906 2014-04-03 16:40:00,81.48852095420952 2014-04-03 16:45:00,89.280215876 2014-04-03 16:50:00,86.54231654479048 2014-04-03 16:55:00,84.94447759578095 2014-04-03 17:00:00,90.76008323307143 2014-04-03 17:05:00,81.7069069076619 2014-04-03 17:10:00,91.94923483655238 2014-04-03 17:15:00,86.80264152794284 2014-04-03 17:20:00,87.58010001263334 2014-04-03 17:25:00,91.8416842118238 2014-04-03 17:30:00,90.92950462011429 2014-04-03 17:35:00,87.48061651910476 2014-04-03 17:40:00,89.91406622409525 2014-04-03 17:45:00,84.80361724768571 2014-04-03 17:50:00,86.63598923537619 2014-04-03 17:55:00,78.87851082466668 2014-04-03 18:00:00,35.26794217805714 2014-04-03 18:05:00,40.008613657047626 2014-04-03 18:10:00,35.0896310886381 2014-04-03 18:15:00,35.79932723772857 2014-04-03 18:20:00,39.81594155741905 2014-04-03 18:25:00,34.73738807680952 2014-04-03 18:30:00,36.544881828 2014-04-03 18:35:00,38.482781638990474 2014-04-03 18:40:00,38.56325425248095 2014-04-03 18:45:00,39.73359355667143 2014-04-03 18:50:00,38.0051837822619 2014-04-03 18:55:00,38.03486819035238 2014-04-03 19:00:00,29.391532951442855 2014-04-03 19:05:00,28.38341970033333 2014-04-03 19:10:00,28.88306262182381 2014-04-03 19:15:00,30.186490784914284 2014-04-03 19:20:00,27.97040407140476 2014-04-03 19:25:00,27.90470435519524 2014-04-03 19:30:00,26.202684091085715 2014-04-03 19:35:00,28.942374585376186 2014-04-03 19:40:00,26.335043698566665 2014-04-03 19:45:00,28.467691147057142 2014-04-03 19:50:00,29.819513690347627 2014-04-03 19:55:00,28.68763325013809 2014-04-03 20:00:00,25.60785806972857 2014-04-03 20:05:00,27.731014642019048 2014-04-03 20:10:00,25.623070138109526 2014-04-03 20:15:00,86.09375 2014-04-03 20:20:00,27.03280885749048 2014-04-03 20:25:00,25.236935554280954 2014-04-03 20:30:00,28.255499514271428 2014-04-03 20:35:00,25.377348199061906 2014-04-03 20:40:00,28.61630076685238 2014-04-03 20:45:00,24.600336397142858 2014-04-03 20:50:00,25.65706101193333 2014-04-03 20:55:00,25.40390135612381 2014-04-03 21:00:00,24.303356555514284 2014-04-03 21:05:00,27.198087774704764 2014-04-03 21:10:00,27.049012170795237 2014-04-03 21:15:00,27.454052658185716 2014-04-03 21:20:00,25.308598941676188 2014-04-03 21:25:00,26.070188521566664 2014-04-03 21:30:00,26.94086615825714 2014-04-03 21:35:00,26.066715141347622 2014-04-03 21:40:00,27.109329780238095 2014-04-03 21:45:00,26.862144444128567 2014-04-03 21:50:00,24.782311452119046 2014-04-03 21:55:00,27.468127984109522 2014-04-03 22:00:00,27.1527528233 2014-04-03 22:05:00,26.900576420590475 2014-04-03 22:10:00,24.903130927780953 2014-04-03 22:15:00,25.362616320771426 2014-04-03 22:20:00,25.871259821261905 2014-04-03 22:25:00,25.42527578795238 2014-04-03 22:30:00,25.22403880204286 2014-04-03 22:35:00,27.54388657703333 2014-04-03 22:40:00,26.88218359672381 2014-04-03 22:45:00,26.598304214914286 2014-04-03 22:50:00,25.246363254404763 2014-04-03 22:55:00,28.024956890495236 2014-04-03 23:00:00,25.107620697385713 2014-04-03 23:05:00,27.53059644197619 2014-04-03 23:10:00,28.225055735966663 2014-04-03 23:15:00,27.273992464957143 2014-04-03 23:20:00,28.344701233147617 2014-04-03 23:25:00,26.984648568338095 2014-04-03 23:30:00,25.257392953528573 2014-04-03 23:35:00,25.21025955401905 2014-04-03 23:40:00,25.70077192430952 2014-04-03 23:45:00,24.438231555 2014-04-03 23:50:00,27.14446389889048 2014-04-03 23:55:00,25.49946442588095 2014-04-04 00:00:00,27.689304357771427 2014-04-04 00:05:00,25.872702506961904 2014-04-04 00:10:00,26.36327835485238 2014-04-04 00:15:00,28.313648523342856 2014-04-04 00:20:00,25.427021825533334 2014-04-04 00:25:00,27.35079019922381 2014-04-04 00:30:00,27.493685442914284 2014-04-04 00:35:00,25.364647392004763 2014-04-04 00:40:00,26.49208258449524 2014-04-04 00:45:00,25.89634341558571 2014-04-04 00:50:00,27.59060116407619 2014-04-04 00:55:00,27.000349942766668 2014-04-04 01:00:00,26.421789362257144 2014-04-04 01:05:00,27.64275067924762 2014-04-04 01:10:00,25.473360375238094 2014-04-04 01:15:00,27.55466609372857 2014-04-04 01:20:00,28.009116296019048 2014-04-04 01:25:00,28.06954591100952 2014-04-04 01:30:00,27.6971943721 2014-04-04 01:35:00,26.201997144190475 2014-04-04 01:40:00,28.504613043280955 2014-04-04 01:45:00,26.103196003871428 2014-04-04 01:50:00,27.146763501161907 2014-04-04 01:55:00,25.24399909325238 2014-04-04 02:00:00,28.528938451642855 2014-04-04 02:05:00,27.43052702083333 2014-04-04 02:10:00,27.635533990523808 2014-04-04 02:15:00,24.892571099314285 2014-04-04 02:20:00,27.690576018804762 2014-04-04 02:25:00,27.74323895499524 2014-04-04 02:30:00,27.338876619685713 2014-04-04 02:35:00,25.82686464567619 2014-04-04 02:40:00,26.625426835266666 2014-04-04 02:45:00,25.115844628057143 2014-04-04 02:50:00,26.567895884847616 2014-04-04 02:55:00,25.664283505638096 2014-04-04 03:00:00,26.092816517428567 2014-04-04 03:05:00,25.354270681219045 2014-04-04 03:10:00,25.63152699480952 2014-04-04 03:15:00,25.0250245673 2014-04-04 03:20:00,28.405795941890478 2014-04-04 03:25:00,26.855273704280954 2014-04-04 03:30:00,26.328039313671425 2014-04-04 03:35:00,26.888628755861905 2014-04-04 03:40:00,27.26912529485238 2014-04-04 03:45:00,28.450908030642857 2014-04-04 03:50:00,25.485605142433332 2014-04-04 03:55:00,25.96048380402381 2014-04-04 04:00:00,28.688871631114285 2014-04-04 04:05:00,26.277926708504765 2014-04-04 04:10:00,24.890841841095238 2014-04-04 04:15:00,25.39860968478571 2014-04-04 04:20:00,24.92083099747619 2014-04-04 04:25:00,28.782609236366667 2014-04-04 04:30:00,25.94584053885714 2014-04-04 04:35:00,28.53196864674762 2014-04-04 04:40:00,28.828783198238096 2014-04-04 04:45:00,27.252043456028574 2014-04-04 04:50:00,24.992904307919048 2014-04-04 04:55:00,25.193926045309524 2014-04-04 05:00:00,26.8013562204 2014-04-04 05:05:00,26.507128527790474 2014-04-04 05:10:00,27.31459017548095 2014-04-04 05:15:00,26.65271266737143 2014-04-04 05:20:00,28.641069301861904 2014-04-04 05:25:00,27.05116124265238 2014-04-04 05:30:00,27.694547102942856 2014-04-04 05:35:00,28.51302442393333 2014-04-04 05:40:00,25.52201131282381 2014-04-04 05:45:00,25.860902902214285 2014-04-04 05:50:00,25.378679403804764 2014-04-04 05:55:00,25.51539883499524 2014-04-04 06:00:00,27.014621581985715 2014-04-04 06:05:00,26.256443226376188 2014-04-04 06:10:00,26.671858024766664 2014-04-04 06:15:00,28.91656647005714 2014-04-04 06:20:00,25.62086501024762 2014-04-04 06:25:00,27.164736378438093 2014-04-04 06:30:00,25.40441319162857 2014-04-04 06:35:00,26.29035430071905 2014-04-04 06:40:00,27.133913218509527 2014-04-04 06:45:00,28.8177769839 2014-04-04 06:50:00,26.603603361290475 2014-04-04 06:55:00,25.305757737280953 2014-04-04 07:00:00,26.606217220371427 2014-04-04 07:05:00,25.643976608261905 2014-04-04 07:10:00,25.98841083415238 2014-04-04 07:15:00,27.548255349842858 2014-04-04 07:20:00,25.353028798133334 2014-04-04 07:25:00,26.94966883452381 2014-04-04 07:30:00,27.536060629714285 2014-04-04 07:35:00,26.793088331404764 2014-04-04 07:40:00,25.189600640595238 2014-04-04 07:45:00,29.062613141885713 2014-04-04 07:50:00,26.596439259876192 2014-04-04 07:55:00,28.249725414366665 2014-04-04 08:00:00,26.44544311155714 2014-04-04 08:05:00,27.050364647047616 2014-04-04 08:10:00,26.711592665638094 2014-04-04 08:15:00,26.53533548942857 2014-04-04 08:20:00,25.260024556419047 2014-04-04 08:25:00,26.62014327520952 2014-04-04 08:30:00,28.745459961599998 2014-04-04 08:35:00,27.956513830590474 2014-04-04 08:40:00,25.784072388780952 2014-04-04 08:45:00,27.574441447071425 2014-04-04 08:50:00,28.786185344561904 2014-04-04 08:55:00,28.02483854485238 2014-04-04 09:00:00,70.45425059324286 2014-04-04 09:05:00,80.24210528893333 2014-04-04 09:10:00,72.5480223902238 2014-04-04 09:15:00,74.6298998483143 2014-04-04 09:20:00,75.61744629370476 2014-04-04 09:25:00,80.03623505759523 2014-04-04 09:30:00,81.14664764828571 2014-04-04 09:35:00,81.12750532847619 2014-04-04 09:40:00,68.59984353206667 2014-04-04 09:45:00,81.03679054685713 2014-04-04 09:50:00,69.24621035664762 2014-04-04 09:55:00,72.1285098279381 2014-04-04 10:00:00,85.15404007682857 2014-04-04 10:05:00,84.61731574091905 2014-04-04 10:10:00,86.56140552490952 2014-04-04 10:15:00,84.62475547 2014-04-04 10:20:00,91.69270102419048 2014-04-04 10:25:00,80.93194907668095 2014-04-04 10:30:00,81.45893468007142 2014-04-04 10:35:00,91.5033646667619 2014-04-04 10:40:00,78.41194963425238 2014-04-04 10:45:00,86.68877681314287 2014-04-04 10:50:00,87.81637530943333 2014-04-04 10:55:00,85.08928135712381 2014-04-04 11:00:00,90.0197780865143 2014-04-04 11:05:00,81.73364465210476 2014-04-04 11:10:00,92.55385826809524 2014-04-04 11:15:00,81.2280042795857 2014-04-04 11:20:00,85.38299730487618 2014-04-04 11:25:00,80.21281355786667 2014-04-04 11:30:00,87.69439414035713 2014-04-04 11:35:00,89.68243494034762 2014-04-04 11:40:00,94.00742697983807 2014-04-04 11:45:00,90.80408143092856 2014-04-04 11:50:00,87.65881983091903 2014-04-04 11:55:00,93.89290056490952 2014-04-04 12:00:00,87.0594034214 2014-04-04 12:05:00,88.38955577719048 2014-04-04 12:10:00,88.95461230338096 2014-04-04 12:15:00,85.98772543197143 2014-04-04 12:20:00,92.8429860861619 2014-04-04 12:25:00,82.41006202445239 2014-04-04 12:30:00,88.32506493304287 2014-04-04 12:35:00,91.00754855383333 2014-04-04 12:40:00,93.91938621702381 2014-04-04 12:45:00,93.60628739541428 2014-04-04 12:50:00,87.61808157920476 2014-04-04 12:55:00,89.77367975689526 2014-04-04 13:00:00,85.87829561948571 2014-04-04 13:05:00,87.06849259397619 2014-04-04 13:10:00,94.08365928716667 2014-04-04 13:15:00,94.48201713055714 2014-04-04 13:20:00,93.92495415814761 2014-04-04 13:25:00,81.8226105401381 2014-04-04 13:30:00,93.21472859002857 2014-04-04 13:35:00,94.79426702721904 2014-04-04 13:40:00,85.41013743820952 2014-04-04 13:45:00,87.935319029 2014-04-04 13:50:00,92.10894284339048 2014-04-04 13:55:00,88.64494277338095 2014-04-04 14:00:00,95.57008878057144 2014-04-04 14:05:00,86.9736197593619 2014-04-04 14:10:00,91.11253145225238 2014-04-04 14:15:00,92.37828639024286 2014-04-04 14:20:00,87.61010451633334 2014-04-04 14:25:00,93.4234005373238 2014-04-04 14:30:00,88.4578122983143 2014-04-04 14:35:00,86.31329536290477 2014-04-04 14:40:00,81.45973521109524 2014-04-04 14:45:00,86.03639479428571 2014-04-04 14:50:00,91.49193980297619 2014-04-04 14:55:00,94.49683570556667 2014-04-04 15:00:00,83.79399774665714 2014-04-04 15:05:00,85.45832013214762 2014-04-04 15:10:00,82.24539915253808 2014-04-04 15:15:00,90.84094758402857 2014-04-04 15:20:00,95.15979524281906 2014-04-04 15:25:00,90.05950539110951 2014-04-04 15:30:00,89.6849384971 2014-04-04 15:35:00,88.67500314819048 2014-04-04 15:40:00,81.24196801658096 2014-04-04 15:45:00,91.50607939967142 2014-04-04 15:50:00,89.47427092676189 2014-04-04 15:55:00,90.43253787985239 2014-04-04 16:00:00,94.23795449414287 2014-04-04 16:05:00,92.40779360303333 2014-04-04 16:10:00,92.3665056143238 2014-04-04 16:15:00,94.71423786471429 2014-04-04 16:20:00,95.72569533450476 2014-04-04 16:25:00,89.19471285249524 2014-04-04 16:30:00,81.6437499859857 2014-04-04 16:35:00,87.2551523703762 2014-04-04 16:40:00,92.51812257496667 2014-04-04 16:45:00,80.36757324735714 2014-04-04 16:50:00,80.84160664514762 2014-04-04 16:55:00,81.01337231023808 2014-04-04 17:00:00,91.64296856522857 2014-04-04 17:05:00,87.97250437741904 2014-04-04 17:10:00,85.86364670560953 2014-04-04 17:15:00,81.6585944273 2014-04-04 17:20:00,91.69200233259049 2014-04-04 17:25:00,85.11991830088095 2014-04-04 17:30:00,84.23622727147144 2014-04-04 17:35:00,90.4355874737619 2014-04-04 17:40:00,88.95009557995238 2014-04-04 17:45:00,85.81193325154285 2014-04-04 17:50:00,90.28460127693333 2014-04-04 17:55:00,84.36778882132381 2014-04-04 18:00:00,41.922621453714285 2014-04-04 18:05:00,38.31079023250476 2014-04-04 18:10:00,37.86715076379524 2014-04-04 18:15:00,41.865641443985716 2014-04-04 18:20:00,41.39597878747619 2014-04-04 18:25:00,38.041800357166665 2014-04-04 18:30:00,37.624324287657146 2014-04-04 18:35:00,42.25354522554762 2014-04-04 18:40:00,41.865461897438095 2014-04-04 18:45:00,38.99711983132857 2014-04-04 18:50:00,41.12257612181905 2014-04-04 18:55:00,37.71217903550952 2014-04-04 19:00:00,30.556572281999998 2014-04-04 19:05:00,28.37635107409048 2014-04-04 19:10:00,30.054256176780953 2014-04-04 19:15:00,28.642616144471425 2014-04-04 19:20:00,30.443420049161904 2014-04-04 19:25:00,30.211334949252382 2014-04-04 19:30:00,30.320486561342854 2014-04-04 19:35:00,28.540166449433332 2014-04-04 19:40:00,29.964563823723807 2014-04-04 19:45:00,31.741010637814284 2014-04-04 19:50:00,30.012139957904758 2014-04-04 19:55:00,31.570814304095236 2014-04-04 20:00:00,28.15967032698571 2014-04-04 20:05:00,28.38731470087619 2014-04-04 20:10:00,28.97086851186667 2014-04-04 20:15:00,30.562600088057142 2014-04-04 20:20:00,27.121939781947617 2014-04-04 20:25:00,26.818302668838093 2014-04-04 20:30:00,29.18112094522857 2014-04-04 20:35:00,30.585870456019048 2014-04-04 20:40:00,30.759715204909526 2014-04-04 20:45:00,28.696386512300002 2014-04-04 20:50:00,28.637952551990473 2014-04-04 20:55:00,29.369902304480952 2014-04-04 21:00:00,28.62317859507143 2014-04-04 21:05:00,28.945938575461906 2014-04-04 21:10:00,29.91763081925238 2014-04-04 21:15:00,29.41184656194286 2014-04-04 21:20:00,28.416782896833332 2014-04-04 21:25:00,28.28349939432381 2014-04-04 21:30:00,29.005301582814287 2014-04-04 21:35:00,28.273629411504764 2014-04-04 21:40:00,28.28940195799524 2014-04-04 21:45:00,26.522472350385712 2014-04-04 21:50:00,27.16397472557619 2014-04-04 21:55:00,28.435250639466666 2014-04-04 22:00:00,29.703909957857142 2014-04-04 22:05:00,27.533555948247617 2014-04-04 22:10:00,28.517598768638095 2014-04-04 22:15:00,27.81363155532857 2014-04-04 22:20:00,26.859517444019048 2014-04-04 22:25:00,30.284213311509525 2014-04-04 22:30:00,29.8767574181 2014-04-04 22:35:00,26.776491575990477 2014-04-04 22:40:00,29.351573975080953 2014-04-04 22:45:00,27.86875574327143 2014-04-04 22:50:00,30.467761345461906 2014-04-04 22:55:00,27.70273766115238 2014-04-04 23:00:00,27.440735987842857 2014-04-04 23:05:00,28.76503766453333 2014-04-04 23:10:00,29.84162583772381 2014-04-04 23:15:00,27.278143625614284 2014-04-04 23:20:00,29.35351666010476 2014-04-04 23:25:00,26.768474729095235 2014-04-04 23:30:00,30.20668642648571 2014-04-04 23:35:00,26.86204411877619 2014-04-04 23:40:00,30.202750299566667 2014-04-04 23:45:00,28.516169078657143 2014-04-04 23:50:00,28.352712202247616 2014-04-04 23:55:00,30.461419910938098 2014-04-05 00:00:00,30.532965282228574 2014-04-05 00:05:00,29.179581551419048 2014-04-05 00:10:00,27.09478669120952 2014-04-05 00:15:00,28.6184303426 2014-04-05 00:20:00,28.717842879990478 2014-04-05 00:25:00,28.666416664880952 2014-04-05 00:30:00,28.89403878267143 2014-04-05 00:35:00,26.698410759961906 2014-04-05 00:40:00,29.47586150685238 2014-04-05 00:45:00,29.487970064942857 2014-04-05 00:50:00,27.10771243403333 2014-04-05 00:55:00,28.934231579323807 2014-04-05 01:00:00,28.934159015414284 2014-04-05 01:05:00,29.39795644270476 2014-04-05 01:10:00,27.017186006595235 2014-04-05 01:15:00,29.189048943385714 2014-04-05 01:20:00,27.81348399347619 2014-04-05 01:25:00,28.725928628666665 2014-04-05 01:30:00,29.798651353657142 2014-04-05 01:35:00,29.535381364547618 2014-04-05 01:40:00,27.195850165938094 2014-04-05 01:45:00,29.09241771992857 2014-04-05 01:50:00,30.611585171419048 2014-04-05 01:55:00,27.369637273109525 2014-04-05 02:00:00,30.1616283509 2014-04-05 02:05:00,29.567632798390477 2014-04-05 02:10:00,29.860894203980955 2014-04-05 02:15:00,27.900154737171427 2014-04-05 02:20:00,27.931317622261904 2014-04-05 02:25:00,30.411280204052378 2014-04-05 02:30:00,28.233970985542854 2014-04-05 02:35:00,27.05414489613333 2014-04-05 02:40:00,29.21191062382381 2014-04-05 02:45:00,27.316234961914283 2014-04-05 02:50:00,30.010789727504758 2014-04-05 02:55:00,29.398831008095236 2014-04-05 03:00:00,30.338191735185717 2014-04-05 03:05:00,29.98607518957619 2014-04-05 03:10:00,27.302621260066665 2014-04-05 03:15:00,28.38588984855714 2014-04-05 03:20:00,29.967288618747617 2014-04-05 03:25:00,28.545853988338095 2014-04-05 03:30:00,30.77339051052857 2014-04-05 03:35:00,29.834330847219046 2014-04-05 03:40:00,26.960809190609524 2014-04-05 03:45:00,30.4261927662 2014-04-05 03:50:00,27.316909615690477 2014-04-05 03:55:00,27.483225849080952 2014-04-05 04:00:00,29.866541030971426 2014-04-05 04:05:00,30.395886142461904 2014-04-05 04:10:00,29.08885089255238 2014-04-05 04:15:00,28.10709178894286 2014-04-05 04:20:00,28.36359551433333 2014-04-05 04:25:00,28.33733112792381 2014-04-05 04:30:00,28.279926700914285 2014-04-05 04:35:00,27.95229344920476 2014-04-05 04:40:00,29.423563616595235 2014-04-05 04:45:00,30.59715698858571 2014-04-05 04:50:00,28.23130584277619 2014-04-05 04:55:00,27.757193856466664 2014-04-05 05:00:00,30.37216780835714 2014-04-05 05:05:00,29.992430942647616 2014-04-05 05:10:00,30.756086221438093 2014-04-05 05:15:00,27.70225751382857 2014-04-05 05:20:00,27.62462430411905 2014-04-05 05:25:00,29.220777101009524 2014-04-05 05:30:00,29.520234619300002 2014-04-05 05:35:00,28.990634243590478 2014-04-05 05:40:00,29.47324749768095 2014-04-05 05:45:00,27.80634050407143 2014-04-05 05:50:00,29.010716921461906 2014-04-05 05:55:00,29.73207262475238 2014-04-05 06:00:00,28.837968654142855 2014-04-05 06:05:00,29.83237267663333 2014-04-05 06:10:00,28.926788931723806 2014-04-05 06:15:00,28.463862609114283 2014-04-05 06:20:00,28.351324950204763 2014-04-05 06:25:00,28.787953474095236 2014-04-05 06:30:00,27.244144204985716 2014-04-05 06:35:00,29.833326744276192 2014-04-05 06:40:00,30.54708923056667 2014-04-05 06:45:00,28.59261552065714 2014-04-05 06:50:00,27.365680163647617 2014-04-05 06:55:00,31.136090484738094 2014-04-05 07:00:00,28.25122159322857 2014-04-05 07:05:00,27.71035353441905 2014-04-05 07:10:00,28.69031955570952 2014-04-05 07:15:00,30.1729781625 2014-04-05 07:20:00,28.401856863790478 2014-04-05 07:25:00,29.532443768080952 2014-04-05 07:30:00,28.903311406271428 2014-04-05 07:35:00,27.719567873861905 2014-04-05 07:40:00,28.57710043095238 2014-04-05 07:45:00,30.162874880042857 2014-04-05 07:50:00,29.718848922633335 2014-04-05 07:55:00,27.757387329023807 2014-04-05 08:00:00,27.939003924614287 2014-04-05 08:05:00,29.85608819910476 2014-04-05 08:10:00,30.554256895395238 2014-04-05 08:15:00,28.705933698085715 2014-04-05 08:20:00,29.696719197876188 2014-04-05 08:25:00,28.005491021666664 2014-04-05 08:30:00,28.57586249045714 2014-04-05 08:35:00,27.418878441747616 2014-04-05 08:40:00,30.418341886438093 2014-04-05 08:45:00,28.95671785052857 2014-04-05 08:50:00,30.624621342219047 2014-04-05 08:55:00,30.201051507909526 2014-04-05 09:00:00,81.84592201390001 2014-04-05 09:05:00,74.46739838249049 2014-04-05 09:10:00,73.10735968618096 2014-04-05 09:15:00,83.81523871267143 2014-04-05 09:20:00,80.36041980856191 2014-04-05 09:25:00,81.95517722475238 2014-04-05 09:30:00,70.79825673964285 2014-04-05 09:35:00,75.44776136933334 2014-04-05 09:40:00,80.7368308014238 2014-04-05 09:45:00,71.70253081441427 2014-04-05 09:50:00,78.36522780400476 2014-04-05 09:55:00,76.49223487549524 2014-04-05 10:00:00,79.57769390508571 2014-04-05 10:05:00,82.97406714737619 2014-04-05 10:10:00,83.73913833696668 2014-04-05 10:15:00,81.06267351015714 2014-04-05 10:20:00,89.13550045824762 2014-04-05 10:25:00,83.10350313463809 2014-04-05 10:30:00,83.65758320552857 2014-04-05 10:35:00,93.29703209171905 2014-04-05 10:40:00,86.61355992240952 2014-04-05 10:45:00,85.457078841 2014-04-05 10:50:00,90.61316899079048 2014-04-05 10:55:00,93.50333707998095 2014-04-05 11:00:00,81.51974932007143 2014-04-05 11:05:00,88.2578025203619 2014-04-05 11:10:00,90.85031906805239 2014-04-05 11:15:00,86.21032036974286 2014-04-05 11:20:00,93.43570574593333 2014-04-05 11:25:00,96.60914513512381 2014-04-05 11:30:00,96.17048311851428 2014-04-05 11:35:00,85.40384106820476 2014-04-05 11:40:00,84.78077921839524 2014-04-05 11:45:00,96.41646511968571 2014-04-05 11:50:00,88.49000365457618 2014-04-05 11:55:00,84.51618365456667 2014-04-05 12:00:00,92.85483421925714 2014-04-05 12:05:00,86.10916193124763 2014-04-05 12:10:00,85.8421585544381 2014-04-05 12:15:00,95.62988167902857 2014-04-05 12:20:00,84.18276590191905 2014-04-05 12:25:00,82.62271032270952 2014-04-05 12:30:00,85.9029146631 2014-04-05 12:35:00,91.30801372969049 2014-04-05 12:40:00,83.58302332008095 2014-04-05 12:45:00,89.15988156727143 2014-04-05 12:50:00,91.65621079906191 2014-04-05 12:55:00,95.20179851215238 2014-04-05 13:00:00,85.39189361714286 2014-04-05 13:05:00,94.79670589753333 2014-04-05 13:10:00,85.48734194762382 2014-04-05 13:15:00,92.56285016201431 2014-04-05 13:20:00,88.63374811910477 2014-04-05 13:25:00,83.58652474019524 2014-04-05 13:30:00,93.18497834778572 2014-04-05 13:35:00,85.25031187877619 2014-04-05 13:40:00,84.59968324906667 2014-04-05 13:45:00,87.51361804025714 2014-04-05 13:50:00,92.23940290064762 2014-04-05 13:55:00,85.53975320943809 2014-04-05 14:00:00,84.75641613982857 2014-04-05 14:05:00,81.98466341461905 2014-04-05 14:10:00,89.37878085550952 2014-04-05 14:15:00,88.6982939092 2014-04-05 14:20:00,85.58943876399047 2014-04-05 14:25:00,82.71356837168095 2014-04-05 14:30:00,88.73037975357143 2014-04-05 14:35:00,94.4807323403619 2014-04-05 14:40:00,93.32146114555238 2014-04-05 14:45:00,95.65699400444285 2014-04-05 14:50:00,82.04569297723333 2014-04-05 14:55:00,97.3617846683238 2014-04-05 15:00:00,87.37256668681428 2014-04-05 15:05:00,97.76367617430476 2014-04-05 15:10:00,85.96677660539524 2014-04-05 15:15:00,89.47685428758571 2014-04-05 15:20:00,87.60257345237619 2014-04-05 15:25:00,87.63934226176667 2014-04-05 15:30:00,95.43105014825714 2014-04-05 15:35:00,93.90469480484762 2014-04-05 15:40:00,97.8438174644381 2014-04-05 15:45:00,91.79312805902858 2014-04-05 15:50:00,89.39646236171905 2014-04-05 15:55:00,83.43303629560953 2014-04-05 16:00:00,97.94481385790002 2014-04-05 16:05:00,90.83177574009048 2014-04-05 16:10:00,93.22236070878095 2014-04-05 16:15:00,88.53004888847143 2014-04-05 16:20:00,90.79305816976189 2014-04-05 16:25:00,97.1182788952524 2014-04-05 16:30:00,84.70721051164286 2014-04-05 16:35:00,86.72989746093333 2014-04-05 16:40:00,84.4923365427238 2014-04-05 16:45:00,94.74225616971427 2014-04-05 16:50:00,83.06698878260475 2014-04-05 16:55:00,83.38781088799524 2014-04-05 17:00:00,86.86516203698571 2014-04-05 17:05:00,90.32370627807619 2014-04-05 17:10:00,88.60453333146667 2014-04-05 17:15:00,82.82864019025713 2014-04-05 17:20:00,97.43887901414762 2014-04-05 17:25:00,97.37236691853809 2014-04-05 17:30:00,86.60360037892858 2014-04-05 17:35:00,93.84574674941905 2014-04-05 17:40:00,91.40598490320951 2014-04-05 17:45:00,85.95584801300001 2014-04-05 17:50:00,86.35840604529048 2014-04-05 17:55:00,90.02955107568094 2014-04-05 18:00:00,41.66168180937143 2014-04-05 18:05:00,40.849873717961906 2014-04-05 18:10:00,44.16152007545238 2014-04-05 18:15:00,42.082249408842856 2014-04-05 18:20:00,43.19935459833333 2014-04-05 18:25:00,40.22711844842381 2014-04-05 18:30:00,42.437657140614284 2014-04-05 18:35:00,41.06569555800477 2014-04-05 18:40:00,42.40713616819524 2014-04-05 18:45:00,44.04281455908571 2014-04-05 18:50:00,43.97401426057619 2014-04-05 18:55:00,41.32742304126667 2014-04-05 19:00:00,33.538217350857146 2014-04-05 19:05:00,34.65227525954762 2014-04-05 19:10:00,33.245735433638096 2014-04-05 19:15:00,31.11505478182857 2014-04-05 19:20:00,33.50271243381904 2014-04-05 19:25:00,30.935030042909524 2014-04-05 19:30:00,34.3795533111 2014-04-05 19:35:00,32.794578264490475 2014-04-05 19:40:00,32.212810250480956 2014-04-05 19:45:00,30.750209852671432 2014-04-05 19:50:00,32.20817183626191 2014-04-05 19:55:00,34.55606692535238 2014-04-05 20:00:00,28.875088987742856 2014-04-05 20:05:00,30.740741943133333 2014-04-05 20:10:00,32.61804708372381 2014-04-05 20:15:00,30.428732780114284 2014-04-05 20:20:00,30.57271213550476 2014-04-05 20:25:00,31.196126974595238 2014-04-05 20:30:00,30.72997678868571 2014-04-05 20:35:00,29.53181848827619 2014-04-05 20:40:00,28.924669932566665 2014-04-05 20:45:00,31.353895442757143 2014-04-05 20:50:00,32.63517113294762 2014-04-05 20:55:00,29.306655357738094 2014-04-05 21:00:00,29.380689694328574 2014-04-05 21:05:00,30.02829534921905 2014-04-05 21:10:00,31.798206238509522 2014-04-05 21:15:00,29.6373610171 2014-04-05 21:20:00,32.10774348499048 2014-04-05 21:25:00,28.790917597380954 2014-04-05 21:30:00,32.35936422727143 2014-04-05 21:35:00,30.838666510361904 2014-04-05 21:40:00,31.24011157565238 2014-04-05 21:45:00,30.07761053824286 2014-04-05 21:50:00,31.75022471373333 2014-04-05 21:55:00,29.284136836023812 2014-04-05 22:00:00,28.748829399314285 2014-04-05 22:05:00,30.144021309804764 2014-04-05 22:10:00,31.985936274995236 2014-04-05 22:15:00,31.597921969585713 2014-04-05 22:20:00,30.65336594147619 2014-04-05 22:25:00,30.880944654266663 2014-04-05 22:30:00,29.117707227357144 2014-04-05 22:35:00,31.971031860047617 2014-04-05 22:40:00,31.763378741838096 2014-04-05 22:45:00,31.24836098312857 2014-04-05 22:50:00,30.493953356719047 2014-04-05 22:55:00,32.49638010980952 2014-04-05 23:00:00,32.1452589819 2014-04-05 23:05:00,31.214113370890473 2014-04-05 23:10:00,30.130826484480952 2014-04-05 23:15:00,31.123341182371433 2014-04-05 23:20:00,30.960423547561902 2014-04-05 23:25:00,30.24292910825238 2014-04-05 23:30:00,29.900030267642855 2014-04-05 23:35:00,30.308895084633335 2014-04-05 23:40:00,30.98406619562381 2014-04-05 23:45:00,30.408288470214284 2014-04-05 23:50:00,29.75736113800476 2014-04-05 23:55:00,31.75473892689524 2014-04-06 00:00:00,30.840155698085717 2014-04-06 00:05:00,28.99242684337619 2014-04-06 00:10:00,30.202432689166663 2014-04-06 00:15:00,32.276260971657145 2014-04-06 00:20:00,31.76499374384762 2014-04-06 00:25:00,30.044475231038096 2014-04-06 00:30:00,32.511661179628575 2014-04-06 00:35:00,29.072780681019047 2014-04-06 00:40:00,32.61874833940952 2014-04-06 00:45:00,29.7640703699 2014-04-06 00:50:00,28.825067197390474 2014-04-06 00:55:00,30.531363098480952 2014-04-06 01:00:00,30.239453147271426 2014-04-06 01:05:00,30.967367925561902 2014-04-06 01:10:00,32.00554382325238 2014-04-06 01:15:00,32.195616065742854 2014-04-06 01:20:00,30.438253331733332 2014-04-06 01:25:00,30.56015678432381 2014-04-06 01:30:00,29.440925207014285 2014-04-06 01:35:00,29.04584519740476 2014-04-06 01:40:00,31.427955198995235 2014-04-06 01:45:00,29.128286216485712 2014-04-06 01:50:00,31.81329666817619 2014-04-06 01:55:00,31.041777246766664 2014-04-06 02:00:00,29.68718905575714 2014-04-06 02:05:00,31.05838939314762 2014-04-06 02:10:00,29.639728961638095 2014-04-06 02:15:00,30.670127401428573 2014-04-06 02:20:00,32.120860312619044 2014-04-06 02:25:00,30.777736697409523 2014-04-06 02:30:00,29.5322972732 2014-04-06 02:35:00,31.84025520349048 2014-04-06 02:40:00,29.699454617480953 2014-04-06 02:45:00,31.91402092607143 2014-04-06 02:50:00,30.884671061661905 2014-04-06 02:55:00,30.789669417352382 2014-04-06 03:00:00,32.38788300854286 2014-04-06 03:05:00,31.823997430733332 2014-04-06 03:10:00,29.128666997323805 2014-04-06 03:15:00,30.189161544114285 2014-04-06 03:20:00,32.49558740530476 2014-04-06 03:25:00,29.092649912295236 2014-04-06 03:30:00,31.207799499285713 2014-04-06 03:35:00,31.94552886717619 2014-04-06 03:40:00,31.529091008566667 2014-04-06 03:45:00,32.09123595125714 2014-04-06 03:50:00,31.959315014747617 2014-04-06 03:55:00,31.832110875838094 2014-04-06 04:00:00,32.35758801512857 2014-04-06 04:05:00,31.66163172141905 2014-04-06 04:10:00,30.695983500809525 2014-04-06 04:15:00,30.9813864397 2014-04-06 04:20:00,31.968089606890473 2014-04-06 04:25:00,32.61385507108095 2014-04-06 04:30:00,30.20494663197143 2014-04-06 04:35:00,30.491819088661906 2014-04-06 04:40:00,32.853909966352376 2014-04-06 04:45:00,31.452440026742856 2014-04-06 04:50:00,29.86168060183333 2014-04-06 04:55:00,31.80805436512381 2014-04-06 05:00:00,33.12376290791428 2014-04-06 05:05:00,32.46196901980476 2014-04-06 05:10:00,32.158559784295235 2014-04-06 05:15:00,30.015222331385715 2014-04-06 05:20:00,32.69503532917619 2014-04-06 05:25:00,31.30107204076667 2014-04-06 05:30:00,32.76251723115714 2014-04-06 05:35:00,30.53210893674762 2014-04-06 05:40:00,29.468442305738094 2014-04-06 05:45:00,31.131582446028574 2014-04-06 05:50:00,30.314469466919046 2014-04-06 05:55:00,32.10347668290952 2014-04-06 06:00:00,33.0784262114 2014-04-06 06:05:00,32.021337080790474 2014-04-06 06:10:00,32.812616671180955 2014-04-06 06:15:00,31.084417482971432 2014-04-06 06:20:00,32.366324853561906 2014-04-06 06:25:00,32.65937612765238 2014-04-06 06:30:00,32.13814536744285 2014-04-06 06:35:00,31.333192477633332 2014-04-06 06:40:00,31.812988248023807 2014-04-06 06:45:00,32.11899226841429 2014-04-06 06:50:00,30.336742374804757 2014-04-06 06:55:00,32.570162281795234 2014-04-06 07:00:00,33.140583870185715 2014-04-06 07:05:00,31.207683451176187 2014-04-06 07:10:00,32.15843539906667 2014-04-06 07:15:00,32.30971076605714 2014-04-06 07:20:00,32.01803780914762 2014-04-06 07:25:00,31.564948528538093 2014-04-06 07:30:00,32.91052038972857 2014-04-06 07:35:00,31.187075884719047 2014-04-06 07:40:00,29.64322134970952 2014-04-06 07:45:00,32.7844755028 2014-04-06 07:50:00,32.10961556549048 2014-04-06 07:55:00,32.81816545838095 2014-04-06 08:00:00,29.982761198371428 2014-04-06 08:05:00,29.559023666761902 2014-04-06 08:10:00,33.18095054245238 2014-04-06 08:15:00,30.041806080542855 2014-04-06 08:20:00,32.69694266163333 2014-04-06 08:25:00,32.75861357822381 2014-04-06 08:30:00,32.308035087914284 2014-04-06 08:35:00,30.005703606304763 2014-04-06 08:40:00,32.15768973629524 2014-04-06 08:45:00,33.051882047585714 2014-04-06 08:50:00,31.20510276967619 2014-04-06 08:55:00,31.164484084166666 2014-04-06 09:00:00,78.74073015315713 2014-04-06 09:05:00,73.84419533224761 2014-04-06 09:10:00,84.8642858340381 2014-04-06 09:15:00,84.56106552152858 2014-04-06 09:20:00,86.31918582391906 2014-04-06 09:25:00,80.71355024820951 2014-04-06 09:30:00,82.97870625569999 2014-04-06 09:35:00,75.52627840199048 2014-04-06 09:40:00,81.85577288018095 2014-04-06 09:45:00,81.62118817167143 2014-04-06 09:50:00,85.04870071216189 2014-04-06 09:55:00,84.09848341155238 2014-04-06 10:00:00,96.01214235694286 2014-04-06 10:05:00,94.93887882963332 2014-04-06 10:10:00,94.9441530583238 2014-04-06 10:15:00,82.45845031591429 2014-04-06 10:20:00,94.60623426770476 2014-04-06 10:25:00,90.91240992079524 2014-04-06 10:30:00,87.39628360568571 2014-04-06 10:35:00,82.37633316097619 2014-04-06 10:40:00,92.02416365106667 2014-04-06 10:45:00,86.60779831115714 2014-04-06 10:50:00,88.78143525164762 2014-04-06 10:55:00,92.1094134383381 2014-04-06 11:00:00,97.76529096732857 2014-04-06 11:05:00,96.39961775341905 2014-04-06 11:10:00,90.44560626510952 2014-04-06 11:15:00,89.454053336 2014-04-06 11:20:00,87.10764744279048 2014-04-06 11:25:00,89.22470600308094 2014-04-06 11:30:00,85.07515317207144 2014-04-06 11:35:00,98.7609739097619 2014-04-06 11:40:00,92.45153540965238 2014-04-06 11:45:00,85.36401698094286 2014-04-06 11:50:00,88.94986010473333 2014-04-06 11:55:00,92.0463843496238 2014-04-06 12:00:00,92.21525306771429 2014-04-06 12:05:00,84.27412699670475 2014-04-06 12:10:00,98.90939563789522 2014-04-06 12:15:00,88.12235940478571 2014-04-06 12:20:00,83.98772014777619 2014-04-06 12:25:00,84.95815308486667 2014-04-06 12:30:00,93.01593585265714 2014-04-06 12:35:00,85.95332046784762 2014-04-06 12:40:00,84.4256336648381 2014-04-06 12:45:00,89.83301320582856 2014-04-06 12:50:00,93.72594111021905 2014-04-06 12:55:00,85.56844907700952 2014-04-06 13:00:00,88.8697621355 2014-04-06 13:05:00,90.54772702119048 2014-04-06 13:10:00,86.42335019018094 2014-04-06 13:15:00,91.97528048027144 2014-04-06 13:20:00,85.2505800730619 2014-04-06 13:25:00,84.63903969145238 2014-04-06 13:30:00,92.21773256384286 2014-04-06 13:35:00,87.87520297293332 2014-04-06 13:40:00,85.44285850042381 2014-04-06 13:45:00,90.70565786121429 2014-04-06 13:50:00,98.57086245370476 2014-04-06 13:55:00,95.52386348559524 2014-04-06 14:00:00,97.01005796678571 2014-04-06 14:05:00,97.9182243806762 2014-04-06 14:10:00,99.53700755086668 2014-04-06 14:15:00,96.19451014575714 2014-04-06 14:20:00,93.72465111274762 2014-04-06 14:25:00,89.8445655330381 2014-04-06 14:30:00,86.91162485432856 2014-04-06 14:35:00,94.99894367651905 2014-04-06 14:40:00,99.93878918020951 2014-04-06 14:45:00,91.5051740224 2014-04-06 14:50:00,95.61354857989048 2014-04-06 14:55:00,91.96377392128095 2014-04-06 15:00:00,90.96374865737143 2014-04-06 15:05:00,90.62514749876189 2014-04-06 15:10:00,92.14167859755239 2014-04-06 15:15:00,89.94547589184286 2014-04-06 15:20:00,96.06290027093333 2014-04-06 15:25:00,98.07830074682379 2014-04-06 15:30:00,98.22355238081428 2014-04-06 15:35:00,87.74810800220476 2014-04-06 15:40:00,98.44681264619524 2014-04-06 15:45:00,89.58461176168571 2014-04-06 15:50:00,89.07616012857619 2014-04-06 15:55:00,95.76271075526667 2014-04-06 16:00:00,89.01785098395713 2014-04-06 16:05:00,84.99762024164762 2014-04-06 16:10:00,90.13547273463809 2014-04-06 16:15:00,95.70846777372857 2014-04-06 16:20:00,89.40380548781906 2014-04-06 16:25:00,94.25284683970952 2014-04-06 16:30:00,94.7492525893 2014-04-06 16:35:00,95.93455588349048 2014-04-06 16:40:00,98.55630261348095 2014-04-06 16:45:00,91.13070188847144 2014-04-06 16:50:00,86.8800317785619 2014-04-06 16:55:00,89.32736579045238 2014-04-06 17:00:00,91.14678863664285 2014-04-06 17:05:00,95.66181480843333 2014-04-06 17:10:00,84.45695008992381 2014-04-06 17:15:00,89.30700083261428 2014-04-06 17:20:00,96.73935361890476 2014-04-06 17:25:00,95.00303672159525 2014-04-06 17:30:00,95.9845931478857 2014-04-06 17:35:00,97.27316586577619 2014-04-06 17:40:00,96.82340570846668 2014-04-06 17:45:00,95.21400596195714 2014-04-06 17:50:00,91.34110178764762 2014-04-06 17:55:00,100.05152766603808 2014-04-06 18:00:00,44.76349079432857 2014-04-06 18:05:00,42.426586208819046 2014-04-06 18:10:00,43.010305907109526 2014-04-06 18:15:00,45.5825433364 2014-04-06 18:20:00,47.06951702759047 2014-04-06 18:25:00,42.30243403008095 2014-04-06 18:30:00,41.69308337057143 2014-04-06 18:35:00,46.81530399936191 2014-04-06 18:40:00,47.038724791652385 2014-04-06 18:45:00,42.957214797942854 2014-04-06 18:50:00,43.61045597613334 2014-04-06 18:55:00,45.42847065262381 2014-04-06 19:00:00,34.04879959211428 2014-04-06 19:05:00,36.50782445350476 2014-04-06 19:10:00,33.06754669389524 2014-04-06 19:15:00,32.76319494888571 2014-04-06 19:20:00,33.53449323957619 2014-04-06 19:25:00,33.88958873676667 2014-04-06 19:30:00,33.12126713815714 2014-04-06 19:35:00,32.91708962044762 2014-04-06 19:40:00,36.01535936013809 2014-04-06 19:45:00,33.373636440328575 2014-04-06 19:50:00,36.73948916891906 2014-04-06 19:55:00,34.30119681070953 2014-04-06 20:00:00,33.6788011425 2014-04-06 20:05:00,31.862687305990477 2014-04-06 20:10:00,31.931242779080954 2014-04-06 20:15:00,33.30833007407143 2014-04-06 20:20:00,33.2581550774619 2014-04-06 20:25:00,34.11791703995238 2014-04-06 20:30:00,34.08064589884285 2014-04-06 20:35:00,33.73122016323333 2014-04-06 20:40:00,32.831162364123806 2014-04-06 20:45:00,34.64702704291428 2014-04-06 20:50:00,33.55648600610476 2014-04-06 20:55:00,35.06969798519523 2014-04-06 21:00:00,33.968896834285715 2014-04-06 21:05:00,30.86121613917619 2014-04-06 21:10:00,31.979097650566665 2014-04-06 21:15:00,32.996489972657145 2014-04-06 21:20:00,33.605177934347616 2014-04-06 21:25:00,32.9248004974381 2014-04-06 21:30:00,33.87994391342857 2014-04-06 21:35:00,31.863818600119046 2014-04-06 21:40:00,31.474388794109522 2014-04-06 21:45:00,30.9593518907 2014-04-06 21:50:00,33.054353028490475 2014-04-06 21:55:00,33.525150094880956 2014-04-06 22:00:00,32.00170270247143 2014-04-06 22:05:00,33.1599847973619 2014-04-06 22:10:00,30.91956157915238 2014-04-06 22:15:00,31.115727519742855 2014-04-06 22:20:00,33.53532715043333 2014-04-06 22:25:00,32.20674600852381 2014-04-06 22:30:00,33.42840832261429 2014-04-06 22:35:00,34.07801304160476 2014-04-06 22:40:00,34.16913904759524 2014-04-06 22:45:00,31.45214741068571 2014-04-06 22:50:00,32.71726580667619 2014-04-06 22:55:00,33.71622182956666 2014-04-06 23:00:00,33.867829942957144 2014-04-06 23:05:00,33.91806017104762 2014-04-06 23:10:00,31.699038663438095 2014-04-06 23:15:00,31.563921707228573 2014-04-06 23:20:00,33.16157804831904 2014-04-06 23:25:00,33.773427866609524 2014-04-06 23:30:00,32.0927591594 2014-04-06 23:35:00,31.242297515390476 2014-04-06 23:40:00,33.698372943180956 2014-04-06 23:45:00,32.03729892017142 2014-04-06 23:50:00,31.511296566761906 2014-04-06 23:55:00,31.444165944352378 2014-04-07 00:00:00,32.11678104724285 2014-04-07 00:05:00,33.23529559703333 2014-04-07 00:10:00,32.30563276432381 2014-04-07 00:15:00,30.962111692114284 2014-04-07 00:20:00,31.274538500604763 2014-04-07 00:25:00,32.05635822689524 2014-04-07 00:30:00,33.54060364288571 2014-04-07 00:35:00,31.30328648437619 2014-04-07 00:40:00,33.15929408066667 2014-04-07 00:45:00,31.40365062615714 2014-04-07 00:50:00,31.77800892844762 2014-04-07 00:55:00,31.627742205438096 2014-04-07 01:00:00,31.215343113728572 2014-04-07 01:05:00,33.63918831711905 2014-04-07 01:10:00,32.814923713309526 2014-04-07 01:15:00,34.2929637636 2014-04-07 01:20:00,31.371753836090477 2014-04-07 01:25:00,31.562562685780946 2014-04-07 01:30:00,32.21690235397143 2014-04-07 01:35:00,34.0619758525619 2014-04-07 01:40:00,32.22898767355238 2014-04-07 01:45:00,32.64706768714286 2014-04-07 01:50:00,32.22724759853333 2014-04-07 01:55:00,31.349170976723812 2014-04-07 02:00:00,34.79344877731428 2014-04-07 02:05:00,33.23731073020476 2014-04-07 02:10:00,34.20192799079524 2014-04-07 02:15:00,33.69146408298571 2014-04-07 02:20:00,33.12249330667619 2014-04-07 02:25:00,31.431629693266665 2014-04-07 02:30:00,33.65129132395714 2014-04-07 02:35:00,31.709279042747617 2014-04-07 02:40:00,32.752770772638094 2014-04-07 02:45:00,33.61913114532857 2014-04-07 02:50:00,34.239035049519046 2014-04-07 02:55:00,33.85774022660952 2014-04-07 03:00:00,33.811134116199995 2014-04-07 03:05:00,31.728609312890477 2014-04-07 03:10:00,32.52439511268095 2014-04-07 03:15:00,31.318970519171426 2014-04-07 03:20:00,34.0326694774619 2014-04-07 03:25:00,34.97254630625238 2014-04-07 03:30:00,32.226084417842856 2014-04-07 03:35:00,31.527870169933333 2014-04-07 03:40:00,33.08680411652381 2014-04-07 03:45:00,34.61875717821428 2014-04-07 03:50:00,33.40730154300476 2014-04-07 03:55:00,31.393953838895236 2014-04-07 04:00:00,35.111374676385715 2014-04-07 04:05:00,34.536325830376185 2014-04-07 04:10:00,31.755542974866664 2014-04-07 04:15:00,34.92379816885715 2014-04-07 04:20:00,33.04680077344762 2014-04-07 04:25:00,32.7390800575381 2014-04-07 04:30:00,33.10314189352857 2014-04-07 04:35:00,34.60465687511905 2014-04-07 04:40:00,33.911728236909525 2014-04-07 04:45:00,31.5182438096 2014-04-07 04:50:00,35.11910796069048 2014-04-07 04:55:00,31.887267486280955 2014-04-07 05:00:00,34.28584323547143 2014-04-07 05:05:00,33.85555802646191 2014-04-07 05:10:00,32.06856457275238 2014-04-07 05:15:00,32.00882116164286 2014-04-07 05:20:00,34.81464370813333 2014-04-07 05:25:00,33.01955350352381 2014-04-07 05:30:00,33.966520342414285 2014-04-07 05:35:00,33.37193877730476 2014-04-07 05:40:00,34.272509306395236 2014-04-07 05:45:00,33.28750521448571 2014-04-07 05:50:00,32.52749585147619 2014-04-07 05:55:00,32.83895015066667 2014-04-07 06:00:00,34.82916792065714 2014-04-07 06:05:00,33.27243639074762 2014-04-07 06:10:00,32.2615354242381 2014-04-07 06:15:00,35.15360012372857 2014-04-07 06:20:00,34.609020873619045 2014-04-07 06:25:00,31.652724108009522 2014-04-07 06:30:00,35.4332718479 2014-04-07 06:35:00,34.22464726199048 2014-04-07 06:40:00,32.09344734858095 2014-04-07 06:45:00,32.40849215377143 2014-04-07 06:50:00,34.2370438297619 2014-04-07 06:55:00,34.59374660205238 2014-04-07 07:00:00,32.438286629742855 2014-04-07 07:05:00,32.517458748933336 2014-04-07 07:10:00,32.72550658902381 2014-04-07 07:15:00,33.896537745014285 2014-04-07 07:20:00,32.19916947510476 2014-04-07 07:25:00,31.936318033595235 2014-04-07 07:30:00,34.24224207058572 2014-04-07 07:35:00,34.65061794967619 2014-04-07 07:40:00,33.54538428436667 2014-04-07 07:45:00,33.004437983957146 2014-04-07 07:50:00,33.28471847314762 2014-04-07 07:55:00,33.117619430738095 2014-04-07 08:00:00,35.41136820442857 2014-04-07 08:05:00,34.651228668519046 2014-04-07 08:10:00,32.418658383209525 2014-04-07 08:15:00,33.1305066082 2014-04-07 08:20:00,33.77723964169048 2014-04-07 08:25:00,34.06057440068095 2014-04-07 08:30:00,33.48880701267143 2014-04-07 08:35:00,34.8640184447619 2014-04-07 08:40:00,34.70137645875238 2014-04-07 08:45:00,33.65902453164286 2014-04-07 08:50:00,35.06355088043333 2014-04-07 08:55:00,34.657631931323806 2014-04-07 09:00:00,85.4494274283143 2014-04-07 09:05:00,87.87520536220475 2014-04-07 09:10:00,78.49954563849523 2014-04-07 09:15:00,78.5230507224857 2014-04-07 09:20:00,86.98022686787618 2014-04-07 09:25:00,85.40019534466667 2014-04-07 09:30:00,87.50637650635714 2014-04-07 09:35:00,75.77136779944762 2014-04-07 09:40:00,83.45773434603808 2014-04-07 09:45:00,76.89462396992857 2014-04-07 09:50:00,81.78812094441905 2014-04-07 09:55:00,77.06071779700952 2014-04-07 10:00:00,85.5777784594 2014-04-07 10:05:00,83.78629319649048 2014-04-07 10:10:00,93.38618732058094 2014-04-07 10:15:00,89.18435243957144 2014-04-07 10:20:00,85.25228408606192 2014-04-07 10:25:00,88.63764469135238 2014-04-07 10:30:00,86.25665515644286 2014-04-07 10:35:00,98.25718711823333 2014-04-07 10:40:00,88.61599963652381 2014-04-07 10:45:00,88.83992296721428 2014-04-07 10:50:00,96.69900097470476 2014-04-07 10:55:00,93.72501465329525 2014-04-07 11:00:00,96.70185495838571 2014-04-07 11:05:00,95.5296988810762 2014-04-07 11:10:00,100.47047236656667 2014-04-07 11:15:00,88.72174836795715 2014-04-07 11:20:00,101.16672771994762 2014-04-07 11:25:00,98.66001514313808 2014-04-07 11:30:00,94.81894862492857 2014-04-07 11:35:00,95.99372736201904 2014-04-07 11:40:00,95.78573626370951 2014-04-07 11:45:00,86.4029835474 2014-04-07 11:50:00,88.94902486889049 2014-04-07 11:55:00,100.78036389988095 2014-04-07 12:00:00,94.38174249327143 2014-04-07 12:05:00,91.8960051677619 2014-04-07 12:10:00,98.03503665665238 2014-04-07 12:15:00,94.24672517594286 2014-04-07 12:20:00,86.08228495103333 2014-04-07 12:25:00,97.64503959512382 2014-04-07 12:30:00,97.58823666941427 2014-04-07 12:35:00,88.53346330040476 2014-04-07 12:40:00,101.18988877919524 2014-04-07 12:45:00,89.48736678278571 2014-04-07 12:50:00,93.23177728077619 2014-04-07 12:55:00,87.75758911636667 2014-04-07 13:00:00,95.65077764995713 2014-04-07 13:05:00,92.01379380764762 2014-04-07 13:10:00,91.6648773045381 2014-04-07 13:15:00,99.25135301572857 2014-04-07 13:20:00,86.18328973621905 2014-04-07 13:25:00,98.8018637425095 2014-04-07 13:30:00,95.18620268949999 2014-04-07 13:35:00,101.82645007359048 2014-04-07 13:40:00,95.48892902008096 2014-04-07 13:45:00,86.95339491907143 2014-04-07 13:50:00,86.8851126497619 2014-04-07 13:55:00,100.20947885545239 2014-04-07 14:00:00,99.56246713284285 2014-04-07 14:05:00,91.64510289903332 2014-04-07 14:10:00,96.00661290752382 2014-04-07 14:15:00,93.9590939924143 2014-04-07 14:20:00,101.60733086210476 2014-04-07 14:25:00,101.33953408219524 2014-04-07 14:30:00,101.8889982625857 2014-04-07 14:35:00,100.0182852479762 2014-04-07 14:40:00,100.71533758346668 2014-04-07 14:45:00,89.64694473305714 2014-04-07 14:50:00,99.47356202964762 2014-04-07 14:55:00,97.5267015042381 2014-04-07 15:00:00,101.60017362862857 2014-04-07 15:05:00,95.34327935691906 2014-04-07 15:10:00,87.57327990950951 2014-04-07 15:15:00,95.77634929850001 2014-04-07 15:20:00,97.21068866569048 2014-04-07 15:25:00,89.75804237048095 2014-04-07 15:30:00,92.54613382897143 2014-04-07 15:35:00,95.8237833994619 2014-04-07 15:40:00,92.24089551535238 2014-04-07 15:45:00,92.26180754094288 2014-04-07 15:50:00,88.39950791803334 2014-04-07 15:55:00,101.3293856800238 2014-04-07 16:00:00,98.29346314241428 2014-04-07 16:05:00,86.31291150560476 2014-04-07 16:10:00,98.55024602279525 2014-04-07 16:15:00,98.14459463028571 2014-04-07 16:20:00,86.47103301407618 2014-04-07 16:25:00,92.23643583426667 2014-04-07 16:30:00,96.03816330875713 2014-04-07 16:35:00,93.58165590024763 2014-04-07 16:40:00,98.79285385503809 2014-04-07 16:45:00,93.15986058352857 2014-04-07 16:50:00,88.82178359221905 2014-04-07 16:55:00,101.99004127670953 2014-04-07 17:00:00,90.24761074930001 2014-04-07 17:05:00,97.86548538739048 2014-04-07 17:10:00,88.68035341148095 2014-04-07 17:15:00,91.66149357967143 2014-04-07 17:20:00,93.4771732758619 2014-04-07 17:25:00,89.48788562435239 2014-04-07 17:30:00,93.61896566644286 2014-04-07 17:35:00,88.94165988763334 2014-04-07 17:40:00,95.37859735072381 2014-04-07 17:45:00,97.06134460021428 2014-04-07 17:50:00,87.44832527480476 2014-04-07 17:55:00,100.39492617519524 2014-04-07 18:00:00,44.449181621485714 2014-04-07 18:05:00,44.71403990597619 2014-04-07 18:10:00,47.511799300966665 2014-04-07 18:15:00,46.28660782405714 2014-04-07 18:20:00,46.49017331044762 2014-04-07 18:25:00,44.12167430933809 2014-04-07 18:30:00,48.46563131172857 2014-04-07 18:35:00,47.26550993481905 2014-04-07 18:40:00,44.190248905009526 2014-04-07 18:45:00,45.7248399598 2014-04-07 18:50:00,48.525307520290475 2014-04-07 18:55:00,46.98359701868095 2014-04-07 19:00:00,35.20031682647142 2014-04-07 19:05:00,36.391051872361906 2014-04-07 19:10:00,35.81572212045238 2014-04-07 19:15:00,37.054137304442854 2014-04-07 19:20:00,38.52158987753333 2014-04-07 19:25:00,36.705249360323805 2014-04-07 19:30:00,36.699585369314285 2014-04-07 19:35:00,38.82162547590476 2014-04-07 19:40:00,37.35440463859524 2014-04-07 19:45:00,37.317070540785714 2014-04-07 19:50:00,35.961331335776194 2014-04-07 19:55:00,37.518013321666665 2014-04-07 20:00:00,35.43378616795714 2014-04-07 20:05:00,34.70780100084762 2014-04-07 20:10:00,37.147626863238095 2014-04-07 20:15:00,36.70940369932857 2014-04-07 20:20:00,36.174924233719054 2014-04-07 20:25:00,35.31302680630952 2014-04-07 20:30:00,35.0120967047 2014-04-07 20:35:00,33.884279976790474 2014-04-07 20:40:00,34.38668140978095 2014-04-07 20:45:00,36.31196460547143 2014-04-07 20:50:00,35.0078173765619 2014-04-07 20:55:00,36.77047805625239 2014-04-07 21:00:00,33.413027250642855 2014-04-07 21:05:00,34.86913193243333 2014-04-07 21:10:00,35.433708236123806 2014-04-07 21:15:00,34.91818155201429 2014-04-07 21:20:00,36.422285431604756 2014-04-07 21:25:00,36.83299792649524 2014-04-07 21:30:00,33.328748327685716 2014-04-07 21:35:00,33.39294089547619 2014-04-07 21:40:00,33.401865298366666 2014-04-07 21:45:00,35.62329407645714 2014-04-07 21:50:00,34.39080733414762 2014-04-07 21:55:00,35.84772633033809 2014-04-07 22:00:00,34.46215146382857 2014-04-07 22:05:00,35.35898593271905 2014-04-07 22:10:00,35.935977790909526 2014-04-07 22:15:00,35.0559987818 2014-04-07 22:20:00,35.02855652189047 2014-04-07 22:25:00,33.22918706428095 2014-04-07 22:30:00,34.52805579247143 2014-04-07 22:35:00,35.07599629196191 2014-04-07 22:40:00,34.74792968025238 2014-04-07 22:45:00,36.51225985014286 2014-04-07 22:50:00,36.54271692883333 2014-04-07 22:55:00,36.21137948412381 2014-04-07 23:00:00,34.41565081421429 2014-04-07 23:05:00,35.79135825230476 2014-04-07 23:10:00,34.51050866199524 2014-04-07 23:15:00,33.86704474018571 2014-04-07 23:20:00,34.31580611197619 2014-04-07 23:25:00,33.23528569886667 2014-04-07 23:30:00,34.28617798205714 2014-04-07 23:35:00,34.80957633614762 2014-04-07 23:40:00,36.796351481538096 2014-04-07 23:45:00,34.23501761372857 2014-04-07 23:50:00,36.59908228661905 2014-04-07 23:55:00,33.91162438840952 2014-04-08 00:00:00,33.763875591 2014-04-08 00:05:00,35.08342230189047 2014-04-08 00:10:00,35.70492642958095 2014-04-08 00:15:00,33.19965043177143 2014-04-08 00:20:00,33.9140253649619 2014-04-08 00:25:00,34.85993704695238 2014-04-08 00:30:00,34.36866020104286 2014-04-08 00:35:00,35.90256765073333 2014-04-08 00:40:00,35.104166193723806 2014-04-08 00:45:00,33.70840070811428 2014-04-08 00:50:00,36.65226627920476 2014-04-08 00:55:00,34.25346793999524 2014-04-08 01:00:00,36.01381015018571 2014-04-08 01:05:00,36.216389306876195 2014-04-08 01:10:00,36.95679746766667 2014-04-08 01:15:00,35.105637008957146 2014-04-08 01:20:00,35.58238968094762 2014-04-08 01:25:00,34.465993269138096 2014-04-08 01:30:00,35.84664574502857 2014-04-08 01:35:00,34.99490299111905 2014-04-08 01:40:00,34.89941898270953 2014-04-08 01:45:00,36.5781201165 2014-04-08 01:50:00,33.364365850190474 2014-04-08 01:55:00,36.69898066368095 2014-04-08 02:00:00,36.586850779871426 2014-04-08 02:05:00,35.21147691896191 2014-04-08 02:10:00,35.15426379775238 2014-04-08 02:15:00,34.64812232924286 2014-04-08 02:20:00,37.18502850003333 2014-04-08 02:25:00,33.660451140523804 2014-04-08 02:30:00,35.58407522821429 2014-04-08 02:35:00,35.95738112230476 2014-04-08 02:40:00,36.97541527099524 2014-04-08 02:45:00,36.366349701685714 2014-04-08 02:50:00,35.82836500167619 2014-04-08 02:55:00,33.72766593386667 2014-04-08 03:00:00,34.76279121015715 2014-04-08 03:05:00,33.83066418924762 2014-04-08 03:10:00,36.80758902513809 2014-04-08 03:15:00,36.288663193728574 2014-04-08 03:20:00,36.32776619481905 2014-04-08 03:25:00,35.91408559490952 2014-04-08 03:30:00,35.3406741477 2014-04-08 03:35:00,33.919824714090474 2014-04-08 03:40:00,34.64616049918095 2014-04-08 03:45:00,33.88248459847143 2014-04-08 03:50:00,36.2419144761619 2014-04-08 03:55:00,33.99061748505238 2014-04-08 04:00:00,36.16559705784285 2014-04-08 04:05:00,36.13360489173333 2014-04-08 04:10:00,35.20924172552381 2014-04-08 04:15:00,33.92037890221428 2014-04-08 04:20:00,34.646108066404764 2014-04-08 04:25:00,34.67471767439524 2014-04-08 04:30:00,36.203326246885716 2014-04-08 04:35:00,33.86419826817619 2014-04-08 04:40:00,36.732941251566665 2014-04-08 04:45:00,36.468136303557145 2014-04-08 04:50:00,34.17677529174762 2014-04-08 04:55:00,36.315645622338096 2014-04-08 05:00:00,36.12048129732857 2014-04-08 05:05:00,36.446352248019046 2014-04-08 05:10:00,34.217023745609524 2014-04-08 05:15:00,34.0991112886 2014-04-08 05:20:00,34.422126419890475 2014-04-08 05:25:00,34.94711776498095 2014-04-08 05:30:00,36.66573135267143 2014-04-08 05:35:00,36.4502076546619 2014-04-08 05:40:00,37.20775875005238 2014-04-08 05:45:00,33.747911093542854 2014-04-08 05:50:00,33.56705845743333 2014-04-08 05:55:00,36.324829128323806 2014-04-08 06:00:00,34.652864268914286 2014-04-08 06:05:00,34.87947034400476 2014-04-08 06:10:00,35.737803341795235 2014-04-08 06:15:00,33.967688206785716 2014-04-08 06:20:00,36.13625385667619 2014-04-08 06:25:00,34.87350645156667 2014-04-08 06:30:00,36.11121764005714 2014-04-08 06:35:00,36.92382527134762 2014-04-08 06:40:00,34.27968342853809 2014-04-08 06:45:00,37.326170943128574 2014-04-08 06:50:00,35.73287161181905 2014-04-08 06:55:00,37.30927058450953 2014-04-08 07:00:00,34.455920328800005 2014-04-08 07:05:00,36.05069113459047 2014-04-08 07:10:00,35.25542942168095 2014-04-08 07:15:00,36.744210193171426 2014-04-08 07:20:00,36.078397677661904 2014-04-08 07:25:00,35.640264208752384 2014-04-08 07:30:00,37.32158448284286 2014-04-08 07:35:00,35.185551590033334 2014-04-08 07:40:00,34.564444629123805 2014-04-08 07:45:00,36.124369033114284 2014-04-08 07:50:00,36.19551851060476 2014-04-08 07:55:00,35.463223724395235 2014-04-08 08:00:00,35.66072588908571 2014-04-08 08:05:00,37.55993984767619 2014-04-08 08:10:00,36.659909432266666 2014-04-08 08:15:00,34.17901414875714 2014-04-08 08:20:00,34.592567902547614 2014-04-08 08:25:00,37.653794632938094 2014-04-08 08:30:00,36.66479078662857 2014-04-08 08:35:00,37.42654955221904 2014-04-08 08:40:00,34.98925537980952 2014-04-08 08:45:00,36.7487174403 2014-04-08 08:50:00,36.64470131029047 2014-04-08 08:55:00,34.97489089418095 2014-04-08 09:00:00,84.49467345467143 2014-04-08 09:05:00,85.5438574180619 2014-04-08 09:10:00,83.56184500825238 2014-04-08 09:15:00,88.27552326764287 2014-04-08 09:20:00,88.36035230183333 2014-04-08 09:25:00,88.60894126642381 2014-04-08 09:30:00,87.9747748254143 2014-04-08 09:35:00,83.69359005180476 2014-04-08 09:40:00,82.25065609289524 2014-04-08 09:45:00,88.37725317278571 2014-04-08 09:50:00,83.74471602687619 2014-04-08 09:55:00,80.43606768796667 2014-04-08 10:00:00,93.60682876445713 2014-04-08 10:05:00,87.94180685524762 2014-04-08 10:10:00,96.4818277893381 2014-04-08 10:15:00,90.96867686222856 2014-04-08 10:20:00,89.80804359951905 2014-04-08 10:25:00,100.61507526540952 2014-04-08 10:30:00,97.8346930542 2014-04-08 10:35:00,98.00025915849048 2014-04-08 10:40:00,95.47254591558095 2014-04-08 10:45:00,98.82378344767143 2014-04-08 10:50:00,97.5894636124619 2014-04-08 10:55:00,95.10767026915238 2014-04-08 11:00:00,102.83586534414287 2014-04-08 11:05:00,90.60470941313332 2014-04-08 11:10:00,102.56853486042381 2014-04-08 11:15:00,93.9569368141143 2014-04-08 11:20:00,95.98356219390476 2014-04-08 11:25:00,89.53939137609524 2014-04-08 11:30:00,96.1846544228857 2014-04-08 11:35:00,97.32285837207618 2014-04-08 11:40:00,103.47711198756667 2014-04-08 11:45:00,103.12656724855714 2014-04-08 11:50:00,102.99413014904762 2014-04-08 11:55:00,93.17275180313808 2014-04-08 12:00:00,103.82626023452855 2014-04-08 12:05:00,95.27137429261906 2014-04-08 12:10:00,101.61293440780952 2014-04-08 12:15:00,91.4643161609 2014-04-08 12:20:00,96.09840935369047 2014-04-08 12:25:00,103.45987705818095 2014-04-08 12:30:00,103.16399077657142 2014-04-08 12:35:00,98.9637422402619 2014-04-08 12:40:00,100.79426350685237 2014-04-08 12:45:00,90.87143261024286 2014-04-08 12:50:00,99.59211428093333 2014-04-08 12:55:00,97.9438201673238 2014-04-08 13:00:00,89.6079104991143 2014-04-08 13:05:00,89.96098433670475 2014-04-08 13:10:00,89.89299669859524 2014-04-08 13:15:00,99.7526851408857 2014-04-08 13:20:00,90.4400953360762 2014-04-08 13:25:00,95.66255691256666 2014-04-08 13:30:00,93.89841522675714 2014-04-08 13:35:00,97.00146993544763 2014-04-08 13:40:00,99.5038690210381 2014-04-08 13:45:00,99.16332983242857 2014-04-08 13:50:00,96.46417810581904 2014-04-08 13:55:00,95.65285445570952 2014-04-08 14:00:00,94.6112879996 2014-04-08 14:05:00,102.04388170219048 2014-04-08 14:10:00,93.55479973618095 2014-04-08 14:15:00,92.41851937427143 2014-04-08 14:20:00,100.16878293696192 2014-04-08 14:25:00,94.03968546975238 2014-04-08 14:30:00,101.84251395834286 2014-04-08 14:35:00,93.54459501303333 2014-04-08 14:40:00,99.5366459091238 2014-04-08 14:45:00,89.03521774251428 2014-04-08 14:50:00,94.48965873140476 2014-04-08 14:55:00,93.81980843679524 2014-04-08 15:00:00,101.4053289008857 2014-04-08 15:05:00,103.8187729023762 2014-04-08 15:10:00,95.72750510236665 2014-04-08 15:15:00,101.55816968245713 2014-04-08 15:20:00,99.56336416124762 2014-04-08 15:25:00,103.85382410733808 2014-04-08 15:30:00,101.36084901462857 2014-04-08 15:35:00,89.63031500241905 2014-04-08 15:40:00,99.81051632180952 2014-04-08 15:45:00,96.973471994 2014-04-08 15:50:00,88.67597367849046 2014-04-08 15:55:00,92.44140849028095 2014-04-08 16:00:00,103.17648879267144 2014-04-08 16:05:00,103.2528271807619 2014-04-08 16:10:00,101.22489696345238 2014-04-08 16:15:00,104.15919810934285 2014-04-08 16:20:00,101.36289391023332 2014-04-08 16:25:00,88.62890225262382 2014-04-08 16:30:00,93.07841664831429 2014-04-08 16:35:00,88.97050249690476 2014-04-08 16:40:00,89.99368160689524 2014-04-08 16:45:00,91.9968438226857 2014-04-08 16:50:00,96.55975922237619 2014-04-08 16:55:00,102.07076444586667 2014-04-08 17:00:00,102.30929229745713 2014-04-08 17:05:00,98.38449592204762 2014-04-08 17:10:00,103.38351976953811 2014-04-08 17:15:00,96.54114507652857 2014-04-08 17:20:00,102.77216264351905 2014-04-08 17:25:00,95.82007318730952 2014-04-08 17:30:00,92.9980707675 2014-04-08 17:35:00,103.2325138873905 2014-04-08 17:40:00,94.78431213178095 2014-04-08 17:45:00,96.63925642917144 2014-04-08 17:50:00,93.8540023567619 2014-04-08 17:55:00,99.20507226515238 2014-04-08 18:00:00,51.77533594484285 2014-04-08 18:05:00,45.57786448513333 2014-04-08 18:10:00,51.18104441262381 2014-04-08 18:15:00,45.45458551601429 2014-04-08 18:20:00,47.76795722410476 2014-04-08 18:25:00,46.52342306159524 2014-04-08 18:30:00,50.298766650385716 2014-04-08 18:35:00,45.78312997957619 2014-04-08 18:40:00,49.008964159866665 2014-04-08 18:45:00,47.36162850745714 2014-04-08 18:50:00,46.337031517947615 2014-04-08 18:55:00,50.428618174638096 2014-04-08 19:00:00,37.83045482952857 2014-04-08 19:05:00,37.86593283671905 2014-04-08 19:10:00,38.10365234770953 2014-04-08 19:15:00,39.5074638518 2014-04-08 19:20:00,39.84149258209048 2014-04-08 19:25:00,36.97248914828096 2014-04-08 19:30:00,37.98464623297143 2014-04-08 19:35:00,38.839260067361906 2014-04-08 19:40:00,38.40320793915238 2014-04-08 19:45:00,40.88447608404286 2014-04-08 19:50:00,40.459767148233325 2014-04-08 19:55:00,39.74226071542381 2014-04-08 20:00:00,36.60233578381428 2014-04-08 20:05:00,38.09510843080476 2014-04-08 20:10:00,38.688136276095236 2014-04-08 20:15:00,37.67646068948571 2014-04-08 20:20:00,38.460630099176186 2014-04-08 20:25:00,38.323250330566665 2014-04-08 20:30:00,37.604192920057145 2014-04-08 20:35:00,36.548499838647615 2014-04-08 20:40:00,38.3319615565381 2014-04-08 20:45:00,36.131716256728566 2014-04-08 20:50:00,38.48490305531905 2014-04-08 20:55:00,38.594982514109525 2014-04-08 21:00:00,38.265764647699996 2014-04-08 21:05:00,36.869584297890476 2014-04-08 21:10:00,35.74989960808095 2014-04-08 21:15:00,35.38453047677143 2014-04-08 21:20:00,37.97887939116191 2014-04-08 21:25:00,38.56066408475238 2014-04-08 21:30:00,37.62189233834286 2014-04-08 21:35:00,35.59289140243334 2014-04-08 21:40:00,38.77845956202381 2014-04-08 21:45:00,39.00376304861429 2014-04-08 21:50:00,36.777640022504755 2014-04-08 21:55:00,37.43396699069524 2014-04-08 22:00:00,38.09346434138571 2014-04-08 22:05:00,37.93739307717619 2014-04-08 22:10:00,38.871311726466665 2014-04-08 22:15:00,35.46386064915714 2014-04-08 22:20:00,37.33645705714761 2014-04-08 22:25:00,37.78915078033809 2014-04-08 22:30:00,38.59002023552857 2014-04-08 22:35:00,38.533444128919044 2014-04-08 22:40:00,38.95684420650952 2014-04-08 22:45:00,37.0988101872 2014-04-08 22:50:00,38.382204054690476 2014-04-08 22:55:00,36.774178536980955 2014-04-08 23:00:00,36.746607275071426 2014-04-08 23:05:00,36.078055932361906 2014-04-08 23:10:00,38.345485933152375 2014-04-08 23:15:00,39.02336638424286 2014-04-08 23:20:00,36.112353115333335 2014-04-08 23:25:00,35.31879926892381 2014-04-08 23:30:00,38.36446636991428 2014-04-08 23:35:00,37.59050730670476 2014-04-08 23:40:00,38.95608348679524 2014-04-08 23:45:00,36.133142308485716 2014-04-08 23:50:00,35.415597369876195 2014-04-08 23:55:00,37.10901990386667 2014-04-09 00:00:00,35.484721234757146 2014-04-09 00:05:00,36.19745762344762 2014-04-09 00:10:00,35.66164953853809 2014-04-09 00:15:00,36.061707290028565 2014-04-09 00:20:00,35.59719765891904 2014-04-09 00:25:00,38.99568352150952 2014-04-09 00:30:00,36.3017508538 2014-04-09 00:35:00,36.970530820190476 2014-04-09 00:40:00,38.79682818288096 2014-04-09 00:45:00,37.91910778037143 2014-04-09 00:50:00,37.6894118269619 2014-04-09 00:55:00,38.04695514235238 2014-04-09 01:00:00,38.547431885542856 2014-04-09 01:05:00,38.75026040473333 2014-04-09 01:10:00,37.817582492223806 2014-04-09 01:15:00,38.814493384514286 2014-04-09 01:20:00,37.403494871604764 2014-04-09 01:25:00,36.378508663195234 2014-04-09 01:30:00,38.79709254978572 2014-04-09 01:35:00,37.45011750017619 2014-04-09 01:40:00,38.91621701696667 2014-04-09 01:45:00,35.45977839865714 2014-04-09 01:50:00,36.89661062524762 2014-04-09 01:55:00,39.1052081686381 2014-04-09 02:00:00,36.320028942428564 2014-04-09 02:05:00,39.09501403181905 2014-04-09 02:10:00,39.15191936830952 2014-04-09 02:15:00,38.8723192569 2014-04-09 02:20:00,37.605862656590475 2014-04-09 02:25:00,37.94638874868095 2014-04-09 02:30:00,38.844539422371426 2014-04-09 02:35:00,38.477100234361906 2014-04-09 02:40:00,37.901327778752375 2014-04-09 02:45:00,39.317430488642856 2014-04-09 02:50:00,38.13853987863333 2014-04-09 02:55:00,39.30520177932381 2014-04-09 03:00:00,35.640268184114284 2014-04-09 03:05:00,35.973996244904754 2014-04-09 03:10:00,37.23143062209524 2014-04-09 03:15:00,36.972553557785716 2014-04-09 03:20:00,38.571415555876186 2014-04-09 03:25:00,36.09037277256667 2014-04-09 03:30:00,39.35973785925714 2014-04-09 03:35:00,36.72306112004762 2014-04-09 03:40:00,37.185932926238095 2014-04-09 03:45:00,36.57665870122857 2014-04-09 03:50:00,37.80257351691905 2014-04-09 03:55:00,35.72707432550952 2014-04-09 04:00:00,36.0987100223 2014-04-09 04:05:00,38.49063128989047 2014-04-09 04:10:00,36.26088328598095 2014-04-09 04:15:00,36.46437923477143 2014-04-09 04:20:00,38.70169084766191 2014-04-09 04:25:00,35.91040709435238 2014-04-09 04:30:00,37.29453814824286 2014-04-09 04:35:00,35.64433688133333 2014-04-09 04:40:00,36.94675340682381 2014-04-09 04:45:00,38.36288989611428 2014-04-09 04:50:00,35.93481788080476 2014-04-09 04:55:00,39.135183745195235 2014-04-09 05:00:00,39.227281886085706 2014-04-09 05:05:00,36.01668769097619 2014-04-09 05:10:00,39.56709641216666 2014-04-09 05:15:00,36.80172535645714 2014-04-09 05:20:00,35.95545430354762 2014-04-09 05:25:00,35.64675655323809 2014-04-09 05:30:00,37.26802015452857 2014-04-09 05:35:00,38.16060899041905 2014-04-09 05:40:00,36.97752652340952 2014-04-09 05:45:00,39.0031194619 2014-04-09 05:50:00,38.530115578490474 2014-04-09 05:55:00,37.07177708028095 2014-04-09 06:00:00,38.61581009497143 2014-04-09 06:05:00,39.4479628526619 2014-04-09 06:10:00,36.06583637515238 2014-04-09 06:15:00,36.92530869774286 2014-04-09 06:20:00,37.56163708983333 2014-04-09 06:25:00,37.70773432052381 2014-04-09 06:30:00,37.89199686521428 2014-04-09 06:35:00,36.93316238810476 2014-04-09 06:40:00,38.40713382199524 2014-04-09 06:45:00,38.325873728385716 2014-04-09 06:50:00,38.06426221557619 2014-04-09 06:55:00,36.21546355346666 2014-04-09 07:00:00,37.67572870725714 2014-04-09 07:05:00,37.20020516904762 2014-04-09 07:10:00,37.746891974638096 2014-04-09 07:15:00,39.47764431352857 2014-04-09 07:20:00,37.719744420219044 2014-04-09 07:25:00,35.86098269120952 2014-04-09 07:30:00,37.5678469523 2014-04-09 07:35:00,39.102533196390475 2014-04-09 07:40:00,38.94762464528095 2014-04-09 07:45:00,37.888381722671426 2014-04-09 07:50:00,36.84133795616191 2014-04-09 07:55:00,37.71005703265238 2014-04-09 08:00:00,38.11195173484286 2014-04-09 08:05:00,39.86406908643333 2014-04-09 08:10:00,38.44873617022381 2014-04-09 08:15:00,38.65652400601428 2014-04-09 08:20:00,37.85272133620476 2014-04-09 08:25:00,37.31230344119524 2014-04-09 08:30:00,39.15359764888571 2014-04-09 08:35:00,37.88895548787619 2014-04-09 08:40:00,39.895427186566664 2014-04-09 08:45:00,37.75258943995714 2014-04-09 08:50:00,36.20354875364762 2014-04-09 08:55:00,38.669300643638095 2014-04-09 09:00:00,79.78075230402858 2014-04-09 09:05:00,82.56069076521905 2014-04-09 09:10:00,83.97214976160951 2014-04-09 09:15:00,89.2257267645 2014-04-09 09:20:00,85.89779907529046 2014-04-09 09:25:00,79.57321561818095 2014-04-09 09:30:00,87.58022940597142 2014-04-09 09:35:00,84.7940447337619 2014-04-09 09:40:00,91.74290171655238 2014-04-09 09:45:00,86.00744028864285 2014-04-09 09:50:00,88.86289531813333 2014-04-09 09:55:00,82.20488530522381 2014-04-09 10:00:00,99.68602400721429 2014-04-09 10:05:00,99.07238118060476 2014-04-09 10:10:00,101.92194335469524 2014-04-09 10:15:00,88.42294759378571 2014-04-09 10:20:00,94.85068701747619 2014-04-09 10:25:00,98.45340851716668 2014-04-09 10:30:00,89.39730087205714 2014-04-09 10:35:00,94.30037274124763 2014-04-09 10:40:00,102.5573533748381 2014-04-09 10:45:00,94.70838187002856 2014-04-09 10:50:00,103.24360128721905 2014-04-09 10:55:00,88.83970175180951 2014-04-09 11:00:00,101.1093647597 2014-04-09 11:05:00,98.94092269749046 2014-04-09 11:10:00,97.66846397748095 2014-04-09 11:15:00,105.15567850177143 2014-04-09 11:20:00,91.7847218741619 2014-04-09 11:25:00,103.98016970845238 2014-04-09 11:30:00,100.73113035584286 2014-04-09 11:35:00,93.86415688313332 2014-04-09 11:40:00,104.09266990162381 2014-04-09 11:45:00,96.5874706594143 2014-04-09 11:50:00,102.71687618760475 2014-04-09 11:55:00,95.95890120519525 2014-04-09 12:00:00,103.7264410812857 2014-04-09 12:05:00,100.3091688064762 2014-04-09 12:10:00,92.39680470866665 2014-04-09 12:15:00,100.53234422565714 2014-04-09 12:20:00,93.21549000284762 2014-04-09 12:25:00,96.74794122713809 2014-04-09 12:30:00,92.89398824422857 2014-04-09 12:35:00,90.53180418891905 2014-04-09 12:40:00,93.57352593340951 2014-04-09 12:45:00,98.7665040367 2014-04-09 12:50:00,97.89801999009049 2014-04-09 12:55:00,98.22405573668095 2014-04-09 13:00:00,94.24833036607143 2014-04-09 13:05:00,101.25368009556192 2014-04-09 13:10:00,101.56668059905239 2014-04-09 13:15:00,96.03472346964286 2014-04-09 13:20:00,104.41139105573333 2014-04-09 13:25:00,100.62539222652381 2014-04-09 13:30:00,101.73682461901427 2014-04-09 13:35:00,94.77474846360477 2014-04-09 13:40:00,90.35559905189524 2014-04-09 13:45:00,104.19594246558573 2014-04-09 13:50:00,103.51632823407618 2014-04-09 13:55:00,92.33873381846666 2014-04-09 14:00:00,96.37479598945714 2014-04-09 14:05:00,100.97776264464763 2014-04-09 14:10:00,100.83755498963808 2014-04-09 14:15:00,104.17666717932858 2014-04-09 14:20:00,92.66334590781905 2014-04-09 14:25:00,97.30530929460951 2014-04-09 14:30:00,91.9895600185 2014-04-09 14:35:00,96.67470924209047 2014-04-09 14:40:00,90.69063247928095 2014-04-09 14:45:00,104.82804459657142 2014-04-09 14:50:00,98.8961050842619 2014-04-09 14:55:00,104.06742990565239 2014-04-09 15:00:00,91.43991767184286 2014-04-09 15:05:00,94.12818696333333 2014-04-09 15:10:00,94.64637269232381 2014-04-09 15:15:00,96.69077760411429 2014-04-09 15:20:00,103.35695220000477 2014-04-09 15:25:00,96.70352064249523 2014-04-09 15:30:00,93.8005195538857 2014-04-09 15:35:00,91.5733691733762 2014-04-09 15:40:00,91.81283123036667 2014-04-09 15:45:00,102.70905449495714 2014-04-09 15:50:00,97.67263595384762 2014-04-09 15:55:00,102.18208330583809 2014-04-09 16:00:00,101.48786331982858 2014-04-09 16:05:00,92.74452603741905 2014-04-09 16:10:00,92.87237384140953 2014-04-09 16:15:00,102.6790608028 2014-04-09 16:20:00,102.14132277459046 2014-04-09 16:25:00,96.65697336928095 2014-04-09 16:30:00,91.85468702347143 2014-04-09 16:35:00,90.81694164026192 2014-04-09 16:40:00,95.24131648015238 2014-04-09 16:45:00,90.78581071124286 2014-04-09 16:50:00,94.32684996313333 2014-04-09 16:55:00,97.3651345258238 2014-04-09 17:00:00,92.60333813671429 2014-04-09 17:05:00,92.33657059850476 2014-04-09 17:10:00,105.01856105389524 2014-04-09 17:15:00,100.0505249334857 2014-04-09 17:20:00,105.64173378937619 2014-04-09 17:25:00,96.23110551446666 2014-04-09 17:30:00,101.53964433175715 2014-04-09 17:35:00,93.98783550734763 2014-04-09 17:40:00,100.61365172463809 2014-04-09 17:45:00,92.80102180742857 2014-04-09 17:50:00,90.76838161361906 2014-04-09 17:55:00,105.64703497500953 2014-04-09 18:00:00,51.1013177961 2014-04-09 18:05:00,53.48985404939047 2014-04-09 18:10:00,49.70139676428096 2014-04-09 18:15:00,49.67014633887143 2014-04-09 18:20:00,50.143947894161904 2014-04-09 18:25:00,52.105858281052384 2014-04-09 18:30:00,51.21581189104286 2014-04-09 18:35:00,53.524348072133336 2014-04-09 18:40:00,47.77234001592381 2014-04-09 18:45:00,52.14941188891429 2014-04-09 18:50:00,49.73849603830476 2014-04-09 18:55:00,48.78533485869524 2014-04-09 19:00:00,41.28585687178571 2014-04-09 19:05:00,41.26941071357619 2014-04-09 19:10:00,39.62797493556667 2014-04-09 19:15:00,39.926100318757136 2014-04-09 19:20:00,40.857624111547615 2014-04-09 19:25:00,40.8679620163381 2014-04-09 19:30:00,40.46658785292857 2014-04-09 19:35:00,39.71685018391905 2014-04-09 19:40:00,39.07840249920952 2014-04-09 19:45:00,43.412901735300004 2014-04-09 19:50:00,43.300565687490476 2014-04-09 19:55:00,41.24788342628095 2014-04-09 20:00:00,41.43630313987143 2014-04-09 20:05:00,40.127299789361906 2014-04-09 20:10:00,37.65749263045238 2014-04-09 20:15:00,37.86506637364286 2014-04-09 20:20:00,41.142723083633335 2014-04-09 20:25:00,39.97846737742381 2014-04-09 20:30:00,40.85889415791428 2014-04-09 20:35:00,41.09196698150476 2014-04-09 20:40:00,39.254865473095236 2014-04-09 20:45:00,37.62629778838571 2014-04-09 20:50:00,38.20617226907619 2014-04-09 20:55:00,37.715095138366664 2014-04-09 21:00:00,37.862840284557144 2014-04-09 21:05:00,38.76171150874762 2014-04-09 21:10:00,37.594194670638096 2014-04-09 21:15:00,37.79671279512857 2014-04-09 21:20:00,38.925865905519046 2014-04-09 21:25:00,38.508674560009524 2014-04-09 21:30:00,39.028511483900004 2014-04-09 21:35:00,38.881268641690475 2014-04-09 21:40:00,39.75406698378096 2014-04-09 21:45:00,40.93797360997142 2014-04-09 21:50:00,37.612190208561906 2014-04-09 21:55:00,37.58504872785238 2014-04-09 22:00:00,40.53892206644286 2014-04-09 22:05:00,39.15939470543333 2014-04-09 22:10:00,40.207866888723814 2014-04-09 22:15:00,38.00925911101429 2014-04-09 22:20:00,40.47281787640476 2014-04-09 22:25:00,40.86055929519524 2014-04-09 22:30:00,39.71343802118571 2014-04-09 22:35:00,37.60042884277619 2014-04-09 22:40:00,40.76856384476666 2014-04-09 22:45:00,40.364381194757144 2014-04-09 22:50:00,40.205222085447616 2014-04-09 22:55:00,37.35332187813809 2014-04-09 23:00:00,40.39634827362857 2014-04-09 23:05:00,37.75923503401905 2014-04-09 23:10:00,38.10448101930952 2014-04-09 23:15:00,39.531188577 2014-04-09 23:20:00,38.289773071190474 2014-04-09 23:25:00,39.882987690980954 2014-04-09 23:30:00,39.67727621547142 2014-04-09 23:35:00,37.68464935386191 2014-04-09 23:40:00,39.88397051645238 2014-04-09 23:45:00,40.96337809164285 2014-04-09 23:50:00,37.918852684633336 2014-04-09 23:55:00,39.670436434923815 2014-04-10 00:00:00,38.65317577341428 2014-04-10 00:05:00,39.13160144900476 2014-04-10 00:10:00,38.44859595439524 2014-04-10 00:15:00,38.72455825968571 2014-04-10 00:20:00,37.43112348357619 2014-04-10 00:25:00,41.24912361836667 2014-04-10 00:30:00,39.82955683115714 2014-04-10 00:35:00,39.34061998104762 2014-04-10 00:40:00,38.88009949323809 2014-04-10 00:45:00,39.510176806728566 2014-04-10 00:50:00,38.88054304251905 2014-04-10 00:55:00,38.80719123380952 2014-04-10 01:00:00,39.2307861669 2014-04-10 01:05:00,38.48637261089047 2014-04-10 01:10:00,38.11008055228095 2014-04-10 01:15:00,39.62374502127143 2014-04-10 01:20:00,40.775823649361904 2014-04-10 01:25:00,38.023515091852374 2014-04-10 01:30:00,37.55058021954286 2014-04-10 01:35:00,38.414330313933334 2014-04-10 01:40:00,41.353406383323815 2014-04-10 01:45:00,40.756996580714286 2014-04-10 01:50:00,39.83286897600476 2014-04-10 01:55:00,41.17384089909524 2014-04-10 02:00:00,39.24540218158571 2014-04-10 02:05:00,41.40484860077619 2014-04-10 02:10:00,38.66437484716666 2014-04-10 02:15:00,38.44783014095714 2014-04-10 02:20:00,40.04624042364762 2014-04-10 02:25:00,39.014103967038096 2014-04-10 02:30:00,40.01439073932857 2014-04-10 02:35:00,38.73635112081905 2014-04-10 02:40:00,39.99548255120952 2014-04-10 02:45:00,38.6342350423 2014-04-10 02:50:00,37.74257875149047 2014-04-10 02:55:00,41.194674560080955 2014-04-10 03:00:00,41.086392236071426 2014-04-10 03:05:00,41.444204501861904 2014-04-10 03:10:00,40.43456108585238 2014-04-10 03:15:00,40.30677756804286 2014-04-10 03:20:00,39.81934561363333 2014-04-10 03:25:00,38.09454347492381 2014-04-10 03:30:00,38.355155529514285 2014-04-10 03:35:00,38.76353351660476 2014-04-10 03:40:00,41.173720688395235 2014-04-10 03:45:00,38.31241381268571 2014-04-10 03:50:00,41.319468888476194 2014-04-10 03:55:00,39.726559598866665 2014-04-10 04:00:00,40.50513568475714 2014-04-10 04:05:00,38.09127556574762 2014-04-10 04:10:00,38.7338722903381 2014-04-10 04:15:00,41.49925300412857 2014-04-10 04:20:00,38.73721883531905 2014-04-10 04:25:00,38.86614640540952 2014-04-10 04:30:00,38.477889539399996 2014-04-10 04:35:00,38.211235137390474 2014-04-10 04:40:00,38.63541151818095 2014-04-10 04:45:00,40.279128996371426 2014-04-10 04:50:00,39.5387328387619 2014-04-10 04:55:00,39.93972572635238 2014-04-10 05:00:00,38.221602172242854 2014-04-10 05:05:00,40.94804912203333 2014-04-10 05:10:00,40.88340261182381 2014-04-10 05:15:00,37.840823930314286 2014-04-10 05:20:00,39.29596513990476 2014-04-10 05:25:00,38.04442764599524 2014-04-10 05:30:00,40.94520883198571 2014-04-10 05:35:00,40.73330492297619 2014-04-10 05:40:00,41.399619043866664 2014-04-10 05:45:00,38.74472297865714 2014-04-10 05:50:00,39.63173115154761 2014-04-10 05:55:00,38.551939603938095 2014-04-10 06:00:00,39.30636830932857 2014-04-10 06:05:00,39.917842053919045 2014-04-10 06:10:00,38.04963268320952 2014-04-10 06:15:00,40.703231642700004 2014-04-10 06:20:00,40.02436391769048 2014-04-10 06:25:00,41.17446702118095 2014-04-10 06:30:00,38.953193433371425 2014-04-10 06:35:00,41.4867963258619 2014-04-10 06:40:00,41.87572939305238 2014-04-10 06:45:00,41.56558661064285 2014-04-10 06:50:00,41.00740323663333 2014-04-10 06:55:00,41.15274902102381 2014-04-10 07:00:00,40.20569125591429 2014-04-10 07:05:00,38.678770213604764 2014-04-10 07:10:00,40.633757978695236 2014-04-10 07:15:00,40.78404772248571 2014-04-10 07:20:00,41.88201675157619 2014-04-10 07:25:00,40.11312193166667 2014-04-10 07:30:00,39.040833202957145 2014-04-10 07:35:00,40.69748770604762 2014-04-10 07:40:00,41.8877413739381 2014-04-10 07:45:00,38.68653420452857 2014-04-10 07:50:00,39.28911072171905 2014-04-10 07:55:00,40.16008333890952 2014-04-10 08:00:00,38.6808585395 2014-04-10 08:05:00,38.09632303429048 2014-04-10 08:10:00,39.36281344218095 2014-04-10 08:15:00,41.48380463457143 2014-04-10 08:20:00,38.20363550206191 2014-04-10 08:25:00,39.75291861705238 2014-04-10 08:30:00,41.093445948842856 2014-04-10 08:35:00,41.864813720933334 2014-04-10 08:40:00,42.001425405523804 2014-04-10 08:45:00,39.754841808114286 2014-04-10 08:50:00,41.875941939404754 2014-04-10 08:55:00,38.22352113119524 2014-04-10 09:00:00,91.43375607108571 2014-04-10 09:05:00,90.03807226147619 2014-04-10 09:10:00,84.69766392986665 2014-04-10 09:15:00,88.21113875205714 2014-04-10 09:20:00,83.08097845254763 2014-04-10 09:25:00,93.1802093481381 2014-04-10 09:30:00,86.20134253482857 2014-04-10 09:35:00,89.85557384591905 2014-04-10 09:40:00,83.50816701730953 2014-04-10 09:45:00,84.160091887 2014-04-10 09:50:00,94.85429711909046 2014-04-10 09:55:00,91.61310591678094 2014-04-10 10:00:00,104.94837484747143 2014-04-10 10:05:00,94.61762198886191 2014-04-10 10:10:00,92.58746822605238 2014-04-10 10:15:00,97.84851541034286 2014-04-10 10:20:00,97.72558507353334 2014-04-10 10:25:00,92.77094370302382 2014-04-10 10:30:00,101.44278200561428 2014-04-10 10:35:00,95.68544209640476 2014-04-10 10:40:00,92.97048362209523 2014-04-10 10:45:00,95.23791799758571 2014-04-10 10:50:00,98.84095920877618 2014-04-10 10:55:00,101.37524553406666 2014-04-10 11:00:00,99.49984979475714 2014-04-10 11:05:00,100.20236033724761 2014-04-10 11:10:00,94.06053426043809 2014-04-10 11:15:00,106.40542303802857 2014-04-10 11:20:00,106.63604869251905 2014-04-10 11:25:00,102.74227601780952 2014-04-10 11:30:00,92.1609099277 2014-04-10 11:35:00,100.42956880589048 2014-04-10 11:40:00,101.90247948448095 2014-04-10 11:45:00,107.72180219047144 2014-04-10 11:50:00,107.75171076016193 2014-04-10 11:55:00,105.55715146755237 2014-04-10 12:00:00,93.29081317454286 2014-04-10 12:05:00,107.51230267913333 2014-04-10 12:10:00,102.07644066802382 2014-04-10 12:15:00,105.09187558741428 2014-04-10 12:20:00,98.80777225420475 2014-04-10 12:25:00,97.41651912399524 2014-04-10 12:30:00,99.7183977543857 2014-04-10 12:35:00,94.66999840737618 2014-04-10 12:40:00,98.03646921686666 2014-04-10 12:45:00,106.04312088315713 2014-04-10 12:50:00,92.95162674984762 2014-04-10 12:55:00,94.76373998593809 2014-04-10 13:00:00,94.43052667972857 2014-04-10 13:05:00,98.88424992071906 2014-04-10 13:10:00,108.3919915084095 2014-04-10 13:15:00,95.2245311889 2014-04-10 13:20:00,94.78607421639049 2014-04-10 13:25:00,107.10372881478095 2014-04-10 13:30:00,106.58321262607143 2014-04-10 13:35:00,92.9969540216619 2014-04-10 13:40:00,104.51308119295238 2014-04-10 13:45:00,102.98104709244286 2014-04-10 13:50:00,104.7844581662333 2014-04-10 13:55:00,100.4211341968238 2014-04-10 14:00:00,108.3935644016143 2014-04-10 14:05:00,93.24121738680476 2014-04-10 14:10:00,96.29690462319525 2014-04-10 14:15:00,98.8990109585857 2014-04-10 14:20:00,99.75812182607619 2014-04-10 14:25:00,107.31063149966667 2014-04-10 14:30:00,101.53654088475713 2014-04-10 14:35:00,93.30608290214762 2014-04-10 14:40:00,99.11727627133808 2014-04-10 14:45:00,99.26274930472857 2014-04-10 14:50:00,108.05377656561905 2014-04-10 14:55:00,102.20079679680953 2014-04-10 15:00:00,102.7946283025 2014-04-10 15:05:00,104.04368822059047 2014-04-10 15:10:00,104.95970052528095 2014-04-10 15:15:00,102.80734980797142 2014-04-10 15:20:00,96.44914388986192 2014-04-10 15:25:00,106.64611155695238 2014-04-10 15:30:00,104.38275601014287 2014-04-10 15:35:00,104.54620594353334 2014-04-10 15:40:00,108.62858736612381 2014-04-10 15:45:00,105.5315743754143 2014-04-10 15:50:00,105.96500865470476 2014-04-10 15:55:00,107.92849615359523 2014-04-10 16:00:00,95.13228682898571 2014-04-10 16:05:00,100.6852106839762 2014-04-10 16:10:00,102.01808296906665 2014-04-10 16:15:00,98.00487045505714 2014-04-10 16:20:00,106.17433709484762 2014-04-10 16:25:00,104.9500403800381 2014-04-10 16:30:00,104.29289737802857 2014-04-10 16:35:00,108.72059121131906 2014-04-10 16:40:00,96.92376529010951 2014-04-10 16:45:00,104.54840519359999 2014-04-10 16:50:00,101.61100689549048 2014-04-10 16:55:00,97.80381001728095 2014-04-10 17:00:00,95.37293272547143 2014-04-10 17:05:00,107.14512014556192 2014-04-10 17:10:00,102.34570879775238 2014-04-10 17:15:00,106.02480154304287 2014-04-10 17:20:00,101.55882207873333 2014-04-10 17:25:00,96.36037810042382 2014-04-10 17:30:00,98.2489655734143 2014-04-10 17:35:00,98.96024624930476 2014-04-10 17:40:00,108.43001861239524 2014-04-10 17:45:00,92.9606404857857 2014-04-10 17:50:00,108.6485988549762 2014-04-10 17:55:00,108.57276915646665 2014-04-10 18:00:00,56.06821544855714 2014-04-10 18:05:00,52.75045584894761 2014-04-10 18:10:00,55.876108786838095 2014-04-10 18:15:00,52.247007319528564 2014-04-10 18:20:00,49.89089790601905 2014-04-10 18:25:00,51.165875711309525 2014-04-10 18:30:00,55.7873892764 2014-04-10 18:35:00,49.83302896699047 2014-04-10 18:40:00,53.24673721858095 2014-04-10 18:45:00,50.24366597497142 2014-04-10 18:50:00,51.600194125161906 2014-04-10 18:55:00,50.33849098765238 2014-04-10 19:00:00,44.992829762542854 2014-04-10 19:05:00,43.797578861333335 2014-04-10 19:10:00,45.1984594483238 2014-04-10 19:15:00,44.24828534461429 2014-04-10 19:20:00,45.522113925304765 2014-04-10 19:25:00,43.46359590019524 2014-04-10 19:30:00,44.04820785768571 2014-04-10 19:35:00,43.77608845597619 2014-04-10 19:40:00,43.371152165666665 2014-04-10 19:45:00,44.99900378615715 2014-04-10 19:50:00,44.10401896254761 2014-04-10 19:55:00,44.81386573893809 2014-04-10 20:00:00,42.72437499592857 2014-04-10 20:05:00,40.29338979511905 2014-04-10 20:10:00,42.18137909990952 2014-04-10 20:15:00,40.3435080556 2014-04-10 20:20:00,41.92247090519048 2014-04-10 20:25:00,42.31540316538096 2014-04-10 20:30:00,43.63274601157143 2014-04-10 20:35:00,39.680611624561905 2014-04-10 20:40:00,39.93668100155238 2014-04-10 20:45:00,39.88589398054286 2014-04-10 20:50:00,41.20952092113333 2014-04-10 20:55:00,42.950499476623804 2014-04-10 21:00:00,42.63954544591428 2014-04-10 21:05:00,42.21662310150476 2014-04-10 21:10:00,42.86672821459524 2014-04-10 21:15:00,40.56707435448571 2014-04-10 21:20:00,39.63118729157619 2014-04-10 21:25:00,39.51804527196666 2014-04-10 21:30:00,42.71664891695714 2014-04-10 21:35:00,42.23496712184762 2014-04-10 21:40:00,42.1145126820381 2014-04-10 21:45:00,40.67930566372857 2014-04-10 21:50:00,40.84843393371905 2014-04-10 21:55:00,43.17980936550953 2014-04-10 22:00:00,39.5227439776 2014-04-10 22:05:00,42.372618543490475 2014-04-10 22:10:00,40.52188322968095 2014-04-10 22:15:00,39.445969863071426 2014-04-10 22:20:00,42.2701738066619 2014-04-10 22:25:00,40.629400615852376 2014-04-10 22:30:00,42.203285968342854 2014-04-10 22:35:00,42.15269824843333 2014-04-10 22:40:00,41.46800488292381 2014-04-10 22:45:00,42.446721905014286 2014-04-10 22:50:00,41.668069235804765 2014-04-10 22:55:00,40.49677332559524 2014-04-10 23:00:00,42.27976671708571 2014-04-10 23:05:00,41.707193911376194 2014-04-10 23:10:00,39.40854156616666 2014-04-10 23:15:00,42.97233231455714 2014-04-10 23:20:00,41.55549714464762 2014-04-10 23:25:00,42.8551202607381 2014-04-10 23:30:00,42.91900986712857 2014-04-10 23:35:00,41.17503340701904 2014-04-10 23:40:00,41.43329539050953 2014-04-10 23:45:00,41.0730428481 2014-04-10 23:50:00,41.21523874289048 2014-04-10 23:55:00,43.00586305918095 2014-04-11 00:00:00,42.58114748447143 2014-04-11 00:05:00,39.94211461006191 2014-04-11 00:10:00,41.884683507152374 2014-04-11 00:15:00,43.43451941864286 2014-04-11 00:20:00,41.84053613823333 2014-04-11 00:25:00,42.609260311923805 2014-04-11 00:30:00,42.54946017921428 2014-04-11 00:35:00,40.881924865404756 2014-04-11 00:40:00,40.97549244889524 2014-04-11 00:45:00,42.39184140148571 2014-04-11 00:50:00,41.50291031687619 2014-04-11 00:55:00,41.792699503166666 2014-04-11 01:00:00,42.36948030435714 2014-04-11 01:05:00,42.635597727247614 2014-04-11 01:10:00,40.618804406138096 2014-04-11 01:15:00,40.12735360912857 2014-04-11 01:20:00,40.714797634519044 2014-04-11 01:25:00,41.58521282420952 2014-04-11 01:30:00,40.931065269200005 2014-04-11 01:35:00,41.843391511590475 2014-04-11 01:40:00,39.79124384888095 2014-04-11 01:45:00,41.62382307507143 2014-04-11 01:50:00,41.06420153256191 2014-04-11 01:55:00,41.73836940055238 2014-04-11 02:00:00,41.29727627664286 2014-04-11 02:05:00,40.751486735933334 2014-04-11 02:10:00,43.2384554313238 2014-04-11 02:15:00,40.368524239414285 2014-04-11 02:20:00,42.36236706420476 2014-04-11 02:25:00,43.342924088395236 2014-04-11 02:30:00,41.80646555298571 2014-04-11 02:35:00,43.164860144776185 2014-04-11 02:40:00,40.16607258036666 2014-04-11 02:45:00,41.64926222385714 2014-04-11 02:50:00,41.50964874094762 2014-04-11 02:55:00,39.7214633233381 2014-04-11 03:00:00,41.46945793682857 2014-04-11 03:05:00,41.17998807311905 2014-04-11 03:10:00,42.390504434909516 2014-04-11 03:15:00,43.4720691143 2014-04-11 03:20:00,40.06935482919047 2014-04-11 03:25:00,41.043536499280954 2014-04-11 03:30:00,41.51733037817142 2014-04-11 03:35:00,41.569253416861905 2014-04-11 03:40:00,42.85519126435238 2014-04-11 03:45:00,41.53697552044286 2014-04-11 03:50:00,39.87947853913333 2014-04-11 03:55:00,42.618690187923804 2014-04-11 04:00:00,43.32503306631428 2014-04-11 04:05:00,41.84877361210476 2014-04-11 04:10:00,42.12502932489524 2014-04-11 04:15:00,40.45978147018571 2014-04-11 04:20:00,40.698059969176185 2014-04-11 04:25:00,40.76359762316666 2014-04-11 04:30:00,41.553325042357145 2014-04-11 04:35:00,43.55037850264762 2014-04-11 04:40:00,41.932377162138096 2014-04-11 04:45:00,40.62106915222857 2014-04-11 04:50:00,40.92446999111905 2014-04-11 04:55:00,41.40361964270952 2014-04-11 05:00:00,42.3680359028 2014-04-11 05:05:00,41.642573088190474 2014-04-11 05:10:00,41.459660329080954 2014-04-11 05:15:00,42.156235830171426 2014-04-11 05:20:00,40.8721018845619 2014-04-11 05:25:00,40.227815471252384 2014-04-11 05:30:00,40.017300116442854 2014-04-11 05:35:00,40.932119987233335 2014-04-11 05:40:00,40.30089194612381 2014-04-11 05:45:00,41.287326839814284 2014-04-11 05:50:00,43.04113892330476 2014-04-11 05:55:00,42.82202255999523 2014-04-11 06:00:00,42.40799620548571 2014-04-11 06:05:00,43.38172716597619 2014-04-11 06:10:00,41.10743716486667 2014-04-11 06:15:00,43.526822154957145 2014-04-11 06:20:00,41.59100429774762 2014-04-11 06:25:00,41.6050613683381 2014-04-11 06:30:00,41.630335025928574 2014-04-11 06:35:00,40.40874651261905 2014-04-11 06:40:00,43.925771517109524 2014-04-11 06:45:00,40.5852771113 2014-04-11 06:50:00,41.40223337409047 2014-04-11 06:55:00,41.32333223368096 2014-04-11 07:00:00,40.35228915987143 2014-04-11 07:05:00,40.670052425161906 2014-04-11 07:10:00,40.24788572565238 2014-04-11 07:15:00,41.245510831342855 2014-04-11 07:20:00,43.549961029433334 2014-04-11 07:25:00,41.44854263242381 2014-04-11 07:30:00,40.592981614014285 2014-04-11 07:35:00,42.68843023540476 2014-04-11 07:40:00,44.09949888629524 2014-04-11 07:45:00,41.04983087238571 2014-04-11 07:50:00,41.24626021197619 2014-04-11 07:55:00,44.02280488376667 2014-04-11 08:00:00,40.85796229305714 2014-04-11 08:05:00,42.195153888847614 2014-04-11 08:10:00,41.116346627338096 2014-04-11 08:15:00,43.89458616302856 2014-04-11 08:20:00,44.09870310591904 2014-04-11 08:25:00,43.43885090830952 2014-04-11 08:30:00,41.446635263299996 2014-04-11 08:35:00,41.808890377290474 2014-04-11 08:40:00,41.17160368708095 2014-04-11 08:45:00,43.77285329657143 2014-04-11 08:50:00,43.8754950155619 2014-04-11 08:55:00,41.90018502995238 2014-04-11 09:00:00,150.11416299114285 2014-04-11 09:05:00,137.94530219133333 2014-04-11 09:10:00,144.6334341385238 2014-04-11 09:15:00,149.5156421317143 2014-04-11 09:20:00,143.41990210090475 2014-04-11 09:25:00,142.73781347509524 2014-04-11 09:30:00,133.9015607222857 2014-04-11 09:35:00,153.8307040924762 2014-04-11 09:40:00,155.94723944466665 2014-04-11 09:45:00,157.94180267585713 2014-04-11 09:50:00,151.7444779690476 2014-04-11 09:55:00,147.5240374422381 2014-04-11 10:00:00,160.43990826542858 2014-04-11 10:05:00,181.58858187161903 2014-04-11 10:10:00,169.73555219080953 2014-04-11 10:15:00,172.389971935 2014-04-11 10:20:00,172.43367292619047 2014-04-11 10:25:00,177.15712295738098 2014-04-11 10:30:00,152.9661881535714 2014-04-11 10:35:00,159.0718632997619 2014-04-11 10:40:00,171.97481702595238 2014-04-11 10:45:00,178.63181339514284 2014-04-11 10:50:00,172.56324445733333 2014-04-11 10:55:00,164.6979816115238 2014-04-11 11:00:00,167.24617561871426 2014-04-11 11:05:00,178.46710182490474 2014-04-11 11:10:00,178.57254871109524 2014-04-11 11:15:00,174.58250742728572 2014-04-11 11:20:00,165.1878617724762 2014-04-11 11:25:00,184.07412901666666 2014-04-11 11:30:00,172.96096437885714 2014-04-11 11:35:00,180.07714589604763 2014-04-11 11:40:00,162.9189098412381 2014-04-11 11:45:00,166.79134174542855 2014-04-11 11:50:00,182.60459199961903 2014-04-11 11:55:00,158.0493481598095 2014-04-11 12:00:00,172.660947021 2014-04-11 12:05:00,171.7513659231905 2014-04-11 12:10:00,179.83333544338097 2014-04-11 12:15:00,165.78020776557142 2014-04-11 12:20:00,163.9054533807619 2014-04-11 12:25:00,185.09546041795238 2014-04-11 12:30:00,174.48494929414287 2014-04-11 12:35:00,160.50121529533334 2014-04-11 12:40:00,163.1553783715238 2014-04-11 12:45:00,187.30299490671428 2014-04-11 12:50:00,163.24733731490474 2014-04-11 12:55:00,175.68351479709523 2014-04-11 13:00:00,170.1521926182857 2014-04-11 13:05:00,184.1198908514762 2014-04-11 13:10:00,180.21550143266666 2014-04-11 13:15:00,175.47774239485716 2014-04-11 13:20:00,157.90368772504763 2014-04-11 13:25:00,183.9755844242381 2014-04-11 13:30:00,170.93281306342857 2014-04-11 13:35:00,185.54350791161903 2014-04-11 13:40:00,172.47341702480952 2014-04-11 13:45:00,178.439768728 2014-04-11 13:50:00,159.70445344519047 2014-04-11 13:55:00,179.98204089638097 2014-04-11 14:00:00,167.81040194257142 2014-04-11 14:05:00,168.2187096737619 2014-04-11 14:10:00,161.24544227895237 2014-04-11 14:15:00,162.09887494614287 2014-04-11 14:20:00,163.27330791633332 2014-04-11 14:25:00,167.5539247315238 2014-04-11 14:30:00,184.47333943071428 2014-04-11 14:35:00,168.77036112390476 2014-04-11 14:40:00,179.46028309509524 2014-04-11 14:45:00,160.2203351392857 2014-04-11 14:50:00,175.47746858047617 2014-04-11 14:55:00,172.20886373766666 2014-04-11 15:00:00,187.10477248685714 2014-04-11 15:05:00,183.1597514970476 2014-04-11 15:10:00,171.4259823012381 2014-04-11 15:15:00,181.04270592542855 2014-04-11 15:20:00,163.58721944361903 2014-04-11 15:25:00,174.67346459980953 2014-04-11 15:30:00,160.04954923399998 2014-04-11 15:35:00,168.26099800019048 2014-04-11 15:40:00,164.60167363438097 2014-04-11 15:45:00,179.40037903557143 2014-04-11 15:50:00,172.5433219387619 2014-04-11 15:55:00,180.38006918995237 2014-04-11 16:00:00,173.31567216814287 2014-04-11 16:05:00,160.45881132133334 2014-04-11 16:10:00,179.9327048355238 2014-04-11 16:15:00,182.87598722571428 2014-04-11 16:20:00,184.99248187990474 2014-04-11 16:25:00,175.05376600509524 2014-04-11 16:30:00,180.50899680528573 2014-04-11 16:35:00,180.4702067204762 2014-04-11 16:40:00,162.58884957366666 2014-04-11 16:45:00,162.85041731585713 2014-04-11 16:50:00,160.05780855504761 2014-04-11 16:55:00,167.5360763362381 2014-04-11 17:00:00,172.15161999642856 2014-04-11 17:05:00,187.89073144261903 2014-04-11 17:10:00,170.8910441448095 2014-04-11 17:15:00,179.755958083 2014-04-11 17:20:00,178.77803213019047 2014-04-11 17:25:00,164.11802683438097 2014-04-11 17:30:00,159.7462252895714 2014-04-11 17:35:00,174.3786472787619 2014-04-11 17:40:00,179.01505092395237 2014-04-11 17:45:00,187.96087337014285 2014-04-11 17:50:00,168.77910022433335 2014-04-11 17:55:00,184.9191388355238 2014-04-11 18:00:00,67.94947988201429 2014-04-11 18:05:00,70.78572866320476 2014-04-11 18:10:00,69.95450862529523 2014-04-11 18:15:00,64.94542849078572 2014-04-11 18:20:00,65.1866375290762 2014-04-11 18:25:00,64.66393425606667 2014-04-11 18:30:00,67.89201775305715 2014-04-11 18:35:00,71.34915330124763 2014-04-11 18:40:00,66.0845752792381 2014-04-11 18:45:00,70.07651228672856 2014-04-11 18:50:00,67.16732187411904 2014-04-11 18:55:00,71.84987756170952 2014-04-11 19:00:00,49.828913769699994 2014-04-11 19:05:00,49.72052682259047 2014-04-11 19:10:00,48.46503918628095 2014-04-11 19:15:00,47.26153509967143 2014-04-11 19:20:00,49.91435705876191 2014-04-11 19:25:00,46.780146717852375 2014-04-11 19:30:00,47.31002870094285 2014-04-11 19:35:00,46.78417727823333 2014-04-11 19:40:00,49.2625402627238 2014-04-11 19:45:00,49.330591105814285 2014-04-11 19:50:00,49.16805238190476 2014-04-11 19:55:00,47.98147401359524 2014-04-11 20:00:00,42.571804822685706 2014-04-11 20:05:00,45.99192722587619 2014-04-11 20:10:00,44.30169802996666 2014-04-11 20:15:00,43.88514561645714 2014-04-11 20:20:00,44.65782222784762 2014-04-11 20:25:00,42.99874974943809 2014-04-11 20:30:00,42.752693340528566 2014-04-11 20:35:00,43.90881865711905 2014-04-11 20:40:00,43.16595370110952 2014-04-11 20:45:00,43.2452230542 2014-04-11 20:50:00,45.980378242490474 2014-04-11 20:55:00,44.465565034180955 2014-04-11 21:00:00,43.44475989277143 2014-04-11 21:05:00,44.28481252026191 2014-04-11 21:10:00,45.351429121052384 2014-04-11 21:15:00,41.966554477042855 2014-04-11 21:20:00,44.88934652613334 2014-04-11 21:25:00,43.88834561862381 2014-04-11 21:30:00,42.12615608071428 2014-04-11 21:35:00,42.74381334610476 2014-04-11 21:40:00,43.49980703279524 2014-04-11 21:45:00,44.35119715128572 2014-04-11 21:50:00,42.54569660917619 2014-04-11 21:55:00,43.73438278006667 2014-04-11 22:00:00,44.17468009835714 2014-04-11 22:05:00,43.23643412444761 2014-04-11 22:10:00,44.9044622928381 2014-04-11 22:15:00,44.93768885962857 2014-04-11 22:20:00,43.34674004791905 2014-04-11 22:25:00,45.36729708400952 2014-04-11 22:30:00,41.7779092181 2014-04-11 22:35:00,41.495857945290474 2014-04-11 22:40:00,43.01566114678096 2014-04-11 22:45:00,43.90665077987143 2014-04-11 22:50:00,44.0267374580619 2014-04-11 22:55:00,43.421889333452384 2014-04-11 23:00:00,41.989371912042856 2014-04-11 23:05:00,42.17934512433333 2014-04-11 23:10:00,44.9145217146238 2014-04-11 23:15:00,44.98504101221428 2014-04-11 23:20:00,44.21610827610476 2014-04-11 23:25:00,44.18481038149524 2014-04-11 23:30:00,43.92599676508571 2014-04-11 23:35:00,42.35375539797619 2014-04-11 23:40:00,43.262870072666665 2014-04-11 23:45:00,44.34133171295714 2014-04-11 23:50:00,43.71393869054762 2014-04-11 23:55:00,41.645828345238094 2014-04-12 00:00:00,45.38565579832857 2014-04-12 00:05:00,44.958133257919044 2014-04-12 00:10:00,42.62848958020952 2014-04-12 00:15:00,44.0595857407 2014-04-12 00:20:00,45.29414801109047 2014-04-12 00:25:00,41.99267500088095 2014-04-12 00:30:00,43.628189351771425 2014-04-12 00:35:00,43.448484008161905 2014-04-12 00:40:00,43.27177240205238 2014-04-12 00:45:00,44.980747292742855 2014-04-12 00:50:00,43.16841792013334 2014-04-12 00:55:00,41.9079271425238 2014-04-12 01:00:00,41.92406525441429 2014-04-12 01:05:00,41.83913318800476 2014-04-12 01:10:00,43.31217692559524 2014-04-12 01:15:00,44.556660825085714 2014-04-12 01:20:00,42.50536603817619 2014-04-12 01:25:00,44.28379074836667 2014-04-12 01:30:00,44.45371103125714 2014-04-12 01:35:00,42.733606115147616 2014-04-12 01:40:00,44.122468719438096 2014-04-12 01:45:00,44.46715193152857 2014-04-12 01:50:00,43.601573538819046 2014-04-12 01:55:00,43.08942591290952 2014-04-12 02:00:00,44.226606206300005 2014-04-12 02:05:00,45.66882882549047 2014-04-12 02:10:00,43.47224658988095 2014-04-12 02:15:00,43.33926181367143 2014-04-12 02:20:00,43.63682951446191 2014-04-12 02:25:00,42.09207595475238 2014-04-12 02:30:00,44.00729597584285 2014-04-12 02:35:00,43.11687288223334 2014-04-12 02:40:00,42.295212298823806 2014-04-12 02:45:00,43.68199125021428 2014-04-12 02:50:00,41.83794070820476 2014-04-12 02:55:00,43.438986218795236 2014-04-12 03:00:00,42.26222678598572 2014-04-12 03:05:00,41.94389700407619 2014-04-12 03:10:00,45.15206685166666 2014-04-12 03:15:00,45.52660235595714 2014-04-12 03:20:00,42.699746212447614 2014-04-12 03:25:00,44.033681150538094 2014-04-12 03:30:00,42.995761199928566 2014-04-12 03:35:00,43.86567880231905 2014-04-12 03:40:00,43.645334807409526 2014-04-12 03:45:00,42.9824542203 2014-04-12 03:50:00,44.71526479469047 2014-04-12 03:55:00,42.42709478968095 2014-04-12 04:00:00,42.140862557271426 2014-04-12 04:05:00,45.0067136368619 2014-04-12 04:10:00,44.607172505852375 2014-04-12 04:15:00,43.944997353742856 2014-04-12 04:20:00,43.82949241523333 2014-04-12 04:25:00,43.955419327523806 2014-04-12 04:30:00,43.721310590114285 2014-04-12 04:35:00,43.55222394520476 2014-04-12 04:40:00,43.98685764959524 2014-04-12 04:45:00,44.109596398885714 2014-04-12 04:50:00,44.770585446776195 2014-04-12 04:55:00,44.85524530956667 2014-04-12 05:00:00,43.52837346345714 2014-04-12 05:05:00,43.67945971004762 2014-04-12 05:10:00,43.527526774138096 2014-04-12 05:15:00,44.186321665928574 2014-04-12 05:20:00,43.86103319931905 2014-04-12 05:25:00,45.61344537630952 2014-04-12 05:30:00,44.847945067699996 2014-04-12 05:35:00,45.66456601119047 2014-04-12 05:40:00,44.91392891858095 2014-04-12 05:45:00,45.96879002267143 2014-04-12 05:50:00,44.63520901776191 2014-04-12 05:55:00,45.95390293365238 2014-04-12 06:00:00,42.739822418742854 2014-04-12 06:05:00,42.32449405663333 2014-04-12 06:10:00,44.438524550323805 2014-04-12 06:15:00,46.063437108914286 2014-04-12 06:20:00,43.807325751104756 2014-04-12 06:25:00,42.99251868689524 2014-04-12 06:30:00,44.23795151108571 2014-04-12 06:35:00,44.75442068877619 2014-04-12 06:40:00,43.42738144876667 2014-04-12 06:45:00,45.03318457685714 2014-04-12 06:50:00,46.08200564724762 2014-04-12 06:55:00,45.77684058203809 2014-04-12 07:00:00,43.36277006542857 2014-04-12 07:05:00,43.51076378021905 2014-04-12 07:10:00,43.69747442160952 2014-04-12 07:15:00,43.7969611136 2014-04-12 07:20:00,42.62746847299047 2014-04-12 07:25:00,45.28148230798095 2014-04-12 07:30:00,43.70242848297143 2014-04-12 07:35:00,45.76779181156191 2014-04-12 07:40:00,45.963714873452375 2014-04-12 07:45:00,42.36111809434286 2014-04-12 07:50:00,46.22484561303333 2014-04-12 07:55:00,45.118364735523805 2014-04-12 08:00:00,44.367283189714286 2014-04-12 08:05:00,43.85126519540476 2014-04-12 08:10:00,44.374667768495236 2014-04-12 08:15:00,43.60653461018571 2014-04-12 08:20:00,44.80622744527619 2014-04-12 08:25:00,42.69483777246666 2014-04-12 08:30:00,44.814847554457145 2014-04-12 08:35:00,43.439177019647616 2014-04-12 08:40:00,42.41577741143809 2014-04-12 08:45:00,44.56350163612857 2014-04-12 08:50:00,44.67391007101905 2014-04-12 08:55:00,44.07383554260952 2014-04-12 09:00:00,86.5580927627 2014-04-12 09:05:00,97.73190463429049 2014-04-12 09:10:00,93.90533993068095 2014-04-12 09:15:00,87.17102230267143 2014-04-12 09:20:00,92.55341774646192 2014-04-12 09:25:00,92.37486107785237 2014-04-12 09:30:00,86.44110827274287 2014-04-12 09:35:00,93.88037530233332 2014-04-12 09:40:00,96.62776283482381 2014-04-12 09:45:00,95.82847382351429 2014-04-12 09:50:00,88.40978879450476 2014-04-12 09:55:00,97.38402363999523 2014-04-12 10:00:00,99.62054012528571 2014-04-12 10:05:00,109.00153622157619 2014-04-12 10:10:00,95.43269507146667 2014-04-12 10:15:00,101.87256598865714 2014-04-12 10:20:00,103.60141795284763 2014-04-12 10:25:00,98.1850176235381 2014-04-12 10:30:00,106.32074910032857 2014-04-12 10:35:00,104.08578999831904 2014-04-12 10:40:00,94.64486799050952 2014-04-12 10:45:00,103.81313052760001 2014-04-12 10:50:00,102.00643267439048 2014-04-12 10:55:00,97.42850416278095 2014-04-12 11:00:00,111.95795123177143 2014-04-12 11:05:00,110.39747945126189 2014-04-12 11:10:00,100.78849476265238 2014-04-12 11:15:00,104.74908478154285 2014-04-12 11:20:00,101.18498336643333 2014-04-12 11:25:00,108.4922582435238 2014-04-12 11:30:00,110.96220539931429 2014-04-12 11:35:00,101.88046492630475 2014-04-12 11:40:00,108.99310713649524 2014-04-12 11:45:00,104.1152092735857 2014-04-12 11:50:00,102.50316162957618 2014-04-12 11:55:00,111.12807780246666 2014-04-12 12:00:00,104.71313239235714 2014-04-12 12:05:00,104.03349134154762 2014-04-12 12:10:00,107.31737778613811 2014-04-12 12:15:00,100.75351009102857 2014-04-12 12:20:00,101.77666895711904 2014-04-12 12:25:00,111.48849762360952 2014-04-12 12:30:00,107.444549754 2014-04-12 12:35:00,109.81886340729048 2014-04-12 12:40:00,100.94856379748096 2014-04-12 12:45:00,105.31362369577144 2014-04-12 12:50:00,112.15455136826193 2014-04-12 12:55:00,101.73144565055237 2014-04-12 13:00:00,99.28187024854284 2014-04-12 13:05:00,104.89451766263333 2014-04-12 13:10:00,102.9333919961238 2014-04-12 13:15:00,99.2898072337143 2014-04-12 13:20:00,110.95803484780475 2014-04-12 13:25:00,112.59984342709524 2014-04-12 13:30:00,105.85463724978571 2014-04-12 13:35:00,109.15879972567619 2014-04-12 13:40:00,110.51570187206667 2014-04-12 13:45:00,107.99484746825713 2014-04-12 13:50:00,97.49559484564762 2014-04-12 13:55:00,99.31825048723809 2014-04-12 14:00:00,97.95374511012857 2014-04-12 14:05:00,96.98347916631903 2014-04-12 14:10:00,101.72856105870952 2014-04-12 14:15:00,103.1176880383 2014-04-12 14:20:00,100.70402508269046 2014-04-12 14:25:00,97.88879970538095 2014-04-12 14:30:00,105.34001794707143 2014-04-12 14:35:00,101.2429551148619 2014-04-12 14:40:00,109.61347950225237 2014-04-12 14:45:00,97.01377261874285 2014-04-12 14:50:00,110.37216309313332 2014-04-12 14:55:00,112.1751434218238 2014-04-12 15:00:00,108.36807409781429 2014-04-12 15:05:00,108.65565591840476 2014-04-12 15:10:00,111.86175762859523 2014-04-12 15:15:00,100.2774529657857 2014-04-12 15:20:00,112.8526813165762 2014-04-12 15:25:00,109.32280591396665 2014-04-12 15:30:00,108.57968567485713 2014-04-12 15:35:00,102.73950021944762 2014-04-12 15:40:00,105.7019028303381 2014-04-12 15:45:00,107.43957154202857 2014-04-12 15:50:00,106.90981834401906 2014-04-12 15:55:00,108.27151425380951 2014-04-12 16:00:00,98.3179670545 2014-04-12 16:05:00,102.69766623599048 2014-04-12 16:10:00,103.95872964538096 2014-04-12 16:15:00,101.19224394807142 2014-04-12 16:20:00,99.7916546859619 2014-04-12 16:25:00,99.25989955175238 2014-04-12 16:30:00,102.90662763794285 2014-04-12 16:35:00,104.94699714383333 2014-04-12 16:40:00,98.06700667722382 2014-04-12 16:45:00,112.2101264840143 2014-04-12 16:50:00,109.31813617940476 2014-04-12 16:55:00,108.77531291729524 2014-04-12 17:00:00,99.85502540408571 2014-04-12 17:05:00,106.75750712087618 2014-04-12 17:10:00,105.57973491296667 2014-04-12 17:15:00,112.83107499115714 2014-04-12 17:20:00,109.08176369864762 2014-04-12 17:25:00,106.33864704923809 2014-04-12 17:30:00,110.74689835952857 2014-04-12 17:35:00,99.62284878051905 2014-04-12 17:40:00,97.39224625740951 2014-04-12 17:45:00,108.1999514458 2014-04-12 17:50:00,98.73664558799047 2014-04-12 17:55:00,99.01804083488095 2014-04-12 18:00:00,58.74452163307143 2014-04-12 18:05:00,55.71742904516191 2014-04-12 18:10:00,58.01668585855238 2014-04-12 18:15:00,59.87229052724285 2014-04-12 18:20:00,56.03376441733333 2014-04-12 18:25:00,55.405490623223805 2014-04-12 18:30:00,54.705211081114285 2014-04-12 18:35:00,54.86560818510476 2014-04-12 18:40:00,54.43631488249524 2014-04-12 18:45:00,54.60644130148571 2014-04-12 18:50:00,56.81779949837619 2014-04-12 18:55:00,56.11394703096666 2014-04-12 19:00:00,48.59324831145715 2014-04-12 19:05:00,49.33397892824762 2014-04-12 19:10:00,48.9585207465381 2014-04-12 19:15:00,47.82743224492857 2014-04-12 19:20:00,45.91655859721905 2014-04-12 19:25:00,48.64481567550952 2014-04-12 19:30:00,47.0979714917 2014-04-12 19:35:00,45.86365311399047 2014-04-12 19:40:00,49.26162914368095 2014-04-12 19:45:00,47.01003023647142 2014-04-12 19:50:00,46.480015514861904 2014-04-12 19:55:00,49.413806310352385 2014-04-12 20:00:00,47.484282916742856 2014-04-12 20:05:00,45.18500764463333 2014-04-12 20:10:00,45.25729018432381 2014-04-12 20:15:00,46.185622485014285 2014-04-12 20:20:00,46.82308086330476 2014-04-12 20:25:00,44.085004144795235 2014-04-12 20:30:00,46.26412108378571 2014-04-12 20:35:00,47.743976895476194 2014-04-12 20:40:00,44.922203035466666 2014-04-12 20:45:00,47.57866314595714 2014-04-12 20:50:00,47.75543687494762 2014-04-12 20:55:00,44.9734411742381 2014-04-12 21:00:00,46.56411665912857 2014-04-12 21:05:00,44.49995351451905 2014-04-12 21:10:00,46.512316253509525 2014-04-12 21:15:00,46.7601402965 2014-04-12 21:20:00,44.55615959389047 2014-04-12 21:25:00,46.44725377068095 2014-04-12 21:30:00,46.84148193897143 2014-04-12 21:35:00,45.0261120597619 2014-04-12 21:40:00,44.266383332352376 2014-04-12 21:45:00,43.96941680094285 2014-04-12 21:50:00,45.91980742663333 2014-04-12 21:55:00,47.545845716823806 2014-04-12 22:00:00,46.847955684614284 2014-04-12 22:05:00,45.305466932104764 2014-04-12 22:10:00,45.716419463895235 2014-04-12 22:15:00,44.69450063358571 2014-04-12 22:20:00,44.235645823676194 2014-04-12 22:25:00,45.520372481466666 2014-04-12 22:30:00,45.45342324375714 2014-04-12 22:35:00,45.69480163144762 2014-04-12 22:40:00,47.4273951963381 2014-04-12 22:45:00,46.037858719928565 2014-04-12 22:50:00,46.052812547919046 2014-04-12 22:55:00,44.14743018120952 2014-04-12 23:00:00,47.615176766 2014-04-12 23:05:00,46.72786979599047 2014-04-12 23:10:00,47.15282401878095 2014-04-12 23:15:00,45.30829725667142 2014-04-12 23:20:00,45.66711592036191 2014-04-12 23:25:00,45.754394575952375 2014-04-12 23:30:00,44.44962607704285 2014-04-12 23:35:00,46.439025484233326 2014-04-12 23:40:00,47.3005801880238 2014-04-12 23:45:00,44.350369282514286 2014-04-12 23:50:00,44.048200146504755 2014-04-12 23:55:00,46.66374381029524 2014-04-13 00:00:00,44.80709304098571 2014-04-13 00:05:00,46.21717635697619 2014-04-13 00:10:00,46.51220001866666 2014-04-13 00:15:00,45.024250197157144 2014-04-13 00:20:00,125.74404761904762 2014-04-13 00:25:00,45.95144402373809 2014-04-13 00:30:00,47.23492620322857 2014-04-13 00:35:00,46.81954325781905 2014-04-13 00:40:00,47.24811205190952 2014-04-13 00:45:00,43.8618955285 2014-04-13 00:50:00,44.76271551919048 2014-04-13 00:55:00,44.15616271418095 2014-04-13 01:00:00,45.57190349737142 2014-04-13 01:05:00,47.370852391261906 2014-04-13 01:10:00,45.688613430052385 2014-04-13 01:15:00,47.22474503544285 2014-04-13 01:20:00,45.14204628543333 2014-04-13 01:25:00,45.19905410072381 2014-04-13 01:30:00,47.43046120701429 2014-04-13 01:35:00,45.55892334790476 2014-04-13 01:40:00,47.022157189295235 2014-04-13 01:45:00,44.81710990578571 2014-04-13 01:50:00,47.673179509176194 2014-04-13 01:55:00,46.18372965276666 2014-04-13 02:00:00,46.93015141715715 2014-04-13 02:05:00,44.25836041824762 2014-04-13 02:10:00,45.8783949985381 2014-04-13 02:15:00,47.51933256232857 2014-04-13 02:20:00,47.430773563819045 2014-04-13 02:25:00,44.117315352709525 2014-04-13 02:30:00,45.152293876499996 2014-04-13 02:35:00,45.718220502090475 2014-04-13 02:40:00,44.64144020978095 2014-04-13 02:45:00,46.87981467257143 2014-04-13 02:50:00,44.7053098871619 2014-04-13 02:55:00,45.36126115845238 2014-04-13 03:00:00,46.63526540454285 2014-04-13 03:05:00,45.91794071143333 2014-04-13 03:10:00,46.95130796402381 2014-04-13 03:15:00,47.849295890614286 2014-04-13 03:20:00,44.47809151280476 2014-04-13 03:25:00,46.857616103695236 2014-04-13 03:30:00,44.948162336785714 2014-04-13 03:35:00,45.69213310007619 2014-04-13 03:40:00,44.17311756986666 2014-04-13 03:45:00,44.59273667205714 2014-04-13 03:50:00,45.335656775247614 2014-04-13 03:55:00,45.431931316438096 2014-04-13 04:00:00,47.66976943722857 2014-04-13 04:05:00,47.04612068471904 2014-04-13 04:10:00,47.975041396509525 2014-04-13 04:15:00,46.4900360413 2014-04-13 04:20:00,45.06804540459048 2014-04-13 04:25:00,45.419251072080954 2014-04-13 04:30:00,45.39541512177142 2014-04-13 04:35:00,45.4294892154619 2014-04-13 04:40:00,46.82280907335238 2014-04-13 04:45:00,46.26162456954285 2014-04-13 04:50:00,45.68753004563333 2014-04-13 04:55:00,44.749632884423804 2014-04-13 05:00:00,44.24927093751428 2014-04-13 05:05:00,45.04349347230476 2014-04-13 05:10:00,44.60548085399523 2014-04-13 05:15:00,47.32481583768571 2014-04-13 05:20:00,44.640468021776186 2014-04-13 05:25:00,47.094829615866665 2014-04-13 05:30:00,45.74799190195714 2014-04-13 05:35:00,44.50631117804762 2014-04-13 05:40:00,47.4711582929381 2014-04-13 05:45:00,46.54620085232857 2014-04-13 05:50:00,45.17816509911905 2014-04-13 05:55:00,47.82128422110952 2014-04-13 06:00:00,44.4310332555 2014-04-13 06:05:00,45.06471890899047 2014-04-13 06:10:00,47.27306866358095 2014-04-13 06:15:00,47.109833149771426 2014-04-13 06:20:00,45.43684867966191 2014-04-13 06:25:00,44.535301882352385 2014-04-13 06:30:00,47.726955146042854 2014-04-13 06:35:00,45.55687388563334 2014-04-13 06:40:00,45.092377469223806 2014-04-13 06:45:00,46.381211575114285 2014-04-13 06:50:00,47.965313559004755 2014-04-13 06:55:00,44.50603154949523 2014-04-13 07:00:00,47.40250206638571 2014-04-13 07:05:00,46.636619102276185 2014-04-13 07:10:00,46.055963132866665 2014-04-13 07:15:00,47.337928919257145 2014-04-13 07:20:00,48.23234531684762 2014-04-13 07:25:00,45.29331293993809 2014-04-13 07:30:00,44.95851803172857 2014-04-13 07:35:00,48.04289602851905 2014-04-13 07:40:00,47.07462183360953 2014-04-13 07:45:00,46.1581940862 2014-04-13 07:50:00,46.70672875729048 2014-04-13 07:55:00,47.40358657308095 2014-04-13 08:00:00,47.52069902337143 2014-04-13 08:05:00,48.1155886280619 2014-04-13 08:10:00,46.15082353655238 2014-04-13 08:15:00,45.62453649724286 2014-04-13 08:20:00,47.01699040053333 2014-04-13 08:25:00,46.1286854066238 2014-04-13 08:30:00,46.85160810151429 2014-04-13 08:35:00,46.16059795570476 2014-04-13 08:40:00,45.10007838479524 2014-04-13 08:45:00,46.37324272088571 2014-04-13 08:50:00,47.26664747827619 2014-04-13 08:55:00,47.70755189736666 2014-04-13 09:00:00,94.42709450725714 2014-04-13 09:05:00,89.97253292594762 2014-04-13 09:10:00,93.37249094643809 2014-04-13 09:15:00,98.43377600362857 2014-04-13 09:20:00,93.36250512801905 2014-04-13 09:25:00,97.22787831680952 2014-04-13 09:30:00,94.6606060708 2014-04-13 09:35:00,91.05057497769047 2014-04-13 09:40:00,98.60502786148095 2014-04-13 09:45:00,88.93012440397143 2014-04-13 09:50:00,94.9307697502619 2014-04-13 09:55:00,90.64062044665238 2014-04-13 10:00:00,97.48800141214286 2014-04-13 10:05:00,104.26011803683333 2014-04-13 10:10:00,104.21522846962381 2014-04-13 10:15:00,107.44056627971429 2014-04-13 10:20:00,108.03543551810476 2014-04-13 10:25:00,107.77966914259524 2014-04-13 10:30:00,102.84813724918571 2014-04-13 10:35:00,106.30305168827618 2014-04-13 10:40:00,105.46085683246667 2014-04-13 10:45:00,103.05674559775714 2014-04-13 10:50:00,105.79028863284762 2014-04-13 10:55:00,111.2302751417381 2014-04-13 11:00:00,101.33221067092856 2014-04-13 11:05:00,112.67726845901905 2014-04-13 11:10:00,99.12946601820951 2014-04-13 11:15:00,103.191372042 2014-04-13 11:20:00,102.87685251009049 2014-04-13 11:25:00,108.26334162808095 2014-04-13 11:30:00,100.39607306167143 2014-04-13 11:35:00,112.3493683234619 2014-04-13 11:40:00,111.50123398115238 2014-04-13 11:45:00,108.70184765344288 2014-04-13 11:50:00,105.62944691413333 2014-04-13 11:55:00,113.18400670372381 2014-04-13 12:00:00,111.9753088274143 2014-04-13 12:05:00,106.68621028040477 2014-04-13 12:10:00,109.93069294099524 2014-04-13 12:15:00,107.7816298940857 2014-04-13 12:20:00,108.12486351367619 2014-04-13 12:25:00,104.02577903716667 2014-04-13 12:30:00,106.12843879245716 2014-04-13 12:35:00,99.99984058024762 2014-04-13 12:40:00,104.4695560670381 2014-04-13 12:45:00,109.88617490972857 2014-04-13 12:50:00,114.00687378791906 2014-04-13 12:55:00,114.17169449700951 2014-04-13 13:00:00,107.7471519302 2014-04-13 13:05:00,108.56878707569047 2014-04-13 13:10:00,101.84342675108095 2014-04-13 13:15:00,110.00230117497144 2014-04-13 13:20:00,100.0177512577619 2014-04-13 13:25:00,103.44880016075237 2014-04-13 13:30:00,109.59360989844285 2014-04-13 13:35:00,103.87357384713333 2014-04-13 13:40:00,99.71460238332381 2014-04-13 13:45:00,112.23141645291429 2014-04-13 13:50:00,103.89621320880475 2014-04-13 13:55:00,99.94900651179522 2014-04-13 14:00:00,100.15738290898571 2014-04-13 14:05:00,102.99621762037619 2014-04-13 14:10:00,101.82382910596667 2014-04-13 14:15:00,111.37135836485713 2014-04-13 14:20:00,104.13728931234762 2014-04-13 14:25:00,111.8725466495381 2014-04-13 14:30:00,101.78687502282857 2014-04-13 14:35:00,106.89860138911905 2014-04-13 14:40:00,110.02841924810951 2014-04-13 14:45:00,109.4591469329 2014-04-13 14:50:00,108.65284336769048 2014-04-13 14:55:00,113.83911032028095 2014-04-13 15:00:00,102.70924749037144 2014-04-13 15:05:00,106.9597521408619 2014-04-13 15:10:00,113.21150620085238 2014-04-13 15:15:00,100.32148994214285 2014-04-13 15:20:00,99.97684584093334 2014-04-13 15:25:00,102.82288337522381 2014-04-13 15:30:00,109.22576536621429 2014-04-13 15:35:00,103.26299766760475 2014-04-13 15:40:00,102.15621295819524 2014-04-13 15:45:00,106.46061108798571 2014-04-13 15:50:00,108.9447598420762 2014-04-13 15:55:00,103.11161060046666 2014-04-13 16:00:00,103.95376865315714 2014-04-13 16:05:00,108.96708940744762 2014-04-13 16:10:00,114.2893855539381 2014-04-13 16:15:00,109.96088724232857 2014-04-13 16:20:00,111.69892305411905 2014-04-13 16:25:00,105.04887153150952 2014-04-13 16:30:00,103.54342314649999 2014-04-13 16:35:00,106.46307217229048 2014-04-13 16:40:00,112.11634317668096 2014-04-13 16:45:00,106.51046343967143 2014-04-13 16:50:00,112.7647041939619 2014-04-13 16:55:00,115.04488545695239 2014-04-13 17:00:00,100.38454141834285 2014-04-13 17:05:00,99.96611790363333 2014-04-13 17:10:00,101.64043048902381 2014-04-13 17:15:00,105.40434908791428 2014-04-13 17:20:00,101.35855165510476 2014-04-13 17:25:00,113.19994388259525 2014-04-13 17:30:00,99.64709794048571 2014-04-13 17:35:00,104.33688006357619 2014-04-13 17:40:00,102.24675195576665 2014-04-13 17:45:00,114.20370305395714 2014-04-13 17:50:00,110.01821193594762 2014-04-13 17:55:00,113.90643894693812 2014-04-13 18:00:00,62.344325593028564 2014-04-13 18:05:00,59.310291666719046 2014-04-13 18:10:00,57.63594599780952 2014-04-13 18:15:00,57.383608464000005 2014-04-13 18:20:00,57.577865387490476 2014-04-13 18:25:00,60.693621720880955 2014-04-13 18:30:00,56.42491850927143 2014-04-13 18:35:00,56.502217179461894 2014-04-13 18:40:00,60.07306093535238 2014-04-13 18:45:00,60.29755227774285 2014-04-13 18:50:00,60.45350970193333 2014-04-13 18:55:00,58.583303052323814 2014-04-13 19:00:00,51.18134608321428 2014-04-13 19:05:00,49.96879167790476 2014-04-13 19:10:00,48.05808012869524 2014-04-13 19:15:00,51.16403930808571 2014-04-13 19:20:00,51.87021853277619 2014-04-13 19:25:00,47.87687822826666 2014-04-13 19:30:00,49.36860993815715 2014-04-13 19:35:00,49.80686827414762 2014-04-13 19:40:00,48.286425958438095 2014-04-13 19:45:00,51.52501333832857 2014-04-13 19:50:00,48.918108281019045 2014-04-13 19:55:00,51.16043648440952 2014-04-13 20:00:00,48.680393144199996 2014-04-13 20:05:00,48.389035914390476 2014-04-13 20:10:00,46.733897829980954 2014-04-13 20:15:00,46.858322816671425 2014-04-13 20:20:00,46.1557007470619 2014-04-13 20:25:00,46.95516026035238 2014-04-13 20:30:00,47.39157964334285 2014-04-13 20:35:00,49.39664623583333 2014-04-13 20:40:00,47.4922679332238 2014-04-13 20:45:00,49.08989484961428 2014-04-13 20:50:00,47.80636010330476 2014-04-13 20:55:00,49.228665584295236 2014-04-13 21:00:00,49.59951647688571 2014-04-13 21:05:00,46.64709733407619 2014-04-13 21:10:00,49.15649002076666 2014-04-13 21:15:00,48.19724246015714 2014-04-13 21:20:00,48.99031666294762 2014-04-13 21:25:00,48.331742103038096 2014-04-13 21:30:00,47.42426638262857 2014-04-13 21:35:00,46.644447797719046 2014-04-13 21:40:00,46.01669505650952 2014-04-13 21:45:00,47.8950053609 2014-04-13 21:50:00,49.730409061390475 2014-04-13 21:55:00,48.72386852358095 2014-04-13 22:00:00,47.00649059157143 2014-04-13 22:05:00,49.0152875610619 2014-04-13 22:10:00,48.789621269852375 2014-04-13 22:15:00,46.84579750264285 2014-04-13 22:20:00,45.78289822443333 2014-04-13 22:25:00,46.20615809912381 2014-04-13 22:30:00,49.25308789211428 2014-04-13 22:35:00,49.09739929470476 2014-04-13 22:40:00,46.93734483469524 2014-04-13 22:45:00,46.904692560485714 2014-04-13 22:50:00,48.94476073007619 2014-04-13 22:55:00,49.53224744746666 2014-04-13 23:00:00,48.88846054535714 2014-04-13 23:05:00,48.201533409547615 2014-04-13 23:10:00,46.757065866338095 2014-04-13 23:15:00,47.89703000022857 2014-04-13 23:20:00,46.73530181721905 2014-04-13 23:25:00,49.041181754909516 2014-04-13 23:30:00,47.3640975023 2014-04-13 23:35:00,49.15882562149048 2014-04-13 23:40:00,47.35756689828095 2014-04-13 23:45:00,49.13550799397143 2014-04-13 23:50:00,47.1792451515619 2014-04-13 23:55:00,47.61402721935238 2014-04-14 00:00:00,48.31909653454285 2014-04-14 00:05:00,46.145733789433336 2014-04-14 00:10:00,49.664852056823804 2014-04-14 00:15:00,48.173887430214286 2014-04-14 00:20:00,47.91818482070476 2014-04-14 00:25:00,49.251921122595235 2014-04-14 00:30:00,49.364836633885716 2014-04-14 00:35:00,47.99826780857619 2014-04-14 00:40:00,49.62571596986666 2014-04-14 00:45:00,46.183058207157146 2014-04-14 00:50:00,46.384450788047616 2014-04-14 00:55:00,48.326141015338095 2014-04-14 01:00:00,47.362692018628564 2014-04-14 01:05:00,47.810769712419045 2014-04-14 01:10:00,47.27362639540952 2014-04-14 01:15:00,47.587651245800004 2014-04-14 01:20:00,49.266775864790475 2014-04-14 01:25:00,48.35753575178096 2014-04-14 01:30:00,49.980449625671426 2014-04-14 01:35:00,49.146028696061904 2014-04-14 01:40:00,47.10061739735238 2014-04-14 01:45:00,47.070773328042854 2014-04-14 01:50:00,47.36442641383333 2014-04-14 01:55:00,49.4013117321238 2014-04-14 02:00:00,46.14486488831429 2014-04-14 02:05:00,46.96387987740476 2014-04-14 02:10:00,49.670268919495236 2014-04-14 02:15:00,48.61762145858572 2014-04-14 02:20:00,46.97286457247619 2014-04-14 02:25:00,46.94949653956667 2014-04-14 02:30:00,49.530829549857145 2014-04-14 02:35:00,49.66282765214761 2014-04-14 02:40:00,47.1197624590381 2014-04-14 02:45:00,47.784720003728566 2014-04-14 02:50:00,49.44850200211905 2014-04-14 02:55:00,49.201589278209525 2014-04-14 03:00:00,49.3806644263 2014-04-14 03:05:00,48.20603323939048 2014-04-14 03:10:00,49.786077145580954 2014-04-14 03:15:00,47.45112760437142 2014-04-14 03:20:00,46.7814504421619 2014-04-14 03:25:00,48.99713171125238 2014-04-14 03:30:00,48.327060521142855 2014-04-14 03:35:00,49.59542640853333 2014-04-14 03:40:00,46.50916080602381 2014-04-14 03:45:00,49.56673389951429 2014-04-14 03:50:00,47.37258337470476 2014-04-14 03:55:00,48.82626790679524 2014-04-14 04:00:00,46.374800870585716 2014-04-14 04:05:00,48.66005137567619 2014-04-14 04:10:00,49.098253423366664 2014-04-14 04:15:00,47.71160800085714 2014-04-14 04:20:00,47.10569044004762 2014-04-14 04:25:00,48.4020108016381 2014-04-14 04:30:00,49.59169178912857 2014-04-14 04:35:00,47.56055848081905 2014-04-14 04:40:00,47.28368671390952 2014-04-14 04:45:00,47.3969912346 2014-04-14 04:50:00,50.08521908789048 2014-04-14 04:55:00,47.73323861548096 2014-04-14 05:00:00,46.31798838817143 2014-04-14 05:05:00,49.4377367365619 2014-04-14 05:10:00,49.11555156225238 2014-04-14 05:15:00,46.840165915542855 2014-04-14 05:20:00,50.272950329833336 2014-04-14 05:25:00,48.773022950723806 2014-04-14 05:30:00,48.351332249514286 2014-04-14 05:35:00,47.88453183240476 2014-04-14 05:40:00,49.95778626039524 2014-04-14 05:45:00,47.346389639985716 2014-04-14 05:50:00,47.52105179137619 2014-04-14 05:55:00,46.87505989336667 2014-04-14 06:00:00,49.42933352515715 2014-04-14 06:05:00,48.78249474064762 2014-04-14 06:10:00,48.8440027722381 2014-04-14 06:15:00,47.28906029552857 2014-04-14 06:20:00,49.02729260411905 2014-04-14 06:25:00,49.49189331280952 2014-04-14 06:30:00,47.869054122899996 2014-04-14 06:35:00,49.650329051990475 2014-04-14 06:40:00,47.84754330648096 2014-04-14 06:45:00,49.49237527457143 2014-04-14 06:50:00,46.6021823345619 2014-04-14 06:55:00,48.67936078685238 2014-04-14 07:00:00,50.36024909974286 2014-04-14 07:05:00,50.414561736033335 2014-04-14 07:10:00,47.6240341229238 2014-04-14 07:15:00,48.27006065001429 2014-04-14 07:20:00,46.76381639380476 2014-04-14 07:25:00,50.012710468495236 2014-04-14 07:30:00,48.80107432688571 2014-04-14 07:35:00,48.07462890627619 2014-04-14 07:40:00,46.99274890066667 2014-04-14 07:45:00,50.33617628485714 2014-04-14 07:50:00,48.67742381034762 2014-04-14 07:55:00,47.69569981153809 2014-04-14 08:00:00,47.97228909192857 2014-04-14 08:05:00,47.66165777131904 2014-04-14 08:10:00,48.99354875920952 2014-04-14 08:15:00,50.3136043031 2014-04-14 08:20:00,50.02796568949047 2014-04-14 08:25:00,48.45015445408095 2014-04-14 08:30:00,49.92206887777142 2014-04-14 08:35:00,48.315933829861905 2014-04-14 08:40:00,47.64018094395238 2014-04-14 08:45:00,50.57205331824285 2014-04-14 08:50:00,47.86138360523333 2014-04-14 08:55:00,47.94817073342381 2014-04-14 09:00:00,103.32053728761429 2014-04-14 09:05:00,91.68956866900476 2014-04-14 09:10:00,100.21885747499523 2014-04-14 09:15:00,102.61008922968571 2014-04-14 09:20:00,96.85088811257619 2014-04-14 09:25:00,89.93221262586667 2014-04-14 09:30:00,95.00615878275714 2014-04-14 09:35:00,91.43013591544762 2014-04-14 09:40:00,95.5803902839381 2014-04-14 09:45:00,100.67204252972857 2014-04-14 09:50:00,95.90159611241904 2014-04-14 09:55:00,95.81674117410951 2014-04-14 10:00:00,107.2313726818 2014-04-14 10:05:00,107.62527835149046 2014-04-14 10:10:00,111.89459966498094 2014-04-14 10:15:00,103.39799784537144 2014-04-14 10:20:00,111.3720999277619 2014-04-14 10:25:00,107.41049416065238 2014-04-14 10:30:00,103.29886146874284 2014-04-14 10:35:00,103.22243953633333 2014-04-14 10:40:00,104.25437807502381 2014-04-14 10:45:00,108.32116341121429 2014-04-14 10:50:00,102.24660283260475 2014-04-14 10:55:00,112.95542211529525 2014-04-14 11:00:00,109.55069545308571 2014-04-14 11:05:00,115.04665710777618 2014-04-14 11:10:00,101.16018158546666 2014-04-14 11:15:00,105.87849837865714 2014-04-14 11:20:00,100.79978065464762 2014-04-14 11:25:00,104.77438096253809 2014-04-14 11:30:00,114.16127950642857 2014-04-14 11:35:00,101.04160996841905 2014-04-14 11:40:00,107.40329300090951 2014-04-14 11:45:00,102.3440366888 2014-04-14 11:50:00,107.11112432109047 2014-04-14 11:55:00,113.83022654848095 2014-04-14 12:00:00,110.79934499917144 2014-04-14 12:05:00,112.6235677082619 2014-04-14 12:10:00,106.43601542915238 2014-04-14 12:15:00,115.95672354154289 2014-04-14 12:20:00,112.20650900163332 2014-04-14 12:25:00,107.62005638072381 2014-04-14 12:30:00,107.70206296521428 2014-04-14 12:35:00,115.57556287280478 2014-04-14 12:40:00,110.11310336299523 2014-04-14 12:45:00,112.19764059188572 2014-04-14 12:50:00,107.5811327063762 2014-04-14 12:55:00,104.49880600186668 2014-04-14 13:00:00,112.57474734705714 2014-04-14 13:05:00,210.7308639300476 2014-04-14 13:10:00,109.0350190253381 2014-04-14 13:15:00,111.00483737092857 2014-04-14 13:20:00,104.36210860801906 2014-04-14 13:25:00,113.73775010370952 2014-04-14 13:30:00,116.2121839352 2014-04-14 13:35:00,115.30688894679048 2014-04-14 13:40:00,106.20183856408094 2014-04-14 13:45:00,107.56207473887143 2014-04-14 13:50:00,114.0063144366619 2014-04-14 13:55:00,110.60201122435238 2014-04-14 14:00:00,109.86989715764287 2014-04-14 14:05:00,115.93668715283333 2014-04-14 14:10:00,109.69455551802382 2014-04-14 14:15:00,109.3646316862143 2014-04-14 14:20:00,101.80571395190476 2014-04-14 14:25:00,102.25150726329525 2014-04-14 14:30:00,101.2670489415857 2014-04-14 14:35:00,115.7669764314762 2014-04-14 14:40:00,107.69708358596668 2014-04-14 14:45:00,108.66727330585714 2014-04-14 14:50:00,114.70363352334762 2014-04-14 14:55:00,110.93300516003808 2014-04-14 15:00:00,110.94766929422856 2014-04-14 15:05:00,105.94768316961905 2014-04-14 15:10:00,114.55302421830952 2014-04-14 15:15:00,103.8713129451 2014-04-14 15:20:00,102.07588458719047 2014-04-14 15:25:00,104.29856404238095 2014-04-14 15:30:00,105.52413460457143 2014-04-14 15:35:00,105.7647542674619 2014-04-14 15:40:00,111.98337576795238 2014-04-14 15:45:00,104.74786159654286 2014-04-14 15:50:00,112.09657107053333 2014-04-14 15:55:00,102.73568338332382 2014-04-14 16:00:00,103.64081090121428 2014-04-14 16:05:00,109.43414406680476 2014-04-14 16:10:00,116.05076151869524 2014-04-14 16:15:00,115.06095248938571 2014-04-14 16:20:00,116.81536326947617 2014-04-14 16:25:00,111.73042348836665 2014-04-14 16:30:00,112.14323600445714 2014-04-14 16:35:00,111.33800816124763 2014-04-14 16:40:00,111.3101834879381 2014-04-14 16:45:00,103.70646133292857 2014-04-14 16:50:00,110.05978740261905 2014-04-14 16:55:00,107.54449635900953 2014-04-14 17:00:00,108.4555650855 2014-04-14 17:05:00,109.76001878009049 2014-04-14 17:10:00,103.44419126438095 2014-04-14 17:15:00,107.14909531347143 2014-04-14 17:20:00,102.41992684096189 2014-04-14 17:25:00,117.08685880065238 2014-04-14 17:30:00,103.31606294204286 2014-04-14 17:35:00,105.56344991363332 2014-04-14 17:40:00,115.69517751272379 2014-04-14 17:45:00,109.16529441181427 2014-04-14 17:50:00,103.61957150490475 2014-04-14 17:55:00,107.60450383799524 2014-04-14 18:00:00,59.00583520508571 2014-04-14 18:05:00,59.55310279617619 2014-04-14 18:10:00,58.612152093566664 2014-04-14 18:15:00,61.09125703985714 2014-04-14 18:20:00,63.45651227724761 2014-04-14 18:25:00,62.05168458923809 2014-04-14 18:30:00,62.18953225182857 2014-04-14 18:35:00,59.600101064119045 2014-04-14 18:40:00,60.52472416840952 2014-04-14 18:45:00,63.7407928963 2014-04-14 18:50:00,58.90096441829047 2014-04-14 18:55:00,63.83688055208095 2014-04-14 19:00:00,51.88050152147143 2014-04-14 19:05:00,53.4714310854619 2014-04-14 19:10:00,51.15311995575238 2014-04-14 19:15:00,51.25390809104285 2014-04-14 19:20:00,53.11052185283333 2014-04-14 19:25:00,53.26755536752381 2014-04-14 19:30:00,50.787021280714285 2014-04-14 19:35:00,54.12411695210476 2014-04-14 19:40:00,50.15160977839524 2014-04-14 19:45:00,50.08742786618571 2014-04-14 19:50:00,52.45583382267618 2014-04-14 19:55:00,53.03329402276667 2014-04-14 20:00:00,52.01064645975714 2014-04-14 20:05:00,49.74095529614762 2014-04-14 20:10:00,48.1933314840381 2014-04-14 20:15:00,50.56664172702857 2014-04-14 20:20:00,49.29121371251905 2014-04-14 20:25:00,49.88541068980952 2014-04-14 20:30:00,50.120270754100005 2014-04-14 20:35:00,48.39118390539048 2014-04-14 20:40:00,50.12496209688095 2014-04-14 20:45:00,49.88802654167142 2014-04-14 20:50:00,51.0678429591619 2014-04-14 20:55:00,50.801349700352375 2014-04-14 21:00:00,48.562961825442855 2014-04-14 21:05:00,48.65449682713333 2014-04-14 21:10:00,48.84226779652381 2014-04-14 21:15:00,48.56010184931428 2014-04-14 21:20:00,50.48977600330476 2014-04-14 21:25:00,51.852558960295234 2014-04-14 21:30:00,50.48413950588571 2014-04-14 21:35:00,50.30900061077619 2014-04-14 21:40:00,49.525648968166664 2014-04-14 21:45:00,49.14182967195714 2014-04-14 21:50:00,51.55473520964762 2014-04-14 21:55:00,51.795000374038096 2014-04-14 22:00:00,49.82772088442857 2014-04-14 22:05:00,49.00806539011904 2014-04-14 22:10:00,50.93703561340952 2014-04-14 22:15:00,48.391365788399995 2014-04-14 22:20:00,50.933763275290474 2014-04-14 22:25:00,51.154849200880946 2014-04-14 22:30:00,48.383446829171426 2014-04-14 22:35:00,51.8019889172619 2014-04-14 22:40:00,51.84406589895238 2014-04-14 22:45:00,51.65614776654286 2014-04-14 22:50:00,49.89915733483333 2014-04-14 22:55:00,48.905795294023804 2014-04-14 23:00:00,50.24265439041429 2014-04-14 23:05:00,49.601668623004755 2014-04-14 23:10:00,48.75300398369524 2014-04-14 23:15:00,49.63152273428571 2014-04-14 23:20:00,50.60000139857619 2014-04-14 23:25:00,48.235080369466665 2014-04-14 23:30:00,49.292741211757146 2014-04-14 23:35:00,48.03744684384762 2014-04-14 23:40:00,50.972251727538094 2014-04-14 23:45:00,50.544391690728574 2014-04-14 23:50:00,48.239311716819046 2014-04-14 23:55:00,51.85570667850952 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/art_daily_jumpsup_noised_trended_det2_ts.csv ================================================ timestamp,value 1396310400,19.761251902999998 1396310700,20.508273763190477 1396311000,19.976522396880952 1396311300,21.512587501971424 1396311600,20.217501314561908 1396311900,19.960328052752377 1396312200,21.74304681884286 1396312500,20.93084171753333 1396312800,18.50572343892381 1396313100,18.77778213051429 1396313400,21.222896213704765 1396313700,21.42525052279524 1396314000,20.27004903068572 1396314300,20.314547101976192 1396314600,20.63189851806667 1396314900,19.868070239957138 1396315200,20.83984411294762 1396315500,18.560413125538094 1396315800,21.97904554092857 1396316100,21.141988342819047 1396316400,20.673506339809524 1396316700,19.421538228 1396317000,18.807512425990478 1396317300,19.808502807680952 1396317600,20.824878390871426 1396317900,20.720850878461906 1396318200,19.724017001252374 1396318500,20.654038432442857 1396318800,21.463326515633334 1396319100,18.320912898923808 1396319400,20.025698477414288 1396319700,21.264875675804767 1396320000,20.42267311999524 1396320300,20.851440065985717 1396320600,20.31968176087619 1396320900,22.227914845366662 1396321200,18.486343288857146 1396321500,20.239476906147626 1396321800,18.648404291738093 1396322100,18.929320819928574 1396322400,19.829772449319048 1396322700,18.92721988980952 1396323000,22.167248663800002 1396323300,22.107099583090477 1396323600,19.671819537280953 1396323900,20.893812276771428 1396324200,20.477275187161904 1396324500,21.612050303052378 1396324800,20.866925296442854 1396325100,18.36559315133333 1396325400,21.424721351923807 1396325700,21.36685677091429 1396326000,20.425795584204767 1396326300,22.00602113099524 1396326600,22.035570537085718 1396326900,20.50487289727619 1396327200,20.848619591466672 1396327500,22.410195430557145 1396327800,19.62682855824762 1396328100,19.737457064438093 1396328400,19.177524182128565 1396328700,22.037336804219045 1396329000,21.439263083609525 1396329300,18.8913213955 1396329600,22.403259880990475 1396329900,21.40747778498095 1396330200,21.893159866971427 1396330500,18.691115061461907 1396330800,20.52579605675238 1396331100,21.307786004042853 1396331400,20.692619671633327 1396331700,21.19486367232381 1396332000,21.807210540114284 1396332300,20.040503013704765 1396332600,21.945269940595242 1396332900,19.209700133385716 1396333200,19.649020410576192 1396333500,18.746299146366667 1396333800,20.038064388157142 1396334100,20.10743579834762 1396334400,21.816320484038094 1396334700,21.21520125262857 1396335000,20.357009280219046 1396335300,21.226015438309524 1396335600,18.8361334021 1396335900,19.353526620290477 1396336200,21.147672373380953 1396336500,21.21278870547143 1396336800,21.751300539561907 1396337100,20.27420141715238 1396337400,21.559859243642855 1396337700,21.41300466353333 1396338000,22.53809732302381 1396338300,19.552485191414284 1396338600,20.90612301690476 1396338900,21.113903006495235 1396339200,22.70887725398571 1396339500,19.526462759176187 1396339800,20.822038746566673 1396340100,20.12134837375714 1396340400,20.847619493347626 1396340700,19.680002503638093 1396341000,18.94937808512857 1396341300,21.056630863219052 1396341600,20.11722678720952 1396341900,19.509015607000002 1396342200,20.084432740490477 1396342500,18.993251758180953 1396342800,74.92958581217142 1396343100,69.91462354836189 1396343400,73.09930644725237 1396343700,67.78030034374287 1396344000,74.31841281223332 1396344300,68.61390162262381 1396344600,69.85387066761429 1396344900,68.74405289080478 1396345200,72.03568006189523 1396345500,69.7770583696857 1396345800,65.77172155117619 1396346100,64.06475429266668 1396346400,80.13990765835716 1396346700,78.33237062224762 1396347000,72.23728090793809 1396347300,76.89516164052857 1396347600,78.75194911701904 1396347900,83.60344251280951 1396348200,71.9585883865 1396348500,76.19358828099048 1396348800,83.56000397688095 1396349100,80.86336084967142 1396349400,75.30741505916191 1396349700,83.93430347475238 1396350000,80.39548396244285 1396350300,80.48337181273331 1396350600,88.09666885212381 1396350900,87.63540515321431 1396351200,78.28200855820477 1396351500,74.82311570039523 1396351800,77.7741894244857 1396352100,73.08703196247619 1396352400,72.93995913686669 1396352700,78.90749119775714 1396353000,87.59052687924763 1396353300,86.4900552502381 1396353600,81.15829421172856 1396353900,82.02523879981905 1396354200,73.09473154860952 1396354500,76.4512308711 1396354800,73.41070084389048 1396355100,85.08037631648095 1396355400,75.35720776567143 1396355700,86.92517984006192 1396356000,83.32538957295237 1396356300,76.71828684284286 1396356600,75.57993017653331 1396356900,83.09681863002382 1396357200,87.55336675621429 1396357500,84.64187976130475 1396357800,78.73372324459523 1396358100,82.5616376855857 1396358400,78.1441899914762 1396358700,89.16319300076668 1396359000,85.16662861575712 1396359300,83.02326462964763 1396359600,79.97347906433811 1396359900,83.09846151082856 1396360200,78.68238424141906 1396360500,73.68700611410952 1396360800,79.56765692970001 1396361100,88.14096298019048 1396361400,83.28176146948095 1396361700,74.61209219977142 1396362000,87.43552404396192 1396362300,77.58553747455237 1396362600,77.19131153154285 1396362900,78.05185466793333 1396363200,82.54086029622381 1396363500,82.0280994602143 1396363800,81.18319143010476 1396364100,84.80842798599524 1396364400,78.40314959548569 1396364700,85.85894721047619 1396365000,76.15859539126667 1396365300,85.88272835755714 1396365600,83.98921614184763 1396365900,84.30702490723809 1396366200,81.08801775882857 1396366500,84.06259991911904 1396366800,74.67485881190952 1396367100,87.03024587450001 1396367400,74.30174647989048 1396367700,75.80028106358095 1396368000,82.65705080557144 1396368300,85.2664342373619 1396368600,74.66333682805238 1396368900,88.18296335724287 1396369200,89.03588756493332 1396369500,83.1608197228238 1396369800,81.1729565479143 1396370100,85.34281330270477 1396370400,78.74166454819525 1396370700,81.3876132668857 1396371000,88.16122623537619 1396371300,88.80073587276668 1396371600,88.35092965575714 1396371900,77.72443742994763 1396372200,77.25221366243811 1396372500,78.30278118942856 1396372800,80.60856648641905 1396373100,78.58170855020953 1396373400,79.54987478470001 1396373700,83.50010024889049 1396374000,85.77775945288096 1396374300,85.35372043357144 1396374600,86.6230063261619 1396374900,74.11462498665237 1396375200,30.71263352284286 1396375500,35.466627782133344 1396375800,33.83372208772381 1396376100,34.12955835781428 1396376400,30.773455073104767 1396376700,32.078347722295234 1396377000,34.537246951585715 1396377300,35.95798370177619 1396377600,36.335353752266656 1396377900,33.676785771657144 1396378200,33.97257650864762 1396378500,35.82049918083809 1396378800,24.26498554472857 1396379100,24.179394009119054 1396379400,25.926084684609517 1396379700,25.417647290300003 1396380000,25.958834064990484 1396380300,22.871376598280953 1396380600,24.25027237397143 1396380900,25.682785727861905 1396381200,22.413893514752377 1396381500,25.483478007142853 1396381800,22.75055294013333 1396382100,25.558644527323807 1396382400,22.724469874714284 1396382700,21.016649152304762 1396383000,22.171453712195238 1396383300,23.03311902138572 1396383600,22.84373742017619 1396383900,22.004920940266672 1396384200,23.946162179957145 1396384500,22.396700318047618 1396384800,22.349270303938095 1396385100,20.539656763628575 1396385400,24.06912389771905 1396385700,21.02502875920953 1396386000,22.0849229424 1396386300,23.198539327590474 1396386600,20.842230716780954 1396386900,22.103340106171427 1396387200,20.958522645261905 1396387500,23.051968464452383 1396387800,22.27424282924286 1396388100,23.45382145873333 1396388400,23.616331281623808 1396388700,22.635753847714287 1396389000,22.951297207104766 1396389300,22.250670613895238 1396389600,21.520756843285717 1396389900,22.583966645276195 1396390200,23.633088978266674 1396390500,21.672208707557143 1396390800,21.27017504954762 1396391100,21.57400743763809 1396391400,21.76947100942857 1396391700,20.328175628919052 1396392000,22.03677089240952 1396392300,22.027685149099998 1396392600,22.41200540109048 1396392900,21.516084293580953 1396393200,22.509928676971427 1396393500,23.578007613861903 1396393800,23.89452614255238 1396394100,22.41424593384286 1396394400,20.25718585723333 1396394700,23.971918169723807 1396395000,22.925660629314283 1396395300,21.453223374304766 1396395600,20.70529505719524 1396395900,20.697776306885714 1396396200,20.80253864087619 1396396500,20.321197751066673 1396396800,23.751473897457146 1396397100,22.31337055034762 1396397400,22.95757574613809 1396397700,23.47761260852857 1396398000,23.33878307291905 1396398300,23.71048201870952 1396398600,24.056518490100004 1396398900,21.951222935190483 1396399200,24.00372281908095 1396399500,23.102981221971426 1396399800,20.499934665961906 1396400100,22.95183486575237 1396400400,22.979009495542854 1396400700,23.86302558853333 1396401000,21.738752339423808 1396401300,22.594110286814285 1396401600,20.310654965904764 1396401900,21.59764620679524 1396402200,20.52576061888572 1396402500,22.371718081576184 1396402800,23.561457268666672 1396403100,21.124877911357146 1396403400,22.41631180124762 1396403700,21.130022641238085 1396404000,20.80418244282857 1396404300,22.372856215319047 1396404600,20.65290400760952 1396404900,22.6931685246 1396405200,20.476540318890482 1396405500,20.785490839880953 1396405800,22.56606137047143 1396406100,22.739141556361908 1396406400,20.49690010135238 1396406700,22.681900009142858 1396407000,23.749843434633327 1396407300,23.292538518723806 1396407600,20.935454701414283 1396407900,22.788053352204766 1396408200,23.11460523839524 1396408500,20.58196052128572 1396408800,23.861866865176193 1396409100,24.07298625586667 1396409400,23.857166236257143 1396409700,23.76132349104762 1396410000,23.45009888903809 1396410300,23.011406696528567 1396410600,23.19962706761905 1396410900,23.718140697109533 1396411200,23.1499938334 1396411500,21.818348302890477 1396411800,22.018725360980948 1396412100,24.110551302071425 1396412400,20.598250247961907 1396412700,23.33248470595238 1396413000,24.36375306684285 1396413300,23.37699601313333 1396413600,24.53517176242381 1396413900,23.317143907814284 1396414200,20.711856878804763 1396414500,23.88988476469524 1396414800,21.727805362085714 1396415100,22.380955093176194 1396415400,21.852534330266668 1396415700,21.685823567657145 1396416000,22.34467043374762 1396416300,22.141493889038095 1396416600,23.167282898828567 1396416900,23.89397385161905 1396417200,21.837164136509518 1396417500,21.5111346113 1396417800,23.331271559690475 1396418100,23.35241121568095 1396418400,24.28309638567143 1396418700,20.749794650561906 1396419000,24.10561502945238 1396419300,22.784901548942862 1396419600,23.193541690033324 1396419900,21.08125957172381 1396420200,22.45367401721429 1396420500,21.639864390904762 1396420800,21.754995358395238 1396421100,22.761916172985718 1396421400,24.00279999207619 1396421700,23.735540387266674 1396422000,23.131856979157142 1396422300,22.932970390047622 1396422600,22.491962268138092 1396422900,24.681018465628572 1396423200,23.038389264519054 1396423500,21.820925117009526 1396423800,21.7328631682 1396424100,23.265352599290477 1396424400,22.918691061580954 1396424700,20.865612640371424 1396425000,24.162523393561905 1396425300,23.666191797852377 1396425600,23.504460015842856 1396425900,21.139705964133327 1396426200,22.32024721022381 1396426500,24.620993328614286 1396426800,24.337261727304764 1396427100,22.03651698959524 1396427400,21.53002125068572 1396427700,22.705578019176194 1396428000,22.339988181366667 1396428300,23.653012649657146 1396428600,24.797286859347626 1396428900,22.39099389513809 1396429200,64.99267731952858 1396429500,76.36141956111905 1396429800,64.67742585510952 1396430100,77.1263662013 1396430400,73.21447069709048 1396430700,76.99060418718096 1396431000,66.90644316697144 1396431300,64.75202912026191 1396431600,70.84560808555239 1396431900,70.34187129534286 1396432200,68.72912824963333 1396432500,77.25240186122382 1396432800,85.64221380881429 1396433100,83.15090773360474 1396433400,75.41815592429523 1396433700,84.2947350098857 1396434000,84.18870948737619 1396434300,79.50997472116667 1396434600,87.27303446165712 1396434900,75.51929435124762 1396435200,77.08431706383809 1396435500,73.92392031662857 1396435800,85.29551791851905 1396436100,82.60726519600951 1396436400,79.7018106216 1396436700,77.30573298199047 1396437000,75.34639108688094 1396437300,77.36724295197143 1396437600,81.93180092016188 1396437900,78.66130489605239 1396438200,78.85649540704286 1396438500,88.67024986883331 1396438800,82.94527336822381 1396439100,86.3579876663143 1396439400,75.33535169520476 1396439700,80.58240324679524 1396440000,82.78539522118571 1396440300,78.1144166701762 1396440600,77.0635236521667 1396440900,89.05835776635716 1396441200,90.1705165654476 1396441500,76.42448217533807 1396441800,80.75012681282855 1396442100,90.49414001391905 1396442400,76.51640054860951 1396442700,85.4807540517 1396443000,90.7391657612905 1396443300,90.84252775528095 1396443600,82.82405522547144 1396443900,77.8970926726619 1396444200,78.53374541685238 1396444500,89.53881910974285 1396444800,89.89948053983329 1396445100,85.04723385362381 1396445400,87.5868145598143 1396445700,87.17443344940477 1396446000,85.93241941099524 1396446300,88.5865102486857 1396446600,86.3245701976762 1396446900,83.91012298976668 1396447200,79.18052096175714 1396447500,87.29848061884762 1396447800,82.9789243803381 1396448100,80.12816311552857 1396448400,88.24968756471905 1396448700,86.57348605340952 1396449000,90.4307571332 1396449300,78.08842365729049 1396449600,85.83545492918095 1396449900,79.36400934207144 1396450200,89.9204397178619 1396450500,77.06316059355238 1396450800,85.97993977384287 1396451100,88.14614216703333 1396451400,81.17496354002381 1396451700,90.7698358002143 1396452000,89.12277384300474 1396452300,80.23250157969524 1396452600,75.64675083938572 1396452900,80.2800042417762 1396453200,80.04189978486667 1396453500,89.78771296435714 1396453800,91.02964672134762 1396454100,76.69032585113807 1396454400,83.11199310982856 1396454700,84.35202593931905 1396455000,77.07275501080952 1396455300,81.6335635095 1396455600,80.67436117369049 1396455900,84.18537791398094 1396456200,86.19496727247144 1396456500,86.87911382166189 1396456800,77.81889031765238 1396457100,88.64539287454286 1396457400,86.50234672513334 1396457700,89.87830692512381 1396458000,82.85006082791429 1396458300,89.97035782540476 1396458600,89.52794822849523 1396458900,82.6975546904857 1396459200,181.78873924537623 1396459500,90.62287552696668 1396459800,87.14796085345716 1396460100,90.56468981094764 1396460400,88.4718020129381 1396460700,85.47640620852857 1396461000,77.58873511991904 1396461300,80.40622084620952 1396461600,38.750584685300005 1396461900,34.60173598589047 1396462200,33.16170647478095 1396462500,37.10065650737143 1396462800,37.277382702261896 1396463100,34.41412591045238 1396463400,34.499737629542864 1396463700,35.602992334833345 1396464000,32.748967531623805 1396464300,37.66862505251428 1396464600,34.65376708120476 1396464900,38.095922512195244 1396465200,27.595068699885715 1396465500,26.96980603037619 1396465800,25.46960488546667 1396466100,26.334704106257142 1396466400,26.021881477847618 1396466700,25.55467775643809 1396467000,27.84357783312857 1396467300,26.217479517019054 1396467600,27.78940769140953 1396467900,24.537627632399996 1396468200,24.70548038859048 1396468500,28.459524573180953 1396468800,24.768070801371426 1396469100,24.456028241161903 1396469400,24.51829936865238 1396469700,23.264633523842853 1396470000,25.33414445403333 1396470300,22.745035018923808 1396470600,24.753547965214285 1396470900,24.750523503504766 1396471200,26.164610757195234 1396471500,24.582780257385718 1396471800,22.996384765276193 1396472100,24.788413767166663 1396472400,22.471321165957146 1396472700,22.930785755647623 1396473000,22.244169672238094 1396473300,24.189608088728573 1396473600,22.473772489919046 1396473900,24.028049361109524 1396474200,25.898592632600003 1396474500,25.04920549609048 1396474800,22.474913908380948 1396475100,23.072365459371422 1396475400,24.88624585196191 1396475700,25.782088047752374 1396476000,22.256223602642862 1396476300,25.384787662133327 1396476600,24.38871668622381 1396476900,24.333206567714285 1396477200,25.989115484804763 1396477500,25.15507463349524 1396477800,25.572805632485714 1396478100,23.59384780207619 1396478400,24.40353157796667 1396478700,24.65537300035714 1396479000,23.486398253347613 1396479300,24.489450337838093 1396479600,23.14668783882857 1396479900,22.780937842619053 1396480200,23.710933768209518 1396480500,25.179932287399996 1396480800,25.895098698090482 1396481100,24.068294680780948 1396481400,24.81631586827143 1396481700,22.664195559361907 1396482000,25.87795804125238 1396482300,24.541702397442855 1396482600,25.396241621533328 1396482900,25.46010474192381 1396483200,23.31163639121429 1396483500,24.409852574604763 1396483800,26.142514244295235 1396484100,22.66657389358572 1396484400,25.04767578257619 1396484700,26.17197297876667 1396485000,23.532665575057138 1396485300,25.783589304647624 1396485600,26.079868276838088 1396485900,25.34102340902857 1396486200,23.285432296819053 1396486500,23.703562399109522 1396486800,22.5182371777 1396487100,25.70825341319048 1396487400,25.788325698380948 1396487700,24.928162668471426 1396488000,23.81487330986191 1396488300,22.719446491552375 1396488600,25.431873296842863 1396488900,25.333188107733324 1396489200,26.08493389652381 1396489500,25.364092369714285 1396489800,25.764184530904764 1396490100,25.44066370969524 1396490400,24.987034467485714 1396490700,24.179591767276193 1396491000,26.087635901266665 1396491300,25.090481430457142 1396491600,24.087468906947624 1396491900,22.83536527593809 1396492200,23.67174799502857 1396492500,24.69127598691905 1396492800,23.62635100390953 1396493100,23.4161913917 1396493400,24.648264532590474 1396493700,23.22541233598095 1396494000,25.755211681871423 1396494300,24.498484510161905 1396494600,24.86390347685238 1396494900,23.165425927542852 1396495200,23.88163867583333 1396495500,24.23113254252381 1396495800,25.831065607814285 1396496100,25.68629285420476 1396496400,23.505005137295235 1396496700,25.08525204068572 1396497000,23.60180162157619 1396497300,26.58840528946667 1396497600,26.45135265535714 1396497900,24.903356501147623 1396498200,25.45334838283809 1396498500,25.87090010022857 1396498800,25.55661272781905 1396499100,25.479374288109533 1396499400,26.521716031799997 1396499700,25.080764901390477 1396500000,25.247591639680948 1396500300,26.106896430371428 1396500600,25.39682537616191 1396500900,25.656432869052377 1396501200,23.66881760194286 1396501500,24.224651029833325 1396501800,23.33622919232381 1396502100,24.777526055014285 1396502400,24.584814364604764 1396502700,26.757996495195236 1396503000,25.221620325585718 1396503300,25.93000548327619 1396503600,24.127725349666672 1396503900,26.125288468257146 1396504200,25.266887485047622 1396504500,25.601957421638094 1396504800,23.99915168322857 1396505100,25.02342261441905 1396505400,25.372457417509523 1396505700,25.2001287033 1396506000,26.51196532189048 1396506300,26.451721610380954 1396506600,26.75000766007143 1396506900,25.54322392876191 1396507200,26.768608901452378 1396507500,26.218304857242856 1396507800,23.97916189473333 1396508100,24.613016487723808 1396508400,23.86428405451429 1396508700,22.934943405204763 1396509000,23.67779025069524 1396509300,22.94927805938572 1396509600,25.819830035876194 1396509900,24.65005385756667 1396510200,24.205656051157145 1396510500,26.009681183447622 1396510800,26.300185193738088 1396511100,26.878876726028572 1396511400,25.553173386319045 1396511700,24.838675358009525 1396512000,24.221057206399998 1396512300,23.896713313090483 1396512600,23.866584754280954 1396512900,24.659078927471427 1396513200,26.996907325961903 1396513500,23.04061717065238 1396513800,23.833466446042856 1396514100,23.805655262933325 1396514400,25.928001751623807 1396514700,24.476903196114286 1396515000,24.90344798030476 1396515300,23.676341759995235 1396515600,71.79724544298571 1396515900,67.70024363237619 1396516200,73.55355538196666 1396516500,67.64356891205715 1396516800,77.06996160304763 1396517100,74.03227145383809 1396517400,76.17989165472856 1396517700,72.03319190611906 1396518000,71.53709111190952 1396518300,67.6918908911 1396518600,73.48812673199048 1396518900,73.36836039448093 1396519200,82.28351515847145 1396519500,86.51885692466189 1396519800,87.95392066945239 1396520100,86.69314861234287 1396520400,77.28112966173333 1396520700,84.71013739362381 1396521000,76.3098288860143 1396521300,85.85119266300475 1396521600,81.00423801669523 1396521900,77.1419195155857 1396522200,88.4720054907762 1396522500,84.62982608856667 1396522800,82.47740303305714 1396523100,77.33198268424762 1396523400,85.39612045443809 1396523700,91.54116294282856 1396524000,86.35044390691904 1396524300,92.32619073970952 1396524600,79.050618585 1396524900,85.92626485969048 1396525200,89.58876171588095 1396525500,85.26102121637145 1396525800,78.3585812303619 1396526100,86.18792134955238 1396526400,87.04680398284286 1396526700,88.92354009133335 1396527000,89.45039279112379 1396527300,89.6106284615143 1396527600,87.90287692780475 1396527900,80.75678064599524 1396528200,83.77539648118571 1396528500,89.72600405687618 1396528800,92.56679260296666 1396529100,78.59934279855713 1396529400,85.90345215954764 1396529700,82.34694400883808 1396530000,81.03458536792856 1396530300,85.52761767091907 1396530600,87.1391315896095 1396530900,77.6077881773 1396531200,89.93921963819048 1396531500,90.58131670518095 1396531800,92.91825706007143 1396532100,80.37083796446191 1396532400,86.99923029685237 1396532700,84.32048059134286 1396533000,82.85951321923334 1396533300,86.55895700002381 1396533600,90.0497869071143 1396533900,77.90852559250477 1396534200,93.05679653989523 1396534500,90.5120630964857 1396534800,89.57990256277618 1396535100,89.73507480406667 1396535400,83.80157369815714 1396535700,89.60969318794761 1396536000,83.77980839333809 1396536300,91.97784163782856 1396536600,80.44208507371904 1396536900,82.29143778840952 1396537200,86.4456247977 1396537500,82.73907681959048 1396537800,84.42692051428095 1396538100,85.52531762287144 1396538400,91.35559274986191 1396538700,86.03250687635239 1396539000,83.46825356114286 1396539300,81.64013270563332 1396539600,84.22258549752381 1396539900,85.94297153931429 1396540200,89.63643667390474 1396540500,79.64291586379524 1396540800,81.25988767828571 1396541100,83.79604054137619 1396541400,83.4953918371667 1396541700,84.00442627005714 1396542000,90.44022523634762 1396542300,82.93781034463808 1396542600,85.78914579952855 1396542900,87.74872416691906 1396543200,81.48852095420952 1396543500,89.280215876 1396543800,86.54231654479048 1396544100,84.94447759578095 1396544400,90.76008323307144 1396544700,81.7069069076619 1396545000,91.94923483655238 1396545300,86.80264152794285 1396545600,87.58010001263334 1396545900,91.84168421182379 1396546200,90.92950462011429 1396546500,87.48061651910477 1396546800,89.91406622409525 1396547100,84.8036172476857 1396547400,86.63598923537619 1396547700,78.87851082466669 1396548000,35.26794217805714 1396548300,40.008613657047626 1396548600,35.0896310886381 1396548900,35.79932723772857 1396549200,39.815941557419045 1396549500,34.73738807680952 1396549800,36.544881828 1396550100,38.48278163899048 1396550400,38.56325425248095 1396550700,39.73359355667143 1396551000,38.005183782261895 1396551300,38.034868190352384 1396551600,29.39153295144285 1396551900,28.383419700333327 1396552200,28.883062621823807 1396552500,30.186490784914284 1396552800,27.97040407140476 1396553100,27.904704355195236 1396553400,26.202684091085715 1396553700,28.942374585376182 1396554000,26.335043698566665 1396554300,28.467691147057142 1396554600,29.81951369034763 1396554900,28.68763325013809 1396555200,25.60785806972857 1396555500,27.73101464201905 1396555800,25.623070138109533 1396556100,86.09375 1396556400,27.032808857490483 1396556700,25.236935554280954 1396557000,28.25549951427143 1396557300,25.377348199061903 1396557600,28.61630076685238 1396557900,24.600336397142854 1396558200,25.657061011933326 1396558500,25.40390135612381 1396558800,24.303356555514284 1396559100,27.198087774704767 1396559400,27.04901217079524 1396559700,27.45405265818572 1396560000,25.30859894167619 1396560300,26.070188521566664 1396560600,26.94086615825714 1396560900,26.066715141347622 1396561200,27.109329780238088 1396561500,26.86214444412857 1396561800,24.78231145211905 1396562100,27.468127984109522 1396562400,27.1527528233 1396562700,26.900576420590475 1396563000,24.903130927780953 1396563300,25.362616320771426 1396563600,25.871259821261905 1396563900,25.42527578795238 1396564200,25.224038802042863 1396564500,27.54388657703333 1396564800,26.88218359672381 1396565100,26.59830421491429 1396565400,25.246363254404763 1396565700,28.02495689049524 1396566000,25.107620697385716 1396566300,27.53059644197619 1396566600,28.225055735966663 1396566900,27.273992464957146 1396567200,28.34470123314761 1396567500,26.984648568338088 1396567800,25.257392953528573 1396568100,25.21025955401905 1396568400,25.70077192430952 1396568700,24.438231555 1396569000,27.144463898890482 1396569300,25.499464425880948 1396569600,27.68930435777143 1396569900,25.872702506961907 1396570200,26.36327835485238 1396570500,28.313648523342856 1396570800,25.427021825533327 1396571100,27.35079019922381 1396571400,27.493685442914284 1396571700,25.364647392004766 1396572000,26.49208258449524 1396572300,25.896343415585708 1396572600,27.59060116407619 1396572900,27.00034994276667 1396573200,26.421789362257147 1396573500,27.642750679247623 1396573800,25.47336037523809 1396574100,27.55466609372857 1396574400,28.009116296019048 1396574700,28.06954591100952 1396575000,27.6971943721 1396575300,26.20199714419048 1396575600,28.504613043280955 1396575900,26.10319600387143 1396576200,27.14676350116191 1396576500,25.243999093252377 1396576800,28.52893845164285 1396577100,27.43052702083333 1396577400,27.63553399052381 1396577700,24.892571099314285 1396578000,27.69057601880476 1396578300,27.743238954995235 1396578600,27.338876619685717 1396578900,25.826864645676192 1396579200,26.625426835266666 1396579500,25.115844628057147 1396579800,26.567895884847612 1396580100,25.664283505638092 1396580400,26.09281651742857 1396580700,25.35427068121905 1396581000,25.63152699480952 1396581300,25.0250245673 1396581600,28.405795941890478 1396581900,26.855273704280954 1396582200,26.328039313671425 1396582500,26.888628755861905 1396582800,27.26912529485238 1396583100,28.450908030642857 1396583400,25.48560514243333 1396583700,25.96048380402381 1396584000,28.68887163111429 1396584300,26.27792670850477 1396584600,24.890841841095238 1396584900,25.398609684785708 1396585200,24.92083099747619 1396585500,28.78260923636667 1396585800,25.94584053885714 1396586100,28.53196864674762 1396586400,28.828783198238092 1396586700,27.25204345602857 1396587000,24.992904307919048 1396587300,25.193926045309524 1396587600,26.8013562204 1396587900,26.507128527790474 1396588200,27.314590175480948 1396588500,26.652712667371432 1396588800,28.641069301861908 1396589100,27.051161242652377 1396589400,27.694547102942856 1396589700,28.51302442393333 1396590000,25.52201131282381 1396590300,25.860902902214285 1396590600,25.378679403804764 1396590900,25.515398834995235 1396591200,27.01462158198572 1396591500,26.25644322637619 1396591800,26.671858024766664 1396592100,28.916566470057138 1396592400,25.62086501024762 1396592700,27.164736378438093 1396593000,25.40441319162857 1396593300,26.290354300719052 1396593600,27.13391321850953 1396593900,28.8177769839 1396594200,26.603603361290478 1396594500,25.305757737280956 1396594800,26.606217220371427 1396595100,25.643976608261905 1396595400,25.98841083415238 1396595700,27.548255349842854 1396596000,25.35302879813333 1396596300,26.949668834523806 1396596600,27.536060629714285 1396596900,26.793088331404768 1396597200,25.18960064059524 1396597500,29.062613141885713 1396597800,26.59643925987619 1396598100,28.249725414366665 1396598400,26.44544311155714 1396598700,27.050364647047616 1396599000,26.71159266563809 1396599300,26.535335489428572 1396599600,25.260024556419054 1396599900,26.620143275209518 1396600200,28.745459961599998 1396600500,27.956513830590477 1396600800,25.784072388780952 1396601100,27.574441447071422 1396601400,28.786185344561908 1396601700,28.02483854485238 1396602000,70.45425059324286 1396602300,80.24210528893333 1396602600,72.54802239022379 1396602900,74.6298998483143 1396603200,75.61744629370477 1396603500,80.03623505759523 1396603800,81.14664764828571 1396604100,81.12750532847619 1396604400,68.59984353206667 1396604700,81.03679054685713 1396605000,69.24621035664761 1396605300,72.12850982793809 1396605600,85.15404007682857 1396605900,84.61731574091904 1396606200,86.56140552490952 1396606500,84.62475547 1396606800,91.69270102419048 1396607100,80.93194907668095 1396607400,81.45893468007142 1396607700,91.50336466676191 1396608000,78.41194963425238 1396608300,86.68877681314287 1396608600,87.81637530943333 1396608900,85.08928135712381 1396609200,90.01977808651431 1396609500,81.73364465210477 1396609800,92.55385826809523 1396610100,81.2280042795857 1396610400,85.38299730487618 1396610700,80.21281355786667 1396611000,87.69439414035713 1396611300,89.68243494034763 1396611600,94.00742697983809 1396611900,90.80408143092855 1396612200,87.65881983091904 1396612500,93.89290056490951 1396612800,87.05940342139999 1396613100,88.38955577719048 1396613400,88.95461230338094 1396613700,85.98772543197144 1396614000,92.8429860861619 1396614300,82.41006202445239 1396614600,88.32506493304287 1396614900,91.00754855383332 1396615200,93.9193862170238 1396615500,93.60628739541427 1396615800,87.61808157920477 1396616100,89.77367975689528 1396616400,85.8782956194857 1396616700,87.06849259397619 1396617000,94.0836592871667 1396617300,94.48201713055714 1396617600,93.9249541581476 1396617900,81.82261054013809 1396618200,93.21472859002856 1396618500,94.79426702721905 1396618800,85.41013743820952 1396619100,87.935319029 1396619400,92.10894284339048 1396619700,88.64494277338095 1396620000,95.57008878057144 1396620300,86.97361975936191 1396620600,91.11253145225237 1396620900,92.37828639024286 1396621200,87.61010451633335 1396621500,93.4234005373238 1396621800,88.45781229831431 1396622100,86.31329536290475 1396622400,81.45973521109524 1396622700,86.0363947942857 1396623000,91.4919398029762 1396623300,94.4968357055667 1396623600,83.79399774665714 1396623900,85.45832013214763 1396624200,82.24539915253808 1396624500,90.84094758402857 1396624800,95.15979524281906 1396625100,90.05950539110952 1396625400,89.68493849709999 1396625700,88.67500314819048 1396626000,81.24196801658096 1396626300,91.50607939967142 1396626600,89.47427092676189 1396626900,90.4325378798524 1396627200,94.23795449414287 1396627500,92.40779360303331 1396627800,92.36650561432378 1396628100,94.71423786471428 1396628400,95.72569533450476 1396628700,89.19471285249523 1396629000,81.64374998598569 1396629300,87.25515237037621 1396629600,92.51812257496668 1396629900,80.36757324735714 1396630200,80.84160664514764 1396630500,81.01337231023807 1396630800,91.64296856522856 1396631100,87.97250437741906 1396631400,85.86364670560953 1396631700,81.6585944273 1396632000,91.69200233259049 1396632300,85.11991830088095 1396632600,84.23622727147144 1396632900,90.4355874737619 1396633200,88.95009557995238 1396633500,85.81193325154284 1396633800,90.2846012769333 1396634100,84.36778882132381 1396634400,41.92262145371429 1396634700,38.31079023250476 1396635000,37.867150763795244 1396635300,41.86564144398572 1396635600,41.39597878747619 1396635900,38.041800357166665 1396636200,37.624324287657146 1396636500,42.25354522554762 1396636800,41.865461897438095 1396637100,38.99711983132857 1396637400,41.12257612181905 1396637700,37.71217903550952 1396638000,30.556572281999998 1396638300,28.37635107409048 1396638600,30.054256176780953 1396638900,28.642616144471425 1396639200,30.443420049161904 1396639500,30.211334949252386 1396639800,30.32048656134285 1396640100,28.540166449433325 1396640400,29.964563823723807 1396640700,31.741010637814284 1396641000,30.012139957904765 1396641300,31.57081430409524 1396641600,28.15967032698571 1396641900,28.387314700876193 1396642200,28.97086851186667 1396642500,30.562600088057145 1396642800,27.121939781947614 1396643100,26.81830266883809 1396643400,29.18112094522857 1396643700,30.585870456019048 1396644000,30.75971520490953 1396644300,28.696386512300002 1396644600,28.637952551990477 1396644900,29.36990230448095 1396645200,28.62317859507143 1396645500,28.945938575461906 1396645800,29.917630819252377 1396646100,29.41184656194286 1396646400,28.41678289683333 1396646700,28.283499394323808 1396647000,29.005301582814287 1396647300,28.273629411504764 1396647600,28.28940195799524 1396647900,26.52247235038571 1396648200,27.163974725576193 1396648500,28.435250639466663 1396648800,29.703909957857146 1396649100,27.533555948247614 1396649400,28.51759876863809 1396649700,27.81363155532857 1396650000,26.85951744401905 1396650300,30.284213311509525 1396650600,29.8767574181 1396650900,26.77649157599048 1396651200,29.351573975080953 1396651500,27.868755743271432 1396651800,30.467761345461906 1396652100,27.702737661152376 1396652400,27.440735987842857 1396652700,28.765037664533327 1396653000,29.841625837723807 1396653300,27.278143625614284 1396653600,29.353516660104763 1396653900,26.768474729095235 1396654200,30.20668642648571 1396654500,26.862044118776193 1396654800,30.202750299566674 1396655100,28.516169078657146 1396655400,28.352712202247616 1396655700,30.461419910938098 1396656000,30.53296528222857 1396656300,29.17958155141905 1396656600,27.09478669120952 1396656900,28.618430342600004 1396657200,28.71784287999048 1396657500,28.66641666488095 1396657800,28.894038782671426 1396658100,26.698410759961906 1396658400,29.47586150685238 1396658700,29.487970064942857 1396659000,27.107712434033328 1396659300,28.934231579323807 1396659600,28.934159015414284 1396659900,29.397956442704764 1396660200,27.017186006595235 1396660500,29.189048943385714 1396660800,27.81348399347619 1396661100,28.72592862866666 1396661400,29.798651353657146 1396661700,29.535381364547614 1396662000,27.19585016593809 1396662300,29.09241771992857 1396662600,30.611585171419055 1396662900,27.36963727310952 1396663200,30.161628350900003 1396663500,29.56763279839048 1396663800,29.86089420398095 1396664100,27.90015473717143 1396664400,27.931317622261904 1396664700,30.411280204052378 1396665000,28.23397098554285 1396665300,27.054144896133327 1396665600,29.211910623823808 1396665900,27.316234961914287 1396666200,30.010789727504765 1396666500,29.39883100809524 1396666800,30.338191735185717 1396667100,29.98607518957619 1396667400,27.302621260066662 1396667700,28.385889848557138 1396668000,29.96728861874761 1396668300,28.545853988338088 1396668600,30.773390510528568 1396668900,29.834330847219054 1396669200,26.96080919060952 1396669500,30.4261927662 1396669800,27.31690961569048 1396670100,27.48322584908095 1396670400,29.866541030971426 1396670700,30.395886142461904 1396671000,29.08885089255238 1396671300,28.10709178894286 1396671600,28.36359551433333 1396671900,28.337331127923807 1396672200,28.279926700914285 1396672500,27.95229344920476 1396672800,29.423563616595235 1396673100,30.59715698858571 1396673400,28.231305842776194 1396673700,27.757193856466664 1396674000,30.372167808357137 1396674300,29.992430942647616 1396674600,30.75608622143809 1396674900,27.702257513828567 1396675200,27.624624304119052 1396675500,29.22077710100952 1396675800,29.5202346193 1396676100,28.990634243590478 1396676400,29.47324749768095 1396676700,27.806340504071432 1396677000,29.010716921461906 1396677300,29.73207262475238 1396677600,28.837968654142852 1396677900,29.83237267663333 1396678200,28.92678893172381 1396678500,28.463862609114283 1396678800,28.351324950204763 1396679100,28.78795347409524 1396679400,27.24414420498572 1396679700,29.83332674427619 1396680000,30.547089230566673 1396680300,28.592615520657137 1396680600,27.365680163647614 1396680900,31.136090484738087 1396681200,28.251221593228568 1396681500,27.71035353441905 1396681800,28.690319555709518 1396682100,30.1729781625 1396682400,28.401856863790478 1396682700,29.53244376808095 1396683000,28.903311406271428 1396683300,27.719567873861905 1396683600,28.577100430952378 1396683900,30.162874880042853 1396684200,29.718848922633327 1396684500,27.75738732902381 1396684800,27.93900392461429 1396685100,29.85608819910476 1396685400,30.554256895395238 1396685700,28.705933698085712 1396686000,29.69671919787619 1396686300,28.005491021666664 1396686600,28.57586249045714 1396686900,27.418878441747612 1396687200,30.41834188643809 1396687500,28.95671785052857 1396687800,30.62462134221905 1396688100,30.201051507909533 1396688400,81.84592201390001 1396688700,74.46739838249049 1396689000,73.10735968618096 1396689300,83.81523871267144 1396689600,80.3604198085619 1396689900,81.95517722475238 1396690200,70.79825673964284 1396690500,75.44776136933335 1396690800,80.73683080142379 1396691100,71.70253081441426 1396691400,78.36522780400476 1396691700,76.49223487549523 1396692000,79.57769390508571 1396692300,82.97406714737619 1396692600,83.73913833696669 1396692900,81.06267351015714 1396693200,89.13550045824762 1396693500,83.10350313463809 1396693800,83.65758320552857 1396694100,93.29703209171906 1396694400,86.61355992240952 1396694700,85.457078841 1396695000,90.61316899079048 1396695300,93.50333707998095 1396695600,81.51974932007144 1396695900,88.2578025203619 1396696200,90.8503190680524 1396696500,86.21032036974285 1396696800,93.4357057459333 1396697100,96.60914513512381 1396697400,96.17048311851428 1396697700,85.40384106820477 1396698000,84.78077921839524 1396698300,96.41646511968572 1396698600,88.49000365457618 1396698900,84.51618365456667 1396699200,92.85483421925714 1396699500,86.10916193124761 1396699800,85.8421585544381 1396700100,95.62988167902857 1396700400,84.18276590191905 1396700700,82.62271032270951 1396701000,85.90291466309999 1396701300,91.30801372969047 1396701600,83.58302332008095 1396701900,89.15988156727144 1396702200,91.65621079906192 1396702500,95.20179851215237 1396702800,85.39189361714286 1396703100,94.79670589753331 1396703400,85.48734194762382 1396703700,92.56285016201431 1396704000,88.63374811910477 1396704300,83.58652474019523 1396704600,93.18497834778572 1396704900,85.25031187877619 1396705200,84.59968324906667 1396705500,87.51361804025714 1396705800,92.23940290064762 1396706100,85.53975320943809 1396706400,84.75641613982856 1396706700,81.98466341461905 1396707000,89.3787808555095 1396707300,88.6982939092 1396707600,85.58943876399047 1396707900,82.71356837168095 1396708200,88.73037975357144 1396708500,94.4807323403619 1396708800,93.32146114555236 1396709100,95.65699400444285 1396709400,82.04569297723333 1396709700,97.3617846683238 1396710000,87.3725666868143 1396710300,97.76367617430478 1396710600,85.96677660539524 1396710900,89.4768542875857 1396711200,87.60257345237619 1396711500,87.63934226176666 1396711800,95.43105014825714 1396712100,93.90469480484762 1396712400,97.84381746443809 1396712700,91.79312805902859 1396713000,89.39646236171906 1396713300,83.43303629560953 1396713600,97.94481385790002 1396713900,90.83177574009048 1396714200,93.22236070878095 1396714500,88.53004888847143 1396714800,90.79305816976186 1396715100,97.1182788952524 1396715400,84.70721051164286 1396715700,86.72989746093333 1396716000,84.4923365427238 1396716300,94.74225616971428 1396716600,83.06698878260475 1396716900,83.38781088799523 1396717200,86.86516203698571 1396717500,90.32370627807622 1396717800,88.60453333146667 1396718100,82.82864019025713 1396718400,97.43887901414763 1396718700,97.37236691853808 1396719000,86.60360037892859 1396719300,93.84574674941904 1396719600,91.40598490320951 1396719900,85.95584801300001 1396720200,86.3584060452905 1396720500,90.02955107568094 1396720800,41.66168180937143 1396721100,40.849873717961906 1396721400,44.16152007545239 1396721700,42.08224940884285 1396722000,43.19935459833333 1396722300,40.227118448423816 1396722600,42.43765714061429 1396722900,41.065695558004776 1396723200,42.407136168195244 1396723500,44.04281455908571 1396723800,43.97401426057619 1396724100,41.32742304126667 1396724400,33.538217350857146 1396724700,34.65227525954762 1396725000,33.245735433638096 1396725300,31.11505478182857 1396725600,33.50271243381904 1396725900,30.93503004290952 1396726200,34.379553311100004 1396726500,32.794578264490475 1396726800,32.21281025048096 1396727100,30.75020985267143 1396727400,32.20817183626191 1396727700,34.556066925352376 1396728000,28.875088987742853 1396728300,30.74074194313333 1396728600,32.61804708372381 1396728900,30.428732780114284 1396729200,30.572712135504762 1396729500,31.196126974595238 1396729800,30.72997678868571 1396730100,29.53181848827619 1396730400,28.924669932566662 1396730700,31.353895442757143 1396731000,32.63517113294762 1396731300,29.30665535773809 1396731600,29.38068969432857 1396731900,30.02829534921905 1396732200,31.798206238509522 1396732500,29.6373610171 1396732800,32.10774348499048 1396733100,28.790917597380954 1396733400,32.35936422727143 1396733700,30.838666510361904 1396734000,31.24011157565238 1396734300,30.07761053824286 1396734600,31.75022471373333 1396734900,29.28413683602381 1396735200,28.748829399314285 1396735500,30.144021309804764 1396735800,31.985936274995236 1396736100,31.597921969585716 1396736400,30.653365941476192 1396736700,30.880944654266663 1396737000,29.117707227357144 1396737300,31.971031860047614 1396737600,31.763378741838093 1396737900,31.24836098312857 1396738200,30.49395335671905 1396738500,32.496380109809515 1396738800,32.1452589819 1396739100,31.214113370890473 1396739400,30.13082648448095 1396739700,31.123341182371433 1396740000,30.96042354756191 1396740300,30.242929108252376 1396740600,29.90003026764285 1396740900,30.308895084633328 1396741200,30.984066195623807 1396741500,30.408288470214284 1396741800,29.75736113800476 1396742100,31.754738926895236 1396742400,30.840155698085717 1396742700,28.992426843376194 1396743000,30.202432689166667 1396743300,32.276260971657145 1396743600,31.764993743847622 1396743900,30.044475231038092 1396744200,32.511661179628575 1396744500,29.072780681019047 1396744800,32.61874833940952 1396745100,29.764070369899997 1396745400,28.825067197390474 1396745700,30.53136309848095 1396746000,30.23945314727143 1396746300,30.967367925561906 1396746600,32.005543823252374 1396746900,32.19561606574285 1396747200,30.43825333173333 1396747500,30.560156784323805 1396747800,29.440925207014285 1396748100,29.045845197404763 1396748400,31.42795519899523 1396748700,29.12828621648571 1396749000,31.813296668176193 1396749300,31.041777246766664 1396749600,29.68718905575714 1396749900,31.05838939314762 1396750200,29.639728961638088 1396750500,30.67012740142857 1396750800,32.120860312619044 1396751100,30.777736697409527 1396751400,29.5322972732 1396751700,31.840255203490482 1396752000,29.699454617480956 1396752300,31.91402092607143 1396752600,30.884671061661905 1396752900,30.789669417352385 1396753200,32.38788300854286 1396753500,31.82399743073333 1396753800,29.128666997323805 1396754100,30.189161544114285 1396754400,32.49558740530476 1396754700,29.092649912295236 1396755000,31.207799499285716 1396755300,31.94552886717619 1396755600,31.52909100856667 1396755900,32.09123595125714 1396756200,31.959315014747617 1396756500,31.83211087583809 1396756800,32.35758801512857 1396757100,31.661631721419052 1396757400,30.695983500809522 1396757700,30.9813864397 1396758000,31.968089606890477 1396758300,32.61385507108095 1396758600,30.20494663197143 1396758900,30.491819088661906 1396759200,32.853909966352376 1396759500,31.452440026742853 1396759800,29.861680601833328 1396760100,31.808054365123812 1396760400,33.12376290791428 1396760700,32.46196901980476 1396761000,32.158559784295235 1396761300,30.01522233138571 1396761600,32.69503532917619 1396761900,31.301072040766673 1396762200,32.76251723115714 1396762500,30.532108936747623 1396762800,29.46844230573809 1396763100,31.13158244602857 1396763400,30.31446946691905 1396763700,32.103476682909516 1396764000,33.0784262114 1396764300,32.021337080790474 1396764600,32.812616671180955 1396764900,31.08441748297143 1396765200,32.366324853561906 1396765500,32.65937612765238 1396765800,32.13814536744285 1396766100,31.33319247763333 1396766400,31.81298824802381 1396766700,32.11899226841429 1396767000,30.336742374804764 1396767300,32.570162281795234 1396767600,33.140583870185715 1396767900,31.20768345117619 1396768200,32.158435399066676 1396768500,32.30971076605714 1396768800,32.01803780914762 1396769100,31.56494852853809 1396769400,32.91052038972857 1396769700,31.187075884719054 1396770000,29.64322134970952 1396770300,32.7844755028 1396770600,32.10961556549048 1396770900,32.818165458380946 1396771200,29.982761198371428 1396771500,29.55902366676191 1396771800,33.18095054245238 1396772100,30.04180608054285 1396772400,32.69694266163333 1396772700,32.75861357822381 1396773000,32.308035087914284 1396773300,30.005703606304763 1396773600,32.15768973629524 1396773900,33.051882047585714 1396774200,31.205102769676188 1396774500,31.164484084166666 1396774800,78.74073015315713 1396775100,73.84419533224761 1396775400,84.8642858340381 1396775700,84.56106552152858 1396776000,86.31918582391907 1396776300,80.71355024820951 1396776600,82.97870625569999 1396776900,75.52627840199048 1396777200,81.85577288018095 1396777500,81.62118817167143 1396777800,85.04870071216189 1396778100,84.09848341155237 1396778400,96.01214235694286 1396778700,94.93887882963331 1396779000,94.9441530583238 1396779300,82.45845031591429 1396779600,94.60623426770478 1396779900,90.91240992079523 1396780200,87.39628360568571 1396780500,82.37633316097619 1396780800,92.02416365106669 1396781100,86.60779831115713 1396781400,88.78143525164762 1396781700,92.1094134383381 1396782000,97.76529096732857 1396782300,96.39961775341905 1396782600,90.44560626510952 1396782900,89.454053336 1396783200,87.1076474427905 1396783500,89.22470600308094 1396783800,85.07515317207144 1396784100,98.7609739097619 1396784400,92.45153540965237 1396784700,85.36401698094286 1396785000,88.94986010473333 1396785300,92.04638434962379 1396785600,92.21525306771429 1396785900,84.27412699670475 1396786200,98.90939563789522 1396786500,88.12235940478571 1396786800,83.98772014777619 1396787100,84.95815308486668 1396787400,93.01593585265715 1396787700,85.95332046784763 1396788000,84.42563366483809 1396788300,89.83301320582858 1396788600,93.72594111021904 1396788900,85.56844907700952 1396789200,88.8697621355 1396789500,90.5477270211905 1396789800,86.42335019018093 1396790100,91.97528048027144 1396790400,85.25058007306191 1396790700,84.63903969145238 1396791000,92.21773256384287 1396791300,87.87520297293331 1396791600,85.44285850042381 1396791900,90.70565786121428 1396792200,98.57086245370476 1396792500,95.52386348559523 1396792800,97.01005796678572 1396793100,97.91822438067621 1396793400,99.53700755086668 1396793700,96.19451014575714 1396794000,93.72465111274764 1396794300,89.84456553303811 1396794600,86.91162485432855 1396794900,94.99894367651905 1396795200,99.93878918020953 1396795500,91.5051740224 1396795800,95.61354857989048 1396796100,91.96377392128096 1396796400,90.96374865737144 1396796700,90.62514749876188 1396797000,92.14167859755241 1396797300,89.94547589184286 1396797600,96.0629002709333 1396797900,98.07830074682379 1396798200,98.22355238081428 1396798500,87.74810800220476 1396798800,98.44681264619524 1396799100,89.5846117616857 1396799400,89.07616012857618 1396799700,95.76271075526668 1396800000,89.01785098395712 1396800300,84.99762024164762 1396800600,90.13547273463809 1396800900,95.70846777372856 1396801200,89.40380548781906 1396801500,94.2528468397095 1396801800,94.7492525893 1396802100,95.93455588349049 1396802400,98.55630261348095 1396802700,91.13070188847144 1396803000,86.8800317785619 1396803300,89.32736579045236 1396803600,91.14678863664284 1396803900,95.6618148084333 1396804200,84.45695008992381 1396804500,89.30700083261429 1396804800,96.73935361890476 1396805100,95.00303672159524 1396805400,95.9845931478857 1396805700,97.27316586577619 1396806000,96.82340570846668 1396806300,95.21400596195716 1396806600,91.34110178764763 1396806900,100.05152766603807 1396807200,44.76349079432857 1396807500,42.426586208819046 1396807800,43.010305907109526 1396808100,45.5825433364 1396808400,47.069517027590464 1396808700,42.30243403008095 1396809000,41.69308337057143 1396809300,46.81530399936191 1396809600,47.03872479165239 1396809900,42.95721479794285 1396810200,43.610455976133345 1396810500,45.428470652623815 1396810800,34.04879959211428 1396811100,36.50782445350476 1396811400,33.06754669389524 1396811700,32.76319494888571 1396812000,33.53449323957619 1396812300,33.88958873676667 1396812600,33.12126713815714 1396812900,32.91708962044762 1396813200,36.01535936013809 1396813500,33.37363644032857 1396813800,36.739489168919064 1396814100,34.30119681070953 1396814400,33.6788011425 1396814700,31.86268730599048 1396815000,31.931242779080954 1396815300,33.30833007407143 1396815600,33.2581550774619 1396815900,34.11791703995238 1396816200,34.08064589884285 1396816500,33.73122016323333 1396816800,32.831162364123806 1396817100,34.64702704291428 1396817400,33.55648600610476 1396817700,35.06969798519523 1396818000,33.968896834285715 1396818300,30.861216139176193 1396818600,31.979097650566665 1396818900,32.996489972657145 1396819200,33.605177934347616 1396819500,32.9248004974381 1396819800,33.87994391342857 1396820100,31.863818600119053 1396820400,31.474388794109522 1396820700,30.959351890700002 1396821000,33.054353028490475 1396821300,33.52515009488096 1396821600,32.00170270247143 1396821900,33.1599847973619 1396822200,30.91956157915238 1396822500,31.11572751974285 1396822800,33.535327150433325 1396823100,32.20674600852381 1396823400,33.42840832261429 1396823700,34.07801304160476 1396824000,34.16913904759524 1396824300,31.45214741068571 1396824600,32.717265806676195 1396824900,33.71622182956666 1396825200,33.867829942957144 1396825500,33.91806017104762 1396825800,31.699038663438092 1396826100,31.56392170722857 1396826400,33.161578048319036 1396826700,33.773427866609524 1396827000,32.0927591594 1396827300,31.242297515390483 1396827600,33.69837294318096 1396827900,32.03729892017142 1396828200,31.51129656676191 1396828500,31.444165944352374 1396828800,32.11678104724285 1396829100,33.23529559703333 1396829400,32.3056327643238 1396829700,30.962111692114288 1396830000,31.274538500604766 1396830300,32.056358226895235 1396830600,33.540603642885706 1396830900,31.30328648437619 1396831200,33.15929408066667 1396831500,31.40365062615714 1396831800,31.778008928447623 1396832100,31.627742205438093 1396832400,31.215343113728572 1396832700,33.63918831711905 1396833000,32.81492371330953 1396833300,34.2929637636 1396833600,31.37175383609048 1396833900,31.562562685780946 1396834200,32.21690235397143 1396834500,34.0619758525619 1396834800,32.22898767355238 1396835100,32.64706768714286 1396835400,32.22724759853333 1396835700,31.34917097672381 1396836000,34.79344877731428 1396836300,33.23731073020476 1396836600,34.20192799079524 1396836900,33.69146408298571 1396837200,33.12249330667619 1396837500,31.431629693266665 1396837800,33.651291323957146 1396838100,31.70927904274761 1396838400,32.752770772638094 1396838700,33.619131145328566 1396839000,34.23903504951905 1396839300,33.85774022660952 1396839600,33.811134116199995 1396839900,31.72860931289048 1396840200,32.52439511268095 1396840500,31.318970519171422 1396840800,34.0326694774619 1396841100,34.97254630625238 1396841400,32.226084417842856 1396841700,31.52787016993333 1396842000,33.08680411652381 1396842300,34.61875717821428 1396842600,33.40730154300476 1396842900,31.39395383889524 1396843200,35.111374676385715 1396843500,34.53632583037618 1396843800,31.75554297486666 1396844100,34.92379816885715 1396844400,33.04680077344762 1396844700,32.7390800575381 1396845000,33.10314189352857 1396845300,34.604656875119055 1396845600,33.911728236909525 1396845900,31.5182438096 1396846200,35.11910796069048 1396846500,31.88726748628095 1396846800,34.28584323547143 1396847100,33.855558026461914 1396847400,32.06856457275238 1396847700,32.008821161642864 1396848000,34.81464370813333 1396848300,33.01955350352381 1396848600,33.966520342414285 1396848900,33.37193877730476 1396849200,34.27250930639524 1396849500,33.28750521448571 1396849800,32.52749585147619 1396850100,32.83895015066667 1396850400,34.82916792065714 1396850700,33.27243639074762 1396851000,32.2615354242381 1396851300,35.15360012372857 1396851600,34.609020873619045 1396851900,31.65272410800952 1396852200,35.4332718479 1396852500,34.224647261990484 1396852800,32.093447348580945 1396853100,32.40849215377143 1396853400,34.237043829761895 1396853700,34.59374660205238 1396854000,32.43828662974285 1396854300,32.517458748933336 1396854600,32.72550658902381 1396854900,33.896537745014285 1396855200,32.19916947510476 1396855500,31.93631803359523 1396855800,34.24224207058572 1396856100,34.65061794967619 1396856400,33.54538428436667 1396856700,33.004437983957146 1396857000,33.28471847314762 1396857300,33.11761943073809 1396857600,35.41136820442857 1396857900,34.651228668519046 1396858200,32.418658383209525 1396858500,33.1305066082 1396858800,33.77723964169048 1396859100,34.06057440068095 1396859400,33.48880701267143 1396859700,34.864018444761896 1396860000,34.70137645875238 1396860300,33.659024531642864 1396860600,35.063550880433326 1396860900,34.65763193132381 1396861200,85.4494274283143 1396861500,87.87520536220474 1396861800,78.49954563849523 1396862100,78.5230507224857 1396862400,86.98022686787618 1396862700,85.40019534466667 1396863000,87.50637650635714 1396863300,75.77136779944762 1396863600,83.45773434603808 1396863900,76.89462396992856 1396864200,81.78812094441905 1396864500,77.06071779700952 1396864800,85.5777784594 1396865100,83.78629319649049 1396865400,93.38618732058094 1396865700,89.18435243957144 1396866000,85.25228408606192 1396866300,88.63764469135236 1396866600,86.25665515644285 1396866900,98.25718711823332 1396867200,88.61599963652382 1396867500,88.83992296721428 1396867800,96.69900097470476 1396868100,93.72501465329523 1396868400,96.70185495838571 1396868700,95.5296988810762 1396869000,100.4704723665667 1396869300,88.72174836795715 1396869600,101.16672771994763 1396869900,98.66001514313808 1396870200,94.81894862492857 1396870500,95.99372736201904 1396870800,95.78573626370951 1396871100,86.4029835474 1396871400,88.94902486889048 1396871700,100.78036389988097 1396872000,94.38174249327145 1396872300,91.8960051677619 1396872600,98.03503665665238 1396872900,94.24672517594286 1396873200,86.08228495103333 1396873500,97.6450395951238 1396873800,97.58823666941427 1396874100,88.53346330040476 1396874400,101.18988877919523 1396874700,89.4873667827857 1396875000,93.2317772807762 1396875300,87.75758911636667 1396875600,95.65077764995712 1396875900,92.01379380764763 1396876200,91.6648773045381 1396876500,99.25135301572857 1396876800,86.18328973621904 1396877100,98.8018637425095 1396877400,95.1862026895 1396877700,101.8264500735905 1396878000,95.48892902008095 1396878300,86.95339491907144 1396878600,86.88511264976191 1396878900,100.2094788554524 1396879200,99.56246713284284 1396879500,91.64510289903332 1396879800,96.0066129075238 1396880100,93.9590939924143 1396880400,101.60733086210476 1396880700,101.33953408219524 1396881000,101.8889982625857 1396881300,100.01828524797621 1396881600,100.71533758346668 1396881900,89.64694473305714 1396882200,99.47356202964762 1396882500,97.52670150423809 1396882800,101.60017362862855 1396883100,95.34327935691906 1396883400,87.57327990950951 1396883700,95.77634929850001 1396884000,97.21068866569048 1396884300,89.75804237048095 1396884600,92.54613382897145 1396884900,95.8237833994619 1396885200,92.24089551535238 1396885500,92.26180754094288 1396885800,88.39950791803335 1396886100,101.3293856800238 1396886400,98.29346314241428 1396886700,86.31291150560476 1396887000,98.55024602279524 1396887300,98.14459463028572 1396887600,86.4710330140762 1396887900,92.23643583426669 1396888200,96.03816330875713 1396888500,93.58165590024765 1396888800,98.79285385503808 1396889100,93.15986058352856 1396889400,88.82178359221905 1396889700,101.99004127670952 1396890000,90.24761074930001 1396890300,97.86548538739048 1396890600,88.68035341148097 1396890900,91.66149357967144 1396891200,93.47717327586192 1396891500,89.4878856243524 1396891800,93.61896566644285 1396892100,88.94165988763335 1396892400,95.3785973507238 1396892700,97.06134460021428 1396893000,87.44832527480476 1396893300,100.39492617519524 1396893600,44.44918162148571 1396893900,44.71403990597619 1396894200,47.51179930096665 1396894500,46.28660782405714 1396894800,46.49017331044762 1396895100,44.12167430933809 1396895400,48.46563131172857 1396895700,47.26550993481905 1396896000,44.190248905009526 1396896300,45.72483995979999 1396896600,48.52530752029048 1396896900,46.98359701868095 1396897200,35.20031682647142 1396897500,36.391051872361906 1396897800,35.815722120452385 1396898100,37.054137304442854 1396898400,38.52158987753332 1396898700,36.70524936032381 1396899000,36.69958536931429 1396899300,38.82162547590475 1396899600,37.35440463859524 1396899900,37.317070540785714 1396900200,35.961331335776194 1396900500,37.518013321666665 1396900800,35.43378616795714 1396901100,34.707801000847624 1396901400,37.14762686323809 1396901700,36.70940369932857 1396902000,36.174924233719054 1396902300,35.31302680630952 1396902600,35.0120967047 1396902900,33.884279976790474 1396903200,34.38668140978095 1396903500,36.31196460547143 1396903800,35.0078173765619 1396904100,36.77047805625239 1396904400,33.413027250642855 1396904700,34.869131932433326 1396905000,35.43370823612381 1396905300,34.91818155201429 1396905600,36.422285431604756 1396905900,36.832997926495246 1396906200,33.328748327685716 1396906500,33.392940895476194 1396906800,33.401865298366666 1396907100,35.62329407645714 1396907400,34.39080733414762 1396907700,35.84772633033809 1396908000,34.46215146382857 1396908300,35.358985932719044 1396908600,35.93597779090953 1396908900,35.0559987818 1396909200,35.028556521890465 1396909500,33.22918706428095 1396909800,34.52805579247143 1396910100,35.07599629196191 1396910400,34.74792968025238 1396910700,36.51225985014286 1396911000,36.54271692883333 1396911300,36.21137948412381 1396911600,34.41565081421429 1396911900,35.79135825230476 1396912200,34.51050866199524 1396912500,33.86704474018571 1396912800,34.31580611197619 1396913100,33.235285698866676 1396913400,34.28617798205714 1396913700,34.80957633614762 1396914000,36.796351481538096 1396914300,34.23501761372857 1396914600,36.59908228661905 1396914900,33.91162438840952 1396915200,33.763875591 1396915500,35.083422301890465 1396915800,35.70492642958096 1396916100,33.19965043177143 1396916400,33.9140253649619 1396916700,34.85993704695238 1396917000,34.36866020104286 1396917300,35.902567650733324 1396917600,35.104166193723806 1396917900,33.70840070811428 1396918200,36.65226627920476 1396918500,34.25346793999524 1396918800,36.01381015018571 1396919100,36.2163893068762 1396919400,36.956797467666675 1396919700,35.105637008957146 1396920000,35.58238968094762 1396920300,34.465993269138096 1396920600,35.846645745028574 1396920900,34.99490299111905 1396921200,34.899418982709534 1396921500,36.5781201165 1396921800,33.364365850190474 1396922100,36.698980663680956 1396922400,36.58685077987143 1396922700,35.21147691896191 1396923000,35.15426379775238 1396923300,34.64812232924286 1396923600,37.185028500033326 1396923900,33.660451140523804 1396924200,35.58407522821429 1396924500,35.95738112230476 1396924800,36.97541527099524 1396925100,36.36634970168571 1396925400,35.82836500167619 1396925700,33.727665933866675 1396926000,34.76279121015715 1396926300,33.83066418924762 1396926600,36.80758902513809 1396926900,36.28866319372858 1396927200,36.32776619481905 1396927500,35.91408559490952 1396927800,35.3406741477 1396928100,33.919824714090474 1396928400,34.64616049918095 1396928700,33.88248459847143 1396929000,36.2419144761619 1396929300,33.99061748505238 1396929600,36.16559705784285 1396929900,36.13360489173333 1396930200,35.20924172552381 1396930500,33.92037890221428 1396930800,34.646108066404764 1396931100,34.67471767439524 1396931400,36.203326246885716 1396931700,33.864198268176196 1396932000,36.732941251566665 1396932300,36.468136303557145 1396932600,34.176775291747624 1396932900,36.315645622338096 1396933200,36.120481297328574 1396933500,36.446352248019046 1396933800,34.217023745609524 1396934100,34.0991112886 1396934400,34.422126419890475 1396934700,34.94711776498095 1396935000,36.66573135267143 1396935300,36.450207654661895 1396935600,37.20775875005238 1396935900,33.747911093542854 1396936200,33.567058457433326 1396936500,36.32482912832381 1396936800,34.65286426891429 1396937100,34.87947034400476 1396937400,35.737803341795235 1396937700,33.967688206785716 1396938000,36.136253856676184 1396938300,34.87350645156667 1396938600,36.11121764005714 1396938900,36.92382527134762 1396939200,34.279683428538085 1396939500,37.326170943128574 1396939800,35.73287161181905 1396940100,37.30927058450953 1396940400,34.455920328800005 1396940700,36.050691134590465 1396941000,35.25542942168095 1396941300,36.744210193171426 1396941600,36.078397677661904 1396941900,35.640264208752384 1396942200,37.32158448284286 1396942500,35.18555159003333 1396942800,34.564444629123805 1396943100,36.12436903311429 1396943400,36.19551851060476 1396943700,35.463223724395235 1396944000,35.66072588908571 1396944300,37.55993984767618 1396944600,36.659909432266666 1396944900,34.17901414875714 1396945200,34.59256790254761 1396945500,37.653794632938094 1396945800,36.66479078662857 1396946100,37.426549552219036 1396946400,34.98925537980952 1396946700,36.748717440300005 1396947000,36.64470131029047 1396947300,34.97489089418095 1396947600,84.49467345467144 1396947900,85.5438574180619 1396948200,83.56184500825238 1396948500,88.27552326764288 1396948800,88.36035230183333 1396949100,88.60894126642381 1396949400,87.9747748254143 1396949700,83.69359005180476 1396950000,82.25065609289523 1396950300,88.3772531727857 1396950600,83.74471602687619 1396950900,80.43606768796667 1396951200,93.60682876445713 1396951500,87.94180685524763 1396951800,96.4818277893381 1396952100,90.96867686222856 1396952400,89.80804359951904 1396952700,100.6150752654095 1396953000,97.8346930542 1396953300,98.00025915849048 1396953600,95.47254591558097 1396953900,98.82378344767143 1396954200,97.58946361246191 1396954500,95.10767026915238 1396954800,102.83586534414287 1396955100,90.60470941313332 1396955400,102.5685348604238 1396955700,93.9569368141143 1396956000,95.98356219390476 1396956300,89.53939137609524 1396956600,96.1846544228857 1396956900,97.32285837207618 1396957200,103.47711198756669 1396957500,103.12656724855715 1396957800,102.99413014904762 1396958100,93.17275180313808 1396958400,103.82626023452856 1396958700,95.27137429261906 1396959000,101.61293440780952 1396959300,91.4643161609 1396959600,96.09840935369049 1396959900,103.45987705818096 1396960200,103.16399077657142 1396960500,98.9637422402619 1396960800,100.79426350685236 1396961100,90.87143261024286 1396961400,99.5921142809333 1396961700,97.94382016732379 1396962000,89.6079104991143 1396962300,89.96098433670475 1396962600,89.89299669859524 1396962900,99.7526851408857 1396963200,90.4400953360762 1396963500,95.66255691256666 1396963800,93.89841522675715 1396964100,97.00146993544763 1396964400,99.5038690210381 1396964700,99.16332983242857 1396965000,96.46417810581906 1396965300,95.65285445570952 1396965600,94.6112879996 1396965900,102.04388170219048 1396966200,93.55479973618095 1396966500,92.41851937427143 1396966800,100.16878293696192 1396967100,94.03968546975237 1396967400,101.84251395834286 1396967700,93.54459501303332 1396968000,99.5366459091238 1396968300,89.03521774251429 1396968600,94.48965873140476 1396968900,93.81980843679523 1396969200,101.40532890088569 1396969500,103.8187729023762 1396969800,95.72750510236664 1396970100,101.55816968245712 1396970400,99.56336416124762 1396970700,103.85382410733808 1396971000,101.36084901462856 1396971300,89.63031500241905 1396971600,99.81051632180952 1396971900,96.973471994 1396972200,88.67597367849045 1396972500,92.44140849028095 1396972800,103.17648879267144 1396973100,103.25282718076191 1396973400,101.22489696345238 1396973700,104.15919810934284 1396974000,101.36289391023331 1396974300,88.6289022526238 1396974600,93.07841664831429 1396974900,88.97050249690477 1396975200,89.99368160689524 1396975500,91.9968438226857 1396975800,96.5597592223762 1396976100,102.07076444586669 1396976400,102.30929229745712 1396976700,98.38449592204763 1396977000,103.38351976953811 1396977300,96.54114507652857 1396977600,102.77216264351904 1396977900,95.82007318730952 1396978200,92.9980707675 1396978500,103.2325138873905 1396978800,94.78431213178095 1396979100,96.63925642917143 1396979400,93.85400235676191 1396979700,99.20507226515238 1396980000,51.77533594484285 1396980300,45.577864485133325 1396980600,51.18104441262381 1396980900,45.45458551601429 1396981200,47.767957224104755 1396981500,46.52342306159524 1396981800,50.29876665038572 1396982100,45.78312997957619 1396982400,49.00896415986666 1396982700,47.36162850745714 1396983000,46.337031517947615 1396983300,50.428618174638096 1396983600,37.83045482952857 1396983900,37.86593283671905 1396984200,38.103652347709534 1396984500,39.5074638518 1396984800,39.84149258209048 1396985100,36.97248914828096 1396985400,37.98464623297143 1396985700,38.839260067361906 1396986000,38.40320793915238 1396986300,40.88447608404286 1396986600,40.459767148233325 1396986900,39.74226071542381 1396987200,36.60233578381428 1396987500,38.09510843080476 1396987800,38.68813627609524 1396988100,37.676460689485715 1396988400,38.460630099176186 1396988700,38.323250330566665 1396989000,37.60419292005715 1396989300,36.548499838647615 1396989600,38.3319615565381 1396989900,36.131716256728566 1396990200,38.484903055319045 1396990500,38.59498251410953 1396990800,38.2657646477 1396991100,36.869584297890476 1396991400,35.74989960808095 1396991700,35.38453047677143 1396992000,37.978879391161904 1396992300,38.56066408475238 1396992600,37.62189233834286 1396992900,35.592891402433345 1396993200,38.77845956202381 1396993500,39.00376304861429 1396993800,36.77764002250476 1396994100,37.43396699069524 1396994400,38.09346434138571 1396994700,37.93739307717619 1396995000,38.871311726466665 1396995300,35.46386064915714 1396995600,37.336457057147605 1396995900,37.78915078033809 1396996200,38.59002023552857 1396996500,38.53344412891904 1396996800,38.95684420650952 1396997100,37.098810187199994 1396997400,38.382204054690476 1396997700,36.77417853698096 1396998000,36.74660727507143 1396998300,36.078055932361906 1396998600,38.345485933152375 1396998900,39.023366384242856 1396999200,36.112353115333335 1396999500,35.31879926892381 1396999800,38.36446636991428 1397000100,37.59050730670476 1397000400,38.956083486795244 1397000700,36.133142308485716 1397001000,35.415597369876195 1397001300,37.109019903866674 1397001600,35.484721234757146 1397001900,36.19745762344762 1397002200,35.66164953853809 1397002500,36.06170729002857 1397002800,35.597197658919036 1397003100,38.99568352150953 1397003400,36.3017508538 1397003700,36.970530820190476 1397004000,38.79682818288096 1397004300,37.91910778037143 1397004600,37.6894118269619 1397004900,38.04695514235238 1397005200,38.54743188554285 1397005500,38.75026040473333 1397005800,37.81758249222381 1397006100,38.814493384514286 1397006400,37.40349487160477 1397006700,36.37850866319523 1397007000,38.79709254978572 1397007300,37.450117500176184 1397007600,38.91621701696667 1397007900,35.45977839865714 1397008200,36.89661062524762 1397008500,39.1052081686381 1397008800,36.32002894242856 1397009100,39.09501403181905 1397009400,39.15191936830952 1397009700,38.8723192569 1397010000,37.605862656590475 1397010300,37.94638874868095 1397010600,38.84453942237143 1397010900,38.477100234361906 1397011200,37.901327778752375 1397011500,39.31743048864285 1397011800,38.138539878633324 1397012100,39.30520177932381 1397012400,35.64026818411428 1397012700,35.973996244904754 1397013000,37.23143062209524 1397013300,36.97255355778572 1397013600,38.571415555876186 1397013900,36.090372772566674 1397014200,39.35973785925714 1397014500,36.72306112004762 1397014800,37.185932926238095 1397015100,36.576658701228574 1397015400,37.80257351691905 1397015700,35.72707432550953 1397016000,36.0987100223 1397016300,38.49063128989047 1397016600,36.26088328598095 1397016900,36.46437923477143 1397017200,38.70169084766191 1397017500,35.91040709435239 1397017800,37.29453814824286 1397018100,35.64433688133333 1397018400,36.94675340682381 1397018700,38.36288989611428 1397019000,35.93481788080476 1397019300,39.13518374519524 1397019600,39.2272818860857 1397019900,36.016687690976184 1397020200,39.567096412166656 1397020500,36.80172535645714 1397020800,35.95545430354762 1397021100,35.64675655323809 1397021400,37.26802015452857 1397021700,38.16060899041904 1397022000,36.97752652340952 1397022300,39.0031194619 1397022600,38.530115578490474 1397022900,37.07177708028095 1397023200,38.61581009497143 1397023500,39.4479628526619 1397023800,36.06583637515238 1397024100,36.92530869774286 1397024400,37.561637089833326 1397024700,37.70773432052381 1397025000,37.89199686521428 1397025300,36.933162388104755 1397025600,38.407133821995245 1397025900,38.32587372838572 1397026200,38.064262215576186 1397026500,36.215463553466655 1397026800,37.67572870725714 1397027100,37.20020516904762 1397027400,37.746891974638096 1397027700,39.47764431352857 1397028000,37.71974442021904 1397028300,35.86098269120952 1397028600,37.5678469523 1397028900,39.102533196390475 1397029200,38.94762464528095 1397029500,37.888381722671426 1397029800,36.8413379561619 1397030100,37.71005703265238 1397030400,38.11195173484286 1397030700,39.86406908643333 1397031000,38.44873617022381 1397031300,38.65652400601428 1397031600,37.85272133620476 1397031900,37.31230344119524 1397032200,39.153597648885714 1397032500,37.88895548787619 1397032800,39.89542718656666 1397033100,37.75258943995714 1397033400,36.20354875364762 1397033700,38.669300643638095 1397034000,79.78075230402858 1397034300,82.56069076521905 1397034600,83.97214976160951 1397034900,89.22572676450001 1397035200,85.89779907529045 1397035500,79.57321561818095 1397035800,87.58022940597141 1397036100,84.79404473376191 1397036400,91.74290171655237 1397036700,86.00744028864284 1397037000,88.86289531813334 1397037300,82.20488530522381 1397037600,99.68602400721429 1397037900,99.07238118060476 1397038200,101.92194335469524 1397038500,88.42294759378571 1397038800,94.85068701747619 1397039100,98.4534085171667 1397039400,89.39730087205713 1397039700,94.30037274124763 1397040000,102.55735337483809 1397040300,94.70838187002855 1397040600,103.24360128721905 1397040900,88.83970175180951 1397041200,101.1093647597 1397041500,98.94092269749045 1397041800,97.66846397748094 1397042100,105.15567850177143 1397042400,91.78472187416192 1397042700,103.98016970845238 1397043000,100.73113035584285 1397043300,93.86415688313332 1397043600,104.09266990162381 1397043900,96.5874706594143 1397044200,102.71687618760477 1397044500,95.95890120519523 1397044800,103.7264410812857 1397045100,100.30916880647621 1397045400,92.39680470866665 1397045700,100.53234422565714 1397046000,93.21549000284763 1397046300,96.74794122713809 1397046600,92.89398824422855 1397046900,90.53180418891905 1397047200,93.57352593340951 1397047500,98.7665040367 1397047800,97.89801999009049 1397048100,98.22405573668095 1397048400,94.24833036607143 1397048700,101.25368009556192 1397049000,101.5666805990524 1397049300,96.03472346964287 1397049600,104.41139105573332 1397049900,100.6253922265238 1397050200,101.73682461901429 1397050500,94.77474846360478 1397050800,90.35559905189524 1397051100,104.19594246558573 1397051400,103.5163282340762 1397051700,92.33873381846666 1397052000,96.37479598945716 1397052300,100.97776264464764 1397052600,100.83755498963808 1397052900,104.17666717932858 1397053200,92.66334590781904 1397053500,97.30530929460951 1397053800,91.9895600185 1397054100,96.67470924209049 1397054400,90.69063247928095 1397054700,104.82804459657143 1397055000,98.89610508426192 1397055300,104.0674299056524 1397055600,91.43991767184286 1397055900,94.12818696333332 1397056200,94.6463726923238 1397056500,96.69077760411429 1397056800,103.35695220000477 1397057100,96.70352064249523 1397057400,93.8005195538857 1397057700,91.5733691733762 1397058000,91.81283123036668 1397058300,102.70905449495714 1397058600,97.67263595384762 1397058900,102.18208330583806 1397059200,101.48786331982859 1397059500,92.74452603741905 1397059800,92.87237384140951 1397060100,102.67906080280001 1397060400,102.14132277459045 1397060700,96.65697336928095 1397061000,91.85468702347143 1397061300,90.81694164026192 1397061600,95.24131648015238 1397061900,90.78581071124286 1397062200,94.32684996313331 1397062500,97.3651345258238 1397062800,92.60333813671429 1397063100,92.33657059850478 1397063400,105.01856105389523 1397063700,100.0505249334857 1397064000,105.6417337893762 1397064300,96.23110551446665 1397064600,101.53964433175716 1397064900,93.98783550734764 1397065200,100.61365172463807 1397065500,92.80102180742857 1397065800,90.76838161361906 1397066100,105.64703497500952 1397066400,51.1013177961 1397066700,53.489854049390466 1397067000,49.70139676428096 1397067300,49.67014633887143 1397067600,50.143947894161904 1397067900,52.10585828105238 1397068200,51.21581189104286 1397068500,53.52434807213334 1397068800,47.77234001592382 1397069100,52.14941188891429 1397069400,49.73849603830476 1397069700,48.785334858695244 1397070000,41.28585687178571 1397070300,41.269410713576185 1397070600,39.62797493556668 1397070900,39.926100318757136 1397071200,40.857624111547615 1397071500,40.8679620163381 1397071800,40.46658785292857 1397072100,39.71685018391905 1397072400,39.078402499209524 1397072700,43.4129017353 1397073000,43.300565687490476 1397073300,41.24788342628095 1397073600,41.43630313987143 1397073900,40.127299789361906 1397074200,37.65749263045239 1397074500,37.86506637364286 1397074800,41.142723083633335 1397075100,39.97846737742381 1397075400,40.85889415791428 1397075700,41.09196698150476 1397076000,39.25486547309524 1397076300,37.62629778838571 1397076600,38.206172269076184 1397076900,37.71509513836666 1397077200,37.86284028455713 1397077500,38.76171150874762 1397077800,37.594194670638096 1397078100,37.79671279512857 1397078400,38.925865905519046 1397078700,38.508674560009524 1397079000,39.0285114839 1397079300,38.881268641690475 1397079600,39.75406698378096 1397079900,40.93797360997142 1397080200,37.612190208561906 1397080500,37.58504872785238 1397080800,40.538922066442865 1397081100,39.15939470543333 1397081400,40.207866888723814 1397081700,38.00925911101429 1397082000,40.472817876404754 1397082300,40.86055929519524 1397082600,39.713438021185716 1397082900,37.60042884277619 1397083200,40.76856384476665 1397083500,40.36438119475713 1397083800,40.205222085447616 1397084100,37.3533218781381 1397084400,40.39634827362857 1397084700,37.75923503401905 1397085000,38.104481019309524 1397085300,39.531188576999995 1397085600,38.289773071190474 1397085900,39.88298769098096 1397086200,39.67727621547142 1397086500,37.68464935386191 1397086800,39.883970516452386 1397087100,40.96337809164285 1397087400,37.918852684633336 1397087700,39.67043643492381 1397088000,38.65317577341428 1397088300,39.13160144900476 1397088600,38.448595954395245 1397088900,38.724558259685715 1397089200,37.43112348357619 1397089500,41.24912361836667 1397089800,39.82955683115714 1397090100,39.34061998104762 1397090400,38.88009949323809 1397090700,39.510176806728566 1397091000,38.880543042519044 1397091300,38.807191233809526 1397091600,39.2307861669 1397091900,38.48637261089047 1397092200,38.110080552280955 1397092500,39.62374502127143 1397092800,40.775823649361904 1397093100,38.02351509185237 1397093400,37.55058021954286 1397093700,38.41433031393333 1397094000,41.353406383323815 1397094300,40.756996580714286 1397094600,39.83286897600476 1397094900,41.17384089909525 1397095200,39.24540218158571 1397095500,41.404848600776184 1397095800,38.664374847166656 1397096100,38.447830140957144 1397096400,40.04624042364762 1397096700,39.01410396703809 1397097000,40.01439073932857 1397097300,38.73635112081905 1397097600,39.99548255120952 1397097900,38.6342350423 1397098200,37.74257875149047 1397098500,41.19467456008096 1397098800,41.08639223607143 1397099100,41.444204501861904 1397099400,40.43456108585239 1397099700,40.30677756804286 1397100000,39.81934561363333 1397100300,38.09454347492381 1397100600,38.35515552951429 1397100900,38.76353351660476 1397101200,41.17372068839524 1397101500,38.31241381268571 1397101800,41.31946888847619 1397102100,39.726559598866665 1397102400,40.50513568475714 1397102700,38.091275565747615 1397103000,38.7338722903381 1397103300,41.49925300412857 1397103600,38.73721883531905 1397103900,38.86614640540952 1397104200,38.4778895394 1397104500,38.211235137390474 1397104800,38.63541151818095 1397105100,40.27912899637143 1397105400,39.538732838761895 1397105700,39.93972572635238 1397106000,38.221602172242854 1397106300,40.94804912203333 1397106600,40.88340261182381 1397106900,37.840823930314286 1397107200,39.29596513990476 1397107500,38.04442764599524 1397107800,40.94520883198571 1397108100,40.73330492297619 1397108400,41.39961904386666 1397108700,38.744722978657144 1397109000,39.631731151547605 1397109300,38.551939603938095 1397109600,39.30636830932857 1397109900,39.917842053919045 1397110200,38.04963268320952 1397110500,40.7032316427 1397110800,40.02436391769048 1397111100,41.17446702118095 1397111400,38.95319343337143 1397111700,41.486796325861896 1397112000,41.87572939305238 1397112300,41.56558661064285 1397112600,41.00740323663333 1397112900,41.152749021023816 1397113200,40.20569125591429 1397113500,38.67877021360477 1397113800,40.63375797869524 1397114100,40.78404772248571 1397114400,41.88201675157619 1397114700,40.11312193166667 1397115000,39.040833202957145 1397115300,40.69748770604762 1397115600,41.887741373938105 1397115900,38.68653420452857 1397116200,39.28911072171905 1397116500,40.16008333890952 1397116800,38.6808585395 1397117100,38.09632303429048 1397117400,39.36281344218095 1397117700,41.48380463457143 1397118000,38.20363550206191 1397118300,39.75291861705238 1397118600,41.09344594884285 1397118900,41.86481372093333 1397119200,42.00142540552381 1397119500,39.75484180811429 1397119800,41.87594193940475 1397120100,38.22352113119524 1397120400,91.43375607108572 1397120700,90.03807226147619 1397121000,84.69766392986666 1397121300,88.21113875205714 1397121600,83.08097845254763 1397121900,93.18020934813808 1397122200,86.20134253482857 1397122500,89.85557384591905 1397122800,83.50816701730953 1397123100,84.160091887 1397123400,94.85429711909046 1397123700,91.61310591678092 1397124000,104.94837484747144 1397124300,94.61762198886193 1397124600,92.58746822605238 1397124900,97.84851541034287 1397125200,97.72558507353334 1397125500,92.77094370302382 1397125800,101.44278200561428 1397126100,95.68544209640476 1397126400,92.97048362209524 1397126700,95.23791799758571 1397127000,98.84095920877618 1397127300,101.37524553406666 1397127600,99.49984979475714 1397127900,100.2023603372476 1397128200,94.06053426043808 1397128500,106.40542303802856 1397128800,106.63604869251905 1397129100,102.74227601780953 1397129400,92.1609099277 1397129700,100.42956880589048 1397130000,101.90247948448095 1397130300,107.72180219047144 1397130600,107.75171076016191 1397130900,105.55715146755236 1397131200,93.29081317454286 1397131500,107.51230267913331 1397131800,102.07644066802382 1397132100,105.09187558741428 1397132400,98.80777225420476 1397132700,97.41651912399523 1397133000,99.7183977543857 1397133300,94.6699984073762 1397133600,98.03646921686666 1397133900,106.04312088315712 1397134200,92.95162674984762 1397134500,94.76373998593807 1397134800,94.43052667972856 1397135100,98.88424992071907 1397135400,108.3919915084095 1397135700,95.22453118889999 1397136000,94.78607421639047 1397136300,107.10372881478096 1397136600,106.58321262607143 1397136900,92.9969540216619 1397137200,104.51308119295237 1397137500,102.98104709244285 1397137800,104.78445816623329 1397138100,100.42113419682379 1397138400,108.3935644016143 1397138700,93.24121738680478 1397139000,96.29690462319523 1397139300,98.8990109585857 1397139600,99.7581218260762 1397139900,107.31063149966668 1397140200,101.53654088475712 1397140500,93.30608290214762 1397140800,99.11727627133808 1397141100,99.26274930472856 1397141400,108.05377656561905 1397141700,102.20079679680953 1397142000,102.7946283025 1397142300,104.04368822059048 1397142600,104.95970052528095 1397142900,102.80734980797142 1397143200,96.44914388986193 1397143500,106.64611155695238 1397143800,104.38275601014288 1397144100,104.54620594353334 1397144400,108.6285873661238 1397144700,105.5315743754143 1397145000,105.96500865470476 1397145300,107.92849615359523 1397145600,95.13228682898571 1397145900,100.68521068397621 1397146200,102.01808296906664 1397146500,98.00487045505714 1397146800,106.17433709484762 1397147100,104.95004038003809 1397147400,104.29289737802857 1397147700,108.72059121131906 1397148000,96.92376529010951 1397148300,104.5484051936 1397148600,101.61100689549049 1397148900,97.80381001728097 1397149200,95.37293272547144 1397149500,107.14512014556192 1397149800,102.34570879775238 1397150100,106.02480154304287 1397150400,101.55882207873331 1397150700,96.36037810042382 1397151000,98.24896557341428 1397151300,98.96024624930477 1397151600,108.43001861239523 1397151900,92.96064048578569 1397152200,108.6485988549762 1397152500,108.57276915646663 1397152800,56.06821544855714 1397153100,52.75045584894761 1397153400,55.8761087868381 1397153700,52.247007319528564 1397154000,49.89089790601905 1397154300,51.165875711309525 1397154600,55.787389276400006 1397154900,49.83302896699047 1397155200,53.246737218580954 1397155500,50.24366597497142 1397155800,51.600194125161906 1397156100,50.33849098765238 1397156400,44.99282976254285 1397156700,43.797578861333335 1397157000,45.198459448323796 1397157300,44.24828534461429 1397157600,45.52211392530477 1397157900,43.463595900195244 1397158200,44.04820785768571 1397158500,43.77608845597619 1397158800,43.371152165666665 1397159100,44.999003786157154 1397159400,44.104018962547606 1397159700,44.81386573893809 1397160000,42.72437499592857 1397160300,40.29338979511905 1397160600,42.18137909990953 1397160900,40.3435080556 1397161200,41.92247090519048 1397161500,42.31540316538096 1397161800,43.63274601157143 1397162100,39.680611624561905 1397162400,39.93668100155238 1397162700,39.88589398054286 1397163000,41.209520921133326 1397163300,42.95049947662381 1397163600,42.63954544591428 1397163900,42.21662310150476 1397164200,42.86672821459524 1397164500,40.56707435448571 1397164800,39.63118729157618 1397165100,39.518045271966656 1397165400,42.71664891695714 1397165700,42.23496712184762 1397166000,42.114512682038104 1397166300,40.67930566372857 1397166600,40.84843393371905 1397166900,43.17980936550953 1397167200,39.5227439776 1397167500,42.372618543490475 1397167800,40.52188322968095 1397168100,39.445969863071426 1397168400,42.270173806661894 1397168700,40.629400615852376 1397169000,42.203285968342854 1397169300,42.152698248433325 1397169600,41.468004882923815 1397169900,42.44672190501429 1397170200,41.66806923580477 1397170500,40.49677332559524 1397170800,42.27976671708571 1397171100,41.70719391137619 1397171400,39.40854156616666 1397171700,42.97233231455714 1397172000,41.55549714464762 1397172300,42.855120260738104 1397172600,42.91900986712857 1397172900,41.175033407019036 1397173200,41.43329539050953 1397173500,41.0730428481 1397173800,41.21523874289048 1397174100,43.00586305918095 1397174400,42.58114748447143 1397174700,39.94211461006191 1397175000,41.88468350715237 1397175300,43.43451941864286 1397175600,41.840536138233325 1397175900,42.60926031192381 1397176200,42.54946017921428 1397176500,40.881924865404756 1397176800,40.97549244889524 1397177100,42.39184140148571 1397177400,41.50291031687619 1397177700,41.792699503166666 1397178000,42.36948030435714 1397178300,42.635597727247614 1397178600,40.618804406138096 1397178900,40.12735360912857 1397179200,40.71479763451904 1397179500,41.58521282420952 1397179800,40.931065269200005 1397180100,41.843391511590475 1397180400,39.79124384888095 1397180700,41.62382307507143 1397181000,41.06420153256191 1397181300,41.73836940055238 1397181600,41.29727627664286 1397181900,40.75148673593333 1397182200,43.23845543132379 1397182500,40.36852423941429 1397182800,42.36236706420476 1397183100,43.34292408839524 1397183400,41.80646555298571 1397183700,43.16486014477619 1397184000,40.16607258036665 1397184300,41.64926222385714 1397184600,41.50964874094762 1397184900,39.72146332333811 1397185200,41.46945793682857 1397185500,41.17998807311905 1397185800,42.39050443490952 1397186100,43.472069114300005 1397186400,40.069354829190466 1397186700,41.04353649928096 1397187000,41.51733037817142 1397187300,41.569253416861905 1397187600,42.855191264352385 1397187900,41.53697552044286 1397188200,39.87947853913333 1397188500,42.61869018792381 1397188800,43.325033066314276 1397189100,41.84877361210476 1397189400,42.125029324895245 1397189700,40.45978147018571 1397190000,40.698059969176185 1397190300,40.76359762316665 1397190600,41.55332504235715 1397190900,43.55037850264762 1397191200,41.932377162138096 1397191500,40.62106915222857 1397191800,40.92446999111905 1397192100,41.40361964270952 1397192400,42.3680359028 1397192700,41.642573088190474 1397193000,41.45966032908096 1397193300,42.156235830171426 1397193600,40.87210188456189 1397193900,40.227815471252384 1397194200,40.017300116442854 1397194500,40.932119987233335 1397194800,40.30089194612381 1397195100,41.28732683981429 1397195400,43.04113892330476 1397195700,42.822022559995226 1397196000,42.40799620548571 1397196300,43.38172716597619 1397196600,41.107437164866674 1397196900,43.52682215495715 1397197200,41.59100429774762 1397197500,41.605061368338106 1397197800,41.63033502592858 1397198100,40.40874651261905 1397198400,43.925771517109524 1397198700,40.5852771113 1397199000,41.402233374090464 1397199300,41.32333223368096 1397199600,40.35228915987143 1397199900,40.670052425161906 1397200200,40.24788572565239 1397200500,41.24551083134285 1397200800,43.54996102943333 1397201100,41.44854263242381 1397201400,40.592981614014285 1397201700,42.68843023540476 1397202000,44.099498886295244 1397202300,41.04983087238571 1397202600,41.24626021197619 1397202900,44.02280488376667 1397203200,40.85796229305714 1397203500,42.19515388884762 1397203800,41.116346627338096 1397204100,43.89458616302856 1397204400,44.098703105919036 1397204700,43.438850908309526 1397205000,41.446635263299996 1397205300,41.808890377290474 1397205600,41.17160368708095 1397205900,43.77285329657143 1397206200,43.875495015561896 1397206500,41.90018502995238 1397206800,150.11416299114285 1397207100,137.94530219133333 1397207400,144.6334341385238 1397207700,149.51564213171432 1397208000,143.41990210090475 1397208300,142.73781347509527 1397208600,133.90156072228572 1397208900,153.8307040924762 1397209200,155.94723944466662 1397209500,157.94180267585713 1397209800,151.74447796904758 1397210100,147.5240374422381 1397210400,160.4399082654286 1397210700,181.58858187161903 1397211000,169.73555219080953 1397211300,172.389971935 1397211600,172.43367292619044 1397211900,177.15712295738098 1397212200,152.9661881535714 1397212500,159.0718632997619 1397212800,171.97481702595238 1397213100,178.63181339514287 1397213400,172.5632444573333 1397213700,164.69798161152383 1397214000,167.24617561871426 1397214300,178.46710182490474 1397214600,178.57254871109524 1397214900,174.58250742728572 1397215200,165.1878617724762 1397215500,184.07412901666663 1397215800,172.9609643788571 1397216100,180.07714589604763 1397216400,162.9189098412381 1397216700,166.79134174542855 1397217000,182.60459199961903 1397217300,158.04934815980948 1397217600,172.660947021 1397217900,171.7513659231905 1397218200,179.83333544338097 1397218500,165.7802077655714 1397218800,163.9054533807619 1397219100,185.0954604179524 1397219400,174.48494929414287 1397219700,160.50121529533334 1397220000,163.15537837152382 1397220300,187.30299490671428 1397220600,163.24733731490474 1397220900,175.68351479709526 1397221200,170.15219261828568 1397221500,184.11989085147619 1397221800,180.21550143266663 1397222100,175.47774239485713 1397222400,157.90368772504763 1397222700,183.9755844242381 1397223000,170.93281306342857 1397223300,185.54350791161903 1397223600,172.47341702480952 1397223900,178.439768728 1397224200,159.70445344519047 1397224500,179.98204089638097 1397224800,167.81040194257142 1397225100,168.2187096737619 1397225400,161.24544227895237 1397225700,162.09887494614287 1397226000,163.27330791633332 1397226300,167.5539247315238 1397226600,184.47333943071428 1397226900,168.77036112390473 1397227200,179.46028309509526 1397227500,160.22033513928568 1397227800,175.47746858047614 1397228100,172.20886373766666 1397228400,187.10477248685714 1397228700,183.15975149704758 1397229000,171.4259823012381 1397229300,181.04270592542855 1397229600,163.58721944361903 1397229900,174.67346459980953 1397230200,160.04954923399998 1397230500,168.26099800019045 1397230800,164.60167363438097 1397231100,179.40037903557143 1397231400,172.5433219387619 1397231700,180.3800691899524 1397232000,173.3156721681429 1397232300,160.45881132133334 1397232600,179.9327048355238 1397232900,182.87598722571425 1397233200,184.99248187990474 1397233500,175.05376600509524 1397233800,180.50899680528573 1397234100,180.4702067204762 1397234400,162.58884957366664 1397234700,162.85041731585713 1397235000,160.0578085550476 1397235300,167.5360763362381 1397235600,172.15161999642856 1397235900,187.89073144261903 1397236200,170.89104414480948 1397236500,179.755958083 1397236800,178.77803213019047 1397237100,164.11802683438097 1397237400,159.7462252895714 1397237700,174.3786472787619 1397238000,179.01505092395237 1397238300,187.96087337014285 1397238600,168.77910022433338 1397238900,184.9191388355238 1397239200,67.94947988201429 1397239500,70.78572866320476 1397239800,69.95450862529523 1397240100,64.94542849078572 1397240400,65.18663752907621 1397240700,64.66393425606668 1397241000,67.89201775305715 1397241300,71.34915330124763 1397241600,66.0845752792381 1397241900,70.07651228672856 1397242200,67.16732187411904 1397242500,71.84987756170952 1397242800,49.8289137697 1397243100,49.720526822590465 1397243400,48.465039186280954 1397243700,47.261535099671434 1397244000,49.9143570587619 1397244300,46.78014671785238 1397244600,47.31002870094285 1397244900,46.78417727823333 1397245200,49.262540262723796 1397245500,49.330591105814285 1397245800,49.16805238190476 1397246100,47.98147401359524 1397246400,42.571804822685706 1397246700,45.99192722587619 1397247000,44.30169802996666 1397247300,43.88514561645714 1397247600,44.65782222784762 1397247900,42.9987497494381 1397248200,42.752693340528566 1397248500,43.90881865711904 1397248800,43.16595370110952 1397249100,43.245223054200004 1397249400,45.980378242490474 1397249700,44.46556503418097 1397250000,43.44475989277142 1397250300,44.28481252026191 1397250600,45.35142912105238 1397250900,41.96655447704285 1397251200,44.889346526133345 1397251500,43.88834561862381 1397251800,42.12615608071428 1397252100,42.74381334610476 1397252400,43.49980703279524 1397252700,44.35119715128572 1397253000,42.54569660917619 1397253300,43.734382780066674 1397253600,44.17468009835714 1397253900,43.23643412444761 1397254200,44.904462292838105 1397254500,44.93768885962857 1397254800,43.34674004791904 1397255100,45.36729708400952 1397255400,41.7779092181 1397255700,41.495857945290474 1397256000,43.01566114678096 1397256300,43.90665077987143 1397256600,44.026737458061895 1397256900,43.421889333452384 1397257200,41.98937191204285 1397257500,42.17934512433333 1397257800,44.914521714623795 1397258100,44.98504101221428 1397258400,44.216108276104755 1397258700,44.18481038149525 1397259000,43.925996765085706 1397259300,42.35375539797619 1397259600,43.262870072666665 1397259900,44.34133171295714 1397260200,43.71393869054762 1397260500,41.645828345238094 1397260800,45.38565579832857 1397261100,44.95813325791904 1397261400,42.628489580209525 1397261700,44.059585740699994 1397262000,45.29414801109047 1397262300,41.99267500088095 1397262600,43.62818935177143 1397262900,43.448484008161905 1397263200,43.271772402052385 1397263500,44.980747292742855 1397263800,43.168417920133344 1397264100,41.907927142523796 1397264400,41.924065254414295 1397264700,41.83913318800476 1397265000,43.312176925595246 1397265300,44.55666082508571 1397265600,42.50536603817619 1397265900,44.28379074836667 1397266200,44.45371103125714 1397266500,42.733606115147616 1397266800,44.122468719438096 1397267100,44.46715193152857 1397267400,43.601573538819046 1397267700,43.089425912909526 1397268000,44.22660620630001 1397268300,45.668828825490465 1397268600,43.47224658988095 1397268900,43.33926181367143 1397269200,43.63682951446191 1397269500,42.09207595475238 1397269800,44.00729597584285 1397270100,43.116872882233345 1397270400,42.29521229882381 1397270700,43.68199125021428 1397271000,41.837940708204755 1397271300,43.43898621879524 1397271600,42.26222678598572 1397271900,41.943897004076184 1397272200,45.15206685166666 1397272500,45.52660235595714 1397272800,42.69974621244762 1397273100,44.033681150538094 1397273400,42.99576119992857 1397273700,43.86567880231905 1397274000,43.64533480740953 1397274300,42.9824542203 1397274600,44.71526479469047 1397274900,42.42709478968095 1397275200,42.140862557271426 1397275500,45.006713636861896 1397275800,44.607172505852375 1397276100,43.94499735374285 1397276400,43.829492415233325 1397276700,43.95541932752381 1397277000,43.721310590114285 1397277300,43.55222394520475 1397277600,43.986857649595244 1397277900,44.10959639888571 1397278200,44.7705854467762 1397278500,44.85524530956667 1397278800,43.528373463457136 1397279100,43.67945971004762 1397279400,43.527526774138096 1397279700,44.186321665928574 1397280000,43.861033199319046 1397280300,45.61344537630952 1397280600,44.8479450677 1397280900,45.66456601119047 1397281200,44.91392891858095 1397281500,45.968790022671435 1397281800,44.63520901776191 1397282100,45.95390293365238 1397282400,42.739822418742854 1397282700,42.32449405663333 1397283000,44.43852455032381 1397283300,46.063437108914286 1397283600,43.807325751104756 1397283900,42.992518686895245 1397284200,44.23795151108571 1397284500,44.754420688776186 1397284800,43.42738144876667 1397285100,45.03318457685714 1397285400,46.08200564724762 1397285700,45.7768405820381 1397286000,43.36277006542857 1397286300,43.51076378021905 1397286600,43.69747442160953 1397286900,43.7969611136 1397287200,42.62746847299047 1397287500,45.28148230798096 1397287800,43.70242848297143 1397288100,45.76779181156191 1397288400,45.96371487345239 1397288700,42.361118094342864 1397289000,46.22484561303333 1397289300,45.11836473552381 1397289600,44.367283189714286 1397289900,43.85126519540476 1397290200,44.37466776849524 1397290500,43.60653461018571 1397290800,44.806227445276186 1397291100,42.694837772466656 1397291400,44.81484755445715 1397291700,43.439177019647616 1397292000,42.41577741143809 1397292300,44.56350163612857 1397292600,44.67391007101905 1397292900,44.07383554260952 1397293200,86.5580927627 1397293500,97.73190463429049 1397293800,93.90533993068097 1397294100,87.17102230267143 1397294400,92.55341774646193 1397294700,92.37486107785236 1397295000,86.44110827274288 1397295300,93.88037530233332 1397295600,96.6277628348238 1397295900,95.82847382351429 1397296200,88.40978879450476 1397296500,97.38402363999523 1397296800,99.62054012528571 1397297100,109.00153622157619 1397297400,95.4326950714667 1397297700,101.87256598865713 1397298000,103.60141795284764 1397298300,98.18501762353809 1397298600,106.32074910032856 1397298900,104.08578999831906 1397299200,94.64486799050951 1397299500,103.81313052760001 1397299800,102.00643267439048 1397300100,97.42850416278095 1397300400,111.95795123177143 1397300700,110.39747945126189 1397301000,100.78849476265238 1397301300,104.74908478154283 1397301600,101.18498336643331 1397301900,108.49225824352379 1397302200,110.96220539931429 1397302500,101.88046492630475 1397302800,108.99310713649523 1397303100,104.1152092735857 1397303400,102.50316162957618 1397303700,111.12807780246666 1397304000,104.71313239235714 1397304300,104.03349134154762 1397304600,107.31737778613814 1397304900,100.75351009102856 1397305200,101.77666895711904 1397305500,111.48849762360952 1397305800,107.444549754 1397306100,109.81886340729048 1397306400,100.94856379748094 1397306700,105.31362369577144 1397307000,112.15455136826193 1397307300,101.73144565055237 1397307600,99.28187024854284 1397307900,104.8945176626333 1397308200,102.93339199612379 1397308500,99.2898072337143 1397308800,110.95803484780475 1397309100,112.59984342709524 1397309400,105.85463724978571 1397309700,109.15879972567622 1397310000,110.51570187206669 1397310300,107.99484746825712 1397310600,97.49559484564762 1397310900,99.31825048723809 1397311200,97.95374511012855 1397311500,96.98347916631904 1397311800,101.7285610587095 1397312100,103.1176880383 1397312400,100.70402508269045 1397312700,97.88879970538096 1397313000,105.34001794707144 1397313300,101.24295511486191 1397313600,109.61347950225235 1397313900,97.01377261874285 1397314200,110.37216309313331 1397314500,112.17514342182379 1397314800,108.36807409781427 1397315100,108.65565591840478 1397315400,111.86175762859524 1397315700,100.2774529657857 1397316000,112.8526813165762 1397316300,109.32280591396663 1397316600,108.57968567485712 1397316900,102.73950021944763 1397317200,105.7019028303381 1397317500,107.43957154202856 1397317800,106.90981834401907 1397318100,108.27151425380951 1397318400,98.3179670545 1397318700,102.69766623599048 1397319000,103.95872964538096 1397319300,101.19224394807142 1397319600,99.79165468596192 1397319900,99.25989955175238 1397320200,102.90662763794285 1397320500,104.94699714383331 1397320800,98.06700667722382 1397321100,112.2101264840143 1397321400,109.31813617940477 1397321700,108.77531291729522 1397322000,99.85502540408571 1397322300,106.75750712087618 1397322600,105.57973491296669 1397322900,112.83107499115714 1397323200,109.08176369864763 1397323500,106.33864704923808 1397323800,110.74689835952856 1397324100,99.62284878051905 1397324400,97.39224625740951 1397324700,108.1999514458 1397325000,98.7366455879905 1397325300,99.01804083488096 1397325600,58.74452163307143 1397325900,55.71742904516191 1397326200,58.01668585855238 1397326500,59.87229052724285 1397326800,56.03376441733332 1397327100,55.40549062322381 1397327400,54.70521108111429 1397327700,54.86560818510476 1397328000,54.43631488249524 1397328300,54.60644130148571 1397328600,56.81779949837619 1397328900,56.113947030966656 1397329200,48.593248311457145 1397329500,49.33397892824761 1397329800,48.958520746538106 1397330100,47.827432244928566 1397330400,45.916558597219044 1397330700,48.64481567550952 1397331000,47.0979714917 1397331300,45.863653113990466 1397331600,49.261629143680956 1397331900,47.01003023647142 1397332200,46.4800155148619 1397332500,49.41380631035239 1397332800,47.484282916742856 1397333100,45.18500764463333 1397333400,45.257290184323814 1397333700,46.185622485014285 1397334000,46.82308086330476 1397334300,44.08500414479525 1397334600,46.26412108378572 1397334900,47.74397689547619 1397335200,44.92220303546666 1397335500,47.57866314595714 1397335800,47.75543687494761 1397336100,44.9734411742381 1397336400,46.56411665912857 1397336700,44.49995351451904 1397337000,46.51231625350953 1397337300,46.7601402965 1397337600,44.55615959389047 1397337900,46.44725377068095 1397338200,46.841481938971434 1397338500,45.02611205976189 1397338800,44.26638333235237 1397339100,43.96941680094285 1397339400,45.91980742663333 1397339700,47.54584571682382 1397340000,46.847955684614284 1397340300,45.30546693210477 1397340600,45.71641946389524 1397340900,44.69450063358571 1397341200,44.23564582367619 1397341500,45.52037248146666 1397341800,45.45342324375714 1397342100,45.69480163144762 1397342400,47.427395196338104 1397342700,46.03785871992857 1397343000,46.052812547919046 1397343300,44.14743018120953 1397343600,47.615176766000005 1397343900,46.727869795990465 1397344200,47.152824018780954 1397344500,45.308297256671416 1397344800,45.66711592036191 1397345100,45.75439457595239 1397345400,44.44962607704286 1397345700,46.43902548423333 1397346000,47.300580188023794 1397346300,44.350369282514286 1397346600,44.048200146504755 1397346900,46.66374381029524 1397347200,44.807093040985706 1397347500,46.21717635697618 1397347800,46.51220001866666 1397348100,45.02425019715714 1397348400,125.74404761904762 1397348700,45.9514440237381 1397349000,47.23492620322857 1397349300,46.81954325781904 1397349600,47.24811205190952 1397349900,43.86189552850001 1397350200,44.76271551919047 1397350500,44.15616271418096 1397350800,45.57190349737142 1397351100,47.3708523912619 1397351400,45.68861343005239 1397351700,47.22474503544285 1397352000,45.14204628543333 1397352300,45.199054100723814 1397352600,47.4304612070143 1397352900,45.55892334790476 1397353200,47.02215718929524 1397353500,44.81710990578571 1397353800,47.67317950917619 1397354100,46.18372965276666 1397354400,46.93015141715714 1397354700,44.25836041824761 1397355000,45.878394998538106 1397355300,47.519332562328565 1397355600,47.430773563819045 1397355900,44.11731535270953 1397356200,45.152293876499996 1397356500,45.718220502090475 1397356800,44.64144020978095 1397357100,46.87981467257143 1397357400,44.705309887161896 1397357700,45.361261158452386 1397358000,46.63526540454286 1397358300,45.917940711433324 1397358600,46.95130796402381 1397358900,47.84929589061429 1397359200,44.47809151280476 1397359500,46.85761610369524 1397359800,44.94816233678571 1397360100,45.69213310007619 1397360400,44.173117569866655 1397360700,44.59273667205714 1397361000,45.33565677524762 1397361300,45.4319313164381 1397361600,47.669769437228574 1397361900,47.046120684719035 1397362200,47.97504139650953 1397362500,46.4900360413 1397362800,45.06804540459047 1397363100,45.41925107208097 1397363400,45.39541512177142 1397363700,45.4294892154619 1397364000,46.82280907335238 1397364300,46.26162456954285 1397364600,45.68753004563332 1397364900,44.74963288442381 1397365200,44.249270937514275 1397365500,45.04349347230475 1397365800,44.605480853995225 1397366100,47.32481583768571 1397366400,44.640468021776186 1397366700,47.09482961586665 1397367000,45.74799190195714 1397367300,44.50631117804762 1397367600,47.4711582929381 1397367900,46.54620085232857 1397368200,45.17816509911904 1397368500,47.82128422110952 1397368800,44.431033255500004 1397369100,45.06471890899047 1397369400,47.27306866358095 1397369700,47.10983314977143 1397370000,45.43684867966191 1397370300,44.53530188235239 1397370600,47.726955146042854 1397370900,45.556873885633344 1397371200,45.09237746922381 1397371500,46.381211575114285 1397371800,47.965313559004755 1397372100,44.506031549495226 1397372400,47.40250206638571 1397372700,46.636619102276185 1397373000,46.05596313286666 1397373300,47.337928919257145 1397373600,48.23234531684762 1397373900,45.2933129399381 1397374200,44.95851803172857 1397374500,48.042896028519046 1397374800,47.074621833609534 1397375100,46.1581940862 1397375400,46.70672875729048 1397375700,47.40358657308095 1397376000,47.52069902337143 1397376300,48.11558862806189 1397376600,46.15082353655238 1397376900,45.62453649724286 1397377200,47.01699040053333 1397377500,46.128685406623795 1397377800,46.851608101514294 1397378100,46.16059795570476 1397378400,45.100078384795246 1397378700,46.37324272088571 1397379000,47.266647478276184 1397379300,47.707551897366656 1397379600,94.42709450725714 1397379900,89.97253292594763 1397380200,93.37249094643808 1397380500,98.43377600362857 1397380800,93.36250512801905 1397381100,97.22787831680952 1397381400,94.6606060708 1397381700,91.05057497769049 1397382000,98.60502786148096 1397382300,88.93012440397145 1397382600,94.9307697502619 1397382900,90.64062044665238 1397383200,97.48800141214286 1397383500,104.2601180368333 1397383800,104.2152284696238 1397384100,107.44056627971428 1397384400,108.03543551810476 1397384700,107.77966914259524 1397385000,102.84813724918571 1397385300,106.3030516882762 1397385600,105.46085683246667 1397385900,103.05674559775714 1397386200,105.79028863284763 1397386500,111.23027514173809 1397386800,101.33221067092856 1397387100,112.67726845901905 1397387400,99.12946601820951 1397387700,103.19137204200001 1397388000,102.87685251009049 1397388300,108.26334162808097 1397388600,100.39607306167143 1397388900,112.34936832346192 1397389200,111.50123398115238 1397389500,108.70184765344288 1397389800,105.62944691413333 1397390100,113.1840067037238 1397390400,111.97530882741431 1397390700,106.68621028040477 1397391000,109.93069294099523 1397391300,107.78162989408571 1397391600,108.1248635136762 1397391900,104.02577903716669 1397392200,106.12843879245716 1397392500,99.99984058024764 1397392800,104.4695560670381 1397393100,109.88617490972857 1397393400,114.00687378791906 1397393700,114.17169449700951 1397394000,107.7471519302 1397394300,108.56878707569048 1397394600,101.84342675108095 1397394900,110.00230117497145 1397395200,100.0177512577619 1397395500,103.44880016075236 1397395800,109.59360989844284 1397396100,103.87357384713331 1397396400,99.71460238332381 1397396700,112.23141645291427 1397397000,103.89621320880477 1397397300,99.94900651179522 1397397600,100.15738290898571 1397397900,102.9962176203762 1397398200,101.82382910596668 1397398500,111.37135836485712 1397398800,104.13728931234762 1397399100,111.8725466495381 1397399400,101.78687502282855 1397399700,106.89860138911905 1397400000,110.02841924810951 1397400300,109.45914693290001 1397400600,108.6528433676905 1397400900,113.83911032028095 1397401200,102.70924749037144 1397401500,106.95975214086191 1397401800,113.21150620085237 1397402100,100.32148994214285 1397402400,99.97684584093334 1397402700,102.8228833752238 1397403000,109.22576536621428 1397403300,103.26299766760476 1397403600,102.15621295819523 1397403900,106.46061108798573 1397404200,108.94475984207621 1397404500,103.11161060046665 1397404800,103.95376865315714 1397405100,108.96708940744763 1397405400,114.2893855539381 1397405700,109.96088724232857 1397406000,111.69892305411905 1397406300,105.04887153150952 1397406600,103.54342314649999 1397406900,106.46307217229048 1397407200,112.11634317668094 1397407500,106.51046343967144 1397407800,112.7647041939619 1397408100,115.0448854569524 1397408400,100.38454141834283 1397408700,99.9661179036333 1397409000,101.6404304890238 1397409300,105.40434908791427 1397409600,101.35855165510478 1397409900,113.19994388259524 1397410200,99.64709794048572 1397410500,104.3368800635762 1397410800,102.24675195576664 1397411100,114.20370305395714 1397411400,110.01821193594763 1397411700,113.90643894693814 1397412000,62.344325593028564 1397412300,59.310291666719046 1397412600,57.63594599780952 1397412900,57.383608464000005 1397413200,57.577865387490476 1397413500,60.693621720880955 1397413800,56.42491850927143 1397414100,56.50221717946189 1397414400,60.07306093535238 1397414700,60.29755227774285 1397415000,60.45350970193333 1397415300,58.58330305232381 1397415600,51.18134608321428 1397415900,49.96879167790476 1397416200,48.05808012869524 1397416500,51.164039308085705 1397416800,51.870218532776185 1397417100,47.87687822826666 1397417400,49.36860993815715 1397417700,49.80686827414762 1397418000,48.2864259584381 1397418300,51.52501333832857 1397418600,48.91810828101905 1397418900,51.16043648440952 1397419200,48.6803931442 1397419500,48.389035914390476 1397419800,46.73389782998097 1397420100,46.85832281667143 1397420400,46.1557007470619 1397420700,46.955160260352386 1397421000,47.39157964334285 1397421300,49.39664623583333 1397421600,47.4922679332238 1397421900,49.089894849614275 1397422200,47.806360103304755 1397422500,49.22866558429524 1397422800,49.59951647688571 1397423100,46.647097334076186 1397423400,49.15649002076666 1397423700,48.197242460157135 1397424000,48.99031666294761 1397424300,48.3317421030381 1397424600,47.42426638262857 1397424900,46.644447797719046 1397425200,46.016695056509526 1397425500,47.8950053609 1397425800,49.730409061390475 1397426100,48.723868523580954 1397426400,47.00649059157143 1397426700,49.015287561061896 1397427000,48.78962126985238 1397427300,46.84579750264285 1397427600,45.782898224433325 1397427900,46.20615809912381 1397428200,49.25308789211428 1397428500,49.097399294704765 1397428800,46.937344834695246 1397429100,46.90469256048571 1397429400,48.94476073007619 1397429700,49.53224744746666 1397430000,48.88846054535714 1397430300,48.201533409547615 1397430600,46.7570658663381 1397430900,47.89703000022857 1397431200,46.735301817219046 1397431500,49.04118175490952 1397431800,47.3640975023 1397432100,49.15882562149048 1397432400,47.35756689828096 1397432700,49.13550799397143 1397433000,47.1792451515619 1397433300,47.61402721935238 1397433600,48.31909653454286 1397433900,46.14573378943334 1397434200,49.66485205682382 1397434500,48.17388743021429 1397434800,47.91818482070475 1397435100,49.25192112259524 1397435400,49.364836633885716 1397435700,47.99826780857618 1397436000,49.625715969866654 1397436300,46.183058207157146 1397436600,46.384450788047616 1397436900,48.32614101533811 1397437200,47.36269201862856 1397437500,47.810769712419045 1397437800,47.27362639540953 1397438100,47.5876512458 1397438400,49.266775864790475 1397438700,48.35753575178096 1397439000,49.98044962567143 1397439300,49.1460286960619 1397439600,47.10061739735238 1397439900,47.07077332804285 1397440200,47.364426413833336 1397440500,49.401311732123794 1397440800,46.14486488831429 1397441100,46.96387987740476 1397441400,49.67026891949524 1397441700,48.61762145858572 1397442000,46.97286457247618 1397442300,46.94949653956667 1397442600,49.53082954985714 1397442900,49.662827652147605 1397443200,47.11976245903811 1397443500,47.78472000372857 1397443800,49.44850200211904 1397444100,49.20158927820953 1397444400,49.3806644263 1397444700,48.20603323939048 1397445000,49.78607714558096 1397445300,47.45112760437142 1397445600,46.78145044216189 1397445900,48.997131711252386 1397446200,48.327060521142855 1397446500,49.59542640853333 1397446800,46.509160806023814 1397447100,49.5667338995143 1397447400,47.37258337470476 1397447700,48.826267906795245 1397448000,46.374800870585716 1397448300,48.66005137567618 1397448600,49.09825342336665 1397448900,47.71160800085714 1397449200,47.10569044004762 1397449500,48.4020108016381 1397449800,49.59169178912857 1397450100,47.56055848081905 1397450400,47.28368671390952 1397450700,47.3969912346 1397451000,50.08521908789047 1397451300,47.73323861548096 1397451600,46.317988388171436 1397451900,49.4377367365619 1397452200,49.11555156225238 1397452500,46.84016591554286 1397452800,50.27295032983334 1397453100,48.77302295072381 1397453400,48.35133224951429 1397453700,47.884531832404754 1397454000,49.95778626039524 1397454300,47.34638963998572 1397454600,47.52105179137619 1397454900,46.87505989336667 1397455200,49.42933352515715 1397455500,48.78249474064762 1397455800,48.8440027722381 1397456100,47.28906029552857 1397456400,49.02729260411904 1397456700,49.49189331280952 1397457000,47.869054122899996 1397457300,49.65032905199048 1397457600,47.84754330648096 1397457900,49.49237527457143 1397458200,46.6021823345619 1397458500,48.67936078685238 1397458800,50.36024909974286 1397459100,50.41456173603334 1397459400,47.624034122923796 1397459700,48.27006065001429 1397460000,46.76381639380476 1397460300,50.01271046849524 1397460600,48.80107432688571 1397460900,48.07462890627619 1397461200,46.992748900666676 1397461500,50.33617628485714 1397461800,48.67742381034761 1397462100,47.6956998115381 1397462400,47.972289091928566 1397462700,47.661657771319035 1397463000,48.99354875920953 1397463300,50.31360430310001 1397463600,50.02796568949047 1397463900,48.45015445408095 1397464200,49.92206887777142 1397464500,48.315933829861905 1397464800,47.64018094395238 1397465100,50.57205331824286 1397465400,47.86138360523333 1397465700,47.948170733423815 1397466000,103.32053728761429 1397466300,91.68956866900477 1397466600,100.21885747499523 1397466900,102.61008922968573 1397467200,96.8508881125762 1397467500,89.93221262586668 1397467800,95.00615878275715 1397468100,91.43013591544762 1397468400,95.5803902839381 1397468700,100.67204252972857 1397469000,95.90159611241906 1397469300,95.81674117410951 1397469600,107.2313726818 1397469900,107.62527835149046 1397470200,111.89459966498094 1397470500,103.39799784537144 1397470800,111.3720999277619 1397471100,107.41049416065238 1397471400,103.29886146874284 1397471700,103.22243953633331 1397472000,104.25437807502381 1397472300,108.32116341121427 1397472600,102.24660283260476 1397472900,112.95542211529524 1397473200,109.55069545308572 1397473500,115.04665710777618 1397473800,101.16018158546665 1397474100,105.87849837865713 1397474400,100.79978065464762 1397474700,104.77438096253807 1397475000,114.16127950642857 1397475300,101.04160996841905 1397475600,107.40329300090951 1397475900,102.34403668879999 1397476200,107.11112432109049 1397476500,113.83022654848095 1397476800,110.79934499917142 1397477100,112.62356770826192 1397477400,106.43601542915238 1397477700,115.95672354154287 1397478000,112.20650900163332 1397478300,107.6200563807238 1397478600,107.7020629652143 1397478900,115.57556287280478 1397479200,110.11310336299525 1397479500,112.19764059188572 1397479800,107.58113270637621 1397480100,104.49880600186668 1397480400,112.57474734705713 1397480700,210.7308639300476 1397481000,109.0350190253381 1397481300,111.00483737092856 1397481600,104.36210860801907 1397481900,113.7377501037095 1397482200,116.2121839352 1397482500,115.30688894679048 1397482800,106.20183856408094 1397483100,107.56207473887144 1397483400,114.00631443666191 1397483700,110.60201122435238 1397484000,109.86989715764288 1397484300,115.93668715283331 1397484600,109.69455551802382 1397484900,109.3646316862143 1397485200,101.80571395190478 1397485500,102.25150726329522 1397485800,101.26704894158571 1397486100,115.76697643147621 1397486400,107.69708358596668 1397486700,108.66727330585714 1397487000,114.70363352334762 1397487300,110.93300516003806 1397487600,110.94766929422855 1397487900,105.94768316961904 1397488200,114.55302421830952 1397488500,103.8713129451 1397488800,102.07588458719047 1397489100,104.29856404238096 1397489400,105.52413460457144 1397489700,105.76475426746191 1397490000,111.98337576795237 1397490300,104.74786159654285 1397490600,112.09657107053332 1397490900,102.73568338332382 1397491200,103.64081090121428 1397491500,109.43414406680478 1397491800,116.05076151869524 1397492100,115.06095248938571 1397492400,116.81536326947617 1397492700,111.73042348836664 1397493000,112.14323600445715 1397493300,111.33800816124763 1397493600,111.3101834879381 1397493900,103.70646133292857 1397494200,110.05978740261904 1397494500,107.54449635900951 1397494800,108.4555650855 1397495100,109.76001878009049 1397495400,103.44419126438095 1397495700,107.14909531347143 1397496000,102.41992684096188 1397496300,117.08685880065237 1397496600,103.31606294204286 1397496900,105.5634499136333 1397497200,115.69517751272379 1397497500,109.16529441181429 1397497800,103.61957150490477 1397498100,107.60450383799524 1397498400,59.00583520508571 1397498700,59.553102796176184 1397499000,58.61215209356666 1397499300,61.09125703985714 1397499600,63.45651227724761 1397499900,62.05168458923809 1397500200,62.18953225182857 1397500500,59.600101064119045 1397500800,60.52472416840952 1397501100,63.7407928963 1397501400,58.90096441829047 1397501700,63.836880552080956 1397502000,51.88050152147143 1397502300,53.4714310854619 1397502600,51.15311995575238 1397502900,51.25390809104285 1397503200,53.11052185283333 1397503500,53.26755536752381 1397503800,50.78702128071429 1397504100,54.12411695210476 1397504400,50.15160977839524 1397504700,50.08742786618571 1397505000,52.45583382267618 1397505300,53.033294022766675 1397505600,52.01064645975714 1397505900,49.74095529614761 1397506200,48.193331484038104 1397506500,50.56664172702857 1397506800,49.291213712519045 1397507100,49.885410689809525 1397507400,50.120270754100005 1397507700,48.39118390539047 1397508000,50.12496209688095 1397508300,49.88802654167142 1397508600,51.0678429591619 1397508900,50.80134970035238 1397509200,48.562961825442855 1397509500,48.65449682713333 1397509800,48.84226779652381 1397510100,48.56010184931428 1397510400,50.489776003304755 1397510700,51.85255896029523 1397511000,50.484139505885715 1397511300,50.30900061077619 1397511600,49.52564896816666 1397511900,49.14182967195714 1397512200,51.55473520964762 1397512500,51.7950003740381 1397512800,49.827720884428565 1397513100,49.008065390119036 1397513400,50.93703561340952 1397513700,48.3913657884 1397514000,50.93376327529048 1397514300,51.15484920088095 1397514600,48.383446829171426 1397514900,51.801988917261895 1397515200,51.84406589895238 1397515500,51.656147766542865 1397515800,49.899157334833326 1397516100,48.90579529402381 1397516400,50.24265439041429 1397516700,49.60166862300476 1397517000,48.75300398369524 1397517300,49.63152273428571 1397517600,50.60000139857618 1397517900,48.23508036946666 1397518200,49.292741211757146 1397518500,48.03744684384762 1397518800,50.9722517275381 1397519100,50.54439169072858 1397519400,48.239311716819046 1397519700,51.85570667850952 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/art_daily_nojump.csv ================================================ timestamp,value 2014-04-07 01:50:00,19.6866160273 2014-04-07 01:55:00,19.3563053672 2014-04-07 02:00:00,20.4140421657 2014-04-07 02:05:00,18.8776063185 2014-04-07 02:10:00,18.9195739623 2014-04-07 02:15:00,20.081154923499998 2014-04-07 02:20:00,19.6370909146 2014-04-07 02:25:00,19.179929535699998 2014-04-07 02:30:00,18.2158045291 2014-04-07 02:35:00,20.083096954600002 2014-04-07 02:40:00,21.2664368224 2014-04-07 02:45:00,21.4055088211 2014-04-07 02:50:00,18.9417599189 2014-04-07 02:55:00,20.3985648158 2014-04-07 03:00:00,21.423525237899998 2014-04-07 03:05:00,19.634903713099998 2014-04-07 03:10:00,21.7285472692 2014-04-07 03:15:00,21.6119141165 2014-04-07 03:20:00,18.8325355897 2014-04-07 03:25:00,19.0358593316 2014-04-07 03:30:00,18.7217679946 2014-04-07 03:35:00,18.7842174058 2014-04-07 03:40:00,21.631448348699998 2014-04-07 03:45:00,21.724551636799998 2014-04-07 03:50:00,18.2075889647 2014-04-07 03:55:00,20.374413422699998 2014-04-07 04:00:00,20.2569262514 2014-04-07 04:05:00,19.5621905869 2014-04-07 04:10:00,20.526790371300002 2014-04-07 04:15:00,21.789471302 2014-04-07 04:20:00,18.6810195309 2014-04-07 04:25:00,18.4816436389 2014-04-07 04:30:00,18.133562283299998 2014-04-07 04:35:00,19.4553332314 2014-04-07 04:40:00,19.350513908299998 2014-04-07 04:45:00,19.7232787526 2014-04-07 04:50:00,20.013240123499997 2014-04-07 04:55:00,21.031295976099997 2014-04-07 05:00:00,19.568453561800002 2014-04-07 05:05:00,19.3224524374 2014-04-07 05:10:00,21.307515281 2014-04-07 05:15:00,21.3991866826 2014-04-07 05:20:00,18.9310638572 2014-04-07 05:25:00,19.258687290799998 2014-04-07 05:30:00,21.3004654836 2014-04-07 05:35:00,18.3176329772 2014-04-07 05:40:00,19.3033871216 2014-04-07 05:45:00,19.7934004282 2014-04-07 05:50:00,18.7482864608 2014-04-07 05:55:00,18.7196567864 2014-04-07 06:00:00,19.6994482321 2014-04-07 06:05:00,21.018086898900002 2014-04-07 06:10:00,21.3609319182 2014-04-07 06:15:00,21.9169403701 2014-04-07 06:20:00,18.2959362004 2014-04-07 06:25:00,18.8667288046 2014-04-07 06:30:00,21.0265193695 2014-04-07 06:35:00,20.1623948242 2014-04-07 06:40:00,19.3107190958 2014-04-07 06:45:00,18.822358645 2014-04-07 06:50:00,19.121910206600003 2014-04-07 06:55:00,19.7171558012 2014-04-07 07:00:00,18.708604878 2014-04-07 07:05:00,21.856903823499998 2014-04-07 07:10:00,18.4303537784 2014-04-07 07:15:00,21.942309738000002 2014-04-07 07:20:00,21.367573144 2014-04-07 07:25:00,19.6926064701 2014-04-07 07:30:00,20.9592653376 2014-04-07 07:35:00,20.6860609748 2014-04-07 07:40:00,18.853147671800002 2014-04-07 07:45:00,19.3562803445 2014-04-07 07:50:00,20.0524902512 2014-04-07 07:55:00,20.5513767196 2014-04-07 08:00:00,20.1715799254 2014-04-07 08:05:00,19.891949844000003 2014-04-07 08:10:00,19.7726090938 2014-04-07 08:15:00,19.9930579972 2014-04-07 08:20:00,19.7374060794 2014-04-07 08:25:00,20.1653203102 2014-04-07 08:30:00,21.551941196199998 2014-04-07 08:35:00,20.5313172522 2014-04-07 08:40:00,20.8904835 2014-04-07 08:45:00,20.3899325349 2014-04-07 08:50:00,20.572070729700002 2014-04-07 08:55:00,20.3133993138 2014-04-07 09:00:00,61.565384701899994 2014-04-07 09:05:00,74.7945379979 2014-04-07 09:10:00,61.657085666899995 2014-04-07 09:15:00,66.574012912 2014-04-07 09:20:00,62.6295732249 2014-04-07 09:25:00,62.518226926000004 2014-04-07 09:30:00,71.9919665428 2014-04-07 09:35:00,66.9925905993 2014-04-07 09:40:00,72.0954864329 2014-04-07 09:45:00,64.9098960013 2014-04-07 09:50:00,64.6878939686 2014-04-07 09:55:00,64.6167467927 2014-04-07 10:00:00,79.4025801219 2014-04-07 10:05:00,82.4887905304 2014-04-07 10:10:00,76.8590908764 2014-04-07 10:15:00,75.7259427827 2014-04-07 10:20:00,84.9499546812 2014-04-07 10:25:00,71.65202263890001 2014-04-07 10:30:00,77.3925392253 2014-04-07 10:35:00,76.1797299294 2014-04-07 10:40:00,71.362924779 2014-04-07 10:45:00,74.0024696196 2014-04-07 10:50:00,70.2814076192 2014-04-07 10:55:00,83.450330565 2014-04-07 11:00:00,81.2352389091 2014-04-07 11:05:00,84.5300541901 2014-04-07 11:10:00,79.862802011 2014-04-07 11:15:00,81.1026043271 2014-04-07 11:20:00,82.7143896151 2014-04-07 11:25:00,86.0090169232 2014-04-07 11:30:00,73.027222024 2014-04-07 11:35:00,76.8314032699 2014-04-07 11:40:00,82.84435253689999 2014-04-07 11:45:00,86.809607354 2014-04-07 11:50:00,87.1667613427 2014-04-07 11:55:00,81.71639025729999 2014-04-07 12:00:00,75.0074585533 2014-04-07 12:05:00,73.8186537715 2014-04-07 12:10:00,87.0321342705 2014-04-07 12:15:00,78.8481116198 2014-04-07 12:20:00,75.0269160644 2014-04-07 12:25:00,86.83794951610001 2014-04-07 12:30:00,73.583981479 2014-04-07 12:35:00,83.5727297847 2014-04-07 12:40:00,81.9058033906 2014-04-07 12:45:00,73.3156701245 2014-04-07 12:50:00,77.32707675340001 2014-04-07 12:55:00,74.3096123634 2014-04-07 13:00:00,81.6523762059 2014-04-07 13:05:00,79.6146963928 2014-04-07 13:10:00,72.0511055781 2014-04-07 13:15:00,87.590342332 2014-04-07 13:20:00,77.5747319932 2014-04-07 13:25:00,76.1129987805 2014-04-07 13:30:00,75.54095311180001 2014-04-07 13:35:00,74.5231644857 2014-04-07 13:40:00,87.96507653309997 2014-04-07 13:45:00,76.7033382657 2014-04-07 13:50:00,78.4693787838 2014-04-07 13:55:00,85.92106865209999 2014-04-07 14:00:00,82.2662510871 2014-04-07 14:05:00,77.89537143060001 2014-04-07 14:10:00,86.3691090585 2014-04-07 14:15:00,83.9915554472 2014-04-07 14:20:00,75.64277709310001 2014-04-07 14:25:00,82.2958735221 2014-04-07 14:30:00,86.75421157059998 2014-04-07 14:35:00,79.9395367733 2014-04-07 14:40:00,83.733779031 2014-04-07 14:45:00,87.53345809620001 2014-04-07 14:50:00,83.0426400163 2014-04-07 14:55:00,73.6354843633 2014-04-07 15:00:00,75.9122240506 2014-04-07 15:05:00,81.52076039069999 2014-04-07 15:10:00,76.40815952060001 2014-04-07 15:15:00,87.31982900780001 2014-04-07 15:20:00,78.4848790823 2014-04-07 15:25:00,79.3149250611 2014-04-07 15:30:00,83.2248345294 2014-04-07 15:35:00,80.3872239767 2014-04-07 15:40:00,78.1135855726 2014-04-07 15:45:00,73.2255030309 2014-04-07 15:50:00,81.5423466181 2014-04-07 15:55:00,85.88045603239999 2014-04-07 16:00:00,82.9720397615 2014-04-07 16:05:00,78.10377020119998 2014-04-07 16:10:00,74.0434748702 2014-04-07 16:15:00,85.0612476726 2014-04-07 16:20:00,87.0678066252 2014-04-07 16:25:00,78.212217685 2014-04-07 16:30:00,83.6581144031 2014-04-07 16:35:00,78.5720641796 2014-04-07 16:40:00,80.036117352 2014-04-07 16:45:00,85.3834581533 2014-04-07 16:50:00,73.3346486726 2014-04-07 16:55:00,80.4852110487 2014-04-07 17:00:00,75.4338954281 2014-04-07 17:05:00,77.4368653922 2014-04-07 17:10:00,82.3108295869 2014-04-07 17:15:00,72.4356267821 2014-04-07 17:20:00,81.5011702871 2014-04-07 17:25:00,76.5350464418 2014-04-07 17:30:00,82.7117180116 2014-04-07 17:35:00,74.2652731127 2014-04-07 17:40:00,83.7729534922 2014-04-07 17:45:00,82.3302039014 2014-04-07 17:50:00,87.5398357108 2014-04-07 17:55:00,86.5797325655 2014-04-07 18:00:00,30.613132446799998 2014-04-07 18:05:00,28.974820502300002 2014-04-07 18:10:00,32.9943524562 2014-04-07 18:15:00,32.6584730192 2014-04-07 18:20:00,28.975538556799997 2014-04-07 18:25:00,29.5851305066 2014-04-07 18:30:00,32.5420846609 2014-04-07 18:35:00,34.6356878398 2014-04-07 18:40:00,34.601595126199996 2014-04-07 18:45:00,29.7694986338 2014-04-07 18:50:00,31.2612672548 2014-04-07 18:55:00,29.0764927492 2014-04-07 19:00:00,22.262336650500004 2014-04-07 19:05:00,23.5338126083 2014-04-07 19:10:00,23.6990764469 2014-04-07 19:15:00,22.3954715818 2014-04-07 19:20:00,20.5894950132 2014-04-07 19:25:00,21.8685094092 2014-04-07 19:30:00,24.335815445700003 2014-04-07 19:35:00,21.1886630909 2014-04-07 19:40:00,21.592498751100006 2014-04-07 19:45:00,23.505784456599997 2014-04-07 19:50:00,23.446440648000003 2014-04-07 19:55:00,24.2466649202 2014-04-07 20:00:00,20.0217339169 2014-04-07 20:05:00,20.5397961265 2014-04-07 20:10:00,20.346439277 2014-04-07 20:15:00,22.232072625700003 2014-04-07 20:20:00,21.5831778328 2014-04-07 20:25:00,21.8375852681 2014-04-07 20:30:00,18.9771702814 2014-04-07 20:35:00,21.6754037939 2014-04-07 20:40:00,20.2054807833 2014-04-07 20:45:00,18.5275950225 2014-04-07 20:50:00,18.678121668699998 2014-04-07 20:55:00,21.208710666600002 2014-04-07 21:00:00,19.581592355599998 2014-04-07 21:05:00,21.5755300591 2014-04-07 21:10:00,21.0375905282 2014-04-07 21:15:00,18.1735362584 2014-04-07 21:20:00,20.8471414519 2014-04-07 21:25:00,18.8595030123 2014-04-07 21:30:00,19.7848438117 2014-04-07 21:35:00,20.597335674 2014-04-07 21:40:00,21.594027494899997 2014-04-07 21:45:00,19.9195485843 2014-04-07 21:50:00,21.335884781300003 2014-04-07 21:55:00,21.23329554 2014-04-07 22:00:00,19.6770258696 2014-04-07 22:05:00,20.0231244077 2014-04-07 22:10:00,20.8219098924 2014-04-07 22:15:00,18.1419933397 2014-04-07 22:20:00,21.5839463604 2014-04-07 22:25:00,21.099500721400002 2014-04-07 22:30:00,19.0159012733 2014-04-07 22:35:00,21.945767533 2014-04-07 22:40:00,18.7355302601 2014-04-07 22:45:00,21.677136776999998 2014-04-07 22:50:00,19.3164198019 2014-04-07 22:55:00,21.072797313699997 2014-04-07 23:00:00,19.8293128683 2014-04-07 23:05:00,20.9498911547 2014-04-07 23:10:00,18.626707831300003 2014-04-07 23:15:00,19.0816888126 2014-04-07 23:20:00,18.4029639869 2014-04-07 23:25:00,21.4646963542 2014-04-07 23:30:00,19.1888555022 2014-04-07 23:35:00,20.7818942734 2014-04-07 23:40:00,21.2849707188 2014-04-07 23:45:00,21.6098212326 2014-04-07 23:50:00,18.4287260956 2014-04-07 23:55:00,21.5762015674 2014-04-08 00:00:00,18.7890111109 2014-04-08 00:05:00,20.947608046400003 2014-04-08 00:10:00,20.9153960775 2014-04-08 00:15:00,18.034012567 2014-04-08 00:20:00,18.882495633199998 2014-04-08 00:25:00,19.9676340587 2014-04-08 00:30:00,19.680138826700002 2014-04-08 00:35:00,21.6742939195 2014-04-08 00:40:00,19.438963477999998 2014-04-08 00:45:00,21.7479348593 2014-04-08 00:50:00,19.8377172736 2014-04-08 00:55:00,21.857411586599998 2014-04-08 01:00:00,20.9494192401 2014-04-08 01:05:00,21.3173383665 2014-04-08 01:10:00,18.4195075534 2014-04-08 01:15:00,20.344565733 2014-04-08 01:20:00,18.570801439300002 2014-04-08 01:25:00,19.1904840082 2014-04-08 01:30:00,20.494261624700002 2014-04-08 01:35:00,20.9049028188 2014-04-08 01:40:00,18.156735128 2014-04-08 01:45:00,20.1237749243 2014-04-08 01:50:00,20.2612559452 2014-04-08 01:55:00,18.315311988399998 2014-04-08 02:00:00,20.0027521368 2014-04-08 02:05:00,20.8553691202 2014-04-08 02:10:00,18.2129091395 2014-04-08 02:15:00,21.0410711053 2014-04-08 02:20:00,20.3057060196 2014-04-08 02:25:00,21.3329088331 2014-04-08 02:30:00,18.8722502914 2014-04-08 02:35:00,21.3330947369 2014-04-08 02:40:00,18.3782439011 2014-04-08 02:45:00,19.6153187858 2014-04-08 02:50:00,18.797939166099997 2014-04-08 02:55:00,21.5040833292 2014-04-08 03:00:00,20.8196792652 2014-04-08 03:05:00,18.1014471086 2014-04-08 03:10:00,18.0380934225 2014-04-08 03:15:00,19.1649970179 2014-04-08 03:20:00,18.5731324571 2014-04-08 03:25:00,20.5212179102 2014-04-08 03:30:00,20.6551877355 2014-04-08 03:35:00,21.767803614600002 2014-04-08 03:40:00,21.8081596982 2014-04-08 03:45:00,20.6355868216 2014-04-08 03:50:00,18.022700451400002 2014-04-08 03:55:00,19.4359916663 2014-04-08 04:00:00,20.052566053 2014-04-08 04:05:00,19.996719025999997 2014-04-08 04:10:00,20.413362518 2014-04-08 04:15:00,21.8422059312 2014-04-08 04:20:00,21.5407707678 2014-04-08 04:25:00,18.435632133800002 2014-04-08 04:30:00,19.0639215656 2014-04-08 04:35:00,21.3324376697 2014-04-08 04:40:00,21.2972276353 2014-04-08 04:45:00,19.101482896500002 2014-04-08 04:50:00,20.9223521227 2014-04-08 04:55:00,20.6881495149 2014-04-08 05:00:00,19.8940958599 2014-04-08 05:05:00,18.8058198107 2014-04-08 05:10:00,21.5545727236 2014-04-08 05:15:00,20.7114047372 2014-04-08 05:20:00,18.6759716995 2014-04-08 05:25:00,20.8192093794 2014-04-08 05:30:00,20.965734878299997 2014-04-08 05:35:00,21.547521140500002 2014-04-08 05:40:00,18.891357020999997 2014-04-08 05:45:00,21.9550164217 2014-04-08 05:50:00,18.6135736901 2014-04-08 05:55:00,20.4027555674 2014-04-08 06:00:00,20.628706021099998 2014-04-08 06:05:00,19.6758115811 2014-04-08 06:10:00,19.9001508351 2014-04-08 06:15:00,21.5636403869 2014-04-08 06:20:00,20.5810969187 2014-04-08 06:25:00,19.9880038329 2014-04-08 06:30:00,18.5133982497 2014-04-08 06:35:00,18.029350500899998 2014-04-08 06:40:00,18.4998744726 2014-04-08 06:45:00,21.8247382699 2014-04-08 06:50:00,21.056347132 2014-04-08 06:55:00,21.86846531 2014-04-08 07:00:00,18.142834838800002 2014-04-08 07:05:00,20.7208816154 2014-04-08 07:10:00,18.1771741056 2014-04-08 07:15:00,21.1282258755 2014-04-08 07:20:00,19.5238006909 2014-04-08 07:25:00,18.3830614404 2014-04-08 07:30:00,20.2721865672 2014-04-08 07:35:00,19.1204807864 2014-04-08 07:40:00,20.6382957675 2014-04-08 07:45:00,20.6326990381 2014-04-08 07:50:00,20.8200298965 2014-04-08 07:55:00,21.969860315100004 2014-04-08 08:00:00,19.5467908398 2014-04-08 08:05:00,19.8612618979 2014-04-08 08:10:00,21.2184468041 2014-04-08 08:15:00,20.3134800921 2014-04-08 08:20:00,18.1490288428 2014-04-08 08:25:00,21.372314081 2014-04-08 08:30:00,18.2059947278 2014-04-08 08:35:00,18.683280546 2014-04-08 08:40:00,18.4083198679 2014-04-08 08:45:00,18.311708531500003 2014-04-08 08:50:00,18.1027395012 2014-04-08 08:55:00,18.2201108559 2014-04-08 09:00:00,67.2171729728 2014-04-08 09:05:00,64.6387908718 2014-04-08 09:10:00,62.920901614499996 2014-04-08 09:15:00,70.1583953811 2014-04-08 09:20:00,64.2751219846 2014-04-08 09:25:00,61.4577085127 2014-04-08 09:30:00,66.8905090592 2014-04-08 09:35:00,65.4218886909 2014-04-08 09:40:00,65.5330202663 2014-04-08 09:45:00,67.2556723833 2014-04-08 09:50:00,70.29722941039999 2014-04-08 09:55:00,69.5841160325 2014-04-08 10:00:00,84.3863001839 2014-04-08 10:05:00,77.874962661 2014-04-08 10:10:00,77.1742849989 2014-04-08 10:15:00,73.1521920346 2014-04-08 10:20:00,81.5635176029 2014-04-08 10:25:00,72.02484004680001 2014-04-08 10:30:00,77.46238245 2014-04-08 10:35:00,76.37892051899999 2014-04-08 10:40:00,80.0568296328 2014-04-08 10:45:00,84.0814852137 2014-04-08 10:50:00,84.5311635801 2014-04-08 10:55:00,72.4442446264 2014-04-08 11:00:00,75.7319410393 2014-04-08 11:05:00,84.47624812869998 2014-04-08 11:10:00,79.810721342 2014-04-08 11:15:00,78.7730617751 2014-04-08 11:20:00,82.86978719470001 2014-04-08 11:25:00,81.1410144463 2014-04-08 11:30:00,87.0062363215 2014-04-08 11:35:00,80.85553287 2014-04-08 11:40:00,78.9788477342 2014-04-08 11:45:00,80.20096732649999 2014-04-08 11:50:00,84.4270172447 2014-04-08 11:55:00,81.3119841031 2014-04-08 12:00:00,82.2539461388 2014-04-08 12:05:00,87.4379704541 2014-04-08 12:10:00,81.7960545575 2014-04-08 12:15:00,77.9908624966 2014-04-08 12:20:00,82.9615429725 2014-04-08 12:25:00,82.4522887312 2014-04-08 12:30:00,72.1348962935 2014-04-08 12:35:00,79.3818960261 2014-04-08 12:40:00,83.78579389689999 2014-04-08 12:45:00,79.8886817275 2014-04-08 12:50:00,84.3725694492 2014-04-08 12:55:00,79.1190821759 2014-04-08 13:00:00,87.7120896073 2014-04-08 13:05:00,76.6678607236 2014-04-08 13:10:00,73.4563279795 2014-04-08 13:15:00,78.8612575731 2014-04-08 13:20:00,80.6479842353 2014-04-08 13:25:00,77.566879187 2014-04-08 13:30:00,75.8582882022 2014-04-08 13:35:00,82.73307835680001 2014-04-08 13:40:00,78.0152734373 2014-04-08 13:45:00,82.08219201050001 2014-04-08 13:50:00,84.4448715432 2014-04-08 13:55:00,84.1558397941 2014-04-08 14:00:00,78.0012047326 2014-04-08 14:05:00,81.0824795174 2014-04-08 14:10:00,79.1907302536 2014-04-08 14:15:00,85.9287592649 2014-04-08 14:20:00,86.05600479030001 2014-04-08 14:25:00,77.49614533270001 2014-04-08 14:30:00,73.4642727117 2014-04-08 14:35:00,74.67773502979999 2014-04-08 14:40:00,77.8682900168 2014-04-08 14:45:00,81.0241099322 2014-04-08 14:50:00,82.504631763 2014-04-08 14:55:00,77.2982262476 2014-04-08 15:00:00,82.6791921861 2014-04-08 15:05:00,87.00300450190002 2014-04-08 15:10:00,82.43143468529999 2014-04-08 15:15:00,74.5363281155 2014-04-08 15:20:00,81.2739223705 2014-04-08 15:25:00,80.66955383310001 2014-04-08 15:30:00,85.9303768348 2014-04-08 15:35:00,77.6041038769 2014-04-08 15:40:00,78.7663735965 2014-04-08 15:45:00,81.5777617338 2014-04-08 15:50:00,80.3900332361 2014-04-08 15:55:00,83.5034638375 2014-04-08 16:00:00,72.64608437390001 2014-04-08 16:05:00,81.0161007561 2014-04-08 16:10:00,73.9466083103 2014-04-08 16:15:00,77.0431959571 2014-04-08 16:20:00,82.5858712193 2014-04-08 16:25:00,74.5184841337 2014-04-08 16:30:00,76.94132164050001 2014-04-08 16:35:00,83.247943889 2014-04-08 16:40:00,82.4127256477 2014-04-08 16:45:00,73.45649367060001 2014-04-08 16:50:00,81.2361399222 2014-04-08 16:55:00,74.355928627 2014-04-08 17:00:00,76.0363128615 2014-04-08 17:05:00,79.3473499888 2014-04-08 17:10:00,73.7495208529 2014-04-08 17:15:00,87.89831773370001 2014-04-08 17:20:00,74.64588431279999 2014-04-08 17:25:00,84.50096960649999 2014-04-08 17:30:00,85.2773887738 2014-04-08 17:35:00,87.91138976030001 2014-04-08 17:40:00,78.858421204 2014-04-08 17:45:00,85.98547930379999 2014-04-08 17:50:00,87.3205974931 2014-04-08 17:55:00,74.7662776081 2014-04-08 18:00:00,31.8683848513 2014-04-08 18:05:00,29.1840636373 2014-04-08 18:10:00,32.7726273846 2014-04-08 18:15:00,32.520993159899994 2014-04-08 18:20:00,30.1064024414 2014-04-08 18:25:00,33.9065711469 2014-04-08 18:30:00,29.0385142503 2014-04-08 18:35:00,33.9598483541 2014-04-08 18:40:00,28.97052430110001 2014-04-08 18:45:00,33.003698061 2014-04-08 18:50:00,29.3041192627 2014-04-08 18:55:00,30.407837485300004 2014-04-08 19:00:00,23.3941705216 2014-04-08 19:05:00,21.4162123275 2014-04-08 19:10:00,22.4500576107 2014-04-08 19:15:00,24.260310916599998 2014-04-08 19:20:00,20.382360788 2014-04-08 19:25:00,23.7936361707 2014-04-08 19:30:00,20.4524174316 2014-04-08 19:35:00,20.7280397655 2014-04-08 19:40:00,20.6945484502 2014-04-08 19:45:00,24.6135768786 2014-04-08 19:50:00,20.9672335604 2014-04-08 19:55:00,24.1774917449 2014-04-08 20:00:00,22.490857869499997 2014-04-08 20:05:00,20.0039821796 2014-04-08 20:10:00,21.016774582100002 2014-04-08 20:15:00,21.6231575159 2014-04-08 20:20:00,20.0402740147 2014-04-08 20:25:00,19.0947904903 2014-04-08 20:30:00,20.208691956099997 2014-04-08 20:35:00,21.5936515348 2014-04-08 20:40:00,21.6300040167 2014-04-08 20:45:00,19.376286660199998 2014-04-08 20:50:00,19.148659031199998 2014-04-08 20:55:00,22.2026163694 2014-04-08 21:00:00,18.263240859 2014-04-08 21:05:00,21.0394608303 2014-04-08 21:10:00,18.2729767877 2014-04-08 21:15:00,21.4540878319 2014-04-08 21:20:00,21.7254431646 2014-04-08 21:25:00,19.2817868969 2014-04-08 21:30:00,18.3835620935 2014-04-08 21:35:00,20.0183672395 2014-04-08 21:40:00,19.2859825901 2014-04-08 21:45:00,19.7629535368 2014-04-08 21:50:00,20.7591094839 2014-04-08 21:55:00,18.9297327574 2014-04-08 22:00:00,19.4464569625 2014-04-08 22:05:00,21.1505349907 2014-04-08 22:10:00,20.5947998356 2014-04-08 22:15:00,19.323634852999998 2014-04-08 22:20:00,20.677037309 2014-04-08 22:25:00,21.0814704828 2014-04-08 22:30:00,20.389497458399997 2014-04-08 22:35:00,18.9761869885 2014-04-08 22:40:00,18.0182620951 2014-04-08 22:45:00,21.2317593581 2014-04-08 22:50:00,21.3109731237 2014-04-08 22:55:00,20.8103767966 2014-04-08 23:00:00,18.3098385378 2014-04-08 23:05:00,20.3447945987 2014-04-08 23:10:00,21.2881692269 2014-04-08 23:15:00,19.5624285438 2014-04-08 23:20:00,18.7956109996 2014-04-08 23:25:00,20.3544164847 2014-04-08 23:30:00,21.3093171106 2014-04-08 23:35:00,18.1989733652 2014-04-08 23:40:00,20.3917193252 2014-04-08 23:45:00,20.5766451368 2014-04-08 23:50:00,20.4133867733 2014-04-08 23:55:00,20.6040899608 2014-04-09 00:00:00,20.5255012304 2014-04-09 00:05:00,18.5216155399 2014-04-09 00:10:00,18.9397471078 2014-04-09 00:15:00,20.475976021199997 2014-04-09 00:20:00,18.0707726445 2014-04-09 00:25:00,20.5389780749 2014-04-09 00:30:00,20.6615464951 2014-04-09 00:35:00,18.9566990394 2014-04-09 00:40:00,20.392531319 2014-04-09 00:45:00,20.1363602429 2014-04-09 00:50:00,19.0427661926 2014-04-09 00:55:00,19.8518960475 2014-04-09 01:00:00,21.6384981176 2014-04-09 01:05:00,19.706411121800002 2014-04-09 01:10:00,20.5193767075 2014-04-09 01:15:00,18.1414032842 2014-04-09 01:20:00,18.3112004533 2014-04-09 01:25:00,18.3252322932 2014-04-09 01:30:00,21.1129630545 2014-04-09 01:35:00,19.4010275792 2014-04-09 01:40:00,18.9104467535 2014-04-09 01:45:00,20.989298273800003 2014-04-09 01:50:00,18.679840250199998 2014-04-09 01:55:00,18.9859701003 2014-04-09 02:00:00,19.7237257731 2014-04-09 02:05:00,19.325752276099998 2014-04-09 02:10:00,20.3415688441 2014-04-09 02:15:00,19.3513624763 2014-04-09 02:20:00,19.571806543399997 2014-04-09 02:25:00,21.451546433 2014-04-09 02:30:00,21.538125758499998 2014-04-09 02:35:00,21.3108447633 2014-04-09 02:40:00,21.459323730799998 2014-04-09 02:45:00,20.2789146774 2014-04-09 02:50:00,20.584932859000002 2014-04-09 02:55:00,20.2286926662 2014-04-09 03:00:00,21.1423523362 2014-04-09 03:05:00,20.204001942999998 2014-04-09 03:10:00,18.4443078582 2014-04-09 03:15:00,21.238320481800002 2014-04-09 03:20:00,21.0423406827 2014-04-09 03:25:00,21.281202381099998 2014-04-09 03:30:00,18.7617178536 2014-04-09 03:35:00,19.086468210899998 2014-04-09 03:40:00,19.183006789100002 2014-04-09 03:45:00,20.0323221447 2014-04-09 03:50:00,18.5355083367 2014-04-09 03:55:00,19.541527013099998 2014-04-09 04:00:00,18.7286326443 2014-04-09 04:05:00,19.0590508521 2014-04-09 04:10:00,20.825550538199998 2014-04-09 04:15:00,21.4192446253 2014-04-09 04:20:00,18.0916234664 2014-04-09 04:25:00,20.2635878534 2014-04-09 04:30:00,18.1442390482 2014-04-09 04:35:00,18.34099698 2014-04-09 04:40:00,20.8203361385 2014-04-09 04:45:00,20.942432426 2014-04-09 04:50:00,21.2559226927 2014-04-09 04:55:00,19.8969660471 2014-04-09 05:00:00,21.439229928099998 2014-04-09 05:05:00,18.6673531666 2014-04-09 05:10:00,18.9988656545 2014-04-09 05:15:00,18.5380085904 2014-04-09 05:20:00,21.1901490423 2014-04-09 05:25:00,18.914700473499998 2014-04-09 05:30:00,18.622044970999998 2014-04-09 05:35:00,20.4924427504 2014-04-09 05:40:00,18.3083281054 2014-04-09 05:45:00,18.179601108900002 2014-04-09 05:50:00,18.4268705942 2014-04-09 05:55:00,18.0009635359 2014-04-09 06:00:00,20.7879606169 2014-04-09 06:05:00,20.2489412869 2014-04-09 06:10:00,18.839500436199998 2014-04-09 06:15:00,18.9320197919 2014-04-09 06:20:00,21.2438743939 2014-04-09 06:25:00,20.0072804634 2014-04-09 06:30:00,20.794113428299998 2014-04-09 06:35:00,19.8110218051 2014-04-09 06:40:00,18.9508721041 2014-04-09 06:45:00,21.8816112027 2014-04-09 06:50:00,20.262590253499997 2014-04-09 06:55:00,18.5239276151 2014-04-09 07:00:00,19.624360168699997 2014-04-09 07:05:00,19.3173496478 2014-04-09 07:10:00,18.8563498744 2014-04-09 07:15:00,21.733759956999997 2014-04-09 07:20:00,21.523679981799997 2014-04-09 07:25:00,18.796588466099998 2014-04-09 07:30:00,19.408591556199998 2014-04-09 07:35:00,21.0492615667 2014-04-09 07:40:00,18.8340241926 2014-04-09 07:45:00,20.3662594504 2014-04-09 07:50:00,20.7991757685 2014-04-09 07:55:00,20.6158893028 2014-04-09 08:00:00,20.8256345611 2014-04-09 08:05:00,20.8267983561 2014-04-09 08:10:00,21.8592236794 2014-04-09 08:15:00,19.3859955581 2014-04-09 08:20:00,21.5143616975 2014-04-09 08:25:00,18.0872282501 2014-04-09 08:30:00,19.152811853299998 2014-04-09 08:35:00,18.194623128 2014-04-09 08:40:00,20.6048158398 2014-04-09 08:45:00,18.4031614829 2014-04-09 08:50:00,21.3828274546 2014-04-09 08:55:00,20.5863667352 2014-04-09 09:00:00,61.5918894543 2014-04-09 09:05:00,70.9209721699 2014-04-09 09:10:00,72.9236752827 2014-04-09 09:15:00,70.1912457042 2014-04-09 09:20:00,61.6151293367 2014-04-09 09:25:00,72.8677058591 2014-04-09 09:30:00,71.1615092159 2014-04-09 09:35:00,66.3469378498 2014-04-09 09:40:00,65.6693715131 2014-04-09 09:45:00,67.7255544671 2014-04-09 09:50:00,72.99258381279999 2014-04-09 09:55:00,64.6280071854 2014-04-09 10:00:00,71.4069583505 2014-04-09 10:05:00,83.2591565084 2014-04-09 10:10:00,70.2480184546 2014-04-09 10:15:00,83.9786737852 2014-04-09 10:20:00,74.5851654156 2014-04-09 10:25:00,77.72761633020001 2014-04-09 10:30:00,71.8932265442 2014-04-09 10:35:00,83.8429971247 2014-04-09 10:40:00,81.4774581869 2014-04-09 10:45:00,84.1828947042 2014-04-09 10:50:00,80.4437148734 2014-04-09 10:55:00,72.706447415 2014-04-09 11:00:00,76.4706784155 2014-04-09 11:05:00,79.3108397384 2014-04-09 11:10:00,81.225834498 2014-04-09 11:15:00,86.3024108914 2014-04-09 11:20:00,77.67436411189999 2014-04-09 11:25:00,82.7496574364 2014-04-09 11:30:00,86.8518847331 2014-04-09 11:35:00,73.9913571046 2014-04-09 11:40:00,85.2885333 2014-04-09 11:45:00,78.25890934350001 2014-04-09 11:50:00,83.2164359244 2014-04-09 11:55:00,76.2364337393 2014-04-09 12:00:00,77.2509349953 2014-04-09 12:05:00,72.34721064 2014-04-09 12:10:00,87.43741549090002 2014-04-09 12:15:00,84.9132229142 2014-04-09 12:20:00,73.414484102 2014-04-09 12:25:00,87.8865501617 2014-04-09 12:30:00,81.582377083 2014-04-09 12:35:00,85.55686661760001 2014-04-09 12:40:00,72.9788923258 2014-04-09 12:45:00,78.1373413932 2014-04-09 12:50:00,82.6151606553 2014-04-09 12:55:00,73.6144959718 2014-04-09 13:00:00,79.8032880316 2014-04-09 13:05:00,79.0638661097 2014-04-09 13:10:00,75.4385339971 2014-04-09 13:15:00,76.7858843375 2014-04-09 13:20:00,87.45289993739998 2014-04-09 13:25:00,76.59998736600001 2014-04-09 13:30:00,75.3967185871 2014-04-09 13:35:00,80.5600076939 2014-04-09 13:40:00,82.7154720663 2014-04-09 13:45:00,83.5814254196 2014-04-09 13:50:00,84.0477786428 2014-04-09 13:55:00,72.5718984275 2014-04-09 14:00:00,78.29640799810001 2014-04-09 14:05:00,84.3792788767 2014-04-09 14:10:00,86.47348270239998 2014-04-09 14:15:00,81.6312834836 2014-04-09 14:20:00,72.8334134845 2014-04-09 14:25:00,78.3425722697 2014-04-09 14:30:00,73.1841208475 2014-04-09 14:35:00,83.9725749259 2014-04-09 14:40:00,73.0125827363 2014-04-09 14:45:00,74.9680984263 2014-04-09 14:50:00,78.66755855939999 2014-04-09 14:55:00,79.3985625599 2014-04-09 15:00:00,78.5029535695 2014-04-09 15:05:00,79.413583968 2014-04-09 15:10:00,83.4110256788 2014-04-09 15:15:00,77.9075532476 2014-04-09 15:20:00,80.7632320119 2014-04-09 15:25:00,76.8531703229 2014-04-09 15:30:00,77.6572944043 2014-04-09 15:35:00,81.81999786520001 2014-04-09 15:40:00,79.8471478862 2014-04-09 15:45:00,83.56777845939999 2014-04-09 15:50:00,80.9678401101 2014-04-09 15:55:00,84.85637073720001 2014-04-09 16:00:00,79.0943795464 2014-04-09 16:05:00,79.85638459329998 2014-04-09 16:10:00,82.7193827609 2014-04-09 16:15:00,75.53975807399999 2014-04-09 16:20:00,78.1747224951 2014-04-09 16:25:00,81.99730246909999 2014-04-09 16:30:00,72.4618811812 2014-04-09 16:35:00,78.9913912744 2014-04-09 16:40:00,81.5814423442 2014-04-09 16:45:00,87.4778405539 2014-04-09 16:50:00,86.0320998039 2014-04-09 16:55:00,76.4917243827 2014-04-09 17:00:00,80.11533090020001 2014-04-09 17:05:00,72.902601968 2014-04-09 17:10:00,75.8520415099 2014-04-09 17:15:00,84.3976614804 2014-04-09 17:20:00,73.9729957908 2014-04-09 17:25:00,76.1230191661 2014-04-09 17:30:00,87.10464657959999 2014-04-09 17:35:00,85.18166009810001 2014-04-09 17:40:00,84.5092109508 2014-04-09 17:45:00,85.832886885 2014-04-09 17:50:00,83.9936587317 2014-04-09 17:55:00,73.92935106899999 2014-04-09 18:00:00,32.1059863252 2014-04-09 18:05:00,31.6431550176 2014-04-09 18:10:00,30.791364189 2014-04-09 18:15:00,34.1378520677 2014-04-09 18:20:00,31.770484795300003 2014-04-09 18:25:00,29.185899045 2014-04-09 18:30:00,30.5597738683 2014-04-09 18:35:00,30.2631689609 2014-04-09 18:40:00,34.4798582427 2014-04-09 18:45:00,32.9435975189 2014-04-09 18:50:00,32.3864018835 2014-04-09 18:55:00,32.0425489946 2014-04-09 19:00:00,23.0725050977 2014-04-09 19:05:00,23.5418411581 2014-04-09 19:10:00,22.64364224 2014-04-09 19:15:00,24.3635173234 2014-04-09 19:20:00,24.536215738499997 2014-04-09 19:25:00,24.6191322279 2014-04-09 19:30:00,23.1588709028 2014-04-09 19:35:00,24.3381383559 2014-04-09 19:40:00,21.9720678297 2014-04-09 19:45:00,24.0109725956 2014-04-09 19:50:00,24.233099529 2014-04-09 19:55:00,24.2105479879 2014-04-09 20:00:00,21.8351461128 2014-04-09 20:05:00,20.0974299249 2014-04-09 20:10:00,19.0828848172 2014-04-09 20:15:00,19.799884998 2014-04-09 20:20:00,21.5748137209 2014-04-09 20:25:00,19.3858988218 2014-04-09 20:30:00,20.3910021328 2014-04-09 20:35:00,20.7478761767 2014-04-09 20:40:00,20.9054044209 2014-04-09 20:45:00,22.264731579 2014-04-09 20:50:00,21.1414751579 2014-04-09 20:55:00,21.6526796908 2014-04-09 21:00:00,20.4250854059 2014-04-09 21:05:00,21.4367259651 2014-04-09 21:10:00,19.1461167468 2014-04-09 21:15:00,18.9299402917 2014-04-09 21:20:00,21.809465486599997 2014-04-09 21:25:00,20.8736382872 2014-04-09 21:30:00,20.7853955485 2014-04-09 21:35:00,19.964552974300002 2014-04-09 21:40:00,19.600421576600002 2014-04-09 21:45:00,20.319833999100002 2014-04-09 21:50:00,18.5709802262 2014-04-09 21:55:00,19.9139806768 2014-04-09 22:00:00,19.8404994201 2014-04-09 22:05:00,20.1726932541 2014-04-09 22:10:00,20.5584596401 2014-04-09 22:15:00,21.8502295557 2014-04-09 22:20:00,20.6284608277 2014-04-09 22:25:00,21.555574101799998 2014-04-09 22:30:00,20.244631642799998 2014-04-09 22:35:00,20.527398923499998 2014-04-09 22:40:00,18.2968959774 2014-04-09 22:45:00,18.5508466151 2014-04-09 22:50:00,20.3381876653 2014-04-09 22:55:00,19.6016510076 2014-04-09 23:00:00,21.1993115639 2014-04-09 23:05:00,20.176584658099998 2014-04-09 23:10:00,21.533297753200003 2014-04-09 23:15:00,21.893529462399997 2014-04-09 23:20:00,18.5941101225 2014-04-09 23:25:00,19.5830702324 2014-04-09 23:30:00,20.6638908043 2014-04-09 23:35:00,19.2256456351 2014-04-09 23:40:00,19.0717904298 2014-04-09 23:45:00,21.259035191600002 2014-04-09 23:50:00,21.925722804699998 2014-04-09 23:55:00,21.099263603900003 2014-04-10 00:00:00,20.0947064912 2014-04-10 00:05:00,19.7700449278 2014-04-10 00:10:00,20.1585908821 2014-04-10 00:15:00,19.8513588088 2014-04-10 00:20:00,20.0115522271 2014-04-10 00:25:00,18.8138122021 2014-04-10 00:30:00,21.6149677972 2014-04-10 00:35:00,21.018140006099998 2014-04-10 00:40:00,20.7239096908 2014-04-10 00:45:00,21.799699883899997 2014-04-10 00:50:00,19.1375773277 2014-04-10 00:55:00,18.3246376436 2014-04-10 01:00:00,21.3045546414 2014-04-10 01:05:00,21.9936678546 2014-04-10 01:10:00,20.3137297521 2014-04-10 01:15:00,18.2352375517 2014-04-10 01:20:00,21.1218721606 2014-04-10 01:25:00,18.2949961954 2014-04-10 01:30:00,20.160055945 2014-04-10 01:35:00,19.1101298968 2014-04-10 01:40:00,21.6601071224 2014-04-10 01:45:00,19.805324853 2014-04-10 01:50:00,21.593853393899998 2014-04-10 01:55:00,19.196324341 2014-04-10 02:00:00,19.5494503353 2014-04-10 02:05:00,21.788476753 2014-04-10 02:10:00,18.805257803699998 2014-04-10 02:15:00,20.3140046066 2014-04-10 02:20:00,19.5540413142 2014-04-10 02:25:00,21.0966675403 2014-04-10 02:30:00,18.5171854847 2014-04-10 02:35:00,19.748859875999997 2014-04-10 02:40:00,20.795730507400002 2014-04-10 02:45:00,19.62806494 2014-04-10 02:50:00,18.2341269571 2014-04-10 02:55:00,20.8204490453 2014-04-10 03:00:00,20.012793310699998 2014-04-10 03:05:00,18.0452347467 2014-04-10 03:10:00,20.4506235809 2014-04-10 03:15:00,21.679524090100003 2014-04-10 03:20:00,18.4441037928 2014-04-10 03:25:00,20.36268494 2014-04-10 03:30:00,20.9146755271 2014-04-10 03:35:00,18.283094680599998 2014-04-10 03:40:00,18.0904618327 2014-04-10 03:45:00,19.8567834666 2014-04-10 03:50:00,21.1647467489 2014-04-10 03:55:00,18.6428776404 2014-04-10 04:00:00,21.3465490889 2014-04-10 04:05:00,20.6263090217 2014-04-10 04:10:00,19.3286931512 2014-04-10 04:15:00,20.063303194 2014-04-10 04:20:00,21.8622999189 2014-04-10 04:25:00,18.8657478825 2014-04-10 04:30:00,19.998141591 2014-04-10 04:35:00,20.4979462244 2014-04-10 04:40:00,18.5520584219 2014-04-10 04:45:00,18.1740883545 2014-04-10 04:50:00,18.0538398117 2014-04-10 04:55:00,19.298771426400002 2014-04-10 05:00:00,18.295789177899998 2014-04-10 05:05:00,21.2150798102 2014-04-10 05:10:00,21.9892781086 2014-04-10 05:15:00,18.2452152869 2014-04-10 05:20:00,19.7309051037 2014-04-10 05:25:00,18.102928491900002 2014-04-10 05:30:00,18.535963563 2014-04-10 05:35:00,19.291690243599998 2014-04-10 05:40:00,19.5747928522 2014-04-10 05:45:00,21.759131785700003 2014-04-10 05:50:00,19.583347235 2014-04-10 05:55:00,19.985110636199998 2014-04-10 06:00:00,18.9823334731 2014-04-10 06:05:00,18.000500555 2014-04-10 06:10:00,21.597337826900002 2014-04-10 06:15:00,18.3268590281 2014-04-10 06:20:00,21.856995364099998 2014-04-10 06:25:00,18.5233764164 2014-04-10 06:30:00,20.419513923 2014-04-10 06:35:00,21.9976423514 2014-04-10 06:40:00,18.5538583843 2014-04-10 06:45:00,19.6957723398 2014-04-10 06:50:00,21.1216946759 2014-04-10 06:55:00,18.1287605994 2014-04-10 07:00:00,20.7591310046 2014-04-10 07:05:00,18.3214933516 2014-04-10 07:10:00,18.9460805691 2014-04-10 07:15:00,18.64030465 2014-04-10 07:20:00,21.629345726599997 2014-04-10 07:25:00,18.7218268671 2014-04-10 07:30:00,18.1617363821 2014-04-10 07:35:00,20.3505027138 2014-04-10 07:40:00,19.384723701600002 2014-04-10 07:45:00,19.6228248826 2014-04-10 07:50:00,18.4762509795 2014-04-10 07:55:00,20.992937965699998 2014-04-10 08:00:00,20.4062145986 2014-04-10 08:05:00,19.456868179 2014-04-10 08:10:00,18.6862997751 2014-04-10 08:15:00,20.3738069567 2014-04-10 08:20:00,21.114389118 2014-04-10 08:25:00,19.2495891355 2014-04-10 08:30:00,18.1034415342 2014-04-10 08:35:00,18.857375939 2014-04-10 08:40:00,20.7295912756 2014-04-10 08:45:00,21.9563855098 2014-04-10 08:50:00,18.0535049576 2014-04-10 08:55:00,19.2246142485 2014-04-10 09:00:00,62.0434838381 2014-04-10 09:05:00,65.50235031359999 2014-04-10 09:10:00,66.7204350665 2014-04-10 09:15:00,73.7237244505 2014-04-10 09:20:00,62.2956268719 2014-04-10 09:25:00,71.7690231217 2014-04-10 09:30:00,66.5792677865 2014-04-10 09:35:00,72.2331747555 2014-04-10 09:40:00,68.1822697204 2014-04-10 09:45:00,61.7342357283 2014-04-10 09:50:00,74.0684000321 2014-04-10 09:55:00,62.3251832627 2014-04-10 10:00:00,79.1160479593 2014-04-10 10:05:00,83.4614036807 2014-04-10 10:10:00,71.07802726109999 2014-04-10 10:15:00,78.43642538819999 2014-04-10 10:20:00,82.63297886810001 2014-04-10 10:25:00,85.1477594782 2014-04-10 10:30:00,81.0815612606 2014-04-10 10:35:00,74.1597495072 2014-04-10 10:40:00,80.6973315192 2014-04-10 10:45:00,80.7935002597 2014-04-10 10:50:00,80.7034725079 2014-04-10 10:55:00,83.0981219837 2014-04-10 11:00:00,72.9576925143 2014-04-10 11:05:00,73.29230922149999 2014-04-10 11:10:00,81.7563747437 2014-04-10 11:15:00,86.7385249523 2014-04-10 11:20:00,78.9766977134 2014-04-10 11:25:00,86.8447892067 2014-04-10 11:30:00,86.4873079673 2014-04-10 11:35:00,85.92787647690002 2014-04-10 11:40:00,86.0382699042 2014-04-10 11:45:00,85.8548620891 2014-04-10 11:50:00,84.6075207558 2014-04-10 11:55:00,82.62094535770001 2014-04-10 12:00:00,72.3036622205 2014-04-10 12:05:00,74.0271182055 2014-04-10 12:10:00,74.0587356171 2014-04-10 12:15:00,72.289792575 2014-04-10 12:20:00,73.7785876208 2014-04-10 12:25:00,86.61188380549999 2014-04-10 12:30:00,82.5217235483 2014-04-10 12:35:00,76.9007764908 2014-04-10 12:40:00,84.5921276836 2014-04-10 12:45:00,79.7181350971 2014-04-10 12:50:00,74.1849037515 2014-04-10 12:55:00,86.04865085969999 2014-04-10 13:00:00,77.4000106779 2014-04-10 13:05:00,83.16178406899999 2014-04-10 13:10:00,76.6311106864 2014-04-10 13:15:00,79.98193973720001 2014-04-10 13:20:00,85.0396289741 2014-04-10 13:25:00,74.4905555178 2014-04-10 13:30:00,87.61498967850002 2014-04-10 13:35:00,73.1059051366 2014-04-10 13:40:00,80.5248119616 2014-04-10 13:45:00,86.6356107716 2014-04-10 13:50:00,87.1101906936 2014-04-10 13:55:00,75.6955721077 2014-04-10 14:00:00,74.300193119 2014-04-10 14:05:00,83.5864356636 2014-04-10 14:10:00,72.6680888567 2014-04-10 14:15:00,79.75999484100001 2014-04-10 14:20:00,84.7376160279 2014-04-10 14:25:00,80.9601893166 2014-04-10 14:30:00,75.0046118582 2014-04-10 14:35:00,79.7888787415 2014-04-10 14:40:00,86.7362319242 2014-04-10 14:45:00,81.8714776291 2014-04-10 14:50:00,83.5398399363 2014-04-10 14:55:00,77.3765078239 2014-04-10 15:00:00,75.01502025159999 2014-04-10 15:05:00,76.0895452117 2014-04-10 15:10:00,80.53006840409999 2014-04-10 15:15:00,76.482788216 2014-04-10 15:20:00,80.670662153 2014-04-10 15:25:00,83.3238709212 2014-04-10 15:30:00,83.7495300155 2014-04-10 15:35:00,74.634242539 2014-04-10 15:40:00,84.0060871152 2014-04-10 15:45:00,82.7622157086 2014-04-10 15:50:00,72.1913890899 2014-04-10 15:55:00,72.9412545587 2014-04-10 16:00:00,82.339833937 2014-04-10 16:05:00,78.1391123656 2014-04-10 16:10:00,74.3375212649 2014-04-10 16:15:00,72.7102053429 2014-04-10 16:20:00,74.55023031399999 2014-04-10 16:25:00,87.3200557743 2014-04-10 16:30:00,83.6408896743 2014-04-10 16:35:00,80.4431322838 2014-04-10 16:40:00,87.0644808367 2014-04-10 16:45:00,81.9056097438 2014-04-10 16:50:00,83.6101624807 2014-04-10 16:55:00,76.52228217300001 2014-04-10 17:00:00,81.42367823069999 2014-04-10 17:05:00,74.2956073792 2014-04-10 17:10:00,78.47170019 2014-04-10 17:15:00,72.5318173476 2014-04-10 17:20:00,75.46602042239999 2014-04-10 17:25:00,73.1978699628 2014-04-10 17:30:00,78.20443108159999 2014-04-10 17:35:00,85.4885298066 2014-04-10 17:40:00,78.0469157315 2014-04-10 17:45:00,85.30620125829998 2014-04-10 17:50:00,82.5039413197 2014-04-10 17:55:00,80.1524403675 2014-04-10 18:00:00,30.316101016199998 2014-04-10 18:05:00,34.7017923315 2014-04-10 18:10:00,29.1468795804 2014-04-10 18:15:00,33.2090369371 2014-04-10 18:20:00,32.775929020999996 2014-04-10 18:25:00,31.622659670900003 2014-04-10 18:30:00,30.338048289 2014-04-10 18:35:00,31.556447936999998 2014-04-10 18:40:00,34.3857388415 2014-04-10 18:45:00,34.1552965478 2014-04-10 18:50:00,34.8248333135 2014-04-10 18:55:00,30.769870614600002 2014-04-10 19:00:00,21.894225428400002 2014-04-10 19:05:00,20.2438920534 2014-04-10 19:10:00,24.384414638699997 2014-04-10 19:15:00,21.6356664245 2014-04-10 19:20:00,21.9706527152 2014-04-10 19:25:00,24.226963330300002 2014-04-10 19:30:00,22.5191597318 2014-04-10 19:35:00,22.696460702 2014-04-10 19:40:00,20.9495219657 2014-04-10 19:45:00,22.3939956648 2014-04-10 19:50:00,24.273573200500003 2014-04-10 19:55:00,22.6630557915 2014-04-10 20:00:00,19.4769563958 2014-04-10 20:05:00,18.5597165968 2014-04-10 20:10:00,19.809491826400002 2014-04-10 20:15:00,20.7773321347 2014-04-10 20:20:00,18.6065438059 2014-04-10 20:25:00,20.929710145399998 2014-04-10 20:30:00,20.575902789 2014-04-10 20:35:00,21.640951421999997 2014-04-10 20:40:00,18.550325730999997 2014-04-10 20:45:00,21.6303504648 2014-04-10 20:50:00,20.5655121326 2014-04-10 20:55:00,19.9496879077 2014-04-10 21:00:00,21.9664672049 2014-04-10 21:05:00,18.729952438399998 2014-04-10 21:10:00,20.2620938691 2014-04-10 21:15:00,19.3764886913 2014-04-10 21:20:00,20.2064732042 2014-04-10 21:25:00,20.306105449300002 2014-04-10 21:30:00,18.445910355 2014-04-10 21:35:00,20.7436343318 2014-04-10 21:40:00,20.6365079779 2014-04-10 21:45:00,21.1790428184 2014-04-10 21:50:00,18.4507745726 2014-04-10 21:55:00,19.2811415046 2014-04-10 22:00:00,20.6202188135 2014-04-10 22:05:00,18.5647283409 2014-04-10 22:10:00,20.7302748101 2014-04-10 22:15:00,18.2536134969 2014-04-10 22:20:00,19.3582923395 2014-04-10 22:25:00,21.4073758495 2014-04-10 22:30:00,21.1174184297 2014-04-10 22:35:00,20.5987987319 2014-04-10 22:40:00,21.5024562163 2014-04-10 22:45:00,20.8570817615 2014-04-10 22:50:00,20.0967748114 2014-04-10 22:55:00,21.939912105999998 2014-04-10 23:00:00,20.7834139666 2014-04-10 23:05:00,20.4093865552 2014-04-10 23:10:00,19.6392522545 2014-04-10 23:15:00,21.613799045 2014-04-10 23:20:00,19.1865194851 2014-04-10 23:25:00,18.0403414557 2014-04-10 23:30:00,18.7905691846 2014-04-10 23:35:00,18.4416100754 2014-04-10 23:40:00,19.279676082 2014-04-10 23:45:00,21.3076049826 2014-04-10 23:50:00,20.6100751142 2014-04-10 23:55:00,18.6795081322 2014-04-11 00:00:00,21.1552868844 2014-04-11 00:05:00,20.016879464400002 2014-04-11 00:10:00,20.050858496500002 2014-04-11 00:15:00,19.4484487239 2014-04-11 00:20:00,21.4584654593 2014-04-11 00:25:00,19.2733092154 2014-04-11 00:30:00,18.3765590427 2014-04-11 00:35:00,19.2109159759 2014-04-11 00:40:00,20.8614141851 2014-04-11 00:45:00,20.6303275472 2014-04-11 00:50:00,18.752068614200002 2014-04-11 00:55:00,18.4471371964 2014-04-11 01:00:00,20.6434630336 2014-04-11 01:05:00,20.7055073426 2014-04-11 01:10:00,19.4645985488 2014-04-11 01:15:00,21.3712055341 2014-04-11 01:20:00,21.9128208152 2014-04-11 01:25:00,18.8225808938 2014-04-11 01:30:00,20.3082748628 2014-04-11 01:35:00,18.021385316 2014-04-11 01:40:00,20.8522175841 2014-04-11 01:45:00,19.6571284543 2014-04-11 01:50:00,18.7730769076 2014-04-11 01:55:00,21.0088876871 2014-04-11 02:00:00,21.2425951902 2014-04-11 02:05:00,18.4446660047 2014-04-11 02:10:00,18.1639830474 2014-04-11 02:15:00,19.336313766700002 2014-04-11 02:20:00,20.503961863 2014-04-11 02:25:00,21.1736781088 2014-04-11 02:30:00,20.1842499865 2014-04-11 02:35:00,20.3229951052 2014-04-11 02:40:00,21.199432887 2014-04-11 02:45:00,20.115373496900002 2014-04-11 02:50:00,20.4446179609 2014-04-11 02:55:00,20.0648693599 2014-04-11 03:00:00,21.5218329335 2014-04-11 03:05:00,18.9420664743 2014-04-11 03:10:00,19.0559743382 2014-04-11 03:15:00,18.5118458464 2014-04-11 03:20:00,21.277867005999997 2014-04-11 03:25:00,19.6471091622 2014-04-11 03:30:00,19.3915757635 2014-04-11 03:35:00,21.9253948683 2014-04-11 03:40:00,21.7072134658 2014-04-11 03:45:00,21.887950728499998 2014-04-11 03:50:00,18.569195987 2014-04-11 03:55:00,21.5650072526 2014-04-11 04:00:00,19.3148383975 2014-04-11 04:05:00,18.0506270808 2014-04-11 04:10:00,19.565193343900003 2014-04-11 04:15:00,20.0367854126 2014-04-11 04:20:00,18.4328816943 2014-04-11 04:25:00,20.1507104675 2014-04-11 04:30:00,21.2778543367 2014-04-11 04:35:00,19.5106038034 2014-04-11 04:40:00,19.410579226099998 2014-04-11 04:45:00,19.3552416809 2014-04-11 04:50:00,21.6923777835 2014-04-11 04:55:00,18.1950323952 2014-04-11 05:00:00,19.780304568 2014-04-11 05:05:00,19.0583978166 2014-04-11 05:10:00,21.575228101599997 2014-04-11 05:15:00,18.3842090543 2014-04-11 05:20:00,19.6457710667 2014-04-11 05:25:00,19.6272646081 2014-04-11 05:30:00,21.5535776702 2014-04-11 05:35:00,18.8619737802 2014-04-11 05:40:00,20.579581641199997 2014-04-11 05:45:00,18.5376245076 2014-04-11 05:50:00,21.815902856300006 2014-04-11 05:55:00,20.3720598371 2014-04-11 06:00:00,20.5050269213 2014-04-11 06:05:00,19.7350936066 2014-04-11 06:10:00,19.3691308507 2014-04-11 06:15:00,18.850705718 2014-04-11 06:20:00,20.4159510153 2014-04-11 06:25:00,21.818246981399998 2014-04-11 06:30:00,19.4391638164 2014-04-11 06:35:00,21.5326275546 2014-04-11 06:40:00,18.5951052514 2014-04-11 06:45:00,21.7445040835 2014-04-11 06:50:00,19.4019451356 2014-04-11 06:55:00,19.518908846400002 2014-04-11 07:00:00,19.8513690281 2014-04-11 07:05:00,20.872977079800002 2014-04-11 07:10:00,20.878613734800002 2014-04-11 07:15:00,19.918354338900002 2014-04-11 07:20:00,20.0926115973 2014-04-11 07:25:00,18.1200419511 2014-04-11 07:30:00,19.217186806199997 2014-04-11 07:35:00,19.3840682969 2014-04-11 07:40:00,20.2349090749 2014-04-11 07:45:00,20.2331990695 2014-04-11 07:50:00,20.8395991909 2014-04-11 07:55:00,20.8681091849 2014-04-11 08:00:00,18.9408428968 2014-04-11 08:05:00,21.0807486044 2014-04-11 08:10:00,18.0784142722 2014-04-11 08:15:00,20.8646475384 2014-04-11 08:20:00,18.4082444141 2014-04-11 08:25:00,20.9185928337 2014-04-11 08:30:00,20.1084723623 2014-04-11 08:35:00,19.7490180027 2014-04-11 08:40:00,20.762665559000002 2014-04-11 08:45:00,18.145483335 2014-04-11 08:50:00,18.8938813027 2014-04-11 08:55:00,20.4657605699 2014-04-11 09:00:00,21.388861626500002 2014-04-11 09:05:00,19.524430547799998 2014-04-11 09:10:00,19.0350458905 2014-04-11 09:15:00,20.0749457432 2014-04-11 09:20:00,20.4892610095 2014-04-11 09:25:00,19.6804121256 2014-04-11 09:30:00,21.5068427306 2014-04-11 09:35:00,20.0937548354 2014-04-11 09:40:00,18.1432943503 2014-04-11 09:45:00,18.8922158188 2014-04-11 09:50:00,19.802588123699998 2014-04-11 09:55:00,20.7909020761 2014-04-11 10:00:00,18.8790089752 2014-04-11 10:05:00,21.9050297589 2014-04-11 10:10:00,19.274233032799998 2014-04-11 10:15:00,20.1299208274 2014-04-11 10:20:00,18.0758655389 2014-04-11 10:25:00,21.5395628857 2014-04-11 10:30:00,21.1553386141 2014-04-11 10:35:00,18.7818320172 2014-04-11 10:40:00,21.732946765 2014-04-11 10:45:00,19.2633590552 2014-04-11 10:50:00,20.7687451535 2014-04-11 10:55:00,21.2759052721 2014-04-11 11:00:00,20.9636578449 2014-04-11 11:05:00,21.6703311361 2014-04-11 11:10:00,21.4570990414 2014-04-11 11:15:00,21.9784460564 2014-04-11 11:20:00,18.7304456503 2014-04-11 11:25:00,19.2190472049 2014-04-11 11:30:00,20.5449034697 2014-04-11 11:35:00,20.932188743599998 2014-04-11 11:40:00,20.1384202182 2014-04-11 11:45:00,18.2957134595 2014-04-11 11:50:00,21.3663809072 2014-04-11 11:55:00,21.843497424099997 2014-04-11 12:00:00,19.6220673753 2014-04-11 12:05:00,18.8992499268 2014-04-11 12:10:00,18.0772550198 2014-04-11 12:15:00,18.949196144400002 2014-04-11 12:20:00,20.7996750994 2014-04-11 12:25:00,21.646357550700003 2014-04-11 12:30:00,18.374052265699998 2014-04-11 12:35:00,20.2130367486 2014-04-11 12:40:00,20.782124994 2014-04-11 12:45:00,19.1055232844 2014-04-11 12:50:00,20.2795881567 2014-04-11 12:55:00,20.860993704000002 2014-04-11 13:00:00,21.3508769725 2014-04-11 13:05:00,19.8099994033 2014-04-11 13:10:00,20.9914288757 2014-04-11 13:15:00,19.207131887 2014-04-11 13:20:00,18.8521869871 2014-04-11 13:25:00,18.7492549844 2014-04-11 13:30:00,19.435490927300002 2014-04-11 13:35:00,18.1435187272 2014-04-11 13:40:00,19.1319673507 2014-04-11 13:45:00,20.6088912978 2014-04-11 13:50:00,20.591676188599997 2014-04-11 13:55:00,18.294215226 2014-04-11 14:00:00,19.1496624683 2014-04-11 14:05:00,20.2782306587 2014-04-11 14:10:00,19.27420855 2014-04-11 14:15:00,19.671952096800002 2014-04-11 14:20:00,20.8512430285 2014-04-11 14:25:00,18.0370673178 2014-04-11 14:30:00,19.1055741764 2014-04-11 14:35:00,18.5694889751 2014-04-11 14:40:00,18.5104367311 2014-04-11 14:45:00,21.8361608658 2014-04-11 14:50:00,19.506241326199998 2014-04-11 14:55:00,20.1083543396 2014-04-11 15:00:00,20.9352875483 2014-04-11 15:05:00,18.1897898994 2014-04-11 15:10:00,18.964090554200002 2014-04-11 15:15:00,21.3285911494 2014-04-11 15:20:00,21.4479624527 2014-04-11 15:25:00,19.4918036826 2014-04-11 15:30:00,19.4994463986 2014-04-11 15:35:00,21.0275875084 2014-04-11 15:40:00,19.180280907 2014-04-11 15:45:00,18.4683763246 2014-04-11 15:50:00,19.030141801 2014-04-11 15:55:00,19.5493789265 2014-04-11 16:00:00,18.2088188384 2014-04-11 16:05:00,19.9147210168 2014-04-11 16:10:00,20.9600300511 2014-04-11 16:15:00,20.0549805779 2014-04-11 16:20:00,18.2875813621 2014-04-11 16:25:00,19.7605985254 2014-04-11 16:30:00,20.8356184322 2014-04-11 16:35:00,18.232386616 2014-04-11 16:40:00,18.239388758900002 2014-04-11 16:45:00,19.4824056127 2014-04-11 16:50:00,18.7798558565 2014-04-11 16:55:00,21.7391231652 2014-04-11 17:00:00,20.325374415 2014-04-11 17:05:00,19.1493015976 2014-04-11 17:10:00,20.8191069165 2014-04-11 17:15:00,19.4997162054 2014-04-11 17:20:00,18.5284625775 2014-04-11 17:25:00,18.9489289194 2014-04-11 17:30:00,20.570989137799998 2014-04-11 17:35:00,18.207504424 2014-04-11 17:40:00,19.0907561602 2014-04-11 17:45:00,18.8332459106 2014-04-11 17:50:00,18.8045404427 2014-04-11 17:55:00,20.7310496479 2014-04-11 18:00:00,21.303267667 2014-04-11 18:05:00,20.8634664323 2014-04-11 18:10:00,20.5829112632 2014-04-11 18:15:00,21.6658070873 2014-04-11 18:20:00,18.2335695217 2014-04-11 18:25:00,18.6699323439 2014-04-11 18:30:00,19.6576274227 2014-04-11 18:35:00,19.489806574 2014-04-11 18:40:00,19.6722064119 2014-04-11 18:45:00,18.8258196202 2014-04-11 18:50:00,18.5980132623 2014-04-11 18:55:00,20.0367729898 2014-04-11 19:00:00,21.7122100963 2014-04-11 19:05:00,19.567877849400002 2014-04-11 19:10:00,18.1734128565 2014-04-11 19:15:00,20.824669371600002 2014-04-11 19:20:00,19.1644196221 2014-04-11 19:25:00,18.9803800292 2014-04-11 19:30:00,19.297032002799998 2014-04-11 19:35:00,20.8952620956 2014-04-11 19:40:00,21.2752775475 2014-04-11 19:45:00,20.3522242694 2014-04-11 19:50:00,19.2899150149 2014-04-11 19:55:00,19.2419129325 2014-04-11 20:00:00,18.4972333996 2014-04-11 20:05:00,21.7332041929 2014-04-11 20:10:00,20.552557595899998 2014-04-11 20:15:00,18.1078984794 2014-04-11 20:20:00,20.6494683807 2014-04-11 20:25:00,19.788613696800002 2014-04-11 20:30:00,21.8902318522 2014-04-11 20:35:00,21.2762752992 2014-04-11 20:40:00,18.6852630153 2014-04-11 20:45:00,20.8804444755 2014-04-11 20:50:00,19.9422640153 2014-04-11 20:55:00,18.7481806547 2014-04-11 21:00:00,20.7949596293 2014-04-11 21:05:00,20.1895503148 2014-04-11 21:10:00,18.1214955151 2014-04-11 21:15:00,20.5863518021 2014-04-11 21:20:00,20.5399483594 2014-04-11 21:25:00,18.576340644200002 2014-04-11 21:30:00,19.395950908 2014-04-11 21:35:00,20.343595883 2014-04-11 21:40:00,18.5551320564 2014-04-11 21:45:00,21.4108935113 2014-04-11 21:50:00,18.1099441852 2014-04-11 21:55:00,18.4113496599 2014-04-11 22:00:00,18.4644276794 2014-04-11 22:05:00,20.112428503900002 2014-04-11 22:10:00,20.4804560487 2014-04-11 22:15:00,19.614963186 2014-04-11 22:20:00,19.1546673107 2014-04-11 22:25:00,21.2372695025 2014-04-11 22:30:00,18.2731439349 2014-04-11 22:35:00,19.1211674445 2014-04-11 22:40:00,18.1564623152 2014-04-11 22:45:00,18.0555605399 2014-04-11 22:50:00,19.413519547699998 2014-04-11 22:55:00,18.7792946498 2014-04-11 23:00:00,19.0734634194 2014-04-11 23:05:00,21.2837886298 2014-04-11 23:10:00,18.651920385 2014-04-11 23:15:00,21.1209334686 2014-04-11 23:20:00,20.7002024926 2014-04-11 23:25:00,19.3057821006 2014-04-11 23:30:00,20.1862245807 2014-04-11 23:35:00,19.777742439100003 2014-04-11 23:40:00,18.513581262 2014-04-11 23:45:00,21.628741286900002 2014-04-11 23:50:00,20.2784718703 2014-04-11 23:55:00,21.520960183200003 2014-04-12 00:00:00,21.2953060473 2014-04-12 00:05:00,18.3191037012 2014-04-12 00:10:00,18.8290826641 2014-04-12 00:15:00,18.5810444575 2014-04-12 00:20:00,21.3231181311 2014-04-12 00:25:00,21.4497865058 2014-04-12 00:30:00,20.1118860392 2014-04-12 00:35:00,18.41671229 2014-04-12 00:40:00,18.5424664742 2014-04-12 00:45:00,21.2541952498 2014-04-12 00:50:00,21.7167605461 2014-04-12 00:55:00,18.797902740399998 2014-04-12 01:00:00,18.0445503059 2014-04-12 01:05:00,19.3238116206 2014-04-12 01:10:00,18.1219975586 2014-04-12 01:15:00,21.3118996643 2014-04-12 01:20:00,19.966049028900002 2014-04-12 01:25:00,20.5674431151 2014-04-12 01:30:00,19.6459395045 2014-04-12 01:35:00,19.3820301881 2014-04-12 01:40:00,18.8888016523 2014-04-12 01:45:00,21.0821301882 2014-04-12 01:50:00,20.7821903377 2014-04-12 01:55:00,19.442915938 2014-04-12 02:00:00,19.2844645372 2014-04-12 02:05:00,18.0049715146 2014-04-12 02:10:00,18.2542085202 2014-04-12 02:15:00,20.4930220996 2014-04-12 02:20:00,20.0584292409 2014-04-12 02:25:00,19.7392128179 2014-04-12 02:30:00,21.310008963199998 2014-04-12 02:35:00,20.015592817599998 2014-04-12 02:40:00,19.5379743256 2014-04-12 02:45:00,18.6450253901 2014-04-12 02:50:00,21.2827520329 2014-04-12 02:55:00,20.304993000499998 2014-04-12 03:00:00,18.369839863699998 2014-04-12 03:05:00,20.595593592 2014-04-12 03:10:00,19.700282982 2014-04-12 03:15:00,21.245544894400002 2014-04-12 03:20:00,21.675658388000002 2014-04-12 03:25:00,20.4018632527 2014-04-12 03:30:00,20.9264512773 2014-04-12 03:35:00,18.2263633904 2014-04-12 03:40:00,20.24102182 2014-04-12 03:45:00,21.021359913399998 2014-04-12 03:50:00,19.9870485979 2014-04-12 03:55:00,20.374200358 2014-04-12 04:00:00,21.5957927423 2014-04-12 04:05:00,18.7923982881 2014-04-12 04:10:00,18.3929860302 2014-04-12 04:15:00,20.7625744526 2014-04-12 04:20:00,21.2913956221 2014-04-12 04:25:00,21.4019607543 2014-04-12 04:30:00,20.5665779884 2014-04-12 04:35:00,21.3328536727 2014-04-12 04:40:00,20.8026568229 2014-04-12 04:45:00,18.349507663599997 2014-04-12 04:50:00,21.0481740315 2014-04-12 04:55:00,18.7174387582 2014-04-12 05:00:00,18.946437370399998 2014-04-12 05:05:00,19.578602508 2014-04-12 05:10:00,19.2582682653 2014-04-12 05:15:00,19.2866069532 2014-04-12 05:20:00,18.6770380968 2014-04-12 05:25:00,19.1754841884 2014-04-12 05:30:00,18.0786503599 2014-04-12 05:35:00,19.8916437868 2014-04-12 05:40:00,21.0743638351 2014-04-12 05:45:00,21.4489894769 2014-04-12 05:50:00,21.2817142358 2014-04-12 05:55:00,19.665830875999998 2014-04-12 06:00:00,20.9217059247 2014-04-12 06:05:00,19.1515630964 2014-04-12 06:10:00,18.2222498909 2014-04-12 06:15:00,20.703886101600002 2014-04-12 06:20:00,20.595184658900003 2014-04-12 06:25:00,21.206517581900002 2014-04-12 06:30:00,20.464424826800002 2014-04-12 06:35:00,18.6275664999 2014-04-12 06:40:00,21.4126495682 2014-04-12 06:45:00,20.5090111521 2014-04-12 06:50:00,21.2304387961 2014-04-12 06:55:00,21.096428481500002 2014-04-12 07:00:00,19.191457948900002 2014-04-12 07:05:00,18.298211899400002 2014-04-12 07:10:00,18.706017636400002 2014-04-12 07:15:00,18.3714493373 2014-04-12 07:20:00,18.9736497283 2014-04-12 07:25:00,19.8381290921 2014-04-12 07:30:00,21.627242419899996 2014-04-12 07:35:00,21.4880750237 2014-04-12 07:40:00,20.8743992604 2014-04-12 07:45:00,18.0964494382 2014-04-12 07:50:00,19.3655568053 2014-04-12 07:55:00,20.729393705899998 2014-04-12 08:00:00,18.5161155874 2014-04-12 08:05:00,21.2043514001 2014-04-12 08:10:00,21.65829472 2014-04-12 08:15:00,19.4164177866 2014-04-12 08:20:00,20.8233722475 2014-04-12 08:25:00,18.5928165307 2014-04-12 08:30:00,20.7632657965 2014-04-12 08:35:00,18.0858216491 2014-04-12 08:40:00,18.6030860272 2014-04-12 08:45:00,20.8395257864 2014-04-12 08:50:00,20.8474008915 2014-04-12 08:55:00,20.564650823399997 2014-04-12 09:00:00,67.6921507316 2014-04-12 09:05:00,70.3787500399 2014-04-12 09:10:00,71.7236908567 2014-04-12 09:15:00,74.3441505629 2014-04-12 09:20:00,73.2855180291 2014-04-12 09:25:00,72.0056651549 2014-04-12 09:30:00,70.64870222729999 2014-04-12 09:35:00,69.0085154179 2014-04-12 09:40:00,62.8402799976 2014-04-12 09:45:00,63.4515730525 2014-04-12 09:50:00,72.3558020251 2014-04-12 09:55:00,72.125055606 2014-04-12 10:00:00,79.3764025311 2014-04-12 10:05:00,76.65079885979999 2014-04-12 10:10:00,70.2440267253 2014-04-12 10:15:00,74.917786148 2014-04-12 10:20:00,76.3683274854 2014-04-12 10:25:00,77.3798687614 2014-04-12 10:30:00,84.2631177697 2014-04-12 10:35:00,71.5271698849 2014-04-12 10:40:00,77.892814595 2014-04-12 10:45:00,75.5501540488 2014-04-12 10:50:00,85.2063228102 2014-04-12 10:55:00,83.21612953270001 2014-04-12 11:00:00,78.5464502258 2014-04-12 11:05:00,87.4671589712 2014-04-12 11:10:00,79.7436618719 2014-04-12 11:15:00,74.225841437 2014-04-12 11:20:00,80.4086310988 2014-04-12 11:25:00,75.1655764993 2014-04-12 11:30:00,81.6879194086 2014-04-12 11:35:00,86.4770485414 2014-04-12 11:40:00,84.07170216600001 2014-04-12 11:45:00,75.9123953324 2014-04-12 11:50:00,76.28923957149999 2014-04-12 11:55:00,72.6699595819 2014-04-12 12:00:00,76.4819967079 2014-04-12 12:05:00,73.3938183987 2014-04-12 12:10:00,79.8951900938 2014-04-12 12:15:00,83.233553008 2014-04-12 12:20:00,83.9180759057 2014-04-12 12:25:00,72.8649247547 2014-04-12 12:30:00,77.3463672186 2014-04-12 12:35:00,76.5188153668 2014-04-12 12:40:00,73.5804026016 2014-04-12 12:45:00,77.7061815257 2014-04-12 12:50:00,76.69697480010001 2014-04-12 12:55:00,82.0534052842 2014-04-12 13:00:00,86.1121707375 2014-04-12 13:05:00,79.2584409418 2014-04-12 13:10:00,83.92649557 2014-04-12 13:15:00,74.318325194 2014-04-12 13:20:00,86.2987453874 2014-04-12 13:25:00,74.4236498476 2014-04-12 13:30:00,75.05560122109999 2014-04-12 13:35:00,73.6857320364 2014-04-12 13:40:00,76.936402855 2014-04-12 13:45:00,80.8191658913 2014-04-12 13:50:00,87.7868318851 2014-04-12 13:55:00,84.6735620213 2014-04-12 14:00:00,78.0832246716 2014-04-12 14:05:00,81.2096386767 2014-04-12 14:10:00,81.9689937945 2014-04-12 14:15:00,85.1595476855 2014-04-12 14:20:00,83.7792069717 2014-04-12 14:25:00,81.104764816 2014-04-12 14:30:00,82.7029585001 2014-04-12 14:35:00,83.93065291069999 2014-04-12 14:40:00,74.1267466915 2014-04-12 14:45:00,75.20367743109999 2014-04-12 14:50:00,83.0133637898 2014-04-12 14:55:00,85.602699865 2014-04-12 15:00:00,78.54744246050001 2014-04-12 15:05:00,87.6774034484 2014-04-12 15:10:00,75.4564233342 2014-04-12 15:15:00,78.6664333077 2014-04-12 15:20:00,78.0556193543 2014-04-12 15:25:00,86.8839009582 2014-04-12 15:30:00,76.565321247 2014-04-12 15:35:00,79.5318889352 2014-04-12 15:40:00,74.9950214747 2014-04-12 15:45:00,80.33948855050001 2014-04-12 15:50:00,85.7176438141 2014-04-12 15:55:00,76.86389348979999 2014-04-12 16:00:00,84.9725100071 2014-04-12 16:05:00,86.5808190793 2014-04-12 16:10:00,73.1671857542 2014-04-12 16:15:00,84.1026311037 2014-04-12 16:20:00,76.0853488943 2014-04-12 16:25:00,74.8050989745 2014-04-12 16:30:00,81.6178015659 2014-04-12 16:35:00,83.28948194350001 2014-04-12 16:40:00,78.3160254047 2014-04-12 16:45:00,72.6266398699 2014-04-12 16:50:00,86.5391062317 2014-04-12 16:55:00,83.691789981 2014-04-12 17:00:00,76.34663958979999 2014-04-12 17:05:00,79.9497909912 2014-04-12 17:10:00,72.44465682069999 2014-04-12 17:15:00,77.4284947763 2014-04-12 17:20:00,80.3605329109 2014-04-12 17:25:00,80.275547016 2014-04-12 17:30:00,75.330929121 2014-04-12 17:35:00,84.4279254386 2014-04-12 17:40:00,76.7817650522 2014-04-12 17:45:00,81.2865291568 2014-04-12 17:50:00,76.3443262924 2014-04-12 17:55:00,78.8026557076 2014-04-12 18:00:00,30.128087816999997 2014-04-12 18:05:00,32.8512435648 2014-04-12 18:10:00,31.5237338523 2014-04-12 18:15:00,28.9031451993 2014-04-12 18:20:00,28.9802503975 2014-04-12 18:25:00,31.815253529699998 2014-04-12 18:30:00,29.972639793400003 2014-04-12 18:35:00,32.5442628596 2014-04-12 18:40:00,31.412421372199997 2014-04-12 18:45:00,32.9882806137 2014-04-12 18:50:00,34.8953224141 2014-04-12 18:55:00,32.1839050834 2014-04-12 19:00:00,23.6874548447 2014-04-12 19:05:00,23.5336223725 2014-04-12 19:10:00,24.289622814899996 2014-04-12 19:15:00,21.118798886700002 2014-04-12 19:20:00,23.866423519899996 2014-04-12 19:25:00,24.2167299672 2014-04-12 19:30:00,21.919576952199996 2014-04-12 19:35:00,21.5658953688 2014-04-12 19:40:00,24.425119535500002 2014-04-12 19:45:00,22.971793783000003 2014-04-12 19:50:00,21.8654294544 2014-04-12 19:55:00,23.707386889299997 2014-04-12 20:00:00,19.6791248649 2014-04-12 20:05:00,19.1545652427 2014-04-12 20:10:00,20.6600993803 2014-04-12 20:15:00,20.751204286900002 2014-04-12 20:20:00,21.8142573296 2014-04-12 20:25:00,20.3039838025 2014-04-12 20:30:00,21.7685462046 2014-04-12 20:35:00,19.7071774581 2014-04-12 20:40:00,20.7887079067 2014-04-12 20:45:00,19.285904270899998 2014-04-12 20:50:00,20.0107863748 2014-04-12 20:55:00,21.944482339 2014-04-12 21:00:00,18.954499700699998 2014-04-12 21:05:00,21.3429143971 2014-04-12 21:10:00,19.2233177202 2014-04-12 21:15:00,18.2250210368 2014-04-12 21:20:00,18.5282489787 2014-04-12 21:25:00,21.084239017 2014-04-12 21:30:00,19.139715421 2014-04-12 21:35:00,20.715541913699997 2014-04-12 21:40:00,20.8966201789 2014-04-12 21:45:00,19.4735000846 2014-04-12 21:50:00,19.9951943445 2014-04-12 21:55:00,19.7092206418 2014-04-12 22:00:00,21.810313794899997 2014-04-12 22:05:00,19.298304043599998 2014-04-12 22:10:00,18.7512761202 2014-04-12 22:15:00,19.481055238499998 2014-04-12 22:20:00,20.6979137606 2014-04-12 22:25:00,20.809408624 2014-04-12 22:30:00,21.7170576309 2014-04-12 22:35:00,21.5476838661 2014-04-12 22:40:00,19.1716692231 2014-04-12 22:45:00,19.839680813 2014-04-12 22:50:00,21.0092254553 2014-04-12 22:55:00,21.686948614899997 2014-04-12 23:00:00,19.3523749923 2014-04-12 23:05:00,19.7815630658 2014-04-12 23:10:00,21.602059879000002 2014-04-12 23:15:00,19.4376668063 2014-04-12 23:20:00,19.9258769768 2014-04-12 23:25:00,21.6221672219 2014-04-12 23:30:00,21.2130449927 2014-04-12 23:35:00,18.9773666531 2014-04-12 23:40:00,19.3028857024 2014-04-12 23:45:00,19.4155619802 2014-04-12 23:50:00,21.655110874699997 2014-04-12 23:55:00,21.9999581274 2014-04-13 00:00:00,21.0960172086 2014-04-13 00:05:00,19.93730521 2014-04-13 00:10:00,18.0406952723 2014-04-13 00:15:00,20.7899522264 2014-04-13 00:20:00,19.557444657999998 2014-04-13 00:25:00,20.5319458809 2014-04-13 00:30:00,20.426775853800002 2014-04-13 00:35:00,19.9233282263 2014-04-13 00:40:00,21.7775495909 2014-04-13 00:45:00,18.0925853814 2014-04-13 00:50:00,20.8485299379 2014-04-13 00:55:00,19.6393594732 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/exchange-2_cpc_results.csv ================================================ timestamp,value 2011-07-01 00:00:01,0.0819647355164 2011-07-01 01:00:01,0.0989722357526 2011-07-01 02:00:01,0.0653139485883 2011-07-01 03:00:01,0.0706628339533 2011-07-01 04:00:01,0.102490196078 2011-07-01 05:00:01,0.123394648829 2011-07-01 06:00:01,0.153045112782 2011-07-01 07:00:01,0.148321513002 2011-07-01 08:00:01,0.218257756563 2011-07-01 09:00:01,0.226597938144 2011-07-01 10:00:01,0.174045801527 2011-07-01 11:00:01,0.159901960784 2011-07-01 12:00:01,0.145626477541 2011-07-01 13:00:01,0.143828571429 2011-07-01 14:00:01,0.136604651163 2011-07-01 15:00:01,0.134952494062 2011-07-01 16:00:01,0.112707774799 2011-07-01 17:00:01,0.103763277693 2011-07-01 18:00:01,0.0987147766323 2011-07-01 19:00:01,0.0916247582205 2011-07-01 20:00:01,0.0804951690821 2011-07-01 21:00:01,0.0845783926219 2011-07-01 22:00:01,0.0866643159379 2011-07-01 23:00:01,0.0988316679477 2011-07-02 00:00:01,0.11795614722 2011-07-02 01:00:01,0.0909769230769 2011-07-02 02:00:01,0.0843243243243 2011-07-02 03:00:01,0.0694744820616 2011-07-02 04:00:01,0.0712875751503 2011-07-02 05:00:01,0.0738199181446 2011-07-02 06:00:01,0.113498134328 2011-07-02 07:00:01,0.141458064516 2011-07-02 08:00:01,0.189128787879 2011-07-02 09:00:01,0.151339712919 2011-07-02 10:00:01,0.155231143552 2011-07-02 11:00:01,0.14298245614 2011-07-02 12:00:01,0.144218181818 2011-07-02 13:00:01,0.143366500829 2011-07-02 14:00:01,0.152361516035 2011-07-02 15:00:01,0.143050228311 2011-07-02 16:00:01,0.102183828611 2011-07-02 17:00:01,0.0924731182796 2011-07-02 18:00:01,0.0764556962025 2011-07-02 19:00:01,0.0743530192435 2011-07-02 20:00:01,0.0709893842887 2011-07-02 21:00:01,0.0571908831909 2011-07-02 22:00:01,0.0629096362955 2011-07-02 23:00:01,0.065544768069 2011-07-03 00:00:01,0.0567160161507 2011-07-03 01:00:01,0.0587607170694 2011-07-03 02:00:01,0.0598788546256 2011-07-03 03:00:01,0.0512832369942 2011-07-03 04:00:01,0.0591086065574 2011-07-03 05:00:01,0.0691399082569 2011-07-03 06:00:01,0.091963099631 2011-07-03 07:00:01,0.124621212121 2011-07-03 08:00:01,0.218095238095 2011-07-03 09:00:01,0.172130325815 2011-07-03 10:00:01,0.142936288089 2011-07-03 11:00:01,0.147341389728 2011-07-03 12:00:01,0.123138297872 2011-07-03 13:00:01,0.123795986622 2011-07-03 14:00:01,0.121458797327 2011-07-03 15:00:01,0.114387596899 2011-07-03 16:00:01,0.0894912891986 2011-07-03 17:00:01,0.0797851697852 2011-07-03 18:00:01,0.0724256756757 2011-07-03 19:00:01,0.0671052631579 2011-07-03 20:00:01,0.0625718496684 2011-07-03 21:00:01,0.0512057335582 2011-07-03 22:00:01,0.050217721519 2011-07-03 23:00:01,0.0530833333333 2011-07-04 00:00:01,0.0454658136745 2011-07-04 01:00:01,0.0482011892963 2011-07-04 02:00:01,0.0424707080998 2011-07-04 03:00:01,0.0361947700631 2011-07-04 04:00:01,0.0423479561316 2011-07-04 05:00:01,0.0616081330869 2011-07-04 06:00:01,0.0973949579832 2011-07-04 07:00:01,0.122106918239 2011-07-04 08:00:01,0.182614213198 2011-07-04 09:00:01,0.176124567474 2011-07-04 10:00:01,0.146950672646 2011-07-04 11:00:01,0.121809045226 2011-07-04 12:00:01,0.127351694915 2011-07-04 13:00:01,0.111390532544 2011-07-04 14:00:01,0.123798816568 2011-07-04 15:00:01,0.110897571278 2011-07-04 16:00:01,0.0864069952305 2011-07-04 17:00:01,0.0857901085645 2011-07-04 18:00:01,0.0712333965844 2011-07-04 19:00:01,0.0664840182648 2011-07-04 20:00:01,0.0633661075766 2011-07-04 21:00:01,0.0602728613569 2011-07-04 22:00:01,0.0604935424354 2011-07-04 23:00:01,0.059634551495 2011-07-05 00:00:01,0.0555023094688 2011-07-05 01:00:01,0.0426701570681 2011-07-05 02:00:01,0.0454550792719 2011-07-05 03:00:01,0.0372700871249 2011-07-05 04:00:01,0.0448206751055 2011-07-05 05:00:01,0.0649965493444 2011-07-05 06:00:01,0.0948186528497 2011-07-05 07:00:01,0.11772173913 2011-07-05 08:00:01,0.176833333333 2011-07-05 09:00:01,0.146557377049 2011-07-05 10:00:01,0.133574297189 2011-07-05 11:00:01,0.139591836735 2011-07-05 12:00:01,0.113243243243 2011-07-05 13:00:01,0.121060070671 2011-07-05 14:00:01,0.119309210526 2011-07-05 15:00:01,0.105715846995 2011-07-05 16:00:01,0.0908553546592 2011-07-05 17:00:01,0.0824758220503 2011-07-05 18:00:01,0.0744980370163 2011-07-05 19:00:01,0.0757240204429 2011-07-05 20:00:01,0.0704836829837 2011-07-05 21:00:01,0.0659228486647 2011-07-05 22:00:01,0.0508973252804 2011-07-05 23:00:01,0.0550694444444 2011-07-06 00:00:01,0.0592647765497 2011-07-06 01:00:01,0.0506581469649 2011-07-06 02:00:01,0.0409549982824 2011-07-06 03:00:01,0.0354873115116 2011-07-06 04:00:01,0.0584235976789 2011-07-06 05:00:01,0.0979736408567 2011-07-06 06:00:01,0.109025423729 2011-07-06 07:00:01,0.11874025974 2011-07-06 08:00:01,0.171501416431 2011-07-06 09:00:01,0.177857142857 2011-07-06 10:00:01,0.138678414097 2011-07-06 11:00:01,0.140806451613 2011-07-06 12:00:01,0.153417721519 2011-07-06 13:00:01,0.11140070922 2011-07-06 14:00:01,0.114154929577 2011-07-06 15:00:01,0.117304261645 2011-07-06 16:00:01,0.0871753246753 2011-07-06 17:00:01,0.0905656934307 2011-07-06 18:00:01,0.0828233970754 2011-07-06 19:00:01,0.0885174625802 2011-07-06 20:00:01,0.0849336128581 2011-07-06 21:00:01,0.0927850877193 2011-07-06 22:00:01,0.080655983976 2011-07-06 23:00:01,0.0737714285714 2011-07-07 00:00:01,0.0589785227868 2011-07-07 01:00:01,0.0518829376035 2011-07-07 02:00:01,0.0399152920196 2011-07-07 03:00:01,0.0365565345081 2011-07-07 04:00:01,0.0422852912142 2011-07-07 05:00:01,0.0599111111111 2011-07-07 06:00:01,0.06836 2011-07-07 07:00:01,0.0785412474849 2011-07-07 08:00:01,0.1369 2011-07-07 09:00:01,0.134372469636 2011-07-07 10:00:01,0.130298102981 2011-07-07 11:00:01,0.0940255591054 2011-07-07 12:00:01,0.0949642004773 2011-07-07 13:00:01,0.0797727272727 2011-07-07 14:00:01,0.0865840938722 2011-07-07 15:00:01,0.0828489795918 2011-07-07 16:00:01,0.0643440860215 2011-07-07 17:00:01,0.0631866776316 2011-07-07 18:00:01,0.0588312368973 2011-07-07 19:00:01,0.0553018372703 2011-07-07 20:00:01,0.0636177474403 2011-07-07 21:00:01,0.0696616541353 2011-07-07 22:00:01,0.0672093023256 2011-07-07 23:00:01,0.0647668393782 2011-07-08 00:00:01,0.0529286858974 2011-07-08 01:00:01,0.043 2011-07-08 02:00:01,0.0370847315436 2011-07-08 03:00:01,0.029056261343 2011-07-08 04:00:01,0.0390342793955 2011-07-08 05:00:01,0.0547750865052 2011-07-08 06:00:01,0.077652733119 2011-07-08 07:00:01,0.105649202733 2011-07-08 08:00:01,0.106728624535 2011-07-08 09:00:01,0.13031358885 2011-07-08 10:00:01,0.114 2011-07-08 11:00:01,0.0982986111111 2011-07-08 12:00:01,0.0896160558464 2011-07-08 13:00:01,0.082061482821 2011-07-08 14:00:01,0.0775255102041 2011-07-08 15:00:01,0.080700525394 2011-07-08 16:00:01,0.0630213706706 2011-07-08 17:00:01,0.0710957642726 2011-07-08 18:00:01,0.0692333019755 2011-07-08 19:00:01,0.0578288770053 2011-07-08 20:00:01,0.0509116607774 2011-07-08 21:00:01,0.0566599025974 2011-07-08 22:00:01,0.051887966805 2011-07-08 23:00:01,0.0498945703743 2011-07-09 00:00:01,0.05091367713 2011-07-09 01:00:01,0.0543451568895 2011-07-09 02:00:01,0.0465873959572 2011-07-09 03:00:01,0.0408384458078 2011-07-09 04:00:01,0.0569039323046 2011-07-09 05:00:01,0.065549898167 2011-07-09 06:00:01,0.0830152671756 2011-07-09 07:00:01,0.103198924731 2011-07-09 08:00:01,0.137385398981 2011-07-09 09:00:01,0.124793187348 2011-07-09 10:00:01,0.108936170213 2011-07-09 11:00:01,0.110889423077 2011-07-09 12:00:01,0.102679180887 2011-07-09 13:00:01,0.0846708860759 2011-07-09 14:00:01,0.074122983871 2011-07-09 15:00:01,0.0688360175695 2011-07-09 16:00:01,0.0609321533923 2011-07-09 17:00:01,0.0511821086262 2011-07-09 18:00:01,0.0732703213611 2011-07-09 19:00:01,0.0747021445592 2011-07-09 20:00:01,0.0693601190476 2011-07-09 21:00:01,0.069770879527 2011-07-09 22:00:01,0.0528718226068 2011-07-09 23:00:01,0.0605546403075 2011-07-10 00:00:01,0.0679034582133 2011-07-10 01:00:01,0.0553818443804 2011-07-10 02:00:01,0.0410645339217 2011-07-10 03:00:01,0.03905 2011-07-10 04:00:01,0.0452134831461 2011-07-10 05:00:01,0.0568603465851 2011-07-10 06:00:01,0.0712981199642 2011-07-10 07:00:01,0.088981042654 2011-07-10 08:00:01,0.14926335175 2011-07-10 09:00:01,0.12248 2011-07-10 10:00:01,0.116993318486 2011-07-10 11:00:01,0.111520342612 2011-07-10 12:00:01,0.100423728814 2011-07-10 13:00:01,0.0807338129496 2011-07-10 14:00:01,0.0885483870968 2011-07-10 15:00:01,0.0845520833333 2011-07-10 16:00:01,0.0803118503119 2011-07-10 17:00:01,0.0752053063803 2011-07-10 18:00:01,0.0604114134041 2011-07-10 19:00:01,0.0611792138574 2011-07-10 20:00:01,0.0581619758759 2011-07-10 21:00:01,0.0557387444515 2011-07-10 22:00:01,0.0557292271935 2011-07-10 23:00:01,0.0554871794872 2011-07-11 00:00:01,0.0435956467141 2011-07-11 01:00:01,0.0410140708394 2011-07-11 02:00:01,0.0390708661417 2011-07-11 03:00:01,0.0484085051546 2011-07-11 04:00:01,0.0548306233062 2011-07-11 05:00:01,0.0798846787479 2011-07-11 06:00:01,0.0904545454545 2011-07-11 07:00:01,0.109911504425 2011-07-11 08:00:01,0.14953125 2011-07-11 09:00:01,0.128966789668 2011-07-11 10:00:01,0.120981132075 2011-07-11 11:00:01,0.10642599278 2011-07-11 12:00:01,0.0980687830688 2011-07-11 13:00:01,0.0895955882353 2011-07-11 14:00:01,0.0831072555205 2011-07-11 15:00:01,0.0761529933481 2011-07-11 16:00:01,0.0695591836735 2011-07-11 17:00:01,0.0800690184049 2011-07-11 18:00:01,0.0713066871637 2011-07-11 19:00:01,0.0689016172507 2011-07-11 20:00:01,0.0657076101469 2011-07-11 21:00:01,0.0488832772166 2011-07-11 22:00:01,0.0446334716459 2011-07-11 23:00:01,0.0437057808456 2011-07-12 00:00:01,0.0405548387097 2011-07-12 01:00:01,0.0395984286338 2011-07-12 02:00:01,0.0376497277677 2011-07-12 03:00:01,0.0273855730502 2011-07-12 04:00:01,0.0399748638458 2011-07-12 05:00:01,0.0512578222778 2011-07-12 06:00:01,0.0768638392857 2011-07-12 07:00:01,0.0844540229885 2011-07-12 08:00:01,0.134916317992 2011-07-12 09:00:01,0.130771812081 2011-07-12 10:00:01,0.122636363636 2011-07-12 11:00:01,0.116319218241 2011-07-12 12:00:01,0.113074935401 2011-07-12 13:00:01,0.0957581227437 2011-07-12 14:00:01,0.0948387096774 2011-07-12 15:00:01,0.0883890954151 2011-07-12 16:00:01,0.0805347091932 2011-07-12 17:00:01,0.0838054474708 2011-07-12 18:00:01,0.0699471598415 2011-07-12 19:00:01,0.0719724437999 2011-07-12 20:00:01,0.0716866359447 2011-07-12 21:00:01,0.0751682134571 2011-07-12 22:00:01,0.0701829697396 2011-07-12 23:00:01,0.0624853458382 2011-07-13 00:00:01,0.0591021967526 2011-07-13 01:00:01,0.0564490339773 2011-07-13 02:00:01,0.0495853829937 2011-07-13 03:00:01,0.0428013833992 2011-07-13 04:00:01,0.06172 2011-07-13 05:00:01,0.0787394957983 2011-07-13 06:00:01,0.104476190476 2011-07-13 07:00:01,0.137398843931 2011-07-13 08:00:01,0.173003095975 2011-07-13 09:00:01,0.160666666667 2011-07-13 10:00:01,0.140447761194 2011-07-13 11:00:01,0.14541322314 2011-07-13 12:00:01,0.105280665281 2011-07-13 13:00:01,0.109710144928 2011-07-13 14:00:01,0.119234234234 2011-07-13 15:00:01,0.109706521739 2011-07-13 16:00:01,0.1125 2011-07-13 17:00:01,0.0806234203875 2011-07-13 18:00:01,0.0751756954612 2011-07-13 19:00:01,0.0643361473523 2011-07-13 20:00:01,0.0632748143147 2011-07-13 21:00:01,0.0527571669477 2011-07-13 22:00:01,0.0587525562372 2011-07-13 23:00:01,0.0675053153792 2011-07-14 00:00:01,0.0630647709321 2011-07-14 01:00:01,0.0542712671029 2011-07-14 02:00:01,0.0454437869822 2011-07-14 03:00:01,0.0427843915344 2011-07-14 04:00:01,0.0754888039323 2011-07-14 05:00:01,0.12162962963 2011-07-14 06:00:01,0.104147465438 2011-07-14 07:00:01,0.11685300207 2011-07-14 08:00:01,0.163841463415 2011-07-14 09:00:01,0.134169491525 2011-07-14 10:00:01,0.119638554217 2011-07-14 11:00:01,0.105258215962 2011-07-14 12:00:01,0.139400428266 2011-07-14 13:00:01,0.172899728997 2011-07-14 14:00:01,0.143414285714 2011-07-14 15:00:01,0.113112980769 2011-07-14 16:00:01,0.102432082794 2011-07-14 17:00:01,0.0945905420992 2011-07-14 18:00:01,0.0876892109501 2011-07-14 19:00:01,0.0769917743831 2011-07-14 20:00:01,0.0660641579272 2011-07-14 21:00:01,0.0686515748031 2011-07-14 22:00:01,0.0630867518494 2011-07-14 23:00:01,0.0668716289105 2011-07-15 00:00:01,0.066568 2011-07-15 01:00:01,0.064297188755 2011-07-15 02:00:01,0.0545993031359 2011-07-15 03:00:01,0.0488020833333 2011-07-15 04:00:01,0.0657415254237 2011-07-15 05:00:01,0.0831349628055 2011-07-15 06:00:01,0.0972619047619 2011-07-15 07:00:01,0.128293650794 2011-07-15 08:00:01,0.142421052632 2011-07-15 09:00:01,0.143630573248 2011-07-15 10:00:01,0.107873754153 2011-07-15 11:00:01,0.128459119497 2011-07-15 12:00:01,0.153944954128 2011-07-15 13:00:01,0.121011904762 2011-07-15 14:00:01,0.122206349206 2011-07-15 15:00:01,0.119244114002 2011-07-15 16:00:01,0.125719257541 2011-07-15 17:00:01,0.105527472527 2011-07-15 18:00:01,0.107925531915 2011-07-15 19:00:01,0.101285140562 2011-07-15 20:00:01,0.0782247557003 2011-07-15 21:00:01,0.0794422535211 2011-07-15 22:00:01,0.0666718386346 2011-07-15 23:00:01,0.0679684763573 2011-07-16 00:00:01,0.0628316953317 2011-07-16 01:00:01,0.0576279974076 2011-07-16 02:00:01,0.0515857226448 2011-07-16 03:00:01,0.0459335873707 2011-07-16 04:00:01,0.0593970893971 2011-07-16 05:00:01,0.0690847322142 2011-07-16 06:00:01,0.0845133819951 2011-07-16 07:00:01,0.128930987821 2011-07-16 08:00:01,0.133377777778 2011-07-16 09:00:01,0.133666666667 2011-07-16 10:00:01,0.110243902439 2011-07-16 11:00:01,0.124468085106 2011-07-16 12:00:01,0.129587426326 2011-07-16 13:00:01,0.116791277259 2011-07-16 14:00:01,0.131853658537 2011-07-16 15:00:01,0.12354799514 2011-07-16 16:00:01,0.106280991736 2011-07-16 17:00:01,0.0875408163265 2011-07-16 18:00:01,0.0848959032908 2011-07-16 19:00:01,0.0850235849057 2011-07-16 20:00:01,0.088818263205 2011-07-16 21:00:01,0.0806446140797 2011-07-16 22:00:01,0.0916818181818 2011-07-16 23:00:01,0.0951011433597 2011-07-17 00:00:01,0.0823130608175 2011-07-17 01:00:01,0.0839484126984 2011-07-17 02:00:01,0.0714049586777 2011-07-17 03:00:01,0.0668453865337 2011-07-17 04:00:01,0.089832149774 2011-07-17 05:00:01,0.0864338235294 2011-07-17 06:00:01,0.0963191763192 2011-07-17 07:00:01,0.133951219512 2011-07-17 08:00:01,0.129698113208 2011-07-17 09:00:01,0.113882352941 2011-07-17 10:00:01,0.103264033264 2011-07-17 11:00:01,0.123671232877 2011-07-17 12:00:01,0.118403361345 2011-07-17 13:00:01,0.120855263158 2011-07-17 14:00:01,0.128103932584 2011-07-17 15:00:01,0.123614864865 2011-07-17 16:00:01,0.103994169096 2011-07-17 17:00:01,0.0921825023518 2011-07-17 18:00:01,0.0784539007092 2011-07-17 19:00:01,0.0691608391608 2011-07-17 20:00:01,0.0860685033507 2011-07-17 21:00:01,0.0812937347437 2011-07-17 22:00:01,0.0766594360087 2011-07-17 23:00:01,0.0688845553822 2011-07-18 00:00:01,0.0831017369727 2011-07-18 01:00:01,0.0562208915502 2011-07-18 02:00:01,0.0542358688067 2011-07-18 03:00:01,0.0529631794272 2011-07-18 04:00:01,0.057367657723 2011-07-18 05:00:01,0.080813810111 2011-07-18 06:00:01,0.0828771384137 2011-07-18 07:00:01,0.098482428115 2011-07-18 08:00:01,0.133706720978 2011-07-18 09:00:01,0.125448504983 2011-07-18 10:00:01,0.112797202797 2011-07-18 11:00:01,0.133260869565 2011-07-18 12:00:01,0.114242424242 2011-07-18 13:00:01,0.109731958763 2011-07-18 14:00:01,0.110627118644 2011-07-18 15:00:01,0.13235915493 2011-07-18 16:00:01,0.108308004053 2011-07-18 17:00:01,0.112766934558 2011-07-18 18:00:01,0.0867071057192 2011-07-18 19:00:01,0.0666476624857 2011-07-18 20:00:01,0.0610063291139 2011-07-18 21:00:01,0.0633564814815 2011-07-18 22:00:01,0.0577608297743 2011-07-18 23:00:01,0.0592826221398 2011-07-19 00:00:01,0.058606557377 2011-07-19 01:00:01,0.060243902439 2011-07-19 02:00:01,0.0581115202525 2011-07-19 03:00:01,0.0536248012719 2011-07-19 04:00:01,0.0759214285714 2011-07-19 05:00:01,0.0956813819578 2011-07-19 06:00:01,0.145669456067 2011-07-19 07:00:01,0.0781401273885 2011-07-19 08:00:01,0.126855670103 2011-07-19 09:00:01,0.13587628866 2011-07-19 10:00:01,0.123628691983 2011-07-19 11:00:01,0.11277992278 2011-07-19 12:00:01,0.108265306122 2011-07-19 13:00:01,0.101017964072 2011-07-19 14:00:01,0.119724310777 2011-07-19 15:00:01,0.105197740113 2011-07-19 16:00:01,0.104038997214 2011-07-19 17:00:01,0.0876279650437 2011-07-19 18:00:01,0.0786526122823 2011-07-19 19:00:01,0.0785493682733 2011-07-19 20:00:01,0.0720879940343 2011-07-19 21:00:01,0.069072079536 2011-07-19 22:00:01,0.0646453546454 2011-07-19 23:00:01,0.0581058328322 2011-07-20 00:00:01,0.0471131270011 2011-07-20 01:00:01,0.0470863683663 2011-07-20 02:00:01,0.0441111667501 2011-07-20 03:00:01,0.0398035363458 2011-07-20 04:00:01,0.0531552962298 2011-07-20 05:00:01,0.0831355181577 2011-07-20 06:00:01,0.0858263971463 2011-07-20 07:00:01,0.11486013986 2011-07-20 08:00:01,0.140924092409 2011-07-20 09:00:01,0.145905797101 2011-07-20 10:00:01,0.1198046875 2011-07-20 11:00:01,0.105261324042 2011-07-20 12:00:01,0.114985163205 2011-07-20 13:00:01,0.12178807947 2011-07-20 14:00:01,0.123 2011-07-20 15:00:01,0.101586666667 2011-07-20 16:00:01,0.105029069767 2011-07-20 17:00:01,0.0886812627291 2011-07-20 18:00:01,0.076380952381 2011-07-20 19:00:01,0.0720992028344 2011-07-20 20:00:01,0.0846785486951 2011-07-20 21:00:01,0.086369168357 2011-07-20 22:00:01,0.0858272208639 2011-07-20 23:00:01,0.0881660899654 2011-07-21 00:00:01,0.0725509670674 2011-07-21 01:00:01,0.0504150702427 2011-07-21 02:00:01,0.0539956092206 2011-07-21 03:00:01,0.0498293891029 2011-07-21 04:00:01,0.0638204456094 2011-07-21 06:00:01,0.0896588235294 2011-07-21 07:00:01,0.0983348017621 2011-07-21 08:00:01,0.156194690265 2011-07-21 09:00:01,0.113283018868 2011-07-21 10:00:01,0.121479289941 2011-07-21 11:00:01,0.117583333333 2011-07-21 12:00:01,0.1255754858 2011-07-21 13:00:01,0.125865237366 2011-07-21 14:00:01,0.129348230912 2011-07-21 15:00:01,0.122638190955 2011-07-21 16:00:01,0.102814070352 2011-07-21 17:00:01,0.08875 2011-07-21 18:00:01,0.0884564740307 2011-07-21 19:00:01,0.0861376146789 2011-07-21 20:00:01,0.0786027190332 2011-07-21 21:00:01,0.0796965317919 2011-07-21 22:00:01,0.0731962761831 2011-07-21 23:00:01,0.0628108465608 2011-07-22 00:00:01,0.057536 2011-07-22 01:00:01,0.0501960784314 2011-07-22 02:00:01,0.0441025641026 2011-07-22 03:00:01,0.0395596330275 2011-07-22 04:00:01,0.0612002152853 2011-07-22 05:00:01,0.0658501208703 2011-07-22 06:00:01,0.0704761904762 2011-07-22 07:00:01,0.0902773497689 2011-07-22 08:00:01,0.123726708075 2011-07-22 09:00:01,0.125622119816 2011-07-22 10:00:01,0.122831460674 2011-07-22 11:00:01,0.10141955836 2011-07-22 12:00:01,0.114628820961 2011-07-22 13:00:01,0.125454545455 2011-07-22 14:00:01,0.125721311475 2011-07-22 15:00:01,0.117919191919 2011-07-22 16:00:01,0.108773784355 2011-07-22 17:00:01,0.0938828202582 2011-07-22 18:00:01,0.0868648648649 2011-07-22 19:00:01,0.0619215686275 2011-07-22 20:00:01,0.0658013245033 2011-07-22 21:00:01,0.0715577275504 2011-07-22 22:00:01,0.071060197664 2011-07-22 23:00:01,0.0672566371681 2011-07-23 00:00:01,0.0576546530393 2011-07-23 01:00:01,0.0647784200385 2011-07-23 02:00:01,0.0429639309984 2011-07-23 03:00:01,0.0369493177388 2011-07-23 04:00:01,0.0667547633682 2011-07-23 05:00:01,0.0781133671743 2011-07-23 06:00:01,0.0569483101392 2011-07-23 07:00:01,0.087599469496 2011-07-23 08:00:01,0.128206521739 2011-07-23 09:00:01,0.123089770355 2011-07-23 10:00:01,0.110472222222 2011-07-23 11:00:01,0.118646616541 2011-07-23 12:00:01,0.124588477366 2011-07-23 13:00:01,0.117697478992 2011-07-23 14:00:01,0.125595984944 2011-07-23 15:00:01,0.112482690406 2011-07-23 16:00:01,0.0839690301548 2011-07-23 17:00:01,0.0694921583271 2011-07-23 18:00:01,0.0620277953253 2011-07-23 19:00:01,0.0605489260143 2011-07-23 20:00:01,0.0551867219917 2011-07-23 21:00:01,0.050596432553 2011-07-23 22:00:01,0.0578482513337 2011-07-23 23:00:01,0.0493202416918 2011-07-24 00:00:01,0.0517379958246 2011-07-24 01:00:01,0.0433963202387 2011-07-24 02:00:01,0.0352476572959 2011-07-24 03:00:01,0.029256302521 2011-07-24 04:00:01,0.0570788614092 2011-07-24 05:00:01,0.0647458628842 2011-07-24 06:00:01,0.0498529411765 2011-07-24 07:00:01,0.0787314017228 2011-07-24 08:00:01,0.106375464684 2011-07-24 09:00:01,0.10786 2011-07-24 10:00:01,0.111375358166 2011-07-24 11:00:01,0.108213166144 2011-07-24 12:00:01,0.104781144781 2011-07-24 13:00:01,0.102242424242 2011-07-24 14:00:01,0.136987087518 2011-07-24 15:00:01,0.107728571429 2011-07-24 16:00:01,0.081749837978 2011-07-24 17:00:01,0.0739983713355 2011-07-24 18:00:01,0.0703389830508 2011-07-24 19:00:01,0.0576832018038 2011-07-24 20:00:01,0.0548765432099 2011-07-24 21:00:01,0.0514774417452 2011-07-24 22:00:01,0.0539698492462 2011-07-24 23:00:01,0.0497205284553 2011-07-25 00:00:01,0.0473873873874 2011-07-25 01:00:01,0.0363285910968 2011-07-25 02:00:01,0.0298359310911 2011-07-25 03:00:01,0.0268430335097 2011-07-25 04:00:01,0.0470331753555 2011-07-25 05:00:01,0.0762164750958 2011-07-25 06:00:01,0.06735 2011-07-25 07:00:01,0.0817728055077 2011-07-25 08:00:01,0.135342465753 2011-07-25 09:00:01,0.10347107438 2011-07-25 10:00:01,0.104528301887 2011-07-25 11:00:01,0.110830188679 2011-07-25 12:00:01,0.114666666667 2011-07-25 13:00:01,0.115458715596 2011-07-25 14:00:01,0.119266409266 2011-07-25 15:00:01,0.122647058824 2011-07-25 16:00:01,0.106795366795 2011-07-25 17:00:01,0.0827593360996 2011-07-25 18:00:01,0.0724266144814 2011-07-25 19:00:01,0.0713251879699 2011-07-25 20:00:01,0.063962529274 2011-07-25 21:00:01,0.0686650185414 2011-07-25 22:00:01,0.0754482323232 2011-07-25 23:00:01,0.0718975705844 2011-07-26 00:00:01,0.0666692015209 2011-07-26 01:00:01,0.0498381877023 2011-07-26 02:00:01,0.0471448352257 2011-07-26 03:00:01,0.041893349311 2011-07-26 04:00:01,0.0506090863704 2011-07-26 05:00:01,0.0692014971928 2011-07-26 06:00:01,0.0692014971928 2011-07-26 07:00:01,0.0724771838331 2011-07-26 08:00:01,0.137659090909 2011-07-26 09:00:01,0.110408805031 2011-07-26 10:00:01,0.115993589744 2011-07-26 11:00:01,0.105376712329 2011-07-26 12:00:01,0.109313432836 2011-07-26 13:00:01,0.0955578512397 2011-07-26 14:00:01,0.115785498489 2011-07-26 15:00:01,0.109773869347 2011-07-26 16:00:01,0.0816580756014 2011-07-26 17:00:01,0.0825984911987 2011-07-26 18:00:01,0.0901673640167 2011-07-26 19:00:01,0.0776923076923 2011-07-26 20:00:01,0.0674664224664 2011-07-26 21:00:01,0.0651013941698 2011-07-26 22:00:01,0.0701068376068 2011-07-26 23:00:01,0.0780705543557 2011-07-27 00:00:01,0.0710584752036 2011-07-27 01:00:01,0.070609939759 2011-07-27 02:00:01,0.0600668449198 2011-07-27 03:00:01,0.0437102272727 2011-07-27 04:00:01,0.0566702470462 2011-07-27 05:00:01,0.10780075188 2011-07-27 06:00:01,0.07596 2011-07-27 07:00:01,0.0859259259259 2011-07-27 08:00:01,0.124216589862 2011-07-27 09:00:01,0.0986075949367 2011-07-27 10:00:01,0.11397260274 2011-07-27 11:00:01,0.118854625551 2011-07-27 12:00:01,0.110099800399 2011-07-27 13:00:01,0.114842657343 2011-07-27 14:00:01,0.120839260313 2011-07-27 15:00:01,0.11123880597 2011-07-27 16:00:01,0.10975257732 2011-07-27 17:00:01,0.104363207547 2011-07-27 18:00:01,0.0920824881677 2011-07-27 19:00:01,0.087886563133 2011-07-27 20:00:01,0.0919845360825 2011-07-27 21:00:01,0.0936326737697 2011-07-27 22:00:01,0.104090189873 2011-07-27 23:00:01,0.0873058082575 2011-07-28 00:00:01,0.078776328987 2011-07-28 01:00:01,0.0860120391272 2011-07-28 02:00:01,0.074702467344 2011-07-28 03:00:01,0.070370096225 2011-07-28 04:00:01,0.0783658787256 2011-07-28 05:00:01,0.110487421384 2011-07-28 06:00:01,0.0803856041131 2011-07-28 07:00:01,0.0619230769231 2011-07-28 08:00:01,0.1198 2011-07-28 09:00:01,0.113601398601 2011-07-28 10:00:01,0.124456824513 2011-07-28 11:00:01,0.107990074442 2011-07-28 12:00:01,0.10199488491 2011-07-28 13:00:01,0.104290780142 2011-07-28 14:00:01,0.119104234528 2011-07-28 15:00:01,0.118211206897 2011-07-28 16:00:01,0.118211206897 2011-07-28 17:00:01,0.118211206897 2011-07-28 18:00:01,0.0885949110561 2011-07-28 19:00:01,0.0801347449471 2011-07-28 20:00:01,0.0899249374479 2011-07-28 21:00:01,0.0973896499239 2011-07-28 22:00:01,0.0805698005698 2011-07-28 23:00:01,0.073049074819 2011-07-29 00:00:01,0.0734753857458 2011-07-29 01:00:01,0.0722496749025 2011-07-29 02:00:01,0.0732498394348 2011-07-29 03:00:01,0.0676326129666 2011-07-29 04:00:01,0.0724244415243 2011-07-29 05:00:01,0.0896695821186 2011-07-29 06:00:01,0.0784363636364 2011-07-29 07:00:01,0.096213740458 2011-07-29 08:00:01,0.156112311015 2011-07-29 09:00:01,0.11890052356 2011-07-29 10:00:01,0.132742857143 2011-07-29 11:00:01,0.114931880109 2011-07-29 12:00:01,0.128949880668 2011-07-29 13:00:01,0.122662807525 2011-07-29 14:00:01,0.117895953757 2011-07-29 15:00:01,0.113000987167 2011-07-29 16:00:01,0.0856885245902 2011-07-29 17:00:01,0.0841629711752 2011-07-29 18:00:01,0.0767937701396 2011-07-29 19:00:01,0.0789443005181 2011-07-29 20:00:01,0.0845344129555 2011-07-29 21:00:01,0.0913032031593 2011-07-29 22:00:01,0.0925146689019 2011-07-29 23:00:01,0.101165644172 2011-07-30 00:00:01,0.0886551155116 2011-07-30 01:00:01,0.0797572435395 2011-07-30 02:00:01,0.0728994544037 2011-07-30 03:00:01,0.0740775780511 2011-07-30 04:00:01,0.0722648238966 2011-07-30 05:00:01,0.0683806818182 2011-07-30 06:00:01,0.0948214285714 2011-07-30 07:00:01,0.0938634046891 2011-07-30 08:00:01,0.130261437908 2011-07-30 09:00:01,0.111311827957 2011-07-30 10:00:01,0.0984196891192 2011-07-30 11:00:01,0.116709265176 2011-07-30 12:00:01,0.113532818533 2011-07-30 13:00:01,0.125555555556 2011-07-30 14:00:01,0.115386533666 2011-07-30 15:00:01,0.1102342918 2011-07-30 16:00:01,0.0929906542056 2011-07-30 17:00:01,0.0869395348837 2011-07-30 18:00:01,0.0907490864799 2011-07-30 19:00:01,0.0838778311599 2011-07-30 20:00:01,0.0804285714286 2011-07-30 21:00:01,0.0788680555556 2011-07-30 22:00:01,0.0821278089888 2011-07-30 23:00:01,0.0842050520059 2011-07-31 00:00:01,0.080601387818 2011-07-31 01:00:01,0.0680497925311 2011-07-31 02:00:01,0.0631529726119 2011-07-31 03:00:01,0.0551472556894 2011-07-31 04:00:01,0.0601333333333 2011-07-31 05:00:01,0.0610477941176 2011-07-31 06:00:01,0.0709155429383 2011-07-31 07:00:01,0.083761682243 2011-07-31 08:00:01,0.12181663837 2011-07-31 09:00:01,0.118093841642 2011-07-31 10:00:01,0.0936153846154 2011-07-31 11:00:01,0.0994202898551 2011-07-31 12:00:01,0.0964052287582 2011-07-31 13:00:01,0.100709459459 2011-07-31 14:00:01,0.115931034483 2011-07-31 15:00:01,0.105705329154 2011-07-31 16:00:01,0.103412969283 2011-07-31 17:00:01,0.0962058823529 2011-07-31 18:00:01,0.0869072948328 2011-07-31 19:00:01,0.0886683209264 2011-07-31 20:00:01,0.0852365930599 2011-07-31 21:00:01,0.0830542986425 2011-07-31 22:00:01,0.0863148788927 2011-07-31 23:00:01,0.0808888888889 2011-08-01 00:00:01,0.0844655929722 2011-08-01 01:00:01,0.0788088235294 2011-08-01 02:00:01,0.0846559633028 2011-08-01 03:00:01,0.0568824940048 2011-08-01 04:00:01,0.0727328714396 2011-08-01 05:00:01,0.0826939471441 2011-08-01 06:00:01,0.084090382387 2011-08-01 07:00:01,0.0908172362556 2011-08-01 08:00:01,0.135628865979 2011-08-01 09:00:01,0.125981308411 2011-08-01 10:00:01,0.121021505376 2011-08-01 11:00:01,0.127050147493 2011-08-01 12:00:01,0.105648854962 2011-08-01 13:00:01,0.111731748727 2011-08-01 14:00:01,0.11498392283 2011-08-01 15:00:01,0.112511415525 2011-08-01 16:00:01,0.0994946808511 2011-08-01 17:00:01,0.106244665718 2011-08-01 18:00:01,0.0854833424358 2011-08-01 19:00:01,0.0872797427653 2011-08-01 20:00:01,0.0819312169312 2011-08-01 21:00:01,0.0881 2011-08-01 22:00:01,0.0955753337572 2011-08-01 23:00:01,0.0987902592302 2011-08-02 00:00:01,0.0889931350114 2011-08-02 01:00:01,0.084732061762 2011-08-02 02:00:01,0.0879424920128 2011-08-02 03:00:01,0.0664155251142 2011-08-02 04:00:01,0.0831809145129 2011-08-02 05:00:01,0.0926953125 2011-08-02 06:00:01,0.0890781796966 2011-08-02 07:00:01,0.116447166922 2011-08-02 08:00:01,0.150505050505 2011-08-02 09:00:01,0.120997442455 2011-08-02 10:00:01,0.12171641791 2011-08-02 11:00:01,0.13024691358 2011-08-02 12:00:01,0.12217032967 2011-08-02 13:00:01,0.120845070423 2011-08-02 14:00:01,0.137652671756 2011-08-02 15:00:01,0.124419354839 2011-08-02 16:00:01,0.119978448276 2011-08-02 17:00:01,0.102033898305 2011-08-02 18:00:01,0.0973706896552 2011-08-02 19:00:01,0.0990192791282 2011-08-02 20:00:01,0.104033546326 2011-08-02 21:00:01,0.103341483293 2011-08-02 22:00:01,0.104043126685 2011-08-02 23:00:01,0.0923657817109 2011-08-03 00:00:01,0.0908755364807 2011-08-03 01:00:01,0.0832804614275 2011-08-03 02:00:01,0.0718162983425 2011-08-03 03:00:01,0.0641237113402 2011-08-03 04:00:01,0.0730695970696 2011-08-03 05:00:01,0.0877640203933 2011-08-03 06:00:01,0.0793930348259 2011-08-03 07:00:01,0.113240310078 2011-08-03 08:00:01,0.135289079229 2011-08-03 09:00:01,0.140438596491 2011-08-03 10:00:01,0.132291262136 2011-08-03 11:00:01,0.0986138613861 2011-08-03 12:00:01,0.107055702918 2011-08-03 13:00:01,0.122393320965 2011-08-03 14:00:01,0.118733974359 2011-08-03 15:00:01,0.131208333333 2011-08-03 16:00:01,0.120161137441 2011-08-03 17:00:01,0.102637465051 2011-08-03 18:00:01,0.0927382875606 2011-08-03 19:00:01,0.110486641221 2011-08-03 20:00:01,0.0917786561265 2011-08-03 21:00:01,0.0896810631229 2011-08-03 22:00:01,0.0854006586169 2011-08-03 23:00:01,0.0681545998911 2011-08-04 00:00:01,0.0555156537753 2011-08-04 01:00:01,0.0530039700044 2011-08-04 02:00:01,0.0474216027875 2011-08-04 03:00:01,0.0435638051044 2011-08-04 04:00:01,0.0628515815085 2011-08-04 05:00:01,0.0907293354943 2011-08-04 06:00:01,0.079404641776 2011-08-04 07:00:01,0.124388254486 2011-08-04 08:00:01,0.192708333333 2011-08-04 09:00:01,0.155310880829 2011-08-04 10:00:01,0.11597826087 2011-08-04 11:00:01,0.122092307692 2011-08-04 12:00:01,0.118666666667 2011-08-04 13:00:01,0.114611398964 2011-08-04 14:00:01,0.11694980695 2011-08-04 15:00:01,0.111554663992 2011-08-04 16:00:01,0.117184466019 2011-08-04 17:00:01,0.107725080386 2011-08-04 18:00:01,0.0907093292213 2011-08-04 19:00:01,0.0940831074977 2011-08-04 20:00:01,0.0903178991016 2011-08-04 21:00:01,0.0942023346304 2011-08-04 22:00:01,0.0980128548473 2011-08-04 23:00:01,0.0961186903138 2011-08-05 00:00:01,0.083626707132 2011-08-05 01:00:01,0.0662049335863 2011-08-05 02:00:01,0.0627621483376 2011-08-05 03:00:01,0.0654652071931 2011-08-05 04:00:01,0.0682556591212 2011-08-05 05:00:01,0.108736462094 2011-08-05 06:00:01,0.0956589147287 2011-08-05 07:00:01,0.121594684385 2011-08-05 08:00:01,0.169946808511 2011-08-05 09:00:01,0.138291925466 2011-08-05 10:00:01,0.122438162544 2011-08-05 11:00:01,0.124915730337 2011-08-05 12:00:01,0.103655172414 2011-08-05 13:00:01,0.120434782609 2011-08-05 14:00:01,0.127615384615 2011-08-05 15:00:01,0.116647398844 2011-08-05 16:00:01,0.119007470651 2011-08-05 17:00:01,0.123242753623 2011-08-05 18:00:01,0.10378812199 2011-08-05 19:00:01,0.103911671924 2011-08-05 20:00:01,0.1031834404 2011-08-05 21:00:01,0.0813955342903 2011-08-05 22:00:01,0.0997409326425 2011-08-05 23:00:01,0.0937476808905 2011-08-06 00:00:01,0.0944382022472 2011-08-06 01:00:01,0.0806839452844 2011-08-06 02:00:01,0.0811759868421 2011-08-06 03:00:01,0.079875 2011-08-06 04:00:01,0.101463607595 2011-08-06 05:00:01,0.0946192528736 2011-08-06 06:00:01,0.103779385172 2011-08-06 07:00:01,0.131770833333 2011-08-06 08:00:01,0.164243902439 2011-08-06 09:00:01,0.114065420561 2011-08-06 10:00:01,0.097802690583 2011-08-06 11:00:01,0.118575418994 2011-08-06 12:00:01,0.144545454545 2011-08-06 13:00:01,0.115585106383 2011-08-06 14:00:01,0.138979865772 2011-08-06 15:00:01,0.117599277978 2011-08-06 16:00:01,0.127989556136 2011-08-06 17:00:01,0.11869047619 2011-08-06 18:00:01,0.112857142857 2011-08-06 19:00:01,0.104221105528 2011-08-06 20:00:01,0.110081300813 2011-08-06 21:00:01,0.109489795918 2011-08-06 22:00:01,0.132456320658 2011-08-06 23:00:01,0.112317198764 2011-08-07 00:00:01,0.0978862793572 2011-08-07 01:00:01,0.0939727126806 2011-08-07 02:00:01,0.0917095777549 2011-08-07 03:00:01,0.08609375 2011-08-07 04:00:01,0.0917391304348 2011-08-07 05:00:01,0.0846818181818 2011-08-07 06:00:01,0.0921988950276 2011-08-07 07:00:01,0.137547169811 2011-08-07 08:00:01,0.194764957265 2011-08-07 09:00:01,0.137314578005 2011-08-07 10:00:01,0.123309178744 2011-08-07 11:00:01,0.101875 2011-08-07 12:00:01,0.113897810219 2011-08-07 13:00:01,0.123737541528 2011-08-07 14:00:01,0.125498533724 2011-08-07 15:00:01,0.124308390023 2011-08-07 16:00:01,0.107933014354 2011-08-07 17:00:01,0.114069050555 2011-08-07 18:00:01,0.114200260078 2011-08-07 19:00:01,0.115863921218 2011-08-07 20:00:01,0.132262016965 2011-08-07 21:00:01,0.0852321428571 2011-08-07 22:00:01,0.085404040404 2011-08-07 23:00:01,0.0957723577236 2011-08-08 00:00:01,0.0809021406728 2011-08-08 01:00:01,0.0813665086888 2011-08-08 02:00:01,0.0686845549738 2011-08-08 03:00:01,0.06375 2011-08-08 04:00:01,0.0718086419753 2011-08-08 05:00:01,0.0990780141844 2011-08-08 06:00:01,0.101891891892 2011-08-08 07:00:01,0.131940594059 2011-08-08 08:00:01,0.198534031414 2011-08-08 09:00:01,0.131197411003 2011-08-08 10:00:01,0.135933333333 2011-08-08 11:00:01,0.137407407407 2011-08-08 12:00:01,0.135081081081 2011-08-08 13:00:01,0.127449799197 2011-08-08 14:00:01,0.134806547619 2011-08-08 15:00:01,0.146736292428 2011-08-08 16:00:01,0.140640732265 2011-08-08 17:00:01,0.124901639344 2011-08-08 19:00:01,0.107754940711 2011-08-08 20:00:01,0.0973099801718 2011-08-08 21:00:01,0.105857445307 2011-08-08 22:00:01,0.104513274336 2011-08-08 23:00:01,0.0998374558304 2011-08-09 00:00:01,0.0816804822909 2011-08-09 01:00:01,0.0678761061947 2011-08-09 02:00:01,0.0752766639936 2011-08-09 03:00:01,0.0670263591433 2011-08-09 04:00:01,0.079624920534 2011-08-09 05:00:01,0.088817264574 2011-08-09 06:00:01,0.0894524119948 2011-08-09 07:00:01,0.110949913644 2011-08-09 08:00:01,0.184171428571 2011-08-09 09:00:01,0.126060606061 2011-08-09 10:00:01,0.122429022082 2011-08-09 11:00:01,0.113667711599 2011-08-09 12:00:01,0.12118902439 2011-08-09 13:00:01,0.120177304965 2011-08-09 14:00:01,0.126299212598 2011-08-09 15:00:01,0.160228136882 2011-08-09 16:00:01,0.130101180438 2011-08-09 17:00:01,0.132857142857 2011-08-09 18:00:01,0.106023657871 2011-08-09 19:00:01,0.109564902103 2011-08-09 20:00:01,0.112048293089 2011-08-09 21:00:01,0.109079847909 2011-08-09 22:00:01,0.108366935484 2011-08-09 23:00:01,0.0944126738794 2011-08-10 00:00:01,0.0868382352941 2011-08-10 01:00:01,0.0871462264151 2011-08-10 02:00:01,0.0835324107793 2011-08-10 03:00:01,0.0797773654917 2011-08-10 04:00:01,0.0870853573907 2011-08-10 05:00:01,0.107430962343 2011-08-10 06:00:01,0.103407572383 2011-08-10 07:00:01,0.131053763441 2011-08-10 08:00:01,0.149262820513 2011-08-10 09:00:01,0.149195804196 2011-08-10 10:00:01,0.116387096774 2011-08-10 11:00:01,0.133109243697 2011-08-10 12:00:01,0.113486973948 2011-08-10 13:00:01,0.134677419355 2011-08-10 14:00:01,0.13365159129 2011-08-10 15:00:01,0.162853025937 2011-08-10 17:00:01,0.129087837838 2011-08-10 18:00:01,0.129151061174 2011-08-10 19:00:01,0.0959275452842 2011-08-10 20:00:01,0.120016652789 2011-08-10 21:00:01,0.139963099631 2011-08-10 22:00:01,0.1335 2011-08-10 23:00:01,0.11544 2011-08-11 00:00:01,0.0934608208955 2011-08-11 01:00:01,0.100648648649 2011-08-11 02:00:01,0.0751342281879 2011-08-11 03:00:01,0.0717509481669 2011-08-11 04:00:01,0.0848198198198 2011-08-11 05:00:01,0.0985912823752 2011-08-11 06:00:01,0.111722365039 2011-08-11 07:00:01,0.144885931559 2011-08-11 08:00:01,0.158951310861 2011-08-11 09:00:01,0.168668341709 2011-08-11 10:00:01,0.153682170543 2011-08-11 11:00:01,0.12256281407 2011-08-11 12:00:01,0.151400437637 2011-08-11 13:00:01,0.136942675159 2011-08-11 14:00:01,0.129286498353 2011-08-11 15:00:01,0.116570477248 2011-08-11 16:00:01,0.100236486486 2011-08-11 17:00:01,0.132017857143 2011-08-11 18:00:01,0.121481481481 2011-08-11 19:00:01,0.117148626817 2011-08-11 20:00:01,0.0993429158111 2011-08-11 21:00:01,0.0867046718576 2011-08-11 22:00:01,0.101101137044 2011-08-11 23:00:01,0.0985993485342 2011-08-12 00:00:01,0.0790524534687 2011-08-12 01:00:01,0.0890992767916 2011-08-12 02:00:01,0.0801247537754 2011-08-12 03:00:01,0.0816735112936 2011-08-12 04:00:01,0.108480420807 2011-08-12 05:00:01,0.123552123552 2011-08-12 06:00:01,0.123780864198 2011-08-12 07:00:01,0.154623955432 2011-08-12 08:00:01,0.218536121673 2011-08-12 09:00:01,0.174148148148 2011-08-12 10:00:01,0.139515151515 2011-08-12 11:00:01,0.144714714715 2011-08-12 12:00:01,0.130277777778 2011-08-12 13:00:01,0.164316831683 2011-08-12 14:00:01,0.146094364351 2011-08-12 15:00:01,0.15875491481 2011-08-12 16:00:01,0.137076271186 2011-08-12 17:00:01,0.117378723404 2011-08-12 18:00:01,0.112778702163 2011-08-12 19:00:01,0.140034423408 2011-08-12 20:00:01,0.127083333333 2011-08-12 21:00:01,0.103282647585 2011-08-12 22:00:01,0.0950205930807 2011-08-12 23:00:01,0.114839491217 2011-08-13 00:00:01,0.111620400258 2011-08-13 01:00:01,0.115210150674 2011-08-13 02:00:01,0.0884778292522 2011-08-13 03:00:01,0.0781188118812 2011-08-13 04:00:01,0.0926106770833 2011-08-13 05:00:01,0.105254452926 2011-08-13 06:00:01,0.147014084507 2011-08-13 07:00:01,0.184960526316 2011-08-13 08:00:01,0.200205338809 2011-08-13 09:00:01,0.16768707483 2011-08-13 10:00:01,0.143217158177 2011-08-13 11:00:01,0.128606965174 2011-08-13 12:00:01,0.176341463415 2011-08-13 13:00:01,0.190699844479 2011-08-13 14:00:01,0.207095490716 2011-08-13 15:00:01,0.170642303433 2011-08-13 16:00:01,0.166080956762 2011-08-13 17:00:01,0.140209339775 2011-08-13 18:00:01,0.121964285714 2011-08-13 19:00:01,0.121059288538 2011-08-13 20:00:01,0.111311258278 2011-08-13 21:00:01,0.105853485064 2011-08-13 22:00:01,0.0939015904573 2011-08-13 23:00:01,0.0974674220963 2011-08-14 00:00:01,0.103974603175 2011-08-14 01:00:01,0.100102880658 2011-08-14 02:00:01,0.0934496124031 2011-08-14 03:00:01,0.0931725768322 2011-08-14 04:00:01,0.101034282394 2011-08-14 05:00:01,0.123640988372 2011-08-14 06:00:01,0.168444444444 2011-08-14 07:00:01,0.191602465331 2011-08-14 08:00:01,0.177750556793 2011-08-14 09:00:01,0.13620596206 2011-08-14 10:00:01,0.131743486974 2011-08-14 11:00:01,0.1367003367 2011-08-14 12:00:01,0.135974499089 2011-08-14 13:00:01,0.153161875946 2011-08-14 14:00:01,0.176701183432 2011-08-14 15:00:01,0.149260739261 2011-08-14 16:00:01,0.140222793488 2011-08-14 17:00:01,0.123384879725 2011-08-14 18:00:01,0.113982056591 2011-08-14 19:00:01,0.102060857538 2011-08-14 20:00:01,0.0899290780142 2011-08-14 21:00:01,0.1030813618 2011-08-14 22:00:01,0.115312 2011-08-14 23:00:01,0.0971056439942 2011-08-15 00:00:01,0.0887619047619 2011-08-15 01:00:01,0.0767574059247 2011-08-15 02:00:01,0.0635458409229 2011-08-15 03:00:01,0.0615452688904 2011-08-15 04:00:01,0.0844965034965 2011-08-15 05:00:01,0.125080416272 2011-08-15 06:00:01,0.152823529412 2011-08-15 07:00:01,0.160897435897 2011-08-15 08:00:01,0.208504464286 2011-08-15 09:00:01,0.159442622951 2011-08-15 10:00:01,0.126083333333 2011-08-15 11:00:01,0.147287066246 2011-08-15 12:00:01,0.13907275321 2011-08-15 13:00:01,0.152277580071 2011-08-15 14:00:01,0.175957820738 2011-08-15 15:00:01,0.172835595777 2011-08-15 16:00:01,0.15900990099 2011-08-15 17:00:01,0.145223880597 2011-08-15 18:00:01,0.149354518371 2011-08-15 19:00:01,0.131401693321 2011-08-15 20:00:01,0.124854288093 2011-08-15 21:00:01,0.120876451954 2011-08-16 00:00:01,0.112879852126 2011-08-16 01:00:01,0.0948547717842 2011-08-16 02:00:01,0.07600505689 2011-08-16 03:00:01,0.0601774785802 2011-08-16 04:00:01,0.0721493506494 2011-08-16 05:00:01,0.109337016575 2011-08-16 06:00:01,0.12738045738 2011-08-16 07:00:01,0.180516795866 2011-08-16 08:00:01,0.175753424658 2011-08-16 09:00:01,0.144705882353 2011-08-16 10:00:01,0.139488054608 2011-08-16 11:00:01,0.156717325228 2011-08-16 12:00:01,0.156968911917 2011-08-16 13:00:01,0.173802281369 2011-08-16 14:00:01,0.195833333333 2011-08-16 15:00:01,0.159928315412 2011-08-16 16:00:01,0.156680555556 2011-08-16 17:00:01,0.130603732162 2011-08-16 18:00:01,0.120630541872 2011-08-16 19:00:01,0.117578194817 2011-08-16 20:00:01,0.100228855721 2011-08-16 21:00:01,0.110859774821 2011-08-16 22:00:01,0.100555972953 2011-08-16 23:00:01,0.0928300609343 2011-08-17 00:00:01,0.0887169312169 2011-08-17 01:00:01,0.0751711026616 2011-08-17 02:00:01,0.0671932299013 2011-08-17 03:00:01,0.0569876453488 2011-08-17 04:00:01,0.0739644970414 2011-08-17 05:00:01,0.0940488656195 2011-08-17 06:00:01,0.0884420289855 2011-08-17 07:00:01,0.119948275862 2011-08-17 08:00:01,0.135165394402 2011-08-17 09:00:01,0.128560411311 2011-08-17 10:00:01,0.12003236246 2011-08-17 11:00:01,0.116625 2011-08-17 12:00:01,0.115021276596 2011-08-17 13:00:01,0.124337152209 2011-08-17 14:00:01,0.110400972053 2011-08-17 15:00:01,0.148208409506 2011-08-17 16:00:01,0.146277890467 2011-08-17 17:00:01,0.110632911392 2011-08-17 18:00:01,0.129878721058 2011-08-17 19:00:01,0.107172489083 2011-08-17 20:00:01,0.109739130435 2011-08-17 21:00:01,0.102514619883 2011-08-17 22:00:01,0.0949129852744 2011-08-17 23:00:01,0.0821228615863 2011-08-18 00:00:01,0.0739106901218 2011-08-18 01:00:01,0.0707963246554 2011-08-18 02:00:01,0.0606611570248 2011-08-18 03:00:01,0.0442401392111 2011-08-18 04:00:01,0.0616063675832 2011-08-18 05:00:01,0.0953426248548 2011-08-18 06:00:01,0.0802471169687 2011-08-18 07:00:01,0.139586563307 2011-08-18 08:00:01,0.172919463087 2011-08-18 09:00:01,0.145015772871 2011-08-18 10:00:01,0.152935153584 2011-08-18 11:00:01,0.126653846154 2011-08-18 12:00:01,0.134631578947 2011-08-18 13:00:01,0.139772296015 2011-08-18 14:00:01,0.156115384615 2011-08-18 15:00:01,0.161610429448 2011-08-18 16:00:01,0.142340136054 2011-08-18 17:00:01,0.124217758985 2011-08-18 18:00:01,0.112732502397 2011-08-18 19:00:01,0.109907407407 2011-08-18 20:00:01,0.103028301887 2011-08-18 21:00:01,0.108101265823 2011-08-18 22:00:01,0.109340101523 2011-08-18 23:00:01,0.0928143133462 2011-08-19 00:00:01,0.0860546875 2011-08-19 01:00:01,0.0710621468927 2011-08-19 02:00:01,0.0732460447354 2011-08-19 03:00:01,0.0536189747513 2011-08-19 04:00:01,0.0822508038585 2011-08-19 05:00:01,0.094796030871 2011-08-19 06:00:01,0.0969190140845 2011-08-19 07:00:01,0.144830699774 2011-08-19 08:00:01,0.174155844156 2011-08-19 09:00:01,0.151114369501 2011-08-19 10:00:01,0.152806324111 2011-08-19 11:00:01,0.146851311953 2011-08-19 12:00:01,0.16219858156 2011-08-19 13:00:01,0.18921875 2011-08-19 14:00:01,0.157520242915 2011-08-19 15:00:01,0.158472584856 2011-08-19 16:00:01,0.13572815534 2011-08-19 17:00:01,0.101354420114 2011-08-19 18:00:01,0.10043381535 2011-08-19 19:00:01,0.113808016878 2011-08-19 20:00:01,0.104941176471 2011-08-19 21:00:01,0.0976577840112 2011-08-19 22:00:01,0.101288951841 2011-08-19 23:00:01,0.0807769145394 2011-08-20 00:00:01,0.0770080321285 2011-08-20 01:00:01,0.0724773834377 2011-08-20 02:00:01,0.0632070707071 2011-08-20 03:00:01,0.0492577224527 2011-08-20 04:00:01,0.0694444444444 2011-08-20 05:00:01,0.111746183206 2011-08-20 06:00:01,0.0953485064011 2011-08-20 07:00:01,0.13880866426 2011-08-20 08:00:01,0.158722891566 2011-08-20 09:00:01,0.142033333333 2011-08-20 10:00:01,0.118189415042 2011-08-20 11:00:01,0.123484848485 2011-08-20 12:00:01,0.155338983051 2011-08-20 13:00:01,0.171588132635 2011-08-20 14:00:01,0.154665757162 2011-08-20 15:00:01,0.144744897959 2011-08-20 16:00:01,0.142985409652 2011-08-20 17:00:01,0.101298157454 2011-08-20 18:00:01,0.0898817567568 2011-08-20 19:00:01,0.0887995198079 2011-08-20 20:00:01,0.0915183946488 2011-08-20 21:00:01,0.088203125 2011-08-20 22:00:01,0.0940313111546 2011-08-20 23:00:01,0.0947100802855 2011-08-21 00:00:01,0.0783 2011-08-21 01:00:01,0.0807470049331 2011-08-21 02:00:01,0.0641913439636 2011-08-21 03:00:01,0.0538818565401 2011-08-21 04:00:01,0.0753577106518 2011-08-21 05:00:01,0.115963203463 2011-08-21 06:00:01,0.0939847715736 2011-08-21 07:00:01,0.137370242215 2011-08-21 08:00:01,0.171899109792 2011-08-21 09:00:01,0.134024640657 2011-08-21 10:00:01,0.116201780415 2011-08-21 11:00:01,0.111481481481 2011-08-21 12:00:01,0.121878172589 2011-08-21 13:00:01,0.121111111111 2011-08-21 14:00:01,0.127411067194 2011-08-21 15:00:01,0.129568014706 2011-08-21 16:00:01,0.113125 2011-08-21 17:00:01,0.091846419327 2011-08-21 18:00:01,0.083811023622 2011-08-21 19:00:01,0.0901892744479 2011-08-21 20:00:01,0.0848633440514 2011-08-21 21:00:01,0.0827652733119 2011-08-21 22:00:01,0.0729182295574 2011-08-21 23:00:01,0.0687188019967 2011-08-22 00:00:01,0.0652910512598 2011-08-22 01:00:01,0.0597656744775 2011-08-22 02:00:01,0.0489229720518 2011-08-22 03:00:01,0.0477128782548 2011-08-22 04:00:01,0.0638228438228 2011-08-22 05:00:01,0.103051702396 2011-08-22 06:00:01,0.0895652173913 2011-08-22 07:00:01,0.124128440367 2011-08-22 08:00:01,0.215017421603 2011-08-22 09:00:01,0.154131274131 2011-08-22 10:00:01,0.151511111111 2011-08-22 11:00:01,0.129569230769 2011-08-22 12:00:01,0.137255369928 2011-08-22 13:00:01,0.141398305085 2011-08-22 14:00:01,0.127036395147 2011-08-22 15:00:01,0.144790528233 2011-08-22 16:00:01,0.117414880202 2011-08-22 17:00:01,0.118756157635 2011-08-22 18:00:01,0.119006309148 2011-08-22 19:00:01,0.113553859203 2011-08-22 20:00:01,0.0979017857143 2011-08-22 21:00:01,0.10843902439 2011-08-22 22:00:01,0.0995095948827 2011-08-22 23:00:01,0.0754669887279 2011-08-23 00:00:01,0.0701578947368 2011-08-23 01:00:01,0.0633381088825 2011-08-23 02:00:01,0.0578227245687 2011-08-23 03:00:01,0.054068914956 2011-08-23 04:00:01,0.0800538116592 2011-08-23 05:00:01,0.0942072409488 2011-08-23 06:00:01,0.110804347826 2011-08-23 07:00:01,0.141096605744 2011-08-23 08:00:01,0.211731601732 2011-08-23 09:00:01,0.181084337349 2011-08-23 10:00:01,0.158333333333 2011-08-23 11:00:01,0.128907563025 2011-08-23 12:00:01,0.116029411765 2011-08-23 13:00:01,0.120865800866 2011-08-23 14:00:01,0.133739130435 2011-08-23 15:00:01,0.143019480519 2011-08-23 16:00:01,0.12492286115 2011-08-23 17:00:01,0.105073529412 2011-08-23 18:00:01,0.0983081155433 2011-08-23 19:00:01,0.0931699687174 2011-08-23 20:00:01,0.0918820224719 2011-08-23 21:00:01,0.0894471387003 2011-08-23 22:00:01,0.102030360531 2011-08-23 23:00:01,0.0903076923077 2011-08-24 00:00:01,0.1046875 2011-08-24 01:00:01,0.0749254226052 2011-08-24 02:00:01,0.0649182561308 2011-08-24 03:00:01,0.0571681415929 2011-08-24 04:00:01,0.0727165775401 2011-08-24 05:00:01,0.0925959780622 2011-08-24 06:00:01,0.107063492063 2011-08-24 07:00:01,0.140641891892 2011-08-24 08:00:01,0.197115384615 2011-08-24 09:00:01,0.191169590643 2011-08-24 10:00:01,0.103025477707 2011-08-24 11:00:01,0.134267515924 2011-08-24 12:00:01,0.13125 2011-08-24 12:00:01,0.119452887538 2011-08-24 13:00:01,0.142298578199 2011-08-24 14:00:01,0.121895424837 2011-08-24 15:00:01,0.128388791594 2011-08-24 16:00:01,0.107593880389 2011-08-24 17:00:01,0.134992967651 2011-08-24 18:00:01,0.137509247842 2011-08-24 19:00:01,0.118355995056 2011-08-24 20:00:01,0.0995682613769 2011-08-24 21:00:01,0.100749711649 2011-08-24 22:00:01,0.0836117936118 2011-08-24 23:00:01,0.089214527027 2011-08-25 00:00:01,0.0810109090909 2011-08-25 01:00:01,0.0740128410915 2011-08-25 02:00:01,0.0661502347418 2011-08-25 03:00:01,0.0658904109589 2011-08-25 04:00:01,0.0658904109589 2011-08-25 05:00:01,0.0795053147997 2011-08-25 06:00:01,0.100915331808 2011-08-25 07:00:01,0.150614334471 2011-08-25 08:00:01,0.161641791045 2011-08-25 09:00:01,0.186170212766 2011-08-25 10:00:01,0.120856269113 2011-08-25 11:00:01,0.139667774086 2011-08-25 12:00:01,0.148098159509 2011-08-25 13:00:01,0.150740740741 2011-08-25 14:00:01,0.128050089445 2011-08-25 15:00:01,0.123235685752 2011-08-25 16:00:01,0.113632019116 2011-08-25 17:00:01,0.103065217391 2011-08-25 18:00:01,0.102137203166 2011-08-25 19:00:01,0.116292517007 2011-08-25 20:00:01,0.0962192216044 2011-08-25 21:00:01,0.0926034958602 2011-08-25 22:00:01,0.0993384223919 2011-08-25 23:00:01,0.0854255319149 2011-08-26 00:00:01,0.0726258992806 2011-08-26 01:00:01,0.0689721485411 2011-08-26 02:00:01,0.0659612903226 2011-08-26 03:00:01,0.0546968403074 2011-08-26 04:00:01,0.0795277777778 2011-08-26 05:00:01,0.0923461538462 2011-08-26 06:00:01,0.105986842105 2011-08-26 07:00:01,0.165223097113 2011-08-26 08:00:01,0.175538461538 2011-08-26 09:00:01,0.151849315068 2011-08-26 10:00:01,0.177138263666 2011-08-26 11:00:01,0.121359773371 2011-08-26 12:00:01,0.131615541922 2011-08-26 13:00:01,0.145436241611 2011-08-26 14:00:01,0.131875 2011-08-26 15:00:01,0.145088566828 2011-08-26 16:00:01,0.138504672897 2011-08-26 17:00:01,0.123757881463 2011-08-26 18:00:01,0.117987804878 2011-08-26 19:00:01,0.110223577236 2011-08-26 20:00:01,0.107444608567 2011-08-26 21:00:01,0.103782095767 2011-08-26 22:00:01,0.095650713686 2011-08-26 23:00:01,0.101652360515 2011-08-27 00:00:01,0.0850060606061 2011-08-27 01:00:01,0.0855480769231 2011-08-27 02:00:01,0.0793292682927 2011-08-27 03:00:01,0.0749841269841 2011-08-27 04:00:01,0.0956683168317 2011-08-27 05:00:01,0.0981013824885 2011-08-27 06:00:01,0.110380622837 2011-08-27 07:00:01,0.135073529412 2011-08-27 08:00:01,0.163687635575 2011-08-27 09:00:01,0.147275132275 2011-08-27 10:00:01,0.118717339667 2011-08-27 11:00:01,0.154738292011 2011-08-27 12:00:01,0.134536082474 2011-08-27 13:00:01,0.131927536232 2011-08-27 14:00:01,0.126748057714 2011-08-27 15:00:01,0.120754005655 2011-08-27 16:00:01,0.118395833333 2011-08-27 17:00:01,0.103737646002 2011-08-27 18:00:01,0.100345140781 2011-08-27 19:00:01,0.098473547268 2011-08-27 20:00:01,0.0985117967332 2011-08-27 21:00:01,0.0954140127389 2011-08-27 22:00:01,0.0860727272727 2011-08-27 23:00:01,0.0821031746032 2011-08-28 00:00:01,0.0727639751553 2011-08-28 01:00:01,0.062752851711 2011-08-28 02:00:01,0.0587381473377 2011-08-28 03:00:01,0.0479363057325 2011-08-28 04:00:01,0.0682142857143 2011-08-28 05:00:01,0.0759542586751 2011-08-28 06:00:01,0.106373626374 2011-08-28 07:00:01,0.0969246861925 2011-08-28 08:00:01,0.170033388982 2011-08-28 09:00:01,0.124548104956 2011-08-28 10:00:01,0.114635514019 2011-08-28 11:00:01,0.103448275862 2011-08-28 12:00:01,0.116266173752 2011-08-28 13:00:01,0.126609907121 2011-08-28 14:00:01,0.130183006536 2011-08-28 15:00:01,0.120176531672 2011-08-28 16:00:01,0.111587301587 2011-08-28 17:00:01,0.0976240846216 2011-08-28 18:00:01,0.0948384353741 2011-08-28 19:00:01,0.0840584166026 2011-08-28 20:00:01,0.0743294117647 2011-08-28 21:00:01,0.0712329863891 2011-08-28 22:00:01,0.0668421052632 2011-08-28 23:00:01,0.0719213114754 2011-08-29 00:00:01,0.0600398406375 2011-08-29 01:00:01,0.0555158069884 2011-08-29 02:00:01,0.0490916597853 2011-08-29 03:00:01,0.0423600973236 2011-08-29 04:00:01,0.0606539735099 2011-08-29 05:00:01,0.0777566539924 2011-08-29 06:00:01,0.0873804971319 2011-08-29 07:00:01,0.129604863222 2011-08-29 08:00:01,0.158345070423 2011-08-29 09:00:01,0.138106508876 2011-08-29 10:00:01,0.150680272109 2011-08-29 11:00:01,0.116778042959 2011-08-29 12:00:01,0.0966950959488 2011-08-29 13:00:01,0.123992932862 2011-08-29 14:00:01,0.11081570997 2011-08-29 15:00:01,0.129307432432 2011-08-29 16:00:01,0.125940740741 2011-08-29 17:00:01,0.102137592138 2011-08-29 18:00:01,0.0941742081448 2011-08-29 19:00:01,0.109444995045 2011-08-29 20:00:01,0.0872681451613 2011-08-29 21:00:01,0.0890061349693 2011-08-29 22:00:01,0.0870618228171 2011-08-29 23:00:01,0.0841054613936 2011-08-30 00:00:01,0.0761148325359 2011-08-30 01:00:01,0.0600057937428 2011-08-30 02:00:01,0.054295958279 2011-08-30 03:00:01,0.051952887538 2011-08-30 04:00:01,0.0924405218726 2011-08-30 05:00:01,0.109405010438 2011-08-30 06:00:01,0.122962138085 2011-08-30 07:00:01,0.147909407666 2011-08-30 08:00:01,0.152699228792 2011-08-30 09:00:01,0.1541875 2011-08-30 10:00:01,0.115840707965 2011-08-30 11:00:01,0.110201149425 2011-08-30 12:00:01,0.110076142132 2011-08-30 13:00:01,0.108673267327 2011-08-30 14:00:01,0.106678832117 2011-08-30 15:00:01,0.107907949791 2011-08-30 16:00:01,0.119509692132 2011-08-30 17:00:01,0.101547749726 2011-08-30 18:00:01,0.111957340025 2011-08-30 19:00:01,0.101444007859 2011-08-30 20:00:01,0.0753491055972 2011-08-30 21:00:01,0.0653881278539 2011-08-30 22:00:01,0.089246805649 2011-08-30 23:00:01,0.0813057961359 2011-08-31 00:00:01,0.0938608119304 2011-08-31 01:00:01,0.0797480451781 2011-08-31 02:00:01,0.066393442623 2011-08-31 03:00:01,0.0646177606178 2011-08-31 04:00:01,0.0873961499493 2011-08-31 05:00:01,0.10959047619 2011-08-31 06:00:01,0.126039119804 2011-08-31 07:00:01,0.12546835443 2011-08-31 08:00:01,0.156303030303 2011-08-31 09:00:01,0.147432432432 2011-08-31 10:00:01,0.133876651982 2011-08-31 11:00:01,0.129890410959 2011-08-31 12:00:01,0.141053811659 2011-08-31 13:00:01,0.117336065574 2011-08-31 14:00:01,0.137372708758 2011-08-31 15:00:01,0.113037593985 2011-08-31 16:00:01,0.110820995962 2011-08-31 17:00:01,0.0996882793017 2011-08-31 18:00:01,0.111057934509 2011-08-31 19:00:01,0.145935563817 2011-08-31 20:00:01,0.165860349127 2011-08-31 21:00:01,0.17193687231 2011-08-31 22:00:01,0.183753623188 2011-08-31 23:00:01,0.173424036281 2011-09-01 00:00:01,0.12689453125 2011-09-01 01:00:01,0.107446988974 2011-09-01 02:00:01,0.0718667642753 2011-09-01 03:00:01,0.0693063583815 2011-09-01 04:00:01,0.136761168385 2011-09-01 05:00:01,0.161497461929 2011-09-01 06:00:01,0.183985890653 2011-09-01 07:00:01,0.190461538462 2011-09-01 08:00:01,0.19428030303 2011-09-01 09:00:01,0.170563380282 2011-09-01 10:00:01,0.181725490196 2011-09-01 11:00:01,0.155087719298 2011-09-01 12:00:01,0.127297297297 2011-09-01 13:00:01,0.127475728155 2011-09-01 14:00:01,0.138672839506 2011-09-01 15:00:01,0.124584980237 2011-09-01 16:00:01,0.119408450704 2011-09-01 17:00:01,0.105145228216 2011-09-01 18:00:01,0.104637681159 2011-09-02 15:00:01,0.125439066059 2011-09-02 16:00:01,0.120748373102 2011-09-02 17:00:01,0.0994585448393 2011-09-02 18:00:01,0.10984 2011-09-02 19:00:01,0.0994903339192 2011-09-02 20:00:01,0.108297511312 2011-09-02 21:00:01,0.109546979866 2011-09-02 22:00:01,0.129507908612 2011-09-02 23:00:01,0.143330266789 2011-09-03 00:00:01,0.121093613298 2011-09-03 01:00:01,0.11054478301 2011-09-03 02:00:01,0.101602160216 2011-09-03 03:00:01,0.0762834917891 2011-09-03 04:00:01,0.0875485799701 2011-09-03 05:00:01,0.127487091222 2011-09-03 06:00:01,0.125506241331 2011-09-03 07:00:01,0.114149797571 2011-09-03 08:00:01,0.148712871287 2011-09-03 09:00:01,0.159177057357 2011-09-03 10:00:01,0.125173267327 2011-09-03 11:00:01,0.12546835443 2011-09-03 12:00:01,0.136340508806 2011-09-03 13:00:01,0.14014084507 2011-09-03 14:00:01,0.135180586907 2011-09-03 15:00:01,0.126968888889 2011-09-03 16:00:01,0.12272195122 2011-09-03 17:00:01,0.112063609467 2011-09-03 18:00:01,0.10224852071 2011-09-03 19:00:01,0.0998234774934 2011-09-03 20:00:01,0.0981008902077 2011-09-03 21:00:01,0.095011148272 2011-09-03 22:00:01,0.0947378277154 2011-09-03 23:00:01,0.0939592123769 2011-09-04 00:00:01,0.0895993589744 2011-09-04 01:00:01,0.0939749328559 2011-09-04 02:00:01,0.0869841269841 2011-09-04 03:00:01,0.0758333333333 2011-09-04 04:00:01,0.103483976993 2011-09-04 05:00:01,0.124340101523 2011-09-04 06:00:01,0.123559748428 2011-09-04 07:00:01,0.143132780083 2011-09-04 08:00:01,0.153292978208 2011-09-04 09:00:01,0.144975961538 2011-09-04 10:00:01,0.148344988345 2011-09-04 11:00:01,0.121404958678 2011-09-04 12:00:01,0.125106761566 2011-09-04 13:00:01,0.137014446228 2011-09-04 14:00:01,0.145497572816 2011-09-04 15:00:01,0.129219653179 2011-09-04 16:00:01,0.125491891892 2011-09-04 17:00:01,0.112601296596 2011-09-04 18:00:01,0.108785123967 2011-09-04 19:00:01,0.104248704663 2011-09-04 20:00:01,0.0923049001815 2011-09-04 21:00:01,0.0836208178439 2011-09-04 22:00:01,0.0923566878981 2011-09-04 23:00:01,0.0781174984207 2011-09-05 00:00:01,0.0772262190248 2011-09-05 01:00:01,0.0748298755187 2011-09-05 02:00:01,0.0652133044107 2011-09-05 03:00:01,0.0451913709116 2011-09-05 04:00:01,0.0791123188406 2011-09-05 05:00:01,0.117971830986 2011-09-05 06:00:01,0.114479338843 2011-09-05 07:00:01,0.113695150115 2011-09-05 08:00:01,0.175580645161 2011-09-05 09:00:01,0.154212328767 2011-09-05 10:00:01,0.139960784314 2011-09-05 11:00:01,0.131630094044 2011-09-05 12:00:01,0.124085714286 2011-09-05 13:00:01,0.127188552189 2011-09-05 14:00:01,0.133503448276 2011-09-05 15:00:01,0.12168972332 2011-09-05 16:00:01,0.115792592593 2011-09-05 17:00:01,0.098496835443 2011-09-05 18:00:01,0.0950494396836 2011-09-05 19:00:01,0.0910444874275 2011-09-05 20:00:01,0.0811893687708 2011-09-05 21:00:01,0.0825793907971 2011-09-05 22:00:01,0.0765527950311 2011-09-05 23:00:01,0.0788387978142 2011-09-06 00:00:01,0.0739627659574 2011-09-06 01:00:01,0.0691387900356 2011-09-06 02:00:01,0.0510319076714 2011-09-06 03:00:01,0.0468152031455 2011-09-06 04:00:01,0.0999201596806 2011-09-06 05:00:01,0.10201884253 2011-09-06 06:00:01,0.106287262873 2011-09-06 07:00:01,0.150187265918 2011-09-06 08:00:01,0.140684210526 2011-09-06 09:00:01,0.154042553191 2011-09-06 10:00:01,0.138396946565 2011-09-06 11:00:01,0.116378737542 2011-09-06 12:00:01,0.111181318681 2011-09-06 13:00:01,0.116266375546 2011-09-06 14:00:01,0.116395112016 2011-09-06 15:00:01,0.114629948365 2011-09-06 16:00:01,0.111974522293 2011-09-06 17:00:01,0.0947324613555 2011-09-06 18:00:01,0.112244224422 2011-09-06 19:00:01,0.102278911565 2011-09-06 20:00:01,0.0928500496524 2011-09-06 21:00:01,0.0991582733813 2011-09-06 22:00:01,0.0976913580247 2011-09-06 23:00:01,0.0857002111189 2011-09-07 00:00:01,0.0823789294817 2011-09-07 01:00:01,0.0659537882859 2011-09-07 02:00:01,0.0494587280108 2011-09-07 03:00:01,0.0497890818859 2011-09-07 04:00:01,0.0654583772392 2011-09-07 05:00:01,0.0896212121212 2011-09-07 06:00:01,0.111073619632 2011-09-07 07:00:01,0.101031746032 2011-09-07 08:00:01,0.151616766467 2011-09-07 09:00:01,0.124743589744 2011-09-07 10:00:01,0.135588235294 2011-09-07 11:00:01,0.0946623794212 2011-09-07 12:00:01,0.097656612529 2011-09-07 13:00:01,0.0962009803922 2011-09-07 14:00:01,0.0853863636364 2011-09-07 15:00:01,0.109326923077 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/exchange-2_cpm_results.csv ================================================ timestamp,value 2011-07-01 00:00:01,0.401048098657 2011-07-01 01:00:01,0.392718881005 2011-07-01 02:00:01,0.309996119798 2011-07-01 03:00:01,0.212938552018 2011-07-01 04:00:01,0.205800905571 2011-07-01 05:00:01,0.255867457952 2011-07-01 06:00:01,0.306630479265 2011-07-01 07:00:01,0.29600203814 2011-07-01 08:00:01,0.530440128999 2011-07-01 09:00:01,0.790249514633 2011-07-01 10:00:01,0.743906815883 2011-07-01 11:00:01,0.736919786741 2011-07-01 12:00:01,0.697582243361 2011-07-01 13:00:01,0.687341841286 2011-07-01 14:00:01,0.517447938078 2011-07-01 15:00:01,0.519026716424 2011-07-01 16:00:01,0.51413336812 2011-07-01 17:00:01,0.417275625868 2011-07-01 18:00:01,0.24845741212 2011-07-01 19:00:01,0.309360489543 2011-07-01 20:00:01,0.273067885947 2011-07-01 21:00:01,0.264461005442 2011-07-01 22:00:01,0.23187973727 2011-07-01 23:00:01,0.261552512902 2011-07-02 00:00:01,0.324815629448 2011-07-02 01:00:01,0.251320671322 2011-07-02 02:00:01,0.21464613516 2011-07-02 03:00:01,0.166280263697 2011-07-02 04:00:01,0.211815143689 2011-07-02 05:00:01,0.303217093576 2011-07-02 06:00:01,0.2878979686 2011-07-02 07:00:01,0.396715687694 2011-07-02 08:00:01,0.588415532379 2011-07-02 09:00:01,0.59337773192 2011-07-02 10:00:01,0.71387011592 2011-07-02 11:00:01,0.787525214093 2011-07-02 12:00:01,0.736921318877 2011-07-02 13:00:01,0.682062044372 2011-07-02 14:00:01,0.72266165164 2011-07-02 15:00:01,0.529339407129 2011-07-02 16:00:01,0.403918440491 2011-07-02 17:00:01,0.346285484196 2011-07-02 18:00:01,0.276515628398 2011-07-02 19:00:01,0.273633723983 2011-07-02 20:00:01,0.348633036515 2011-07-02 21:00:01,0.289148226997 2011-07-02 22:00:01,0.321686929479 2011-07-02 23:00:01,0.260040957735 2011-07-03 00:00:01,0.204862942608 2011-07-03 01:00:01,0.207419676118 2011-07-03 02:00:01,0.173298017129 2011-07-03 03:00:01,0.132202637198 2011-07-03 04:00:01,0.17089560971 2011-07-03 05:00:01,0.279315632688 2011-07-03 06:00:01,0.247734583438 2011-07-03 07:00:01,0.347788950248 2011-07-03 08:00:01,0.677039989488 2011-07-03 09:00:01,0.628506062686 2011-07-03 10:00:01,0.600754435803 2011-07-03 11:00:01,0.595576831487 2011-07-03 12:00:01,0.718312044267 2011-07-03 13:00:01,0.636428503882 2011-07-03 14:00:01,0.561490030939 2011-07-03 15:00:01,0.439826406276 2011-07-03 16:00:01,0.364600634261 2011-07-03 17:00:01,0.304671828772 2011-07-03 18:00:01,0.263320157909 2011-07-03 19:00:01,0.24291524883 2011-07-03 20:00:01,0.241346377957 2011-07-03 21:00:01,0.208214406325 2011-07-03 22:00:01,0.20241559894 2011-07-03 23:00:01,0.231243016929 2011-07-04 00:00:01,0.179941670478 2011-07-04 01:00:01,0.192673380292 2011-07-04 02:00:01,0.166335472132 2011-07-04 03:00:01,0.14227206431 2011-07-04 04:00:01,0.13035498909 2011-07-04 05:00:01,0.167021065133 2011-07-04 06:00:01,0.212676159718 2011-07-04 07:00:01,0.280531152468 2011-07-04 08:00:01,0.475011553443 2011-07-04 09:00:01,0.544187140505 2011-07-04 10:00:01,0.504340064024 2011-07-04 11:00:01,0.534922211188 2011-07-04 12:00:01,0.60978950038 2011-07-04 13:00:01,0.519403479245 2011-07-04 14:00:01,0.523303802344 2011-07-04 15:00:01,0.426077466417 2011-07-04 16:00:01,0.328359110681 2011-07-04 17:00:01,0.350118888796 2011-07-04 18:00:01,0.244078992995 2011-07-04 19:00:01,0.240777566013 2011-07-04 20:00:01,0.219701770288 2011-07-04 21:00:01,0.216081451577 2011-07-04 22:00:01,0.22231036663 2011-07-04 23:00:01,0.251700203323 2011-07-05 00:00:01,0.228566944935 2011-07-05 01:00:01,0.162717684817 2011-07-05 02:00:01,0.180383183189 2011-07-05 03:00:01,0.12846822497 2011-07-05 04:00:01,0.13198890411 2011-07-05 05:00:01,0.175684372523 2011-07-05 06:00:01,0.221543602021 2011-07-05 07:00:01,0.277728770304 2011-07-05 08:00:01,0.441068874921 2011-07-05 09:00:01,0.478228308548 2011-07-05 10:00:01,0.545594724496 2011-07-05 11:00:01,0.667490729295 2011-07-05 12:00:01,0.543584663105 2011-07-05 13:00:01,0.588245394138 2011-07-05 14:00:01,0.428748744016 2011-07-05 15:00:01,0.395360148449 2011-07-05 16:00:01,0.362225419824 2011-07-05 17:00:01,0.32167455849 2011-07-05 18:00:01,0.271341345083 2011-07-05 19:00:01,0.238122873903 2011-07-05 20:00:01,0.215218118536 2011-07-05 21:00:01,0.212734989045 2011-07-05 22:00:01,0.191313851687 2011-07-05 23:00:01,0.242111992062 2011-07-06 00:00:01,0.225081442142 2011-07-06 01:00:01,0.197461002199 2011-07-06 02:00:01,0.136700901134 2011-07-06 03:00:01,0.113719800728 2011-07-06 04:00:01,0.15875414394 2011-07-06 05:00:01,0.202746124147 2011-07-06 06:00:01,0.225718914303 2011-07-06 07:00:01,0.282354321784 2011-07-06 08:00:01,0.479532349027 2011-07-06 09:00:01,0.645141390712 2011-07-06 10:00:01,0.526166240452 2011-07-06 11:00:01,0.575165121144 2011-07-06 12:00:01,0.576957406548 2011-07-06 13:00:01,0.515025329115 2011-07-06 14:00:01,0.406212215185 2011-07-06 15:00:01,0.446764580432 2011-07-06 16:00:01,0.360918143496 2011-07-06 17:00:01,0.354822719712 2011-07-06 18:00:01,0.28959628398 2011-07-06 19:00:01,0.243605335426 2011-07-06 20:00:01,0.207677612716 2011-07-06 21:00:01,0.295679762953 2011-07-06 22:00:01,0.215115083297 2011-07-06 23:00:01,0.225798427437 2011-07-07 00:00:01,0.211171317162 2011-07-07 01:00:01,0.163630094284 2011-07-07 02:00:01,0.123460876016 2011-07-07 03:00:01,0.112138881944 2011-07-07 04:00:01,0.123695651232 2011-07-07 05:00:01,0.174191714264 2011-07-07 06:00:01,0.194801123896 2011-07-07 07:00:01,0.248622655329 2011-07-07 08:00:01,0.408404765219 2011-07-07 09:00:01,0.533661344524 2011-07-07 10:00:01,0.541734270777 2011-07-07 11:00:01,0.440232756428 2011-07-07 12:00:01,0.465434553749 2011-07-07 13:00:01,0.434325310895 2011-07-07 14:00:01,0.350176907623 2011-07-07 15:00:01,0.381217461856 2011-07-07 16:00:01,0.322961923523 2011-07-07 17:00:01,0.250851707414 2011-07-07 18:00:01,0.228276143974 2011-07-07 19:00:01,0.151708247831 2011-07-07 20:00:01,0.180537641872 2011-07-07 21:00:01,0.172451902159 2011-07-07 22:00:01,0.170809031956 2011-07-07 23:00:01,0.15733239773 2011-07-08 00:00:01,0.160795812079 2011-07-08 01:00:01,0.146745639797 2011-07-08 02:00:01,0.140944765148 2011-07-08 03:00:01,0.102638951514 2011-07-08 04:00:01,0.11056241713 2011-07-08 05:00:01,0.144226388965 2011-07-08 06:00:01,0.158332277056 2011-07-08 07:00:01,0.312025914701 2011-07-08 08:00:01,0.527204950695 2011-07-08 09:00:01,0.434005616543 2011-07-08 10:00:01,0.494257013647 2011-07-08 11:00:01,0.456944556533 2011-07-08 12:00:01,0.444284861437 2011-07-08 13:00:01,0.361783886347 2011-07-08 14:00:01,0.309215412949 2011-07-08 15:00:01,0.323232323232 2011-07-08 16:00:01,0.228027186216 2011-07-08 17:00:01,0.248385861855 2011-07-08 18:00:01,0.230339962317 2011-07-08 19:00:01,0.199236511832 2011-07-08 20:00:01,0.182615991827 2011-07-08 21:00:01,0.201566213223 2011-07-08 22:00:01,0.197890930527 2011-07-08 23:00:01,0.180271292582 2011-07-09 00:00:01,0.192514343728 2011-07-09 01:00:01,0.15683009122 2011-07-09 02:00:01,0.129613425807 2011-07-09 03:00:01,0.110494486342 2011-07-09 04:00:01,0.170957809371 2011-07-09 05:00:01,0.237131289763 2011-07-09 06:00:01,0.229209149397 2011-07-09 07:00:01,0.298367102676 2011-07-09 08:00:01,0.499133363352 2011-07-09 09:00:01,0.464385632928 2011-07-09 10:00:01,0.472395538999 2011-07-09 11:00:01,0.544146269537 2011-07-09 12:00:01,0.577541441502 2011-07-09 13:00:01,0.515494108308 2011-07-09 14:00:01,0.407933425798 2011-07-09 15:00:01,0.399840114981 2011-07-09 16:00:01,0.353425088801 2011-07-09 17:00:01,0.288194806737 2011-07-09 18:00:01,0.215691621082 2011-07-09 19:00:01,0.235888689633 2011-07-09 20:00:01,0.191367325907 2011-07-09 21:00:01,0.188934143242 2011-07-09 22:00:01,0.201572828906 2011-07-09 23:00:01,0.22097753552 2011-07-10 00:00:01,0.20411036036 2011-07-10 01:00:01,0.162965130084 2011-07-10 02:00:01,0.119492242233 2011-07-10 03:00:01,0.11211438251 2011-07-10 04:00:01,0.132642082613 2011-07-10 05:00:01,0.222133726255 2011-07-10 06:00:01,0.191750214286 2011-07-10 07:00:01,0.260790149008 2011-07-10 08:00:01,0.471314096973 2011-07-10 09:00:01,0.477296463143 2011-07-10 10:00:01,0.446584938704 2011-07-10 11:00:01,0.496146481342 2011-07-10 12:00:01,0.495432405878 2011-07-10 13:00:01,0.429185534206 2011-07-10 14:00:01,0.416406816228 2011-07-10 15:00:01,0.376365524788 2011-07-10 16:00:01,0.346310385427 2011-07-10 17:00:01,0.324941180324 2011-07-10 18:00:01,0.224988446606 2011-07-10 19:00:01,0.193877335585 2011-07-10 20:00:01,0.195783481953 2011-07-10 21:00:01,0.179647327158 2011-07-10 22:00:01,0.179125049492 2011-07-10 23:00:01,0.15644170512 2011-07-11 00:00:01,0.139389470106 2011-07-11 01:00:01,0.140954515364 2011-07-11 02:00:01,0.0922539182816 2011-07-11 03:00:01,0.082216125654 2011-07-11 04:00:01,0.0908497986666 2011-07-11 05:00:01,0.157180412254 2011-07-11 06:00:01,0.1727280618 2011-07-11 07:00:01,0.256565982078 2011-07-11 08:00:01,0.428283732379 2011-07-11 09:00:01,0.444226956124 2011-07-11 10:00:01,0.483698194053 2011-07-11 11:00:01,0.458668492213 2011-07-11 12:00:01,0.418402013567 2011-07-11 13:00:01,0.393451621757 2011-07-11 14:00:01,0.313871961208 2011-07-11 15:00:01,0.2891833066 2011-07-11 16:00:01,0.249155689411 2011-07-11 17:00:01,0.25617308183 2011-07-11 18:00:01,0.212968170705 2011-07-11 19:00:01,0.216770052025 2011-07-11 20:00:01,0.197776496284 2011-07-11 21:00:01,0.187934318994 2011-07-11 22:00:01,0.187420141712 2011-07-11 23:00:01,0.187506940589 2011-07-12 00:00:01,0.168980614452 2011-07-12 01:00:01,0.152074937809 2011-07-12 02:00:01,0.137461484942 2011-07-12 03:00:01,0.104112579122 2011-07-12 04:00:01,0.142918552002 2011-07-12 05:00:01,0.143275447091 2011-07-12 06:00:01,0.185618913885 2011-07-12 07:00:01,0.172907780556 2011-07-12 08:00:01,0.489569415766 2011-07-12 09:00:01,0.475371441118 2011-07-12 10:00:01,0.510875190931 2011-07-12 11:00:01,0.539295638516 2011-07-12 12:00:01,0.562670369799 2011-07-12 13:00:01,0.493639908065 2011-07-12 14:00:01,0.375071761179 2011-07-12 15:00:01,0.367231783852 2011-07-12 16:00:01,0.309527758348 2011-07-12 17:00:01,0.289907743167 2011-07-12 18:00:01,0.247273915988 2011-07-12 19:00:01,0.225066896458 2011-07-12 20:00:01,0.235480042627 2011-07-12 21:00:01,0.243742335442 2011-07-12 22:00:01,0.226198468573 2011-07-12 23:00:01,0.220480258123 2011-07-13 00:00:01,0.177474657233 2011-07-13 01:00:01,0.165109689891 2011-07-13 02:00:01,0.130659891709 2011-07-13 03:00:01,0.114740658034 2011-07-13 04:00:01,0.141167988992 2011-07-13 05:00:01,0.186317495352 2011-07-13 06:00:01,0.229541927497 2011-07-13 07:00:01,0.373358604369 2011-07-13 08:00:01,0.487958224908 2011-07-13 09:00:01,0.539149888143 2011-07-13 10:00:01,0.464484920282 2011-07-13 11:00:01,0.622171145686 2011-07-13 12:00:01,0.557672400502 2011-07-13 13:00:01,0.454296051165 2011-07-13 14:00:01,0.455315598903 2011-07-13 15:00:01,0.40590212985 2011-07-13 16:00:01,0.412460472538 2011-07-13 17:00:01,0.321670941047 2011-07-13 18:00:01,0.313384053393 2011-07-13 19:00:01,0.261011165287 2011-07-13 20:00:01,0.267151307818 2011-07-13 21:00:01,0.202422469962 2011-07-13 22:00:01,0.250151828141 2011-07-13 23:00:01,0.258616476517 2011-07-14 00:00:01,0.203289190586 2011-07-14 01:00:01,0.167275100891 2011-07-14 02:00:01,0.129840366979 2011-07-14 03:00:01,0.117719206301 2011-07-14 04:00:01,0.185196847018 2011-07-14 05:00:01,0.252898111735 2011-07-14 06:00:01,0.231405043299 2011-07-14 07:00:01,0.368990180311 2011-07-14 08:00:01,0.493794641216 2011-07-14 09:00:01,0.495958899818 2011-07-14 10:00:01,0.449545022409 2011-07-14 11:00:01,0.418541266078 2011-07-14 12:00:01,0.594471687259 2011-07-14 13:00:01,0.660831736496 2011-07-14 14:00:01,0.564546967788 2011-07-14 15:00:01,0.426793043242 2011-07-14 16:00:01,0.401047443943 2011-07-14 17:00:01,0.249061577522 2011-07-14 18:00:01,0.310849033716 2011-07-14 19:00:01,0.233542090686 2011-07-14 20:00:01,0.216787081441 2011-07-14 21:00:01,0.234240406218 2011-07-14 22:00:01,0.224834627552 2011-07-14 23:00:01,0.224770026795 2011-07-15 00:00:01,0.186996327941 2011-07-15 01:00:01,0.192104631629 2011-07-15 02:00:01,0.134936613375 2011-07-15 03:00:01,0.129935763999 2011-07-15 04:00:01,0.167604705679 2011-07-15 05:00:01,0.181410049787 2011-07-15 06:00:01,0.231296513212 2011-07-15 07:00:01,0.288950955201 2011-07-15 08:00:01,0.459122644791 2011-07-15 09:00:01,0.577886549723 2011-07-15 10:00:01,0.459511477173 2011-07-15 11:00:01,0.573333333333 2011-07-15 12:00:01,0.735811618194 2011-07-15 13:00:01,0.531054359278 2011-07-15 14:00:01,0.481355974591 2011-07-15 15:00:01,0.449878916513 2011-07-15 16:00:01,0.420883789935 2011-07-15 17:00:01,0.322864798895 2011-07-15 18:00:01,0.143973206366 2011-07-15 19:00:01,0.0449098864075 2011-07-15 20:00:01,0.231909669663 2011-07-15 21:00:01,0.307814215642 2011-07-15 22:00:01,0.215337200416 2011-07-15 23:00:01,0.200955847706 2011-07-16 00:00:01,0.457925390707 2011-07-16 01:00:01,0.207633787425 2011-07-16 02:00:01,0.183786893926 2011-07-16 03:00:01,0.166145206736 2011-07-16 04:00:01,0.0546898928025 2011-07-16 05:00:01,0.41349399435 2011-07-16 06:00:01,0.21266565237 2011-07-16 07:00:01,0.405484768787 2011-07-16 08:00:01,0.393868203116 2011-07-16 09:00:01,0.529876582362 2011-07-16 10:00:01,0.474258533856 2011-07-16 11:00:01,0.48150129635 2011-07-16 12:00:01,0.714378546983 2011-07-16 13:00:01,0.594970759306 2011-07-16 14:00:01,0.497414475258 2011-07-16 15:00:01,0.472394120161 2011-07-16 16:00:01,0.391052321493 2011-07-16 17:00:01,0.347261857056 2011-07-16 18:00:01,0.295052657131 2011-07-16 19:00:01,0.279554883486 2011-07-16 20:00:01,0.247339868564 2011-07-16 21:00:01,0.234330907379 2011-07-16 22:00:01,0.244476551099 2011-07-16 23:00:01,0.260264476655 2011-07-17 00:00:01,0.19759374095 2011-07-17 01:00:01,0.196832352893 2011-07-17 02:00:01,0.165662875197 2011-07-17 03:00:01,0.143359111767 2011-07-17 04:00:01,0.21387587975 2011-07-17 05:00:01,0.217570859757 2011-07-17 06:00:01,0.234414152551 2011-07-17 07:00:01,0.346885066425 2011-07-17 08:00:01,0.417195190785 2011-07-17 09:00:01,0.42452044101 2011-07-17 10:00:01,0.548663964034 2011-07-17 11:00:01,0.584730174357 2011-07-17 12:00:01,0.6129684815 2011-07-17 13:00:01,0.570864765338 2011-07-17 14:00:01,0.58035288204 2011-07-17 15:00:01,0.525839273396 2011-07-17 16:00:01,0.396771251233 2011-07-17 17:00:01,0.346949542015 2011-07-17 18:00:01,0.288522229931 2011-07-17 19:00:01,0.256968065004 2011-07-17 20:00:01,0.270501758648 2011-07-17 21:00:01,0.239742956006 2011-07-17 22:00:01,0.234361529517 2011-07-17 23:00:01,0.187886021629 2011-07-18 00:00:01,0.225183226125 2011-07-18 01:00:01,0.161582089438 2011-07-18 02:00:01,0.150193152414 2011-07-18 03:00:01,0.138530070901 2011-07-18 04:00:01,0.139423483631 2011-07-18 05:00:01,0.145971095318 2011-07-18 06:00:01,0.186878853127 2011-07-18 07:00:01,0.319640385124 2011-07-18 08:00:01,0.520614428117 2011-07-18 09:00:01,0.453551781296 2011-07-18 10:00:01,0.502821160261 2011-07-18 11:00:01,0.59417456907 2011-07-18 12:00:01,0.416779265447 2011-07-18 13:00:01,0.457051579327 2011-07-18 14:00:01,0.425053888784 2011-07-18 15:00:01,0.391342369917 2011-07-18 16:00:01,0.565611458262 2011-07-18 17:00:01,0.321790125479 2011-07-18 18:00:01,0.224332674191 2011-07-18 19:00:01,0.246549051451 2011-07-18 20:00:01,0.208119218911 2011-07-18 21:00:01,0.228249765454 2011-07-18 22:00:01,0.207939342422 2011-07-18 23:00:01,0.202166765437 2011-07-19 00:00:01,0.209550828532 2011-07-19 01:00:01,0.184091194376 2011-07-19 02:00:01,0.175728556885 2011-07-19 03:00:01,0.156583178334 2011-07-19 04:00:01,0.169780127627 2011-07-19 05:00:01,0.213679793221 2011-07-19 06:00:01,0.307929755045 2011-07-19 07:00:01,0.206288191397 2011-07-19 08:00:01,0.384913156022 2011-07-19 09:00:01,0.485701650943 2011-07-19 10:00:01,0.543841413616 2011-07-19 11:00:01,0.512707996911 2011-07-19 12:00:01,0.514567697661 2011-07-19 13:00:01,0.387080490715 2011-07-19 14:00:01,0.299222659994 2011-07-19 15:00:01,0.467463346053 2011-07-19 16:00:01,0.305939401882 2011-07-19 17:00:01,0.266237288393 2011-07-19 18:00:01,0.228824225875 2011-07-19 19:00:01,0.377479839707 2011-07-19 20:00:01,0.222640362231 2011-07-19 21:00:01,0.239374301933 2011-07-19 22:00:01,0.210807509061 2011-07-19 23:00:01,0.20721999674 2011-07-20 00:00:01,0.183171233672 2011-07-20 01:00:01,0.17535293411 2011-07-20 02:00:01,0.149082471767 2011-07-20 03:00:01,0.13322111022 2011-07-20 04:00:01,0.152328400635 2011-07-20 05:00:01,0.194135398375 2011-07-20 06:00:01,0.228316568609 2011-07-20 07:00:01,0.317831969929 2011-07-20 08:00:01,0.368739205527 2011-07-20 09:00:01,0.506948990382 2011-07-20 10:00:01,0.47500309751 2011-07-20 11:00:01,0.493425888118 2011-07-20 12:00:01,0.484030128533 2011-07-20 13:00:01,0.525203484221 2011-07-20 14:00:01,0.37446179272 2011-07-20 15:00:01,0.298930848455 2011-07-20 16:00:01,0.209247912154 2011-07-20 17:00:01,0.395342238767 2011-07-20 18:00:01,0.247451712976 2011-07-20 19:00:01,0.201449246669 2011-07-20 20:00:01,0.226587929504 2011-07-20 21:00:01,0.216551601378 2011-07-20 22:00:01,0.217818915146 2011-07-20 23:00:01,0.279013742631 2011-07-21 00:00:01,0.176800070317 2011-07-21 01:00:01,0.155743881702 2011-07-21 02:00:01,0.16790458896 2011-07-21 03:00:01,0.145339317705 2011-07-21 04:00:01,0.162310985782 2011-07-21 06:00:01,0.225127023514 2011-07-21 07:00:01,0.305405131769 2011-07-21 08:00:01,0.272592485817 2011-07-21 09:00:01,0.333844887792 2011-07-21 10:00:01,0.500682860209 2011-07-21 11:00:01,0.394310306282 2011-07-21 12:00:01,0.688708170058 2011-07-21 13:00:01,0.546541474379 2011-07-21 14:00:01,0.468349650727 2011-07-21 15:00:01,0.438412517347 2011-07-21 16:00:01,0.405492179511 2011-07-21 17:00:01,0.34746436655 2011-07-21 18:00:01,0.355934947384 2011-07-21 19:00:01,0.321369405386 2011-07-21 20:00:01,0.297296988465 2011-07-21 21:00:01,0.310397325461 2011-07-21 22:00:01,0.279340360019 2011-07-21 23:00:01,0.273138547997 2011-07-22 00:00:01,0.216208416255 2011-07-22 01:00:01,0.218956491608 2011-07-22 02:00:01,0.185362212692 2011-07-22 03:00:01,0.160410400635 2011-07-22 04:00:01,0.2296313499 2011-07-22 05:00:01,0.211899236364 2011-07-22 06:00:01,0.236990707817 2011-07-22 07:00:01,0.285074808417 2011-07-22 08:00:01,0.496803531495 2011-07-22 09:00:01,0.414682750962 2011-07-22 10:00:01,0.658459017973 2011-07-22 11:00:01,0.477002967359 2011-07-22 12:00:01,0.596746877025 2011-07-22 13:00:01,0.512225170584 2011-07-22 14:00:01,0.491375775283 2011-07-22 15:00:01,0.376930826058 2011-07-22 16:00:01,0.335408585677 2011-07-22 17:00:01,0.331426247669 2011-07-22 18:00:01,0.330962613101 2011-07-22 19:00:01,0.165794585514 2011-07-22 20:00:01,0.394205934513 2011-07-22 21:00:01,0.285497024143 2011-07-22 22:00:01,0.285426606134 2011-07-22 23:00:01,0.28290912475 2011-07-23 00:00:01,0.26473414201 2011-07-23 01:00:01,0.294095349176 2011-07-23 02:00:01,0.214179244496 2011-07-23 03:00:01,0.180678676961 2011-07-23 04:00:01,0.270198998415 2011-07-23 05:00:01,0.271868273594 2011-07-23 06:00:01,0.224572434312 2011-07-23 07:00:01,0.362203601746 2011-07-23 08:00:01,0.493507761398 2011-07-23 09:00:01,0.486753791412 2011-07-23 10:00:01,0.509806435072 2011-07-23 11:00:01,0.606573130886 2011-07-23 12:00:01,0.620478347304 2011-07-23 13:00:01,0.536817575544 2011-07-23 14:00:01,0.588276778053 2011-07-23 15:00:01,0.520050669728 2011-07-23 16:00:01,0.407757000099 2011-07-23 17:00:01,0.320313118552 2011-07-23 18:00:01,0.30309578123 2011-07-23 19:00:01,0.256693040856 2011-07-23 20:00:01,0.229650861622 2011-07-23 21:00:01,0.199366122475 2011-07-23 22:00:01,0.204156773323 2011-07-23 23:00:01,0.201065369338 2011-07-24 00:00:01,0.211396157209 2011-07-24 01:00:01,0.174167629608 2011-07-24 02:00:01,0.128643599089 2011-07-24 03:00:01,0.113269608672 2011-07-24 04:00:01,0.193969379098 2011-07-24 05:00:01,0.211982066182 2011-07-24 06:00:01,0.182067187626 2011-07-24 07:00:01,0.28538258695 2011-07-24 08:00:01,0.289536124982 2011-07-24 09:00:01,0.43311355076 2011-07-24 10:00:01,0.434267710905 2011-07-24 11:00:01,0.6073508454 2011-07-24 12:00:01,0.551777941294 2011-07-24 13:00:01,0.513737999711 2011-07-24 14:00:01,0.575968342251 2011-07-24 15:00:01,0.464939917259 2011-07-24 16:00:01,0.363468714432 2011-07-24 17:00:01,0.292985374913 2011-07-24 18:00:01,0.274288096558 2011-07-24 19:00:01,0.212545877133 2011-07-24 20:00:01,0.213512020559 2011-07-24 21:00:01,0.198521271775 2011-07-24 22:00:01,0.191002754581 2011-07-24 23:00:01,0.176639853272 2011-07-25 00:00:01,0.17807286211 2011-07-25 01:00:01,0.135347010517 2011-07-25 02:00:01,0.114142604504 2011-07-25 03:00:01,0.104569738809 2011-07-25 04:00:01,0.144246911642 2011-07-25 05:00:01,0.170474143934 2011-07-25 06:00:01,0.153459241305 2011-07-25 07:00:01,0.190020237895 2011-07-25 08:00:01,0.375302939367 2011-07-25 09:00:01,0.347942083762 2011-07-25 10:00:01,0.390454308388 2011-07-25 11:00:01,0.409452112087 2011-07-25 12:00:01,0.430285297861 2011-07-25 13:00:01,0.424308833446 2011-07-25 14:00:01,0.452680324746 2011-07-25 15:00:01,0.445520436247 2011-07-25 16:00:01,0.157649955543 2011-07-25 17:00:01,0.400905529913 2011-07-25 18:00:01,0.24124369894 2011-07-25 19:00:01,0.169687077264 2011-07-25 20:00:01,0.235160002135 2011-07-25 21:00:01,0.200913242009 2011-07-25 22:00:01,0.203985491786 2011-07-25 23:00:01,0.205137620179 2011-07-26 00:00:01,0.142881356485 2011-07-26 01:00:01,0.448868356238 2011-07-26 02:00:01,0.139351944698 2011-07-26 03:00:01,0.128736004655 2011-07-26 04:00:01,0.128572624444 2011-07-26 05:00:01,0.162722674678 2011-07-26 06:00:01,0.000983971620187 2011-07-26 07:00:01,0.242902773348 2011-07-26 08:00:01,0.38248295024 2011-07-26 09:00:01,0.329844801022 2011-07-26 10:00:01,0.5233777315 2011-07-26 11:00:01,0.458856512273 2011-07-26 12:00:01,0.399162869787 2011-07-26 13:00:01,0.379555694156 2011-07-26 14:00:01,0.419891863465 2011-07-26 15:00:01,0.300920186241 2011-07-26 16:00:01,0.28030162283 2011-07-26 17:00:01,0.253520184622 2011-07-26 18:00:01,0.259408524489 2011-07-26 19:00:01,0.193844435914 2011-07-26 20:00:01,0.218603988717 2011-07-26 21:00:01,0.195998000527 2011-07-26 22:00:01,0.1877134733 2011-07-26 23:00:01,0.196431126834 2011-07-27 00:00:01,0.176174912325 2011-07-27 01:00:01,0.161064534026 2011-07-27 02:00:01,0.14548881067 2011-07-27 03:00:01,0.10755273831 2011-07-27 04:00:01,0.155952563936 2011-07-27 05:00:01,0.209577337144 2011-07-27 06:00:01,0.148669490265 2011-07-27 07:00:01,0.209511837419 2011-07-27 08:00:01,0.295059356682 2011-07-27 09:00:01,0.361572165905 2011-07-27 10:00:01,0.439566245328 2011-07-27 11:00:01,0.491474788691 2011-07-27 12:00:01,0.442614926619 2011-07-27 13:00:01,0.448160352579 2011-07-27 14:00:01,0.438678027369 2011-07-27 15:00:01,0.37405645226 2011-07-27 16:00:01,0.379522109676 2011-07-27 17:00:01,0.321533673235 2011-07-27 18:00:01,0.331314163382 2011-07-27 19:00:01,0.259387243472 2011-07-27 20:00:01,0.256637040872 2011-07-27 21:00:01,0.225029690994 2011-07-27 22:00:01,0.243701401417 2011-07-27 23:00:01,0.213428038176 2011-07-28 00:00:01,0.147534516765 2011-07-28 01:00:01,0.221122616563 2011-07-28 02:00:01,0.157066545009 2011-07-28 03:00:01,0.135839707145 2011-07-28 04:00:01,0.142731993306 2011-07-28 05:00:01,0.203193201254 2011-07-28 06:00:01,0.162148007374 2011-07-28 07:00:01,0.0356090305386 2011-07-28 08:00:01,0.517897285146 2011-07-28 09:00:01,0.370649235087 2011-07-28 10:00:01,0.612499485928 2011-07-28 11:00:01,0.478236502896 2011-07-28 12:00:01,0.446529542833 2011-07-28 13:00:01,0.419630308694 2011-07-28 14:00:01,0.404135857732 2011-07-28 15:00:01,0.378717263569 2011-07-28 16:00:01,0.00326508400789 2011-07-28 17:00:01,0.00307836835862 2011-07-28 18:00:01,0.455160685778 2011-07-28 19:00:01,0.297786274149 2011-07-28 20:00:01,0.202158077792 2011-07-28 21:00:01,0.241454196911 2011-07-28 22:00:01,0.220964257391 2011-07-28 23:00:01,0.225213493959 2011-07-29 00:00:01,0.211517106446 2011-07-29 01:00:01,0.196341739229 2011-07-29 02:00:01,0.147722062332 2011-07-29 03:00:01,0.134019815857 2011-07-29 04:00:01,0.141013537197 2011-07-29 05:00:01,0.168965441467 2011-07-29 06:00:01,0.158813135032 2011-07-29 07:00:01,0.223773542028 2011-07-29 08:00:01,0.457448087743 2011-07-29 09:00:01,0.497110585763 2011-07-29 10:00:01,0.469454155973 2011-07-29 11:00:01,0.495279695646 2011-07-29 12:00:01,0.465535068068 2011-07-29 13:00:01,0.531950947043 2011-07-29 14:00:01,0.45310146576 2011-07-29 15:00:01,0.427706184123 2011-07-29 16:00:01,0.172425168071 2011-07-29 17:00:01,0.423704927457 2011-07-29 18:00:01,0.266947696995 2011-07-29 19:00:01,0.260453726674 2011-07-29 20:00:01,0.062668451477 2011-07-29 21:00:01,0.335431661925 2011-07-29 22:00:01,0.220403664009 2011-07-29 23:00:01,0.273034152036 2011-07-30 00:00:01,0.229069311321 2011-07-30 01:00:01,0.209343911864 2011-07-30 02:00:01,0.154835868682 2011-07-30 03:00:01,0.171468364853 2011-07-30 04:00:01,0.203818083967 2011-07-30 05:00:01,0.298213445003 2011-07-30 06:00:01,0.232935602737 2011-07-30 07:00:01,0.271720206092 2011-07-30 08:00:01,0.375881709479 2011-07-30 09:00:01,0.377435538444 2011-07-30 10:00:01,0.439536282858 2011-07-30 11:00:01,0.577576802062 2011-07-30 12:00:01,0.475051899481 2011-07-30 13:00:01,0.561543737839 2011-07-30 14:00:01,0.454925326176 2011-07-30 15:00:01,0.41081754716 2011-07-30 16:00:01,0.310035490495 2011-07-30 17:00:01,0.318734610636 2011-07-30 18:00:01,0.322629535726 2011-07-30 19:00:01,0.263100107643 2011-07-30 20:00:01,0.239908136512 2011-07-30 21:00:01,0.24635895478 2011-07-30 22:00:01,0.234870484843 2011-07-30 23:00:01,0.235311703923 2011-07-31 00:00:01,0.25892067675 2011-07-31 01:00:01,0.215918456552 2011-07-31 02:00:01,0.168897432416 2011-07-31 03:00:01,0.13620050354 2011-07-31 04:00:01,0.195074396444 2011-07-31 05:00:01,0.257899682382 2011-07-31 06:00:01,0.21212590836 2011-07-31 07:00:01,0.253616780446 2011-07-31 08:00:01,0.280396110798 2011-07-31 09:00:01,0.335011022836 2011-07-31 10:00:01,0.325472865004 2011-07-31 11:00:01,0.478309878796 2011-07-31 12:00:01,0.42241017221 2011-07-31 13:00:01,0.428092396729 2011-07-31 14:00:01,0.454567579407 2011-07-31 15:00:01,0.434495021948 2011-07-31 16:00:01,0.376663051281 2011-07-31 17:00:01,0.276657889247 2011-07-31 18:00:01,0.231251390096 2011-07-31 19:00:01,0.230442483964 2011-07-31 20:00:01,0.221718482353 2011-07-31 21:00:01,0.147292482506 2011-07-31 22:00:01,0.2719695304 2011-07-31 23:00:01,0.18424957212 2011-08-01 00:00:01,0.183854930206 2011-08-01 01:00:01,0.146498617435 2011-08-01 02:00:01,0.136459424487 2011-08-01 03:00:01,0.087785768676 2011-08-01 04:00:01,0.113553461349 2011-08-01 05:00:01,0.123708237311 2011-08-01 06:00:01,0.149411987548 2011-08-01 07:00:01,0.218854736601 2011-08-01 08:00:01,0.361513984073 2011-08-01 09:00:01,0.20819818985 2011-08-01 10:00:01,0.488597227448 2011-08-01 11:00:01,0.508212583188 2011-08-01 12:00:01,0.41313021761 2011-08-01 13:00:01,0.448025379708 2011-08-01 14:00:01,0.359762170646 2011-08-01 15:00:01,0.376602931511 2011-08-01 16:00:01,0.289073768803 2011-08-01 17:00:01,0.316292739115 2011-08-01 18:00:01,0.323627807345 2011-08-01 19:00:01,0.25922530369 2011-08-01 20:00:01,0.229332661947 2011-08-01 21:00:01,0.217184733646 2011-08-01 22:00:01,0.202887167798 2011-08-01 23:00:01,0.192562989504 2011-08-02 00:00:01,0.175209644865 2011-08-02 01:00:01,0.130037217212 2011-08-02 02:00:01,0.172503691226 2011-08-02 03:00:01,0.102679648204 2011-08-02 04:00:01,0.122842945119 2011-08-02 05:00:01,0.162794978716 2011-08-02 06:00:01,0.171762466504 2011-08-02 07:00:01,0.291704229404 2011-08-02 08:00:01,0.401144203264 2011-08-02 09:00:01,0.471953153836 2011-08-02 10:00:01,0.447094298246 2011-08-02 11:00:01,0.581099131105 2011-08-02 12:00:01,0.464249548487 2011-08-02 13:00:01,0.496229838855 2011-08-02 14:00:01,0.452098154126 2011-08-02 15:00:01,0.433815975945 2011-08-02 16:00:01,0.387994271038 2011-08-02 17:00:01,0.338336251156 2011-08-02 18:00:01,0.309087077998 2011-08-02 19:00:01,0.290744323188 2011-08-02 20:00:01,0.305809320552 2011-08-02 21:00:01,0.317276030146 2011-08-02 22:00:01,0.29720504068 2011-08-02 23:00:01,0.235773190287 2011-08-03 00:00:01,0.188286974461 2011-08-03 01:00:01,0.171487446869 2011-08-03 02:00:01,0.133994781432 2011-08-03 03:00:01,0.10274998997 2011-08-03 04:00:01,0.128252606457 2011-08-03 05:00:01,0.174345589129 2011-08-03 06:00:01,0.153733810649 2011-08-03 07:00:01,0.224686610782 2011-08-03 08:00:01,0.362468087548 2011-08-03 09:00:01,0.1944754871 2011-08-03 10:00:01,0.691956124314 2011-08-03 11:00:01,0.468199125652 2011-08-03 12:00:01,0.444023939447 2011-08-03 13:00:01,0.488482128973 2011-08-03 14:00:01,0.453174792496 2011-08-03 15:00:01,0.413451733329 2011-08-03 16:00:01,0.378406614728 2011-08-03 17:00:01,0.290162457252 2011-08-03 18:00:01,0.267312071302 2011-08-03 19:00:01,0.316459501711 2011-08-03 20:00:01,0.260711886419 2011-08-03 21:00:01,0.236257686646 2011-08-03 22:00:01,0.233285806598 2011-08-03 23:00:01,0.197457031016 2011-08-04 00:00:01,0.158111370303 2011-08-04 01:00:01,0.154896261014 2011-08-04 02:00:01,0.128176016257 2011-08-04 03:00:01,0.0970092266232 2011-08-04 04:00:01,0.124495046127 2011-08-04 05:00:01,0.134242511807 2011-08-04 06:00:01,0.125320507716 2011-08-04 07:00:01,0.229197163666 2011-08-04 08:00:01,0.505902851026 2011-08-04 09:00:01,0.4434204395 2011-08-04 10:00:01,0.417950592782 2011-08-04 11:00:01,0.534482758621 2011-08-04 12:00:01,0.549754911728 2011-08-04 13:00:01,0.47062494681 2011-08-04 14:00:01,0.442797415431 2011-08-04 15:00:01,0.412228226625 2011-08-04 16:00:01,0.377236338633 2011-08-04 17:00:01,0.277504550528 2011-08-04 18:00:01,0.307153691718 2011-08-04 19:00:01,0.251961989181 2011-08-04 20:00:01,0.257590838762 2011-08-04 21:00:01,0.248772705904 2011-08-04 22:00:01,0.239097911372 2011-08-04 23:00:01,0.221741388264 2011-08-05 00:00:01,0.171688928697 2011-08-05 01:00:01,0.157732699811 2011-08-05 02:00:01,0.126886132106 2011-08-05 03:00:01,0.100102337993 2011-08-05 04:00:01,0.12949774781 2011-08-05 05:00:01,0.190892065494 2011-08-05 06:00:01,0.184490653727 2011-08-05 07:00:01,0.337005713444 2011-08-05 08:00:01,0.50548598641 2011-08-05 09:00:01,0.556096708127 2011-08-05 10:00:01,0.467201510146 2011-08-05 11:00:01,0.567045802305 2011-08-05 12:00:01,0.452915473859 2011-08-05 13:00:01,0.496396431493 2011-08-05 14:00:01,0.470616936536 2011-08-05 15:00:01,0.427549619485 2011-08-05 16:00:01,0.378977633828 2011-08-05 17:00:01,0.332794411519 2011-08-05 18:00:01,0.268990764623 2011-08-05 19:00:01,0.274022173834 2011-08-05 20:00:01,0.251701544928 2011-08-05 21:00:01,0.241048360814 2011-08-05 22:00:01,0.246216858429 2011-08-05 23:00:01,0.215926329509 2011-08-06 00:00:01,0.249949816738 2011-08-06 01:00:01,0.158907963264 2011-08-06 02:00:01,0.137552866091 2011-08-06 03:00:01,0.197561654283 2011-08-06 04:00:01,0.288752499144 2011-08-06 05:00:01,0.381611047047 2011-08-06 06:00:01,0.273987644537 2011-08-06 07:00:01,0.500351036795 2011-08-06 08:00:01,0.580597323769 2011-08-06 09:00:01,0.430048801113 2011-08-06 10:00:01,0.420263604131 2011-08-06 11:00:01,0.534715574142 2011-08-06 12:00:01,0.751038636193 2011-08-06 13:00:01,0.526120396749 2011-08-06 14:00:01,0.560445151722 2011-08-06 15:00:01,0.405883598938 2011-08-06 16:00:01,0.447607191665 2011-08-06 17:00:01,0.369951829013 2011-08-06 18:00:01,0.349190198989 2011-08-06 19:00:01,0.300690835019 2011-08-06 20:00:01,0.34599954003 2011-08-06 21:00:01,0.310183250683 2011-08-06 22:00:01,0.394767069663 2011-08-06 23:00:01,0.308900212146 2011-08-07 00:00:01,0.30013037612 2011-08-07 01:00:01,0.257981928706 2011-08-07 02:00:01,0.220632140194 2011-08-07 03:00:01,0.213772281907 2011-08-07 04:00:01,0.255685414881 2011-08-07 05:00:01,0.329683456102 2011-08-07 06:00:01,0.265684254769 2011-08-07 07:00:01,0.442110689396 2011-08-07 08:00:01,0.705293375736 2011-08-07 09:00:01,0.48961762587 2011-08-07 10:00:01,0.570971602411 2011-08-07 11:00:01,0.22696418004 2011-08-07 12:00:01,0.625506089104 2011-08-07 13:00:01,0.58756714546 2011-08-07 14:00:01,0.494468355527 2011-08-07 15:00:01,0.485719475295 2011-08-07 16:00:01,0.343257645616 2011-08-07 17:00:01,0.326607707109 2011-08-07 18:00:01,0.295759445392 2011-08-07 19:00:01,0.255623742077 2011-08-07 20:00:01,0.2688082445 2011-08-07 21:00:01,0.1781069836 2011-08-07 22:00:01,0.203492220123 2011-08-07 23:00:01,0.181770487756 2011-08-08 00:00:01,0.158421474179 2011-08-08 01:00:01,0.147071211249 2011-08-08 02:00:01,0.121540243196 2011-08-08 03:00:01,0.0939121008678 2011-08-08 04:00:01,0.125770320237 2011-08-08 05:00:01,0.173913163759 2011-08-08 06:00:01,0.164388738427 2011-08-08 07:00:01,0.311083305709 2011-08-08 08:00:01,0.538720538721 2011-08-08 09:00:01,0.427245038836 2011-08-08 10:00:01,0.504777937317 2011-08-08 11:00:01,0.642475589125 2011-08-08 12:00:01,0.552252988884 2011-08-08 13:00:01,0.475174437756 2011-08-08 14:00:01,0.488050599086 2011-08-08 15:00:01,0.437199279633 2011-08-08 16:00:01,0.371820079252 2011-08-08 17:00:01,0.310788044919 2011-08-08 19:00:01,0.303475913506 2011-08-08 20:00:01,0.1854877826 2011-08-08 21:00:01,0.228444369989 2011-08-08 22:00:01,0.228988961458 2011-08-08 23:00:01,0.224449362654 2011-08-09 00:00:01,0.166602366156 2011-08-09 01:00:01,0.136542467022 2011-08-09 02:00:01,0.131424755232 2011-08-09 03:00:01,0.120690831531 2011-08-09 04:00:01,0.118270279458 2011-08-09 05:00:01,0.162574348651 2011-08-09 06:00:01,0.178186039626 2011-08-09 07:00:01,0.303853030489 2011-08-09 08:00:01,0.550789527651 2011-08-09 09:00:01,0.441010177158 2011-08-09 10:00:01,0.530068153571 2011-08-09 11:00:01,0.464782413638 2011-08-09 12:00:01,0.480716903095 2011-08-09 13:00:01,0.438503988458 2011-08-09 14:00:01,0.344222628775 2011-08-09 15:00:01,0.164215514352 2011-08-09 16:00:01,0.451334552102 2011-08-09 17:00:01,0.488523409429 2011-08-09 18:00:01,0.301641007852 2011-08-09 19:00:01,0.262345464648 2011-08-09 20:00:01,0.271071656625 2011-08-09 21:00:01,0.257790414093 2011-08-09 22:00:01,0.293765610568 2011-08-09 23:00:01,0.20190184698 2011-08-10 00:00:01,0.180893592905 2011-08-10 01:00:01,0.183241464642 2011-08-10 02:00:01,0.152546971805 2011-08-10 03:00:01,0.121649223991 2011-08-10 04:00:01,0.132782550453 2011-08-10 05:00:01,0.191172813493 2011-08-10 06:00:01,0.247488073346 2011-08-10 07:00:01,0.307326101538 2011-08-10 08:00:01,0.354036794891 2011-08-10 09:00:01,0.517268550509 2011-08-10 10:00:01,0.457137065099 2011-08-10 11:00:01,0.546461283701 2011-08-10 12:00:01,0.450287840718 2011-08-10 13:00:01,0.482360222818 2011-08-10 14:00:01,0.485721764645 2011-08-10 15:00:01,0.587476998888 2011-08-10 17:00:01,0.948150721473 2011-08-10 18:00:01,0.65729071692 2011-08-10 19:00:01,0.182410748433 2011-08-10 20:00:01,0.210126419891 2011-08-10 21:00:01,0.335356850457 2011-08-10 22:00:01,0.298046930123 2011-08-10 23:00:01,0.238643552035 2011-08-11 00:00:01,0.212103377903 2011-08-11 01:00:01,0.185923903004 2011-08-11 02:00:01,0.154776075863 2011-08-11 03:00:01,0.13665744862 2011-08-11 04:00:01,0.160230773158 2011-08-11 05:00:01,0.210830475115 2011-08-11 06:00:01,0.286224224343 2011-08-11 07:00:01,0.436791095675 2011-08-11 08:00:01,0.461444787544 2011-08-11 09:00:01,0.576718213058 2011-08-11 10:00:01,0.678798876943 2011-08-11 11:00:01,0.543104312101 2011-08-11 12:00:01,0.651850316551 2011-08-11 13:00:01,0.515319777893 2011-08-11 14:00:01,0.567822431348 2011-08-11 15:00:01,0.476313569699 2011-08-11 16:00:01,0.410222140289 2011-08-11 17:00:01,0.37021457723 2011-08-11 18:00:01,0.0360733895514 2011-08-11 19:00:01,0.323799955347 2011-08-11 20:00:01,0.343160724482 2011-08-11 21:00:01,0.397203435066 2011-08-11 22:00:01,0.315529764651 2011-08-11 23:00:01,0.30144478392 2011-08-12 00:00:01,0.26762085518 2011-08-12 01:00:01,0.233376729833 2011-08-12 02:00:01,0.194452765968 2011-08-12 03:00:01,0.138647787561 2011-08-12 04:00:01,0.213030424064 2011-08-12 05:00:01,0.258790799987 2011-08-12 06:00:01,0.24952092977 2011-08-12 07:00:01,0.276817816874 2011-08-12 08:00:01,1.0514424748 2011-08-12 09:00:01,0.550761758252 2011-08-12 10:00:01,0.555629306912 2011-08-12 11:00:01,0.609984557353 2011-08-12 12:00:01,0.577830188679 2011-08-12 13:00:01,0.590268886044 2011-08-12 14:00:01,0.552825126341 2011-08-12 15:00:01,0.491198332529 2011-08-12 16:00:01,0.410258361313 2011-08-12 17:00:01,0.33909556486 2011-08-12 18:00:01,0.286050702466 2011-08-12 19:00:01,0.323586496548 2011-08-12 20:00:01,0.304786649345 2011-08-12 21:00:01,0.255882392047 2011-08-12 22:00:01,0.247207914596 2011-08-12 23:00:01,0.250140836151 2011-08-13 00:00:01,0.25194385834 2011-08-13 01:00:01,0.258218632693 2011-08-13 02:00:01,0.226015539942 2011-08-13 03:00:01,0.159070977107 2011-08-13 04:00:01,0.211005513585 2011-08-13 05:00:01,0.247687565773 2011-08-13 06:00:01,0.282709693961 2011-08-13 07:00:01,0.424723840371 2011-08-13 08:00:01,0.543314721321 2011-08-13 09:00:01,0.61625 2011-08-13 10:00:01,0.654440319992 2011-08-13 11:00:01,0.635822510823 2011-08-13 12:00:01,0.821226108237 2011-08-13 13:00:01,0.842164545573 2011-08-13 14:00:01,0.731631892872 2011-08-13 15:00:01,0.540964671767 2011-08-13 16:00:01,0.455897653464 2011-08-13 17:00:01,0.374288563715 2011-08-13 18:00:01,0.319265175906 2011-08-13 19:00:01,0.307065473481 2011-08-13 20:00:01,0.273386162835 2011-08-13 21:00:01,0.260776318994 2011-08-13 22:00:01,0.286839076795 2011-08-13 23:00:01,0.278639375568 2011-08-14 00:00:01,0.305872772168 2011-08-14 01:00:01,0.287767656453 2011-08-14 02:00:01,0.266756655086 2011-08-14 03:00:01,0.261519269562 2011-08-14 04:00:01,0.279994138609 2011-08-14 05:00:01,0.357949130112 2011-08-14 06:00:01,0.395057867769 2011-08-14 07:00:01,0.514521207708 2011-08-14 08:00:01,0.532560172426 2011-08-14 09:00:01,0.476172430128 2011-08-14 10:00:01,0.60236216865 2011-08-14 11:00:01,0.644956314535 2011-08-14 12:00:01,0.697846165352 2011-08-14 13:00:01,0.698616430321 2011-08-14 14:00:01,0.705035886297 2011-08-14 15:00:01,0.617404347988 2011-08-14 16:00:01,0.51239017303 2011-08-14 17:00:01,0.403875086121 2011-08-14 18:00:01,0.374578723674 2011-08-14 19:00:01,0.285211260801 2011-08-14 20:00:01,0.258318839399 2011-08-14 21:00:01,0.247235485434 2011-08-14 22:00:01,0.252419295524 2011-08-14 23:00:01,0.215061345367 2011-08-15 00:00:01,0.219272374672 2011-08-15 01:00:01,0.259993491349 2011-08-15 02:00:01,0.112465680559 2011-08-15 03:00:01,0.129889907492 2011-08-15 04:00:01,0.184368853672 2011-08-15 05:00:01,0.291590392801 2011-08-15 06:00:01,0.354687066255 2011-08-15 07:00:01,0.369693934663 2011-08-15 08:00:01,0.616148756951 2011-08-15 09:00:01,0.571445358402 2011-08-15 10:00:01,0.571309896915 2011-08-15 11:00:01,0.763170368917 2011-08-15 12:00:01,0.542183415828 2011-08-15 13:00:01,0.624161269619 2011-08-15 14:00:01,0.577879875789 2011-08-15 15:00:01,0.674388083594 2011-08-15 16:00:01,0.465648351938 2011-08-15 17:00:01,0.379129244052 2011-08-15 18:00:01,0.377605768531 2011-08-15 19:00:01,0.295029612795 2011-08-15 20:00:01,0.294380946024 2011-08-15 21:00:01,0.286841907435 2011-08-16 00:00:01,0.643067449002 2011-08-16 01:00:01,0.111433485031 2011-08-16 02:00:01,0.167272282104 2011-08-16 03:00:01,0.136371705472 2011-08-16 04:00:01,0.178216551315 2011-08-16 05:00:01,0.213757839048 2011-08-16 06:00:01,0.24371422548 2011-08-16 07:00:01,0.397670672215 2011-08-16 08:00:01,0.569862575619 2011-08-16 09:00:01,0.615672379046 2011-08-16 10:00:01,0.565135026756 2011-08-16 11:00:01,0.649623908579 2011-08-16 12:00:01,0.684601825906 2011-08-16 13:00:01,0.649529655839 2011-08-16 14:00:01,0.761553756413 2011-08-16 15:00:01,0.547737809294 2011-08-16 16:00:01,0.414905863704 2011-08-16 17:00:01,0.345750477303 2011-08-16 18:00:01,0.290037711535 2011-08-16 19:00:01,0.291690037489 2011-08-16 20:00:01,0.251921989966 2011-08-16 21:00:01,0.253541172643 2011-08-16 22:00:01,0.232801250976 2011-08-16 23:00:01,0.217425777744 2011-08-17 00:00:01,0.23586630843 2011-08-17 01:00:01,0.195312307046 2011-08-17 02:00:01,0.195701468993 2011-08-17 03:00:01,0.204026143655 2011-08-17 04:00:01,0.147768401599 2011-08-17 05:00:01,0.268017002427 2011-08-17 06:00:01,0.265700570732 2011-08-17 07:00:01,0.398809933274 2011-08-17 08:00:01,0.457430227251 2011-08-17 09:00:01,0.652012359682 2011-08-17 10:00:01,0.581056523374 2011-08-17 11:00:01,0.484555758969 2011-08-17 12:00:01,0.510756497832 2011-08-17 13:00:01,0.552549276311 2011-08-17 14:00:01,0.528956989498 2011-08-17 15:00:01,0.49939939015 2011-08-17 16:00:01,0.444223371391 2011-08-17 17:00:01,0.345758932585 2011-08-17 18:00:01,0.356207628528 2011-08-17 19:00:01,0.365411529986 2011-08-17 20:00:01,0.303964545498 2011-08-17 21:00:01,0.312720759806 2011-08-17 22:00:01,0.265141882694 2011-08-17 23:00:01,0.203903533414 2011-08-18 00:00:01,0.201826116196 2011-08-18 01:00:01,0.176334283725 2011-08-18 02:00:01,0.168131389871 2011-08-18 03:00:01,0.126134290765 2011-08-18 04:00:01,0.148568237737 2011-08-18 05:00:01,0.185830771529 2011-08-18 06:00:01,0.191789020266 2011-08-18 07:00:01,0.357648865878 2011-08-18 08:00:01,0.563748550423 2011-08-18 09:00:01,0.621535383035 2011-08-18 10:00:01,0.651507000683 2011-08-18 11:00:01,0.552312904633 2011-08-18 12:00:01,0.561417986445 2011-08-18 13:00:01,0.472352077362 2011-08-18 14:00:01,0.457558336152 2011-08-18 15:00:01,0.514818687278 2011-08-18 16:00:01,0.440904397665 2011-08-18 17:00:01,0.438773033624 2011-08-18 18:00:01,0.384591481943 2011-08-18 19:00:01,0.3398700712 2011-08-18 20:00:01,0.278668738629 2011-08-18 21:00:01,0.288797207236 2011-08-18 22:00:01,0.267286115268 2011-08-18 23:00:01,0.223896266296 2011-08-19 00:00:01,0.203410801178 2011-08-19 01:00:01,0.175413151105 2011-08-19 02:00:01,0.166775150428 2011-08-19 03:00:01,0.12467887362 2011-08-19 04:00:01,0.193797788902 2011-08-19 05:00:01,0.193257346049 2011-08-19 06:00:01,0.241784594303 2011-08-19 07:00:01,0.468629026368 2011-08-19 08:00:01,0.578231585846 2011-08-19 09:00:01,0.654648474223 2011-08-19 10:00:01,0.59239963224 2011-08-19 11:00:01,0.632796894433 2011-08-19 12:00:01,0.654688066566 2011-08-19 13:00:01,0.860451897115 2011-08-19 14:00:01,0.568877159379 2011-08-19 15:00:01,0.548794271092 2011-08-19 16:00:01,0.43334728228 2011-08-19 17:00:01,0.32739514291 2011-08-19 18:00:01,0.287733789679 2011-08-19 19:00:01,0.333736493864 2011-08-19 20:00:01,0.267481161941 2011-08-19 21:00:01,0.253034377498 2011-08-19 22:00:01,0.279273210119 2011-08-19 23:00:01,0.230464507263 2011-08-20 00:00:01,0.217553267932 2011-08-20 01:00:01,0.222056393582 2011-08-20 02:00:01,0.181206110186 2011-08-20 03:00:01,0.146636380481 2011-08-20 04:00:01,0.175709562939 2011-08-20 05:00:01,0.253476618725 2011-08-20 06:00:01,0.221588241906 2011-08-20 07:00:01,0.40262623301 2011-08-20 08:00:01,0.538118423632 2011-08-20 09:00:01,0.537468938811 2011-08-20 10:00:01,0.556407936321 2011-08-20 11:00:01,0.56064608442 2011-08-20 12:00:01,0.73048260471 2011-08-20 13:00:01,0.6854003862 2011-08-20 14:00:01,0.637795142698 2011-08-20 15:00:01,0.490752336998 2011-08-20 16:00:01,0.449458814896 2011-08-20 17:00:01,0.31548826994 2011-08-20 18:00:01,0.27838088113 2011-08-20 19:00:01,0.236309268997 2011-08-20 20:00:01,0.235254469267 2011-08-20 21:00:01,0.220512119377 2011-08-20 22:00:01,0.232456508137 2011-08-20 23:00:01,0.240371118336 2011-08-21 00:00:01,0.195062405022 2011-08-21 01:00:01,0.219409444296 2011-08-21 02:00:01,0.154082530934 2011-08-21 03:00:01,0.124101873028 2011-08-21 04:00:01,0.161069173093 2011-08-21 05:00:01,0.224335890393 2011-08-21 06:00:01,0.201105728499 2011-08-21 07:00:01,0.327890515953 2011-08-21 08:00:01,0.587823439878 2011-08-21 09:00:01,0.490445812012 2011-08-21 10:00:01,0.523634418667 2011-08-21 11:00:01,0.601553131959 2011-08-21 12:00:01,0.512415566677 2011-08-21 13:00:01,0.530476204522 2011-08-21 14:00:01,0.493195327382 2011-08-21 15:00:01,0.476013601353 2011-08-21 16:00:01,0.32574985779 2011-08-21 17:00:01,0.261994654275 2011-08-21 18:00:01,0.221285300868 2011-08-21 19:00:01,0.210531741765 2011-08-21 20:00:01,0.201633388977 2011-08-21 21:00:01,0.186981062174 2011-08-21 22:00:01,0.177261959255 2011-08-21 23:00:01,0.176000818212 2011-08-22 00:00:01,0.151385433559 2011-08-22 01:00:01,0.136277320086 2011-08-22 02:00:01,0.110605455837 2011-08-22 03:00:01,0.106407187978 2011-08-22 04:00:01,0.123628854559 2011-08-22 05:00:01,0.17403044894 2011-08-22 06:00:01,0.157171522962 2011-08-22 07:00:01,0.294450489663 2011-08-22 08:00:01,0.667178411573 2011-08-22 09:00:01,0.534268392243 2011-08-22 10:00:01,0.531195462478 2011-08-22 11:00:01,0.527912545288 2011-08-22 12:00:01,0.515761625039 2011-08-22 13:00:01,0.55597207644 2011-08-22 14:00:01,0.519979853441 2011-08-22 15:00:01,0.394642121307 2011-08-22 16:00:01,0.373577168902 2011-08-22 17:00:01,0.2985790942 2011-08-22 18:00:01,0.307674114188 2011-08-22 19:00:01,0.340823750741 2011-08-22 20:00:01,0.335536583127 2011-08-22 21:00:01,0.345641197072 2011-08-22 22:00:01,0.273107112762 2011-08-22 23:00:01,0.155089425029 2011-08-23 00:00:01,0.123046532451 2011-08-23 01:00:01,0.160052421603 2011-08-23 02:00:01,0.0853665712587 2011-08-23 03:00:01,0.0899181896878 2011-08-23 04:00:01,0.121679410333 2011-08-23 05:00:01,0.171454019149 2011-08-23 06:00:01,0.238440523194 2011-08-23 07:00:01,0.381339486702 2011-08-23 08:00:01,0.82047238811 2011-08-23 09:00:01,0.772525570956 2011-08-23 10:00:01,0.692144654921 2011-08-23 11:00:01,0.613436416955 2011-08-23 12:00:01,0.572794590446 2011-08-23 13:00:01,0.555439507425 2011-08-23 14:00:01,0.665397594531 2011-08-23 15:00:01,0.458677384758 2011-08-23 16:00:01,0.272270417989 2011-08-23 17:00:01,0.327019749338 2011-08-23 18:00:01,0.290489487183 2011-08-23 19:00:01,0.279222240278 2011-08-23 20:00:01,0.233345064394 2011-08-23 21:00:01,0.226307303822 2011-08-23 22:00:01,0.258378562796 2011-08-23 23:00:01,0.176908471716 2011-08-24 00:00:01,0.245062179956 2011-08-24 01:00:01,0.172705171911 2011-08-24 02:00:01,0.136768867789 2011-08-24 03:00:01,0.0966510269546 2011-08-24 04:00:01,0.118956597201 2011-08-24 05:00:01,0.160615189472 2011-08-24 06:00:01,0.199960472355 2011-08-24 07:00:01,0.361688633264 2011-08-24 08:00:01,0.533729073915 2011-08-24 09:00:01,0.732902126515 2011-08-24 10:00:01,0.412975208722 2011-08-24 11:00:01,0.54914424154 2011-08-24 12:00:01,0.408489668886 2011-08-24 12:00:01,0.461744524861 2011-08-24 13:00:01,0.486782694693 2011-08-24 14:00:01,0.443630395224 2011-08-24 15:00:01,0.395182983036 2011-08-24 16:00:01,0.31286904473 2011-08-24 17:00:01,0.359353179254 2011-08-24 18:00:01,0.393515741335 2011-08-24 19:00:01,0.344992829914 2011-08-24 20:00:01,0.269384611013 2011-08-24 21:00:01,0.407613767872 2011-08-24 22:00:01,0.173129266121 2011-08-24 23:00:01,0.216109054976 2011-08-25 00:00:01,0.175930985902 2011-08-25 01:00:01,0.169038558828 2011-08-25 02:00:01,0.147807538989 2011-08-25 03:00:01,0.105627064622 2011-08-25 04:00:01,0.000385004945833 2011-08-25 05:00:01,0.461301616821 2011-08-25 06:00:01,0.233271621264 2011-08-25 07:00:01,0.468516100264 2011-08-25 08:00:01,0.581226855579 2011-08-25 09:00:01,0.63461901101 2011-08-25 10:00:01,0.566099898297 2011-08-25 11:00:01,0.493856166154 2011-08-25 12:00:01,0.510208394978 2011-08-25 13:00:01,0.598881695115 2011-08-25 14:00:01,0.470719757998 2011-08-25 15:00:01,0.487960478101 2011-08-25 16:00:01,0.40945390361 2011-08-25 17:00:01,0.398078876882 2011-08-25 18:00:01,0.28019152332 2011-08-25 19:00:01,0.241039451792 2011-08-25 20:00:01,0.381863230297 2011-08-25 21:00:01,0.245432579188 2011-08-25 22:00:01,0.234515320987 2011-08-25 23:00:01,0.206420721247 2011-08-26 00:00:01,0.172429499479 2011-08-26 01:00:01,0.159241958671 2011-08-26 02:00:01,0.155278229609 2011-08-26 03:00:01,0.118453611679 2011-08-26 04:00:01,0.240569535561 2011-08-26 05:00:01,0.22545800559 2011-08-26 06:00:01,0.279070573154 2011-08-26 07:00:01,0.56754661185 2011-08-26 08:00:01,0.561253351042 2011-08-26 09:00:01,0.641437375228 2011-08-26 10:00:01,0.820133388912 2011-08-26 11:00:01,0.493383546972 2011-08-26 12:00:01,0.547982528587 2011-08-26 13:00:01,0.622099310054 2011-08-26 14:00:01,0.512080118077 2011-08-26 15:00:01,0.507217005562 2011-08-26 16:00:01,0.489108910891 2011-08-26 17:00:01,0.424249760079 2011-08-26 18:00:01,0.412710194262 2011-08-26 19:00:01,0.34001279045 2011-08-26 20:00:01,0.326853774051 2011-08-26 21:00:01,0.28062583972 2011-08-26 22:00:01,0.252289920805 2011-08-26 23:00:01,0.291602799682 2011-08-27 00:00:01,0.215436933318 2011-08-27 01:00:01,0.220260936301 2011-08-27 02:00:01,0.186717041518 2011-08-27 03:00:01,0.176219012927 2011-08-27 04:00:01,0.231765575966 2011-08-27 05:00:01,0.275286303963 2011-08-27 06:00:01,0.264370483326 2011-08-27 07:00:01,0.400318162503 2011-08-27 08:00:01,0.622545622546 2011-08-27 09:00:01,0.633239680138 2011-08-27 10:00:01,0.650044871045 2011-08-27 11:00:01,0.734008493956 2011-08-27 12:00:01,0.598190302441 2011-08-27 13:00:01,0.633516598232 2011-08-27 14:00:01,0.475215553114 2011-08-27 15:00:01,0.463420456765 2011-08-27 16:00:01,0.386224238408 2011-08-27 17:00:01,0.328932749121 2011-08-27 18:00:01,0.322341586383 2011-08-27 19:00:01,0.314598024411 2011-08-27 20:00:01,0.298952180319 2011-08-27 21:00:01,0.294076404898 2011-08-27 22:00:01,0.246401440725 2011-08-27 23:00:01,0.235950187027 2011-08-28 00:00:01,0.207632234838 2011-08-28 01:00:01,0.168988587332 2011-08-28 02:00:01,0.141435536447 2011-08-28 03:00:01,0.126585685019 2011-08-28 04:00:01,0.183147548843 2011-08-28 05:00:01,0.2020204139 2011-08-28 06:00:01,0.255996614921 2011-08-28 07:00:01,0.29123345193 2011-08-28 08:00:01,0.540378503706 2011-08-28 09:00:01,0.527062539326 2011-08-28 10:00:01,0.549995516097 2011-08-28 11:00:01,0.55179662353 2011-08-28 12:00:01,0.599372992958 2011-08-28 13:00:01,0.559588399094 2011-08-28 14:00:01,0.511762469039 2011-08-28 15:00:01,0.423079453978 2011-08-28 16:00:01,0.36398231864 2011-08-28 17:00:01,0.316098691924 2011-08-28 18:00:01,0.266430646333 2011-08-28 19:00:01,0.239828768926 2011-08-28 20:00:01,0.193407373847 2011-08-28 21:00:01,0.208397747608 2011-08-28 22:00:01,0.21315769397 2011-08-28 23:00:01,0.182707732595 2011-08-29 00:00:01,0.148677099386 2011-08-29 01:00:01,0.122675363449 2011-08-29 02:00:01,0.109181934384 2011-08-29 03:00:01,0.0892852563938 2011-08-29 04:00:01,0.124574945593 2011-08-29 05:00:01,0.176364561503 2011-08-29 06:00:01,0.202152459227 2011-08-29 07:00:01,0.33298712252 2011-08-29 08:00:01,0.534548955745 2011-08-29 09:00:01,0.64617045722 2011-08-29 10:00:01,0.676532123822 2011-08-29 11:00:01,0.489383195143 2011-08-29 12:00:01,0.40194279738 2011-08-29 13:00:01,0.54963816923 2011-08-29 14:00:01,0.434075134761 2011-08-29 15:00:01,0.435051944804 2011-08-29 16:00:01,0.431632394009 2011-08-29 17:00:01,0.330456971831 2011-08-29 18:00:01,0.301809771023 2011-08-29 19:00:01,0.350951347332 2011-08-29 20:00:01,0.25222889109 2011-08-29 21:00:01,0.241087185555 2011-08-29 22:00:01,0.241589040418 2011-08-29 23:00:01,0.281068471368 2011-08-30 00:00:01,0.206532492386 2011-08-30 01:00:01,0.152663766787 2011-08-30 02:00:01,0.131335780603 2011-08-30 03:00:01,0.109843853676 2011-08-30 04:00:01,0.25651510021 2011-08-30 05:00:01,0.311446035534 2011-08-30 06:00:01,0.283640212075 2011-08-30 07:00:01,0.44263013013 2011-08-30 08:00:01,0.648082483225 2011-08-30 09:00:01,0.791351906205 2011-08-30 10:00:01,0.418384632595 2011-08-30 11:00:01,0.448443602516 2011-08-30 12:00:01,0.435691108365 2011-08-30 13:00:01,0.439349301909 2011-08-30 14:00:01,0.326906301027 2011-08-30 15:00:01,0.447574697018 2011-08-30 16:00:01,0.4682634356 2011-08-30 17:00:01,0.362289894575 2011-08-30 18:00:01,0.3538050999 2011-08-30 19:00:01,0.356699998273 2011-08-30 20:00:01,0.354342033138 2011-08-30 21:00:01,0.300823483278 2011-08-30 22:00:01,0.255876324836 2011-08-30 23:00:01,0.263742533346 2011-08-31 00:00:01,0.241733293219 2011-08-31 01:00:01,0.187582254993 2011-08-31 02:00:01,0.162264258936 2011-08-31 03:00:01,0.144376676817 2011-08-31 04:00:01,0.231260053619 2011-08-31 05:00:01,0.456911647336 2011-08-31 06:00:01,0.329230985394 2011-08-31 07:00:01,0.39677837734 2011-08-31 08:00:01,0.621348463494 2011-08-31 09:00:01,0.533931484502 2011-08-31 10:00:01,0.537277018546 2011-08-31 11:00:01,0.450036545891 2011-08-31 12:00:01,0.57521395655 2011-08-31 13:00:01,0.43598099531 2011-08-31 14:00:01,0.482761582341 2011-08-31 15:00:01,0.394738224019 2011-08-31 16:00:01,0.421161390641 2011-08-31 17:00:01,0.361342866699 2011-08-31 18:00:01,0.408855917468 2011-08-31 19:00:01,0.493310546466 2011-08-31 20:00:01,0.491194901203 2011-08-31 21:00:01,0.494053140395 2011-08-31 22:00:01,0.342674749528 2011-08-31 23:00:01,0.344078797404 2011-09-01 00:00:01,0.216449062676 2011-09-01 01:00:01,0.197612674167 2011-09-01 02:00:01,0.157555506338 2011-09-01 03:00:01,0.129452284039 2011-09-01 04:00:01,0.265415755215 2011-09-01 05:00:01,0.414916925324 2011-09-01 06:00:01,0.436399536493 2011-09-01 07:00:01,0.510638297872 2011-09-01 08:00:01,0.667334565042 2011-09-01 09:00:01,0.683456790123 2011-09-01 10:00:01,0.736830389086 2011-09-01 11:00:01,0.572532679915 2011-09-01 12:00:01,0.420446983591 2011-09-01 13:00:01,0.528570163362 2011-09-01 14:00:01,0.412298289967 2011-09-01 15:00:01,0.490840855649 2011-09-01 16:00:01,0.428572872891 2011-09-01 17:00:01,0.344159041135 2011-09-01 18:00:01,0.362985835006 2011-09-02 15:00:01,0.29474600602 2011-09-02 16:00:01,0.485279887016 2011-09-02 17:00:01,0.41176305761 2011-09-02 18:00:01,0.410321629465 2011-09-02 19:00:01,0.361436552275 2011-09-02 20:00:01,0.330957212541 2011-09-02 21:00:01,0.276432333565 2011-09-02 22:00:01,0.291694292981 2011-09-02 23:00:01,0.301794690505 2011-09-03 00:00:01,0.291617242099 2011-09-03 01:00:01,0.277953194651 2011-09-03 02:00:01,0.248127176169 2011-09-03 03:00:01,0.169511707947 2011-09-03 04:00:01,0.249690391588 2011-09-03 05:00:01,0.385299625468 2011-09-03 06:00:01,0.384656257837 2011-09-03 07:00:01,0.376194161285 2011-09-03 08:00:01,0.578187102424 2011-09-03 09:00:01,0.729936189191 2011-09-03 10:00:01,0.673216449006 2011-09-03 11:00:01,0.61254001409 2011-09-03 12:00:01,0.641445854126 2011-09-03 13:00:01,0.588598734069 2011-09-03 14:00:01,0.570395805255 2011-09-03 15:00:01,0.472354497354 2011-09-03 16:00:01,0.37974110345 2011-09-03 17:00:01,0.350129181052 2011-09-03 18:00:01,0.275710950256 2011-09-03 19:00:01,0.28777674021 2011-09-03 20:00:01,0.265807976651 2011-09-03 21:00:01,0.278050562952 2011-09-03 22:00:01,0.28659804327 2011-09-03 23:00:01,0.262018924352 2011-09-04 00:00:01,0.259513603461 2011-09-04 01:00:01,0.246324607821 2011-09-04 02:00:01,0.209808549698 2011-09-04 03:00:01,0.17836460505 2011-09-04 04:00:01,0.245289560099 2011-09-04 05:00:01,0.344276292442 2011-09-04 06:00:01,0.306586474989 2011-09-04 07:00:01,0.430391276139 2011-09-04 08:00:01,0.547901341411 2011-09-04 09:00:01,0.641821064842 2011-09-04 10:00:01,0.81641030904 2011-09-04 11:00:01,0.670888581041 2011-09-04 12:00:01,0.614528069363 2011-09-04 13:00:01,0.612822169574 2011-09-04 14:00:01,0.579268292683 2011-09-04 15:00:01,0.485615808491 2011-09-04 16:00:01,0.402082460157 2011-09-04 17:00:01,0.375212989741 2011-09-04 18:00:01,0.307740145091 2011-09-04 19:00:01,0.27382792936 2011-09-04 20:00:01,0.246910383732 2011-09-04 21:00:01,0.228353890665 2011-09-04 22:00:01,0.233535193639 2011-09-04 23:00:01,0.215548571638 2011-09-05 00:00:01,0.225015080971 2011-09-05 01:00:01,0.209993129869 2011-09-05 02:00:01,0.15313251846 2011-09-05 03:00:01,0.119231002264 2011-09-05 04:00:01,0.165732017867 2011-09-05 05:00:01,0.230474174382 2011-09-05 06:00:01,0.233619482907 2011-09-05 07:00:01,0.284188650927 2011-09-05 08:00:01,0.550548728064 2011-09-05 09:00:01,0.728971054847 2011-09-05 10:00:01,0.530146611013 2011-09-05 11:00:01,0.67969179967 2011-09-05 12:00:01,0.56956630077 2011-09-05 13:00:01,0.558141252955 2011-09-05 14:00:01,0.503757754924 2011-09-05 15:00:01,0.387006146845 2011-09-05 16:00:01,0.360744566447 2011-09-05 17:00:01,0.262992239088 2011-09-05 18:00:01,0.266060699999 2011-09-05 19:00:01,0.240317359828 2011-09-05 20:00:01,0.226144185194 2011-09-05 21:00:01,0.20473812416 2011-09-05 22:00:01,0.174043818091 2011-09-05 23:00:01,0.172111187824 2011-09-06 00:00:01,0.181676539327 2011-09-06 01:00:01,0.166772823961 2011-09-06 02:00:01,0.105305627274 2011-09-06 03:00:01,0.0892502429895 2011-09-06 04:00:01,0.163954560416 2011-09-06 05:00:01,0.188989727735 2011-09-06 06:00:01,0.215441237057 2011-09-06 07:00:01,0.445466462263 2011-09-06 08:00:01,0.514810677555 2011-09-06 09:00:01,0.497141778106 2011-09-06 10:00:01,0.601606052562 2011-09-06 11:00:01,0.400448117791 2011-09-06 12:00:01,0.385146130933 2011-09-06 13:00:01,0.451650113231 2011-09-06 14:00:01,0.414082425226 2011-09-06 15:00:01,0.425809421513 2011-09-06 16:00:01,0.342556508184 2011-09-06 17:00:01,0.325499873346 2011-09-06 18:00:01,0.180503882346 2011-09-06 19:00:01,0.557667699041 2011-09-06 20:00:01,0.367222540787 2011-09-06 21:00:01,0.464463472743 2011-09-06 22:00:01,0.327087544384 2011-09-06 23:00:01,0.277730265483 2011-09-07 00:00:01,0.288533644404 2011-09-07 01:00:01,0.2231056289 2011-09-07 02:00:01,0.151394339798 2011-09-07 03:00:01,0.133753737139 2011-09-07 04:00:01,0.153141093435 2011-09-07 05:00:01,0.240614655527 2011-09-07 06:00:01,0.307711918419 2011-09-07 07:00:01,0.391228851975 2011-09-07 08:00:01,0.562866797083 2011-09-07 09:00:01,0.572038880615 2011-09-07 10:00:01,0.587186345688 2011-09-07 11:00:01,0.343989530753 2011-09-07 12:00:01,0.404890624699 2011-09-07 13:00:01,0.441900001126 2011-09-07 14:00:01,0.285779485034 2011-09-07 15:00:01,0.378583558086 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/exchange-3_cpm_results.csv ================================================ timestamp,value 2011-07-01 00:15:01,0.405422534525 2011-07-01 01:15:01,0.433961278227 2011-07-01 02:15:01,0.389267501625 2011-07-01 03:15:01,0.368098502243 2011-07-01 04:15:01,0.365234426765 2011-07-01 05:15:01,0.3428794869 2011-07-01 06:15:01,0.320650020989 2011-07-01 07:15:01,0.328999171839 2011-07-01 08:15:01,0.330918820695 2011-07-01 09:15:01,0.396968683829 2011-07-01 10:15:01,0.44347161212 2011-07-01 11:15:01,0.662412074347 2011-07-01 12:15:01,0.707460331375 2011-07-01 13:15:01,0.597161557559 2011-07-01 14:15:01,0.600127175161 2011-07-01 15:15:01,0.534812246524 2011-07-01 16:15:01,0.46917505741 2011-07-01 17:15:01,0.505456517193 2011-07-01 18:15:01,0.4535763584 2011-07-01 19:15:01,0.579827163973 2011-07-01 20:15:01,0.929018598624 2011-07-01 21:15:01,0.481969218049 2011-07-01 22:15:01,1.59456911756 2011-07-01 23:15:01,3.02086765513 2011-07-02 00:15:01,2.82484901469 2011-07-02 01:15:01,1.01660459594 2011-07-02 02:15:01,0.550420623732 2011-07-02 03:15:01,0.689861668363 2011-07-02 04:15:01,0.643394562177 2011-07-02 05:15:01,0.603330401792 2011-07-02 06:15:01,0.60099737106 2011-07-02 07:15:01,0.644907856905 2011-07-02 08:15:01,0.619896282481 2011-07-02 09:15:01,0.711410835499 2011-07-02 10:15:01,0.823032683736 2011-07-02 11:15:01,0.982650117997 2011-07-02 12:15:01,1.82198845938 2011-07-02 13:15:01,1.4539117855 2011-07-02 14:15:01,1.33707622155 2011-07-02 15:15:01,1.08711717782 2011-07-02 16:15:01,0.91170299956 2011-07-02 17:15:01,0.803212193223 2011-07-02 18:15:01,1.11925182413 2011-07-02 19:15:01,0.747777030865 2011-07-02 20:15:01,0.79998925588 2011-07-02 21:15:01,0.765987648091 2011-07-02 22:15:01,0.705948517041 2011-07-02 23:15:01,1.45388610672 2011-07-03 00:15:01,1.38902113011 2011-07-03 01:15:01,0.925834177713 2011-07-03 02:15:01,0.831415320602 2011-07-03 03:15:01,0.483019261215 2011-07-03 04:15:01,0.693500280828 2011-07-03 05:15:01,0.680136615604 2011-07-03 06:15:01,0.696506878058 2011-07-03 07:15:01,0.742017606353 2011-07-03 08:15:01,0.713239099849 2011-07-03 09:15:01,0.757453614431 2011-07-03 10:15:01,0.963004377293 2011-07-03 11:15:01,1.6822211246 2011-07-03 12:15:01,2.07516028693 2011-07-03 13:15:01,1.94973024968 2011-07-03 14:15:01,1.38908773657 2011-07-03 15:15:01,1.11706077222 2011-07-03 16:15:01,1.00365466979 2011-07-03 17:15:01,0.959327269607 2011-07-03 18:15:01,0.835083924374 2011-07-03 19:15:01,0.814624009308 2011-07-03 20:15:01,0.827716419656 2011-07-03 21:15:01,0.882878070554 2011-07-03 22:15:01,0.997623517817 2011-07-03 23:15:01,1.74638339578 2011-07-04 00:15:01,1.43257308234 2011-07-04 01:15:01,0.943704898459 2011-07-04 02:15:01,0.558643628895 2011-07-04 03:15:01,0.715673181984 2011-07-04 04:15:01,0.732596504133 2011-07-04 05:15:01,0.640847995481 2011-07-04 06:15:01,0.623399850096 2011-07-04 07:15:01,0.674131851371 2011-07-04 08:15:01,0.781035713426 2011-07-04 09:15:01,0.684518122173 2011-07-04 10:15:01,0.899108227688 2011-07-04 11:15:01,1.63733247215 2011-07-04 12:15:01,1.74557145559 2011-07-04 13:15:01,1.97659441357 2011-07-04 14:15:01,1.58846906697 2011-07-04 15:15:01,1.04741587993 2011-07-04 16:15:01,0.678772584881 2011-07-04 17:15:01,0.602611129637 2011-07-04 18:15:01,0.570830160915 2011-07-04 19:15:01,0.550038076316 2011-07-04 20:15:01,0.59489693004 2011-07-04 21:15:01,0.582188580506 2011-07-04 22:15:01,0.675870716328 2011-07-04 23:15:01,1.05814892078 2011-07-05 00:15:01,1.09302018155 2011-07-05 01:15:01,0.619185328719 2011-07-05 02:15:01,0.546216679365 2011-07-05 03:15:01,0.43930623552 2011-07-05 04:15:01,0.464924821965 2011-07-05 05:15:01,0.457552001746 2011-07-05 06:15:01,0.426136705088 2011-07-05 07:15:01,0.463126895367 2011-07-05 08:15:01,0.470788232029 2011-07-05 09:15:01,0.438059738418 2011-07-05 10:15:01,0.750424972956 2011-07-05 11:15:01,0.787270610412 2011-07-05 12:15:01,1.07755946225 2011-07-05 13:15:01,0.998522373197 2011-07-05 14:15:01,0.952744270496 2011-07-05 15:15:01,0.707829298362 2011-07-05 16:15:01,0.612651923352 2011-07-05 17:15:01,0.582697780816 2011-07-05 18:15:01,0.650834949828 2011-07-05 19:15:01,0.616827982495 2011-07-05 20:15:01,0.588550728092 2011-07-05 21:15:01,0.525827739324 2011-07-05 22:15:01,0.580492705313 2011-07-05 23:15:01,0.850236788743 2011-07-06 00:15:01,0.989699069715 2011-07-06 01:15:01,0.542059746448 2011-07-06 02:15:01,0.417662676746 2011-07-06 03:15:01,0.42774941839 2011-07-06 04:15:01,0.42921970945 2011-07-06 05:15:01,0.407084105315 2011-07-06 06:15:01,0.419973474988 2011-07-06 07:15:01,0.419987213504 2011-07-06 08:15:01,0.419571904869 2011-07-06 09:15:01,0.542099108317 2011-07-06 10:15:01,0.523028762708 2011-07-06 11:15:01,0.860811277047 2011-07-06 12:15:01,1.03834696676 2011-07-06 13:15:01,1.02756469696 2011-07-06 14:15:01,0.726965750121 2011-07-06 15:15:01,0.697692029382 2011-07-06 16:15:01,0.61312845603 2011-07-06 17:15:01,0.589332440756 2011-07-06 18:15:01,0.70509726472 2011-07-06 19:15:01,0.684018898444 2011-07-06 20:15:01,0.453724582931 2011-07-06 21:15:01,0.689319329302 2011-07-06 22:15:01,0.56934558103 2011-07-06 23:15:01,0.593638974059 2011-07-07 00:15:01,0.495223004774 2011-07-07 01:15:01,0.533024251743 2011-07-07 02:15:01,0.513768520467 2011-07-07 05:15:01,0.484609943601 2011-07-07 06:15:01,0.372865059711 2011-07-07 07:15:01,0.580024914694 2011-07-07 08:15:01,0.448067683962 2011-07-07 09:15:01,0.613364729387 2011-07-07 10:15:01,0.618467559655 2011-07-07 11:15:01,0.838079048024 2011-07-07 12:15:01,1.2565580859 2011-07-07 13:15:01,1.14752664089 2011-07-07 14:15:01,1.01583644619 2011-07-07 15:15:01,0.913571537965 2011-07-07 16:15:01,0.618304360192 2011-07-07 17:15:01,0.763646369801 2011-07-07 18:15:01,0.764605470099 2011-07-07 19:15:01,1.21798800094 2011-07-07 20:15:01,1.01495047186 2011-07-07 21:15:01,1.03107344633 2011-07-07 22:15:01,0.876598530712 2011-07-07 23:15:01,0.552934085566 2011-07-08 00:15:01,0.49550387185 2011-07-08 01:15:01,0.847840103159 2011-07-08 02:15:01,0.643240884261 2011-07-08 06:15:01,0.706602697276 2011-07-08 09:15:01,0.681349823745 2011-07-08 10:15:01,0.590646181328 2011-07-08 14:15:01,1.24385033027 2011-07-08 16:15:01,2.59258016906 2011-07-08 17:15:01,1.3542439637 2011-07-08 18:15:01,0.700856342781 2011-07-08 19:15:01,0.970253925004 2011-07-08 20:15:01,1.18064743289 2011-07-08 21:15:01,1.04666954508 2011-07-08 22:15:01,1.09588027648 2011-07-08 23:15:01,0.989867032787 2011-07-09 09:15:01,0.722730241672 2011-07-09 15:15:01,0.672810392706 2011-07-09 17:15:01,0.730694412571 2011-07-09 18:15:01,1.1065965848 2011-07-09 19:15:01,0.951126681146 2011-07-09 20:15:01,0.86612700358 2011-07-09 21:15:01,0.822021986321 2011-07-09 22:15:01,1.03145922094 2011-07-09 23:15:01,1.16544612166 2011-07-10 00:15:01,1.05581045236 2011-07-10 01:15:01,0.933769979761 2011-07-10 02:15:01,0.852321869447 2011-07-10 03:15:01,0.562376237624 2011-07-10 04:15:01,0.690265027243 2011-07-10 05:15:01,0.661577265667 2011-07-10 06:15:01,0.683708791707 2011-07-10 07:15:01,0.585272294012 2011-07-10 08:15:01,0.725823769416 2011-07-10 09:15:01,1.06548190842 2011-07-10 10:15:01,0.812296171035 2011-07-10 11:15:01,1.15012216089 2011-07-10 12:15:01,1.91079022846 2011-07-10 13:15:01,1.89823760173 2011-07-10 14:15:01,1.60666972834 2011-07-10 15:15:01,1.36903179016 2011-07-10 16:15:01,1.23539136879 2011-07-10 17:15:01,1.30004968561 2011-07-10 18:15:01,1.02969040624 2011-07-10 19:15:01,0.932536450273 2011-07-10 20:15:01,0.931886464036 2011-07-10 21:15:01,0.863524014067 2011-07-10 22:15:01,0.991745182096 2011-07-10 23:15:01,0.862854251012 2011-07-11 00:15:01,0.747998448544 2011-07-11 01:15:01,0.850183503168 2011-07-11 02:15:01,0.654526695899 2011-07-11 03:15:01,0.728679424723 2011-07-11 04:15:01,0.690021862785 2011-07-11 05:15:01,0.698213122487 2011-07-11 06:15:01,0.638280829834 2011-07-11 07:15:01,0.671747063098 2011-07-11 08:15:01,0.641360186156 2011-07-11 09:15:01,0.588559867574 2011-07-11 10:15:01,0.97926990996 2011-07-11 11:15:01,2.03972428805 2011-07-11 12:15:01,1.43419613562 2011-07-11 13:15:01,1.50993833205 2011-07-11 14:15:01,1.39176641082 2011-07-11 15:15:01,1.10735535393 2011-07-11 16:15:01,0.997729716812 2011-07-11 17:15:01,0.838516364175 2011-07-11 18:15:01,0.591521865594 2011-07-11 19:15:01,0.523210749244 2011-07-11 20:15:01,0.50741379187 2011-07-11 21:15:01,0.538820681939 2011-07-11 22:15:01,0.537126366514 2011-07-11 23:15:01,0.575014047574 2011-07-12 00:15:01,0.434892834119 2011-07-12 01:15:01,0.568473258729 2011-07-12 02:15:01,0.576361277601 2011-07-12 03:15:01,0.561665799733 2011-07-12 04:15:01,0.506676771373 2011-07-12 05:15:01,0.532992059663 2011-07-12 06:15:01,0.533646651609 2011-07-12 07:15:01,0.543344592151 2011-07-12 08:15:01,0.63393689344 2011-07-12 09:15:01,0.673402868318 2011-07-12 10:15:01,0.670085200379 2011-07-12 11:15:01,0.702719812998 2011-07-12 12:15:01,0.995558682556 2011-07-12 13:15:01,1.16926536732 2011-07-12 14:15:01,1.01409928115 2011-07-12 15:15:01,0.996637659048 2011-07-12 16:15:01,0.679225381434 2011-07-12 17:15:01,0.75814025419 2011-07-12 18:15:01,0.763981210671 2011-07-12 19:15:01,0.708667855921 2011-07-12 20:15:01,0.714510023353 2011-07-12 21:15:01,0.762345540039 2011-07-12 22:15:01,0.703105906489 2011-07-12 23:15:01,0.707826549505 2011-07-13 00:15:01,0.57670519965 2011-07-13 01:15:01,0.679474448094 2011-07-13 02:15:01,0.557389600963 2011-07-13 03:15:01,0.531382043611 2011-07-13 04:15:01,0.529654200621 2011-07-13 05:15:01,0.519767135236 2011-07-13 06:15:01,0.512662431177 2011-07-13 07:15:01,0.555591534137 2011-07-13 08:15:01,0.656115012713 2011-07-13 09:15:01,0.78798286152 2011-07-13 10:15:01,0.692587249625 2011-07-13 11:15:01,0.935283109196 2011-07-13 12:15:01,1.07905121568 2011-07-13 13:15:01,1.26547389169 2011-07-13 14:15:01,0.758122743682 2011-07-13 15:15:01,0.861263139606 2011-07-13 16:15:01,0.818969842122 2011-07-13 17:15:01,0.781863718801 2011-07-13 18:15:01,0.754097953198 2011-07-13 19:15:01,0.734934125478 2011-07-13 20:15:01,0.690540979909 2011-07-13 21:15:01,0.729830698994 2011-07-13 22:15:01,0.75001446262 2011-07-13 23:15:01,0.788613597882 2011-07-14 00:15:01,0.599371499577 2011-07-14 01:15:01,0.618132010667 2011-07-14 02:15:01,0.492632136346 2011-07-14 03:15:01,0.433984949291 2011-07-14 04:15:01,0.401924624437 2011-07-14 05:15:01,0.391060382405 2011-07-14 06:15:01,0.394108266834 2011-07-14 07:15:01,0.414870889838 2011-07-14 08:15:01,0.459231967846 2011-07-14 09:15:01,0.554594329429 2011-07-14 10:15:01,0.586447433981 2011-07-14 11:15:01,0.774360121165 2011-07-14 12:15:01,1.09174200349 2011-07-14 13:15:01,1.02217110037 2011-07-14 14:15:01,0.927402784199 2011-07-14 15:15:01,0.758385916177 2011-07-14 16:15:01,0.628370275811 2011-07-14 17:15:01,0.620875293673 2011-07-14 18:15:01,0.599521386669 2011-07-14 19:15:01,0.571684647103 2011-07-14 20:15:01,0.553937947494 2011-07-14 21:15:01,0.583300039952 2011-07-14 22:15:01,0.54794987059 2011-07-14 23:15:01,0.584078029022 2011-07-15 00:15:01,0.470730436595 2011-07-15 01:15:01,0.613684756703 2011-07-15 02:15:01,0.500075260381 2011-07-15 03:15:01,0.465845307932 2011-07-15 04:15:01,0.41024236317 2011-07-15 05:15:01,0.387587791441 2011-07-15 06:15:01,0.424290111819 2011-07-15 07:15:01,0.419710942605 2011-07-15 08:15:01,0.490660629494 2011-07-15 09:15:01,0.579498460973 2011-07-15 10:15:01,0.629326672567 2011-07-15 11:15:01,0.678068562505 2011-07-15 12:15:01,0.92753386871 2011-07-15 13:15:01,0.999694137996 2011-07-15 14:15:01,0.666268214936 2011-07-15 15:15:01,0.697556091181 2011-07-15 16:15:01,0.641203792909 2011-07-15 17:15:01,0.63342731861 2011-07-15 18:15:01,0.582036667388 2011-07-15 19:15:01,0.563113818597 2011-07-15 20:15:01,0.526980162514 2011-07-15 21:15:01,0.52827791804 2011-07-15 22:15:01,0.475220574063 2011-07-15 23:15:01,0.447709441696 2011-07-16 00:15:01,0.573151033543 2011-07-16 01:15:01,0.660520510001 2011-07-16 02:15:01,0.653658941313 2011-07-16 03:15:01,0.54005469609 2011-07-16 04:15:01,0.515772970517 2011-07-16 05:15:01,0.429273997931 2011-07-16 06:15:01,0.407590018152 2011-07-16 07:15:01,0.421466054048 2011-07-16 08:15:01,0.530038045387 2011-07-16 09:15:01,0.57930338213 2011-07-16 10:15:01,0.770295651048 2011-07-16 11:15:01,0.808551183638 2011-07-16 12:15:01,0.841766168283 2011-07-16 13:15:01,1.14397851684 2011-07-16 14:15:01,0.693110948221 2011-07-16 15:15:01,0.765183723366 2011-07-16 16:15:01,0.679417321464 2011-07-16 17:15:01,0.599942000367 2011-07-16 18:15:01,0.577088263652 2011-07-16 19:15:01,0.61229276245 2011-07-16 22:15:01,0.554915456933 2011-07-16 23:15:01,0.558064606445 2011-07-17 00:15:01,0.551861184907 2011-07-17 01:15:01,0.61407608019 2011-07-17 02:15:01,0.614105010588 2011-07-17 03:15:01,0.547997259079 2011-07-17 04:15:01,0.52247125088 2011-07-17 05:15:01,0.44803768545 2011-07-17 06:15:01,0.422634977534 2011-07-17 07:15:01,0.449383287256 2011-07-17 08:15:01,0.48685191239 2011-07-17 09:15:01,0.55355034739 2011-07-17 10:15:01,0.751857084264 2011-07-17 11:15:01,0.752667091441 2011-07-17 12:15:01,0.929141547083 2011-07-17 13:15:01,1.20847661477 2011-07-17 14:15:01,0.779651764165 2011-07-17 15:15:01,0.842350417376 2011-07-17 16:15:01,0.660812279132 2011-07-17 17:15:01,0.604369143437 2011-07-17 18:15:01,0.545339087944 2011-07-17 19:15:01,0.553533960498 2011-07-17 20:15:01,0.548774325402 2011-07-17 21:15:01,0.538358082874 2011-07-17 22:15:01,0.53644178623 2011-07-17 23:15:01,0.534592977484 2011-07-18 00:15:01,0.512258339014 2011-07-18 01:15:01,0.566221756929 2011-07-18 02:15:01,0.522523408729 2011-07-18 03:15:01,0.471140262255 2011-07-18 04:15:01,0.427749227361 2011-07-18 05:15:01,0.389042222628 2011-07-18 06:15:01,0.383151727687 2011-07-18 07:15:01,0.431656005927 2011-07-18 08:15:01,0.450789800048 2011-07-18 09:15:01,0.579229368551 2011-07-18 10:15:01,0.619556840077 2011-07-18 11:15:01,0.723378174503 2011-07-18 12:15:01,1.01502410409 2011-07-18 13:15:01,0.846268382728 2011-07-18 14:15:01,0.839328087923 2011-07-18 15:15:01,0.725356643836 2011-07-18 16:15:01,0.724121952079 2011-07-18 17:15:01,0.651006083675 2011-07-18 18:15:01,0.602683655851 2011-07-18 19:15:01,0.586257084968 2011-07-18 20:15:01,0.562953513723 2011-07-18 21:15:01,0.515027143549 2011-07-18 22:15:01,0.51568420058 2011-07-18 23:15:01,0.520976591741 2011-07-19 00:15:01,0.443980609863 2011-07-19 01:15:01,0.616688653055 2011-07-19 02:15:01,0.543115927044 2011-07-19 03:15:01,0.453472535098 2011-07-19 04:15:01,0.42156878009 2011-07-19 05:15:01,0.354035310108 2011-07-19 06:15:01,0.338454738679 2011-07-19 07:15:01,0.410903748263 2011-07-19 08:15:01,0.447593728971 2011-07-19 09:15:01,0.55913499836 2011-07-19 10:15:01,0.719621810927 2011-07-19 11:15:01,0.767196681645 2011-07-19 12:15:01,0.942294520548 2011-07-19 13:15:01,1.0032383212 2011-07-19 14:15:01,0.862942524284 2011-07-19 15:15:01,0.733837310024 2011-07-19 16:15:01,0.625142679429 2011-07-19 17:15:01,0.509370235269 2011-07-19 18:15:01,0.53930596467 2011-07-19 19:15:01,0.50644543215 2011-07-19 20:15:01,0.488141028621 2011-07-19 21:15:01,0.436814157173 2011-07-19 22:15:01,0.47635140278 2011-07-19 23:15:01,0.457919393325 2011-07-20 00:15:01,0.4295801077 2011-07-20 01:15:01,0.564498167608 2011-07-20 02:15:01,0.509544562716 2011-07-20 03:15:01,0.463203968782 2011-07-20 04:15:01,0.407072030767 2011-07-20 05:15:01,0.358862801122 2011-07-20 06:15:01,0.373697236561 2011-07-20 07:15:01,0.439205007516 2011-07-20 08:15:01,0.415318662475 2011-07-20 09:15:01,0.542676839911 2011-07-20 10:15:01,0.575836639641 2011-07-20 11:15:01,0.693750209668 2011-07-20 12:15:01,0.958649679038 2011-07-20 13:15:01,0.978838236235 2011-07-20 14:15:01,0.847355615316 2011-07-20 15:15:01,0.662280939932 2011-07-20 16:15:01,0.583318113117 2011-07-20 17:15:01,0.533766852362 2011-07-20 18:15:01,0.534896914979 2011-07-20 19:15:01,0.49444521527 2011-07-20 20:15:01,0.472729580661 2011-07-20 21:15:01,0.480673062305 2011-07-20 22:15:01,0.423097534834 2011-07-20 23:15:01,0.486307654948 2011-07-21 00:15:01,0.422066413938 2011-07-21 01:15:01,0.519997336916 2011-07-21 02:15:01,0.503462395529 2011-07-21 03:15:01,0.443251378533 2011-07-21 04:15:01,0.384122851996 2011-07-21 05:15:01,0.362461723631 2011-07-21 06:15:01,0.362696176533 2011-07-21 07:15:01,0.382357225458 2011-07-21 08:15:01,0.409054677065 2011-07-21 09:15:01,0.529625586473 2011-07-21 10:15:01,0.575244382969 2011-07-21 11:15:01,0.5888 2011-07-21 12:15:01,0.847774407738 2011-07-21 13:15:01,0.791340636411 2011-07-21 14:15:01,0.896465706439 2011-07-21 15:15:01,0.665230969614 2011-07-21 16:15:01,0.593758564712 2011-07-21 17:15:01,0.569387656299 2011-07-21 18:15:01,0.634304010683 2011-07-21 22:15:01,0.486431017698 2011-07-22 00:15:01,0.422591891003 2011-07-22 01:15:01,0.486913311221 2011-07-22 02:15:01,0.46735676419 2011-07-22 03:15:01,0.434363028666 2011-07-22 04:15:01,0.386714049044 2011-07-22 05:15:01,0.369504587288 2011-07-22 06:15:01,0.397595454874 2011-07-22 07:15:01,0.410352632737 2011-07-22 08:15:01,0.423393177227 2011-07-22 09:15:01,0.491140774627 2011-07-22 10:15:01,0.468621217473 2011-07-22 11:15:01,0.580554113678 2011-07-22 12:15:01,0.833853226071 2011-07-22 13:15:01,0.896172284725 2011-07-22 14:15:01,0.767720788852 2011-07-22 15:15:01,0.56208989333 2011-07-22 16:15:01,0.605598263972 2011-07-22 17:15:01,0.474154728687 2011-07-22 18:15:01,0.527754990429 2011-07-22 19:15:01,0.570643559125 2011-07-22 20:15:01,0.487113274889 2011-07-22 21:15:01,0.446442694765 2011-07-22 22:15:01,0.493629595145 2011-07-22 23:15:01,0.416509432515 2011-07-23 03:15:01,0.471425611142 2011-07-23 05:15:01,0.429440714477 2011-07-23 06:15:01,0.432265331459 2011-07-23 07:15:01,0.454228292268 2011-07-23 08:15:01,0.394017939728 2011-07-23 11:15:01,0.524489350397 2011-07-23 12:15:01,0.634432981899 2011-07-23 13:15:01,1.04193118459 2011-07-23 14:15:01,0.90026207413 2011-07-23 15:15:01,0.801925327328 2011-07-23 16:15:01,0.664488563101 2011-07-23 17:15:01,0.746938916439 2011-07-23 18:15:01,0.58430610608 2011-07-23 19:15:01,0.551052096356 2011-07-23 20:15:01,0.539589028335 2011-07-23 21:15:01,0.458878228066 2011-07-23 22:15:01,0.508391976452 2011-07-23 23:15:01,0.455166495807 2011-07-24 00:15:01,0.354592054203 2011-07-24 01:15:01,0.847647604173 2011-07-24 02:15:01,0.623232870952 2011-07-24 03:15:01,0.454925500145 2011-07-24 04:15:01,0.388240283175 2011-07-24 05:15:01,0.362204837798 2011-07-24 06:15:01,0.38663181282 2011-07-24 07:15:01,0.432720462465 2011-07-24 08:15:01,0.463825888665 2011-07-24 09:15:01,0.5587072312 2011-07-24 10:15:01,0.537009158919 2011-07-24 11:15:01,0.668545698278 2011-07-24 12:15:01,1.00081699346 2011-07-24 13:15:01,0.875236467932 2011-07-24 14:15:01,0.940858277968 2011-07-24 15:15:01,0.528411701639 2011-07-24 16:15:01,0.65468678144 2011-07-24 17:15:01,0.581666157293 2011-07-24 18:15:01,0.514303731701 2011-07-24 19:15:01,0.461928980193 2011-07-24 20:15:01,0.422771996885 2011-07-24 21:15:01,0.411778295097 2011-07-24 22:15:01,0.422908418695 2011-07-24 23:15:01,0.373979374279 2011-07-25 00:15:01,0.392288088245 2011-07-25 01:15:01,0.624979173708 2011-07-25 02:15:01,0.467264498355 2011-07-25 03:15:01,0.491341991342 2011-07-25 04:15:01,0.380918382013 2011-07-25 05:15:01,0.335816771323 2011-07-25 06:15:01,0.39575696898 2011-07-25 07:15:01,0.389068499632 2011-07-25 08:15:01,0.401918936275 2011-07-25 09:15:01,0.560098031871 2011-07-25 10:15:01,0.632278380734 2011-07-25 11:15:01,0.754956701996 2011-07-25 12:15:01,0.956091142046 2011-07-25 13:15:01,0.993110160026 2011-07-25 14:15:01,0.89732544683 2011-07-25 15:15:01,0.677849823197 2011-07-25 16:15:01,0.61280505222 2011-07-25 17:15:01,0.554349758464 2011-07-25 18:15:01,0.455914446791 2011-07-25 19:15:01,0.464386331397 2011-07-25 20:15:01,0.401464711746 2011-07-25 21:15:01,0.359988588258 2011-07-25 22:15:01,0.403315849798 2011-07-25 23:15:01,0.396394253289 2011-07-26 00:15:01,0.345829294262 2011-07-26 01:15:01,0.458796101136 2011-07-26 02:15:01,0.478773805802 2011-07-26 03:15:01,0.398860697414 2011-07-26 04:15:01,0.44840088318 2011-07-26 05:15:01,0.323450423714 2011-07-26 06:15:01,0.365505482974 2011-07-26 07:15:01,0.394108235626 2011-07-26 08:15:01,0.441997940672 2011-07-26 09:15:01,0.524900355719 2011-07-26 10:15:01,0.691827625706 2011-07-26 11:15:01,0.796475686699 2011-07-26 12:15:01,0.843537414966 2011-07-26 13:15:01,0.861174539371 2011-07-26 14:15:01,0.86726415966 2011-07-26 15:15:01,0.541147669817 2011-07-26 16:15:01,0.620446859419 2011-07-26 17:15:01,0.525748138561 2011-07-26 19:15:01,0.484852616211 2011-07-26 20:15:01,0.484225645719 2011-07-26 21:15:01,0.396638624414 2011-07-26 22:15:01,0.422340743999 2011-07-26 23:15:01,0.347862423243 2011-07-27 00:15:01,0.355651253272 2011-07-27 01:15:01,0.472819637318 2011-07-27 02:15:01,0.42465090411 2011-07-27 05:15:01,0.369590666017 2011-07-27 06:15:01,0.341975423207 2011-07-27 07:15:01,0.385071903859 2011-07-27 08:15:01,0.449638417028 2011-07-27 09:15:01,0.485024107731 2011-07-27 10:15:01,0.503880485702 2011-07-27 11:15:01,0.649875468026 2011-07-27 12:15:01,0.900444803882 2011-07-27 13:15:01,0.921812066603 2011-07-27 14:15:01,0.799267434936 2011-07-27 15:15:01,0.5669058795 2011-07-27 16:15:01,0.592411494104 2011-07-27 17:15:01,0.476107270232 2011-07-27 18:15:01,0.491887576287 2011-07-27 19:15:01,0.475071540278 2011-07-27 20:15:01,0.447284149613 2011-07-27 21:15:01,0.478995312103 2011-07-27 22:15:01,0.44316906746 2011-07-27 23:15:01,0.362373551562 2011-07-28 00:15:01,0.353371351895 2011-07-28 01:15:01,0.500298235797 2011-07-28 02:15:01,0.453735304062 2011-07-28 03:15:01,0.444910788743 2011-07-28 04:15:01,0.388427934987 2011-07-28 05:15:01,0.336372101252 2011-07-28 06:15:01,0.356857600543 2011-07-28 07:15:01,0.50117066916 2011-07-28 08:15:01,0.419210640281 2011-07-28 09:15:01,0.606202190542 2011-07-28 10:15:01,0.612685287889 2011-07-28 11:15:01,0.849234393404 2011-07-28 12:15:01,1.19378143801 2011-07-28 13:15:01,0.693728857663 2011-07-28 14:15:01,0.830594474462 2011-07-28 15:15:01,0.642496762959 2011-07-28 16:15:01,0.549461019164 2011-07-28 17:15:01,0.471706205502 2011-07-28 18:15:01,0.523558103174 2011-07-28 19:15:01,0.460153344327 2011-07-28 20:15:01,0.484955907773 2011-07-28 21:15:01,0.515769796423 2011-07-28 22:15:01,0.448284108066 2011-07-28 23:15:01,0.430648577052 2011-07-29 00:15:01,0.428464730929 2011-07-29 01:15:01,0.50383463487 2011-07-29 02:15:01,0.48908390281 2011-07-29 03:15:01,0.430424920234 2011-07-29 04:15:01,0.421459720562 2011-07-29 05:15:01,0.38182361723 2011-07-29 06:15:01,0.414216287201 2011-07-29 07:15:01,0.429408844655 2011-07-29 08:15:01,0.536157500477 2011-07-29 09:15:01,0.72305326685 2011-07-29 10:15:01,0.796266588887 2011-07-29 11:15:01,1.03498390948 2011-07-29 12:15:01,1.10071677602 2011-07-29 13:15:01,0.980824921978 2011-07-29 14:15:01,1.00210466131 2011-07-29 15:15:01,0.734911682259 2011-07-29 16:15:01,0.756412897909 2011-07-29 17:15:01,0.59817101608 2011-07-29 18:15:01,0.673976028606 2011-07-29 19:15:01,0.649754020916 2011-07-29 20:15:01,0.592631426905 2011-07-29 21:15:01,0.65991491423 2011-07-29 22:15:01,0.626581379568 2011-07-29 23:15:01,0.578915126635 2011-07-30 00:15:01,0.608687044547 2011-07-30 01:15:01,0.670799943403 2011-07-30 02:15:01,0.640060585538 2011-07-30 03:15:01,0.659653508315 2011-07-30 04:15:01,0.475267844485 2011-07-30 05:15:01,0.512949516523 2011-07-30 06:15:01,0.524415858356 2011-07-30 07:15:01,0.574065799941 2011-07-30 08:15:01,0.568731977426 2011-07-30 09:15:01,0.644472679623 2011-07-30 10:15:01,0.559871884315 2011-07-30 11:15:01,0.969953850686 2011-07-30 12:15:01,1.07140826653 2011-07-30 13:15:01,1.03096993273 2011-07-30 14:15:01,0.937015144758 2011-07-30 15:15:01,0.819120085845 2011-07-30 16:15:01,0.683689190651 2011-07-30 17:15:01,0.535112398674 2011-07-30 20:15:01,0.576377992756 2011-07-30 21:15:01,0.553529713893 2011-07-30 22:15:01,0.523731134272 2011-07-30 23:15:01,0.51688836525 2011-07-31 00:15:01,0.439294307061 2011-07-31 01:15:01,0.648390249655 2011-07-31 02:15:01,0.581880306629 2011-07-31 04:15:01,0.529118257924 2011-07-31 05:15:01,0.485536149182 2011-07-31 06:15:01,0.500015487422 2011-07-31 07:15:01,0.51460008046 2011-07-31 08:15:01,0.533621281078 2011-07-31 09:15:01,0.682004403246 2011-07-31 10:15:01,0.630815315617 2011-07-31 11:15:01,0.851473399697 2011-07-31 12:15:01,1.02661392802 2011-07-31 13:15:01,1.29937784256 2011-07-31 14:15:01,0.901679325483 2011-07-31 15:15:01,0.832724097616 2011-07-31 16:15:01,0.677929487521 2011-07-31 17:15:01,0.635344512686 2011-07-31 18:15:01,0.541728069495 2011-07-31 19:15:01,0.557364618123 2011-07-31 20:15:01,0.611843812083 2011-07-31 21:15:01,0.523288282779 2011-07-31 23:15:01,0.518364312775 2011-08-01 00:15:01,0.498728225752 2011-08-01 03:15:01,0.576555937381 2011-08-01 05:15:01,0.554290565277 2011-08-01 06:15:01,0.476010861023 2011-08-01 07:15:01,0.449696671034 2011-08-01 08:15:01,0.551743210305 2011-08-01 09:15:01,0.756095103768 2011-08-01 10:15:01,0.734396138798 2011-08-01 11:15:01,0.846458555842 2011-08-01 12:15:01,1.1775573547 2011-08-01 13:15:01,0.780463324214 2011-08-01 14:15:01,1.00941909107 2011-08-01 15:15:01,0.819694770134 2011-08-01 16:15:01,0.764223282266 2011-08-01 17:15:01,0.663092200538 2011-08-01 18:15:01,0.653564393467 2011-08-01 20:15:01,0.577674184768 2011-08-01 21:15:01,0.54488363266 2011-08-01 23:15:01,0.531751330342 2011-08-02 00:15:01,0.574685145904 2011-08-02 01:15:01,0.635687697157 2011-08-02 02:15:01,0.58853026189 2011-08-02 03:15:01,0.466300750966 2011-08-02 05:15:01,0.426776142971 2011-08-02 06:15:01,0.431905267695 2011-08-02 07:15:01,0.486788508189 2011-08-02 08:15:01,0.520916021747 2011-08-02 09:15:01,0.631112923168 2011-08-02 10:15:01,0.787905664181 2011-08-02 11:15:01,1.15101155113 2011-08-02 12:15:01,1.40471250275 2011-08-02 13:15:01,0.919172005914 2011-08-02 14:15:01,0.930289680113 2011-08-02 15:15:01,0.911233169005 2011-08-02 16:15:01,0.562151951525 2011-08-02 18:15:01,0.645033038997 2011-08-02 19:15:01,0.648685752389 2011-08-02 20:15:01,0.541655156634 2011-08-02 21:15:01,0.629047798928 2011-08-02 22:15:01,0.70048738269 2011-08-02 23:15:01,0.53379122543 2011-08-03 00:15:01,0.440444722304 2011-08-03 01:15:01,0.719683930527 2011-08-03 02:15:01,0.710997940534 2011-08-03 03:15:01,0.594979361314 2011-08-03 04:15:01,0.449055478674 2011-08-03 05:15:01,0.477755007181 2011-08-03 06:15:01,0.503697983752 2011-08-03 07:15:01,0.600102091293 2011-08-03 08:15:01,0.561552932585 2011-08-03 09:15:01,0.79419877957 2011-08-03 10:15:01,0.785667933624 2011-08-03 11:15:01,1.13982041415 2011-08-03 12:15:01,1.19103416667 2011-08-03 13:15:01,1.17852075751 2011-08-03 14:15:01,0.75004468933 2011-08-03 15:15:01,0.817874388891 2011-08-03 17:15:01,0.722743200455 2011-08-03 18:15:01,0.584243911365 2011-08-03 19:15:01,0.62690718902 2011-08-03 20:15:01,0.583636953993 2011-08-03 21:15:01,0.638105501939 2011-08-03 22:15:01,0.553943354236 2011-08-03 23:15:01,0.698302566298 2011-08-04 00:15:01,0.585952461824 2011-08-04 01:15:01,0.680807542384 2011-08-04 02:15:01,0.633855601382 2011-08-04 03:15:01,0.820624317284 2011-08-04 04:15:01,0.557292109026 2011-08-04 05:15:01,0.41470422161 2011-08-04 06:15:01,0.525180710389 2011-08-04 07:15:01,0.548682741313 2011-08-04 08:15:01,0.556389097274 2011-08-04 09:15:01,0.671852412749 2011-08-04 10:15:01,0.815993714002 2011-08-04 11:15:01,0.893970122675 2011-08-04 12:15:01,1.08664281817 2011-08-04 13:15:01,1.12298696319 2011-08-04 14:15:01,0.95005399809 2011-08-04 16:15:01,0.715950660979 2011-08-04 17:15:01,0.795825740766 2011-08-04 18:15:01,0.647634508959 2011-08-04 19:15:01,0.555697769319 2011-08-04 20:15:01,1.42072295982 2011-08-04 21:15:01,0.592265160479 2011-08-04 22:15:01,0.568243786567 2011-08-04 23:15:01,0.604767739087 2011-08-05 00:15:01,0.555048814747 2011-08-05 01:15:01,0.686409550046 2011-08-05 02:15:01,0.664502043993 2011-08-05 03:15:01,0.751783059049 2011-08-05 04:15:01,0.536707916534 2011-08-05 05:15:01,0.584625706011 2011-08-05 06:15:01,0.543533656374 2011-08-05 07:15:01,0.541778547457 2011-08-05 08:15:01,0.611421644746 2011-08-05 09:15:01,0.726964468474 2011-08-05 10:15:01,0.802952723852 2011-08-05 11:15:01,1.0420973625 2011-08-05 12:15:01,1.05794478293 2011-08-05 13:15:01,1.14759081927 2011-08-05 14:15:01,0.995947810883 2011-08-05 15:15:01,0.837924146178 2011-08-05 17:15:01,0.639849442198 2011-08-05 19:15:01,0.676064732772 2011-08-05 20:15:01,0.543911542172 2011-08-05 21:15:01,0.577292345427 2011-08-05 22:15:01,0.543720793978 2011-08-05 23:15:01,0.574428235604 2011-08-06 00:15:01,0.536694938229 2011-08-06 01:15:01,0.721242372337 2011-08-06 02:15:01,0.719180486143 2011-08-06 03:15:01,0.664986357941 2011-08-06 04:15:01,0.675107829796 2011-08-06 05:15:01,0.568417908432 2011-08-06 06:15:01,0.560745261334 2011-08-06 07:15:01,0.589784142503 2011-08-06 08:15:01,0.675166106392 2011-08-06 09:15:01,0.713929339861 2011-08-06 10:15:01,0.720525247971 2011-08-06 11:15:01,0.973101693998 2011-08-06 12:15:01,1.04109900091 2011-08-06 13:15:01,1.10076528064 2011-08-06 15:15:01,0.858281143262 2011-08-06 16:15:01,0.718258734174 2011-08-06 17:15:01,0.652482726953 2011-08-06 18:15:01,0.603126873225 2011-08-06 19:15:01,0.615980506115 2011-08-06 20:15:01,0.518617271676 2011-08-06 21:15:01,0.612084186098 2011-08-06 22:15:01,0.6041011793 2011-08-06 23:15:01,0.519409820872 2011-08-07 00:15:01,0.635188073777 2011-08-07 01:15:01,0.68608152933 2011-08-07 02:15:01,0.609118718996 2011-08-07 03:15:01,0.582622271093 2011-08-07 04:15:01,0.598422475252 2011-08-07 05:15:01,0.561157963103 2011-08-07 06:15:01,0.593355289604 2011-08-07 07:15:01,0.623050235785 2011-08-07 08:15:01,0.687373850639 2011-08-07 09:15:01,0.665167658556 2011-08-07 10:15:01,0.849833024706 2011-08-07 11:15:01,0.946772757303 2011-08-07 12:15:01,1.05214350573 2011-08-07 13:15:01,1.49678514312 2011-08-07 14:15:01,0.867744078979 2011-08-07 15:15:01,0.819632696943 2011-08-07 16:15:01,0.74004421129 2011-08-07 17:15:01,0.705276178788 2011-08-07 18:15:01,0.648443555101 2011-08-07 19:15:01,0.55609604234 2011-08-07 20:15:01,0.624781661692 2011-08-07 21:15:01,0.605392560095 2011-08-07 22:15:01,0.568348885355 2011-08-07 23:15:01,0.548749163255 2011-08-08 00:15:01,0.606434621799 2011-08-08 01:15:01,0.646378233592 2011-08-08 02:15:01,0.580301698869 2011-08-08 03:15:01,0.565836250493 2011-08-08 04:15:01,0.569189356342 2011-08-08 05:15:01,0.538710969129 2011-08-08 06:15:01,0.513768455929 2011-08-08 07:15:01,0.559171613811 2011-08-08 08:15:01,0.575195729644 2011-08-08 09:15:01,0.652947245764 2011-08-08 10:15:01,0.74503888758 2011-08-08 11:15:01,0.857579554687 2011-08-08 12:15:01,0.875553118504 2011-08-08 13:15:01,0.854941413658 2011-08-08 14:15:01,0.790767678673 2011-08-08 16:15:01,0.712741698358 2011-08-08 17:15:01,0.615699781863 2011-08-08 18:15:01,0.595200849764 2011-08-08 19:15:01,0.634719459996 2011-08-08 20:15:01,0.547550792253 2011-08-08 21:15:01,0.590809094235 2011-08-08 22:15:01,0.570679942692 2011-08-08 23:15:01,0.54153421526 2011-08-09 00:15:01,0.536134186043 2011-08-09 01:15:01,0.58694728119 2011-08-09 02:15:01,0.599060021738 2011-08-09 03:15:01,0.578157413533 2011-08-09 04:15:01,0.50181775834 2011-08-09 05:15:01,0.518201067593 2011-08-09 06:15:01,0.511505673511 2011-08-09 07:15:01,0.597075586726 2011-08-09 08:15:01,0.598728666922 2011-08-09 09:15:01,0.783646778861 2011-08-09 10:15:01,0.788622722111 2011-08-09 11:15:01,0.86311824481 2011-08-09 12:15:01,1.27301519137 2011-08-09 14:15:01,0.88404025791 2011-08-09 15:15:01,0.802570074162 2011-08-09 16:15:01,0.723815454876 2011-08-09 17:15:01,0.661586612293 2011-08-09 18:15:01,0.617642290617 2011-08-09 19:15:01,0.629898957434 2011-08-09 20:15:01,0.601685026205 2011-08-09 21:15:01,0.645256582208 2011-08-09 22:15:01,0.590185964475 2011-08-09 23:15:01,0.620264322455 2011-08-10 00:15:01,0.559184359065 2011-08-10 01:15:01,0.590161480456 2011-08-10 02:15:01,0.591462623116 2011-08-10 03:15:01,0.642369010583 2011-08-10 04:15:01,0.520049263822 2011-08-10 05:15:01,0.502427012098 2011-08-10 06:15:01,0.504466919255 2011-08-10 07:15:01,0.50623672691 2011-08-10 08:15:01,0.547044702758 2011-08-10 09:15:01,0.624164877273 2011-08-10 10:15:01,0.821473591903 2011-08-10 11:15:01,0.962219823481 2011-08-10 12:15:01,1.13254543144 2011-08-10 13:15:01,0.946045959158 2011-08-10 15:15:01,0.983489745003 2011-08-10 17:15:01,0.82094562393 2011-08-10 18:15:01,0.730903856743 2011-08-10 19:15:01,0.625206071634 2011-08-10 20:15:01,0.731170579564 2011-08-10 21:15:01,0.676400974391 2011-08-10 23:15:01,0.660492954703 2011-08-11 00:15:01,0.554590237895 2011-08-11 01:15:01,0.715748968801 2011-08-11 02:15:01,0.552449342809 2011-08-11 03:15:01,0.608818563823 2011-08-11 04:15:01,0.56535245238 2011-08-11 05:15:01,0.545612490685 2011-08-11 06:15:01,0.521651179882 2011-08-11 07:15:01,0.577066436906 2011-08-11 08:15:01,0.649319201432 2011-08-11 09:15:01,0.761580436424 2011-08-11 10:15:01,0.958909403592 2011-08-11 11:15:01,0.879025593085 2011-08-11 12:15:01,1.02881514616 2011-08-11 14:15:01,1.12794638303 2011-08-11 15:15:01,0.806395267298 2011-08-11 16:15:01,0.998546127412 2011-08-11 17:15:01,0.797586425481 2011-08-11 18:15:01,0.653892646469 2011-08-11 19:15:01,0.668489407469 2011-08-11 20:15:01,0.704774059598 2011-08-11 21:15:01,0.618160741346 2011-08-11 22:15:01,0.703522679277 2011-08-11 23:15:01,0.645565581113 2011-08-12 00:15:01,0.641368766824 2011-08-12 01:15:01,0.705282913257 2011-08-12 02:15:01,0.612891663325 2011-08-12 03:15:01,0.59561723886 2011-08-12 04:15:01,0.397505242902 2011-08-12 05:15:01,0.4334602526 2011-08-12 06:15:01,0.452638011815 2011-08-12 07:15:01,0.554466657955 2011-08-12 08:15:01,0.762423745569 2011-08-12 09:15:01,0.743389683572 2011-08-12 10:15:01,1.2398054085 2011-08-12 11:15:01,1.24785288471 2011-08-12 13:15:01,1.56976504958 2011-08-12 14:15:01,1.30445869153 2011-08-12 15:15:01,0.913389056971 2011-08-12 16:15:01,0.797229088648 2011-08-12 17:15:01,0.588670630441 2011-08-12 18:15:01,0.621693121693 2011-08-12 19:15:01,0.561822051743 2011-08-12 21:15:01,0.586936754634 2011-08-12 22:15:01,0.510457600443 2011-08-12 23:15:01,0.411906443438 2011-08-13 00:15:01,0.481140662888 2011-08-13 01:15:01,0.727249846188 2011-08-13 02:15:01,0.692740174194 2011-08-13 03:15:01,0.606669069316 2011-08-13 04:15:01,0.481597592012 2011-08-13 05:15:01,0.452214871573 2011-08-13 06:15:01,0.503423930085 2011-08-13 07:15:01,0.592080023871 2011-08-13 08:15:01,0.670440067671 2011-08-13 09:15:01,0.781322734271 2011-08-13 10:15:01,1.12155162029 2011-08-13 11:15:01,1.14461358314 2011-08-13 12:15:01,2.3458511804 2011-08-13 13:15:01,1.78017877028 2011-08-13 15:15:01,1.16344626108 2011-08-13 17:15:01,0.80366590851 2011-08-13 18:15:01,0.835319293809 2011-08-13 19:15:01,0.61608130586 2011-08-13 20:15:01,0.551187458629 2011-08-13 21:15:01,0.496627535469 2011-08-13 22:15:01,0.471666183154 2011-08-13 23:15:01,0.646252600178 2011-08-14 00:15:01,0.610524145889 2011-08-14 01:15:01,0.740457772665 2011-08-14 02:15:01,0.67648312914 2011-08-14 03:15:01,0.6999543225 2011-08-14 04:15:01,0.581878572182 2011-08-14 05:15:01,0.574517129817 2011-08-14 06:15:01,0.588103546132 2011-08-14 07:15:01,0.682825589466 2011-08-14 08:15:01,0.702503350973 2011-08-14 09:15:01,0.811665071193 2011-08-14 10:15:01,0.959159638626 2011-08-14 11:15:01,1.13891248326 2011-08-14 12:15:01,1.31995254103 2011-08-14 13:15:01,1.14913574749 2011-08-14 14:15:01,1.17398097723 2011-08-14 15:15:01,0.910558605102 2011-08-14 16:15:01,0.786068674769 2011-08-14 17:15:01,0.809601949747 2011-08-14 18:15:01,0.755417840119 2011-08-14 19:15:01,0.749192553692 2011-08-14 20:15:01,0.665563624108 2011-08-14 21:15:01,0.721558658688 2011-08-14 22:15:01,0.685192621577 2011-08-14 23:15:01,0.557077450057 2011-08-15 01:15:01,0.636081308305 2011-08-15 02:15:01,0.667131109384 2011-08-15 03:15:01,0.735076057078 2011-08-15 04:15:01,0.580668384959 2011-08-15 05:15:01,0.579281629473 2011-08-15 06:15:01,0.602451454238 2011-08-15 07:15:01,0.644382914486 2011-08-15 08:15:01,0.714276606054 2011-08-15 09:15:01,0.848933518167 2011-08-15 10:15:01,0.966559247715 2011-08-15 11:15:01,1.05050887436 2011-08-15 12:15:01,1.04251488078 2011-08-15 14:15:01,0.932878270762 2011-08-15 15:15:01,0.826720919972 2011-08-15 16:15:01,0.776904573404 2011-08-15 17:15:01,0.716201992703 2011-08-15 18:15:01,0.711605913562 2011-08-15 19:15:01,0.708530490055 2011-08-15 20:15:01,0.663736975075 2011-08-15 21:15:01,0.622400018566 2011-08-15 22:15:01,0.607611681058 2011-08-15 23:15:01,0.611072281173 2011-08-16 00:15:01,0.563604798437 2011-08-16 01:15:01,0.686922142397 2011-08-16 02:15:01,0.675897036319 2011-08-16 03:15:01,0.667313844917 2011-08-16 04:15:01,0.628226199954 2011-08-16 05:15:01,0.595912441675 2011-08-16 06:15:01,0.634416844861 2011-08-16 07:15:01,0.685898336104 2011-08-16 08:15:01,0.826101318279 2011-08-16 09:15:01,0.892529350396 2011-08-16 10:15:01,1.12081818742 2011-08-16 11:15:01,1.12547861639 2011-08-16 12:15:01,1.12175474239 2011-08-16 13:15:01,1.05128934078 2011-08-16 14:15:01,0.966681309319 2011-08-16 15:15:01,0.990511125266 2011-08-16 16:15:01,0.879749252927 2011-08-16 17:15:01,0.714478939876 2011-08-16 18:15:01,0.877238546553 2011-08-16 19:15:01,0.725744019401 2011-08-16 20:15:01,0.761700055415 2011-08-16 21:15:01,0.714732926186 2011-08-16 22:15:01,0.676804863428 2011-08-16 23:15:01,0.711416021227 2011-08-17 00:15:01,0.607743520633 2011-08-17 01:15:01,0.736028088655 2011-08-17 02:15:01,0.66488033209 2011-08-17 03:15:01,0.619237027662 2011-08-17 04:15:01,0.550742015432 2011-08-17 05:15:01,0.555550082264 2011-08-17 06:15:01,0.616679440644 2011-08-17 07:15:01,0.693236714976 2011-08-17 08:15:01,0.810488810541 2011-08-17 09:15:01,0.932629669333 2011-08-17 10:15:01,1.10551712253 2011-08-17 11:15:01,1.24432225675 2011-08-17 12:15:01,1.07751682008 2011-08-17 13:15:01,0.993365801281 2011-08-17 14:15:01,1.03636422863 2011-08-17 15:15:01,0.927039239851 2011-08-17 16:15:01,0.821436448207 2011-08-17 18:15:01,0.762617399275 2011-08-17 19:15:01,0.714061062878 2011-08-17 20:15:01,0.735661201354 2011-08-17 21:15:01,0.666658952973 2011-08-17 22:15:01,0.621769977351 2011-08-17 23:15:01,0.548446739751 2011-08-18 00:15:01,0.544978141492 2011-08-18 01:15:01,0.758639317537 2011-08-18 02:15:01,0.732381898533 2011-08-18 03:15:01,0.570647047727 2011-08-18 04:15:01,0.534028307408 2011-08-18 05:15:01,0.542765533075 2011-08-18 06:15:01,0.567515064457 2011-08-18 07:15:01,0.683516370065 2011-08-18 08:15:01,0.718008272579 2011-08-18 09:15:01,0.936216066342 2011-08-18 10:15:01,0.977670956737 2011-08-18 11:15:01,0.953869233654 2011-08-18 12:15:01,0.958412841486 2011-08-18 13:15:01,0.982262310647 2011-08-18 14:15:01,0.944170398835 2011-08-18 15:15:01,0.712214878216 2011-08-18 16:15:01,0.779245317679 2011-08-18 18:15:01,0.770476887313 2011-08-18 20:15:01,0.772785581145 2011-08-18 21:15:01,0.792569185776 2011-08-18 22:15:01,0.892232194744 2011-08-18 23:15:01,0.928590112477 2011-08-19 00:15:01,0.809001110711 2011-08-19 01:15:01,0.773142351037 2011-08-19 02:15:01,0.68364500895 2011-08-19 03:15:01,0.666356498685 2011-08-19 04:15:01,0.602663491936 2011-08-19 05:15:01,0.615586216743 2011-08-19 06:15:01,0.680106983428 2011-08-19 07:15:01,0.715438473764 2011-08-19 08:15:01,0.778365849468 2011-08-19 09:15:01,0.940738025415 2011-08-19 10:15:01,1.06431149513 2011-08-19 11:15:01,1.03322345475 2011-08-19 12:15:01,1.06920531499 2011-08-19 13:15:01,0.90248188841 2011-08-19 14:15:01,0.948048756512 2011-08-19 15:15:01,0.940754216038 2011-08-19 16:15:01,0.934222809879 2011-08-19 18:15:01,5.49754000266 2011-08-19 19:15:01,0.863326087315 2011-08-19 20:15:01,0.703298738091 2011-08-19 21:15:01,0.713623326394 2011-08-19 22:15:01,0.654695043258 2011-08-19 23:15:01,0.674132038136 2011-08-20 00:15:01,0.662703093534 2011-08-20 01:15:01,0.794094232044 2011-08-20 02:15:01,0.682984438197 2011-08-20 03:15:01,0.668096114705 2011-08-20 04:15:01,0.644444815845 2011-08-20 05:15:01,0.631821336803 2011-08-20 06:15:01,0.664079704752 2011-08-20 07:15:01,0.691809112522 2011-08-20 08:15:01,0.731047520971 2011-08-20 09:15:01,0.916183652659 2011-08-20 10:15:01,1.12615701063 2011-08-20 11:15:01,1.37892666256 2011-08-20 12:15:01,1.48058619127 2011-08-20 13:15:01,1.11576620573 2011-08-20 14:15:01,1.10130283386 2011-08-20 15:15:01,0.917978202373 2011-08-20 16:15:01,0.868671626148 2011-08-20 17:15:01,0.804527172255 2011-08-20 18:15:01,0.745593099694 2011-08-20 19:15:01,0.693628880174 2011-08-20 20:15:01,0.713280266363 2011-08-20 21:15:01,0.69452314481 2011-08-20 22:15:01,0.676418731136 2011-08-20 23:15:01,0.705210678675 2011-08-21 00:15:01,0.693664559433 2011-08-21 01:15:01,0.741737529738 2011-08-21 02:15:01,0.740867235598 2011-08-21 03:15:01,0.755155629406 2011-08-21 04:15:01,0.663611083149 2011-08-21 05:15:01,0.645370135798 2011-08-21 06:15:01,0.649619761544 2011-08-21 07:15:01,0.70872257412 2011-08-21 08:15:01,0.692568813021 2011-08-21 09:15:01,0.739975603038 2011-08-21 10:15:01,1.07428499644 2011-08-21 11:15:01,1.29783044803 2011-08-21 12:15:01,1.18176109093 2011-08-21 13:15:01,1.29187384737 2011-08-21 15:15:01,0.937208385358 2011-08-21 16:15:01,0.91911195455 2011-08-21 17:15:01,0.755583102096 2011-08-21 18:15:01,0.745270462145 2011-08-21 19:15:01,0.710554099813 2011-08-21 20:15:01,0.658328261736 2011-08-21 21:15:01,0.724803116745 2011-08-21 22:15:01,0.705354280218 2011-08-21 23:15:01,0.689806462107 2011-08-22 00:15:01,0.60689583826 2011-08-22 01:15:01,0.651337689557 2011-08-22 02:15:01,0.62934487776 2011-08-22 03:15:01,0.62372916466 2011-08-22 04:15:01,0.577398944823 2011-08-22 05:15:01,0.572886854195 2011-08-22 06:15:01,0.594058752156 2011-08-22 07:15:01,0.582907570831 2011-08-22 08:15:01,0.734216695443 2011-08-22 09:15:01,0.806454982244 2011-08-22 10:15:01,0.969068717606 2011-08-22 11:15:01,0.849613756806 2011-08-22 12:15:01,0.890577507599 2011-08-22 13:15:01,0.972369871643 2011-08-22 15:15:01,0.830408286317 2011-08-22 16:15:01,0.790874543276 2011-08-22 17:15:01,0.868033239748 2011-08-22 18:15:01,0.753268013611 2011-08-22 19:15:01,0.75341096872 2011-08-22 20:15:01,0.723666685969 2011-08-22 21:15:01,0.641627543036 2011-08-22 22:15:01,0.793713273077 2011-08-22 23:15:01,0.778934874729 2011-08-23 00:15:01,0.710999652634 2011-08-23 01:15:01,0.703201657157 2011-08-23 02:15:01,0.669306023229 2011-08-23 03:15:01,0.623246944026 2011-08-23 04:15:01,0.59842770237 2011-08-23 05:15:01,0.618625761565 2011-08-23 06:15:01,0.673907341691 2011-08-23 07:15:01,0.776481358143 2011-08-23 08:15:01,0.904231856983 2011-08-23 09:15:01,1.29383792352 2011-08-23 10:15:01,1.13551430877 2011-08-23 11:15:01,1.0251356609 2011-08-23 12:15:01,1.18905411994 2011-08-23 13:15:01,1.27127243107 2011-08-23 14:15:01,1.15911742747 2011-08-23 16:15:01,1.05845536275 2011-08-23 17:15:01,0.926634493627 2011-08-23 18:15:01,0.776918970136 2011-08-23 19:15:01,0.928010146312 2011-08-23 20:15:01,0.838158380029 2011-08-23 21:15:01,0.819862464009 2011-08-23 22:15:01,0.69970306261 2011-08-23 23:15:01,0.842383353699 2011-08-24 00:15:01,0.792468794781 2011-08-24 01:15:01,0.713359095889 2011-08-24 02:15:01,0.704135949192 2011-08-24 03:15:01,0.641155335986 2011-08-24 04:15:01,0.634568795601 2011-08-24 05:15:01,0.645873833534 2011-08-24 06:15:01,0.6590434368 2011-08-24 07:15:01,0.812906195196 2011-08-24 08:15:01,0.881111571307 2011-08-24 09:15:01,1.24918386562 2011-08-24 10:15:01,1.36501420903 2011-08-24 11:15:01,1.95241011285 2011-08-24 12:15:01,1.54697912263 2011-08-24 13:15:01,1.5651661815 2011-08-24 15:15:01,1.22446525543 2011-08-24 16:15:01,1.1562087199 2011-08-24 17:15:01,1.33774834437 2011-08-24 18:15:01,1.03148188994 2011-08-24 19:15:01,0.935049971832 2011-08-24 20:15:01,0.711196895617 2011-08-24 21:15:01,0.767570958313 2011-08-24 22:15:01,0.735954907513 2011-08-24 23:15:01,0.77345193875 2011-08-25 00:15:01,0.692628331902 2011-08-25 01:15:01,0.824416895061 2011-08-25 02:15:01,0.730707604827 2011-08-25 03:15:01,0.715088082545 2011-08-25 04:15:01,0.744875421318 2011-08-25 05:15:01,0.737488743085 2011-08-25 06:15:01,0.717183548371 2011-08-25 07:15:01,0.833624102622 2011-08-25 08:15:01,0.953373503323 2011-08-25 09:15:01,1.31115307189 2011-08-25 10:15:01,1.16843727867 2011-08-25 11:15:01,1.0374018924 2011-08-25 12:15:01,1.07353824758 2011-08-25 13:15:01,1.18426544594 2011-08-25 15:15:01,0.81995711885 2011-08-25 16:15:01,1.08679580518 2011-08-25 17:15:01,1.2173424085 2011-08-25 18:15:01,1.00456228294 2011-08-25 19:15:01,1.03477665107 2011-08-25 20:15:01,0.948686262348 2011-08-25 21:15:01,0.993665532552 2011-08-25 22:15:01,0.903960473484 2011-08-25 23:15:01,0.788313159199 2011-08-26 00:15:01,0.798556558757 2011-08-26 01:15:01,0.734166131373 2011-08-26 02:15:01,0.742638615815 2011-08-26 03:15:01,0.675874389581 2011-08-26 04:15:01,0.705817989883 2011-08-26 05:15:01,0.727232396299 2011-08-26 06:15:01,0.753356912152 2011-08-26 07:15:01,0.875354972671 2011-08-26 08:15:01,0.925335068588 2011-08-26 10:15:01,1.19420541076 2011-08-26 11:15:01,0.851330505206 2011-08-26 12:15:01,1.31130509932 2011-08-26 13:15:01,1.18812702098 2011-08-26 14:15:01,1.10183903133 2011-08-26 15:15:01,1.05379013513 2011-08-26 16:15:01,1.07217664514 2011-08-26 17:15:01,0.789734929311 2011-08-26 18:15:01,0.890166131849 2011-08-26 19:15:01,0.920508307487 2011-08-26 20:15:01,0.950929806345 2011-08-26 21:15:01,0.822102406411 2011-08-26 22:15:01,0.826540433576 2011-08-26 23:15:01,0.791927711761 2011-08-27 00:15:01,0.702807204893 2011-08-27 01:15:01,0.864523887721 2011-08-27 02:15:01,0.809851903585 2011-08-27 03:15:01,0.758690430787 2011-08-27 04:15:01,0.80677831628 2011-08-27 05:15:01,0.688049770453 2011-08-27 06:15:01,0.81968980524 2011-08-27 07:15:01,0.821442694794 2011-08-27 08:15:01,1.06152614064 2011-08-27 09:15:01,1.44317491332 2011-08-27 10:15:01,1.22704597643 2011-08-27 11:15:01,1.58093752585 2011-08-27 12:15:01,1.51858142365 2011-08-27 13:15:01,1.06284454245 2011-08-27 14:15:01,1.29828215868 2011-08-27 15:15:01,1.17357031987 2011-08-27 16:15:01,0.938417521965 2011-08-27 17:15:01,0.719759087413 2011-08-27 18:15:01,0.793253640139 2011-08-27 19:15:01,0.821043529075 2011-08-27 20:15:01,0.77728705129 2011-08-27 21:15:01,0.761011905195 2011-08-27 22:15:01,0.794456554147 2011-08-27 23:15:01,0.71510777014 2011-08-28 00:15:01,0.670100640381 2011-08-28 01:15:01,0.54761579658 2011-08-28 17:15:01,0.849284090378 2011-08-28 18:15:01,0.852476609926 2011-08-28 19:15:01,0.805305280552 2011-08-28 20:15:01,0.889728282553 2011-08-28 21:15:01,0.778613508361 2011-08-28 22:15:01,0.685767835952 2011-08-28 23:15:01,0.726981575893 2011-08-29 00:15:01,0.645975352581 2011-08-29 01:15:01,0.777534142894 2011-08-29 02:15:01,0.723113114405 2011-08-29 03:15:01,0.831905214884 2011-08-29 04:15:01,0.674230251552 2011-08-29 05:15:01,0.71415081987 2011-08-29 06:15:01,0.795823883546 2011-08-29 07:15:01,0.853323981424 2011-08-29 08:15:01,1.03638510945 2011-08-29 09:15:01,1.16972027756 2011-08-29 10:15:01,1.37015829137 2011-08-29 11:15:01,1.19479416172 2011-08-29 12:15:01,1.50872750294 2011-08-29 13:15:01,1.25480461243 2011-08-29 14:15:01,1.18351258787 2011-08-29 15:15:01,0.838183770344 2011-08-29 16:15:01,1.05843861494 2011-08-29 17:15:01,1.1154608336 2011-08-29 18:15:01,0.87860810131 2011-08-29 19:15:01,1.09936880724 2011-08-29 20:15:01,0.87085318709 2011-08-29 21:15:01,0.843596628444 2011-08-29 22:15:01,0.777040471902 2011-08-29 23:15:01,0.688557936796 2011-08-30 00:15:01,0.697836804319 2011-08-30 01:15:01,0.771217121712 2011-08-30 02:15:01,0.694660626848 2011-08-30 03:15:01,0.786323057256 2011-08-30 04:15:01,0.654660190687 2011-08-30 05:15:01,0.72306000212 2011-08-30 06:15:01,0.774674210709 2011-08-30 07:15:01,0.884858627959 2011-08-30 08:15:01,1.08493710832 2011-08-30 09:15:01,1.14704937346 2011-08-30 10:15:01,1.40645395214 2011-08-30 11:15:01,0.967981387104 2011-08-30 12:15:01,1.75374564605 2011-08-30 13:15:01,1.22262717456 2011-08-30 15:15:01,1.2477794358 2011-08-30 16:15:01,1.04428573933 2011-08-30 17:15:01,0.924926251082 2011-08-30 18:15:01,1.20389636883 2011-08-30 19:15:01,0.936448977169 2011-08-30 21:15:01,0.869768173712 2011-08-30 22:15:01,0.820539262738 2011-08-30 23:15:01,0.855369516046 2011-08-31 00:15:01,0.961147001986 2011-08-31 01:15:01,0.958316270557 2011-08-31 02:15:01,0.814787274063 2011-08-31 03:15:01,0.771593377122 2011-08-31 04:15:01,0.766299657727 2011-08-31 05:15:01,0.724229465703 2011-08-31 06:15:01,0.792862195384 2011-08-31 07:15:01,0.942622099425 2011-08-31 08:15:01,1.14142180366 2011-08-31 09:15:01,1.50385784428 2011-08-31 10:15:01,1.32986869524 2011-08-31 11:15:01,1.35511366926 2011-08-31 12:15:01,1.30690884147 2011-08-31 13:15:01,1.36129882778 2011-08-31 14:15:01,1.26118176226 2011-08-31 15:15:01,1.29325090898 2011-08-31 16:15:01,1.13162826786 2011-08-31 17:15:01,0.878180273521 2011-08-31 19:15:01,1.00724076188 2011-08-31 20:15:01,0.82977849928 2011-08-31 21:15:01,0.791770492231 2011-08-31 22:15:01,0.776412218566 2011-08-31 23:15:01,1.01967346467 2011-09-01 00:15:01,0.672524767707 2011-09-01 01:15:01,0.805459791968 2011-09-01 02:15:01,0.697760708058 2011-09-01 03:15:01,0.671198221878 2011-09-01 04:15:01,0.686612619056 2011-09-01 05:15:01,0.730138629699 2011-09-01 06:15:01,0.773151750973 2011-09-01 07:15:01,0.920818621438 2011-09-01 08:15:01,1.05974998234 2011-09-01 09:15:01,1.25720738674 2011-09-01 10:15:01,1.69107806691 2011-09-01 13:15:01,1.38872596255 2011-09-01 18:15:01,1.18474325929 2011-09-01 19:15:01,1.00755614801 2011-09-01 20:15:01,0.889925459781 2011-09-01 21:15:01,0.879357863581 2011-09-01 22:15:01,0.813560856853 2011-09-01 23:15:01,0.668334950547 2011-09-02 00:15:01,0.634700519233 2011-09-02 01:15:01,0.710229977153 2011-09-02 02:15:01,0.697412833033 2011-09-02 03:15:01,0.725219217625 2011-09-02 04:15:01,0.60871199833 2011-09-02 05:15:01,0.636974122101 2011-09-02 06:15:01,0.841129477074 2011-09-02 07:15:01,0.771209479568 2011-09-02 08:15:01,1.02627235945 2011-09-02 09:15:01,1.38391615999 2011-09-02 10:15:01,1.70182048664 2011-09-02 11:15:01,1.30911498665 2011-09-02 12:15:01,1.44916720916 2011-09-02 13:15:01,1.10994932226 2011-09-02 14:15:01,1.20104749435 2011-09-02 15:15:01,1.00461581227 2011-09-02 16:15:01,1.24974971635 2011-09-02 17:15:01,0.930537334322 2011-09-02 18:15:01,0.696674235341 2011-09-02 19:15:01,1.90695503664 2011-09-02 20:15:01,1.14246709184 2011-09-02 21:15:01,1.11277858928 2011-09-02 22:15:01,0.694990722636 2011-09-02 23:15:01,1.1243682849 2011-09-03 00:15:01,1.63223166525 2011-09-03 01:15:01,1.12621421132 2011-09-03 02:15:01,1.22375614029 2011-09-03 03:15:01,0.836308743265 2011-09-03 04:15:01,0.764508533837 2011-09-03 05:15:01,0.824846108339 2011-09-03 06:15:01,0.858898956181 2011-09-03 07:15:01,1.06302492473 2011-09-03 08:15:01,1.40538621285 2011-09-03 09:15:01,1.74459064633 2011-09-03 10:15:01,2.03489870008 2011-09-03 11:15:01,1.93540664402 2011-09-03 12:15:01,2.27425030493 2011-09-03 13:15:01,2.14033402306 2011-09-03 14:15:01,1.77426028471 2011-09-03 15:15:01,1.25941144301 2011-09-03 16:15:01,1.02897679946 2011-09-03 17:15:01,0.924615076404 2011-09-03 18:15:01,0.909732905845 2011-09-03 19:15:01,0.869216123697 2011-09-03 20:15:01,0.541295740253 2011-09-03 21:15:01,1.1777566405 2011-09-03 22:15:01,1.13735222856 2011-09-03 23:15:01,0.890667031052 2011-09-04 00:15:01,0.610490083267 2011-09-04 01:15:01,0.909803400811 2011-09-04 02:15:01,0.997966281743 2011-09-04 03:15:01,0.760097226529 2011-09-04 04:15:01,0.695617328423 2011-09-04 05:15:01,0.756014604219 2011-09-04 06:15:01,0.79008464589 2011-09-04 07:15:01,0.917348874571 2011-09-04 08:15:01,1.13719366386 2011-09-04 09:15:01,1.42018674399 2011-09-04 10:15:01,1.62974773646 2011-09-04 11:15:01,2.39951967225 2011-09-04 12:15:01,1.90579824839 2011-09-04 13:15:01,1.41094529283 2011-09-04 14:15:01,1.51420659222 2011-09-04 15:15:01,0.907680196378 2011-09-04 16:15:01,0.949640701076 2011-09-04 17:15:01,0.853479545072 2011-09-04 19:15:01,0.734071967028 2011-09-04 21:15:01,0.664832645575 2011-09-04 22:15:01,0.751175591232 2011-09-04 23:15:01,0.699932102092 2011-09-05 00:15:01,0.512007082519 2011-09-05 01:15:01,0.768525925193 2011-09-05 02:15:01,0.720969190212 2011-09-05 03:15:01,0.834640838517 2011-09-05 04:15:01,0.627736806898 2011-09-05 05:15:01,0.651203112053 2011-09-05 06:15:01,0.830826437039 2011-09-05 07:15:01,0.708797528226 2011-09-05 08:15:01,0.914809516084 2011-09-05 09:15:01,1.19163674636 2011-09-05 10:15:01,1.64855351909 2011-09-05 11:15:01,1.75118246316 2011-09-05 12:15:01,2.23766160764 2011-09-05 13:15:01,1.66328470303 2011-09-05 15:15:01,0.832920669506 2011-09-05 17:15:01,0.933893576278 2011-09-05 18:15:01,0.689506085719 2011-09-05 19:15:01,0.768903526829 2011-09-05 20:15:01,0.698904886719 2011-09-05 21:15:01,0.681318152131 2011-09-05 22:15:01,0.570423466165 2011-09-05 23:15:01,0.63045223235 2011-09-06 01:15:01,0.614224788781 2011-09-06 02:15:01,0.655868229912 2011-09-06 03:15:01,0.693436352057 2011-09-06 04:15:01,0.611312925873 2011-09-06 05:15:01,0.807827692044 2011-09-06 06:15:01,0.653708482915 2011-09-06 07:15:01,0.937306761036 2011-09-06 08:15:01,1.34108358121 2011-09-06 09:15:01,1.47226847333 2011-09-06 10:15:01,1.72638563622 2011-09-06 11:15:01,1.3196855493 2011-09-06 12:15:01,1.262905036 2011-09-06 14:15:01,1.2017614271 2011-09-06 15:15:01,1.10625236699 2011-09-06 16:15:01,1.45940072715 2011-09-06 17:15:01,1.09848556824 2011-09-06 18:15:01,0.953394382083 2011-09-06 19:15:01,0.878863784275 2011-09-06 20:15:01,1.12067995176 2011-09-06 21:15:01,0.991837847317 2011-09-06 22:15:01,0.831665933419 2011-09-06 23:15:01,0.60047251793 2011-09-07 00:15:01,0.555876363857 2011-09-07 01:15:01,0.823805154231 2011-09-07 02:15:01,0.678606401328 2011-09-07 03:15:01,0.687514096173 2011-09-07 04:15:01,0.657496548202 2011-09-07 05:15:01,0.75337310206 2011-09-07 06:15:01,0.8787691939 2011-09-07 07:15:01,1.14312883039 2011-09-07 08:15:01,1.15805690626 2011-09-07 09:15:01,1.63436764871 2011-09-07 10:15:01,1.74975517548 2011-09-07 11:15:01,2.01440045625 2011-09-07 12:15:01,1.49396356503 2011-09-07 13:15:01,0.908472003661 2011-09-07 14:15:01,1.34644468314 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/nyc_taxi.csv ================================================ timestamp,value 2014-07-01 00:00:00,10844 2014-07-01 00:30:00,8127 2014-07-01 01:00:00,6210 2014-07-01 01:30:00,4656 2014-07-01 02:00:00,3820 2014-07-01 02:30:00,2873 2014-07-01 03:00:00,2369 2014-07-01 03:30:00,2064 2014-07-01 04:00:00,2221 2014-07-01 04:30:00,2158 2014-07-01 05:00:00,2515 2014-07-01 05:30:00,4364 2014-07-01 06:00:00,6526 2014-07-01 06:30:00,11039 2014-07-01 07:00:00,13857 2014-07-01 07:30:00,15865 2014-07-01 08:00:00,17920 2014-07-01 08:30:00,20346 2014-07-01 09:00:00,19539 2014-07-01 09:30:00,20107 2014-07-01 10:00:00,18984 2014-07-01 10:30:00,17720 2014-07-01 11:00:00,17249 2014-07-01 11:30:00,18463 2014-07-01 12:00:00,18908 2014-07-01 12:30:00,18886 2014-07-01 13:00:00,18178 2014-07-01 13:30:00,19459 2014-07-01 14:00:00,19546 2014-07-01 14:30:00,20591 2014-07-01 15:00:00,19380 2014-07-01 15:30:00,18544 2014-07-01 16:00:00,16228 2014-07-01 16:30:00,15013 2014-07-01 17:00:00,17203 2014-07-01 17:30:00,19525 2014-07-01 18:00:00,22966 2014-07-01 18:30:00,27598 2014-07-01 19:00:00,26827 2014-07-01 19:30:00,24904 2014-07-01 20:00:00,22875 2014-07-01 20:30:00,20394 2014-07-01 21:00:00,23401 2014-07-01 21:30:00,24439 2014-07-01 22:00:00,23318 2014-07-01 22:30:00,21733 2014-07-01 23:00:00,20104 2014-07-01 23:30:00,16111 2014-07-02 00:00:00,13370 2014-07-02 00:30:00,9945 2014-07-02 01:00:00,7571 2014-07-02 01:30:00,5917 2014-07-02 02:00:00,4820 2014-07-02 02:30:00,3634 2014-07-02 03:00:00,2993 2014-07-02 03:30:00,2535 2014-07-02 04:00:00,2570 2014-07-02 04:30:00,2485 2014-07-02 05:00:00,2868 2014-07-02 05:30:00,4482 2014-07-02 06:00:00,6788 2014-07-02 06:30:00,11078 2014-07-02 07:00:00,13729 2014-07-02 07:30:00,16700 2014-07-02 08:00:00,19156 2014-07-02 08:30:00,19953 2014-07-02 09:00:00,19502 2014-07-02 09:30:00,18994 2014-07-02 10:00:00,17311 2014-07-02 10:30:00,17904 2014-07-02 11:00:00,17133 2014-07-02 11:30:00,18589 2014-07-02 12:00:00,19134 2014-07-02 12:30:00,19259 2014-07-02 13:00:00,18667 2014-07-02 13:30:00,19078 2014-07-02 14:00:00,18546 2014-07-02 14:30:00,18593 2014-07-02 15:00:00,17967 2014-07-02 15:30:00,16624 2014-07-02 16:00:00,14634 2014-07-02 16:30:00,13888 2014-07-02 17:00:00,17430 2014-07-02 17:30:00,21919 2014-07-02 18:00:00,23633 2014-07-02 18:30:00,24512 2014-07-02 19:00:00,24887 2014-07-02 19:30:00,26872 2014-07-02 20:00:00,22009 2014-07-02 20:30:00,18259 2014-07-02 21:00:00,20844 2014-07-02 21:30:00,22576 2014-07-02 22:00:00,22401 2014-07-02 22:30:00,19056 2014-07-02 23:00:00,17518 2014-07-02 23:30:00,15307 2014-07-03 00:00:00,12646 2014-07-03 00:30:00,10562 2014-07-03 01:00:00,8416 2014-07-03 01:30:00,7098 2014-07-03 02:00:00,5826 2014-07-03 02:30:00,4383 2014-07-03 03:00:00,3270 2014-07-03 03:30:00,2948 2014-07-03 04:00:00,3146 2014-07-03 04:30:00,3077 2014-07-03 05:00:00,3000 2014-07-03 05:30:00,4592 2014-07-03 06:00:00,6486 2014-07-03 06:30:00,10113 2014-07-03 07:00:00,12240 2014-07-03 07:30:00,14574 2014-07-03 08:00:00,16778 2014-07-03 08:30:00,18910 2014-07-03 09:00:00,18350 2014-07-03 09:30:00,17218 2014-07-03 10:00:00,16097 2014-07-03 10:30:00,16409 2014-07-03 11:00:00,15893 2014-07-03 11:30:00,16778 2014-07-03 12:00:00,17604 2014-07-03 12:30:00,18665 2014-07-03 13:00:00,19045 2014-07-03 13:30:00,19261 2014-07-03 14:00:00,19363 2014-07-03 14:30:00,19078 2014-07-03 15:00:00,18193 2014-07-03 15:30:00,16635 2014-07-03 16:00:00,14615 2014-07-03 16:30:00,13759 2014-07-03 17:00:00,17008 2014-07-03 17:30:00,19595 2014-07-03 18:00:00,21328 2014-07-03 18:30:00,22661 2014-07-03 19:00:00,29985 2014-07-03 19:30:00,21501 2014-07-03 20:00:00,22684 2014-07-03 20:30:00,22188 2014-07-03 21:00:00,22663 2014-07-03 21:30:00,19573 2014-07-03 22:00:00,17136 2014-07-03 22:30:00,16606 2014-07-03 23:00:00,16166 2014-07-03 23:30:00,16020 2014-07-04 00:00:00,15591 2014-07-04 00:30:00,14395 2014-07-04 01:00:00,12535 2014-07-04 01:30:00,11341 2014-07-04 02:00:00,9980 2014-07-04 02:30:00,8404 2014-07-04 03:00:00,7200 2014-07-04 03:30:00,6578 2014-07-04 04:00:00,5657 2014-07-04 04:30:00,4474 2014-07-04 05:00:00,3459 2014-07-04 05:30:00,3276 2014-07-04 06:00:00,3595 2014-07-04 06:30:00,4240 2014-07-04 07:00:00,4828 2014-07-04 07:30:00,4926 2014-07-04 08:00:00,5165 2014-07-04 08:30:00,5776 2014-07-04 09:00:00,7338 2014-07-04 09:30:00,7839 2014-07-04 10:00:00,8623 2014-07-04 10:30:00,9731 2014-07-04 11:00:00,11024 2014-07-04 11:30:00,13231 2014-07-04 12:00:00,13613 2014-07-04 12:30:00,13737 2014-07-04 13:00:00,15574 2014-07-04 13:30:00,14226 2014-07-04 14:00:00,18480 2014-07-04 14:30:00,18265 2014-07-04 15:00:00,16575 2014-07-04 15:30:00,16417 2014-07-04 16:00:00,14703 2014-07-04 16:30:00,13469 2014-07-04 17:00:00,12105 2014-07-04 17:30:00,11676 2014-07-04 18:00:00,15487 2014-07-04 18:30:00,15077 2014-07-04 19:00:00,14999 2014-07-04 19:30:00,14487 2014-07-04 20:00:00,14415 2014-07-04 20:30:00,13796 2014-07-04 21:00:00,14036 2014-07-04 21:30:00,14021 2014-07-04 22:00:00,15593 2014-07-04 22:30:00,16589 2014-07-04 23:00:00,17984 2014-07-04 23:30:00,18035 2014-07-05 00:00:00,17576 2014-07-05 00:30:00,16189 2014-07-05 01:00:00,14441 2014-07-05 01:30:00,12535 2014-07-05 02:00:00,11006 2014-07-05 02:30:00,9151 2014-07-05 03:00:00,8010 2014-07-05 03:30:00,7096 2014-07-05 04:00:00,6407 2014-07-05 04:30:00,4421 2014-07-05 05:00:00,3126 2014-07-05 05:30:00,2514 2014-07-05 06:00:00,2550 2014-07-05 06:30:00,3148 2014-07-05 07:00:00,3658 2014-07-05 07:30:00,4345 2014-07-05 08:00:00,4682 2014-07-05 08:30:00,6248 2014-07-05 09:00:00,7454 2014-07-05 09:30:00,9010 2014-07-05 10:00:00,10280 2014-07-05 10:30:00,11488 2014-07-05 11:00:00,11595 2014-07-05 11:30:00,13098 2014-07-05 12:00:00,12623 2014-07-05 12:30:00,13031 2014-07-05 13:00:00,13263 2014-07-05 13:30:00,13349 2014-07-05 14:00:00,13822 2014-07-05 14:30:00,13716 2014-07-05 15:00:00,13919 2014-07-05 15:30:00,14203 2014-07-05 16:00:00,13179 2014-07-05 16:30:00,13708 2014-07-05 17:00:00,13897 2014-07-05 17:30:00,14740 2014-07-05 18:00:00,14575 2014-07-05 18:30:00,16085 2014-07-05 19:00:00,18182 2014-07-05 19:30:00,16861 2014-07-05 20:00:00,14140 2014-07-05 20:30:00,14477 2014-07-05 21:00:00,15293 2014-07-05 21:30:00,15457 2014-07-05 22:00:00,16048 2014-07-05 22:30:00,17477 2014-07-05 23:00:00,16391 2014-07-05 23:30:00,17006 2014-07-06 00:00:00,15427 2014-07-06 00:30:00,14615 2014-07-06 01:00:00,13124 2014-07-06 01:30:00,12222 2014-07-06 02:00:00,11134 2014-07-06 02:30:00,9145 2014-07-06 03:00:00,8624 2014-07-06 03:30:00,7885 2014-07-06 04:00:00,7167 2014-07-06 04:30:00,4805 2014-07-06 05:00:00,3103 2014-07-06 05:30:00,2671 2014-07-06 06:00:00,2510 2014-07-06 06:30:00,2917 2014-07-06 07:00:00,3189 2014-07-06 07:30:00,4107 2014-07-06 08:00:00,4122 2014-07-06 08:30:00,5654 2014-07-06 09:00:00,6360 2014-07-06 09:30:00,8406 2014-07-06 10:00:00,9372 2014-07-06 10:30:00,11067 2014-07-06 11:00:00,11595 2014-07-06 11:30:00,12909 2014-07-06 12:00:00,13715 2014-07-06 12:30:00,13648 2014-07-06 13:00:00,14296 2014-07-06 13:30:00,14798 2014-07-06 14:00:00,15473 2014-07-06 14:30:00,16032 2014-07-06 15:00:00,14661 2014-07-06 15:30:00,14836 2014-07-06 16:00:00,13700 2014-07-06 16:30:00,14565 2014-07-06 17:00:00,15392 2014-07-06 17:30:00,16866 2014-07-06 18:00:00,16893 2014-07-06 18:30:00,16877 2014-07-06 19:00:00,17025 2014-07-06 19:30:00,15884 2014-07-06 20:00:00,14487 2014-07-06 20:30:00,14159 2014-07-06 21:00:00,16135 2014-07-06 21:30:00,16165 2014-07-06 22:00:00,14025 2014-07-06 22:30:00,13970 2014-07-06 23:00:00,13198 2014-07-06 23:30:00,11355 2014-07-07 00:00:00,8675 2014-07-07 00:30:00,7180 2014-07-07 01:00:00,5178 2014-07-07 01:30:00,3658 2014-07-07 02:00:00,3181 2014-07-07 02:30:00,2402 2014-07-07 03:00:00,1944 2014-07-07 03:30:00,1877 2014-07-07 04:00:00,2257 2014-07-07 04:30:00,2280 2014-07-07 05:00:00,2575 2014-07-07 05:30:00,4174 2014-07-07 06:00:00,6346 2014-07-07 06:30:00,10594 2014-07-07 07:00:00,12632 2014-07-07 07:30:00,14893 2014-07-07 08:00:00,16470 2014-07-07 08:30:00,18998 2014-07-07 09:00:00,17792 2014-07-07 09:30:00,16396 2014-07-07 10:00:00,14128 2014-07-07 10:30:00,14161 2014-07-07 11:00:00,14154 2014-07-07 11:30:00,15074 2014-07-07 12:00:00,15188 2014-07-07 12:30:00,15483 2014-07-07 13:00:00,15338 2014-07-07 13:30:00,16242 2014-07-07 14:00:00,16579 2014-07-07 14:30:00,16885 2014-07-07 15:00:00,16824 2014-07-07 15:30:00,16238 2014-07-07 16:00:00,15702 2014-07-07 16:30:00,15132 2014-07-07 17:00:00,17500 2014-07-07 17:30:00,19167 2014-07-07 18:00:00,21398 2014-07-07 18:30:00,22382 2014-07-07 19:00:00,22270 2014-07-07 19:30:00,20575 2014-07-07 20:00:00,18824 2014-07-07 20:30:00,17909 2014-07-07 21:00:00,19707 2014-07-07 21:30:00,19066 2014-07-07 22:00:00,17755 2014-07-07 22:30:00,16583 2014-07-07 23:00:00,14955 2014-07-07 23:30:00,11849 2014-07-08 00:00:00,9292 2014-07-08 00:30:00,8110 2014-07-08 01:00:00,7352 2014-07-08 01:30:00,5049 2014-07-08 02:00:00,3451 2014-07-08 02:30:00,2465 2014-07-08 03:00:00,2125 2014-07-08 03:30:00,1877 2014-07-08 04:00:00,2069 2014-07-08 04:30:00,2080 2014-07-08 05:00:00,2375 2014-07-08 05:30:00,4303 2014-07-08 06:00:00,6537 2014-07-08 06:30:00,11331 2014-07-08 07:00:00,13565 2014-07-08 07:30:00,16455 2014-07-08 08:00:00,18310 2014-07-08 08:30:00,20288 2014-07-08 09:00:00,19564 2014-07-08 09:30:00,19380 2014-07-08 10:00:00,16507 2014-07-08 10:30:00,16939 2014-07-08 11:00:00,16113 2014-07-08 11:30:00,17537 2014-07-08 12:00:00,18120 2014-07-08 12:30:00,18038 2014-07-08 13:00:00,17870 2014-07-08 13:30:00,18427 2014-07-08 14:00:00,18971 2014-07-08 14:30:00,19071 2014-07-08 15:00:00,18646 2014-07-08 15:30:00,18229 2014-07-08 16:00:00,15977 2014-07-08 16:30:00,15026 2014-07-08 17:00:00,17398 2014-07-08 17:30:00,20865 2014-07-08 18:00:00,23875 2014-07-08 18:30:00,25290 2014-07-08 19:00:00,25510 2014-07-08 19:30:00,24535 2014-07-08 20:00:00,21922 2014-07-08 20:30:00,20113 2014-07-08 21:00:00,22079 2014-07-08 21:30:00,23111 2014-07-08 22:00:00,25209 2014-07-08 22:30:00,21978 2014-07-08 23:00:00,18320 2014-07-08 23:30:00,14881 2014-07-09 00:00:00,12053 2014-07-09 00:30:00,9409 2014-07-09 01:00:00,7740 2014-07-09 01:30:00,5528 2014-07-09 02:00:00,4667 2014-07-09 02:30:00,3242 2014-07-09 03:00:00,2678 2014-07-09 03:30:00,2370 2014-07-09 04:00:00,2475 2014-07-09 04:30:00,2304 2014-07-09 05:00:00,2491 2014-07-09 05:30:00,4117 2014-07-09 06:00:00,6435 2014-07-09 06:30:00,11067 2014-07-09 07:00:00,13384 2014-07-09 07:30:00,17194 2014-07-09 08:00:00,18510 2014-07-09 08:30:00,20464 2014-07-09 09:00:00,19777 2014-07-09 09:30:00,18928 2014-07-09 10:00:00,17243 2014-07-09 10:30:00,17490 2014-07-09 11:00:00,16558 2014-07-09 11:30:00,17830 2014-07-09 12:00:00,18203 2014-07-09 12:30:00,18126 2014-07-09 13:00:00,18122 2014-07-09 13:30:00,18488 2014-07-09 14:00:00,18487 2014-07-09 14:30:00,18542 2014-07-09 15:00:00,18240 2014-07-09 15:30:00,17393 2014-07-09 16:00:00,15175 2014-07-09 16:30:00,15360 2014-07-09 17:00:00,17103 2014-07-09 17:30:00,19561 2014-07-09 18:00:00,22262 2014-07-09 18:30:00,24725 2014-07-09 19:00:00,25995 2014-07-09 19:30:00,26319 2014-07-09 20:00:00,24995 2014-07-09 20:30:00,20534 2014-07-09 21:00:00,23458 2014-07-09 21:30:00,24681 2014-07-09 22:00:00,23955 2014-07-09 22:30:00,23655 2014-07-09 23:00:00,21896 2014-07-09 23:30:00,19338 2014-07-10 00:00:00,15185 2014-07-10 00:30:00,11459 2014-07-10 01:00:00,8847 2014-07-10 01:30:00,6580 2014-07-10 02:00:00,5247 2014-07-10 02:30:00,4127 2014-07-10 03:00:00,3440 2014-07-10 03:30:00,2957 2014-07-10 04:00:00,2779 2014-07-10 04:30:00,2532 2014-07-10 05:00:00,2718 2014-07-10 05:30:00,4449 2014-07-10 06:00:00,6601 2014-07-10 06:30:00,11202 2014-07-10 07:00:00,13934 2014-07-10 07:30:00,17176 2014-07-10 08:00:00,19057 2014-07-10 08:30:00,21112 2014-07-10 09:00:00,19882 2014-07-10 09:30:00,19024 2014-07-10 10:00:00,16989 2014-07-10 10:30:00,16979 2014-07-10 11:00:00,16381 2014-07-10 11:30:00,17815 2014-07-10 12:00:00,18029 2014-07-10 12:30:00,17495 2014-07-10 13:00:00,17075 2014-07-10 13:30:00,18234 2014-07-10 14:00:00,18091 2014-07-10 14:30:00,18495 2014-07-10 15:00:00,17523 2014-07-10 15:30:00,16714 2014-07-10 16:00:00,14735 2014-07-10 16:30:00,13610 2014-07-10 17:00:00,16290 2014-07-10 17:30:00,19152 2014-07-10 18:00:00,21865 2014-07-10 18:30:00,24347 2014-07-10 19:00:00,26186 2014-07-10 19:30:00,25852 2014-07-10 20:00:00,23995 2014-07-10 20:30:00,21664 2014-07-10 21:00:00,25027 2014-07-10 21:30:00,25431 2014-07-10 22:00:00,25643 2014-07-10 22:30:00,24654 2014-07-10 23:00:00,23154 2014-07-10 23:30:00,21863 2014-07-11 00:00:00,20051 2014-07-11 00:30:00,16122 2014-07-11 01:00:00,13107 2014-07-11 01:30:00,10506 2014-07-11 02:00:00,8444 2014-07-11 02:30:00,6876 2014-07-11 03:00:00,5375 2014-07-11 03:30:00,4366 2014-07-11 04:00:00,4183 2014-07-11 04:30:00,3249 2014-07-11 05:00:00,3134 2014-07-11 05:30:00,4620 2014-07-11 06:00:00,6725 2014-07-11 06:30:00,10651 2014-07-11 07:00:00,12952 2014-07-11 07:30:00,15808 2014-07-11 08:00:00,17565 2014-07-11 08:30:00,19784 2014-07-11 09:00:00,19699 2014-07-11 09:30:00,18663 2014-07-11 10:00:00,16509 2014-07-11 10:30:00,16600 2014-07-11 11:00:00,15636 2014-07-11 11:30:00,17434 2014-07-11 12:00:00,17668 2014-07-11 12:30:00,17124 2014-07-11 13:00:00,17124 2014-07-11 13:30:00,17489 2014-07-11 14:00:00,18371 2014-07-11 14:30:00,18381 2014-07-11 15:00:00,17898 2014-07-11 15:30:00,16350 2014-07-11 16:00:00,14688 2014-07-11 16:30:00,14227 2014-07-11 17:00:00,16924 2014-07-11 17:30:00,19952 2014-07-11 18:00:00,22665 2014-07-11 18:30:00,23465 2014-07-11 19:00:00,25111 2014-07-11 19:30:00,23984 2014-07-11 20:00:00,21701 2014-07-11 20:30:00,20592 2014-07-11 21:00:00,22630 2014-07-11 21:30:00,22854 2014-07-11 22:00:00,23892 2014-07-11 22:30:00,24959 2014-07-11 23:00:00,26039 2014-07-11 23:30:00,26873 2014-07-12 00:00:00,25871 2014-07-12 00:30:00,24874 2014-07-12 01:00:00,23243 2014-07-12 01:30:00,21674 2014-07-12 02:00:00,19221 2014-07-12 02:30:00,16140 2014-07-12 03:00:00,13371 2014-07-12 03:30:00,12041 2014-07-12 04:00:00,10301 2014-07-12 04:30:00,6472 2014-07-12 05:00:00,4507 2014-07-12 05:30:00,3682 2014-07-12 06:00:00,3422 2014-07-12 06:30:00,4554 2014-07-12 07:00:00,5347 2014-07-12 07:30:00,6853 2014-07-12 08:00:00,7107 2014-07-12 08:30:00,9463 2014-07-12 09:00:00,11022 2014-07-12 09:30:00,13393 2014-07-12 10:00:00,13567 2014-07-12 10:30:00,15452 2014-07-12 11:00:00,15525 2014-07-12 11:30:00,17165 2014-07-12 12:00:00,17263 2014-07-12 12:30:00,18418 2014-07-12 13:00:00,18578 2014-07-12 13:30:00,18762 2014-07-12 14:00:00,18076 2014-07-12 14:30:00,18604 2014-07-12 15:00:00,18580 2014-07-12 15:30:00,19306 2014-07-12 16:00:00,18140 2014-07-12 16:30:00,17455 2014-07-12 17:00:00,18980 2014-07-12 17:30:00,21152 2014-07-12 18:00:00,22483 2014-07-12 18:30:00,22534 2014-07-12 19:00:00,22801 2014-07-12 19:30:00,22117 2014-07-12 20:00:00,19864 2014-07-12 20:30:00,19494 2014-07-12 21:00:00,20607 2014-07-12 21:30:00,20627 2014-07-12 22:00:00,21706 2014-07-12 22:30:00,24243 2014-07-12 23:00:00,25204 2014-07-12 23:30:00,25752 2014-07-13 00:00:00,25792 2014-07-13 00:30:00,25033 2014-07-13 01:00:00,23935 2014-07-13 01:30:00,21440 2014-07-13 02:00:00,19468 2014-07-13 02:30:00,16622 2014-07-13 03:00:00,14485 2014-07-13 03:30:00,12974 2014-07-13 04:00:00,11191 2014-07-13 04:30:00,6911 2014-07-13 05:00:00,4410 2014-07-13 05:30:00,3467 2014-07-13 06:00:00,3429 2014-07-13 06:30:00,3599 2014-07-13 07:00:00,3575 2014-07-13 07:30:00,4557 2014-07-13 08:00:00,5243 2014-07-13 08:30:00,6588 2014-07-13 09:00:00,8009 2014-07-13 09:30:00,10743 2014-07-13 10:00:00,13524 2014-07-13 10:30:00,16179 2014-07-13 11:00:00,14905 2014-07-13 11:30:00,16916 2014-07-13 12:00:00,17082 2014-07-13 12:30:00,18606 2014-07-13 13:00:00,18935 2014-07-13 13:30:00,20175 2014-07-13 14:00:00,22219 2014-07-13 14:30:00,22868 2014-07-13 15:00:00,20375 2014-07-13 15:30:00,18489 2014-07-13 16:00:00,16187 2014-07-13 16:30:00,14015 2014-07-13 17:00:00,14261 2014-07-13 17:30:00,20081 2014-07-13 18:00:00,21503 2014-07-13 18:30:00,19850 2014-07-13 19:00:00,18383 2014-07-13 19:30:00,17640 2014-07-13 20:00:00,16225 2014-07-13 20:30:00,15566 2014-07-13 21:00:00,17088 2014-07-13 21:30:00,16968 2014-07-13 22:00:00,15271 2014-07-13 22:30:00,14141 2014-07-13 23:00:00,12851 2014-07-13 23:30:00,13877 2014-07-14 00:00:00,12484 2014-07-14 00:30:00,9037 2014-07-14 01:00:00,7393 2014-07-14 01:30:00,5176 2014-07-14 02:00:00,3479 2014-07-14 02:30:00,2755 2014-07-14 03:00:00,2027 2014-07-14 03:30:00,1769 2014-07-14 04:00:00,2091 2014-07-14 04:30:00,2553 2014-07-14 05:00:00,2853 2014-07-14 05:30:00,4835 2014-07-14 06:00:00,6603 2014-07-14 06:30:00,11230 2014-07-14 07:00:00,13395 2014-07-14 07:30:00,15650 2014-07-14 08:00:00,17601 2014-07-14 08:30:00,18818 2014-07-14 09:00:00,18515 2014-07-14 09:30:00,16972 2014-07-14 10:00:00,15316 2014-07-14 10:30:00,16003 2014-07-14 11:00:00,14818 2014-07-14 11:30:00,15610 2014-07-14 12:00:00,16536 2014-07-14 12:30:00,16153 2014-07-14 13:00:00,15548 2014-07-14 13:30:00,16500 2014-07-14 14:00:00,16726 2014-07-14 14:30:00,16838 2014-07-14 15:00:00,16550 2014-07-14 15:30:00,16621 2014-07-14 16:00:00,15657 2014-07-14 16:30:00,15334 2014-07-14 17:00:00,17584 2014-07-14 17:30:00,20903 2014-07-14 18:00:00,21968 2014-07-14 18:30:00,26945 2014-07-14 19:00:00,24416 2014-07-14 19:30:00,22401 2014-07-14 20:00:00,23549 2014-07-14 20:30:00,21498 2014-07-14 21:00:00,23114 2014-07-14 21:30:00,23341 2014-07-14 22:00:00,22141 2014-07-14 22:30:00,19110 2014-07-14 23:00:00,16682 2014-07-14 23:30:00,12631 2014-07-15 00:00:00,10089 2014-07-15 00:30:00,8553 2014-07-15 01:00:00,6416 2014-07-15 01:30:00,4694 2014-07-15 02:00:00,3933 2014-07-15 02:30:00,2833 2014-07-15 03:00:00,2089 2014-07-15 03:30:00,1896 2014-07-15 04:00:00,2055 2014-07-15 04:30:00,2031 2014-07-15 05:00:00,2449 2014-07-15 05:30:00,4360 2014-07-15 06:00:00,7036 2014-07-15 06:30:00,11730 2014-07-15 07:00:00,14387 2014-07-15 07:30:00,17505 2014-07-15 08:00:00,19091 2014-07-15 08:30:00,21057 2014-07-15 09:00:00,20050 2014-07-15 09:30:00,18637 2014-07-15 10:00:00,17555 2014-07-15 10:30:00,17595 2014-07-15 11:00:00,16312 2014-07-15 11:30:00,18232 2014-07-15 12:00:00,18446 2014-07-15 12:30:00,18204 2014-07-15 13:00:00,17607 2014-07-15 13:30:00,18945 2014-07-15 14:00:00,22208 2014-07-15 14:30:00,21574 2014-07-15 15:00:00,17299 2014-07-15 15:30:00,15515 2014-07-15 16:00:00,13246 2014-07-15 16:30:00,12328 2014-07-15 17:00:00,15342 2014-07-15 17:30:00,18730 2014-07-15 18:00:00,23412 2014-07-15 18:30:00,26340 2014-07-15 19:00:00,27167 2014-07-15 19:30:00,26279 2014-07-15 20:00:00,23392 2014-07-15 20:30:00,21571 2014-07-15 21:00:00,23477 2014-07-15 21:30:00,22612 2014-07-15 22:00:00,21389 2014-07-15 22:30:00,19575 2014-07-15 23:00:00,18165 2014-07-15 23:30:00,14923 2014-07-16 00:00:00,11815 2014-07-16 00:30:00,9024 2014-07-16 01:00:00,7363 2014-07-16 01:30:00,5812 2014-07-16 02:00:00,4559 2014-07-16 02:30:00,3673 2014-07-16 03:00:00,2830 2014-07-16 03:30:00,2374 2014-07-16 04:00:00,2556 2014-07-16 04:30:00,2456 2014-07-16 05:00:00,2486 2014-07-16 05:30:00,4451 2014-07-16 06:00:00,6723 2014-07-16 06:30:00,12501 2014-07-16 07:00:00,14763 2014-07-16 07:30:00,18127 2014-07-16 08:00:00,20393 2014-07-16 08:30:00,20753 2014-07-16 09:00:00,20124 2014-07-16 09:30:00,19253 2014-07-16 10:00:00,17981 2014-07-16 10:30:00,17720 2014-07-16 11:00:00,16525 2014-07-16 11:30:00,18153 2014-07-16 12:00:00,18558 2014-07-16 12:30:00,17652 2014-07-16 13:00:00,17292 2014-07-16 13:30:00,17551 2014-07-16 14:00:00,17951 2014-07-16 14:30:00,17909 2014-07-16 15:00:00,17442 2014-07-16 15:30:00,16533 2014-07-16 16:00:00,14776 2014-07-16 16:30:00,13462 2014-07-16 17:00:00,16363 2014-07-16 17:30:00,19310 2014-07-16 18:00:00,22346 2014-07-16 18:30:00,24408 2014-07-16 19:00:00,26225 2014-07-16 19:30:00,25423 2014-07-16 20:00:00,23811 2014-07-16 20:30:00,22028 2014-07-16 21:00:00,24290 2014-07-16 21:30:00,24835 2014-07-16 22:00:00,24269 2014-07-16 22:30:00,23526 2014-07-16 23:00:00,21968 2014-07-16 23:30:00,20137 2014-07-17 00:00:00,16928 2014-07-17 00:30:00,12753 2014-07-17 01:00:00,10087 2014-07-17 01:30:00,7881 2014-07-17 02:00:00,6006 2014-07-17 02:30:00,4382 2014-07-17 03:00:00,3676 2014-07-17 03:30:00,3214 2014-07-17 04:00:00,3205 2014-07-17 04:30:00,2849 2014-07-17 05:00:00,2887 2014-07-17 05:30:00,5039 2014-07-17 06:00:00,7132 2014-07-17 06:30:00,12095 2014-07-17 07:00:00,14558 2014-07-17 07:30:00,17298 2014-07-17 08:00:00,19124 2014-07-17 08:30:00,20407 2014-07-17 09:00:00,19379 2014-07-17 09:30:00,18867 2014-07-17 10:00:00,17662 2014-07-17 10:30:00,17447 2014-07-17 11:00:00,16579 2014-07-17 11:30:00,18340 2014-07-17 12:00:00,18760 2014-07-17 12:30:00,18457 2014-07-17 13:00:00,17608 2014-07-17 13:30:00,18913 2014-07-17 14:00:00,19122 2014-07-17 14:30:00,19547 2014-07-17 15:00:00,17267 2014-07-17 15:30:00,15916 2014-07-17 16:00:00,13836 2014-07-17 16:30:00,11985 2014-07-17 17:00:00,14313 2014-07-17 17:30:00,17988 2014-07-17 18:00:00,21181 2014-07-17 18:30:00,23539 2014-07-17 19:00:00,24714 2014-07-17 19:30:00,25079 2014-07-17 20:00:00,23032 2014-07-17 20:30:00,21168 2014-07-17 21:00:00,25514 2014-07-17 21:30:00,26286 2014-07-17 22:00:00,25650 2014-07-17 22:30:00,24850 2014-07-17 23:00:00,23869 2014-07-17 23:30:00,22913 2014-07-18 00:00:00,20850 2014-07-18 00:30:00,16734 2014-07-18 01:00:00,14106 2014-07-18 01:30:00,11587 2014-07-18 02:00:00,8951 2014-07-18 02:30:00,7199 2014-07-18 03:00:00,6051 2014-07-18 03:30:00,4693 2014-07-18 04:00:00,4507 2014-07-18 04:30:00,3791 2014-07-18 05:00:00,3586 2014-07-18 05:30:00,4918 2014-07-18 06:00:00,7039 2014-07-18 06:30:00,11262 2014-07-18 07:00:00,13725 2014-07-18 07:30:00,15899 2014-07-18 08:00:00,17329 2014-07-18 08:30:00,19757 2014-07-18 09:00:00,19341 2014-07-18 09:30:00,17660 2014-07-18 10:00:00,16532 2014-07-18 10:30:00,16354 2014-07-18 11:00:00,16054 2014-07-18 11:30:00,17326 2014-07-18 12:00:00,17463 2014-07-18 12:30:00,17091 2014-07-18 13:00:00,16668 2014-07-18 13:30:00,17096 2014-07-18 14:00:00,17811 2014-07-18 14:30:00,17980 2014-07-18 15:00:00,17080 2014-07-18 15:30:00,15185 2014-07-18 16:00:00,13538 2014-07-18 16:30:00,12704 2014-07-18 17:00:00,15019 2014-07-18 17:30:00,18778 2014-07-18 18:00:00,21583 2014-07-18 18:30:00,23834 2014-07-18 19:00:00,25123 2014-07-18 19:30:00,24762 2014-07-18 20:00:00,22761 2014-07-18 20:30:00,22227 2014-07-18 21:00:00,23985 2014-07-18 21:30:00,23788 2014-07-18 22:00:00,23855 2014-07-18 22:30:00,26040 2014-07-18 23:00:00,25863 2014-07-18 23:30:00,25851 2014-07-19 00:00:00,26100 2014-07-19 00:30:00,24625 2014-07-19 01:00:00,22657 2014-07-19 01:30:00,20289 2014-07-19 02:00:00,18524 2014-07-19 02:30:00,15943 2014-07-19 03:00:00,13179 2014-07-19 03:30:00,12423 2014-07-19 04:00:00,10478 2014-07-19 04:30:00,6556 2014-07-19 05:00:00,4561 2014-07-19 05:30:00,3513 2014-07-19 06:00:00,3607 2014-07-19 06:30:00,4781 2014-07-19 07:00:00,5423 2014-07-19 07:30:00,6669 2014-07-19 08:00:00,7064 2014-07-19 08:30:00,9363 2014-07-19 09:00:00,10874 2014-07-19 09:30:00,13255 2014-07-19 10:00:00,13164 2014-07-19 10:30:00,15159 2014-07-19 11:00:00,16030 2014-07-19 11:30:00,18256 2014-07-19 12:00:00,17751 2014-07-19 12:30:00,17675 2014-07-19 13:00:00,18557 2014-07-19 13:30:00,18389 2014-07-19 14:00:00,17538 2014-07-19 14:30:00,17506 2014-07-19 15:00:00,17580 2014-07-19 15:30:00,18027 2014-07-19 16:00:00,16959 2014-07-19 16:30:00,17066 2014-07-19 17:00:00,18155 2014-07-19 17:30:00,20610 2014-07-19 18:00:00,20793 2014-07-19 18:30:00,21584 2014-07-19 19:00:00,23493 2014-07-19 19:30:00,22555 2014-07-19 20:00:00,20183 2014-07-19 20:30:00,20441 2014-07-19 21:00:00,21555 2014-07-19 21:30:00,22406 2014-07-19 22:00:00,22512 2014-07-19 22:30:00,24667 2014-07-19 23:00:00,25424 2014-07-19 23:30:00,25852 2014-07-20 00:00:00,25137 2014-07-20 00:30:00,24099 2014-07-20 01:00:00,23058 2014-07-20 01:30:00,20786 2014-07-20 02:00:00,19217 2014-07-20 02:30:00,16329 2014-07-20 03:00:00,14293 2014-07-20 03:30:00,13193 2014-07-20 04:00:00,11166 2014-07-20 04:30:00,7518 2014-07-20 05:00:00,4877 2014-07-20 05:30:00,3639 2014-07-20 06:00:00,3412 2014-07-20 06:30:00,3827 2014-07-20 07:00:00,3922 2014-07-20 07:30:00,5241 2014-07-20 08:00:00,5601 2014-07-20 08:30:00,7147 2014-07-20 09:00:00,8425 2014-07-20 09:30:00,10951 2014-07-20 10:00:00,11800 2014-07-20 10:30:00,13936 2014-07-20 11:00:00,14835 2014-07-20 11:30:00,16412 2014-07-20 12:00:00,16763 2014-07-20 12:30:00,17613 2014-07-20 13:00:00,17439 2014-07-20 13:30:00,17921 2014-07-20 14:00:00,18605 2014-07-20 14:30:00,18113 2014-07-20 15:00:00,17579 2014-07-20 15:30:00,16927 2014-07-20 16:00:00,16526 2014-07-20 16:30:00,16956 2014-07-20 17:00:00,17381 2014-07-20 17:30:00,19232 2014-07-20 18:00:00,19127 2014-07-20 18:30:00,19404 2014-07-20 19:00:00,18812 2014-07-20 19:30:00,18253 2014-07-20 20:00:00,16497 2014-07-20 20:30:00,16681 2014-07-20 21:00:00,17334 2014-07-20 21:30:00,17674 2014-07-20 22:00:00,16469 2014-07-20 22:30:00,15128 2014-07-20 23:00:00,13973 2014-07-20 23:30:00,12040 2014-07-21 00:00:00,9494 2014-07-21 00:30:00,6963 2014-07-21 01:00:00,5611 2014-07-21 01:30:00,4140 2014-07-21 02:00:00,3370 2014-07-21 02:30:00,2625 2014-07-21 03:00:00,2093 2014-07-21 03:30:00,1854 2014-07-21 04:00:00,2482 2014-07-21 04:30:00,2529 2014-07-21 05:00:00,2968 2014-07-21 05:30:00,4540 2014-07-21 06:00:00,6868 2014-07-21 06:30:00,10765 2014-07-21 07:00:00,13095 2014-07-21 07:30:00,15651 2014-07-21 08:00:00,17427 2014-07-21 08:30:00,18637 2014-07-21 09:00:00,18614 2014-07-21 09:30:00,17187 2014-07-21 10:00:00,15281 2014-07-21 10:30:00,15505 2014-07-21 11:00:00,15168 2014-07-21 11:30:00,15813 2014-07-21 12:00:00,15979 2014-07-21 12:30:00,16314 2014-07-21 13:00:00,16002 2014-07-21 13:30:00,16845 2014-07-21 14:00:00,17009 2014-07-21 14:30:00,17302 2014-07-21 15:00:00,16649 2014-07-21 15:30:00,16857 2014-07-21 16:00:00,15733 2014-07-21 16:30:00,15537 2014-07-21 17:00:00,17362 2014-07-21 17:30:00,19639 2014-07-21 18:00:00,22891 2014-07-21 18:30:00,22920 2014-07-21 19:00:00,22941 2014-07-21 19:30:00,21849 2014-07-21 20:00:00,20483 2014-07-21 20:30:00,18868 2014-07-21 21:00:00,20235 2014-07-21 21:30:00,20658 2014-07-21 22:00:00,20751 2014-07-21 22:30:00,18642 2014-07-21 23:00:00,16106 2014-07-21 23:30:00,13303 2014-07-22 00:00:00,10611 2014-07-22 00:30:00,8009 2014-07-22 01:00:00,6210 2014-07-22 01:30:00,4830 2014-07-22 02:00:00,3753 2014-07-22 02:30:00,2962 2014-07-22 03:00:00,2379 2014-07-22 03:30:00,2114 2014-07-22 04:00:00,2232 2014-07-22 04:30:00,2090 2014-07-22 05:00:00,2532 2014-07-22 05:30:00,4492 2014-07-22 06:00:00,6830 2014-07-22 06:30:00,11269 2014-07-22 07:00:00,13635 2014-07-22 07:30:00,16356 2014-07-22 08:00:00,18449 2014-07-22 08:30:00,20054 2014-07-22 09:00:00,19462 2014-07-22 09:30:00,19016 2014-07-22 10:00:00,17349 2014-07-22 10:30:00,17684 2014-07-22 11:00:00,17412 2014-07-22 11:30:00,17854 2014-07-22 12:00:00,18649 2014-07-22 12:30:00,19970 2014-07-22 13:00:00,19168 2014-07-22 13:30:00,19270 2014-07-22 14:00:00,19463 2014-07-22 14:30:00,18999 2014-07-22 15:00:00,17998 2014-07-22 15:30:00,17209 2014-07-22 16:00:00,15581 2014-07-22 16:30:00,14846 2014-07-22 17:00:00,17832 2014-07-22 17:30:00,21545 2014-07-22 18:00:00,24769 2014-07-22 18:30:00,25573 2014-07-22 19:00:00,26243 2014-07-22 19:30:00,25057 2014-07-22 20:00:00,23381 2014-07-22 20:30:00,22148 2014-07-22 21:00:00,24590 2014-07-22 21:30:00,24168 2014-07-22 22:00:00,23364 2014-07-22 22:30:00,23272 2014-07-22 23:00:00,19939 2014-07-22 23:30:00,17316 2014-07-23 00:00:00,13369 2014-07-23 00:30:00,10390 2014-07-23 01:00:00,7994 2014-07-23 01:30:00,5889 2014-07-23 02:00:00,4711 2014-07-23 02:30:00,3757 2014-07-23 03:00:00,3066 2014-07-23 03:30:00,2647 2014-07-23 04:00:00,2645 2014-07-23 04:30:00,2411 2014-07-23 05:00:00,2600 2014-07-23 05:30:00,4483 2014-07-23 06:00:00,6956 2014-07-23 06:30:00,11788 2014-07-23 07:00:00,14098 2014-07-23 07:30:00,17141 2014-07-23 08:00:00,19124 2014-07-23 08:30:00,20604 2014-07-23 09:00:00,20114 2014-07-23 09:30:00,19641 2014-07-23 10:00:00,18423 2014-07-23 10:30:00,18480 2014-07-23 11:00:00,18318 2014-07-23 11:30:00,19378 2014-07-23 12:00:00,19585 2014-07-23 12:30:00,19614 2014-07-23 13:00:00,19295 2014-07-23 13:30:00,19850 2014-07-23 14:00:00,20120 2014-07-23 14:30:00,19621 2014-07-23 15:00:00,18809 2014-07-23 15:30:00,17731 2014-07-23 16:00:00,15483 2014-07-23 16:30:00,15112 2014-07-23 17:00:00,18183 2014-07-23 17:30:00,21187 2014-07-23 18:00:00,24034 2014-07-23 18:30:00,25411 2014-07-23 19:00:00,26528 2014-07-23 19:30:00,26022 2014-07-23 20:00:00,23253 2014-07-23 20:30:00,25665 2014-07-23 21:00:00,26600 2014-07-23 21:30:00,24757 2014-07-23 22:00:00,24337 2014-07-23 22:30:00,24294 2014-07-23 23:00:00,22087 2014-07-23 23:30:00,19064 2014-07-24 00:00:00,15542 2014-07-24 00:30:00,12026 2014-07-24 01:00:00,8678 2014-07-24 01:30:00,7042 2014-07-24 02:00:00,5355 2014-07-24 02:30:00,4129 2014-07-24 03:00:00,3109 2014-07-24 03:30:00,2534 2014-07-24 04:00:00,2788 2014-07-24 04:30:00,2507 2014-07-24 05:00:00,2671 2014-07-24 05:30:00,4445 2014-07-24 06:00:00,7163 2014-07-24 06:30:00,11942 2014-07-24 07:00:00,14544 2014-07-24 07:30:00,17435 2014-07-24 08:00:00,19254 2014-07-24 08:30:00,20518 2014-07-24 09:00:00,20003 2014-07-24 09:30:00,19642 2014-07-24 10:00:00,17626 2014-07-24 10:30:00,18194 2014-07-24 11:00:00,16975 2014-07-24 11:30:00,18125 2014-07-24 12:00:00,18555 2014-07-24 12:30:00,18356 2014-07-24 13:00:00,17683 2014-07-24 13:30:00,18298 2014-07-24 14:00:00,18613 2014-07-24 14:30:00,18548 2014-07-24 15:00:00,17742 2014-07-24 15:30:00,16312 2014-07-24 16:00:00,14782 2014-07-24 16:30:00,13614 2014-07-24 17:00:00,16220 2014-07-24 17:30:00,18901 2014-07-24 18:00:00,21794 2014-07-24 18:30:00,23933 2014-07-24 19:00:00,25474 2014-07-24 19:30:00,24985 2014-07-24 20:00:00,22877 2014-07-24 20:30:00,22518 2014-07-24 21:00:00,25246 2014-07-24 21:30:00,25871 2014-07-24 22:00:00,25324 2014-07-24 22:30:00,25738 2014-07-24 23:00:00,24763 2014-07-24 23:30:00,23158 2014-07-25 00:00:00,20525 2014-07-25 00:30:00,17608 2014-07-25 01:00:00,14436 2014-07-25 01:30:00,11145 2014-07-25 02:00:00,8915 2014-07-25 02:30:00,7244 2014-07-25 03:00:00,5856 2014-07-25 03:30:00,4953 2014-07-25 04:00:00,4546 2014-07-25 04:30:00,3589 2014-07-25 05:00:00,3516 2014-07-25 05:30:00,5087 2014-07-25 06:00:00,7102 2014-07-25 06:30:00,10887 2014-07-25 07:00:00,12988 2014-07-25 07:30:00,15831 2014-07-25 08:00:00,17326 2014-07-25 08:30:00,19179 2014-07-25 09:00:00,18805 2014-07-25 09:30:00,17730 2014-07-25 10:00:00,16439 2014-07-25 10:30:00,16401 2014-07-25 11:00:00,16240 2014-07-25 11:30:00,17487 2014-07-25 12:00:00,17622 2014-07-25 12:30:00,17313 2014-07-25 13:00:00,16647 2014-07-25 13:30:00,16627 2014-07-25 14:00:00,17646 2014-07-25 14:30:00,17694 2014-07-25 15:00:00,17661 2014-07-25 15:30:00,15842 2014-07-25 16:00:00,14950 2014-07-25 16:30:00,13473 2014-07-25 17:00:00,16633 2014-07-25 17:30:00,19501 2014-07-25 18:00:00,22009 2014-07-25 18:30:00,23891 2014-07-25 19:00:00,25196 2014-07-25 19:30:00,24427 2014-07-25 20:00:00,22357 2014-07-25 20:30:00,22460 2014-07-25 21:00:00,24066 2014-07-25 21:30:00,23690 2014-07-25 22:00:00,24491 2014-07-25 22:30:00,25737 2014-07-25 23:00:00,26688 2014-07-25 23:30:00,26230 2014-07-26 00:00:00,26300 2014-07-26 00:30:00,24337 2014-07-26 01:00:00,23124 2014-07-26 01:30:00,20675 2014-07-26 02:00:00,18663 2014-07-26 02:30:00,15997 2014-07-26 03:00:00,13405 2014-07-26 03:30:00,11921 2014-07-26 04:00:00,10203 2014-07-26 04:30:00,6543 2014-07-26 05:00:00,4719 2014-07-26 05:30:00,3853 2014-07-26 06:00:00,4116 2014-07-26 06:30:00,5274 2014-07-26 07:00:00,5331 2014-07-26 07:30:00,6830 2014-07-26 08:00:00,7303 2014-07-26 08:30:00,9704 2014-07-26 09:00:00,11209 2014-07-26 09:30:00,13874 2014-07-26 10:00:00,14548 2014-07-26 10:30:00,16204 2014-07-26 11:00:00,16938 2014-07-26 11:30:00,18696 2014-07-26 12:00:00,17585 2014-07-26 12:30:00,18538 2014-07-26 13:00:00,18206 2014-07-26 13:30:00,17532 2014-07-26 14:00:00,17657 2014-07-26 14:30:00,17943 2014-07-26 15:00:00,17698 2014-07-26 15:30:00,18074 2014-07-26 16:00:00,16920 2014-07-26 16:30:00,18262 2014-07-26 17:00:00,19013 2014-07-26 17:30:00,19902 2014-07-26 18:00:00,20449 2014-07-26 18:30:00,22190 2014-07-26 19:00:00,23099 2014-07-26 19:30:00,22128 2014-07-26 20:00:00,20110 2014-07-26 20:30:00,20261 2014-07-26 21:00:00,22299 2014-07-26 21:30:00,21886 2014-07-26 22:00:00,22600 2014-07-26 22:30:00,24667 2014-07-26 23:00:00,25662 2014-07-26 23:30:00,25832 2014-07-27 00:00:00,25659 2014-07-27 00:30:00,24748 2014-07-27 01:00:00,22552 2014-07-27 01:30:00,20712 2014-07-27 02:00:00,19122 2014-07-27 02:30:00,16777 2014-07-27 03:00:00,14475 2014-07-27 03:30:00,12720 2014-07-27 04:00:00,11239 2014-07-27 04:30:00,7087 2014-07-27 05:00:00,4896 2014-07-27 05:30:00,3818 2014-07-27 06:00:00,3449 2014-07-27 06:30:00,3883 2014-07-27 07:00:00,3810 2014-07-27 07:30:00,5059 2014-07-27 08:00:00,5476 2014-07-27 08:30:00,7083 2014-07-27 09:00:00,8153 2014-07-27 09:30:00,10647 2014-07-27 10:00:00,11873 2014-07-27 10:30:00,14193 2014-07-27 11:00:00,14938 2014-07-27 11:30:00,16488 2014-07-27 12:00:00,16996 2014-07-27 12:30:00,17381 2014-07-27 13:00:00,18173 2014-07-27 13:30:00,17651 2014-07-27 14:00:00,18698 2014-07-27 14:30:00,18260 2014-07-27 15:00:00,18181 2014-07-27 15:30:00,17413 2014-07-27 16:00:00,17230 2014-07-27 16:30:00,18275 2014-07-27 17:00:00,18883 2014-07-27 17:30:00,19851 2014-07-27 18:00:00,19673 2014-07-27 18:30:00,20508 2014-07-27 19:00:00,19557 2014-07-27 19:30:00,18268 2014-07-27 20:00:00,16615 2014-07-27 20:30:00,16969 2014-07-27 21:00:00,18252 2014-07-27 21:30:00,16920 2014-07-27 22:00:00,16356 2014-07-27 22:30:00,15567 2014-07-27 23:00:00,14278 2014-07-27 23:30:00,12786 2014-07-28 00:00:00,10323 2014-07-28 00:30:00,7645 2014-07-28 01:00:00,6791 2014-07-28 01:30:00,5394 2014-07-28 02:00:00,3694 2014-07-28 02:30:00,2713 2014-07-28 03:00:00,2376 2014-07-28 03:30:00,2146 2014-07-28 04:00:00,2250 2014-07-28 04:30:00,2370 2014-07-28 05:00:00,2906 2014-07-28 05:30:00,4477 2014-07-28 06:00:00,6446 2014-07-28 06:30:00,9332 2014-07-28 07:00:00,10577 2014-07-28 07:30:00,11765 2014-07-28 08:00:00,13452 2014-07-28 08:30:00,14290 2014-07-28 09:00:00,15239 2014-07-28 09:30:00,14926 2014-07-28 10:00:00,14475 2014-07-28 10:30:00,14435 2014-07-28 11:00:00,14103 2014-07-28 11:30:00,15124 2014-07-28 12:00:00,15376 2014-07-28 12:30:00,15758 2014-07-28 13:00:00,14653 2014-07-28 13:30:00,15786 2014-07-28 14:00:00,15554 2014-07-28 14:30:00,16332 2014-07-28 15:00:00,15602 2014-07-28 15:30:00,14931 2014-07-28 16:00:00,13817 2014-07-28 16:30:00,13611 2014-07-28 17:00:00,14678 2014-07-28 17:30:00,16669 2014-07-28 18:00:00,18171 2014-07-28 18:30:00,20033 2014-07-28 19:00:00,20467 2014-07-28 19:30:00,20263 2014-07-28 20:00:00,18901 2014-07-28 20:30:00,18249 2014-07-28 21:00:00,18421 2014-07-28 21:30:00,17932 2014-07-28 22:00:00,17568 2014-07-28 22:30:00,16656 2014-07-28 23:00:00,15574 2014-07-28 23:30:00,13310 2014-07-29 00:00:00,10468 2014-07-29 00:30:00,7932 2014-07-29 01:00:00,6080 2014-07-29 01:30:00,4735 2014-07-29 02:00:00,3834 2014-07-29 02:30:00,2746 2014-07-29 03:00:00,2244 2014-07-29 03:30:00,1940 2014-07-29 04:00:00,2066 2014-07-29 04:30:00,2046 2014-07-29 05:00:00,2295 2014-07-29 05:30:00,4533 2014-07-29 06:00:00,6655 2014-07-29 06:30:00,11415 2014-07-29 07:00:00,13863 2014-07-29 07:30:00,15517 2014-07-29 08:00:00,17106 2014-07-29 08:30:00,18521 2014-07-29 09:00:00,18016 2014-07-29 09:30:00,17448 2014-07-29 10:00:00,16131 2014-07-29 10:30:00,16534 2014-07-29 11:00:00,15744 2014-07-29 11:30:00,17039 2014-07-29 12:00:00,17357 2014-07-29 12:30:00,16841 2014-07-29 13:00:00,16797 2014-07-29 13:30:00,17226 2014-07-29 14:00:00,17550 2014-07-29 14:30:00,17336 2014-07-29 15:00:00,17343 2014-07-29 15:30:00,16601 2014-07-29 16:00:00,15090 2014-07-29 16:30:00,14130 2014-07-29 17:00:00,16356 2014-07-29 17:30:00,19357 2014-07-29 18:00:00,22313 2014-07-29 18:30:00,23636 2014-07-29 19:00:00,24822 2014-07-29 19:30:00,24550 2014-07-29 20:00:00,22761 2014-07-29 20:30:00,23119 2014-07-29 21:00:00,23658 2014-07-29 21:30:00,23853 2014-07-29 22:00:00,22995 2014-07-29 22:30:00,21708 2014-07-29 23:00:00,20231 2014-07-29 23:30:00,17264 2014-07-30 00:00:00,13549 2014-07-30 00:30:00,10142 2014-07-30 01:00:00,7783 2014-07-30 01:30:00,6011 2014-07-30 02:00:00,4935 2014-07-30 02:30:00,3668 2014-07-30 03:00:00,3092 2014-07-30 03:30:00,2577 2014-07-30 04:00:00,2772 2014-07-30 04:30:00,2637 2014-07-30 05:00:00,2605 2014-07-30 05:30:00,4449 2014-07-30 06:00:00,6912 2014-07-30 06:30:00,11909 2014-07-30 07:00:00,14184 2014-07-30 07:30:00,17246 2014-07-30 08:00:00,18393 2014-07-30 08:30:00,19797 2014-07-30 09:00:00,19101 2014-07-30 09:30:00,18889 2014-07-30 10:00:00,16897 2014-07-30 10:30:00,16922 2014-07-30 11:00:00,16218 2014-07-30 11:30:00,17511 2014-07-30 12:00:00,17941 2014-07-30 12:30:00,17203 2014-07-30 13:00:00,16879 2014-07-30 13:30:00,17733 2014-07-30 14:00:00,17587 2014-07-30 14:30:00,17564 2014-07-30 15:00:00,17003 2014-07-30 15:30:00,15725 2014-07-30 16:00:00,13832 2014-07-30 16:30:00,12826 2014-07-30 17:00:00,15603 2014-07-30 17:30:00,18935 2014-07-30 18:00:00,21175 2014-07-30 18:30:00,22980 2014-07-30 19:00:00,24644 2014-07-30 19:30:00,24938 2014-07-30 20:00:00,24095 2014-07-30 20:30:00,23952 2014-07-30 21:00:00,24913 2014-07-30 21:30:00,25138 2014-07-30 22:00:00,24972 2014-07-30 22:30:00,23605 2014-07-30 23:00:00,22758 2014-07-30 23:30:00,19560 2014-07-31 00:00:00,15486 2014-07-31 00:30:00,12362 2014-07-31 01:00:00,9401 2014-07-31 01:30:00,7131 2014-07-31 02:00:00,5949 2014-07-31 02:30:00,4722 2014-07-31 03:00:00,3792 2014-07-31 03:30:00,3266 2014-07-31 04:00:00,3267 2014-07-31 04:30:00,2605 2014-07-31 05:00:00,2562 2014-07-31 05:30:00,4595 2014-07-31 06:00:00,7263 2014-07-31 06:30:00,11825 2014-07-31 07:00:00,13863 2014-07-31 07:30:00,16898 2014-07-31 08:00:00,18741 2014-07-31 08:30:00,20117 2014-07-31 09:00:00,19185 2014-07-31 09:30:00,17821 2014-07-31 10:00:00,16721 2014-07-31 10:30:00,16869 2014-07-31 11:00:00,16188 2014-07-31 11:30:00,17325 2014-07-31 12:00:00,17849 2014-07-31 12:30:00,17746 2014-07-31 13:00:00,17208 2014-07-31 13:30:00,17848 2014-07-31 14:00:00,18132 2014-07-31 14:30:00,18019 2014-07-31 15:00:00,17120 2014-07-31 15:30:00,15410 2014-07-31 16:00:00,13868 2014-07-31 16:30:00,13146 2014-07-31 17:00:00,15734 2014-07-31 17:30:00,18139 2014-07-31 18:00:00,20969 2014-07-31 18:30:00,23287 2014-07-31 19:00:00,24723 2014-07-31 19:30:00,25186 2014-07-31 20:00:00,24192 2014-07-31 20:30:00,24605 2014-07-31 21:00:00,25805 2014-07-31 21:30:00,25969 2014-07-31 22:00:00,25593 2014-07-31 22:30:00,24695 2014-07-31 23:00:00,24316 2014-07-31 23:30:00,23050 2014-08-01 00:00:00,20138 2014-08-01 00:30:00,17252 2014-08-01 01:00:00,14103 2014-08-01 01:30:00,10859 2014-08-01 02:00:00,9242 2014-08-01 02:30:00,7122 2014-08-01 03:00:00,5763 2014-08-01 03:30:00,4912 2014-08-01 04:00:00,4648 2014-08-01 04:30:00,3673 2014-08-01 05:00:00,3322 2014-08-01 05:30:00,4968 2014-08-01 06:00:00,7209 2014-08-01 06:30:00,11113 2014-08-01 07:00:00,13143 2014-08-01 07:30:00,15932 2014-08-01 08:00:00,17355 2014-08-01 08:30:00,19462 2014-08-01 09:00:00,18581 2014-08-01 09:30:00,18123 2014-08-01 10:00:00,16476 2014-08-01 10:30:00,16964 2014-08-01 11:00:00,16009 2014-08-01 11:30:00,16890 2014-08-01 12:00:00,17069 2014-08-01 12:30:00,16779 2014-08-01 13:00:00,16654 2014-08-01 13:30:00,16580 2014-08-01 14:00:00,17407 2014-08-01 14:30:00,17037 2014-08-01 15:00:00,16651 2014-08-01 15:30:00,15324 2014-08-01 16:00:00,12987 2014-08-01 16:30:00,12845 2014-08-01 17:00:00,15439 2014-08-01 17:30:00,18280 2014-08-01 18:00:00,20439 2014-08-01 18:30:00,22588 2014-08-01 19:00:00,24047 2014-08-01 19:30:00,23745 2014-08-01 20:00:00,22420 2014-08-01 20:30:00,23260 2014-08-01 21:00:00,23454 2014-08-01 21:30:00,22822 2014-08-01 22:00:00,23704 2014-08-01 22:30:00,24940 2014-08-01 23:00:00,25951 2014-08-01 23:30:00,25479 2014-08-02 00:00:00,25234 2014-08-02 00:30:00,23378 2014-08-02 01:00:00,22180 2014-08-02 01:30:00,20497 2014-08-02 02:00:00,18933 2014-08-02 02:30:00,17041 2014-08-02 03:00:00,14983 2014-08-02 03:30:00,12488 2014-08-02 04:00:00,10554 2014-08-02 04:30:00,6425 2014-08-02 05:00:00,4384 2014-08-02 05:30:00,3611 2014-08-02 06:00:00,3904 2014-08-02 06:30:00,5204 2014-08-02 07:00:00,5624 2014-08-02 07:30:00,7264 2014-08-02 08:00:00,7501 2014-08-02 08:30:00,9344 2014-08-02 09:00:00,10021 2014-08-02 09:30:00,12227 2014-08-02 10:00:00,12203 2014-08-02 10:30:00,14669 2014-08-02 11:00:00,14849 2014-08-02 11:30:00,16363 2014-08-02 12:00:00,16489 2014-08-02 12:30:00,17237 2014-08-02 13:00:00,17955 2014-08-02 13:30:00,17713 2014-08-02 14:00:00,17418 2014-08-02 14:30:00,17679 2014-08-02 15:00:00,18014 2014-08-02 15:30:00,18031 2014-08-02 16:00:00,17643 2014-08-02 16:30:00,17167 2014-08-02 17:00:00,18409 2014-08-02 17:30:00,20034 2014-08-02 18:00:00,21113 2014-08-02 18:30:00,21487 2014-08-02 19:00:00,22872 2014-08-02 19:30:00,22995 2014-08-02 20:00:00,20896 2014-08-02 20:30:00,21411 2014-08-02 21:00:00,21273 2014-08-02 21:30:00,21628 2014-08-02 22:00:00,21872 2014-08-02 22:30:00,23457 2014-08-02 23:00:00,24958 2014-08-02 23:30:00,24984 2014-08-03 00:00:00,24613 2014-08-03 00:30:00,23468 2014-08-03 01:00:00,22125 2014-08-03 01:30:00,22220 2014-08-03 02:00:00,20171 2014-08-03 02:30:00,17690 2014-08-03 03:00:00,14908 2014-08-03 03:30:00,13465 2014-08-03 04:00:00,11663 2014-08-03 04:30:00,6997 2014-08-03 05:00:00,4810 2014-08-03 05:30:00,3650 2014-08-03 06:00:00,3561 2014-08-03 06:30:00,4060 2014-08-03 07:00:00,4382 2014-08-03 07:30:00,5741 2014-08-03 08:00:00,6722 2014-08-03 08:30:00,7857 2014-08-03 09:00:00,8424 2014-08-03 09:30:00,10636 2014-08-03 10:00:00,11811 2014-08-03 10:30:00,13776 2014-08-03 11:00:00,14821 2014-08-03 11:30:00,16169 2014-08-03 12:00:00,16715 2014-08-03 12:30:00,17652 2014-08-03 13:00:00,17360 2014-08-03 13:30:00,17167 2014-08-03 14:00:00,18546 2014-08-03 14:30:00,17882 2014-08-03 15:00:00,17268 2014-08-03 15:30:00,17322 2014-08-03 16:00:00,16500 2014-08-03 16:30:00,16446 2014-08-03 17:00:00,17317 2014-08-03 17:30:00,18472 2014-08-03 18:00:00,19503 2014-08-03 18:30:00,19622 2014-08-03 19:00:00,18900 2014-08-03 19:30:00,17188 2014-08-03 20:00:00,16880 2014-08-03 20:30:00,17035 2014-08-03 21:00:00,16790 2014-08-03 21:30:00,17007 2014-08-03 22:00:00,15893 2014-08-03 22:30:00,14672 2014-08-03 23:00:00,12667 2014-08-03 23:30:00,10905 2014-08-04 00:00:00,8882 2014-08-04 00:30:00,6896 2014-08-04 01:00:00,5417 2014-08-04 01:30:00,4245 2014-08-04 02:00:00,3478 2014-08-04 02:30:00,2525 2014-08-04 03:00:00,2288 2014-08-04 03:30:00,2114 2014-08-04 04:00:00,2212 2014-08-04 04:30:00,2303 2014-08-04 05:00:00,2482 2014-08-04 05:30:00,4420 2014-08-04 06:00:00,6426 2014-08-04 06:30:00,10775 2014-08-04 07:00:00,12795 2014-08-04 07:30:00,15762 2014-08-04 08:00:00,17271 2014-08-04 08:30:00,18418 2014-08-04 09:00:00,18214 2014-08-04 09:30:00,17223 2014-08-04 10:00:00,15029 2014-08-04 10:30:00,15614 2014-08-04 11:00:00,15026 2014-08-04 11:30:00,16170 2014-08-04 12:00:00,16111 2014-08-04 12:30:00,16049 2014-08-04 13:00:00,16084 2014-08-04 13:30:00,16640 2014-08-04 14:00:00,16634 2014-08-04 14:30:00,17210 2014-08-04 15:00:00,16546 2014-08-04 15:30:00,16798 2014-08-04 16:00:00,15124 2014-08-04 16:30:00,14870 2014-08-04 17:00:00,16956 2014-08-04 17:30:00,18613 2014-08-04 18:00:00,21126 2014-08-04 18:30:00,22510 2014-08-04 19:00:00,22568 2014-08-04 19:30:00,21668 2014-08-04 20:00:00,21659 2014-08-04 20:30:00,21278 2014-08-04 21:00:00,21346 2014-08-04 21:30:00,20247 2014-08-04 22:00:00,19945 2014-08-04 22:30:00,17601 2014-08-04 23:00:00,15750 2014-08-04 23:30:00,12897 2014-08-05 00:00:00,10385 2014-08-05 00:30:00,8125 2014-08-05 01:00:00,6294 2014-08-05 01:30:00,4485 2014-08-05 02:00:00,3669 2014-08-05 02:30:00,3097 2014-08-05 03:00:00,2484 2014-08-05 03:30:00,2011 2014-08-05 04:00:00,2175 2014-08-05 04:30:00,2108 2014-08-05 05:00:00,2252 2014-08-05 05:30:00,4131 2014-08-05 06:00:00,6599 2014-08-05 06:30:00,11040 2014-08-05 07:00:00,13290 2014-08-05 07:30:00,16754 2014-08-05 08:00:00,18504 2014-08-05 08:30:00,19897 2014-08-05 09:00:00,19208 2014-08-05 09:30:00,18253 2014-08-05 10:00:00,16976 2014-08-05 10:30:00,16888 2014-08-05 11:00:00,16080 2014-08-05 11:30:00,17328 2014-08-05 12:00:00,17901 2014-08-05 12:30:00,18121 2014-08-05 13:00:00,17478 2014-08-05 13:30:00,18616 2014-08-05 14:00:00,18576 2014-08-05 14:30:00,18465 2014-08-05 15:00:00,17373 2014-08-05 15:30:00,16457 2014-08-05 16:00:00,14626 2014-08-05 16:30:00,13466 2014-08-05 17:00:00,16213 2014-08-05 17:30:00,18715 2014-08-05 18:00:00,21356 2014-08-05 18:30:00,22899 2014-08-05 19:00:00,23782 2014-08-05 19:30:00,22778 2014-08-05 20:00:00,22401 2014-08-05 20:30:00,22986 2014-08-05 21:00:00,23340 2014-08-05 21:30:00,24046 2014-08-05 22:00:00,22726 2014-08-05 22:30:00,20819 2014-08-05 23:00:00,19149 2014-08-05 23:30:00,16406 2014-08-06 00:00:00,13399 2014-08-06 00:30:00,10273 2014-08-06 01:00:00,7723 2014-08-06 01:30:00,5860 2014-08-06 02:00:00,4664 2014-08-06 02:30:00,3875 2014-08-06 03:00:00,3057 2014-08-06 03:30:00,2675 2014-08-06 04:00:00,2803 2014-08-06 04:30:00,2364 2014-08-06 05:00:00,2602 2014-08-06 05:30:00,4488 2014-08-06 06:00:00,6944 2014-08-06 06:30:00,11761 2014-08-06 07:00:00,14631 2014-08-06 07:30:00,17455 2014-08-06 08:00:00,19107 2014-08-06 08:30:00,19737 2014-08-06 09:00:00,18707 2014-08-06 09:30:00,18466 2014-08-06 10:00:00,16630 2014-08-06 10:30:00,17291 2014-08-06 11:00:00,15977 2014-08-06 11:30:00,17643 2014-08-06 12:00:00,17959 2014-08-06 12:30:00,17652 2014-08-06 13:00:00,17197 2014-08-06 13:30:00,17949 2014-08-06 14:00:00,17918 2014-08-06 14:30:00,17534 2014-08-06 15:00:00,17350 2014-08-06 15:30:00,16327 2014-08-06 16:00:00,14582 2014-08-06 16:30:00,13374 2014-08-06 17:00:00,16090 2014-08-06 17:30:00,18989 2014-08-06 18:00:00,21429 2014-08-06 18:30:00,23892 2014-08-06 19:00:00,24481 2014-08-06 19:30:00,24197 2014-08-06 20:00:00,23556 2014-08-06 20:30:00,23555 2014-08-06 21:00:00,24355 2014-08-06 21:30:00,24699 2014-08-06 22:00:00,23955 2014-08-06 22:30:00,22754 2014-08-06 23:00:00,21450 2014-08-06 23:30:00,18427 2014-08-07 00:00:00,15411 2014-08-07 00:30:00,11851 2014-08-07 01:00:00,9317 2014-08-07 01:30:00,6973 2014-08-07 02:00:00,5807 2014-08-07 02:30:00,4812 2014-08-07 03:00:00,3738 2014-08-07 03:30:00,3108 2014-08-07 04:00:00,3199 2014-08-07 04:30:00,2642 2014-08-07 05:00:00,2704 2014-08-07 05:30:00,4812 2014-08-07 06:00:00,6873 2014-08-07 06:30:00,11765 2014-08-07 07:00:00,13641 2014-08-07 07:30:00,17052 2014-08-07 08:00:00,18252 2014-08-07 08:30:00,19400 2014-08-07 09:00:00,18455 2014-08-07 09:30:00,18277 2014-08-07 10:00:00,16719 2014-08-07 10:30:00,16764 2014-08-07 11:00:00,16636 2014-08-07 11:30:00,18205 2014-08-07 12:00:00,18034 2014-08-07 12:30:00,17700 2014-08-07 13:00:00,16970 2014-08-07 13:30:00,17983 2014-08-07 14:00:00,18230 2014-08-07 14:30:00,18073 2014-08-07 15:00:00,17471 2014-08-07 15:30:00,15872 2014-08-07 16:00:00,13784 2014-08-07 16:30:00,13341 2014-08-07 17:00:00,15857 2014-08-07 17:30:00,18396 2014-08-07 18:00:00,21500 2014-08-07 18:30:00,23368 2014-08-07 19:00:00,24977 2014-08-07 19:30:00,24747 2014-08-07 20:00:00,23895 2014-08-07 20:30:00,24153 2014-08-07 21:00:00,24778 2014-08-07 21:30:00,24533 2014-08-07 22:00:00,24478 2014-08-07 22:30:00,24253 2014-08-07 23:00:00,23299 2014-08-07 23:30:00,22155 2014-08-08 00:00:00,19329 2014-08-08 00:30:00,15933 2014-08-08 01:00:00,13410 2014-08-08 01:30:00,10614 2014-08-08 02:00:00,8934 2014-08-08 02:30:00,7079 2014-08-08 03:00:00,5803 2014-08-08 03:30:00,4992 2014-08-08 04:00:00,4555 2014-08-08 04:30:00,3601 2014-08-08 05:00:00,3643 2014-08-08 05:30:00,4924 2014-08-08 06:00:00,6649 2014-08-08 06:30:00,10748 2014-08-08 07:00:00,12731 2014-08-08 07:30:00,15178 2014-08-08 08:00:00,16731 2014-08-08 08:30:00,18521 2014-08-08 09:00:00,17924 2014-08-08 09:30:00,17129 2014-08-08 10:00:00,15820 2014-08-08 10:30:00,16405 2014-08-08 11:00:00,15710 2014-08-08 11:30:00,16406 2014-08-08 12:00:00,17040 2014-08-08 12:30:00,16998 2014-08-08 13:00:00,16524 2014-08-08 13:30:00,17157 2014-08-08 14:00:00,17341 2014-08-08 14:30:00,17716 2014-08-08 15:00:00,17135 2014-08-08 15:30:00,15591 2014-08-08 16:00:00,13942 2014-08-08 16:30:00,13215 2014-08-08 17:00:00,16320 2014-08-08 17:30:00,19539 2014-08-08 18:00:00,21553 2014-08-08 18:30:00,23100 2014-08-08 19:00:00,24705 2014-08-08 19:30:00,23913 2014-08-08 20:00:00,22283 2014-08-08 20:30:00,22808 2014-08-08 21:00:00,22239 2014-08-08 21:30:00,21989 2014-08-08 22:00:00,22689 2014-08-08 22:30:00,23756 2014-08-08 23:00:00,24182 2014-08-08 23:30:00,24184 2014-08-09 00:00:00,23849 2014-08-09 00:30:00,22495 2014-08-09 01:00:00,20367 2014-08-09 01:30:00,18368 2014-08-09 02:00:00,17499 2014-08-09 02:30:00,15607 2014-08-09 03:00:00,13502 2014-08-09 03:30:00,11670 2014-08-09 04:00:00,9956 2014-08-09 04:30:00,5950 2014-08-09 05:00:00,4023 2014-08-09 05:30:00,3499 2014-08-09 06:00:00,3663 2014-08-09 06:30:00,4608 2014-08-09 07:00:00,5226 2014-08-09 07:30:00,6154 2014-08-09 08:00:00,7082 2014-08-09 08:30:00,8917 2014-08-09 09:00:00,9965 2014-08-09 09:30:00,12488 2014-08-09 10:00:00,12845 2014-08-09 10:30:00,14960 2014-08-09 11:00:00,15195 2014-08-09 11:30:00,16331 2014-08-09 12:00:00,16385 2014-08-09 12:30:00,16704 2014-08-09 13:00:00,17450 2014-08-09 13:30:00,17458 2014-08-09 14:00:00,16849 2014-08-09 14:30:00,16880 2014-08-09 15:00:00,16951 2014-08-09 15:30:00,16926 2014-08-09 16:00:00,16376 2014-08-09 16:30:00,16454 2014-08-09 17:00:00,17768 2014-08-09 17:30:00,19335 2014-08-09 18:00:00,20035 2014-08-09 18:30:00,21023 2014-08-09 19:00:00,21977 2014-08-09 19:30:00,20987 2014-08-09 20:00:00,19159 2014-08-09 20:30:00,19801 2014-08-09 21:00:00,20361 2014-08-09 21:30:00,20651 2014-08-09 22:00:00,20833 2014-08-09 22:30:00,22467 2014-08-09 23:00:00,23285 2014-08-09 23:30:00,23652 2014-08-10 00:00:00,23701 2014-08-10 00:30:00,21532 2014-08-10 01:00:00,20557 2014-08-10 01:30:00,18415 2014-08-10 02:00:00,17813 2014-08-10 02:30:00,16223 2014-08-10 03:00:00,13777 2014-08-10 03:30:00,11818 2014-08-10 04:00:00,10499 2014-08-10 04:30:00,6180 2014-08-10 05:00:00,4096 2014-08-10 05:30:00,3476 2014-08-10 06:00:00,3259 2014-08-10 06:30:00,3468 2014-08-10 07:00:00,3690 2014-08-10 07:30:00,5047 2014-08-10 08:00:00,5503 2014-08-10 08:30:00,6667 2014-08-10 09:00:00,8014 2014-08-10 09:30:00,10532 2014-08-10 10:00:00,11486 2014-08-10 10:30:00,13733 2014-08-10 11:00:00,14525 2014-08-10 11:30:00,15314 2014-08-10 12:00:00,16013 2014-08-10 12:30:00,16268 2014-08-10 13:00:00,16610 2014-08-10 13:30:00,16496 2014-08-10 14:00:00,16885 2014-08-10 14:30:00,16396 2014-08-10 15:00:00,15796 2014-08-10 15:30:00,15545 2014-08-10 16:00:00,15642 2014-08-10 16:30:00,15531 2014-08-10 17:00:00,16410 2014-08-10 17:30:00,17684 2014-08-10 18:00:00,17992 2014-08-10 18:30:00,18285 2014-08-10 19:00:00,17697 2014-08-10 19:30:00,16452 2014-08-10 20:00:00,16195 2014-08-10 20:30:00,16545 2014-08-10 21:00:00,15989 2014-08-10 21:30:00,15763 2014-08-10 22:00:00,14767 2014-08-10 22:30:00,14157 2014-08-10 23:00:00,12939 2014-08-10 23:30:00,11801 2014-08-11 00:00:00,9595 2014-08-11 00:30:00,7267 2014-08-11 01:00:00,5616 2014-08-11 01:30:00,4253 2014-08-11 02:00:00,3261 2014-08-11 02:30:00,2770 2014-08-11 03:00:00,2240 2014-08-11 03:30:00,2084 2014-08-11 04:00:00,2407 2014-08-11 04:30:00,2262 2014-08-11 05:00:00,2728 2014-08-11 05:30:00,4273 2014-08-11 06:00:00,6194 2014-08-11 06:30:00,10158 2014-08-11 07:00:00,12697 2014-08-11 07:30:00,14281 2014-08-11 08:00:00,16009 2014-08-11 08:30:00,17659 2014-08-11 09:00:00,17250 2014-08-11 09:30:00,16687 2014-08-11 10:00:00,14465 2014-08-11 10:30:00,14373 2014-08-11 11:00:00,14599 2014-08-11 11:30:00,15212 2014-08-11 12:00:00,16026 2014-08-11 12:30:00,15526 2014-08-11 13:00:00,15672 2014-08-11 13:30:00,16419 2014-08-11 14:00:00,16083 2014-08-11 14:30:00,16352 2014-08-11 15:00:00,16535 2014-08-11 15:30:00,16248 2014-08-11 16:00:00,14959 2014-08-11 16:30:00,14201 2014-08-11 17:00:00,16142 2014-08-11 17:30:00,18163 2014-08-11 18:00:00,20715 2014-08-11 18:30:00,21256 2014-08-11 19:00:00,21528 2014-08-11 19:30:00,20720 2014-08-11 20:00:00,20604 2014-08-11 20:30:00,19786 2014-08-11 21:00:00,19471 2014-08-11 21:30:00,19116 2014-08-11 22:00:00,18358 2014-08-11 22:30:00,16440 2014-08-11 23:00:00,14821 2014-08-11 23:30:00,12022 2014-08-12 00:00:00,9701 2014-08-12 00:30:00,7757 2014-08-12 01:00:00,6003 2014-08-12 01:30:00,4648 2014-08-12 02:00:00,3805 2014-08-12 02:30:00,3093 2014-08-12 03:00:00,2487 2014-08-12 03:30:00,2164 2014-08-12 04:00:00,2288 2014-08-12 04:30:00,2083 2014-08-12 05:00:00,2452 2014-08-12 05:30:00,4282 2014-08-12 06:00:00,6142 2014-08-12 06:30:00,10744 2014-08-12 07:00:00,13034 2014-08-12 07:30:00,15724 2014-08-12 08:00:00,18102 2014-08-12 08:30:00,19748 2014-08-12 09:00:00,18510 2014-08-12 09:30:00,17502 2014-08-12 10:00:00,15832 2014-08-12 10:30:00,15940 2014-08-12 11:00:00,15064 2014-08-12 11:30:00,16927 2014-08-12 12:00:00,16871 2014-08-12 12:30:00,17325 2014-08-12 13:00:00,16350 2014-08-12 13:30:00,17244 2014-08-12 14:00:00,18778 2014-08-12 14:30:00,19036 2014-08-12 15:00:00,18549 2014-08-12 15:30:00,16263 2014-08-12 16:00:00,13781 2014-08-12 16:30:00,13197 2014-08-12 17:00:00,14909 2014-08-12 17:30:00,18695 2014-08-12 18:00:00,21494 2014-08-12 18:30:00,23426 2014-08-12 19:00:00,25057 2014-08-12 19:30:00,26062 2014-08-12 20:00:00,20944 2014-08-12 20:30:00,20583 2014-08-12 21:00:00,22343 2014-08-12 21:30:00,22704 2014-08-12 22:00:00,20090 2014-08-12 22:30:00,21338 2014-08-12 23:00:00,18853 2014-08-12 23:30:00,14548 2014-08-13 00:00:00,12933 2014-08-13 00:30:00,11301 2014-08-13 01:00:00,8095 2014-08-13 01:30:00,6266 2014-08-13 02:00:00,4752 2014-08-13 02:30:00,3446 2014-08-13 03:00:00,2793 2014-08-13 03:30:00,2333 2014-08-13 04:00:00,2468 2014-08-13 04:30:00,2059 2014-08-13 05:00:00,2411 2014-08-13 05:30:00,4204 2014-08-13 06:00:00,6516 2014-08-13 06:30:00,11706 2014-08-13 07:00:00,14894 2014-08-13 07:30:00,17894 2014-08-13 08:00:00,18081 2014-08-13 08:30:00,19597 2014-08-13 09:00:00,19047 2014-08-13 09:30:00,19060 2014-08-13 10:00:00,17041 2014-08-13 10:30:00,16354 2014-08-13 11:00:00,15259 2014-08-13 11:30:00,16470 2014-08-13 12:00:00,17146 2014-08-13 12:30:00,17220 2014-08-13 13:00:00,16932 2014-08-13 13:30:00,17515 2014-08-13 14:00:00,17285 2014-08-13 14:30:00,17467 2014-08-13 15:00:00,16869 2014-08-13 15:30:00,16383 2014-08-13 16:00:00,14727 2014-08-13 16:30:00,14059 2014-08-13 17:00:00,16707 2014-08-13 17:30:00,20486 2014-08-13 18:00:00,22207 2014-08-13 18:30:00,23183 2014-08-13 19:00:00,24873 2014-08-13 19:30:00,24028 2014-08-13 20:00:00,22822 2014-08-13 20:30:00,22831 2014-08-13 21:00:00,23148 2014-08-13 21:30:00,23005 2014-08-13 22:00:00,23506 2014-08-13 22:30:00,22493 2014-08-13 23:00:00,20703 2014-08-13 23:30:00,18013 2014-08-14 00:00:00,14505 2014-08-14 00:30:00,11389 2014-08-14 01:00:00,8924 2014-08-14 01:30:00,7135 2014-08-14 02:00:00,5649 2014-08-14 02:30:00,4544 2014-08-14 03:00:00,3542 2014-08-14 03:30:00,3086 2014-08-14 04:00:00,3091 2014-08-14 04:30:00,2590 2014-08-14 05:00:00,2706 2014-08-14 05:30:00,4336 2014-08-14 06:00:00,6237 2014-08-14 06:30:00,10724 2014-08-14 07:00:00,13183 2014-08-14 07:30:00,15723 2014-08-14 08:00:00,17752 2014-08-14 08:30:00,19645 2014-08-14 09:00:00,18448 2014-08-14 09:30:00,17796 2014-08-14 10:00:00,16361 2014-08-14 10:30:00,16636 2014-08-14 11:00:00,15606 2014-08-14 11:30:00,17003 2014-08-14 12:00:00,17538 2014-08-14 12:30:00,16979 2014-08-14 13:00:00,16844 2014-08-14 13:30:00,17372 2014-08-14 14:00:00,17667 2014-08-14 14:30:00,17859 2014-08-14 15:00:00,17357 2014-08-14 15:30:00,16100 2014-08-14 16:00:00,14347 2014-08-14 16:30:00,13630 2014-08-14 17:00:00,16197 2014-08-14 17:30:00,18210 2014-08-14 18:00:00,21282 2014-08-14 18:30:00,22623 2014-08-14 19:00:00,24035 2014-08-14 19:30:00,24056 2014-08-14 20:00:00,23987 2014-08-14 20:30:00,24289 2014-08-14 21:00:00,24134 2014-08-14 21:30:00,24141 2014-08-14 22:00:00,24661 2014-08-14 22:30:00,24114 2014-08-14 23:00:00,23611 2014-08-14 23:30:00,21287 2014-08-15 00:00:00,19491 2014-08-15 00:30:00,16128 2014-08-15 01:00:00,13044 2014-08-15 01:30:00,9984 2014-08-15 02:00:00,8526 2014-08-15 02:30:00,7009 2014-08-15 03:00:00,5525 2014-08-15 03:30:00,4688 2014-08-15 04:00:00,4665 2014-08-15 04:30:00,3542 2014-08-15 05:00:00,3163 2014-08-15 05:30:00,4547 2014-08-15 06:00:00,6346 2014-08-15 06:30:00,10699 2014-08-15 07:00:00,12050 2014-08-15 07:30:00,14555 2014-08-15 08:00:00,16322 2014-08-15 08:30:00,18762 2014-08-15 09:00:00,18321 2014-08-15 09:30:00,17235 2014-08-15 10:00:00,15496 2014-08-15 10:30:00,15859 2014-08-15 11:00:00,15559 2014-08-15 11:30:00,16873 2014-08-15 12:00:00,17350 2014-08-15 12:30:00,16611 2014-08-15 13:00:00,16543 2014-08-15 13:30:00,16753 2014-08-15 14:00:00,17552 2014-08-15 14:30:00,17361 2014-08-15 15:00:00,16508 2014-08-15 15:30:00,15776 2014-08-15 16:00:00,14232 2014-08-15 16:30:00,13784 2014-08-15 17:00:00,16867 2014-08-15 17:30:00,19906 2014-08-15 18:00:00,21668 2014-08-15 18:30:00,23098 2014-08-15 19:00:00,24319 2014-08-15 19:30:00,23800 2014-08-15 20:00:00,22649 2014-08-15 20:30:00,23190 2014-08-15 21:00:00,22209 2014-08-15 21:30:00,22105 2014-08-15 22:00:00,23041 2014-08-15 22:30:00,23974 2014-08-15 23:00:00,24057 2014-08-15 23:30:00,23997 2014-08-16 00:00:00,23174 2014-08-16 00:30:00,21534 2014-08-16 01:00:00,20240 2014-08-16 01:30:00,18434 2014-08-16 02:00:00,17382 2014-08-16 02:30:00,14870 2014-08-16 03:00:00,12921 2014-08-16 03:30:00,11258 2014-08-16 04:00:00,9869 2014-08-16 04:30:00,6061 2014-08-16 05:00:00,4150 2014-08-16 05:30:00,3688 2014-08-16 06:00:00,3811 2014-08-16 06:30:00,4938 2014-08-16 07:00:00,5248 2014-08-16 07:30:00,6972 2014-08-16 08:00:00,7885 2014-08-16 08:30:00,9526 2014-08-16 09:00:00,10750 2014-08-16 09:30:00,12899 2014-08-16 10:00:00,12950 2014-08-16 10:30:00,14145 2014-08-16 11:00:00,14724 2014-08-16 11:30:00,15667 2014-08-16 12:00:00,16016 2014-08-16 12:30:00,16245 2014-08-16 13:00:00,17156 2014-08-16 13:30:00,17194 2014-08-16 14:00:00,16993 2014-08-16 14:30:00,17286 2014-08-16 15:00:00,17109 2014-08-16 15:30:00,17115 2014-08-16 16:00:00,16437 2014-08-16 16:30:00,15986 2014-08-16 17:00:00,17735 2014-08-16 17:30:00,19247 2014-08-16 18:00:00,20555 2014-08-16 18:30:00,21424 2014-08-16 19:00:00,22252 2014-08-16 19:30:00,21379 2014-08-16 20:00:00,20043 2014-08-16 20:30:00,19941 2014-08-16 21:00:00,19947 2014-08-16 21:30:00,20601 2014-08-16 22:00:00,21109 2014-08-16 22:30:00,22185 2014-08-16 23:00:00,22255 2014-08-16 23:30:00,23286 2014-08-17 00:00:00,23263 2014-08-17 00:30:00,22356 2014-08-17 01:00:00,20247 2014-08-17 01:30:00,19261 2014-08-17 02:00:00,18335 2014-08-17 02:30:00,15881 2014-08-17 03:00:00,14076 2014-08-17 03:30:00,12215 2014-08-17 04:00:00,10492 2014-08-17 04:30:00,6297 2014-08-17 05:00:00,4328 2014-08-17 05:30:00,3426 2014-08-17 06:00:00,3367 2014-08-17 06:30:00,3930 2014-08-17 07:00:00,3834 2014-08-17 07:30:00,5166 2014-08-17 08:00:00,6704 2014-08-17 08:30:00,8252 2014-08-17 09:00:00,8872 2014-08-17 09:30:00,10157 2014-08-17 10:00:00,11490 2014-08-17 10:30:00,13701 2014-08-17 11:00:00,14623 2014-08-17 11:30:00,15373 2014-08-17 12:00:00,15798 2014-08-17 12:30:00,16478 2014-08-17 13:00:00,16986 2014-08-17 13:30:00,16375 2014-08-17 14:00:00,17545 2014-08-17 14:30:00,17532 2014-08-17 15:00:00,16751 2014-08-17 15:30:00,16425 2014-08-17 16:00:00,16231 2014-08-17 16:30:00,16257 2014-08-17 17:00:00,16875 2014-08-17 17:30:00,18041 2014-08-17 18:00:00,18055 2014-08-17 18:30:00,18276 2014-08-17 19:00:00,18030 2014-08-17 19:30:00,17081 2014-08-17 20:00:00,16006 2014-08-17 20:30:00,16544 2014-08-17 21:00:00,16394 2014-08-17 21:30:00,16467 2014-08-17 22:00:00,15480 2014-08-17 22:30:00,14150 2014-08-17 23:00:00,12599 2014-08-17 23:30:00,11942 2014-08-18 00:00:00,9875 2014-08-18 00:30:00,7581 2014-08-18 01:00:00,5815 2014-08-18 01:30:00,4164 2014-08-18 02:00:00,3757 2014-08-18 02:30:00,2863 2014-08-18 03:00:00,2372 2014-08-18 03:30:00,1951 2014-08-18 04:00:00,2353 2014-08-18 04:30:00,2332 2014-08-18 05:00:00,2702 2014-08-18 05:30:00,4271 2014-08-18 06:00:00,6107 2014-08-18 06:30:00,10069 2014-08-18 07:00:00,11882 2014-08-18 07:30:00,14095 2014-08-18 08:00:00,15597 2014-08-18 08:30:00,18046 2014-08-18 09:00:00,17168 2014-08-18 09:30:00,16333 2014-08-18 10:00:00,14794 2014-08-18 10:30:00,14653 2014-08-18 11:00:00,14058 2014-08-18 11:30:00,15162 2014-08-18 12:00:00,15013 2014-08-18 12:30:00,15376 2014-08-18 13:00:00,14922 2014-08-18 13:30:00,16122 2014-08-18 14:00:00,16229 2014-08-18 14:30:00,16481 2014-08-18 15:00:00,16424 2014-08-18 15:30:00,15719 2014-08-18 16:00:00,15087 2014-08-18 16:30:00,14465 2014-08-18 17:00:00,16588 2014-08-18 17:30:00,17923 2014-08-18 18:00:00,20054 2014-08-18 18:30:00,21402 2014-08-18 19:00:00,21523 2014-08-18 19:30:00,20447 2014-08-18 20:00:00,20431 2014-08-18 20:30:00,19708 2014-08-18 21:00:00,19821 2014-08-18 21:30:00,19291 2014-08-18 22:00:00,18093 2014-08-18 22:30:00,16177 2014-08-18 23:00:00,14282 2014-08-18 23:30:00,11852 2014-08-19 00:00:00,9601 2014-08-19 00:30:00,7532 2014-08-19 01:00:00,5866 2014-08-19 01:30:00,4515 2014-08-19 02:00:00,3787 2014-08-19 02:30:00,2947 2014-08-19 03:00:00,2237 2014-08-19 03:30:00,2022 2014-08-19 04:00:00,2313 2014-08-19 04:30:00,1932 2014-08-19 05:00:00,2200 2014-08-19 05:30:00,4019 2014-08-19 06:00:00,5928 2014-08-19 06:30:00,9987 2014-08-19 07:00:00,12094 2014-08-19 07:30:00,14716 2014-08-19 08:00:00,16670 2014-08-19 08:30:00,18950 2014-08-19 09:00:00,17964 2014-08-19 09:30:00,17783 2014-08-19 10:00:00,15966 2014-08-19 10:30:00,15946 2014-08-19 11:00:00,15205 2014-08-19 11:30:00,16175 2014-08-19 12:00:00,16790 2014-08-19 12:30:00,17284 2014-08-19 13:00:00,16153 2014-08-19 13:30:00,17673 2014-08-19 14:00:00,18157 2014-08-19 14:30:00,17858 2014-08-19 15:00:00,17087 2014-08-19 15:30:00,16385 2014-08-19 16:00:00,15063 2014-08-19 16:30:00,13909 2014-08-19 17:00:00,16462 2014-08-19 17:30:00,18855 2014-08-19 18:00:00,21606 2014-08-19 18:30:00,22910 2014-08-19 19:00:00,23691 2014-08-19 19:30:00,22752 2014-08-19 20:00:00,22414 2014-08-19 20:30:00,21896 2014-08-19 21:00:00,21887 2014-08-19 21:30:00,21845 2014-08-19 22:00:00,21436 2014-08-19 22:30:00,19787 2014-08-19 23:00:00,18369 2014-08-19 23:30:00,15132 2014-08-20 00:00:00,12168 2014-08-20 00:30:00,9288 2014-08-20 01:00:00,7465 2014-08-20 01:30:00,5656 2014-08-20 02:00:00,4693 2014-08-20 02:30:00,3694 2014-08-20 03:00:00,3027 2014-08-20 03:30:00,2587 2014-08-20 04:00:00,2733 2014-08-20 04:30:00,2216 2014-08-20 05:00:00,2289 2014-08-20 05:30:00,3937 2014-08-20 06:00:00,5718 2014-08-20 06:30:00,10053 2014-08-20 07:00:00,12154 2014-08-20 07:30:00,15289 2014-08-20 08:00:00,17424 2014-08-20 08:30:00,19403 2014-08-20 09:00:00,18488 2014-08-20 09:30:00,17881 2014-08-20 10:00:00,16397 2014-08-20 10:30:00,16319 2014-08-20 11:00:00,15923 2014-08-20 11:30:00,17200 2014-08-20 12:00:00,17140 2014-08-20 12:30:00,17422 2014-08-20 13:00:00,17393 2014-08-20 13:30:00,17612 2014-08-20 14:00:00,17475 2014-08-20 14:30:00,17685 2014-08-20 15:00:00,16765 2014-08-20 15:30:00,15701 2014-08-20 16:00:00,14276 2014-08-20 16:30:00,13715 2014-08-20 17:00:00,15577 2014-08-20 17:30:00,18831 2014-08-20 18:00:00,21971 2014-08-20 18:30:00,23814 2014-08-20 19:00:00,24147 2014-08-20 19:30:00,23300 2014-08-20 20:00:00,23237 2014-08-20 20:30:00,23018 2014-08-20 21:00:00,22814 2014-08-20 21:30:00,22716 2014-08-20 22:00:00,22838 2014-08-20 22:30:00,21546 2014-08-20 23:00:00,19205 2014-08-20 23:30:00,17041 2014-08-21 00:00:00,14569 2014-08-21 00:30:00,11396 2014-08-21 01:00:00,8719 2014-08-21 01:30:00,6717 2014-08-21 02:00:00,5410 2014-08-21 02:30:00,4458 2014-08-21 03:00:00,3703 2014-08-21 03:30:00,3166 2014-08-21 04:00:00,3256 2014-08-21 04:30:00,2805 2014-08-21 05:00:00,3067 2014-08-21 05:30:00,4424 2014-08-21 06:00:00,6076 2014-08-21 06:30:00,10251 2014-08-21 07:00:00,12400 2014-08-21 07:30:00,15229 2014-08-21 08:00:00,17252 2014-08-21 08:30:00,19332 2014-08-21 09:00:00,18249 2014-08-21 09:30:00,18059 2014-08-21 10:00:00,15889 2014-08-21 10:30:00,16234 2014-08-21 11:00:00,15730 2014-08-21 11:30:00,16578 2014-08-21 12:00:00,17363 2014-08-21 12:30:00,16708 2014-08-21 13:00:00,16809 2014-08-21 13:30:00,17193 2014-08-21 14:00:00,18105 2014-08-21 14:30:00,19035 2014-08-21 15:00:00,17230 2014-08-21 15:30:00,15928 2014-08-21 16:00:00,14180 2014-08-21 16:30:00,13252 2014-08-21 17:00:00,15256 2014-08-21 17:30:00,17773 2014-08-21 18:00:00,21104 2014-08-21 18:30:00,23557 2014-08-21 19:00:00,24797 2014-08-21 19:30:00,24794 2014-08-21 20:00:00,24154 2014-08-21 20:30:00,24501 2014-08-21 21:00:00,24042 2014-08-21 21:30:00,24125 2014-08-21 22:00:00,23970 2014-08-21 22:30:00,25949 2014-08-21 23:00:00,25094 2014-08-21 23:30:00,23295 2014-08-22 00:00:00,20552 2014-08-22 00:30:00,16266 2014-08-22 01:00:00,13365 2014-08-22 01:30:00,10287 2014-08-22 02:00:00,7901 2014-08-22 02:30:00,6235 2014-08-22 03:00:00,4869 2014-08-22 03:30:00,3995 2014-08-22 04:00:00,3734 2014-08-22 04:30:00,3190 2014-08-22 05:00:00,2878 2014-08-22 05:30:00,4020 2014-08-22 06:00:00,6062 2014-08-22 06:30:00,9502 2014-08-22 07:00:00,11446 2014-08-22 07:30:00,13665 2014-08-22 08:00:00,15257 2014-08-22 08:30:00,17391 2014-08-22 09:00:00,16922 2014-08-22 09:30:00,16227 2014-08-22 10:00:00,15185 2014-08-22 10:30:00,15390 2014-08-22 11:00:00,14725 2014-08-22 11:30:00,15415 2014-08-22 12:00:00,15729 2014-08-22 12:30:00,16131 2014-08-22 13:00:00,16058 2014-08-22 13:30:00,16015 2014-08-22 14:00:00,16749 2014-08-22 14:30:00,16857 2014-08-22 15:00:00,16588 2014-08-22 15:30:00,15430 2014-08-22 16:00:00,14186 2014-08-22 16:30:00,13756 2014-08-22 17:00:00,15596 2014-08-22 17:30:00,17743 2014-08-22 18:00:00,19439 2014-08-22 18:30:00,21047 2014-08-22 19:00:00,22647 2014-08-22 19:30:00,21734 2014-08-22 20:00:00,21394 2014-08-22 20:30:00,20208 2014-08-22 21:00:00,20329 2014-08-22 21:30:00,20221 2014-08-22 22:00:00,20945 2014-08-22 22:30:00,22327 2014-08-22 23:00:00,22765 2014-08-22 23:30:00,22852 2014-08-23 00:00:00,22726 2014-08-23 00:30:00,21079 2014-08-23 01:00:00,19166 2014-08-23 01:30:00,17719 2014-08-23 02:00:00,16471 2014-08-23 02:30:00,14158 2014-08-23 03:00:00,12730 2014-08-23 03:30:00,10984 2014-08-23 04:00:00,9409 2014-08-23 04:30:00,5667 2014-08-23 05:00:00,3879 2014-08-23 05:30:00,3398 2014-08-23 06:00:00,3683 2014-08-23 06:30:00,4437 2014-08-23 07:00:00,4732 2014-08-23 07:30:00,6130 2014-08-23 08:00:00,6492 2014-08-23 08:30:00,8397 2014-08-23 09:00:00,9673 2014-08-23 09:30:00,11493 2014-08-23 10:00:00,11723 2014-08-23 10:30:00,14060 2014-08-23 11:00:00,14204 2014-08-23 11:30:00,15542 2014-08-23 12:00:00,15446 2014-08-23 12:30:00,15993 2014-08-23 13:00:00,16206 2014-08-23 13:30:00,16531 2014-08-23 14:00:00,15717 2014-08-23 14:30:00,15964 2014-08-23 15:00:00,15868 2014-08-23 15:30:00,16012 2014-08-23 16:00:00,16200 2014-08-23 16:30:00,15778 2014-08-23 17:00:00,16268 2014-08-23 17:30:00,18160 2014-08-23 18:00:00,19155 2014-08-23 18:30:00,20365 2014-08-23 19:00:00,21278 2014-08-23 19:30:00,20466 2014-08-23 20:00:00,20057 2014-08-23 20:30:00,23457 2014-08-23 21:00:00,18798 2014-08-23 21:30:00,19387 2014-08-23 22:00:00,19998 2014-08-23 22:30:00,21426 2014-08-23 23:00:00,22449 2014-08-23 23:30:00,22640 2014-08-24 00:00:00,22666 2014-08-24 00:30:00,21430 2014-08-24 01:00:00,20015 2014-08-24 01:30:00,18791 2014-08-24 02:00:00,17683 2014-08-24 02:30:00,15830 2014-08-24 03:00:00,13862 2014-08-24 03:30:00,11961 2014-08-24 04:00:00,10153 2014-08-24 04:30:00,6051 2014-08-24 05:00:00,3848 2014-08-24 05:30:00,2948 2014-08-24 06:00:00,3143 2014-08-24 06:30:00,3505 2014-08-24 07:00:00,3812 2014-08-24 07:30:00,4939 2014-08-24 08:00:00,5442 2014-08-24 08:30:00,6630 2014-08-24 09:00:00,7744 2014-08-24 09:30:00,10198 2014-08-24 10:00:00,11041 2014-08-24 10:30:00,13200 2014-08-24 11:00:00,14107 2014-08-24 11:30:00,15069 2014-08-24 12:00:00,15638 2014-08-24 12:30:00,15464 2014-08-24 13:00:00,15901 2014-08-24 13:30:00,16001 2014-08-24 14:00:00,16492 2014-08-24 14:30:00,16166 2014-08-24 15:00:00,15531 2014-08-24 15:30:00,15655 2014-08-24 16:00:00,15040 2014-08-24 16:30:00,15083 2014-08-24 17:00:00,16229 2014-08-24 17:30:00,17409 2014-08-24 18:00:00,17288 2014-08-24 18:30:00,17242 2014-08-24 19:00:00,17129 2014-08-24 19:30:00,16103 2014-08-24 20:00:00,16485 2014-08-24 20:30:00,16190 2014-08-24 21:00:00,15500 2014-08-24 21:30:00,15128 2014-08-24 22:00:00,14489 2014-08-24 22:30:00,13947 2014-08-24 23:00:00,12525 2014-08-24 23:30:00,11899 2014-08-25 00:00:00,9192 2014-08-25 00:30:00,6886 2014-08-25 01:00:00,4888 2014-08-25 01:30:00,4138 2014-08-25 02:00:00,3366 2014-08-25 02:30:00,2698 2014-08-25 03:00:00,2290 2014-08-25 03:30:00,2009 2014-08-25 04:00:00,2265 2014-08-25 04:30:00,2213 2014-08-25 05:00:00,2450 2014-08-25 05:30:00,3829 2014-08-25 06:00:00,5933 2014-08-25 06:30:00,9356 2014-08-25 07:00:00,11482 2014-08-25 07:30:00,13178 2014-08-25 08:00:00,14803 2014-08-25 08:30:00,16826 2014-08-25 09:00:00,16649 2014-08-25 09:30:00,15422 2014-08-25 10:00:00,13996 2014-08-25 10:30:00,13682 2014-08-25 11:00:00,13297 2014-08-25 11:30:00,14284 2014-08-25 12:00:00,14435 2014-08-25 12:30:00,14612 2014-08-25 13:00:00,14814 2014-08-25 13:30:00,15398 2014-08-25 14:00:00,15511 2014-08-25 14:30:00,15828 2014-08-25 15:00:00,15396 2014-08-25 15:30:00,15109 2014-08-25 16:00:00,14787 2014-08-25 16:30:00,14532 2014-08-25 17:00:00,16387 2014-08-25 17:30:00,18242 2014-08-25 18:00:00,19715 2014-08-25 18:30:00,20288 2014-08-25 19:00:00,20761 2014-08-25 19:30:00,19466 2014-08-25 20:00:00,19670 2014-08-25 20:30:00,18802 2014-08-25 21:00:00,18709 2014-08-25 21:30:00,17186 2014-08-25 22:00:00,16500 2014-08-25 22:30:00,15616 2014-08-25 23:00:00,13902 2014-08-25 23:30:00,11077 2014-08-26 00:00:00,9618 2014-08-26 00:30:00,7193 2014-08-26 01:00:00,5665 2014-08-26 01:30:00,4149 2014-08-26 02:00:00,3502 2014-08-26 02:30:00,2634 2014-08-26 03:00:00,2100 2014-08-26 03:30:00,1985 2014-08-26 04:00:00,2053 2014-08-26 04:30:00,1841 2014-08-26 05:00:00,1909 2014-08-26 05:30:00,3547 2014-08-26 06:00:00,5829 2014-08-26 06:30:00,9599 2014-08-26 07:00:00,11323 2014-08-26 07:30:00,13923 2014-08-26 08:00:00,16029 2014-08-26 08:30:00,18308 2014-08-26 09:00:00,17153 2014-08-26 09:30:00,16723 2014-08-26 10:00:00,15360 2014-08-26 10:30:00,16066 2014-08-26 11:00:00,14643 2014-08-26 11:30:00,15960 2014-08-26 12:00:00,16351 2014-08-26 12:30:00,16173 2014-08-26 13:00:00,15659 2014-08-26 13:30:00,17346 2014-08-26 14:00:00,17145 2014-08-26 14:30:00,16896 2014-08-26 15:00:00,16746 2014-08-26 15:30:00,15797 2014-08-26 16:00:00,14202 2014-08-26 16:30:00,14083 2014-08-26 17:00:00,16074 2014-08-26 17:30:00,18329 2014-08-26 18:00:00,20961 2014-08-26 18:30:00,22545 2014-08-26 19:00:00,22067 2014-08-26 19:30:00,21416 2014-08-26 20:00:00,21484 2014-08-26 20:30:00,20731 2014-08-26 21:00:00,20969 2014-08-26 21:30:00,20820 2014-08-26 22:00:00,19650 2014-08-26 22:30:00,18240 2014-08-26 23:00:00,17133 2014-08-26 23:30:00,14907 2014-08-27 00:00:00,11703 2014-08-27 00:30:00,8521 2014-08-27 01:00:00,6962 2014-08-27 01:30:00,5451 2014-08-27 02:00:00,4439 2014-08-27 02:30:00,3436 2014-08-27 03:00:00,2741 2014-08-27 03:30:00,2311 2014-08-27 04:00:00,2532 2014-08-27 04:30:00,2066 2014-08-27 05:00:00,2111 2014-08-27 05:30:00,3623 2014-08-27 06:00:00,5719 2014-08-27 06:30:00,9376 2014-08-27 07:00:00,11971 2014-08-27 07:30:00,14673 2014-08-27 08:00:00,16545 2014-08-27 08:30:00,18678 2014-08-27 09:00:00,17655 2014-08-27 09:30:00,17485 2014-08-27 10:00:00,15834 2014-08-27 10:30:00,15703 2014-08-27 11:00:00,15816 2014-08-27 11:30:00,16870 2014-08-27 12:00:00,17123 2014-08-27 12:30:00,16841 2014-08-27 13:00:00,16700 2014-08-27 13:30:00,17722 2014-08-27 14:00:00,17849 2014-08-27 14:30:00,18221 2014-08-27 15:00:00,17208 2014-08-27 15:30:00,16318 2014-08-27 16:00:00,14910 2014-08-27 16:30:00,14145 2014-08-27 17:00:00,16330 2014-08-27 17:30:00,19328 2014-08-27 18:00:00,21226 2014-08-27 18:30:00,23109 2014-08-27 19:00:00,24206 2014-08-27 19:30:00,23297 2014-08-27 20:00:00,23493 2014-08-27 20:30:00,22794 2014-08-27 21:00:00,22502 2014-08-27 21:30:00,22337 2014-08-27 22:00:00,24446 2014-08-27 22:30:00,20929 2014-08-27 23:00:00,17937 2014-08-27 23:30:00,16036 2014-08-28 00:00:00,13547 2014-08-28 00:30:00,10363 2014-08-28 01:00:00,8553 2014-08-28 01:30:00,6457 2014-08-28 02:00:00,5248 2014-08-28 02:30:00,3879 2014-08-28 03:00:00,3173 2014-08-28 03:30:00,2653 2014-08-28 04:00:00,2858 2014-08-28 04:30:00,2244 2014-08-28 05:00:00,2312 2014-08-28 05:30:00,3859 2014-08-28 06:00:00,5772 2014-08-28 06:30:00,9391 2014-08-28 07:00:00,11375 2014-08-28 07:30:00,14319 2014-08-28 08:00:00,16103 2014-08-28 08:30:00,18835 2014-08-28 09:00:00,17891 2014-08-28 09:30:00,17000 2014-08-28 10:00:00,15534 2014-08-28 10:30:00,15916 2014-08-28 11:00:00,15153 2014-08-28 11:30:00,16440 2014-08-28 12:00:00,16424 2014-08-28 12:30:00,16093 2014-08-28 13:00:00,16178 2014-08-28 13:30:00,17050 2014-08-28 14:00:00,16795 2014-08-28 14:30:00,17547 2014-08-28 15:00:00,16769 2014-08-28 15:30:00,15701 2014-08-28 16:00:00,14067 2014-08-28 16:30:00,13534 2014-08-28 17:00:00,15939 2014-08-28 17:30:00,18560 2014-08-28 18:00:00,21029 2014-08-28 18:30:00,22181 2014-08-28 19:00:00,22860 2014-08-28 19:30:00,22742 2014-08-28 20:00:00,22569 2014-08-28 20:30:00,22184 2014-08-28 21:00:00,21926 2014-08-28 21:30:00,22510 2014-08-28 22:00:00,22350 2014-08-28 22:30:00,21756 2014-08-28 23:00:00,20994 2014-08-28 23:30:00,19084 2014-08-29 00:00:00,16702 2014-08-29 00:30:00,13985 2014-08-29 01:00:00,11632 2014-08-29 01:30:00,9900 2014-08-29 02:00:00,8443 2014-08-29 02:30:00,6546 2014-08-29 03:00:00,5270 2014-08-29 03:30:00,4521 2014-08-29 04:00:00,4369 2014-08-29 04:30:00,3409 2014-08-29 05:00:00,2967 2014-08-29 05:30:00,4444 2014-08-29 06:00:00,5712 2014-08-29 06:30:00,9008 2014-08-29 07:00:00,10312 2014-08-29 07:30:00,12809 2014-08-29 08:00:00,13491 2014-08-29 08:30:00,16417 2014-08-29 09:00:00,15906 2014-08-29 09:30:00,15249 2014-08-29 10:00:00,14367 2014-08-29 10:30:00,14667 2014-08-29 11:00:00,14738 2014-08-29 11:30:00,16134 2014-08-29 12:00:00,16343 2014-08-29 12:30:00,15908 2014-08-29 13:00:00,16700 2014-08-29 13:30:00,16712 2014-08-29 14:00:00,17394 2014-08-29 14:30:00,17680 2014-08-29 15:00:00,17495 2014-08-29 15:30:00,15984 2014-08-29 16:00:00,14946 2014-08-29 16:30:00,14572 2014-08-29 17:00:00,16880 2014-08-29 17:30:00,19398 2014-08-29 18:00:00,20797 2014-08-29 18:30:00,21449 2014-08-29 19:00:00,22077 2014-08-29 19:30:00,21483 2014-08-29 20:00:00,20415 2014-08-29 20:30:00,20436 2014-08-29 21:00:00,19315 2014-08-29 21:30:00,19328 2014-08-29 22:00:00,19660 2014-08-29 22:30:00,21469 2014-08-29 23:00:00,20853 2014-08-29 23:30:00,21452 2014-08-30 00:00:00,20564 2014-08-30 00:30:00,19267 2014-08-30 01:00:00,17439 2014-08-30 01:30:00,14848 2014-08-30 02:00:00,13900 2014-08-30 02:30:00,12731 2014-08-30 03:00:00,10776 2014-08-30 03:30:00,9550 2014-08-30 04:00:00,8605 2014-08-30 04:30:00,5547 2014-08-30 05:00:00,3605 2014-08-30 05:30:00,3238 2014-08-30 06:00:00,3520 2014-08-30 06:30:00,4315 2014-08-30 07:00:00,5116 2014-08-30 07:30:00,5918 2014-08-30 08:00:00,6383 2014-08-30 08:30:00,8259 2014-08-30 09:00:00,9430 2014-08-30 09:30:00,11656 2014-08-30 10:00:00,11833 2014-08-30 10:30:00,13393 2014-08-30 11:00:00,13778 2014-08-30 11:30:00,15204 2014-08-30 12:00:00,15367 2014-08-30 12:30:00,15775 2014-08-30 13:00:00,16045 2014-08-30 13:30:00,16499 2014-08-30 14:00:00,16113 2014-08-30 14:30:00,16651 2014-08-30 15:00:00,16507 2014-08-30 15:30:00,16868 2014-08-30 16:00:00,15594 2014-08-30 16:30:00,16037 2014-08-30 17:00:00,16973 2014-08-30 17:30:00,18390 2014-08-30 18:00:00,18681 2014-08-30 18:30:00,19196 2014-08-30 19:00:00,19744 2014-08-30 19:30:00,19564 2014-08-30 20:00:00,17522 2014-08-30 20:30:00,17731 2014-08-30 21:00:00,17364 2014-08-30 21:30:00,17483 2014-08-30 22:00:00,18037 2014-08-30 22:30:00,19559 2014-08-30 23:00:00,19421 2014-08-30 23:30:00,19857 2014-08-31 00:00:00,19205 2014-08-31 00:30:00,18139 2014-08-31 01:00:00,16686 2014-08-31 01:30:00,14841 2014-08-31 02:00:00,14018 2014-08-31 02:30:00,12187 2014-08-31 03:00:00,10536 2014-08-31 03:30:00,9591 2014-08-31 04:00:00,8665 2014-08-31 04:30:00,5317 2014-08-31 05:00:00,3597 2014-08-31 05:30:00,2783 2014-08-31 06:00:00,2587 2014-08-31 06:30:00,2914 2014-08-31 07:00:00,3167 2014-08-31 07:30:00,4212 2014-08-31 08:00:00,4502 2014-08-31 08:30:00,5730 2014-08-31 09:00:00,7102 2014-08-31 09:30:00,9054 2014-08-31 10:00:00,10152 2014-08-31 10:30:00,13059 2014-08-31 11:00:00,13923 2014-08-31 11:30:00,14755 2014-08-31 12:00:00,15186 2014-08-31 12:30:00,16404 2014-08-31 13:00:00,16652 2014-08-31 13:30:00,17446 2014-08-31 14:00:00,17493 2014-08-31 14:30:00,17264 2014-08-31 15:00:00,16546 2014-08-31 15:30:00,17090 2014-08-31 16:00:00,17297 2014-08-31 16:30:00,16546 2014-08-31 17:00:00,16474 2014-08-31 17:30:00,16959 2014-08-31 18:00:00,16567 2014-08-31 18:30:00,17590 2014-08-31 19:00:00,17053 2014-08-31 19:30:00,16561 2014-08-31 20:00:00,16870 2014-08-31 20:30:00,16514 2014-08-31 21:00:00,15871 2014-08-31 21:30:00,15529 2014-08-31 22:00:00,15049 2014-08-31 22:30:00,15675 2014-08-31 23:00:00,15673 2014-08-31 23:30:00,15524 2014-09-01 00:00:00,14618 2014-09-01 00:30:00,12908 2014-09-01 01:00:00,10842 2014-09-01 01:30:00,9248 2014-09-01 02:00:00,8588 2014-09-01 02:30:00,7631 2014-09-01 03:00:00,6519 2014-09-01 03:30:00,5657 2014-09-01 04:00:00,5214 2014-09-01 04:30:00,3827 2014-09-01 05:00:00,2939 2014-09-01 05:30:00,2872 2014-09-01 06:00:00,2994 2014-09-01 06:30:00,3708 2014-09-01 07:00:00,3547 2014-09-01 07:30:00,4761 2014-09-01 08:00:00,5038 2014-09-01 08:30:00,5875 2014-09-01 09:00:00,6910 2014-09-01 09:30:00,8800 2014-09-01 10:00:00,9782 2014-09-01 10:30:00,11506 2014-09-01 11:00:00,12291 2014-09-01 11:30:00,13600 2014-09-01 12:00:00,14040 2014-09-01 12:30:00,15063 2014-09-01 13:00:00,15073 2014-09-01 13:30:00,15834 2014-09-01 14:00:00,16567 2014-09-01 14:30:00,16955 2014-09-01 15:00:00,17408 2014-09-01 15:30:00,16857 2014-09-01 16:00:00,16002 2014-09-01 16:30:00,15826 2014-09-01 17:00:00,16961 2014-09-01 17:30:00,17779 2014-09-01 18:00:00,17578 2014-09-01 18:30:00,17777 2014-09-01 19:00:00,17764 2014-09-01 19:30:00,17130 2014-09-01 20:00:00,16641 2014-09-01 20:30:00,16884 2014-09-01 21:00:00,15068 2014-09-01 21:30:00,15557 2014-09-01 22:00:00,13766 2014-09-01 22:30:00,13377 2014-09-01 23:00:00,11025 2014-09-01 23:30:00,9707 2014-09-02 00:00:00,8043 2014-09-02 00:30:00,5630 2014-09-02 01:00:00,4347 2014-09-02 01:30:00,3606 2014-09-02 02:00:00,2588 2014-09-02 02:30:00,1969 2014-09-02 03:00:00,1876 2014-09-02 03:30:00,1431 2014-09-02 04:00:00,1752 2014-09-02 04:30:00,2044 2014-09-02 05:00:00,2447 2014-09-02 05:30:00,4617 2014-09-02 06:00:00,6988 2014-09-02 06:30:00,11616 2014-09-02 07:00:00,14774 2014-09-02 07:30:00,17823 2014-09-02 08:00:00,18623 2014-09-02 08:30:00,18814 2014-09-02 09:00:00,19221 2014-09-02 09:30:00,18627 2014-09-02 10:00:00,16650 2014-09-02 10:30:00,17378 2014-09-02 11:00:00,16414 2014-09-02 11:30:00,17230 2014-09-02 12:00:00,17557 2014-09-02 12:30:00,18262 2014-09-02 13:00:00,17698 2014-09-02 13:30:00,18863 2014-09-02 14:00:00,18234 2014-09-02 14:30:00,18514 2014-09-02 15:00:00,18364 2014-09-02 15:30:00,17952 2014-09-02 16:00:00,15781 2014-09-02 16:30:00,14487 2014-09-02 17:00:00,16062 2014-09-02 17:30:00,18952 2014-09-02 18:00:00,21395 2014-09-02 18:30:00,23040 2014-09-02 19:00:00,22890 2014-09-02 19:30:00,22306 2014-09-02 20:00:00,21704 2014-09-02 20:30:00,20543 2014-09-02 21:00:00,19896 2014-09-02 21:30:00,19857 2014-09-02 22:00:00,17841 2014-09-02 22:30:00,16192 2014-09-02 23:00:00,14116 2014-09-02 23:30:00,12865 2014-09-03 00:00:00,10465 2014-09-03 00:30:00,8215 2014-09-03 01:00:00,6481 2014-09-03 01:30:00,4265 2014-09-03 02:00:00,3434 2014-09-03 02:30:00,2726 2014-09-03 03:00:00,2358 2014-09-03 03:30:00,2019 2014-09-03 04:00:00,2137 2014-09-03 04:30:00,1903 2014-09-03 05:00:00,2252 2014-09-03 05:30:00,4206 2014-09-03 06:00:00,6545 2014-09-03 06:30:00,11780 2014-09-03 07:00:00,14707 2014-09-03 07:30:00,18624 2014-09-03 08:00:00,19178 2014-09-03 08:30:00,20265 2014-09-03 09:00:00,19277 2014-09-03 09:30:00,19042 2014-09-03 10:00:00,18108 2014-09-03 10:30:00,18275 2014-09-03 11:00:00,17300 2014-09-03 11:30:00,18631 2014-09-03 12:00:00,18582 2014-09-03 12:30:00,18037 2014-09-03 13:00:00,17899 2014-09-03 13:30:00,18984 2014-09-03 14:00:00,18491 2014-09-03 14:30:00,19072 2014-09-03 15:00:00,18693 2014-09-03 15:30:00,17268 2014-09-03 16:00:00,15918 2014-09-03 16:30:00,14478 2014-09-03 17:00:00,16540 2014-09-03 17:30:00,19765 2014-09-03 18:00:00,22526 2014-09-03 18:30:00,23454 2014-09-03 19:00:00,24380 2014-09-03 19:30:00,24477 2014-09-03 20:00:00,24234 2014-09-03 20:30:00,23319 2014-09-03 21:00:00,23387 2014-09-03 21:30:00,22963 2014-09-03 22:00:00,22006 2014-09-03 22:30:00,20301 2014-09-03 23:00:00,18259 2014-09-03 23:30:00,15608 2014-09-04 00:00:00,12990 2014-09-04 00:30:00,10273 2014-09-04 01:00:00,8434 2014-09-04 01:30:00,6378 2014-09-04 02:00:00,5549 2014-09-04 02:30:00,4131 2014-09-04 03:00:00,3241 2014-09-04 03:30:00,2410 2014-09-04 04:00:00,2804 2014-09-04 04:30:00,2320 2014-09-04 05:00:00,2431 2014-09-04 05:30:00,4222 2014-09-04 06:00:00,6633 2014-09-04 06:30:00,12006 2014-09-04 07:00:00,15589 2014-09-04 07:30:00,20359 2014-09-04 08:00:00,20593 2014-09-04 08:30:00,19590 2014-09-04 09:00:00,19637 2014-09-04 09:30:00,19026 2014-09-04 10:00:00,18629 2014-09-04 10:30:00,18568 2014-09-04 11:00:00,18041 2014-09-04 11:30:00,18695 2014-09-04 12:00:00,19692 2014-09-04 12:30:00,19173 2014-09-04 13:00:00,17824 2014-09-04 13:30:00,19684 2014-09-04 14:00:00,20139 2014-09-04 14:30:00,20320 2014-09-04 15:00:00,19468 2014-09-04 15:30:00,17391 2014-09-04 16:00:00,15218 2014-09-04 16:30:00,13649 2014-09-04 17:00:00,16052 2014-09-04 17:30:00,18987 2014-09-04 18:00:00,21967 2014-09-04 18:30:00,24107 2014-09-04 19:00:00,25260 2014-09-04 19:30:00,25638 2014-09-04 20:00:00,26045 2014-09-04 20:30:00,25045 2014-09-04 21:00:00,24846 2014-09-04 21:30:00,24703 2014-09-04 22:00:00,24863 2014-09-04 22:30:00,23610 2014-09-04 23:00:00,21637 2014-09-04 23:30:00,21643 2014-09-05 00:00:00,18962 2014-09-05 00:30:00,15475 2014-09-05 01:00:00,11955 2014-09-05 01:30:00,9339 2014-09-05 02:00:00,7967 2014-09-05 02:30:00,6372 2014-09-05 03:00:00,5132 2014-09-05 03:30:00,4357 2014-09-05 04:00:00,4305 2014-09-05 04:30:00,3195 2014-09-05 05:00:00,2878 2014-09-05 05:30:00,4762 2014-09-05 06:00:00,7294 2014-09-05 06:30:00,12886 2014-09-05 07:00:00,15820 2014-09-05 07:30:00,19874 2014-09-05 08:00:00,20367 2014-09-05 08:30:00,20091 2014-09-05 09:00:00,19600 2014-09-05 09:30:00,19283 2014-09-05 10:00:00,18413 2014-09-05 10:30:00,18745 2014-09-05 11:00:00,17998 2014-09-05 11:30:00,19325 2014-09-05 12:00:00,19004 2014-09-05 12:30:00,18450 2014-09-05 13:00:00,18029 2014-09-05 13:30:00,18057 2014-09-05 14:00:00,19315 2014-09-05 14:30:00,20057 2014-09-05 15:00:00,19211 2014-09-05 15:30:00,16903 2014-09-05 16:00:00,15288 2014-09-05 16:30:00,13729 2014-09-05 17:00:00,17003 2014-09-05 17:30:00,20142 2014-09-05 18:00:00,23177 2014-09-05 18:30:00,25036 2014-09-05 19:00:00,27337 2014-09-05 19:30:00,26812 2014-09-05 20:00:00,26592 2014-09-05 20:30:00,26243 2014-09-05 21:00:00,25919 2014-09-05 21:30:00,25898 2014-09-05 22:00:00,26603 2014-09-05 22:30:00,26899 2014-09-05 23:00:00,26900 2014-09-05 23:30:00,26763 2014-09-06 00:00:00,25721 2014-09-06 00:30:00,24590 2014-09-06 01:00:00,22118 2014-09-06 01:30:00,20378 2014-09-06 02:00:00,19093 2014-09-06 02:30:00,16717 2014-09-06 03:00:00,14043 2014-09-06 03:30:00,12077 2014-09-06 04:00:00,10212 2014-09-06 04:30:00,6328 2014-09-06 05:00:00,4440 2014-09-06 05:30:00,3603 2014-09-06 06:00:00,3781 2014-09-06 06:30:00,4846 2014-09-06 07:00:00,5444 2014-09-06 07:30:00,7701 2014-09-06 08:00:00,8375 2014-09-06 08:30:00,11334 2014-09-06 09:00:00,12747 2014-09-06 09:30:00,15930 2014-09-06 10:00:00,16567 2014-09-06 10:30:00,18716 2014-09-06 11:00:00,18722 2014-09-06 11:30:00,20103 2014-09-06 12:00:00,20287 2014-09-06 12:30:00,21127 2014-09-06 13:00:00,21259 2014-09-06 13:30:00,21946 2014-09-06 14:00:00,21655 2014-09-06 14:30:00,21830 2014-09-06 15:00:00,22886 2014-09-06 15:30:00,20736 2014-09-06 16:00:00,18209 2014-09-06 16:30:00,17090 2014-09-06 17:00:00,19270 2014-09-06 17:30:00,22270 2014-09-06 18:00:00,24264 2014-09-06 18:30:00,25210 2014-09-06 19:00:00,25976 2014-09-06 19:30:00,25765 2014-09-06 20:00:00,24487 2014-09-06 20:30:00,23499 2014-09-06 21:00:00,23210 2014-09-06 21:30:00,23487 2014-09-06 22:00:00,24515 2014-09-06 22:30:00,30313 2014-09-06 23:00:00,30373 2014-09-06 23:30:00,28464 2014-09-07 00:00:00,25818 2014-09-07 00:30:00,24635 2014-09-07 01:00:00,23410 2014-09-07 01:30:00,21481 2014-09-07 02:00:00,19800 2014-09-07 02:30:00,17674 2014-09-07 03:00:00,15215 2014-09-07 03:30:00,13501 2014-09-07 04:00:00,10896 2014-09-07 04:30:00,6766 2014-09-07 05:00:00,4261 2014-09-07 05:30:00,3415 2014-09-07 06:00:00,3220 2014-09-07 06:30:00,4160 2014-09-07 07:00:00,4345 2014-09-07 07:30:00,5963 2014-09-07 08:00:00,6887 2014-09-07 08:30:00,8834 2014-09-07 09:00:00,10042 2014-09-07 09:30:00,13188 2014-09-07 10:00:00,14600 2014-09-07 10:30:00,18209 2014-09-07 11:00:00,18446 2014-09-07 11:30:00,20350 2014-09-07 12:00:00,20838 2014-09-07 12:30:00,22183 2014-09-07 13:00:00,20582 2014-09-07 13:30:00,20506 2014-09-07 14:00:00,20109 2014-09-07 14:30:00,20198 2014-09-07 15:00:00,18873 2014-09-07 15:30:00,19041 2014-09-07 16:00:00,19295 2014-09-07 16:30:00,18868 2014-09-07 17:00:00,18851 2014-09-07 17:30:00,20518 2014-09-07 18:00:00,21710 2014-09-07 18:30:00,20895 2014-09-07 19:00:00,20761 2014-09-07 19:30:00,19916 2014-09-07 20:00:00,19740 2014-09-07 20:30:00,18975 2014-09-07 21:00:00,17866 2014-09-07 21:30:00,17750 2014-09-07 22:00:00,16820 2014-09-07 22:30:00,15292 2014-09-07 23:00:00,13219 2014-09-07 23:30:00,12246 2014-09-08 00:00:00,9733 2014-09-08 00:30:00,7542 2014-09-08 01:00:00,5518 2014-09-08 01:30:00,4348 2014-09-08 02:00:00,3828 2014-09-08 02:30:00,3083 2014-09-08 03:00:00,2583 2014-09-08 03:30:00,2328 2014-09-08 04:00:00,2523 2014-09-08 04:30:00,2579 2014-09-08 05:00:00,2901 2014-09-08 05:30:00,4963 2014-09-08 06:00:00,7013 2014-09-08 06:30:00,11830 2014-09-08 07:00:00,14665 2014-09-08 07:30:00,18099 2014-09-08 08:00:00,18601 2014-09-08 08:30:00,18329 2014-09-08 09:00:00,18506 2014-09-08 09:30:00,17983 2014-09-08 10:00:00,16869 2014-09-08 10:30:00,16771 2014-09-08 11:00:00,16010 2014-09-08 11:30:00,17370 2014-09-08 12:00:00,17526 2014-09-08 12:30:00,17910 2014-09-08 13:00:00,16565 2014-09-08 13:30:00,18380 2014-09-08 14:00:00,18294 2014-09-08 14:30:00,19585 2014-09-08 15:00:00,19323 2014-09-08 15:30:00,18113 2014-09-08 16:00:00,16472 2014-09-08 16:30:00,16007 2014-09-08 17:00:00,18299 2014-09-08 17:30:00,20385 2014-09-08 18:00:00,22906 2014-09-08 18:30:00,24153 2014-09-08 19:00:00,24545 2014-09-08 19:30:00,23635 2014-09-08 20:00:00,23773 2014-09-08 20:30:00,23212 2014-09-08 21:00:00,21918 2014-09-08 21:30:00,21096 2014-09-08 22:00:00,21563 2014-09-08 22:30:00,17989 2014-09-08 23:00:00,15442 2014-09-08 23:30:00,12815 2014-09-09 00:00:00,10436 2014-09-09 00:30:00,8092 2014-09-09 01:00:00,6061 2014-09-09 01:30:00,5058 2014-09-09 02:00:00,4073 2014-09-09 02:30:00,3310 2014-09-09 03:00:00,2623 2014-09-09 03:30:00,2364 2014-09-09 04:00:00,2333 2014-09-09 04:30:00,2287 2014-09-09 05:00:00,2444 2014-09-09 05:30:00,4427 2014-09-09 06:00:00,6661 2014-09-09 06:30:00,12136 2014-09-09 07:00:00,15910 2014-09-09 07:30:00,20003 2014-09-09 08:00:00,19956 2014-09-09 08:30:00,19897 2014-09-09 09:00:00,18719 2014-09-09 09:30:00,18485 2014-09-09 10:00:00,17235 2014-09-09 10:30:00,17705 2014-09-09 11:00:00,17089 2014-09-09 11:30:00,18334 2014-09-09 12:00:00,18564 2014-09-09 12:30:00,18599 2014-09-09 13:00:00,17715 2014-09-09 13:30:00,18692 2014-09-09 14:00:00,19276 2014-09-09 14:30:00,20557 2014-09-09 15:00:00,19505 2014-09-09 15:30:00,16820 2014-09-09 16:00:00,14005 2014-09-09 16:30:00,13683 2014-09-09 17:00:00,16918 2014-09-09 17:30:00,20051 2014-09-09 18:00:00,22624 2014-09-09 18:30:00,23987 2014-09-09 19:00:00,24069 2014-09-09 19:30:00,24933 2014-09-09 20:00:00,24928 2014-09-09 20:30:00,24390 2014-09-09 21:00:00,24199 2014-09-09 21:30:00,24277 2014-09-09 22:00:00,23154 2014-09-09 22:30:00,21090 2014-09-09 23:00:00,18854 2014-09-09 23:30:00,16194 2014-09-10 00:00:00,13226 2014-09-10 00:30:00,9866 2014-09-10 01:00:00,8085 2014-09-10 01:30:00,6177 2014-09-10 02:00:00,5324 2014-09-10 02:30:00,4177 2014-09-10 03:00:00,3464 2014-09-10 03:30:00,2855 2014-09-10 04:00:00,2850 2014-09-10 04:30:00,2361 2014-09-10 05:00:00,2675 2014-09-10 05:30:00,4589 2014-09-10 06:00:00,6868 2014-09-10 06:30:00,12256 2014-09-10 07:00:00,16024 2014-09-10 07:30:00,20193 2014-09-10 08:00:00,20747 2014-09-10 08:30:00,20007 2014-09-10 09:00:00,18782 2014-09-10 09:30:00,18657 2014-09-10 10:00:00,17331 2014-09-10 10:30:00,17989 2014-09-10 11:00:00,17529 2014-09-10 11:30:00,18953 2014-09-10 12:00:00,18567 2014-09-10 12:30:00,17872 2014-09-10 13:00:00,17411 2014-09-10 13:30:00,18792 2014-09-10 14:00:00,18899 2014-09-10 14:30:00,19548 2014-09-10 15:00:00,19093 2014-09-10 15:30:00,16956 2014-09-10 16:00:00,14987 2014-09-10 16:30:00,13895 2014-09-10 17:00:00,17078 2014-09-10 17:30:00,20224 2014-09-10 18:00:00,22805 2014-09-10 18:30:00,24418 2014-09-10 19:00:00,25720 2014-09-10 19:30:00,25891 2014-09-10 20:00:00,26138 2014-09-10 20:30:00,25149 2014-09-10 21:00:00,24908 2014-09-10 21:30:00,24260 2014-09-10 22:00:00,24620 2014-09-10 22:30:00,22813 2014-09-10 23:00:00,20948 2014-09-10 23:30:00,18271 2014-09-11 00:00:00,14939 2014-09-11 00:30:00,11332 2014-09-11 01:00:00,8890 2014-09-11 01:30:00,6980 2014-09-11 02:00:00,5659 2014-09-11 02:30:00,4679 2014-09-11 03:00:00,3550 2014-09-11 03:30:00,2761 2014-09-11 04:00:00,3009 2014-09-11 04:30:00,2596 2014-09-11 05:00:00,2755 2014-09-11 05:30:00,4554 2014-09-11 06:00:00,6964 2014-09-11 06:30:00,12814 2014-09-11 07:00:00,16360 2014-09-11 07:30:00,20658 2014-09-11 08:00:00,21352 2014-09-11 08:30:00,20521 2014-09-11 09:00:00,19759 2014-09-11 09:30:00,19670 2014-09-11 10:00:00,18301 2014-09-11 10:30:00,17768 2014-09-11 11:00:00,16583 2014-09-11 11:30:00,18179 2014-09-11 12:00:00,18896 2014-09-11 12:30:00,18611 2014-09-11 13:00:00,17662 2014-09-11 13:30:00,19057 2014-09-11 14:00:00,18951 2014-09-11 14:30:00,19997 2014-09-11 15:00:00,19260 2014-09-11 15:30:00,17088 2014-09-11 16:00:00,15367 2014-09-11 16:30:00,13915 2014-09-11 17:00:00,17107 2014-09-11 17:30:00,20299 2014-09-11 18:00:00,23029 2014-09-11 18:30:00,24408 2014-09-11 19:00:00,25778 2014-09-11 19:30:00,26274 2014-09-11 20:00:00,26475 2014-09-11 20:30:00,25326 2014-09-11 21:00:00,24557 2014-09-11 21:30:00,24984 2014-09-11 22:00:00,25001 2014-09-11 22:30:00,24112 2014-09-11 23:00:00,23100 2014-09-11 23:30:00,20158 2014-09-12 00:00:00,17954 2014-09-12 00:30:00,14466 2014-09-12 01:00:00,11632 2014-09-12 01:30:00,9400 2014-09-12 02:00:00,7816 2014-09-12 02:30:00,6678 2014-09-12 03:00:00,5499 2014-09-12 03:30:00,4088 2014-09-12 04:00:00,4312 2014-09-12 04:30:00,3433 2014-09-12 05:00:00,3156 2014-09-12 05:30:00,4545 2014-09-12 06:00:00,6802 2014-09-12 06:30:00,11555 2014-09-12 07:00:00,15447 2014-09-12 07:30:00,20385 2014-09-12 08:00:00,20562 2014-09-12 08:30:00,20191 2014-09-12 09:00:00,19405 2014-09-12 09:30:00,18903 2014-09-12 10:00:00,17251 2014-09-12 10:30:00,17874 2014-09-12 11:00:00,17024 2014-09-12 11:30:00,18267 2014-09-12 12:00:00,18351 2014-09-12 12:30:00,17253 2014-09-12 13:00:00,17098 2014-09-12 13:30:00,17885 2014-09-12 14:00:00,18868 2014-09-12 14:30:00,19352 2014-09-12 15:00:00,18035 2014-09-12 15:30:00,15737 2014-09-12 16:00:00,14420 2014-09-12 16:30:00,13148 2014-09-12 17:00:00,16354 2014-09-12 17:30:00,20087 2014-09-12 18:00:00,22814 2014-09-12 18:30:00,25027 2014-09-12 19:00:00,25983 2014-09-12 19:30:00,27090 2014-09-12 20:00:00,26622 2014-09-12 20:30:00,25560 2014-09-12 21:00:00,25141 2014-09-12 21:30:00,25495 2014-09-12 22:00:00,26737 2014-09-12 22:30:00,26657 2014-09-12 23:00:00,27379 2014-09-12 23:30:00,27284 2014-09-13 00:00:00,26227 2014-09-13 00:30:00,24744 2014-09-13 01:00:00,23304 2014-09-13 01:30:00,21293 2014-09-13 02:00:00,19870 2014-09-13 02:30:00,17657 2014-09-13 03:00:00,15100 2014-09-13 03:30:00,12932 2014-09-13 04:00:00,10574 2014-09-13 04:30:00,6546 2014-09-13 05:00:00,4531 2014-09-13 05:30:00,3807 2014-09-13 06:00:00,3672 2014-09-13 06:30:00,5070 2014-09-13 07:00:00,5484 2014-09-13 07:30:00,7528 2014-09-13 08:00:00,8713 2014-09-13 08:30:00,11686 2014-09-13 09:00:00,12432 2014-09-13 09:30:00,16216 2014-09-13 10:00:00,16126 2014-09-13 10:30:00,18527 2014-09-13 11:00:00,18755 2014-09-13 11:30:00,20352 2014-09-13 12:00:00,21020 2014-09-13 12:30:00,20732 2014-09-13 13:00:00,21345 2014-09-13 13:30:00,21500 2014-09-13 14:00:00,20453 2014-09-13 14:30:00,23821 2014-09-13 15:00:00,26150 2014-09-13 15:30:00,24051 2014-09-13 16:00:00,19433 2014-09-13 16:30:00,17521 2014-09-13 17:00:00,19137 2014-09-13 17:30:00,22602 2014-09-13 18:00:00,25039 2014-09-13 18:30:00,25988 2014-09-13 19:00:00,26920 2014-09-13 19:30:00,26845 2014-09-13 20:00:00,26733 2014-09-13 20:30:00,24954 2014-09-13 21:00:00,22317 2014-09-13 21:30:00,22581 2014-09-13 22:00:00,23544 2014-09-13 22:30:00,25662 2014-09-13 23:00:00,26615 2014-09-13 23:30:00,27542 2014-09-14 00:00:00,27320 2014-09-14 00:30:00,25627 2014-09-14 01:00:00,23964 2014-09-14 01:30:00,22332 2014-09-14 02:00:00,20620 2014-09-14 02:30:00,18567 2014-09-14 03:00:00,15772 2014-09-14 03:30:00,13346 2014-09-14 04:00:00,11616 2014-09-14 04:30:00,6999 2014-09-14 05:00:00,4273 2014-09-14 05:30:00,3568 2014-09-14 06:00:00,4209 2014-09-14 06:30:00,4684 2014-09-14 07:00:00,4527 2014-09-14 07:30:00,6231 2014-09-14 08:00:00,7725 2014-09-14 08:30:00,10159 2014-09-14 09:00:00,11013 2014-09-14 09:30:00,14091 2014-09-14 10:00:00,15480 2014-09-14 10:30:00,18669 2014-09-14 11:00:00,18796 2014-09-14 11:30:00,20213 2014-09-14 12:00:00,20410 2014-09-14 12:30:00,21782 2014-09-14 13:00:00,20634 2014-09-14 13:30:00,20061 2014-09-14 14:00:00,19774 2014-09-14 14:30:00,20069 2014-09-14 15:00:00,19417 2014-09-14 15:30:00,19363 2014-09-14 16:00:00,19206 2014-09-14 16:30:00,18284 2014-09-14 17:00:00,19503 2014-09-14 17:30:00,20621 2014-09-14 18:00:00,21554 2014-09-14 18:30:00,21538 2014-09-14 19:00:00,20589 2014-09-14 19:30:00,20391 2014-09-14 20:00:00,19593 2014-09-14 20:30:00,18439 2014-09-14 21:00:00,17587 2014-09-14 21:30:00,17638 2014-09-14 22:00:00,15698 2014-09-14 22:30:00,14343 2014-09-14 23:00:00,12808 2014-09-14 23:30:00,10827 2014-09-15 00:00:00,8077 2014-09-15 00:30:00,6261 2014-09-15 01:00:00,4724 2014-09-15 01:30:00,3852 2014-09-15 02:00:00,3132 2014-09-15 02:30:00,2606 2014-09-15 03:00:00,1975 2014-09-15 03:30:00,1896 2014-09-15 04:00:00,2310 2014-09-15 04:30:00,2388 2014-09-15 05:00:00,2778 2014-09-15 05:30:00,4775 2014-09-15 06:00:00,7022 2014-09-15 06:30:00,11923 2014-09-15 07:00:00,14969 2014-09-15 07:30:00,17943 2014-09-15 08:00:00,18886 2014-09-15 08:30:00,18711 2014-09-15 09:00:00,18012 2014-09-15 09:30:00,17214 2014-09-15 10:00:00,16337 2014-09-15 10:30:00,16157 2014-09-15 11:00:00,15487 2014-09-15 11:30:00,16741 2014-09-15 12:00:00,16793 2014-09-15 12:30:00,16685 2014-09-15 13:00:00,15824 2014-09-15 13:30:00,17040 2014-09-15 14:00:00,17360 2014-09-15 14:30:00,18501 2014-09-15 15:00:00,18143 2014-09-15 15:30:00,16972 2014-09-15 16:00:00,16098 2014-09-15 16:30:00,15878 2014-09-15 17:00:00,18183 2014-09-15 17:30:00,20482 2014-09-15 18:00:00,23314 2014-09-15 18:30:00,24477 2014-09-15 19:00:00,24387 2014-09-15 19:30:00,24193 2014-09-15 20:00:00,24388 2014-09-15 20:30:00,22725 2014-09-15 21:00:00,21907 2014-09-15 21:30:00,21789 2014-09-15 22:00:00,20289 2014-09-15 22:30:00,16585 2014-09-15 23:00:00,14423 2014-09-15 23:30:00,12432 2014-09-16 00:00:00,9359 2014-09-16 00:30:00,7247 2014-09-16 01:00:00,5659 2014-09-16 01:30:00,4155 2014-09-16 02:00:00,3369 2014-09-16 02:30:00,2617 2014-09-16 03:00:00,2214 2014-09-16 03:30:00,1871 2014-09-16 04:00:00,2101 2014-09-16 04:30:00,2016 2014-09-16 05:00:00,2334 2014-09-16 05:30:00,4141 2014-09-16 06:00:00,6465 2014-09-16 06:30:00,11772 2014-09-16 07:00:00,16219 2014-09-16 07:30:00,21253 2014-09-16 08:00:00,22609 2014-09-16 08:30:00,21527 2014-09-16 09:00:00,20975 2014-09-16 09:30:00,19673 2014-09-16 10:00:00,18065 2014-09-16 10:30:00,18948 2014-09-16 11:00:00,18111 2014-09-16 11:30:00,17622 2014-09-16 12:00:00,17320 2014-09-16 12:30:00,16939 2014-09-16 13:00:00,16404 2014-09-16 13:30:00,17247 2014-09-16 14:00:00,17782 2014-09-16 14:30:00,18554 2014-09-16 15:00:00,18680 2014-09-16 15:30:00,16755 2014-09-16 16:00:00,14825 2014-09-16 16:30:00,13975 2014-09-16 17:00:00,17093 2014-09-16 17:30:00,19977 2014-09-16 18:00:00,22922 2014-09-16 18:30:00,24364 2014-09-16 19:00:00,24630 2014-09-16 19:30:00,25234 2014-09-16 20:00:00,24839 2014-09-16 20:30:00,24161 2014-09-16 21:00:00,24550 2014-09-16 21:30:00,23734 2014-09-16 22:00:00,22366 2014-09-16 22:30:00,20411 2014-09-16 23:00:00,17774 2014-09-16 23:30:00,14027 2014-09-17 00:00:00,11590 2014-09-17 00:30:00,8440 2014-09-17 01:00:00,6881 2014-09-17 01:30:00,4920 2014-09-17 02:00:00,4097 2014-09-17 02:30:00,3159 2014-09-17 03:00:00,2653 2014-09-17 03:30:00,2347 2014-09-17 04:00:00,2387 2014-09-17 04:30:00,2194 2014-09-17 05:00:00,2479 2014-09-17 05:30:00,4554 2014-09-17 06:00:00,6775 2014-09-17 06:30:00,12311 2014-09-17 07:00:00,15989 2014-09-17 07:30:00,20058 2014-09-17 08:00:00,20361 2014-09-17 08:30:00,20172 2014-09-17 09:00:00,18974 2014-09-17 09:30:00,17732 2014-09-17 10:00:00,17336 2014-09-17 10:30:00,17321 2014-09-17 11:00:00,16872 2014-09-17 11:30:00,18295 2014-09-17 12:00:00,18273 2014-09-17 12:30:00,17275 2014-09-17 13:00:00,17095 2014-09-17 13:30:00,17715 2014-09-17 14:00:00,18451 2014-09-17 14:30:00,18612 2014-09-17 15:00:00,18148 2014-09-17 15:30:00,16473 2014-09-17 16:00:00,14474 2014-09-17 16:30:00,13434 2014-09-17 17:00:00,16229 2014-09-17 17:30:00,19852 2014-09-17 18:00:00,22394 2014-09-17 18:30:00,24618 2014-09-17 19:00:00,25838 2014-09-17 19:30:00,25496 2014-09-17 20:00:00,24980 2014-09-17 20:30:00,23545 2014-09-17 21:00:00,23847 2014-09-17 21:30:00,24236 2014-09-17 22:00:00,23551 2014-09-17 22:30:00,22454 2014-09-17 23:00:00,20389 2014-09-17 23:30:00,17673 2014-09-18 00:00:00,13651 2014-09-18 00:30:00,10769 2014-09-18 01:00:00,8102 2014-09-18 01:30:00,6196 2014-09-18 02:00:00,5249 2014-09-18 02:30:00,3850 2014-09-18 03:00:00,3150 2014-09-18 03:30:00,2584 2014-09-18 04:00:00,2770 2014-09-18 04:30:00,2477 2014-09-18 05:00:00,2678 2014-09-18 05:30:00,4506 2014-09-18 06:00:00,7292 2014-09-18 06:30:00,12449 2014-09-18 07:00:00,16418 2014-09-18 07:30:00,20080 2014-09-18 08:00:00,20693 2014-09-18 08:30:00,19988 2014-09-18 09:00:00,19313 2014-09-18 09:30:00,18918 2014-09-18 10:00:00,17790 2014-09-18 10:30:00,18028 2014-09-18 11:00:00,17242 2014-09-18 11:30:00,18279 2014-09-18 12:00:00,18118 2014-09-18 12:30:00,17858 2014-09-18 13:00:00,17635 2014-09-18 13:30:00,18265 2014-09-18 14:00:00,18676 2014-09-18 14:30:00,18686 2014-09-18 15:00:00,18134 2014-09-18 15:30:00,15579 2014-09-18 16:00:00,13635 2014-09-18 16:30:00,12689 2014-09-18 17:00:00,15756 2014-09-18 17:30:00,19691 2014-09-18 18:00:00,21487 2014-09-18 18:30:00,22751 2014-09-18 19:00:00,24126 2014-09-18 19:30:00,24956 2014-09-18 20:00:00,26003 2014-09-18 20:30:00,25167 2014-09-18 21:00:00,25659 2014-09-18 21:30:00,25536 2014-09-18 22:00:00,25761 2014-09-18 22:30:00,25212 2014-09-18 23:00:00,23548 2014-09-18 23:30:00,22005 2014-09-19 00:00:00,19518 2014-09-19 00:30:00,15755 2014-09-19 01:00:00,12747 2014-09-19 01:30:00,10116 2014-09-19 02:00:00,8379 2014-09-19 02:30:00,6566 2014-09-19 03:00:00,5478 2014-09-19 03:30:00,4552 2014-09-19 04:00:00,4546 2014-09-19 04:30:00,3489 2014-09-19 05:00:00,3269 2014-09-19 05:30:00,4799 2014-09-19 06:00:00,7384 2014-09-19 06:30:00,11928 2014-09-19 07:00:00,15434 2014-09-19 07:30:00,19509 2014-09-19 08:00:00,19672 2014-09-19 08:30:00,19287 2014-09-19 09:00:00,18369 2014-09-19 09:30:00,18050 2014-09-19 10:00:00,17306 2014-09-19 10:30:00,17661 2014-09-19 11:00:00,17158 2014-09-19 11:30:00,18215 2014-09-19 12:00:00,18175 2014-09-19 12:30:00,17568 2014-09-19 13:00:00,17079 2014-09-19 13:30:00,17287 2014-09-19 14:00:00,17885 2014-09-19 14:30:00,18287 2014-09-19 15:00:00,17782 2014-09-19 15:30:00,16021 2014-09-19 16:00:00,14205 2014-09-19 16:30:00,12834 2014-09-19 17:00:00,16332 2014-09-19 17:30:00,19704 2014-09-19 18:00:00,22931 2014-09-19 18:30:00,25328 2014-09-19 19:00:00,26188 2014-09-19 19:30:00,27541 2014-09-19 20:00:00,26811 2014-09-19 20:30:00,26093 2014-09-19 21:00:00,26091 2014-09-19 21:30:00,26247 2014-09-19 22:00:00,27090 2014-09-19 22:30:00,27681 2014-09-19 23:00:00,27159 2014-09-19 23:30:00,26816 2014-09-20 00:00:00,25251 2014-09-20 00:30:00,23375 2014-09-20 01:00:00,21806 2014-09-20 01:30:00,20635 2014-09-20 02:00:00,19322 2014-09-20 02:30:00,16841 2014-09-20 03:00:00,14744 2014-09-20 03:30:00,12309 2014-09-20 04:00:00,10242 2014-09-20 04:30:00,6470 2014-09-20 05:00:00,4374 2014-09-20 05:30:00,3435 2014-09-20 06:00:00,3789 2014-09-20 06:30:00,4454 2014-09-20 07:00:00,5381 2014-09-20 07:30:00,7585 2014-09-20 08:00:00,8782 2014-09-20 08:30:00,11824 2014-09-20 09:00:00,12587 2014-09-20 09:30:00,15795 2014-09-20 10:00:00,16088 2014-09-20 10:30:00,18430 2014-09-20 11:00:00,18543 2014-09-20 11:30:00,20332 2014-09-20 12:00:00,19797 2014-09-20 12:30:00,20601 2014-09-20 13:00:00,20823 2014-09-20 13:30:00,21182 2014-09-20 14:00:00,20742 2014-09-20 14:30:00,20477 2014-09-20 15:00:00,20654 2014-09-20 15:30:00,20386 2014-09-20 16:00:00,18174 2014-09-20 16:30:00,16690 2014-09-20 17:00:00,18151 2014-09-20 17:30:00,21330 2014-09-20 18:00:00,23268 2014-09-20 18:30:00,25025 2014-09-20 19:00:00,25816 2014-09-20 19:30:00,25694 2014-09-20 20:00:00,24693 2014-09-20 20:30:00,24187 2014-09-20 21:00:00,23820 2014-09-20 21:30:00,24549 2014-09-20 22:00:00,25442 2014-09-20 22:30:00,25914 2014-09-20 23:00:00,26329 2014-09-20 23:30:00,26618 2014-09-21 00:00:00,26477 2014-09-21 00:30:00,25461 2014-09-21 01:00:00,25371 2014-09-21 01:30:00,21726 2014-09-21 02:00:00,20737 2014-09-21 02:30:00,18852 2014-09-21 03:00:00,16474 2014-09-21 03:30:00,13647 2014-09-21 04:00:00,11793 2014-09-21 04:30:00,7142 2014-09-21 05:00:00,4611 2014-09-21 05:30:00,3474 2014-09-21 06:00:00,4131 2014-09-21 06:30:00,4395 2014-09-21 07:00:00,4443 2014-09-21 07:30:00,6155 2014-09-21 08:00:00,6827 2014-09-21 08:30:00,9510 2014-09-21 09:00:00,10785 2014-09-21 09:30:00,13570 2014-09-21 10:00:00,14691 2014-09-21 10:30:00,17071 2014-09-21 11:00:00,17457 2014-09-21 11:30:00,17961 2014-09-21 12:00:00,17900 2014-09-21 12:30:00,18347 2014-09-21 13:00:00,17302 2014-09-21 13:30:00,16009 2014-09-21 14:00:00,15427 2014-09-21 14:30:00,14986 2014-09-21 15:00:00,14381 2014-09-21 15:30:00,13763 2014-09-21 16:00:00,13163 2014-09-21 16:30:00,11940 2014-09-21 17:00:00,13536 2014-09-21 17:30:00,15175 2014-09-21 18:00:00,16406 2014-09-21 18:30:00,17318 2014-09-21 19:00:00,17588 2014-09-21 19:30:00,17895 2014-09-21 20:00:00,18084 2014-09-21 20:30:00,16972 2014-09-21 21:00:00,16389 2014-09-21 21:30:00,15846 2014-09-21 22:00:00,15329 2014-09-21 22:30:00,14446 2014-09-21 23:00:00,12721 2014-09-21 23:30:00,10826 2014-09-22 00:00:00,9067 2014-09-22 00:30:00,6546 2014-09-22 01:00:00,4580 2014-09-22 01:30:00,3654 2014-09-22 02:00:00,3137 2014-09-22 02:30:00,2610 2014-09-22 03:00:00,2061 2014-09-22 03:30:00,1959 2014-09-22 04:00:00,2356 2014-09-22 04:30:00,2400 2014-09-22 05:00:00,2911 2014-09-22 05:30:00,4833 2014-09-22 06:00:00,7398 2014-09-22 06:30:00,11809 2014-09-22 07:00:00,14495 2014-09-22 07:30:00,16812 2014-09-22 08:00:00,17569 2014-09-22 08:30:00,16738 2014-09-22 09:00:00,16612 2014-09-22 09:30:00,15702 2014-09-22 10:00:00,14817 2014-09-22 10:30:00,14668 2014-09-22 11:00:00,14458 2014-09-22 11:30:00,15475 2014-09-22 12:00:00,15539 2014-09-22 12:30:00,15345 2014-09-22 13:00:00,15222 2014-09-22 13:30:00,15213 2014-09-22 14:00:00,16167 2014-09-22 14:30:00,16210 2014-09-22 15:00:00,16393 2014-09-22 15:30:00,14797 2014-09-22 16:00:00,13755 2014-09-22 16:30:00,13960 2014-09-22 17:00:00,16248 2014-09-22 17:30:00,18272 2014-09-22 18:00:00,20440 2014-09-22 18:30:00,21524 2014-09-22 19:00:00,21828 2014-09-22 19:30:00,22825 2014-09-22 20:00:00,22647 2014-09-22 20:30:00,22210 2014-09-22 21:00:00,22426 2014-09-22 21:30:00,20839 2014-09-22 22:00:00,20239 2014-09-22 22:30:00,18144 2014-09-22 23:00:00,15459 2014-09-22 23:30:00,13766 2014-09-23 00:00:00,11187 2014-09-23 00:30:00,8959 2014-09-23 01:00:00,7101 2014-09-23 01:30:00,4710 2014-09-23 02:00:00,3571 2014-09-23 02:30:00,2765 2014-09-23 03:00:00,2101 2014-09-23 03:30:00,1867 2014-09-23 04:00:00,2126 2014-09-23 04:30:00,2082 2014-09-23 05:00:00,2393 2014-09-23 05:30:00,4443 2014-09-23 06:00:00,7297 2014-09-23 06:30:00,12466 2014-09-23 07:00:00,15547 2014-09-23 07:30:00,18160 2014-09-23 08:00:00,18295 2014-09-23 08:30:00,17794 2014-09-23 09:00:00,16541 2014-09-23 09:30:00,16239 2014-09-23 10:00:00,15239 2014-09-23 10:30:00,15153 2014-09-23 11:00:00,14168 2014-09-23 11:30:00,14872 2014-09-23 12:00:00,15293 2014-09-23 12:30:00,14971 2014-09-23 13:00:00,14359 2014-09-23 13:30:00,14486 2014-09-23 14:00:00,14471 2014-09-23 14:30:00,14920 2014-09-23 15:00:00,14411 2014-09-23 15:30:00,13573 2014-09-23 16:00:00,11876 2014-09-23 16:30:00,11040 2014-09-23 17:00:00,13441 2014-09-23 17:30:00,16163 2014-09-23 18:00:00,19059 2014-09-23 18:30:00,19621 2014-09-23 19:00:00,21616 2014-09-23 19:30:00,23427 2014-09-23 20:00:00,23735 2014-09-23 20:30:00,23354 2014-09-23 21:00:00,23391 2014-09-23 21:30:00,23228 2014-09-23 22:00:00,21882 2014-09-23 22:30:00,21221 2014-09-23 23:00:00,18922 2014-09-23 23:30:00,15473 2014-09-24 00:00:00,12457 2014-09-24 00:30:00,9497 2014-09-24 01:00:00,7073 2014-09-24 01:30:00,5496 2014-09-24 02:00:00,4477 2014-09-24 02:30:00,3527 2014-09-24 03:00:00,2971 2014-09-24 03:30:00,2660 2014-09-24 04:00:00,2497 2014-09-24 04:30:00,2250 2014-09-24 05:00:00,2594 2014-09-24 05:30:00,4316 2014-09-24 06:00:00,7112 2014-09-24 06:30:00,12119 2014-09-24 07:00:00,15652 2014-09-24 07:30:00,18565 2014-09-24 08:00:00,18437 2014-09-24 08:30:00,17831 2014-09-24 09:00:00,17103 2014-09-24 09:30:00,16446 2014-09-24 10:00:00,15593 2014-09-24 10:30:00,15353 2014-09-24 11:00:00,15105 2014-09-24 11:30:00,16058 2014-09-24 12:00:00,16475 2014-09-24 12:30:00,16226 2014-09-24 13:00:00,15766 2014-09-24 13:30:00,16242 2014-09-24 14:00:00,16976 2014-09-24 14:30:00,17117 2014-09-24 15:00:00,16910 2014-09-24 15:30:00,14845 2014-09-24 16:00:00,12840 2014-09-24 16:30:00,12913 2014-09-24 17:00:00,15736 2014-09-24 17:30:00,18396 2014-09-24 18:00:00,21170 2014-09-24 18:30:00,21255 2014-09-24 19:00:00,22014 2014-09-24 19:30:00,22334 2014-09-24 20:00:00,21426 2014-09-24 20:30:00,21152 2014-09-24 21:00:00,22304 2014-09-24 21:30:00,22947 2014-09-24 22:00:00,22195 2014-09-24 22:30:00,21592 2014-09-24 23:00:00,18884 2014-09-24 23:30:00,15885 2014-09-25 00:00:00,12556 2014-09-25 00:30:00,10023 2014-09-25 01:00:00,7320 2014-09-25 01:30:00,6007 2014-09-25 02:00:00,4886 2014-09-25 02:30:00,4068 2014-09-25 03:00:00,3170 2014-09-25 03:30:00,2671 2014-09-25 04:00:00,2844 2014-09-25 04:30:00,2430 2014-09-25 05:00:00,2534 2014-09-25 05:30:00,4193 2014-09-25 06:00:00,6274 2014-09-25 06:30:00,11614 2014-09-25 07:00:00,14471 2014-09-25 07:30:00,17184 2014-09-25 08:00:00,18428 2014-09-25 08:30:00,18257 2014-09-25 09:00:00,17375 2014-09-25 09:30:00,18079 2014-09-25 10:00:00,17902 2014-09-25 10:30:00,17934 2014-09-25 11:00:00,16311 2014-09-25 11:30:00,16460 2014-09-25 12:00:00,17383 2014-09-25 12:30:00,16931 2014-09-25 13:00:00,17236 2014-09-25 13:30:00,17120 2014-09-25 14:00:00,16635 2014-09-25 14:30:00,16048 2014-09-25 15:00:00,15553 2014-09-25 15:30:00,14421 2014-09-25 16:00:00,13456 2014-09-25 16:30:00,12820 2014-09-25 17:00:00,16109 2014-09-25 17:30:00,19198 2014-09-25 18:00:00,21302 2014-09-25 18:30:00,22657 2014-09-25 19:00:00,23276 2014-09-25 19:30:00,23723 2014-09-25 20:00:00,23021 2014-09-25 20:30:00,21823 2014-09-25 21:00:00,21666 2014-09-25 21:30:00,22491 2014-09-25 22:00:00,22004 2014-09-25 22:30:00,23595 2014-09-25 23:00:00,22090 2014-09-25 23:30:00,20296 2014-09-26 00:00:00,16288 2014-09-26 00:30:00,13049 2014-09-26 01:00:00,10504 2014-09-26 01:30:00,8423 2014-09-26 02:00:00,7090 2014-09-26 02:30:00,5920 2014-09-26 03:00:00,4849 2014-09-26 03:30:00,4102 2014-09-26 04:00:00,4093 2014-09-26 04:30:00,3162 2014-09-26 05:00:00,2939 2014-09-26 05:30:00,4012 2014-09-26 06:00:00,6627 2014-09-26 06:30:00,10911 2014-09-26 07:00:00,13043 2014-09-26 07:30:00,16141 2014-09-26 08:00:00,16551 2014-09-26 08:30:00,17566 2014-09-26 09:00:00,16839 2014-09-26 09:30:00,16706 2014-09-26 10:00:00,15946 2014-09-26 10:30:00,16319 2014-09-26 11:00:00,15319 2014-09-26 11:30:00,16456 2014-09-26 12:00:00,16719 2014-09-26 12:30:00,16157 2014-09-26 13:00:00,15798 2014-09-26 13:30:00,16747 2014-09-26 14:00:00,16855 2014-09-26 14:30:00,17441 2014-09-26 15:00:00,16769 2014-09-26 15:30:00,15274 2014-09-26 16:00:00,14150 2014-09-26 16:30:00,13382 2014-09-26 17:00:00,16018 2014-09-26 17:30:00,19412 2014-09-26 18:00:00,22047 2014-09-26 18:30:00,23843 2014-09-26 19:00:00,24816 2014-09-26 19:30:00,25433 2014-09-26 20:00:00,25249 2014-09-26 20:30:00,24492 2014-09-26 21:00:00,24332 2014-09-26 21:30:00,24473 2014-09-26 22:00:00,25932 2014-09-26 22:30:00,25931 2014-09-26 23:00:00,26479 2014-09-26 23:30:00,25878 2014-09-27 00:00:00,25100 2014-09-27 00:30:00,23886 2014-09-27 01:00:00,22982 2014-09-27 01:30:00,20541 2014-09-27 02:00:00,18970 2014-09-27 02:30:00,17433 2014-09-27 03:00:00,14547 2014-09-27 03:30:00,12694 2014-09-27 04:00:00,10374 2014-09-27 04:30:00,6339 2014-09-27 05:00:00,4313 2014-09-27 05:30:00,3538 2014-09-27 06:00:00,3709 2014-09-27 06:30:00,5311 2014-09-27 07:00:00,5974 2014-09-27 07:30:00,8183 2014-09-27 08:00:00,8942 2014-09-27 08:30:00,11805 2014-09-27 09:00:00,12261 2014-09-27 09:30:00,15226 2014-09-27 10:00:00,15802 2014-09-27 10:30:00,17334 2014-09-27 11:00:00,18070 2014-09-27 11:30:00,20105 2014-09-27 12:00:00,20138 2014-09-27 12:30:00,19968 2014-09-27 13:00:00,20411 2014-09-27 13:30:00,20317 2014-09-27 14:00:00,19930 2014-09-27 14:30:00,20502 2014-09-27 15:00:00,19916 2014-09-27 15:30:00,19259 2014-09-27 16:00:00,17572 2014-09-27 16:30:00,15629 2014-09-27 17:00:00,17721 2014-09-27 17:30:00,21308 2014-09-27 18:00:00,23297 2014-09-27 18:30:00,24024 2014-09-27 19:00:00,24925 2014-09-27 19:30:00,25418 2014-09-27 20:00:00,23601 2014-09-27 20:30:00,23219 2014-09-27 21:00:00,22544 2014-09-27 21:30:00,23273 2014-09-27 22:00:00,25131 2014-09-27 22:30:00,26895 2014-09-27 23:00:00,27936 2014-09-27 23:30:00,28113 2014-09-28 00:00:00,27269 2014-09-28 00:30:00,26320 2014-09-28 01:00:00,24571 2014-09-28 01:30:00,22698 2014-09-28 02:00:00,20948 2014-09-28 02:30:00,18561 2014-09-28 03:00:00,16218 2014-09-28 03:30:00,13873 2014-09-28 04:00:00,11926 2014-09-28 04:30:00,7361 2014-09-28 05:00:00,4330 2014-09-28 05:30:00,3681 2014-09-28 06:00:00,3886 2014-09-28 06:30:00,4600 2014-09-28 07:00:00,4930 2014-09-28 07:30:00,6204 2014-09-28 08:00:00,7212 2014-09-28 08:30:00,9136 2014-09-28 09:00:00,10287 2014-09-28 09:30:00,12808 2014-09-28 10:00:00,13952 2014-09-28 10:30:00,16763 2014-09-28 11:00:00,17356 2014-09-28 11:30:00,19238 2014-09-28 12:00:00,19607 2014-09-28 12:30:00,20310 2014-09-28 13:00:00,20033 2014-09-28 13:30:00,19595 2014-09-28 14:00:00,19871 2014-09-28 14:30:00,19819 2014-09-28 15:00:00,18620 2014-09-28 15:30:00,18657 2014-09-28 16:00:00,17688 2014-09-28 16:30:00,16927 2014-09-28 17:00:00,17637 2014-09-28 17:30:00,19283 2014-09-28 18:00:00,20448 2014-09-28 18:30:00,19638 2014-09-28 19:00:00,19509 2014-09-28 19:30:00,18936 2014-09-28 20:00:00,18188 2014-09-28 20:30:00,16594 2014-09-28 21:00:00,16330 2014-09-28 21:30:00,16075 2014-09-28 22:00:00,14977 2014-09-28 22:30:00,13503 2014-09-28 23:00:00,12052 2014-09-28 23:30:00,10779 2014-09-29 00:00:00,8332 2014-09-29 00:30:00,6357 2014-09-29 01:00:00,4958 2014-09-29 01:30:00,3461 2014-09-29 02:00:00,3253 2014-09-29 02:30:00,2493 2014-09-29 03:00:00,1993 2014-09-29 03:30:00,1839 2014-09-29 04:00:00,2275 2014-09-29 04:30:00,2280 2014-09-29 05:00:00,2986 2014-09-29 05:30:00,4608 2014-09-29 06:00:00,7253 2014-09-29 06:30:00,11360 2014-09-29 07:00:00,14157 2014-09-29 07:30:00,16864 2014-09-29 08:00:00,17399 2014-09-29 08:30:00,16671 2014-09-29 09:00:00,15478 2014-09-29 09:30:00,14677 2014-09-29 10:00:00,14935 2014-09-29 10:30:00,15392 2014-09-29 11:00:00,15147 2014-09-29 11:30:00,16345 2014-09-29 12:00:00,16382 2014-09-29 12:30:00,15798 2014-09-29 13:00:00,15584 2014-09-29 13:30:00,16544 2014-09-29 14:00:00,17377 2014-09-29 14:30:00,18345 2014-09-29 15:00:00,18004 2014-09-29 15:30:00,16863 2014-09-29 16:00:00,15714 2014-09-29 16:30:00,14743 2014-09-29 17:00:00,17579 2014-09-29 17:30:00,21604 2014-09-29 18:00:00,23120 2014-09-29 18:30:00,22717 2014-09-29 19:00:00,22757 2014-09-29 19:30:00,22311 2014-09-29 20:00:00,21642 2014-09-29 20:30:00,20568 2014-09-29 21:00:00,19969 2014-09-29 21:30:00,19484 2014-09-29 22:00:00,17993 2014-09-29 22:30:00,17446 2014-09-29 23:00:00,13722 2014-09-29 23:30:00,11549 2014-09-30 00:00:00,9459 2014-09-30 00:30:00,6800 2014-09-30 01:00:00,5323 2014-09-30 01:30:00,3976 2014-09-30 02:00:00,3279 2014-09-30 02:30:00,2617 2014-09-30 03:00:00,2010 2014-09-30 03:30:00,1853 2014-09-30 04:00:00,2150 2014-09-30 04:30:00,2019 2014-09-30 05:00:00,2414 2014-09-30 05:30:00,4193 2014-09-30 06:00:00,6473 2014-09-30 06:30:00,11500 2014-09-30 07:00:00,14892 2014-09-30 07:30:00,19148 2014-09-30 08:00:00,19942 2014-09-30 08:30:00,19874 2014-09-30 09:00:00,18453 2014-09-30 09:30:00,18316 2014-09-30 10:00:00,16768 2014-09-30 10:30:00,16430 2014-09-30 11:00:00,16035 2014-09-30 11:30:00,17493 2014-09-30 12:00:00,17298 2014-09-30 12:30:00,16790 2014-09-30 13:00:00,15966 2014-09-30 13:30:00,17428 2014-09-30 14:00:00,18268 2014-09-30 14:30:00,18462 2014-09-30 15:00:00,18361 2014-09-30 15:30:00,16495 2014-09-30 16:00:00,14614 2014-09-30 16:30:00,14124 2014-09-30 17:00:00,17230 2014-09-30 17:30:00,20123 2014-09-30 18:00:00,22947 2014-09-30 18:30:00,23715 2014-09-30 19:00:00,24428 2014-09-30 19:30:00,24482 2014-09-30 20:00:00,24208 2014-09-30 20:30:00,23513 2014-09-30 21:00:00,24049 2014-09-30 21:30:00,23634 2014-09-30 22:00:00,22175 2014-09-30 22:30:00,20697 2014-09-30 23:00:00,17890 2014-09-30 23:30:00,15516 2014-10-01 00:00:00,12751 2014-10-01 00:30:00,8767 2014-10-01 01:00:00,7005 2014-10-01 01:30:00,5257 2014-10-01 02:00:00,4189 2014-10-01 02:30:00,3236 2014-10-01 03:00:00,2817 2014-10-01 03:30:00,2527 2014-10-01 04:00:00,2406 2014-10-01 04:30:00,1961 2014-10-01 05:00:00,2478 2014-10-01 05:30:00,4483 2014-10-01 06:00:00,7002 2014-10-01 06:30:00,11917 2014-10-01 07:00:00,15929 2014-10-01 07:30:00,20327 2014-10-01 08:00:00,20974 2014-10-01 08:30:00,20999 2014-10-01 09:00:00,19639 2014-10-01 09:30:00,19221 2014-10-01 10:00:00,17308 2014-10-01 10:30:00,17140 2014-10-01 11:00:00,16773 2014-10-01 11:30:00,19397 2014-10-01 12:00:00,18697 2014-10-01 12:30:00,18042 2014-10-01 13:00:00,17332 2014-10-01 13:30:00,17585 2014-10-01 14:00:00,18263 2014-10-01 14:30:00,18842 2014-10-01 15:00:00,18583 2014-10-01 15:30:00,17301 2014-10-01 16:00:00,15060 2014-10-01 16:30:00,14201 2014-10-01 17:00:00,16655 2014-10-01 17:30:00,19964 2014-10-01 18:00:00,22960 2014-10-01 18:30:00,23759 2014-10-01 19:00:00,25024 2014-10-01 19:30:00,25414 2014-10-01 20:00:00,24917 2014-10-01 20:30:00,24348 2014-10-01 21:00:00,24248 2014-10-01 21:30:00,24669 2014-10-01 22:00:00,23132 2014-10-01 22:30:00,22753 2014-10-01 23:00:00,20371 2014-10-01 23:30:00,17313 2014-10-02 00:00:00,13534 2014-10-02 00:30:00,10485 2014-10-02 01:00:00,7944 2014-10-02 01:30:00,6030 2014-10-02 02:00:00,4867 2014-10-02 02:30:00,3812 2014-10-02 03:00:00,3251 2014-10-02 03:30:00,2738 2014-10-02 04:00:00,2755 2014-10-02 04:30:00,2221 2014-10-02 05:00:00,2363 2014-10-02 05:30:00,4351 2014-10-02 06:00:00,6835 2014-10-02 06:30:00,11982 2014-10-02 07:00:00,15844 2014-10-02 07:30:00,19853 2014-10-02 08:00:00,20187 2014-10-02 08:30:00,20480 2014-10-02 09:00:00,19531 2014-10-02 09:30:00,18873 2014-10-02 10:00:00,17534 2014-10-02 10:30:00,17803 2014-10-02 11:00:00,16994 2014-10-02 11:30:00,18149 2014-10-02 12:00:00,18251 2014-10-02 12:30:00,17723 2014-10-02 13:00:00,17104 2014-10-02 13:30:00,18124 2014-10-02 14:00:00,18680 2014-10-02 14:30:00,19364 2014-10-02 15:00:00,19044 2014-10-02 15:30:00,16883 2014-10-02 16:00:00,14389 2014-10-02 16:30:00,13866 2014-10-02 17:00:00,17005 2014-10-02 17:30:00,20674 2014-10-02 18:00:00,22678 2014-10-02 18:30:00,23225 2014-10-02 19:00:00,25012 2014-10-02 19:30:00,25574 2014-10-02 20:00:00,25301 2014-10-02 20:30:00,25391 2014-10-02 21:00:00,25520 2014-10-02 21:30:00,25582 2014-10-02 22:00:00,24848 2014-10-02 22:30:00,24100 2014-10-02 23:00:00,23336 2014-10-02 23:30:00,21549 2014-10-03 00:00:00,18003 2014-10-03 00:30:00,15266 2014-10-03 01:00:00,12130 2014-10-03 01:30:00,9847 2014-10-03 02:00:00,8022 2014-10-03 02:30:00,6508 2014-10-03 03:00:00,5309 2014-10-03 03:30:00,4339 2014-10-03 04:00:00,4202 2014-10-03 04:30:00,3358 2014-10-03 05:00:00,3083 2014-10-03 05:30:00,4391 2014-10-03 06:00:00,6769 2014-10-03 06:30:00,11309 2014-10-03 07:00:00,14866 2014-10-03 07:30:00,18942 2014-10-03 08:00:00,19693 2014-10-03 08:30:00,19776 2014-10-03 09:00:00,19309 2014-10-03 09:30:00,18801 2014-10-03 10:00:00,17108 2014-10-03 10:30:00,16952 2014-10-03 11:00:00,17108 2014-10-03 11:30:00,17927 2014-10-03 12:00:00,18426 2014-10-03 12:30:00,17340 2014-10-03 13:00:00,17150 2014-10-03 13:30:00,17581 2014-10-03 14:00:00,18924 2014-10-03 14:30:00,19602 2014-10-03 15:00:00,18893 2014-10-03 15:30:00,16691 2014-10-03 16:00:00,15332 2014-10-03 16:30:00,14661 2014-10-03 17:00:00,18110 2014-10-03 17:30:00,22624 2014-10-03 18:00:00,25209 2014-10-03 18:30:00,24975 2014-10-03 19:00:00,26477 2014-10-03 19:30:00,27165 2014-10-03 20:00:00,25960 2014-10-03 20:30:00,25435 2014-10-03 21:00:00,24847 2014-10-03 21:30:00,25174 2014-10-03 22:00:00,25419 2014-10-03 22:30:00,25904 2014-10-03 23:00:00,24543 2014-10-03 23:30:00,24513 2014-10-04 00:00:00,23316 2014-10-04 00:30:00,22311 2014-10-04 01:00:00,20470 2014-10-04 01:30:00,18629 2014-10-04 02:00:00,17120 2014-10-04 02:30:00,15544 2014-10-04 03:00:00,14012 2014-10-04 03:30:00,11425 2014-10-04 04:00:00,9541 2014-10-04 04:30:00,5912 2014-10-04 05:00:00,3832 2014-10-04 05:30:00,3230 2014-10-04 06:00:00,3425 2014-10-04 06:30:00,4159 2014-10-04 07:00:00,4720 2014-10-04 07:30:00,5848 2014-10-04 08:00:00,6901 2014-10-04 08:30:00,9611 2014-10-04 09:00:00,11626 2014-10-04 09:30:00,14814 2014-10-04 10:00:00,16839 2014-10-04 10:30:00,18245 2014-10-04 11:00:00,18230 2014-10-04 11:30:00,18322 2014-10-04 12:00:00,18541 2014-10-04 12:30:00,18062 2014-10-04 13:00:00,18008 2014-10-04 13:30:00,18784 2014-10-04 14:00:00,17708 2014-10-04 14:30:00,17998 2014-10-04 15:00:00,18033 2014-10-04 15:30:00,17851 2014-10-04 16:00:00,17046 2014-10-04 16:30:00,17241 2014-10-04 17:00:00,19295 2014-10-04 17:30:00,21740 2014-10-04 18:00:00,22729 2014-10-04 18:30:00,23854 2014-10-04 19:00:00,25857 2014-10-04 19:30:00,26490 2014-10-04 20:00:00,24115 2014-10-04 20:30:00,23384 2014-10-04 21:00:00,23515 2014-10-04 21:30:00,24476 2014-10-04 22:00:00,24455 2014-10-04 22:30:00,25474 2014-10-04 23:00:00,25811 2014-10-04 23:30:00,25847 2014-10-05 00:00:00,25224 2014-10-05 00:30:00,23248 2014-10-05 01:00:00,22772 2014-10-05 01:30:00,20671 2014-10-05 02:00:00,19208 2014-10-05 02:30:00,17300 2014-10-05 03:00:00,15260 2014-10-05 03:30:00,12970 2014-10-05 04:00:00,11168 2014-10-05 04:30:00,6678 2014-10-05 05:00:00,4321 2014-10-05 05:30:00,3259 2014-10-05 06:00:00,3277 2014-10-05 06:30:00,4072 2014-10-05 07:00:00,4566 2014-10-05 07:30:00,5973 2014-10-05 08:00:00,7209 2014-10-05 08:30:00,8999 2014-10-05 09:00:00,10669 2014-10-05 09:30:00,12678 2014-10-05 10:00:00,14511 2014-10-05 10:30:00,16953 2014-10-05 11:00:00,17817 2014-10-05 11:30:00,18894 2014-10-05 12:00:00,18505 2014-10-05 12:30:00,19227 2014-10-05 13:00:00,18361 2014-10-05 13:30:00,18014 2014-10-05 14:00:00,17486 2014-10-05 14:30:00,17816 2014-10-05 15:00:00,17364 2014-10-05 15:30:00,16871 2014-10-05 16:00:00,15497 2014-10-05 16:30:00,15185 2014-10-05 17:00:00,16114 2014-10-05 17:30:00,18312 2014-10-05 18:00:00,19793 2014-10-05 18:30:00,19706 2014-10-05 19:00:00,20198 2014-10-05 19:30:00,19790 2014-10-05 20:00:00,18192 2014-10-05 20:30:00,17701 2014-10-05 21:00:00,16484 2014-10-05 21:30:00,16626 2014-10-05 22:00:00,14889 2014-10-05 22:30:00,14114 2014-10-05 23:00:00,11870 2014-10-05 23:30:00,10041 2014-10-06 00:00:00,7997 2014-10-06 00:30:00,5689 2014-10-06 01:00:00,4351 2014-10-06 01:30:00,3348 2014-10-06 02:00:00,2809 2014-10-06 02:30:00,2193 2014-10-06 03:00:00,1752 2014-10-06 03:30:00,1731 2014-10-06 04:00:00,1994 2014-10-06 04:30:00,2178 2014-10-06 05:00:00,2787 2014-10-06 05:30:00,4578 2014-10-06 06:00:00,6816 2014-10-06 06:30:00,11243 2014-10-06 07:00:00,14265 2014-10-06 07:30:00,17395 2014-10-06 08:00:00,18327 2014-10-06 08:30:00,17729 2014-10-06 09:00:00,17870 2014-10-06 09:30:00,16982 2014-10-06 10:00:00,15335 2014-10-06 10:30:00,15998 2014-10-06 11:00:00,15414 2014-10-06 11:30:00,16233 2014-10-06 12:00:00,16499 2014-10-06 12:30:00,16380 2014-10-06 13:00:00,15414 2014-10-06 13:30:00,16720 2014-10-06 14:00:00,17137 2014-10-06 14:30:00,18046 2014-10-06 15:00:00,18110 2014-10-06 15:30:00,17087 2014-10-06 16:00:00,15794 2014-10-06 16:30:00,15965 2014-10-06 17:00:00,18732 2014-10-06 17:30:00,21107 2014-10-06 18:00:00,23450 2014-10-06 18:30:00,24200 2014-10-06 19:00:00,24518 2014-10-06 19:30:00,23704 2014-10-06 20:00:00,22112 2014-10-06 20:30:00,20986 2014-10-06 21:00:00,21032 2014-10-06 21:30:00,19963 2014-10-06 22:00:00,18986 2014-10-06 22:30:00,17125 2014-10-06 23:00:00,15528 2014-10-06 23:30:00,11610 2014-10-07 00:00:00,9469 2014-10-07 00:30:00,6605 2014-10-07 01:00:00,5283 2014-10-07 01:30:00,4152 2014-10-07 02:00:00,3319 2014-10-07 02:30:00,2432 2014-10-07 03:00:00,1968 2014-10-07 03:30:00,1769 2014-10-07 04:00:00,2018 2014-10-07 04:30:00,1933 2014-10-07 05:00:00,2240 2014-10-07 05:30:00,4305 2014-10-07 06:00:00,6719 2014-10-07 06:30:00,11392 2014-10-07 07:00:00,14960 2014-10-07 07:30:00,18975 2014-10-07 08:00:00,19602 2014-10-07 08:30:00,19572 2014-10-07 09:00:00,18772 2014-10-07 09:30:00,17757 2014-10-07 10:00:00,16706 2014-10-07 10:30:00,16601 2014-10-07 11:00:00,15673 2014-10-07 11:30:00,16929 2014-10-07 12:00:00,17435 2014-10-07 12:30:00,16953 2014-10-07 13:00:00,16417 2014-10-07 13:30:00,17022 2014-10-07 14:00:00,17540 2014-10-07 14:30:00,18417 2014-10-07 15:00:00,18698 2014-10-07 15:30:00,16193 2014-10-07 16:00:00,14544 2014-10-07 16:30:00,13864 2014-10-07 17:00:00,17041 2014-10-07 17:30:00,20434 2014-10-07 18:00:00,23029 2014-10-07 18:30:00,23711 2014-10-07 19:00:00,24817 2014-10-07 19:30:00,24933 2014-10-07 20:00:00,24002 2014-10-07 20:30:00,23651 2014-10-07 21:00:00,23764 2014-10-07 21:30:00,23224 2014-10-07 22:00:00,22020 2014-10-07 22:30:00,22214 2014-10-07 23:00:00,21446 2014-10-07 23:30:00,15974 2014-10-08 00:00:00,12484 2014-10-08 00:30:00,9130 2014-10-08 01:00:00,6693 2014-10-08 01:30:00,5333 2014-10-08 02:00:00,3820 2014-10-08 02:30:00,3065 2014-10-08 03:00:00,2511 2014-10-08 03:30:00,2299 2014-10-08 04:00:00,2318 2014-10-08 04:30:00,2125 2014-10-08 05:00:00,2484 2014-10-08 05:30:00,4358 2014-10-08 06:00:00,6790 2014-10-08 06:30:00,11660 2014-10-08 07:00:00,15780 2014-10-08 07:30:00,19516 2014-10-08 08:00:00,20307 2014-10-08 08:30:00,19954 2014-10-08 09:00:00,18254 2014-10-08 09:30:00,18010 2014-10-08 10:00:00,17206 2014-10-08 10:30:00,17213 2014-10-08 11:00:00,16691 2014-10-08 11:30:00,18259 2014-10-08 12:00:00,18151 2014-10-08 12:30:00,17555 2014-10-08 13:00:00,16944 2014-10-08 13:30:00,17728 2014-10-08 14:00:00,18074 2014-10-08 14:30:00,18993 2014-10-08 15:00:00,18695 2014-10-08 15:30:00,17191 2014-10-08 16:00:00,15023 2014-10-08 16:30:00,14164 2014-10-08 17:00:00,17004 2014-10-08 17:30:00,20361 2014-10-08 18:00:00,23633 2014-10-08 18:30:00,24661 2014-10-08 19:00:00,25754 2014-10-08 19:30:00,25671 2014-10-08 20:00:00,25156 2014-10-08 20:30:00,24961 2014-10-08 21:00:00,24938 2014-10-08 21:30:00,24851 2014-10-08 22:00:00,24683 2014-10-08 22:30:00,23411 2014-10-08 23:00:00,20599 2014-10-08 23:30:00,17147 2014-10-09 00:00:00,13602 2014-10-09 00:30:00,10452 2014-10-09 01:00:00,7836 2014-10-09 01:30:00,6040 2014-10-09 02:00:00,4981 2014-10-09 02:30:00,3613 2014-10-09 03:00:00,2923 2014-10-09 03:30:00,2632 2014-10-09 04:00:00,2912 2014-10-09 04:30:00,2577 2014-10-09 05:00:00,2921 2014-10-09 05:30:00,4679 2014-10-09 06:00:00,6693 2014-10-09 06:30:00,12140 2014-10-09 07:00:00,15534 2014-10-09 07:30:00,19974 2014-10-09 08:00:00,20533 2014-10-09 08:30:00,19988 2014-10-09 09:00:00,19239 2014-10-09 09:30:00,18788 2014-10-09 10:00:00,17934 2014-10-09 10:30:00,18048 2014-10-09 11:00:00,17415 2014-10-09 11:30:00,18292 2014-10-09 12:00:00,18506 2014-10-09 12:30:00,18180 2014-10-09 13:00:00,17401 2014-10-09 13:30:00,18973 2014-10-09 14:00:00,19361 2014-10-09 14:30:00,19722 2014-10-09 15:00:00,19572 2014-10-09 15:30:00,17500 2014-10-09 16:00:00,15213 2014-10-09 16:30:00,14457 2014-10-09 17:00:00,17736 2014-10-09 17:30:00,21319 2014-10-09 18:00:00,23270 2014-10-09 18:30:00,24892 2014-10-09 19:00:00,26555 2014-10-09 19:30:00,26743 2014-10-09 20:00:00,26376 2014-10-09 20:30:00,26311 2014-10-09 21:00:00,26179 2014-10-09 21:30:00,26774 2014-10-09 22:00:00,26449 2014-10-09 22:30:00,25459 2014-10-09 23:00:00,23927 2014-10-09 23:30:00,21851 2014-10-10 00:00:00,18756 2014-10-10 00:30:00,14990 2014-10-10 01:00:00,13865 2014-10-10 01:30:00,10263 2014-10-10 02:00:00,7873 2014-10-10 02:30:00,6480 2014-10-10 03:00:00,5094 2014-10-10 03:30:00,4217 2014-10-10 04:00:00,4289 2014-10-10 04:30:00,3640 2014-10-10 05:00:00,3376 2014-10-10 05:30:00,5145 2014-10-10 06:00:00,7144 2014-10-10 06:30:00,11739 2014-10-10 07:00:00,15197 2014-10-10 07:30:00,19716 2014-10-10 08:00:00,20851 2014-10-10 08:30:00,20463 2014-10-10 09:00:00,19658 2014-10-10 09:30:00,19287 2014-10-10 10:00:00,17986 2014-10-10 10:30:00,17776 2014-10-10 11:00:00,17735 2014-10-10 11:30:00,18716 2014-10-10 12:00:00,19032 2014-10-10 12:30:00,17702 2014-10-10 13:00:00,17023 2014-10-10 13:30:00,18352 2014-10-10 14:00:00,19791 2014-10-10 14:30:00,20131 2014-10-10 15:00:00,18645 2014-10-10 15:30:00,16572 2014-10-10 16:00:00,14736 2014-10-10 16:30:00,13731 2014-10-10 17:00:00,17166 2014-10-10 17:30:00,20392 2014-10-10 18:00:00,22838 2014-10-10 18:30:00,23791 2014-10-10 19:00:00,25914 2014-10-10 19:30:00,26355 2014-10-10 20:00:00,25656 2014-10-10 20:30:00,25449 2014-10-10 21:00:00,25448 2014-10-10 21:30:00,25823 2014-10-10 22:00:00,25813 2014-10-10 22:30:00,26407 2014-10-10 23:00:00,26898 2014-10-10 23:30:00,26587 2014-10-11 00:00:00,25257 2014-10-11 00:30:00,23717 2014-10-11 01:00:00,22541 2014-10-11 01:30:00,19773 2014-10-11 02:00:00,19652 2014-10-11 02:30:00,16294 2014-10-11 03:00:00,13968 2014-10-11 03:30:00,12000 2014-10-11 04:00:00,10432 2014-10-11 04:30:00,6402 2014-10-11 05:00:00,4443 2014-10-11 05:30:00,3481 2014-10-11 06:00:00,3971 2014-10-11 06:30:00,5191 2014-10-11 07:00:00,6434 2014-10-11 07:30:00,8435 2014-10-11 08:00:00,10255 2014-10-11 08:30:00,13847 2014-10-11 09:00:00,14970 2014-10-11 09:30:00,18403 2014-10-11 10:00:00,19338 2014-10-11 10:30:00,21107 2014-10-11 11:00:00,20821 2014-10-11 11:30:00,21854 2014-10-11 12:00:00,21813 2014-10-11 12:30:00,22250 2014-10-11 13:00:00,21450 2014-10-11 13:30:00,21271 2014-10-11 14:00:00,20595 2014-10-11 14:30:00,20863 2014-10-11 15:00:00,20262 2014-10-11 15:30:00,21024 2014-10-11 16:00:00,19141 2014-10-11 16:30:00,17903 2014-10-11 17:00:00,19903 2014-10-11 17:30:00,22820 2014-10-11 18:00:00,24243 2014-10-11 18:30:00,25880 2014-10-11 19:00:00,26756 2014-10-11 19:30:00,26593 2014-10-11 20:00:00,25248 2014-10-11 20:30:00,23934 2014-10-11 21:00:00,23401 2014-10-11 21:30:00,24145 2014-10-11 22:00:00,25308 2014-10-11 22:30:00,26284 2014-10-11 23:00:00,27136 2014-10-11 23:30:00,27099 2014-10-12 00:00:00,26610 2014-10-12 00:30:00,25400 2014-10-12 01:00:00,23992 2014-10-12 01:30:00,22359 2014-10-12 02:00:00,21054 2014-10-12 02:30:00,18812 2014-10-12 03:00:00,16584 2014-10-12 03:30:00,14204 2014-10-12 04:00:00,11990 2014-10-12 04:30:00,7092 2014-10-12 05:00:00,4311 2014-10-12 05:30:00,3844 2014-10-12 06:00:00,3796 2014-10-12 06:30:00,4755 2014-10-12 07:00:00,4491 2014-10-12 07:30:00,5559 2014-10-12 08:00:00,6959 2014-10-12 08:30:00,9127 2014-10-12 09:00:00,11015 2014-10-12 09:30:00,13961 2014-10-12 10:00:00,15445 2014-10-12 10:30:00,17923 2014-10-12 11:00:00,18438 2014-10-12 11:30:00,19592 2014-10-12 12:00:00,19733 2014-10-12 12:30:00,19766 2014-10-12 13:00:00,19809 2014-10-12 13:30:00,19242 2014-10-12 14:00:00,18990 2014-10-12 14:30:00,18676 2014-10-12 15:00:00,18037 2014-10-12 15:30:00,16660 2014-10-12 16:00:00,15948 2014-10-12 16:30:00,15261 2014-10-12 17:00:00,17141 2014-10-12 17:30:00,19085 2014-10-12 18:00:00,20188 2014-10-12 18:30:00,20512 2014-10-12 19:00:00,20723 2014-10-12 19:30:00,20415 2014-10-12 20:00:00,19483 2014-10-12 20:30:00,19008 2014-10-12 21:00:00,17958 2014-10-12 21:30:00,18341 2014-10-12 22:00:00,18181 2014-10-12 22:30:00,17069 2014-10-12 23:00:00,15057 2014-10-12 23:30:00,13867 2014-10-13 00:00:00,11544 2014-10-13 00:30:00,9016 2014-10-13 01:00:00,6739 2014-10-13 01:30:00,5420 2014-10-13 02:00:00,4584 2014-10-13 02:30:00,3787 2014-10-13 03:00:00,3018 2014-10-13 03:30:00,2667 2014-10-13 04:00:00,2981 2014-10-13 04:30:00,2756 2014-10-13 05:00:00,2712 2014-10-13 05:30:00,3798 2014-10-13 06:00:00,5117 2014-10-13 06:30:00,7727 2014-10-13 07:00:00,9655 2014-10-13 07:30:00,12109 2014-10-13 08:00:00,13484 2014-10-13 08:30:00,15506 2014-10-13 09:00:00,15325 2014-10-13 09:30:00,15924 2014-10-13 10:00:00,14830 2014-10-13 10:30:00,14907 2014-10-13 11:00:00,14796 2014-10-13 11:30:00,15699 2014-10-13 12:00:00,15705 2014-10-13 12:30:00,15880 2014-10-13 13:00:00,15693 2014-10-13 13:30:00,16643 2014-10-13 14:00:00,16929 2014-10-13 14:30:00,17698 2014-10-13 15:00:00,17429 2014-10-13 15:30:00,17248 2014-10-13 16:00:00,16219 2014-10-13 16:30:00,15918 2014-10-13 17:00:00,17780 2014-10-13 17:30:00,19414 2014-10-13 18:00:00,21594 2014-10-13 18:30:00,24915 2014-10-13 19:00:00,24556 2014-10-13 19:30:00,22341 2014-10-13 20:00:00,22343 2014-10-13 20:30:00,21619 2014-10-13 21:00:00,21315 2014-10-13 21:30:00,19821 2014-10-13 22:00:00,17669 2014-10-13 22:30:00,15504 2014-10-13 23:00:00,14525 2014-10-13 23:30:00,10738 2014-10-14 00:00:00,8908 2014-10-14 00:30:00,6593 2014-10-14 01:00:00,5560 2014-10-14 01:30:00,4014 2014-10-14 02:00:00,3046 2014-10-14 02:30:00,2349 2014-10-14 03:00:00,1876 2014-10-14 03:30:00,1691 2014-10-14 04:00:00,1941 2014-10-14 04:30:00,1850 2014-10-14 05:00:00,2318 2014-10-14 05:30:00,4337 2014-10-14 06:00:00,6669 2014-10-14 06:30:00,11585 2014-10-14 07:00:00,15170 2014-10-14 07:30:00,19136 2014-10-14 08:00:00,20085 2014-10-14 08:30:00,19758 2014-10-14 09:00:00,18842 2014-10-14 09:30:00,18530 2014-10-14 10:00:00,16617 2014-10-14 10:30:00,17458 2014-10-14 11:00:00,16359 2014-10-14 11:30:00,17483 2014-10-14 12:00:00,17600 2014-10-14 12:30:00,17552 2014-10-14 13:00:00,17058 2014-10-14 13:30:00,17658 2014-10-14 14:00:00,18319 2014-10-14 14:30:00,18818 2014-10-14 15:00:00,18735 2014-10-14 15:30:00,17254 2014-10-14 16:00:00,15022 2014-10-14 16:30:00,14365 2014-10-14 17:00:00,16300 2014-10-14 17:30:00,19687 2014-10-14 18:00:00,22620 2014-10-14 18:30:00,23309 2014-10-14 19:00:00,23636 2014-10-14 19:30:00,23752 2014-10-14 20:00:00,23095 2014-10-14 20:30:00,23108 2014-10-14 21:00:00,23221 2014-10-14 21:30:00,23581 2014-10-14 22:00:00,22249 2014-10-14 22:30:00,19533 2014-10-14 23:00:00,17226 2014-10-14 23:30:00,13935 2014-10-15 00:00:00,11429 2014-10-15 00:30:00,8486 2014-10-15 01:00:00,6484 2014-10-15 01:30:00,5093 2014-10-15 02:00:00,4018 2014-10-15 02:30:00,3218 2014-10-15 03:00:00,2536 2014-10-15 03:30:00,2219 2014-10-15 04:00:00,2171 2014-10-15 04:30:00,2268 2014-10-15 05:00:00,2437 2014-10-15 05:30:00,4569 2014-10-15 06:00:00,6862 2014-10-15 06:30:00,11924 2014-10-15 07:00:00,15860 2014-10-15 07:30:00,19821 2014-10-15 08:00:00,20508 2014-10-15 08:30:00,20540 2014-10-15 09:00:00,19590 2014-10-15 09:30:00,18480 2014-10-15 10:00:00,17330 2014-10-15 10:30:00,18508 2014-10-15 11:00:00,17354 2014-10-15 11:30:00,18552 2014-10-15 12:00:00,18241 2014-10-15 12:30:00,18475 2014-10-15 13:00:00,17939 2014-10-15 13:30:00,18398 2014-10-15 14:00:00,18875 2014-10-15 14:30:00,19559 2014-10-15 15:00:00,19133 2014-10-15 15:30:00,16816 2014-10-15 16:00:00,14757 2014-10-15 16:30:00,14470 2014-10-15 17:00:00,17800 2014-10-15 17:30:00,21127 2014-10-15 18:00:00,22269 2014-10-15 18:30:00,22819 2014-10-15 19:00:00,23582 2014-10-15 19:30:00,26273 2014-10-15 20:00:00,25338 2014-10-15 20:30:00,24021 2014-10-15 21:00:00,26163 2014-10-15 21:30:00,23839 2014-10-15 22:00:00,22608 2014-10-15 22:30:00,24886 2014-10-15 23:00:00,20128 2014-10-15 23:30:00,16180 2014-10-16 00:00:00,13302 2014-10-16 00:30:00,10509 2014-10-16 01:00:00,8241 2014-10-16 01:30:00,5536 2014-10-16 02:00:00,4664 2014-10-16 02:30:00,3460 2014-10-16 03:00:00,2799 2014-10-16 03:30:00,2730 2014-10-16 04:00:00,2801 2014-10-16 04:30:00,2511 2014-10-16 05:00:00,2670 2014-10-16 05:30:00,4767 2014-10-16 06:00:00,7096 2014-10-16 06:30:00,12556 2014-10-16 07:00:00,16431 2014-10-16 07:30:00,21581 2014-10-16 08:00:00,21355 2014-10-16 08:30:00,21573 2014-10-16 09:00:00,20390 2014-10-16 09:30:00,20452 2014-10-16 10:00:00,19678 2014-10-16 10:30:00,18801 2014-10-16 11:00:00,17223 2014-10-16 11:30:00,18249 2014-10-16 12:00:00,17691 2014-10-16 12:30:00,17052 2014-10-16 13:00:00,16783 2014-10-16 13:30:00,18392 2014-10-16 14:00:00,18593 2014-10-16 14:30:00,19364 2014-10-16 15:00:00,19176 2014-10-16 15:30:00,16795 2014-10-16 16:00:00,15293 2014-10-16 16:30:00,14922 2014-10-16 17:00:00,17899 2014-10-16 17:30:00,21758 2014-10-16 18:00:00,24169 2014-10-16 18:30:00,24615 2014-10-16 19:00:00,26370 2014-10-16 19:30:00,26990 2014-10-16 20:00:00,26168 2014-10-16 20:30:00,25449 2014-10-16 21:00:00,25994 2014-10-16 21:30:00,27115 2014-10-16 22:00:00,26191 2014-10-16 22:30:00,25146 2014-10-16 23:00:00,24371 2014-10-16 23:30:00,23771 2014-10-17 00:00:00,19268 2014-10-17 00:30:00,15623 2014-10-17 01:00:00,12595 2014-10-17 01:30:00,10224 2014-10-17 02:00:00,7941 2014-10-17 02:30:00,6678 2014-10-17 03:00:00,5182 2014-10-17 03:30:00,4502 2014-10-17 04:00:00,4316 2014-10-17 04:30:00,3512 2014-10-17 05:00:00,3174 2014-10-17 05:30:00,4771 2014-10-17 06:00:00,6557 2014-10-17 06:30:00,11929 2014-10-17 07:00:00,14950 2014-10-17 07:30:00,19835 2014-10-17 08:00:00,20149 2014-10-17 08:30:00,19998 2014-10-17 09:00:00,19310 2014-10-17 09:30:00,18601 2014-10-17 10:00:00,17567 2014-10-17 10:30:00,17890 2014-10-17 11:00:00,17470 2014-10-17 11:30:00,18557 2014-10-17 12:00:00,18944 2014-10-17 12:30:00,17922 2014-10-17 13:00:00,17627 2014-10-17 13:30:00,18361 2014-10-17 14:00:00,19557 2014-10-17 14:30:00,19811 2014-10-17 15:00:00,19277 2014-10-17 15:30:00,16741 2014-10-17 16:00:00,14948 2014-10-17 16:30:00,14244 2014-10-17 17:00:00,17563 2014-10-17 17:30:00,21246 2014-10-17 18:00:00,23115 2014-10-17 18:30:00,24785 2014-10-17 19:00:00,26396 2014-10-17 19:30:00,26837 2014-10-17 20:00:00,26621 2014-10-17 20:30:00,26144 2014-10-17 21:00:00,26019 2014-10-17 21:30:00,26816 2014-10-17 22:00:00,26701 2014-10-17 22:30:00,26519 2014-10-17 23:00:00,26740 2014-10-17 23:30:00,26173 2014-10-18 00:00:00,25059 2014-10-18 00:30:00,24437 2014-10-18 01:00:00,22718 2014-10-18 01:30:00,20700 2014-10-18 02:00:00,19623 2014-10-18 02:30:00,16675 2014-10-18 03:00:00,14447 2014-10-18 03:30:00,12377 2014-10-18 04:00:00,10609 2014-10-18 04:30:00,6436 2014-10-18 05:00:00,4562 2014-10-18 05:30:00,3783 2014-10-18 06:00:00,3923 2014-10-18 06:30:00,5060 2014-10-18 07:00:00,5992 2014-10-18 07:30:00,8639 2014-10-18 08:00:00,10309 2014-10-18 08:30:00,13563 2014-10-18 09:00:00,14136 2014-10-18 09:30:00,16945 2014-10-18 10:00:00,17004 2014-10-18 10:30:00,19045 2014-10-18 11:00:00,19859 2014-10-18 11:30:00,21198 2014-10-18 12:00:00,21550 2014-10-18 12:30:00,21583 2014-10-18 13:00:00,21455 2014-10-18 13:30:00,21869 2014-10-18 14:00:00,21426 2014-10-18 14:30:00,21650 2014-10-18 15:00:00,21611 2014-10-18 15:30:00,20904 2014-10-18 16:00:00,18820 2014-10-18 16:30:00,17255 2014-10-18 17:00:00,19029 2014-10-18 17:30:00,22812 2014-10-18 18:00:00,24455 2014-10-18 18:30:00,26373 2014-10-18 19:00:00,27460 2014-10-18 19:30:00,27222 2014-10-18 20:00:00,25204 2014-10-18 20:30:00,24329 2014-10-18 21:00:00,24526 2014-10-18 21:30:00,25203 2014-10-18 22:00:00,25975 2014-10-18 22:30:00,27073 2014-10-18 23:00:00,27881 2014-10-18 23:30:00,28626 2014-10-19 00:00:00,28093 2014-10-19 00:30:00,26200 2014-10-19 01:00:00,25610 2014-10-19 01:30:00,23483 2014-10-19 02:00:00,21850 2014-10-19 02:30:00,19297 2014-10-19 03:00:00,16574 2014-10-19 03:30:00,14355 2014-10-19 04:00:00,12112 2014-10-19 04:30:00,7284 2014-10-19 05:00:00,4845 2014-10-19 05:30:00,3667 2014-10-19 06:00:00,3718 2014-10-19 06:30:00,4573 2014-10-19 07:00:00,5167 2014-10-19 07:30:00,6844 2014-10-19 08:00:00,7279 2014-10-19 08:30:00,9761 2014-10-19 09:00:00,11712 2014-10-19 09:30:00,14210 2014-10-19 10:00:00,15394 2014-10-19 10:30:00,18387 2014-10-19 11:00:00,19168 2014-10-19 11:30:00,20891 2014-10-19 12:00:00,21806 2014-10-19 12:30:00,22188 2014-10-19 13:00:00,22153 2014-10-19 13:30:00,21713 2014-10-19 14:00:00,21838 2014-10-19 14:30:00,21082 2014-10-19 15:00:00,20448 2014-10-19 15:30:00,20113 2014-10-19 16:00:00,18645 2014-10-19 16:30:00,17210 2014-10-19 17:00:00,18326 2014-10-19 17:30:00,20498 2014-10-19 18:00:00,20924 2014-10-19 18:30:00,21579 2014-10-19 19:00:00,22026 2014-10-19 19:30:00,22197 2014-10-19 20:00:00,19709 2014-10-19 20:30:00,18780 2014-10-19 21:00:00,18060 2014-10-19 21:30:00,17973 2014-10-19 22:00:00,16572 2014-10-19 22:30:00,14957 2014-10-19 23:00:00,12461 2014-10-19 23:30:00,10448 2014-10-20 00:00:00,8295 2014-10-20 00:30:00,6837 2014-10-20 01:00:00,4747 2014-10-20 01:30:00,3283 2014-10-20 02:00:00,2904 2014-10-20 02:30:00,2345 2014-10-20 03:00:00,1917 2014-10-20 03:30:00,1783 2014-10-20 04:00:00,2174 2014-10-20 04:30:00,2157 2014-10-20 05:00:00,2989 2014-10-20 05:30:00,4841 2014-10-20 06:00:00,7228 2014-10-20 06:30:00,11726 2014-10-20 07:00:00,14557 2014-10-20 07:30:00,17848 2014-10-20 08:00:00,18436 2014-10-20 08:30:00,18059 2014-10-20 09:00:00,18028 2014-10-20 09:30:00,17353 2014-10-20 10:00:00,16350 2014-10-20 10:30:00,16376 2014-10-20 11:00:00,16099 2014-10-20 11:30:00,16817 2014-10-20 12:00:00,16898 2014-10-20 12:30:00,16809 2014-10-20 13:00:00,16199 2014-10-20 13:30:00,16758 2014-10-20 14:00:00,17679 2014-10-20 14:30:00,18148 2014-10-20 15:00:00,18644 2014-10-20 15:30:00,17183 2014-10-20 16:00:00,16196 2014-10-20 16:30:00,15534 2014-10-20 17:00:00,18451 2014-10-20 17:30:00,20950 2014-10-20 18:00:00,23192 2014-10-20 18:30:00,24655 2014-10-20 19:00:00,24094 2014-10-20 19:30:00,23285 2014-10-20 20:00:00,22083 2014-10-20 20:30:00,21485 2014-10-20 21:00:00,21579 2014-10-20 21:30:00,21118 2014-10-20 22:00:00,20204 2014-10-20 22:30:00,16909 2014-10-20 23:00:00,13785 2014-10-20 23:30:00,11695 2014-10-21 00:00:00,9214 2014-10-21 00:30:00,6931 2014-10-21 01:00:00,5413 2014-10-21 01:30:00,4130 2014-10-21 02:00:00,3276 2014-10-21 02:30:00,2475 2014-10-21 03:00:00,2080 2014-10-21 03:30:00,1917 2014-10-21 04:00:00,2123 2014-10-21 04:30:00,1984 2014-10-21 05:00:00,2458 2014-10-21 05:30:00,4338 2014-10-21 06:00:00,6470 2014-10-21 06:30:00,11775 2014-10-21 07:00:00,15088 2014-10-21 07:30:00,19429 2014-10-21 08:00:00,20482 2014-10-21 08:30:00,19886 2014-10-21 09:00:00,19170 2014-10-21 09:30:00,18277 2014-10-21 10:00:00,17064 2014-10-21 10:30:00,16386 2014-10-21 11:00:00,16633 2014-10-21 11:30:00,17681 2014-10-21 12:00:00,18233 2014-10-21 12:30:00,17996 2014-10-21 13:00:00,16695 2014-10-21 13:30:00,16912 2014-10-21 14:00:00,18124 2014-10-21 14:30:00,18411 2014-10-21 15:00:00,19013 2014-10-21 15:30:00,17590 2014-10-21 16:00:00,15673 2014-10-21 16:30:00,14923 2014-10-21 17:00:00,17981 2014-10-21 17:30:00,21208 2014-10-21 18:00:00,23458 2014-10-21 18:30:00,24028 2014-10-21 19:00:00,24934 2014-10-21 19:30:00,25135 2014-10-21 20:00:00,24613 2014-10-21 20:30:00,24617 2014-10-21 21:00:00,25841 2014-10-21 21:30:00,24141 2014-10-21 22:00:00,23069 2014-10-21 22:30:00,21243 2014-10-21 23:00:00,18077 2014-10-21 23:30:00,15745 2014-10-22 00:00:00,12115 2014-10-22 00:30:00,9035 2014-10-22 01:00:00,7015 2014-10-22 01:30:00,5113 2014-10-22 02:00:00,4220 2014-10-22 02:30:00,3331 2014-10-22 03:00:00,2870 2014-10-22 03:30:00,2516 2014-10-22 04:00:00,2656 2014-10-22 04:30:00,2336 2014-10-22 05:00:00,2494 2014-10-22 05:30:00,5081 2014-10-22 06:00:00,8091 2014-10-22 06:30:00,13037 2014-10-22 07:00:00,16579 2014-10-22 07:30:00,19657 2014-10-22 08:00:00,20914 2014-10-22 08:30:00,20612 2014-10-22 09:00:00,20015 2014-10-22 09:30:00,19001 2014-10-22 10:00:00,17533 2014-10-22 10:30:00,17877 2014-10-22 11:00:00,16470 2014-10-22 11:30:00,18266 2014-10-22 12:00:00,17992 2014-10-22 12:30:00,17419 2014-10-22 13:00:00,16775 2014-10-22 13:30:00,17378 2014-10-22 14:00:00,18067 2014-10-22 14:30:00,19841 2014-10-22 15:00:00,18552 2014-10-22 15:30:00,16825 2014-10-22 16:00:00,14712 2014-10-22 16:30:00,14439 2014-10-22 17:00:00,17305 2014-10-22 17:30:00,20949 2014-10-22 18:00:00,22182 2014-10-22 18:30:00,23886 2014-10-22 19:00:00,25234 2014-10-22 19:30:00,24731 2014-10-22 20:00:00,25195 2014-10-22 20:30:00,25551 2014-10-22 21:00:00,26110 2014-10-22 21:30:00,24842 2014-10-22 22:00:00,23178 2014-10-22 22:30:00,23408 2014-10-22 23:00:00,21749 2014-10-22 23:30:00,17918 2014-10-23 00:00:00,13496 2014-10-23 00:30:00,10416 2014-10-23 01:00:00,8090 2014-10-23 01:30:00,5946 2014-10-23 02:00:00,4330 2014-10-23 02:30:00,3282 2014-10-23 03:00:00,2732 2014-10-23 03:30:00,2524 2014-10-23 04:00:00,2700 2014-10-23 04:30:00,2290 2014-10-23 05:00:00,2743 2014-10-23 05:30:00,4732 2014-10-23 06:00:00,7570 2014-10-23 06:30:00,12751 2014-10-23 07:00:00,16887 2014-10-23 07:30:00,20268 2014-10-23 08:00:00,21992 2014-10-23 08:30:00,21301 2014-10-23 09:00:00,20526 2014-10-23 09:30:00,19251 2014-10-23 10:00:00,18228 2014-10-23 10:30:00,18603 2014-10-23 11:00:00,18762 2014-10-23 11:30:00,19645 2014-10-23 12:00:00,20453 2014-10-23 12:30:00,19400 2014-10-23 13:00:00,18448 2014-10-23 13:30:00,18199 2014-10-23 14:00:00,18845 2014-10-23 14:30:00,18973 2014-10-23 15:00:00,17968 2014-10-23 15:30:00,15112 2014-10-23 16:00:00,13580 2014-10-23 16:30:00,12751 2014-10-23 17:00:00,15901 2014-10-23 17:30:00,19774 2014-10-23 18:00:00,21960 2014-10-23 18:30:00,23790 2014-10-23 19:00:00,24998 2014-10-23 19:30:00,25414 2014-10-23 20:00:00,26075 2014-10-23 20:30:00,25616 2014-10-23 21:00:00,25916 2014-10-23 21:30:00,25589 2014-10-23 22:00:00,25041 2014-10-23 22:30:00,24891 2014-10-23 23:00:00,23888 2014-10-23 23:30:00,22464 2014-10-24 00:00:00,19061 2014-10-24 00:30:00,16689 2014-10-24 01:00:00,13006 2014-10-24 01:30:00,9512 2014-10-24 02:00:00,7745 2014-10-24 02:30:00,6037 2014-10-24 03:00:00,5194 2014-10-24 03:30:00,4419 2014-10-24 04:00:00,4267 2014-10-24 04:30:00,3366 2014-10-24 05:00:00,3096 2014-10-24 05:30:00,4532 2014-10-24 06:00:00,6877 2014-10-24 06:30:00,11826 2014-10-24 07:00:00,15333 2014-10-24 07:30:00,19013 2014-10-24 08:00:00,20131 2014-10-24 08:30:00,19779 2014-10-24 09:00:00,19227 2014-10-24 09:30:00,18824 2014-10-24 10:00:00,17705 2014-10-24 10:30:00,18111 2014-10-24 11:00:00,17408 2014-10-24 11:30:00,18509 2014-10-24 12:00:00,18510 2014-10-24 12:30:00,17910 2014-10-24 13:00:00,17690 2014-10-24 13:30:00,18149 2014-10-24 14:00:00,19632 2014-10-24 14:30:00,19426 2014-10-24 15:00:00,18760 2014-10-24 15:30:00,16379 2014-10-24 16:00:00,15083 2014-10-24 16:30:00,14553 2014-10-24 17:00:00,17509 2014-10-24 17:30:00,20911 2014-10-24 18:00:00,22958 2014-10-24 18:30:00,25257 2014-10-24 19:00:00,26659 2014-10-24 19:30:00,27104 2014-10-24 20:00:00,26439 2014-10-24 20:30:00,25840 2014-10-24 21:00:00,25694 2014-10-24 21:30:00,26093 2014-10-24 22:00:00,26821 2014-10-24 22:30:00,26870 2014-10-24 23:00:00,26889 2014-10-24 23:30:00,27283 2014-10-25 00:00:00,25739 2014-10-25 00:30:00,23889 2014-10-25 01:00:00,22278 2014-10-25 01:30:00,20337 2014-10-25 02:00:00,19179 2014-10-25 02:30:00,16566 2014-10-25 03:00:00,14146 2014-10-25 03:30:00,12015 2014-10-25 04:00:00,10285 2014-10-25 04:30:00,6316 2014-10-25 05:00:00,4106 2014-10-25 05:30:00,3465 2014-10-25 06:00:00,3657 2014-10-25 06:30:00,4756 2014-10-25 07:00:00,6003 2014-10-25 07:30:00,7853 2014-10-25 08:00:00,9091 2014-10-25 08:30:00,12209 2014-10-25 09:00:00,13433 2014-10-25 09:30:00,16768 2014-10-25 10:00:00,16390 2014-10-25 10:30:00,18666 2014-10-25 11:00:00,19740 2014-10-25 11:30:00,21266 2014-10-25 12:00:00,21452 2014-10-25 12:30:00,21613 2014-10-25 13:00:00,21773 2014-10-25 13:30:00,21440 2014-10-25 14:00:00,20362 2014-10-25 14:30:00,20601 2014-10-25 15:00:00,20989 2014-10-25 15:30:00,20210 2014-10-25 16:00:00,18243 2014-10-25 16:30:00,16875 2014-10-25 17:00:00,19078 2014-10-25 17:30:00,22244 2014-10-25 18:00:00,23703 2014-10-25 18:30:00,25544 2014-10-25 19:00:00,27125 2014-10-25 19:30:00,26539 2014-10-25 20:00:00,24964 2014-10-25 20:30:00,23665 2014-10-25 21:00:00,23200 2014-10-25 21:30:00,24238 2014-10-25 22:00:00,25202 2014-10-25 22:30:00,26140 2014-10-25 23:00:00,27417 2014-10-25 23:30:00,27692 2014-10-26 00:00:00,26866 2014-10-26 00:30:00,26254 2014-10-26 01:00:00,24482 2014-10-26 01:30:00,22425 2014-10-26 02:00:00,20865 2014-10-26 02:30:00,18801 2014-10-26 03:00:00,16066 2014-10-26 03:30:00,14093 2014-10-26 04:00:00,11863 2014-10-26 04:30:00,7194 2014-10-26 05:00:00,4661 2014-10-26 05:30:00,3656 2014-10-26 06:00:00,3780 2014-10-26 06:30:00,4116 2014-10-26 07:00:00,4530 2014-10-26 07:30:00,6287 2014-10-26 08:00:00,7318 2014-10-26 08:30:00,9260 2014-10-26 09:00:00,10911 2014-10-26 09:30:00,14136 2014-10-26 10:00:00,15466 2014-10-26 10:30:00,18611 2014-10-26 11:00:00,18437 2014-10-26 11:30:00,20375 2014-10-26 12:00:00,20658 2014-10-26 12:30:00,21283 2014-10-26 13:00:00,20200 2014-10-26 13:30:00,20135 2014-10-26 14:00:00,20306 2014-10-26 14:30:00,20404 2014-10-26 15:00:00,19931 2014-10-26 15:30:00,19772 2014-10-26 16:00:00,18406 2014-10-26 16:30:00,16957 2014-10-26 17:00:00,17972 2014-10-26 17:30:00,19563 2014-10-26 18:00:00,20106 2014-10-26 18:30:00,20449 2014-10-26 19:00:00,19860 2014-10-26 19:30:00,19343 2014-10-26 20:00:00,18128 2014-10-26 20:30:00,17298 2014-10-26 21:00:00,16004 2014-10-26 21:30:00,16422 2014-10-26 22:00:00,14618 2014-10-26 22:30:00,13017 2014-10-26 23:00:00,11532 2014-10-26 23:30:00,10089 2014-10-27 00:00:00,8326 2014-10-27 00:30:00,6579 2014-10-27 01:00:00,4385 2014-10-27 01:30:00,3470 2014-10-27 02:00:00,2854 2014-10-27 02:30:00,2128 2014-10-27 03:00:00,1785 2014-10-27 03:30:00,1707 2014-10-27 04:00:00,2138 2014-10-27 04:30:00,2406 2014-10-27 05:00:00,2847 2014-10-27 05:30:00,4951 2014-10-27 06:00:00,7094 2014-10-27 06:30:00,11090 2014-10-27 07:00:00,14205 2014-10-27 07:30:00,17506 2014-10-27 08:00:00,18105 2014-10-27 08:30:00,17656 2014-10-27 09:00:00,17751 2014-10-27 09:30:00,17096 2014-10-27 10:00:00,15784 2014-10-27 10:30:00,16086 2014-10-27 11:00:00,14843 2014-10-27 11:30:00,16446 2014-10-27 12:00:00,16614 2014-10-27 12:30:00,16155 2014-10-27 13:00:00,15502 2014-10-27 13:30:00,16293 2014-10-27 14:00:00,16885 2014-10-27 14:30:00,17759 2014-10-27 15:00:00,18533 2014-10-27 15:30:00,17617 2014-10-27 16:00:00,16279 2014-10-27 16:30:00,15551 2014-10-27 17:00:00,18199 2014-10-27 17:30:00,20618 2014-10-27 18:00:00,22703 2014-10-27 18:30:00,23897 2014-10-27 19:00:00,24329 2014-10-27 19:30:00,23182 2014-10-27 20:00:00,21778 2014-10-27 20:30:00,21251 2014-10-27 21:00:00,21189 2014-10-27 21:30:00,20884 2014-10-27 22:00:00,19670 2014-10-27 22:30:00,18163 2014-10-27 23:00:00,15613 2014-10-27 23:30:00,13371 2014-10-28 00:00:00,10910 2014-10-28 00:30:00,7638 2014-10-28 01:00:00,5589 2014-10-28 01:30:00,4215 2014-10-28 02:00:00,3386 2014-10-28 02:30:00,2753 2014-10-28 03:00:00,2181 2014-10-28 03:30:00,2034 2014-10-28 04:00:00,2094 2014-10-28 04:30:00,1896 2014-10-28 05:00:00,2632 2014-10-28 05:30:00,4581 2014-10-28 06:00:00,6612 2014-10-28 06:30:00,11609 2014-10-28 07:00:00,15127 2014-10-28 07:30:00,19097 2014-10-28 08:00:00,19516 2014-10-28 08:30:00,19422 2014-10-28 09:00:00,18088 2014-10-28 09:30:00,17669 2014-10-28 10:00:00,16744 2014-10-28 10:30:00,17075 2014-10-28 11:00:00,16035 2014-10-28 11:30:00,17421 2014-10-28 12:00:00,17756 2014-10-28 12:30:00,17057 2014-10-28 13:00:00,16101 2014-10-28 13:30:00,17443 2014-10-28 14:00:00,17890 2014-10-28 14:30:00,18651 2014-10-28 15:00:00,18762 2014-10-28 15:30:00,17135 2014-10-28 16:00:00,15175 2014-10-28 16:30:00,13958 2014-10-28 17:00:00,16881 2014-10-28 17:30:00,19615 2014-10-28 18:00:00,22196 2014-10-28 18:30:00,22906 2014-10-28 19:00:00,23482 2014-10-28 19:30:00,23088 2014-10-28 20:00:00,23728 2014-10-28 20:30:00,23210 2014-10-28 21:00:00,23685 2014-10-28 21:30:00,23843 2014-10-28 22:00:00,22597 2014-10-28 22:30:00,20923 2014-10-28 23:00:00,19229 2014-10-28 23:30:00,15963 2014-10-29 00:00:00,12292 2014-10-29 00:30:00,9190 2014-10-29 01:00:00,6864 2014-10-29 01:30:00,5693 2014-10-29 02:00:00,4499 2014-10-29 02:30:00,3304 2014-10-29 03:00:00,2560 2014-10-29 03:30:00,2485 2014-10-29 04:00:00,2560 2014-10-29 04:30:00,2248 2014-10-29 05:00:00,2389 2014-10-29 05:30:00,4313 2014-10-29 06:00:00,6649 2014-10-29 06:30:00,11289 2014-10-29 07:00:00,15103 2014-10-29 07:30:00,19437 2014-10-29 08:00:00,19443 2014-10-29 08:30:00,19707 2014-10-29 09:00:00,18912 2014-10-29 09:30:00,18203 2014-10-29 10:00:00,16492 2014-10-29 10:30:00,16837 2014-10-29 11:00:00,16075 2014-10-29 11:30:00,17160 2014-10-29 12:00:00,17606 2014-10-29 12:30:00,17267 2014-10-29 13:00:00,16875 2014-10-29 13:30:00,17940 2014-10-29 14:00:00,18339 2014-10-29 14:30:00,18971 2014-10-29 15:00:00,19298 2014-10-29 15:30:00,16665 2014-10-29 16:00:00,15008 2014-10-29 16:30:00,13873 2014-10-29 17:00:00,17894 2014-10-29 17:30:00,21574 2014-10-29 18:00:00,22116 2014-10-29 18:30:00,23582 2014-10-29 19:00:00,25553 2014-10-29 19:30:00,25299 2014-10-29 20:00:00,24778 2014-10-29 20:30:00,24729 2014-10-29 21:00:00,24907 2014-10-29 21:30:00,24810 2014-10-29 22:00:00,24246 2014-10-29 22:30:00,23250 2014-10-29 23:00:00,20700 2014-10-29 23:30:00,18631 2014-10-30 00:00:00,14048 2014-10-30 00:30:00,10691 2014-10-30 01:00:00,8363 2014-10-30 01:30:00,6405 2014-10-30 02:00:00,5251 2014-10-30 02:30:00,3714 2014-10-30 03:00:00,3232 2014-10-30 03:30:00,3057 2014-10-30 04:00:00,3005 2014-10-30 04:30:00,2506 2014-10-30 05:00:00,2821 2014-10-30 05:30:00,5287 2014-10-30 06:00:00,7427 2014-10-30 06:30:00,12248 2014-10-30 07:00:00,15618 2014-10-30 07:30:00,19528 2014-10-30 08:00:00,19813 2014-10-30 08:30:00,19680 2014-10-30 09:00:00,19351 2014-10-30 09:30:00,18967 2014-10-30 10:00:00,17899 2014-10-30 10:30:00,17994 2014-10-30 11:00:00,17167 2014-10-30 11:30:00,18094 2014-10-30 12:00:00,18575 2014-10-30 12:30:00,18022 2014-10-30 13:00:00,17359 2014-10-30 13:30:00,18035 2014-10-30 14:00:00,18733 2014-10-30 14:30:00,19410 2014-10-30 15:00:00,18991 2014-10-30 15:30:00,16749 2014-10-30 16:00:00,14604 2014-10-30 16:30:00,13367 2014-10-30 17:00:00,16382 2014-10-30 17:30:00,19879 2014-10-30 18:00:00,21735 2014-10-30 18:30:00,23802 2014-10-30 19:00:00,24832 2014-10-30 19:30:00,24964 2014-10-30 20:00:00,25791 2014-10-30 20:30:00,25810 2014-10-30 21:00:00,25816 2014-10-30 21:30:00,25849 2014-10-30 22:00:00,24877 2014-10-30 22:30:00,25072 2014-10-30 23:00:00,24763 2014-10-30 23:30:00,22241 2014-10-31 00:00:00,19957 2014-10-31 00:30:00,16881 2014-10-31 01:00:00,13588 2014-10-31 01:30:00,10958 2014-10-31 02:00:00,9119 2014-10-31 02:30:00,7589 2014-10-31 03:00:00,6221 2014-10-31 03:30:00,4936 2014-10-31 04:00:00,4796 2014-10-31 04:30:00,3555 2014-10-31 05:00:00,3337 2014-10-31 05:30:00,4665 2014-10-31 06:00:00,7084 2014-10-31 06:30:00,11681 2014-10-31 07:00:00,14822 2014-10-31 07:30:00,19004 2014-10-31 08:00:00,20306 2014-10-31 08:30:00,20687 2014-10-31 09:00:00,19585 2014-10-31 09:30:00,18702 2014-10-31 10:00:00,18099 2014-10-31 10:30:00,18335 2014-10-31 11:00:00,17653 2014-10-31 11:30:00,18889 2014-10-31 12:00:00,19146 2014-10-31 12:30:00,18833 2014-10-31 13:00:00,18315 2014-10-31 13:30:00,18917 2014-10-31 14:00:00,20430 2014-10-31 14:30:00,20608 2014-10-31 15:00:00,19915 2014-10-31 15:30:00,16981 2014-10-31 16:00:00,15045 2014-10-31 16:30:00,13978 2014-10-31 17:00:00,16891 2014-10-31 17:30:00,20025 2014-10-31 18:00:00,21438 2014-10-31 18:30:00,23813 2014-10-31 19:00:00,25517 2014-10-31 19:30:00,25493 2014-10-31 20:00:00,25475 2014-10-31 20:30:00,26996 2014-10-31 21:00:00,27015 2014-10-31 21:30:00,27264 2014-10-31 22:00:00,26977 2014-10-31 22:30:00,26343 2014-10-31 23:00:00,26333 2014-10-31 23:30:00,26524 2014-11-01 00:00:00,25425 2014-11-01 00:30:00,24937 2014-11-01 01:00:00,24946 2014-11-01 01:30:00,23736 2014-11-01 02:00:00,23245 2014-11-01 02:30:00,21459 2014-11-01 03:00:00,19849 2014-11-01 03:30:00,17679 2014-11-01 04:00:00,15018 2014-11-01 04:30:00,10600 2014-11-01 05:00:00,7758 2014-11-01 05:30:00,5907 2014-11-01 06:00:00,5743 2014-11-01 06:30:00,6223 2014-11-01 07:00:00,6386 2014-11-01 07:30:00,9098 2014-11-01 08:00:00,9864 2014-11-01 08:30:00,12903 2014-11-01 09:00:00,14185 2014-11-01 09:30:00,18584 2014-11-01 10:00:00,19066 2014-11-01 10:30:00,22683 2014-11-01 11:00:00,23292 2014-11-01 11:30:00,24154 2014-11-01 12:00:00,25310 2014-11-01 12:30:00,26625 2014-11-01 13:00:00,25584 2014-11-01 13:30:00,25115 2014-11-01 14:00:00,23935 2014-11-01 14:30:00,23341 2014-11-01 15:00:00,23337 2014-11-01 15:30:00,22199 2014-11-01 16:00:00,20008 2014-11-01 16:30:00,18443 2014-11-01 17:00:00,20865 2014-11-01 17:30:00,23719 2014-11-01 18:00:00,25241 2014-11-01 18:30:00,27383 2014-11-01 19:00:00,28398 2014-11-01 19:30:00,27426 2014-11-01 20:00:00,26537 2014-11-01 20:30:00,25980 2014-11-01 21:00:00,24601 2014-11-01 21:30:00,24838 2014-11-01 22:00:00,26372 2014-11-01 22:30:00,26567 2014-11-01 23:00:00,25879 2014-11-01 23:30:00,26125 2014-11-02 00:00:00,25110 2014-11-02 00:30:00,23109 2014-11-02 01:00:00,39197 2014-11-02 01:30:00,35212 2014-11-02 02:00:00,13259 2014-11-02 02:30:00,12250 2014-11-02 03:00:00,10013 2014-11-02 03:30:00,7898 2014-11-02 04:00:00,6375 2014-11-02 04:30:00,4532 2014-11-02 05:00:00,5116 2014-11-02 05:30:00,5232 2014-11-02 06:00:00,4542 2014-11-02 06:30:00,5298 2014-11-02 07:00:00,5155 2014-11-02 07:30:00,6029 2014-11-02 08:00:00,6280 2014-11-02 08:30:00,8771 2014-11-02 09:00:00,10151 2014-11-02 09:30:00,12501 2014-11-02 10:00:00,13990 2014-11-02 10:30:00,16534 2014-11-02 11:00:00,17133 2014-11-02 11:30:00,18775 2014-11-02 12:00:00,18985 2014-11-02 12:30:00,19911 2014-11-02 13:00:00,19123 2014-11-02 13:30:00,19524 2014-11-02 14:00:00,19640 2014-11-02 14:30:00,18364 2014-11-02 15:00:00,17940 2014-11-02 15:30:00,17949 2014-11-02 16:00:00,17288 2014-11-02 16:30:00,16326 2014-11-02 17:00:00,17522 2014-11-02 17:30:00,19243 2014-11-02 18:00:00,20291 2014-11-02 18:30:00,21649 2014-11-02 19:00:00,22839 2014-11-02 19:30:00,21772 2014-11-02 20:00:00,20994 2014-11-02 20:30:00,19774 2014-11-02 21:00:00,18398 2014-11-02 21:30:00,17764 2014-11-02 22:00:00,17334 2014-11-02 22:30:00,15431 2014-11-02 23:00:00,12958 2014-11-02 23:30:00,10224 2014-11-03 00:00:00,8771 2014-11-03 00:30:00,6045 2014-11-03 01:00:00,4413 2014-11-03 01:30:00,3235 2014-11-03 02:00:00,2688 2014-11-03 02:30:00,1983 2014-11-03 03:00:00,1756 2014-11-03 03:30:00,1683 2014-11-03 04:00:00,2140 2014-11-03 04:30:00,2288 2014-11-03 05:00:00,2948 2014-11-03 05:30:00,4813 2014-11-03 06:00:00,8044 2014-11-03 06:30:00,12885 2014-11-03 07:00:00,14627 2014-11-03 07:30:00,18111 2014-11-03 08:00:00,18266 2014-11-03 08:30:00,18384 2014-11-03 09:00:00,18104 2014-11-03 09:30:00,17357 2014-11-03 10:00:00,16008 2014-11-03 10:30:00,16379 2014-11-03 11:00:00,15351 2014-11-03 11:30:00,16770 2014-11-03 12:00:00,16711 2014-11-03 12:30:00,17011 2014-11-03 13:00:00,16373 2014-11-03 13:30:00,17097 2014-11-03 14:00:00,17364 2014-11-03 14:30:00,18333 2014-11-03 15:00:00,18428 2014-11-03 15:30:00,16974 2014-11-03 16:00:00,16139 2014-11-03 16:30:00,15205 2014-11-03 17:00:00,17392 2014-11-03 17:30:00,20141 2014-11-03 18:00:00,22581 2014-11-03 18:30:00,23098 2014-11-03 19:00:00,23154 2014-11-03 19:30:00,22688 2014-11-03 20:00:00,22047 2014-11-03 20:30:00,21283 2014-11-03 21:00:00,21070 2014-11-03 21:30:00,19910 2014-11-03 22:00:00,20541 2014-11-03 22:30:00,18105 2014-11-03 23:00:00,14554 2014-11-03 23:30:00,12695 2014-11-04 00:00:00,10667 2014-11-04 00:30:00,8479 2014-11-04 01:00:00,6005 2014-11-04 01:30:00,3899 2014-11-04 02:00:00,3111 2014-11-04 02:30:00,2526 2014-11-04 03:00:00,2112 2014-11-04 03:30:00,1885 2014-11-04 04:00:00,1921 2014-11-04 04:30:00,2267 2014-11-04 05:00:00,2413 2014-11-04 05:30:00,4413 2014-11-04 06:00:00,7168 2014-11-04 06:30:00,12160 2014-11-04 07:00:00,14845 2014-11-04 07:30:00,18403 2014-11-04 08:00:00,18445 2014-11-04 08:30:00,19018 2014-11-04 09:00:00,18105 2014-11-04 09:30:00,17459 2014-11-04 10:00:00,16381 2014-11-04 10:30:00,16623 2014-11-04 11:00:00,16144 2014-11-04 11:30:00,17318 2014-11-04 12:00:00,17658 2014-11-04 12:30:00,17108 2014-11-04 13:00:00,16178 2014-11-04 13:30:00,17973 2014-11-04 14:00:00,18152 2014-11-04 14:30:00,18445 2014-11-04 15:00:00,18556 2014-11-04 15:30:00,16865 2014-11-04 16:00:00,14505 2014-11-04 16:30:00,13471 2014-11-04 17:00:00,15853 2014-11-04 17:30:00,18369 2014-11-04 18:00:00,20968 2014-11-04 18:30:00,22239 2014-11-04 19:00:00,22626 2014-11-04 19:30:00,22924 2014-11-04 20:00:00,22853 2014-11-04 20:30:00,22393 2014-11-04 21:00:00,23088 2014-11-04 21:30:00,22431 2014-11-04 22:00:00,22239 2014-11-04 22:30:00,19918 2014-11-04 23:00:00,17675 2014-11-04 23:30:00,14953 2014-11-05 00:00:00,12025 2014-11-05 00:30:00,8767 2014-11-05 01:00:00,6670 2014-11-05 01:30:00,5197 2014-11-05 02:00:00,4289 2014-11-05 02:30:00,3186 2014-11-05 03:00:00,2747 2014-11-05 03:30:00,2257 2014-11-05 04:00:00,2397 2014-11-05 04:30:00,2205 2014-11-05 05:00:00,2625 2014-11-05 05:30:00,4404 2014-11-05 06:00:00,7007 2014-11-05 06:30:00,12065 2014-11-05 07:00:00,15803 2014-11-05 07:30:00,19844 2014-11-05 08:00:00,19937 2014-11-05 08:30:00,20299 2014-11-05 09:00:00,19584 2014-11-05 09:30:00,19313 2014-11-05 10:00:00,16887 2014-11-05 10:30:00,17118 2014-11-05 11:00:00,16847 2014-11-05 11:30:00,18356 2014-11-05 12:00:00,18124 2014-11-05 12:30:00,17783 2014-11-05 13:00:00,17223 2014-11-05 13:30:00,17852 2014-11-05 14:00:00,18374 2014-11-05 14:30:00,18641 2014-11-05 15:00:00,18913 2014-11-05 15:30:00,16314 2014-11-05 16:00:00,13917 2014-11-05 16:30:00,13151 2014-11-05 17:00:00,16100 2014-11-05 17:30:00,19136 2014-11-05 18:00:00,21762 2014-11-05 18:30:00,22829 2014-11-05 19:00:00,23705 2014-11-05 19:30:00,23740 2014-11-05 20:00:00,23789 2014-11-05 20:30:00,23389 2014-11-05 21:00:00,24122 2014-11-05 21:30:00,24156 2014-11-05 22:00:00,23679 2014-11-05 22:30:00,22803 2014-11-05 23:00:00,20814 2014-11-05 23:30:00,17376 2014-11-06 00:00:00,13846 2014-11-06 00:30:00,10387 2014-11-06 01:00:00,8384 2014-11-06 01:30:00,6455 2014-11-06 02:00:00,5043 2014-11-06 02:30:00,3738 2014-11-06 03:00:00,3155 2014-11-06 03:30:00,2758 2014-11-06 04:00:00,3122 2014-11-06 04:30:00,2625 2014-11-06 05:00:00,2760 2014-11-06 05:30:00,4995 2014-11-06 06:00:00,8021 2014-11-06 06:30:00,13803 2014-11-06 07:00:00,17405 2014-11-06 07:30:00,20841 2014-11-06 08:00:00,21338 2014-11-06 08:30:00,21281 2014-11-06 09:00:00,20108 2014-11-06 09:30:00,20198 2014-11-06 10:00:00,19035 2014-11-06 10:30:00,19155 2014-11-06 11:00:00,17964 2014-11-06 11:30:00,18680 2014-11-06 12:00:00,18600 2014-11-06 12:30:00,17556 2014-11-06 13:00:00,17373 2014-11-06 13:30:00,17832 2014-11-06 14:00:00,18087 2014-11-06 14:30:00,18057 2014-11-06 15:00:00,17634 2014-11-06 15:30:00,15492 2014-11-06 16:00:00,13677 2014-11-06 16:30:00,12574 2014-11-06 17:00:00,15818 2014-11-06 17:30:00,19350 2014-11-06 18:00:00,21754 2014-11-06 18:30:00,23740 2014-11-06 19:00:00,24666 2014-11-06 19:30:00,25142 2014-11-06 20:00:00,25597 2014-11-06 20:30:00,25126 2014-11-06 21:00:00,25312 2014-11-06 21:30:00,26067 2014-11-06 22:00:00,25613 2014-11-06 22:30:00,23971 2014-11-06 23:00:00,22859 2014-11-06 23:30:00,21287 2014-11-07 00:00:00,18308 2014-11-07 00:30:00,14352 2014-11-07 01:00:00,11746 2014-11-07 01:30:00,9042 2014-11-07 02:00:00,7318 2014-11-07 02:30:00,6009 2014-11-07 03:00:00,5364 2014-11-07 03:30:00,4336 2014-11-07 04:00:00,4008 2014-11-07 04:30:00,3263 2014-11-07 05:00:00,3183 2014-11-07 05:30:00,4813 2014-11-07 06:00:00,7519 2014-11-07 06:30:00,12074 2014-11-07 07:00:00,15249 2014-11-07 07:30:00,19300 2014-11-07 08:00:00,19564 2014-11-07 08:30:00,19132 2014-11-07 09:00:00,18454 2014-11-07 09:30:00,17950 2014-11-07 10:00:00,17374 2014-11-07 10:30:00,17674 2014-11-07 11:00:00,17016 2014-11-07 11:30:00,18484 2014-11-07 12:00:00,18460 2014-11-07 12:30:00,17693 2014-11-07 13:00:00,18093 2014-11-07 13:30:00,19918 2014-11-07 14:00:00,19945 2014-11-07 14:30:00,19077 2014-11-07 15:00:00,18186 2014-11-07 15:30:00,16030 2014-11-07 16:00:00,14092 2014-11-07 16:30:00,13270 2014-11-07 17:00:00,15935 2014-11-07 17:30:00,19419 2014-11-07 18:00:00,21778 2014-11-07 18:30:00,24460 2014-11-07 19:00:00,26246 2014-11-07 19:30:00,27224 2014-11-07 20:00:00,26862 2014-11-07 20:30:00,27340 2014-11-07 21:00:00,27335 2014-11-07 21:30:00,26727 2014-11-07 22:00:00,27181 2014-11-07 22:30:00,27761 2014-11-07 23:00:00,27193 2014-11-07 23:30:00,26857 2014-11-08 00:00:00,25692 2014-11-08 00:30:00,24162 2014-11-08 01:00:00,22219 2014-11-08 01:30:00,20748 2014-11-08 02:00:00,19471 2014-11-08 02:30:00,16940 2014-11-08 03:00:00,14431 2014-11-08 03:30:00,11898 2014-11-08 04:00:00,10264 2014-11-08 04:30:00,5942 2014-11-08 05:00:00,4063 2014-11-08 05:30:00,3498 2014-11-08 06:00:00,3726 2014-11-08 06:30:00,5242 2014-11-08 07:00:00,5655 2014-11-08 07:30:00,8191 2014-11-08 08:00:00,9371 2014-11-08 08:30:00,13050 2014-11-08 09:00:00,13820 2014-11-08 09:30:00,17437 2014-11-08 10:00:00,17281 2014-11-08 10:30:00,19718 2014-11-08 11:00:00,19999 2014-11-08 11:30:00,22047 2014-11-08 12:00:00,22352 2014-11-08 12:30:00,22898 2014-11-08 13:00:00,22660 2014-11-08 13:30:00,23047 2014-11-08 14:00:00,21976 2014-11-08 14:30:00,22746 2014-11-08 15:00:00,22382 2014-11-08 15:30:00,21956 2014-11-08 16:00:00,18619 2014-11-08 16:30:00,15861 2014-11-08 17:00:00,18326 2014-11-08 17:30:00,22332 2014-11-08 18:00:00,25097 2014-11-08 18:30:00,27236 2014-11-08 19:00:00,27898 2014-11-08 19:30:00,26790 2014-11-08 20:00:00,25561 2014-11-08 20:30:00,24344 2014-11-08 21:00:00,23890 2014-11-08 21:30:00,24609 2014-11-08 22:00:00,26595 2014-11-08 22:30:00,27260 2014-11-08 23:00:00,27998 2014-11-08 23:30:00,27854 2014-11-09 00:00:00,26931 2014-11-09 00:30:00,25208 2014-11-09 01:00:00,23782 2014-11-09 01:30:00,22472 2014-11-09 02:00:00,21183 2014-11-09 02:30:00,18443 2014-11-09 03:00:00,16105 2014-11-09 03:30:00,13801 2014-11-09 04:00:00,11997 2014-11-09 04:30:00,7112 2014-11-09 05:00:00,4627 2014-11-09 05:30:00,3683 2014-11-09 06:00:00,3587 2014-11-09 06:30:00,4158 2014-11-09 07:00:00,4351 2014-11-09 07:30:00,5823 2014-11-09 08:00:00,6850 2014-11-09 08:30:00,9839 2014-11-09 09:00:00,11422 2014-11-09 09:30:00,14897 2014-11-09 10:00:00,15815 2014-11-09 10:30:00,18787 2014-11-09 11:00:00,18880 2014-11-09 11:30:00,19871 2014-11-09 12:00:00,20722 2014-11-09 12:30:00,21774 2014-11-09 13:00:00,21318 2014-11-09 13:30:00,20699 2014-11-09 14:00:00,20831 2014-11-09 14:30:00,20467 2014-11-09 15:00:00,20249 2014-11-09 15:30:00,20100 2014-11-09 16:00:00,18688 2014-11-09 16:30:00,17249 2014-11-09 17:00:00,18573 2014-11-09 17:30:00,19937 2014-11-09 18:00:00,20564 2014-11-09 18:30:00,20132 2014-11-09 19:00:00,19654 2014-11-09 19:30:00,18449 2014-11-09 20:00:00,17176 2014-11-09 20:30:00,17596 2014-11-09 21:00:00,16431 2014-11-09 21:30:00,15860 2014-11-09 22:00:00,15253 2014-11-09 22:30:00,13845 2014-11-09 23:00:00,11656 2014-11-09 23:30:00,9818 2014-11-10 00:00:00,7870 2014-11-10 00:30:00,6079 2014-11-10 01:00:00,4644 2014-11-10 01:30:00,3501 2014-11-10 02:00:00,2989 2014-11-10 02:30:00,2247 2014-11-10 03:00:00,1853 2014-11-10 03:30:00,1791 2014-11-10 04:00:00,2189 2014-11-10 04:30:00,2328 2014-11-10 05:00:00,2827 2014-11-10 05:30:00,4738 2014-11-10 06:00:00,6803 2014-11-10 06:30:00,11738 2014-11-10 07:00:00,14296 2014-11-10 07:30:00,17240 2014-11-10 08:00:00,17657 2014-11-10 08:30:00,17904 2014-11-10 09:00:00,17705 2014-11-10 09:30:00,16814 2014-11-10 10:00:00,15908 2014-11-10 10:30:00,15545 2014-11-10 11:00:00,15119 2014-11-10 11:30:00,16241 2014-11-10 12:00:00,16354 2014-11-10 12:30:00,16002 2014-11-10 13:00:00,15560 2014-11-10 13:30:00,16855 2014-11-10 14:00:00,17292 2014-11-10 14:30:00,17780 2014-11-10 15:00:00,18467 2014-11-10 15:30:00,17048 2014-11-10 16:00:00,15386 2014-11-10 16:30:00,15329 2014-11-10 17:00:00,17444 2014-11-10 17:30:00,19765 2014-11-10 18:00:00,22418 2014-11-10 18:30:00,22794 2014-11-10 19:00:00,23094 2014-11-10 19:30:00,22197 2014-11-10 20:00:00,21796 2014-11-10 20:30:00,20849 2014-11-10 21:00:00,21169 2014-11-10 21:30:00,20613 2014-11-10 22:00:00,20734 2014-11-10 22:30:00,17540 2014-11-10 23:00:00,15189 2014-11-10 23:30:00,12879 2014-11-11 00:00:00,10511 2014-11-11 00:30:00,7509 2014-11-11 01:00:00,6277 2014-11-11 01:30:00,4622 2014-11-11 02:00:00,3785 2014-11-11 02:30:00,2970 2014-11-11 03:00:00,2332 2014-11-11 03:30:00,2166 2014-11-11 04:00:00,2179 2014-11-11 04:30:00,2040 2014-11-11 05:00:00,2278 2014-11-11 05:30:00,3860 2014-11-11 06:00:00,5517 2014-11-11 06:30:00,9569 2014-11-11 07:00:00,12272 2014-11-11 07:30:00,16460 2014-11-11 08:00:00,16976 2014-11-11 08:30:00,17823 2014-11-11 09:00:00,17655 2014-11-11 09:30:00,16946 2014-11-11 10:00:00,15846 2014-11-11 10:30:00,15835 2014-11-11 11:00:00,15442 2014-11-11 11:30:00,16069 2014-11-11 12:00:00,15966 2014-11-11 12:30:00,15584 2014-11-11 13:00:00,15384 2014-11-11 13:30:00,15909 2014-11-11 14:00:00,16140 2014-11-11 14:30:00,16337 2014-11-11 15:00:00,16381 2014-11-11 15:30:00,15196 2014-11-11 16:00:00,13003 2014-11-11 16:30:00,12213 2014-11-11 17:00:00,15103 2014-11-11 17:30:00,18301 2014-11-11 18:00:00,20626 2014-11-11 18:30:00,22533 2014-11-11 19:00:00,22905 2014-11-11 19:30:00,22181 2014-11-11 20:00:00,21899 2014-11-11 20:30:00,21789 2014-11-11 21:00:00,22253 2014-11-11 21:30:00,22515 2014-11-11 22:00:00,21410 2014-11-11 22:30:00,19812 2014-11-11 23:00:00,17135 2014-11-11 23:30:00,13567 2014-11-12 00:00:00,10829 2014-11-12 00:30:00,7850 2014-11-12 01:00:00,6572 2014-11-12 01:30:00,4748 2014-11-12 02:00:00,3777 2014-11-12 02:30:00,3255 2014-11-12 03:00:00,2415 2014-11-12 03:30:00,2279 2014-11-12 04:00:00,2353 2014-11-12 04:30:00,2142 2014-11-12 05:00:00,2540 2014-11-12 05:30:00,4177 2014-11-12 06:00:00,6843 2014-11-12 06:30:00,11818 2014-11-12 07:00:00,15665 2014-11-12 07:30:00,19785 2014-11-12 08:00:00,19813 2014-11-12 08:30:00,19623 2014-11-12 09:00:00,18444 2014-11-12 09:30:00,17937 2014-11-12 10:00:00,16552 2014-11-12 10:30:00,17394 2014-11-12 11:00:00,16960 2014-11-12 11:30:00,18105 2014-11-12 12:00:00,17724 2014-11-12 12:30:00,16327 2014-11-12 13:00:00,16527 2014-11-12 13:30:00,17290 2014-11-12 14:00:00,18042 2014-11-12 14:30:00,18250 2014-11-12 15:00:00,17656 2014-11-12 15:30:00,16288 2014-11-12 16:00:00,13992 2014-11-12 16:30:00,12912 2014-11-12 17:00:00,16032 2014-11-12 17:30:00,18814 2014-11-12 18:00:00,21296 2014-11-12 18:30:00,23115 2014-11-12 19:00:00,23859 2014-11-12 19:30:00,24749 2014-11-12 20:00:00,23879 2014-11-12 20:30:00,23815 2014-11-12 21:00:00,24595 2014-11-12 21:30:00,24494 2014-11-12 22:00:00,24213 2014-11-12 22:30:00,22931 2014-11-12 23:00:00,20785 2014-11-12 23:30:00,17464 2014-11-13 00:00:00,13303 2014-11-13 00:30:00,10350 2014-11-13 01:00:00,7850 2014-11-13 01:30:00,5961 2014-11-13 02:00:00,5051 2014-11-13 02:30:00,3833 2014-11-13 03:00:00,3006 2014-11-13 03:30:00,2515 2014-11-13 04:00:00,2816 2014-11-13 04:30:00,2248 2014-11-13 05:00:00,2621 2014-11-13 05:30:00,4392 2014-11-13 06:00:00,7062 2014-11-13 06:30:00,12333 2014-11-13 07:00:00,15661 2014-11-13 07:30:00,19597 2014-11-13 08:00:00,20200 2014-11-13 08:30:00,19843 2014-11-13 09:00:00,19031 2014-11-13 09:30:00,18253 2014-11-13 10:00:00,17244 2014-11-13 10:30:00,17402 2014-11-13 11:00:00,17286 2014-11-13 11:30:00,18936 2014-11-13 12:00:00,18516 2014-11-13 12:30:00,17635 2014-11-13 13:00:00,17343 2014-11-13 13:30:00,19090 2014-11-13 14:00:00,19197 2014-11-13 14:30:00,19207 2014-11-13 15:00:00,18412 2014-11-13 15:30:00,16391 2014-11-13 16:00:00,13472 2014-11-13 16:30:00,12807 2014-11-13 17:00:00,16097 2014-11-13 17:30:00,19322 2014-11-13 18:00:00,21645 2014-11-13 18:30:00,22745 2014-11-13 19:00:00,24219 2014-11-13 19:30:00,25443 2014-11-13 20:00:00,25695 2014-11-13 20:30:00,25994 2014-11-13 21:00:00,26424 2014-11-13 21:30:00,25450 2014-11-13 22:00:00,24621 2014-11-13 22:30:00,23727 2014-11-13 23:00:00,22503 2014-11-13 23:30:00,20709 2014-11-14 00:00:00,17932 2014-11-14 00:30:00,14668 2014-11-14 01:00:00,11986 2014-11-14 01:30:00,9213 2014-11-14 02:00:00,7202 2014-11-14 02:30:00,5552 2014-11-14 03:00:00,5023 2014-11-14 03:30:00,3900 2014-11-14 04:00:00,4039 2014-11-14 04:30:00,2987 2014-11-14 05:00:00,3090 2014-11-14 05:30:00,4737 2014-11-14 06:00:00,7102 2014-11-14 06:30:00,12268 2014-11-14 07:00:00,15903 2014-11-14 07:30:00,20015 2014-11-14 08:00:00,20432 2014-11-14 08:30:00,20735 2014-11-14 09:00:00,19149 2014-11-14 09:30:00,18665 2014-11-14 10:00:00,17992 2014-11-14 10:30:00,17773 2014-11-14 11:00:00,17786 2014-11-14 11:30:00,18128 2014-11-14 12:00:00,18355 2014-11-14 12:30:00,17629 2014-11-14 13:00:00,17104 2014-11-14 13:30:00,18151 2014-11-14 14:00:00,18892 2014-11-14 14:30:00,19540 2014-11-14 15:00:00,18557 2014-11-14 15:30:00,16263 2014-11-14 16:00:00,14668 2014-11-14 16:30:00,13473 2014-11-14 17:00:00,16747 2014-11-14 17:30:00,20594 2014-11-14 18:00:00,23151 2014-11-14 18:30:00,25446 2014-11-14 19:00:00,27196 2014-11-14 19:30:00,26881 2014-11-14 20:00:00,25994 2014-11-14 20:30:00,25879 2014-11-14 21:00:00,26301 2014-11-14 21:30:00,27136 2014-11-14 22:00:00,26940 2014-11-14 22:30:00,26834 2014-11-14 23:00:00,26960 2014-11-14 23:30:00,26107 2014-11-15 00:00:00,25034 2014-11-15 00:30:00,24103 2014-11-15 01:00:00,22682 2014-11-15 01:30:00,20630 2014-11-15 02:00:00,19226 2014-11-15 02:30:00,16555 2014-11-15 03:00:00,14088 2014-11-15 03:30:00,12491 2014-11-15 04:00:00,10208 2014-11-15 04:30:00,5853 2014-11-15 05:00:00,4019 2014-11-15 05:30:00,3477 2014-11-15 06:00:00,3582 2014-11-15 06:30:00,4936 2014-11-15 07:00:00,5272 2014-11-15 07:30:00,7427 2014-11-15 08:00:00,8646 2014-11-15 08:30:00,12313 2014-11-15 09:00:00,13426 2014-11-15 09:30:00,17040 2014-11-15 10:00:00,16811 2014-11-15 10:30:00,19069 2014-11-15 11:00:00,19423 2014-11-15 11:30:00,21552 2014-11-15 12:00:00,21685 2014-11-15 12:30:00,22380 2014-11-15 13:00:00,21954 2014-11-15 13:30:00,21926 2014-11-15 14:00:00,21851 2014-11-15 14:30:00,22014 2014-11-15 15:00:00,22075 2014-11-15 15:30:00,20936 2014-11-15 16:00:00,18358 2014-11-15 16:30:00,15289 2014-11-15 17:00:00,17742 2014-11-15 17:30:00,21769 2014-11-15 18:00:00,24058 2014-11-15 18:30:00,26029 2014-11-15 19:00:00,27266 2014-11-15 19:30:00,26817 2014-11-15 20:00:00,25049 2014-11-15 20:30:00,23713 2014-11-15 21:00:00,23324 2014-11-15 21:30:00,23970 2014-11-15 22:00:00,26325 2014-11-15 22:30:00,26139 2014-11-15 23:00:00,27312 2014-11-15 23:30:00,28114 2014-11-16 00:00:00,26651 2014-11-16 00:30:00,25212 2014-11-16 01:00:00,24273 2014-11-16 01:30:00,22665 2014-11-16 02:00:00,21069 2014-11-16 02:30:00,18803 2014-11-16 03:00:00,16590 2014-11-16 03:30:00,14414 2014-11-16 04:00:00,12228 2014-11-16 04:30:00,7230 2014-11-16 05:00:00,4624 2014-11-16 05:30:00,3594 2014-11-16 06:00:00,3332 2014-11-16 06:30:00,4083 2014-11-16 07:00:00,4416 2014-11-16 07:30:00,5214 2014-11-16 08:00:00,6429 2014-11-16 08:30:00,8898 2014-11-16 09:00:00,10911 2014-11-16 09:30:00,13475 2014-11-16 10:00:00,15157 2014-11-16 10:30:00,18595 2014-11-16 11:00:00,19233 2014-11-16 11:30:00,20372 2014-11-16 12:00:00,21847 2014-11-16 12:30:00,21695 2014-11-16 13:00:00,21880 2014-11-16 13:30:00,21047 2014-11-16 14:00:00,21107 2014-11-16 14:30:00,20602 2014-11-16 15:00:00,19817 2014-11-16 15:30:00,19310 2014-11-16 16:00:00,18479 2014-11-16 16:30:00,16296 2014-11-16 17:00:00,17751 2014-11-16 17:30:00,19230 2014-11-16 18:00:00,19883 2014-11-16 18:30:00,19768 2014-11-16 19:00:00,18931 2014-11-16 19:30:00,17936 2014-11-16 20:00:00,16360 2014-11-16 20:30:00,16885 2014-11-16 21:00:00,16000 2014-11-16 21:30:00,14902 2014-11-16 22:00:00,13707 2014-11-16 22:30:00,13406 2014-11-16 23:00:00,12021 2014-11-16 23:30:00,11115 2014-11-17 00:00:00,8317 2014-11-17 00:30:00,5887 2014-11-17 01:00:00,4464 2014-11-17 01:30:00,3425 2014-11-17 02:00:00,2961 2014-11-17 02:30:00,2328 2014-11-17 03:00:00,2020 2014-11-17 03:30:00,1764 2014-11-17 04:00:00,2139 2014-11-17 04:30:00,2296 2014-11-17 05:00:00,2960 2014-11-17 05:30:00,5121 2014-11-17 06:00:00,7871 2014-11-17 06:30:00,11902 2014-11-17 07:00:00,14583 2014-11-17 07:30:00,17190 2014-11-17 08:00:00,18725 2014-11-17 08:30:00,18822 2014-11-17 09:00:00,17992 2014-11-17 09:30:00,17210 2014-11-17 10:00:00,15940 2014-11-17 10:30:00,17094 2014-11-17 11:00:00,15247 2014-11-17 11:30:00,16676 2014-11-17 12:00:00,16895 2014-11-17 12:30:00,17205 2014-11-17 13:00:00,17634 2014-11-17 13:30:00,18189 2014-11-17 14:00:00,19319 2014-11-17 14:30:00,18757 2014-11-17 15:00:00,17239 2014-11-17 15:30:00,14885 2014-11-17 16:00:00,13577 2014-11-17 16:30:00,13513 2014-11-17 17:00:00,15864 2014-11-17 17:30:00,18502 2014-11-17 18:00:00,20313 2014-11-17 18:30:00,20674 2014-11-17 19:00:00,21079 2014-11-17 19:30:00,21433 2014-11-17 20:00:00,20590 2014-11-17 20:30:00,19515 2014-11-17 21:00:00,20194 2014-11-17 21:30:00,19251 2014-11-17 22:00:00,18436 2014-11-17 22:30:00,16099 2014-11-17 23:00:00,14985 2014-11-17 23:30:00,11612 2014-11-18 00:00:00,9828 2014-11-18 00:30:00,7529 2014-11-18 01:00:00,6162 2014-11-18 01:30:00,4296 2014-11-18 02:00:00,3090 2014-11-18 02:30:00,2366 2014-11-18 03:00:00,2094 2014-11-18 03:30:00,1831 2014-11-18 04:00:00,1987 2014-11-18 04:30:00,1936 2014-11-18 05:00:00,2346 2014-11-18 05:30:00,4328 2014-11-18 06:00:00,6935 2014-11-18 06:30:00,12642 2014-11-18 07:00:00,16037 2014-11-18 07:30:00,20032 2014-11-18 08:00:00,20709 2014-11-18 08:30:00,20897 2014-11-18 09:00:00,20127 2014-11-18 09:30:00,19075 2014-11-18 10:00:00,17883 2014-11-18 10:30:00,17581 2014-11-18 11:00:00,16559 2014-11-18 11:30:00,17870 2014-11-18 12:00:00,18097 2014-11-18 12:30:00,17714 2014-11-18 13:00:00,17104 2014-11-18 13:30:00,17999 2014-11-18 14:00:00,19071 2014-11-18 14:30:00,19197 2014-11-18 15:00:00,19000 2014-11-18 15:30:00,17013 2014-11-18 16:00:00,14962 2014-11-18 16:30:00,13727 2014-11-18 17:00:00,16826 2014-11-18 17:30:00,20320 2014-11-18 18:00:00,23167 2014-11-18 18:30:00,23782 2014-11-18 19:00:00,24068 2014-11-18 19:30:00,24831 2014-11-18 20:00:00,25564 2014-11-18 20:30:00,25300 2014-11-18 21:00:00,25503 2014-11-18 21:30:00,24598 2014-11-18 22:00:00,24120 2014-11-18 22:30:00,22641 2014-11-18 23:00:00,19722 2014-11-18 23:30:00,15507 2014-11-19 00:00:00,12079 2014-11-19 00:30:00,8561 2014-11-19 01:00:00,6632 2014-11-19 01:30:00,4846 2014-11-19 02:00:00,3996 2014-11-19 02:30:00,3339 2014-11-19 03:00:00,2594 2014-11-19 03:30:00,2315 2014-11-19 04:00:00,2462 2014-11-19 04:30:00,2077 2014-11-19 05:00:00,2448 2014-11-19 05:30:00,4656 2014-11-19 06:00:00,7055 2014-11-19 06:30:00,12903 2014-11-19 07:00:00,16639 2014-11-19 07:30:00,20585 2014-11-19 08:00:00,21833 2014-11-19 08:30:00,21453 2014-11-19 09:00:00,20023 2014-11-19 09:30:00,18790 2014-11-19 10:00:00,18382 2014-11-19 10:30:00,17956 2014-11-19 11:00:00,17477 2014-11-19 11:30:00,18590 2014-11-19 12:00:00,18409 2014-11-19 12:30:00,18020 2014-11-19 13:00:00,16950 2014-11-19 13:30:00,17826 2014-11-19 14:00:00,18105 2014-11-19 14:30:00,18187 2014-11-19 15:00:00,18565 2014-11-19 15:30:00,16454 2014-11-19 16:00:00,14355 2014-11-19 16:30:00,13109 2014-11-19 17:00:00,15924 2014-11-19 17:30:00,19175 2014-11-19 18:00:00,21521 2014-11-19 18:30:00,22762 2014-11-19 19:00:00,23889 2014-11-19 19:30:00,24408 2014-11-19 20:00:00,24501 2014-11-19 20:30:00,24316 2014-11-19 21:00:00,24362 2014-11-19 21:30:00,24032 2014-11-19 22:00:00,23174 2014-11-19 22:30:00,22453 2014-11-19 23:00:00,20964 2014-11-19 23:30:00,18142 2014-11-20 00:00:00,14466 2014-11-20 00:30:00,10771 2014-11-20 01:00:00,8100 2014-11-20 01:30:00,5976 2014-11-20 02:00:00,5000 2014-11-20 02:30:00,3727 2014-11-20 03:00:00,2984 2014-11-20 03:30:00,2584 2014-11-20 04:00:00,2591 2014-11-20 04:30:00,2253 2014-11-20 05:00:00,2489 2014-11-20 05:30:00,4419 2014-11-20 06:00:00,7014 2014-11-20 06:30:00,12470 2014-11-20 07:00:00,16549 2014-11-20 07:30:00,19879 2014-11-20 08:00:00,20437 2014-11-20 08:30:00,19549 2014-11-20 09:00:00,18639 2014-11-20 09:30:00,18683 2014-11-20 10:00:00,18486 2014-11-20 10:30:00,18014 2014-11-20 11:00:00,16720 2014-11-20 11:30:00,18570 2014-11-20 12:00:00,18309 2014-11-20 12:30:00,17294 2014-11-20 13:00:00,16699 2014-11-20 13:30:00,17819 2014-11-20 14:00:00,18227 2014-11-20 14:30:00,18586 2014-11-20 15:00:00,18078 2014-11-20 15:30:00,15656 2014-11-20 16:00:00,12989 2014-11-20 16:30:00,11740 2014-11-20 17:00:00,14934 2014-11-20 17:30:00,18494 2014-11-20 18:00:00,21215 2014-11-20 18:30:00,23643 2014-11-20 19:00:00,24623 2014-11-20 19:30:00,24564 2014-11-20 20:00:00,25305 2014-11-20 20:30:00,25039 2014-11-20 21:00:00,25351 2014-11-20 21:30:00,24526 2014-11-20 22:00:00,24739 2014-11-20 22:30:00,23638 2014-11-20 23:00:00,21861 2014-11-20 23:30:00,21500 2014-11-21 00:00:00,19838 2014-11-21 00:30:00,16307 2014-11-21 01:00:00,12324 2014-11-21 01:30:00,10006 2014-11-21 02:00:00,8077 2014-11-21 02:30:00,6355 2014-11-21 03:00:00,5091 2014-11-21 03:30:00,4247 2014-11-21 04:00:00,4440 2014-11-21 04:30:00,3089 2014-11-21 05:00:00,2930 2014-11-21 05:30:00,4782 2014-11-21 06:00:00,7250 2014-11-21 06:30:00,12167 2014-11-21 07:00:00,15235 2014-11-21 07:30:00,20053 2014-11-21 08:00:00,20654 2014-11-21 08:30:00,21158 2014-11-21 09:00:00,19863 2014-11-21 09:30:00,18775 2014-11-21 10:00:00,18346 2014-11-21 10:30:00,18645 2014-11-21 11:00:00,17986 2014-11-21 11:30:00,19070 2014-11-21 12:00:00,18901 2014-11-21 12:30:00,17585 2014-11-21 13:00:00,17309 2014-11-21 13:30:00,18226 2014-11-21 14:00:00,18788 2014-11-21 14:30:00,19103 2014-11-21 15:00:00,18261 2014-11-21 15:30:00,15945 2014-11-21 16:00:00,14181 2014-11-21 16:30:00,12992 2014-11-21 17:00:00,15847 2014-11-21 17:30:00,19426 2014-11-21 18:00:00,22514 2014-11-21 18:30:00,24457 2014-11-21 19:00:00,26156 2014-11-21 19:30:00,26677 2014-11-21 20:00:00,26217 2014-11-21 20:30:00,26289 2014-11-21 21:00:00,26370 2014-11-21 21:30:00,26344 2014-11-21 22:00:00,26736 2014-11-21 22:30:00,27093 2014-11-21 23:00:00,27569 2014-11-21 23:30:00,27064 2014-11-22 00:00:00,26220 2014-11-22 00:30:00,24289 2014-11-22 01:00:00,22849 2014-11-22 01:30:00,20731 2014-11-22 02:00:00,19081 2014-11-22 02:30:00,16573 2014-11-22 03:00:00,14188 2014-11-22 03:30:00,12213 2014-11-22 04:00:00,10145 2014-11-22 04:30:00,5902 2014-11-22 05:00:00,3983 2014-11-22 05:30:00,3556 2014-11-22 06:00:00,3651 2014-11-22 06:30:00,5153 2014-11-22 07:00:00,5379 2014-11-22 07:30:00,7174 2014-11-22 08:00:00,9070 2014-11-22 08:30:00,12114 2014-11-22 09:00:00,13665 2014-11-22 09:30:00,17463 2014-11-22 10:00:00,17209 2014-11-22 10:30:00,20299 2014-11-22 11:00:00,20255 2014-11-22 11:30:00,22981 2014-11-22 12:00:00,23368 2014-11-22 12:30:00,23444 2014-11-22 13:00:00,22610 2014-11-22 13:30:00,22258 2014-11-22 14:00:00,21160 2014-11-22 14:30:00,22960 2014-11-22 15:00:00,23007 2014-11-22 15:30:00,21145 2014-11-22 16:00:00,18440 2014-11-22 16:30:00,16028 2014-11-22 17:00:00,19101 2014-11-22 17:30:00,22361 2014-11-22 18:00:00,24256 2014-11-22 18:30:00,26410 2014-11-22 19:00:00,27377 2014-11-22 19:30:00,26255 2014-11-22 20:00:00,23977 2014-11-22 20:30:00,23565 2014-11-22 21:00:00,22703 2014-11-22 21:30:00,23078 2014-11-22 22:00:00,25755 2014-11-22 22:30:00,27028 2014-11-22 23:00:00,28126 2014-11-22 23:30:00,28472 2014-11-23 00:00:00,27424 2014-11-23 00:30:00,25493 2014-11-23 01:00:00,24876 2014-11-23 01:30:00,22639 2014-11-23 02:00:00,21013 2014-11-23 02:30:00,19100 2014-11-23 03:00:00,16662 2014-11-23 03:30:00,14489 2014-11-23 04:00:00,12023 2014-11-23 04:30:00,7069 2014-11-23 05:00:00,4453 2014-11-23 05:30:00,3483 2014-11-23 06:00:00,3479 2014-11-23 06:30:00,3968 2014-11-23 07:00:00,4092 2014-11-23 07:30:00,5877 2014-11-23 08:00:00,6845 2014-11-23 08:30:00,8283 2014-11-23 09:00:00,10231 2014-11-23 09:30:00,13189 2014-11-23 10:00:00,14458 2014-11-23 10:30:00,17284 2014-11-23 11:00:00,17800 2014-11-23 11:30:00,19509 2014-11-23 12:00:00,20547 2014-11-23 12:30:00,20211 2014-11-23 13:00:00,20041 2014-11-23 13:30:00,19619 2014-11-23 14:00:00,19947 2014-11-23 14:30:00,19844 2014-11-23 15:00:00,19088 2014-11-23 15:30:00,19237 2014-11-23 16:00:00,18316 2014-11-23 16:30:00,16996 2014-11-23 17:00:00,18134 2014-11-23 17:30:00,19633 2014-11-23 18:00:00,20204 2014-11-23 18:30:00,19810 2014-11-23 19:00:00,17925 2014-11-23 19:30:00,16938 2014-11-23 20:00:00,15096 2014-11-23 20:30:00,15539 2014-11-23 21:00:00,14806 2014-11-23 21:30:00,15035 2014-11-23 22:00:00,13285 2014-11-23 22:30:00,12090 2014-11-23 23:00:00,10552 2014-11-23 23:30:00,9136 2014-11-24 00:00:00,8106 2014-11-24 00:30:00,7020 2014-11-24 01:00:00,5562 2014-11-24 01:30:00,3917 2014-11-24 02:00:00,3592 2014-11-24 02:30:00,2637 2014-11-24 03:00:00,2031 2014-11-24 03:30:00,1900 2014-11-24 04:00:00,2172 2014-11-24 04:30:00,2008 2014-11-24 05:00:00,2546 2014-11-24 05:30:00,4409 2014-11-24 06:00:00,7269 2014-11-24 06:30:00,11863 2014-11-24 07:00:00,14244 2014-11-24 07:30:00,17238 2014-11-24 08:00:00,18382 2014-11-24 08:30:00,17940 2014-11-24 09:00:00,17447 2014-11-24 09:30:00,16773 2014-11-24 10:00:00,15319 2014-11-24 10:30:00,15867 2014-11-24 11:00:00,15751 2014-11-24 11:30:00,17462 2014-11-24 12:00:00,16292 2014-11-24 12:30:00,16317 2014-11-24 13:00:00,16104 2014-11-24 13:30:00,16967 2014-11-24 14:00:00,17035 2014-11-24 14:30:00,17976 2014-11-24 15:00:00,18230 2014-11-24 15:30:00,16521 2014-11-24 16:00:00,14887 2014-11-24 16:30:00,13707 2014-11-24 17:00:00,16596 2014-11-24 17:30:00,18683 2014-11-24 18:00:00,20289 2014-11-24 18:30:00,21377 2014-11-24 19:00:00,21962 2014-11-24 19:30:00,21126 2014-11-24 20:00:00,20531 2014-11-24 20:30:00,19217 2014-11-24 21:00:00,19353 2014-11-24 21:30:00,19109 2014-11-24 22:00:00,18814 2014-11-24 22:30:00,17036 2014-11-24 23:00:00,14147 2014-11-24 23:30:00,11595 2014-11-25 00:00:00,10091 2014-11-25 00:30:00,7575 2014-11-25 01:00:00,5977 2014-11-25 01:30:00,4705 2014-11-25 02:00:00,3796 2014-11-25 02:30:00,2894 2014-11-25 03:00:00,2471 2014-11-25 03:30:00,2115 2014-11-25 04:00:00,2474 2014-11-25 04:30:00,2285 2014-11-25 05:00:00,2538 2014-11-25 05:30:00,4380 2014-11-25 06:00:00,6537 2014-11-25 06:30:00,11238 2014-11-25 07:00:00,14764 2014-11-25 07:30:00,18187 2014-11-25 08:00:00,18885 2014-11-25 08:30:00,19188 2014-11-25 09:00:00,18398 2014-11-25 09:30:00,18057 2014-11-25 10:00:00,16899 2014-11-25 10:30:00,17137 2014-11-25 11:00:00,16203 2014-11-25 11:30:00,17742 2014-11-25 12:00:00,17843 2014-11-25 12:30:00,17866 2014-11-25 13:00:00,17548 2014-11-25 13:30:00,18306 2014-11-25 14:00:00,18577 2014-11-25 14:30:00,18506 2014-11-25 15:00:00,18691 2014-11-25 15:30:00,15729 2014-11-25 16:00:00,13396 2014-11-25 16:30:00,11923 2014-11-25 17:00:00,14463 2014-11-25 17:30:00,17026 2014-11-25 18:00:00,19078 2014-11-25 18:30:00,20439 2014-11-25 19:00:00,20776 2014-11-25 19:30:00,20941 2014-11-25 20:00:00,20209 2014-11-25 20:30:00,19987 2014-11-25 21:00:00,19952 2014-11-25 21:30:00,19234 2014-11-25 22:00:00,18455 2014-11-25 22:30:00,18097 2014-11-25 23:00:00,17461 2014-11-25 23:30:00,16002 2014-11-26 00:00:00,13400 2014-11-26 00:30:00,10978 2014-11-26 01:00:00,8613 2014-11-26 01:30:00,6446 2014-11-26 02:00:00,5205 2014-11-26 02:30:00,4118 2014-11-26 03:00:00,3510 2014-11-26 03:30:00,3249 2014-11-26 04:00:00,3698 2014-11-26 04:30:00,3584 2014-11-26 05:00:00,3622 2014-11-26 05:30:00,4987 2014-11-26 06:00:00,7213 2014-11-26 06:30:00,10827 2014-11-26 07:00:00,14141 2014-11-26 07:30:00,16965 2014-11-26 08:00:00,19391 2014-11-26 08:30:00,19557 2014-11-26 09:00:00,19067 2014-11-26 09:30:00,18807 2014-11-26 10:00:00,18232 2014-11-26 10:30:00,18999 2014-11-26 11:00:00,18896 2014-11-26 11:30:00,19764 2014-11-26 12:00:00,20227 2014-11-26 12:30:00,19602 2014-11-26 13:00:00,20456 2014-11-26 13:30:00,19580 2014-11-26 14:00:00,19156 2014-11-26 14:30:00,19572 2014-11-26 15:00:00,18925 2014-11-26 15:30:00,17545 2014-11-26 16:00:00,15465 2014-11-26 16:30:00,14104 2014-11-26 17:00:00,16996 2014-11-26 17:30:00,20113 2014-11-26 18:00:00,21015 2014-11-26 18:30:00,21580 2014-11-26 19:00:00,22501 2014-11-26 19:30:00,21159 2014-11-26 20:00:00,18991 2014-11-26 20:30:00,18046 2014-11-26 21:00:00,18300 2014-11-26 21:30:00,18538 2014-11-26 22:00:00,17170 2014-11-26 22:30:00,17081 2014-11-26 23:00:00,15613 2014-11-26 23:30:00,13718 2014-11-27 00:00:00,13522 2014-11-27 00:30:00,11323 2014-11-27 01:00:00,10315 2014-11-27 01:30:00,8870 2014-11-27 02:00:00,8150 2014-11-27 02:30:00,7209 2014-11-27 03:00:00,6018 2014-11-27 03:30:00,5819 2014-11-27 04:00:00,5291 2014-11-27 04:30:00,4127 2014-11-27 05:00:00,3540 2014-11-27 05:30:00,3715 2014-11-27 06:00:00,4613 2014-11-27 06:30:00,5500 2014-11-27 07:00:00,5955 2014-11-27 07:30:00,6512 2014-11-27 08:00:00,7076 2014-11-27 08:30:00,7813 2014-11-27 09:00:00,8365 2014-11-27 09:30:00,9013 2014-11-27 10:00:00,9695 2014-11-27 10:30:00,11389 2014-11-27 11:00:00,12701 2014-11-27 11:30:00,13400 2014-11-27 12:00:00,13282 2014-11-27 12:30:00,13542 2014-11-27 13:00:00,13538 2014-11-27 13:30:00,13663 2014-11-27 14:00:00,13980 2014-11-27 14:30:00,14673 2014-11-27 15:00:00,14614 2014-11-27 15:30:00,15255 2014-11-27 16:00:00,13560 2014-11-27 16:30:00,13120 2014-11-27 17:00:00,13273 2014-11-27 17:30:00,13334 2014-11-27 18:00:00,12930 2014-11-27 18:30:00,13683 2014-11-27 19:00:00,13682 2014-11-27 19:30:00,14106 2014-11-27 20:00:00,14088 2014-11-27 20:30:00,14417 2014-11-27 21:00:00,15187 2014-11-27 21:30:00,15280 2014-11-27 22:00:00,15654 2014-11-27 22:30:00,13989 2014-11-27 23:00:00,12592 2014-11-27 23:30:00,11811 2014-11-28 00:00:00,9653 2014-11-28 00:30:00,7791 2014-11-28 01:00:00,6862 2014-11-28 01:30:00,5644 2014-11-28 02:00:00,4639 2014-11-28 02:30:00,3673 2014-11-28 03:00:00,2945 2014-11-28 03:30:00,2875 2014-11-28 04:00:00,2883 2014-11-28 04:30:00,2165 2014-11-28 05:00:00,1902 2014-11-28 05:30:00,2226 2014-11-28 06:00:00,2870 2014-11-28 06:30:00,4313 2014-11-28 07:00:00,4936 2014-11-28 07:30:00,6240 2014-11-28 08:00:00,7376 2014-11-28 08:30:00,8850 2014-11-28 09:00:00,9864 2014-11-28 09:30:00,10863 2014-11-28 10:00:00,11900 2014-11-28 10:30:00,12969 2014-11-28 11:00:00,14045 2014-11-28 11:30:00,15281 2014-11-28 12:00:00,16153 2014-11-28 12:30:00,17025 2014-11-28 13:00:00,17596 2014-11-28 13:30:00,18437 2014-11-28 14:00:00,17777 2014-11-28 14:30:00,18774 2014-11-28 15:00:00,18868 2014-11-28 15:30:00,19046 2014-11-28 16:00:00,17706 2014-11-28 16:30:00,16591 2014-11-28 17:00:00,18951 2014-11-28 17:30:00,20519 2014-11-28 18:00:00,20626 2014-11-28 18:30:00,21227 2014-11-28 19:00:00,22716 2014-11-28 19:30:00,21044 2014-11-28 20:00:00,18862 2014-11-28 20:30:00,18821 2014-11-28 21:00:00,18485 2014-11-28 21:30:00,18416 2014-11-28 22:00:00,19806 2014-11-28 22:30:00,19671 2014-11-28 23:00:00,19234 2014-11-28 23:30:00,17725 2014-11-29 00:00:00,16089 2014-11-29 00:30:00,14561 2014-11-29 01:00:00,13292 2014-11-29 01:30:00,12000 2014-11-29 02:00:00,10967 2014-11-29 02:30:00,9747 2014-11-29 03:00:00,8556 2014-11-29 03:30:00,8342 2014-11-29 04:00:00,7178 2014-11-29 04:30:00,4441 2014-11-29 05:00:00,2747 2014-11-29 05:30:00,2489 2014-11-29 06:00:00,2283 2014-11-29 06:30:00,3109 2014-11-29 07:00:00,3380 2014-11-29 07:30:00,4628 2014-11-29 08:00:00,5291 2014-11-29 08:30:00,7405 2014-11-29 09:00:00,9044 2014-11-29 09:30:00,11193 2014-11-29 10:00:00,12541 2014-11-29 10:30:00,15281 2014-11-29 11:00:00,15551 2014-11-29 11:30:00,17665 2014-11-29 12:00:00,18499 2014-11-29 12:30:00,18680 2014-11-29 13:00:00,19621 2014-11-29 13:30:00,19830 2014-11-29 14:00:00,19187 2014-11-29 14:30:00,19999 2014-11-29 15:00:00,19722 2014-11-29 15:30:00,20600 2014-11-29 16:00:00,19125 2014-11-29 16:30:00,16658 2014-11-29 17:00:00,18684 2014-11-29 17:30:00,20891 2014-11-29 18:00:00,21554 2014-11-29 18:30:00,22678 2014-11-29 19:00:00,24055 2014-11-29 19:30:00,23418 2014-11-29 20:00:00,20196 2014-11-29 20:30:00,19676 2014-11-29 21:00:00,19566 2014-11-29 21:30:00,19272 2014-11-29 22:00:00,20686 2014-11-29 22:30:00,21659 2014-11-29 23:00:00,21154 2014-11-29 23:30:00,21170 2014-11-30 00:00:00,20149 2014-11-30 00:30:00,18555 2014-11-30 01:00:00,17768 2014-11-30 01:30:00,15608 2014-11-30 02:00:00,14966 2014-11-30 02:30:00,13074 2014-11-30 03:00:00,11332 2014-11-30 03:30:00,9965 2014-11-30 04:00:00,9167 2014-11-30 04:30:00,5520 2014-11-30 05:00:00,3812 2014-11-30 05:30:00,3123 2014-11-30 06:00:00,3103 2014-11-30 06:30:00,3777 2014-11-30 07:00:00,3699 2014-11-30 07:30:00,4968 2014-11-30 08:00:00,5630 2014-11-30 08:30:00,7422 2014-11-30 09:00:00,9123 2014-11-30 09:30:00,10981 2014-11-30 10:00:00,12227 2014-11-30 10:30:00,15247 2014-11-30 11:00:00,14970 2014-11-30 11:30:00,16912 2014-11-30 12:00:00,17420 2014-11-30 12:30:00,18336 2014-11-30 13:00:00,18091 2014-11-30 13:30:00,17841 2014-11-30 14:00:00,18946 2014-11-30 14:30:00,19156 2014-11-30 15:00:00,18159 2014-11-30 15:30:00,17805 2014-11-30 16:00:00,16838 2014-11-30 16:30:00,15906 2014-11-30 17:00:00,16917 2014-11-30 17:30:00,17670 2014-11-30 18:00:00,17941 2014-11-30 18:30:00,18093 2014-11-30 19:00:00,17587 2014-11-30 19:30:00,16867 2014-11-30 20:00:00,15693 2014-11-30 20:30:00,15342 2014-11-30 21:00:00,13821 2014-11-30 21:30:00,14083 2014-11-30 22:00:00,13714 2014-11-30 22:30:00,12119 2014-11-30 23:00:00,9904 2014-11-30 23:30:00,8970 2014-12-01 00:00:00,7706 2014-12-01 00:30:00,5494 2014-12-01 01:00:00,4249 2014-12-01 01:30:00,2891 2014-12-01 02:00:00,2632 2014-12-01 02:30:00,2192 2014-12-01 03:00:00,1648 2014-12-01 03:30:00,1639 2014-12-01 04:00:00,1913 2014-12-01 04:30:00,2142 2014-12-01 05:00:00,2909 2014-12-01 05:30:00,4587 2014-12-01 06:00:00,7235 2014-12-01 06:30:00,11448 2014-12-01 07:00:00,14106 2014-12-01 07:30:00,17184 2014-12-01 08:00:00,18306 2014-12-01 08:30:00,18746 2014-12-01 09:00:00,17914 2014-12-01 09:30:00,16699 2014-12-01 10:00:00,15681 2014-12-01 10:30:00,15210 2014-12-01 11:00:00,14532 2014-12-01 11:30:00,15985 2014-12-01 12:00:00,16226 2014-12-01 12:30:00,16000 2014-12-01 13:00:00,15641 2014-12-01 13:30:00,16373 2014-12-01 14:00:00,16830 2014-12-01 14:30:00,17470 2014-12-01 15:00:00,18131 2014-12-01 15:30:00,16870 2014-12-01 16:00:00,15192 2014-12-01 16:30:00,14453 2014-12-01 17:00:00,17382 2014-12-01 17:30:00,19815 2014-12-01 18:00:00,21750 2014-12-01 18:30:00,22217 2014-12-01 19:00:00,21813 2014-12-01 19:30:00,21536 2014-12-01 20:00:00,22541 2014-12-01 20:30:00,21329 2014-12-01 21:00:00,20165 2014-12-01 21:30:00,19498 2014-12-01 22:00:00,19355 2014-12-01 22:30:00,16691 2014-12-01 23:00:00,14387 2014-12-01 23:30:00,12101 2014-12-02 00:00:00,9805 2014-12-02 00:30:00,7121 2014-12-02 01:00:00,5019 2014-12-02 01:30:00,3822 2014-12-02 02:00:00,3268 2014-12-02 02:30:00,2261 2014-12-02 03:00:00,1853 2014-12-02 03:30:00,1722 2014-12-02 04:00:00,2077 2014-12-02 04:30:00,1988 2014-12-02 05:00:00,2296 2014-12-02 05:30:00,4537 2014-12-02 06:00:00,6661 2014-12-02 06:30:00,11901 2014-12-02 07:00:00,15501 2014-12-02 07:30:00,19573 2014-12-02 08:00:00,20896 2014-12-02 08:30:00,21051 2014-12-02 09:00:00,19670 2014-12-02 09:30:00,18654 2014-12-02 10:00:00,17108 2014-12-02 10:30:00,17553 2014-12-02 11:00:00,16232 2014-12-02 11:30:00,17534 2014-12-02 12:00:00,17697 2014-12-02 12:30:00,19165 2014-12-02 13:00:00,18916 2014-12-02 13:30:00,19543 2014-12-02 14:00:00,18570 2014-12-02 14:30:00,19043 2014-12-02 15:00:00,18343 2014-12-02 15:30:00,16666 2014-12-02 16:00:00,14050 2014-12-02 16:30:00,12845 2014-12-02 17:00:00,16111 2014-12-02 17:30:00,19112 2014-12-02 18:00:00,21205 2014-12-02 18:30:00,22337 2014-12-02 19:00:00,23340 2014-12-02 19:30:00,23082 2014-12-02 20:00:00,23718 2014-12-02 20:30:00,22936 2014-12-02 21:00:00,23466 2014-12-02 21:30:00,23387 2014-12-02 22:00:00,22893 2014-12-02 22:30:00,20923 2014-12-02 23:00:00,18684 2014-12-02 23:30:00,14962 2014-12-03 00:00:00,12558 2014-12-03 00:30:00,8876 2014-12-03 01:00:00,6626 2014-12-03 01:30:00,4926 2014-12-03 02:00:00,4046 2014-12-03 02:30:00,3168 2014-12-03 03:00:00,2692 2014-12-03 03:30:00,2237 2014-12-03 04:00:00,2384 2014-12-03 04:30:00,2109 2014-12-03 05:00:00,2403 2014-12-03 05:30:00,4250 2014-12-03 06:00:00,6529 2014-12-03 06:30:00,12185 2014-12-03 07:00:00,16016 2014-12-03 07:30:00,19504 2014-12-03 08:00:00,20925 2014-12-03 08:30:00,20891 2014-12-03 09:00:00,20047 2014-12-03 09:30:00,19138 2014-12-03 10:00:00,18431 2014-12-03 10:30:00,16960 2014-12-03 11:00:00,16426 2014-12-03 11:30:00,18092 2014-12-03 12:00:00,19190 2014-12-03 12:30:00,18957 2014-12-03 13:00:00,18288 2014-12-03 13:30:00,18843 2014-12-03 14:00:00,19003 2014-12-03 14:30:00,18193 2014-12-03 15:00:00,17260 2014-12-03 15:30:00,15103 2014-12-03 16:00:00,12941 2014-12-03 16:30:00,11797 2014-12-03 17:00:00,15545 2014-12-03 17:30:00,17938 2014-12-03 18:00:00,20693 2014-12-03 18:30:00,21585 2014-12-03 19:00:00,21689 2014-12-03 19:30:00,21995 2014-12-03 20:00:00,22096 2014-12-03 20:30:00,22115 2014-12-03 21:00:00,21860 2014-12-03 21:30:00,22041 2014-12-03 22:00:00,21680 2014-12-03 22:30:00,21378 2014-12-03 23:00:00,20295 2014-12-03 23:30:00,18176 2014-12-04 00:00:00,14846 2014-12-04 00:30:00,11480 2014-12-04 01:00:00,8939 2014-12-04 01:30:00,6679 2014-12-04 02:00:00,5175 2014-12-04 02:30:00,3800 2014-12-04 03:00:00,3135 2014-12-04 03:30:00,2671 2014-12-04 04:00:00,2843 2014-12-04 04:30:00,2476 2014-12-04 05:00:00,2670 2014-12-04 05:30:00,4521 2014-12-04 06:00:00,6841 2014-12-04 06:30:00,12178 2014-12-04 07:00:00,15916 2014-12-04 07:30:00,19872 2014-12-04 08:00:00,20957 2014-12-04 08:30:00,20358 2014-12-04 09:00:00,19717 2014-12-04 09:30:00,18943 2014-12-04 10:00:00,18082 2014-12-04 10:30:00,18560 2014-12-04 11:00:00,17316 2014-12-04 11:30:00,18817 2014-12-04 12:00:00,18439 2014-12-04 12:30:00,17771 2014-12-04 13:00:00,17214 2014-12-04 13:30:00,17836 2014-12-04 14:00:00,18676 2014-12-04 14:30:00,19241 2014-12-04 15:00:00,19068 2014-12-04 15:30:00,16567 2014-12-04 16:00:00,14529 2014-12-04 16:30:00,12862 2014-12-04 17:00:00,16086 2014-12-04 17:30:00,19221 2014-12-04 18:00:00,21408 2014-12-04 18:30:00,23385 2014-12-04 19:00:00,23604 2014-12-04 19:30:00,23384 2014-12-04 20:00:00,23209 2014-12-04 20:30:00,22592 2014-12-04 21:00:00,23164 2014-12-04 21:30:00,23638 2014-12-04 22:00:00,23192 2014-12-04 22:30:00,22417 2014-12-04 23:00:00,22630 2014-12-04 23:30:00,21278 2014-12-05 00:00:00,19300 2014-12-05 00:30:00,16241 2014-12-05 01:00:00,12966 2014-12-05 01:30:00,10322 2014-12-05 02:00:00,8160 2014-12-05 02:30:00,6611 2014-12-05 03:00:00,5410 2014-12-05 03:30:00,4453 2014-12-05 04:00:00,4287 2014-12-05 04:30:00,3250 2014-12-05 05:00:00,3396 2014-12-05 05:30:00,4846 2014-12-05 06:00:00,7090 2014-12-05 06:30:00,11832 2014-12-05 07:00:00,15506 2014-12-05 07:30:00,20211 2014-12-05 08:00:00,21053 2014-12-05 08:30:00,20635 2014-12-05 09:00:00,20128 2014-12-05 09:30:00,18838 2014-12-05 10:00:00,17936 2014-12-05 10:30:00,18210 2014-12-05 11:00:00,17653 2014-12-05 11:30:00,18847 2014-12-05 12:00:00,18814 2014-12-05 12:30:00,17478 2014-12-05 13:00:00,18029 2014-12-05 13:30:00,18953 2014-12-05 14:00:00,19684 2014-12-05 14:30:00,19747 2014-12-05 15:00:00,18464 2014-12-05 15:30:00,16396 2014-12-05 16:00:00,14436 2014-12-05 16:30:00,13461 2014-12-05 17:00:00,17047 2014-12-05 17:30:00,20614 2014-12-05 18:00:00,23322 2014-12-05 18:30:00,25791 2014-12-05 19:00:00,26650 2014-12-05 19:30:00,26971 2014-12-05 20:00:00,26688 2014-12-05 20:30:00,25508 2014-12-05 21:00:00,26284 2014-12-05 21:30:00,26978 2014-12-05 22:00:00,26983 2014-12-05 22:30:00,25438 2014-12-05 23:00:00,24914 2014-12-05 23:30:00,24165 2014-12-06 00:00:00,22925 2014-12-06 00:30:00,22187 2014-12-06 01:00:00,21493 2014-12-06 01:30:00,19021 2014-12-06 02:00:00,18009 2014-12-06 02:30:00,15786 2014-12-06 03:00:00,13114 2014-12-06 03:30:00,10541 2014-12-06 04:00:00,9296 2014-12-06 04:30:00,5388 2014-12-06 05:00:00,3578 2014-12-06 05:30:00,3205 2014-12-06 06:00:00,3427 2014-12-06 06:30:00,4666 2014-12-06 07:00:00,5262 2014-12-06 07:30:00,7841 2014-12-06 08:00:00,8786 2014-12-06 08:30:00,11893 2014-12-06 09:00:00,12849 2014-12-06 09:30:00,16411 2014-12-06 10:00:00,16917 2014-12-06 10:30:00,19706 2014-12-06 11:00:00,22924 2014-12-06 11:30:00,26224 2014-12-06 12:00:00,25548 2014-12-06 12:30:00,24376 2014-12-06 13:00:00,24464 2014-12-06 13:30:00,23825 2014-12-06 14:00:00,24235 2014-12-06 14:30:00,24001 2014-12-06 15:00:00,23877 2014-12-06 15:30:00,21761 2014-12-06 16:00:00,18277 2014-12-06 16:30:00,15670 2014-12-06 17:00:00,18411 2014-12-06 17:30:00,21332 2014-12-06 18:00:00,23306 2014-12-06 18:30:00,24856 2014-12-06 19:00:00,25798 2014-12-06 19:30:00,25274 2014-12-06 20:00:00,25158 2014-12-06 20:30:00,24164 2014-12-06 21:00:00,23771 2014-12-06 21:30:00,24363 2014-12-06 22:00:00,25705 2014-12-06 22:30:00,26429 2014-12-06 23:00:00,27272 2014-12-06 23:30:00,27636 2014-12-07 00:00:00,26695 2014-12-07 00:30:00,25626 2014-12-07 01:00:00,24285 2014-12-07 01:30:00,22249 2014-12-07 02:00:00,20741 2014-12-07 02:30:00,18554 2014-12-07 03:00:00,15770 2014-12-07 03:30:00,13976 2014-12-07 04:00:00,11368 2014-12-07 04:30:00,6531 2014-12-07 05:00:00,3929 2014-12-07 05:30:00,3236 2014-12-07 06:00:00,3177 2014-12-07 06:30:00,3757 2014-12-07 07:00:00,4042 2014-12-07 07:30:00,5401 2014-12-07 08:00:00,6483 2014-12-07 08:30:00,9264 2014-12-07 09:00:00,11497 2014-12-07 09:30:00,14585 2014-12-07 10:00:00,16159 2014-12-07 10:30:00,20205 2014-12-07 11:00:00,21146 2014-12-07 11:30:00,22387 2014-12-07 12:00:00,23081 2014-12-07 12:30:00,23163 2014-12-07 13:00:00,22660 2014-12-07 13:30:00,22127 2014-12-07 14:00:00,22237 2014-12-07 14:30:00,22193 2014-12-07 15:00:00,21252 2014-12-07 15:30:00,20818 2014-12-07 16:00:00,19110 2014-12-07 16:30:00,17255 2014-12-07 17:00:00,18368 2014-12-07 17:30:00,20327 2014-12-07 18:00:00,21411 2014-12-07 18:30:00,21379 2014-12-07 19:00:00,21735 2014-12-07 19:30:00,20031 2014-12-07 20:00:00,18305 2014-12-07 20:30:00,17961 2014-12-07 21:00:00,17334 2014-12-07 21:30:00,17401 2014-12-07 22:00:00,17020 2014-12-07 22:30:00,14661 2014-12-07 23:00:00,12367 2014-12-07 23:30:00,10891 2014-12-08 00:00:00,8141 2014-12-08 00:30:00,6411 2014-12-08 01:00:00,4762 2014-12-08 01:30:00,3616 2014-12-08 02:00:00,3130 2014-12-08 02:30:00,2273 2014-12-08 03:00:00,2031 2014-12-08 03:30:00,1788 2014-12-08 04:00:00,2203 2014-12-08 04:30:00,2270 2014-12-08 05:00:00,2727 2014-12-08 05:30:00,4686 2014-12-08 06:00:00,6827 2014-12-08 06:30:00,11984 2014-12-08 07:00:00,14644 2014-12-08 07:30:00,18338 2014-12-08 08:00:00,19590 2014-12-08 08:30:00,19762 2014-12-08 09:00:00,19372 2014-12-08 09:30:00,18754 2014-12-08 10:00:00,17736 2014-12-08 10:30:00,17624 2014-12-08 11:00:00,16856 2014-12-08 11:30:00,18005 2014-12-08 12:00:00,18028 2014-12-08 12:30:00,17733 2014-12-08 13:00:00,17678 2014-12-08 13:30:00,18275 2014-12-08 14:00:00,18070 2014-12-08 14:30:00,19038 2014-12-08 15:00:00,18998 2014-12-08 15:30:00,16932 2014-12-08 16:00:00,15201 2014-12-08 16:30:00,14426 2014-12-08 17:00:00,16942 2014-12-08 17:30:00,19768 2014-12-08 18:00:00,21911 2014-12-08 18:30:00,22917 2014-12-08 19:00:00,23371 2014-12-08 19:30:00,23343 2014-12-08 20:00:00,22358 2014-12-08 20:30:00,22302 2014-12-08 21:00:00,22712 2014-12-08 21:30:00,22329 2014-12-08 22:00:00,21979 2014-12-08 22:30:00,19387 2014-12-08 23:00:00,17494 2014-12-08 23:30:00,13745 2014-12-09 00:00:00,11339 2014-12-09 00:30:00,8699 2014-12-09 01:00:00,6796 2014-12-09 01:30:00,5236 2014-12-09 02:00:00,3800 2014-12-09 02:30:00,3042 2014-12-09 03:00:00,2532 2014-12-09 03:30:00,2258 2014-12-09 04:00:00,2212 2014-12-09 04:30:00,2135 2014-12-09 05:00:00,2592 2014-12-09 05:30:00,4617 2014-12-09 06:00:00,8006 2014-12-09 06:30:00,13619 2014-12-09 07:00:00,16700 2014-12-09 07:30:00,19651 2014-12-09 08:00:00,20630 2014-12-09 08:30:00,21217 2014-12-09 09:00:00,19857 2014-12-09 09:30:00,18753 2014-12-09 10:00:00,17813 2014-12-09 10:30:00,17833 2014-12-09 11:00:00,17164 2014-12-09 11:30:00,18181 2014-12-09 12:00:00,17482 2014-12-09 12:30:00,15676 2014-12-09 13:00:00,16018 2014-12-09 13:30:00,17066 2014-12-09 14:00:00,17654 2014-12-09 14:30:00,17696 2014-12-09 15:00:00,16781 2014-12-09 15:30:00,14189 2014-12-09 16:00:00,12461 2014-12-09 16:30:00,12252 2014-12-09 17:00:00,15431 2014-12-09 17:30:00,18137 2014-12-09 18:00:00,20649 2014-12-09 18:30:00,21989 2014-12-09 19:00:00,22350 2014-12-09 19:30:00,22177 2014-12-09 20:00:00,22991 2014-12-09 20:30:00,22128 2014-12-09 21:00:00,23207 2014-12-09 21:30:00,23091 2014-12-09 22:00:00,22616 2014-12-09 22:30:00,21118 2014-12-09 23:00:00,19301 2014-12-09 23:30:00,16789 2014-12-10 00:00:00,14252 2014-12-10 00:30:00,10138 2014-12-10 01:00:00,7847 2014-12-10 01:30:00,5782 2014-12-10 02:00:00,4951 2014-12-10 02:30:00,3696 2014-12-10 03:00:00,2833 2014-12-10 03:30:00,2375 2014-12-10 04:00:00,2533 2014-12-10 04:30:00,2423 2014-12-10 05:00:00,2512 2014-12-10 05:30:00,4337 2014-12-10 06:00:00,6721 2014-12-10 06:30:00,11812 2014-12-10 07:00:00,16054 2014-12-10 07:30:00,19337 2014-12-10 08:00:00,21348 2014-12-10 08:30:00,21167 2014-12-10 09:00:00,20051 2014-12-10 09:30:00,18809 2014-12-10 10:00:00,17812 2014-12-10 10:30:00,17889 2014-12-10 11:00:00,17482 2014-12-10 11:30:00,18775 2014-12-10 12:00:00,18351 2014-12-10 12:30:00,17604 2014-12-10 13:00:00,17729 2014-12-10 13:30:00,17499 2014-12-10 14:00:00,17558 2014-12-10 14:30:00,18070 2014-12-10 15:00:00,17422 2014-12-10 15:30:00,14666 2014-12-10 16:00:00,12252 2014-12-10 16:30:00,11174 2014-12-10 17:00:00,13853 2014-12-10 17:30:00,16962 2014-12-10 18:00:00,19708 2014-12-10 18:30:00,20764 2014-12-10 19:00:00,21802 2014-12-10 19:30:00,22239 2014-12-10 20:00:00,22169 2014-12-10 20:30:00,23923 2014-12-10 21:00:00,24403 2014-12-10 21:30:00,24211 2014-12-10 22:00:00,23439 2014-12-10 22:30:00,23394 2014-12-10 23:00:00,21701 2014-12-10 23:30:00,19727 2014-12-11 00:00:00,17270 2014-12-11 00:30:00,13379 2014-12-11 01:00:00,10314 2014-12-11 01:30:00,7470 2014-12-11 02:00:00,6039 2014-12-11 02:30:00,4322 2014-12-11 03:00:00,3461 2014-12-11 03:30:00,2872 2014-12-11 04:00:00,2854 2014-12-11 04:30:00,2422 2014-12-11 05:00:00,2578 2014-12-11 05:30:00,4513 2014-12-11 06:00:00,6672 2014-12-11 06:30:00,12358 2014-12-11 07:00:00,15790 2014-12-11 07:30:00,19441 2014-12-11 08:00:00,20920 2014-12-11 08:30:00,20665 2014-12-11 09:00:00,19708 2014-12-11 09:30:00,20066 2014-12-11 10:00:00,18424 2014-12-11 10:30:00,18403 2014-12-11 11:00:00,17621 2014-12-11 11:30:00,18994 2014-12-11 12:00:00,18845 2014-12-11 12:30:00,17937 2014-12-11 13:00:00,17974 2014-12-11 13:30:00,18671 2014-12-11 14:00:00,19082 2014-12-11 14:30:00,20224 2014-12-11 15:00:00,18966 2014-12-11 15:30:00,16165 2014-12-11 16:00:00,14013 2014-12-11 16:30:00,12246 2014-12-11 17:00:00,15021 2014-12-11 17:30:00,18834 2014-12-11 18:00:00,21115 2014-12-11 18:30:00,22746 2014-12-11 19:00:00,23679 2014-12-11 19:30:00,23992 2014-12-11 20:00:00,23597 2014-12-11 20:30:00,23581 2014-12-11 21:00:00,24093 2014-12-11 21:30:00,24130 2014-12-11 22:00:00,24027 2014-12-11 22:30:00,23575 2014-12-11 23:00:00,22502 2014-12-11 23:30:00,22049 2014-12-12 00:00:00,20667 2014-12-12 00:30:00,19265 2014-12-12 01:00:00,16192 2014-12-12 01:30:00,12814 2014-12-12 02:00:00,10410 2014-12-12 02:30:00,8218 2014-12-12 03:00:00,6335 2014-12-12 03:30:00,5377 2014-12-12 04:00:00,4659 2014-12-12 04:30:00,3597 2014-12-12 05:00:00,3208 2014-12-12 05:30:00,4698 2014-12-12 06:00:00,6900 2014-12-12 06:30:00,12308 2014-12-12 07:00:00,15444 2014-12-12 07:30:00,19511 2014-12-12 08:00:00,20489 2014-12-12 08:30:00,20834 2014-12-12 09:00:00,19854 2014-12-12 09:30:00,18687 2014-12-12 10:00:00,18014 2014-12-12 10:30:00,18564 2014-12-12 11:00:00,18237 2014-12-12 11:30:00,18916 2014-12-12 12:00:00,18244 2014-12-12 12:30:00,16850 2014-12-12 13:00:00,17845 2014-12-12 13:30:00,18162 2014-12-12 14:00:00,19043 2014-12-12 14:30:00,19128 2014-12-12 15:00:00,18287 2014-12-12 15:30:00,15667 2014-12-12 16:00:00,13938 2014-12-12 16:30:00,12626 2014-12-12 17:00:00,15807 2014-12-12 17:30:00,19375 2014-12-12 18:00:00,21905 2014-12-12 18:30:00,24008 2014-12-12 19:00:00,25410 2014-12-12 19:30:00,25568 2014-12-12 20:00:00,24888 2014-12-12 20:30:00,25190 2014-12-12 21:00:00,25350 2014-12-12 21:30:00,25927 2014-12-12 22:00:00,26737 2014-12-12 22:30:00,26771 2014-12-12 23:00:00,26180 2014-12-12 23:30:00,25739 2014-12-13 00:00:00,24743 2014-12-13 00:30:00,24285 2014-12-13 01:00:00,22826 2014-12-13 01:30:00,21266 2014-12-13 02:00:00,19907 2014-12-13 02:30:00,17053 2014-12-13 03:00:00,14423 2014-12-13 03:30:00,12363 2014-12-13 04:00:00,10600 2014-12-13 04:30:00,6501 2014-12-13 05:00:00,4211 2014-12-13 05:30:00,3425 2014-12-13 06:00:00,3475 2014-12-13 06:30:00,5132 2014-12-13 07:00:00,4986 2014-12-13 07:30:00,7716 2014-12-13 08:00:00,8873 2014-12-13 08:30:00,12361 2014-12-13 09:00:00,13217 2014-12-13 09:30:00,17706 2014-12-13 10:00:00,19199 2014-12-13 10:30:00,21605 2014-12-13 11:00:00,22106 2014-12-13 11:30:00,23452 2014-12-13 12:00:00,24095 2014-12-13 12:30:00,24114 2014-12-13 13:00:00,24368 2014-12-13 13:30:00,23648 2014-12-13 14:00:00,22929 2014-12-13 14:30:00,22531 2014-12-13 15:00:00,21489 2014-12-13 15:30:00,19081 2014-12-13 16:00:00,15734 2014-12-13 16:30:00,13140 2014-12-13 17:00:00,15041 2014-12-13 17:30:00,17961 2014-12-13 18:00:00,20757 2014-12-13 18:30:00,22233 2014-12-13 19:00:00,23550 2014-12-13 19:30:00,24311 2014-12-13 20:00:00,24320 2014-12-13 20:30:00,23465 2014-12-13 21:00:00,24125 2014-12-13 21:30:00,24696 2014-12-13 22:00:00,24848 2014-12-13 22:30:00,25952 2014-12-13 23:00:00,26481 2014-12-13 23:30:00,26376 2014-12-14 00:00:00,26065 2014-12-14 00:30:00,25745 2014-12-14 01:00:00,24053 2014-12-14 01:30:00,22288 2014-12-14 02:00:00,21263 2014-12-14 02:30:00,18637 2014-12-14 03:00:00,16106 2014-12-14 03:30:00,13609 2014-12-14 04:00:00,11786 2014-12-14 04:30:00,6978 2014-12-14 05:00:00,4468 2014-12-14 05:30:00,3728 2014-12-14 06:00:00,3611 2014-12-14 06:30:00,3909 2014-12-14 07:00:00,4139 2014-12-14 07:30:00,5583 2014-12-14 08:00:00,6831 2014-12-14 08:30:00,8929 2014-12-14 09:00:00,10358 2014-12-14 09:30:00,14261 2014-12-14 10:00:00,16254 2014-12-14 10:30:00,19993 2014-12-14 11:00:00,20203 2014-12-14 11:30:00,21630 2014-12-14 12:00:00,22210 2014-12-14 12:30:00,22458 2014-12-14 13:00:00,21793 2014-12-14 13:30:00,21177 2014-12-14 14:00:00,20831 2014-12-14 14:30:00,20577 2014-12-14 15:00:00,20293 2014-12-14 15:30:00,18839 2014-12-14 16:00:00,17406 2014-12-14 16:30:00,15292 2014-12-14 17:00:00,16443 2014-12-14 17:30:00,17727 2014-12-14 18:00:00,18988 2014-12-14 18:30:00,19533 2014-12-14 19:00:00,19548 2014-12-14 19:30:00,18055 2014-12-14 20:00:00,17006 2014-12-14 20:30:00,16671 2014-12-14 21:00:00,16007 2014-12-14 21:30:00,16344 2014-12-14 22:00:00,15913 2014-12-14 22:30:00,14327 2014-12-14 23:00:00,12060 2014-12-14 23:30:00,10952 2014-12-15 00:00:00,9228 2014-12-15 00:30:00,6754 2014-12-15 01:00:00,5230 2014-12-15 01:30:00,4058 2014-12-15 02:00:00,3386 2014-12-15 02:30:00,2854 2014-12-15 03:00:00,2088 2014-12-15 03:30:00,2063 2014-12-15 04:00:00,2573 2014-12-15 04:30:00,2606 2014-12-15 05:00:00,3027 2014-12-15 05:30:00,4795 2014-12-15 06:00:00,7029 2014-12-15 06:30:00,11534 2014-12-15 07:00:00,14434 2014-12-15 07:30:00,17808 2014-12-15 08:00:00,18371 2014-12-15 08:30:00,18743 2014-12-15 09:00:00,17992 2014-12-15 09:30:00,17405 2014-12-15 10:00:00,16508 2014-12-15 10:30:00,15778 2014-12-15 11:00:00,15424 2014-12-15 11:30:00,16627 2014-12-15 12:00:00,16484 2014-12-15 12:30:00,16637 2014-12-15 13:00:00,16135 2014-12-15 13:30:00,16513 2014-12-15 14:00:00,17025 2014-12-15 14:30:00,18231 2014-12-15 15:00:00,17722 2014-12-15 15:30:00,16477 2014-12-15 16:00:00,14298 2014-12-15 16:30:00,13229 2014-12-15 17:00:00,15523 2014-12-15 17:30:00,17795 2014-12-15 18:00:00,20424 2014-12-15 18:30:00,21017 2014-12-15 19:00:00,21475 2014-12-15 19:30:00,22549 2014-12-15 20:00:00,21924 2014-12-15 20:30:00,21131 2014-12-15 21:00:00,21393 2014-12-15 21:30:00,21577 2014-12-15 22:00:00,21019 2014-12-15 22:30:00,18908 2014-12-15 23:00:00,17370 2014-12-15 23:30:00,13782 2014-12-16 00:00:00,11608 2014-12-16 00:30:00,8753 2014-12-16 01:00:00,6959 2014-12-16 01:30:00,5332 2014-12-16 02:00:00,4417 2014-12-16 02:30:00,3812 2014-12-16 03:00:00,2785 2014-12-16 03:30:00,2230 2014-12-16 04:00:00,2383 2014-12-16 04:30:00,2206 2014-12-16 05:00:00,2455 2014-12-16 05:30:00,4355 2014-12-16 06:00:00,6534 2014-12-16 06:30:00,11684 2014-12-16 07:00:00,14785 2014-12-16 07:30:00,18872 2014-12-16 08:00:00,19244 2014-12-16 08:30:00,20521 2014-12-16 09:00:00,19197 2014-12-16 09:30:00,18299 2014-12-16 10:00:00,17178 2014-12-16 10:30:00,16812 2014-12-16 11:00:00,16250 2014-12-16 11:30:00,17275 2014-12-16 12:00:00,17818 2014-12-16 12:30:00,17228 2014-12-16 13:00:00,16423 2014-12-16 13:30:00,17067 2014-12-16 14:00:00,17759 2014-12-16 14:30:00,18175 2014-12-16 15:00:00,17997 2014-12-16 15:30:00,16045 2014-12-16 16:00:00,14086 2014-12-16 16:30:00,12498 2014-12-16 17:00:00,15616 2014-12-16 17:30:00,17897 2014-12-16 18:00:00,20215 2014-12-16 18:30:00,21911 2014-12-16 19:00:00,22798 2014-12-16 19:30:00,24359 2014-12-16 20:00:00,23687 2014-12-16 20:30:00,23843 2014-12-16 21:00:00,23849 2014-12-16 21:30:00,24686 2014-12-16 22:00:00,23566 2014-12-16 22:30:00,22591 2014-12-16 23:00:00,20184 2014-12-16 23:30:00,17824 2014-12-17 00:00:00,14522 2014-12-17 00:30:00,10981 2014-12-17 01:00:00,8494 2014-12-17 01:30:00,6739 2014-12-17 02:00:00,5562 2014-12-17 02:30:00,4095 2014-12-17 03:00:00,3228 2014-12-17 03:30:00,2801 2014-12-17 04:00:00,2905 2014-12-17 04:30:00,2604 2014-12-17 05:00:00,2634 2014-12-17 05:30:00,4453 2014-12-17 06:00:00,6610 2014-12-17 06:30:00,11882 2014-12-17 07:00:00,15378 2014-12-17 07:30:00,18958 2014-12-17 08:00:00,20241 2014-12-17 08:30:00,20321 2014-12-17 09:00:00,19626 2014-12-17 09:30:00,18615 2014-12-17 10:00:00,17801 2014-12-17 10:30:00,17622 2014-12-17 11:00:00,17122 2014-12-17 11:30:00,18747 2014-12-17 12:00:00,18708 2014-12-17 12:30:00,18308 2014-12-17 13:00:00,17777 2014-12-17 13:30:00,17824 2014-12-17 14:00:00,18196 2014-12-17 14:30:00,18499 2014-12-17 15:00:00,18003 2014-12-17 15:30:00,16052 2014-12-17 16:00:00,13607 2014-12-17 16:30:00,12212 2014-12-17 17:00:00,14983 2014-12-17 17:30:00,18285 2014-12-17 18:00:00,20665 2014-12-17 18:30:00,21841 2014-12-17 19:00:00,23081 2014-12-17 19:30:00,22785 2014-12-17 20:00:00,24069 2014-12-17 20:30:00,24039 2014-12-17 21:00:00,25073 2014-12-17 21:30:00,24980 2014-12-17 22:00:00,24878 2014-12-17 22:30:00,23338 2014-12-17 23:00:00,22407 2014-12-17 23:30:00,20950 2014-12-18 00:00:00,18285 2014-12-18 00:30:00,14827 2014-12-18 01:00:00,10904 2014-12-18 01:30:00,8901 2014-12-18 02:00:00,6765 2014-12-18 02:30:00,5188 2014-12-18 03:00:00,3823 2014-12-18 03:30:00,3524 2014-12-18 04:00:00,3414 2014-12-18 04:30:00,2681 2014-12-18 05:00:00,3079 2014-12-18 05:30:00,4828 2014-12-18 06:00:00,7029 2014-12-18 06:30:00,12063 2014-12-18 07:00:00,15230 2014-12-18 07:30:00,18835 2014-12-18 08:00:00,20484 2014-12-18 08:30:00,20222 2014-12-18 09:00:00,19752 2014-12-18 09:30:00,18914 2014-12-18 10:00:00,18466 2014-12-18 10:30:00,18364 2014-12-18 11:00:00,17439 2014-12-18 11:30:00,19228 2014-12-18 12:00:00,19485 2014-12-18 12:30:00,18539 2014-12-18 13:00:00,18424 2014-12-18 13:30:00,18594 2014-12-18 14:00:00,19253 2014-12-18 14:30:00,19536 2014-12-18 15:00:00,19129 2014-12-18 15:30:00,16419 2014-12-18 16:00:00,14143 2014-12-18 16:30:00,12440 2014-12-18 17:00:00,15352 2014-12-18 17:30:00,19402 2014-12-18 18:00:00,21772 2014-12-18 18:30:00,23309 2014-12-18 19:00:00,24617 2014-12-18 19:30:00,24906 2014-12-18 20:00:00,25149 2014-12-18 20:30:00,25441 2014-12-18 21:00:00,26065 2014-12-18 21:30:00,25822 2014-12-18 22:00:00,25738 2014-12-18 22:30:00,24879 2014-12-18 23:00:00,24496 2014-12-18 23:30:00,23501 2014-12-19 00:00:00,20698 2014-12-19 00:30:00,19243 2014-12-19 01:00:00,16900 2014-12-19 01:30:00,13421 2014-12-19 02:00:00,10585 2014-12-19 02:30:00,8512 2014-12-19 03:00:00,6744 2014-12-19 03:30:00,5653 2014-12-19 04:00:00,5420 2014-12-19 04:30:00,3982 2014-12-19 05:00:00,3682 2014-12-19 05:30:00,4979 2014-12-19 06:00:00,6847 2014-12-19 06:30:00,11330 2014-12-19 07:00:00,14716 2014-12-19 07:30:00,18996 2014-12-19 08:00:00,20784 2014-12-19 08:30:00,20763 2014-12-19 09:00:00,21030 2014-12-19 09:30:00,19778 2014-12-19 10:00:00,18496 2014-12-19 10:30:00,18800 2014-12-19 11:00:00,18765 2014-12-19 11:30:00,20209 2014-12-19 12:00:00,19684 2014-12-19 12:30:00,18093 2014-12-19 13:00:00,17958 2014-12-19 13:30:00,18794 2014-12-19 14:00:00,19592 2014-12-19 14:30:00,20240 2014-12-19 15:00:00,19125 2014-12-19 15:30:00,16262 2014-12-19 16:00:00,14858 2014-12-19 16:30:00,12685 2014-12-19 17:00:00,15752 2014-12-19 17:30:00,19931 2014-12-19 18:00:00,22925 2014-12-19 18:30:00,24921 2014-12-19 19:00:00,26335 2014-12-19 19:30:00,26896 2014-12-19 20:00:00,26796 2014-12-19 20:30:00,25989 2014-12-19 21:00:00,26280 2014-12-19 21:30:00,26403 2014-12-19 22:00:00,26905 2014-12-19 22:30:00,26723 2014-12-19 23:00:00,25807 2014-12-19 23:30:00,26432 2014-12-20 00:00:00,25976 2014-12-20 00:30:00,24322 2014-12-20 01:00:00,22993 2014-12-20 01:30:00,21186 2014-12-20 02:00:00,19390 2014-12-20 02:30:00,16298 2014-12-20 03:00:00,14308 2014-12-20 03:30:00,12289 2014-12-20 04:00:00,10822 2014-12-20 04:30:00,6612 2014-12-20 05:00:00,4648 2014-12-20 05:30:00,3998 2014-12-20 06:00:00,4080 2014-12-20 06:30:00,5139 2014-12-20 07:00:00,4833 2014-12-20 07:30:00,6360 2014-12-20 08:00:00,7568 2014-12-20 08:30:00,10329 2014-12-20 09:00:00,11646 2014-12-20 09:30:00,15228 2014-12-20 10:00:00,16173 2014-12-20 10:30:00,18920 2014-12-20 11:00:00,19813 2014-12-20 11:30:00,21529 2014-12-20 12:00:00,22544 2014-12-20 12:30:00,22751 2014-12-20 13:00:00,22744 2014-12-20 13:30:00,22263 2014-12-20 14:00:00,22212 2014-12-20 14:30:00,21906 2014-12-20 15:00:00,21744 2014-12-20 15:30:00,21173 2014-12-20 16:00:00,18061 2014-12-20 16:30:00,15360 2014-12-20 17:00:00,17470 2014-12-20 17:30:00,20909 2014-12-20 18:00:00,22562 2014-12-20 18:30:00,24471 2014-12-20 19:00:00,25685 2014-12-20 19:30:00,25252 2014-12-20 20:00:00,23238 2014-12-20 20:30:00,22683 2014-12-20 21:00:00,22523 2014-12-20 21:30:00,23214 2014-12-20 22:00:00,23741 2014-12-20 22:30:00,24614 2014-12-20 23:00:00,25195 2014-12-20 23:30:00,25864 2014-12-21 00:00:00,25530 2014-12-21 00:30:00,24429 2014-12-21 01:00:00,22976 2014-12-21 01:30:00,21027 2014-12-21 02:00:00,19741 2014-12-21 02:30:00,17359 2014-12-21 03:00:00,15156 2014-12-21 03:30:00,12970 2014-12-21 04:00:00,11246 2014-12-21 04:30:00,6712 2014-12-21 05:00:00,4593 2014-12-21 05:30:00,3675 2014-12-21 06:00:00,3974 2014-12-21 06:30:00,3929 2014-12-21 07:00:00,3922 2014-12-21 07:30:00,5061 2014-12-21 08:00:00,5995 2014-12-21 08:30:00,7813 2014-12-21 09:00:00,9237 2014-12-21 09:30:00,12647 2014-12-21 10:00:00,13946 2014-12-21 10:30:00,18143 2014-12-21 11:00:00,18415 2014-12-21 11:30:00,19646 2014-12-21 12:00:00,20124 2014-12-21 12:30:00,21235 2014-12-21 13:00:00,20709 2014-12-21 13:30:00,20382 2014-12-21 14:00:00,20570 2014-12-21 14:30:00,20093 2014-12-21 15:00:00,19670 2014-12-21 15:30:00,19194 2014-12-21 16:00:00,17506 2014-12-21 16:30:00,15650 2014-12-21 17:00:00,17057 2014-12-21 17:30:00,19010 2014-12-21 18:00:00,19688 2014-12-21 18:30:00,19461 2014-12-21 19:00:00,19098 2014-12-21 19:30:00,17989 2014-12-21 20:00:00,16406 2014-12-21 20:30:00,16716 2014-12-21 21:00:00,15983 2014-12-21 21:30:00,16304 2014-12-21 22:00:00,15546 2014-12-21 22:30:00,13653 2014-12-21 23:00:00,12018 2014-12-21 23:30:00,10392 2014-12-22 00:00:00,8488 2014-12-22 00:30:00,6812 2014-12-22 01:00:00,5155 2014-12-22 01:30:00,4081 2014-12-22 02:00:00,3429 2014-12-22 02:30:00,2686 2014-12-22 03:00:00,2341 2014-12-22 03:30:00,2080 2014-12-22 04:00:00,2561 2014-12-22 04:30:00,2438 2014-12-22 05:00:00,2549 2014-12-22 05:30:00,4003 2014-12-22 06:00:00,5410 2014-12-22 06:30:00,9139 2014-12-22 07:00:00,10980 2014-12-22 07:30:00,13351 2014-12-22 08:00:00,14666 2014-12-22 08:30:00,16540 2014-12-22 09:00:00,16439 2014-12-22 09:30:00,16681 2014-12-22 10:00:00,15663 2014-12-22 10:30:00,16128 2014-12-22 11:00:00,16377 2014-12-22 11:30:00,17607 2014-12-22 12:00:00,17770 2014-12-22 12:30:00,17843 2014-12-22 13:00:00,17279 2014-12-22 13:30:00,18264 2014-12-22 14:00:00,18359 2014-12-22 14:30:00,18664 2014-12-22 15:00:00,18428 2014-12-22 15:30:00,15976 2014-12-22 16:00:00,13994 2014-12-22 16:30:00,12958 2014-12-22 17:00:00,15433 2014-12-22 17:30:00,17793 2014-12-22 18:00:00,19903 2014-12-22 18:30:00,20358 2014-12-22 19:00:00,20800 2014-12-22 19:30:00,19898 2014-12-22 20:00:00,18981 2014-12-22 20:30:00,19600 2014-12-22 21:00:00,19672 2014-12-22 21:30:00,20359 2014-12-22 22:00:00,19147 2014-12-22 22:30:00,17490 2014-12-22 23:00:00,14392 2014-12-22 23:30:00,12366 2014-12-23 00:00:00,10077 2014-12-23 00:30:00,8426 2014-12-23 01:00:00,7343 2014-12-23 01:30:00,5818 2014-12-23 02:00:00,4395 2014-12-23 02:30:00,3238 2014-12-23 03:00:00,2837 2014-12-23 03:30:00,2628 2014-12-23 04:00:00,2815 2014-12-23 04:30:00,2524 2014-12-23 05:00:00,2749 2014-12-23 05:30:00,4221 2014-12-23 06:00:00,5790 2014-12-23 06:30:00,9106 2014-12-23 07:00:00,10805 2014-12-23 07:30:00,13627 2014-12-23 08:00:00,14896 2014-12-23 08:30:00,16914 2014-12-23 09:00:00,16813 2014-12-23 09:30:00,17257 2014-12-23 10:00:00,16746 2014-12-23 10:30:00,16668 2014-12-23 11:00:00,16334 2014-12-23 11:30:00,17869 2014-12-23 12:00:00,18559 2014-12-23 12:30:00,18627 2014-12-23 13:00:00,18394 2014-12-23 13:30:00,19529 2014-12-23 14:00:00,18765 2014-12-23 14:30:00,19273 2014-12-23 15:00:00,18364 2014-12-23 15:30:00,16426 2014-12-23 16:00:00,13940 2014-12-23 16:30:00,12171 2014-12-23 17:00:00,14585 2014-12-23 17:30:00,16878 2014-12-23 18:00:00,19444 2014-12-23 18:30:00,20377 2014-12-23 19:00:00,20065 2014-12-23 19:30:00,19194 2014-12-23 20:00:00,18589 2014-12-23 20:30:00,17560 2014-12-23 21:00:00,17394 2014-12-23 21:30:00,18424 2014-12-23 22:00:00,16611 2014-12-23 22:30:00,15547 2014-12-23 23:00:00,14391 2014-12-23 23:30:00,12687 2014-12-24 00:00:00,11488 2014-12-24 00:30:00,9158 2014-12-24 01:00:00,7484 2014-12-24 01:30:00,6303 2014-12-24 02:00:00,5454 2014-12-24 02:30:00,4400 2014-12-24 03:00:00,3409 2014-12-24 03:30:00,3301 2014-12-24 04:00:00,3479 2014-12-24 04:30:00,2809 2014-12-24 05:00:00,2713 2014-12-24 05:30:00,3654 2014-12-24 06:00:00,4943 2014-12-24 06:30:00,6952 2014-12-24 07:00:00,7357 2014-12-24 07:30:00,9019 2014-12-24 08:00:00,9982 2014-12-24 08:30:00,12036 2014-12-24 09:00:00,13416 2014-12-24 09:30:00,16386 2014-12-24 10:00:00,18242 2014-12-24 10:30:00,17436 2014-12-24 11:00:00,19281 2014-12-24 11:30:00,18939 2014-12-24 12:00:00,18558 2014-12-24 12:30:00,20400 2014-12-24 13:00:00,21494 2014-12-24 13:30:00,19961 2014-12-24 14:00:00,19618 2014-12-24 14:30:00,17870 2014-12-24 15:00:00,17549 2014-12-24 15:30:00,17387 2014-12-24 16:00:00,15882 2014-12-24 16:30:00,15280 2014-12-24 17:00:00,16907 2014-12-24 17:30:00,16821 2014-12-24 18:00:00,17096 2014-12-24 18:30:00,16830 2014-12-24 19:00:00,15846 2014-12-24 19:30:00,14421 2014-12-24 20:00:00,13101 2014-12-24 20:30:00,13010 2014-12-24 21:00:00,12453 2014-12-24 21:30:00,12904 2014-12-24 22:00:00,12563 2014-12-24 22:30:00,12915 2014-12-24 23:00:00,12169 2014-12-24 23:30:00,11420 2014-12-25 00:00:00,10665 2014-12-25 00:30:00,9890 2014-12-25 01:00:00,8488 2014-12-25 01:30:00,7209 2014-12-25 02:00:00,6240 2014-12-25 02:30:00,5143 2014-12-25 03:00:00,4003 2014-12-25 03:30:00,3414 2014-12-25 04:00:00,3206 2014-12-25 04:30:00,2193 2014-12-25 05:00:00,1801 2014-12-25 05:30:00,1756 2014-12-25 06:00:00,2144 2014-12-25 06:30:00,2710 2014-12-25 07:00:00,2637 2014-12-25 07:30:00,3029 2014-12-25 08:00:00,2926 2014-12-25 08:30:00,3485 2014-12-25 09:00:00,4195 2014-12-25 09:30:00,5410 2014-12-25 10:00:00,6572 2014-12-25 10:30:00,7857 2014-12-25 11:00:00,8586 2014-12-25 11:30:00,9599 2014-12-25 12:00:00,10158 2014-12-25 12:30:00,10843 2014-12-25 13:00:00,10618 2014-12-25 13:30:00,11206 2014-12-25 14:00:00,11176 2014-12-25 14:30:00,12218 2014-12-25 15:00:00,12039 2014-12-25 15:30:00,11754 2014-12-25 16:00:00,11282 2014-12-25 16:30:00,10380 2014-12-25 17:00:00,10642 2014-12-25 17:30:00,10788 2014-12-25 18:00:00,10786 2014-12-25 18:30:00,11433 2014-12-25 19:00:00,11262 2014-12-25 19:30:00,10510 2014-12-25 20:00:00,9827 2014-12-25 20:30:00,10446 2014-12-25 21:00:00,10164 2014-12-25 21:30:00,11279 2014-12-25 22:00:00,10756 2014-12-25 22:30:00,10622 2014-12-25 23:00:00,8270 2014-12-25 23:30:00,7685 2014-12-26 00:00:00,6540 2014-12-26 00:30:00,5312 2014-12-26 01:00:00,4573 2014-12-26 01:30:00,3322 2014-12-26 02:00:00,2840 2014-12-26 02:30:00,2294 2014-12-26 03:00:00,1888 2014-12-26 03:30:00,1628 2014-12-26 04:00:00,1962 2014-12-26 04:30:00,1541 2014-12-26 05:00:00,1459 2014-12-26 05:30:00,1993 2014-12-26 06:00:00,2763 2014-12-26 06:30:00,3830 2014-12-26 07:00:00,4376 2014-12-26 07:30:00,5533 2014-12-26 08:00:00,6342 2014-12-26 08:30:00,7425 2014-12-26 09:00:00,8473 2014-12-26 09:30:00,9288 2014-12-26 10:00:00,10259 2014-12-26 10:30:00,10994 2014-12-26 11:00:00,11708 2014-12-26 11:30:00,13105 2014-12-26 12:00:00,13577 2014-12-26 12:30:00,14110 2014-12-26 13:00:00,14559 2014-12-26 13:30:00,14063 2014-12-26 14:00:00,14506 2014-12-26 14:30:00,15863 2014-12-26 15:00:00,16608 2014-12-26 15:30:00,15959 2014-12-26 16:00:00,15481 2014-12-26 16:30:00,14491 2014-12-26 17:00:00,15597 2014-12-26 17:30:00,16349 2014-12-26 18:00:00,16711 2014-12-26 18:30:00,16708 2014-12-26 19:00:00,18113 2014-12-26 19:30:00,16700 2014-12-26 20:00:00,15087 2014-12-26 20:30:00,15282 2014-12-26 21:00:00,14797 2014-12-26 21:30:00,14744 2014-12-26 22:00:00,15618 2014-12-26 22:30:00,16172 2014-12-26 23:00:00,14863 2014-12-26 23:30:00,13696 2014-12-27 00:00:00,13396 2014-12-27 00:30:00,12040 2014-12-27 01:00:00,11298 2014-12-27 01:30:00,10005 2014-12-27 02:00:00,9368 2014-12-27 02:30:00,8002 2014-12-27 03:00:00,7493 2014-12-27 03:30:00,6509 2014-12-27 04:00:00,5928 2014-12-27 04:30:00,4158 2014-12-27 05:00:00,2648 2014-12-27 05:30:00,2313 2014-12-27 06:00:00,2391 2014-12-27 06:30:00,2821 2014-12-27 07:00:00,2967 2014-12-27 07:30:00,4013 2014-12-27 08:00:00,4505 2014-12-27 08:30:00,6117 2014-12-27 09:00:00,7591 2014-12-27 09:30:00,9467 2014-12-27 10:00:00,10065 2014-12-27 10:30:00,11788 2014-12-27 11:00:00,12882 2014-12-27 11:30:00,14317 2014-12-27 12:00:00,15130 2014-12-27 12:30:00,15345 2014-12-27 13:00:00,17040 2014-12-27 13:30:00,16684 2014-12-27 14:00:00,16291 2014-12-27 14:30:00,17065 2014-12-27 15:00:00,17860 2014-12-27 15:30:00,17447 2014-12-27 16:00:00,16199 2014-12-27 16:30:00,14999 2014-12-27 17:00:00,15570 2014-12-27 17:30:00,17132 2014-12-27 18:00:00,17710 2014-12-27 18:30:00,18132 2014-12-27 19:00:00,18627 2014-12-27 19:30:00,17430 2014-12-27 20:00:00,16148 2014-12-27 20:30:00,15807 2014-12-27 21:00:00,16121 2014-12-27 21:30:00,17054 2014-12-27 22:00:00,18095 2014-12-27 22:30:00,17628 2014-12-27 23:00:00,17414 2014-12-27 23:30:00,17594 2014-12-28 00:00:00,16514 2014-12-28 00:30:00,15556 2014-12-28 01:00:00,14465 2014-12-28 01:30:00,12810 2014-12-28 02:00:00,12680 2014-12-28 02:30:00,11121 2014-12-28 03:00:00,9850 2014-12-28 03:30:00,9033 2014-12-28 04:00:00,8122 2014-12-28 04:30:00,5228 2014-12-28 05:00:00,3452 2014-12-28 05:30:00,2937 2014-12-28 06:00:00,2764 2014-12-28 06:30:00,3090 2014-12-28 07:00:00,3109 2014-12-28 07:30:00,4300 2014-12-28 08:00:00,5130 2014-12-28 08:30:00,6652 2014-12-28 09:00:00,7486 2014-12-28 09:30:00,9812 2014-12-28 10:00:00,10911 2014-12-28 10:30:00,13280 2014-12-28 11:00:00,13191 2014-12-28 11:30:00,14218 2014-12-28 12:00:00,14878 2014-12-28 12:30:00,15665 2014-12-28 13:00:00,15911 2014-12-28 13:30:00,15002 2014-12-28 14:00:00,15102 2014-12-28 14:30:00,15658 2014-12-28 15:00:00,15756 2014-12-28 15:30:00,16645 2014-12-28 16:00:00,16464 2014-12-28 16:30:00,15288 2014-12-28 17:00:00,15988 2014-12-28 17:30:00,16608 2014-12-28 18:00:00,16556 2014-12-28 18:30:00,16635 2014-12-28 19:00:00,16446 2014-12-28 19:30:00,15796 2014-12-28 20:00:00,14951 2014-12-28 20:30:00,14373 2014-12-28 21:00:00,13695 2014-12-28 21:30:00,14411 2014-12-28 22:00:00,14035 2014-12-28 22:30:00,12954 2014-12-28 23:00:00,11239 2014-12-28 23:30:00,10461 2014-12-29 00:00:00,8548 2014-12-29 00:30:00,6766 2014-12-29 01:00:00,5087 2014-12-29 01:30:00,4353 2014-12-29 02:00:00,3646 2014-12-29 02:30:00,2857 2014-12-29 03:00:00,2484 2014-12-29 03:30:00,2105 2014-12-29 04:00:00,2270 2014-12-29 04:30:00,2033 2014-12-29 05:00:00,2123 2014-12-29 05:30:00,2886 2014-12-29 06:00:00,4249 2014-12-29 06:30:00,6400 2014-12-29 07:00:00,6953 2014-12-29 07:30:00,8715 2014-12-29 08:00:00,9590 2014-12-29 08:30:00,12167 2014-12-29 09:00:00,12436 2014-12-29 09:30:00,13052 2014-12-29 10:00:00,13503 2014-12-29 10:30:00,13798 2014-12-29 11:00:00,14277 2014-12-29 11:30:00,15344 2014-12-29 12:00:00,15677 2014-12-29 12:30:00,16534 2014-12-29 13:00:00,16220 2014-12-29 13:30:00,16650 2014-12-29 14:00:00,17395 2014-12-29 14:30:00,17895 2014-12-29 15:00:00,17701 2014-12-29 15:30:00,17989 2014-12-29 16:00:00,16737 2014-12-29 16:30:00,15371 2014-12-29 17:00:00,17519 2014-12-29 17:30:00,18500 2014-12-29 18:00:00,20064 2014-12-29 18:30:00,20153 2014-12-29 19:00:00,20364 2014-12-29 19:30:00,18808 2014-12-29 20:00:00,17718 2014-12-29 20:30:00,16678 2014-12-29 21:00:00,17523 2014-12-29 21:30:00,17397 2014-12-29 22:00:00,16308 2014-12-29 22:30:00,15954 2014-12-29 23:00:00,14488 2014-12-29 23:30:00,12738 2014-12-30 00:00:00,11042 2014-12-30 00:30:00,8774 2014-12-30 01:00:00,7267 2014-12-30 01:30:00,5704 2014-12-30 02:00:00,4749 2014-12-30 02:30:00,3932 2014-12-30 03:00:00,3336 2014-12-30 03:30:00,3023 2014-12-30 04:00:00,3059 2014-12-30 04:30:00,2399 2014-12-30 05:00:00,2091 2014-12-30 05:30:00,3019 2014-12-30 06:00:00,4208 2014-12-30 06:30:00,6505 2014-12-30 07:00:00,7026 2014-12-30 07:30:00,8953 2014-12-30 08:00:00,10186 2014-12-30 08:30:00,13046 2014-12-30 09:00:00,13519 2014-12-30 09:30:00,14319 2014-12-30 10:00:00,14433 2014-12-30 10:30:00,15570 2014-12-30 11:00:00,15690 2014-12-30 11:30:00,17265 2014-12-30 12:00:00,17830 2014-12-30 12:30:00,18552 2014-12-30 13:00:00,19340 2014-12-30 13:30:00,19070 2014-12-30 14:00:00,18866 2014-12-30 14:30:00,18709 2014-12-30 15:00:00,18906 2014-12-30 15:30:00,18178 2014-12-30 16:00:00,16420 2014-12-30 16:30:00,15066 2014-12-30 17:00:00,17023 2014-12-30 17:30:00,19201 2014-12-30 18:00:00,20950 2014-12-30 18:30:00,22321 2014-12-30 19:00:00,22549 2014-12-30 19:30:00,21405 2014-12-30 20:00:00,20209 2014-12-30 20:30:00,19574 2014-12-30 21:00:00,20294 2014-12-30 21:30:00,20054 2014-12-30 22:00:00,19779 2014-12-30 22:30:00,18396 2014-12-30 23:00:00,17966 2014-12-30 23:30:00,15892 2014-12-31 00:00:00,14294 2014-12-31 00:30:00,12150 2014-12-31 01:00:00,10423 2014-12-31 01:30:00,8229 2014-12-31 02:00:00,7068 2014-12-31 02:30:00,5572 2014-12-31 03:00:00,4669 2014-12-31 03:30:00,3922 2014-12-31 04:00:00,4120 2014-12-31 04:30:00,2786 2014-12-31 05:00:00,2265 2014-12-31 05:30:00,2825 2014-12-31 06:00:00,3705 2014-12-31 06:30:00,5745 2014-12-31 07:00:00,6334 2014-12-31 07:30:00,8324 2014-12-31 08:00:00,9449 2014-12-31 08:30:00,11877 2014-12-31 09:00:00,11917 2014-12-31 09:30:00,12621 2014-12-31 10:00:00,13294 2014-12-31 10:30:00,13850 2014-12-31 11:00:00,15128 2014-12-31 11:30:00,16996 2014-12-31 12:00:00,16815 2014-12-31 12:30:00,17275 2014-12-31 13:00:00,18553 2014-12-31 13:30:00,18607 2014-12-31 14:00:00,18703 2014-12-31 14:30:00,18970 2014-12-31 15:00:00,19316 2014-12-31 15:30:00,18542 2014-12-31 16:00:00,17583 2014-12-31 16:30:00,16607 2014-12-31 17:00:00,17991 2014-12-31 17:30:00,18983 2014-12-31 18:00:00,20014 2014-12-31 18:30:00,20943 2014-12-31 19:00:00,22114 2014-12-31 19:30:00,24368 2014-12-31 20:00:00,25524 2014-12-31 20:30:00,26779 2014-12-31 21:00:00,27804 2014-12-31 21:30:00,27315 2014-12-31 22:00:00,25417 2014-12-31 22:30:00,23177 2014-12-31 23:00:00,21826 2014-12-31 23:30:00,14152 2015-01-01 00:00:00,22153 2015-01-01 00:30:00,29547 2015-01-01 01:00:00,30236 2015-01-01 01:30:00,28348 2015-01-01 02:00:00,26264 2015-01-01 02:30:00,25243 2015-01-01 03:00:00,23117 2015-01-01 03:30:00,21017 2015-01-01 04:00:00,18170 2015-01-01 04:30:00,12629 2015-01-01 05:00:00,8899 2015-01-01 05:30:00,6999 2015-01-01 06:00:00,5750 2015-01-01 06:30:00,5381 2015-01-01 07:00:00,5056 2015-01-01 07:30:00,4930 2015-01-01 08:00:00,4624 2015-01-01 08:30:00,4726 2015-01-01 09:00:00,5505 2015-01-01 09:30:00,6510 2015-01-01 10:00:00,7705 2015-01-01 10:30:00,10007 2015-01-01 11:00:00,11405 2015-01-01 11:30:00,13562 2015-01-01 12:00:00,14537 2015-01-01 12:30:00,15296 2015-01-01 13:00:00,15376 2015-01-01 13:30:00,16302 2015-01-01 14:00:00,16066 2015-01-01 14:30:00,16485 2015-01-01 15:00:00,16887 2015-01-01 15:30:00,16430 2015-01-01 16:00:00,16044 2015-01-01 16:30:00,14655 2015-01-01 17:00:00,15514 2015-01-01 17:30:00,16184 2015-01-01 18:00:00,16280 2015-01-01 18:30:00,16550 2015-01-01 19:00:00,15626 2015-01-01 19:30:00,14304 2015-01-01 20:00:00,13741 2015-01-01 20:30:00,13578 2015-01-01 21:00:00,13326 2015-01-01 21:30:00,13560 2015-01-01 22:00:00,12730 2015-01-01 22:30:00,12533 2015-01-01 23:00:00,10673 2015-01-01 23:30:00,9947 2015-01-02 00:00:00,8258 2015-01-02 00:30:00,8343 2015-01-02 01:00:00,6326 2015-01-02 01:30:00,4485 2015-01-02 02:00:00,3991 2015-01-02 02:30:00,3126 2015-01-02 03:00:00,2794 2015-01-02 03:30:00,2296 2015-01-02 04:00:00,2506 2015-01-02 04:30:00,2012 2015-01-02 05:00:00,1955 2015-01-02 05:30:00,2486 2015-01-02 06:00:00,3774 2015-01-02 06:30:00,5344 2015-01-02 07:00:00,5956 2015-01-02 07:30:00,7314 2015-01-02 08:00:00,8030 2015-01-02 08:30:00,10085 2015-01-02 09:00:00,10867 2015-01-02 09:30:00,11830 2015-01-02 10:00:00,12507 2015-01-02 10:30:00,13943 2015-01-02 11:00:00,14115 2015-01-02 11:30:00,15399 2015-01-02 12:00:00,16521 2015-01-02 12:30:00,16913 2015-01-02 13:00:00,16207 2015-01-02 13:30:00,17068 2015-01-02 14:00:00,17756 2015-01-02 14:30:00,17887 2015-01-02 15:00:00,17936 2015-01-02 15:30:00,18259 2015-01-02 16:00:00,16710 2015-01-02 16:30:00,15525 2015-01-02 17:00:00,17440 2015-01-02 17:30:00,19523 2015-01-02 18:00:00,20137 2015-01-02 18:30:00,20936 2015-01-02 19:00:00,21998 2015-01-02 19:30:00,19934 2015-01-02 20:00:00,18302 2015-01-02 20:30:00,17815 2015-01-02 21:00:00,17366 2015-01-02 21:30:00,17518 2015-01-02 22:00:00,19508 2015-01-02 22:30:00,19720 2015-01-02 23:00:00,18658 2015-01-02 23:30:00,19337 2015-01-03 00:00:00,18085 2015-01-03 00:30:00,16661 2015-01-03 01:00:00,15624 2015-01-03 01:30:00,14177 2015-01-03 02:00:00,12850 2015-01-03 02:30:00,11509 2015-01-03 03:00:00,10329 2015-01-03 03:30:00,8830 2015-01-03 04:00:00,7903 2015-01-03 04:30:00,4497 2015-01-03 05:00:00,3189 2015-01-03 05:30:00,2793 2015-01-03 06:00:00,2810 2015-01-03 06:30:00,3696 2015-01-03 07:00:00,3707 2015-01-03 07:30:00,4758 2015-01-03 08:00:00,5334 2015-01-03 08:30:00,7736 2015-01-03 09:00:00,9130 2015-01-03 09:30:00,11189 2015-01-03 10:00:00,11887 2015-01-03 10:30:00,14095 2015-01-03 11:00:00,14737 2015-01-03 11:30:00,16826 2015-01-03 12:00:00,18143 2015-01-03 12:30:00,20074 2015-01-03 13:00:00,21386 2015-01-03 13:30:00,21466 2015-01-03 14:00:00,21368 2015-01-03 14:30:00,21695 2015-01-03 15:00:00,21529 2015-01-03 15:30:00,20273 2015-01-03 16:00:00,19355 2015-01-03 16:30:00,17061 2015-01-03 17:00:00,18676 2015-01-03 17:30:00,21073 2015-01-03 18:00:00,22091 2015-01-03 18:30:00,23100 2015-01-03 19:00:00,23801 2015-01-03 19:30:00,22393 2015-01-03 20:00:00,18954 2015-01-03 20:30:00,18005 2015-01-03 21:00:00,19333 2015-01-03 21:30:00,18891 2015-01-03 22:00:00,20259 2015-01-03 22:30:00,20055 2015-01-03 23:00:00,19787 2015-01-03 23:30:00,20995 2015-01-04 00:00:00,19613 2015-01-04 00:30:00,16975 2015-01-04 01:00:00,16541 2015-01-04 01:30:00,14379 2015-01-04 02:00:00,13089 2015-01-04 02:30:00,10506 2015-01-04 03:00:00,9216 2015-01-04 03:30:00,8103 2015-01-04 04:00:00,6823 2015-01-04 04:30:00,4263 2015-01-04 05:00:00,3025 2015-01-04 05:30:00,2549 2015-01-04 06:00:00,2605 2015-01-04 06:30:00,3064 2015-01-04 07:00:00,3205 2015-01-04 07:30:00,4254 2015-01-04 08:00:00,4897 2015-01-04 08:30:00,6628 2015-01-04 09:00:00,7726 2015-01-04 09:30:00,9284 2015-01-04 10:00:00,10955 2015-01-04 10:30:00,13348 2015-01-04 11:00:00,13517 2015-01-04 11:30:00,14443 2015-01-04 12:00:00,15285 2015-01-04 12:30:00,16028 2015-01-04 13:00:00,16329 2015-01-04 13:30:00,15891 2015-01-04 14:00:00,15960 2015-01-04 14:30:00,16376 2015-01-04 15:00:00,15303 2015-01-04 15:30:00,16271 2015-01-04 16:00:00,15873 2015-01-04 16:30:00,15588 2015-01-04 17:00:00,15471 2015-01-04 17:30:00,16139 2015-01-04 18:00:00,15862 2015-01-04 18:30:00,16218 2015-01-04 19:00:00,14093 2015-01-04 19:30:00,17786 2015-01-04 20:00:00,16079 2015-01-04 20:30:00,14137 2015-01-04 21:00:00,11407 2015-01-04 21:30:00,12479 2015-01-04 22:00:00,11317 2015-01-04 22:30:00,10005 2015-01-04 23:00:00,8802 2015-01-04 23:30:00,8002 2015-01-05 00:00:00,6669 2015-01-05 00:30:00,5961 2015-01-05 01:00:00,4169 2015-01-05 01:30:00,3365 2015-01-05 02:00:00,2853 2015-01-05 02:30:00,2227 2015-01-05 03:00:00,1609 2015-01-05 03:30:00,1697 2015-01-05 04:00:00,1883 2015-01-05 04:30:00,1837 2015-01-05 05:00:00,2476 2015-01-05 05:30:00,4040 2015-01-05 06:00:00,6431 2015-01-05 06:30:00,10496 2015-01-05 07:00:00,13610 2015-01-05 07:30:00,16277 2015-01-05 08:00:00,17760 2015-01-05 08:30:00,18026 2015-01-05 09:00:00,16706 2015-01-05 09:30:00,14662 2015-01-05 10:00:00,13070 2015-01-05 10:30:00,13459 2015-01-05 11:00:00,13218 2015-01-05 11:30:00,13909 2015-01-05 12:00:00,14379 2015-01-05 12:30:00,14113 2015-01-05 13:00:00,13982 2015-01-05 13:30:00,14514 2015-01-05 14:00:00,15268 2015-01-05 14:30:00,16675 2015-01-05 15:00:00,17423 2015-01-05 15:30:00,16521 2015-01-05 16:00:00,15352 2015-01-05 16:30:00,14644 2015-01-05 17:00:00,17059 2015-01-05 17:30:00,19269 2015-01-05 18:00:00,21361 2015-01-05 18:30:00,21906 2015-01-05 19:00:00,21994 2015-01-05 19:30:00,20678 2015-01-05 20:00:00,19248 2015-01-05 20:30:00,17546 2015-01-05 21:00:00,17201 2015-01-05 21:30:00,15830 2015-01-05 22:00:00,14238 2015-01-05 22:30:00,13120 2015-01-05 23:00:00,11660 2015-01-05 23:30:00,9741 2015-01-06 00:00:00,7969 2015-01-06 00:30:00,6005 2015-01-06 01:00:00,4592 2015-01-06 01:30:00,3487 2015-01-06 02:00:00,2856 2015-01-06 02:30:00,2238 2015-01-06 03:00:00,1689 2015-01-06 03:30:00,1602 2015-01-06 04:00:00,1774 2015-01-06 04:30:00,1721 2015-01-06 05:00:00,2118 2015-01-06 05:30:00,4101 2015-01-06 06:00:00,6266 2015-01-06 06:30:00,11168 2015-01-06 07:00:00,13976 2015-01-06 07:30:00,18081 2015-01-06 08:00:00,19819 2015-01-06 08:30:00,20102 2015-01-06 09:00:00,18237 2015-01-06 09:30:00,16472 2015-01-06 10:00:00,14510 2015-01-06 10:30:00,14365 2015-01-06 11:00:00,13611 2015-01-06 11:30:00,14729 2015-01-06 12:00:00,15072 2015-01-06 12:30:00,14628 2015-01-06 13:00:00,14069 2015-01-06 13:30:00,14987 2015-01-06 14:00:00,15176 2015-01-06 14:30:00,16884 2015-01-06 15:00:00,17055 2015-01-06 15:30:00,16238 2015-01-06 16:00:00,14566 2015-01-06 16:30:00,14604 2015-01-06 17:00:00,16314 2015-01-06 17:30:00,18758 2015-01-06 18:00:00,21579 2015-01-06 18:30:00,22500 2015-01-06 19:00:00,21920 2015-01-06 19:30:00,20788 2015-01-06 20:00:00,20461 2015-01-06 20:30:00,19640 2015-01-06 21:00:00,19580 2015-01-06 21:30:00,19424 2015-01-06 22:00:00,17170 2015-01-06 22:30:00,14955 2015-01-06 23:00:00,12934 2015-01-06 23:30:00,11087 2015-01-07 00:00:00,8357 2015-01-07 00:30:00,6788 2015-01-07 01:00:00,5378 2015-01-07 01:30:00,3889 2015-01-07 02:00:00,3068 2015-01-07 02:30:00,2406 2015-01-07 03:00:00,2025 2015-01-07 03:30:00,1739 2015-01-07 04:00:00,1897 2015-01-07 04:30:00,1820 2015-01-07 05:00:00,2039 2015-01-07 05:30:00,3857 2015-01-07 06:00:00,6280 2015-01-07 06:30:00,11280 2015-01-07 07:00:00,14586 2015-01-07 07:30:00,18374 2015-01-07 08:00:00,20307 2015-01-07 08:30:00,21113 2015-01-07 09:00:00,19287 2015-01-07 09:30:00,17966 2015-01-07 10:00:00,15690 2015-01-07 10:30:00,16091 2015-01-07 11:00:00,14981 2015-01-07 11:30:00,16906 2015-01-07 12:00:00,16648 2015-01-07 12:30:00,16826 2015-01-07 13:00:00,16379 2015-01-07 13:30:00,17457 2015-01-07 14:00:00,17335 2015-01-07 14:30:00,18690 2015-01-07 15:00:00,19029 2015-01-07 15:30:00,17234 2015-01-07 16:00:00,16505 2015-01-07 16:30:00,15509 2015-01-07 17:00:00,17873 2015-01-07 17:30:00,21871 2015-01-07 18:00:00,24019 2015-01-07 18:30:00,24965 2015-01-07 19:00:00,25708 2015-01-07 19:30:00,24871 2015-01-07 20:00:00,23732 2015-01-07 20:30:00,22463 2015-01-07 21:00:00,23142 2015-01-07 21:30:00,22369 2015-01-07 22:00:00,21904 2015-01-07 22:30:00,18610 2015-01-07 23:00:00,15262 2015-01-07 23:30:00,12490 2015-01-08 00:00:00,9843 2015-01-08 00:30:00,7477 2015-01-08 01:00:00,5697 2015-01-08 01:30:00,4327 2015-01-08 02:00:00,3405 2015-01-08 02:30:00,2739 2015-01-08 03:00:00,2066 2015-01-08 03:30:00,2013 2015-01-08 04:00:00,1975 2015-01-08 04:30:00,1760 2015-01-08 05:00:00,2033 2015-01-08 05:30:00,4164 2015-01-08 06:00:00,6627 2015-01-08 06:30:00,12142 2015-01-08 07:00:00,15873 2015-01-08 07:30:00,20194 2015-01-08 08:00:00,21891 2015-01-08 08:30:00,22117 2015-01-08 09:00:00,20435 2015-01-08 09:30:00,19472 2015-01-08 10:00:00,17256 2015-01-08 10:30:00,17401 2015-01-08 11:00:00,15595 2015-01-08 11:30:00,17559 2015-01-08 12:00:00,17823 2015-01-08 12:30:00,16634 2015-01-08 13:00:00,16523 2015-01-08 13:30:00,17209 2015-01-08 14:00:00,17438 2015-01-08 14:30:00,19801 2015-01-08 15:00:00,20241 2015-01-08 15:30:00,18535 2015-01-08 16:00:00,16573 2015-01-08 16:30:00,15095 2015-01-08 17:00:00,17871 2015-01-08 17:30:00,21606 2015-01-08 18:00:00,24071 2015-01-08 18:30:00,25176 2015-01-08 19:00:00,25592 2015-01-08 19:30:00,25125 2015-01-08 20:00:00,24584 2015-01-08 20:30:00,23692 2015-01-08 21:00:00,23593 2015-01-08 21:30:00,23676 2015-01-08 22:00:00,23367 2015-01-08 22:30:00,21952 2015-01-08 23:00:00,19331 2015-01-08 23:30:00,15847 2015-01-09 00:00:00,13156 2015-01-09 00:30:00,10295 2015-01-09 01:00:00,8080 2015-01-09 01:30:00,6041 2015-01-09 02:00:00,5180 2015-01-09 02:30:00,3992 2015-01-09 03:00:00,3359 2015-01-09 03:30:00,2808 2015-01-09 04:00:00,2703 2015-01-09 04:30:00,2176 2015-01-09 05:00:00,2434 2015-01-09 05:30:00,4092 2015-01-09 06:00:00,6053 2015-01-09 06:30:00,11326 2015-01-09 07:00:00,13826 2015-01-09 07:30:00,15011 2015-01-09 08:00:00,15124 2015-01-09 08:30:00,15755 2015-01-09 09:00:00,16110 2015-01-09 09:30:00,16271 2015-01-09 10:00:00,15323 2015-01-09 10:30:00,15421 2015-01-09 11:00:00,14604 2015-01-09 11:30:00,15840 2015-01-09 12:00:00,15962 2015-01-09 12:30:00,15948 2015-01-09 13:00:00,16283 2015-01-09 13:30:00,16502 2015-01-09 14:00:00,17377 2015-01-09 14:30:00,18858 2015-01-09 15:00:00,18338 2015-01-09 15:30:00,17567 2015-01-09 16:00:00,15857 2015-01-09 16:30:00,15069 2015-01-09 17:00:00,18144 2015-01-09 17:30:00,21770 2015-01-09 18:00:00,24651 2015-01-09 18:30:00,26480 2015-01-09 19:00:00,27443 2015-01-09 19:30:00,27676 2015-01-09 20:00:00,25589 2015-01-09 20:30:00,23761 2015-01-09 21:00:00,23882 2015-01-09 21:30:00,23922 2015-01-09 22:00:00,24901 2015-01-09 22:30:00,25440 2015-01-09 23:00:00,25306 2015-01-09 23:30:00,25133 2015-01-10 00:00:00,24251 2015-01-10 00:30:00,22330 2015-01-10 01:00:00,19918 2015-01-10 01:30:00,17922 2015-01-10 02:00:00,16425 2015-01-10 02:30:00,13977 2015-01-10 03:00:00,11797 2015-01-10 03:30:00,10171 2015-01-10 04:00:00,8666 2015-01-10 04:30:00,4721 2015-01-10 05:00:00,3390 2015-01-10 05:30:00,2905 2015-01-10 06:00:00,3265 2015-01-10 06:30:00,4249 2015-01-10 07:00:00,5058 2015-01-10 07:30:00,6976 2015-01-10 08:00:00,7425 2015-01-10 08:30:00,11024 2015-01-10 09:00:00,13013 2015-01-10 09:30:00,16327 2015-01-10 10:00:00,16385 2015-01-10 10:30:00,18820 2015-01-10 11:00:00,19868 2015-01-10 11:30:00,22503 2015-01-10 12:00:00,22724 2015-01-10 12:30:00,23856 2015-01-10 13:00:00,23073 2015-01-10 13:30:00,22492 2015-01-10 14:00:00,21336 2015-01-10 14:30:00,22371 2015-01-10 15:00:00,23119 2015-01-10 15:30:00,23941 2015-01-10 16:00:00,22728 2015-01-10 16:30:00,20126 2015-01-10 17:00:00,21139 2015-01-10 17:30:00,24417 2015-01-10 18:00:00,26639 2015-01-10 18:30:00,26907 2015-01-10 19:00:00,28043 2015-01-10 19:30:00,26853 2015-01-10 20:00:00,27983 2015-01-10 20:30:00,24555 2015-01-10 21:00:00,23596 2015-01-10 21:30:00,24947 2015-01-10 22:00:00,26085 2015-01-10 22:30:00,27646 2015-01-10 23:00:00,28301 2015-01-10 23:30:00,28401 2015-01-11 00:00:00,26653 2015-01-11 00:30:00,24790 2015-01-11 01:00:00,23141 2015-01-11 01:30:00,20654 2015-01-11 02:00:00,19179 2015-01-11 02:30:00,16879 2015-01-11 03:00:00,14597 2015-01-11 03:30:00,12394 2015-01-11 04:00:00,9787 2015-01-11 04:30:00,5859 2015-01-11 05:00:00,3682 2015-01-11 05:30:00,3108 2015-01-11 06:00:00,2883 2015-01-11 06:30:00,3710 2015-01-11 07:00:00,3790 2015-01-11 07:30:00,5294 2015-01-11 08:00:00,6133 2015-01-11 08:30:00,8808 2015-01-11 09:00:00,9884 2015-01-11 09:30:00,13052 2015-01-11 10:00:00,13881 2015-01-11 10:30:00,17481 2015-01-11 11:00:00,17730 2015-01-11 11:30:00,20015 2015-01-11 12:00:00,19794 2015-01-11 12:30:00,21709 2015-01-11 13:00:00,21296 2015-01-11 13:30:00,20381 2015-01-11 14:00:00,19508 2015-01-11 14:30:00,19210 2015-01-11 15:00:00,18255 2015-01-11 15:30:00,19171 2015-01-11 16:00:00,18758 2015-01-11 16:30:00,19444 2015-01-11 17:00:00,19816 2015-01-11 17:30:00,19830 2015-01-11 18:00:00,19842 2015-01-11 18:30:00,19586 2015-01-11 19:00:00,18579 2015-01-11 19:30:00,17586 2015-01-11 20:00:00,15320 2015-01-11 20:30:00,13987 2015-01-11 21:00:00,13611 2015-01-11 21:30:00,13943 2015-01-11 22:00:00,12956 2015-01-11 22:30:00,11585 2015-01-11 23:00:00,12116 2015-01-11 23:30:00,9058 2015-01-12 00:00:00,7147 2015-01-12 00:30:00,5365 2015-01-12 01:00:00,3756 2015-01-12 01:30:00,3077 2015-01-12 02:00:00,2603 2015-01-12 02:30:00,2264 2015-01-12 03:00:00,1973 2015-01-12 03:30:00,1679 2015-01-12 04:00:00,1964 2015-01-12 04:30:00,1891 2015-01-12 05:00:00,2303 2015-01-12 05:30:00,4462 2015-01-12 06:00:00,6496 2015-01-12 06:30:00,11269 2015-01-12 07:00:00,14140 2015-01-12 07:30:00,18040 2015-01-12 08:00:00,19618 2015-01-12 08:30:00,19631 2015-01-12 09:00:00,18598 2015-01-12 09:30:00,17797 2015-01-12 10:00:00,16160 2015-01-12 10:30:00,15872 2015-01-12 11:00:00,15103 2015-01-12 11:30:00,16858 2015-01-12 12:00:00,17532 2015-01-12 12:30:00,16478 2015-01-12 13:00:00,16071 2015-01-12 13:30:00,17036 2015-01-12 14:00:00,17167 2015-01-12 14:30:00,18607 2015-01-12 15:00:00,19387 2015-01-12 15:30:00,16274 2015-01-12 16:00:00,15210 2015-01-12 16:30:00,14695 2015-01-12 17:00:00,16686 2015-01-12 17:30:00,19234 2015-01-12 18:00:00,21350 2015-01-12 18:30:00,22150 2015-01-12 19:00:00,21582 2015-01-12 19:30:00,20321 2015-01-12 20:00:00,20071 2015-01-12 20:30:00,18532 2015-01-12 21:00:00,18801 2015-01-12 21:30:00,17972 2015-01-12 22:00:00,17298 2015-01-12 22:30:00,14655 2015-01-12 23:00:00,12376 2015-01-12 23:30:00,10191 2015-01-13 00:00:00,11139 2015-01-13 00:30:00,7323 2015-01-13 01:00:00,5142 2015-01-13 01:30:00,3987 2015-01-13 02:00:00,3197 2015-01-13 02:30:00,2336 2015-01-13 03:00:00,1800 2015-01-13 03:30:00,1742 2015-01-13 04:00:00,1901 2015-01-13 04:30:00,1681 2015-01-13 05:00:00,2036 2015-01-13 05:30:00,4284 2015-01-13 06:00:00,6390 2015-01-13 06:30:00,11432 2015-01-13 07:00:00,14929 2015-01-13 07:30:00,19814 2015-01-13 08:00:00,21295 2015-01-13 08:30:00,21258 2015-01-13 09:00:00,20209 2015-01-13 09:30:00,19420 2015-01-13 10:00:00,18088 2015-01-13 10:30:00,17942 2015-01-13 11:00:00,17251 2015-01-13 11:30:00,18843 2015-01-13 12:00:00,18906 2015-01-13 12:30:00,18117 2015-01-13 13:00:00,17533 2015-01-13 13:30:00,18593 2015-01-13 14:00:00,18967 2015-01-13 14:30:00,20374 2015-01-13 15:00:00,20245 2015-01-13 15:30:00,18663 2015-01-13 16:00:00,16688 2015-01-13 16:30:00,14860 2015-01-13 17:00:00,16990 2015-01-13 17:30:00,20233 2015-01-13 18:00:00,23012 2015-01-13 18:30:00,24353 2015-01-13 19:00:00,24698 2015-01-13 19:30:00,24188 2015-01-13 20:00:00,24033 2015-01-13 20:30:00,23737 2015-01-13 21:00:00,23774 2015-01-13 21:30:00,23522 2015-01-13 22:00:00,21828 2015-01-13 22:30:00,18996 2015-01-13 23:00:00,15659 2015-01-13 23:30:00,12989 2015-01-14 00:00:00,10584 2015-01-14 00:30:00,7941 2015-01-14 01:00:00,6221 2015-01-14 01:30:00,4792 2015-01-14 02:00:00,3814 2015-01-14 02:30:00,3053 2015-01-14 03:00:00,2725 2015-01-14 03:30:00,2356 2015-01-14 04:00:00,2327 2015-01-14 04:30:00,2058 2015-01-14 05:00:00,2267 2015-01-14 05:30:00,4547 2015-01-14 06:00:00,6582 2015-01-14 06:30:00,12004 2015-01-14 07:00:00,15442 2015-01-14 07:30:00,20021 2015-01-14 08:00:00,20953 2015-01-14 08:30:00,21276 2015-01-14 09:00:00,20444 2015-01-14 09:30:00,19071 2015-01-14 10:00:00,17173 2015-01-14 10:30:00,17446 2015-01-14 11:00:00,16319 2015-01-14 11:30:00,18120 2015-01-14 12:00:00,18258 2015-01-14 12:30:00,17222 2015-01-14 13:00:00,16563 2015-01-14 13:30:00,17953 2015-01-14 14:00:00,18119 2015-01-14 14:30:00,18740 2015-01-14 15:00:00,18803 2015-01-14 15:30:00,17318 2015-01-14 16:00:00,15354 2015-01-14 16:30:00,14243 2015-01-14 17:00:00,16310 2015-01-14 17:30:00,20078 2015-01-14 18:00:00,22844 2015-01-14 18:30:00,23895 2015-01-14 19:00:00,24410 2015-01-14 19:30:00,24216 2015-01-14 20:00:00,22351 2015-01-14 20:30:00,22154 2015-01-14 21:00:00,22757 2015-01-14 21:30:00,22301 2015-01-14 22:00:00,22537 2015-01-14 22:30:00,19647 2015-01-14 23:00:00,16555 2015-01-14 23:30:00,13935 2015-01-15 00:00:00,10852 2015-01-15 00:30:00,8131 2015-01-15 01:00:00,6253 2015-01-15 01:30:00,4881 2015-01-15 02:00:00,3872 2015-01-15 02:30:00,2952 2015-01-15 03:00:00,2530 2015-01-15 03:30:00,2242 2015-01-15 04:00:00,2384 2015-01-15 04:30:00,2102 2015-01-15 05:00:00,2353 2015-01-15 05:30:00,4388 2015-01-15 06:00:00,6600 2015-01-15 06:30:00,11844 2015-01-15 07:00:00,15429 2015-01-15 07:30:00,19536 2015-01-15 08:00:00,20800 2015-01-15 08:30:00,21237 2015-01-15 09:00:00,20044 2015-01-15 09:30:00,19195 2015-01-15 10:00:00,16819 2015-01-15 10:30:00,17002 2015-01-15 11:00:00,15592 2015-01-15 11:30:00,17319 2015-01-15 12:00:00,18062 2015-01-15 12:30:00,16821 2015-01-15 13:00:00,16158 2015-01-15 13:30:00,17614 2015-01-15 14:00:00,17978 2015-01-15 14:30:00,18693 2015-01-15 15:00:00,18743 2015-01-15 15:30:00,17213 2015-01-15 16:00:00,15389 2015-01-15 16:30:00,13926 2015-01-15 17:00:00,16336 2015-01-15 17:30:00,19647 2015-01-15 18:00:00,22732 2015-01-15 18:30:00,24064 2015-01-15 19:00:00,24881 2015-01-15 19:30:00,24507 2015-01-15 20:00:00,24438 2015-01-15 20:30:00,23792 2015-01-15 21:00:00,24517 2015-01-15 21:30:00,24126 2015-01-15 22:00:00,23957 2015-01-15 22:30:00,22825 2015-01-15 23:00:00,21086 2015-01-15 23:30:00,17957 2015-01-16 00:00:00,14729 2015-01-16 00:30:00,11814 2015-01-16 01:00:00,9221 2015-01-16 01:30:00,7049 2015-01-16 02:00:00,6102 2015-01-16 02:30:00,4971 2015-01-16 03:00:00,4205 2015-01-16 03:30:00,3238 2015-01-16 04:00:00,3474 2015-01-16 04:30:00,2952 2015-01-16 05:00:00,2858 2015-01-16 05:30:00,4621 2015-01-16 06:00:00,6570 2015-01-16 06:30:00,11368 2015-01-16 07:00:00,14644 2015-01-16 07:30:00,18846 2015-01-16 08:00:00,19936 2015-01-16 08:30:00,20315 2015-01-16 09:00:00,19285 2015-01-16 09:30:00,18492 2015-01-16 10:00:00,16873 2015-01-16 10:30:00,16492 2015-01-16 11:00:00,15440 2015-01-16 11:30:00,17341 2015-01-16 12:00:00,17377 2015-01-16 12:30:00,16922 2015-01-16 13:00:00,16465 2015-01-16 13:30:00,17797 2015-01-16 14:00:00,18924 2015-01-16 14:30:00,19579 2015-01-16 15:00:00,19159 2015-01-16 15:30:00,17343 2015-01-16 16:00:00,15856 2015-01-16 16:30:00,14769 2015-01-16 17:00:00,16980 2015-01-16 17:30:00,21604 2015-01-16 18:00:00,24026 2015-01-16 18:30:00,26085 2015-01-16 19:00:00,27462 2015-01-16 19:30:00,27681 2015-01-16 20:00:00,26427 2015-01-16 20:30:00,25444 2015-01-16 21:00:00,25168 2015-01-16 21:30:00,25376 2015-01-16 22:00:00,26024 2015-01-16 22:30:00,26428 2015-01-16 23:00:00,25890 2015-01-16 23:30:00,25472 2015-01-17 00:00:00,24841 2015-01-17 00:30:00,22159 2015-01-17 01:00:00,20046 2015-01-17 01:30:00,17945 2015-01-17 02:00:00,15954 2015-01-17 02:30:00,14210 2015-01-17 03:00:00,12146 2015-01-17 03:30:00,10342 2015-01-17 04:00:00,8970 2015-01-17 04:30:00,5302 2015-01-17 05:00:00,3600 2015-01-17 05:30:00,3192 2015-01-17 06:00:00,3473 2015-01-17 06:30:00,4304 2015-01-17 07:00:00,4478 2015-01-17 07:30:00,6310 2015-01-17 08:00:00,7465 2015-01-17 08:30:00,11664 2015-01-17 09:00:00,12000 2015-01-17 09:30:00,14970 2015-01-17 10:00:00,15205 2015-01-17 10:30:00,17118 2015-01-17 11:00:00,17495 2015-01-17 11:30:00,19508 2015-01-17 12:00:00,20017 2015-01-17 12:30:00,20707 2015-01-17 13:00:00,20941 2015-01-17 13:30:00,20725 2015-01-17 14:00:00,19358 2015-01-17 14:30:00,20008 2015-01-17 15:00:00,20758 2015-01-17 15:30:00,21068 2015-01-17 16:00:00,20316 2015-01-17 16:30:00,19248 2015-01-17 17:00:00,20449 2015-01-17 17:30:00,23133 2015-01-17 18:00:00,23733 2015-01-17 18:30:00,25602 2015-01-17 19:00:00,27074 2015-01-17 19:30:00,25487 2015-01-17 20:00:00,22437 2015-01-17 20:30:00,21569 2015-01-17 21:00:00,21542 2015-01-17 21:30:00,22661 2015-01-17 22:00:00,23754 2015-01-17 22:30:00,25114 2015-01-17 23:00:00,25308 2015-01-17 23:30:00,25251 2015-01-18 00:00:00,25423 2015-01-18 00:30:00,23964 2015-01-18 01:00:00,22134 2015-01-18 01:30:00,20253 2015-01-18 02:00:00,19354 2015-01-18 02:30:00,17470 2015-01-18 03:00:00,14916 2015-01-18 03:30:00,13069 2015-01-18 04:00:00,10617 2015-01-18 04:30:00,6053 2015-01-18 05:00:00,4097 2015-01-18 05:30:00,3219 2015-01-18 06:00:00,3050 2015-01-18 06:30:00,3114 2015-01-18 07:00:00,3521 2015-01-18 07:30:00,4745 2015-01-18 08:00:00,6290 2015-01-18 08:30:00,8298 2015-01-18 09:00:00,9919 2015-01-18 09:30:00,13441 2015-01-18 10:00:00,15096 2015-01-18 10:30:00,18880 2015-01-18 11:00:00,20210 2015-01-18 11:30:00,22395 2015-01-18 12:00:00,22791 2015-01-18 12:30:00,22619 2015-01-18 13:00:00,22916 2015-01-18 13:30:00,22472 2015-01-18 14:00:00,22015 2015-01-18 14:30:00,23848 2015-01-18 15:00:00,22149 2015-01-18 15:30:00,19787 2015-01-18 16:00:00,18399 2015-01-18 16:30:00,18309 2015-01-18 17:00:00,17623 2015-01-18 17:30:00,18567 2015-01-18 18:00:00,18557 2015-01-18 18:30:00,20670 2015-01-18 19:00:00,16805 2015-01-18 19:30:00,14576 2015-01-18 20:00:00,14056 2015-01-18 20:30:00,14591 2015-01-18 21:00:00,13904 2015-01-18 21:30:00,14487 2015-01-18 22:00:00,15516 2015-01-18 22:30:00,14292 2015-01-18 23:00:00,12676 2015-01-18 23:30:00,11970 2015-01-19 00:00:00,10938 2015-01-19 00:30:00,9181 2015-01-19 01:00:00,7630 2015-01-19 01:30:00,6241 2015-01-19 02:00:00,5370 2015-01-19 02:30:00,4199 2015-01-19 03:00:00,3815 2015-01-19 03:30:00,3367 2015-01-19 04:00:00,3278 2015-01-19 04:30:00,2542 2015-01-19 05:00:00,2341 2015-01-19 05:30:00,2774 2015-01-19 06:00:00,3479 2015-01-19 06:30:00,5228 2015-01-19 07:00:00,5531 2015-01-19 07:30:00,7133 2015-01-19 08:00:00,8572 2015-01-19 08:30:00,11251 2015-01-19 09:00:00,11815 2015-01-19 09:30:00,13223 2015-01-19 10:00:00,12862 2015-01-19 10:30:00,14360 2015-01-19 11:00:00,14101 2015-01-19 11:30:00,16056 2015-01-19 12:00:00,16454 2015-01-19 12:30:00,17460 2015-01-19 13:00:00,17295 2015-01-19 13:30:00,17872 2015-01-19 14:00:00,17517 2015-01-19 14:30:00,18228 2015-01-19 15:00:00,17900 2015-01-19 15:30:00,18245 2015-01-19 16:00:00,17379 2015-01-19 16:30:00,16921 2015-01-19 17:00:00,17309 2015-01-19 17:30:00,18431 2015-01-19 18:00:00,19142 2015-01-19 18:30:00,19449 2015-01-19 19:00:00,18494 2015-01-19 19:30:00,17217 2015-01-19 20:00:00,16075 2015-01-19 20:30:00,15157 2015-01-19 21:00:00,14245 2015-01-19 21:30:00,14069 2015-01-19 22:00:00,13506 2015-01-19 22:30:00,12936 2015-01-19 23:00:00,10400 2015-01-19 23:30:00,8189 2015-01-20 00:00:00,6941 2015-01-20 00:30:00,5164 2015-01-20 01:00:00,3940 2015-01-20 01:30:00,3073 2015-01-20 02:00:00,2690 2015-01-20 02:30:00,2006 2015-01-20 03:00:00,1584 2015-01-20 03:30:00,1495 2015-01-20 04:00:00,1692 2015-01-20 04:30:00,1663 2015-01-20 05:00:00,2275 2015-01-20 05:30:00,4423 2015-01-20 06:00:00,6390 2015-01-20 06:30:00,11694 2015-01-20 07:00:00,14427 2015-01-20 07:30:00,18672 2015-01-20 08:00:00,19568 2015-01-20 08:30:00,20068 2015-01-20 09:00:00,18961 2015-01-20 09:30:00,17965 2015-01-20 10:00:00,15858 2015-01-20 10:30:00,15942 2015-01-20 11:00:00,14858 2015-01-20 11:30:00,16031 2015-01-20 12:00:00,15767 2015-01-20 12:30:00,15718 2015-01-20 13:00:00,14752 2015-01-20 13:30:00,16556 2015-01-20 14:00:00,16333 2015-01-20 14:30:00,17782 2015-01-20 15:00:00,17590 2015-01-20 15:30:00,16525 2015-01-20 16:00:00,15174 2015-01-20 16:30:00,14241 2015-01-20 17:00:00,16378 2015-01-20 17:30:00,19480 2015-01-20 18:00:00,22419 2015-01-20 18:30:00,23262 2015-01-20 19:00:00,22395 2015-01-20 19:30:00,21663 2015-01-20 20:00:00,21386 2015-01-20 20:30:00,20673 2015-01-20 21:00:00,21258 2015-01-20 21:30:00,21186 2015-01-20 22:00:00,20053 2015-01-20 22:30:00,16936 2015-01-20 23:00:00,14319 2015-01-20 23:30:00,11226 2015-01-21 00:00:00,8987 2015-01-21 00:30:00,6616 2015-01-21 01:00:00,5410 2015-01-21 01:30:00,4152 2015-01-21 02:00:00,3405 2015-01-21 02:30:00,2682 2015-01-21 03:00:00,2180 2015-01-21 03:30:00,1905 2015-01-21 04:00:00,2089 2015-01-21 04:30:00,1981 2015-01-21 05:00:00,2213 2015-01-21 05:30:00,4205 2015-01-21 06:00:00,6482 2015-01-21 06:30:00,11513 2015-01-21 07:00:00,15263 2015-01-21 07:30:00,19134 2015-01-21 08:00:00,20366 2015-01-21 08:30:00,21165 2015-01-21 09:00:00,19723 2015-01-21 09:30:00,18557 2015-01-21 10:00:00,17106 2015-01-21 10:30:00,17373 2015-01-21 11:00:00,15714 2015-01-21 11:30:00,16754 2015-01-21 12:00:00,17156 2015-01-21 12:30:00,16405 2015-01-21 13:00:00,15565 2015-01-21 13:30:00,17267 2015-01-21 14:00:00,17711 2015-01-21 14:30:00,18372 2015-01-21 15:00:00,18579 2015-01-21 15:30:00,16601 2015-01-21 16:00:00,15939 2015-01-21 16:30:00,14513 2015-01-21 17:00:00,17001 2015-01-21 17:30:00,20962 2015-01-21 18:00:00,23400 2015-01-21 18:30:00,23891 2015-01-21 19:00:00,24112 2015-01-21 19:30:00,23195 2015-01-21 20:00:00,22527 2015-01-21 20:30:00,21978 2015-01-21 21:00:00,22624 2015-01-21 21:30:00,21970 2015-01-21 22:00:00,21085 2015-01-21 22:30:00,19624 2015-01-21 23:00:00,15974 2015-01-21 23:30:00,12520 2015-01-22 00:00:00,10173 2015-01-22 00:30:00,7771 2015-01-22 01:00:00,6287 2015-01-22 01:30:00,4720 2015-01-22 02:00:00,3642 2015-01-22 02:30:00,2769 2015-01-22 03:00:00,2406 2015-01-22 03:30:00,2194 2015-01-22 04:00:00,2275 2015-01-22 04:30:00,2021 2015-01-22 05:00:00,2385 2015-01-22 05:30:00,4276 2015-01-22 06:00:00,6311 2015-01-22 06:30:00,11643 2015-01-22 07:00:00,14874 2015-01-22 07:30:00,19720 2015-01-22 08:00:00,20607 2015-01-22 08:30:00,20838 2015-01-22 09:00:00,19347 2015-01-22 09:30:00,18316 2015-01-22 10:00:00,16233 2015-01-22 10:30:00,16420 2015-01-22 11:00:00,14997 2015-01-22 11:30:00,17341 2015-01-22 12:00:00,17606 2015-01-22 12:30:00,16850 2015-01-22 13:00:00,15625 2015-01-22 13:30:00,17210 2015-01-22 14:00:00,17552 2015-01-22 14:30:00,18531 2015-01-22 15:00:00,18806 2015-01-22 15:30:00,17322 2015-01-22 16:00:00,15719 2015-01-22 16:30:00,14717 2015-01-22 17:00:00,16955 2015-01-22 17:30:00,20647 2015-01-22 18:00:00,23122 2015-01-22 18:30:00,25031 2015-01-22 19:00:00,25376 2015-01-22 19:30:00,25849 2015-01-22 20:00:00,24434 2015-01-22 20:30:00,23690 2015-01-22 21:00:00,24704 2015-01-22 21:30:00,25221 2015-01-22 22:00:00,24320 2015-01-22 22:30:00,22823 2015-01-22 23:00:00,21754 2015-01-22 23:30:00,17946 2015-01-23 00:00:00,14722 2015-01-23 00:30:00,11815 2015-01-23 01:00:00,9274 2015-01-23 01:30:00,7241 2015-01-23 02:00:00,6184 2015-01-23 02:30:00,4956 2015-01-23 03:00:00,4158 2015-01-23 03:30:00,3499 2015-01-23 04:00:00,3433 2015-01-23 04:30:00,2736 2015-01-23 05:00:00,2534 2015-01-23 05:30:00,4436 2015-01-23 06:00:00,6559 2015-01-23 06:30:00,11173 2015-01-23 07:00:00,14477 2015-01-23 07:30:00,19424 2015-01-23 08:00:00,20059 2015-01-23 08:30:00,20211 2015-01-23 09:00:00,19220 2015-01-23 09:30:00,18519 2015-01-23 10:00:00,16466 2015-01-23 10:30:00,16651 2015-01-23 11:00:00,15564 2015-01-23 11:30:00,17483 2015-01-23 12:00:00,18057 2015-01-23 12:30:00,16855 2015-01-23 13:00:00,16827 2015-01-23 13:30:00,17900 2015-01-23 14:00:00,18747 2015-01-23 14:30:00,19493 2015-01-23 15:00:00,19020 2015-01-23 15:30:00,17169 2015-01-23 16:00:00,15680 2015-01-23 16:30:00,15126 2015-01-23 17:00:00,17664 2015-01-23 17:30:00,21065 2015-01-23 18:00:00,23573 2015-01-23 18:30:00,25063 2015-01-23 19:00:00,26854 2015-01-23 19:30:00,26037 2015-01-23 20:00:00,24863 2015-01-23 20:30:00,23793 2015-01-23 21:00:00,23560 2015-01-23 21:30:00,23904 2015-01-23 22:00:00,25266 2015-01-23 22:30:00,25284 2015-01-23 23:00:00,25157 2015-01-23 23:30:00,24597 2015-01-24 00:00:00,24223 2015-01-24 00:30:00,21761 2015-01-24 01:00:00,20356 2015-01-24 01:30:00,18221 2015-01-24 02:00:00,14264 2015-01-24 02:30:00,11852 2015-01-24 03:00:00,10245 2015-01-24 03:30:00,8895 2015-01-24 04:00:00,7634 2015-01-24 04:30:00,4822 2015-01-24 05:00:00,3521 2015-01-24 05:30:00,2971 2015-01-24 06:00:00,3225 2015-01-24 06:30:00,4324 2015-01-24 07:00:00,4948 2015-01-24 07:30:00,6401 2015-01-24 08:00:00,7537 2015-01-24 08:30:00,10085 2015-01-24 09:00:00,11421 2015-01-24 09:30:00,15063 2015-01-24 10:00:00,14932 2015-01-24 10:30:00,16512 2015-01-24 11:00:00,16893 2015-01-24 11:30:00,19945 2015-01-24 12:00:00,19851 2015-01-24 12:30:00,20385 2015-01-24 13:00:00,20321 2015-01-24 13:30:00,19563 2015-01-24 14:00:00,18692 2015-01-24 14:30:00,19016 2015-01-24 15:00:00,19252 2015-01-24 15:30:00,19325 2015-01-24 16:00:00,19139 2015-01-24 16:30:00,19092 2015-01-24 17:00:00,19901 2015-01-24 17:30:00,21433 2015-01-24 18:00:00,22997 2015-01-24 18:30:00,24210 2015-01-24 19:00:00,26175 2015-01-24 19:30:00,24935 2015-01-24 20:00:00,21243 2015-01-24 20:30:00,20206 2015-01-24 21:00:00,20188 2015-01-24 21:30:00,21588 2015-01-24 22:00:00,24357 2015-01-24 22:30:00,25009 2015-01-24 23:00:00,25641 2015-01-24 23:30:00,25928 2015-01-25 00:00:00,25026 2015-01-25 00:30:00,23773 2015-01-25 01:00:00,22667 2015-01-25 01:30:00,20864 2015-01-25 02:00:00,19498 2015-01-25 02:30:00,17494 2015-01-25 03:00:00,15262 2015-01-25 03:30:00,12727 2015-01-25 04:00:00,10682 2015-01-25 04:30:00,5804 2015-01-25 05:00:00,3732 2015-01-25 05:30:00,3050 2015-01-25 06:00:00,2793 2015-01-25 06:30:00,3690 2015-01-25 07:00:00,4009 2015-01-25 07:30:00,5014 2015-01-25 08:00:00,5354 2015-01-25 08:30:00,7694 2015-01-25 09:00:00,9298 2015-01-25 09:30:00,12036 2015-01-25 10:00:00,13457 2015-01-25 10:30:00,16776 2015-01-25 11:00:00,16838 2015-01-25 11:30:00,18681 2015-01-25 12:00:00,19382 2015-01-25 12:30:00,19841 2015-01-25 13:00:00,19688 2015-01-25 13:30:00,19900 2015-01-25 14:00:00,19767 2015-01-25 14:30:00,19114 2015-01-25 15:00:00,18144 2015-01-25 15:30:00,18343 2015-01-25 16:00:00,17879 2015-01-25 16:30:00,17910 2015-01-25 17:00:00,17868 2015-01-25 17:30:00,19079 2015-01-25 18:00:00,19687 2015-01-25 18:30:00,19227 2015-01-25 19:00:00,17843 2015-01-25 19:30:00,16231 2015-01-25 20:00:00,14905 2015-01-25 20:30:00,14598 2015-01-25 21:00:00,13551 2015-01-25 21:30:00,13933 2015-01-25 22:00:00,12374 2015-01-25 22:30:00,10625 2015-01-25 23:00:00,9964 2015-01-25 23:30:00,8190 2015-01-26 00:00:00,6663 2015-01-26 00:30:00,5151 2015-01-26 01:00:00,4092 2015-01-26 01:30:00,3207 2015-01-26 02:00:00,2626 2015-01-26 02:30:00,1994 2015-01-26 03:00:00,1987 2015-01-26 03:30:00,1912 2015-01-26 04:00:00,2156 2015-01-26 04:30:00,2175 2015-01-26 05:00:00,2757 2015-01-26 05:30:00,4689 2015-01-26 06:00:00,6715 2015-01-26 06:30:00,11577 2015-01-26 07:00:00,13954 2015-01-26 07:30:00,17717 2015-01-26 08:00:00,18686 2015-01-26 08:30:00,18923 2015-01-26 09:00:00,17326 2015-01-26 09:30:00,15926 2015-01-26 10:00:00,13785 2015-01-26 10:30:00,13905 2015-01-26 11:00:00,13575 2015-01-26 11:30:00,14094 2015-01-26 12:00:00,14488 2015-01-26 12:30:00,14428 2015-01-26 13:00:00,14402 2015-01-26 13:30:00,14747 2015-01-26 14:00:00,13915 2015-01-26 14:30:00,11432 2015-01-26 15:00:00,9659 2015-01-26 15:30:00,7681 2015-01-26 16:00:00,6257 2015-01-26 16:30:00,5520 2015-01-26 17:00:00,5159 2015-01-26 17:30:00,5283 2015-01-26 18:00:00,5821 2015-01-26 18:30:00,5586 2015-01-26 19:00:00,4729 2015-01-26 19:30:00,4402 2015-01-26 20:00:00,3877 2015-01-26 20:30:00,3384 2015-01-26 21:00:00,3203 2015-01-26 21:30:00,2611 2015-01-26 22:00:00,1783 2015-01-26 22:30:00,866 2015-01-26 23:00:00,297 2015-01-26 23:30:00,189 2015-01-27 00:00:00,109 2015-01-27 00:30:00,80 2015-01-27 01:00:00,40 2015-01-27 01:30:00,39 2015-01-27 02:00:00,26 2015-01-27 02:30:00,32 2015-01-27 03:00:00,8 2015-01-27 03:30:00,11 2015-01-27 04:00:00,9 2015-01-27 04:30:00,20 2015-01-27 05:00:00,21 2015-01-27 05:30:00,37 2015-01-27 06:00:00,69 2015-01-27 06:30:00,107 2015-01-27 07:00:00,216 2015-01-27 07:30:00,332 2015-01-27 08:00:00,570 2015-01-27 08:30:00,1049 2015-01-27 09:00:00,1589 2015-01-27 09:30:00,2285 2015-01-27 10:00:00,2945 2015-01-27 10:30:00,3544 2015-01-27 11:00:00,3876 2015-01-27 11:30:00,4535 2015-01-27 12:00:00,4923 2015-01-27 12:30:00,5157 2015-01-27 13:00:00,5273 2015-01-27 13:30:00,5584 2015-01-27 14:00:00,5773 2015-01-27 14:30:00,6569 2015-01-27 15:00:00,7007 2015-01-27 15:30:00,7400 2015-01-27 16:00:00,7962 2015-01-27 16:30:00,8760 2015-01-27 17:00:00,9776 2015-01-27 17:30:00,10863 2015-01-27 18:00:00,12687 2015-01-27 18:30:00,12541 2015-01-27 19:00:00,11967 2015-01-27 19:30:00,10813 2015-01-27 20:00:00,10419 2015-01-27 20:30:00,10132 2015-01-27 21:00:00,10566 2015-01-27 21:30:00,11073 2015-01-27 22:00:00,10559 2015-01-27 22:30:00,9121 2015-01-27 23:00:00,8700 2015-01-27 23:30:00,6884 2015-01-28 00:00:00,5502 2015-01-28 00:30:00,4001 2015-01-28 01:00:00,3039 2015-01-28 01:30:00,2431 2015-01-28 02:00:00,2005 2015-01-28 02:30:00,1661 2015-01-28 03:00:00,1300 2015-01-28 03:30:00,1279 2015-01-28 04:00:00,1407 2015-01-28 04:30:00,1353 2015-01-28 05:00:00,1887 2015-01-28 05:30:00,3714 2015-01-28 06:00:00,6019 2015-01-28 06:30:00,11208 2015-01-28 07:00:00,14063 2015-01-28 07:30:00,17572 2015-01-28 08:00:00,18746 2015-01-28 08:30:00,18397 2015-01-28 09:00:00,17430 2015-01-28 09:30:00,15997 2015-01-28 10:00:00,13900 2015-01-28 10:30:00,14138 2015-01-28 11:00:00,13361 2015-01-28 11:30:00,14156 2015-01-28 12:00:00,14075 2015-01-28 12:30:00,13887 2015-01-28 13:00:00,13593 2015-01-28 13:30:00,14093 2015-01-28 14:00:00,14699 2015-01-28 14:30:00,15372 2015-01-28 15:00:00,16220 2015-01-28 15:30:00,15107 2015-01-28 16:00:00,14057 2015-01-28 16:30:00,13802 2015-01-28 17:00:00,15961 2015-01-28 17:30:00,18422 2015-01-28 18:00:00,21270 2015-01-28 18:30:00,22262 2015-01-28 19:00:00,22786 2015-01-28 19:30:00,22169 2015-01-28 20:00:00,21155 2015-01-28 20:30:00,20120 2015-01-28 21:00:00,20428 2015-01-28 21:30:00,20309 2015-01-28 22:00:00,20059 2015-01-28 22:30:00,19055 2015-01-28 23:00:00,15481 2015-01-28 23:30:00,12535 2015-01-29 00:00:00,10134 2015-01-29 00:30:00,7568 2015-01-29 01:00:00,5619 2015-01-29 01:30:00,4342 2015-01-29 02:00:00,3604 2015-01-29 02:30:00,2822 2015-01-29 03:00:00,2379 2015-01-29 03:30:00,2121 2015-01-29 04:00:00,2130 2015-01-29 04:30:00,1968 2015-01-29 05:00:00,2339 2015-01-29 05:30:00,4306 2015-01-29 06:00:00,6575 2015-01-29 06:30:00,11896 2015-01-29 07:00:00,15030 2015-01-29 07:30:00,18687 2015-01-29 08:00:00,19710 2015-01-29 08:30:00,19585 2015-01-29 09:00:00,18438 2015-01-29 09:30:00,17398 2015-01-29 10:00:00,16241 2015-01-29 10:30:00,15905 2015-01-29 11:00:00,14690 2015-01-29 11:30:00,16203 2015-01-29 12:00:00,16711 2015-01-29 12:30:00,16013 2015-01-29 13:00:00,15725 2015-01-29 13:30:00,16432 2015-01-29 14:00:00,17190 2015-01-29 14:30:00,17571 2015-01-29 15:00:00,18184 2015-01-29 15:30:00,16484 2015-01-29 16:00:00,14774 2015-01-29 16:30:00,13800 2015-01-29 17:00:00,15971 2015-01-29 17:30:00,19384 2015-01-29 18:00:00,21649 2015-01-29 18:30:00,23102 2015-01-29 19:00:00,23464 2015-01-29 19:30:00,23343 2015-01-29 20:00:00,23197 2015-01-29 20:30:00,23120 2015-01-29 21:00:00,23208 2015-01-29 21:30:00,23188 2015-01-29 22:00:00,22638 2015-01-29 22:30:00,21501 2015-01-29 23:00:00,20719 2015-01-29 23:30:00,17877 2015-01-30 00:00:00,14367 2015-01-30 00:30:00,11118 2015-01-30 01:00:00,8733 2015-01-30 01:30:00,6954 2015-01-30 02:00:00,5898 2015-01-30 02:30:00,4541 2015-01-30 03:00:00,3834 2015-01-30 03:30:00,3143 2015-01-30 04:00:00,3295 2015-01-30 04:30:00,2652 2015-01-30 05:00:00,2541 2015-01-30 05:30:00,4585 2015-01-30 06:00:00,6626 2015-01-30 06:30:00,11854 2015-01-30 07:00:00,15913 2015-01-30 07:30:00,19574 2015-01-30 08:00:00,20898 2015-01-30 08:30:00,20859 2015-01-30 09:00:00,19707 2015-01-30 09:30:00,18495 2015-01-30 10:00:00,17096 2015-01-30 10:30:00,16561 2015-01-30 11:00:00,16496 2015-01-30 11:30:00,17310 2015-01-30 12:00:00,17354 2015-01-30 12:30:00,16305 2015-01-30 13:00:00,16685 2015-01-30 13:30:00,18077 2015-01-30 14:00:00,18375 2015-01-30 14:30:00,18633 2015-01-30 15:00:00,18401 2015-01-30 15:30:00,17079 2015-01-30 16:00:00,15582 2015-01-30 16:30:00,14719 2015-01-30 17:00:00,17569 2015-01-30 17:30:00,21013 2015-01-30 18:00:00,23696 2015-01-30 18:30:00,25758 2015-01-30 19:00:00,27289 2015-01-30 19:30:00,28107 2015-01-30 20:00:00,27308 2015-01-30 20:30:00,26570 2015-01-30 21:00:00,25935 2015-01-30 21:30:00,26432 2015-01-30 22:00:00,26739 2015-01-30 22:30:00,26874 2015-01-30 23:00:00,26928 2015-01-30 23:30:00,26000 2015-01-31 00:00:00,25778 2015-01-31 00:30:00,23304 2015-01-31 01:00:00,21318 2015-01-31 01:30:00,19024 2015-01-31 02:00:00,17022 2015-01-31 02:30:00,14733 2015-01-31 03:00:00,12593 2015-01-31 03:30:00,11048 2015-01-31 04:00:00,9364 2015-01-31 04:30:00,5209 2015-01-31 05:00:00,3683 2015-01-31 05:30:00,3329 2015-01-31 06:00:00,3714 2015-01-31 06:30:00,4531 2015-01-31 07:00:00,4803 2015-01-31 07:30:00,7049 2015-01-31 08:00:00,8363 2015-01-31 08:30:00,11899 2015-01-31 09:00:00,13522 2015-01-31 09:30:00,18164 2015-01-31 10:00:00,17645 2015-01-31 10:30:00,20056 2015-01-31 11:00:00,20270 2015-01-31 11:30:00,22865 2015-01-31 12:00:00,22951 2015-01-31 12:30:00,23387 2015-01-31 13:00:00,23069 2015-01-31 13:30:00,23298 2015-01-31 14:00:00,21817 2015-01-31 14:30:00,21565 2015-01-31 15:00:00,21729 2015-01-31 15:30:00,22838 2015-01-31 16:00:00,21068 2015-01-31 16:30:00,19920 2015-01-31 17:00:00,20715 2015-01-31 17:30:00,23595 2015-01-31 18:00:00,26044 2015-01-31 18:30:00,27286 2015-01-31 19:00:00,28804 2015-01-31 19:30:00,27773 2015-01-31 20:00:00,24985 2015-01-31 20:30:00,23291 2015-01-31 21:00:00,23719 2015-01-31 21:30:00,24670 2015-01-31 22:00:00,25721 2015-01-31 22:30:00,27309 2015-01-31 23:00:00,26591 2015-01-31 23:30:00,26288 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/occupancy_6005.csv ================================================ timestamp,value 2015-09-01 13:45:00,3.06 2015-09-01 13:50:00,6.44 2015-09-01 13:55:00,5.17 2015-09-01 14:00:00,3.83 2015-09-01 14:05:00,4.5 2015-09-01 14:20:00,2.94 2015-09-01 14:25:00,2.28 2015-09-01 14:35:00,1.67 2015-09-01 14:40:00,18.83 2015-09-01 14:45:00,12 2015-09-01 14:50:00,13.11 2015-09-01 14:55:00,12.72 2015-09-01 15:20:00,1.67 2015-09-01 17:15:00,12.78 2015-09-01 17:25:00,7.5 2015-09-01 17:30:00,1.94 2015-09-01 17:35:00,3.72 2015-09-01 17:45:00,2.72 2015-09-01 17:55:00,3.83 2015-09-01 18:10:00,3.83 2015-09-01 18:45:00,1.83 2015-09-01 18:50:00,2.56 2015-09-01 19:00:00,2.28 2015-09-01 19:05:00,2.28 2015-09-01 19:10:00,7.89 2015-09-01 19:20:00,2.28 2015-09-01 19:25:00,2.06 2015-09-01 19:30:00,1.17 2015-09-01 19:40:00,1.17 2015-09-01 19:55:00,1.56 2015-09-01 20:00:00,3.61 2015-09-01 20:05:00,2.72 2015-09-01 20:10:00,1.17 2015-09-01 20:20:00,3.44 2015-09-01 20:25:00,3.5 2015-09-01 20:30:00,4.5 2015-09-01 20:45:00,1.44 2015-09-01 20:55:00,5.44 2015-09-01 21:05:00,1.67 2015-09-01 21:25:00,5.17 2015-09-01 21:40:00,2.06 2015-09-01 22:30:00,2.56 2015-09-01 22:35:00,2.94 2015-09-01 22:40:00,1.44 2015-09-01 22:45:00,2.94 2015-09-01 23:01:00,1.83 2015-09-01 23:05:00,1.94 2015-09-01 23:10:00,2.17 2015-09-01 23:20:00,1 2015-09-01 23:40:00,0.89 2015-09-02 00:00:00,1.39 2015-09-02 00:05:00,0.28 2015-09-02 00:15:00,0.39 2015-09-02 00:20:00,1 2015-09-02 00:35:00,1 2015-09-02 01:00:00,0.5 2015-09-02 01:35:00,0.22 2015-09-02 02:10:00,5 2015-09-02 02:25:00,0.5 2015-09-02 02:40:00,0 2015-09-02 03:05:00,0.5 2015-09-02 03:10:00,0 2015-09-02 03:35:00,1.67 2015-09-02 04:15:00,2.17 2015-09-02 04:20:00,0.5 2015-09-02 04:25:00,1.44 2015-09-02 04:30:00,1.39 2015-09-02 04:35:00,3.5 2015-09-02 04:45:00,2.56 2015-09-02 04:50:00,2.56 2015-09-02 05:00:00,6.06 2015-09-02 05:05:00,2.06 2015-09-02 05:15:00,4.39 2015-09-02 05:20:00,5.44 2015-09-02 05:25:00,12.39 2015-09-02 05:30:00,5.83 2015-09-02 05:35:00,4.5 2015-09-02 05:45:00,9.28 2015-09-02 05:50:00,5.39 2015-09-02 05:55:00,9.17 2015-09-02 06:00:00,7.5 2015-09-02 06:05:00,10.33 2015-09-02 06:10:00,10.44 2015-09-02 06:15:00,10.94 2015-09-02 06:20:00,8.89 2015-09-02 06:25:00,15.61 2015-09-02 06:30:00,11.89 2015-09-02 06:35:00,17 2015-09-02 06:40:00,7.83 2015-09-02 06:45:00,11.11 2015-09-02 06:50:00,14.33 2015-09-02 06:55:00,10.83 2015-09-02 07:00:00,8.11 2015-09-02 07:05:00,14.83 2015-09-02 07:10:00,13.67 2015-09-02 07:15:00,16.5 2015-09-02 07:20:00,12.28 2015-09-02 07:25:00,11.06 2015-09-02 07:30:00,7.61 2015-09-02 07:35:00,11.44 2015-09-02 07:40:00,6.33 2015-09-02 07:45:00,13.89 2015-09-02 07:50:00,9.44 2015-09-02 07:55:00,2.72 2015-09-02 08:00:00,6.17 2015-09-02 08:05:00,11.83 2015-09-02 08:10:00,8.5 2015-09-02 08:15:00,6.06 2015-09-02 08:20:00,7.5 2015-09-02 08:30:00,9.78 2015-09-02 08:35:00,11.89 2015-09-02 08:45:00,9.28 2015-09-02 08:50:00,6.44 2015-09-02 08:55:00,4.28 2015-09-02 09:00:00,6.83 2015-09-02 09:05:00,8 2015-09-02 09:10:00,9 2015-09-02 09:20:00,1.06 2015-09-02 09:30:00,4.11 2015-09-02 09:35:00,8.11 2015-09-02 09:40:00,5.06 2015-09-02 09:50:00,4.61 2015-09-02 09:55:00,1 2015-09-02 10:00:00,1.39 2015-09-02 10:10:00,4.22 2015-09-02 10:15:00,3.33 2015-09-02 10:20:00,4.67 2015-09-02 10:25:00,3.33 2015-09-02 10:30:00,2.94 2015-09-02 10:35:00,3.83 2015-09-02 10:40:00,1.78 2015-09-02 10:45:00,3.89 2015-09-02 10:50:00,3.5 2015-09-02 11:00:00,6.67 2015-09-02 11:15:00,2.28 2015-09-02 11:20:00,5.39 2015-09-02 11:25:00,4.11 2015-09-02 11:30:00,2.17 2015-09-02 11:35:00,3.33 2015-09-02 12:00:00,1.28 2015-09-02 12:05:00,2.28 2015-09-02 12:10:00,4.28 2015-09-02 12:15:00,7.06 2015-09-02 12:25:00,4.67 2015-09-02 12:35:00,4.5 2015-09-02 12:40:00,4.89 2015-09-02 12:45:00,7.11 2015-09-02 12:50:00,2.33 2015-09-02 12:55:00,3.06 2015-09-02 13:05:00,1.56 2015-09-02 13:10:00,3.33 2015-09-02 13:15:00,4.22 2015-09-02 13:20:00,7.89 2015-09-02 13:25:00,4.28 2015-09-02 13:30:00,3.22 2015-09-02 13:35:00,5.06 2015-09-02 13:40:00,1 2015-09-02 13:45:00,4.89 2015-09-02 13:50:00,2.17 2015-09-02 13:55:00,6.28 2015-09-02 14:05:00,1 2015-09-02 14:15:00,6.28 2015-09-02 14:20:00,6.72 2015-09-02 14:25:00,5.94 2015-09-02 14:30:00,4.39 2015-09-02 14:35:00,5.06 2015-09-02 14:50:00,5.83 2015-09-02 14:55:00,3.72 2015-09-02 15:05:00,3.33 2015-09-02 15:10:00,4.67 2015-09-02 15:15:00,4.61 2015-09-02 15:20:00,4.28 2015-09-02 15:25:00,2.44 2015-09-02 15:30:00,3.11 2015-09-02 15:35:00,3.11 2015-09-02 15:40:00,2.83 2015-09-02 15:45:00,6.17 2015-09-02 15:50:00,5 2015-09-02 16:05:00,1.44 2015-09-02 16:15:00,2.17 2015-09-02 16:20:00,3.44 2015-09-02 16:25:00,6.83 2015-09-02 16:30:00,7.89 2015-09-02 16:50:00,9.39 2015-09-02 16:55:00,7.33 2015-09-02 17:00:00,5.44 2015-09-02 17:10:00,8.5 2015-09-02 17:20:00,7.83 2015-09-02 17:35:00,4 2015-09-02 17:45:00,4.78 2015-09-02 18:05:00,2.72 2015-09-02 18:10:00,5.39 2015-09-02 18:15:00,2.56 2015-09-02 18:20:00,3.83 2015-09-02 18:30:00,4.67 2015-09-02 18:35:00,4.61 2015-09-02 18:45:00,0.78 2015-09-02 18:50:00,1.56 2015-09-02 19:00:00,4 2015-09-02 19:05:00,4.11 2015-09-02 19:10:00,4.39 2015-09-02 19:15:00,2.67 2015-09-02 19:21:00,4.67 2015-09-02 19:26:00,4.22 2015-09-02 19:46:00,4.89 2015-09-02 19:56:00,1.17 2015-09-02 20:11:00,2.33 2015-09-02 20:46:00,4.89 2015-09-02 20:56:00,3.89 2015-09-02 21:00:00,4.61 2015-09-02 21:16:00,3.72 2015-09-02 21:21:00,3.5 2015-09-02 21:31:00,1.17 2015-09-02 21:36:00,2.67 2015-09-02 21:46:00,4.67 2015-09-02 21:51:00,2.28 2015-09-02 22:11:00,1.28 2015-09-02 22:21:00,3.44 2015-09-02 22:31:00,2.67 2015-09-02 22:36:00,2.56 2015-09-02 22:41:00,0.78 2015-09-02 22:51:00,1.56 2015-09-02 23:51:00,2.94 2015-09-03 00:01:00,1.83 2015-09-03 00:11:00,0 2015-09-03 00:21:00,2.33 2015-09-03 00:36:00,1.06 2015-09-03 00:41:00,0.22 2015-09-03 00:51:00,0.28 2015-09-03 01:21:00,1 2015-09-03 01:26:00,1.28 2015-09-03 01:51:00,1.44 2015-09-03 01:56:00,0.5 2015-09-03 02:01:00,0.61 2015-09-03 02:11:00,0.28 2015-09-03 02:16:00,1.78 2015-09-03 02:21:00,0.28 2015-09-03 03:11:00,1.94 2015-09-03 03:21:00,1 2015-09-03 03:26:00,1.17 2015-09-03 03:46:00,1.94 2015-09-03 03:51:00,2.44 2015-09-03 04:06:00,0.22 2015-09-03 04:11:00,1.67 2015-09-03 04:16:00,1.83 2015-09-03 04:36:00,0.39 2015-09-03 04:56:00,1.56 2015-09-03 05:01:00,4.78 2015-09-03 05:06:00,1.17 2015-09-03 05:11:00,10.94 2015-09-03 05:21:00,1.56 2015-09-03 05:26:00,3.89 2015-09-03 05:31:00,5.39 2015-09-03 05:36:00,4.11 2015-09-03 05:41:00,3.61 2015-09-03 05:46:00,2.56 2015-09-03 05:51:00,7.44 2015-09-03 05:56:00,9.94 2015-09-03 06:01:00,4.61 2015-09-03 06:06:00,12.28 2015-09-03 06:11:00,10.56 2015-09-03 06:16:00,21.17 2015-09-03 06:21:00,15.33 2015-09-03 06:26:00,12.11 2015-09-03 06:36:00,11.33 2015-09-03 06:41:00,13.94 2015-09-03 06:46:00,14.78 2015-09-03 06:51:00,11.44 2015-09-03 06:56:00,13.89 2015-09-03 07:01:00,9.39 2015-09-03 07:06:00,12 2015-09-03 07:11:00,17.89 2015-09-03 07:16:00,11.89 2015-09-03 07:21:00,10.17 2015-09-03 07:26:00,11.11 2015-09-03 07:31:00,21.11 2015-09-03 07:36:00,9.28 2015-09-03 07:41:00,5.28 2015-09-03 07:46:00,10.06 2015-09-03 07:51:00,10.72 2015-09-03 07:56:00,5.83 2015-09-03 08:01:00,6.44 2015-09-03 08:11:00,4.11 2015-09-03 08:16:00,10.28 2015-09-03 08:21:00,10.44 2015-09-03 08:26:00,9.28 2015-09-03 08:31:00,11.22 2015-09-03 08:36:00,7.44 2015-09-03 08:41:00,5.06 2015-09-03 08:46:00,15.33 2015-09-03 08:56:00,8 2015-09-03 09:01:00,3.83 2015-09-03 09:06:00,14.28 2015-09-03 09:16:00,6.83 2015-09-03 09:21:00,5.39 2015-09-03 09:26:00,8.39 2015-09-03 09:31:00,6.72 2015-09-03 09:36:00,7.5 2015-09-03 09:41:00,7.11 2015-09-03 09:56:00,5.78 2015-09-03 10:01:00,5.28 2015-09-03 10:06:00,6.94 2015-09-03 10:11:00,5.06 2015-09-03 10:16:00,3.06 2015-09-03 10:26:00,2.94 2015-09-03 10:31:00,4.5 2015-09-03 10:36:00,4.89 2015-09-03 10:41:00,3.5 2015-09-03 10:46:00,4.61 2015-09-03 10:51:00,1.67 2015-09-03 11:01:00,5.17 2015-09-03 11:06:00,3.72 2015-09-03 11:16:00,5.56 2015-09-03 11:21:00,6.28 2015-09-03 11:26:00,4.61 2015-09-03 11:36:00,7.06 2015-09-03 11:46:00,3.5 2015-09-03 12:01:00,3.83 2015-09-03 12:06:00,1.67 2015-09-03 12:11:00,3.72 2015-09-03 12:16:00,2.83 2015-09-03 12:21:00,2.83 2015-09-03 12:31:00,3.89 2015-09-03 12:41:00,7.33 2015-09-03 12:46:00,3.61 2015-09-03 12:51:00,2.67 2015-09-03 12:56:00,4.11 2015-09-03 13:01:00,4.61 2015-09-03 13:06:00,0.78 2015-09-03 13:11:00,5.44 2015-09-03 13:21:00,1 2015-09-03 13:26:00,1.78 2015-09-03 13:31:00,8.5 2015-09-03 13:41:00,5.56 2015-09-03 13:46:00,9.83 2015-09-03 14:01:00,6.17 2015-09-03 14:06:00,2.28 2015-09-03 14:11:00,8.28 2015-09-03 14:16:00,7.72 2015-09-03 14:21:00,4.89 2015-09-03 14:26:00,6.94 2015-09-03 14:31:00,5.39 2015-09-03 14:41:00,8.78 2015-09-03 14:46:00,7.5 2015-09-03 14:56:00,7.61 2015-09-03 15:01:00,6.72 2015-09-03 15:06:00,2.17 2015-09-03 15:11:00,5.67 2015-09-03 15:16:00,7.22 2015-09-03 15:21:00,5 2015-09-03 15:26:00,5.17 2015-09-03 15:31:00,9.94 2015-09-03 15:36:00,10.72 2015-09-03 15:41:00,7.44 2015-09-03 15:46:00,9.83 2015-09-03 15:51:00,3.89 2015-09-03 15:56:00,4.11 2015-09-03 16:06:00,4 2015-09-03 16:21:00,7.22 2015-09-03 16:31:00,3.44 2015-09-03 16:36:00,7.33 2015-09-03 16:41:00,9 2015-09-03 16:46:00,11.44 2015-09-03 16:56:00,10.17 2015-09-03 17:01:00,8.67 2015-09-03 17:06:00,9.83 2015-09-03 17:11:00,4.5 2015-09-03 17:16:00,9.83 2015-09-03 17:21:00,3.83 2015-09-03 17:26:00,7.22 2015-09-03 17:36:00,5.78 2015-09-03 17:41:00,10.28 2015-09-03 17:46:00,3.89 2015-09-03 17:51:00,5.28 2015-09-03 17:56:00,3.5 2015-09-03 18:01:00,7.5 2015-09-03 18:11:00,7.72 2015-09-03 18:16:00,2.94 2015-09-03 18:21:00,3.33 2015-09-03 18:31:00,3.61 2015-09-03 18:36:00,2.83 2015-09-03 18:41:00,7.06 2015-09-03 18:51:00,3.06 2015-09-03 19:06:00,3.33 2015-09-03 19:11:00,6.67 2015-09-03 19:21:00,3.5 2015-09-03 19:26:00,3.44 2015-09-03 20:02:00,1.67 2015-09-03 20:12:00,3.11 2015-09-03 20:17:00,7.22 2015-09-03 20:22:00,3.06 2015-09-03 20:27:00,5.56 2015-09-03 20:57:00,1.67 2015-09-03 21:02:00,4 2015-09-03 21:32:00,0.67 2015-09-03 21:42:00,4.89 2015-09-03 22:02:00,0.39 2015-09-03 22:22:00,1.56 2015-09-03 22:27:00,2.67 2015-09-03 23:22:00,3.22 2015-09-03 23:27:00,4.11 2015-09-03 23:32:00,3.11 2015-09-03 23:42:00,0.89 2015-09-03 23:57:00,5.06 2015-09-04 00:02:00,2.56 2015-09-04 00:07:00,0.22 2015-09-04 00:22:00,0.61 2015-09-04 00:27:00,1 2015-09-04 00:42:00,0.28 2015-09-04 01:07:00,1.28 2015-09-04 01:27:00,1.78 2015-09-04 02:27:00,1.44 2015-09-04 02:52:00,1.17 2015-09-04 02:57:00,1.44 2015-09-04 03:12:00,1.39 2015-09-04 03:27:00,2.56 2015-09-04 04:02:00,1.78 2015-09-04 04:22:00,1.39 2015-09-04 04:37:00,4.39 2015-09-04 04:52:00,0.67 2015-09-04 05:12:00,5.06 2015-09-04 05:17:00,3.44 2015-09-04 05:22:00,3.61 2015-09-04 05:32:00,4.67 2015-09-04 05:37:00,3.61 2015-09-04 05:42:00,8.78 2015-09-04 05:47:00,6.17 2015-09-04 05:52:00,2.56 2015-09-04 05:57:00,5.67 2015-09-04 06:07:00,5 2015-09-04 06:12:00,6.56 2015-09-04 06:17:00,8.39 2015-09-04 06:22:00,6.83 2015-09-04 06:27:00,10.67 2015-09-04 06:32:00,8.28 2015-09-04 06:37:00,9.06 2015-09-04 06:42:00,8.78 2015-09-04 06:47:00,5.83 2015-09-04 06:52:00,14.28 2015-09-04 06:57:00,15.56 2015-09-04 07:02:00,5.67 2015-09-04 07:07:00,4.61 2015-09-04 07:12:00,9.06 2015-09-04 07:22:00,9.39 2015-09-04 07:27:00,12.22 2015-09-04 07:32:00,8.5 2015-09-04 07:37:00,8.67 2015-09-04 07:47:00,6.56 2015-09-04 07:52:00,6.17 2015-09-04 07:57:00,8.89 2015-09-04 08:02:00,7.72 2015-09-04 08:07:00,12.11 2015-09-04 08:12:00,7.22 2015-09-04 08:17:00,9.28 2015-09-04 08:22:00,10.94 2015-09-04 08:27:00,5.17 2015-09-04 08:32:00,6.83 2015-09-04 08:37:00,5.78 2015-09-04 08:52:00,7.89 2015-09-04 08:57:00,2.33 2015-09-04 09:12:00,7.06 2015-09-04 09:17:00,8 2015-09-04 09:32:00,2.94 2015-09-04 09:42:00,2.17 2015-09-04 09:47:00,6.17 2015-09-04 09:52:00,8.22 2015-09-04 09:57:00,4 2015-09-04 10:12:00,3.89 2015-09-04 10:17:00,8.22 2015-09-04 10:22:00,4.78 2015-09-04 10:27:00,3.83 2015-09-04 10:32:00,6.17 2015-09-04 10:37:00,4.11 2015-09-04 10:42:00,2.83 2015-09-04 10:47:00,5.56 2015-09-04 10:57:00,3.33 2015-09-04 11:02:00,8.61 2015-09-04 11:07:00,4.5 2015-09-04 11:17:00,5.94 2015-09-04 11:22:00,9.39 2015-09-04 11:27:00,3.11 2015-09-04 11:32:00,6.72 2015-09-04 11:37:00,4.61 2015-09-04 11:42:00,5.67 2015-09-04 11:47:00,4.89 2015-09-04 11:52:00,5.78 2015-09-04 11:57:00,7.5 2015-09-04 12:12:00,3.72 2015-09-04 12:27:00,2.33 2015-09-04 12:32:00,5.06 2015-09-04 12:37:00,6.44 2015-09-04 12:42:00,2.44 2015-09-04 12:52:00,6.33 2015-09-04 12:57:00,9.78 2015-09-04 13:02:00,2.17 2015-09-04 13:12:00,6.67 2015-09-04 13:17:00,6.83 2015-09-04 13:27:00,2.06 2015-09-04 13:37:00,8.22 2015-09-04 13:47:00,7.61 2015-09-04 13:52:00,5.56 2015-09-04 13:57:00,4.61 2015-09-04 14:02:00,3.11 2015-09-04 14:07:00,6.44 2015-09-04 14:12:00,4.11 2015-09-04 14:17:00,11.44 2015-09-04 14:22:00,7.22 2015-09-04 14:27:00,8.28 2015-09-04 14:32:00,3.11 2015-09-04 14:37:00,3.22 2015-09-04 14:42:00,4.39 2015-09-04 14:47:00,8.67 2015-09-04 14:52:00,2.33 2015-09-04 15:02:00,3.61 2015-09-04 15:17:00,3.5 2015-09-04 15:22:00,6.17 2015-09-04 15:32:00,6.44 2015-09-04 15:42:00,3.89 2015-09-04 15:47:00,5.83 2015-09-04 15:52:00,6.67 2015-09-04 16:02:00,6.83 2015-09-04 16:12:00,3.61 2015-09-04 16:17:00,4.39 2015-09-04 16:27:00,3.72 2015-09-04 16:32:00,5.28 2015-09-04 16:42:00,5.28 2015-09-04 16:47:00,4.28 2015-09-04 16:52:00,5 2015-09-04 16:57:00,7.06 2015-09-04 17:02:00,4.61 2015-09-04 17:07:00,5.39 2015-09-04 17:12:00,14.44 2015-09-04 17:17:00,7.61 2015-09-04 17:22:00,11.5 2015-09-04 17:27:00,6.33 2015-09-04 17:32:00,6.44 2015-09-04 17:37:00,6.06 2015-09-04 17:42:00,6.33 2015-09-04 17:47:00,3.61 2015-09-04 18:02:00,5 2015-09-04 18:07:00,5.56 2015-09-04 18:12:00,2.72 2015-09-04 18:17:00,6.33 2015-09-04 18:22:00,4.22 2015-09-04 18:27:00,4.11 2015-09-04 18:32:00,4.78 2015-09-04 18:37:00,7.5 2015-09-04 18:42:00,13.28 2015-09-04 18:47:00,7.22 2015-09-04 18:52:00,10.06 2015-09-04 18:57:00,2.44 2015-09-04 19:02:00,3.83 2015-09-04 19:07:00,2.33 2015-09-04 19:12:00,4.28 2015-09-04 19:22:00,2.06 2015-09-04 19:27:00,1.39 2015-09-04 19:32:00,4.22 2015-09-04 19:42:00,2.33 2015-09-04 19:47:00,1.56 2015-09-04 19:57:00,5.67 2015-09-04 20:02:00,4 2015-09-04 20:12:00,3.33 2015-09-04 20:17:00,4.28 2015-09-04 20:23:00,2.17 2015-09-04 20:28:00,4.61 2015-09-04 20:33:00,3.33 2015-09-04 20:38:00,6.28 2015-09-04 20:48:00,1.78 2015-09-04 20:53:00,3.5 2015-09-04 21:03:00,3.22 2015-09-04 21:13:00,3.44 2015-09-04 21:18:00,5.17 2015-09-04 21:33:00,2.72 2015-09-04 21:38:00,4.22 2015-09-04 21:53:00,2.83 2015-09-04 22:08:00,0.89 2015-09-04 22:13:00,1.83 2015-09-04 22:23:00,3.72 2015-09-04 22:34:00,3.61 2015-09-04 22:41:00,0.78 2015-09-08 10:44:00,3.61 2015-09-08 10:49:00,1.44 2015-09-08 10:59:00,4.28 2015-09-08 11:04:00,6.28 2015-09-08 11:09:00,4.61 2015-09-08 11:14:00,5.28 2015-09-08 11:19:00,2.06 2015-09-08 11:29:00,7.5 2015-09-08 11:34:00,8.39 2015-09-08 11:39:00,0.67 2015-09-08 11:49:00,2.94 2015-09-08 11:59:00,1.67 2015-09-08 12:14:00,5.44 2015-09-08 12:19:00,3.72 2015-09-08 12:24:00,3.5 2015-09-08 12:27:00,3.11 2015-09-08 12:32:00,5.78 2015-09-08 12:36:00,4.67 2015-09-08 12:46:00,9 2015-09-08 12:51:00,6.72 2015-09-08 12:56:00,1 2015-09-08 13:01:00,5.17 2015-09-08 13:06:00,8.89 2015-09-08 13:16:00,6.06 2015-09-08 13:26:00,1.39 2015-09-08 13:36:00,2.44 2015-09-08 13:41:00,3.44 2015-09-08 13:46:00,6.06 2015-09-08 13:51:00,1.78 2015-09-08 13:56:00,3.89 2015-09-08 14:00:00,5 2015-09-08 14:06:00,5 2015-09-08 14:11:00,10.28 2015-09-08 14:21:00,1.17 2015-09-08 14:31:00,4.67 2015-09-08 14:36:00,5 2015-09-08 14:41:00,5.39 2015-09-08 14:51:00,1.67 2015-09-08 14:56:00,4.39 2015-09-08 15:01:00,4.22 2015-09-08 15:06:00,4.5 2015-09-08 15:11:00,7.89 2015-09-08 15:16:00,4.28 2015-09-08 15:26:00,5.06 2015-09-08 15:29:00,2.72 2015-09-08 15:41:00,5.56 2015-09-08 16:15:00,6.83 2015-09-08 16:31:00,2.83 2015-09-08 16:36:00,3.44 2015-09-08 16:41:00,2.06 2015-09-08 16:46:00,7.06 2015-09-08 16:56:00,1.83 2015-09-08 17:06:00,7.72 2015-09-08 17:11:00,6.94 2015-09-08 17:21:00,5.28 2015-09-08 17:26:00,3.5 2015-09-08 17:31:00,5.83 2015-09-08 17:36:00,8.22 2015-09-08 17:46:00,6.33 2015-09-08 17:51:00,4.11 2015-09-08 17:56:00,5 2015-09-08 18:26:00,1.78 2015-09-08 18:31:00,7.89 2015-09-08 18:36:00,4.78 2015-09-08 18:41:00,2.72 2015-09-08 18:46:00,1 2015-09-08 18:56:00,1.17 2015-09-08 19:01:00,5.56 2015-09-08 19:06:00,1.28 2015-09-08 19:16:00,7.44 2015-09-08 19:26:00,2.44 2015-09-08 19:36:00,2.67 2015-09-08 19:41:00,4.39 2015-09-08 19:46:00,1.44 2015-09-08 19:51:00,1.56 2015-09-08 20:06:00,2.72 2015-09-08 20:11:00,2.67 2015-09-08 20:26:00,1.56 2015-09-08 20:36:00,2.94 2015-09-08 20:41:00,0.67 2015-09-08 20:46:00,1.44 2015-09-08 20:56:00,0.89 2015-09-08 21:06:00,1.78 2015-09-08 21:11:00,1.56 2015-09-08 21:16:00,0.89 2015-09-08 21:21:00,2.33 2015-09-08 21:46:00,0.22 2015-09-08 21:51:00,1.39 2015-09-08 21:56:00,0.5 2015-09-08 22:06:00,1.06 2015-09-08 22:12:00,0.67 2015-09-08 22:26:00,2.56 2015-09-08 22:36:00,1.17 2015-09-08 22:51:00,0.28 2015-09-08 22:56:00,3.33 2015-09-08 23:56:00,2.94 2015-09-09 00:26:00,1.67 2015-09-09 01:11:00,1.67 2015-09-09 01:51:00,0.61 2015-09-09 03:11:00,0.78 2015-09-09 06:04:00,12.28 2015-09-09 07:34:00,8.89 2015-09-09 09:20:00,5.06 2015-09-09 09:48:00,2.06 2015-09-09 09:53:00,6.44 2015-09-09 09:58:00,2.44 2015-09-09 10:03:00,4.67 2015-09-09 10:08:00,4.61 2015-09-09 10:18:00,5 2015-09-09 10:23:00,9.67 2015-09-09 10:33:00,4.67 2015-09-09 10:43:00,4.5 2015-09-09 10:53:00,3.83 2015-09-09 10:58:00,4.67 2015-09-09 11:08:00,5.39 2015-09-09 11:18:00,2.94 2015-09-09 11:23:00,3.06 2015-09-09 11:38:00,3.22 2015-09-09 11:43:00,2.94 2015-09-09 11:48:00,5.56 2015-09-09 11:58:00,4.89 2015-09-09 12:13:00,6.06 2015-09-09 12:23:00,2.56 2015-09-09 12:28:00,2.17 2015-09-09 12:43:00,3.06 2015-09-09 12:53:00,1.06 2015-09-09 12:58:00,5.17 2015-09-09 13:03:00,6.56 2015-09-09 13:13:00,1.44 2015-09-09 13:18:00,0.22 2015-09-09 13:23:00,1.67 2015-09-09 13:38:00,6.28 2015-09-09 13:48:00,2.67 2015-09-09 13:53:00,4.89 2015-09-09 14:08:00,2.06 2015-09-09 14:13:00,7.11 2015-09-09 14:18:00,2.06 2015-09-09 14:23:00,7.83 2015-09-09 14:33:00,3.5 2015-09-09 14:43:00,4.5 2015-09-09 15:03:00,3.06 2015-09-09 15:08:00,3.11 2015-09-09 15:13:00,11.06 2015-09-09 15:18:00,5.78 2015-09-09 15:23:00,6.56 2015-09-09 15:28:00,2.28 2015-09-09 15:33:00,7.22 2015-09-09 15:43:00,4.78 2015-09-09 15:48:00,5.56 2015-09-09 15:53:00,6.44 2015-09-09 15:58:00,3.44 2015-09-09 16:03:00,1.56 2015-09-09 16:08:00,5.39 2015-09-09 16:13:00,10.56 2015-09-09 16:23:00,8.5 2015-09-09 16:28:00,3.5 2015-09-09 16:38:00,6.17 2015-09-09 16:43:00,3.44 2015-09-09 16:48:00,5 2015-09-09 16:53:00,7.61 2015-09-09 16:58:00,3.83 2015-09-09 17:08:00,7.11 2015-09-09 17:13:00,5 2015-09-09 17:18:00,3.44 2015-09-09 17:23:00,7.22 2015-09-09 17:33:00,4.5 2015-09-09 17:48:00,3.61 2015-09-09 17:58:00,1.94 2015-09-09 18:03:00,2.56 2015-09-09 18:08:00,2.17 2015-09-09 18:18:00,3.22 2015-09-09 18:23:00,4.39 2015-09-09 18:28:00,1.17 2015-09-09 18:43:00,4.5 2015-09-09 18:48:00,1.56 2015-09-09 18:53:00,1.28 2015-09-09 19:03:00,2.56 2015-09-09 19:18:00,4.89 2015-09-09 19:33:00,4 2015-09-09 19:38:00,3.22 2015-09-09 19:43:00,2.06 2015-09-09 19:48:00,0.39 2015-09-09 19:58:00,1.67 2015-09-09 20:03:00,2.94 2015-09-09 20:08:00,4.11 2015-09-09 20:13:00,7.22 2015-09-09 20:18:00,0.61 2015-09-09 20:33:00,2.44 2015-09-09 20:38:00,1.44 2015-09-09 20:48:00,0.61 2015-09-09 20:58:00,1.56 2015-09-09 21:03:00,4 2015-09-09 21:08:00,1.06 2015-09-09 21:13:00,0.78 2015-09-09 21:18:00,1.67 2015-09-09 21:23:00,7.06 2015-09-09 21:33:00,1.94 2015-09-09 21:38:00,3.11 2015-09-09 21:43:00,2.94 2015-09-09 21:48:00,0.78 2015-09-09 22:03:00,0.61 2015-09-09 22:08:00,1 2015-09-09 22:13:00,0.78 2015-09-09 22:23:00,3.83 2015-09-09 22:28:00,1.28 2015-09-09 22:33:00,0.67 2015-09-09 22:38:00,1.06 2015-09-09 22:41:00,8.28 2015-09-09 22:46:00,2.83 2015-09-10 00:08:00,0.39 2015-09-10 00:23:00,3.61 2015-09-10 00:38:00,1.39 2015-09-10 00:53:00,0.5 2015-09-10 00:58:00,1.67 2015-09-10 01:03:00,1.06 2015-09-10 01:08:00,0.61 2015-09-10 01:13:00,2.17 2015-09-10 01:38:00,1.06 2015-09-10 01:58:00,2.17 2015-09-10 02:08:00,2.72 2015-09-10 02:18:00,0.39 2015-09-10 02:23:00,0.67 2015-09-10 02:28:00,0.89 2015-09-10 05:28:00,11.33 2015-09-10 05:33:00,6.72 2015-09-10 05:38:00,5.67 2015-09-10 05:45:00,6.44 2015-09-10 08:00:00,8.67 2015-09-10 08:13:00,9.06 2015-09-10 08:18:00,5.28 2015-09-10 08:23:00,12.28 2015-09-10 08:28:00,9.06 2015-09-10 08:33:00,8.89 2015-09-10 08:43:00,3.89 2015-09-10 08:48:00,2.94 2015-09-10 08:53:00,6.33 2015-09-10 08:58:00,6.56 2015-09-10 09:03:00,4.78 2015-09-10 09:08:00,3.61 2015-09-10 09:13:00,7.22 2015-09-10 09:18:00,10.72 2015-09-10 09:28:00,4.11 2015-09-10 09:33:00,6.06 2015-09-10 09:38:00,7.5 2015-09-10 09:43:00,1.94 2015-09-10 09:48:00,3.72 2015-09-10 09:52:00,6.06 2015-09-10 09:57:00,2.28 2015-09-10 10:02:00,1.67 2015-09-10 10:07:00,4 2015-09-10 10:17:00,10.56 2015-09-10 10:22:00,4.78 2015-09-10 10:27:00,4.28 2015-09-10 10:37:00,1.67 2015-09-10 10:42:00,4.39 2015-09-10 10:47:00,7.44 2015-09-10 10:52:00,1.39 2015-09-10 10:57:00,2.33 2015-09-10 11:02:00,7.06 2015-09-10 11:07:00,4.22 2015-09-10 11:12:00,1.56 2015-09-10 11:22:00,4 2015-09-10 11:32:00,1.44 2015-09-10 11:42:00,1.78 2015-09-10 11:47:00,6.56 2015-09-10 11:57:00,2.28 2015-09-10 12:02:00,5.78 2015-09-10 12:12:00,1.17 2015-09-10 12:17:00,3.22 2015-09-10 12:22:00,1.28 2015-09-10 12:57:00,2.44 2015-09-10 13:02:00,1.94 2015-09-10 13:07:00,6.44 2015-09-10 13:12:00,3.89 2015-09-10 13:17:00,2.06 2015-09-10 13:22:00,2.28 2015-09-10 13:27:00,6.44 2015-09-10 13:42:00,0.61 2015-09-10 13:47:00,2.17 2015-09-10 13:57:00,4.67 2015-09-10 14:02:00,7.61 2015-09-10 14:12:00,7.06 2015-09-10 14:37:00,1.94 2015-09-10 14:42:00,4.39 2015-09-10 14:47:00,5.06 2015-09-10 14:57:00,4.61 2015-09-10 15:02:00,1.78 2015-09-10 15:07:00,6.33 2015-09-10 15:12:00,4.39 2015-09-10 15:17:00,3.72 2015-09-10 15:22:00,5.83 2015-09-10 15:27:00,4.39 2015-09-10 15:32:00,3.5 2015-09-10 15:37:00,5.56 2015-09-10 15:42:00,2.28 2015-09-10 15:47:00,6.17 2015-09-10 15:52:00,3.72 2015-09-10 15:57:00,1.67 2015-09-10 16:02:00,5.06 2015-09-10 16:12:00,8.61 2015-09-10 16:17:00,8.11 2015-09-10 16:27:00,6.17 2015-09-10 16:32:00,5.17 2015-09-10 16:37:00,5.67 2015-09-10 16:42:00,8 2015-09-10 16:47:00,4.28 2015-09-10 16:57:00,4.5 2015-09-10 17:02:00,6.94 2015-09-10 17:17:00,5.44 2015-09-10 17:22:00,6.33 2015-09-10 17:27:00,7.33 2015-09-10 17:37:00,4.28 2015-09-10 17:42:00,5.83 2015-09-10 17:47:00,5.28 2015-09-10 17:52:00,9.28 2015-09-10 18:02:00,4.39 2015-09-10 18:07:00,6.06 2015-09-10 18:12:00,9.56 2015-09-10 18:17:00,5.67 2015-09-10 18:22:00,3.83 2015-09-10 18:27:00,2.83 2015-09-10 18:32:00,5.44 2015-09-10 18:42:00,8.61 2015-09-10 18:47:00,1.06 2015-09-10 18:52:00,5.28 2015-09-10 19:02:00,2.33 2015-09-10 19:07:00,2.33 2015-09-10 19:17:00,2.17 2015-09-10 19:27:00,5.06 2015-09-10 19:37:00,0.39 2015-09-10 19:47:00,1.83 2015-09-10 19:52:00,3.06 2015-09-10 20:02:00,5.06 2015-09-10 20:12:00,2.56 2015-09-10 20:28:00,3.11 2015-09-10 20:32:00,1.83 2015-09-10 20:43:00,1.83 2015-09-10 20:47:00,1.83 2015-09-10 20:57:00,3.11 2015-09-10 21:07:00,1.78 2015-09-10 21:12:00,2.33 2015-09-10 21:17:00,1.44 2015-09-10 21:32:00,3.44 2015-09-10 21:37:00,1.94 2015-09-10 21:42:00,0.22 2015-09-10 21:47:00,2.06 2015-09-10 22:12:00,3.5 2015-09-10 22:27:00,0.61 2015-09-10 22:32:00,1.44 2015-09-10 22:37:00,1.56 2015-09-10 22:47:00,0.28 2015-09-10 22:57:00,0.78 2015-09-10 23:02:00,0.89 2015-09-10 23:07:00,4 2015-09-10 23:37:00,2.33 2015-09-10 23:42:00,2.28 2015-09-10 23:57:00,1.44 2015-09-11 00:02:00,1.83 2015-09-11 00:22:00,1 2015-09-11 01:07:00,0.28 2015-09-11 01:17:00,0.78 2015-09-11 01:32:00,1.06 2015-09-11 01:42:00,0.39 2015-09-11 01:57:00,1.78 2015-09-11 02:12:00,0.67 2015-09-11 02:22:00,0.89 2015-09-11 02:32:00,1.67 2015-09-11 02:57:00,1.17 2015-09-11 03:12:00,0.5 2015-09-11 03:27:00,1.56 2015-09-11 03:32:00,0.78 2015-09-11 03:47:00,3.33 2015-09-11 04:07:00,0.61 2015-09-11 04:12:00,0.22 2015-09-11 04:17:00,3.5 2015-09-11 04:27:00,0.67 2015-09-11 04:47:00,2.72 2015-09-11 04:52:00,2.94 2015-09-11 05:17:00,3.61 2015-09-11 05:22:00,4.11 2015-09-11 05:32:00,2.67 2015-09-11 05:37:00,4.5 2015-09-11 05:42:00,6.44 2015-09-11 05:47:00,8.39 2015-09-11 05:52:00,7.06 2015-09-11 05:57:00,4.5 2015-09-11 06:02:00,8.39 2015-09-11 06:07:00,6.44 2015-09-11 06:12:00,11.5 2015-09-11 06:17:00,9.06 2015-09-11 06:22:00,5.44 2015-09-11 06:27:00,9.94 2015-09-11 06:32:00,12.5 2015-09-11 06:37:00,14.17 2015-09-11 06:42:00,12.11 2015-09-11 06:47:00,6.94 2015-09-11 06:52:00,14.33 2015-09-11 06:57:00,8.11 2015-09-11 07:02:00,13 2015-09-11 07:07:00,10.94 2015-09-11 07:12:00,11.83 2015-09-11 07:17:00,6.33 2015-09-11 07:22:00,10.44 2015-09-11 07:27:00,13.11 2015-09-11 07:32:00,12.78 2015-09-11 07:37:00,8.39 2015-09-11 07:42:00,11.33 2015-09-11 07:47:00,9.44 2015-09-11 07:57:00,7.44 2015-09-11 08:02:00,4.39 2015-09-11 08:07:00,9.06 2015-09-11 08:12:00,5.56 2015-09-11 08:17:00,4.39 2015-09-11 08:22:00,6.67 2015-09-11 08:27:00,9.56 2015-09-11 08:32:00,9.17 2015-09-11 08:37:00,5.28 2015-09-11 08:47:00,5.28 2015-09-11 08:52:00,3.5 2015-09-11 08:57:00,4.22 2015-09-11 09:02:00,5.17 2015-09-11 09:12:00,4.78 2015-09-11 09:17:00,5.28 2015-09-11 09:22:00,8.22 2015-09-11 09:27:00,0.89 2015-09-11 09:32:00,5.39 2015-09-11 09:37:00,0.28 2015-09-11 09:42:00,2.67 2015-09-11 10:02:00,2.33 2015-09-11 10:07:00,4.28 2015-09-11 10:17:00,7.11 2015-09-11 10:34:00,3.22 2015-09-11 10:44:00,3.72 2015-09-11 10:49:00,8 2015-09-11 10:54:00,1.39 2015-09-11 10:59:00,5.83 2015-09-11 11:04:00,3.61 2015-09-11 11:09:00,8.5 2015-09-11 11:14:00,6.28 2015-09-11 11:24:00,5.28 2015-09-11 11:29:00,1.67 2015-09-11 11:34:00,6.67 2015-09-11 11:39:00,2.06 2015-09-11 11:44:00,4.39 2015-09-11 11:49:00,3.89 2015-09-11 11:54:00,3.5 2015-09-11 11:59:00,5.28 2015-09-11 12:04:00,6.67 2015-09-11 12:09:00,3.83 2015-09-11 12:14:00,6.33 2015-09-11 12:19:00,5 2015-09-11 12:24:00,2.67 2015-09-11 12:29:00,1.78 2015-09-11 12:34:00,5.94 2015-09-11 12:44:00,3.89 2015-09-11 12:49:00,7.5 2015-09-11 12:54:00,1.94 2015-09-11 12:59:00,4.39 2015-09-11 13:04:00,4.28 2015-09-11 13:09:00,8.11 2015-09-11 13:19:00,7.44 2015-09-11 13:24:00,5.56 2015-09-11 13:29:00,3.89 2015-09-11 13:34:00,4.89 2015-09-11 13:39:00,5.83 2015-09-11 13:44:00,9.94 2015-09-11 13:49:00,9 2015-09-11 13:54:00,4.61 2015-09-11 13:59:00,5.78 2015-09-11 14:04:00,3.33 2015-09-11 14:09:00,2.56 2015-09-11 14:14:00,6.06 2015-09-11 14:19:00,4.39 2015-09-11 14:24:00,5.56 2015-09-11 14:29:00,1.94 2015-09-11 14:34:00,10.33 2015-09-11 14:39:00,4.11 2015-09-11 14:44:00,5.56 2015-09-11 14:49:00,10.17 2015-09-11 14:54:00,10.83 2015-09-11 14:59:00,6.72 2015-09-11 15:04:00,3.22 2015-09-11 15:19:00,10.06 2015-09-11 15:24:00,8.28 2015-09-11 15:29:00,7.22 2015-09-11 15:34:00,6.28 2015-09-11 15:39:00,4.61 2015-09-11 15:44:00,7.61 2015-09-11 15:49:00,3.5 2015-09-11 15:54:00,8.89 2015-09-11 15:59:00,2.67 2015-09-11 16:04:00,1.56 2015-09-11 16:09:00,5.94 2015-09-11 16:14:00,4.89 2015-09-11 16:19:00,7.11 2015-09-11 16:24:00,6.33 2015-09-11 16:29:00,8.28 2015-09-11 16:34:00,9.28 2015-09-11 16:39:00,6.83 2015-09-11 16:44:00,1.67 2015-09-11 16:49:00,4.67 2015-09-11 16:54:00,4.78 2015-09-11 16:59:00,10.33 2015-09-11 17:04:00,4.67 2015-09-11 17:09:00,3.72 2015-09-11 17:14:00,9.78 2015-09-11 17:19:00,7.61 2015-09-11 17:24:00,6.56 2015-09-11 17:29:00,5.56 2015-09-11 17:34:00,4.78 2015-09-11 17:39:00,7.11 2015-09-11 17:44:00,6.83 2015-09-11 17:49:00,3.06 2015-09-11 17:54:00,5.44 2015-09-11 17:59:00,7.5 2015-09-11 18:04:00,5.83 2015-09-11 18:11:00,5.06 2015-09-11 18:16:00,3.5 2015-09-11 18:21:00,6.33 2015-09-11 18:26:00,3.44 2015-09-11 18:31:00,2.83 2015-09-11 18:36:00,4.5 2015-09-11 18:41:00,1.78 2015-09-11 18:46:00,2.83 2015-09-11 18:51:00,3.72 2015-09-11 18:56:00,3.44 2015-09-11 19:01:00,1.28 2015-09-11 19:06:00,1.67 2015-09-11 19:11:00,3.22 2015-09-11 19:21:00,4.39 2015-09-11 19:31:00,1.94 2015-09-11 19:41:00,3.11 2015-09-11 19:46:00,6.06 2015-09-11 19:51:00,8.39 2015-09-11 20:11:00,1.39 2015-09-11 20:26:00,5.17 2015-09-11 20:31:00,2.44 2015-09-11 20:36:00,7.83 2015-09-11 20:41:00,2.33 2015-09-11 20:46:00,1.39 2015-09-11 20:51:00,2.28 2015-09-11 20:56:00,2.44 2015-09-11 21:01:00,1.39 2015-09-11 21:06:00,0.78 2015-09-11 21:21:00,3.06 2015-09-11 21:26:00,0.78 2015-09-11 21:36:00,1.39 2015-09-11 21:46:00,2.28 2015-09-11 21:51:00,5.06 2015-09-11 22:06:00,2.72 2015-09-11 22:11:00,4.67 2015-09-11 22:21:00,2.06 2015-09-11 22:41:00,3.06 2015-09-11 22:46:00,5.06 2015-09-11 22:56:00,0.78 2015-09-11 23:01:00,2.28 2015-09-11 23:11:00,1 2015-09-11 23:16:00,0.78 2015-09-11 23:36:00,1.06 2015-09-11 23:41:00,0 2015-09-12 00:11:00,0.78 2015-09-12 00:26:00,3.61 2015-09-12 00:31:00,0.67 2015-09-12 00:41:00,1.67 2015-09-12 00:46:00,0 2015-09-12 00:51:00,0 2015-09-12 01:01:00,0.89 2015-09-12 01:26:00,0.89 2015-09-12 01:31:00,0.61 2015-09-12 02:21:00,1.67 2015-09-12 02:56:00,2.44 2015-09-12 03:46:00,3.33 2015-09-12 03:56:00,0.5 2015-09-12 04:06:00,0 2015-09-12 04:36:00,0 2015-09-12 04:41:00,0.22 2015-09-12 04:51:00,1.67 2015-09-12 05:06:00,0.39 2015-09-12 05:21:00,1.39 2015-09-12 05:41:00,1.39 2015-09-12 05:46:00,1.94 2015-09-12 05:56:00,4.11 2015-09-12 06:06:00,1.56 2015-09-12 06:16:00,2.06 2015-09-12 06:26:00,3.61 2015-09-12 06:51:00,0.28 2015-09-12 06:56:00,2.83 2015-09-12 07:01:00,3.61 2015-09-12 07:16:00,5.06 2015-09-12 07:21:00,2.28 2015-09-12 07:31:00,3.06 2015-09-12 07:36:00,2.44 2015-09-12 07:46:00,2.17 2015-09-12 07:51:00,1.67 2015-09-12 07:56:00,5.44 2015-09-12 08:06:00,3.44 2015-09-12 08:11:00,2.72 2015-09-12 08:16:00,3.11 2015-09-12 08:21:00,2.06 2015-09-12 08:26:00,2.06 2015-09-12 08:31:00,2.17 2015-09-12 08:36:00,0.89 2015-09-12 08:46:00,8.61 2015-09-12 08:56:00,2.44 2015-09-12 09:01:00,2.72 2015-09-12 09:06:00,7.11 2015-09-12 09:11:00,2.72 2015-09-12 09:16:00,1.39 2015-09-12 09:21:00,2.67 2015-09-12 09:26:00,1.28 2015-09-12 09:36:00,5.94 2015-09-12 09:41:00,1.94 2015-09-12 09:51:00,2.33 2015-09-12 10:01:00,2.56 2015-09-12 10:06:00,3.22 2015-09-12 10:11:00,3.89 2015-09-12 10:16:00,1.94 2015-09-12 10:21:00,5.28 2015-09-12 10:31:00,3.83 2015-09-12 10:36:00,3.61 2015-09-12 10:41:00,8.61 2015-09-12 10:46:00,12.5 2015-09-12 10:51:00,5.17 2015-09-12 10:56:00,3.33 2015-09-12 11:01:00,4.78 2015-09-12 11:06:00,2.33 2015-09-12 11:11:00,5.39 2015-09-12 11:16:00,6.72 2015-09-12 11:21:00,4.22 2015-09-12 11:26:00,3.11 2015-09-12 11:31:00,8.89 2015-09-12 11:36:00,7.22 2015-09-12 11:46:00,8.78 2015-09-12 11:51:00,11.89 2015-09-12 11:56:00,6.06 2015-09-12 12:01:00,5.78 2015-09-12 12:16:00,3.83 2015-09-12 12:21:00,7.72 2015-09-12 12:26:00,4.78 2015-09-12 12:31:00,6.17 2015-09-12 12:36:00,6.17 2015-09-12 12:41:00,11.11 2015-09-12 12:46:00,5.78 2015-09-12 12:51:00,3.72 2015-09-12 12:56:00,4.67 2015-09-12 13:01:00,5 2015-09-12 13:11:00,2.33 2015-09-12 13:16:00,6.28 2015-09-12 13:21:00,6.56 2015-09-12 13:31:00,8.28 2015-09-12 13:41:00,6.83 2015-09-12 13:46:00,4.5 2015-09-12 13:56:00,5.94 2015-09-12 14:01:00,7.22 2015-09-12 14:06:00,4 2015-09-12 14:11:00,5.67 2015-09-12 14:16:00,3.89 2015-09-12 14:21:00,5 2015-09-12 14:26:00,5.17 2015-09-12 14:31:00,4.22 2015-09-12 14:36:00,8 2015-09-12 14:41:00,7.06 2015-09-12 14:46:00,4.67 2015-09-12 14:51:00,6.06 2015-09-12 14:56:00,7.5 2015-09-12 15:01:00,2.17 2015-09-12 15:06:00,6.28 2015-09-12 15:11:00,0.67 2015-09-12 15:21:00,5.39 2015-09-12 15:26:00,5.44 2015-09-12 15:36:00,4.89 2015-09-12 15:41:00,6.83 2015-09-12 15:46:00,8.28 2015-09-12 15:51:00,1.83 2015-09-12 15:56:00,2.33 2015-09-12 16:01:00,6.17 2015-09-12 16:06:00,2.94 2015-09-12 16:11:00,2.72 2015-09-12 16:16:00,3.22 2015-09-12 16:21:00,4.28 2015-09-12 16:26:00,4.22 2015-09-12 16:36:00,3.11 2015-09-12 16:41:00,2.28 2015-09-12 16:46:00,2.06 2015-09-12 16:56:00,2.56 2015-09-12 17:01:00,2.94 2015-09-12 17:06:00,7.89 2015-09-12 17:11:00,1.83 2015-09-12 17:16:00,2.72 2015-09-12 17:21:00,1.78 2015-09-12 17:26:00,2.44 2015-09-12 17:31:00,3.61 2015-09-12 17:36:00,5.67 2015-09-12 17:41:00,3.22 2015-09-12 17:46:00,1.94 2015-09-12 17:51:00,3.72 2015-09-12 17:56:00,3.11 2015-09-12 18:01:00,2.83 2015-09-12 18:06:00,0 2015-09-12 18:11:00,3.61 2015-09-12 18:16:00,1.39 2015-09-12 18:21:00,3.33 2015-09-12 18:26:00,2.72 2015-09-12 18:36:00,3.83 2015-09-12 18:41:00,2.17 2015-09-12 18:46:00,1.39 2015-09-12 18:51:00,6.94 2015-09-12 19:01:00,2.67 2015-09-12 19:06:00,1.56 2015-09-12 19:21:00,7.22 2015-09-12 19:31:00,5.39 2015-09-12 19:36:00,5.39 2015-09-12 19:41:00,5.44 2015-09-12 19:51:00,3.44 2015-09-12 19:56:00,3.5 2015-09-12 20:01:00,5.83 2015-09-12 20:11:00,3.72 2015-09-12 20:21:00,0.67 2015-09-12 20:31:00,4.89 2015-09-12 20:36:00,2.17 2015-09-12 20:46:00,1.94 2015-09-12 21:01:00,7.22 2015-09-12 21:06:00,3.5 2015-09-12 21:11:00,2.94 2015-09-12 21:16:00,6.17 2015-09-12 21:21:00,3.5 2015-09-12 21:26:00,0.28 2015-09-12 21:31:00,1.39 2015-09-12 21:46:00,0.61 2015-09-12 21:56:00,4.22 2015-09-12 22:11:00,0.61 2015-09-12 22:16:00,5.28 2015-09-12 22:21:00,2.33 2015-09-12 22:26:00,1.94 2015-09-12 22:36:00,0.61 2015-09-12 22:41:00,2.33 2015-09-12 22:46:00,2.72 2015-09-12 22:56:00,2.28 2015-09-12 23:01:00,3.11 2015-09-12 23:11:00,0.89 2015-09-12 23:26:00,1.94 2015-09-12 23:31:00,0.67 2015-09-12 23:41:00,2.44 2015-09-12 23:51:00,1.56 2015-09-13 00:16:00,0.67 2015-09-13 00:21:00,1.06 2015-09-13 00:26:00,2.06 2015-09-13 02:21:00,1.83 2015-09-13 02:26:00,1.17 2015-09-13 02:36:00,0.78 2015-09-13 02:56:00,1.06 2015-09-13 04:41:00,0.89 2015-09-13 04:46:00,0.61 2015-09-13 04:51:00,0.89 2015-09-13 05:21:00,0.39 2015-09-13 06:11:00,1.17 2015-09-13 06:21:00,1.17 2015-09-13 06:41:00,1.28 2015-09-13 06:46:00,1.78 2015-09-13 06:51:00,0.89 2015-09-13 07:11:00,1.83 2015-09-13 07:16:00,1.28 2015-09-13 07:21:00,4.28 2015-09-13 07:36:00,0.39 2015-09-13 07:46:00,3.33 2015-09-13 07:56:00,0 2015-09-13 08:01:00,2.28 2015-09-13 08:16:00,0.22 2015-09-13 08:31:00,2.33 2015-09-13 08:41:00,1.56 2015-09-13 08:56:00,3.61 2015-09-13 09:06:00,3.22 2015-09-13 09:11:00,1.28 2015-09-13 09:16:00,2.67 2015-09-13 09:31:00,2.94 2015-09-13 09:36:00,4.22 2015-09-13 09:46:00,4 2015-09-13 09:51:00,1.78 2015-09-13 10:01:00,0.5 2015-09-13 10:06:00,3.5 2015-09-13 10:11:00,3.33 2015-09-13 10:16:00,8.22 2015-09-13 10:21:00,4.39 2015-09-13 10:26:00,2.44 2015-09-13 10:31:00,4 2015-09-13 10:36:00,7.11 2015-09-13 10:41:00,5.39 2015-09-13 10:46:00,2.06 2015-09-13 10:51:00,7.72 2015-09-13 10:56:00,1.78 2015-09-13 11:06:00,6.94 2015-09-13 11:11:00,4.67 2015-09-13 11:16:00,6.56 2015-09-13 11:26:00,7.89 2015-09-13 11:31:00,9.28 2015-09-13 11:36:00,5 2015-09-13 11:41:00,3.89 2015-09-13 11:46:00,1.78 2015-09-13 11:51:00,4.67 2015-09-13 11:56:00,4.39 2015-09-13 12:01:00,6.83 2015-09-13 12:06:00,5.94 2015-09-13 12:11:00,4.61 2015-09-13 12:16:00,8.11 2015-09-13 12:21:00,4 2015-09-13 12:26:00,10.72 2015-09-13 12:31:00,2.44 2015-09-13 12:41:00,3.72 2015-09-13 12:46:00,8.22 2015-09-13 12:53:00,2.67 2015-09-13 12:58:00,7.06 2015-09-13 13:03:00,13.28 2015-09-13 13:08:00,5 2015-09-13 13:13:00,8.39 2015-09-13 13:18:00,8.89 2015-09-13 13:23:00,7.33 2015-09-13 13:33:00,12.28 2015-09-13 13:38:00,11.33 2015-09-13 13:43:00,6.28 2015-09-13 13:48:00,6.17 2015-09-13 13:53:00,9.06 2015-09-13 13:58:00,4.22 2015-09-13 14:03:00,6.83 2015-09-13 14:13:00,7.72 2015-09-13 14:18:00,7.11 2015-09-13 14:28:00,3.5 2015-09-13 14:38:00,4.28 2015-09-13 14:43:00,7.44 2015-09-13 14:48:00,5.94 2015-09-13 14:53:00,5.17 2015-09-13 15:03:00,10.83 2015-09-13 15:13:00,2.56 2015-09-13 15:18:00,8.11 2015-09-13 15:23:00,10.67 2015-09-13 15:28:00,6.56 2015-09-13 15:33:00,8.22 2015-09-13 15:43:00,9.83 2015-09-13 15:48:00,5.67 2015-09-13 15:53:00,6.83 2015-09-13 15:58:00,7.33 2015-09-13 16:03:00,7.06 2015-09-13 16:08:00,7.11 2015-09-13 16:13:00,3.83 2015-09-13 16:18:00,5.83 2015-09-13 16:23:00,11.06 2015-09-13 16:28:00,11.83 2015-09-13 16:33:00,6.06 2015-09-13 16:38:00,6.56 2015-09-13 16:43:00,8.61 2015-09-13 16:48:00,8.67 2015-09-13 16:58:00,8.78 2015-09-13 17:03:00,9.28 2015-09-13 17:08:00,9 2015-09-13 17:13:00,9.44 2015-09-13 17:18:00,5.17 2015-09-13 17:23:00,4.28 2015-09-13 17:28:00,2.94 2015-09-13 17:33:00,10.17 2015-09-13 17:38:00,10.67 2015-09-13 17:43:00,6.72 2015-09-13 17:48:00,10.06 2015-09-13 17:53:00,5.28 2015-09-13 17:58:00,5.56 2015-09-13 18:03:00,5.17 2015-09-13 18:08:00,10.67 2015-09-13 18:13:00,5.06 2015-09-13 18:18:00,3.11 2015-09-13 18:23:00,10.72 2015-09-13 18:28:00,7.22 2015-09-13 18:33:00,5 2015-09-13 18:38:00,10.67 2015-09-13 18:43:00,1.67 2015-09-13 18:48:00,5.56 2015-09-13 18:53:00,10.28 2015-09-13 18:58:00,11.06 2015-09-13 19:03:00,5.44 2015-09-13 19:13:00,4.89 2015-09-13 19:18:00,10.28 2015-09-13 19:23:00,6.67 2015-09-13 19:33:00,0.67 2015-09-13 19:38:00,5.17 2015-09-13 19:43:00,4 2015-09-13 19:48:00,2.56 2015-09-13 19:53:00,2.67 2015-09-13 19:58:00,4.11 2015-09-13 20:03:00,4.11 2015-09-13 20:08:00,7.61 2015-09-13 20:13:00,3.11 2015-09-13 20:18:00,9 2015-09-13 20:28:00,2.44 2015-09-13 20:33:00,2.67 2015-09-13 20:38:00,2.94 2015-09-13 20:48:00,1.39 2015-09-13 20:53:00,2.67 2015-09-13 20:58:00,1.17 2015-09-13 21:03:00,3.22 2015-09-13 21:08:00,1.44 2015-09-13 21:13:00,2.06 2015-09-13 21:18:00,1.44 2015-09-13 21:43:00,3.06 2015-09-13 22:03:00,1.44 2015-09-13 22:13:00,3.44 2015-09-13 22:28:00,1.67 2015-09-13 22:33:00,1.44 2015-09-13 22:38:00,1.67 2015-09-13 22:43:00,0.22 2015-09-13 22:48:00,0.28 2015-09-13 22:58:00,2.44 2015-09-13 23:03:00,0.67 2015-09-13 23:13:00,0.78 2015-09-13 23:18:00,1 2015-09-13 23:28:00,0.39 2015-09-13 23:33:00,0.67 2015-09-13 23:38:00,0.78 2015-09-13 23:48:00,1.06 2015-09-13 23:59:00,0.67 2015-09-14 00:03:00,2.94 2015-09-14 00:18:00,0.78 2015-09-14 00:33:00,0.39 2015-09-14 01:08:00,2.28 2015-09-14 01:33:00,3.5 2015-09-14 01:53:00,0.89 2015-09-14 01:58:00,0.28 2015-09-14 02:08:00,0 2015-09-14 02:23:00,0.67 2015-09-14 02:28:00,1.28 2015-09-14 02:33:00,1.06 2015-09-14 02:48:00,0.5 2015-09-14 02:53:00,0.78 2015-09-14 03:18:00,0.78 2015-09-14 03:33:00,0.78 2015-09-14 03:38:00,0 2015-09-14 03:43:00,1 2015-09-14 03:48:00,0 2015-09-14 04:03:00,0.61 2015-09-14 04:08:00,0.22 2015-09-14 04:23:00,0.39 2015-09-14 04:28:00,1.06 2015-09-14 04:43:00,1.44 2015-09-14 04:48:00,0.78 2015-09-14 04:53:00,4.5 2015-09-14 04:58:00,2.33 2015-09-14 05:03:00,1.67 2015-09-14 05:08:00,3.33 2015-09-14 05:13:00,5.44 2015-09-14 05:18:00,2.94 2015-09-14 05:23:00,10.33 2015-09-14 05:28:00,6.56 2015-09-14 05:33:00,5.28 2015-09-14 05:38:00,6.17 2015-09-14 05:43:00,8.39 2015-09-14 05:48:00,3.72 2015-09-14 05:53:00,5.83 2015-09-14 05:58:00,8.22 2015-09-14 06:03:00,9 2015-09-14 06:08:00,16.72 2015-09-14 06:13:00,10.33 2015-09-14 06:18:00,8.5 2015-09-14 06:23:00,13.56 2015-09-14 06:28:00,18.33 2015-09-14 06:33:00,9.83 2015-09-14 06:38:00,9.06 2015-09-14 06:43:00,17.11 2015-09-14 08:23:00,9.83 2015-09-14 08:28:00,8 2015-09-14 08:33:00,8.78 2015-09-14 08:38:00,9.28 2015-09-14 08:43:00,4.28 2015-09-14 08:48:00,6.44 2015-09-14 08:53:00,3.83 2015-09-14 08:58:00,7.5 2015-09-14 09:03:00,1.06 2015-09-14 09:08:00,1.17 2015-09-14 09:13:00,6.72 2015-09-14 09:23:00,3.33 2015-09-14 09:28:00,2.44 2015-09-14 09:33:00,5.83 2015-09-14 09:38:00,5.28 2015-09-14 09:43:00,4.61 2015-09-14 09:48:00,3.06 2015-09-14 09:53:00,1.17 2015-09-14 09:58:00,2.28 2015-09-14 10:03:00,4.11 2015-09-14 10:08:00,2.72 2015-09-14 10:13:00,3.5 2015-09-14 10:18:00,2.17 2015-09-14 10:23:00,6.83 2015-09-14 10:28:00,8.61 2015-09-14 10:33:00,1.83 2015-09-14 10:38:00,4.5 2015-09-14 10:43:00,5.06 2015-09-14 10:48:00,4.89 2015-09-14 10:53:00,1.78 2015-09-14 10:58:00,2.44 2015-09-14 11:03:00,2.44 2015-09-14 11:23:00,4 2015-09-14 11:33:00,4.22 2015-09-14 11:38:00,3.33 2015-09-14 11:48:00,4.11 2015-09-14 11:53:00,5 2015-09-14 11:58:00,1.67 2015-09-14 12:03:00,1 2015-09-14 12:08:00,3.72 2015-09-14 12:13:00,4.61 2015-09-14 12:18:00,2.06 2015-09-14 12:23:00,5.39 2015-09-14 12:28:00,5 2015-09-14 12:33:00,4.5 2015-09-14 12:38:00,2.17 2015-09-14 12:43:00,1.06 2015-09-14 12:48:00,7.44 2015-09-14 13:03:00,1.83 2015-09-14 13:08:00,3.72 2015-09-14 13:13:00,2.94 2015-09-14 13:15:00,3.61 2015-09-14 13:20:00,2.17 2015-09-14 13:25:00,7.11 2015-09-14 13:35:00,3.06 2015-09-14 13:40:00,3.22 2015-09-14 13:45:00,6.17 2015-09-14 13:55:00,4.5 2015-09-14 14:00:00,4.28 2015-09-14 14:05:00,4.39 2015-09-14 14:10:00,7.33 2015-09-14 14:15:00,5 2015-09-14 14:20:00,2.28 2015-09-14 14:25:00,4.22 2015-09-14 14:30:00,1.28 2015-09-14 14:35:00,6.56 2015-09-14 14:40:00,5 2015-09-14 14:45:00,5.17 2015-09-14 14:50:00,5.06 2015-09-14 14:55:00,4.78 2015-09-14 15:00:00,1.83 2015-09-14 15:05:00,4.39 2015-09-14 15:10:00,5.94 2015-09-14 15:15:00,6.44 2015-09-14 15:20:00,1.28 2015-09-14 15:25:00,2.06 2015-09-14 15:30:00,1.94 2015-09-14 15:35:00,5.56 2015-09-14 15:40:00,4.78 2015-09-14 15:45:00,3.33 2015-09-14 15:50:00,3.22 2015-09-14 15:55:00,3.11 2015-09-14 16:00:00,3.72 2015-09-14 16:05:00,3.11 2015-09-14 16:10:00,3.22 2015-09-14 16:15:00,3.11 2015-09-14 16:20:00,2.17 2015-09-14 16:25:00,6.06 2015-09-14 16:30:00,1.83 2015-09-14 16:35:00,2.72 2015-09-14 16:40:00,3.72 2015-09-14 16:45:00,2.33 2015-09-14 16:50:00,6.72 2015-09-14 16:55:00,5.06 2015-09-14 17:00:00,4.28 2015-09-14 17:10:00,4.11 2015-09-14 17:15:00,6.44 2015-09-14 17:20:00,5.67 2015-09-14 17:25:00,7.5 2015-09-14 17:30:00,5.17 2015-09-14 17:35:00,3.22 2015-09-14 17:40:00,2.94 2015-09-14 17:45:00,3.11 2015-09-14 17:50:00,4.67 2015-09-14 17:55:00,1.56 2015-09-14 18:00:00,3.11 2015-09-14 18:05:00,1.17 2015-09-14 18:10:00,3.83 2015-09-14 18:15:00,5.78 2015-09-14 18:20:00,3.5 2015-09-14 18:25:00,2.06 2015-09-14 18:30:00,1.56 2015-09-14 18:35:00,2.94 2015-09-14 18:45:00,2.94 2015-09-14 18:50:00,5.44 2015-09-14 18:55:00,3.61 2015-09-14 19:01:00,1.78 2015-09-14 19:05:00,1.39 2015-09-14 19:10:00,2.33 2015-09-14 19:15:00,1.83 2015-09-14 19:20:00,2.72 2015-09-14 19:30:00,0.89 2015-09-14 19:35:00,1.39 2015-09-14 19:40:00,2.44 2015-09-14 19:45:00,1.78 2015-09-14 19:50:00,4.67 2015-09-14 19:55:00,3.11 2015-09-14 20:05:00,1.94 2015-09-14 20:10:00,2.44 2015-09-14 20:15:00,1.78 2015-09-14 20:20:00,1.28 2015-09-14 20:25:00,1.39 2015-09-14 20:30:00,1.78 2015-09-14 20:50:00,1.78 2015-09-14 20:55:00,1.56 2015-09-14 20:59:00,2.56 2015-09-14 21:05:00,2.33 2015-09-14 21:10:00,2.33 2015-09-14 21:25:00,4.61 2015-09-14 21:35:00,0.5 2015-09-14 21:45:00,2.17 2015-09-14 21:50:00,0.89 2015-09-14 21:55:00,1.94 2015-09-14 22:01:00,1.17 2015-09-14 22:06:00,1.06 2015-09-14 22:11:00,1 2015-09-14 22:16:00,2.33 2015-09-14 22:21:00,0.67 2015-09-14 22:25:00,2.06 2015-09-14 22:30:00,1.17 2015-09-14 22:40:00,0.61 2015-09-14 23:01:00,1 2015-09-14 23:06:00,0.78 2015-09-14 23:11:00,0.67 2015-09-14 23:15:00,0.39 2015-09-14 23:26:00,0.28 2015-09-14 23:31:00,0.89 2015-09-14 23:36:00,0.61 2015-09-14 23:41:00,0.39 2015-09-14 23:51:00,0.39 2015-09-14 23:56:00,1.67 2015-09-15 00:06:00,1 2015-09-15 00:11:00,0 2015-09-15 00:16:00,0 2015-09-15 00:20:00,1.67 2015-09-15 00:40:00,0.5 2015-09-15 00:56:00,2.17 2015-09-15 01:10:00,0.89 2015-09-15 01:15:00,0.61 2015-09-15 01:25:00,0 2015-09-15 01:35:00,0.39 2015-09-15 01:40:00,0.78 2015-09-15 01:45:00,1 2015-09-15 01:50:00,0.89 2015-09-15 01:55:00,0.28 2015-09-15 02:06:00,0 2015-09-15 02:11:00,0.78 2015-09-15 02:31:00,0 2015-09-15 02:41:00,1 2015-09-15 02:56:00,2.44 2015-09-15 03:01:00,0.89 2015-09-15 03:10:00,0.67 2015-09-15 03:20:00,0.28 2015-09-15 03:25:00,0.28 2015-09-15 03:30:00,0.61 2015-09-15 03:40:00,0.78 2015-09-15 03:45:00,1.06 2015-09-15 03:50:00,1.17 2015-09-15 04:01:00,1.39 2015-09-15 04:06:00,1.28 2015-09-15 04:10:00,1 2015-09-15 04:16:00,1 2015-09-15 04:21:00,1.67 2015-09-15 04:26:00,2.28 2015-09-15 04:31:00,0.78 2015-09-15 04:35:00,0.61 2015-09-15 04:46:00,2.06 2015-09-15 04:51:00,2.28 2015-09-15 04:55:00,3.44 2015-09-15 05:01:00,3.11 2015-09-15 05:05:00,2.67 2015-09-15 05:10:00,3.33 2015-09-15 05:15:00,3.61 2015-09-15 05:20:00,3.72 2015-09-15 05:26:00,8.22 2015-09-15 05:31:00,8.28 2015-09-15 05:36:00,5.06 2015-09-15 05:46:00,3.89 2015-09-15 05:51:00,2.56 2015-09-15 05:55:00,7.33 2015-09-15 06:00:00,9.83 2015-09-15 06:05:00,8.78 2015-09-15 06:10:00,11.72 2015-09-15 06:16:00,14.28 2015-09-15 06:20:00,9.94 2015-09-15 06:25:00,13.94 2015-09-15 06:30:00,14.17 2015-09-15 06:35:00,11.11 2015-09-15 06:41:00,17.94 2015-09-15 06:45:00,7.61 2015-09-15 06:50:00,6.67 2015-09-15 06:55:00,22.28 2015-09-15 07:00:00,13.78 2015-09-15 07:06:00,14.17 2015-09-15 07:11:00,15.94 2015-09-15 07:16:00,8.61 2015-09-15 07:21:00,17.39 2015-09-15 07:26:00,13.39 2015-09-15 07:31:00,9.83 2015-09-15 07:36:00,12.28 2015-09-15 07:41:00,14.44 2015-09-15 07:46:00,9.83 2015-09-15 07:51:00,10.17 2015-09-15 07:56:00,9.56 2015-09-15 08:01:00,8.89 2015-09-15 08:06:00,8.67 2015-09-15 08:11:00,4 2015-09-15 08:16:00,8.39 2015-09-15 08:21:00,12.78 2015-09-15 08:26:00,6.33 2015-09-15 08:31:00,3.44 2015-09-15 08:36:00,4.5 2015-09-15 08:41:00,3.89 2015-09-15 08:46:00,5.83 2015-09-15 08:51:00,4.78 2015-09-15 08:56:00,5.78 2015-09-15 09:01:00,5.39 2015-09-15 09:06:00,4.11 2015-09-15 09:11:00,1.94 2015-09-15 09:16:00,5.67 2015-09-15 09:21:00,3.72 2015-09-15 09:26:00,7.89 2015-09-15 09:31:00,5.56 2015-09-15 09:36:00,4.22 2015-09-15 09:41:00,4.11 2015-09-15 09:46:00,13.28 2015-09-15 09:51:00,4.61 2015-09-15 10:01:00,0.22 2015-09-15 10:06:00,7.89 2015-09-15 10:11:00,5 2015-09-15 10:21:00,0.89 2015-09-15 10:31:00,2.17 2015-09-15 10:36:00,3.11 2015-09-15 10:41:00,2.72 2015-09-15 10:46:00,6.44 2015-09-15 10:51:00,3.89 2015-09-15 11:01:00,5.28 2015-09-15 11:06:00,2.17 2015-09-15 11:11:00,7.83 2015-09-15 11:16:00,4.39 2015-09-15 11:21:00,3.72 2015-09-15 11:26:00,1.67 2015-09-15 11:31:00,4.22 2015-09-15 11:36:00,6.28 2015-09-15 11:41:00,1.39 2015-09-15 11:46:00,3.5 2015-09-15 11:51:00,3.89 2015-09-15 11:56:00,4.39 2015-09-15 12:01:00,1.78 2015-09-15 12:06:00,2.83 2015-09-15 12:11:00,1.39 2015-09-15 12:16:00,2.67 2015-09-15 12:21:00,2.44 2015-09-15 12:26:00,6.83 2015-09-15 12:31:00,4.61 2015-09-15 12:36:00,3.72 2015-09-15 12:46:00,1.06 2015-09-15 12:51:00,3.72 2015-09-15 12:56:00,2.28 2015-09-15 13:01:00,1.67 2015-09-15 13:06:00,2.28 2015-09-15 13:11:00,4.67 2015-09-15 13:16:00,3.06 2015-09-15 13:21:00,2.72 2015-09-15 13:26:00,3.72 2015-09-15 13:31:00,6.44 2015-09-15 13:36:00,1.56 2015-09-15 13:46:00,2.28 2015-09-15 13:51:00,1.94 2015-09-15 13:54:00,0.61 2015-09-15 13:59:00,4.61 2015-09-15 14:04:00,8.11 2015-09-15 14:09:00,2.83 2015-09-15 14:14:00,4.89 2015-09-15 14:19:00,5.06 2015-09-15 14:24:00,4 2015-09-15 14:29:00,5.28 2015-09-15 14:34:00,5.06 2015-09-15 14:39:00,2.67 2015-09-15 14:44:00,2.83 2015-09-15 14:49:00,4.5 2015-09-15 14:54:00,2.33 2015-09-15 15:04:00,5.17 2015-09-15 15:09:00,5.78 2015-09-15 15:14:00,4.39 2015-09-15 15:19:00,3.06 2015-09-15 15:24:00,4.67 2015-09-15 15:29:00,5.39 2015-09-15 15:34:00,5.94 2015-09-15 15:39:00,1.78 2015-09-15 15:44:00,7.11 2015-09-15 15:49:00,3.33 2015-09-15 15:54:00,5.44 2015-09-15 15:59:00,4.5 2015-09-15 16:04:00,6.28 2015-09-15 16:09:00,5.17 2015-09-15 16:14:00,8.78 2015-09-15 16:19:00,5.44 2015-09-15 16:24:00,6.44 2015-09-15 16:29:00,9 2015-09-15 16:34:00,4.22 2015-09-15 16:39:00,6.06 2015-09-15 16:44:00,7.06 2015-09-15 16:49:00,4.89 2015-09-15 16:54:00,1.39 2015-09-15 16:59:00,5.39 2015-09-15 17:04:00,1.94 2015-09-15 17:09:00,3.83 2015-09-15 17:14:00,5 2015-09-15 17:19:00,5.78 2015-09-15 17:24:00,10.72 2015-09-15 17:29:00,10.44 2015-09-15 17:34:00,4.28 2015-09-15 17:39:00,5.39 2015-09-15 17:44:00,3.22 2015-09-15 17:49:00,0.61 2015-09-15 17:54:00,5.67 2015-09-15 18:04:00,5.06 2015-09-15 18:09:00,6.28 2015-09-15 18:14:00,5.39 2015-09-15 18:19:00,2.44 2015-09-15 18:24:00,4.67 2015-09-15 18:29:00,3.33 2015-09-15 18:39:00,2.28 2015-09-15 18:44:00,2.06 2015-09-15 18:49:00,3.89 2015-09-15 18:54:00,1.94 2015-09-15 18:59:00,3.33 2015-09-15 19:04:00,4.61 2015-09-15 19:14:00,5.06 2015-09-15 19:24:00,6.94 2015-09-15 19:29:00,3.72 2015-09-15 19:34:00,1.83 2015-09-15 19:44:00,1.67 2015-09-15 19:49:00,3.72 2015-09-15 19:54:00,3.22 2015-09-15 19:59:00,5.83 2015-09-15 20:04:00,1.67 2015-09-15 20:09:00,2.17 2015-09-15 20:14:00,5.28 2015-09-15 20:19:00,4.22 2015-09-15 20:29:00,1.06 2015-09-15 20:34:00,1.17 2015-09-15 20:39:00,0.78 2015-09-15 20:44:00,1.67 2015-09-15 20:49:00,2.28 2015-09-15 20:54:00,0.67 2015-09-15 20:59:00,4.5 2015-09-15 21:04:00,1.28 2015-09-15 21:09:00,0.39 2015-09-15 21:14:00,0.67 2015-09-15 21:19:00,2.33 2015-09-15 21:24:00,0.78 2015-09-15 21:29:00,2.17 2015-09-15 21:34:00,1.94 2015-09-15 21:39:00,1.67 2015-09-15 21:44:00,1.83 2015-09-15 21:59:00,1.67 2015-09-15 22:09:00,2.72 2015-09-15 22:19:00,0.89 2015-09-15 22:24:00,1.56 2015-09-15 22:34:00,0.28 2015-09-15 22:44:00,0.89 2015-09-15 22:59:00,0.67 2015-09-15 23:04:00,1.44 2015-09-15 23:09:00,0 2015-09-15 23:19:00,1.44 2015-09-15 23:24:00,0 2015-09-15 23:29:00,1 2015-09-15 23:34:00,1 2015-09-15 23:39:00,2.44 2015-09-15 23:44:00,0.61 2015-09-15 23:49:00,0.89 2015-09-15 23:54:00,1 2015-09-16 00:09:00,0.89 2015-09-16 00:14:00,1.06 2015-09-16 00:19:00,1.83 2015-09-16 00:29:00,3.44 2015-09-16 00:34:00,0 2015-09-16 00:44:00,0 2015-09-16 00:49:00,0 2015-09-16 00:54:00,1.17 2015-09-16 01:04:00,0.28 2015-09-16 01:09:00,0.22 2015-09-16 01:14:00,0.61 2015-09-16 01:19:00,0.78 2015-09-16 01:24:00,0 2015-09-16 01:29:00,0 2015-09-16 01:34:00,0 2015-09-16 01:39:00,1.78 2015-09-16 02:04:00,1.67 2015-09-16 02:09:00,1.67 2015-09-16 02:24:00,0.89 2015-09-16 02:44:00,0 2015-09-16 02:49:00,0.61 2015-09-16 02:54:00,1 2015-09-16 02:59:00,0.78 2015-09-16 03:04:00,1.28 2015-09-16 03:14:00,1.17 2015-09-16 03:19:00,0.78 2015-09-16 03:29:00,0.89 2015-09-16 03:34:00,0 2015-09-16 03:39:00,1.94 2015-09-16 03:44:00,1.17 2015-09-16 03:49:00,0.28 2015-09-16 03:54:00,1.06 2015-09-16 03:59:00,3.44 2015-09-16 04:09:00,0.22 2015-09-16 04:14:00,1.78 2015-09-16 04:29:00,1.94 2015-09-16 04:34:00,3.33 2015-09-16 04:44:00,0.78 2015-09-16 04:49:00,0.67 2015-09-16 05:09:00,3.89 2015-09-16 05:14:00,6.44 2015-09-16 05:19:00,6.33 2015-09-16 05:24:00,6.56 2015-09-16 05:29:00,13.5 2015-09-16 05:39:00,4 2015-09-16 05:44:00,5.83 2015-09-16 05:49:00,8.78 2015-09-16 05:54:00,9.06 2015-09-16 05:59:00,8.5 2015-09-16 06:04:00,9.17 2015-09-16 06:09:00,11.5 2015-09-16 06:14:00,10.83 2015-09-16 06:19:00,12.22 2015-09-16 06:24:00,17.56 2015-09-16 06:29:00,13.28 2015-09-16 06:34:00,16.11 2015-09-16 06:39:00,11.06 2015-09-16 06:44:00,14.78 2015-09-16 06:49:00,10.44 2015-09-16 06:54:00,11.83 2015-09-16 06:59:00,14.67 2015-09-16 07:04:00,17.17 2015-09-16 07:09:00,14.67 2015-09-16 07:14:00,10.44 2015-09-16 07:19:00,17.56 2015-09-16 07:24:00,11.22 2015-09-16 07:29:00,10.17 2015-09-16 07:34:00,12.22 2015-09-16 07:39:00,8 2015-09-16 07:44:00,18.67 2015-09-16 07:49:00,8.89 2015-09-16 07:54:00,10.28 2015-09-16 07:59:00,15.83 2015-09-16 08:04:00,12.61 2015-09-16 08:09:00,5.28 2015-09-16 08:14:00,13 2015-09-16 08:19:00,8.11 2015-09-16 08:24:00,7.72 2015-09-16 08:29:00,7.61 2015-09-16 08:34:00,5.94 2015-09-16 08:39:00,8.11 2015-09-16 08:44:00,8.22 2015-09-16 08:49:00,4.39 2015-09-16 08:54:00,6.72 2015-09-16 08:59:00,5.56 2015-09-16 09:04:00,6.17 2015-09-16 09:09:00,4 2015-09-16 09:14:00,6.17 2015-09-16 09:19:00,2.72 2015-09-16 09:24:00,8.67 2015-09-16 09:29:00,3.61 2015-09-16 09:34:00,9.28 2015-09-16 09:39:00,5.67 2015-09-16 09:49:00,3.33 2015-09-16 09:54:00,6.44 2015-09-16 09:59:00,3.72 2015-09-16 10:04:00,1.67 2015-09-16 10:09:00,3.33 2015-09-16 10:14:00,2.17 2015-09-16 10:19:00,6.56 2015-09-16 10:24:00,4.39 2015-09-16 10:29:00,3.33 2015-09-16 10:34:00,2.67 2015-09-16 10:39:00,1.67 2015-09-16 10:44:00,8.67 2015-09-16 10:49:00,3.5 2015-09-16 10:54:00,3.61 2015-09-16 10:59:00,4.78 2015-09-16 11:04:00,2.06 2015-09-16 11:09:00,3.5 2015-09-16 11:14:00,6.06 2015-09-16 11:24:00,3.06 2015-09-16 11:29:00,1.44 2015-09-16 11:34:00,1.39 2015-09-16 11:39:00,2.17 2015-09-16 11:44:00,5.39 2015-09-16 11:49:00,1.94 2015-09-16 11:54:00,2.17 2015-09-16 11:59:00,2.17 2015-09-16 12:04:00,4.11 2015-09-16 12:09:00,4.28 2015-09-16 12:14:00,1.67 2015-09-16 12:19:00,6.44 2015-09-16 12:24:00,3.5 2015-09-16 12:29:00,4.67 2015-09-16 12:34:00,2.94 2015-09-16 12:39:00,2.72 2015-09-16 12:44:00,2.17 2015-09-16 12:49:00,1.67 2015-09-16 12:54:00,4.22 2015-09-16 12:59:00,2.33 2015-09-16 13:04:00,2.33 2015-09-16 13:09:00,1.67 2015-09-16 13:14:00,4.89 2015-09-16 13:19:00,2.56 2015-09-16 13:24:00,4.22 2015-09-16 13:29:00,2.56 2015-09-16 13:34:00,1.67 2015-09-16 13:39:00,6.17 2015-09-16 13:44:00,1.83 2015-09-16 13:54:00,4.28 2015-09-16 13:59:00,3.5 2015-09-16 14:04:00,2.94 2015-09-16 14:09:00,8 2015-09-16 14:14:00,3.44 2015-09-16 14:19:00,3.83 2015-09-16 14:24:00,6.83 2015-09-16 14:29:00,5.94 2015-09-16 14:30:00,2.94 2015-09-16 14:35:00,1.44 2015-09-16 14:40:00,4.5 2015-09-16 14:50:00,1.39 2015-09-16 14:55:00,4.11 2015-09-16 15:00:00,1.17 2015-09-16 15:05:00,5.28 2015-09-16 15:10:00,4.11 2015-09-16 15:15:00,2.83 2015-09-16 15:20:00,1.83 2015-09-16 15:25:00,4.89 2015-09-16 15:30:00,3.61 2015-09-16 15:35:00,2.17 2015-09-16 15:40:00,5.78 2015-09-16 15:45:00,7.5 2015-09-16 15:50:00,6.06 2015-09-16 15:55:00,1.06 2015-09-16 16:00:00,8.67 2015-09-16 16:05:00,4.11 2015-09-16 16:10:00,4.28 2015-09-16 16:15:00,3.06 2015-09-16 16:20:00,6.06 2015-09-16 16:25:00,5.83 2015-09-16 16:30:00,2.44 2015-09-16 16:35:00,2.28 2015-09-16 16:40:00,4.61 2015-09-16 16:45:00,5.56 2015-09-16 16:55:00,5.83 2015-09-16 17:00:00,3.11 2015-09-16 17:05:00,3.89 2015-09-16 17:10:00,2.83 2015-09-16 17:15:00,3.44 2015-09-16 17:20:00,2.44 2015-09-16 17:25:00,1.44 2015-09-16 17:30:00,5.56 2015-09-16 17:35:00,4.78 2015-09-16 17:45:00,3.61 2015-09-16 17:50:00,1.39 2015-09-16 17:55:00,0.67 2015-09-16 18:00:00,5.94 2015-09-16 18:05:00,3.83 2015-09-16 18:10:00,4.61 2015-09-16 18:15:00,5.83 2015-09-16 18:20:00,4 2015-09-16 18:30:00,5.94 2015-09-16 18:35:00,1.83 2015-09-16 18:40:00,1.94 2015-09-16 18:45:00,1.83 2015-09-16 18:50:00,2.72 2015-09-16 18:55:00,3.11 2015-09-16 19:00:00,4.89 2015-09-16 19:05:00,0.89 2015-09-16 19:10:00,2.33 2015-09-16 19:15:00,1.56 2015-09-16 19:20:00,2.72 2015-09-16 19:25:00,2.83 2015-09-16 19:30:00,2.33 2015-09-16 19:35:00,2.83 2015-09-16 19:40:00,3.06 2015-09-16 19:45:00,6.44 2015-09-16 19:50:00,1.56 2015-09-16 19:55:00,4.39 2015-09-16 20:00:00,1.39 2015-09-16 20:05:00,4.11 2015-09-16 20:10:00,1.44 2015-09-16 20:15:00,1.56 2015-09-16 20:20:00,4.67 2015-09-16 20:25:00,0.67 2015-09-16 20:30:00,5.67 2015-09-16 20:35:00,2.67 2015-09-16 20:40:00,1.28 2015-09-16 20:45:00,2.06 2015-09-16 20:50:00,2.72 2015-09-16 20:55:00,3.89 2015-09-16 21:00:00,1.06 2015-09-16 21:15:00,2.44 2015-09-16 21:20:00,1.44 2015-09-16 21:30:00,2.44 2015-09-16 21:35:00,4.39 2015-09-16 21:40:00,1.56 2015-09-16 21:45:00,1.94 2015-09-16 21:50:00,3.61 2015-09-16 21:55:00,1.28 2015-09-16 21:59:00,1.44 2015-09-16 22:05:00,0 2015-09-16 22:10:00,1.83 2015-09-16 22:14:00,0.67 2015-09-16 22:20:00,0.39 2015-09-16 22:25:00,1.67 2015-09-16 22:30:00,1 2015-09-16 22:35:00,2.06 2015-09-16 22:40:00,0.39 2015-09-16 22:45:00,0 2015-09-16 23:00:00,0.61 2015-09-16 23:05:00,0 2015-09-16 23:10:00,0.28 2015-09-16 23:15:00,0.5 2015-09-16 23:20:00,0 2015-09-16 23:40:00,0 2015-09-16 23:45:00,0 2015-09-16 23:50:00,0.39 2015-09-17 00:00:00,1.94 2015-09-17 00:10:00,1.56 2015-09-17 00:15:00,2.28 2015-09-17 00:25:00,0.39 2015-09-17 00:50:00,0.39 2015-09-17 00:59:00,2.28 2015-09-17 01:05:00,1.94 2015-09-17 01:15:00,1.06 2015-09-17 01:25:00,0 2015-09-17 01:40:00,0 2015-09-17 01:45:00,1.06 2015-09-17 01:50:00,0.67 2015-09-17 01:55:00,0 2015-09-17 02:00:00,0 2015-09-17 02:05:00,1.28 2015-09-17 02:15:00,0.67 2015-09-17 02:20:00,1 2015-09-17 02:25:00,0.67 2015-09-17 02:35:00,0.89 2015-09-17 02:40:00,0 2015-09-17 02:45:00,2.06 2015-09-17 02:50:00,0 2015-09-17 02:55:00,0.5 2015-09-17 03:00:00,0 2015-09-17 03:05:00,1.83 2015-09-17 03:10:00,2.56 2015-09-17 03:15:00,0 2015-09-17 03:20:00,0.39 2015-09-17 03:30:00,0.89 2015-09-17 03:35:00,2.28 2015-09-17 03:40:00,0 2015-09-17 03:45:00,0.89 2015-09-17 03:50:00,0 2015-09-17 03:55:00,0.28 2015-09-17 04:00:00,0 2015-09-17 04:05:00,0 2015-09-17 04:10:00,0.28 2015-09-17 04:15:00,3.33 2015-09-17 04:20:00,0.78 2015-09-17 04:25:00,1.39 2015-09-17 04:30:00,0.89 2015-09-17 04:35:00,5.28 2015-09-17 04:40:00,1.83 2015-09-17 04:45:00,2.83 2015-09-17 04:50:00,2.28 2015-09-17 04:55:00,2.28 2015-09-17 05:00:00,1.83 2015-09-17 05:05:00,3.33 2015-09-17 05:10:00,4.67 2015-09-17 05:15:00,1.28 2015-09-17 05:20:00,3.89 2015-09-17 05:25:00,6.56 2015-09-17 05:30:00,7.44 2015-09-17 05:35:00,7.06 2015-09-17 05:40:00,7.61 2015-09-17 05:45:00,5.56 2015-09-17 05:50:00,7.5 2015-09-17 05:55:00,7.72 2015-09-17 06:00:00,14.06 2015-09-17 06:05:00,11.06 2015-09-17 06:10:00,8.61 2015-09-17 06:15:00,16.33 2015-09-17 06:20:00,13.28 2015-09-17 06:25:00,16.61 2015-09-17 06:30:00,14.44 2015-09-17 06:35:00,16.78 2015-09-17 06:40:00,18.17 2015-09-17 06:45:00,14.67 2015-09-17 06:50:00,16.78 2015-09-17 06:55:00,8.89 2015-09-17 07:00:00,10.83 2015-09-17 07:05:00,8.5 2015-09-17 07:10:00,1.28 2015-09-17 07:15:00,2.83 2015-09-17 07:20:00,16.78 2015-09-17 07:25:00,8.11 2015-09-17 07:30:00,1.28 2015-09-17 07:35:00,5.39 2015-09-17 07:40:00,19.17 2015-09-17 07:45:00,6.67 2015-09-17 07:50:00,8.11 2015-09-17 07:55:00,9.39 2015-09-17 08:00:00,12.89 2015-09-17 08:05:00,8.67 2015-09-17 08:10:00,6.94 2015-09-17 08:15:00,12.72 2015-09-17 08:20:00,8.67 2015-09-17 08:25:00,6.06 2015-09-17 08:30:00,4 2015-09-17 08:35:00,8.78 2015-09-17 08:40:00,6.83 2015-09-17 08:45:00,5.78 2015-09-17 08:50:00,6.06 2015-09-17 08:55:00,4.61 2015-09-17 09:00:00,3.22 2015-09-17 09:05:00,4.22 2015-09-17 09:10:00,13.39 2015-09-17 09:15:00,6.28 2015-09-17 09:20:00,9.56 2015-09-17 09:25:00,12.39 2015-09-17 09:30:00,2.33 2015-09-17 09:35:00,5 2015-09-17 09:40:00,6.56 2015-09-17 09:45:00,4.67 2015-09-17 09:50:00,2.94 2015-09-17 09:55:00,6.17 2015-09-17 10:00:00,1 2015-09-17 10:05:00,7.11 2015-09-17 10:10:00,3.61 2015-09-17 10:15:00,3.22 2015-09-17 10:20:00,7.61 2015-09-17 10:25:00,3.06 2015-09-17 10:30:00,2.06 2015-09-17 10:35:00,5.83 2015-09-17 10:40:00,4.22 2015-09-17 10:45:00,4.5 2015-09-17 10:50:00,4.5 2015-09-17 10:55:00,1.44 2015-09-17 11:05:00,0.67 2015-09-17 11:10:00,5.56 2015-09-17 11:15:00,2.56 2015-09-17 11:20:00,3.33 2015-09-17 11:25:00,3.61 2015-09-17 11:30:00,5.78 2015-09-17 11:35:00,5.17 2015-09-17 11:40:00,6.56 2015-09-17 11:45:00,3.72 2015-09-17 11:50:00,2.28 2015-09-17 11:55:00,5.39 2015-09-17 12:00:00,2.06 2015-09-17 12:05:00,4.78 2015-09-17 12:10:00,5.94 2015-09-17 12:15:00,3.83 2015-09-17 12:20:00,3.22 2015-09-17 12:25:00,6.94 2015-09-17 12:30:00,1 2015-09-17 12:35:00,1.83 2015-09-17 12:40:00,3.5 2015-09-17 12:45:00,2.56 2015-09-17 12:50:00,3.83 2015-09-17 12:55:00,5 2015-09-17 13:00:00,3.06 2015-09-17 13:05:00,1.28 2015-09-17 13:10:00,2.33 2015-09-17 13:15:00,2.44 2015-09-17 13:20:00,5.06 2015-09-17 13:25:00,2.83 2015-09-17 13:30:00,4.89 2015-09-17 13:35:00,1.56 2015-09-17 13:40:00,2.67 2015-09-17 13:45:00,2.17 2015-09-17 13:50:00,5.67 2015-09-17 13:55:00,2.06 2015-09-17 14:00:00,3.83 2015-09-17 14:05:00,5.94 2015-09-17 14:10:00,3.89 2015-09-17 14:15:00,5.06 2015-09-17 14:20:00,6.94 2015-09-17 14:25:00,0 2015-09-17 14:30:00,5.39 2015-09-17 14:34:00,4.67 2015-09-17 14:39:00,5.67 2015-09-17 14:44:00,6.06 2015-09-17 14:49:00,7.22 2015-09-17 14:54:00,2.94 2015-09-17 14:58:00,3.06 2015-09-17 15:04:00,3.44 2015-09-17 15:08:00,3.89 2015-09-17 15:13:00,2.56 2015-09-17 15:18:00,2.72 2015-09-17 15:23:00,6.28 2015-09-17 15:28:00,2.83 2015-09-17 15:34:00,4.11 2015-09-17 15:38:00,5.78 2015-09-17 15:43:00,7.89 2015-09-17 15:48:00,4.22 2015-09-17 15:49:00,2.83 2015-09-17 15:54:00,4.5 2015-09-17 15:59:00,11.11 2015-09-17 16:04:00,9.28 2015-09-17 16:09:00,5.06 2015-09-17 16:14:00,3.44 2015-09-17 16:19:00,8.5 2015-09-17 16:24:00,5.56 ================================================ FILE: workspace/anomaly_detector/datasets/selected/seasonal/occupancy_t4013.csv ================================================ timestamp,value 2015-09-01 11:30:00,13.56 2015-09-01 11:35:00,8.33 2015-09-01 11:40:00,11.78 2015-09-01 11:55:00,15.28 2015-09-01 12:00:00,10.06 2015-09-01 12:05:00,7.44 2015-09-01 12:10:00,8.11 2015-09-01 12:15:00,10.72 2015-09-01 12:20:00,11.83 2015-09-01 12:25:00,9.61 2015-09-01 12:30:00,10.22 2015-09-01 12:35:00,10.72 2015-09-01 12:45:00,10.28 2015-09-01 12:50:00,13.72 2015-09-01 12:55:00,7.39 2015-09-01 13:05:00,2.61 2015-09-01 13:10:00,7.33 2015-09-01 13:15:00,8.5 2015-09-01 13:20:00,10.56 2015-09-01 13:25:00,13.78 2015-09-01 13:35:00,7.78 2015-09-01 13:45:00,7.72 2015-09-01 13:50:00,10.11 2015-09-01 14:00:00,9.56 2015-09-01 14:05:00,14.94 2015-09-01 14:10:00,25.89 2015-09-01 14:15:00,10.17 2015-09-01 14:30:00,6.39 2015-09-01 14:35:00,12.89 2015-09-01 14:40:00,9.06 2015-09-01 14:50:00,11.67 2015-09-01 14:55:00,7.94 2015-09-01 15:00:00,8.17 2015-09-01 15:05:00,24.72 2015-09-01 15:10:00,9.06 2015-09-01 15:25:00,14.89 2015-09-01 15:30:00,8.28 2015-09-01 15:35:00,7.83 2015-09-01 15:40:00,12.28 2015-09-01 15:45:00,14.94 2015-09-01 15:55:00,14.39 2015-09-01 16:00:00,7.5 2015-09-01 16:05:00,11.5 2015-09-01 16:10:00,10 2015-09-01 16:15:00,8.83 2015-09-01 16:20:00,11.33 2015-09-01 16:25:00,11.17 2015-09-01 16:30:00,9.83 2015-09-01 16:40:00,7.67 2015-09-01 16:45:00,14.89 2015-09-01 16:55:00,7.28 2015-09-01 17:05:00,11.83 2015-09-01 17:10:00,13.72 2015-09-01 17:15:00,21.33 2015-09-01 17:20:00,21.61 2015-09-01 17:25:00,14.61 2015-09-01 17:35:00,15.28 2015-09-01 17:40:00,10.33 2015-09-01 17:45:00,7.61 2015-09-01 17:50:00,8.89 2015-09-01 17:55:00,10.72 2015-09-01 17:59:00,9.06 2015-09-01 18:10:00,14 2015-09-01 18:15:00,14.56 2015-09-01 18:20:00,8.06 2015-09-01 18:25:00,4.89 2015-09-01 18:30:00,7.72 2015-09-01 18:35:00,9.11 2015-09-01 18:45:00,6.89 2015-09-01 18:50:00,9.11 2015-09-01 19:20:00,8.33 2015-09-01 19:25:00,5.33 2015-09-01 19:35:00,6.11 2015-09-01 19:50:00,4.06 2015-09-01 20:00:00,7.06 2015-09-01 20:15:00,5.83 2015-09-01 20:35:00,8.67 2015-09-01 20:40:00,5.94 2015-09-01 20:50:00,3.39 2015-09-01 20:55:00,5.5 2015-09-01 21:00:00,9.11 2015-09-01 21:05:00,12.83 2015-09-01 21:10:00,6.11 2015-09-01 21:15:00,5.67 2015-09-01 21:20:00,6.17 2015-09-01 21:25:00,2.44 2015-09-01 21:30:00,4 2015-09-01 21:35:00,6.72 2015-09-01 21:59:00,1.44 2015-09-01 22:10:00,9 2015-09-01 22:20:00,1.06 2015-09-01 22:25:00,6.61 2015-09-01 22:40:00,4.61 2015-09-01 22:45:00,3.28 2015-09-01 22:50:00,1.83 2015-09-01 23:01:00,3.17 2015-09-01 23:05:00,5.17 2015-09-01 23:10:00,2.56 2015-09-01 23:15:00,4.17 2015-09-01 23:45:00,0.67 2015-09-02 00:05:00,0.61 2015-09-02 00:10:00,2.72 2015-09-02 00:30:00,2.39 2015-09-02 01:25:00,5.67 2015-09-02 01:35:00,0.83 2015-09-02 02:30:00,1.61 2015-09-02 02:40:00,4.39 2015-09-02 02:50:00,3.67 2015-09-02 03:05:00,1.89 2015-09-02 03:10:00,0.83 2015-09-02 03:40:00,1.72 2015-09-02 03:50:00,4.44 2015-09-02 03:55:00,5.5 2015-09-02 04:05:00,4.17 2015-09-02 04:20:00,2.22 2015-09-02 04:25:00,10.11 2015-09-02 04:40:00,1.72 2015-09-02 04:45:00,1.39 2015-09-02 04:50:00,6.11 2015-09-02 04:55:00,7.94 2015-09-02 05:00:00,5.67 2015-09-02 05:10:00,5.67 2015-09-02 05:15:00,4.44 2015-09-02 05:20:00,6.06 2015-09-02 05:30:00,2.17 2015-09-02 05:35:00,5.61 2015-09-02 05:45:00,6.44 2015-09-02 05:50:00,8 2015-09-02 05:55:00,10.33 2015-09-02 06:00:00,14.28 2015-09-02 06:05:00,14.06 2015-09-02 06:10:00,11.61 2015-09-02 06:20:00,12.94 2015-09-02 06:25:00,12.39 2015-09-02 06:30:00,16.78 2015-09-02 06:40:00,8.67 2015-09-02 06:45:00,21.72 2015-09-02 06:50:00,10.67 2015-09-02 06:55:00,12.28 2015-09-02 07:00:00,16.17 2015-09-02 07:05:00,25.61 2015-09-02 07:10:00,25.78 2015-09-02 07:15:00,9.44 2015-09-02 07:20:00,8.83 2015-09-02 07:25:00,11.72 2015-09-02 07:30:00,12.17 2015-09-02 07:35:00,14.33 2015-09-02 07:40:00,12.11 2015-09-02 07:45:00,13.67 2015-09-02 07:50:00,9.17 2015-09-02 07:55:00,15.06 2015-09-02 08:00:00,19.56 2015-09-02 08:05:00,18 2015-09-02 08:10:00,14.17 2015-09-02 08:15:00,8.33 2015-09-02 08:20:00,15.72 2015-09-02 08:25:00,12.83 2015-09-02 08:30:00,21.22 2015-09-02 08:35:00,17.39 2015-09-02 08:40:00,16.11 2015-09-02 08:45:00,18.83 2015-09-02 08:50:00,16.89 2015-09-02 08:55:00,18.61 2015-09-02 09:00:00,12.78 2015-09-02 09:05:00,13.33 2015-09-02 09:10:00,20.17 2015-09-02 09:15:00,21.56 2015-09-02 09:25:00,11.78 2015-09-02 09:30:00,12.78 2015-09-02 09:35:00,12.17 2015-09-02 09:40:00,7.78 2015-09-02 09:55:00,6.56 2015-09-02 10:00:00,13.06 2015-09-02 10:05:00,15.06 2015-09-02 10:10:00,11.72 2015-09-02 10:15:00,6.5 2015-09-02 10:20:00,12.72 2015-09-02 10:25:00,9.56 2015-09-02 10:30:00,13.78 2015-09-02 10:35:00,12.33 2015-09-02 10:40:00,9.22 2015-09-02 10:45:00,10.39 2015-09-02 10:50:00,5.06 2015-09-02 10:55:00,5.72 2015-09-02 11:00:00,10.56 2015-09-02 11:10:00,12.72 2015-09-02 11:15:00,18.33 2015-09-02 11:25:00,8.78 2015-09-02 11:30:00,9.61 2015-09-02 11:40:00,13.33 2015-09-02 11:45:00,7 2015-09-02 11:50:00,9.61 2015-09-02 11:55:00,11.78 2015-09-02 12:00:00,3.06 2015-09-02 12:05:00,13.33 2015-09-02 12:15:00,14.28 2015-09-02 12:20:00,14.33 2015-09-02 12:25:00,6.89 2015-09-02 12:30:00,11.22 2015-09-02 12:35:00,8.17 2015-09-02 12:40:00,8.28 2015-09-02 12:50:00,15.11 2015-09-02 12:55:00,13.06 2015-09-02 13:00:00,12.39 2015-09-02 13:05:00,13.28 2015-09-02 13:10:00,6.06 2015-09-02 13:15:00,17.61 2015-09-02 13:20:00,13.22 2015-09-02 13:25:00,10.11 2015-09-02 13:30:00,8.83 2015-09-02 13:35:00,12.89 2015-09-02 13:40:00,4.61 2015-09-02 13:55:00,15.28 2015-09-02 14:00:00,6.56 2015-09-02 14:05:00,9.61 2015-09-02 14:10:00,13.67 2015-09-02 14:15:00,8.78 2015-09-02 14:20:00,11.78 2015-09-02 14:25:00,9.94 2015-09-02 14:30:00,11.33 2015-09-02 14:35:00,12.44 2015-09-02 14:40:00,12.61 2015-09-02 14:45:00,10.78 2015-09-02 14:50:00,10.28 2015-09-02 15:00:00,14.17 2015-09-02 15:05:00,13.72 2015-09-02 15:10:00,12.67 2015-09-02 15:15:00,14.17 2015-09-02 15:20:00,15.39 2015-09-02 15:25:00,13.44 2015-09-02 15:30:00,10.33 2015-09-02 15:35:00,12.06 2015-09-02 15:40:00,11.17 2015-09-02 15:45:00,14 2015-09-02 15:50:00,11.78 2015-09-02 15:55:00,13.61 2015-09-02 16:00:00,7.44 2015-09-02 16:05:00,9.78 2015-09-02 16:10:00,11.67 2015-09-02 16:15:00,8.56 2015-09-02 16:20:00,7.5 2015-09-02 16:25:00,12.22 2015-09-02 16:30:00,12.44 2015-09-02 16:35:00,7.89 2015-09-02 16:40:00,17.72 2015-09-02 16:45:00,13.94 2015-09-02 16:50:00,11.94 2015-09-02 16:55:00,13.39 2015-09-02 17:00:00,8.94 2015-09-02 17:05:00,14.33 2015-09-02 17:10:00,14.67 2015-09-02 17:15:00,11.17 2015-09-02 17:20:00,18.5 2015-09-02 17:25:00,5.56 2015-09-02 17:30:00,10.11 2015-09-02 17:35:00,10.72 2015-09-02 17:40:00,8.44 2015-09-02 17:45:00,10.17 2015-09-02 17:50:00,9.83 2015-09-02 18:05:00,11.5 2015-09-02 18:10:00,9.89 2015-09-02 18:15:00,11.78 2015-09-02 18:30:00,9.17 2015-09-02 18:35:00,6.72 2015-09-02 18:45:00,8.11 2015-09-02 18:55:00,8.06 2015-09-02 19:00:00,3.78 2015-09-02 19:05:00,7.11 2015-09-02 19:10:00,6.78 2015-09-02 19:21:00,6.5 2015-09-02 19:36:00,6.56 2015-09-02 19:41:00,4.78 2015-09-02 19:51:00,3.72 2015-09-02 20:01:00,3.78 2015-09-02 20:06:00,10.67 2015-09-02 20:11:00,5.67 2015-09-02 20:16:00,13.33 2015-09-02 20:21:00,9.44 2015-09-02 20:26:00,10.22 2015-09-02 20:36:00,8 2015-09-02 20:41:00,7.78 2015-09-02 20:46:00,5.11 2015-09-02 20:56:00,3.83 2015-09-02 21:06:00,2.94 2015-09-02 21:21:00,6.56 2015-09-02 21:26:00,3.72 2015-09-02 21:36:00,5.56 2015-09-02 21:51:00,4.78 2015-09-02 22:01:00,5.11 2015-09-02 22:06:00,5.11 2015-09-02 22:11:00,9.44 2015-09-02 22:26:00,3.39 2015-09-02 22:41:00,5.83 2015-09-02 22:51:00,1.39 2015-09-02 23:01:00,3.22 2015-09-02 23:11:00,1.61 2015-09-02 23:16:00,5.17 2015-09-02 23:26:00,1.61 2015-09-02 23:41:00,1.78 2015-09-03 00:11:00,0.67 2015-09-03 00:21:00,2.06 2015-09-03 00:26:00,3.89 2015-09-03 00:36:00,2.61 2015-09-03 00:56:00,3.5 2015-09-03 01:01:00,4.33 2015-09-03 01:06:00,1.22 2015-09-03 01:16:00,1.94 2015-09-03 01:31:00,2.44 2015-09-03 01:56:00,2.28 2015-09-03 02:36:00,2.72 2015-09-03 02:46:00,2.94 2015-09-03 02:56:00,3.22 2015-09-03 03:16:00,0.72 2015-09-03 03:31:00,0.56 2015-09-03 03:41:00,4.78 2015-09-03 03:46:00,1.61 2015-09-03 04:11:00,1.72 2015-09-03 04:31:00,2.72 2015-09-03 04:46:00,2.22 2015-09-03 05:01:00,1.83 2015-09-03 05:11:00,5.83 2015-09-03 05:31:00,8.17 2015-09-03 05:36:00,10.67 2015-09-03 05:41:00,3.17 2015-09-03 05:51:00,7.56 2015-09-03 05:56:00,6.11 2015-09-03 06:01:00,6.44 2015-09-03 06:06:00,4.11 2015-09-03 06:11:00,2.17 2015-09-03 06:16:00,5.06 2015-09-03 06:21:00,12 2015-09-03 06:26:00,11.83 2015-09-03 06:36:00,13.56 2015-09-03 06:41:00,4.56 2015-09-03 06:51:00,7 2015-09-03 07:06:00,8 2015-09-03 07:11:00,12.33 2015-09-03 07:16:00,12.44 2015-09-03 07:21:00,13.06 2015-09-03 07:26:00,6.28 2015-09-03 07:31:00,11.5 2015-09-03 07:36:00,11.33 2015-09-03 07:41:00,8.39 2015-09-03 07:46:00,12.78 2015-09-03 07:51:00,11.28 2015-09-03 07:56:00,8.89 2015-09-03 08:01:00,8.33 2015-09-03 08:06:00,17.61 2015-09-03 08:31:00,10.83 2015-09-03 08:36:00,12.22 2015-09-03 08:41:00,12.67 2015-09-03 08:46:00,7.5 2015-09-03 08:51:00,13 2015-09-03 09:01:00,10.78 2015-09-03 09:11:00,12.22 2015-09-03 09:16:00,18.5 2015-09-03 09:21:00,13.72 2015-09-03 09:26:00,12.06 2015-09-03 09:31:00,9.44 2015-09-03 09:36:00,7.72 2015-09-03 09:46:00,8.72 2015-09-03 09:51:00,11.94 2015-09-03 09:56:00,5.5 2015-09-03 10:01:00,7.39 2015-09-03 10:06:00,17.28 2015-09-03 10:11:00,12.06 2015-09-03 10:21:00,7.5 2015-09-03 10:26:00,6.22 2015-09-03 10:36:00,7.17 2015-09-03 10:41:00,7.94 2015-09-03 10:46:00,13.61 2015-09-03 10:51:00,10.56 2015-09-03 10:56:00,7.22 2015-09-03 11:06:00,12.67 2015-09-03 11:11:00,10.72 2015-09-03 11:16:00,11.83 2015-09-03 11:26:00,10.11 2015-09-03 11:31:00,8.33 2015-09-03 11:36:00,16.72 2015-09-03 11:41:00,10.44 2015-09-03 11:46:00,11.39 2015-09-03 11:51:00,8.5 2015-09-03 12:01:00,8.22 2015-09-03 12:06:00,10.44 2015-09-03 12:11:00,9.67 2015-09-03 12:16:00,7.56 2015-09-03 12:21:00,6.17 2015-09-03 12:26:00,10.39 2015-09-03 12:31:00,7.67 2015-09-03 12:36:00,9.39 2015-09-03 12:41:00,12.17 2015-09-03 12:51:00,15.5 2015-09-03 12:56:00,5.06 2015-09-03 13:06:00,6.06 2015-09-03 13:11:00,6.17 2015-09-03 13:26:00,6.44 2015-09-03 13:31:00,9.5 2015-09-03 13:36:00,13.39 2015-09-03 13:41:00,8.89 2015-09-03 13:46:00,9.44 2015-09-03 13:51:00,8 2015-09-03 14:01:00,11.11 2015-09-03 14:06:00,10.28 2015-09-03 14:11:00,6.5 2015-09-03 14:16:00,6.72 2015-09-03 14:21:00,14.28 2015-09-03 14:26:00,1.17 2015-09-03 14:31:00,8.44 2015-09-03 14:41:00,12.33 2015-09-03 14:51:00,12.06 2015-09-03 14:56:00,12.28 2015-09-03 15:01:00,8.06 2015-09-03 15:06:00,9.44 2015-09-03 15:11:00,12.28 2015-09-03 15:21:00,6.72 2015-09-03 15:26:00,9.33 2015-09-03 15:36:00,12.17 2015-09-03 15:41:00,8.83 2015-09-03 15:51:00,6.72 2015-09-03 15:56:00,11.33 2015-09-03 16:01:00,3.89 2015-09-03 16:06:00,8.56 2015-09-03 16:11:00,16.06 2015-09-03 16:16:00,8.83 2015-09-03 16:26:00,6.78 2015-09-03 16:36:00,10.33 2015-09-03 16:41:00,13.89 2015-09-03 16:46:00,9.72 2015-09-03 16:51:00,4.17 2015-09-03 17:01:00,4 2015-09-03 17:06:00,6.22 2015-09-03 17:11:00,8.33 2015-09-03 17:21:00,9.28 2015-09-03 17:26:00,10.28 2015-09-03 17:36:00,4.39 2015-09-03 17:41:00,6.06 2015-09-03 17:46:00,5.06 2015-09-03 17:51:00,13.94 2015-09-03 17:56:00,9.17 2015-09-03 18:01:00,5.72 2015-09-03 18:06:00,5.5 2015-09-03 18:11:00,4.5 2015-09-03 18:16:00,5.67 2015-09-03 18:21:00,11.11 2015-09-03 18:26:00,8.44 2015-09-03 18:31:00,11.17 2015-09-03 18:36:00,5.72 2015-09-03 18:46:00,7.67 2015-09-03 18:51:00,5 2015-09-03 18:56:00,5.94 2015-09-03 19:01:00,4.83 2015-09-03 19:06:00,4.83 2015-09-03 19:11:00,7.39 2015-09-03 19:16:00,5.72 2015-09-03 19:21:00,4.56 2015-09-03 19:31:00,2.17 2015-09-03 19:42:00,7.11 2015-09-03 19:47:00,4.17 2015-09-03 19:57:00,4.44 2015-09-03 20:02:00,1.67 2015-09-03 20:07:00,4.06 2015-09-03 20:17:00,4.06 2015-09-03 20:42:00,6.33 2015-09-03 20:47:00,6.06 2015-09-03 20:57:00,2.44 2015-09-03 21:07:00,5.61 2015-09-03 21:12:00,3.44 2015-09-03 21:17:00,8.72 2015-09-03 21:22:00,3.22 2015-09-03 21:27:00,2 2015-09-03 21:32:00,4.67 2015-09-03 21:37:00,6.94 2015-09-03 21:42:00,4.11 2015-09-03 21:47:00,5.06 2015-09-03 22:02:00,8.67 2015-09-03 22:12:00,6.89 2015-09-03 22:22:00,5.11 2015-09-03 23:02:00,1.44 2015-09-03 23:22:00,4.33 2015-09-03 23:37:00,1.94 2015-09-03 23:42:00,0.83 2015-09-03 23:47:00,0.78 2015-09-04 00:02:00,2.61 2015-09-04 00:17:00,4.44 2015-09-04 00:27:00,0.67 2015-09-04 01:02:00,0.94 2015-09-04 01:17:00,3.11 2015-09-04 01:37:00,3.78 2015-09-04 01:42:00,2.89 2015-09-04 01:57:00,4.61 2015-09-04 02:02:00,3.44 2015-09-04 02:22:00,3.67 2015-09-04 03:57:00,1.22 2015-09-04 04:12:00,4.06 2015-09-04 04:17:00,0.89 2015-09-04 04:22:00,3.5 2015-09-04 04:27:00,1.06 2015-09-04 04:32:00,3.72 2015-09-04 04:37:00,3 2015-09-04 04:52:00,3.78 2015-09-04 05:17:00,2.94 2015-09-04 05:22:00,3.06 2015-09-04 05:27:00,2.17 2015-09-04 05:42:00,7.28 2015-09-04 05:52:00,7.11 2015-09-04 05:57:00,5.61 2015-09-04 06:02:00,4.61 2015-09-04 06:07:00,6.39 2015-09-04 06:12:00,10.06 2015-09-04 06:17:00,11.78 2015-09-04 06:22:00,7.06 2015-09-04 06:27:00,5.11 2015-09-04 06:32:00,7.11 2015-09-04 06:37:00,10.28 2015-09-04 06:42:00,7.89 2015-09-04 06:47:00,11.61 2015-09-04 06:52:00,9.44 2015-09-04 06:57:00,7.61 2015-09-04 07:02:00,3.22 2015-09-04 07:07:00,7.33 2015-09-04 07:12:00,13.67 2015-09-04 07:17:00,10.17 2015-09-04 07:22:00,10.17 2015-09-04 07:32:00,13.17 2015-09-04 07:42:00,11.5 2015-09-04 07:47:00,11.11 2015-09-04 08:07:00,6.17 2015-09-04 08:12:00,7.17 2015-09-04 08:17:00,13.78 2015-09-04 08:22:00,9.17 2015-09-04 08:27:00,7.83 2015-09-04 08:32:00,9.67 2015-09-04 08:37:00,10.72 2015-09-04 08:42:00,13.17 2015-09-04 08:47:00,9.22 2015-09-04 08:57:00,8 2015-09-04 09:02:00,9.67 2015-09-04 09:07:00,3.67 2015-09-04 09:22:00,7 2015-09-04 09:27:00,7.06 2015-09-04 09:32:00,12.06 2015-09-04 09:42:00,8.78 2015-09-04 09:47:00,11.33 2015-09-04 09:52:00,13.89 2015-09-04 09:57:00,6 2015-09-04 10:07:00,7.11 2015-09-04 10:12:00,5.17 2015-09-04 10:22:00,9 2015-09-04 10:27:00,11.11 2015-09-04 10:32:00,6.94 2015-09-04 10:42:00,9.72 2015-09-04 10:52:00,6 2015-09-04 10:57:00,9.06 2015-09-04 11:02:00,7.39 2015-09-04 11:12:00,6 2015-09-04 11:17:00,9.89 2015-09-04 11:22:00,4.78 2015-09-04 11:27:00,10.56 2015-09-04 11:32:00,8.33 2015-09-04 11:37:00,15.28 2015-09-04 11:42:00,11.5 2015-09-04 11:52:00,6.94 2015-09-04 11:57:00,6.11 2015-09-04 12:27:00,6.22 2015-09-04 12:37:00,7.28 2015-09-04 12:47:00,7.44 2015-09-04 13:12:00,10.94 2015-09-04 13:17:00,5.39 2015-09-04 13:22:00,7.33 2015-09-04 13:27:00,9.11 2015-09-04 13:37:00,8.78 2015-09-04 13:47:00,2.22 2015-09-04 14:02:00,3.22 2015-09-04 14:12:00,6.56 2015-09-04 14:17:00,6.72 2015-09-04 14:22:00,2.33 2015-09-04 14:27:00,10.72 2015-09-04 14:37:00,4.67 2015-09-04 14:47:00,9.44 2015-09-04 14:52:00,6.28 2015-09-04 14:57:00,6.5 2015-09-04 15:07:00,5 2015-09-04 15:12:00,10.06 2015-09-04 15:17:00,9.5 2015-09-04 15:27:00,9 2015-09-04 15:32:00,6.22 2015-09-04 15:37:00,7 2015-09-04 15:52:00,15 2015-09-04 15:57:00,7.28 2015-09-04 16:07:00,5.17 2015-09-04 16:12:00,4.17 2015-09-04 16:17:00,10.78 2015-09-04 16:22:00,14.33 2015-09-04 16:27:00,4.17 2015-09-04 16:37:00,8.28 2015-09-04 17:02:00,5.56 2015-09-04 17:07:00,10.72 2015-09-04 17:12:00,5.06 2015-09-04 17:17:00,3.33 2015-09-04 17:22:00,3.78 2015-09-04 17:32:00,6.22 2015-09-04 17:37:00,7.83 2015-09-04 17:42:00,11.83 2015-09-04 17:52:00,6 2015-09-04 18:02:00,6.83 2015-09-04 18:07:00,5.89 2015-09-04 18:12:00,9.67 2015-09-04 18:17:00,8.11 2015-09-04 18:27:00,7.78 2015-09-04 18:32:00,5.06 2015-09-04 18:42:00,10.83 2015-09-04 18:47:00,6.39 2015-09-04 18:52:00,4.83 2015-09-04 18:57:00,2.61 2015-09-04 19:12:00,2.44 2015-09-04 19:22:00,3.39 2015-09-04 19:37:00,3.56 2015-09-04 19:47:00,4.56 2015-09-04 19:52:00,6.67 2015-09-04 19:57:00,1.78 2015-09-04 20:02:00,8.61 2015-09-04 20:12:00,2 2015-09-04 20:17:00,10.89 2015-09-04 20:18:00,3.83 2015-09-04 20:23:00,6.5 2015-09-04 20:28:00,3.78 2015-09-04 20:33:00,3.83 2015-09-04 21:03:00,5.11 2015-09-04 21:08:00,3.56 2015-09-04 21:13:00,2.28 2015-09-04 21:18:00,5.22 2015-09-04 21:23:00,4.22 2015-09-04 21:28:00,1.72 2015-09-04 21:38:00,2.89 2015-09-04 21:43:00,7 2015-09-04 21:48:00,2.94 2015-09-04 21:53:00,6.67 2015-09-04 22:03:00,3 2015-09-04 22:08:00,1.11 2015-09-04 22:13:00,4.83 2015-09-04 22:23:00,3.56 2015-09-08 10:44:00,10.06 2015-09-08 10:54:00,5.11 2015-09-08 10:59:00,9.94 2015-09-08 11:04:00,3.56 2015-09-08 11:14:00,5.5 2015-09-08 11:19:00,6.61 2015-09-08 11:24:00,6.78 2015-09-08 11:29:00,11.11 2015-09-08 11:34:00,7.56 2015-09-08 11:49:00,15 2015-09-08 11:54:00,8.72 2015-09-08 11:59:00,11.56 2015-09-08 12:04:00,10.39 2015-09-08 12:09:00,14.11 2015-09-08 12:19:00,8.39 2015-09-08 12:24:00,9.11 2015-09-08 12:27:00,2.5 2015-09-08 12:32:00,9.17 2015-09-08 12:36:00,7.11 2015-09-08 12:46:00,12.83 2015-09-08 12:56:00,5.94 2015-09-08 13:01:00,6.67 2015-09-08 13:06:00,5 2015-09-08 13:16:00,8.67 2015-09-08 13:21:00,8.94 2015-09-08 13:26:00,10.44 2015-09-08 13:36:00,10.5 2015-09-08 13:41:00,12.28 2015-09-08 13:51:00,15.22 2015-09-08 13:56:00,7.17 2015-09-08 14:00:00,8.11 2015-09-08 14:06:00,11.56 2015-09-08 14:11:00,4.83 2015-09-08 14:21:00,12.28 2015-09-08 14:26:00,10.67 2015-09-08 14:31:00,9.94 2015-09-08 14:36:00,10.22 2015-09-08 14:41:00,8.28 2015-09-08 14:46:00,4.28 2015-09-08 14:51:00,6.06 2015-09-08 14:56:00,9.22 2015-09-08 15:01:00,9.5 2015-09-08 15:06:00,10.89 2015-09-08 15:11:00,8.17 2015-09-08 15:16:00,9.5 2015-09-08 15:21:00,6.33 2015-09-08 15:29:00,8.11 2015-09-08 16:15:00,6.5 2015-09-08 16:36:00,6.17 2015-09-08 16:41:00,13.06 2015-09-08 16:46:00,9.33 2015-09-08 16:51:00,10.72 2015-09-08 16:56:00,9.56 2015-09-08 17:11:00,6.83 2015-09-08 17:16:00,9.56 2015-09-08 17:21:00,6.33 2015-09-08 17:26:00,7.28 2015-09-08 17:31:00,7.22 2015-09-08 17:36:00,6.72 2015-09-08 17:41:00,11.28 2015-09-08 17:46:00,11.78 2015-09-08 17:51:00,5.56 2015-09-08 17:56:00,5.06 2015-09-08 17:57:00,6.56 2015-09-08 18:26:00,5.22 2015-09-08 18:31:00,6.67 2015-09-08 18:36:00,4 2015-09-08 18:41:00,4.56 2015-09-08 18:46:00,10.94 2015-09-08 18:51:00,12.44 2015-09-08 19:01:00,6.33 2015-09-08 19:06:00,8.89 2015-09-08 19:11:00,13.56 2015-09-08 19:31:00,6.94 2015-09-08 19:36:00,9.17 2015-09-08 19:46:00,6.28 2015-09-08 19:51:00,5.72 2015-09-08 20:06:00,4.67 2015-09-08 20:16:00,5.11 2015-09-08 20:26:00,3.56 2015-09-08 20:36:00,9.5 2015-09-08 20:46:00,2.83 2015-09-08 20:51:00,5.89 2015-09-08 21:01:00,2.72 2015-09-08 21:06:00,1.56 2015-09-08 21:11:00,4.61 2015-09-08 21:26:00,3.44 2015-09-08 21:31:00,6.06 2015-09-08 21:36:00,4.22 2015-09-08 21:41:00,7.06 2015-09-08 21:46:00,3 2015-09-08 21:56:00,5.06 2015-09-08 22:01:00,6.28 2015-09-08 22:06:00,1.89 2015-09-08 22:12:00,2.67 2015-09-08 22:26:00,2.33 2015-09-08 22:36:00,4.5 2015-09-08 22:51:00,4.17 2015-09-08 22:56:00,1.78 2015-09-08 23:01:00,1.67 2015-09-08 23:06:00,2.89 2015-09-08 23:11:00,2.61 2015-09-09 00:01:00,4.44 2015-09-09 00:11:00,0.83 2015-09-09 00:36:00,2.72 2015-09-09 01:01:00,3.06 2015-09-09 01:11:00,1.94 2015-09-09 01:51:00,0.61 2015-09-09 02:06:00,0.83 2015-09-09 02:31:00,3.56 2015-09-09 02:46:00,2.44 2015-09-09 06:04:00,6.83 2015-09-09 07:34:00,15.11 2015-09-09 09:48:00,6.61 2015-09-09 09:58:00,12.06 2015-09-09 10:08:00,7.33 2015-09-09 10:13:00,5.83 2015-09-09 10:18:00,12.06 2015-09-09 10:23:00,8.44 2015-09-09 10:33:00,5.94 2015-09-09 10:38:00,8.17 2015-09-09 10:43:00,7.61 2015-09-09 10:48:00,8.83 2015-09-09 10:53:00,6.22 2015-09-09 10:58:00,5.17 2015-09-09 11:03:00,10.78 2015-09-09 11:08:00,10.89 2015-09-09 11:13:00,7.89 2015-09-09 11:18:00,6.78 2015-09-09 11:28:00,4.83 2015-09-09 11:33:00,8.5 2015-09-09 11:38:00,9.11 2015-09-09 11:43:00,10.56 2015-09-09 11:48:00,3.89 2015-09-09 11:53:00,16.94 2015-09-09 11:58:00,10.89 2015-09-09 12:03:00,6.28 2015-09-09 12:08:00,10.5 2015-09-09 12:13:00,6.56 2015-09-09 12:18:00,10.67 2015-09-09 12:23:00,13.06 2015-09-09 12:28:00,10.06 2015-09-09 12:33:00,10.5 2015-09-09 12:38:00,6.17 2015-09-09 12:43:00,6.89 2015-09-09 12:48:00,9.33 2015-09-09 12:53:00,3.94 2015-09-09 12:58:00,11 2015-09-09 13:08:00,11.67 2015-09-09 13:13:00,6.22 2015-09-09 13:18:00,11 2015-09-09 13:23:00,8.11 2015-09-09 13:28:00,8.33 2015-09-09 13:33:00,9.06 2015-09-09 13:38:00,3.67 2015-09-09 13:43:00,6.44 2015-09-09 13:53:00,7.28 2015-09-09 13:58:00,5.39 2015-09-09 14:03:00,7.72 2015-09-09 14:08:00,5 2015-09-09 14:13:00,1.5 2015-09-09 14:18:00,10.78 2015-09-09 14:23:00,5.5 2015-09-09 14:33:00,4.06 2015-09-09 14:38:00,11.06 2015-09-09 14:43:00,2.56 2015-09-09 14:48:00,7.78 2015-09-09 14:53:00,11.28 2015-09-09 14:58:00,5.28 2015-09-09 15:03:00,11.11 2015-09-09 15:13:00,7.28 2015-09-09 15:18:00,10.44 2015-09-09 15:23:00,5.06 2015-09-09 15:28:00,9.28 2015-09-09 15:33:00,8.39 2015-09-09 15:48:00,9.5 2015-09-09 15:53:00,5.11 2015-09-09 16:08:00,8.67 2015-09-09 16:13:00,7.22 2015-09-09 16:18:00,6.67 2015-09-09 16:28:00,6.22 2015-09-09 16:33:00,7 2015-09-09 16:38:00,11.22 2015-09-09 16:43:00,6.89 2015-09-09 16:48:00,9.06 2015-09-09 16:53:00,6.61 2015-09-09 16:58:00,12.89 2015-09-09 17:08:00,6.94 2015-09-09 17:18:00,11.94 2015-09-09 17:23:00,12.17 2015-09-09 17:28:00,8.72 2015-09-09 17:33:00,12.11 2015-09-09 17:38:00,10.39 2015-09-09 17:43:00,5.11 2015-09-09 17:58:00,5.33 2015-09-09 18:03:00,8.72 2015-09-09 18:08:00,10.67 2015-09-09 18:23:00,6.17 2015-09-09 18:28:00,4.06 2015-09-09 18:33:00,7.28 2015-09-09 18:38:00,3.22 2015-09-09 18:48:00,7.94 2015-09-09 18:58:00,4.44 2015-09-09 19:03:00,5.83 2015-09-09 19:08:00,4.83 2015-09-09 19:13:00,6.39 2015-09-09 19:18:00,10.33 2015-09-09 19:23:00,4.56 2015-09-09 19:28:00,3.06 2015-09-09 19:33:00,6.06 2015-09-09 19:43:00,3.28 2015-09-09 19:48:00,1.67 2015-09-09 19:58:00,5.56 2015-09-09 20:23:00,1.33 2015-09-09 20:28:00,2.56 2015-09-09 20:33:00,6.5 2015-09-09 20:38:00,0.89 2015-09-09 20:43:00,13.17 2015-09-09 20:48:00,4.83 2015-09-09 20:58:00,3.94 2015-09-09 21:03:00,3.78 2015-09-09 21:13:00,2.44 2015-09-09 21:18:00,6 2015-09-09 21:28:00,6.89 2015-09-09 21:43:00,2.33 2015-09-09 21:48:00,4.17 2015-09-09 21:53:00,0.56 2015-09-09 21:58:00,12.89 2015-09-09 22:03:00,5.22 2015-09-09 22:08:00,3.33 2015-09-09 22:13:00,0.78 2015-09-09 22:23:00,2.56 2015-09-09 22:28:00,0.94 2015-09-09 22:46:00,2.17 2015-09-09 23:18:00,2.06 2015-09-09 23:23:00,3.44 2015-09-09 23:28:00,5.06 2015-09-09 23:33:00,0.67 2015-09-09 23:38:00,0.67 2015-09-09 23:48:00,3.06 2015-09-10 00:03:00,2.61 2015-09-10 00:13:00,3.06 2015-09-10 00:18:00,2.11 2015-09-10 00:23:00,1.61 2015-09-10 01:48:00,0.94 2015-09-10 01:53:00,0.72 2015-09-10 02:08:00,5.11 2015-09-10 02:53:00,0.78 2015-09-10 03:22:00,0.72 2015-09-10 03:52:00,2.67 2015-09-10 04:34:00,1.06 2015-09-10 05:28:00,6.06 2015-09-10 05:33:00,2.56 2015-09-10 05:33:00,8.94 2015-09-10 05:38:00,5.61 2015-09-10 05:45:00,11.89 2015-09-10 08:00:00,14.67 2015-09-10 08:13:00,12.94 2015-09-10 08:18:00,12.83 2015-09-10 08:23:00,14.22 2015-09-10 08:28:00,13 2015-09-10 08:38:00,8.11 2015-09-10 08:43:00,17.78 2015-09-10 08:48:00,14.11 2015-09-10 08:53:00,11.22 2015-09-10 08:58:00,10.67 2015-09-10 09:03:00,6.83 2015-09-10 09:13:00,14.39 2015-09-10 09:18:00,6.83 2015-09-10 09:23:00,15.94 2015-09-10 09:28:00,10.22 2015-09-10 09:33:00,14.78 2015-09-10 09:38:00,10.33 2015-09-10 09:43:00,3.67 2015-09-10 09:48:00,6.83 2015-09-10 09:52:00,6.5 2015-09-10 09:57:00,3.44 2015-09-10 10:02:00,3.22 2015-09-10 10:07:00,11.28 2015-09-10 10:12:00,7.28 2015-09-10 10:17:00,7.44 2015-09-10 10:27:00,8.5 2015-09-10 10:32:00,9.28 2015-09-10 10:37:00,9.78 2015-09-10 10:42:00,9.61 2015-09-10 10:47:00,7.61 2015-09-10 10:52:00,11.11 2015-09-10 10:57:00,8.83 2015-09-10 11:02:00,10.94 2015-09-10 11:07:00,9.78 2015-09-10 11:12:00,8.44 2015-09-10 11:17:00,7 2015-09-10 11:22:00,10.94 2015-09-10 11:27:00,12.94 2015-09-10 11:32:00,6.78 2015-09-10 11:37:00,10.61 2015-09-10 11:42:00,11.28 2015-09-10 11:47:00,10.61 2015-09-10 11:52:00,7.17 2015-09-10 11:57:00,12.5 2015-09-10 12:02:00,8.5 2015-09-10 12:12:00,9.06 2015-09-10 12:17:00,9.5 2015-09-10 12:32:00,11.11 2015-09-10 12:37:00,3.28 2015-09-10 12:47:00,5.94 2015-09-10 12:52:00,12.06 2015-09-10 12:57:00,7.06 2015-09-10 13:02:00,9.83 2015-09-10 13:07:00,8.17 2015-09-10 13:12:00,4.5 2015-09-10 13:17:00,8.11 2015-09-10 13:22:00,10.78 2015-09-10 13:32:00,8.61 2015-09-10 13:37:00,8.67 2015-09-10 13:47:00,9 2015-09-10 13:52:00,14.72 2015-09-10 13:57:00,6.17 2015-09-10 14:02:00,3.5 2015-09-10 14:07:00,10.17 2015-09-10 14:12:00,11.67 2015-09-10 14:17:00,8.67 2015-09-10 14:27:00,13.44 2015-09-10 14:32:00,8.89 2015-09-10 14:37:00,9.83 2015-09-10 14:47:00,8.94 2015-09-10 14:52:00,4.17 2015-09-10 14:57:00,8.67 2015-09-10 15:02:00,4 2015-09-10 15:07:00,9.78 2015-09-10 15:17:00,9.61 2015-09-10 15:22:00,9.83 2015-09-10 15:27:00,5.56 2015-09-10 15:32:00,9.94 2015-09-10 15:37:00,12.89 2015-09-10 15:42:00,6.33 2015-09-10 15:52:00,4.72 2015-09-10 15:57:00,9.06 2015-09-10 16:02:00,11.56 2015-09-10 16:12:00,10 2015-09-10 16:17:00,4.61 2015-09-10 16:22:00,6.67 2015-09-10 16:27:00,17.22 2015-09-10 16:32:00,11.44 2015-09-10 16:37:00,8.56 2015-09-10 16:42:00,9.17 2015-09-10 16:52:00,6.72 2015-09-10 16:57:00,9.78 2015-09-10 17:02:00,9.28 2015-09-10 17:07:00,9.28 2015-09-10 17:12:00,11.72 2015-09-10 17:17:00,10.33 2015-09-10 17:22:00,8.89 2015-09-10 17:27:00,10.78 2015-09-10 17:32:00,7.61 2015-09-10 17:37:00,10.28 2015-09-10 17:47:00,6.61 2015-09-10 17:52:00,3.78 2015-09-10 17:57:00,10.78 2015-09-10 18:02:00,2.83 2015-09-10 18:07:00,5.28 2015-09-10 18:12:00,8.44 2015-09-10 18:22:00,6.5 2015-09-10 18:27:00,7.44 2015-09-10 18:32:00,13.44 2015-09-10 18:37:00,6.39 2015-09-10 18:42:00,7.28 2015-09-10 18:57:00,7.17 2015-09-10 19:02:00,4.78 2015-09-10 19:07:00,3 2015-09-10 19:12:00,3.89 2015-09-10 19:17:00,3.06 2015-09-10 19:22:00,3.56 2015-09-10 19:27:00,4.94 2015-09-10 19:32:00,6.33 2015-09-10 19:37:00,4.72 2015-09-10 19:42:00,8.56 2015-09-10 19:47:00,6.17 2015-09-10 19:52:00,3.89 2015-09-10 19:57:00,4.67 2015-09-10 20:02:00,1.33 2015-09-10 20:07:00,6.44 2015-09-10 20:12:00,6.44 2015-09-10 20:17:00,5.39 2015-09-10 20:22:00,10.22 2015-09-10 20:28:00,4.67 2015-09-10 20:32:00,1.28 2015-09-10 20:38:00,4.67 2015-09-10 20:52:00,4.89 2015-09-10 20:57:00,1.67 2015-09-10 21:07:00,3.17 2015-09-10 21:12:00,2 2015-09-10 21:17:00,2.56 2015-09-10 21:22:00,3.28 2015-09-10 21:37:00,5.22 2015-09-10 21:47:00,5.39 2015-09-10 21:52:00,4.78 2015-09-10 22:12:00,7.11 2015-09-10 22:27:00,1.67 2015-09-10 22:32:00,2.17 2015-09-10 22:52:00,2.22 2015-09-10 23:17:00,0.89 2015-09-10 23:22:00,2.72 2015-09-10 23:32:00,5.17 2015-09-10 23:37:00,0.78 2015-09-11 00:02:00,3 2015-09-11 00:27:00,2.39 2015-09-11 00:32:00,0.94 2015-09-11 00:37:00,3.33 2015-09-11 00:52:00,2.5 2015-09-11 00:57:00,3.78 2015-09-11 01:12:00,0.22 2015-09-11 01:57:00,3.11 2015-09-11 02:17:00,0.72 2015-09-11 03:32:00,1 2015-09-11 03:42:00,4.67 2015-09-11 03:47:00,0.72 2015-09-11 03:57:00,3.89 2015-09-11 04:32:00,1.56 2015-09-11 04:47:00,2.22 2015-09-11 04:52:00,2.44 2015-09-11 04:57:00,1.5 2015-09-11 05:02:00,8.94 2015-09-11 05:07:00,3.56 2015-09-11 05:12:00,8.28 2015-09-11 05:17:00,8.17 2015-09-11 05:27:00,4.22 2015-09-11 05:32:00,7.94 2015-09-11 05:37:00,6.28 2015-09-11 05:47:00,3 2015-09-11 05:52:00,8.56 2015-09-11 05:57:00,5.06 2015-09-11 06:02:00,5.06 2015-09-11 06:07:00,9.56 2015-09-11 06:12:00,6.44 2015-09-11 06:17:00,4.61 2015-09-11 06:22:00,13.94 2015-09-11 06:27:00,13.06 2015-09-11 06:37:00,7.5 2015-09-11 06:42:00,10.72 2015-09-11 06:47:00,8.11 2015-09-11 06:52:00,7.22 2015-09-11 06:57:00,6.61 2015-09-11 07:02:00,7.94 2015-09-11 07:07:00,11.11 2015-09-11 07:12:00,13.78 2015-09-11 07:17:00,9.44 2015-09-11 07:27:00,9.28 2015-09-11 07:32:00,9.33 2015-09-11 07:37:00,11.28 2015-09-11 07:42:00,12.28 2015-09-11 07:52:00,15.28 2015-09-11 07:57:00,3.56 2015-09-11 08:02:00,8.11 2015-09-11 08:07:00,9.28 2015-09-11 08:12:00,10.28 2015-09-11 08:17:00,9.06 2015-09-11 08:22:00,11.39 2015-09-11 08:27:00,8.06 2015-09-11 08:32:00,12.78 2015-09-11 08:37:00,13.44 2015-09-11 08:42:00,8 2015-09-11 08:57:00,11.56 2015-09-11 09:02:00,6.94 2015-09-11 09:07:00,4.28 2015-09-11 09:17:00,8.06 2015-09-11 09:22:00,10.61 2015-09-11 09:27:00,7.06 2015-09-11 09:32:00,8.39 2015-09-11 09:37:00,10.11 2015-09-11 09:47:00,4.5 2015-09-11 09:52:00,4.72 2015-09-11 09:57:00,13.89 2015-09-11 10:07:00,5.06 2015-09-11 10:12:00,15.06 2015-09-11 10:17:00,9.22 2015-09-11 10:22:00,10.11 2015-09-11 10:27:00,11.89 2015-09-11 10:29:00,7.22 2015-09-11 10:34:00,4.67 2015-09-11 10:39:00,11.94 2015-09-11 10:44:00,6.56 2015-09-11 10:49:00,5.44 2015-09-11 10:59:00,7.72 2015-09-11 11:09:00,2.72 2015-09-11 11:14:00,7.5 2015-09-11 11:19:00,12.72 2015-09-11 11:24:00,4.78 2015-09-11 11:29:00,10.22 2015-09-11 11:34:00,9.17 2015-09-11 11:39:00,7.89 2015-09-11 11:44:00,17.11 2015-09-11 11:49:00,17.06 2015-09-11 11:54:00,10.33 2015-09-11 11:59:00,10.5 2015-09-11 12:04:00,10.67 2015-09-11 12:09:00,11 2015-09-11 12:14:00,9.33 2015-09-11 12:24:00,11.28 2015-09-11 12:34:00,5.5 2015-09-11 12:39:00,11.94 2015-09-11 12:44:00,9.67 2015-09-11 12:54:00,10.83 2015-09-11 12:59:00,10.67 2015-09-11 13:04:00,2.56 2015-09-11 13:09:00,8.5 2015-09-11 13:14:00,11 2015-09-11 13:24:00,11.72 2015-09-11 13:29:00,11.06 2015-09-11 13:34:00,4.83 2015-09-11 13:39:00,10.83 2015-09-11 13:44:00,6.56 2015-09-11 13:49:00,4.89 2015-09-11 13:54:00,8.78 2015-09-11 13:59:00,2.94 2015-09-11 14:04:00,4.33 2015-09-11 14:09:00,9.5 2015-09-11 14:14:00,16.94 2015-09-11 14:24:00,10.89 2015-09-11 14:29:00,8.17 2015-09-11 14:34:00,4.11 2015-09-11 14:39:00,9.94 2015-09-11 14:44:00,7.33 2015-09-11 14:54:00,11 2015-09-11 14:59:00,7.22 2015-09-11 15:04:00,6 2015-09-11 15:09:00,8.39 2015-09-11 15:14:00,7.67 2015-09-11 15:19:00,10.56 2015-09-11 15:24:00,5.94 2015-09-11 15:29:00,6.33 2015-09-11 15:34:00,6.72 2015-09-11 15:39:00,12.28 2015-09-11 15:44:00,7 2015-09-11 15:49:00,9.28 2015-09-11 15:54:00,8 2015-09-11 16:09:00,4.67 2015-09-11 16:19:00,10 2015-09-11 16:24:00,9.61 2015-09-11 16:29:00,10.28 2015-09-11 16:34:00,8.5 2015-09-11 16:44:00,7.89 2015-09-11 16:49:00,10.06 2015-09-11 16:59:00,11.89 2015-09-11 17:04:00,7.94 2015-09-11 17:09:00,12.72 2015-09-11 17:14:00,11.56 2015-09-11 17:19:00,8.11 2015-09-11 17:24:00,10.72 2015-09-11 17:29:00,4.11 2015-09-11 17:34:00,6.39 2015-09-11 17:39:00,8.94 2015-09-11 17:44:00,9.56 2015-09-11 17:49:00,10.06 2015-09-11 17:54:00,11.44 2015-09-11 17:59:00,5.56 2015-09-11 18:04:00,4.44 2015-09-11 18:16:00,6.06 2015-09-11 18:21:00,13.5 2015-09-11 18:26:00,3.89 2015-09-11 18:36:00,7.94 2015-09-11 18:41:00,7.94 2015-09-11 18:46:00,7.56 2015-09-11 18:51:00,4.22 2015-09-11 18:56:00,6.94 2015-09-11 19:01:00,5.89 2015-09-11 19:11:00,3.67 2015-09-11 19:16:00,8.33 2015-09-11 19:21:00,5.83 2015-09-11 19:26:00,5.33 2015-09-11 19:31:00,6.78 2015-09-11 19:41:00,6.33 2015-09-11 19:46:00,7.11 2015-09-11 19:51:00,0.89 2015-09-11 19:56:00,5.17 2015-09-11 20:01:00,1.5 2015-09-11 20:16:00,5.44 2015-09-11 20:21:00,3.39 2015-09-11 20:26:00,6.94 2015-09-11 20:31:00,5.44 2015-09-11 20:46:00,5.78 2015-09-11 20:51:00,2.61 2015-09-11 21:01:00,2.56 2015-09-11 21:21:00,4.61 2015-09-11 21:36:00,5.72 2015-09-11 21:41:00,5.56 2015-09-11 21:46:00,5.94 2015-09-11 21:51:00,5.28 2015-09-11 22:06:00,3.94 2015-09-11 22:11:00,2.89 2015-09-11 22:16:00,5.06 2015-09-11 22:21:00,3.17 2015-09-11 22:31:00,6.78 2015-09-11 22:41:00,1.78 2015-09-11 22:46:00,5.5 2015-09-11 22:51:00,2.94 2015-09-11 23:01:00,6.5 2015-09-11 23:06:00,1 2015-09-11 23:11:00,3.11 2015-09-11 23:16:00,0.78 2015-09-12 00:06:00,5.56 2015-09-12 00:11:00,2.22 2015-09-12 00:16:00,3.44 2015-09-12 00:31:00,1.83 2015-09-12 00:36:00,0.56 2015-09-12 00:46:00,3.78 2015-09-12 01:11:00,0.72 2015-09-12 01:16:00,3.39 2015-09-12 01:21:00,1.78 2015-09-12 01:36:00,4.22 2015-09-12 01:41:00,1.44 2015-09-12 02:21:00,1.06 2015-09-12 02:36:00,1 2015-09-12 02:46:00,0.89 2015-09-12 03:26:00,1.39 2015-09-12 03:36:00,0.67 2015-09-12 03:51:00,4.67 2015-09-12 04:01:00,1.56 2015-09-12 04:41:00,1.78 2015-09-12 04:56:00,2.28 2015-09-12 05:31:00,0.67 2015-09-12 05:36:00,2.28 2015-09-12 05:41:00,1.72 2015-09-12 05:46:00,6.94 2015-09-12 05:51:00,0.67 2015-09-12 05:56:00,1.5 2015-09-12 06:01:00,3.61 2015-09-12 06:06:00,1.89 2015-09-12 06:11:00,2.72 2015-09-12 06:16:00,1.33 2015-09-12 06:21:00,0.83 2015-09-12 06:26:00,1.78 2015-09-12 06:31:00,0.78 2015-09-12 06:41:00,6.83 2015-09-12 06:46:00,1.72 2015-09-12 06:51:00,2.11 2015-09-12 07:01:00,2.78 2015-09-12 07:06:00,0.56 2015-09-12 07:11:00,1.67 2015-09-12 07:16:00,4.28 2015-09-12 07:26:00,5.67 2015-09-12 07:46:00,5.78 2015-09-12 07:51:00,5.33 2015-09-12 07:56:00,6.33 2015-09-12 08:06:00,2.11 2015-09-12 08:11:00,3.06 2015-09-12 08:16:00,7.33 2015-09-12 08:21:00,4.89 2015-09-12 08:31:00,3.33 2015-09-12 08:41:00,9.44 2015-09-12 08:51:00,3.22 2015-09-12 08:56:00,7 2015-09-12 09:01:00,2.28 2015-09-12 09:06:00,7.39 2015-09-12 09:11:00,9 2015-09-12 09:16:00,6.44 2015-09-12 09:21:00,4.22 2015-09-12 09:26:00,3 2015-09-12 09:31:00,8.72 2015-09-12 09:36:00,3.28 2015-09-12 09:41:00,6 2015-09-12 09:51:00,6.78 2015-09-12 09:56:00,6.28 2015-09-12 10:01:00,7.83 2015-09-12 10:06:00,5.94 2015-09-12 10:11:00,9.39 2015-09-12 10:16:00,6.83 2015-09-12 10:21:00,5.56 2015-09-12 10:26:00,8.67 2015-09-12 10:31:00,5.83 2015-09-12 10:36:00,6.11 2015-09-12 10:41:00,5.61 2015-09-12 10:46:00,11.33 2015-09-12 10:51:00,5 2015-09-12 10:56:00,8.72 2015-09-12 11:06:00,4.44 2015-09-12 11:11:00,7.44 2015-09-12 11:26:00,8.17 2015-09-12 11:31:00,6.28 2015-09-12 11:36:00,4.33 2015-09-12 11:41:00,7.94 2015-09-12 11:46:00,10.83 2015-09-12 11:51:00,8.94 2015-09-12 11:56:00,5.44 2015-09-12 12:01:00,12.83 2015-09-12 12:06:00,15.17 2015-09-12 12:11:00,7.56 2015-09-12 12:16:00,8.06 2015-09-12 12:21:00,8.33 2015-09-12 12:26:00,8.06 2015-09-12 12:31:00,5.22 2015-09-12 12:36:00,10.44 2015-09-12 12:46:00,7.22 2015-09-12 12:51:00,5.39 2015-09-12 12:56:00,5.56 2015-09-12 13:06:00,5.28 2015-09-12 13:11:00,5.78 2015-09-12 13:16:00,5.78 2015-09-12 13:21:00,6.94 2015-09-12 13:26:00,3.89 2015-09-12 13:31:00,4.89 2015-09-12 13:36:00,4.28 2015-09-12 13:41:00,7.33 2015-09-12 13:46:00,7 2015-09-12 13:51:00,9.06 2015-09-12 14:06:00,8.94 2015-09-12 14:11:00,5.33 2015-09-12 14:16:00,9.56 2015-09-12 14:21:00,4.17 2015-09-12 14:26:00,4.78 2015-09-12 14:31:00,9.72 2015-09-12 14:36:00,8.89 2015-09-12 14:41:00,3.89 2015-09-12 14:51:00,8.17 2015-09-12 14:56:00,12.33 2015-09-12 15:01:00,8 2015-09-12 15:06:00,6.33 2015-09-12 15:11:00,2.72 2015-09-12 15:16:00,7.56 2015-09-12 15:21:00,7.83 2015-09-12 15:36:00,7.94 2015-09-12 15:46:00,8.44 2015-09-12 15:51:00,9.44 2015-09-12 16:01:00,2.78 2015-09-12 16:06:00,3.94 2015-09-12 16:11:00,8.17 2015-09-12 16:16:00,2.17 2015-09-12 16:21:00,5.61 2015-09-12 16:26:00,5.06 2015-09-12 16:31:00,5.28 2015-09-12 16:36:00,10.83 2015-09-12 16:41:00,9.94 2015-09-12 16:46:00,9.5 2015-09-12 16:51:00,11.78 2015-09-12 16:56:00,3.39 2015-09-12 17:01:00,3.17 2015-09-12 17:06:00,6.44 2015-09-12 17:11:00,4 2015-09-12 17:16:00,5.72 2015-09-12 17:21:00,5.83 2015-09-12 17:26:00,6.61 2015-09-12 17:31:00,9.33 2015-09-12 17:36:00,10.06 2015-09-12 17:41:00,7.39 2015-09-12 17:46:00,7.78 2015-09-12 17:51:00,5.94 2015-09-12 17:56:00,2.44 2015-09-12 18:01:00,9.39 2015-09-12 18:06:00,5 2015-09-12 18:11:00,6 2015-09-12 18:16:00,5.5 2015-09-12 18:21:00,5.78 2015-09-12 18:26:00,5.72 2015-09-12 18:31:00,5.61 2015-09-12 18:46:00,3.17 2015-09-12 18:56:00,2.94 2015-09-12 19:01:00,6.11 2015-09-12 19:11:00,5.17 2015-09-12 19:21:00,5.17 2015-09-12 19:31:00,3.44 2015-09-12 19:36:00,5.44 2015-09-12 19:41:00,2.11 2015-09-12 19:46:00,4.56 2015-09-12 19:51:00,4.06 2015-09-12 20:01:00,3.5 2015-09-12 20:11:00,3.33 2015-09-12 20:21:00,3.22 2015-09-12 20:26:00,3.5 2015-09-12 20:31:00,1.39 2015-09-12 20:36:00,3.17 2015-09-12 20:41:00,4.72 2015-09-12 20:46:00,3.33 2015-09-12 20:51:00,4.5 2015-09-12 21:01:00,2.5 2015-09-12 21:06:00,3.28 2015-09-12 21:16:00,5.11 2015-09-12 21:21:00,4.28 2015-09-12 21:26:00,3.83 2015-09-12 21:36:00,3.44 2015-09-12 21:41:00,6.33 2015-09-12 21:46:00,1.67 2015-09-12 21:51:00,5.44 2015-09-12 21:56:00,2.61 2015-09-12 22:01:00,3.83 2015-09-12 22:06:00,3.44 2015-09-12 22:16:00,3.33 2015-09-12 22:26:00,4.56 2015-09-12 22:36:00,0.67 2015-09-12 22:41:00,4.33 2015-09-12 22:46:00,2.5 2015-09-12 22:51:00,1.94 2015-09-12 22:56:00,4.06 2015-09-12 23:01:00,5.17 2015-09-12 23:06:00,2 2015-09-12 23:16:00,1.78 2015-09-12 23:21:00,3.06 2015-09-12 23:31:00,0.67 2015-09-12 23:41:00,1.56 2015-09-12 23:46:00,4.39 2015-09-12 23:51:00,4.17 2015-09-12 23:56:00,1.67 2015-09-13 00:01:00,1.39 2015-09-13 00:11:00,3.61 2015-09-13 00:16:00,0.83 2015-09-13 00:26:00,2.56 2015-09-13 00:31:00,1.5 2015-09-13 00:56:00,0.89 2015-09-13 01:31:00,0.78 2015-09-13 01:41:00,0.83 2015-09-13 02:01:00,1 2015-09-13 02:06:00,0.83 2015-09-13 02:11:00,0.78 2015-09-13 02:56:00,2 2015-09-13 03:01:00,1.61 2015-09-13 03:11:00,0.78 2015-09-13 05:06:00,2.5 2015-09-13 05:11:00,0.06 2015-09-13 05:26:00,1.89 2015-09-13 05:56:00,2.67 2015-09-13 06:01:00,3.83 2015-09-13 06:06:00,1.56 2015-09-13 06:21:00,1.89 2015-09-13 06:26:00,1.61 2015-09-13 06:31:00,1.17 2015-09-13 06:36:00,0.72 2015-09-13 06:46:00,3.56 2015-09-13 06:51:00,1.72 2015-09-13 06:56:00,2.44 2015-09-13 07:01:00,0.89 2015-09-13 07:11:00,3.39 2015-09-13 07:16:00,1.44 2015-09-13 07:21:00,2.28 2015-09-13 07:26:00,1.61 2015-09-13 07:31:00,6.11 2015-09-13 07:36:00,4.28 2015-09-13 07:46:00,3.67 2015-09-13 07:56:00,3.89 2015-09-13 08:01:00,2.39 2015-09-13 08:06:00,3.11 2015-09-13 08:16:00,1.56 2015-09-13 08:31:00,5.72 2015-09-13 08:36:00,3.78 2015-09-13 08:41:00,3.06 2015-09-13 08:46:00,4.17 2015-09-13 08:51:00,4.83 2015-09-13 08:56:00,5 2015-09-13 09:01:00,6.44 2015-09-13 09:06:00,4.5 2015-09-13 09:11:00,4.67 2015-09-13 09:16:00,3.67 2015-09-13 09:26:00,7.67 2015-09-13 09:31:00,6.33 2015-09-13 09:36:00,6.78 2015-09-13 09:41:00,2.28 2015-09-13 09:46:00,2.83 2015-09-13 09:51:00,5.94 2015-09-13 09:56:00,5 2015-09-13 10:06:00,3.94 2015-09-13 10:11:00,5.5 2015-09-13 10:16:00,4 2015-09-13 10:31:00,8.22 2015-09-13 10:36:00,6.61 2015-09-13 10:41:00,6.89 2015-09-13 10:46:00,4.94 2015-09-13 10:51:00,8.78 2015-09-13 10:56:00,2.94 2015-09-13 11:06:00,4.5 2015-09-13 11:11:00,11.06 2015-09-13 11:16:00,7.83 2015-09-13 11:21:00,7.72 2015-09-13 11:31:00,4.06 2015-09-13 11:36:00,10.44 2015-09-13 11:41:00,0.83 2015-09-13 11:46:00,14.22 2015-09-13 11:51:00,7.39 2015-09-13 11:56:00,6.39 2015-09-13 12:01:00,9.39 2015-09-13 12:06:00,6.5 2015-09-13 12:11:00,7.89 2015-09-13 12:16:00,8.22 2015-09-13 12:21:00,9.67 2015-09-13 12:26:00,9.22 2015-09-13 12:31:00,6.83 2015-09-13 12:41:00,9.61 2015-09-13 12:46:00,4.56 2015-09-13 12:48:00,9.11 2015-09-13 12:53:00,6.89 2015-09-13 12:58:00,6.56 2015-09-13 13:03:00,8.61 2015-09-13 13:08:00,5.39 2015-09-13 13:13:00,8.39 2015-09-13 13:18:00,4.28 2015-09-13 13:23:00,7.83 2015-09-13 13:28:00,5.44 2015-09-13 13:33:00,4.67 2015-09-13 13:43:00,6.06 2015-09-13 13:48:00,5.11 2015-09-13 13:53:00,6.06 2015-09-13 13:58:00,8.33 2015-09-13 14:03:00,5.28 2015-09-13 14:13:00,8.39 2015-09-13 14:18:00,10.17 2015-09-13 14:23:00,3 2015-09-13 14:28:00,8.39 2015-09-13 14:38:00,6.39 2015-09-13 14:43:00,10.17 2015-09-13 14:48:00,6.56 2015-09-13 14:58:00,9.11 2015-09-13 15:03:00,9.89 2015-09-13 15:08:00,5.89 2015-09-13 15:13:00,4.44 2015-09-13 15:18:00,7 2015-09-13 15:23:00,6.83 2015-09-13 15:28:00,4.06 2015-09-13 15:33:00,6.39 2015-09-13 15:38:00,8.94 2015-09-13 15:48:00,9.33 2015-09-13 15:53:00,10.33 2015-09-13 15:58:00,5.44 2015-09-13 16:03:00,3.06 2015-09-13 16:08:00,6.06 2015-09-13 16:13:00,9.72 2015-09-13 16:18:00,9.17 2015-09-13 16:23:00,8.39 2015-09-13 16:28:00,6.67 2015-09-13 16:33:00,3.67 2015-09-13 16:38:00,9.67 2015-09-13 16:43:00,7.33 2015-09-13 17:03:00,4.94 2015-09-13 17:08:00,5.33 2015-09-13 17:13:00,9.17 2015-09-13 17:18:00,2.78 2015-09-13 17:23:00,4.28 2015-09-13 17:28:00,10.39 2015-09-13 17:33:00,2.39 2015-09-13 17:38:00,11.17 2015-09-13 17:48:00,6.67 2015-09-13 17:53:00,6.28 2015-09-13 17:58:00,5.94 2015-09-13 18:08:00,5.83 2015-09-13 18:13:00,6 2015-09-13 18:18:00,8.33 2015-09-13 18:23:00,5.39 2015-09-13 18:28:00,10.17 2015-09-13 18:33:00,6.67 2015-09-13 18:38:00,5.78 2015-09-13 18:48:00,9.72 2015-09-13 18:53:00,1.67 2015-09-13 18:58:00,7.78 2015-09-13 19:03:00,6.83 2015-09-13 19:08:00,2 2015-09-13 19:18:00,3.83 2015-09-13 19:23:00,4.83 2015-09-13 19:28:00,4.56 2015-09-13 19:33:00,4.44 2015-09-13 19:38:00,6.61 2015-09-13 19:48:00,6.89 2015-09-13 19:53:00,5.89 2015-09-13 19:58:00,7 2015-09-13 20:08:00,7.94 2015-09-13 20:13:00,4.72 2015-09-13 20:18:00,3.22 2015-09-13 20:23:00,3 2015-09-13 20:28:00,2.44 2015-09-13 20:33:00,1.89 2015-09-13 20:43:00,3.67 2015-09-13 20:53:00,7.61 2015-09-13 21:03:00,2.22 2015-09-13 21:18:00,3.39 2015-09-13 21:23:00,3.33 2015-09-13 21:28:00,2.33 2015-09-13 21:33:00,0.83 2015-09-13 21:38:00,4.28 2015-09-13 21:43:00,6.28 2015-09-13 21:48:00,4.11 2015-09-13 22:08:00,2.5 2015-09-13 22:13:00,2.94 2015-09-13 22:18:00,2.39 2015-09-13 22:33:00,0.89 2015-09-13 22:38:00,1.89 2015-09-13 22:48:00,0.94 2015-09-13 22:53:00,0.61 2015-09-13 22:58:00,2.33 2015-09-13 23:08:00,1.83 2015-09-13 23:28:00,1.44 2015-09-13 23:38:00,4.61 2015-09-13 23:43:00,1.22 2015-09-13 23:48:00,1.78 2015-09-13 23:53:00,0.89 2015-09-14 00:18:00,0.94 2015-09-14 00:43:00,2.11 2015-09-14 00:53:00,1.61 2015-09-14 00:58:00,1.67 2015-09-14 01:08:00,1.78 2015-09-14 01:28:00,1.72 2015-09-14 02:03:00,3.61 2015-09-14 02:28:00,1.5 2015-09-14 02:43:00,5.22 2015-09-14 02:48:00,2.72 2015-09-14 02:58:00,3.78 2015-09-14 03:08:00,0.78 2015-09-14 03:13:00,1.5 2015-09-14 03:23:00,0.89 2015-09-14 03:48:00,0.83 2015-09-14 04:13:00,0.89 2015-09-14 04:23:00,0.94 2015-09-14 04:28:00,2.44 2015-09-14 04:43:00,2.56 2015-09-14 04:48:00,2.5 2015-09-14 04:53:00,1.39 2015-09-14 04:58:00,3.39 2015-09-14 05:03:00,4 2015-09-14 05:08:00,1.94 2015-09-14 05:18:00,4.33 2015-09-14 05:23:00,3.56 2015-09-14 05:28:00,2.28 2015-09-14 05:33:00,6.11 2015-09-14 05:38:00,4.72 2015-09-14 05:43:00,2.39 2015-09-14 05:48:00,5.22 2015-09-14 05:53:00,3.67 2015-09-14 05:58:00,3.11 2015-09-14 06:03:00,8 2015-09-14 06:08:00,6.06 2015-09-14 06:13:00,8.61 2015-09-14 06:18:00,4.06 2015-09-14 06:23:00,10.39 2015-09-14 06:28:00,13.39 2015-09-14 06:33:00,4.89 2015-09-14 06:38:00,6.83 2015-09-14 06:43:00,8.39 2015-09-14 06:48:00,7.5 2015-09-14 06:53:00,11.17 2015-09-14 06:58:00,12.67 2015-09-14 07:03:00,14 2015-09-14 07:08:00,9.22 2015-09-14 07:13:00,6.78 2015-09-14 07:18:00,11.94 2015-09-14 07:23:00,10.67 2015-09-14 07:28:00,8.94 2015-09-14 07:33:00,10.94 2015-09-14 07:38:00,12.61 2015-09-14 07:43:00,6 2015-09-14 07:48:00,10.28 2015-09-14 07:53:00,6.28 2015-09-14 07:58:00,11.67 2015-09-14 08:03:00,10.5 2015-09-14 08:08:00,20.72 2015-09-14 08:13:00,18.61 2015-09-14 08:18:00,9.72 2015-09-14 08:23:00,12.11 2015-09-14 08:38:00,6.5 2015-09-14 08:43:00,10.78 2015-09-14 08:48:00,15.39 2015-09-14 08:53:00,11.94 2015-09-14 08:58:00,3.56 2015-09-14 09:03:00,3.94 2015-09-14 09:08:00,5.78 2015-09-14 09:13:00,10.17 2015-09-14 09:18:00,12.39 2015-09-14 09:23:00,9.94 2015-09-14 09:28:00,8.67 2015-09-14 09:33:00,14.28 2015-09-14 09:43:00,5.5 2015-09-14 09:48:00,11.78 2015-09-14 09:53:00,8.11 2015-09-14 09:58:00,13.11 2015-09-14 10:03:00,5.67 2015-09-14 10:08:00,9.67 2015-09-14 10:13:00,8.39 2015-09-14 10:18:00,5.56 2015-09-14 10:23:00,6.72 2015-09-14 10:28:00,9.22 2015-09-14 10:33:00,7.06 2015-09-14 10:38:00,10.33 2015-09-14 10:43:00,6.22 2015-09-14 10:48:00,11.28 2015-09-14 10:53:00,6.67 2015-09-14 10:58:00,10.56 2015-09-14 11:03:00,6.11 2015-09-14 11:08:00,8.78 2015-09-14 11:13:00,16.28 2015-09-14 11:18:00,13.89 2015-09-14 11:28:00,4.33 2015-09-14 11:33:00,8.17 2015-09-14 11:38:00,5.44 2015-09-14 11:43:00,6 2015-09-14 11:48:00,1.89 2015-09-14 11:53:00,13.44 2015-09-14 11:58:00,10.39 2015-09-14 12:03:00,8.39 2015-09-14 12:13:00,14.39 2015-09-14 12:18:00,8.39 2015-09-14 12:23:00,7.72 2015-09-14 12:28:00,7.44 2015-09-14 12:33:00,8.28 2015-09-14 12:43:00,8.22 2015-09-14 12:48:00,5.22 2015-09-14 12:53:00,11 2015-09-14 12:58:00,6.28 2015-09-14 13:03:00,8.67 2015-09-14 13:08:00,7.83 2015-09-14 13:13:00,9.89 2015-09-14 13:15:00,10.33 2015-09-14 13:20:00,8.11 2015-09-14 13:30:00,3.89 2015-09-14 13:35:00,7 2015-09-14 13:40:00,1.5 2015-09-14 13:45:00,4.78 2015-09-14 13:50:00,11.28 2015-09-14 13:55:00,5.78 2015-09-14 14:00:00,10.83 2015-09-14 14:05:00,12 2015-09-14 14:10:00,12.22 2015-09-14 14:15:00,7.94 2015-09-14 14:20:00,9.11 2015-09-14 14:25:00,9.67 2015-09-14 14:30:00,6.89 2015-09-14 14:35:00,5.17 2015-09-14 14:40:00,17.33 2015-09-14 14:45:00,2.67 2015-09-14 15:05:00,8.39 2015-09-14 15:10:00,9.89 2015-09-14 15:15:00,5.5 2015-09-14 15:20:00,8.17 2015-09-14 15:30:00,8.94 2015-09-14 15:35:00,8.28 2015-09-14 15:40:00,13.28 2015-09-14 15:45:00,12.56 2015-09-14 15:50:00,13.61 2015-09-14 15:55:00,4.22 2015-09-14 16:05:00,8.83 2015-09-14 16:10:00,6.39 2015-09-14 16:15:00,7.94 2015-09-14 16:20:00,11.06 2015-09-14 16:30:00,3.83 2015-09-14 16:35:00,7.89 2015-09-14 16:40:00,9 2015-09-14 16:45:00,7.5 2015-09-14 16:50:00,14.33 2015-09-14 16:55:00,11.5 2015-09-14 17:00:00,7.78 2015-09-14 17:05:00,11.56 2015-09-14 17:10:00,8.56 2015-09-14 17:15:00,9.17 2015-09-14 17:20:00,6.11 2015-09-14 17:25:00,4.89 2015-09-14 17:30:00,7.22 2015-09-14 17:35:00,4.83 2015-09-14 17:40:00,8.61 2015-09-14 17:45:00,12.28 2015-09-14 17:50:00,7.22 2015-09-14 17:55:00,6.56 2015-09-14 18:00:00,2.78 2015-09-14 18:05:00,5.33 2015-09-14 18:10:00,8.39 2015-09-14 18:20:00,7.83 2015-09-14 18:25:00,10.94 2015-09-14 18:30:00,2.72 2015-09-14 18:35:00,9.67 2015-09-14 18:40:00,7.94 2015-09-14 18:45:00,9.22 2015-09-14 18:50:00,3.44 2015-09-14 18:55:00,4.83 2015-09-14 19:01:00,6.83 2015-09-14 19:05:00,7.94 2015-09-14 19:10:00,8.83 2015-09-14 19:15:00,8.83 2015-09-14 19:20:00,6.56 2015-09-14 19:25:00,7.17 2015-09-14 19:30:00,2.5 2015-09-14 19:40:00,8.94 2015-09-14 19:45:00,7.56 2015-09-14 19:55:00,9.44 2015-09-14 20:00:00,5.61 2015-09-14 20:05:00,2.28 2015-09-14 20:10:00,9.78 2015-09-14 20:15:00,5.11 2015-09-14 20:20:00,3.67 2015-09-14 20:30:00,3.33 2015-09-14 20:35:00,5.5 2015-09-14 20:45:00,3.5 2015-09-14 20:50:00,5.56 2015-09-14 20:55:00,2.17 2015-09-14 21:05:00,1.61 2015-09-14 21:10:00,3.28 2015-09-14 21:15:00,6.5 2015-09-14 21:20:00,5.28 2015-09-14 21:30:00,2.33 2015-09-14 21:35:00,1.67 2015-09-14 21:40:00,8.89 2015-09-14 21:45:00,6.28 2015-09-14 21:55:00,1.72 2015-09-14 22:06:00,0.83 2015-09-14 22:11:00,6.61 2015-09-14 22:21:00,0.83 2015-09-14 22:25:00,1 2015-09-14 22:30:00,0.94 2015-09-14 22:35:00,3 2015-09-14 22:40:00,3.5 2015-09-14 23:01:00,2.39 2015-09-14 23:11:00,2.39 2015-09-14 23:15:00,1.56 2015-09-14 23:21:00,1.44 2015-09-14 23:41:00,2.83 2015-09-14 23:46:00,0.67 2015-09-14 23:51:00,1 2015-09-15 00:16:00,1.61 2015-09-15 00:56:00,0.78 2015-09-15 01:25:00,1 2015-09-15 01:30:00,0.61 2015-09-15 01:40:00,2.83 2015-09-15 02:01:00,1.61 2015-09-15 02:06:00,0.78 2015-09-15 02:56:00,3.61 2015-09-15 03:01:00,1.67 2015-09-15 03:25:00,2.78 2015-09-15 03:30:00,0.56 2015-09-15 03:35:00,1 2015-09-15 03:45:00,0.67 2015-09-15 03:55:00,1.56 2015-09-15 04:01:00,0.61 2015-09-15 04:06:00,3.5 2015-09-15 04:10:00,2.83 2015-09-15 04:16:00,0.78 2015-09-15 04:26:00,4.28 2015-09-15 04:31:00,0.83 2015-09-15 04:35:00,0.72 2015-09-15 04:41:00,5.06 2015-09-15 04:46:00,2.72 2015-09-15 04:55:00,3.06 2015-09-15 05:01:00,4.61 2015-09-15 05:05:00,5.33 2015-09-15 05:10:00,4.56 2015-09-15 05:15:00,4.56 2015-09-15 05:20:00,0.72 2015-09-15 05:26:00,5.67 2015-09-15 05:31:00,4.17 2015-09-15 05:36:00,5.28 2015-09-15 05:41:00,9.56 2015-09-15 05:46:00,1.33 2015-09-15 05:51:00,6.39 2015-09-15 05:55:00,3.72 2015-09-15 06:00:00,12.28 2015-09-15 06:10:00,10.33 2015-09-15 06:16:00,13.83 2015-09-15 06:20:00,8.78 2015-09-15 06:25:00,7.56 2015-09-15 06:30:00,9.33 2015-09-15 06:35:00,10.78 2015-09-15 06:41:00,9.83 2015-09-15 06:45:00,7.28 2015-09-15 06:50:00,10.17 2015-09-15 06:55:00,7.61 2015-09-15 07:00:00,12.11 2015-09-15 07:11:00,14.17 2015-09-15 07:16:00,10.28 2015-09-15 07:21:00,11.89 2015-09-15 07:26:00,9.17 2015-09-15 07:31:00,7.33 2015-09-15 07:36:00,11.5 2015-09-15 07:41:00,11.39 2015-09-15 07:46:00,7.89 2015-09-15 07:51:00,7.67 2015-09-15 07:56:00,9.06 2015-09-15 08:06:00,9.67 2015-09-15 08:11:00,9.78 2015-09-15 08:16:00,11.83 2015-09-15 08:21:00,12.44 2015-09-15 08:26:00,8.28 2015-09-15 08:31:00,12.61 2015-09-15 08:41:00,8.17 2015-09-15 08:46:00,5.22 2015-09-15 08:51:00,12.06 2015-09-15 08:56:00,14.61 2015-09-15 09:01:00,15 2015-09-15 09:06:00,8.72 2015-09-15 09:11:00,7.06 2015-09-15 09:16:00,10.22 2015-09-15 09:21:00,8.11 2015-09-15 09:26:00,11.44 2015-09-15 09:31:00,15.5 2015-09-15 09:36:00,7.44 2015-09-15 09:41:00,2.94 2015-09-15 09:46:00,12.17 2015-09-15 09:51:00,14.56 2015-09-15 09:56:00,2.94 2015-09-15 10:01:00,7.94 2015-09-15 10:06:00,7.44 2015-09-15 10:11:00,5 2015-09-15 10:16:00,6.89 2015-09-15 10:21:00,8.94 2015-09-15 10:26:00,8.83 2015-09-15 10:31:00,11.72 2015-09-15 10:36:00,11.83 2015-09-15 10:41:00,6.94 2015-09-15 10:46:00,6.78 2015-09-15 10:51:00,6.83 2015-09-15 10:56:00,11.56 2015-09-15 11:01:00,11.56 2015-09-15 11:06:00,12.11 2015-09-15 11:11:00,9 2015-09-15 11:16:00,6.94 2015-09-15 11:21:00,10 2015-09-15 11:26:00,5.39 2015-09-15 11:31:00,8.89 2015-09-15 11:36:00,5.94 2015-09-15 11:41:00,10.5 2015-09-15 11:46:00,5.83 2015-09-15 11:51:00,11.67 2015-09-15 11:56:00,4.22 2015-09-15 12:01:00,7.56 2015-09-15 12:06:00,6.83 2015-09-15 12:11:00,4.5 2015-09-15 12:21:00,13.28 2015-09-15 12:26:00,7.06 2015-09-15 12:31:00,3.67 2015-09-15 12:36:00,13.56 2015-09-15 12:41:00,9.67 2015-09-15 12:46:00,5.44 2015-09-15 12:51:00,5.33 2015-09-15 12:56:00,7.39 2015-09-15 13:01:00,9.5 2015-09-15 13:06:00,6.39 2015-09-15 13:11:00,14.11 2015-09-15 13:16:00,6.83 2015-09-15 13:21:00,7.94 2015-09-15 13:26:00,12.61 2015-09-15 13:31:00,8.78 2015-09-15 13:36:00,10.33 2015-09-15 13:41:00,8.06 2015-09-15 13:46:00,6.56 2015-09-15 13:51:00,7.33 2015-09-15 13:54:00,9.83 2015-09-15 13:59:00,8.17 2015-09-15 14:04:00,4.89 2015-09-15 14:09:00,9.28 2015-09-15 14:14:00,12.17 2015-09-15 14:19:00,7.06 2015-09-15 14:24:00,5.83 2015-09-15 14:29:00,9.11 2015-09-15 14:39:00,7 2015-09-15 14:44:00,12.78 2015-09-15 14:49:00,7.39 2015-09-15 14:54:00,6.06 2015-09-15 14:59:00,7.72 2015-09-15 15:04:00,10.83 2015-09-15 15:09:00,11.17 2015-09-15 15:14:00,11.39 2015-09-15 15:19:00,8.33 2015-09-15 15:24:00,11.56 2015-09-15 15:29:00,5.33 2015-09-15 15:34:00,7.89 2015-09-15 15:39:00,11.06 2015-09-15 15:44:00,8 2015-09-15 15:49:00,8.11 2015-09-15 15:54:00,8.83 2015-09-15 15:59:00,7.67 2015-09-15 16:04:00,9.94 2015-09-15 16:09:00,7.72 2015-09-15 16:14:00,5.94 2015-09-15 16:19:00,9.44 2015-09-15 16:24:00,4.06 2015-09-15 16:29:00,7.94 2015-09-15 16:34:00,10.78 2015-09-15 16:39:00,9.67 2015-09-15 16:44:00,8.5 2015-09-15 16:49:00,7.39 2015-09-15 16:54:00,9.72 2015-09-15 16:59:00,6.94 2015-09-15 17:04:00,8.22 2015-09-15 17:09:00,6.44 2015-09-15 17:14:00,11.22 2015-09-15 17:19:00,4.89 2015-09-15 17:24:00,6.56 2015-09-15 17:29:00,11.39 2015-09-15 17:39:00,7.5 2015-09-15 17:44:00,11.67 2015-09-15 17:49:00,13 2015-09-15 17:54:00,9.33 2015-09-15 17:59:00,7.83 2015-09-15 18:04:00,6.61 2015-09-15 18:09:00,3.06 2015-09-15 18:14:00,4.06 2015-09-15 18:19:00,10.56 2015-09-15 18:24:00,9.44 2015-09-15 18:34:00,12.56 2015-09-15 18:39:00,4.94 2015-09-15 18:44:00,5.33 2015-09-15 18:49:00,4.67 2015-09-15 18:54:00,6.56 2015-09-15 18:59:00,7.83 2015-09-15 19:04:00,4.61 2015-09-15 19:09:00,2.83 2015-09-15 19:14:00,3.5 2015-09-15 19:29:00,8.67 2015-09-15 19:34:00,1.83 2015-09-15 19:39:00,1.17 2015-09-15 19:44:00,3.67 2015-09-15 19:49:00,5.17 2015-09-15 19:54:00,7.06 2015-09-15 19:59:00,6.67 2015-09-15 20:09:00,5.72 2015-09-15 20:14:00,2.44 2015-09-15 20:19:00,7 2015-09-15 20:24:00,7.17 2015-09-15 20:29:00,4.06 2015-09-15 20:34:00,8.61 2015-09-15 20:39:00,3.17 2015-09-15 20:44:00,4.17 2015-09-15 20:49:00,5.94 2015-09-15 20:54:00,1.5 2015-09-15 20:59:00,7.5 2015-09-15 21:04:00,5.5 2015-09-15 21:09:00,1.56 2015-09-15 21:14:00,7.39 2015-09-15 21:19:00,2.33 2015-09-15 21:24:00,2.22 2015-09-15 21:29:00,2.89 2015-09-15 21:34:00,4.94 2015-09-15 21:39:00,11.94 2015-09-15 21:49:00,4.5 2015-09-15 21:54:00,6.17 2015-09-15 21:59:00,1.89 2015-09-15 22:04:00,5.67 2015-09-15 22:14:00,7.06 2015-09-15 22:19:00,3.11 2015-09-15 22:24:00,0.72 2015-09-15 22:29:00,3.61 2015-09-15 22:34:00,2.39 2015-09-15 22:39:00,3.28 2015-09-15 22:44:00,1.56 2015-09-15 22:59:00,2.28 2015-09-15 23:04:00,4.39 2015-09-15 23:14:00,1 2015-09-15 23:19:00,2.28 2015-09-15 23:24:00,0.44 2015-09-15 23:29:00,2.28 2015-09-15 23:34:00,7.28 2015-09-15 23:44:00,0.83 2015-09-16 00:04:00,1.44 2015-09-16 00:09:00,0.78 2015-09-16 00:19:00,0.72 2015-09-16 00:24:00,2.78 2015-09-16 00:34:00,4.28 2015-09-16 00:44:00,3.72 2015-09-16 00:59:00,0.78 2015-09-16 01:14:00,0.83 2015-09-16 01:19:00,1.06 2015-09-16 01:29:00,0.83 2015-09-16 01:39:00,0.94 2015-09-16 02:14:00,2.67 2015-09-16 02:34:00,3.44 2015-09-16 02:49:00,1.67 2015-09-16 03:04:00,1.89 2015-09-16 03:14:00,1.94 2015-09-16 03:19:00,0.78 2015-09-16 03:29:00,2.17 2015-09-16 03:34:00,1.33 2015-09-16 03:39:00,3.94 2015-09-16 03:49:00,2.39 2015-09-16 03:59:00,2.33 2015-09-16 04:04:00,3.67 2015-09-16 04:14:00,3.06 2015-09-16 04:24:00,2.28 2015-09-16 04:29:00,2.94 2015-09-16 04:39:00,3.33 2015-09-16 04:44:00,4.72 2015-09-16 04:49:00,3.44 2015-09-16 04:54:00,3.33 2015-09-16 04:59:00,4.06 2015-09-16 05:04:00,1.83 2015-09-16 05:09:00,4.33 2015-09-16 05:14:00,4.67 2015-09-16 05:19:00,5.89 2015-09-16 05:24:00,1.61 2015-09-16 05:29:00,4.39 2015-09-16 05:34:00,5.11 2015-09-16 05:39:00,8.72 2015-09-16 05:44:00,9.94 2015-09-16 05:49:00,4.78 2015-09-16 05:54:00,10.67 2015-09-16 05:59:00,9.11 2015-09-16 06:04:00,3.83 2015-09-16 06:09:00,8.28 2015-09-16 06:14:00,14.17 2015-09-16 06:19:00,11.61 2015-09-16 06:24:00,5.39 2015-09-16 06:29:00,7.11 2015-09-16 06:34:00,13.5 2015-09-16 06:39:00,9.67 2015-09-16 06:44:00,6.06 2015-09-16 06:49:00,9.56 2015-09-16 06:54:00,7.44 2015-09-16 06:59:00,10.44 2015-09-16 07:04:00,15.61 2015-09-16 07:09:00,11.89 2015-09-16 07:14:00,4.61 2015-09-16 07:19:00,8.56 2015-09-16 07:24:00,7.94 2015-09-16 07:29:00,11.22 2015-09-16 07:34:00,13.61 2015-09-16 07:39:00,7.67 2015-09-16 07:44:00,10.33 2015-09-16 07:49:00,11.94 2015-09-16 07:54:00,16.44 2015-09-16 07:59:00,32.17 2015-09-16 08:04:00,26 2015-09-16 08:09:00,38.83 2015-09-16 08:14:00,12.78 2015-09-16 08:19:00,38.28 2015-09-16 08:24:00,33.5 2015-09-16 08:29:00,22.5 2015-09-16 08:34:00,27.17 2015-09-16 08:39:00,29.94 2015-09-16 08:44:00,27.83 2015-09-16 08:49:00,7.78 2015-09-16 08:54:00,12.83 2015-09-16 08:59:00,15.28 2015-09-16 09:04:00,9.11 2015-09-16 09:09:00,9.22 2015-09-16 09:14:00,9.83 2015-09-16 09:19:00,8.44 2015-09-16 09:24:00,11.5 2015-09-16 09:29:00,8 2015-09-16 09:34:00,12.89 2015-09-16 09:39:00,4.56 2015-09-16 09:44:00,15.83 2015-09-16 09:49:00,9.61 2015-09-16 09:54:00,10.17 2015-09-16 09:59:00,12.22 2015-09-16 10:04:00,9.61 2015-09-16 10:09:00,9 2015-09-16 10:14:00,6.67 2015-09-16 10:19:00,3.94 2015-09-16 10:24:00,16.33 2015-09-16 10:29:00,10 2015-09-16 10:34:00,8.67 2015-09-16 10:39:00,11.06 2015-09-16 10:44:00,5.44 2015-09-16 10:49:00,6.61 2015-09-16 10:54:00,3.44 2015-09-16 10:59:00,7.44 2015-09-16 11:04:00,13.67 2015-09-16 11:09:00,5.56 2015-09-16 11:14:00,11.11 2015-09-16 11:19:00,8.11 2015-09-16 11:24:00,15.72 2015-09-16 11:29:00,8.61 2015-09-16 11:34:00,12.67 2015-09-16 11:39:00,13.06 2015-09-16 11:44:00,10.39 2015-09-16 11:49:00,7.5 2015-09-16 11:54:00,4.11 2015-09-16 11:59:00,5.5 2015-09-16 12:04:00,11.56 2015-09-16 12:09:00,3.83 2015-09-16 12:14:00,8.22 2015-09-16 12:19:00,6.5 2015-09-16 12:24:00,4.33 2015-09-16 12:29:00,7.72 2015-09-16 12:34:00,14 2015-09-16 12:39:00,5.11 2015-09-16 12:44:00,8.56 2015-09-16 12:49:00,6.39 2015-09-16 12:54:00,4 2015-09-16 12:59:00,2.56 2015-09-16 13:04:00,8.89 2015-09-16 13:09:00,6.11 2015-09-16 13:14:00,6.67 2015-09-16 13:19:00,10 2015-09-16 13:24:00,8.56 2015-09-16 13:29:00,5.22 2015-09-16 13:34:00,13.22 2015-09-16 13:39:00,8.94 2015-09-16 13:44:00,14.33 2015-09-16 13:49:00,7.56 2015-09-16 13:54:00,14.67 2015-09-16 13:59:00,5.61 2015-09-16 14:04:00,11.44 2015-09-16 14:09:00,9.44 2015-09-16 14:14:00,6.11 2015-09-16 14:19:00,8.22 2015-09-16 14:24:00,10.17 2015-09-16 14:29:00,8.83 2015-09-16 14:30:00,6.61 2015-09-16 14:35:00,6 2015-09-16 14:40:00,6.83 2015-09-16 14:45:00,10.78 2015-09-16 14:50:00,12.44 2015-09-16 14:55:00,9.83 2015-09-16 15:00:00,5.89 2015-09-16 15:05:00,5.78 2015-09-16 15:10:00,12.39 2015-09-16 15:15:00,9.11 2015-09-16 15:25:00,15.11 2015-09-16 15:30:00,16 2015-09-16 15:35:00,6.72 2015-09-16 15:40:00,11.06 2015-09-16 15:45:00,8.78 2015-09-16 15:50:00,12.56 2015-09-16 15:55:00,14.78 2015-09-16 16:00:00,2.78 2015-09-16 16:05:00,6.17 2015-09-16 16:10:00,8.89 2015-09-16 16:15:00,9.83 2015-09-16 16:20:00,8.67 2015-09-16 16:25:00,6.78 2015-09-16 16:30:00,5.11 2015-09-16 16:35:00,11.33 2015-09-16 16:40:00,8.33 2015-09-16 16:45:00,5.83 2015-09-16 16:50:00,6.11 2015-09-16 16:55:00,5.67 2015-09-16 17:00:00,19 2015-09-16 17:05:00,11.89 2015-09-16 17:10:00,5.39 2015-09-16 17:15:00,5.17 2015-09-16 17:20:00,10.78 2015-09-16 17:25:00,9.5 2015-09-16 17:30:00,11.28 2015-09-16 17:35:00,8.44 2015-09-16 17:40:00,10.94 2015-09-16 17:45:00,5.44 2015-09-16 17:50:00,7.44 2015-09-16 17:55:00,7 2015-09-16 18:00:00,8.17 2015-09-16 18:05:00,11.94 2015-09-16 18:10:00,11.06 2015-09-16 18:15:00,8.56 2015-09-16 18:20:00,9 2015-09-16 18:25:00,6.78 2015-09-16 18:30:00,5.11 2015-09-16 18:35:00,8.17 2015-09-16 18:40:00,3.94 2015-09-16 18:45:00,4.67 2015-09-16 18:50:00,8.72 2015-09-16 18:55:00,4.44 2015-09-16 19:00:00,4.72 2015-09-16 19:05:00,5.56 2015-09-16 19:10:00,7.5 2015-09-16 19:15:00,6.56 2015-09-16 19:20:00,5.72 2015-09-16 19:25:00,0.78 2015-09-16 19:30:00,4.44 2015-09-16 19:35:00,6.44 2015-09-16 19:40:00,4.06 2015-09-16 19:45:00,4.78 2015-09-16 19:50:00,5.72 2015-09-16 19:55:00,7.61 2015-09-16 20:00:00,4.33 2015-09-16 20:05:00,7.11 2015-09-16 20:10:00,3.11 2015-09-16 20:15:00,3.22 2015-09-16 20:20:00,4.44 2015-09-16 20:25:00,2.5 2015-09-16 20:30:00,7 2015-09-16 20:35:00,2.39 2015-09-16 20:40:00,1.56 2015-09-16 20:45:00,1.72 2015-09-16 20:50:00,2.11 2015-09-16 20:55:00,1.83 2015-09-16 21:00:00,2.61 2015-09-16 21:05:00,5.61 2015-09-16 21:10:00,6.67 2015-09-16 21:15:00,0.72 2015-09-16 21:20:00,0.72 2015-09-16 21:25:00,4.89 2015-09-16 21:30:00,3.06 2015-09-16 21:35:00,1.67 2015-09-16 21:40:00,1.5 2015-09-16 21:45:00,3.33 2015-09-16 21:50:00,4.11 2015-09-16 21:55:00,2.61 2015-09-16 22:05:00,5.11 2015-09-16 22:14:00,0.72 2015-09-16 22:20:00,2.67 2015-09-16 22:30:00,1.72 2015-09-16 22:35:00,2.11 2015-09-16 22:40:00,0.72 2015-09-16 22:45:00,1.39 2015-09-16 22:50:00,0.67 2015-09-16 22:55:00,4.33 2015-09-16 23:00:00,2.44 2015-09-16 23:05:00,2.89 2015-09-16 23:10:00,2.17 2015-09-16 23:15:00,2.94 2015-09-16 23:25:00,0.78 2015-09-16 23:40:00,1.56 2015-09-16 23:45:00,1.28 2015-09-16 23:55:00,1.67 2015-09-17 00:00:00,2.22 2015-09-17 00:05:00,2.56 2015-09-17 00:10:00,4.28 2015-09-17 00:20:00,1.17 2015-09-17 00:25:00,0.89 2015-09-17 00:30:00,0.94 2015-09-17 00:50:00,0.89 2015-09-17 00:55:00,0.67 2015-09-17 01:05:00,0.78 2015-09-17 01:10:00,3.83 2015-09-17 01:15:00,1.22 2015-09-17 01:20:00,1 2015-09-17 01:30:00,0.67 2015-09-17 01:45:00,0.78 2015-09-17 02:15:00,3.17 2015-09-17 03:05:00,0.67 2015-09-17 03:30:00,1.56 2015-09-17 03:45:00,0.72 2015-09-17 03:50:00,1.56 2015-09-17 04:05:00,4.94 2015-09-17 04:10:00,0.61 2015-09-17 04:15:00,1.33 2015-09-17 04:20:00,2.06 2015-09-17 04:25:00,1.39 2015-09-17 04:30:00,2.72 2015-09-17 04:35:00,3.39 2015-09-17 04:40:00,2.33 2015-09-17 04:45:00,0 2015-09-17 04:50:00,4.33 2015-09-17 04:55:00,4.33 2015-09-17 05:00:00,3.56 2015-09-17 05:05:00,4.11 2015-09-17 05:10:00,4.72 2015-09-17 05:15:00,2.33 2015-09-17 05:20:00,4.72 2015-09-17 05:25:00,2.72 2015-09-17 05:30:00,3.61 2015-09-17 05:35:00,6.39 2015-09-17 05:40:00,5.33 2015-09-17 05:45:00,8.39 2015-09-17 05:50:00,2.39 2015-09-17 05:55:00,3.28 2015-09-17 06:00:00,8.06 2015-09-17 06:05:00,7.22 2015-09-17 06:10:00,5.67 2015-09-17 06:15:00,11.39 2015-09-17 06:20:00,8.06 2015-09-17 06:25:00,4.22 2015-09-17 06:30:00,2.89 2015-09-17 06:35:00,5.39 2015-09-17 06:40:00,7 2015-09-17 06:45:00,8.94 2015-09-17 06:50:00,13.06 2015-09-17 06:55:00,13 2015-09-17 07:00:00,13.17 2015-09-17 07:05:00,5.94 2015-09-17 07:10:00,9 2015-09-17 07:15:00,11.06 2015-09-17 07:20:00,8.89 2015-09-17 07:25:00,17.39 2015-09-17 07:30:00,14.11 2015-09-17 07:35:00,9.83 2015-09-17 07:40:00,7.78 2015-09-17 07:45:00,14.56 2015-09-17 07:50:00,19 2015-09-17 07:55:00,43.06 2015-09-17 08:00:00,36.33 2015-09-17 08:05:00,14.17 2015-09-17 08:10:00,26.61 2015-09-17 08:15:00,22.11 2015-09-17 08:20:00,15.22 2015-09-17 08:25:00,20.56 2015-09-17 08:30:00,17.06 2015-09-17 08:35:00,6.5 2015-09-17 08:40:00,13.56 2015-09-17 08:45:00,7.06 2015-09-17 08:55:00,13.11 2015-09-17 09:00:00,10.67 2015-09-17 09:05:00,11.61 2015-09-17 09:10:00,12.33 2015-09-17 09:15:00,7.72 2015-09-17 09:20:00,9.33 2015-09-17 09:25:00,10.56 2015-09-17 09:30:00,10.44 2015-09-17 09:35:00,13.06 2015-09-17 09:40:00,5.17 2015-09-17 09:45:00,9.67 2015-09-17 09:50:00,4 2015-09-17 09:55:00,10.72 2015-09-17 10:00:00,8.61 2015-09-17 10:05:00,6.94 2015-09-17 10:10:00,15.5 2015-09-17 10:15:00,7.11 2015-09-17 10:20:00,8.22 2015-09-17 10:25:00,9.83 2015-09-17 10:30:00,6.89 2015-09-17 10:35:00,10.11 2015-09-17 10:40:00,10.39 2015-09-17 10:45:00,9.61 2015-09-17 10:50:00,12.67 2015-09-17 10:55:00,12.17 2015-09-17 11:00:00,9.28 2015-09-17 11:05:00,12.44 2015-09-17 11:10:00,7.67 2015-09-17 11:15:00,9.44 2015-09-17 11:20:00,10.94 2015-09-17 11:25:00,4.94 2015-09-17 11:30:00,7.78 2015-09-17 11:35:00,5.44 2015-09-17 11:40:00,10 2015-09-17 11:45:00,5.56 2015-09-17 11:50:00,9.56 2015-09-17 11:55:00,8.78 2015-09-17 12:00:00,5.11 2015-09-17 12:05:00,3.78 2015-09-17 12:10:00,5.67 2015-09-17 12:15:00,9.22 2015-09-17 12:20:00,4.11 2015-09-17 12:25:00,10.28 2015-09-17 12:30:00,14.28 2015-09-17 12:35:00,5.56 2015-09-17 12:40:00,11.78 2015-09-17 12:45:00,10.39 2015-09-17 12:50:00,8.56 2015-09-17 12:55:00,4.33 2015-09-17 13:00:00,6.39 2015-09-17 13:05:00,12.44 2015-09-17 13:10:00,7.33 2015-09-17 13:15:00,6.5 2015-09-17 13:20:00,7.11 2015-09-17 13:25:00,16.94 2015-09-17 13:30:00,11.78 2015-09-17 13:35:00,11.06 2015-09-17 13:40:00,10.89 2015-09-17 13:45:00,5.22 2015-09-17 13:50:00,2.56 2015-09-17 13:55:00,10.61 2015-09-17 14:00:00,3.78 2015-09-17 14:05:00,15.33 2015-09-17 14:10:00,13.17 2015-09-17 14:15:00,10.61 2015-09-17 14:20:00,6.22 2015-09-17 14:25:00,14.94 2015-09-17 14:30:00,13.22 2015-09-17 14:34:00,12.11 2015-09-17 14:39:00,7.83 2015-09-17 14:44:00,10.94 2015-09-17 14:49:00,6.94 2015-09-17 14:54:00,10 2015-09-17 14:58:00,0.61 2015-09-17 15:04:00,10.5 2015-09-17 15:08:00,6.78 2015-09-17 15:13:00,9.33 2015-09-17 15:18:00,8.28 2015-09-17 15:23:00,10.78 2015-09-17 15:28:00,5.67 2015-09-17 15:34:00,7.17 2015-09-17 15:38:00,7.17 2015-09-17 15:43:00,7.33 2015-09-17 15:48:00,7.11 2015-09-17 15:49:00,6.28 2015-09-17 15:54:00,4.39 2015-09-17 15:59:00,8.72 2015-09-17 16:04:00,9.94 2015-09-17 16:09:00,12.72 2015-09-17 16:14:00,10 2015-09-17 16:19:00,9.39 2015-09-17 16:24:00,8.06 ================================================ FILE: workspace/anomaly_detector/datasets/selected/trending/ambient_temperature_system_failure.csv ================================================ timestamp,value 2013-07-04 00:00:00,69.88083514 2013-07-04 01:00:00,71.22022706 2013-07-04 02:00:00,70.87780496 2013-07-04 03:00:00,68.95939994 2013-07-04 04:00:00,69.28355102 2013-07-04 05:00:00,70.06096581 2013-07-04 06:00:00,69.27976479 2013-07-04 07:00:00,69.36960846 2013-07-04 08:00:00,69.16671394 2013-07-04 09:00:00,68.98608257 2013-07-04 10:00:00,69.96506224 2013-07-04 11:00:00,70.55619466 2013-07-04 12:00:00,70.30750511 2013-07-04 13:00:00,70.24625215 2013-07-04 14:00:00,69.85490839 2013-07-04 15:00:00,71.64329118 2013-07-04 16:00:00,71.24565942 2013-07-04 17:00:00,70.74509976 2013-07-04 18:00:00,71.37329829 2013-07-04 19:00:00,71.7957509 2013-07-04 20:00:00,72.09160609999998 2013-07-04 21:00:00,71.55307612 2013-07-04 22:00:00,72.18769545 2013-07-04 23:00:00,70.64995744 2013-07-05 00:00:00,71.34274211 2013-07-05 01:00:00,71.5867281 2013-07-05 02:00:00,70.97700116 2013-07-05 03:00:00,70.24388209 2013-07-05 04:00:00,70.43282627 2013-07-05 05:00:00,69.74896285 2013-07-05 06:00:00,68.74938222 2013-07-05 07:00:00,69.35162661 2013-07-05 08:00:00,68.85314844 2013-07-05 09:00:00,70.31790951 2013-07-05 10:00:00,70.30055692 2013-07-05 11:00:00,72.53056283 2013-07-05 12:00:00,71.64320692 2013-07-05 13:00:00,72.92223804 2013-07-05 14:00:00,72.63758833 2013-07-05 15:00:00,72.95903086 2013-07-05 16:00:00,72.15222081 2013-07-05 17:00:00,72.16607562 2013-07-05 18:00:00,72.30558574 2013-07-05 19:00:00,72.3823022 2013-07-05 20:00:00,72.61234869 2013-07-05 21:00:00,72.77599570000002 2013-07-05 22:00:00,71.91696888 2013-07-05 23:00:00,71.55368851 2013-07-06 00:00:00,71.63096403 2013-07-06 01:00:00,70.59673521 2013-07-06 02:00:00,70.85248247 2013-07-06 03:00:00,71.08476824 2013-07-06 04:00:00,70.84723252 2013-07-06 05:00:00,70.23242259999999 2013-07-06 06:00:00,70.12823808 2013-07-06 07:00:00,69.92923136 2013-07-06 08:00:00,69.28574982 2013-07-06 09:00:00,69.72638712 2013-07-06 10:00:00,68.19010253 2013-07-06 11:00:00,68.91679541 2013-07-06 12:00:00,67.26820458 2013-07-06 13:00:00,66.9649601 2013-07-06 14:00:00,67.76538379 2013-07-06 15:00:00,66.91858576 2013-07-06 16:00:00,67.60522282 2013-07-06 17:00:00,67.17661097 2013-07-06 18:00:00,67.99254044 2013-07-06 19:00:00,67.25818019 2013-07-06 20:00:00,66.59407898 2013-07-06 21:00:00,67.86855757 2013-07-06 22:00:00,67.2922007 2013-07-06 23:00:00,67.16337656 2013-07-07 00:00:00,66.27568448 2013-07-07 01:00:00,65.96858705 2013-07-07 02:00:00,65.31642297 2013-07-07 03:00:00,65.42912751 2013-07-07 04:00:00,66.75098393 2013-07-07 05:00:00,64.68391715 2013-07-07 06:00:00,64.56520692 2013-07-07 07:00:00,66.12965686 2013-07-07 08:00:00,66.09613054 2013-07-07 09:00:00,64.9748123 2013-07-07 10:00:00,64.33478963 2013-07-07 11:00:00,65.54142516 2013-07-07 12:00:00,63.9130944 2013-07-07 13:00:00,65.00924432 2013-07-07 14:00:00,64.04781966 2013-07-07 15:00:00,64.25831852 2013-07-07 16:00:00,63.89332373 2013-07-07 17:00:00,64.14310465 2013-07-07 18:00:00,64.17594209 2013-07-07 19:00:00,63.1570819 2013-07-07 20:00:00,63.38689893 2013-07-07 21:00:00,63.99038726 2013-07-07 22:00:00,62.67478854 2013-07-07 23:00:00,64.24663357 2013-07-08 00:00:00,62.48078508 2013-07-08 01:00:00,62.03055446 2013-07-08 02:00:00,63.41156044 2013-07-08 03:00:00,61.70510991 2013-07-08 04:00:00,62.77513946 2013-07-08 05:00:00,61.36447611 2013-07-08 06:00:00,61.68984072 2013-07-08 07:00:00,62.20048874 2013-07-08 08:00:00,62.98280722 2013-07-08 09:00:00,64.44813096 2013-07-08 10:00:00,65.33294727 2013-07-08 11:00:00,66.51294379 2013-07-08 12:00:00,67.88554227 2013-07-08 13:00:00,67.22250712 2013-07-08 14:00:00,68.08885127 2013-07-08 15:00:00,68.55257476 2013-07-08 16:00:00,70.32033392 2013-07-08 17:00:00,70.48553783 2013-07-08 18:00:00,72.33830154 2013-07-08 19:00:00,71.1908248 2013-07-08 20:00:00,70.75989770000002 2013-07-08 21:00:00,70.57075487 2013-07-08 22:00:00,68.88572309999999 2013-07-08 23:00:00,68.36836764 2013-07-09 00:00:00,68.42198714 2013-07-09 01:00:00,67.55824354 2013-07-09 02:00:00,66.4884322 2013-07-09 03:00:00,66.00939653 2013-07-09 04:00:00,64.88258671 2013-07-09 05:00:00,65.79409771 2013-07-09 06:00:00,65.69617694 2013-07-09 07:00:00,66.14773729 2013-07-09 08:00:00,67.47861967 2013-07-09 09:00:00,67.43966413 2013-07-09 10:00:00,68.50079012 2013-07-09 11:00:00,69.93367814 2013-07-09 12:00:00,70.66856782 2013-07-09 13:00:00,69.43364009999999 2013-07-09 14:00:00,70.20645921 2013-07-09 15:00:00,70.23002897 2013-07-09 16:00:00,71.58361231 2013-07-09 17:00:00,71.56436778 2013-07-09 18:00:00,71.02917453 2013-07-09 19:00:00,72.831066 2013-07-09 20:00:00,71.13716811 2013-07-09 21:00:00,69.72083178 2013-07-09 22:00:00,69.17560647 2013-07-09 23:00:00,69.31959282 2013-07-10 00:00:00,68.81260454 2013-07-10 01:00:00,68.55716829 2013-07-10 02:00:00,67.73062887 2013-07-10 03:00:00,67.80815335 2013-07-10 04:00:00,66.93277621 2013-07-10 05:00:00,65.84066557 2013-07-10 06:00:00,66.15467548 2013-07-10 07:00:00,65.78125301 2013-07-10 08:00:00,67.33388757 2013-07-10 09:00:00,67.3485843 2013-07-10 10:00:00,69.75301970000001 2013-07-10 11:00:00,69.90438916 2013-07-10 12:00:00,70.59424483 2013-07-10 13:00:00,70.05946788 2013-07-10 14:00:00,71.02625542 2013-07-10 15:00:00,71.56116588 2013-07-10 16:00:00,70.98303947 2013-07-10 17:00:00,71.78059711 2013-07-10 18:00:00,73.40419990000002 2013-07-10 19:00:00,71.60391994 2013-07-10 20:00:00,70.48045714 2013-07-10 21:00:00,69.48780075 2013-07-10 22:00:00,69.37470081 2013-07-10 23:00:00,68.66754682 2013-07-11 00:00:00,69.05640228 2013-07-11 01:00:00,69.28118591 2013-07-11 02:00:00,68.00921159 2013-07-11 03:00:00,68.57902651 2013-07-11 04:00:00,66.49549932 2013-07-11 05:00:00,66.7500451 2013-07-11 06:00:00,66.42304923 2013-07-11 07:00:00,67.52779448 2013-07-11 08:00:00,67.89346899 2013-07-11 09:00:00,69.1011507 2013-07-11 10:00:00,70.51575503 2013-07-11 11:00:00,71.51359764 2013-07-11 12:00:00,70.78913828 2013-07-11 13:00:00,70.92408975 2013-07-11 14:00:00,71.43667911 2013-07-11 15:00:00,72.77048744 2013-07-11 16:00:00,72.18360109 2013-07-11 17:00:00,72.2317116 2013-07-11 18:00:00,72.14511125 2013-07-11 19:00:00,72.66568122 2013-07-11 20:00:00,71.74663208 2013-07-11 21:00:00,71.47523835 2013-07-11 22:00:00,70.17998073 2013-07-11 23:00:00,70.01828427 2013-07-12 00:00:00,69.63409091 2013-07-12 01:00:00,69.24166979 2013-07-12 02:00:00,69.44746561 2013-07-12 03:00:00,69.56135461 2013-07-12 04:00:00,67.43148423 2013-07-12 05:00:00,67.27588501 2013-07-12 06:00:00,67.64302314 2013-07-12 07:00:00,67.11633221 2013-07-12 08:00:00,68.58615434 2013-07-12 09:00:00,68.54878335 2013-07-12 10:00:00,69.78361434 2013-07-12 11:00:00,70.13666468 2013-07-12 12:00:00,71.79856679999997 2013-07-12 13:00:00,72.95326709 2013-07-12 14:00:00,73.38358272 2013-07-12 15:00:00,72.72556855 2013-07-12 16:00:00,74.27730941 2013-07-12 17:00:00,73.58946213 2013-07-12 18:00:00,73.07774519 2013-07-12 19:00:00,74.52428051 2013-07-12 20:00:00,72.52552383 2013-07-12 21:00:00,72.64264374 2013-07-12 22:00:00,73.47727338 2013-07-12 23:00:00,72.37521094 2013-07-13 00:00:00,71.20816904 2013-07-13 01:00:00,72.23586399 2013-07-13 02:00:00,71.09992340000002 2013-07-13 03:00:00,70.95986451 2013-07-13 04:00:00,70.25370091 2013-07-13 05:00:00,71.29442554 2013-07-13 06:00:00,70.37620145 2013-07-13 07:00:00,70.33534302 2013-07-13 08:00:00,68.96127518 2013-07-13 09:00:00,68.67478951 2013-07-13 10:00:00,68.68142551 2013-07-13 11:00:00,70.09922792 2013-07-13 12:00:00,69.29115996 2013-07-13 13:00:00,69.14944184 2013-07-13 14:00:00,69.38045679999999 2013-07-13 15:00:00,68.32729437 2013-07-13 16:00:00,68.71167009999999 2013-07-13 17:00:00,69.43031387 2013-07-13 18:00:00,69.12568539 2013-07-13 19:00:00,69.40509502 2013-07-13 20:00:00,68.64876516 2013-07-13 21:00:00,67.68106913 2013-07-13 22:00:00,69.16363194 2013-07-13 23:00:00,68.19982138 2013-07-14 00:00:00,68.1347302 2013-07-14 01:00:00,67.28588699 2013-07-14 02:00:00,67.77737459 2013-07-14 03:00:00,68.40400085 2013-07-14 04:00:00,68.12434843 2013-07-14 05:00:00,66.62975642 2013-07-14 06:00:00,67.75402118 2013-07-14 07:00:00,67.19706687 2013-07-14 08:00:00,66.19511529 2013-07-14 09:00:00,67.03467174 2013-07-14 10:00:00,66.39229109 2013-07-14 11:00:00,66.98910128 2013-07-14 12:00:00,66.70652022 2013-07-14 13:00:00,65.89533219 2013-07-14 14:00:00,66.15310629999999 2013-07-14 15:00:00,65.94826687 2013-07-14 16:00:00,66.18545065 2013-07-14 17:00:00,65.956704 2013-07-14 18:00:00,66.58099932 2013-07-14 19:00:00,67.19124175 2013-07-14 20:00:00,66.74457508 2013-07-14 21:00:00,65.89869767 2013-07-14 22:00:00,65.51804828 2013-07-14 23:00:00,65.98471013 2013-07-15 00:00:00,66.62908319 2013-07-15 01:00:00,64.90780861 2013-07-15 02:00:00,64.9498236 2013-07-15 03:00:00,65.64024470000001 2013-07-15 04:00:00,64.33322178 2013-07-15 05:00:00,65.81400458 2013-07-15 06:00:00,64.19811908 2013-07-15 07:00:00,65.79277627 2013-07-15 08:00:00,66.47022878 2013-07-15 09:00:00,66.21114689 2013-07-15 10:00:00,68.4034625 2013-07-15 11:00:00,69.51708004 2013-07-15 12:00:00,69.39746721 2013-07-15 13:00:00,70.91288645 2013-07-15 14:00:00,70.88878119 2013-07-15 15:00:00,71.10972093 2013-07-15 16:00:00,72.96756108 2013-07-15 17:00:00,72.02770961 2013-07-15 18:00:00,73.95202783 2013-07-15 19:00:00,73.37599022 2013-07-15 20:00:00,73.50769737 2013-07-15 21:00:00,72.71914771 2013-07-15 22:00:00,72.47419791 2013-07-15 23:00:00,72.0845572 2013-07-16 00:00:00,70.36089703 2013-07-16 01:00:00,71.0505306 2013-07-16 02:00:00,71.07182369 2013-07-16 03:00:00,70.51372607 2013-07-16 04:00:00,70.18259029999999 2013-07-16 05:00:00,69.85543379 2013-07-16 06:00:00,67.99007603 2013-07-16 07:00:00,68.45766038 2013-07-16 08:00:00,68.27103298 2013-07-16 09:00:00,68.96138225 2013-07-16 10:00:00,69.74436809 2013-07-16 11:00:00,70.61571518 2013-07-16 12:00:00,71.17846267 2013-07-16 13:00:00,72.386747 2013-07-16 14:00:00,72.41193764 2013-07-16 15:00:00,73.68813485 2013-07-16 16:00:00,73.74326223 2013-07-16 17:00:00,73.75611822 2013-07-16 18:00:00,74.32401543 2013-07-16 19:00:00,73.86398591 2013-07-16 20:00:00,73.78849309 2013-07-16 21:00:00,73.00264849 2013-07-16 22:00:00,72.04541547 2013-07-16 23:00:00,71.08743709 2013-07-17 00:00:00,71.9849653 2013-07-17 01:00:00,71.11160009999998 2013-07-17 02:00:00,70.99668759999999 2013-07-17 03:00:00,69.26084472 2013-07-17 04:00:00,69.52490512 2013-07-17 05:00:00,68.65398309 2013-07-17 06:00:00,68.44222186 2013-07-17 07:00:00,68.98691712 2013-07-17 08:00:00,68.12116394 2013-07-17 09:00:00,70.27706087 2013-07-17 10:00:00,69.46657012 2013-07-17 11:00:00,70.32267213 2013-07-17 12:00:00,71.8078395 2013-07-17 13:00:00,72.06436516 2013-07-17 14:00:00,72.48594731 2013-07-17 15:00:00,72.35822858 2013-07-17 16:00:00,74.73026071 2013-07-17 17:00:00,74.45593333 2013-07-17 18:00:00,75.42083051 2013-07-17 19:00:00,74.93021109 2013-07-17 20:00:00,73.46169520000002 2013-07-17 21:00:00,73.44264061 2013-07-17 22:00:00,73.59425862 2013-07-17 23:00:00,72.56355591 2013-07-18 00:00:00,71.67826483 2013-07-18 01:00:00,72.61615717 2013-07-18 02:00:00,70.46155106 2013-07-18 03:00:00,70.68690223 2013-07-18 04:00:00,71.27823432 2013-07-18 05:00:00,70.31179231 2013-07-18 06:00:00,69.53791299 2013-07-18 07:00:00,70.39827926 2013-07-18 08:00:00,69.63338286 2013-07-18 09:00:00,69.47214598 2013-07-18 10:00:00,71.46398548 2013-07-18 11:00:00,72.41314268 2013-07-18 12:00:00,70.9737679 2013-07-18 13:00:00,72.40852176 2013-07-18 14:00:00,73.89859399 2013-07-18 15:00:00,73.99496326 2013-07-18 16:00:00,74.54050584 2013-07-18 17:00:00,74.01063854 2013-07-18 18:00:00,76.39001911 2013-07-18 19:00:00,75.69719107 2013-07-18 20:00:00,75.38408868 2013-07-18 21:00:00,74.12498598 2013-07-18 22:00:00,75.41434918 2013-07-18 23:00:00,74.69411987 2013-07-19 00:00:00,73.07657971 2013-07-19 01:00:00,73.16384917 2013-07-19 02:00:00,73.505794 2013-07-19 03:00:00,74.12699807 2013-07-19 04:00:00,73.71152259 2013-07-19 05:00:00,71.98042488 2013-07-19 06:00:00,71.25116014 2013-07-19 07:00:00,72.16027157 2013-07-19 08:00:00,71.37306717 2013-07-19 09:00:00,71.51790632 2013-07-19 10:00:00,72.2737793 2013-07-19 11:00:00,71.8167371 2013-07-19 12:00:00,73.80696593 2013-07-19 13:00:00,72.94734057 2013-07-19 14:00:00,75.32774091 2013-07-19 15:00:00,75.75888894 2013-07-19 16:00:00,75.61622646 2013-07-19 17:00:00,74.80626301 2013-07-19 18:00:00,75.95162112 2013-07-19 19:00:00,75.00414728 2013-07-19 20:00:00,75.7922298 2013-07-19 21:00:00,75.93662081 2013-07-19 22:00:00,74.08191979 2013-07-19 23:00:00,74.0239745 2013-07-20 00:00:00,73.62518064 2013-07-20 01:00:00,73.55238749 2013-07-20 02:00:00,74.17438898 2013-07-20 03:00:00,72.87160933 2013-07-20 04:00:00,72.28482269 2013-07-20 05:00:00,73.51122601 2013-07-20 06:00:00,72.89366827 2013-07-20 07:00:00,72.14791650000002 2013-07-20 08:00:00,72.9557522 2013-07-20 09:00:00,72.42186823 2013-07-20 10:00:00,70.665252 2013-07-20 11:00:00,71.61263958 2013-07-20 12:00:00,69.74580737 2013-07-20 13:00:00,71.39185449 2013-07-20 14:00:00,70.82733191 2013-07-20 15:00:00,69.32886638 2013-07-20 16:00:00,70.65200484 2013-07-20 17:00:00,70.26620516 2013-07-20 18:00:00,69.04063432 2013-07-20 19:00:00,68.41965745 2013-07-20 20:00:00,68.8585241 2013-07-20 21:00:00,68.36710746 2013-07-20 22:00:00,68.83774585 2013-07-20 23:00:00,68.30402817 2013-07-21 00:00:00,69.3689329 2013-07-21 01:00:00,68.08187826 2013-07-21 02:00:00,67.60392999 2013-07-21 03:00:00,67.44621031 2013-07-21 04:00:00,67.54039145 2013-07-21 05:00:00,67.80852224 2013-07-21 06:00:00,66.38552342 2013-07-21 07:00:00,66.67172095 2013-07-21 08:00:00,65.91622406 2013-07-21 09:00:00,65.67154675 2013-07-21 10:00:00,65.72519189 2013-07-21 11:00:00,66.79848157 2013-07-21 12:00:00,65.43107747 2013-07-21 13:00:00,66.88734467 2013-07-21 14:00:00,65.94946794 2013-07-21 15:00:00,65.28216492 2013-07-21 16:00:00,66.6497085 2013-07-21 17:00:00,66.3990687 2013-07-21 18:00:00,65.00919878 2013-07-21 19:00:00,65.06137224 2013-07-21 20:00:00,65.62911927 2013-07-21 21:00:00,66.37157503 2013-07-21 22:00:00,64.5293161 2013-07-21 23:00:00,66.33871216 2013-07-22 00:00:00,65.29158087 2013-07-22 01:00:00,65.17119986 2013-07-22 02:00:00,65.36758419 2013-07-22 03:00:00,64.55987145 2013-07-22 04:00:00,64.65845259 2013-07-22 05:00:00,64.86762829999999 2013-07-22 06:00:00,63.6094313 2013-07-22 07:00:00,64.96073316 2013-07-22 08:00:00,65.43995404 2013-07-22 09:00:00,67.07099988 2013-07-22 10:00:00,66.67125763 2013-07-22 11:00:00,67.64060287 2013-07-22 12:00:00,68.62797459999999 2013-07-22 13:00:00,70.2454449 2013-07-22 14:00:00,69.70567339 2013-07-22 15:00:00,70.36650487 2013-07-22 16:00:00,72.27945276 2013-07-22 17:00:00,72.71664316 2013-07-22 18:00:00,71.84306091 2013-07-22 19:00:00,71.53844637 2013-07-22 20:00:00,71.55812139 2013-07-22 21:00:00,70.76534571 2013-07-22 22:00:00,71.14242657 2013-07-22 23:00:00,70.71393712 2013-07-23 00:00:00,69.58966371 2013-07-23 01:00:00,69.02299462 2013-07-23 02:00:00,68.95729279 2013-07-23 03:00:00,68.14795876 2013-07-23 04:00:00,67.48635522 2013-07-23 05:00:00,66.52278589 2013-07-23 06:00:00,66.81771127 2013-07-23 07:00:00,66.25215878 2013-07-23 08:00:00,68.14487953 2013-07-23 09:00:00,68.75540328 2013-07-23 10:00:00,68.54546326 2013-07-23 11:00:00,68.65504344 2013-07-23 12:00:00,69.96525521 2013-07-23 13:00:00,70.93097625 2013-07-23 14:00:00,70.67200225 2013-07-23 15:00:00,72.45541594 2013-07-23 16:00:00,72.75267236 2013-07-23 17:00:00,72.98703117 2013-07-23 18:00:00,73.15160594 2013-07-23 19:00:00,73.18754221 2013-07-23 20:00:00,71.04274096 2013-07-23 21:00:00,71.54354038 2013-07-23 22:00:00,71.74520109 2013-07-23 23:00:00,70.94274876 2013-07-24 00:00:00,69.74530422 2013-07-24 01:00:00,69.52726729 2013-07-24 02:00:00,70.32903161 2013-07-24 03:00:00,70.03017299 2013-07-24 04:00:00,68.87043296 2013-07-24 05:00:00,68.92349639 2013-07-24 06:00:00,68.10636443 2013-07-24 07:00:00,68.55988567 2013-07-24 08:00:00,67.85392905 2013-07-24 09:00:00,68.35577512 2013-07-24 10:00:00,69.70795831 2013-07-24 11:00:00,70.53390858 2013-07-24 12:00:00,69.78024465 2013-07-24 13:00:00,71.51678733 2013-07-24 14:00:00,72.03103759999998 2013-07-24 15:00:00,73.40007449 2013-07-24 16:00:00,73.8675255 2013-07-24 17:00:00,72.66779455 2013-07-24 18:00:00,72.85222389 2013-07-24 19:00:00,73.11323349999998 2013-07-24 20:00:00,72.2813031 2013-07-24 21:00:00,72.61561106 2013-07-24 22:00:00,71.61517817 2013-07-24 23:00:00,72.75668787 2013-07-25 00:00:00,71.14354005 2013-07-25 01:00:00,70.8585056 2013-07-25 02:00:00,70.89259768 2013-07-25 03:00:00,70.85000882 2013-07-25 04:00:00,71.4091997 2013-07-25 05:00:00,70.257825 2013-07-25 06:00:00,69.82174319 2013-07-25 07:00:00,69.39311984 2013-07-25 08:00:00,69.94923869 2013-07-25 09:00:00,70.35977277 2013-07-25 10:00:00,71.59751048 2013-07-25 11:00:00,71.15990415 2013-07-25 12:00:00,72.51273013 2013-07-25 13:00:00,73.02999473 2013-07-25 14:00:00,72.09791824 2013-07-25 15:00:00,72.92583014 2013-07-25 16:00:00,73.86938351 2013-07-25 17:00:00,73.91377788 2013-07-25 18:00:00,74.46991144 2013-07-25 19:00:00,73.21314175 2013-07-25 20:00:00,74.51203141 2013-07-25 21:00:00,72.84294254 2013-07-25 22:00:00,73.43276491 2013-07-25 23:00:00,73.30466379999999 2013-07-26 00:00:00,72.81092703 2013-07-26 01:00:00,72.86473466 2013-07-26 02:00:00,71.38222869 2013-07-26 03:00:00,71.19623896 2013-07-26 04:00:00,71.03955791 2013-07-26 05:00:00,72.27910059999998 2013-07-26 06:00:00,70.21785723 2013-07-26 07:00:00,70.31733297 2013-07-26 08:00:00,69.78868463 2013-07-26 09:00:00,70.88145123 2013-07-26 10:00:00,71.61930479 2013-07-26 11:00:00,72.28509323 2013-07-26 12:00:00,72.77202114 2013-07-26 13:00:00,73.24703993 2013-07-26 14:00:00,72.80712104 2013-07-26 15:00:00,72.58748947 2013-07-26 16:00:00,74.68417583 2013-07-26 17:00:00,73.09200323 2013-07-26 18:00:00,74.09006089 2013-07-26 19:00:00,74.61862587 2013-07-26 20:00:00,73.81911639 2013-07-26 21:00:00,74.57014385 2013-07-26 22:00:00,72.69101123 2013-07-26 23:00:00,73.56142292 2013-07-27 00:00:00,73.77909916 2013-07-27 01:00:00,72.91239911 2013-07-27 02:00:00,73.48633826 2013-07-27 03:00:00,72.73447053 2013-07-27 04:00:00,71.62959719 2013-07-27 05:00:00,72.41051865 2013-07-27 06:00:00,71.64829313 2013-07-27 07:00:00,71.34815297 2013-07-27 08:00:00,70.69776199 2013-07-27 09:00:00,70.47033288 2013-07-27 10:00:00,71.02517791 2013-07-27 11:00:00,69.83488902 2013-07-27 12:00:00,71.50090936 2013-07-27 13:00:00,70.40361959 2013-07-27 14:00:00,70.54399168 2013-07-27 15:00:00,71.85746328 2013-07-27 16:00:00,71.15225757 2013-07-27 17:00:00,72.78516393 2013-07-27 18:00:00,73.36070500000002 2013-07-27 19:00:00,72.86473047 2013-07-27 20:00:00,72.70608578 2013-07-27 21:00:00,73.85915886 2013-07-27 22:00:00,73.50507967 2013-07-27 23:00:00,72.19240313 2013-07-28 00:00:00,72.13995763 2013-07-28 01:00:00,72.76124036 2013-07-28 03:00:00,72.78238947 2013-07-28 04:00:00,71.89290086 2013-07-29 12:00:00,73.24344321 2013-07-29 13:00:00,73.25408094 2013-07-29 14:00:00,72.61221201 2013-07-29 15:00:00,73.02852459 2013-07-29 16:00:00,73.29062043 2013-07-29 17:00:00,74.12192813 2013-07-29 18:00:00,75.04218319 2013-07-29 19:00:00,75.01049779 2013-07-29 20:00:00,74.14262591 2013-07-29 21:00:00,73.92443272 2013-07-29 22:00:00,74.65910397 2013-07-29 23:00:00,74.79811406 2013-07-30 00:00:00,74.46700925 2013-07-30 01:00:00,73.29755441 2013-07-30 02:00:00,73.68345172 2013-07-30 03:00:00,72.34692708 2013-07-30 04:00:00,73.24426001 2013-07-30 05:00:00,72.14957625 2013-07-30 06:00:00,72.41976913 2013-07-30 07:00:00,71.31132501 2013-07-30 08:00:00,71.70322328 2013-07-30 09:00:00,72.25103685 2013-07-30 10:00:00,71.97716389 2013-07-30 11:00:00,71.39886276 2013-07-30 12:00:00,71.59695286 2013-07-30 13:00:00,72.63410157 2013-07-30 14:00:00,73.23961797 2013-07-30 15:00:00,72.52081721 2013-07-30 16:00:00,74.01598050000003 2013-07-30 17:00:00,73.67468353 2013-07-30 18:00:00,75.75032693 2013-07-30 19:00:00,74.3638755 2013-07-30 20:00:00,74.41574553 2013-07-30 21:00:00,74.22077381 2013-07-30 22:00:00,75.24461638 2013-07-30 23:00:00,75.76683279 2013-07-31 00:00:00,75.2599283 2013-07-31 01:00:00,75.00430133 2013-07-31 02:00:00,72.99868724 2013-07-31 03:00:00,74.22813959 2013-07-31 04:00:00,73.86242657 2013-07-31 05:00:00,73.64995716 2013-07-31 06:00:00,72.4157443 2013-07-31 07:00:00,72.33008672 2013-07-31 08:00:00,72.6550647 2013-07-31 09:00:00,72.28311126 2013-07-31 10:00:00,73.03449417 2013-07-31 11:00:00,72.28032012 2013-07-31 12:00:00,71.87820491 2013-07-31 13:00:00,73.40155661 2013-07-31 14:00:00,74.44122979 2013-07-31 15:00:00,73.87635966 2013-07-31 16:00:00,73.90784081 2013-07-31 17:00:00,75.16955484 2013-07-31 18:00:00,75.15953611 2013-07-31 19:00:00,74.80214938 2013-07-31 20:00:00,76.28002237 2013-07-31 21:00:00,74.85748264 2013-07-31 22:00:00,75.92805235 2013-07-31 23:00:00,75.91643042 2013-08-01 00:00:00,74.39653829999997 2013-08-01 01:00:00,75.10901277 2013-08-01 02:00:00,74.09065784 2013-08-01 03:00:00,74.99478559 2013-08-01 04:00:00,74.49008385 2013-08-01 05:00:00,74.15968431 2013-08-01 06:00:00,73.77074883 2013-08-01 07:00:00,73.761944 2013-08-01 08:00:00,72.39267309 2013-08-01 09:00:00,72.65461782 2013-08-01 10:00:00,71.85842391 2013-08-01 11:00:00,72.90726702 2013-08-01 12:00:00,72.74347127 2013-08-01 13:00:00,73.80882616 2013-08-01 14:00:00,74.02068569 2013-08-01 15:00:00,74.93830342 2013-08-01 16:00:00,73.482711 2013-08-01 17:00:00,74.16997946 2013-08-01 18:00:00,74.01751843 2013-08-01 19:00:00,74.49814040000003 2013-08-01 20:00:00,76.3120219 2013-08-01 21:00:00,75.08484325 2013-08-01 22:00:00,74.65943066 2013-08-01 23:00:00,75.82212698 2013-08-02 00:00:00,74.8569766 2013-08-02 01:00:00,73.98785798 2013-08-02 02:00:00,74.22412386 2013-08-02 03:00:00,74.51575386 2013-08-02 04:00:00,74.45778211 2013-08-02 05:00:00,74.12643606 2013-08-02 06:00:00,73.99954302 2013-08-02 07:00:00,72.26824527 2013-08-02 08:00:00,73.7764128 2013-08-02 09:00:00,72.90101937 2013-08-02 10:00:00,72.11776996 2013-08-02 11:00:00,72.92499217 2013-08-02 12:00:00,72.05187563 2013-08-02 13:00:00,72.38437545 2013-08-02 14:00:00,74.07630529 2013-08-02 15:00:00,74.61920753 2013-08-02 16:00:00,75.08524938 2013-08-02 17:00:00,75.82866138 2013-08-02 18:00:00,75.42713311 2013-08-02 19:00:00,76.56950166 2013-08-02 20:00:00,76.17963379 2013-08-02 21:00:00,74.94074803 2013-08-02 22:00:00,74.76418837 2013-08-02 23:00:00,74.12540695 2013-08-03 00:00:00,74.84051371 2013-08-03 01:00:00,73.79928772 2013-08-03 02:00:00,74.780247 2013-08-03 03:00:00,72.82864301 2013-08-03 04:00:00,72.48177255 2013-08-03 05:00:00,73.27429509999997 2013-08-03 06:00:00,73.26715622 2013-08-03 07:00:00,72.74611472 2013-08-03 08:00:00,71.30564248 2013-08-03 09:00:00,70.79796992 2013-08-03 10:00:00,70.8324548 2013-08-03 11:00:00,71.36899796 2013-08-03 12:00:00,71.30600481 2013-08-03 13:00:00,69.95127986 2013-08-03 14:00:00,71.11183674 2013-08-03 15:00:00,71.24355108 2013-08-03 16:00:00,71.16602046 2013-08-03 17:00:00,69.5362003 2013-08-03 18:00:00,71.21599291 2013-08-03 19:00:00,70.94704371 2013-08-03 20:00:00,71.14172451 2013-08-03 21:00:00,70.94719413 2013-08-03 22:00:00,70.28093351 2013-08-03 23:00:00,69.95038298 2013-08-04 00:00:00,70.06016939 2013-08-04 01:00:00,68.72937535 2013-08-04 02:00:00,68.31124754 2013-08-04 03:00:00,67.59938455 2013-08-04 04:00:00,69.23919313 2013-08-04 05:00:00,68.70527934 2013-08-04 06:00:00,67.30881248 2013-08-04 07:00:00,67.29093890000001 2013-08-04 08:00:00,67.01058194 2013-08-04 09:00:00,67.11700116 2013-08-04 10:00:00,67.17114622 2013-08-04 11:00:00,64.8612751 2013-08-04 12:00:00,66.1031092 2013-08-04 13:00:00,64.70015253 2013-08-04 14:00:00,65.97732586 2013-08-04 15:00:00,64.83488246 2013-08-04 16:00:00,65.16140029 2013-08-04 17:00:00,65.86503497 2013-08-04 18:00:00,67.73521012 2013-08-04 19:00:00,68.12101336 2013-08-04 20:00:00,68.68838431 2013-08-04 21:00:00,67.73402197 2013-08-04 22:00:00,68.42818207 2013-08-04 23:00:00,68.16946111 2013-08-05 00:00:00,67.49229937 2013-08-05 01:00:00,66.98395449 2013-08-05 02:00:00,68.04064964 2013-08-05 03:00:00,66.62055167 2013-08-05 04:00:00,66.64744323 2013-08-05 05:00:00,66.08743294 2013-08-05 06:00:00,67.22510503 2013-08-05 07:00:00,66.43247979 2013-08-05 08:00:00,66.57052361 2013-08-05 09:00:00,68.05327519 2013-08-05 10:00:00,67.67038945 2013-08-05 11:00:00,69.17031869 2013-08-05 12:00:00,68.89948983 2013-08-05 13:00:00,70.00978672 2013-08-05 14:00:00,69.82913552 2013-08-05 15:00:00,70.9242198 2013-08-05 16:00:00,71.27814633 2013-08-05 17:00:00,72.15965785 2013-08-05 18:00:00,72.97618331 2013-08-05 19:00:00,72.66683797 2013-08-05 20:00:00,73.69117746 2013-08-05 21:00:00,72.80151077 2013-08-05 22:00:00,71.85931396 2013-08-05 23:00:00,72.23815016 2013-08-06 00:00:00,70.95862334 2013-08-06 01:00:00,72.4688891 2013-08-06 02:00:00,71.66219799 2013-08-06 03:00:00,71.86755979 2013-08-06 04:00:00,70.7802684 2013-08-06 05:00:00,70.99083764 2013-08-06 06:00:00,69.15653193 2013-08-06 07:00:00,69.08522976 2013-08-06 08:00:00,69.75214256 2013-08-06 09:00:00,69.46942493 2013-08-06 10:00:00,68.77679875 2013-08-06 11:00:00,70.22714587 2013-08-06 12:00:00,71.01598435 2013-08-06 13:00:00,72.44743344 2013-08-06 14:00:00,72.06658701 2013-08-06 15:00:00,72.98693668 2013-08-06 16:00:00,73.69835469 2013-08-06 17:00:00,73.75209157 2013-08-06 18:00:00,74.55800629 2013-08-06 19:00:00,72.35247916 2013-08-06 20:00:00,65.26017655 2013-08-06 21:00:00,74.76223447 2013-08-06 22:00:00,73.49525372 2013-08-06 23:00:00,73.36538505 2013-08-07 00:00:00,72.5976732 2013-08-07 01:00:00,72.99425699999998 2013-08-07 02:00:00,72.85282429 2013-08-07 03:00:00,72.74890938 2013-08-07 04:00:00,72.12765994 2013-08-07 05:00:00,71.09856805 2013-08-07 06:00:00,71.23849804 2013-08-07 07:00:00,70.27255592 2013-08-07 08:00:00,70.88395870000002 2013-08-07 09:00:00,71.39022061 2013-08-07 10:00:00,70.52089931 2013-08-07 11:00:00,71.25419744 2013-08-07 12:00:00,72.68993228 2013-08-07 13:00:00,72.61074543 2013-08-07 14:00:00,72.43902889 2013-08-07 15:00:00,73.58512146 2013-08-07 16:00:00,73.89459624 2013-08-07 17:00:00,72.95170937 2013-08-07 18:00:00,74.07563886 2013-08-07 19:00:00,73.6806514 2013-08-07 20:00:00,72.89217355 2013-08-07 21:00:00,73.32218412 2013-08-07 22:00:00,73.24266369 2013-08-07 23:00:00,72.14171440000001 2013-08-08 00:00:00,72.30380183 2013-08-08 01:00:00,72.89276841 2013-08-08 02:00:00,71.56299973 2013-08-08 03:00:00,72.39705979 2013-08-08 04:00:00,72.00657008 2013-08-08 05:00:00,71.32736169 2013-08-08 06:00:00,70.82135373 2013-08-08 07:00:00,70.1336473 2013-08-08 08:00:00,70.0467162 2013-08-08 09:00:00,70.06918582 2013-08-08 10:00:00,70.79634920000002 2013-08-08 11:00:00,70.91540196 2013-08-08 12:00:00,71.67451047 2013-08-08 13:00:00,72.18760774 2013-08-08 14:00:00,72.1207947 2013-08-08 15:00:00,72.51156743 2013-08-08 16:00:00,72.23695024 2013-08-08 17:00:00,71.87503532 2013-08-08 18:00:00,72.49582348 2013-08-08 19:00:00,72.35768598 2013-08-08 20:00:00,73.93378927 2013-08-08 21:00:00,73.98233814 2013-08-08 22:00:00,73.59560241 2013-08-08 23:00:00,71.98821679 2013-08-09 00:00:00,72.32396967 2013-08-09 01:00:00,71.6259057 2013-08-09 02:00:00,71.72859842 2013-08-09 03:00:00,70.70127666 2013-08-09 04:00:00,71.00161546 2013-08-09 05:00:00,70.81636614 2013-08-09 06:00:00,70.72324263 2013-08-09 07:00:00,70.3860912 2013-08-09 08:00:00,68.77908287 2013-08-09 09:00:00,70.22778904 2013-08-09 10:00:00,69.87258414 2013-08-09 11:00:00,70.44715736 2013-08-09 12:00:00,71.08361107 2013-08-09 13:00:00,71.23292042 2013-08-09 14:00:00,72.16067996 2013-08-09 15:00:00,71.86722192 2013-08-09 16:00:00,72.16014273 2013-08-09 17:00:00,72.99568483 2013-08-09 18:00:00,73.27572883 2013-08-09 19:00:00,73.49417662 2013-08-09 20:00:00,74.21107376 2013-08-09 21:00:00,72.54083404 2013-08-09 22:00:00,73.21324868 2013-08-09 23:00:00,72.58771726 2013-08-10 00:00:00,73.50120424 2013-08-10 01:00:00,72.09154651 2013-08-10 02:00:00,71.09042019 2013-08-10 03:00:00,71.23416619 2013-08-10 04:00:00,70.63012271 2013-08-10 05:00:00,69.77541726 2013-08-10 06:00:00,69.28687677 2013-08-10 07:00:00,70.44057715 2013-08-10 08:00:00,69.28731334 2013-08-10 09:00:00,69.93728934 2013-08-10 10:00:00,69.3391448 2013-08-10 11:00:00,69.13334157 2013-08-10 12:00:00,68.65929831 2013-08-10 13:00:00,68.18197506 2013-08-10 14:00:00,67.84812498 2013-08-10 15:00:00,69.37597782 2013-08-10 16:00:00,69.10036669 2013-08-10 17:00:00,68.8546449 2013-08-10 18:00:00,67.85837277 2013-08-10 19:00:00,68.46916703 2013-08-10 20:00:00,68.17855534 2013-08-10 21:00:00,69.21501077 2013-08-10 22:00:00,68.96464737 2013-08-10 23:00:00,67.87377682 2013-08-11 00:00:00,67.72178625 2013-08-11 01:00:00,68.58499733 2013-08-11 02:00:00,68.44962111 2013-08-11 03:00:00,67.14273776 2013-08-11 04:00:00,67.07599947 2013-08-11 05:00:00,68.29349922 2013-08-11 06:00:00,66.78969926 2013-08-11 07:00:00,65.82622549 2013-08-11 08:00:00,66.59954318 2013-08-11 09:00:00,65.01332031 2013-08-11 10:00:00,65.90620917 2013-08-11 11:00:00,65.84496837 2013-08-11 12:00:00,64.92189809 2013-08-11 13:00:00,65.58278655 2013-08-11 14:00:00,65.55748205 2013-08-11 15:00:00,65.59894884 2013-08-11 16:00:00,64.94337424 2013-08-11 17:00:00,64.74950254 2013-08-11 18:00:00,64.84844096 2013-08-11 19:00:00,65.83625843 2013-08-11 20:00:00,66.03749482 2013-08-11 21:00:00,65.38311565 2013-08-11 22:00:00,65.99967447 2013-08-11 23:00:00,64.36458794 2013-08-12 00:00:00,65.07952767 2013-08-12 01:00:00,65.29604166 2013-08-12 02:00:00,65.20610988 2013-08-12 03:00:00,63.96596281 2013-08-12 04:00:00,64.72425165 2013-08-12 05:00:00,65.40331196 2013-08-12 06:00:00,65.42865101 2013-08-12 07:00:00,64.09801612 2013-08-12 08:00:00,63.80900879 2013-08-12 09:00:00,64.54585931 2013-08-12 10:00:00,66.95784817 2013-08-12 11:00:00,66.61279611 2013-08-12 12:00:00,67.94979306 2013-08-12 13:00:00,66.39778915 2013-08-12 14:00:00,66.77796074 2013-08-12 15:00:00,67.1940435 2013-08-12 16:00:00,68.38187061 2013-08-12 17:00:00,67.12861534 2013-08-12 18:00:00,67.17067346 2013-08-12 19:00:00,68.43923628 2013-08-12 20:00:00,66.57086417 2013-08-12 21:00:00,67.78803691 2013-08-12 22:00:00,67.2787936 2013-08-12 23:00:00,67.87219243 2013-08-13 00:00:00,67.50915846 2013-08-13 01:00:00,67.66070149 2013-08-13 02:00:00,65.93597991 2013-08-13 03:00:00,65.72336823 2013-08-13 04:00:00,65.72245666 2013-08-13 05:00:00,66.11658266 2013-08-13 06:00:00,65.32184413 2013-08-13 07:00:00,65.71791971 2013-08-13 08:00:00,65.47364884 2013-08-13 09:00:00,66.64929047 2013-08-13 10:00:00,66.55123544 2013-08-13 11:00:00,67.79521779999999 2013-08-13 12:00:00,68.14077842 2013-08-13 13:00:00,69.79685244 2013-08-13 14:00:00,70.34622184 2013-08-13 15:00:00,69.32175382 2013-08-13 16:00:00,69.89015017 2013-08-13 17:00:00,71.58845383 2013-08-13 18:00:00,71.86175982 2013-08-13 19:00:00,72.7410679 2013-08-13 20:00:00,71.90458946 2013-08-13 21:00:00,71.28351048 2013-08-13 22:00:00,70.09728390000001 2013-08-13 23:00:00,69.27726512 2013-08-14 00:00:00,68.92546699 2013-08-14 01:00:00,68.55186335 2013-08-14 02:00:00,67.65673848 2013-08-14 03:00:00,68.32131351 2013-08-14 04:00:00,68.12150858 2013-08-14 05:00:00,66.5554972 2013-08-14 06:00:00,66.38718242 2013-08-14 07:00:00,66.99569939 2013-08-14 08:00:00,65.87173899 2013-08-14 09:00:00,67.22433388 2013-08-14 10:00:00,68.40446699 2013-08-14 11:00:00,68.74846629999999 2013-08-14 12:00:00,69.32469028 2013-08-14 13:00:00,71.15467576 2013-08-14 14:00:00,71.05227306 2013-08-14 15:00:00,70.83181931 2013-08-14 16:00:00,70.91625104 2013-08-14 17:00:00,72.39488293 2013-08-14 18:00:00,71.98328520000003 2013-08-14 19:00:00,72.37378341 2013-08-14 20:00:00,71.80748327 2013-08-14 21:00:00,72.54903002 2013-08-14 22:00:00,71.18557043 2013-08-14 23:00:00,70.6560059 2013-08-15 00:00:00,71.42334777 2013-08-15 01:00:00,69.34699767 2013-08-15 02:00:00,70.73289851 2013-08-15 03:00:00,68.5593425 2013-08-15 04:00:00,69.75429868 2013-08-15 05:00:00,69.42528082 2013-08-15 06:00:00,68.78050479 2013-08-15 07:00:00,67.57592345 2013-08-15 08:00:00,67.31292692 2013-08-15 09:00:00,68.61465054 2013-08-15 10:00:00,68.93048832 2013-08-15 11:00:00,70.42238762 2013-08-15 12:00:00,70.84558646 2013-08-15 13:00:00,71.06424324 2013-08-15 14:00:00,72.69610401 2013-08-15 15:00:00,72.32617126 2013-08-15 16:00:00,72.22167626 2013-08-15 17:00:00,73.21437055 2013-08-15 18:00:00,73.15708957 2013-08-15 19:00:00,73.49412607 2013-08-15 20:00:00,72.3006671 2013-08-15 21:00:00,73.86668101 2013-08-15 22:00:00,72.6701852 2013-08-15 23:00:00,72.7624445 2013-08-16 00:00:00,72.76328752 2013-08-16 01:00:00,71.3147316 2013-08-16 02:00:00,71.43288687 2013-08-16 03:00:00,70.82264418 2013-08-16 04:00:00,70.66687081 2013-08-16 05:00:00,70.43909465 2013-08-16 06:00:00,69.81296825 2013-08-16 07:00:00,69.69858982 2013-08-16 08:00:00,68.34291749 2013-08-16 09:00:00,69.78913221 2013-08-16 10:00:00,69.04301127 2013-08-16 11:00:00,71.2618595 2013-08-16 12:00:00,71.53303086 2013-08-16 13:00:00,71.2414772 2013-08-16 14:00:00,73.36763803 2013-08-16 15:00:00,73.57415941 2013-08-16 16:00:00,72.24425435 2013-08-16 17:00:00,74.26516471 2013-08-16 18:00:00,72.92651196 2013-08-16 19:00:00,74.39635211 2013-08-16 20:00:00,74.11889706 2013-08-16 21:00:00,72.19232832 2013-08-16 22:00:00,73.73903840000001 2013-08-16 23:00:00,72.2079627 2013-08-17 00:00:00,72.96446399 2013-08-17 01:00:00,72.47851039 2013-08-17 02:00:00,71.26534459 2013-08-17 03:00:00,70.53066333 2013-08-17 04:00:00,71.25037104 2013-08-17 05:00:00,70.43519581 2013-08-17 06:00:00,70.42341332 2013-08-17 07:00:00,70.79164337 2013-08-17 08:00:00,68.95439433 2013-08-17 09:00:00,70.34051981 2013-08-17 10:00:00,69.80542162 2013-08-17 11:00:00,68.64316206 2013-08-17 12:00:00,69.38668045 2013-08-17 13:00:00,68.78927469999999 2013-08-17 14:00:00,68.83952616 2013-08-17 15:00:00,67.63291116 2013-08-17 16:00:00,68.40694416 2013-08-17 17:00:00,69.14007715 2013-08-17 18:00:00,69.11590587 2013-08-17 19:00:00,68.03579823 2013-08-17 20:00:00,69.27272007 2013-08-17 21:00:00,68.75322294 2013-08-17 22:00:00,69.56566049 2013-08-17 23:00:00,68.17712131 2013-08-18 00:00:00,67.79477436 2013-08-18 01:00:00,67.49347171 2013-08-18 02:00:00,67.79427593 2013-08-18 03:00:00,67.70107774 2013-08-18 04:00:00,67.26294021 2013-08-18 05:00:00,66.86984441 2013-08-18 06:00:00,66.14932783 2013-08-18 07:00:00,66.42313039 2013-08-18 08:00:00,67.0524877 2013-08-18 09:00:00,65.34818634 2013-08-18 10:00:00,65.89940057 2013-08-18 11:00:00,66.64739688 2013-08-18 12:00:00,66.64122284 2013-08-18 13:00:00,64.79138473 2013-08-18 14:00:00,65.90167301 2013-08-18 15:00:00,65.74127604 2013-08-18 16:00:00,65.45031794 2013-08-18 17:00:00,66.16094532 2013-08-18 18:00:00,65.7044379 2013-08-18 19:00:00,64.77549911 2013-08-18 20:00:00,66.10922106 2013-08-18 21:00:00,64.65138267 2013-08-18 22:00:00,64.63763005 2013-08-18 23:00:00,64.86524307 2013-08-19 00:00:00,64.67189696 2013-08-19 01:00:00,64.46795885 2013-08-19 02:00:00,65.91187512 2013-08-19 03:00:00,64.34806529 2013-08-19 04:00:00,63.99581812 2013-08-19 05:00:00,65.39461929 2013-08-19 06:00:00,64.65292546 2013-08-19 07:00:00,63.25807837 2013-08-19 08:00:00,63.73827199 2013-08-19 09:00:00,64.48038308 2013-08-19 10:00:00,65.99746656 2013-08-19 11:00:00,66.25822123 2013-08-19 12:00:00,68.10328147 2013-08-19 13:00:00,67.8042515 2013-08-19 14:00:00,69.4870625 2013-08-19 15:00:00,70.03024494 2013-08-19 16:00:00,70.29600481 2013-08-19 17:00:00,71.04468694 2013-08-19 18:00:00,72.07494806 2013-08-19 19:00:00,71.92135771 2013-08-19 20:00:00,72.83067187 2013-08-19 21:00:00,71.98101498 2013-08-19 22:00:00,69.32089454 2013-08-19 23:00:00,70.13159511 2013-08-20 00:00:00,70.00507257 2013-08-20 01:00:00,69.43663186 2013-08-20 02:00:00,68.94680541 2013-08-20 03:00:00,67.39526388 2013-08-20 04:00:00,66.86451228 2013-08-20 05:00:00,67.61515255 2013-08-20 06:00:00,67.50015115 2013-08-20 07:00:00,67.06492539999999 2013-08-20 08:00:00,66.18109356 2013-08-20 09:00:00,67.67862944 2013-08-20 10:00:00,67.28780716 2013-08-20 11:00:00,68.64887048 2013-08-20 12:00:00,68.03818943 2013-08-20 13:00:00,69.43733797 2013-08-20 14:00:00,69.42521625 2013-08-20 15:00:00,70.34561943 2013-08-20 16:00:00,70.30816394 2013-08-20 17:00:00,70.8360583 2013-08-20 18:00:00,71.1470857 2013-08-20 19:00:00,71.57781772 2013-08-20 20:00:00,72.19406331 2013-08-20 21:00:00,72.28995087 2013-08-20 22:00:00,71.14766239 2013-08-20 23:00:00,69.76492572 2013-08-21 00:00:00,69.91788048 2013-08-21 01:00:00,69.25384854 2013-08-21 02:00:00,67.70300258 2013-08-21 03:00:00,67.34860655 2013-08-21 04:00:00,67.03007179 2013-08-21 05:00:00,67.02774425 2013-08-21 06:00:00,66.79530391 2013-08-21 07:00:00,65.29474687 2013-08-21 08:00:00,66.61324069 2013-08-21 09:00:00,66.79489002 2013-08-21 10:00:00,66.72432203 2013-08-21 11:00:00,66.81536983 2013-08-21 12:00:00,67.17358633 2013-08-21 13:00:00,67.63012369 2013-08-21 14:00:00,67.48754605 2013-08-21 15:00:00,67.33171806 2013-08-21 16:00:00,69.7284424 2013-08-21 17:00:00,69.89615603 2013-08-21 18:00:00,68.99214926 2013-08-21 19:00:00,70.03999165 2013-08-21 20:00:00,70.55714223 2013-08-21 21:00:00,70.17848707 2013-08-21 22:00:00,68.21913112 2013-08-21 23:00:00,68.40833713 2013-08-22 00:00:00,68.94808523 2013-08-22 01:00:00,67.38899521 2013-08-22 02:00:00,68.05245103 2013-08-22 03:00:00,67.21188517 2013-08-22 04:00:00,65.70328183 2013-08-22 05:00:00,67.16985267 2013-08-22 06:00:00,66.55460769 2013-08-22 07:00:00,65.72798535 2013-08-22 08:00:00,65.75716876 2013-08-22 09:00:00,67.16913702 2013-08-22 10:00:00,67.21744752 2013-08-22 11:00:00,68.42865711 2013-08-22 12:00:00,67.939555 2013-08-22 13:00:00,68.21272047 2013-08-22 14:00:00,68.59771355 2013-08-22 15:00:00,69.8746694 2013-08-22 16:00:00,69.78932095 2013-08-22 17:00:00,71.20599841 2013-08-22 18:00:00,71.58253869 2013-08-22 19:00:00,71.88959565 2013-08-22 20:00:00,71.86056438 2013-08-22 21:00:00,72.04256027 2013-08-22 22:00:00,71.39573223 2013-08-22 23:00:00,69.55668318 2013-08-23 00:00:00,68.93024269 2013-08-23 01:00:00,69.66341833 2013-08-23 02:00:00,69.04101322 2013-08-23 03:00:00,67.96747227 2013-08-23 04:00:00,69.31576272 2013-08-23 05:00:00,68.15040455 2013-08-23 06:00:00,68.35613984 2013-08-23 07:00:00,67.76316051 2013-08-23 08:00:00,67.03590822 2013-08-23 09:00:00,67.39406286 2013-08-23 10:00:00,68.68188132 2013-08-23 11:00:00,70.23539114 2013-08-23 12:00:00,70.72213492 2013-08-23 13:00:00,70.58200639 2013-08-23 14:00:00,71.80797978 2013-08-23 15:00:00,70.57872691 2013-08-23 16:00:00,72.0077339 2013-08-23 17:00:00,71.71571281 2013-08-23 18:00:00,72.11695816 2013-08-23 19:00:00,72.64909676 2013-08-23 20:00:00,71.43282886 2013-08-23 21:00:00,71.71418699 2013-08-23 22:00:00,72.28243141 2013-08-23 23:00:00,72.25217338 2013-08-24 00:00:00,71.74318478 2013-08-24 01:00:00,69.68874182 2013-08-24 02:00:00,70.11075437 2013-08-24 03:00:00,68.69315914 2013-08-24 04:00:00,68.49395196 2013-08-24 05:00:00,69.05769349 2013-08-24 06:00:00,67.38563023 2013-08-24 07:00:00,68.51017483 2013-08-24 08:00:00,68.046038 2013-08-24 09:00:00,66.69591868 2013-08-24 10:00:00,67.0893911 2013-08-24 11:00:00,66.22561571 2013-08-24 12:00:00,66.50296546 2013-08-24 13:00:00,65.29980537 2013-08-24 14:00:00,65.44279328 2013-08-24 15:00:00,65.87726412 2013-08-24 16:00:00,65.57372439 2013-08-24 17:00:00,65.68296557 2013-08-24 18:00:00,66.93568163 2013-08-24 19:00:00,66.69982543 2013-08-24 20:00:00,65.99025408 2013-08-24 21:00:00,65.93769573 2013-08-24 22:00:00,67.04970768 2013-08-24 23:00:00,66.73555970000001 2013-08-25 00:00:00,66.23665366 2013-08-25 01:00:00,66.23546935 2013-08-25 02:00:00,66.85525388 2013-08-25 03:00:00,65.44418785 2013-08-25 04:00:00,66.70939032 2013-08-25 05:00:00,64.88554717 2013-08-25 06:00:00,64.35080723 2013-08-25 07:00:00,64.38802527 2013-08-25 08:00:00,64.40835278 2013-08-25 09:00:00,64.42226129 2013-08-25 10:00:00,64.05518099 2013-08-25 11:00:00,64.71716427 2013-08-25 12:00:00,64.45389357 2013-08-25 13:00:00,64.50166125 2013-08-25 14:00:00,64.01651861 2013-08-25 15:00:00,62.85522295 2013-08-25 16:00:00,64.23986264 2013-08-25 17:00:00,63.38848875 2013-08-25 18:00:00,63.39183252 2013-08-25 19:00:00,65.20905227 2013-08-25 20:00:00,64.94516739 2013-08-25 21:00:00,64.25107982 2013-08-25 22:00:00,64.17982393 2013-08-25 23:00:00,64.38921578 2013-08-26 00:00:00,64.49909975 2013-08-26 01:00:00,65.09660852 2013-08-26 02:00:00,63.40543705 2013-08-26 03:00:00,63.83826011 2013-08-26 04:00:00,63.68217925 2013-08-26 05:00:00,63.32128642 2013-08-26 06:00:00,63.45009249 2013-08-26 07:00:00,63.58602877 2013-08-26 08:00:00,62.73132759 2013-08-26 09:00:00,64.6219447 2013-08-26 10:00:00,65.04527027 2013-08-26 11:00:00,65.66669249 2013-08-26 12:00:00,66.04597893 2013-08-26 13:00:00,66.92945334 2013-08-26 14:00:00,68.27335848 2013-08-26 15:00:00,68.03643251 2013-08-26 16:00:00,68.32526303 2013-08-26 17:00:00,69.45241625 2013-08-26 18:00:00,69.292876 2013-08-26 19:00:00,69.61637759 2013-08-26 20:00:00,69.09830136 2013-08-26 21:00:00,68.9295352 2013-08-26 22:00:00,68.38166541 2013-08-26 23:00:00,66.69776707 2013-08-27 00:00:00,66.55923923 2013-08-27 01:00:00,65.50421593 2013-08-27 02:00:00,65.36283826 2013-08-27 03:00:00,65.03631072 2013-08-27 04:00:00,64.28289583 2013-08-27 05:00:00,64.70837708 2013-08-27 06:00:00,65.19959422 2013-08-27 07:00:00,64.37599177 2013-08-27 08:00:00,65.80010808 2013-08-27 09:00:00,66.90052411 2013-08-27 10:00:00,65.97556180000001 2013-08-27 11:00:00,67.21755426 2013-08-29 11:00:00,67.61970814 2013-08-29 12:00:00,68.68919867 2013-08-29 13:00:00,68.99230755 2013-08-29 14:00:00,69.01270334 2013-08-29 15:00:00,69.60076165 2013-08-29 16:00:00,70.62180453 2013-08-29 17:00:00,70.80389723 2013-08-29 18:00:00,71.95049453 2013-08-29 19:00:00,71.45525932 2013-08-29 20:00:00,70.69089941 2013-08-29 21:00:00,70.84845568 2013-08-29 22:00:00,71.14711094 2013-08-29 23:00:00,70.19670613 2013-08-30 00:00:00,70.26757380000001 2013-08-30 01:00:00,70.3477134 2013-08-30 02:00:00,68.94715476 2013-08-30 03:00:00,68.19452413 2013-08-30 04:00:00,67.41217981 2013-08-30 05:00:00,67.6915133 2013-08-30 06:00:00,68.1326941 2013-08-30 07:00:00,67.72304464 2013-08-30 08:00:00,67.00024303 2013-08-30 09:00:00,68.33122058 2013-08-30 10:00:00,68.77081792 2013-08-30 11:00:00,67.89464946 2013-08-30 12:00:00,70.32897545 2013-08-30 13:00:00,69.94984745 2013-08-30 14:00:00,69.04940045 2013-08-30 15:00:00,70.48680148 2013-08-30 16:00:00,70.73164318 2013-08-30 17:00:00,70.27130965 2013-08-30 18:00:00,70.56771532 2013-08-30 19:00:00,70.52348927 2013-08-30 20:00:00,70.94288585 2013-08-30 21:00:00,70.09622236 2013-08-30 22:00:00,70.92253659999999 2013-08-30 23:00:00,69.73699276 2013-08-31 00:00:00,69.50362657 2013-08-31 01:00:00,68.74107885 2013-08-31 02:00:00,67.98350404 2013-08-31 03:00:00,68.65775842 2013-08-31 04:00:00,69.01901831 2013-08-31 05:00:00,68.7557281 2013-08-31 06:00:00,67.6440132 2013-08-31 07:00:00,67.09824802 2013-08-31 08:00:00,68.86076740000001 2013-08-31 09:00:00,68.54857064 2013-08-31 10:00:00,68.10020545 2013-08-31 11:00:00,67.3162411 2013-08-31 12:00:00,67.37946307 2013-08-31 13:00:00,68.16976322 2013-08-31 14:00:00,68.33976301 2013-08-31 15:00:00,68.55040093 2013-08-31 16:00:00,67.16532869 2013-08-31 17:00:00,67.30479343 2013-08-31 18:00:00,66.79372649 2013-08-31 19:00:00,66.97126902 2013-08-31 20:00:00,66.36018507 2013-08-31 21:00:00,67.20420628 2013-08-31 22:00:00,68.07608732 2013-08-31 23:00:00,67.23191893 2013-09-01 00:00:00,67.78175194 2013-09-01 01:00:00,66.07614673 2013-09-01 02:00:00,66.11011254 2013-09-01 03:00:00,67.10977933 2013-09-01 04:00:00,67.52951352 2013-09-01 05:00:00,67.37827727 2013-09-01 06:00:00,67.10470918 2013-09-01 07:00:00,66.9472606 2013-09-01 08:00:00,67.13996477 2013-09-01 09:00:00,66.67085420000001 2013-09-01 10:00:00,65.9378113 2013-09-01 11:00:00,66.5151767 2013-09-01 12:00:00,66.072041 2013-09-01 13:00:00,66.3918316 2013-09-01 14:00:00,65.43023923 2013-09-01 15:00:00,65.6508534 2013-09-01 16:00:00,66.13170688 2013-09-01 17:00:00,65.63831743 2013-09-01 18:00:00,65.95578224 2013-09-01 19:00:00,67.36956957 2013-09-01 20:00:00,67.02516809 2013-09-01 21:00:00,66.72385597 2013-09-01 22:00:00,67.25433659 2013-09-01 23:00:00,68.06762583 2013-09-02 00:00:00,68.2229547 2013-09-02 01:00:00,66.04236184 2013-09-02 02:00:00,66.95310877 2013-09-02 03:00:00,66.30459021 2013-09-02 04:00:00,66.61170465 2013-09-02 05:00:00,64.69937871 2013-09-02 06:00:00,66.21768604 2013-09-02 07:00:00,65.95636186 2013-09-02 08:00:00,65.97202741 2013-09-02 09:00:00,67.53287993 2013-09-02 10:00:00,67.49599206 2013-09-02 11:00:00,67.72868098 2013-09-02 12:00:00,68.32218023 2013-09-02 13:00:00,68.08308598 2013-09-02 14:00:00,68.607251 2013-09-02 15:00:00,68.77487445 2013-09-02 16:00:00,68.7696785 2013-09-02 17:00:00,68.64186817 2013-09-02 18:00:00,70.62377265 2013-09-02 19:00:00,69.50433389 2013-09-02 20:00:00,68.92231254 2013-09-02 21:00:00,70.48760069 2013-09-02 22:00:00,68.22783476 2013-09-02 23:00:00,69.04882691 2013-09-03 00:00:00,67.74723934 2013-09-03 01:00:00,68.09114575 2013-09-03 02:00:00,68.65891435 2013-09-03 03:00:00,69.63167183 2013-09-03 04:00:00,69.57087107 2013-09-03 05:00:00,68.92351224 2013-09-03 06:00:00,67.53393503 2013-09-03 07:00:00,68.2712078 2013-09-03 08:00:00,68.65631055 2013-09-03 09:00:00,67.39411119 2013-09-03 10:00:00,68.37006622 2013-09-03 11:00:00,68.23821811 2013-09-03 12:00:00,68.24746423 2013-09-03 13:00:00,67.42129150000001 2013-09-03 14:00:00,67.17151006 2013-09-03 15:00:00,68.84601436 2013-09-03 16:00:00,68.98532397 2013-09-03 17:00:00,68.6852691 2013-09-03 18:00:00,70.38096941 2013-09-03 19:00:00,70.63271507 2013-09-03 20:00:00,70.71181053 2013-09-03 21:00:00,71.77605259 2013-09-03 22:00:00,71.9902121 2013-09-03 23:00:00,70.50334409 2013-09-04 00:00:00,70.02106963 2013-09-04 01:00:00,71.10226832 2013-09-04 02:00:00,71.07281481 2013-09-04 03:00:00,71.00298194 2013-09-04 04:00:00,69.64750524 2013-09-04 05:00:00,69.29922688 2013-09-04 06:00:00,70.19295937 2013-09-04 07:00:00,69.59298326 2013-09-04 08:00:00,69.94483099 2013-09-04 09:00:00,68.38753638 2013-09-04 10:00:00,70.12778664 2013-09-04 11:00:00,69.75996879 2013-09-04 12:00:00,70.57663801 2013-09-04 13:00:00,70.11459489 2013-09-04 14:00:00,71.54936878 2013-09-04 15:00:00,71.04470664 2013-09-04 16:00:00,71.67149466 2013-09-04 17:00:00,73.23762503 2013-09-04 18:00:00,72.25962147 2013-09-04 19:00:00,72.93900293 2013-09-04 20:00:00,71.27122808 2013-09-04 21:00:00,72.55002116 2013-09-04 22:00:00,71.25225098 2013-09-04 23:00:00,71.97747232 2013-09-05 00:00:00,70.23719215 2013-09-05 01:00:00,69.94606111 2013-09-05 02:00:00,69.450805 2013-09-05 03:00:00,69.93479403 2013-09-05 04:00:00,69.0965309 2013-09-05 05:00:00,68.97376954 2013-09-05 06:00:00,70.04102824 2013-09-05 07:00:00,69.54259642 2013-09-05 08:00:00,69.85107284 2013-09-05 09:00:00,69.61953454 2013-09-05 10:00:00,69.99920276 2013-09-05 11:00:00,70.41283415 2013-09-05 12:00:00,72.11046261 2013-09-05 13:00:00,72.80678003 2013-09-05 14:00:00,72.51801434 2013-09-05 15:00:00,72.69228723 2013-09-05 16:00:00,72.16597707 2013-09-05 17:00:00,73.99614903 2013-09-05 18:00:00,72.82582702 2013-09-05 19:00:00,74.24818259 2013-09-05 20:00:00,74.69982523 2013-09-05 21:00:00,75.16462698 2013-09-05 22:00:00,74.48402123 2013-09-05 23:00:00,72.97264305 2013-09-06 00:00:00,72.49176792 2013-09-06 01:00:00,73.77290611 2013-09-06 02:00:00,73.53132409999998 2013-09-06 03:00:00,72.73837497 2013-09-06 04:00:00,71.88548201 2013-09-06 05:00:00,71.52278755 2013-09-06 06:00:00,71.76144938 2013-09-06 07:00:00,72.45670094 2013-09-06 08:00:00,71.89475031 2013-09-06 09:00:00,70.52341229 2013-09-06 10:00:00,71.2629687 2013-09-06 11:00:00,72.8074479 2013-09-06 12:00:00,73.80156306 2013-09-06 13:00:00,73.52862948 2013-09-06 14:00:00,72.90089441 2013-09-06 15:00:00,73.17178042 2013-09-06 16:00:00,73.42038306 2013-09-06 17:00:00,73.47819457 2013-09-06 18:00:00,73.96854139 2013-09-06 19:00:00,74.39984284 2013-09-06 20:00:00,74.13263209 2013-09-06 21:00:00,73.66106497 2013-09-06 22:00:00,74.42455034 2013-09-06 23:00:00,73.88125989 2013-09-07 00:00:00,72.88416225 2013-09-07 01:00:00,72.53366149 2013-09-07 02:00:00,72.28026919 2013-09-07 03:00:00,73.5383584 2013-09-07 04:00:00,72.97417623 2013-09-07 05:00:00,72.80378043 2013-09-07 06:00:00,71.11640175 2013-09-07 07:00:00,71.8028968 2013-09-07 08:00:00,71.74339169 2013-09-07 09:00:00,71.89946776 2013-09-07 10:00:00,71.37667995 2013-09-07 11:00:00,70.97398196 2013-09-07 12:00:00,71.3123657 2013-09-07 13:00:00,71.86460893 2013-09-07 14:00:00,71.16599578 2013-09-07 15:00:00,71.37723976 2013-09-07 16:00:00,71.36848881 2013-09-07 17:00:00,70.78637361 2013-09-07 18:00:00,71.11015784 2013-09-07 19:00:00,71.85983966 2013-09-07 20:00:00,70.95035881 2013-09-07 21:00:00,72.65891354 2013-09-07 22:00:00,72.33779272 2013-09-07 23:00:00,70.61711298 2013-09-08 00:00:00,71.01930095 2013-09-08 01:00:00,71.63639202 2013-09-08 02:00:00,71.32415634 2013-09-08 03:00:00,70.5466809 2013-09-08 04:00:00,70.97726886 2013-09-08 05:00:00,69.7019157 2013-09-08 06:00:00,70.36501785 2013-09-08 07:00:00,69.28265658 2013-09-08 08:00:00,68.52513155 2013-09-08 09:00:00,68.91671905 2013-09-08 10:00:00,68.90391361 2013-09-08 11:00:00,69.25304945 2013-09-08 12:00:00,69.20694068 2013-09-08 13:00:00,68.4344154 2013-09-08 14:00:00,69.13783219 2013-09-08 15:00:00,67.78567323 2013-09-08 16:00:00,68.87397161 2013-09-08 17:00:00,68.04502775 2013-09-08 18:00:00,67.81055256 2013-09-08 19:00:00,68.99773267 2013-09-08 20:00:00,68.99448259 2013-09-08 21:00:00,67.84551049 2013-09-08 22:00:00,68.86458993 2013-09-08 23:00:00,67.97043986 2013-09-09 00:00:00,66.92321439 2013-09-09 01:00:00,68.59393936 2013-09-09 02:00:00,66.62695158 2013-09-09 03:00:00,67.75427493 2013-09-09 04:00:00,66.66782263 2013-09-09 05:00:00,67.46664892 2013-09-09 06:00:00,67.60322003 2013-09-09 07:00:00,67.66040956 2013-09-09 08:00:00,66.65714613 2013-09-09 09:00:00,68.75283581 2013-09-09 10:00:00,69.19079475 2013-09-09 11:00:00,70.45646119 2013-09-09 12:00:00,70.93982761 2013-09-09 13:00:00,69.63003292 2013-09-09 14:00:00,71.41526516 2013-09-09 15:00:00,71.55056424 2013-09-09 16:00:00,71.90106522 2013-09-09 17:00:00,71.69673606 2013-09-09 18:00:00,71.04065657 2013-09-09 19:00:00,71.73045012 2013-09-09 20:00:00,72.76664681 2013-09-16 12:00:00,72.69643979 2013-09-16 13:00:00,72.80547371 2013-09-16 14:00:00,72.91975931 2013-09-16 15:00:00,72.26792976 2013-09-16 16:00:00,72.85550390000002 2013-09-16 17:00:00,72.96351653 2013-09-16 18:00:00,72.77608689 2013-09-16 19:00:00,74.71764725 2013-09-16 20:00:00,75.18175232 2013-09-16 21:00:00,74.68157666 2013-09-16 22:00:00,75.03251294 2013-09-16 23:00:00,74.89547613 2013-09-17 00:00:00,72.88724781 2013-09-17 01:00:00,74.04983548 2013-09-17 02:00:00,73.82712414 2013-09-17 03:00:00,72.79875638 2013-09-17 04:00:00,71.99918837 2013-09-17 05:00:00,72.17190677 2013-09-17 06:00:00,71.25158302 2013-09-17 07:00:00,71.28680525 2013-09-17 08:00:00,71.38988043 2013-09-17 09:00:00,72.24634579 2013-09-17 10:00:00,71.59644925 2013-09-17 11:00:00,72.90837738 2013-09-17 12:00:00,73.24145352 2013-09-17 13:00:00,73.06605307 2013-09-17 14:00:00,72.64709801 2013-09-17 15:00:00,73.15343178 2013-09-17 16:00:00,72.96232879 2013-09-17 17:00:00,72.52813486 2013-09-17 18:00:00,73.81719904 2013-09-17 19:00:00,74.02874448 2013-09-17 20:00:00,73.79102864 2013-09-17 21:00:00,73.25605739 2013-09-17 22:00:00,73.05358423 2013-09-17 23:00:00,73.77224906 2013-09-18 00:00:00,72.8998969 2013-09-18 01:00:00,72.24385814 2013-09-18 02:00:00,71.33933531 2013-09-18 03:00:00,72.29793377 2013-09-18 04:00:00,70.34516442 2013-09-18 05:00:00,71.13949198 2013-09-18 06:00:00,70.16453648 2013-09-18 07:00:00,71.11202658 2013-09-18 08:00:00,70.4874724 2013-09-18 09:00:00,70.71749668 2013-09-18 10:00:00,69.89570423 2013-09-18 11:00:00,71.68790348 2013-09-18 12:00:00,71.37615947 2013-09-18 13:00:00,71.74150703 2013-09-18 14:00:00,73.20729802 2013-09-18 15:00:00,72.89029189 2013-09-18 16:00:00,72.30341978 2013-09-18 17:00:00,72.6912123 2013-09-18 18:00:00,72.34201351 2013-09-18 19:00:00,74.49429294 2013-09-18 20:00:00,73.25501422 2013-09-18 21:00:00,74.13004256 2013-09-18 22:00:00,73.68325892 2013-09-18 23:00:00,72.11340117 2013-09-19 00:00:00,72.31138231 2013-09-19 01:00:00,71.29385993 2013-09-19 02:00:00,71.93404046 2013-09-19 03:00:00,71.67908598 2013-09-19 04:00:00,71.48141177 2013-09-19 05:00:00,70.85357689 2013-09-19 06:00:00,69.45647733 2013-09-19 07:00:00,70.12965246 2013-09-19 08:00:00,69.02484940000001 2013-09-19 09:00:00,69.00810205 2013-09-19 10:00:00,67.59898139 2013-09-19 11:00:00,67.55493576 2013-09-19 12:00:00,67.40273072 2013-09-19 13:00:00,67.39032649 2013-09-19 14:00:00,68.09580201 2013-09-19 15:00:00,67.39266673 2013-09-19 16:00:00,68.36226835 2013-09-19 17:00:00,68.40469903 2013-09-19 18:00:00,67.83621597 2013-09-19 19:00:00,69.19489788 2013-09-19 20:00:00,68.49088179 2013-09-19 21:00:00,68.33740959999999 2013-09-19 22:00:00,68.76983220000001 2013-09-19 23:00:00,68.4357686 2013-09-20 00:00:00,68.74846768 2013-09-20 01:00:00,68.95527404 2013-09-20 02:00:00,68.2181708 2013-09-20 03:00:00,69.12993292 2013-09-20 04:00:00,68.4385586 2013-09-20 05:00:00,69.06796416 2013-09-20 06:00:00,68.30227174 2013-09-20 07:00:00,68.64631402 2013-09-20 08:00:00,68.88148079 2013-09-20 09:00:00,68.90088305 2013-09-20 10:00:00,69.65328565 2013-09-20 11:00:00,68.86754593 2013-09-20 12:00:00,68.42564703 2013-09-20 13:00:00,69.09581068 2013-09-20 14:00:00,69.44780599 2013-09-20 15:00:00,68.42082002 2013-09-20 16:00:00,68.83199074 2013-09-20 17:00:00,69.55729317 2013-09-20 18:00:00,68.83137434 2013-09-20 19:00:00,70.02835926 2013-09-20 20:00:00,71.07058978 2013-09-20 21:00:00,71.28937940000002 2013-09-20 22:00:00,70.10090101 2013-09-20 23:00:00,71.68557803 2013-09-21 00:00:00,69.88814945 2013-09-21 01:00:00,70.42523491 2013-09-21 02:00:00,69.44404702 2013-09-21 03:00:00,70.1451179 2013-09-21 04:00:00,69.48543471 2013-09-21 05:00:00,69.63115874 2013-09-21 06:00:00,70.00727727 2013-09-21 07:00:00,69.16183248 2013-09-21 08:00:00,68.43812628 2013-09-21 09:00:00,68.65276698 2013-09-21 10:00:00,68.15293671 2013-09-21 11:00:00,69.64474901 2013-09-21 12:00:00,69.0369617 2013-09-21 13:00:00,68.59565354 2013-09-21 14:00:00,69.91779386 2013-09-21 15:00:00,68.59944984 2013-09-21 16:00:00,68.66763575 2013-09-21 17:00:00,68.79732688 2013-09-21 18:00:00,69.52728032 2013-09-21 19:00:00,69.14499021 2013-09-21 20:00:00,69.36640493 2013-09-21 21:00:00,69.32436477 2013-09-21 22:00:00,70.04079998 2013-09-21 23:00:00,70.32088532 2013-09-22 00:00:00,70.68643574 2013-09-22 01:00:00,69.41778612 2013-09-22 02:00:00,69.52225613 2013-09-22 03:00:00,69.97825566 2013-09-22 04:00:00,69.84686459999999 2013-09-22 05:00:00,69.94587165 2013-09-22 06:00:00,68.70555692 2013-09-22 07:00:00,68.59229114 2013-09-22 08:00:00,69.9367965 2013-09-22 09:00:00,69.07467717 2013-09-22 10:00:00,68.77459707 2013-09-22 11:00:00,68.96774462 2013-09-22 12:00:00,69.51423059 2013-09-22 13:00:00,69.60984678 2013-09-22 14:00:00,68.45901476 2013-09-22 15:00:00,68.66205887 2013-09-22 16:00:00,69.07470807 2013-09-22 17:00:00,68.98798244 2013-09-22 18:00:00,70.4512398 2013-09-22 19:00:00,69.1587948 2013-09-22 20:00:00,70.02852311 2013-09-22 21:00:00,70.30112967 2013-09-22 22:00:00,71.02701721 2013-09-22 23:00:00,70.44438138 2013-09-23 00:00:00,71.21079549 2013-09-23 01:00:00,70.08097943 2013-09-23 02:00:00,70.01900785 2013-09-23 03:00:00,71.31684052 2013-09-23 04:00:00,69.49194049 2013-09-23 05:00:00,70.71476009 2013-09-23 06:00:00,70.30901685 2013-09-23 07:00:00,69.92749715 2013-09-23 08:00:00,69.28252505 2013-09-23 09:00:00,70.51499697 2013-09-23 10:00:00,69.17037572 2013-09-23 11:00:00,69.67300935 2013-09-23 12:00:00,70.98686733 2013-09-23 13:00:00,72.71037561 2013-09-23 14:00:00,72.84618043 2013-09-23 15:00:00,71.49931817 2013-09-23 16:00:00,71.82884072 2013-09-23 17:00:00,71.96846019 2013-09-23 18:00:00,72.38205511 2013-09-23 19:00:00,73.10852105 2013-09-23 20:00:00,72.50710177 2013-09-23 21:00:00,71.36822279 2013-09-23 22:00:00,71.73373415 2013-09-23 23:00:00,70.39800507 2013-09-24 00:00:00,71.02329854 2013-09-24 01:00:00,70.42861121 2013-09-24 02:00:00,71.29850242 2013-09-24 03:00:00,70.41391036 2013-09-24 04:00:00,69.83300525 2013-09-24 05:00:00,70.04073494 2013-09-24 06:00:00,69.2952676 2013-09-24 07:00:00,69.80497056 2013-09-24 08:00:00,70.47845996 2013-09-24 09:00:00,68.87983862 2013-09-24 10:00:00,70.82988977 2013-09-24 11:00:00,71.7612628 2013-09-24 12:00:00,71.23686153 2013-09-24 13:00:00,72.17708088 2013-09-24 14:00:00,73.52407232 2013-09-24 15:00:00,73.43257426 2013-09-24 16:00:00,71.96142812 2013-09-24 17:00:00,72.06857704 2013-09-24 18:00:00,72.80742737 2013-09-24 19:00:00,74.18072649 2013-09-24 20:00:00,72.6407991 2013-09-24 21:00:00,72.49329287 2013-09-24 22:00:00,73.37279171 2013-09-24 23:00:00,72.84631814 2013-09-25 00:00:00,73.74634464 2013-09-25 01:00:00,73.08950487 2013-09-25 02:00:00,73.12797789 2013-09-25 03:00:00,72.85145065 2013-09-25 04:00:00,71.78459362 2013-09-25 05:00:00,71.96428662 2013-09-25 06:00:00,70.98315976 2013-09-25 07:00:00,72.09370496 2013-09-25 08:00:00,70.47875896 2013-09-25 09:00:00,71.15613714 2013-09-25 10:00:00,71.79613981 2013-09-25 11:00:00,70.53267958 2013-09-25 12:00:00,70.92408688 2013-09-25 13:00:00,71.07714472 2013-09-25 14:00:00,72.12801602 2013-09-25 15:00:00,73.76239725 2013-09-25 16:00:00,73.50455944 2013-09-25 17:00:00,74.06381073 2013-09-25 18:00:00,75.84971566 2013-09-25 19:00:00,74.917338 2013-09-25 20:00:00,74.48204982 2013-09-25 21:00:00,75.4754704 2013-09-25 22:00:00,75.86633429 2013-09-25 23:00:00,75.82692618 2013-09-26 00:00:00,74.83518922 2013-09-26 01:00:00,75.84170562 2013-09-26 02:00:00,74.56152098 2013-09-26 03:00:00,74.74597341 2013-09-26 04:00:00,73.95196621 2013-09-26 05:00:00,74.73785827 2013-09-26 06:00:00,73.40944252 2013-09-26 07:00:00,74.09665445 2013-09-26 08:00:00,74.24341181 2013-09-26 09:00:00,72.4241878 2013-09-26 10:00:00,73.53577955 2013-09-26 11:00:00,72.89263790000003 2013-09-26 12:00:00,74.20179708 2013-09-26 13:00:00,73.82891751 2013-09-26 14:00:00,75.00384972 2013-09-26 15:00:00,75.06654759999998 2013-09-26 16:00:00,76.10375919 2013-09-26 17:00:00,75.0111683 2013-09-26 18:00:00,76.19220719 2013-09-26 19:00:00,75.75430219 2013-09-26 20:00:00,76.55201347 2013-09-26 21:00:00,76.3420965 2013-09-26 22:00:00,77.36149124 2013-09-26 23:00:00,76.62602951 2013-09-27 00:00:00,77.08086395 2013-09-27 01:00:00,77.09614267 2013-09-27 02:00:00,76.94079244 2013-09-27 03:00:00,76.9216273 2013-09-27 04:00:00,76.41395592 2013-09-27 05:00:00,76.76728419 2013-09-27 06:00:00,75.56516500000002 2013-09-27 07:00:00,75.00316640000001 2013-09-27 08:00:00,74.96022554 2013-09-27 09:00:00,76.25958507 2013-09-27 10:00:00,75.03195475 2013-09-27 11:00:00,75.97741221 2013-09-27 12:00:00,74.70847211 2013-10-01 12:00:00,75.66428844 2013-10-01 13:00:00,76.15183593 2013-10-01 14:00:00,74.94798282 2013-10-01 15:00:00,76.11749514 2013-10-01 16:00:00,76.35342739 2013-10-01 17:00:00,78.18999866 2013-10-01 18:00:00,78.34183958 2013-10-01 19:00:00,77.44052693 2013-10-01 20:00:00,76.20708541 2013-10-01 21:00:00,78.08998122 2013-10-01 22:00:00,78.05491504 2013-10-01 23:00:00,78.98542499 2013-10-02 00:00:00,78.23875807 2013-10-02 01:00:00,78.65871078 2013-10-02 02:00:00,78.53164898 2013-10-02 03:00:00,78.14277259999999 2013-10-02 04:00:00,76.73686252 2013-10-02 05:00:00,76.53612798 2013-10-02 06:00:00,77.21543335 2013-10-02 07:00:00,76.92976821 2013-10-02 08:00:00,77.61334761 2013-10-02 09:00:00,75.94869317 2013-10-02 10:00:00,76.80988678 2013-10-02 11:00:00,76.35617474 2013-10-02 12:00:00,75.51487417 2013-10-02 13:00:00,76.75914485 2013-10-02 14:00:00,77.18231352 2013-10-02 15:00:00,76.72424559 2013-10-02 16:00:00,77.02058259 2013-10-02 17:00:00,77.59412726 2013-10-02 18:00:00,76.57737238 2013-10-02 19:00:00,78.14370344 2013-10-02 20:00:00,76.44863817 2013-10-02 21:00:00,77.11808435 2013-10-02 22:00:00,76.66444143 2013-10-02 23:00:00,77.60066939 2013-10-03 00:00:00,76.44893235 2013-10-03 01:00:00,77.72893525 2013-10-03 02:00:00,76.61186772 2013-10-03 03:00:00,77.04302364 2013-10-03 04:00:00,75.7689679 2013-10-03 05:00:00,76.38938955 2013-10-03 06:00:00,76.10096966 2013-10-03 07:00:00,76.62421773 2013-10-03 08:00:00,75.41072897 2013-10-03 09:00:00,76.32543548 2013-10-03 10:00:00,75.26776154 2013-10-03 11:00:00,75.11220118 2013-10-03 12:00:00,76.37061231 2013-10-03 13:00:00,75.17527773 2013-10-03 14:00:00,76.48020188 2013-10-03 15:00:00,75.40371872 2013-10-03 16:00:00,76.08145149 2013-10-03 17:00:00,74.83978917 2013-10-03 18:00:00,74.700469 2013-10-03 19:00:00,75.46720555 2013-10-03 20:00:00,74.52571486 2013-10-03 21:00:00,75.50447062 2013-10-03 22:00:00,76.68142877 2013-10-03 23:00:00,77.07422539 2013-10-04 00:00:00,76.62848003 2013-10-04 01:00:00,75.65887074 2013-10-04 02:00:00,76.78498097 2013-10-04 03:00:00,76.97398833 2013-10-04 04:00:00,76.81809786 2013-10-04 05:00:00,76.18810762 2013-10-04 06:00:00,75.14738658 2013-10-04 07:00:00,74.60880026 2013-10-04 08:00:00,74.71020506 2013-10-04 09:00:00,74.33666665 2013-10-04 10:00:00,75.89063588 2013-10-04 11:00:00,74.92352501 2013-10-04 12:00:00,76.25032166 2013-10-04 13:00:00,76.76285447 2013-10-04 14:00:00,76.43795622 2013-10-04 15:00:00,75.84095165 2013-10-04 16:00:00,76.30759992 2013-10-04 17:00:00,76.37889288 2013-10-04 18:00:00,74.50037961 2013-10-04 19:00:00,75.46855478 2013-10-04 20:00:00,76.23977529 2013-10-04 21:00:00,75.60803745 2013-10-04 22:00:00,75.53609477 2013-10-04 23:00:00,76.15092858 2013-10-05 00:00:00,77.04357167 2013-10-05 01:00:00,76.83958927 2013-10-05 02:00:00,75.35704476 2013-10-05 03:00:00,75.26244693 2013-10-05 04:00:00,75.67256245 2013-10-05 05:00:00,74.97423465 2013-10-05 06:00:00,74.68662683 2013-10-05 07:00:00,74.67127682 2013-10-05 08:00:00,75.30039984 2013-10-05 09:00:00,75.41442640000002 2013-10-05 10:00:00,75.77834261 2013-10-05 11:00:00,76.30250549 2013-10-05 12:00:00,76.08729308 2013-10-05 13:00:00,76.17387791 2013-10-05 14:00:00,74.59539903 2013-10-05 15:00:00,74.8586202 2013-10-05 16:00:00,76.15473545 2013-10-05 17:00:00,76.73544665 2013-10-05 18:00:00,76.81207028 2013-10-05 19:00:00,76.76942959 2013-10-05 20:00:00,76.0742703 2013-10-05 21:00:00,77.67624752 2013-10-05 22:00:00,77.20513301 2013-10-05 23:00:00,78.30547509 2013-10-06 00:00:00,76.57887568 2013-10-06 01:00:00,76.88289528 2013-10-06 02:00:00,77.48251447 2013-10-06 03:00:00,76.38323965 2013-10-06 04:00:00,76.26112886 2013-10-06 05:00:00,77.83782089 2013-10-06 06:00:00,77.81793736 2013-10-06 07:00:00,76.88455309 2013-10-06 08:00:00,77.29695705 2013-10-06 09:00:00,75.7818161 2013-10-06 10:00:00,77.23681223 2013-10-06 11:00:00,77.65970467 2013-10-06 12:00:00,76.47686703 2013-10-06 13:00:00,76.45250409 2013-10-06 14:00:00,76.44446488 2013-10-06 15:00:00,75.338712 2013-10-06 16:00:00,75.43988813 2013-10-06 17:00:00,76.11375195 2013-10-06 18:00:00,75.44361839 2013-10-06 19:00:00,74.85664993 2013-10-06 20:00:00,75.89981187 2013-10-06 21:00:00,75.52638288 2013-10-06 22:00:00,76.70454118 2013-10-06 23:00:00,76.91841747 2013-10-07 00:00:00,76.77395886 2013-10-07 01:00:00,76.24255849 2013-10-07 02:00:00,75.93339717 2013-10-07 03:00:00,75.02163716 2013-10-07 04:00:00,75.85554729 2013-10-07 05:00:00,75.36964545 2013-10-07 06:00:00,74.66467269 2013-10-07 07:00:00,73.75869737 2013-10-07 08:00:00,74.69866385 2013-10-07 09:00:00,74.63334088 2013-10-07 10:00:00,74.24988343 2013-10-07 11:00:00,75.38338771 2013-10-07 12:00:00,74.12097863 2013-10-07 13:00:00,75.46608714 2013-10-07 14:00:00,74.99673301 2013-10-07 15:00:00,75.84411143 2013-10-07 16:00:00,76.15467811 2013-10-07 17:00:00,75.38180222 2013-10-07 18:00:00,74.98612428 2013-10-07 19:00:00,74.83290714 2013-10-07 20:00:00,75.33838706 2013-10-07 21:00:00,75.99301951 2013-10-07 22:00:00,75.44383011 2013-10-07 23:00:00,74.71510278 2013-10-08 00:00:00,75.16393256 2013-10-08 01:00:00,73.98772604 2013-10-08 02:00:00,72.99713921 2013-10-08 03:00:00,72.73963377 2013-10-08 04:00:00,72.56210332 2013-10-08 05:00:00,71.95415339 2013-10-08 06:00:00,71.53772099 2013-10-08 07:00:00,73.3846364 2013-10-08 08:00:00,73.02911198 2013-10-08 09:00:00,73.32056873 2013-10-08 10:00:00,72.65757445 2013-10-08 11:00:00,72.91058794 2013-10-08 12:00:00,72.00144343 2013-10-08 13:00:00,72.17948397 2013-10-08 14:00:00,73.13684959999998 2013-10-08 15:00:00,72.74243972 2013-10-08 16:00:00,74.04314141 2013-10-08 17:00:00,74.9362334 2013-10-08 18:00:00,73.60819261 2013-10-08 19:00:00,74.85510654 2013-10-08 20:00:00,75.18349971 2013-10-08 21:00:00,74.64847435 2013-10-08 22:00:00,74.30749947 2013-10-08 23:00:00,74.22020409 2013-10-09 00:00:00,73.93927621 2013-10-09 01:00:00,73.62134422 2013-10-09 02:00:00,73.81914203 2013-10-09 03:00:00,72.9684546 2013-10-09 04:00:00,73.01285776 2013-10-09 05:00:00,72.80505299 2013-10-09 06:00:00,72.66330867 2013-10-09 07:00:00,72.77940061 2013-10-09 08:00:00,72.45267623 2013-10-09 09:00:00,72.41013365 2013-10-09 10:00:00,72.97620201 2013-10-09 11:00:00,72.70599693 2013-10-09 12:00:00,72.67329612 2013-10-09 13:00:00,73.25471351 2013-10-09 14:00:00,74.21758249 2013-10-09 15:00:00,73.41679227 2013-10-09 16:00:00,73.26801845 2013-10-09 17:00:00,74.21654701 2013-10-09 18:00:00,74.49963991 2013-10-09 19:00:00,74.93839694 2013-10-09 20:00:00,74.48590659999998 2013-10-09 21:00:00,74.5249187 2013-10-09 22:00:00,74.94497354 2013-10-09 23:00:00,75.11312816 2013-10-10 00:00:00,73.45479839 2013-10-10 01:00:00,73.62753539 2013-10-10 02:00:00,74.65356252 2013-10-10 03:00:00,73.65569667 2013-10-10 04:00:00,74.30833238 2013-10-10 05:00:00,72.36883324 2013-10-10 06:00:00,72.63029089 2013-10-10 07:00:00,72.92216679 2013-10-10 08:00:00,73.50841047 2013-10-10 09:00:00,73.8940062 2013-10-10 10:00:00,72.75520825 2013-10-10 11:00:00,72.77342691 2013-10-10 12:00:00,74.0173653 2013-10-10 13:00:00,74.07999403 2013-10-10 14:00:00,74.98348749 2013-10-10 15:00:00,74.93166228 2013-10-10 16:00:00,75.00032977 2013-10-10 17:00:00,74.79545142 2013-10-10 18:00:00,74.22649476 2013-10-10 19:00:00,74.89181277 2013-10-10 20:00:00,76.03381278 2013-10-10 21:00:00,75.75160616 2013-10-10 22:00:00,75.35499490000002 2013-10-10 23:00:00,75.3520882 2013-10-11 00:00:00,75.59122877 2013-10-11 01:00:00,74.60615095 2013-10-11 02:00:00,73.66657269 2013-10-11 03:00:00,75.29576071 2013-10-11 04:00:00,73.07467638 2013-10-11 05:00:00,73.54096289 2013-10-11 06:00:00,73.56748044 2013-10-11 07:00:00,72.23943668 2013-10-11 08:00:00,72.98971633 2013-10-11 09:00:00,71.8624757 2013-10-11 10:00:00,72.15907086 2013-10-11 11:00:00,73.28710779 2013-10-11 12:00:00,73.23267068 2013-10-11 13:00:00,72.91831075 2013-10-11 14:00:00,74.13951981 2013-10-11 15:00:00,73.91840559 2013-10-11 16:00:00,74.05658495 2013-10-11 17:00:00,74.4819446 2013-10-11 18:00:00,75.13591435 2013-10-11 19:00:00,75.68312614 2013-10-11 20:00:00,74.4794284 2013-10-14 19:00:00,72.98303434 2013-10-14 20:00:00,73.97904439 2013-10-14 21:00:00,72.80960896 2013-10-14 22:00:00,74.45908003 2013-10-14 23:00:00,73.22449615 2013-10-15 00:00:00,74.08849517 2013-10-15 01:00:00,72.09427723 2013-10-15 02:00:00,73.30412261 2013-10-15 03:00:00,72.49226170000001 2013-10-15 04:00:00,71.55592659 2013-10-15 05:00:00,71.92880201 2013-10-15 06:00:00,72.20455302 2013-10-15 07:00:00,71.5729309 2013-10-15 08:00:00,71.38455809 2013-10-15 09:00:00,71.57838797 2013-10-15 10:00:00,72.33092601 2013-10-15 11:00:00,72.5020361 2013-10-15 12:00:00,72.16890223 2013-10-15 13:00:00,71.80124576 2013-10-15 14:00:00,71.98653741 2013-10-15 15:00:00,73.57829998 2013-10-15 16:00:00,73.76993449 2013-10-15 17:00:00,73.90520817 2013-10-15 18:00:00,73.88052554 2013-10-15 19:00:00,72.72460722 2013-10-15 20:00:00,73.87825084 2013-10-15 21:00:00,73.1538236 2013-10-15 22:00:00,74.25507299 2013-10-15 23:00:00,72.78303586 2013-10-16 00:00:00,72.70043711 2013-10-16 01:00:00,72.55484862 2013-10-16 02:00:00,72.52805707 2013-10-16 03:00:00,73.14618943 2013-10-16 04:00:00,71.23182363 2013-10-16 05:00:00,72.41740232 2013-10-16 06:00:00,71.66301343 2013-10-16 07:00:00,71.06682037 2013-10-16 08:00:00,72.17174017 2013-10-16 09:00:00,71.98736373 2013-10-16 10:00:00,71.53260775 2013-10-16 11:00:00,72.36545699 2013-10-16 12:00:00,72.78437383 2013-10-16 13:00:00,71.97296390000002 2013-10-16 14:00:00,72.4644608 2013-10-16 15:00:00,72.62455626 2013-10-16 16:00:00,73.55532127 2013-10-16 17:00:00,72.89143683 2013-10-16 18:00:00,74.21730356 2013-10-16 19:00:00,75.25147517 2013-10-16 20:00:00,75.28003046 2013-10-16 21:00:00,73.45611639 2013-10-16 22:00:00,67.59220788 2013-10-16 23:00:00,74.3959065 2013-10-17 00:00:00,72.76152535 2013-10-17 01:00:00,72.84667905 2013-10-17 02:00:00,74.06782481 2013-10-17 03:00:00,73.40328569 2013-10-17 04:00:00,72.4928657 2013-10-17 05:00:00,72.36963864 2013-10-17 06:00:00,70.63012656 2013-10-17 07:00:00,70.32611117 2013-10-17 08:00:00,71.46025104 2013-10-17 09:00:00,71.14590855 2013-10-17 10:00:00,71.46817075 2013-10-17 11:00:00,71.41876211 2013-10-17 12:00:00,72.99363734 2013-10-17 13:00:00,72.24666709 2013-10-17 14:00:00,73.45167119 2013-10-17 15:00:00,74.39956072 2013-10-17 16:00:00,72.81416628 2013-10-17 17:00:00,73.03240204 2013-10-17 18:00:00,75.04333658 2013-10-17 19:00:00,73.92938757 2013-10-17 20:00:00,73.81507515 2013-10-17 21:00:00,74.08455767 2013-10-17 22:00:00,73.38180602 2013-10-17 23:00:00,73.23701247 2013-10-18 00:00:00,72.99037413 2013-10-18 01:00:00,72.99012950000002 2013-10-18 02:00:00,72.66562134 2013-10-18 03:00:00,72.51950292 2013-10-18 04:00:00,72.45390193 2013-10-18 05:00:00,72.03998157 2013-10-18 06:00:00,72.47195408 2013-10-18 07:00:00,72.34968064 2013-10-18 08:00:00,71.45220535 2013-10-18 09:00:00,71.55743829999999 2013-10-18 10:00:00,72.63790855 2013-10-18 11:00:00,71.85849263 2013-10-18 12:00:00,72.93395917 2013-10-18 13:00:00,72.38591831 2013-10-18 14:00:00,73.80702055 2013-10-18 15:00:00,73.52710171 2013-10-18 16:00:00,74.83471181 2013-10-18 17:00:00,74.21326248 2013-10-18 18:00:00,73.25223693 2013-10-18 19:00:00,73.93628199999998 2013-10-18 20:00:00,73.04669143 2013-10-18 21:00:00,73.08417829999998 2013-10-18 22:00:00,74.19287354 2013-10-18 23:00:00,73.41808921 2013-10-19 00:00:00,74.12963911 2013-10-19 01:00:00,73.46278565 2013-10-19 02:00:00,73.62789649 2013-10-19 03:00:00,71.92833946 2013-10-19 04:00:00,72.26119661 2013-10-19 05:00:00,71.47946165 2013-10-19 06:00:00,72.63321496 2013-10-19 07:00:00,72.24354039 2013-10-19 08:00:00,71.57056509 2013-10-19 09:00:00,72.2797028 2013-10-19 10:00:00,73.01911793 2013-10-19 11:00:00,71.61445258 2013-10-19 12:00:00,71.26409105 2013-10-19 13:00:00,71.75373049 2013-10-19 14:00:00,72.57075359 2013-10-19 15:00:00,71.7959401 2013-10-19 16:00:00,71.53861613 2013-10-19 17:00:00,70.90022339 2013-10-19 18:00:00,71.73254786 2013-10-19 19:00:00,71.71309029999998 2013-10-19 20:00:00,72.76010528 2013-10-19 21:00:00,72.84417558 2013-10-19 22:00:00,71.99223058 2013-10-19 23:00:00,71.70725001 2013-10-20 00:00:00,71.71438532 2013-10-20 01:00:00,72.55191183 2013-10-20 02:00:00,71.03928043 2013-10-20 03:00:00,71.46046414 2013-10-20 04:00:00,71.99130446 2013-10-20 05:00:00,71.45046564 2013-10-20 06:00:00,71.51504432 2013-10-20 07:00:00,70.99280008 2013-10-20 08:00:00,71.34776909 2013-10-20 09:00:00,70.72845843 2013-10-20 10:00:00,70.27507626 2013-10-20 11:00:00,70.27111929 2013-10-20 12:00:00,70.85408914 2013-10-20 13:00:00,69.94855497 2013-10-20 14:00:00,69.53492069 2013-10-20 15:00:00,70.92058525 2013-10-20 16:00:00,70.99850582 2013-10-20 17:00:00,71.05686947 2013-10-20 18:00:00,72.14843798 2013-10-20 19:00:00,71.45617637 2013-10-20 20:00:00,73.27200083 2013-10-20 21:00:00,71.80063059 2013-10-20 22:00:00,73.01762667 2013-10-20 23:00:00,72.12768954 2013-10-21 00:00:00,73.33199587 2013-10-21 01:00:00,73.21702132 2013-10-21 02:00:00,72.41071376 2013-10-21 03:00:00,72.12548765 2013-10-21 04:00:00,73.03066312 2013-10-21 05:00:00,71.54792939 2013-10-21 06:00:00,72.74034991 2013-10-21 07:00:00,71.35108732 2013-10-21 08:00:00,71.40181091 2013-10-21 09:00:00,72.12977881 2013-10-21 10:00:00,72.31327617 2013-10-21 11:00:00,71.50759292 2013-10-21 12:00:00,73.42790189 2013-10-21 13:00:00,74.33787739 2013-10-21 14:00:00,73.42943331 2013-10-21 15:00:00,72.64800749999998 2013-10-21 16:00:00,74.48313565 2013-10-21 17:00:00,73.37484563 2013-10-21 18:00:00,74.54468294 2013-10-21 19:00:00,74.91468608 2013-10-21 20:00:00,74.48188759 2013-10-21 21:00:00,73.21984661 2013-10-21 22:00:00,73.46717767 2013-10-21 23:00:00,73.43538257 2013-10-22 00:00:00,74.11014418 2013-10-22 01:00:00,74.0856674 2013-10-22 02:00:00,74.43241463 2013-10-22 03:00:00,74.304057 2013-10-22 04:00:00,73.43146696 2013-10-22 05:00:00,72.49383421 2013-10-22 06:00:00,73.03216682 2013-10-22 07:00:00,71.83335039 2013-10-22 08:00:00,71.01856015 2013-10-22 09:00:00,72.21563105 2013-10-22 10:00:00,72.48771792 2013-10-22 11:00:00,72.7382649 2013-10-22 12:00:00,73.60978997 2013-10-22 13:00:00,73.74620023 2013-10-22 14:00:00,73.23713965 2013-10-22 15:00:00,73.4530571 2013-10-22 16:00:00,73.92328043 2013-10-22 17:00:00,75.18250744 2013-10-22 18:00:00,74.02490252 2013-10-22 19:00:00,75.3285915 2013-10-22 20:00:00,74.66865644 2013-10-22 21:00:00,74.14984749 2013-10-22 22:00:00,74.89985381 2013-10-22 23:00:00,75.30346611 2013-10-23 00:00:00,73.91031296 2013-10-23 01:00:00,73.93275037 2013-10-23 02:00:00,73.16148058 2013-10-23 03:00:00,73.52562326 2013-10-23 04:00:00,72.47484370000002 2013-10-23 05:00:00,72.49504420000002 2013-10-23 06:00:00,71.61991048 2013-10-23 07:00:00,73.22943968 2013-10-23 08:00:00,71.58909683 2013-10-23 09:00:00,71.81584418 2013-10-23 10:00:00,71.34809224 2013-10-23 11:00:00,72.96869218 2013-10-23 12:00:00,72.55053234 2013-10-23 13:00:00,72.57797464 2013-10-23 14:00:00,74.69536550000002 2013-10-23 15:00:00,74.1296061 2013-10-23 16:00:00,73.94533205 2013-10-23 17:00:00,74.07901132 2013-10-23 18:00:00,75.05479911 2013-10-23 19:00:00,74.85789892 2013-10-23 20:00:00,76.0974356 2013-10-23 21:00:00,75.60625767 2013-10-23 22:00:00,76.460003 2013-10-23 23:00:00,75.95853846 2013-10-24 00:00:00,75.66920488 2013-10-24 01:00:00,76.19819465 2013-10-24 02:00:00,74.83838032 2013-10-24 03:00:00,75.34256101 2013-10-24 04:00:00,75.63691814 2013-10-24 05:00:00,76.00126612 2013-10-24 06:00:00,74.28973725 2013-10-24 07:00:00,74.80605955 2013-10-24 08:00:00,75.30172567 2013-10-24 09:00:00,74.34735395 2013-10-24 10:00:00,75.12651355 2013-10-24 11:00:00,73.75813908 2013-10-24 12:00:00,75.04085467 2013-10-24 13:00:00,74.7295084 2013-10-24 14:00:00,75.23496324 2013-10-24 15:00:00,74.09558127 2013-10-24 16:00:00,75.40924951 2013-10-24 17:00:00,75.05840643 2013-10-24 18:00:00,75.20790637 2013-10-24 19:00:00,73.69135931 2013-10-24 20:00:00,73.54196014 2013-10-24 21:00:00,75.19082042 2013-10-24 22:00:00,74.60746814 2013-10-24 23:00:00,74.53993625 2013-10-25 00:00:00,73.4168865 2013-10-25 01:00:00,73.95852383 2013-10-25 02:00:00,73.75006416 2013-10-25 03:00:00,74.14389026 2013-10-25 04:00:00,72.51791753 2013-10-25 05:00:00,73.6608867 2013-10-25 06:00:00,71.99874820000002 2013-10-25 07:00:00,72.38400327 2013-10-25 08:00:00,72.51858237 2013-10-25 09:00:00,71.55343537 2013-10-25 10:00:00,72.55778642 2013-10-25 11:00:00,71.96670972 2013-10-25 12:00:00,72.36781957 2013-10-25 13:00:00,72.69666807 2013-10-25 14:00:00,72.75559541 2013-10-25 15:00:00,73.59062056 2013-10-25 16:00:00,73.17199341 2013-10-25 17:00:00,74.06972966 2013-10-25 18:00:00,74.49830916 2013-10-25 19:00:00,73.95696452 2013-10-25 20:00:00,73.63058672 2013-10-25 21:00:00,73.49661513 2013-10-25 22:00:00,75.0238628 2013-10-25 23:00:00,73.41067783 2013-10-26 00:00:00,74.43789627 2013-10-26 01:00:00,73.69728217 2013-10-26 02:00:00,72.79073013 2013-10-26 03:00:00,74.02303394 2013-10-26 04:00:00,73.99547327 2013-10-26 05:00:00,72.63698998 2013-10-26 06:00:00,72.65022647 2013-10-26 07:00:00,71.45778273 2013-10-26 08:00:00,73.30880143 2013-10-26 09:00:00,71.88486246 2013-10-26 10:00:00,72.3666265 2013-10-26 11:00:00,71.51972021 2013-10-26 12:00:00,71.73511359 2013-10-26 13:00:00,72.78641155 2013-10-26 14:00:00,71.38856419 2013-10-26 15:00:00,72.18526942 2013-10-26 16:00:00,73.51448987 2013-10-26 17:00:00,73.57199426 2013-10-26 18:00:00,72.91075318 2013-10-26 19:00:00,73.81514959 2013-10-26 20:00:00,72.68504592 2013-10-26 21:00:00,74.08911438 2013-10-26 22:00:00,72.9589277 2013-10-26 23:00:00,73.14610095 2013-10-27 00:00:00,73.78917147 2013-10-27 01:00:00,72.79764335 2013-10-27 02:00:00,73.85796513 2013-10-27 03:00:00,73.14750042 2013-10-27 04:00:00,73.68655845 2013-10-27 05:00:00,71.99772202 2013-10-27 06:00:00,71.98066434 2013-10-27 07:00:00,72.34138543 2013-10-27 08:00:00,72.73493389 2013-10-27 09:00:00,71.65669486 2013-10-27 10:00:00,71.49563964 2013-10-27 11:00:00,72.5480017 2013-10-27 12:00:00,71.57221259 2013-10-27 13:00:00,72.7741422 2013-10-27 14:00:00,72.50897204 2013-10-27 15:00:00,72.37165679 2013-10-27 16:00:00,71.76151786 2013-10-27 17:00:00,71.14297184 2013-10-27 18:00:00,71.17422664 2013-10-27 19:00:00,72.7253094 2013-10-27 20:00:00,71.85317981 2013-10-27 21:00:00,72.85663059 2013-10-27 22:00:00,71.76247182 2013-10-27 23:00:00,71.69635699999998 2013-10-28 00:00:00,70.92483713 2013-10-28 01:00:00,71.43725419 2013-10-28 02:00:00,72.13600699999998 2013-10-28 03:00:00,70.64687742 2013-10-28 04:00:00,70.22032111 2013-10-28 05:00:00,69.75235982 2013-10-28 06:00:00,71.33829611 2013-10-28 07:00:00,69.61769321 2013-10-28 08:00:00,70.75591875 2013-10-28 09:00:00,71.47646234 2013-10-28 10:00:00,71.59381864 2013-10-28 11:00:00,70.66816135 2013-10-28 12:00:00,73.12430398 2013-10-28 13:00:00,72.97024298 2013-10-28 14:00:00,73.74160859999998 2013-10-28 15:00:00,73.95406465 2013-10-28 16:00:00,73.45808119 2013-10-28 17:00:00,73.14484568 2013-10-28 18:00:00,74.48764885 2013-10-28 19:00:00,73.40434954 2013-10-28 20:00:00,73.32924842 2013-10-28 21:00:00,74.46460516 2013-10-28 22:00:00,74.68612326 2013-10-28 23:00:00,73.64400862 2013-10-29 00:00:00,73.05155138 2013-10-29 01:00:00,73.20917824 2013-10-29 02:00:00,72.9686264 2013-10-29 03:00:00,73.44971023 2013-10-29 04:00:00,73.55495921 2013-10-29 05:00:00,71.69592455 2013-10-29 06:00:00,73.53646843 2013-10-29 07:00:00,72.02971426 2013-10-29 08:00:00,73.42081575 2013-10-29 09:00:00,72.58490985 2013-10-29 10:00:00,73.0300541 2013-10-29 11:00:00,73.33546169 2013-10-29 12:00:00,73.69525708 2013-10-29 13:00:00,74.44248772 2013-10-29 14:00:00,73.36288859 2013-10-29 15:00:00,74.23441848 2013-10-29 16:00:00,73.53614618 2013-10-29 17:00:00,73.55358243 2013-10-29 18:00:00,73.31606619 2013-10-29 19:00:00,74.07121348 2013-10-29 20:00:00,73.84322808 2013-10-29 21:00:00,74.31880636 2013-10-29 22:00:00,75.37365059999998 2013-10-29 23:00:00,74.6158649 2013-10-30 00:00:00,74.22361987 2013-10-30 01:00:00,74.90183652 2013-10-30 02:00:00,74.60288205 2013-10-30 03:00:00,73.60468314 2013-10-30 04:00:00,74.41600686 2013-10-30 05:00:00,74.16088548 2013-10-30 06:00:00,72.84884222 2013-10-30 07:00:00,72.92107082 2013-10-30 08:00:00,73.01604281 2013-10-30 09:00:00,74.13143498 2013-10-30 10:00:00,72.57848043 2013-10-30 11:00:00,72.87188536 2013-10-30 12:00:00,73.61682058 2013-10-30 13:00:00,73.37016715 2013-10-30 14:00:00,74.04450691 2013-10-30 15:00:00,74.12361236 2013-10-30 16:00:00,74.66328477 2013-10-30 17:00:00,75.70737338 2013-10-30 18:00:00,75.3545802 2013-10-30 19:00:00,75.25614118 2013-10-30 20:00:00,74.87355721 2013-10-30 21:00:00,76.29745203 2013-10-30 22:00:00,75.32289320000002 2013-10-30 23:00:00,75.85634859999998 2013-10-31 00:00:00,75.14595644 2013-10-31 01:00:00,75.88962012 2013-10-31 02:00:00,76.4180307 2013-10-31 03:00:00,76.56197890000001 2013-10-31 04:00:00,76.10597378 2013-10-31 05:00:00,75.25141922 2013-10-31 06:00:00,75.72435817 2013-10-31 07:00:00,74.49878947 2013-10-31 08:00:00,75.84183322 2013-10-31 09:00:00,75.2866983 2013-10-31 10:00:00,74.87398102 2013-10-31 11:00:00,74.94194615 2013-10-31 12:00:00,75.98035652 2013-10-31 13:00:00,74.95842691 2013-10-31 14:00:00,75.24512346 2013-10-31 15:00:00,75.35692048 2013-10-31 16:00:00,76.88500697 2013-10-31 17:00:00,76.12766594 2013-10-31 18:00:00,75.86319296 2013-10-31 19:00:00,76.41346624 2013-10-31 20:00:00,75.5347714 2013-10-31 21:00:00,75.84580103 2013-10-31 22:00:00,76.34558396 2013-10-31 23:00:00,77.39292354 2013-11-01 00:00:00,76.30796353 2013-11-01 01:00:00,77.25259793 2013-11-01 02:00:00,76.43178992 2013-11-01 03:00:00,77.69772574 2013-11-01 04:00:00,76.53784364 2013-11-01 05:00:00,76.38649065 2013-11-01 06:00:00,77.20675318 2013-11-01 07:00:00,77.18738382 2013-11-01 08:00:00,75.67736243 2013-11-01 09:00:00,74.81300493 2013-11-01 10:00:00,75.83696911 2013-11-01 11:00:00,75.02326067 2013-11-01 12:00:00,75.05073943 2013-11-01 13:00:00,75.28745236 2013-11-01 14:00:00,75.20319345 2013-11-01 15:00:00,75.12528566 2013-11-01 16:00:00,75.19924971 2013-11-01 17:00:00,75.73098218 2013-11-01 18:00:00,75.93704108 2013-11-01 19:00:00,74.89355303 2013-11-01 20:00:00,75.07774926 2013-11-01 21:00:00,75.25618705 2013-11-01 22:00:00,75.71797654 2013-11-01 23:00:00,75.63395379 2013-11-02 00:00:00,75.48381386 2013-11-02 01:00:00,75.66762937 2013-11-02 02:00:00,76.51474357 2013-11-02 03:00:00,75.08953119 2013-11-02 04:00:00,75.81216694 2013-11-02 05:00:00,75.60610346 2013-11-02 06:00:00,74.96367140000002 2013-11-02 07:00:00,74.98121493 2013-11-02 08:00:00,74.45643905 2013-11-02 09:00:00,75.51516542 2013-11-02 10:00:00,74.73560812 2013-11-02 11:00:00,74.69915087 2013-11-02 12:00:00,74.54298971 2013-11-02 13:00:00,73.35219351 2013-11-02 14:00:00,74.12383795 2013-11-02 15:00:00,74.22554631 2013-11-02 16:00:00,73.99079534 2013-11-02 17:00:00,74.79507379 2013-11-02 18:00:00,76.11205116 2013-11-02 19:00:00,75.22593768 2013-11-02 20:00:00,75.27953666 2013-11-02 21:00:00,77.15937503 2013-11-02 22:00:00,76.19111223 2013-11-02 23:00:00,76.31079818 2013-11-03 00:00:00,76.38206634 2013-11-03 01:00:00,75.57825005 2013-11-03 02:00:00,76.13455079999999 2013-11-03 03:00:00,75.23603382 2013-11-03 04:00:00,76.23782807 2013-11-03 05:00:00,75.336605 2013-11-03 06:00:00,74.36531352 2013-11-03 07:00:00,73.71769524 2013-11-03 08:00:00,74.074138 2013-11-03 09:00:00,74.84189513 2013-11-03 10:00:00,73.95914727 2013-11-03 11:00:00,74.04130502 2013-11-03 12:00:00,74.56437617 2013-11-03 13:00:00,73.29808803 2013-11-03 14:00:00,73.53188681 2013-11-03 15:00:00,73.87759563 2013-11-03 16:00:00,74.87971926 2013-11-03 17:00:00,74.1892936 2013-11-03 18:00:00,75.41399344 2013-11-03 19:00:00,75.86744504 2013-11-03 20:00:00,75.6150603 2013-11-03 21:00:00,76.97153329 2013-11-03 22:00:00,77.0894334 2013-11-03 23:00:00,76.17299187 2013-11-04 00:00:00,75.60827582 2013-11-04 01:00:00,76.66746590000002 2013-11-04 02:00:00,76.59056219 2013-11-04 03:00:00,75.05998404 2013-11-04 04:00:00,75.88379996 2013-11-04 05:00:00,75.47865146 2013-11-04 06:00:00,74.4588194 2013-11-04 07:00:00,73.60738959 2013-11-04 08:00:00,74.41420743 2013-11-04 09:00:00,74.765766 2013-11-04 10:00:00,74.16291232 2013-11-04 11:00:00,74.19468656 2013-11-04 12:00:00,74.43225537 2013-11-04 13:00:00,74.24359177 2013-11-04 14:00:00,74.55720475 2013-11-04 15:00:00,75.76889616 2013-11-04 16:00:00,75.5197806 2013-11-04 17:00:00,74.72805694 2013-11-04 18:00:00,75.06364679 2013-11-04 19:00:00,75.92542961 2013-11-04 20:00:00,75.03438753 2013-11-04 21:00:00,75.53025670000002 2013-11-04 22:00:00,76.20838186 2013-11-04 23:00:00,75.88011467 2013-11-05 00:00:00,75.25305005 2013-11-05 01:00:00,76.16092035 2013-11-05 02:00:00,74.87732367 2013-11-05 03:00:00,75.70725229 2013-11-05 04:00:00,74.62446294 2013-11-05 05:00:00,73.93894725 2013-11-05 06:00:00,75.39833336 2013-11-05 07:00:00,73.67042395 2013-11-05 08:00:00,74.78394113 2013-11-05 09:00:00,75.36637593 2013-11-05 10:00:00,75.62678541 2013-11-05 11:00:00,75.54245470000002 2013-11-05 12:00:00,75.56486359 2013-11-05 13:00:00,75.40045594 2013-11-05 14:00:00,75.72241656 2013-11-05 15:00:00,75.38360735 2013-11-05 16:00:00,74.96366192 2013-11-05 17:00:00,75.15506847 2013-11-05 18:00:00,76.44462418 2013-11-05 19:00:00,76.14152676 2013-11-05 20:00:00,77.7365963 2013-11-05 21:00:00,75.94504175 2013-11-05 22:00:00,77.66560315 2013-11-05 23:00:00,77.14421695 2013-11-06 00:00:00,77.14840943 2013-11-06 01:00:00,76.57972961 2013-11-06 02:00:00,75.67263157 2013-11-06 03:00:00,75.55554775 2013-11-06 04:00:00,76.02875358 2013-11-06 05:00:00,75.83856917 2013-11-06 06:00:00,76.72809013 2013-11-06 07:00:00,76.8067863 2013-11-06 08:00:00,76.14957763 2013-11-06 09:00:00,74.72851186 2013-11-06 10:00:00,76.79427945 2013-11-06 11:00:00,75.54402995 2013-11-06 12:00:00,75.62375922 2013-11-06 13:00:00,75.66503039 2013-11-06 14:00:00,76.1298699 2013-11-06 15:00:00,75.2965713 2013-11-06 16:00:00,75.65848549 2013-11-06 17:00:00,75.77541647 2013-11-06 18:00:00,75.7226112 2013-11-06 19:00:00,75.17457270000001 2013-11-06 20:00:00,76.75484571 2013-11-06 21:00:00,76.17423765 2013-11-06 22:00:00,76.11021976 2013-11-06 23:00:00,77.62413958 2013-11-07 00:00:00,76.47954412 2013-11-07 01:00:00,77.95666612 2013-11-07 02:00:00,77.26824525 2013-11-07 03:00:00,76.93680905 2013-11-07 04:00:00,77.33274264 2013-11-07 05:00:00,75.89490524 2013-11-07 06:00:00,76.97245983 2013-11-07 07:00:00,76.44928327 2013-11-07 08:00:00,76.38799696 2013-11-07 09:00:00,76.09948105 2013-11-07 10:00:00,76.81359962 2013-11-07 11:00:00,75.10202225 2013-11-07 12:00:00,75.6896651 2013-11-07 13:00:00,76.31908661 2013-11-07 14:00:00,76.23526528 2013-11-07 15:00:00,75.71330856 2013-11-07 16:00:00,75.27910715 2013-11-07 17:00:00,75.6502543 2013-11-07 18:00:00,76.21250234 2013-11-07 19:00:00,77.10759799 2013-11-07 20:00:00,76.93375995 2013-11-07 21:00:00,75.77571222 2013-11-07 22:00:00,75.93642846 2013-11-07 23:00:00,75.42451794 2013-11-08 00:00:00,75.74984119 2013-11-08 01:00:00,75.72379288 2013-11-08 02:00:00,76.19812769 2013-11-08 03:00:00,76.40959723 2013-11-08 04:00:00,76.17249971 2013-11-08 05:00:00,74.18157735 2013-11-08 06:00:00,75.54911204 2013-11-08 07:00:00,74.92685622 2013-11-08 08:00:00,74.06821774 2013-11-08 09:00:00,74.6063132 2013-11-08 10:00:00,74.59934737 2013-11-08 11:00:00,74.57257027 2013-11-08 12:00:00,75.80192985 2013-11-08 13:00:00,75.58576634 2013-11-08 14:00:00,75.80339835 2013-11-08 15:00:00,74.95083817 2013-11-08 16:00:00,74.30202352 2013-11-08 17:00:00,74.30126215 2013-11-08 18:00:00,74.56143904 2013-11-08 19:00:00,74.80702056 2013-11-08 20:00:00,73.81540339 2013-11-08 21:00:00,74.46177933 2013-11-08 22:00:00,73.33340389 2013-11-08 23:00:00,73.13844142 2013-11-09 00:00:00,74.43327812 2013-11-09 01:00:00,73.55423309999998 2013-11-09 02:00:00,74.72110603 2013-11-09 03:00:00,73.50877487 2013-11-09 04:00:00,74.83946496 2013-11-09 05:00:00,73.55614636 2013-11-09 06:00:00,73.07126074 2013-11-09 07:00:00,72.82584529 2013-11-09 08:00:00,72.95550534 2013-11-09 09:00:00,73.64826422 2013-11-09 10:00:00,73.4784976 2013-11-09 11:00:00,73.16790935 2013-11-09 12:00:00,72.25990891 2013-11-09 13:00:00,73.22695232 2013-11-09 14:00:00,73.36574509999998 2013-11-09 15:00:00,72.78698119 2013-11-09 16:00:00,73.23132790000003 2013-11-09 17:00:00,73.06305918 2013-11-09 18:00:00,73.23528333 2013-11-09 19:00:00,73.95548531 2013-11-09 20:00:00,73.98859537 2013-11-09 21:00:00,73.18927798 2013-11-09 22:00:00,73.48796428 2013-11-09 23:00:00,73.23741435 2013-11-10 00:00:00,74.54367695 2013-11-10 01:00:00,73.43081550000002 2013-11-10 02:00:00,74.74891586 2013-11-10 03:00:00,74.75362909 2013-11-10 04:00:00,72.86175442 2013-11-10 05:00:00,72.73720269 2013-11-10 06:00:00,73.3559507 2013-11-10 07:00:00,73.39759537 2013-11-10 08:00:00,73.14595598 2013-11-10 09:00:00,73.76092178 2013-11-10 10:00:00,72.25168702 2013-11-10 11:00:00,73.13205651 2013-11-10 12:00:00,72.08360267 2013-11-10 13:00:00,72.07368375 2013-11-10 14:00:00,72.61268471 2013-11-10 15:00:00,73.72321874 2013-11-10 16:00:00,73.72849169 2013-11-10 17:00:00,73.13296089 2013-11-10 18:00:00,72.65494358 2013-11-10 19:00:00,72.32299088 2013-11-10 20:00:00,73.55015881 2013-11-10 21:00:00,73.72223486 2013-11-10 22:00:00,72.25297108 2013-11-10 23:00:00,72.31541006 2013-11-11 00:00:00,72.76195068 2013-11-11 01:00:00,73.76142519 2013-11-11 02:00:00,73.10583663 2013-11-11 03:00:00,73.50193935 2013-11-11 04:00:00,73.49132918 2013-11-11 05:00:00,72.41669997 2013-11-11 06:00:00,73.04263579 2013-11-11 07:00:00,72.31388627 2013-11-11 08:00:00,71.53125555 2013-11-11 09:00:00,72.51297974 2013-11-11 10:00:00,73.05072318 2013-11-11 11:00:00,72.93039079 2013-11-11 12:00:00,72.68112696 2013-11-11 13:00:00,74.10651227 2013-11-11 14:00:00,73.20678582 2013-11-11 15:00:00,73.97883407 2013-11-11 16:00:00,74.29101178 2013-11-11 17:00:00,75.92300396 2013-11-11 18:00:00,75.09551863 2013-11-11 19:00:00,74.50642676 2013-11-11 20:00:00,75.29868809 2013-11-11 21:00:00,74.81087057 2013-11-11 22:00:00,75.04623283 2013-11-11 23:00:00,75.27267490000001 2013-11-12 00:00:00,74.35723061 2013-11-12 01:00:00,75.59912555 2013-11-12 02:00:00,75.38508019 2013-11-12 03:00:00,74.01849770000003 2013-11-12 04:00:00,74.67643353 2013-11-12 05:00:00,74.23187951 2013-11-12 06:00:00,73.23464912 2013-11-12 07:00:00,72.9246375 2013-11-12 08:00:00,73.50042577 2013-11-12 09:00:00,73.9103724 2013-11-12 10:00:00,73.36473041 2013-11-12 11:00:00,74.56847369 2013-11-12 12:00:00,73.01626683 2013-11-12 13:00:00,74.58986064 2013-11-12 14:00:00,74.79361415 2013-11-12 15:00:00,74.62816075 2013-11-12 16:00:00,73.48499084 2013-11-12 17:00:00,74.83572629999998 2013-11-12 18:00:00,75.71863379 2013-11-12 19:00:00,74.10748463 2013-11-12 20:00:00,76.18679389 2013-11-12 21:00:00,75.68515368 2013-11-12 22:00:00,75.95116314 2013-11-12 23:00:00,75.27091748 2013-11-13 00:00:00,75.10698746 2013-11-13 01:00:00,75.50230648 2013-11-13 02:00:00,74.96947424 2013-11-13 03:00:00,74.66135819 2013-11-13 04:00:00,74.16500932 2013-11-13 05:00:00,73.61945248 2013-11-13 06:00:00,73.04705436 2013-11-13 07:00:00,73.10898413 2013-11-13 08:00:00,73.14571961 2013-11-13 09:00:00,73.13454489 2013-11-13 10:00:00,73.63776206 2013-11-13 11:00:00,72.51683568 2013-11-13 12:00:00,74.15631949 2013-11-13 13:00:00,73.16933890000001 2013-11-13 14:00:00,74.42966035 2013-11-13 15:00:00,73.93593742 2013-11-13 16:00:00,74.0165059 2013-11-13 17:00:00,75.64136409999998 2013-11-13 18:00:00,75.49191161 2013-11-13 19:00:00,74.71810201 2013-11-13 20:00:00,75.30978555 2013-11-13 21:00:00,75.66631972 2013-11-13 22:00:00,76.3113897 2013-11-13 23:00:00,75.93818590000002 2013-11-14 00:00:00,75.28806128 2013-11-14 01:00:00,74.04154576 2013-11-14 02:00:00,75.03847755 2013-11-14 03:00:00,74.23765297 2013-11-14 04:00:00,74.41627738 2013-11-14 05:00:00,72.52116762 2013-11-14 06:00:00,72.25396537 2013-11-14 07:00:00,73.35919816 2013-11-14 08:00:00,73.3005709 2013-11-14 09:00:00,71.94989116 2013-11-14 10:00:00,72.70754191 2013-11-14 11:00:00,73.57919806 2013-11-14 12:00:00,73.71447163 2013-11-14 13:00:00,73.20962568 2013-11-14 14:00:00,73.60901764 2013-11-14 15:00:00,73.39056823 2013-11-14 16:00:00,74.84991329 2013-11-14 17:00:00,75.29117938 2013-11-14 18:00:00,75.05266772 2013-11-14 19:00:00,73.87313966 2013-11-14 20:00:00,73.88685052 2013-11-14 21:00:00,75.32457686 2013-11-14 22:00:00,74.52795985 2013-11-14 23:00:00,74.50517038 2013-11-15 00:00:00,75.28019509999999 2013-11-15 01:00:00,73.39054569 2013-11-15 02:00:00,73.61502322 2013-11-15 03:00:00,73.40129594 2013-11-15 04:00:00,72.71904624 2013-11-15 05:00:00,73.04163914 2013-11-15 06:00:00,71.66850691 2013-11-15 07:00:00,72.44293549 2013-11-15 08:00:00,72.77424531 2013-11-15 09:00:00,71.02651442 2013-11-15 10:00:00,72.46122501 2013-11-15 11:00:00,72.053069 2013-11-15 12:00:00,71.43164940000003 2013-11-15 13:00:00,73.5399011 2013-11-15 14:00:00,73.32159625 2013-11-15 15:00:00,74.17128378 2013-11-15 16:00:00,73.44249817 2013-11-15 17:00:00,73.84389329999998 2013-11-15 18:00:00,74.32478195 2013-11-15 19:00:00,74.33059913 2013-11-15 20:00:00,74.50938842 2013-11-15 21:00:00,74.18876225 2013-11-15 22:00:00,73.26010958 2013-11-15 23:00:00,72.71542581 2013-11-16 00:00:00,72.91699629 2013-11-16 01:00:00,72.72921375 2013-11-16 02:00:00,72.00496338 2013-11-16 03:00:00,72.91473652 2013-11-16 04:00:00,72.22070042 2013-11-16 05:00:00,72.19057869 2013-11-16 06:00:00,72.75354149 2013-11-16 07:00:00,70.85140062 2013-11-16 08:00:00,72.60434778 2013-11-16 09:00:00,72.2513124 2013-11-16 10:00:00,72.44304869 2013-11-16 11:00:00,71.82902242 2013-11-16 12:00:00,72.13432831 2013-11-16 13:00:00,72.28302117 2013-11-16 14:00:00,70.87841589 2013-11-16 15:00:00,70.5596423 2013-11-16 16:00:00,71.49929374 2013-11-16 17:00:00,70.91004612 2013-11-16 18:00:00,71.52840484 2013-11-16 19:00:00,71.62859496 2013-11-16 20:00:00,72.74468133 2013-11-16 21:00:00,71.59071961 2013-11-16 22:00:00,72.53877392 2013-11-16 23:00:00,72.67710054 2013-11-17 00:00:00,72.51924339 2013-11-17 01:00:00,72.53149628 2013-11-17 02:00:00,71.57898299 2013-11-17 03:00:00,72.42367877 2013-11-17 04:00:00,71.48775583 2013-11-17 05:00:00,71.06116079 2013-11-17 06:00:00,70.32136308 2013-11-17 07:00:00,71.8799218 2013-11-17 08:00:00,72.01945706 2013-11-17 09:00:00,71.02801335 2013-11-17 10:00:00,70.32011267 2013-11-17 11:00:00,70.43736052 2013-11-17 12:00:00,70.71326074 2013-11-17 13:00:00,71.29496969 2013-11-17 14:00:00,71.19238211 2013-11-17 15:00:00,70.76197992 2013-11-17 16:00:00,71.97783594 2013-11-17 17:00:00,71.93428932 2013-11-17 18:00:00,70.92727189 2013-11-17 19:00:00,70.69309796 2013-11-17 20:00:00,72.26337995 2013-11-17 21:00:00,71.59257385 2013-11-17 22:00:00,72.78595446 2013-11-17 23:00:00,72.51893435 2013-11-18 00:00:00,71.86984301 2013-11-18 01:00:00,72.26094927 2013-11-18 02:00:00,71.49387364 2013-11-18 03:00:00,71.34440084 2013-11-18 04:00:00,71.45222531 2013-11-18 05:00:00,71.07687116 2013-11-18 06:00:00,70.85817442 2013-11-18 07:00:00,70.94781553 2013-11-18 08:00:00,70.27853073 2013-11-18 09:00:00,69.32489169 2013-11-18 10:00:00,70.20579203 2013-11-18 11:00:00,70.38921093 2013-11-18 12:00:00,71.97995521 2013-11-18 13:00:00,71.09700465 2013-11-18 14:00:00,73.01321007 2013-11-18 15:00:00,72.74733169 2013-11-18 16:00:00,72.53910037 2013-11-18 17:00:00,73.35960207 2013-11-18 18:00:00,72.84142418 2013-11-18 19:00:00,74.43420638 2013-11-18 20:00:00,74.6164561 2013-11-18 21:00:00,74.22528903 2013-11-18 22:00:00,74.42442215 2013-11-18 23:00:00,73.14775012 2013-11-19 00:00:00,73.69107041 2013-11-19 01:00:00,74.03109935 2013-11-19 02:00:00,73.46135999 2013-11-19 03:00:00,72.49412233 2013-11-19 04:00:00,73.09658152 2013-11-19 05:00:00,73.46536527 2013-11-19 06:00:00,72.80605916 2013-11-19 07:00:00,71.59932742 2013-11-19 08:00:00,72.73375635 2013-11-19 09:00:00,73.27079545 2013-11-19 10:00:00,72.32538482 2013-11-19 11:00:00,71.96557762 2013-11-19 12:00:00,72.50861543 2013-11-19 13:00:00,72.20848244 2013-11-19 14:00:00,73.98532747 2013-11-19 15:00:00,73.77910642 2013-11-19 16:00:00,73.74309124 2013-11-19 17:00:00,75.62033656 2013-11-19 18:00:00,75.92989871 2013-11-19 19:00:00,76.14345589 2013-11-19 20:00:00,75.62712477 2013-11-19 21:00:00,76.09385992 2013-11-19 22:00:00,76.71081637 2013-11-19 23:00:00,76.04933698 2013-11-20 00:00:00,75.72755913 2013-11-20 01:00:00,75.51638547 2013-11-20 02:00:00,74.52746945 2013-11-20 03:00:00,74.48053719 2013-11-20 04:00:00,75.44810401 2013-11-20 05:00:00,73.87105555 2013-11-20 06:00:00,75.52376743 2013-11-20 07:00:00,73.59258353 2013-11-20 08:00:00,73.54086694 2013-11-20 09:00:00,74.60328237 2013-11-20 10:00:00,73.53405054 2013-11-20 11:00:00,73.18585771 2013-11-20 12:00:00,74.73396876 2013-11-20 13:00:00,74.00301199 2013-11-20 14:00:00,74.25992091 2013-11-20 15:00:00,75.3819048 2013-11-20 16:00:00,74.89925956 2013-11-20 17:00:00,74.95695549 2013-11-20 18:00:00,74.99328121 2013-11-20 19:00:00,76.8861063 2013-11-20 20:00:00,75.74120031 2013-11-20 21:00:00,77.29515004 2013-11-20 22:00:00,77.42615583 2013-11-20 23:00:00,77.57042544 2013-11-21 00:00:00,76.97148499 2013-11-21 01:00:00,76.55304852 2013-11-21 02:00:00,76.83218408 2013-11-21 03:00:00,76.76691174 2013-11-21 04:00:00,75.03003109 2013-11-21 05:00:00,76.13262453 2013-11-21 06:00:00,74.88298612 2013-11-21 07:00:00,74.75528879999997 2013-11-21 08:00:00,74.96824419 2013-11-21 09:00:00,74.38032373 2013-11-21 10:00:00,74.51502775 2013-11-21 11:00:00,75.03807231 2013-11-21 12:00:00,75.47315484 2013-11-21 13:00:00,74.28147702 2013-11-21 14:00:00,74.9158214 2013-11-21 15:00:00,74.73332116 2013-11-21 16:00:00,74.57659907 2013-11-21 17:00:00,75.13741621 2013-11-21 18:00:00,76.09123393 2013-11-21 19:00:00,75.48996689 2013-11-21 20:00:00,75.37277558 2013-11-21 21:00:00,74.86375645 2013-11-21 22:00:00,74.72416427 2013-11-21 23:00:00,75.88303251 2013-11-22 00:00:00,76.26881945 2013-11-22 01:00:00,74.40797403 2013-11-22 02:00:00,75.07100534 2013-11-22 03:00:00,75.22936273 2013-11-22 04:00:00,75.3850351 2013-11-22 05:00:00,74.12951939 2013-11-22 06:00:00,74.33830078 2013-11-22 07:00:00,73.13110340000001 2013-11-22 08:00:00,73.72892540000002 2013-11-22 09:00:00,73.47971521 2013-11-22 10:00:00,73.55503441 2013-11-22 11:00:00,73.21770574 2013-11-22 12:00:00,74.8002409 2013-11-22 13:00:00,75.10424352 2013-11-22 14:00:00,74.02504086 2013-11-22 15:00:00,75.99705923 2013-11-22 16:00:00,76.14728499 2013-11-22 17:00:00,75.97342391 2013-11-22 18:00:00,74.55135899 2013-11-22 19:00:00,75.52513628 2013-11-22 20:00:00,74.83841776 2013-11-22 21:00:00,75.86804316 2013-11-22 22:00:00,74.78322701 2013-11-22 23:00:00,74.93730171 2013-11-23 00:00:00,75.99533878 2013-11-23 01:00:00,74.9811996 2013-11-23 02:00:00,74.90004537 2013-11-23 03:00:00,74.45881512 2013-11-23 04:00:00,74.98859321 2013-11-23 05:00:00,74.80551896 2013-11-23 06:00:00,74.37725744 2013-11-23 07:00:00,73.23877045 2013-11-23 08:00:00,74.57228705 2013-11-23 09:00:00,73.61937989 2013-11-23 10:00:00,73.62510552 2013-11-23 11:00:00,73.89538449 2013-11-23 12:00:00,73.97705688 2013-11-23 13:00:00,73.49598319 2013-11-23 14:00:00,74.480482 2013-11-23 15:00:00,74.05324671 2013-11-23 16:00:00,72.99508362 2013-11-23 17:00:00,74.06252472 2013-11-23 18:00:00,74.31310832 2013-11-23 19:00:00,73.86600895 2013-11-23 20:00:00,74.72618679 2013-11-23 21:00:00,74.87409105 2013-11-23 22:00:00,75.16150552 2013-11-23 23:00:00,75.24524494 2013-11-24 00:00:00,76.06110472 2013-11-24 01:00:00,76.04876445 2013-11-24 02:00:00,75.92643826 2013-11-24 03:00:00,75.30896496 2013-11-24 04:00:00,73.85862031 2013-11-24 05:00:00,74.35243191 2013-11-24 06:00:00,73.22576335 2013-11-24 07:00:00,73.89709736 2013-11-24 08:00:00,73.45107827 2013-11-24 09:00:00,74.28662864 2013-11-24 10:00:00,73.11935916 2013-11-24 11:00:00,73.61847392 2013-11-24 12:00:00,73.95085216 2013-11-24 13:00:00,73.81302278 2013-11-24 14:00:00,74.47090026 2013-11-24 15:00:00,73.99949512 2013-11-24 16:00:00,74.01073568 2013-11-24 17:00:00,74.48269327 2013-11-24 18:00:00,74.99975789 2013-11-24 19:00:00,75.51838405 2013-11-24 20:00:00,74.91884001 2013-11-24 21:00:00,76.19947972 2013-11-24 22:00:00,76.37182291 2013-11-24 23:00:00,75.88886956 2013-11-25 00:00:00,75.8200126 2013-11-25 01:00:00,75.09124497 2013-11-25 02:00:00,76.15627384 2013-11-25 03:00:00,74.91899343 2013-11-25 04:00:00,74.96455081 2013-11-25 05:00:00,73.92706103 2013-11-25 06:00:00,74.79903613 2013-11-25 07:00:00,73.3751018 2013-11-25 08:00:00,73.59611961 2013-11-25 09:00:00,73.62927662 2013-11-25 10:00:00,74.00708949 2013-11-25 11:00:00,73.65766251 2013-11-25 12:00:00,75.03306974 2013-11-25 13:00:00,75.04645886 2013-11-25 14:00:00,75.24681613 2013-11-25 15:00:00,75.70692895 2013-11-25 16:00:00,74.67360854 2013-11-25 17:00:00,74.61358909 2013-11-25 18:00:00,74.491203 2013-11-25 19:00:00,76.12426881 2013-11-25 20:00:00,76.37678862 2013-11-25 21:00:00,76.92387133 2013-11-25 22:00:00,75.33838879 2013-11-25 23:00:00,75.99550579 2013-11-26 00:00:00,76.69138228 2013-11-26 01:00:00,75.88567453 2013-11-26 02:00:00,75.76685516 2013-11-26 03:00:00,75.37412724 2013-11-26 04:00:00,76.68765753 2013-11-26 05:00:00,74.51443263 2013-11-26 06:00:00,74.81803517 2013-11-26 07:00:00,75.98462212 2013-11-26 08:00:00,75.47773677 2013-11-26 09:00:00,73.83422894 2013-11-26 10:00:00,74.80800635 2013-11-26 11:00:00,74.2813275 2013-11-26 12:00:00,75.90857214 2013-11-26 13:00:00,75.58094376 2013-11-26 14:00:00,75.38129562 2013-11-26 15:00:00,75.16651189 2013-11-26 16:00:00,75.93238329 2013-11-26 17:00:00,74.27644123 2013-11-26 18:00:00,74.14545793 2013-11-26 19:00:00,74.83272443 2013-11-26 20:00:00,75.96087554 2013-11-26 21:00:00,76.77265319 2013-11-26 22:00:00,77.00068715 2013-11-26 23:00:00,77.15745947 2013-11-27 00:00:00,77.15974376 2013-11-27 01:00:00,76.69033706 2013-11-27 02:00:00,76.17756923 2013-11-27 03:00:00,77.24837065 2013-11-27 04:00:00,77.35430618 2013-11-27 05:00:00,77.55637201 2013-11-27 06:00:00,77.11772453 2013-11-27 07:00:00,76.16169102 2013-11-27 08:00:00,76.13252582 2013-11-27 09:00:00,76.22151059999999 2013-11-27 10:00:00,74.98788383 2013-11-27 11:00:00,75.70819313 2013-11-27 12:00:00,75.28208686 2013-11-27 13:00:00,75.58863441 2013-11-27 14:00:00,76.04015957 2013-11-27 15:00:00,76.30194796 2013-11-27 16:00:00,76.25516001 2013-11-27 17:00:00,74.8667481 2013-11-27 18:00:00,75.62370485 2013-11-27 19:00:00,74.98800103 2013-11-27 20:00:00,76.56855175 2013-11-27 21:00:00,76.20402117 2013-11-27 22:00:00,76.04503464 2013-11-27 23:00:00,78.00863821 2013-11-28 00:00:00,77.16791565 2013-11-28 01:00:00,77.47286351 2013-11-28 02:00:00,78.34299712 2013-11-28 03:00:00,77.23397943 2013-11-28 04:00:00,78.33064076 2013-11-28 05:00:00,77.74235688 2013-11-28 06:00:00,76.90841346 2013-11-28 07:00:00,78.19122395 2013-11-28 08:00:00,77.11531177 2013-11-28 09:00:00,76.19078959 2013-11-28 10:00:00,75.89108336 2013-11-28 11:00:00,74.91135143 2013-11-28 12:00:00,76.05428041 2013-11-28 13:00:00,74.98413324 2013-11-28 14:00:00,76.71790748 2013-11-28 15:00:00,76.87780803 2013-11-28 16:00:00,75.59376618 2013-11-28 17:00:00,75.42355277 2013-11-28 18:00:00,76.12701487 2013-11-28 19:00:00,76.85731503 2013-11-28 20:00:00,76.36303141 2013-11-28 21:00:00,75.84007067 2013-11-28 22:00:00,76.46922703 2013-11-28 23:00:00,76.80884417 2013-11-29 00:00:00,79.02591263 2013-11-29 01:00:00,78.20757005 2013-11-29 02:00:00,78.47792298 2013-11-29 03:00:00,79.23633448 2013-11-29 04:00:00,78.88770756 2013-11-29 05:00:00,78.8953397 2013-11-29 06:00:00,78.876609 2013-11-29 07:00:00,77.56230513 2013-11-29 08:00:00,76.59404839 2013-11-29 09:00:00,76.94499489 2013-11-29 10:00:00,78.49555784 2013-11-29 11:00:00,76.94027286 2013-11-29 12:00:00,77.88769599 2013-11-29 13:00:00,77.17967275 2013-11-29 14:00:00,77.53951629 2013-11-29 15:00:00,76.83583058 2013-11-29 16:00:00,77.38018752 2013-11-29 17:00:00,78.10468211 2013-11-29 18:00:00,77.14646568 2013-11-29 19:00:00,76.97117206 2013-11-29 20:00:00,77.84318487 2013-11-29 21:00:00,76.66135240000001 2013-11-29 22:00:00,78.15703794 2013-11-29 23:00:00,77.46965922 2013-11-30 00:00:00,77.88460537 2013-11-30 01:00:00,77.65864458 2013-11-30 02:00:00,78.70593097 2013-11-30 03:00:00,78.50094859 2013-11-30 04:00:00,77.02001536 2013-11-30 05:00:00,78.09143757 2013-11-30 06:00:00,76.72362831 2013-11-30 07:00:00,76.45580209 2013-11-30 08:00:00,77.02544955 2013-11-30 09:00:00,78.11045131 2013-11-30 10:00:00,76.35997079 2013-11-30 11:00:00,76.89472925 2013-11-30 12:00:00,77.04274751 2013-11-30 13:00:00,77.94149348 2013-11-30 14:00:00,77.75067472 2013-11-30 15:00:00,77.55710197 2013-11-30 16:00:00,76.86340194 2013-11-30 17:00:00,78.53850778 2013-11-30 18:00:00,78.37908378 2013-11-30 19:00:00,78.81008775 2013-11-30 20:00:00,77.73485863 2013-11-30 21:00:00,77.83555944 2013-11-30 22:00:00,78.56664962 2013-11-30 23:00:00,78.4432628 2013-12-01 00:00:00,78.58726082 2013-12-01 01:00:00,77.53521019 2013-12-01 02:00:00,77.63065448 2013-12-01 03:00:00,78.12865125 2013-12-01 04:00:00,77.86603288 2013-12-01 05:00:00,77.44856207 2013-12-01 06:00:00,76.98370721 2013-12-01 07:00:00,75.4790699 2013-12-01 08:00:00,75.33305301 2013-12-01 09:00:00,75.89776898 2013-12-01 10:00:00,76.60147615 2013-12-01 11:00:00,74.71098020000002 2013-12-01 12:00:00,75.3552543 2013-12-01 13:00:00,74.87224431 2013-12-01 14:00:00,75.9791723 2013-12-01 15:00:00,75.47730656 2013-12-01 16:00:00,75.2003445 2013-12-01 17:00:00,76.27953207 2013-12-01 18:00:00,76.45168292 2013-12-01 19:00:00,76.07015052 2013-12-01 20:00:00,75.73563349999998 2013-12-01 21:00:00,77.0986277 2013-12-01 22:00:00,76.35243379 2013-12-01 23:00:00,76.91635076 2013-12-02 00:00:00,75.41786731 2013-12-02 01:00:00,76.54536726 2013-12-02 02:00:00,75.59756303 2013-12-02 03:00:00,74.89586951 2013-12-02 04:00:00,75.43229909 2013-12-02 05:00:00,74.50186087 2013-12-02 06:00:00,74.80732462 2013-12-02 07:00:00,73.08595318 2013-12-02 08:00:00,73.80861958 2013-12-02 09:00:00,73.38120847 2013-12-02 10:00:00,74.42042248 2013-12-02 11:00:00,75.53513849 2013-12-02 12:00:00,75.09092686 2013-12-02 13:00:00,75.56936508 2013-12-02 14:00:00,74.90652388 2013-12-02 15:00:00,74.082068 2013-12-02 16:00:00,75.77601988 2013-12-02 17:00:00,74.20052806 2013-12-02 18:00:00,75.23398924 2013-12-02 19:00:00,74.67382574 2013-12-02 20:00:00,74.65542741 2013-12-02 21:00:00,74.67489567 2013-12-02 22:00:00,74.8350368 2013-12-02 23:00:00,76.08893067 2013-12-03 00:00:00,75.15278013 2013-12-03 01:00:00,75.02923911 2013-12-03 02:00:00,75.85895688 2013-12-03 03:00:00,74.36103377 2013-12-03 04:00:00,75.5156958 2013-12-03 05:00:00,74.70868339 2013-12-03 06:00:00,73.83262026 2013-12-03 07:00:00,73.70124329 2013-12-03 08:00:00,73.63678504 2013-12-03 09:00:00,73.41637369 2013-12-03 10:00:00,73.80197277 2013-12-03 11:00:00,73.97767514 2013-12-03 12:00:00,74.83469243 2013-12-03 13:00:00,74.97139121 2013-12-03 14:00:00,73.77486044 2013-12-03 15:00:00,75.13503163 2013-12-03 16:00:00,73.87999867 2013-12-03 17:00:00,75.77548486 2013-12-03 18:00:00,75.01213492 2013-12-03 19:00:00,75.50478063 2013-12-03 20:00:00,76.25258396 2013-12-03 21:00:00,75.71050611 2013-12-03 22:00:00,77.20657998 2013-12-03 23:00:00,77.30399661 2013-12-04 00:00:00,75.91202374 2013-12-04 01:00:00,76.66853953 2013-12-04 02:00:00,75.74567822 2013-12-04 03:00:00,75.19938463 2013-12-04 04:00:00,76.19384417 2013-12-04 05:00:00,76.09302338 2013-12-04 06:00:00,76.04003915 2013-12-04 07:00:00,75.29326815 2013-12-04 08:00:00,74.21052551 2013-12-04 09:00:00,75.1991017 2013-12-04 10:00:00,74.06782191 2013-12-04 11:00:00,75.64687089 2013-12-04 12:00:00,74.70819726 2013-12-04 13:00:00,75.45305517 2013-12-04 14:00:00,74.00072839 2013-12-04 15:00:00,74.0555797 2013-12-04 16:00:00,74.61075053 2013-12-04 17:00:00,75.33297088 2013-12-04 18:00:00,75.94712761 2013-12-04 19:00:00,75.58518275 2013-12-04 20:00:00,76.02023976 2013-12-04 21:00:00,76.59701799 2013-12-04 22:00:00,76.96921944 2013-12-04 23:00:00,77.22393149 2013-12-05 00:00:00,75.97207085 2013-12-05 01:00:00,77.39107002 2013-12-05 02:00:00,76.84450656 2013-12-05 03:00:00,77.41677019 2013-12-05 04:00:00,75.98938319 2013-12-05 05:00:00,76.6635247 2013-12-05 06:00:00,75.44756559999998 2013-12-05 07:00:00,76.21819272 2013-12-05 08:00:00,76.32008979 2013-12-05 09:00:00,74.9409507 2013-12-05 10:00:00,75.4784256 2013-12-05 11:00:00,75.17090954 2013-12-05 12:00:00,74.29941509 2013-12-05 13:00:00,74.3062439 2013-12-05 14:00:00,75.90126283 2013-12-05 15:00:00,75.04716769 2013-12-05 16:00:00,75.58599677 2013-12-05 17:00:00,74.87807236 2013-12-05 18:00:00,75.27313151 2013-12-05 19:00:00,76.48370315 2013-12-05 20:00:00,75.50998007 2013-12-05 21:00:00,76.75086745 2013-12-05 22:00:00,76.68483447 2013-12-05 23:00:00,77.38495142 2013-12-06 00:00:00,75.87360168 2013-12-06 01:00:00,77.6556306 2013-12-06 02:00:00,76.42670507 2013-12-06 03:00:00,75.71056203 2013-12-06 04:00:00,75.06068153 2013-12-06 05:00:00,76.10503754 2013-12-06 06:00:00,75.62420413 2013-12-06 07:00:00,76.08456044 2013-12-06 08:00:00,75.29375586 2013-12-06 09:00:00,74.80440567 2013-12-06 10:00:00,75.19512835 2013-12-06 11:00:00,76.00205619 2013-12-06 12:00:00,74.52998721 2013-12-06 13:00:00,74.90420227 2013-12-06 14:00:00,74.16669948 2013-12-06 15:00:00,73.80445232 2013-12-06 16:00:00,74.47552074 2013-12-06 17:00:00,75.30827578 2013-12-06 18:00:00,75.03218705 2013-12-06 19:00:00,76.23218309999999 2013-12-06 20:00:00,75.6839157 2013-12-06 21:00:00,74.92143663 2013-12-06 22:00:00,76.87342138 2013-12-06 23:00:00,76.59855258 2013-12-07 00:00:00,75.33861432 2013-12-07 01:00:00,75.45218311 2013-12-07 02:00:00,76.06290495 2013-12-07 03:00:00,74.9575668 2013-12-07 04:00:00,76.00917564 2013-12-07 05:00:00,75.8543825 2013-12-07 06:00:00,75.27205469 2013-12-07 07:00:00,75.31174871 2013-12-07 08:00:00,74.68013979999998 2013-12-07 09:00:00,74.82785613 2013-12-07 10:00:00,74.52306854 2013-12-07 11:00:00,74.15590675 2013-12-07 12:00:00,75.10514663 2013-12-07 13:00:00,74.7545796 2013-12-07 14:00:00,74.52277912 2013-12-07 15:00:00,75.82423762 2013-12-07 16:00:00,74.22414092 2013-12-07 17:00:00,75.46409745 2013-12-07 18:00:00,76.33578873 2013-12-07 19:00:00,76.79710999 2013-12-07 20:00:00,75.93536531 2013-12-07 21:00:00,75.56283028 2013-12-07 22:00:00,77.20560211 2013-12-07 23:00:00,76.87039405 2013-12-08 00:00:00,75.44604893 2013-12-08 01:00:00,76.57429989 2013-12-08 02:00:00,76.06483199 2013-12-08 03:00:00,76.00964555 2013-12-08 04:00:00,74.80675596 2013-12-08 05:00:00,75.1980522 2013-12-08 06:00:00,76.07994366 2013-12-08 07:00:00,74.76370837 2013-12-08 08:00:00,74.52201927 2013-12-08 09:00:00,74.64224735 2013-12-08 10:00:00,75.14042076 2013-12-08 11:00:00,74.36953798 2013-12-08 12:00:00,75.37965099 2013-12-08 13:00:00,74.93759126 2013-12-08 14:00:00,74.37191177 2013-12-08 15:00:00,74.73159262 2013-12-08 16:00:00,75.61318422 2013-12-08 17:00:00,74.40147509 2013-12-08 18:00:00,76.13732359999999 2013-12-08 19:00:00,74.9962055 2013-12-08 20:00:00,75.54659614 2013-12-08 21:00:00,75.26882561 2013-12-08 22:00:00,74.39856404 2013-12-08 23:00:00,74.28786598 2013-12-09 00:00:00,75.1690554 2013-12-09 01:00:00,75.28609538 2013-12-09 02:00:00,75.1906637 2013-12-09 03:00:00,73.93566312 2013-12-09 04:00:00,74.13405397 2013-12-09 05:00:00,74.18672976 2013-12-09 06:00:00,74.17864554 2013-12-09 07:00:00,72.37641122 2013-12-09 08:00:00,73.10689581 2013-12-09 09:00:00,73.18092841 2013-12-09 10:00:00,72.4431114 2013-12-09 11:00:00,73.61399348 2013-12-09 12:00:00,73.50101128 2013-12-09 13:00:00,72.3008609 2013-12-09 14:00:00,72.34904296 2013-12-09 15:00:00,72.21993949 2013-12-09 16:00:00,73.2791445 2013-12-09 17:00:00,73.29098671 2013-12-09 18:00:00,73.02860249 2013-12-09 19:00:00,73.73807814 2013-12-09 20:00:00,73.96940648 2013-12-09 21:00:00,73.87529271 2013-12-09 22:00:00,74.12690095 2013-12-09 23:00:00,74.54068596 2013-12-10 00:00:00,74.58730262 2013-12-10 01:00:00,73.27195908 2013-12-10 02:00:00,73.90958789 2013-12-10 03:00:00,74.12705890000002 2013-12-10 04:00:00,73.64989009 2013-12-10 05:00:00,73.12019765 2013-12-10 06:00:00,72.94981371 2013-12-10 07:00:00,72.63017091 2013-12-10 08:00:00,72.71613838 2013-12-10 09:00:00,72.71722481 2013-12-10 10:00:00,73.73304064 2013-12-10 11:00:00,72.67712283 2013-12-10 12:00:00,73.64547544 2013-12-10 13:00:00,72.30699831 2013-12-10 14:00:00,72.64327782 2013-12-10 15:00:00,72.70649962 2013-12-10 16:00:00,74.00551 2013-12-10 17:00:00,73.59150747 2013-12-10 18:00:00,74.36327747 2013-12-10 19:00:00,73.43398151 2013-12-10 20:00:00,73.34037954 2013-12-10 21:00:00,72.49370372 2013-12-10 22:00:00,73.36328308 2013-12-10 23:00:00,73.75270216 2013-12-11 00:00:00,74.07760056 2013-12-11 01:00:00,74.13267133 2013-12-11 02:00:00,73.55944399 2013-12-11 03:00:00,72.82256754 2013-12-11 04:00:00,72.55823579 2013-12-11 05:00:00,72.94645319 2013-12-11 06:00:00,73.85665686 2013-12-11 07:00:00,72.43060965 2013-12-11 08:00:00,73.64939159 2013-12-11 09:00:00,72.18117166 2013-12-11 10:00:00,72.68621701 2013-12-11 11:00:00,73.38138872 2013-12-11 12:00:00,72.59355339 2013-12-11 13:00:00,73.08965494 2013-12-11 14:00:00,72.15235240000001 2013-12-11 15:00:00,74.58666641 2013-12-11 16:00:00,75.02738785 2013-12-11 17:00:00,74.62411392 2013-12-11 18:00:00,75.34149751 2013-12-11 19:00:00,75.31820223 2013-12-11 20:00:00,74.99496694 2013-12-11 21:00:00,75.14356488 2013-12-11 22:00:00,75.35414616 2013-12-11 23:00:00,75.60743795 2013-12-12 00:00:00,75.11999997 2013-12-12 01:00:00,74.84177433 2013-12-12 02:00:00,75.34780841 2013-12-12 03:00:00,74.96166134 2013-12-12 04:00:00,76.02028875 2013-12-12 05:00:00,74.99070572 2013-12-12 06:00:00,74.54696679 2013-12-12 07:00:00,75.24551555 2013-12-12 08:00:00,74.58234736 2013-12-12 09:00:00,73.27790479 2013-12-12 10:00:00,73.75848662 2013-12-12 11:00:00,73.72426779 2013-12-12 12:00:00,73.40027014 2013-12-12 13:00:00,74.42141665 2013-12-12 14:00:00,74.09206973 2013-12-12 15:00:00,76.13283725 2013-12-12 16:00:00,76.27032048 2013-12-12 17:00:00,76.22574288 2013-12-12 18:00:00,76.19386187 2013-12-12 19:00:00,75.38155998 2013-12-12 20:00:00,75.54108786 2013-12-12 21:00:00,75.44093455 2013-12-12 22:00:00,75.98674438 2013-12-12 23:00:00,76.37852170000002 2013-12-13 00:00:00,76.24170509 2013-12-13 01:00:00,76.07005174 2013-12-13 02:00:00,76.18773069 2013-12-13 03:00:00,74.54095745 2013-12-13 04:00:00,75.9857027 2013-12-13 05:00:00,75.70301054 2013-12-13 06:00:00,75.97637738 2013-12-13 07:00:00,73.99051999 2013-12-13 08:00:00,74.25959878 2013-12-13 09:00:00,74.06537538 2013-12-13 10:00:00,73.497738 2013-12-13 11:00:00,74.40930673 2013-12-13 12:00:00,73.53465219 2013-12-13 13:00:00,74.01325297 2013-12-13 14:00:00,74.65517361 2013-12-13 15:00:00,73.80252519999998 2013-12-13 16:00:00,73.47288405 2013-12-13 17:00:00,74.39571525 2013-12-13 18:00:00,75.54122752 2013-12-13 19:00:00,75.61996717 2013-12-13 20:00:00,74.29673142 2013-12-13 21:00:00,75.83949955 2013-12-13 22:00:00,76.92758894 2013-12-13 23:00:00,75.89869489 2013-12-14 00:00:00,75.17568757 2013-12-14 01:00:00,75.81093193 2013-12-14 02:00:00,75.69196428 2013-12-14 03:00:00,74.5128894 2013-12-14 04:00:00,74.98113099 2013-12-14 05:00:00,76.17734177 2013-12-14 06:00:00,74.42758116 2013-12-14 07:00:00,74.07682949 2013-12-14 08:00:00,75.69932551 2013-12-14 09:00:00,74.84695927 2013-12-14 10:00:00,74.35760136 2013-12-14 11:00:00,74.39803827 2013-12-14 12:00:00,75.02743496 2013-12-14 13:00:00,74.02252097 2013-12-14 14:00:00,74.56358368 2013-12-14 15:00:00,74.69963645 2013-12-14 16:00:00,75.09767236 2013-12-14 17:00:00,76.44727912 2013-12-14 18:00:00,76.95586845 2013-12-14 19:00:00,76.87810004 2013-12-14 20:00:00,78.17639551 2013-12-14 21:00:00,78.63037082 2013-12-14 22:00:00,77.38397999 2013-12-14 23:00:00,78.19047845 2013-12-15 00:00:00,78.61378004 2013-12-15 01:00:00,77.03252890000002 2013-12-15 02:00:00,78.6107109 2013-12-15 03:00:00,76.68094652 2013-12-15 04:00:00,77.05003701 2013-12-15 05:00:00,76.33040884 2013-12-15 06:00:00,77.55881425 2013-12-15 07:00:00,77.29425879 2013-12-15 08:00:00,75.96598011 2013-12-15 09:00:00,76.44504229 2013-12-15 10:00:00,77.37936193 2013-12-15 11:00:00,76.39378285 2013-12-15 12:00:00,76.18731941 2013-12-15 13:00:00,75.55839334 2013-12-15 14:00:00,77.31227539 2013-12-15 15:00:00,77.63696989 2013-12-15 16:00:00,76.61057145 2013-12-15 17:00:00,78.01573292 2013-12-15 18:00:00,78.11484883 2013-12-15 19:00:00,77.7134697 2013-12-15 20:00:00,78.35903267 2013-12-15 21:00:00,77.54037213 2013-12-15 22:00:00,77.50429946 2013-12-15 23:00:00,78.54151818 2013-12-16 00:00:00,78.51850373 2013-12-16 01:00:00,79.21046638 2013-12-16 02:00:00,79.13826897 2013-12-16 03:00:00,78.40306640000001 2013-12-16 04:00:00,78.62008697 2013-12-16 05:00:00,77.13148416 2013-12-16 06:00:00,78.02477786 2013-12-16 07:00:00,77.86136184 2013-12-16 08:00:00,77.78773632 2013-12-16 09:00:00,76.85925072 2013-12-16 10:00:00,76.69516519 2013-12-16 11:00:00,77.00482738 2013-12-16 12:00:00,76.44663657 2013-12-16 13:00:00,76.83346215 2013-12-16 14:00:00,76.46349867 2013-12-16 15:00:00,75.94666293 2013-12-16 16:00:00,75.43675043 2013-12-16 17:00:00,76.31010809 2013-12-16 18:00:00,75.95438461 2013-12-16 19:00:00,76.15312638 2013-12-16 20:00:00,76.12036689 2013-12-16 21:00:00,75.94597297 2013-12-16 22:00:00,76.55225442 2013-12-16 23:00:00,76.79808015 2013-12-17 00:00:00,76.48918773 2013-12-17 01:00:00,76.33896896 2013-12-17 02:00:00,77.05310437 2013-12-17 03:00:00,76.54734976 2013-12-17 04:00:00,75.9568436 2013-12-17 05:00:00,76.51240415 2013-12-17 06:00:00,76.18995103 2013-12-17 07:00:00,76.90449174 2013-12-17 08:00:00,76.17663538 2013-12-17 09:00:00,75.63774692 2013-12-17 10:00:00,74.76111351 2013-12-17 11:00:00,75.90421071 2013-12-17 12:00:00,76.50791927 2013-12-17 13:00:00,75.03569534 2013-12-17 14:00:00,76.44788554 2013-12-17 15:00:00,75.69349585 2013-12-17 16:00:00,74.67369137 2013-12-17 17:00:00,75.53230267 2013-12-17 18:00:00,75.69028376 2013-12-17 19:00:00,75.61612508 2013-12-17 20:00:00,75.38417556 2013-12-17 21:00:00,76.53118614 2013-12-17 22:00:00,76.0893708 2013-12-17 23:00:00,76.67098365 2013-12-18 00:00:00,77.51409604 2013-12-18 01:00:00,77.71518301 2013-12-18 02:00:00,77.49253948 2013-12-18 03:00:00,76.1495223 2013-12-18 04:00:00,77.69271299 2013-12-18 05:00:00,77.3078518 2013-12-18 06:00:00,76.58823094 2013-12-18 07:00:00,77.01356606 2013-12-18 08:00:00,76.29867262 2013-12-18 09:00:00,76.6226516 2013-12-18 10:00:00,76.44608657 2013-12-18 11:00:00,75.00817082 2013-12-18 12:00:00,74.40000215 2013-12-18 13:00:00,75.95158419 2013-12-18 14:00:00,74.806774 2013-12-18 15:00:00,76.18399877 2013-12-18 16:00:00,75.65218318 2013-12-18 17:00:00,75.92126892 2013-12-18 18:00:00,74.56981993 2013-12-18 19:00:00,74.55990289 2013-12-18 20:00:00,74.70972542 2013-12-18 21:00:00,75.87615507 2013-12-18 22:00:00,75.79608847 2013-12-18 23:00:00,74.99922907 2013-12-19 00:00:00,75.24370674 2013-12-19 01:00:00,76.28685920000002 2013-12-19 02:00:00,76.86505572 2013-12-19 03:00:00,75.77297344 2013-12-19 04:00:00,75.97494123 2013-12-19 05:00:00,74.90139316 2013-12-19 06:00:00,74.02325849 2013-12-19 07:00:00,75.06232298 2013-12-19 08:00:00,74.98321538 2013-12-19 09:00:00,75.28863521 2013-12-19 10:00:00,74.94672097 2013-12-19 11:00:00,73.86675878 2013-12-19 12:00:00,73.71014444 2013-12-19 13:00:00,74.90952525 2013-12-19 14:00:00,74.84580286 2013-12-19 15:00:00,75.602222 2013-12-19 16:00:00,74.74889536 2013-12-19 17:00:00,75.01816634 2013-12-19 18:00:00,75.72022589 2013-12-19 19:00:00,76.30473901 2013-12-19 20:00:00,76.01042931 2013-12-19 21:00:00,77.21635808 2013-12-19 22:00:00,76.50729669 2013-12-19 23:00:00,76.88382451 2013-12-20 00:00:00,76.77573772 2013-12-20 01:00:00,76.28321772 2013-12-20 02:00:00,76.24950337 2013-12-20 03:00:00,76.06611132 2013-12-20 04:00:00,75.81287763 2013-12-20 05:00:00,75.70166172 2013-12-20 06:00:00,77.39653919999998 2013-12-20 07:00:00,76.21575455 2013-12-20 08:00:00,76.42174243 2013-12-20 09:00:00,76.12429859999997 2013-12-20 10:00:00,75.95841843 2013-12-20 11:00:00,74.24349947 2013-12-20 12:00:00,76.0751302 2013-12-20 13:00:00,75.84588787 2013-12-20 14:00:00,74.92850291 2013-12-20 15:00:00,76.3109073 2013-12-20 16:00:00,75.13722516 2013-12-20 17:00:00,75.66403255 2013-12-20 18:00:00,77.34278041 2013-12-20 19:00:00,76.93423637 2013-12-20 20:00:00,76.61857052 2013-12-20 21:00:00,77.03286984 2013-12-20 22:00:00,77.55962287 2013-12-20 23:00:00,79.09188313 2013-12-21 00:00:00,78.52068112 2013-12-21 01:00:00,78.98608769 2013-12-21 02:00:00,79.4198418 2013-12-21 03:00:00,79.04463822 2013-12-21 04:00:00,78.08950603 2013-12-21 05:00:00,77.60666850000001 2013-12-21 06:00:00,77.94600233 2013-12-21 07:00:00,77.89349375 2013-12-21 08:00:00,78.60456446 2013-12-21 09:00:00,77.06658421 2013-12-21 10:00:00,78.3217143 2013-12-21 11:00:00,77.70983715 2013-12-21 12:00:00,78.84426107 2013-12-21 13:00:00,77.1455334 2013-12-21 14:00:00,78.76918765 2013-12-21 15:00:00,77.91774797 2013-12-21 16:00:00,78.34500813 2013-12-21 17:00:00,79.86106375 2013-12-21 18:00:00,80.52026302 2013-12-21 19:00:00,79.89687488 2013-12-21 20:00:00,82.28923988 2013-12-21 21:00:00,82.98986906 2013-12-21 22:00:00,83.24788623 2013-12-21 23:00:00,82.51965884 2013-12-22 00:00:00,82.73680192 2013-12-22 01:00:00,83.78099481 2013-12-22 02:00:00,83.00863385 2013-12-22 03:00:00,82.8156272 2013-12-22 04:00:00,81.77474405 2013-12-22 05:00:00,82.45427776 2013-12-22 06:00:00,82.09190101 2013-12-22 07:00:00,80.96998612 2013-12-22 08:00:00,81.84802474 2013-12-22 09:00:00,82.11075802 2013-12-22 10:00:00,80.90724311 2013-12-22 11:00:00,81.79664979 2013-12-22 12:00:00,80.13996622 2013-12-22 13:00:00,80.56010402 2013-12-22 14:00:00,81.53097122 2013-12-22 15:00:00,81.83006626 2013-12-22 16:00:00,83.51163000000003 2013-12-22 17:00:00,84.39093203 2013-12-22 18:00:00,85.22768546 2013-12-22 19:00:00,86.09488844 2013-12-22 20:00:00,86.20418922 2013-12-22 21:00:00,86.22321261 2013-12-22 22:00:00,85.64943737 2013-12-22 23:00:00,86.07470988 2013-12-23 00:00:00,85.32616543 2013-12-23 01:00:00,85.70599036 2013-12-23 02:00:00,84.08697057 2013-12-23 03:00:00,85.22227695 2013-12-23 04:00:00,83.65396808 2013-12-23 05:00:00,84.32899995 2013-12-23 06:00:00,83.11824067 2013-12-23 07:00:00,82.62728762 2013-12-23 08:00:00,82.6222981 2013-12-23 09:00:00,82.37343675 2013-12-23 10:00:00,81.32311924 2013-12-23 11:00:00,80.15369446 2013-12-23 12:00:00,80.29698997 2013-12-23 13:00:00,81.14245049 2013-12-23 14:00:00,79.87450895 2013-12-23 15:00:00,78.72789303 2013-12-23 16:00:00,80.46954892 2013-12-23 17:00:00,79.03221423 2013-12-23 18:00:00,79.87953093 2013-12-23 19:00:00,78.55827641 2013-12-23 20:00:00,79.53990963 2013-12-23 21:00:00,78.25863964 2013-12-23 22:00:00,79.65429515 2013-12-23 23:00:00,80.24362459999998 2013-12-24 00:00:00,80.69153985 2013-12-24 01:00:00,80.39914328 2013-12-24 02:00:00,81.39129706 2013-12-24 03:00:00,81.17088406 2013-12-24 04:00:00,79.61617311 2013-12-24 05:00:00,81.12807513 2013-12-24 06:00:00,80.430862 2013-12-24 07:00:00,80.02182976 2013-12-24 08:00:00,79.86815899999998 2013-12-24 09:00:00,80.57302099 2013-12-24 10:00:00,78.64657966 2013-12-24 11:00:00,77.52978652 2013-12-24 12:00:00,77.83306033 2013-12-24 13:00:00,77.05832672 2013-12-24 14:00:00,77.19065966 2013-12-24 15:00:00,78.12445799999998 2013-12-24 16:00:00,78.72794247 2013-12-24 17:00:00,78.00471004 2013-12-24 18:00:00,77.76657966 2013-12-24 19:00:00,77.67753604 2013-12-24 20:00:00,78.95358338 2013-12-24 21:00:00,78.36725003 2013-12-24 22:00:00,78.6347335 2013-12-24 23:00:00,79.85459920000002 2013-12-25 00:00:00,78.54898156 2013-12-25 01:00:00,79.24333333 2013-12-25 02:00:00,80.04303671 2013-12-25 03:00:00,78.27609712 2013-12-25 04:00:00,79.68598902 2013-12-25 05:00:00,77.91620784 2013-12-25 06:00:00,79.18453247 2013-12-25 07:00:00,77.94191184 2013-12-25 08:00:00,77.08242193 2013-12-25 09:00:00,77.14715291 2013-12-25 10:00:00,77.62220228 2013-12-25 11:00:00,78.39516049 2013-12-25 12:00:00,76.84592783 2013-12-25 13:00:00,78.29719758 2013-12-25 14:00:00,77.61888521 2013-12-25 15:00:00,77.00744034 2013-12-25 16:00:00,77.76062769 2013-12-25 17:00:00,77.05181008 2013-12-25 18:00:00,77.0723302 2013-12-25 19:00:00,78.46417804 2013-12-25 20:00:00,77.42081363 2013-12-25 21:00:00,77.808112 2013-12-25 22:00:00,77.61400932 2013-12-25 23:00:00,78.09598691 2013-12-26 00:00:00,77.77116624 2013-12-26 01:00:00,77.12786457 2013-12-26 02:00:00,77.0909157 2013-12-26 03:00:00,78.23972837 2013-12-26 04:00:00,77.93250468 2013-12-26 05:00:00,77.65365613 2013-12-26 06:00:00,76.34552706 2013-12-26 07:00:00,77.17220436 2013-12-26 08:00:00,76.85489779 2013-12-26 09:00:00,77.10917493 2013-12-26 10:00:00,76.08132018 2013-12-26 11:00:00,75.97126016 2013-12-26 12:00:00,75.31930024 2013-12-26 13:00:00,76.16500538 2013-12-26 14:00:00,76.33505989 2013-12-26 15:00:00,74.71455759 2013-12-26 16:00:00,75.16889103 2013-12-26 17:00:00,76.88840520000002 2013-12-26 18:00:00,75.877899 2013-12-26 19:00:00,76.41369568 2013-12-26 20:00:00,76.51985988 2013-12-26 21:00:00,76.32626701 2013-12-26 22:00:00,76.75690732 2013-12-26 23:00:00,77.20223204 2013-12-27 00:00:00,76.54350997 2013-12-27 01:00:00,77.01021977 2013-12-27 02:00:00,77.28761998 2013-12-27 03:00:00,77.13929934 2013-12-27 04:00:00,75.83918057 2013-12-27 05:00:00,77.4130038 2013-12-27 06:00:00,75.63631529 2013-12-27 07:00:00,76.80939855 2013-12-27 08:00:00,77.20317007 2013-12-27 09:00:00,75.9880975 2013-12-27 10:00:00,75.60517409 2013-12-27 11:00:00,76.4823878 2013-12-27 12:00:00,76.08486147 2013-12-27 13:00:00,75.05631746 2013-12-27 14:00:00,75.71939344 2013-12-27 15:00:00,75.49636047 2013-12-27 16:00:00,75.55847428 2013-12-27 17:00:00,75.78702171 2013-12-27 18:00:00,75.42590876 2013-12-27 19:00:00,76.5985245 2013-12-27 20:00:00,75.35253788 2013-12-27 21:00:00,75.52461588 2013-12-27 22:00:00,75.27324876 2013-12-27 23:00:00,76.24473974 2013-12-28 00:00:00,76.39365772 2013-12-28 01:00:00,76.14188495 2013-12-28 02:00:00,76.01404616 2013-12-28 03:00:00,76.24766604 2013-12-28 04:00:00,74.60550738 2013-12-28 05:00:00,75.27305911 2013-12-28 06:00:00,75.76095709 2013-12-28 07:00:00,75.18391571 2013-12-28 08:00:00,74.39944531 2013-12-28 09:00:00,74.93700505 2013-12-28 10:00:00,74.62630625 2013-12-28 11:00:00,74.52466577 2013-12-28 12:00:00,75.20171861 2013-12-28 13:00:00,75.59031954 2013-12-28 14:00:00,74.99300208 2013-12-28 15:00:00,75.12205049 2013-12-28 16:00:00,74.8451182 2013-12-28 17:00:00,75.5004353 2013-12-28 18:00:00,75.78745907 2013-12-28 19:00:00,76.80171084 2013-12-28 20:00:00,76.89224059 2013-12-28 21:00:00,76.57189936 2013-12-28 22:00:00,76.05772001 2013-12-28 23:00:00,76.30518585 2013-12-29 00:00:00,75.67921558 2013-12-29 01:00:00,75.65697105 2013-12-29 02:00:00,76.36312409 2013-12-29 03:00:00,76.36912771 2013-12-29 04:00:00,75.98000468 2013-12-29 05:00:00,74.95772326 2013-12-29 06:00:00,75.4259806 2013-12-29 07:00:00,75.84298448 2013-12-29 08:00:00,74.33460196 2013-12-29 09:00:00,75.25125208 2013-12-29 10:00:00,75.28419137 2013-12-29 11:00:00,73.97549299 2013-12-29 12:00:00,73.77993441 2013-12-29 13:00:00,74.11605842 2013-12-29 14:00:00,75.41199782 2013-12-29 15:00:00,75.88781183 2013-12-29 16:00:00,75.34116597 2013-12-29 17:00:00,74.87521094 2013-12-29 18:00:00,76.97509822 2013-12-29 19:00:00,76.83889695 2013-12-29 20:00:00,76.92440774 2013-12-29 21:00:00,77.32019076 2013-12-29 22:00:00,77.67837913 2013-12-29 23:00:00,76.02861347 2013-12-30 00:00:00,75.57417604 2013-12-30 01:00:00,75.79405442 2013-12-30 02:00:00,76.64253253 2013-12-30 03:00:00,76.35495023 2013-12-30 04:00:00,76.05391238 2013-12-30 05:00:00,75.76492651 2013-12-30 06:00:00,75.53227413 2013-12-30 07:00:00,75.96286731 2013-12-30 08:00:00,76.43916795 2013-12-30 09:00:00,75.79904062 2013-12-30 10:00:00,75.53723344 2013-12-30 11:00:00,74.76067835 2013-12-30 12:00:00,74.8480328 2013-12-30 13:00:00,76.23999342 2013-12-30 14:00:00,75.11179225 2013-12-30 15:00:00,74.94556814 2013-12-30 16:00:00,75.55307362 2013-12-30 17:00:00,76.83833799 2013-12-30 18:00:00,75.59523206 2013-12-30 19:00:00,76.31503423 2013-12-30 20:00:00,77.53459374 2013-12-30 21:00:00,76.0050383 2013-12-30 22:00:00,77.68454433 2013-12-30 23:00:00,77.72108111 2013-12-31 00:00:00,77.51558001 2013-12-31 01:00:00,78.44437589 2013-12-31 02:00:00,77.97499028 2013-12-31 03:00:00,76.46430922 2013-12-31 04:00:00,77.99078395 2013-12-31 05:00:00,76.65166801 2013-12-31 06:00:00,76.38382148 2013-12-31 07:00:00,77.98764166 2013-12-31 08:00:00,76.02353562 2013-12-31 09:00:00,76.85941302 2013-12-31 10:00:00,77.02694156 2013-12-31 11:00:00,77.4351667 2013-12-31 12:00:00,75.742419 2013-12-31 13:00:00,76.75512501 2013-12-31 14:00:00,76.1618611 2013-12-31 15:00:00,76.68101761 2013-12-31 16:00:00,76.57323145 2013-12-31 17:00:00,77.42705796 2013-12-31 18:00:00,78.04219444 2013-12-31 19:00:00,77.03500259 2013-12-31 20:00:00,77.59435294 2013-12-31 21:00:00,76.86767814 2013-12-31 22:00:00,77.59032761 2013-12-31 23:00:00,77.68816859 2014-01-01 00:00:00,77.17536982 2014-01-01 01:00:00,76.88160145 2014-01-01 02:00:00,77.64735761 2014-01-01 03:00:00,76.6094964 2014-01-01 04:00:00,76.88619653 2014-01-01 05:00:00,76.25204932 2014-01-01 06:00:00,75.93757409 2014-01-01 07:00:00,77.0866129 2014-01-01 08:00:00,76.89226412 2014-01-01 09:00:00,77.15228638 2014-01-01 10:00:00,76.16837159999999 2014-01-01 11:00:00,76.0309472 2014-01-01 12:00:00,76.36542467 2014-01-01 13:00:00,76.21666009999998 2014-01-01 14:00:00,77.344746 2014-01-01 15:00:00,77.17413937 2014-01-01 16:00:00,77.7444573 2014-01-01 17:00:00,77.80851622 2014-01-01 18:00:00,76.95110006 2014-01-01 19:00:00,77.37914862 2014-01-01 20:00:00,77.64861189 2014-01-01 21:00:00,77.57337175 2014-01-01 22:00:00,77.64969323 2014-01-01 23:00:00,77.28681311 2014-01-02 00:00:00,77.62789588 2014-01-02 01:00:00,76.37452465 2014-01-02 02:00:00,76.89324349 2014-01-02 03:00:00,75.84159632 2014-01-02 04:00:00,76.54495496 2014-01-02 05:00:00,75.54568718 2014-01-02 06:00:00,75.61285500000002 2014-01-02 07:00:00,75.77509947 2014-01-02 08:00:00,76.86025712 2014-01-02 09:00:00,76.75063266 2014-01-02 10:00:00,76.65430247 2014-01-02 11:00:00,76.07822982 2014-01-02 12:00:00,75.64525857 2014-01-02 13:00:00,75.6153839 2014-01-02 14:00:00,75.63346999 2014-01-02 15:00:00,75.45555433 2014-01-02 16:00:00,75.36337466 2014-01-02 17:00:00,76.62929369 2014-01-02 18:00:00,76.02807317 2014-01-02 19:00:00,76.95841456 2014-01-02 20:00:00,77.16409297 2014-01-02 21:00:00,77.50435808 2014-01-02 22:00:00,76.45265121 2014-01-02 23:00:00,76.48343837 2014-01-03 00:00:00,75.53864608 2014-01-03 01:00:00,75.63032548 2014-01-03 02:00:00,75.41759869 2014-01-03 03:00:00,75.98132744 2014-01-03 04:00:00,73.93952186 2014-01-03 05:00:00,74.72379503 2014-01-03 06:00:00,74.41912965 2014-01-03 07:00:00,73.57769606 2014-01-03 08:00:00,73.39289962 2014-01-03 09:00:00,73.40029958 2014-01-03 10:00:00,73.15702733 2014-01-03 11:00:00,73.14839463 2014-01-03 12:00:00,73.56870109 2014-01-03 13:00:00,74.24132001 2014-01-03 14:00:00,73.74719451 2014-01-03 15:00:00,75.18506859 2014-01-03 16:00:00,75.62687166 2014-01-03 17:00:00,75.05191762 2014-01-03 18:00:00,75.03447509 2014-01-03 19:00:00,76.67924387 2014-01-03 20:00:00,75.85058042 2014-01-03 21:00:00,76.26521877 2014-01-03 22:00:00,76.40487485 2014-01-03 23:00:00,76.20869095 2014-01-04 00:00:00,75.78848542 2014-01-04 01:00:00,75.78491462 2014-01-04 02:00:00,74.35316083 2014-01-04 03:00:00,73.2440553 2014-01-04 04:00:00,74.52607513 2014-01-04 05:00:00,72.70071992 2014-01-04 06:00:00,72.55197957 2014-01-04 07:00:00,72.76263888 2014-01-04 08:00:00,74.03023695 2014-01-04 09:00:00,72.1040175 2014-01-04 10:00:00,72.46775852 2014-01-04 11:00:00,72.42871912 2014-01-04 12:00:00,72.52468151 2014-01-04 13:00:00,73.11919307 2014-01-04 14:00:00,72.88771617 2014-01-04 15:00:00,73.79287601 2014-01-04 16:00:00,72.8959554 2014-01-04 17:00:00,73.45337227 2014-01-04 18:00:00,74.06806234 2014-01-04 19:00:00,75.77846693 2014-01-04 20:00:00,75.23072963 2014-01-04 21:00:00,75.61607375 2014-01-04 22:00:00,74.98886104 2014-01-04 23:00:00,75.7975775 2014-01-05 00:00:00,74.59213146 2014-01-05 01:00:00,74.133984 2014-01-05 02:00:00,75.68401665 2014-01-05 03:00:00,74.63891988 2014-01-05 04:00:00,74.84522321 2014-01-05 05:00:00,74.99541401 2014-01-05 06:00:00,73.95833504 2014-01-05 07:00:00,73.91074857 2014-01-05 08:00:00,73.56416169 2014-01-05 09:00:00,73.94257293 2014-01-05 10:00:00,73.32290889 2014-01-05 11:00:00,73.93627585 2014-01-05 12:00:00,74.19905101 2014-01-05 13:00:00,72.79990441 2014-01-05 14:00:00,74.06666139 2014-01-05 15:00:00,74.44944008 2014-01-05 16:00:00,74.62982839 2014-01-05 17:00:00,73.89403209 2014-01-05 18:00:00,75.44283941 2014-01-05 19:00:00,74.9532114 2014-01-05 20:00:00,75.48287312 2014-01-05 21:00:00,74.85663000000002 2014-01-05 22:00:00,75.91564308 2014-01-05 23:00:00,74.31605939 2014-01-06 00:00:00,75.58963791 2014-01-06 01:00:00,73.80836459 2014-01-06 02:00:00,74.64795190000002 2014-01-06 03:00:00,75.13418494 2014-01-06 04:00:00,73.66916292 2014-01-06 05:00:00,73.35199946 2014-01-06 06:00:00,73.97781018 2014-01-06 07:00:00,74.35526471 2014-01-06 08:00:00,73.95431726 2014-01-06 09:00:00,73.80845391 2014-01-06 10:00:00,73.97871909 2014-01-06 11:00:00,72.86942158 2014-01-06 12:00:00,74.94885797 2014-01-06 13:00:00,75.39944679999998 2014-01-06 14:00:00,74.74238142 2014-01-06 15:00:00,74.66350681 2014-01-06 16:00:00,74.41156835 2014-01-06 17:00:00,75.13358423 2014-01-06 18:00:00,75.11834143 2014-01-06 19:00:00,75.43622284 2014-01-06 20:00:00,76.21395639 2014-01-06 21:00:00,74.73751944 2014-01-06 22:00:00,74.54551289 2014-01-06 23:00:00,75.71630602 2014-01-07 00:00:00,73.71800848 2014-01-07 01:00:00,73.64882122 2014-01-07 02:00:00,74.84681716 2014-01-07 03:00:00,73.4509252 2014-01-07 04:00:00,74.87858197 2014-01-07 05:00:00,74.74808979 2014-01-07 06:00:00,74.36531581 2014-01-07 07:00:00,74.17844994 2014-01-07 08:00:00,74.32707278 2014-01-07 09:00:00,73.04205499 2014-01-07 10:00:00,73.88036889 2014-01-07 11:00:00,74.06747359999999 2014-01-07 12:00:00,73.85181753 2014-01-07 13:00:00,73.52105745 2014-01-07 14:00:00,75.89900009 2014-01-07 15:00:00,75.83602568 2014-01-07 16:00:00,75.7488075 2014-01-07 17:00:00,77.03472136 2014-01-07 18:00:00,75.75358374 2014-01-07 19:00:00,76.37330245 2014-01-07 20:00:00,76.41021209 2014-01-07 21:00:00,76.86214074 2014-01-07 22:00:00,76.37969889 2014-01-07 23:00:00,75.8606675 2014-01-08 00:00:00,75.98763517 2014-01-08 01:00:00,75.23598479 2014-01-08 02:00:00,75.71067527 2014-01-08 03:00:00,75.16753331 2014-01-08 04:00:00,74.70772724 2014-01-08 05:00:00,76.07797055 2014-01-08 06:00:00,74.98527003 2014-01-08 07:00:00,74.9606503 2014-01-08 08:00:00,75.33628459999998 2014-01-08 09:00:00,73.55344265 2014-01-08 10:00:00,73.99107759 2014-01-08 11:00:00,74.84672677 2014-01-08 12:00:00,75.07497205 2014-01-08 13:00:00,74.36771562 2014-01-08 14:00:00,75.74259037 2014-01-08 15:00:00,74.87882442 2014-01-08 16:00:00,76.24095087 2014-01-08 17:00:00,75.95860682 2014-01-08 18:00:00,76.37186909 2014-01-08 19:00:00,75.9443031 2014-01-08 20:00:00,75.11146533 2014-01-08 21:00:00,75.15274793 2014-01-08 22:00:00,75.06549983 2014-01-08 23:00:00,74.69714713 2014-01-09 00:00:00,76.19664042 2014-01-09 01:00:00,74.10948331 2014-01-09 02:00:00,74.63482711 2014-01-09 03:00:00,73.51138733 2014-01-09 04:00:00,73.12606794 2014-01-09 05:00:00,74.01271456 2014-01-09 06:00:00,73.86542453 2014-01-09 07:00:00,73.89712719 2014-01-09 08:00:00,74.03537465 2014-01-09 09:00:00,73.72201999 2014-01-09 10:00:00,72.66948077 2014-01-09 11:00:00,72.50391252 2014-01-09 12:00:00,73.95811461 2014-01-09 13:00:00,74.01521745 2014-01-09 14:00:00,74.01596603 2014-01-09 15:00:00,75.4479466 2014-01-09 16:00:00,76.13073887 2014-01-09 17:00:00,75.25463596 2014-01-09 18:00:00,75.93286118 2014-01-09 19:00:00,75.59193841 2014-01-09 20:00:00,76.30709504 2014-01-09 21:00:00,77.18425747 2014-01-09 22:00:00,75.64246944 2014-01-09 23:00:00,76.37537373 2014-01-10 00:00:00,74.68720578 2014-01-10 01:00:00,75.18990319 2014-01-10 02:00:00,75.849666 2014-01-10 03:00:00,75.14636897 2014-01-10 04:00:00,73.90081676 2014-01-10 05:00:00,74.73933733 2014-01-10 06:00:00,73.74171083 2014-01-10 07:00:00,74.46143239 2014-01-10 08:00:00,73.4840964 2014-01-10 09:00:00,73.03863545 2014-01-10 10:00:00,74.07519737 2014-01-10 11:00:00,72.93006063 2014-01-10 12:00:00,73.18888994 2014-01-10 13:00:00,73.95558633 2014-01-10 14:00:00,75.22775409 2014-01-10 15:00:00,75.05332699 2014-01-10 16:00:00,75.36510048 2014-01-10 17:00:00,76.11231412 2014-01-10 18:00:00,75.58706498 2014-01-10 19:00:00,76.06972961 2014-01-10 20:00:00,75.32744105 2014-01-10 21:00:00,76.06533695 2014-01-10 22:00:00,75.66969997 2014-01-10 23:00:00,76.2727697 2014-01-11 00:00:00,75.50606319 2014-01-11 01:00:00,75.37971925 2014-01-11 02:00:00,74.86435121 2014-01-11 03:00:00,75.92346681 2014-01-11 04:00:00,75.81348126 2014-01-11 05:00:00,75.53701836 2014-01-11 06:00:00,74.23671001 2014-01-11 07:00:00,75.16424971 2014-01-11 08:00:00,74.30239478 2014-01-11 09:00:00,74.59790374 2014-01-11 10:00:00,73.58871356 2014-01-11 11:00:00,73.01315859 2014-01-11 12:00:00,72.58458265 2014-01-11 13:00:00,73.95143473 2014-01-11 14:00:00,73.97461465 2014-01-11 15:00:00,74.56884896 2014-01-11 16:00:00,75.03613111 2014-01-11 17:00:00,75.56055848 2014-01-11 18:00:00,75.62240148 2014-01-11 19:00:00,77.67158003 2014-01-11 20:00:00,77.56623639 2014-01-11 21:00:00,77.61657097 2014-01-11 22:00:00,77.69091215 2014-01-11 23:00:00,77.65642064 2014-01-12 00:00:00,76.58082694 2014-01-12 01:00:00,76.82821008 2014-01-12 02:00:00,77.44683206 2014-01-12 03:00:00,77.63174648 2014-01-12 04:00:00,76.76049719 2014-01-12 05:00:00,76.10329035 2014-01-12 06:00:00,75.93474711 2014-01-12 07:00:00,76.39983542 2014-01-12 08:00:00,75.07645543 2014-01-12 09:00:00,76.25156678 2014-01-12 10:00:00,75.59060727 2014-01-12 11:00:00,75.83963106 2014-01-12 12:00:00,75.22056579999997 2014-01-12 13:00:00,74.85866283 2014-01-12 14:00:00,75.53354519 2014-01-12 15:00:00,75.71749619 2014-01-12 16:00:00,77.69659197 2014-01-12 17:00:00,78.08214012 2014-01-12 18:00:00,78.95522712 2014-01-12 19:00:00,79.64623758 2014-01-12 20:00:00,81.37618811 2014-01-12 21:00:00,80.96947535 2014-01-12 22:00:00,80.30864114 2014-01-12 23:00:00,80.18657579 2014-01-13 00:00:00,78.47491514 2014-01-13 01:00:00,78.96162765 2014-01-13 02:00:00,79.1300713 2014-01-13 03:00:00,78.39635208 2014-01-13 04:00:00,79.85480600000002 2014-01-13 05:00:00,77.98583629 2014-01-13 06:00:00,78.35432954 2014-01-13 07:00:00,78.66812563 2014-01-13 08:00:00,79.03360146 2014-01-13 09:00:00,77.31328955 2014-01-13 10:00:00,77.73451371 2014-01-13 11:00:00,77.69436304 2014-01-13 12:00:00,77.79754628 2014-01-13 13:00:00,77.22909454 2014-01-13 14:00:00,78.35433755 2014-01-13 15:00:00,78.03170789 2014-01-13 16:00:00,76.63660126 2014-01-13 17:00:00,76.57220626 2014-01-13 18:00:00,77.76546817 2014-01-13 19:00:00,77.38246298 2014-01-13 20:00:00,76.69839827 2014-01-13 21:00:00,76.3966038 2014-01-13 22:00:00,78.2430965 2014-01-13 23:00:00,77.18014447 2014-01-14 00:00:00,76.98731733 2014-01-14 01:00:00,76.802564 2014-01-14 02:00:00,78.04845667 2014-01-14 03:00:00,78.30808931 2014-01-14 04:00:00,78.56024461 2014-01-14 05:00:00,78.00986597 2014-01-14 06:00:00,77.74735738 2014-01-14 07:00:00,76.56851354 2014-01-14 08:00:00,76.57631974 2014-01-14 09:00:00,76.29506325 2014-01-14 10:00:00,76.91856774 2014-01-14 11:00:00,77.35300179999999 2014-01-14 12:00:00,76.69395845 2014-01-14 13:00:00,76.79314078 2014-01-14 14:00:00,76.78184988 2014-01-14 15:00:00,76.58378687 2014-01-14 16:00:00,75.29365403 2014-01-14 17:00:00,77.08526779 2014-01-14 18:00:00,77.16331386 2014-01-14 19:00:00,76.08578513 2014-01-14 20:00:00,76.26928873 2014-01-14 21:00:00,76.76325951 2014-01-14 22:00:00,75.47553688 2014-01-14 23:00:00,75.0534243 2014-01-15 00:00:00,75.69341909 2014-01-15 01:00:00,74.84655904 2014-01-15 02:00:00,74.60828148 2014-01-15 03:00:00,75.23334924 2014-01-15 04:00:00,74.76757914 2014-01-15 05:00:00,74.32699919 2014-01-15 06:00:00,72.97529237 2014-01-15 07:00:00,73.30416843 2014-01-15 08:00:00,73.38232286 2014-01-15 09:00:00,74.58791578 2014-01-15 10:00:00,72.9067279 2014-01-15 11:00:00,74.15335692 2014-01-15 12:00:00,74.15977548 2014-01-15 13:00:00,75.48000267 2014-01-15 14:00:00,74.94602944 2014-01-15 15:00:00,74.36597865 2014-01-15 16:00:00,75.40107507 2014-01-15 17:00:00,76.43324294 2014-01-15 18:00:00,76.76879953 2014-01-15 19:00:00,75.42099851 2014-01-15 20:00:00,75.04376408 2014-01-15 21:00:00,75.14537633 2014-01-15 22:00:00,75.26255156 2014-01-15 23:00:00,75.35976422 2014-01-16 00:00:00,75.45234139 2014-01-16 01:00:00,73.94180609 2014-01-16 02:00:00,75.00647379 2014-01-16 03:00:00,74.33106778 2014-01-16 04:00:00,74.87396446 2014-01-16 05:00:00,73.3379579 2014-01-16 06:00:00,72.80256039 2014-01-16 07:00:00,73.66597073 2014-01-16 08:00:00,73.87172516 2014-01-16 09:00:00,73.27324959 2014-01-16 10:00:00,72.72014324 2014-01-16 11:00:00,74.17992104 2014-01-16 12:00:00,74.15880306 2014-01-16 13:00:00,75.59329179999997 2014-01-16 14:00:00,75.41968933 2014-01-16 15:00:00,74.53134496 2014-01-16 16:00:00,74.44982256 2014-01-16 17:00:00,75.434016 2014-01-16 18:00:00,75.62950104 2014-01-16 19:00:00,75.34933235 2014-01-16 20:00:00,75.201389 2014-01-16 21:00:00,75.40868152 2014-01-16 22:00:00,75.11984946 2014-01-16 23:00:00,74.38931293 2014-01-17 00:00:00,74.69809723 2014-01-17 01:00:00,75.18846342 2014-01-17 02:00:00,74.45343886 2014-01-17 03:00:00,74.67691315 2014-01-17 04:00:00,73.41217429 2014-01-17 05:00:00,72.83454005 2014-01-17 06:00:00,73.5939262 2014-01-17 07:00:00,72.76406621 2014-01-17 08:00:00,72.68778157 2014-01-17 09:00:00,73.37875182 2014-01-17 10:00:00,72.06183623 2014-01-17 11:00:00,72.86400869 2014-01-17 12:00:00,74.31198445 2014-01-17 13:00:00,73.92421104 2014-01-17 14:00:00,73.6834725 2014-01-17 15:00:00,73.71034271 2014-01-17 16:00:00,73.515123 2014-01-17 17:00:00,74.65384045 2014-01-17 18:00:00,74.59773769 2014-01-17 19:00:00,74.96277198 2014-01-17 20:00:00,74.62437982 2014-01-17 21:00:00,73.58807814 2014-01-17 22:00:00,74.27463197 2014-01-17 23:00:00,73.46593712 2014-01-18 00:00:00,73.37697331 2014-01-18 01:00:00,74.28679774 2014-01-18 02:00:00,74.60507656 2014-01-18 03:00:00,73.56215036 2014-01-18 04:00:00,74.11232577 2014-01-18 05:00:00,73.97053959 2014-01-18 06:00:00,72.77785049 2014-01-18 07:00:00,72.57867332 2014-01-18 08:00:00,73.50341351 2014-01-18 09:00:00,73.17997554 2014-01-18 10:00:00,73.07969608 2014-01-18 11:00:00,72.86778282 2014-01-18 12:00:00,72.97978227 2014-01-18 13:00:00,72.06864306 2014-01-18 14:00:00,73.46915696 2014-01-18 15:00:00,72.73501198 2014-01-18 16:00:00,73.06122541 2014-01-18 17:00:00,73.9831845 2014-01-18 18:00:00,74.44162889 2014-01-18 19:00:00,74.04541228 2014-01-18 20:00:00,74.99423532 2014-01-18 21:00:00,76.25032982 2014-01-18 22:00:00,75.29434003 2014-01-18 23:00:00,74.45046834 2014-01-19 00:00:00,75.03906858 2014-01-19 01:00:00,75.11973678 2014-01-19 02:00:00,73.60403299 2014-01-19 03:00:00,73.44321638 2014-01-19 04:00:00,73.43418914 2014-01-19 05:00:00,73.23859587 2014-01-19 06:00:00,73.7150373 2014-01-19 07:00:00,73.89335646 2014-01-19 08:00:00,73.87424506 2014-01-19 09:00:00,72.96073809 2014-01-19 10:00:00,72.61113449999998 2014-01-19 11:00:00,71.38831163 2014-01-19 12:00:00,72.09667227 2014-01-19 13:00:00,72.43175322 2014-01-19 14:00:00,73.43453663 2014-01-19 15:00:00,71.85172628 2014-01-19 16:00:00,73.33181218 2014-01-19 17:00:00,73.98179005 2014-01-19 18:00:00,75.60339242 2014-01-19 19:00:00,74.84669634 2014-01-19 20:00:00,75.66432669 2014-01-19 21:00:00,75.41398766 2014-01-19 22:00:00,75.62691835 2014-01-19 23:00:00,76.12839652 2014-01-20 00:00:00,75.24374402 2014-01-20 01:00:00,74.25000295 2014-01-20 02:00:00,74.76520353 2014-01-20 03:00:00,74.88412726 2014-01-20 04:00:00,74.70121296 2014-01-20 05:00:00,73.93681762 2014-01-20 06:00:00,74.25651103 2014-01-20 07:00:00,73.57337828 2014-01-20 08:00:00,72.94924405 2014-01-20 09:00:00,73.73581362 2014-01-20 10:00:00,73.57616849 2014-01-20 11:00:00,73.09497078 2014-01-20 12:00:00,74.97348441 2014-01-20 13:00:00,74.48410538 2014-01-20 14:00:00,74.37005879 2014-01-20 15:00:00,74.89437525 2014-01-20 16:00:00,75.36858942 2014-01-20 17:00:00,75.51543606 2014-01-20 18:00:00,75.93149966 2014-01-20 19:00:00,76.80408083 2014-01-20 20:00:00,76.08022555 2014-01-20 21:00:00,74.81338988 2014-01-20 22:00:00,75.92940133 2014-01-20 23:00:00,75.50636120000001 2014-01-21 00:00:00,74.14574816 2014-01-21 01:00:00,74.86999088 2014-01-21 02:00:00,75.32625215 2014-01-21 03:00:00,73.74854939 2014-01-21 04:00:00,74.07036021 2014-01-21 05:00:00,74.04524108 2014-01-21 06:00:00,74.05595233 2014-01-21 07:00:00,74.2393244 2014-01-21 08:00:00,73.90532239 2014-01-21 09:00:00,73.53187021 2014-01-21 10:00:00,73.96226531 2014-01-21 11:00:00,73.20525326 2014-01-21 12:00:00,74.60467618 2014-01-21 13:00:00,74.24149076 2014-01-21 14:00:00,75.28123022 2014-01-21 15:00:00,74.40222479 2014-01-21 16:00:00,74.19210633 2014-01-21 17:00:00,75.87886303 2014-01-21 18:00:00,75.23863029 2014-01-21 19:00:00,74.96873237 2014-01-21 20:00:00,76.10793148 2014-01-21 21:00:00,75.36131634 2014-01-21 22:00:00,75.90263465 2014-01-21 23:00:00,75.50472037 2014-01-22 00:00:00,74.28022956 2014-01-22 01:00:00,72.97203667 2014-01-22 02:00:00,72.67511800000003 2014-01-22 03:00:00,73.47639463 2014-01-22 04:00:00,73.39614473 2014-01-22 05:00:00,72.10091024 2014-01-22 06:00:00,71.8777649 2014-01-22 07:00:00,72.55737568 2014-01-22 08:00:00,72.98505223 2014-01-22 09:00:00,73.73262672 2014-01-22 10:00:00,72.69930722 2014-01-22 11:00:00,73.01882828 2014-01-22 12:00:00,72.80921712 2014-01-22 13:00:00,73.65716599 2014-01-22 14:00:00,74.68008894 2014-01-22 15:00:00,74.65383035 2014-01-22 16:00:00,73.90375633 2014-01-22 17:00:00,74.95962081 2014-01-22 18:00:00,74.72151271 2014-01-22 19:00:00,76.1127814 2014-01-22 20:00:00,76.27976034 2014-01-22 21:00:00,75.43044158 2014-01-22 22:00:00,74.81221712 2014-01-22 23:00:00,75.29112173 2014-01-23 00:00:00,74.11805047 2014-01-23 01:00:00,73.08506057 2014-01-23 02:00:00,73.71635914 2014-01-23 03:00:00,72.75477351 2014-01-23 04:00:00,73.06979399999999 2014-01-23 05:00:00,73.43277483 2014-01-23 06:00:00,72.12848145 2014-01-23 07:00:00,72.30633866 2014-01-23 08:00:00,72.55350882 2014-01-23 09:00:00,72.43365278 2014-01-23 10:00:00,72.16028829999998 2014-01-23 11:00:00,71.87997676 2014-01-23 12:00:00,72.30469043 2014-01-23 13:00:00,72.90140272 2014-01-23 14:00:00,73.52178365 2014-01-23 15:00:00,74.33549357 2014-01-23 16:00:00,75.39468245 2014-01-23 17:00:00,74.07597525 2014-01-23 18:00:00,75.35896953 2014-01-23 19:00:00,76.20885954 2014-01-23 20:00:00,75.47638239 2014-01-23 21:00:00,74.560063 2014-01-23 22:00:00,74.52753611 2014-01-23 23:00:00,73.71689559999999 2014-01-24 00:00:00,73.90866358 2014-01-24 01:00:00,74.09748437 2014-01-24 02:00:00,73.87374575 2014-01-24 03:00:00,73.74883976 2014-01-24 04:00:00,72.9320447 2014-01-24 05:00:00,73.49330934 2014-01-24 06:00:00,73.66155176 2014-01-24 07:00:00,73.62855627 2014-01-24 08:00:00,73.16522286 2014-01-24 09:00:00,72.7479508 2014-01-24 10:00:00,73.56592026 2014-01-24 11:00:00,71.75263157 2014-01-24 12:00:00,73.18039611 2014-01-24 13:00:00,73.92384 2014-01-24 14:00:00,73.80439905 2014-01-24 15:00:00,73.73073979 2014-01-24 16:00:00,73.80911621 2014-01-24 17:00:00,73.53212237 2014-01-24 18:00:00,75.18577049 2014-01-24 19:00:00,75.01261659 2014-01-24 20:00:00,75.04608932 2014-01-24 21:00:00,73.33607329 2014-01-24 22:00:00,73.1043253 2014-01-24 23:00:00,74.10360046 2014-01-25 00:00:00,73.78519774 2014-01-25 01:00:00,71.71663594 2014-01-25 02:00:00,72.13397159 2014-01-25 03:00:00,71.51253422 2014-01-25 04:00:00,72.46607477 2014-01-25 05:00:00,70.94402108 2014-01-25 06:00:00,72.61890668 2014-01-25 07:00:00,70.73076574 2014-01-25 08:00:00,72.48740311 2014-01-25 09:00:00,70.83079397 2014-01-25 10:00:00,71.04843529 2014-01-25 11:00:00,70.71591042 2014-01-25 12:00:00,70.79152507 2014-01-25 13:00:00,70.65705161 2014-01-25 14:00:00,71.61997893 2014-01-25 15:00:00,71.01293809 2014-01-25 16:00:00,71.73672317 2014-01-25 17:00:00,72.73172553 2014-01-25 18:00:00,71.46886416 2014-01-25 19:00:00,71.86085423 2014-01-25 20:00:00,73.11208905 2014-01-25 21:00:00,72.20025328 2014-01-25 22:00:00,72.23507842 2014-01-25 23:00:00,72.0287567 2014-01-26 00:00:00,71.82552414 2014-01-26 01:00:00,72.33922968 2014-01-26 02:00:00,71.85635252 2014-01-26 03:00:00,70.5453744 2014-01-26 04:00:00,70.37989579 2014-01-26 05:00:00,70.37604173 2014-01-26 06:00:00,70.77914323 2014-01-26 07:00:00,70.19317971 2014-01-26 08:00:00,70.24674398 2014-01-26 09:00:00,71.35010374 2014-01-26 10:00:00,69.99332028 2014-01-26 11:00:00,71.14020035 2014-01-26 12:00:00,69.67929351 2014-01-26 13:00:00,69.35287097 2014-01-26 14:00:00,70.07391138 2014-01-26 15:00:00,70.16723295 2014-01-26 16:00:00,70.29923518 2014-01-26 17:00:00,70.53565511 2014-01-26 18:00:00,71.79430755 2014-01-26 19:00:00,71.82889986 2014-01-26 20:00:00,72.54095975 2014-01-26 21:00:00,71.58480523 2014-01-26 22:00:00,73.13032124 2014-01-26 23:00:00,72.19137711 2014-01-27 00:00:00,72.69299224 2014-01-27 01:00:00,72.52594748 2014-01-27 02:00:00,72.1202739 2014-01-27 03:00:00,71.63100933 2014-01-27 04:00:00,72.32810907 2014-01-27 05:00:00,71.35093709 2014-01-27 06:00:00,72.35543488 2014-01-27 07:00:00,72.9372165 2014-01-27 08:00:00,71.70966262 2014-01-27 09:00:00,72.032484 2014-01-27 10:00:00,72.49053701 2014-01-27 11:00:00,71.89054985 2014-01-27 12:00:00,71.26701803 2014-01-27 13:00:00,74.46663598 2014-01-27 14:00:00,72.22220945 2014-01-27 15:00:00,73.72378953 2014-01-27 16:00:00,73.22172217 2014-01-27 17:00:00,73.98717586 2014-01-27 18:00:00,73.03814208 2014-01-27 19:00:00,73.32673418 2014-01-27 20:00:00,74.66952758 2014-01-27 21:00:00,74.79814747 2014-01-27 22:00:00,73.00862053 2014-01-27 23:00:00,72.03939489 2014-01-28 00:00:00,72.84926503 2014-01-28 01:00:00,72.21653075 2014-01-28 02:00:00,72.82207234 2014-01-28 03:00:00,72.13937972 2014-01-28 04:00:00,71.41855654 2014-01-28 05:00:00,72.13106037 2014-01-28 06:00:00,70.30742259 2014-01-28 07:00:00,71.29753092 2014-01-28 08:00:00,70.73465105 2014-01-28 09:00:00,70.97773483 2014-01-28 10:00:00,71.29569485 2014-01-28 11:00:00,70.86865163 2014-01-28 12:00:00,71.13147563 2014-01-28 13:00:00,71.26149539 2014-01-28 14:00:00,71.94856019 2014-01-28 15:00:00,73.39954311 2014-01-28 16:00:00,72.71250801 2014-01-28 17:00:00,72.77672232 2014-01-28 18:00:00,72.35599271 2014-01-28 19:00:00,73.15618385 2014-01-28 20:00:00,73.63572063 2014-01-28 21:00:00,72.21822025 2014-01-28 22:00:00,73.09245779 2014-01-28 23:00:00,72.11831496 2014-01-29 00:00:00,71.42071144 2014-01-29 01:00:00,70.56138073 2014-01-29 02:00:00,71.67378573 2014-01-29 03:00:00,70.69482748 2014-01-29 04:00:00,71.05763613 2014-01-29 05:00:00,69.64124933 2014-01-29 06:00:00,69.98065226 2014-01-29 07:00:00,69.64774646 2014-01-29 08:00:00,68.90916513 2014-01-29 09:00:00,68.87238795 2014-01-29 10:00:00,69.78818855 2014-01-29 11:00:00,71.12277947 2014-01-29 12:00:00,69.26547487 2014-01-29 13:00:00,69.4026087 2014-01-29 14:00:00,70.83920046 2014-01-29 15:00:00,69.3426551 2014-01-29 16:00:00,70.48650218 2014-01-29 17:00:00,71.05859214 2014-01-29 18:00:00,72.61395853 2014-01-29 19:00:00,72.86434604 2014-01-29 20:00:00,72.37767629 2014-01-29 21:00:00,71.96930019 2014-01-29 22:00:00,70.34552908 2014-01-29 23:00:00,70.14337141 2014-01-30 00:00:00,69.65669593 2014-01-30 01:00:00,70.78838358 2014-01-30 02:00:00,69.51059999 2014-01-30 03:00:00,70.31048879 2014-01-30 04:00:00,68.33312277 2014-01-30 05:00:00,69.11285507 2014-01-30 06:00:00,68.36206502 2014-01-30 07:00:00,70.00255638 2014-01-30 08:00:00,69.84002555 2014-01-30 09:00:00,70.8745921 2014-01-30 10:00:00,69.71342166 2014-01-30 11:00:00,70.57222326 2014-01-30 12:00:00,71.52531104 2014-01-30 13:00:00,72.153684 2014-01-30 14:00:00,71.81595951 2014-01-30 15:00:00,72.36544447 2014-01-30 16:00:00,72.4569589 2014-01-30 17:00:00,74.33983452 2014-01-30 18:00:00,72.53925557 2014-01-30 19:00:00,73.62854553 2014-01-30 20:00:00,74.16754767 2014-01-30 21:00:00,72.13192721 2014-01-30 22:00:00,72.59170057 2014-01-30 23:00:00,73.23535767 2014-01-31 00:00:00,71.19719727 2014-01-31 01:00:00,72.61891747 2014-01-31 02:00:00,70.88976393 2014-01-31 03:00:00,71.45727319 2014-01-31 04:00:00,70.03927892 2014-01-31 05:00:00,71.28071130000002 2014-01-31 06:00:00,70.26626228 2014-01-31 07:00:00,70.99283914 2014-01-31 08:00:00,72.32981714 2014-01-31 09:00:00,73.11036920000002 2014-01-31 10:00:00,71.65932377 2014-01-31 11:00:00,71.69114293 2014-01-31 12:00:00,73.06636241 2014-01-31 13:00:00,72.80727072 2014-01-31 14:00:00,73.03538763 2014-01-31 15:00:00,74.79646198 2014-01-31 16:00:00,74.73596869 2014-01-31 17:00:00,74.52413086 2014-01-31 18:00:00,75.13725636 2014-01-31 19:00:00,75.51339861 2014-01-31 20:00:00,74.97912619 2014-01-31 21:00:00,75.16085571 2014-01-31 22:00:00,73.94071425 2014-01-31 23:00:00,74.6188033 2014-02-01 00:00:00,74.59156686 2014-02-01 01:00:00,73.28286835 2014-02-01 02:00:00,74.00350054 2014-02-01 03:00:00,72.69543879 2014-02-01 04:00:00,71.81722439 2014-02-01 05:00:00,71.22178031 2014-02-01 06:00:00,70.71015231 2014-02-01 07:00:00,71.85774564 2014-02-01 08:00:00,72.71240816 2014-02-01 09:00:00,70.8336897 2014-02-01 10:00:00,70.79616568 2014-02-01 11:00:00,71.21849014 2014-02-01 12:00:00,70.71605474 2014-02-01 13:00:00,70.86097936 2014-02-01 14:00:00,70.84299733 2014-02-01 15:00:00,71.92974532 2014-02-01 16:00:00,71.79294961 2014-02-01 17:00:00,71.10245254 2014-02-01 18:00:00,71.47578673 2014-02-01 19:00:00,73.06019458 2014-02-01 20:00:00,71.57960823 2014-02-01 21:00:00,72.00120605 2014-02-01 22:00:00,71.53750218 2014-02-01 23:00:00,71.07065184 2014-02-02 00:00:00,70.44906285 2014-02-02 01:00:00,71.26135473 2014-02-02 02:00:00,71.33996454 2014-02-02 03:00:00,71.30097322 2014-02-02 04:00:00,69.9892031 2014-02-02 05:00:00,70.48431814 2014-02-02 06:00:00,70.00301726 2014-02-02 07:00:00,70.80399895 2014-02-02 08:00:00,69.16903154 2014-02-02 09:00:00,70.23674187 2014-02-02 10:00:00,70.13354079 2014-02-02 11:00:00,70.15141027 2014-02-02 12:00:00,69.00452108 2014-02-02 13:00:00,69.71760276 2014-02-02 14:00:00,70.12305221 2014-02-02 15:00:00,69.76208503 2014-02-02 16:00:00,69.90676189 2014-02-02 17:00:00,70.43625119 2014-02-02 18:00:00,71.23295217 2014-02-02 19:00:00,71.99986698 2014-02-02 20:00:00,72.88904636 2014-02-02 21:00:00,72.65424564 2014-02-02 22:00:00,71.64446397 2014-02-02 23:00:00,72.49652262 2014-02-03 00:00:00,72.19594917 2014-02-03 01:00:00,71.27499667 2014-02-03 02:00:00,71.54927665 2014-02-03 03:00:00,71.37741336 2014-02-03 04:00:00,70.96126394 2014-02-03 05:00:00,70.86526769 2014-02-03 06:00:00,69.51742692 2014-02-03 07:00:00,70.23699729 2014-02-03 08:00:00,70.25478592 2014-02-03 09:00:00,69.54660274 2014-02-03 10:00:00,71.28535022 2014-02-03 11:00:00,71.76620383 2014-02-03 12:00:00,73.1581291 2014-02-03 13:00:00,72.81950243 2014-02-03 14:00:00,73.94357122 2014-02-03 15:00:00,73.31051239 2014-02-03 16:00:00,75.01779737 2014-02-03 17:00:00,73.79603192 2014-02-03 18:00:00,74.03478298 2014-02-03 19:00:00,74.89001392 2014-02-03 20:00:00,74.20342727 2014-02-03 21:00:00,75.47335894 2014-02-03 22:00:00,74.35480145 2014-02-03 23:00:00,73.90516246 2014-02-04 00:00:00,74.27115536 2014-02-04 01:00:00,72.83977840000001 2014-02-04 02:00:00,72.75240643 2014-02-04 03:00:00,72.32492459999997 2014-02-04 04:00:00,73.52854801 2014-02-04 05:00:00,72.4911934 2014-02-04 06:00:00,72.27198579 2014-02-04 07:00:00,71.4871934 2014-02-04 08:00:00,72.12293771 2014-02-04 09:00:00,72.29360612 2014-02-04 10:00:00,72.86539996 2014-02-04 11:00:00,71.36774996 2014-02-04 12:00:00,73.26391824 2014-02-04 13:00:00,73.68072512 2014-02-04 14:00:00,72.61150204 2014-02-04 15:00:00,73.07639687 2014-02-04 16:00:00,74.24530254 2014-02-04 17:00:00,74.49700643 2014-02-04 18:00:00,75.69456912 2014-02-04 19:00:00,74.47440675 2014-02-04 20:00:00,74.34991774 2014-02-04 21:00:00,73.98990175 2014-02-04 22:00:00,73.49337021 2014-02-04 23:00:00,74.69248458 2014-02-05 00:00:00,72.92171344 2014-02-05 01:00:00,73.9381704 2014-02-05 02:00:00,73.26932063 2014-02-05 03:00:00,72.89486303 2014-02-05 04:00:00,71.82789886 2014-02-05 05:00:00,71.50326635 2014-02-05 06:00:00,72.43797863 2014-02-05 07:00:00,71.49212101 2014-02-05 08:00:00,71.97523749 2014-02-05 09:00:00,72.25395073 2014-02-05 10:00:00,72.56517449 2014-02-05 11:00:00,71.83775883 2014-02-05 12:00:00,73.44242506 2014-02-05 13:00:00,74.27947284 2014-02-05 14:00:00,72.99596329 2014-02-05 15:00:00,74.10552743 2014-02-05 16:00:00,73.61788608 2014-02-05 17:00:00,73.31701516 2014-02-05 18:00:00,73.01174645 2014-02-05 19:00:00,74.31390131 2014-02-05 20:00:00,73.22819982 2014-02-05 21:00:00,73.72890646 2014-02-05 22:00:00,72.94723977 2014-02-05 23:00:00,73.8378393 2014-02-06 00:00:00,72.12373833 2014-02-06 01:00:00,72.04284098 2014-02-06 02:00:00,72.25186859 2014-02-06 03:00:00,73.09282493 2014-02-06 04:00:00,71.36865067 2014-02-06 05:00:00,71.49960342 2014-02-06 06:00:00,70.32354612 2014-02-06 07:00:00,70.39520632 2014-02-06 08:00:00,71.16626768 2014-02-06 09:00:00,70.02861579 2014-02-06 10:00:00,71.96241743 2014-02-06 11:00:00,72.38074162 2014-02-06 12:00:00,71.76366871 2014-02-06 13:00:00,71.43442294 2014-02-06 14:00:00,72.96389766 2014-02-06 15:00:00,72.40563890000001 2014-02-06 16:00:00,73.24319119 2014-02-06 17:00:00,74.49209885 2014-02-06 18:00:00,75.67593984 2014-02-06 19:00:00,76.29491541 2014-02-06 20:00:00,74.47855616 2014-02-06 21:00:00,73.97881601 2014-02-06 22:00:00,74.2503925 2014-02-06 23:00:00,73.65281821 2014-02-07 00:00:00,73.5566298 2014-02-07 01:00:00,74.55125277 2014-02-07 02:00:00,73.17815807 2014-02-07 03:00:00,73.99622426 2014-02-07 04:00:00,72.16705646 2014-02-07 05:00:00,72.45023357 2014-02-07 06:00:00,73.06302806 2014-02-07 07:00:00,72.0095 2014-02-07 08:00:00,71.80741665 2014-02-07 09:00:00,71.04467432 2014-02-07 10:00:00,71.97005629 2014-02-07 11:00:00,72.90941163 2014-02-07 12:00:00,72.17063774 2014-02-07 13:00:00,73.06947938 2014-02-07 14:00:00,73.0341092 2014-02-07 15:00:00,73.80953945 2014-02-07 16:00:00,74.31038278 2014-02-07 17:00:00,73.68024234 2014-02-07 18:00:00,74.41363078 2014-02-07 19:00:00,74.41119626 2014-02-07 20:00:00,75.30582101 2014-02-07 21:00:00,73.72231831 2014-02-07 22:00:00,73.956886 2014-02-07 23:00:00,74.57015739 2014-02-08 00:00:00,74.38656607 2014-02-08 01:00:00,73.40422925 2014-02-08 02:00:00,74.70798308 2014-02-08 03:00:00,74.45851269 2014-02-08 04:00:00,73.61811087 2014-02-08 05:00:00,72.61189448 2014-02-08 06:00:00,72.51799386 2014-02-08 07:00:00,72.23863682 2014-02-08 08:00:00,72.24960786 2014-02-08 09:00:00,72.36965218 2014-02-08 10:00:00,73.01194094 2014-02-08 11:00:00,71.62813647 2014-02-08 12:00:00,73.08187593 2014-02-08 13:00:00,72.56747177 2014-02-08 14:00:00,72.40514197 2014-02-08 15:00:00,71.49508201 2014-02-08 16:00:00,72.94715866 2014-02-08 17:00:00,72.921265 2014-02-08 18:00:00,73.01400553 2014-02-08 19:00:00,72.79306485 2014-02-08 20:00:00,72.85442183 2014-02-08 21:00:00,71.65525912 2014-02-08 22:00:00,72.67823919 2014-02-08 23:00:00,71.24393979999998 2014-02-09 00:00:00,72.55938056 2014-02-09 01:00:00,72.05872252 2014-02-09 02:00:00,70.76837988 2014-02-09 03:00:00,72.2572247 2014-02-09 04:00:00,70.78523809 2014-02-09 05:00:00,70.62316491 2014-02-09 06:00:00,69.95124246 2014-02-09 07:00:00,69.93090011 2014-02-09 08:00:00,70.59418428 2014-02-09 09:00:00,70.22278152 2014-02-09 10:00:00,70.96283441 2014-02-09 11:00:00,69.80899995 2014-02-09 12:00:00,70.54885559 2014-02-09 13:00:00,69.93109781 2014-02-09 14:00:00,69.51149457 2014-02-09 15:00:00,69.65236836 2014-02-09 16:00:00,70.29518506 2014-02-09 17:00:00,71.62899935 2014-02-09 18:00:00,70.19075454 2014-02-09 19:00:00,70.75169665 2014-02-09 20:00:00,70.81184472 2014-02-09 21:00:00,72.25826358 2014-02-09 22:00:00,71.2385615 2014-02-09 23:00:00,71.58482682 2014-02-10 00:00:00,72.05545689 2014-02-10 01:00:00,70.68437859 2014-02-10 02:00:00,71.74562272 2014-02-10 03:00:00,70.63016123 2014-02-10 04:00:00,70.10605477 2014-02-10 05:00:00,69.15085681 2014-02-10 06:00:00,70.53897933 2014-02-10 07:00:00,69.75848063 2014-02-10 08:00:00,69.0311664 2014-02-10 09:00:00,69.97462923 2014-02-10 10:00:00,70.99730927 2014-02-10 11:00:00,71.81090729 2014-02-10 12:00:00,71.22813976 2014-02-10 13:00:00,73.54807891 2014-02-10 14:00:00,73.1994691 2014-02-10 15:00:00,72.48376476 2014-02-10 16:00:00,73.27048296 2014-02-10 17:00:00,72.63291885 2014-02-10 18:00:00,73.04230204 2014-02-10 19:00:00,73.59851179 2014-02-10 20:00:00,73.94426246 2014-02-10 21:00:00,72.24379429999998 2014-02-10 22:00:00,72.89933674 2014-02-10 23:00:00,73.3069622 2014-02-11 00:00:00,73.94052267 2014-02-11 01:00:00,72.92628635 2014-02-11 02:00:00,72.67838417 2014-02-11 03:00:00,73.30959938 2014-02-11 04:00:00,73.02655382 2014-02-11 05:00:00,72.29872004 2014-02-11 06:00:00,71.88552448 2014-02-11 07:00:00,72.40495323 2014-02-11 08:00:00,72.02464429 2014-02-11 09:00:00,72.19614083 2014-02-11 10:00:00,72.60597358 2014-02-11 11:00:00,72.39294669 2014-02-11 12:00:00,71.43716569 2014-02-11 13:00:00,73.99604465 2014-02-11 14:00:00,73.50943035 2014-02-11 15:00:00,73.45291204 2014-02-11 16:00:00,72.83513404 2014-02-11 17:00:00,73.94819798 2014-02-11 18:00:00,72.4788448 2014-02-11 19:00:00,72.83570362 2014-02-11 20:00:00,73.99025826 2014-02-11 21:00:00,72.88226906 2014-02-11 22:00:00,73.27645109 2014-02-11 23:00:00,74.02768967 2014-02-12 00:00:00,73.89558413 2014-02-12 01:00:00,72.59262336 2014-02-12 02:00:00,71.72471476 2014-02-12 03:00:00,72.13704935 2014-02-12 04:00:00,71.67420314 2014-02-12 05:00:00,70.80216066 2014-02-12 06:00:00,71.79116991 2014-02-12 07:00:00,70.14151030000001 2014-02-12 08:00:00,71.38580367 2014-02-12 09:00:00,70.1927803 2014-02-12 10:00:00,71.53122540000003 2014-02-12 11:00:00,70.74462709 2014-02-12 12:00:00,71.60956249 2014-02-12 13:00:00,72.63429747 2014-02-12 14:00:00,72.72337319 2014-02-12 15:00:00,73.61530291 2014-02-12 16:00:00,73.79199341 2014-02-12 17:00:00,74.02452744 2014-02-12 18:00:00,73.33443313 2014-02-12 19:00:00,73.77239947 2014-02-12 20:00:00,74.18795723 2014-02-12 21:00:00,72.73057539 2014-02-12 22:00:00,73.0460628 2014-02-12 23:00:00,72.61851266 2014-02-13 00:00:00,73.63047725 2014-02-13 01:00:00,71.86090259999997 2014-02-13 02:00:00,73.39534945 2014-02-13 03:00:00,72.5265888 2014-02-13 04:00:00,72.50012423 2014-02-13 05:00:00,70.9921352 2014-02-13 06:00:00,70.68379403 2014-02-13 07:00:00,70.92225816 2014-02-13 08:00:00,71.06859469 2014-02-13 09:00:00,70.50557416 2014-02-13 10:00:00,72.40911188 2014-02-13 11:00:00,71.18403064 2014-02-13 12:00:00,72.27270943 2014-02-13 13:00:00,72.11898377 2014-02-13 14:00:00,74.22012096 2014-02-13 15:00:00,74.14513886 2014-02-13 16:00:00,72.57257271 2014-02-13 17:00:00,73.9980464 2014-02-13 18:00:00,73.63505079999999 2014-02-13 19:00:00,74.18442393 2014-02-13 20:00:00,74.01379528 2014-02-13 21:00:00,73.31100848 2014-02-13 22:00:00,73.2449359 2014-02-13 23:00:00,73.63799953 2014-02-14 00:00:00,74.22768593 2014-02-14 01:00:00,73.25438431 2014-02-14 02:00:00,73.33046811 2014-02-14 03:00:00,73.61255907 2014-02-14 04:00:00,72.97745167 2014-02-14 05:00:00,71.89748993 2014-02-14 06:00:00,72.9483533 2014-02-14 07:00:00,70.81534967 2014-02-14 08:00:00,72.54651585 2014-02-14 09:00:00,71.6016416 2014-02-14 10:00:00,71.38492873 2014-02-14 11:00:00,72.63654073 2014-02-14 12:00:00,72.26304553 2014-02-14 13:00:00,73.08441684 2014-02-14 14:00:00,72.98119162 2014-02-14 15:00:00,73.44090643 2014-02-14 16:00:00,73.67536027 2014-02-14 17:00:00,73.57106999 2014-02-14 18:00:00,75.09120703 2014-02-14 19:00:00,74.01718788 2014-02-14 20:00:00,74.75368514 2014-02-14 21:00:00,74.06098855 2014-02-14 22:00:00,73.64913399 2014-02-14 23:00:00,72.97725908 2014-02-15 00:00:00,74.31242165 2014-02-15 01:00:00,73.36846791 2014-02-15 02:00:00,73.40601581 2014-02-15 03:00:00,71.88177019 2014-02-15 04:00:00,72.16843891 2014-02-15 05:00:00,72.02037785 2014-02-15 06:00:00,71.46429845 2014-02-15 07:00:00,70.13150262 2014-02-15 08:00:00,71.3592175 2014-02-15 09:00:00,71.52512352 2014-02-15 10:00:00,71.20384956 2014-02-15 11:00:00,70.74443864 2014-02-15 12:00:00,70.44676548 2014-02-15 13:00:00,69.73276669 2014-02-15 14:00:00,69.16754481 2014-02-15 15:00:00,68.61762076 2014-02-15 16:00:00,68.2700207 2014-02-15 17:00:00,68.32512358 2014-02-15 18:00:00,68.00591358 2014-02-15 19:00:00,67.69518570000001 2014-02-15 20:00:00,67.66314846 2014-02-15 21:00:00,68.83888277 2014-02-15 22:00:00,67.71317938 2014-02-15 23:00:00,68.16526105 2014-02-16 00:00:00,67.74392032 2014-02-16 01:00:00,66.91077531 2014-02-16 02:00:00,67.67449688 2014-02-16 03:00:00,67.30731382 2014-02-16 04:00:00,67.90404578 2014-02-16 05:00:00,66.9816318 2014-02-16 06:00:00,67.36349977 2014-02-16 07:00:00,66.85608572 2014-02-16 08:00:00,66.82867178 2014-02-16 09:00:00,65.9175334 2014-02-16 10:00:00,65.85412004 2014-02-16 11:00:00,66.57327898 2014-02-16 12:00:00,66.93439295 2014-02-16 13:00:00,65.95981552 2014-02-16 14:00:00,65.52567020000001 2014-02-16 15:00:00,65.00654684 2014-02-16 16:00:00,65.86116824 2014-02-16 17:00:00,66.24895835 2014-02-16 18:00:00,64.84240685 2014-02-16 19:00:00,65.69994977 2014-02-16 20:00:00,65.11922166 2014-02-16 21:00:00,65.06927583 2014-02-16 22:00:00,65.16381523 2014-02-16 23:00:00,64.32817118 2014-02-17 00:00:00,66.17891449 2014-02-17 01:00:00,65.64161252 2014-02-17 02:00:00,64.79075623 2014-02-17 03:00:00,64.67428457 2014-02-17 04:00:00,64.36980786 2014-02-17 05:00:00,63.50098479 2014-02-17 06:00:00,63.81534068 2014-02-17 07:00:00,64.24808886 2014-02-17 08:00:00,63.39175042 2014-02-17 09:00:00,65.78667951 2014-02-17 10:00:00,65.26018668 2014-02-17 11:00:00,66.52420616 2014-02-17 12:00:00,68.3216973 2014-02-17 13:00:00,69.51920746 2014-02-17 14:00:00,70.41798643 2014-02-17 15:00:00,69.85636686 2014-02-17 16:00:00,70.50368788 2014-02-17 17:00:00,71.55722128 2014-02-17 18:00:00,72.21400820000002 2014-02-17 19:00:00,72.23486752 2014-02-17 20:00:00,72.30190595 2014-02-17 21:00:00,71.38697638 2014-02-17 22:00:00,71.71658422 2014-02-17 23:00:00,70.60328489 2014-02-18 00:00:00,70.70527374 2014-02-18 01:00:00,69.37279327 2014-02-18 02:00:00,69.26929995 2014-02-18 03:00:00,68.33325827 2014-02-18 04:00:00,68.26287644 2014-02-18 05:00:00,68.58490764 2014-02-18 06:00:00,67.91159536 2014-02-18 07:00:00,67.02506652 2014-02-18 08:00:00,66.65870493 2014-02-18 09:00:00,68.35154455 2014-02-18 10:00:00,67.47621403 2014-02-18 11:00:00,69.77932913 2014-02-18 12:00:00,69.15476006 2014-02-18 13:00:00,71.2527348 2014-02-18 14:00:00,70.75971585 2014-02-18 15:00:00,72.72805852 2014-02-18 16:00:00,71.57641906 2014-02-18 17:00:00,71.53146856 2014-02-18 18:00:00,72.43892738 2014-02-18 19:00:00,72.51358476 2014-02-18 20:00:00,73.04307154 2014-02-18 21:00:00,72.01489481 2014-02-18 22:00:00,72.03402933 2014-02-18 23:00:00,71.36277817 2014-02-19 00:00:00,70.22442557 2014-02-19 01:00:00,71.04606096 2014-02-19 02:00:00,70.29642466 2014-02-19 03:00:00,69.67691329 2014-02-19 04:00:00,68.59571214 2014-02-19 05:00:00,69.32304528 2014-02-19 06:00:00,69.67748164 2014-02-19 07:00:00,68.7353527 2014-02-19 08:00:00,68.35921937 2014-02-19 09:00:00,68.72795161 2014-02-19 10:00:00,68.99210194 2014-02-19 11:00:00,70.19905465 2014-02-19 12:00:00,69.97929042 2014-02-19 13:00:00,71.22263248 2014-02-19 14:00:00,71.68970302 2014-02-19 15:00:00,71.30018987 2014-02-19 16:00:00,71.27840683 2014-02-19 17:00:00,71.89062285 2014-02-19 18:00:00,70.7418569 2014-02-19 19:00:00,72.45036867 2014-02-19 20:00:00,71.32687587 2014-02-19 21:00:00,71.41737459999997 2014-02-19 22:00:00,72.27479477 2014-02-19 23:00:00,70.60398854 2014-02-20 00:00:00,71.26949942 2014-02-20 01:00:00,70.11901901 2014-02-20 02:00:00,70.71862637 2014-02-20 03:00:00,70.01345997 2014-02-20 04:00:00,70.36792895 2014-02-20 05:00:00,70.25181505 2014-02-20 06:00:00,70.06343925 2014-02-20 07:00:00,69.51877722 2014-02-20 08:00:00,69.51143689 2014-02-20 09:00:00,69.28431029 2014-02-20 10:00:00,70.02917117 2014-02-20 11:00:00,69.77788948 2014-02-20 12:00:00,70.64429563 2014-02-20 13:00:00,72.09907213 2014-02-20 14:00:00,72.55900491 2014-02-20 15:00:00,72.48953325 2014-02-20 16:00:00,72.02762569 2014-02-20 17:00:00,72.56107268 2014-02-20 18:00:00,72.29252772 2014-02-20 19:00:00,72.14536417 2014-02-20 20:00:00,73.17633192 2014-02-20 21:00:00,72.09881309 2014-02-20 22:00:00,73.03183616 2014-02-20 23:00:00,73.4095494 2014-02-21 00:00:00,73.61055026 2014-02-21 01:00:00,73.22469023 2014-02-21 02:00:00,72.77238923 2014-02-21 03:00:00,71.77678685 2014-02-21 04:00:00,71.39870017 2014-02-21 05:00:00,72.01672718 2014-02-21 06:00:00,71.71709105 2014-02-21 07:00:00,71.89082404 2014-02-21 08:00:00,71.79162775 2014-02-21 09:00:00,71.73870688 2014-02-21 10:00:00,70.86190335 2014-02-21 11:00:00,71.69377098 2014-02-21 12:00:00,72.24965305 2014-02-21 13:00:00,71.86440398 2014-02-21 14:00:00,71.71570293 2014-02-21 15:00:00,73.11333987 2014-02-21 16:00:00,73.11595078 2014-02-21 17:00:00,71.98594655 2014-02-21 18:00:00,71.77056727 2014-02-21 19:00:00,72.69503008 2014-02-21 20:00:00,72.97101070000002 2014-02-21 21:00:00,72.4740122 2014-02-21 22:00:00,73.52059659 2014-02-21 23:00:00,72.43691661 2014-02-22 00:00:00,72.18066282 2014-02-22 01:00:00,71.32459195 2014-02-22 02:00:00,71.85583639 2014-02-22 03:00:00,71.88074888 2014-02-22 04:00:00,72.15361442 2014-02-22 05:00:00,71.17776846 2014-02-22 06:00:00,71.41359324 2014-02-22 07:00:00,71.75202769 2014-02-22 08:00:00,72.29547661 2014-02-22 09:00:00,72.06697006 2014-02-22 10:00:00,70.50858274 2014-02-22 11:00:00,70.18441596 2014-02-22 12:00:00,71.29025253 2014-02-22 13:00:00,70.23647890000001 2014-02-22 14:00:00,70.42527414 2014-02-22 15:00:00,70.62841849 2014-02-22 16:00:00,71.29022977 2014-02-22 17:00:00,70.83192557 2014-02-22 18:00:00,71.13549561 2014-02-22 19:00:00,70.83738869 2014-02-22 20:00:00,70.83849743 2014-02-22 21:00:00,70.93245308 2014-02-22 22:00:00,70.27290872 2014-02-22 23:00:00,70.58817206 2014-02-23 00:00:00,70.24057965 2014-02-23 01:00:00,70.80419 2014-02-23 02:00:00,69.80143685 2014-02-23 03:00:00,69.31283198 2014-02-23 04:00:00,69.35668517 2014-02-23 05:00:00,69.13396209999999 2014-02-23 06:00:00,70.44526682 2014-02-23 07:00:00,70.20928733 2014-02-23 08:00:00,69.93524085 2014-02-23 09:00:00,69.29629038 2014-02-23 10:00:00,68.45718549 2014-02-23 11:00:00,69.36682524 2014-02-23 12:00:00,69.78440146 2014-02-23 13:00:00,70.05047118 2014-02-23 14:00:00,69.94616047 2014-02-23 15:00:00,69.58663804 2014-02-23 16:00:00,69.26826291 2014-02-23 17:00:00,70.67206672 2014-02-23 18:00:00,69.77136750000001 2014-02-23 19:00:00,70.36000475 2014-02-23 20:00:00,71.22900600000001 2014-02-23 21:00:00,71.01855228 2014-02-23 22:00:00,71.67436488 2014-02-23 23:00:00,71.98920306 2014-02-24 00:00:00,71.41241783 2014-02-24 01:00:00,70.21304108 2014-02-24 02:00:00,70.46941197 2014-02-24 03:00:00,71.81875355 2014-02-24 04:00:00,70.75726396 2014-02-24 05:00:00,70.35054453 2014-02-24 06:00:00,71.46188706 2014-02-24 07:00:00,70.98973616 2014-02-24 08:00:00,69.85618346 2014-02-24 09:00:00,70.33833311 2014-02-24 10:00:00,70.64534116 2014-02-24 11:00:00,71.59340431 2014-02-24 12:00:00,72.81269719 2014-02-24 13:00:00,71.4608208 2014-02-24 14:00:00,72.85545543 2014-02-24 15:00:00,73.05311023 2014-02-24 16:00:00,73.92592685 2014-02-24 17:00:00,74.95996905 2014-02-24 18:00:00,75.94820959999998 2014-02-24 19:00:00,75.75487779999997 2014-02-24 20:00:00,74.81028192 2014-02-24 21:00:00,73.54824379 2014-02-24 22:00:00,75.07458015 2014-02-24 23:00:00,73.30253287 2014-02-25 00:00:00,74.89976587 2014-02-25 01:00:00,74.93152766 2014-02-25 02:00:00,73.08132323 2014-02-25 03:00:00,74.38609616 2014-02-25 04:00:00,73.555717 2014-02-25 05:00:00,72.43144467 2014-02-25 06:00:00,73.01942581 2014-02-25 07:00:00,72.1483262 2014-02-25 08:00:00,72.8103996 2014-02-25 09:00:00,72.69220185 2014-02-25 10:00:00,72.93948367 2014-02-25 11:00:00,72.10962389 2014-02-25 12:00:00,73.58615695 2014-02-25 13:00:00,72.55872059 2014-02-25 14:00:00,73.58393306 2014-02-25 15:00:00,72.67472192 2014-02-25 16:00:00,73.6832062 2014-02-25 17:00:00,74.65712512 2014-02-25 18:00:00,74.81826612 2014-02-25 19:00:00,75.30493537 2014-02-25 20:00:00,74.75955931 2014-02-25 21:00:00,74.82300241 2014-02-25 22:00:00,75.2020531 2014-02-25 23:00:00,73.73854426 2014-02-26 00:00:00,74.52699276 2014-02-26 01:00:00,74.22793271 2014-02-26 02:00:00,73.43795586 2014-02-26 03:00:00,73.07056291 2014-02-26 04:00:00,72.27324959999999 2014-02-26 05:00:00,71.51947436 2014-02-26 06:00:00,71.63920884 2014-02-26 07:00:00,72.10054496 2014-02-26 08:00:00,72.35798657 2014-02-26 09:00:00,71.52260473 2014-02-26 10:00:00,70.96393378 2014-02-26 11:00:00,72.58154764 2014-02-26 12:00:00,72.58419551 2014-02-26 13:00:00,72.36171361 2014-02-26 14:00:00,72.42998458 2014-02-26 15:00:00,71.75716944 2014-02-26 16:00:00,73.07326185 2014-02-26 17:00:00,72.75507065 2014-02-26 18:00:00,72.5752305 2014-02-26 19:00:00,73.48040164 2014-02-26 20:00:00,72.81148014 2014-02-26 21:00:00,72.55668889 2014-02-26 22:00:00,72.85158523 2014-02-26 23:00:00,73.26970533 2014-02-27 00:00:00,71.19146991 2014-02-27 01:00:00,72.08289113 2014-02-27 02:00:00,71.96350659 2014-02-27 03:00:00,71.82605361 2014-02-27 04:00:00,70.82030946 2014-02-27 05:00:00,69.42550165 2014-02-27 06:00:00,69.92242421 2014-02-27 07:00:00,69.31438143 2014-02-27 08:00:00,70.76033757 2014-02-27 09:00:00,70.97100633 2014-02-27 10:00:00,70.17113554 2014-02-27 11:00:00,70.71432592 2014-02-27 12:00:00,71.921708 2014-02-27 13:00:00,72.00375809999998 2014-02-27 14:00:00,71.78458459 2014-02-27 15:00:00,72.65555112 2014-02-27 16:00:00,72.58009757 2014-02-27 17:00:00,73.05064890000001 2014-02-27 18:00:00,74.54039587 2014-02-27 19:00:00,75.18858469 2014-02-27 20:00:00,74.27894519 2014-02-27 21:00:00,74.26208079 2014-02-27 22:00:00,73.23807909 2014-02-27 23:00:00,73.87025742 2014-02-28 00:00:00,73.43235603 2014-02-28 01:00:00,72.37198523 2014-02-28 02:00:00,73.92808884 2014-02-28 03:00:00,73.25719839 2014-02-28 04:00:00,72.53001535 2014-02-28 05:00:00,71.63872957 2014-02-28 06:00:00,72.28002048 2014-02-28 07:00:00,71.72196102 2014-02-28 08:00:00,70.39334093 2014-02-28 09:00:00,70.10964532 2014-02-28 10:00:00,70.65823648 2014-02-28 11:00:00,71.51087208 2014-02-28 12:00:00,72.44637778 2014-02-28 13:00:00,71.51568524 2014-02-28 14:00:00,72.7279092 2014-02-28 15:00:00,72.29771123 2014-02-28 16:00:00,71.52876516 2014-02-28 17:00:00,72.59605592 2014-02-28 18:00:00,72.01554663 2014-02-28 19:00:00,72.97598217 2014-02-28 20:00:00,71.20551 2014-02-28 21:00:00,72.52524715 2014-02-28 22:00:00,72.49802968 2014-02-28 23:00:00,72.6226827 2014-03-01 00:00:00,71.39694912 2014-03-01 01:00:00,70.29320788 2014-03-01 02:00:00,70.10398202 2014-03-01 03:00:00,70.02121361 2014-03-01 04:00:00,70.27777940000001 2014-03-01 05:00:00,68.76433592 2014-03-01 06:00:00,69.37923216 2014-03-01 07:00:00,67.78520256 2014-03-01 08:00:00,68.49976639 2014-03-01 09:00:00,66.66557183 2014-03-01 10:00:00,66.92889456 2014-03-01 11:00:00,65.80440933 2014-03-01 12:00:00,66.89565828 2014-03-01 13:00:00,66.20627379 2014-03-01 14:00:00,65.62264979 2014-03-01 15:00:00,66.38603358 2014-03-01 16:00:00,66.57722161 2014-03-01 17:00:00,67.22633566 2014-03-01 18:00:00,66.59760208 2014-03-01 19:00:00,67.12154486 2014-03-01 20:00:00,65.97349626 2014-03-01 21:00:00,66.84503091 2014-03-01 22:00:00,66.34569414 2014-03-01 23:00:00,65.04830890000001 2014-03-02 00:00:00,65.36668131 2014-03-02 01:00:00,64.60285133 2014-03-02 02:00:00,65.00628144 2014-03-02 03:00:00,65.10276279 2014-03-03 09:00:00,64.73752596 2014-03-03 10:00:00,66.44422198 2014-03-03 11:00:00,66.67119237 2014-03-03 12:00:00,68.20387067 2014-03-03 13:00:00,67.99377700000001 2014-03-03 14:00:00,68.82246666 2014-03-03 15:00:00,69.83201105 2014-03-03 16:00:00,70.41675915 2014-03-03 17:00:00,69.67662317 2014-03-03 18:00:00,69.75960523 2014-03-03 19:00:00,70.63902199 2014-03-03 20:00:00,71.26261117 2014-03-03 21:00:00,70.37991099999998 2014-03-03 22:00:00,68.99746538 2014-03-03 23:00:00,67.80571471 2014-03-04 00:00:00,68.65145086 2014-03-04 01:00:00,67.3954395 2014-03-04 02:00:00,67.04867326 2014-03-04 03:00:00,66.58482439 2014-03-04 04:00:00,65.50344586 2014-03-04 05:00:00,65.72809278 2014-03-04 06:00:00,65.71347736 2014-03-04 07:00:00,66.21746488 2014-03-04 08:00:00,67.3270938 2014-03-04 09:00:00,67.62303328 2014-03-04 10:00:00,68.08086803 2014-03-04 11:00:00,68.72680885 2014-03-04 12:00:00,70.45355378 2014-03-04 13:00:00,70.06613398 2014-03-04 14:00:00,69.97752106 2014-03-04 15:00:00,70.4927163 2014-03-04 16:00:00,71.61681198 2014-03-04 17:00:00,70.29198332 2014-03-04 18:00:00,71.67066391 2014-03-04 19:00:00,70.70533885 2014-03-04 20:00:00,70.4300817 2014-03-04 21:00:00,69.29157767 2014-03-04 22:00:00,69.34063822 2014-03-04 23:00:00,70.38420092 2014-03-05 00:00:00,69.63034413 2014-03-05 01:00:00,69.0398113 2014-03-05 02:00:00,67.76196134 2014-03-05 03:00:00,67.67675741 2014-03-05 04:00:00,68.86005963 2014-03-05 05:00:00,67.57048842 2014-03-05 06:00:00,68.46335363 2014-03-05 07:00:00,69.29349205 2014-03-05 08:00:00,68.01547296 2014-03-05 09:00:00,68.10090635 2014-03-05 10:00:00,68.12754514 2014-03-05 11:00:00,70.01662351 2014-03-05 12:00:00,70.25863434 2014-03-05 13:00:00,71.09608996 2014-03-05 14:00:00,71.50280303 2014-03-05 15:00:00,71.42488612 2014-03-05 16:00:00,72.71167276 2014-03-05 17:00:00,71.59459113 2014-03-05 18:00:00,72.43328872 2014-03-05 19:00:00,71.48709146 2014-03-05 20:00:00,71.99469951 2014-03-05 21:00:00,71.35471229 2014-03-05 22:00:00,70.39110149 2014-03-05 23:00:00,69.43812495 2014-03-06 00:00:00,70.2584932 2014-03-06 01:00:00,69.67190229 2014-03-06 02:00:00,68.22337002 2014-03-06 03:00:00,68.80799396 2014-03-06 04:00:00,68.03247815 2014-03-06 05:00:00,67.80972606 2014-03-06 06:00:00,66.40552502 2014-03-06 07:00:00,67.83509944 2014-03-06 08:00:00,65.97248106 2014-03-06 09:00:00,66.31911328 2014-03-06 10:00:00,66.29172592 2014-03-06 11:00:00,66.46979301 2014-03-06 12:00:00,67.19727082 2014-03-06 13:00:00,67.26610171 2014-03-06 14:00:00,66.58963271 2014-03-06 15:00:00,66.13565431 2014-03-06 16:00:00,67.45824979 2014-03-06 17:00:00,67.08281943 2014-03-06 18:00:00,66.60154522 2014-03-06 19:00:00,66.14435074 2014-03-06 20:00:00,65.70970149 2014-03-06 21:00:00,65.72663154 2014-03-06 22:00:00,65.58931781 2014-03-06 23:00:00,65.82957452 2014-03-07 00:00:00,65.66945407 2014-03-07 01:00:00,64.47296805 2014-03-07 02:00:00,64.33275758 2014-03-07 03:00:00,64.30729548 2014-03-07 04:00:00,63.27916803 2014-03-07 05:00:00,63.28661915 2014-03-07 06:00:00,62.71784797 2014-03-07 07:00:00,62.10356599 2014-03-07 08:00:00,62.35873434 2014-03-07 09:00:00,62.26844161 2014-03-07 10:00:00,64.14762913 2014-03-07 11:00:00,66.74519744 2014-03-07 12:00:00,66.88478620000001 2014-03-07 13:00:00,67.39191825 2014-03-07 14:00:00,66.3784179 2014-03-07 15:00:00,67.24728902 2014-03-07 16:00:00,68.80478948 2014-03-07 17:00:00,67.78706753 2014-03-07 18:00:00,67.6234333 2014-03-07 19:00:00,68.13243751 2014-03-07 20:00:00,68.35249809 2014-03-07 21:00:00,68.76098726 2014-03-07 22:00:00,68.27847874 2014-03-07 23:00:00,67.18038204 2014-03-08 00:00:00,66.54164375 2014-03-08 01:00:00,67.01120528 2014-03-08 02:00:00,66.64272086 2014-03-08 03:00:00,65.06151932 2014-03-08 04:00:00,65.17996189 2014-03-08 05:00:00,64.67925087 2014-03-08 06:00:00,65.55120828 2014-03-08 07:00:00,64.59678509 2014-03-08 08:00:00,65.27563058 2014-03-08 09:00:00,64.88539882 2014-03-08 10:00:00,65.15421592 2014-03-08 11:00:00,64.26521212 2014-03-08 12:00:00,64.07879166 2014-03-08 13:00:00,63.99581719 2014-03-08 14:00:00,63.37198838 2014-03-08 15:00:00,63.85857426 2014-03-08 16:00:00,65.7786958 2014-03-08 17:00:00,66.00473119 2014-03-08 18:00:00,65.12337382 2014-03-08 19:00:00,66.57607623 2014-03-08 20:00:00,65.02660446 2014-03-08 21:00:00,64.95266133 2014-03-08 22:00:00,64.97658136 2014-03-08 23:00:00,65.67719536 2014-03-09 00:00:00,65.24741305 2014-03-09 01:00:00,65.41542891 2014-03-09 02:00:00,64.98877478 2014-03-09 03:00:00,64.96988162 2014-03-09 04:00:00,63.30792665 2014-03-09 05:00:00,64.40463119 2014-03-09 06:00:00,63.87984768 2014-03-09 07:00:00,62.65054877 2014-03-09 08:00:00,63.64803912 2014-03-09 09:00:00,63.06377998 2014-03-09 10:00:00,63.08252395 2014-03-09 11:00:00,62.42757669 2014-03-09 12:00:00,62.08987607 2014-03-09 13:00:00,61.82403302 2014-03-09 14:00:00,61.80836032 2014-03-09 15:00:00,63.57034584 2014-03-09 16:00:00,63.14298573 2014-03-09 17:00:00,65.21301797 2014-03-09 18:00:00,63.94421349 2014-03-09 19:00:00,64.45766756 2014-03-09 20:00:00,63.5914373 2014-03-09 21:00:00,62.89815719 2014-03-09 22:00:00,64.45257404 2014-03-09 23:00:00,64.12681763 2014-03-10 00:00:00,63.49055243 2014-03-10 01:00:00,63.42430336 2014-03-10 02:00:00,62.15728246 2014-03-10 03:00:00,62.18439593 2014-03-10 04:00:00,62.23825287 2014-03-10 05:00:00,61.28489989 2014-03-10 06:00:00,62.43160143 2014-03-10 07:00:00,62.64010591 2014-03-10 08:00:00,62.75477551 2014-03-10 09:00:00,63.07107014 2014-03-10 10:00:00,65.36263572 2014-03-10 11:00:00,67.68834829 2014-03-10 12:00:00,66.78938507 2014-03-10 13:00:00,67.4030453 2014-03-10 14:00:00,69.22223465 2014-03-10 15:00:00,68.72906724 2014-03-10 16:00:00,69.43623743 2014-03-10 17:00:00,70.25809179999999 2014-03-10 18:00:00,70.25948981 2014-03-10 19:00:00,70.60726748 2014-03-10 20:00:00,70.2063059 2014-03-10 21:00:00,69.81033474 2014-03-10 22:00:00,68.24486669 2014-03-10 23:00:00,68.10978258 2014-03-11 00:00:00,67.63116079 2014-03-11 01:00:00,68.12898944 2014-03-11 02:00:00,66.93579537 2014-03-11 03:00:00,67.28183681 2014-03-11 04:00:00,67.12842156 2014-03-11 05:00:00,65.79175844 2014-03-11 06:00:00,65.13144669 2014-03-11 07:00:00,66.1775294 2014-03-11 08:00:00,66.51384686 2014-03-11 09:00:00,66.52764863 2014-03-11 10:00:00,67.78500622 2014-03-11 11:00:00,69.36668186 2014-03-11 12:00:00,71.10686192 2014-03-11 13:00:00,71.34507296 2014-03-11 14:00:00,71.63930695 2014-03-11 15:00:00,70.36000942 2014-03-11 16:00:00,71.98604698 2014-03-11 17:00:00,71.66471114 2014-03-11 18:00:00,72.72998288 2014-03-11 19:00:00,72.17540433 2014-03-11 20:00:00,71.92709502 2014-03-11 21:00:00,70.85195269 2014-03-11 22:00:00,69.01463509 2014-03-11 23:00:00,68.49462169 2014-03-12 00:00:00,67.48580392 2014-03-12 01:00:00,68.07698894 2014-03-12 02:00:00,68.23106386 2014-03-12 03:00:00,67.01328165 2014-03-12 04:00:00,67.18611750000001 2014-03-12 05:00:00,65.92239173 2014-03-12 06:00:00,66.38206209 2014-03-12 07:00:00,66.46286064 2014-03-12 08:00:00,68.24047875 2014-03-12 09:00:00,68.02786863 2014-03-12 10:00:00,70.1038357 2014-03-12 11:00:00,70.22659164 2014-03-12 12:00:00,71.37680632 2014-03-12 13:00:00,70.67512681 2014-03-12 14:00:00,70.46297529 2014-03-12 15:00:00,71.28157524 2014-03-12 16:00:00,71.05593879999998 2014-03-12 17:00:00,71.70627229 2014-03-12 18:00:00,72.17357465 2014-03-12 19:00:00,71.84544009 2014-03-12 20:00:00,71.17415427 2014-03-12 21:00:00,71.43730024 2014-03-12 22:00:00,71.00435876 2014-03-12 23:00:00,71.1510194 2014-03-13 00:00:00,69.55935905 2014-03-13 01:00:00,69.6460687 2014-03-13 02:00:00,69.7364644 2014-03-13 03:00:00,68.79399824 2014-03-13 04:00:00,69.72507825 2014-03-13 05:00:00,69.23149065 2014-03-13 06:00:00,67.21438079 2014-03-13 07:00:00,68.75934959 2014-03-13 08:00:00,69.27054515 2014-03-13 09:00:00,69.90997802 2014-03-13 10:00:00,69.07299661 2014-03-13 11:00:00,70.97799327 2014-03-13 12:00:00,70.81341304 2014-03-13 13:00:00,69.80737543 2014-03-13 14:00:00,70.50417147 2014-03-13 15:00:00,71.00976364 2014-03-13 16:00:00,71.64484062 2014-03-13 17:00:00,71.60940441 2014-03-13 18:00:00,71.17635266 2014-03-13 19:00:00,70.46962717 2014-03-13 20:00:00,70.50548628 2014-03-13 21:00:00,70.62289581 2014-03-13 22:00:00,71.69910104 2014-03-13 23:00:00,70.73907743 2014-03-14 00:00:00,69.02175496 2014-03-14 01:00:00,68.78503059 2014-03-14 02:00:00,69.22496356 2014-03-14 03:00:00,67.87748709 2014-03-14 04:00:00,67.29471566 2014-03-14 05:00:00,67.28621294 2014-03-14 06:00:00,66.7890731 2014-03-14 07:00:00,67.50432318 2014-03-14 08:00:00,67.79009858 2014-03-14 09:00:00,69.87567 2014-03-14 10:00:00,70.21520038 2014-03-14 11:00:00,71.18656942 2014-03-14 12:00:00,71.67624154 2014-03-14 13:00:00,71.22363341 2014-03-14 14:00:00,70.43924193 2014-03-14 15:00:00,70.36288978 2014-03-14 16:00:00,70.79729744 2014-03-14 17:00:00,70.23646361 2014-03-14 18:00:00,71.73164608 2014-03-14 19:00:00,70.94221602 2014-03-14 20:00:00,70.53918108 2014-03-14 21:00:00,70.54767727 2014-03-14 22:00:00,70.90770815 2014-03-14 23:00:00,69.78682182 2014-03-15 00:00:00,70.91189536 2014-03-15 01:00:00,70.07406754 2014-03-15 02:00:00,69.59586543 2014-03-15 03:00:00,69.60260984 2014-03-15 04:00:00,68.27877452 2014-03-15 05:00:00,69.45619825 2014-03-15 06:00:00,68.44995951 2014-03-15 07:00:00,69.73862286 2014-03-15 08:00:00,68.94209701 2014-03-15 09:00:00,68.18149599 2014-03-15 10:00:00,68.76664235 2014-03-15 11:00:00,67.45815017 2014-03-15 12:00:00,67.66257636 2014-03-15 13:00:00,67.77115437 2014-03-15 14:00:00,67.69510921 2014-03-15 15:00:00,68.11376092 2014-03-15 16:00:00,68.40917826 2014-03-15 17:00:00,68.68576669 2014-03-15 18:00:00,68.70780771 2014-03-15 19:00:00,68.52816028 2014-03-15 20:00:00,67.29328776 2014-03-15 21:00:00,67.71998071 2014-03-15 22:00:00,66.43501296 2014-03-15 23:00:00,67.6421382 2014-03-16 00:00:00,67.50558169 2014-03-16 01:00:00,66.63507662 2014-03-16 02:00:00,66.03094617 2014-03-16 03:00:00,66.85659507 2014-03-16 04:00:00,65.17315838 2014-03-16 05:00:00,65.21746396 2014-03-16 06:00:00,66.28285507 2014-03-16 07:00:00,65.42152866 2014-03-16 08:00:00,64.94362409 2014-03-16 09:00:00,64.89450895 2014-03-16 10:00:00,64.55896017 2014-03-16 11:00:00,63.75135279 2014-03-16 12:00:00,64.59758157 2014-03-16 13:00:00,64.12270321 2014-03-16 14:00:00,63.49946799 2014-03-16 15:00:00,64.70090581 2014-03-16 16:00:00,63.79618368 2014-03-16 17:00:00,64.00797024 2014-03-16 18:00:00,64.72220608 2014-03-16 19:00:00,62.87773689 2014-03-16 20:00:00,63.82235957 2014-03-16 21:00:00,63.75804636 2014-03-16 22:00:00,63.15739889 2014-03-16 23:00:00,63.44294756 2014-03-17 00:00:00,62.12890913 2014-03-17 01:00:00,61.82512301 2014-03-17 02:00:00,61.83080286 2014-03-17 03:00:00,63.16291422 2014-03-17 04:00:00,61.25053172 2014-03-17 05:00:00,61.01365104 2014-03-17 06:00:00,61.21543911 2014-03-17 07:00:00,62.37751935 2014-03-17 08:00:00,62.92591945 2014-03-17 09:00:00,64.87107009 2014-03-17 10:00:00,64.86490926 2014-03-17 11:00:00,66.04123541 2014-03-17 12:00:00,67.6714638 2014-03-17 13:00:00,68.92351552 2014-03-17 14:00:00,67.95417072 2014-03-17 15:00:00,69.769521 2014-03-17 16:00:00,70.24593681 2014-03-17 17:00:00,69.82130302 2014-03-17 18:00:00,70.83974955 2014-03-17 19:00:00,70.51174374 2014-03-17 20:00:00,71.02364643 2014-03-17 21:00:00,68.7052537 2014-03-17 22:00:00,68.11165389 2014-03-17 23:00:00,68.1166531 2014-03-18 00:00:00,67.21496653 2014-03-18 01:00:00,67.06224246 2014-03-18 02:00:00,67.30972126 2014-03-18 05:00:00,66.69399198 2014-03-18 06:00:00,65.70506463 2014-03-18 07:00:00,64.62101714 2014-03-18 08:00:00,65.77618074 2014-03-18 09:00:00,67.40523118 2014-03-18 10:00:00,68.71941661 2014-03-18 11:00:00,69.61966828 2014-03-18 12:00:00,70.27366665 2014-03-18 13:00:00,70.56337429 2014-03-18 14:00:00,70.67077922 2014-03-18 15:00:00,72.26734255 2014-03-18 16:00:00,70.62328355 2014-03-18 17:00:00,71.06334712 2014-03-18 18:00:00,71.65028164 2014-03-18 19:00:00,71.77769312 2014-03-18 20:00:00,70.059985 2014-03-18 21:00:00,70.75799228 2014-03-18 22:00:00,69.98433493 2014-03-18 23:00:00,68.84969949 2014-03-19 00:00:00,69.74606796 2014-03-19 01:00:00,69.53952356 2014-03-19 02:00:00,67.523201 2014-03-19 03:00:00,67.37990329 2014-03-19 04:00:00,67.41747840000001 2014-03-19 05:00:00,65.93843117 2014-03-19 06:00:00,66.82475179 2014-03-19 07:00:00,67.27135893 2014-03-19 08:00:00,67.13357776 2014-03-19 09:00:00,68.52772342 2014-03-19 10:00:00,68.55982584 2014-03-19 11:00:00,68.81377025 2014-03-19 12:00:00,70.36173769 2014-03-19 13:00:00,71.70237934 2014-03-19 14:00:00,72.13491131 2014-03-19 15:00:00,72.18835193 2014-03-19 16:00:00,71.92595429 2014-03-19 17:00:00,71.92725603 2014-03-19 18:00:00,71.54807344 2014-03-19 19:00:00,70.49187639 2014-03-19 20:00:00,71.48653484 2014-03-19 21:00:00,70.20635388 2014-03-19 22:00:00,69.49279694 2014-03-19 23:00:00,68.9205068 2014-03-20 00:00:00,68.33056564 2014-03-20 01:00:00,68.82533073 2014-03-20 02:00:00,68.84005375 2014-03-20 03:00:00,68.31437625 2014-03-20 04:00:00,66.64807821 2014-03-20 05:00:00,66.34454369 2014-03-20 06:00:00,66.17310237 2014-03-20 07:00:00,66.74208658 2014-03-20 08:00:00,68.01627433 2014-03-20 09:00:00,68.92086970000001 2014-03-20 10:00:00,70.1290524 2014-03-20 11:00:00,70.85226597 2014-03-20 12:00:00,70.66374179 2014-03-20 13:00:00,70.4602105 2014-03-20 14:00:00,70.72339624 2014-03-20 15:00:00,71.44960721 2014-03-20 16:00:00,72.70811888 2014-03-20 17:00:00,72.77820708 2014-03-20 18:00:00,71.29761709 2014-03-20 19:00:00,71.33906347 2014-03-20 20:00:00,72.43172383 2014-03-20 21:00:00,70.68626447 2014-03-20 22:00:00,70.90794649 2014-03-20 23:00:00,69.22547767 2014-03-21 00:00:00,69.59225848 2014-03-21 01:00:00,69.23210541 2014-03-21 02:00:00,68.15528042 2014-03-21 03:00:00,66.91203197 2014-03-21 04:00:00,67.71558241 2014-03-21 05:00:00,66.33452731 2014-03-21 06:00:00,66.34030271 2014-03-21 07:00:00,66.1824594 2014-03-21 08:00:00,66.26386 2014-03-21 09:00:00,68.22384891 2014-03-21 10:00:00,69.16427797 2014-03-21 11:00:00,69.10930036 2014-03-21 12:00:00,70.81803261 2014-03-21 13:00:00,70.01676069 2014-03-21 14:00:00,70.90161589 2014-03-21 15:00:00,71.64555322 2014-03-21 16:00:00,71.70339358 2014-03-21 17:00:00,71.27680445 2014-03-21 18:00:00,70.63130618 2014-03-21 19:00:00,70.97130269 2014-03-21 20:00:00,71.71353903 2014-03-21 21:00:00,69.9054085 2014-03-21 22:00:00,69.66400387 2014-03-21 23:00:00,69.16838511 2014-03-22 00:00:00,69.69722981 2014-03-22 01:00:00,69.15682991 2014-03-22 02:00:00,68.72517924 2014-03-22 03:00:00,68.35990386 2014-03-22 04:00:00,67.18127785 2014-03-22 05:00:00,67.94571484 2014-03-22 06:00:00,66.71803036 2014-03-22 07:00:00,65.66712074 2014-03-22 08:00:00,66.84586991 2014-03-22 09:00:00,66.29208118 2014-03-22 10:00:00,66.88373267 2014-03-22 11:00:00,65.19948254 2014-03-22 12:00:00,65.58210550000001 2014-03-22 13:00:00,64.70394655 2014-03-22 14:00:00,66.22315748 2014-03-22 15:00:00,64.88013387 2014-03-22 16:00:00,65.55529857 2014-03-22 17:00:00,64.64947474 2014-03-22 18:00:00,64.68176215 2014-03-22 19:00:00,64.80958215 2014-03-22 20:00:00,65.33285671 2014-03-22 21:00:00,64.36267745 2014-03-22 22:00:00,64.11222793 2014-03-22 23:00:00,65.11150875 2014-03-23 00:00:00,65.33899224 2014-03-23 01:00:00,65.61427437 2014-03-23 02:00:00,63.77836909 2014-03-23 03:00:00,63.70443845 2014-03-23 04:00:00,63.46343576 2014-03-23 05:00:00,63.6445251 2014-03-23 06:00:00,65.44047774 2014-03-23 07:00:00,63.66470663 2014-03-23 08:00:00,64.32136806 2014-03-23 09:00:00,64.17341 2014-03-23 10:00:00,64.86387244 2014-03-23 11:00:00,62.98320455 2014-03-23 12:00:00,63.83170364 2014-03-23 13:00:00,62.81085999 2014-03-23 14:00:00,62.84699795 2014-03-23 15:00:00,63.166335499999995 2014-03-23 16:00:00,63.23431085 2014-03-23 17:00:00,63.01982143 2014-03-23 18:00:00,63.70769083 2014-03-23 19:00:00,62.51382762 2014-03-23 20:00:00,63.21955192 2014-03-23 21:00:00,62.20602098 2014-03-23 22:00:00,62.15285065 2014-03-23 23:00:00,63.05547087 2014-03-24 00:00:00,62.10293066 2014-03-24 01:00:00,62.540844799999995 2014-03-24 02:00:00,62.5503174 2014-03-24 03:00:00,63.20486663 2014-03-24 04:00:00,62.9317748 2014-03-24 19:00:00,71.94336325 2014-03-24 20:00:00,70.71564295 2014-03-24 21:00:00,69.28811871 2014-03-24 22:00:00,68.43786337 2014-03-24 23:00:00,68.24934959 2014-03-25 00:00:00,68.47135744 2014-03-25 01:00:00,67.01776467 2014-03-25 02:00:00,68.08328348 2014-03-25 03:00:00,67.68747842 2014-03-25 04:00:00,67.39799093 2014-03-25 05:00:00,66.2691171 2014-03-25 06:00:00,65.34304105 2014-03-25 07:00:00,64.77433465 2014-03-25 08:00:00,66.44792487 2014-03-25 09:00:00,67.26279954 2014-03-25 10:00:00,67.60152815 2014-03-25 11:00:00,69.90530838 2014-03-25 12:00:00,70.73996852 2014-03-25 13:00:00,70.49826866 2014-03-25 14:00:00,70.2611678 2014-03-25 15:00:00,71.53832084 2014-03-25 16:00:00,71.27033912 2014-03-25 17:00:00,70.90025791 2014-03-25 18:00:00,71.52148116 2014-03-25 19:00:00,70.28414588 2014-03-25 20:00:00,71.60015916 2014-03-25 21:00:00,70.28728127 2014-03-25 22:00:00,68.83984168 2014-03-25 23:00:00,68.49777461 2014-03-26 00:00:00,69.31375581 2014-03-26 01:00:00,67.72785184 2014-03-26 02:00:00,68.09933961 2014-03-26 03:00:00,67.25783658 2014-03-26 04:00:00,66.86402700000001 2014-03-26 05:00:00,66.59775853 2014-03-26 06:00:00,65.53304117 2014-03-26 07:00:00,66.86270078 2014-03-26 08:00:00,67.50801513 2014-03-26 09:00:00,67.77407736 2014-03-26 10:00:00,68.52400365 2014-03-26 11:00:00,69.56611683 2014-03-26 12:00:00,71.28961034 2014-03-26 13:00:00,70.14062086 2014-03-26 14:00:00,71.034825 2014-03-26 15:00:00,71.44418165 2014-03-26 16:00:00,70.78327368 2014-03-26 17:00:00,70.66347191 2014-03-26 18:00:00,69.90711596 2014-03-26 19:00:00,70.24754496 2014-03-26 20:00:00,71.0175816 2014-03-26 21:00:00,71.11791992 2014-03-26 22:00:00,69.28691532 2014-03-26 23:00:00,69.27422586 2014-03-27 00:00:00,70.19449054 2014-03-27 01:00:00,68.77820054 2014-03-27 02:00:00,68.18678053 2014-03-27 03:00:00,68.85984403 2014-03-27 04:00:00,67.73755512 2014-03-27 05:00:00,67.49811369 2014-03-27 06:00:00,66.73351538 2014-03-27 07:00:00,65.96544261 2014-03-27 08:00:00,66.93124294 2014-03-27 09:00:00,69.07779412 2014-03-27 10:00:00,69.22374151 2014-03-27 11:00:00,69.4535237 2014-03-27 12:00:00,72.22574727 2014-03-27 13:00:00,72.32609476 2014-03-27 14:00:00,72.0268521 2014-03-27 15:00:00,71.58630641 2014-03-27 16:00:00,70.57044597 2014-03-27 17:00:00,71.2768215 2014-03-27 18:00:00,71.55483881 2014-03-27 19:00:00,72.03927682 2014-03-27 20:00:00,71.48654663 2014-03-27 21:00:00,70.86464227 2014-03-27 22:00:00,69.35637651 2014-03-27 23:00:00,69.61239792 2014-03-28 00:00:00,68.43977756 2014-03-28 01:00:00,68.1853957 2014-03-28 02:00:00,67.29170594 2014-03-28 03:00:00,68.42970414 2014-03-28 04:00:00,67.05828335 2014-03-28 05:00:00,66.50295007 2014-03-28 06:00:00,67.00732027 2014-03-28 07:00:00,65.42638245 2014-03-28 08:00:00,67.67939638 2014-03-28 09:00:00,67.02204681 2014-03-28 10:00:00,68.54764706 2014-03-28 11:00:00,69.4655308 2014-03-28 12:00:00,70.43402561 2014-03-28 13:00:00,71.9389561 2014-03-28 14:00:00,70.81297494 2014-03-28 15:00:00,70.81249572 2014-03-28 16:00:00,70.15898776 2014-03-28 17:00:00,71.64451052 2014-03-28 18:00:00,70.19782359 2014-03-28 19:00:00,70.58227035 2014-03-28 20:00:00,71.2087204 2014-03-28 21:00:00,70.20658031 2014-03-28 22:00:00,71.01175909999998 2014-03-28 23:00:00,68.85446017 2014-03-29 00:00:00,69.98331416 2014-03-29 01:00:00,68.46446529 2014-03-29 02:00:00,68.73818002 2014-03-29 03:00:00,69.062706 2014-03-29 04:00:00,68.38697286 2014-03-29 05:00:00,67.58387429 2014-03-29 06:00:00,67.83077241 2014-03-29 07:00:00,68.81423687 2014-03-29 08:00:00,66.69042351 2014-03-29 09:00:00,66.36840797 2014-03-29 10:00:00,66.61346754 2014-03-29 11:00:00,67.33922911 2014-03-29 12:00:00,66.9322944 2014-03-29 13:00:00,66.76955124 2014-03-29 14:00:00,66.00830414 2014-03-29 15:00:00,66.7799832 2014-03-29 16:00:00,66.58172048 2014-03-29 17:00:00,67.11698683 2014-03-29 18:00:00,66.15598172 2014-03-29 19:00:00,66.69489329 2014-03-29 20:00:00,64.82380273 2014-03-29 21:00:00,65.2430426 2014-03-29 22:00:00,65.21164883 2014-03-29 23:00:00,64.54188892 2014-03-30 00:00:00,64.8747141 2014-03-30 01:00:00,65.4966696 2014-03-30 02:00:00,65.38109608 2014-03-30 03:00:00,65.02897391 2014-03-30 04:00:00,64.67595377 2014-03-30 05:00:00,64.44424833 2014-03-30 06:00:00,64.25219739 2014-03-30 07:00:00,65.40018788 2014-03-30 08:00:00,63.73067948 2014-03-30 09:00:00,64.20889648 2014-03-30 10:00:00,63.45681538 2014-03-30 11:00:00,64.48807692 2014-03-30 12:00:00,63.79730874 2014-03-30 13:00:00,64.36082107 2014-03-30 14:00:00,63.84830762 2014-03-30 15:00:00,65.51296869 2014-03-30 16:00:00,65.48389278 2014-03-30 17:00:00,65.75005021 2014-03-30 18:00:00,64.65810145 2014-03-30 19:00:00,64.36282383 2014-03-30 20:00:00,64.99007209 2014-03-30 21:00:00,65.34666001 2014-03-30 22:00:00,65.39531562 2014-03-30 23:00:00,64.45329069 2014-03-31 00:00:00,64.61712504 2014-03-31 01:00:00,63.75428142 2014-03-31 02:00:00,63.49502357 2014-03-31 03:00:00,64.12967698 2014-03-31 04:00:00,63.69871435 2014-03-31 05:00:00,62.31748849 2014-03-31 06:00:00,62.56249792 2014-03-31 07:00:00,62.083133 2014-03-31 08:00:00,64.28414943 2014-03-31 09:00:00,63.94397227 2014-03-31 10:00:00,65.76317725 2014-03-31 11:00:00,67.38934556 2014-03-31 12:00:00,66.79761934 2014-03-31 13:00:00,67.51730856 2014-03-31 14:00:00,69.42271076 2014-03-31 15:00:00,69.86566479 2014-03-31 16:00:00,69.47338876 2014-03-31 17:00:00,70.95110588 2014-03-31 18:00:00,71.56889705 2014-03-31 19:00:00,70.99062865 2014-03-31 20:00:00,70.60246289 2014-03-31 21:00:00,68.00017618 2014-03-31 22:00:00,68.25783759999999 2014-03-31 23:00:00,68.63980318 2014-04-01 00:00:00,68.32316289 2014-04-01 01:00:00,66.43383631 2014-04-01 02:00:00,67.18821052 2014-04-01 03:00:00,67.27079193 2014-04-01 04:00:00,65.27791142 2014-04-01 05:00:00,64.67375005 2014-04-01 06:00:00,63.96850495 2014-04-01 07:00:00,64.60849643 2014-04-01 08:00:00,65.56452156 2014-04-01 09:00:00,66.5334125 2014-04-01 10:00:00,68.23406291 2014-04-01 11:00:00,68.56959033 2014-04-01 12:00:00,69.70420104 2014-04-01 13:00:00,69.63981849 2014-04-01 14:00:00,70.22222824 2014-04-01 15:00:00,70.31535411 2014-04-01 16:00:00,71.95951248 2014-04-01 17:00:00,71.24637137 2014-04-01 18:00:00,71.58768312 2014-04-01 19:00:00,70.42108950000002 2014-04-01 20:00:00,71.20646965 2014-04-01 21:00:00,70.61530009 2014-04-01 22:00:00,70.06998582 2014-04-01 23:00:00,69.29171113 2014-04-02 00:00:00,67.85447566 2014-04-02 01:00:00,68.24887826 2014-04-02 02:00:00,68.76715290000001 2014-04-02 03:00:00,68.21590455 2014-04-02 04:00:00,66.42226253 2014-04-02 05:00:00,67.39517591 2014-04-02 06:00:00,65.36892099 2014-04-02 07:00:00,66.25362724 2014-04-02 08:00:00,66.59754547 2014-04-02 09:00:00,67.72967658 2014-04-02 10:00:00,68.48225745 2014-04-02 11:00:00,69.92320652 2014-04-02 12:00:00,70.58513885 2014-04-02 13:00:00,71.41308851 2014-04-02 14:00:00,70.3227835 2014-04-02 15:00:00,71.11789389 2014-04-02 16:00:00,69.47243025 2014-04-02 17:00:00,70.89176392 2014-04-02 18:00:00,71.46215140000002 2014-04-02 19:00:00,71.40483009 2014-04-02 20:00:00,72.2868221 2014-04-02 21:00:00,69.7696442 2014-04-02 22:00:00,69.85857394 2014-04-02 23:00:00,70.29044092 2014-04-03 00:00:00,69.18897735 2014-04-03 01:00:00,68.25903615 2014-04-03 02:00:00,69.48405619 2014-04-03 03:00:00,69.03729828 2014-04-03 04:00:00,68.99054634 2014-04-03 05:00:00,66.96693467 2014-04-03 06:00:00,67.79585605 2014-04-03 07:00:00,67.30111228 2014-04-03 08:00:00,68.06321777 2014-04-03 09:00:00,68.92309559 2014-04-10 15:00:00,69.95467957 2014-04-10 16:00:00,69.99969109999999 2014-04-10 17:00:00,70.46057561 2014-04-10 18:00:00,69.69177635 2014-04-10 19:00:00,71.01239837 2014-04-10 20:00:00,69.3636139 2014-04-10 21:00:00,69.23956202 2014-04-10 22:00:00,69.02602271 2014-04-10 23:00:00,67.66881974 2014-04-11 00:00:00,66.9784945 2014-04-11 01:00:00,66.1376634 2014-04-11 02:00:00,65.64125076 2014-04-11 03:00:00,64.99436157 2014-04-11 04:00:00,64.15511608 2014-04-11 05:00:00,62.70299143 2014-04-11 06:00:00,63.83944116 2014-04-11 07:00:00,62.44194873 2014-04-11 08:00:00,62.37114409 2014-04-11 09:00:00,65.37565585 2014-04-11 10:00:00,65.96957647 2014-04-11 11:00:00,66.59359265 2014-04-11 12:00:00,68.33141592 2014-04-11 13:00:00,68.92824643 2014-04-11 14:00:00,69.4470812 2014-04-11 15:00:00,70.69379188 2014-04-11 16:00:00,68.80751333 2014-04-11 17:00:00,69.77099451 2014-04-11 18:00:00,69.4302069 2014-04-11 19:00:00,69.69943799 2014-04-11 20:00:00,68.39255358 2014-04-11 21:00:00,69.67023519 2014-04-11 22:00:00,68.57844056 2014-04-11 23:00:00,67.05017892 2014-04-12 00:00:00,68.53844670000001 2014-04-12 01:00:00,66.58977222 2014-04-12 02:00:00,66.4437355 2014-04-12 03:00:00,66.63975574 2014-04-12 04:00:00,65.35200151 2014-04-12 05:00:00,66.56495507 2014-04-12 06:00:00,64.62244069 2014-04-12 07:00:00,64.9923665 2014-04-12 08:00:00,63.97746263 2014-04-12 09:00:00,64.18268808 2014-04-12 10:00:00,64.55629521 2014-04-12 11:00:00,63.96192594 2014-04-12 12:00:00,63.56770877 2014-04-12 13:00:00,63.45102885 2014-04-12 14:00:00,62.75664373 2014-04-12 15:00:00,61.88488434 2014-04-12 16:00:00,61.97105163 2014-04-12 17:00:00,62.03644725 2014-04-12 18:00:00,62.85879831 2014-04-12 19:00:00,61.75532146 2014-04-12 20:00:00,60.33080311 2014-04-12 21:00:00,61.31862007 2014-04-12 22:00:00,61.26515428 2014-04-12 23:00:00,59.564727100000006 2014-04-13 00:00:00,59.92144785 2014-04-13 01:00:00,60.09354127 2014-04-13 02:00:00,59.92218636 2014-04-13 03:00:00,58.86227492 2014-04-13 04:00:00,58.77714115 2014-04-13 05:00:00,59.41074654 2014-04-13 06:00:00,57.84457312 2014-04-13 07:00:00,58.38952164 2014-04-13 08:00:00,59.12502309 2014-04-13 09:00:00,57.45840559 2014-04-13 10:00:00,58.23364994 2014-04-13 11:00:00,58.73348655 2014-04-13 12:00:00,58.97261213 2014-04-13 13:00:00,60.25792529 2014-04-13 14:00:00,59.15943501 2014-04-13 15:00:00,60.26702164 2014-04-13 16:00:00,59.20056905 2014-04-13 17:00:00,59.42050888 2014-04-13 18:00:00,59.61076035 2014-04-13 19:00:00,59.375844799999996 2014-04-13 20:00:00,60.45036956 2014-04-13 21:00:00,60.38321276 2014-04-13 22:00:00,59.91094693 2014-04-13 23:00:00,60.28396361 2014-04-14 00:00:00,58.83249363 2014-04-14 01:00:00,60.184197 2014-04-14 02:00:00,60.57384958 2014-04-14 03:00:00,60.58416247 2014-04-14 04:00:00,59.54132737 2014-04-14 05:00:00,60.578911899999994 2014-04-14 06:00:00,59.20245134 2014-04-14 07:00:00,59.53629772 2014-04-14 08:00:00,61.42760267 2014-04-14 09:00:00,62.35052077 2014-04-14 10:00:00,63.87302969 2014-04-14 11:00:00,63.95474106 2014-04-14 12:00:00,64.33255339 2014-04-14 13:00:00,66.89048639 2014-04-14 14:00:00,66.76290578 2014-04-14 15:00:00,68.22765033 2014-04-14 16:00:00,68.66217484 2014-04-14 17:00:00,68.77584664 2014-04-14 18:00:00,69.85149804 2014-04-14 19:00:00,69.64134024 2014-04-14 20:00:00,68.67883235 2014-04-14 21:00:00,66.53906385 2014-04-14 22:00:00,66.75587974 2014-04-14 23:00:00,66.67419463 2014-04-15 00:00:00,65.2054392 2014-04-15 01:00:00,65.2363275 2014-04-15 02:00:00,63.50605093 2014-04-15 03:00:00,64.46464095 2014-04-15 04:00:00,63.51738461 2014-04-15 05:00:00,63.61950823 2014-04-15 06:00:00,62.96296552 2014-04-15 07:00:00,61.77349005 2014-04-15 08:00:00,63.95443765 2014-04-15 09:00:00,63.98985647 2014-04-15 10:00:00,66.04334863 2014-04-15 11:00:00,68.14218819999999 2014-04-15 12:00:00,68.61566659 2014-04-15 13:00:00,68.80427879999999 2014-04-15 14:00:00,70.24867959 2014-04-15 15:00:00,68.84215496 2014-04-15 16:00:00,71.07422118 2014-04-15 17:00:00,70.7975171 2014-04-15 18:00:00,70.00379538 2014-04-15 19:00:00,69.63818207 2014-04-15 20:00:00,71.11138859 2014-04-15 21:00:00,68.9745537 2014-04-15 22:00:00,68.41451411 2014-04-15 23:00:00,67.63084599 2014-04-16 00:00:00,65.73481705 2014-04-16 01:00:00,65.50434383 2014-04-16 02:00:00,64.79166617 2014-04-16 03:00:00,63.918387100000004 2014-04-16 04:00:00,64.49704161 2014-04-16 05:00:00,63.67515316 2014-04-16 06:00:00,62.46829544 2014-04-16 07:00:00,63.58707467 2014-04-16 08:00:00,64.98478124 2014-04-16 09:00:00,64.79823783 2014-04-16 10:00:00,67.37766731 2014-04-16 11:00:00,67.53637026 2014-04-16 12:00:00,68.93675906 2014-04-16 13:00:00,69.01582856 2014-04-16 14:00:00,70.01135347 2014-04-16 15:00:00,70.54341131 2014-04-16 16:00:00,70.35620490000001 2014-04-16 17:00:00,72.05054652 2014-04-16 18:00:00,70.83587447 2014-04-16 19:00:00,71.22103625 2014-04-16 20:00:00,70.22217235 2014-04-16 21:00:00,69.83271805 2014-04-16 22:00:00,67.95233259 2014-04-16 23:00:00,67.65108997 2014-04-17 00:00:00,67.466994 2014-04-17 01:00:00,65.22016644 2014-04-17 02:00:00,65.24342103 2014-04-17 03:00:00,64.62596906 2014-04-17 04:00:00,63.67041499 2014-04-17 05:00:00,64.21771116 2014-04-17 06:00:00,62.40771234 2014-04-17 07:00:00,64.25745568 2014-04-17 08:00:00,63.78224775 2014-04-17 09:00:00,65.71063960000001 2014-04-17 10:00:00,66.77957199 2014-04-17 11:00:00,68.38229729 2014-04-17 12:00:00,68.29797018 2014-04-17 13:00:00,70.41445853 2014-04-17 14:00:00,68.73075749 2014-04-17 15:00:00,70.53796369999998 2014-04-17 16:00:00,69.84495909999998 2014-04-17 17:00:00,69.92419335 2014-04-17 18:00:00,70.06645502 2014-04-17 19:00:00,70.01194478 2014-04-17 20:00:00,70.75213902 2014-04-17 21:00:00,70.23146023 2014-04-17 22:00:00,68.89087654 2014-04-17 23:00:00,68.74794199 2014-04-18 00:00:00,68.6134614 2014-04-18 01:00:00,67.80409959999999 2014-04-18 02:00:00,66.81999556 2014-04-18 03:00:00,66.76963018 2014-04-18 04:00:00,65.69553058 2014-04-18 05:00:00,65.73002042 2014-04-18 06:00:00,65.04376513 2014-04-18 07:00:00,64.66042336 2014-04-18 08:00:00,66.66369506 2014-04-18 09:00:00,66.91478029 2014-04-18 10:00:00,68.35124962 2014-04-18 11:00:00,68.53892428 2014-04-18 12:00:00,69.18079834 2014-04-18 13:00:00,70.04821235 2014-04-18 14:00:00,69.09186246 2014-04-18 15:00:00,70.13679966 2014-04-18 16:00:00,68.64486802 2014-04-18 17:00:00,69.10913357 2014-04-18 18:00:00,69.34877115 2014-04-18 19:00:00,70.06810868 2014-04-18 20:00:00,69.68681363 2014-04-18 21:00:00,69.28946496 2014-04-18 22:00:00,68.10328878 2014-04-18 23:00:00,68.52704977 2014-04-19 00:00:00,67.80210719 2014-04-19 01:00:00,66.29263566 2014-04-19 02:00:00,66.15580573 2014-04-19 03:00:00,65.50262029 2014-04-19 04:00:00,65.67858252 2014-04-19 05:00:00,66.76499604 2014-04-19 06:00:00,65.38745208 2014-04-19 07:00:00,64.95897072 2014-04-19 08:00:00,64.77271857 2014-04-19 09:00:00,64.36173315 2014-04-19 10:00:00,65.1175339 2014-04-19 11:00:00,64.06584001 2014-04-19 12:00:00,63.84447255 2014-04-19 13:00:00,63.69995847 2014-04-19 14:00:00,64.95980589 2014-04-19 15:00:00,64.54564962 2014-04-19 16:00:00,64.92641544 2014-04-19 17:00:00,64.05690668 2014-04-19 18:00:00,65.14093075 2014-04-19 19:00:00,65.37596399 2014-04-19 20:00:00,64.49955643 2014-04-19 21:00:00,64.61511022 2014-04-19 22:00:00,64.38633566 2014-04-19 23:00:00,64.6986036 2014-04-20 00:00:00,63.69621365 2014-04-20 01:00:00,63.46227468 2014-04-20 02:00:00,61.73732749 2014-04-20 03:00:00,62.88858987 2014-04-20 04:00:00,62.02517391 2014-04-20 05:00:00,61.32938908 2014-04-20 06:00:00,61.58004254 2014-04-20 07:00:00,60.95237553 2014-04-20 08:00:00,60.85101193 2014-04-20 09:00:00,59.91009200000001 2014-04-20 10:00:00,60.32414667 2014-04-20 11:00:00,61.24486641 2014-04-20 12:00:00,59.66938197 2014-04-20 13:00:00,61.12053222 2014-04-20 14:00:00,61.88004071 2014-04-20 15:00:00,60.49012871 2014-04-20 16:00:00,61.00233827 2014-04-20 17:00:00,61.765906799999996 2014-04-20 18:00:00,60.26541206 2014-04-20 19:00:00,60.71115886 2014-04-20 20:00:00,60.52159375 2014-04-20 21:00:00,61.72193037 2014-04-20 22:00:00,60.84591691 2014-04-20 23:00:00,60.77650542 2014-04-21 00:00:00,60.2969507 2014-04-21 01:00:00,60.50295653 2014-04-21 02:00:00,60.86537483 2014-04-21 03:00:00,60.31204125 2014-04-21 04:00:00,59.84361371 2014-04-21 05:00:00,60.93695396 2014-04-21 06:00:00,61.29175138 2014-04-21 07:00:00,61.35624139 2014-04-21 08:00:00,62.51476508 2014-04-21 09:00:00,62.43283694 2014-04-21 10:00:00,64.91681271 2014-04-21 11:00:00,65.39698618 2014-04-21 12:00:00,65.915587 2014-04-21 13:00:00,67.29050932 2014-04-21 14:00:00,68.45738752 2014-04-21 15:00:00,70.07377229 2014-04-21 16:00:00,69.70332453 2014-04-21 17:00:00,69.7202728 2014-04-21 18:00:00,69.40144364 2014-04-21 19:00:00,68.60855551 2014-04-21 20:00:00,68.59433384 2014-04-21 21:00:00,67.36680577 2014-04-21 22:00:00,67.03274551 2014-04-21 23:00:00,67.24095409 2014-04-22 00:00:00,65.7964252 2014-04-22 01:00:00,64.99226274 2014-04-22 02:00:00,64.49559793 2014-04-22 03:00:00,65.11700189 2014-04-22 04:00:00,64.3213603 2014-04-22 05:00:00,63.60761024 2014-04-22 06:00:00,64.31240029 2014-04-22 07:00:00,63.6046907 2014-04-22 08:00:00,64.44609818 2014-04-22 09:00:00,65.51557705 2014-04-22 10:00:00,66.98431814 2014-04-22 11:00:00,67.61193771 2014-04-22 12:00:00,69.98132266 2014-04-22 13:00:00,70.67558021 2014-04-22 14:00:00,69.62883752 2014-04-22 15:00:00,69.69713146 2014-04-22 16:00:00,69.91198782 2014-04-22 17:00:00,70.55887454 2014-04-22 18:00:00,70.51507392 2014-04-22 19:00:00,69.61686927 2014-04-22 20:00:00,69.95093901 2014-04-22 21:00:00,68.91740485 2014-04-22 22:00:00,67.98366316 2014-04-22 23:00:00,69.21152689 2014-04-23 00:00:00,68.4994454 2014-04-23 01:00:00,68.2065762 2014-04-23 02:00:00,67.17531475 2014-04-23 03:00:00,66.98745597 2014-04-23 04:00:00,66.01118571 2014-04-23 05:00:00,66.26108706 2014-04-23 06:00:00,66.03229855 2014-04-23 07:00:00,66.26457169 2014-04-23 08:00:00,66.5901253 2014-04-23 09:00:00,67.33860469 2014-04-23 10:00:00,67.71813475 2014-04-23 11:00:00,68.74407883 2014-04-23 12:00:00,70.07146655 2014-04-23 13:00:00,69.09664385 2014-04-23 14:00:00,68.54085218 2014-04-23 15:00:00,68.74793879 2014-04-23 16:00:00,70.2110304 2014-04-23 17:00:00,69.08812898 2014-04-23 18:00:00,71.14090948 2014-04-23 19:00:00,71.35406032 2014-04-23 20:00:00,70.40898557 2014-04-23 21:00:00,70.11680124 2014-04-23 22:00:00,68.45657214 2014-04-23 23:00:00,68.04369977 2014-04-24 00:00:00,67.86825922 2014-04-24 01:00:00,68.25265298 2014-04-24 02:00:00,67.93389846 2014-04-24 03:00:00,67.41557857 2014-04-24 04:00:00,66.82858317 2014-04-24 05:00:00,66.46827942 2014-04-24 06:00:00,66.70529771 2014-04-24 07:00:00,65.99333339 2014-04-24 08:00:00,66.39954920000001 2014-04-24 09:00:00,68.68937881 2014-04-24 10:00:00,68.86981543 2014-04-24 11:00:00,69.28930829 2014-04-24 12:00:00,70.13701442 2014-04-24 13:00:00,70.87920902 2014-04-24 14:00:00,69.73387857 2014-04-24 15:00:00,71.07672883 2014-04-24 16:00:00,70.8997397 2014-04-24 17:00:00,70.81721973 2014-04-24 18:00:00,70.08894813 2014-04-24 19:00:00,71.49812440000002 2014-04-24 20:00:00,70.33872212 2014-04-24 21:00:00,69.97998584 2014-04-24 22:00:00,69.11046806 2014-04-24 23:00:00,68.18636306 2014-04-25 00:00:00,67.39351909 2014-04-25 01:00:00,66.57525861 2014-04-25 02:00:00,67.73318644 2014-04-25 03:00:00,66.68982673 2014-04-25 04:00:00,65.83218116 2014-04-25 05:00:00,65.95237266 2014-04-25 06:00:00,67.28099527 2014-04-25 07:00:00,66.90419491 2014-04-25 08:00:00,67.80676658 2014-04-25 09:00:00,68.71115712 2014-04-25 10:00:00,70.02939458 2014-04-25 11:00:00,69.32625844 2014-04-25 12:00:00,70.95509984 2014-04-25 13:00:00,70.33649459 2014-04-25 14:00:00,70.46790053 2014-04-25 15:00:00,71.4753647 2014-04-25 16:00:00,71.6850702 2014-04-25 17:00:00,70.43496647 2014-04-25 18:00:00,70.80912379 2014-04-25 19:00:00,70.67649218 2014-04-25 20:00:00,70.53630655 2014-04-25 21:00:00,70.9107218 2014-04-25 22:00:00,69.72934336 2014-04-25 23:00:00,69.6017667 2014-04-26 00:00:00,69.48880205 2014-04-26 01:00:00,67.24793666 2014-04-26 02:00:00,67.33153476 2014-04-26 03:00:00,66.89338891 2014-04-26 04:00:00,66.56130689 2014-04-26 05:00:00,66.53741504 2014-04-26 06:00:00,67.13725522 2014-04-26 07:00:00,66.5594858 2014-04-26 08:00:00,65.90565072 2014-04-26 09:00:00,65.53921771 2014-04-26 10:00:00,65.83948867 2014-04-26 11:00:00,64.57393058 2014-04-26 12:00:00,65.47092598 2014-04-26 13:00:00,64.06228730000001 2014-04-26 14:00:00,65.61321875 2014-04-26 15:00:00,65.0033148 2014-04-26 16:00:00,65.06987305 2014-04-26 17:00:00,65.49571691 2014-04-26 18:00:00,64.89058829999999 2014-04-26 19:00:00,63.93327257 2014-04-26 20:00:00,65.74230017 2014-04-26 21:00:00,64.87334743 2014-04-26 22:00:00,64.59101491 2014-04-26 23:00:00,64.52446439 2014-04-27 00:00:00,65.86073905 2014-04-27 01:00:00,65.70163338 2014-04-27 02:00:00,65.48002454 2014-04-27 03:00:00,65.01981817 2014-04-27 04:00:00,64.07651163 2014-04-27 05:00:00,64.19020524 2014-04-27 06:00:00,64.54513799 2014-04-27 07:00:00,64.16276662 2014-04-27 08:00:00,64.68808942 2014-04-27 09:00:00,65.0067767 2014-04-27 10:00:00,64.86726485 2014-04-27 11:00:00,65.27562701 2014-04-27 12:00:00,64.76188253 2014-04-27 13:00:00,64.21479337 2014-04-27 14:00:00,64.22497124 2014-04-27 15:00:00,63.48983416 2014-04-27 16:00:00,64.02881119 2014-04-27 17:00:00,65.14115001 2014-04-27 18:00:00,64.16580322 2014-04-27 19:00:00,63.82552427 2014-04-27 20:00:00,64.51645768 2014-04-27 21:00:00,64.81548712 2014-04-27 22:00:00,63.65811355 2014-04-27 23:00:00,63.04274263 2014-04-28 00:00:00,63.66900707 2014-04-28 01:00:00,62.84663436 2014-04-28 02:00:00,64.00274294 2014-04-28 03:00:00,64.17028398 2014-04-28 04:00:00,64.29074432 2014-04-28 05:00:00,62.8534311 2014-04-28 06:00:00,64.27748755 2014-04-28 07:00:00,63.93818963 2014-04-28 08:00:00,64.19242071 2014-04-28 09:00:00,66.39555183 2014-04-28 10:00:00,66.35592434 2014-04-28 11:00:00,66.93708398 2014-04-28 12:00:00,67.94603672 2014-04-28 13:00:00,67.83616225 2014-04-28 14:00:00,68.02972643 2014-04-28 15:00:00,67.63528784 2014-04-28 16:00:00,67.95345262 2014-04-28 17:00:00,67.94164899 2014-04-28 18:00:00,66.31355879 2014-04-28 19:00:00,66.90239851 2014-04-28 20:00:00,67.92545865 2014-04-28 21:00:00,66.24886617 2014-04-28 22:00:00,66.61769712 2014-04-28 23:00:00,66.45853965 2014-04-29 00:00:00,65.70015178 2014-04-29 01:00:00,66.15509081 2014-04-29 02:00:00,64.37093221 2014-04-29 03:00:00,64.73766535 2014-04-29 04:00:00,63.71676928 2014-04-29 05:00:00,65.12909065 2014-04-29 06:00:00,64.59083625 2014-04-29 07:00:00,65.39479955 2014-04-29 08:00:00,64.99259943 2014-04-29 09:00:00,63.55132406 2014-04-29 10:00:00,63.86318351 2014-04-29 11:00:00,63.4598629 2014-04-29 12:00:00,63.08150923 2014-04-29 13:00:00,63.48047822 2014-04-29 14:00:00,64.82342973 2014-04-29 15:00:00,64.45813978 2014-04-29 16:00:00,63.80209508 2014-04-29 17:00:00,65.04887616 2014-04-29 18:00:00,65.88072103 2014-04-29 19:00:00,65.4814587 2014-04-29 20:00:00,64.19984122 2014-04-29 21:00:00,65.87838087 2014-04-29 22:00:00,64.72572253 2014-04-29 23:00:00,65.00936847 2014-04-30 00:00:00,64.37972197 2014-04-30 01:00:00,64.81705324 2014-04-30 02:00:00,64.01853731 2014-04-30 03:00:00,62.59835239 2014-04-30 04:00:00,62.15358748 2014-04-30 05:00:00,63.65464859 2014-04-30 06:00:00,62.66869499 2014-04-30 07:00:00,63.19330523 2014-04-30 08:00:00,64.24502053 2014-04-30 09:00:00,65.1453243 2014-04-30 10:00:00,64.9329398 2014-04-30 11:00:00,66.64151484 2014-04-30 12:00:00,66.82120203 2014-04-30 13:00:00,67.1960497 2014-04-30 14:00:00,66.13772358 2014-04-30 15:00:00,66.37318638 2014-04-30 16:00:00,67.38361772 2014-04-30 17:00:00,67.98871109999999 2014-04-30 18:00:00,66.25593843 2014-04-30 19:00:00,65.92849928 2014-04-30 20:00:00,67.21492219 2014-04-30 21:00:00,66.24671438 2014-04-30 22:00:00,66.61478769 2014-04-30 23:00:00,64.84814958 2014-05-01 00:00:00,64.94889814 2014-05-01 01:00:00,64.45625398 2014-05-01 02:00:00,63.9798679 2014-05-01 03:00:00,64.26732464 2014-05-01 04:00:00,64.59177699 2014-05-01 05:00:00,65.37702424 2014-05-01 06:00:00,65.19211401 2014-05-01 07:00:00,65.37953893 2014-05-01 08:00:00,65.05709023 2014-05-01 09:00:00,65.87109317 2014-05-01 10:00:00,66.54947805 2014-05-01 11:00:00,66.4332683 2014-05-01 12:00:00,67.94196795 2014-05-01 13:00:00,67.73779434 2014-05-01 14:00:00,67.94409258 2014-05-01 15:00:00,68.59569962 2014-05-01 16:00:00,67.76281833 2014-05-01 17:00:00,66.3713461 2014-05-01 18:00:00,66.45491031 2014-05-01 19:00:00,67.7664687 2014-05-01 20:00:00,66.30486725 2014-05-01 21:00:00,66.77500592 2014-05-01 22:00:00,66.08791142 2014-05-01 23:00:00,66.23633214 2014-05-02 00:00:00,66.08952394 2014-05-02 01:00:00,65.49363114 2014-05-02 02:00:00,65.20911118 2014-05-02 03:00:00,64.65270388 2014-05-02 04:00:00,65.68346791 2014-05-02 05:00:00,64.53848669 2014-05-02 06:00:00,64.87436222 2014-05-02 07:00:00,65.83693065 2014-05-02 08:00:00,66.45562134 2014-05-02 09:00:00,66.22132242 2014-05-02 10:00:00,67.40617703 2014-05-02 11:00:00,66.82972449 2014-05-02 12:00:00,66.3484439 2014-05-02 13:00:00,66.56058031 2014-05-02 14:00:00,67.87466603 2014-05-02 15:00:00,68.36875479999999 2014-05-02 16:00:00,68.32191349 2014-05-02 17:00:00,68.61482576 2014-05-02 18:00:00,67.74306346 2014-05-02 19:00:00,67.08645996 2014-05-02 20:00:00,68.34330065 2014-05-02 21:00:00,68.30007946 2014-05-02 22:00:00,68.22785404 2014-05-02 23:00:00,66.69875824 2014-05-03 00:00:00,66.4911086 2014-05-03 01:00:00,66.35595511 2014-05-03 02:00:00,66.81821492 2014-05-03 03:00:00,65.56948969 2014-05-03 04:00:00,66.61559763 2014-05-03 05:00:00,65.6976645 2014-05-03 06:00:00,64.59377619 2014-05-03 07:00:00,64.74378706 2014-05-03 08:00:00,65.25902071 2014-05-03 09:00:00,64.47503572 2014-05-03 10:00:00,64.61145531 2014-05-03 11:00:00,63.68596001 2014-05-03 12:00:00,65.43821188 2014-05-03 13:00:00,64.12205423 2014-05-03 14:00:00,65.42301205 2014-05-03 15:00:00,65.95634267 2014-05-03 16:00:00,65.81969209 2014-05-03 17:00:00,64.85601416 2014-05-03 18:00:00,65.00620928 2014-05-03 19:00:00,63.94392708 2014-05-03 20:00:00,65.20208745 2014-05-03 21:00:00,63.84740672 2014-05-03 22:00:00,63.75022634 2014-05-03 23:00:00,64.87600042 2014-05-04 00:00:00,64.18060217 2014-05-04 01:00:00,64.07250966 2014-05-04 02:00:00,62.43332813 2014-05-04 03:00:00,62.52641171 2014-05-04 04:00:00,62.30957888 2014-05-04 05:00:00,62.35436891 2014-05-04 06:00:00,63.42459056 2014-05-04 07:00:00,63.09408094 2014-05-04 08:00:00,62.58243369 2014-05-04 09:00:00,63.37961637 2014-05-04 10:00:00,62.86781634 2014-05-04 11:00:00,62.88417215 2014-05-04 12:00:00,62.11991599 2014-05-04 13:00:00,62.70773678 2014-05-04 14:00:00,63.59298753 2014-05-04 15:00:00,62.71663598 2014-05-04 16:00:00,63.60890306 2014-05-04 17:00:00,62.82802932 2014-05-04 18:00:00,63.79858076 2014-05-04 19:00:00,63.11692463 2014-05-04 20:00:00,62.12890815 2014-05-04 21:00:00,61.59769629 2014-05-04 22:00:00,62.8583145 2014-05-04 23:00:00,61.41615236 2014-05-05 00:00:00,61.49160445 2014-05-05 01:00:00,61.82814205 2014-05-05 02:00:00,61.69737845 2014-05-05 03:00:00,61.65254063 2014-05-05 04:00:00,60.606883700000004 2014-05-05 05:00:00,60.47320097 2014-05-05 06:00:00,61.5530172 2014-05-05 07:00:00,62.01910222 2014-05-05 08:00:00,61.23608102 2014-05-05 09:00:00,63.67999575 2014-05-05 10:00:00,63.36326181 2014-05-05 11:00:00,64.13721032 2014-05-05 12:00:00,64.5332446 2014-05-05 13:00:00,64.19481423 2014-05-05 14:00:00,65.1361502 2014-05-05 15:00:00,65.97596267 2014-05-05 16:00:00,65.85552001 2014-05-05 17:00:00,66.32755106 2014-05-05 18:00:00,66.92969566 2014-05-05 19:00:00,67.2613918 2014-05-05 20:00:00,65.80789035 2014-05-05 21:00:00,66.20385124 2014-05-05 22:00:00,66.51044071 2014-05-05 23:00:00,64.8207324 2014-05-06 00:00:00,63.59220664 2014-05-06 01:00:00,63.23531713 2014-05-06 02:00:00,62.49046863 2014-05-06 03:00:00,62.28369414 2014-05-06 04:00:00,63.30749881 2014-05-06 05:00:00,62.80276256 2014-05-06 06:00:00,62.34187092 2014-05-06 07:00:00,64.17473372 2014-05-06 08:00:00,63.97093501 2014-05-06 09:00:00,65.0523434 2014-05-06 10:00:00,64.75464232 2014-05-06 11:00:00,65.04876411 2014-05-06 12:00:00,65.74920338 2014-05-06 13:00:00,66.40186825 2014-05-06 14:00:00,66.18664212 2014-05-06 15:00:00,67.31747692 2014-05-06 16:00:00,66.95425995 2014-05-06 17:00:00,66.93790428 2014-05-06 18:00:00,67.73969822 2014-05-06 19:00:00,66.72610529 2014-05-06 20:00:00,66.08638956 2014-05-06 21:00:00,66.71634147 2014-05-06 22:00:00,65.14686479999999 2014-05-06 23:00:00,64.64265197 2014-05-07 00:00:00,65.62693199 2014-05-07 01:00:00,64.08219838 2014-05-07 02:00:00,64.54200752 2014-05-07 03:00:00,65.09258433 2014-05-07 04:00:00,64.43853993 2014-05-07 05:00:00,64.62081306 2014-05-07 06:00:00,63.29588419 2014-05-07 07:00:00,64.71917156 2014-05-07 08:00:00,63.73179147 2014-05-07 09:00:00,66.29709464 2014-05-07 10:00:00,67.19427577 2014-05-07 11:00:00,67.06897531 2014-05-07 12:00:00,68.72099133 2014-05-07 13:00:00,69.96068224 2014-05-07 14:00:00,70.56685636 2014-05-07 15:00:00,69.75004488 2014-05-07 16:00:00,69.17335133 2014-05-07 17:00:00,70.50844769 2014-05-07 18:00:00,70.24540175 2014-05-07 19:00:00,70.81293524 2014-05-07 20:00:00,69.94704581 2014-05-07 21:00:00,68.86682809 2014-05-07 22:00:00,68.39329009 2014-05-07 23:00:00,66.6067577 2014-05-08 00:00:00,66.76001378 2014-05-08 01:00:00,66.27637613 2014-05-08 02:00:00,65.75512541 2014-05-08 03:00:00,65.81007339 2014-05-08 04:00:00,65.37270606 2014-05-08 05:00:00,66.28889617 2014-05-08 06:00:00,66.23410255 2014-05-08 07:00:00,64.91234651 2014-05-08 08:00:00,67.05133706 2014-05-08 09:00:00,67.83863065 2014-05-08 10:00:00,68.10943196 2014-05-08 11:00:00,69.65642273 2014-05-08 12:00:00,70.60573585 2014-05-08 13:00:00,70.62927012 2014-05-08 14:00:00,70.21115072 2014-05-08 15:00:00,70.29113189 2014-05-08 16:00:00,70.64550484 2014-05-08 17:00:00,71.27645212 2014-05-08 18:00:00,71.83727293 2014-05-08 19:00:00,71.46726041 2014-05-08 20:00:00,69.75939304 2014-05-08 21:00:00,70.11417736 2014-05-08 22:00:00,70.05504972 2014-05-08 23:00:00,69.37027812 2014-05-09 00:00:00,67.98228281 2014-05-09 01:00:00,67.7865791 2014-05-09 02:00:00,68.43446290000001 2014-05-09 03:00:00,68.07785549 2014-05-09 04:00:00,67.81285784 2014-05-09 05:00:00,67.56774369 2014-05-09 06:00:00,66.24760777 2014-05-09 07:00:00,67.65004294 2014-05-09 08:00:00,67.05143804 2014-05-09 09:00:00,69.05576366 2014-05-09 10:00:00,70.10149255 2014-05-09 11:00:00,70.63274013 2014-05-09 12:00:00,71.06084806 2014-05-09 13:00:00,71.07378866 2014-05-09 14:00:00,69.87334432 2014-05-09 15:00:00,70.92486991 2014-05-09 16:00:00,71.2245648 2014-05-09 17:00:00,70.78867373 2014-05-09 18:00:00,71.99197043 2014-05-09 19:00:00,70.89590208 2014-05-09 20:00:00,72.38733933 2014-05-09 21:00:00,70.14675317 2014-05-09 22:00:00,69.74583888 2014-05-09 23:00:00,69.43160284 2014-05-10 00:00:00,68.23254059 2014-05-10 01:00:00,69.47792142 2014-05-10 02:00:00,68.91530719 2014-05-10 03:00:00,68.35492212 2014-05-10 04:00:00,68.39336374 2014-05-10 05:00:00,68.42272702 2014-05-10 06:00:00,67.0775277 2014-05-10 07:00:00,66.90356792 2014-05-10 08:00:00,66.37013021 2014-05-10 09:00:00,68.21760218 2014-05-10 10:00:00,67.53453251 2014-05-10 11:00:00,67.42839785 2014-05-10 12:00:00,66.96098515 2014-05-10 13:00:00,67.33616722 2014-05-10 14:00:00,66.84359334 2014-05-10 15:00:00,65.89084398 2014-05-10 16:00:00,66.81261725 2014-05-10 17:00:00,65.32919958 2014-05-10 18:00:00,65.92892671 2014-05-10 19:00:00,66.58894429 2014-05-10 20:00:00,65.10538195 2014-05-10 21:00:00,65.63011787 2014-05-10 22:00:00,65.81492917 2014-05-10 23:00:00,65.57018764 2014-05-11 00:00:00,63.91974669 2014-05-11 01:00:00,64.51176296 2014-05-11 02:00:00,64.43387227 2014-05-11 03:00:00,64.33383818 2014-05-11 04:00:00,64.57554395 2014-05-11 05:00:00,65.03499427 2014-05-11 06:00:00,63.11467108 2014-05-11 07:00:00,63.87061555 2014-05-11 08:00:00,64.64784774 2014-05-11 09:00:00,63.64523071 2014-05-11 10:00:00,64.05141919 2014-05-11 11:00:00,62.7828001 2014-05-11 12:00:00,63.82347474 2014-05-11 13:00:00,63.58691465 2014-05-11 14:00:00,62.08829654 2014-05-11 15:00:00,63.01928506 2014-05-11 16:00:00,63.90711168 2014-05-11 17:00:00,63.07839314 2014-05-11 18:00:00,62.69840054 2014-05-11 19:00:00,61.72789308 2014-05-11 20:00:00,62.289274 2014-05-11 21:00:00,63.08826676 2014-05-11 22:00:00,61.55557216 2014-05-11 23:00:00,63.00932675 2014-05-12 00:00:00,62.18412627 2014-05-12 01:00:00,62.39660826 2014-05-12 02:00:00,61.14767562 2014-05-12 03:00:00,61.13299926 2014-05-12 04:00:00,62.20171526 2014-05-12 05:00:00,61.03856972 2014-05-12 06:00:00,62.82075925 2014-05-12 07:00:00,62.287278799999996 2014-05-12 08:00:00,61.74042901 2014-05-12 09:00:00,64.34959977 2014-05-12 10:00:00,66.00850439 2014-05-12 11:00:00,65.98530817 2014-05-12 12:00:00,67.03067426 2014-05-12 13:00:00,68.11149661 2014-05-12 14:00:00,68.18592974 2014-05-12 15:00:00,69.09194409999999 2014-05-12 16:00:00,70.46158593 2014-05-12 17:00:00,68.55542525 2014-05-12 18:00:00,68.18348692 2014-05-12 19:00:00,68.79946301 2014-05-12 20:00:00,68.94392853 2014-05-12 21:00:00,68.37912217 2014-05-12 22:00:00,68.03272736 2014-05-12 23:00:00,66.7522962 2014-05-13 00:00:00,65.70093962 2014-05-13 01:00:00,65.23145055 2014-05-13 02:00:00,65.58334605 2014-05-13 03:00:00,64.43826513 2014-05-13 04:00:00,64.76745107 2014-05-13 05:00:00,63.63936741 2014-05-13 06:00:00,64.99365642 2014-05-13 07:00:00,65.42791053 2014-05-13 08:00:00,64.54368408 2014-05-13 09:00:00,65.7424681 2014-05-13 10:00:00,68.2490268 2014-05-13 11:00:00,68.81523729 2014-05-13 12:00:00,69.61897566 2014-05-13 13:00:00,69.27540087 2014-05-13 14:00:00,69.46898521 2014-05-13 15:00:00,70.39851654 2014-05-13 16:00:00,70.72748205 2014-05-13 17:00:00,70.07376172 2014-05-13 18:00:00,70.43111508 2014-05-13 19:00:00,69.18648323 2014-05-13 20:00:00,69.33720712 2014-05-13 21:00:00,68.52452572 2014-05-13 22:00:00,68.66320083 2014-05-13 23:00:00,67.39728285 2014-05-14 00:00:00,68.3111207 2014-05-14 01:00:00,67.1601394 2014-05-14 02:00:00,66.97372975 2014-05-14 03:00:00,66.48481188 2014-05-14 04:00:00,64.8808456 2014-05-14 05:00:00,64.70801495 2014-05-14 06:00:00,64.5459563 2014-05-14 07:00:00,65.67840491 2014-05-14 08:00:00,65.05875661 2014-05-14 09:00:00,67.03858825 2014-05-14 10:00:00,69.05639384 2014-05-14 11:00:00,68.99189609999999 2014-05-14 12:00:00,69.97788528 2014-05-14 13:00:00,70.175432 2014-05-14 14:00:00,68.16664370000001 2014-05-14 15:00:00,68.57300267 2014-05-14 16:00:00,69.83526008 2014-05-14 17:00:00,70.27480031 2014-05-14 18:00:00,70.20609040000001 2014-05-14 19:00:00,69.40921677 2014-05-14 20:00:00,70.27798951 2014-05-14 21:00:00,68.30333556 2014-05-14 22:00:00,68.09324242 2014-05-14 23:00:00,68.36429597 2014-05-15 00:00:00,67.72416061 2014-05-15 01:00:00,67.8085136 2014-05-15 02:00:00,68.26962214 2014-05-15 03:00:00,66.64600393 2014-05-15 04:00:00,67.56801604 2014-05-15 05:00:00,67.36462946 2014-05-15 06:00:00,64.81152604 2014-05-15 07:00:00,66.53328753 2014-05-15 08:00:00,67.08670333 2014-05-15 09:00:00,66.85800575 2014-05-15 10:00:00,69.47031702 2014-05-15 11:00:00,70.77703377 2014-05-15 12:00:00,71.07003789 2014-05-15 13:00:00,70.78202725 2014-05-15 14:00:00,70.7083186 2014-05-15 15:00:00,70.96353620000002 2014-05-15 16:00:00,70.2180453 2014-05-15 17:00:00,71.14732103 2014-05-15 18:00:00,71.78243404 2014-05-15 19:00:00,70.94431125 2014-05-15 20:00:00,70.25408586 2014-05-15 21:00:00,69.97385592 2014-05-15 22:00:00,71.20814017 2014-05-15 23:00:00,70.28109027 2014-05-16 00:00:00,68.42534022 2014-05-16 01:00:00,68.14026632 2014-05-16 02:00:00,68.31516842 2014-05-16 03:00:00,68.80554576 2014-05-16 04:00:00,68.70805438 2014-05-16 05:00:00,68.21126844 2014-05-16 06:00:00,67.02311979 2014-05-16 07:00:00,68.13634615 2014-05-16 08:00:00,68.50810021 2014-05-16 09:00:00,68.78472332 2014-05-16 10:00:00,70.26313322 2014-05-16 11:00:00,69.48894493 2014-05-16 12:00:00,69.78809126 2014-05-16 13:00:00,69.96723012 2014-05-16 14:00:00,69.74249505 2014-05-16 15:00:00,70.69057352 2014-05-16 16:00:00,70.63243838 2014-05-16 17:00:00,70.67548445 2014-05-16 18:00:00,71.48839758 2014-05-16 19:00:00,70.21791457 2014-05-16 20:00:00,69.93428517 2014-05-16 21:00:00,70.22321349 2014-05-16 22:00:00,70.68873242 2014-05-16 23:00:00,68.72204475 2014-05-17 00:00:00,69.45225691 2014-05-17 01:00:00,68.41224787 2014-05-17 02:00:00,68.36748732 2014-05-17 03:00:00,67.63648402 2014-05-17 04:00:00,67.66201157 2014-05-17 05:00:00,65.90307781 2014-05-17 06:00:00,66.21437481 2014-05-17 07:00:00,65.82644339 2014-05-17 08:00:00,65.50506941 2014-05-17 09:00:00,65.74501564 2014-05-17 10:00:00,65.36640537 2014-05-17 11:00:00,65.90704699 2014-05-17 12:00:00,63.77248723 2014-05-17 13:00:00,64.55949992 2014-05-17 14:00:00,64.5256338 2014-05-17 15:00:00,64.67400160000001 2014-05-17 16:00:00,62.79405286 2014-05-17 17:00:00,64.31443601 2014-05-17 18:00:00,62.55982025 2014-05-17 19:00:00,62.74968304 2014-05-17 20:00:00,62.73063243 2014-05-17 21:00:00,63.65406403 2014-05-17 22:00:00,63.42070867 2014-05-17 23:00:00,61.94114934 2014-05-18 00:00:00,62.89319989 2014-05-18 01:00:00,61.96136235 2014-05-18 02:00:00,61.33631343 2014-05-18 03:00:00,61.95426535 2014-05-18 04:00:00,61.38195858 2014-05-18 05:00:00,62.38443786 2014-05-18 06:00:00,61.0947659 2014-05-18 07:00:00,61.36331427 2014-05-18 08:00:00,60.59300743 2014-05-18 09:00:00,60.43062383 2014-05-18 10:00:00,60.58242408 2014-05-18 11:00:00,60.31117133 2014-05-18 12:00:00,59.76775547 2014-05-18 13:00:00,59.86404445 2014-05-18 14:00:00,60.24787212 2014-05-18 15:00:00,60.87471092 2014-05-18 16:00:00,60.28561460000001 2014-05-18 17:00:00,59.52889185 2014-05-18 18:00:00,59.31666076 2014-05-18 19:00:00,59.14006513 2014-05-18 20:00:00,59.33578729 2014-05-18 21:00:00,58.5039748 2014-05-18 22:00:00,59.10760819 2014-05-18 23:00:00,58.16034228 2014-05-19 00:00:00,58.42363855 2014-05-19 01:00:00,57.8619057 2014-05-19 02:00:00,58.63929497 2014-05-19 03:00:00,59.07469099 2014-05-19 04:00:00,60.49092523 2014-05-19 05:00:00,59.71185823 2014-05-19 06:00:00,60.37589367 2014-05-19 07:00:00,60.17109245 2014-05-19 08:00:00,60.29668226 2014-05-19 09:00:00,62.032778 2014-05-19 10:00:00,63.30565358 2014-05-19 11:00:00,66.46108503 2014-05-19 12:00:00,68.26175947 2014-05-19 13:00:00,70.71157984 2014-05-19 14:00:00,71.27550282 2014-05-19 15:00:00,72.16832368 2014-05-19 16:00:00,71.18424703 2014-05-19 17:00:00,72.14062818 2014-05-19 18:00:00,71.21197512 2014-05-19 19:00:00,69.21714746 2014-05-19 20:00:00,68.35285951 2014-05-19 21:00:00,65.94373646 2014-05-19 22:00:00,63.16581259 2014-05-19 23:00:00,63.4757356 2014-05-20 00:00:00,63.46895245 2014-05-20 01:00:00,61.42920712 2014-05-20 02:00:00,61.67708270000001 2014-05-20 03:00:00,61.78693595 2014-05-20 04:00:00,60.88555024 2014-05-20 05:00:00,61.49993807 2014-05-20 06:00:00,61.05565421 2014-05-20 07:00:00,61.47083928 2014-05-20 08:00:00,62.30626718 2014-05-20 09:00:00,62.87057976 2014-05-20 10:00:00,63.400864500000004 2014-05-20 11:00:00,67.54217170000001 2014-05-20 12:00:00,69.71421777 2014-05-20 13:00:00,69.51084605 2014-05-20 14:00:00,71.30924261 2014-05-20 15:00:00,71.54100964 2014-05-20 16:00:00,72.16153754 2014-05-20 17:00:00,70.88654096 2014-05-20 18:00:00,70.91172121 2014-05-20 19:00:00,72.16415303 2014-05-20 20:00:00,70.52750726 2014-05-20 21:00:00,67.87157133 2014-05-20 22:00:00,68.33303676 2014-05-20 23:00:00,66.90035458 2014-05-21 00:00:00,66.99561858 2014-05-21 01:00:00,65.40626786 2014-05-21 02:00:00,64.32359927 2014-05-21 03:00:00,63.56365044 2014-05-21 04:00:00,64.11854793 2014-05-21 05:00:00,62.70245453 2014-05-21 06:00:00,62.74071071 2014-05-21 07:00:00,64.71093807 2014-05-21 08:00:00,65.83512160000001 2014-05-21 09:00:00,66.70320421 2014-05-21 10:00:00,68.58472225 2014-05-21 11:00:00,71.45729537 2014-05-21 12:00:00,71.66573622 2014-05-21 13:00:00,72.395749 2014-05-21 14:00:00,73.90430952 2014-05-21 15:00:00,74.74593843 2014-05-21 16:00:00,74.30063758 2014-05-21 17:00:00,72.59432304 2014-05-21 18:00:00,72.22398046 2014-05-21 19:00:00,72.32603021 2014-05-21 20:00:00,73.63394052 2014-05-21 21:00:00,71.85085806 2014-05-21 22:00:00,70.92319988 2014-05-21 23:00:00,69.67101298 2014-05-22 00:00:00,69.59055937 2014-05-22 01:00:00,68.10096848 2014-05-22 02:00:00,67.59063877 2014-05-22 03:00:00,67.28802796 2014-05-22 04:00:00,65.50415242 2014-05-22 05:00:00,64.98749725 2014-05-22 06:00:00,63.84289079999999 2014-05-22 07:00:00,65.27590436 2014-05-22 08:00:00,65.24654655 2014-05-22 09:00:00,69.10167387 2014-05-22 10:00:00,70.78848187 2014-05-22 11:00:00,71.86870384 2014-05-22 12:00:00,71.94794239 2014-05-22 13:00:00,73.677598 2014-05-22 14:00:00,72.98770276 2014-05-22 15:00:00,74.42875737 2014-05-22 16:00:00,72.64701052 2014-05-22 17:00:00,73.13696747 2014-05-22 18:00:00,72.89262523 2014-05-22 19:00:00,71.9456771 2014-05-22 20:00:00,72.75306445 2014-05-22 21:00:00,72.16946467 2014-05-22 22:00:00,70.85768581 2014-05-22 23:00:00,68.89846747 2014-05-23 00:00:00,69.76426088 2014-05-23 01:00:00,67.22274865 2014-05-23 02:00:00,66.84469742 2014-05-23 03:00:00,65.7499409 2014-05-23 04:00:00,65.72828867 2014-05-23 05:00:00,64.56403526 2014-05-23 06:00:00,64.82619471 2014-05-23 07:00:00,65.55274567 2014-05-23 08:00:00,66.27026002 2014-05-23 09:00:00,68.11559824 2014-05-23 10:00:00,69.89230339 2014-05-23 11:00:00,70.85563315 2014-05-23 12:00:00,72.70590985 2014-05-23 13:00:00,73.19388671 2014-05-23 14:00:00,71.69026293 2014-05-23 15:00:00,71.85985178 2014-05-23 16:00:00,73.21648743 2014-05-23 17:00:00,72.87018134 2014-05-23 18:00:00,72.78601953 2014-05-23 19:00:00,72.3176002 2014-05-23 20:00:00,72.96734992 2014-05-23 21:00:00,72.9728198 2014-05-23 22:00:00,71.42381462 2014-05-23 23:00:00,71.5294155 2014-05-24 00:00:00,70.53019592 2014-05-24 01:00:00,67.44737298 2014-05-24 02:00:00,68.10673337 2014-05-24 03:00:00,66.54488604 2014-05-24 04:00:00,65.99044378 2014-05-24 05:00:00,65.57383653 2014-05-24 06:00:00,63.7342402 2014-05-24 07:00:00,64.60030306 2014-05-24 08:00:00,63.81887969 2014-05-24 09:00:00,62.53317986 2014-05-24 10:00:00,62.63998719 2014-05-24 11:00:00,63.36766655 2014-05-24 12:00:00,62.24567585 2014-05-24 13:00:00,62.11892222 2014-05-24 14:00:00,60.93392081 2014-05-24 15:00:00,60.93279727 2014-05-24 16:00:00,61.2825587 2014-05-24 17:00:00,61.86767484 2014-05-24 18:00:00,61.09664628 2014-05-24 19:00:00,62.27844332 2014-05-24 20:00:00,61.90070789 2014-05-24 21:00:00,62.39310154 2014-05-24 22:00:00,62.30137458 2014-05-24 23:00:00,62.56461867 2014-05-25 00:00:00,62.72498472 2014-05-25 01:00:00,61.83288929 2014-05-25 02:00:00,61.81999904 2014-05-25 03:00:00,61.63311346 2014-05-25 04:00:00,62.64551718 2014-05-25 05:00:00,62.36561658 2014-05-25 06:00:00,60.95432355 2014-05-25 07:00:00,62.2887861 2014-05-25 08:00:00,61.79099234 2014-05-25 09:00:00,61.2350892 2014-05-25 10:00:00,61.70115537 2014-05-25 11:00:00,62.50943034 2014-05-25 12:00:00,61.01775642 2014-05-25 13:00:00,62.17679039 2014-05-25 14:00:00,62.78656524 2014-05-25 15:00:00,61.01764809 2014-05-25 16:00:00,62.19066364 2014-05-25 17:00:00,62.3200289 2014-05-25 18:00:00,61.24446489 2014-05-25 19:00:00,61.04660004 2014-05-25 20:00:00,62.45615333 2014-05-25 21:00:00,60.84765432 2014-05-25 22:00:00,62.16201772 2014-05-25 23:00:00,61.47244327 2014-05-26 00:00:00,62.07873026 2014-05-26 01:00:00,61.76786 2014-05-26 02:00:00,61.14309718 2014-05-26 03:00:00,61.00938428 2014-05-26 04:00:00,61.95202076 2014-05-26 05:00:00,62.03764829 2014-05-26 06:00:00,61.473338899999995 2014-05-26 07:00:00,61.51732548 2014-05-26 08:00:00,63.77163674 2014-05-26 09:00:00,66.16135606 2014-05-26 10:00:00,68.07227638 2014-05-26 11:00:00,69.81799259 2014-05-26 12:00:00,72.0269253 2014-05-26 13:00:00,71.77669121 2014-05-26 14:00:00,72.19859519 2014-05-26 15:00:00,72.23311654 2014-05-26 16:00:00,72.51360720000002 2014-05-26 17:00:00,73.97990891 2014-05-26 18:00:00,72.13547844 2014-05-26 19:00:00,73.53223604 2014-05-26 20:00:00,71.63600005 2014-05-26 21:00:00,70.98695943 2014-05-26 22:00:00,69.02377801 2014-05-26 23:00:00,68.51109537 2014-05-27 00:00:00,67.10193816 2014-05-27 01:00:00,66.822098 2014-05-27 02:00:00,65.9294706 2014-05-27 03:00:00,67.12169762 2014-05-27 04:00:00,65.4066128 2014-05-27 05:00:00,64.94669438 2014-05-27 06:00:00,64.01596424 2014-05-27 07:00:00,63.637964399999994 2014-05-27 08:00:00,64.58194931 2014-05-27 09:00:00,66.86987932 2014-05-27 10:00:00,70.10010407 2014-05-27 11:00:00,71.53161261 2014-05-27 12:00:00,72.17782106 2014-05-27 13:00:00,72.68078037 2014-05-27 14:00:00,71.96861391 2014-05-27 15:00:00,72.11443201 2014-05-27 16:00:00,73.00783047 2014-05-27 17:00:00,73.08768457 2014-05-27 18:00:00,71.32243816 2014-05-27 19:00:00,71.49022791 2014-05-27 20:00:00,71.8134752 2014-05-27 21:00:00,69.75022022 2014-05-27 22:00:00,69.68719735 2014-05-27 23:00:00,68.98695874 2014-05-28 00:00:00,68.63483818 2014-05-28 01:00:00,67.0000815 2014-05-28 02:00:00,66.52891628 2014-05-28 03:00:00,67.65632279 2014-05-28 04:00:00,65.74329837 2014-05-28 05:00:00,66.24037883 2014-05-28 06:00:00,64.78402266 2014-05-28 07:00:00,65.6458741 2014-05-28 08:00:00,67.47256826 2014-05-28 09:00:00,68.03307954 2014-05-28 10:00:00,70.45571697 2014-05-28 11:00:00,72.37020644 2014-05-28 12:00:00,72.17295622 2014-05-28 13:00:00,72.04656545 2014-05-28 14:00:00,71.82522648 2014-05-28 15:00:00,72.58408858 ================================================ FILE: workspace/anomaly_detector/datasets/selected/variance_change/exchange-3_cpm_results.csv ================================================ timestamp,value 2011-07-01 00:15:01,0.405422534525 2011-07-01 01:15:01,0.433961278227 2011-07-01 02:15:01,0.389267501625 2011-07-01 03:15:01,0.368098502243 2011-07-01 04:15:01,0.365234426765 2011-07-01 05:15:01,0.3428794869 2011-07-01 06:15:01,0.320650020989 2011-07-01 07:15:01,0.328999171839 2011-07-01 08:15:01,0.330918820695 2011-07-01 09:15:01,0.396968683829 2011-07-01 10:15:01,0.44347161212 2011-07-01 11:15:01,0.662412074347 2011-07-01 12:15:01,0.707460331375 2011-07-01 13:15:01,0.597161557559 2011-07-01 14:15:01,0.600127175161 2011-07-01 15:15:01,0.534812246524 2011-07-01 16:15:01,0.46917505741 2011-07-01 17:15:01,0.505456517193 2011-07-01 18:15:01,0.4535763584 2011-07-01 19:15:01,0.579827163973 2011-07-01 20:15:01,0.929018598624 2011-07-01 21:15:01,0.481969218049 2011-07-01 22:15:01,1.59456911756 2011-07-01 23:15:01,3.02086765513 2011-07-02 00:15:01,2.82484901469 2011-07-02 01:15:01,1.01660459594 2011-07-02 02:15:01,0.550420623732 2011-07-02 03:15:01,0.689861668363 2011-07-02 04:15:01,0.643394562177 2011-07-02 05:15:01,0.603330401792 2011-07-02 06:15:01,0.60099737106 2011-07-02 07:15:01,0.644907856905 2011-07-02 08:15:01,0.619896282481 2011-07-02 09:15:01,0.711410835499 2011-07-02 10:15:01,0.823032683736 2011-07-02 11:15:01,0.982650117997 2011-07-02 12:15:01,1.82198845938 2011-07-02 13:15:01,1.4539117855 2011-07-02 14:15:01,1.33707622155 2011-07-02 15:15:01,1.08711717782 2011-07-02 16:15:01,0.91170299956 2011-07-02 17:15:01,0.803212193223 2011-07-02 18:15:01,1.11925182413 2011-07-02 19:15:01,0.747777030865 2011-07-02 20:15:01,0.79998925588 2011-07-02 21:15:01,0.765987648091 2011-07-02 22:15:01,0.705948517041 2011-07-02 23:15:01,1.45388610672 2011-07-03 00:15:01,1.38902113011 2011-07-03 01:15:01,0.925834177713 2011-07-03 02:15:01,0.831415320602 2011-07-03 03:15:01,0.483019261215 2011-07-03 04:15:01,0.693500280828 2011-07-03 05:15:01,0.680136615604 2011-07-03 06:15:01,0.696506878058 2011-07-03 07:15:01,0.742017606353 2011-07-03 08:15:01,0.713239099849 2011-07-03 09:15:01,0.757453614431 2011-07-03 10:15:01,0.963004377293 2011-07-03 11:15:01,1.6822211246 2011-07-03 12:15:01,2.07516028693 2011-07-03 13:15:01,1.94973024968 2011-07-03 14:15:01,1.38908773657 2011-07-03 15:15:01,1.11706077222 2011-07-03 16:15:01,1.00365466979 2011-07-03 17:15:01,0.959327269607 2011-07-03 18:15:01,0.835083924374 2011-07-03 19:15:01,0.814624009308 2011-07-03 20:15:01,0.827716419656 2011-07-03 21:15:01,0.882878070554 2011-07-03 22:15:01,0.997623517817 2011-07-03 23:15:01,1.74638339578 2011-07-04 00:15:01,1.43257308234 2011-07-04 01:15:01,0.943704898459 2011-07-04 02:15:01,0.558643628895 2011-07-04 03:15:01,0.715673181984 2011-07-04 04:15:01,0.732596504133 2011-07-04 05:15:01,0.640847995481 2011-07-04 06:15:01,0.623399850096 2011-07-04 07:15:01,0.674131851371 2011-07-04 08:15:01,0.781035713426 2011-07-04 09:15:01,0.684518122173 2011-07-04 10:15:01,0.899108227688 2011-07-04 11:15:01,1.63733247215 2011-07-04 12:15:01,1.74557145559 2011-07-04 13:15:01,1.97659441357 2011-07-04 14:15:01,1.58846906697 2011-07-04 15:15:01,1.04741587993 2011-07-04 16:15:01,0.678772584881 2011-07-04 17:15:01,0.602611129637 2011-07-04 18:15:01,0.570830160915 2011-07-04 19:15:01,0.550038076316 2011-07-04 20:15:01,0.59489693004 2011-07-04 21:15:01,0.582188580506 2011-07-04 22:15:01,0.675870716328 2011-07-04 23:15:01,1.05814892078 2011-07-05 00:15:01,1.09302018155 2011-07-05 01:15:01,0.619185328719 2011-07-05 02:15:01,0.546216679365 2011-07-05 03:15:01,0.43930623552 2011-07-05 04:15:01,0.464924821965 2011-07-05 05:15:01,0.457552001746 2011-07-05 06:15:01,0.426136705088 2011-07-05 07:15:01,0.463126895367 2011-07-05 08:15:01,0.470788232029 2011-07-05 09:15:01,0.438059738418 2011-07-05 10:15:01,0.750424972956 2011-07-05 11:15:01,0.787270610412 2011-07-05 12:15:01,1.07755946225 2011-07-05 13:15:01,0.998522373197 2011-07-05 14:15:01,0.952744270496 2011-07-05 15:15:01,0.707829298362 2011-07-05 16:15:01,0.612651923352 2011-07-05 17:15:01,0.582697780816 2011-07-05 18:15:01,0.650834949828 2011-07-05 19:15:01,0.616827982495 2011-07-05 20:15:01,0.588550728092 2011-07-05 21:15:01,0.525827739324 2011-07-05 22:15:01,0.580492705313 2011-07-05 23:15:01,0.850236788743 2011-07-06 00:15:01,0.989699069715 2011-07-06 01:15:01,0.542059746448 2011-07-06 02:15:01,0.417662676746 2011-07-06 03:15:01,0.42774941839 2011-07-06 04:15:01,0.42921970945 2011-07-06 05:15:01,0.407084105315 2011-07-06 06:15:01,0.419973474988 2011-07-06 07:15:01,0.419987213504 2011-07-06 08:15:01,0.419571904869 2011-07-06 09:15:01,0.542099108317 2011-07-06 10:15:01,0.523028762708 2011-07-06 11:15:01,0.860811277047 2011-07-06 12:15:01,1.03834696676 2011-07-06 13:15:01,1.02756469696 2011-07-06 14:15:01,0.726965750121 2011-07-06 15:15:01,0.697692029382 2011-07-06 16:15:01,0.61312845603 2011-07-06 17:15:01,0.589332440756 2011-07-06 18:15:01,0.70509726472 2011-07-06 19:15:01,0.684018898444 2011-07-06 20:15:01,0.453724582931 2011-07-06 21:15:01,0.689319329302 2011-07-06 22:15:01,0.56934558103 2011-07-06 23:15:01,0.593638974059 2011-07-07 00:15:01,0.495223004774 2011-07-07 01:15:01,0.533024251743 2011-07-07 02:15:01,0.513768520467 2011-07-07 05:15:01,0.484609943601 2011-07-07 06:15:01,0.372865059711 2011-07-07 07:15:01,0.580024914694 2011-07-07 08:15:01,0.448067683962 2011-07-07 09:15:01,0.613364729387 2011-07-07 10:15:01,0.618467559655 2011-07-07 11:15:01,0.838079048024 2011-07-07 12:15:01,1.2565580859 2011-07-07 13:15:01,1.14752664089 2011-07-07 14:15:01,1.01583644619 2011-07-07 15:15:01,0.913571537965 2011-07-07 16:15:01,0.618304360192 2011-07-07 17:15:01,0.763646369801 2011-07-07 18:15:01,0.764605470099 2011-07-07 19:15:01,1.21798800094 2011-07-07 20:15:01,1.01495047186 2011-07-07 21:15:01,1.03107344633 2011-07-07 22:15:01,0.876598530712 2011-07-07 23:15:01,0.552934085566 2011-07-08 00:15:01,0.49550387185 2011-07-08 01:15:01,0.847840103159 2011-07-08 02:15:01,0.643240884261 2011-07-08 06:15:01,0.706602697276 2011-07-08 09:15:01,0.681349823745 2011-07-08 10:15:01,0.590646181328 2011-07-08 14:15:01,1.24385033027 2011-07-08 16:15:01,2.59258016906 2011-07-08 17:15:01,1.3542439637 2011-07-08 18:15:01,0.700856342781 2011-07-08 19:15:01,0.970253925004 2011-07-08 20:15:01,1.18064743289 2011-07-08 21:15:01,1.04666954508 2011-07-08 22:15:01,1.09588027648 2011-07-08 23:15:01,0.989867032787 2011-07-09 09:15:01,0.722730241672 2011-07-09 15:15:01,0.672810392706 2011-07-09 17:15:01,0.730694412571 2011-07-09 18:15:01,1.1065965848 2011-07-09 19:15:01,0.951126681146 2011-07-09 20:15:01,0.86612700358 2011-07-09 21:15:01,0.822021986321 2011-07-09 22:15:01,1.03145922094 2011-07-09 23:15:01,1.16544612166 2011-07-10 00:15:01,1.05581045236 2011-07-10 01:15:01,0.933769979761 2011-07-10 02:15:01,0.852321869447 2011-07-10 03:15:01,0.562376237624 2011-07-10 04:15:01,0.690265027243 2011-07-10 05:15:01,0.661577265667 2011-07-10 06:15:01,0.683708791707 2011-07-10 07:15:01,0.585272294012 2011-07-10 08:15:01,0.725823769416 2011-07-10 09:15:01,1.06548190842 2011-07-10 10:15:01,0.812296171035 2011-07-10 11:15:01,1.15012216089 2011-07-10 12:15:01,1.91079022846 2011-07-10 13:15:01,1.89823760173 2011-07-10 14:15:01,1.60666972834 2011-07-10 15:15:01,1.36903179016 2011-07-10 16:15:01,1.23539136879 2011-07-10 17:15:01,1.30004968561 2011-07-10 18:15:01,1.02969040624 2011-07-10 19:15:01,0.932536450273 2011-07-10 20:15:01,0.931886464036 2011-07-10 21:15:01,0.863524014067 2011-07-10 22:15:01,0.991745182096 2011-07-10 23:15:01,0.862854251012 2011-07-11 00:15:01,0.747998448544 2011-07-11 01:15:01,0.850183503168 2011-07-11 02:15:01,0.654526695899 2011-07-11 03:15:01,0.728679424723 2011-07-11 04:15:01,0.690021862785 2011-07-11 05:15:01,0.698213122487 2011-07-11 06:15:01,0.638280829834 2011-07-11 07:15:01,0.671747063098 2011-07-11 08:15:01,0.641360186156 2011-07-11 09:15:01,0.588559867574 2011-07-11 10:15:01,0.97926990996 2011-07-11 11:15:01,2.03972428805 2011-07-11 12:15:01,1.43419613562 2011-07-11 13:15:01,1.50993833205 2011-07-11 14:15:01,1.39176641082 2011-07-11 15:15:01,1.10735535393 2011-07-11 16:15:01,0.997729716812 2011-07-11 17:15:01,0.838516364175 2011-07-11 18:15:01,0.591521865594 2011-07-11 19:15:01,0.523210749244 2011-07-11 20:15:01,0.50741379187 2011-07-11 21:15:01,0.538820681939 2011-07-11 22:15:01,0.537126366514 2011-07-11 23:15:01,0.575014047574 2011-07-12 00:15:01,0.434892834119 2011-07-12 01:15:01,0.568473258729 2011-07-12 02:15:01,0.576361277601 2011-07-12 03:15:01,0.561665799733 2011-07-12 04:15:01,0.506676771373 2011-07-12 05:15:01,0.532992059663 2011-07-12 06:15:01,0.533646651609 2011-07-12 07:15:01,0.543344592151 2011-07-12 08:15:01,0.63393689344 2011-07-12 09:15:01,0.673402868318 2011-07-12 10:15:01,0.670085200379 2011-07-12 11:15:01,0.702719812998 2011-07-12 12:15:01,0.995558682556 2011-07-12 13:15:01,1.16926536732 2011-07-12 14:15:01,1.01409928115 2011-07-12 15:15:01,0.996637659048 2011-07-12 16:15:01,0.679225381434 2011-07-12 17:15:01,0.75814025419 2011-07-12 18:15:01,0.763981210671 2011-07-12 19:15:01,0.708667855921 2011-07-12 20:15:01,0.714510023353 2011-07-12 21:15:01,0.762345540039 2011-07-12 22:15:01,0.703105906489 2011-07-12 23:15:01,0.707826549505 2011-07-13 00:15:01,0.57670519965 2011-07-13 01:15:01,0.679474448094 2011-07-13 02:15:01,0.557389600963 2011-07-13 03:15:01,0.531382043611 2011-07-13 04:15:01,0.529654200621 2011-07-13 05:15:01,0.519767135236 2011-07-13 06:15:01,0.512662431177 2011-07-13 07:15:01,0.555591534137 2011-07-13 08:15:01,0.656115012713 2011-07-13 09:15:01,0.78798286152 2011-07-13 10:15:01,0.692587249625 2011-07-13 11:15:01,0.935283109196 2011-07-13 12:15:01,1.07905121568 2011-07-13 13:15:01,1.26547389169 2011-07-13 14:15:01,0.758122743682 2011-07-13 15:15:01,0.861263139606 2011-07-13 16:15:01,0.818969842122 2011-07-13 17:15:01,0.781863718801 2011-07-13 18:15:01,0.754097953198 2011-07-13 19:15:01,0.734934125478 2011-07-13 20:15:01,0.690540979909 2011-07-13 21:15:01,0.729830698994 2011-07-13 22:15:01,0.75001446262 2011-07-13 23:15:01,0.788613597882 2011-07-14 00:15:01,0.599371499577 2011-07-14 01:15:01,0.618132010667 2011-07-14 02:15:01,0.492632136346 2011-07-14 03:15:01,0.433984949291 2011-07-14 04:15:01,0.401924624437 2011-07-14 05:15:01,0.391060382405 2011-07-14 06:15:01,0.394108266834 2011-07-14 07:15:01,0.414870889838 2011-07-14 08:15:01,0.459231967846 2011-07-14 09:15:01,0.554594329429 2011-07-14 10:15:01,0.586447433981 2011-07-14 11:15:01,0.774360121165 2011-07-14 12:15:01,1.09174200349 2011-07-14 13:15:01,1.02217110037 2011-07-14 14:15:01,0.927402784199 2011-07-14 15:15:01,0.758385916177 2011-07-14 16:15:01,0.628370275811 2011-07-14 17:15:01,0.620875293673 2011-07-14 18:15:01,0.599521386669 2011-07-14 19:15:01,0.571684647103 2011-07-14 20:15:01,0.553937947494 2011-07-14 21:15:01,0.583300039952 2011-07-14 22:15:01,0.54794987059 2011-07-14 23:15:01,0.584078029022 2011-07-15 00:15:01,0.470730436595 2011-07-15 01:15:01,0.613684756703 2011-07-15 02:15:01,0.500075260381 2011-07-15 03:15:01,0.465845307932 2011-07-15 04:15:01,0.41024236317 2011-07-15 05:15:01,0.387587791441 2011-07-15 06:15:01,0.424290111819 2011-07-15 07:15:01,0.419710942605 2011-07-15 08:15:01,0.490660629494 2011-07-15 09:15:01,0.579498460973 2011-07-15 10:15:01,0.629326672567 2011-07-15 11:15:01,0.678068562505 2011-07-15 12:15:01,0.92753386871 2011-07-15 13:15:01,0.999694137996 2011-07-15 14:15:01,0.666268214936 2011-07-15 15:15:01,0.697556091181 2011-07-15 16:15:01,0.641203792909 2011-07-15 17:15:01,0.63342731861 2011-07-15 18:15:01,0.582036667388 2011-07-15 19:15:01,0.563113818597 2011-07-15 20:15:01,0.526980162514 2011-07-15 21:15:01,0.52827791804 2011-07-15 22:15:01,0.475220574063 2011-07-15 23:15:01,0.447709441696 2011-07-16 00:15:01,0.573151033543 2011-07-16 01:15:01,0.660520510001 2011-07-16 02:15:01,0.653658941313 2011-07-16 03:15:01,0.54005469609 2011-07-16 04:15:01,0.515772970517 2011-07-16 05:15:01,0.429273997931 2011-07-16 06:15:01,0.407590018152 2011-07-16 07:15:01,0.421466054048 2011-07-16 08:15:01,0.530038045387 2011-07-16 09:15:01,0.57930338213 2011-07-16 10:15:01,0.770295651048 2011-07-16 11:15:01,0.808551183638 2011-07-16 12:15:01,0.841766168283 2011-07-16 13:15:01,1.14397851684 2011-07-16 14:15:01,0.693110948221 2011-07-16 15:15:01,0.765183723366 2011-07-16 16:15:01,0.679417321464 2011-07-16 17:15:01,0.599942000367 2011-07-16 18:15:01,0.577088263652 2011-07-16 19:15:01,0.61229276245 2011-07-16 22:15:01,0.554915456933 2011-07-16 23:15:01,0.558064606445 2011-07-17 00:15:01,0.551861184907 2011-07-17 01:15:01,0.61407608019 2011-07-17 02:15:01,0.614105010588 2011-07-17 03:15:01,0.547997259079 2011-07-17 04:15:01,0.52247125088 2011-07-17 05:15:01,0.44803768545 2011-07-17 06:15:01,0.422634977534 2011-07-17 07:15:01,0.449383287256 2011-07-17 08:15:01,0.48685191239 2011-07-17 09:15:01,0.55355034739 2011-07-17 10:15:01,0.751857084264 2011-07-17 11:15:01,0.752667091441 2011-07-17 12:15:01,0.929141547083 2011-07-17 13:15:01,1.20847661477 2011-07-17 14:15:01,0.779651764165 2011-07-17 15:15:01,0.842350417376 2011-07-17 16:15:01,0.660812279132 2011-07-17 17:15:01,0.604369143437 2011-07-17 18:15:01,0.545339087944 2011-07-17 19:15:01,0.553533960498 2011-07-17 20:15:01,0.548774325402 2011-07-17 21:15:01,0.538358082874 2011-07-17 22:15:01,0.53644178623 2011-07-17 23:15:01,0.534592977484 2011-07-18 00:15:01,0.512258339014 2011-07-18 01:15:01,0.566221756929 2011-07-18 02:15:01,0.522523408729 2011-07-18 03:15:01,0.471140262255 2011-07-18 04:15:01,0.427749227361 2011-07-18 05:15:01,0.389042222628 2011-07-18 06:15:01,0.383151727687 2011-07-18 07:15:01,0.431656005927 2011-07-18 08:15:01,0.450789800048 2011-07-18 09:15:01,0.579229368551 2011-07-18 10:15:01,0.619556840077 2011-07-18 11:15:01,0.723378174503 2011-07-18 12:15:01,1.01502410409 2011-07-18 13:15:01,0.846268382728 2011-07-18 14:15:01,0.839328087923 2011-07-18 15:15:01,0.725356643836 2011-07-18 16:15:01,0.724121952079 2011-07-18 17:15:01,0.651006083675 2011-07-18 18:15:01,0.602683655851 2011-07-18 19:15:01,0.586257084968 2011-07-18 20:15:01,0.562953513723 2011-07-18 21:15:01,0.515027143549 2011-07-18 22:15:01,0.51568420058 2011-07-18 23:15:01,0.520976591741 2011-07-19 00:15:01,0.443980609863 2011-07-19 01:15:01,0.616688653055 2011-07-19 02:15:01,0.543115927044 2011-07-19 03:15:01,0.453472535098 2011-07-19 04:15:01,0.42156878009 2011-07-19 05:15:01,0.354035310108 2011-07-19 06:15:01,0.338454738679 2011-07-19 07:15:01,0.410903748263 2011-07-19 08:15:01,0.447593728971 2011-07-19 09:15:01,0.55913499836 2011-07-19 10:15:01,0.719621810927 2011-07-19 11:15:01,0.767196681645 2011-07-19 12:15:01,0.942294520548 2011-07-19 13:15:01,1.0032383212 2011-07-19 14:15:01,0.862942524284 2011-07-19 15:15:01,0.733837310024 2011-07-19 16:15:01,0.625142679429 2011-07-19 17:15:01,0.509370235269 2011-07-19 18:15:01,0.53930596467 2011-07-19 19:15:01,0.50644543215 2011-07-19 20:15:01,0.488141028621 2011-07-19 21:15:01,0.436814157173 2011-07-19 22:15:01,0.47635140278 2011-07-19 23:15:01,0.457919393325 2011-07-20 00:15:01,0.4295801077 2011-07-20 01:15:01,0.564498167608 2011-07-20 02:15:01,0.509544562716 2011-07-20 03:15:01,0.463203968782 2011-07-20 04:15:01,0.407072030767 2011-07-20 05:15:01,0.358862801122 2011-07-20 06:15:01,0.373697236561 2011-07-20 07:15:01,0.439205007516 2011-07-20 08:15:01,0.415318662475 2011-07-20 09:15:01,0.542676839911 2011-07-20 10:15:01,0.575836639641 2011-07-20 11:15:01,0.693750209668 2011-07-20 12:15:01,0.958649679038 2011-07-20 13:15:01,0.978838236235 2011-07-20 14:15:01,0.847355615316 2011-07-20 15:15:01,0.662280939932 2011-07-20 16:15:01,0.583318113117 2011-07-20 17:15:01,0.533766852362 2011-07-20 18:15:01,0.534896914979 2011-07-20 19:15:01,0.49444521527 2011-07-20 20:15:01,0.472729580661 2011-07-20 21:15:01,0.480673062305 2011-07-20 22:15:01,0.423097534834 2011-07-20 23:15:01,0.486307654948 2011-07-21 00:15:01,0.422066413938 2011-07-21 01:15:01,0.519997336916 2011-07-21 02:15:01,0.503462395529 2011-07-21 03:15:01,0.443251378533 2011-07-21 04:15:01,0.384122851996 2011-07-21 05:15:01,0.362461723631 2011-07-21 06:15:01,0.362696176533 2011-07-21 07:15:01,0.382357225458 2011-07-21 08:15:01,0.409054677065 2011-07-21 09:15:01,0.529625586473 2011-07-21 10:15:01,0.575244382969 2011-07-21 11:15:01,0.5888 2011-07-21 12:15:01,0.847774407738 2011-07-21 13:15:01,0.791340636411 2011-07-21 14:15:01,0.896465706439 2011-07-21 15:15:01,0.665230969614 2011-07-21 16:15:01,0.593758564712 2011-07-21 17:15:01,0.569387656299 2011-07-21 18:15:01,0.634304010683 2011-07-21 22:15:01,0.486431017698 2011-07-22 00:15:01,0.422591891003 2011-07-22 01:15:01,0.486913311221 2011-07-22 02:15:01,0.46735676419 2011-07-22 03:15:01,0.434363028666 2011-07-22 04:15:01,0.386714049044 2011-07-22 05:15:01,0.369504587288 2011-07-22 06:15:01,0.397595454874 2011-07-22 07:15:01,0.410352632737 2011-07-22 08:15:01,0.423393177227 2011-07-22 09:15:01,0.491140774627 2011-07-22 10:15:01,0.468621217473 2011-07-22 11:15:01,0.580554113678 2011-07-22 12:15:01,0.833853226071 2011-07-22 13:15:01,0.896172284725 2011-07-22 14:15:01,0.767720788852 2011-07-22 15:15:01,0.56208989333 2011-07-22 16:15:01,0.605598263972 2011-07-22 17:15:01,0.474154728687 2011-07-22 18:15:01,0.527754990429 2011-07-22 19:15:01,0.570643559125 2011-07-22 20:15:01,0.487113274889 2011-07-22 21:15:01,0.446442694765 2011-07-22 22:15:01,0.493629595145 2011-07-22 23:15:01,0.416509432515 2011-07-23 03:15:01,0.471425611142 2011-07-23 05:15:01,0.429440714477 2011-07-23 06:15:01,0.432265331459 2011-07-23 07:15:01,0.454228292268 2011-07-23 08:15:01,0.394017939728 2011-07-23 11:15:01,0.524489350397 2011-07-23 12:15:01,0.634432981899 2011-07-23 13:15:01,1.04193118459 2011-07-23 14:15:01,0.90026207413 2011-07-23 15:15:01,0.801925327328 2011-07-23 16:15:01,0.664488563101 2011-07-23 17:15:01,0.746938916439 2011-07-23 18:15:01,0.58430610608 2011-07-23 19:15:01,0.551052096356 2011-07-23 20:15:01,0.539589028335 2011-07-23 21:15:01,0.458878228066 2011-07-23 22:15:01,0.508391976452 2011-07-23 23:15:01,0.455166495807 2011-07-24 00:15:01,0.354592054203 2011-07-24 01:15:01,0.847647604173 2011-07-24 02:15:01,0.623232870952 2011-07-24 03:15:01,0.454925500145 2011-07-24 04:15:01,0.388240283175 2011-07-24 05:15:01,0.362204837798 2011-07-24 06:15:01,0.38663181282 2011-07-24 07:15:01,0.432720462465 2011-07-24 08:15:01,0.463825888665 2011-07-24 09:15:01,0.5587072312 2011-07-24 10:15:01,0.537009158919 2011-07-24 11:15:01,0.668545698278 2011-07-24 12:15:01,1.00081699346 2011-07-24 13:15:01,0.875236467932 2011-07-24 14:15:01,0.940858277968 2011-07-24 15:15:01,0.528411701639 2011-07-24 16:15:01,0.65468678144 2011-07-24 17:15:01,0.581666157293 2011-07-24 18:15:01,0.514303731701 2011-07-24 19:15:01,0.461928980193 2011-07-24 20:15:01,0.422771996885 2011-07-24 21:15:01,0.411778295097 2011-07-24 22:15:01,0.422908418695 2011-07-24 23:15:01,0.373979374279 2011-07-25 00:15:01,0.392288088245 2011-07-25 01:15:01,0.624979173708 2011-07-25 02:15:01,0.467264498355 2011-07-25 03:15:01,0.491341991342 2011-07-25 04:15:01,0.380918382013 2011-07-25 05:15:01,0.335816771323 2011-07-25 06:15:01,0.39575696898 2011-07-25 07:15:01,0.389068499632 2011-07-25 08:15:01,0.401918936275 2011-07-25 09:15:01,0.560098031871 2011-07-25 10:15:01,0.632278380734 2011-07-25 11:15:01,0.754956701996 2011-07-25 12:15:01,0.956091142046 2011-07-25 13:15:01,0.993110160026 2011-07-25 14:15:01,0.89732544683 2011-07-25 15:15:01,0.677849823197 2011-07-25 16:15:01,0.61280505222 2011-07-25 17:15:01,0.554349758464 2011-07-25 18:15:01,0.455914446791 2011-07-25 19:15:01,0.464386331397 2011-07-25 20:15:01,0.401464711746 2011-07-25 21:15:01,0.359988588258 2011-07-25 22:15:01,0.403315849798 2011-07-25 23:15:01,0.396394253289 2011-07-26 00:15:01,0.345829294262 2011-07-26 01:15:01,0.458796101136 2011-07-26 02:15:01,0.478773805802 2011-07-26 03:15:01,0.398860697414 2011-07-26 04:15:01,0.44840088318 2011-07-26 05:15:01,0.323450423714 2011-07-26 06:15:01,0.365505482974 2011-07-26 07:15:01,0.394108235626 2011-07-26 08:15:01,0.441997940672 2011-07-26 09:15:01,0.524900355719 2011-07-26 10:15:01,0.691827625706 2011-07-26 11:15:01,0.796475686699 2011-07-26 12:15:01,0.843537414966 2011-07-26 13:15:01,0.861174539371 2011-07-26 14:15:01,0.86726415966 2011-07-26 15:15:01,0.541147669817 2011-07-26 16:15:01,0.620446859419 2011-07-26 17:15:01,0.525748138561 2011-07-26 19:15:01,0.484852616211 2011-07-26 20:15:01,0.484225645719 2011-07-26 21:15:01,0.396638624414 2011-07-26 22:15:01,0.422340743999 2011-07-26 23:15:01,0.347862423243 2011-07-27 00:15:01,0.355651253272 2011-07-27 01:15:01,0.472819637318 2011-07-27 02:15:01,0.42465090411 2011-07-27 05:15:01,0.369590666017 2011-07-27 06:15:01,0.341975423207 2011-07-27 07:15:01,0.385071903859 2011-07-27 08:15:01,0.449638417028 2011-07-27 09:15:01,0.485024107731 2011-07-27 10:15:01,0.503880485702 2011-07-27 11:15:01,0.649875468026 2011-07-27 12:15:01,0.900444803882 2011-07-27 13:15:01,0.921812066603 2011-07-27 14:15:01,0.799267434936 2011-07-27 15:15:01,0.5669058795 2011-07-27 16:15:01,0.592411494104 2011-07-27 17:15:01,0.476107270232 2011-07-27 18:15:01,0.491887576287 2011-07-27 19:15:01,0.475071540278 2011-07-27 20:15:01,0.447284149613 2011-07-27 21:15:01,0.478995312103 2011-07-27 22:15:01,0.44316906746 2011-07-27 23:15:01,0.362373551562 2011-07-28 00:15:01,0.353371351895 2011-07-28 01:15:01,0.500298235797 2011-07-28 02:15:01,0.453735304062 2011-07-28 03:15:01,0.444910788743 2011-07-28 04:15:01,0.388427934987 2011-07-28 05:15:01,0.336372101252 2011-07-28 06:15:01,0.356857600543 2011-07-28 07:15:01,0.50117066916 2011-07-28 08:15:01,0.419210640281 2011-07-28 09:15:01,0.606202190542 2011-07-28 10:15:01,0.612685287889 2011-07-28 11:15:01,0.849234393404 2011-07-28 12:15:01,1.19378143801 2011-07-28 13:15:01,0.693728857663 2011-07-28 14:15:01,0.830594474462 2011-07-28 15:15:01,0.642496762959 2011-07-28 16:15:01,0.549461019164 2011-07-28 17:15:01,0.471706205502 2011-07-28 18:15:01,0.523558103174 2011-07-28 19:15:01,0.460153344327 2011-07-28 20:15:01,0.484955907773 2011-07-28 21:15:01,0.515769796423 2011-07-28 22:15:01,0.448284108066 2011-07-28 23:15:01,0.430648577052 2011-07-29 00:15:01,0.428464730929 2011-07-29 01:15:01,0.50383463487 2011-07-29 02:15:01,0.48908390281 2011-07-29 03:15:01,0.430424920234 2011-07-29 04:15:01,0.421459720562 2011-07-29 05:15:01,0.38182361723 2011-07-29 06:15:01,0.414216287201 2011-07-29 07:15:01,0.429408844655 2011-07-29 08:15:01,0.536157500477 2011-07-29 09:15:01,0.72305326685 2011-07-29 10:15:01,0.796266588887 2011-07-29 11:15:01,1.03498390948 2011-07-29 12:15:01,1.10071677602 2011-07-29 13:15:01,0.980824921978 2011-07-29 14:15:01,1.00210466131 2011-07-29 15:15:01,0.734911682259 2011-07-29 16:15:01,0.756412897909 2011-07-29 17:15:01,0.59817101608 2011-07-29 18:15:01,0.673976028606 2011-07-29 19:15:01,0.649754020916 2011-07-29 20:15:01,0.592631426905 2011-07-29 21:15:01,0.65991491423 2011-07-29 22:15:01,0.626581379568 2011-07-29 23:15:01,0.578915126635 2011-07-30 00:15:01,0.608687044547 2011-07-30 01:15:01,0.670799943403 2011-07-30 02:15:01,0.640060585538 2011-07-30 03:15:01,0.659653508315 2011-07-30 04:15:01,0.475267844485 2011-07-30 05:15:01,0.512949516523 2011-07-30 06:15:01,0.524415858356 2011-07-30 07:15:01,0.574065799941 2011-07-30 08:15:01,0.568731977426 2011-07-30 09:15:01,0.644472679623 2011-07-30 10:15:01,0.559871884315 2011-07-30 11:15:01,0.969953850686 2011-07-30 12:15:01,1.07140826653 2011-07-30 13:15:01,1.03096993273 2011-07-30 14:15:01,0.937015144758 2011-07-30 15:15:01,0.819120085845 2011-07-30 16:15:01,0.683689190651 2011-07-30 17:15:01,0.535112398674 2011-07-30 20:15:01,0.576377992756 2011-07-30 21:15:01,0.553529713893 2011-07-30 22:15:01,0.523731134272 2011-07-30 23:15:01,0.51688836525 2011-07-31 00:15:01,0.439294307061 2011-07-31 01:15:01,0.648390249655 2011-07-31 02:15:01,0.581880306629 2011-07-31 04:15:01,0.529118257924 2011-07-31 05:15:01,0.485536149182 2011-07-31 06:15:01,0.500015487422 2011-07-31 07:15:01,0.51460008046 2011-07-31 08:15:01,0.533621281078 2011-07-31 09:15:01,0.682004403246 2011-07-31 10:15:01,0.630815315617 2011-07-31 11:15:01,0.851473399697 2011-07-31 12:15:01,1.02661392802 2011-07-31 13:15:01,1.29937784256 2011-07-31 14:15:01,0.901679325483 2011-07-31 15:15:01,0.832724097616 2011-07-31 16:15:01,0.677929487521 2011-07-31 17:15:01,0.635344512686 2011-07-31 18:15:01,0.541728069495 2011-07-31 19:15:01,0.557364618123 2011-07-31 20:15:01,0.611843812083 2011-07-31 21:15:01,0.523288282779 2011-07-31 23:15:01,0.518364312775 2011-08-01 00:15:01,0.498728225752 2011-08-01 03:15:01,0.576555937381 2011-08-01 05:15:01,0.554290565277 2011-08-01 06:15:01,0.476010861023 2011-08-01 07:15:01,0.449696671034 2011-08-01 08:15:01,0.551743210305 2011-08-01 09:15:01,0.756095103768 2011-08-01 10:15:01,0.734396138798 2011-08-01 11:15:01,0.846458555842 2011-08-01 12:15:01,1.1775573547 2011-08-01 13:15:01,0.780463324214 2011-08-01 14:15:01,1.00941909107 2011-08-01 15:15:01,0.819694770134 2011-08-01 16:15:01,0.764223282266 2011-08-01 17:15:01,0.663092200538 2011-08-01 18:15:01,0.653564393467 2011-08-01 20:15:01,0.577674184768 2011-08-01 21:15:01,0.54488363266 2011-08-01 23:15:01,0.531751330342 2011-08-02 00:15:01,0.574685145904 2011-08-02 01:15:01,0.635687697157 2011-08-02 02:15:01,0.58853026189 2011-08-02 03:15:01,0.466300750966 2011-08-02 05:15:01,0.426776142971 2011-08-02 06:15:01,0.431905267695 2011-08-02 07:15:01,0.486788508189 2011-08-02 08:15:01,0.520916021747 2011-08-02 09:15:01,0.631112923168 2011-08-02 10:15:01,0.787905664181 2011-08-02 11:15:01,1.15101155113 2011-08-02 12:15:01,1.40471250275 2011-08-02 13:15:01,0.919172005914 2011-08-02 14:15:01,0.930289680113 2011-08-02 15:15:01,0.911233169005 2011-08-02 16:15:01,0.562151951525 2011-08-02 18:15:01,0.645033038997 2011-08-02 19:15:01,0.648685752389 2011-08-02 20:15:01,0.541655156634 2011-08-02 21:15:01,0.629047798928 2011-08-02 22:15:01,0.70048738269 2011-08-02 23:15:01,0.53379122543 2011-08-03 00:15:01,0.440444722304 2011-08-03 01:15:01,0.719683930527 2011-08-03 02:15:01,0.710997940534 2011-08-03 03:15:01,0.594979361314 2011-08-03 04:15:01,0.449055478674 2011-08-03 05:15:01,0.477755007181 2011-08-03 06:15:01,0.503697983752 2011-08-03 07:15:01,0.600102091293 2011-08-03 08:15:01,0.561552932585 2011-08-03 09:15:01,0.79419877957 2011-08-03 10:15:01,0.785667933624 2011-08-03 11:15:01,1.13982041415 2011-08-03 12:15:01,1.19103416667 2011-08-03 13:15:01,1.17852075751 2011-08-03 14:15:01,0.75004468933 2011-08-03 15:15:01,0.817874388891 2011-08-03 17:15:01,0.722743200455 2011-08-03 18:15:01,0.584243911365 2011-08-03 19:15:01,0.62690718902 2011-08-03 20:15:01,0.583636953993 2011-08-03 21:15:01,0.638105501939 2011-08-03 22:15:01,0.553943354236 2011-08-03 23:15:01,0.698302566298 2011-08-04 00:15:01,0.585952461824 2011-08-04 01:15:01,0.680807542384 2011-08-04 02:15:01,0.633855601382 2011-08-04 03:15:01,0.820624317284 2011-08-04 04:15:01,0.557292109026 2011-08-04 05:15:01,0.41470422161 2011-08-04 06:15:01,0.525180710389 2011-08-04 07:15:01,0.548682741313 2011-08-04 08:15:01,0.556389097274 2011-08-04 09:15:01,0.671852412749 2011-08-04 10:15:01,0.815993714002 2011-08-04 11:15:01,0.893970122675 2011-08-04 12:15:01,1.08664281817 2011-08-04 13:15:01,1.12298696319 2011-08-04 14:15:01,0.95005399809 2011-08-04 16:15:01,0.715950660979 2011-08-04 17:15:01,0.795825740766 2011-08-04 18:15:01,0.647634508959 2011-08-04 19:15:01,0.555697769319 2011-08-04 20:15:01,1.42072295982 2011-08-04 21:15:01,0.592265160479 2011-08-04 22:15:01,0.568243786567 2011-08-04 23:15:01,0.604767739087 2011-08-05 00:15:01,0.555048814747 2011-08-05 01:15:01,0.686409550046 2011-08-05 02:15:01,0.664502043993 2011-08-05 03:15:01,0.751783059049 2011-08-05 04:15:01,0.536707916534 2011-08-05 05:15:01,0.584625706011 2011-08-05 06:15:01,0.543533656374 2011-08-05 07:15:01,0.541778547457 2011-08-05 08:15:01,0.611421644746 2011-08-05 09:15:01,0.726964468474 2011-08-05 10:15:01,0.802952723852 2011-08-05 11:15:01,1.0420973625 2011-08-05 12:15:01,1.05794478293 2011-08-05 13:15:01,1.14759081927 2011-08-05 14:15:01,0.995947810883 2011-08-05 15:15:01,0.837924146178 2011-08-05 17:15:01,0.639849442198 2011-08-05 19:15:01,0.676064732772 2011-08-05 20:15:01,0.543911542172 2011-08-05 21:15:01,0.577292345427 2011-08-05 22:15:01,0.543720793978 2011-08-05 23:15:01,0.574428235604 2011-08-06 00:15:01,0.536694938229 2011-08-06 01:15:01,0.721242372337 2011-08-06 02:15:01,0.719180486143 2011-08-06 03:15:01,0.664986357941 2011-08-06 04:15:01,0.675107829796 2011-08-06 05:15:01,0.568417908432 2011-08-06 06:15:01,0.560745261334 2011-08-06 07:15:01,0.589784142503 2011-08-06 08:15:01,0.675166106392 2011-08-06 09:15:01,0.713929339861 2011-08-06 10:15:01,0.720525247971 2011-08-06 11:15:01,0.973101693998 2011-08-06 12:15:01,1.04109900091 2011-08-06 13:15:01,1.10076528064 2011-08-06 15:15:01,0.858281143262 2011-08-06 16:15:01,0.718258734174 2011-08-06 17:15:01,0.652482726953 2011-08-06 18:15:01,0.603126873225 2011-08-06 19:15:01,0.615980506115 2011-08-06 20:15:01,0.518617271676 2011-08-06 21:15:01,0.612084186098 2011-08-06 22:15:01,0.6041011793 2011-08-06 23:15:01,0.519409820872 2011-08-07 00:15:01,0.635188073777 2011-08-07 01:15:01,0.68608152933 2011-08-07 02:15:01,0.609118718996 2011-08-07 03:15:01,0.582622271093 2011-08-07 04:15:01,0.598422475252 2011-08-07 05:15:01,0.561157963103 2011-08-07 06:15:01,0.593355289604 2011-08-07 07:15:01,0.623050235785 2011-08-07 08:15:01,0.687373850639 2011-08-07 09:15:01,0.665167658556 2011-08-07 10:15:01,0.849833024706 2011-08-07 11:15:01,0.946772757303 2011-08-07 12:15:01,1.05214350573 2011-08-07 13:15:01,1.49678514312 2011-08-07 14:15:01,0.867744078979 2011-08-07 15:15:01,0.819632696943 2011-08-07 16:15:01,0.74004421129 2011-08-07 17:15:01,0.705276178788 2011-08-07 18:15:01,0.648443555101 2011-08-07 19:15:01,0.55609604234 2011-08-07 20:15:01,0.624781661692 2011-08-07 21:15:01,0.605392560095 2011-08-07 22:15:01,0.568348885355 2011-08-07 23:15:01,0.548749163255 2011-08-08 00:15:01,0.606434621799 2011-08-08 01:15:01,0.646378233592 2011-08-08 02:15:01,0.580301698869 2011-08-08 03:15:01,0.565836250493 2011-08-08 04:15:01,0.569189356342 2011-08-08 05:15:01,0.538710969129 2011-08-08 06:15:01,0.513768455929 2011-08-08 07:15:01,0.559171613811 2011-08-08 08:15:01,0.575195729644 2011-08-08 09:15:01,0.652947245764 2011-08-08 10:15:01,0.74503888758 2011-08-08 11:15:01,0.857579554687 2011-08-08 12:15:01,0.875553118504 2011-08-08 13:15:01,0.854941413658 2011-08-08 14:15:01,0.790767678673 2011-08-08 16:15:01,0.712741698358 2011-08-08 17:15:01,0.615699781863 2011-08-08 18:15:01,0.595200849764 2011-08-08 19:15:01,0.634719459996 2011-08-08 20:15:01,0.547550792253 2011-08-08 21:15:01,0.590809094235 2011-08-08 22:15:01,0.570679942692 2011-08-08 23:15:01,0.54153421526 2011-08-09 00:15:01,0.536134186043 2011-08-09 01:15:01,0.58694728119 2011-08-09 02:15:01,0.599060021738 2011-08-09 03:15:01,0.578157413533 2011-08-09 04:15:01,0.50181775834 2011-08-09 05:15:01,0.518201067593 2011-08-09 06:15:01,0.511505673511 2011-08-09 07:15:01,0.597075586726 2011-08-09 08:15:01,0.598728666922 2011-08-09 09:15:01,0.783646778861 2011-08-09 10:15:01,0.788622722111 2011-08-09 11:15:01,0.86311824481 2011-08-09 12:15:01,1.27301519137 2011-08-09 14:15:01,0.88404025791 2011-08-09 15:15:01,0.802570074162 2011-08-09 16:15:01,0.723815454876 2011-08-09 17:15:01,0.661586612293 2011-08-09 18:15:01,0.617642290617 2011-08-09 19:15:01,0.629898957434 2011-08-09 20:15:01,0.601685026205 2011-08-09 21:15:01,0.645256582208 2011-08-09 22:15:01,0.590185964475 2011-08-09 23:15:01,0.620264322455 2011-08-10 00:15:01,0.559184359065 2011-08-10 01:15:01,0.590161480456 2011-08-10 02:15:01,0.591462623116 2011-08-10 03:15:01,0.642369010583 2011-08-10 04:15:01,0.520049263822 2011-08-10 05:15:01,0.502427012098 2011-08-10 06:15:01,0.504466919255 2011-08-10 07:15:01,0.50623672691 2011-08-10 08:15:01,0.547044702758 2011-08-10 09:15:01,0.624164877273 2011-08-10 10:15:01,0.821473591903 2011-08-10 11:15:01,0.962219823481 2011-08-10 12:15:01,1.13254543144 2011-08-10 13:15:01,0.946045959158 2011-08-10 15:15:01,0.983489745003 2011-08-10 17:15:01,0.82094562393 2011-08-10 18:15:01,0.730903856743 2011-08-10 19:15:01,0.625206071634 2011-08-10 20:15:01,0.731170579564 2011-08-10 21:15:01,0.676400974391 2011-08-10 23:15:01,0.660492954703 2011-08-11 00:15:01,0.554590237895 2011-08-11 01:15:01,0.715748968801 2011-08-11 02:15:01,0.552449342809 2011-08-11 03:15:01,0.608818563823 2011-08-11 04:15:01,0.56535245238 2011-08-11 05:15:01,0.545612490685 2011-08-11 06:15:01,0.521651179882 2011-08-11 07:15:01,0.577066436906 2011-08-11 08:15:01,0.649319201432 2011-08-11 09:15:01,0.761580436424 2011-08-11 10:15:01,0.958909403592 2011-08-11 11:15:01,0.879025593085 2011-08-11 12:15:01,1.02881514616 2011-08-11 14:15:01,1.12794638303 2011-08-11 15:15:01,0.806395267298 2011-08-11 16:15:01,0.998546127412 2011-08-11 17:15:01,0.797586425481 2011-08-11 18:15:01,0.653892646469 2011-08-11 19:15:01,0.668489407469 2011-08-11 20:15:01,0.704774059598 2011-08-11 21:15:01,0.618160741346 2011-08-11 22:15:01,0.703522679277 2011-08-11 23:15:01,0.645565581113 2011-08-12 00:15:01,0.641368766824 2011-08-12 01:15:01,0.705282913257 2011-08-12 02:15:01,0.612891663325 2011-08-12 03:15:01,0.59561723886 2011-08-12 04:15:01,0.397505242902 2011-08-12 05:15:01,0.4334602526 2011-08-12 06:15:01,0.452638011815 2011-08-12 07:15:01,0.554466657955 2011-08-12 08:15:01,0.762423745569 2011-08-12 09:15:01,0.743389683572 2011-08-12 10:15:01,1.2398054085 2011-08-12 11:15:01,1.24785288471 2011-08-12 13:15:01,1.56976504958 2011-08-12 14:15:01,1.30445869153 2011-08-12 15:15:01,0.913389056971 2011-08-12 16:15:01,0.797229088648 2011-08-12 17:15:01,0.588670630441 2011-08-12 18:15:01,0.621693121693 2011-08-12 19:15:01,0.561822051743 2011-08-12 21:15:01,0.586936754634 2011-08-12 22:15:01,0.510457600443 2011-08-12 23:15:01,0.411906443438 2011-08-13 00:15:01,0.481140662888 2011-08-13 01:15:01,0.727249846188 2011-08-13 02:15:01,0.692740174194 2011-08-13 03:15:01,0.606669069316 2011-08-13 04:15:01,0.481597592012 2011-08-13 05:15:01,0.452214871573 2011-08-13 06:15:01,0.503423930085 2011-08-13 07:15:01,0.592080023871 2011-08-13 08:15:01,0.670440067671 2011-08-13 09:15:01,0.781322734271 2011-08-13 10:15:01,1.12155162029 2011-08-13 11:15:01,1.14461358314 2011-08-13 12:15:01,2.3458511804 2011-08-13 13:15:01,1.78017877028 2011-08-13 15:15:01,1.16344626108 2011-08-13 17:15:01,0.80366590851 2011-08-13 18:15:01,0.835319293809 2011-08-13 19:15:01,0.61608130586 2011-08-13 20:15:01,0.551187458629 2011-08-13 21:15:01,0.496627535469 2011-08-13 22:15:01,0.471666183154 2011-08-13 23:15:01,0.646252600178 2011-08-14 00:15:01,0.610524145889 2011-08-14 01:15:01,0.740457772665 2011-08-14 02:15:01,0.67648312914 2011-08-14 03:15:01,0.6999543225 2011-08-14 04:15:01,0.581878572182 2011-08-14 05:15:01,0.574517129817 2011-08-14 06:15:01,0.588103546132 2011-08-14 07:15:01,0.682825589466 2011-08-14 08:15:01,0.702503350973 2011-08-14 09:15:01,0.811665071193 2011-08-14 10:15:01,0.959159638626 2011-08-14 11:15:01,1.13891248326 2011-08-14 12:15:01,1.31995254103 2011-08-14 13:15:01,1.14913574749 2011-08-14 14:15:01,1.17398097723 2011-08-14 15:15:01,0.910558605102 2011-08-14 16:15:01,0.786068674769 2011-08-14 17:15:01,0.809601949747 2011-08-14 18:15:01,0.755417840119 2011-08-14 19:15:01,0.749192553692 2011-08-14 20:15:01,0.665563624108 2011-08-14 21:15:01,0.721558658688 2011-08-14 22:15:01,0.685192621577 2011-08-14 23:15:01,0.557077450057 2011-08-15 01:15:01,0.636081308305 2011-08-15 02:15:01,0.667131109384 2011-08-15 03:15:01,0.735076057078 2011-08-15 04:15:01,0.580668384959 2011-08-15 05:15:01,0.579281629473 2011-08-15 06:15:01,0.602451454238 2011-08-15 07:15:01,0.644382914486 2011-08-15 08:15:01,0.714276606054 2011-08-15 09:15:01,0.848933518167 2011-08-15 10:15:01,0.966559247715 2011-08-15 11:15:01,1.05050887436 2011-08-15 12:15:01,1.04251488078 2011-08-15 14:15:01,0.932878270762 2011-08-15 15:15:01,0.826720919972 2011-08-15 16:15:01,0.776904573404 2011-08-15 17:15:01,0.716201992703 2011-08-15 18:15:01,0.711605913562 2011-08-15 19:15:01,0.708530490055 2011-08-15 20:15:01,0.663736975075 2011-08-15 21:15:01,0.622400018566 2011-08-15 22:15:01,0.607611681058 2011-08-15 23:15:01,0.611072281173 2011-08-16 00:15:01,0.563604798437 2011-08-16 01:15:01,0.686922142397 2011-08-16 02:15:01,0.675897036319 2011-08-16 03:15:01,0.667313844917 2011-08-16 04:15:01,0.628226199954 2011-08-16 05:15:01,0.595912441675 2011-08-16 06:15:01,0.634416844861 2011-08-16 07:15:01,0.685898336104 2011-08-16 08:15:01,0.826101318279 2011-08-16 09:15:01,0.892529350396 2011-08-16 10:15:01,1.12081818742 2011-08-16 11:15:01,1.12547861639 2011-08-16 12:15:01,1.12175474239 2011-08-16 13:15:01,1.05128934078 2011-08-16 14:15:01,0.966681309319 2011-08-16 15:15:01,0.990511125266 2011-08-16 16:15:01,0.879749252927 2011-08-16 17:15:01,0.714478939876 2011-08-16 18:15:01,0.877238546553 2011-08-16 19:15:01,0.725744019401 2011-08-16 20:15:01,0.761700055415 2011-08-16 21:15:01,0.714732926186 2011-08-16 22:15:01,0.676804863428 2011-08-16 23:15:01,0.711416021227 2011-08-17 00:15:01,0.607743520633 2011-08-17 01:15:01,0.736028088655 2011-08-17 02:15:01,0.66488033209 2011-08-17 03:15:01,0.619237027662 2011-08-17 04:15:01,0.550742015432 2011-08-17 05:15:01,0.555550082264 2011-08-17 06:15:01,0.616679440644 2011-08-17 07:15:01,0.693236714976 2011-08-17 08:15:01,0.810488810541 2011-08-17 09:15:01,0.932629669333 2011-08-17 10:15:01,1.10551712253 2011-08-17 11:15:01,1.24432225675 2011-08-17 12:15:01,1.07751682008 2011-08-17 13:15:01,0.993365801281 2011-08-17 14:15:01,1.03636422863 2011-08-17 15:15:01,0.927039239851 2011-08-17 16:15:01,0.821436448207 2011-08-17 18:15:01,0.762617399275 2011-08-17 19:15:01,0.714061062878 2011-08-17 20:15:01,0.735661201354 2011-08-17 21:15:01,0.666658952973 2011-08-17 22:15:01,0.621769977351 2011-08-17 23:15:01,0.548446739751 2011-08-18 00:15:01,0.544978141492 2011-08-18 01:15:01,0.758639317537 2011-08-18 02:15:01,0.732381898533 2011-08-18 03:15:01,0.570647047727 2011-08-18 04:15:01,0.534028307408 2011-08-18 05:15:01,0.542765533075 2011-08-18 06:15:01,0.567515064457 2011-08-18 07:15:01,0.683516370065 2011-08-18 08:15:01,0.718008272579 2011-08-18 09:15:01,0.936216066342 2011-08-18 10:15:01,0.977670956737 2011-08-18 11:15:01,0.953869233654 2011-08-18 12:15:01,0.958412841486 2011-08-18 13:15:01,0.982262310647 2011-08-18 14:15:01,0.944170398835 2011-08-18 15:15:01,0.712214878216 2011-08-18 16:15:01,0.779245317679 2011-08-18 18:15:01,0.770476887313 2011-08-18 20:15:01,0.772785581145 2011-08-18 21:15:01,0.792569185776 2011-08-18 22:15:01,0.892232194744 2011-08-18 23:15:01,0.928590112477 2011-08-19 00:15:01,0.809001110711 2011-08-19 01:15:01,0.773142351037 2011-08-19 02:15:01,0.68364500895 2011-08-19 03:15:01,0.666356498685 2011-08-19 04:15:01,0.602663491936 2011-08-19 05:15:01,0.615586216743 2011-08-19 06:15:01,0.680106983428 2011-08-19 07:15:01,0.715438473764 2011-08-19 08:15:01,0.778365849468 2011-08-19 09:15:01,0.940738025415 2011-08-19 10:15:01,1.06431149513 2011-08-19 11:15:01,1.03322345475 2011-08-19 12:15:01,1.06920531499 2011-08-19 13:15:01,0.90248188841 2011-08-19 14:15:01,0.948048756512 2011-08-19 15:15:01,0.940754216038 2011-08-19 16:15:01,0.934222809879 2011-08-19 18:15:01,5.49754000266 2011-08-19 19:15:01,0.863326087315 2011-08-19 20:15:01,0.703298738091 2011-08-19 21:15:01,0.713623326394 2011-08-19 22:15:01,0.654695043258 2011-08-19 23:15:01,0.674132038136 2011-08-20 00:15:01,0.662703093534 2011-08-20 01:15:01,0.794094232044 2011-08-20 02:15:01,0.682984438197 2011-08-20 03:15:01,0.668096114705 2011-08-20 04:15:01,0.644444815845 2011-08-20 05:15:01,0.631821336803 2011-08-20 06:15:01,0.664079704752 2011-08-20 07:15:01,0.691809112522 2011-08-20 08:15:01,0.731047520971 2011-08-20 09:15:01,0.916183652659 2011-08-20 10:15:01,1.12615701063 2011-08-20 11:15:01,1.37892666256 2011-08-20 12:15:01,1.48058619127 2011-08-20 13:15:01,1.11576620573 2011-08-20 14:15:01,1.10130283386 2011-08-20 15:15:01,0.917978202373 2011-08-20 16:15:01,0.868671626148 2011-08-20 17:15:01,0.804527172255 2011-08-20 18:15:01,0.745593099694 2011-08-20 19:15:01,0.693628880174 2011-08-20 20:15:01,0.713280266363 2011-08-20 21:15:01,0.69452314481 2011-08-20 22:15:01,0.676418731136 2011-08-20 23:15:01,0.705210678675 2011-08-21 00:15:01,0.693664559433 2011-08-21 01:15:01,0.741737529738 2011-08-21 02:15:01,0.740867235598 2011-08-21 03:15:01,0.755155629406 2011-08-21 04:15:01,0.663611083149 2011-08-21 05:15:01,0.645370135798 2011-08-21 06:15:01,0.649619761544 2011-08-21 07:15:01,0.70872257412 2011-08-21 08:15:01,0.692568813021 2011-08-21 09:15:01,0.739975603038 2011-08-21 10:15:01,1.07428499644 2011-08-21 11:15:01,1.29783044803 2011-08-21 12:15:01,1.18176109093 2011-08-21 13:15:01,1.29187384737 2011-08-21 15:15:01,0.937208385358 2011-08-21 16:15:01,0.91911195455 2011-08-21 17:15:01,0.755583102096 2011-08-21 18:15:01,0.745270462145 2011-08-21 19:15:01,0.710554099813 2011-08-21 20:15:01,0.658328261736 2011-08-21 21:15:01,0.724803116745 2011-08-21 22:15:01,0.705354280218 2011-08-21 23:15:01,0.689806462107 2011-08-22 00:15:01,0.60689583826 2011-08-22 01:15:01,0.651337689557 2011-08-22 02:15:01,0.62934487776 2011-08-22 03:15:01,0.62372916466 2011-08-22 04:15:01,0.577398944823 2011-08-22 05:15:01,0.572886854195 2011-08-22 06:15:01,0.594058752156 2011-08-22 07:15:01,0.582907570831 2011-08-22 08:15:01,0.734216695443 2011-08-22 09:15:01,0.806454982244 2011-08-22 10:15:01,0.969068717606 2011-08-22 11:15:01,0.849613756806 2011-08-22 12:15:01,0.890577507599 2011-08-22 13:15:01,0.972369871643 2011-08-22 15:15:01,0.830408286317 2011-08-22 16:15:01,0.790874543276 2011-08-22 17:15:01,0.868033239748 2011-08-22 18:15:01,0.753268013611 2011-08-22 19:15:01,0.75341096872 2011-08-22 20:15:01,0.723666685969 2011-08-22 21:15:01,0.641627543036 2011-08-22 22:15:01,0.793713273077 2011-08-22 23:15:01,0.778934874729 2011-08-23 00:15:01,0.710999652634 2011-08-23 01:15:01,0.703201657157 2011-08-23 02:15:01,0.669306023229 2011-08-23 03:15:01,0.623246944026 2011-08-23 04:15:01,0.59842770237 2011-08-23 05:15:01,0.618625761565 2011-08-23 06:15:01,0.673907341691 2011-08-23 07:15:01,0.776481358143 2011-08-23 08:15:01,0.904231856983 2011-08-23 09:15:01,1.29383792352 2011-08-23 10:15:01,1.13551430877 2011-08-23 11:15:01,1.0251356609 2011-08-23 12:15:01,1.18905411994 2011-08-23 13:15:01,1.27127243107 2011-08-23 14:15:01,1.15911742747 2011-08-23 16:15:01,1.05845536275 2011-08-23 17:15:01,0.926634493627 2011-08-23 18:15:01,0.776918970136 2011-08-23 19:15:01,0.928010146312 2011-08-23 20:15:01,0.838158380029 2011-08-23 21:15:01,0.819862464009 2011-08-23 22:15:01,0.69970306261 2011-08-23 23:15:01,0.842383353699 2011-08-24 00:15:01,0.792468794781 2011-08-24 01:15:01,0.713359095889 2011-08-24 02:15:01,0.704135949192 2011-08-24 03:15:01,0.641155335986 2011-08-24 04:15:01,0.634568795601 2011-08-24 05:15:01,0.645873833534 2011-08-24 06:15:01,0.6590434368 2011-08-24 07:15:01,0.812906195196 2011-08-24 08:15:01,0.881111571307 2011-08-24 09:15:01,1.24918386562 2011-08-24 10:15:01,1.36501420903 2011-08-24 11:15:01,1.95241011285 2011-08-24 12:15:01,1.54697912263 2011-08-24 13:15:01,1.5651661815 2011-08-24 15:15:01,1.22446525543 2011-08-24 16:15:01,1.1562087199 2011-08-24 17:15:01,1.33774834437 2011-08-24 18:15:01,1.03148188994 2011-08-24 19:15:01,0.935049971832 2011-08-24 20:15:01,0.711196895617 2011-08-24 21:15:01,0.767570958313 2011-08-24 22:15:01,0.735954907513 2011-08-24 23:15:01,0.77345193875 2011-08-25 00:15:01,0.692628331902 2011-08-25 01:15:01,0.824416895061 2011-08-25 02:15:01,0.730707604827 2011-08-25 03:15:01,0.715088082545 2011-08-25 04:15:01,0.744875421318 2011-08-25 05:15:01,0.737488743085 2011-08-25 06:15:01,0.717183548371 2011-08-25 07:15:01,0.833624102622 2011-08-25 08:15:01,0.953373503323 2011-08-25 09:15:01,1.31115307189 2011-08-25 10:15:01,1.16843727867 2011-08-25 11:15:01,1.0374018924 2011-08-25 12:15:01,1.07353824758 2011-08-25 13:15:01,1.18426544594 2011-08-25 15:15:01,0.81995711885 2011-08-25 16:15:01,1.08679580518 2011-08-25 17:15:01,1.2173424085 2011-08-25 18:15:01,1.00456228294 2011-08-25 19:15:01,1.03477665107 2011-08-25 20:15:01,0.948686262348 2011-08-25 21:15:01,0.993665532552 2011-08-25 22:15:01,0.903960473484 2011-08-25 23:15:01,0.788313159199 2011-08-26 00:15:01,0.798556558757 2011-08-26 01:15:01,0.734166131373 2011-08-26 02:15:01,0.742638615815 2011-08-26 03:15:01,0.675874389581 2011-08-26 04:15:01,0.705817989883 2011-08-26 05:15:01,0.727232396299 2011-08-26 06:15:01,0.753356912152 2011-08-26 07:15:01,0.875354972671 2011-08-26 08:15:01,0.925335068588 2011-08-26 10:15:01,1.19420541076 2011-08-26 11:15:01,0.851330505206 2011-08-26 12:15:01,1.31130509932 2011-08-26 13:15:01,1.18812702098 2011-08-26 14:15:01,1.10183903133 2011-08-26 15:15:01,1.05379013513 2011-08-26 16:15:01,1.07217664514 2011-08-26 17:15:01,0.789734929311 2011-08-26 18:15:01,0.890166131849 2011-08-26 19:15:01,0.920508307487 2011-08-26 20:15:01,0.950929806345 2011-08-26 21:15:01,0.822102406411 2011-08-26 22:15:01,0.826540433576 2011-08-26 23:15:01,0.791927711761 2011-08-27 00:15:01,0.702807204893 2011-08-27 01:15:01,0.864523887721 2011-08-27 02:15:01,0.809851903585 2011-08-27 03:15:01,0.758690430787 2011-08-27 04:15:01,0.80677831628 2011-08-27 05:15:01,0.688049770453 2011-08-27 06:15:01,0.81968980524 2011-08-27 07:15:01,0.821442694794 2011-08-27 08:15:01,1.06152614064 2011-08-27 09:15:01,1.44317491332 2011-08-27 10:15:01,1.22704597643 2011-08-27 11:15:01,1.58093752585 2011-08-27 12:15:01,1.51858142365 2011-08-27 13:15:01,1.06284454245 2011-08-27 14:15:01,1.29828215868 2011-08-27 15:15:01,1.17357031987 2011-08-27 16:15:01,0.938417521965 2011-08-27 17:15:01,0.719759087413 2011-08-27 18:15:01,0.793253640139 2011-08-27 19:15:01,0.821043529075 2011-08-27 20:15:01,0.77728705129 2011-08-27 21:15:01,0.761011905195 2011-08-27 22:15:01,0.794456554147 2011-08-27 23:15:01,0.71510777014 2011-08-28 00:15:01,0.670100640381 2011-08-28 01:15:01,0.54761579658 2011-08-28 17:15:01,0.849284090378 2011-08-28 18:15:01,0.852476609926 2011-08-28 19:15:01,0.805305280552 2011-08-28 20:15:01,0.889728282553 2011-08-28 21:15:01,0.778613508361 2011-08-28 22:15:01,0.685767835952 2011-08-28 23:15:01,0.726981575893 2011-08-29 00:15:01,0.645975352581 2011-08-29 01:15:01,0.777534142894 2011-08-29 02:15:01,0.723113114405 2011-08-29 03:15:01,0.831905214884 2011-08-29 04:15:01,0.674230251552 2011-08-29 05:15:01,0.71415081987 2011-08-29 06:15:01,0.795823883546 2011-08-29 07:15:01,0.853323981424 2011-08-29 08:15:01,1.03638510945 2011-08-29 09:15:01,1.16972027756 2011-08-29 10:15:01,1.37015829137 2011-08-29 11:15:01,1.19479416172 2011-08-29 12:15:01,1.50872750294 2011-08-29 13:15:01,1.25480461243 2011-08-29 14:15:01,1.18351258787 2011-08-29 15:15:01,0.838183770344 2011-08-29 16:15:01,1.05843861494 2011-08-29 17:15:01,1.1154608336 2011-08-29 18:15:01,0.87860810131 2011-08-29 19:15:01,1.09936880724 2011-08-29 20:15:01,0.87085318709 2011-08-29 21:15:01,0.843596628444 2011-08-29 22:15:01,0.777040471902 2011-08-29 23:15:01,0.688557936796 2011-08-30 00:15:01,0.697836804319 2011-08-30 01:15:01,0.771217121712 2011-08-30 02:15:01,0.694660626848 2011-08-30 03:15:01,0.786323057256 2011-08-30 04:15:01,0.654660190687 2011-08-30 05:15:01,0.72306000212 2011-08-30 06:15:01,0.774674210709 2011-08-30 07:15:01,0.884858627959 2011-08-30 08:15:01,1.08493710832 2011-08-30 09:15:01,1.14704937346 2011-08-30 10:15:01,1.40645395214 2011-08-30 11:15:01,0.967981387104 2011-08-30 12:15:01,1.75374564605 2011-08-30 13:15:01,1.22262717456 2011-08-30 15:15:01,1.2477794358 2011-08-30 16:15:01,1.04428573933 2011-08-30 17:15:01,0.924926251082 2011-08-30 18:15:01,1.20389636883 2011-08-30 19:15:01,0.936448977169 2011-08-30 21:15:01,0.869768173712 2011-08-30 22:15:01,0.820539262738 2011-08-30 23:15:01,0.855369516046 2011-08-31 00:15:01,0.961147001986 2011-08-31 01:15:01,0.958316270557 2011-08-31 02:15:01,0.814787274063 2011-08-31 03:15:01,0.771593377122 2011-08-31 04:15:01,0.766299657727 2011-08-31 05:15:01,0.724229465703 2011-08-31 06:15:01,0.792862195384 2011-08-31 07:15:01,0.942622099425 2011-08-31 08:15:01,1.14142180366 2011-08-31 09:15:01,1.50385784428 2011-08-31 10:15:01,1.32986869524 2011-08-31 11:15:01,1.35511366926 2011-08-31 12:15:01,1.30690884147 2011-08-31 13:15:01,1.36129882778 2011-08-31 14:15:01,1.26118176226 2011-08-31 15:15:01,1.29325090898 2011-08-31 16:15:01,1.13162826786 2011-08-31 17:15:01,0.878180273521 2011-08-31 19:15:01,1.00724076188 2011-08-31 20:15:01,0.82977849928 2011-08-31 21:15:01,0.791770492231 2011-08-31 22:15:01,0.776412218566 2011-08-31 23:15:01,1.01967346467 2011-09-01 00:15:01,0.672524767707 2011-09-01 01:15:01,0.805459791968 2011-09-01 02:15:01,0.697760708058 2011-09-01 03:15:01,0.671198221878 2011-09-01 04:15:01,0.686612619056 2011-09-01 05:15:01,0.730138629699 2011-09-01 06:15:01,0.773151750973 2011-09-01 07:15:01,0.920818621438 2011-09-01 08:15:01,1.05974998234 2011-09-01 09:15:01,1.25720738674 2011-09-01 10:15:01,1.69107806691 2011-09-01 13:15:01,1.38872596255 2011-09-01 18:15:01,1.18474325929 2011-09-01 19:15:01,1.00755614801 2011-09-01 20:15:01,0.889925459781 2011-09-01 21:15:01,0.879357863581 2011-09-01 22:15:01,0.813560856853 2011-09-01 23:15:01,0.668334950547 2011-09-02 00:15:01,0.634700519233 2011-09-02 01:15:01,0.710229977153 2011-09-02 02:15:01,0.697412833033 2011-09-02 03:15:01,0.725219217625 2011-09-02 04:15:01,0.60871199833 2011-09-02 05:15:01,0.636974122101 2011-09-02 06:15:01,0.841129477074 2011-09-02 07:15:01,0.771209479568 2011-09-02 08:15:01,1.02627235945 2011-09-02 09:15:01,1.38391615999 2011-09-02 10:15:01,1.70182048664 2011-09-02 11:15:01,1.30911498665 2011-09-02 12:15:01,1.44916720916 2011-09-02 13:15:01,1.10994932226 2011-09-02 14:15:01,1.20104749435 2011-09-02 15:15:01,1.00461581227 2011-09-02 16:15:01,1.24974971635 2011-09-02 17:15:01,0.930537334322 2011-09-02 18:15:01,0.696674235341 2011-09-02 19:15:01,1.90695503664 2011-09-02 20:15:01,1.14246709184 2011-09-02 21:15:01,1.11277858928 2011-09-02 22:15:01,0.694990722636 2011-09-02 23:15:01,1.1243682849 2011-09-03 00:15:01,1.63223166525 2011-09-03 01:15:01,1.12621421132 2011-09-03 02:15:01,1.22375614029 2011-09-03 03:15:01,0.836308743265 2011-09-03 04:15:01,0.764508533837 2011-09-03 05:15:01,0.824846108339 2011-09-03 06:15:01,0.858898956181 2011-09-03 07:15:01,1.06302492473 2011-09-03 08:15:01,1.40538621285 2011-09-03 09:15:01,1.74459064633 2011-09-03 10:15:01,2.03489870008 2011-09-03 11:15:01,1.93540664402 2011-09-03 12:15:01,2.27425030493 2011-09-03 13:15:01,2.14033402306 2011-09-03 14:15:01,1.77426028471 2011-09-03 15:15:01,1.25941144301 2011-09-03 16:15:01,1.02897679946 2011-09-03 17:15:01,0.924615076404 2011-09-03 18:15:01,0.909732905845 2011-09-03 19:15:01,0.869216123697 2011-09-03 20:15:01,0.541295740253 2011-09-03 21:15:01,1.1777566405 2011-09-03 22:15:01,1.13735222856 2011-09-03 23:15:01,0.890667031052 2011-09-04 00:15:01,0.610490083267 2011-09-04 01:15:01,0.909803400811 2011-09-04 02:15:01,0.997966281743 2011-09-04 03:15:01,0.760097226529 2011-09-04 04:15:01,0.695617328423 2011-09-04 05:15:01,0.756014604219 2011-09-04 06:15:01,0.79008464589 2011-09-04 07:15:01,0.917348874571 2011-09-04 08:15:01,1.13719366386 2011-09-04 09:15:01,1.42018674399 2011-09-04 10:15:01,1.62974773646 2011-09-04 11:15:01,2.39951967225 2011-09-04 12:15:01,1.90579824839 2011-09-04 13:15:01,1.41094529283 2011-09-04 14:15:01,1.51420659222 2011-09-04 15:15:01,0.907680196378 2011-09-04 16:15:01,0.949640701076 2011-09-04 17:15:01,0.853479545072 2011-09-04 19:15:01,0.734071967028 2011-09-04 21:15:01,0.664832645575 2011-09-04 22:15:01,0.751175591232 2011-09-04 23:15:01,0.699932102092 2011-09-05 00:15:01,0.512007082519 2011-09-05 01:15:01,0.768525925193 2011-09-05 02:15:01,0.720969190212 2011-09-05 03:15:01,0.834640838517 2011-09-05 04:15:01,0.627736806898 2011-09-05 05:15:01,0.651203112053 2011-09-05 06:15:01,0.830826437039 2011-09-05 07:15:01,0.708797528226 2011-09-05 08:15:01,0.914809516084 2011-09-05 09:15:01,1.19163674636 2011-09-05 10:15:01,1.64855351909 2011-09-05 11:15:01,1.75118246316 2011-09-05 12:15:01,2.23766160764 2011-09-05 13:15:01,1.66328470303 2011-09-05 15:15:01,0.832920669506 2011-09-05 17:15:01,0.933893576278 2011-09-05 18:15:01,0.689506085719 2011-09-05 19:15:01,0.768903526829 2011-09-05 20:15:01,0.698904886719 2011-09-05 21:15:01,0.681318152131 2011-09-05 22:15:01,0.570423466165 2011-09-05 23:15:01,0.63045223235 2011-09-06 01:15:01,0.614224788781 2011-09-06 02:15:01,0.655868229912 2011-09-06 03:15:01,0.693436352057 2011-09-06 04:15:01,0.611312925873 2011-09-06 05:15:01,0.807827692044 2011-09-06 06:15:01,0.653708482915 2011-09-06 07:15:01,0.937306761036 2011-09-06 08:15:01,1.34108358121 2011-09-06 09:15:01,1.47226847333 2011-09-06 10:15:01,1.72638563622 2011-09-06 11:15:01,1.3196855493 2011-09-06 12:15:01,1.262905036 2011-09-06 14:15:01,1.2017614271 2011-09-06 15:15:01,1.10625236699 2011-09-06 16:15:01,1.45940072715 2011-09-06 17:15:01,1.09848556824 2011-09-06 18:15:01,0.953394382083 2011-09-06 19:15:01,0.878863784275 2011-09-06 20:15:01,1.12067995176 2011-09-06 21:15:01,0.991837847317 2011-09-06 22:15:01,0.831665933419 2011-09-06 23:15:01,0.60047251793 2011-09-07 00:15:01,0.555876363857 2011-09-07 01:15:01,0.823805154231 2011-09-07 02:15:01,0.678606401328 2011-09-07 03:15:01,0.687514096173 2011-09-07 04:15:01,0.657496548202 2011-09-07 05:15:01,0.75337310206 2011-09-07 06:15:01,0.8787691939 2011-09-07 07:15:01,1.14312883039 2011-09-07 08:15:01,1.15805690626 2011-09-07 09:15:01,1.63436764871 2011-09-07 10:15:01,1.74975517548 2011-09-07 11:15:01,2.01440045625 2011-09-07 12:15:01,1.49396356503 2011-09-07 13:15:01,0.908472003661 2011-09-07 14:15:01,1.34644468314 ================================================ FILE: workspace/concurrent_taskpool/Makefile ================================================ SUBDIRS := src tests_and_benchmarks all: $(SUBDIRS) $(SUBDIRS): $(MAKE) -C $@ .PHONY: all $(SUBDIRS) clean: $(MAKE) -C src clean $(MAKE) -C tests_and_benchmarks clean ================================================ FILE: workspace/concurrent_taskpool/src/Makefile ================================================ # jemalloc is faster so let's use it by default JEM_LIBS:= JEM_FLAGS:= # there's no pkg-config ?? JEM_LIB?=$(wildcard /usr/lib/x86_64-linux-gnu/libjemalloc.a) ifeq ($(JEM_LIB),) $(info ** Not using jemalloc) else $(info Using jemalloc: $(JEM_LIB)) JEM_FLAGS:=-DUSE_JEMALLOC JEM_LIBS:=$(JEM_LIB) endif CFLAGS:=$(JEM_FLAGS) LIBS:=$(JEM_LIBS) LIBDIR=../lib all: libtaskpool libtaskpool: concurrent_task_pool_list.o concurrent_task_pool_tree.o $(LIBDIR) ar rcs $(LIBDIR)/libtaskpool.a concurrent_task_pool_list.o concurrent_task_pool_tree.o ranlib $(LIBDIR)/libtaskpool.a concurrent_task_pool_list.o: cc concurrent_task_pool_list.c -c -I src -latomic -lm -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast concurrent_task_pool_tree.o: cc concurrent_task_pool_tree.c -c -I src -latomic -lm -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast $(LIBDIR): mkdir -p $(LIBDIR) clean: rm -rf *.o *.a $(LIBDIR) ================================================ FILE: workspace/concurrent_taskpool/src/concurrent_task_pool.h ================================================ /* * A concurrent, scalable, wait-free task pool implementation that performs well under high CAS contention * * Created on: 22 Jan 2019 * Author: aagapi */ #ifndef KERNEL_CONCURRENT_TASK_POOL_H_ #define KERNEL_CONCURRENT_TASK_POOL_H_ #include #include "fastrand.h" #define DEFAULT_TREE_HEIGHT 3 #define DEFAULT_K_NO_TRIALS 4 #define MAX_DEGREE 64 #define DEFAULT_DEGREE MAX_DEGREE #define DEFAULT_PREALLOCATED_ELEMENTS 1000000 #define SLACK_PREALLOCATED_ELEMENTS 1 #define PRECALCULATE_TREE_LEVEL_SIZES #define CALCULATE_TREE_SIZE(h,d) ((((int) pow(d, h)) - 1) / (d - 1)) #define TREE_FILL_FACTOR(h,d,k) ((int)(pow((double)d,(((double)k+2)*h/(k+3))) / (d - 1))) // == (degree^^((k+2)/(k+3)*height))/(degree-1) #define _NO_PREALLOCATED_TREES(no_elems, h,d,k) (((int) (SLACK_PREALLOCATED_ELEMENTS*(no_elems))) / (TREE_FILL_FACTOR(h,d,k))) #define MAX(a, b) ((a>b)?(a):(b)) #define NO_PREALLOCATED_TREES(no_elems, h,d,k) (MAX(_NO_PREALLOCATED_TREES(no_elems, h,d,k),1)) // Macros for version handling (ABA etc): #define EMPTY_0_VERSION 0 #define FULL_0_VERSION (1 << 31) #define IS_EMPTY(n) (!((n) & (1 << 31))) #define VERSION(n) ((n) & ~(1 << 31)) #define NEW_VERSION(n, v) ((v) | ((n) & (1 << 31))) #define EMPTY_0_VERSION_BYTE 0 #define FULL_0_VERSION_BYTE ((unsigned char) (1 << 7)) #define IS_EMPTY_BYTE(n) (!((n) & (1 << 7))) #define VERSION_BYTE(n) ((n) & ~(1 << 7)) #define NEW_VERSION_BYTE(n, v) ((v) | ((n) & (1 << 7))) #define BITMASK(len) ((1 << len) - 1) // A 'slice' of a 32 bit integer, encompassing bits [start,start+len-1]: #define SLICE(n,start,len) ((n >> (32 - start - len)) & ((1 << len) - 1)) // Macros for binary trees: #define LEFT_CHILD(i) (2*(i)+1) #define RIGHT_CHILD(i) (2*(i)+2) #define PARENT(i) (((i)-1)/2) #define HAS_PARENT(i) ((i)>0) #define HAS_TASKS(node) (!IS_EMPTY(node.tasks_left) || !IS_EMPTY(node.tasks_right) || (node.data != NULL)) // Macros for k-ary trees: #define CHILD_K(p,k,d) ((d)*(p) + (k) + 1) #define PARENT_K(i,d) (((i)-1)/d) // Macro points to the array of TREE_SIZE elements, holding the actual tree data (struct concurrent_tree_pool_node *), // allocated contiguously in the same mem chunk, right after the corresponding tree pool metadata (struct concurrent_pool_node): #define TREE_PTR(ptr) ((struct concurrent_tree_pool_node *) (&ptr[1])) // CAS and atomic load utility macros: // #define USE_ATOMIC_LOAD // #define USE_MEMORY_ORDER_RELAXED #ifdef USE_ATOMIC_LOAD #ifdef USE_MEMORY_ORDER_RELAXED #define LOAD(a) (atomic_load_explicit(&(a), memory_order_relaxed)) #else #define LOAD(a) (atomic_load_(&(a))) #endif #else #define LOAD(a) (a) #endif #define USE_WEAK_CAS_IN_LOOPS // #define USE_WEAK_CAS_OUT_OF_LOOPS #ifdef USE_WEAK_CAS_IN_LOOPS #define LOOP_CAS atomic_compare_exchange_weak #else #define LOOP_CAS atomic_compare_exchange_strong #endif #ifdef USE_WEAK_CAS_OUT_OF_LOOPS #define CAS atomic_compare_exchange_weak #else #define CAS atomic_compare_exchange_strong #endif // #define FAST_PUT // #define FAST_GET // #define FAST_GET_PER_LEVEL // #define TASKPOOL_DEBUG // #define TASKPOOL_TRACE typedef void *WORD; typedef struct concurrent_pool_node * concurrent_pool_node_ptr; typedef _Atomic concurrent_pool_node_ptr atomic_concurrent_pool_node_ptr; typedef struct concurrent_pool_node_ptr_pair { concurrent_pool_node_ptr prev; concurrent_pool_node_ptr crt; } concurrent_pool_node_ptr_pair; typedef _Atomic concurrent_pool_node_ptr_pair atomic_concurrent_pool_node_ptr_pair; typedef struct concurrent_pool { int tree_height; // tree height for component complete tree pools int degree; // tree degree for component complete tree pools int k_no_trials; // number of retries upon a failed put (influences fill factor of component trees) concurrent_pool_node_ptr head; // head of concurrent tree list atomic_concurrent_pool_node_ptr producer_tree; // pointer to current producer tree atomic_concurrent_pool_node_ptr_pair consumer_trees; // pair of pointers to (previous ,current) consumer trees atomic_uint old_producers; // producers that currently attempt to move producer_tree backwards #ifdef PRECALCULATE_TREE_LEVEL_SIZES int * level_sizes; // precomputed array of level sizes (used to speed up pool inserts) #endif concurrent_pool_node_ptr _last_prealloc_block; } concurrent_pool; typedef struct concurrent_tree_pool_node { atomic_uchar child_has_tasks[MAX_DEGREE]; atomic_uchar dirty; // any task was placed in this node? atomic_uchar grabbed; // was this task grabbed? atomic_uint pending; // pending concurrent updates to parent WORD data; // actual task } concurrent_tree_pool_node; // Actual array of "struct concurrent_tree_pool_node" tree nodes (array representation of the complete tree) // is allocated right after the "struct concurrent_pool_node" metadata, in the same mem chunk, // and accessible via the TREE_PTR) macro: typedef struct concurrent_pool_node { int node_id; atomic_concurrent_pool_node_ptr next; } concurrent_pool_node; // "Public" API: // Functions to allocate a taskpool: // Set 'no_prealloc' if you have an idea of the typical number of items a pool will hold, to optimize mem allocations. // Otherwise, set 'no_prealloc' to something < 0 and a default value will be used. // Set 'degree' and 'tree_height' to choose custom values for the tree degree and height, respectively. // Degree must be smaller than MAX_DEGREE. concurrent_pool * allocate_pool(int no_prealloc); concurrent_pool * allocate_pool_with_tree_height(int tree_height, int no_prealloc); concurrent_pool * allocate_pool_with_tree_height_and_degree(int tree_height, int degree, int no_prealloc); void free_pool(concurrent_pool * p); // Functions to manipulate a taskpool: // Args: // - task: void* allocated and managed by the app // - pool: ptr to taskpool // - fastrandstate: *Always* pass a valid pointer to the fast random generator state to each call. // Before starting library use in each thread, seed this state via GET_RANDSEED(&fastrandstate, apprand), // where apprand is an (optional) per-thread unique state. If not available, just call GET_RANDSEED(&fastrandstate, 0) to seed // Use the same pointer on each subsequent call to all taskpool library functions int put(WORD task, concurrent_pool* pool, unsigned int * fastrandstate); int get(WORD* task, concurrent_pool* pool, unsigned int * fastrandstate); int get_last_block_id(concurrent_pool * p); void set_no_trials(concurrent_pool * pool, int no_trials); // Lower level API to access tree pools directly: concurrent_tree_pool_node * allocate_tree_pool(int tree_height, int degree, int * precomputed_level_sizes); void free_tree_pool(concurrent_tree_pool_node * p); int put_in_tree(WORD task, concurrent_tree_pool_node* pool, int degree, int tree_height, int k_no_trials, int * precomputed_level_sizes, unsigned int * fastrandstate); int get_from_tree(WORD* task, concurrent_tree_pool_node* pool, int degree, int tree_height, int * precomputed_level_sizes, unsigned int * fastrandstate); int preallocate_trees(concurrent_pool* pool, int no_trees, int per_tree_data_size, char * prealloc_mem); #endif /* KERNEL_CONCURRENT_TASK_POOL_H_ */ ================================================ FILE: workspace/concurrent_taskpool/src/concurrent_task_pool_list.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * A concurrent, scalable, wait-free task pool implementation that performs well under high CAS contention * * This file contains functions related to managing lists of tree pools * * Created on: 22 Jan 2019 * Author: aagapi */ #include #include #include #include #include #include #include "concurrent_task_pool.h" concurrent_pool_node * allocate_pool_node(int node_id, int tree_height, int degree, int * precomputed_level_sizes, concurrent_pool_node * prealloc_mem) { concurrent_pool_node * pn = NULL; int total_nodes, total_size; if(prealloc_mem != NULL) { pn=prealloc_mem; } else { if(precomputed_level_sizes!=NULL) total_nodes = precomputed_level_sizes[tree_height-1]; else total_nodes = CALCULATE_TREE_SIZE(tree_height, degree); total_size = total_nodes * sizeof(struct concurrent_tree_pool_node); // Actual array of "total_nodes" tree nodes is allocated right after the "struct concurrent_pool_node" metadata: pn = (concurrent_pool_node *) malloc(sizeof(struct concurrent_pool_node) + total_size); if(pn == NULL) { printf("Failed to allocate tree of size %d/%d\n", total_nodes, total_size); return NULL; } memset(pn, 0, sizeof(struct concurrent_pool_node) + total_size); #ifdef TASKPOOL_DEBUG printf("Allocated tree of size %d/%d\n", total_nodes, total_size); #endif } pn->node_id = node_id; atomic_init(&pn->next, NULL); return pn; } void free_pool_node(concurrent_pool_node * p) { free(p); } concurrent_pool * _allocate_pool(int tree_height, int k_no_trials, int degree, int no_prealloc) { int nodes_per_tree = CALCULATE_TREE_SIZE(tree_height, degree); int per_tree_data_size = nodes_per_tree * sizeof(struct concurrent_tree_pool_node); int no_prealloced_trees = NO_PREALLOCATED_TREES(no_prealloc, tree_height, degree, k_no_trials); // The list of all pre-allocated tree blocks is allocated in the memchunk right after the pool's metadata. // In turn, for each pre-allocated tree node block, the actual array of "nodes_per_tree" tree nodes is also // allocated in the chunk right after the "struct concurrent_pool_node" metadata. So we use a single malloc for all these: concurrent_pool * p = (concurrent_pool *) malloc(sizeof(struct concurrent_pool) + no_prealloced_trees * (sizeof(struct concurrent_pool_node) + per_tree_data_size)); if(p == NULL) { printf("Failed to allocate pool of %d blocks, each of size %d/%d\n", no_prealloced_trees, nodes_per_tree, per_tree_data_size); return NULL; } memset(p, 0, sizeof(struct concurrent_pool) + no_prealloced_trees * (sizeof(struct concurrent_pool_node) + per_tree_data_size)); #ifdef TASKPOOL_DEBUG printf("Pre-allocated tree of %d blocks, each of size %d/%d\n", no_prealloced_trees, nodes_per_tree, per_tree_data_size); #endif #ifdef PRECALCULATE_TREE_LEVEL_SIZES p->level_sizes = (int *) malloc(tree_height * sizeof(int)); if(p->level_sizes == NULL) { free(p); return NULL; } for(int i=0;ilevel_sizes[i]=CALCULATE_TREE_SIZE(i+1, degree); #endif p->tree_height = tree_height; p->degree = degree; p->k_no_trials = k_no_trials; preallocate_trees(p, no_prealloced_trees, per_tree_data_size, (char *)(&p[1])); atomic_init(&p->producer_tree, p->head); concurrent_pool_node_ptr_pair cts = { .prev = NULL, .crt = p->head }; atomic_init(&p->consumer_trees, cts); // Set consumer pointer pair to (prev=NULL, current=producer=head) return p; } concurrent_pool * allocate_pool_with_tree_height_and_degree(int tree_height, int degree, int no_prealloc) { return _allocate_pool(tree_height, DEFAULT_K_NO_TRIALS, degree, MAX(no_prealloc, DEFAULT_PREALLOCATED_ELEMENTS)); } concurrent_pool * allocate_pool_with_tree_height(int tree_height, int no_prealloc) { return _allocate_pool(tree_height, DEFAULT_K_NO_TRIALS, DEFAULT_DEGREE, MAX(no_prealloc, DEFAULT_PREALLOCATED_ELEMENTS)); } concurrent_pool * allocate_pool(int no_prealloc) { return _allocate_pool(DEFAULT_TREE_HEIGHT, DEFAULT_K_NO_TRIALS, DEFAULT_DEGREE, MAX(no_prealloc, DEFAULT_PREALLOCATED_ELEMENTS)); } void set_no_trials(concurrent_pool * pool, int no_trials) { pool->k_no_trials = no_trials; } void free_pool(concurrent_pool * p) { concurrent_pool_node_ptr pn = p->_last_prealloc_block->next, next_pn = NULL; while(pn != NULL) { next_pn = pn->next; free_pool_node(pn); pn = next_pn; } #ifdef PRECALCULATE_TREE_LEVEL_SIZES free(p->level_sizes); #endif free(p); } int get_last_block_id(concurrent_pool * p) { concurrent_pool_node_ptr pn = p->head, next_pn = NULL; while(pn->next != NULL) { next_pn = pn->next; pn = next_pn; } return pn->node_id; } static inline int move_consumer_ptr_back(concurrent_pool* pool, concurrent_pool_node_ptr producer_tree, concurrent_pool_node_ptr_pair c_ptrs_in) { atomic_fetch_add(&(pool->old_producers), 1); concurrent_pool_node_ptr_pair c_ptrs = c_ptrs_in; while(1) { concurrent_pool_node_ptr_pair new_cts = { .prev = NULL, .crt = producer_tree }; if(LOOP_CAS(&(pool->consumer_trees), &c_ptrs, new_cts)) { #ifdef TASKPOOL_DEBUG printf("Succeeded moving back consumer ptrs to (%p/%d,%p/%d)\n", new_cts.prev, (new_cts.prev!=NULL)?(new_cts.prev->node_id):-1, new_cts.crt, (new_cts.crt!=NULL)?(new_cts.crt->node_id):-1); #endif break; } else { #ifdef TASKPOOL_DEBUG printf("Failed moving back consumer ptrs to (%p/%d,%p/%d)\n", new_cts.prev, (new_cts.prev!=NULL)?(new_cts.prev->node_id):-1, new_cts.crt, (new_cts.crt!=NULL)?(new_cts.crt->node_id):-1); #endif } if(c_ptrs.crt->node_id <= producer_tree->node_id) break; } atomic_fetch_add(&(pool->old_producers), -1); return 0; } // Note: This function is NOT supposed to be thread safe. Only call in pool constructor. int preallocate_trees(concurrent_pool* pool, int no_trees, int per_tree_data_size, char * prealloc_mem) { concurrent_pool_node_ptr crt_tree = NULL; for(int i=0;itree_height, pool->degree, pool->level_sizes, (concurrent_pool_node *)(prealloc_mem + i*(sizeof(struct concurrent_pool_node) + per_tree_data_size))); #else concurrent_pool_node_ptr pool_node = allocate_pool_node(i+1, pool->tree_height, pool->degree, NULL, (concurrent_pool_node *)(prealloc_mem + i*(sizeof(struct concurrent_pool_node) + per_tree_data_size))); #endif if(crt_tree != NULL) { atomic_init(&crt_tree->next, pool_node); } else { pool->head = pool_node; } crt_tree = pool_node; } pool->_last_prealloc_block=crt_tree; return 0; } static inline int insert_new_tree(concurrent_pool* pool, concurrent_pool_node_ptr producer_tree_in) { concurrent_pool_node_ptr producer_tree = producer_tree_in, next_ptr = LOAD(producer_tree_in->next); #ifdef PRECALCULATE_TREE_LEVEL_SIZES concurrent_pool_node_ptr pool_node = allocate_pool_node(0, pool->tree_height, pool->degree, pool->level_sizes, NULL); #else concurrent_pool_node_ptr pool_node = allocate_pool_node(0, pool->tree_height, pool->degree, NULL, NULL); #endif if(pool_node == NULL) return -1; // Find end of tree list: while(next_ptr != NULL) { producer_tree = next_ptr; next_ptr = LOAD(producer_tree->next); } pool_node->node_id = producer_tree->node_id + 1; concurrent_pool_node_ptr old = NULL; // Attempt to chain our newly allocated tree pool to the end of the list. // If the CAS fails, it means a concurrent producer managed to extend the list before us, // in which case we free our newly allocated pool and return. if(!CAS(&(producer_tree->next), &old, pool_node)) { #ifdef TASKPOOL_DEBUG printf("Failed setting next ptr of %p/%d to %p/%d\n", producer_tree, (producer_tree!=NULL)?(producer_tree->node_id):-1, pool_node, (pool_node!=NULL)?(pool_node->node_id):-1); #endif free_pool_node(pool_node); } else { #ifdef TASKPOOL_DEBUG printf("Succeeded setting next ptr of %p/%d to %p/%d\n", producer_tree, (producer_tree!=NULL)?(producer_tree->node_id):-1, pool_node, (pool_node!=NULL)?(pool_node->node_id):-1); #endif } return 0; } int put(WORD task, concurrent_pool* pool, unsigned int * seedptr) { concurrent_pool_node_ptr producer_tree = NULL; int status = 0; #ifdef PRECALCULATE_TREE_LEVEL_SIZES int * precalculated_level_sizes = pool->level_sizes; #else int * precalculated_level_sizes = NULL; #endif producer_tree = LOAD(pool->producer_tree); while(1) { int put_index = put_in_tree(task, TREE_PTR(producer_tree), pool->degree, pool->tree_height, pool->k_no_trials, precalculated_level_sizes, seedptr); if(put_index >= 0) { #ifdef TASKPOOL_TRACE printf("Successfully put task %ld in tree %d at index %d\n", (long) task, producer_tree->node_id, put_index); #endif // Put succeeded in current tree, but we may need to move back consumer pointer if it overshot us: concurrent_pool_node_ptr_pair c_ptrs = LOAD(pool->consumer_trees); if(c_ptrs.crt->node_id > producer_tree->node_id) { move_consumer_ptr_back(pool, producer_tree, c_ptrs); } return 0; } else // current producer tree is "full" { #ifdef TASKPOOL_DEBUG printf("put_in_tree() returned status %d when attempting to put task %ld in full tree %d. Next pointer is: %d\n", status, (long) task, producer_tree->node_id, (producer_tree->next != NULL)?(producer_tree->next->node_id):(-1)); #endif // It might be that another producer already inserted a new tree, so first check for that: atomic_concurrent_pool_node_ptr producer_tree_next = LOAD(producer_tree->next); if(producer_tree_next == NULL) { status = insert_new_tree(pool, producer_tree); #ifdef TASKPOOL_DEBUG printf("insert_new_tree() returned status %d when attempting to put task %ld in full tree %d. Next pointer is: %d\n", status, (long) task, producer_tree->node_id, producer_tree->next->node_id); #endif // Note the only failure condition is failure to allocate memory, otherwise inserts s'd always succeed: if(status != 0) return status; } // At this point a new tree was successfully linked into the list (either by us or by a concurrent producer). // We next attempt to progress the producer pointer of the pool. If that CAS fails, it just means that // some other producer managed to progress it before us, which is OK: we just continue and attempt // to put our task in the current producer tree of the pool: status = CAS(&(pool->producer_tree), &producer_tree, LOAD(producer_tree->next)); #ifdef TASKPOOL_DEBUG if(status != 1) printf("CAS returned status %d when attempting to progress producer pointer (after put failed in full tree).\n", status); #endif } } } int get(WORD* task, concurrent_pool* pool, unsigned int * seedptr) { concurrent_pool_node_ptr producer_tree = NULL; concurrent_pool_node_ptr_pair consumer_ptrs = LOAD(pool->consumer_trees); int status; while(1) { // First try the previous and current consumer pointers: if(consumer_ptrs.prev != NULL) { #ifdef TASKPOOL_TRACE printf("get() attempting to find a task in prev tree %d\n", consumer_ptrs.prev->node_id); #endif if(get_from_tree(task, TREE_PTR(consumer_ptrs.prev), pool->degree, pool->tree_height, pool->level_sizes, seedptr)==0) { #ifdef TASKPOOL_TRACE printf("get() found task %ld in prev tree %d\n", (long) *task, consumer_ptrs.prev->node_id); #endif return 0; } } if(consumer_ptrs.crt != NULL) { #ifdef TASKPOOL_TRACE printf("get() attempting to find a task in crt tree %d\n", consumer_ptrs.crt->node_id); #endif if(get_from_tree(task, TREE_PTR(consumer_ptrs.crt), pool->degree, pool->tree_height, pool->level_sizes, seedptr)==0) { #ifdef TASKPOOL_TRACE printf("get() found task %ld in crt tree %d\n", (long) *task, consumer_ptrs.crt->node_id); #endif return 0; } } producer_tree = LOAD(pool->producer_tree); if(producer_tree->node_id <= consumer_ptrs.crt->node_id) { #ifdef TASKPOOL_TRACE printf("get(): No new tasks exist (producer tree %d < consumer tree %d)\n", producer_tree->node_id, consumer_ptrs.crt->node_id); #endif *task = NULL; // No new tasks exist return 1; } concurrent_pool_node_ptr_pair new_cts = { .prev = consumer_ptrs.crt, .crt = consumer_ptrs.crt->next }; if(LOAD(pool->old_producers) == 0) { // Whether my CAS to update consumer pointers succeeds or not, use the most recent value // of the (prev, crt) pointer pair to retry grabbing tasks from the new tree pointers: status = CAS(&(pool->consumer_trees), &consumer_ptrs, new_cts); #ifdef TASKPOOL_DEBUG printf("%s setting consumer ptrs to (%p/%d,%p/%d)\n", (status>0)?"Succeeded":"Failed", new_cts.prev, (new_cts.prev!=NULL)?(new_cts.prev->node_id):-1, new_cts.crt, (new_cts.crt!=NULL)?(new_cts.crt->node_id):-1); #endif } else // If there are currently some producers attempting to move consumer pointer back, retry to read from // the (updated) consumer pointer again, but *do not* attempt to progress consumer pointer after that, // to avoid race condition: { consumer_ptrs = new_cts; #ifdef TASKPOOL_DEBUG printf("Locally setting consumer ptrs to (%p/%d,%p/%d)\n", new_cts.prev, (new_cts.prev!=NULL)?(new_cts.prev->node_id):-1, new_cts.crt, (new_cts.crt!=NULL)?(new_cts.crt->node_id):-1); #endif } } } ================================================ FILE: workspace/concurrent_taskpool/src/concurrent_task_pool_tree.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * A concurrent, scalable, wait-free task pool implementation that performs well under high CAS contention * * This file contains functions related to managing tree pools * * Created on: 22 Jan 2019 * Author: aagapi */ #include #include #include #include #include #include #include "concurrent_task_pool.h" static inline int has_tasks_k(concurrent_tree_pool_node node, int degree) { if(node.data != NULL) return 1; for(int i=0;i< degree;i++) if(!IS_EMPTY_BYTE(node.child_has_tasks[i])) return 1; return 0; } static inline int random_in_level(int level, int degree, int * precomputed_level_sizes, unsigned int * seedptr) { unsigned int first_in_level, last_in_level, randno; if(level==0) return 0; if(precomputed_level_sizes!=NULL) { first_in_level = precomputed_level_sizes[level-1]; last_in_level = precomputed_level_sizes[level] - 1; } else { first_in_level = CALCULATE_TREE_SIZE(level, degree); last_in_level = CALCULATE_TREE_SIZE(level+1, degree) - 1; } FASTRAND(seedptr, randno); return (randno % (last_in_level - first_in_level + 1)) + first_in_level; } static inline int update_father(int index, concurrent_tree_pool_node* pool, int degree, unsigned char value) { atomic_fetch_add(&(pool[index].pending), 1); int parent_index=PARENT_K(index, degree); int child_index = (index - 1) % degree; unsigned char old = 0, new = 0; int success = 0; old = LOAD(pool[parent_index].child_has_tasks[child_index]); new = (value)?(FULL_0_VERSION_BYTE):(EMPTY_0_VERSION_BYTE); new = NEW_VERSION_BYTE(new, VERSION_BYTE(old) + 1); success = CAS(&(pool[parent_index].child_has_tasks[child_index]), &old, new); #ifdef TASKPOOL_DEBUG printf("update_father(): Updating parent index %d of index %d from (%u, %u, %u) to (%u, %u, %u) returned %d\n", parent_index, index, old, IS_EMPTY_BYTE(old), VERSION_BYTE(old), new, IS_EMPTY_BYTE(new), VERSION_BYTE(new), success); #endif atomic_fetch_add(&(pool[index].pending), -1); return success; } static inline void update_node_metadata(int index, concurrent_tree_pool_node* pool, int degree, unsigned char value) { int trials = 0, crt_index = index; #ifdef TASKPOOL_TRACE printf("update_node_metadata(index=%d, value=%d)\n", index, value); #endif while(HAS_PARENT(crt_index)) { int have_tasks = has_tasks_k(pool[crt_index], degree); if(value != have_tasks) { #ifdef TASKPOOL_TRACE printf("update_node_metadata(): Skipping because my operation has been eliminated: value=%d != has_tasks(%d)=%d\n", value, crt_index, have_tasks); #endif return; } int parent_index=PARENT_K(crt_index, degree); concurrent_tree_pool_node parent_node = pool[parent_index]; int child_index = (crt_index - 1) % degree; if(IS_EMPTY_BYTE(pool[parent_index].child_has_tasks[child_index]) == have_tasks || pool[crt_index].pending > 0) { #ifdef TASKPOOL_TRACE printf("update_node_metadata(index=%d, value=%d), updating parent index %d\n", index, value, parent_index); #endif trials++; if(!update_father(crt_index, pool, degree, value)) { #ifdef TASKPOOL_TRACE printf("update_node_metadata(index=%d, value=%d), update_father() failed on parent index %d, trials=%d\n", index, value, parent_index, trials); #endif if(trials < 2) continue; } } else { #ifdef TASKPOOL_TRACE printf("update_node_metadata(index=%d, value=%d), skipping update of parent index %d because pool[%d].pending=%d, child_index=%d, parent_empty_child=%d, has_tasks=%d\n", index, value, parent_index, crt_index, pool[crt_index].pending, child_index, IS_EMPTY(pool[parent_index].child_has_tasks[child_index]), have_tasks); #endif } crt_index = parent_index; trials = 0; } } static inline int put_in_node_simple(int index, concurrent_tree_pool_node* pool, int degree, WORD task) { int crt_index = index; unsigned char old = LOAD(pool[crt_index].dirty); if(old == 0 && CAS(&pool[crt_index].dirty, &old, 1)) { pool[crt_index].data = task; return crt_index; } else { return -1; } } static inline int put_in_node(int index, concurrent_tree_pool_node* pool, int degree, WORD task) { int crt_index = index; while(HAS_PARENT(crt_index) && pool[PARENT_K(crt_index, degree)].data==NULL) crt_index=PARENT_K(crt_index, degree); unsigned char old = LOAD(pool[crt_index].dirty); if(old == 0 && CAS(&pool[crt_index].dirty, &old, 1)) { pool[crt_index].data = task; return crt_index; } else { return -1; } } static inline int find_node_for_put(WORD task, concurrent_tree_pool_node* pool, int tree_height, int degree, int k_no_trials, int * precomputed_level_sizes, unsigned int * seedptr) { int index; #ifdef FAST_PUT int total_nodes = 0; if(precomputed_level_sizes!=NULL) { total_nodes = precomputed_level_sizes[tree_height-1]; } else { total_nodes = CALCULATE_TREE_SIZE(tree_height, degree); } unsigned int randno; FASTRAND(seedptr, randno); index=put_in_node_simple(randno % total_nodes, pool, degree, task); if(index!=-1) return index; #endif for(int level=1;level 0) update_node_metadata(index, pool, degree, 0); return 0; } else // Didn't manage to grab the task. Keep trying to get a task from the current tree: { continue; } } } concurrent_tree_pool_node * allocate_tree_pool(int tree_height, int degree, int * precomputed_level_sizes) { int total_nodes, total_size; if(precomputed_level_sizes!=NULL) total_nodes = precomputed_level_sizes[tree_height-1]; else total_nodes = CALCULATE_TREE_SIZE(tree_height, degree); total_size = total_nodes * sizeof(struct concurrent_tree_pool_node); concurrent_tree_pool_node * tpn = (concurrent_tree_pool_node *) malloc(total_size); if(tpn) { memset(tpn, 0, total_size); #ifdef TASKPOOL_DEBUG printf("Allocated tree of size %d/%d\n", total_nodes, total_size); #endif } else { printf("Failed to allocate tree of size %d/%d\n", total_nodes, total_size); } return tpn; } void free_tree_pool(concurrent_tree_pool_node * p) { free(p); } ================================================ FILE: workspace/concurrent_taskpool/src/fastrand.h ================================================ #ifndef FASTRAND_H_ #define FASTRAND_H_ #if( defined _POSIX_THREADS && _POSIX_TIMERS >= 0 && _POSIX_MONOTONIC_CLOCK >= 0 ) #define GET_RANDSEED(seedptr, rand) \ { \ struct timespec tp; \ clock_gettime( CLOCK_MONOTONIC_RAW, &tp ); \ *(seedptr) = (unsigned int) ((tp.tv_nsec & 0xFFFFFFFF00000000) + (tp.tv_nsec & 0x00000000FFFFFFFF) + rand) ; \ } #else #define GET_RANDSEED(seedptr, rand) \ { \ long now = time(NULL); \ *(seedptr) = (unsigned int) ((now & 0xFFFFFFFF00000000) + (now & 0x00000000FFFFFFFF) + rand) ; \ } #endif #define FASTRAND(seedptr, value) \ { *seedptr = (214013*(*seedptr)+2531011); \ value = ((*seedptr)>>16)&0x7FFF; \ } static unsigned int g_seed; inline static void fast_srand(int seed) { g_seed = seed; } inline static int fastrand() { g_seed = (214013*g_seed+2531011); return (g_seed>>16)&0x7FFF; } #endif /* FASTRAND_H_ */ ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/Makefile ================================================ # jemalloc is faster so let's use it by default JEM_LIBS:= JEM_FLAGS:= # there's no pkg-config ?? JEM_LIB?=$(wildcard /usr/lib/x86_64-linux-gnu/libjemalloc.a) ifeq ($(JEM_LIB),) $(info ** Not using jemalloc) else $(info Using jemalloc: $(JEM_LIB)) JEM_FLAGS:=-DUSE_JEMALLOC JEM_LIBS:=$(JEM_LIB) endif LDFS_FLAGS:=-I ~/liblfds7.1.1/liblfds711/inc -L ~/liblfds7.1.1/liblfds711/bin LDFS_LIBS:=-llfds711 CFLAGS:=$(JEM_FLAGS) $(LDFS_FLAGS) LIBS:=$(JEM_LIBS) $(LDFS_LIBS) all: concurrent_task_pool_test_multithreaded concurrent_task_pool_test_multithreaded_mixed concurrent_task_pool_test_multithreaded: concurrent_task_pool_test_multithreaded.c cc -std=c11 concurrent_task_pool_test_multithreaded.c -O3 \ $(CFLAGS) -I ../src -L ../lib \ -ltaskpool -latomic -pthread -lm \ $(LIBS) \ -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast \ -o concurrent_task_pool_test_multithreaded concurrent_task_pool_test_multithreaded_mixed: concurrent_task_pool_test_multithreaded_mixed.c cc -std=c11 concurrent_task_pool_test_multithreaded_mixed.c -O3 \ $(CFLAGS) -I ../src -L ../lib \ -ltaskpool -latomic -pthread -lm \ $(LIBS) \ -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast \ -o concurrent_task_pool_test_multithreaded_mixed clean: rm -f concurrent_task_pool_test_multithreaded concurrent_task_pool_test_multithreaded_mixed ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/compare_old_new ================================================ #!/bin/bash # e.g. 11 concurrent_task_pool_times_t_v11_k_ary_tree_static_vector_inline_list_fixed_degree_2.bare_iron.1.ammended.merged.txt concurrent_task_pool_times_t_v12_k_ary_tree_static_vector_inline_list_fixed_no_atomic_load_degree_2.bare_iron.1.txt field=$1 oldfile="$2" newfile="$3" cat $oldfile | cut -f $field -d ' ' | cut -f 2 -d = | sed -e 's/,//g' > old_times.txt cat $newfile | cut -f $field -d ' ' | cut -f 2 -d = | sed -e 's/,//g' > new_times.txt no_msmts=`wc -l new_times.txt | cut -f 1 -d ' '` for msmt in `seq ${no_msmts}` do oldtime=`cat old_times.txt | head -$msmt | tail -1` newtime=`cat new_times.txt | head -$msmt | tail -1` echo `cat $newfile | head -$msmt | tail -1 | cut -f 3,4,5 -d ' '` time_diff=`echo $oldtime - $newtime | bc -l` done | grep -vE "tree_height=1, k_retries=4,"\|"tree_height=1, k_retries=8,"\|"tree_height=1, k_retries=10,"\|"tree_height=2, k_retries=4,"\|"tree_height=2, k_retries=8,"\|"tree_height=2, k_retries=10,"\|"tree_height=4, k_retries=8,"\|"tree_height=4, k_retries=10," ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/compare_settings ================================================ #!/bin/bash # e.g. 11_3_1 11_3_2 11 concurrent_task_pool_times_t_v15_fast_get_per_level_new_test_10M_no_keep_tasks_preallocated_more_threads3_all_degrees.bare_iron.7.txt old=$1 new=$2 field=$3 file=$4 od=`echo $old | cut -f 1 -d '_'` oh=`echo $old | cut -f 2 -d '_'` ok=`echo $old | cut -f 3 -d '_'` nd=`echo $new | cut -f 1 -d '_'` nh=`echo $new | cut -f 2 -d '_'` nk=`echo $new | cut -f 3 -d '_'` ./get_series $od $oh $ok "$field" $file l > series_${field}_${old}.txt ./get_series $nd $nh $nk "$field" $file l > series_${field}_${new}.txt oldseries=`cat series_${field}_${old}.txt | cut -f 2 -d ' '` newseries=`cat series_${field}_${new}.txt | cut -f 2 -d ' '` noentries=`echo $newseries | wc -w` for entryno in `seq $noentries` do newentry=`echo $newseries | cut -f $entryno -d ' '` oldentry=`echo $oldseries | cut -f $entryno -d ' ' | bc -l` x=`head -$entryno series_${field}_${old}.txt | tail -1 | cut -f 1 -d ' '` ; echo $x `echo $oldentry - $newentry | bc -l` done ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/get_series ================================================ #!/bin/bash # e.g. 10 4 1 "11,13" concurrent_task_pool_times_t_v11_k_ary_tree_static_vector_inline_list_fixed_all_degrees_1_32.txt [l] d=$1 h=$2 k=$3 fields="$4" file=$5 if [ $# -eq 5 ] then cat $file | grep "tree_degree=$d, tree_height=$h, k_retries=$k," | cut -f 3,$fields -d ' ' else cat $file | grep "tree_degree=$d, tree_height=$h, k_retries=$k," | cut -f 3,$fields -d ' ' | sed -e 's/[^0-9 ]*=//g' -e 's/,//g' fi ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/get_series_avg ================================================ #!/bin/bash # e.g. 11 3 2 "11" "concurrent_task_pool_times_t_v15_fast_get_per_level_new_test_10M_no_keep_tasks_preallocated_more_threads_aligned_degree_11_h_3_k_2_t_1_32.bare_iron.*" degree=$1 h=$2 k=$3 field=$4 files=`ls $5` nofiles=`echo $files | wc -w` i=0 for file in $files do i=`expr $i + 1` ./get_series ${degree} ${h} ${k} "$field" $file l | sort -n -k 1 -t ' ' | cut -f 2 -d ' ' > s${i}.txt done nomsmts=`cat s1.txt | wc -l` for msmt in `seq $nomsmts` do avg=0 for fileindex in `seq $nofiles` do number=`cat s${fileindex}.txt | head -$msmt | tail -1` avg=`echo $avg + $number | bc -l` done avg=`echo "scale=0; $avg / $nofiles" | bc -l` echo $avg done ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/get_series_q ================================================ #!/bin/bash # e.g. "10,12" concurrent_task_pool_times_r.bare_iron.txt fields="$1" file=$2 if [ $# -eq 2 ] then cat $file | cut -f 3,$fields -d ' ' else cat $file | cut -f 3,$fields -d ' ' | sed -e 's/[^0-9 ]*=//g' -e 's/,//g' fi ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/get_series_r ================================================ #!/bin/bash # e.g. 50000 "10,12" concurrent_task_pool_times_r.bare_iron.txt r=$1 fields="$2" file=$3 if [ $# -eq 3 ] then cat $file | grep ring_buffer_size=$r, | cut -f 3,$fields -d ' ' else cat $file | grep ring_buffer_size=$r, | cut -f 3,$fields -d ' ' | sed -e 's/[^0-9 ]*=//g' -e 's/,//g' fi ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/get_series_r_avg ================================================ #!/bin/bash # e.g. 5000 "11" "concurrent_task_pool_times_t_v15_fast_get_per_level_new_test_10M_no_keep_tasks_preallocated_more_threads_aligned_degree_11_h_3_k_2_t_1_32.bare_iron.*" buffsize=$1 field=$2 files=`ls $3` nofiles=`echo $files | wc -w` firstfile=`echo $files | cut -f 1 -d ' '` nomsmts=`cat $firstfile | wc -l` i=0 for file in $files do i=`expr $i + 1` ./get_series_r ${buffsize} "$field" $file l | sort -n -k 1 -t ' ' | cut -f 2 -d ' ' > s${i}.txt done for msmt in `seq $nomsmts` do avg=0 for fileindex in `seq $nofiles` do number=`cat s${fileindex}.txt | head -$msmt | tail -1` avg=`echo $avg + $number | bc -l` done avg=`echo "scale=0; $avg / $nofiles" | bc -l` echo $avg done ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/rank_param_settings ================================================ #!/bin/bash # e.g. concurrent_task_pool_times_t_v11_k_ary_tree_static_vector_inline_list_fixed_all_degrees_1_32.txt 13 1 32 5 file="$1" field=$2 minthreads=$3 maxthreads=$4 top=$5 for threads in `seq $minthreads $maxthreads` do triples=`cat $file | grep no_threads=$threads, | cut -f 4,5,6,11 -d ' ' | sed -e 's/[ ]*[^0-9]*=/ /g' -e 's/,//g' -e 's/^ //g' | sort -g -k 4 -t ' ' | head -$top | cut -f 1-3 -d ' ' | sed -e 's/ /,/g'` echo "threads=$threads, "`echo $triples | sed -e 's/ /) (/g' -e 's/^/(/g' -e 's/$/)/g'` done ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/rank_param_settings_d_h ================================================ #!/bin/bash # e.g. concurrent_task_pool_times_t_v11_k_ary_tree_static_vector_inline_list_fixed_all_degrees_1_32.txt 13 1 32 5 file=$1 field=$2 minthreads=$3 maxthreads=$4 top=$5 for threads in `seq $minthreads $maxthreads` do tuples=`cat $file | grep no_threads=$threads, | cut -f 4,5,11 -d ' ' | sed -e 's/[ ]*[^0-9]*=/ /g' -e 's/,//g' -e 's/^ //g' | sort -g -k 3 -t ' ' | head -$top | cut -f 1-2 -d ' ' | sed -e 's/ /,/g'` echo "threads=$threads, "`echo $tuples | sed -e 's/ /) (/g' -e 's/^/(/g' -e 's/$/)/g'` done ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/rank_param_settings_freqs ================================================ #!/bin/bash # e.g. concurrent_task_pool_times_t_v11_k_ary_tree_static_vector_inline_list_fixed_all_degrees_1_32.txt 13 1 32 5 file="$1" field=$2 minthreads=$3 maxthreads=$4 top=$5 for threads in `seq $minthreads $maxthreads` do cat $file | grep no_threads=$threads, | cut -f 4,5,6,11 -d ' ' | sed -e 's/[ ]*[^0-9]*=/ /g' -e 's/,//g' -e 's/^ //g' | sort -g -k 4 -t ' ' | head -$top | cut -f 1-3 -d ' ' | sed -e 's/ /,/g' done | sort | uniq -c | sort -n ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/benchmarking_scripts/rank_param_settings_freqs_d_h ================================================ #!/bin/bash # e.g. concurrent_task_pool_times_t_v11_k_ary_tree_static_vector_inline_list_fixed_all_degrees_1_32.txt 13 1 32 5 file=$1 field=$2 minthreads=$3 maxthreads=$4 top=$5 for threads in `seq $minthreads $maxthreads` do cat $file | grep no_threads=$threads, | cut -f 4,5,11 -d ' ' | sed -e 's/[ ]*[^0-9]*=/ /g' -e 's/,//g' -e 's/^ //g' | sort -g -k 3 -t ' ' | head -$top | cut -f 1-2 -d ' ' | sed -e 's/ /,/g' done | sort | uniq -c | sort -n ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/concurrent_task_pool_test_multithreaded.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * A concurrent, scalable, wait-free task pool implementation that performs well under high CAS contention * * This file contains testing functions for pools * * Created on: 22 Jan 2019 * Author: aagapi */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "fastrand.h" #include "concurrent_task_pool.h" // For comparative benchmarking: #include #define NO_TASKS 10000 #define NO_THREADS 1 #define RING_BUFFER_SIZE 1000 // #define VERBOSE // #define KEEP_TASKS_PUT // #define KEEP_TASKS_GET #define BENCHMARK_TASKPOOL 0 #define BENCHMARK_LIBLFDS_QUEUE 1 #define BENCHMARK_LIBLFDS_RINGBUFFER 2 #define BENCHMARK_MUTEX 3 #define BENCHMARK_SPINLOCK_ATOMIC_FLAG 4 #define BENCHMARK_SPINLOCK_PTHREAD 5 int no_tasks = NO_TASKS, no_threads = NO_THREADS, tree_height = DEFAULT_TREE_HEIGHT, k_retries = DEFAULT_K_NO_TRIALS; long num_cpu, ring_buffer_size = RING_BUFFER_SIZE; int benchmark_target = BENCHMARK_TASKPOOL; int verbose = 0; long * put_errs, * dequeued_elems; #define NUMBER_OF_NANOSECONDS_IN_ONE_SECOND 1000000000LLU #if( defined _POSIX_THREADS && _POSIX_TIMERS >= 0 && _POSIX_MONOTONIC_CLOCK >= 0 ) #define TIME_UNITS_PER_SECOND( pointer_to_time_units_per_second ) *(pointer_to_time_units_per_second) = NUMBER_OF_NANOSECONDS_IN_ONE_SECOND #define GET_HIGHRES_TIME( pointer_to_time ) \ { \ struct timespec tp; \ clock_gettime( CLOCK_MONOTONIC_RAW, &tp ); \ *(pointer_to_time) = tp.tv_sec * NUMBER_OF_NANOSECONDS_IN_ONE_SECOND + tp.tv_nsec; \ } #else #error Linux without high resolution timers. #endif // Taskpool-related global vars: concurrent_pool * pool; WORD* tasks; struct lfds711_queue_umm_element *qes; WORD* recovered_tasks; struct lfds711_queue_umm_element *recovered_qes; // Liblfds queue-related global vars: struct lfds711_queue_umm_state qs; // Liblfds ringbuffer-related global vars: struct lfds711_ringbuffer_state rs; struct lfds711_ringbuffer_element * re; // Mutex-related: pthread_mutex_t queue_mutex; // Spinlock-related: volatile atomic_flag queue_spinlock_af; void inline spinlock_lock(volatile atomic_flag *f) { while (atomic_flag_test_and_set(f)) { // spin until we could set the flag } } void inline spinlock_unlock(volatile atomic_flag *f) { atomic_flag_clear(f); } // Libpthread spinlock-related: pthread_spinlock_t queue_spinlock_pthread; // Basic list structs for benchmarking mutexes & spinlocks: typedef struct queue_entry { WORD data; struct queue_entry * next; } queue_entry; queue_entry * queue_head, * queue_tail; queue_entry * simple_qes, * recovered_simple_qes; void *thread_main_put(void *arg) { int thread_id = (int) arg, status=0; int long long unsigned start_put, end_put; struct lfds711_queue_umm_element qe; struct lfds711_ringbuffer_element elem; enum lfds711_misc_flag overwrite_occurred_flag; unsigned int seed; GET_RANDSEED(&seed, thread_id); LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; if(verbose) { GET_HIGHRES_TIME(&start_put); printf("[thread %d put] start_time=%lld, no_tasks=%d\n", thread_id, start_put, no_tasks/no_threads); } int first_task_index = thread_id*(no_tasks/no_threads); for(long i=first_task_index;inext = simple_qes + i; queue_tail = simple_qes + i; } else { queue_tail = simple_qes + i; queue_head = simple_qes + i; } #endif if(benchmark_target == BENCHMARK_MUTEX) pthread_mutex_unlock(&queue_mutex); else if(benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG) spinlock_unlock(&queue_spinlock_af); else if(benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) pthread_spin_unlock(&queue_spinlock_pthread); } if(status!=0) { put_errs[thread_id]++; if(verbose) printf("ERROR (thread %d - put): put() attempt %ld failed!\n", thread_id, i+1); } } if(verbose) { GET_HIGHRES_TIME(&end_put); printf("[thread %d put] no_tasks=%d, total_seconds_put=%f, put_tpt=%f, put_latency_ns=%lld\n", thread_id, no_tasks/no_threads, (end_put-start_put)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND, (no_tasks/no_threads) / ((end_put-start_put)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND), ((end_put-start_put)) / (no_tasks/no_threads)); } return NULL; } void *thread_main_get(void *arg) { int thread_id = (int) arg; int status=0; int long long unsigned start_get, end_get; struct lfds711_queue_umm_element * qep; void *buffer_read_element; int dequeued_elements = 0; WORD recovered_task; unsigned int seed; GET_RANDSEED(&seed, thread_id); LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; if(verbose) { GET_HIGHRES_TIME(&start_get); printf("[thread %d get] start_time=%lld, no_tasks=%d\n", thread_id, start_get, no_tasks/no_threads); } do { if(benchmark_target == BENCHMARK_TASKPOOL) { #ifdef KEEP_TASKS_GET status = get(recovered_tasks + thread_id*(no_tasks/no_threads) + dequeued_elements, pool, &seed); #else status = get(&recovered_task, pool, &seed); #endif } else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) { #ifdef KEEP_TASKS_GET status = !lfds711_queue_umm_dequeue(&qs, &qep); recovered_tasks[thread_id*(no_tasks/no_threads) + dequeued_elements] = (WORD) LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT(*qep); #else status = !lfds711_queue_umm_dequeue(&qs, &qep); LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT(*qep); #endif } else if(benchmark_target == BENCHMARK_LIBLFDS_RINGBUFFER) { #ifdef KEEP_TASKS_GET status = !lfds711_ringbuffer_read(&rs, recovered_tasks + thread_id*(no_tasks/no_threads) + dequeued_elements, NULL); #else status = !lfds711_ringbuffer_read(&rs, &buffer_read_element, NULL); #endif } else if(benchmark_target == BENCHMARK_MUTEX || benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG || benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) { if(benchmark_target == BENCHMARK_MUTEX) pthread_mutex_lock(&queue_mutex); else if(benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG) spinlock_lock(&queue_spinlock_af); else if(benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) pthread_spin_lock(&queue_spinlock_pthread); if(queue_head != NULL) { #ifdef KEEP_TASKS_GET *(recovered_simple_qes + thread_id*(no_tasks/no_threads) + dequeued_elements) = queue_head; #endif queue_head = queue_head->next; if(queue_head == NULL) queue_tail = NULL; } else { status = 1; } if(benchmark_target == BENCHMARK_MUTEX) pthread_mutex_unlock(&queue_mutex); else if(benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG) spinlock_unlock(&queue_spinlock_af); else if(benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) pthread_spin_unlock(&queue_spinlock_pthread); } if(status==0) dequeued_elements++; else break; if(verbose) printf("[thread %d get] got task %d\n", thread_id, (int) ((benchmark_target == BENCHMARK_TASKPOOL)?(recovered_task):(LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT(*qep)))); } while(1); dequeued_elems[thread_id]=dequeued_elements; if(verbose) { GET_HIGHRES_TIME(&end_get); printf("[thread %d get] no_tasks=%d, total_seconds_get=%f, get_tpt=%f, get_latency_ns=%lld\n", thread_id, dequeued_elements, (end_get-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND, (no_tasks/no_threads) / ((end_get-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND), ((end_get-start_get)) / (no_tasks/no_threads)); } return NULL; } int main(int argc, char **argv) { struct lfds711_queue_umm_element qe_dummy; int status = 0, opt, n; long total_put_errs = 0, total_get_errs = 0; int long long unsigned start_put, end_put, start_get, end_get; while ((opt = getopt(argc, argv, "t:h:k:T:B:R:v")) != -1) { switch (opt) { case 't': { n = atoi(optarg); no_tasks = (n>0)?n:NO_TASKS; break; } case 'h': { n = atoi(optarg); tree_height = (n>0)?n:DEFAULT_TREE_HEIGHT; break; } case 'k': { n = atoi(optarg); k_retries = (n>0)?n:DEFAULT_K_NO_TRIALS; break; } case 'T': { n = atoi(optarg); no_threads = (n>0)?n:NO_THREADS; break; } case 'B': { if(optarg[0] == 'T') benchmark_target = BENCHMARK_TASKPOOL; else if(optarg[0] == 'Q') benchmark_target = BENCHMARK_LIBLFDS_QUEUE; else if(optarg[0] == 'R') benchmark_target = BENCHMARK_LIBLFDS_RINGBUFFER; else if(optarg[0] == 'M') benchmark_target = BENCHMARK_MUTEX; else if(optarg[0] == 'A') benchmark_target = BENCHMARK_SPINLOCK_ATOMIC_FLAG; else if(optarg[0] == 'S') benchmark_target = BENCHMARK_SPINLOCK_PTHREAD; break; } case 'R': { n = atoi(optarg); ring_buffer_size = (n>0)?n:RING_BUFFER_SIZE; break; } case 'v': { verbose = 1; break; } } } num_cpu = sysconf(_SC_NPROCESSORS_ONLN); // Detect if we have hyperthreading: u_int32_t registers[4]; __asm__ __volatile__ ("cpuid " : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) : "a" (1), "c" (0)); unsigned CPUFeatureSet = registers[3]; unsigned char hyperthreading = CPUFeatureSet & (1 << 28); hyperthreading=0; // Assume no hyperthreading if(verbose) printf("Detected num_cpu=%ld, hyperthreading=%d\n", num_cpu, hyperthreading); #ifdef KEEP_TASKS_PUT if(benchmark_target == BENCHMARK_TASKPOOL) { tasks = (WORD*) malloc(no_tasks * sizeof(WORD)); } else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) { qes = (struct lfds711_queue_umm_element *) malloc(no_tasks * sizeof(struct lfds711_queue_umm_element)); } #endif #ifdef KEEP_TASKS_GET if(benchmark_target == BENCHMARK_TASKPOOL) { recovered_tasks = (WORD*) malloc(no_tasks * sizeof(WORD)); } else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) { recovered_qes = (struct lfds711_queue_umm_element *) malloc(no_tasks * sizeof(struct lfds711_queue_umm_element)); } #endif // Taskpool init: if(benchmark_target == BENCHMARK_TASKPOOL) { pool = allocate_pool_with_tree_height(tree_height, no_tasks); set_no_trials(pool, k_retries); } // Liblfds queue init: else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) { lfds711_queue_umm_init_valid_on_current_logical_core(&qs, &qe_dummy, NULL); } else if(benchmark_target == BENCHMARK_LIBLFDS_RINGBUFFER) { re = (struct lfds711_ringbuffer_element *) malloc(sizeof(struct lfds711_ringbuffer_element) * ((ring_buffer_size) + 1)); lfds711_ringbuffer_init_valid_on_current_logical_core(&rs, re, (ring_buffer_size) + 1, NULL); } else if(benchmark_target == BENCHMARK_MUTEX || benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG || benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) { queue_head=NULL; queue_tail=NULL; if(benchmark_target == BENCHMARK_MUTEX) pthread_mutex_init(&queue_mutex, NULL); else if(benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) pthread_spin_init(&queue_spinlock_pthread, PTHREAD_PROCESS_SHARED); } pthread_t threads_put[no_threads]; pthread_t threads_get[no_threads]; pthread_attr_t attrs[no_threads]; cpu_set_t cpu_set[no_threads]; for(int th_id = 0; th_id < no_threads; ++th_id) { pthread_attr_init(&attrs[th_id]); CPU_ZERO(&cpu_set[th_id]); int core_id = (th_id % num_cpu) * (hyperthreading+1); if(verbose) printf("Setting thread affinity of thread %d to core %d\n", th_id, core_id); CPU_SET(core_id, &cpu_set[th_id]); #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) pthread_attr_setaffinity_np(&attrs[th_id], sizeof(cpu_set_t), &cpu_set[th_id]); #else printf("\x1b[41;1mSetting thread affinity is not implemented for your OS\x1b[m\n"); // __unix__ #endif } put_errs = (long *) malloc(no_threads * sizeof(long)); dequeued_elems = (long *) malloc(no_threads * sizeof(long)); int last_block_start = (benchmark_target == BENCHMARK_TASKPOOL)?(get_last_block_id(pool)):-1; GET_HIGHRES_TIME(&start_put); for(int th_id = 0; th_id < no_threads; ++th_id) { pthread_create(&threads_put[th_id], &attrs[th_id], thread_main_put, (void *) th_id); } for(int th_id = 0; th_id < no_threads; ++th_id) { pthread_join(threads_put[th_id], NULL); if(verbose) printf("[%d put] exited\n", th_id); } GET_HIGHRES_TIME(&end_put); start_get = end_put ; for(int th_id = 0; th_id < no_threads; ++th_id) { pthread_create(&threads_get[th_id], &attrs[th_id], thread_main_get, (void *) th_id); } for(int th_id = 0; th_id < no_threads; ++th_id) { pthread_join(threads_get[th_id], NULL); if(verbose) printf("[%d get] exited\n", th_id); } GET_HIGHRES_TIME(&end_get); total_get_errs = no_tasks; for(int th_id = 0; th_id < no_threads; ++th_id) { total_put_errs += put_errs[th_id]; total_get_errs -= dequeued_elems[th_id]; } int tree_degree_pool = (benchmark_target == BENCHMARK_TASKPOOL)?pool->degree:-1; int tree_height_pool = (benchmark_target == BENCHMARK_TASKPOOL)?pool->tree_height:-1; int k_retries_pool = (benchmark_target == BENCHMARK_TASKPOOL)?pool->k_no_trials:-1; int last_block_end = (benchmark_target == BENCHMARK_TASKPOOL)?get_last_block_id(pool):-1; int last_used_block = (benchmark_target == BENCHMARK_TASKPOOL)?pool->producer_tree->node_id:-1; int block_size = (benchmark_target == BENCHMARK_TASKPOOL)?(CALCULATE_TREE_SIZE(pool->tree_height, pool->degree)):-1; int block_fill = (benchmark_target == BENCHMARK_TASKPOOL)?(TREE_FILL_FACTOR(pool->tree_height, pool->degree, pool->k_no_trials)):-1; printf("data_struct=%s, no_tasks=%d, no_threads=%d, tree_degree=%d, tree_height=%d, k_retries=%d, ring_buffer_size=%ld, total_seconds_put=%f, total_seconds_get=%f, put_tpt=%f, put_latency_ns=%lld, get_tpt=%f, get_latency_ns=%lld, put_errs=%ld, get_errs=%ld, prealloc_blocks=%d, dynamicalloc_blocks=%d, unused_blocks=%d, block_size=%d, block_fill=%d\n", (benchmark_target == BENCHMARK_TASKPOOL)?"taskpool":((benchmark_target == BENCHMARK_LIBLFDS_QUEUE)?"lfds_queue":"lfds_ringbuffer"), no_tasks, no_threads, tree_degree_pool, tree_height_pool, k_retries_pool, ring_buffer_size, (end_put-start_put)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND, (end_get-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND, no_tasks / ((end_put-start_put)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND), (end_put-start_put) / no_tasks, (no_tasks-total_get_errs) / ((end_get-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND), (end_get-start_get) / (no_tasks-total_get_errs), total_put_errs, total_get_errs, last_block_start + 1, last_block_end - last_block_start, last_block_end - last_used_block, block_size, block_fill); if(benchmark_target == BENCHMARK_TASKPOOL) free_pool(pool); else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) lfds711_queue_umm_cleanup(&qs, NULL); else if(benchmark_target == BENCHMARK_LIBLFDS_RINGBUFFER) lfds711_ringbuffer_cleanup(&rs, NULL); free(put_errs); free(dequeued_elems); #ifdef KEEP_TASKS_PUT if(benchmark_target == BENCHMARK_TASKPOOL) free(tasks); else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) free(qes); else if(benchmark_target == BENCHMARK_MUTEX || benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG || benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) free(simple_qes); #endif #ifdef KEEP_TASKS_GET if(benchmark_target == BENCHMARK_TASKPOOL) free(recovered_tasks); else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) free(recovered_qes); else if(benchmark_target == BENCHMARK_MUTEX || benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG || benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) free(recovered_simple_qes); #endif } ================================================ FILE: workspace/concurrent_taskpool/tests_and_benchmarks/concurrent_task_pool_test_multithreaded_mixed.c ================================================ /* * Copyright (C) 2019-2021 Deutsche Telekom AG * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * A concurrent, scalable, wait-free task pool implementation that performs well under high CAS contention * * This file contains testing functions for pools * * Created on: 22 Jan 2019 * Author: aagapi */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "fastrand.h" #include "concurrent_task_pool.h" // For comparative benchmarking: #include #define NO_TASKS 10000 #define NO_THREADS 1 #define RING_BUFFER_SIZE 1000 #define DEFAULT_MAX_BENCHMARK_DURATION_SECONDS 60 // #define VERBOSE // #define KEEP_TASKS_PUT // #define KEEP_TASKS_GET #define BENCHMARK_TASKPOOL 0 #define BENCHMARK_LIBLFDS_QUEUE 1 #define BENCHMARK_LIBLFDS_RINGBUFFER 2 #define BENCHMARK_MUTEX 3 #define BENCHMARK_SPINLOCK_ATOMIC_FLAG 4 #define BENCHMARK_SPINLOCK_PTHREAD 5 int no_tasks = NO_TASKS, no_threads = NO_THREADS, tree_height = DEFAULT_TREE_HEIGHT, k_retries = DEFAULT_K_NO_TRIALS; long num_cpu, ring_buffer_size = RING_BUFFER_SIZE; int benchmark_target = BENCHMARK_TASKPOOL; int verbose = 0; long * put_errs, * dequeued_elems; int long long unsigned * last_dequeues; int benchmark_duration_seconds = DEFAULT_MAX_BENCHMARK_DURATION_SECONDS; #define NUMBER_OF_NANOSECONDS_IN_ONE_SECOND 1000000000LLU #if( defined _POSIX_THREADS && _POSIX_TIMERS >= 0 && _POSIX_MONOTONIC_CLOCK >= 0 ) #define TIME_UNITS_PER_SECOND( pointer_to_time_units_per_second ) *(pointer_to_time_units_per_second) = NUMBER_OF_NANOSECONDS_IN_ONE_SECOND #define GET_HIGHRES_TIME( pointer_to_time ) \ { \ struct timespec tp; \ clock_gettime( CLOCK_MONOTONIC_RAW, &tp ); \ *(pointer_to_time) = tp.tv_sec * NUMBER_OF_NANOSECONDS_IN_ONE_SECOND + tp.tv_nsec; \ } #define GET_LOWRES_LOWOVERHEAD_TIME_SECONDS( pointer_to_time ) \ { \ struct timespec tp; \ clock_gettime( CLOCK_MONOTONIC_COARSE, &tp ); \ *(pointer_to_time) = tp.tv_sec; \ } #else #error Linux without high resolution timers. #endif // Taskpool-related global vars: concurrent_pool * pool; WORD* tasks; struct lfds711_queue_umm_element *qes; WORD* recovered_tasks; struct lfds711_queue_umm_element *recovered_qes; // Liblfds queue-related global vars: struct lfds711_queue_umm_state qs; // Liblfds ringbuffer-related global vars: struct lfds711_ringbuffer_state rs; struct lfds711_ringbuffer_element * re; // Mutex-related: pthread_mutex_t queue_mutex; // Spinlock-related: volatile atomic_flag queue_spinlock_af; void inline spinlock_lock(volatile atomic_flag *f) { while (atomic_flag_test_and_set(f)) { // spin until we could set the flag } } void inline spinlock_unlock(volatile atomic_flag *f) { atomic_flag_clear(f); } // Libpthread spinlock-related: pthread_spinlock_t queue_spinlock_pthread; // Basic list structs for benchmarking mutexes & spinlocks: typedef struct queue_entry { WORD data; struct queue_entry * next; } queue_entry; queue_entry * queue_head, * queue_tail; queue_entry * simple_qes, * recovered_simple_qes; void *thread_main_put(void *arg) { int thread_id = (int) arg, status=0; int long long unsigned start_put, end_put; struct lfds711_queue_umm_element qe; struct lfds711_ringbuffer_element elem; enum lfds711_misc_flag overwrite_occurred_flag; unsigned int seed; GET_RANDSEED(&seed, thread_id); LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; if(verbose) { GET_HIGHRES_TIME(&start_put); printf("[thread %d put] start_time=%lld, no_tasks=%d\n", thread_id, start_put, 2*no_tasks/no_threads); } int first_task_index = thread_id*(2*no_tasks/no_threads); for(long i=first_task_index;inext = simple_qes + i; queue_tail = simple_qes + i; } else { queue_tail = simple_qes + i; queue_head = simple_qes + i; } #endif if(benchmark_target == BENCHMARK_MUTEX) pthread_mutex_unlock(&queue_mutex); else if(benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG) spinlock_unlock(&queue_spinlock_af); else if(benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) pthread_spin_unlock(&queue_spinlock_pthread); } if(status!=0) { put_errs[thread_id]++; if(verbose) printf("ERROR (thread %d - put): put() attempt %ld failed!\n", thread_id, i+1); } } if(verbose) { GET_HIGHRES_TIME(&end_put); printf("[thread %d put] no_tasks=%d, total_seconds_put=%f, put_tpt=%f, put_latency_ns=%lld\n", thread_id, 2*no_tasks/no_threads, (end_put-start_put)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND, (2*no_tasks/no_threads) / ((end_put-start_put)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND), ((end_put-start_put)) / (2*no_tasks/no_threads)); } return NULL; } void *thread_main_get(void *arg) { int thread_id = (int) arg; int status=0, prev_status=1; int long long unsigned start_get, end_get, last_dequeue=0; struct lfds711_queue_umm_element * qep; void *buffer_read_element; int dequeued_elements = 0; WORD recovered_task; queue_entry recovered_simple_qe; unsigned int seed; GET_RANDSEED(&seed, thread_id); LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; GET_HIGHRES_TIME(&start_get); if(verbose) { printf("[thread %d get] start_time=%lld, no_tasks=%d\n", thread_id, start_get, 2*no_tasks/no_threads); } do { if(benchmark_target == BENCHMARK_TASKPOOL) { #ifdef KEEP_TASKS_GET status = get(recovered_tasks + thread_id*(no_tasks/no_threads) + dequeued_elements, pool, &seed); #else status = get(&recovered_task, pool, &seed); #endif } else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) { #ifdef KEEP_TASKS_GET status = !lfds711_queue_umm_dequeue(&qs, &qep); recovered_tasks[thread_id*(no_tasks/no_threads) + dequeued_elements] = (WORD) LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT(*qep); #else status = !lfds711_queue_umm_dequeue(&qs, &qep); LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT(*qep); #endif } else if(benchmark_target == BENCHMARK_LIBLFDS_RINGBUFFER) { #ifdef KEEP_TASKS_GET status = !lfds711_ringbuffer_read(&rs, recovered_tasks + thread_id*(no_tasks/no_threads) + dequeued_elements, NULL); #else status = !lfds711_ringbuffer_read(&rs, &buffer_read_element, NULL); #endif } else if(benchmark_target == BENCHMARK_MUTEX || benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG || benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) { if(benchmark_target == BENCHMARK_MUTEX) pthread_mutex_lock(&queue_mutex); else if(benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG) spinlock_lock(&queue_spinlock_af); else if(benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) pthread_spin_lock(&queue_spinlock_pthread); if(queue_head != NULL) { #ifdef KEEP_TASKS_GET recovered_simple_qes[thread_id*(no_tasks/no_threads) + dequeued_elements].data = queue_head->data; #else recovered_simple_qe.data=queue_head->data; #endif queue_head = queue_head->next; if(queue_head == NULL) queue_tail = NULL; status = 0; } else { status = 1; } if(benchmark_target == BENCHMARK_MUTEX) pthread_mutex_unlock(&queue_mutex); else if(benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG) spinlock_unlock(&queue_spinlock_af); else if(benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) pthread_spin_unlock(&queue_spinlock_pthread); } if(status==0) { dequeued_elements++; } else { GET_HIGHRES_TIME(&end_get); if(prev_status==0) last_dequeue=end_get; if(((end_get - start_get) / NUMBER_OF_NANOSECONDS_IN_ONE_SECOND) > benchmark_duration_seconds) break; } prev_status = status; if(verbose) { int value=-1; if(status==0) { switch(benchmark_target) { case BENCHMARK_TASKPOOL: case BENCHMARK_LIBLFDS_QUEUE: case BENCHMARK_LIBLFDS_RINGBUFFER: #ifdef KEEP_TASKS_GET value = (int) recovered_tasks[thread_id*(no_tasks/no_threads) + dequeued_elements]; #else value = (int) recovered_task; #endif break; case BENCHMARK_MUTEX: case BENCHMARK_SPINLOCK_ATOMIC_FLAG: case BENCHMARK_SPINLOCK_PTHREAD: #ifdef KEEP_TASKS_GET value = (int) recovered_simple_qes[thread_id*(no_tasks/no_threads) + dequeued_elements].data; #else value = (int) recovered_simple_qe.data; #endif break; } printf("[thread %d get] got task %d\n", thread_id, value); } else { printf("[thread %d get] failed to get task %f ago, last dequeue %f ago, start_get=%lld, end_get=%lld, last_dequeue=%lld, dequeued_elements=%d\n", thread_id, (end_get-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND, (last_dequeue>0)?((last_dequeue-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND):-1, start_get, end_get, last_dequeue, dequeued_elements); } } } while(1); GET_HIGHRES_TIME(&end_get); dequeued_elems[thread_id]=dequeued_elements; last_dequeues[thread_id]=last_dequeue; if(verbose) { printf("[thread %d get] no_tasks=%d, total_seconds_get=%f, get_tpt=%f, get_latency_ns=%lld, quit_after=%f\n", thread_id, dequeued_elements, (dequeued_elements>0)?((last_dequeue-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND):-1, (dequeued_elements>0)?((no_tasks/no_threads) / ((last_dequeue-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND)):-1, (dequeued_elements>0)?(((last_dequeue-start_get)) / (no_tasks/no_threads)):-1, (end_get-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND); } return NULL; } int main(int argc, char **argv) { struct lfds711_queue_umm_element qe_dummy; int status = 0, opt, n; long total_put_errs = 0, total_get_errs = 0; int long long unsigned start_put, end_put, start_get, end_get, start_prealloc, end_prealloc; char * struct_type = "NA"; int alternate_prod_cons_placement = 0; while ((opt = getopt(argc, argv, "t:h:k:T:B:R:M:av")) != -1) { switch (opt) { case 't': { n = atoi(optarg); no_tasks = (n>0)?n:NO_TASKS; break; } case 'h': { n = atoi(optarg); tree_height = (n>0)?n:DEFAULT_TREE_HEIGHT; break; } case 'k': { n = atoi(optarg); k_retries = (n>0)?n:DEFAULT_K_NO_TRIALS; break; } case 'T': { n = atoi(optarg); no_threads = (n>0)?n:NO_THREADS; break; } case 'B': { switch(optarg[0]) { case 'Q': { benchmark_target = BENCHMARK_LIBLFDS_QUEUE; struct_type = "lfds_queue"; break; } case 'R': { benchmark_target = BENCHMARK_LIBLFDS_RINGBUFFER; struct_type = "lfds_ringbuffer"; break; } case 'M': { benchmark_target = BENCHMARK_MUTEX; struct_type = "pthread_mutex"; break; } case 'A': { benchmark_target = BENCHMARK_SPINLOCK_ATOMIC_FLAG; struct_type = "atomic_flag_spinlock"; break; } case 'S': { benchmark_target = BENCHMARK_SPINLOCK_PTHREAD; struct_type = "pthread_spinlock"; break; } case 'T': default: { benchmark_target = BENCHMARK_TASKPOOL; struct_type = "taskpool"; } } break; } case 'R': { n = atoi(optarg); ring_buffer_size = (n>0)?n:RING_BUFFER_SIZE; break; } case 'M': { n = atoi(optarg); benchmark_duration_seconds = (n>0)?n:DEFAULT_MAX_BENCHMARK_DURATION_SECONDS; break; } case 'a': { alternate_prod_cons_placement = 1; break; } case 'v': { verbose = 1; break; } } } num_cpu = sysconf(_SC_NPROCESSORS_ONLN); // Detect if we have hyperthreading: u_int32_t registers[4]; __asm__ __volatile__ ("cpuid " : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) : "a" (1), "c" (0)); unsigned CPUFeatureSet = registers[3]; unsigned char hyperthreading = CPUFeatureSet & (1 << 28); hyperthreading=0; // Assume no hyperthreading if(verbose) printf("Detected num_cpu=%ld, hyperthreading=%d\n", num_cpu, hyperthreading); #ifdef KEEP_TASKS_PUT if(benchmark_target == BENCHMARK_TASKPOOL) { tasks = (WORD*) malloc(no_tasks * sizeof(WORD)); } else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) { qes = (struct lfds711_queue_umm_element *) malloc(no_tasks * sizeof(struct lfds711_queue_umm_element)); } else if(benchmark_target == BENCHMARK_MUTEX || benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG || benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) { simple_qes = (queue_entry *) malloc(no_tasks * sizeof(struct queue_entry)); } #endif #ifdef KEEP_TASKS_GET if(benchmark_target == BENCHMARK_TASKPOOL) { recovered_tasks = (WORD*) malloc(no_tasks * sizeof(WORD)); } else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) { recovered_qes = (struct lfds711_queue_umm_element *) malloc(no_tasks * sizeof(struct lfds711_queue_umm_element)); } else if(benchmark_target == BENCHMARK_MUTEX || benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG || benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) { recovered_simple_qes = (queue_entry *) malloc(no_tasks * sizeof(struct queue_entry)); } #endif GET_HIGHRES_TIME(&start_prealloc); // Taskpool init: if(benchmark_target == BENCHMARK_TASKPOOL) { pool = allocate_pool_with_tree_height(tree_height, no_tasks); set_no_trials(pool, k_retries); } // Liblfds queue init: else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) { lfds711_queue_umm_init_valid_on_current_logical_core(&qs, &qe_dummy, NULL); } else if(benchmark_target == BENCHMARK_LIBLFDS_RINGBUFFER) { re = (struct lfds711_ringbuffer_element *) malloc(sizeof(struct lfds711_ringbuffer_element) * ((ring_buffer_size) + 1)); lfds711_ringbuffer_init_valid_on_current_logical_core(&rs, re, (ring_buffer_size) + 1, NULL); } else if(benchmark_target == BENCHMARK_MUTEX || benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG || benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) { queue_head=NULL; queue_tail=NULL; if(benchmark_target == BENCHMARK_MUTEX) pthread_mutex_init(&queue_mutex, NULL); else if(benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) pthread_spin_init(&queue_spinlock_pthread, PTHREAD_PROCESS_SHARED); } GET_HIGHRES_TIME(&end_prealloc); pthread_t threads_put[no_threads/2]; pthread_t threads_get[no_threads/2]; pthread_attr_t attrs[no_threads]; cpu_set_t cpu_set[no_threads]; for(int th_id = 0; th_id < no_threads; ++th_id) { pthread_attr_init(&attrs[th_id]); CPU_ZERO(&cpu_set[th_id]); int core_id; if(alternate_prod_cons_placement) { if(th_id end_get && dequeued_elems[th_id] > 0) end_get = last_dequeues[th_id]; } int tree_degree_pool = (benchmark_target == BENCHMARK_TASKPOOL)?pool->degree:-1; int tree_height_pool = (benchmark_target == BENCHMARK_TASKPOOL)?pool->tree_height:-1; int k_retries_pool = (benchmark_target == BENCHMARK_TASKPOOL)?pool->k_no_trials:-1; int last_block_end = (benchmark_target == BENCHMARK_TASKPOOL)?get_last_block_id(pool):-1; int last_used_block = (benchmark_target == BENCHMARK_TASKPOOL)?pool->producer_tree->node_id:-1; int block_size = (benchmark_target == BENCHMARK_TASKPOOL)?(CALCULATE_TREE_SIZE(pool->tree_height, pool->degree)):-1; int block_fill = (benchmark_target == BENCHMARK_TASKPOOL)?(TREE_FILL_FACTOR(pool->tree_height, pool->degree, pool->k_no_trials)):-1; printf("data_struct=%s, no_tasks=%d, no_threads=%d, tree_degree=%d, tree_height=%d, k_retries=%d, ring_buffer_size=%ld, total_seconds_put=%f, total_seconds_get=%f, put_tpt=%f, put_latency_ns=%lld, get_tpt=%f, get_latency_ns=%lld, put_errs=%ld, get_errs=%ld, prealloc_blocks=%d, dynamicalloc_blocks=%d, unused_blocks=%d, block_size=%d, block_fill=%d, total_seconds_prealloc=%f\n", struct_type, no_tasks, no_threads/2, tree_degree_pool, tree_height_pool, k_retries_pool, ring_buffer_size, (end_put-start_put)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND, (end_get-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND, no_tasks / ((end_put-start_put)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND), (end_put-start_put) / no_tasks, (no_tasks-total_get_errs) / ((end_get-start_get)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND), (no_tasks>total_get_errs)?((end_get-start_get) / (no_tasks-total_get_errs)):-1, total_put_errs, total_get_errs, last_block_start + 1, last_block_end - last_block_start, last_block_end - last_used_block, block_size, block_fill, (end_prealloc-start_prealloc)/(double)NUMBER_OF_NANOSECONDS_IN_ONE_SECOND); if(benchmark_target == BENCHMARK_TASKPOOL) free_pool(pool); else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) lfds711_queue_umm_cleanup(&qs, NULL); else if(benchmark_target == BENCHMARK_LIBLFDS_RINGBUFFER) lfds711_ringbuffer_cleanup(&rs, NULL); free(put_errs); free(dequeued_elems); free(last_dequeues); #ifdef KEEP_TASKS_PUT if(benchmark_target == BENCHMARK_TASKPOOL) free(tasks); else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) free(qes); else if(benchmark_target == BENCHMARK_MUTEX || benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG || benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) free(simple_qes); #endif #ifdef KEEP_TASKS_GET if(benchmark_target == BENCHMARK_TASKPOOL) free(recovered_tasks); else if(benchmark_target == BENCHMARK_LIBLFDS_QUEUE) free(recovered_qes); else if(benchmark_target == BENCHMARK_MUTEX || benchmark_target == BENCHMARK_SPINLOCK_ATOMIC_FLAG || benchmark_target == BENCHMARK_SPINLOCK_PTHREAD) free(recovered_simple_qes); #endif } ================================================ FILE: workspace/micke/Makefile ================================================ DEBUG ?= 0 # jemalloc is faster so let's use it by default (if it's found) USE_JEM ?= 1 CC := cc CXX := c++ CFLAGS := -std=c11 -Wall -Werror -pedantic -pedantic-errors CXXFLAGS := -std=c++11 -Wall -Werror -pedantic -pedantic-errors LDFLAGS := ifeq ($(DEBUG), 1) CFLAGS += -g -DDEBUG CXXFLAGS += -g -DDEBUG else CFLAGS += -O3 -DNDEBUG CXXFLAGS += -O3 -DNDEBUG endif ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1) LDFLAGS += -fuse-ld=bfd endif # there's no pkg-config ?? JEM_LIB?=$(wildcard /usr/lib/x86_64-linux-gnu/libjemalloc.a) ifeq ($(USE_JEM), 1) ifeq ($(JEM_LIB),) $(error jemalloc library not in assumed location, use JEM_LIB=) endif $(info Using jemalloc: $(JEM_LIB)) CFLAGS += -DUSE_JEMALLOC LDFLAGS += $(JEM_LIB) endif # for e.g. clock_gettime CFLAGS += -D_GNU_SOURCE -D_XOPEN_SOURCE=600 PQUEUE_LIB := ../deps/libpqueue/libpqueue.a all: bvtest %.o: %.c $(CC) $(CFLAGS) -c -o $@ $^ bvtest: bytesview_test.o bytesview.o $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ .PHONY: test test: @make -C test clean: rm -f *.a *.o rm -f bvtest .PHONY: help help: @echo "Targets:" @echo " all Same as `kernel`" @echo " kernel Build the kernel (test program)" @echo " test_io Testing program of IO polling" @echo " clean Do some cleaning" @echo "Options:" @echo " USE_JEM=1 Use jemalloc (default: on)" @echo " requires a jemalloc .so or .a file (use JEM_LIB=...)" ================================================ FILE: workspace/micke/bytesview.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* bytesview.c */ #include #include #include #include #include #include "bytesview.h" bytesview_t const _empty = { ._pre = NULL, ._eof = 0, .buf = { ._start = 0, ._end = 0, ._bytes = (uint8_t *) ""} }; act_bv_method_table_t *_bv_meth; /* ### creation ### */ bytesview_t const *act_bv_init (const uint8_t *b, size_t n, size_t start, const bytesview_t *pre, int closed) { size_t len; bytesview_t *bv = (bytesview_t *) malloc(sizeof(bytesview_t)); bv->_pre = (bytesview_t *) pre; /* disable warning: discards const qualifier */ bv->_eof = closed; if (start >= 0) { bv->buf._start = start; } else { bv->buf._start = 0; } if (n >= 0) { bv->buf._end = bv->buf._start+n; } else { len = strlen((char *) b); bv->buf._end = len - bv->buf._start; } bv->buf._bytes = (uint8_t *) b; /* disable warning: discards const qualifier */ return bv; } bytesview_t const *act_bv_empty() { return &_empty; } bytesview_t const *act_bv_fromstr (char const *s) { return act_bv_init((uint8_t const *)s, strlen(s), 0, NULL, 0); } bytesview_t const *act_bv_frombuf(bytesview_data_buffer_t const *buf) { bytesview_t *bv = (bytesview_t *) malloc(sizeof(bytesview_t)); bv->_pre = NULL; bv->_eof = 0; bv->buf._start = buf->_start; bv->buf._end = buf->_end; bv->buf._bytes = buf->_bytes; return bv; } /* ### analysis ### */ size_t act_bv_n(bytesview_t const *self) { size_t prelen; if (self->_pre == NULL) { prelen = 0; } else { prelen = act_bv_n(self->_pre); } return prelen + self->buf._end - self->buf._start; } static uint8_t *act_bv_cpybuf(bytesview_t const *self, uint8_t *p) { /* copy all bytes to *p */ uint8_t *q; size_t thislen; if (self->_pre != NULL) { q = act_bv_cpybuf(self->_pre, p); } else { q = p; } thislen = self->buf._end - self->buf._start; memcpy(q, self->buf._bytes+self->buf._start, thislen); return q+thislen; } bytesview_data_buffer_t const *act_bv_tobuf(bytesview_t const *self) { size_t n = act_bv_n(self); bytesview_data_buffer_t *p; #if NDEBUG #else uint8_t *q; #endif if (self->buf._end - self->buf._start == n) { /* no more than one buffer */ p = (bytesview_data_buffer_t *) &(self->buf); } else { /* several buffers, must concatenate */ p = (bytesview_data_buffer_t *) malloc(sizeof(bytesview_data_buffer_t)); p->_bytes = (uint8_t *) malloc (n); #if NDEBUG act_bv_cpybuf(self, p->_bytes); #else q = act_bv_cpybuf(self, p->_bytes); assert(q-p->_bytes == n); #endif p->_start = 0; p->_end = n; } return p; } char *act_bv_tostr(bytesview_t const *self) { size_t n = act_bv_n(self); uint8_t *p, *q; p = (uint8_t *) malloc(n+1); /* room for NUL character at end */ q = act_bv_cpybuf(self, p); assert(q-p == n); *q = 0; /* NUL character at end */ return (char *) p; } int act_bv_at_eof (const bytesview_t *self) { return self->_eof; } /* ### de-lousing */ void act_bv_showbuf(const bytesview_data_buffer_t *buf) { size_t i; size_t thislen; uint8_t *p; thislen = buf->_end - buf->_start; p = buf->_bytes+buf->_start; printf("[%lu,%lu] b'", buf->_start, buf->_end); i = 0; while (i++ < thislen) { printf("%c", *p++); } printf("'\n"); } void act_bv_show(const bytesview_t *self) { if (self == NULL) return; act_bv_show(self->_pre); printf("_eof=%d - buf= ", self->_eof); act_bv_showbuf(&self->buf); } void raise_IncompleteReadError(char *msg) { fprintf(stderr, "IncompleteReadError: %s\n", msg); // assert(0==1); } void raise_IndexError(char *msg) { fprintf(stderr, "IndexError: %s\n", msg); // assert(0==1); } void raise_ValueError(char *msg) { fprintf(stderr, "ValueError: %s\n", msg); // assert(0==1); } /* ### consuming data */ void act_bv__consume(bytesview_t const *self, int amount, bytesview_t const **prep, size_t *remainingp) { bytesview_t const *pre; bytesview_t const *newthis; size_t remaining, newremaining; size_t thislen; if (self->_pre != NULL) { act_bv__consume(self->_pre, amount, &pre, &remaining); } else { pre = NULL; remaining = amount; } thislen = self->buf._end - self->buf._start; if (remaining < thislen) { newthis = act_bv_init(self->buf._bytes, thislen-remaining, self->buf._start+remaining, pre, self->_eof); newremaining = 0; } else { newthis = pre; newremaining = remaining - thislen; } *prep = newthis; *remainingp = newremaining; return; } bytesview_t const *act_bv_consume(bytesview_t const *self, size_t amount) { bytesview_t const *newview; size_t remaining; act_bv__consume(self, amount, &newview, &remaining); if (remaining > 0) { raise_IndexError("Not enough data to consume"); return NULL; } if (newview != NULL) { return newview; } else { return act_bv_empty(); } } void act_bv__read(bytesview_t const *self, int n, int *remainingp, bytesview_t const **initialp) { bytesview_t const *initial; int remaining; size_t thislen; assert(n>=0); if (self->_pre != NULL) { act_bv__read(self->_pre, n, &remaining, &initial); } else { remaining = n; initial = NULL; } thislen = self->buf._end-self->buf._start; if (remaining == 0) { *remainingp = remaining; *initialp = initial; } else if (remaining >= thislen) { *remainingp = remaining-thislen; *initialp = self; } else { /* 0 < remaining < thislen */ *remainingp = 0; *initialp = act_bv_init(self->buf._bytes, remaining, self->buf._start, initial, 0); } return; } bytesview_t const *act_bv_read(bytesview_t const *self, size_t n) { bytesview_t const *initial; int remaining; int thislen; if (n == -1) { if (!self->_eof) { raise_IncompleteReadError("read(-1) on non-closed Bytesview"); return NULL; } else { return (bytesview_t *) self; } } else { /* deliver n bytes, if there are n bytes. * if not, deliver available bytes if closed, error if not closed */ thislen = self->buf._end - self->buf._start; if (self->_pre != NULL) { act_bv__read(self->_pre, n, &remaining, &initial); } else { remaining = n; initial = NULL; } if (remaining == 0) { if (initial != NULL) { return initial; } else { return act_bv_empty(); } } else if (remaining < thislen) { return act_bv_init(self->buf._bytes, remaining, self->buf._start, initial, 0); } else if (remaining > thislen) { if (self->_eof) return (bytesview_t *) self; else raise_IncompleteReadError("read(n) on non-closed Bytesview with less than n bytes"); return NULL; } else { /* remaining == thislen */ return (bytesview_t *) self; } } } bytesview_t const *act_bv_readline(bytesview_t const *self) { return act_bv_readuntil(self, "\n"); } static void act_bv__readexactly(bytesview_t const *self, size_t n, bytesview_t const **initialp, size_t *remainsp) { bytesview_t const *initial; size_t remains, thislen; thislen = self->buf._end - self->buf._start; if (self->_pre != NULL) { act_bv__readexactly(self->_pre, n, &initial, &remains); } else { initial = NULL; remains = n; } if (remains == 0) { *initialp = initial; *remainsp = remains; } else if (remains >= thislen) { *initialp = (bytesview_t *) self; *remainsp = remains - thislen; } else { /* remains < thislen */ *initialp = act_bv_init(self->buf._bytes, remains, self->buf._start, initial, 0); *remainsp = 0; } } bytesview_t const *act_bv_readexactly(const bytesview_t *self, size_t n) { bytesview_t const *initial; size_t remains; act_bv__readexactly(self, n, &initial, &remains); if (remains > 0) { raise_IncompleteReadError("readexactly(): Too few bytes available"); return NULL; } if (initial == NULL) { initial = act_bv_empty(); } return initial; } static size_t act_bv_min(size_t a, size_t b) { if (a <= b) return a; else return b; } static int act_bv__readuntil(bytesview_t const *self, void const *separator, size_t seplen, bytesview_data_buffer_t *last, bytesview_t const ** initialp) { bytesview_t const *initial; int found; uint8_t *m; size_t idx, lastlen, cpylen, thislen, keeplen; if (self->_pre != NULL) { found = act_bv__readuntil(self->_pre, separator, seplen, last, &initial); } else { /* last initialized in act_bv_readuntil() */ initial = NULL; found = 0; //printf("-"); } // last is potential beginning of separator at end of previous buffer(s) if (found) { /* last made empty in recursive call */ *initialp = initial; return found; } //printf("-\n"); /* still looking - is separator straddling buffers? */ lastlen = last->_end - last->_start; thislen = self->buf._end - self->buf._start; cpylen = act_bv_min(seplen-1, thislen); memcpy(last->_bytes+last->_end, self->buf._bytes+self->buf._start, cpylen); lastlen = last->_end += cpylen; /* now, last contains last part of previous plus first part of this */ //printf("lastlen = %ld, cpylen = %ld\n", lastlen, cpylen); //printf("last: "); //act_bv_showbuf(last); if (lastlen >= seplen) { // might be straddling, check! m = (uint8_t *) strstr((const char *)last->_bytes+last->_start, separator); if (m != NULL) { found = 1; idx = m - (last->_bytes+last->_start); //printf("straddling! idx=%ld cpylen=%ld last: [%ld, %ld]\n", idx, cpylen, last->_start, last->_end); // end of separator at idx + seplen - len(last) *initialp = act_bv_init(self->buf._bytes, cpylen-(last->_end-(idx+seplen)), self->buf._start, self->_pre, 0); // last->_start = last->_end = 0; return found; } } /* Nope, so search this buffer */ m = memmem(self->buf._bytes+self->buf._start, self->buf._end-self->buf._start, separator, seplen); if (m != NULL) { found = 1; idx = m - (self->buf._bytes + self->buf._start); //printf("inbuf [%ld, %ld]: idx == %ld\n", self->buf._start, self->buf._end, idx); *initialp = act_bv_init(self->buf._bytes, idx+seplen, self->buf._start, self->_pre, 0); return found; } /* Nope, so return last part of this buffer in case separator is straddling */ found = 0; if (thislen >= seplen-1) { /* discard old contents of last */ last->_start = 0; last->_end = seplen-1; memcpy(last->_bytes, self->buf._bytes+self->buf._end-(seplen-1), seplen-1); *(last->_bytes+last->_end) = 0; } else { /* entire this is in last, so just keep end of last */ keeplen = act_bv_min(seplen-1, lastlen); if (keeplen < lastlen) { // move end of last up front memcpy(last->_bytes, last->_bytes+last->_end-keeplen, keeplen); last->_start = 0; last->_end = keeplen; *(last->_bytes+last->_end) = 0; } else { /* keep all of last */ } } *initialp = self; return found; } bytesview_t const *act_bv_readuntil(bytesview_t const *self, void const *separator) { bytesview_data_buffer_t buf, *last; size_t seplen; bytesview_t const *initial; int found; seplen = strlen(separator); last = &buf; last->_start = 0; last->_end = 0; last->_bytes = (uint8_t *) malloc (seplen + seplen -1); // room for (seplen-1)*2 bytes + nul byte *(last->_bytes) = 0; found = act_bv__readuntil(self, separator, seplen, last, &initial); if (found) { if (initial != NULL) { return initial; } else { return act_bv_empty(); } } else { if (self->_eof) { raise_IncompleteReadError("Separator not found and Bytesview closed"); return NULL; } else { raise_IncompleteReadError("Separator not found"); return NULL; } } } /* ### feeding data & closing */ bytesview_t const *act_bv_append(bytesview_t const *self, void const *b, size_t n) { if (self->_eof) { raise_ValueError("append() on closed Bytesview"); return NULL; } if (self->buf._start < self->buf._end) { return act_bv_init(b, n, 0, self, 0); } else { return act_bv_init(b, n, 0, NULL, 0); } } bytesview_t const *act_bv_write(bytesview_t const *self, void const *b, size_t n) { if (self->_eof) { raise_ValueError("write() on closed Bytesview"); return NULL; } return act_bv_append(self, b, n); } bytesview_t const *act_bv_writelines(bytesview_t const *self, void const **data) { if (self->_eof) { raise_ValueError("writelines() on closed Bytesview"); } /* XXX */ assert(0); return act_bv_empty(); } bytesview_t const *act_bv_close (bytesview_t const *self) { if (self->_eof) return (bytesview_t *) self; /* disable warning: discards const qualifier */ return act_bv_init(self->buf._bytes, self->buf._end-self->buf._start, self->buf._start, self->_pre, 1); } /* method table */ act_bv_method_table_t _act_bv_method_table = { .init = act_bv_init, .empty = act_bv_empty }; void act_bv_class_init() { _bv_meth = & _act_bv_method_table; } ================================================ FILE: workspace/micke/bytesview.h ================================================ /* bytesview.h */ /* C version of bytesview */ #include #include #define ACT_BV_DEFAULT_BUFFER_SIZE 8192 typedef struct { size_t _start; size_t _end; uint8_t *_bytes; /* will usually have size ACT_BV_DEFAULT_BUFFER_SIZE */ } bytesview_data_buffer_t; typedef struct bytesview_t { struct bytesview_t *_pre; int _eof; bytesview_data_buffer_t buf; } bytesview_t; extern void act_bv_class_init(); /* ### Creation ### */ bytesview_t const *act_bv_init(uint8_t const *b, size_t n, size_t start, const bytesview_t *pre, int closed); bytesview_t const *act_bv_empty(); bytesview_t const *act_bv_frombuf(bytesview_data_buffer_t const *buf); bytesview_t const *act_bv_fromstr(char const *s); /* ### Analysis ### */ size_t act_bv_n(bytesview_t const *self); bytesview_data_buffer_t const *act_bv_tobuf(bytesview_t const *self); /* return value SHOULD NOT be mutated */ char *act_bv_tostr(bytesview_t const *self); /* return value SHOULD NOT be mutated */ int act_bv_at_eof (bytesview_t const *self); /* ### De-lousing ### */ void act_bv_show(bytesview_t const *self); void act_bv_showbuf(bytesview_data_buffer_t const *buf); void raise_IncompleteReadError(char *msg); void raise_IndexError(char *msg); void raise_ValueError(char *msg); /* ### Consuming data ### */ bytesview_t const *act_bv_consume(bytesview_t const *self, size_t amount); bytesview_t const *act_bv_read(bytesview_t const *self, size_t n); bytesview_t const *act_bv_readline(bytesview_t const *self); bytesview_t const *act_bv_readexactly(bytesview_t const *self, size_t n); bytesview_t const *act_bv_readuntil(bytesview_t const *self, void const *separator); /* ### Adding data ### */ bytesview_t const *act_bv_append(bytesview_t const *self, void const *b, size_t n); bytesview_t const *act_bv_write(bytesview_t const *self, void const *b, size_t n); bytesview_t const *act_bv_writelines(bytesview_t const *self, void const **data); bytesview_t const *act_bv_close (bytesview_t const *self); typedef int (*BV_INT_T)(int); typedef bytesview_t const * (*BYTESVIEW_INIT_T)(const uint8_t *b, size_t n, size_t start, bytesview_t const *pre, int closed); typedef bytesview_t const * (*BYTESVIEW_EMPTY_T)(bytesview_t const *self); typedef bytesview_t const * (*BYTESVIEW_FROMBUF_T)(bytesview_data_buffer_t const *buf); typedef bytesview_t const * (*BYTESVIEW_FROMSTR_T)(char const *s); typedef struct { BV_INT_T intfunc; BYTESVIEW_INIT_T init; /* = act_bv_init; */ BYTESVIEW_EMPTY_T empty; /* = act_bv_empty; */ BYTESVIEW_FROMBUF_T frombuf; /* = act_bv_frombuf; */ } act_bv_method_table_t; ================================================ FILE: workspace/micke/bytesview.py ================================================ # Copyright (C) 2019-2021 Data Ductus AB # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Python version of bytesview ################################################## ### Bytesview class Bytesview(): _bytes : bytes = None _pre = None _start : int = 0 _end : int = 0 _eof : bool = False def __init__(self, b, n=None, start=None, pre=None, closed=False): self._bytes = b self._pre = pre self._start = 0 if start is None else start if n is not None: self._end = self._start + n else: self._end = len(b)-self._start self._eof = closed ### analysis of Bytesview objects def n(self): return self._end - self._start + (self._pre.n() if self._pre is not None else 0) def to_bytes(self): these = self._bytes[self._start:self._end] if self._pre is None: return these else: return self._pre.to_bytes() + these ### de-lousing def show(self): if self._pre is not None: self._pre.show() print(self._bytes, "[{}:{}]".format(self._start,self._end)) if self._eof: print("_eof = {}".format(self._eof)) ### consuming data def _consume(self, amount): if self._pre is not None: (pre, remaining) = self._pre._consume(amount) else: pre = None remaining = amount thislen = self._end - self._start if remaining < thislen: newthis = Bytesview(self._bytes, n=thislen-remaining, start=self._start+remaining, pre=pre) newremaining = 0 else: newthis = pre newremaining = remaining - thislen return(newthis,newremaining) def consume(self, amount): # assert(self.n()>=amount) (newview, remaining) = self._consume(amount) if remaining > 0: # raise IndexError return None if newview is not None: return newview else: return Bytesview(b'') # def _initialbytes(self, amount=a, end=-1, endskip=0): # # # def initialbytes(self, end=-1, endskip=0): # # remove data at end of bytesview. # # # # end == -1 implies trimming from eof (so error if -1 and not closed) # # end >= 0 implies end-endskip is the index where returned bytesview object ends. # # remove endskip bytes before end. # if end == -1 and not self._eof: # raise ValueError("Trim(end=-1) on non-closed Bytesview") # # if self._pre is None: # # thislen = self._end - self._start # thislen -= # if self._pre is None: # newstartskip = startskip # newend = end # newenskip = endskip # return Bytesview(self._bytes, start=self._start+ # else: # # if start is None: # if end is None or end == -1: # these = self._bytes[self._start:self._end] # else: # these = self._bytes[self._start:self._start+end] # else: # if end is None or end == -1: # these = self._bytes[self._start+start:self._end] # else: # these = self._bytes[self._start+start:self._start+end] # if self._pre is None: # return these # else: # return self._pre.to_bytes() + these ### reading out data from a Bytesview object (creating a new) ### ### Raises IncompleteReadError if Bytesview object does not contain ### enough data to fulfill request. def _read(self, n): # n is always >= 0 if self._pre is not None: (remaining, initial) = self._pre._read(n) else: remaining = n initial = None thislen = self._end - self._start if remaining == 0: return (remaining,initial) elif remaining >= thislen: return (remaining-thislen, self) else: # 0 < remaining < thislen return (0, Bytesview(self._bytes, start=self._start, n=remaining, pre=initial)) def read(self, n=-1): # (int) -> (bytes, Bytesview) if n == -1: if not self._eof: raise IncompleteReadError("read(-1) on non-closed Bytesview") return None else: return self else: # deliver n bytes, if there are n bytes. # if not, deliver available bytes if closed, error if not closed thislen = self._end - self._start if self._pre is not None: (remaining, initial) = self._pre._read(n) else: remaining = n initial = None if remaining == 0: return initial if initial is not None else Bytesview(b'') elif remaining < thislen: return Bytesview(self._bytes, n=remaining, start=self._start, pre=initial) elif remaining > thislen: if self._eof: return self else: #raise IncompleteReadError("read(n) on non-closed Bytesview with less than n bytes") return None else: # remaining == thislen return self def readline(self): return self.readuntil (separator=b'\n') def _readexactly(self, n): thislen = self._end - self._start if self._pre: (initial, remains) = self._pre._readexactly(n) else: (initial, remains) = (None, n) if remains == 0: return (initial, remains) elif remains >= thislen: return (self, remains-thislen) else: # remains < thislen return (Bytesview(self._bytes, start=self._start, n=remains, pre=initial), 0) def readexactly(self, n): (initial, remains) = self._readexactly(n) if remains > 0: #raise IncompleteReadError("readexactly(): Too few bytes available") return None if initial is None: initial = Bytesview(b'') return initial def _readuntil(self, separator, seplen): # len(last) < len(separator) if self._pre is not None: (last, initial, found) = self._pre._readuntil(separator, seplen) else: (last, initial, found) = (b'', None, False) # last is potential beginning of separator at end of previous Bytesview(s) if found: return (b'',initial, found) else: buf = last+self._bytes[self._start:self._start+seplen-1] idx = buf.find(separator) if idx >= 0: # found it! # end of separator at ix+seplen-len(last) #print (buf, len(buf), last, len(last), sep, idx) return (b'', Bytesview(self._bytes, n=idx+seplen-len(last), start=self._start, pre=self._pre), True) idx = self._bytes.find(separator, self._start) if idx >= 0: # found it! return (b'', Bytesview(self._bytes, n=idx-self._start+seplen, start=self._start, pre=self._pre), True) thislen = self._end-self._start if thislen >= seplen-1: last = self._bytes[self._end-(seplen-1):self._end] else: last = last[thislen-(seplen-1):] + self._bytes[self._start:self._end] return (last, self, False) def readuntil(self, separator=b'\n'): seplen = len(separator) (_, initial, found) = self._readuntil(separator, seplen) if found: return initial if initial is not None else Bytesview(b'') else: if self._eof: #raise IncompleteReadError("Separator not found and Bytesview closed") return None else: #raise IncompleteReadError("Separator not found") return None def at_eof(self): return self._eof and self._pre is None and self._start == self._end ### feeding data & closing def append(self, b, n=None): if self._eof: #raise ValueError("append() on closed Bytesview") return None if self._start < self._end: return Bytesview(b, n=n, pre=self) else: return Bytesview(b, n=n) def write(self, b, n=None): # same as append(self, b, n=None) if self._eof: #raise ValueError("write() on closed Bytesview") return None return self.append(b, n) def writelines(self,data): if self._eof: #raise ValueError("writelines() on closed Bytesview") return None for b in data: self.append(b) def close(self): if self._eof: return self return Bytesview(self._bytes, n=self._end-self._start, start=self._start, pre=self._pre, closed=True) ################################################## ### Unit tests def report(bv, name): print (name+" = ", bv) print (name+".n() = ", bv.n()) # print (name+"limits() = ", bv.limits()) print (name+".to_bytes() = ", bv.to_bytes()) print (name+".show():") bv.show() by = b'0123456789abcdef' #l = len(by) #print("by = ",by) #print("l = ", l) # #bv1 = Bytesview(by) #bv2 = Bytesview(by, n=16) # #report(bv1, "bv1") #report(bv2, "bv2") bv3 = bv2.append(by, n=16) #report(bv2, "bv2") #report(bv3, "bv3") bv4 = bv3.append(by) #report(bv4,"bv4") #bv = bv4 #n=0 #while True: # res = bv.consume(n) # print("") # res.show() # #print(res.to_bytes()) # n += 1 ########### ### read() # #bv = bv4 #n=0 #while True: # res = bv.read(n) # print("") # res.show() # #print(res.to_bytes()) # n += 1 #print("read() test") #bv = bv4 #n=0 #while n < 60: # res = bv.read(n) # print(res.to_bytes()) # n += 1 #bv = bv4.close() #print("bv length: ", bv.n()) # #n=0 #while n < 60: # res = bv.read(n) # print(res.to_bytes()) # n += 1 #bv = bv4.close() #print("bv length: ", bv.n()) # #n=0 #while n < 60: # res = bv.read(n) # print(res.to_bytes()) # res.show() # n += 1 ########### ### readuntil() # #separators = by+b'x'+by+b'y'+by+b'z'+by+b'w' #bv = Bytesview(by+b'x').append(by+b'y').append(by+b'z').append(by) #bv.close() #print("bv length: ", bv.n()) # #n=0 #while n < 4*16+3+5: # sep = separators[n:n+7] # res = bv.readuntil(separator=sep) # print(sep, " ", res.to_bytes()) # res.show() # n += 1 def bv_list(bv=None): bvl = bv if bv is not None else Bytesview(b'') n = 0 while n < 16: bvl = bvl.append(by[n:n+1]) n += 1 return bvl bvl = bv_list().append(b'x') bvl = bv_list(bvl).append(b'y') bvl = bv_list(bvl).append(b'z') bvl = bv_list(bvl) print ("bvl: ", bvl.to_bytes()) bvl.show() #bv.close() print("bv length: ", bvl.n()) separators = by+b'x'+by+b'y'+by+b'z'+by+b'w' n=0 while n < 4*16+3+5: sep = separators[n:n+7] res = bvl.readuntil(separator=sep) print(sep, " ", res.to_bytes()) res.show() n += 1 ########### ### readexactly() # #bv = Bytesview(by+b'x').append(by+b'y').append(by+b'z').append(by) #bv.close() #print("bv length: ", bv.n()) # #n=0 #while n < 4*16+3+5: # res = bv.readexactly(n) # print(res.to_bytes()) # #res.show() # n += 1 # ================================================ FILE: workspace/micke/bytesview_test.c ================================================ /* * Copyright (C) 2019-2021 Data Ductus AB * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* bytesview_test.c */ #include #include #include #include #include #include "bytesview.h" void report(bytesview_t const *bv, char *name) { printf("%s.n() = %ld\n", name, act_bv_n(bv)); printf("%s.tostr() = %s\n", name, act_bv_tostr(bv)); printf("%s.show():\n", name); act_bv_show(bv); printf("\n"); } void consumetest(bytesview_t const *bv, int additional, int show) { bytesview_t const *bvr; size_t i, iterations; printf("consume test (show=%d)\n", show); printf("=====================\n"); printf("bv: b'%s'\n", act_bv_tostr(bv)); printf("additional: %d\n", additional); printf("---\n"); iterations = act_bv_n(bv) + 2; i = 0; while (i < iterations) { bvr = act_bv_consume(bv, i); if (additional>0 && bvr != NULL) bvr = act_bv_consume(bvr, additional); if (show) { if (bvr != NULL) report(bvr,"bvr"); else printf("NULL\n"); } else { if (bvr != NULL) printf("bvr: b'%s'\n", act_bv_tostr(bvr)); else printf("NULL\n"); } i++; } } void readtest(bytesview_t const *bv, int show) { bytesview_t const *bvr; size_t i, iterations; printf("read test (show = %d)\n", show); printf("====================\n"); iterations = act_bv_n(bv) + 2; // iterations = 3; i = 0; while (i < iterations) { bvr = act_bv_read(bv, i); if (show) { if (bvr != NULL) report(bvr,"bv"); else printf("NULL\n"); } else { if (bvr != NULL) printf("b'%s'\n", act_bv_tostr(bvr)); else printf("NULL\n"); } i++; } } void readexactlytest(bytesview_t const *bv, int show) { bytesview_t const *bvr; size_t i, iterations; printf("readexactly test (show = %d)\n", show); printf("===========================\n"); iterations = act_bv_n(bv) + 2; // iterations = 3; i = 0; while (i < iterations) { bvr = act_bv_readexactly(bv, i); if (show) { if (bvr != NULL) report(bvr,"bv"); else printf("NULL\n"); } else { if (bvr != NULL) printf("b'%s'\n", act_bv_tostr(bvr)); else printf("NULL\n"); } i++; } } void readuntiltest(bytesview_t const *bv, char *sep, int show) { bytesview_t const *bvr; bytesview_t const *bvs; size_t seplen = strlen(sep); size_t i, iterations; printf("readuntil test (show = %d)\n", show); printf("=========================\n"); printf("data = '%s'\n", act_bv_tostr(bv)); printf("separator ='%s'\n", sep); printf("seplen = %ld\n", seplen); printf("---\n"); iterations = act_bv_n(bv) + 2; i = 0; while (i < iterations) { bvr = act_bv_consume(bv, i); if (bvr != NULL) { bvs = act_bv_readuntil(bvr, sep); if (show) { if (bvr != NULL) printf("bvr: b'%s'\n", act_bv_tostr(bvr)); else printf("bvr: NULL\n"); if (bvs != NULL) report(bvs,"bvs"); else printf("bvs: NULL\n"); } else { if (bvr != NULL) printf("b'%s'\n", act_bv_tostr(bvr)); else printf("NULL\n"); if (bvs != NULL) printf("b'%s'\n", act_bv_tostr(bvs)); else printf("NULL\n"); } } i++; } } int main() { char *by = "0123456789abcdef"; bytesview_data_buffer_t b = { ._start = 0, ._end = 16, ._bytes = (uint8_t *) by }; size_t l = strlen(by); //int j; bytesview_t const *bv1; bytesview_t const *bv2; bytesview_t const *bv3; bytesview_t const *bv4; bytesview_t const *bv5; bv1 = act_bv_fromstr(by); report(bv1, "bv1"); bv2 = act_bv_frombuf(&b); report(bv2, "bv2"); bv3 = act_bv_append(bv2, by, l); report(bv3, "bv3"); bv4 = act_bv_append(bv1, "x", 1); bv4 = act_bv_append(bv4, by, 16); bv4 = act_bv_append(bv4, by, 16); bv4 = act_bv_append(bv4, "z", 1); bv4 = act_bv_append(bv4, by, 16); bv4 = act_bv_append(bv4, "w", 1); report(bv4, "bv4"); bv5 = act_bv_close(bv4); report(bv5, "bv5"); //consumetest(bv4, 20, 1); //consumetest(bv5); //readtest(bv4,1); //readtest(bv4,0); //readtest(bv5,1); //readtest(bv5,0); //readexactlytest(bv4,1); //readexactlytest(bv4,0); //readexactlytest(bv5,1); //readexactlytest(bv5,0); // readuntiltest(bv4,"0123456",0); // OK! // readuntiltest(bv4,"x",0); // OK! // readuntiltest(bv4,"fz",0); // OK! // readuntiltest(bv4,"z0",0); // OK! // readuntiltest(bv4,"fz0",0); // OK! // readuntiltest(bv4,"efz",0); // OK! // readuntiltest(bv4,"z01",0); //OK! // readuntiltest(bv4,"9ab",0); //OK! //readuntiltest(bv4,"def012",0); //OK! //readuntiltest(bv4,"def012",0); //OK readuntiltest(bv4,"f0123",0); //OK! readuntiltest(bv4,"cdef0",0); //OK! //readuntiltest(bv4,"9",1); //readuntiltest(bv4,"9a",0); //readuntiltest(bv5,,1); //readuntiltest(bv5,bv4,0); return 0; } ================================================ FILE: workspace/micke/flow.txt ================================================ # Definitions for interface between producing and consuming sides of # a data flow with simple flow control. # # Producer delivers data by calling deliver_data() of Consumer. struct Consumer(Type, Error): # methods that may be called by associated producer deliver_data: (Type) -> bool # Delivery of data to be consumed. # Always succeeds. # return True equivalent with encourage() # return False equivalent with discourage() is_closed: () -> bool # True when any data delivered will be ignored producer_closed: () -> None # Producer promises it will never call # deliver_data() again. Called exactly once. producer_error: (Error) -> None # Error condition reported by Producer struct Producer(Error): # methods that may be called by associated consumer discourage: () -> None # consumer asks producer to slow down encourage: () -> None # consumer asks producer to deliver is_discouraged: () -> bool # Am I delivering or am I slowed down? close: (opt(bool)) -> None # close(True) - Consumer wants all data # currently available, but # nothing more after that. Default. # close(False) - Consumer wants no more data, # effective immediately is_closed: () -> bool # True iff producer will not deliver any more # data. consumer_error: (Error) -> None # Error condition reported by Consumer. # Flow control: # Consumer buffers data delivered by deliver_data(data) as needed. # No blocking. # If Consumer deems it is busy or has buffered enough, it will # return False and/or call discourage() to inform Producer. # When at some later time the Consumer deems it is ready to accept more # data, it informs producer by calling encourage(). # Calls to discourage() and deliver_data() returning False are idempotent. # Calls to encourage() and deliver_data() returning True are idempotent. # # A Consumer that represents an outgoing OS socket, SHOULD call # discourage() or have deliver_data() return False whenever an OS send() # operation would have blocked. It SHOULD call encourage() when it has sent # all its buffered data and can send() without blocking. # # A Producer that represents an incoming OS socket, SHOULD react to # discourage() or deliver_data() returning False by no longer receiving # data from the socket. It MUST NOT receive data from the socket only to # buffer it. The intended sequence of events is that discourage() stops # receiving from the socket, so that the receive buffer of the socket # fills up, which will cause the flow-control mechanisms of TCP (assuming # a TCP socket) to pace or stop the network peer sending to the socket. # A Producer SHOULD react to encourage() by again receiving from the socket # whenever there is data to receive, and delivering received data using the # deliver_data() method of its associated consumer. ================================================ FILE: workspace/micke/processing.txt ================================================ Processing of an incoming NETCONF RPC ===================================== IP + TCP + receive buf + sockets in OS kernel | | stream of bytes, delivered in chunks by OS recv() syscall | V SSH impl processes an encrypted stream consisting of ssh packets. After key exchange, the stream is decrypted and then deframed and demultiplexed, producing sequences of ssh packet streams, one per open ssh channel. SSH decrypt + byte order + deframing + trimming of frames + demultiplexing | | | | ... | | decrypted ssh packets | | | ... | | | | | ... | V V V V V NETCONF subsystem One NETCONF session per SSH channel processes stream of channel data chunks produces sequence of NETCONF frames NETCONF deframing + trimming of frames | | utf-8 encoded XML documents representing NETCONF RPC:s | V utf-8 decoding (bytes -> string) | | XML-encoded NETCONF RPC:s | V XML parsing | | XML trees | V XML Operations -> XML replies | | XML trees | V XML printing | | XML-encoded NETCONF RPC-REPLIES | V utf-8 encoding (string -> bytes) | | utf-8 encoded XML for NETCONF RPC-REPLIES | V NETCONF framing (adding framing headers & trailers) | | | . . . | | NETCONF frames | | . . . | | | | . . . | V V V V SSH system multiplexing per-channel data into single SSH pipe adding headers & trailers to data chunks byte ordering | | plaintext SSH packets | V SSH encryption | | stream of bytes (encrypted multiplexed SSH packets) | V OS send() syscall OS sockets + send buf + TCP + IP ================================================ FILE: workspace/misc-examples/divtest.act ================================================ import numpy as np import math actor main(env): print(3/5) print(3.2/1.6) a = np.arange(1, 10) b = np.full(a.shape,2) print(a/b) c = np.linspace(0,5,5) d = np.array([2.5] * 5) print(c/d) env.exit(0) ================================================ FILE: workspace/misc-examples/loess_smoother.act ================================================ import numpy import math def loess(x, y, xin, win): win1 = win-1 # to be compatible with Loess.py and Loess_with_np.py xd = numpy.abs(xin[:,numpy.newaxis] - x) q = xd/numpy.partition(xd,win1)[:,win1][:,numpy.newaxis] w = numpy.clip(q, 0.0, 1.0) ws = (1.0 - w ** 3.0) ** 3.0 a00 = numpy.sum(ws,1) a01 = numpy.dot(ws, x) a11 = numpy.dot(ws, x*x) b0 = numpy.dot(ws, y) b1 = numpy.dot(ws, x*y) det = a00*a11-a01*a01 return ((a11*b0 - a01*b1) + (-a01*b0 + a00*b1)*xin)/det def sample(): x = numpy.linspace(0.0, 10.0, 101) y = numpy.unirandfloat(1.0, 3.0, 101) + math.sin(x) z = loess(x, y, x, 40) print("clear\n$data <weeks in graph> ") env.exit(0) win_width = int(env.argv[1]) loess_win_width = int(env.argv[2]) a = analyzer(win_width, loess_win_width) s = sampler(win_width//8, a.add_sample) ================================================ FILE: workspace/misc-examples/numpyfns.act ================================================ import numpy import math actor main(env): a = numpy.arange(20) b = numpy.tile(a,3) print(b) c = numpy.roll(a,-7) print(c) d = numpy.zeros(12) print(d) env.exit(0) ================================================ FILE: workspace/misc-examples/timestest.act ================================================ actor main(env): print([3,5] * 4) print([3,5] * -3) print(3 * 5) print(7.5 * 2.5) print("abc" * 6) print("abc" * -1) print(bytearray([65,67]) * 4) ================================================ FILE: workspace/upgrades/upgrade_v1.act ================================================ actor Counter(foo): var a = 0 def get(): a += 1 return "%s: %d" % (foo, a) actor main(env): var counter = Counter("banana") def _work(): msg = counter.get() print(msg) after 1: _work() _work() ================================================ FILE: workspace/upgrades/upgrade_v2.act ================================================ actor Counter(foo): var b = 0 def get(): b += 1 return "%s: %d" % (foo, b) actor main(env): var counter = Counter("banana") def _work(): msg = counter.get() print(msg) after 1: _work() _work()